clock24xx.c 21.0 KB
Newer Older
1 2 3
/*
 *  linux/arch/arm/mach-omap2/clock.c
 *
4 5
 *  Copyright (C) 2005-2008 Texas Instruments, Inc.
 *  Copyright (C) 2004-2008 Nokia Corporation
6
 *
7 8 9
 *  Contacts:
 *  Richard Woodruff <r-woodruff2@ti.com>
 *  Paul Walmsley
10
 *
11 12
 *  Based on earlier work by Tuukka Tikkanen, Tony Lindgren,
 *  Gordon McNutt and RidgeRun, Inc.
13 14 15 16 17
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 */
18 19
#undef DEBUG

20 21 22 23 24 25
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/device.h>
#include <linux/list.h>
#include <linux/errno.h>
#include <linux/delay.h>
26
#include <linux/clk.h>
27 28
#include <linux/io.h>
#include <linux/cpufreq.h>
29
#include <linux/bitops.h>
30

31 32
#include <mach/clock.h>
#include <mach/sram.h>
33
#include <asm/div64.h>
34
#include <asm/clkdev.h>
35

36
#include "memory.h"
37 38 39 40 41
#include "clock.h"
#include "prm.h"
#include "prm-regbits-24xx.h"
#include "cm.h"
#include "cm-regbits-24xx.h"
42

43 44 45 46 47
static const struct clkops clkops_oscck;
static const struct clkops clkops_fixed;

#include "clock24xx.h"

48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218
struct omap_clk {
	u32		cpu;
	struct clk_lookup lk;
};

#define CLK(dev, con, ck, cp) 		\
	{				\
		 .cpu = cp,		\
		.lk = {			\
			.dev_id = dev,	\
			.con_id = con,	\
			.clk = ck,	\
		},			\
	}

#define CK_243X	(1 << 0)
#define CK_242X	(1 << 1)

static struct omap_clk omap24xx_clks[] = {
	/* external root sources */
	CLK(NULL,	"func_32k_ck",	&func_32k_ck,	CK_243X | CK_242X),
	CLK(NULL,	"osc_ck",	&osc_ck,	CK_243X | CK_242X),
	CLK(NULL,	"sys_ck",	&sys_ck,	CK_243X | CK_242X),
	CLK(NULL,	"alt_ck",	&alt_ck,	CK_243X | CK_242X),
	/* internal analog sources */
	CLK(NULL,	"dpll_ck",	&dpll_ck,	CK_243X | CK_242X),
	CLK(NULL,	"apll96_ck",	&apll96_ck,	CK_243X | CK_242X),
	CLK(NULL,	"apll54_ck",	&apll54_ck,	CK_243X | CK_242X),
	/* internal prcm root sources */
	CLK(NULL,	"func_54m_ck",	&func_54m_ck,	CK_243X | CK_242X),
	CLK(NULL,	"core_ck",	&core_ck,	CK_243X | CK_242X),
	CLK(NULL,	"func_96m_ck",	&func_96m_ck,	CK_243X | CK_242X),
	CLK(NULL,	"func_48m_ck",	&func_48m_ck,	CK_243X | CK_242X),
	CLK(NULL,	"func_12m_ck",	&func_12m_ck,	CK_243X | CK_242X),
	CLK(NULL,	"ck_wdt1_osc",	&wdt1_osc_ck,	CK_243X | CK_242X),
	CLK(NULL,	"sys_clkout_src", &sys_clkout_src, CK_243X | CK_242X),
	CLK(NULL,	"sys_clkout",	&sys_clkout,	CK_243X | CK_242X),
	CLK(NULL,	"sys_clkout2_src", &sys_clkout2_src, CK_242X),
	CLK(NULL,	"sys_clkout2",	&sys_clkout2,	CK_242X),
	CLK(NULL,	"emul_ck",	&emul_ck,	CK_242X),
	/* mpu domain clocks */
	CLK(NULL,	"mpu_ck",	&mpu_ck,	CK_243X | CK_242X),
	/* dsp domain clocks */
	CLK(NULL,	"dsp_fck",	&dsp_fck,	CK_243X | CK_242X),
	CLK(NULL,	"dsp_irate_ick", &dsp_irate_ick, CK_243X | CK_242X),
	CLK(NULL,	"dsp_ick",	&dsp_ick,	CK_242X),
	CLK(NULL,	"iva2_1_ick",	&iva2_1_ick,	CK_243X),
	CLK(NULL,	"iva1_ifck",	&iva1_ifck,	CK_242X),
	CLK(NULL,	"iva1_mpu_int_ifck", &iva1_mpu_int_ifck, CK_242X),
	/* GFX domain clocks */
	CLK(NULL,	"gfx_3d_fck",	&gfx_3d_fck,	CK_243X | CK_242X),
	CLK(NULL,	"gfx_2d_fck",	&gfx_2d_fck,	CK_243X | CK_242X),
	CLK(NULL,	"gfx_ick",	&gfx_ick,	CK_243X | CK_242X),
	/* Modem domain clocks */
	CLK(NULL,	"mdm_ick",	&mdm_ick,	CK_243X),
	CLK(NULL,	"mdm_osc_ck",	&mdm_osc_ck,	CK_243X),
	/* DSS domain clocks */
	CLK(NULL,	"dss_ick",	&dss_ick,	CK_243X | CK_242X),
	CLK(NULL,	"dss1_fck",	&dss1_fck,	CK_243X | CK_242X),
	CLK(NULL,	"dss2_fck",	&dss2_fck,	CK_243X | CK_242X),
	CLK(NULL,	"dss_54m_fck",	&dss_54m_fck,	CK_243X | CK_242X),
	/* L3 domain clocks */
	CLK(NULL,	"core_l3_ck",	&core_l3_ck,	CK_243X | CK_242X),
	CLK(NULL,	"ssi_fck",	&ssi_ssr_sst_fck, CK_243X | CK_242X),
	CLK(NULL,	"usb_l4_ick",	&usb_l4_ick,	CK_243X | CK_242X),
	/* L4 domain clocks */
	CLK(NULL,	"l4_ck",	&l4_ck,		CK_243X | CK_242X),
	/* virtual meta-group clock */
	CLK(NULL,	"virt_prcm_set", &virt_prcm_set, CK_243X | CK_242X),
	/* general l4 interface ck, multi-parent functional clk */
	CLK(NULL,	"gpt1_ick",	&gpt1_ick,	CK_243X | CK_242X),
	CLK(NULL,	"gpt1_fck",	&gpt1_fck,	CK_243X | CK_242X),
	CLK(NULL,	"gpt2_ick",	&gpt2_ick,	CK_243X | CK_242X),
	CLK(NULL,	"gpt2_fck",	&gpt2_fck,	CK_243X | CK_242X),
	CLK(NULL,	"gpt3_ick",	&gpt3_ick,	CK_243X | CK_242X),
	CLK(NULL,	"gpt3_fck",	&gpt3_fck,	CK_243X | CK_242X),
	CLK(NULL,	"gpt4_ick",	&gpt4_ick,	CK_243X | CK_242X),
	CLK(NULL,	"gpt4_fck",	&gpt4_fck,	CK_243X | CK_242X),
	CLK(NULL,	"gpt5_ick",	&gpt5_ick,	CK_243X | CK_242X),
	CLK(NULL,	"gpt5_fck",	&gpt5_fck,	CK_243X | CK_242X),
	CLK(NULL,	"gpt6_ick",	&gpt6_ick,	CK_243X | CK_242X),
	CLK(NULL,	"gpt6_fck",	&gpt6_fck,	CK_243X | CK_242X),
	CLK(NULL,	"gpt7_ick",	&gpt7_ick,	CK_243X | CK_242X),
	CLK(NULL,	"gpt7_fck",	&gpt7_fck,	CK_243X | CK_242X),
	CLK(NULL,	"gpt8_ick",	&gpt8_ick,	CK_243X | CK_242X),
	CLK(NULL,	"gpt8_fck",	&gpt8_fck,	CK_243X | CK_242X),
	CLK(NULL,	"gpt9_ick",	&gpt9_ick,	CK_243X | CK_242X),
	CLK(NULL,	"gpt9_fck",	&gpt9_fck,	CK_243X | CK_242X),
	CLK(NULL,	"gpt10_ick",	&gpt10_ick,	CK_243X | CK_242X),
	CLK(NULL,	"gpt10_fck",	&gpt10_fck,	CK_243X | CK_242X),
	CLK(NULL,	"gpt11_ick",	&gpt11_ick,	CK_243X | CK_242X),
	CLK(NULL,	"gpt11_fck",	&gpt11_fck,	CK_243X | CK_242X),
	CLK(NULL,	"gpt12_ick",	&gpt12_ick,	CK_243X | CK_242X),
	CLK(NULL,	"gpt12_fck",	&gpt12_fck,	CK_243X | CK_242X),
	CLK("omap-mcbsp.1", "mcbsp_ick", &mcbsp1_ick,	CK_243X | CK_242X),
	CLK("omap-mcbsp.1", "mcbsp_fck", &mcbsp1_fck,	CK_243X | CK_242X),
	CLK("omap-mcbsp.2", "mcbsp_ick", &mcbsp2_ick,	CK_243X | CK_242X),
	CLK("omap-mcbsp.2", "mcbsp_fck", &mcbsp2_fck,	CK_243X | CK_242X),
	CLK("omap-mcbsp.3", "mcbsp_ick", &mcbsp3_ick,	CK_243X),
	CLK("omap-mcbsp.3", "mcbsp_fck", &mcbsp3_fck,	CK_243X),
	CLK("omap-mcbsp.4", "mcbsp_ick", &mcbsp4_ick,	CK_243X),
	CLK("omap-mcbsp.4", "mcbsp_fck", &mcbsp4_fck,	CK_243X),
	CLK("omap-mcbsp.5", "mcbsp_ick", &mcbsp5_ick,	CK_243X),
	CLK("omap-mcbsp.5", "mcbsp_fck", &mcbsp5_fck,	CK_243X),
	CLK("omap2_mcspi.1", "mcspi_ick", &mcspi1_ick,	CK_243X | CK_242X),
	CLK("omap2_mcspi.1", "mcspi_fck", &mcspi1_fck,	CK_243X | CK_242X),
	CLK("omap2_mcspi.2", "mcspi_ick", &mcspi2_ick,	CK_243X | CK_242X),
	CLK("omap2_mcspi.2", "mcspi_fck", &mcspi2_fck,	CK_243X | CK_242X),
	CLK("omap2_mcspi.3", "mcspi_ick", &mcspi3_ick,	CK_243X),
	CLK("omap2_mcspi.3", "mcspi_fck", &mcspi3_fck,	CK_243X),
	CLK(NULL,	"uart1_ick",	&uart1_ick,	CK_243X | CK_242X),
	CLK(NULL,	"uart1_fck",	&uart1_fck,	CK_243X | CK_242X),
	CLK(NULL,	"uart2_ick",	&uart2_ick,	CK_243X | CK_242X),
	CLK(NULL,	"uart2_fck",	&uart2_fck,	CK_243X | CK_242X),
	CLK(NULL,	"uart3_ick",	&uart3_ick,	CK_243X | CK_242X),
	CLK(NULL,	"uart3_fck",	&uart3_fck,	CK_243X | CK_242X),
	CLK(NULL,	"gpios_ick",	&gpios_ick,	CK_243X | CK_242X),
	CLK(NULL,	"gpios_fck",	&gpios_fck,	CK_243X | CK_242X),
	CLK(NULL,	"mpu_wdt_ick",	&mpu_wdt_ick,	CK_243X | CK_242X),
	CLK(NULL,	"mpu_wdt_fck",	&mpu_wdt_fck,	CK_243X | CK_242X),
	CLK(NULL,	"sync_32k_ick",	&sync_32k_ick,	CK_243X | CK_242X),
	CLK(NULL,	"wdt1_ick",	&wdt1_ick,	CK_243X | CK_242X),
	CLK(NULL,	"omapctrl_ick",	&omapctrl_ick,	CK_243X | CK_242X),
	CLK(NULL,	"icr_ick",	&icr_ick,	CK_243X),
	CLK(NULL,	"cam_fck",	&cam_fck,	CK_243X | CK_242X),
	CLK(NULL,	"cam_ick",	&cam_ick,	CK_243X | CK_242X),
	CLK(NULL,	"mailboxes_ick", &mailboxes_ick,	CK_243X | CK_242X),
	CLK(NULL,	"wdt4_ick",	&wdt4_ick,	CK_243X | CK_242X),
	CLK(NULL,	"wdt4_fck",	&wdt4_fck,	CK_243X | CK_242X),
	CLK(NULL,	"wdt3_ick",	&wdt3_ick,	CK_242X),
	CLK(NULL,	"wdt3_fck",	&wdt3_fck,	CK_242X),
	CLK(NULL,	"mspro_ick",	&mspro_ick,	CK_243X | CK_242X),
	CLK(NULL,	"mspro_fck",	&mspro_fck,	CK_243X | CK_242X),
	CLK(NULL,	"mmc_ick",	&mmc_ick,	CK_242X),
	CLK(NULL,	"mmc_fck",	&mmc_fck,	CK_242X),
	CLK(NULL,	"fac_ick",	&fac_ick,	CK_243X | CK_242X),
	CLK(NULL,	"fac_fck",	&fac_fck,	CK_243X | CK_242X),
	CLK(NULL,	"eac_ick",	&eac_ick,	CK_242X),
	CLK(NULL,	"eac_fck",	&eac_fck,	CK_242X),
	CLK(NULL,	"hdq_ick",	&hdq_ick,	CK_243X | CK_242X),
	CLK(NULL,	"hdq_fck",	&hdq_fck,	CK_243X | CK_242X),
	CLK("i2c_omap.1", "i2c_ick",	&i2c1_ick,	CK_243X | CK_242X),
	CLK("i2c_omap.1", "i2c_fck",	&i2c1_fck,	CK_242X),
	CLK("i2c_omap.1", "i2c_fck",	&i2chs1_fck,	CK_243X),
	CLK("i2c_omap.2", "i2c_ick",	&i2c2_ick,	CK_243X | CK_242X),
	CLK("i2c_omap.2", "i2c_fck",	&i2c2_fck,	CK_242X),
	CLK("i2c_omap.2", "i2c_fck",	&i2chs2_fck,	CK_243X),
	CLK(NULL,	"gpmc_fck",	&gpmc_fck,	CK_243X | CK_242X),
	CLK(NULL,	"sdma_fck",	&sdma_fck,	CK_243X | CK_242X),
	CLK(NULL,	"sdma_ick",	&sdma_ick,	CK_243X | CK_242X),
	CLK(NULL,	"vlynq_ick",	&vlynq_ick,	CK_242X),
	CLK(NULL,	"vlynq_fck",	&vlynq_fck,	CK_242X),
	CLK(NULL,	"sdrc_ick",	&sdrc_ick,	CK_243X),
	CLK(NULL,	"des_ick",	&des_ick,	CK_243X | CK_242X),
	CLK(NULL,	"sha_ick",	&sha_ick,	CK_243X | CK_242X),
	CLK(NULL,	"rng_ick",	&rng_ick,	CK_243X | CK_242X),
	CLK(NULL,	"aes_ick",	&aes_ick,	CK_243X | CK_242X),
	CLK(NULL,	"pka_ick",	&pka_ick,	CK_243X | CK_242X),
	CLK(NULL,	"usb_fck",	&usb_fck,	CK_243X | CK_242X),
	CLK(NULL,	"usbhs_ick",	&usbhs_ick,	CK_243X),
	CLK("mmci-omap-hs.0", "mmchs_ick",	&mmchs1_ick,	CK_243X),
	CLK("mmci-omap-hs.0", "mmchs_fck",	&mmchs1_fck,	CK_243X),
	CLK("mmci-omap-hs.1", "mmchs_ick",	&mmchs2_ick,	CK_243X),
	CLK("mmci-omap-hs.1", "mmchs_fck",	&mmchs2_fck,	CK_243X),
	CLK(NULL,	"gpio5_ick",	&gpio5_ick,	CK_243X),
	CLK(NULL,	"gpio5_fck",	&gpio5_fck,	CK_243X),
	CLK(NULL,	"mdm_intc_ick",	&mdm_intc_ick,	CK_243X),
	CLK("mmci-omap-hs.0", "mmchsdb_fck",	&mmchsdb1_fck,	CK_243X),
	CLK("mmci-omap-hs.1", "mmchsdb_fck", 	&mmchsdb2_fck,	CK_243X),
};

219 220 221
/* CM_CLKEN_PLL.EN_{54,96}M_PLL options (24XX) */
#define EN_APLL_STOPPED			0
#define EN_APLL_LOCKED			3
222

223 224 225 226 227 228
/* CM_CLKSEL1_PLL.APLLS_CLKIN options (24XX) */
#define APLLS_CLKIN_19_2MHZ		0
#define APLLS_CLKIN_13MHZ		2
#define APLLS_CLKIN_12MHZ		3

/* #define DOWN_VARIABLE_DPLL 1 */		/* Experimental */
229 230

static struct prcm_config *curr_prcm_set;
231 232
static struct clk *vclk;
static struct clk *sclk;
233 234

/*-------------------------------------------------------------------------
235
 * Omap24xx specific clock functions
236 237
 *-------------------------------------------------------------------------*/

238 239 240 241 242 243 244 245 246 247 248 249 250 251 252
/* This actually returns the rate of core_ck, not dpll_ck. */
static u32 omap2_get_dpll_rate_24xx(struct clk *tclk)
{
	long long dpll_clk;
	u8 amult;

	dpll_clk = omap2_get_dpll_rate(tclk);

	amult = cm_read_mod_reg(PLL_MOD, CM_CLKSEL2);
	amult &= OMAP24XX_CORE_CLK_SRC_MASK;
	dpll_clk *= amult;

	return dpll_clk;
}

253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274
static int omap2_enable_osc_ck(struct clk *clk)
{
	u32 pcc;

	pcc = __raw_readl(OMAP24XX_PRCM_CLKSRC_CTRL);

	__raw_writel(pcc & ~OMAP_AUTOEXTCLKMODE_MASK,
		      OMAP24XX_PRCM_CLKSRC_CTRL);

	return 0;
}

static void omap2_disable_osc_ck(struct clk *clk)
{
	u32 pcc;

	pcc = __raw_readl(OMAP24XX_PRCM_CLKSRC_CTRL);

	__raw_writel(pcc | OMAP_AUTOEXTCLKMODE_MASK,
		      OMAP24XX_PRCM_CLKSRC_CTRL);
}

275 276 277 278 279
static const struct clkops clkops_oscck = {
	.enable		= &omap2_enable_osc_ck,
	.disable	= &omap2_disable_osc_ck,
};

280
#ifdef OLD_CK
281 282 283 284 285 286 287 288 289
/* Recalculate SYST_CLK */
static void omap2_sys_clk_recalc(struct clk * clk)
{
	u32 div = PRCM_CLKSRC_CTRL;
	div &= (1 << 7) | (1 << 6);	/* Test if ext clk divided by 1 or 2 */
	div >>= clk->rate_offset;
	clk->rate = (clk->parent->rate / div);
	propagate_rate(clk);
}
290
#endif	/* OLD_CK */
291 292

/* Enable an APLL if off */
293
static int omap2_clk_fixed_enable(struct clk *clk)
294
{
295
	u32 cval, apll_mask;
296

297
	apll_mask = EN_APLL_LOCKED << clk->enable_bit;
298

299
	cval = cm_read_mod_reg(PLL_MOD, CM_CLKEN);
300

301 302
	if ((cval & apll_mask) == apll_mask)
		return 0;   /* apll already enabled */
303

304 305 306
	cval &= ~apll_mask;
	cval |= apll_mask;
	cm_write_mod_reg(cval, PLL_MOD, CM_CLKEN);
307 308

	if (clk == &apll96_ck)
309
		cval = OMAP24XX_ST_96M_APLL;
310
	else if (clk == &apll54_ck)
311
		cval = OMAP24XX_ST_54M_APLL;
312

313 314 315 316 317 318 319 320
	omap2_wait_clock_ready(OMAP_CM_REGADDR(PLL_MOD, CM_IDLEST), cval,
			    clk->name);

	/*
	 * REVISIT: Should we return an error code if omap2_wait_clock_ready()
	 * fails?
	 */
	return 0;
321 322 323 324 325 326 327
}

/* Stop APLL */
static void omap2_clk_fixed_disable(struct clk *clk)
{
	u32 cval;

328 329 330
	cval = cm_read_mod_reg(PLL_MOD, CM_CLKEN);
	cval &= ~(EN_APLL_LOCKED << clk->enable_bit);
	cm_write_mod_reg(cval, PLL_MOD, CM_CLKEN);
331 332
}

333 334 335 336 337
static const struct clkops clkops_fixed = {
	.enable		= &omap2_clk_fixed_enable,
	.disable	= &omap2_clk_fixed_disable,
};

338 339 340 341
/*
 * Uses the current prcm set to tell if a rate is valid.
 * You can go slower, but not faster within a given rate set.
 */
342
long omap2_dpllcore_round_rate(unsigned long target_rate)
343
{
344
	u32 high, low, core_clk_src;
345

346 347 348 349
	core_clk_src = cm_read_mod_reg(PLL_MOD, CM_CLKSEL2);
	core_clk_src &= OMAP24XX_CORE_CLK_SRC_MASK;

	if (core_clk_src == CORE_CLK_SRC_DPLL) {	/* DPLL clockout */
350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370
		high = curr_prcm_set->dpll_speed * 2;
		low = curr_prcm_set->dpll_speed;
	} else {				/* DPLL clockout x 2 */
		high = curr_prcm_set->dpll_speed;
		low = curr_prcm_set->dpll_speed / 2;
	}

#ifdef DOWN_VARIABLE_DPLL
	if (target_rate > high)
		return high;
	else
		return target_rate;
#else
	if (target_rate > low)
		return high;
	else
		return low;
#endif

}

371
static void omap2_dpllcore_recalc(struct clk *clk)
372 373 374
{
	clk->rate = omap2_get_dpll_rate_24xx(clk);
}
375

376
static int omap2_reprogram_dpllcore(struct clk *clk, unsigned long rate)
377
{
378
	u32 cur_rate, low, mult, div, valid_rate, done_rate;
379 380
	u32 bypass = 0;
	struct prcm_config tmpset;
381 382
	const struct dpll_data *dd;
	unsigned long flags;
383 384 385
	int ret = -EINVAL;

	local_irq_save(flags);
386 387 388
	cur_rate = omap2_get_dpll_rate_24xx(&dpll_ck);
	mult = cm_read_mod_reg(PLL_MOD, CM_CLKSEL2);
	mult &= OMAP24XX_CORE_CLK_SRC_MASK;
389 390

	if ((rate == (cur_rate / 2)) && (mult == 2)) {
391
		omap2_reprogram_sdrc(CORE_CLK_SRC_DPLL, 1);
392
	} else if ((rate == (cur_rate * 2)) && (mult == 1)) {
393
		omap2_reprogram_sdrc(CORE_CLK_SRC_DPLL_X2, 1);
394
	} else if (rate != cur_rate) {
395
		valid_rate = omap2_dpllcore_round_rate(rate);
396 397 398
		if (valid_rate != rate)
			goto dpll_exit;

399
		if (mult == 1)
400 401 402 403
			low = curr_prcm_set->dpll_speed;
		else
			low = curr_prcm_set->dpll_speed / 2;

404 405 406 407 408 409 410
		dd = clk->dpll_data;
		if (!dd)
			goto dpll_exit;

		tmpset.cm_clksel1_pll = __raw_readl(dd->mult_div1_reg);
		tmpset.cm_clksel1_pll &= ~(dd->mult_mask |
					   dd->div1_mask);
411
		div = ((curr_prcm_set->xtal_speed / 1000000) - 1);
412 413
		tmpset.cm_clksel2_pll = cm_read_mod_reg(PLL_MOD, CM_CLKSEL2);
		tmpset.cm_clksel2_pll &= ~OMAP24XX_CORE_CLK_SRC_MASK;
414
		if (rate > low) {
415
			tmpset.cm_clksel2_pll |= CORE_CLK_SRC_DPLL_X2;
416
			mult = ((rate / 2) / 1000000);
417
			done_rate = CORE_CLK_SRC_DPLL_X2;
418
		} else {
419
			tmpset.cm_clksel2_pll |= CORE_CLK_SRC_DPLL;
420
			mult = (rate / 1000000);
421
			done_rate = CORE_CLK_SRC_DPLL;
422
		}
423 424
		tmpset.cm_clksel1_pll |= (div << __ffs(dd->mult_mask));
		tmpset.cm_clksel1_pll |= (mult << __ffs(dd->div1_mask));
425 426

		/* Worst case */
427
		tmpset.base_sdrc_rfr = SDRC_RFR_CTRL_BYPASS;
428 429 430 431

		if (rate == curr_prcm_set->xtal_speed)	/* If asking for 1-1 */
			bypass = 1;

432
		omap2_reprogram_sdrc(CORE_CLK_SRC_DPLL_X2, 1); /* For init_mem */
433 434 435 436 437 438 439 440 441

		/* Force dll lock mode */
		omap2_set_prcm(tmpset.cm_clksel1_pll, tmpset.base_sdrc_rfr,
			       bypass);

		/* Errata: ret dll entry state */
		omap2_init_memory_params(omap2_dll_force_needed());
		omap2_reprogram_sdrc(done_rate, 0);
	}
442
	omap2_dpllcore_recalc(&dpll_ck);
443 444 445 446 447 448 449
	ret = 0;

dpll_exit:
	local_irq_restore(flags);
	return(ret);
}

450 451 452 453 454 455 456
/**
 * omap2_table_mpu_recalc - just return the MPU speed
 * @clk: virt_prcm_set struct clk
 *
 * Set virt_prcm_set's rate to the mpu_speed field of the current PRCM set.
 */
static void omap2_table_mpu_recalc(struct clk *clk)
457 458 459 460 461 462 463 464 465 466 467
{
	clk->rate = curr_prcm_set->mpu_speed;
}

/*
 * Look for a rate equal or less than the target rate given a configuration set.
 *
 * What's not entirely clear is "which" field represents the key field.
 * Some might argue L3-DDR, others ARM, others IVA. This code is simple and
 * just uses the ARM rates.
 */
468
static long omap2_round_to_table_rate(struct clk *clk, unsigned long rate)
469
{
470
	struct prcm_config *ptr;
471 472 473 474 475 476 477 478
	long highest_rate;

	if (clk != &virt_prcm_set)
		return -EINVAL;

	highest_rate = -EINVAL;

	for (ptr = rate_table; ptr->mpu_speed; ptr++) {
479 480
		if (!(ptr->flags & cpu_mask))
			continue;
481 482 483 484 485 486 487 488 489 490 491 492 493
		if (ptr->xtal_speed != sys_ck.rate)
			continue;

		highest_rate = ptr->mpu_speed;

		/* Can check only after xtal frequency check */
		if (ptr->mpu_speed <= rate)
			break;
	}
	return highest_rate;
}

/* Sets basic clocks based on the specified rate */
494
static int omap2_select_table_rate(struct clk *clk, unsigned long rate)
495
{
496
	u32 cur_rate, done_rate, bypass = 0, tmp;
497 498
	struct prcm_config *prcm;
	unsigned long found_speed = 0;
499
	unsigned long flags;
500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518

	if (clk != &virt_prcm_set)
		return -EINVAL;

	for (prcm = rate_table; prcm->mpu_speed; prcm++) {
		if (!(prcm->flags & cpu_mask))
			continue;

		if (prcm->xtal_speed != sys_ck.rate)
			continue;

		if (prcm->mpu_speed <= rate) {
			found_speed = prcm->mpu_speed;
			break;
		}
	}

	if (!found_speed) {
		printk(KERN_INFO "Could not set MPU rate to %luMHz\n",
519
		       rate / 1000000);
520 521 522 523
		return -EINVAL;
	}

	curr_prcm_set = prcm;
524
	cur_rate = omap2_get_dpll_rate_24xx(&dpll_ck);
525 526

	if (prcm->dpll_speed == cur_rate / 2) {
527
		omap2_reprogram_sdrc(CORE_CLK_SRC_DPLL, 1);
528
	} else if (prcm->dpll_speed == cur_rate * 2) {
529
		omap2_reprogram_sdrc(CORE_CLK_SRC_DPLL_X2, 1);
530 531 532 533 534 535
	} else if (prcm->dpll_speed != cur_rate) {
		local_irq_save(flags);

		if (prcm->dpll_speed == prcm->xtal_speed)
			bypass = 1;

536 537 538
		if ((prcm->cm_clksel2_pll & OMAP24XX_CORE_CLK_SRC_MASK) ==
		    CORE_CLK_SRC_DPLL_X2)
			done_rate = CORE_CLK_SRC_DPLL_X2;
539
		else
540
			done_rate = CORE_CLK_SRC_DPLL;
541 542

		/* MPU divider */
543
		cm_write_mod_reg(prcm->cm_clksel_mpu, MPU_MOD, CM_CLKSEL);
544 545

		/* dsp + iva1 div(2420), iva2.1(2430) */
546 547
		cm_write_mod_reg(prcm->cm_clksel_dsp,
				 OMAP24XX_DSP_MOD, CM_CLKSEL);
548

549
		cm_write_mod_reg(prcm->cm_clksel_gfx, GFX_MOD, CM_CLKSEL);
550 551

		/* Major subsystem dividers */
552 553
		tmp = cm_read_mod_reg(CORE_MOD, CM_CLKSEL1) & OMAP24XX_CLKSEL_DSS2_MASK;
		cm_write_mod_reg(prcm->cm_clksel1_core | tmp, CORE_MOD, CM_CLKSEL1);
554
		if (cpu_is_omap2430())
555 556
			cm_write_mod_reg(prcm->cm_clksel_mdm,
					 OMAP2430_MDM_MOD, CM_CLKSEL);
557 558

		/* x2 to enter init_mem */
559
		omap2_reprogram_sdrc(CORE_CLK_SRC_DPLL_X2, 1);
560 561 562 563 564 565 566 567 568

		omap2_set_prcm(prcm->cm_clksel1_pll, prcm->base_sdrc_rfr,
			       bypass);

		omap2_init_memory_params(omap2_dll_force_needed());
		omap2_reprogram_sdrc(done_rate, 0);

		local_irq_restore(flags);
	}
569
	omap2_dpllcore_recalc(&dpll_ck);
570 571 572 573 574 575 576 577 578 579

	return 0;
}

static struct clk_functions omap2_clk_functions = {
	.clk_enable		= omap2_clk_enable,
	.clk_disable		= omap2_clk_disable,
	.clk_round_rate		= omap2_clk_round_rate,
	.clk_set_rate		= omap2_clk_set_rate,
	.clk_set_parent		= omap2_clk_set_parent,
580
	.clk_disable_unused	= omap2_clk_disable_unused,
581 582
};

583
static u32 omap2_get_apll_clkin(void)
584
{
585
	u32 aplls, sclk = 0;
586

587 588 589
	aplls = cm_read_mod_reg(PLL_MOD, CM_CLKSEL1);
	aplls &= OMAP24XX_APLLS_CLKIN_MASK;
	aplls >>= OMAP24XX_APLLS_CLKIN_SHIFT;
590

591
	if (aplls == APLLS_CLKIN_19_2MHZ)
592
		sclk = 19200000;
593
	else if (aplls == APLLS_CLKIN_13MHZ)
594
		sclk = 13000000;
595
	else if (aplls == APLLS_CLKIN_12MHZ)
596 597
		sclk = 12000000;

598 599 600 601 602 603 604 605 606 607
	return sclk;
}

static u32 omap2_get_sysclkdiv(void)
{
	u32 div;

	div = __raw_readl(OMAP24XX_PRCM_CLKSRC_CTRL);
	div &= OMAP_SYSCLKDIV_MASK;
	div >>= OMAP_SYSCLKDIV_SHIFT;
608

609 610 611 612 613 614 615 616 617 618 619
	return div;
}

static void omap2_osc_clk_recalc(struct clk *clk)
{
	clk->rate = omap2_get_apll_clkin() * omap2_get_sysclkdiv();
}

static void omap2_sys_clk_recalc(struct clk *clk)
{
	clk->rate = clk->parent->rate / omap2_get_sysclkdiv();
620 621
}

622 623 624 625 626 627 628 629 630 631 632 633 634 635
/*
 * Set clocks for bypass mode for reboot to work.
 */
void omap2_clk_prepare_for_reboot(void)
{
	u32 rate;

	if (vclk == NULL || sclk == NULL)
		return;

	rate = clk_get_rate(sclk);
	clk_set_rate(vclk, rate);
}

636 637 638 639 640 641 642 643 644 645 646 647
/*
 * Switch the MPU rate if specified on cmdline.
 * We cannot do this early until cmdline is parsed.
 */
static int __init omap2_clk_arch_init(void)
{
	if (!mpurate)
		return -EINVAL;

	if (omap2_select_table_rate(&virt_prcm_set, mpurate))
		printk(KERN_ERR "Could not find matching MPU rate\n");

648
	recalculate_root_clocks();
649 650 651 652 653 654 655 656 657 658 659 660 661

	printk(KERN_INFO "Switched to new clocking rate (Crystal/DPLL/MPU): "
	       "%ld.%01ld/%ld/%ld MHz\n",
	       (sys_ck.rate / 1000000), (sys_ck.rate / 100000) % 10,
	       (dpll_ck.rate / 1000000), (mpu_ck.rate / 1000000)) ;

	return 0;
}
arch_initcall(omap2_clk_arch_init);

int __init omap2_clk_init(void)
{
	struct prcm_config *prcm;
662 663
	struct omap_clk *c;
	u32 clkrate, cpu_mask;
664

665 666 667 668 669
	if (cpu_is_omap242x())
		cpu_mask = RATE_IN_242X;
	else if (cpu_is_omap2430())
		cpu_mask = RATE_IN_243X;

670 671
	clk_init(&omap2_clk_functions);

672
	omap2_osc_clk_recalc(&osc_ck);
673
	propagate_rate(&osc_ck);
674
	omap2_sys_clk_recalc(&sys_ck);
675
	propagate_rate(&sys_ck);
676

677 678 679 680 681
	cpu_mask = 0;
	if (cpu_is_omap2420())
		cpu_mask |= CK_242X;
	if (cpu_is_omap2430())
		cpu_mask |= CK_243X;
682

683 684 685 686
	for (c = omap24xx_clks; c < omap24xx_clks + ARRAY_SIZE(omap24xx_clks); c++)
		if (c->cpu & cpu_mask) {
			clkdev_add(&c->lk);
			clk_register(c->lk.clk);
687 688 689
		}

	/* Check the MPU rate set by bootloader */
690
	clkrate = omap2_get_dpll_rate_24xx(&dpll_ck);
691
	for (prcm = rate_table; prcm->mpu_speed; prcm++) {
692 693
		if (!(prcm->flags & cpu_mask))
			continue;
694 695 696 697 698 699 700
		if (prcm->xtal_speed != sys_ck.rate)
			continue;
		if (prcm->dpll_speed <= clkrate)
			 break;
	}
	curr_prcm_set = prcm;

701
	recalculate_root_clocks();
702 703 704 705 706 707 708 709 710 711

	printk(KERN_INFO "Clocking rate (Crystal/DPLL/MPU): "
	       "%ld.%01ld/%ld/%ld MHz\n",
	       (sys_ck.rate / 1000000), (sys_ck.rate / 100000) % 10,
	       (dpll_ck.rate / 1000000), (mpu_ck.rate / 1000000)) ;

	/*
	 * Only enable those clocks we will need, let the drivers
	 * enable other clocks as necessary
	 */
712
	clk_enable_init_clocks();
713

714 715 716 717
	/* Avoid sleeping sleeping during omap2_clk_prepare_for_reboot() */
	vclk = clk_get(NULL, "virt_prcm_set");
	sclk = clk_get(NULL, "sys_ck");

718 719
	return 0;
}