1 /* *********************************************************************
2 * Broadcom Common Firmware Environment (CFE)
4 * Memory Config Utility File: memconfig.c
6 * Author: Mitch Lichtenberg (mpl@broadcom.com)
8 * This host tool lets you enter DRAM parameters and run CFE's
9 * standard memory configuration to calculate the relevant timing
10 * parameters. It's a good way to see what CFE would have done,
11 * to find bogus timing calculations.
13 *********************************************************************
15 * Copyright 2000,2001,2002,2003
16 * Broadcom Corporation. All rights reserved.
18 * This software is furnished under license and may be used and
19 * copied only in accordance with the following terms and
20 * conditions. Subject to these conditions, you may download,
21 * copy, install, use, modify and distribute modified or unmodified
22 * copies of this software in source and/or binary form. No title
23 * or ownership is transferred hereby.
25 * 1) Any source code used, modified or distributed must reproduce
26 * and retain this copyright notice and list of conditions
27 * as they appear in the source file.
29 * 2) No right is granted to use any trade name, trademark, or
30 * logo of Broadcom Corporation. The "Broadcom Corporation"
31 * name may not be used to endorse or promote products derived
32 * from this software without the prior written permission of
33 * Broadcom Corporation.
35 * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR
36 * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED
37 * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
38 * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT
39 * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN
40 * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT,
41 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
42 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
43 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
44 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
45 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
46 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF
47 * THE POSSIBILITY OF SUCH DAMAGE.
48 ********************************************************************* */
53 /* *********************************************************************
55 ********************************************************************* */
57 typedef unsigned char uint8_t;
58 typedef unsigned short uint16_t;
59 typedef unsigned long uint32_t;
60 typedef unsigned long long uint64_t;
62 /* *********************************************************************
64 ********************************************************************* */
66 #include "sb1250_defs.h"
67 #include "sb1250_mc.h"
68 #include "sb1250_draminit.h"
69 #include "sb1250_regs.h"
70 #include "sb1250_scd.h"
72 /* *********************************************************************
74 ********************************************************************* */
76 #define DECTO10THS(x) ((((x) >> 4)*10)+((x) & 0x0F))
78 /* *********************************************************************
80 ********************************************************************* */
82 #define MIN_tMEMCLK DRT10(8,0)
83 #define tROUNDTRIP DRT10(2,5)
85 /* *********************************************************************
87 ********************************************************************* */
89 typedef struct encvalue_s
{
94 typedef struct spdbyte_s
{
104 #define SPD_DEC_BCD 1
105 #define SPD_DEC_QTR 2
106 #define SPD_ENCODED 3
107 #define SPD_ENCODED2 4
109 /* *********************************************************************
111 ********************************************************************* */
114 uint8_t spd
[64] = {0}; /* SPD data */
115 uint8_t mintmemclk
= MIN_tMEMCLK
; /* Default value: 8.0ns */
116 uint8_t roundtrip
= tROUNDTRIP
; /* Default value: 2.5ns */
117 uint8_t dramtype
= JEDEC
; /* Regular DDR SDRAMs */
118 uint8_t plldiv
= 10; /* 500 MHz using 100Mhz refclk */
119 uint8_t refclk
= 100; /* 100Mhz reference clock */
120 uint8_t portintlv
= 0; /* no port interleaving */
122 uint8_t addrskew
= 0x8;
123 uint8_t dqoskew
= 0x8;
124 uint8_t dqiskew
= 0x8;
125 uint8_t addrdrive
= 0xF;
126 uint8_t datadrive
= 0xF;
127 uint8_t clkdrive
= 0xF;
129 uint64_t mc0_mclkcfg
; /* Value programmed by draminit */
130 uint64_t mc0_timing1
; /* Value programmed by draminit */
131 uint64_t smbus0_start
= 0; /* Rememberd SMBus register value */
132 uint64_t smbus0_cmd
= 0; /* Rememberd SMBus register value */
134 extern int sb1250_refclk
; /* from draminit - reference clock */
135 extern int dram_cas_latency
; /* from draminit - calc'd cas latency */
136 extern int dram_tMemClk
; /* from draminit - calc'd tMemClk */
138 draminittab_t inittab
[16]; /* our init tab */
142 /* *********************************************************************
143 * Parameter and value tables
144 ********************************************************************* */
146 encvalue_t caslatencies
[] = {
147 {"3.5",JEDEC_CASLAT_35
},
148 {"3.0",JEDEC_CASLAT_30
},
149 {"2.5",JEDEC_CASLAT_25
},
150 {"2.0",JEDEC_CASLAT_20
},
151 {"1.5",JEDEC_CASLAT_15
},
152 {"1.0",JEDEC_CASLAT_10
},
155 encvalue_t refreshrates
[] = {
156 {"64",JEDEC_RFSH_64khz
},
157 {"256",JEDEC_RFSH_256khz
},
158 {"128",JEDEC_RFSH_128khz
},
159 {"32",JEDEC_RFSH_32khz
},
160 {"16",JEDEC_RFSH_16khz
},
161 {"8",JEDEC_RFSH_8khz
},
164 encvalue_t modattribs
[] = {
166 {"reg",JEDEC_ATTRIB_REG
},
170 encvalue_t dramtypes
[] = {
176 spdbyte_t spdfields
[] = {
177 {"mintmemclk",&mintmemclk
,SPD_DEC_BCD
,NULL
,"ns","Minimum value for tMEMCLK","8.0"},
178 {"roundtrip", &roundtrip
, SPD_DEC_BCD
,NULL
,"ns","Round trip time from CLK to returned DQS","2.5"},
179 {"plldiv", &plldiv
, 0,NULL
,"","PLL Ratio (System Config Register)","10"},
180 {"refclk", &refclk
, 0,NULL
,"Mhz","Reference clock, usually 100Mhz","100"},
181 // {"portintlv", &portintlv, 0,NULL,"","Port interleave (1=on)","0"},
182 {"memtype", &dramtype
, SPD_ENCODED
,dramtypes
,"","Memory type (jedec, fcram, sgram)","jedec"},
183 {"rows", &spd
[JEDEC_SPD_ROWS
],0,NULL
,"","[3 ] Number of row bits","13"},
184 {"cols", &spd
[JEDEC_SPD_COLS
],0,NULL
,"","[4 ] Number of column bits","9"},
185 {"banks", &spd
[JEDEC_SPD_BANKS
],0,NULL
,"","[17] Number of banks","4"},
186 {"tCK25", &spd
[JEDEC_SPD_tCK25
],SPD_DEC_BCD
,NULL
,"ns","[9 ] tCK value for CAS Latency 2.5","7.5"},
187 {"tCK20", &spd
[JEDEC_SPD_tCK20
],SPD_DEC_BCD
,NULL
,"ns","[23] tCK value for CAS Latency 2.0","0"},
188 {"tCK10", &spd
[JEDEC_SPD_tCK10
],SPD_DEC_BCD
,NULL
,"ns","[25] tCK value for CAS Latency 1.0","0"},
189 {"rfsh", &spd
[JEDEC_SPD_RFSH
],SPD_ENCODED
,refreshrates
,"","[12] Refresh rate (KHz)","8"},
190 {"caslat", &spd
[JEDEC_SPD_CASLATENCIES
],SPD_ENCODED2
,caslatencies
,"","[18] CAS Latencies supported","2.5"},
191 {"attrib", &spd
[JEDEC_SPD_ATTRIBUTES
],SPD_ENCODED
,modattribs
,"","[21] Module attributes","none"},
192 {"tRAS", &spd
[JEDEC_SPD_tRAS
],0,NULL
,"ns","[30]","45"},
193 {"tRP", &spd
[JEDEC_SPD_tRP
],SPD_DEC_QTR
,NULL
,"ns","[27]","20.0"},
194 {"tRRD", &spd
[JEDEC_SPD_tRRD
],SPD_DEC_QTR
,NULL
,"ns","[28]","15.0"},
195 {"tRCD", &spd
[JEDEC_SPD_tRCD
],SPD_DEC_QTR
,NULL
,"ns","[29]","20.0"},
196 {"tRFC", &spd
[JEDEC_SPD_tRFC
],0,NULL
,"ns","[42]","0"},
197 {"tRC", &spd
[JEDEC_SPD_tRC
],0,NULL
,"ns","[41]","0"},
199 {"addrskew", &addrskew
, 0, NULL
, "","Address Skew","0x0F"},
200 {"dqoskew", &dqoskew
, 0, NULL
, "","DQO Skew","0x08"},
201 {"dqikew", &dqiskew
, 0, NULL
, "","DQI Skew","0x08"},
202 {"addrdrive", &addrdrive
, 0, NULL
, "","Address Drive","0x0F"},
203 {"datadrive", &datadrive
, 0, NULL
, "","Data Drive","0x0F"},
204 {"clkdrive", &clkdrive
, 0, NULL
, "","Clock Drive","0"},
205 {NULL
,0,0,NULL
,NULL
,NULL
,NULL
}};
207 char *lookupstr(encvalue_t
*ev
,uint8_t val
)
210 if (ev
->val
== val
) return ev
->name
;
216 uint64_t sbreadcsr(uint64_t reg
)
220 if (debug
) printf("READ %08X\n",(uint32_t) reg
);
222 switch ((uint32_t) reg
) {
223 case A_SCD_SYSTEM_REVISION
:
224 val
= V_SYS_PART(0x1250) | V_SYS_WID(0) | V_SYS_REVISION(1) | 0xFF;
226 case A_SCD_SYSTEM_CFG
:
227 val
= V_SYS_PLL_DIV(plldiv
);
239 val
= spd
[smbus0_cmd
& 0x3F];
245 void sbwritecsr(uint64_t reg
,uint64_t val
)
247 if (debug
) printf("WRITE %08X %016llX\n",(uint32_t) reg
,val
);
249 switch ((uint32_t) reg
) {
250 case A_MC_REGISTER(0,R_MC_MCLK_CFG
):
253 case A_MC_REGISTER(0,R_MC_TIMING1
):
266 int procfield(char *txt
)
277 printf("Fields must be specified as 'name=value'\n");
284 if (strcmp(sf
->name
,txt
) == 0) break;
288 if (sf
->name
== NULL
) {
289 printf("Invalid field name: %s\n",txt
);
293 if (memcmp(x
,"0x",2) == 0) {
294 sscanf(x
+2,"%x",&num
);
298 if (sscanf(x
,"%d.%d",&a
,&b
) != 2) {
299 printf("%s: invalid number: %s\n",sf
->name
,x
);
308 switch (sf
->decimal
) {
310 if ((b
< 0) || (b
> 9)) {
311 printf("%s: Invalid BCD number: %s\n",sf
->name
,x
);
317 if ((b
!= 0) && (b
!= 25) && (b
!= 50) && (b
!= 75)) {
318 printf("%s: Invalid 2-bit fraction number: %s\n",sf
->name
,x
);
319 printf("(number after decimal should be 0,25,50,75)\n");
327 if (strcmp(ev
->name
,x
) == 0) break;
331 printf("%s: Invalid value. Valid values are: ",x
);
333 while (ev
->name
) { printf("%s ",ev
->name
); ev
++; }
340 tok
= strtok(x
," ,");
345 if (strcmp(ev
->name
,tok
) == 0) break;
349 printf("%s: Invalid value. Valid values are: ",tok
);
351 while (ev
->name
) { printf("%s ",ev
->name
); ev
++; }
356 tok
= strtok(NULL
," ,");
370 void interactive(void)
380 printf("%-65.65s: Value\n","Parameter");
381 printf("%-65.65s: -----\n","-----------------------------------------------------------------");
386 x
+= sprintf(x
,"%s (%s", sf
->name
,sf
->description
);
387 if (sf
->units
&& sf
->units
[0]) {
388 if (sf
->description
&& sf
->description
[0]) x
+= sprintf(x
,", ");
389 x
+= sprintf(x
,"%s",sf
->units
);
391 x
+= sprintf(x
,"): [%s]", sf
->deflt
);
392 printf("%-65.65s: ",prompt
);
394 fgets(ask
,sizeof(ask
),stdin
);
395 if ((x
= strchr(ask
,'\n'))) *x
= '\0';
396 if (ask
[0] == 0) strcpy(ask
,sf
->deflt
);
397 sprintf(field
,"%s=%s",sf
->name
,ask
);
398 if (procfield(field
) < 0) continue;
410 int proc_args(int argc
,char *argv
[])
416 for (inidx
= 1; inidx
< argc
; inidx
++) {
417 if (argv
[inidx
][0] != '-') {
418 argv
[outidx
++] = argv
[inidx
];
421 swnames
[swcnt
] = argv
[inidx
];
433 for (idx
= 0; idx
< swcnt
; idx
++) {
434 if (strcmp(x
,swnames
[idx
]) == 0) return 1;
439 void dumpmclkcfg(uint64_t val
)
441 printf("clk_ratio = %d\n",G_MC_CLK_RATIO(val
));
442 printf("ref_rate = %d\n",G_MC_REF_RATE(val
));
446 void dumptiming1(uint64_t val
)
448 printf("w2rIdle = %d\n",(val
& M_MC_w2rIDLE_TWOCYCLES
) ? 1 : 0);
449 printf("r2rIdle = %d\n",(val
& M_MC_r2rIDLE_TWOCYCLES
) ? 1 : 0);
450 printf("r2wIdle = %d\n",(val
& M_MC_r2wIDLE_TWOCYCLES
) ? 1 : 0);
451 printf("tCrD = %d\n",(int)G_MC_tCrD(val
));
452 printf("tCrDh = %d\n",(val
& M_MC_tCrDh
) ? 1 : 0);
453 printf("tFIFO = %d\n",(int)G_MC_tFIFO(val
));
454 printf("tCwD = %d\n",(int)G_MC_tCwD(val
));
456 printf("tRP = %d\n",(int)G_MC_tRP(val
));
457 printf("tRRD = %d\n",(int)G_MC_tRRD(val
));
458 printf("tRCD = %d\n",(int)G_MC_tRCD(val
));
460 printf("tRFC = %d\n",(int)G_MC_tRFC(val
));
461 printf("tRCw = %d\n",(int)G_MC_tRCw(val
));
462 printf("tRCr = %d\n",(int)G_MC_tRCr(val
));
463 printf("tCwCr = %d\n",(int)G_MC_tCwCr(val
));
466 int main(int argc
,char *argv
[])
474 spd
[JEDEC_SPD_MEMTYPE
] = JEDEC_MEMTYPE_DDRSDRAM2
;
475 spd
[JEDEC_SPD_ROWS
] = 13;
476 spd
[JEDEC_SPD_COLS
] = 9;
477 spd
[JEDEC_SPD_BANKS
] = 2;
478 spd
[JEDEC_SPD_SIDES
] = 1;
479 spd
[JEDEC_SPD_WIDTH
] = 72;
481 argc
= proc_args(argc
,argv
);
483 if ((argc
== 1) && !swisset("-i")) {
484 printf("usage: memconfig name=value name=value ...\n");
486 printf("Available fields: ");
489 printf("%s ",sf
->name
);
500 for (idx
= 1; idx
< argc
; idx
++) {
501 if (procfield(argv
[idx
]) < 0) exit(1);
505 debug
= swisset("-d");
507 printf("-------Memory Parameters---------\n");
515 printf("%-10.10s = 0x%02X ",sf
->name
,t
);
516 switch (sf
->decimal
) {
518 p
+= sprintf(p
,"(%d.%d)",
522 p
+= sprintf(p
,"(%d.%02d)",
526 p
+= sprintf(p
,"(%s)",lookupstr(sf
->values
,t
));
529 p
+= sprintf(p
,"(%d)",t
);
533 p
+= sprintf(p
," %s",sf
->units
);
534 printf("%-16.16s %s\n",buffer
,sf
->description
);
541 memset(inittab
,0,sizeof(inittab
));
543 init
->gbl
.gbl_type
= MCR_GLOBALS
;
544 init
->gbl
.gbl_intlv_ch
= portintlv
;
547 init
->cfg
.cfg_type
= MCR_CHCFG
;
548 init
->cfg
.cfg_chan
= 0;
549 init
->cfg
.cfg_mintmemclk
= mintmemclk
;
550 init
->cfg
.cfg_dramtype
= dramtype
;
551 init
->cfg
.cfg_pagepolicy
= CASCHECK
;
552 init
->cfg
.cfg_blksize
= BLKSIZE32
;
553 init
->cfg
.cfg_intlv_cs
= NOCSINTLV
;
554 init
->cfg
.cfg_ecc
= 0;
555 init
->cfg
.cfg_roundtrip
= roundtrip
;
558 init
->clk
.clk_type
= MCR_CLKCFG
;
559 init
->clk
.clk_addrskew
= addrskew
;
560 init
->clk
.clk_dqoskew
= dqoskew
;
561 init
->clk
.clk_dqiskew
= dqiskew
;
562 init
->clk
.clk_addrdrive
= addrdrive
;
563 init
->clk
.clk_datadrive
= datadrive
;
564 init
->clk
.clk_clkdrive
= clkdrive
;
567 init
->geom
.geom_type
= MCR_GEOM
;
568 init
->geom
.geom_csel
= 0;
569 init
->geom
.geom_rows
= spd
[JEDEC_SPD_ROWS
];
570 init
->geom
.geom_cols
= spd
[JEDEC_SPD_COLS
];
571 init
->geom
.geom_banks
= spd
[JEDEC_SPD_BANKS
];
574 init
->spd
.spd_type
= MCR_SPD
;
575 init
->spd
.spd_csel
= 0;
576 init
->spd
.spd_flags
= 0;
577 init
->spd
.spd_smbuschan
= 0;
578 init
->spd
.spd_smbusdev
= 0x50;
581 init
->mcr
.mcr_type
= MCR_EOT
;
584 sb1250_refclk
= (int) refclk
;
586 sb1250_dram_init(inittab
);
589 printf("-----Memory Timing Register Values-----\n");
590 printf("System Clock %dMHz\n",plldiv
*refclk
/2);
591 printf("CAS latency %d.%d\n",dram_cas_latency
>>1,(dram_cas_latency
&1)?5:0);
592 printf("tMemClk %d.%d ns\n",dram_tMemClk
/10,dram_tMemClk
%10);
593 mclk
= (plldiv
*refclk
)*10/2/((int)G_MC_CLK_RATIO(mc0_mclkcfg
));
594 printf("MCLK Freq %d.%dMHz\n",mclk
/10,mclk
%10);
596 printf("MC_TIMING1 = %016llX\n",mc0_timing1
);
597 printf("MCLK_CONFIG = %016llX\n",mc0_mclkcfg
);
600 printf("-----Memory Timing Register Fields-----\n");
601 dumptiming1(mc0_timing1
);
603 printf("-----Memory Clock Config Register Fields-----\n");
604 dumpmclkcfg(mc0_mclkcfg
);
606 printf("---Done!---\n");
608 printf("%s ",argv
[0]);
616 p
+= sprintf(p
,"%s=",sf
->name
);
617 switch (sf
->decimal
) {
619 p
+= sprintf(p
,"%d.%d",
623 p
+= sprintf(p
,"%d.%02d",
628 p
+= sprintf(p
,"0x%02X",t
);
632 printf("%s ",buffer
);