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 #ifdef CONFIG_SPL_BUILD 216 #include <asm/arch/mx6-ddr.h> 217 static const struct mx6dq_iomux_ddr_regs mx6q_ddr_ioregs = { 218 .dram_sdclk_0 = 0x00020030, 219 .dram_sdclk_1 = 0x00020030, 220 .dram_cas = 0x00020030, 221 .dram_ras = 0x00020030, 222 .dram_reset = 0x00020030, 223 .dram_sdcke0 = 0x00003000, 224 .dram_sdcke1 = 0x00003000, 225 .dram_sdba2 = 0x00000000, 226 .dram_sdodt0 = 0x00003030, 227 .dram_sdodt1 = 0x00003030, 228 .dram_sdqs0 = 0x00000030, 229 .dram_sdqs1 = 0x00000030, 230 .dram_sdqs2 = 0x00000030, 231 .dram_sdqs3 = 0x00000030, 232 .dram_sdqs4 = 0x00000030, 233 .dram_sdqs5 = 0x00000030, 234 .dram_sdqs6 = 0x00000030, 235 .dram_sdqs7 = 0x00000030, 236 .dram_dqm0 = 0x00020030, 237 .dram_dqm1 = 0x00020030, 238 .dram_dqm2 = 0x00020030, 239 .dram_dqm3 = 0x00020030, 240 .dram_dqm4 = 0x00020030, 241 .dram_dqm5 = 0x00020030, 242 .dram_dqm6 = 0x00020030, 243 .dram_dqm7 = 0x00020030, 244 }; 245 246 static const struct mx6sdl_iomux_ddr_regs mx6dl_ddr_ioregs = { 247 .dram_sdclk_0 = 0x00000028, 248 .dram_sdclk_1 = 0x00000028, 249 .dram_cas = 0x00000028, 250 .dram_ras = 0x00000028, 251 .dram_reset = 0x000c0028, 252 .dram_sdcke0 = 0x00003000, 253 .dram_sdcke1 = 0x00003000, 254 .dram_sdba2 = 0x00000000, 255 .dram_sdodt0 = 0x00003030, 256 .dram_sdodt1 = 0x00003030, 257 .dram_sdqs0 = 0x00000028, 258 .dram_sdqs1 = 0x00000028, 259 .dram_sdqs2 = 0x00000028, 260 .dram_sdqs3 = 0x00000028, 261 .dram_sdqs4 = 0x00000028, 262 .dram_sdqs5 = 0x00000028, 263 .dram_sdqs6 = 0x00000028, 264 .dram_sdqs7 = 0x00000028, 265 .dram_dqm0 = 0x00000028, 266 .dram_dqm1 = 0x00000028, 267 .dram_dqm2 = 0x00000028, 268 .dram_dqm3 = 0x00000028, 269 .dram_dqm4 = 0x00000028, 270 .dram_dqm5 = 0x00000028, 271 .dram_dqm6 = 0x00000028, 272 .dram_dqm7 = 0x00000028, 273 }; 274 275 static const struct mx6dq_iomux_grp_regs mx6q_grp_ioregs = { 276 .grp_ddr_type = 0x000C0000, 277 .grp_ddrmode_ctl = 0x00020000, 278 .grp_ddrpke = 0x00000000, 279 .grp_addds = 0x00000030, 280 .grp_ctlds = 0x00000030, 281 .grp_ddrmode = 0x00020000, 282 .grp_b0ds = 0x00000030, 283 .grp_b1ds = 0x00000030, 284 .grp_b2ds = 0x00000030, 285 .grp_b3ds = 0x00000030, 286 .grp_b4ds = 0x00000030, 287 .grp_b5ds = 0x00000030, 288 .grp_b6ds = 0x00000030, 289 .grp_b7ds = 0x00000030, 290 }; 291 292 static const struct mx6sdl_iomux_grp_regs mx6sdl_grp_ioregs = { 293 .grp_ddr_type = 0x000c0000, 294 .grp_ddrmode_ctl = 0x00020000, 295 .grp_ddrpke = 0x00000000, 296 .grp_addds = 0x00000028, 297 .grp_ctlds = 0x00000028, 298 .grp_ddrmode = 0x00020000, 299 .grp_b0ds = 0x00000028, 300 .grp_b1ds = 0x00000028, 301 .grp_b2ds = 0x00000028, 302 .grp_b3ds = 0x00000028, 303 .grp_b4ds = 0x00000028, 304 .grp_b5ds = 0x00000028, 305 .grp_b6ds = 0x00000028, 306 .grp_b7ds = 0x00000028, 307 }; 308 309 /* microSOM with Dual processor and 1GB memory */ 310 static const struct mx6_mmdc_calibration mx6q_1g_mmcd_calib = { 311 .p0_mpwldectrl0 = 0x00000000, 312 .p0_mpwldectrl1 = 0x00000000, 313 .p1_mpwldectrl0 = 0x00000000, 314 .p1_mpwldectrl1 = 0x00000000, 315 .p0_mpdgctrl0 = 0x0314031c, 316 .p0_mpdgctrl1 = 0x023e0304, 317 .p1_mpdgctrl0 = 0x03240330, 318 .p1_mpdgctrl1 = 0x03180260, 319 .p0_mprddlctl = 0x3630323c, 320 .p1_mprddlctl = 0x3436283a, 321 .p0_mpwrdlctl = 0x36344038, 322 .p1_mpwrdlctl = 0x422a423c, 323 }; 324 325 /* microSOM with Quad processor and 2GB memory */ 326 static const struct mx6_mmdc_calibration mx6q_2g_mmcd_calib = { 327 .p0_mpwldectrl0 = 0x00000000, 328 .p0_mpwldectrl1 = 0x00000000, 329 .p1_mpwldectrl0 = 0x00000000, 330 .p1_mpwldectrl1 = 0x00000000, 331 .p0_mpdgctrl0 = 0x0314031c, 332 .p0_mpdgctrl1 = 0x023e0304, 333 .p1_mpdgctrl0 = 0x03240330, 334 .p1_mpdgctrl1 = 0x03180260, 335 .p0_mprddlctl = 0x3630323c, 336 .p1_mprddlctl = 0x3436283a, 337 .p0_mpwrdlctl = 0x36344038, 338 .p1_mpwrdlctl = 0x422a423c, 339 }; 340 341 /* microSOM with Solo processor and 512MB memory */ 342 static const struct mx6_mmdc_calibration mx6dl_512m_mmcd_calib = { 343 .p0_mpwldectrl0 = 0x0045004D, 344 .p0_mpwldectrl1 = 0x003A0047, 345 .p0_mpdgctrl0 = 0x023C0224, 346 .p0_mpdgctrl1 = 0x02000220, 347 .p0_mprddlctl = 0x44444846, 348 .p0_mpwrdlctl = 0x32343032, 349 }; 350 351 /* microSOM with Dual lite processor and 1GB memory */ 352 static const struct mx6_mmdc_calibration mx6dl_1g_mmcd_calib = { 353 .p0_mpwldectrl0 = 0x0045004D, 354 .p0_mpwldectrl1 = 0x003A0047, 355 .p1_mpwldectrl0 = 0x001F001F, 356 .p1_mpwldectrl1 = 0x00210035, 357 .p0_mpdgctrl0 = 0x023C0224, 358 .p0_mpdgctrl1 = 0x02000220, 359 .p1_mpdgctrl0 = 0x02200220, 360 .p1_mpdgctrl1 = 0x02000220, 361 .p0_mprddlctl = 0x44444846, 362 .p1_mprddlctl = 0x4042463C, 363 .p0_mpwrdlctl = 0x32343032, 364 .p1_mpwrdlctl = 0x36363430, 365 }; 366 367 static struct mx6_ddr3_cfg mem_ddr_2g = { 368 .mem_speed = 1600, 369 .density = 2, 370 .width = 16, 371 .banks = 8, 372 .rowaddr = 14, 373 .coladdr = 10, 374 .pagesz = 2, 375 .trcd = 1375, 376 .trcmin = 4875, 377 .trasmin = 3500, 378 .SRT = 1, 379 }; 380 381 static struct mx6_ddr3_cfg mem_ddr_4g = { 382 .mem_speed = 1600, 383 .density = 4, 384 .width = 16, 385 .banks = 8, 386 .rowaddr = 15, 387 .coladdr = 10, 388 .pagesz = 2, 389 .trcd = 1375, 390 .trcmin = 4875, 391 .trasmin = 3500, 392 }; 393 394 static void ccgr_init(void) 395 { 396 struct mxc_ccm_reg *ccm = (struct mxc_ccm_reg *)CCM_BASE_ADDR; 397 398 writel(0x00C03F3F, &ccm->CCGR0); 399 writel(0x0030FC03, &ccm->CCGR1); 400 writel(0x0FFFC000, &ccm->CCGR2); 401 writel(0x3FF00000, &ccm->CCGR3); 402 writel(0x00FFF300, &ccm->CCGR4); 403 writel(0x0F0000C3, &ccm->CCGR5); 404 writel(0x000003FF, &ccm->CCGR6); 405 } 406 407 static void gpr_init(void) 408 { 409 struct iomuxc *iomux = (struct iomuxc *)IOMUXC_BASE_ADDR; 410 411 /* enable AXI cache for VDOA/VPU/IPU */ 412 writel(0xF00000CF, &iomux->gpr[4]); 413 /* set IPU AXI-id0 Qos=0xf(bypass) AXI-id1 Qos=0x7 */ 414 writel(0x007F007F, &iomux->gpr[6]); 415 writel(0x007F007F, &iomux->gpr[7]); 416 } 417 418 /* 419 * This section requires the differentiation between Solidrun mx6 boards, but 420 * for now, it will configure only for the mx6dual hummingboard version. 421 */ 422 static void spl_dram_init(int width) 423 { 424 struct mx6_ddr_sysinfo sysinfo = { 425 /* width of data bus: 0=16, 1=32, 2=64 */ 426 .dsize = width / 32, 427 /* config for full 4GB range so that get_mem_size() works */ 428 .cs_density = 32, /* 32Gb per CS */ 429 .ncs = 1, /* single chip select */ 430 .cs1_mirror = 0, 431 .rtt_wr = 1 /*DDR3_RTT_60_OHM*/, /* RTT_Wr = RZQ/4 */ 432 .rtt_nom = 1 /*DDR3_RTT_60_OHM*/, /* RTT_Nom = RZQ/4 */ 433 .walat = 1, /* Write additional latency */ 434 .ralat = 5, /* Read additional latency */ 435 .mif3_mode = 3, /* Command prediction working mode */ 436 .bi_on = 1, /* Bank interleaving enabled */ 437 .sde_to_rst = 0x10, /* 14 cycles, 200us (JEDEC default) */ 438 .rst_to_cke = 0x23, /* 33 cycles, 500us (JEDEC default) */ 439 }; 440 441 if (is_cpu_type(MXC_CPU_MX6D) || is_cpu_type(MXC_CPU_MX6Q)) 442 mx6dq_dram_iocfg(width, &mx6q_ddr_ioregs, &mx6q_grp_ioregs); 443 else 444 mx6sdl_dram_iocfg(width, &mx6dl_ddr_ioregs, &mx6sdl_grp_ioregs); 445 446 if (is_cpu_type(MXC_CPU_MX6D)) 447 mx6_dram_cfg(&sysinfo, &mx6q_1g_mmcd_calib, &mem_ddr_2g); 448 else if (is_cpu_type(MXC_CPU_MX6Q)) 449 mx6_dram_cfg(&sysinfo, &mx6q_2g_mmcd_calib, &mem_ddr_4g); 450 else if (is_cpu_type(MXC_CPU_MX6DL)) 451 mx6_dram_cfg(&sysinfo, &mx6q_1g_mmcd_calib, &mem_ddr_2g); 452 else if (is_cpu_type(MXC_CPU_MX6SOLO)) 453 mx6_dram_cfg(&sysinfo, &mx6dl_512m_mmcd_calib, &mem_ddr_2g); 454 } 455 456 void board_init_f(ulong dummy) 457 { 458 /* setup AIPS and disable watchdog */ 459 arch_cpu_init(); 460 461 ccgr_init(); 462 gpr_init(); 463 464 /* iomux and setup of i2c */ 465 board_early_init_f(); 466 467 /* setup GP timer */ 468 timer_init(); 469 470 /* UART clocks enabled and gd valid - init serial console */ 471 preloader_console_init(); 472 473 /* DDR initialization */ 474 if (is_cpu_type(MXC_CPU_MX6SOLO)) 475 spl_dram_init(32); 476 else 477 spl_dram_init(64); 478 479 /* Clear the BSS. */ 480 memset(__bss_start, 0, __bss_end - __bss_start); 481 482 /* load/boot image from boot device */ 483 board_init_r(NULL, 0); 484 } 485 #endif 486