170 lines
		
	
	
		
			4.6 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			170 lines
		
	
	
		
			4.6 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| // SPDX-License-Identifier: GPL-2.0+
 | |
| /*
 | |
|  * Copyright 2014 Broadcom Corporation.
 | |
|  */
 | |
| 
 | |
| #include <common.h>
 | |
| #include <asm/io.h>
 | |
| #include <asm/iproc-common/armpll.h>
 | |
| #include <asm/iproc-common/sysmap.h>
 | |
| 
 | |
| #define NELEMS(x)	(sizeof(x) / sizeof(x[0]))
 | |
| 
 | |
| struct armpll_parameters {
 | |
| 	unsigned int mode;
 | |
| 	unsigned int ndiv_int;
 | |
| 	unsigned int ndiv_frac;
 | |
| 	unsigned int pdiv;
 | |
| 	unsigned int freqid;
 | |
| };
 | |
| 
 | |
| struct armpll_parameters armpll_clk_tab[] = {
 | |
| 	{   25, 64,      1, 1, 0},
 | |
| 	{  100, 64,      1, 1, 2},
 | |
| 	{  400, 64,      1, 1, 6},
 | |
| 	{  448, 71, 713050, 1, 6},
 | |
| 	{  500, 80,      1, 1, 6},
 | |
| 	{  560, 89, 629145, 1, 6},
 | |
| 	{  600, 96,      1, 1, 6},
 | |
| 	{  800, 64,      1, 1, 7},
 | |
| 	{  896, 71, 713050, 1, 7},
 | |
| 	{ 1000, 80,      1, 1, 7},
 | |
| 	{ 1100, 88,      1, 1, 7},
 | |
| 	{ 1120, 89, 629145, 1, 7},
 | |
| 	{ 1200, 96,      1, 1, 7},
 | |
| };
 | |
| 
 | |
| uint32_t armpll_config(uint32_t clkmhz)
 | |
| {
 | |
| 	uint32_t freqid;
 | |
| 	uint32_t ndiv_frac;
 | |
| 	uint32_t pll;
 | |
| 	uint32_t status = 1;
 | |
| 	uint32_t timeout_countdown;
 | |
| 	int i;
 | |
| 
 | |
| 	for (i = 0; i < NELEMS(armpll_clk_tab); i++) {
 | |
| 		if (armpll_clk_tab[i].mode == clkmhz) {
 | |
| 			status = 0;
 | |
| 			break;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	if (status) {
 | |
| 		printf("Error: Clock configuration not supported\n");
 | |
| 		goto armpll_config_done;
 | |
| 	}
 | |
| 
 | |
| 	/* Enable write access */
 | |
| 	writel(IPROC_REG_WRITE_ACCESS, IHOST_PROC_CLK_WR_ACCESS);
 | |
| 
 | |
| 	if (clkmhz == 25)
 | |
| 		freqid = 0;
 | |
| 	else
 | |
| 		freqid = 2;
 | |
| 
 | |
| 	/* Bypass ARM clock and run on sysclk */
 | |
| 	writel(1 << IHOST_PROC_CLK_POLICY_FREQ__PRIV_ACCESS_MODE |
 | |
| 	       freqid << IHOST_PROC_CLK_POLICY_FREQ__POLICY3_FREQ_R |
 | |
| 	       freqid << IHOST_PROC_CLK_POLICY_FREQ__POLICY2_FREQ_R |
 | |
| 	       freqid << IHOST_PROC_CLK_POLICY_FREQ__POLICY1_FREQ_R |
 | |
| 	       freqid << IHOST_PROC_CLK_POLICY_FREQ__POLICY0_FREQ_R,
 | |
| 	       IHOST_PROC_CLK_POLICY_FREQ);
 | |
| 
 | |
| 	writel(1 << IHOST_PROC_CLK_POLICY_CTL__GO |
 | |
| 	       1 << IHOST_PROC_CLK_POLICY_CTL__GO_AC,
 | |
| 	       IHOST_PROC_CLK_POLICY_CTL);
 | |
| 
 | |
| 	/* Poll CCU until operation complete */
 | |
| 	timeout_countdown = 0x100000;
 | |
| 	while (readl(IHOST_PROC_CLK_POLICY_CTL) &
 | |
| 	       (1 << IHOST_PROC_CLK_POLICY_CTL__GO)) {
 | |
| 		timeout_countdown--;
 | |
| 		if (timeout_countdown == 0) {
 | |
| 			printf("CCU polling timedout\n");
 | |
| 			status = 1;
 | |
| 			goto armpll_config_done;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	if (clkmhz == 25 || clkmhz == 100) {
 | |
| 		status = 0;
 | |
| 		goto armpll_config_done;
 | |
| 	}
 | |
| 
 | |
| 	/* Now it is safe to program the PLL */
 | |
| 	pll = readl(IHOST_PROC_CLK_PLLARMB);
 | |
| 	pll &= ~((1 << IHOST_PROC_CLK_PLLARMB__PLLARM_NDIV_FRAC_WIDTH) - 1);
 | |
| 	ndiv_frac =
 | |
| 		((1 << IHOST_PROC_CLK_PLLARMB__PLLARM_NDIV_FRAC_WIDTH) - 1) &
 | |
| 		 (armpll_clk_tab[i].ndiv_frac <<
 | |
| 		 IHOST_PROC_CLK_PLLARMB__PLLARM_NDIV_FRAC_R);
 | |
| 	pll |= ndiv_frac;
 | |
| 	writel(pll, IHOST_PROC_CLK_PLLARMB);
 | |
| 
 | |
| 	writel(1 << IHOST_PROC_CLK_PLLARMA__PLLARM_LOCK |
 | |
| 	       armpll_clk_tab[i].ndiv_int <<
 | |
| 			IHOST_PROC_CLK_PLLARMA__PLLARM_NDIV_INT_R |
 | |
| 	       armpll_clk_tab[i].pdiv <<
 | |
| 			IHOST_PROC_CLK_PLLARMA__PLLARM_PDIV_R |
 | |
| 	       1 << IHOST_PROC_CLK_PLLARMA__PLLARM_SOFT_RESETB,
 | |
| 	       IHOST_PROC_CLK_PLLARMA);
 | |
| 
 | |
| 	/* Poll ARM PLL Lock until operation complete */
 | |
| 	timeout_countdown = 0x100000;
 | |
| 	while (readl(IHOST_PROC_CLK_PLLARMA) &
 | |
| 	       (1 << IHOST_PROC_CLK_PLLARMA__PLLARM_LOCK)) {
 | |
| 		timeout_countdown--;
 | |
| 		if (timeout_countdown == 0) {
 | |
| 			printf("ARM PLL lock failed\n");
 | |
| 			status = 1;
 | |
| 			goto armpll_config_done;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	pll = readl(IHOST_PROC_CLK_PLLARMA);
 | |
| 	pll |= (1 << IHOST_PROC_CLK_PLLARMA__PLLARM_SOFT_POST_RESETB);
 | |
| 	writel(pll, IHOST_PROC_CLK_PLLARMA);
 | |
| 
 | |
| 	/* Set the policy */
 | |
| 	writel(1 << IHOST_PROC_CLK_POLICY_FREQ__PRIV_ACCESS_MODE |
 | |
| 	       armpll_clk_tab[i].freqid <<
 | |
| 			IHOST_PROC_CLK_POLICY_FREQ__POLICY3_FREQ_R |
 | |
| 	       armpll_clk_tab[i].freqid <<
 | |
| 			IHOST_PROC_CLK_POLICY_FREQ__POLICY2_FREQ_R |
 | |
| 	       armpll_clk_tab[i].freqid <<
 | |
| 			IHOST_PROC_CLK_POLICY_FREQ__POLICY1_FREQ_R |
 | |
| 	       armpll_clk_tab[i+4].freqid <<
 | |
| 			IHOST_PROC_CLK_POLICY_FREQ__POLICY0_FREQ_R,
 | |
| 	       IHOST_PROC_CLK_POLICY_FREQ);
 | |
| 
 | |
| 	writel(IPROC_CLKCT_HDELAY_SW_EN, IHOST_PROC_CLK_CORE0_CLKGATE);
 | |
| 	writel(IPROC_CLKCT_HDELAY_SW_EN, IHOST_PROC_CLK_CORE1_CLKGATE);
 | |
| 	writel(IPROC_CLKCT_HDELAY_SW_EN, IHOST_PROC_CLK_ARM_SWITCH_CLKGATE);
 | |
| 	writel(IPROC_CLKCT_HDELAY_SW_EN, IHOST_PROC_CLK_ARM_PERIPH_CLKGATE);
 | |
| 	writel(IPROC_CLKCT_HDELAY_SW_EN, IHOST_PROC_CLK_APB0_CLKGATE);
 | |
| 
 | |
| 	writel(1 << IHOST_PROC_CLK_POLICY_CTL__GO |
 | |
| 	       1 << IHOST_PROC_CLK_POLICY_CTL__GO_AC,
 | |
| 	       IHOST_PROC_CLK_POLICY_CTL);
 | |
| 
 | |
| 	/* Poll CCU until operation complete */
 | |
| 	timeout_countdown = 0x100000;
 | |
| 	while (readl(IHOST_PROC_CLK_POLICY_CTL) &
 | |
| 	       (1 << IHOST_PROC_CLK_POLICY_CTL__GO)) {
 | |
| 		timeout_countdown--;
 | |
| 		if (timeout_countdown == 0) {
 | |
| 			printf("CCU polling failed\n");
 | |
| 			status = 1;
 | |
| 			goto armpll_config_done;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	status = 0;
 | |
| armpll_config_done:
 | |
| 	/* Disable access to PLL registers */
 | |
| 	writel(0, IHOST_PROC_CLK_WR_ACCESS);
 | |
| 
 | |
| 	return status;
 | |
| }
 | 
