1 /* 2 * Copyright (C) 2015 Freescale Semiconductor, Inc. 3 * 4 * Author: Fabio Estevam <fabio.estevam@freescale.com> 5 * 6 * Copyright (C) 2013 Jon Nettleton <jon.nettleton@gmail.com> 7 * 8 * Based on SPL code from Solidrun tree, which is: 9 * Author: Tungyi Lin <tungyilin1127@gmail.com> 10 * 11 * Derived from EDM_CF_IMX6 code by TechNexion,Inc 12 * Ported to SolidRun microSOM by Rabeeh Khoury <rabeeh@solid-run.com> 13 * 14 * SPDX-License-Identifier: GPL-2.0+ 15 */ 16 17 #include <asm/arch/clock.h> 18 #include <asm/arch/imx-regs.h> 19 #include <asm/arch/iomux.h> 20 #include <asm/arch/mx6-pins.h> 21 #include <asm/errno.h> 22 #include <asm/gpio.h> 23 #include <asm/imx-common/iomux-v3.h> 24 #include <mmc.h> 25 #include <fsl_esdhc.h> 26 #include <miiphy.h> 27 #include <netdev.h> 28 #include <asm/arch/crm_regs.h> 29 #include <asm/io.h> 30 #include <asm/arch/sys_proto.h> 31 #include <spl.h> 32 33 DECLARE_GLOBAL_DATA_PTR; 34 35 #define UART_PAD_CTRL (PAD_CTL_PUS_100K_UP | \ 36 PAD_CTL_SPEED_MED | PAD_CTL_DSE_40ohm | \ 37 PAD_CTL_SRE_FAST | PAD_CTL_HYS) 38 39 #define USDHC_PAD_CTRL (PAD_CTL_PUS_47K_UP | \ 40 PAD_CTL_SPEED_LOW | PAD_CTL_DSE_80ohm | \ 41 PAD_CTL_SRE_FAST | PAD_CTL_HYS) 42 43 #define ENET_PAD_CTRL (PAD_CTL_PUS_100K_UP | \ 44 PAD_CTL_SPEED_MED | PAD_CTL_DSE_40ohm | PAD_CTL_HYS) 45 46 #define ENET_PAD_CTRL_PD (PAD_CTL_PUS_100K_DOWN | \ 47 PAD_CTL_SPEED_MED | PAD_CTL_DSE_40ohm | PAD_CTL_HYS) 48 49 #define ENET_PAD_CTRL_CLK ((PAD_CTL_PUS_100K_UP & ~PAD_CTL_PKE) | \ 50 PAD_CTL_SPEED_MED | PAD_CTL_DSE_40ohm | PAD_CTL_SRE_FAST) 51 52 #define ETH_PHY_RESET IMX_GPIO_NR(4, 15) 53 54 int dram_init(void) 55 { 56 gd->ram_size = imx_ddr_size(); 57 return 0; 58 } 59 60 static iomux_v3_cfg_t const uart1_pads[] = { 61 IOMUX_PADS(PAD_CSI0_DAT10__UART1_TX_DATA | MUX_PAD_CTRL(UART_PAD_CTRL)), 62 IOMUX_PADS(PAD_CSI0_DAT11__UART1_RX_DATA | MUX_PAD_CTRL(UART_PAD_CTRL)), 63 }; 64 65 static iomux_v3_cfg_t const usdhc2_pads[] = { 66 IOMUX_PADS(PAD_SD2_CLK__SD2_CLK | MUX_PAD_CTRL(USDHC_PAD_CTRL)), 67 IOMUX_PADS(PAD_SD2_CMD__SD2_CMD | MUX_PAD_CTRL(USDHC_PAD_CTRL)), 68 IOMUX_PADS(PAD_SD2_DAT0__SD2_DATA0 | MUX_PAD_CTRL(USDHC_PAD_CTRL)), 69 IOMUX_PADS(PAD_SD2_DAT1__SD2_DATA1 | MUX_PAD_CTRL(USDHC_PAD_CTRL)), 70 IOMUX_PADS(PAD_SD2_DAT2__SD2_DATA2 | MUX_PAD_CTRL(USDHC_PAD_CTRL)), 71 IOMUX_PADS(PAD_SD2_DAT3__SD2_DATA3 | MUX_PAD_CTRL(USDHC_PAD_CTRL)), 72 }; 73 74 static iomux_v3_cfg_t const hb_cbi_sense[] = { 75 /* These pins are for sensing if it is a CuBox-i or a HummingBoard */ 76 IOMUX_PADS(PAD_KEY_ROW1__GPIO4_IO09 | MUX_PAD_CTRL(UART_PAD_CTRL)), 77 IOMUX_PADS(PAD_EIM_DA4__GPIO3_IO04 | MUX_PAD_CTRL(UART_PAD_CTRL)), 78 }; 79 80 static void setup_iomux_uart(void) 81 { 82 SETUP_IOMUX_PADS(uart1_pads); 83 } 84 85 static struct fsl_esdhc_cfg usdhc_cfg[1] = { 86 {USDHC2_BASE_ADDR}, 87 }; 88 89 int board_mmc_getcd(struct mmc *mmc) 90 { 91 return 1; /* uSDHC2 is always present */ 92 } 93 94 int board_mmc_init(bd_t *bis) 95 { 96 SETUP_IOMUX_PADS(usdhc2_pads); 97 usdhc_cfg[0].esdhc_base = USDHC2_BASE_ADDR; 98 usdhc_cfg[0].sdhc_clk = mxc_get_clock(MXC_ESDHC2_CLK); 99 gd->arch.sdhc_clk = usdhc_cfg[0].sdhc_clk; 100 101 return fsl_esdhc_initialize(bis, &usdhc_cfg[0]); 102 } 103 104 static iomux_v3_cfg_t const enet_pads[] = { 105 IOMUX_PADS(PAD_ENET_MDIO__ENET_MDIO | MUX_PAD_CTRL(ENET_PAD_CTRL)), 106 IOMUX_PADS(PAD_ENET_MDC__ENET_MDC | MUX_PAD_CTRL(ENET_PAD_CTRL)), 107 /* AR8035 reset */ 108 IOMUX_PADS(PAD_KEY_ROW4__GPIO4_IO15 | MUX_PAD_CTRL(ENET_PAD_CTRL_PD)), 109 /* AR8035 interrupt */ 110 IOMUX_PADS(PAD_DI0_PIN2__GPIO4_IO18 | MUX_PAD_CTRL(NO_PAD_CTRL)), 111 /* GPIO16 -> AR8035 25MHz */ 112 IOMUX_PADS(PAD_GPIO_16__ENET_REF_CLK | MUX_PAD_CTRL(NO_PAD_CTRL)), 113 IOMUX_PADS(PAD_RGMII_TXC__RGMII_TXC | MUX_PAD_CTRL(NO_PAD_CTRL)), 114 IOMUX_PADS(PAD_RGMII_TD0__RGMII_TD0 | MUX_PAD_CTRL(ENET_PAD_CTRL)), 115 IOMUX_PADS(PAD_RGMII_TD1__RGMII_TD1 | MUX_PAD_CTRL(ENET_PAD_CTRL)), 116 IOMUX_PADS(PAD_RGMII_TD2__RGMII_TD2 | MUX_PAD_CTRL(ENET_PAD_CTRL)), 117 IOMUX_PADS(PAD_RGMII_TD3__RGMII_TD3 | MUX_PAD_CTRL(ENET_PAD_CTRL)), 118 IOMUX_PADS(PAD_RGMII_TX_CTL__RGMII_TX_CTL | MUX_PAD_CTRL(ENET_PAD_CTRL)), 119 /* AR8035 CLK_25M --> ENET_REF_CLK (V22) */ 120 IOMUX_PADS(PAD_ENET_REF_CLK__ENET_TX_CLK | MUX_PAD_CTRL(ENET_PAD_CTRL_CLK)), 121 IOMUX_PADS(PAD_RGMII_RXC__RGMII_RXC | MUX_PAD_CTRL(ENET_PAD_CTRL)), 122 IOMUX_PADS(PAD_RGMII_RD0__RGMII_RD0 | MUX_PAD_CTRL(ENET_PAD_CTRL_PD)), 123 IOMUX_PADS(PAD_RGMII_RD1__RGMII_RD1 | MUX_PAD_CTRL(ENET_PAD_CTRL_PD)), 124 IOMUX_PADS(PAD_RGMII_RD2__RGMII_RD2 | MUX_PAD_CTRL(ENET_PAD_CTRL)), 125 IOMUX_PADS(PAD_RGMII_RD3__RGMII_RD3 | MUX_PAD_CTRL(ENET_PAD_CTRL)), 126 IOMUX_PADS(PAD_RGMII_RX_CTL__RGMII_RX_CTL | MUX_PAD_CTRL(ENET_PAD_CTRL_PD)), 127 }; 128 129 static void setup_iomux_enet(void) 130 { 131 SETUP_IOMUX_PADS(enet_pads); 132 133 gpio_direction_output(ETH_PHY_RESET, 0); 134 mdelay(2); 135 gpio_set_value(ETH_PHY_RESET, 1); 136 } 137 138 int board_phy_config(struct phy_device *phydev) 139 { 140 if (phydev->drv->config) 141 phydev->drv->config(phydev); 142 143 return 0; 144 } 145 146 int board_eth_init(bd_t *bis) 147 { 148 struct iomuxc *const iomuxc_regs = (struct iomuxc *)IOMUXC_BASE_ADDR; 149 150 int ret = enable_fec_anatop_clock(ENET_25MHZ); 151 if (ret) 152 return ret; 153 154 /* set gpr1[ENET_CLK_SEL] */ 155 setbits_le32(&iomuxc_regs->gpr[1], IOMUXC_GPR1_ENET_CLK_SEL_MASK); 156 157 setup_iomux_enet(); 158 159 return cpu_eth_init(bis); 160 } 161 162 int board_early_init_f(void) 163 { 164 setup_iomux_uart(); 165 return 0; 166 } 167 168 int board_init(void) 169 { 170 /* address of boot parameters */ 171 gd->bd->bi_boot_params = CONFIG_SYS_SDRAM_BASE + 0x100; 172 173 return 0; 174 } 175 176 static bool is_hummingboard(void) 177 { 178 int val1, val2; 179 180 SETUP_IOMUX_PADS(hb_cbi_sense); 181 182 gpio_direction_input(IMX_GPIO_NR(4, 9)); 183 gpio_direction_input(IMX_GPIO_NR(3, 4)); 184 185 val1 = gpio_get_value(IMX_GPIO_NR(4, 9)); 186 val2 = gpio_get_value(IMX_GPIO_NR(3, 4)); 187 188 /* 189 * Machine selection - 190 * Machine val1, val2 191 * ------------------------- 192 * HB rev 3.x x 0 193 * CBi 0 1 194 * HB 1 1 195 */ 196 197 if (val2 == 0) 198 return true; 199 else if (val1 == 0) 200 return false; 201 else 202 return true; 203 } 204 205 int checkboard(void) 206 { 207 if (is_hummingboard()) 208 puts("Board: MX6 Hummingboard\n"); 209 else 210 puts("Board: MX6 Cubox-i\n"); 211 212 return 0; 213 } 214 215 static bool is_mx6q(void) 216 { 217 if (is_cpu_type(MXC_CPU_MX6Q) || is_cpu_type(MXC_CPU_MX6D)) 218 return true; 219 else 220 return false; 221 } 222 223 int board_late_init(void) 224 { 225 #ifdef CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG 226 if (is_hummingboard()) 227 setenv("board_name", "HUMMINGBOARD"); 228 else 229 setenv("board_name", "CUBOXI"); 230 231 if (is_mx6q()) 232 setenv("board_rev", "MX6Q"); 233 else 234 setenv("board_rev", "MX6DL"); 235 #endif 236 237 return 0; 238 } 239 240 #ifdef CONFIG_SPL_BUILD 241 #include <asm/arch/mx6-ddr.h> 242 static const struct mx6dq_iomux_ddr_regs mx6q_ddr_ioregs = { 243 .dram_sdclk_0 = 0x00020030, 244 .dram_sdclk_1 = 0x00020030, 245 .dram_cas = 0x00020030, 246 .dram_ras = 0x00020030, 247 .dram_reset = 0x00020030, 248 .dram_sdcke0 = 0x00003000, 249 .dram_sdcke1 = 0x00003000, 250 .dram_sdba2 = 0x00000000, 251 .dram_sdodt0 = 0x00003030, 252 .dram_sdodt1 = 0x00003030, 253 .dram_sdqs0 = 0x00000030, 254 .dram_sdqs1 = 0x00000030, 255 .dram_sdqs2 = 0x00000030, 256 .dram_sdqs3 = 0x00000030, 257 .dram_sdqs4 = 0x00000030, 258 .dram_sdqs5 = 0x00000030, 259 .dram_sdqs6 = 0x00000030, 260 .dram_sdqs7 = 0x00000030, 261 .dram_dqm0 = 0x00020030, 262 .dram_dqm1 = 0x00020030, 263 .dram_dqm2 = 0x00020030, 264 .dram_dqm3 = 0x00020030, 265 .dram_dqm4 = 0x00020030, 266 .dram_dqm5 = 0x00020030, 267 .dram_dqm6 = 0x00020030, 268 .dram_dqm7 = 0x00020030, 269 }; 270 271 static const struct mx6sdl_iomux_ddr_regs mx6dl_ddr_ioregs = { 272 .dram_sdclk_0 = 0x00000028, 273 .dram_sdclk_1 = 0x00000028, 274 .dram_cas = 0x00000028, 275 .dram_ras = 0x00000028, 276 .dram_reset = 0x000c0028, 277 .dram_sdcke0 = 0x00003000, 278 .dram_sdcke1 = 0x00003000, 279 .dram_sdba2 = 0x00000000, 280 .dram_sdodt0 = 0x00003030, 281 .dram_sdodt1 = 0x00003030, 282 .dram_sdqs0 = 0x00000028, 283 .dram_sdqs1 = 0x00000028, 284 .dram_sdqs2 = 0x00000028, 285 .dram_sdqs3 = 0x00000028, 286 .dram_sdqs4 = 0x00000028, 287 .dram_sdqs5 = 0x00000028, 288 .dram_sdqs6 = 0x00000028, 289 .dram_sdqs7 = 0x00000028, 290 .dram_dqm0 = 0x00000028, 291 .dram_dqm1 = 0x00000028, 292 .dram_dqm2 = 0x00000028, 293 .dram_dqm3 = 0x00000028, 294 .dram_dqm4 = 0x00000028, 295 .dram_dqm5 = 0x00000028, 296 .dram_dqm6 = 0x00000028, 297 .dram_dqm7 = 0x00000028, 298 }; 299 300 static const struct mx6dq_iomux_grp_regs mx6q_grp_ioregs = { 301 .grp_ddr_type = 0x000C0000, 302 .grp_ddrmode_ctl = 0x00020000, 303 .grp_ddrpke = 0x00000000, 304 .grp_addds = 0x00000030, 305 .grp_ctlds = 0x00000030, 306 .grp_ddrmode = 0x00020000, 307 .grp_b0ds = 0x00000030, 308 .grp_b1ds = 0x00000030, 309 .grp_b2ds = 0x00000030, 310 .grp_b3ds = 0x00000030, 311 .grp_b4ds = 0x00000030, 312 .grp_b5ds = 0x00000030, 313 .grp_b6ds = 0x00000030, 314 .grp_b7ds = 0x00000030, 315 }; 316 317 static const struct mx6sdl_iomux_grp_regs mx6sdl_grp_ioregs = { 318 .grp_ddr_type = 0x000c0000, 319 .grp_ddrmode_ctl = 0x00020000, 320 .grp_ddrpke = 0x00000000, 321 .grp_addds = 0x00000028, 322 .grp_ctlds = 0x00000028, 323 .grp_ddrmode = 0x00020000, 324 .grp_b0ds = 0x00000028, 325 .grp_b1ds = 0x00000028, 326 .grp_b2ds = 0x00000028, 327 .grp_b3ds = 0x00000028, 328 .grp_b4ds = 0x00000028, 329 .grp_b5ds = 0x00000028, 330 .grp_b6ds = 0x00000028, 331 .grp_b7ds = 0x00000028, 332 }; 333 334 /* microSOM with Dual processor and 1GB memory */ 335 static const struct mx6_mmdc_calibration mx6q_1g_mmcd_calib = { 336 .p0_mpwldectrl0 = 0x00000000, 337 .p0_mpwldectrl1 = 0x00000000, 338 .p1_mpwldectrl0 = 0x00000000, 339 .p1_mpwldectrl1 = 0x00000000, 340 .p0_mpdgctrl0 = 0x0314031c, 341 .p0_mpdgctrl1 = 0x023e0304, 342 .p1_mpdgctrl0 = 0x03240330, 343 .p1_mpdgctrl1 = 0x03180260, 344 .p0_mprddlctl = 0x3630323c, 345 .p1_mprddlctl = 0x3436283a, 346 .p0_mpwrdlctl = 0x36344038, 347 .p1_mpwrdlctl = 0x422a423c, 348 }; 349 350 /* microSOM with Quad processor and 2GB memory */ 351 static const struct mx6_mmdc_calibration mx6q_2g_mmcd_calib = { 352 .p0_mpwldectrl0 = 0x00000000, 353 .p0_mpwldectrl1 = 0x00000000, 354 .p1_mpwldectrl0 = 0x00000000, 355 .p1_mpwldectrl1 = 0x00000000, 356 .p0_mpdgctrl0 = 0x0314031c, 357 .p0_mpdgctrl1 = 0x023e0304, 358 .p1_mpdgctrl0 = 0x03240330, 359 .p1_mpdgctrl1 = 0x03180260, 360 .p0_mprddlctl = 0x3630323c, 361 .p1_mprddlctl = 0x3436283a, 362 .p0_mpwrdlctl = 0x36344038, 363 .p1_mpwrdlctl = 0x422a423c, 364 }; 365 366 /* microSOM with Solo processor and 512MB memory */ 367 static const struct mx6_mmdc_calibration mx6dl_512m_mmcd_calib = { 368 .p0_mpwldectrl0 = 0x0045004D, 369 .p0_mpwldectrl1 = 0x003A0047, 370 .p0_mpdgctrl0 = 0x023C0224, 371 .p0_mpdgctrl1 = 0x02000220, 372 .p0_mprddlctl = 0x44444846, 373 .p0_mpwrdlctl = 0x32343032, 374 }; 375 376 /* microSOM with Dual lite processor and 1GB memory */ 377 static const struct mx6_mmdc_calibration mx6dl_1g_mmcd_calib = { 378 .p0_mpwldectrl0 = 0x0045004D, 379 .p0_mpwldectrl1 = 0x003A0047, 380 .p1_mpwldectrl0 = 0x001F001F, 381 .p1_mpwldectrl1 = 0x00210035, 382 .p0_mpdgctrl0 = 0x023C0224, 383 .p0_mpdgctrl1 = 0x02000220, 384 .p1_mpdgctrl0 = 0x02200220, 385 .p1_mpdgctrl1 = 0x02000220, 386 .p0_mprddlctl = 0x44444846, 387 .p1_mprddlctl = 0x4042463C, 388 .p0_mpwrdlctl = 0x32343032, 389 .p1_mpwrdlctl = 0x36363430, 390 }; 391 392 static struct mx6_ddr3_cfg mem_ddr_2g = { 393 .mem_speed = 1600, 394 .density = 2, 395 .width = 16, 396 .banks = 8, 397 .rowaddr = 14, 398 .coladdr = 10, 399 .pagesz = 2, 400 .trcd = 1375, 401 .trcmin = 4875, 402 .trasmin = 3500, 403 .SRT = 1, 404 }; 405 406 static struct mx6_ddr3_cfg mem_ddr_4g = { 407 .mem_speed = 1600, 408 .density = 4, 409 .width = 16, 410 .banks = 8, 411 .rowaddr = 15, 412 .coladdr = 10, 413 .pagesz = 2, 414 .trcd = 1375, 415 .trcmin = 4875, 416 .trasmin = 3500, 417 }; 418 419 static void ccgr_init(void) 420 { 421 struct mxc_ccm_reg *ccm = (struct mxc_ccm_reg *)CCM_BASE_ADDR; 422 423 writel(0x00C03F3F, &ccm->CCGR0); 424 writel(0x0030FC03, &ccm->CCGR1); 425 writel(0x0FFFC000, &ccm->CCGR2); 426 writel(0x3FF00000, &ccm->CCGR3); 427 writel(0x00FFF300, &ccm->CCGR4); 428 writel(0x0F0000C3, &ccm->CCGR5); 429 writel(0x000003FF, &ccm->CCGR6); 430 } 431 432 static void gpr_init(void) 433 { 434 struct iomuxc *iomux = (struct iomuxc *)IOMUXC_BASE_ADDR; 435 436 /* enable AXI cache for VDOA/VPU/IPU */ 437 writel(0xF00000CF, &iomux->gpr[4]); 438 /* set IPU AXI-id0 Qos=0xf(bypass) AXI-id1 Qos=0x7 */ 439 writel(0x007F007F, &iomux->gpr[6]); 440 writel(0x007F007F, &iomux->gpr[7]); 441 } 442 443 /* 444 * This section requires the differentiation between Solidrun mx6 boards, but 445 * for now, it will configure only for the mx6dual hummingboard version. 446 */ 447 static void spl_dram_init(int width) 448 { 449 struct mx6_ddr_sysinfo sysinfo = { 450 /* width of data bus: 0=16, 1=32, 2=64 */ 451 .dsize = width / 32, 452 /* config for full 4GB range so that get_mem_size() works */ 453 .cs_density = 32, /* 32Gb per CS */ 454 .ncs = 1, /* single chip select */ 455 .cs1_mirror = 0, 456 .rtt_wr = 1 /*DDR3_RTT_60_OHM*/, /* RTT_Wr = RZQ/4 */ 457 .rtt_nom = 1 /*DDR3_RTT_60_OHM*/, /* RTT_Nom = RZQ/4 */ 458 .walat = 1, /* Write additional latency */ 459 .ralat = 5, /* Read additional latency */ 460 .mif3_mode = 3, /* Command prediction working mode */ 461 .bi_on = 1, /* Bank interleaving enabled */ 462 .sde_to_rst = 0x10, /* 14 cycles, 200us (JEDEC default) */ 463 .rst_to_cke = 0x23, /* 33 cycles, 500us (JEDEC default) */ 464 }; 465 466 if (is_cpu_type(MXC_CPU_MX6D) || is_cpu_type(MXC_CPU_MX6Q)) 467 mx6dq_dram_iocfg(width, &mx6q_ddr_ioregs, &mx6q_grp_ioregs); 468 else 469 mx6sdl_dram_iocfg(width, &mx6dl_ddr_ioregs, &mx6sdl_grp_ioregs); 470 471 if (is_cpu_type(MXC_CPU_MX6D)) 472 mx6_dram_cfg(&sysinfo, &mx6q_1g_mmcd_calib, &mem_ddr_2g); 473 else if (is_cpu_type(MXC_CPU_MX6Q)) 474 mx6_dram_cfg(&sysinfo, &mx6q_2g_mmcd_calib, &mem_ddr_4g); 475 else if (is_cpu_type(MXC_CPU_MX6DL)) 476 mx6_dram_cfg(&sysinfo, &mx6q_1g_mmcd_calib, &mem_ddr_2g); 477 else if (is_cpu_type(MXC_CPU_MX6SOLO)) 478 mx6_dram_cfg(&sysinfo, &mx6dl_512m_mmcd_calib, &mem_ddr_2g); 479 } 480 481 void board_init_f(ulong dummy) 482 { 483 /* setup AIPS and disable watchdog */ 484 arch_cpu_init(); 485 486 ccgr_init(); 487 gpr_init(); 488 489 /* iomux and setup of i2c */ 490 board_early_init_f(); 491 492 /* setup GP timer */ 493 timer_init(); 494 495 /* UART clocks enabled and gd valid - init serial console */ 496 preloader_console_init(); 497 498 /* DDR initialization */ 499 if (is_cpu_type(MXC_CPU_MX6SOLO)) 500 spl_dram_init(32); 501 else 502 spl_dram_init(64); 503 504 /* Clear the BSS. */ 505 memset(__bss_start, 0, __bss_end - __bss_start); 506 507 /* load/boot image from boot device */ 508 board_init_r(NULL, 0); 509 } 510 #endif 511