diff options
Diffstat (limited to 'arch/arm/mach-imx/imx6.c')
-rw-r--r-- | arch/arm/mach-imx/imx6.c | 168 |
1 files changed, 80 insertions, 88 deletions
diff --git a/arch/arm/mach-imx/imx6.c b/arch/arm/mach-imx/imx6.c index 41e0066add..b0d3d8ef2f 100644 --- a/arch/arm/mach-imx/imx6.c +++ b/arch/arm/mach-imx/imx6.c @@ -1,34 +1,23 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ +// SPDX-License-Identifier: GPL-2.0-or-later +#include <abort.h> #include <init.h> #include <common.h> #include <io.h> #include <linux/sizes.h> #include <mfd/imx6q-iomuxc-gpr.h> -#include <mach/clock-imx6.h> -#include <mach/imx6.h> -#include <mach/generic.h> -#include <mach/revision.h> -#include <mach/reset-reason.h> -#include <mach/imx6-anadig.h> -#include <mach/imx6-regs.h> -#include <mach/imx6-fusemap.h> -#include <mach/usb.h> +#include <mach/imx/clock-imx6.h> +#include <mach/imx/imx6.h> +#include <mach/imx/generic.h> +#include <mach/imx/revision.h> +#include <mach/imx/reset-reason.h> +#include <mach/imx/imx6-anadig.h> +#include <mach/imx/imx6-regs.h> +#include <mach/imx/imx6-fusemap.h> +#include <mach/imx/usb.h> #include <asm/mmu.h> #include <asm/cache-l2x0.h> - -#include <poweroff.h> +#include <mfd/pfuze.h> #define CLPCR 0x54 #define BP_CLPCR_LPM(mode) ((mode) & 0x3) @@ -42,76 +31,54 @@ #define MX6_OCOTP_CFG0 0x410 #define MX6_OCOTP_CFG1 0x420 -static void imx6_init_lowlevel(void) +static void imx6_configure_aips(void __iomem *aips) { - void __iomem *aips1 = (void *)MX6_AIPS1_ON_BASE_ADDR; - void __iomem *aips2 = (void *)MX6_AIPS2_ON_BASE_ADDR; - bool is_imx6q = __imx6_cpu_type() == IMX6_CPUTYPE_IMX6Q; - bool is_imx6d = __imx6_cpu_type() == IMX6_CPUTYPE_IMX6D; - uint32_t val_480; - uint32_t val_528; - uint32_t periph_sel_1; - uint32_t periph_sel_2; - uint32_t reg; - - if ((readl(MXC_CCM_CCGR6) & 0x3)) - imx_reset_otg_controller(IOMEM(MX6_OTG_BASE_ADDR)); - /* * Set all MPROTx to be non-bufferable, trusted for R/W, * not forced to user-mode. */ - writel(0x77777777, aips1); - writel(0x77777777, aips1 + 0x4); - writel(0, aips1 + 0x40); - writel(0, aips1 + 0x44); - writel(0, aips1 + 0x48); - writel(0, aips1 + 0x4c); - writel(0, aips1 + 0x50); - - writel(0x77777777, aips2); - writel(0x77777777, aips2 + 0x4); - writel(0, aips2 + 0x40); - writel(0, aips2 + 0x44); - writel(0, aips2 + 0x48); - writel(0, aips2 + 0x4c); - writel(0, aips2 + 0x50); - - /* Due to hardware limitation, on MX6Q we need to gate/ungate all PFDs - * to make sure PFD is working right, otherwise, PFDs may - * not output clock after reset, MX6DL and MX6SL have added 396M pfd - * workaround in ROM code, as bus clock need it. - * Don't reset PLL2 PFD0 / PLL2 PFD2 if is's used by periph_clk. - */ - if (is_imx6q || is_imx6d) { - val_480 = BM_ANADIG_PFD_480_PFD3_CLKGATE | - BM_ANADIG_PFD_480_PFD2_CLKGATE | - BM_ANADIG_PFD_480_PFD1_CLKGATE | - BM_ANADIG_PFD_480_PFD0_CLKGATE; - - val_528 = BM_ANADIG_PFD_528_PFD3_CLKGATE | - BM_ANADIG_PFD_528_PFD1_CLKGATE; + writel(0x77777777, aips); + writel(0x77777777, aips + 0x4); - reg = readl(MXC_CCM_CBCMR); - periph_sel_1 = (reg & MXC_CCM_CBCMR_PRE_PERIPH_CLK_SEL_MASK) - >> MXC_CCM_CBCMR_PRE_PERIPH_CLK_SEL_OFFSET; + /* + * Set all OPACRx to be non-bufferable, not require + * supervisor privilege level for access,allow for + * write access and untrusted master access. + */ + writel(0, aips + 0x40); + writel(0, aips + 0x44); + writel(0, aips + 0x48); + writel(0, aips + 0x4c); + writel(0, aips + 0x50); +} - periph_sel_2 = (reg & MXC_CCM_CBCMR_PRE_PERIPH2_CLK_SEL_MASK) - >> MXC_CCM_CBCMR_PRE_PERIPH2_CLK_SEL_OFFSET; +static void imx6_init_lowlevel(void) +{ + bool is_imx6ull = __imx6_cpu_type() == IMX6_CPUTYPE_IMX6ULL; + bool is_imx6sx = __imx6_cpu_type() == IMX6_CPUTYPE_IMX6SX; - if ((periph_sel_1 != 0x2) && (periph_sel_2 != 0x2)) - val_528 |= BM_ANADIG_PFD_528_PFD0_CLKGATE; + /* + * Before reset the controller imx6_boot_save_loc() must be called to + * detect serial-downloader fall back boots. For further information + * check the comment in imx6_get_boot_source(). + */ + if ((readl(MXC_CCM_CCGR6) & 0x3)) + imx_reset_otg_controller(IOMEM(MX6_OTG_BASE_ADDR)); - if ((periph_sel_1 != 0x1) && (periph_sel_2 != 0x1) - && (periph_sel_1 != 0x3) && (periph_sel_2 != 0x3)) - val_528 |= BM_ANADIG_PFD_528_PFD2_CLKGATE; + imx6_configure_aips(IOMEM(MX6_AIPS1_ON_BASE_ADDR)); + imx6_configure_aips(IOMEM(MX6_AIPS2_ON_BASE_ADDR)); + if (is_imx6ull || is_imx6sx) + imx6_configure_aips(IOMEM(MX6_AIPS3_ON_BASE_ADDR)); +} - writel(val_480, MX6_ANATOP_BASE_ADDR + HW_ANADIG_PFD_480_SET); - writel(val_528, MX6_ANATOP_BASE_ADDR + HW_ANADIG_PFD_528_SET); +static bool imx6_has_ipu(void) +{ + if (cpu_mx6_is_mx6qp() || cpu_mx6_is_mx6dp() || + cpu_mx6_is_mx6q() || cpu_mx6_is_mx6d() || + cpu_mx6_is_mx6dl() || cpu_mx6_is_mx6s()) + return true; - writel(val_480, MX6_ANATOP_BASE_ADDR + HW_ANADIG_PFD_480_CLR); - writel(val_528, MX6_ANATOP_BASE_ADDR + HW_ANADIG_PFD_528_CLR); - } + return false; } static void imx6_setup_ipu_qos(void) @@ -120,8 +87,7 @@ static void imx6_setup_ipu_qos(void) void __iomem *fast2 = (void *)MX6_FAST2_BASE_ADDR; uint32_t val; - if (!cpu_mx6_is_mx6q() && !cpu_mx6_is_mx6d() && - !cpu_mx6_is_mx6dl() && !cpu_mx6_is_mx6s()) + if (!imx6_has_ipu()) return; val = readl(iomux + IOMUXC_GPR4); @@ -195,6 +161,11 @@ u64 imx6_uid(void) return imx_ocotp_read_uid(IOMEM(MX6_OCOTP_BASE_ADDR)); } +static void imx6_register_poweroff_init(struct regmap *map) +{ + poweroff_handler_register_fn(imx6_pm_stby_poweroff); +} + int imx6_init(void) { const char *cputypestr; @@ -202,10 +173,10 @@ int imx6_init(void) void __iomem *src = IOMEM(MX6_SRC_BASE_ADDR); u64 mx6_uid; - imx6_init_lowlevel(); - imx6_boot_save_loc(); + imx6_init_lowlevel(); + mx6_silicon_revision = imx6_cpu_revision(); mx6_uid = imx6_uid(); @@ -252,6 +223,8 @@ int imx6_init(void) imx6_setup_ipu_qos(); imx6ul_enet_clk_init(); + pfuze_register_init_callback(imx6_register_poweroff_init); + return 0; } @@ -273,6 +246,22 @@ int imx6_devices_init(void) return 0; } +static bool imx6_cannot_write_l2x0(void) +{ + void __iomem *l2x0_base = IOMEM(0x00a02000); + u32 val; + /* + * Mask data aborts and try to access the PL210. If OP-TEE is running we + * will receive a data-abort and assume barebox is running in the normal + * world. + */ + val = readl(l2x0_base + L2X0_PREFETCH_CTRL); + + data_abort_mask(); + writel(val, l2x0_base + L2X0_PREFETCH_CTRL); + return data_abort_unmask(); +} + static int imx6_mmu_init(void) { void __iomem *l2x0_base = IOMEM(0x00a02000); @@ -281,6 +270,9 @@ static int imx6_mmu_init(void) if (!cpu_is_mx6()) return 0; + if (imx6_cannot_write_l2x0()) + return 0; + val = readl(l2x0_base + L2X0_CACHE_ID); cache_part = val & L2X0_CACHE_ID_PART_MASK; cache_rtl = val & L2X0_CACHE_ID_RTL_MASK; @@ -334,7 +326,7 @@ static int imx6_fixup_cpus(struct device_node *root, void *context) unsigned long scu_phys_base; unsigned int max_core_index; - cpus_node = of_find_node_by_name(root, "cpus"); + cpus_node = of_find_node_by_name_address(root, "cpus"); if (!cpus_node) return 0; @@ -366,7 +358,7 @@ static int imx6_fixup_cpus_register(void) } device_initcall(imx6_fixup_cpus_register); -void __noreturn imx6_pm_stby_poweroff(void) +void __noreturn imx6_pm_stby_poweroff(struct poweroff_handler *handler) { void *ccm_base = IOMEM(MX6_CCM_BASE_ADDR); void *gpc_base = IOMEM(MX6_GPC_BASE_ADDR); |