1/* ********************************************************************* 2 * Broadcom Common Firmware Environment (CFE) 3 * 4 * Memory Config Utility File: memconfig.c 5 * 6 * Author: Mitch Lichtenberg (mpl@broadcom.com) 7 * 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. 12 * 13 ********************************************************************* 14 * 15 * Copyright 2000,2001,2002,2003 16 * Broadcom Corporation. All rights reserved. 17 * 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. 24 * 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. 28 * 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. 34 * 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 ********************************************************************* */ 49 50#include <stdio.h> 51#include <string.h> 52 53/* ********************************************************************* 54 * Basic types 55 ********************************************************************* */ 56 57typedef unsigned char uint8_t; 58typedef unsigned short uint16_t; 59typedef unsigned long uint32_t; 60typedef unsigned long long uint64_t; 61 62/* ********************************************************************* 63 * SB1250 stuff 64 ********************************************************************* */ 65 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" 71 72/* ********************************************************************* 73 * BCD macros 74 ********************************************************************* */ 75 76#define DECTO10THS(x) ((((x) >> 4)*10)+((x) & 0x0F)) 77 78/* ********************************************************************* 79 * Global defaults 80 ********************************************************************* */ 81 82#define MIN_tMEMCLK DRT10(8,0) 83#define tROUNDTRIP DRT10(2,5) 84 85/* ********************************************************************* 86 * Types 87 ********************************************************************* */ 88 89typedef struct encvalue_s { 90 char *name; 91 uint8_t val; 92} encvalue_t; 93 94typedef struct spdbyte_s { 95 char *name; 96 uint8_t *data; 97 int decimal; 98 encvalue_t *values; 99 char *units; 100 char *description; 101 char *deflt; 102} spdbyte_t; 103 104#define SPD_DEC_BCD 1 105#define SPD_DEC_QTR 2 106#define SPD_ENCODED 3 107#define SPD_ENCODED2 4 108 109/* ********************************************************************* 110 * Globals 111 ********************************************************************* */ 112 113 114uint8_t spd[64] = {0}; /* SPD data */ 115uint8_t mintmemclk = MIN_tMEMCLK; /* Default value: 8.0ns */ 116uint8_t roundtrip = tROUNDTRIP; /* Default value: 2.5ns */ 117uint8_t dramtype = JEDEC; /* Regular DDR SDRAMs */ 118uint8_t plldiv = 10; /* 500 MHz using 100Mhz refclk */ 119uint8_t refclk = 100; /* 100Mhz reference clock */ 120uint8_t portintlv = 0; /* no port interleaving */ 121 122uint8_t addrskew = 0x8; 123uint8_t dqoskew = 0x8; 124uint8_t dqiskew = 0x8; 125uint8_t addrdrive = 0xF; 126uint8_t datadrive = 0xF; 127uint8_t clkdrive = 0xF; 128 129uint64_t mc0_mclkcfg; /* Value programmed by draminit */ 130uint64_t mc0_timing1; /* Value programmed by draminit */ 131uint64_t smbus0_start = 0; /* Rememberd SMBus register value */ 132uint64_t smbus0_cmd = 0; /* Rememberd SMBus register value */ 133 134extern int sb1250_refclk; /* from draminit - reference clock */ 135extern int dram_cas_latency; /* from draminit - calc'd cas latency */ 136extern int dram_tMemClk; /* from draminit - calc'd tMemClk */ 137 138draminittab_t inittab[16]; /* our init tab */ 139 140int debug = 0; 141 142/* ********************************************************************* 143 * Parameter and value tables 144 ********************************************************************* */ 145 146encvalue_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}, 153 {NULL,0}}; 154 155encvalue_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}, 162 {NULL,0}}; 163 164encvalue_t modattribs[] = { 165 {"none",0}, 166 {"reg",JEDEC_ATTRIB_REG}, 167 {"diffclk",0x20}, 168 {NULL,0}}; 169 170encvalue_t dramtypes[] = { 171 {"jedec",JEDEC}, 172 {"fcram",FCRAM}, 173 {"sgram",SGRAM}, 174 {NULL,0}}; 175 176spdbyte_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"}, 198 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}}; 206 207char *lookupstr(encvalue_t *ev,uint8_t val) 208{ 209 while (ev->name) { 210 if (ev->val == val) return ev->name; 211 ev++; 212 } 213 return "unknown"; 214} 215 216uint64_t sbreadcsr(uint64_t reg) 217{ 218 uint64_t val = 0; 219 220 if (debug) printf("READ %08X\n",(uint32_t) reg); 221 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; 225 break; 226 case A_SCD_SYSTEM_CFG: 227 val = V_SYS_PLL_DIV(plldiv); 228 break; 229 case A_SMB_STATUS_0: 230 val = 0; 231 break; 232 case A_SMB_CMD_0: 233 val = smbus0_cmd; 234 break; 235 case A_SMB_START_0: 236 val = smbus0_start; 237 break; 238 case A_SMB_DATA_0: 239 val = spd[smbus0_cmd & 0x3F]; 240 break; 241 } 242 return val; 243} 244 245void sbwritecsr(uint64_t reg,uint64_t val) 246{ 247 if (debug) printf("WRITE %08X %016llX\n",(uint32_t) reg,val); 248 249 switch ((uint32_t) reg) { 250 case A_MC_REGISTER(0,R_MC_MCLK_CFG): 251 mc0_mclkcfg = val; 252 break; 253 case A_MC_REGISTER(0,R_MC_TIMING1): 254 mc0_timing1 = val; 255 break; 256 case A_SMB_CMD_0: 257 smbus0_cmd = val; 258 break; 259 case A_SMB_START_0: 260 smbus0_start = val; 261 break; 262 } 263} 264 265 266int procfield(char *txt) 267{ 268 int num = 0; 269 int a,b; 270 spdbyte_t *sf; 271 encvalue_t *ev; 272 char *x; 273 char *tok; 274 275 x = strchr(txt,'='); 276 if (!x) { 277 printf("Fields must be specified as 'name=value'\n"); 278 exit(1); 279 } 280 *x++ = '\0'; 281 282 sf = spdfields; 283 while (sf->name) { 284 if (strcmp(sf->name,txt) == 0) break; 285 sf++; 286 } 287 288 if (sf->name == NULL) { 289 printf("Invalid field name: %s\n",txt); 290 return -1; 291 } 292 293 if (memcmp(x,"0x",2) == 0) { 294 sscanf(x+2,"%x",&num); 295 } 296 else { 297 if (strchr(x,'.')) { 298 if (sscanf(x,"%d.%d",&a,&b) != 2) { 299 printf("%s: invalid number: %s\n",sf->name,x); 300 return -1; 301 } 302 } 303 else { 304 a = atoi(x); 305 b = 0; 306 } 307 308 switch (sf->decimal) { 309 case SPD_DEC_BCD: 310 if ((b < 0) || (b > 9)) { 311 printf("%s: Invalid BCD number: %s\n",sf->name,x); 312 return -1; 313 } 314 num = (a*16)+b; 315 break; 316 case SPD_DEC_QTR: 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"); 320 exit(1); 321 } 322 num = (a*4)+(b/25); 323 break; 324 case SPD_ENCODED: 325 ev = sf->values; 326 while (ev->name) { 327 if (strcmp(ev->name,x) == 0) break; 328 ev++; 329 } 330 if (!ev->name) { 331 printf("%s: Invalid value. Valid values are: ",x); 332 ev = sf->values; 333 while (ev->name) { printf("%s ",ev->name); ev++; } 334 printf("\n"); 335 return -1; 336 } 337 num = ev->val; 338 break; 339 case SPD_ENCODED2: 340 tok = strtok(x," ,"); 341 num = 0; 342 while (tok) { 343 ev = sf->values; 344 while (ev->name) { 345 if (strcmp(ev->name,tok) == 0) break; 346 ev++; 347 } 348 if (!ev->name) { 349 printf("%s: Invalid value. Valid values are: ",tok); 350 ev = sf->values; 351 while (ev->name) { printf("%s ",ev->name); ev++; } 352 printf("\n"); 353 return -1; 354 } 355 num |= ev->val; 356 tok = strtok(NULL," ,"); 357 } 358 break; 359 default: 360 num = a; 361 break; 362 } 363 } 364 365 *(sf->data) = num; 366 367 return 0; 368} 369 370void interactive(void) 371{ 372 spdbyte_t *sf; 373 char field[100]; 374 char ask[100]; 375 char prompt[100]; 376 char *x; 377 378 sf = spdfields; 379 380 printf("%-65.65s: Value\n","Parameter"); 381 printf("%-65.65s: -----\n","-----------------------------------------------------------------"); 382 383 while (sf->name) { 384 for (;;) { 385 x = prompt; 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); 390 } 391 x += sprintf(x,"): [%s]", sf->deflt); 392 printf("%-65.65s: ",prompt); 393 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; 399 break; 400 } 401 sf++; 402 } 403 404 printf("\n\n"); 405} 406 407int swcnt = 0; 408char *swnames[32]; 409 410int proc_args(int argc,char *argv[]) 411{ 412 int inidx,outidx; 413 414 outidx = 1; 415 416 for (inidx = 1; inidx < argc; inidx++) { 417 if (argv[inidx][0] != '-') { 418 argv[outidx++] = argv[inidx]; 419 } 420 else { 421 swnames[swcnt] = argv[inidx]; 422 swcnt++; 423 } 424 } 425 426 return outidx; 427} 428 429int swisset(char *x) 430{ 431 int idx; 432 433 for (idx = 0; idx < swcnt; idx++) { 434 if (strcmp(x,swnames[idx]) == 0) return 1; 435 } 436 return 0; 437} 438 439void dumpmclkcfg(uint64_t val) 440{ 441 printf("clk_ratio = %d\n",G_MC_CLK_RATIO(val)); 442 printf("ref_rate = %d\n",G_MC_REF_RATE(val)); 443 444} 445 446void dumptiming1(uint64_t val) 447{ 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)); 455 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)); 459 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)); 464} 465 466int main(int argc,char *argv[]) 467{ 468 spdbyte_t *sf; 469 uint8_t t; 470 int idx; 471 int mclk; 472 draminittab_t *init; 473 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; 480 481 argc = proc_args(argc,argv); 482 483 if ((argc == 1) && !swisset("-i")) { 484 printf("usage: memconfig name=value name=value ...\n"); 485 printf("\n"); 486 printf("Available fields: "); 487 sf = spdfields; 488 while (sf->name) { 489 printf("%s ",sf->name); 490 sf++; 491 } 492 printf("\n"); 493 exit(1); 494 } 495 496 if (swisset("-i")) { 497 interactive(); 498 } 499 else { 500 for (idx = 1; idx < argc; idx++) { 501 if (procfield(argv[idx]) < 0) exit(1); 502 } 503 } 504 505 debug = swisset("-d"); 506 507 printf("-------Memory Parameters---------\n"); 508 509 sf = spdfields; 510 while (sf->name) { 511 char buffer[64]; 512 char *p = buffer; 513 514 t = *(sf->data); 515 printf("%-10.10s = 0x%02X ",sf->name,t); 516 switch (sf->decimal) { 517 case SPD_DEC_BCD: 518 p += sprintf(p,"(%d.%d)", 519 t >> 4, t & 0x0F); 520 break; 521 case SPD_DEC_QTR: 522 p += sprintf(p,"(%d.%02d)", 523 t/4,(t&3)*25); 524 break; 525 case SPD_ENCODED: 526 p += sprintf(p,"(%s)",lookupstr(sf->values,t)); 527 break; 528 default: 529 p += sprintf(p,"(%d)",t); 530 break; 531 } 532 533 p += sprintf(p," %s",sf->units); 534 printf("%-16.16s %s\n",buffer,sf->description); 535 sf++; 536 } 537 538 printf("\n"); 539 540 init = &inittab[0]; 541 memset(inittab,0,sizeof(inittab)); 542 543 init->gbl.gbl_type = MCR_GLOBALS; 544 init->gbl.gbl_intlv_ch = portintlv; 545 init++; 546 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; 556 init++; 557 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; 565 init++; 566 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]; 572 init++; 573 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; 579 init++; 580 581 init->mcr.mcr_type = MCR_EOT; 582 583 584 sb1250_refclk = (int) refclk; 585 586 sb1250_dram_init(inittab); 587 588 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); 595 printf("\n"); 596 printf("MC_TIMING1 = %016llX\n",mc0_timing1); 597 printf("MCLK_CONFIG = %016llX\n",mc0_mclkcfg); 598 printf("\n"); 599 600 printf("-----Memory Timing Register Fields-----\n"); 601 dumptiming1(mc0_timing1); 602 603 printf("-----Memory Clock Config Register Fields-----\n"); 604 dumpmclkcfg(mc0_mclkcfg); 605 606 printf("---Done!---\n"); 607 608 printf("%s ",argv[0]); 609 sf = spdfields; 610 while (sf->name) { 611 char buffer[64]; 612 char *p = buffer; 613 614 t = *(sf->data); 615 616 p += sprintf(p,"%s=",sf->name); 617 switch (sf->decimal) { 618 case SPD_DEC_BCD: 619 p += sprintf(p,"%d.%d", 620 t >> 4, t & 0x0F); 621 break; 622 case SPD_DEC_QTR: 623 p += sprintf(p,"%d.%02d", 624 t/4,(t&3)*25); 625 break; 626 case SPD_ENCODED: 627 default: 628 p += sprintf(p,"0x%02X",t); 629 break; 630 } 631 632 printf("%s ",buffer); 633 sf++; 634 } 635 636 printf("\n"); 637 638 return 0; 639} 640