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