diff options
Diffstat (limited to 'arch/arm/mach-layerscape')
25 files changed, 2210 insertions, 337 deletions
diff --git a/arch/arm/mach-layerscape/Kconfig b/arch/arm/mach-layerscape/Kconfig index 139c63f66d..5658a63b33 100644 --- a/arch/arm/mach-layerscape/Kconfig +++ b/arch/arm/mach-layerscape/Kconfig @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-only + if ARCH_LAYERSCAPE config ARCH_LAYERSCAPE_PPA @@ -5,7 +7,6 @@ config ARCH_LAYERSCAPE_PPA select ARM_PSCI_OF select ARM_SMCCC select FITIMAGE - bool help The "Primary Protected Application" (PPA) is a PSCI compliant firmware distributed by NXP. It is needed to start the secondary cores on @@ -13,10 +14,23 @@ config ARCH_LAYERSCAPE_PPA work properly. The precompiled firmware images can be found here: https://github.com/NXP/qoriq-ppa-binary -config ARCH_LS1046 +config ARCH_LS1028 + bool select CPU_V8 select SYS_SUPPORTS_64BIT_KERNEL + select ARM_ATF + select FIRMWARE_LS1028A_ATF + +config ARCH_LS1046 bool + select CPU_V8 + select SYS_SUPPORTS_64BIT_KERNEL + +if 64BIT + +config MACH_LS1028ARDB + bool "QorIQ LS1028A Reference Design Board" + select ARCH_LS1028 config MACH_LS1046ARDB bool "QorIQ LS1046A Reference Design Board" @@ -30,5 +44,24 @@ config MACH_LS1046ARDB config MACH_TQMLS1046A bool "TQ TQMLS1046A Board" select ARCH_LS1046 + select MCI_IMX_ESDHC_PBL + select DDR_FSL + select DDR_FSL_DDR4 + +endif + +config ARCH_LS1021 + select CPU_V7 + bool + +if 32BIT + +config MACH_LS1021AIOT + bool "LS1021AIOT Board" + select ARCH_LS1021 + select DDR_FSL + select DDR_FSL_DDR3 + +endif endif diff --git a/arch/arm/mach-layerscape/Makefile b/arch/arm/mach-layerscape/Makefile index 854a327c91..e4bb1b42f2 100644 --- a/arch/arm/mach-layerscape/Makefile +++ b/arch/arm/mach-layerscape/Makefile @@ -1,8 +1,16 @@ +# SPDX-License-Identifier: GPL-2.0-only + obj- := __dummy__.o -lwl-y += lowlevel.o errata.o -lwl-$(CONFIG_ARCH_LS1046) += lowlevel-ls1046a.o -obj-y += icid.o -obj-pbl-y += boot.o +lwl-y += errata.o +lwl-$(CONFIG_ARCH_LS1046) += lowlevel.o lowlevel-ls1046a.o +obj-$(CONFIG_ARCH_LS1046) += icid.o +obj-pbl-y += boot.o soc.o pbl-y += xload-qspi.o xload.o +pbl-$(CONFIG_ARCH_LS1028) += tzc400.o obj-$(CONFIG_ARCH_LAYERSCAPE_PPA) += ppa.o ppa-entry.o obj-$(CONFIG_BOOTM) += pblimage.o + +lwl-$(CONFIG_ARCH_LS1021) += lowlevel-ls102xa.o +obj-$(CONFIG_ARCH_LS1021) += restart.o ls102xa_stream_id.o + +lwl-$(CONFIG_ARCH_LS1028) += lowlevel-ls1028a.o diff --git a/arch/arm/mach-layerscape/boot.c b/arch/arm/mach-layerscape/boot.c index c804977d22..4d074205cc 100644 --- a/arch/arm/mach-layerscape/boot.c +++ b/arch/arm/mach-layerscape/boot.c @@ -3,10 +3,12 @@ #include <common.h> #include <init.h> #include <bootsource.h> -#include <mach/layerscape.h> +#include <linux/bitfield.h> +#include <mach/layerscape/layerscape.h> #include <soc/fsl/immap_lsch2.h> +#include <soc/fsl/immap_lsch3.h> -enum bootsource ls1046_bootsource_get(void) +enum bootsource ls1046a_bootsource_get(void) { void __iomem *dcfg = IOMEM(LSCH2_DCFG_ADDR); uint32_t rcw_src; @@ -27,13 +29,55 @@ enum bootsource ls1046_bootsource_get(void) return BOOTSOURCE_UNKNOWN; } -static int ls1046a_bootsource_init(void) +enum bootsource ls1021a_bootsource_get(void) { - if (!of_machine_is_compatible("fsl,ls1046a")) - return 0; + return ls1046a_bootsource_get(); +} + +void ls1021a_bootsource_init(void) +{ + bootsource_set_raw(ls1021a_bootsource_get(), BOOTSOURCE_INSTANCE_UNKNOWN); +} + +void ls1046a_bootsource_init(void) +{ + bootsource_set_raw(ls1046a_bootsource_get(), BOOTSOURCE_INSTANCE_UNKNOWN); +} + +#define PORSR1_RCW_SRC GENMASK(26, 23) + +static enum bootsource ls1028a_bootsource_get(int *instance) +{ + void __iomem *porsr1 = IOMEM(LSCH3_DCFG_BASE); + uint32_t rcw_src; - bootsource_set(ls1046_bootsource_get()); + rcw_src = FIELD_GET(PORSR1_RCW_SRC, readl(porsr1)); + + printf("%s: 0x%08x\n", __func__, rcw_src); + + switch (rcw_src) { + case 8: + *instance = 0; + return BOOTSOURCE_MMC; + case 9: + *instance = 1; + return BOOTSOURCE_MMC; + case 0xa: + return BOOTSOURCE_I2C; + case 0xd: + case 0xc: + return BOOTSOURCE_NAND; + case 0xf: + return BOOTSOURCE_SPI_NOR; + } + + return BOOTSOURCE_UNKNOWN; +} + +void ls1028a_bootsource_init(void) +{ + int instance = BOOTSOURCE_INSTANCE_UNKNOWN; + enum bootsource source = ls1028a_bootsource_get(&instance); - return 0; + bootsource_set_raw(source, instance); } -coredevice_initcall(ls1046a_bootsource_init);
\ No newline at end of file diff --git a/arch/arm/mach-layerscape/errata.c b/arch/arm/mach-layerscape/errata.c index 4f4b759ddb..deab584243 100644 --- a/arch/arm/mach-layerscape/errata.c +++ b/arch/arm/mach-layerscape/errata.c @@ -2,13 +2,12 @@ #include <common.h> #include <io.h> #include <soc/fsl/immap_lsch2.h> +#include <soc/fsl/immap_lsch3.h> #include <soc/fsl/fsl_ddr_sdram.h> #include <asm/system.h> -#include <mach/errata.h> -#include <mach/lowlevel.h> - -#define scfg_clrsetbits32(addr, clear, set) clrsetbits_be32(addr, clear, set) -#define scfg_clrbits32(addr, clear) clrbits_be32(addr, clear) +#include <mach/layerscape/errata.h> +#include <mach/layerscape/lowlevel.h> +#include <soc/fsl/scfg.h> static inline void set_usb_pcstxswingfull(u32 __iomem *scfg, u32 offset) { @@ -17,6 +16,22 @@ static inline void set_usb_pcstxswingfull(u32 __iomem *scfg, u32 offset) SCFG_USB_PCSTXSWINGFULL << 9); } +static void erratum_a008997_ls1021a(void) +{ + u32 __iomem *scfg = (u32 __iomem *)LSCH2_SCFG_ADDR; + + set_usb_pcstxswingfull(scfg, SCFG_USB3PRM2CR_USB1); +} + +static void erratum_a008997_ls1028a(void) +{ + void __iomem *dcsr = IOMEM(LSCH3_DCSR_BASE); + + clrsetbits_le32(dcsr + LSCH3_DCSR_USB_IOCR1, + 0x7f << 11, + LSCH3_DCSR_USB_PCSTXSWINGFULL << 11); +} + static void erratum_a008997_ls1046a(void) { u32 __iomem *scfg = (u32 __iomem *)LSCH2_SCFG_ADDR; @@ -26,22 +41,24 @@ static void erratum_a008997_ls1046a(void) set_usb_pcstxswingfull(scfg, SCFG_USB3PRM2CR_USB3); } -#define PROGRAM_USB_PHY_RX_OVRD_IN_HI(phy) \ - out_be16((phy) + SCFG_USB_PHY_RX_OVRD_IN_HI, USB_PHY_RX_EQ_VAL_1); \ - out_be16((phy) + SCFG_USB_PHY_RX_OVRD_IN_HI, USB_PHY_RX_EQ_VAL_2); \ - out_be16((phy) + SCFG_USB_PHY_RX_OVRD_IN_HI, USB_PHY_RX_EQ_VAL_3); \ - out_be16((phy) + SCFG_USB_PHY_RX_OVRD_IN_HI, USB_PHY_RX_EQ_VAL_4) +static void erratum_a009007(void __iomem *phy, u16 val1, u16 val2, u16 val3, u16 val4) +{ + scfg_out16(phy + SCFG_USB_PHY_RX_OVRD_IN_HI, val1); + scfg_out16(phy + SCFG_USB_PHY_RX_OVRD_IN_HI, val2); + scfg_out16(phy + SCFG_USB_PHY_RX_OVRD_IN_HI, val3); + scfg_out16(phy + SCFG_USB_PHY_RX_OVRD_IN_HI, val4); +} static void erratum_a009007_ls1046a(void) { - void __iomem *usb_phy = IOMEM(SCFG_USB_PHY1); - - PROGRAM_USB_PHY_RX_OVRD_IN_HI(usb_phy); - usb_phy = (void __iomem *)SCFG_USB_PHY2; - PROGRAM_USB_PHY_RX_OVRD_IN_HI(usb_phy); + erratum_a009007(IOMEM(SCFG_USB_PHY1), 0x0000, 0x0080, 0x0380, 0x0b80); + erratum_a009007(IOMEM(SCFG_USB_PHY2), 0x0000, 0x0080, 0x0380, 0x0b80); + erratum_a009007(IOMEM(SCFG_USB_PHY3), 0x0000, 0x0080, 0x0380, 0x0b80); +} - usb_phy = (void __iomem *)SCFG_USB_PHY3; - PROGRAM_USB_PHY_RX_OVRD_IN_HI(usb_phy); +static void erratum_a009007_ls1021a(void) +{ + erratum_a009007(IOMEM(SCFG_USB_PHY1), 0x0000, 0x8000, 0x8004, 0x800C); } static inline void set_usb_txvreftune(u32 __iomem *scfg, u32 offset) @@ -49,6 +66,18 @@ static inline void set_usb_txvreftune(u32 __iomem *scfg, u32 offset) scfg_clrsetbits32(scfg + offset / 4, 0xf << 6, SCFG_USB_TXVREFTUNE << 6); } +static void erratum_a009007_ls1028a(void) +{ + erratum_a009007(IOMEM(LSCH3_DCSR_BASE), 0x0000, 0x0080, 0x0380, 0x0b80); +} + +static void erratum_a009008_ls1021a(void) +{ + u32 __iomem *scfg = IOMEM(LSCH2_SCFG_ADDR); + + set_usb_txvreftune(scfg, SCFG_USB3PRM1CR_USB1); +} + static void erratum_a009008_ls1046a(void) { u32 __iomem *scfg = IOMEM(LSCH2_SCFG_ADDR); @@ -63,6 +92,13 @@ static inline void set_usb_sqrxtune(u32 __iomem *scfg, u32 offset) scfg_clrbits32(scfg + offset / 4, SCFG_USB_SQRXTUNE_MASK << 23); } +static void erratum_a009798_ls1021a(void) +{ + u32 __iomem *scfg = IOMEM(LSCH2_SCFG_ADDR); + + set_usb_sqrxtune(scfg, SCFG_USB3PRM1CR_USB1); +} + static void erratum_a009798_ls1046a(void) { u32 __iomem *scfg = IOMEM(LSCH2_SCFG_ADDR); @@ -72,15 +108,16 @@ static void erratum_a009798_ls1046a(void) set_usb_sqrxtune(scfg, SCFG_USB3PRM1CR_USB3); } -static void erratum_a008850_early(void) +static void erratum_a008850_early(struct ccsr_cci400 __iomem *cci, + struct ccsr_ddr __iomem *ddr) { /* part 1 of 2 */ - struct ccsr_cci400 __iomem *cci = IOMEM(LSCH2_CCI400_ADDR); - struct ccsr_ddr __iomem *ddr = IOMEM(LSCH2_DDR_ADDR); /* Skip if running at lower exception level */ - if (current_el() < 3) - return; +#if __LINUX_ARM_ARCH__ > 7 + if (current_el() < 3) + return; +#endif /* disables propagation of barrier transactions to DDRC from CCI400 */ out_le32(&cci->ctrl_ord, CCI400_CTRLORD_TERM_BARRIER); @@ -89,27 +126,64 @@ static void erratum_a008850_early(void) ddr_out32(&ddr->eor, DDR_EOR_RD_REOD_DIS | DDR_EOR_WD_REOD_DIS); } -/* erratum_a009942_check_cpo */ +/* + * This erratum requires a register write before being Memory + * controller 3 being enabled. + */ +static void erratum_a008514(void) +{ + u32 *eddrtqcr1; + + eddrtqcr1 = IOMEM(LSCH3_DCSR_DDR3_ADDR) + 0x800; + out_le32(eddrtqcr1, 0x63b20002); +} + +static void erratum_a009798(void) +{ + u32 __iomem *scfg = IOMEM(LSCH3_SCFG_BASE); + + clrbits_be32(scfg + LSCH3_SCFG_USB3PRM1CR / 4, + LSCH3_SCFG_USB_SQRXTUNE_MASK << 23); +} void ls1046a_errata(void) { - erratum_a008850_early(); + erratum_a008850_early(IOMEM(LSCH2_CCI400_ADDR), IOMEM(LSCH2_DDR_ADDR)); erratum_a009008_ls1046a(); erratum_a009798_ls1046a(); erratum_a008997_ls1046a(); erratum_a009007_ls1046a(); } -static void erratum_a008850_post(void) +void ls1021a_errata(void) +{ + erratum_a008850_early(IOMEM(LSCH2_CCI400_ADDR), IOMEM(LSCH2_DDR_ADDR)); + erratum_a009008_ls1021a(); + erratum_a009798_ls1021a(); + erratum_a008997_ls1021a(); + erratum_a009007_ls1021a(); +} + +void ls1028a_errata(void) +{ + erratum_a008850_early(IOMEM(LSCH3_CCI400_ADDR), IOMEM(LSCH3_DDR_ADDR)); + erratum_a009007_ls1028a(); + erratum_a008997_ls1028a(); + erratum_a008514(); + erratum_a009798(); +} + +static void erratum_a008850_post(struct ccsr_cci400 __iomem *cci, + struct ccsr_ddr __iomem *ddr) { /* part 2 of 2 */ - struct ccsr_cci400 __iomem *cci = IOMEM(LSCH2_CCI400_ADDR); - struct ccsr_ddr __iomem *ddr = IOMEM(LSCH2_DDR_ADDR); u32 tmp; /* Skip if running at lower exception level */ - if (current_el() < 3) - return; +#if __LINUX_ARM_ARCH__ > 7 + if (current_el() < 3) + return; +#endif /* enable propagation of barrier transactions to DDRC from CCI400 */ out_le32(&cci->ctrl_ord, CCI400_CTRLORD_EN_BARRIER); @@ -190,6 +264,16 @@ static void erratum_a009942_check_cpo(void) void ls1046a_errata_post_ddr(void) { - erratum_a008850_post(); + erratum_a008850_post(IOMEM(LSCH2_CCI400_ADDR), IOMEM(LSCH2_DDR_ADDR)); erratum_a009942_check_cpo(); } + +void ls1021a_errata_post_ddr(void) +{ + erratum_a008850_post(IOMEM(LSCH2_CCI400_ADDR), IOMEM(LSCH2_DDR_ADDR)); +} + +void ls1028a_errata_post_ddr(void) +{ + erratum_a008850_post(IOMEM(LSCH3_CCI400_ADDR), IOMEM(LSCH3_DDR_ADDR)); +} diff --git a/arch/arm/mach-layerscape/icid.c b/arch/arm/mach-layerscape/icid.c index 2326d7e67a..ebe3896075 100644 --- a/arch/arm/mach-layerscape/icid.c +++ b/arch/arm/mach-layerscape/icid.c @@ -1,9 +1,14 @@ +// SPDX-License-Identifier: GPL-2.0-only + #include <common.h> #include <io.h> #include <init.h> +#include <of_address.h> #include <soc/fsl/immap_lsch2.h> +#include <soc/fsl/immap_lsch3.h> #include <soc/fsl/fsl_qbman.h> #include <soc/fsl/fsl_fman.h> +#include <mach/layerscape/layerscape.h> /* * Stream IDs on Chassis-2 (for example ls1043a, ls1046a, ls1012) devices @@ -36,9 +41,6 @@ * */ - -#define FSL_INVALID_STREAM_ID 0 - /* legacy devices */ #define FSL_USB1_STREAM_ID 1 #define FSL_USB2_STREAM_ID 2 @@ -56,8 +58,8 @@ #define FSL_PEX_STREAM_ID_END 26 /* DPAA1 - Stream-ID that can be programmed in DPAA1 h/w */ -#define FSL_DPAA1_STREAM_ID_START 27 -#define FSL_DPAA1_STREAM_ID_END 63 +#define DPAA1_SID_START 27 +#define DPAA1_SID_END 63 struct icid_id_table { const char *compat; @@ -67,177 +69,727 @@ struct icid_id_table { phys_addr_t reg_addr; }; +static void of_set_iommu_prop(struct device_node *np, phandle iommu_handle, + int stream_id) +{ + u32 prop[] = { + iommu_handle, + stream_id + }; + + of_property_write_u32_array(np, "iommus", prop, ARRAY_SIZE(prop)); +} + +static phandle of_get_iommu_handle(struct device_node *root) +{ + struct device_node *iommu; + + iommu = of_find_compatible_node(root, NULL, "arm,mmu-500"); + if (!iommu) { + pr_info("No \"arm,mmu-500\" node found, won't fixup\n"); + return 0; + } + + return of_node_create_phandle(iommu); +} + +static int of_fixup_icid(struct device_node *root, phandle iommu_handle, + const struct icid_id_table *icid_table, int num_icid) +{ + int i; + + for (i = 0; i < num_icid; i++) { + const struct icid_id_table *icid = &icid_table[i]; + struct device_node *np; + + if (!icid->compat) + continue; + + for_each_compatible_node_from(np, root, NULL, icid->compat) { + struct resource res; + + if (of_address_to_resource(np, 0, &res)) + continue; + + if (res.start == icid->compat_addr) { + of_set_iommu_prop(np, iommu_handle, icid->id); + break; + } + } + } + + return 0; +} + +static void setup_icid_offsets(const struct icid_id_table *icid_table, int num_icids, bool le) +{ + int i; + + for (i = 0; i < num_icids; i++) { + const struct icid_id_table *icid = &icid_table[i]; + + if (le) + out_le32((u32 *)(icid->reg_addr), icid->reg); + else + out_be32((u32 *)(icid->reg_addr), icid->reg); + } +} + struct fman_icid_id_table { u32 port_id; u32 icid; }; -#define SET_ICID_ENTRY(name, idA, regA, addr, compataddr) \ - { \ - .compat = name, \ - .id = idA, \ - .reg = regA, \ - .compat_addr = compataddr, \ - .reg_addr = addr, \ +#define QMAN_CQSIDR_REG 0x20a80 + +#define SEC_JRnICID_LS(n) ((0x10 + (n) * 0x8) + 0x4) +#define SEC_RTICnICID_LS(n) ((0x60 + (n) * 0x8) + 0x4) +#define SEC_DECOnICID_LS(n) ((0xa0 + (n) * 0x8) + 0x4) +#define SEC_QIIC_LS 0x70024 +#define SEC_IRBAR_JRn(n) (0x10000 * ((n) + 1)) + +static const struct icid_id_table icid_tbl_ls1046a[] = { + { + .compat = "fsl,qman", + .id = DPAA1_SID_START, + .reg = DPAA1_SID_START, + .compat_addr = LSCH2_QMAN_ADDR, + .reg_addr = offsetof(struct ccsr_qman_v3, liodnr) + LSCH2_QMAN_ADDR, + }, { + .compat = "fsl,bman", + .id = DPAA1_SID_START + 1, + .reg = DPAA1_SID_START + 1, + .compat_addr = LSCH2_BMAN_ADDR, + .reg_addr = offsetof(struct ccsr_bman, liodnr) + LSCH2_BMAN_ADDR, + }, { + .compat = "fsl,esdhc", + .id = FSL_SDHC_STREAM_ID, + .reg = (((FSL_SDHC_STREAM_ID) << 24) | (1 << 23)), + .compat_addr = LSCH2_ESDHC_ADDR, + .reg_addr = offsetof(struct ccsr_scfg, sdhc_icid) + LSCH2_SCFG_ADDR, + }, { + .compat = "snps,dwc3", + .id = FSL_USB1_STREAM_ID, + .reg = (((FSL_USB1_STREAM_ID) << 24) | (1 << 23)), + .compat_addr = LSCH2_XHCI_USB1_ADDR, + .reg_addr = offsetof(struct ccsr_scfg, usb1_icid) + LSCH2_SCFG_ADDR, + }, { + .compat = "snps,dwc3", + .id = FSL_USB2_STREAM_ID, + .reg = (((FSL_USB2_STREAM_ID) << 24) | (1 << 23)), + .compat_addr = LSCH2_XHCI_USB2_ADDR, + .reg_addr = offsetof(struct ccsr_scfg, usb2_icid) + LSCH2_SCFG_ADDR, + }, { + .compat = "snps,dwc3", + .id = FSL_USB3_STREAM_ID, + .reg = (((FSL_USB3_STREAM_ID) << 24) | (1 << 23)), + .compat_addr = LSCH2_XHCI_USB3_ADDR, + .reg_addr = offsetof(struct ccsr_scfg, usb3_icid) + LSCH2_SCFG_ADDR, + }, { + .compat = "fsl,ls1046a-ahci", + .id = FSL_SATA_STREAM_ID, + .reg = (((FSL_SATA_STREAM_ID) << 24) | (1 << 23)), + .compat_addr = LSCH2_HCI_BASE_ADDR, + .reg_addr = offsetof(struct ccsr_scfg, sata_icid) + LSCH2_SCFG_ADDR, + }, { + .compat = "fsl,ls1046a-qdma", + .id = FSL_QDMA_STREAM_ID, + .reg = (1 << 31) | (FSL_QDMA_STREAM_ID), + .compat_addr = LSCH2_QDMA_BASE_ADDR, + .reg_addr = LSCH2_QDMA_BASE_ADDR + QMAN_CQSIDR_REG, + }, { + .id = FSL_QDMA_STREAM_ID, + .reg = (1 << 31) | (FSL_QDMA_STREAM_ID), + .compat_addr = LSCH2_QDMA_BASE_ADDR, + .reg_addr = LSCH2_QDMA_BASE_ADDR + QMAN_CQSIDR_REG + 4, + }, { + .compat = "fsl,vf610-edma", + .id = FSL_EDMA_STREAM_ID, + .reg = (((FSL_EDMA_STREAM_ID) << 24) | (1 << 23)), + .compat_addr = LSCH2_EDMA_BASE_ADDR, + .reg_addr = offsetof(struct ccsr_scfg, edma_icid) + LSCH2_SCFG_ADDR, + }, { + .id = FSL_ETR_STREAM_ID, + .reg = (((FSL_ETR_STREAM_ID) << 24) | (1 << 23)), + .reg_addr = offsetof(struct ccsr_scfg, etr_icid) + LSCH2_SCFG_ADDR, + }, { + .id = FSL_DEBUG_STREAM_ID, + .reg = (((FSL_DEBUG_STREAM_ID) << 24) | (1 << 23)), + .reg_addr = offsetof(struct ccsr_scfg, debug_icid) + LSCH2_SCFG_ADDR, + }, { + .compat = "fsl,sec-v4.0", + .id = DPAA1_SID_END, + .compat_addr = LSCH2_SEC_ADDR, + .reg_addr = SEC_QIIC_LS + LSCH2_SEC_ADDR, + }, { + .compat = "fsl,sec-v4.0-job-ring", + .id = DPAA1_SID_START + 3, + .reg = (((DPAA1_SID_START + 3) << 16) | (DPAA1_SID_START + 3)), + .compat_addr = LSCH2_SEC_ADDR + SEC_IRBAR_JRn(0), + .reg_addr = SEC_JRnICID_LS(0) + LSCH2_SEC_ADDR, + }, { + .compat = "fsl,sec-v4.0-job-ring", + .id = DPAA1_SID_START + 4, + .reg = (((DPAA1_SID_START + 4) << 16) | (DPAA1_SID_START + 4)), + .compat_addr = LSCH2_SEC_ADDR + SEC_IRBAR_JRn(1), + .reg_addr = SEC_JRnICID_LS(1) + LSCH2_SEC_ADDR, + }, { + .compat = "fsl,sec-v4.0-job-ring", + .id = DPAA1_SID_START + 5, + .reg = (((DPAA1_SID_START + 5) << 16) | (DPAA1_SID_START + 5)), + .compat_addr = LSCH2_SEC_ADDR + SEC_IRBAR_JRn(2), + .reg_addr = SEC_JRnICID_LS(2) + LSCH2_SEC_ADDR, + }, { + .compat = "fsl,sec-v4.0-job-ring", + .id = DPAA1_SID_START + 6, + .reg = (((DPAA1_SID_START + 6) << 16) | (DPAA1_SID_START + 6)), + .compat_addr = LSCH2_SEC_ADDR + SEC_IRBAR_JRn(3), + .reg_addr = SEC_JRnICID_LS(3) + LSCH2_SEC_ADDR, + }, { + .id = DPAA1_SID_START + 7, + .reg = (((DPAA1_SID_START + 7) << 16) | (DPAA1_SID_START + 7)), + .reg_addr = SEC_RTICnICID_LS(0) + LSCH2_SEC_ADDR, + }, { + .id = DPAA1_SID_START + 8, + .reg = (((DPAA1_SID_START + 8) << 16) | (DPAA1_SID_START + 8)), + .reg_addr = SEC_RTICnICID_LS(1) + LSCH2_SEC_ADDR, + },{ + .id = DPAA1_SID_START + 9, + .reg = (((DPAA1_SID_START + 9) << 16) | (DPAA1_SID_START + 9)), + .reg_addr = SEC_RTICnICID_LS(2) + LSCH2_SEC_ADDR, + }, { + .id = DPAA1_SID_START + 10, + .reg = (((DPAA1_SID_START + 10) << 16) | (DPAA1_SID_START + 10)), + .reg_addr = SEC_RTICnICID_LS(3) + LSCH2_SEC_ADDR, + }, { + .id = DPAA1_SID_START + 11, + .reg = (((DPAA1_SID_START + 11) << 16) | (DPAA1_SID_START + 11)), + .reg_addr = SEC_DECOnICID_LS(0) + LSCH2_SEC_ADDR, + }, { + .id = DPAA1_SID_START + 12, + .reg = (((DPAA1_SID_START + 12) << 16) | (DPAA1_SID_START + 12)), + .reg_addr = SEC_DECOnICID_LS(1) + LSCH2_SEC_ADDR, + }, { + .id = DPAA1_SID_START + 13, + .reg = (((DPAA1_SID_START + 13) << 16) | (DPAA1_SID_START + 13)), + .reg_addr = SEC_DECOnICID_LS(2) + LSCH2_SEC_ADDR, + }, +}; + +static const struct fman_icid_id_table fman_icid_tbl_ls1046a[] = { + { + .port_id = 0x02, + .icid = DPAA1_SID_END, + }, { + .port_id = 0x03, + .icid = DPAA1_SID_END, + }, { + .port_id = 0x04, + .icid = DPAA1_SID_END, + }, { + .port_id = 0x05, + .icid = DPAA1_SID_END, + }, { + .port_id = 0x06, + .icid = DPAA1_SID_END, + }, { + .port_id = 0x07, + .icid = DPAA1_SID_END, + }, { + .port_id = 0x08, + .icid = DPAA1_SID_END, + }, { + .port_id = 0x09, + .icid = DPAA1_SID_END, + }, { + .port_id = 0x0a, + .icid = DPAA1_SID_END, + }, { + .port_id = 0x0b, + .icid = DPAA1_SID_END, + }, { + .port_id = 0x0c, + .icid = DPAA1_SID_END, + }, { + .port_id = 0x0d, + .icid = DPAA1_SID_END, + }, { + .port_id = 0x28, + .icid = DPAA1_SID_END, + }, { + .port_id = 0x29, + .icid = DPAA1_SID_END, + }, { + .port_id = 0x2a, + .icid = DPAA1_SID_END, + }, { + .port_id = 0x2b, + .icid = DPAA1_SID_END, + }, { + .port_id = 0x2c, + .icid = DPAA1_SID_END, + }, { + .port_id = 0x2d, + .icid = DPAA1_SID_END, + }, { + .port_id = 0x10, + .icid = DPAA1_SID_END, + }, { + .port_id = 0x11, + .icid = DPAA1_SID_END, + }, { + .port_id = 0x30, + .icid = DPAA1_SID_END, + }, { + .port_id = 0x31, + .icid = DPAA1_SID_END, + }, +}; + +static int get_fman_port_icid(int port_id, const struct fman_icid_id_table *tbl, + const int size) +{ + int i; + + for (i = 0; i < size; i++) { + if (tbl[i].port_id == port_id) + return tbl[i].icid; + } + + return -ENODEV; +} + +static void of_fixup_fman_port_icid_by_compat(struct device_node *root, + phandle iommu_handle, + const char *compat) +{ + struct device_node *np; + int ret, icid; + u32 cell_index; + + for_each_compatible_node_from(np, root, NULL, compat) { + ret = of_property_read_u32(np, "cell-index", &cell_index); + if (ret) + continue; + + icid = get_fman_port_icid(cell_index, fman_icid_tbl_ls1046a, + ARRAY_SIZE(fman_icid_tbl_ls1046a)); + if (icid < 0) { + printf("WARNING unknown ICID for fman port %u\n", + cell_index); + continue; + } + + of_set_iommu_prop(np, iommu_handle, icid); } +} + +static void of_fixup_fman_icids(struct device_node *root, phandle iommu_handle) +{ + static const char * const compats[] = { + "fsl,fman-v3-port-oh", + "fsl,fman-v3-port-rx", + "fsl,fman-v3-port-tx", + }; + int i; + + for (i = 0; i < ARRAY_SIZE(compats); i++) + of_fixup_fman_port_icid_by_compat(root, iommu_handle, compats[i]); +} -#define SET_SCFG_ICID(compat, streamid, name, compataddr) \ - SET_ICID_ENTRY(compat, streamid, (((streamid) << 24) | (1 << 23)), \ - offsetof(struct ccsr_scfg, name) + LSCH2_SCFG_ADDR, \ - compataddr) - -#define SET_USB_ICID(usb_num, compat, streamid) \ - SET_SCFG_ICID(compat, streamid, usb##usb_num##_icid,\ - LSCH2_XHCI_USB##usb_num##_ADDR) - -#define SET_SATA_ICID(compat, streamid) \ - SET_SCFG_ICID(compat, streamid, sata_icid,\ - LSCH2_HCI_BASE_ADDR) - -#define SET_SDHC_ICID(streamid) \ - SET_SCFG_ICID("fsl,esdhc", streamid, sdhc_icid,\ - LSCH2_ESDHC_ADDR) - -#define QMAN_CQSIDR_REG 0x20a80 - -#define SET_QDMA_ICID(compat, streamid) \ - SET_ICID_ENTRY(compat, streamid, (1 << 31) | (streamid), \ - LSCH2_QDMA_BASE_ADDR + QMAN_CQSIDR_REG, \ - LSCH2_QDMA_BASE_ADDR), \ - SET_ICID_ENTRY(NULL, streamid, (1 << 31) | (streamid), \ - LSCH2_QDMA_BASE_ADDR + QMAN_CQSIDR_REG + 4, \ - LSCH2_QDMA_BASE_ADDR) - -#define SET_EDMA_ICID(streamid) \ - SET_SCFG_ICID("fsl,vf610-edma", streamid, edma_icid,\ - LSCH2_EDMA_BASE_ADDR) - -#define SET_ETR_ICID(streamid) \ - SET_SCFG_ICID(NULL, streamid, etr_icid, 0) - -#define SET_DEBUG_ICID(streamid) \ - SET_SCFG_ICID(NULL, streamid, debug_icid, 0) - -#define SET_QE_ICID(streamid) \ - SET_SCFG_ICID("fsl,qe", streamid, qe_icid,\ - LSCH2_QE_BASE_ADDR) - -#define SET_QMAN_ICID(streamid) \ - SET_ICID_ENTRY("fsl,qman", streamid, streamid, \ - offsetof(struct ccsr_qman, liodnr) + \ - LSCH2_QMAN_ADDR, \ - LSCH2_QMAN_ADDR) - -#define SET_BMAN_ICID(streamid) \ - SET_ICID_ENTRY("fsl,bman", streamid, streamid, \ - offsetof(struct ccsr_bman, liodnr) + \ - LSCH2_BMAN_ADDR, \ - LSCH2_BMAN_ADDR) - -#define SET_FMAN_ICID_ENTRY(_port_id, streamid) \ - { .port_id = (_port_id), .icid = (streamid) } - -#define SET_SEC_QI_ICID(streamid) \ - SET_ICID_ENTRY("fsl,sec-v4.0", streamid, \ - 0, offsetof(ccsr_sec_t, qilcr_ls) + \ - LSCH2_SEC_ADDR, \ - LSCH2_SEC_ADDR) - -#define SET_SEC_JR_ICID_ENTRY(jr_num, streamid) \ - SET_ICID_ENTRY( \ - (CONFIG_ARMV8_SEC_FIRMWARE_SUPPORT && \ - (FSL_SEC_JR##jr_num##_OFFSET == \ - SEC_JR3_OFFSET + CONFIG_SYS_FSL_SEC_OFFSET) \ - ? NULL \ - : "fsl,sec-v4.0-job-ring"), \ - streamid, \ - (((streamid) << 16) | (streamid)), \ - offsetof(ccsr_sec_t, jrliodnr[jr_num].ls) + \ - LSCH2_SEC_ADDR, \ - FSL_SEC_JR##jr_num##_BASE_ADDR) - -#define SET_SEC_DECO_ICID_ENTRY(deco_num, streamid) \ - SET_ICID_ENTRY(NULL, streamid, (((streamid) << 16) | (streamid)), \ - offsetof(ccsr_sec_t, decoliodnr[deco_num].ls) + \ - LSCH2_SEC_ADDR, 0) - -#define SET_SEC_RTIC_ICID_ENTRY(rtic_num, streamid) \ - SET_ICID_ENTRY(NULL, streamid, (((streamid) << 16) | (streamid)), \ - offsetof(ccsr_sec_t, rticliodnr[rtic_num].ls) + \ - LSCH2_SEC_ADDR, 0) - -static struct icid_id_table icid_tbl_ls1046a[] = { - SET_QMAN_ICID(FSL_DPAA1_STREAM_ID_START), - SET_BMAN_ICID(FSL_DPAA1_STREAM_ID_START + 1), - - SET_SDHC_ICID(FSL_SDHC_STREAM_ID), - - SET_USB_ICID(1, "snps,dwc3", FSL_USB1_STREAM_ID), - SET_USB_ICID(2, "snps,dwc3", FSL_USB2_STREAM_ID), - SET_USB_ICID(3, "snps,dwc3", FSL_USB3_STREAM_ID), - - SET_SATA_ICID("fsl,ls1046a-ahci", FSL_SATA_STREAM_ID), - SET_QDMA_ICID("fsl,ls1046a-qdma", FSL_QDMA_STREAM_ID), - SET_EDMA_ICID(FSL_EDMA_STREAM_ID), - SET_ETR_ICID(FSL_ETR_STREAM_ID), - SET_DEBUG_ICID(FSL_DEBUG_STREAM_ID), +struct qportal_info { + u16 dicid; /* DQRR ICID */ + u16 ficid; /* frame data ICID */ + u16 icid; + u8 sdest; }; -static struct fman_icid_id_table fman_icid_tbl_ls1046a[] = { - /* port id, icid */ - SET_FMAN_ICID_ENTRY(0x02, FSL_DPAA1_STREAM_ID_END), - SET_FMAN_ICID_ENTRY(0x03, FSL_DPAA1_STREAM_ID_END), - SET_FMAN_ICID_ENTRY(0x04, FSL_DPAA1_STREAM_ID_END), - SET_FMAN_ICID_ENTRY(0x05, FSL_DPAA1_STREAM_ID_END), - SET_FMAN_ICID_ENTRY(0x06, FSL_DPAA1_STREAM_ID_END), - SET_FMAN_ICID_ENTRY(0x07, FSL_DPAA1_STREAM_ID_END), - SET_FMAN_ICID_ENTRY(0x08, FSL_DPAA1_STREAM_ID_END), - SET_FMAN_ICID_ENTRY(0x09, FSL_DPAA1_STREAM_ID_END), - SET_FMAN_ICID_ENTRY(0x0a, FSL_DPAA1_STREAM_ID_END), - SET_FMAN_ICID_ENTRY(0x0b, FSL_DPAA1_STREAM_ID_END), - SET_FMAN_ICID_ENTRY(0x0c, FSL_DPAA1_STREAM_ID_END), - SET_FMAN_ICID_ENTRY(0x0d, FSL_DPAA1_STREAM_ID_END), - SET_FMAN_ICID_ENTRY(0x28, FSL_DPAA1_STREAM_ID_END), - SET_FMAN_ICID_ENTRY(0x29, FSL_DPAA1_STREAM_ID_END), - SET_FMAN_ICID_ENTRY(0x2a, FSL_DPAA1_STREAM_ID_END), - SET_FMAN_ICID_ENTRY(0x2b, FSL_DPAA1_STREAM_ID_END), - SET_FMAN_ICID_ENTRY(0x2c, FSL_DPAA1_STREAM_ID_END), - SET_FMAN_ICID_ENTRY(0x2d, FSL_DPAA1_STREAM_ID_END), - SET_FMAN_ICID_ENTRY(0x10, FSL_DPAA1_STREAM_ID_END), - SET_FMAN_ICID_ENTRY(0x11, FSL_DPAA1_STREAM_ID_END), - SET_FMAN_ICID_ENTRY(0x30, FSL_DPAA1_STREAM_ID_END), - SET_FMAN_ICID_ENTRY(0x31, FSL_DPAA1_STREAM_ID_END), +static const struct qportal_info qp_info[] = { + { + .dicid = DPAA1_SID_END, + .ficid = DPAA1_SID_END, + .icid = DPAA1_SID_END, + .sdest = 0, + }, { + .dicid = DPAA1_SID_END, + .ficid = DPAA1_SID_END, + .icid = DPAA1_SID_END, + .sdest = 0, + }, { + .dicid = DPAA1_SID_END, + .ficid = DPAA1_SID_END, + .icid = DPAA1_SID_END, + .sdest = 0, + }, { + .dicid = DPAA1_SID_END, + .ficid = DPAA1_SID_END, + .icid = DPAA1_SID_END, + .sdest = 0, + }, { + .dicid = DPAA1_SID_END, + .ficid = DPAA1_SID_END, + .icid = DPAA1_SID_END, + .sdest = 0, + }, { + .dicid = DPAA1_SID_END, + .ficid = DPAA1_SID_END, + .icid = DPAA1_SID_END, + .sdest = 0, + }, { + .dicid = DPAA1_SID_END, + .ficid = DPAA1_SID_END, + .icid = DPAA1_SID_END, + .sdest = 0, + }, { + .dicid = DPAA1_SID_END, + .ficid = DPAA1_SID_END, + .icid = DPAA1_SID_END, + .sdest = 0, + }, { + .dicid = DPAA1_SID_END, + .ficid = DPAA1_SID_END, + .icid = DPAA1_SID_END, + .sdest = 0, + }, { + .dicid = DPAA1_SID_END, + .ficid = DPAA1_SID_END, + .icid = DPAA1_SID_END, + .sdest = 0, + }, }; -static void set_icid(struct icid_id_table *tbl, int size) +#define BMAN_NUM_PORTALS 10 +#define BMAN_MEM_BASE 0x508000000 +#define BMAN_MEM_SIZE 0x08000000 +#define BMAN_SP_CINH_SIZE 0x10000 +#define BMAN_CENA_SIZE (BMAN_MEM_SIZE >> 1) +#define BMAN_CINH_BASE (BMAN_MEM_BASE + BMAN_CENA_SIZE) +#define BMAN_SWP_ISDR_REG 0x3e80 +#define QMAN_MEM_BASE 0x500000000 +#define QMAN_MEM_PHYS QMAN_MEM_BASE +#define QMAN_MEM_SIZE 0x08000000 +#define QMAN_SP_CINH_SIZE 0x10000 +#define QMAN_CENA_SIZE (QMAN_MEM_SIZE >> 1) +#define QMAN_CINH_BASE (QMAN_MEM_BASE + QMAN_CENA_SIZE) +#define QMAN_SWP_ISDR_REG 0x3680 + +static void inhibit_portals(void __iomem *addr, int max_portals, + int portal_cinh_size) { int i; - for (i = 0; i < size; i++) - out_be32((u32 *)(tbl[i].reg_addr), tbl[i].reg); + for (i = 0; i < max_portals; i++) { + out_be32(addr, -1); + addr += portal_cinh_size; + } } -static void set_fman_icids(struct fman_icid_id_table *tbl, int size) +static void setup_qbman_portals(void) { + void __iomem *bpaddr = (void *)BMAN_CINH_BASE + BMAN_SWP_ISDR_REG; + void __iomem *qpaddr = (void *)QMAN_CINH_BASE + QMAN_SWP_ISDR_REG; + struct ccsr_qman_v3 *qman = IOMEM(LSCH2_QMAN_ADDR); int i; + + /* Set the Qman initiator BAR to match the LAW (for DQRR stashing) */ + out_be32(&qman->qcsp_bare, (u32)(QMAN_MEM_PHYS >> 32)); + out_be32(&qman->qcsp_bar, (u32)QMAN_MEM_PHYS); + + for (i = 0; i < ARRAY_SIZE(qp_info); i++) { + const struct qportal_info *qi = &qp_info[i]; + + out_be32(&qman->qcsp[i].qcsp_lio_cfg, (qi->icid << 16) | qi->dicid); + /* set frame icid */ + out_be32(&qman->qcsp[i].qcsp_io_cfg, (qi->sdest << 16) | qi->ficid); + } + + /* Change default state of BMan ISDR portals to all 1s */ + inhibit_portals(bpaddr, BMAN_NUM_PORTALS, BMAN_SP_CINH_SIZE); + inhibit_portals(qpaddr, ARRAY_SIZE(qp_info), QMAN_SP_CINH_SIZE); +} + +static void of_set_qportal_iommu_prop(struct device_node *np, phandle iommu_handle, + const struct qportal_info *qp_info) +{ + u32 prop[] = { + iommu_handle, + qp_info->icid, + iommu_handle, + qp_info->dicid, + iommu_handle, + qp_info->ficid + }; + + of_property_write_u32_array(np, "iommus", prop, ARRAY_SIZE(prop)); +} + +static void of_fixup_qportals(struct device_node *root, phandle iommu_handle) +{ + struct device_node *np; + unsigned int maj, min; + unsigned int ip_cfg; + struct ccsr_qman_v3 *qman = IOMEM(LSCH2_QMAN_ADDR); + u32 rev_1 = in_be32(&qman->ip_rev_1); + u32 rev_2 = in_be32(&qman->ip_rev_2); + u32 cell_index; + int ret; + + maj = (rev_1 >> 8) & 0xff; + min = rev_1 & 0xff; + ip_cfg = rev_2 & 0xff; + + for_each_compatible_node_from(np, root, NULL, "fsl,qman-portal") { + ret = of_property_read_u32(np, "cell-index", &cell_index); + if (ret) + continue; + + of_set_qportal_iommu_prop(np, iommu_handle, &qp_info[cell_index]); + } +} + +static int of_fixup_ls1046a(struct device_node *root, void *context) +{ + phandle iommu_handle; + + iommu_handle = of_get_iommu_handle(root); + if (!iommu_handle) + return 0; + + of_fixup_icid(root, iommu_handle, icid_tbl_ls1046a, ARRAY_SIZE(icid_tbl_ls1046a)); + of_fixup_fman_icids(root, iommu_handle); + of_fixup_qportals(root, iommu_handle); + + return 0; +} + +void ls1046a_setup_icids(void) +{ struct ccsr_fman *fm = (void *)LSCH2_FM1_ADDR; + int i; - for (i = 0; i < size; i++) { - out_be32(&fm->fm_bmi_common.fmbm_ppid[tbl[i].port_id - 1], - tbl[i].icid); + setup_icid_offsets(icid_tbl_ls1046a, ARRAY_SIZE(icid_tbl_ls1046a), false); + + /* setup fman icids */ + for (i = 0; i < ARRAY_SIZE(fman_icid_tbl_ls1046a); i++) { + const struct fman_icid_id_table *icid = &fman_icid_tbl_ls1046a[i]; + + out_be32(&fm->fm_bmi_common.fmbm_ppid[icid->port_id - 1], + icid->icid); } + + setup_qbman_portals(); + + of_register_fixup(of_fixup_ls1046a, NULL); } -static int set_icids(void) +static const struct icid_id_table icid_tbl_ls1028a[] = { + { + .compat = "snps,dwc3", + .id = 1, + .reg = 1, + .compat_addr = LSCH3_XHCI_USB1_ADDR, + .reg_addr = offsetof(struct lsch3_ccsr_gur, usb1_amqr) + LSCH3_GUTS_ADDR, + }, { + .compat = "snps,dwc3", + .id = 2, + .reg = 2, + .compat_addr = LSCH3_XHCI_USB2_ADDR, + .reg_addr = offsetof(struct lsch3_ccsr_gur, usb2_amqr) + LSCH3_GUTS_ADDR, + }, { + .compat = "fsl,esdhc", + .id = 3, + .reg = 3, + .compat_addr = LSCH3_ESDHC1_BASE_ADDR, + .reg_addr = offsetof(struct lsch3_ccsr_gur, sdmm1_amqr) + LSCH3_GUTS_ADDR, + }, { + .compat = "fsl,esdhc", + .id = 69, + .reg = 69, + .compat_addr = LSCH3_ESDHC2_BASE_ADDR, + .reg_addr = offsetof(struct lsch3_ccsr_gur, sdmm2_amqr) + LSCH3_GUTS_ADDR, + }, { + .compat = "fsl,ls1028a-ahci", + .id = 4, + .reg = 4, + .compat_addr = LSCH3_AHCI1_ADDR, + .reg_addr = offsetof(struct lsch3_ccsr_gur, sata1_amqr) + LSCH3_GUTS_ADDR, + }, { + .compat = "fsl,vf610-edma", + .id = 40, + .reg = 40, + .compat_addr = LSCH3_EDMA_ADDR, + .reg_addr = offsetof(struct lsch3_ccsr_gur, spare3_amqr) + LSCH3_GUTS_ADDR, + }, { + .compat = "fsl,ls1028a-qdma", + .id = 5, + .reg = (1 << 31) | 5, + .compat_addr = LSCH3_QDMA_ADDR, + .reg_addr = LSCH3_QDMA_ADDR + QMAN_CQSIDR_REG, + }, { + .compat = NULL, + .id = 5, + .reg = (1 << 31) | 5, + .compat_addr = LSCH3_QDMA_ADDR, + .reg_addr = LSCH3_QDMA_ADDR + QMAN_CQSIDR_REG + 4, + }, { + .compat = "vivante,gc", + .id = 71, + .reg = 71, + .compat_addr = LSCH3_GPU_ADDR, + .reg_addr = offsetof(struct lsch3_ccsr_gur, misc1_amqr) + LSCH3_GUTS_ADDR, + }, { + .compat = "arm,mali-dp500", + .id = 72, + .reg = 72, + .compat_addr = LSCH3_DISPLAY_ADDR, + .reg_addr = offsetof(struct lsch3_ccsr_gur, spare2_amqr) + LSCH3_GUTS_ADDR, + }, { + .compat = "fsl,sec-v4.0-job-ring", + .id = 65, + .reg = 65, + .compat_addr = LSCH3_SEC_JR0_ADDR, + .reg_addr = offsetof(struct ccsr_sec, jrliodnr[0].ls) + LSCH3_SEC_ADDR, + }, { + .compat = "fsl,sec-v4.0-job-ring", + .id = 66, + .reg = 66, + .compat_addr = LSCH3_SEC_JR1_ADDR, + .reg_addr = offsetof(struct ccsr_sec, jrliodnr[1].ls) + LSCH3_SEC_ADDR, + }, { + .id = 67, + .reg = 67, + .compat_addr = LSCH3_SEC_JR2_ADDR, + .reg_addr = offsetof(struct ccsr_sec, jrliodnr[2].ls) + LSCH3_SEC_ADDR, + }, { + .compat = "fsl,sec-v4.0-job-ring", + .id = 68, + .reg = 68, + .compat_addr = LSCH3_SEC_JR3_ADDR, + .reg_addr = offsetof(struct ccsr_sec, jrliodnr[3].ls) + LSCH3_SEC_ADDR, + }, { + .id = 64, + .reg = 64, + .compat_addr = 0, + .reg_addr = offsetof(struct ccsr_sec, rticliodnr[0].ls) + LSCH3_SEC_ADDR, + }, { + .id = 64, + .reg = 64, + .compat_addr = 0, + .reg_addr = offsetof(struct ccsr_sec, rticliodnr[1].ls) + LSCH3_SEC_ADDR, + }, { + .id = 64, + .reg = 64, + .compat_addr = 0, + .reg_addr = offsetof(struct ccsr_sec, rticliodnr[2].ls) + LSCH3_SEC_ADDR, + }, { + .id = 64, + .reg = 64, + .compat_addr = 0, + .reg_addr = offsetof(struct ccsr_sec, rticliodnr[3].ls) + LSCH3_SEC_ADDR, + }, { + .id = 64, + .reg = 64, + .compat_addr = 0, + .reg_addr = offsetof(struct ccsr_sec, decoliodnr[0].ls) + LSCH3_SEC_ADDR, + }, { + .id = 64, + .reg = 64, + .compat_addr = 0, + .reg_addr = offsetof(struct ccsr_sec, decoliodnr[1].ls) + LSCH3_SEC_ADDR, + } +}; + +static int of_fixup_icid_ls1028a(struct device_node *root, void *context) { - if (!of_machine_is_compatible("fsl,ls1046a")) + phandle iommu_handle; + + iommu_handle = of_get_iommu_handle(root); + if (!iommu_handle) return 0; - /* setup general icid offsets */ - set_icid(icid_tbl_ls1046a, ARRAY_SIZE(icid_tbl_ls1046a)); + of_fixup_icid(root, iommu_handle, icid_tbl_ls1028a, ARRAY_SIZE(icid_tbl_ls1028a)); + + return 0; +} + +/* offset of IERB config register per PCI function */ +static const int ierb_offset[] = { + 0x0800, + 0x1800, + 0x2800, + 0x3800, + 0x4800, + 0x5800, + 0x6800, + -1, + 0x0804, + 0x0808, + 0x1804, + 0x1808, +}; + +#define ECAM_IERB_BASE 0x1f0800000ULL +#define ECAM_IERB_MSICAR (ECAM_IERB_BASE + 0xa400) +#define ECAM_IERB_MSICAR_VALUE 0x30 +#define FSL_ECAM_STREAM_ID_START 41 + +/* + * Use a custom function for LS1028A, for now this is the only SoC with IERB + * and we're currently considering reorganizing IERB for future SoCs. + */ +static void ls1028a_set_ecam_icids(void) +{ + int i; + + out_le32(ECAM_IERB_MSICAR, ECAM_IERB_MSICAR_VALUE); - set_fman_icids(fman_icid_tbl_ls1046a, ARRAY_SIZE(fman_icid_tbl_ls1046a)); + for (i = 0; i < ARRAY_SIZE(ierb_offset); i++) { + if (ierb_offset[i] < 0) + continue; + + out_le32(ECAM_IERB_BASE + ierb_offset[i], + FSL_ECAM_STREAM_ID_START + i); + } +} + +static int of_fixup_ecam_ls1028a(struct device_node *root, void *context) +{ + struct device_node *np; + int i, ret; + const char *props[] = { "msi-map", "iommu-map" }; + uint32_t map[4]; + + np = of_find_compatible_node(root, NULL, "pci-host-ecam-generic"); + if (!np) { + pr_info("No \"pci-host-ecam-generic\" node found, won't fixup\n"); + return 0; + } + + for (i = 0; i < ARRAY_SIZE(props); i++) { + ret = of_property_read_u32_array(np, props[i], map, 4); + if (ret) { + pr_err("Cannot read \"%s\" property: %pe", props[i], ERR_PTR(ret)); + return ret; + } + + map[2] = FSL_ECAM_STREAM_ID_START; + map[3] = ARRAY_SIZE(ierb_offset); + ret = of_property_write_u32_array(np, props[i], map, 4); + if (ret) { + pr_err("Cannot write \"%s\" property: %pe", props[i], ERR_PTR(ret)); + return ret; + } + } return 0; } -postcore_initcall(set_icids);
\ No newline at end of file + +void ls1028a_setup_icids(void) +{ + setup_icid_offsets(icid_tbl_ls1028a, ARRAY_SIZE(icid_tbl_ls1028a), true); + + ls1028a_set_ecam_icids(); + + of_register_fixup(of_fixup_icid_ls1028a, NULL); + of_register_fixup(of_fixup_ecam_ls1028a, NULL); +} diff --git a/arch/arm/mach-layerscape/include/mach/bbu.h b/arch/arm/mach-layerscape/include/mach/bbu.h deleted file mode 100644 index 1ea0cbb11f..0000000000 --- a/arch/arm/mach-layerscape/include/mach/bbu.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef __MACH_LAYERSCAPE_BBU_H -#define __MACH_LAYERSCAPE_BBU_H - -#include <bbu.h> - -static inline int ls1046a_bbu_mmc_register_handler(const char *name, - const char *devicefile, - unsigned long flags) -{ - return bbu_register_std_file_update(name, flags, devicefile, - filetype_layerscape_image); -} - -static inline int ls1046a_bbu_qspi_register_handler(const char *name, - const char *devicefile, - unsigned long flags) -{ - return bbu_register_std_file_update(name, flags, devicefile, - filetype_layerscape_qspi_image); -} - -#endif /* __MACH_LAYERSCAPE_BBU_H */
\ No newline at end of file diff --git a/arch/arm/mach-layerscape/include/mach/debug_ll.h b/arch/arm/mach-layerscape/include/mach/debug_ll.h deleted file mode 100644 index 2658a4a7c9..0000000000 --- a/arch/arm/mach-layerscape/include/mach/debug_ll.h +++ /dev/null @@ -1,34 +0,0 @@ -#ifndef __INCLUDE_ARCH_DEBUG_LL_H__ -#define __INCLUDE_ARCH_DEBUG_LL_H__ - -#include <io.h> -#include <soc/fsl/immap_lsch2.h> - -#define __LS_UART_BASE(num) LSCH2_NS16550_COM##num -#define LS_UART_BASE(num) __LS_UART_BASE(num) - -static inline uint8_t debug_ll_read_reg(int reg) -{ - void __iomem *base = IOMEM(LS_UART_BASE(CONFIG_DEBUG_LAYERSCAPE_UART_PORT)); - - return readb(base + reg); -} - -static inline void debug_ll_write_reg(int reg, uint8_t val) -{ - void __iomem *base = IOMEM(LS_UART_BASE(CONFIG_DEBUG_LAYERSCAPE_UART_PORT)); - - writeb(val, base + reg); -} - -#include <debug_ll/ns16550.h> - -static inline void debug_ll_init(void) -{ - uint16_t divisor; - - divisor = debug_ll_ns16550_calc_divisor(300000000); - debug_ll_ns16550_init(divisor); -} - -#endif /* __INCLUDE_ARCH_DEBUG_LL_H__ */ diff --git a/arch/arm/mach-layerscape/include/mach/errata.h b/arch/arm/mach-layerscape/include/mach/errata.h deleted file mode 100644 index bdefa22172..0000000000 --- a/arch/arm/mach-layerscape/include/mach/errata.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef __MACH_ERRATA_H -#define __MACH_ERRATA_H - -void ls1046a_errata(void); -void ls1046a_errata_post_ddr(void); - -#endif /* __MACH_ERRATA_H */ diff --git a/arch/arm/mach-layerscape/include/mach/layerscape.h b/arch/arm/mach-layerscape/include/mach/layerscape.h deleted file mode 100644 index 1f1da0f66e..0000000000 --- a/arch/arm/mach-layerscape/include/mach/layerscape.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef __MACH_LAYERSCAPE_H -#define __MACH_LAYERSCAPE_H - -#define LS1046A_DDR_SDRAM_BASE 0x80000000 -#define LS1046A_DDR_FREQ 2100000000 - -enum bootsource ls1046_bootsource_get(void); - -#ifdef CONFIG_ARCH_LAYERSCAPE_PPA -int ls1046a_ppa_init(resource_size_t ppa_start, resource_size_t ppa_size); -#else -static inline int ls1046a_ppa_init(resource_size_t ppa_start, - resource_size_t ppa_size) -{ - return -ENOSYS; -} -#endif - -#endif /* __MACH_LAYERSCAPE_H */ diff --git a/arch/arm/mach-layerscape/include/mach/lowlevel.h b/arch/arm/mach-layerscape/include/mach/lowlevel.h deleted file mode 100644 index 0f5f0f3aad..0000000000 --- a/arch/arm/mach-layerscape/include/mach/lowlevel.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef __MACH_LOWLEVEL_H -#define __MACH_LOWLEVEL_H - -void ls1046a_init_lowlevel(void); -void ls1046a_init_l2_latency(void); - -#endif /* __MACH_LOWLEVEL_H */ diff --git a/arch/arm/mach-layerscape/include/mach/xload.h b/arch/arm/mach-layerscape/include/mach/xload.h deleted file mode 100644 index eb2d998865..0000000000 --- a/arch/arm/mach-layerscape/include/mach/xload.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef __MACH_XLOAD_H -#define __MACH_XLOAD_H - -int ls1046a_esdhc_start_image(unsigned long r0, unsigned long r1, unsigned long r2); -int ls1046a_qspi_start_image(unsigned long r0, unsigned long r1, - unsigned long r2); -int ls1046a_xload_start_image(unsigned long r0, unsigned long r1, - unsigned long r2); - -#endif /* __MACH_XLOAD_H */ diff --git a/arch/arm/mach-layerscape/lowlevel-ls1028a.c b/arch/arm/mach-layerscape/lowlevel-ls1028a.c new file mode 100644 index 0000000000..fd013b2b52 --- /dev/null +++ b/arch/arm/mach-layerscape/lowlevel-ls1028a.c @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: GPL-2.0+ +#include <common.h> +#include <io.h> +#include <asm/syscounter.h> +#include <asm/system.h> +#include <mach/layerscape/errata.h> +#include <mach/layerscape/lowlevel.h> +#include <soc/fsl/immap_lsch3.h> +#include <soc/fsl/scfg.h> + +static void ls1028a_timer_init(void) +{ + u32 __iomem *cntcr = IOMEM(LSCH3_TIMER_ADDR); + u32 __iomem *cltbenr = IOMEM(LSCH3_PMU_CLTBENR); + + u32 __iomem *pctbenr = IOMEM(LSCH3_PCTBENR_OFFSET); + + /* Enable timebase for all clusters. + * It is safe to do so even some clusters are not enabled. + */ + out_le32(cltbenr, 0xf); + + /* + * In certain Layerscape SoCs, the clock for each core's + * has an enable bit in the PMU Physical Core Time Base Enable + * Register (PCTBENR), which allows the watchdog to operate. + */ + setbits_le32(pctbenr, 0xff); + + /* Enable clock for timer + * This is a global setting. + */ + out_le32(cntcr, 0x1); +} + +void ls1028a_init_lowlevel(void) +{ + scfg_init(SCFG_ENDIANESS_LITTLE); + set_cntfrq(25000000); + ls1028a_timer_init(); + ls1028a_errata(); +} diff --git a/arch/arm/mach-layerscape/lowlevel-ls102xa.c b/arch/arm/mach-layerscape/lowlevel-ls102xa.c new file mode 100644 index 0000000000..440d50282a --- /dev/null +++ b/arch/arm/mach-layerscape/lowlevel-ls102xa.c @@ -0,0 +1,400 @@ +// SPDX-License-Identifier: GPL-2.0+ + +/* + * Derived from Freescale LSDK-19.09-update-311219 + */ +#include <common.h> +#include <io.h> +#include <clock.h> +#include <asm/barebox-arm-head.h> +#include <asm/syscounter.h> +#include <asm/system.h> +#include <mach/layerscape/errata.h> +#include <mach/layerscape/lowlevel.h> +#include <mach/layerscape/fsl_epu.h> +#include <soc/fsl/immap_lsch2.h> +#include <soc/fsl/fsl_immap.h> +#include <soc/fsl/scfg.h> + +void udelay(unsigned long usecs) +{ + arm_architected_timer_udelay(usecs); +} + +void mdelay(unsigned long msecs) +{ + udelay(1000 * msecs); +} + +enum csu_cslx_access { + CSU_NS_SUP_R = 0x08, + CSU_NS_SUP_W = 0x80, + CSU_NS_SUP_RW = 0x88, + CSU_NS_USER_R = 0x04, + CSU_NS_USER_W = 0x40, + CSU_NS_USER_RW = 0x44, + CSU_S_SUP_R = 0x02, + CSU_S_SUP_W = 0x20, + CSU_S_SUP_RW = 0x22, + CSU_S_USER_R = 0x01, + CSU_S_USER_W = 0x10, + CSU_S_USER_RW = 0x11, + CSU_ALL_RW = 0xff, +}; + +struct csu_ns_dev { + unsigned long ind; + uint32_t val; +}; + +enum csu_cslx_ind { + CSU_CSLX_PCIE2_IO = 0, + CSU_CSLX_PCIE1_IO, + CSU_CSLX_MG2TPR_IP, + CSU_CSLX_IFC_MEM, + CSU_CSLX_OCRAM, + CSU_CSLX_GIC, + CSU_CSLX_PCIE1, + CSU_CSLX_OCRAM2, + CSU_CSLX_QSPI_MEM, + CSU_CSLX_PCIE2, + CSU_CSLX_SATA, + CSU_CSLX_USB3, + CSU_CSLX_SERDES = 32, + CSU_CSLX_QDMA, + CSU_CSLX_LPUART2, + CSU_CSLX_LPUART1, + CSU_CSLX_LPUART4, + CSU_CSLX_LPUART3, + CSU_CSLX_LPUART6, + CSU_CSLX_LPUART5, + CSU_CSLX_DSPI2 = 40, + CSU_CSLX_DSPI1, + CSU_CSLX_QSPI, + CSU_CSLX_ESDHC, + CSU_CSLX_2D_ACE, + CSU_CSLX_IFC, + CSU_CSLX_I2C1, + CSU_CSLX_USB2, + CSU_CSLX_I2C3, + CSU_CSLX_I2C2, + CSU_CSLX_DUART2 = 50, + CSU_CSLX_DUART1, + CSU_CSLX_WDT2, + CSU_CSLX_WDT1, + CSU_CSLX_EDMA, + CSU_CSLX_SYS_CNT, + CSU_CSLX_DMA_MUX2, + CSU_CSLX_DMA_MUX1, + CSU_CSLX_DDR, + CSU_CSLX_QUICC, + CSU_CSLX_DCFG_CCU_RCPM = 60, + CSU_CSLX_SECURE_BOOTROM, + CSU_CSLX_SFP, + CSU_CSLX_TMU, + CSU_CSLX_SECURE_MONITOR, + CSU_CSLX_RESERVED0, + CSU_CSLX_ETSEC1, + CSU_CSLX_SEC5_5, + CSU_CSLX_ETSEC3, + CSU_CSLX_ETSEC2, + CSU_CSLX_GPIO2 = 70, + CSU_CSLX_GPIO1, + CSU_CSLX_GPIO4, + CSU_CSLX_GPIO3, + CSU_CSLX_PLATFORM_CONT, + CSU_CSLX_CSU, + CSU_CSLX_ASRC, + CSU_CSLX_SPDIF, + CSU_CSLX_FLEXCAN2, + CSU_CSLX_FLEXCAN1, + CSU_CSLX_FLEXCAN4 = 80, + CSU_CSLX_FLEXCAN3, + CSU_CSLX_SAI2, + CSU_CSLX_SAI1, + CSU_CSLX_SAI4, + CSU_CSLX_SAI3, + CSU_CSLX_FTM2, + CSU_CSLX_FTM1, + CSU_CSLX_FTM4, + CSU_CSLX_FTM3, + CSU_CSLX_FTM6 = 90, + CSU_CSLX_FTM5, + CSU_CSLX_FTM8, + CSU_CSLX_FTM7, + CSU_CSLX_EPU, + CSU_CSLX_COP_DCSR, + CSU_CSLX_DDI, + CSU_CSLX_GDI, + CSU_CSLX_RESERVED1, + CSU_CSLX_USB3_PHY = 116, + CSU_CSLX_RESERVED2, + CSU_CSLX_MAX, +}; + +static struct csu_ns_dev ns_dev[] = { + { CSU_CSLX_PCIE2_IO, CSU_ALL_RW }, + { CSU_CSLX_PCIE1_IO, CSU_ALL_RW }, + { CSU_CSLX_MG2TPR_IP, CSU_ALL_RW }, + { CSU_CSLX_IFC_MEM, CSU_ALL_RW }, + { CSU_CSLX_OCRAM, CSU_ALL_RW }, + { CSU_CSLX_GIC, CSU_ALL_RW }, + { CSU_CSLX_PCIE1, CSU_ALL_RW }, + { CSU_CSLX_OCRAM2, CSU_ALL_RW }, + { CSU_CSLX_QSPI_MEM, CSU_ALL_RW }, + { CSU_CSLX_PCIE2, CSU_ALL_RW }, + { CSU_CSLX_SATA, CSU_ALL_RW }, + { CSU_CSLX_USB3, CSU_ALL_RW }, + { CSU_CSLX_SERDES, CSU_ALL_RW }, + { CSU_CSLX_QDMA, CSU_ALL_RW }, + { CSU_CSLX_LPUART2, CSU_ALL_RW }, + { CSU_CSLX_LPUART1, CSU_ALL_RW }, + { CSU_CSLX_LPUART4, CSU_ALL_RW }, + { CSU_CSLX_LPUART3, CSU_ALL_RW }, + { CSU_CSLX_LPUART6, CSU_ALL_RW }, + { CSU_CSLX_LPUART5, CSU_ALL_RW }, + { CSU_CSLX_DSPI2, CSU_ALL_RW }, + { CSU_CSLX_DSPI1, CSU_ALL_RW }, + { CSU_CSLX_QSPI, CSU_ALL_RW }, + { CSU_CSLX_ESDHC, CSU_ALL_RW }, + { CSU_CSLX_2D_ACE, CSU_ALL_RW }, + { CSU_CSLX_IFC, CSU_ALL_RW }, + { CSU_CSLX_I2C1, CSU_ALL_RW }, + { CSU_CSLX_USB2, CSU_ALL_RW }, + { CSU_CSLX_I2C3, CSU_ALL_RW }, + { CSU_CSLX_I2C2, CSU_ALL_RW }, + { CSU_CSLX_DUART2, CSU_ALL_RW }, + { CSU_CSLX_DUART1, CSU_ALL_RW }, + { CSU_CSLX_WDT2, CSU_ALL_RW }, + { CSU_CSLX_WDT1, CSU_ALL_RW }, + { CSU_CSLX_EDMA, CSU_ALL_RW }, + { CSU_CSLX_SYS_CNT, CSU_ALL_RW }, + { CSU_CSLX_DMA_MUX2, CSU_ALL_RW }, + { CSU_CSLX_DMA_MUX1, CSU_ALL_RW }, + { CSU_CSLX_DDR, CSU_ALL_RW }, + { CSU_CSLX_QUICC, CSU_ALL_RW }, + { CSU_CSLX_DCFG_CCU_RCPM, CSU_ALL_RW }, + { CSU_CSLX_SECURE_BOOTROM, CSU_ALL_RW }, + { CSU_CSLX_SFP, CSU_ALL_RW }, + { CSU_CSLX_TMU, CSU_ALL_RW }, + { CSU_CSLX_SECURE_MONITOR, CSU_ALL_RW }, + { CSU_CSLX_RESERVED0, CSU_ALL_RW }, + { CSU_CSLX_ETSEC1, CSU_ALL_RW }, + { CSU_CSLX_SEC5_5, CSU_ALL_RW }, + { CSU_CSLX_ETSEC3, CSU_ALL_RW }, + { CSU_CSLX_ETSEC2, CSU_ALL_RW }, + { CSU_CSLX_GPIO2, CSU_ALL_RW }, + { CSU_CSLX_GPIO1, CSU_ALL_RW }, + { CSU_CSLX_GPIO4, CSU_ALL_RW }, + { CSU_CSLX_GPIO3, CSU_ALL_RW }, + { CSU_CSLX_PLATFORM_CONT, CSU_ALL_RW }, + { CSU_CSLX_CSU, CSU_ALL_RW }, + { CSU_CSLX_ASRC, CSU_ALL_RW }, + { CSU_CSLX_SPDIF, CSU_ALL_RW }, + { CSU_CSLX_FLEXCAN2, CSU_ALL_RW }, + { CSU_CSLX_FLEXCAN1, CSU_ALL_RW }, + { CSU_CSLX_FLEXCAN4, CSU_ALL_RW }, + { CSU_CSLX_FLEXCAN3, CSU_ALL_RW }, + { CSU_CSLX_SAI2, CSU_ALL_RW }, + { CSU_CSLX_SAI1, CSU_ALL_RW }, + { CSU_CSLX_SAI4, CSU_ALL_RW }, + { CSU_CSLX_SAI3, CSU_ALL_RW }, + { CSU_CSLX_FTM2, CSU_ALL_RW }, + { CSU_CSLX_FTM1, CSU_ALL_RW }, + { CSU_CSLX_FTM4, CSU_ALL_RW }, + { CSU_CSLX_FTM3, CSU_ALL_RW }, + { CSU_CSLX_FTM6, CSU_ALL_RW }, + { CSU_CSLX_FTM5, CSU_ALL_RW }, + { CSU_CSLX_FTM8, CSU_ALL_RW }, + { CSU_CSLX_FTM7, CSU_ALL_RW }, + { CSU_CSLX_COP_DCSR, CSU_ALL_RW }, + { CSU_CSLX_EPU, CSU_ALL_RW }, + { CSU_CSLX_GDI, CSU_ALL_RW }, + { CSU_CSLX_DDI, CSU_ALL_RW }, + { CSU_CSLX_RESERVED1, CSU_ALL_RW }, + { CSU_CSLX_USB3_PHY, CSU_ALL_RW }, + { CSU_CSLX_RESERVED2, CSU_ALL_RW }, +}; + +/* Found in U-boot but not in LS1021ARM.pdf 02/2020 */ +#define DCSR_RCPM2_ADDR 0x20223000 +#define DCSR_RCPM2_CPMFSMCR0 0x400 +#define DCSR_RCPM2_CPMFSMSR0 0x404 +#define DCSR_RCPM2_CPMFSMCR1 0x414 +#define DCSR_RCPM2_CPMFSMSR1 0x418 +#define CPMFSMSR_FSM_STATE_MASK 0x7f + +#define DCSR_EPU_ADDR 0x20000000 + +static void set_devices_ns_access(unsigned long index, u16 val) +{ + u32 *base = IOMEM(LSCH2_CSU_ADDR); + u32 *reg; + uint32_t tmp; + + reg = base + index / 2; + tmp = in_be32(reg); + if (index % 2 == 0) { + tmp &= 0x0000ffff; + tmp |= val << 16; + } else { + tmp &= 0xffff0000; + tmp |= val; + } + + out_be32(reg, tmp); +} + +static void init_csu(void) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(ns_dev); i++) + set_devices_ns_access(ns_dev[i].ind, ns_dev[i].val); +} + +/** + * fsl_epu_clean - Clear EPU registers + */ +static void fsl_epu_clean(void *epu_base) +{ + u32 offset; + + /* follow the exact sequence to clear the registers */ + /* Clear EPACRn */ + for (offset = EPACR0; offset <= EPACR15; offset += EPACR_STRIDE) + out_be32(epu_base + offset, 0); + + /* Clear EPEVTCRn */ + for (offset = EPEVTCR0; offset <= EPEVTCR9; offset += EPEVTCR_STRIDE) + out_be32(epu_base + offset, 0); + + /* Clear EPGCR */ + out_be32(epu_base + EPGCR, 0); + + /* Clear EPSMCRn */ + for (offset = EPSMCR0; offset <= EPSMCR15; offset += EPSMCR_STRIDE) + out_be32(epu_base + offset, 0); + + /* Clear EPCCRn */ + for (offset = EPCCR0; offset <= EPCCR31; offset += EPCCR_STRIDE) + out_be32(epu_base + offset, 0); + + /* Clear EPCMPRn */ + for (offset = EPCMPR0; offset <= EPCMPR31; offset += EPCMPR_STRIDE) + out_be32(epu_base + offset, 0); + + /* Clear EPCTRn */ + for (offset = EPCTR0; offset <= EPCTR31; offset += EPCTR_STRIDE) + out_be32(epu_base + offset, 0); + + /* Clear EPIMCRn */ + for (offset = EPIMCR0; offset <= EPIMCR31; offset += EPIMCR_STRIDE) + out_be32(epu_base + offset, 0); + + /* Clear EPXTRIGCRn */ + out_be32(epu_base + EPXTRIGCR, 0); + + /* Clear EPECRn */ + for (offset = EPECR0; offset <= EPECR15; offset += EPECR_STRIDE) + out_be32(epu_base + offset, 0); +} + +#define TIMER_COMP_VAL 0xffffffffffffffffull +#define ARCH_TIMER_CTRL_ENABLE (1 << 0) +#define SYS_COUNTER_CTRL_ENABLE (1 << 24) +#define SCFG_QSPI_CLKSEL 0x50100000 + +/* ls102xa_init_lowlevel + * Based on ls1046 and U-boot ls102xa arch_cpu_init + */ +void ls102xa_init_lowlevel(void) +{ + struct ccsr_cci400 __iomem *cci = IOMEM(LSCH2_CCI400_ADDR); + struct ls102xa_ccsr_scfg *scfg = IOMEM(LSCH2_SCFG_ADDR); + struct ls102xa_ccsr_gur __iomem *gur = IOMEM(LSCH2_GUTS_ADDR); + void *rcpm2_base = IOMEM(DCSR_RCPM2_ADDR); + void *epu_base = IOMEM(DCSR_EPU_ADDR); + uint32_t state, major, ctrl, freq; + uint64_t val; + + cortex_a7_lowlevel_init(); + arm_cpu_lowlevel_init(); + + scfg_init(SCFG_ENDIANESS_BIG); + init_csu(); + + writel(SYS_COUNTER_CTRL_ENABLE, LSCH2_SYS_COUNTER_ADDR); + freq = 12500000; + asm("mcr p15, 0, %0, c14, c0, 0" : : "r" (freq)); + + /* Set PL1 Physical Timer Ctrl */ + ctrl = ARCH_TIMER_CTRL_ENABLE; + asm("mcr p15, 0, %0, c14, c2, 1" : : "r" (ctrl)); + + /* Set PL1 Physical Comp Value */ + val = TIMER_COMP_VAL; + asm("mcrr p15, 2, %Q0, %R0, c14" : : "r" (val)); + + + state = in_be32(rcpm2_base + DCSR_RCPM2_CPMFSMSR0) & + CPMFSMSR_FSM_STATE_MASK; + if (state != 0) { + out_be32(rcpm2_base + DCSR_RCPM2_CPMFSMCR0, 0x80); + out_be32(rcpm2_base + DCSR_RCPM2_CPMFSMCR0, 0x0); + } + state = in_be32(rcpm2_base + DCSR_RCPM2_CPMFSMSR1) & + CPMFSMSR_FSM_STATE_MASK; + if (state != 0) { + out_be32(rcpm2_base + DCSR_RCPM2_CPMFSMCR1, 0x80); + out_be32(rcpm2_base + DCSR_RCPM2_CPMFSMCR1, 0x0); + } + + fsl_epu_clean(epu_base); + + /* Enable all the snoop signal for various masters */ + out_be32(&scfg->snpcnfgcr, SCFG_SNPCNFGCR_SEC_RD_WR | + SCFG_SNPCNFGCR_DBG_RD_WR | + SCFG_SNPCNFGCR_EDMA_SNP); + + if (IS_ENABLED(CONFIG_DRIVER_SPI_FSL_QUADSPI)) + out_be32(&scfg->qspi_cfg, SCFG_QSPI_CLKSEL); + + /* Configure Little endian for SAI, ASRC and SPDIF */ + out_be32(&scfg->endiancr, SCFG_ENDIANCR_LE); + + /* + * Enable snoop requests and DVM message requests for + * All the slave interfaces. + */ + out_le32(&cci->slave[0].snoop_ctrl, + CCI400_DVM_MESSAGE_REQ_EN | CCI400_SNOOP_REQ_EN); + out_le32(&cci->slave[1].snoop_ctrl, + CCI400_DVM_MESSAGE_REQ_EN | CCI400_SNOOP_REQ_EN); + out_le32(&cci->slave[2].snoop_ctrl, + CCI400_DVM_MESSAGE_REQ_EN | CCI400_SNOOP_REQ_EN); + out_le32(&cci->slave[4].snoop_ctrl, + CCI400_DVM_MESSAGE_REQ_EN | CCI400_SNOOP_REQ_EN); + + major = in_be32(&gur->svr); + if (SVR_MAJ(major) == SOC_MAJOR_VER_1_0) { + /* + * Set CCI-400 Slave interface S1, S2 Shareable Override + * Register All transactions are treated as non-shareable + */ + out_le32(&cci->slave[1].sha_ord, CCI400_SHAORD_NON_SHAREABLE); + out_le32(&cci->slave[2].sha_ord, CCI400_SHAORD_NON_SHAREABLE); + } + + /* + * Memory controller require a register write before being enabled. + * Affects: DDR + * Register: EDDRTQCFG + * Description: Memory controller performance is not optimal with + * default internal target queue register values. + * Workaround: Write a value of 63b2_0042h to address: 157_020Ch. + */ + out_be32(&scfg->eddrtqcfg, 0x63b20042); + + ls1021a_errata(); +} diff --git a/arch/arm/mach-layerscape/lowlevel-ls1046a.c b/arch/arm/mach-layerscape/lowlevel-ls1046a.c index 32f825ec25..1307c05eaf 100644 --- a/arch/arm/mach-layerscape/lowlevel-ls1046a.c +++ b/arch/arm/mach-layerscape/lowlevel-ls1046a.c @@ -3,10 +3,11 @@ #include <io.h> #include <asm/syscounter.h> #include <asm/system.h> -#include <mach/errata.h> -#include <mach/lowlevel.h> +#include <mach/layerscape/errata.h> +#include <mach/layerscape/lowlevel.h> #include <soc/fsl/immap_lsch2.h> #include <soc/fsl/fsl_immap.h> +#include <soc/fsl/scfg.h> enum csu_cslx_access { CSU_NS_SUP_R = 0x08, @@ -222,16 +223,19 @@ void ls1046a_init_lowlevel(void) struct ccsr_cci400 __iomem *cci = IOMEM(LSCH2_CCI400_ADDR); struct ccsr_scfg *scfg = IOMEM(LSCH2_SCFG_ADDR); + scfg_init(SCFG_ENDIANESS_BIG); init_csu(); ls1046a_init_l2_latency(); set_cntfrq(25000000); syscnt_enable(IOMEM(LSCH2_SYS_COUNTER_ADDR)); - /* Make SEC reads and writes snoopable */ + /* Make DMA master reads and writes snoopable */ setbits_be32(&scfg->snpcnfgcr, SCFG_SNPCNFGCR_SECRDSNP | - SCFG_SNPCNFGCR_SECWRSNP | - SCFG_SNPCNFGCR_SATARDSNP | - SCFG_SNPCNFGCR_SATAWRSNP); + SCFG_SNPCNFGCR_SECWRSNP | SCFG_SNPCNFGCR_USB1RDSNP | + SCFG_SNPCNFGCR_USB1WRSNP | SCFG_SNPCNFGCR_USB2RDSNP | + SCFG_SNPCNFGCR_USB2WRSNP | SCFG_SNPCNFGCR_USB3RDSNP | + SCFG_SNPCNFGCR_USB3WRSNP | SCFG_SNPCNFGCR_SATARDSNP | + SCFG_SNPCNFGCR_SATAWRSNP | SCFG_SNPCNFGCR_EDMASNP); /* * Enable snoop requests and DVM message requests for diff --git a/arch/arm/mach-layerscape/lowlevel.S b/arch/arm/mach-layerscape/lowlevel.S index adb3e54367..e8e6410c52 100644 --- a/arch/arm/mach-layerscape/lowlevel.S +++ b/arch/arm/mach-layerscape/lowlevel.S @@ -1,3 +1,5 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + #include <linux/linkage.h> .section .text.ls1046a_init_l2_latency diff --git a/arch/arm/mach-layerscape/ls102xa_stream_id.c b/arch/arm/mach-layerscape/ls102xa_stream_id.c new file mode 100644 index 0000000000..fd9be35c1d --- /dev/null +++ b/arch/arm/mach-layerscape/ls102xa_stream_id.c @@ -0,0 +1,50 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2014 Freescale Semiconductor + */ + +#include <common.h> +#include <asm/io.h> +#include <soc/fsl/immap_lsch2.h> +#include <mach/layerscape/layerscape.h> + +struct smmu_stream_id { + uint16_t offset; + uint16_t stream_id; + char dev_name[32]; +}; + +static struct smmu_stream_id dev_stream_id[] = { + { 0x100, 0x01, "ETSEC MAC1" }, + { 0x104, 0x02, "ETSEC MAC2" }, + { 0x108, 0x03, "ETSEC MAC3" }, + { 0x10c, 0x04, "PEX1" }, + { 0x110, 0x05, "PEX2" }, + { 0x114, 0x06, "qDMA" }, + { 0x118, 0x07, "SATA" }, + { 0x11c, 0x08, "USB3" }, + { 0x120, 0x09, "QE" }, + { 0x124, 0x0a, "eSDHC" }, + { 0x128, 0x0b, "eMA" }, + { 0x14c, 0x0c, "2D-ACE" }, + { 0x150, 0x0d, "USB2" }, + { 0x18c, 0x0e, "DEBUG" }, +}; + +static void +ls102xa_config_smmu_stream_id(struct smmu_stream_id *id, uint32_t num) +{ + void *scfg = (void *)LSCH2_SCFG_ADDR; + int i; + u32 icid; + + for (i = 0; i < num; i++) { + icid = (id[i].stream_id & 0xff) << 24; + out_be32((u32 *)(scfg + id[i].offset), icid); + } +} + +void ls102xa_smmu_stream_id_init(void) +{ + ls102xa_config_smmu_stream_id(dev_stream_id, ARRAY_SIZE(dev_stream_id)); +} diff --git a/arch/arm/mach-layerscape/pblimage.c b/arch/arm/mach-layerscape/pblimage.c index deaf7143b9..5a525f0933 100644 --- a/arch/arm/mach-layerscape/pblimage.c +++ b/arch/arm/mach-layerscape/pblimage.c @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-only + #define pr_fmt(fmt) "pblimage: " fmt #include <bootm.h> @@ -5,6 +7,7 @@ #include <init.h> #include <memory.h> #include <linux/sizes.h> +#include <mach/layerscape/layerscape.h> #define BAREBOX_STAGE2_OFFSET SZ_128K @@ -48,11 +51,8 @@ static struct image_handler image_handler_layerscape_qspi_pbl_image = { .filetype = filetype_layerscape_qspi_image, }; -static int layerscape_register_pbl_image_handler(void) +void layerscape_register_pbl_image_handler(void) { register_image_handler(&image_handler_layerscape_pbl_image); register_image_handler(&image_handler_layerscape_qspi_pbl_image); - - return 0; } -late_initcall(layerscape_register_pbl_image_handler); diff --git a/arch/arm/mach-layerscape/ppa-entry.S b/arch/arm/mach-layerscape/ppa-entry.S index 18cfa6c37e..f5f30b6719 100644 --- a/arch/arm/mach-layerscape/ppa-entry.S +++ b/arch/arm/mach-layerscape/ppa-entry.S @@ -1,3 +1,5 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + #include <linux/linkage.h> .section .text.ppa_entry diff --git a/arch/arm/mach-layerscape/ppa.c b/arch/arm/mach-layerscape/ppa.c index 6070451020..21efaae3ab 100644 --- a/arch/arm/mach-layerscape/ppa.c +++ b/arch/arm/mach-layerscape/ppa.c @@ -4,6 +4,7 @@ #include <common.h> #include <init.h> +#include <mmu.h> #include <firmware.h> #include <memory.h> #include <linux/sizes.h> @@ -13,20 +14,40 @@ #include <asm/system.h> #include <image-fit.h> #include <asm/psci.h> -#include <mach/layerscape.h> +#include <mach/layerscape/layerscape.h> +#include <asm/cache.h> int ppa_entry(const void *, u32 *, u32 *); -void dma_flush_range(void *ptr, size_t size); + +#define SEC_JR3_OFFSET 0x40000 static int of_psci_do_fixup(struct device_node *root, void *unused) { unsigned long psci_version; + struct device_node *np; struct arm_smccc_res res = {}; arm_smccc_smc(ARM_PSCI_0_2_FN_PSCI_VERSION, 0, 0, 0, 0, 0, 0, 0, &res); psci_version = res.a0; - return of_psci_fixup(root, psci_version); + for_each_compatible_node_from(np, root, NULL, "fsl,sec-v4.0-job-ring") { + const void *reg; + int na = of_n_addr_cells(np); + u64 offset; + + reg = of_get_property(np, "reg", NULL); + if (!reg) + continue; + + offset = of_read_number(reg, na); + if (offset != SEC_JR3_OFFSET) + continue; + + of_delete_node(np); + break; + } + + return of_psci_fixup(root, psci_version, "smc"); } static int ppa_init(void *ppa, size_t ppa_size, void *sec_firmware_addr) @@ -34,32 +55,25 @@ static int ppa_init(void *ppa, size_t ppa_size, void *sec_firmware_addr) int ret; u32 *boot_loc_ptr_l, *boot_loc_ptr_h; struct ccsr_scfg __iomem *scfg = (void *)(LSCH2_SCFG_ADDR); - int el = current_el(); struct fit_handle *fit; void *conf; const void *buf; unsigned long firmware_size; - if (el < 3) { - printf("EL%d, skip ppa init\n", el); - return 0; - } - boot_loc_ptr_l = &scfg->scratchrw[1]; boot_loc_ptr_h = &scfg->scratchrw[0]; fit = fit_open_buf(ppa, ppa_size, false, BOOTM_VERIFY_AVAILABLE); if (IS_ERR(fit)) { - pr_err("Cannot open ppa FIT image: %s\n", strerrorp(fit)); + pr_err("Cannot open ppa FIT image: %pe\n", fit); return PTR_ERR(fit); } conf = fit_open_configuration(fit, NULL); if (IS_ERR(conf)) { - pr_err("Cannot open default config in ppa FIT image: %s\n", - strerrorp(conf)); - fit_close(fit); - return PTR_ERR(fit); + pr_err("Cannot open default config in ppa FIT image: %pe\n", conf); + ret = PTR_ERR(conf); + goto err; } @@ -67,13 +81,12 @@ static int ppa_init(void *ppa, size_t ppa_size, void *sec_firmware_addr) if (ret) { pr_err("Cannot open firmware image in ppa FIT image: %s\n", strerror(-ret)); - ret = PTR_ERR(fit); goto err; } /* Copy the secure firmware to secure memory */ memcpy(sec_firmware_addr, buf, firmware_size); - dma_flush_range(sec_firmware_addr, ppa_size); + sync_caches_for_execution(); ret = ppa_entry(sec_firmware_addr, boot_loc_ptr_l, boot_loc_ptr_h); if (ret) { @@ -88,7 +101,7 @@ static int ppa_init(void *ppa, size_t ppa_size, void *sec_firmware_addr) err: fit_close(fit); - return 0; + return ret; } int ls1046a_ppa_init(resource_size_t ppa_start, resource_size_t ppa_size) @@ -97,9 +110,10 @@ int ls1046a_ppa_init(resource_size_t ppa_start, resource_size_t ppa_size) struct resource *res; void *ppa_fw; size_t ppa_fw_size; + int el = current_el(); int ret; - res = request_sdram_region("ppa", ppa_start, ppa_size); + res = reserve_sdram_region("ppa", ppa_start, ppa_size); if (!res) { pr_err("Cannot request SDRAM region %pa - %pa\n", &ppa_start, &ppa_end); @@ -108,11 +122,22 @@ int ls1046a_ppa_init(resource_size_t ppa_start, resource_size_t ppa_size) get_builtin_firmware(ppa_ls1046a_bin, &ppa_fw, &ppa_fw_size); - ret = ppa_init(ppa_fw, ppa_fw_size, (void *)ppa_start); - if (ret) - return ret; + if (el == 3) { + unsigned long cr; + + asm volatile("mrs %0, sctlr_el3" : "=r" (cr) : : "cc"); + remap_range((void *)ppa_start, ppa_size, MAP_CACHED); + + ret = ppa_init(ppa_fw, ppa_fw_size, (void *)ppa_start); + + asm volatile("msr sctlr_el2, %0" : : "r" (cr) : "cc"); + remap_range((void *)ppa_start, ppa_size, MAP_UNCACHED); + + if (ret) + return ret; + } - of_add_reserve_entry(ppa_start, ppa_end); + of_register_fixup(of_fixup_reserved_memory, res); return 0; } diff --git a/arch/arm/mach-layerscape/restart.c b/arch/arm/mach-layerscape/restart.c new file mode 100644 index 0000000000..138a82bdb5 --- /dev/null +++ b/arch/arm/mach-layerscape/restart.c @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: GPL-2.0 +#include <common.h> +#include <init.h> +#include <restart.h> +#include <asm/io.h> +#include <soc/fsl/immap_lsch2.h> +#include <soc/fsl/fsl_immap.h> +#include <mach/layerscape/layerscape.h> + +static void ls102xa_restart(struct restart_handler *rst) +{ + void __iomem *rcr = IOMEM(LSCH2_RST_ADDR); + + /* Set RESET_REQ bit */ + setbits_be32(rcr, 0x2); + + mdelay(100); + + hang(); +} + +void ls1021a_restart_register_feature(void) +{ + restart_handler_register_fn("soc-reset", ls102xa_restart); +} diff --git a/arch/arm/mach-layerscape/soc.c b/arch/arm/mach-layerscape/soc.c new file mode 100644 index 0000000000..1742ff58ce --- /dev/null +++ b/arch/arm/mach-layerscape/soc.c @@ -0,0 +1,189 @@ +// SPDX-License-Identifier: GPL-2.0-only +#include <soc/fsl/scfg.h> +#include <io.h> +#include <init.h> +#include <memory.h> +#include <linux/bug.h> +#include <linux/bitfield.h> +#include <linux/printk.h> +#include <mach/layerscape/layerscape.h> +#include <of.h> +#include <of_address.h> + +int __layerscape_soc_type; + +static enum scfg_endianess scfg_endianess = SCFG_ENDIANESS_INVALID; + +static void scfg_check_endianess(void) +{ + BUG_ON(scfg_endianess == SCFG_ENDIANESS_INVALID); +} + +void scfg_clrsetbits32(void __iomem *addr, u32 clear, u32 set) +{ + scfg_check_endianess(); + + if (scfg_endianess == SCFG_ENDIANESS_LITTLE) + clrsetbits_le32(addr, clear, set); + else + clrsetbits_be32(addr, clear, set); +} + +void scfg_clrbits32(void __iomem *addr, u32 clear) +{ + scfg_check_endianess(); + + if (scfg_endianess == SCFG_ENDIANESS_LITTLE) + clrbits_le32(addr, clear); + else + clrbits_be32(addr, clear); +} + +void scfg_setbits32(void __iomem *addr, u32 set) +{ + scfg_check_endianess(); + + if (scfg_endianess == SCFG_ENDIANESS_LITTLE) + setbits_le32(addr, set); + else + setbits_be32(addr, set); +} + +void scfg_out16(void __iomem *addr, u16 val) +{ + scfg_check_endianess(); + + if (scfg_endianess == SCFG_ENDIANESS_LITTLE) + out_le16(addr, val); + else + out_be16(addr, val); +} + +void scfg_init(enum scfg_endianess endianess) +{ + scfg_endianess = endianess; +} + +static int layerscape_soc_from_dt(void) +{ + if (of_machine_is_compatible("fsl,ls1021a")) + return LAYERSCAPE_SOC_LS1021A; + if (of_machine_is_compatible("fsl,ls1028a")) + return LAYERSCAPE_SOC_LS1028A; + if (of_machine_is_compatible("fsl,ls1046a")) + return LAYERSCAPE_SOC_LS1046A; + + return 0; +} + +static int ls1021a_init(void) +{ + if (!cpu_is_ls1021a()) + return -EINVAL; + + ls1021a_bootsource_init(); + ls102xa_smmu_stream_id_init(); + layerscape_register_pbl_image_handler(); + ls1021a_restart_register_feature(); + + return 0; +} + +static int ls1028a_init(void) +{ + if (!cpu_is_ls1028a()) + return -EINVAL; + + ls1028a_bootsource_init(); + layerscape_register_pbl_image_handler(); + ls1028a_setup_icids(); + + return 0; +} + +static int ls1028a_reserve_tfa(void) +{ + resource_size_t tfa_start = LS1028A_TFA_RESERVED_START; + resource_size_t tfa_size = LS1028A_TFA_RESERVED_SIZE; + struct resource *res; + + if (!cpu_is_ls1028a()) + return 0; + + res = reserve_sdram_region("tfa", tfa_start, tfa_size); + if (!res) { + pr_err("Cannot request SDRAM region %pa - %pa\n", &tfa_start, &tfa_size); + return -EINVAL; + } + + of_register_fixup(of_fixup_reserved_memory, res); + + return 0; +} +mmu_initcall(ls1028a_reserve_tfa); + +#define DWC3_GSBUSCFG0 0xc100 +#define DWC3_GSBUSCFG0_CACHETYPE_MASK GENMASK(31, 16) + +static void layerscape_usb_enable_snooping(void) +{ + struct device_node *np; + + for_each_compatible_node(np, NULL, "snps,dwc3") { + struct resource res; + + if (of_address_to_resource(np, 0, &res)) + continue; + + /* Set cacheable bit for all of Data read, Descriptor read, + * Data write and Descriptor write. Bufferable and read/write + * allocate bits are not set. This is the recommended configurationr + * in LS1046ARM Rev. 3 34.2.10.2: + * "For master interface DMA access, program the GSBUSCFG0 + * register to 0x2222000F for better performance.". + * The 0x000F is configured via snps,incr-burst-type-adjustment + * (which despite the name is Layerscape-specific), so below + * line only manipulates the upper 16 bits. + */ + clrsetbits_le32(IOMEM(res.start) + DWC3_GSBUSCFG0, + DWC3_GSBUSCFG0_CACHETYPE_MASK, + FIELD_PREP(DWC3_GSBUSCFG0_CACHETYPE_MASK, 0x2222)); + } +} + +static int ls1046a_init(void) +{ + if (!cpu_is_ls1046a()) + return -EINVAL; + + ls1046a_bootsource_init(); + ls1046a_setup_icids(); + layerscape_register_pbl_image_handler(); + layerscape_usb_enable_snooping(); + + return 0; +} + +static int layerscape_init(void) +{ + struct device_node *root; + + root = of_get_root_node(); + if (root) { + __layerscape_soc_type = layerscape_soc_from_dt(); + if (!__layerscape_soc_type) + return 0; + } + + switch (__layerscape_soc_type) { + case LAYERSCAPE_SOC_LS1021A: + return ls1021a_init(); + case LAYERSCAPE_SOC_LS1028A: + return ls1028a_init(); + case LAYERSCAPE_SOC_LS1046A: + return ls1046a_init(); + } + + return 0; +} +postcore_initcall(layerscape_init); diff --git a/arch/arm/mach-layerscape/tzc400.c b/arch/arm/mach-layerscape/tzc400.c new file mode 100644 index 0000000000..04a97809f5 --- /dev/null +++ b/arch/arm/mach-layerscape/tzc400.c @@ -0,0 +1,303 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright (c) 2016-2022, ARM Limited and Contributors. All rights reserved. + * + */ +#define pr_fmt(fmt) "tzc400: " fmt + +#include <common.h> +#include <linux/bitfield.h> +#include <linux/sizes.h> +#include <mach/layerscape/lowlevel.h> +#include <mach/layerscape/layerscape.h> + +#include "tzc400.h" + +static inline void mmio_write_32(uintptr_t addr, uint32_t value) +{ + out_le32(addr, value); +} + +static inline uint32_t mmio_read_32(uintptr_t addr) +{ + return in_le32(addr); +} + +static inline void mmio_clrsetbits_32(uintptr_t addr, + uint32_t clear, + uint32_t set) +{ + clrsetbits_le32(addr, clear, set); +} + +static inline unsigned int tzc_read_peripheral_id(uintptr_t base) +{ + unsigned int id; + + id = mmio_read_32(base + PID0_OFF); + /* Masks DESC part in PID1 */ + id |= ((mmio_read_32(base + PID1_OFF) & 0xFU) << 8U); + + return id; +} + +/* + * Implementation defined values used to validate inputs later. + * Filters : max of 4 ; 0 to 3 + * Regions : max of 9 ; 0 to 8 + * Address width : Values between 32 to 64 + */ +struct tzc400_instance { + uintptr_t base; + uint8_t addr_width; + uint8_t num_filters; + uint8_t num_regions; +}; + +static struct tzc400_instance tzc400; + +static inline unsigned int tzc400_read_gate_keeper(void) +{ + uintptr_t base = tzc400.base; + + return mmio_read_32(base + TZC400_GATE_KEEPER); +} + +static inline void tzc400_write_gate_keeper(unsigned int val) +{ + uintptr_t base = tzc400.base; + + mmio_write_32(base + TZC400_GATE_KEEPER, val); +} + +static unsigned int tzc400_open_status(void) +{ + return FIELD_GET(TZC400_GATE_KEEPER_OS, tzc400_read_gate_keeper()); +} + +static unsigned int tzc400_get_gate_keeper(unsigned int filter) +{ + return (tzc400_open_status() >> filter) & GATE_KEEPER_FILTER_MASK; +} + +/* This function is not MP safe. */ +static void tzc400_set_gate_keeper(unsigned int filter, int val) +{ + unsigned int os; + + /* Upper half is current state. Lower half is requested state. */ + os = tzc400_open_status(); + + if (val != 0) + os |= (1UL << filter); + else + os &= ~(1UL << filter); + + tzc400_write_gate_keeper(FIELD_PREP(TZC400_GATE_KEEPER_OR, os)); + + /* Wait here until we see the change reflected in the TZC status. */ + while ((tzc400_open_status()) != os) + ; +} + +void tzc400_set_action(unsigned int action) +{ + uintptr_t base = tzc400.base; + + ASSERT(base != 0U); + ASSERT(action <= TZC_ACTION_ERR_INT); + + mmio_write_32(base + TZC400_ACTION, action); +} + +void tzc400_init(uintptr_t base) +{ + unsigned int tzc400_id; + unsigned int tzc400_build; + + tzc400.base = base; + + tzc400_id = tzc_read_peripheral_id(base); + if (tzc400_id != TZC400_PERIPHERAL_ID) + panic("TZC-400 : Wrong device ID (0x%x).\n", tzc400_id); + + /* Save values we will use later. */ + tzc400_build = mmio_read_32(base + TZC400_BUILD_CONFIG); + tzc400.num_filters = FIELD_GET(TZC400_BUILD_CONFIG_NF, tzc400_build) + 1; + tzc400.addr_width = FIELD_GET(TZC400_BUILD_CONFIG_AW, tzc400_build) + 1; + tzc400.num_regions = FIELD_GET(TZC400_BUILD_CONFIG_NR, tzc400_build) + 1; +} + +/* + * `tzc400_configure_region` is used to program regions into the TrustZone + * controller. A region can be associated with more than one filter. The + * associated filters are passed in as a bitmap (bit0 = filter0), except that + * the value TZC400_REGION_ATTR_FILTER_BIT_ALL selects all filters, based on + * the value of tzc400.num_filters. + * NOTE: + * Region 0 is special; it is preferable to use tzc400_configure_region0 + * for this region (see comment for that function). + */ +void tzc400_configure_region(unsigned int filters, unsigned int region, uint64_t region_base, + uint64_t region_top, unsigned int sec_attr, + unsigned int nsaid_permissions) +{ + uintptr_t rbase = tzc400.base + TZC_REGION_OFFSET(TZC400_REGION_SIZE, region); + + /* Adjust filter mask by real filter number */ + if (filters == TZC400_REGION_ATTR_FILTER_BIT_ALL) + filters = (1U << tzc400.num_filters) - 1U; + + /* Do range checks on filters and regions. */ + ASSERT(((filters >> tzc400.num_filters) == 0U) && + (region < tzc400.num_regions)); + + /* + * Do address range check based on TZC configuration. A 64bit address is + * the max and expected case. + */ + ASSERT((region_top <= (U64_MAX >> (64U - tzc400.addr_width))) && + (region_base < region_top)); + + /* region_base and (region_top + 1) must be 4KB aligned */ + ASSERT(((region_base | (region_top + 1U)) & (4096U - 1U)) == 0U); + + ASSERT(sec_attr <= TZC_REGION_S_RDWR); + + pr_debug("TrustZone : Configuring region %u\n", region); + pr_debug("TrustZone : ... base = %llx, top = %llx,\n", region_base, region_top); + pr_debug("TrustZone : ... sec_attr = 0x%x, ns_devs = 0x%x)\n", + sec_attr, nsaid_permissions); + + /***************************************************/ + /* Inputs look ok, start programming registers. */ + /* All the address registers are 32 bits wide and */ + /* have a LOW and HIGH */ + /* component used to construct an address up to a */ + /* 64bit. */ + /***************************************************/ + mmio_write_32(rbase + TZC400_REGION_BASE_LOW_0, (uint32_t)region_base); + mmio_write_32(rbase + TZC400_REGION_BASE_HIGH_0, (uint32_t)(region_base >> 32)); + mmio_write_32(rbase + TZC400_REGION_TOP_LOW_0, (uint32_t)region_top); + mmio_write_32(rbase + TZC400_REGION_TOP_HIGH_0, (uint32_t)(region_top >> 32)); + + /* Enable filter to the region and set secure attributes */ + mmio_write_32(rbase + TZC400_REGION_ATTR_0, + (sec_attr << TZC_REGION_ATTR_SEC_SHIFT) | (filters << TZC_REGION_ATTR_F_EN_SHIFT)); + + /***************************************************/ + /* Specify which non-secure devices have permission*/ + /* to access this region. */ + /***************************************************/ + mmio_write_32(rbase + TZC400_REGION_ID_ACCESS_0, nsaid_permissions); +} + +void tzc400_update_filters(unsigned int region, unsigned int filters) +{ + uintptr_t rbase = tzc400.base + TZC_REGION_OFFSET(TZC400_REGION_SIZE, region); + uint32_t filters_mask = GENMASK(tzc400.num_filters - 1U, 0); + + /* Do range checks on filters and regions. */ + ASSERT(((filters >> tzc400.num_filters) == 0U) && + (region < tzc400.num_regions)); + + mmio_clrsetbits_32(rbase + TZC400_REGION_ATTR_0, + filters_mask << TZC_REGION_ATTR_F_EN_SHIFT, + filters << TZC_REGION_ATTR_F_EN_SHIFT); +} + +void tzc400_enable_filters(void) +{ + unsigned int state; + unsigned int filter; + + ASSERT(tzc400.base != 0U); + + for (filter = 0U; filter < tzc400.num_filters; filter++) { + state = tzc400_get_gate_keeper(filter); + if (state != 0U) { + /* Filter 0 is special and cannot be disabled. + * So here we allow it being already enabled. */ + if (filter == 0U) + continue; + + /* + * The TZC filter is already configured. Changing the + * programmer's view in an active system can cause + * unpredictable behavior therefore panic for now rather + * than try to determine whether this is safe in this + * instance. + * + * See the 'ARM (R) CoreLink TM TZC-400 TrustZone (R) + * Address Space Controller' Technical Reference Manual. + */ + panic("TZC-400 : Filter %u Gatekeeper already enabled.\n", + filter); + } + tzc400_set_gate_keeper(filter, 1); + } +} + +void tzc400_disable_filters(void) +{ + unsigned int filter; + unsigned int state; + unsigned int start = 0U; + + ASSERT(tzc400.base != 0U); + + /* Filter 0 is special and cannot be disabled. */ + state = tzc400_get_gate_keeper(0); + if (state != 0U) + start++; + + for (filter = start; filter < tzc400.num_filters; filter++) + tzc400_set_gate_keeper(filter, 0); +} + +unsigned long ls1028a_tzc400_init(unsigned long memsize) +{ + unsigned long lowmem, highmem, lowmem_end; + + tzc400_init(LS1028A_TZC400_BASE); + tzc400_disable_filters(); + + /* Region 0 set to no access by default */ + mmio_write_32(tzc400.base + TZC400_REGION_ATTR_0, TZC_REGION_S_NONE << TZC_REGION_ATTR_SEC_SHIFT); + mmio_write_32(tzc400.base + TZC400_REGION_ID_ACCESS_0, 0); + + lowmem = min_t(unsigned long, LS1028A_DDR_SDRAM_LOWMEM_SIZE, memsize); + lowmem_end = LS1028A_DDR_SDRAM_BASE + lowmem; + highmem = memsize - lowmem; + + /* region 1: secure memory */ + tzc400_configure_region(1, 1, + lowmem_end - LS1028A_SECURE_DRAM_SIZE, + lowmem_end - 1, + TZC_REGION_S_RDWR, TZC_REGION_NS_NONE); + + /* region 2: shared memory */ + tzc400_configure_region(1, 2, + lowmem_end - LS1028A_SECURE_DRAM_SIZE - LS1028A_SP_SHARED_DRAM_SIZE, + lowmem_end - LS1028A_SECURE_DRAM_SIZE - 1, + TZC_REGION_S_RDWR, TZC_NS_ACCESS_ID); + + /* region 3: nonsecure low memory */ + tzc400_configure_region(1, 3, + LS1028A_DDR_SDRAM_BASE, + lowmem_end - LS1028A_SECURE_DRAM_SIZE - LS1028A_SP_SHARED_DRAM_SIZE - 1, + TZC_REGION_S_RDWR, TZC_NS_ACCESS_ID); + + if (highmem) + /* nonsecure high memory */ + tzc400_configure_region(1, 4, + LS1028A_DDR_SDRAM_HIGHMEM_BASE, + LS1028A_DDR_SDRAM_HIGHMEM_BASE + highmem - 1, + TZC_REGION_S_RDWR, TZC_NS_ACCESS_ID); + + tzc400_set_action(TZC_ACTION_ERR); + + tzc400_enable_filters(); + + return lowmem - LS1028A_SECURE_DRAM_SIZE - LS1028A_SP_SHARED_DRAM_SIZE; +} diff --git a/arch/arm/mach-layerscape/tzc400.h b/arch/arm/mach-layerscape/tzc400.h new file mode 100644 index 0000000000..c8d4583622 --- /dev/null +++ b/arch/arm/mach-layerscape/tzc400.h @@ -0,0 +1,164 @@ +/* + * Copyright (c) 2014-2021, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef TZC400_H +#define TZC400_H + +#include <linux/bits.h> + +/* + * Offset of core registers from the start of the base of configuration + * registers for each region. + */ + +/* ID Registers */ +#define PID0_OFF 0xfe0 +#define PID1_OFF 0xfe4 +#define PID2_OFF 0xfe8 +#define PID3_OFF 0xfec +#define PID4_OFF 0xfd0 +#define CID0_OFF 0xff0 +#define CID1_OFF 0xff4 +#define CID2_OFF 0xff8 +#define CID3_OFF 0xffc + +/* + * What type of action is expected when an access violation occurs. + * The memory requested is returned as zero. But we can also raise an event to + * let the system know it happened. + * We can raise an interrupt(INT) and/or cause an exception(ERR). + * TZC_ACTION_NONE - No interrupt, no Exception + * TZC_ACTION_ERR - No interrupt, raise exception -> sync external + * data abort + * TZC_ACTION_INT - Raise interrupt, no exception + * TZC_ACTION_ERR_INT - Raise interrupt, raise exception -> sync + * external data abort + */ +#define TZC_ACTION_NONE 0 +#define TZC_ACTION_ERR 1 +#define TZC_ACTION_INT 2 +#define TZC_ACTION_ERR_INT (TZC_ACTION_ERR | TZC_ACTION_INT) + +/* Bit positions of TZC_ACTION registers */ +#define TZC_ACTION_RV_SHIFT 0 +#define TZC_ACTION_RV_MASK 0x3 +#define TZC_ACTION_RV_LOWOK 0x0 +#define TZC_ACTION_RV_LOWERR 0x1 +#define TZC_ACTION_RV_HIGHOK 0x2 +#define TZC_ACTION_RV_HIGHERR 0x3 + +/* + * Controls secure access to a region. If not enabled secure access is not + * allowed to region. + */ +#define TZC_REGION_S_NONE 0 +#define TZC_REGION_S_RD 1 +#define TZC_REGION_S_WR 2 +#define TZC_REGION_S_RDWR (TZC_REGION_S_RD | TZC_REGION_S_WR) + +#define TZC_REGION_ATTR_S_RD_SHIFT 30 +#define TZC_REGION_ATTR_S_WR_SHIFT 31 +#define TZC_REGION_ATTR_F_EN_SHIFT 0 +#define TZC_REGION_ATTR_SEC_SHIFT 30 +#define TZC_REGION_ATTR_S_RD_MASK 0x1 +#define TZC_REGION_ATTR_S_WR_MASK 0x1 +#define TZC_REGION_ATTR_SEC_MASK 0x3 + +#define TZC_REGION_ACCESS_WR_EN_SHIFT 16 +#define TZC_REGION_ACCESS_RD_EN_SHIFT 0 +#define TZC_REGION_ACCESS_ID_MASK 0xf + +/* Macros for allowing Non-Secure access to a region based on NSAID */ +#define TZC_REGION_ACCESS_RD(nsaid) \ + ((U(1) << ((nsaid) & TZC_REGION_ACCESS_ID_MASK)) << \ + TZC_REGION_ACCESS_RD_EN_SHIFT) +#define TZC_REGION_ACCESS_WR(nsaid) \ + ((U(1) << ((nsaid) & TZC_REGION_ACCESS_ID_MASK)) << \ + TZC_REGION_ACCESS_WR_EN_SHIFT) +#define TZC_REGION_ACCESS_RDWR(nsaid) \ + (TZC_REGION_ACCESS_RD(nsaid) | \ + TZC_REGION_ACCESS_WR(nsaid)) + +/* Returns offset of registers to program for a given region no */ +#define TZC_REGION_OFFSET(region_size, region_no) \ + ((region_size) * (region_no)) + +#define TZC400_BUILD_CONFIG 0x000 +#define TZC400_GATE_KEEPER 0x008 +#define TZC400_SPECULATION_CTRL 0x00c +#define TZC400_INT_STATUS 0x010 +#define TZC400_INT_CLEAR 0x014 + +#define TZC400_FAIL_ADDRESS_LOW 0x020 +#define TZC400_FAIL_ADDRESS_HIGH 0x024 +#define TZC400_FAIL_CONTROL 0x028 +#define TZC400_FAIL_ID 0x02c + +#define TZC400_BUILD_CONFIG_NF GENMASK(25, 24) +#define TZC400_BUILD_CONFIG_AW GENMASK(13, 8) +#define TZC400_BUILD_CONFIG_NR GENMASK(4, 0) + +/* + * Number of gate keepers is implementation defined. But we know the max for + * this device is 4. Get implementation details from BUILD_CONFIG. + */ +#define TZC400_GATE_KEEPER_OS GENMASK(19, 16) +#define TZC400_GATE_KEEPER_OR GENMASK(3, 0) +#define GATE_KEEPER_FILTER_MASK 0x1 + +#define TZC400_FAIL_CONTROL_DIR_WRITE BIT(24) +#define TZC400_FAIL_CONTROL_NS_NONSECURE BIT(21) +#define TZC400_FAIL_CONTROL_PRIV BIT(20) + +#define TZC400_PERIPHERAL_ID 0x460 + +/* Filter enable bits in a TZC */ +#define TZC400_REGION_ATTR_F_EN_MASK 0xf +#define TZC400_REGION_ATTR_FILTER_BIT(x) (1) << (x)) +#define TZC400_REGION_ATTR_FILTER_BIT_ALL TZC400_REGION_ATTR_F_EN_MASK + +/* + * All TZC region configuration registers are placed one after another. It + * depicts size of block of registers for programming each region. + */ +#define TZC400_REGION_SIZE 0x20 +#define TZC400_ACTION 0x4 + +#define FILTER_OFFSET 0x10 + +#define TZC400_REGION_BASE_LOW_0 0x100 +#define TZC400_REGION_BASE_HIGH_0 0x104 +#define TZC400_REGION_TOP_LOW_0 0x108 +#define TZC400_REGION_TOP_HIGH_0 0x10c +#define TZC400_REGION_ATTR_0 0x110 +#define TZC400_REGION_ID_ACCESS_0 0x114 + +#define TZC_REGION_NS_NONE 0x00000000U + +/* + * NXP Platforms do not support NS Access ID (NSAID) based non-secure access. + * Supports only non secure through generic NS ACCESS ID + */ +#define TZC_NS_ACCESS_ID 0xFFFFFFFFU + +/******************************************************************************* + * Function & variable prototypes + ******************************************************************************/ +void tzc400_init(uintptr_t base); +void tzc400_configure_region0(unsigned int sec_attr, + unsigned int ns_device_access); +void tzc400_configure_region(unsigned int filters, + unsigned int region, + unsigned long long region_base, + unsigned long long region_top, + unsigned int sec_attr, + unsigned int nsaid_permissions); +void tzc400_update_filters(unsigned int region, unsigned int filters); +void tzc400_set_action(unsigned int action); +void tzc400_enable_filters(void); +void tzc400_disable_filters(void); + +#endif /* TZC400_H */ diff --git a/arch/arm/mach-layerscape/xload-qspi.c b/arch/arm/mach-layerscape/xload-qspi.c index 192aea64b4..608434bf1f 100644 --- a/arch/arm/mach-layerscape/xload-qspi.c +++ b/arch/arm/mach-layerscape/xload-qspi.c @@ -4,8 +4,8 @@ #include <soc/fsl/immap_lsch2.h> #include <asm-generic/sections.h> #include <asm/cache.h> -#include <mach/xload.h> -#include <mach/layerscape.h> +#include <mach/layerscape/xload.h> +#include <mach/layerscape/layerscape.h> /* * The offset of the 2nd stage image in the output file. This must match with the @@ -13,18 +13,21 @@ */ #define BAREBOX_START (128 * 1024) -int ls1046a_qspi_start_image(unsigned long r0, unsigned long r1, - unsigned long r2) +struct layerscape_base_addr { + void *qspi_reg_base; + void *membase; + void *qspi_mem_base; +}; + +static int layerscape_qspi_start_image(struct layerscape_base_addr *base, + unsigned long r0, unsigned long r1, unsigned long r2) { - void *qspi_reg_base = IOMEM(LSCH2_QSPI0_BASE_ADDR); - void *membase = (void *)LS1046A_DDR_SDRAM_BASE; - void *qspi_mem_base = IOMEM(0x40000000); - void (*barebox)(unsigned long, unsigned long, unsigned long) = membase; + void (*barebox)(unsigned long, unsigned long, unsigned long) = base->membase; /* Switch controller into little endian mode */ - out_be32(qspi_reg_base, 0x000f400c); + out_be32(base->qspi_reg_base, 0x000f400c); - memcpy(membase, qspi_mem_base + BAREBOX_START, barebox_image_size); + memcpy(base->membase, base->qspi_mem_base + BAREBOX_START, barebox_image_size); sync_caches_for_execution(); @@ -36,3 +39,27 @@ int ls1046a_qspi_start_image(unsigned long r0, unsigned long r1, return -EIO; } + +int ls1046a_qspi_start_image(unsigned long r0, unsigned long r1, + unsigned long r2) +{ + struct layerscape_base_addr base; + + base.qspi_reg_base = IOMEM(LSCH2_QSPI0_BASE_ADDR); + base.membase = IOMEM(LS1046A_DDR_SDRAM_BASE); + base.qspi_mem_base = IOMEM(0x40000000); + + return layerscape_qspi_start_image(&base, r0, r1, r2); +} + +int ls1021a_qspi_start_image(unsigned long r0, unsigned long r1, + unsigned long r2) +{ + struct layerscape_base_addr base; + + base.qspi_reg_base = IOMEM(LSCH2_QSPI0_BASE_ADDR); + base.membase = IOMEM(LS1021A_DDR_SDRAM_BASE); + base.qspi_mem_base = IOMEM(0x40000000); + + return layerscape_qspi_start_image(&base, r0, r1, r2); +} diff --git a/arch/arm/mach-layerscape/xload.c b/arch/arm/mach-layerscape/xload.c index 54495d7f97..32ff158b1b 100644 --- a/arch/arm/mach-layerscape/xload.c +++ b/arch/arm/mach-layerscape/xload.c @@ -2,21 +2,39 @@ #include <common.h> #include <bootsource.h> -#include <mach/layerscape.h> -#include <mach/xload.h> +#include <mach/layerscape/layerscape.h> +#include <mach/layerscape/xload.h> int ls1046a_xload_start_image(unsigned long r0, unsigned long r1, unsigned long r2) { enum bootsource src; - src = ls1046_bootsource_get(); + src = ls1046a_bootsource_get(); switch (src) { case BOOTSOURCE_SPI_NOR: return ls1046a_qspi_start_image(r0, r1, r2); +#if defined(CONFIG_MCI_IMX_ESDHC_PBL) case BOOTSOURCE_MMC: return ls1046a_esdhc_start_image(r0, r1, r2); +#endif + default: + pr_err("Unknown bootsource\n"); + return -EINVAL; + } +} + +int ls1021a_xload_start_image(unsigned long r0, unsigned long r1, + unsigned long r2) +{ + enum bootsource src; + + src = ls1021a_bootsource_get(); + + switch (src) { + case BOOTSOURCE_SPI_NOR: + return ls1021a_qspi_start_image(r0, r1, r2); default: pr_err("Unknown bootsource\n"); return -EINVAL; |