1 /* 2 * Copyright 2013 Freescale Semiconductor, Inc. 3 * 4 * SPDX-License-Identifier: GPL-2.0+ 5 */ 6 7 #include <common.h> 8 #include <asm/io.h> 9 #include <asm/arch/imx-regs.h> 10 #include <asm/arch/clock.h> 11 #include <asm/arch/crm_regs.h> 12 #include <netdev.h> 13 #ifdef CONFIG_FSL_ESDHC 14 #include <fsl_esdhc.h> 15 #endif 16 17 #ifdef CONFIG_FSL_ESDHC 18 DECLARE_GLOBAL_DATA_PTR; 19 #endif 20 21 #ifdef CONFIG_MXC_OCOTP 22 void enable_ocotp_clk(unsigned char enable) 23 { 24 struct ccm_reg *ccm = (struct ccm_reg *)CCM_BASE_ADDR; 25 u32 reg; 26 27 reg = readl(&ccm->ccgr6); 28 if (enable) 29 reg |= CCM_CCGR6_OCOTP_CTRL_MASK; 30 else 31 reg &= ~CCM_CCGR6_OCOTP_CTRL_MASK; 32 writel(reg, &ccm->ccgr6); 33 } 34 #endif 35 36 static u32 get_mcu_main_clk(void) 37 { 38 struct ccm_reg *ccm = (struct ccm_reg *)CCM_BASE_ADDR; 39 u32 ccm_ccsr, ccm_cacrr, armclk_div; 40 u32 sysclk_sel, pll_pfd_sel = 0; 41 u32 freq = 0; 42 43 ccm_ccsr = readl(&ccm->ccsr); 44 sysclk_sel = ccm_ccsr & CCM_CCSR_SYS_CLK_SEL_MASK; 45 sysclk_sel >>= CCM_CCSR_SYS_CLK_SEL_OFFSET; 46 47 ccm_cacrr = readl(&ccm->cacrr); 48 armclk_div = ccm_cacrr & CCM_CACRR_ARM_CLK_DIV_MASK; 49 armclk_div >>= CCM_CACRR_ARM_CLK_DIV_OFFSET; 50 armclk_div += 1; 51 52 switch (sysclk_sel) { 53 case 0: 54 freq = FASE_CLK_FREQ; 55 break; 56 case 1: 57 freq = SLOW_CLK_FREQ; 58 break; 59 case 2: 60 pll_pfd_sel = ccm_ccsr & CCM_CCSR_PLL2_PFD_CLK_SEL_MASK; 61 pll_pfd_sel >>= CCM_CCSR_PLL2_PFD_CLK_SEL_OFFSET; 62 if (pll_pfd_sel == 0) 63 freq = PLL2_MAIN_FREQ; 64 else if (pll_pfd_sel == 1) 65 freq = PLL2_PFD1_FREQ; 66 else if (pll_pfd_sel == 2) 67 freq = PLL2_PFD2_FREQ; 68 else if (pll_pfd_sel == 3) 69 freq = PLL2_PFD3_FREQ; 70 else if (pll_pfd_sel == 4) 71 freq = PLL2_PFD4_FREQ; 72 break; 73 case 3: 74 freq = PLL2_MAIN_FREQ; 75 break; 76 case 4: 77 pll_pfd_sel = ccm_ccsr & CCM_CCSR_PLL1_PFD_CLK_SEL_MASK; 78 pll_pfd_sel >>= CCM_CCSR_PLL1_PFD_CLK_SEL_OFFSET; 79 if (pll_pfd_sel == 0) 80 freq = PLL1_MAIN_FREQ; 81 else if (pll_pfd_sel == 1) 82 freq = PLL1_PFD1_FREQ; 83 else if (pll_pfd_sel == 2) 84 freq = PLL1_PFD2_FREQ; 85 else if (pll_pfd_sel == 3) 86 freq = PLL1_PFD3_FREQ; 87 else if (pll_pfd_sel == 4) 88 freq = PLL1_PFD4_FREQ; 89 break; 90 case 5: 91 freq = PLL3_MAIN_FREQ; 92 break; 93 default: 94 printf("unsupported system clock select\n"); 95 } 96 97 return freq / armclk_div; 98 } 99 100 static u32 get_bus_clk(void) 101 { 102 struct ccm_reg *ccm = (struct ccm_reg *)CCM_BASE_ADDR; 103 u32 ccm_cacrr, busclk_div; 104 105 ccm_cacrr = readl(&ccm->cacrr); 106 107 busclk_div = ccm_cacrr & CCM_CACRR_BUS_CLK_DIV_MASK; 108 busclk_div >>= CCM_CACRR_BUS_CLK_DIV_OFFSET; 109 busclk_div += 1; 110 111 return get_mcu_main_clk() / busclk_div; 112 } 113 114 static u32 get_ipg_clk(void) 115 { 116 struct ccm_reg *ccm = (struct ccm_reg *)CCM_BASE_ADDR; 117 u32 ccm_cacrr, ipgclk_div; 118 119 ccm_cacrr = readl(&ccm->cacrr); 120 121 ipgclk_div = ccm_cacrr & CCM_CACRR_IPG_CLK_DIV_MASK; 122 ipgclk_div >>= CCM_CACRR_IPG_CLK_DIV_OFFSET; 123 ipgclk_div += 1; 124 125 return get_bus_clk() / ipgclk_div; 126 } 127 128 static u32 get_uart_clk(void) 129 { 130 return get_ipg_clk(); 131 } 132 133 static u32 get_sdhc_clk(void) 134 { 135 struct ccm_reg *ccm = (struct ccm_reg *)CCM_BASE_ADDR; 136 u32 ccm_cscmr1, ccm_cscdr2, sdhc_clk_sel, sdhc_clk_div; 137 u32 freq = 0; 138 139 ccm_cscmr1 = readl(&ccm->cscmr1); 140 sdhc_clk_sel = ccm_cscmr1 & CCM_CSCMR1_ESDHC1_CLK_SEL_MASK; 141 sdhc_clk_sel >>= CCM_CSCMR1_ESDHC1_CLK_SEL_OFFSET; 142 143 ccm_cscdr2 = readl(&ccm->cscdr2); 144 sdhc_clk_div = ccm_cscdr2 & CCM_CSCDR2_ESDHC1_CLK_DIV_MASK; 145 sdhc_clk_div >>= CCM_CSCDR2_ESDHC1_CLK_DIV_OFFSET; 146 sdhc_clk_div += 1; 147 148 switch (sdhc_clk_sel) { 149 case 0: 150 freq = PLL3_MAIN_FREQ; 151 break; 152 case 1: 153 freq = PLL3_PFD3_FREQ; 154 break; 155 case 2: 156 freq = PLL1_PFD3_FREQ; 157 break; 158 case 3: 159 freq = get_bus_clk(); 160 break; 161 } 162 163 return freq / sdhc_clk_div; 164 } 165 166 u32 get_fec_clk(void) 167 { 168 struct ccm_reg *ccm = (struct ccm_reg *)CCM_BASE_ADDR; 169 u32 ccm_cscmr2, rmii_clk_sel; 170 u32 freq = 0; 171 172 ccm_cscmr2 = readl(&ccm->cscmr2); 173 rmii_clk_sel = ccm_cscmr2 & CCM_CSCMR2_RMII_CLK_SEL_MASK; 174 rmii_clk_sel >>= CCM_CSCMR2_RMII_CLK_SEL_OFFSET; 175 176 switch (rmii_clk_sel) { 177 case 0: 178 freq = ENET_EXTERNAL_CLK; 179 break; 180 case 1: 181 freq = AUDIO_EXTERNAL_CLK; 182 break; 183 case 2: 184 freq = PLL5_MAIN_FREQ; 185 break; 186 case 3: 187 freq = PLL5_MAIN_FREQ / 2; 188 break; 189 } 190 191 return freq; 192 } 193 194 static u32 get_i2c_clk(void) 195 { 196 return get_ipg_clk(); 197 } 198 199 unsigned int mxc_get_clock(enum mxc_clock clk) 200 { 201 switch (clk) { 202 case MXC_ARM_CLK: 203 return get_mcu_main_clk(); 204 case MXC_BUS_CLK: 205 return get_bus_clk(); 206 case MXC_IPG_CLK: 207 return get_ipg_clk(); 208 case MXC_UART_CLK: 209 return get_uart_clk(); 210 case MXC_ESDHC_CLK: 211 return get_sdhc_clk(); 212 case MXC_FEC_CLK: 213 return get_fec_clk(); 214 case MXC_I2C_CLK: 215 return get_i2c_clk(); 216 default: 217 break; 218 } 219 return -1; 220 } 221 222 /* Dump some core clocks */ 223 int do_vf610_showclocks(cmd_tbl_t *cmdtp, int flag, int argc, 224 char * const argv[]) 225 { 226 printf("\n"); 227 printf("cpu clock : %8d MHz\n", mxc_get_clock(MXC_ARM_CLK) / 1000000); 228 printf("bus clock : %8d MHz\n", mxc_get_clock(MXC_BUS_CLK) / 1000000); 229 printf("ipg clock : %8d MHz\n", mxc_get_clock(MXC_IPG_CLK) / 1000000); 230 231 return 0; 232 } 233 234 U_BOOT_CMD( 235 clocks, CONFIG_SYS_MAXARGS, 1, do_vf610_showclocks, 236 "display clocks", 237 "" 238 ); 239 240 #ifdef CONFIG_FEC_MXC 241 void imx_get_mac_from_fuse(int dev_id, unsigned char *mac) 242 { 243 struct ocotp_regs *ocotp = (struct ocotp_regs *)OCOTP_BASE_ADDR; 244 struct fuse_bank *bank = &ocotp->bank[4]; 245 struct fuse_bank4_regs *fuse = 246 (struct fuse_bank4_regs *)bank->fuse_regs; 247 248 u32 value = readl(&fuse->mac_addr0); 249 mac[0] = (value >> 8); 250 mac[1] = value; 251 252 value = readl(&fuse->mac_addr1); 253 mac[2] = value >> 24; 254 mac[3] = value >> 16; 255 mac[4] = value >> 8; 256 mac[5] = value; 257 } 258 #endif 259 260 #if defined(CONFIG_DISPLAY_CPUINFO) 261 static char *get_reset_cause(void) 262 { 263 u32 cause; 264 struct src *src_regs = (struct src *)SRC_BASE_ADDR; 265 266 cause = readl(&src_regs->srsr); 267 writel(cause, &src_regs->srsr); 268 cause &= 0xff; 269 270 switch (cause) { 271 case 0x08: 272 return "WDOG"; 273 case 0x20: 274 return "JTAG HIGH-Z"; 275 case 0x80: 276 return "EXTERNAL RESET"; 277 case 0xfd: 278 return "POR"; 279 default: 280 return "unknown reset"; 281 } 282 } 283 284 int print_cpuinfo(void) 285 { 286 printf("CPU: Freescale Vybrid VF610 at %d MHz\n", 287 mxc_get_clock(MXC_ARM_CLK) / 1000000); 288 printf("Reset cause: %s\n", get_reset_cause()); 289 290 return 0; 291 } 292 #endif 293 294 int cpu_eth_init(bd_t *bis) 295 { 296 int rc = -ENODEV; 297 298 #if defined(CONFIG_FEC_MXC) 299 rc = fecmxc_initialize(bis); 300 #endif 301 302 return rc; 303 } 304 305 #ifdef CONFIG_FSL_ESDHC 306 int cpu_mmc_init(bd_t *bis) 307 { 308 return fsl_esdhc_mmc_init(bis); 309 } 310 #endif 311 312 int get_clocks(void) 313 { 314 #ifdef CONFIG_FSL_ESDHC 315 gd->arch.sdhc_clk = mxc_get_clock(MXC_ESDHC_CLK); 316 #endif 317 return 0; 318 } 319