Skip to content

Commit 78bc231

Browse files
Sam Protsenkokrzk
authored andcommitted
clk: samsung: Keep register offsets in chip specific structure
Abstract CPU clock registers by keeping their offsets in a dedicated chip specific structure to accommodate for oncoming Exynos850 support, which has different offsets for cluster 0 and cluster 1. This rework also makes it possible to use exynos_set_safe_div() for all chips, so exynos5433_set_safe_div() is removed here to reduce the code duplication. The ".regs" field has to be (void *) as different Exynos chips can have very different register layout, so this way it's possible for ".regs" to point to different structures, each representing its own chip's layout. No functional change. Signed-off-by: Sam Protsenko <[email protected]> Link: https://lore.kernel.org/r/[email protected] [krzysztof: drop redundant const for regs in exynos_cpuclk_chip] Signed-off-by: Krzysztof Kozlowski <[email protected]>
1 parent 9c746e5 commit 78bc231

File tree

1 file changed

+86
-70
lines changed

1 file changed

+86
-70
lines changed

drivers/clk/samsung/clk-cpu.c

Lines changed: 86 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -43,14 +43,34 @@ struct exynos_cpuclk;
4343
typedef int (*exynos_rate_change_fn_t)(struct clk_notifier_data *ndata,
4444
struct exynos_cpuclk *cpuclk);
4545

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+
4664
/**
4765
* struct exynos_cpuclk_chip - Chip specific data for CPU clock
66+
* @regs: register offsets for CPU related clocks
4867
* @pre_rate_cb: callback to run before CPU clock rate change
4968
* @post_rate_cb: callback to run after CPU clock rate change
5069
*/
5170
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;
5474
};
5575

5676
/**
@@ -130,43 +150,48 @@ static void wait_until_mux_stable(void __iomem *mux_reg, u32 mux_pos,
130150
pr_err("%s: re-parenting mux timed-out\n", __func__);
131151
}
132152

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-
149153
/*
150154
* Helper function to set the 'safe' dividers for the CPU clock. The parameters
151155
* div and mask contain the divider value and the register bit mask of the
152156
* dividers to be programmed.
153157
*/
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,
155159
unsigned long mask)
156160
{
161+
const struct exynos_cpuclk_regs * const regs = cpuclk->chip->regs;
162+
void __iomem *base = cpuclk->base;
157163
unsigned long div0;
158164

159-
div0 = readl(base + E4210_DIV_CPU0);
165+
div0 = readl(base + regs->div_cpu0);
160166
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);
163169
}
164170

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+
165189
/* handler for pre-rate change notification from parent clock */
166190
static int exynos_cpuclk_pre_rate_change(struct clk_notifier_data *ndata,
167191
struct exynos_cpuclk *cpuclk)
168192
{
169193
const struct exynos_cpuclk_cfg_data *cfg_data = cpuclk->cfg;
194+
const struct exynos_cpuclk_regs * const regs = cpuclk->chip->regs;
170195
void __iomem *base = cpuclk->base;
171196
unsigned long alt_prate = clk_hw_get_rate(cpuclk->alt_parent);
172197
unsigned long div0, div1 = 0, mux_reg;
@@ -189,8 +214,8 @@ static int exynos_cpuclk_pre_rate_change(struct clk_notifier_data *ndata,
189214
div0 = cfg_data->div0;
190215
if (cpuclk->flags & CLK_CPU_HAS_DIV1) {
191216
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) &
194219
(E4210_DIV1_HPM_MASK | E4210_DIV1_COPY_MASK);
195220
}
196221

@@ -217,22 +242,22 @@ static int exynos_cpuclk_pre_rate_change(struct clk_notifier_data *ndata,
217242
alt_div |= E4210_DIV0_ATB_MASK;
218243
alt_div_mask |= E4210_DIV0_ATB_MASK;
219244
}
220-
exynos_set_safe_div(base, alt_div, alt_div_mask);
245+
exynos_set_safe_div(cpuclk, alt_div, alt_div_mask);
221246
div0 |= alt_div;
222247
}
223248

224249
/* 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);
228253

229254
/* 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);
232257

233258
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,
236261
DIV_MASK_ALL);
237262
}
238263

@@ -245,6 +270,7 @@ static int exynos_cpuclk_post_rate_change(struct clk_notifier_data *ndata,
245270
struct exynos_cpuclk *cpuclk)
246271
{
247272
const struct exynos_cpuclk_cfg_data *cfg_data = cpuclk->cfg;
273+
const struct exynos_cpuclk_regs * const regs = cpuclk->chip->regs;
248274
void __iomem *base = cpuclk->base;
249275
unsigned long div = 0, div_mask = DIV_MASK;
250276
unsigned long mux_reg;
@@ -262,50 +288,37 @@ static int exynos_cpuclk_post_rate_change(struct clk_notifier_data *ndata,
262288
spin_lock_irqsave(cpuclk->lock, flags);
263289

264290
/* 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);
268294

269295
if (cpuclk->flags & CLK_CPU_NEEDS_DEBUG_ALT_DIV) {
270296
div |= (cfg_data->div0 & E4210_DIV0_ATB_MASK);
271297
div_mask |= E4210_DIV0_ATB_MASK;
272298
}
273299

274-
exynos_set_safe_div(base, div, div_mask);
300+
exynos_set_safe_div(cpuclk, div, div_mask);
275301
spin_unlock_irqrestore(cpuclk->lock, flags);
276302
return 0;
277303
}
278304

279305
/* ---- Exynos5433 ---------------------------------------------------------- */
280306

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+
};
303315

304316
/* handler for pre-rate change notification from parent clock */
305317
static int exynos5433_cpuclk_pre_rate_change(struct clk_notifier_data *ndata,
306318
struct exynos_cpuclk *cpuclk)
307319
{
308320
const struct exynos_cpuclk_cfg_data *cfg_data = cpuclk->cfg;
321+
const struct exynos_cpuclk_regs * const regs = cpuclk->chip->regs;
309322
void __iomem *base = cpuclk->base;
310323
unsigned long alt_prate = clk_hw_get_rate(cpuclk->alt_parent);
311324
unsigned long div0, div1 = 0, mux_reg;
@@ -342,21 +355,21 @@ static int exynos5433_cpuclk_pre_rate_change(struct clk_notifier_data *ndata,
342355
alt_div = DIV_ROUND_UP(alt_prate, tmp_rate) - 1;
343356
WARN_ON(alt_div >= MAX_DIV);
344357

345-
exynos5433_set_safe_div(base, alt_div, alt_div_mask);
358+
exynos_set_safe_div(cpuclk, alt_div, alt_div_mask);
346359
div0 |= alt_div;
347360
}
348361

349362
/* 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);
353366

354367
/* 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);
357370

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);
360373

361374
spin_unlock_irqrestore(cpuclk->lock, flags);
362375
return 0;
@@ -366,6 +379,7 @@ static int exynos5433_cpuclk_pre_rate_change(struct clk_notifier_data *ndata,
366379
static int exynos5433_cpuclk_post_rate_change(struct clk_notifier_data *ndata,
367380
struct exynos_cpuclk *cpuclk)
368381
{
382+
const struct exynos_cpuclk_regs * const regs = cpuclk->chip->regs;
369383
void __iomem *base = cpuclk->base;
370384
unsigned long div = 0, div_mask = DIV_MASK;
371385
unsigned long mux_reg;
@@ -374,11 +388,11 @@ static int exynos5433_cpuclk_post_rate_change(struct clk_notifier_data *ndata,
374388
spin_lock_irqsave(cpuclk->lock, flags);
375389

376390
/* 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);
380394

381-
exynos5433_set_safe_div(base, div, div_mask);
395+
exynos_set_safe_div(cpuclk, div, div_mask);
382396
spin_unlock_irqrestore(cpuclk->lock, flags);
383397
return 0;
384398
}
@@ -436,10 +450,12 @@ static int exynos_cpuclk_notifier_cb(struct notifier_block *nb,
436450

437451
static const struct exynos_cpuclk_chip exynos_clkcpu_chips[] = {
438452
[CPUCLK_LAYOUT_E4210] = {
453+
.regs = &e4210_cpuclk_regs,
439454
.pre_rate_cb = exynos_cpuclk_pre_rate_change,
440455
.post_rate_cb = exynos_cpuclk_post_rate_change,
441456
},
442457
[CPUCLK_LAYOUT_E5433] = {
458+
.regs = &e5433_cpuclk_regs,
443459
.pre_rate_cb = exynos5433_cpuclk_pre_rate_change,
444460
.post_rate_cb = exynos5433_cpuclk_post_rate_change,
445461
},

0 commit comments

Comments
 (0)