@ -106,16 +106,29 @@ long int spd_sdram()
volatile ddr83xx_t * ddr = & immap - > ddr ;
volatile law83xx_t * ecm = & immap - > sysconf . ddrlaw [ 0 ] ;
spd_eeprom_t spd ;
unsigned int n_ranks ;
unsigned int odt_rd_cfg , odt_wr_cfg ;
unsigned char twr_clk , twtr_clk ;
unsigned char sdram_type ;
unsigned int memsize ;
unsigned int law_size ;
unsigned char caslat , caslat_ctrl ;
unsigned int trfc , trfc_clk , trfc_low , trfc_high ;
unsigned int trcd_clk , trtp_clk ;
unsigned char cke_min_clk ;
unsigned char add_lat , wr_lat ;
unsigned char wr_data_delay ;
unsigned char four_act ;
unsigned char cpo ;
unsigned char burstlen ;
unsigned char odt_cfg , mode_odt_enable ;
unsigned int max_bus_clk ;
unsigned int max_data_rate , effective_data_rate ;
unsigned int ddrc_clk ;
unsigned int refresh_clk ;
unsigned sdram_cfg ;
unsigned int sdram_cfg ;
unsigned int ddrc_ecc_enable ;
unsigned int pvr = get_pvr ( ) ;
/* Read SPD parameters with I2C */
CFG_READ_SPD ( SPD_EEPROM_ADDRESS , 0 , 1 , ( uchar * ) & spd , sizeof ( spd ) ) ;
@ -123,19 +136,25 @@ long int spd_sdram()
spd_debug ( & spd ) ;
# endif
/* Check the memory type */
if ( spd . mem_type ! = SPD_MEMTYPE_DDR ) {
if ( spd . mem_type ! = SPD_MEMTYPE_DDR & & spd . mem_type ! = SPD_MEMTYPE_DDR2 ) {
printf ( " DDR: Module mem type is %02X \n " , spd . mem_type ) ;
return 0 ;
}
/* Check the number of physical bank */
if ( spd . nrows > 2 ) {
printf ( " DDR: The number of physical bank is %02X \n " , spd . nrows ) ;
if ( spd . mem_type = = SPD_MEMTYPE_DDR ) {
n_ranks = spd . nrows ;
} else {
n_ranks = ( spd . nrows & 0x7 ) + 1 ;
}
if ( n_ranks > 2 ) {
printf ( " DDR: The number of physical bank is %02X \n " , n_ranks ) ;
return 0 ;
}
/* Check if the number of row of the module is in the range of DDRC */
if ( spd . nrow_addr < 12 | | spd . nrow_addr > 14 ) {
if ( spd . nrow_addr < 12 | | spd . nrow_addr > 15 ) {
printf ( " DDR: Row number is out of range of DDRC, row=%02X \n " ,
spd . nrow_addr ) ;
return 0 ;
@ -147,20 +166,43 @@ long int spd_sdram()
spd . ncol_addr ) ;
return 0 ;
}
# ifdef CFG_DDRCDR_VALUE
/*
* Adjust DDR II IO voltage biasing . It just makes it work .
*/
if ( spd . mem_type = = SPD_MEMTYPE_DDR2 ) {
immap - > sysconf . ddrcdr = CFG_DDRCDR_VALUE ;
}
# endif
/*
* ODT configuration recommendation from DDR Controller Chapter .
*/
odt_rd_cfg = 0 ; /* Never assert ODT */
odt_wr_cfg = 0 ; /* Never assert ODT */
if ( spd . mem_type = = SPD_MEMTYPE_DDR2 ) {
odt_wr_cfg = 1 ; /* Assert ODT on writes to CSn */
}
/* Setup DDR chip select register */
# ifdef CFG_83XX_DDR_USES_CS0
ddr - > csbnds [ 0 ] . csbnds = ( banksize ( spd . row_dens ) > > 24 ) - 1 ;
ddr - > cs_config [ 0 ] = ( 1 < < 31
| ( odt_rd_cfg < < 20 )
| ( odt_wr_cfg < < 16 )
| ( spd . nrow_addr - 12 ) < < 8
| ( spd . ncol_addr - 8 ) ) ;
debug ( " \n " ) ;
debug ( " cs0_bnds = 0x%08x \n " , ddr - > csbnds [ 0 ] . csbnds ) ;
debug ( " cs0_config = 0x%08x \n " , ddr - > cs_config [ 0 ] ) ;
if ( spd . nrows = = 2 ) {
if ( n_rank s = = 2 ) {
ddr - > csbnds [ 1 ] . csbnds = ( ( banksize ( spd . row_dens ) > > 8 )
| ( ( banksize ( spd . row_dens ) > > 23 ) - 1 ) ) ;
ddr - > cs_config [ 1 ] = ( 1 < < 31
| ( odt_rd_cfg < < 20 )
| ( odt_wr_cfg < < 16 )
| ( spd . nrow_addr - 12 ) < < 8
| ( spd . ncol_addr - 8 ) ) ;
debug ( " cs1_bnds = 0x%08x \n " , ddr - > csbnds [ 1 ] . csbnds ) ;
@ -170,16 +212,20 @@ long int spd_sdram()
# else
ddr - > csbnds [ 2 ] . csbnds = ( banksize ( spd . row_dens ) > > 24 ) - 1 ;
ddr - > cs_config [ 2 ] = ( 1 < < 31
| ( odt_rd_cfg < < 20 )
| ( odt_wr_cfg < < 16 )
| ( spd . nrow_addr - 12 ) < < 8
| ( spd . ncol_addr - 8 ) ) ;
debug ( " \n " ) ;
debug ( " cs2_bnds = 0x%08x \n " , ddr - > csbnds [ 2 ] . csbnds ) ;
debug ( " cs2_config = 0x%08x \n " , ddr - > cs_config [ 2 ] ) ;
if ( spd . nrow s = = 2 ) {
if ( n_rank s = = 2 ) {
ddr - > csbnds [ 3 ] . csbnds = ( ( banksize ( spd . row_dens ) > > 8 )
| ( ( banksize ( spd . row_dens ) > > 23 ) - 1 ) ) ;
ddr - > cs_config [ 3 ] = ( 1 < < 31
| ( odt_rd_cfg < < 20 )
| ( odt_wr_cfg < < 16 )
| ( spd . nrow_addr - 12 ) < < 8
| ( spd . ncol_addr - 8 ) ) ;
debug ( " cs3_bnds = 0x%08x \n " , ddr - > csbnds [ 3 ] . csbnds ) ;
@ -187,15 +233,10 @@ long int spd_sdram()
}
# endif
if ( spd . mem_type ! = 0x07 ) {
puts ( " No DDR module found! \n " ) ;
return 0 ;
}
/*
* Figure out memory size in Megabytes .
*/
memsize = spd . nrow s * banksize ( spd . row_dens ) / 0x100000 ;
memsize = n_ranks * banksize ( spd . row_dens ) / 0x100000 ;
/*
* First supported LAW size is 16 M , at LAWAR_SIZE_16M = = 23.
@ -215,24 +256,32 @@ long int spd_sdram()
* in the spd . cas_lat field . Translate it to a DDR
* controller field value :
*
* CAS Lat DDR I Ctrl
* Clocks SPD Bit Value
* - - - - - - - + - - - - - - - - + - - - - - - - - -
* 1.0 0 001
* 1.5 1 010
* 2.0 2 011
* 2.5 3 100
* 3.0 4 101
* 3.5 5 110
* 4.0 6 111
* CAS Lat DDR I DDR II Ctrl
* Clocks SPD Bit SPD Bit Value
* - - - - - - - - - - - - - - - - - - - - - - - - - -
* 1.0 0 0001
* 1.5 1 0010
* 2.0 2 2 0011
* 2.5 3 0100
* 3.0 4 3 0101
* 3.5 5 0110
* 4.0 6 4 0111
* 4.5 1000
* 5.0 5 1001
*/
caslat = __ilog2 ( spd . cas_lat ) ;
if ( caslat > 6 ) {
printf ( " DDR: Invalid SPD CAS Latency, caslat=%02X \n " ,
spd . cas_lat ) ;
if ( ( spd . mem_type = = SPD_MEMTYPE_DDR )
& & ( caslat > 6 ) ) {
printf ( " DDR I: Invalid SPD CAS Latency: 0x%x. \n " , spd . cas_lat ) ;
return 0 ;
} else if ( spd . mem_type = = SPD_MEMTYPE_DDR2
& & ( caslat < 2 | | caslat > 5 ) ) {
printf ( " DDR II: Invalid SPD CAS Latency: 0x%x. \n " ,
spd . cas_lat ) ;
return 0 ;
}
debug ( " DDR: caslat SPD bit is %d \n " , caslat ) ;
max_bus_clk = 1000 * 10 / ( ( ( spd . clk_cycle & 0xF0 ) > > 4 ) * 10
+ ( spd . clk_cycle & 0x0f ) ) ;
max_data_rate = max_bus_clk * 2 ;
@ -240,10 +289,11 @@ long int spd_sdram()
debug ( " DDR:Module maximum data rate is: %dMhz \n " , max_data_rate ) ;
ddrc_clk = gd - > ddr_clk / 1000000 ;
effective_data_rate = 0 ;
if ( max_data_rate > = 390 ) { /* it is DDR 400 */
if ( ddrc_clk < = 41 0 & & ddrc_clk > 350 ) {
/* DDR controller clk at 350~41 0 */
if ( max_data_rate > = 390 & & max_data_rate < 460 ) { /* it is DDR 400 */
if ( ddrc_clk < = 46 0 & & ddrc_clk > 350 ) {
/* DDR controller clk at 350~46 0 */
effective_data_rate = 400 ; /* 5ns */
caslat = caslat ;
} else if ( ddrc_clk < = 350 & & ddrc_clk > 280 ) {
@ -258,16 +308,16 @@ long int spd_sdram()
effective_data_rate = 266 ; /* 7.5ns */
if ( spd . clk_cycle3 = = 0x75 )
caslat = caslat - 2 ;
else if ( spd . clk_cycle2 = = 0x60 )
else if ( spd . clk_cycle2 = = 0x75 )
caslat = caslat - 1 ;
else
caslat = caslat ;
} else if ( ddrc_clk < = 230 & & ddrc_clk > 90 ) {
/* DDR controller clk at 90~230 */
effective_data_rate = 200 ; /* 10ns */
if ( spd . clk_cycle3 = = 0x75 )
if ( spd . clk_cycle3 = = 0xa0 )
caslat = caslat - 2 ;
else if ( spd . clk_cycle2 = = 0x6 0 )
else if ( spd . clk_cycle2 = = 0xa 0 )
caslat = caslat - 1 ;
else
caslat = caslat ;
@ -289,7 +339,7 @@ long int spd_sdram()
effective_data_rate = 200 ; /* 10ns */
if ( spd . clk_cycle3 = = 0xa0 )
caslat = caslat - 2 ;
else if ( spd . clk_cycle2 = = 0x75 )
else if ( spd . clk_cycle2 = = 0xa0 )
caslat = caslat - 1 ;
else
caslat = caslat ;
@ -330,41 +380,197 @@ long int spd_sdram()
* Errata DDR6 work around : input enable 2 cycles earlier .
* including MPC834x Rev1 .0 / 1.1 and MPC8360 Rev1 .1 / 1.2 .
*/
if ( caslat = = 2 )
ddr - > debug_reg = 0x201c0000 ; /* CL=2 */
else if ( caslat = = 3 )
ddr - > debug_reg = 0x202c0000 ; /* CL=2.5 */
else if ( caslat = = 4 )
ddr - > debug_reg = 0x202c0000 ; /* CL=3.0 */
if ( PVR_MAJ ( pvr ) < = 1 & & spd . mem_type = = SPD_MEMTYPE_DDR ) {
if ( caslat = = 2 )
ddr - > debug_reg = 0x201c0000 ; /* CL=2 */
else if ( caslat = = 3 )
ddr - > debug_reg = 0x202c0000 ; /* CL=2.5 */
else if ( caslat = = 4 )
ddr - > debug_reg = 0x202c0000 ; /* CL=3.0 */
__asm__ __volatile__ ( " sync " ) ;
__asm__ __volatile__ ( " sync " ) ;
debug ( " Errata DDR6 (debug_reg=0x%08x) \n " , ddr - > debug_reg ) ;
debug ( " Errata DDR6 (debug_reg=0x%08x) \n " , ddr - > debug_reg ) ;
}
/*
* note : caslat must also be programmed into ddr - > sdram_mode
* register .
*
* note : WRREC ( Twr ) and WRTORD ( Twtr ) are not in SPD ,
* use conservative value here .
* Convert caslat clocks to DDR controller value .
* Force caslat_ctrl to be DDR Controller field - sized .
*/
caslat_ctrl = ( caslat + 1 ) & 0x07 ; /* see as above */
if ( spd . mem_type = = SPD_MEMTYPE_DDR ) {
caslat_ctrl = ( caslat + 1 ) & 0x07 ;
} else {
caslat_ctrl = ( 2 * caslat - 1 ) & 0x0f ;
}
debug ( " DDR: effective data rate is %d MHz \n " , effective_data_rate ) ;
debug ( " DDR: caslat SPD bit is %d, controller field is 0x%x \n " ,
caslat , caslat_ctrl ) ;
/*
* Timing Config 0.
* Avoid writing for DDR I .
*/
if ( spd . mem_type = = SPD_MEMTYPE_DDR2 ) {
unsigned char taxpd_clk = 8 ; /* By the book. */
unsigned char tmrd_clk = 2 ; /* By the book. */
unsigned char act_pd_exit = 2 ; /* Empirical? */
unsigned char pre_pd_exit = 6 ; /* Empirical? */
ddr - > timing_cfg_0 = ( 0
| ( ( act_pd_exit & 0x7 ) < < 20 ) /* ACT_PD_EXIT */
| ( ( pre_pd_exit & 0x7 ) < < 16 ) /* PRE_PD_EXIT */
| ( ( taxpd_clk & 0xf ) < < 8 ) /* ODT_PD_EXIT */
| ( ( tmrd_clk & 0xf ) < < 0 ) /* MRS_CYC */
) ;
debug ( " DDR: timing_cfg_0 = 0x%08x \n " , ddr - > timing_cfg_0 ) ;
}
/*
* For DDR I , WRREC ( Twr ) and WRTORD ( Twtr ) are not in SPD ,
* use conservative value .
* For DDR II , they are bytes 36 and 37 , in quarter nanos .
*/
if ( spd . mem_type = = SPD_MEMTYPE_DDR ) {
twr_clk = 3 ; /* Clocks */
twtr_clk = 1 ; /* Clocks */
} else {
twr_clk = picos_to_clk ( spd . twr * 250 ) ;
twtr_clk = picos_to_clk ( spd . twtr * 250 ) ;
}
/*
* Calculate Trfc , in picos .
* DDR I : Byte 42 straight up in ns .
* DDR II : Byte 40 and 42 swizzled some , in ns .
*/
if ( spd . mem_type = = SPD_MEMTYPE_DDR ) {
trfc = spd . trfc * 1000 ; /* up to ps */
} else {
unsigned int byte40_table_ps [ 8 ] = {
0 ,
250 ,
330 ,
500 ,
660 ,
750 ,
0 ,
0
} ;
trfc = ( ( ( spd . trctrfc_ext & 0x1 ) * 256 ) + spd . trfc ) * 1000
+ byte40_table_ps [ ( spd . trctrfc_ext > > 1 ) & 0x7 ] ;
}
trfc_clk = picos_to_clk ( trfc ) ;
/*
* Trcd , Byte 29 , from quarter nanos to ps and clocks .
*/
trcd_clk = picos_to_clk ( spd . trcd * 250 ) & 0x7 ;
/*
* Convert trfc_clk to DDR controller fields . DDR I should
* fit in the REFREC field ( 16 - 19 ) of TIMING_CFG_1 , but the
* 83 xx controller has an extended REFREC field of three bits .
* The controller automatically adds 8 clocks to this value ,
* so preadjust it down 8 first before splitting it up .
*/
trfc_low = ( trfc_clk - 8 ) & 0xf ;
trfc_high = ( ( trfc_clk - 8 ) > > 4 ) & 0x3 ;
ddr - > timing_cfg_1 =
( ( ( picos_to_clk ( spd . trp * 250 ) & 0x07 ) < < 28 ) |
( ( picos_to_clk ( spd . tras * 1000 ) & 0x0f ) < < 24 ) |
( ( picos_to_clk ( spd . trcd * 250 ) & 0x07 ) < < 20 ) |
( ( caslat_ctrl & 0x07 ) < < 16 ) |
( ( ( picos_to_clk ( spd . trfc * 1000 ) - 8 ) & 0x0f ) < < 12 ) |
( 0x300 ) |
( ( picos_to_clk ( spd . trrd * 250 ) & 0x07 ) < < 4 ) | 1 ) ;
( ( ( picos_to_clk ( spd . trp * 250 ) & 0x07 ) < < 28 ) | /* PRETOACT */
( ( picos_to_clk ( spd . tras * 1000 ) & 0x0f ) < < 24 ) | /* ACTTOPRE */
( trcd_clk < < 20 ) | /* ACTTORW */
( caslat_ctrl < < 16 ) | /* CASLAT */
( trfc_low < < 12 ) | /* REFEC */
( ( twr_clk & 0x07 ) < < 8 ) | /* WRRREC */
( ( picos_to_clk ( spd . trrd * 250 ) & 0x07 ) < < 4 ) | /* ACTTOACT */
( ( twtr_clk & 0x07 ) < < 0 ) /* WRTORD */
) ;
/*
* Additive Latency
* For DDR I , 0.
* For DDR II , with ODT enabled , use " a value " less than ACTTORW ,
* which comes from Trcd , and also note that :
* add_lat + caslat must be > = 4
*/
add_lat = 0 ;
if ( spd . mem_type = = SPD_MEMTYPE_DDR2
& & ( odt_wr_cfg | | odt_rd_cfg )
& & ( caslat < 4 ) ) {
add_lat = trcd_clk - 1 ;
if ( ( add_lat + caslat ) < 4 ) {
add_lat = 0 ;
}
}
/*
* Write Data Delay
* Historically 0x2 = = 4 / 8 clock delay .
* Empirically , 0x3 = = 6 / 8 clock delay is suggested for DDR I 266.
*/
wr_data_delay = 2 ;
/*
* Write Latency
* Read to Precharge
* Minimum CKE Pulse Width .
* Four Activate Window
*/
if ( spd . mem_type = = SPD_MEMTYPE_DDR ) {
/*
* This is a lie . It should really be 1 , but if it is
* set to 1 , bits overlap into the old controller ' s
* otherwise unused ACSM field . If we leave it 0 , then
* the HW will magically treat it as 1 for DDR 1. Oh Yea .
*/
wr_lat = 0 ;
trtp_clk = 2 ; /* By the book. */
cke_min_clk = 1 ; /* By the book. */
four_act = 1 ; /* By the book. */
} else {
wr_lat = caslat - 1 ;
/* Convert SPD value from quarter nanos to picos. */
trtp_clk = picos_to_clk ( spd . trtp * 250 ) ;
ddr - > timing_cfg_2 = 0x00000800 ;
cke_min_clk = 3 ; /* By the book. */
four_act = picos_to_clk ( 37500 ) ; /* By the book. 1k pages? */
}
/*
* Empirically set ~ MCAS - to - preamble override for DDR 2.
* Your milage will vary .
*/
cpo = 0 ;
if ( spd . mem_type = = SPD_MEMTYPE_DDR2 ) {
if ( effective_data_rate = = 266 | | effective_data_rate = = 333 ) {
cpo = 0x7 ; /* READ_LAT + 5/4 */
} else if ( effective_data_rate = = 400 ) {
cpo = 0x9 ; /* READ_LAT + 7/4 */
} else {
/* Automatic calibration */
cpo = 0x1f ;
}
}
ddr - > timing_cfg_2 = ( 0
| ( ( add_lat & 0x7 ) < < 28 ) /* ADD_LAT */
| ( ( cpo & 0x1f ) < < 23 ) /* CPO */
| ( ( wr_lat & 0x7 ) < < 19 ) /* WR_LAT */
| ( ( trtp_clk & 0x7 ) < < 13 ) /* RD_TO_PRE */
| ( ( wr_data_delay & 0x7 ) < < 10 ) /* WR_DATA_DELAY */
| ( ( cke_min_clk & 0x7 ) < < 6 ) /* CKE_PLS */
| ( ( four_act & 0x1f ) < < 0 ) /* FOUR_ACT */
) ;
debug ( " DDR:timing_cfg_1=0x%08x \n " , ddr - > timing_cfg_1 ) ;
debug ( " DDR:timing_cfg_2=0x%08x \n " , ddr - > timing_cfg_2 ) ;
/* Setup init value, but not enable */
ddr - > sdram_cfg = 0x42000000 ;
/* Check DIMM data bus width */
if ( spd . dataw_lsb = = 0x20 ) {
@ -384,7 +590,8 @@ long int spd_sdram()
/* Burst length is always 4 for 64 bit data bus, 8 for 32 bit data bus,
Burst type is sequential
*/
switch ( caslat ) {
if ( spd . mem_type = = SPD_MEMTYPE_DDR ) {
switch ( caslat ) {
case 1 :
ddr - > sdram_mode = 0x50 | burstlen ; /* CL=1.5 */
break ;
@ -400,9 +607,36 @@ long int spd_sdram()
default :
printf ( " DDR:only CL 1.5, 2.0, 2.5, 3.0 is supported \n " ) ;
return 0 ;
}
} else {
mode_odt_enable = 0x0 ; /* Default disabled */
if ( odt_wr_cfg | | odt_rd_cfg ) {
/*
* Bits 6 and 2 in Extended MRS ( 1 )
* Bit 2 = = 0x04 = = 75 Ohm , with 2 DIMM modules .
* Bit 6 = = 0x40 = = 150 Ohm , with 1 DIMM module .
*/
mode_odt_enable = 0x40 ; /* 150 Ohm */
}
ddr - > sdram_mode =
( 0
| ( 1 < < ( 16 + 10 ) ) /* DQS Differential disable */
| ( add_lat < < ( 16 + 3 ) ) /* Additive Latency in EMRS1 */
| ( mode_odt_enable < < 16 ) /* ODT Enable in EMRS1 */
| ( ( twr_clk > > 1 ) < < 9 ) /* Write Recovery Autopre */
| ( caslat < < 4 ) /* caslat */
| ( burstlen < < 0 ) /* Burst length */
) ;
}
debug ( " DDR:sdram_mode=0x%08x \n " , ddr - > sdram_mode ) ;
/*
* Clear EMRS2 and EMRS3 .
*/
ddr - > sdram_mode2 = 0 ;
debug ( " DDR: sdram_mode2 = 0x%08x \n " , ddr - > sdram_mode2 ) ;
switch ( spd . refresh ) {
case 0x00 :
case 0x80 :
@ -440,6 +674,23 @@ long int spd_sdram()
ddr - > sdram_interval = ( ( refresh_clk & 0x3fff ) < < 16 ) | 0x100 ;
debug ( " DDR:sdram_interval=0x%08x \n " , ddr - > sdram_interval ) ;
/*
* SDRAM Cfg 2
*/
odt_cfg = 0 ;
if ( odt_rd_cfg | odt_wr_cfg ) {
odt_cfg = 0x2 ; /* ODT to IOs during reads */
}
if ( spd . mem_type = = SPD_MEMTYPE_DDR2 ) {
ddr - > sdram_cfg2 = ( 0
| ( 0 < < 26 ) /* True DQS */
| ( odt_cfg < < 21 ) /* ODT only read */
| ( 1 < < 12 ) /* 1 refresh at a time */
) ;
debug ( " DDR: sdram_cfg2 = 0x%08x \n " , ddr - > sdram_cfg2 ) ;
}
# ifdef CFG_DDR_SDRAM_CLK_CNTL /* Optional platform specific value */
ddr - > sdram_clk_cntl = CFG_DDR_SDRAM_CLK_CNTL ;
# else
@ -462,11 +713,22 @@ long int spd_sdram()
*
* sdram_cfg [ 0 ] = 1 ( ddr sdram logic enable )
* sdram_cfg [ 1 ] = 1 ( self - refresh - enable )
* sdram_cfg [ 6 : 7 ] = 2 ( SDRAM type = DDR SDRAM )
* sdram_cfg [ 5 : 7 ] = ( SDRAM type = DDR SDRAM )
* 010 DDR 1 SDRAM
* 011 DDR 2 SDRAM
* sdram_cfg [ 12 ] = 0 ( 32 _BE = 0 , 64 bit bus mode )
* sdram_cfg [ 13 ] = 0 ( 8 _BE = 0 , 4 - beat bursts )
*/
sdram_cfg = 0xC2000000 ;
if ( spd . mem_type = = SPD_MEMTYPE_DDR )
sdram_type = 2 ;
else
sdram_type = 3 ;
sdram_cfg = ( 0
| ( 1 < < 31 ) /* DDR enable */
| ( 1 < < 30 ) /* Self refresh */
| ( sdram_type < < 24 ) /* SDRAM type */
) ;
/* sdram_cfg[3] = RD_EN - registered DIMM enable */
if ( spd . mod_attr & 0x02 )