1 /* 2 * (C) Copyright 2007 3 * Sascha Hauer, Pengutronix 4 * 5 * (C) Copyright 2009 Freescale Semiconductor, Inc. 6 * 7 * SPDX-License-Identifier: GPL-2.0+ 8 */ 9 10 #include <bootm.h> 11 #include <common.h> 12 #include <netdev.h> 13 #include <linux/errno.h> 14 #include <asm/io.h> 15 #include <asm/arch/imx-regs.h> 16 #include <asm/arch/clock.h> 17 #include <asm/arch/sys_proto.h> 18 #include <asm/arch/crm_regs.h> 19 #include <imx_thermal.h> 20 #include <ipu_pixfmt.h> 21 #include <thermal.h> 22 #include <sata.h> 23 24 #ifdef CONFIG_FSL_ESDHC 25 #include <fsl_esdhc.h> 26 #endif 27 28 #if defined(CONFIG_DISPLAY_CPUINFO) 29 static u32 reset_cause = -1; 30 31 static char *get_reset_cause(void) 32 { 33 u32 cause; 34 struct src *src_regs = (struct src *)SRC_BASE_ADDR; 35 36 cause = readl(&src_regs->srsr); 37 writel(cause, &src_regs->srsr); 38 reset_cause = cause; 39 40 switch (cause) { 41 case 0x00001: 42 case 0x00011: 43 return "POR"; 44 case 0x00004: 45 return "CSU"; 46 case 0x00008: 47 return "IPP USER"; 48 case 0x00010: 49 #ifdef CONFIG_MX7 50 return "WDOG1"; 51 #else 52 return "WDOG"; 53 #endif 54 case 0x00020: 55 return "JTAG HIGH-Z"; 56 case 0x00040: 57 return "JTAG SW"; 58 case 0x00080: 59 return "WDOG3"; 60 #ifdef CONFIG_MX7 61 case 0x00100: 62 return "WDOG4"; 63 case 0x00200: 64 return "TEMPSENSE"; 65 #else 66 case 0x00100: 67 return "TEMPSENSE"; 68 case 0x10000: 69 return "WARM BOOT"; 70 #endif 71 default: 72 return "unknown reset"; 73 } 74 } 75 76 u32 get_imx_reset_cause(void) 77 { 78 return reset_cause; 79 } 80 #endif 81 82 #if defined(CONFIG_MX53) || defined(CONFIG_MX6) 83 #if defined(CONFIG_MX53) 84 #define MEMCTL_BASE ESDCTL_BASE_ADDR 85 #else 86 #define MEMCTL_BASE MMDC_P0_BASE_ADDR 87 #endif 88 static const unsigned char col_lookup[] = {9, 10, 11, 8, 12, 9, 9, 9}; 89 static const unsigned char bank_lookup[] = {3, 2}; 90 91 /* these MMDC registers are common to the IMX53 and IMX6 */ 92 struct esd_mmdc_regs { 93 uint32_t ctl; 94 uint32_t pdc; 95 uint32_t otc; 96 uint32_t cfg0; 97 uint32_t cfg1; 98 uint32_t cfg2; 99 uint32_t misc; 100 }; 101 102 #define ESD_MMDC_CTL_GET_ROW(mdctl) ((ctl >> 24) & 7) 103 #define ESD_MMDC_CTL_GET_COLUMN(mdctl) ((ctl >> 20) & 7) 104 #define ESD_MMDC_CTL_GET_WIDTH(mdctl) ((ctl >> 16) & 3) 105 #define ESD_MMDC_CTL_GET_CS1(mdctl) ((ctl >> 30) & 1) 106 #define ESD_MMDC_MISC_GET_BANK(mdmisc) ((misc >> 5) & 1) 107 108 /* 109 * imx_ddr_size - return size in bytes of DRAM according MMDC config 110 * The MMDC MDCTL register holds the number of bits for row, col, and data 111 * width and the MMDC MDMISC register holds the number of banks. Combine 112 * all these bits to determine the meme size the MMDC has been configured for 113 */ 114 unsigned imx_ddr_size(void) 115 { 116 struct esd_mmdc_regs *mem = (struct esd_mmdc_regs *)MEMCTL_BASE; 117 unsigned ctl = readl(&mem->ctl); 118 unsigned misc = readl(&mem->misc); 119 int bits = 11 + 0 + 0 + 1; /* row + col + bank + width */ 120 121 bits += ESD_MMDC_CTL_GET_ROW(ctl); 122 bits += col_lookup[ESD_MMDC_CTL_GET_COLUMN(ctl)]; 123 bits += bank_lookup[ESD_MMDC_MISC_GET_BANK(misc)]; 124 bits += ESD_MMDC_CTL_GET_WIDTH(ctl); 125 bits += ESD_MMDC_CTL_GET_CS1(ctl); 126 127 /* The MX6 can do only 3840 MiB of DRAM */ 128 if (bits == 32) 129 return 0xf0000000; 130 131 return 1 << bits; 132 } 133 #endif 134 135 #if defined(CONFIG_DISPLAY_CPUINFO) 136 137 const char *get_imx_type(u32 imxtype) 138 { 139 switch (imxtype) { 140 case MXC_CPU_MX7S: 141 return "7S"; /* Single-core version of the mx7 */ 142 case MXC_CPU_MX7D: 143 return "7D"; /* Dual-core version of the mx7 */ 144 case MXC_CPU_MX6QP: 145 return "6QP"; /* Quad-Plus version of the mx6 */ 146 case MXC_CPU_MX6DP: 147 return "6DP"; /* Dual-Plus version of the mx6 */ 148 case MXC_CPU_MX6Q: 149 return "6Q"; /* Quad-core version of the mx6 */ 150 case MXC_CPU_MX6D: 151 return "6D"; /* Dual-core version of the mx6 */ 152 case MXC_CPU_MX6DL: 153 return "6DL"; /* Dual Lite version of the mx6 */ 154 case MXC_CPU_MX6SOLO: 155 return "6SOLO"; /* Solo version of the mx6 */ 156 case MXC_CPU_MX6SL: 157 return "6SL"; /* Solo-Lite version of the mx6 */ 158 case MXC_CPU_MX6SLL: 159 return "6SLL"; /* SLL version of the mx6 */ 160 case MXC_CPU_MX6SX: 161 return "6SX"; /* SoloX version of the mx6 */ 162 case MXC_CPU_MX6UL: 163 return "6UL"; /* Ultra-Lite version of the mx6 */ 164 case MXC_CPU_MX6ULL: 165 return "6ULL"; /* ULL version of the mx6 */ 166 case MXC_CPU_MX51: 167 return "51"; 168 case MXC_CPU_MX53: 169 return "53"; 170 default: 171 return "??"; 172 } 173 } 174 175 int print_cpuinfo(void) 176 { 177 u32 cpurev; 178 __maybe_unused u32 max_freq; 179 180 cpurev = get_cpu_rev(); 181 182 #if defined(CONFIG_IMX_THERMAL) 183 struct udevice *thermal_dev; 184 int cpu_tmp, minc, maxc, ret; 185 186 printf("CPU: Freescale i.MX%s rev%d.%d", 187 get_imx_type((cpurev & 0xFF000) >> 12), 188 (cpurev & 0x000F0) >> 4, 189 (cpurev & 0x0000F) >> 0); 190 max_freq = get_cpu_speed_grade_hz(); 191 if (!max_freq || max_freq == mxc_get_clock(MXC_ARM_CLK)) { 192 printf(" at %dMHz\n", mxc_get_clock(MXC_ARM_CLK) / 1000000); 193 } else { 194 printf(" %d MHz (running at %d MHz)\n", max_freq / 1000000, 195 mxc_get_clock(MXC_ARM_CLK) / 1000000); 196 } 197 #else 198 printf("CPU: Freescale i.MX%s rev%d.%d at %d MHz\n", 199 get_imx_type((cpurev & 0xFF000) >> 12), 200 (cpurev & 0x000F0) >> 4, 201 (cpurev & 0x0000F) >> 0, 202 mxc_get_clock(MXC_ARM_CLK) / 1000000); 203 #endif 204 205 #if defined(CONFIG_IMX_THERMAL) 206 puts("CPU: "); 207 switch (get_cpu_temp_grade(&minc, &maxc)) { 208 case TEMP_AUTOMOTIVE: 209 puts("Automotive temperature grade "); 210 break; 211 case TEMP_INDUSTRIAL: 212 puts("Industrial temperature grade "); 213 break; 214 case TEMP_EXTCOMMERCIAL: 215 puts("Extended Commercial temperature grade "); 216 break; 217 default: 218 puts("Commercial temperature grade "); 219 break; 220 } 221 printf("(%dC to %dC)", minc, maxc); 222 ret = uclass_get_device(UCLASS_THERMAL, 0, &thermal_dev); 223 if (!ret) { 224 ret = thermal_get_temp(thermal_dev, &cpu_tmp); 225 226 if (!ret) 227 printf(" at %dC\n", cpu_tmp); 228 else 229 debug(" - invalid sensor data\n"); 230 } else { 231 debug(" - invalid sensor device\n"); 232 } 233 #endif 234 235 printf("Reset cause: %s\n", get_reset_cause()); 236 return 0; 237 } 238 #endif 239 240 int cpu_eth_init(bd_t *bis) 241 { 242 int rc = -ENODEV; 243 244 #if defined(CONFIG_FEC_MXC) 245 rc = fecmxc_initialize(bis); 246 #endif 247 248 return rc; 249 } 250 251 #ifdef CONFIG_FSL_ESDHC 252 /* 253 * Initializes on-chip MMC controllers. 254 * to override, implement board_mmc_init() 255 */ 256 int cpu_mmc_init(bd_t *bis) 257 { 258 return fsl_esdhc_mmc_init(bis); 259 } 260 #endif 261 262 #ifndef CONFIG_MX7 263 u32 get_ahb_clk(void) 264 { 265 struct mxc_ccm_reg *imx_ccm = (struct mxc_ccm_reg *)CCM_BASE_ADDR; 266 u32 reg, ahb_podf; 267 268 reg = __raw_readl(&imx_ccm->cbcdr); 269 reg &= MXC_CCM_CBCDR_AHB_PODF_MASK; 270 ahb_podf = reg >> MXC_CCM_CBCDR_AHB_PODF_OFFSET; 271 272 return get_periph_clk() / (ahb_podf + 1); 273 } 274 #endif 275 276 void arch_preboot_os(void) 277 { 278 #if defined(CONFIG_PCIE_IMX) 279 imx_pcie_remove(); 280 #endif 281 #if defined(CONFIG_SATA) 282 sata_stop(); 283 #if defined(CONFIG_MX6) 284 disable_sata_clock(); 285 #endif 286 #endif 287 #if defined(CONFIG_VIDEO_IPUV3) 288 /* disable video before launching O/S */ 289 ipuv3_fb_shutdown(); 290 #endif 291 #if defined(CONFIG_VIDEO_MXS) 292 lcdif_power_down(); 293 #endif 294 } 295 296 void set_chipselect_size(int const cs_size) 297 { 298 unsigned int reg; 299 struct iomuxc *iomuxc_regs = (struct iomuxc *)IOMUXC_BASE_ADDR; 300 reg = readl(&iomuxc_regs->gpr[1]); 301 302 switch (cs_size) { 303 case CS0_128: 304 reg &= ~0x7; /* CS0=128MB, CS1=0, CS2=0, CS3=0 */ 305 reg |= 0x5; 306 break; 307 case CS0_64M_CS1_64M: 308 reg &= ~0x3F; /* CS0=64MB, CS1=64MB, CS2=0, CS3=0 */ 309 reg |= 0x1B; 310 break; 311 case CS0_64M_CS1_32M_CS2_32M: 312 reg &= ~0x1FF; /* CS0=64MB, CS1=32MB, CS2=32MB, CS3=0 */ 313 reg |= 0x4B; 314 break; 315 case CS0_32M_CS1_32M_CS2_32M_CS3_32M: 316 reg &= ~0xFFF; /* CS0=32MB, CS1=32MB, CS2=32MB, CS3=32MB */ 317 reg |= 0x249; 318 break; 319 default: 320 printf("Unknown chip select size: %d\n", cs_size); 321 break; 322 } 323 324 writel(reg, &iomuxc_regs->gpr[1]); 325 } 326