📄 bcm1480_draminit.c
字号:
clk_ratio = clk_ratio * 2; if (clk_ratio < 4) clk_ratio = 4; if (clk_ratio > 24) clk_ratio = 24; /* recompute tMemClk using the new clk_ratio */ tMemClk = (10000 * clk_ratio)/(BCM1480_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 * BCM1480_REFCLK * 1000 / 2) / (ref_freq*32*clk_ratio)) - 1; timing1 = mc->mantiming; base = PHYS_TO_K1(A_BCM1480_MC_BASE(mcidx)); WRITECSR(base+R_BCM1480_MC_TIMING1,timing1); 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_SMBUS_INIT() * * Initialize SMBUS channel * * Input parameters: * chan - SMBus channel number, 0 or 1 * * Return value: * smbus_base - KSEG1 address of SMBus channel * * Registers used: * tmp0 ********************************************************************* */static sbport_t bcm1480_smbus_init(int chan){ sbport_t base; base = PHYS_TO_K1(A_SMB_BASE(chan)); WRITECSR(base+R_SMB_FREQ,K_SMB_FREQ_100KHZ); WRITECSR(base+R_SMB_CONTROL,0); return base;} /* ********************************************************************* * BCM1480_SMBUS_WAITREADY() * * Wait for SMBUS channel to be ready. * * Input parameters: * smbus_base - SMBus channel base (K1seg addr) * * Return value: * ret0 - 0 if no error occured, else -1 * * Registers used: * tmp0,tmp1 ********************************************************************* */static int bcm1480_smbus_waitready(sbport_t base){ uint64_t status; /* * Wait for busy bit to clear */ for (;;) { status = READCSR(base+R_SMB_STATUS); if (!(status & M_SMB_BUSY)) break; } /* * Isolate error bit and clear error status */ status &= M_SMB_ERROR; WRITECSR(base+R_SMB_STATUS,status); /* * Return status */ return (status) ? -1 : 0;}/* ********************************************************************* * BCM1480_SMBUS_READBYTE() * * Read a byte from a serial ROM attached to an SMBus channel * * Input parameters: * base - SMBus channel base address (K1seg addr) * dev - address of device on SMBUS * offset - address of byte within device on SMBUS * * Return value: * byte from device (-1 indicates an error) ********************************************************************* */static int bcm1480_smbus_readbyte(sbport_t base,unsigned int dev,unsigned int offset){ int res; /* * Wait for channel to be ready */ res = bcm1480_smbus_waitready(base); if (res < 0) return res; /* * Set up a READ BYTE command. This command has no associated * data field, the command code is the data */ WRITECSR(base+R_SMB_CMD,offset); WRITECSR(base+R_SMB_START,dev | V_SMB_TT(K_SMB_TT_CMD_RD1BYTE)); /* * Wait for the command to complete */ res = bcm1480_smbus_waitready(base); if (res < 0) return res; /* * Return the data byte */ return (int) ((READCSR(base+R_SMB_DATA)) & 0xFF);}/* ********************************************************************* * BCM1480_DRAM_GETINFO * * Process a single init table entry and move data into the * memory controller's data structure. * * Input parameters: * smbase - points to base of SMbus device to read from * mc - memory controller data * init - pointer to current user init table entry * * Return value: * nothing ********************************************************************* */static void bcm1480_dram_getinfo(unsigned int smbchan, unsigned int smbdev, mcdata_t *mc, int chipsel){ int res; unsigned char spd[JEDEC_SPD_SIZE]; int idx; csdata_t *cs = &(mc->csdata[chipsel]); sbport_t smbase; smbase = bcm1480_smbus_init(smbchan); /* * Read just the memory type to see if the RAM is present. */ res = bcm1480_smbus_readbyte(smbase,smbdev,JEDEC_SPD_MEMTYPE); if ((res < 0) || ((res != JEDEC_MEMTYPE_DDRSDRAM) && (res != JEDEC_MEMTYPE_DDRSDRAM2) && (res != SPD_MEMTYPE_FCRAM))) { return; /* invalid or no memory installed */ } /* * Now go back and read everything. */ res = 0; for (idx = 0; idx < JEDEC_SPD_SIZE; idx++) { res = bcm1480_smbus_readbyte(smbase,smbdev,idx); if (res < 0) break; spd[idx] = res; } if (res < 0) return; /* some SMBus error */ cs->rows = spd[JEDEC_SPD_ROWS]; cs->cols = spd[JEDEC_SPD_COLS]; /* * Determine how many bits the banks represent. Unlike * the rows/columns, the bank byte says how *many* banks * there are, not how many bits represent banks */ switch (spd[JEDEC_SPD_BANKS]) { case 2: /* 2 banks = 1 bits */ cs->banks = 1; break; case 4: /* 4 banks = 2 bits */ cs->banks = 2; break; case 8: /* 8 banks = 3 bits */ cs->banks = 3; break; case 16: /* 16 banks = 4 bits */ cs->banks = 4; break; default: /* invalid bank count */ return; } /* * Read timing parameters from the DIMM. By this time we kind of trust */ cs->spd_dramtype = spd[JEDEC_SPD_MEMTYPE]; cs->spd_tCK_25 = spd[JEDEC_SPD_tCK25]; cs->spd_tCK_20 = spd[JEDEC_SPD_tCK20]; cs->spd_tCK_10 = spd[JEDEC_SPD_tCK10]; cs->spd_rfsh = spd[JEDEC_SPD_RFSH]; cs->spd_caslatency = spd[JEDEC_SPD_CASLATENCIES]; cs->spd_attributes = spd[JEDEC_SPD_ATTRIBUTES]; cs->spd_tRAS = spd[JEDEC_SPD_tRAS]; cs->spd_tRP = spd[JEDEC_SPD_tRP]; cs->spd_tRRD = spd[JEDEC_SPD_tRRD]; cs->spd_tRCD = spd[JEDEC_SPD_tRCD]; cs->spd_tRFC = spd[JEDEC_SPD_tRFC]; cs->spd_tRC = spd[JEDEC_SPD_tRC]; /* * Okay, we got all the required data. mark this CS present. */ cs->flags = CS_PRESENT | CS_AUTO_TIMING; /* * If the module width is not 72 for any DIMM, disable ECC for this * channel. All DIMMs must support ECC for us to enable it. */ if (spd[JEDEC_SPD_WIDTH] != 72) mc->flags &= ~MCFLG_ECC_ENABLE; /* * If it was a double-sided DIMM, also mark the odd chip select * present. */ if ((spd[JEDEC_SPD_SIDES] == 2) && !(mc->flags & MCFLG_BIGMEM)) { csdata_t *oddcs = &(mc->csdata[chipsel | 1]); oddcs->rows = cs->rows; oddcs->cols = cs->cols; oddcs->banks = cs->banks; oddcs->flags = CS_PRESENT; oddcs->spd_dramtype = spd[JEDEC_SPD_MEMTYPE]; oddcs->spd_tCK_25 = spd[JEDEC_SPD_tCK25]; oddcs->spd_tCK_20 = spd[JEDEC_SPD_tCK20]; oddcs->spd_tCK_10 = spd[JEDEC_SPD_tCK10]; oddcs->spd_rfsh = spd[JEDEC_SPD_RFSH]; oddcs->spd_caslatency = spd[JEDEC_SPD_CASLATENCIES]; oddcs->spd_attributes = spd[JEDEC_SPD_ATTRIBUTES]; oddcs->spd_tRAS = spd[JEDEC_SPD_tRAS]; oddcs->spd_tRP = spd[JEDEC_SPD_tRP]; oddcs->spd_tRRD = spd[JEDEC_SPD_tRRD]; oddcs->spd_tRCD = spd[JEDEC_SPD_tRCD]; oddcs->spd_tRFC = spd[JEDEC_SPD_tRFC]; oddcs->spd_tRC = spd[JEDEC_SPD_tRC]; }}/* ********************************************************************* * BCM1480_DRAM_READPARAMS(d,init) * * Read all the parameters from the user parameter table and * digest them into our local data structure. This routine basically * walks the table and calls the routine above to handle each * entry. * * Input parameters: * d - our data structure (our RAM data) * init - pointer to user config table * * Return value: * nothing ********************************************************************* */static void bcm1480_dram_readparams(initdata_t *d,const draminittab_t *init){ mcdata_t *mc; csdata_t *cs; /* Assume we're staring on the first channel */ mc = &(d->mc[MC_FIRSTCHANNEL]); cs = &(mc->csdata[0]); while (init->mcr.mcr_type != MCR_EOT) {#ifdef _MCSTANDALONE_NOISY_ printf("DRAM: Processing record '%s'\n",bcm1480_rectypes[init->mcr.mcr_type]);#endif switch (init->mcr.mcr_type) { case MCR_GLOBALS: /* Channel interleave type */ d->cfg_chanintlv_type = init->gbl.gbl_intlv_ch; break; case MCR_CHCFG: mc = &(d->mc[init->cfg.cfg_chan]); mc->mintmemclk = DECTO10THS(init->cfg.cfg_mintmemclk); mc->chantype = init->cfg.cfg_chantype; mc->dramtype = init->cfg.cfg_dramtype; mc->pagepolicy = init->cfg.cfg_pagepolicy; mc->cfgcsint = init->cfg.cfg_intlv_cs; mc->dllcfg = V_MC_DLLCONFIG_ADJ_DEFAULT; /* Default unless overridden */ mc->drvcfg = V_MC_DRVCONFIG_CLASS_DEFAULT; /* Default, no overridding */ mc->flags = (init->cfg.cfg_ecc & (MCFLG_ECC_ENABLE | MCFLG_ECC_FORCE64)) | (init->cfg.cfg_flags & (MCFLG_FORCEREG | MCFLG_BIGMEM)); mc->roundtrip = DECTO10THS(init->cfg.cfg_roundtrip); if (mc->roundtrip == 0 && mc->dramtype != DRAM_TYPE_SPD) { /* * Only set default roundtrip if mem type is specified, else wait * to get type from SPD */ mc->roundtrip = (mc->dramtype == FCRAM) ? DEFAULT_MEMORY_ROUNDTRIP_TIME_FCRAM : DEFAULT_MEMORY_ROUNDTRIP_TIME; } if (mc->dramtype == FCRAM) mc->pagepolicy = CLOSED; /*FCRAM must be closed page policy*/ cs = &(mc->csdata[0]); break; case MCR_TIMING: cs->spd_tCK_25 = init->tmg.tmg_tCK; cs->spd_tCK_20 = 0; cs->spd_tCK_10 = 0; cs->spd_rfsh = init->tmg.tmg_rfsh; cs->spd_caslatency = init->tmg.tmg_caslatency; cs->spd_attributes = init->tmg.tmg_attributes; cs->spd_tRAS = init->tmg.tmg_tRAS; cs->spd_tRP = init->tmg.tmg_tRP; cs->spd_tRRD = init->tmg.tmg_tRRD; cs->spd_tRCD = init->tmg.tmg_tRCD; cs->spd_tRFC = init->tmg.tmg_tRFC; cs->spd_tRC = init->tmg.tmg_tRC; break; case MCR_DLLCFG: mc->dllcfg = V_BCM1480_MC_ADDR_COARSE_ADJ(init->dll.dll_addrcoarse) | V_BCM1480_MC_ADDR_FINE_ADJ(init->dll.dll_addrfine) | V_BCM1480_MC_DQI_COARSE_ADJ(init->dll.dll_dqicoarse) | V_BCM1480_MC_DQI_FINE_ADJ(init->dll.dll_dqifine) | V_BCM1480_MC_DQO_COARSE_ADJ(init->dll.dll_dqocoarse) | V_BCM1480_MC_DQO_FINE_ADJ(init->dll.dll_dqofine); break; case MCR_GEOM:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -