xref: /linux/drivers/clk/bcm/clk-iproc-pll.c (revision 1b24a132)
152e6676eSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
252e6676eSThomas Gleixner // Copyright (C) 2014 Broadcom Corporation
35fe225c1SRay Jui 
45fe225c1SRay Jui #include <linux/kernel.h>
55fe225c1SRay Jui #include <linux/err.h>
65fe225c1SRay Jui #include <linux/clk-provider.h>
75fe225c1SRay Jui #include <linux/io.h>
85fe225c1SRay Jui #include <linux/of.h>
95fe225c1SRay Jui #include <linux/clkdev.h>
105fe225c1SRay Jui #include <linux/of_address.h>
115fe225c1SRay Jui #include <linux/delay.h>
125fe225c1SRay Jui 
135fe225c1SRay Jui #include "clk-iproc.h"
145fe225c1SRay Jui 
155fe225c1SRay Jui #define PLL_VCO_HIGH_SHIFT 19
165fe225c1SRay Jui #define PLL_VCO_LOW_SHIFT  30
175fe225c1SRay Jui 
18bcd8be13SSimran Rai /*
19bcd8be13SSimran Rai  * PLL MACRO_SELECT modes 0 to 5 choose pre-calculated PLL output frequencies
20bcd8be13SSimran Rai  * from a look-up table. Mode 7 allows user to manipulate PLL clock dividers
21bcd8be13SSimran Rai  */
22bcd8be13SSimran Rai #define PLL_USER_MODE 7
23bcd8be13SSimran Rai 
245fe225c1SRay Jui /* number of delay loops waiting for PLL to lock */
255fe225c1SRay Jui #define LOCK_DELAY 100
265fe225c1SRay Jui 
275fe225c1SRay Jui /* number of VCO frequency bands */
285fe225c1SRay Jui #define NUM_FREQ_BANDS 8
295fe225c1SRay Jui 
305fe225c1SRay Jui #define NUM_KP_BANDS 3
315fe225c1SRay Jui enum kp_band {
325fe225c1SRay Jui 	KP_BAND_MID = 0,
335fe225c1SRay Jui 	KP_BAND_HIGH,
345fe225c1SRay Jui 	KP_BAND_HIGH_HIGH
355fe225c1SRay Jui };
365fe225c1SRay Jui 
375fe225c1SRay Jui static const unsigned int kp_table[NUM_KP_BANDS][NUM_FREQ_BANDS] = {
385fe225c1SRay Jui 	{ 5, 6, 6, 7, 7, 8, 9, 10 },
395fe225c1SRay Jui 	{ 4, 4, 5, 5, 6, 7, 8, 9  },
405fe225c1SRay Jui 	{ 4, 5, 5, 6, 7, 8, 9, 10 },
415fe225c1SRay Jui };
425fe225c1SRay Jui 
435fe225c1SRay Jui static const unsigned long ref_freq_table[NUM_FREQ_BANDS][2] = {
445fe225c1SRay Jui 	{ 10000000,  12500000  },
455fe225c1SRay Jui 	{ 12500000,  15000000  },
465fe225c1SRay Jui 	{ 15000000,  20000000  },
475fe225c1SRay Jui 	{ 20000000,  25000000  },
485fe225c1SRay Jui 	{ 25000000,  50000000  },
495fe225c1SRay Jui 	{ 50000000,  75000000  },
505fe225c1SRay Jui 	{ 75000000,  100000000 },
515fe225c1SRay Jui 	{ 100000000, 125000000 },
525fe225c1SRay Jui };
535fe225c1SRay Jui 
545fe225c1SRay Jui enum vco_freq_range {
555fe225c1SRay Jui 	VCO_LOW       = 700000000U,
565fe225c1SRay Jui 	VCO_MID       = 1200000000U,
575fe225c1SRay Jui 	VCO_HIGH      = 2200000000U,
585fe225c1SRay Jui 	VCO_HIGH_HIGH = 3100000000U,
595fe225c1SRay Jui 	VCO_MAX       = 4000000000U,
605fe225c1SRay Jui };
615fe225c1SRay Jui 
625fe225c1SRay Jui struct iproc_pll {
6340c8bec3SJon Mason 	void __iomem *status_base;
6440c8bec3SJon Mason 	void __iomem *control_base;
655fe225c1SRay Jui 	void __iomem *pwr_base;
665fe225c1SRay Jui 	void __iomem *asiu_base;
675fe225c1SRay Jui 
685fe225c1SRay Jui 	const struct iproc_pll_ctrl *ctrl;
695fe225c1SRay Jui 	const struct iproc_pll_vco_param *vco_param;
705fe225c1SRay Jui 	unsigned int num_vco_entries;
71b33db497SLori Hikichi };
725fe225c1SRay Jui 
73b33db497SLori Hikichi struct iproc_clk {
74b33db497SLori Hikichi 	struct clk_hw hw;
75b33db497SLori Hikichi 	struct iproc_pll *pll;
76b33db497SLori Hikichi 	const struct iproc_clk_ctrl *ctrl;
775fe225c1SRay Jui };
785fe225c1SRay Jui 
795fe225c1SRay Jui #define to_iproc_clk(hw) container_of(hw, struct iproc_clk, hw)
805fe225c1SRay Jui 
pll_calc_param(unsigned long target_rate,unsigned long parent_rate,struct iproc_pll_vco_param * vco_out)81becf1237SLori Hikichi static int pll_calc_param(unsigned long target_rate,
82becf1237SLori Hikichi 			unsigned long parent_rate,
83becf1237SLori Hikichi 			struct iproc_pll_vco_param *vco_out)
84becf1237SLori Hikichi {
85becf1237SLori Hikichi 	u64 ndiv_int, ndiv_frac, residual;
86becf1237SLori Hikichi 
87becf1237SLori Hikichi 	ndiv_int = target_rate / parent_rate;
88becf1237SLori Hikichi 
89becf1237SLori Hikichi 	if (!ndiv_int || (ndiv_int > 255))
90becf1237SLori Hikichi 		return -EINVAL;
91becf1237SLori Hikichi 
92becf1237SLori Hikichi 	residual = target_rate - (ndiv_int * parent_rate);
93becf1237SLori Hikichi 	residual <<= 20;
94becf1237SLori Hikichi 
95becf1237SLori Hikichi 	/*
96becf1237SLori Hikichi 	 * Add half of the divisor so the result will be rounded to closest
97becf1237SLori Hikichi 	 * instead of rounded down.
98becf1237SLori Hikichi 	 */
99becf1237SLori Hikichi 	residual += (parent_rate / 2);
100becf1237SLori Hikichi 	ndiv_frac = div64_u64((u64)residual, (u64)parent_rate);
101becf1237SLori Hikichi 
102becf1237SLori Hikichi 	vco_out->ndiv_int = ndiv_int;
103becf1237SLori Hikichi 	vco_out->ndiv_frac = ndiv_frac;
104becf1237SLori Hikichi 	vco_out->pdiv = 1;
105becf1237SLori Hikichi 
106becf1237SLori Hikichi 	vco_out->rate = vco_out->ndiv_int * parent_rate;
107becf1237SLori Hikichi 	residual = (u64)vco_out->ndiv_frac * (u64)parent_rate;
108becf1237SLori Hikichi 	residual >>= 20;
109becf1237SLori Hikichi 	vco_out->rate += residual;
110becf1237SLori Hikichi 
111becf1237SLori Hikichi 	return 0;
112becf1237SLori Hikichi }
113becf1237SLori Hikichi 
1145fe225c1SRay Jui /*
1155fe225c1SRay Jui  * Based on the target frequency, find a match from the VCO frequency parameter
1165fe225c1SRay Jui  * table and return its index
1175fe225c1SRay Jui  */
pll_get_rate_index(struct iproc_pll * pll,unsigned int target_rate)1185fe225c1SRay Jui static int pll_get_rate_index(struct iproc_pll *pll, unsigned int target_rate)
1195fe225c1SRay Jui {
1205fe225c1SRay Jui 	int i;
1215fe225c1SRay Jui 
1225fe225c1SRay Jui 	for (i = 0; i < pll->num_vco_entries; i++)
1235fe225c1SRay Jui 		if (target_rate == pll->vco_param[i].rate)
1245fe225c1SRay Jui 			break;
1255fe225c1SRay Jui 
1265fe225c1SRay Jui 	if (i >= pll->num_vco_entries)
1275fe225c1SRay Jui 		return -EINVAL;
1285fe225c1SRay Jui 
1295fe225c1SRay Jui 	return i;
1305fe225c1SRay Jui }
1315fe225c1SRay Jui 
get_kp(unsigned long ref_freq,enum kp_band kp_index)1325fe225c1SRay Jui static int get_kp(unsigned long ref_freq, enum kp_band kp_index)
1335fe225c1SRay Jui {
1345fe225c1SRay Jui 	int i;
1355fe225c1SRay Jui 
1365fe225c1SRay Jui 	if (ref_freq < ref_freq_table[0][0])
1375fe225c1SRay Jui 		return -EINVAL;
1385fe225c1SRay Jui 
1395fe225c1SRay Jui 	for (i = 0; i < NUM_FREQ_BANDS; i++) {
1405fe225c1SRay Jui 		if (ref_freq >= ref_freq_table[i][0] &&
1415fe225c1SRay Jui 		    ref_freq < ref_freq_table[i][1])
1425fe225c1SRay Jui 			return kp_table[kp_index][i];
1435fe225c1SRay Jui 	}
1445fe225c1SRay Jui 	return -EINVAL;
1455fe225c1SRay Jui }
1465fe225c1SRay Jui 
pll_wait_for_lock(struct iproc_pll * pll)1475fe225c1SRay Jui static int pll_wait_for_lock(struct iproc_pll *pll)
1485fe225c1SRay Jui {
1495fe225c1SRay Jui 	int i;
1505fe225c1SRay Jui 	const struct iproc_pll_ctrl *ctrl = pll->ctrl;
1515fe225c1SRay Jui 
1525fe225c1SRay Jui 	for (i = 0; i < LOCK_DELAY; i++) {
15340c8bec3SJon Mason 		u32 val = readl(pll->status_base + ctrl->status.offset);
1545fe225c1SRay Jui 
1555fe225c1SRay Jui 		if (val & (1 << ctrl->status.shift))
1565fe225c1SRay Jui 			return 0;
1575fe225c1SRay Jui 		udelay(10);
1585fe225c1SRay Jui 	}
1595fe225c1SRay Jui 
1605fe225c1SRay Jui 	return -EIO;
1615fe225c1SRay Jui }
1625fe225c1SRay Jui 
iproc_pll_write(const struct iproc_pll * pll,void __iomem * base,const u32 offset,u32 val)1637968d241SJon Mason static void iproc_pll_write(const struct iproc_pll *pll, void __iomem *base,
1647968d241SJon Mason 			    const u32 offset, u32 val)
1657968d241SJon Mason {
1667968d241SJon Mason 	const struct iproc_pll_ctrl *ctrl = pll->ctrl;
1677968d241SJon Mason 
1687968d241SJon Mason 	writel(val, base + offset);
1697968d241SJon Mason 
1707968d241SJon Mason 	if (unlikely(ctrl->flags & IPROC_CLK_NEEDS_READ_BACK &&
17140c8bec3SJon Mason 		     (base == pll->status_base || base == pll->control_base)))
1727968d241SJon Mason 		val = readl(base + offset);
1737968d241SJon Mason }
1747968d241SJon Mason 
__pll_disable(struct iproc_pll * pll)1755fe225c1SRay Jui static void __pll_disable(struct iproc_pll *pll)
1765fe225c1SRay Jui {
1775fe225c1SRay Jui 	const struct iproc_pll_ctrl *ctrl = pll->ctrl;
1785fe225c1SRay Jui 	u32 val;
1795fe225c1SRay Jui 
1805fe225c1SRay Jui 	if (ctrl->flags & IPROC_CLK_PLL_ASIU) {
1815fe225c1SRay Jui 		val = readl(pll->asiu_base + ctrl->asiu.offset);
1825fe225c1SRay Jui 		val &= ~(1 << ctrl->asiu.en_shift);
1837968d241SJon Mason 		iproc_pll_write(pll, pll->asiu_base, ctrl->asiu.offset, val);
1845fe225c1SRay Jui 	}
1855fe225c1SRay Jui 
18601b6722fSJon Mason 	if (ctrl->flags & IPROC_CLK_EMBED_PWRCTRL) {
18740c8bec3SJon Mason 		val = readl(pll->control_base + ctrl->aon.offset);
18801b6722fSJon Mason 		val |= bit_mask(ctrl->aon.pwr_width) << ctrl->aon.pwr_shift;
18940c8bec3SJon Mason 		iproc_pll_write(pll, pll->control_base, ctrl->aon.offset, val);
19001b6722fSJon Mason 	}
19101b6722fSJon Mason 
19201b6722fSJon Mason 	if (pll->pwr_base) {
1935fe225c1SRay Jui 		/* latch input value so core power can be shut down */
1945fe225c1SRay Jui 		val = readl(pll->pwr_base + ctrl->aon.offset);
19501b6722fSJon Mason 		val |= 1 << ctrl->aon.iso_shift;
1967968d241SJon Mason 		iproc_pll_write(pll, pll->pwr_base, ctrl->aon.offset, val);
1975fe225c1SRay Jui 
1985fe225c1SRay Jui 		/* power down the core */
1995fe225c1SRay Jui 		val &= ~(bit_mask(ctrl->aon.pwr_width) << ctrl->aon.pwr_shift);
2007968d241SJon Mason 		iproc_pll_write(pll, pll->pwr_base, ctrl->aon.offset, val);
2015fe225c1SRay Jui 	}
2025fe225c1SRay Jui }
2035fe225c1SRay Jui 
__pll_enable(struct iproc_pll * pll)2045fe225c1SRay Jui static int __pll_enable(struct iproc_pll *pll)
2055fe225c1SRay Jui {
2065fe225c1SRay Jui 	const struct iproc_pll_ctrl *ctrl = pll->ctrl;
2075fe225c1SRay Jui 	u32 val;
2085fe225c1SRay Jui 
20901b6722fSJon Mason 	if (ctrl->flags & IPROC_CLK_EMBED_PWRCTRL) {
21040c8bec3SJon Mason 		val = readl(pll->control_base + ctrl->aon.offset);
21101b6722fSJon Mason 		val &= ~(bit_mask(ctrl->aon.pwr_width) << ctrl->aon.pwr_shift);
21240c8bec3SJon Mason 		iproc_pll_write(pll, pll->control_base, ctrl->aon.offset, val);
21301b6722fSJon Mason 	}
21401b6722fSJon Mason 
21501b6722fSJon Mason 	if (pll->pwr_base) {
2165fe225c1SRay Jui 		/* power up the PLL and make sure it's not latched */
2175fe225c1SRay Jui 		val = readl(pll->pwr_base + ctrl->aon.offset);
2185fe225c1SRay Jui 		val |= bit_mask(ctrl->aon.pwr_width) << ctrl->aon.pwr_shift;
2195fe225c1SRay Jui 		val &= ~(1 << ctrl->aon.iso_shift);
2207968d241SJon Mason 		iproc_pll_write(pll, pll->pwr_base, ctrl->aon.offset, val);
22101b6722fSJon Mason 	}
2225fe225c1SRay Jui 
2235fe225c1SRay Jui 	/* certain PLLs also need to be ungated from the ASIU top level */
2245fe225c1SRay Jui 	if (ctrl->flags & IPROC_CLK_PLL_ASIU) {
2255fe225c1SRay Jui 		val = readl(pll->asiu_base + ctrl->asiu.offset);
2265fe225c1SRay Jui 		val |= (1 << ctrl->asiu.en_shift);
2277968d241SJon Mason 		iproc_pll_write(pll, pll->asiu_base, ctrl->asiu.offset, val);
2285fe225c1SRay Jui 	}
2295fe225c1SRay Jui 
2305fe225c1SRay Jui 	return 0;
2315fe225c1SRay Jui }
2325fe225c1SRay Jui 
__pll_put_in_reset(struct iproc_pll * pll)2335fe225c1SRay Jui static void __pll_put_in_reset(struct iproc_pll *pll)
2345fe225c1SRay Jui {
2355fe225c1SRay Jui 	u32 val;
2365fe225c1SRay Jui 	const struct iproc_pll_ctrl *ctrl = pll->ctrl;
2375fe225c1SRay Jui 	const struct iproc_pll_reset_ctrl *reset = &ctrl->reset;
2385fe225c1SRay Jui 
23940c8bec3SJon Mason 	val = readl(pll->control_base + reset->offset);
240bcd8be13SSimran Rai 	if (ctrl->flags & IPROC_CLK_PLL_RESET_ACTIVE_LOW)
241bcd8be13SSimran Rai 		val |= BIT(reset->reset_shift) | BIT(reset->p_reset_shift);
242bcd8be13SSimran Rai 	else
243bcd8be13SSimran Rai 		val &= ~(BIT(reset->reset_shift) | BIT(reset->p_reset_shift));
24440c8bec3SJon Mason 	iproc_pll_write(pll, pll->control_base, reset->offset, val);
2455fe225c1SRay Jui }
2465fe225c1SRay Jui 
__pll_bring_out_reset(struct iproc_pll * pll,unsigned int kp,unsigned int ka,unsigned int ki)2475fe225c1SRay Jui static void __pll_bring_out_reset(struct iproc_pll *pll, unsigned int kp,
2485fe225c1SRay Jui 				  unsigned int ka, unsigned int ki)
2495fe225c1SRay Jui {
2505fe225c1SRay Jui 	u32 val;
2515fe225c1SRay Jui 	const struct iproc_pll_ctrl *ctrl = pll->ctrl;
2525fe225c1SRay Jui 	const struct iproc_pll_reset_ctrl *reset = &ctrl->reset;
253f713c6bfSJon Mason 	const struct iproc_pll_dig_filter_ctrl *dig_filter = &ctrl->dig_filter;
2545fe225c1SRay Jui 
25540c8bec3SJon Mason 	val = readl(pll->control_base + dig_filter->offset);
256f713c6bfSJon Mason 	val &= ~(bit_mask(dig_filter->ki_width) << dig_filter->ki_shift |
257f713c6bfSJon Mason 		bit_mask(dig_filter->kp_width) << dig_filter->kp_shift |
258f713c6bfSJon Mason 		bit_mask(dig_filter->ka_width) << dig_filter->ka_shift);
259f713c6bfSJon Mason 	val |= ki << dig_filter->ki_shift | kp << dig_filter->kp_shift |
260f713c6bfSJon Mason 	       ka << dig_filter->ka_shift;
26140c8bec3SJon Mason 	iproc_pll_write(pll, pll->control_base, dig_filter->offset, val);
2625fe225c1SRay Jui 
26340c8bec3SJon Mason 	val = readl(pll->control_base + reset->offset);
264bcd8be13SSimran Rai 	if (ctrl->flags & IPROC_CLK_PLL_RESET_ACTIVE_LOW)
265bcd8be13SSimran Rai 		val &= ~(BIT(reset->reset_shift) | BIT(reset->p_reset_shift));
266bcd8be13SSimran Rai 	else
267bcd8be13SSimran Rai 		val |= BIT(reset->reset_shift) | BIT(reset->p_reset_shift);
26840c8bec3SJon Mason 	iproc_pll_write(pll, pll->control_base, reset->offset, val);
2695fe225c1SRay Jui }
2705fe225c1SRay Jui 
271f3f739c9SLori Hikichi /*
272f3f739c9SLori Hikichi  * Determines if the change to be applied to the PLL is minor (just an update
273f3f739c9SLori Hikichi  * or the fractional divider). If so, then we can avoid going through a
274f3f739c9SLori Hikichi  * disruptive reset and lock sequence.
275f3f739c9SLori Hikichi  */
pll_fractional_change_only(struct iproc_pll * pll,struct iproc_pll_vco_param * vco)276f3f739c9SLori Hikichi static bool pll_fractional_change_only(struct iproc_pll *pll,
277f3f739c9SLori Hikichi 				       struct iproc_pll_vco_param *vco)
278f3f739c9SLori Hikichi {
279f3f739c9SLori Hikichi 	const struct iproc_pll_ctrl *ctrl = pll->ctrl;
280f3f739c9SLori Hikichi 	u32 val;
281f3f739c9SLori Hikichi 	u32 ndiv_int;
282f3f739c9SLori Hikichi 	unsigned int pdiv;
283f3f739c9SLori Hikichi 
284f3f739c9SLori Hikichi 	/* PLL needs to be locked */
285f3f739c9SLori Hikichi 	val = readl(pll->status_base + ctrl->status.offset);
286f3f739c9SLori Hikichi 	if ((val & (1 << ctrl->status.shift)) == 0)
287f3f739c9SLori Hikichi 		return false;
288f3f739c9SLori Hikichi 
289f3f739c9SLori Hikichi 	val = readl(pll->control_base + ctrl->ndiv_int.offset);
290f3f739c9SLori Hikichi 	ndiv_int = (val >> ctrl->ndiv_int.shift) &
291f3f739c9SLori Hikichi 		bit_mask(ctrl->ndiv_int.width);
292f3f739c9SLori Hikichi 
293f3f739c9SLori Hikichi 	if (ndiv_int != vco->ndiv_int)
294f3f739c9SLori Hikichi 		return false;
295f3f739c9SLori Hikichi 
296f3f739c9SLori Hikichi 	val = readl(pll->control_base + ctrl->pdiv.offset);
297f3f739c9SLori Hikichi 	pdiv = (val >> ctrl->pdiv.shift) & bit_mask(ctrl->pdiv.width);
298f3f739c9SLori Hikichi 
299f3f739c9SLori Hikichi 	if (pdiv != vco->pdiv)
300f3f739c9SLori Hikichi 		return false;
301f3f739c9SLori Hikichi 
302f3f739c9SLori Hikichi 	return true;
303f3f739c9SLori Hikichi }
304f3f739c9SLori Hikichi 
pll_set_rate(struct iproc_clk * clk,struct iproc_pll_vco_param * vco,unsigned long parent_rate)305becf1237SLori Hikichi static int pll_set_rate(struct iproc_clk *clk, struct iproc_pll_vco_param *vco,
3065fe225c1SRay Jui 			unsigned long parent_rate)
3075fe225c1SRay Jui {
3085fe225c1SRay Jui 	struct iproc_pll *pll = clk->pll;
3095fe225c1SRay Jui 	const struct iproc_pll_ctrl *ctrl = pll->ctrl;
3105fe225c1SRay Jui 	int ka = 0, ki, kp, ret;
3115fe225c1SRay Jui 	unsigned long rate = vco->rate;
3125fe225c1SRay Jui 	u32 val;
3135fe225c1SRay Jui 	enum kp_band kp_index;
3145fe225c1SRay Jui 	unsigned long ref_freq;
315b33db497SLori Hikichi 	const char *clk_name = clk_hw_get_name(&clk->hw);
3165fe225c1SRay Jui 
3175fe225c1SRay Jui 	/*
3185fe225c1SRay Jui 	 * reference frequency = parent frequency / PDIV
3195fe225c1SRay Jui 	 * If PDIV = 0, then it becomes a multiplier (x2)
3205fe225c1SRay Jui 	 */
3215fe225c1SRay Jui 	if (vco->pdiv == 0)
3225fe225c1SRay Jui 		ref_freq = parent_rate * 2;
3235fe225c1SRay Jui 	else
3245fe225c1SRay Jui 		ref_freq = parent_rate / vco->pdiv;
3255fe225c1SRay Jui 
3265fe225c1SRay Jui 	/* determine Ki and Kp index based on target VCO frequency */
3275fe225c1SRay Jui 	if (rate >= VCO_LOW && rate < VCO_HIGH) {
3285fe225c1SRay Jui 		ki = 4;
3295fe225c1SRay Jui 		kp_index = KP_BAND_MID;
330d5a0945fSRay Jui 	} else if (rate >= VCO_HIGH && rate < VCO_HIGH_HIGH) {
3315fe225c1SRay Jui 		ki = 3;
3325fe225c1SRay Jui 		kp_index = KP_BAND_HIGH;
3335fe225c1SRay Jui 	} else if (rate >= VCO_HIGH_HIGH && rate < VCO_MAX) {
3345fe225c1SRay Jui 		ki = 3;
3355fe225c1SRay Jui 		kp_index = KP_BAND_HIGH_HIGH;
3365fe225c1SRay Jui 	} else {
3375fe225c1SRay Jui 		pr_err("%s: pll: %s has invalid rate: %lu\n", __func__,
338b33db497SLori Hikichi 				clk_name, rate);
3395fe225c1SRay Jui 		return -EINVAL;
3405fe225c1SRay Jui 	}
3415fe225c1SRay Jui 
3425fe225c1SRay Jui 	kp = get_kp(ref_freq, kp_index);
3435fe225c1SRay Jui 	if (kp < 0) {
344b33db497SLori Hikichi 		pr_err("%s: pll: %s has invalid kp\n", __func__, clk_name);
3455fe225c1SRay Jui 		return kp;
3465fe225c1SRay Jui 	}
3475fe225c1SRay Jui 
3485fe225c1SRay Jui 	ret = __pll_enable(pll);
3495fe225c1SRay Jui 	if (ret) {
350b33db497SLori Hikichi 		pr_err("%s: pll: %s fails to enable\n", __func__, clk_name);
3515fe225c1SRay Jui 		return ret;
3525fe225c1SRay Jui 	}
3535fe225c1SRay Jui 
354f3f739c9SLori Hikichi 	if (pll_fractional_change_only(clk->pll, vco)) {
355f3f739c9SLori Hikichi 		/* program fractional part of NDIV */
356f3f739c9SLori Hikichi 		if (ctrl->flags & IPROC_CLK_PLL_HAS_NDIV_FRAC) {
357f3f739c9SLori Hikichi 			val = readl(pll->control_base + ctrl->ndiv_frac.offset);
358f3f739c9SLori Hikichi 			val &= ~(bit_mask(ctrl->ndiv_frac.width) <<
359f3f739c9SLori Hikichi 				 ctrl->ndiv_frac.shift);
360f3f739c9SLori Hikichi 			val |= vco->ndiv_frac << ctrl->ndiv_frac.shift;
361f3f739c9SLori Hikichi 			iproc_pll_write(pll, pll->control_base,
362f3f739c9SLori Hikichi 					ctrl->ndiv_frac.offset, val);
363f3f739c9SLori Hikichi 			return 0;
364f3f739c9SLori Hikichi 		}
365f3f739c9SLori Hikichi 	}
366f3f739c9SLori Hikichi 
3675fe225c1SRay Jui 	/* put PLL in reset */
3685fe225c1SRay Jui 	__pll_put_in_reset(pll);
3695fe225c1SRay Jui 
370bcd8be13SSimran Rai 	/* set PLL in user mode before modifying PLL controls */
371bcd8be13SSimran Rai 	if (ctrl->flags & IPROC_CLK_PLL_USER_MODE_ON) {
372bcd8be13SSimran Rai 		val = readl(pll->control_base + ctrl->macro_mode.offset);
373bcd8be13SSimran Rai 		val &= ~(bit_mask(ctrl->macro_mode.width) <<
374bcd8be13SSimran Rai 			ctrl->macro_mode.shift);
375bcd8be13SSimran Rai 		val |= PLL_USER_MODE << ctrl->macro_mode.shift;
376bcd8be13SSimran Rai 		iproc_pll_write(pll, pll->control_base,
377bcd8be13SSimran Rai 			ctrl->macro_mode.offset, val);
378bcd8be13SSimran Rai 	}
379bcd8be13SSimran Rai 
38040c8bec3SJon Mason 	iproc_pll_write(pll, pll->control_base, ctrl->vco_ctrl.u_offset, 0);
3817968d241SJon Mason 
38240c8bec3SJon Mason 	val = readl(pll->control_base + ctrl->vco_ctrl.l_offset);
3835fe225c1SRay Jui 
3845fe225c1SRay Jui 	if (rate >= VCO_LOW && rate < VCO_MID)
3855fe225c1SRay Jui 		val |= (1 << PLL_VCO_LOW_SHIFT);
3865fe225c1SRay Jui 
3875fe225c1SRay Jui 	if (rate < VCO_HIGH)
3885fe225c1SRay Jui 		val &= ~(1 << PLL_VCO_HIGH_SHIFT);
3895fe225c1SRay Jui 	else
3905fe225c1SRay Jui 		val |= (1 << PLL_VCO_HIGH_SHIFT);
3915fe225c1SRay Jui 
39240c8bec3SJon Mason 	iproc_pll_write(pll, pll->control_base, ctrl->vco_ctrl.l_offset, val);
3935fe225c1SRay Jui 
3945fe225c1SRay Jui 	/* program integer part of NDIV */
39540c8bec3SJon Mason 	val = readl(pll->control_base + ctrl->ndiv_int.offset);
3965fe225c1SRay Jui 	val &= ~(bit_mask(ctrl->ndiv_int.width) << ctrl->ndiv_int.shift);
3975fe225c1SRay Jui 	val |= vco->ndiv_int << ctrl->ndiv_int.shift;
39840c8bec3SJon Mason 	iproc_pll_write(pll, pll->control_base, ctrl->ndiv_int.offset, val);
3995fe225c1SRay Jui 
4005fe225c1SRay Jui 	/* program fractional part of NDIV */
4015fe225c1SRay Jui 	if (ctrl->flags & IPROC_CLK_PLL_HAS_NDIV_FRAC) {
40240c8bec3SJon Mason 		val = readl(pll->control_base + ctrl->ndiv_frac.offset);
4035fe225c1SRay Jui 		val &= ~(bit_mask(ctrl->ndiv_frac.width) <<
4045fe225c1SRay Jui 			 ctrl->ndiv_frac.shift);
4055fe225c1SRay Jui 		val |= vco->ndiv_frac << ctrl->ndiv_frac.shift;
40640c8bec3SJon Mason 		iproc_pll_write(pll, pll->control_base, ctrl->ndiv_frac.offset,
4077968d241SJon Mason 				val);
4085fe225c1SRay Jui 	}
4095fe225c1SRay Jui 
4105fe225c1SRay Jui 	/* program PDIV */
41140c8bec3SJon Mason 	val = readl(pll->control_base + ctrl->pdiv.offset);
4125fe225c1SRay Jui 	val &= ~(bit_mask(ctrl->pdiv.width) << ctrl->pdiv.shift);
4135fe225c1SRay Jui 	val |= vco->pdiv << ctrl->pdiv.shift;
41440c8bec3SJon Mason 	iproc_pll_write(pll, pll->control_base, ctrl->pdiv.offset, val);
4155fe225c1SRay Jui 
4165fe225c1SRay Jui 	__pll_bring_out_reset(pll, kp, ka, ki);
4175fe225c1SRay Jui 
4185fe225c1SRay Jui 	ret = pll_wait_for_lock(pll);
4195fe225c1SRay Jui 	if (ret < 0) {
420b33db497SLori Hikichi 		pr_err("%s: pll: %s failed to lock\n", __func__, clk_name);
4215fe225c1SRay Jui 		return ret;
4225fe225c1SRay Jui 	}
4235fe225c1SRay Jui 
4245fe225c1SRay Jui 	return 0;
4255fe225c1SRay Jui }
4265fe225c1SRay Jui 
iproc_pll_enable(struct clk_hw * hw)4275fe225c1SRay Jui static int iproc_pll_enable(struct clk_hw *hw)
4285fe225c1SRay Jui {
4295fe225c1SRay Jui 	struct iproc_clk *clk = to_iproc_clk(hw);
4305fe225c1SRay Jui 	struct iproc_pll *pll = clk->pll;
4315fe225c1SRay Jui 
4325fe225c1SRay Jui 	return __pll_enable(pll);
4335fe225c1SRay Jui }
4345fe225c1SRay Jui 
iproc_pll_disable(struct clk_hw * hw)4355fe225c1SRay Jui static void iproc_pll_disable(struct clk_hw *hw)
4365fe225c1SRay Jui {
4375fe225c1SRay Jui 	struct iproc_clk *clk = to_iproc_clk(hw);
4385fe225c1SRay Jui 	struct iproc_pll *pll = clk->pll;
4395fe225c1SRay Jui 	const struct iproc_pll_ctrl *ctrl = pll->ctrl;
4405fe225c1SRay Jui 
4415fe225c1SRay Jui 	if (ctrl->flags & IPROC_CLK_AON)
4425fe225c1SRay Jui 		return;
4435fe225c1SRay Jui 
4445fe225c1SRay Jui 	__pll_disable(pll);
4455fe225c1SRay Jui }
4465fe225c1SRay Jui 
iproc_pll_recalc_rate(struct clk_hw * hw,unsigned long parent_rate)4475fe225c1SRay Jui static unsigned long iproc_pll_recalc_rate(struct clk_hw *hw,
4485fe225c1SRay Jui 					   unsigned long parent_rate)
4495fe225c1SRay Jui {
4505fe225c1SRay Jui 	struct iproc_clk *clk = to_iproc_clk(hw);
4515fe225c1SRay Jui 	struct iproc_pll *pll = clk->pll;
4525fe225c1SRay Jui 	const struct iproc_pll_ctrl *ctrl = pll->ctrl;
4535fe225c1SRay Jui 	u32 val;
45463243a4dSSimran Rai 	u64 ndiv, ndiv_int, ndiv_frac;
45563243a4dSSimran Rai 	unsigned int pdiv;
456b33db497SLori Hikichi 	unsigned long rate;
4575fe225c1SRay Jui 
4585fe225c1SRay Jui 	if (parent_rate == 0)
4595fe225c1SRay Jui 		return 0;
4605fe225c1SRay Jui 
4615fe225c1SRay Jui 	/* PLL needs to be locked */
46240c8bec3SJon Mason 	val = readl(pll->status_base + ctrl->status.offset);
463b33db497SLori Hikichi 	if ((val & (1 << ctrl->status.shift)) == 0)
4645fe225c1SRay Jui 		return 0;
4655fe225c1SRay Jui 
4665fe225c1SRay Jui 	/*
4675fe225c1SRay Jui 	 * PLL output frequency =
4685fe225c1SRay Jui 	 *
4695fe225c1SRay Jui 	 * ((ndiv_int + ndiv_frac / 2^20) * (parent clock rate / pdiv)
4705fe225c1SRay Jui 	 */
47140c8bec3SJon Mason 	val = readl(pll->control_base + ctrl->ndiv_int.offset);
4725fe225c1SRay Jui 	ndiv_int = (val >> ctrl->ndiv_int.shift) &
4735fe225c1SRay Jui 		bit_mask(ctrl->ndiv_int.width);
47463243a4dSSimran Rai 	ndiv = ndiv_int << 20;
4755fe225c1SRay Jui 
4765fe225c1SRay Jui 	if (ctrl->flags & IPROC_CLK_PLL_HAS_NDIV_FRAC) {
47740c8bec3SJon Mason 		val = readl(pll->control_base + ctrl->ndiv_frac.offset);
4785fe225c1SRay Jui 		ndiv_frac = (val >> ctrl->ndiv_frac.shift) &
4795fe225c1SRay Jui 			bit_mask(ctrl->ndiv_frac.width);
48063243a4dSSimran Rai 		ndiv += ndiv_frac;
4815fe225c1SRay Jui 	}
4825fe225c1SRay Jui 
48340c8bec3SJon Mason 	val = readl(pll->control_base + ctrl->pdiv.offset);
4845fe225c1SRay Jui 	pdiv = (val >> ctrl->pdiv.shift) & bit_mask(ctrl->pdiv.width);
4855fe225c1SRay Jui 
486b33db497SLori Hikichi 	rate = (ndiv * parent_rate) >> 20;
4875fe225c1SRay Jui 
4885fe225c1SRay Jui 	if (pdiv == 0)
489b33db497SLori Hikichi 		rate *= 2;
4905fe225c1SRay Jui 	else
491b33db497SLori Hikichi 		rate /= pdiv;
4925fe225c1SRay Jui 
493b33db497SLori Hikichi 	return rate;
4945fe225c1SRay Jui }
4955fe225c1SRay Jui 
iproc_pll_determine_rate(struct clk_hw * hw,struct clk_rate_request * req)496becf1237SLori Hikichi static int iproc_pll_determine_rate(struct clk_hw *hw,
497becf1237SLori Hikichi 		struct clk_rate_request *req)
4985fe225c1SRay Jui {
499becf1237SLori Hikichi 	unsigned int  i;
5005fe225c1SRay Jui 	struct iproc_clk *clk = to_iproc_clk(hw);
5015fe225c1SRay Jui 	struct iproc_pll *pll = clk->pll;
502becf1237SLori Hikichi 	const struct iproc_pll_ctrl *ctrl = pll->ctrl;
503becf1237SLori Hikichi 	unsigned long  diff, best_diff;
504becf1237SLori Hikichi 	unsigned int  best_idx = 0;
505becf1237SLori Hikichi 	int ret;
5065fe225c1SRay Jui 
507becf1237SLori Hikichi 	if (req->rate == 0 || req->best_parent_rate == 0)
5085fe225c1SRay Jui 		return -EINVAL;
5095fe225c1SRay Jui 
510becf1237SLori Hikichi 	if (ctrl->flags & IPROC_CLK_PLL_CALC_PARAM) {
511becf1237SLori Hikichi 		struct iproc_pll_vco_param vco_param;
512becf1237SLori Hikichi 
513becf1237SLori Hikichi 		ret = pll_calc_param(req->rate, req->best_parent_rate,
514becf1237SLori Hikichi 					&vco_param);
515becf1237SLori Hikichi 		if (ret)
516becf1237SLori Hikichi 			return ret;
517becf1237SLori Hikichi 
518becf1237SLori Hikichi 		req->rate = vco_param.rate;
519becf1237SLori Hikichi 		return 0;
520becf1237SLori Hikichi 	}
521becf1237SLori Hikichi 
522becf1237SLori Hikichi 	if (!pll->vco_param)
523becf1237SLori Hikichi 		return -EINVAL;
524becf1237SLori Hikichi 
525becf1237SLori Hikichi 	best_diff = ULONG_MAX;
5265fe225c1SRay Jui 	for (i = 0; i < pll->num_vco_entries; i++) {
527becf1237SLori Hikichi 		diff = abs(req->rate - pll->vco_param[i].rate);
528becf1237SLori Hikichi 		if (diff <= best_diff) {
529becf1237SLori Hikichi 			best_diff = diff;
530becf1237SLori Hikichi 			best_idx = i;
531becf1237SLori Hikichi 		}
532becf1237SLori Hikichi 		/* break now if perfect match */
533becf1237SLori Hikichi 		if (diff == 0)
5345fe225c1SRay Jui 			break;
5355fe225c1SRay Jui 	}
5365fe225c1SRay Jui 
537becf1237SLori Hikichi 	req->rate = pll->vco_param[best_idx].rate;
5385fe225c1SRay Jui 
539becf1237SLori Hikichi 	return 0;
5405fe225c1SRay Jui }
5415fe225c1SRay Jui 
iproc_pll_set_rate(struct clk_hw * hw,unsigned long rate,unsigned long parent_rate)5425fe225c1SRay Jui static int iproc_pll_set_rate(struct clk_hw *hw, unsigned long rate,
5435fe225c1SRay Jui 		unsigned long parent_rate)
5445fe225c1SRay Jui {
5455fe225c1SRay Jui 	struct iproc_clk *clk = to_iproc_clk(hw);
5465fe225c1SRay Jui 	struct iproc_pll *pll = clk->pll;
547becf1237SLori Hikichi 	const struct iproc_pll_ctrl *ctrl = pll->ctrl;
548becf1237SLori Hikichi 	struct iproc_pll_vco_param vco_param;
5495fe225c1SRay Jui 	int rate_index, ret;
5505fe225c1SRay Jui 
551becf1237SLori Hikichi 	if (ctrl->flags & IPROC_CLK_PLL_CALC_PARAM) {
552becf1237SLori Hikichi 		ret = pll_calc_param(rate, parent_rate, &vco_param);
553becf1237SLori Hikichi 		if (ret)
554becf1237SLori Hikichi 			return ret;
555becf1237SLori Hikichi 	} else {
5565fe225c1SRay Jui 		rate_index = pll_get_rate_index(pll, rate);
5575fe225c1SRay Jui 		if (rate_index < 0)
5585fe225c1SRay Jui 			return rate_index;
5595fe225c1SRay Jui 
560becf1237SLori Hikichi 		vco_param = pll->vco_param[rate_index];
561becf1237SLori Hikichi 	}
562becf1237SLori Hikichi 
563becf1237SLori Hikichi 	ret = pll_set_rate(clk, &vco_param, parent_rate);
5645fe225c1SRay Jui 	return ret;
5655fe225c1SRay Jui }
5665fe225c1SRay Jui 
5675fe225c1SRay Jui static const struct clk_ops iproc_pll_ops = {
5685fe225c1SRay Jui 	.enable = iproc_pll_enable,
5695fe225c1SRay Jui 	.disable = iproc_pll_disable,
5705fe225c1SRay Jui 	.recalc_rate = iproc_pll_recalc_rate,
571becf1237SLori Hikichi 	.determine_rate = iproc_pll_determine_rate,
5725fe225c1SRay Jui 	.set_rate = iproc_pll_set_rate,
5735fe225c1SRay Jui };
5745fe225c1SRay Jui 
iproc_clk_enable(struct clk_hw * hw)5755fe225c1SRay Jui static int iproc_clk_enable(struct clk_hw *hw)
5765fe225c1SRay Jui {
5775fe225c1SRay Jui 	struct iproc_clk *clk = to_iproc_clk(hw);
5785fe225c1SRay Jui 	const struct iproc_clk_ctrl *ctrl = clk->ctrl;
5795fe225c1SRay Jui 	struct iproc_pll *pll = clk->pll;
5805fe225c1SRay Jui 	u32 val;
5815fe225c1SRay Jui 
5825fe225c1SRay Jui 	/* channel enable is active low */
58340c8bec3SJon Mason 	val = readl(pll->control_base + ctrl->enable.offset);
5845fe225c1SRay Jui 	val &= ~(1 << ctrl->enable.enable_shift);
58540c8bec3SJon Mason 	iproc_pll_write(pll, pll->control_base, ctrl->enable.offset, val);
5865fe225c1SRay Jui 
5875fe225c1SRay Jui 	/* also make sure channel is not held */
58840c8bec3SJon Mason 	val = readl(pll->control_base + ctrl->enable.offset);
5895fe225c1SRay Jui 	val &= ~(1 << ctrl->enable.hold_shift);
59040c8bec3SJon Mason 	iproc_pll_write(pll, pll->control_base, ctrl->enable.offset, val);
5915fe225c1SRay Jui 
5925fe225c1SRay Jui 	return 0;
5935fe225c1SRay Jui }
5945fe225c1SRay Jui 
iproc_clk_disable(struct clk_hw * hw)5955fe225c1SRay Jui static void iproc_clk_disable(struct clk_hw *hw)
5965fe225c1SRay Jui {
5975fe225c1SRay Jui 	struct iproc_clk *clk = to_iproc_clk(hw);
5985fe225c1SRay Jui 	const struct iproc_clk_ctrl *ctrl = clk->ctrl;
5995fe225c1SRay Jui 	struct iproc_pll *pll = clk->pll;
6005fe225c1SRay Jui 	u32 val;
6015fe225c1SRay Jui 
6025fe225c1SRay Jui 	if (ctrl->flags & IPROC_CLK_AON)
6035fe225c1SRay Jui 		return;
6045fe225c1SRay Jui 
60540c8bec3SJon Mason 	val = readl(pll->control_base + ctrl->enable.offset);
6065fe225c1SRay Jui 	val |= 1 << ctrl->enable.enable_shift;
60740c8bec3SJon Mason 	iproc_pll_write(pll, pll->control_base, ctrl->enable.offset, val);
6085fe225c1SRay Jui }
6095fe225c1SRay Jui 
iproc_clk_recalc_rate(struct clk_hw * hw,unsigned long parent_rate)6105fe225c1SRay Jui static unsigned long iproc_clk_recalc_rate(struct clk_hw *hw,
6115fe225c1SRay Jui 		unsigned long parent_rate)
6125fe225c1SRay Jui {
6135fe225c1SRay Jui 	struct iproc_clk *clk = to_iproc_clk(hw);
6145fe225c1SRay Jui 	const struct iproc_clk_ctrl *ctrl = clk->ctrl;
6155fe225c1SRay Jui 	struct iproc_pll *pll = clk->pll;
6165fe225c1SRay Jui 	u32 val;
6175fe225c1SRay Jui 	unsigned int mdiv;
618b33db497SLori Hikichi 	unsigned long rate;
6195fe225c1SRay Jui 
6205fe225c1SRay Jui 	if (parent_rate == 0)
6215fe225c1SRay Jui 		return 0;
6225fe225c1SRay Jui 
62340c8bec3SJon Mason 	val = readl(pll->control_base + ctrl->mdiv.offset);
6245fe225c1SRay Jui 	mdiv = (val >> ctrl->mdiv.shift) & bit_mask(ctrl->mdiv.width);
6255fe225c1SRay Jui 	if (mdiv == 0)
6265fe225c1SRay Jui 		mdiv = 256;
6275fe225c1SRay Jui 
628bcd8be13SSimran Rai 	if (ctrl->flags & IPROC_CLK_MCLK_DIV_BY_2)
629b33db497SLori Hikichi 		rate = parent_rate / (mdiv * 2);
630bcd8be13SSimran Rai 	else
631b33db497SLori Hikichi 		rate = parent_rate / mdiv;
6325fe225c1SRay Jui 
633b33db497SLori Hikichi 	return rate;
6345fe225c1SRay Jui }
6355fe225c1SRay Jui 
iproc_clk_determine_rate(struct clk_hw * hw,struct clk_rate_request * req)63685151a6bSLori Hikichi static int iproc_clk_determine_rate(struct clk_hw *hw,
63785151a6bSLori Hikichi 		struct clk_rate_request *req)
6385fe225c1SRay Jui {
63985151a6bSLori Hikichi 	unsigned int bestdiv;
6405fe225c1SRay Jui 
64185151a6bSLori Hikichi 	if (req->rate == 0)
6425fe225c1SRay Jui 		return -EINVAL;
64385151a6bSLori Hikichi 	if (req->rate == req->best_parent_rate)
64485151a6bSLori Hikichi 		return 0;
6455fe225c1SRay Jui 
64685151a6bSLori Hikichi 	bestdiv = DIV_ROUND_CLOSEST(req->best_parent_rate, req->rate);
64785151a6bSLori Hikichi 	if (bestdiv < 2)
64885151a6bSLori Hikichi 		req->rate = req->best_parent_rate;
6495fe225c1SRay Jui 
65085151a6bSLori Hikichi 	if (bestdiv > 256)
65185151a6bSLori Hikichi 		bestdiv = 256;
6525fe225c1SRay Jui 
65385151a6bSLori Hikichi 	req->rate = req->best_parent_rate / bestdiv;
6545fe225c1SRay Jui 
65585151a6bSLori Hikichi 	return 0;
6565fe225c1SRay Jui }
6575fe225c1SRay Jui 
iproc_clk_set_rate(struct clk_hw * hw,unsigned long rate,unsigned long parent_rate)6585fe225c1SRay Jui static int iproc_clk_set_rate(struct clk_hw *hw, unsigned long rate,
6595fe225c1SRay Jui 		unsigned long parent_rate)
6605fe225c1SRay Jui {
6615fe225c1SRay Jui 	struct iproc_clk *clk = to_iproc_clk(hw);
6625fe225c1SRay Jui 	const struct iproc_clk_ctrl *ctrl = clk->ctrl;
6635fe225c1SRay Jui 	struct iproc_pll *pll = clk->pll;
6645fe225c1SRay Jui 	u32 val;
6655fe225c1SRay Jui 	unsigned int div;
6665fe225c1SRay Jui 
6675fe225c1SRay Jui 	if (rate == 0 || parent_rate == 0)
6685fe225c1SRay Jui 		return -EINVAL;
6695fe225c1SRay Jui 
67085151a6bSLori Hikichi 	div = DIV_ROUND_CLOSEST(parent_rate, rate);
671bcd8be13SSimran Rai 	if (ctrl->flags & IPROC_CLK_MCLK_DIV_BY_2)
67285151a6bSLori Hikichi 		div /=  2;
67385151a6bSLori Hikichi 
6745fe225c1SRay Jui 	if (div > 256)
6755fe225c1SRay Jui 		return -EINVAL;
6765fe225c1SRay Jui 
67740c8bec3SJon Mason 	val = readl(pll->control_base + ctrl->mdiv.offset);
6785fe225c1SRay Jui 	if (div == 256) {
6795fe225c1SRay Jui 		val &= ~(bit_mask(ctrl->mdiv.width) << ctrl->mdiv.shift);
6805fe225c1SRay Jui 	} else {
6815fe225c1SRay Jui 		val &= ~(bit_mask(ctrl->mdiv.width) << ctrl->mdiv.shift);
6825fe225c1SRay Jui 		val |= div << ctrl->mdiv.shift;
6835fe225c1SRay Jui 	}
68440c8bec3SJon Mason 	iproc_pll_write(pll, pll->control_base, ctrl->mdiv.offset, val);
6855fe225c1SRay Jui 
6865fe225c1SRay Jui 	return 0;
6875fe225c1SRay Jui }
6885fe225c1SRay Jui 
6895fe225c1SRay Jui static const struct clk_ops iproc_clk_ops = {
6905fe225c1SRay Jui 	.enable = iproc_clk_enable,
6915fe225c1SRay Jui 	.disable = iproc_clk_disable,
6925fe225c1SRay Jui 	.recalc_rate = iproc_clk_recalc_rate,
69385151a6bSLori Hikichi 	.determine_rate = iproc_clk_determine_rate,
6945fe225c1SRay Jui 	.set_rate = iproc_clk_set_rate,
6955fe225c1SRay Jui };
6965fe225c1SRay Jui 
697ee70d49aSLee Jones /*
6985fe225c1SRay Jui  * Some PLLs require the PLL SW override bit to be set before changes can be
6995fe225c1SRay Jui  * applied to the PLL
7005fe225c1SRay Jui  */
iproc_pll_sw_cfg(struct iproc_pll * pll)7015fe225c1SRay Jui static void iproc_pll_sw_cfg(struct iproc_pll *pll)
7025fe225c1SRay Jui {
7035fe225c1SRay Jui 	const struct iproc_pll_ctrl *ctrl = pll->ctrl;
7045fe225c1SRay Jui 
7055fe225c1SRay Jui 	if (ctrl->flags & IPROC_CLK_PLL_NEEDS_SW_CFG) {
7065fe225c1SRay Jui 		u32 val;
7075fe225c1SRay Jui 
70840c8bec3SJon Mason 		val = readl(pll->control_base + ctrl->sw_ctrl.offset);
7095fe225c1SRay Jui 		val |= BIT(ctrl->sw_ctrl.shift);
71040c8bec3SJon Mason 		iproc_pll_write(pll, pll->control_base, ctrl->sw_ctrl.offset,
71140c8bec3SJon Mason 				val);
7125fe225c1SRay Jui 	}
7135fe225c1SRay Jui }
7145fe225c1SRay Jui 
iproc_pll_clk_setup(struct device_node * node,const struct iproc_pll_ctrl * pll_ctrl,const struct iproc_pll_vco_param * vco,unsigned int num_vco_entries,const struct iproc_clk_ctrl * clk_ctrl,unsigned int num_clks)715e293915aSStephen Boyd void iproc_pll_clk_setup(struct device_node *node,
7165fe225c1SRay Jui 			 const struct iproc_pll_ctrl *pll_ctrl,
7175fe225c1SRay Jui 			 const struct iproc_pll_vco_param *vco,
7185fe225c1SRay Jui 			 unsigned int num_vco_entries,
7195fe225c1SRay Jui 			 const struct iproc_clk_ctrl *clk_ctrl,
7205fe225c1SRay Jui 			 unsigned int num_clks)
7215fe225c1SRay Jui {
7225fe225c1SRay Jui 	int i, ret;
7235fe225c1SRay Jui 	struct iproc_pll *pll;
7245fe225c1SRay Jui 	struct iproc_clk *iclk;
7255fe225c1SRay Jui 	struct clk_init_data init;
7265fe225c1SRay Jui 	const char *parent_name;
727b33db497SLori Hikichi 	struct iproc_clk *iclk_array;
728b33db497SLori Hikichi 	struct clk_hw_onecell_data *clk_data;
729*1b24a132SFlorian Fainelli 	const char *clk_name;
7305fe225c1SRay Jui 
7315fe225c1SRay Jui 	if (WARN_ON(!pll_ctrl) || WARN_ON(!clk_ctrl))
7325fe225c1SRay Jui 		return;
7335fe225c1SRay Jui 
7345fe225c1SRay Jui 	pll = kzalloc(sizeof(*pll), GFP_KERNEL);
7355fe225c1SRay Jui 	if (WARN_ON(!pll))
7365fe225c1SRay Jui 		return;
7375fe225c1SRay Jui 
738acafe7e3SKees Cook 	clk_data = kzalloc(struct_size(clk_data, hws, num_clks), GFP_KERNEL);
739b33db497SLori Hikichi 	if (WARN_ON(!clk_data))
7405fe225c1SRay Jui 		goto err_clk_data;
741b33db497SLori Hikichi 	clk_data->num = num_clks;
7425fe225c1SRay Jui 
743b33db497SLori Hikichi 	iclk_array = kcalloc(num_clks, sizeof(struct iproc_clk), GFP_KERNEL);
744b33db497SLori Hikichi 	if (WARN_ON(!iclk_array))
7455fe225c1SRay Jui 		goto err_clks;
7465fe225c1SRay Jui 
74740c8bec3SJon Mason 	pll->control_base = of_iomap(node, 0);
74840c8bec3SJon Mason 	if (WARN_ON(!pll->control_base))
7495fe225c1SRay Jui 		goto err_pll_iomap;
7505fe225c1SRay Jui 
75101b6722fSJon Mason 	/* Some SoCs do not require the pwr_base, thus failing is not fatal */
7525fe225c1SRay Jui 	pll->pwr_base = of_iomap(node, 1);
7535fe225c1SRay Jui 
7545fe225c1SRay Jui 	/* some PLLs require gating control at the top ASIU level */
7555fe225c1SRay Jui 	if (pll_ctrl->flags & IPROC_CLK_PLL_ASIU) {
7565fe225c1SRay Jui 		pll->asiu_base = of_iomap(node, 2);
7575fe225c1SRay Jui 		if (WARN_ON(!pll->asiu_base))
7585fe225c1SRay Jui 			goto err_asiu_iomap;
7595fe225c1SRay Jui 	}
7605fe225c1SRay Jui 
76140c8bec3SJon Mason 	if (pll_ctrl->flags & IPROC_CLK_PLL_SPLIT_STAT_CTRL) {
76240c8bec3SJon Mason 		/* Some SoCs have a split status/control.  If this does not
76340c8bec3SJon Mason 		 * exist, assume they are unified.
76440c8bec3SJon Mason 		 */
76540c8bec3SJon Mason 		pll->status_base = of_iomap(node, 2);
76640c8bec3SJon Mason 		if (!pll->status_base)
76740c8bec3SJon Mason 			goto err_status_iomap;
76840c8bec3SJon Mason 	} else
76940c8bec3SJon Mason 		pll->status_base = pll->control_base;
77040c8bec3SJon Mason 
7715fe225c1SRay Jui 	/* initialize and register the PLL itself */
7725fe225c1SRay Jui 	pll->ctrl = pll_ctrl;
7735fe225c1SRay Jui 
774b33db497SLori Hikichi 	iclk = &iclk_array[0];
7755fe225c1SRay Jui 	iclk->pll = pll;
7765fe225c1SRay Jui 
777*1b24a132SFlorian Fainelli 	ret = of_property_read_string_index(node, "clock-output-names",
778*1b24a132SFlorian Fainelli 					    0, &clk_name);
779*1b24a132SFlorian Fainelli 	if (WARN_ON(ret))
780*1b24a132SFlorian Fainelli 		goto err_pll_register;
781*1b24a132SFlorian Fainelli 
782*1b24a132SFlorian Fainelli 	init.name = clk_name;
7835fe225c1SRay Jui 	init.ops = &iproc_pll_ops;
7845fe225c1SRay Jui 	init.flags = 0;
7855fe225c1SRay Jui 	parent_name = of_clk_get_parent_name(node, 0);
7865fe225c1SRay Jui 	init.parent_names = (parent_name ? &parent_name : NULL);
7875fe225c1SRay Jui 	init.num_parents = (parent_name ? 1 : 0);
7885fe225c1SRay Jui 	iclk->hw.init = &init;
7895fe225c1SRay Jui 
7905fe225c1SRay Jui 	if (vco) {
7915fe225c1SRay Jui 		pll->num_vco_entries = num_vco_entries;
7925fe225c1SRay Jui 		pll->vco_param = vco;
7935fe225c1SRay Jui 	}
7945fe225c1SRay Jui 
7955fe225c1SRay Jui 	iproc_pll_sw_cfg(pll);
7965fe225c1SRay Jui 
797ff02c6c0SStephen Boyd 	ret = clk_hw_register(NULL, &iclk->hw);
798ff02c6c0SStephen Boyd 	if (WARN_ON(ret))
7995fe225c1SRay Jui 		goto err_pll_register;
8005fe225c1SRay Jui 
801b33db497SLori Hikichi 	clk_data->hws[0] = &iclk->hw;
802*1b24a132SFlorian Fainelli 	parent_name = clk_name;
8035fe225c1SRay Jui 
8045fe225c1SRay Jui 	/* now initialize and register all leaf clocks */
8055fe225c1SRay Jui 	for (i = 1; i < num_clks; i++) {
8065fe225c1SRay Jui 		memset(&init, 0, sizeof(init));
8075fe225c1SRay Jui 
8085fe225c1SRay Jui 		ret = of_property_read_string_index(node, "clock-output-names",
8095fe225c1SRay Jui 						    i, &clk_name);
8105fe225c1SRay Jui 		if (WARN_ON(ret))
8115fe225c1SRay Jui 			goto err_clk_register;
8125fe225c1SRay Jui 
813b33db497SLori Hikichi 		iclk = &iclk_array[i];
8145fe225c1SRay Jui 		iclk->pll = pll;
8155fe225c1SRay Jui 		iclk->ctrl = &clk_ctrl[i];
8165fe225c1SRay Jui 
8175fe225c1SRay Jui 		init.name = clk_name;
8185fe225c1SRay Jui 		init.ops = &iproc_clk_ops;
8195fe225c1SRay Jui 		init.flags = 0;
8205fe225c1SRay Jui 		init.parent_names = (parent_name ? &parent_name : NULL);
8215fe225c1SRay Jui 		init.num_parents = (parent_name ? 1 : 0);
8225fe225c1SRay Jui 		iclk->hw.init = &init;
8235fe225c1SRay Jui 
824ff02c6c0SStephen Boyd 		ret = clk_hw_register(NULL, &iclk->hw);
825ff02c6c0SStephen Boyd 		if (WARN_ON(ret))
8265fe225c1SRay Jui 			goto err_clk_register;
8275fe225c1SRay Jui 
828b33db497SLori Hikichi 		clk_data->hws[i] = &iclk->hw;
8295fe225c1SRay Jui 	}
8305fe225c1SRay Jui 
831b33db497SLori Hikichi 	ret = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
8325fe225c1SRay Jui 	if (WARN_ON(ret))
8335fe225c1SRay Jui 		goto err_clk_register;
8345fe225c1SRay Jui 
8355fe225c1SRay Jui 	return;
8365fe225c1SRay Jui 
8375fe225c1SRay Jui err_clk_register:
838ff02c6c0SStephen Boyd 	while (--i >= 0)
839b33db497SLori Hikichi 		clk_hw_unregister(clk_data->hws[i]);
8405fe225c1SRay Jui 
8415fe225c1SRay Jui err_pll_register:
84240c8bec3SJon Mason 	if (pll->status_base != pll->control_base)
84340c8bec3SJon Mason 		iounmap(pll->status_base);
84440c8bec3SJon Mason 
84540c8bec3SJon Mason err_status_iomap:
8465fe225c1SRay Jui 	if (pll->asiu_base)
8475fe225c1SRay Jui 		iounmap(pll->asiu_base);
8485fe225c1SRay Jui 
8495fe225c1SRay Jui err_asiu_iomap:
85001b6722fSJon Mason 	if (pll->pwr_base)
8515fe225c1SRay Jui 		iounmap(pll->pwr_base);
8525fe225c1SRay Jui 
85340c8bec3SJon Mason 	iounmap(pll->control_base);
8545fe225c1SRay Jui 
8555fe225c1SRay Jui err_pll_iomap:
856b33db497SLori Hikichi 	kfree(iclk_array);
8575fe225c1SRay Jui 
8585fe225c1SRay Jui err_clks:
859b33db497SLori Hikichi 	kfree(clk_data);
8605fe225c1SRay Jui 
8615fe225c1SRay Jui err_clk_data:
8625fe225c1SRay Jui 	kfree(pll);
8635fe225c1SRay Jui }
864