📄 sb1250_draminit.c
字号:
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 + -