summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlexandre Belloni <alexandre.belloni@bootlin.com>2019-04-02 08:50:50 -0400
committerStephen Boyd <sboyd@kernel.org>2019-04-25 15:34:03 -0400
commitcb4f4949b1c76f29ca804d6ecd879a2e84c88afc (patch)
treee825c68b3d6352b24ebd15a07cfe2fcbc039b478
parent5c16ffa795b7bcdbd73d5983482c5c0fe5566c06 (diff)
clk: at91: allow configuring peripheral PCR layout
The PCR register actually changed layout for each SoC. By chance, this didn't have impact on sama5d[2-4] support but since sama5d3, PID is seven bits wide and sama5d4 and sama5d2 don't have DIV. For the DT backward compatibility, keep the layout as is. Signed-off-by: Alexandre Belloni <alexandre.belloni@bootlin.com> Signed-off-by: Stephen Boyd <sboyd@kernel.org>
-rw-r--r--drivers/clk/at91/at91sam9x5.c9
-rw-r--r--drivers/clk/at91/clk-peripheral.c46
-rw-r--r--drivers/clk/at91/dt-compat.c9
-rw-r--r--drivers/clk/at91/pmc.h12
-rw-r--r--drivers/clk/at91/sama5d2.c9
-rw-r--r--drivers/clk/at91/sama5d4.c8
-rw-r--r--include/linux/clk/at91_pmc.h3
7 files changed, 71 insertions, 25 deletions
diff --git a/drivers/clk/at91/at91sam9x5.c b/drivers/clk/at91/at91sam9x5.c
index 3487e03d4bc6..f5cfcbd85f10 100644
--- a/drivers/clk/at91/at91sam9x5.c
+++ b/drivers/clk/at91/at91sam9x5.c
@@ -49,6 +49,13 @@ static const struct {
49 { .n = "pck1", .p = "prog1", .id = 9 }, 49 { .n = "pck1", .p = "prog1", .id = 9 },
50}; 50};
51 51
52static const struct clk_pcr_layout at91sam9x5_pcr_layout = {
53 .offset = 0x10c,
54 .cmd = BIT(12),
55 .pid_mask = GENMASK(5, 0),
56 .div_mask = GENMASK(17, 16),
57};
58
52struct pck { 59struct pck {
53 char *n; 60 char *n;
54 u8 id; 61 u8 id;
@@ -242,6 +249,7 @@ static void __init at91sam9x5_pmc_setup(struct device_node *np,
242 249
243 for (i = 0; i < ARRAY_SIZE(at91sam9x5_periphck); i++) { 250 for (i = 0; i < ARRAY_SIZE(at91sam9x5_periphck); i++) {
244 hw = at91_clk_register_sam9x5_peripheral(regmap, &pmc_pcr_lock, 251 hw = at91_clk_register_sam9x5_peripheral(regmap, &pmc_pcr_lock,
252 &at91sam9x5_pcr_layout,
245 at91sam9x5_periphck[i].n, 253 at91sam9x5_periphck[i].n,
246 "masterck", 254 "masterck",
247 at91sam9x5_periphck[i].id, 255 at91sam9x5_periphck[i].id,
@@ -254,6 +262,7 @@ static void __init at91sam9x5_pmc_setup(struct device_node *np,
254 262
255 for (i = 0; extra_pcks[i].id; i++) { 263 for (i = 0; extra_pcks[i].id; i++) {
256 hw = at91_clk_register_sam9x5_peripheral(regmap, &pmc_pcr_lock, 264 hw = at91_clk_register_sam9x5_peripheral(regmap, &pmc_pcr_lock,
265 &at91sam9x5_pcr_layout,
257 extra_pcks[i].n, 266 extra_pcks[i].n,
258 "masterck", 267 "masterck",
259 extra_pcks[i].id, 268 extra_pcks[i].id,
diff --git a/drivers/clk/at91/clk-peripheral.c b/drivers/clk/at91/clk-peripheral.c
index 65c1defa78e4..6b7748b9588a 100644
--- a/drivers/clk/at91/clk-peripheral.c
+++ b/drivers/clk/at91/clk-peripheral.c
@@ -8,6 +8,7 @@
8 * 8 *
9 */ 9 */
10 10
11#include <linux/bitops.h>
11#include <linux/clk-provider.h> 12#include <linux/clk-provider.h>
12#include <linux/clkdev.h> 13#include <linux/clkdev.h>
13#include <linux/clk/at91_pmc.h> 14#include <linux/clk/at91_pmc.h>
@@ -23,9 +24,6 @@ DEFINE_SPINLOCK(pmc_pcr_lock);
23#define PERIPHERAL_ID_MAX 31 24#define PERIPHERAL_ID_MAX 31
24#define PERIPHERAL_MASK(id) (1 << ((id) & PERIPHERAL_ID_MAX)) 25#define PERIPHERAL_MASK(id) (1 << ((id) & PERIPHERAL_ID_MAX))
25 26
26#define PERIPHERAL_RSHIFT_MASK 0x3
27#define PERIPHERAL_RSHIFT(val) (((val) >> 16) & PERIPHERAL_RSHIFT_MASK)
28
29#define PERIPHERAL_MAX_SHIFT 3 27#define PERIPHERAL_MAX_SHIFT 3
30 28
31struct clk_peripheral { 29struct clk_peripheral {
@@ -43,6 +41,7 @@ struct clk_sam9x5_peripheral {
43 spinlock_t *lock; 41 spinlock_t *lock;
44 u32 id; 42 u32 id;
45 u32 div; 43 u32 div;
44 const struct clk_pcr_layout *layout;
46 bool auto_div; 45 bool auto_div;
47}; 46};
48 47
@@ -169,13 +168,13 @@ static int clk_sam9x5_peripheral_enable(struct clk_hw *hw)
169 return 0; 168 return 0;
170 169
171 spin_lock_irqsave(periph->lock, flags); 170 spin_lock_irqsave(periph->lock, flags);
172 regmap_write(periph->regmap, AT91_PMC_PCR, 171 regmap_write(periph->regmap, periph->layout->offset,
173 (periph->id & AT91_PMC_PCR_PID_MASK)); 172 (periph->id & periph->layout->pid_mask));
174 regmap_update_bits(periph->regmap, AT91_PMC_PCR, 173 regmap_update_bits(periph->regmap, periph->layout->offset,
175 AT91_PMC_PCR_DIV_MASK | AT91_PMC_PCR_CMD | 174 periph->layout->div_mask | periph->layout->cmd |
176 AT91_PMC_PCR_EN, 175 AT91_PMC_PCR_EN,
177 AT91_PMC_PCR_DIV(periph->div) | 176 field_prep(periph->layout->div_mask, periph->div) |
178 AT91_PMC_PCR_CMD | 177 periph->layout->cmd |
179 AT91_PMC_PCR_EN); 178 AT91_PMC_PCR_EN);
180 spin_unlock_irqrestore(periph->lock, flags); 179 spin_unlock_irqrestore(periph->lock, flags);
181 180
@@ -191,11 +190,11 @@ static void clk_sam9x5_peripheral_disable(struct clk_hw *hw)
191 return; 190 return;
192 191
193 spin_lock_irqsave(periph->lock, flags); 192 spin_lock_irqsave(periph->lock, flags);
194 regmap_write(periph->regmap, AT91_PMC_PCR, 193 regmap_write(periph->regmap, periph->layout->offset,
195 (periph->id & AT91_PMC_PCR_PID_MASK)); 194 (periph->id & periph->layout->pid_mask));
196 regmap_update_bits(periph->regmap, AT91_PMC_PCR, 195 regmap_update_bits(periph->regmap, periph->layout->offset,
197 AT91_PMC_PCR_EN | AT91_PMC_PCR_CMD, 196 AT91_PMC_PCR_EN | periph->layout->cmd,
198 AT91_PMC_PCR_CMD); 197 periph->layout->cmd);
199 spin_unlock_irqrestore(periph->lock, flags); 198 spin_unlock_irqrestore(periph->lock, flags);
200} 199}
201 200
@@ -209,9 +208,9 @@ static int clk_sam9x5_peripheral_is_enabled(struct clk_hw *hw)
209 return 1; 208 return 1;
210 209
211 spin_lock_irqsave(periph->lock, flags); 210 spin_lock_irqsave(periph->lock, flags);
212 regmap_write(periph->regmap, AT91_PMC_PCR, 211 regmap_write(periph->regmap, periph->layout->offset,
213 (periph->id & AT91_PMC_PCR_PID_MASK)); 212 (periph->id & periph->layout->pid_mask));
214 regmap_read(periph->regmap, AT91_PMC_PCR, &status); 213 regmap_read(periph->regmap, periph->layout->offset, &status);
215 spin_unlock_irqrestore(periph->lock, flags); 214 spin_unlock_irqrestore(periph->lock, flags);
216 215
217 return status & AT91_PMC_PCR_EN ? 1 : 0; 216 return status & AT91_PMC_PCR_EN ? 1 : 0;
@@ -229,13 +228,13 @@ clk_sam9x5_peripheral_recalc_rate(struct clk_hw *hw,
229 return parent_rate; 228 return parent_rate;
230 229
231 spin_lock_irqsave(periph->lock, flags); 230 spin_lock_irqsave(periph->lock, flags);
232 regmap_write(periph->regmap, AT91_PMC_PCR, 231 regmap_write(periph->regmap, periph->layout->offset,
233 (periph->id & AT91_PMC_PCR_PID_MASK)); 232 (periph->id & periph->layout->pid_mask));
234 regmap_read(periph->regmap, AT91_PMC_PCR, &status); 233 regmap_read(periph->regmap, periph->layout->offset, &status);
235 spin_unlock_irqrestore(periph->lock, flags); 234 spin_unlock_irqrestore(periph->lock, flags);
236 235
237 if (status & AT91_PMC_PCR_EN) { 236 if (status & AT91_PMC_PCR_EN) {
238 periph->div = PERIPHERAL_RSHIFT(status); 237 periph->div = field_get(periph->layout->div_mask, status);
239 periph->auto_div = false; 238 periph->auto_div = false;
240 } else { 239 } else {
241 clk_sam9x5_peripheral_autodiv(periph); 240 clk_sam9x5_peripheral_autodiv(periph);
@@ -328,6 +327,7 @@ static const struct clk_ops sam9x5_peripheral_ops = {
328 327
329struct clk_hw * __init 328struct clk_hw * __init
330at91_clk_register_sam9x5_peripheral(struct regmap *regmap, spinlock_t *lock, 329at91_clk_register_sam9x5_peripheral(struct regmap *regmap, spinlock_t *lock,
330 const struct clk_pcr_layout *layout,
331 const char *name, const char *parent_name, 331 const char *name, const char *parent_name,
332 u32 id, const struct clk_range *range) 332 u32 id, const struct clk_range *range)
333{ 333{
@@ -354,7 +354,9 @@ at91_clk_register_sam9x5_peripheral(struct regmap *regmap, spinlock_t *lock,
354 periph->div = 0; 354 periph->div = 0;
355 periph->regmap = regmap; 355 periph->regmap = regmap;
356 periph->lock = lock; 356 periph->lock = lock;
357 periph->auto_div = true; 357 if (layout->div_mask)
358 periph->auto_div = true;
359 periph->layout = layout;
358 periph->range = *range; 360 periph->range = *range;
359 361
360 hw = &periph->hw; 362 hw = &periph->hw;
diff --git a/drivers/clk/at91/dt-compat.c b/drivers/clk/at91/dt-compat.c
index b95bb4e2a927..aa09072f36db 100644
--- a/drivers/clk/at91/dt-compat.c
+++ b/drivers/clk/at91/dt-compat.c
@@ -93,6 +93,14 @@ CLK_OF_DECLARE(of_sama5d2_clk_audio_pll_pmc_setup,
93 of_sama5d2_clk_audio_pll_pmc_setup); 93 of_sama5d2_clk_audio_pll_pmc_setup);
94#endif /* CONFIG_HAVE_AT91_AUDIO_PLL */ 94#endif /* CONFIG_HAVE_AT91_AUDIO_PLL */
95 95
96static const struct clk_pcr_layout dt_pcr_layout = {
97 .offset = 0x10c,
98 .cmd = BIT(12),
99 .pid_mask = GENMASK(5, 0),
100 .div_mask = GENMASK(17, 16),
101 .gckcss_mask = GENMASK(10, 8),
102};
103
96#ifdef CONFIG_HAVE_AT91_GENERATED_CLK 104#ifdef CONFIG_HAVE_AT91_GENERATED_CLK
97#define GENERATED_SOURCE_MAX 6 105#define GENERATED_SOURCE_MAX 6
98 106
@@ -448,6 +456,7 @@ of_at91_clk_periph_setup(struct device_node *np, u8 type)
448 456
449 hw = at91_clk_register_sam9x5_peripheral(regmap, 457 hw = at91_clk_register_sam9x5_peripheral(regmap,
450 &pmc_pcr_lock, 458 &pmc_pcr_lock,
459 &dt_pcr_layout,
451 name, 460 name,
452 parent_name, 461 parent_name,
453 id, &range); 462 id, &range);
diff --git a/drivers/clk/at91/pmc.h b/drivers/clk/at91/pmc.h
index 672a79bda88c..616c04588093 100644
--- a/drivers/clk/at91/pmc.h
+++ b/drivers/clk/at91/pmc.h
@@ -80,6 +80,17 @@ extern const struct clk_programmable_layout at91rm9200_programmable_layout;
80extern const struct clk_programmable_layout at91sam9g45_programmable_layout; 80extern const struct clk_programmable_layout at91sam9g45_programmable_layout;
81extern const struct clk_programmable_layout at91sam9x5_programmable_layout; 81extern const struct clk_programmable_layout at91sam9x5_programmable_layout;
82 82
83struct clk_pcr_layout {
84 u32 offset;
85 u32 cmd;
86 u32 div_mask;
87 u32 gckcss_mask;
88 u32 pid_mask;
89};
90
91#define field_get(_mask, _reg) (((_reg) & (_mask)) >> (ffs(_mask) - 1))
92#define field_prep(_mask, _val) (((_val) << (ffs(_mask) - 1)) & (_mask))
93
83#define ndck(a, s) (a[s - 1].id + 1) 94#define ndck(a, s) (a[s - 1].id + 1)
84#define nck(a) (a[ARRAY_SIZE(a) - 1].id + 1) 95#define nck(a) (a[ARRAY_SIZE(a) - 1].id + 1)
85struct pmc_data *pmc_data_allocate(unsigned int ncore, unsigned int nsystem, 96struct pmc_data *pmc_data_allocate(unsigned int ncore, unsigned int nsystem,
@@ -143,6 +154,7 @@ at91_clk_register_peripheral(struct regmap *regmap, const char *name,
143 const char *parent_name, u32 id); 154 const char *parent_name, u32 id);
144struct clk_hw * __init 155struct clk_hw * __init
145at91_clk_register_sam9x5_peripheral(struct regmap *regmap, spinlock_t *lock, 156at91_clk_register_sam9x5_peripheral(struct regmap *regmap, spinlock_t *lock,
157 const struct clk_pcr_layout *layout,
146 const char *name, const char *parent_name, 158 const char *name, const char *parent_name,
147 u32 id, const struct clk_range *range); 159 u32 id, const struct clk_range *range);
148 160
diff --git a/drivers/clk/at91/sama5d2.c b/drivers/clk/at91/sama5d2.c
index 1f70cb164b06..9d128bd60fee 100644
--- a/drivers/clk/at91/sama5d2.c
+++ b/drivers/clk/at91/sama5d2.c
@@ -28,6 +28,13 @@ static const struct clk_pll_characteristics plla_characteristics = {
28 .out = plla_out, 28 .out = plla_out,
29}; 29};
30 30
31static const struct clk_pcr_layout sama5d2_pcr_layout = {
32 .offset = 0x10c,
33 .cmd = BIT(12),
34 .gckcss_mask = GENMASK(10, 8),
35 .pid_mask = GENMASK(6, 0),
36};
37
31static const struct { 38static const struct {
32 char *n; 39 char *n;
33 char *p; 40 char *p;
@@ -266,6 +273,7 @@ static void __init sama5d2_pmc_setup(struct device_node *np)
266 273
267 for (i = 0; i < ARRAY_SIZE(sama5d2_periphck); i++) { 274 for (i = 0; i < ARRAY_SIZE(sama5d2_periphck); i++) {
268 hw = at91_clk_register_sam9x5_peripheral(regmap, &pmc_pcr_lock, 275 hw = at91_clk_register_sam9x5_peripheral(regmap, &pmc_pcr_lock,
276 &sama5d2_pcr_layout,
269 sama5d2_periphck[i].n, 277 sama5d2_periphck[i].n,
270 "masterck", 278 "masterck",
271 sama5d2_periphck[i].id, 279 sama5d2_periphck[i].id,
@@ -278,6 +286,7 @@ static void __init sama5d2_pmc_setup(struct device_node *np)
278 286
279 for (i = 0; i < ARRAY_SIZE(sama5d2_periph32ck); i++) { 287 for (i = 0; i < ARRAY_SIZE(sama5d2_periph32ck); i++) {
280 hw = at91_clk_register_sam9x5_peripheral(regmap, &pmc_pcr_lock, 288 hw = at91_clk_register_sam9x5_peripheral(regmap, &pmc_pcr_lock,
289 &sama5d2_pcr_layout,
281 sama5d2_periph32ck[i].n, 290 sama5d2_periph32ck[i].n,
282 "h32mxck", 291 "h32mxck",
283 sama5d2_periph32ck[i].id, 292 sama5d2_periph32ck[i].id,
diff --git a/drivers/clk/at91/sama5d4.c b/drivers/clk/at91/sama5d4.c
index b645a9d59cdb..840edca77821 100644
--- a/drivers/clk/at91/sama5d4.c
+++ b/drivers/clk/at91/sama5d4.c
@@ -28,6 +28,12 @@ static const struct clk_pll_characteristics plla_characteristics = {
28 .out = plla_out, 28 .out = plla_out,
29}; 29};
30 30
31static const struct clk_pcr_layout sama5d4_pcr_layout = {
32 .offset = 0x10c,
33 .cmd = BIT(12),
34 .pid_mask = GENMASK(6, 0),
35};
36
31static const struct { 37static const struct {
32 char *n; 38 char *n;
33 char *p; 39 char *p;
@@ -232,6 +238,7 @@ static void __init sama5d4_pmc_setup(struct device_node *np)
232 238
233 for (i = 0; i < ARRAY_SIZE(sama5d4_periphck); i++) { 239 for (i = 0; i < ARRAY_SIZE(sama5d4_periphck); i++) {
234 hw = at91_clk_register_sam9x5_peripheral(regmap, &pmc_pcr_lock, 240 hw = at91_clk_register_sam9x5_peripheral(regmap, &pmc_pcr_lock,
241 &sama5d4_pcr_layout,
235 sama5d4_periphck[i].n, 242 sama5d4_periphck[i].n,
236 "masterck", 243 "masterck",
237 sama5d4_periphck[i].id, 244 sama5d4_periphck[i].id,
@@ -244,6 +251,7 @@ static void __init sama5d4_pmc_setup(struct device_node *np)
244 251
245 for (i = 0; i < ARRAY_SIZE(sama5d4_periph32ck); i++) { 252 for (i = 0; i < ARRAY_SIZE(sama5d4_periph32ck); i++) {
246 hw = at91_clk_register_sam9x5_peripheral(regmap, &pmc_pcr_lock, 253 hw = at91_clk_register_sam9x5_peripheral(regmap, &pmc_pcr_lock,
254 &sama5d4_pcr_layout,
247 sama5d4_periph32ck[i].n, 255 sama5d4_periph32ck[i].n,
248 "h32mxck", 256 "h32mxck",
249 sama5d4_periph32ck[i].id, 257 sama5d4_periph32ck[i].id,
diff --git a/include/linux/clk/at91_pmc.h b/include/linux/clk/at91_pmc.h
index 931ab05f771d..b97b8dcbffe6 100644
--- a/include/linux/clk/at91_pmc.h
+++ b/include/linux/clk/at91_pmc.h
@@ -191,9 +191,6 @@
191#define AT91_PMC_PCR_GCKCSS_MASK (0x7 << AT91_PMC_PCR_GCKCSS_OFFSET) 191#define AT91_PMC_PCR_GCKCSS_MASK (0x7 << AT91_PMC_PCR_GCKCSS_OFFSET)
192#define AT91_PMC_PCR_GCKCSS(n) ((n) << AT91_PMC_PCR_GCKCSS_OFFSET) /* GCK Clock Source Selection */ 192#define AT91_PMC_PCR_GCKCSS(n) ((n) << AT91_PMC_PCR_GCKCSS_OFFSET) /* GCK Clock Source Selection */
193#define AT91_PMC_PCR_CMD (0x1 << 12) /* Command (read=0, write=1) */ 193#define AT91_PMC_PCR_CMD (0x1 << 12) /* Command (read=0, write=1) */
194#define AT91_PMC_PCR_DIV_OFFSET 16
195#define AT91_PMC_PCR_DIV_MASK (0x3 << AT91_PMC_PCR_DIV_OFFSET)
196#define AT91_PMC_PCR_DIV(n) ((n) << AT91_PMC_PCR_DIV_OFFSET) /* Divisor Value */
197#define AT91_PMC_PCR_GCKDIV_OFFSET 20 194#define AT91_PMC_PCR_GCKDIV_OFFSET 20
198#define AT91_PMC_PCR_GCKDIV_MASK (0xff << AT91_PMC_PCR_GCKDIV_OFFSET) 195#define AT91_PMC_PCR_GCKDIV_MASK (0xff << AT91_PMC_PCR_GCKDIV_OFFSET)
199#define AT91_PMC_PCR_GCKDIV(n) ((n) << AT91_PMC_PCR_GCKDIV_OFFSET) /* Generated Clock Divisor Value */ 196#define AT91_PMC_PCR_GCKDIV(n) ((n) << AT91_PMC_PCR_GCKDIV_OFFSET) /* Generated Clock Divisor Value */