brintos

brintos / linux-shallow public Read only

0
0
Text · 12.7 KiB · 81f304f Raw
541 lines · c
1// SPDX-License-Identifier: (GPL-2.0 OR MIT)2/*3 * Copyright 2018 NXP.4 *5 * This driver supports the SCCG plls found in the imx8m SOCs6 *7 * Documentation for this SCCG pll can be found at:8 *   https://www.nxp.com/docs/en/reference-manual/IMX8MDQLQRM.pdf#page=8349 */10 11#include <linux/clk-provider.h>12#include <linux/err.h>13#include <linux/export.h>14#include <linux/io.h>15#include <linux/iopoll.h>16#include <linux/slab.h>17#include <linux/bitfield.h>18 19#include "clk.h"20 21/* PLL CFGs */22#define PLL_CFG0		0x023#define PLL_CFG1		0x424#define PLL_CFG2		0x825 26#define PLL_DIVF1_MASK		GENMASK(18, 13)27#define PLL_DIVF2_MASK		GENMASK(12, 7)28#define PLL_DIVR1_MASK		GENMASK(27, 25)29#define PLL_DIVR2_MASK		GENMASK(24, 19)30#define PLL_DIVQ_MASK           GENMASK(6, 1)31#define PLL_REF_MASK		GENMASK(2, 0)32 33#define PLL_LOCK_MASK		BIT(31)34#define PLL_PD_MASK		BIT(7)35 36/* These are the specification limits for the SSCG PLL */37#define PLL_REF_MIN_FREQ		25000000UL38#define PLL_REF_MAX_FREQ		235000000UL39 40#define PLL_STAGE1_MIN_FREQ		1600000000UL41#define PLL_STAGE1_MAX_FREQ		2400000000UL42 43#define PLL_STAGE1_REF_MIN_FREQ		25000000UL44#define PLL_STAGE1_REF_MAX_FREQ		54000000UL45 46#define PLL_STAGE2_MIN_FREQ		1200000000UL47#define PLL_STAGE2_MAX_FREQ		2400000000UL48 49#define PLL_STAGE2_REF_MIN_FREQ		54000000UL50#define PLL_STAGE2_REF_MAX_FREQ		75000000UL51 52#define PLL_OUT_MIN_FREQ		20000000UL53#define PLL_OUT_MAX_FREQ		1200000000UL54 55#define PLL_DIVR1_MAX			756#define PLL_DIVR2_MAX			6357#define PLL_DIVF1_MAX			6358#define PLL_DIVF2_MAX			6359#define PLL_DIVQ_MAX			6360 61#define PLL_BYPASS_NONE			0x062#define PLL_BYPASS1			0x263#define PLL_BYPASS2			0x164 65#define SSCG_PLL_BYPASS1_MASK           BIT(5)66#define SSCG_PLL_BYPASS2_MASK           BIT(4)67#define SSCG_PLL_BYPASS_MASK		GENMASK(5, 4)68 69#define PLL_SCCG_LOCK_TIMEOUT		7070 71struct clk_sscg_pll_setup {72	int divr1, divf1;73	int divr2, divf2;74	int divq;75	int bypass;76	uint64_t vco1;77	uint64_t vco2;78	uint64_t fout;79	uint64_t ref;80	uint64_t ref_div1;81	uint64_t ref_div2;82	uint64_t fout_request;83	int fout_error;84};85 86struct clk_sscg_pll {87	struct clk_hw	hw;88	const struct clk_ops  ops;89	void __iomem *base;90	struct clk_sscg_pll_setup setup;91	u8 parent;92	u8 bypass1;93	u8 bypass2;94};95 96#define to_clk_sscg_pll(_hw) container_of(_hw, struct clk_sscg_pll, hw)97 98static int clk_sscg_pll_wait_lock(struct clk_sscg_pll *pll)99{100	u32 val;101 102	val = readl_relaxed(pll->base + PLL_CFG0);103 104	/* don't wait for lock if all plls are bypassed */105	if (!(val & SSCG_PLL_BYPASS2_MASK))106		return readl_poll_timeout(pll->base, val, val & PLL_LOCK_MASK,107						0, PLL_SCCG_LOCK_TIMEOUT);108 109	return 0;110}111 112static int clk_sscg_pll2_check_match(struct clk_sscg_pll_setup *setup,113					struct clk_sscg_pll_setup *temp_setup)114{115	int new_diff = temp_setup->fout - temp_setup->fout_request;116	int diff = temp_setup->fout_error;117 118	if (abs(diff) > abs(new_diff)) {119		temp_setup->fout_error = new_diff;120		memcpy(setup, temp_setup, sizeof(struct clk_sscg_pll_setup));121 122		if (temp_setup->fout_request == temp_setup->fout)123			return 0;124	}125	return -1;126}127 128static int clk_sscg_divq_lookup(struct clk_sscg_pll_setup *setup,129				struct clk_sscg_pll_setup *temp_setup)130{131	int ret = -EINVAL;132 133	for (temp_setup->divq = 0; temp_setup->divq <= PLL_DIVQ_MAX;134	     temp_setup->divq++) {135		temp_setup->vco2 = temp_setup->vco1;136		do_div(temp_setup->vco2, temp_setup->divr2 + 1);137		temp_setup->vco2 *= 2;138		temp_setup->vco2 *= temp_setup->divf2 + 1;139		if (temp_setup->vco2 >= PLL_STAGE2_MIN_FREQ &&140				temp_setup->vco2 <= PLL_STAGE2_MAX_FREQ) {141			temp_setup->fout = temp_setup->vco2;142			do_div(temp_setup->fout, 2 * (temp_setup->divq + 1));143 144			ret = clk_sscg_pll2_check_match(setup, temp_setup);145			if (!ret) {146				temp_setup->bypass = PLL_BYPASS1;147				return ret;148			}149		}150	}151 152	return ret;153}154 155static int clk_sscg_divf2_lookup(struct clk_sscg_pll_setup *setup,156					struct clk_sscg_pll_setup *temp_setup)157{158	int ret = -EINVAL;159 160	for (temp_setup->divf2 = 0; temp_setup->divf2 <= PLL_DIVF2_MAX;161	     temp_setup->divf2++) {162		ret = clk_sscg_divq_lookup(setup, temp_setup);163		if (!ret)164			return ret;165	}166 167	return ret;168}169 170static int clk_sscg_divr2_lookup(struct clk_sscg_pll_setup *setup,171				struct clk_sscg_pll_setup *temp_setup)172{173	int ret = -EINVAL;174 175	for (temp_setup->divr2 = 0; temp_setup->divr2 <= PLL_DIVR2_MAX;176	     temp_setup->divr2++) {177		temp_setup->ref_div2 = temp_setup->vco1;178		do_div(temp_setup->ref_div2, temp_setup->divr2 + 1);179		if (temp_setup->ref_div2 >= PLL_STAGE2_REF_MIN_FREQ &&180		    temp_setup->ref_div2 <= PLL_STAGE2_REF_MAX_FREQ) {181			ret = clk_sscg_divf2_lookup(setup, temp_setup);182			if (!ret)183				return ret;184		}185	}186 187	return ret;188}189 190static int clk_sscg_pll2_find_setup(struct clk_sscg_pll_setup *setup,191					struct clk_sscg_pll_setup *temp_setup,192					uint64_t ref)193{194	int ret;195 196	if (ref < PLL_STAGE1_MIN_FREQ || ref > PLL_STAGE1_MAX_FREQ)197		return -EINVAL;198 199	temp_setup->vco1 = ref;200 201	ret = clk_sscg_divr2_lookup(setup, temp_setup);202	return ret;203}204 205static int clk_sscg_divf1_lookup(struct clk_sscg_pll_setup *setup,206				struct clk_sscg_pll_setup *temp_setup)207{208	int ret = -EINVAL;209 210	for (temp_setup->divf1 = 0; temp_setup->divf1 <= PLL_DIVF1_MAX;211	     temp_setup->divf1++) {212		uint64_t vco1 = temp_setup->ref;213 214		do_div(vco1, temp_setup->divr1 + 1);215		vco1 *= 2;216		vco1 *= temp_setup->divf1 + 1;217 218		ret = clk_sscg_pll2_find_setup(setup, temp_setup, vco1);219		if (!ret) {220			temp_setup->bypass = PLL_BYPASS_NONE;221			return ret;222		}223	}224 225	return ret;226}227 228static int clk_sscg_divr1_lookup(struct clk_sscg_pll_setup *setup,229				struct clk_sscg_pll_setup *temp_setup)230{231	int ret = -EINVAL;232 233	for (temp_setup->divr1 = 0; temp_setup->divr1 <= PLL_DIVR1_MAX;234	     temp_setup->divr1++) {235		temp_setup->ref_div1 = temp_setup->ref;236		do_div(temp_setup->ref_div1, temp_setup->divr1 + 1);237		if (temp_setup->ref_div1 >= PLL_STAGE1_REF_MIN_FREQ &&238		    temp_setup->ref_div1 <= PLL_STAGE1_REF_MAX_FREQ) {239			ret = clk_sscg_divf1_lookup(setup, temp_setup);240			if (!ret)241				return ret;242		}243	}244 245	return ret;246}247 248static int clk_sscg_pll1_find_setup(struct clk_sscg_pll_setup *setup,249					struct clk_sscg_pll_setup *temp_setup,250					uint64_t ref)251{252	int ret;253 254	if (ref < PLL_REF_MIN_FREQ || ref > PLL_REF_MAX_FREQ)255		return -EINVAL;256 257	temp_setup->ref = ref;258 259	ret = clk_sscg_divr1_lookup(setup, temp_setup);260 261	return ret;262}263 264static int clk_sscg_pll_find_setup(struct clk_sscg_pll_setup *setup,265					uint64_t prate,266					uint64_t rate, int try_bypass)267{268	struct clk_sscg_pll_setup temp_setup;269	int ret = -EINVAL;270 271	memset(&temp_setup, 0, sizeof(struct clk_sscg_pll_setup));272	memset(setup, 0, sizeof(struct clk_sscg_pll_setup));273 274	temp_setup.fout_error = PLL_OUT_MAX_FREQ;275	temp_setup.fout_request = rate;276 277	switch (try_bypass) {278	case PLL_BYPASS2:279		if (prate == rate) {280			setup->bypass = PLL_BYPASS2;281			setup->fout = rate;282			ret = 0;283		}284		break;285	case PLL_BYPASS1:286		ret = clk_sscg_pll2_find_setup(setup, &temp_setup, prate);287		break;288	case PLL_BYPASS_NONE:289		ret = clk_sscg_pll1_find_setup(setup, &temp_setup, prate);290		break;291	}292 293	return ret;294}295 296static int clk_sscg_pll_is_prepared(struct clk_hw *hw)297{298	struct clk_sscg_pll *pll = to_clk_sscg_pll(hw);299 300	u32 val = readl_relaxed(pll->base + PLL_CFG0);301 302	return (val & PLL_PD_MASK) ? 0 : 1;303}304 305static int clk_sscg_pll_prepare(struct clk_hw *hw)306{307	struct clk_sscg_pll *pll = to_clk_sscg_pll(hw);308	u32 val;309 310	val = readl_relaxed(pll->base + PLL_CFG0);311	val &= ~PLL_PD_MASK;312	writel_relaxed(val, pll->base + PLL_CFG0);313 314	return clk_sscg_pll_wait_lock(pll);315}316 317static void clk_sscg_pll_unprepare(struct clk_hw *hw)318{319	struct clk_sscg_pll *pll = to_clk_sscg_pll(hw);320	u32 val;321 322	val = readl_relaxed(pll->base + PLL_CFG0);323	val |= PLL_PD_MASK;324	writel_relaxed(val, pll->base + PLL_CFG0);325}326 327static unsigned long clk_sscg_pll_recalc_rate(struct clk_hw *hw,328					 unsigned long parent_rate)329{330	struct clk_sscg_pll *pll = to_clk_sscg_pll(hw);331	u32 val, divr1, divf1, divr2, divf2, divq;332	u64 temp64;333 334	val = readl_relaxed(pll->base + PLL_CFG2);335	divr1 = FIELD_GET(PLL_DIVR1_MASK, val);336	divr2 = FIELD_GET(PLL_DIVR2_MASK, val);337	divf1 = FIELD_GET(PLL_DIVF1_MASK, val);338	divf2 = FIELD_GET(PLL_DIVF2_MASK, val);339	divq = FIELD_GET(PLL_DIVQ_MASK, val);340 341	temp64 = parent_rate;342 343	val = readl(pll->base + PLL_CFG0);344	if (val & SSCG_PLL_BYPASS2_MASK) {345		temp64 = parent_rate;346	} else if (val & SSCG_PLL_BYPASS1_MASK) {347		temp64 *= divf2;348		do_div(temp64, (divr2 + 1) * (divq + 1));349	} else {350		temp64 *= 2;351		temp64 *= (divf1 + 1) * (divf2 + 1);352		do_div(temp64, (divr1 + 1) * (divr2 + 1) * (divq + 1));353	}354 355	return temp64;356}357 358static int clk_sscg_pll_set_rate(struct clk_hw *hw, unsigned long rate,359			    unsigned long parent_rate)360{361	struct clk_sscg_pll *pll = to_clk_sscg_pll(hw);362	struct clk_sscg_pll_setup *setup = &pll->setup;363	u32 val;364 365	/* set bypass here too since the parent might be the same */366	val = readl(pll->base + PLL_CFG0);367	val &= ~SSCG_PLL_BYPASS_MASK;368	val |= FIELD_PREP(SSCG_PLL_BYPASS_MASK, setup->bypass);369	writel(val, pll->base + PLL_CFG0);370 371	val = readl_relaxed(pll->base + PLL_CFG2);372	val &= ~(PLL_DIVF1_MASK | PLL_DIVF2_MASK);373	val &= ~(PLL_DIVR1_MASK | PLL_DIVR2_MASK | PLL_DIVQ_MASK);374	val |= FIELD_PREP(PLL_DIVF1_MASK, setup->divf1);375	val |= FIELD_PREP(PLL_DIVF2_MASK, setup->divf2);376	val |= FIELD_PREP(PLL_DIVR1_MASK, setup->divr1);377	val |= FIELD_PREP(PLL_DIVR2_MASK, setup->divr2);378	val |= FIELD_PREP(PLL_DIVQ_MASK, setup->divq);379	writel_relaxed(val, pll->base + PLL_CFG2);380 381	return clk_sscg_pll_wait_lock(pll);382}383 384static u8 clk_sscg_pll_get_parent(struct clk_hw *hw)385{386	struct clk_sscg_pll *pll = to_clk_sscg_pll(hw);387	u32 val;388	u8 ret = pll->parent;389 390	val = readl(pll->base + PLL_CFG0);391	if (val & SSCG_PLL_BYPASS2_MASK)392		ret = pll->bypass2;393	else if (val & SSCG_PLL_BYPASS1_MASK)394		ret = pll->bypass1;395	return ret;396}397 398static int clk_sscg_pll_set_parent(struct clk_hw *hw, u8 index)399{400	struct clk_sscg_pll *pll = to_clk_sscg_pll(hw);401	u32 val;402 403	val = readl(pll->base + PLL_CFG0);404	val &= ~SSCG_PLL_BYPASS_MASK;405	val |= FIELD_PREP(SSCG_PLL_BYPASS_MASK, pll->setup.bypass);406	writel(val, pll->base + PLL_CFG0);407 408	return clk_sscg_pll_wait_lock(pll);409}410 411static int __clk_sscg_pll_determine_rate(struct clk_hw *hw,412					struct clk_rate_request *req,413					uint64_t min,414					uint64_t max,415					uint64_t rate,416					int bypass)417{418	struct clk_sscg_pll *pll = to_clk_sscg_pll(hw);419	struct clk_sscg_pll_setup *setup = &pll->setup;420	struct clk_hw *parent_hw = NULL;421	int bypass_parent_index;422	int ret;423 424	req->max_rate = max;425	req->min_rate = min;426 427	switch (bypass) {428	case PLL_BYPASS2:429		bypass_parent_index = pll->bypass2;430		break;431	case PLL_BYPASS1:432		bypass_parent_index = pll->bypass1;433		break;434	default:435		bypass_parent_index = pll->parent;436		break;437	}438 439	parent_hw = clk_hw_get_parent_by_index(hw, bypass_parent_index);440	ret = __clk_determine_rate(parent_hw, req);441	if (!ret) {442		ret = clk_sscg_pll_find_setup(setup, req->rate,443						rate, bypass);444	}445 446	req->best_parent_hw = parent_hw;447	req->best_parent_rate = req->rate;448	req->rate = setup->fout;449 450	return ret;451}452 453static int clk_sscg_pll_determine_rate(struct clk_hw *hw,454				       struct clk_rate_request *req)455{456	struct clk_sscg_pll *pll = to_clk_sscg_pll(hw);457	struct clk_sscg_pll_setup *setup = &pll->setup;458	uint64_t rate = req->rate;459	uint64_t min = req->min_rate;460	uint64_t max = req->max_rate;461	int ret;462 463	if (rate < PLL_OUT_MIN_FREQ || rate > PLL_OUT_MAX_FREQ)464		return -EINVAL;465 466	ret = __clk_sscg_pll_determine_rate(hw, req, req->rate, req->rate,467						rate, PLL_BYPASS2);468	if (!ret)469		return ret;470 471	ret = __clk_sscg_pll_determine_rate(hw, req, PLL_STAGE1_REF_MIN_FREQ,472						PLL_STAGE1_REF_MAX_FREQ, rate,473						PLL_BYPASS1);474	if (!ret)475		return ret;476 477	ret = __clk_sscg_pll_determine_rate(hw, req, PLL_REF_MIN_FREQ,478						PLL_REF_MAX_FREQ, rate,479						PLL_BYPASS_NONE);480	if (!ret)481		return ret;482 483	if (setup->fout >= min && setup->fout <= max)484		ret = 0;485 486	return ret;487}488 489static const struct clk_ops clk_sscg_pll_ops = {490	.prepare	= clk_sscg_pll_prepare,491	.unprepare	= clk_sscg_pll_unprepare,492	.is_prepared	= clk_sscg_pll_is_prepared,493	.recalc_rate	= clk_sscg_pll_recalc_rate,494	.set_rate	= clk_sscg_pll_set_rate,495	.set_parent	= clk_sscg_pll_set_parent,496	.get_parent	= clk_sscg_pll_get_parent,497	.determine_rate	= clk_sscg_pll_determine_rate,498};499 500struct clk_hw *imx_clk_hw_sscg_pll(const char *name,501				const char * const *parent_names,502				u8 num_parents,503				u8 parent, u8 bypass1, u8 bypass2,504				void __iomem *base,505				unsigned long flags)506{507	struct clk_sscg_pll *pll;508	struct clk_init_data init;509	struct clk_hw *hw;510	int ret;511 512	pll = kzalloc(sizeof(*pll), GFP_KERNEL);513	if (!pll)514		return ERR_PTR(-ENOMEM);515 516	pll->parent = parent;517	pll->bypass1 = bypass1;518	pll->bypass2 = bypass2;519 520	pll->base = base;521	init.name = name;522	init.ops = &clk_sscg_pll_ops;523 524	init.flags = flags;525	init.parent_names = parent_names;526	init.num_parents = num_parents;527 528	pll->hw.init = &init;529 530	hw = &pll->hw;531 532	ret = clk_hw_register(NULL, hw);533	if (ret) {534		kfree(pll);535		return ERR_PTR(ret);536	}537 538	return hw;539}540EXPORT_SYMBOL_GPL(imx_clk_hw_sscg_pll);541