1 /* 2 * Copyright 2014 Broadcom Corporation. 3 * 4 * SPDX-License-Identifier: GPL-2.0+ 5 */ 6 7 #include <common.h> 8 #include <asm/io.h> 9 #include <asm/iproc-common/armpll.h> 10 #include <asm/iproc-common/sysmap.h> 11 12 #define NELEMS(x) (sizeof(x) / sizeof(x[0])) 13 14 struct armpll_parameters { 15 unsigned int mode; 16 unsigned int ndiv_int; 17 unsigned int ndiv_frac; 18 unsigned int pdiv; 19 unsigned int freqid; 20 }; 21 22 struct armpll_parameters armpll_clk_tab[] = { 23 { 25, 64, 1, 1, 0}, 24 { 100, 64, 1, 1, 2}, 25 { 400, 64, 1, 1, 6}, 26 { 448, 71, 713050, 1, 6}, 27 { 500, 80, 1, 1, 6}, 28 { 560, 89, 629145, 1, 6}, 29 { 600, 96, 1, 1, 6}, 30 { 800, 64, 1, 1, 7}, 31 { 896, 71, 713050, 1, 7}, 32 { 1000, 80, 1, 1, 7}, 33 { 1100, 88, 1, 1, 7}, 34 { 1120, 89, 629145, 1, 7}, 35 { 1200, 96, 1, 1, 7}, 36 }; 37 38 uint32_t armpll_config(uint32_t clkmhz) 39 { 40 uint32_t freqid; 41 uint32_t ndiv_frac; 42 uint32_t pll; 43 uint32_t status = 1; 44 uint32_t timeout_countdown; 45 int i; 46 47 for (i = 0; i < NELEMS(armpll_clk_tab); i++) { 48 if (armpll_clk_tab[i].mode == clkmhz) { 49 status = 0; 50 break; 51 } 52 } 53 54 if (status) { 55 printf("Error: Clock configuration not supported\n"); 56 goto armpll_config_done; 57 } 58 59 /* Enable write access */ 60 writel(IPROC_REG_WRITE_ACCESS, IHOST_PROC_CLK_WR_ACCESS); 61 62 if (clkmhz == 25) 63 freqid = 0; 64 else 65 freqid = 2; 66 67 /* Bypass ARM clock and run on sysclk */ 68 writel(1 << IHOST_PROC_CLK_POLICY_FREQ__PRIV_ACCESS_MODE | 69 freqid << IHOST_PROC_CLK_POLICY_FREQ__POLICY3_FREQ_R | 70 freqid << IHOST_PROC_CLK_POLICY_FREQ__POLICY2_FREQ_R | 71 freqid << IHOST_PROC_CLK_POLICY_FREQ__POLICY1_FREQ_R | 72 freqid << IHOST_PROC_CLK_POLICY_FREQ__POLICY0_FREQ_R, 73 IHOST_PROC_CLK_POLICY_FREQ); 74 75 writel(1 << IHOST_PROC_CLK_POLICY_CTL__GO | 76 1 << IHOST_PROC_CLK_POLICY_CTL__GO_AC, 77 IHOST_PROC_CLK_POLICY_CTL); 78 79 /* Poll CCU until operation complete */ 80 timeout_countdown = 0x100000; 81 while (readl(IHOST_PROC_CLK_POLICY_CTL) & 82 (1 << IHOST_PROC_CLK_POLICY_CTL__GO)) { 83 timeout_countdown--; 84 if (timeout_countdown == 0) { 85 printf("CCU polling timedout\n"); 86 status = 1; 87 goto armpll_config_done; 88 } 89 } 90 91 if (clkmhz == 25 || clkmhz == 100) { 92 status = 0; 93 goto armpll_config_done; 94 } 95 96 /* Now it is safe to program the PLL */ 97 pll = readl(IHOST_PROC_CLK_PLLARMB); 98 pll &= ~((1 << IHOST_PROC_CLK_PLLARMB__PLLARM_NDIV_FRAC_WIDTH) - 1); 99 ndiv_frac = 100 ((1 << IHOST_PROC_CLK_PLLARMB__PLLARM_NDIV_FRAC_WIDTH) - 1) & 101 (armpll_clk_tab[i].ndiv_frac << 102 IHOST_PROC_CLK_PLLARMB__PLLARM_NDIV_FRAC_R); 103 pll |= ndiv_frac; 104 writel(pll, IHOST_PROC_CLK_PLLARMB); 105 106 writel(1 << IHOST_PROC_CLK_PLLARMA__PLLARM_LOCK | 107 armpll_clk_tab[i].ndiv_int << 108 IHOST_PROC_CLK_PLLARMA__PLLARM_NDIV_INT_R | 109 armpll_clk_tab[i].pdiv << 110 IHOST_PROC_CLK_PLLARMA__PLLARM_PDIV_R | 111 1 << IHOST_PROC_CLK_PLLARMA__PLLARM_SOFT_RESETB, 112 IHOST_PROC_CLK_PLLARMA); 113 114 /* Poll ARM PLL Lock until operation complete */ 115 timeout_countdown = 0x100000; 116 while (readl(IHOST_PROC_CLK_PLLARMA) & 117 (1 << IHOST_PROC_CLK_PLLARMA__PLLARM_LOCK)) { 118 timeout_countdown--; 119 if (timeout_countdown == 0) { 120 printf("ARM PLL lock failed\n"); 121 status = 1; 122 goto armpll_config_done; 123 } 124 } 125 126 pll = readl(IHOST_PROC_CLK_PLLARMA); 127 pll |= (1 << IHOST_PROC_CLK_PLLARMA__PLLARM_SOFT_POST_RESETB); 128 writel(pll, IHOST_PROC_CLK_PLLARMA); 129 130 /* Set the policy */ 131 writel(1 << IHOST_PROC_CLK_POLICY_FREQ__PRIV_ACCESS_MODE | 132 armpll_clk_tab[i].freqid << 133 IHOST_PROC_CLK_POLICY_FREQ__POLICY3_FREQ_R | 134 armpll_clk_tab[i].freqid << 135 IHOST_PROC_CLK_POLICY_FREQ__POLICY2_FREQ_R | 136 armpll_clk_tab[i].freqid << 137 IHOST_PROC_CLK_POLICY_FREQ__POLICY1_FREQ_R | 138 armpll_clk_tab[i+4].freqid << 139 IHOST_PROC_CLK_POLICY_FREQ__POLICY0_FREQ_R, 140 IHOST_PROC_CLK_POLICY_FREQ); 141 142 writel(IPROC_CLKCT_HDELAY_SW_EN, IHOST_PROC_CLK_CORE0_CLKGATE); 143 writel(IPROC_CLKCT_HDELAY_SW_EN, IHOST_PROC_CLK_CORE1_CLKGATE); 144 writel(IPROC_CLKCT_HDELAY_SW_EN, IHOST_PROC_CLK_ARM_SWITCH_CLKGATE); 145 writel(IPROC_CLKCT_HDELAY_SW_EN, IHOST_PROC_CLK_ARM_PERIPH_CLKGATE); 146 writel(IPROC_CLKCT_HDELAY_SW_EN, IHOST_PROC_CLK_APB0_CLKGATE); 147 148 writel(1 << IHOST_PROC_CLK_POLICY_CTL__GO | 149 1 << IHOST_PROC_CLK_POLICY_CTL__GO_AC, 150 IHOST_PROC_CLK_POLICY_CTL); 151 152 /* Poll CCU until operation complete */ 153 timeout_countdown = 0x100000; 154 while (readl(IHOST_PROC_CLK_POLICY_CTL) & 155 (1 << IHOST_PROC_CLK_POLICY_CTL__GO)) { 156 timeout_countdown--; 157 if (timeout_countdown == 0) { 158 printf("CCU polling failed\n"); 159 status = 1; 160 goto armpll_config_done; 161 } 162 } 163 164 status = 0; 165 armpll_config_done: 166 /* Disable access to PLL registers */ 167 writel(0, IHOST_PROC_CLK_WR_ACCESS); 168 169 return status; 170 } 171