X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=board%2Ffreescale%2Fb4860qds%2Fb4860qds.c;h=bed8f56be43a0adb187e7bd87cdede01b89d6b1f;hb=36da51ebacdc549b9d034a9241b6d88b06a951c5;hp=25b3be8663690806e18aff4923278b0afef5dc76;hpb=c7d506d4ee477368d54f226065416648be08a60d;p=u-boot diff --git a/board/freescale/b4860qds/b4860qds.c b/board/freescale/b4860qds/b4860qds.c index 25b3be8663..bed8f56be4 100644 --- a/board/freescale/b4860qds/b4860qds.c +++ b/board/freescale/b4860qds/b4860qds.c @@ -23,13 +23,13 @@ #include "../common/qixis.h" #include "../common/vsc3316_3308.h" #include "../common/idt8t49n222a_serdes_clk.h" +#include "../common/zm7300.h" #include "b4860qds.h" #include "b4860qds_qixis.h" #include "b4860qds_crossbar_con.h" #define CLK_MUX_SEL_MASK 0x4 #define ETH_PHY_CLK_OUT 0x4 -#define PLL_NUM 2 DECLARE_GLOBAL_DATA_PTR; @@ -95,6 +95,238 @@ int select_i2c_ch_pca(u8 ch) return 0; } +/* + * read_voltage from sensor on I2C bus + * We use average of 4 readings, waiting for 532us befor another reading + */ +#define WAIT_FOR_ADC 532 /* wait for 532 microseconds for ADC */ +#define NUM_READINGS 4 /* prefer to be power of 2 for efficiency */ + +static inline int read_voltage(void) +{ + int i, ret, voltage_read = 0; + u16 vol_mon; + + for (i = 0; i < NUM_READINGS; i++) { + ret = i2c_read(I2C_VOL_MONITOR_ADDR, + I2C_VOL_MONITOR_BUS_V_OFFSET, 1, (void *)&vol_mon, 2); + if (ret) { + printf("VID: failed to read core voltage\n"); + return ret; + } + if (vol_mon & I2C_VOL_MONITOR_BUS_V_OVF) { + printf("VID: Core voltage sensor error\n"); + return -1; + } + debug("VID: bus voltage reads 0x%04x\n", vol_mon); + /* LSB = 4mv */ + voltage_read += (vol_mon >> I2C_VOL_MONITOR_BUS_V_SHIFT) * 4; + udelay(WAIT_FOR_ADC); + } + /* calculate the average */ + voltage_read /= NUM_READINGS; + + return voltage_read; +} + +static int adjust_vdd(ulong vdd_override) +{ + int re_enable = disable_interrupts(); + ccsr_gur_t __iomem *gur = + (void __iomem *)(CONFIG_SYS_MPC85xx_GUTS_ADDR); + u32 fusesr; + u8 vid; + int vdd_target, vdd_last; + int existing_voltage, temp_voltage, voltage; /* all in 1/10 mV */ + int ret; + unsigned int orig_i2c_speed; + unsigned long vdd_string_override; + char *vdd_string; + static const uint16_t vdd[32] = { + 0, /* unused */ + 9875, /* 0.9875V */ + 9750, + 9625, + 9500, + 9375, + 9250, + 9125, + 9000, + 8875, + 8750, + 8625, + 8500, + 8375, + 8250, + 8125, + 10000, /* 1.0000V */ + 10125, + 10250, + 10375, + 10500, + 10625, + 10750, + 10875, + 11000, + 0, /* reserved */ + }; + struct vdd_drive { + u8 vid; + unsigned voltage; + }; + + ret = select_i2c_ch_pca(I2C_MUX_CH_VOL_MONITOR); + if (ret) { + printf("VID: I2c failed to switch channel\n"); + ret = -1; + goto exit; + } + + /* get the voltage ID from fuse status register */ + fusesr = in_be32(&gur->dcfg_fusesr); + vid = (fusesr >> FSL_CORENET_DCFG_FUSESR_VID_SHIFT) & + FSL_CORENET_DCFG_FUSESR_VID_MASK; + if (vid == FSL_CORENET_DCFG_FUSESR_VID_MASK) { + vid = (fusesr >> FSL_CORENET_DCFG_FUSESR_ALTVID_SHIFT) & + FSL_CORENET_DCFG_FUSESR_ALTVID_MASK; + } + vdd_target = vdd[vid]; + debug("VID:Reading from from fuse,vid=%x vdd is %dmV\n", + vid, vdd_target/10); + + /* check override variable for overriding VDD */ + vdd_string = getenv("b4qds_vdd_mv"); + if (vdd_override == 0 && vdd_string && + !strict_strtoul(vdd_string, 10, &vdd_string_override)) + vdd_override = vdd_string_override; + if (vdd_override >= 819 && vdd_override <= 1212) { + vdd_target = vdd_override * 10; /* convert to 1/10 mV */ + debug("VDD override is %lu\n", vdd_override); + } else if (vdd_override != 0) { + printf("Invalid value.\n"); + } + + if (vdd_target == 0) { + printf("VID: VID not used\n"); + ret = 0; + goto exit; + } + + /* + * Read voltage monitor to check real voltage. + * Voltage monitor LSB is 4mv. + */ + vdd_last = read_voltage(); + if (vdd_last < 0) { + printf("VID: abort VID adjustment\n"); + ret = -1; + goto exit; + } + + debug("VID: Core voltage is at %d mV\n", vdd_last); + ret = select_i2c_ch_pca(I2C_MUX_CH_DPM); + if (ret) { + printf("VID: I2c failed to switch channel to DPM\n"); + ret = -1; + goto exit; + } + + /* Round up to the value of step of Voltage regulator */ + voltage = roundup(vdd_target, ZM_STEP); + debug("VID: rounded up voltage = %d\n", voltage); + + /* lower the speed to 100kHz to access ZM7300 device */ + debug("VID: Setting bus speed to 100KHz if not already set\n"); + orig_i2c_speed = i2c_get_bus_speed(); + if (orig_i2c_speed != 100000) + i2c_set_bus_speed(100000); + + /* Read the existing level on board, if equal to requsted one, + no need to re-set */ + existing_voltage = zm_read_voltage(); + + /* allowing the voltage difference of one step 0.0125V acceptable */ + if ((existing_voltage >= voltage) && + (existing_voltage < (voltage + ZM_STEP))) { + debug("VID: voltage already set as requested,returning\n"); + ret = existing_voltage; + goto out; + } + debug("VID: Changing voltage for board from %dmV to %dmV\n", + existing_voltage/10, voltage/10); + + if (zm_disable_wp() < 0) { + ret = -1; + goto out; + } + /* Change Voltage: the change is done through all the steps in the + way, to avoid reset to the board due to power good signal fail + in big voltage change gap jump. + */ + if (existing_voltage > voltage) { + temp_voltage = existing_voltage - ZM_STEP; + while (temp_voltage >= voltage) { + ret = zm_write_voltage(temp_voltage); + if (ret == temp_voltage) { + temp_voltage -= ZM_STEP; + } else { + /* ZM7300 device failed to set + * the voltage */ + printf + ("VID:Stepping down vol failed:%dmV\n", + temp_voltage/10); + ret = -1; + goto out; + } + } + } else { + temp_voltage = existing_voltage + ZM_STEP; + while (temp_voltage < (voltage + ZM_STEP)) { + ret = zm_write_voltage(temp_voltage); + if (ret == temp_voltage) { + temp_voltage += ZM_STEP; + } else { + /* ZM7300 device failed to set + * the voltage */ + printf + ("VID:Stepping up vol failed:%dmV\n", + temp_voltage/10); + ret = -1; + goto out; + } + } + } + + if (zm_enable_wp() < 0) + ret = -1; + + /* restore the speed to 400kHz */ +out: debug("VID: Restore the I2C bus speed to %dKHz\n", + orig_i2c_speed/1000); + i2c_set_bus_speed(orig_i2c_speed); + if (ret < 0) + goto exit; + + ret = select_i2c_ch_pca(I2C_MUX_CH_VOL_MONITOR); + if (ret) { + printf("VID: I2c failed to switch channel\n"); + ret = -1; + goto exit; + } + vdd_last = read_voltage(); + select_i2c_ch_pca(I2C_CH_DEFAULT); + + if (vdd_last > 0) + printf("VID: Core voltage %d mV\n", vdd_last); + else + ret = -1; + +exit: + if (re_enable) + enable_interrupts(); + return ret; +} + int configure_vsc3316_3308(void) { ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR); @@ -256,6 +488,9 @@ int configure_vsc3316_3308(void) } switch (serdes2_prtcl) { +#ifdef CONFIG_PPC_B4420 + case 0x9d: +#endif case 0x9E: case 0x9A: case 0x98: @@ -289,6 +524,182 @@ int configure_vsc3316_3308(void) return 0; } +static int calibrate_pll(serdes_corenet_t *srds_regs, int pll_num) +{ + u32 rst_err; + + /* Steps For SerDes PLLs reset and reconfiguration + * or PLL power-up procedure + */ + debug("CALIBRATE PLL:%d\n", pll_num); + clrbits_be32(&srds_regs->bank[pll_num].rstctl, + SRDS_RSTCTL_SDRST_B); + udelay(10); + clrbits_be32(&srds_regs->bank[pll_num].rstctl, + (SRDS_RSTCTL_SDEN | SRDS_RSTCTL_PLLRST_B)); + udelay(10); + setbits_be32(&srds_regs->bank[pll_num].rstctl, + SRDS_RSTCTL_RST); + setbits_be32(&srds_regs->bank[pll_num].rstctl, + (SRDS_RSTCTL_SDEN | SRDS_RSTCTL_PLLRST_B + | SRDS_RSTCTL_SDRST_B)); + + udelay(20); + + /* Check whether PLL has been locked or not */ + rst_err = in_be32(&srds_regs->bank[pll_num].rstctl) & + SRDS_RSTCTL_RSTERR; + rst_err >>= SRDS_RSTCTL_RSTERR_SHIFT; + debug("RST_ERR value for PLL %d is: 0x%x:\n", pll_num, rst_err); + if (rst_err) + return rst_err; + + return rst_err; +} + +static int check_pll_locks(serdes_corenet_t *srds_regs, int pll_num) +{ + int ret = 0; + u32 fcap, dcbias, bcap, pllcr1, pllcr0; + + if (calibrate_pll(srds_regs, pll_num)) { + /* STEP 1 */ + /* Read fcap, dcbias and bcap value */ + clrbits_be32(&srds_regs->bank[pll_num].pllcr0, + SRDS_PLLCR0_DCBIAS_OUT_EN); + fcap = in_be32(&srds_regs->bank[pll_num].pllsr2) & + SRDS_PLLSR2_FCAP; + fcap >>= SRDS_PLLSR2_FCAP_SHIFT; + bcap = in_be32(&srds_regs->bank[pll_num].pllsr2) & + SRDS_PLLSR2_BCAP_EN; + bcap >>= SRDS_PLLSR2_BCAP_EN_SHIFT; + setbits_be32(&srds_regs->bank[pll_num].pllcr0, + SRDS_PLLCR0_DCBIAS_OUT_EN); + dcbias = in_be32(&srds_regs->bank[pll_num].pllsr2) & + SRDS_PLLSR2_DCBIAS; + dcbias >>= SRDS_PLLSR2_DCBIAS_SHIFT; + debug("values of bcap:%x, fcap:%x and dcbias:%x\n", + bcap, fcap, dcbias); + if (fcap == 0 && bcap == 1) { + /* Step 3 */ + clrbits_be32(&srds_regs->bank[pll_num].rstctl, + (SRDS_RSTCTL_SDEN | SRDS_RSTCTL_PLLRST_B + | SRDS_RSTCTL_SDRST_B)); + clrbits_be32(&srds_regs->bank[pll_num].pllcr1, + SRDS_PLLCR1_BCAP_EN); + setbits_be32(&srds_regs->bank[pll_num].pllcr1, + SRDS_PLLCR1_BCAP_OVD); + if (calibrate_pll(srds_regs, pll_num)) { + /*save the fcap, dcbias and bcap values*/ + clrbits_be32(&srds_regs->bank[pll_num].pllcr0, + SRDS_PLLCR0_DCBIAS_OUT_EN); + fcap = in_be32(&srds_regs->bank[pll_num].pllsr2) + & SRDS_PLLSR2_FCAP; + fcap >>= SRDS_PLLSR2_FCAP_SHIFT; + bcap = in_be32(&srds_regs->bank[pll_num].pllsr2) + & SRDS_PLLSR2_BCAP_EN; + bcap >>= SRDS_PLLSR2_BCAP_EN_SHIFT; + setbits_be32(&srds_regs->bank[pll_num].pllcr0, + SRDS_PLLCR0_DCBIAS_OUT_EN); + dcbias = in_be32 + (&srds_regs->bank[pll_num].pllsr2) & + SRDS_PLLSR2_DCBIAS; + dcbias >>= SRDS_PLLSR2_DCBIAS_SHIFT; + + /* Step 4*/ + clrbits_be32(&srds_regs->bank[pll_num].rstctl, + (SRDS_RSTCTL_SDEN | SRDS_RSTCTL_PLLRST_B + | SRDS_RSTCTL_SDRST_B)); + setbits_be32(&srds_regs->bank[pll_num].pllcr1, + SRDS_PLLCR1_BYP_CAL); + clrbits_be32(&srds_regs->bank[pll_num].pllcr1, + SRDS_PLLCR1_BCAP_EN); + setbits_be32(&srds_regs->bank[pll_num].pllcr1, + SRDS_PLLCR1_BCAP_OVD); + /* change the fcap and dcbias to the saved + * values from Step 3 */ + clrbits_be32(&srds_regs->bank[pll_num].pllcr1, + SRDS_PLLCR1_PLL_FCAP); + pllcr1 = (in_be32 + (&srds_regs->bank[pll_num].pllcr1)| + (fcap << SRDS_PLLCR1_PLL_FCAP_SHIFT)); + out_be32(&srds_regs->bank[pll_num].pllcr1, + pllcr1); + clrbits_be32(&srds_regs->bank[pll_num].pllcr0, + SRDS_PLLCR0_DCBIAS_OVRD); + pllcr0 = (in_be32 + (&srds_regs->bank[pll_num].pllcr0)| + (dcbias << SRDS_PLLCR0_DCBIAS_OVRD_SHIFT)); + out_be32(&srds_regs->bank[pll_num].pllcr0, + pllcr0); + ret = calibrate_pll(srds_regs, pll_num); + if (ret) + return ret; + } else { + goto out; + } + } else { /* Step 5 */ + clrbits_be32(&srds_regs->bank[pll_num].rstctl, + (SRDS_RSTCTL_SDEN | SRDS_RSTCTL_PLLRST_B + | SRDS_RSTCTL_SDRST_B)); + udelay(10); + /* Change the fcap, dcbias, and bcap to the + * values from Step 1 */ + setbits_be32(&srds_regs->bank[pll_num].pllcr1, + SRDS_PLLCR1_BYP_CAL); + clrbits_be32(&srds_regs->bank[pll_num].pllcr1, + SRDS_PLLCR1_PLL_FCAP); + pllcr1 = (in_be32(&srds_regs->bank[pll_num].pllcr1)| + (fcap << SRDS_PLLCR1_PLL_FCAP_SHIFT)); + out_be32(&srds_regs->bank[pll_num].pllcr1, + pllcr1); + clrbits_be32(&srds_regs->bank[pll_num].pllcr0, + SRDS_PLLCR0_DCBIAS_OVRD); + pllcr0 = (in_be32(&srds_regs->bank[pll_num].pllcr0)| + (dcbias << SRDS_PLLCR0_DCBIAS_OVRD_SHIFT)); + out_be32(&srds_regs->bank[pll_num].pllcr0, + pllcr0); + clrbits_be32(&srds_regs->bank[pll_num].pllcr1, + SRDS_PLLCR1_BCAP_EN); + setbits_be32(&srds_regs->bank[pll_num].pllcr1, + SRDS_PLLCR1_BCAP_OVD); + ret = calibrate_pll(srds_regs, pll_num); + if (ret) + return ret; + } + } +out: + return 0; +} + +static int check_serdes_pll_locks(void) +{ + serdes_corenet_t *srds1_regs = + (void *)CONFIG_SYS_FSL_CORENET_SERDES_ADDR; + serdes_corenet_t *srds2_regs = + (void *)CONFIG_SYS_FSL_CORENET_SERDES2_ADDR; + int i, ret1, ret2; + + debug("\nSerDes1 Lock check\n"); + for (i = 0; i < CONFIG_SYS_FSL_SRDS_NUM_PLLS; i++) { + ret1 = check_pll_locks(srds1_regs, i); + if (ret1) { + printf("SerDes1, PLL:%d didnt lock\n", i); + return ret1; + } + } + debug("\nSerDes2 Lock check\n"); + for (i = 0; i < CONFIG_SYS_FSL_SRDS_NUM_PLLS; i++) { + ret2 = check_pll_locks(srds2_regs, i); + if (ret2) { + printf("SerDes2, PLL:%d didnt lock\n", i); + return ret2; + } + } + + return 0; +} + int config_serdes1_refclks(void) { ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR); @@ -386,7 +797,7 @@ int config_serdes1_refclks(void) /* Steps For SerDes PLLs reset and reconfiguration after * changing SerDes's refclks */ - for (i = 0; i < PLL_NUM; i++) { + for (i = 0; i < CONFIG_SYS_FSL_SRDS_NUM_PLLS; i++) { debug("For PLL%d reset and reconfiguration after" " changing refclks\n", i+1); clrbits_be32(&srds_regs->bank[i].rstctl, @@ -444,6 +855,9 @@ int config_serdes2_refclks(void) * For this SerDes2's Refclk1 need to be set to 100MHz */ switch (serdes2_prtcl) { +#ifdef CONFIG_PPC_B4420 + case 0x9d: +#endif case 0x9E: case 0x9A: case 0xb2: @@ -453,7 +867,7 @@ int config_serdes2_refclks(void) if (!ret) { ret = set_serdes_refclk(IDT_SERDES2_ADDRESS, 2, SERDES_REFCLK_100, - SERDES_REFCLK_100, 0); + SERDES_REFCLK_156_25, 0); if (ret) { printf("IDT8T49N222A configuration failed.\n"); goto out; @@ -467,7 +881,7 @@ int config_serdes2_refclks(void) /* Steps For SerDes PLLs reset and reconfiguration after * changing SerDes's refclks */ - for (i = 0; i < PLL_NUM; i++) { + for (i = 0; i < CONFIG_SYS_FSL_SRDS_NUM_PLLS; i++) { clrbits_be32(&srds2_regs->bank[i].rstctl, SRDS_RSTCTL_SDRST_B); udelay(10); @@ -479,6 +893,8 @@ int config_serdes2_refclks(void) setbits_be32(&srds2_regs->bank[i].rstctl, (SRDS_RSTCTL_SDEN | SRDS_RSTCTL_PLLRST_B | SRDS_RSTCTL_SDRST_B)); + + udelay(10); } break; default: @@ -497,7 +913,7 @@ out: int board_early_init_r(void) { const unsigned int flashbase = CONFIG_SYS_FLASH_BASE; - const u8 flash_esel = find_tlb_idx((void *)flashbase, 1); + int flash_esel = find_tlb_idx((void *)flashbase, 1); int ret; /* @@ -509,8 +925,14 @@ int board_early_init_r(void) flush_dcache(); invalidate_icache(); - /* invalidate existing TLB entry for flash + promjet */ - disable_tlb(flash_esel); + if (flash_esel == -1) { + /* very unlikely unless something is messed up */ + puts("Error: Could not find TLB for FLASH BASE\n"); + flash_esel = 2; /* give our best effort to continue */ + } else { + /* invalidate existing TLB entry for flash + promjet */ + disable_tlb(flash_esel); + } set_tlb(1, flashbase, CONFIG_SYS_FLASH_BASE_PHYS, MAS3_SX|MAS3_SW|MAS3_SR, MAS2_I|MAS2_G, @@ -520,6 +942,13 @@ int board_early_init_r(void) #ifdef CONFIG_SYS_DPAA_QBMAN setup_portals(); #endif + /* + * Adjust core voltage according to voltage ID + * This function changes I2C mux to channel 2. + */ + if (adjust_vdd(0) < 0) + printf("Warning: Adjusting core voltage failed\n"); + /* SerDes1 refclks need to be set again, as default clks * are not suitable for CPRI and onboard SGMIIs to work * simultaneously. @@ -545,6 +974,21 @@ int board_early_init_r(void) else printf("SerDes2 Refclk reconfiguring failed.\n"); +#if defined(CONFIG_SYS_FSL_ERRATUM_A006384) || \ + defined(CONFIG_SYS_FSL_ERRATUM_A006475) + /* Rechecking the SerDes locks after all SerDes configurations + * are done, As SerDes PLLs may not lock reliably at 5 G VCO + * and at cold temperatures. + * Following sequence ensure the proper locking of SerDes PLLs. + */ + if (SVR_MAJ(get_svr()) == 1) { + if (check_serdes_pll_locks()) + printf("SerDes plls still not locked properly.\n"); + else + printf("SerDes plls have been locked well.\n"); + } +#endif + /* Configure VSC3316 and VSC3308 crossbar switches */ if (configure_vsc3316_3308()) printf("VSC:failed to configure VSC3316/3308.\n"); @@ -666,7 +1110,7 @@ int misc_init_r(void) return 0; } -void ft_board_setup(void *blob, bd_t *bd) +int ft_board_setup(void *blob, bd_t *bd) { phys_addr_t base; phys_size_t size; @@ -692,6 +1136,8 @@ void ft_board_setup(void *blob, bd_t *bd) fdt_fixup_fman_ethernet(blob); fdt_fixup_board_enet(blob); #endif + + return 0; } /*