brintos

brintos / linux-shallow public Read only

0
0
Text · 12.6 KiB · 4c8246a Raw
573 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Copyright (C) 2014 Texas Instruments Incorporated - https://www.ti.com/4 */5 6#define DSS_SUBSYS_NAME "PLL"7 8#include <linux/delay.h>9#include <linux/clk.h>10#include <linux/io.h>11#include <linux/kernel.h>12#include <linux/regulator/consumer.h>13#include <linux/sched.h>14 15#include "omapdss.h"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 28int dss_pll_register(struct dss_device *dss, struct dss_pll *pll)29{30	int i;31 32	for (i = 0; i < ARRAY_SIZE(dss->plls); ++i) {33		if (!dss->plls[i]) {34			dss->plls[i] = pll;35			pll->dss = dss;36			return 0;37		}38	}39 40	return -EBUSY;41}42 43void dss_pll_unregister(struct dss_pll *pll)44{45	struct dss_device *dss = pll->dss;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			pll->dss = NULL;52			return;53		}54	}55}56 57struct dss_pll *dss_pll_find(struct dss_device *dss, const char *name)58{59	int i;60 61	for (i = 0; i < ARRAY_SIZE(dss->plls); ++i) {62		if (dss->plls[i] && strcmp(dss->plls[i]->name, name) == 0)63			return dss->plls[i];64	}65 66	return NULL;67}68 69struct dss_pll *dss_pll_find_by_src(struct dss_device *dss,70				    enum dss_clk_source src)71{72	struct dss_pll *pll;73 74	switch (src) {75	default:76	case DSS_CLK_SRC_FCK:77		return NULL;78 79	case DSS_CLK_SRC_HDMI_PLL:80		return dss_pll_find(dss, "hdmi");81 82	case DSS_CLK_SRC_PLL1_1:83	case DSS_CLK_SRC_PLL1_2:84	case DSS_CLK_SRC_PLL1_3:85		pll = dss_pll_find(dss, "dsi0");86		if (!pll)87			pll = dss_pll_find(dss, "video0");88		return pll;89 90	case DSS_CLK_SRC_PLL2_1:91	case DSS_CLK_SRC_PLL2_2:92	case DSS_CLK_SRC_PLL2_3:93		pll = dss_pll_find(dss, "dsi1");94		if (!pll)95			pll = dss_pll_find(dss, "video1");96		return pll;97	}98}99 100unsigned int dss_pll_get_clkout_idx_for_src(enum dss_clk_source src)101{102	switch (src) {103	case DSS_CLK_SRC_HDMI_PLL:104		return 0;105 106	case DSS_CLK_SRC_PLL1_1:107	case DSS_CLK_SRC_PLL2_1:108		return 0;109 110	case DSS_CLK_SRC_PLL1_2:111	case DSS_CLK_SRC_PLL2_2:112		return 1;113 114	case DSS_CLK_SRC_PLL1_3:115	case DSS_CLK_SRC_PLL2_3:116		return 2;117 118	default:119		return 0;120	}121}122 123int dss_pll_enable(struct dss_pll *pll)124{125	int r;126 127	r = clk_prepare_enable(pll->clkin);128	if (r)129		return r;130 131	if (pll->regulator) {132		r = regulator_enable(pll->regulator);133		if (r)134			goto err_reg;135	}136 137	r = pll->ops->enable(pll);138	if (r)139		goto err_enable;140 141	return 0;142 143err_enable:144	if (pll->regulator)145		regulator_disable(pll->regulator);146err_reg:147	clk_disable_unprepare(pll->clkin);148	return r;149}150 151void dss_pll_disable(struct dss_pll *pll)152{153	pll->ops->disable(pll);154 155	if (pll->regulator)156		regulator_disable(pll->regulator);157 158	clk_disable_unprepare(pll->clkin);159 160	memset(&pll->cinfo, 0, sizeof(pll->cinfo));161}162 163int dss_pll_set_config(struct dss_pll *pll, const struct dss_pll_clock_info *cinfo)164{165	int r;166 167	r = pll->ops->set_config(pll, cinfo);168	if (r)169		return r;170 171	pll->cinfo = *cinfo;172 173	return 0;174}175 176bool dss_pll_hsdiv_calc_a(const struct dss_pll *pll, unsigned long clkdco,177		unsigned long out_min, unsigned long out_max,178		dss_hsdiv_calc_func func, void *data)179{180	const struct dss_pll_hw *hw = pll->hw;181	int m, m_start, m_stop;182	unsigned long out;183 184	out_min = out_min ? out_min : 1;185	out_max = out_max ? out_max : ULONG_MAX;186 187	m_start = max(DIV_ROUND_UP(clkdco, out_max), 1ul);188 189	m_stop = min((unsigned)(clkdco / out_min), hw->mX_max);190 191	for (m = m_start; m <= m_stop; ++m) {192		out = clkdco / m;193 194		if (func(m, out, data))195			return true;196	}197 198	return false;199}200 201/*202 * clkdco = clkin / n * m * 2203 * clkoutX = clkdco / mX204 */205bool dss_pll_calc_a(const struct dss_pll *pll, unsigned long clkin,206		unsigned long pll_min, unsigned long pll_max,207		dss_pll_calc_func func, void *data)208{209	const struct dss_pll_hw *hw = pll->hw;210	int n, n_start, n_stop, n_inc;211	int m, m_start, m_stop, m_inc;212	unsigned long fint, clkdco;213	unsigned long pll_hw_max;214	unsigned long fint_hw_min, fint_hw_max;215 216	pll_hw_max = hw->clkdco_max;217 218	fint_hw_min = hw->fint_min;219	fint_hw_max = hw->fint_max;220 221	n_start = max(DIV_ROUND_UP(clkin, fint_hw_max), 1ul);222	n_stop = min((unsigned)(clkin / fint_hw_min), hw->n_max);223	n_inc = 1;224 225	if (n_start > n_stop)226		return false;227 228	if (hw->errata_i886) {229		swap(n_start, n_stop);230		n_inc = -1;231	}232 233	pll_max = pll_max ? pll_max : ULONG_MAX;234 235	for (n = n_start; n != n_stop; n += n_inc) {236		fint = clkin / n;237 238		m_start = max(DIV_ROUND_UP(DIV_ROUND_UP(pll_min, fint), 2),239				1ul);240		m_stop = min3((unsigned)(pll_max / fint / 2),241				(unsigned)(pll_hw_max / fint / 2),242				hw->m_max);243		m_inc = 1;244 245		if (m_start > m_stop)246			continue;247 248		if (hw->errata_i886) {249			swap(m_start, m_stop);250			m_inc = -1;251		}252 253		for (m = m_start; m != m_stop; m += m_inc) {254			clkdco = 2 * m * fint;255 256			if (func(n, m, fint, clkdco, data))257				return true;258		}259	}260 261	return false;262}263 264/*265 * This calculates a PLL config that will provide the target_clkout rate266 * for clkout. Additionally clkdco rate will be the same as clkout rate267 * when clkout rate is >= min_clkdco.268 *269 * clkdco = clkin / n * m + clkin / n * mf / 262144270 * clkout = clkdco / m2271 */272bool dss_pll_calc_b(const struct dss_pll *pll, unsigned long clkin,273	unsigned long target_clkout, struct dss_pll_clock_info *cinfo)274{275	unsigned long fint, clkdco, clkout;276	unsigned long target_clkdco;277	unsigned long min_dco;278	unsigned int n, m, mf, m2, sd;279	const struct dss_pll_hw *hw = pll->hw;280 281	DSSDBG("clkin %lu, target clkout %lu\n", clkin, target_clkout);282 283	/* Fint */284	n = DIV_ROUND_UP(clkin, hw->fint_max);285	fint = clkin / n;286 287	/* adjust m2 so that the clkdco will be high enough */288	min_dco = roundup(hw->clkdco_min, fint);289	m2 = DIV_ROUND_UP(min_dco, target_clkout);290	if (m2 == 0)291		m2 = 1;292 293	target_clkdco = target_clkout * m2;294	m = target_clkdco / fint;295 296	clkdco = fint * m;297 298	/* adjust clkdco with fractional mf */299	if (WARN_ON(target_clkdco - clkdco > fint))300		mf = 0;301	else302		mf = (u32)div_u64(262144ull * (target_clkdco - clkdco), fint);303 304	if (mf > 0)305		clkdco += (u32)div_u64((u64)mf * fint, 262144);306 307	clkout = clkdco / m2;308 309	/* sigma-delta */310	sd = DIV_ROUND_UP(fint * m, 250000000);311 312	DSSDBG("N = %u, M = %u, M.f = %u, M2 = %u, SD = %u\n",313		n, m, mf, m2, sd);314	DSSDBG("Fint %lu, clkdco %lu, clkout %lu\n", fint, clkdco, clkout);315 316	cinfo->n = n;317	cinfo->m = m;318	cinfo->mf = mf;319	cinfo->mX[0] = m2;320	cinfo->sd = sd;321 322	cinfo->fint = fint;323	cinfo->clkdco = clkdco;324	cinfo->clkout[0] = clkout;325 326	return true;327}328 329static int wait_for_bit_change(void __iomem *reg, int bitnum, int value)330{331	unsigned long timeout;332	ktime_t wait;333	int t;334 335	/* first busyloop to see if the bit changes right away */336	t = 100;337	while (t-- > 0) {338		if (FLD_GET(readl_relaxed(reg), bitnum, bitnum) == value)339			return value;340	}341 342	/* then loop for 500ms, sleeping for 1ms in between */343	timeout = jiffies + msecs_to_jiffies(500);344	while (time_before(jiffies, timeout)) {345		if (FLD_GET(readl_relaxed(reg), bitnum, bitnum) == value)346			return value;347 348		wait = ns_to_ktime(1000 * 1000);349		set_current_state(TASK_UNINTERRUPTIBLE);350		schedule_hrtimeout(&wait, HRTIMER_MODE_REL);351	}352 353	return !value;354}355 356int dss_pll_wait_reset_done(struct dss_pll *pll)357{358	void __iomem *base = pll->base;359 360	if (wait_for_bit_change(base + PLL_STATUS, 0, 1) != 1)361		return -ETIMEDOUT;362	else363		return 0;364}365 366static int dss_wait_hsdiv_ack(struct dss_pll *pll, u32 hsdiv_ack_mask)367{368	int t = 100;369 370	while (t-- > 0) {371		u32 v = readl_relaxed(pll->base + PLL_STATUS);372		v &= hsdiv_ack_mask;373		if (v == hsdiv_ack_mask)374			return 0;375	}376 377	return -ETIMEDOUT;378}379 380static bool pll_is_locked(u32 stat)381{382	/*383	 * Required value for each bitfield listed below384	 *385	 * PLL_STATUS[6] = 0  PLL_BYPASS386	 * PLL_STATUS[5] = 0  PLL_HIGHJITTER387	 *388	 * PLL_STATUS[3] = 0  PLL_LOSSREF389	 * PLL_STATUS[2] = 0  PLL_RECAL390	 * PLL_STATUS[1] = 1  PLL_LOCK391	 * PLL_STATUS[0] = 1  PLL_CTRL_RESET_DONE392	 */393	return ((stat & 0x6f) == 0x3);394}395 396int dss_pll_write_config_type_a(struct dss_pll *pll,397		const struct dss_pll_clock_info *cinfo)398{399	const struct dss_pll_hw *hw = pll->hw;400	void __iomem *base = pll->base;401	int r = 0;402	u32 l;403 404	l = 0;405	if (hw->has_stopmode)406		l = FLD_MOD(l, 1, 0, 0);		/* PLL_STOPMODE */407	l = FLD_MOD(l, cinfo->n - 1, hw->n_msb, hw->n_lsb);	/* PLL_REGN */408	l = FLD_MOD(l, cinfo->m, hw->m_msb, hw->m_lsb);		/* PLL_REGM */409	/* M4 */410	l = FLD_MOD(l, cinfo->mX[0] ? cinfo->mX[0] - 1 : 0,411			hw->mX_msb[0], hw->mX_lsb[0]);412	/* M5 */413	l = FLD_MOD(l, cinfo->mX[1] ? cinfo->mX[1] - 1 : 0,414			hw->mX_msb[1], hw->mX_lsb[1]);415	writel_relaxed(l, base + PLL_CONFIGURATION1);416 417	l = 0;418	/* M6 */419	l = FLD_MOD(l, cinfo->mX[2] ? cinfo->mX[2] - 1 : 0,420			hw->mX_msb[2], hw->mX_lsb[2]);421	/* M7 */422	l = FLD_MOD(l, cinfo->mX[3] ? cinfo->mX[3] - 1 : 0,423			hw->mX_msb[3], hw->mX_lsb[3]);424	writel_relaxed(l, base + PLL_CONFIGURATION3);425 426	l = readl_relaxed(base + PLL_CONFIGURATION2);427	if (hw->has_freqsel) {428		u32 f = cinfo->fint < 1000000 ? 0x3 :429			cinfo->fint < 1250000 ? 0x4 :430			cinfo->fint < 1500000 ? 0x5 :431			cinfo->fint < 1750000 ? 0x6 :432			0x7;433 434		l = FLD_MOD(l, f, 4, 1);	/* PLL_FREQSEL */435	} else if (hw->has_selfreqdco) {436		u32 f = cinfo->clkdco < hw->clkdco_low ? 0x2 : 0x4;437 438		l = FLD_MOD(l, f, 3, 1);	/* PLL_SELFREQDCO */439	}440	l = FLD_MOD(l, 1, 13, 13);		/* PLL_REFEN */441	l = FLD_MOD(l, 0, 14, 14);		/* PHY_CLKINEN */442	l = FLD_MOD(l, 0, 16, 16);		/* M4_CLOCK_EN */443	l = FLD_MOD(l, 0, 18, 18);		/* M5_CLOCK_EN */444	l = FLD_MOD(l, 1, 20, 20);		/* HSDIVBYPASS */445	if (hw->has_refsel)446		l = FLD_MOD(l, 3, 22, 21);	/* REFSEL = sysclk */447	l = FLD_MOD(l, 0, 23, 23);		/* M6_CLOCK_EN */448	l = FLD_MOD(l, 0, 25, 25);		/* M7_CLOCK_EN */449	writel_relaxed(l, base + PLL_CONFIGURATION2);450 451	if (hw->errata_i932) {452		int cnt = 0;453		u32 sleep_time;454		const u32 max_lock_retries = 20;455 456		/*457		 * Calculate wait time for PLL LOCK458		 * 1000 REFCLK cycles in us.459		 */460		sleep_time = DIV_ROUND_UP(1000*1000*1000, cinfo->fint);461 462		for (cnt = 0; cnt < max_lock_retries; cnt++) {463			writel_relaxed(1, base + PLL_GO);	/* PLL_GO */464 465			/**466			 * read the register back to ensure the write is467			 * flushed468			 */469			readl_relaxed(base + PLL_GO);470 471			usleep_range(sleep_time, sleep_time + 5);472			l = readl_relaxed(base + PLL_STATUS);473 474			if (pll_is_locked(l) &&475			    !(readl_relaxed(base + PLL_GO) & 0x1))476				break;477 478		}479 480		if (cnt == max_lock_retries) {481			DSSERR("cannot lock PLL\n");482			r = -EIO;483			goto err;484		}485	} else {486		writel_relaxed(1, base + PLL_GO);	/* PLL_GO */487 488		if (wait_for_bit_change(base + PLL_GO, 0, 0) != 0) {489			DSSERR("DSS DPLL GO bit not going down.\n");490			r = -EIO;491			goto err;492		}493 494		if (wait_for_bit_change(base + PLL_STATUS, 1, 1) != 1) {495			DSSERR("cannot lock DSS DPLL\n");496			r = -EIO;497			goto err;498		}499	}500 501	l = readl_relaxed(base + PLL_CONFIGURATION2);502	l = FLD_MOD(l, 1, 14, 14);			/* PHY_CLKINEN */503	l = FLD_MOD(l, cinfo->mX[0] ? 1 : 0, 16, 16);	/* M4_CLOCK_EN */504	l = FLD_MOD(l, cinfo->mX[1] ? 1 : 0, 18, 18);	/* M5_CLOCK_EN */505	l = FLD_MOD(l, 0, 20, 20);			/* HSDIVBYPASS */506	l = FLD_MOD(l, cinfo->mX[2] ? 1 : 0, 23, 23);	/* M6_CLOCK_EN */507	l = FLD_MOD(l, cinfo->mX[3] ? 1 : 0, 25, 25);	/* M7_CLOCK_EN */508	writel_relaxed(l, base + PLL_CONFIGURATION2);509 510	r = dss_wait_hsdiv_ack(pll,511		(cinfo->mX[0] ? BIT(7) : 0) |512		(cinfo->mX[1] ? BIT(8) : 0) |513		(cinfo->mX[2] ? BIT(10) : 0) |514		(cinfo->mX[3] ? BIT(11) : 0));515	if (r) {516		DSSERR("failed to enable HSDIV clocks\n");517		goto err;518	}519 520err:521	return r;522}523 524int dss_pll_write_config_type_b(struct dss_pll *pll,525		const struct dss_pll_clock_info *cinfo)526{527	const struct dss_pll_hw *hw = pll->hw;528	void __iomem *base = pll->base;529	u32 l;530 531	l = 0;532	l = FLD_MOD(l, cinfo->m, 20, 9);	/* PLL_REGM */533	l = FLD_MOD(l, cinfo->n - 1, 8, 1);	/* PLL_REGN */534	writel_relaxed(l, base + PLL_CONFIGURATION1);535 536	l = readl_relaxed(base + PLL_CONFIGURATION2);537	l = FLD_MOD(l, 0x0, 12, 12);	/* PLL_HIGHFREQ divide by 2 */538	l = FLD_MOD(l, 0x1, 13, 13);	/* PLL_REFEN */539	l = FLD_MOD(l, 0x0, 14, 14);	/* PHY_CLKINEN */540	if (hw->has_refsel)541		l = FLD_MOD(l, 0x3, 22, 21);	/* REFSEL = SYSCLK */542 543	/* PLL_SELFREQDCO */544	if (cinfo->clkdco > hw->clkdco_low)545		l = FLD_MOD(l, 0x4, 3, 1);546	else547		l = FLD_MOD(l, 0x2, 3, 1);548	writel_relaxed(l, base + PLL_CONFIGURATION2);549 550	l = readl_relaxed(base + PLL_CONFIGURATION3);551	l = FLD_MOD(l, cinfo->sd, 17, 10);	/* PLL_REGSD */552	writel_relaxed(l, base + PLL_CONFIGURATION3);553 554	l = readl_relaxed(base + PLL_CONFIGURATION4);555	l = FLD_MOD(l, cinfo->mX[0], 24, 18);	/* PLL_REGM2 */556	l = FLD_MOD(l, cinfo->mf, 17, 0);	/* PLL_REGM_F */557	writel_relaxed(l, base + PLL_CONFIGURATION4);558 559	writel_relaxed(1, base + PLL_GO);	/* PLL_GO */560 561	if (wait_for_bit_change(base + PLL_GO, 0, 0) != 0) {562		DSSERR("DSS DPLL GO bit not going down.\n");563		return -EIO;564	}565 566	if (wait_for_bit_change(base + PLL_STATUS, 1, 1) != 1) {567		DSSERR("cannot lock DSS DPLL\n");568		return -ETIMEDOUT;569	}570 571	return 0;572}573