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