GNU Linux-libre 4.19.268-gnu1
[releases.git] / drivers / clk / berlin / berlin2-div.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (c) 2014 Marvell Technology Group Ltd.
4  *
5  * Alexandre Belloni <alexandre.belloni@free-electrons.com>
6  * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
7  */
8 #include <linux/bitops.h>
9 #include <linux/clk-provider.h>
10 #include <linux/of.h>
11 #include <linux/of_address.h>
12 #include <linux/slab.h>
13 #include <linux/spinlock.h>
14
15 #include "berlin2-div.h"
16
17 /*
18  * Clock dividers in Berlin2 SoCs comprise a complex cell to select
19  * input pll and divider. The virtual structure as it is used in Marvell
20  * BSP code can be seen as:
21  *
22  *                      +---+
23  * pll0 --------------->| 0 |                   +---+
24  *           +---+      |(B)|--+--------------->| 0 |      +---+
25  * pll1.0 -->| 0 |  +-->| 1 |  |   +--------+   |(E)|----->| 0 |   +---+
26  * pll1.1 -->| 1 |  |   +---+  +-->|(C) 1:M |-->| 1 |      |(F)|-->|(G)|->
27  * ...    -->|(A)|--+          |   +--------+   +---+  +-->| 1 |   +---+
28  * ...    -->|   |             +-->|(D) 1:3 |----------+   +---+
29  * pll1.N -->| N |                 +---------
30  *           +---+
31  *
32  * (A) input pll clock mux controlled by               <PllSelect[1:n]>
33  * (B) input pll bypass mux controlled by              <PllSwitch>
34  * (C) programmable clock divider controlled by        <Select[1:n]>
35  * (D) constant div-by-3 clock divider
36  * (E) programmable clock divider bypass controlled by <Switch>
37  * (F) constant div-by-3 clock mux controlled by       <D3Switch>
38  * (G) clock gate controlled by                        <Enable>
39  *
40  * For whatever reason, above control signals come in two flavors:
41  * - single register dividers with all bits in one register
42  * - shared register dividers with bits spread over multiple registers
43  *   (including signals for the same cell spread over consecutive registers)
44  *
45  * Also, clock gate and pll mux is not available on every div cell, so
46  * we have to deal with those, too. We reuse common clock composite driver
47  * for it.
48  */
49
50 #define PLL_SELECT_MASK 0x7
51 #define DIV_SELECT_MASK 0x7
52
53 struct berlin2_div {
54         struct clk_hw hw;
55         void __iomem *base;
56         struct berlin2_div_map map;
57         spinlock_t *lock;
58 };
59
60 #define to_berlin2_div(hw) container_of(hw, struct berlin2_div, hw)
61
62 static u8 clk_div[] = { 1, 2, 4, 6, 8, 12, 1, 1 };
63
64 static int berlin2_div_is_enabled(struct clk_hw *hw)
65 {
66         struct berlin2_div *div = to_berlin2_div(hw);
67         struct berlin2_div_map *map = &div->map;
68         u32 reg;
69
70         if (div->lock)
71                 spin_lock(div->lock);
72
73         reg = readl_relaxed(div->base + map->gate_offs);
74         reg >>= map->gate_shift;
75
76         if (div->lock)
77                 spin_unlock(div->lock);
78
79         return (reg & 0x1);
80 }
81
82 static int berlin2_div_enable(struct clk_hw *hw)
83 {
84         struct berlin2_div *div = to_berlin2_div(hw);
85         struct berlin2_div_map *map = &div->map;
86         u32 reg;
87
88         if (div->lock)
89                 spin_lock(div->lock);
90
91         reg = readl_relaxed(div->base + map->gate_offs);
92         reg |= BIT(map->gate_shift);
93         writel_relaxed(reg, div->base + map->gate_offs);
94
95         if (div->lock)
96                 spin_unlock(div->lock);
97
98         return 0;
99 }
100
101 static void berlin2_div_disable(struct clk_hw *hw)
102 {
103         struct berlin2_div *div = to_berlin2_div(hw);
104         struct berlin2_div_map *map = &div->map;
105         u32 reg;
106
107         if (div->lock)
108                 spin_lock(div->lock);
109
110         reg = readl_relaxed(div->base + map->gate_offs);
111         reg &= ~BIT(map->gate_shift);
112         writel_relaxed(reg, div->base + map->gate_offs);
113
114         if (div->lock)
115                 spin_unlock(div->lock);
116 }
117
118 static int berlin2_div_set_parent(struct clk_hw *hw, u8 index)
119 {
120         struct berlin2_div *div = to_berlin2_div(hw);
121         struct berlin2_div_map *map = &div->map;
122         u32 reg;
123
124         if (div->lock)
125                 spin_lock(div->lock);
126
127         /* index == 0 is PLL_SWITCH */
128         reg = readl_relaxed(div->base + map->pll_switch_offs);
129         if (index == 0)
130                 reg &= ~BIT(map->pll_switch_shift);
131         else
132                 reg |= BIT(map->pll_switch_shift);
133         writel_relaxed(reg, div->base + map->pll_switch_offs);
134
135         /* index > 0 is PLL_SELECT */
136         if (index > 0) {
137                 reg = readl_relaxed(div->base + map->pll_select_offs);
138                 reg &= ~(PLL_SELECT_MASK << map->pll_select_shift);
139                 reg |= (index - 1) << map->pll_select_shift;
140                 writel_relaxed(reg, div->base + map->pll_select_offs);
141         }
142
143         if (div->lock)
144                 spin_unlock(div->lock);
145
146         return 0;
147 }
148
149 static u8 berlin2_div_get_parent(struct clk_hw *hw)
150 {
151         struct berlin2_div *div = to_berlin2_div(hw);
152         struct berlin2_div_map *map = &div->map;
153         u32 reg;
154         u8 index = 0;
155
156         if (div->lock)
157                 spin_lock(div->lock);
158
159         /* PLL_SWITCH == 0 is index 0 */
160         reg = readl_relaxed(div->base + map->pll_switch_offs);
161         reg &= BIT(map->pll_switch_shift);
162         if (reg) {
163                 reg = readl_relaxed(div->base + map->pll_select_offs);
164                 reg >>= map->pll_select_shift;
165                 reg &= PLL_SELECT_MASK;
166                 index = 1 + reg;
167         }
168
169         if (div->lock)
170                 spin_unlock(div->lock);
171
172         return index;
173 }
174
175 static unsigned long berlin2_div_recalc_rate(struct clk_hw *hw,
176                                              unsigned long parent_rate)
177 {
178         struct berlin2_div *div = to_berlin2_div(hw);
179         struct berlin2_div_map *map = &div->map;
180         u32 divsw, div3sw, divider = 1;
181
182         if (div->lock)
183                 spin_lock(div->lock);
184
185         divsw = readl_relaxed(div->base + map->div_switch_offs) &
186                 (1 << map->div_switch_shift);
187         div3sw = readl_relaxed(div->base + map->div3_switch_offs) &
188                 (1 << map->div3_switch_shift);
189
190         /* constant divide-by-3 (dominant) */
191         if (div3sw != 0) {
192                 divider = 3;
193         /* divider can be bypassed with DIV_SWITCH == 0 */
194         } else if (divsw == 0) {
195                 divider = 1;
196         /* clock divider determined by DIV_SELECT */
197         } else {
198                 u32 reg;
199                 reg = readl_relaxed(div->base + map->div_select_offs);
200                 reg >>= map->div_select_shift;
201                 reg &= DIV_SELECT_MASK;
202                 divider = clk_div[reg];
203         }
204
205         if (div->lock)
206                 spin_unlock(div->lock);
207
208         return parent_rate / divider;
209 }
210
211 static const struct clk_ops berlin2_div_rate_ops = {
212         .recalc_rate    = berlin2_div_recalc_rate,
213 };
214
215 static const struct clk_ops berlin2_div_gate_ops = {
216         .is_enabled     = berlin2_div_is_enabled,
217         .enable         = berlin2_div_enable,
218         .disable        = berlin2_div_disable,
219 };
220
221 static const struct clk_ops berlin2_div_mux_ops = {
222         .set_parent     = berlin2_div_set_parent,
223         .get_parent     = berlin2_div_get_parent,
224 };
225
226 struct clk_hw * __init
227 berlin2_div_register(const struct berlin2_div_map *map,
228                      void __iomem *base, const char *name, u8 div_flags,
229                      const char **parent_names, int num_parents,
230                      unsigned long flags, spinlock_t *lock)
231 {
232         const struct clk_ops *mux_ops = &berlin2_div_mux_ops;
233         const struct clk_ops *rate_ops = &berlin2_div_rate_ops;
234         const struct clk_ops *gate_ops = &berlin2_div_gate_ops;
235         struct berlin2_div *div;
236
237         div = kzalloc(sizeof(*div), GFP_KERNEL);
238         if (!div)
239                 return ERR_PTR(-ENOMEM);
240
241         /* copy div_map to allow __initconst */
242         memcpy(&div->map, map, sizeof(*map));
243         div->base = base;
244         div->lock = lock;
245
246         if ((div_flags & BERLIN2_DIV_HAS_GATE) == 0)
247                 gate_ops = NULL;
248         if ((div_flags & BERLIN2_DIV_HAS_MUX) == 0)
249                 mux_ops = NULL;
250
251         return clk_hw_register_composite(NULL, name, parent_names, num_parents,
252                                       &div->hw, mux_ops, &div->hw, rate_ops,
253                                       &div->hw, gate_ops, flags);
254 }