📄 bcm1480_draminit.c
字号:
fMemClk = ((plldiv * BCM1480_REFCLK * 1000 / 2 / 2) * 4 / clk_ratio); refrate = fMemClk / 32 / ref_freq; /* Don't let the refresh rate go beyond the field width */ if (refrate > 255) refrate = 255; /* * Calculate CAS Latency in half cycles. The low bit indicates * half a cycle, so 2 (0010) = 1 cycle and 3 (0011) = 1.5 cycles */ res = tdata->spd_caslatency; if (res & JEDEC_CASLAT_40) caslatency = (4 << 1); /* 4.0 */ else if (res & JEDEC_CASLAT_35) caslatency = (3 << 1) + 1; /* 3.5 */ else if (res & JEDEC_CASLAT_30) caslatency = (3 << 1); /* 3.0 */ else if (res & JEDEC_CASLAT_25) caslatency = (2 << 1) + 1; /* 2.5 */ else if (res & JEDEC_CASLAT_20) caslatency = (2 << 1); /* 2.0 */ else if (res & JEDEC_CASLAT_15) caslatency = (1 << 1) + 1; /* 1.5 */ else caslatency = (1 << 1); /* 1.0 */ if ((spd_tCK_10 != 0) && (spd_tCK_10 <= tMemClk)) { caslatency -= (1 << 1); /* subtract 1.0 */ } 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. XXX this is a 1250 bug, what to do on 1480? */ r2rIdle = 0; /* ======================================================================== */ /* * New "Window" calculations */ n01_open = -BCM1480_WINDOW_OPEN_OFFSET; n02_open = -BCM1480_WINDOW_OPEN_OFFSET; n12_open = tMemClk/2 - BCM1480_WINDOW_OPEN_OFFSET; n01_close = tMemClk - BCM1480_CLOSE_01_OFFSET; n02_close = 3*tMemClk/2 - BCM1480_CLOSE_02_OFFSET; n12_close = 7*tMemClk/4 - BCM1480_CLOSE_12_OFFSET; minDqsMargin = BCM1480_MIN_DQS_MARGIN; dllScaleNum = DLL_SCALE_NUMERATOR; dllScaleDenom = DLL_SCALE_DENOMINATOR; dllOffset = DLL_OFFSET; /* * get initial values for tCL and dqsArrival */ tCL = (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 = ((int)tMemClk * dllScaleNum - dllOffset) / (8 * dllScaleDenom); dqiAdjust = ((int)tMemClk * dllScaleNum - dllOffset) / (8 * dllScaleDenom); dqsArrival += addrAdjust + dqiAdjust; dqoAdjust = (tMemClk * dllScaleNum - dllOffset) / (8 * dllScaleDenom); n12_close += dqoAdjust;#ifdef _MCSTANDALONE_NOISY_ printf("DRAM: addrAdjust=%d dqiAdjust=%d dqsArrival=%d\n", addrAdjust,dqiAdjust,dqsArrival); printf("DRAM: n02_close=%d n12_close=%d minDqsMargin=%d\n", n02_close,n12_close,minDqsMargin); printf("DRAM: tMemClk=%d dllScaleNum=%d dllScaleDenom=%d dllOffset=%d\n", tMemClk,dllScaleNum,dllScaleDenom,dllOffset);#endif 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 ++tCL; 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) < BCM1480_MIN_R2W_TIME);*/ r2wIdle = 2; /* XXX force 1 for now until 1480 measurements are done */#ifdef _VERILOG_ tFIFO = 0;#endif /* * Above stuff just calculated tCrDh, tCL, and tFIFO */// tFIFO = 0; tCrDh = 1; tCL = 2; /* XXX */ /* ======================================================================== */ /* Recompute tMemClk as a fixed-point 6.2 value */ tMemClk = (4000 * clk_ratio) / (BCM1480_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; /* * 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 = 1; /* always 1 for FCRAM */ break; default: /* Otherwise calculate based on registered attribute */ if ((tdata->spd_attributes & JEDEC_ATTRIB_REG) || (mc->flags & MCFLG_FORCEREG)) { /* registered DIMM */ tCwD = 2; tCL++; } else { /* standard unbuffered DIMM */ tCwD = 1; } break; } /* * 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; /* * Okay, using this info, figure out tRCw,tRCr. */ tRCw = tRCD + tCwD + BURSTLEN/2 + tWR + tRP; tRCr = tRCD + (caslatency>>1) + BURSTLEN/2 + tRP; /* * 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 is greater than 48, * then we need to slow the memory down. */ if (tRFC > 48) {#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; }#if _BCM1480_S0_WORKAROUNDS_ /* * XXX Override some values for ddr2 (Micron MT47H32M8-37E 256Mb) * * tRFC=19@250 15@200 14@175 12@150 10@125 (75ns) * tCL=3 caslat=3 * tCwD=caslat-1 (2) (write latency) @200 * tWR=4@250 3@200 3@175 3@150 2@125 (15nc) * tRP=4@250 3@200 3@175 3@150 2@125 (15ns) * tRRD=2@250 2@200 2@175 2@150 2@125 (7.5ns) * tRCD=4@250 3@200 3@175 3@150 2@125 (15ns) * * tRCw=16@250 13@200 13@175 11@150 9@125 * tRCr=14@250 11@200 11@175 9@150 7@125 (55ns) * * tFIFO=1; tCrDh=0 ; r2wIdle=1; * w2rIdle=1; r2rIdle=1; * * XXX Set it for 150 MClk @ cas latency 3 */ if(mc->dramtype == JEDEC_DDR2) { tRFC=12; tCL=3; tCwD=2; tWR=3; tRP=3; tRRD=2; tRCD=3; tRCw=11; tRCr=9; tFIFO=1; tCrDh=0; r2wIdle=1; w2rIdle=1; r2rIdle=1; mc->tWR = tWR; /* DDR2 part requires tWR. See bcm1480_jedec_ddr2_initcmds */ }#endif /* * Finally, put it all together in the timing register. */ timing1 = V_BCM1480_MC_tRCD(tRCD) | V_BCM1480_MC_tCL(tCL) | (tCrDh ? M_BCM1480_MC_tCrDh : 0) | V_BCM1480_MC_tWR(tWR) | V_BCM1480_MC_tCwD(tCwD) | V_BCM1480_MC_tRP(tRP) | V_BCM1480_MC_tRRD(tRRD) | V_BCM1480_MC_tRCw(tRCw) | V_BCM1480_MC_tRCr(tRCr) | V_BCM1480_MC_tRFC(tRFC) | V_BCM1480_MC_tFIFO(tFIFO) | V_BCM1480_MC_tR2W(r2wIdle) | V_BCM1480_MC_tW2R(w2rIdle) | (r2rIdle ? M_BCM1480_MC_tR2R : 0); base = PHYS_TO_K1(A_BCM1480_MC_BASE(mcidx)); WRITECSR(base+R_BCM1480_MC_TIMING1,timing1); /* * Set the clk_ratio and refresh rate in memory clock config register. */ mclkcfg = V_BCM1480_MC_CLK_RATIO(clk_ratio) | V_BCM1480_MC_REF_RATE(refrate); WRITECSR(base+R_BCM1480_MC_MCLK_CFG,mclkcfg); /* * Memory DLL config and memory drive config registers. */ WRITECSR(base+R_BCM1480_MC_DLL_CFG,mc->dllcfg); WRITECSR(base+R_BCM1480_MC_DRIVE_CFG,mc->drvcfg); /* * In the case of 64-bit channels, do the same things on the * "ganged" channel so that they'll have the same timing. */ if (mc->chantype == MC_64BIT_CHAN) { base = PHYS_TO_K1(A_BCM1480_MC_BASE(mcidx+2)); WRITECSR(base+R_BCM1480_MC_TIMING1,timing1); WRITECSR(base+R_BCM1480_MC_MCLK_CFG,mclkcfg); WRITECSR(base+R_BCM1480_MC_DLL_CFG,mc->dllcfg); WRITECSR(base+R_BCM1480_MC_DRIVE_CFG,mc->drvcfg); }}/* ********************************************************************* * BCM1480_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 bcm1480_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, mclkcfg; sbport_t base; /* * We need our cpu clock for all sorts of things. */#if defined(_FUNCSIM_) plldiv = 16; /* 800MHz CPU for functional simulation */#else plldiv = G_BCM1480_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/(BCM1480_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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -