Skip to content

Commit

Permalink
ARM i.MX6q: Add GPU, VPU, IPU, and OpenVG resets to System Reset Cont…
Browse files Browse the repository at this point in the history
…roller (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>
  • Loading branch information
Philipp Zabel authored and Shawn Guo committed Apr 12, 2013
1 parent 7006ba2 commit 02985b9
Show file tree
Hide file tree
Showing 3 changed files with 115 additions and 0 deletions.
49 changes: 49 additions & 0 deletions Documentation/devicetree/bindings/reset/fsl,imx-src.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
Freescale i.MX System Reset Controller
======================================

Please also refer to reset.txt in this directory for common reset
controller binding usage.

Required properties:
- compatible: Should be "fsl,<chip>-src"
- reg: should be register base and length as documented in the
datasheet
- interrupts: Should contain SRC interrupt and CPU WDOG interrupt,
in this order.
- #reset-cells: 1, see below

example:

src: src@020d8000 {
compatible = "fsl,imx6q-src";
reg = <0x020d8000 0x4000>;
interrupts = <0 91 0x04 0 96 0x04>;
#reset-cells = <1>;
};

Specifying reset lines connected to IP modules
==============================================

The system reset controller can be used to reset the GPU, VPU,
IPU, and OpenVG IP modules on i.MX5 and i.MX6 ICs. Those device
nodes should specify the reset line on the SRC in their resets
property, containing a phandle to the SRC device node and a
RESET_INDEX specifying which module to reset, as described in
reset.txt

example:

ipu1: ipu@02400000 {
resets = <&src 2>;
};
ipu2: ipu@02800000 {
resets = <&src 4>;
};

The following RESET_INDEX values are valid for i.MX5:
GPU_RESET 0
VPU_RESET 1
IPU1_RESET 2
OPEN_VG_RESET 3
The following additional RESET_INDEX value is valid for i.MX6:
IPU2_RESET 4
1 change: 1 addition & 0 deletions arch/arm/mach-imx/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ config HAVE_IMX_MMDC

config HAVE_IMX_SRC
def_bool y if SMP
select ARCH_HAS_RESET_CONTROLLER

config IMX_HAVE_IOMUX_V1
bool
Expand Down
65 changes: 65 additions & 0 deletions arch/arm/mach-imx/src.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,26 +14,84 @@
#include <linux/io.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/reset-controller.h>
#include <linux/smp.h>
#include <asm/smp_plat.h>

#define SRC_SCR 0x000
#define SRC_GPR1 0x020
#define BP_SRC_SCR_WARM_RESET_ENABLE 0
#define BP_SRC_SCR_SW_GPU_RST 1
#define BP_SRC_SCR_SW_VPU_RST 2
#define BP_SRC_SCR_SW_IPU1_RST 3
#define BP_SRC_SCR_SW_OPEN_VG_RST 4
#define BP_SRC_SCR_SW_IPU2_RST 12
#define BP_SRC_SCR_CORE1_RST 14
#define BP_SRC_SCR_CORE1_ENABLE 22

static void __iomem *src_base;
static DEFINE_SPINLOCK(scr_lock);

static const int sw_reset_bits[5] = {
BP_SRC_SCR_SW_GPU_RST,
BP_SRC_SCR_SW_VPU_RST,
BP_SRC_SCR_SW_IPU1_RST,
BP_SRC_SCR_SW_OPEN_VG_RST,
BP_SRC_SCR_SW_IPU2_RST
};

static int imx_src_reset_module(struct reset_controller_dev *rcdev,
unsigned long sw_reset_idx)
{
unsigned long timeout;
unsigned long flags;
int bit;
u32 val;

if (!src_base)
return -ENODEV;

if (sw_reset_idx >= ARRAY_SIZE(sw_reset_bits))
return -EINVAL;

bit = 1 << sw_reset_bits[sw_reset_idx];

spin_lock_irqsave(&scr_lock, flags);
val = readl_relaxed(src_base + SRC_SCR);
val |= bit;
writel_relaxed(val, src_base + SRC_SCR);
spin_unlock_irqrestore(&scr_lock, flags);

timeout = jiffies + msecs_to_jiffies(1000);
while (readl(src_base + SRC_SCR) & bit) {
if (time_after(jiffies, timeout))
return -ETIME;
cpu_relax();
}

return 0;
}

static struct reset_control_ops imx_src_ops = {
.reset = imx_src_reset_module,
};

static struct reset_controller_dev imx_reset_controller = {
.ops = &imx_src_ops,
.nr_resets = ARRAY_SIZE(sw_reset_bits),
};

void imx_enable_cpu(int cpu, bool enable)
{
u32 mask, val;

cpu = cpu_logical_map(cpu);
mask = 1 << (BP_SRC_SCR_CORE1_ENABLE + cpu - 1);
spin_lock(&scr_lock);
val = readl_relaxed(src_base + SRC_SCR);
val = enable ? val | mask : val & ~mask;
writel_relaxed(val, src_base + SRC_SCR);
spin_unlock(&scr_lock);
}

void imx_set_cpu_jump(int cpu, void *jump_addr)
Expand All @@ -60,9 +118,11 @@ void imx_src_prepare_restart(void)
u32 val;

/* clear enable bits of secondary cores */
spin_lock(&scr_lock);
val = readl_relaxed(src_base + SRC_SCR);
val &= ~(0x7 << BP_SRC_SCR_CORE1_ENABLE);
writel_relaxed(val, src_base + SRC_SCR);
spin_unlock(&scr_lock);

/* clear persistent entry register of primary core */
writel_relaxed(0, src_base + SRC_GPR1);
Expand All @@ -77,11 +137,16 @@ void __init imx_src_init(void)
src_base = of_iomap(np, 0);
WARN_ON(!src_base);

imx_reset_controller.of_node = np;
reset_controller_register(&imx_reset_controller);

/*
* force warm reset sources to generate cold reset
* for a more reliable restart
*/
spin_lock(&scr_lock);
val = readl_relaxed(src_base + SRC_SCR);
val &= ~(1 << BP_SRC_SCR_WARM_RESET_ENABLE);
writel_relaxed(val, src_base + SRC_SCR);
spin_unlock(&scr_lock);
}

0 comments on commit 02985b9

Please sign in to comment.