1 /* 2 * Copyright 2011 Freescale Semiconductor, Inc. 3 * Copyright 2011 Linaro Ltd. 4 * 5 * The code contained herein is licensed under the GNU General Public 6 * License. You may obtain a copy of the GNU General Public License 7 * Version 2 or later at the following locations: 8 * 9 * http://www.opensource.org/licenses/gpl-license.html 10 * http://www.gnu.org/copyleft/gpl.html 11 */ 12 13 #include <linux/init.h> 14 #include <linux/io.h> 15 #include <linux/of.h> 16 #include <linux/of_address.h> 17 #include <linux/reset-controller.h> 18 #include <linux/smp.h> 19 #include <asm/smp_plat.h> 20 #include "common.h" 21 22 #define SRC_SCR 0x000 23 #define SRC_GPR1 0x020 24 #define BP_SRC_SCR_WARM_RESET_ENABLE 0 25 #define BP_SRC_SCR_SW_GPU_RST 1 26 #define BP_SRC_SCR_SW_VPU_RST 2 27 #define BP_SRC_SCR_SW_IPU1_RST 3 28 #define BP_SRC_SCR_SW_OPEN_VG_RST 4 29 #define BP_SRC_SCR_SW_IPU2_RST 12 30 #define BP_SRC_SCR_CORE1_RST 14 31 #define BP_SRC_SCR_CORE1_ENABLE 22 32 33 static void __iomem *src_base; 34 static DEFINE_SPINLOCK(scr_lock); 35 36 static const int sw_reset_bits[5] = { 37 BP_SRC_SCR_SW_GPU_RST, 38 BP_SRC_SCR_SW_VPU_RST, 39 BP_SRC_SCR_SW_IPU1_RST, 40 BP_SRC_SCR_SW_OPEN_VG_RST, 41 BP_SRC_SCR_SW_IPU2_RST 42 }; 43 44 static int imx_src_reset_module(struct reset_controller_dev *rcdev, 45 unsigned long sw_reset_idx) 46 { 47 unsigned long timeout; 48 unsigned long flags; 49 int bit; 50 u32 val; 51 52 if (!src_base) 53 return -ENODEV; 54 55 if (sw_reset_idx >= ARRAY_SIZE(sw_reset_bits)) 56 return -EINVAL; 57 58 bit = 1 << sw_reset_bits[sw_reset_idx]; 59 60 spin_lock_irqsave(&scr_lock, flags); 61 val = readl_relaxed(src_base + SRC_SCR); 62 val |= bit; 63 writel_relaxed(val, src_base + SRC_SCR); 64 spin_unlock_irqrestore(&scr_lock, flags); 65 66 timeout = jiffies + msecs_to_jiffies(1000); 67 while (readl(src_base + SRC_SCR) & bit) { 68 if (time_after(jiffies, timeout)) 69 return -ETIME; 70 cpu_relax(); 71 } 72 73 return 0; 74 } 75 76 static struct reset_control_ops imx_src_ops = { 77 .reset = imx_src_reset_module, 78 }; 79 80 static struct reset_controller_dev imx_reset_controller = { 81 .ops = &imx_src_ops, 82 .nr_resets = ARRAY_SIZE(sw_reset_bits), 83 }; 84 85 void imx_enable_cpu(int cpu, bool enable) 86 { 87 u32 mask, val; 88 89 cpu = cpu_logical_map(cpu); 90 mask = 1 << (BP_SRC_SCR_CORE1_ENABLE + cpu - 1); 91 spin_lock(&scr_lock); 92 val = readl_relaxed(src_base + SRC_SCR); 93 val = enable ? val | mask : val & ~mask; 94 val |= 1 << (BP_SRC_SCR_CORE1_RST + cpu - 1); 95 writel_relaxed(val, src_base + SRC_SCR); 96 spin_unlock(&scr_lock); 97 } 98 99 void imx_set_cpu_jump(int cpu, void *jump_addr) 100 { 101 cpu = cpu_logical_map(cpu); 102 writel_relaxed(virt_to_phys(jump_addr), 103 src_base + SRC_GPR1 + cpu * 8); 104 } 105 106 u32 imx_get_cpu_arg(int cpu) 107 { 108 cpu = cpu_logical_map(cpu); 109 return readl_relaxed(src_base + SRC_GPR1 + cpu * 8 + 4); 110 } 111 112 void imx_set_cpu_arg(int cpu, u32 arg) 113 { 114 cpu = cpu_logical_map(cpu); 115 writel_relaxed(arg, src_base + SRC_GPR1 + cpu * 8 + 4); 116 } 117 118 void imx_src_prepare_restart(void) 119 { 120 u32 val; 121 122 /* clear enable bits of secondary cores */ 123 spin_lock(&scr_lock); 124 val = readl_relaxed(src_base + SRC_SCR); 125 val &= ~(0x7 << BP_SRC_SCR_CORE1_ENABLE); 126 writel_relaxed(val, src_base + SRC_SCR); 127 spin_unlock(&scr_lock); 128 129 /* clear persistent entry register of primary core */ 130 writel_relaxed(0, src_base + SRC_GPR1); 131 } 132 133 void __init imx_src_init(void) 134 { 135 struct device_node *np; 136 u32 val; 137 138 np = of_find_compatible_node(NULL, NULL, "fsl,imx51-src"); 139 if (!np) 140 return; 141 src_base = of_iomap(np, 0); 142 WARN_ON(!src_base); 143 144 imx_reset_controller.of_node = np; 145 if (IS_ENABLED(CONFIG_RESET_CONTROLLER)) 146 reset_controller_register(&imx_reset_controller); 147 148 /* 149 * force warm reset sources to generate cold reset 150 * for a more reliable restart 151 */ 152 spin_lock(&scr_lock); 153 val = readl_relaxed(src_base + SRC_SCR); 154 val &= ~(1 << BP_SRC_SCR_WARM_RESET_ENABLE); 155 writel_relaxed(val, src_base + SRC_SCR); 156 spin_unlock(&scr_lock); 157 } 158