1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * Clock driver for Keystone 2 based devices |
4 | * |
5 | * Copyright (C) 2013 Texas Instruments. |
6 | * Murali Karicheri <m-karicheri2@ti.com> |
7 | * Santosh Shilimkar <santosh.shilimkar@ti.com> |
8 | */ |
9 | #include <linux/clk-provider.h> |
10 | #include <linux/err.h> |
11 | #include <linux/io.h> |
12 | #include <linux/slab.h> |
13 | #include <linux/of_address.h> |
14 | #include <linux/of.h> |
15 | #include <linux/module.h> |
16 | |
17 | /* PSC register offsets */ |
18 | #define PTCMD 0x120 |
19 | #define PTSTAT 0x128 |
20 | #define PDSTAT 0x200 |
21 | #define PDCTL 0x300 |
22 | #define MDSTAT 0x800 |
23 | #define MDCTL 0xa00 |
24 | |
25 | /* PSC module states */ |
26 | #define PSC_STATE_SWRSTDISABLE 0 |
27 | #define PSC_STATE_SYNCRST 1 |
28 | #define PSC_STATE_DISABLE 2 |
29 | #define PSC_STATE_ENABLE 3 |
30 | |
31 | #define MDSTAT_STATE_MASK 0x3f |
32 | #define MDSTAT_MCKOUT BIT(12) |
33 | #define PDSTAT_STATE_MASK 0x1f |
34 | #define MDCTL_FORCE BIT(31) |
35 | #define MDCTL_LRESET BIT(8) |
36 | #define PDCTL_NEXT BIT(0) |
37 | |
38 | /* Maximum timeout to bail out state transition for module */ |
39 | #define STATE_TRANS_MAX_COUNT 0xffff |
40 | |
41 | static void __iomem *domain_transition_base; |
42 | |
43 | /** |
44 | * struct clk_psc_data - PSC data |
45 | * @control_base: Base address for a PSC control |
46 | * @domain_base: Base address for a PSC domain |
47 | * @domain_id: PSC domain id number |
48 | */ |
49 | struct clk_psc_data { |
50 | void __iomem *control_base; |
51 | void __iomem *domain_base; |
52 | u32 domain_id; |
53 | }; |
54 | |
55 | /** |
56 | * struct clk_psc - PSC clock structure |
57 | * @hw: clk_hw for the psc |
58 | * @psc_data: PSC driver specific data |
59 | * @lock: Spinlock used by the driver |
60 | */ |
61 | struct clk_psc { |
62 | struct clk_hw hw; |
63 | struct clk_psc_data *psc_data; |
64 | spinlock_t *lock; |
65 | }; |
66 | |
67 | static DEFINE_SPINLOCK(psc_lock); |
68 | |
69 | #define to_clk_psc(_hw) container_of(_hw, struct clk_psc, hw) |
70 | |
71 | static void psc_config(void __iomem *control_base, void __iomem *domain_base, |
72 | u32 next_state, u32 domain_id) |
73 | { |
74 | u32 ptcmd, pdstat, pdctl, mdstat, mdctl, ptstat; |
75 | u32 count = STATE_TRANS_MAX_COUNT; |
76 | |
77 | mdctl = readl(addr: control_base + MDCTL); |
78 | mdctl &= ~MDSTAT_STATE_MASK; |
79 | mdctl |= next_state; |
80 | /* For disable, we always put the module in local reset */ |
81 | if (next_state == PSC_STATE_DISABLE) |
82 | mdctl &= ~MDCTL_LRESET; |
83 | writel(val: mdctl, addr: control_base + MDCTL); |
84 | |
85 | pdstat = readl(addr: domain_base + PDSTAT); |
86 | if (!(pdstat & PDSTAT_STATE_MASK)) { |
87 | pdctl = readl(addr: domain_base + PDCTL); |
88 | pdctl |= PDCTL_NEXT; |
89 | writel(val: pdctl, addr: domain_base + PDCTL); |
90 | } |
91 | |
92 | ptcmd = 1 << domain_id; |
93 | writel(val: ptcmd, addr: domain_transition_base + PTCMD); |
94 | do { |
95 | ptstat = readl(addr: domain_transition_base + PTSTAT); |
96 | } while (((ptstat >> domain_id) & 1) && count--); |
97 | |
98 | count = STATE_TRANS_MAX_COUNT; |
99 | do { |
100 | mdstat = readl(addr: control_base + MDSTAT); |
101 | } while (!((mdstat & MDSTAT_STATE_MASK) == next_state) && count--); |
102 | } |
103 | |
104 | static int keystone_clk_is_enabled(struct clk_hw *hw) |
105 | { |
106 | struct clk_psc *psc = to_clk_psc(hw); |
107 | struct clk_psc_data *data = psc->psc_data; |
108 | u32 mdstat = readl(addr: data->control_base + MDSTAT); |
109 | |
110 | return (mdstat & MDSTAT_MCKOUT) ? 1 : 0; |
111 | } |
112 | |
113 | static int keystone_clk_enable(struct clk_hw *hw) |
114 | { |
115 | struct clk_psc *psc = to_clk_psc(hw); |
116 | struct clk_psc_data *data = psc->psc_data; |
117 | unsigned long flags = 0; |
118 | |
119 | if (psc->lock) |
120 | spin_lock_irqsave(psc->lock, flags); |
121 | |
122 | psc_config(control_base: data->control_base, domain_base: data->domain_base, |
123 | PSC_STATE_ENABLE, domain_id: data->domain_id); |
124 | |
125 | if (psc->lock) |
126 | spin_unlock_irqrestore(lock: psc->lock, flags); |
127 | |
128 | return 0; |
129 | } |
130 | |
131 | static void keystone_clk_disable(struct clk_hw *hw) |
132 | { |
133 | struct clk_psc *psc = to_clk_psc(hw); |
134 | struct clk_psc_data *data = psc->psc_data; |
135 | unsigned long flags = 0; |
136 | |
137 | if (psc->lock) |
138 | spin_lock_irqsave(psc->lock, flags); |
139 | |
140 | psc_config(control_base: data->control_base, domain_base: data->domain_base, |
141 | PSC_STATE_DISABLE, domain_id: data->domain_id); |
142 | |
143 | if (psc->lock) |
144 | spin_unlock_irqrestore(lock: psc->lock, flags); |
145 | } |
146 | |
147 | static const struct clk_ops clk_psc_ops = { |
148 | .enable = keystone_clk_enable, |
149 | .disable = keystone_clk_disable, |
150 | .is_enabled = keystone_clk_is_enabled, |
151 | }; |
152 | |
153 | /** |
154 | * clk_register_psc - register psc clock |
155 | * @dev: device that is registering this clock |
156 | * @name: name of this clock |
157 | * @parent_name: name of clock's parent |
158 | * @psc_data: platform data to configure this clock |
159 | * @lock: spinlock used by this clock |
160 | */ |
161 | static struct clk *clk_register_psc(struct device *dev, |
162 | const char *name, |
163 | const char *parent_name, |
164 | struct clk_psc_data *psc_data, |
165 | spinlock_t *lock) |
166 | { |
167 | struct clk_init_data init; |
168 | struct clk_psc *psc; |
169 | struct clk *clk; |
170 | |
171 | psc = kzalloc(size: sizeof(*psc), GFP_KERNEL); |
172 | if (!psc) |
173 | return ERR_PTR(error: -ENOMEM); |
174 | |
175 | init.name = name; |
176 | init.ops = &clk_psc_ops; |
177 | init.flags = 0; |
178 | init.parent_names = (parent_name ? &parent_name : NULL); |
179 | init.num_parents = (parent_name ? 1 : 0); |
180 | |
181 | psc->psc_data = psc_data; |
182 | psc->lock = lock; |
183 | psc->hw.init = &init; |
184 | |
185 | clk = clk_register(NULL, hw: &psc->hw); |
186 | if (IS_ERR(ptr: clk)) |
187 | kfree(objp: psc); |
188 | |
189 | return clk; |
190 | } |
191 | |
192 | /** |
193 | * of_psc_clk_init - initialize psc clock through DT |
194 | * @node: device tree node for this clock |
195 | * @lock: spinlock used by this clock |
196 | */ |
197 | static void __init of_psc_clk_init(struct device_node *node, spinlock_t *lock) |
198 | { |
199 | const char *clk_name = node->name; |
200 | const char *parent_name; |
201 | struct clk_psc_data *data; |
202 | struct clk *clk; |
203 | int i; |
204 | |
205 | data = kzalloc(size: sizeof(*data), GFP_KERNEL); |
206 | if (!data) { |
207 | pr_err("%s: Out of memory\n" , __func__); |
208 | return; |
209 | } |
210 | |
211 | i = of_property_match_string(np: node, propname: "reg-names" , string: "control" ); |
212 | data->control_base = of_iomap(node, index: i); |
213 | if (!data->control_base) { |
214 | pr_err("%s: control ioremap failed\n" , __func__); |
215 | goto out; |
216 | } |
217 | |
218 | i = of_property_match_string(np: node, propname: "reg-names" , string: "domain" ); |
219 | data->domain_base = of_iomap(node, index: i); |
220 | if (!data->domain_base) { |
221 | pr_err("%s: domain ioremap failed\n" , __func__); |
222 | goto unmap_ctrl; |
223 | } |
224 | |
225 | of_property_read_u32(np: node, propname: "domain-id" , out_value: &data->domain_id); |
226 | |
227 | /* Domain transition registers at fixed address space of domain_id 0 */ |
228 | if (!domain_transition_base && !data->domain_id) |
229 | domain_transition_base = data->domain_base; |
230 | |
231 | of_property_read_string(np: node, propname: "clock-output-names" , out_string: &clk_name); |
232 | parent_name = of_clk_get_parent_name(np: node, index: 0); |
233 | if (!parent_name) { |
234 | pr_err("%s: Parent clock not found\n" , __func__); |
235 | goto unmap_domain; |
236 | } |
237 | |
238 | clk = clk_register_psc(NULL, name: clk_name, parent_name, psc_data: data, lock); |
239 | if (!IS_ERR(ptr: clk)) { |
240 | of_clk_add_provider(np: node, clk_src_get: of_clk_src_simple_get, data: clk); |
241 | return; |
242 | } |
243 | |
244 | pr_err("%s: error registering clk %pOFn\n" , __func__, node); |
245 | |
246 | unmap_domain: |
247 | iounmap(addr: data->domain_base); |
248 | unmap_ctrl: |
249 | iounmap(addr: data->control_base); |
250 | out: |
251 | kfree(objp: data); |
252 | return; |
253 | } |
254 | |
255 | /** |
256 | * of_keystone_psc_clk_init - initialize psc clock through DT |
257 | * @node: device tree node for this clock |
258 | */ |
259 | static void __init of_keystone_psc_clk_init(struct device_node *node) |
260 | { |
261 | of_psc_clk_init(node, lock: &psc_lock); |
262 | } |
263 | CLK_OF_DECLARE(keystone_gate_clk, "ti,keystone,psc-clock" , |
264 | of_keystone_psc_clk_init); |
265 | |
266 | MODULE_LICENSE("GPL" ); |
267 | MODULE_DESCRIPTION("Clock driver for Keystone 2 based devices" ); |
268 | MODULE_AUTHOR("Murali Karicheri <m-karicheri2@ti.com>" ); |
269 | MODULE_AUTHOR("Santosh Shilimkar <santosh.shilimkar@ti.com>" ); |
270 | |