1// SPDX-License-Identifier: GPL-2.0-only
2/*
3 * Copyright (c) 2014 Samsung Electronics Co., Ltd.
4 * Author: Thomas Abraham <thomas.ab@samsung.com>
5 *
6 * Copyright (c) 2015 Samsung Electronics Co., Ltd.
7 * Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com>
8 *
9 * This file contains the utility function to register CPU clock for Samsung
10 * Exynos platforms. A CPU clock is defined as a clock supplied to a CPU or a
11 * group of CPUs. The CPU clock is typically derived from a hierarchy of clock
12 * blocks which includes mux and divider blocks. There are a number of other
13 * auxiliary clocks supplied to the CPU domain such as the debug blocks and AXI
14 * clock for CPU domain. The rates of these auxiliary clocks are related to the
15 * CPU clock rate and this relation is usually specified in the hardware manual
16 * of the SoC or supplied after the SoC characterization.
17 *
18 * The below implementation of the CPU clock allows the rate changes of the CPU
19 * clock and the corresponding rate changes of the auxiliary clocks of the CPU
20 * domain. The platform clock driver provides a clock register configuration
21 * for each configurable rate which is then used to program the clock hardware
22 * registers to achieve a fast coordinated rate change for all the CPU domain
23 * clocks.
24 *
25 * On a rate change request for the CPU clock, the rate change is propagated
26 * up to the PLL supplying the clock to the CPU domain clock blocks. While the
27 * CPU domain PLL is reconfigured, the CPU domain clocks are driven using an
28 * alternate clock source. If required, the alternate clock source is divided
29 * down in order to keep the output clock rate within the previous OPP limits.
30 */
31
32#include <linux/delay.h>
33#include <linux/errno.h>
34#include <linux/io.h>
35#include <linux/slab.h>
36#include <linux/clk.h>
37#include <linux/clk-provider.h>
38
39#include "clk.h"
40#include "clk-cpu.h"
41
42struct exynos_cpuclk;
43
44typedef int (*exynos_rate_change_fn_t)(struct clk_notifier_data *ndata,
45				       struct exynos_cpuclk *cpuclk);
46
47/**
48 * struct exynos_cpuclk_regs - Register offsets for CPU related clocks
49 * @mux_sel: offset of CPU MUX_SEL register (for selecting MUX clock parent)
50 * @mux_stat: offset of CPU MUX_STAT register (for checking MUX clock status)
51 * @div_cpu0: offset of CPU DIV0 register (for modifying divider values)
52 * @div_cpu1: offset of CPU DIV1 register (for modifying divider values)
53 * @div_stat_cpu0: offset of CPU DIV0_STAT register (for checking DIV status)
54 * @div_stat_cpu1: offset of CPU DIV1_STAT register (for checking DIV status)
55 * @mux: offset of MUX register for choosing CPU clock source
56 * @divs: offsets of DIV registers (ACLK, ATCLK, PCLKDBG and PERIPHCLK)
57 */
58struct exynos_cpuclk_regs {
59	u32 mux_sel;
60	u32 mux_stat;
61	u32 div_cpu0;
62	u32 div_cpu1;
63	u32 div_stat_cpu0;
64	u32 div_stat_cpu1;
65
66	u32 mux;
67	u32 divs[4];
68};
69
70/**
71 * struct exynos_cpuclk_chip - Chip specific data for CPU clock
72 * @regs: register offsets for CPU related clocks
73 * @pre_rate_cb: callback to run before CPU clock rate change
74 * @post_rate_cb: callback to run after CPU clock rate change
75 */
76struct exynos_cpuclk_chip {
77	const struct exynos_cpuclk_regs		*regs;
78	exynos_rate_change_fn_t			pre_rate_cb;
79	exynos_rate_change_fn_t			post_rate_cb;
80};
81
82/**
83 * struct exynos_cpuclk - information about clock supplied to a CPU core
84 * @hw:		handle between CCF and CPU clock
85 * @alt_parent:	alternate parent clock to use when switching the speed
86 *		of the primary parent clock
87 * @base:	start address of the CPU clock registers block
88 * @lock:	cpu clock domain register access lock
89 * @cfg:	cpu clock rate configuration data
90 * @num_cfgs:	number of array elements in @cfg array
91 * @clk_nb:	clock notifier registered for changes in clock speed of the
92 *		primary parent clock
93 * @flags:	configuration flags for the CPU clock
94 * @chip:	chip-specific data for the CPU clock
95 *
96 * This structure holds information required for programming the CPU clock for
97 * various clock speeds.
98 */
99struct exynos_cpuclk {
100	struct clk_hw				hw;
101	const struct clk_hw			*alt_parent;
102	void __iomem				*base;
103	spinlock_t				*lock;
104	const struct exynos_cpuclk_cfg_data	*cfg;
105	const unsigned long			num_cfgs;
106	struct notifier_block			clk_nb;
107	unsigned long				flags;
108	const struct exynos_cpuclk_chip		*chip;
109};
110
111/* ---- Common code --------------------------------------------------------- */
112
113/* Divider stabilization time, msec */
114#define MAX_STAB_TIME		10
115#define MAX_DIV			8
116#define DIV_MASK		GENMASK(2, 0)
117#define DIV_MASK_ALL		GENMASK(31, 0)
118#define MUX_MASK		GENMASK(2, 0)
119
120/*
121 * Helper function to wait until divider(s) have stabilized after the divider
122 * value has changed.
123 */
124static void wait_until_divider_stable(void __iomem *div_reg, unsigned long mask)
125{
126	unsigned long timeout = jiffies + msecs_to_jiffies(MAX_STAB_TIME);
127
128	do {
129		if (!(readl(div_reg) & mask))
130			return;
131	} while (time_before(jiffies, timeout));
132
133	if (!(readl(div_reg) & mask))
134		return;
135
136	pr_err("%s: timeout in divider stablization\n", __func__);
137}
138
139/*
140 * Helper function to wait until mux has stabilized after the mux selection
141 * value was changed.
142 */
143static void wait_until_mux_stable(void __iomem *mux_reg, u32 mux_pos,
144				  unsigned long mask, unsigned long mux_value)
145{
146	unsigned long timeout = jiffies + msecs_to_jiffies(MAX_STAB_TIME);
147
148	do {
149		if (((readl(mux_reg) >> mux_pos) & mask) == mux_value)
150			return;
151	} while (time_before(jiffies, timeout));
152
153	if (((readl(mux_reg) >> mux_pos) & mask) == mux_value)
154		return;
155
156	pr_err("%s: re-parenting mux timed-out\n", __func__);
157}
158
159/*
160 * Helper function to set the 'safe' dividers for the CPU clock. The parameters
161 * div and mask contain the divider value and the register bit mask of the
162 * dividers to be programmed.
163 */
164static void exynos_set_safe_div(struct exynos_cpuclk *cpuclk, unsigned long div,
165				unsigned long mask)
166{
167	const struct exynos_cpuclk_regs * const regs = cpuclk->chip->regs;
168	void __iomem *base = cpuclk->base;
169	unsigned long div0;
170
171	div0 = readl(base + regs->div_cpu0);
172	div0 = (div0 & ~mask) | (div & mask);
173	writel(div0, base + regs->div_cpu0);
174	wait_until_divider_stable(base + regs->div_stat_cpu0, mask);
175}
176
177/* ---- Exynos 3/4/5 -------------------------------------------------------- */
178
179#define E4210_DIV0_RATIO0_MASK	GENMASK(2, 0)
180#define E4210_DIV1_HPM_MASK	GENMASK(6, 4)
181#define E4210_DIV1_COPY_MASK	GENMASK(2, 0)
182#define E4210_MUX_HPM_MASK	BIT(20)
183#define E4210_DIV0_ATB_SHIFT	16
184#define E4210_DIV0_ATB_MASK	(DIV_MASK << E4210_DIV0_ATB_SHIFT)
185
186static const struct exynos_cpuclk_regs e4210_cpuclk_regs = {
187	.mux_sel	= 0x200,
188	.mux_stat	= 0x400,
189	.div_cpu0	= 0x500,
190	.div_cpu1	= 0x504,
191	.div_stat_cpu0	= 0x600,
192	.div_stat_cpu1	= 0x604,
193};
194
195/* handler for pre-rate change notification from parent clock */
196static int exynos_cpuclk_pre_rate_change(struct clk_notifier_data *ndata,
197					 struct exynos_cpuclk *cpuclk)
198{
199	const struct exynos_cpuclk_cfg_data *cfg_data = cpuclk->cfg;
200	const struct exynos_cpuclk_regs * const regs = cpuclk->chip->regs;
201	void __iomem *base = cpuclk->base;
202	unsigned long alt_prate = clk_hw_get_rate(cpuclk->alt_parent);
203	unsigned long div0, div1 = 0, mux_reg;
204	unsigned long flags;
205
206	/* find out the divider values to use for clock data */
207	while ((cfg_data->prate * 1000) != ndata->new_rate) {
208		if (cfg_data->prate == 0)
209			return -EINVAL;
210		cfg_data++;
211	}
212
213	spin_lock_irqsave(cpuclk->lock, flags);
214
215	/*
216	 * For the selected PLL clock frequency, get the pre-defined divider
217	 * values. If the clock for sclk_hpm is not sourced from apll, then
218	 * the values for DIV_COPY and DIV_HPM dividers need not be set.
219	 */
220	div0 = cfg_data->div0;
221	if (cpuclk->flags & CLK_CPU_HAS_DIV1) {
222		div1 = cfg_data->div1;
223		if (readl(base + regs->mux_sel) & E4210_MUX_HPM_MASK)
224			div1 = readl(base + regs->div_cpu1) &
225				(E4210_DIV1_HPM_MASK | E4210_DIV1_COPY_MASK);
226	}
227
228	/*
229	 * If the old parent clock speed is less than the clock speed of
230	 * the alternate parent, then it should be ensured that at no point
231	 * the armclk speed is more than the old_prate until the dividers are
232	 * set.  Also workaround the issue of the dividers being set to lower
233	 * values before the parent clock speed is set to new lower speed
234	 * (this can result in too high speed of armclk output clocks).
235	 */
236	if (alt_prate > ndata->old_rate || ndata->old_rate > ndata->new_rate) {
237		unsigned long tmp_rate = min(ndata->old_rate, ndata->new_rate);
238		unsigned long alt_div, alt_div_mask = DIV_MASK;
239
240		alt_div = DIV_ROUND_UP(alt_prate, tmp_rate) - 1;
241		WARN_ON(alt_div >= MAX_DIV);
242
243		if (cpuclk->flags & CLK_CPU_NEEDS_DEBUG_ALT_DIV) {
244			/*
245			 * In Exynos4210, ATB clock parent is also mout_core. So
246			 * ATB clock also needs to be mantained at safe speed.
247			 */
248			alt_div |= E4210_DIV0_ATB_MASK;
249			alt_div_mask |= E4210_DIV0_ATB_MASK;
250		}
251		exynos_set_safe_div(cpuclk, alt_div, alt_div_mask);
252		div0 |= alt_div;
253	}
254
255	/* select sclk_mpll as the alternate parent */
256	mux_reg = readl(base + regs->mux_sel);
257	writel(mux_reg | (1 << 16), base + regs->mux_sel);
258	wait_until_mux_stable(base + regs->mux_stat, 16, MUX_MASK, 2);
259
260	/* alternate parent is active now. set the dividers */
261	writel(div0, base + regs->div_cpu0);
262	wait_until_divider_stable(base + regs->div_stat_cpu0, DIV_MASK_ALL);
263
264	if (cpuclk->flags & CLK_CPU_HAS_DIV1) {
265		writel(div1, base + regs->div_cpu1);
266		wait_until_divider_stable(base + regs->div_stat_cpu1,
267					  DIV_MASK_ALL);
268	}
269
270	spin_unlock_irqrestore(cpuclk->lock, flags);
271	return 0;
272}
273
274/* handler for post-rate change notification from parent clock */
275static int exynos_cpuclk_post_rate_change(struct clk_notifier_data *ndata,
276					  struct exynos_cpuclk *cpuclk)
277{
278	const struct exynos_cpuclk_cfg_data *cfg_data = cpuclk->cfg;
279	const struct exynos_cpuclk_regs * const regs = cpuclk->chip->regs;
280	void __iomem *base = cpuclk->base;
281	unsigned long div = 0, div_mask = DIV_MASK;
282	unsigned long mux_reg;
283	unsigned long flags;
284
285	/* find out the divider values to use for clock data */
286	if (cpuclk->flags & CLK_CPU_NEEDS_DEBUG_ALT_DIV) {
287		while ((cfg_data->prate * 1000) != ndata->new_rate) {
288			if (cfg_data->prate == 0)
289				return -EINVAL;
290			cfg_data++;
291		}
292	}
293
294	spin_lock_irqsave(cpuclk->lock, flags);
295
296	/* select mout_apll as the alternate parent */
297	mux_reg = readl(base + regs->mux_sel);
298	writel(mux_reg & ~(1 << 16), base + regs->mux_sel);
299	wait_until_mux_stable(base + regs->mux_stat, 16, MUX_MASK, 1);
300
301	if (cpuclk->flags & CLK_CPU_NEEDS_DEBUG_ALT_DIV) {
302		div |= (cfg_data->div0 & E4210_DIV0_ATB_MASK);
303		div_mask |= E4210_DIV0_ATB_MASK;
304	}
305
306	exynos_set_safe_div(cpuclk, div, div_mask);
307	spin_unlock_irqrestore(cpuclk->lock, flags);
308	return 0;
309}
310
311/* ---- Exynos5433 ---------------------------------------------------------- */
312
313static const struct exynos_cpuclk_regs e5433_cpuclk_regs = {
314	.mux_sel	= 0x208,
315	.mux_stat	= 0x408,
316	.div_cpu0	= 0x600,
317	.div_cpu1	= 0x604,
318	.div_stat_cpu0	= 0x700,
319	.div_stat_cpu1	= 0x704,
320};
321
322/* handler for pre-rate change notification from parent clock */
323static int exynos5433_cpuclk_pre_rate_change(struct clk_notifier_data *ndata,
324					     struct exynos_cpuclk *cpuclk)
325{
326	const struct exynos_cpuclk_cfg_data *cfg_data = cpuclk->cfg;
327	const struct exynos_cpuclk_regs * const regs = cpuclk->chip->regs;
328	void __iomem *base = cpuclk->base;
329	unsigned long alt_prate = clk_hw_get_rate(cpuclk->alt_parent);
330	unsigned long div0, div1 = 0, mux_reg;
331	unsigned long flags;
332
333	/* find out the divider values to use for clock data */
334	while ((cfg_data->prate * 1000) != ndata->new_rate) {
335		if (cfg_data->prate == 0)
336			return -EINVAL;
337		cfg_data++;
338	}
339
340	spin_lock_irqsave(cpuclk->lock, flags);
341
342	/*
343	 * For the selected PLL clock frequency, get the pre-defined divider
344	 * values.
345	 */
346	div0 = cfg_data->div0;
347	div1 = cfg_data->div1;
348
349	/*
350	 * If the old parent clock speed is less than the clock speed of
351	 * the alternate parent, then it should be ensured that at no point
352	 * the armclk speed is more than the old_prate until the dividers are
353	 * set.  Also workaround the issue of the dividers being set to lower
354	 * values before the parent clock speed is set to new lower speed
355	 * (this can result in too high speed of armclk output clocks).
356	 */
357	if (alt_prate > ndata->old_rate || ndata->old_rate > ndata->new_rate) {
358		unsigned long tmp_rate = min(ndata->old_rate, ndata->new_rate);
359		unsigned long alt_div, alt_div_mask = DIV_MASK;
360
361		alt_div = DIV_ROUND_UP(alt_prate, tmp_rate) - 1;
362		WARN_ON(alt_div >= MAX_DIV);
363
364		exynos_set_safe_div(cpuclk, alt_div, alt_div_mask);
365		div0 |= alt_div;
366	}
367
368	/* select the alternate parent */
369	mux_reg = readl(base + regs->mux_sel);
370	writel(mux_reg | 1, base + regs->mux_sel);
371	wait_until_mux_stable(base + regs->mux_stat, 0, MUX_MASK, 2);
372
373	/* alternate parent is active now. set the dividers */
374	writel(div0, base + regs->div_cpu0);
375	wait_until_divider_stable(base + regs->div_stat_cpu0, DIV_MASK_ALL);
376
377	writel(div1, base + regs->div_cpu1);
378	wait_until_divider_stable(base + regs->div_stat_cpu1, DIV_MASK_ALL);
379
380	spin_unlock_irqrestore(cpuclk->lock, flags);
381	return 0;
382}
383
384/* handler for post-rate change notification from parent clock */
385static int exynos5433_cpuclk_post_rate_change(struct clk_notifier_data *ndata,
386					      struct exynos_cpuclk *cpuclk)
387{
388	const struct exynos_cpuclk_regs * const regs = cpuclk->chip->regs;
389	void __iomem *base = cpuclk->base;
390	unsigned long div = 0, div_mask = DIV_MASK;
391	unsigned long mux_reg;
392	unsigned long flags;
393
394	spin_lock_irqsave(cpuclk->lock, flags);
395
396	/* select apll as the alternate parent */
397	mux_reg = readl(base + regs->mux_sel);
398	writel(mux_reg & ~1, base + regs->mux_sel);
399	wait_until_mux_stable(base + regs->mux_stat, 0, MUX_MASK, 1);
400
401	exynos_set_safe_div(cpuclk, div, div_mask);
402	spin_unlock_irqrestore(cpuclk->lock, flags);
403	return 0;
404}
405
406/* ---- Exynos850 ----------------------------------------------------------- */
407
408#define E850_DIV_RATIO_MASK	GENMASK(3, 0)
409#define E850_BUSY_MASK		BIT(16)
410
411/* Max time for divider or mux to stabilize, usec */
412#define E850_DIV_MUX_STAB_TIME	100
413/* OSCCLK clock rate, Hz */
414#define E850_OSCCLK		(26 * MHZ)
415
416static const struct exynos_cpuclk_regs e850cl0_cpuclk_regs = {
417	.mux	= 0x100c,
418	.divs	= { 0x1800, 0x1808, 0x180c, 0x1810 },
419};
420
421static const struct exynos_cpuclk_regs e850cl1_cpuclk_regs = {
422	.mux	= 0x1000,
423	.divs	= { 0x1800, 0x1808, 0x180c, 0x1810 },
424};
425
426/*
427 * Set alternate parent rate to "rate" value or less.
428 *
429 * rate: Desired alt_parent rate, or 0 for max alt_parent rate
430 *
431 * Exynos850 doesn't have CPU clock divider in CMU_CPUCLx block (CMUREF divider
432 * doesn't affect CPU speed). So CPUCLx_SWITCH divider from CMU_TOP is used
433 * instead to adjust alternate parent speed.
434 *
435 * It's possible to use clk_set_max_rate() instead of this function, but it
436 * would set overly pessimistic rate values to alternate parent.
437 */
438static int exynos850_alt_parent_set_max_rate(const struct clk_hw *alt_parent,
439					     unsigned long rate)
440{
441	struct clk_hw *clk_div, *clk_divp;
442	unsigned long divp_rate, div_rate, div;
443	int ret;
444
445	/* Divider from CMU_TOP */
446	clk_div = clk_hw_get_parent(alt_parent);
447	if (!clk_div)
448		return -ENOENT;
449	/* Divider's parent from CMU_TOP */
450	clk_divp = clk_hw_get_parent(clk_div);
451	if (!clk_divp)
452		return -ENOENT;
453	/* Divider input rate */
454	divp_rate = clk_hw_get_rate(clk_divp);
455	if (!divp_rate)
456		return -EINVAL;
457
458	/* Calculate new alt_parent rate for integer divider value */
459	if (rate == 0)
460		div = 1;
461	else
462		div = DIV_ROUND_UP(divp_rate, rate);
463	div_rate = DIV_ROUND_UP(divp_rate, div);
464	WARN_ON(div >= MAX_DIV);
465
466	/* alt_parent will propagate this change up to the divider */
467	ret = clk_set_rate(alt_parent->clk, div_rate);
468	if (ret)
469		return ret;
470	udelay(E850_DIV_MUX_STAB_TIME);
471
472	return 0;
473}
474
475/* Handler for pre-rate change notification from parent clock */
476static int exynos850_cpuclk_pre_rate_change(struct clk_notifier_data *ndata,
477					    struct exynos_cpuclk *cpuclk)
478{
479	const unsigned int shifts[4] = { 16, 12, 8, 4 }; /* E850_CPU_DIV0() */
480	const struct exynos_cpuclk_regs * const regs = cpuclk->chip->regs;
481	const struct exynos_cpuclk_cfg_data *cfg_data = cpuclk->cfg;
482	const struct clk_hw *alt_parent = cpuclk->alt_parent;
483	void __iomem *base = cpuclk->base;
484	unsigned long alt_prate = clk_hw_get_rate(alt_parent);
485	unsigned long flags;
486	u32 mux_reg;
487	size_t i;
488	int ret;
489
490	/* No actions are needed when switching to or from OSCCLK parent */
491	if (ndata->new_rate == E850_OSCCLK || ndata->old_rate == E850_OSCCLK)
492		return 0;
493
494	/* Find out the divider values to use for clock data */
495	while ((cfg_data->prate * 1000) != ndata->new_rate) {
496		if (cfg_data->prate == 0)
497			return -EINVAL;
498		cfg_data++;
499	}
500
501	/*
502	 * If the old parent clock speed is less than the clock speed of
503	 * the alternate parent, then it should be ensured that at no point
504	 * the armclk speed is more than the old_prate until the dividers are
505	 * set.  Also workaround the issue of the dividers being set to lower
506	 * values before the parent clock speed is set to new lower speed
507	 * (this can result in too high speed of armclk output clocks).
508	 */
509	if (alt_prate > ndata->old_rate || ndata->old_rate > ndata->new_rate) {
510		unsigned long tmp_rate = min(ndata->old_rate, ndata->new_rate);
511
512		ret = exynos850_alt_parent_set_max_rate(alt_parent, tmp_rate);
513		if (ret)
514			return ret;
515	}
516
517	spin_lock_irqsave(cpuclk->lock, flags);
518
519	/* Select the alternate parent */
520	mux_reg = readl(base + regs->mux);
521	writel(mux_reg | 1, base + regs->mux);
522	wait_until_mux_stable(base + regs->mux, 16, 1, 0);
523
524	/* Alternate parent is active now. Set the dividers */
525	for (i = 0; i < ARRAY_SIZE(shifts); ++i) {
526		unsigned long div = (cfg_data->div0 >> shifts[i]) & 0xf;
527		u32 val;
528
529		val = readl(base + regs->divs[i]);
530		val = (val & ~E850_DIV_RATIO_MASK) | div;
531		writel(val, base + regs->divs[i]);
532		wait_until_divider_stable(base + regs->divs[i], E850_BUSY_MASK);
533	}
534
535	spin_unlock_irqrestore(cpuclk->lock, flags);
536
537	return 0;
538}
539
540/* Handler for post-rate change notification from parent clock */
541static int exynos850_cpuclk_post_rate_change(struct clk_notifier_data *ndata,
542					     struct exynos_cpuclk *cpuclk)
543{
544	const struct exynos_cpuclk_regs * const regs = cpuclk->chip->regs;
545	const struct clk_hw *alt_parent = cpuclk->alt_parent;
546	void __iomem *base = cpuclk->base;
547	unsigned long flags;
548	u32 mux_reg;
549
550	/* No actions are needed when switching to or from OSCCLK parent */
551	if (ndata->new_rate == E850_OSCCLK || ndata->old_rate == E850_OSCCLK)
552		return 0;
553
554	spin_lock_irqsave(cpuclk->lock, flags);
555
556	/* Select main parent (PLL) for mux */
557	mux_reg = readl(base + regs->mux);
558	writel(mux_reg & ~1, base + regs->mux);
559	wait_until_mux_stable(base + regs->mux, 16, 1, 0);
560
561	spin_unlock_irqrestore(cpuclk->lock, flags);
562
563	/* Set alt_parent rate back to max */
564	return exynos850_alt_parent_set_max_rate(alt_parent, 0);
565}
566
567/* -------------------------------------------------------------------------- */
568
569/* Common round rate callback usable for all types of CPU clocks */
570static long exynos_cpuclk_round_rate(struct clk_hw *hw, unsigned long drate,
571				     unsigned long *prate)
572{
573	struct clk_hw *parent = clk_hw_get_parent(hw);
574	*prate = clk_hw_round_rate(parent, drate);
575	return *prate;
576}
577
578/* Common recalc rate callback usable for all types of CPU clocks */
579static unsigned long exynos_cpuclk_recalc_rate(struct clk_hw *hw,
580					       unsigned long parent_rate)
581{
582	/*
583	 * The CPU clock output (armclk) rate is the same as its parent
584	 * rate. Although there exist certain dividers inside the CPU
585	 * clock block that could be used to divide the parent clock,
586	 * the driver does not make use of them currently, except during
587	 * frequency transitions.
588	 */
589	return parent_rate;
590}
591
592static const struct clk_ops exynos_cpuclk_clk_ops = {
593	.recalc_rate = exynos_cpuclk_recalc_rate,
594	.round_rate = exynos_cpuclk_round_rate,
595};
596
597/*
598 * This notifier function is called for the pre-rate and post-rate change
599 * notifications of the parent clock of cpuclk.
600 */
601static int exynos_cpuclk_notifier_cb(struct notifier_block *nb,
602				     unsigned long event, void *data)
603{
604	struct clk_notifier_data *ndata = data;
605	struct exynos_cpuclk *cpuclk;
606	int err = 0;
607
608	cpuclk = container_of(nb, struct exynos_cpuclk, clk_nb);
609
610	if (event == PRE_RATE_CHANGE)
611		err = cpuclk->chip->pre_rate_cb(ndata, cpuclk);
612	else if (event == POST_RATE_CHANGE)
613		err = cpuclk->chip->post_rate_cb(ndata, cpuclk);
614
615	return notifier_from_errno(err);
616}
617
618static const struct exynos_cpuclk_chip exynos_clkcpu_chips[] = {
619	[CPUCLK_LAYOUT_E4210] = {
620		.regs		= &e4210_cpuclk_regs,
621		.pre_rate_cb	= exynos_cpuclk_pre_rate_change,
622		.post_rate_cb	= exynos_cpuclk_post_rate_change,
623	},
624	[CPUCLK_LAYOUT_E5433] = {
625		.regs		= &e5433_cpuclk_regs,
626		.pre_rate_cb	= exynos5433_cpuclk_pre_rate_change,
627		.post_rate_cb	= exynos5433_cpuclk_post_rate_change,
628	},
629	[CPUCLK_LAYOUT_E850_CL0] = {
630		.regs		= &e850cl0_cpuclk_regs,
631		.pre_rate_cb	= exynos850_cpuclk_pre_rate_change,
632		.post_rate_cb	= exynos850_cpuclk_post_rate_change,
633	},
634	[CPUCLK_LAYOUT_E850_CL1] = {
635		.regs		= &e850cl1_cpuclk_regs,
636		.pre_rate_cb	= exynos850_cpuclk_pre_rate_change,
637		.post_rate_cb	= exynos850_cpuclk_post_rate_change,
638	},
639};
640
641/* helper function to register a CPU clock */
642static int __init exynos_register_cpu_clock(struct samsung_clk_provider *ctx,
643				const struct samsung_cpu_clock *clk_data)
644{
645	const struct clk_hw *parent, *alt_parent;
646	struct clk_hw **hws;
647	struct exynos_cpuclk *cpuclk;
648	struct clk_init_data init;
649	const char *parent_name;
650	unsigned int num_cfgs;
651	int ret = 0;
652
653	hws = ctx->clk_data.hws;
654	parent = hws[clk_data->parent_id];
655	alt_parent = hws[clk_data->alt_parent_id];
656	if (IS_ERR(parent) || IS_ERR(alt_parent)) {
657		pr_err("%s: invalid parent clock(s)\n", __func__);
658		return -EINVAL;
659	}
660
661	cpuclk = kzalloc(sizeof(*cpuclk), GFP_KERNEL);
662	if (!cpuclk)
663		return -ENOMEM;
664
665	parent_name = clk_hw_get_name(parent);
666
667	init.name = clk_data->name;
668	init.flags = CLK_SET_RATE_PARENT;
669	init.parent_names = &parent_name;
670	init.num_parents = 1;
671	init.ops = &exynos_cpuclk_clk_ops;
672
673	cpuclk->alt_parent = alt_parent;
674	cpuclk->hw.init = &init;
675	cpuclk->base = ctx->reg_base + clk_data->offset;
676	cpuclk->lock = &ctx->lock;
677	cpuclk->flags = clk_data->flags;
678	cpuclk->clk_nb.notifier_call = exynos_cpuclk_notifier_cb;
679	cpuclk->chip = &exynos_clkcpu_chips[clk_data->reg_layout];
680
681	ret = clk_notifier_register(parent->clk, &cpuclk->clk_nb);
682	if (ret) {
683		pr_err("%s: failed to register clock notifier for %s\n",
684		       __func__, clk_data->name);
685		goto free_cpuclk;
686	}
687
688	/* Find count of configuration rates in cfg */
689	for (num_cfgs = 0; clk_data->cfg[num_cfgs].prate != 0; )
690		num_cfgs++;
691
692	cpuclk->cfg = kmemdup(clk_data->cfg, sizeof(*clk_data->cfg) * num_cfgs,
693			      GFP_KERNEL);
694	if (!cpuclk->cfg) {
695		ret = -ENOMEM;
696		goto unregister_clk_nb;
697	}
698
699	ret = clk_hw_register(NULL, &cpuclk->hw);
700	if (ret) {
701		pr_err("%s: could not register cpuclk %s\n", __func__,
702		       clk_data->name);
703		goto free_cpuclk_data;
704	}
705
706	samsung_clk_add_lookup(ctx, &cpuclk->hw, clk_data->id);
707	return 0;
708
709free_cpuclk_data:
710	kfree(cpuclk->cfg);
711unregister_clk_nb:
712	clk_notifier_unregister(parent->clk, &cpuclk->clk_nb);
713free_cpuclk:
714	kfree(cpuclk);
715	return ret;
716}
717
718void __init samsung_clk_register_cpu(struct samsung_clk_provider *ctx,
719		const struct samsung_cpu_clock *list, unsigned int nr_clk)
720{
721	unsigned int idx;
722
723	for (idx = 0; idx < nr_clk; idx++)
724		exynos_register_cpu_clock(ctx, &list[idx]);
725}
726