@ -132,6 +132,228 @@ int select_i2c_ch_pca9547(u8 ch)
return 0 ;
return 0 ;
}
}
/*
* read_voltage from sensor on I2C bus
* We use average of 4 readings , waiting for 532u s befor another reading
*/
# define NUM_READINGS 4 /* prefer to be power of 2 for efficiency */
# define WAIT_FOR_ADC 532 /* wait for 532 microseconds for ADC */
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 ;
}
/*
* We need to calculate how long before the voltage starts to drop or increase
* It returns with the loop count . Each loop takes several readings ( 532u s )
*/
static inline int wait_for_voltage_change ( int vdd_last )
{
int timeout , vdd_current ;
vdd_current = read_voltage ( ) ;
/* wait until voltage starts to drop */
for ( timeout = 0 ; abs ( vdd_last - vdd_current ) < = 4 & &
timeout < 100 ; timeout + + ) {
vdd_current = read_voltage ( ) ;
}
if ( timeout > = 100 ) {
printf ( " VID: Voltage adjustment timeout \n " ) ;
return - 1 ;
}
return timeout ;
}
/*
* argument ' wait ' is the time we know the voltage difference can be measured
* this function keeps reading the voltage until it is stable
*/
static inline int wait_for_voltage_stable ( int wait )
{
int timeout , vdd_current , vdd_last ;
vdd_last = read_voltage ( ) ;
udelay ( wait * NUM_READINGS * WAIT_FOR_ADC ) ;
/* wait until voltage is stable */
vdd_current = read_voltage ( ) ;
for ( timeout = 0 ; abs ( vdd_last - vdd_current ) > = 4 & &
timeout < 100 ; timeout + + ) {
vdd_last = vdd_current ;
udelay ( wait * NUM_READINGS * WAIT_FOR_ADC ) ;
vdd_current = read_voltage ( ) ;
}
if ( timeout > = 100 ) {
printf ( " VID: Voltage adjustment timeout \n " ) ;
return - 1 ;
}
return vdd_current ;
}
static inline int set_voltage ( u8 vid )
{
int wait , vdd_last ;
vdd_last = read_voltage ( ) ;
QIXIS_WRITE ( brdcfg [ 6 ] , vid ) ;
wait = wait_for_voltage_change ( vdd_last ) ;
if ( wait < 0 )
return - 1 ;
debug ( " VID: Waited %d us \n " , wait * NUM_READINGS * WAIT_FOR_ADC ) ;
wait = wait ? wait : 1 ;
vdd_last = wait_for_voltage_stable ( wait ) ;
if ( vdd_last < 0 )
return - 1 ;
debug ( " VID: Current voltage is %d mV \n " , vdd_last ) ;
return vdd_last ;
}
static int adjust_vdd ( void )
{
int re_enable = disable_interrupts ( ) ;
ccsr_gur_t __iomem * gur =
( void __iomem * ) ( CONFIG_SYS_MPC85xx_GUTS_ADDR ) ;
u32 fusesr ;
u8 vid , vid_current ;
int vdd_target , vdd_current , vdd_last ;
int ret ;
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_pca9547 ( I2C_MUX_CH_VOL_MONITOR ) ;
if ( ret ) {
debug ( " 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 ] ;
if ( vdd_target = = 0 ) {
debug ( " VID: VID not used \n " ) ;
ret = 0 ;
goto exit ;
} else {
/* round up and divice by 10 to get a value in mV */
vdd_target = DIV_ROUND_UP ( vdd_target , 10 ) ;
debug ( " VID: vid = %d mV \n " , vdd_target ) ;
}
/*
* Check current board VID setting
* Voltage regulator support output to 6.250 mv step
* The highes voltage allowed for this board is ( vid = 0x40 ) 1.21250 V
* the lowest is ( vid = 0x7f ) 0.81875 V
*/
vid_current = QIXIS_READ ( brdcfg [ 6 ] ) ;
vdd_current = 121250 - ( vid_current - 0x40 ) * 625 ;
debug ( " VID: Current vid setting is (0x%x) %d mV \n " ,
vid_current , vdd_current / 100 ) ;
/*
* Read voltage monitor to check real voltage .
* Voltage monitor LSB is 4 mv .
*/
vdd_last = read_voltage ( ) ;
if ( vdd_last < 0 ) {
printf ( " VID: Could not read voltage sensor abort VID adjustment \n " ) ;
ret = - 1 ;
goto exit ;
}
debug ( " VID: Core voltage is at %d mV \n " , vdd_last ) ;
/*
* Adjust voltage to at or 8 mV above target .
* Each step of adjustment is 6.25 mV .
* Stepping down too fast may cause over current .
*/
while ( vdd_last > 0 & & vid_current < 0x80 & &
vdd_last > ( vdd_target + 8 ) ) {
vid_current + + ;
vdd_last = set_voltage ( vid_current ) ;
}
/*
* Check if we need to step up
* This happens when board voltage switch was set too low
*/
while ( vdd_last > 0 & & vid_current > = 0x40 & &
vdd_last < vdd_target + 2 ) {
vid_current - - ;
vdd_last = set_voltage ( vid_current ) ;
}
if ( vdd_last > 0 )
printf ( " VID: Core voltage %d mV \n " , vdd_last ) ;
else
ret = - 1 ;
exit :
if ( re_enable )
enable_interrupts ( ) ;
return ret ;
}
/* Configure Crossbar switches for Front-Side SerDes Ports */
/* Configure Crossbar switches for Front-Side SerDes Ports */
int config_frontside_crossbar_vsc3316 ( void )
int config_frontside_crossbar_vsc3316 ( void )
{
{
@ -285,6 +507,13 @@ int board_early_init_r(void)
/* Disable remote I2C connectoin */
/* Disable remote I2C connectoin */
QIXIS_WRITE ( brdcfg [ 5 ] , BRDCFG5_RESET ) ;
QIXIS_WRITE ( brdcfg [ 5 ] , BRDCFG5_RESET ) ;
/*
* Adjust core voltage according to voltage ID
* This function changes I2C mux to channel 2.
*/
if ( adjust_vdd ( ) )
printf ( " Warning: Adjusting core voltage failed. \n " ) ;
/* Configure board SERDES ports crossbar */
/* Configure board SERDES ports crossbar */
config_frontside_crossbar_vsc3316 ( ) ;
config_frontside_crossbar_vsc3316 ( ) ;
config_backside_crossbar_mux ( ) ;
config_backside_crossbar_mux ( ) ;