diff options
Diffstat (limited to 'cfe/cfe/hosttools/memconfig.c')
-rw-r--r-- | cfe/cfe/hosttools/memconfig.c | 654 |
1 files changed, 654 insertions, 0 deletions
diff --git a/cfe/cfe/hosttools/memconfig.c b/cfe/cfe/hosttools/memconfig.c new file mode 100644 index 0000000..3d84b05 --- /dev/null +++ b/cfe/cfe/hosttools/memconfig.c @@ -0,0 +1,654 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * Memory Config Utility File: memconfig.c + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + * This host tool lets you enter DRAM parameters and run CFE's + * standard memory configuration to calculate the relevant timing + * parameters. It's a good way to see what CFE would have done, + * to find bogus timing calculations. + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + +#include <stdio.h> +#include <string.h> + +/* ********************************************************************* + * Basic types + ********************************************************************* */ + +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef unsigned long uint32_t; +typedef unsigned long long uint64_t; + +/* ********************************************************************* + * SB1250 stuff + ********************************************************************* */ + +#include "sb1250_defs.h" +#include "sb1250_mc.h" +#include "sb1250_draminit.h" +#include "sb1250_regs.h" +#include "sb1250_scd.h" + +/* ********************************************************************* + * BCD macros + ********************************************************************* */ + +#define DECTO10THS(x) ((((x) >> 4)*10)+((x) & 0x0F)) + +/* ********************************************************************* + * Global defaults + ********************************************************************* */ + +#define MIN_tMEMCLK DRT10(8,0) +#define tROUNDTRIP DRT10(2,5) + +/* ********************************************************************* + * Types + ********************************************************************* */ + +typedef struct encvalue_s { + char *name; + uint8_t val; +} encvalue_t; + +typedef struct spdbyte_s { + char *name; + uint8_t *data; + int decimal; + encvalue_t *values; + char *units; + char *description; + char *deflt; +} spdbyte_t; + +#define SPD_DEC_BCD 1 +#define SPD_DEC_QTR 2 +#define SPD_ENCODED 3 +#define SPD_ENCODED2 4 + +/* ********************************************************************* + * Globals + ********************************************************************* */ + + +uint8_t spd[64] = {0}; /* SPD data */ +uint8_t mintmemclk = MIN_tMEMCLK; /* Default value: 8.0ns */ +uint8_t roundtrip = tROUNDTRIP; /* Default value: 2.5ns */ +uint8_t dramtype = JEDEC; /* Regular DDR SDRAMs */ +uint8_t plldiv = 10; /* 500 MHz using 100Mhz refclk */ +uint8_t refclk = 100; /* 100Mhz reference clock */ +uint8_t portintlv = 0; /* no port interleaving */ + +uint8_t addrskew = 0xF; +uint8_t dqoskew = 0x8; +uint8_t dqiskew = 0x8; +uint8_t addrdrive = 0xF; +uint8_t datadrive = 0xF; +uint8_t clkdrive = 0; + +uint64_t mc0_mclkcfg; /* Value programmed by draminit */ +uint64_t mc0_timing1; /* Value programmed by draminit */ +uint64_t smbus0_start = 0; /* Rememberd SMBus register value */ +uint64_t smbus0_cmd = 0; /* Rememberd SMBus register value */ + +extern int sb1250_refclk; /* from draminit - reference clock */ +extern int dram_cas_latency; /* from draminit - calc'd cas latency */ +extern int dram_tMemClk; /* from draminit - calc'd tMemClk */ + +draminittab_t inittab[16]; /* our init tab */ + +int debug = 0; + +/* ********************************************************************* + * Parameter and value tables + ********************************************************************* */ + +encvalue_t caslatencies[] = { + {"3.5",JEDEC_CASLAT_35}, + {"3.0",JEDEC_CASLAT_30}, + {"2.5",JEDEC_CASLAT_25}, + {"2.0",JEDEC_CASLAT_20}, + {"1.5",JEDEC_CASLAT_15}, + {"1.0",JEDEC_CASLAT_10}, + {NULL,0}}; + +encvalue_t refreshrates[] = { + {"64",JEDEC_RFSH_64khz}, + {"256",JEDEC_RFSH_256khz}, + {"128",JEDEC_RFSH_128khz}, + {"32",JEDEC_RFSH_32khz}, + {"16",JEDEC_RFSH_16khz}, + {"8",JEDEC_RFSH_8khz}, + {NULL,0}}; + +encvalue_t modattribs[] = { + {"none",0}, + {"reg",JEDEC_ATTRIB_REG}, + {"diffclk",0x20}, + {NULL,0}}; + +encvalue_t dramtypes[] = { + {"jedec",JEDEC}, + {"fcram",FCRAM}, + {"sgram",SGRAM}, + {NULL,0}}; + +spdbyte_t spdfields[] = { + {"mintmemclk",&mintmemclk,SPD_DEC_BCD,NULL,"ns","Minimum value for tMEMCLK","8.0"}, + {"roundtrip", &roundtrip, SPD_DEC_BCD,NULL,"ns","Round trip time from CLK to returned DQS","2.5"}, + {"plldiv", &plldiv, 0,NULL,"","PLL Ratio (System Config Register)","10"}, + {"refclk", &refclk, 0,NULL,"Mhz","Reference clock, usually 100Mhz","100"}, +// {"portintlv", &portintlv, 0,NULL,"","Port interleave (1=on)","0"}, + {"memtype", &dramtype, SPD_ENCODED,dramtypes,"","Memory type (jedec, fcram, sgram)","jedec"}, + {"rows", &spd[JEDEC_SPD_ROWS],0,NULL,"","[3 ] Number of row bits","13"}, + {"cols", &spd[JEDEC_SPD_COLS],0,NULL,"","[4 ] Number of column bits","9"}, + {"banks", &spd[JEDEC_SPD_BANKS],0,NULL,"","[17] Number of banks","4"}, + {"tCK25", &spd[JEDEC_SPD_tCK25],SPD_DEC_BCD,NULL,"ns","[9 ] tCK value for CAS Latency 2.5","7.5"}, + {"tCK20", &spd[JEDEC_SPD_tCK20],SPD_DEC_BCD,NULL,"ns","[23] tCK value for CAS Latency 2.0","0"}, + {"tCK10", &spd[JEDEC_SPD_tCK10],SPD_DEC_BCD,NULL,"ns","[25] tCK value for CAS Latency 1.0","0"}, + {"rfsh", &spd[JEDEC_SPD_RFSH],SPD_ENCODED,refreshrates,"","[12] Refresh rate (KHz)","8"}, + {"caslat", &spd[JEDEC_SPD_CASLATENCIES],SPD_ENCODED2,caslatencies,"","[18] CAS Latencies supported","2.5"}, + {"attrib", &spd[JEDEC_SPD_ATTRIBUTES],SPD_ENCODED,modattribs,"","[21] Module attributes","none"}, + {"tRAS", &spd[JEDEC_SPD_tRAS],0,NULL,"ns","[30]","45"}, + {"tRP", &spd[JEDEC_SPD_tRP],SPD_DEC_QTR,NULL,"ns","[27]","20.0"}, + {"tRRD", &spd[JEDEC_SPD_tRRD],SPD_DEC_QTR,NULL,"ns","[28]","15.0"}, + {"tRCD", &spd[JEDEC_SPD_tRCD],SPD_DEC_QTR,NULL,"ns","[29]","20.0"}, + {"tRFC", &spd[JEDEC_SPD_tRFC],0,NULL,"ns","[42]","0"}, + {"tRC", &spd[JEDEC_SPD_tRC],0,NULL,"ns","[41]","0"}, + + {"addrskew", &addrskew, 0, NULL, "","Address Skew","0x0F"}, + {"dqoskew", &dqoskew, 0, NULL, "","DQO Skew","0x08"}, + {"dqikew", &dqiskew, 0, NULL, "","DQI Skew","0x08"}, + {"addrdrive", &addrdrive, 0, NULL, "","Address Drive","0x0F"}, + {"datadrive", &datadrive, 0, NULL, "","Data Drive","0x0F"}, + {"clkdrive", &clkdrive, 0, NULL, "","Clock Drive","0"}, + {NULL,0,0,NULL,NULL,NULL,NULL}}; + +char *lookupstr(encvalue_t *ev,uint8_t val) +{ + while (ev->name) { + if (ev->val == val) return ev->name; + ev++; + } + return "unknown"; +} + +uint64_t sbreadcsr(uint64_t reg) +{ + uint64_t val = 0; + + if (debug) printf("READ %08X\n",(uint32_t) reg); + + switch ((uint32_t) reg) { + case A_SCD_SYSTEM_REVISION: + val = V_SYS_PART(0x1250) | V_SYS_WID(0) | V_SYS_REVISION(1) | 0xFF; + break; + case A_SCD_SYSTEM_CFG: + val = V_SYS_PLL_DIV(plldiv); + break; + case A_SMB_STATUS_0: + val = 0; + break; + case A_SMB_CMD_0: + val = smbus0_cmd; + break; + case A_SMB_START_0: + val = smbus0_start; + break; + case A_SMB_DATA_0: + val = spd[smbus0_cmd & 0x3F]; + break; + } + return val; +} + +void sbwritecsr(uint64_t reg,uint64_t val) +{ + if (debug) printf("WRITE %08X %016llX\n",(uint32_t) reg,val); + + switch ((uint32_t) reg) { + case A_MC_REGISTER(0,R_MC_MCLK_CFG): + mc0_mclkcfg = val; + break; + case A_MC_REGISTER(0,R_MC_TIMING1): + mc0_timing1 = val; + break; + case A_SMB_CMD_0: + smbus0_cmd = val; + break; + case A_SMB_START_0: + smbus0_start = val; + break; + } +} + + +int procfield(char *txt) +{ + int num = 0; + int a,b; + spdbyte_t *sf; + encvalue_t *ev; + char *x; + char *tok; + + x = strchr(txt,'='); + if (!x) { + printf("Fields must be specified as 'name=value'\n"); + exit(1); + } + *x++ = '\0'; + + sf = spdfields; + while (sf->name) { + if (strcmp(sf->name,txt) == 0) break; + sf++; + } + + if (sf->name == NULL) { + printf("Invalid field name: %s\n",txt); + return -1; + } + + if (memcmp(x,"0x",2) == 0) { + sscanf(x+2,"%x",&num); + } + else { + if (strchr(x,'.')) { + if (sscanf(x,"%d.%d",&a,&b) != 2) { + printf("%s: invalid number: %s\n",sf->name,x); + return -1; + } + } + else { + a = atoi(x); + b = 0; + } + + switch (sf->decimal) { + case SPD_DEC_BCD: + if ((b < 0) || (b > 9)) { + printf("%s: Invalid BCD number: %s\n",sf->name,x); + return -1; + } + num = (a*16)+b; + break; + case SPD_DEC_QTR: + if ((b != 0) && (b != 25) && (b != 50) && (b != 75)) { + printf("%s: Invalid 2-bit fraction number: %s\n",sf->name,x); + printf("(number after decimal should be 0,25,50,75)\n"); + exit(1); + } + num = (a*4)+(b/25); + break; + case SPD_ENCODED: + ev = sf->values; + while (ev->name) { + if (strcmp(ev->name,x) == 0) break; + ev++; + } + if (!ev->name) { + printf("%s: Invalid value. Valid values are: ",x); + ev = sf->values; + while (ev->name) { printf("%s ",ev->name); ev++; } + printf("\n"); + return -1; + } + num = ev->val; + break; + case SPD_ENCODED2: + tok = strtok(x," ,"); + num = 0; + while (tok) { + ev = sf->values; + while (ev->name) { + if (strcmp(ev->name,tok) == 0) break; + ev++; + } + if (!ev->name) { + printf("%s: Invalid value. Valid values are: ",tok); + ev = sf->values; + while (ev->name) { printf("%s ",ev->name); ev++; } + printf("\n"); + return -1; + } + num |= ev->val; + tok = strtok(NULL," ,"); + } + break; + default: + num = a; + break; + } + } + + *(sf->data) = num; + + return 0; +} + +void interactive(void) +{ + spdbyte_t *sf; + char field[100]; + char ask[100]; + char prompt[100]; + char *x; + + sf = spdfields; + + printf("%-65.65s: Value\n","Parameter"); + printf("%-65.65s: -----\n","-----------------------------------------------------------------"); + + while (sf->name) { + for (;;) { + x = prompt; + x += sprintf(x,"%s (%s", sf->name,sf->description); + if (sf->units && sf->units[0]) { + if (sf->description && sf->description[0]) x += sprintf(x,", "); + x += sprintf(x,"%s",sf->units); + } + x += sprintf(x,"): [%s]", sf->deflt); + printf("%-65.65s: ",prompt); + + fgets(ask,sizeof(ask),stdin); + if ((x = strchr(ask,'\n'))) *x = '\0'; + if (ask[0] == 0) strcpy(ask,sf->deflt); + sprintf(field,"%s=%s",sf->name,ask); + if (procfield(field) < 0) continue; + break; + } + sf++; + } + + printf("\n\n"); +} + +int swcnt = 0; +char *swnames[32]; + +int proc_args(int argc,char *argv[]) +{ + int inidx,outidx; + + outidx = 1; + + for (inidx = 1; inidx < argc; inidx++) { + if (argv[inidx][0] != '-') { + argv[outidx++] = argv[inidx]; + } + else { + swnames[swcnt] = argv[inidx]; + swcnt++; + } + } + + return outidx; +} + +int swisset(char *x) +{ + int idx; + + for (idx = 0; idx < swcnt; idx++) { + if (strcmp(x,swnames[idx]) == 0) return 1; + } + return 0; +} + +void dumpmclkcfg(uint64_t val) +{ + printf("clk_ratio = %d\n",G_MC_CLK_RATIO(val)); + printf("ref_rate = %d\n",G_MC_REF_RATE(val)); + +} + +void dumptiming1(uint64_t val) +{ + printf("w2rIdle = %d\n",(val & M_MC_w2rIDLE_TWOCYCLES) ? 1 : 0); + printf("r2rIdle = %d\n",(val & M_MC_r2rIDLE_TWOCYCLES) ? 1 : 0); + printf("r2wIdle = %d\n",(val & M_MC_r2wIDLE_TWOCYCLES) ? 1 : 0); + printf("tCrD = %d\n",(int)G_MC_tCrD(val)); + printf("tCrDh = %d\n",(val & M_MC_tCrDh) ? 1 : 0); + printf("tFIFO = %d\n",(int)G_MC_tFIFO(val)); + printf("tCwD = %d\n",(int)G_MC_tCwD(val)); + + printf("tRP = %d\n",(int)G_MC_tRP(val)); + printf("tRRD = %d\n",(int)G_MC_tRRD(val)); + printf("tRCD = %d\n",(int)G_MC_tRCD(val)); + + printf("tRFC = %d\n",(int)G_MC_tRFC(val)); + printf("tRCw = %d\n",(int)G_MC_tRCw(val)); + printf("tRCr = %d\n",(int)G_MC_tRCr(val)); + printf("tCwCr = %d\n",(int)G_MC_tCwCr(val)); +} + +int main(int argc,char *argv[]) +{ + spdbyte_t *sf; + uint8_t t; + int idx; + int mclk; + draminittab_t *init; + + spd[JEDEC_SPD_MEMTYPE] = JEDEC_MEMTYPE_DDRSDRAM2; + spd[JEDEC_SPD_ROWS] = 13; + spd[JEDEC_SPD_COLS] = 9; + spd[JEDEC_SPD_BANKS] = 2; + spd[JEDEC_SPD_SIDES] = 1; + spd[JEDEC_SPD_WIDTH] = 72; + + argc = proc_args(argc,argv); + + if ((argc == 1) && !swisset("-i")) { + printf("usage: memconfig name=value name=value ...\n"); + printf("\n"); + printf("Available fields: "); + sf = spdfields; + while (sf->name) { + printf("%s ",sf->name); + sf++; + } + printf("\n"); + exit(1); + } + + if (swisset("-i")) { + interactive(); + } + else { + for (idx = 1; idx < argc; idx++) { + if (procfield(argv[idx]) < 0) exit(1); + } + } + + debug = swisset("-d"); + + printf("-------Memory Parameters---------\n"); + + sf = spdfields; + while (sf->name) { + char buffer[64]; + char *p = buffer; + + t = *(sf->data); + printf("%-10.10s = 0x%02X ",sf->name,t); + switch (sf->decimal) { + case SPD_DEC_BCD: + p += sprintf(p,"(%d.%d)", + t >> 4, t & 0x0F); + break; + case SPD_DEC_QTR: + p += sprintf(p,"(%d.%02d)", + t/4,(t&3)*25); + break; + case SPD_ENCODED: + p += sprintf(p,"(%s)",lookupstr(sf->values,t)); + break; + default: + p += sprintf(p,"(%d)",t); + break; + } + + p += sprintf(p," %s",sf->units); + printf("%-16.16s %s\n",buffer,sf->description); + sf++; + } + + printf("\n"); + + init = &inittab[0]; + memset(inittab,0,sizeof(inittab)); + + init->gbl.gbl_type = MCR_GLOBALS; + init->gbl.gbl_intlv_ch = portintlv; + init++; + + init->cfg.cfg_type = MCR_CHCFG; + init->cfg.cfg_chan = 0; + init->cfg.cfg_mintmemclk = mintmemclk; + init->cfg.cfg_dramtype = dramtype; + init->cfg.cfg_pagepolicy = CASCHECK; + init->cfg.cfg_blksize = BLKSIZE32; + init->cfg.cfg_intlv_cs = NOCSINTLV; + init->cfg.cfg_ecc = 0; + init->cfg.cfg_roundtrip = roundtrip; + init++; + + init->clk.clk_type = MCR_CLKCFG; + init->clk.clk_addrskew = addrskew; + init->clk.clk_dqoskew = dqoskew; + init->clk.clk_dqiskew = dqiskew; + init->clk.clk_addrdrive = addrdrive; + init->clk.clk_datadrive = datadrive; + init->clk.clk_clkdrive = clkdrive; + init++; + + init->geom.geom_type = MCR_GEOM; + init->geom.geom_csel = 0; + init->geom.geom_rows = spd[JEDEC_SPD_ROWS]; + init->geom.geom_cols = spd[JEDEC_SPD_COLS]; + init->geom.geom_banks = spd[JEDEC_SPD_BANKS]; + init++; + +#if 0 + init->tmg.tmg_type = MCR_TIMING; + init->tmg.tmg_tCK = spd[JEDEC_SPD_tCK25]; + init->tmg.tmg_rfsh = spd[JEDEC_SPD_RFSH]; + init->tmg.tmg_caslatency = spd[JEDEC_SPD_CASLATENCIES]; + init->tmg.tmg_attributes = spd[JEDEC_SPD_ATTRIBUTES]; + init->tmg.tmg_tRAS = spd[JEDEC_SPD_tRAS]; + init->tmg.tmg_tRP = spd[JEDEC_SPD_tRP]; + init->tmg.tmg_tRRD = spd[JEDEC_SPD_tRRD]; + init->tmg.tmg_tRCD = spd[JEDEC_SPD_tRCD]; + init->tmg.tmg_tRFC = spd[JEDEC_SPD_tRFC]; + init->tmg.tmg_tRC = spd[JEDEC_SPD_tRC]; + init++; +#else + init->spd.spd_type = MCR_SPD; + init->spd.spd_csel = 0; + init->spd.spd_flags = 0; + init->spd.spd_smbuschan = 0; + init->spd.spd_smbusdev = 0x50; + init++; +#endif + + init->mcr.mcr_type = MCR_EOT; + + + sb1250_refclk = (int) refclk; + + sb1250_dram_init(inittab); + + + printf("-----Memory Timing Register Values-----\n"); + printf("System Clock %dMHz\n",plldiv*refclk/2); + printf("CAS latency %d.%d\n",dram_cas_latency>>1,(dram_cas_latency&1)?5:0); + printf("tMemClk %d.%d ns\n",dram_tMemClk/10,dram_tMemClk%10); + mclk = (plldiv*refclk)*10/2/((int)G_MC_CLK_RATIO(mc0_mclkcfg)); + printf("MCLK Freq %d.%dMHz\n",mclk/10,mclk%10); + printf("\n"); + printf("MC_TIMING1 = %016llX\n",mc0_timing1); + printf("MCLK_CONFIG = %016llX\n",mc0_mclkcfg); + printf("\n"); + + printf("-----Memory Timing Register Fields-----\n"); + dumptiming1(mc0_timing1); + + printf("-----Memory Clock Config Register Fields-----\n"); + dumpmclkcfg(mc0_mclkcfg); + + printf("---Done!---\n"); + + printf("%s ",argv[0]); + sf = spdfields; + while (sf->name) { + char buffer[64]; + char *p = buffer; + + t = *(sf->data); + + p += sprintf(p,"%s=",sf->name); + switch (sf->decimal) { + case SPD_DEC_BCD: + p += sprintf(p,"%d.%d", + t >> 4, t & 0x0F); + break; + case SPD_DEC_QTR: + p += sprintf(p,"%d.%02d", + t/4,(t&3)*25); + break; + case SPD_ENCODED: + default: + p += sprintf(p,"0x%02X",t); + break; + } + + printf("%s ",buffer); + sf++; + } + + printf("\n"); + + return 0; +} |