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 <asm/mach-imx/sys_proto.h> 13 #include <netdev.h> 14 #ifdef CONFIG_FSL_ESDHC 15 #include <fsl_esdhc.h> 16 #endif 17 18 #ifdef CONFIG_FSL_ESDHC 19 DECLARE_GLOBAL_DATA_PTR; 20 #endif 21 22 static char soc_type[] = "xx0"; 23 24 #ifdef CONFIG_MXC_OCOTP 25 void enable_ocotp_clk(unsigned char enable) 26 { 27 struct ccm_reg *ccm = (struct ccm_reg *)CCM_BASE_ADDR; 28 u32 reg; 29 30 reg = readl(&ccm->ccgr6); 31 if (enable) 32 reg |= CCM_CCGR6_OCOTP_CTRL_MASK; 33 else 34 reg &= ~CCM_CCGR6_OCOTP_CTRL_MASK; 35 writel(reg, &ccm->ccgr6); 36 } 37 #endif 38 39 static u32 get_mcu_main_clk(void) 40 { 41 struct ccm_reg *ccm = (struct ccm_reg *)CCM_BASE_ADDR; 42 u32 ccm_ccsr, ccm_cacrr, armclk_div; 43 u32 sysclk_sel, pll_pfd_sel = 0; 44 u32 freq = 0; 45 46 ccm_ccsr = readl(&ccm->ccsr); 47 sysclk_sel = ccm_ccsr & CCM_CCSR_SYS_CLK_SEL_MASK; 48 sysclk_sel >>= CCM_CCSR_SYS_CLK_SEL_OFFSET; 49 50 ccm_cacrr = readl(&ccm->cacrr); 51 armclk_div = ccm_cacrr & CCM_CACRR_ARM_CLK_DIV_MASK; 52 armclk_div >>= CCM_CACRR_ARM_CLK_DIV_OFFSET; 53 armclk_div += 1; 54 55 switch (sysclk_sel) { 56 case 0: 57 freq = FASE_CLK_FREQ; 58 break; 59 case 1: 60 freq = SLOW_CLK_FREQ; 61 break; 62 case 2: 63 pll_pfd_sel = ccm_ccsr & CCM_CCSR_PLL2_PFD_CLK_SEL_MASK; 64 pll_pfd_sel >>= CCM_CCSR_PLL2_PFD_CLK_SEL_OFFSET; 65 if (pll_pfd_sel == 0) 66 freq = PLL2_MAIN_FREQ; 67 else if (pll_pfd_sel == 1) 68 freq = PLL2_PFD1_FREQ; 69 else if (pll_pfd_sel == 2) 70 freq = PLL2_PFD2_FREQ; 71 else if (pll_pfd_sel == 3) 72 freq = PLL2_PFD3_FREQ; 73 else if (pll_pfd_sel == 4) 74 freq = PLL2_PFD4_FREQ; 75 break; 76 case 3: 77 freq = PLL2_MAIN_FREQ; 78 break; 79 case 4: 80 pll_pfd_sel = ccm_ccsr & CCM_CCSR_PLL1_PFD_CLK_SEL_MASK; 81 pll_pfd_sel >>= CCM_CCSR_PLL1_PFD_CLK_SEL_OFFSET; 82 if (pll_pfd_sel == 0) 83 freq = PLL1_MAIN_FREQ; 84 else if (pll_pfd_sel == 1) 85 freq = PLL1_PFD1_FREQ; 86 else if (pll_pfd_sel == 2) 87 freq = PLL1_PFD2_FREQ; 88 else if (pll_pfd_sel == 3) 89 freq = PLL1_PFD3_FREQ; 90 else if (pll_pfd_sel == 4) 91 freq = PLL1_PFD4_FREQ; 92 break; 93 case 5: 94 freq = PLL3_MAIN_FREQ; 95 break; 96 default: 97 printf("unsupported system clock select\n"); 98 } 99 100 return freq / armclk_div; 101 } 102 103 static u32 get_bus_clk(void) 104 { 105 struct ccm_reg *ccm = (struct ccm_reg *)CCM_BASE_ADDR; 106 u32 ccm_cacrr, busclk_div; 107 108 ccm_cacrr = readl(&ccm->cacrr); 109 110 busclk_div = ccm_cacrr & CCM_CACRR_BUS_CLK_DIV_MASK; 111 busclk_div >>= CCM_CACRR_BUS_CLK_DIV_OFFSET; 112 busclk_div += 1; 113 114 return get_mcu_main_clk() / busclk_div; 115 } 116 117 static u32 get_ipg_clk(void) 118 { 119 struct ccm_reg *ccm = (struct ccm_reg *)CCM_BASE_ADDR; 120 u32 ccm_cacrr, ipgclk_div; 121 122 ccm_cacrr = readl(&ccm->cacrr); 123 124 ipgclk_div = ccm_cacrr & CCM_CACRR_IPG_CLK_DIV_MASK; 125 ipgclk_div >>= CCM_CACRR_IPG_CLK_DIV_OFFSET; 126 ipgclk_div += 1; 127 128 return get_bus_clk() / ipgclk_div; 129 } 130 131 static u32 get_uart_clk(void) 132 { 133 return get_ipg_clk(); 134 } 135 136 static u32 get_sdhc_clk(void) 137 { 138 struct ccm_reg *ccm = (struct ccm_reg *)CCM_BASE_ADDR; 139 u32 ccm_cscmr1, ccm_cscdr2, sdhc_clk_sel, sdhc_clk_div; 140 u32 freq = 0; 141 142 ccm_cscmr1 = readl(&ccm->cscmr1); 143 sdhc_clk_sel = ccm_cscmr1 & CCM_CSCMR1_ESDHC1_CLK_SEL_MASK; 144 sdhc_clk_sel >>= CCM_CSCMR1_ESDHC1_CLK_SEL_OFFSET; 145 146 ccm_cscdr2 = readl(&ccm->cscdr2); 147 sdhc_clk_div = ccm_cscdr2 & CCM_CSCDR2_ESDHC1_CLK_DIV_MASK; 148 sdhc_clk_div >>= CCM_CSCDR2_ESDHC1_CLK_DIV_OFFSET; 149 sdhc_clk_div += 1; 150 151 switch (sdhc_clk_sel) { 152 case 0: 153 freq = PLL3_MAIN_FREQ; 154 break; 155 case 1: 156 freq = PLL3_PFD3_FREQ; 157 break; 158 case 2: 159 freq = PLL1_PFD3_FREQ; 160 break; 161 case 3: 162 freq = get_bus_clk(); 163 break; 164 } 165 166 return freq / sdhc_clk_div; 167 } 168 169 u32 get_fec_clk(void) 170 { 171 struct ccm_reg *ccm = (struct ccm_reg *)CCM_BASE_ADDR; 172 u32 ccm_cscmr2, rmii_clk_sel; 173 u32 freq = 0; 174 175 ccm_cscmr2 = readl(&ccm->cscmr2); 176 rmii_clk_sel = ccm_cscmr2 & CCM_CSCMR2_RMII_CLK_SEL_MASK; 177 rmii_clk_sel >>= CCM_CSCMR2_RMII_CLK_SEL_OFFSET; 178 179 switch (rmii_clk_sel) { 180 case 0: 181 freq = ENET_EXTERNAL_CLK; 182 break; 183 case 1: 184 freq = AUDIO_EXTERNAL_CLK; 185 break; 186 case 2: 187 freq = PLL5_MAIN_FREQ; 188 break; 189 case 3: 190 freq = PLL5_MAIN_FREQ / 2; 191 break; 192 } 193 194 return freq; 195 } 196 197 static u32 get_i2c_clk(void) 198 { 199 return get_ipg_clk(); 200 } 201 202 static u32 get_dspi_clk(void) 203 { 204 return get_ipg_clk(); 205 } 206 207 u32 get_lpuart_clk(void) 208 { 209 return get_uart_clk(); 210 } 211 212 unsigned int mxc_get_clock(enum mxc_clock clk) 213 { 214 switch (clk) { 215 case MXC_ARM_CLK: 216 return get_mcu_main_clk(); 217 case MXC_BUS_CLK: 218 return get_bus_clk(); 219 case MXC_IPG_CLK: 220 return get_ipg_clk(); 221 case MXC_UART_CLK: 222 return get_uart_clk(); 223 case MXC_ESDHC_CLK: 224 return get_sdhc_clk(); 225 case MXC_FEC_CLK: 226 return get_fec_clk(); 227 case MXC_I2C_CLK: 228 return get_i2c_clk(); 229 case MXC_DSPI_CLK: 230 return get_dspi_clk(); 231 default: 232 break; 233 } 234 return -1; 235 } 236 237 /* Dump some core clocks */ 238 int do_vf610_showclocks(cmd_tbl_t *cmdtp, int flag, int argc, 239 char * const argv[]) 240 { 241 printf("\n"); 242 printf("cpu clock : %8d MHz\n", mxc_get_clock(MXC_ARM_CLK) / 1000000); 243 printf("bus clock : %8d MHz\n", mxc_get_clock(MXC_BUS_CLK) / 1000000); 244 printf("ipg clock : %8d MHz\n", mxc_get_clock(MXC_IPG_CLK) / 1000000); 245 246 return 0; 247 } 248 249 U_BOOT_CMD( 250 clocks, CONFIG_SYS_MAXARGS, 1, do_vf610_showclocks, 251 "display clocks", 252 "" 253 ); 254 255 #ifdef CONFIG_FEC_MXC 256 void imx_get_mac_from_fuse(int dev_id, unsigned char *mac) 257 { 258 struct ocotp_regs *ocotp = (struct ocotp_regs *)OCOTP_BASE_ADDR; 259 struct fuse_bank *bank = &ocotp->bank[4]; 260 struct fuse_bank4_regs *fuse = 261 (struct fuse_bank4_regs *)bank->fuse_regs; 262 263 u32 value = readl(&fuse->mac_addr0); 264 mac[0] = (value >> 8); 265 mac[1] = value; 266 267 value = readl(&fuse->mac_addr1); 268 mac[2] = value >> 24; 269 mac[3] = value >> 16; 270 mac[4] = value >> 8; 271 mac[5] = value; 272 } 273 #endif 274 275 u32 get_cpu_rev(void) 276 { 277 return MXC_CPU_VF610 << 12; 278 } 279 280 #if defined(CONFIG_DISPLAY_CPUINFO) 281 static char *get_reset_cause(void) 282 { 283 u32 cause; 284 struct src *src_regs = (struct src *)SRC_BASE_ADDR; 285 286 cause = readl(&src_regs->srsr); 287 writel(cause, &src_regs->srsr); 288 289 if (cause & SRC_SRSR_POR_RST) 290 return "POWER ON RESET"; 291 else if (cause & SRC_SRSR_WDOG_A5) 292 return "WDOG A5"; 293 else if (cause & SRC_SRSR_WDOG_M4) 294 return "WDOG M4"; 295 else if (cause & SRC_SRSR_JTAG_RST) 296 return "JTAG HIGH-Z"; 297 else if (cause & SRC_SRSR_SW_RST) 298 return "SW RESET"; 299 else if (cause & SRC_SRSR_RESETB) 300 return "EXTERNAL RESET"; 301 else 302 return "unknown reset"; 303 } 304 305 int print_cpuinfo(void) 306 { 307 printf("CPU: Freescale Vybrid VF%s at %d MHz\n", 308 soc_type, mxc_get_clock(MXC_ARM_CLK) / 1000000); 309 printf("Reset cause: %s\n", get_reset_cause()); 310 311 return 0; 312 } 313 #endif 314 315 int arch_cpu_init(void) 316 { 317 struct mscm *mscm = (struct mscm *)MSCM_BASE_ADDR; 318 319 soc_type[0] = mscm->cpxcount ? '6' : '5'; /*Dual Core => VF6x0 */ 320 soc_type[1] = mscm->cpxcfg1 ? '1' : '0'; /* L2 Cache => VFx10 */ 321 322 return 0; 323 } 324 325 #ifdef CONFIG_ARCH_MISC_INIT 326 int arch_misc_init(void) 327 { 328 char soc[6]; 329 330 strcpy(soc, "vf"); 331 strcat(soc, soc_type); 332 env_set("soc", soc); 333 334 return 0; 335 } 336 #endif 337 338 int cpu_eth_init(bd_t *bis) 339 { 340 int rc = -ENODEV; 341 342 #if defined(CONFIG_FEC_MXC) 343 rc = fecmxc_initialize(bis); 344 #endif 345 346 return rc; 347 } 348 349 #ifdef CONFIG_FSL_ESDHC 350 int cpu_mmc_init(bd_t *bis) 351 { 352 return fsl_esdhc_mmc_init(bis); 353 } 354 #endif 355 356 int get_clocks(void) 357 { 358 #ifdef CONFIG_FSL_ESDHC 359 gd->arch.sdhc_clk = mxc_get_clock(MXC_ESDHC_CLK); 360 #endif 361 return 0; 362 } 363 364 #ifndef CONFIG_SYS_DCACHE_OFF 365 void enable_caches(void) 366 { 367 #if defined(CONFIG_SYS_ARM_CACHE_WRITETHROUGH) 368 enum dcache_option option = DCACHE_WRITETHROUGH; 369 #else 370 enum dcache_option option = DCACHE_WRITEBACK; 371 #endif 372 dcache_enable(); 373 icache_enable(); 374 375 /* Enable caching on OCRAM */ 376 mmu_set_region_dcache_behaviour(IRAM_BASE_ADDR, IRAM_SIZE, option); 377 } 378 #endif 379