1 /* 2 * (C) Copyright 2013-2016, 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/mc_cgm_regs.h> 12 #include <asm/arch/mc_me_regs.h> 13 #include <asm/arch/mc_rgm_regs.h> 14 #include <netdev.h> 15 #include <div64.h> 16 #include <errno.h> 17 18 u32 get_cpu_rev(void) 19 { 20 struct mscm_ir *mscmir = (struct mscm_ir *)MSCM_BASE_ADDR; 21 u32 cpu = readl(&mscmir->cpxtype); 22 23 return cpu; 24 } 25 26 DECLARE_GLOBAL_DATA_PTR; 27 28 static uintptr_t get_pllfreq(u32 pll, u32 refclk_freq, u32 plldv, 29 u32 pllfd, u32 selected_output) 30 { 31 u32 vco = 0, plldv_prediv = 0, plldv_mfd = 0, pllfd_mfn = 0; 32 u32 plldv_rfdphi_div = 0, fout = 0; 33 u32 dfs_portn = 0, dfs_mfn = 0, dfs_mfi = 0; 34 35 if (selected_output > DFS_MAXNUMBER) { 36 return -1; 37 } 38 39 plldv_prediv = 40 (plldv & PLLDIG_PLLDV_PREDIV_MASK) >> PLLDIG_PLLDV_PREDIV_OFFSET; 41 plldv_mfd = (plldv & PLLDIG_PLLDV_MFD_MASK); 42 43 pllfd_mfn = (pllfd & PLLDIG_PLLFD_MFN_MASK); 44 45 plldv_prediv = plldv_prediv == 0 ? 1 : plldv_prediv; 46 47 /* The formula for VCO is from TR manual, rev. D */ 48 vco = refclk_freq / plldv_prediv * (plldv_mfd + pllfd_mfn / 20481); 49 50 if (selected_output != 0) { 51 /* Determine the RFDPHI for PHI1 */ 52 plldv_rfdphi_div = 53 (plldv & PLLDIG_PLLDV_RFDPHI1_MASK) >> 54 PLLDIG_PLLDV_RFDPHI1_OFFSET; 55 plldv_rfdphi_div = plldv_rfdphi_div == 0 ? 1 : plldv_rfdphi_div; 56 if (pll == ARM_PLL || pll == ENET_PLL || pll == DDR_PLL) { 57 dfs_portn = 58 readl(DFS_DVPORTn(pll, selected_output - 1)); 59 dfs_mfi = 60 (dfs_portn & DFS_DVPORTn_MFI_MASK) >> 61 DFS_DVPORTn_MFI_OFFSET; 62 dfs_mfn = 63 (dfs_portn & DFS_DVPORTn_MFI_MASK) >> 64 DFS_DVPORTn_MFI_OFFSET; 65 fout = vco / (dfs_mfi + (dfs_mfn / 256)); 66 } else { 67 fout = vco / plldv_rfdphi_div; 68 } 69 70 } else { 71 /* Determine the RFDPHI for PHI0 */ 72 plldv_rfdphi_div = 73 (plldv & PLLDIG_PLLDV_RFDPHI_MASK) >> 74 PLLDIG_PLLDV_RFDPHI_OFFSET; 75 fout = vco / plldv_rfdphi_div; 76 } 77 78 return fout; 79 80 } 81 82 /* Implemented for ARMPLL, PERIPH_PLL, ENET_PLL, DDR_PLL, VIDEO_LL */ 83 static uintptr_t decode_pll(enum pll_type pll, u32 refclk_freq, 84 u32 selected_output) 85 { 86 u32 plldv, pllfd; 87 88 plldv = readl(PLLDIG_PLLDV(pll)); 89 pllfd = readl(PLLDIG_PLLFD(pll)); 90 91 return get_pllfreq(pll, refclk_freq, plldv, pllfd, selected_output); 92 } 93 94 static u32 get_mcu_main_clk(void) 95 { 96 u32 coreclk_div; 97 u32 sysclk_sel; 98 u32 freq = 0; 99 100 sysclk_sel = readl(CGM_SC_SS(MC_CGM1_BASE_ADDR)) & MC_CGM_SC_SEL_MASK; 101 sysclk_sel >>= MC_CGM_SC_SEL_OFFSET; 102 103 coreclk_div = 104 readl(CGM_SC_DCn(MC_CGM1_BASE_ADDR, 0)) & MC_CGM_SC_DCn_PREDIV_MASK; 105 coreclk_div >>= MC_CGM_SC_DCn_PREDIV_OFFSET; 106 coreclk_div += 1; 107 108 switch (sysclk_sel) { 109 case MC_CGM_SC_SEL_FIRC: 110 freq = FIRC_CLK_FREQ; 111 break; 112 case MC_CGM_SC_SEL_XOSC: 113 freq = XOSC_CLK_FREQ; 114 break; 115 case MC_CGM_SC_SEL_ARMPLL: 116 /* ARMPLL has as source XOSC and CORE_CLK has as input PHI0 */ 117 freq = decode_pll(ARM_PLL, XOSC_CLK_FREQ, 0); 118 break; 119 case MC_CGM_SC_SEL_CLKDISABLE: 120 printf("Sysclk is disabled\n"); 121 break; 122 default: 123 printf("unsupported system clock select\n"); 124 } 125 126 return freq / coreclk_div; 127 } 128 129 static u32 get_sys_clk(u32 number) 130 { 131 u32 sysclk_div, sysclk_div_number; 132 u32 sysclk_sel; 133 u32 freq = 0; 134 135 switch (number) { 136 case 3: 137 sysclk_div_number = 0; 138 break; 139 case 6: 140 sysclk_div_number = 1; 141 break; 142 default: 143 printf("unsupported system clock \n"); 144 return -1; 145 } 146 sysclk_sel = readl(CGM_SC_SS(MC_CGM0_BASE_ADDR)) & MC_CGM_SC_SEL_MASK; 147 sysclk_sel >>= MC_CGM_SC_SEL_OFFSET; 148 149 sysclk_div = 150 readl(CGM_SC_DCn(MC_CGM1_BASE_ADDR, sysclk_div_number)) & 151 MC_CGM_SC_DCn_PREDIV_MASK; 152 sysclk_div >>= MC_CGM_SC_DCn_PREDIV_OFFSET; 153 sysclk_div += 1; 154 155 switch (sysclk_sel) { 156 case MC_CGM_SC_SEL_FIRC: 157 freq = FIRC_CLK_FREQ; 158 break; 159 case MC_CGM_SC_SEL_XOSC: 160 freq = XOSC_CLK_FREQ; 161 break; 162 case MC_CGM_SC_SEL_ARMPLL: 163 /* ARMPLL has as source XOSC and SYSn_CLK has as input DFS1 */ 164 freq = decode_pll(ARM_PLL, XOSC_CLK_FREQ, 1); 165 break; 166 case MC_CGM_SC_SEL_CLKDISABLE: 167 printf("Sysclk is disabled\n"); 168 break; 169 default: 170 printf("unsupported system clock select\n"); 171 } 172 173 return freq / sysclk_div; 174 } 175 176 static u32 get_peripherals_clk(void) 177 { 178 u32 aux5clk_div; 179 u32 freq = 0; 180 181 aux5clk_div = 182 readl(CGM_ACn_DCm(MC_CGM0_BASE_ADDR, 5, 0)) & 183 MC_CGM_ACn_DCm_PREDIV_MASK; 184 aux5clk_div >>= MC_CGM_ACn_DCm_PREDIV_OFFSET; 185 aux5clk_div += 1; 186 187 freq = decode_pll(PERIPH_PLL, XOSC_CLK_FREQ, 0); 188 189 return freq / aux5clk_div; 190 191 } 192 193 static u32 get_uart_clk(void) 194 { 195 u32 auxclk3_div, auxclk3_sel, freq = 0; 196 197 auxclk3_sel = 198 readl(CGM_ACn_SS(MC_CGM0_BASE_ADDR, 3)) & MC_CGM_ACn_SEL_MASK; 199 auxclk3_sel >>= MC_CGM_ACn_SEL_OFFSET; 200 201 auxclk3_div = 202 readl(CGM_ACn_DCm(MC_CGM0_BASE_ADDR, 3, 0)) & 203 MC_CGM_ACn_DCm_PREDIV_MASK; 204 auxclk3_div >>= MC_CGM_ACn_DCm_PREDIV_OFFSET; 205 auxclk3_div += 1; 206 207 switch (auxclk3_sel) { 208 case MC_CGM_ACn_SEL_FIRC: 209 freq = FIRC_CLK_FREQ; 210 break; 211 case MC_CGM_ACn_SEL_XOSC: 212 freq = XOSC_CLK_FREQ; 213 break; 214 case MC_CGM_ACn_SEL_PERPLLDIVX: 215 freq = get_peripherals_clk() / 3; 216 break; 217 case MC_CGM_ACn_SEL_SYSCLK: 218 freq = get_sys_clk(6); 219 break; 220 default: 221 printf("unsupported system clock select\n"); 222 } 223 224 return freq / auxclk3_div; 225 } 226 227 static u32 get_fec_clk(void) 228 { 229 u32 aux2clk_div; 230 u32 freq = 0; 231 232 aux2clk_div = 233 readl(CGM_ACn_DCm(MC_CGM0_BASE_ADDR, 2, 0)) & 234 MC_CGM_ACn_DCm_PREDIV_MASK; 235 aux2clk_div >>= MC_CGM_ACn_DCm_PREDIV_OFFSET; 236 aux2clk_div += 1; 237 238 freq = decode_pll(ENET_PLL, XOSC_CLK_FREQ, 0); 239 240 return freq / aux2clk_div; 241 } 242 243 static u32 get_usdhc_clk(void) 244 { 245 u32 aux15clk_div; 246 u32 freq = 0; 247 248 aux15clk_div = 249 readl(CGM_ACn_DCm(MC_CGM0_BASE_ADDR, 15, 0)) & 250 MC_CGM_ACn_DCm_PREDIV_MASK; 251 aux15clk_div >>= MC_CGM_ACn_DCm_PREDIV_OFFSET; 252 aux15clk_div += 1; 253 254 freq = decode_pll(ENET_PLL, XOSC_CLK_FREQ, 4); 255 256 return freq / aux15clk_div; 257 } 258 259 static u32 get_i2c_clk(void) 260 { 261 return get_peripherals_clk(); 262 } 263 264 /* return clocks in Hz */ 265 unsigned int mxc_get_clock(enum mxc_clock clk) 266 { 267 switch (clk) { 268 case MXC_ARM_CLK: 269 return get_mcu_main_clk(); 270 case MXC_PERIPHERALS_CLK: 271 return get_peripherals_clk(); 272 case MXC_UART_CLK: 273 return get_uart_clk(); 274 case MXC_FEC_CLK: 275 return get_fec_clk(); 276 case MXC_I2C_CLK: 277 return get_i2c_clk(); 278 case MXC_USDHC_CLK: 279 return get_usdhc_clk(); 280 default: 281 break; 282 } 283 printf("Error: Unsupported function to read the frequency! \ 284 Please define it correctly!"); 285 return -1; 286 } 287 288 /* Not yet implemented - int soc_clk_dump(); */ 289 290 #if defined(CONFIG_DISPLAY_CPUINFO) 291 static char *get_reset_cause(void) 292 { 293 u32 cause = readl(MC_RGM_BASE_ADDR + 0x300); 294 295 switch (cause) { 296 case F_SWT4: 297 return "WDOG"; 298 case F_JTAG: 299 return "JTAG"; 300 case F_FCCU_SOFT: 301 return "FCCU soft reaction"; 302 case F_FCCU_HARD: 303 return "FCCU hard reaction"; 304 case F_SOFT_FUNC: 305 return "Software Functional reset"; 306 case F_ST_DONE: 307 return "Self Test done reset"; 308 case F_EXT_RST: 309 return "External reset"; 310 default: 311 return "unknown reset"; 312 } 313 314 } 315 316 #define SRC_SCR_SW_RST (1<<12) 317 318 void reset_cpu(ulong addr) 319 { 320 printf("Feature not supported.\n"); 321 }; 322 323 int print_cpuinfo(void) 324 { 325 printf("CPU: Freescale Treerunner S32V234 at %d MHz\n", 326 mxc_get_clock(MXC_ARM_CLK) / 1000000); 327 printf("Reset cause: %s\n", get_reset_cause()); 328 329 return 0; 330 } 331 #endif 332 333 int cpu_eth_init(bd_t * bis) 334 { 335 int rc = -ENODEV; 336 337 #if defined(CONFIG_FEC_MXC) 338 rc = fecmxc_initialize(bis); 339 #endif 340 341 return rc; 342 } 343 344 int get_clocks(void) 345 { 346 #ifdef CONFIG_FSL_ESDHC 347 gd->arch.sdhc_clk = mxc_get_clock(MXC_USDHC_CLK); 348 #endif 349 return 0; 350 } 351