clock.c 21.5 KB
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 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 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 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 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 622 623 624 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 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979
// SPDX-License-Identifier: GPL-2.0+
/*
 * (C) Copyright 2007
 * Sascha Hauer, Pengutronix
 *
 * (C) Copyright 2009 Freescale Semiconductor, Inc.
 */

#include <common.h>
#include <asm/io.h>
#include <linux/errno.h>
#include <asm/arch/imx-regs.h>
#include <asm/arch/crm_regs.h>
#include <asm/arch/clock.h>
#include <div64.h>
#include <asm/arch/sys_proto.h>

enum pll_clocks {
	PLL1_CLOCK = 0,
	PLL2_CLOCK,
	PLL3_CLOCK,
#ifdef CONFIG_MX53
	PLL4_CLOCK,
#endif
	PLL_CLOCKS,
};

struct mxc_pll_reg *mxc_plls[PLL_CLOCKS] = {
	[PLL1_CLOCK] = (struct mxc_pll_reg *)PLL1_BASE_ADDR,
	[PLL2_CLOCK] = (struct mxc_pll_reg *)PLL2_BASE_ADDR,
	[PLL3_CLOCK] = (struct mxc_pll_reg *)PLL3_BASE_ADDR,
#ifdef	CONFIG_MX53
	[PLL4_CLOCK] = (struct mxc_pll_reg *)PLL4_BASE_ADDR,
#endif
};

#define AHB_CLK_ROOT    133333333
#define SZ_DEC_1M       1000000
#define PLL_PD_MAX      16      /* Actual pd+1 */
#define PLL_MFI_MAX     15
#define PLL_MFI_MIN     5
#define ARM_DIV_MAX     8
#define IPG_DIV_MAX     4
#define AHB_DIV_MAX     8
#define EMI_DIV_MAX     8
#define NFC_DIV_MAX     8

#define MX5_CBCMR	0x00015154
#define MX5_CBCDR	0x02888945

struct fixed_pll_mfd {
	u32 ref_clk_hz;
	u32 mfd;
};

const struct fixed_pll_mfd fixed_mfd[] = {
	{MXC_HCLK, 24 * 16},
};

struct pll_param {
	u32 pd;
	u32 mfi;
	u32 mfn;
	u32 mfd;
};

#define PLL_FREQ_MAX(ref_clk)  (4 * (ref_clk) * PLL_MFI_MAX)
#define PLL_FREQ_MIN(ref_clk) \
		((2 * (ref_clk) * (PLL_MFI_MIN - 1)) / PLL_PD_MAX)
#define MAX_DDR_CLK     420000000
#define NFC_CLK_MAX     34000000

struct mxc_ccm_reg *mxc_ccm = (struct mxc_ccm_reg *)MXC_CCM_BASE;

void set_usboh3_clk(void)
{
	clrsetbits_le32(&mxc_ccm->cscmr1,
			MXC_CCM_CSCMR1_USBOH3_CLK_SEL_MASK,
			MXC_CCM_CSCMR1_USBOH3_CLK_SEL(1));
	clrsetbits_le32(&mxc_ccm->cscdr1,
			MXC_CCM_CSCDR1_USBOH3_CLK_PODF_MASK |
			MXC_CCM_CSCDR1_USBOH3_CLK_PRED_MASK,
			MXC_CCM_CSCDR1_USBOH3_CLK_PRED(4) |
			MXC_CCM_CSCDR1_USBOH3_CLK_PODF(1));
}

void enable_usboh3_clk(bool enable)
{
	unsigned int cg = enable ? MXC_CCM_CCGR_CG_ON : MXC_CCM_CCGR_CG_OFF;

	clrsetbits_le32(&mxc_ccm->CCGR2,
			MXC_CCM_CCGR2_USBOH3_60M(MXC_CCM_CCGR_CG_MASK),
			MXC_CCM_CCGR2_USBOH3_60M(cg));
}

#ifdef CONFIG_SYS_I2C_MXC
/* i2c_num can be from 0, to 1 for i.MX51 and 2 for i.MX53 */
int enable_i2c_clk(unsigned char enable, unsigned i2c_num)
{
	u32 mask;

#if defined(CONFIG_MX51)
	if (i2c_num > 1)
#elif defined(CONFIG_MX53)
	if (i2c_num > 2)
#endif
		return -EINVAL;
	mask = MXC_CCM_CCGR_CG_MASK <<
			(MXC_CCM_CCGR1_I2C1_OFFSET + (i2c_num << 1));
	if (enable)
		setbits_le32(&mxc_ccm->CCGR1, mask);
	else
		clrbits_le32(&mxc_ccm->CCGR1, mask);
	return 0;
}
#endif

void set_usb_phy_clk(void)
{
	clrbits_le32(&mxc_ccm->cscmr1, MXC_CCM_CSCMR1_USB_PHY_CLK_SEL);
}

#if defined(CONFIG_MX51)
void enable_usb_phy1_clk(bool enable)
{
	unsigned int cg = enable ? MXC_CCM_CCGR_CG_ON : MXC_CCM_CCGR_CG_OFF;

	clrsetbits_le32(&mxc_ccm->CCGR2,
			MXC_CCM_CCGR2_USB_PHY(MXC_CCM_CCGR_CG_MASK),
			MXC_CCM_CCGR2_USB_PHY(cg));
}

void enable_usb_phy2_clk(bool enable)
{
	/* i.MX51 has a single USB PHY clock, so do nothing here. */
}
#elif defined(CONFIG_MX53)
void enable_usb_phy1_clk(bool enable)
{
	unsigned int cg = enable ? MXC_CCM_CCGR_CG_ON : MXC_CCM_CCGR_CG_OFF;

	clrsetbits_le32(&mxc_ccm->CCGR4,
			MXC_CCM_CCGR4_USB_PHY1(MXC_CCM_CCGR_CG_MASK),
			MXC_CCM_CCGR4_USB_PHY1(cg));
}

void enable_usb_phy2_clk(bool enable)
{
	unsigned int cg = enable ? MXC_CCM_CCGR_CG_ON : MXC_CCM_CCGR_CG_OFF;

	clrsetbits_le32(&mxc_ccm->CCGR4,
			MXC_CCM_CCGR4_USB_PHY2(MXC_CCM_CCGR_CG_MASK),
			MXC_CCM_CCGR4_USB_PHY2(cg));
}
#endif

/*
 * Calculate the frequency of PLLn.
 */
static uint32_t decode_pll(struct mxc_pll_reg *pll, uint32_t infreq)
{
	uint32_t ctrl, op, mfd, mfn, mfi, pdf, ret;
	uint64_t refclk, temp;
	int32_t mfn_abs;

	ctrl = readl(&pll->ctrl);

	if (ctrl & MXC_DPLLC_CTL_HFSM) {
		mfn = readl(&pll->hfs_mfn);
		mfd = readl(&pll->hfs_mfd);
		op = readl(&pll->hfs_op);
	} else {
		mfn = readl(&pll->mfn);
		mfd = readl(&pll->mfd);
		op = readl(&pll->op);
	}

	mfd &= MXC_DPLLC_MFD_MFD_MASK;
	mfn &= MXC_DPLLC_MFN_MFN_MASK;
	pdf = op & MXC_DPLLC_OP_PDF_MASK;
	mfi = MXC_DPLLC_OP_MFI_RD(op);

	/* 21.2.3 */
	if (mfi < 5)
		mfi = 5;

	/* Sign extend */
	if (mfn >= 0x04000000) {
		mfn |= 0xfc000000;
		mfn_abs = -mfn;
	} else
		mfn_abs = mfn;

	refclk = infreq * 2;
	if (ctrl & MXC_DPLLC_CTL_DPDCK0_2_EN)
		refclk *= 2;

	do_div(refclk, pdf + 1);
	temp = refclk * mfn_abs;
	do_div(temp, mfd + 1);
	ret = refclk * mfi;

	if ((int)mfn < 0)
		ret -= temp;
	else
		ret += temp;

	return ret;
}

#ifdef CONFIG_MX51
/*
 * This function returns the Frequency Pre-Multiplier clock.
 */
static u32 get_fpm(void)
{
	u32 mult;
	u32 ccr = readl(&mxc_ccm->ccr);

	if (ccr & MXC_CCM_CCR_FPM_MULT)
		mult = 1024;
	else
		mult = 512;

	return MXC_CLK32 * mult;
}
#endif

/*
 * This function returns the low power audio clock.
 */
static u32 get_lp_apm(void)
{
	u32 ret_val = 0;
	u32 ccsr = readl(&mxc_ccm->ccsr);

	if (ccsr & MXC_CCM_CCSR_LP_APM)
#if defined(CONFIG_MX51)
		ret_val = get_fpm();
#elif defined(CONFIG_MX53)
		ret_val = decode_pll(mxc_plls[PLL4_CLOCK], MXC_HCLK);
#endif
	else
		ret_val = MXC_HCLK;

	return ret_val;
}

/*
 * Get mcu main rate
 */
u32 get_mcu_main_clk(void)
{
	u32 reg, freq;

	reg = MXC_CCM_CACRR_ARM_PODF_RD(readl(&mxc_ccm->cacrr));
	freq = decode_pll(mxc_plls[PLL1_CLOCK], MXC_HCLK);
	return freq / (reg + 1);
}

/*
 * Get the rate of peripheral's root clock.
 */
u32 get_periph_clk(void)
{
	u32 reg;

	reg = readl(&mxc_ccm->cbcdr);
	if (!(reg & MXC_CCM_CBCDR_PERIPH_CLK_SEL))
		return decode_pll(mxc_plls[PLL2_CLOCK], MXC_HCLK);
	reg = readl(&mxc_ccm->cbcmr);
	switch (MXC_CCM_CBCMR_PERIPH_CLK_SEL_RD(reg)) {
	case 0:
		return decode_pll(mxc_plls[PLL1_CLOCK], MXC_HCLK);
	case 1:
		return decode_pll(mxc_plls[PLL3_CLOCK], MXC_HCLK);
	case 2:
		return get_lp_apm();
	default:
		return 0;
	}
	/* NOTREACHED */
}

/*
 * Get the rate of ipg clock.
 */
static u32 get_ipg_clk(void)
{
	uint32_t freq, reg, div;

	freq = get_ahb_clk();

	reg = readl(&mxc_ccm->cbcdr);
	div = MXC_CCM_CBCDR_IPG_PODF_RD(reg) + 1;

	return freq / div;
}

/*
 * Get the rate of ipg_per clock.
 */
static u32 get_ipg_per_clk(void)
{
	u32 freq, pred1, pred2, podf;

	if (readl(&mxc_ccm->cbcmr) & MXC_CCM_CBCMR_PERCLK_IPG_CLK_SEL)
		return get_ipg_clk();

	if (readl(&mxc_ccm->cbcmr) & MXC_CCM_CBCMR_PERCLK_LP_APM_CLK_SEL)
		freq = get_lp_apm();
	else
		freq = get_periph_clk();
	podf = readl(&mxc_ccm->cbcdr);
	pred1 = MXC_CCM_CBCDR_PERCLK_PRED1_RD(podf);
	pred2 = MXC_CCM_CBCDR_PERCLK_PRED2_RD(podf);
	podf = MXC_CCM_CBCDR_PERCLK_PODF_RD(podf);
	return freq / ((pred1 + 1) * (pred2 + 1) * (podf + 1));
}

/* Get the output clock rate of a standard PLL MUX for peripherals. */
static u32 get_standard_pll_sel_clk(u32 clk_sel)
{
	u32 freq = 0;

	switch (clk_sel & 0x3) {
	case 0:
		freq = decode_pll(mxc_plls[PLL1_CLOCK], MXC_HCLK);
		break;
	case 1:
		freq = decode_pll(mxc_plls[PLL2_CLOCK], MXC_HCLK);
		break;
	case 2:
		freq = decode_pll(mxc_plls[PLL3_CLOCK], MXC_HCLK);
		break;
	case 3:
		freq = get_lp_apm();
		break;
	}

	return freq;
}

/*
 * Get the rate of uart clk.
 */
static u32 get_uart_clk(void)
{
	unsigned int clk_sel, freq, reg, pred, podf;

	reg = readl(&mxc_ccm->cscmr1);
	clk_sel = MXC_CCM_CSCMR1_UART_CLK_SEL_RD(reg);
	freq = get_standard_pll_sel_clk(clk_sel);

	reg = readl(&mxc_ccm->cscdr1);
	pred = MXC_CCM_CSCDR1_UART_CLK_PRED_RD(reg);
	podf = MXC_CCM_CSCDR1_UART_CLK_PODF_RD(reg);
	freq /= (pred + 1) * (podf + 1);

	return freq;
}

/*
 * get cspi clock rate.
 */
static u32 imx_get_cspiclk(void)
{
	u32 ret_val = 0, pdf, pre_pdf, clk_sel, freq;
	u32 cscmr1 = readl(&mxc_ccm->cscmr1);
	u32 cscdr2 = readl(&mxc_ccm->cscdr2);

	pre_pdf = MXC_CCM_CSCDR2_CSPI_CLK_PRED_RD(cscdr2);
	pdf = MXC_CCM_CSCDR2_CSPI_CLK_PODF_RD(cscdr2);
	clk_sel = MXC_CCM_CSCMR1_CSPI_CLK_SEL_RD(cscmr1);
	freq = get_standard_pll_sel_clk(clk_sel);
	ret_val = freq / ((pre_pdf + 1) * (pdf + 1));
	return ret_val;
}

/*
 * get esdhc clock rate.
 */
static u32 get_esdhc_clk(u32 port)
{
	u32 clk_sel = 0, pred = 0, podf = 0, freq = 0;
	u32 cscmr1 = readl(&mxc_ccm->cscmr1);
	u32 cscdr1 = readl(&mxc_ccm->cscdr1);

	switch (port) {
	case 0:
		clk_sel = MXC_CCM_CSCMR1_ESDHC1_MSHC1_CLK_SEL_RD(cscmr1);
		pred = MXC_CCM_CSCDR1_ESDHC1_MSHC1_CLK_PRED_RD(cscdr1);
		podf = MXC_CCM_CSCDR1_ESDHC1_MSHC1_CLK_PODF_RD(cscdr1);
		break;
	case 1:
		clk_sel = MXC_CCM_CSCMR1_ESDHC2_MSHC2_CLK_SEL_RD(cscmr1);
		pred = MXC_CCM_CSCDR1_ESDHC2_MSHC2_CLK_PRED_RD(cscdr1);
		podf = MXC_CCM_CSCDR1_ESDHC2_MSHC2_CLK_PODF_RD(cscdr1);
		break;
	case 2:
		if (cscmr1 & MXC_CCM_CSCMR1_ESDHC3_CLK_SEL)
			return get_esdhc_clk(1);
		else
			return get_esdhc_clk(0);
	case 3:
		if (cscmr1 & MXC_CCM_CSCMR1_ESDHC4_CLK_SEL)
			return get_esdhc_clk(1);
		else
			return get_esdhc_clk(0);
	default:
		break;
	}

	freq = get_standard_pll_sel_clk(clk_sel) / ((pred + 1) * (podf + 1));
	return freq;
}

static u32 get_axi_a_clk(void)
{
	u32 cbcdr = readl(&mxc_ccm->cbcdr);
	u32 pdf = MXC_CCM_CBCDR_AXI_A_PODF_RD(cbcdr);

	return  get_periph_clk() / (pdf + 1);
}

static u32 get_axi_b_clk(void)
{
	u32 cbcdr = readl(&mxc_ccm->cbcdr);
	u32 pdf = MXC_CCM_CBCDR_AXI_B_PODF_RD(cbcdr);

	return  get_periph_clk() / (pdf + 1);
}

static u32 get_emi_slow_clk(void)
{
	u32 cbcdr = readl(&mxc_ccm->cbcdr);
	u32 emi_clk_sel = cbcdr & MXC_CCM_CBCDR_EMI_CLK_SEL;
	u32 pdf = MXC_CCM_CBCDR_EMI_PODF_RD(cbcdr);

	if (emi_clk_sel)
		return  get_ahb_clk() / (pdf + 1);

	return  get_periph_clk() / (pdf + 1);
}

static u32 get_ddr_clk(void)
{
	u32 ret_val = 0;
	u32 cbcmr = readl(&mxc_ccm->cbcmr);
	u32 ddr_clk_sel = MXC_CCM_CBCMR_DDR_CLK_SEL_RD(cbcmr);
#ifdef CONFIG_MX51
	u32 cbcdr = readl(&mxc_ccm->cbcdr);
	if (cbcdr & MXC_CCM_CBCDR_DDR_HIFREQ_SEL) {
		u32 ddr_clk_podf = MXC_CCM_CBCDR_DDR_PODF_RD(cbcdr);

		ret_val = decode_pll(mxc_plls[PLL1_CLOCK], MXC_HCLK);
		ret_val /= ddr_clk_podf + 1;

		return ret_val;
	}
#endif
	switch (ddr_clk_sel) {
	case 0:
		ret_val = get_axi_a_clk();
		break;
	case 1:
		ret_val = get_axi_b_clk();
		break;
	case 2:
		ret_val = get_emi_slow_clk();
		break;
	case 3:
		ret_val = get_ahb_clk();
		break;
	default:
		break;
	}

	return ret_val;
}

/*
 * The API of get mxc clocks.
 */
unsigned int mxc_get_clock(enum mxc_clock clk)
{
	switch (clk) {
	case MXC_ARM_CLK:
		return get_mcu_main_clk();
	case MXC_AHB_CLK:
		return get_ahb_clk();
	case MXC_IPG_CLK:
		return get_ipg_clk();
	case MXC_IPG_PERCLK:
	case MXC_I2C_CLK:
		return get_ipg_per_clk();
	case MXC_UART_CLK:
		return get_uart_clk();
	case MXC_CSPI_CLK:
		return imx_get_cspiclk();
	case MXC_ESDHC_CLK:
		return get_esdhc_clk(0);
	case MXC_ESDHC2_CLK:
		return get_esdhc_clk(1);
	case MXC_ESDHC3_CLK:
		return get_esdhc_clk(2);
	case MXC_ESDHC4_CLK:
		return get_esdhc_clk(3);
	case MXC_FEC_CLK:
		return get_ipg_clk();
	case MXC_SATA_CLK:
		return get_ahb_clk();
	case MXC_DDR_CLK:
		return get_ddr_clk();
	default:
		break;
	}
	return -EINVAL;
}

u32 imx_get_uartclk(void)
{
	return get_uart_clk();
}

u32 imx_get_fecclk(void)
{
	return get_ipg_clk();
}

static int gcd(int m, int n)
{
	int t;
	while (m > 0) {
		if (n > m) {
			t = m;
			m = n;
			n = t;
		} /* swap */
		m -= n;
	}
	return n;
}

/*
 * This is to calculate various parameters based on reference clock and
 * targeted clock based on the equation:
 *      t_clk = 2*ref_freq*(mfi + mfn/(mfd+1))/(pd+1)
 * This calculation is based on a fixed MFD value for simplicity.
 */
static int calc_pll_params(u32 ref, u32 target, struct pll_param *pll)
{
	u64 pd, mfi = 1, mfn, mfd, t1;
	u32 n_target = target;
	u32 n_ref = ref, i;

	/*
	 * Make sure targeted freq is in the valid range.
	 * Otherwise the following calculation might be wrong!!!
	 */
	if (n_target < PLL_FREQ_MIN(ref) ||
		n_target > PLL_FREQ_MAX(ref)) {
		printf("Targeted peripheral clock should be"
			"within [%d - %d]\n",
			PLL_FREQ_MIN(ref) / SZ_DEC_1M,
			PLL_FREQ_MAX(ref) / SZ_DEC_1M);
		return -EINVAL;
	}

	for (i = 0; i < ARRAY_SIZE(fixed_mfd); i++) {
		if (fixed_mfd[i].ref_clk_hz == ref) {
			mfd = fixed_mfd[i].mfd;
			break;
		}
	}

	if (i == ARRAY_SIZE(fixed_mfd))
		return -EINVAL;

	/* Use n_target and n_ref to avoid overflow */
	for (pd = 1; pd <= PLL_PD_MAX; pd++) {
		t1 = n_target * pd;
		do_div(t1, (4 * n_ref));
		mfi = t1;
		if (mfi > PLL_MFI_MAX)
			return -EINVAL;
		else if (mfi < 5)
			continue;
		break;
	}
	/*
	 * Now got pd and mfi already
	 *
	 * mfn = (((n_target * pd) / 4 - n_ref * mfi) * mfd) / n_ref;
	 */
	t1 = n_target * pd;
	do_div(t1, 4);
	t1 -= n_ref * mfi;
	t1 *= mfd;
	do_div(t1, n_ref);
	mfn = t1;
	debug("ref=%d, target=%d, pd=%d," "mfi=%d,mfn=%d, mfd=%d\n",
		ref, n_target, (u32)pd, (u32)mfi, (u32)mfn, (u32)mfd);
	i = 1;
	if (mfn != 0)
		i = gcd(mfd, mfn);
	pll->pd = (u32)pd;
	pll->mfi = (u32)mfi;
	do_div(mfn, i);
	pll->mfn = (u32)mfn;
	do_div(mfd, i);
	pll->mfd = (u32)mfd;

	return 0;
}

#define calc_div(tgt_clk, src_clk, limit) ({		\
		u32 v = 0;				\
		if (((src_clk) % (tgt_clk)) <= 100)	\
			v = (src_clk) / (tgt_clk);	\
		else					\
			v = ((src_clk) / (tgt_clk)) + 1;\
		if (v > limit)				\
			v = limit;			\
		(v - 1);				\
	})

#define CHANGE_PLL_SETTINGS(pll, pd, fi, fn, fd) \
	{	\
		writel(0x1232, &pll->ctrl);		\
		writel(0x2, &pll->config);		\
		writel((((pd) - 1) << 0) | ((fi) << 4),	\
			&pll->op);			\
		writel(fn, &(pll->mfn));		\
		writel((fd) - 1, &pll->mfd);		\
		writel((((pd) - 1) << 0) | ((fi) << 4),	\
			&pll->hfs_op);			\
		writel(fn, &pll->hfs_mfn);		\
		writel((fd) - 1, &pll->hfs_mfd);	\
		writel(0x1232, &pll->ctrl);		\
		while (!readl(&pll->ctrl) & 0x1)	\
			;\
	}

static int config_pll_clk(enum pll_clocks index, struct pll_param *pll_param)
{
	u32 ccsr = readl(&mxc_ccm->ccsr);
	struct mxc_pll_reg *pll = mxc_plls[index];

	switch (index) {
	case PLL1_CLOCK:
		/* Switch ARM to PLL2 clock */
		writel(ccsr | MXC_CCM_CCSR_PLL1_SW_CLK_SEL,
				&mxc_ccm->ccsr);
		CHANGE_PLL_SETTINGS(pll, pll_param->pd,
					pll_param->mfi, pll_param->mfn,
					pll_param->mfd);
		/* Switch back */
		writel(ccsr & ~MXC_CCM_CCSR_PLL1_SW_CLK_SEL,
				&mxc_ccm->ccsr);
		break;
	case PLL2_CLOCK:
		/* Switch to pll2 bypass clock */
		writel(ccsr | MXC_CCM_CCSR_PLL2_SW_CLK_SEL,
				&mxc_ccm->ccsr);
		CHANGE_PLL_SETTINGS(pll, pll_param->pd,
					pll_param->mfi, pll_param->mfn,
					pll_param->mfd);
		/* Switch back */
		writel(ccsr & ~MXC_CCM_CCSR_PLL2_SW_CLK_SEL,
				&mxc_ccm->ccsr);
		break;
	case PLL3_CLOCK:
		/* Switch to pll3 bypass clock */
		writel(ccsr | MXC_CCM_CCSR_PLL3_SW_CLK_SEL,
				&mxc_ccm->ccsr);
		CHANGE_PLL_SETTINGS(pll, pll_param->pd,
					pll_param->mfi, pll_param->mfn,
					pll_param->mfd);
		/* Switch back */
		writel(ccsr & ~MXC_CCM_CCSR_PLL3_SW_CLK_SEL,
				&mxc_ccm->ccsr);
		break;
#ifdef CONFIG_MX53
	case PLL4_CLOCK:
		/* Switch to pll4 bypass clock */
		writel(ccsr | MXC_CCM_CCSR_PLL4_SW_CLK_SEL,
				&mxc_ccm->ccsr);
		CHANGE_PLL_SETTINGS(pll, pll_param->pd,
					pll_param->mfi, pll_param->mfn,
					pll_param->mfd);
		/* Switch back */
		writel(ccsr & ~MXC_CCM_CCSR_PLL4_SW_CLK_SEL,
				&mxc_ccm->ccsr);
		break;
#endif
	default:
		return -EINVAL;
	}

	return 0;
}

/* Config CPU clock */
static int config_core_clk(u32 ref, u32 freq)
{
	int ret = 0;
	struct pll_param pll_param;

	memset(&pll_param, 0, sizeof(struct pll_param));

	/* The case that periph uses PLL1 is not considered here */
	ret = calc_pll_params(ref, freq, &pll_param);
	if (ret != 0) {
		printf("Error:Can't find pll parameters: %d\n", ret);
		return ret;
	}

	return config_pll_clk(PLL1_CLOCK, &pll_param);
}

static int config_nfc_clk(u32 nfc_clk)
{
	u32 parent_rate = get_emi_slow_clk();
	u32 div;

	if (nfc_clk == 0)
		return -EINVAL;
	div = parent_rate / nfc_clk;
	if (div == 0)
		div++;
	if (parent_rate / div > NFC_CLK_MAX)
		div++;
	clrsetbits_le32(&mxc_ccm->cbcdr,
			MXC_CCM_CBCDR_NFC_PODF_MASK,
			MXC_CCM_CBCDR_NFC_PODF(div - 1));
	while (readl(&mxc_ccm->cdhipr) != 0)
		;
	return 0;
}

void enable_nfc_clk(unsigned char enable)
{
	unsigned int cg = enable ? MXC_CCM_CCGR_CG_ON : MXC_CCM_CCGR_CG_OFF;

	clrsetbits_le32(&mxc_ccm->CCGR5,
		MXC_CCM_CCGR5_EMI_ENFC(MXC_CCM_CCGR_CG_MASK),
		MXC_CCM_CCGR5_EMI_ENFC(cg));
}

#ifdef CONFIG_FSL_IIM
void enable_efuse_prog_supply(bool enable)
{
	if (enable)
		setbits_le32(&mxc_ccm->cgpr,
			     MXC_CCM_CGPR_EFUSE_PROG_SUPPLY_GATE);
	else
		clrbits_le32(&mxc_ccm->cgpr,
			     MXC_CCM_CGPR_EFUSE_PROG_SUPPLY_GATE);
}
#endif

/* Config main_bus_clock for periphs */
static int config_periph_clk(u32 ref, u32 freq)
{
	int ret = 0;
	struct pll_param pll_param;

	memset(&pll_param, 0, sizeof(struct pll_param));

	if (readl(&mxc_ccm->cbcdr) & MXC_CCM_CBCDR_PERIPH_CLK_SEL) {
		ret = calc_pll_params(ref, freq, &pll_param);
		if (ret != 0) {
			printf("Error:Can't find pll parameters: %d\n",
				ret);
			return ret;
		}
		switch (MXC_CCM_CBCMR_PERIPH_CLK_SEL_RD(
				readl(&mxc_ccm->cbcmr))) {
		case 0:
			return config_pll_clk(PLL1_CLOCK, &pll_param);
			break;
		case 1:
			return config_pll_clk(PLL3_CLOCK, &pll_param);
			break;
		default:
			return -EINVAL;
		}
	}

	return 0;
}

static int config_ddr_clk(u32 emi_clk)
{
	u32 clk_src;
	s32 shift = 0, clk_sel, div = 1;
	u32 cbcmr = readl(&mxc_ccm->cbcmr);

	if (emi_clk > MAX_DDR_CLK) {
		printf("Warning:DDR clock should not exceed %d MHz\n",
			MAX_DDR_CLK / SZ_DEC_1M);
		emi_clk = MAX_DDR_CLK;
	}

	clk_src = get_periph_clk();
	/* Find DDR clock input */
	clk_sel = MXC_CCM_CBCMR_DDR_CLK_SEL_RD(cbcmr);
	switch (clk_sel) {
	case 0:
		shift = 16;
		break;
	case 1:
		shift = 19;
		break;
	case 2:
		shift = 22;
		break;
	case 3:
		shift = 10;
		break;
	default:
		return -EINVAL;
	}

	if ((clk_src % emi_clk) < 10000000)
		div = clk_src / emi_clk;
	else
		div = (clk_src / emi_clk) + 1;
	if (div > 8)
		div = 8;

	clrsetbits_le32(&mxc_ccm->cbcdr, 0x7 << shift, (div - 1) << shift);
	while (readl(&mxc_ccm->cdhipr) != 0)
		;
	writel(0x0, &mxc_ccm->ccdr);

	return 0;
}

#ifdef CONFIG_MX53
static int config_ldb_clk(u32 ref, u32 freq)
{
	int ret = 0;
	struct pll_param pll_param;

	memset(&pll_param, 0, sizeof(struct pll_param));

	ret = calc_pll_params(ref, freq, &pll_param);
	if (ret != 0) {
		printf("Error:Can't find pll parameters: %d\n",
			ret);
		return ret;
	}

	return config_pll_clk(PLL4_CLOCK, &pll_param);
}
#else
static int config_ldb_clk(u32 ref, u32 freq)
{
	/* Platform not supported */
	return -EINVAL;
}
#endif

/*
 * This function assumes the expected core clock has to be changed by
 * modifying the PLL. This is NOT true always but for most of the times,
 * it is. So it assumes the PLL output freq is the same as the expected
 * core clock (presc=1) unless the core clock is less than PLL_FREQ_MIN.
 * In the latter case, it will try to increase the presc value until
 * (presc*core_clk) is greater than PLL_FREQ_MIN. It then makes call to
 * calc_pll_params() and obtains the values of PD, MFI,MFN, MFD based
 * on the targeted PLL and reference input clock to the PLL. Lastly,
 * it sets the register based on these values along with the dividers.
 * Note 1) There is no value checking for the passed-in divider values
 *         so the caller has to make sure those values are sensible.
 *      2) Also adjust the NFC divider such that the NFC clock doesn't
 *         exceed NFC_CLK_MAX.
 *      3) IPU HSP clock is independent of AHB clock. Even it can go up to
 *         177MHz for higher voltage, this function fixes the max to 133MHz.
 *      4) This function should not have allowed diag_printf() calls since
 *         the serial driver has been stoped. But leave then here to allow
 *         easy debugging by NOT calling the cyg_hal_plf_serial_stop().
 */
int mxc_set_clock(u32 ref, u32 freq, enum mxc_clock clk)
{
	freq *= SZ_DEC_1M;

	switch (clk) {
	case MXC_ARM_CLK:
		if (config_core_clk(ref, freq))
			return -EINVAL;
		break;
	case MXC_PERIPH_CLK:
		if (config_periph_clk(ref, freq))
			return -EINVAL;
		break;
	case MXC_DDR_CLK:
		if (config_ddr_clk(freq))
			return -EINVAL;
		break;
	case MXC_NFC_CLK:
		if (config_nfc_clk(freq))
			return -EINVAL;
		break;
	case MXC_LDB_CLK:
		if (config_ldb_clk(ref, freq))
			return -EINVAL;
		break;
	default:
		printf("Warning:Unsupported or invalid clock type\n");
	}

	return 0;
}

#ifdef CONFIG_MX53
/*
 * The clock for the external interface can be set to use internal clock
 * if fuse bank 4, row 3, bit 2 is set.
 * This is an undocumented feature and it was confirmed by Freescale's support:
 * Fuses (but not pins) may be used to configure SATA clocks.
 * Particularly the i.MX53 Fuse_Map contains the next information
 * about configuring SATA clocks :  SATA_ALT_REF_CLK[1:0] (offset 0x180C)
 * '00' - 100MHz (External)
 * '01' - 50MHz (External)
 * '10' - 120MHz, internal (USB PHY)
 * '11' - Reserved
*/
void mxc_set_sata_internal_clock(void)
{
	u32 *tmp_base =
		(u32 *)(IIM_BASE_ADDR + 0x180c);

	set_usb_phy_clk();

	clrsetbits_le32(tmp_base, 0x6, 0x4);
}
#endif

#ifndef CONFIG_SPL_BUILD
/*
 * Dump some core clockes.
 */
static int do_mx5_showclocks(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
	u32 freq;

	freq = decode_pll(mxc_plls[PLL1_CLOCK], MXC_HCLK);
	printf("PLL1       %8d MHz\n", freq / 1000000);
	freq = decode_pll(mxc_plls[PLL2_CLOCK], MXC_HCLK);
	printf("PLL2       %8d MHz\n", freq / 1000000);
	freq = decode_pll(mxc_plls[PLL3_CLOCK], MXC_HCLK);
	printf("PLL3       %8d MHz\n", freq / 1000000);
#ifdef	CONFIG_MX53
	freq = decode_pll(mxc_plls[PLL4_CLOCK], MXC_HCLK);
	printf("PLL4       %8d MHz\n", freq / 1000000);
#endif

	printf("\n");
	printf("AHB        %8d kHz\n", mxc_get_clock(MXC_AHB_CLK) / 1000);
	printf("IPG        %8d kHz\n", mxc_get_clock(MXC_IPG_CLK) / 1000);
	printf("IPG PERCLK %8d kHz\n", mxc_get_clock(MXC_IPG_PERCLK) / 1000);
	printf("DDR        %8d kHz\n", mxc_get_clock(MXC_DDR_CLK) / 1000);
#ifdef CONFIG_MXC_SPI
	printf("CSPI       %8d kHz\n", mxc_get_clock(MXC_CSPI_CLK) / 1000);
#endif
	return 0;
}

/***************************************************/

U_BOOT_CMD(
	clocks,	CONFIG_SYS_MAXARGS, 1, do_mx5_showclocks,
	"display clocks",
	""
);
#endif