diff options
author | Heiko Stübner <heiko@sntech.de> | 2014-07-02 19:59:39 -0400 |
---|---|---|
committer | Mike Turquette <mturquette@linaro.org> | 2014-07-13 15:17:07 -0400 |
commit | 85fa0c7f8d05eb6baf2c122e85d45d928df0992b (patch) | |
tree | a0617813aaf643e6b80578632bfa58efdc044611 | |
parent | 90c590254051f511299538c158e12fdad41ce163 (diff) |
clk: rockchip: add reset controller
All Rockchip SoCs at least down to the ARM9-based RK28xx include the reset-
controller for SoC peripherals in their clock controller.
While the older SoCs (ARM9 and Cortex-A8) use a regular scheme to change
register values, the Cortex-A9 SoCs use a hiword-mask making locking unecessary.
To be compatible with both schemes the reset controller takes a flag to
decide which scheme to use, similar to the other HIWORD_MASK flags used in the
clock framework.
Signed-off-by: Heiko Stuebner <heiko@sntech.de>
Acked-By: Max Schwarz <max.schwarz@online.de>
Tested-By: Max Schwarz <max.schwarz@online.de>
Signed-off-by: Mike Turquette <mturquette@linaro.org>
-rw-r--r-- | drivers/clk/rockchip/Makefile | 1 | ||||
-rw-r--r-- | drivers/clk/rockchip/clk.h | 14 | ||||
-rw-r--r-- | drivers/clk/rockchip/softrst.c | 118 |
3 files changed, 133 insertions, 0 deletions
diff --git a/drivers/clk/rockchip/Makefile b/drivers/clk/rockchip/Makefile index 2cb916496040..85f8a551fc1a 100644 --- a/drivers/clk/rockchip/Makefile +++ b/drivers/clk/rockchip/Makefile | |||
@@ -5,3 +5,4 @@ | |||
5 | obj-y += clk-rockchip.o | 5 | obj-y += clk-rockchip.o |
6 | obj-y += clk.o | 6 | obj-y += clk.o |
7 | obj-y += clk-pll.o | 7 | obj-y += clk-pll.o |
8 | obj-$(CONFIG_RESET_CONTROLLER) += softrst.o | ||
diff --git a/drivers/clk/rockchip/clk.h b/drivers/clk/rockchip/clk.h index fb7ce851d4a0..32c334d7fc87 100644 --- a/drivers/clk/rockchip/clk.h +++ b/drivers/clk/rockchip/clk.h | |||
@@ -321,4 +321,18 @@ void rockchip_clk_register_branches(struct rockchip_clk_branch *clk_list, | |||
321 | void rockchip_clk_register_plls(struct rockchip_pll_clock *pll_list, | 321 | void rockchip_clk_register_plls(struct rockchip_pll_clock *pll_list, |
322 | unsigned int nr_pll, int grf_lock_offset); | 322 | unsigned int nr_pll, int grf_lock_offset); |
323 | 323 | ||
324 | #define ROCKCHIP_SOFTRST_HIWORD_MASK BIT(0) | ||
325 | |||
326 | #ifdef CONFIG_RESET_CONTROLLER | ||
327 | void rockchip_register_softrst(struct device_node *np, | ||
328 | unsigned int num_regs, | ||
329 | void __iomem *base, u8 flags); | ||
330 | #else | ||
331 | static inline void rockchip_register_softrst(struct device_node *np, | ||
332 | unsigned int num_regs, | ||
333 | void __iomem *base, u8 flags) | ||
334 | { | ||
335 | } | ||
336 | #endif | ||
337 | |||
324 | #endif | 338 | #endif |
diff --git a/drivers/clk/rockchip/softrst.c b/drivers/clk/rockchip/softrst.c new file mode 100644 index 000000000000..552f7bb15bc5 --- /dev/null +++ b/drivers/clk/rockchip/softrst.c | |||
@@ -0,0 +1,118 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2014 MundoReader S.L. | ||
3 | * Author: Heiko Stuebner <heiko@sntech.de> | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation; either version 2 of the License, or | ||
8 | * (at your option) any later version. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | */ | ||
15 | |||
16 | #include <linux/slab.h> | ||
17 | #include <linux/io.h> | ||
18 | #include <linux/reset-controller.h> | ||
19 | #include <linux/spinlock.h> | ||
20 | #include "clk.h" | ||
21 | |||
22 | struct rockchip_softrst { | ||
23 | struct reset_controller_dev rcdev; | ||
24 | void __iomem *reg_base; | ||
25 | int num_regs; | ||
26 | int num_per_reg; | ||
27 | u8 flags; | ||
28 | spinlock_t lock; | ||
29 | }; | ||
30 | |||
31 | static int rockchip_softrst_assert(struct reset_controller_dev *rcdev, | ||
32 | unsigned long id) | ||
33 | { | ||
34 | struct rockchip_softrst *softrst = container_of(rcdev, | ||
35 | struct rockchip_softrst, | ||
36 | rcdev); | ||
37 | int bank = id / softrst->num_per_reg; | ||
38 | int offset = id % softrst->num_per_reg; | ||
39 | |||
40 | if (softrst->flags & ROCKCHIP_SOFTRST_HIWORD_MASK) { | ||
41 | writel(BIT(offset) | (BIT(offset) << 16), | ||
42 | softrst->reg_base + (bank * 4)); | ||
43 | } else { | ||
44 | unsigned long flags; | ||
45 | u32 reg; | ||
46 | |||
47 | spin_lock_irqsave(&softrst->lock, flags); | ||
48 | |||
49 | reg = readl(softrst->reg_base + (bank * 4)); | ||
50 | writel(reg | BIT(offset), softrst->reg_base + (bank * 4)); | ||
51 | |||
52 | spin_unlock_irqrestore(&softrst->lock, flags); | ||
53 | } | ||
54 | |||
55 | return 0; | ||
56 | } | ||
57 | |||
58 | static int rockchip_softrst_deassert(struct reset_controller_dev *rcdev, | ||
59 | unsigned long id) | ||
60 | { | ||
61 | struct rockchip_softrst *softrst = container_of(rcdev, | ||
62 | struct rockchip_softrst, | ||
63 | rcdev); | ||
64 | int bank = id / softrst->num_per_reg; | ||
65 | int offset = id % softrst->num_per_reg; | ||
66 | |||
67 | if (softrst->flags & ROCKCHIP_SOFTRST_HIWORD_MASK) { | ||
68 | writel((BIT(offset) << 16), softrst->reg_base + (bank * 4)); | ||
69 | } else { | ||
70 | unsigned long flags; | ||
71 | u32 reg; | ||
72 | |||
73 | spin_lock_irqsave(&softrst->lock, flags); | ||
74 | |||
75 | reg = readl(softrst->reg_base + (bank * 4)); | ||
76 | writel(reg & ~BIT(offset), softrst->reg_base + (bank * 4)); | ||
77 | |||
78 | spin_unlock_irqrestore(&softrst->lock, flags); | ||
79 | } | ||
80 | |||
81 | return 0; | ||
82 | } | ||
83 | |||
84 | static struct reset_control_ops rockchip_softrst_ops = { | ||
85 | .assert = rockchip_softrst_assert, | ||
86 | .deassert = rockchip_softrst_deassert, | ||
87 | }; | ||
88 | |||
89 | void __init rockchip_register_softrst(struct device_node *np, | ||
90 | unsigned int num_regs, | ||
91 | void __iomem *base, u8 flags) | ||
92 | { | ||
93 | struct rockchip_softrst *softrst; | ||
94 | int ret; | ||
95 | |||
96 | softrst = kzalloc(sizeof(*softrst), GFP_KERNEL); | ||
97 | if (!softrst) | ||
98 | return; | ||
99 | |||
100 | spin_lock_init(&softrst->lock); | ||
101 | |||
102 | softrst->reg_base = base; | ||
103 | softrst->flags = flags; | ||
104 | softrst->num_regs = num_regs; | ||
105 | softrst->num_per_reg = (flags & ROCKCHIP_SOFTRST_HIWORD_MASK) ? 16 | ||
106 | : 32; | ||
107 | |||
108 | softrst->rcdev.owner = THIS_MODULE; | ||
109 | softrst->rcdev.nr_resets = num_regs * softrst->num_per_reg; | ||
110 | softrst->rcdev.ops = &rockchip_softrst_ops; | ||
111 | softrst->rcdev.of_node = np; | ||
112 | ret = reset_controller_register(&softrst->rcdev); | ||
113 | if (ret) { | ||
114 | pr_err("%s: could not register reset controller, %d\n", | ||
115 | __func__, ret); | ||
116 | kfree(softrst); | ||
117 | } | ||
118 | }; | ||