1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * sun4i, sun5i and sun7i specific clock code 4 * 5 * (C) Copyright 2007-2012 6 * Allwinner Technology Co., Ltd. <www.allwinnertech.com> 7 * Tom Cubie <tangliang@allwinnertech.com> 8 * 9 * (C) Copyright 2013 Luke Kenneth Casson Leighton <lkcl@lkcl.net> 10 */ 11 12 #include <common.h> 13 #include <asm/io.h> 14 #include <asm/arch/clock.h> 15 #include <asm/arch/gpio.h> 16 #include <asm/arch/sys_proto.h> 17 18 #ifdef CONFIG_SPL_BUILD 19 void clock_init_safe(void) 20 { 21 struct sunxi_ccm_reg * const ccm = 22 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE; 23 24 /* Set safe defaults until PMU is configured */ 25 writel(AXI_DIV_1 << AXI_DIV_SHIFT | 26 AHB_DIV_2 << AHB_DIV_SHIFT | 27 APB0_DIV_1 << APB0_DIV_SHIFT | 28 CPU_CLK_SRC_OSC24M << CPU_CLK_SRC_SHIFT, 29 &ccm->cpu_ahb_apb0_cfg); 30 writel(PLL1_CFG_DEFAULT, &ccm->pll1_cfg); 31 sdelay(200); 32 writel(AXI_DIV_1 << AXI_DIV_SHIFT | 33 AHB_DIV_2 << AHB_DIV_SHIFT | 34 APB0_DIV_1 << APB0_DIV_SHIFT | 35 CPU_CLK_SRC_PLL1 << CPU_CLK_SRC_SHIFT, 36 &ccm->cpu_ahb_apb0_cfg); 37 #ifdef CONFIG_MACH_SUN7I 38 setbits_le32(&ccm->ahb_gate0, 0x1 << AHB_GATE_OFFSET_DMA); 39 #endif 40 writel(PLL6_CFG_DEFAULT, &ccm->pll6_cfg); 41 #ifdef CONFIG_SUNXI_AHCI 42 setbits_le32(&ccm->ahb_gate0, 0x1 << AHB_GATE_OFFSET_SATA); 43 setbits_le32(&ccm->pll6_cfg, 0x1 << CCM_PLL6_CTRL_SATA_EN_SHIFT); 44 #endif 45 } 46 #endif 47 48 void clock_init_uart(void) 49 { 50 struct sunxi_ccm_reg *const ccm = 51 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE; 52 53 /* uart clock source is apb1 */ 54 writel(APB1_CLK_SRC_OSC24M| 55 APB1_CLK_RATE_N_1| 56 APB1_CLK_RATE_M(1), 57 &ccm->apb1_clk_div_cfg); 58 59 /* open the clock for uart */ 60 setbits_le32(&ccm->apb1_gate, 61 CLK_GATE_OPEN << (APB1_GATE_UART_SHIFT+CONFIG_CONS_INDEX - 1)); 62 } 63 64 int clock_twi_onoff(int port, int state) 65 { 66 struct sunxi_ccm_reg *const ccm = 67 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE; 68 69 /* set the apb clock gate for twi */ 70 if (state) 71 setbits_le32(&ccm->apb1_gate, 72 CLK_GATE_OPEN << (APB1_GATE_TWI_SHIFT + port)); 73 else 74 clrbits_le32(&ccm->apb1_gate, 75 CLK_GATE_OPEN << (APB1_GATE_TWI_SHIFT + port)); 76 77 return 0; 78 } 79 80 #ifdef CONFIG_SPL_BUILD 81 #define PLL1_CFG(N, K, M, P) ( 1 << CCM_PLL1_CFG_ENABLE_SHIFT | \ 82 0 << CCM_PLL1_CFG_VCO_RST_SHIFT | \ 83 8 << CCM_PLL1_CFG_VCO_BIAS_SHIFT | \ 84 0 << CCM_PLL1_CFG_PLL4_EXCH_SHIFT | \ 85 16 << CCM_PLL1_CFG_BIAS_CUR_SHIFT | \ 86 (P)<< CCM_PLL1_CFG_DIVP_SHIFT | \ 87 2 << CCM_PLL1_CFG_LCK_TMR_SHIFT | \ 88 (N)<< CCM_PLL1_CFG_FACTOR_N_SHIFT | \ 89 (K)<< CCM_PLL1_CFG_FACTOR_K_SHIFT | \ 90 0 << CCM_PLL1_CFG_SIG_DELT_PAT_IN_SHIFT | \ 91 0 << CCM_PLL1_CFG_SIG_DELT_PAT_EN_SHIFT | \ 92 (M)<< CCM_PLL1_CFG_FACTOR_M_SHIFT) 93 94 static struct { 95 u32 pll1_cfg; 96 unsigned int freq; 97 } pll1_para[] = { 98 /* This array must be ordered by frequency. */ 99 { PLL1_CFG(31, 1, 0, 0), 1488000000}, 100 { PLL1_CFG(30, 1, 0, 0), 1440000000}, 101 { PLL1_CFG(29, 1, 0, 0), 1392000000}, 102 { PLL1_CFG(28, 1, 0, 0), 1344000000}, 103 { PLL1_CFG(27, 1, 0, 0), 1296000000}, 104 { PLL1_CFG(26, 1, 0, 0), 1248000000}, 105 { PLL1_CFG(25, 1, 0, 0), 1200000000}, 106 { PLL1_CFG(24, 1, 0, 0), 1152000000}, 107 { PLL1_CFG(23, 1, 0, 0), 1104000000}, 108 { PLL1_CFG(22, 1, 0, 0), 1056000000}, 109 { PLL1_CFG(21, 1, 0, 0), 1008000000}, 110 { PLL1_CFG(20, 1, 0, 0), 960000000 }, 111 { PLL1_CFG(19, 1, 0, 0), 912000000 }, 112 { PLL1_CFG(16, 1, 0, 0), 768000000 }, 113 /* Final catchall entry 384MHz*/ 114 { PLL1_CFG(16, 0, 0, 0), 0 }, 115 116 }; 117 118 void clock_set_pll1(unsigned int hz) 119 { 120 int i = 0; 121 int axi, ahb, apb0; 122 struct sunxi_ccm_reg * const ccm = 123 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE; 124 125 /* Find target frequency */ 126 while (pll1_para[i].freq > hz) 127 i++; 128 129 hz = pll1_para[i].freq; 130 if (! hz) 131 hz = 384000000; 132 133 /* Calculate system clock divisors */ 134 axi = DIV_ROUND_UP(hz, 432000000); /* Max 450MHz */ 135 ahb = DIV_ROUND_UP(hz/axi, 204000000); /* Max 250MHz */ 136 apb0 = 2; /* Max 150MHz */ 137 138 printf("CPU: %uHz, AXI/AHB/APB: %d/%d/%d\n", hz, axi, ahb, apb0); 139 140 /* Map divisors to register values */ 141 axi = axi - 1; 142 if (ahb > 4) 143 ahb = 3; 144 else if (ahb > 2) 145 ahb = 2; 146 else if (ahb > 1) 147 ahb = 1; 148 else 149 ahb = 0; 150 151 apb0 = apb0 - 1; 152 153 /* Switch to 24MHz clock while changing PLL1 */ 154 writel(AXI_DIV_1 << AXI_DIV_SHIFT | 155 AHB_DIV_2 << AHB_DIV_SHIFT | 156 APB0_DIV_1 << APB0_DIV_SHIFT | 157 CPU_CLK_SRC_OSC24M << CPU_CLK_SRC_SHIFT, 158 &ccm->cpu_ahb_apb0_cfg); 159 sdelay(20); 160 161 /* Configure sys clock divisors */ 162 writel(axi << AXI_DIV_SHIFT | 163 ahb << AHB_DIV_SHIFT | 164 apb0 << APB0_DIV_SHIFT | 165 CPU_CLK_SRC_OSC24M << CPU_CLK_SRC_SHIFT, 166 &ccm->cpu_ahb_apb0_cfg); 167 168 /* Configure PLL1 at the desired frequency */ 169 writel(pll1_para[i].pll1_cfg, &ccm->pll1_cfg); 170 sdelay(200); 171 172 /* Switch CPU to PLL1 */ 173 writel(axi << AXI_DIV_SHIFT | 174 ahb << AHB_DIV_SHIFT | 175 apb0 << APB0_DIV_SHIFT | 176 CPU_CLK_SRC_PLL1 << CPU_CLK_SRC_SHIFT, 177 &ccm->cpu_ahb_apb0_cfg); 178 sdelay(20); 179 } 180 #endif 181 182 void clock_set_pll3(unsigned int clk) 183 { 184 struct sunxi_ccm_reg * const ccm = 185 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE; 186 187 if (clk == 0) { 188 clrbits_le32(&ccm->pll3_cfg, CCM_PLL3_CTRL_EN); 189 return; 190 } 191 192 /* PLL3 rate = 3000000 * m */ 193 writel(CCM_PLL3_CTRL_EN | CCM_PLL3_CTRL_INTEGER_MODE | 194 CCM_PLL3_CTRL_M(clk / 3000000), &ccm->pll3_cfg); 195 } 196 197 unsigned int clock_get_pll3(void) 198 { 199 struct sunxi_ccm_reg *const ccm = 200 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE; 201 uint32_t rval = readl(&ccm->pll3_cfg); 202 int m = ((rval & CCM_PLL3_CTRL_M_MASK) >> CCM_PLL3_CTRL_M_SHIFT); 203 return 3000000 * m; 204 } 205 206 unsigned int clock_get_pll5p(void) 207 { 208 struct sunxi_ccm_reg *const ccm = 209 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE; 210 uint32_t rval = readl(&ccm->pll5_cfg); 211 int n = ((rval & CCM_PLL5_CTRL_N_MASK) >> CCM_PLL5_CTRL_N_SHIFT); 212 int k = ((rval & CCM_PLL5_CTRL_K_MASK) >> CCM_PLL5_CTRL_K_SHIFT) + 1; 213 int p = ((rval & CCM_PLL5_CTRL_P_MASK) >> CCM_PLL5_CTRL_P_SHIFT); 214 return (24000000 * n * k) >> p; 215 } 216 217 unsigned int clock_get_pll6(void) 218 { 219 struct sunxi_ccm_reg *const ccm = 220 (struct sunxi_ccm_reg *)SUNXI_CCM_BASE; 221 uint32_t rval = readl(&ccm->pll6_cfg); 222 int n = ((rval & CCM_PLL6_CTRL_N_MASK) >> CCM_PLL6_CTRL_N_SHIFT); 223 int k = ((rval & CCM_PLL6_CTRL_K_MASK) >> CCM_PLL6_CTRL_K_SHIFT) + 1; 224 return 24000000 * n * k / 2; 225 } 226 227 void clock_set_de_mod_clock(u32 *clk_cfg, unsigned int hz) 228 { 229 int pll = clock_get_pll5p(); 230 int div = 1; 231 232 while ((pll / div) > hz) 233 div++; 234 235 writel(CCM_DE_CTRL_GATE | CCM_DE_CTRL_RST | CCM_DE_CTRL_PLL5P | 236 CCM_DE_CTRL_M(div), clk_cfg); 237 } 238