diff options
author | 2023-10-10 14:33:42 +0000 | |
---|---|---|
committer | 2023-10-10 14:33:42 +0000 | |
commit | af1a266670d040d2f4083ff309d732d648afba2a (patch) | |
tree | 2fc46203448ddcc6f81546d379abfaeb323575e9 /roms/u-boot/arch/arm/cpu/armv7/iproc-common/armpll.c | |
parent | e02cda008591317b1625707ff8e115a4841aa889 (diff) |
Change-Id: Iaf8d18082d3991dec7c0ebbea540f092188eb4ec
Diffstat (limited to 'roms/u-boot/arch/arm/cpu/armv7/iproc-common/armpll.c')
-rw-r--r-- | roms/u-boot/arch/arm/cpu/armv7/iproc-common/armpll.c | 169 |
1 files changed, 169 insertions, 0 deletions
diff --git a/roms/u-boot/arch/arm/cpu/armv7/iproc-common/armpll.c b/roms/u-boot/arch/arm/cpu/armv7/iproc-common/armpll.c new file mode 100644 index 000000000..efa3d9e5a --- /dev/null +++ b/roms/u-boot/arch/arm/cpu/armv7/iproc-common/armpll.c @@ -0,0 +1,169 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2014 Broadcom Corporation. + */ + +#include <common.h> +#include <asm/io.h> +#include <asm/iproc-common/armpll.h> +#include <asm/iproc-common/sysmap.h> + +#define NELEMS(x) (sizeof(x) / sizeof(x[0])) + +struct armpll_parameters { + unsigned int mode; + unsigned int ndiv_int; + unsigned int ndiv_frac; + unsigned int pdiv; + unsigned int freqid; +}; + +struct armpll_parameters armpll_clk_tab[] = { + { 25, 64, 1, 1, 0}, + { 100, 64, 1, 1, 2}, + { 400, 64, 1, 1, 6}, + { 448, 71, 713050, 1, 6}, + { 500, 80, 1, 1, 6}, + { 560, 89, 629145, 1, 6}, + { 600, 96, 1, 1, 6}, + { 800, 64, 1, 1, 7}, + { 896, 71, 713050, 1, 7}, + { 1000, 80, 1, 1, 7}, + { 1100, 88, 1, 1, 7}, + { 1120, 89, 629145, 1, 7}, + { 1200, 96, 1, 1, 7}, +}; + +uint32_t armpll_config(uint32_t clkmhz) +{ + uint32_t freqid; + uint32_t ndiv_frac; + uint32_t pll; + uint32_t status = 1; + uint32_t timeout_countdown; + int i; + + for (i = 0; i < NELEMS(armpll_clk_tab); i++) { + if (armpll_clk_tab[i].mode == clkmhz) { + status = 0; + break; + } + } + + if (status) { + printf("Error: Clock configuration not supported\n"); + goto armpll_config_done; + } + + /* Enable write access */ + writel(IPROC_REG_WRITE_ACCESS, IHOST_PROC_CLK_WR_ACCESS); + + if (clkmhz == 25) + freqid = 0; + else + freqid = 2; + + /* Bypass ARM clock and run on sysclk */ + writel(1 << IHOST_PROC_CLK_POLICY_FREQ__PRIV_ACCESS_MODE | + freqid << IHOST_PROC_CLK_POLICY_FREQ__POLICY3_FREQ_R | + freqid << IHOST_PROC_CLK_POLICY_FREQ__POLICY2_FREQ_R | + freqid << IHOST_PROC_CLK_POLICY_FREQ__POLICY1_FREQ_R | + freqid << IHOST_PROC_CLK_POLICY_FREQ__POLICY0_FREQ_R, + IHOST_PROC_CLK_POLICY_FREQ); + + writel(1 << IHOST_PROC_CLK_POLICY_CTL__GO | + 1 << IHOST_PROC_CLK_POLICY_CTL__GO_AC, + IHOST_PROC_CLK_POLICY_CTL); + + /* Poll CCU until operation complete */ + timeout_countdown = 0x100000; + while (readl(IHOST_PROC_CLK_POLICY_CTL) & + (1 << IHOST_PROC_CLK_POLICY_CTL__GO)) { + timeout_countdown--; + if (timeout_countdown == 0) { + printf("CCU polling timedout\n"); + status = 1; + goto armpll_config_done; + } + } + + if (clkmhz == 25 || clkmhz == 100) { + status = 0; + goto armpll_config_done; + } + + /* Now it is safe to program the PLL */ + pll = readl(IHOST_PROC_CLK_PLLARMB); + pll &= ~((1 << IHOST_PROC_CLK_PLLARMB__PLLARM_NDIV_FRAC_WIDTH) - 1); + ndiv_frac = + ((1 << IHOST_PROC_CLK_PLLARMB__PLLARM_NDIV_FRAC_WIDTH) - 1) & + (armpll_clk_tab[i].ndiv_frac << + IHOST_PROC_CLK_PLLARMB__PLLARM_NDIV_FRAC_R); + pll |= ndiv_frac; + writel(pll, IHOST_PROC_CLK_PLLARMB); + + writel(1 << IHOST_PROC_CLK_PLLARMA__PLLARM_LOCK | + armpll_clk_tab[i].ndiv_int << + IHOST_PROC_CLK_PLLARMA__PLLARM_NDIV_INT_R | + armpll_clk_tab[i].pdiv << + IHOST_PROC_CLK_PLLARMA__PLLARM_PDIV_R | + 1 << IHOST_PROC_CLK_PLLARMA__PLLARM_SOFT_RESETB, + IHOST_PROC_CLK_PLLARMA); + + /* Poll ARM PLL Lock until operation complete */ + timeout_countdown = 0x100000; + while (readl(IHOST_PROC_CLK_PLLARMA) & + (1 << IHOST_PROC_CLK_PLLARMA__PLLARM_LOCK)) { + timeout_countdown--; + if (timeout_countdown == 0) { + printf("ARM PLL lock failed\n"); + status = 1; + goto armpll_config_done; + } + } + + pll = readl(IHOST_PROC_CLK_PLLARMA); + pll |= (1 << IHOST_PROC_CLK_PLLARMA__PLLARM_SOFT_POST_RESETB); + writel(pll, IHOST_PROC_CLK_PLLARMA); + + /* Set the policy */ + writel(1 << IHOST_PROC_CLK_POLICY_FREQ__PRIV_ACCESS_MODE | + armpll_clk_tab[i].freqid << + IHOST_PROC_CLK_POLICY_FREQ__POLICY3_FREQ_R | + armpll_clk_tab[i].freqid << + IHOST_PROC_CLK_POLICY_FREQ__POLICY2_FREQ_R | + armpll_clk_tab[i].freqid << + IHOST_PROC_CLK_POLICY_FREQ__POLICY1_FREQ_R | + armpll_clk_tab[i+4].freqid << + IHOST_PROC_CLK_POLICY_FREQ__POLICY0_FREQ_R, + IHOST_PROC_CLK_POLICY_FREQ); + + writel(IPROC_CLKCT_HDELAY_SW_EN, IHOST_PROC_CLK_CORE0_CLKGATE); + writel(IPROC_CLKCT_HDELAY_SW_EN, IHOST_PROC_CLK_CORE1_CLKGATE); + writel(IPROC_CLKCT_HDELAY_SW_EN, IHOST_PROC_CLK_ARM_SWITCH_CLKGATE); + writel(IPROC_CLKCT_HDELAY_SW_EN, IHOST_PROC_CLK_ARM_PERIPH_CLKGATE); + writel(IPROC_CLKCT_HDELAY_SW_EN, IHOST_PROC_CLK_APB0_CLKGATE); + + writel(1 << IHOST_PROC_CLK_POLICY_CTL__GO | + 1 << IHOST_PROC_CLK_POLICY_CTL__GO_AC, + IHOST_PROC_CLK_POLICY_CTL); + + /* Poll CCU until operation complete */ + timeout_countdown = 0x100000; + while (readl(IHOST_PROC_CLK_POLICY_CTL) & + (1 << IHOST_PROC_CLK_POLICY_CTL__GO)) { + timeout_countdown--; + if (timeout_countdown == 0) { + printf("CCU polling failed\n"); + status = 1; + goto armpll_config_done; + } + } + + status = 0; +armpll_config_done: + /* Disable access to PLL registers */ + writel(0, IHOST_PROC_CLK_WR_ACCESS); + + return status; +} |