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