1 /* 2 * Copyright 2011-2012 Freescale Semiconductor, Inc. 3 * 4 * See file CREDITS for list of people who contributed to this 5 * project. 6 * 7 * This program is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU General Public License as 9 * published by the Free Software Foundation; either version 2 of 10 * the License, or (at your option) any later version. 11 * 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with this program; if not, write to the Free Software 19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 20 * MA 02111-1307 USA 21 */ 22 23 #include <common.h> 24 #include <command.h> 25 #include <i2c.h> 26 #include <netdev.h> 27 #include <linux/compiler.h> 28 #include <asm/mmu.h> 29 #include <asm/processor.h> 30 #include <asm/cache.h> 31 #include <asm/immap_85xx.h> 32 #include <asm/fsl_law.h> 33 #include <asm/fsl_serdes.h> 34 #include <asm/fsl_portals.h> 35 #include <asm/fsl_liodn.h> 36 #include <fm_eth.h> 37 38 #include "../common/qixis.h" 39 #include "../common/vsc3316_3308.h" 40 #include "b4860qds.h" 41 #include "b4860qds_qixis.h" 42 #include "b4860qds_crossbar_con.h" 43 44 #define CLK_MUX_SEL_MASK 0x4 45 #define ETH_PHY_CLK_OUT 0x4 46 47 DECLARE_GLOBAL_DATA_PTR; 48 49 int checkboard(void) 50 { 51 char buf[64]; 52 u8 sw; 53 struct cpu_type *cpu = gd->arch.cpu; 54 ccsr_gur_t *gur = (void *)CONFIG_SYS_MPC85xx_GUTS_ADDR; 55 unsigned int i; 56 static const char *const freq[] = {"100", "125", "156.25", "161.13", 57 "122.88", "122.88", "122.88"}; 58 int clock; 59 60 printf("Board: %sQDS, ", cpu->name); 61 printf("Sys ID: 0x%02x, Sys Ver: 0x%02x, ", 62 QIXIS_READ(id), QIXIS_READ(arch)); 63 64 sw = QIXIS_READ(brdcfg[0]); 65 sw = (sw & QIXIS_LBMAP_MASK) >> QIXIS_LBMAP_SHIFT; 66 67 if (sw < 0x8) 68 printf("vBank: %d\n", sw); 69 else if (sw >= 0x8 && sw <= 0xE) 70 puts("NAND\n"); 71 else 72 printf("invalid setting of SW%u\n", QIXIS_LBMAP_SWITCH); 73 74 printf("FPGA: v%d (%s), build %d", 75 (int)QIXIS_READ(scver), qixis_read_tag(buf), 76 (int)qixis_read_minor()); 77 /* the timestamp string contains "\n" at the end */ 78 printf(" on %s", qixis_read_time(buf)); 79 80 /* Display the RCW, so that no one gets confused as to what RCW 81 * we're actually using for this boot. 82 */ 83 puts("Reset Configuration Word (RCW):"); 84 for (i = 0; i < ARRAY_SIZE(gur->rcwsr); i++) { 85 u32 rcw = in_be32(&gur->rcwsr[i]); 86 87 if ((i % 4) == 0) 88 printf("\n %08x:", i * 4); 89 printf(" %08x", rcw); 90 } 91 puts("\n"); 92 93 /* 94 * Display the actual SERDES reference clocks as configured by the 95 * dip switches on the board. Note that the SWx registers could 96 * technically be set to force the reference clocks to match the 97 * values that the SERDES expects (or vice versa). For now, however, 98 * we just display both values and hope the user notices when they 99 * don't match. 100 */ 101 puts("SERDES Reference Clocks: "); 102 sw = QIXIS_READ(brdcfg[2]); 103 clock = (sw >> 5) & 7; 104 printf("Bank1=%sMHz ", freq[clock]); 105 sw = QIXIS_READ(brdcfg[4]); 106 clock = (sw >> 6) & 3; 107 printf("Bank2=%sMHz\n", freq[clock]); 108 109 return 0; 110 } 111 112 int select_i2c_ch_pca(u8 ch) 113 { 114 int ret; 115 116 /* Selecting proper channel via PCA*/ 117 ret = i2c_write(I2C_MUX_PCA_ADDR, 0x0, 1, &ch, 1); 118 if (ret) { 119 printf("PCA: failed to select proper channel.\n"); 120 return ret; 121 } 122 123 return 0; 124 } 125 126 int configure_vsc3316_3308(void) 127 { 128 ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR); 129 unsigned int num_vsc16_con, num_vsc08_con; 130 u32 serdes1_prtcl, serdes2_prtcl; 131 int ret; 132 133 serdes1_prtcl = in_be32(&gur->rcwsr[4]) & 134 FSL_CORENET2_RCWSR4_SRDS1_PRTCL; 135 if (!serdes1_prtcl) { 136 printf("SERDES1 is not enabled\n"); 137 return 0; 138 } 139 serdes1_prtcl >>= FSL_CORENET2_RCWSR4_SRDS1_PRTCL_SHIFT; 140 debug("Using SERDES1 Protocol: 0x%x:\n", serdes1_prtcl); 141 142 serdes2_prtcl = in_be32(&gur->rcwsr[4]) & 143 FSL_CORENET2_RCWSR4_SRDS2_PRTCL; 144 if (!serdes2_prtcl) { 145 printf("SERDES2 is not enabled\n"); 146 return 0; 147 } 148 serdes2_prtcl >>= FSL_CORENET2_RCWSR4_SRDS2_PRTCL_SHIFT; 149 debug("Using SERDES2 Protocol: 0x%x:\n", serdes2_prtcl); 150 151 switch (serdes1_prtcl) { 152 case 0x2a: 153 case 0x2C: 154 case 0x2D: 155 case 0x2E: 156 /* 157 * Configuration: 158 * SERDES: 1 159 * Lanes: A,B: SGMII 160 * Lanes: C,D,E,F,G,H: CPRI 161 */ 162 debug("Configuring crossbar to use onboard SGMII PHYs:" 163 "srds_prctl:%x\n", serdes1_prtcl); 164 num_vsc16_con = NUM_CON_VSC3316; 165 /* Configure VSC3316 crossbar switch */ 166 ret = select_i2c_ch_pca(I2C_CH_VSC3316); 167 if (!ret) { 168 ret = vsc3316_config(VSC3316_TX_ADDRESS, 169 vsc16_tx_sgmii_lane_ab, num_vsc16_con); 170 if (ret) 171 return ret; 172 ret = vsc3316_config(VSC3316_RX_ADDRESS, 173 vsc16_rx_sgmii_lane_ab, num_vsc16_con); 174 if (ret) 175 return ret; 176 } else { 177 return ret; 178 } 179 break; 180 181 #ifdef CONFIG_PPC_B4420 182 case 0x18: 183 /* 184 * Configuration: 185 * SERDES: 1 186 * Lanes: A,B,C,D: SGMII 187 * Lanes: E,F,G,H: CPRI 188 */ 189 debug("Configuring crossbar to use onboard SGMII PHYs:" 190 "srds_prctl:%x\n", serdes1_prtcl); 191 num_vsc16_con = NUM_CON_VSC3316; 192 /* Configure VSC3316 crossbar switch */ 193 ret = select_i2c_ch_pca(I2C_CH_VSC3316); 194 if (!ret) { 195 ret = vsc3316_config(VSC3316_TX_ADDRESS, 196 vsc16_tx_sgmii_lane_cd, num_vsc16_con); 197 if (ret) 198 return ret; 199 ret = vsc3316_config(VSC3316_RX_ADDRESS, 200 vsc16_rx_sgmii_lane_cd, num_vsc16_con); 201 if (ret) 202 return ret; 203 } else { 204 return ret; 205 } 206 break; 207 #endif 208 209 case 0x3E: 210 case 0x0D: 211 case 0x0E: 212 case 0x12: 213 num_vsc16_con = NUM_CON_VSC3316; 214 /* Configure VSC3316 crossbar switch */ 215 ret = select_i2c_ch_pca(I2C_CH_VSC3316); 216 if (!ret) { 217 ret = vsc3316_config(VSC3316_TX_ADDRESS, 218 vsc16_tx_sfp, num_vsc16_con); 219 if (ret) 220 return ret; 221 ret = vsc3316_config(VSC3316_RX_ADDRESS, 222 vsc16_rx_sfp, num_vsc16_con); 223 if (ret) 224 return ret; 225 } else { 226 return ret; 227 } 228 break; 229 default: 230 printf("WARNING:VSC crossbars programming not supported for:%x" 231 " SerDes1 Protocol.\n", serdes1_prtcl); 232 return -1; 233 } 234 235 switch (serdes2_prtcl) { 236 case 0x9E: 237 case 0x9A: 238 case 0x98: 239 case 0xb2: 240 case 0x49: 241 case 0x4E: 242 case 0x8D: 243 case 0x7A: 244 num_vsc08_con = NUM_CON_VSC3308; 245 /* Configure VSC3308 crossbar switch */ 246 ret = select_i2c_ch_pca(I2C_CH_VSC3308); 247 if (!ret) { 248 ret = vsc3308_config(VSC3308_TX_ADDRESS, 249 vsc08_tx_amc, num_vsc08_con); 250 if (ret) 251 return ret; 252 ret = vsc3308_config(VSC3308_RX_ADDRESS, 253 vsc08_rx_amc, num_vsc08_con); 254 if (ret) 255 return ret; 256 } else { 257 return ret; 258 } 259 break; 260 default: 261 printf("WARNING:VSC crossbars programming not supported for: %x" 262 " SerDes2 Protocol.\n", serdes2_prtcl); 263 return -1; 264 } 265 266 return 0; 267 } 268 269 int board_early_init_r(void) 270 { 271 const unsigned int flashbase = CONFIG_SYS_FLASH_BASE; 272 const u8 flash_esel = find_tlb_idx((void *)flashbase, 1); 273 274 /* 275 * Remap Boot flash + PROMJET region to caching-inhibited 276 * so that flash can be erased properly. 277 */ 278 279 /* Flush d-cache and invalidate i-cache of any FLASH data */ 280 flush_dcache(); 281 invalidate_icache(); 282 283 /* invalidate existing TLB entry for flash + promjet */ 284 disable_tlb(flash_esel); 285 286 set_tlb(1, flashbase, CONFIG_SYS_FLASH_BASE_PHYS, 287 MAS3_SX|MAS3_SW|MAS3_SR, MAS2_I|MAS2_G, 288 0, flash_esel, BOOKE_PAGESZ_256M, 1); 289 290 set_liodns(); 291 #ifdef CONFIG_SYS_DPAA_QBMAN 292 setup_portals(); 293 #endif 294 295 /* Configure VSC3316 and VSC3308 crossbar switches */ 296 if (configure_vsc3316_3308()) 297 printf("VSC:failed to configure VSC3316/3308.\n"); 298 else 299 printf("VSC:VSC3316/3308 successfully configured.\n"); 300 301 select_i2c_ch_pca(I2C_CH_DEFAULT); 302 303 return 0; 304 } 305 306 unsigned long get_board_sys_clk(void) 307 { 308 u8 sysclk_conf = QIXIS_READ(brdcfg[1]); 309 310 switch ((sysclk_conf & 0x0C) >> 2) { 311 case QIXIS_CLK_100: 312 return 100000000; 313 case QIXIS_CLK_125: 314 return 125000000; 315 case QIXIS_CLK_133: 316 return 133333333; 317 } 318 return 66666666; 319 } 320 321 unsigned long get_board_ddr_clk(void) 322 { 323 u8 ddrclk_conf = QIXIS_READ(brdcfg[1]); 324 325 switch (ddrclk_conf & 0x03) { 326 case QIXIS_CLK_100: 327 return 100000000; 328 case QIXIS_CLK_125: 329 return 125000000; 330 case QIXIS_CLK_133: 331 return 133333333; 332 } 333 return 66666666; 334 } 335 336 static int serdes_refclock(u8 sw, u8 sdclk) 337 { 338 unsigned int clock; 339 int ret = -1; 340 u8 brdcfg4; 341 342 if (sdclk == 1) { 343 brdcfg4 = QIXIS_READ(brdcfg[4]); 344 if ((brdcfg4 & CLK_MUX_SEL_MASK) == ETH_PHY_CLK_OUT) 345 return SRDS_PLLCR0_RFCK_SEL_125; 346 else 347 clock = (sw >> 5) & 7; 348 } else 349 clock = (sw >> 6) & 3; 350 351 switch (clock) { 352 case 0: 353 ret = SRDS_PLLCR0_RFCK_SEL_100; 354 break; 355 case 1: 356 ret = SRDS_PLLCR0_RFCK_SEL_125; 357 break; 358 case 2: 359 ret = SRDS_PLLCR0_RFCK_SEL_156_25; 360 break; 361 case 3: 362 ret = SRDS_PLLCR0_RFCK_SEL_161_13; 363 break; 364 case 4: 365 case 5: 366 case 6: 367 ret = SRDS_PLLCR0_RFCK_SEL_122_88; 368 break; 369 default: 370 ret = -1; 371 break; 372 } 373 374 return ret; 375 } 376 377 static const char *serdes_clock_to_string(u32 clock) 378 { 379 switch (clock) { 380 case SRDS_PLLCR0_RFCK_SEL_100: 381 return "100"; 382 case SRDS_PLLCR0_RFCK_SEL_125: 383 return "125"; 384 case SRDS_PLLCR0_RFCK_SEL_156_25: 385 return "156.25"; 386 case SRDS_PLLCR0_RFCK_SEL_161_13: 387 return "161.13"; 388 default: 389 return "122.88"; 390 } 391 } 392 393 #define NUM_SRDS_BANKS 2 394 395 int misc_init_r(void) 396 { 397 u8 sw; 398 serdes_corenet_t *srds_regs = 399 (void *)CONFIG_SYS_FSL_CORENET_SERDES_ADDR; 400 u32 actual[NUM_SRDS_BANKS]; 401 unsigned int i; 402 int clock; 403 404 sw = QIXIS_READ(brdcfg[2]); 405 clock = serdes_refclock(sw, 1); 406 if (clock >= 0) 407 actual[0] = clock; 408 else 409 printf("Warning: SDREFCLK1 switch setting is unsupported\n"); 410 411 sw = QIXIS_READ(brdcfg[4]); 412 clock = serdes_refclock(sw, 2); 413 if (clock >= 0) 414 actual[1] = clock; 415 else 416 printf("Warning: SDREFCLK2 switch setting unsupported\n"); 417 418 for (i = 0; i < NUM_SRDS_BANKS; i++) { 419 u32 pllcr0 = srds_regs->bank[i].pllcr0; 420 u32 expected = pllcr0 & SRDS_PLLCR0_RFCK_SEL_MASK; 421 if (expected != actual[i]) { 422 printf("Warning: SERDES bank %u expects reference clock" 423 " %sMHz, but actual is %sMHz\n", i + 1, 424 serdes_clock_to_string(expected), 425 serdes_clock_to_string(actual[i])); 426 } 427 } 428 429 return 0; 430 } 431 432 void ft_board_setup(void *blob, bd_t *bd) 433 { 434 phys_addr_t base; 435 phys_size_t size; 436 437 ft_cpu_setup(blob, bd); 438 439 base = getenv_bootm_low(); 440 size = getenv_bootm_size(); 441 442 fdt_fixup_memory(blob, (u64)base, (u64)size); 443 444 #ifdef CONFIG_PCI 445 pci_of_setup(blob, bd); 446 #endif 447 448 fdt_fixup_liodn(blob); 449 450 #ifdef CONFIG_HAS_FSL_DR_USB 451 fdt_fixup_dr_usb(blob, bd); 452 #endif 453 454 #ifdef CONFIG_SYS_DPAA_FMAN 455 fdt_fixup_fman_ethernet(blob); 456 fdt_fixup_board_enet(blob); 457 #endif 458 } 459 460 /* 461 * Dump board switch settings. 462 * The bits that cannot be read/sampled via some FPGA or some 463 * registers, they will be displayed as 464 * underscore in binary format. mask[] has those bits. 465 * Some bits are calculated differently than the actual switches 466 * if booting with overriding by FPGA. 467 */ 468 void qixis_dump_switch(void) 469 { 470 int i; 471 u8 sw[5]; 472 473 /* 474 * Any bit with 1 means that bit cannot be reverse engineered. 475 * It will be displayed as _ in binary format. 476 */ 477 static const u8 mask[] = {0x07, 0, 0, 0xff, 0}; 478 char buf[10]; 479 u8 brdcfg[16], dutcfg[16]; 480 481 for (i = 0; i < 16; i++) { 482 brdcfg[i] = qixis_read(offsetof(struct qixis, brdcfg[0]) + i); 483 dutcfg[i] = qixis_read(offsetof(struct qixis, dutcfg[0]) + i); 484 } 485 486 sw[0] = ((brdcfg[0] & 0x0f) << 4) | \ 487 (brdcfg[9] & 0x08); 488 sw[1] = ((dutcfg[1] & 0x01) << 7) | \ 489 ((dutcfg[2] & 0x07) << 4) | \ 490 ((dutcfg[6] & 0x10) >> 1) | \ 491 ((dutcfg[6] & 0x80) >> 5) | \ 492 ((dutcfg[1] & 0x40) >> 5) | \ 493 (dutcfg[6] & 0x01); 494 sw[2] = dutcfg[0]; 495 sw[3] = 0; 496 sw[4] = ((brdcfg[1] & 0x30) << 2) | \ 497 ((brdcfg[1] & 0xc0) >> 2) | \ 498 (brdcfg[1] & 0x0f); 499 500 puts("DIP switch settings:\n"); 501 for (i = 0; i < 5; i++) { 502 printf("SW%d = 0b%s (0x%02x)\n", 503 i + 1, byte_to_binary_mask(sw[i], mask[i], buf), sw[i]); 504 } 505 } 506