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 unsigned int mxc_get_clock(enum mxc_clock clk) 195 { 196 switch (clk) { 197 case MXC_ARM_CLK: 198 return get_mcu_main_clk(); 199 case MXC_BUS_CLK: 200 return get_bus_clk(); 201 case MXC_IPG_CLK: 202 return get_ipg_clk(); 203 case MXC_UART_CLK: 204 return get_uart_clk(); 205 case MXC_ESDHC_CLK: 206 return get_sdhc_clk(); 207 case MXC_FEC_CLK: 208 return get_fec_clk(); 209 default: 210 break; 211 } 212 return -1; 213 } 214 215 /* Dump some core clocks */ 216 int do_vf610_showclocks(cmd_tbl_t *cmdtp, int flag, int argc, 217 char * const argv[]) 218 { 219 printf("\n"); 220 printf("cpu clock : %8d MHz\n", mxc_get_clock(MXC_ARM_CLK) / 1000000); 221 printf("bus clock : %8d MHz\n", mxc_get_clock(MXC_BUS_CLK) / 1000000); 222 printf("ipg clock : %8d MHz\n", mxc_get_clock(MXC_IPG_CLK) / 1000000); 223 224 return 0; 225 } 226 227 U_BOOT_CMD( 228 clocks, CONFIG_SYS_MAXARGS, 1, do_vf610_showclocks, 229 "display clocks", 230 "" 231 ); 232 233 #ifdef CONFIG_FEC_MXC 234 void imx_get_mac_from_fuse(int dev_id, unsigned char *mac) 235 { 236 struct ocotp_regs *ocotp = (struct ocotp_regs *)OCOTP_BASE_ADDR; 237 struct fuse_bank *bank = &ocotp->bank[4]; 238 struct fuse_bank4_regs *fuse = 239 (struct fuse_bank4_regs *)bank->fuse_regs; 240 241 u32 value = readl(&fuse->mac_addr0); 242 mac[0] = (value >> 8); 243 mac[1] = value; 244 245 value = readl(&fuse->mac_addr1); 246 mac[2] = value >> 24; 247 mac[3] = value >> 16; 248 mac[4] = value >> 8; 249 mac[5] = value; 250 } 251 #endif 252 253 #if defined(CONFIG_DISPLAY_CPUINFO) 254 static char *get_reset_cause(void) 255 { 256 u32 cause; 257 struct src *src_regs = (struct src *)SRC_BASE_ADDR; 258 259 cause = readl(&src_regs->srsr); 260 writel(cause, &src_regs->srsr); 261 cause &= 0xff; 262 263 switch (cause) { 264 case 0x08: 265 return "WDOG"; 266 case 0x20: 267 return "JTAG HIGH-Z"; 268 case 0x80: 269 return "EXTERNAL RESET"; 270 case 0xfd: 271 return "POR"; 272 default: 273 return "unknown reset"; 274 } 275 } 276 277 int print_cpuinfo(void) 278 { 279 printf("CPU: Freescale Vybrid VF610 at %d MHz\n", 280 mxc_get_clock(MXC_ARM_CLK) / 1000000); 281 printf("Reset cause: %s\n", get_reset_cause()); 282 283 return 0; 284 } 285 #endif 286 287 int cpu_eth_init(bd_t *bis) 288 { 289 int rc = -ENODEV; 290 291 #if defined(CONFIG_FEC_MXC) 292 rc = fecmxc_initialize(bis); 293 #endif 294 295 return rc; 296 } 297 298 #ifdef CONFIG_FSL_ESDHC 299 int cpu_mmc_init(bd_t *bis) 300 { 301 return fsl_esdhc_mmc_init(bis); 302 } 303 #endif 304 305 int get_clocks(void) 306 { 307 #ifdef CONFIG_FSL_ESDHC 308 gd->arch.sdhc_clk = mxc_get_clock(MXC_ESDHC_CLK); 309 #endif 310 return 0; 311 } 312