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