brintos

brintos / linux-shallow public Read only

0
0
Text · 9.2 KiB · 4c37649 Raw
392 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * R-Car Gen2 Clock Pulse Generator4 *5 * Copyright (C) 2016 Cogent Embedded Inc.6 */7 8#include <linux/bug.h>9#include <linux/clk.h>10#include <linux/clk-provider.h>11#include <linux/device.h>12#include <linux/err.h>13#include <linux/init.h>14#include <linux/io.h>15#include <linux/slab.h>16#include <linux/sys_soc.h>17 18#include "renesas-cpg-mssr.h"19#include "rcar-gen2-cpg.h"20 21#define CPG_FRQCRB		0x000422#define CPG_FRQCRB_KICK		BIT(31)23#define CPG_SDCKCR		0x007424#define CPG_PLL0CR		0x00d825#define CPG_PLL0CR_STC_SHIFT	2426#define CPG_PLL0CR_STC_MASK	(0x7f << CPG_PLL0CR_STC_SHIFT)27#define CPG_FRQCRC		0x00e028#define CPG_FRQCRC_ZFC_SHIFT	829#define CPG_FRQCRC_ZFC_MASK	(0x1f << CPG_FRQCRC_ZFC_SHIFT)30#define CPG_ADSPCKCR		0x025c31#define CPG_RCANCKCR		0x027032 33static DEFINE_SPINLOCK(cpg_lock);34 35/*36 * Z Clock37 *38 * Traits of this clock:39 * prepare - clk_prepare only ensures that parents are prepared40 * enable - clk_enable only ensures that parents are enabled41 * rate - rate is adjustable.  clk->rate = parent->rate * mult / 3242 * parent - fixed parent.  No clk_set_parent support43 */44 45struct cpg_z_clk {46	struct clk_hw hw;47	void __iomem *reg;48	void __iomem *kick_reg;49};50 51#define to_z_clk(_hw)	container_of(_hw, struct cpg_z_clk, hw)52 53static unsigned long cpg_z_clk_recalc_rate(struct clk_hw *hw,54					   unsigned long parent_rate)55{56	struct cpg_z_clk *zclk = to_z_clk(hw);57	unsigned int mult;58	unsigned int val;59 60	val = (readl(zclk->reg) & CPG_FRQCRC_ZFC_MASK) >> CPG_FRQCRC_ZFC_SHIFT;61	mult = 32 - val;62 63	return div_u64((u64)parent_rate * mult, 32);64}65 66static int cpg_z_clk_determine_rate(struct clk_hw *hw,67				    struct clk_rate_request *req)68{69	unsigned long prate = req->best_parent_rate;70	unsigned int min_mult, max_mult, mult;71 72	min_mult = max(div64_ul(req->min_rate * 32ULL, prate), 1ULL);73	max_mult = min(div64_ul(req->max_rate * 32ULL, prate), 32ULL);74	if (max_mult < min_mult)75		return -EINVAL;76 77	mult = div64_ul(req->rate * 32ULL, prate);78	mult = clamp(mult, min_mult, max_mult);79 80	req->rate = div_u64((u64)prate * mult, 32);81	return 0;82}83 84static int cpg_z_clk_set_rate(struct clk_hw *hw, unsigned long rate,85			      unsigned long parent_rate)86{87	struct cpg_z_clk *zclk = to_z_clk(hw);88	unsigned int mult;89	u32 val, kick;90	unsigned int i;91 92	mult = div64_ul(rate * 32ULL, parent_rate);93	mult = clamp(mult, 1U, 32U);94 95	if (readl(zclk->kick_reg) & CPG_FRQCRB_KICK)96		return -EBUSY;97 98	val = readl(zclk->reg);99	val &= ~CPG_FRQCRC_ZFC_MASK;100	val |= (32 - mult) << CPG_FRQCRC_ZFC_SHIFT;101	writel(val, zclk->reg);102 103	/*104	 * Set KICK bit in FRQCRB to update hardware setting and wait for105	 * clock change completion.106	 */107	kick = readl(zclk->kick_reg);108	kick |= CPG_FRQCRB_KICK;109	writel(kick, zclk->kick_reg);110 111	/*112	 * Note: There is no HW information about the worst case latency.113	 *114	 * Using experimental measurements, it seems that no more than115	 * ~10 iterations are needed, independently of the CPU rate.116	 * Since this value might be dependent on external xtal rate, pll1117	 * rate or even the other emulation clocks rate, use 1000 as a118	 * "super" safe value.119	 */120	for (i = 1000; i; i--) {121		if (!(readl(zclk->kick_reg) & CPG_FRQCRB_KICK))122			return 0;123 124		cpu_relax();125	}126 127	return -ETIMEDOUT;128}129 130static const struct clk_ops cpg_z_clk_ops = {131	.recalc_rate = cpg_z_clk_recalc_rate,132	.determine_rate = cpg_z_clk_determine_rate,133	.set_rate = cpg_z_clk_set_rate,134};135 136static struct clk * __init cpg_z_clk_register(const char *name,137					      const char *parent_name,138					      void __iomem *base)139{140	struct clk_init_data init = {};141	struct cpg_z_clk *zclk;142	struct clk *clk;143 144	zclk = kzalloc(sizeof(*zclk), GFP_KERNEL);145	if (!zclk)146		return ERR_PTR(-ENOMEM);147 148	init.name = name;149	init.ops = &cpg_z_clk_ops;150	init.parent_names = &parent_name;151	init.num_parents = 1;152 153	zclk->reg = base + CPG_FRQCRC;154	zclk->kick_reg = base + CPG_FRQCRB;155	zclk->hw.init = &init;156 157	clk = clk_register(NULL, &zclk->hw);158	if (IS_ERR(clk))159		kfree(zclk);160 161	return clk;162}163 164static struct clk * __init cpg_rcan_clk_register(const char *name,165						 const char *parent_name,166						 void __iomem *base)167{168	struct clk_fixed_factor *fixed;169	struct clk_gate *gate;170	struct clk *clk;171 172	fixed = kzalloc(sizeof(*fixed), GFP_KERNEL);173	if (!fixed)174		return ERR_PTR(-ENOMEM);175 176	fixed->mult = 1;177	fixed->div = 6;178 179	gate = kzalloc(sizeof(*gate), GFP_KERNEL);180	if (!gate) {181		kfree(fixed);182		return ERR_PTR(-ENOMEM);183	}184 185	gate->reg = base + CPG_RCANCKCR;186	gate->bit_idx = 8;187	gate->flags = CLK_GATE_SET_TO_DISABLE;188	gate->lock = &cpg_lock;189 190	clk = clk_register_composite(NULL, name, &parent_name, 1, NULL, NULL,191				     &fixed->hw, &clk_fixed_factor_ops,192				     &gate->hw, &clk_gate_ops, 0);193	if (IS_ERR(clk)) {194		kfree(gate);195		kfree(fixed);196	}197 198	return clk;199}200 201/* ADSP divisors */202static const struct clk_div_table cpg_adsp_div_table[] = {203	{  1,  3 }, {  2,  4 }, {  3,  6 }, {  4,  8 },204	{  5, 12 }, {  6, 16 }, {  7, 18 }, {  8, 24 },205	{ 10, 36 }, { 11, 48 }, {  0,  0 },206};207 208static struct clk * __init cpg_adsp_clk_register(const char *name,209						 const char *parent_name,210						 void __iomem *base)211{212	struct clk_divider *div;213	struct clk_gate *gate;214	struct clk *clk;215 216	div = kzalloc(sizeof(*div), GFP_KERNEL);217	if (!div)218		return ERR_PTR(-ENOMEM);219 220	div->reg = base + CPG_ADSPCKCR;221	div->width = 4;222	div->table = cpg_adsp_div_table;223	div->lock = &cpg_lock;224 225	gate = kzalloc(sizeof(*gate), GFP_KERNEL);226	if (!gate) {227		kfree(div);228		return ERR_PTR(-ENOMEM);229	}230 231	gate->reg = base + CPG_ADSPCKCR;232	gate->bit_idx = 8;233	gate->flags = CLK_GATE_SET_TO_DISABLE;234	gate->lock = &cpg_lock;235 236	clk = clk_register_composite(NULL, name, &parent_name, 1, NULL, NULL,237				     &div->hw, &clk_divider_ops,238				     &gate->hw, &clk_gate_ops, 0);239	if (IS_ERR(clk)) {240		kfree(gate);241		kfree(div);242	}243 244	return clk;245}246 247/* SDHI divisors */248static const struct clk_div_table cpg_sdh_div_table[] = {249	{  0,  2 }, {  1,  3 }, {  2,  4 }, {  3,  6 },250	{  4,  8 }, {  5, 12 }, {  6, 16 }, {  7, 18 },251	{  8, 24 }, { 10, 36 }, { 11, 48 }, {  0,  0 },252};253 254static const struct clk_div_table cpg_sd01_div_table[] = {255	{  4,  8 }, {  5, 12 }, {  6, 16 }, {  7, 18 },256	{  8, 24 }, { 10, 36 }, { 11, 48 }, { 12, 10 },257	{  0,  0 },258};259 260static const struct rcar_gen2_cpg_pll_config *cpg_pll_config __initdata;261static unsigned int cpg_pll0_div __initdata;262static u32 cpg_mode __initdata;263static u32 cpg_quirks __initdata;264 265#define SD_SKIP_FIRST	BIT(0)		/* Skip first clock in SD table */266 267static const struct soc_device_attribute cpg_quirks_match[] __initconst = {268	{269		.soc_id = "r8a77470",270		.data = (void *)SD_SKIP_FIRST,271	},272	{ /* sentinel */ }273};274 275struct clk * __init rcar_gen2_cpg_clk_register(struct device *dev,276	const struct cpg_core_clk *core, const struct cpg_mssr_info *info,277	struct clk **clks, void __iomem *base,278	struct raw_notifier_head *notifiers)279{280	const struct clk_div_table *table = NULL;281	const struct clk *parent;282	const char *parent_name;283	unsigned int mult = 1;284	unsigned int div = 1;285	unsigned int shift;286 287	parent = clks[core->parent];288	if (IS_ERR(parent))289		return ERR_CAST(parent);290 291	parent_name = __clk_get_name(parent);292 293	switch (core->type) {294	/* R-Car Gen2 */295	case CLK_TYPE_GEN2_MAIN:296		div = cpg_pll_config->extal_div;297		break;298 299	case CLK_TYPE_GEN2_PLL0:300		/*301		 * PLL0 is a  configurable multiplier clock except on R-Car302		 * V2H/E2. Register the PLL0 clock as a fixed factor clock for303		 * now as there's no generic multiplier clock implementation and304		 * we  currently  have no need to change  the multiplier value.305		 */306		mult = cpg_pll_config->pll0_mult;307		div  = cpg_pll0_div;308		if (!mult) {309			u32 pll0cr = readl(base + CPG_PLL0CR);310 311			mult = (((pll0cr & CPG_PLL0CR_STC_MASK) >>312				 CPG_PLL0CR_STC_SHIFT) + 1) * 2;313		}314		break;315 316	case CLK_TYPE_GEN2_PLL1:317		mult = cpg_pll_config->pll1_mult / 2;318		break;319 320	case CLK_TYPE_GEN2_PLL3:321		mult = cpg_pll_config->pll3_mult;322		break;323 324	case CLK_TYPE_GEN2_Z:325		return cpg_z_clk_register(core->name, parent_name, base);326 327	case CLK_TYPE_GEN2_LB:328		div = cpg_mode & BIT(18) ? 36 : 24;329		break;330 331	case CLK_TYPE_GEN2_ADSP:332		return cpg_adsp_clk_register(core->name, parent_name, base);333 334	case CLK_TYPE_GEN2_SDH:335		table = cpg_sdh_div_table;336		shift = 8;337		break;338 339	case CLK_TYPE_GEN2_SD0:340		table = cpg_sd01_div_table;341		if (cpg_quirks & SD_SKIP_FIRST)342			table++;343 344		shift = 4;345		break;346 347	case CLK_TYPE_GEN2_SD1:348		table = cpg_sd01_div_table;349		if (cpg_quirks & SD_SKIP_FIRST)350			table++;351 352		shift = 0;353		break;354 355	case CLK_TYPE_GEN2_QSPI:356		div = (cpg_mode & (BIT(3) | BIT(2) | BIT(1))) == BIT(2) ?357		      8 : 10;358		break;359 360	case CLK_TYPE_GEN2_RCAN:361		return cpg_rcan_clk_register(core->name, parent_name, base);362 363	default:364		return ERR_PTR(-EINVAL);365	}366 367	if (!table)368		return clk_register_fixed_factor(NULL, core->name, parent_name,369						 0, mult, div);370	else371		return clk_register_divider_table(NULL, core->name,372						  parent_name, 0,373						  base + CPG_SDCKCR, shift, 4,374						  0, table, &cpg_lock);375}376 377int __init rcar_gen2_cpg_init(const struct rcar_gen2_cpg_pll_config *config,378			      unsigned int pll0_div, u32 mode)379{380	const struct soc_device_attribute *attr;381 382	cpg_pll_config = config;383	cpg_pll0_div = pll0_div;384	cpg_mode = mode;385	attr = soc_device_match(cpg_quirks_match);386	if (attr)387		cpg_quirks = (uintptr_t)attr->data;388	pr_debug("%s: mode = 0x%x quirks = 0x%x\n", __func__, mode, cpg_quirks);389 390	return 0;391}392