@@ -43,14 +43,34 @@ struct exynos_cpuclk;
43
43
typedef int (* exynos_rate_change_fn_t )(struct clk_notifier_data * ndata ,
44
44
struct exynos_cpuclk * cpuclk );
45
45
46
+ /**
47
+ * struct exynos_cpuclk_regs - Register offsets for CPU related clocks
48
+ * @mux_sel: offset of CPU MUX_SEL register (for selecting MUX clock parent)
49
+ * @mux_stat: offset of CPU MUX_STAT register (for checking MUX clock status)
50
+ * @div_cpu0: offset of CPU DIV0 register (for modifying divider values)
51
+ * @div_cpu1: offset of CPU DIV1 register (for modifying divider values)
52
+ * @div_stat_cpu0: offset of CPU DIV0_STAT register (for checking DIV status)
53
+ * @div_stat_cpu1: offset of CPU DIV1_STAT register (for checking DIV status)
54
+ */
55
+ struct exynos_cpuclk_regs {
56
+ u32 mux_sel ;
57
+ u32 mux_stat ;
58
+ u32 div_cpu0 ;
59
+ u32 div_cpu1 ;
60
+ u32 div_stat_cpu0 ;
61
+ u32 div_stat_cpu1 ;
62
+ };
63
+
46
64
/**
47
65
* struct exynos_cpuclk_chip - Chip specific data for CPU clock
66
+ * @regs: register offsets for CPU related clocks
48
67
* @pre_rate_cb: callback to run before CPU clock rate change
49
68
* @post_rate_cb: callback to run after CPU clock rate change
50
69
*/
51
70
struct exynos_cpuclk_chip {
52
- exynos_rate_change_fn_t pre_rate_cb ;
53
- exynos_rate_change_fn_t post_rate_cb ;
71
+ const struct exynos_cpuclk_regs * regs ;
72
+ exynos_rate_change_fn_t pre_rate_cb ;
73
+ exynos_rate_change_fn_t post_rate_cb ;
54
74
};
55
75
56
76
/**
@@ -130,43 +150,48 @@ static void wait_until_mux_stable(void __iomem *mux_reg, u32 mux_pos,
130
150
pr_err ("%s: re-parenting mux timed-out\n" , __func__ );
131
151
}
132
152
133
- /* ---- Exynos 3/4/5 -------------------------------------------------------- */
134
-
135
- #define E4210_SRC_CPU 0x200
136
- #define E4210_STAT_CPU 0x400
137
- #define E4210_DIV_CPU0 0x500
138
- #define E4210_DIV_CPU1 0x504
139
- #define E4210_DIV_STAT_CPU0 0x600
140
- #define E4210_DIV_STAT_CPU1 0x604
141
-
142
- #define E4210_DIV0_RATIO0_MASK GENMASK(2, 0)
143
- #define E4210_DIV1_HPM_MASK GENMASK(6, 4)
144
- #define E4210_DIV1_COPY_MASK GENMASK(2, 0)
145
- #define E4210_MUX_HPM_MASK BIT(20)
146
- #define E4210_DIV0_ATB_SHIFT 16
147
- #define E4210_DIV0_ATB_MASK (DIV_MASK << E4210_DIV0_ATB_SHIFT)
148
-
149
153
/*
150
154
* Helper function to set the 'safe' dividers for the CPU clock. The parameters
151
155
* div and mask contain the divider value and the register bit mask of the
152
156
* dividers to be programmed.
153
157
*/
154
- static void exynos_set_safe_div (void __iomem * base , unsigned long div ,
158
+ static void exynos_set_safe_div (struct exynos_cpuclk * cpuclk , unsigned long div ,
155
159
unsigned long mask )
156
160
{
161
+ const struct exynos_cpuclk_regs * const regs = cpuclk -> chip -> regs ;
162
+ void __iomem * base = cpuclk -> base ;
157
163
unsigned long div0 ;
158
164
159
- div0 = readl (base + E4210_DIV_CPU0 );
165
+ div0 = readl (base + regs -> div_cpu0 );
160
166
div0 = (div0 & ~mask ) | (div & mask );
161
- writel (div0 , base + E4210_DIV_CPU0 );
162
- wait_until_divider_stable (base + E4210_DIV_STAT_CPU0 , mask );
167
+ writel (div0 , base + regs -> div_cpu0 );
168
+ wait_until_divider_stable (base + regs -> div_stat_cpu0 , mask );
163
169
}
164
170
171
+ /* ---- Exynos 3/4/5 -------------------------------------------------------- */
172
+
173
+ #define E4210_DIV0_RATIO0_MASK GENMASK(2, 0)
174
+ #define E4210_DIV1_HPM_MASK GENMASK(6, 4)
175
+ #define E4210_DIV1_COPY_MASK GENMASK(2, 0)
176
+ #define E4210_MUX_HPM_MASK BIT(20)
177
+ #define E4210_DIV0_ATB_SHIFT 16
178
+ #define E4210_DIV0_ATB_MASK (DIV_MASK << E4210_DIV0_ATB_SHIFT)
179
+
180
+ static const struct exynos_cpuclk_regs e4210_cpuclk_regs = {
181
+ .mux_sel = 0x200 ,
182
+ .mux_stat = 0x400 ,
183
+ .div_cpu0 = 0x500 ,
184
+ .div_cpu1 = 0x504 ,
185
+ .div_stat_cpu0 = 0x600 ,
186
+ .div_stat_cpu1 = 0x604 ,
187
+ };
188
+
165
189
/* handler for pre-rate change notification from parent clock */
166
190
static int exynos_cpuclk_pre_rate_change (struct clk_notifier_data * ndata ,
167
191
struct exynos_cpuclk * cpuclk )
168
192
{
169
193
const struct exynos_cpuclk_cfg_data * cfg_data = cpuclk -> cfg ;
194
+ const struct exynos_cpuclk_regs * const regs = cpuclk -> chip -> regs ;
170
195
void __iomem * base = cpuclk -> base ;
171
196
unsigned long alt_prate = clk_hw_get_rate (cpuclk -> alt_parent );
172
197
unsigned long div0 , div1 = 0 , mux_reg ;
@@ -189,8 +214,8 @@ static int exynos_cpuclk_pre_rate_change(struct clk_notifier_data *ndata,
189
214
div0 = cfg_data -> div0 ;
190
215
if (cpuclk -> flags & CLK_CPU_HAS_DIV1 ) {
191
216
div1 = cfg_data -> div1 ;
192
- if (readl (base + E4210_SRC_CPU ) & E4210_MUX_HPM_MASK )
193
- div1 = readl (base + E4210_DIV_CPU1 ) &
217
+ if (readl (base + regs -> mux_sel ) & E4210_MUX_HPM_MASK )
218
+ div1 = readl (base + regs -> div_cpu1 ) &
194
219
(E4210_DIV1_HPM_MASK | E4210_DIV1_COPY_MASK );
195
220
}
196
221
@@ -217,22 +242,22 @@ static int exynos_cpuclk_pre_rate_change(struct clk_notifier_data *ndata,
217
242
alt_div |= E4210_DIV0_ATB_MASK ;
218
243
alt_div_mask |= E4210_DIV0_ATB_MASK ;
219
244
}
220
- exynos_set_safe_div (base , alt_div , alt_div_mask );
245
+ exynos_set_safe_div (cpuclk , alt_div , alt_div_mask );
221
246
div0 |= alt_div ;
222
247
}
223
248
224
249
/* select sclk_mpll as the alternate parent */
225
- mux_reg = readl (base + E4210_SRC_CPU );
226
- writel (mux_reg | (1 << 16 ), base + E4210_SRC_CPU );
227
- wait_until_mux_stable (base + E4210_STAT_CPU , 16 , 2 );
250
+ mux_reg = readl (base + regs -> mux_sel );
251
+ writel (mux_reg | (1 << 16 ), base + regs -> mux_sel );
252
+ wait_until_mux_stable (base + regs -> mux_stat , 16 , 2 );
228
253
229
254
/* alternate parent is active now. set the dividers */
230
- writel (div0 , base + E4210_DIV_CPU0 );
231
- wait_until_divider_stable (base + E4210_DIV_STAT_CPU0 , DIV_MASK_ALL );
255
+ writel (div0 , base + regs -> div_cpu0 );
256
+ wait_until_divider_stable (base + regs -> div_stat_cpu0 , DIV_MASK_ALL );
232
257
233
258
if (cpuclk -> flags & CLK_CPU_HAS_DIV1 ) {
234
- writel (div1 , base + E4210_DIV_CPU1 );
235
- wait_until_divider_stable (base + E4210_DIV_STAT_CPU1 ,
259
+ writel (div1 , base + regs -> div_cpu1 );
260
+ wait_until_divider_stable (base + regs -> div_stat_cpu1 ,
236
261
DIV_MASK_ALL );
237
262
}
238
263
@@ -245,6 +270,7 @@ static int exynos_cpuclk_post_rate_change(struct clk_notifier_data *ndata,
245
270
struct exynos_cpuclk * cpuclk )
246
271
{
247
272
const struct exynos_cpuclk_cfg_data * cfg_data = cpuclk -> cfg ;
273
+ const struct exynos_cpuclk_regs * const regs = cpuclk -> chip -> regs ;
248
274
void __iomem * base = cpuclk -> base ;
249
275
unsigned long div = 0 , div_mask = DIV_MASK ;
250
276
unsigned long mux_reg ;
@@ -262,50 +288,37 @@ static int exynos_cpuclk_post_rate_change(struct clk_notifier_data *ndata,
262
288
spin_lock_irqsave (cpuclk -> lock , flags );
263
289
264
290
/* select mout_apll as the alternate parent */
265
- mux_reg = readl (base + E4210_SRC_CPU );
266
- writel (mux_reg & ~(1 << 16 ), base + E4210_SRC_CPU );
267
- wait_until_mux_stable (base + E4210_STAT_CPU , 16 , 1 );
291
+ mux_reg = readl (base + regs -> mux_sel );
292
+ writel (mux_reg & ~(1 << 16 ), base + regs -> mux_sel );
293
+ wait_until_mux_stable (base + regs -> mux_stat , 16 , 1 );
268
294
269
295
if (cpuclk -> flags & CLK_CPU_NEEDS_DEBUG_ALT_DIV ) {
270
296
div |= (cfg_data -> div0 & E4210_DIV0_ATB_MASK );
271
297
div_mask |= E4210_DIV0_ATB_MASK ;
272
298
}
273
299
274
- exynos_set_safe_div (base , div , div_mask );
300
+ exynos_set_safe_div (cpuclk , div , div_mask );
275
301
spin_unlock_irqrestore (cpuclk -> lock , flags );
276
302
return 0 ;
277
303
}
278
304
279
305
/* ---- Exynos5433 ---------------------------------------------------------- */
280
306
281
- #define E5433_MUX_SEL2 0x208
282
- #define E5433_MUX_STAT2 0x408
283
- #define E5433_DIV_CPU0 0x600
284
- #define E5433_DIV_CPU1 0x604
285
- #define E5433_DIV_STAT_CPU0 0x700
286
- #define E5433_DIV_STAT_CPU1 0x704
287
-
288
- /*
289
- * Helper function to set the 'safe' dividers for the CPU clock. The parameters
290
- * div and mask contain the divider value and the register bit mask of the
291
- * dividers to be programmed.
292
- */
293
- static void exynos5433_set_safe_div (void __iomem * base , unsigned long div ,
294
- unsigned long mask )
295
- {
296
- unsigned long div0 ;
297
-
298
- div0 = readl (base + E5433_DIV_CPU0 );
299
- div0 = (div0 & ~mask ) | (div & mask );
300
- writel (div0 , base + E5433_DIV_CPU0 );
301
- wait_until_divider_stable (base + E5433_DIV_STAT_CPU0 , mask );
302
- }
307
+ static const struct exynos_cpuclk_regs e5433_cpuclk_regs = {
308
+ .mux_sel = 0x208 ,
309
+ .mux_stat = 0x408 ,
310
+ .div_cpu0 = 0x600 ,
311
+ .div_cpu1 = 0x604 ,
312
+ .div_stat_cpu0 = 0x700 ,
313
+ .div_stat_cpu1 = 0x704 ,
314
+ };
303
315
304
316
/* handler for pre-rate change notification from parent clock */
305
317
static int exynos5433_cpuclk_pre_rate_change (struct clk_notifier_data * ndata ,
306
318
struct exynos_cpuclk * cpuclk )
307
319
{
308
320
const struct exynos_cpuclk_cfg_data * cfg_data = cpuclk -> cfg ;
321
+ const struct exynos_cpuclk_regs * const regs = cpuclk -> chip -> regs ;
309
322
void __iomem * base = cpuclk -> base ;
310
323
unsigned long alt_prate = clk_hw_get_rate (cpuclk -> alt_parent );
311
324
unsigned long div0 , div1 = 0 , mux_reg ;
@@ -342,21 +355,21 @@ static int exynos5433_cpuclk_pre_rate_change(struct clk_notifier_data *ndata,
342
355
alt_div = DIV_ROUND_UP (alt_prate , tmp_rate ) - 1 ;
343
356
WARN_ON (alt_div >= MAX_DIV );
344
357
345
- exynos5433_set_safe_div ( base , alt_div , alt_div_mask );
358
+ exynos_set_safe_div ( cpuclk , alt_div , alt_div_mask );
346
359
div0 |= alt_div ;
347
360
}
348
361
349
362
/* select the alternate parent */
350
- mux_reg = readl (base + E5433_MUX_SEL2 );
351
- writel (mux_reg | 1 , base + E5433_MUX_SEL2 );
352
- wait_until_mux_stable (base + E5433_MUX_STAT2 , 0 , 2 );
363
+ mux_reg = readl (base + regs -> mux_sel );
364
+ writel (mux_reg | 1 , base + regs -> mux_sel );
365
+ wait_until_mux_stable (base + regs -> mux_stat , 0 , 2 );
353
366
354
367
/* alternate parent is active now. set the dividers */
355
- writel (div0 , base + E5433_DIV_CPU0 );
356
- wait_until_divider_stable (base + E5433_DIV_STAT_CPU0 , DIV_MASK_ALL );
368
+ writel (div0 , base + regs -> div_cpu0 );
369
+ wait_until_divider_stable (base + regs -> div_stat_cpu0 , DIV_MASK_ALL );
357
370
358
- writel (div1 , base + E5433_DIV_CPU1 );
359
- wait_until_divider_stable (base + E5433_DIV_STAT_CPU1 , DIV_MASK_ALL );
371
+ writel (div1 , base + regs -> div_cpu1 );
372
+ wait_until_divider_stable (base + regs -> div_stat_cpu1 , DIV_MASK_ALL );
360
373
361
374
spin_unlock_irqrestore (cpuclk -> lock , flags );
362
375
return 0 ;
@@ -366,6 +379,7 @@ static int exynos5433_cpuclk_pre_rate_change(struct clk_notifier_data *ndata,
366
379
static int exynos5433_cpuclk_post_rate_change (struct clk_notifier_data * ndata ,
367
380
struct exynos_cpuclk * cpuclk )
368
381
{
382
+ const struct exynos_cpuclk_regs * const regs = cpuclk -> chip -> regs ;
369
383
void __iomem * base = cpuclk -> base ;
370
384
unsigned long div = 0 , div_mask = DIV_MASK ;
371
385
unsigned long mux_reg ;
@@ -374,11 +388,11 @@ static int exynos5433_cpuclk_post_rate_change(struct clk_notifier_data *ndata,
374
388
spin_lock_irqsave (cpuclk -> lock , flags );
375
389
376
390
/* select apll as the alternate parent */
377
- mux_reg = readl (base + E5433_MUX_SEL2 );
378
- writel (mux_reg & ~1 , base + E5433_MUX_SEL2 );
379
- wait_until_mux_stable (base + E5433_MUX_STAT2 , 0 , 1 );
391
+ mux_reg = readl (base + regs -> mux_sel );
392
+ writel (mux_reg & ~1 , base + regs -> mux_sel );
393
+ wait_until_mux_stable (base + regs -> mux_stat , 0 , 1 );
380
394
381
- exynos5433_set_safe_div ( base , div , div_mask );
395
+ exynos_set_safe_div ( cpuclk , div , div_mask );
382
396
spin_unlock_irqrestore (cpuclk -> lock , flags );
383
397
return 0 ;
384
398
}
@@ -436,10 +450,12 @@ static int exynos_cpuclk_notifier_cb(struct notifier_block *nb,
436
450
437
451
static const struct exynos_cpuclk_chip exynos_clkcpu_chips [] = {
438
452
[CPUCLK_LAYOUT_E4210 ] = {
453
+ .regs = & e4210_cpuclk_regs ,
439
454
.pre_rate_cb = exynos_cpuclk_pre_rate_change ,
440
455
.post_rate_cb = exynos_cpuclk_post_rate_change ,
441
456
},
442
457
[CPUCLK_LAYOUT_E5433 ] = {
458
+ .regs = & e5433_cpuclk_regs ,
443
459
.pre_rate_cb = exynos5433_cpuclk_pre_rate_change ,
444
460
.post_rate_cb = exynos5433_cpuclk_post_rate_change ,
445
461
},
0 commit comments