brintos

brintos / linux-shallow public Read only

0
0
Text · 6.7 KiB · ebee2af Raw
252 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Marvell PXA family clocks4 *5 * Copyright (C) 2014 Robert Jarzmik6 *7 * Common clock code for PXA clocks ("CKEN" type clocks + DT)8 */9#include <linux/clk.h>10#include <linux/clk-provider.h>11#include <linux/clkdev.h>12#include <linux/io.h>13#include <linux/of.h>14#include <linux/soc/pxa/smemc.h>15 16#include <dt-bindings/clock/pxa-clock.h>17#include "clk-pxa.h"18 19#define KHz 100020#define MHz (1000 * 1000)21 22#define MDREFR_K0DB4	(1 << 29)	/* SDCLK0 Divide by 4 Control/Status */23#define MDREFR_K2FREE	(1 << 25)	/* SDRAM Free-Running Control */24#define MDREFR_K1FREE	(1 << 24)	/* SDRAM Free-Running Control */25#define MDREFR_K0FREE	(1 << 23)	/* SDRAM Free-Running Control */26#define MDREFR_SLFRSH	(1 << 22)	/* SDRAM Self-Refresh Control/Status */27#define MDREFR_APD	(1 << 20)	/* SDRAM/SSRAM Auto-Power-Down Enable */28#define MDREFR_K2DB2	(1 << 19)	/* SDCLK2 Divide by 2 Control/Status */29#define MDREFR_K2RUN	(1 << 18)	/* SDCLK2 Run Control/Status */30#define MDREFR_K1DB2	(1 << 17)	/* SDCLK1 Divide by 2 Control/Status */31#define MDREFR_K1RUN	(1 << 16)	/* SDCLK1 Run Control/Status */32#define MDREFR_E1PIN	(1 << 15)	/* SDCKE1 Level Control/Status */33#define MDREFR_K0DB2	(1 << 14)	/* SDCLK0 Divide by 2 Control/Status */34#define MDREFR_K0RUN	(1 << 13)	/* SDCLK0 Run Control/Status */35#define MDREFR_E0PIN	(1 << 12)	/* SDCKE0 Level Control/Status */36#define MDREFR_DB2_MASK	(MDREFR_K2DB2 | MDREFR_K1DB2)37#define MDREFR_DRI_MASK	0xFFF38 39static DEFINE_SPINLOCK(pxa_clk_lock);40 41static struct clk *pxa_clocks[CLK_MAX];42static struct clk_onecell_data onecell_data = {43	.clks = pxa_clocks,44	.clk_num = CLK_MAX,45};46 47struct pxa_clk {48	struct clk_hw hw;49	struct clk_fixed_factor lp;50	struct clk_fixed_factor hp;51	struct clk_gate gate;52	bool (*is_in_low_power)(void);53};54 55#define to_pxa_clk(_hw) container_of(_hw, struct pxa_clk, hw)56 57static unsigned long cken_recalc_rate(struct clk_hw *hw,58				      unsigned long parent_rate)59{60	struct pxa_clk *pclk = to_pxa_clk(hw);61	struct clk_fixed_factor *fix;62 63	if (!pclk->is_in_low_power || pclk->is_in_low_power())64		fix = &pclk->lp;65	else66		fix = &pclk->hp;67	__clk_hw_set_clk(&fix->hw, hw);68	return clk_fixed_factor_ops.recalc_rate(&fix->hw, parent_rate);69}70 71static const struct clk_ops cken_rate_ops = {72	.recalc_rate = cken_recalc_rate,73};74 75static u8 cken_get_parent(struct clk_hw *hw)76{77	struct pxa_clk *pclk = to_pxa_clk(hw);78 79	if (!pclk->is_in_low_power)80		return 0;81	return pclk->is_in_low_power() ? 0 : 1;82}83 84static const struct clk_ops cken_mux_ops = {85	.determine_rate = clk_hw_determine_rate_no_reparent,86	.get_parent = cken_get_parent,87	.set_parent = dummy_clk_set_parent,88};89 90void __init clkdev_pxa_register(int ckid, const char *con_id,91				const char *dev_id, struct clk *clk)92{93	if (!IS_ERR(clk) && (ckid != CLK_NONE))94		pxa_clocks[ckid] = clk;95	if (!IS_ERR(clk))96		clk_register_clkdev(clk, con_id, dev_id);97}98 99int __init clk_pxa_cken_init(const struct desc_clk_cken *clks,100			     int nb_clks, void __iomem *clk_regs)101{102	int i;103	struct pxa_clk *pxa_clk;104	struct clk *clk;105 106	for (i = 0; i < nb_clks; i++) {107		pxa_clk = kzalloc(sizeof(*pxa_clk), GFP_KERNEL);108		if (!pxa_clk)109			return -ENOMEM;110		pxa_clk->is_in_low_power = clks[i].is_in_low_power;111		pxa_clk->lp = clks[i].lp;112		pxa_clk->hp = clks[i].hp;113		pxa_clk->gate = clks[i].gate;114		pxa_clk->gate.reg = clk_regs + clks[i].cken_reg;115		pxa_clk->gate.lock = &pxa_clk_lock;116		clk = clk_register_composite(NULL, clks[i].name,117					     clks[i].parent_names, 2,118					     &pxa_clk->hw, &cken_mux_ops,119					     &pxa_clk->hw, &cken_rate_ops,120					     &pxa_clk->gate.hw, &clk_gate_ops,121					     clks[i].flags);122		clkdev_pxa_register(clks[i].ckid, clks[i].con_id,123				    clks[i].dev_id, clk);124	}125	return 0;126}127 128void __init clk_pxa_dt_common_init(struct device_node *np)129{130	of_clk_add_provider(np, of_clk_src_onecell_get, &onecell_data);131}132 133void pxa2xx_core_turbo_switch(bool on)134{135	unsigned long flags;136	unsigned int unused, clkcfg;137 138	local_irq_save(flags);139 140	asm("mrc p14, 0, %0, c6, c0, 0" : "=r" (clkcfg));141	clkcfg &= ~CLKCFG_TURBO & ~CLKCFG_HALFTURBO;142	if (on)143		clkcfg |= CLKCFG_TURBO;144	clkcfg |= CLKCFG_FCS;145 146	asm volatile(147	"	b	2f\n"148	"	.align	5\n"149	"1:	mcr	p14, 0, %1, c6, c0, 0\n"150	"	b	3f\n"151	"2:	b	1b\n"152	"3:	nop\n"153		: "=&r" (unused) : "r" (clkcfg));154 155	local_irq_restore(flags);156}157 158void pxa2xx_cpll_change(struct pxa2xx_freq *freq,159			u32 (*mdrefr_dri)(unsigned int),160			void __iomem *cccr)161{162	unsigned int clkcfg = freq->clkcfg;163	unsigned int unused, preset_mdrefr, postset_mdrefr;164	unsigned long flags;165	void __iomem *mdrefr = pxa_smemc_get_mdrefr();166 167	local_irq_save(flags);168 169	/* Calculate the next MDREFR.  If we're slowing down the SDRAM clock170	 * we need to preset the smaller DRI before the change.	 If we're171	 * speeding up we need to set the larger DRI value after the change.172	 */173	preset_mdrefr = postset_mdrefr = readl(mdrefr);174	if ((preset_mdrefr & MDREFR_DRI_MASK) > mdrefr_dri(freq->membus_khz)) {175		preset_mdrefr = (preset_mdrefr & ~MDREFR_DRI_MASK);176		preset_mdrefr |= mdrefr_dri(freq->membus_khz);177	}178	postset_mdrefr =179		(postset_mdrefr & ~MDREFR_DRI_MASK) |180		mdrefr_dri(freq->membus_khz);181 182	/* If we're dividing the memory clock by two for the SDRAM clock, this183	 * must be set prior to the change.  Clearing the divide must be done184	 * after the change.185	 */186	if (freq->div2) {187		preset_mdrefr  |= MDREFR_DB2_MASK;188		postset_mdrefr |= MDREFR_DB2_MASK;189	} else {190		postset_mdrefr &= ~MDREFR_DB2_MASK;191	}192 193	/* Set new the CCCR and prepare CLKCFG */194	writel(freq->cccr, cccr);195 196	asm volatile(197	"	ldr	r4, [%1]\n"198	"	b	2f\n"199	"	.align	5\n"200	"1:	str	%3, [%1]		/* preset the MDREFR */\n"201	"	mcr	p14, 0, %2, c6, c0, 0	/* set CLKCFG[FCS] */\n"202	"	str	%4, [%1]		/* postset the MDREFR */\n"203	"	b	3f\n"204	"2:	b	1b\n"205	"3:	nop\n"206	     : "=&r" (unused)207	     : "r" (mdrefr), "r" (clkcfg), "r" (preset_mdrefr),208	       "r" (postset_mdrefr)209	     : "r4", "r5");210 211	local_irq_restore(flags);212}213 214int pxa2xx_determine_rate(struct clk_rate_request *req,215			  struct pxa2xx_freq *freqs, int nb_freqs)216{217	int i, closest_below = -1, closest_above = -1;218	unsigned long rate;219 220	for (i = 0; i < nb_freqs; i++) {221		rate = freqs[i].cpll;222		if (rate == req->rate)223			break;224		if (rate < req->min_rate)225			continue;226		if (rate > req->max_rate)227			continue;228		if (rate <= req->rate)229			closest_below = i;230		if ((rate >= req->rate) && (closest_above == -1))231			closest_above = i;232	}233 234	req->best_parent_hw = NULL;235 236	if (i < nb_freqs) {237		rate = req->rate;238	} else if (closest_below >= 0) {239		rate = freqs[closest_below].cpll;240	} else if (closest_above >= 0) {241		rate = freqs[closest_above].cpll;242	} else {243		pr_debug("%s(rate=%lu) no match\n", __func__, req->rate);244		return -EINVAL;245	}246 247	pr_debug("%s(rate=%lu) rate=%lu\n", __func__, req->rate, rate);248	req->rate = rate;249 250	return 0;251}252