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 13struct 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 21struct 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 { 1300, 104, 1, 1, 7}, 36 { 1350, 108, 1, 1, 7}, 37 { 1400, 112, 1, 1, 7}, 38}; 39 40uint32_t armpll_config(uint32_t clkmhz) 41{ 42 uint32_t freqid; 43 uint32_t ndiv_frac; 44 uint32_t pll; 45 uint32_t status = 1; 46 uint32_t timeout_countdown; 47 int i; 48 49 for (i = 0; i < NELEMS(armpll_clk_tab); i++) { 50 if (armpll_clk_tab[i].mode == clkmhz) { 51 status = 0; 52 break; 53 } 54 } 55 56 if (status) { 57 printf("Error: Clock configuration not supported\n"); 58 goto armpll_config_done; 59 } 60 61 /* Enable write access */ 62 writel(IPROC_REG_WRITE_ACCESS, IHOST_PROC_CLK_WR_ACCESS); 63 64 if (clkmhz == 25) 65 freqid = 0; 66 else 67 freqid = 2; 68 69 /* Bypass ARM clock and run on sysclk */ 70 writel(1 << IHOST_PROC_CLK_POLICY_FREQ__PRIV_ACCESS_MODE | 71 freqid << IHOST_PROC_CLK_POLICY_FREQ__POLICY3_FREQ_R | 72 freqid << IHOST_PROC_CLK_POLICY_FREQ__POLICY2_FREQ_R | 73 freqid << IHOST_PROC_CLK_POLICY_FREQ__POLICY1_FREQ_R | 74 freqid << IHOST_PROC_CLK_POLICY_FREQ__POLICY0_FREQ_R, 75 IHOST_PROC_CLK_POLICY_FREQ); 76 77 writel(1 << IHOST_PROC_CLK_POLICY_CTL__GO | 78 1 << IHOST_PROC_CLK_POLICY_CTL__GO_AC, 79 IHOST_PROC_CLK_POLICY_CTL); 80 81 /* Poll CCU until operation complete */ 82 timeout_countdown = 0x100000; 83 while (readl(IHOST_PROC_CLK_POLICY_CTL) & 84 (1 << IHOST_PROC_CLK_POLICY_CTL__GO)) { 85 timeout_countdown--; 86 if (timeout_countdown == 0) { 87 printf("CCU polling timedout\n"); 88 status = 1; 89 goto armpll_config_done; 90 } 91 } 92 93 if (clkmhz == 25 || clkmhz == 100) { 94 status = 0; 95 goto armpll_config_done; 96 } 97 98 /* Now it is safe to program the PLL */ 99 pll = readl(IHOST_PROC_CLK_PLLARMB); 100 pll &= ~((1 << IHOST_PROC_CLK_PLLARMB__PLLARM_NDIV_FRAC_WIDTH) - 1); 101 ndiv_frac = 102 ((1 << IHOST_PROC_CLK_PLLARMB__PLLARM_NDIV_FRAC_WIDTH) - 1) & 103 (armpll_clk_tab[i].ndiv_frac << 104 IHOST_PROC_CLK_PLLARMB__PLLARM_NDIV_FRAC_R); 105 pll |= ndiv_frac; 106 writel(pll, IHOST_PROC_CLK_PLLARMB); 107 108 writel(1 << IHOST_PROC_CLK_PLLARMA__PLLARM_LOCK | 109 armpll_clk_tab[i].ndiv_int << 110 IHOST_PROC_CLK_PLLARMA__PLLARM_NDIV_INT_R | 111 armpll_clk_tab[i].pdiv << 112 IHOST_PROC_CLK_PLLARMA__PLLARM_PDIV_R | 113 1 << IHOST_PROC_CLK_PLLARMA__PLLARM_SOFT_RESETB, 114 IHOST_PROC_CLK_PLLARMA); 115 116 /* Poll ARM PLL Lock until operation complete */ 117 timeout_countdown = 0x100000; 118 while (readl(IHOST_PROC_CLK_PLLARMA) & 119 (1 << IHOST_PROC_CLK_PLLARMA__PLLARM_LOCK)) { 120 timeout_countdown--; 121 if (timeout_countdown == 0) { 122 printf("ARM PLL lock failed\n"); 123 status = 1; 124 goto armpll_config_done; 125 } 126 } 127 128 pll = readl(IHOST_PROC_CLK_PLLARMA); 129 pll |= (1 << IHOST_PROC_CLK_PLLARMA__PLLARM_SOFT_POST_RESETB); 130 writel(pll, IHOST_PROC_CLK_PLLARMA); 131 132 /* Set the policy */ 133 writel(1 << IHOST_PROC_CLK_POLICY_FREQ__PRIV_ACCESS_MODE | 134 armpll_clk_tab[i].freqid << 135 IHOST_PROC_CLK_POLICY_FREQ__POLICY3_FREQ_R | 136 armpll_clk_tab[i].freqid << 137 IHOST_PROC_CLK_POLICY_FREQ__POLICY2_FREQ_R | 138 armpll_clk_tab[i].freqid << 139 IHOST_PROC_CLK_POLICY_FREQ__POLICY1_FREQ_R | 140 armpll_clk_tab[i+4].freqid << 141 IHOST_PROC_CLK_POLICY_FREQ__POLICY0_FREQ_R, 142 IHOST_PROC_CLK_POLICY_FREQ); 143 144 writel(IPROC_CLKCT_HDELAY_SW_EN, IHOST_PROC_CLK_CORE0_CLKGATE); 145 writel(IPROC_CLKCT_HDELAY_SW_EN, IHOST_PROC_CLK_CORE1_CLKGATE); 146 writel(IPROC_CLKCT_HDELAY_SW_EN, IHOST_PROC_CLK_ARM_SWITCH_CLKGATE); 147 writel(IPROC_CLKCT_HDELAY_SW_EN, IHOST_PROC_CLK_ARM_PERIPH_CLKGATE); 148 writel(IPROC_CLKCT_HDELAY_SW_EN, IHOST_PROC_CLK_APB0_CLKGATE); 149 150 writel(1 << IHOST_PROC_CLK_POLICY_CTL__GO | 151 1 << IHOST_PROC_CLK_POLICY_CTL__GO_AC, 152 IHOST_PROC_CLK_POLICY_CTL); 153 154 /* Poll CCU until operation complete */ 155 timeout_countdown = 0x100000; 156 while (readl(IHOST_PROC_CLK_POLICY_CTL) & 157 (1 << IHOST_PROC_CLK_POLICY_CTL__GO)) { 158 timeout_countdown--; 159 if (timeout_countdown == 0) { 160 printf("CCU polling failed\n"); 161 status = 1; 162 goto armpll_config_done; 163 } 164 } 165 166 status = 0; 167armpll_config_done: 168 /* Disable access to PLL registers */ 169 writel(0, IHOST_PROC_CLK_WR_ACCESS); 170 171 return status; 172} 173