📄 sb1250_draminit.c
字号:
#define M_MCINIT_TRYPINTLV 1 /* Try to do port interleaving */#define M_MCINIT_PINTLV 2 /* Actually do port interleaving *//* Work area: initdata structure plus enough working stack to run the DRAM init routine. We round the initdata structure up to a 1K boundary, and throw in an extra 1K for stack space. This **MUST** evaluate to a compile-time constant. */#define WORK_AREA_SIZE (((sizeof(initdata_t) + 1023) / 1024) + 1) * 1024/* ********************************************************************* * Configuration data structure ********************************************************************* */#include "sb1250_draminit.h"#include "jedec.h"/* ********************************************************************* * Initialized data * * WARNING WARNING WARNING! * * This module is *very magical*! We are using the cache as * SRAM, and we're running as relocatable code *before* the code * is relocated and *before* the GP register is set up. * * Therefore, there should be NO data declared in the data * segment - all data must be allocated in the .text segment * and references to this data must be calculated by an inline * assembly stub. * * If you grep the disassembly of this file, you should not see * ANY references to the GP register. ********************************************************************* */#ifdef _MCSTANDALONE_NOISY_static char *sb1250_rectypes[] = {"MCR_GLOBALS","MCR_CHCFG","MCR_TIMING", "MCR_CLKCFG","MCR_GEOM","MCR_CFG", "MCR_MANTIMING"};#endif/* ********************************************************************* * Module Description * * This module attempts to initialize the DRAM controllers on * the SB1250. Each DRAM controller can control four chip * selects, or two double-sided DDR SDRAM DIMMs. Therefore, at * most four DIMMs can be attached. * * We will assume that all of the DIMMs are connected to the same * SMBUS serial bus, and are addressed sequentially starting from * module 0. The first two DIMMs will be assigned to memory * controller #0 and the second two DIMMs will be assigned to * memory controller #1. * * There is one serial ROM per DIMM, and we will assume that the * front and back of the DIMM are the same memory configuration. * The first DIMM will be configured for CS0 and CS1, and the * second DIMM will be configured for CS2 and CS3. If the DIMM * has only one side, it will be assigned to CS0 or CS2. * * No interleaving will be configured by this routine, but it * should not be difficult to modify it should that be necessary. * * This entire routine needs to run from registers (no read/write * data is allowed). * * The steps to initialize the DRAM controller are: * * * Read the SPD, verify DDR SDRAMs or FCRAMs * * Obtain #rows, #cols, #banks, and module size * * Calculate row, column, and bank masks * * Calculate chip selects * * Calculate timing register. Note that we assume that * all banks will use the same timing. * * Repeat for each DRAM. * * DIMM0 -> MCTL0 : CS0, CS1 SPD Addr = 0x54 * DIMM1 -> MCTL0 : CS2, CS3 SPD Addr = 0x55 * DIMM2 -> MCTL1 : CS0, CS1 SPD Addr = 0x56 * DIMM3 -> MCTL1 : CS2, CS3 SPD Addr = 0x57 * * DRAM Controller registers are programmed in the following order: * * MC_CS_INTERLEAVE * MC_CS_ATTR * MC_TEST_DATA, MC_TEST_ECC * * MC_CSx_ROWS, MC_CSx_COLS * (repeated for each bank) * * MC_CS_START, MC_CS_END * * MC_CLOCK_CFG * (delay) * MC_TIMING * MC_CONFIG * (delay) * MC_DRAMMODE * (delay after each mode setting ??) * * Once the registers are initialized, the DRAM is activated by * sending it the following sequence of commands: * * PRE (precharge) * EMRS (extended mode register set) * MRS (mode register set) * PRE (precharge) * AR (auto-refresh) * AR (auto-refresh again) * MRS (mode register set) * * then wait 200 memory clock cycles without accessing DRAM. * * Following initialization, the ECC bits must be cleared. This * can be accomplished by disabling ECC checking on both memory * controllers, and then zeroing all memory via the mapping * in xkseg. ********************************************************************* *//* ********************************************************************* * * Address Bit Assignment Algorithm: * * Good performance can be achieved by taking the following steps * when assigning address bits to the row, column, and interleave * masks. You will need to know the following: * * - The number of rows, columns, and banks on the memory devices * - The block size (larger tends to be better for sequential * access) * - Whether you will interleave chip-selects * - Whether you will be using both memory controllers and want * to interleave between them * * By choosing the masks carefully you can maximize the number of * open SDRAM banks and reduce access times for nearby and sequential * accesses. * * The diagram below depicts a physical address and the order * that the bits should be placed into the masks. Start with the * least significant bit and assign bits to the row, column, bank, * and interleave registers in the following order: * * <------------Physical Address---------------> * Bits: RRRRRRR..R CCCCCCCC..C NN BB P CC xx000 * Step: 7 6 5 4 3 2 1 * * Where: * R = Row Address Bit (MC_CSX_ROW register) * C = Column Address Bit (MC_CSX_COL register) * N = Chip Select (MC_CS_INTERLEAVE) * (when interleaving via chip selects) * B = Bank Bit (MC_CSX_BA register) * P = Port Select bit (MC_CONFIG register) * (when interleaving memory channels) * x = Does not matter (MC_CSX_COL register) * (internally driven by controller) * 0 = must be zero * * When an address bit is "assigned" it is set in one of the masks * in the MC_CSX_ROW, MC_CSX_COL, MC_CSX_BA, or MC_CS_INTERLEAVE * registers. * * * 1. The bottom 3 bits are ignored and should be set to zero. * The next two bits are also ignored, but are considered * to be column bits, so they should be taken from the * total column bits supported by the device. * * 2. The next two bits are used for column interleave. For * 32-byte blocks (and no column interleave), do not use * any column bits. For 64-byte blocks, use one column * bit, and for 128 byte blocks, use two column bits. Subtract * the column bits assigned in this step from the total. * * 3. If you are using both memory controllers and wish to interleave * between them, assign one bit for the controller interleave. The * bit number is assigned in the MC_CONFIG register. * * 4. These bits represent the bank bits on the memory device. * If the device has 4 banks, assign 2 bits in the MC_CSX_BA * register. * * 5. If you are interleaving via chip-selects, set one or two * bits in the MC_CS_INTERLEAVE register for the bits that will * be interleaved. * * 6. The remaining column bits are assigned in the MC_CSX_COL * register. * * 7. The row bits are assigned in the MC_CSX_ROW register. * ********************************************************************* *//* ********************************************************************* * sb1250_find_timingcs(mc) * * For a given memory controller, choose the chip select whose * timing values will be used to base the TIMING and MCLOCK_CFG * registers on. * * Input parameters: * mc - memory controller * * Return value: * chip select index, or -1 if no active chip selects. ********************************************************************* */static int sb1250_find_timingcs(mcdata_t *mc){ int idx; /* for now, the first one with data is the one we pick */ for (idx = 0; idx < MC_CHIPSELS; idx++) { if (mc->csdata[idx].flags & CS_PRESENT) return idx; } return -1;}/* ********************************************************************* * sb1250_auto_timing(mcidx,tdata) * * Program the memory controller's timing registers based on the * timing information stored with the chip select data. For DIMMs * this information comes from the SPDs, otherwise it was entered * from the datasheets into the tables in the init modules. * * Input parameters: * mcidx - memory controller index (0 or 1) * tdata - a chip select data (csdata_t) * * Return value: * nothing ********************************************************************* */static void sb1250_auto_timing(int mcidx,mcdata_t *mc,csdata_t *tdata){ unsigned int res; unsigned int plldiv; unsigned int clk_ratio; unsigned int refrate; unsigned int ref_freq; unsigned int caslatency; unsigned int spd_tCK_25; unsigned int spd_tCK_20; unsigned int spd_tCK_10; unsigned int tCpuClk; unsigned int tMemClk; unsigned int w2rIdle,r2wIdle,r2rIdle; unsigned int tCrD,tCrDh,tFIFO; unsigned int tCwD; unsigned int tRAS; unsigned int tWR,tWTR; unsigned int tRP,tRRD,tRCD,tRCw,tRCr,tCwCr,tRFC; uint64_t timing1; uint64_t mclkcfg; sbport_t base; uint64_t sysrev; /* Timing window variables */ int addrSkew,dqiSkew,dqoSkew,clkDrive; int n01_open,n02_open,n12_open; int n01_close,n02_close,n12_close; int dqsArrival; int addrAdjust,dqiAdjust,dqoAdjust; int minDqsMargin; int dllScaleNum,dllScaleDenom,dllOffset; /* * We need our cpu clock for all sorts of things. */ sysrev = READCSR(PHYS_TO_K1(A_SCD_SYSTEM_REVISION));#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; } /* * Compute tCpuClk, in picoseconds to avoid rounding errors. * * Calculation: * tCpuClk = 1/fCpuClk * = 1/(100MHz * plldiv/2) * = 2/(100MHz*plldiv) * = 2/(100*plldiv) us * = 20/plldiv ns * = 2000000/plldiv 10ths of ns * * If SB1250_REFCLK is in MHz, then: * 2/(SB1250_REFCLK*plldiv) us * = 2000/(SB1250_REFCLK*plldiv) ns * = 2000000/(SB1250_REFCLK*plldiv) ps * * However, we want to round the result to the nearest integer, * so we double the numerator (to 4000000) to get one more bit * of precision in the quotient, then add one and scale it back down */ /* tCpuClk is in picoseconds */ tCpuClk = ((4000000/(SB1250_REFCLK*plldiv))+1)/2; spd_tCK_25 = DECTO10THS(tdata->spd_tCK_25); spd_tCK_20 = DECTO10THS(tdata->spd_tCK_20); spd_tCK_10 = DECTO10THS(tdata->spd_tCK_10); /* * Compute the target tMemClk, in units of tenths of nanoseconds * to be similar to the JEDEC SPD values. This will be * * MAX(MIN_tMEMCLK,spd_tCK_25) */ tMemClk = spd_tCK_25; if (mc->mintmemclk > tMemClk) tMemClk = mc->mintmemclk; /* * Now compute our clock ratio (the amount we'll divide tCpuClk by * to get as close as possible to tMemClk without exceeding it * * It's (tMemClk*100) here because tCpuClk is in picoseconds */ clk_ratio = ((tMemClk*100) + tCpuClk - 1) / tCpuClk; if (clk_ratio < 4) clk_ratio = 4; if (clk_ratio > 9) clk_ratio = 9; /* * BCM112x A1 parts do not function properly with MC ratio 5. * (This is fixed in A2 parts.) On BCM112x before A2, When * that ratio would be used, back off to 6. */ 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) && G_SYS_REVISION(sysrev) < K_SYS_REVISION_BCM112x_A2 && clk_ratio == 5) { clk_ratio = 6; } /* * Now, recompute tMemClk using the new clk_ratio. This gives us * the actual tMemClk that the memory controller will generate * * Calculation: * fMemClk = SB1250_REFCLK * plldiv / (2 * clk_ratio) Mhz * * tMemClk = 1/fMemClk us * = (2 * clk_ratio) / (SB1250_REFCLK * plldiv) us * = 10000 * (2 * clk_ratio) / (SB1250_REFCLK * plldiv) 0.1ns * * The resulting tMemClk is in tenths of nanoseconds so we * can compare it with the SPD values. The x10000 converts * us to 0.1ns */new_ratio: tMemClk = (10000 * 2 * clk_ratio)/(SB1250_REFCLK * plldiv); /* Calculate the refresh rate */ switch (tdata->spd_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; } /* * Compute the target refresh value, in Khz/16. We know * the rate that the DIMMs expect (in Khz, above). So we need * to calculate what the MemClk is divided by to get that value. * There is an internal divide-by-16 in the 1250 in the refresh * generation. * * Calculation: * refrate = (plldiv/2)*SB1250_REFCLK*1000 Khz /(ref_freq*16*clk_ratio) */ refrate = ((plldiv * SB1250_REFCLK * 1000 / 2) / (ref_freq*16*clk_ratio)) - 1; /* * 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_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 */ }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -