diff options
Diffstat (limited to 'board')
48 files changed, 3000 insertions, 122 deletions
diff --git a/board/AndesTech/adp-ae3xx/adp-ae3xx.c b/board/AndesTech/adp-ae3xx/adp-ae3xx.c index 8cffb6b..52a89dc 100644 --- a/board/AndesTech/adp-ae3xx/adp-ae3xx.c +++ b/board/AndesTech/adp-ae3xx/adp-ae3xx.c @@ -12,7 +12,6 @@ #include <netdev.h> #endif #include <linux/io.h> -#include <faraday/ftsdc010.h> #include <faraday/ftsmc020.h> DECLARE_GLOBAL_DATA_PTR; @@ -75,13 +74,3 @@ ulong board_flash_get_legacy(ulong base, int banknum, flash_info_t *info) return 0; } } - -int board_mmc_init(bd_t *bis) -{ -#ifndef CONFIG_DM_MMC -#ifdef CONFIG_FTSDC010 - ftsdc010_mmc_init(0); -#endif -#endif - return 0; -} diff --git a/board/AndesTech/adp-ag101p/adp-ag101p.c b/board/AndesTech/adp-ag101p/adp-ag101p.c index f918c63..82928e7 100644 --- a/board/AndesTech/adp-ag101p/adp-ag101p.c +++ b/board/AndesTech/adp-ag101p/adp-ag101p.c @@ -14,7 +14,6 @@ #include <asm/io.h> #include <asm/mach-types.h> -#include <faraday/ftsdc010.h> #include <faraday/ftsmc020.h> DECLARE_GLOBAL_DATA_PTR; @@ -82,13 +81,3 @@ ulong board_flash_get_legacy(ulong base, int banknum, flash_info_t *info) return 0; } } - -int board_mmc_init(bd_t *bis) -{ -#ifndef CONFIG_DM_MMC -#ifdef CONFIG_FTSDC010 - ftsdc010_mmc_init(0); -#endif -#endif - return 0; -} diff --git a/board/AndesTech/nx25-ae250/nx25-ae250.c b/board/AndesTech/nx25-ae250/nx25-ae250.c index 12f2d35..6e31be3 100644 --- a/board/AndesTech/nx25-ae250/nx25-ae250.c +++ b/board/AndesTech/nx25-ae250/nx25-ae250.c @@ -11,7 +11,6 @@ #include <netdev.h> #endif #include <linux/io.h> -#include <faraday/ftsdc010.h> DECLARE_GLOBAL_DATA_PTR; @@ -66,12 +65,11 @@ ulong board_flash_get_legacy(ulong base, int banknum, flash_info_t *info) return 0; } -int board_mmc_init(bd_t *bis) +void *board_fdt_blob_setup(void) { -#ifndef CONFIG_DM_MMC -#ifdef CONFIG_FTSDC010 - ftsdc010_mmc_init(0); -#endif -#endif - return 0; + void **ptr = (void *)CONFIG_SYS_SDRAM_BASE; + if (fdt_magic(*ptr) == FDT_MAGIC) + return (void *)*ptr; + + return (void *)CONFIG_SYS_FDT_BASE; } diff --git a/board/Marvell/mvebu_armada-37xx/board.c b/board/Marvell/mvebu_armada-37xx/board.c index ac3e3a3..e205396 100644 --- a/board/Marvell/mvebu_armada-37xx/board.c +++ b/board/Marvell/mvebu_armada-37xx/board.c @@ -50,29 +50,6 @@ DECLARE_GLOBAL_DATA_PTR; int board_early_init_f(void) { - const void *blob = gd->fdt_blob; - const char *bank_name; - const char *compat = "marvell,armada-3700-pinctl"; - int off, len; - void __iomem *addr; - - /* FIXME - * Temporary WA for setting correct pin control values - * until the real pin control driver is awailable. - */ - off = fdt_node_offset_by_compatible(blob, -1, compat); - while (off != -FDT_ERR_NOTFOUND) { - bank_name = fdt_getprop(blob, off, "bank-name", &len); - addr = (void __iomem *)fdtdec_get_addr_size_auto_noparent( - blob, off, "reg", 0, NULL, true); - if (!strncmp(bank_name, "armada-3700-nb", len)) - writel(PINCTRL_NB_REG_VALUE, addr); - else if (!strncmp(bank_name, "armada-3700-sb", len)) - writel(PINCTRL_SB_REG_VALUE, addr); - - off = fdt_node_offset_by_compatible(blob, off, compat); - } - return 0; } diff --git a/board/freescale/ls1012afrdm/Kconfig b/board/freescale/ls1012afrdm/Kconfig index 38bd91b..22d521b 100644 --- a/board/freescale/ls1012afrdm/Kconfig +++ b/board/freescale/ls1012afrdm/Kconfig @@ -12,6 +12,35 @@ config SYS_SOC config SYS_CONFIG_NAME default "ls1012afrdm" +if FSL_PFE + +config BOARD_SPECIFIC_OPTIONS # dummy + def_bool y + select PHYLIB + imply PHY_REALTEK + +config SYS_LS_PFE_FW_ADDR + hex "Flash address of PFE firmware" + default 0x40a00000 + +config DDR_PFE_PHYS_BASEADDR + hex "PFE DDR physical base address" + default 0x03800000 + +config DDR_PFE_BASEADDR + hex "PFE DDR base address" + default 0x83800000 + +config PFE_EMAC1_PHY_ADDR + hex "PFE DDR base address" + default 0x2 + +config PFE_EMAC2_PHY_ADDR + hex "PFE DDR base address" + default 0x1 + +endif + source "board/freescale/common/Kconfig" endif diff --git a/board/freescale/ls1012afrdm/Makefile b/board/freescale/ls1012afrdm/Makefile index dbfa2ce..1e53c96 100644 --- a/board/freescale/ls1012afrdm/Makefile +++ b/board/freescale/ls1012afrdm/Makefile @@ -5,3 +5,4 @@ # obj-y += ls1012afrdm.o +obj-$(CONFIG_FSL_PFE) += eth.o diff --git a/board/freescale/ls1012afrdm/eth.c b/board/freescale/ls1012afrdm/eth.c new file mode 100644 index 0000000..cc6deb2 --- /dev/null +++ b/board/freescale/ls1012afrdm/eth.c @@ -0,0 +1,124 @@ +/* + * Copyright 2015-2016 Freescale Semiconductor, Inc. + * Copyright 2017 NXP + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <dm.h> +#include <asm/io.h> +#include <netdev.h> +#include <fm_eth.h> +#include <fsl_mdio.h> +#include <malloc.h> +#include <asm/types.h> +#include <fsl_dtsec.h> +#include <asm/arch/soc.h> +#include <asm/arch-fsl-layerscape/config.h> +#include <asm/arch-fsl-layerscape/immap_lsch2.h> +#include <asm/arch/fsl_serdes.h> +#include <net/pfe_eth/pfe_eth.h> +#include <dm/platform_data/pfe_dm_eth.h> + +#define DEFAULT_PFE_MDIO_NAME "PFE_MDIO" +#define DEFAULT_PFE_MDIO1_NAME "PFE_MDIO1" + +#define MASK_ETH_PHY_RST 0x00000100 + +static inline void ls1012afrdm_reset_phy(void) +{ + unsigned int val; + struct ccsr_gpio *pgpio = (void *)(GPIO1_BASE_ADDR); + + setbits_be32(&pgpio->gpdir, MASK_ETH_PHY_RST); + + val = in_be32(&pgpio->gpdat); + setbits_be32(&pgpio->gpdat, val & ~MASK_ETH_PHY_RST); + mdelay(10); + + val = in_be32(&pgpio->gpdat); + setbits_be32(&pgpio->gpdat, val | MASK_ETH_PHY_RST); + mdelay(50); +} + +int pfe_eth_board_init(struct udevice *dev) +{ + static int init_done; + struct mii_dev *bus; + struct pfe_mdio_info mac_mdio_info; + struct pfe_eth_dev *priv = dev_get_priv(dev); + + if (!init_done) { + ls1012afrdm_reset_phy(); + + mac_mdio_info.reg_base = (void *)EMAC1_BASE_ADDR; + mac_mdio_info.name = DEFAULT_PFE_MDIO_NAME; + + bus = pfe_mdio_init(&mac_mdio_info); + if (!bus) { + printf("Failed to register mdio\n"); + return -1; + } + + init_done = 1; + } + + if (priv->gemac_port) { + mac_mdio_info.reg_base = (void *)EMAC2_BASE_ADDR; + mac_mdio_info.name = DEFAULT_PFE_MDIO1_NAME; + bus = pfe_mdio_init(&mac_mdio_info); + if (!bus) { + printf("Failed to register mdio\n"); + return -1; + } + } + + pfe_set_mdio(priv->gemac_port, + miiphy_get_dev_by_name(DEFAULT_PFE_MDIO_NAME)); + if (!priv->gemac_port) + /* MAC1 */ + pfe_set_phy_address_mode(priv->gemac_port, + CONFIG_PFE_EMAC1_PHY_ADDR, + PHY_INTERFACE_MODE_SGMII); + else + /* MAC2 */ + pfe_set_phy_address_mode(priv->gemac_port, + CONFIG_PFE_EMAC2_PHY_ADDR, + PHY_INTERFACE_MODE_SGMII); + return 0; +} + +static struct pfe_eth_pdata pfe_pdata0 = { + .pfe_eth_pdata_mac = { + .iobase = (phys_addr_t)EMAC1_BASE_ADDR, + .phy_interface = 0, + }, + + .pfe_ddr_addr = { + .ddr_pfe_baseaddr = (void *)CONFIG_DDR_PFE_BASEADDR, + .ddr_pfe_phys_baseaddr = CONFIG_DDR_PFE_PHYS_BASEADDR, + }, +}; + +static struct pfe_eth_pdata pfe_pdata1 = { + .pfe_eth_pdata_mac = { + .iobase = (phys_addr_t)EMAC2_BASE_ADDR, + .phy_interface = 1, + }, + + .pfe_ddr_addr = { + .ddr_pfe_baseaddr = (void *)CONFIG_DDR_PFE_BASEADDR, + .ddr_pfe_phys_baseaddr = CONFIG_DDR_PFE_PHYS_BASEADDR, + }, +}; + +U_BOOT_DEVICE(ls1012a_pfe0) = { + .name = "pfe_eth", + .platdata = &pfe_pdata0, +}; + +U_BOOT_DEVICE(ls1012a_pfe1) = { + .name = "pfe_eth", + .platdata = &pfe_pdata1, +}; diff --git a/board/freescale/ls1012afrdm/ls1012afrdm.c b/board/freescale/ls1012afrdm/ls1012afrdm.c index 9afd1c4..0145886 100644 --- a/board/freescale/ls1012afrdm/ls1012afrdm.c +++ b/board/freescale/ls1012afrdm/ls1012afrdm.c @@ -57,11 +57,6 @@ int dram_init(void) return 0; } -int board_eth_init(bd_t *bis) -{ - return pci_eth_init(bis); -} - int board_early_init_f(void) { fsl_lsch2_early_init_f(); diff --git a/board/freescale/ls1012aqds/Kconfig b/board/freescale/ls1012aqds/Kconfig index fc9250b..c0b12ed 100644 --- a/board/freescale/ls1012aqds/Kconfig +++ b/board/freescale/ls1012aqds/Kconfig @@ -12,6 +12,51 @@ config SYS_SOC config SYS_CONFIG_NAME default "ls1012aqds" + +if FSL_PFE + +config BOARD_SPECIFIC_OPTIONS # dummy + def_bool y + select PHYLIB + imply PHY_VITESSE + imply PHY_REALTEK + imply PHY_AQUANTIA + imply PHYLIB_10G + +config PFE_RGMII_RESET_WA + def_bool y + +config SYS_LS_PFE_FW_ADDR + hex "Flash address of PFE firmware" + default 0x40a00000 + +config DDR_PFE_PHYS_BASEADDR + hex "PFE DDR physical base address" + default 0x03800000 + +config DDR_PFE_BASEADDR + hex "PFE DDR base address" + default 0x83800000 + +config PFE_EMAC1_PHY_ADDR + hex "PFE DDR base address" + default 0x1e + +config PFE_EMAC2_PHY_ADDR + hex "PFE DDR base address" + default 0x1 + +config PFE_SGMII_2500_PHY1_ADDR + hex "PFE DDR base address" + default 0x1 + +config PFE_SGMII_2500_PHY2_ADDR + hex "PFE DDR base address" + default 0x2 + +endif + + source "board/freescale/common/Kconfig" endif diff --git a/board/freescale/ls1012aqds/Makefile b/board/freescale/ls1012aqds/Makefile index 0b813f9..5aba9ca 100644 --- a/board/freescale/ls1012aqds/Makefile +++ b/board/freescale/ls1012aqds/Makefile @@ -5,3 +5,4 @@ # obj-y += ls1012aqds.o +obj-$(CONFIG_FSL_PFE) += eth.o diff --git a/board/freescale/ls1012aqds/eth.c b/board/freescale/ls1012aqds/eth.c new file mode 100644 index 0000000..f8026a2 --- /dev/null +++ b/board/freescale/ls1012aqds/eth.c @@ -0,0 +1,309 @@ +/* + * Copyright 2015-2016 Freescale Semiconductor, Inc. + * Copyright 2017 NXP + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <dm.h> +#include <asm/io.h> +#include <netdev.h> +#include <fm_eth.h> +#include <fsl_mdio.h> +#include <malloc.h> +#include <asm/types.h> +#include <fsl_dtsec.h> +#include <asm/arch/soc.h> +#include <asm/arch-fsl-layerscape/config.h> +#include <asm/arch-fsl-layerscape/immap_lsch2.h> +#include <asm/arch/fsl_serdes.h> +#include "../common/qixis.h" +#include <net/pfe_eth/pfe_eth.h> +#include <dm/platform_data/pfe_dm_eth.h> +#include "ls1012aqds_qixis.h" + +#define EMI_NONE 0xFF +#define EMI1_RGMII 1 +#define EMI1_SLOT1 2 +#define EMI1_SLOT2 3 + +#define DEFAULT_PFE_MDIO_NAME "PFE_MDIO" +#define DEFAULT_PFE_MDIO1_NAME "PFE_MDIO1" + +static const char * const mdio_names[] = { + "NULL", + "LS1012AQDS_MDIO_RGMII", + "LS1012AQDS_MDIO_SLOT1", + "LS1012AQDS_MDIO_SLOT2", + "NULL", +}; + +static const char *ls1012aqds_mdio_name_for_muxval(u8 muxval) +{ + return mdio_names[muxval]; +} + +struct ls1012aqds_mdio { + u8 muxval; + struct mii_dev *realbus; +}; + +static void ls1012aqds_mux_mdio(u8 muxval) +{ + u8 brdcfg4; + + if (muxval < 7) { + brdcfg4 = QIXIS_READ(brdcfg[4]); + brdcfg4 &= ~BRDCFG4_EMISEL_MASK; + brdcfg4 |= (muxval << BRDCFG4_EMISEL_SHIFT); + QIXIS_WRITE(brdcfg[4], brdcfg4); + } +} + +static int ls1012aqds_mdio_read(struct mii_dev *bus, int addr, int devad, + int regnum) +{ + struct ls1012aqds_mdio *priv = bus->priv; + + ls1012aqds_mux_mdio(priv->muxval); + + return priv->realbus->read(priv->realbus, addr, devad, regnum); +} + +static int ls1012aqds_mdio_write(struct mii_dev *bus, int addr, int devad, + int regnum, u16 value) +{ + struct ls1012aqds_mdio *priv = bus->priv; + + ls1012aqds_mux_mdio(priv->muxval); + + return priv->realbus->write(priv->realbus, addr, devad, regnum, value); +} + +static int ls1012aqds_mdio_reset(struct mii_dev *bus) +{ + struct ls1012aqds_mdio *priv = bus->priv; + + if (priv->realbus->reset) + return priv->realbus->reset(priv->realbus); + else + return -1; +} + +static int ls1012aqds_mdio_init(char *realbusname, u8 muxval) +{ + struct ls1012aqds_mdio *pmdio; + struct mii_dev *bus = mdio_alloc(); + + if (!bus) { + printf("Failed to allocate ls1012aqds MDIO bus\n"); + return -1; + } + + pmdio = malloc(sizeof(*pmdio)); + if (!pmdio) { + printf("Failed to allocate ls1012aqds private data\n"); + free(bus); + return -1; + } + + bus->read = ls1012aqds_mdio_read; + bus->write = ls1012aqds_mdio_write; + bus->reset = ls1012aqds_mdio_reset; + sprintf(bus->name, ls1012aqds_mdio_name_for_muxval(muxval)); + + pmdio->realbus = miiphy_get_dev_by_name(realbusname); + + if (!pmdio->realbus) { + printf("No bus with name %s\n", realbusname); + free(bus); + free(pmdio); + return -1; + } + + pmdio->muxval = muxval; + bus->priv = pmdio; + return mdio_register(bus); +} + +int pfe_eth_board_init(struct udevice *dev) +{ + static int init_done; + struct mii_dev *bus; + static const char *mdio_name; + struct pfe_mdio_info mac_mdio_info; + struct ccsr_gur __iomem *gur = (void *)CONFIG_SYS_FSL_GUTS_ADDR; + u8 data8; + struct pfe_eth_dev *priv = dev_get_priv(dev); + + int srds_s1 = in_be32(&gur->rcwsr[4]) & + FSL_CHASSIS2_RCWSR4_SRDS1_PRTCL_MASK; + srds_s1 >>= FSL_CHASSIS2_RCWSR4_SRDS1_PRTCL_SHIFT; + + ls1012aqds_mux_mdio(EMI1_SLOT1); + + if (!init_done) { + mac_mdio_info.reg_base = (void *)EMAC1_BASE_ADDR; + mac_mdio_info.name = DEFAULT_PFE_MDIO_NAME; + + bus = pfe_mdio_init(&mac_mdio_info); + if (!bus) { + printf("Failed to register mdio\n"); + return -1; + } + init_done = 1; + } + + if (priv->gemac_port) { + mac_mdio_info.reg_base = (void *)EMAC2_BASE_ADDR; + mac_mdio_info.name = DEFAULT_PFE_MDIO1_NAME; + + bus = pfe_mdio_init(&mac_mdio_info); + if (!bus) { + printf("Failed to register mdio\n"); + return -1; + } + } + + switch (srds_s1) { + case 0x3508: + printf("ls1012aqds:supported SerDes PRCTL= %d\n", srds_s1); +#ifdef CONFIG_PFE_RGMII_RESET_WA + /* + * Work around for FPGA registers initialization + * This is needed for RGMII to work. + */ + printf("Reset RGMII WA....\n"); + data8 = QIXIS_READ(rst_frc[0]); + data8 |= 0x2; + QIXIS_WRITE(rst_frc[0], data8); + data8 = QIXIS_READ(rst_frc[0]); + + data8 = QIXIS_READ(res8[6]); + data8 |= 0xff; + QIXIS_WRITE(res8[6], data8); + data8 = QIXIS_READ(res8[6]); +#endif + if (priv->gemac_port) { + mdio_name = ls1012aqds_mdio_name_for_muxval(EMI1_RGMII); + if (ls1012aqds_mdio_init(DEFAULT_PFE_MDIO_NAME, EMI1_RGMII) + < 0) { + printf("Failed to register mdio for %s\n", mdio_name); + } + + /* MAC2 */ + mdio_name = ls1012aqds_mdio_name_for_muxval(EMI1_RGMII); + bus = miiphy_get_dev_by_name(mdio_name); + pfe_set_mdio(priv->gemac_port, bus); + pfe_set_phy_address_mode(priv->gemac_port, + CONFIG_PFE_EMAC2_PHY_ADDR, + PHY_INTERFACE_MODE_RGMII); + + } else { + mdio_name = ls1012aqds_mdio_name_for_muxval(EMI1_SLOT1); + if (ls1012aqds_mdio_init(DEFAULT_PFE_MDIO_NAME, EMI1_SLOT1) + < 0) { + printf("Failed to register mdio for %s\n", mdio_name); + } + + /* MAC1 */ + mdio_name = ls1012aqds_mdio_name_for_muxval(EMI1_SLOT1); + bus = miiphy_get_dev_by_name(mdio_name); + pfe_set_mdio(priv->gemac_port, bus); + pfe_set_phy_address_mode(priv->gemac_port, + CONFIG_PFE_EMAC1_PHY_ADDR, + PHY_INTERFACE_MODE_SGMII); + } + + break; + + case 0x2205: + printf("ls1012aqds:supported SerDes PRCTL= %d\n", srds_s1); + /* + * Work around for FPGA registers initialization + * This is needed for RGMII to work. + */ + printf("Reset SLOT1 SLOT2....\n"); + data8 = QIXIS_READ(rst_frc[2]); + data8 |= 0xc0; + QIXIS_WRITE(rst_frc[2], data8); + mdelay(100); + data8 = QIXIS_READ(rst_frc[2]); + data8 &= 0x3f; + QIXIS_WRITE(rst_frc[2], data8); + + if (priv->gemac_port) { + mdio_name = ls1012aqds_mdio_name_for_muxval(EMI1_SLOT2); + if (ls1012aqds_mdio_init(DEFAULT_PFE_MDIO_NAME, EMI1_SLOT2) + < 0) { + printf("Failed to register mdio for %s\n", mdio_name); + } + /* MAC2 */ + mdio_name = ls1012aqds_mdio_name_for_muxval(EMI1_SLOT2); + bus = miiphy_get_dev_by_name(mdio_name); + pfe_set_mdio(1, bus); + pfe_set_phy_address_mode(1, CONFIG_PFE_SGMII_2500_PHY2_ADDR, + PHY_INTERFACE_MODE_SGMII_2500); + + data8 = QIXIS_READ(brdcfg[12]); + data8 |= 0x20; + QIXIS_WRITE(brdcfg[12], data8); + + } else { + mdio_name = ls1012aqds_mdio_name_for_muxval(EMI1_SLOT1); + if (ls1012aqds_mdio_init(DEFAULT_PFE_MDIO_NAME, EMI1_SLOT1) + < 0) { + printf("Failed to register mdio for %s\n", mdio_name); + } + + /* MAC1 */ + mdio_name = ls1012aqds_mdio_name_for_muxval(EMI1_SLOT1); + bus = miiphy_get_dev_by_name(mdio_name); + pfe_set_mdio(0, bus); + pfe_set_phy_address_mode(0, + CONFIG_PFE_SGMII_2500_PHY1_ADDR, + PHY_INTERFACE_MODE_SGMII_2500); + } + break; + + default: + printf("ls1012aqds:unsupported SerDes PRCTL= %d\n", srds_s1); + break; + } + return 0; +} + +static struct pfe_eth_pdata pfe_pdata0 = { + .pfe_eth_pdata_mac = { + .iobase = (phys_addr_t)EMAC1_BASE_ADDR, + .phy_interface = 0, + }, + + .pfe_ddr_addr = { + .ddr_pfe_baseaddr = (void *)CONFIG_DDR_PFE_BASEADDR, + .ddr_pfe_phys_baseaddr = CONFIG_DDR_PFE_PHYS_BASEADDR, + }, +}; + +static struct pfe_eth_pdata pfe_pdata1 = { + .pfe_eth_pdata_mac = { + .iobase = (phys_addr_t)EMAC2_BASE_ADDR, + .phy_interface = 1, + }, + + .pfe_ddr_addr = { + .ddr_pfe_baseaddr = (void *)CONFIG_DDR_PFE_BASEADDR, + .ddr_pfe_phys_baseaddr = CONFIG_DDR_PFE_PHYS_BASEADDR, + }, +}; + +U_BOOT_DEVICE(ls1012a_pfe0) = { + .name = "pfe_eth", + .platdata = &pfe_pdata0, +}; + +U_BOOT_DEVICE(ls1012a_pfe1) = { + .name = "pfe_eth", + .platdata = &pfe_pdata1, +}; diff --git a/board/freescale/ls1012aqds/ls1012aqds.c b/board/freescale/ls1012aqds/ls1012aqds.c index 406194d..4577917 100644 --- a/board/freescale/ls1012aqds/ls1012aqds.c +++ b/board/freescale/ls1012aqds/ls1012aqds.c @@ -25,9 +25,9 @@ #include <fsl_mmdc.h> #include <spl.h> #include <netdev.h> - #include "../common/qixis.h" #include "ls1012aqds_qixis.h" +#include "ls1012aqds_pfe.h" DECLARE_GLOBAL_DATA_PTR; @@ -128,11 +128,6 @@ int board_init(void) return 0; } -int board_eth_init(bd_t *bis) -{ - return pci_eth_init(bis); -} - int esdhc_status_fixup(void *blob, const char *compat) { char esdhc0_path[] = "/soc/esdhc@1560000"; @@ -161,12 +156,102 @@ int esdhc_status_fixup(void *blob, const char *compat) return 0; } +static int pfe_set_properties(void *set_blob, struct pfe_prop_val prop_val, + char *enet_path, char *mdio_path) +{ + do_fixup_by_path(set_blob, enet_path, "fsl,gemac-bus-id", + &prop_val.busid, PFE_PROP_LEN, 1); + do_fixup_by_path(set_blob, enet_path, "fsl,gemac-phy-id", + &prop_val.phyid, PFE_PROP_LEN, 1); + do_fixup_by_path(set_blob, enet_path, "fsl,mdio-mux-val", + &prop_val.mux_val, PFE_PROP_LEN, 1); + do_fixup_by_path(set_blob, enet_path, "phy-mode", + prop_val.phy_mode, strlen(prop_val.phy_mode) + 1, 1); + do_fixup_by_path(set_blob, mdio_path, "fsl,mdio-phy-mask", + &prop_val.phy_mask, PFE_PROP_LEN, 1); + return 0; +} + +static void fdt_fsl_fixup_of_pfe(void *blob) +{ + int i = 0; + struct pfe_prop_val prop_val; + void *l_blob = blob; + + struct ccsr_gur __iomem *gur = (void *)CONFIG_SYS_FSL_GUTS_ADDR; + unsigned int srds_s1 = in_be32(&gur->rcwsr[4]) & + FSL_CHASSIS2_RCWSR4_SRDS1_PRTCL_MASK; + srds_s1 >>= FSL_CHASSIS2_RCWSR4_SRDS1_PRTCL_SHIFT; + + for (i = 0; i < NUM_ETH_NODE; i++) { + switch (srds_s1) { + case SERDES_1_G_PROTOCOL: + if (i == 0) { + prop_val.busid = cpu_to_fdt32( + ETH_1_1G_BUS_ID); + prop_val.phyid = cpu_to_fdt32( + ETH_1_1G_PHY_ID); + prop_val.mux_val = cpu_to_fdt32( + ETH_1_1G_MDIO_MUX); + prop_val.phy_mask = cpu_to_fdt32( + ETH_1G_MDIO_PHY_MASK); + prop_val.phy_mode = "sgmii"; + pfe_set_properties(l_blob, prop_val, ETH_1_PATH, + ETH_1_MDIO); + } else { + prop_val.busid = cpu_to_fdt32( + ETH_2_1G_BUS_ID); + prop_val.phyid = cpu_to_fdt32( + ETH_2_1G_PHY_ID); + prop_val.mux_val = cpu_to_fdt32( + ETH_2_1G_MDIO_MUX); + prop_val.phy_mask = cpu_to_fdt32( + ETH_1G_MDIO_PHY_MASK); + prop_val.phy_mode = "rgmii"; + pfe_set_properties(l_blob, prop_val, ETH_2_PATH, + ETH_2_MDIO); + } + break; + case SERDES_2_5_G_PROTOCOL: + if (i == 0) { + prop_val.busid = cpu_to_fdt32( + ETH_1_2_5G_BUS_ID); + prop_val.phyid = cpu_to_fdt32( + ETH_1_2_5G_PHY_ID); + prop_val.mux_val = cpu_to_fdt32( + ETH_1_2_5G_MDIO_MUX); + prop_val.phy_mask = cpu_to_fdt32( + ETH_2_5G_MDIO_PHY_MASK); + prop_val.phy_mode = "sgmii-2500"; + pfe_set_properties(l_blob, prop_val, ETH_1_PATH, + ETH_1_MDIO); + } else { + prop_val.busid = cpu_to_fdt32( + ETH_2_2_5G_BUS_ID); + prop_val.phyid = cpu_to_fdt32( + ETH_2_2_5G_PHY_ID); + prop_val.mux_val = cpu_to_fdt32( + ETH_2_2_5G_MDIO_MUX); + prop_val.phy_mask = cpu_to_fdt32( + ETH_2_5G_MDIO_PHY_MASK); + prop_val.phy_mode = "sgmii-2500"; + pfe_set_properties(l_blob, prop_val, ETH_2_PATH, + ETH_2_MDIO); + } + break; + default: + printf("serdes:[%d]\n", srds_s1); + } + } +} + #ifdef CONFIG_OF_BOARD_SETUP int ft_board_setup(void *blob, bd_t *bd) { arch_fixup_fdt(blob); ft_cpu_setup(blob, bd); + fdt_fsl_fixup_of_pfe(blob); return 0; } diff --git a/board/freescale/ls1012aqds/ls1012aqds_pfe.h b/board/freescale/ls1012aqds/ls1012aqds_pfe.h new file mode 100644 index 0000000..b06f722 --- /dev/null +++ b/board/freescale/ls1012aqds/ls1012aqds_pfe.h @@ -0,0 +1,45 @@ +/* + * Copyright 2017 NXP + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#define ETH_1_1G_BUS_ID 0x1 +#define ETH_1_1G_PHY_ID 0x1e +#define ETH_1_1G_MDIO_MUX 0x2 +#define ETH_1G_MDIO_PHY_MASK 0xBFFFFFFD +#define ETH_1_1G_PHY_MODE "sgmii" +#define ETH_2_1G_BUS_ID 0x1 +#define ETH_2_1G_PHY_ID 0x1 +#define ETH_2_1G_MDIO_MUX 0x1 +#define ETH_2_1G_PHY_MODE "rgmii" + +#define ETH_1_2_5G_BUS_ID 0x0 +#define ETH_1_2_5G_PHY_ID 0x1 +#define ETH_1_2_5G_MDIO_MUX 0x2 +#define ETH_2_5G_MDIO_PHY_MASK 0xFFFFFFF9 +#define ETH_2_5G_PHY_MODE "sgmii-2500" +#define ETH_2_2_5G_BUS_ID 0x1 +#define ETH_2_2_5G_PHY_ID 0x2 +#define ETH_2_2_5G_MDIO_MUX 0x3 + +#define SERDES_1_G_PROTOCOL 0x3508 +#define SERDES_2_5_G_PROTOCOL 0x2205 + +#define PFE_PROP_LEN 4 + +#define ETH_1_PATH "/pfe@04000000/ethernet@0" +#define ETH_1_MDIO ETH_1_PATH "/mdio@0" + +#define ETH_2_PATH "/pfe@04000000/ethernet@1" +#define ETH_2_MDIO ETH_2_PATH "/mdio@0" + +#define NUM_ETH_NODE 2 + +struct pfe_prop_val { + int busid; + int phyid; + int mux_val; + int phy_mask; + char *phy_mode; +}; diff --git a/board/freescale/ls1012aqds/ls1012aqds_qixis.h b/board/freescale/ls1012aqds/ls1012aqds_qixis.h index 584f604..7a1ba3d 100644 --- a/board/freescale/ls1012aqds/ls1012aqds_qixis.h +++ b/board/freescale/ls1012aqds/ls1012aqds_qixis.h @@ -11,7 +11,7 @@ /* BRDCFG4[4:7] select EC1 and EC2 as a pair */ #define BRDCFG4_EMISEL_MASK 0xe0 -#define BRDCFG4_EMISEL_SHIFT 5 +#define BRDCFG4_EMISEL_SHIFT 6 /* SYSCLK */ #define QIXIS_SYSCLK_66 0x0 diff --git a/board/freescale/ls1012ardb/Kconfig b/board/freescale/ls1012ardb/Kconfig index d13b08e..493d477 100644 --- a/board/freescale/ls1012ardb/Kconfig +++ b/board/freescale/ls1012ardb/Kconfig @@ -12,6 +12,35 @@ config SYS_SOC config SYS_CONFIG_NAME default "ls1012ardb" +if FSL_PFE + +config BOARD_SPECIFIC_OPTIONS # dummy + def_bool y + select PHYLIB + imply PHY_REALTEK + +config SYS_LS_PFE_FW_ADDR + hex "Flash address of PFE firmware" + default 0x40a00000 + +config DDR_PFE_PHYS_BASEADDR + hex "PFE DDR physical base address" + default 0x03800000 + +config DDR_PFE_BASEADDR + hex "PFE DDR base address" + default 0x83800000 + +config PFE_EMAC1_PHY_ADDR + hex "PFE DDR base address" + default 0x2 + +config PFE_EMAC2_PHY_ADDR + hex "PFE DDR base address" + default 0x1 + +endif + source "board/freescale/common/Kconfig" endif @@ -30,6 +59,36 @@ config SYS_SOC config SYS_CONFIG_NAME default "ls1012a2g5rdb" +if FSL_PFE + +config BOARD_SPECIFIC_OPTIONS # dummy + def_bool y + select PHYLIB + imply CONFIG_PHYLIB_10G + imply CONFIG_PHY_AQUANTIA + +config SYS_LS_PFE_FW_ADDR + hex "Flash address of PFE firmware" + default 0x40a00000 + +config DDR_PFE_PHYS_BASEADDR + hex "PFE DDR physical base address" + default 0x03800000 + +config DDR_PFE_BASEADDR + hex "PFE DDR base address" + default 0x83800000 + +config PFE_EMAC1_PHY_ADDR + hex "PFE DDR base address" + default 0x2 + +config PFE_EMAC2_PHY_ADDR + hex "PFE DDR base address" + default 0x1 + +endif + source "board/freescale/common/Kconfig" endif diff --git a/board/freescale/ls1012ardb/Makefile b/board/freescale/ls1012ardb/Makefile index 05fa9d9..70c7b33 100644 --- a/board/freescale/ls1012ardb/Makefile +++ b/board/freescale/ls1012ardb/Makefile @@ -5,3 +5,4 @@ # obj-y += ls1012ardb.o +obj-$(CONFIG_FSL_PFE) += eth.o diff --git a/board/freescale/ls1012ardb/eth.c b/board/freescale/ls1012ardb/eth.c new file mode 100644 index 0000000..8e6cd0a --- /dev/null +++ b/board/freescale/ls1012ardb/eth.c @@ -0,0 +1,135 @@ +/* + * Copyright 2015-2016 Freescale Semiconductor, Inc. + * Copyright 2017 NXP + * + * SPDX-License-Identifier:GPL-2.0+ + */ + +#include <common.h> +#include <dm.h> +#include <asm/io.h> +#include <netdev.h> +#include <fm_eth.h> +#include <fsl_mdio.h> +#include <malloc.h> +#include <asm/types.h> +#include <fsl_dtsec.h> +#include <asm/arch/soc.h> +#include <asm/arch-fsl-layerscape/config.h> +#include <asm/arch-fsl-layerscape/immap_lsch2.h> +#include <asm/arch/fsl_serdes.h> +#include <net/pfe_eth/pfe_eth.h> +#include <dm/platform_data/pfe_dm_eth.h> +#include <i2c.h> + +#define DEFAULT_PFE_MDIO_NAME "PFE_MDIO" + +static inline void ls1012ardb_reset_phy(void) +{ +#ifdef CONFIG_TARGET_LS1012ARDB + /* Through reset IO expander reset both RGMII and SGMII PHYs */ + i2c_reg_write(I2C_MUX_IO2_ADDR, 6, __PHY_MASK); + i2c_reg_write(I2C_MUX_IO2_ADDR, 2, __PHY_ETH2_MASK); + mdelay(10); + i2c_reg_write(I2C_MUX_IO2_ADDR, 2, __PHY_ETH1_MASK); + mdelay(10); + i2c_reg_write(I2C_MUX_IO2_ADDR, 2, 0xFF); + mdelay(50); +#endif +} + +int pfe_eth_board_init(struct udevice *dev) +{ + static int init_done; + struct mii_dev *bus; + struct pfe_mdio_info mac_mdio_info; + struct pfe_eth_dev *priv = dev_get_priv(dev); + struct ccsr_gur __iomem *gur = (void *)CONFIG_SYS_FSL_GUTS_ADDR; + + int srds_s1 = in_be32(&gur->rcwsr[4]) & + FSL_CHASSIS2_RCWSR4_SRDS1_PRTCL_MASK; + srds_s1 >>= FSL_CHASSIS2_RCWSR4_SRDS1_PRTCL_SHIFT; + + if (!init_done) { + ls1012ardb_reset_phy(); + mac_mdio_info.reg_base = (void *)EMAC1_BASE_ADDR; + mac_mdio_info.name = DEFAULT_PFE_MDIO_NAME; + + bus = pfe_mdio_init(&mac_mdio_info); + if (!bus) { + printf("Failed to register mdio\n"); + return -1; + } + init_done = 1; + } + + pfe_set_mdio(priv->gemac_port, + miiphy_get_dev_by_name(DEFAULT_PFE_MDIO_NAME)); + + switch (srds_s1) { + case 0x3508: + if (!priv->gemac_port) { + /* MAC1 */ + pfe_set_phy_address_mode(priv->gemac_port, + CONFIG_PFE_EMAC1_PHY_ADDR, + PHY_INTERFACE_MODE_SGMII); + } else { + /* MAC2 */ + pfe_set_phy_address_mode(priv->gemac_port, + CONFIG_PFE_EMAC2_PHY_ADDR, + PHY_INTERFACE_MODE_RGMII_TXID); + } + break; + case 0x2208: + if (!priv->gemac_port) { + /* MAC1 */ + pfe_set_phy_address_mode(priv->gemac_port, + CONFIG_PFE_EMAC1_PHY_ADDR, + PHY_INTERFACE_MODE_SGMII_2500); + } else { + /* MAC2 */ + pfe_set_phy_address_mode(priv->gemac_port, + CONFIG_PFE_EMAC2_PHY_ADDR, + PHY_INTERFACE_MODE_SGMII_2500); + } + break; + default: + printf("unsupported SerDes PRCTL= %d\n", srds_s1); + break; + } + return 0; +} + +static struct pfe_eth_pdata pfe_pdata0 = { + .pfe_eth_pdata_mac = { + .iobase = (phys_addr_t)EMAC1_BASE_ADDR, + .phy_interface = 0, + }, + + .pfe_ddr_addr = { + .ddr_pfe_baseaddr = (void *)CONFIG_DDR_PFE_BASEADDR, + .ddr_pfe_phys_baseaddr = CONFIG_DDR_PFE_PHYS_BASEADDR, + }, +}; + +static struct pfe_eth_pdata pfe_pdata1 = { + .pfe_eth_pdata_mac = { + .iobase = (phys_addr_t)EMAC2_BASE_ADDR, + .phy_interface = 1, + }, + + .pfe_ddr_addr = { + .ddr_pfe_baseaddr = (void *)CONFIG_DDR_PFE_BASEADDR, + .ddr_pfe_phys_baseaddr = CONFIG_DDR_PFE_PHYS_BASEADDR, + }, +}; + +U_BOOT_DEVICE(ls1012a_pfe0) = { + .name = "pfe_eth", + .platdata = &pfe_pdata0, +}; + +U_BOOT_DEVICE(ls1012a_pfe1) = { + .name = "pfe_eth", + .platdata = &pfe_pdata1, +}; diff --git a/board/freescale/ls1012ardb/ls1012ardb.c b/board/freescale/ls1012ardb/ls1012ardb.c index c9557bb..ed5a8e6 100644 --- a/board/freescale/ls1012ardb/ls1012ardb.c +++ b/board/freescale/ls1012ardb/ls1012ardb.c @@ -114,10 +114,6 @@ int dram_init(void) return 0; } -int board_eth_init(bd_t *bis) -{ - return pci_eth_init(bis); -} int board_early_init_f(void) { diff --git a/board/freescale/ls1088a/MAINTAINERS b/board/freescale/ls1088a/MAINTAINERS index 371e5db..4d804d9 100644 --- a/board/freescale/ls1088a/MAINTAINERS +++ b/board/freescale/ls1088a/MAINTAINERS @@ -15,6 +15,8 @@ F: board/freescale/ls1088a/ F: include/configs/ls1088aqds.h F: configs/ls1088aqds_qspi_defconfig F: configs/ls1088aqds_sdcard_qspi_defconfig +F: configs/ls1088aqds_defconfig +F: configs/ls1088aqds_sdcard_ifc_defconfig LS1088AQDS_QSPI_SECURE_BOOT BOARD M: Udit Agarwal <udit.agarwal@nxp.com> diff --git a/board/freescale/ls1088a/ls1088a.c b/board/freescale/ls1088a/ls1088a.c index 56e454f..a5fa050 100644 --- a/board/freescale/ls1088a/ls1088a.c +++ b/board/freescale/ls1088a/ls1088a.c @@ -31,6 +31,9 @@ DECLARE_GLOBAL_DATA_PTR; int board_early_init_f(void) { +#if defined(CONFIG_SYS_I2C_EARLY_INIT) && defined(CONFIG_TARGET_LS1088AQDS) + i2c_early_init_f(); +#endif fsl_lsch3_early_init_f(); return 0; } @@ -168,6 +171,7 @@ int checkboard(void) return 0; } +#endif bool if_board_diff_clk(void) { @@ -221,7 +225,6 @@ unsigned long get_board_ddr_clk(void) return 66666666; } -#endif int select_i2c_ch_pca9547(u8 ch) { diff --git a/board/micronas/vct/scc.c b/board/micronas/vct/scc.c index 0d33cc4..8dbf410 100644 --- a/board/micronas/vct/scc.c +++ b/board/micronas/vct/scc.c @@ -524,12 +524,14 @@ int scc_setup_dma(enum scc_id id, u32 buffer_tag, struct scc_dma_state *dma_state; int return_value = 0; union scc_dma_cfg dma_cfg; - u32 *buffer_tag_list = scc_descriptor_table[id].buffer_tag_list; + u32 *buffer_tag_list; u32 tag_count, t, t_valid; if ((id >= SCC_MAX) || (id < 0)) return -EINVAL; + buffer_tag_list = scc_descriptor_table[id].buffer_tag_list; + /* if the register is only configured by hw, cannot write! */ if (1 == scc_descriptor_table[id].hw_dma_cfg) return -EACCES; diff --git a/board/netgear/dgnd3700v2/Kconfig b/board/netgear/dgnd3700v2/Kconfig new file mode 100644 index 0000000..11af188 --- /dev/null +++ b/board/netgear/dgnd3700v2/Kconfig @@ -0,0 +1,12 @@ +if BOARD_NETGEAR_DGND3700V2 + +config SYS_BOARD + default "dgnd3700v2" + +config SYS_VENDOR + default "netgear" + +config SYS_CONFIG_NAME + default "netgear_dgnd3700v2" + +endif diff --git a/board/netgear/dgnd3700v2/MAINTAINERS b/board/netgear/dgnd3700v2/MAINTAINERS new file mode 100644 index 0000000..998077b --- /dev/null +++ b/board/netgear/dgnd3700v2/MAINTAINERS @@ -0,0 +1,6 @@ +NETGEAR DGND3700V2 BOARD +M: Ãlvaro Fernández Rojas <noltari@gmail.com> +S: Maintained +F: board/netgear/dgnd3700v2/ +F: include/configs/netgear_dgnd3700v2.h +F: configs/netgear_dgnd3700v2_ram_defconfig diff --git a/board/netgear/dgnd3700v2/Makefile b/board/netgear/dgnd3700v2/Makefile new file mode 100644 index 0000000..89fd6c8 --- /dev/null +++ b/board/netgear/dgnd3700v2/Makefile @@ -0,0 +1,5 @@ +# +# SPDX-License-Identifier: GPL-2.0+ +# + +obj-y += dgnd3700v2.o diff --git a/board/netgear/dgnd3700v2/dgnd3700v2.c b/board/netgear/dgnd3700v2/dgnd3700v2.c new file mode 100644 index 0000000..3ae7f6a --- /dev/null +++ b/board/netgear/dgnd3700v2/dgnd3700v2.c @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2018 Ãlvaro Fernández Rojas <noltari@gmail.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <asm/io.h> + +#define GPIO_BASE_6362 0x10000080 + +#define GPIO_MODE_6362_REG 0x18 +#define GPIO_MODE_6362_SERIAL_LED_DATA BIT(2) +#define GPIO_MODE_6362_SERIAL_LED_CLK BIT(3) + +#ifdef CONFIG_BOARD_EARLY_INIT_F +int board_early_init_f(void) +{ + void __iomem *gpio_regs = map_physmem(GPIO_BASE_6362, 0, MAP_NOCACHE); + + /* Enable Serial LEDs */ + setbits_be32(gpio_regs + GPIO_MODE_6362_REG, + GPIO_MODE_6362_SERIAL_LED_DATA | + GPIO_MODE_6362_SERIAL_LED_CLK); + + return 0; +} +#endif diff --git a/board/st/stm32f746-disco/stm32f746-disco.c b/board/st/stm32f746-disco/stm32f746-disco.c index 05b316f..c4f2633 100644 --- a/board/st/stm32f746-disco/stm32f746-disco.c +++ b/board/st/stm32f746-disco/stm32f746-disco.c @@ -7,8 +7,12 @@ #include <common.h> #include <dm.h> +#include <lcd.h> #include <ram.h> #include <spl.h> +#include <splash.h> +#include <st_logo_data.h> +#include <video.h> #include <asm/io.h> #include <asm/armv7m.h> #include <asm/arch/stm32.h> @@ -153,5 +157,10 @@ int board_init(void) STM32_SYSCFG->pmc |= SYSCFG_PMC_MII_RMII_SEL; #endif +#if defined(CONFIG_CMD_BMP) + bmp_display((ulong)stmicroelectronics_uboot_logo_8bit_rle, + BMP_ALIGN_CENTER, BMP_ALIGN_CENTER); +#endif /* CONFIG_CMD_BMP */ + return 0; } diff --git a/board/st/stm32mp1/Kconfig b/board/st/stm32mp1/Kconfig new file mode 100644 index 0000000..5ab9415 --- /dev/null +++ b/board/st/stm32mp1/Kconfig @@ -0,0 +1,12 @@ +if TARGET_STM32MP1 + +config SYS_BOARD + default "stm32mp1" + +config SYS_VENDOR + default "st" + +config SYS_CONFIG_NAME + default "stm32mp1" + +endif diff --git a/board/st/stm32mp1/MAINTAINERS b/board/st/stm32mp1/MAINTAINERS new file mode 100644 index 0000000..65266bc --- /dev/null +++ b/board/st/stm32mp1/MAINTAINERS @@ -0,0 +1,7 @@ +STM32MP1 BOARD +M: Patrick Delaunay <patrick.delaunay@st.com> +S: Maintained +F: board/st/stm32mp1 +F: include/configs/stm32mp1.h +F: configs/stm32mp15_basic_defconfig +F: arch/arm/dts/stm32mp157* diff --git a/board/st/stm32mp1/Makefile b/board/st/stm32mp1/Makefile new file mode 100644 index 0000000..eaf45b7 --- /dev/null +++ b/board/st/stm32mp1/Makefile @@ -0,0 +1,13 @@ +# +# Copyright (C) 2018, STMicroelectronics - All Rights Reserved +# +# SPDX-License-Identifier: GPL-2.0+ BSD-3-Clause +# + +ifdef CONFIG_SPL_BUILD +obj-y += spl.o +else +obj-y += stm32mp1.o +endif + +obj-y += board.o diff --git a/board/st/stm32mp1/README b/board/st/stm32mp1/README new file mode 100644 index 0000000..4adc978 --- /dev/null +++ b/board/st/stm32mp1/README @@ -0,0 +1,191 @@ +# +# Copyright (C) 2018 STMicroelectronics - All Rights Reserved +# +# SPDX-License-Identifier: GPL-2.0+ BSD-3-Clause +# + +U-Boot on STMicroelectronics STM32MP1 +====================================== + +1. Summary +========== +This is a quick instruction for setup stm32mp1 boards. + +2. Supported devices +==================== +U-Boot supports one STMP32MP1 SoCs: STM32MP157 + +The STM32MP157 is a Cortex-A MPU aimed at various applications. +It features: +- Dual core Cortex-A7 application core +- 2D/3D image composition with GPU +- Standard memories interface support +- Standard connectivity, widely inherited from the STM32 MCU family +- Comprehensive security support + +Everything is supported in Linux but U-Boot is limited to: +1. UART +2. SDCard/MMC controller (SDMMC) + +And the necessary drivers +1. I2C +2. STPMU1 +3. Clock, Reset + +Currently the following boards are supported: ++ stm32mp157c-ed1 + +3. Boot Sequences +================= + +BootRom => FSBL in SYSRAM => SSBL in DDR => OS (Linux Kernel) + +with FSBL = First Stage Bootloader + SSBL = Second Stage Bootloader + +One boot configuration is supported: + + The "Basic" boot chain (defconfig_file : stm32mp15_basic_defconfig) + BootRom => FSBL = U-Boot SPL => SSBL = U-Boot + SPL has limited security initialisation + U-Boot is running in secure mode and provide a secure monitor to the kernel + with only PSCI support (Power State Coordination Interface defined by ARM) + +All the STM32MP1 board supported by U-Boot use the same generic board +stm32mp1 which support all the bootable devices. + +Each board is configurated only with the associated device tree. + +4. Device Tree Selection +======================== + +You need to select the appropriate device tree for your board, +the supported device trees for stm32mp157 are: + ++ ed1: daughter board with pmic stpmu1 + dts: stm32mp157c-ed1 + +5. Build Procedure +================== + +1. Install required tools for U-Boot + + + install package needed in U-Boot makefile + (libssl-dev, swig, libpython-dev...) + + install ARMv7 toolchain for 32bit Cortex-A (from Linaro, + from SDK for STM32MP1, or any crosstoolchains from your distribution) + +2. Set the cross compiler: + + # export CROSS_COMPILE=/path/to/toolchain/arm-linux-gnueabi- + (you can use any gcc cross compiler compatible with U-Boot) + +3. Select the output directory (optional) + + # export KBUILD_OUTPUT=/path/to/output + + for example: use one output directory for each configuration + # export KBUILD_OUTPUT=stm32mp15_basic + +4. Configure the U-Boot: + + # make <defconfig_file> + + - For basic boot mode: "stm32mp15_basic_defconfig" + +5. Configure the device-tree and build the U-Boot image: + + # make DEVICE_TREE=<name> all + + + example: + basic boot on ed1 + # export KBUILD_OUTPUT=stm32mp15_basic + # make stm32mp15_basic_defconfig + # make DEVICE_TREE=stm32mp157c-ed1 all + +6. Output files + + BootRom and ATF expect binaries with STM32 image header + SPL expects file with U-Boot uImage header + + So in the output directory (selected by KBUILD_OUTPUT), + you can found the needed files: + + + FSBL = spl/u-boot-spl.stm32 + + SSBL = u-boot.img + +6. Prepare an SDCard +=================== + +The minimal requirements for STMP32MP1 boot up to U-Boot are: +- GPT partitioning (with gdisk or with sgdisk) +- 2 fsbl partitions, named fsbl1 and fsbl2, size at least 256KiB +- one ssbl partition for U-Boot + +Then the minimal GPT partition is: + ----- ------- --------- ------------- + | Num | Name | Size | Content | + ----- ------- -------- -------------- + | 1 | fsbl1 | 256 KiB | ATF or SPL | + | 2 | fsbl2 | 256 KiB | ATF or SPL | + | 3 | ssbl | enought | U-Boot | + | * | - | - | Boot/Rootfs| + ----- ------- --------- ------------- + +(*) add bootable partition for extlinux.conf + following Generic Distribution + (doc/README.distro for use) + + according the used card reader select the block device + (/dev/sdx or /dev/mmcblk0) + in the next example I use /dev/mmcblk0 + +for example: with gpt table with 128 entries + + a) remove previous formatting + # sgdisk -o /dev/<SDCard dev> + + b) create minimal image + # sgdisk --resize-table=128 -a 1 \ + -n 1:34:545 -c 1:fsbl1 \ + -n 2:546:1057 -c 2:fsbl2 \ + -n 3:1058:5153 -c 3:ssbl \ + -p /dev/<SDCard dev> + + you can add other partition for kernel (rootfs) + + c) copy the FSBL (2 times) and SSBL file on the correct partition. + in this example in partition 1 to 3 + + for basic boot mode : <SDCard dev> = /dev/mmcblk0 + # dd if=u-boot-spl.stm32 of=/dev/mmcblk0p1 + # dd if=u-boot-spl.stm32 of=/dev/mmcblk0p2 + # dd if=u-boot.img of=/dev/mmcblk0p3 + +7. Switch Setting +================== + +You can select the boot mode, on the board ed1 with the switch SW1 + + ----------------------------------- + Boot Mode BOOT2 BOOT1 BOOT0 + ----------------------------------- + Reserved 0 0 0 + NOR 0 0 1 + SD-Card 1 1 1 + SD-Card 1 0 1 + eMMC 0 1 0 + NAND 0 1 1 + Recovery 1 1 0 + Recovery 0 0 0 + + +To boot from SDCard, select BootPinMode = 1 1 1 and reset. + +Recovery is a boot from serial link (UART/USB) and it is used with +STM32CubeProgrammer tool to load executable in RAM and to update the flash +devices available on the board (NOR/NAND/eMMC/SDCARD). +The communication between HOST and board is based on +- for UARTs : the uart protocol used with all MCU STM32 +- for USB : based on USB DFU 1.1 (without the ST extensions used on MCU STM32) diff --git a/board/st/stm32mp1/board.c b/board/st/stm32mp1/board.c new file mode 100644 index 0000000..03f900a --- /dev/null +++ b/board/st/stm32mp1/board.c @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2018, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: GPL-2.0+ BSD-3-Clause + */ + +#include <common.h> +#include <dm.h> +#include <asm/io.h> +#include <asm/arch/ddr.h> +#include <power/pmic.h> +#include <power/stpmu1.h> + +#ifdef CONFIG_PMIC_STPMU1 +int board_ddr_power_init(void) +{ + struct udevice *dev; + int ret; + + ret = uclass_get_device_by_driver(UCLASS_PMIC, + DM_GET_DRIVER(pmic_stpmu1), &dev); + if (ret) + /* No PMIC on board */ + return 0; + + /* Set LDO3 to sync mode */ + ret = pmic_reg_read(dev, STPMU1_LDOX_CTRL_REG(STPMU1_LDO3)); + if (ret < 0) + return ret; + + ret &= ~STPMU1_LDO3_MODE; + ret &= ~STPMU1_LDO12356_OUTPUT_MASK; + ret |= STPMU1_LDO3_DDR_SEL << STPMU1_LDO12356_OUTPUT_SHIFT; + + ret = pmic_reg_write(dev, STPMU1_LDOX_CTRL_REG(STPMU1_LDO3), + ret); + if (ret < 0) + return ret; + + /* Set BUCK2 to 1.35V */ + ret = pmic_clrsetbits(dev, + STPMU1_BUCKX_CTRL_REG(STPMU1_BUCK2), + STPMU1_BUCK_OUTPUT_MASK, + STPMU1_BUCK2_1350000V); + if (ret < 0) + return ret; + + /* Enable BUCK2 and VREF */ + ret = pmic_clrsetbits(dev, + STPMU1_BUCKX_CTRL_REG(STPMU1_BUCK2), + STPMU1_BUCK_EN, STPMU1_BUCK_EN); + if (ret < 0) + return ret; + + mdelay(STPMU1_DEFAULT_START_UP_DELAY_MS); + + ret = pmic_clrsetbits(dev, STPMU1_VREF_CTRL_REG, + STPMU1_VREF_EN, STPMU1_VREF_EN); + if (ret < 0) + return ret; + + mdelay(STPMU1_DEFAULT_START_UP_DELAY_MS); + + /* Enable LDO3 */ + ret = pmic_clrsetbits(dev, + STPMU1_LDOX_CTRL_REG(STPMU1_LDO3), + STPMU1_LDO_EN, STPMU1_LDO_EN); + if (ret < 0) + return ret; + + mdelay(STPMU1_DEFAULT_START_UP_DELAY_MS); + + return 0; +} +#endif diff --git a/board/st/stm32mp1/spl.c b/board/st/stm32mp1/spl.c new file mode 100644 index 0000000..b7e5f24 --- /dev/null +++ b/board/st/stm32mp1/spl.c @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2018, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: GPL-2.0+ BSD-3-Clause + */ + +#include <config.h> +#include <common.h> +#include <spl.h> +#include <dm.h> +#include <ram.h> +#include <asm/io.h> +#include <post.h> +#include <power/pmic.h> +#include <power/stpmu1.h> +#include <asm/arch/ddr.h> + +void spl_board_init(void) +{ + /* Keep vdd on during the reset cycle */ +#if defined(CONFIG_PMIC_STPMU1) && defined(CONFIG_SPL_POWER_SUPPORT) + struct udevice *dev; + int ret; + + ret = uclass_get_device_by_driver(UCLASS_PMIC, + DM_GET_DRIVER(pmic_stpmu1), &dev); + if (!ret) + pmic_clrsetbits(dev, + STPMU1_MASK_RESET_BUCK, + STPMU1_MASK_RESET_BUCK3, + STPMU1_MASK_RESET_BUCK3); +#endif +} diff --git a/board/st/stm32mp1/stm32mp1.c b/board/st/stm32mp1/stm32mp1.c new file mode 100644 index 0000000..84c971c --- /dev/null +++ b/board/st/stm32mp1/stm32mp1.c @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2018, STMicroelectronics - All Rights Reserved + * + * SPDX-License-Identifier: GPL-2.0+ BSD-3-Clause + */ +#include <config.h> +#include <common.h> +#include <asm/arch/stm32.h> + +/* + * Get a global data pointer + */ +DECLARE_GLOBAL_DATA_PTR; + +int board_late_init(void) +{ + return 0; +} + +/* board dependent setup after realloc */ +int board_init(void) +{ + /* address of boot parameters */ + gd->bd->bi_boot_params = STM32_DDR_BASE + 0x100; + + return 0; +} diff --git a/board/synopsys/axs10x/axs10x.c b/board/synopsys/axs10x/axs10x.c index e6b69da..18f7666 100644 --- a/board/synopsys/axs10x/axs10x.c +++ b/board/synopsys/axs10x/axs10x.c @@ -47,6 +47,18 @@ int board_early_init_f(void) } #ifdef CONFIG_ISA_ARCV2 + +void board_jump_and_run(ulong entry, int zero, int arch, uint params) +{ + void (*kernel_entry)(int zero, int arch, uint params); + + kernel_entry = (void (*)(int, int, uint))entry; + + smp_set_core_boot_addr(entry, -1); + smp_kick_all_cpus(); + kernel_entry(zero, arch, params); +} + #define RESET_VECTOR_ADDR 0x0 void smp_set_core_boot_addr(unsigned long addr, int corenr) diff --git a/board/synopsys/hsdk/MAINTAINERS b/board/synopsys/hsdk/MAINTAINERS index d034bc4..e22bd1e 100644 --- a/board/synopsys/hsdk/MAINTAINERS +++ b/board/synopsys/hsdk/MAINTAINERS @@ -1,5 +1,5 @@ -AXS10X BOARD -M: Alexey Brodkin <abrodkin@synopsys.com> +HSDK BOARD +M: Eugeniy Paltsev <paltsev@synopsys.com> S: Maintained F: board/synopsys/hsdk/ F: configs/hsdk_defconfig diff --git a/board/synopsys/hsdk/Makefile b/board/synopsys/hsdk/Makefile index d84dd03..7ecff3d 100644 --- a/board/synopsys/hsdk/Makefile +++ b/board/synopsys/hsdk/Makefile @@ -5,3 +5,5 @@ # obj-y += hsdk.o +obj-y += env-lib.o +obj-y += clk-lib.o diff --git a/board/synopsys/hsdk/clk-lib.c b/board/synopsys/hsdk/clk-lib.c new file mode 100644 index 0000000..1ce54af --- /dev/null +++ b/board/synopsys/hsdk/clk-lib.c @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2018 Synopsys, Inc. All rights reserved. + * Author: Eugeniy Paltsev <Eugeniy.Paltsev@synopsys.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <clk.h> +#include <dm/device.h> + +#include "clk-lib.h" + +#define HZ_IN_MHZ 1000000 +#define ceil(x, y) ({ ulong __x = (x), __y = (y); (__x + __y - 1) / __y; }) + +int soc_clk_ctl(const char *name, ulong *rate, enum clk_ctl_ops ctl) +{ + int ret; + ulong mhz_rate, priv_rate; + struct clk clk; + + /* Dummy fmeas device, just to be able to use standard clk_* api */ + struct udevice fmeas = { + .name = "clk-fmeas", + .node = ofnode_path("/clk-fmeas"), + }; + + ret = clk_get_by_name(&fmeas, name, &clk); + if (ret) { + pr_err("clock '%s' not found, err=%d\n", name, ret); + return ret; + } + + if (ctl & CLK_ON) { + ret = clk_enable(&clk); + if (ret && ret != -ENOSYS && ret != -ENOTSUPP) + return ret; + } + + if ((ctl & CLK_SET) && rate) { + priv_rate = ctl & CLK_MHZ ? (*rate) * HZ_IN_MHZ : *rate; + ret = clk_set_rate(&clk, priv_rate); + if (ret) + return ret; + } + + if (ctl & CLK_OFF) { + ret = clk_disable(&clk); + if (ret) { + pr_err("clock '%s' can't be disabled, err=%d\n", name, ret); + return ret; + } + } + + priv_rate = clk_get_rate(&clk); + + clk_free(&clk); + + mhz_rate = ceil(priv_rate, HZ_IN_MHZ); + + if (ctl & CLK_MHZ) + priv_rate = mhz_rate; + + if ((ctl & CLK_GET) && rate) + *rate = priv_rate; + + if ((ctl & CLK_PRINT) && (ctl & CLK_MHZ)) + printf("HSDK: clock '%s' rate %lu MHz\n", name, priv_rate); + else if (ctl & CLK_PRINT) + printf("HSDK: clock '%s' rate %lu Hz\n", name, priv_rate); + else + debug("HSDK: clock '%s' rate %lu MHz\n", name, mhz_rate); + + return 0; +} diff --git a/board/synopsys/hsdk/clk-lib.h b/board/synopsys/hsdk/clk-lib.h new file mode 100644 index 0000000..3b7dbc5 --- /dev/null +++ b/board/synopsys/hsdk/clk-lib.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2018 Synopsys, Inc. All rights reserved. + * Author: Eugeniy Paltsev <Eugeniy.Paltsev@synopsys.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef __BOARD_CLK_LIB_H +#define __BOARD_CLK_LIB_H + +#include <common.h> + +enum clk_ctl_ops { + CLK_SET = BIT(0), /* set frequency */ + CLK_GET = BIT(1), /* get frequency */ + CLK_ON = BIT(2), /* enable clock */ + CLK_OFF = BIT(3), /* disable clock */ + CLK_PRINT = BIT(4), /* print frequency */ + CLK_MHZ = BIT(5) /* all values in MHZ instead of HZ */ +}; + +/* + * Depending on the clk_ctl_ops enable / disable / + * set clock rate from 'rate' argument / read clock to 'rate' argument / + * print clock rate. If CLK_MHZ flag set in clk_ctl_ops 'rate' is in MHz, + * otherwise - in Hz. + * + * This function expects "clk-fmeas" node in device tree: + * / { + * clk-fmeas { + * clocks = <&cpu_pll>, <&sys_pll>; + * clock-names = "cpu-pll", "sys-pll"; + * }; + * }; + */ +int soc_clk_ctl(const char *name, ulong *rate, enum clk_ctl_ops ctl); + +#endif /* __BOARD_CLK_LIB_H */ diff --git a/board/synopsys/hsdk/env-lib.c b/board/synopsys/hsdk/env-lib.c new file mode 100644 index 0000000..6b53d92 --- /dev/null +++ b/board/synopsys/hsdk/env-lib.c @@ -0,0 +1,302 @@ +/* + * Copyright (C) 2018 Synopsys, Inc. All rights reserved. + * Author: Eugeniy Paltsev <Eugeniy.Paltsev@synopsys.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include "env-lib.h" + +#define MAX_CMD_LEN 25 + +static void env_clear_common(u32 index, const struct env_map_common *map) +{ + map[index].val->val = 0; + map[index].val->set = false; +} + +static int env_read_common(u32 index, const struct env_map_common *map) +{ + u32 val; + + if (!env_get_yesno(map[index].env_name)) { + if (map[index].type == ENV_HEX) { + val = (u32)env_get_hex(map[index].env_name, 0); + debug("ENV: %s: = %#x\n", map[index].env_name, val); + } else { + val = (u32)env_get_ulong(map[index].env_name, 10, 0); + debug("ENV: %s: = %d\n", map[index].env_name, val); + } + + map[index].val->val = val; + map[index].val->set = true; + } + + return 0; +} + +static void env_clear_core(u32 index, const struct env_map_percpu *map) +{ + for (u32 i = 0; i < NR_CPUS; i++) { + (*map[index].val)[i].val = 0; + (*map[index].val)[i].set = false; + } +} + +static int env_read_core(u32 index, const struct env_map_percpu *map) +{ + u32 val; + char command[MAX_CMD_LEN]; + + for (u32 i = 0; i < NR_CPUS; i++) { + sprintf(command, "%s_%u", map[index].env_name, i); + if (!env_get_yesno(command)) { + if (map[index].type == ENV_HEX) { + val = (u32)env_get_hex(command, 0); + debug("ENV: %s: = %#x\n", command, val); + } else { + val = (u32)env_get_ulong(command, 10, 0); + debug("ENV: %s: = %d\n", command, val); + } + + (*map[index].val)[i].val = val; + (*map[index].val)[i].set = true; + } + } + + return 0; +} + +static int env_validate_common(u32 index, const struct env_map_common *map) +{ + u32 value = map[index].val->val; + bool set = map[index].val->set; + u32 min = map[index].min; + u32 max = map[index].max; + + /* Check if environment is mandatory */ + if (map[index].mandatory && !set) { + pr_err("Variable \'%s\' is mandatory, but it is not defined\n", + map[index].env_name); + + return -EINVAL; + } + + /* Check environment boundary */ + if (set && (value < min || value > max)) { + if (map[index].type == ENV_HEX) + pr_err("Variable \'%s\' must be between %#x and %#x\n", + map[index].env_name, min, max); + else + pr_err("Variable \'%s\' must be between %u and %u\n", + map[index].env_name, min, max); + + return -EINVAL; + } + + return 0; +} + +static int env_validate_core(u32 index, const struct env_map_percpu *map, + bool (*cpu_used)(u32)) +{ + u32 value; + bool set; + bool mandatory = map[index].mandatory; + u32 min, max; + + for (u32 i = 0; i < NR_CPUS; i++) { + set = (*map[index].val)[i].set; + value = (*map[index].val)[i].val; + + /* Check if environment is mandatory */ + if (cpu_used(i) && mandatory && !set) { + pr_err("CPU %u is used, but \'%s_%u\' is not defined\n", + i, map[index].env_name, i); + + return -EINVAL; + } + + min = map[index].min[i]; + max = map[index].max[i]; + + /* Check environment boundary */ + if (set && (value < min || value > max)) { + if (map[index].type == ENV_HEX) + pr_err("Variable \'%s_%u\' must be between %#x and %#x\n", + map[index].env_name, i, min, max); + else + pr_err("Variable \'%s_%u\' must be between %d and %d\n", + map[index].env_name, i, min, max); + + return -EINVAL; + } + } + + return 0; +} + +void envs_cleanup_core(const struct env_map_percpu *map) +{ + /* Cleanup env struct first */ + for (u32 i = 0; map[i].env_name; i++) + env_clear_core(i, map); +} + +void envs_cleanup_common(const struct env_map_common *map) +{ + /* Cleanup env struct first */ + for (u32 i = 0; map[i].env_name; i++) + env_clear_common(i, map); +} + +int envs_read_common(const struct env_map_common *map) +{ + int ret; + + for (u32 i = 0; map[i].env_name; i++) { + ret = env_read_common(i, map); + if (ret) + return ret; + } + + return 0; +} + +int envs_validate_common(const struct env_map_common *map) +{ + int ret; + + for (u32 i = 0; map[i].env_name; i++) { + ret = env_validate_common(i, map); + if (ret) + return ret; + } + + return 0; +} + +int envs_read_validate_common(const struct env_map_common *map) +{ + int ret; + + envs_cleanup_common(map); + + ret = envs_read_common(map); + if (ret) + return ret; + + ret = envs_validate_common(map); + if (ret) + return ret; + + return 0; +} + +int envs_read_validate_core(const struct env_map_percpu *map, + bool (*cpu_used)(u32)) +{ + int ret; + + envs_cleanup_core(map); + + for (u32 i = 0; map[i].env_name; i++) { + ret = env_read_core(i, map); + if (ret) + return ret; + } + + for (u32 i = 0; map[i].env_name; i++) { + ret = env_validate_core(i, map, cpu_used); + if (ret) + return ret; + } + + return 0; +} + +int envs_process_and_validate(const struct env_map_common *common, + const struct env_map_percpu *core, + bool (*cpu_used)(u32)) +{ + int ret; + + ret = envs_read_validate_common(common); + if (ret) + return ret; + + ret = envs_read_validate_core(core, cpu_used); + if (ret) + return ret; + + return 0; +} + +static int args_envs_read_search(const struct env_map_common *map, + int argc, char *const argv[]) +{ + for (int i = 0; map[i].env_name; i++) { + if (!strcmp(argv[0], map[i].env_name)) + return i; + } + + pr_err("Unexpected argument '%s', can't parse\n", argv[0]); + + return -ENOENT; +} + +static int arg_read_set(const struct env_map_common *map, u32 i, int argc, + char *const argv[]) +{ + char *endp = argv[1]; + + if (map[i].type == ENV_HEX) + map[i].val->val = simple_strtoul(argv[1], &endp, 16); + else + map[i].val->val = simple_strtoul(argv[1], &endp, 10); + + map[i].val->set = true; + + if (*endp == '\0') + return 0; + + pr_err("Unexpected argument '%s', can't parse\n", argv[1]); + + map[i].val->set = false; + + return -EINVAL; +} + +int args_envs_enumerate(const struct env_map_common *map, int enum_by, + int argc, char *const argv[]) +{ + u32 i; + + if (argc % enum_by) { + pr_err("unexpected argument number: %d\n", argc); + return -EINVAL; + } + + while (argc > 0) { + i = args_envs_read_search(map, argc, argv); + if (i < 0) + return i; + + debug("ARG: found '%s' with index %d\n", map[i].env_name, i); + + if (i < 0) { + pr_err("unknown arg: %s\n", argv[0]); + return -EINVAL; + } + + if (arg_read_set(map, i, argc, argv)) + return -EINVAL; + + debug("ARG: value.s '%s' == %#x\n", argv[1], map[i].val->val); + + argc -= enum_by; + argv += enum_by; + } + + return 0; +} diff --git a/board/synopsys/hsdk/env-lib.h b/board/synopsys/hsdk/env-lib.h new file mode 100644 index 0000000..606e802 --- /dev/null +++ b/board/synopsys/hsdk/env-lib.h @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2018 Synopsys, Inc. All rights reserved. + * Author: Eugeniy Paltsev <Eugeniy.Paltsev@synopsys.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef __BOARD_ENV_LIB_H +#define __BOARD_ENV_LIB_H + +#include <common.h> +#include <config.h> +#include <linux/kernel.h> + +enum env_type { + ENV_DEC, + ENV_HEX +}; + +typedef struct { + u32 val; + bool set; +} u32_env; + +struct env_map_common { + const char *const env_name; + enum env_type type; + bool mandatory; + u32 min; + u32 max; + u32_env *val; +}; + +struct env_map_percpu { + const char *const env_name; + enum env_type type; + bool mandatory; + u32 min[NR_CPUS]; + u32 max[NR_CPUS]; + u32_env (*val)[NR_CPUS]; +}; + +void envs_cleanup_common(const struct env_map_common *map); +int envs_read_common(const struct env_map_common *map); +int envs_validate_common(const struct env_map_common *map); +int envs_read_validate_common(const struct env_map_common *map); + +void envs_cleanup_core(const struct env_map_percpu *map); +int envs_read_validate_core(const struct env_map_percpu *map, + bool (*cpu_used)(u32)); +int envs_process_and_validate(const struct env_map_common *common, + const struct env_map_percpu *core, + bool (*cpu_used)(u32)); + +int args_envs_enumerate(const struct env_map_common *map, + int enum_by, int argc, char *const argv[]); + +#endif /* __BOARD_ENV_LIB_H */ diff --git a/board/synopsys/hsdk/hsdk.c b/board/synopsys/hsdk/hsdk.c index 7641978..65f937f 100644 --- a/board/synopsys/hsdk/hsdk.c +++ b/board/synopsys/hsdk/hsdk.c @@ -1,34 +1,1024 @@ /* - * Copyright (C) 2017 Synopsys, Inc. All rights reserved. + * Copyright (C) 2018 Synopsys, Inc. All rights reserved. + * Author: Eugeniy Paltsev <Eugeniy.Paltsev@synopsys.com> * * SPDX-License-Identifier: GPL-2.0+ */ #include <common.h> +#include <config.h> +#include <linux/printk.h> +#include <linux/kernel.h> +#include <linux/io.h> +#include <asm/arcregs.h> +#include <fdt_support.h> #include <dwmmc.h> #include <malloc.h> +#include <usb.h> + +#include "clk-lib.h" +#include "env-lib.h" DECLARE_GLOBAL_DATA_PTR; -#define CREG_BASE (ARC_PERIPHERAL_BASE + 0x1000) -#define CREG_PAE (CREG_BASE + 0x180) -#define CREG_PAE_UPDATE (CREG_BASE + 0x194) -#define CREG_CPU_START (CREG_BASE + 0x400) +#define ALL_CPU_MASK GENMASK(NR_CPUS - 1, 0) +#define MASTER_CPU_ID 0 +#define APERTURE_SHIFT 28 +#define NO_CCM 0x10 +#define SLAVE_CPU_READY 0x12345678 +#define BOOTSTAGE_1 1 /* after SP, FP setup, before HW init */ +#define BOOTSTAGE_2 2 /* after HW init, before self halt */ +#define BOOTSTAGE_3 3 /* after self halt */ +#define BOOTSTAGE_4 4 /* before app launch */ +#define BOOTSTAGE_5 5 /* after app launch, unreachable */ + +#define RESET_VECTOR_ADDR 0x0 + +#define CREG_BASE (ARC_PERIPHERAL_BASE + 0x1000) +#define CREG_CPU_START (CREG_BASE + 0x400) +#define CREG_CPU_START_MASK 0xF + +#define SDIO_BASE (ARC_PERIPHERAL_BASE + 0xA000) +#define SDIO_UHS_REG_EXT (SDIO_BASE + 0x108) +#define SDIO_UHS_REG_EXT_DIV_2 (2 << 30) + +/* Uncached access macros */ +#define arc_read_uncached_32(ptr) \ +({ \ + unsigned int __ret; \ + __asm__ __volatile__( \ + " ld.di %0, [%1] \n" \ + : "=r"(__ret) \ + : "r"(ptr)); \ + __ret; \ +}) + +#define arc_write_uncached_32(ptr, data)\ +({ \ + __asm__ __volatile__( \ + " st.di %0, [%1] \n" \ + : \ + : "r"(data), "r"(ptr)); \ +}) + +struct hsdk_env_core_ctl { + u32_env entry[NR_CPUS]; + u32_env iccm[NR_CPUS]; + u32_env dccm[NR_CPUS]; +}; + +struct hsdk_env_common_ctl { + bool halt_on_boot; + u32_env core_mask; + u32_env cpu_freq; + u32_env axi_freq; + u32_env tun_freq; + u32_env nvlim; + u32_env icache; + u32_env dcache; +}; + +/* + * Uncached cross-cpu structure. All CPUs must access to this structure fields + * only with arc_read_uncached_32() / arc_write_uncached_32() accessors (which + * implement ld.di / st.di instructions). Simultaneous cached and uncached + * access to this area will lead to data loss. + * We flush all data caches in board_early_init_r() as we don't want to have + * any dirty line in L1d$ or SL$ in this area. + */ +struct hsdk_cross_cpu { + /* slave CPU ready flag */ + u32 ready_flag; + /* address of the area, which can be used for stack by slave CPU */ + u32 stack_ptr; + /* slave CPU status - bootstage number */ + s32 status[NR_CPUS]; + + /* + * Slave CPU data - it is copy of corresponding fields in + * hsdk_env_core_ctl and hsdk_env_common_ctl structures which are + * required for slave CPUs initialization. + * This fields can be populated by copying from hsdk_env_core_ctl + * and hsdk_env_common_ctl structures with sync_cross_cpu_data() + * function. + */ + u32 entry[NR_CPUS]; + u32 iccm[NR_CPUS]; + u32 dccm[NR_CPUS]; + + u32 core_mask; + u32 icache; + u32 dcache; + + u8 cache_padding[ARCH_DMA_MINALIGN]; +} __aligned(ARCH_DMA_MINALIGN); + +/* Place for slave CPUs temporary stack */ +static u32 slave_stack[256 * NR_CPUS] __aligned(ARCH_DMA_MINALIGN); + +static struct hsdk_env_common_ctl env_common = {}; +static struct hsdk_env_core_ctl env_core = {}; +static struct hsdk_cross_cpu cross_cpu_data; + +static const struct env_map_common env_map_common[] = { + { "core_mask", ENV_HEX, true, 0x1, 0xF, &env_common.core_mask }, + { "non_volatile_limit", ENV_HEX, true, 0, 0xF, &env_common.nvlim }, + { "icache_ena", ENV_HEX, true, 0, 1, &env_common.icache }, + { "dcache_ena", ENV_HEX, true, 0, 1, &env_common.dcache }, + {} +}; + +static const struct env_map_common env_map_clock[] = { + { "cpu_freq", ENV_DEC, false, 100, 1000, &env_common.cpu_freq }, + { "axi_freq", ENV_DEC, false, 200, 800, &env_common.axi_freq }, + { "tun_freq", ENV_DEC, false, 0, 150, &env_common.tun_freq }, + {} +}; + +static const struct env_map_percpu env_map_core[] = { + { "core_iccm", ENV_HEX, true, {NO_CCM, 0, NO_CCM, 0}, {NO_CCM, 0xF, NO_CCM, 0xF}, &env_core.iccm }, + { "core_dccm", ENV_HEX, true, {NO_CCM, 0, NO_CCM, 0}, {NO_CCM, 0xF, NO_CCM, 0xF}, &env_core.dccm }, + {} +}; + +static const struct env_map_common env_map_mask[] = { + { "core_mask", ENV_HEX, false, 0x1, 0xF, &env_common.core_mask }, + {} +}; + +static const struct env_map_percpu env_map_go[] = { + { "core_entry", ENV_HEX, true, {0, 0, 0, 0}, {U32_MAX, U32_MAX, U32_MAX, U32_MAX}, &env_core.entry }, + {} +}; + +static void sync_cross_cpu_data(void) +{ + u32 value; + + for (u32 i = 0; i < NR_CPUS; i++) { + value = env_core.entry[i].val; + arc_write_uncached_32(&cross_cpu_data.entry[i], value); + } + + for (u32 i = 0; i < NR_CPUS; i++) { + value = env_core.iccm[i].val; + arc_write_uncached_32(&cross_cpu_data.iccm[i], value); + } + + for (u32 i = 0; i < NR_CPUS; i++) { + value = env_core.dccm[i].val; + arc_write_uncached_32(&cross_cpu_data.dccm[i], value); + } + + value = env_common.core_mask.val; + arc_write_uncached_32(&cross_cpu_data.core_mask, value); + + value = env_common.icache.val; + arc_write_uncached_32(&cross_cpu_data.icache, value); + + value = env_common.dcache.val; + arc_write_uncached_32(&cross_cpu_data.dcache, value); +} + +/* Can be used only on master CPU */ +static bool is_cpu_used(u32 cpu_id) +{ + return !!(env_common.core_mask.val & BIT(cpu_id)); +} + +/* TODO: add ICCM BCR and DCCM BCR runtime check */ +static void init_slave_cpu_func(u32 core) +{ + u32 val; + + /* Remap ICCM to another memory region if it exists */ + val = arc_read_uncached_32(&cross_cpu_data.iccm[core]); + if (val != NO_CCM) + write_aux_reg(ARC_AUX_ICCM_BASE, val << APERTURE_SHIFT); + + /* Remap DCCM to another memory region if it exists */ + val = arc_read_uncached_32(&cross_cpu_data.dccm[core]); + if (val != NO_CCM) + write_aux_reg(ARC_AUX_DCCM_BASE, val << APERTURE_SHIFT); + + if (arc_read_uncached_32(&cross_cpu_data.icache)) + icache_enable(); + else + icache_disable(); + + if (arc_read_uncached_32(&cross_cpu_data.dcache)) + dcache_enable(); + else + dcache_disable(); +} + +static void init_cluster_nvlim(void) +{ + u32 val = env_common.nvlim.val << APERTURE_SHIFT; + + flush_dcache_all(); + write_aux_reg(ARC_AUX_NON_VOLATILE_LIMIT, val); + write_aux_reg(AUX_AUX_CACHE_LIMIT, val); + flush_n_invalidate_dcache_all(); +} + +static void init_master_icache(void) +{ + if (icache_status()) { + /* I$ is enabled - we need to disable it */ + if (!env_common.icache.val) + icache_disable(); + } else { + /* I$ is disabled - we need to enable it */ + if (env_common.icache.val) { + icache_enable(); + + /* invalidate I$ right after enable */ + invalidate_icache_all(); + } + } +} + +static void init_master_dcache(void) +{ + if (dcache_status()) { + /* D$ is enabled - we need to disable it */ + if (!env_common.dcache.val) + dcache_disable(); + } else { + /* D$ is disabled - we need to enable it */ + if (env_common.dcache.val) + dcache_enable(); + + /* TODO: probably we need ti invalidate D$ right after enable */ + } +} + +static int cleanup_before_go(void) +{ + disable_interrupts(); + sync_n_cleanup_cache_all(); + + return 0; +} + +void slave_cpu_set_boot_addr(u32 addr) +{ + /* All cores have reset vector pointing to 0 */ + writel(addr, (void __iomem *)RESET_VECTOR_ADDR); + + /* Make sure other cores see written value in memory */ + sync_n_cleanup_cache_all(); +} + +static inline void halt_this_cpu(void) +{ + __builtin_arc_flag(1); +} + +static void smp_kick_cpu_x(u32 cpu_id) +{ + int cmd = readl((void __iomem *)CREG_CPU_START); + + if (cpu_id > NR_CPUS) + return; + + cmd &= ~CREG_CPU_START_MASK; + cmd |= (1 << cpu_id); + writel(cmd, (void __iomem *)CREG_CPU_START); +} + +static u32 prepare_cpu_ctart_reg(void) +{ + int cmd = readl((void __iomem *)CREG_CPU_START); + + cmd &= ~CREG_CPU_START_MASK; + + return cmd | env_common.core_mask.val; +} + +/* slave CPU entry for configuration */ +__attribute__((naked, noreturn, flatten)) noinline void hsdk_core_init_f(void) +{ + __asm__ __volatile__( + "ld.di r8, [%0]\n" + "mov %%sp, r8\n" + "mov %%fp, %%sp\n" + : /* no output */ + : "r" (&cross_cpu_data.stack_ptr)); + + invalidate_icache_all(); + + arc_write_uncached_32(&cross_cpu_data.status[CPU_ID_GET()], BOOTSTAGE_1); + init_slave_cpu_func(CPU_ID_GET()); + + arc_write_uncached_32(&cross_cpu_data.ready_flag, SLAVE_CPU_READY); + arc_write_uncached_32(&cross_cpu_data.status[CPU_ID_GET()], BOOTSTAGE_2); + + /* Halt the processor until the master kick us again */ + halt_this_cpu(); + + /* + * 3 NOPs after FLAG 1 instruction are no longer required for ARCv2 + * cores but we leave them for gebug purposes. + */ + __builtin_arc_nop(); + __builtin_arc_nop(); + __builtin_arc_nop(); + + arc_write_uncached_32(&cross_cpu_data.status[CPU_ID_GET()], BOOTSTAGE_3); + + /* get the updated entry - invalidate i$ */ + invalidate_icache_all(); + + arc_write_uncached_32(&cross_cpu_data.status[CPU_ID_GET()], BOOTSTAGE_4); + + /* Run our program */ + ((void (*)(void))(arc_read_uncached_32(&cross_cpu_data.entry[CPU_ID_GET()])))(); + + /* This bootstage is unreachable as we don't return from app we launch */ + arc_write_uncached_32(&cross_cpu_data.status[CPU_ID_GET()], BOOTSTAGE_5); + + /* Something went terribly wrong */ + while (true) + halt_this_cpu(); +} + +static void clear_cross_cpu_data(void) +{ + arc_write_uncached_32(&cross_cpu_data.ready_flag, 0); + arc_write_uncached_32(&cross_cpu_data.stack_ptr, 0); + + for (u32 i = 0; i < NR_CPUS; i++) + arc_write_uncached_32(&cross_cpu_data.status[i], 0); +} + +static noinline void do_init_slave_cpu(u32 cpu_id) +{ + /* attempts number for check clave CPU ready_flag */ + u32 attempts = 100; + u32 stack_ptr = (u32)(slave_stack + (64 * cpu_id)); + + if (cpu_id >= NR_CPUS) + return; + + arc_write_uncached_32(&cross_cpu_data.ready_flag, 0); + + /* Use global unique place for each slave cpu stack */ + arc_write_uncached_32(&cross_cpu_data.stack_ptr, stack_ptr); + + debug("CPU %u: stack pool base: %p\n", cpu_id, slave_stack); + debug("CPU %u: current slave stack base: %x\n", cpu_id, stack_ptr); + slave_cpu_set_boot_addr((u32)hsdk_core_init_f); + + smp_kick_cpu_x(cpu_id); + + debug("CPU %u: cross-cpu flag: %x [before timeout]\n", cpu_id, + arc_read_uncached_32(&cross_cpu_data.ready_flag)); + + while (!arc_read_uncached_32(&cross_cpu_data.ready_flag) && attempts--) + mdelay(10); + + /* Just to be sure that slave cpu is halted after it set ready_flag */ + mdelay(20); + + /* + * Only print error here if we reach timeout as there is no option to + * halt slave cpu (or check that slave cpu is halted) + */ + if (!attempts) + pr_err("CPU %u is not responding after init!\n", cpu_id); + + /* Check current stage of slave cpu */ + if (arc_read_uncached_32(&cross_cpu_data.status[cpu_id]) != BOOTSTAGE_2) + pr_err("CPU %u status is unexpected: %d\n", cpu_id, + arc_read_uncached_32(&cross_cpu_data.status[cpu_id])); + + debug("CPU %u: cross-cpu flag: %x [after timeout]\n", cpu_id, + arc_read_uncached_32(&cross_cpu_data.ready_flag)); + debug("CPU %u: status: %d [after timeout]\n", cpu_id, + arc_read_uncached_32(&cross_cpu_data.status[cpu_id])); +} + +static void do_init_slave_cpus(void) +{ + clear_cross_cpu_data(); + sync_cross_cpu_data(); + + debug("cross_cpu_data location: %#x\n", (u32)&cross_cpu_data); + + for (u32 i = MASTER_CPU_ID + 1; i < NR_CPUS; i++) + if (is_cpu_used(i)) + do_init_slave_cpu(i); +} + +static void do_init_master_cpu(void) +{ + /* + * Setup master caches even if master isn't used as we want to use + * same cache configuration on all running CPUs + */ + init_master_icache(); + init_master_dcache(); +} + +enum hsdk_axi_masters { + M_HS_CORE = 0, + M_HS_RTT, + M_AXI_TUN, + M_HDMI_VIDEO, + M_HDMI_AUDIO, + M_USB_HOST, + M_ETHERNET, + M_SDIO, + M_GPU, + M_DMAC_0, + M_DMAC_1, + M_DVFS +}; + +#define UPDATE_VAL 1 + +/* + * m master AXI_M_m_SLV0 AXI_M_m_SLV1 AXI_M_m_OFFSET0 AXI_M_m_OFFSET1 + * 0 HS (CBU) 0x11111111 0x63111111 0xFEDCBA98 0x0E543210 + * 1 HS (RTT) 0x77777777 0x77777777 0xFEDCBA98 0x76543210 + * 2 AXI Tunnel 0x88888888 0x88888888 0xFEDCBA98 0x76543210 + * 3 HDMI-VIDEO 0x77777777 0x77777777 0xFEDCBA98 0x76543210 + * 4 HDMI-ADUIO 0x77777777 0x77777777 0xFEDCBA98 0x76543210 + * 5 USB-HOST 0x77777777 0x77999999 0xFEDCBA98 0x76DCBA98 + * 6 ETHERNET 0x77777777 0x77999999 0xFEDCBA98 0x76DCBA98 + * 7 SDIO 0x77777777 0x77999999 0xFEDCBA98 0x76DCBA98 + * 8 GPU 0x77777777 0x77777777 0xFEDCBA98 0x76543210 + * 9 DMAC (port #1) 0x77777777 0x77777777 0xFEDCBA98 0x76543210 + * 10 DMAC (port #2) 0x77777777 0x77777777 0xFEDCBA98 0x76543210 + * 11 DVFS 0x00000000 0x60000000 0x00000000 0x00000000 + * + * Please read ARC HS Development IC Specification, section 17.2 for more + * information about apertures configuration. + * NOTE: we intentionally modify default settings in U-boot. Default settings + * are specified in "Table 111 CREG Address Decoder register reset values". + */ + +#define CREG_AXI_M_SLV0(m) ((void __iomem *)(CREG_BASE + 0x020 * (m))) +#define CREG_AXI_M_SLV1(m) ((void __iomem *)(CREG_BASE + 0x020 * (m) + 0x004)) +#define CREG_AXI_M_OFT0(m) ((void __iomem *)(CREG_BASE + 0x020 * (m) + 0x008)) +#define CREG_AXI_M_OFT1(m) ((void __iomem *)(CREG_BASE + 0x020 * (m) + 0x00C)) +#define CREG_AXI_M_UPDT(m) ((void __iomem *)(CREG_BASE + 0x020 * (m) + 0x014)) + +#define CREG_AXI_M_HS_CORE_BOOT ((void __iomem *)(CREG_BASE + 0x010)) + +#define CREG_PAE ((void __iomem *)(CREG_BASE + 0x180)) +#define CREG_PAE_UPDT ((void __iomem *)(CREG_BASE + 0x194)) + +void init_memory_bridge(void) +{ + u32 reg; + + /* + * M_HS_CORE has one unic register - BOOT. + * We need to clean boot mirror (BOOT[1:0]) bits in them. + */ + reg = readl(CREG_AXI_M_HS_CORE_BOOT) & (~0x3); + writel(reg, CREG_AXI_M_HS_CORE_BOOT); + writel(0x11111111, CREG_AXI_M_SLV0(M_HS_CORE)); + writel(0x63111111, CREG_AXI_M_SLV1(M_HS_CORE)); + writel(0xFEDCBA98, CREG_AXI_M_OFT0(M_HS_CORE)); + writel(0x0E543210, CREG_AXI_M_OFT1(M_HS_CORE)); + writel(UPDATE_VAL, CREG_AXI_M_UPDT(M_HS_CORE)); + + writel(0x77777777, CREG_AXI_M_SLV0(M_HS_RTT)); + writel(0x77777777, CREG_AXI_M_SLV1(M_HS_RTT)); + writel(0xFEDCBA98, CREG_AXI_M_OFT0(M_HS_RTT)); + writel(0x76543210, CREG_AXI_M_OFT1(M_HS_RTT)); + writel(UPDATE_VAL, CREG_AXI_M_UPDT(M_HS_RTT)); + + writel(0x88888888, CREG_AXI_M_SLV0(M_AXI_TUN)); + writel(0x88888888, CREG_AXI_M_SLV1(M_AXI_TUN)); + writel(0xFEDCBA98, CREG_AXI_M_OFT0(M_AXI_TUN)); + writel(0x76543210, CREG_AXI_M_OFT1(M_AXI_TUN)); + writel(UPDATE_VAL, CREG_AXI_M_UPDT(M_AXI_TUN)); + + writel(0x77777777, CREG_AXI_M_SLV0(M_HDMI_VIDEO)); + writel(0x77777777, CREG_AXI_M_SLV1(M_HDMI_VIDEO)); + writel(0xFEDCBA98, CREG_AXI_M_OFT0(M_HDMI_VIDEO)); + writel(0x76543210, CREG_AXI_M_OFT1(M_HDMI_VIDEO)); + writel(UPDATE_VAL, CREG_AXI_M_UPDT(M_HDMI_VIDEO)); + + writel(0x77777777, CREG_AXI_M_SLV0(M_HDMI_AUDIO)); + writel(0x77777777, CREG_AXI_M_SLV1(M_HDMI_AUDIO)); + writel(0xFEDCBA98, CREG_AXI_M_OFT0(M_HDMI_AUDIO)); + writel(0x76543210, CREG_AXI_M_OFT1(M_HDMI_AUDIO)); + writel(UPDATE_VAL, CREG_AXI_M_UPDT(M_HDMI_AUDIO)); + + writel(0x77777777, CREG_AXI_M_SLV0(M_USB_HOST)); + writel(0x77999999, CREG_AXI_M_SLV1(M_USB_HOST)); + writel(0xFEDCBA98, CREG_AXI_M_OFT0(M_USB_HOST)); + writel(0x76DCBA98, CREG_AXI_M_OFT1(M_USB_HOST)); + writel(UPDATE_VAL, CREG_AXI_M_UPDT(M_USB_HOST)); + + writel(0x77777777, CREG_AXI_M_SLV0(M_ETHERNET)); + writel(0x77999999, CREG_AXI_M_SLV1(M_ETHERNET)); + writel(0xFEDCBA98, CREG_AXI_M_OFT0(M_ETHERNET)); + writel(0x76DCBA98, CREG_AXI_M_OFT1(M_ETHERNET)); + writel(UPDATE_VAL, CREG_AXI_M_UPDT(M_ETHERNET)); + + writel(0x77777777, CREG_AXI_M_SLV0(M_SDIO)); + writel(0x77999999, CREG_AXI_M_SLV1(M_SDIO)); + writel(0xFEDCBA98, CREG_AXI_M_OFT0(M_SDIO)); + writel(0x76DCBA98, CREG_AXI_M_OFT1(M_SDIO)); + writel(UPDATE_VAL, CREG_AXI_M_UPDT(M_SDIO)); + + writel(0x77777777, CREG_AXI_M_SLV0(M_GPU)); + writel(0x77777777, CREG_AXI_M_SLV1(M_GPU)); + writel(0xFEDCBA98, CREG_AXI_M_OFT0(M_GPU)); + writel(0x76543210, CREG_AXI_M_OFT1(M_GPU)); + writel(UPDATE_VAL, CREG_AXI_M_UPDT(M_GPU)); + + writel(0x77777777, CREG_AXI_M_SLV0(M_DMAC_0)); + writel(0x77777777, CREG_AXI_M_SLV1(M_DMAC_0)); + writel(0xFEDCBA98, CREG_AXI_M_OFT0(M_DMAC_0)); + writel(0x76543210, CREG_AXI_M_OFT1(M_DMAC_0)); + writel(UPDATE_VAL, CREG_AXI_M_UPDT(M_DMAC_0)); + + writel(0x77777777, CREG_AXI_M_SLV0(M_DMAC_1)); + writel(0x77777777, CREG_AXI_M_SLV1(M_DMAC_1)); + writel(0xFEDCBA98, CREG_AXI_M_OFT0(M_DMAC_1)); + writel(0x76543210, CREG_AXI_M_OFT1(M_DMAC_1)); + writel(UPDATE_VAL, CREG_AXI_M_UPDT(M_DMAC_1)); + + writel(0x00000000, CREG_AXI_M_SLV0(M_DVFS)); + writel(0x60000000, CREG_AXI_M_SLV1(M_DVFS)); + writel(0x00000000, CREG_AXI_M_OFT0(M_DVFS)); + writel(0x00000000, CREG_AXI_M_OFT1(M_DVFS)); + writel(UPDATE_VAL, CREG_AXI_M_UPDT(M_DVFS)); + + writel(0x00000000, CREG_PAE); + writel(UPDATE_VAL, CREG_PAE_UPDT); +} + +static void setup_clocks(void) +{ + ulong rate; + + /* Setup CPU clock */ + if (env_common.cpu_freq.set) { + rate = env_common.cpu_freq.val; + soc_clk_ctl("cpu-clk", &rate, CLK_ON | CLK_SET | CLK_MHZ); + } + + /* Setup TUN clock */ + if (env_common.tun_freq.set) { + rate = env_common.tun_freq.val; + if (rate) + soc_clk_ctl("tun-clk", &rate, CLK_ON | CLK_SET | CLK_MHZ); + else + soc_clk_ctl("tun-clk", NULL, CLK_OFF); + } + + if (env_common.axi_freq.set) { + rate = env_common.axi_freq.val; + soc_clk_ctl("axi-clk", &rate, CLK_SET | CLK_ON | CLK_MHZ); + } +} +static void do_init_cluster(void) +{ + /* + * A multi-core ARC HS configuration always includes only one + * ARC_AUX_NON_VOLATILE_LIMIT register, which is shared by all the + * cores. + */ + init_cluster_nvlim(); +} + +static int check_master_cpu_id(void) +{ + if (CPU_ID_GET() == MASTER_CPU_ID) + return 0; + + pr_err("u-boot runs on non-master cpu with id: %lu\n", CPU_ID_GET()); + + return -ENOENT; +} + +static noinline int prepare_cpus(void) +{ + int ret; + + ret = check_master_cpu_id(); + if (ret) + return ret; + + ret = envs_process_and_validate(env_map_common, env_map_core, is_cpu_used); + if (ret) + return ret; + + printf("CPU start mask is %#x\n", env_common.core_mask.val); + + do_init_slave_cpus(); + do_init_master_cpu(); + do_init_cluster(); + + return 0; +} + +static int hsdk_go_run(u32 cpu_start_reg) +{ + /* Cleanup caches, disable interrupts */ + cleanup_before_go(); + + if (env_common.halt_on_boot) + halt_this_cpu(); + + /* + * 3 NOPs after FLAG 1 instruction are no longer required for ARCv2 + * cores but we leave them for gebug purposes. + */ + __builtin_arc_nop(); + __builtin_arc_nop(); + __builtin_arc_nop(); + + /* Kick chosen slave CPUs */ + writel(cpu_start_reg, (void __iomem *)CREG_CPU_START); + + if (is_cpu_used(MASTER_CPU_ID)) + ((void (*)(void))(env_core.entry[MASTER_CPU_ID].val))(); + else + halt_this_cpu(); + + pr_err("u-boot still runs on cpu [%ld]\n", CPU_ID_GET()); + + /* + * We will never return after executing our program if master cpu used + * otherwise halt master cpu manually. + */ + while (true) + halt_this_cpu(); + + return 0; +} + +int board_prep_linux(bootm_headers_t *images) +{ + int ret, ofst; + char mask[15]; + + ret = envs_read_validate_common(env_map_mask); + if (ret) + return ret; + + /* Rollback to default values */ + if (!env_common.core_mask.set) { + env_common.core_mask.val = ALL_CPU_MASK; + env_common.core_mask.set = true; + } + + printf("CPU start mask is %#x\n", env_common.core_mask.val); + + if (!is_cpu_used(MASTER_CPU_ID)) + pr_err("ERR: try to launch linux with CPU[0] disabled! It doesn't work for ARC.\n"); + + /* + * If we want to launch linux on all CPUs we don't need to patch + * linux DTB as it is default configuration + */ + if (env_common.core_mask.val == ALL_CPU_MASK) + return 0; + + if (!IMAGE_ENABLE_OF_LIBFDT || !images->ft_len) { + pr_err("WARN: core_mask setup will work properly only with external DTB!\n"); + return 0; + } + + /* patch '/possible-cpus' property according to cpu mask */ + ofst = fdt_path_offset(images->ft_addr, "/"); + sprintf(mask, "%s%s%s%s", + is_cpu_used(0) ? "0," : "", + is_cpu_used(1) ? "1," : "", + is_cpu_used(2) ? "2," : "", + is_cpu_used(3) ? "3," : ""); + ret = fdt_setprop_string(images->ft_addr, ofst, "possible-cpus", mask); + /* + * If we failed to patch '/possible-cpus' property we don't need break + * linux loading process: kernel will handle it but linux will print + * warning like "Timeout: CPU1 FAILED to comeup !!!". + * So warn here about error, but return 0 like no error had occurred. + */ + if (ret) + pr_err("WARN: failed to patch '/possible-cpus' property, ret=%d\n", + ret); + + return 0; +} + +void board_jump_and_run(ulong entry, int zero, int arch, uint params) +{ + void (*kernel_entry)(int zero, int arch, uint params); + u32 cpu_start_reg; + + kernel_entry = (void (*)(int, int, uint))entry; + + /* Prepare CREG_CPU_START for kicking chosen CPUs */ + cpu_start_reg = prepare_cpu_ctart_reg(); + + /* In case of run without hsdk_init */ + slave_cpu_set_boot_addr(entry); + + /* In case of run with hsdk_init */ + for (u32 i = 0; i < NR_CPUS; i++) { + env_core.entry[i].val = entry; + env_core.entry[i].set = true; + } + /* sync cross_cpu struct as we updated core-entry variables */ + sync_cross_cpu_data(); + + /* Kick chosen slave CPUs */ + writel(cpu_start_reg, (void __iomem *)CREG_CPU_START); + + if (is_cpu_used(0)) + kernel_entry(zero, arch, params); +} + +static int hsdk_go_prepare_and_run(void) +{ + /* Prepare CREG_CPU_START for kicking chosen CPUs */ + u32 reg = prepare_cpu_ctart_reg(); + + if (env_common.halt_on_boot) + printf("CPU will halt before application start, start application with debugger.\n"); + + return hsdk_go_run(reg); +} + +static int do_hsdk_go(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) +{ + int ret; + + /* + * Check for 'halt' parameter. 'halt' = enter halt-mode just before + * starting the application; can be used for debug. + */ + if (argc > 1) { + env_common.halt_on_boot = !strcmp(argv[1], "halt"); + if (!env_common.halt_on_boot) { + pr_err("Unrecognised parameter: \'%s\'\n", argv[1]); + return CMD_RET_FAILURE; + } + } + + ret = check_master_cpu_id(); + if (ret) + return ret; + + ret = envs_process_and_validate(env_map_mask, env_map_go, is_cpu_used); + if (ret) + return ret; + + /* sync cross_cpu struct as we updated core-entry variables */ + sync_cross_cpu_data(); + + ret = hsdk_go_prepare_and_run(); + + return ret ? CMD_RET_FAILURE : CMD_RET_SUCCESS; +} + +U_BOOT_CMD( + hsdk_go, 3, 0, do_hsdk_go, + "Synopsys HSDK specific command", + " - Boot stand-alone application on HSDK\n" + "hsdk_go halt - Boot stand-alone application on HSDK, halt CPU just before application run\n" +); + +static int do_hsdk_init(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) +{ + static bool done = false; + int ret; + + /* hsdk_init can be run only once */ + if (done) { + printf("HSDK HW is already initialized! Please reset the board if you want to change the configuration.\n"); + return CMD_RET_FAILURE; + } + + ret = prepare_cpus(); + if (!ret) + done = true; + + return ret ? CMD_RET_FAILURE : CMD_RET_SUCCESS; +} + +U_BOOT_CMD( + hsdk_init, 1, 0, do_hsdk_init, + "Synopsys HSDK specific command", + "- Init HSDK HW\n" +); + +static int do_hsdk_clock_set(cmd_tbl_t *cmdtp, int flag, int argc, + char *const argv[]) +{ + int ret = 0; + + /* Strip off leading subcommand argument */ + argc--; + argv++; + + envs_cleanup_common(env_map_clock); + + if (!argc) { + printf("Set clocks to values specified in environment\n"); + ret = envs_read_common(env_map_clock); + } else { + printf("Set clocks to values specified in args\n"); + ret = args_envs_enumerate(env_map_clock, 2, argc, argv); + } + + if (ret) + return CMD_RET_FAILURE; + + ret = envs_validate_common(env_map_clock); + if (ret) + return CMD_RET_FAILURE; + + /* Setup clock tree HW */ + setup_clocks(); + + return CMD_RET_SUCCESS; +} + +static int do_hsdk_clock_get(cmd_tbl_t *cmdtp, int flag, int argc, + char *const argv[]) +{ + ulong rate; + + if (soc_clk_ctl("cpu-clk", &rate, CLK_GET | CLK_MHZ)) + return CMD_RET_FAILURE; + + if (env_set_ulong("cpu_freq", rate)) + return CMD_RET_FAILURE; + + if (soc_clk_ctl("tun-clk", &rate, CLK_GET | CLK_MHZ)) + return CMD_RET_FAILURE; + + if (env_set_ulong("tun_freq", rate)) + return CMD_RET_FAILURE; + + if (soc_clk_ctl("axi-clk", &rate, CLK_GET | CLK_MHZ)) + return CMD_RET_FAILURE; + + if (env_set_ulong("axi_freq", rate)) + return CMD_RET_FAILURE; + + printf("Clock values are saved to environment\n"); + + return CMD_RET_SUCCESS; +} + +static int do_hsdk_clock_print(cmd_tbl_t *cmdtp, int flag, int argc, + char *const argv[]) +{ + /* Main clocks */ + soc_clk_ctl("cpu-clk", NULL, CLK_PRINT | CLK_MHZ); + soc_clk_ctl("tun-clk", NULL, CLK_PRINT | CLK_MHZ); + soc_clk_ctl("axi-clk", NULL, CLK_PRINT | CLK_MHZ); + soc_clk_ctl("ddr-clk", NULL, CLK_PRINT | CLK_MHZ); + + return CMD_RET_SUCCESS; +} + +static int do_hsdk_clock_print_all(cmd_tbl_t *cmdtp, int flag, int argc, + char *const argv[]) +{ + /* + * NOTE: as of today we don't use some peripherals like HDMI / EBI + * so we don't want to print their clocks ("hdmi-sys-clk", "hdmi-pll", + * "hdmi-clk", "ebi-clk"). Nevertheless their clock subsystems is fully + * functional and we can print their clocks if it is required + */ + + /* CPU clock domain */ + soc_clk_ctl("cpu-pll", NULL, CLK_PRINT | CLK_MHZ); + soc_clk_ctl("cpu-clk", NULL, CLK_PRINT | CLK_MHZ); + printf("\n"); + + /* SYS clock domain */ + soc_clk_ctl("sys-pll", NULL, CLK_PRINT | CLK_MHZ); + soc_clk_ctl("apb-clk", NULL, CLK_PRINT | CLK_MHZ); + soc_clk_ctl("axi-clk", NULL, CLK_PRINT | CLK_MHZ); + soc_clk_ctl("eth-clk", NULL, CLK_PRINT | CLK_MHZ); + soc_clk_ctl("usb-clk", NULL, CLK_PRINT | CLK_MHZ); + soc_clk_ctl("sdio-clk", NULL, CLK_PRINT | CLK_MHZ); +/* soc_clk_ctl("hdmi-sys-clk", NULL, CLK_PRINT | CLK_MHZ); */ + soc_clk_ctl("gfx-core-clk", NULL, CLK_PRINT | CLK_MHZ); + soc_clk_ctl("gfx-dma-clk", NULL, CLK_PRINT | CLK_MHZ); + soc_clk_ctl("gfx-cfg-clk", NULL, CLK_PRINT | CLK_MHZ); + soc_clk_ctl("dmac-core-clk", NULL, CLK_PRINT | CLK_MHZ); + soc_clk_ctl("dmac-cfg-clk", NULL, CLK_PRINT | CLK_MHZ); + soc_clk_ctl("sdio-ref-clk", NULL, CLK_PRINT | CLK_MHZ); + soc_clk_ctl("spi-clk", NULL, CLK_PRINT | CLK_MHZ); + soc_clk_ctl("i2c-clk", NULL, CLK_PRINT | CLK_MHZ); +/* soc_clk_ctl("ebi-clk", NULL, CLK_PRINT | CLK_MHZ); */ + soc_clk_ctl("uart-clk", NULL, CLK_PRINT | CLK_MHZ); + printf("\n"); + + /* DDR clock domain */ + soc_clk_ctl("ddr-clk", NULL, CLK_PRINT | CLK_MHZ); + printf("\n"); + + /* HDMI clock domain */ +/* soc_clk_ctl("hdmi-pll", NULL, CLK_PRINT | CLK_MHZ); */ +/* soc_clk_ctl("hdmi-clk", NULL, CLK_PRINT | CLK_MHZ); */ +/* printf("\n"); */ + + /* TUN clock domain */ + soc_clk_ctl("tun-pll", NULL, CLK_PRINT | CLK_MHZ); + soc_clk_ctl("tun-clk", NULL, CLK_PRINT | CLK_MHZ); + soc_clk_ctl("rom-clk", NULL, CLK_PRINT | CLK_MHZ); + soc_clk_ctl("pwm-clk", NULL, CLK_PRINT | CLK_MHZ); + printf("\n"); + + return CMD_RET_SUCCESS; +} + +cmd_tbl_t cmd_hsdk_clock[] = { + U_BOOT_CMD_MKENT(set, 3, 0, do_hsdk_clock_set, "", ""), + U_BOOT_CMD_MKENT(get, 3, 0, do_hsdk_clock_get, "", ""), + U_BOOT_CMD_MKENT(print, 4, 0, do_hsdk_clock_print, "", ""), + U_BOOT_CMD_MKENT(print_all, 4, 0, do_hsdk_clock_print_all, "", ""), +}; + +static int do_hsdk_clock(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) +{ + cmd_tbl_t *c; + + if (argc < 2) + return CMD_RET_USAGE; + + /* Strip off leading 'hsdk_clock' command argument */ + argc--; + argv++; + + c = find_cmd_tbl(argv[0], cmd_hsdk_clock, ARRAY_SIZE(cmd_hsdk_clock)); + if (!c) + return CMD_RET_USAGE; + + return c->cmd(cmdtp, flag, argc, argv); +} + +U_BOOT_CMD( + hsdk_clock, CONFIG_SYS_MAXARGS, 0, do_hsdk_clock, + "Synopsys HSDK specific clock command", + "set - Set clock to values specified in environment / command line arguments\n" + "hsdk_clock get - Save clock values to environment\n" + "hsdk_clock print - Print main clock values to console\n" + "hsdk_clock print_all - Print all clock values to console\n" +); + +/* init calls */ int board_early_init_f(void) { - /* In current chip PAE support for DMA is broken, disabling it. */ - writel(0, (void __iomem *) CREG_PAE); + /* + * Setup AXI apertures unconditionally as we want to have DDR + * in 0x00000000 region when we are kicking slave cpus. + */ + init_memory_bridge(); - /* Really apply settings made above */ - writel(1, (void __iomem *) CREG_PAE_UPDATE); + return 0; +} + +int board_early_init_r(void) +{ + /* + * TODO: Init USB here to be able read environment from USB MSD. + * It can be done with usb_init() call. We can't do it right now + * due to brocken USB IP SW reset and lack of USB IP HW reset in + * linux kernel (if we init USB here we will break USB in linux) + */ + + /* + * Flush all d$ as we want to use uncached area with st.di / ld.di + * instructions and we don't want to have any dirty line in L1d$ or SL$ + * in this area. It is enough to flush all d$ once here as we access to + * uncached area with regular st (non .di) instruction only when we copy + * data during u-boot relocation. + */ + flush_dcache_all(); + + printf("Relocation Offset is: %08lx\n", gd->reloc_off); return 0; } -#define SDIO_BASE (ARC_PERIPHERAL_BASE + 0xA000) -#define SDIO_UHS_REG_EXT (SDIO_BASE + 0x108) -#define SDIO_UHS_REG_EXT_DIV_2 (2 << 30) +int board_late_init(void) +{ + /* + * Populate environment with clock frequency values - + * run hsdk_clock get callback without uboot command run. + */ + do_hsdk_clock_get(NULL, 0, 0, NULL); + + return 0; +} int board_mmc_init(bd_t *bis) { @@ -44,7 +1034,7 @@ int board_mmc_init(bd_t *bis) * Switch SDIO external ciu clock divider from default div-by-8 to * minimum possible div-by-2. */ - writel(SDIO_UHS_REG_EXT_DIV_2, (void __iomem *) SDIO_UHS_REG_EXT); + writel(SDIO_UHS_REG_EXT_DIV_2, (void __iomem *)SDIO_UHS_REG_EXT); memset(host, 0, sizeof(struct dwmci_host)); host->name = "Synopsys Mobile storage"; @@ -57,28 +1047,3 @@ int board_mmc_init(bd_t *bis) return 0; } - -#define RESET_VECTOR_ADDR 0x0 - -void smp_set_core_boot_addr(unsigned long addr, int corenr) -{ - /* All cores have reset vector pointing to 0 */ - writel(addr, (void __iomem *)RESET_VECTOR_ADDR); - - /* Make sure other cores see written value in memory */ - flush_dcache_all(); -} - -void smp_kick_all_cpus(void) -{ -#define BITS_START_CORE1 1 -#define BITS_START_CORE2 2 -#define BITS_START_CORE3 3 - - int cmd = readl((void __iomem *)CREG_CPU_START); - - cmd |= (1 << BITS_START_CORE1) | - (1 << BITS_START_CORE2) | - (1 << BITS_START_CORE3); - writel(cmd, (void __iomem *)CREG_CPU_START); -} diff --git a/board/xilinx/zynq/MAINTAINERS b/board/xilinx/zynq/MAINTAINERS index e0dc4fe..fc6463a 100644 --- a/board/xilinx/zynq/MAINTAINERS +++ b/board/xilinx/zynq/MAINTAINERS @@ -1,6 +1,7 @@ ZYNQ BOARD M: Michal Simek <monstr@monstr.eu> S: Maintained +F: arch/arm/dts/zynq-* F: board/xilinx/zynq/ F: include/configs/zynq*.h F: configs/zynq_*_defconfig diff --git a/board/xilinx/zynq/board.c b/board/xilinx/zynq/board.c index fb8eab0..838ac0f 100644 --- a/board/xilinx/zynq/board.c +++ b/board/xilinx/zynq/board.c @@ -6,9 +6,11 @@ */ #include <common.h> +#include <dm/uclass.h> #include <fdtdec.h> #include <fpga.h> #include <mmc.h> +#include <wdt.h> #include <zynqpl.h> #include <asm/arch/hardware.h> #include <asm/arch/sys_proto.h> @@ -33,6 +35,22 @@ static xilinx_desc fpga045 = XILINX_XC7Z045_DESC(0x45); static xilinx_desc fpga100 = XILINX_XC7Z100_DESC(0x100); #endif +#if !defined(CONFIG_SPL_BUILD) && defined(CONFIG_WDT) +static struct udevice *watchdog_dev; +#endif + +#if !defined(CONFIG_SPL_BUILD) && defined(CONFIG_BOARD_EARLY_INIT_F) +int board_early_init_f(void) +{ +# if defined(CONFIG_WDT) + /* bss is not cleared at time when watchdog_reset() is called */ + watchdog_dev = NULL; +# endif + + return 0; +} +#endif + int board_init(void) { #if (defined(CONFIG_FPGA) && !defined(CONFIG_SPL_BUILD)) || \ @@ -75,6 +93,15 @@ int board_init(void) } #endif +#if !defined(CONFIG_SPL_BUILD) && defined(CONFIG_WDT) + if (uclass_get_device(UCLASS_WDT, 0, &watchdog_dev)) { + puts("Watchdog: Not found!\n"); + } else { + wdt_start(watchdog_dev, 0, 0); + puts("Watchdog: Started\n"); + } +# endif + #if (defined(CONFIG_FPGA) && !defined(CONFIG_SPL_BUILD)) || \ (defined(CONFIG_SPL_FPGA_SUPPORT) && defined(CONFIG_SPL_BUILD)) fpga_init(); @@ -164,3 +191,25 @@ int dram_init(void) return 0; } #endif + +#if defined(CONFIG_WATCHDOG) +/* Called by macro WATCHDOG_RESET */ +void watchdog_reset(void) +{ +# if !defined(CONFIG_SPL_BUILD) + static ulong next_reset; + ulong now; + + if (!watchdog_dev) + return; + + now = timer_get_us(); + + /* Do not reset the watchdog too often */ + if (now > next_reset) { + wdt_reset(watchdog_dev); + next_reset = now + 1000; + } +# endif +} +#endif diff --git a/board/xilinx/zynqmp/Kconfig b/board/xilinx/zynqmp/Kconfig new file mode 100644 index 0000000..7d1f739 --- /dev/null +++ b/board/xilinx/zynqmp/Kconfig @@ -0,0 +1,18 @@ +# Copyright (c) 2018, Xilinx, Inc. +# +# SPDX-License-Identifier: GPL-2.0 + +if ARCH_ZYNQMP + +config CMD_ZYNQMP + bool "Enable ZynqMP specific commands" + default y + help + Enable ZynqMP specific commands like "zynqmp secure" + which is used for zynqmp secure image verification. + The secure image is a xilinx specific BOOT.BIN with + either authentication or encryption or both encryption + and authentication feature enabled while generating + BOOT.BIN using Xilinx bootgen tool. + +endif diff --git a/board/xilinx/zynqmp/MAINTAINERS b/board/xilinx/zynqmp/MAINTAINERS index 69edbf2..bb39f87 100644 --- a/board/xilinx/zynqmp/MAINTAINERS +++ b/board/xilinx/zynqmp/MAINTAINERS @@ -1,6 +1,7 @@ XILINX_ZYNQMP BOARDS M: Michal Simek <michal.simek@xilinx.com> S: Maintained +F: arch/arm/dts/zynqmp-* F: board/xilinx/zynqmp/ F: include/configs/xilinx_zynqmp* F: configs/xilinx_zynqmp* diff --git a/board/xilinx/zynqmp/Makefile b/board/xilinx/zynqmp/Makefile index 75aab92..3b7a10e 100644 --- a/board/xilinx/zynqmp/Makefile +++ b/board/xilinx/zynqmp/Makefile @@ -26,6 +26,10 @@ ifneq ($(call ifdef_any_of, CONFIG_ZYNQMP_PSU_INIT_ENABLED CONFIG_SPL_BUILD),) obj-y += $(init-objs) endif +ifndef CONFIG_SPL_BUILD +obj-$(CONFIG_CMD_ZYNQMP) += cmds.o +endif + # Suppress "warning: function declaration isn't a prototype" CFLAGS_REMOVE_psu_init_gpl.o := -Wstrict-prototypes diff --git a/board/xilinx/zynqmp/cmds.c b/board/xilinx/zynqmp/cmds.c new file mode 100644 index 0000000..6712d7b --- /dev/null +++ b/board/xilinx/zynqmp/cmds.c @@ -0,0 +1,105 @@ +/* + * (C) Copyright 2018 Xilinx, Inc. + * Siva Durga Prasad Paladugu <siva.durga.paladugu@xilinx.com> + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#include <common.h> +#include <malloc.h> +#include <asm/arch/sys_proto.h> +#include <asm/io.h> + +static int zynqmp_verify_secure(u8 *key_ptr, u8 *src_ptr, u32 len) +{ + int ret; + u32 src_lo, src_hi; + u32 key_lo = 0; + u32 key_hi = 0; + u32 ret_payload[PAYLOAD_ARG_CNT]; + u64 addr; + + if ((ulong)src_ptr != ALIGN((ulong)src_ptr, + CONFIG_SYS_CACHELINE_SIZE)) { + printf("Failed: source address not aligned:%p\n", src_ptr); + return -EINVAL; + } + + src_lo = lower_32_bits((ulong)src_ptr); + src_hi = upper_32_bits((ulong)src_ptr); + flush_dcache_range((ulong)src_ptr, (ulong)(src_ptr + len)); + + if (key_ptr) { + key_lo = lower_32_bits((ulong)key_ptr); + key_hi = upper_32_bits((ulong)key_ptr); + flush_dcache_range((ulong)key_ptr, + (ulong)(key_ptr + KEY_PTR_LEN)); + } + + ret = invoke_smc(ZYNQMP_SIP_SVC_PM_SECURE_IMG_LOAD, src_lo, src_hi, + key_lo, key_hi, ret_payload); + if (ret) { + printf("Failed: secure op status:0x%x\n", ret); + } else { + addr = (u64)ret_payload[1] << 32 | ret_payload[2]; + printf("Verified image at 0x%llx\n", addr); + env_set_hex("zynqmp_verified_img_addr", addr); + } + + return ret; +} + +/** + * do_zynqmp - Handle the "zynqmp" command-line command + * @cmdtp: Command data struct pointer + * @flag: Command flag + * @argc: Command-line argument count + * @argv: Array of command-line arguments + * + * Processes the zynqmp specific commands + * + * Return: return 0 on success and CMD_RET_USAGE incase of misuse and error + */ +static int do_zynqmp(cmd_tbl_t *cmdtp, int flag, int argc, + char *const argv[]) +{ + u64 src_addr; + u32 len; + u8 *key_ptr = NULL; + u8 *src_ptr; + int ret; + + if (argc > 5 || argc < 4 || strncmp(argv[1], "secure", 6)) + return CMD_RET_USAGE; + + src_addr = simple_strtoull(argv[2], NULL, 16); + + len = simple_strtoul(argv[3], NULL, 16); + + if (argc > 4) + key_ptr = (uint8_t *)(uintptr_t)simple_strtoull(argv[4], + NULL, 16); + + src_ptr = (uint8_t *)(uintptr_t)src_addr; + + ret = zynqmp_verify_secure(key_ptr, src_ptr, len); + if (ret) + return CMD_RET_FAILURE; + + return CMD_RET_SUCCESS; +} + +/***************************************************/ +#ifdef CONFIG_SYS_LONGHELP +static char zynqmp_help_text[] = + "secure src len [key_addr] - verifies secure images of $len bytes\n" + " long at address $src. Optional key_addr\n" + " can be specified if user key needs to\n" + " be used for decryption\n"; +#endif + +U_BOOT_CMD( + zynqmp, 5, 1, do_zynqmp, + "Verify and load secure images", + zynqmp_help_text +) diff --git a/board/xilinx/zynqmp/zynqmp.c b/board/xilinx/zynqmp/zynqmp.c index ff0b3c7..0d1bd54 100644 --- a/board/xilinx/zynqmp/zynqmp.c +++ b/board/xilinx/zynqmp/zynqmp.c @@ -31,6 +31,7 @@ static const struct { u32 id; u32 ver; char *name; + bool evexists; } zynqmp_devices[] = { { .id = 0x10, @@ -53,11 +54,13 @@ static const struct { { .id = 0x20, .name = "5ev", + .evexists = 1, }, { .id = 0x20, .ver = 0x100, .name = "5eg", + .evexists = 1, }, { .id = 0x20, @@ -67,11 +70,13 @@ static const struct { { .id = 0x21, .name = "4ev", + .evexists = 1, }, { .id = 0x21, .ver = 0x100, .name = "4eg", + .evexists = 1, }, { .id = 0x21, @@ -81,11 +86,13 @@ static const struct { { .id = 0x30, .name = "7ev", + .evexists = 1, }, { .id = 0x30, .ver = 0x100, .name = "7eg", + .evexists = 1, }, { .id = 0x30, @@ -219,20 +226,48 @@ int chip_id(unsigned char id) return val; } +#define ZYNQMP_VERSION_SIZE 9 +#define ZYNQMP_PL_STATUS_BIT 9 +#define ZYNQMP_PL_STATUS_MASK BIT(ZYNQMP_PL_STATUS_BIT) +#define ZYNQMP_CSU_VERSION_MASK ~(ZYNQMP_PL_STATUS_MASK) + #if defined(CONFIG_FPGA) && defined(CONFIG_FPGA_ZYNQMPPL) && \ !defined(CONFIG_SPL_BUILD) static char *zynqmp_get_silicon_idcode_name(void) { u32 i, id, ver; + char *buf; + static char name[ZYNQMP_VERSION_SIZE]; id = chip_id(IDCODE); ver = chip_id(IDCODE2); for (i = 0; i < ARRAY_SIZE(zynqmp_devices); i++) { - if (zynqmp_devices[i].id == id && zynqmp_devices[i].ver == ver) - return zynqmp_devices[i].name; + if ((zynqmp_devices[i].id == id) && + (zynqmp_devices[i].ver == (ver & + ZYNQMP_CSU_VERSION_MASK))) { + strncat(name, "zu", 2); + strncat(name, zynqmp_devices[i].name, + ZYNQMP_VERSION_SIZE - 3); + break; + } + } + + if (i >= ARRAY_SIZE(zynqmp_devices)) + return "unknown"; + + if (!zynqmp_devices[i].evexists) + return name; + + if (ver & ZYNQMP_PL_STATUS_MASK) + return name; + + if (strstr(name, "eg") || strstr(name, "ev")) { + buf = strstr(name, "e"); + *buf = '\0'; } - return "unknown"; + + return name; } #endif @@ -250,8 +285,6 @@ int board_early_init_f(void) return ret; } -#define ZYNQMP_VERSION_SIZE 9 - int board_init(void) { printf("EL Level:\tEL%d\n", current_el()); @@ -260,12 +293,7 @@ int board_init(void) !defined(CONFIG_SPL_BUILD) || (defined(CONFIG_SPL_FPGA_SUPPORT) && \ defined(CONFIG_SPL_BUILD)) if (current_el() != 3) { - static char version[ZYNQMP_VERSION_SIZE]; - - strncat(version, "zu", 2); - zynqmppl.name = strncat(version, - zynqmp_get_silicon_idcode_name(), - ZYNQMP_VERSION_SIZE - 3); + zynqmppl.name = zynqmp_get_silicon_idcode_name(); printf("Chip ID:\t%s\n", zynqmppl.name); fpga_init(); fpga_add(fpga_xilinx, &zynqmppl); @@ -316,6 +344,23 @@ int zynq_board_read_rom_ethaddr(unsigned char *ethaddr) return 0; } +unsigned long do_go_exec(ulong (*entry)(int, char * const []), int argc, + char * const argv[]) +{ + int ret = 0; + + if (current_el() > 1) { + smp_kick_all_cpus(); + dcache_disable(); + armv8_switch_to_el1(0x0, 0, 0, 0, (unsigned long)entry, + ES_TO_AARCH64); + } else { + printf("FAIL: current EL is not above EL1\n"); + ret = EINVAL; + } + return ret; +} + #if !defined(CONFIG_SYS_SDRAM_BASE) && !defined(CONFIG_SYS_SDRAM_SIZE) int dram_init_banksize(void) { |