⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sb1250_draminit.c

📁 一个很好的嵌入式linux平台下的bootloader
💻 C
📖 第 1 页 / 共 5 页
字号:
    else if ((spd_tCK_20 != 0) && (spd_tCK_20 <= tMemClk)) {	caslatency -= 1;				/* subtract 0.5 */	}    /*     * Store the CAS latency in the chip select info     */        tdata->flags &= ~CS_CASLAT_MASK;    tdata->flags |= (((caslatency << CS_CASLAT_SHIFT)) & CS_CASLAT_MASK);#ifdef _MCSTANDALONE_    dram_cas_latency = caslatency;	    dram_tMemClk = tMemClk;#endif    /*     * Now, on to the timing parameters.     */    w2rIdle = 1;	/* Needs to be set on all parts. */    r2rIdle = 0;    /* ======================================================================== */    /*     * New "Window" calculations     */    n01_open = -SB1250_WINDOW_OPEN_OFFSET;    n02_open = -SB1250_WINDOW_OPEN_OFFSET;    n12_open = tMemClk/2 - SB1250_WINDOW_OPEN_OFFSET;    n01_close = tMemClk - SB1250_CLOSE_01_OFFSET;    n02_close = 3*tMemClk/2 - SB1250_CLOSE_02_OFFSET;    n12_close = 7*tMemClk/4 - SB1250_CLOSE_12_OFFSET;    minDqsMargin = SB1250_MIN_DQS_MARGIN;    if (SYS_SOC_TYPE(sysrev) == K_SYS_SOC_TYPE_BCM1250 &&	G_SYS_REVISION(sysrev) >= K_SYS_REVISION_PASS1 &&	G_SYS_REVISION(sysrev) < K_SYS_REVISION_PASS2) {	/* pass1 bcm1250 */	dllScaleNum = PASS1_DLL_SCALE_NUMERATOR;	dllScaleDenom = PASS1_DLL_SCALE_DENOMINATOR;	dllOffset = PASS1_DLL_OFFSET;	}    else {	/* pass2+ BCM1250, or BCM112x */	dllScaleNum = PASS2_DLL_SCALE_NUMERATOR;	dllScaleDenom = PASS2_DLL_SCALE_DENOMINATOR;	dllOffset = PASS2_DLL_OFFSET;	}    /*     * Get fields out of the clock config register     */    dqiSkew =  (int) G_MC_DQI_SKEW(mc->clkconfig);    dqoSkew =  (int) G_MC_DQO_SKEW(mc->clkconfig);    addrSkew = (int) G_MC_ADDR_SKEW(mc->clkconfig);    clkDrive = (int) G_MC_CLOCK_DRIVE(mc->clkconfig);    /*      * get initial values for tCrD and dqsArrival     */    tCrD = (caslatency >> 1);    dqsArrival = mc->roundtrip;    if (caslatency & 1) {	dqsArrival += tMemClk/2;	}    /*     * need to adjust for settings of skew values.     * can either add to dqsArrival or subtract from     * all the windows.     */    addrAdjust = (addrSkew - 8) * ((int)tMemClk * dllScaleNum - dllOffset) / (8 * dllScaleDenom);    dqiAdjust  = (dqiSkew - 8)  * ((int)tMemClk * dllScaleNum - dllOffset) / (8 * dllScaleDenom);    dqsArrival += addrAdjust + dqiAdjust;    /* for pass 2, dqoAdjust applies only to n12_Close */    dqoAdjust  = (dqoSkew - 8)  * (tMemClk * dllScaleNum - dllOffset) / (8 * dllScaleDenom);    n12_close += dqoAdjust;    /*      * adjust window for clock drive strength      * Don't be tempted to turn this into an array.  It will break the     * relocation stuff!     */    switch (clkDrive) {	case 0:   dqsArrival += 10; break;	case 1:   dqsArrival += 4;  break;	case 2:   dqsArrival += 3;  break;	case 3:   dqsArrival += 2;  break;	case 4:   dqsArrival += 2;  break;	case 5:   dqsArrival += 1;  break;	case 6:   dqsArrival += 1;  break;	case 7:   dqsArrival += 1;  break;	case 8:   dqsArrival += 8;  break;	case 9:   dqsArrival += 2;  break;	case 0xa: dqsArrival += 1;  break;	case 0xb: break;	case 0xc: break;	case 0xd: break;	case 0xe: break;	case 0xf: break;	default:	    /* shouldn't get here */	    break;	}    while ((n02_close - dqsArrival < minDqsMargin) &&	   (n12_close - dqsArrival < minDqsMargin)) {	/* very late DQS arrival; shift latency by one tick */#ifdef _MCSTANDALONE_NOISY_	printf("DRAM: Very late DQS arrival, shift latency one tick\n");#endif	++tCrD;	dqsArrival -= tMemClk;	}    if ((dqsArrival - n01_open  >= minDqsMargin) &&	(n01_close - dqsArrival >= minDqsMargin)) {	/* use n,0,1 */	tCrDh = 0;	tFIFO = 1;#ifdef _MCSTANDALONE_NOISY_	printf("DRAM: DQS arrival in n,0,1 window\n");#endif	}     else if ((dqsArrival - n02_open  >= minDqsMargin) &&	     (n02_close - dqsArrival >= minDqsMargin)) {	/* use n,0,2 */	tCrDh = 0;	tFIFO = 2;#ifdef _MCSTANDALONE_NOISY_	printf("DRAM: DQS arrival in n,0,2 window\n");#endif	}     else if ((dqsArrival - n12_open  >= minDqsMargin) &&	     (n12_close - dqsArrival >= minDqsMargin)) {	/* use n,1,2 */	tCrDh = 1;	tFIFO = 2;#ifdef _MCSTANDALONE_NOISY_	printf("DRAM: DQS arrival in n,1,2 window\n");#endif	}     else {	/* 	 * minDqsMargin is probably set too high 	 * try using n,0,2	 */	tCrDh = 0;	tFIFO = 2;#ifdef _MCSTANDALONE_NOISY_	printf("DRAM: Default: DQS arrival in n,0,2 window\n");#endif	}    r2wIdle = ((tMemClk - dqsArrival) < SB1250_MIN_R2W_TIME);    /*     * Pass1 BCM112x parts do not function properly with     * M_MC_r2wIDLE_TWOCYCLES clear, so we set r2wIdle here for them     * so that that flag will be set later.     */    if ((SYS_SOC_TYPE(sysrev) == K_SYS_SOC_TYPE_BCM1120 ||         SYS_SOC_TYPE(sysrev) == K_SYS_SOC_TYPE_BCM1125 ||         SYS_SOC_TYPE(sysrev) == K_SYS_SOC_TYPE_BCM1125H) &&	1 /* XXXCGD: When fixed, check revision! */) {	r2wIdle = 1;	}    /*      * Above stuff just calculated tCrDh, tCrD, and tFIFO     */    /* ======================================================================== */    /* Recompute tMemClk as a fixed-point 6.2 value */    tMemClk = (4000 * 2 *  clk_ratio) / (SB1250_REFCLK * plldiv);    /*     * With the actual tMemClk in hand, calculate tRAS, tRP, tRRD, and tRCD      */    tRAS = ( ((unsigned int)(tdata->spd_tRAS))*4 + tMemClk-1) / tMemClk;    tRP =  ( ((unsigned int)(tdata->spd_tRP))    + tMemClk-1) / tMemClk;    tRRD = ( ((unsigned int)(tdata->spd_tRRD))   + tMemClk-1) / tMemClk;    tRCD = ( ((unsigned int)(tdata->spd_tRCD))   + tMemClk-1) / tMemClk;       /* tWR is the write recovery time, a constant of 15ns for DDR DIMMs. */    tWR  = ( ((unsigned int) 15)*4               + tMemClk-1) / tMemClk;    /*     * tWTR should be 1 tick unless we're actually using     * CAS Latency 1.5 (unlikely) or memory runs faster than     * 166MHz (tCK = 6.0ns or less)     *      * CAS Latency is stored in "halves", so 3 means "1.5"      */    tWTR = 1;    if ((caslatency == 3) || (spd_tCK_25 <= 60)) tWTR = 2;    /*      * Check for registered DIMMs, or if we are "forcing" registered     * DIMMs, as might be the case of regular unregistered DIMMs     * behind an external register.     */    switch (mc->dramtype) {	case FCRAM:	    /* For FCRAMs, tCwD is always caslatency - 1  */	    tCwD = (caslatency >> 1) - 1; 	    tRCD = 1;		/* always 1 for FCRAM */	    tRP = 0;		/* always 0 for FCRAM */	    tWR = 1;		/* always 1 for FCRAM */	    tWTR = 0;		/* Must be 0 or 1.  Undecided on which for FCRAM. */	                        /* Used in tCwCr below.  */	    break;	default:	    /* Otherwise calculate based on registered attribute */	    if ((tdata->spd_attributes & JEDEC_ATTRIB_REG) ||		(mc->flags & MCFLG_FORCEREG)) {  	/* registered DIMM */		tCwD = 2; 		tCrD++;		}	    else {			/* standard unbuffered DIMM */		tCwD = 1;		}	    break;	}    /*     * Okay, using this info, figure out tRCw,tRCr,tCwCr.     */    tRCw = tRCD + tCwD + BURSTLEN/2 + tWR + tRP;    tRCr = tRCD + (caslatency>>1) + BURSTLEN/2 + tRP;    tCwCr = tWR + tRP - tWTR;    /*     * Calculate tRFC if the SPD did not specify it.  Use the DIMM's     * actual rated speed, spd_tCK_25.  Remember that spd_tCK_25 is in     * tenths of nanoseconds, and tMemClk is in fixed-6.2 format,     * but the SPD value itself is in nanoseconds (no tenths).     *     * Use the value from the first expression below that matches:     *     *    100Mhz or less  [10.0ns or more]  -- tRFC = 80ns     *    133Mhz or less  [7.5ns or more]   -- tRFC = 75ns     *    166Mhz or less  [6.0ns or more]   -- tRFC = 72ns     *    All others:                       -- tRFC = 70ns     *     * Special case for gigabit parts: always use 120ns [see JEDEC spec]     *      * Note: the calculation may cause tRFC to overflow the 4-bit field     * that we have allocated for it.  If that happens, reduce memory     * speed and try again.  Hopefully we won't go into a loop.     */    if (tdata->spd_tRFC == 0) {	unsigned int calcRFC;	/* in nanoseconds */	if (tdata->rows >= 14) {	/* Gigabit parts have >= 14 rows */	    calcRFC = 120;	    } 	else {	    if (spd_tCK_25 >= 100)     calcRFC = 80;	/* 100MHz */	    else if (spd_tCK_25 >= 75) calcRFC = 75;	/* 133MHz */	    else if (spd_tCK_25 >= 60) calcRFC = 72;	/* 166MHz */	    else calcRFC = 70;				/* Others */	    }	tRFC = (calcRFC*4 + tMemClk-1) / tMemClk;	/* 	 * if tRFC will not fit in our field (more than 4 bits)	 * then we need to slow the memory down.	 */	if (tRFC > 15) {#ifdef _MCSTANDALONE_NOISY_	    printf("DRAM: tRFC too big, reducing memory speed\n");#endif	    clk_ratio++;	    goto new_ratio;			/* yikes! */	    }	}    else {	tRFC = ( ((unsigned int) tdata->spd_tRFC)*4 + tMemClk-1) / tMemClk;	}    /*     * Finally, put it all together in the timing register.     */    timing1 = V_MC_tRCD(tRCD) |	V_MC_tCrD(tCrD) |	(tCrDh ? M_tCrDh : 0) |	V_MC_tRP(tRP) |	V_MC_tRRD(tRRD) |	V_MC_tRCw(tRCw - 1) |	V_MC_tRCr(tRCr - 1) |	V_MC_tCwCr(tCwCr) |	V_MC_tRFC(tRFC) |	V_MC_tFIFO(tFIFO) |	V_MC_tCwD(tCwD) |	(w2rIdle ? M_MC_w2rIDLE_TWOCYCLES : 0) |	(r2wIdle ? M_MC_r2wIDLE_TWOCYCLES : 0) |	(r2rIdle ? M_MC_r2rIDLE_TWOCYCLES : 0);    mclkcfg = V_MC_CLK_RATIO(clk_ratio) |	V_MC_REF_RATE(refrate);    /* Merge in drive strengths from the MC structure */    mclkcfg |= mc->clkconfig;    base = PHYS_TO_K1(A_MC_BASE(mcidx));    WRITECSR(base+R_MC_TIMING1,timing1);#ifdef _VERILOG_    /* Smash in some defaults for Verilog simulation */    mclkcfg &= ~(M_MC_CLK_RATIO | M_MC_DLL_DEFAULT | M_MC_REF_RATE);    mclkcfg |= V_MC_CLK_RATIO_3X | V_MC_REF_RATE(K_MC_REF_RATE_200MHz) | 	V_MC_DLL_DEFAULT(0x18);#endif    WRITECSR(base+R_MC_MCLK_CFG,mclkcfg);}/*  *********************************************************************    *  SB1250_MANUAL_TIMING(mcidx,mc)    *      *  Program the timing registers, for the case of user-specified    *  timing parameters (don't calculate values based on datasheet    *  values, just stuff the info into the MC registers)    *      *  Input parameters:     *  	   mcidx - memory controller index    *  	   mc - memory controller data    *  	       *  Return value:    *  	   nothing    ********************************************************************* */static void sb1250_manual_timing(int mcidx,mcdata_t *mc){    unsigned int plldiv;    unsigned int clk_ratio;    unsigned int refrate;    unsigned int ref_freq;    unsigned int tCpuClk;    unsigned int tMemClk;    uint64_t timing1;    uint64_t mclkcfg;    sbport_t base;    /*     * We need our cpu clock for all sorts of things.     */#if defined(_VERILOG_) || defined(_FUNCSIM_)    plldiv = 16;		/* 800MHz CPU for RTL simulation */#else    plldiv = G_SYS_PLL_DIV(READCSR(PHYS_TO_K1(A_SCD_SYSTEM_CFG)));#endif    if (plldiv == 0) {	/* XXX: should be common macro, also defaulted by boards' *_devs.c.  */	plldiv = 6;	}    /* See comments in auto_timing for details */    tCpuClk = 2000000/(SB1250_REFCLK*plldiv);	/* tCpuClk is in picoseconds */    /* Compute MAX(MIN_tMEMCLK,spd_tCK_25) */    tMemClk = DECTO10THS(mc->tCK);    if (mc->mintmemclk > tMemClk) tMemClk = mc->mintmemclk;    clk_ratio = ((tMemClk*100) + tCpuClk - 1) / tCpuClk;    if (clk_ratio < 4) clk_ratio = 4;    if (clk_ratio > 9) clk_ratio = 9;    /* recompute tMemClk using the new clk_ratio */    tMemClk = (10000 * 2 * clk_ratio)/(SB1250_REFCLK * plldiv);    /* Calculate the refresh rate */    switch (mc->rfsh & JEDEC_RFSH_MASK) {	case JEDEC_RFSH_64khz:	ref_freq = 64;  break;	case JEDEC_RFSH_256khz:	ref_freq = 256; break;	case JEDEC_RFSH_128khz:	ref_freq = 128; break;	case JEDEC_RFSH_32khz:	ref_freq = 32;  break;	case JEDEC_RFSH_8khz:	ref_freq = 16;  break;	default: 		ref_freq = 8;   break;	}    refrate = ((plldiv * SB1250_REFCLK * 1000 / 2) / (ref_freq*16*clk_ratio)) - 1;    timing1 = mc->mantiming;    mclkcfg = V_MC_CLK_RATIO(clk_ratio) |	V_MC_REF_RATE(refrate);    /* Merge in drive strengths from the MC structure */    mclkcfg |= mc->clkconfig;    base = PHYS_TO_K1(A_MC_BASE(mcidx));

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -