Merge branch '2019-07-17-ti-imports'

- Bring in the first three series that we need in order to enhance the
  TI AM65x series support and then later introduce J721E support.
This commit is contained in:
Tom Rini 2019-07-18 11:30:30 -04:00
commit 9a06eb800c
42 changed files with 2041 additions and 267 deletions

View File

@ -69,4 +69,78 @@
clock-frequency = <48000000>;
current-speed = <115200>;
};
main_pmx0: pinmux@11c000 {
compatible = "pinctrl-single";
reg = <0x0 0x11c000 0x0 0x2e4>;
#pinctrl-cells = <1>;
pinctrl-single,register-width = <32>;
pinctrl-single,function-mask = <0xffffffff>;
};
main_pmx1: pinmux@11c2e8 {
compatible = "pinctrl-single";
reg = <0x0 0x11c2e8 0x0 0x24>;
#pinctrl-cells = <1>;
pinctrl-single,register-width = <32>;
pinctrl-single,function-mask = <0xffffffff>;
};
sdhci0: sdhci@4f80000 {
compatible = "ti,am654-sdhci-5.1";
reg = <0x0 0x4f80000 0x0 0x260>, <0x0 0x4f90000 0x0 0x134>;
power-domains = <&k3_pds 47>;
clocks = <&k3_clks 47 0>, <&k3_clks 47 1>;
clock-names = "clk_ahb", "clk_xin";
interrupts = <GIC_SPI 136 IRQ_TYPE_LEVEL_HIGH>;
mmc-ddr-1_8v;
mmc-hs200-1_8v;
ti,otap-del-sel = <0x2>;
ti,trm-icp = <0x8>;
dma-coherent;
};
main_i2c0: i2c@2000000 {
compatible = "ti,am654-i2c", "ti,omap4-i2c";
reg = <0x0 0x2000000 0x0 0x100>;
interrupts = <GIC_SPI 200 IRQ_TYPE_LEVEL_HIGH>;
#address-cells = <1>;
#size-cells = <0>;
clock-names = "fck";
clocks = <&k3_clks 110 1>;
power-domains = <&k3_pds 110>;
};
main_i2c1: i2c@2010000 {
compatible = "ti,am654-i2c", "ti,omap4-i2c";
reg = <0x0 0x2010000 0x0 0x100>;
interrupts = <GIC_SPI 201 IRQ_TYPE_LEVEL_HIGH>;
#address-cells = <1>;
#size-cells = <0>;
clock-names = "fck";
clocks = <&k3_clks 111 1>;
power-domains = <&k3_pds 111>;
};
main_i2c2: i2c@2020000 {
compatible = "ti,am654-i2c", "ti,omap4-i2c";
reg = <0x0 0x2020000 0x0 0x100>;
interrupts = <GIC_SPI 202 IRQ_TYPE_LEVEL_HIGH>;
#address-cells = <1>;
#size-cells = <0>;
clock-names = "fck";
clocks = <&k3_clks 112 1>;
power-domains = <&k3_pds 112>;
};
main_i2c3: i2c@2030000 {
compatible = "ti,am654-i2c", "ti,omap4-i2c";
reg = <0x0 0x2030000 0x0 0x100>;
interrupts = <GIC_SPI 203 IRQ_TYPE_LEVEL_HIGH>;
#address-cells = <1>;
#size-cells = <0>;
clock-names = "fck";
clocks = <&k3_clks 113 1>;
power-domains = <&k3_pds 113>;
};
};

View File

@ -15,4 +15,15 @@
clock-frequency = <96000000>;
current-speed = <115200>;
};
mcu_i2c0: i2c@40b00000 {
compatible = "ti,am654-i2c", "ti,omap4-i2c";
reg = <0x0 0x40b00000 0x0 0x100>;
interrupts = <GIC_SPI 564 IRQ_TYPE_LEVEL_HIGH>;
#address-cells = <1>;
#size-cells = <0>;
clock-names = "fck";
clocks = <&k3_clks 114 1>;
power-domains = <&k3_pds 114>;
};
};

View File

@ -34,6 +34,14 @@
};
};
wkup_pmx0: pinmux@4301c000 {
compatible = "pinctrl-single";
reg = <0x4301c000 0x118>;
#pinctrl-cells = <1>;
pinctrl-single,register-width = <32>;
pinctrl-single,function-mask = <0xffffffff>;
};
wkup_uart0: serial@42300000 {
compatible = "ti,am654-uart";
reg = <0x42300000 0x100>;
@ -43,4 +51,15 @@
clock-frequency = <48000000>;
current-speed = <115200>;
};
wkup_i2c0: i2c@42120000 {
compatible = "ti,am654-i2c", "ti,omap4-i2c";
reg = <0x42120000 0x100>;
interrupts = <GIC_SPI 696 IRQ_TYPE_LEVEL_HIGH>;
#address-cells = <1>;
#size-cells = <0>;
clock-names = "fck";
clocks = <&k3_clks 115 1>;
power-domains = <&k3_pds 115>;
};
};

View File

@ -8,6 +8,7 @@
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/interrupt-controller/irq.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/pinctrl/k3.h>
/ {
model = "Texas Instruments K3 AM654 SoC";
@ -22,6 +23,12 @@
serial2 = &main_uart0;
serial3 = &main_uart1;
serial4 = &main_uart2;
i2c0 = &wkup_i2c0;
i2c1 = &mcu_i2c0;
i2c2 = &main_i2c0;
i2c3 = &main_i2c1;
i2c4 = &main_i2c2;
i2c5 = &main_i2c3;
};
chosen { };

View File

@ -21,51 +21,21 @@
&cbass_main{
u-boot,dm-spl;
main_pmx0: pinmux@11c000 {
compatible = "pinctrl-single";
reg = <0x0 0x11c000 0x0 0x2e4>;
#pinctrl-cells = <1>;
pinctrl-single,register-width = <32>;
pinctrl-single,function-mask = <0xffffffff>;
};
main_pmx1: pinmux@11c2e8 {
compatible = "pinctrl-single";
reg = <0x0 0x11c2e8 0x0 0x24>;
#pinctrl-cells = <1>;
pinctrl-single,register-width = <32>;
pinctrl-single,function-mask = <0xffffffff>;
};
sdhci0: sdhci@04F80000 {
compatible = "arasan,sdhci-5.1";
reg = <0x0 0x4F80000 0x0 0x1000>,
<0x0 0x4F90000 0x0 0x400>;
clocks = <&k3_clks 47 1>;
power-domains = <&k3_pds 47>;
max-frequency = <25000000>;
};
sdhci1: sdhci@04FA0000 {
compatible = "arasan,sdhci-5.1";
compatible = "ti,am654-sdhci-5.1";
reg = <0x0 0x4FA0000 0x0 0x1000>,
<0x0 0x4FB0000 0x0 0x400>;
clocks = <&k3_clks 48 1>;
power-domains = <&k3_pds 48>;
max-frequency = <25000000>;
ti,otap-del-sel = <0x2>;
ti,trm-icp = <0x8>;
};
};
&cbass_mcu {
u-boot,dm-spl;
wkup_pmx0: pinmux@4301c000 {
compatible = "pinctrl-single";
reg = <0x0 0x4301c000 0x0 0x118>;
#pinctrl-cells = <1>;
pinctrl-single,register-width = <32>;
pinctrl-single,function-mask = <0xffffffff>;
};
navss_mcu: navss-mcu {
compatible = "simple-bus";
@ -252,6 +222,14 @@
u-boot,dm-spl;
};
&wkup_pmx0 {
u-boot,dm-spl;
wkup_i2c0_pins_default {
u-boot,dm-spl;
};
};
&main_pmx0 {
u-boot,dm-spl;
main_uart0_pins_default: main_uart0_pins_default {
@ -276,7 +254,8 @@
AM65X_IOPAD(0x0190, PIN_INPUT_PULLUP, 0) /* (A24) MMC0_DAT5 */
AM65X_IOPAD(0x018c, PIN_INPUT_PULLUP, 0) /* (B26) MMC0_DAT6 */
AM65X_IOPAD(0x0188, PIN_INPUT_PULLUP, 0) /* (D25) MMC0_DAT7 */
AM65X_IOPAD(0x01b0, PIN_INPUT, 0) /* (C25) MMC0_DS */
AM65X_IOPAD(0x01b4, PIN_INPUT_PULLUP, 0) /* (A23) MMC0_SDCD */
AM65X_IOPAD(0x01b0, PIN_INPUT, 0) /* (C25) MMC0_DS */
>;
u-boot,dm-spl;
};
@ -336,11 +315,6 @@
&sdhci0 {
u-boot,dm-spl;
status = "okay";
non-removable;
bus-width = <8>;
pinctrl-names = "default";
pinctrl-0 = <&main_mmc0_pins_default>;
};
&sdhci1 {
@ -349,6 +323,7 @@
pinctrl-names = "default";
pinctrl-0 = <&main_mmc1_pins_default>;
sdhci-caps-mask = <0x7 0x0>;
ti,driver-strength-ohm = <50>;
};
&mcu_cpsw {
@ -382,3 +357,7 @@
reg-names = "gmii-sel";
};
};
&wkup_i2c0 {
u-boot,dm-spl;
};

View File

@ -6,6 +6,7 @@
/dts-v1/;
#include "k3-am654.dtsi"
#include <dt-bindings/pinctrl/k3.h>
/ {
compatible = "ti,am654-evm", "ti,am654";
@ -34,3 +35,52 @@
};
};
};
&main_pmx0 {
main_mmc0_pins_default: main_mmc0_pins_default {
pinctrl-single,pins = <
AM65X_IOPAD(0x01a8, PIN_INPUT_PULLDOWN, 0) /* (B25) MMC0_CLK */
AM65X_IOPAD(0x01aC, PIN_INPUT_PULLUP, 0) /* (B27) MMC0_CMD */
AM65X_IOPAD(0x01a4, PIN_INPUT_PULLUP, 0) /* (A26) MMC0_DAT0 */
AM65X_IOPAD(0x01a0, PIN_INPUT_PULLUP, 0) /* (E25) MMC0_DAT1 */
AM65X_IOPAD(0x019c, PIN_INPUT_PULLUP, 0) /* (C26) MMC0_DAT2 */
AM65X_IOPAD(0x0198, PIN_INPUT_PULLUP, 0) /* (A25) MMC0_DAT3 */
AM65X_IOPAD(0x0194, PIN_INPUT_PULLUP, 0) /* (E24) MMC0_DAT4 */
AM65X_IOPAD(0x0190, PIN_INPUT_PULLUP, 0) /* (A24) MMC0_DAT5 */
AM65X_IOPAD(0x018c, PIN_INPUT_PULLUP, 0) /* (B26) MMC0_DAT6 */
AM65X_IOPAD(0x0188, PIN_INPUT_PULLUP, 0) /* (D25) MMC0_DAT7 */
AM65X_IOPAD(0x01b4, PIN_INPUT_PULLUP, 0) /* (A23) MMC0_SDCD */
AM65X_IOPAD(0x01b0, PIN_INPUT, 0) /* (C25) MMC0_DS */
>;
};
};
&wkup_pmx0 {
wkup_i2c0_pins_default: wkup-i2c0-pins-default {
pinctrl-single,pins = <
AM65X_WKUP_IOPAD(0x00e0, PIN_INPUT, 0) /* (AC7) WKUP_I2C0_SCL */
AM65X_WKUP_IOPAD(0x00e4, PIN_INPUT, 0) /* (AD6) WKUP_I2C0_SDA */
>;
};
};
&sdhci0 {
pinctrl-names = "default";
pinctrl-0 = <&main_mmc0_pins_default>;
bus-width = <8>;
non-removable;
ti,driver-strength-ohm = <50>;
};
&wkup_i2c0 {
pinctrl-names = "default";
pinctrl-0 = <&wkup_i2c0_pins_default>;
clock-frequency = <400000>;
tca9554: gpio@38 {
compatible = "nxp,pca9554";
reg = <0x38>;
gpio-controller;
#gpio-cells = <2>;
};
};

View File

@ -96,6 +96,12 @@
u-boot,dm-spl;
};
clk_200mhz: dummy_clock {
compatible = "fixed-clock";
#clock-cells = <0>;
clock-frequency = <200000000>;
u-boot,dm-spl;
};
};
&dmsc {
@ -130,6 +136,32 @@
>;
u-boot,dm-spl;
};
wkup_i2c0_pins_default: wkup-i2c0-pins-default {
pinctrl-single,pins = <
AM65X_WKUP_IOPAD(0x00e0, PIN_INPUT, 0) /* (AC7) WKUP_I2C0_SCL */
AM65X_WKUP_IOPAD(0x00e4, PIN_INPUT, 0) /* (AD6) WKUP_I2C0_SDA */
>;
};
};
&main_pmx0 {
u-boot,dm-spl;
main_mmc0_pins_default: main_mmc0_pins_default {
pinctrl-single,pins = <
AM65X_IOPAD(0x01a8, PIN_INPUT_PULLDOWN, 0) /* (B25) MMC0_CLK */
AM65X_IOPAD(0x01aC, PIN_INPUT_PULLUP, 0) /* (B27) MMC0_CMD */
AM65X_IOPAD(0x01a4, PIN_INPUT_PULLUP, 0) /* (A26) MMC0_DAT0 */
AM65X_IOPAD(0x01a0, PIN_INPUT_PULLUP, 0) /* (E25) MMC0_DAT1 */
AM65X_IOPAD(0x019c, PIN_INPUT_PULLUP, 0) /* (C26) MMC0_DAT2 */
AM65X_IOPAD(0x0198, PIN_INPUT_PULLUP, 0) /* (A25) MMC0_DAT3 */
AM65X_IOPAD(0x0194, PIN_INPUT_PULLUP, 0) /* (E24) MMC0_DAT4 */
AM65X_IOPAD(0x0190, PIN_INPUT_PULLUP, 0) /* (A24) MMC0_DAT5 */
AM65X_IOPAD(0x018c, PIN_INPUT_PULLUP, 0) /* (B26) MMC0_DAT6 */
AM65X_IOPAD(0x0188, PIN_INPUT_PULLUP, 0) /* (D25) MMC0_DAT7 */
AM65X_IOPAD(0x01b0, PIN_INPUT, 0) /* (C25) MMC0_DS */
>;
};
};
&memorycontroller {
@ -137,3 +169,23 @@
pinctrl-names = "default";
pinctrl-0 = <&wkup_vtt_pins_default>;
};
&sdhci0 {
clock-names = "clk_xin";
clocks = <&clk_200mhz>;
/delete-property/ power-domains;
ti,driver-strength-ohm = <50>;
};
&sdhci1 {
clock-names = "clk_xin";
clocks = <&clk_200mhz>;
/delete-property/ power-domains;
ti,driver-strength-ohm = <50>;
};
&wkup_i2c0 {
pinctrl-names = "default";
pinctrl-0 = <&wkup_i2c0_pins_default>;
clock-frequency = <400000>;
};

View File

@ -3,8 +3,6 @@
#ifndef _OMAP_I2C_H
#define _OMAP_I2C_H
#include <asm/arch/cpu.h>
#ifdef CONFIG_DM_I2C
/* Information about a GPIO bank */

View File

@ -57,6 +57,33 @@
* For more information see 'Board Initialisation Flow in README.
*/
/*
* Macro for clearing BSS during SPL execution. Usually called during the
* relocation process for most boards before entering board_init_r(), but
* can also be done early before entering board_init_f() on plaforms that
* can afford it due to sufficient memory being available early.
*/
.macro SPL_CLEAR_BSS
ldr r0, =__bss_start /* this is auto-relocated! */
#ifdef CONFIG_USE_ARCH_MEMSET
ldr r3, =__bss_end /* this is auto-relocated! */
mov r1, #0x00000000 /* prepare zero to clear BSS */
subs r2, r3, r0 /* r2 = memset len */
bl memset
#else
ldr r1, =__bss_end /* this is auto-relocated! */
mov r2, #0x00000000 /* prepare zero to clear BSS */
clbss_l:cmp r0, r1 /* while not at end of BSS */
strlo r2, [r0] /* clear 32-bit BSS word */
addlo r0, r0, #4 /* move to next */
blo clbss_l
#endif
.endm
/*
* entry point of crt0 sequence
*/
@ -82,6 +109,10 @@ ENTRY(_main)
mov r9, r0
bl board_init_f_init_reserve
#if defined(CONFIG_SPL_EARLY_BSS)
SPL_CLEAR_BSS
#endif
mov r0, #0
bl board_init_f
@ -119,6 +150,11 @@ here:
bl c_runtime_cpu_setup /* we still call old routine here */
#endif
#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_FRAMEWORK)
#if !defined(CONFIG_SPL_EARLY_BSS)
SPL_CLEAR_BSS
#endif
# ifdef CONFIG_SPL_BUILD
/* Use a DRAM stack for the rest of SPL, if requested */
bl spl_relocate_stack_gd
@ -126,23 +162,6 @@ here:
movne sp, r0
movne r9, r0
# endif
ldr r0, =__bss_start /* this is auto-relocated! */
#ifdef CONFIG_USE_ARCH_MEMSET
ldr r3, =__bss_end /* this is auto-relocated! */
mov r1, #0x00000000 /* prepare zero to clear BSS */
subs r2, r3, r0 /* r2 = memset len */
bl memset
#else
ldr r1, =__bss_end /* this is auto-relocated! */
mov r2, #0x00000000 /* prepare zero to clear BSS */
clbss_l:cmp r0, r1 /* while not at end of BSS */
strlo r2, [r0] /* clear 32-bit BSS word */
addlo r0, r0, #4 /* move to next */
blo clbss_l
#endif
#if ! defined(CONFIG_SPL_BUILD)
bl coloured_LED_init

View File

@ -58,6 +58,45 @@ config SYS_K3_BOOT_CORE_ID
int
default 16
config K3_LOAD_SYSFW
bool
depends on SPL
config K3_SYSFW_IMAGE_NAME
string "File name of SYSFW firmware and configuration blob"
depends on K3_LOAD_SYSFW
default "sysfw.itb"
help
Filename of the combined System Firmware and configuration image tree
blob to be loaded when booting from a filesystem.
config K3_SYSFW_IMAGE_MMCSD_RAW_MODE_SECT
hex "MMC sector to load SYSFW firmware and configuration blob from"
depends on K3_LOAD_SYSFW && SYS_MMCSD_RAW_MODE_U_BOOT_USE_SECTOR
default 0x3600
help
Address on the MMC to load the combined System Firmware and
configuration image tree blob from, when the MMC is being used
in raw mode. Units: MMC sectors (1 sector = 512 bytes).
config K3_SYSFW_IMAGE_MMCSD_RAW_MODE_PART
hex "MMC partition to load SYSFW firmware and configuration blob from"
depends on K3_LOAD_SYSFW && SYS_MMCSD_RAW_MODE_U_BOOT_USE_PARTITION
default 2
help
Partition on the MMC to the combined System Firmware and configuration
image tree blob from, when the MMC is being used in raw mode.
config K3_SYSFW_IMAGE_SIZE_MAX
int "Amount of memory dynamically allocated for loading SYSFW blob"
depends on K3_LOAD_SYSFW
default 269000
help
Amount of memory (in bytes) reserved through dynamic allocation at
runtime for loading the combined System Firmware and configuration image
tree blob. Keep it as tight as possible, as this directly affects the
overall SPL memory footprint.
config SYS_K3_SPL_ATF
bool "Start Cortex-A from SPL"
depends on SPL && CPU_V7R

View File

@ -7,4 +7,7 @@ obj-$(CONFIG_SOC_K3_AM6) += am6_init.o
obj-$(CONFIG_ARM64) += arm64-mmu.o
obj-$(CONFIG_CPU_V7R) += r5_mpu.o lowlevel_init.o
obj-$(CONFIG_TI_SECURE_DEVICE) += security.o
ifeq ($(CONFIG_SPL_BUILD),y)
obj-$(CONFIG_K3_LOAD_SYSFW) += sysfw-loader.o
endif
obj-y += common.o

View File

@ -10,8 +10,12 @@
#include <asm/io.h>
#include <spl.h>
#include <asm/arch/hardware.h>
#include <asm/arch/sysfw-loader.h>
#include <asm/arch/sys_proto.h>
#include "common.h"
#include <dm.h>
#include <dm/uclass-internal.h>
#include <dm/pinctrl.h>
#ifdef CONFIG_SPL_BUILD
static void mmr_unlock(u32 base, u32 partition)
@ -63,7 +67,7 @@ static void store_boot_index_from_rom(void)
void board_init_f(ulong dummy)
{
#if defined(CONFIG_K3_AM654_DDRSS)
#if defined(CONFIG_K3_LOAD_SYSFW) || defined(CONFIG_K3_AM654_DDRSS)
struct udevice *dev;
int ret;
#endif
@ -83,8 +87,33 @@ void board_init_f(ulong dummy)
/* Init DM early in-order to invoke system controller */
spl_early_init();
#ifdef CONFIG_K3_LOAD_SYSFW
/*
* Process pinctrl for the serial0 a.k.a. WKUP_UART0 module and continue
* regardless of the result of pinctrl. Do this without probing the
* device, but instead by searching the device that would request the
* given sequence number if probed. The UART will be used by the system
* firmware (SYSFW) image for various purposes and SYSFW depends on us
* to initialize its pin settings.
*/
ret = uclass_find_device_by_seq(UCLASS_SERIAL, 0, true, &dev);
if (!ret)
pinctrl_select_state(dev, "default");
/*
* Load, start up, and configure system controller firmware. Provide
* the U-Boot console init function to the SYSFW post-PM configuration
* callback hook, effectively switching on (or over) the console
* output.
*/
k3_sysfw_loader(preloader_console_init);
#else
/* Prepare console output */
preloader_console_init();
#endif
/* Perform EEPROM-based board detection */
do_board_detect();
#ifdef CONFIG_K3_AM654_DDRSS
ret = uclass_get_device(UCLASS_RAM, 0, &dev);

View File

@ -44,4 +44,7 @@
#define CTRLMMR_LOCK_KICK1 0x0100c
#define CTRLMMR_LOCK_KICK1_UNLOCK_VAL 0xd172bc5a
/* MCU SCRATCHPAD usage */
#define TI_SRAM_SCRATCH_BOARD_EEPROM_START CONFIG_SYS_K3_MCU_SCRATCHPAD_BASE
#endif /* __ASM_ARCH_AM6_HARDWARE_H */

View File

@ -12,4 +12,6 @@ u32 wait_on_value(u32 read_bit_mask, u32 match_value, void *read_addr,
u32 bound);
struct ti_sci_handle *get_ti_sci_handle(void);
int fdt_fixup_msmc_ram(void *blob, char *parent_path, char *node_name);
int do_board_detect(void);
#endif

View File

@ -0,0 +1,12 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com/
* Andreas Dannenberg <dannenberg@ti.com>
*/
#ifndef _SYSFW_LOADER_H_
#define _SYSFW_LOADER_H_
void k3_sysfw_loader(void (*config_pm_done_callback)(void));
#endif

View File

@ -0,0 +1,260 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* K3: System Firmware Loader
*
* Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com/
* Andreas Dannenberg <dannenberg@ti.com>
*/
#include <common.h>
#include <spl.h>
#include <malloc.h>
#include <remoteproc.h>
#include <linux/soc/ti/ti_sci_protocol.h>
#include <asm/arch/sys_proto.h>
/* Name of the FIT image nodes for SYSFW and its config data */
#define SYSFW_FIRMWARE "sysfw.bin"
#define SYSFW_CFG_BOARD "board-cfg.bin"
#define SYSFW_CFG_PM "pm-cfg.bin"
#define SYSFW_CFG_RM "rm-cfg.bin"
#define SYSFW_CFG_SEC "sec-cfg.bin"
static bool sysfw_loaded;
static void *sysfw_load_address;
/*
* Populate SPL hook to override the default load address used by the SPL
* loader function with a custom address for SYSFW loading.
*/
struct image_header *spl_get_load_buffer(ssize_t offset, size_t size)
{
if (sysfw_loaded)
return (struct image_header *)(CONFIG_SYS_TEXT_BASE + offset);
else if (sysfw_load_address)
return sysfw_load_address;
else
panic("SYSFW load address not defined!");
}
/*
* Populate SPL hook to skip the default SPL loader FIT post-processing steps
* during SYSFW loading and return to the calling function so we can perform
* our own custom processing.
*/
bool spl_load_simple_fit_skip_processing(void)
{
return !sysfw_loaded;
}
static int fit_get_data_by_name(const void *fit, int images, const char *name,
const void **addr, size_t *size)
{
int node_offset;
node_offset = fdt_subnode_offset(fit, images, name);
if (node_offset < 0)
return -ENOENT;
return fit_image_get_data(fit, node_offset, addr, size);
}
static void k3_sysfw_load_using_fit(void *fit)
{
int images;
const void *sysfw_addr;
size_t sysfw_size;
int ret;
/* Find the node holding the images information */
images = fdt_path_offset(fit, FIT_IMAGES_PATH);
if (images < 0)
panic("Cannot find /images node (%d)\n", images);
/* Extract System Firmware (SYSFW) image from FIT */
ret = fit_get_data_by_name(fit, images, SYSFW_FIRMWARE,
&sysfw_addr, &sysfw_size);
if (ret < 0)
panic("Error accessing %s node in FIT (%d)\n", SYSFW_FIRMWARE,
ret);
/*
* Start up system controller firmware
*
* It is assumed that remoteproc device 0 is the corresponding
* system-controller that runs SYSFW. Make sure DT reflects the same.
*/
ret = rproc_dev_init(0);
if (ret)
panic("rproc failed to be initialized (%d)\n", ret);
ret = rproc_load(0, (ulong)sysfw_addr, (ulong)sysfw_size);
if (ret)
panic("Firmware failed to start on rproc (%d)\n", ret);
ret = rproc_start(0);
if (ret)
panic("Firmware init failed on rproc (%d)\n", ret);
}
static void k3_sysfw_configure_using_fit(void *fit,
struct ti_sci_handle *ti_sci)
{
struct ti_sci_board_ops *board_ops = &ti_sci->ops.board_ops;
int images;
const void *cfg_fragment_addr;
size_t cfg_fragment_size;
int ret;
/* Find the node holding the images information */
images = fdt_path_offset(fit, FIT_IMAGES_PATH);
if (images < 0)
panic("Cannot find /images node (%d)\n", images);
/* Extract board configuration from FIT */
ret = fit_get_data_by_name(fit, images, SYSFW_CFG_BOARD,
&cfg_fragment_addr, &cfg_fragment_size);
if (ret < 0)
panic("Error accessing %s node in FIT (%d)\n", SYSFW_CFG_BOARD,
ret);
/* Apply board configuration to SYSFW */
ret = board_ops->board_config(ti_sci,
(u64)(u32)cfg_fragment_addr,
(u32)cfg_fragment_size);
if (ret)
panic("Failed to set board configuration (%d)\n", ret);
/* Extract power/clock (PM) specific configuration from FIT */
ret = fit_get_data_by_name(fit, images, SYSFW_CFG_PM,
&cfg_fragment_addr, &cfg_fragment_size);
if (ret < 0)
panic("Error accessing %s node in FIT (%d)\n", SYSFW_CFG_PM,
ret);
/* Apply power/clock (PM) specific configuration to SYSFW */
ret = board_ops->board_config_pm(ti_sci,
(u64)(u32)cfg_fragment_addr,
(u32)cfg_fragment_size);
if (ret)
panic("Failed to set board PM configuration (%d)\n", ret);
/* Extract resource management (RM) specific configuration from FIT */
ret = fit_get_data_by_name(fit, images, SYSFW_CFG_RM,
&cfg_fragment_addr, &cfg_fragment_size);
if (ret < 0)
panic("Error accessing %s node in FIT (%d)\n", SYSFW_CFG_RM,
ret);
/* Apply resource management (RM) configuration to SYSFW */
ret = board_ops->board_config_rm(ti_sci,
(u64)(u32)cfg_fragment_addr,
(u32)cfg_fragment_size);
if (ret)
panic("Failed to set board RM configuration (%d)\n", ret);
/* Extract security specific configuration from FIT */
ret = fit_get_data_by_name(fit, images, SYSFW_CFG_SEC,
&cfg_fragment_addr, &cfg_fragment_size);
if (ret < 0)
panic("Error accessing %s node in FIT (%d)\n", SYSFW_CFG_SEC,
ret);
/* Apply security configuration to SYSFW */
ret = board_ops->board_config_security(ti_sci,
(u64)(u32)cfg_fragment_addr,
(u32)cfg_fragment_size);
if (ret)
panic("Failed to set board security configuration (%d)\n",
ret);
}
void k3_sysfw_loader(void (*config_pm_done_callback)(void))
{
struct spl_image_info spl_image = { 0 };
struct spl_boot_device bootdev = { 0 };
struct ti_sci_handle *ti_sci;
int ret;
/* Reserve a block of aligned memory for loading the SYSFW image */
sysfw_load_address = memalign(ARCH_DMA_MINALIGN,
CONFIG_K3_SYSFW_IMAGE_SIZE_MAX);
if (!sysfw_load_address)
panic("Error allocating %u bytes of memory for SYSFW image\n",
CONFIG_K3_SYSFW_IMAGE_SIZE_MAX);
debug("%s: allocated %u bytes at 0x%p\n", __func__,
CONFIG_K3_SYSFW_IMAGE_SIZE_MAX, sysfw_load_address);
/* Set load address for legacy modes that bypass spl_get_load_buffer */
spl_image.load_addr = (uintptr_t)sysfw_load_address;
bootdev.boot_device = spl_boot_device();
/* Load combined System Controller firmware and config data image */
switch (bootdev.boot_device) {
#if CONFIG_IS_ENABLED(MMC_SUPPORT)
case BOOT_DEVICE_MMC1:
case BOOT_DEVICE_MMC2:
case BOOT_DEVICE_MMC2_2:
ret = spl_mmc_load(&spl_image, &bootdev,
#ifdef CONFIG_K3_SYSFW_IMAGE_NAME
CONFIG_K3_SYSFW_IMAGE_NAME,
#else
NULL,
#endif
#ifdef CONFIG_K3_SYSFW_IMAGE_MMCSD_RAW_MODE_PART
CONFIG_K3_SYSFW_IMAGE_MMCSD_RAW_MODE_PART,
#else
0,
#endif
#ifdef CONFIG_K3_SYSFW_IMAGE_MMCSD_RAW_MODE_SECT
CONFIG_K3_SYSFW_IMAGE_MMCSD_RAW_MODE_SECT);
#else
0);
#endif
break;
#endif
default:
panic("Loading SYSFW image from device %u not supported!\n",
bootdev.boot_device);
}
if (ret)
panic("Error %d occurred during loading SYSFW image!\n", ret);
/*
* Now that SYSFW got loaded set helper flag to restore regular SPL
* loader behavior so we can later boot into the next stage as expected.
*/
sysfw_loaded = true;
/* Ensure the SYSFW image is in FIT format */
if (image_get_magic((const image_header_t *)sysfw_load_address) !=
FDT_MAGIC)
panic("SYSFW image not in FIT format!\n");
/* Extract and start SYSFW */
k3_sysfw_load_using_fit(sysfw_load_address);
/* Get handle for accessing SYSFW services */
ti_sci = get_ti_sci_handle();
/* Parse and apply the different SYSFW configuration fragments */
k3_sysfw_configure_using_fit(sysfw_load_address, ti_sci);
/*
* Now that all clocks and PM aspects are setup, invoke a user-
* provided callback function. Usually this callback would be used
* to setup or re-configure the U-Boot console UART.
*/
if (config_pm_done_callback)
config_pm_done_callback();
/* Output System Firmware version info */
printf("SYSFW ABI: %d.%d (firmware rev 0x%04x '%.*s')\n",
ti_sci->version.abi_major, ti_sci->version.abi_minor,
ti_sci->version.firmware_revision,
sizeof(ti_sci->version.firmware_description),
ti_sci->version.firmware_description);
}

View File

@ -12,14 +12,18 @@ config TARGET_AM654_A53_EVM
select ARM64
select SOC_K3_AM6
select SYS_DISABLE_DCACHE_OPS
select BOARD_LATE_INIT
imply TI_I2C_BOARD_DETECT
config TARGET_AM654_R5_EVM
bool "TI K3 based AM654 EVM running on R5"
select CPU_V7R
select SYS_THUMB_BUILD
select SOC_K3_AM6
select K3_LOAD_SYSFW
select K3_AM654_DDRSS
imply SYS_K3_SPL_ATF
imply TI_I2C_BOARD_DETECT
endchoice
@ -34,6 +38,8 @@ config SYS_VENDOR
config SYS_CONFIG_NAME
default "am65x_evm"
source "board/ti/common/Kconfig"
endif
if TARGET_AM654_R5_EVM
@ -50,4 +56,6 @@ config SYS_CONFIG_NAME
config SPL_LDSCRIPT
default "arch/arm/mach-omap2/u-boot-spl.lds"
source "board/ti/common/Kconfig"
endif

View File

@ -209,3 +209,55 @@ Image formats:
| | Secure config | |
| +-------------------+ |
+-----------------------+
eMMC:
-----
ROM supports booting from eMMC from boot0 partition offset 0x0
Flashing images to eMMC:
The following commands can be used to download tiboot3.bin, tispl.bin,
u-boot.img, and sysfw.itb from an SD card and write them to the eMMC boot0
partition at respective addresses.
=> mmc dev 0 1
=> fatload mmc 1 ${loadaddr} tiboot3.bin
=> mmc write ${loadaddr} 0x0 0x400
=> fatload mmc 1 ${loadaddr} tispl.bin
=> mmc write ${loadaddr} 0x400 0x1000
=> fatload mmc 1 ${loadaddr} u-boot.img
=> mmc write ${loadaddr} 0x1400 0x2000
=> fatload mmc 1 ${loadaddr} sysfw.itb
=> mmc write ${loadaddr} 0x3600 0x800
To give the ROM access to the boot partition, the following commands must be
used for the first time:
=> mmc partconf 0 1 1 1
=> mmc bootbus 0 1 0 0
To create a software partition for the rootfs, the following command can be
used:
=> gpt write mmc 0 ${partitions}
eMMC layout:
boot0 partition (8 MB) user partition
0x0+----------------------------------+ 0x0+-------------------------+
| tiboot3.bin (512 KB) | | |
0x400+----------------------------------+ | |
| tispl.bin (2 MB) | | |
0x1400+----------------------------------+ | rootfs |
| u-boot.img (4 MB) | | |
0x3400+----------------------------------+ | |
| environment (128 KB) | | |
0x3500+----------------------------------+ | |
| backup environment (128 KB) | | |
0x3600+----------------------------------+ | |
| sysfw (1 MB) | | |
0x3E00+----------------------------------+ +-------------------------+
Kernel image and DT are expected to be present in the /boot folder of rootfs.
To boot kernel from eMMC, use the following commands:
=> setenv mmcdev 0
=> setenv bootpart 0
=> boot

View File

@ -8,10 +8,31 @@
*/
#include <common.h>
#include <dm.h>
#include <asm/arch/sys_proto.h>
#include <asm/arch/hardware.h>
#include <asm/gpio.h>
#include <asm/io.h>
#include <asm/omap_common.h>
#include <spl.h>
#include <asm/arch/sys_proto.h>
#include "../common/board_detect.h"
#define board_is_am65x_base_board() board_ti_is("AM6-COMPROCEVM")
/* Daughter card presence detection signals */
enum {
AM65X_EVM_APP_BRD_DET,
AM65X_EVM_LCD_BRD_DET,
AM65X_EVM_SERDES_BRD_DET,
AM65X_EVM_HDMI_GPMC_BRD_DET,
AM65X_EVM_BRD_DET_COUNT,
};
/* Max number of MAC addresses that are parsed/processed per daughter card */
#define DAUGHTER_CARD_NO_OF_MAC_ADDR 8
DECLARE_GLOBAL_DATA_PTR;
int board_init(void)
@ -80,3 +101,223 @@ int ft_board_setup(void *blob, bd_t *bd)
return ret;
}
#endif
int do_board_detect(void)
{
int ret;
ret = ti_i2c_eeprom_am6_get_base(CONFIG_EEPROM_BUS_ADDRESS,
CONFIG_EEPROM_CHIP_ADDRESS);
if (ret)
pr_err("Reading on-board EEPROM at 0x%02x failed %d\n",
CONFIG_EEPROM_CHIP_ADDRESS, ret);
return ret;
}
static void setup_board_eeprom_env(void)
{
char *name = "am65x";
if (do_board_detect())
goto invalid_eeprom;
if (board_is_am65x_base_board())
name = "am65x";
else
printf("Unidentified board claims %s in eeprom header\n",
board_ti_get_name());
invalid_eeprom:
set_board_info_env_am6(name);
}
static int init_daughtercard_det_gpio(char *gpio_name, struct gpio_desc *desc)
{
int ret;
memset(desc, 0, sizeof(*desc));
ret = dm_gpio_lookup_name(gpio_name, desc);
if (ret < 0)
return ret;
/* Request GPIO, simply re-using the name as label */
ret = dm_gpio_request(desc, gpio_name);
if (ret < 0)
return ret;
return dm_gpio_set_dir_flags(desc, GPIOD_IS_IN);
}
static int probe_daughtercards(void)
{
struct ti_am6_eeprom ep;
struct gpio_desc board_det_gpios[AM65X_EVM_BRD_DET_COUNT];
char mac_addr[DAUGHTER_CARD_NO_OF_MAC_ADDR][TI_EEPROM_HDR_ETH_ALEN];
u8 mac_addr_cnt;
char name_overlays[1024] = { 0 };
int i, j;
int ret;
/*
* Daughter card presence detection signal name to GPIO (via I2C I/O
* expander @ address 0x38) name and EEPROM I2C address mapping.
*/
const struct {
char *gpio_name;
u8 i2c_addr;
} slot_map[AM65X_EVM_BRD_DET_COUNT] = {
{ "gpio@38_0", 0x52, }, /* AM65X_EVM_APP_BRD_DET */
{ "gpio@38_1", 0x55, }, /* AM65X_EVM_LCD_BRD_DET */
{ "gpio@38_2", 0x54, }, /* AM65X_EVM_SERDES_BRD_DET */
{ "gpio@38_3", 0x53, }, /* AM65X_EVM_HDMI_GPMC_BRD_DET */
};
/* Declaration of daughtercards to probe */
const struct {
u8 slot_index; /* Slot the card is installed */
char *card_name; /* EEPROM-programmed card name */
char *dtbo_name; /* Device tree overlay to apply */
u8 eth_offset; /* ethXaddr MAC address index offset */
} cards[] = {
{
AM65X_EVM_APP_BRD_DET,
"AM6-GPAPPEVM",
"k3-am654-gp.dtbo",
0,
},
{
AM65X_EVM_APP_BRD_DET,
"AM6-IDKAPPEVM",
"k3-am654-idk.dtbo",
3,
},
{
AM65X_EVM_SERDES_BRD_DET,
"SER-PCIE2LEVM",
"k3-am654-pcie-usb2.dtbo",
0,
},
{
AM65X_EVM_SERDES_BRD_DET,
"SER-PCIEUSBEVM",
"k3-am654-pcie-usb3.dtbo",
0,
},
{
AM65X_EVM_LCD_BRD_DET,
"OLDI-LCD1EVM",
"k3-am654-evm-oldi-lcd1evm.dtbo",
0,
},
};
/*
* Initialize GPIO used for daughtercard slot presence detection and
* keep the resulting handles in local array for easier access.
*/
for (i = 0; i < AM65X_EVM_BRD_DET_COUNT; i++) {
ret = init_daughtercard_det_gpio(slot_map[i].gpio_name,
&board_det_gpios[i]);
if (ret < 0)
return ret;
}
for (i = 0; i < ARRAY_SIZE(cards); i++) {
/* Obtain card-specific slot index and associated I2C address */
u8 slot_index = cards[i].slot_index;
u8 i2c_addr = slot_map[slot_index].i2c_addr;
/*
* The presence detection signal is active-low, hence skip
* over this card slot if anything other than 0 is returned.
*/
ret = dm_gpio_get_value(&board_det_gpios[slot_index]);
if (ret < 0)
return ret;
else if (ret)
continue;
/* Get and parse the daughter card EEPROM record */
ret = ti_i2c_eeprom_am6_get(CONFIG_EEPROM_BUS_ADDRESS, i2c_addr,
&ep,
(char **)mac_addr,
DAUGHTER_CARD_NO_OF_MAC_ADDR,
&mac_addr_cnt);
if (ret) {
pr_err("Reading daughtercard EEPROM at 0x%02x failed %d\n",
i2c_addr, ret);
/*
* Even this is pretty serious let's just skip over
* this particular daughtercard, rather than ending
* the probing process altogether.
*/
continue;
}
/* Only process the parsed data if we found a match */
if (strncmp(ep.name, cards[i].card_name, sizeof(ep.name)))
continue;
printf("detected %s\n", cards[i].card_name);
/*
* Populate any MAC addresses from daughtercard into the U-Boot
* environment, starting with a card-specific offset so we can
* have multiple cards contribute to the MAC pool in a well-
* defined manner.
*/
for (j = 0; j < mac_addr_cnt; j++) {
if (!is_valid_ethaddr((u8 *)mac_addr[j]))
continue;
eth_env_set_enetaddr_by_index("eth",
cards[i].eth_offset + j,
(uchar *)mac_addr[j]);
}
/* Skip if no overlays are to be added */
if (!strlen(cards[i].dtbo_name))
continue;
/*
* Make sure we are not running out of buffer space by checking
* if we can fit the new overlay, a trailing space to be used
* as a separator, plus the terminating zero.
*/
if (strlen(name_overlays) + strlen(cards[i].dtbo_name) + 2 >
sizeof(name_overlays))
return -ENOMEM;
/* Append to our list of overlays */
strcat(name_overlays, cards[i].dtbo_name);
strcat(name_overlays, " ");
}
/* Apply device tree overlay(s) to the U-Boot environment, if any */
if (strlen(name_overlays))
return env_set("name_overlays", name_overlays);
return 0;
}
int board_late_init(void)
{
struct ti_am6_eeprom *ep = TI_AM6_EEPROM_DATA;
setup_board_eeprom_env();
/*
* The first MAC address for ethernet a.k.a. ethernet0 comes from
* efuse populated via the am654 gigabit eth switch subsystem driver.
* All the other ones are populated via EEPROM, hence continue with
* an index of 1.
*/
board_ti_am6_set_ethaddr(1, ep->mac_addr_cnt);
/* Check for and probe any plugged-in daughtercards */
probe_daughtercards();
return 0;
}

View File

@ -8,6 +8,7 @@
*/
#include <common.h>
#include <asm/arch/hardware.h>
#include <asm/omap_common.h>
#include <dm/uclass.h>
#include <i2c.h>
@ -284,6 +285,191 @@ int __maybe_unused ti_i2c_eeprom_dra7_get(int bus_addr, int dev_addr)
return 0;
}
static int ti_i2c_eeprom_am6_parse_record(struct ti_am6_eeprom_record *record,
struct ti_am6_eeprom *ep,
char **mac_addr,
u8 mac_addr_max_cnt,
u8 *mac_addr_cnt)
{
switch (record->header.id) {
case TI_AM6_EEPROM_RECORD_BOARD_INFO:
if (record->header.len != sizeof(record->data.board_info))
return -EINVAL;
if (!ep)
break;
/* Populate (and clean, if needed) the board name */
strlcpy(ep->name, record->data.board_info.name,
sizeof(ep->name));
ti_eeprom_string_cleanup(ep->name);
/* Populate selected other fields from the board info record */
strlcpy(ep->version, record->data.board_info.version,
sizeof(ep->version));
strlcpy(ep->software_revision,
record->data.board_info.software_revision,
sizeof(ep->software_revision));
strlcpy(ep->serial, record->data.board_info.serial,
sizeof(ep->serial));
break;
case TI_AM6_EEPROM_RECORD_MAC_INFO:
if (record->header.len != sizeof(record->data.mac_info))
return -EINVAL;
if (!mac_addr || !mac_addr_max_cnt)
break;
*mac_addr_cnt = ((record->data.mac_info.mac_control &
TI_AM6_EEPROM_MAC_ADDR_COUNT_MASK) >>
TI_AM6_EEPROM_MAC_ADDR_COUNT_SHIFT) + 1;
/*
* The EEPROM can (but may not) hold a very large amount
* of MAC addresses, by far exceeding what we want/can store
* in the common memory array, so only grab what we can fit.
* Note that a value of 0 means 1 MAC address, and so on.
*/
*mac_addr_cnt = min(*mac_addr_cnt, mac_addr_max_cnt);
memcpy(mac_addr, record->data.mac_info.mac_addr,
*mac_addr_cnt * TI_EEPROM_HDR_ETH_ALEN);
break;
case 0x00:
/* Illegal value... Fall through... */
case 0xFF:
/* Illegal value... Something went horribly wrong... */
return -EINVAL;
default:
pr_warn("%s: Ignoring record id %u\n", __func__,
record->header.id);
}
return 0;
}
int __maybe_unused ti_i2c_eeprom_am6_get(int bus_addr, int dev_addr,
struct ti_am6_eeprom *ep,
char **mac_addr,
u8 mac_addr_max_cnt,
u8 *mac_addr_cnt)
{
struct udevice *dev;
struct udevice *bus;
unsigned int eeprom_addr;
struct ti_am6_eeprom_record_board_id board_id;
struct ti_am6_eeprom_record record;
int rc;
/* Initialize with a known bad marker for i2c fails.. */
memset(ep, 0, sizeof(*ep));
ep->header = TI_DEAD_EEPROM_MAGIC;
/* Read the board ID record which is always the first EEPROM record */
rc = ti_i2c_eeprom_get(bus_addr, dev_addr, TI_EEPROM_HEADER_MAGIC,
sizeof(board_id), (uint8_t *)&board_id);
if (rc)
return rc;
if (board_id.header.id != TI_AM6_EEPROM_RECORD_BOARD_ID) {
pr_err("%s: Invalid board ID record!\n", __func__);
return -EINVAL;
}
/* Establish DM handle to board config EEPROM */
rc = uclass_get_device_by_seq(UCLASS_I2C, bus_addr, &bus);
if (rc)
return rc;
rc = i2c_get_chip(bus, dev_addr, 1, &dev);
if (rc)
return rc;
ep->header = TI_EEPROM_HEADER_MAGIC;
/* Ready to parse TLV structure. Initialize variables... */
*mac_addr_cnt = 0;
/*
* After the all-encompassing board ID record all other records follow
* a TLV-type scheme. Point to the first such record and then start
* parsing those one by one.
*/
eeprom_addr = sizeof(board_id);
while (true) {
rc = dm_i2c_read(dev, eeprom_addr, (uint8_t *)&record.header,
sizeof(record.header));
if (rc)
return rc;
/*
* Check for end of list marker. If we reached it don't go
* any further and stop parsing right here.
*/
if (record.header.id == TI_AM6_EEPROM_RECORD_END_LIST)
break;
eeprom_addr += sizeof(record.header);
debug("%s: dev_addr=0x%02x header.id=%u header.len=%u\n",
__func__, dev_addr, record.header.id,
record.header.len);
/* Read record into memory if it fits */
if (record.header.len <= sizeof(record.data)) {
rc = dm_i2c_read(dev, eeprom_addr,
(uint8_t *)&record.data,
record.header.len);
if (rc)
return rc;
/* Process record */
rc = ti_i2c_eeprom_am6_parse_record(&record, ep,
mac_addr,
mac_addr_max_cnt,
mac_addr_cnt);
if (rc) {
pr_err("%s: EEPROM parsing error!\n", __func__);
return rc;
}
} else {
/*
* We may get here in case of larger records which
* are not yet understood.
*/
pr_err("%s: Ignoring record id %u\n", __func__,
record.header.id);
}
eeprom_addr += record.header.len;
}
return 0;
}
int __maybe_unused ti_i2c_eeprom_am6_get_base(int bus_addr, int dev_addr)
{
struct ti_am6_eeprom *ep = TI_AM6_EEPROM_DATA;
int ret;
/*
* Always execute EEPROM read by not allowing to bypass it during the
* first invocation of SPL which happens on the R5 core.
*/
#if !(defined(CONFIG_SPL_BUILD) && defined(CONFIG_CPU_V7R))
if (ep->header == TI_EEPROM_HEADER_MAGIC) {
debug("%s: EEPROM has already been read\n", __func__);
return 0;
}
#endif
ret = ti_i2c_eeprom_am6_get(bus_addr, dev_addr, ep,
(char **)ep->mac_addr,
AM6_EEPROM_HDR_NO_OF_MAC_ADDR,
&ep->mac_addr_cnt);
return ret;
}
bool __maybe_unused board_ti_is(char *name_tag)
{
struct ti_common_eeprom *ep = TI_EEPROM_DATA;
@ -348,6 +534,25 @@ fail:
memset(mac_addr, 0, TI_EEPROM_HDR_ETH_ALEN);
}
void __maybe_unused
board_ti_am6_get_eth_mac_addr(int index,
u8 mac_addr[TI_EEPROM_HDR_ETH_ALEN])
{
struct ti_am6_eeprom *ep = TI_AM6_EEPROM_DATA;
if (ep->header == TI_DEAD_EEPROM_MAGIC)
goto fail;
if (index < 0 || index >= ep->mac_addr_cnt)
goto fail;
memcpy(mac_addr, ep->mac_addr[index], TI_EEPROM_HDR_ETH_ALEN);
return;
fail:
memset(mac_addr, 0, TI_EEPROM_HDR_ETH_ALEN);
}
u64 __maybe_unused board_ti_get_emif1_size(void)
{
struct ti_common_eeprom *ep = TI_EEPROM_DATA;
@ -391,6 +596,34 @@ void __maybe_unused set_board_info_env(char *name)
env_set("board_serial", unknown);
}
void __maybe_unused set_board_info_env_am6(char *name)
{
char *unknown = "unknown";
struct ti_am6_eeprom *ep = TI_AM6_EEPROM_DATA;
if (name)
env_set("board_name", name);
else if (ep->name)
env_set("board_name", ep->name);
else
env_set("board_name", unknown);
if (ep->version)
env_set("board_rev", ep->version);
else
env_set("board_rev", unknown);
if (ep->software_revision)
env_set("board_software_revision", ep->software_revision);
else
env_set("board_software_revision", unknown);
if (ep->serial)
env_set("board_serial", ep->serial);
else
env_set("board_serial", unknown);
}
static u64 mac_to_u64(u8 mac[6])
{
int i;
@ -453,6 +686,19 @@ void board_ti_set_ethaddr(int index)
}
}
void board_ti_am6_set_ethaddr(int index, int count)
{
u8 mac_addr[6];
int i;
for (i = 0; i < count; i++) {
board_ti_am6_get_eth_mac_addr(i, mac_addr);
if (is_valid_ethaddr(mac_addr))
eth_env_set_enetaddr_by_index("eth", i + index,
mac_addr);
}
}
bool __maybe_unused board_ti_was_eeprom_read(void)
{
struct ti_common_eeprom *ep = TI_EEPROM_DATA;

View File

@ -43,6 +43,133 @@ struct ti_am_eeprom {
char mac_addr[TI_EEPROM_HDR_NO_OF_MAC_ADDR][TI_EEPROM_HDR_ETH_ALEN];
} __attribute__ ((__packed__));
/* AM6x TI EVM EEPROM Definitions */
#define TI_AM6_EEPROM_RECORD_BOARD_ID 0x01
#define TI_AM6_EEPROM_RECORD_BOARD_INFO 0x10
#define TI_AM6_EEPROM_RECORD_DDR_INFO 0x11
#define TI_AM6_EEPROM_RECORD_DDR_SPD 0x12
#define TI_AM6_EEPROM_RECORD_MAC_INFO 0x13
#define TI_AM6_EEPROM_RECORD_END_LIST 0xFE
/*
* Common header for AM6x TI EVM EEPROM records. Used to encapsulate the config
* EEPROM in its entirety as well as for individual records contained within.
*/
struct ti_am6_eeprom_record_header {
u8 id;
u16 len;
} __attribute__ ((__packed__));
/* AM6x TI EVM EEPROM board ID structure */
struct ti_am6_eeprom_record_board_id {
u32 magic_number;
struct ti_am6_eeprom_record_header header;
} __attribute__ ((__packed__));
/* AM6x TI EVM EEPROM board info structure */
#define AM6_EEPROM_HDR_NAME_LEN 16
#define AM6_EEPROM_HDR_VERSION_LEN 2
#define AM6_EEPROM_HDR_PROC_NR_LEN 4
#define AM6_EEPROM_HDR_VARIANT_LEN 2
#define AM6_EEPROM_HDR_PCB_REV_LEN 2
#define AM6_EEPROM_HDR_SCH_BOM_REV_LEN 2
#define AM6_EEPROM_HDR_SW_REV_LEN 2
#define AM6_EEPROM_HDR_VID_LEN 2
#define AM6_EEPROM_HDR_BLD_WK_LEN 2
#define AM6_EEPROM_HDR_BLD_YR_LEN 2
#define AM6_EEPROM_HDR_4P_NR_LEN 6
#define AM6_EEPROM_HDR_SERIAL_LEN 4
struct ti_am6_eeprom_record_board_info {
char name[AM6_EEPROM_HDR_NAME_LEN];
char version[AM6_EEPROM_HDR_VERSION_LEN];
char proc_number[AM6_EEPROM_HDR_PROC_NR_LEN];
char variant[AM6_EEPROM_HDR_VARIANT_LEN];
char pcb_revision[AM6_EEPROM_HDR_PCB_REV_LEN];
char schematic_bom_revision[AM6_EEPROM_HDR_SCH_BOM_REV_LEN];
char software_revision[AM6_EEPROM_HDR_SW_REV_LEN];
char vendor_id[AM6_EEPROM_HDR_VID_LEN];
char build_week[AM6_EEPROM_HDR_BLD_WK_LEN];
char build_year[AM6_EEPROM_HDR_BLD_YR_LEN];
char board_4p_number[AM6_EEPROM_HDR_4P_NR_LEN];
char serial[AM6_EEPROM_HDR_SERIAL_LEN];
} __attribute__ ((__packed__));
/* Memory location to keep a copy of the AM6 board info record */
#define TI_AM6_EEPROM_BD_INFO_DATA ((struct ti_am6_eeprom_record_board_info *) \
TI_SRAM_SCRATCH_BOARD_EEPROM_START)
/* AM6x TI EVM EEPROM DDR info structure */
#define TI_AM6_EEPROM_DDR_CTRL_INSTANCE_MASK GENMASK(1, 0)
#define TI_AM6_EEPROM_DDR_CTRL_INSTANCE_SHIFT 0
#define TI_AM6_EEPROM_DDR_CTRL_SPD_DATA_LOC_MASK GENMASK(3, 2)
#define TI_AM6_EEPROM_DDR_CTRL_SPD_DATA_LOC_NA (0 << 2)
#define TI_AM6_EEPROM_DDR_CTRL_SPD_DATA_LOC_BOARDID (2 << 2)
#define TI_AM6_EEPROM_DDR_CTRL_SPD_DATA_LOC_I2C51 (3 << 2)
#define TI_AM6_EEPROM_DDR_CTRL_MEM_TYPE_MASK GENMASK(5, 4)
#define TI_AM6_EEPROM_DDR_CTRL_MEM_TYPE_DDR3 (0 << 4)
#define TI_AM6_EEPROM_DDR_CTRL_MEM_TYPE_DDR4 (1 << 4)
#define TI_AM6_EEPROM_DDR_CTRL_MEM_TYPE_LPDDR4 (2 << 4)
#define TI_AM6_EEPROM_DDR_CTRL_IF_DATA_WIDTH_MASK GENMASK(7, 6)
#define TI_AM6_EEPROM_DDR_CTRL_IF_DATA_WIDTH_16 (0 << 6)
#define TI_AM6_EEPROM_DDR_CTRL_IF_DATA_WIDTH_32 (1 << 6)
#define TI_AM6_EEPROM_DDR_CTRL_IF_DATA_WIDTH_64 (2 << 6)
#define TI_AM6_EEPROM_DDR_CTRL_DEV_DATA_WIDTH_MASK GENMASK(9, 8)
#define TI_AM6_EEPROM_DDR_CTRL_DEV_DATA_WIDTH_8 (0 << 8)
#define TI_AM6_EEPROM_DDR_CTRL_DEV_DATA_WIDTH_16 (1 << 8)
#define TI_AM6_EEPROM_DDR_CTRL_DEV_DATA_WIDTH_32 (2 << 8)
#define TI_AM6_EEPROM_DDR_CTRL_RANKS_2 BIT(10)
#define TI_AM6_EEPROM_DDR_CTRL_DENS_MASK GENMASK(13, 11)
#define TI_AM6_EEPROM_DDR_CTRL_DENS_1GB (0 << 11)
#define TI_AM6_EEPROM_DDR_CTRL_DENS_2GB (1 << 11)
#define TI_AM6_EEPROM_DDR_CTRL_DENS_4GB (2 << 11)
#define TI_AM6_EEPROM_DDR_CTRL_DENS_8GB (3 << 11)
#define TI_AM6_EEPROM_DDR_CTRL_DENS_12GB (4 << 11)
#define TI_AM6_EEPROM_DDR_CTRL_DENS_16GB (5 << 11)
#define TI_AM6_EEPROM_DDR_CTRL_DENS_24GB (6 << 11)
#define TI_AM6_EEPROM_DDR_CTRL_DENS_32GB (7 << 11)
#define TI_AM6_EEPROM_DDR_CTRL_ECC BIT(14)
struct ti_am6_eeprom_record_ddr_info {
u16 ddr_control;
} __attribute__ ((__packed__));
/* AM6x TI EVM EEPROM DDR SPD structure */
#define TI_AM6_EEPROM_DDR_SPD_INSTANCE_MASK GENMASK(1, 0)
#define TI_AM6_EEPROM_DDR_SPD_INSTANCE_SHIFT 0
#define TI_AM6_EEPROM_DDR_SPD_MEM_TYPE_MASK GENMASK(4, 3)
#define TI_AM6_EEPROM_DDR_SPD_MEM_TYPE_DDR3 (0 << 3)
#define TI_AM6_EEPROM_DDR_SPD_MEM_TYPE_DDR4 (1 << 3)
#define TI_AM6_EEPROM_DDR_SPD_MEM_TYPE_LPDDR4 (2 << 3)
#define TI_AM6_EEPROM_DDR_SPD_DATA_LEN 512
struct ti_am6_eeprom_record_ddr_spd {
u16 spd_control;
u8 data[TI_AM6_EEPROM_DDR_SPD_DATA_LEN];
} __attribute__ ((__packed__));
/* AM6x TI EVM EEPROM MAC info structure */
#define TI_AM6_EEPROM_MAC_INFO_INSTANCE_MASK GENMASK(2, 0)
#define TI_AM6_EEPROM_MAC_INFO_INSTANCE_SHIFT 0
#define TI_AM6_EEPROM_MAC_ADDR_COUNT_MASK GENMASK(7, 3)
#define TI_AM6_EEPROM_MAC_ADDR_COUNT_SHIFT 3
#define TI_AM6_EEPROM_MAC_ADDR_MAX_COUNT 32
struct ti_am6_eeprom_record_mac_info {
u16 mac_control;
u8 mac_addr[TI_AM6_EEPROM_MAC_ADDR_MAX_COUNT][TI_EEPROM_HDR_ETH_ALEN];
} __attribute__ ((__packed__));
struct ti_am6_eeprom_record {
struct ti_am6_eeprom_record_header header;
union {
struct ti_am6_eeprom_record_board_info board_info;
struct ti_am6_eeprom_record_ddr_info ddr_info;
struct ti_am6_eeprom_record_ddr_spd ddr_spd;
struct ti_am6_eeprom_record_mac_info mac_info;
} data;
} __attribute__ ((__packed__));
/* DRA7 EEPROM MAGIC Header identifier */
#define DRA7_EEPROM_HEADER_MAGIC 0xAA5533EE
#define DRA7_EEPROM_HDR_NAME_LEN 16
@ -99,6 +226,37 @@ struct ti_common_eeprom {
#define TI_EEPROM_DATA ((struct ti_common_eeprom *)\
TI_SRAM_SCRATCH_BOARD_EEPROM_START)
/*
* Maximum number of Ethernet MAC addresses extracted from the AM6x on-board
* EEPROM during the initial probe and carried forward in SRAM.
*/
#define AM6_EEPROM_HDR_NO_OF_MAC_ADDR 8
/**
* struct ti_am6_eeprom - Null terminated, usable EEPROM contents, as extracted
* from the AM6 on-board EEPROM. Note that we only carry a subset of data
* at this time to be considerate about memory consumption.
* @header: Magic number for data validity indication
* @name: NULL terminated name
* @version: NULL terminated version
* @software_revision: NULL terminated software revision
* @serial: Board serial number
* @mac_addr_cnt: Number of MAC addresses stored in this object
* @mac_addr: MAC addresses
*/
struct ti_am6_eeprom {
u32 header;
char name[AM6_EEPROM_HDR_NAME_LEN + 1];
char version[AM6_EEPROM_HDR_VERSION_LEN + 1];
char software_revision[AM6_EEPROM_HDR_SW_REV_LEN + 1];
char serial[AM6_EEPROM_HDR_SERIAL_LEN + 1];
u8 mac_addr_cnt;
char mac_addr[AM6_EEPROM_HDR_NO_OF_MAC_ADDR][TI_EEPROM_HDR_ETH_ALEN];
};
#define TI_AM6_EEPROM_DATA ((struct ti_am6_eeprom *) \
TI_SRAM_SCRATCH_BOARD_EEPROM_START)
/**
* ti_i2c_eeprom_am_get() - Consolidated eeprom data collection for AM* TI EVMs
* @bus_addr: I2C bus address
@ -116,6 +274,33 @@ int ti_i2c_eeprom_am_get(int bus_addr, int dev_addr);
*/
int ti_i2c_eeprom_dra7_get(int bus_addr, int dev_addr);
/**
* ti_i2c_eeprom_am6_get() - Consolidated eeprom data for AM6x TI EVMs and
* associated daughter cards, parsed into user-
* provided data structures
* @bus_addr: I2C bus address
* @dev_addr: I2C slave address
* @ep: Pointer to structure receiving AM6-specific header data
* @mac_addr: Pointer to memory receiving parsed MAC addresses. May be
* NULL to skip MAC parsing.
* @mac_addr_max_cnt: Maximum number of MAC addresses that can be stored into
* mac_addr. May be NULL to skip MAC parsing.
* @mac_addr_cnt: Pointer to a location returning how many MAC addressed got
* actually parsed.
*/
int __maybe_unused ti_i2c_eeprom_am6_get(int bus_addr, int dev_addr,
struct ti_am6_eeprom *ep,
char **mac_addr,
u8 mac_addr_max_cnt,
u8 *mac_addr_cnt);
/**
* ti_i2c_eeprom_am6_get_base() - Consolidated eeprom data for AM6x TI EVMs
* @bus_addr: I2C bus address
* @dev_addr: I2C slave address
*/
int __maybe_unused ti_i2c_eeprom_am6_get_base(int bus_addr, int dev_addr);
/**
* board_ti_is() - Board detection logic for TI EVMs
* @name_tag: Tag used in eeprom for the board
@ -192,6 +377,15 @@ u64 board_ti_get_emif2_size(void);
*/
void set_board_info_env(char *name);
/**
* set_board_info_env_am6() - Setup commonly used board information environment
* vars for AM6-type boards
* @name: Name of the board
*
* If name is NULL, default_name is used.
*/
void set_board_info_env_am6(char *name);
/**
* board_ti_set_ethaddr- Sets the ethaddr environment from EEPROM
* @index: The first eth<index>addr environment variable to set
@ -204,6 +398,18 @@ void set_board_info_env(char *name);
*/
void board_ti_set_ethaddr(int index);
/**
* board_ti_am6_set_ethaddr- Sets the ethaddr environment from EEPROM
* @index: The first eth<index>addr environment variable to set
* @count: The number of MAC addresses to process
*
* EEPROM should be already read before calling this function. The EEPROM
* contains n dedicated MAC addresses. This function sets the ethaddr
* environment variable for all the available MAC addresses starting
* from eth<index>addr.
*/
void board_ti_am6_set_ethaddr(int index, int count);
/**
* board_ti_was_eeprom_read() - Check to see if the eeprom contents have been read
*

View File

@ -248,6 +248,16 @@ config TPL_BANNER_PRINT
info. Disabling this option could be useful to reduce SPL boot time
(e.g. approx. 6 ms faster, when output on i.MX6 with 115200 baud).
config SPL_EARLY_BSS
depends on ARM && !ARM64
bool "Allows initializing BSS early before entering board_init_f"
help
On some platform we have sufficient memory available early on to
allow setting up and using a basic BSS prior to entering
board_init_f. Activating this option will also de-activate the
clearing of BSS during the SPL relocation process, thus allowing
to carry state from board_init_f to board_init_r by way of BSS.
config SPL_DISPLAY_PRINT
bool "Display a board-specific message in SPL"
help

View File

@ -340,6 +340,16 @@ static int spl_fit_image_get_os(const void *fit, int noffset, uint8_t *os)
#endif
}
/*
* Weak default function to allow customizing SPL fit loading for load-only
* use cases by allowing to skip the parsing/processing of the FIT contents
* (so that this can be done separately in a more customized fashion)
*/
__weak bool spl_load_simple_fit_skip_processing(void)
{
return false;
}
int spl_load_simple_fit(struct spl_image_info *spl_image,
struct spl_load_info *info, ulong sector, void *fit)
{
@ -389,6 +399,10 @@ int spl_load_simple_fit(struct spl_image_info *spl_image,
if (count == 0)
return -EIO;
/* skip further processing if requested to enable load-only use cases */
if (spl_load_simple_fit_skip_processing())
return 0;
/* find the node holding the images information */
images = fdt_path_offset(fit, FIT_IMAGES_PATH);
if (images < 0) {

View File

@ -151,7 +151,8 @@ static int spl_mmc_find_device(struct mmc **mmcp, u32 boot_device)
#ifdef CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_USE_PARTITION
static int mmc_load_image_raw_partition(struct spl_image_info *spl_image,
struct mmc *mmc, int partition)
struct mmc *mmc, int partition,
unsigned long sector)
{
disk_partition_t info;
int err;
@ -180,8 +181,7 @@ static int mmc_load_image_raw_partition(struct spl_image_info *spl_image,
}
#ifdef CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_USE_SECTOR
return mmc_load_image_raw_sector(spl_image, mmc,
info.start + CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR);
return mmc_load_image_raw_sector(spl_image, mmc, info.start + sector);
#else
return mmc_load_image_raw_sector(spl_image, mmc, info.start);
#endif
@ -234,7 +234,8 @@ static int mmc_load_image_raw_os(struct spl_image_info *spl_image,
#endif
#ifdef CONFIG_SYS_MMCSD_FS_BOOT_PARTITION
static int spl_mmc_do_fs_boot(struct spl_image_info *spl_image, struct mmc *mmc)
static int spl_mmc_do_fs_boot(struct spl_image_info *spl_image, struct mmc *mmc,
const char *filename)
{
int err = -ENOSYS;
@ -248,7 +249,7 @@ static int spl_mmc_do_fs_boot(struct spl_image_info *spl_image, struct mmc *mmc)
#ifdef CONFIG_SPL_FS_LOAD_PAYLOAD_NAME
err = spl_load_image_fat(spl_image, mmc_get_blk_desc(mmc),
CONFIG_SYS_MMCSD_FS_BOOT_PARTITION,
CONFIG_SPL_FS_LOAD_PAYLOAD_NAME);
filename);
if (!err)
return err;
#endif
@ -263,7 +264,7 @@ static int spl_mmc_do_fs_boot(struct spl_image_info *spl_image, struct mmc *mmc)
#ifdef CONFIG_SPL_FS_LOAD_PAYLOAD_NAME
err = spl_load_image_ext(spl_image, mmc_get_blk_desc(mmc),
CONFIG_SYS_MMCSD_FS_BOOT_PARTITION,
CONFIG_SPL_FS_LOAD_PAYLOAD_NAME);
filename);
if (!err)
return err;
#endif
@ -276,7 +277,8 @@ static int spl_mmc_do_fs_boot(struct spl_image_info *spl_image, struct mmc *mmc)
return err;
}
#else
static int spl_mmc_do_fs_boot(struct spl_image_info *spl_image, struct mmc *mmc)
static int spl_mmc_do_fs_boot(struct spl_image_info *spl_image, struct mmc *mmc,
const char *filename)
{
return -ENOSYS;
}
@ -301,24 +303,31 @@ int spl_boot_partition(const u32 boot_device)
}
#endif
int spl_mmc_load_image(struct spl_image_info *spl_image,
struct spl_boot_device *bootdev)
int spl_mmc_load(struct spl_image_info *spl_image,
struct spl_boot_device *bootdev,
const char *filename,
int raw_part,
unsigned long raw_sect)
{
struct mmc *mmc = NULL;
static struct mmc *mmc;
u32 boot_mode;
int err = 0;
__maybe_unused int part;
err = spl_mmc_find_device(&mmc, bootdev->boot_device);
if (err)
return err;
/* Perform peripheral init only once */
if (!mmc) {
err = spl_mmc_find_device(&mmc, bootdev->boot_device);
if (err)
return err;
err = mmc_init(mmc);
if (err) {
err = mmc_init(mmc);
if (err) {
mmc = NULL;
#ifdef CONFIG_SPL_LIBCOMMON_SUPPORT
printf("spl: mmc init failed with error: %d\n", err);
printf("spl: mmc init failed with error: %d\n", err);
#endif
return err;
return err;
}
}
boot_mode = spl_boot_mode(bootdev->boot_device);
@ -356,17 +365,13 @@ int spl_mmc_load_image(struct spl_image_info *spl_image,
return err;
}
#ifdef CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_USE_PARTITION
err = spl_boot_partition(bootdev->boot_device);
if (!err)
return err;
err = mmc_load_image_raw_partition(spl_image, mmc, err);
err = mmc_load_image_raw_partition(spl_image, mmc, raw_part,
raw_sect);
if (!err)
return err;
#endif
#ifdef CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_USE_SECTOR
err = mmc_load_image_raw_sector(spl_image, mmc,
CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR);
err = mmc_load_image_raw_sector(spl_image, mmc, raw_sect);
if (!err)
return err;
#endif
@ -374,7 +379,7 @@ int spl_mmc_load_image(struct spl_image_info *spl_image,
case MMCSD_MODE_FS:
debug("spl: mmc boot mode: fs\n");
err = spl_mmc_do_fs_boot(spl_image, mmc);
err = spl_mmc_do_fs_boot(spl_image, mmc, filename);
if (!err)
return err;
@ -388,6 +393,27 @@ int spl_mmc_load_image(struct spl_image_info *spl_image,
return err;
}
int spl_mmc_load_image(struct spl_image_info *spl_image,
struct spl_boot_device *bootdev)
{
return spl_mmc_load(spl_image, bootdev,
#ifdef CONFIG_SPL_FS_LOAD_PAYLOAD_NAME
CONFIG_SPL_FS_LOAD_PAYLOAD_NAME,
#else
NULL,
#endif
#ifdef CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_PARTITION
spl_boot_partition(bootdev->boot_device),
#else
0,
#endif
#ifdef CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR
CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR);
#else
0);
#endif
}
SPL_LOAD_IMAGE_METHOD("MMC1", 0, BOOT_DEVICE_MMC1, spl_mmc_load_image);
SPL_LOAD_IMAGE_METHOD("MMC2", 0, BOOT_DEVICE_MMC2, spl_mmc_load_image);
SPL_LOAD_IMAGE_METHOD("MMC2_2", 0, BOOT_DEVICE_MMC2_2, spl_mmc_load_image);

View File

@ -1,4 +1,8 @@
CONFIG_ARM=y
# CONFIG_SPL_USE_ARCH_MEMCPY is not set
# CONFIG_TPL_USE_ARCH_MEMCPY is not set
# CONFIG_SPL_USE_ARCH_MEMSET is not set
# CONFIG_TPL_USE_ARCH_MEMSET is not set
CONFIG_ARCH_OMAP2PLUS=y
CONFIG_TI_COMMON_CMD_OPTIONS=y
CONFIG_AM33XX=y

View File

@ -2,7 +2,7 @@ CONFIG_ARM=y
CONFIG_ARCH_K3=y
CONFIG_SPL_LIBCOMMON_SUPPORT=y
CONFIG_SPL_LIBGENERIC_SUPPORT=y
CONFIG_SYS_MALLOC_F_LEN=0x2000
CONFIG_SYS_MALLOC_F_LEN=0x8000
CONFIG_SOC_K3_AM6=y
CONFIG_TARGET_AM654_A53_EVM=y
CONFIG_SPL_MMC_SUPPORT=y
@ -16,12 +16,14 @@ CONFIG_DISTRO_DEFAULTS=y
# CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set
CONFIG_SPL_LOAD_FIT=y
CONFIG_OF_BOARD_SETUP=y
CONFIG_BOOTCOMMAND="run findfdt; run envboot; run init_${boot}; run get_kern_${boot}; run get_fdt_${boot}; run run_kern"
CONFIG_BOOTCOMMAND="run findfdt; run envboot; run init_${boot}; run get_kern_${boot}; run get_fdt_${boot}; run get_overlay_${boot}; run run_kern"
# CONFIG_DISPLAY_CPUINFO is not set
CONFIG_SPL_TEXT_BASE=0x80080000
CONFIG_SPL_SYS_MALLOC_SIMPLE=y
CONFIG_SPL_STACK_R=y
CONFIG_SPL_SEPARATE_BSS=y
CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_USE_SECTOR=y
CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR=0x1400
CONFIG_SPL_I2C_SUPPORT=y
CONFIG_SPL_DM_MAILBOX=y
CONFIG_SPL_DM_RESET=y
@ -30,35 +32,41 @@ CONFIG_SPL_REMOTEPROC=y
CONFIG_SPL_YMODEM_SUPPORT=y
CONFIG_CMD_ASKENV=y
# CONFIG_CMD_FLASH is not set
CONFIG_CMD_GPT=y
CONFIG_CMD_I2C=y
CONFIG_CMD_MMC=y
CONFIG_CMD_REMOTEPROC=y
# CONFIG_CMD_SETEXPR is not set
CONFIG_CMD_TIME=y
# CONFIG_ISO_PARTITION is not set
# CONFIG_EFI_PARTITION is not set
CONFIG_OF_CONTROL=y
CONFIG_SPL_OF_CONTROL=y
CONFIG_DEFAULT_DEVICE_TREE="k3-am654-base-board"
CONFIG_SPL_MULTI_DTB_FIT=y
CONFIG_SPL_MULTI_DTB_FIT_NO_COMPRESSION=y
CONFIG_ENV_IS_IN_FAT=y
CONFIG_ENV_FAT_INTERFACE="mmc"
CONFIG_ENV_FAT_DEVICE_AND_PART="1:1"
CONFIG_ENV_IS_IN_MMC=y
CONFIG_NET_RANDOM_ETHADDR=y
CONFIG_DM=y
CONFIG_SPL_DM=y
CONFIG_SPL_DM_SEQ_ALIAS=y
CONFIG_REGMAP=y
CONFIG_SPL_REGMAP=y
CONFIG_CLK=y
CONFIG_SPL_CLK=y
CONFIG_CLK_TI_SCI=y
CONFIG_DMA_CHANNELS=y
CONFIG_TI_K3_NAVSS_UDMA=y
CONFIG_TI_SCI_PROTOCOL=y
CONFIG_DM_GPIO=y
CONFIG_DM_PCA953X=y
CONFIG_DM_I2C=y
CONFIG_I2C_SET_DEFAULT_BUS_NUM=y
CONFIG_SYS_I2C_OMAP24XX=y
CONFIG_DM_MAILBOX=y
CONFIG_K3_SEC_PROXY=y
CONFIG_DM_MMC=y
CONFIG_MMC_SDHCI=y
CONFIG_MMC_SDHCI_K3_ARASAN=y
CONFIG_MMC_SDHCI_AM654=y
CONFIG_PHY_TI=y
CONFIG_PHY_FIXED=y
CONFIG_DM_ETH=y
@ -80,3 +88,5 @@ CONFIG_SOC_TI=y
CONFIG_SYSRESET=y
CONFIG_SPL_SYSRESET=y
CONFIG_SYSRESET_TI_SCI=y
CONFIG_FAT_WRITE=y
CONFIG_OF_LIBFDT_OVERLAY=y

View File

@ -3,7 +3,7 @@ CONFIG_ARCH_K3=y
CONFIG_SPL_GPIO_SUPPORT=y
CONFIG_SPL_LIBCOMMON_SUPPORT=y
CONFIG_SPL_LIBGENERIC_SUPPORT=y
CONFIG_SYS_MALLOC_F_LEN=0x2000
CONFIG_SYS_MALLOC_F_LEN=0x55000
CONFIG_SOC_K3_AM6=y
CONFIG_TARGET_AM654_R5_EVM=y
CONFIG_SPL_MMC_SUPPORT=y
@ -18,9 +18,11 @@ CONFIG_SPL_LOAD_FIT=y
CONFIG_USE_BOOTCOMMAND=y
# CONFIG_DISPLAY_CPUINFO is not set
CONFIG_SPL_TEXT_BASE=0x41c00000
CONFIG_SPL_SYS_MALLOC_SIMPLE=y
CONFIG_SPL_STACK_R=y
CONFIG_SPL_SEPARATE_BSS=y
CONFIG_SPL_EARLY_BSS=y
CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_USE_SECTOR=y
CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR=0x400
CONFIG_SPL_I2C_SUPPORT=y
CONFIG_SPL_DM_MAILBOX=y
CONFIG_SPL_DM_RESET=y
@ -35,6 +37,7 @@ CONFIG_CMD_BOOTZ=y
CONFIG_CMD_ASKENV=y
# CONFIG_CMD_FLASH is not set
CONFIG_CMD_GPT=y
CONFIG_CMD_I2C=y
CONFIG_CMD_MMC=y
CONFIG_CMD_REMOTEPROC=y
# CONFIG_CMD_SETEXPR is not set
@ -51,6 +54,8 @@ CONFIG_ENV_FAT_DEVICE_AND_PART="1:1"
CONFIG_DM=y
CONFIG_SPL_DM=y
CONFIG_SPL_DM_SEQ_ALIAS=y
CONFIG_REGMAP=y
CONFIG_SPL_REGMAP=y
CONFIG_SPL_OF_TRANSLATE=y
CONFIG_CLK=y
CONFIG_SPL_CLK=y
@ -58,12 +63,15 @@ CONFIG_CLK_TI_SCI=y
CONFIG_TI_SCI_PROTOCOL=y
CONFIG_DM_GPIO=y
CONFIG_DA8XX_GPIO=y
CONFIG_DM_I2C=y
CONFIG_I2C_SET_DEFAULT_BUS_NUM=y
CONFIG_SYS_I2C_OMAP24XX=y
CONFIG_DM_MAILBOX=y
CONFIG_K3_SEC_PROXY=y
CONFIG_MISC=y
CONFIG_DM_MMC=y
CONFIG_MMC_SDHCI=y
CONFIG_MMC_SDHCI_K3_ARASAN=y
CONFIG_MMC_SDHCI_AM654=y
CONFIG_PINCTRL=y
# CONFIG_PINCTRL_GENERIC is not set
CONFIG_SPL_PINCTRL=y
@ -88,3 +96,4 @@ CONFIG_SYSRESET_TI_SCI=y
CONFIG_TIMER=y
CONFIG_SPL_TIMER=y
CONFIG_OMAP_TIMER=y
CONFIG_FS_FAT_MAX_CLUSTSIZE=16384

View File

@ -3,7 +3,7 @@ CONFIG_ARCH_K3=y
CONFIG_TI_SECURE_DEVICE=y
CONFIG_SPL_LIBCOMMON_SUPPORT=y
CONFIG_SPL_LIBGENERIC_SUPPORT=y
CONFIG_SYS_MALLOC_F_LEN=0x2000
CONFIG_SYS_MALLOC_F_LEN=0x8000
CONFIG_SOC_K3_AM6=y
CONFIG_TARGET_AM654_A53_EVM=y
CONFIG_SPL_MMC_SUPPORT=y
@ -19,12 +19,14 @@ CONFIG_FIT_IMAGE_POST_PROCESS=y
CONFIG_SPL_LOAD_FIT=y
CONFIG_SPL_FIT_IMAGE_POST_PROCESS=y
CONFIG_OF_BOARD_SETUP=y
CONFIG_BOOTCOMMAND="run findfdt; run envboot; run init_${boot}; run get_kern_${boot}; run get_fdt_${boot}; run run_kern"
CONFIG_BOOTCOMMAND="run findfdt; run envboot; run init_${boot}; run get_kern_${boot}; run get_fdt_${boot}; run get_overlay_${boot}; run run_kern"
# CONFIG_DISPLAY_CPUINFO is not set
CONFIG_SPL_TEXT_BASE=0x80080000
CONFIG_SPL_SYS_MALLOC_SIMPLE=y
CONFIG_SPL_STACK_R=y
CONFIG_SPL_SEPARATE_BSS=y
CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_USE_SECTOR=y
CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR=0x1400
CONFIG_SPL_I2C_SUPPORT=y
CONFIG_SPL_DM_MAILBOX=y
CONFIG_SPL_DM_RESET=y
@ -33,6 +35,7 @@ CONFIG_SPL_REMOTEPROC=y
CONFIG_SPL_YMODEM_SUPPORT=y
CONFIG_CMD_ASKENV=y
# CONFIG_CMD_FLASH is not set
CONFIG_CMD_I2C=y
CONFIG_CMD_MMC=y
CONFIG_CMD_REMOTEPROC=y
# CONFIG_CMD_SETEXPR is not set
@ -56,6 +59,11 @@ CONFIG_CLK_TI_SCI=y
CONFIG_DMA_CHANNELS=y
CONFIG_TI_K3_NAVSS_UDMA=y
CONFIG_TI_SCI_PROTOCOL=y
CONFIG_DM_GPIO=y
CONFIG_DM_PCA953X=y
CONFIG_DM_I2C=y
CONFIG_I2C_SET_DEFAULT_BUS_NUM=y
CONFIG_SYS_I2C_OMAP24XX=y
CONFIG_DM_MAILBOX=y
CONFIG_K3_SEC_PROXY=y
CONFIG_DM_MMC=y
@ -77,3 +85,4 @@ CONFIG_SOC_TI=y
CONFIG_SYSRESET=y
CONFIG_SPL_SYSRESET=y
CONFIG_SYSRESET_TI_SCI=y
CONFIG_OF_LIBFDT_OVERLAY=y

View File

@ -4,7 +4,7 @@ CONFIG_TI_SECURE_DEVICE=y
CONFIG_SPL_GPIO_SUPPORT=y
CONFIG_SPL_LIBCOMMON_SUPPORT=y
CONFIG_SPL_LIBGENERIC_SUPPORT=y
CONFIG_SYS_MALLOC_F_LEN=0x2000
CONFIG_SYS_MALLOC_F_LEN=0x55000
CONFIG_SOC_K3_AM6=y
CONFIG_TARGET_AM654_R5_EVM=y
CONFIG_SPL_MMC_SUPPORT=y
@ -20,9 +20,11 @@ CONFIG_SPL_FIT_IMAGE_POST_PROCESS=y
CONFIG_USE_BOOTCOMMAND=y
# CONFIG_DISPLAY_CPUINFO is not set
CONFIG_SPL_TEXT_BASE=0x41c00000
CONFIG_SPL_SYS_MALLOC_SIMPLE=y
CONFIG_SPL_STACK_R=y
CONFIG_SPL_SEPARATE_BSS=y
CONFIG_SPL_EARLY_BSS=y
CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_USE_SECTOR=y
CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR=0x400
CONFIG_SPL_I2C_SUPPORT=y
CONFIG_SPL_DM_MAILBOX=y
CONFIG_SPL_DM_RESET=y
@ -37,6 +39,7 @@ CONFIG_CMD_BOOTZ=y
CONFIG_CMD_ASKENV=y
# CONFIG_CMD_FLASH is not set
CONFIG_CMD_GPT=y
CONFIG_CMD_I2C=y
CONFIG_CMD_MMC=y
CONFIG_CMD_REMOTEPROC=y
# CONFIG_CMD_SETEXPR is not set
@ -60,6 +63,9 @@ CONFIG_CLK_TI_SCI=y
CONFIG_TI_SCI_PROTOCOL=y
CONFIG_DM_GPIO=y
CONFIG_DA8XX_GPIO=y
CONFIG_DM_I2C=y
CONFIG_I2C_SET_DEFAULT_BUS_NUM=y
CONFIG_SYS_I2C_OMAP24XX=y
CONFIG_DM_MAILBOX=y
CONFIG_K3_SEC_PROXY=y
CONFIG_MISC=y
@ -90,3 +96,4 @@ CONFIG_SYSRESET_TI_SCI=y
CONFIG_TIMER=y
CONFIG_SPL_TIMER=y
CONFIG_OMAP_TIMER=y
CONFIG_FS_FAT_MAX_CLUSTSIZE=16384

View File

@ -108,6 +108,48 @@ static int init_range(ofnode node, struct regmap_range *range, int addr_len,
return 0;
}
int regmap_init_mem_index(ofnode node, struct regmap **mapp, int index)
{
struct regmap *map;
int addr_len, size_len;
int ret;
addr_len = ofnode_read_simple_addr_cells(ofnode_get_parent(node));
if (addr_len < 0) {
debug("%s: Error while reading the addr length (ret = %d)\n",
ofnode_get_name(node), addr_len);
return addr_len;
}
size_len = ofnode_read_simple_size_cells(ofnode_get_parent(node));
if (size_len < 0) {
debug("%s: Error while reading the size length: (ret = %d)\n",
ofnode_get_name(node), size_len);
return size_len;
}
map = regmap_alloc(1);
if (!map)
return -ENOMEM;
ret = init_range(node, map->ranges, addr_len, size_len, index);
if (ret)
return ret;
if (ofnode_read_bool(node, "little-endian"))
map->endianness = REGMAP_LITTLE_ENDIAN;
else if (ofnode_read_bool(node, "big-endian"))
map->endianness = REGMAP_BIG_ENDIAN;
else if (ofnode_read_bool(node, "native-endian"))
map->endianness = REGMAP_NATIVE_ENDIAN;
else /* Default: native endianness */
map->endianness = REGMAP_NATIVE_ENDIAN;
*mapp = map;
return ret;
}
int regmap_init_mem(ofnode node, struct regmap **mapp)
{
struct regmap_range *range;

View File

@ -330,7 +330,7 @@ endif
config SYS_I2C_OMAP24XX
bool "TI OMAP2+ I2C driver"
depends on ARCH_OMAP2PLUS
depends on ARCH_OMAP2PLUS || ARCH_K3
help
Add support for the OMAP2+ I2C driver.

View File

@ -468,14 +468,15 @@ config MMC_SDHCI_CADENCE
If unsure, say N.
config MMC_SDHCI_K3_ARASAN
bool "Arasan SDHCI controller for TI's K3 based SoCs"
config MMC_SDHCI_AM654
bool "SDHCI Controller on TI's Am654 devices"
depends on ARCH_K3
depends on MMC_SDHCI
depends on DM_MMC && OF_CONTROL && BLK
depends on REGMAP
help
Support for Arasan SDHCI host controller on Texas Instruments'
K3 family based SoC platforms
Support for Secure Digital Host Controller Interface (SDHCI)
controllers present on TI's AM654 SOCs.
config MMC_SDHCI_KONA
bool "SDHCI support on Broadcom KONA platform"

View File

@ -50,7 +50,7 @@ obj-$(CONFIG_MMC_SDHCI_ATMEL) += atmel_sdhci.o
obj-$(CONFIG_MMC_SDHCI_BCM2835) += bcm2835_sdhci.o
obj-$(CONFIG_MMC_SDHCI_BCMSTB) += bcmstb_sdhci.o
obj-$(CONFIG_MMC_SDHCI_CADENCE) += sdhci-cadence.o
obj-$(CONFIG_MMC_SDHCI_K3_ARASAN) += k3_arsan_sdhci.o
obj-$(CONFIG_MMC_SDHCI_AM654) += am654_sdhci.o
obj-$(CONFIG_MMC_SDHCI_KONA) += kona_sdhci.o
obj-$(CONFIG_MMC_SDHCI_MSM) += msm_sdhci.o
obj-$(CONFIG_MMC_SDHCI_MV) += mv_sdhci.o

333
drivers/mmc/am654_sdhci.c Normal file
View File

@ -0,0 +1,333 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/
*
* Texas Instruments' K3 SD Host Controller Interface
*/
#include <clk.h>
#include <common.h>
#include <dm.h>
#include <malloc.h>
#include <power-domain.h>
#include <regmap.h>
#include <sdhci.h>
/* CTL_CFG Registers */
#define CTL_CFG_2 0x14
#define SLOTTYPE_MASK GENMASK(31, 30)
#define SLOTTYPE_EMBEDDED BIT(30)
/* PHY Registers */
#define PHY_CTRL1 0x100
#define PHY_CTRL2 0x104
#define PHY_CTRL3 0x108
#define PHY_CTRL4 0x10C
#define PHY_CTRL5 0x110
#define PHY_CTRL6 0x114
#define PHY_STAT1 0x130
#define PHY_STAT2 0x134
#define IOMUX_ENABLE_SHIFT 31
#define IOMUX_ENABLE_MASK BIT(IOMUX_ENABLE_SHIFT)
#define OTAPDLYENA_SHIFT 20
#define OTAPDLYENA_MASK BIT(OTAPDLYENA_SHIFT)
#define OTAPDLYSEL_SHIFT 12
#define OTAPDLYSEL_MASK GENMASK(15, 12)
#define STRBSEL_SHIFT 24
#define STRBSEL_MASK GENMASK(27, 24)
#define SEL50_SHIFT 8
#define SEL50_MASK BIT(SEL50_SHIFT)
#define SEL100_SHIFT 9
#define SEL100_MASK BIT(SEL100_SHIFT)
#define DLL_TRIM_ICP_SHIFT 4
#define DLL_TRIM_ICP_MASK GENMASK(7, 4)
#define DR_TY_SHIFT 20
#define DR_TY_MASK GENMASK(22, 20)
#define ENDLL_SHIFT 1
#define ENDLL_MASK BIT(ENDLL_SHIFT)
#define DLLRDY_SHIFT 0
#define DLLRDY_MASK BIT(DLLRDY_SHIFT)
#define PDB_SHIFT 0
#define PDB_MASK BIT(PDB_SHIFT)
#define CALDONE_SHIFT 1
#define CALDONE_MASK BIT(CALDONE_SHIFT)
#define RETRIM_SHIFT 17
#define RETRIM_MASK BIT(RETRIM_SHIFT)
#define DRIVER_STRENGTH_50_OHM 0x0
#define DRIVER_STRENGTH_33_OHM 0x1
#define DRIVER_STRENGTH_66_OHM 0x2
#define DRIVER_STRENGTH_100_OHM 0x3
#define DRIVER_STRENGTH_40_OHM 0x4
#define AM654_SDHCI_MIN_FREQ 400000
struct am654_sdhci_plat {
struct mmc_config cfg;
struct mmc mmc;
struct regmap *base;
bool non_removable;
u32 otap_del_sel;
u32 trm_icp;
u32 drv_strength;
bool dll_on;
};
static void am654_sdhci_set_control_reg(struct sdhci_host *host)
{
struct mmc *mmc = (struct mmc *)host->mmc;
u32 reg;
if (IS_SD(host->mmc) &&
mmc->signal_voltage == MMC_SIGNAL_VOLTAGE_180) {
reg = sdhci_readw(host, SDHCI_HOST_CONTROL2);
reg |= SDHCI_CTRL_VDD_180;
sdhci_writew(host, reg, SDHCI_HOST_CONTROL2);
}
sdhci_set_uhs_timing(host);
}
static int am654_sdhci_set_ios_post(struct sdhci_host *host)
{
struct udevice *dev = host->mmc->dev;
struct am654_sdhci_plat *plat = dev_get_platdata(dev);
unsigned int speed = host->mmc->clock;
int sel50, sel100;
u32 mask, val;
int ret;
/* Reset SD Clock Enable */
val = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
val &= ~SDHCI_CLOCK_CARD_EN;
sdhci_writew(host, val, SDHCI_CLOCK_CONTROL);
/* power off phy */
if (plat->dll_on) {
regmap_update_bits(plat->base, PHY_CTRL1, ENDLL_MASK, 0);
plat->dll_on = false;
}
/* restart clock */
sdhci_set_clock(host->mmc, speed);
/* switch phy back on */
if (speed > AM654_SDHCI_MIN_FREQ) {
mask = OTAPDLYENA_MASK | OTAPDLYSEL_MASK;
val = (1 << OTAPDLYENA_SHIFT) |
(plat->otap_del_sel << OTAPDLYSEL_SHIFT);
regmap_update_bits(plat->base, PHY_CTRL4, mask, val);
switch (speed) {
case 200000000:
sel50 = 0;
sel100 = 0;
break;
case 100000000:
sel50 = 0;
sel100 = 1;
break;
default:
sel50 = 1;
sel100 = 0;
}
/* Configure PHY DLL frequency */
mask = SEL50_MASK | SEL100_MASK;
val = (sel50 << SEL50_SHIFT) | (sel100 << SEL100_SHIFT);
regmap_update_bits(plat->base, PHY_CTRL5, mask, val);
/* Enable DLL */
regmap_update_bits(plat->base, PHY_CTRL1, ENDLL_MASK,
0x1 << ENDLL_SHIFT);
/*
* Poll for DLL ready. Use a one second timeout.
* Works in all experiments done so far
*/
ret = regmap_read_poll_timeout(plat->base, PHY_STAT1, val,
val & DLLRDY_MASK, 1000, 1000000);
if (ret)
return ret;
plat->dll_on = true;
}
return 0;
}
const struct sdhci_ops am654_sdhci_ops = {
.set_ios_post = &am654_sdhci_set_ios_post,
.set_control_reg = &am654_sdhci_set_control_reg,
};
int am654_sdhci_init(struct am654_sdhci_plat *plat)
{
u32 ctl_cfg_2 = 0;
u32 mask, val;
int ret;
/* Reset OTAP to default value */
mask = OTAPDLYENA_MASK | OTAPDLYSEL_MASK;
regmap_update_bits(plat->base, PHY_CTRL4, mask, 0x0);
regmap_read(plat->base, PHY_STAT1, &val);
if (~val & CALDONE_MASK) {
/* Calibrate IO lines */
regmap_update_bits(plat->base, PHY_CTRL1, PDB_MASK, PDB_MASK);
ret = regmap_read_poll_timeout(plat->base, PHY_STAT1, val,
val & CALDONE_MASK, 1, 20);
if (ret)
return ret;
}
/* Configure DLL TRIM */
mask = DLL_TRIM_ICP_MASK;
val = plat->trm_icp << DLL_TRIM_ICP_SHIFT;
/* Configure DLL driver strength */
mask |= DR_TY_MASK;
val |= plat->drv_strength << DR_TY_SHIFT;
regmap_update_bits(plat->base, PHY_CTRL1, mask, val);
/* Enable pins by setting IO mux to 0 */
regmap_update_bits(plat->base, PHY_CTRL1, IOMUX_ENABLE_MASK, 0);
/* Set slot type based on SD or eMMC */
if (plat->non_removable)
ctl_cfg_2 = SLOTTYPE_EMBEDDED;
regmap_update_bits(plat->base, CTL_CFG_2, SLOTTYPE_MASK, ctl_cfg_2);
return 0;
}
static int am654_sdhci_probe(struct udevice *dev)
{
struct am654_sdhci_plat *plat = dev_get_platdata(dev);
struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
struct sdhci_host *host = dev_get_priv(dev);
struct mmc_config *cfg = &plat->cfg;
struct power_domain sdhci_pwrdmn;
struct clk clk;
unsigned long clock;
int ret;
ret = power_domain_get_by_index(dev, &sdhci_pwrdmn, 0);
if (!ret) {
ret = power_domain_on(&sdhci_pwrdmn);
if (ret) {
dev_err(dev, "Power domain on failed (%d)\n", ret);
return ret;
}
} else if (ret != -ENOENT && ret != -ENODEV && ret != -ENOSYS) {
dev_err(dev, "failed to get power domain (%d)\n", ret);
return ret;
}
ret = clk_get_by_index(dev, 0, &clk);
if (ret) {
dev_err(dev, "failed to get clock\n");
return ret;
}
clock = clk_get_rate(&clk);
if (IS_ERR_VALUE(clock)) {
dev_err(dev, "failed to get rate\n");
return clock;
}
host->max_clk = clock;
host->mmc = &plat->mmc;
host->mmc->dev = dev;
ret = sdhci_setup_cfg(cfg, host, cfg->f_max,
AM654_SDHCI_MIN_FREQ);
if (ret)
return ret;
host->ops = &am654_sdhci_ops;
host->mmc->priv = host;
upriv->mmc = host->mmc;
regmap_init_mem_index(dev_ofnode(dev), &plat->base, 1);
am654_sdhci_init(plat);
return sdhci_probe(dev);
}
static int am654_sdhci_ofdata_to_platdata(struct udevice *dev)
{
struct am654_sdhci_plat *plat = dev_get_platdata(dev);
struct sdhci_host *host = dev_get_priv(dev);
struct mmc_config *cfg = &plat->cfg;
u32 drv_strength;
int ret;
host->name = dev->name;
host->ioaddr = (void *)dev_read_addr(dev);
plat->non_removable = dev_read_bool(dev, "non-removable");
ret = dev_read_u32(dev, "ti,trm-icp", &plat->trm_icp);
if (ret)
return ret;
ret = dev_read_u32(dev, "ti,otap-del-sel", &plat->otap_del_sel);
if (ret)
return ret;
ret = dev_read_u32(dev, "ti,driver-strength-ohm", &drv_strength);
if (ret)
return ret;
switch (drv_strength) {
case 50:
plat->drv_strength = DRIVER_STRENGTH_50_OHM;
break;
case 33:
plat->drv_strength = DRIVER_STRENGTH_33_OHM;
break;
case 66:
plat->drv_strength = DRIVER_STRENGTH_66_OHM;
break;
case 100:
plat->drv_strength = DRIVER_STRENGTH_100_OHM;
break;
case 40:
plat->drv_strength = DRIVER_STRENGTH_40_OHM;
break;
default:
dev_err(dev, "Invalid driver strength\n");
return -EINVAL;
}
ret = mmc_of_parse(dev, cfg);
if (ret)
return ret;
return 0;
}
static int am654_sdhci_bind(struct udevice *dev)
{
struct am654_sdhci_plat *plat = dev_get_platdata(dev);
return sdhci_bind(dev, &plat->mmc, &plat->cfg);
}
static const struct udevice_id am654_sdhci_ids[] = {
{ .compatible = "ti,am654-sdhci-5.1" },
{ }
};
U_BOOT_DRIVER(am654_sdhci_drv) = {
.name = "am654_sdhci",
.id = UCLASS_MMC,
.of_match = am654_sdhci_ids,
.ofdata_to_platdata = am654_sdhci_ofdata_to_platdata,
.ops = &sdhci_ops,
.bind = am654_sdhci_bind,
.probe = am654_sdhci_probe,
.priv_auto_alloc_size = sizeof(struct sdhci_host),
.platdata_auto_alloc_size = sizeof(struct am654_sdhci_plat),
};

View File

@ -1,109 +0,0 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/
*
* Texas Instruments' K3 SD Host Controller Interface
*/
#include <clk.h>
#include <common.h>
#include <dm.h>
#include <malloc.h>
#include <power-domain.h>
#include <sdhci.h>
#define K3_ARASAN_SDHCI_MIN_FREQ 0
struct k3_arasan_sdhci_plat {
struct mmc_config cfg;
struct mmc mmc;
unsigned int f_max;
};
static int k3_arasan_sdhci_probe(struct udevice *dev)
{
struct k3_arasan_sdhci_plat *plat = dev_get_platdata(dev);
struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
struct sdhci_host *host = dev_get_priv(dev);
struct power_domain sdhci_pwrdmn;
struct clk clk;
unsigned long clock;
int ret;
ret = power_domain_get_by_index(dev, &sdhci_pwrdmn, 0);
if (ret) {
dev_err(dev, "failed to get power domain\n");
return ret;
}
ret = power_domain_on(&sdhci_pwrdmn);
if (ret) {
dev_err(dev, "Power domain on failed\n");
return ret;
}
ret = clk_get_by_index(dev, 0, &clk);
if (ret) {
dev_err(dev, "failed to get clock\n");
return ret;
}
clock = clk_get_rate(&clk);
if (IS_ERR_VALUE(clock)) {
dev_err(dev, "failed to get rate\n");
return clock;
}
host->quirks = SDHCI_QUIRK_WAIT_SEND_CMD |
SDHCI_QUIRK_BROKEN_R1B;
host->max_clk = clock;
ret = sdhci_setup_cfg(&plat->cfg, host, plat->f_max,
K3_ARASAN_SDHCI_MIN_FREQ);
host->mmc = &plat->mmc;
if (ret)
return ret;
host->mmc->priv = host;
host->mmc->dev = dev;
upriv->mmc = host->mmc;
return sdhci_probe(dev);
}
static int k3_arasan_sdhci_ofdata_to_platdata(struct udevice *dev)
{
struct k3_arasan_sdhci_plat *plat = dev_get_platdata(dev);
struct sdhci_host *host = dev_get_priv(dev);
host->name = dev->name;
host->ioaddr = (void *)dev_read_addr(dev);
host->bus_width = dev_read_u32_default(dev, "bus-width", 4);
plat->f_max = dev_read_u32_default(dev, "max-frequency", 0);
return 0;
}
static int k3_arasan_sdhci_bind(struct udevice *dev)
{
struct k3_arasan_sdhci_plat *plat = dev_get_platdata(dev);
return sdhci_bind(dev, &plat->mmc, &plat->cfg);
}
static const struct udevice_id k3_arasan_sdhci_ids[] = {
{ .compatible = "arasan,sdhci-5.1" },
{ }
};
U_BOOT_DRIVER(k3_arasan_sdhci_drv) = {
.name = "k3_arasan_sdhci",
.id = UCLASS_MMC,
.of_match = k3_arasan_sdhci_ids,
.ofdata_to_platdata = k3_arasan_sdhci_ofdata_to_platdata,
.ops = &sdhci_ops,
.bind = k3_arasan_sdhci_bind,
.probe = k3_arasan_sdhci_probe,
.priv_auto_alloc_size = sizeof(struct sdhci_host),
.platdata_auto_alloc_size = sizeof(struct k3_arasan_sdhci_plat),
};

View File

@ -8,6 +8,7 @@
*/
#include <common.h>
#include <dm.h>
#include <errno.h>
#include <malloc.h>
#include <mmc.h>
@ -409,7 +410,7 @@ static int sdhci_execute_tuning(struct udevice *dev, uint opcode)
return 0;
}
#endif
static int sdhci_set_clock(struct mmc *mmc, unsigned int clock)
int sdhci_set_clock(struct mmc *mmc, unsigned int clock)
{
struct sdhci_host *host = mmc->priv;
unsigned int div, clk = 0, timeout;
@ -533,6 +534,34 @@ static void sdhci_set_power(struct sdhci_host *host, unsigned short power)
sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL);
}
void sdhci_set_uhs_timing(struct sdhci_host *host)
{
struct mmc *mmc = (struct mmc *)host->mmc;
u32 reg;
reg = sdhci_readw(host, SDHCI_HOST_CONTROL2);
reg &= ~SDHCI_CTRL_UHS_MASK;
switch (mmc->selected_mode) {
case UHS_SDR50:
case MMC_HS_52:
reg |= SDHCI_CTRL_UHS_SDR50;
break;
case UHS_DDR50:
case MMC_DDR_52:
reg |= SDHCI_CTRL_UHS_DDR50;
break;
case UHS_SDR104:
case MMC_HS_200:
reg |= SDHCI_CTRL_UHS_SDR104;
break;
default:
reg |= SDHCI_CTRL_UHS_SDR12;
}
sdhci_writew(host, reg, SDHCI_HOST_CONTROL2);
}
#ifdef CONFIG_DM_MMC
static int sdhci_set_ios(struct udevice *dev)
{
@ -583,7 +612,7 @@ static int sdhci_set_ios(struct mmc *mmc)
/* If available, call the driver specific "post" set_ios() function */
if (host->ops && host->ops->set_ios_post)
host->ops->set_ios_post(host);
return host->ops->set_ios_post(host);
return 0;
}
@ -681,8 +710,18 @@ int sdhci_setup_cfg(struct mmc_config *cfg, struct sdhci_host *host,
u32 f_max, u32 f_min)
{
u32 caps, caps_1 = 0;
#if CONFIG_IS_ENABLED(DM_MMC)
u32 mask[2] = {0};
int ret;
ret = dev_read_u32_array(host->mmc->dev, "sdhci-caps-mask",
mask, 2);
if (ret && ret != -1)
return ret;
caps = ~mask[1] & sdhci_readl(host, SDHCI_CAPABILITIES);
#else
caps = sdhci_readl(host, SDHCI_CAPABILITIES);
#endif
#ifdef CONFIG_MMC_SDHCI_SDMA
if (!(caps & SDHCI_CAN_DO_SDMA)) {
@ -722,7 +761,11 @@ int sdhci_setup_cfg(struct mmc_config *cfg, struct sdhci_host *host,
/* Check whether the clock multiplier is supported or not */
if (SDHCI_GET_VERSION(host) >= SDHCI_SPEC_300) {
#if CONFIG_IS_ENABLED(DM_MMC)
caps_1 = ~mask[0] & sdhci_readl(host, SDHCI_CAPABILITIES_1);
#else
caps_1 = sdhci_readl(host, SDHCI_CAPABILITIES_1);
#endif
host->clk_mul = (caps_1 & SDHCI_CLOCK_MUL_MASK) >>
SDHCI_CLOCK_MUL_SHIFT;
}
@ -779,9 +822,6 @@ int sdhci_setup_cfg(struct mmc_config *cfg, struct sdhci_host *host,
cfg->host_caps &= ~MMC_MODE_HS_52MHz;
}
if (SDHCI_GET_VERSION(host) >= SDHCI_SPEC_300)
caps_1 = sdhci_readl(host, SDHCI_CAPABILITIES_1);
if (!(cfg->voltages & MMC_VDD_165_195) ||
(host->quirks & SDHCI_QUIRK_NO_1_8_V))
caps_1 &= ~(SDHCI_SUPPORT_SDR104 | SDHCI_SUPPORT_SDR50 |

View File

@ -326,7 +326,7 @@ static void xenon_mask_cmd_conflict_err(struct sdhci_host *host)
}
/* Platform specific function for post set_ios configuration */
static void xenon_sdhci_set_ios_post(struct sdhci_host *host)
static int xenon_sdhci_set_ios_post(struct sdhci_host *host)
{
struct xenon_sdhci_priv *priv = host->mmc->priv;
uint speed = host->mmc->tran_speed;
@ -364,6 +364,8 @@ static void xenon_sdhci_set_ios_post(struct sdhci_host *host)
/* Re-init the PHY */
xenon_mmc_phy_set(host);
return 0;
}
/* Install a driver specific handler for post set_ios configuration */

View File

@ -48,11 +48,6 @@ static const u8 mode2timing[] = {
[MMC_HS_200] = MMC_HS200_BUS_SPEED,
};
#define SDHCI_HOST_CTRL2 0x3E
#define SDHCI_CTRL2_MODE_MASK 0x7
#define SDHCI_18V_SIGNAL 0x8
#define SDHCI_CTRL_EXEC_TUNING 0x0040
#define SDHCI_CTRL_TUNED_CLK 0x80
#define SDHCI_TUNING_LOOP_COUNT 40
static void arasan_zynqmp_dll_reset(struct sdhci_host *host, u8 deviceid)
@ -99,9 +94,9 @@ static int arasan_sdhci_execute_tuning(struct mmc *mmc, u8 opcode)
host = priv->host;
deviceid = priv->deviceid;
ctrl = sdhci_readw(host, SDHCI_HOST_CTRL2);
ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
ctrl |= SDHCI_CTRL_EXEC_TUNING;
sdhci_writew(host, ctrl, SDHCI_HOST_CTRL2);
sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
mdelay(1);
@ -133,7 +128,7 @@ static int arasan_sdhci_execute_tuning(struct mmc *mmc, u8 opcode)
sdhci_writew(host, SDHCI_TRNS_READ, SDHCI_TRANSFER_MODE);
mmc_send_cmd(mmc, &cmd, NULL);
ctrl = sdhci_readw(host, SDHCI_HOST_CTRL2);
ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
if (cmd.cmdidx == MMC_CMD_SEND_TUNING_BLOCK)
udelay(1);
@ -142,7 +137,7 @@ static int arasan_sdhci_execute_tuning(struct mmc *mmc, u8 opcode)
if (tuning_loop_counter < 0) {
ctrl &= ~SDHCI_CTRL_TUNED_CLK;
sdhci_writel(host, ctrl, SDHCI_HOST_CTRL2);
sdhci_writel(host, ctrl, SDHCI_HOST_CONTROL2);
}
if (!(ctrl & SDHCI_CTRL_TUNED_CLK)) {
@ -184,36 +179,14 @@ static void arasan_sdhci_set_control_reg(struct sdhci_host *host)
return;
if (mmc->signal_voltage == MMC_SIGNAL_VOLTAGE_180) {
reg = sdhci_readw(host, SDHCI_HOST_CTRL2);
reg |= SDHCI_18V_SIGNAL;
sdhci_writew(host, reg, SDHCI_HOST_CTRL2);
reg = sdhci_readw(host, SDHCI_HOST_CONTROL2);
reg |= SDHCI_CTRL_VDD_180;
sdhci_writew(host, reg, SDHCI_HOST_CONTROL2);
}
if (mmc->selected_mode > SD_HS &&
mmc->selected_mode <= UHS_DDR50) {
reg = sdhci_readw(host, SDHCI_HOST_CTRL2);
reg &= ~SDHCI_CTRL2_MODE_MASK;
switch (mmc->selected_mode) {
case UHS_SDR12:
reg |= UHS_SDR12_BUS_SPEED;
break;
case UHS_SDR25:
reg |= UHS_SDR25_BUS_SPEED;
break;
case UHS_SDR50:
reg |= UHS_SDR50_BUS_SPEED;
break;
case UHS_SDR104:
reg |= UHS_SDR104_BUS_SPEED;
break;
case UHS_DDR50:
reg |= UHS_DDR50_BUS_SPEED;
break;
default:
break;
}
sdhci_writew(host, reg, SDHCI_HOST_CTRL2);
}
mmc->selected_mode <= UHS_DDR50)
sdhci_set_uhs_timing(host);
}
#endif

View File

@ -19,6 +19,32 @@
#define CONFIG_SYS_SDRAM_BASE1 0x880000000
/* SPL Loader Configuration */
#ifdef CONFIG_TARGET_AM654_A53_EVM
#define CONFIG_SYS_INIT_SP_ADDR (CONFIG_SPL_TEXT_BASE + \
CONFIG_SYS_K3_NON_SECURE_MSRAM_SIZE)
#else
/*
* Maximum size in memory allocated to the SPL BSS. Keep it as tight as
* possible (to allow the build to go through), as this directly affects
* our memory footprint. The less we use for BSS the more we have available
* for everything else.
*/
#define CONFIG_SPL_BSS_MAX_SIZE 0x5000
/*
* Link BSS to be within SPL in a dedicated region located near the top of
* the MCU SRAM, this way making it available also before relocation. Note
* that we are not using the actual top of the MCU SRAM as there is a memory
* location filled in by the boot ROM that we want to read out without any
* interference from the C context.
*/
#define CONFIG_SPL_BSS_START_ADDR (CONFIG_SYS_K3_BOOT_PARAM_TABLE_INDEX -\
CONFIG_SPL_BSS_MAX_SIZE)
/* Set the stack right below the SPL BSS section */
#define CONFIG_SYS_INIT_SP_ADDR CONFIG_SPL_BSS_START_ADDR
/* Configure R5 SPL post-relocation malloc pool in DDR */
#define CONFIG_SYS_SPL_MALLOC_START 0x84000000
#define CONFIG_SYS_SPL_MALLOC_SIZE SZ_16M
#endif
#ifdef CONFIG_SYS_K3_SPL_ATF
#define CONFIG_SPL_FS_LOAD_PAYLOAD_NAME "tispl.bin"
@ -29,26 +55,26 @@
#endif
#define CONFIG_SPL_MAX_SIZE CONFIG_SYS_K3_MAX_DOWNLODABLE_IMAGE_SIZE
#define CONFIG_SYS_INIT_SP_ADDR (CONFIG_SPL_TEXT_BASE + \
CONFIG_SYS_K3_NON_SECURE_MSRAM_SIZE - 4)
#define CONFIG_SYS_BOOTM_LEN SZ_64M
#define PARTS_DEFAULT \
/* Linux partitions */ \
"name=rootfs,start=0,size=-,uuid=${uuid_gpt_rootfs}\0"
/* U-Boot general configuration */
#define EXTRA_ENV_AM65X_BOARD_SETTINGS \
"findfdt=" \
"if test $board_name = am65x; then " \
"setenv name_fdt k3-am654-base-board.dtb; " \
"else if test $name_fdt = undefined; then " \
"echo WARNING: Could not determine device tree to use;"\
"fi; fi; " \
"setenv fdtfile ${name_fdt}\0" \
"setenv name_fdt k3-am654-base-board.dtb;" \
"setenv fdtfile ${name_fdt};" \
"setenv overlay_files ${name_overlays}\0" \
"loadaddr=0x80080000\0" \
"fdtaddr=0x82000000\0" \
"overlayaddr=0x83000000\0" \
"name_kern=Image\0" \
"console=ttyS2,115200n8\0" \
"args_all=setenv optargs earlycon=ns16550a,mmio32,0x02800000\0" \
"run_kern=booti ${loadaddr} ${rd_spec} ${fdtaddr}\0"
"run_kern=booti ${loadaddr} ${rd_spec} ${fdtaddr}\0" \
/* U-Boot MMC-specific configuration */
#define EXTRA_ENV_AM65X_BOARD_SETTINGS_MMC \
@ -59,8 +85,17 @@
"rd_spec=-\0" \
"init_mmc=run args_all args_mmc\0" \
"get_fdt_mmc=load mmc ${bootpart} ${fdtaddr} ${bootdir}/${name_fdt}\0" \
"get_overlay_mmc=" \
"fdt address ${fdtaddr};" \
"fdt resize 0x100000;" \
"for overlay in $overlay_files;" \
"do;" \
"load mmc ${bootpart} ${overlayaddr} ${bootdir}/${overlay};" \
"fdt apply ${overlayaddr};" \
"done;\0" \
"get_kern_mmc=load mmc ${bootpart} ${loadaddr} " \
"${bootdir}/${name_kern}\0"
"${bootdir}/${name_kern}\0" \
"partitions=" PARTS_DEFAULT
/* Incorporate settings into the U-Boot environment */
#define CONFIG_EXTRA_ENV_SETTINGS \
@ -68,6 +103,18 @@
EXTRA_ENV_AM65X_BOARD_SETTINGS \
EXTRA_ENV_AM65X_BOARD_SETTINGS_MMC
/* MMC ENV related defines */
#ifdef CONFIG_ENV_IS_IN_MMC
#define CONFIG_SYS_MMC_ENV_DEV 0
#define CONFIG_SYS_MMC_ENV_PART 1
#define CONFIG_ENV_SIZE (128 << 10)
#define CONFIG_ENV_OFFSET 0x680000
#define CONFIG_ENV_OFFSET_REDUND (CONFIG_ENV_OFFSET + CONFIG_ENV_SIZE)
#define CONFIG_SYS_REDUNDAND_ENVIRONMENT
#endif
#define CONFIG_SUPPORT_EMMC_BOOT
/* Now for the remaining common defines */
#include <configs/ti_armv7_common.h>

View File

@ -330,6 +330,8 @@ int regmap_init_mem(ofnode node, struct regmap **mapp);
int regmap_init_mem_platdata(struct udevice *dev, fdt_val_t *reg, int count,
struct regmap **mapp);
int regmap_init_mem_index(ofnode node, struct regmap **mapp, int index);
/**
* regmap_get_range() - Obtain the base memory address of a regmap range
*

View File

@ -144,7 +144,23 @@
#define SDHCI_ACMD12_ERR 0x3C
/* 3E-3F reserved */
#define SDHCI_HOST_CONTROL2 0x3E
#define SDHCI_CTRL_UHS_MASK 0x0007
#define SDHCI_CTRL_UHS_SDR12 0x0000
#define SDHCI_CTRL_UHS_SDR25 0x0001
#define SDHCI_CTRL_UHS_SDR50 0x0002
#define SDHCI_CTRL_UHS_SDR104 0x0003
#define SDHCI_CTRL_UHS_DDR50 0x0004
#define SDHCI_CTRL_HS400 0x0005 /* Non-standard */
#define SDHCI_CTRL_VDD_180 0x0008
#define SDHCI_CTRL_DRV_TYPE_MASK 0x0030
#define SDHCI_CTRL_DRV_TYPE_B 0x0000
#define SDHCI_CTRL_DRV_TYPE_A 0x0010
#define SDHCI_CTRL_DRV_TYPE_C 0x0020
#define SDHCI_CTRL_DRV_TYPE_D 0x0030
#define SDHCI_CTRL_EXEC_TUNING 0x0040
#define SDHCI_CTRL_TUNED_CLK 0x0080
#define SDHCI_CTRL_PRESET_VAL_ENABLE 0x8000
#define SDHCI_CAPABILITIES 0x40
#define SDHCI_TIMEOUT_CLK_MASK 0x0000003F
@ -247,7 +263,7 @@ struct sdhci_ops {
#endif
int (*get_cd)(struct sdhci_host *host);
void (*set_control_reg)(struct sdhci_host *host);
void (*set_ios_post)(struct sdhci_host *host);
int (*set_ios_post)(struct sdhci_host *host);
void (*set_clock)(struct sdhci_host *host, u32 div);
int (*platform_execute_tuning)(struct mmc *host, u8 opcode);
void (*set_delay)(struct sdhci_host *host);
@ -467,9 +483,11 @@ int sdhci_bind(struct udevice *dev, struct mmc *mmc, struct mmc_config *cfg);
int add_sdhci(struct sdhci_host *host, u32 f_max, u32 f_min);
#endif /* !CONFIG_BLK */
void sdhci_set_uhs_timing(struct sdhci_host *host);
#ifdef CONFIG_DM_MMC
/* Export the operations to drivers */
int sdhci_probe(struct udevice *dev);
int sdhci_set_clock(struct mmc *mmc, unsigned int clock);
extern const struct dm_mmc_ops sdhci_ops;
#else
#endif

View File

@ -108,6 +108,15 @@ struct spl_load_info {
*/
binman_sym_extern(ulong, u_boot_any, image_pos);
/**
* spl_load_simple_fit_skip_processing() - Hook to allow skipping the FIT
* image processing during spl_load_simple_fit().
*
* Return true to skip FIT processing, false to preserve the full code flow
* of spl_load_simple_fit().
*/
bool spl_load_simple_fit_skip_processing(void);
/**
* spl_load_simple_fit() - Loads a fit image from a device.
* @spl_image: Image description to set up
@ -330,6 +339,23 @@ int spl_dfu_cmd(int usbctrl, char *dfu_alt_info, char *interface, char *devstr);
int spl_mmc_load_image(struct spl_image_info *spl_image,
struct spl_boot_device *bootdev);
/**
* spl_mmc_load() - Load an image file from MMC/SD media
*
* @param spl_image Image data filled in by loading process
* @param bootdev Describes which device to load from
* @param filename Name of file to load (in FS mode)
* @param raw_part Partition to load from (in RAW mode)
* @param raw_sect Sector to load from (in RAW mode)
*
* @return 0 on success, otherwise error code
*/
int spl_mmc_load(struct spl_image_info *spl_image,
struct spl_boot_device *bootdev,
const char *filename,
int raw_part,
unsigned long raw_sect);
/**
* spl_invoke_atf - boot using an ARM trusted firmware image
*/