diff options
Diffstat (limited to 'arch/arm/mach-layerscape')
25 files changed, 1787 insertions, 252 deletions
diff --git a/arch/arm/mach-layerscape/Kconfig b/arch/arm/mach-layerscape/Kconfig index c15d5873a5..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" @@ -35,3 +49,19 @@ config MACH_TQMLS1046A 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 644401b181..ebe3896075 100644 --- a/arch/arm/mach-layerscape/icid.c +++ b/arch/arm/mach-layerscape/icid.c @@ -1,10 +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 @@ -65,6 +69,72 @@ 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; @@ -78,7 +148,7 @@ struct fman_icid_id_table { #define SEC_QIIC_LS 0x70024 #define SEC_IRBAR_JRn(n) (0x10000 * ((n) + 1)) -struct icid_id_table icid_tbl_ls1046a[] = { +static const struct icid_id_table icid_tbl_ls1046a[] = { { .compat = "fsl,qman", .id = DPAA1_SID_START, @@ -206,7 +276,7 @@ struct icid_id_table icid_tbl_ls1046a[] = { }, }; -struct fman_icid_id_table fman_icid_tbl_ls1046a[] = { +static const struct fman_icid_id_table fman_icid_tbl_ls1046a[] = { { .port_id = 0x02, .icid = DPAA1_SID_END, @@ -276,7 +346,7 @@ struct fman_icid_id_table fman_icid_tbl_ls1046a[] = { }, }; -static int get_fman_port_icid(int port_id, struct fman_icid_id_table *tbl, +static int get_fman_port_icid(int port_id, const struct fman_icid_id_table *tbl, const int size) { int i; @@ -289,18 +359,7 @@ static int get_fman_port_icid(int port_id, struct fman_icid_id_table *tbl, return -ENODEV; } -static void fdt_set_iommu_prop(struct device_node *np, phandle iommu_handle, - int stream_id) -{ - u32 prop[2]; - - prop[0] = cpu_to_fdt32(iommu_handle); - prop[1] = cpu_to_fdt32(stream_id); - - of_set_property(np, "iommus", prop, sizeof(prop), 1); -} - -static void fdt_fixup_fman_port_icid_by_compat(struct device_node *root, +static void of_fixup_fman_port_icid_by_compat(struct device_node *root, phandle iommu_handle, const char *compat) { @@ -321,11 +380,11 @@ static void fdt_fixup_fman_port_icid_by_compat(struct device_node *root, continue; } - fdt_set_iommu_prop(np, iommu_handle, icid); + of_set_iommu_prop(np, iommu_handle, icid); } } -static void fdt_fixup_fman_icids(struct device_node *root, phandle iommu_handle) +static void of_fixup_fman_icids(struct device_node *root, phandle iommu_handle) { static const char * const compats[] = { "fsl,fman-v3-port-oh", @@ -335,7 +394,7 @@ static void fdt_fixup_fman_icids(struct device_node *root, phandle iommu_handle) int i; for (i = 0; i < ARRAY_SIZE(compats); i++) - fdt_fixup_fman_port_icid_by_compat(root, iommu_handle, compats[i]); + of_fixup_fman_port_icid_by_compat(root, iommu_handle, compats[i]); } struct qportal_info { @@ -345,7 +404,7 @@ struct qportal_info { u8 sdest; }; -struct qportal_info qp_info[] = { +static const struct qportal_info qp_info[] = { { .dicid = DPAA1_SID_END, .ficid = DPAA1_SID_END, @@ -437,7 +496,7 @@ static void setup_qbman_portals(void) out_be32(&qman->qcsp_bar, (u32)QMAN_MEM_PHYS); for (i = 0; i < ARRAY_SIZE(qp_info); i++) { - struct qportal_info *qi = &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 */ @@ -449,22 +508,22 @@ static void setup_qbman_portals(void) inhibit_portals(qpaddr, ARRAY_SIZE(qp_info), QMAN_SP_CINH_SIZE); } -static void fdt_set_qportal_iommu_prop(struct device_node *np, phandle iommu_handle, - struct qportal_info *qp_info) +static void of_set_qportal_iommu_prop(struct device_node *np, phandle iommu_handle, + const struct qportal_info *qp_info) { - u32 prop[6]; - - prop[0] = cpu_to_fdt32(iommu_handle); - prop[1] = cpu_to_fdt32(qp_info->icid); - prop[2] = cpu_to_fdt32(iommu_handle); - prop[3] = cpu_to_fdt32(qp_info->dicid); - prop[4] = cpu_to_fdt32(iommu_handle); - prop[5] = cpu_to_fdt32(qp_info->ficid); + u32 prop[] = { + iommu_handle, + qp_info->icid, + iommu_handle, + qp_info->dicid, + iommu_handle, + qp_info->ficid + }; - of_set_property(np, "iommus", prop, sizeof(prop), 1); + of_property_write_u32_array(np, "iommus", prop, ARRAY_SIZE(prop)); } -static void fdt_fixup_qportals(struct device_node *root, phandle iommu_handle) +static void of_fixup_qportals(struct device_node *root, phandle iommu_handle) { struct device_node *np; unsigned int maj, min; @@ -484,77 +543,253 @@ static void fdt_fixup_qportals(struct device_node *root, phandle iommu_handle) if (ret) continue; - fdt_set_qportal_iommu_prop(np, iommu_handle, &qp_info[cell_index]); + of_set_qportal_iommu_prop(np, iommu_handle, &qp_info[cell_index]); } } -static int icid_of_fixup(struct device_node *root, void *context) +static int of_fixup_ls1046a(struct device_node *root, void *context) { - int i; - struct device_node *iommu; phandle iommu_handle; - iommu = of_find_compatible_node(root, NULL, "arm,mmu-500"); - if (!iommu) { - pr_info("No \"arm,mmu-500\" node found, won't fixup\n"); + iommu_handle = of_get_iommu_handle(root); + if (!iommu_handle) return 0; - } - iommu_handle = of_node_create_phandle(iommu); + 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); - for (i = 0; i < ARRAY_SIZE(icid_tbl_ls1046a); i++) { - struct icid_id_table *icid = &icid_tbl_ls1046a[i]; - struct device_node *np; + return 0; +} - if (!icid->compat) - continue; +void ls1046a_setup_icids(void) +{ + struct ccsr_fman *fm = (void *)LSCH2_FM1_ADDR; + int i; - for_each_compatible_node_from(np, root, NULL, icid->compat) { - struct resource res; + setup_icid_offsets(icid_tbl_ls1046a, ARRAY_SIZE(icid_tbl_ls1046a), false); - if (of_address_to_resource(np, 0, &res)) - continue; + /* 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]; - if (res.start == icid->compat_addr) { - fdt_set_iommu_prop(np, iommu_handle, icid->id); - break; - } - } + 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 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) +{ + phandle iommu_handle; + + iommu_handle = of_get_iommu_handle(root); + if (!iommu_handle) + return 0; - fdt_fixup_fman_icids(root, iommu_handle); - fdt_fixup_qportals(root, iommu_handle); + of_fixup_icid(root, iommu_handle, icid_tbl_ls1028a, ARRAY_SIZE(icid_tbl_ls1028a)); return 0; } -static int layerscape_setup_icids(void) +/* 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; - struct ccsr_fman *fm = (void *)LSCH2_FM1_ADDR; - if (!of_machine_is_compatible("fsl,ls1046a")) - return 0; + out_le32(ECAM_IERB_MSICAR, ECAM_IERB_MSICAR_VALUE); - /* setup general icid offsets */ - for (i = 0; i < ARRAY_SIZE(icid_tbl_ls1046a); i++) { - struct icid_id_table *icid = &icid_tbl_ls1046a[i]; + for (i = 0; i < ARRAY_SIZE(ierb_offset); i++) { + if (ierb_offset[i] < 0) + continue; - out_be32((u32 *)(icid->reg_addr), icid->reg); + out_le32(ECAM_IERB_BASE + ierb_offset[i], + FSL_ECAM_STREAM_ID_START + i); } +} - /* setup fman icids */ - for (i = 0; i < ARRAY_SIZE(fman_icid_tbl_ls1046a); i++) { - struct fman_icid_id_table *icid = &fman_icid_tbl_ls1046a[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]; - out_be32(&fm->fm_bmi_common.fmbm_ppid[icid->port_id - 1], - icid->icid); + 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; } - setup_qbman_portals(); + 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; + } - of_register_fixup(icid_of_fixup, NULL); + 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; } -coredevice_initcall(layerscape_setup_icids); + +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 d962fba751..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,7 +14,7 @@ #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 *); @@ -46,7 +47,7 @@ static int of_psci_do_fixup(struct device_node *root, void *unused) break; } - return of_psci_fixup(root, psci_version); + return of_psci_fixup(root, psci_version, "smc"); } static int ppa_init(void *ppa, size_t ppa_size, void *sec_firmware_addr) @@ -54,17 +55,11 @@ 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]; @@ -115,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); @@ -126,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; |