brintos

brintos / linux-shallow public Read only

0
0
Text · 8.6 KiB · 725194d Raw
379 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Copyright (C) 2014 Texas Instruments Incorporated4 */5 6#define DSS_SUBSYS_NAME "PLL"7 8#include <linux/clk.h>9#include <linux/io.h>10#include <linux/kernel.h>11#include <linux/regulator/consumer.h>12#include <linux/sched.h>13 14#include <video/omapfb_dss.h>15 16#include "dss.h"17 18#define PLL_CONTROL			0x000019#define PLL_STATUS			0x000420#define PLL_GO				0x000821#define PLL_CONFIGURATION1		0x000C22#define PLL_CONFIGURATION2		0x001023#define PLL_CONFIGURATION3		0x001424#define PLL_SSC_CONFIGURATION1		0x001825#define PLL_SSC_CONFIGURATION2		0x001C26#define PLL_CONFIGURATION4		0x002027 28static struct dss_pll *dss_plls[4];29 30int dss_pll_register(struct dss_pll *pll)31{32	int i;33 34	for (i = 0; i < ARRAY_SIZE(dss_plls); ++i) {35		if (!dss_plls[i]) {36			dss_plls[i] = pll;37			return 0;38		}39	}40 41	return -EBUSY;42}43 44void dss_pll_unregister(struct dss_pll *pll)45{46	int i;47 48	for (i = 0; i < ARRAY_SIZE(dss_plls); ++i) {49		if (dss_plls[i] == pll) {50			dss_plls[i] = NULL;51			return;52		}53	}54}55 56struct dss_pll *dss_pll_find(const char *name)57{58	int i;59 60	for (i = 0; i < ARRAY_SIZE(dss_plls); ++i) {61		if (dss_plls[i] && strcmp(dss_plls[i]->name, name) == 0)62			return dss_plls[i];63	}64 65	return NULL;66}67 68int dss_pll_enable(struct dss_pll *pll)69{70	int r;71 72	r = clk_prepare_enable(pll->clkin);73	if (r)74		return r;75 76	if (pll->regulator) {77		r = regulator_enable(pll->regulator);78		if (r)79			goto err_reg;80	}81 82	r = pll->ops->enable(pll);83	if (r)84		goto err_enable;85 86	return 0;87 88err_enable:89	if (pll->regulator)90		regulator_disable(pll->regulator);91err_reg:92	clk_disable_unprepare(pll->clkin);93	return r;94}95 96void dss_pll_disable(struct dss_pll *pll)97{98	pll->ops->disable(pll);99 100	if (pll->regulator)101		regulator_disable(pll->regulator);102 103	clk_disable_unprepare(pll->clkin);104 105	memset(&pll->cinfo, 0, sizeof(pll->cinfo));106}107 108int dss_pll_set_config(struct dss_pll *pll, const struct dss_pll_clock_info *cinfo)109{110	int r;111 112	r = pll->ops->set_config(pll, cinfo);113	if (r)114		return r;115 116	pll->cinfo = *cinfo;117 118	return 0;119}120 121bool dss_pll_hsdiv_calc(const struct dss_pll *pll, unsigned long clkdco,122		unsigned long out_min, unsigned long out_max,123		dss_hsdiv_calc_func func, void *data)124{125	const struct dss_pll_hw *hw = pll->hw;126	int m, m_start, m_stop;127	unsigned long out;128 129	out_min = out_min ? out_min : 1;130	out_max = out_max ? out_max : ULONG_MAX;131 132	m_start = max(DIV_ROUND_UP(clkdco, out_max), 1ul);133 134	m_stop = min((unsigned)(clkdco / out_min), hw->mX_max);135 136	for (m = m_start; m <= m_stop; ++m) {137		out = clkdco / m;138 139		if (func(m, out, data))140			return true;141	}142 143	return false;144}145 146bool dss_pll_calc(const struct dss_pll *pll, unsigned long clkin,147		unsigned long pll_min, unsigned long pll_max,148		dss_pll_calc_func func, void *data)149{150	const struct dss_pll_hw *hw = pll->hw;151	int n, n_start, n_stop;152	int m, m_start, m_stop;153	unsigned long fint, clkdco;154	unsigned long pll_hw_max;155	unsigned long fint_hw_min, fint_hw_max;156 157	pll_hw_max = hw->clkdco_max;158 159	fint_hw_min = hw->fint_min;160	fint_hw_max = hw->fint_max;161 162	n_start = max(DIV_ROUND_UP(clkin, fint_hw_max), 1ul);163	n_stop = min((unsigned)(clkin / fint_hw_min), hw->n_max);164 165	pll_max = pll_max ? pll_max : ULONG_MAX;166 167	for (n = n_start; n <= n_stop; ++n) {168		fint = clkin / n;169 170		m_start = max(DIV_ROUND_UP(DIV_ROUND_UP(pll_min, fint), 2),171				1ul);172		m_stop = min3((unsigned)(pll_max / fint / 2),173				(unsigned)(pll_hw_max / fint / 2),174				hw->m_max);175 176		for (m = m_start; m <= m_stop; ++m) {177			clkdco = 2 * m * fint;178 179			if (func(n, m, fint, clkdco, data))180				return true;181		}182	}183 184	return false;185}186 187static int wait_for_bit_change(void __iomem *reg, int bitnum, int value)188{189	unsigned long timeout;190	ktime_t wait;191	int t;192 193	/* first busyloop to see if the bit changes right away */194	t = 100;195	while (t-- > 0) {196		if (FLD_GET(readl_relaxed(reg), bitnum, bitnum) == value)197			return value;198	}199 200	/* then loop for 500ms, sleeping for 1ms in between */201	timeout = jiffies + msecs_to_jiffies(500);202	while (time_before(jiffies, timeout)) {203		if (FLD_GET(readl_relaxed(reg), bitnum, bitnum) == value)204			return value;205 206		wait = ns_to_ktime(1000 * 1000);207		set_current_state(TASK_UNINTERRUPTIBLE);208		schedule_hrtimeout(&wait, HRTIMER_MODE_REL);209	}210 211	return !value;212}213 214int dss_pll_wait_reset_done(struct dss_pll *pll)215{216	void __iomem *base = pll->base;217 218	if (wait_for_bit_change(base + PLL_STATUS, 0, 1) != 1)219		return -ETIMEDOUT;220	else221		return 0;222}223 224static int dss_wait_hsdiv_ack(struct dss_pll *pll, u32 hsdiv_ack_mask)225{226	int t = 100;227 228	while (t-- > 0) {229		u32 v = readl_relaxed(pll->base + PLL_STATUS);230		v &= hsdiv_ack_mask;231		if (v == hsdiv_ack_mask)232			return 0;233	}234 235	return -ETIMEDOUT;236}237 238int dss_pll_write_config_type_a(struct dss_pll *pll,239		const struct dss_pll_clock_info *cinfo)240{241	const struct dss_pll_hw *hw = pll->hw;242	void __iomem *base = pll->base;243	int r = 0;244	u32 l;245 246	l = 0;247	if (hw->has_stopmode)248		l = FLD_MOD(l, 1, 0, 0);		/* PLL_STOPMODE */249	l = FLD_MOD(l, cinfo->n - 1, hw->n_msb, hw->n_lsb);	/* PLL_REGN */250	l = FLD_MOD(l, cinfo->m, hw->m_msb, hw->m_lsb);		/* PLL_REGM */251	/* M4 */252	l = FLD_MOD(l, cinfo->mX[0] ? cinfo->mX[0] - 1 : 0,253			hw->mX_msb[0], hw->mX_lsb[0]);254	/* M5 */255	l = FLD_MOD(l, cinfo->mX[1] ? cinfo->mX[1] - 1 : 0,256			hw->mX_msb[1], hw->mX_lsb[1]);257	writel_relaxed(l, base + PLL_CONFIGURATION1);258 259	l = 0;260	/* M6 */261	l = FLD_MOD(l, cinfo->mX[2] ? cinfo->mX[2] - 1 : 0,262			hw->mX_msb[2], hw->mX_lsb[2]);263	/* M7 */264	l = FLD_MOD(l, cinfo->mX[3] ? cinfo->mX[3] - 1 : 0,265			hw->mX_msb[3], hw->mX_lsb[3]);266	writel_relaxed(l, base + PLL_CONFIGURATION3);267 268	l = readl_relaxed(base + PLL_CONFIGURATION2);269	if (hw->has_freqsel) {270		u32 f = cinfo->fint < 1000000 ? 0x3 :271			cinfo->fint < 1250000 ? 0x4 :272			cinfo->fint < 1500000 ? 0x5 :273			cinfo->fint < 1750000 ? 0x6 :274			0x7;275 276		l = FLD_MOD(l, f, 4, 1);	/* PLL_FREQSEL */277	} else if (hw->has_selfreqdco) {278		u32 f = cinfo->clkdco < hw->clkdco_low ? 0x2 : 0x4;279 280		l = FLD_MOD(l, f, 3, 1);	/* PLL_SELFREQDCO */281	}282	l = FLD_MOD(l, 1, 13, 13);		/* PLL_REFEN */283	l = FLD_MOD(l, 0, 14, 14);		/* PHY_CLKINEN */284	l = FLD_MOD(l, 0, 16, 16);		/* M4_CLOCK_EN */285	l = FLD_MOD(l, 0, 18, 18);		/* M5_CLOCK_EN */286	l = FLD_MOD(l, 1, 20, 20);		/* HSDIVBYPASS */287	if (hw->has_refsel)288		l = FLD_MOD(l, 3, 22, 21);	/* REFSEL = sysclk */289	l = FLD_MOD(l, 0, 23, 23);		/* M6_CLOCK_EN */290	l = FLD_MOD(l, 0, 25, 25);		/* M7_CLOCK_EN */291	writel_relaxed(l, base + PLL_CONFIGURATION2);292 293	writel_relaxed(1, base + PLL_GO);	/* PLL_GO */294 295	if (wait_for_bit_change(base + PLL_GO, 0, 0) != 0) {296		DSSERR("DSS DPLL GO bit not going down.\n");297		r = -EIO;298		goto err;299	}300 301	if (wait_for_bit_change(base + PLL_STATUS, 1, 1) != 1) {302		DSSERR("cannot lock DSS DPLL\n");303		r = -EIO;304		goto err;305	}306 307	l = readl_relaxed(base + PLL_CONFIGURATION2);308	l = FLD_MOD(l, 1, 14, 14);			/* PHY_CLKINEN */309	l = FLD_MOD(l, cinfo->mX[0] ? 1 : 0, 16, 16);	/* M4_CLOCK_EN */310	l = FLD_MOD(l, cinfo->mX[1] ? 1 : 0, 18, 18);	/* M5_CLOCK_EN */311	l = FLD_MOD(l, 0, 20, 20);			/* HSDIVBYPASS */312	l = FLD_MOD(l, cinfo->mX[2] ? 1 : 0, 23, 23);	/* M6_CLOCK_EN */313	l = FLD_MOD(l, cinfo->mX[3] ? 1 : 0, 25, 25);	/* M7_CLOCK_EN */314	writel_relaxed(l, base + PLL_CONFIGURATION2);315 316	r = dss_wait_hsdiv_ack(pll,317		(cinfo->mX[0] ? BIT(7) : 0) |318		(cinfo->mX[1] ? BIT(8) : 0) |319		(cinfo->mX[2] ? BIT(10) : 0) |320		(cinfo->mX[3] ? BIT(11) : 0));321	if (r) {322		DSSERR("failed to enable HSDIV clocks\n");323		goto err;324	}325 326err:327	return r;328}329 330int dss_pll_write_config_type_b(struct dss_pll *pll,331		const struct dss_pll_clock_info *cinfo)332{333	const struct dss_pll_hw *hw = pll->hw;334	void __iomem *base = pll->base;335	u32 l;336 337	l = 0;338	l = FLD_MOD(l, cinfo->m, 20, 9);	/* PLL_REGM */339	l = FLD_MOD(l, cinfo->n - 1, 8, 1);	/* PLL_REGN */340	writel_relaxed(l, base + PLL_CONFIGURATION1);341 342	l = readl_relaxed(base + PLL_CONFIGURATION2);343	l = FLD_MOD(l, 0x0, 12, 12);	/* PLL_HIGHFREQ divide by 2 */344	l = FLD_MOD(l, 0x1, 13, 13);	/* PLL_REFEN */345	l = FLD_MOD(l, 0x0, 14, 14);	/* PHY_CLKINEN */346	if (hw->has_refsel)347		l = FLD_MOD(l, 0x3, 22, 21);	/* REFSEL = SYSCLK */348 349	/* PLL_SELFREQDCO */350	if (cinfo->clkdco > hw->clkdco_low)351		l = FLD_MOD(l, 0x4, 3, 1);352	else353		l = FLD_MOD(l, 0x2, 3, 1);354	writel_relaxed(l, base + PLL_CONFIGURATION2);355 356	l = readl_relaxed(base + PLL_CONFIGURATION3);357	l = FLD_MOD(l, cinfo->sd, 17, 10);	/* PLL_REGSD */358	writel_relaxed(l, base + PLL_CONFIGURATION3);359 360	l = readl_relaxed(base + PLL_CONFIGURATION4);361	l = FLD_MOD(l, cinfo->mX[0], 24, 18);	/* PLL_REGM2 */362	l = FLD_MOD(l, cinfo->mf, 17, 0);	/* PLL_REGM_F */363	writel_relaxed(l, base + PLL_CONFIGURATION4);364 365	writel_relaxed(1, base + PLL_GO);	/* PLL_GO */366 367	if (wait_for_bit_change(base + PLL_GO, 0, 0) != 0) {368		DSSERR("DSS DPLL GO bit not going down.\n");369		return -EIO;370	}371 372	if (wait_for_bit_change(base + PLL_STATUS, 1, 1) != 1) {373		DSSERR("cannot lock DSS DPLL\n");374		return -ETIMEDOUT;375	}376 377	return 0;378}379