clock_imx27.c 21.5 KB
Newer Older
1 2 3
/*
 * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved.
 * Copyright 2008 Juergen Beisert, kernel@pengutronix.de
S
Sascha Hauer 已提交
4
 * Copyright 2008 Martin Fuzzey, mfuzzey@gmail.com
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 * MA 02110-1301, USA.
 */

#include <linux/clk.h>
#include <linux/io.h>
#include <linux/module.h>

S
Sascha Hauer 已提交
25
#include <asm/clkdev.h>
26 27
#include <asm/div64.h>

S
Sascha Hauer 已提交
28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
#include <mach/clock.h>
#include <mach/common.h>
#include <mach/hardware.h>

/* Register offsets */
#define CCM_CSCR                (IO_ADDRESS(CCM_BASE_ADDR) + 0x0)
#define CCM_MPCTL0              (IO_ADDRESS(CCM_BASE_ADDR) + 0x4)
#define CCM_MPCTL1              (IO_ADDRESS(CCM_BASE_ADDR) + 0x8)
#define CCM_SPCTL0              (IO_ADDRESS(CCM_BASE_ADDR) + 0xC)
#define CCM_SPCTL1              (IO_ADDRESS(CCM_BASE_ADDR) + 0x10)
#define CCM_OSC26MCTL           (IO_ADDRESS(CCM_BASE_ADDR) + 0x14)
#define CCM_PCDR0               (IO_ADDRESS(CCM_BASE_ADDR) + 0x18)
#define CCM_PCDR1               (IO_ADDRESS(CCM_BASE_ADDR) + 0x1c)
#define CCM_PCCR0               (IO_ADDRESS(CCM_BASE_ADDR) + 0x20)
#define CCM_PCCR1               (IO_ADDRESS(CCM_BASE_ADDR) + 0x24)
#define CCM_CCSR                (IO_ADDRESS(CCM_BASE_ADDR) + 0x28)
#define CCM_PMCTL               (IO_ADDRESS(CCM_BASE_ADDR) + 0x2c)
#define CCM_PMCOUNT             (IO_ADDRESS(CCM_BASE_ADDR) + 0x30)
#define CCM_WKGDCTL             (IO_ADDRESS(CCM_BASE_ADDR) + 0x34)

#define CCM_CSCR_UPDATE_DIS	(1 << 31)
#define CCM_CSCR_SSI2		(1 << 23)
#define CCM_CSCR_SSI1		(1 << 22)
#define CCM_CSCR_VPU		(1 << 21)
#define CCM_CSCR_MSHC           (1 << 20)
#define CCM_CSCR_SPLLRES        (1 << 19)
#define CCM_CSCR_MPLLRES        (1 << 18)
#define CCM_CSCR_SP             (1 << 17)
#define CCM_CSCR_MCU            (1 << 16)
#define CCM_CSCR_OSC26MDIV      (1 << 4)
#define CCM_CSCR_OSC26M         (1 << 3)
#define CCM_CSCR_FPM            (1 << 2)
#define CCM_CSCR_SPEN           (1 << 1)
#define CCM_CSCR_MPEN           (1 << 0)

/* i.MX27 TO 2+ */
#define CCM_CSCR_ARM_SRC        (1 << 15)

#define CCM_SPCTL1_LF           (1 << 15)
#define CCM_SPCTL1_BRMO         (1 << 6)

static struct clk mpll_main1_clk, mpll_main2_clk;

static int clk_pccr_enable(struct clk *clk)
72 73 74
{
	unsigned long reg;

S
Sascha Hauer 已提交
75 76 77
	if (!clk->enable_reg)
		return 0;

78 79 80 81 82 83 84
	reg = __raw_readl(clk->enable_reg);
	reg |= 1 << clk->enable_shift;
	__raw_writel(reg, clk->enable_reg);

	return 0;
}

S
Sascha Hauer 已提交
85
static void clk_pccr_disable(struct clk *clk)
86 87 88
{
	unsigned long reg;

S
Sascha Hauer 已提交
89 90 91
	if (!clk->enable_reg)
		return;

92 93 94 95 96
	reg = __raw_readl(clk->enable_reg);
	reg &= ~(1 << clk->enable_shift);
	__raw_writel(reg, clk->enable_reg);
}

S
Sascha Hauer 已提交
97
static int clk_spll_enable(struct clk *clk)
98 99 100 101 102 103 104
{
	unsigned long reg;

	reg = __raw_readl(CCM_CSCR);
	reg |= CCM_CSCR_SPEN;
	__raw_writel(reg, CCM_CSCR);

S
Sascha Hauer 已提交
105
	while (!(__raw_readl(CCM_SPCTL1) & CCM_SPCTL1_LF));
106 107 108 109

	return 0;
}

S
Sascha Hauer 已提交
110
static void clk_spll_disable(struct clk *clk)
111 112 113 114 115 116 117 118
{
	unsigned long reg;

	reg = __raw_readl(CCM_CSCR);
	reg &= ~CCM_CSCR_SPEN;
	__raw_writel(reg, CCM_CSCR);
}

S
Sascha Hauer 已提交
119
static int clk_cpu_set_parent(struct clk *clk, struct clk *parent)
120
{
S
Sascha Hauer 已提交
121
	int cscr = __raw_readl(CCM_CSCR);
122 123 124 125 126

	if (clk->parent == parent)
		return 0;

	if (mx27_revision() >= CHIP_REV_2_0) {
S
Sascha Hauer 已提交
127
		if (parent == &mpll_main1_clk) {
128 129
			cscr |= CCM_CSCR_ARM_SRC;
		} else {
S
Sascha Hauer 已提交
130
			if (parent == &mpll_main2_clk)
131 132 133 134 135
				cscr &= ~CCM_CSCR_ARM_SRC;
			else
				return -EINVAL;
		}
		__raw_writel(cscr, CCM_CSCR);
S
Sascha Hauer 已提交
136 137 138 139
		clk->parent = parent;
		return 0;
	}
	return -ENODEV;
140 141
}

S
Sascha Hauer 已提交
142
static unsigned long round_rate_cpu(struct clk *clk, unsigned long rate)
143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158
{
	int div;
	unsigned long parent_rate;

	parent_rate = clk_get_rate(clk->parent);

	div = parent_rate / rate;
	if (parent_rate % rate)
		div++;

	if (div > 4)
		div = 4;

	return parent_rate / div;
}

S
Sascha Hauer 已提交
159
static int set_rate_cpu(struct clk *clk, unsigned long rate)
160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175
{
	unsigned int div;
	uint32_t reg;
	unsigned long parent_rate;

	parent_rate = clk_get_rate(clk->parent);

	div = parent_rate / rate;

	if (div > 4 || div < 1 || ((parent_rate / div) != rate))
		return -EINVAL;

	div--;

	reg = __raw_readl(CCM_CSCR);
	if (mx27_revision() >= CHIP_REV_2_0) {
S
Sascha Hauer 已提交
176 177 178 179
		reg &= ~(3 << 12);
		reg |= div << 12;
		reg &= ~(CCM_CSCR_FPM | CCM_CSCR_SPEN);
		__raw_writel(reg | CCM_CSCR_UPDATE_DIS, CCM_CSCR);
180
	} else {
S
Sascha Hauer 已提交
181
		printk(KERN_ERR "Can't set CPU frequency!\n");
182 183 184 185 186
	}

	return 0;
}

S
Sascha Hauer 已提交
187
static unsigned long round_rate_per(struct clk *clk, unsigned long rate)
188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203
{
	u32 div;
	unsigned long parent_rate;

	parent_rate = clk_get_rate(clk->parent);

	div = parent_rate / rate;
	if (parent_rate % rate)
		div++;

	if (div > 64)
		div = 64;

	return parent_rate / div;
}

S
Sascha Hauer 已提交
204
static int set_rate_per(struct clk *clk, unsigned long rate)
205 206 207 208 209 210 211 212 213 214 215 216 217 218 219
{
	u32 reg;
	u32 div;
	unsigned long parent_rate;

	parent_rate = clk_get_rate(clk->parent);

	if (clk->id < 0 || clk->id > 3)
		return -EINVAL;

	div = parent_rate / rate;
	if (div > 64 || div < 1 || ((parent_rate / div) != rate))
		return -EINVAL;
	div--;

S
Sascha Hauer 已提交
220
	reg = __raw_readl(CCM_PCDR1) & ~(0x3f << (clk->id << 3));
221 222 223 224 225 226
	reg |= div << (clk->id << 3);
	__raw_writel(reg, CCM_PCDR1);

	return 0;
}

S
Sascha Hauer 已提交
227
static unsigned long get_rate_usb(struct clk *clk)
228 229 230 231 232 233
{
	unsigned long usb_pdf;
	unsigned long parent_rate;

	parent_rate = clk_get_rate(clk->parent);

S
Sascha Hauer 已提交
234
	usb_pdf = (__raw_readl(CCM_CSCR) >> 28) & 0x7;
235 236 237 238

	return parent_rate / (usb_pdf + 1U);
}

S
Sascha Hauer 已提交
239
static unsigned long get_rate_ssix(struct clk *clk, unsigned long pdf)
240 241 242 243 244 245
{
	unsigned long parent_rate;

	parent_rate = clk_get_rate(clk->parent);

	if (mx27_revision() >= CHIP_REV_2_0)
S
Sascha Hauer 已提交
246
		pdf += 4;  /* MX27 TO2+ */
247
	else
S
Sascha Hauer 已提交
248
		pdf = (pdf < 2) ? 124UL : pdf;  /* MX21 & MX27 TO1 */
249

S
Sascha Hauer 已提交
250
	return 2UL * parent_rate / pdf;
251 252
}

S
Sascha Hauer 已提交
253
static unsigned long get_rate_ssi1(struct clk *clk)
254
{
S
Sascha Hauer 已提交
255 256
	return get_rate_ssix(clk, (__raw_readl(CCM_PCDR0) >> 16) & 0x3f);
}
257

S
Sascha Hauer 已提交
258 259 260
static unsigned long get_rate_ssi2(struct clk *clk)
{
	return get_rate_ssix(clk, (__raw_readl(CCM_PCDR0) >> 26) & 0x3f);
261 262
}

S
Sascha Hauer 已提交
263
static unsigned long get_rate_nfc(struct clk *clk)
264 265 266 267 268 269
{
	unsigned long nfc_pdf;
	unsigned long parent_rate;

	parent_rate = clk_get_rate(clk->parent);

S
Sascha Hauer 已提交
270 271 272 273
	if (mx27_revision() >= CHIP_REV_2_0)
		nfc_pdf = (__raw_readl(CCM_PCDR0) >> 6) & 0xf;
	else
		nfc_pdf = (__raw_readl(CCM_PCDR0) >> 12) & 0xf;
274 275 276 277

	return parent_rate / (nfc_pdf + 1);
}

S
Sascha Hauer 已提交
278
static unsigned long get_rate_vpu(struct clk *clk)
279 280 281 282 283 284 285
{
	unsigned long vpu_pdf;
	unsigned long parent_rate;

	parent_rate = clk_get_rate(clk->parent);

	if (mx27_revision() >= CHIP_REV_2_0) {
S
Sascha Hauer 已提交
286
		vpu_pdf = (__raw_readl(CCM_PCDR0) >> 10) & 0x3f;
287 288
		vpu_pdf += 4;
	} else {
S
Sascha Hauer 已提交
289
		vpu_pdf = (__raw_readl(CCM_PCDR0) >> 8) & 0xf;
290 291
		vpu_pdf = (vpu_pdf < 2) ? 124 : vpu_pdf;
	}
S
Sascha Hauer 已提交
292

293 294 295
	return 2UL * parent_rate / vpu_pdf;
}

S
Sascha Hauer 已提交
296
static unsigned long round_rate_parent(struct clk *clk, unsigned long rate)
297 298 299 300
{
	return clk->parent->round_rate(clk->parent, rate);
}

S
Sascha Hauer 已提交
301 302 303 304 305 306
static unsigned long get_rate_parent(struct clk *clk)
{
	return clk_get_rate(clk->parent);
}

static int set_rate_parent(struct clk *clk, unsigned long rate)
307 308 309 310 311 312 313
{
	return clk->parent->set_rate(clk->parent, rate);
}

/* in Hz */
static unsigned long external_high_reference = 26000000;

S
Sascha Hauer 已提交
314
static unsigned long get_rate_high_reference(struct clk *clk)
315 316 317 318 319 320 321
{
	return external_high_reference;
}

/* in Hz */
static unsigned long external_low_reference = 32768;

S
Sascha Hauer 已提交
322
static unsigned long get_rate_low_reference(struct clk *clk)
323 324 325 326
{
	return external_low_reference;
}

S
Sascha Hauer 已提交
327 328 329 330
static unsigned long get_rate_fpm(struct clk *clk)
{
	return clk_get_rate(clk->parent) * 1024;
}
331

S
Sascha Hauer 已提交
332
static unsigned long get_rate_mpll(struct clk *clk)
333
{
334 335
	return mxc_decode_pll(__raw_readl(CCM_MPCTL0),
			clk_get_rate(clk->parent));
336 337
}

S
Sascha Hauer 已提交
338
static unsigned long get_rate_mpll_main(struct clk *clk)
339 340 341 342 343 344
{
	unsigned long parent_rate;

	parent_rate = clk_get_rate(clk->parent);

	/* i.MX27 TO2:
S
Sascha Hauer 已提交
345 346
	 * clk->id == 0: arm clock source path 1 which is from 2 * MPLL / 2
	 * clk->id == 1: arm clock source path 2 which is from 2 * MPLL / 3
347 348 349 350 351 352 353
	 */
	if (mx27_revision() >= CHIP_REV_2_0 && clk->id == 1)
		return 2UL * parent_rate / 3UL;

	return parent_rate;
}

S
Sascha Hauer 已提交
354
static unsigned long get_rate_spll(struct clk *clk)
355 356
{
	uint32_t reg;
S
Sascha Hauer 已提交
357
	unsigned long rate;
358

S
Sascha Hauer 已提交
359
	rate = clk_get_rate(clk->parent);
360 361

	reg = __raw_readl(CCM_SPCTL0);
362 363 364 365

	/* On TO2 we have to write the value back. Otherwise we
	 * read 0 from this register the next time.
	 */
366 367 368
	if (mx27_revision() >= CHIP_REV_2_0)
		__raw_writel(reg, CCM_SPCTL0);

S
Sascha Hauer 已提交
369
	return mxc_decode_pll(reg, rate);
370 371
}

S
Sascha Hauer 已提交
372
static unsigned long get_rate_cpu(struct clk *clk)
373 374 375 376 377
{
	u32 div;
	unsigned long rate;

	if (mx27_revision() >= CHIP_REV_2_0)
S
Sascha Hauer 已提交
378
		div = (__raw_readl(CCM_CSCR) >> 12) & 0x3;
379
	else
S
Sascha Hauer 已提交
380
		div = (__raw_readl(CCM_CSCR) >> 13) & 0x7;
381 382 383 384 385

	rate = clk_get_rate(clk->parent);
	return rate / (div + 1);
}

S
Sascha Hauer 已提交
386
static unsigned long get_rate_ahb(struct clk *clk)
387
{
S
Sascha Hauer 已提交
388
	unsigned long rate, bclk_pdf;
389 390

	if (mx27_revision() >= CHIP_REV_2_0)
S
Sascha Hauer 已提交
391
		bclk_pdf = (__raw_readl(CCM_CSCR) >> 8) & 0x3;
392
	else
S
Sascha Hauer 已提交
393
		bclk_pdf = (__raw_readl(CCM_CSCR) >> 9) & 0xf;
394 395 396 397 398

	rate = clk_get_rate(clk->parent);
	return rate / (bclk_pdf + 1);
}

S
Sascha Hauer 已提交
399
static unsigned long get_rate_ipg(struct clk *clk)
400
{
S
Sascha Hauer 已提交
401
	unsigned long rate, ipg_pdf;
402 403 404 405

	if (mx27_revision() >= CHIP_REV_2_0)
		return clk_get_rate(clk->parent);
	else
S
Sascha Hauer 已提交
406
		ipg_pdf = (__raw_readl(CCM_CSCR) >> 8) & 1;
407 408 409 410 411

	rate = clk_get_rate(clk->parent);
	return rate / (ipg_pdf + 1);
}

S
Sascha Hauer 已提交
412
static unsigned long get_rate_per(struct clk *clk)
413
{
S
Sascha Hauer 已提交
414
	unsigned long perclk_pdf, parent_rate;
415 416 417 418 419 420

	parent_rate = clk_get_rate(clk->parent);

	if (clk->id < 0 || clk->id > 3)
		return 0;

S
Sascha Hauer 已提交
421
	perclk_pdf = (__raw_readl(CCM_PCDR1) >> (clk->id << 3)) & 0x3f;
422 423 424 425

	return parent_rate / (perclk_pdf + 1);
}

S
Sascha Hauer 已提交
426 427 428 429 430 431 432
/*
 * the high frequency external clock reference
 * Default case is 26MHz. Could be changed at runtime
 * with a call to change_external_high_reference()
 */
static struct clk ckih_clk = {
	.get_rate	= get_rate_high_reference,
433 434
};

S
Sascha Hauer 已提交
435 436 437
static struct clk mpll_clk = {
	.parent		= &ckih_clk,
	.get_rate	= get_rate_mpll,
438 439
};

S
Sascha Hauer 已提交
440 441 442 443 444 445 446
/* For i.MX27 TO2, it is the MPLL path 1 of ARM core
 * It provides the clock source whose rate is same as MPLL
 */
static struct clk mpll_main1_clk = {
	.id		= 0,
	.parent		= &mpll_clk,
	.get_rate	= get_rate_mpll_main,
447 448
};

S
Sascha Hauer 已提交
449 450 451 452 453 454 455
/* For i.MX27 TO2, it is the MPLL path 2 of ARM core
 * It provides the clock source whose rate is same MPLL * 2 / 3
 */
static struct clk mpll_main2_clk = {
	.id		= 1,
	.parent		= &mpll_clk,
	.get_rate	= get_rate_mpll_main,
456 457
};

S
Sascha Hauer 已提交
458 459 460
static struct clk ahb_clk = {
	.parent		= &mpll_main2_clk,
	.get_rate	= get_rate_ahb,
461 462
};

S
Sascha Hauer 已提交
463 464 465
static struct clk ipg_clk = {
	.parent		= &ahb_clk,
	.get_rate	= get_rate_ipg,
466 467
};

S
Sascha Hauer 已提交
468 469 470 471 472 473
static struct clk cpu_clk = {
	.parent = &mpll_main2_clk,
	.set_parent = clk_cpu_set_parent,
	.round_rate = round_rate_cpu,
	.get_rate = get_rate_cpu,
	.set_rate = set_rate_cpu,
474 475
};

S
Sascha Hauer 已提交
476 477 478 479 480
static struct clk spll_clk = {
	.parent = &ckih_clk,
	.get_rate = get_rate_spll,
	.enable = clk_spll_enable,
	.disable = clk_spll_disable,
481 482
};

S
Sascha Hauer 已提交
483 484 485 486 487 488
/*
 * the low frequency external clock reference
 * Default case is 32.768kHz.
 */
static struct clk ckil_clk = {
	.get_rate = get_rate_low_reference,
489 490
};

S
Sascha Hauer 已提交
491 492 493 494
/* Output of frequency pre multiplier */
static struct clk fpm_clk = {
	.parent = &ckil_clk,
	.get_rate = get_rate_fpm,
495 496
};

S
Sascha Hauer 已提交
497 498
#define PCCR0 CCM_PCCR0
#define PCCR1 CCM_PCCR1
499

S
Sascha Hauer 已提交
500 501 502 503 504 505 506 507 508 509
#define DEFINE_CLOCK(name, i, er, es, gr, s, p)		\
	static struct clk name = {			\
		.id		= i,			\
		.enable_reg	= er,			\
		.enable_shift	= es,			\
		.get_rate	= gr,			\
		.enable		= clk_pccr_enable,	\
		.disable	= clk_pccr_disable,	\
		.secondary	= s,			\
		.parent		= p,			\
510 511
	}

S
Sascha Hauer 已提交
512 513 514 515 516 517 518 519 520 521 522 523 524
#define DEFINE_CLOCK1(name, i, er, es, getsetround, s, p)	\
	static struct clk name = {				\
		.id		= i,				\
		.enable_reg	= er,				\
		.enable_shift	= es,				\
		.get_rate	= get_rate_##getsetround,	\
		.set_rate	= set_rate_##getsetround,	\
		.round_rate	= round_rate_##getsetround,	\
		.enable		= clk_pccr_enable,		\
		.disable	= clk_pccr_disable,		\
		.secondary	= s,				\
		.parent		= p,				\
	}
525

S
Sascha Hauer 已提交
526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621
/* Forward declaration to keep the following list in order */
static struct clk slcdc_clk1, sahara2_clk1, rtic_clk1, fec_clk1, emma_clk1,
		  dma_clk1, lcdc_clk2, vpu_clk1;

/* All clocks we can gate through PCCRx in the order of PCCRx bits */
DEFINE_CLOCK(ssi2_clk1,    1, PCCR0,  0, NULL, NULL, &ipg_clk);
DEFINE_CLOCK(ssi1_clk1,    0, PCCR0,  1, NULL, NULL, &ipg_clk);
DEFINE_CLOCK(slcdc_clk,    0, PCCR0,  2, NULL, &slcdc_clk1, &ahb_clk);
DEFINE_CLOCK(sdhc3_clk1,   0, PCCR0,  3, NULL, NULL, &ipg_clk);
DEFINE_CLOCK(sdhc2_clk1,   0, PCCR0,  4, NULL, NULL, &ipg_clk);
DEFINE_CLOCK(sdhc1_clk1,   0, PCCR0,  5, NULL, NULL, &ipg_clk);
DEFINE_CLOCK(scc_clk,      0, PCCR0,  6, NULL, NULL, &ipg_clk);
DEFINE_CLOCK(sahara2_clk,  0, PCCR0,  7, NULL, &sahara2_clk1, &ahb_clk);
DEFINE_CLOCK(rtic_clk,     0, PCCR0,  8, NULL, &rtic_clk1, &ahb_clk);
DEFINE_CLOCK(rtc_clk,      0, PCCR0,  9, NULL, NULL, &ipg_clk);
DEFINE_CLOCK(pwm_clk1,     0, PCCR0, 11, NULL, NULL, &ipg_clk);
DEFINE_CLOCK(owire_clk,    0, PCCR0, 12, NULL, NULL, &ipg_clk);
DEFINE_CLOCK(mstick_clk1,  0, PCCR0, 13, NULL, NULL, &ipg_clk);
DEFINE_CLOCK(lcdc_clk1,    0, PCCR0, 14, NULL, &lcdc_clk2, &ipg_clk);
DEFINE_CLOCK(kpp_clk,      0, PCCR0, 15, NULL, NULL, &ipg_clk);
DEFINE_CLOCK(iim_clk,      0, PCCR0, 16, NULL, NULL, &ipg_clk);
DEFINE_CLOCK(i2c2_clk,     1, PCCR0, 17, NULL, NULL, &ipg_clk);
DEFINE_CLOCK(i2c1_clk,     0, PCCR0, 18, NULL, NULL, &ipg_clk);
DEFINE_CLOCK(gpt6_clk1,    0, PCCR0, 29, NULL, NULL, &ipg_clk);
DEFINE_CLOCK(gpt5_clk1,    0, PCCR0, 20, NULL, NULL, &ipg_clk);
DEFINE_CLOCK(gpt4_clk1,    0, PCCR0, 21, NULL, NULL, &ipg_clk);
DEFINE_CLOCK(gpt3_clk1,    0, PCCR0, 22, NULL, NULL, &ipg_clk);
DEFINE_CLOCK(gpt2_clk1,    0, PCCR0, 23, NULL, NULL, &ipg_clk);
DEFINE_CLOCK(gpt1_clk1,    0, PCCR0, 24, NULL, NULL, &ipg_clk);
DEFINE_CLOCK(gpio_clk,     0, PCCR0, 25, NULL, NULL, &ipg_clk);
DEFINE_CLOCK(fec_clk,      0, PCCR0, 26, NULL, &fec_clk1, &ahb_clk);
DEFINE_CLOCK(emma_clk,     0, PCCR0, 27, NULL, &emma_clk1, &ahb_clk);
DEFINE_CLOCK(dma_clk,      0, PCCR0, 28, NULL, &dma_clk1, &ahb_clk);
DEFINE_CLOCK(cspi13_clk1,  0, PCCR0, 29, NULL, NULL, &ipg_clk);
DEFINE_CLOCK(cspi2_clk1,   0, PCCR0, 30, NULL, NULL, &ipg_clk);
DEFINE_CLOCK(cspi1_clk1,   0, PCCR0, 31, NULL, NULL, &ipg_clk);

DEFINE_CLOCK(mstick_clk,   0, PCCR1,  2, NULL, &mstick_clk1, &ipg_clk);
DEFINE_CLOCK(nfc_clk,      0, PCCR1,  3, get_rate_nfc, NULL, &cpu_clk);
DEFINE_CLOCK(ssi2_clk,     1, PCCR1,  4, get_rate_ssi2, &ssi2_clk1, &mpll_main2_clk);
DEFINE_CLOCK(ssi1_clk,     0, PCCR1,  5, get_rate_ssi1, &ssi1_clk1, &mpll_main2_clk);
DEFINE_CLOCK(vpu_clk,      0, PCCR1,  6, get_rate_vpu, &vpu_clk1, &mpll_main2_clk);
DEFINE_CLOCK1(per4_clk,    3, PCCR1,  7, per, NULL, &mpll_main2_clk);
DEFINE_CLOCK1(per3_clk,    2, PCCR1,  8, per, NULL, &mpll_main2_clk);
DEFINE_CLOCK1(per2_clk,    1, PCCR1,  9, per, NULL, &mpll_main2_clk);
DEFINE_CLOCK1(per1_clk,    0, PCCR1, 10, per, NULL, &mpll_main2_clk);
DEFINE_CLOCK(usb_clk1,     0, PCCR1, 11, NULL, NULL, &ahb_clk);
DEFINE_CLOCK(slcdc_clk1,   0, PCCR1, 12, NULL, NULL, &ahb_clk);
DEFINE_CLOCK(sahara2_clk1, 0, PCCR1, 13, NULL, NULL, &ahb_clk);
DEFINE_CLOCK(rtic_clk1,    0, PCCR1, 14, NULL, NULL, &ahb_clk);
DEFINE_CLOCK(lcdc_clk2,    0, PCCR1, 15, NULL, NULL, &ahb_clk);
DEFINE_CLOCK(vpu_clk1,     0, PCCR1, 16, NULL, NULL, &ahb_clk);
DEFINE_CLOCK(fec_clk1,     0, PCCR1, 17, NULL, NULL, &ahb_clk);
DEFINE_CLOCK(emma_clk1,    0, PCCR1, 18, NULL, NULL, &ahb_clk);
DEFINE_CLOCK(emi_clk,      0, PCCR1, 19, NULL, NULL, &ahb_clk);
DEFINE_CLOCK(dma_clk1,     0, PCCR1, 20, NULL, NULL, &ahb_clk);
DEFINE_CLOCK(csi_clk1,     0, PCCR1, 21, NULL, NULL, &ahb_clk);
DEFINE_CLOCK(brom_clk,     0, PCCR1, 22, NULL, NULL, &ahb_clk);
DEFINE_CLOCK(ata_clk,      0, PCCR1, 23, NULL, NULL, &ahb_clk);
DEFINE_CLOCK(wdog_clk,     0, PCCR1, 24, NULL, NULL, &ipg_clk);
DEFINE_CLOCK(usb_clk,      0, PCCR1, 25, get_rate_usb, &usb_clk1, &spll_clk);
DEFINE_CLOCK(uart6_clk1,   0, PCCR1, 26, NULL, NULL, &ipg_clk);
DEFINE_CLOCK(uart5_clk1,   0, PCCR1, 27, NULL, NULL, &ipg_clk);
DEFINE_CLOCK(uart4_clk1,   0, PCCR1, 28, NULL, NULL, &ipg_clk);
DEFINE_CLOCK(uart3_clk1,   0, PCCR1, 29, NULL, NULL, &ipg_clk);
DEFINE_CLOCK(uart2_clk1,   0, PCCR1, 30, NULL, NULL, &ipg_clk);
DEFINE_CLOCK(uart1_clk1,   0, PCCR1, 31, NULL, NULL, &ipg_clk);

/* Clocks we cannot directly gate, but drivers need their rates */
DEFINE_CLOCK(cspi1_clk,    0, 0,      0, NULL, &cspi1_clk1, &per2_clk);
DEFINE_CLOCK(cspi2_clk,    1, 0,      0, NULL, &cspi2_clk1, &per2_clk);
DEFINE_CLOCK(cspi3_clk,    2, 0,      0, NULL, &cspi13_clk1, &per2_clk);
DEFINE_CLOCK(sdhc1_clk,    0, 0,      0, NULL, &sdhc1_clk1, &per2_clk);
DEFINE_CLOCK(sdhc2_clk,    1, 0,      0, NULL, &sdhc2_clk1, &per2_clk);
DEFINE_CLOCK(sdhc3_clk,    2, 0,      0, NULL, &sdhc3_clk1, &per2_clk);
DEFINE_CLOCK(pwm_clk,      0, 0,      0, NULL, &pwm_clk1, &per1_clk);
DEFINE_CLOCK(gpt1_clk,     0, 0,      0, NULL, &gpt1_clk1, &per1_clk);
DEFINE_CLOCK(gpt2_clk,     1, 0,      0, NULL, &gpt2_clk1, &per1_clk);
DEFINE_CLOCK(gpt3_clk,     2, 0,      0, NULL, &gpt3_clk1, &per1_clk);
DEFINE_CLOCK(gpt4_clk,     3, 0,      0, NULL, &gpt4_clk1, &per1_clk);
DEFINE_CLOCK(gpt5_clk,     4, 0,      0, NULL, &gpt5_clk1, &per1_clk);
DEFINE_CLOCK(gpt6_clk,     5, 0,      0, NULL, &gpt6_clk1, &per1_clk);
DEFINE_CLOCK(uart1_clk,    0, 0,      0, NULL, &uart1_clk1, &per1_clk);
DEFINE_CLOCK(uart2_clk,    1, 0,      0, NULL, &uart2_clk1, &per1_clk);
DEFINE_CLOCK(uart3_clk,    2, 0,      0, NULL, &uart3_clk1, &per1_clk);
DEFINE_CLOCK(uart4_clk,    3, 0,      0, NULL, &uart4_clk1, &per1_clk);
DEFINE_CLOCK(uart5_clk,    4, 0,      0, NULL, &uart5_clk1, &per1_clk);
DEFINE_CLOCK(uart6_clk,    5, 0,      0, NULL, &uart6_clk1, &per1_clk);
DEFINE_CLOCK1(lcdc_clk,    0, 0,      0, parent, &lcdc_clk1, &per3_clk);
DEFINE_CLOCK1(csi_clk,     0, 0,      0, parent, &csi_clk1, &per4_clk);

#define _REGISTER_CLOCK(d, n, c) \
	{ \
		.dev_id = d, \
		.con_id = n, \
		.clk = &c, \
622 623
	},

624
static struct clk_lookup lookups[] = {
S
Sascha Hauer 已提交
625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675
	_REGISTER_CLOCK("imx-uart.0", NULL, uart1_clk)
	_REGISTER_CLOCK("imx-uart.1", NULL, uart2_clk)
	_REGISTER_CLOCK("imx-uart.2", NULL, uart3_clk)
	_REGISTER_CLOCK("imx-uart.3", NULL, uart4_clk)
	_REGISTER_CLOCK("imx-uart.4", NULL, uart5_clk)
	_REGISTER_CLOCK("imx-uart.5", NULL, uart6_clk)
	_REGISTER_CLOCK(NULL, "gpt1", gpt1_clk)
	_REGISTER_CLOCK(NULL, "gpt2", gpt2_clk)
	_REGISTER_CLOCK(NULL, "gpt3", gpt3_clk)
	_REGISTER_CLOCK(NULL, "gpt4", gpt4_clk)
	_REGISTER_CLOCK(NULL, "gpt5", gpt5_clk)
	_REGISTER_CLOCK(NULL, "gpt6", gpt6_clk)
	_REGISTER_CLOCK("mxc_pwm.0", NULL, pwm_clk)
	_REGISTER_CLOCK("mxc-mmc.0", NULL, sdhc1_clk)
	_REGISTER_CLOCK("mxc-mmc.1", NULL, sdhc2_clk)
	_REGISTER_CLOCK("mxc-mmc.2", NULL, sdhc3_clk)
	_REGISTER_CLOCK(NULL, "cspi1", cspi1_clk)
	_REGISTER_CLOCK(NULL, "cspi2", cspi2_clk)
	_REGISTER_CLOCK(NULL, "cspi3", cspi3_clk)
	_REGISTER_CLOCK("imx-fb.0", NULL, lcdc_clk)
	_REGISTER_CLOCK(NULL, "csi", csi_clk)
	_REGISTER_CLOCK(NULL, "usb", usb_clk)
	_REGISTER_CLOCK(NULL, "ssi1", ssi1_clk)
	_REGISTER_CLOCK(NULL, "ssi2", ssi2_clk)
	_REGISTER_CLOCK("mxc_nand.0", NULL, nfc_clk)
	_REGISTER_CLOCK(NULL, "vpu", vpu_clk)
	_REGISTER_CLOCK(NULL, "dma", dma_clk)
	_REGISTER_CLOCK(NULL, "rtic", rtic_clk)
	_REGISTER_CLOCK(NULL, "brom", brom_clk)
	_REGISTER_CLOCK(NULL, "emma", emma_clk)
	_REGISTER_CLOCK(NULL, "slcdc", slcdc_clk)
	_REGISTER_CLOCK("fec.0", NULL, fec_clk)
	_REGISTER_CLOCK(NULL, "emi", emi_clk)
	_REGISTER_CLOCK(NULL, "sahara2", sahara2_clk)
	_REGISTER_CLOCK(NULL, "ata", ata_clk)
	_REGISTER_CLOCK(NULL, "mstick", mstick_clk)
	_REGISTER_CLOCK(NULL, "wdog", wdog_clk)
	_REGISTER_CLOCK(NULL, "gpio", gpio_clk)
	_REGISTER_CLOCK("imx-i2c.0", NULL, i2c1_clk)
	_REGISTER_CLOCK("imx-i2c.1", NULL, i2c2_clk)
	_REGISTER_CLOCK(NULL, "iim", iim_clk)
	_REGISTER_CLOCK(NULL, "kpp", kpp_clk)
	_REGISTER_CLOCK("mxc_w1.0", NULL, owire_clk)
	_REGISTER_CLOCK(NULL, "rtc", rtc_clk)
	_REGISTER_CLOCK(NULL, "scc", scc_clk)
};

/* Adjust the clock path for TO2 and later */
static void __init to2_adjust_clocks(void)
{
	unsigned long cscr = __raw_readl(CCM_CSCR);
676 677

	if (mx27_revision() >= CHIP_REV_2_0) {
S
Sascha Hauer 已提交
678 679
		if (cscr & CCM_CSCR_ARM_SRC)
			cpu_clk.parent = &mpll_main1_clk;
680

S
Sascha Hauer 已提交
681 682
		if (!(cscr & CCM_CSCR_SSI2))
			ssi1_clk.parent = &spll_clk;
683

S
Sascha Hauer 已提交
684 685
		if (!(cscr & CCM_CSCR_SSI1))
			ssi1_clk.parent = &spll_clk;
686

S
Sascha Hauer 已提交
687
		if (!(cscr & CCM_CSCR_VPU))
688 689 690 691 692 693 694 695
			vpu_clk.parent = &spll_clk;
	} else {
		cpu_clk.parent = &mpll_clk;
		cpu_clk.set_parent = NULL;
		cpu_clk.round_rate = NULL;
		cpu_clk.set_rate = NULL;
		ahb_clk.parent = &mpll_clk;

S
Sascha Hauer 已提交
696 697 698 699
		per1_clk.parent = &mpll_clk;
		per2_clk.parent = &mpll_clk;
		per3_clk.parent = &mpll_clk;
		per4_clk.parent = &mpll_clk;
700

S
Sascha Hauer 已提交
701 702
		ssi1_clk.parent = &mpll_clk;
		ssi2_clk.parent = &mpll_clk;
703 704 705 706 707 708 709 710 711

		vpu_clk.parent = &mpll_clk;
	}
}

/*
 * must be called very early to get information about the
 * available clock rate when the timer framework starts
 */
712
int __init mx27_clocks_init(unsigned long fref)
713
{
S
Sascha Hauer 已提交
714 715
	u32 cscr = __raw_readl(CCM_CSCR);
	int i;
716 717 718

	external_high_reference = fref;

S
Sascha Hauer 已提交
719
	/* detect clock reference for both system PLLs */
720 721 722
	if (cscr & CCM_CSCR_MCU)
		mpll_clk.parent = &ckih_clk;
	else
S
Sascha Hauer 已提交
723
		mpll_clk.parent = &fpm_clk;
724 725 726 727

	if (cscr & CCM_CSCR_SP)
		spll_clk.parent = &ckih_clk;
	else
S
Sascha Hauer 已提交
728
		spll_clk.parent = &fpm_clk;
729

S
Sascha Hauer 已提交
730
	to2_adjust_clocks();
731

S
Sascha Hauer 已提交
732 733
	for (i = 0; i < ARRAY_SIZE(lookups); i++)
		clkdev_add(&lookups[i]);
734

S
Sascha Hauer 已提交
735 736 737
	/* Turn off all clocks we do not need */
	__raw_writel(0, CCM_PCCR0);
	__raw_writel((1 << 10) | (1 << 19), CCM_PCCR1);
738 739 740

	spll_clk.disable(&spll_clk);

S
Sascha Hauer 已提交
741 742
	/* enable basic clocks */
	clk_enable(&per1_clk);
743
	clk_enable(&gpio_clk);
S
Sascha Hauer 已提交
744
	clk_enable(&emi_clk);
745
	clk_enable(&iim_clk);
S
Sascha Hauer 已提交
746

747
#ifdef CONFIG_DEBUG_LL_CONSOLE
S
Sascha Hauer 已提交
748
	clk_enable(&uart1_clk);
749
#endif
750

S
Sascha Hauer 已提交
751
	mxc_timer_init(&gpt1_clk);
752

753 754
	return 0;
}
S
Sascha Hauer 已提交
755