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

📄 sb1250_draminit.c

📁 一个很好的嵌入式linux平台下的bootloader
💻 C
📖 第 1 页 / 共 5 页
字号:
#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 + -