Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ARM i.MX6q: Add GPU, VPU, IPU, and OpenVG resets to System Reset Controller (SRC)

The SRC has auto-deasserting reset bits that control reset lines to
the GPU, VPU, IPU, and OpenVG IP modules. This patch adds a reset
controller that can be controlled by those devices using the
reset controller API.

Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
Reviewed-by: Stephen Warren <swarren@nvidia.com>
Reviewed-by: Marek Vasut <marex@denx.de>
Reviewed-by: Pavel Machek <pavel@ucw.cz>
Signed-off-by: Shawn Guo <shawn.guo@linaro.org>

authored by

Philipp Zabel and committed by
Shawn Guo
02985b94 7006ba24

+115
+49
Documentation/devicetree/bindings/reset/fsl,imx-src.txt
··· 1 + Freescale i.MX System Reset Controller 2 + ====================================== 3 + 4 + Please also refer to reset.txt in this directory for common reset 5 + controller binding usage. 6 + 7 + Required properties: 8 + - compatible: Should be "fsl,<chip>-src" 9 + - reg: should be register base and length as documented in the 10 + datasheet 11 + - interrupts: Should contain SRC interrupt and CPU WDOG interrupt, 12 + in this order. 13 + - #reset-cells: 1, see below 14 + 15 + example: 16 + 17 + src: src@020d8000 { 18 + compatible = "fsl,imx6q-src"; 19 + reg = <0x020d8000 0x4000>; 20 + interrupts = <0 91 0x04 0 96 0x04>; 21 + #reset-cells = <1>; 22 + }; 23 + 24 + Specifying reset lines connected to IP modules 25 + ============================================== 26 + 27 + The system reset controller can be used to reset the GPU, VPU, 28 + IPU, and OpenVG IP modules on i.MX5 and i.MX6 ICs. Those device 29 + nodes should specify the reset line on the SRC in their resets 30 + property, containing a phandle to the SRC device node and a 31 + RESET_INDEX specifying which module to reset, as described in 32 + reset.txt 33 + 34 + example: 35 + 36 + ipu1: ipu@02400000 { 37 + resets = <&src 2>; 38 + }; 39 + ipu2: ipu@02800000 { 40 + resets = <&src 4>; 41 + }; 42 + 43 + The following RESET_INDEX values are valid for i.MX5: 44 + GPU_RESET 0 45 + VPU_RESET 1 46 + IPU1_RESET 2 47 + OPEN_VG_RESET 3 48 + The following additional RESET_INDEX value is valid for i.MX6: 49 + IPU2_RESET 4
+1
arch/arm/mach-imx/Kconfig
··· 76 76 77 77 config HAVE_IMX_SRC 78 78 def_bool y if SMP 79 + select ARCH_HAS_RESET_CONTROLLER 79 80 80 81 config IMX_HAVE_IOMUX_V1 81 82 bool
+65
arch/arm/mach-imx/src.c
··· 14 14 #include <linux/io.h> 15 15 #include <linux/of.h> 16 16 #include <linux/of_address.h> 17 + #include <linux/reset-controller.h> 17 18 #include <linux/smp.h> 18 19 #include <asm/smp_plat.h> 19 20 20 21 #define SRC_SCR 0x000 21 22 #define SRC_GPR1 0x020 22 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 23 29 #define BP_SRC_SCR_CORE1_RST 14 24 30 #define BP_SRC_SCR_CORE1_ENABLE 22 25 31 26 32 static void __iomem *src_base; 33 + static DEFINE_SPINLOCK(scr_lock); 34 + 35 + static const int sw_reset_bits[5] = { 36 + BP_SRC_SCR_SW_GPU_RST, 37 + BP_SRC_SCR_SW_VPU_RST, 38 + BP_SRC_SCR_SW_IPU1_RST, 39 + BP_SRC_SCR_SW_OPEN_VG_RST, 40 + BP_SRC_SCR_SW_IPU2_RST 41 + }; 42 + 43 + static int imx_src_reset_module(struct reset_controller_dev *rcdev, 44 + unsigned long sw_reset_idx) 45 + { 46 + unsigned long timeout; 47 + unsigned long flags; 48 + int bit; 49 + u32 val; 50 + 51 + if (!src_base) 52 + return -ENODEV; 53 + 54 + if (sw_reset_idx >= ARRAY_SIZE(sw_reset_bits)) 55 + return -EINVAL; 56 + 57 + bit = 1 << sw_reset_bits[sw_reset_idx]; 58 + 59 + spin_lock_irqsave(&scr_lock, flags); 60 + val = readl_relaxed(src_base + SRC_SCR); 61 + val |= bit; 62 + writel_relaxed(val, src_base + SRC_SCR); 63 + spin_unlock_irqrestore(&scr_lock, flags); 64 + 65 + timeout = jiffies + msecs_to_jiffies(1000); 66 + while (readl(src_base + SRC_SCR) & bit) { 67 + if (time_after(jiffies, timeout)) 68 + return -ETIME; 69 + cpu_relax(); 70 + } 71 + 72 + return 0; 73 + } 74 + 75 + static struct reset_control_ops imx_src_ops = { 76 + .reset = imx_src_reset_module, 77 + }; 78 + 79 + static struct reset_controller_dev imx_reset_controller = { 80 + .ops = &imx_src_ops, 81 + .nr_resets = ARRAY_SIZE(sw_reset_bits), 82 + }; 27 83 28 84 void imx_enable_cpu(int cpu, bool enable) 29 85 { ··· 87 31 88 32 cpu = cpu_logical_map(cpu); 89 33 mask = 1 << (BP_SRC_SCR_CORE1_ENABLE + cpu - 1); 34 + spin_lock(&scr_lock); 90 35 val = readl_relaxed(src_base + SRC_SCR); 91 36 val = enable ? val | mask : val & ~mask; 92 37 writel_relaxed(val, src_base + SRC_SCR); 38 + spin_unlock(&scr_lock); 93 39 } 94 40 95 41 void imx_set_cpu_jump(int cpu, void *jump_addr) ··· 118 60 u32 val; 119 61 120 62 /* clear enable bits of secondary cores */ 63 + spin_lock(&scr_lock); 121 64 val = readl_relaxed(src_base + SRC_SCR); 122 65 val &= ~(0x7 << BP_SRC_SCR_CORE1_ENABLE); 123 66 writel_relaxed(val, src_base + SRC_SCR); 67 + spin_unlock(&scr_lock); 124 68 125 69 /* clear persistent entry register of primary core */ 126 70 writel_relaxed(0, src_base + SRC_GPR1); ··· 137 77 src_base = of_iomap(np, 0); 138 78 WARN_ON(!src_base); 139 79 80 + imx_reset_controller.of_node = np; 81 + reset_controller_register(&imx_reset_controller); 82 + 140 83 /* 141 84 * force warm reset sources to generate cold reset 142 85 * for a more reliable restart 143 86 */ 87 + spin_lock(&scr_lock); 144 88 val = readl_relaxed(src_base + SRC_SCR); 145 89 val &= ~(1 << BP_SRC_SCR_WARM_RESET_ENABLE); 146 90 writel_relaxed(val, src_base + SRC_SCR); 91 + spin_unlock(&scr_lock); 147 92 }