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