1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * Copyright 2011 Freescale Semiconductor, Inc. 4 * Copyright 2011 Linaro Ltd. 5 */ 6 7 #include <linux/init.h> 8 #include <linux/io.h> 9 #include <linux/iopoll.h> 10 #include <linux/of.h> 11 #include <linux/of_address.h> 12 #include <linux/platform_device.h> 13 #include <linux/reset-controller.h> 14 #include <linux/smp.h> 15 #include <asm/smp_plat.h> 16 #include "common.h" 17 #include "hardware.h" 18 19 #define SRC_SCR 0x000 20 #define SRC_GPR1_V1 0x020 21 #define SRC_GPR1_V2 0x074 22 #define SRC_GPR1(gpr_v2) ((gpr_v2) ? SRC_GPR1_V2 : SRC_GPR1_V1) 23 #define BP_SRC_SCR_WARM_RESET_ENABLE 0 24 #define BP_SRC_SCR_SW_GPU_RST 1 25 #define BP_SRC_SCR_SW_VPU_RST 2 26 #define BP_SRC_SCR_SW_IPU1_RST 3 27 #define BP_SRC_SCR_SW_OPEN_VG_RST 4 28 #define BP_SRC_SCR_SW_IPU2_RST 12 29 #define BP_SRC_SCR_CORE1_RST 14 30 #define BP_SRC_SCR_CORE1_ENABLE 22 31 /* below is for i.MX7D */ 32 #define SRC_A7RCR1 0x008 33 #define BP_SRC_A7RCR1_A7_CORE1_ENABLE 1 34 #define GPC_CPU_PGC_SW_PUP_REQ 0xf0 35 #define GPC_CPU_PGC_SW_PDN_REQ 0xfc 36 #define GPC_PGC_C1 0x840 37 #define BM_CPU_PGC_SW_PDN_PUP_REQ_CORE1_A7 0x2 38 39 static void __iomem *src_base; 40 static DEFINE_SPINLOCK(scr_lock); 41 static bool gpr_v2; 42 static void __iomem *gpc_base; 43 44 static const int sw_reset_bits[5] = { 45 BP_SRC_SCR_SW_GPU_RST, 46 BP_SRC_SCR_SW_VPU_RST, 47 BP_SRC_SCR_SW_IPU1_RST, 48 BP_SRC_SCR_SW_OPEN_VG_RST, 49 BP_SRC_SCR_SW_IPU2_RST 50 }; 51 52 static int imx_src_reset_module(struct reset_controller_dev *rcdev, 53 unsigned long sw_reset_idx) 54 { 55 unsigned long timeout; 56 unsigned long flags; 57 int bit; 58 u32 val; 59 60 if (sw_reset_idx >= ARRAY_SIZE(sw_reset_bits)) 61 return -EINVAL; 62 63 bit = 1 << sw_reset_bits[sw_reset_idx]; 64 65 spin_lock_irqsave(&scr_lock, flags); 66 val = readl_relaxed(src_base + SRC_SCR); 67 val |= bit; 68 writel_relaxed(val, src_base + SRC_SCR); 69 spin_unlock_irqrestore(&scr_lock, flags); 70 71 timeout = jiffies + msecs_to_jiffies(1000); 72 while (readl(src_base + SRC_SCR) & bit) { 73 if (time_after(jiffies, timeout)) 74 return -ETIME; 75 cpu_relax(); 76 } 77 78 return 0; 79 } 80 81 static const struct reset_control_ops imx_src_ops = { 82 .reset = imx_src_reset_module, 83 }; 84 85 static void imx_gpcv2_set_m_core_pgc(bool enable, u32 offset) 86 { 87 writel_relaxed(enable, gpc_base + offset); 88 } 89 90 /* 91 * The motivation for bringing up the second i.MX7D core inside the kernel 92 * is that legacy vendor bootloaders usually do not implement PSCI support. 93 * This is a significant blocker for systems in the field that are running old 94 * bootloader versions to upgrade to a modern mainline kernel version, as only 95 * one CPU of the i.MX7D would be brought up. 96 * Bring up the second i.MX7D core inside the kernel to make the migration 97 * path to mainline kernel easier for the existing iMX7D users. 98 */ 99 void imx_gpcv2_set_core1_pdn_pup_by_software(bool pdn) 100 { 101 u32 reg = pdn ? GPC_CPU_PGC_SW_PDN_REQ : GPC_CPU_PGC_SW_PUP_REQ; 102 u32 val, pup; 103 int ret; 104 105 imx_gpcv2_set_m_core_pgc(true, GPC_PGC_C1); 106 val = readl_relaxed(gpc_base + reg); 107 val |= BM_CPU_PGC_SW_PDN_PUP_REQ_CORE1_A7; 108 writel_relaxed(val, gpc_base + reg); 109 110 ret = readl_relaxed_poll_timeout_atomic(gpc_base + reg, pup, 111 !(pup & BM_CPU_PGC_SW_PDN_PUP_REQ_CORE1_A7), 112 5, 1000000); 113 if (ret < 0) { 114 pr_err("i.MX7D: CORE1_A7 power up timeout\n"); 115 val &= ~BM_CPU_PGC_SW_PDN_PUP_REQ_CORE1_A7; 116 writel_relaxed(val, gpc_base + reg); 117 } 118 119 imx_gpcv2_set_m_core_pgc(false, GPC_PGC_C1); 120 } 121 122 void imx_enable_cpu(int cpu, bool enable) 123 { 124 u32 mask, val; 125 126 cpu = cpu_logical_map(cpu); 127 spin_lock(&scr_lock); 128 if (gpr_v2) { 129 if (enable) 130 imx_gpcv2_set_core1_pdn_pup_by_software(false); 131 132 mask = 1 << (BP_SRC_A7RCR1_A7_CORE1_ENABLE + cpu - 1); 133 val = readl_relaxed(src_base + SRC_A7RCR1); 134 val = enable ? val | mask : val & ~mask; 135 writel_relaxed(val, src_base + SRC_A7RCR1); 136 } else { 137 mask = 1 << (BP_SRC_SCR_CORE1_ENABLE + cpu - 1); 138 val = readl_relaxed(src_base + SRC_SCR); 139 val = enable ? val | mask : val & ~mask; 140 val |= 1 << (BP_SRC_SCR_CORE1_RST + cpu - 1); 141 writel_relaxed(val, src_base + SRC_SCR); 142 } 143 spin_unlock(&scr_lock); 144 } 145 146 void imx_set_cpu_jump(int cpu, void *jump_addr) 147 { 148 cpu = cpu_logical_map(cpu); 149 writel_relaxed(__pa_symbol(jump_addr), 150 src_base + SRC_GPR1(gpr_v2) + cpu * 8); 151 } 152 153 u32 imx_get_cpu_arg(int cpu) 154 { 155 cpu = cpu_logical_map(cpu); 156 return readl_relaxed(src_base + SRC_GPR1(gpr_v2) + cpu * 8 + 4); 157 } 158 159 void imx_set_cpu_arg(int cpu, u32 arg) 160 { 161 cpu = cpu_logical_map(cpu); 162 writel_relaxed(arg, src_base + SRC_GPR1(gpr_v2) + cpu * 8 + 4); 163 } 164 165 void __init imx_src_init(void) 166 { 167 struct device_node *np; 168 u32 val; 169 170 np = of_find_compatible_node(NULL, NULL, "fsl,imx51-src"); 171 if (!np) 172 return; 173 src_base = of_iomap(np, 0); 174 WARN_ON(!src_base); 175 176 /* 177 * force warm reset sources to generate cold reset 178 * for a more reliable restart 179 */ 180 spin_lock(&scr_lock); 181 val = readl_relaxed(src_base + SRC_SCR); 182 val &= ~(1 << BP_SRC_SCR_WARM_RESET_ENABLE); 183 writel_relaxed(val, src_base + SRC_SCR); 184 spin_unlock(&scr_lock); 185 } 186 187 void __init imx7_src_init(void) 188 { 189 struct device_node *np; 190 191 gpr_v2 = true; 192 193 np = of_find_compatible_node(NULL, NULL, "fsl,imx7d-src"); 194 if (!np) 195 return; 196 197 src_base = of_iomap(np, 0); 198 if (!src_base) 199 return; 200 201 np = of_find_compatible_node(NULL, NULL, "fsl,imx7d-gpc"); 202 if (!np) 203 return; 204 205 gpc_base = of_iomap(np, 0); 206 if (!gpc_base) 207 return; 208 } 209 210 static const struct of_device_id imx_src_dt_ids[] = { 211 { .compatible = "fsl,imx51-src" }, 212 { /* sentinel */ } 213 }; 214 215 static int imx_src_probe(struct platform_device *pdev) 216 { 217 struct reset_controller_dev *rcdev; 218 219 rcdev = devm_kzalloc(&pdev->dev, sizeof(*rcdev), GFP_KERNEL); 220 if (!rcdev) 221 return -ENOMEM; 222 223 rcdev->ops = &imx_src_ops; 224 rcdev->dev = &pdev->dev; 225 rcdev->of_node = pdev->dev.of_node; 226 rcdev->nr_resets = ARRAY_SIZE(sw_reset_bits); 227 228 return devm_reset_controller_register(&pdev->dev, rcdev); 229 } 230 231 static struct platform_driver imx_src_driver = { 232 .driver = { 233 .name = "imx-src", 234 .of_match_table = imx_src_dt_ids, 235 }, 236 .probe = imx_src_probe, 237 }; 238 builtin_platform_driver(imx_src_driver); 239
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.