1/* ********************************************************************* 2 * Broadcom Common Firmware Environment (CFE) 3 * 4 * Memory Config Utility File: memconfig1480.c 5 * 6 * Author: Mitch Lichtenberg 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#include <stdlib.h> 53 54/* ********************************************************************* 55 * Basic types 56 ********************************************************************* */ 57 58typedef unsigned char uint8_t; 59typedef unsigned short uint16_t; 60typedef unsigned int uint32_t; 61typedef unsigned long long uint64_t; 62 63/* ********************************************************************* 64 * SB1250 stuff 65 ********************************************************************* */ 66 67#include "sb1250_defs.h" 68#include "bcm1480_mc.h" 69#include "jedec.h" 70#include "bcm1480_draminit.h" 71#include "bcm1480_regs.h" 72#include "bcm1480_scd.h" 73 74/* ********************************************************************* 75 * BCD macros 76 ********************************************************************* */ 77 78#define DECTO10THS(x) ((((x) >> 4)*10)+((x) & 0x0F)) 79 80/* ********************************************************************* 81 * Global defaults 82 ********************************************************************* */ 83 84#define MIN_tMEMCLK DRT10(8,0) 85#define tROUNDTRIP DRT10(2,5) 86 87/* ********************************************************************* 88 * Types 89 ********************************************************************* */ 90 91typedef struct encvalue_s { 92 char *name; 93 uint8_t val; 94} encvalue_t; 95 96typedef struct spdbyte_s { 97 char *name; 98 uint8_t *data; 99 int decimal; 100 encvalue_t *values; 101 char *units; 102 char *description; 103 char *deflt; 104} spdbyte_t; 105 106#define SPD_DEC_BCD 1 107#define SPD_DEC_QTR 2 108#define SPD_ENCODED 3 109#define SPD_ENCODED2 4 110 111/* ********************************************************************* 112 * Globals 113 ********************************************************************* */ 114 115 116uint8_t spd[64] = {0}; /* SPD data */ 117uint8_t mintmemclk = MIN_tMEMCLK; /* Default value: 8.0ns */ 118uint8_t roundtrip = tROUNDTRIP; /* Default value: 2.5ns */ 119uint8_t dramtype = JEDEC; /* Regular DDR SDRAMs */ 120uint8_t plldiv = 20; /* 500 MHz using 100Mhz refclk */ 121uint8_t refclk = 100; /* 100Mhz reference clock */ 122uint8_t portintlv = 0; /* no port interleaving */ 123 124uint8_t addrcoarse = 0; 125uint8_t addrfine = 8; 126uint8_t dqocoarse = 0; 127uint8_t dqofine = 8; 128uint8_t dqicoarse = 0; 129uint8_t dqifine = 8; 130 131uint64_t mc0_gblconfig = 0; 132 133uint64_t mc0_mclkcfg; /* Value programmed by draminit */ 134uint64_t mc0_timing1; /* Value programmed by draminit */ 135uint64_t mc1_mclkcfg; /* Value programmed by draminit */ 136uint64_t mc1_timing1; /* Value programmed by draminit */ 137uint64_t mc2_mclkcfg; /* Value programmed by draminit */ 138uint64_t mc2_timing1; /* Value programmed by draminit */ 139uint64_t mc3_mclkcfg; /* Value programmed by draminit */ 140uint64_t mc3_timing1; /* Value programmed by draminit */ 141 142uint64_t mc_cs_start0; 143uint64_t mc_cs_start1; 144uint64_t mc_cs_start2; 145uint64_t mc_cs_start3; 146uint64_t mc_cs_end0; 147uint64_t mc_cs_end1; 148uint64_t mc_cs_end2; 149uint64_t mc_cs_end3; 150 151uint64_t mc_dll_cfg0; 152uint64_t mc_dll_cfg1; 153uint64_t mc_dll_cfg2; 154uint64_t mc_dll_cfg3; 155uint64_t mc_drive_cfg0; 156uint64_t mc_drive_cfg1; 157uint64_t mc_drive_cfg2; 158uint64_t mc_drive_cfg3; 159uint64_t mc_drammode0; 160uint64_t mc_drammode1; 161uint64_t mc_drammode2; 162uint64_t mc_drammode3; 163 164uint64_t smbus0_start = 0; /* Rememberd SMBus register value */ 165uint64_t smbus0_cmd = 0; /* Rememberd SMBus register value */ 166 167extern int bcm1480_refclk; /* from draminit - reference clock */ 168extern int dram_cas_latency; /* from draminit - calc'd cas latency */ 169extern int dram_tMemClk; /* from draminit - calc'd tMemClk */ 170 171draminittab_t inittab[16]; /* our init tab */ 172 173int debug = 0; 174 175/* ********************************************************************* 176 * Parameter and value tables 177 ********************************************************************* */ 178 179encvalue_t caslatencies[] = { 180 {"3.5",JEDEC_CASLAT_35}, 181 {"3.0",JEDEC_CASLAT_30}, 182 {"2.5",JEDEC_CASLAT_25}, 183 {"2.0",JEDEC_CASLAT_20}, 184 {"1.5",JEDEC_CASLAT_15}, 185 {"1.0",JEDEC_CASLAT_10}, 186 {NULL,0}}; 187 188encvalue_t refreshrates[] = { 189 {"64",JEDEC_RFSH_64khz}, 190 {"256",JEDEC_RFSH_256khz}, 191 {"128",JEDEC_RFSH_128khz}, 192 {"32",JEDEC_RFSH_32khz}, 193 {"16",JEDEC_RFSH_16khz}, 194 {"8",JEDEC_RFSH_8khz}, 195 {NULL,0}}; 196 197encvalue_t modattribs[] = { 198 {"none",0}, 199 {"reg",JEDEC_ATTRIB_REG}, 200 {"diffclk",0x20}, 201 {NULL,0}}; 202 203encvalue_t dramtypes[] = { 204 {"jedec",JEDEC}, 205 {"fcram",FCRAM}, 206 {"sgram",SGRAM}, 207 {NULL,0}}; 208 209spdbyte_t spdfields[] = { 210 {"mintmemclk",&mintmemclk,SPD_DEC_BCD,NULL,"ns","Minimum value for tMEMCLK","6.0"}, 211 {"roundtrip", &roundtrip, SPD_DEC_BCD,NULL,"ns","Round trip time from CLK to returned DQS","2.5"}, 212 {"plldiv", &plldiv, 0,NULL,"","PLL Ratio (System Config Register)","20"}, 213 {"refclk", &refclk, 0,NULL,"Mhz","Reference clock, usually 100Mhz","100"}, 214// {"portintlv", &portintlv, 0,NULL,"","Port interleave (1=on)","0"}, 215 {"memtype", &dramtype, SPD_ENCODED,dramtypes,"","Memory type (jedec, fcram, sgram)","jedec"}, 216 {"rows", &spd[JEDEC_SPD_ROWS],0,NULL,"","[3 ] Number of row bits","13"}, 217 {"cols", &spd[JEDEC_SPD_COLS],0,NULL,"","[4 ] Number of column bits","10"}, 218 {"banks", &spd[JEDEC_SPD_BANKS],0,NULL,"","[17] Number of banks","4"}, 219 {"tCK25", &spd[JEDEC_SPD_tCK25],SPD_DEC_BCD,NULL,"ns","[9 ] tCK value for CAS Latency 2.5","6.0"}, 220 {"tCK20", &spd[JEDEC_SPD_tCK20],SPD_DEC_BCD,NULL,"ns","[23] tCK value for CAS Latency 2.0","0"}, 221 {"tCK10", &spd[JEDEC_SPD_tCK10],SPD_DEC_BCD,NULL,"ns","[25] tCK value for CAS Latency 1.0","0"}, 222 {"rfsh", &spd[JEDEC_SPD_RFSH],SPD_ENCODED,refreshrates,"","[12] Refresh rate (KHz)","128"}, 223 {"caslat", &spd[JEDEC_SPD_CASLATENCIES],SPD_ENCODED2,caslatencies,"","[18] CAS Latencies supported","2.5"}, 224 {"attrib", &spd[JEDEC_SPD_ATTRIBUTES],SPD_ENCODED,modattribs,"","[21] Module attributes","none"}, 225 {"tRAS", &spd[JEDEC_SPD_tRAS],0,NULL,"ns","[30]","42"}, 226 {"tRP", &spd[JEDEC_SPD_tRP],SPD_DEC_QTR,NULL,"ns","[27]","18.0"}, 227 {"tRRD", &spd[JEDEC_SPD_tRRD],SPD_DEC_QTR,NULL,"ns","[28]","12.0"}, 228 {"tRCD", &spd[JEDEC_SPD_tRCD],SPD_DEC_QTR,NULL,"ns","[29]","18.0"}, 229 {"tRFC", &spd[JEDEC_SPD_tRFC],0,NULL,"ns","[42]","0"}, 230 {"tRC", &spd[JEDEC_SPD_tRC],0,NULL,"ns","[41]","0"}, 231 232 {"addrcoarse", &addrcoarse, 0, NULL, "","Address Skew Coarse","0"}, 233 {"addrfine", &addrfine, 0, NULL, "","Address Skew Fine","8"}, 234 235 {"dqocoarse", &dqocoarse, 0, NULL, "","DQO Skew Coarse","0"}, 236 {"dqofine", &dqofine, 0, NULL, "","DQO Skew Coarse","8"}, 237 238 {"dqicoarse", &dqicoarse, 0, NULL, "","DQI Skew Coarse","0"}, 239 {"dqifine", &dqifine, 0, NULL, "","DQI Skew Fine","8"}, 240 {NULL,0,0,NULL,NULL,NULL,NULL}}; 241 242static char *lookupstr(encvalue_t *ev,uint8_t val) 243{ 244 while (ev->name) { 245 if (ev->val == val) return ev->name; 246 ev++; 247 } 248 return "unknown"; 249} 250 251uint64_t sbreadcsr(uint64_t reg); 252uint64_t sbreadcsr(uint64_t reg) 253{ 254 uint64_t val = 0; 255 256 if (debug) printf("READ %08X\n",(uint32_t) reg); 257 258 switch ((uint32_t) reg) { 259 case A_BCM1480_MC_GLB_CONFIG: 260 val = mc0_gblconfig; 261 break; 262 case A_BCM1480_MC_REGISTER(0,R_BCM1480_MC_MCLK_CFG): 263 val = mc0_mclkcfg; 264 break; 265 case A_BCM1480_MC_REGISTER(1,R_BCM1480_MC_MCLK_CFG): 266 val = mc1_mclkcfg; 267 break; 268 case A_BCM1480_MC_REGISTER(2,R_BCM1480_MC_MCLK_CFG): 269 val = mc2_mclkcfg; 270 break; 271 case A_BCM1480_MC_REGISTER(3,R_BCM1480_MC_MCLK_CFG): 272 val = mc3_mclkcfg; 273 break; 274 case A_BCM1480_MC_REGISTER(0,R_BCM1480_MC_TIMING1): 275 val = mc0_timing1; 276 break; 277 case A_BCM1480_MC_REGISTER(1,R_BCM1480_MC_TIMING1): 278 val = mc1_timing1; 279 break; 280 case A_BCM1480_MC_REGISTER(2,R_BCM1480_MC_TIMING1): 281 val = mc2_timing1; 282 break; 283 case A_BCM1480_MC_REGISTER(3,R_BCM1480_MC_TIMING1): 284 val = mc3_timing1; 285 break; 286 case A_BCM1480_MC_REGISTER(0,R_BCM1480_MC_CS_START): 287 val = mc_cs_start0; 288 break; 289 case A_BCM1480_MC_REGISTER(1,R_BCM1480_MC_CS_START): 290 val = mc_cs_start1; 291 break; 292 case A_BCM1480_MC_REGISTER(2,R_BCM1480_MC_CS_START): 293 val = mc_cs_start2; 294 break; 295 case A_BCM1480_MC_REGISTER(3,R_BCM1480_MC_CS_START): 296 val = mc_cs_start3; 297 break; 298 case A_BCM1480_MC_REGISTER(0,R_BCM1480_MC_CS_END): 299 val = mc_cs_end0; 300 break; 301 case A_BCM1480_MC_REGISTER(1,R_BCM1480_MC_CS_END): 302 val = mc_cs_end1; 303 break; 304 case A_BCM1480_MC_REGISTER(2,R_BCM1480_MC_CS_END): 305 val = mc_cs_end2; 306 break; 307 case A_BCM1480_MC_REGISTER(3,R_BCM1480_MC_CS_END): 308 val = mc_cs_end3; 309 break; 310 case A_BCM1480_MC_REGISTER(0,R_BCM1480_MC_DLL_CFG): 311 val = mc_dll_cfg0; 312 break; 313 case A_BCM1480_MC_REGISTER(1,R_BCM1480_MC_DLL_CFG): 314 val = mc_dll_cfg1; 315 break; 316 case A_BCM1480_MC_REGISTER(2,R_BCM1480_MC_DLL_CFG): 317 val = mc_dll_cfg2; 318 break; 319 case A_BCM1480_MC_REGISTER(3,R_BCM1480_MC_DLL_CFG): 320 val = mc_dll_cfg3; 321 break; 322 case A_BCM1480_MC_REGISTER(0,R_BCM1480_MC_DRIVE_CFG): 323 val = mc_drive_cfg0; 324 break; 325 case A_BCM1480_MC_REGISTER(1,R_BCM1480_MC_DRIVE_CFG): 326 val = mc_drive_cfg1; 327 break; 328 case A_BCM1480_MC_REGISTER(2,R_BCM1480_MC_DRIVE_CFG): 329 val = mc_drive_cfg2; 330 break; 331 case A_BCM1480_MC_REGISTER(3,R_BCM1480_MC_DRIVE_CFG): 332 val = mc_drive_cfg3; 333 break; 334 case A_BCM1480_MC_REGISTER(0,R_BCM1480_MC_DRAMMODE): 335 val = mc_drammode0; 336 break; 337 case A_BCM1480_MC_REGISTER(1,R_BCM1480_MC_DRAMMODE): 338 val = mc_drammode1; 339 break; 340 case A_BCM1480_MC_REGISTER(2,R_BCM1480_MC_DRAMMODE): 341 val = mc_drammode2; 342 break; 343 case A_BCM1480_MC_REGISTER(3,R_BCM1480_MC_DRAMMODE): 344 val = mc_drammode3; 345 break; 346 case A_SCD_SYSTEM_REVISION: 347 val = V_SYS_PART(K_SYS_PART_BCM1480) | V_SYS_REVISION(1) | 0xFF; 348 break; 349 case A_SCD_SYSTEM_CFG: 350 val = V_BCM1480_SYS_PLL_DIV(plldiv); 351 break; 352 case A_SMB_STATUS_0: 353 val = 0; 354 break; 355 case A_SMB_CMD_0: 356 val = smbus0_cmd; 357 break; 358 case A_SMB_START_0: 359 val = smbus0_start; 360 break; 361 case A_SMB_DATA_0: 362 val = spd[smbus0_cmd & 0x3F]; 363 break; 364 default: 365 printf("Unrecognized register read: %016llX\n",reg); 366 } 367 return val; 368} 369 370void sbwritecsr(uint64_t reg,uint64_t val); 371void sbwritecsr(uint64_t reg,uint64_t val) 372{ 373 if (debug) printf("WRITE %08X %016llX\n",(uint32_t) reg,val); 374 375 switch ((uint32_t) reg) { 376 case A_BCM1480_MC_GLB_CONFIG: 377 mc0_gblconfig = val; 378 break; 379 case A_BCM1480_MC_REGISTER(0,R_BCM1480_MC_MCLK_CFG): 380 mc0_mclkcfg = val; 381 break; 382 case A_BCM1480_MC_REGISTER(1,R_BCM1480_MC_MCLK_CFG): 383 mc1_mclkcfg = val; 384 break; 385 case A_BCM1480_MC_REGISTER(2,R_BCM1480_MC_MCLK_CFG): 386 mc2_mclkcfg = val; 387 break; 388 case A_BCM1480_MC_REGISTER(3,R_BCM1480_MC_MCLK_CFG): 389 mc3_mclkcfg = val; 390 break; 391 case A_BCM1480_MC_REGISTER(0,R_BCM1480_MC_TIMING1): 392 mc0_timing1 = val; 393 break; 394 case A_BCM1480_MC_REGISTER(1,R_BCM1480_MC_TIMING1): 395 mc1_timing1 = val; 396 break; 397 case A_BCM1480_MC_REGISTER(2,R_BCM1480_MC_TIMING1): 398 mc2_timing1 = val; 399 break; 400 case A_BCM1480_MC_REGISTER(3,R_BCM1480_MC_TIMING1): 401 mc3_timing1 = val; 402 break; 403 case A_BCM1480_MC_REGISTER(0,R_BCM1480_MC_CS_START): 404 mc_cs_start0 = val; 405 break; 406 case A_BCM1480_MC_REGISTER(1,R_BCM1480_MC_CS_START): 407 mc_cs_start1 = val; 408 break; 409 case A_BCM1480_MC_REGISTER(2,R_BCM1480_MC_CS_START): 410 mc_cs_start2 = val; 411 break; 412 case A_BCM1480_MC_REGISTER(3,R_BCM1480_MC_CS_START): 413 mc_cs_start3 = val; 414 break; 415 case A_BCM1480_MC_REGISTER(0,R_BCM1480_MC_CS_END): 416 mc_cs_end0 = val; 417 break; 418 case A_BCM1480_MC_REGISTER(1,R_BCM1480_MC_CS_END): 419 mc_cs_end1 = val; 420 break; 421 case A_BCM1480_MC_REGISTER(2,R_BCM1480_MC_CS_END): 422 mc_cs_end2 = val; 423 break; 424 case A_BCM1480_MC_REGISTER(3,R_BCM1480_MC_CS_END): 425 mc_cs_end3 = val; 426 break; 427 case A_BCM1480_MC_REGISTER(0,R_BCM1480_MC_DLL_CFG): 428 mc_dll_cfg0 = val; 429 break; 430 case A_BCM1480_MC_REGISTER(1,R_BCM1480_MC_DLL_CFG): 431 mc_dll_cfg1 = val; 432 break; 433 case A_BCM1480_MC_REGISTER(2,R_BCM1480_MC_DLL_CFG): 434 mc_dll_cfg2 = val; 435 break; 436 case A_BCM1480_MC_REGISTER(3,R_BCM1480_MC_DLL_CFG): 437 mc_dll_cfg3 = val; 438 break; 439 case A_BCM1480_MC_REGISTER(0,R_BCM1480_MC_DRIVE_CFG): 440 mc_drive_cfg0 = val; 441 break; 442 case A_BCM1480_MC_REGISTER(1,R_BCM1480_MC_DRIVE_CFG): 443 mc_drive_cfg1 = val; 444 break; 445 case A_BCM1480_MC_REGISTER(2,R_BCM1480_MC_DRIVE_CFG): 446 mc_drive_cfg2 = val; 447 break; 448 case A_BCM1480_MC_REGISTER(3,R_BCM1480_MC_DRIVE_CFG): 449 mc_drive_cfg3 = val; 450 break; 451 case A_BCM1480_MC_REGISTER(0,R_BCM1480_MC_DRAMMODE): 452 mc_drammode0 = val; 453 break; 454 case A_BCM1480_MC_REGISTER(1,R_BCM1480_MC_DRAMMODE): 455 mc_drammode1 = val; 456 break; 457 case A_BCM1480_MC_REGISTER(2,R_BCM1480_MC_DRAMMODE): 458 mc_drammode2 = val; 459 break; 460 case A_BCM1480_MC_REGISTER(3,R_BCM1480_MC_DRAMMODE): 461 mc_drammode3 = val; 462 break; 463 case A_SMB_CMD_0: 464 smbus0_cmd = val; 465 break; 466 case A_SMB_START_0: 467 smbus0_start = val; 468 break; 469 } 470} 471 472 473static int procfield(char *txt) 474{ 475 int num = 0; 476 int a,b; 477 spdbyte_t *sf; 478 encvalue_t *ev; 479 char *x; 480 char *tok; 481 482 x = strchr(txt,'='); 483 if (!x) { 484 printf("Fields must be specified as 'name=value'\n"); 485 exit(1); 486 } 487 *x++ = '\0'; 488 489 sf = spdfields; 490 while (sf->name) { 491 if (strcmp(sf->name,txt) == 0) break; 492 sf++; 493 } 494 495 if (sf->name == NULL) { 496 printf("Invalid field name: %s\n",txt); 497 return -1; 498 } 499 500 if (memcmp(x,"0x",2) == 0) { 501 sscanf(x+2,"%x",&num); 502 } 503 else { 504 if (strchr(x,'.')) { 505 if (sscanf(x,"%d.%d",&a,&b) != 2) { 506 printf("%s: invalid number: %s\n",sf->name,x); 507 return -1; 508 } 509 } 510 else { 511 a = atoi(x); 512 b = 0; 513 } 514 515 switch (sf->decimal) { 516 case SPD_DEC_BCD: 517 if ((b < 0) || (b > 9)) { 518 printf("%s: Invalid BCD number: %s\n",sf->name,x); 519 return -1; 520 } 521 num = (a*16)+b; 522 break; 523 case SPD_DEC_QTR: 524 if ((b != 0) && (b != 25) && (b != 50) && (b != 75)) { 525 printf("%s: Invalid 2-bit fraction number: %s\n",sf->name,x); 526 printf("(number after decimal should be 0,25,50,75)\n"); 527 exit(1); 528 } 529 num = (a*4)+(b/25); 530 break; 531 case SPD_ENCODED: 532 ev = sf->values; 533 while (ev->name) { 534 if (strcmp(ev->name,x) == 0) break; 535 ev++; 536 } 537 if (!ev->name) { 538 printf("%s: Invalid value. Valid values are: ",x); 539 ev = sf->values; 540 while (ev->name) { printf("%s ",ev->name); ev++; } 541 printf("\n"); 542 return -1; 543 } 544 num = ev->val; 545 break; 546 case SPD_ENCODED2: 547 tok = strtok(x," ,"); 548 num = 0; 549 while (tok) { 550 ev = sf->values; 551 while (ev->name) { 552 if (strcmp(ev->name,tok) == 0) break; 553 ev++; 554 } 555 if (!ev->name) { 556 printf("%s: Invalid value. Valid values are: ",tok); 557 ev = sf->values; 558 while (ev->name) { printf("%s ",ev->name); ev++; } 559 printf("\n"); 560 return -1; 561 } 562 num |= ev->val; 563 tok = strtok(NULL," ,"); 564 } 565 break; 566 default: 567 num = a; 568 break; 569 } 570 } 571 572 *(sf->data) = num; 573 574 return 0; 575} 576 577static void interactive(void) 578{ 579 spdbyte_t *sf; 580 char field[100]; 581 char ask[100]; 582 char prompt[100]; 583 char *x; 584 585 sf = spdfields; 586 587 printf("%-65.65s: Value\n","Parameter"); 588 printf("%-65.65s: -----\n","-----------------------------------------------------------------"); 589 590 while (sf->name) { 591 for (;;) { 592 x = prompt; 593 x += sprintf(x,"%s (%s", sf->name,sf->description); 594 if (sf->units && sf->units[0]) { 595 if (sf->description && sf->description[0]) x += sprintf(x,", "); 596 x += sprintf(x,"%s",sf->units); 597 } 598 x += sprintf(x,"): [%s]", sf->deflt); 599 printf("%-65.65s: ",prompt); 600 601 fgets(ask,sizeof(ask),stdin); 602 if ((x = strchr(ask,'\n'))) *x = '\0'; 603 if (ask[0] == 0) strcpy(ask,sf->deflt); 604 sprintf(field,"%s=%s",sf->name,ask); 605 if (procfield(field) < 0) continue; 606 break; 607 } 608 sf++; 609 } 610 611 printf("\n\n"); 612} 613 614int swcnt = 0; 615char *swnames[32]; 616 617static int proc_args(int argc,char *argv[]) 618{ 619 int inidx,outidx; 620 621 outidx = 1; 622 623 for (inidx = 1; inidx < argc; inidx++) { 624 if (argv[inidx][0] != '-') { 625 argv[outidx++] = argv[inidx]; 626 } 627 else { 628 swnames[swcnt] = argv[inidx]; 629 swcnt++; 630 } 631 } 632 633 return outidx; 634} 635 636static int swisset(char *x) 637{ 638 int idx; 639 640 for (idx = 0; idx < swcnt; idx++) { 641 if (strcmp(x,swnames[idx]) == 0) return 1; 642 } 643 return 0; 644} 645 646static void dumpmclkcfg(uint64_t val) 647{ 648 printf("clk_ratio = %d\n",(int)G_BCM1480_MC_CLK_RATIO(val)); 649 printf("ref_rate = %d\n",(int)G_BCM1480_MC_REF_RATE(val)); 650 651} 652 653static void dumptiming1(uint64_t val) 654{ 655 printf("tRCD = %d\n",(int)G_BCM1480_MC_tRCD(val)); 656 printf("tCL = %d\n",(int)G_BCM1480_MC_tCL(val)); 657 printf("tCrDh = %d\n",(val & M_BCM1480_MC_tCrDh) ? 1 : 0); 658 printf("tWR = %d\n",(int)G_BCM1480_MC_tWR(val)); 659 printf("tCwD = %d\n",(int)G_BCM1480_MC_tCwD(val)); 660 printf("tRP = %d\n",(int)G_BCM1480_MC_tRP(val)); 661 printf("tRRD = %d\n",(int)G_BCM1480_MC_tRRD(val)); 662 printf("tRCw = %d\n",(int)G_BCM1480_MC_tRCw(val)); 663 printf("tRCr = %d\n",(int)G_BCM1480_MC_tRCr(val)); 664 printf("tRFC = %d\n",(int)G_BCM1480_MC_tRFC(val)); 665 printf("tFIFO = %d\n",(int)G_BCM1480_MC_tFIFO(val)); 666 667 printf("w2rIdle = %d\n",(int)G_BCM1480_MC_tW2R(val)); 668 printf("r2wIdle = %d\n",(int)G_BCM1480_MC_tR2W(val)); 669 printf("r2rIdle = %d\n",(val & M_BCM1480_MC_tR2R) ? 1 : 0); 670 671} 672 673 674static int banks2bits(int banks) 675{ 676 switch (banks) { 677 case 2: 678 return 1; 679 case 4: 680 return 2; 681 case 8: 682 return 3; 683 default: 684 printf("Bad banks2bits: %d\n",banks);exit(1); 685 } 686 return 0; 687} 688 689uint64_t bcm1480_dram_init(draminittab_t *init,void *); 690int main(int argc,char *argv[]) 691{ 692 spdbyte_t *sf; 693 uint8_t t; 694 int idx; 695 int mclk; 696 int zclk; 697 draminittab_t *init; 698 int spdmode; 699 700 spd[JEDEC_SPD_MEMTYPE] = JEDEC_MEMTYPE_DDRSDRAM2; 701 spd[JEDEC_SPD_ROWS] = 13; 702 spd[JEDEC_SPD_COLS] = 10; 703 spd[JEDEC_SPD_BANKS] = 4; 704 spd[JEDEC_SPD_SIDES] = 1; 705 spd[JEDEC_SPD_WIDTH] = 72; 706 707 argc = proc_args(argc,argv); 708 709 spdmode = swisset("-spd"); 710 711 if ((argc == 1) && !swisset("-i")) { 712 printf("usage: memconfig name=value name=value ...\n"); 713 printf("\n"); 714 printf("Available fields: "); 715 sf = spdfields; 716 while (sf->name) { 717 printf("%s ",sf->name); 718 sf++; 719 } 720 printf("\n"); 721 exit(1); 722 } 723 724 if (swisset("-i")) { 725 interactive(); 726 } 727 else { 728 for (idx = 1; idx < argc; idx++) { 729 if (procfield(argv[idx]) < 0) exit(1); 730 } 731 } 732 733 debug = swisset("-d"); 734 735 printf("-------Memory Parameters---------\n"); 736 737 sf = spdfields; 738 while (sf->name) { 739 char buffer[64]; 740 char *p = buffer; 741 742 t = *(sf->data); 743 printf("%-10.10s = 0x%02X ",sf->name,t); 744 switch (sf->decimal) { 745 case SPD_DEC_BCD: 746 p += sprintf(p,"(%d.%d)", 747 t >> 4, t & 0x0F); 748 break; 749 case SPD_DEC_QTR: 750 p += sprintf(p,"(%d.%02d)", 751 t/4,(t&3)*25); 752 break; 753 case SPD_ENCODED: 754 p += sprintf(p,"(%s)",lookupstr(sf->values,t)); 755 break; 756 default: 757 p += sprintf(p,"(%d)",t); 758 break; 759 } 760 761 p += sprintf(p," %s",sf->units); 762 printf("%-16.16s %s\n",buffer,sf->description); 763 sf++; 764 } 765 766 printf("\n"); 767 768 init = &inittab[0]; 769 memset(inittab,0,sizeof(inittab)); 770 771 init->gbl.gbl_type = MCR_GLOBALS; 772 init->gbl.gbl_intlv_ch = portintlv; 773 init++; 774 775 init->cfg.cfg_type = MCR_CHCFG; 776 init->cfg.cfg_chan = 0; 777 init->cfg.cfg_mintmemclk = mintmemclk; 778 init->cfg.cfg_chantype = MC_64BIT_CHAN; 779 init->cfg.cfg_dramtype = dramtype; 780 init->cfg.cfg_pagepolicy = CASCHECK; 781 init->cfg.cfg_intlv_cs = NOCSINTLV; 782 init->cfg.cfg_ecc = 0; 783 init->cfg.cfg_roundtrip = roundtrip; 784 init++; 785 786#if 0 787 /* XXX replace with DLL config */ 788 init->clk.clk_type = MCR_CLKCFG; 789 init->clk.clk_addrskew = addrskew; 790 init->clk.clk_dqoskew = dqoskew; 791 init->clk.clk_dqiskew = dqiskew; 792 init->clk.clk_addrdrive = addrdrive; 793 init->clk.clk_datadrive = datadrive; 794 init->clk.clk_clkdrive = clkdrive; 795 init++; 796#endif 797 798 if (spdmode) { 799 init->spd.spd_type = MCR_SPD; 800 init->spd.spd_csel = 0; 801 init->spd.spd_flags = 0; 802 init->spd.spd_smbuschan = 0; 803 init->spd.spd_smbusdev = 0x50; 804 init++; 805 } 806 else { 807 init->geom.geom_type = MCR_GEOM; 808 init->geom.geom_csel = 0; 809 init->geom.geom_rows = spd[JEDEC_SPD_ROWS]; 810 init->geom.geom_cols = spd[JEDEC_SPD_COLS]; 811 init->geom.geom_banks = banks2bits(spd[JEDEC_SPD_BANKS]); 812 init++; 813 814 init->tmg.tmg_type = MCR_TIMING; 815 init->tmg.tmg_tCK = spd[JEDEC_SPD_tCK25]; 816 init->tmg.tmg_rfsh = spd[JEDEC_SPD_RFSH]; 817 init->tmg.tmg_caslatency = spd[JEDEC_SPD_CASLATENCIES]; 818 init->tmg.tmg_attributes = spd[JEDEC_SPD_ATTRIBUTES]; 819 init->tmg.tmg_tRAS = spd[JEDEC_SPD_tRAS]; 820 init->tmg.tmg_tRP = spd[JEDEC_SPD_tRP]; 821 init->tmg.tmg_tRRD = spd[JEDEC_SPD_tRRD]; 822 init->tmg.tmg_tRCD = spd[JEDEC_SPD_tRCD]; 823 init->tmg.tmg_tRFC = spd[JEDEC_SPD_tRFC]; 824 init->tmg.tmg_tRC = spd[JEDEC_SPD_tRC]; 825 init++; 826 } 827 828#if 0 829 830 /* Ch 0, CS 2 */ 831 if (spdmode) { 832 init->spd.spd_type = MCR_SPD; 833 init->spd.spd_csel = 2; 834 init->spd.spd_flags = 0; 835 init->spd.spd_smbuschan = 0; 836 init->spd.spd_smbusdev = 0x50; 837 init++; 838 } 839 else { 840 init->geom.geom_type = MCR_GEOM; 841 init->geom.geom_csel = 2; 842 init->geom.geom_rows = spd[JEDEC_SPD_ROWS]; 843 init->geom.geom_cols = spd[JEDEC_SPD_COLS]; 844 init->geom.geom_banks = banks2bits(spd[JEDEC_SPD_BANKS]); 845 init++; 846 847 init->tmg.tmg_type = MCR_TIMING; 848 init->tmg.tmg_tCK = spd[JEDEC_SPD_tCK25]; 849 init->tmg.tmg_rfsh = spd[JEDEC_SPD_RFSH]; 850 init->tmg.tmg_caslatency = spd[JEDEC_SPD_CASLATENCIES]; 851 init->tmg.tmg_attributes = spd[JEDEC_SPD_ATTRIBUTES]; 852 init->tmg.tmg_tRAS = spd[JEDEC_SPD_tRAS]; 853 init->tmg.tmg_tRP = spd[JEDEC_SPD_tRP]; 854 init->tmg.tmg_tRRD = spd[JEDEC_SPD_tRRD]; 855 init->tmg.tmg_tRCD = spd[JEDEC_SPD_tRCD]; 856 init->tmg.tmg_tRFC = spd[JEDEC_SPD_tRFC]; 857 init->tmg.tmg_tRC = spd[JEDEC_SPD_tRC]; 858 init++; 859 } 860 861 862 863 init->cfg.cfg_type = MCR_CHCFG; 864 init->cfg.cfg_chan = 1; 865 init->cfg.cfg_mintmemclk = mintmemclk; 866 init->cfg.cfg_chantype = MC_64BIT_CHAN; 867 init->cfg.cfg_dramtype = dramtype; 868 init->cfg.cfg_pagepolicy = CASCHECK; 869 init->cfg.cfg_intlv_cs = NOCSINTLV; 870 init->cfg.cfg_ecc = 0; 871 init->cfg.cfg_roundtrip = roundtrip; 872 init++; 873 874 875 if (spdmode) { 876 init->spd.spd_type = MCR_SPD; 877 init->spd.spd_csel = 0; 878 init->spd.spd_flags = 0; 879 init->spd.spd_smbuschan = 0; 880 init->spd.spd_smbusdev = 0x50; 881 init++; 882 } 883 else { 884 init->geom.geom_type = MCR_GEOM; 885 init->geom.geom_csel = 0; 886 init->geom.geom_rows = spd[JEDEC_SPD_ROWS]; 887 init->geom.geom_cols = spd[JEDEC_SPD_COLS]; 888 init->geom.geom_banks = banks2bits(spd[JEDEC_SPD_BANKS]); 889 init++; 890 891 init->tmg.tmg_type = MCR_TIMING; 892 init->tmg.tmg_tCK = spd[JEDEC_SPD_tCK25]; 893 init->tmg.tmg_rfsh = spd[JEDEC_SPD_RFSH]; 894 init->tmg.tmg_caslatency = spd[JEDEC_SPD_CASLATENCIES]; 895 init->tmg.tmg_attributes = spd[JEDEC_SPD_ATTRIBUTES]; 896 init->tmg.tmg_tRAS = spd[JEDEC_SPD_tRAS]; 897 init->tmg.tmg_tRP = spd[JEDEC_SPD_tRP]; 898 init->tmg.tmg_tRRD = spd[JEDEC_SPD_tRRD]; 899 init->tmg.tmg_tRCD = spd[JEDEC_SPD_tRCD]; 900 init->tmg.tmg_tRFC = spd[JEDEC_SPD_tRFC]; 901 init->tmg.tmg_tRC = spd[JEDEC_SPD_tRC]; 902 init++; 903 } 904 905 906 if (spdmode) { 907 init->spd.spd_type = MCR_SPD; 908 init->spd.spd_csel = 2; 909 init->spd.spd_flags = 0; 910 init->spd.spd_smbuschan = 0; 911 init->spd.spd_smbusdev = 0x50; 912 init++; 913 } 914 else { 915 init->geom.geom_type = MCR_GEOM; 916 init->geom.geom_csel = 2; 917 init->geom.geom_rows = spd[JEDEC_SPD_ROWS]; 918 init->geom.geom_cols = spd[JEDEC_SPD_COLS]; 919 init->geom.geom_banks = banks2bits(spd[JEDEC_SPD_BANKS]); 920 init++; 921 922 init->tmg.tmg_type = MCR_TIMING; 923 init->tmg.tmg_tCK = spd[JEDEC_SPD_tCK25]; 924 init->tmg.tmg_rfsh = spd[JEDEC_SPD_RFSH]; 925 init->tmg.tmg_caslatency = spd[JEDEC_SPD_CASLATENCIES]; 926 init->tmg.tmg_attributes = spd[JEDEC_SPD_ATTRIBUTES]; 927 init->tmg.tmg_tRAS = spd[JEDEC_SPD_tRAS]; 928 init->tmg.tmg_tRP = spd[JEDEC_SPD_tRP]; 929 init->tmg.tmg_tRRD = spd[JEDEC_SPD_tRRD]; 930 init->tmg.tmg_tRCD = spd[JEDEC_SPD_tRCD]; 931 init->tmg.tmg_tRFC = spd[JEDEC_SPD_tRFC]; 932 init->tmg.tmg_tRC = spd[JEDEC_SPD_tRC]; 933 init++; 934 } 935 936#endif 937 938 init->mcr.mcr_type = MCR_EOT; 939 940 941 bcm1480_refclk = (int) refclk; 942 943 bcm1480_dram_init(inittab,NULL); 944 945 printf("----Geometry infomration----\n"); 946 printf("Rows=%d, Columns=%d, Banks=%d\n",spd[JEDEC_SPD_ROWS],spd[JEDEC_SPD_COLS],spd[JEDEC_SPD_BANKS]); 947 948 printf("----Start/End Register Values---\n"); 949 printf("MC0: Start %016llX End %016llX\n", mc_cs_start0,mc_cs_end0); 950 printf("MC1: Start %016llX End %016llX\n", mc_cs_start1,mc_cs_end1); 951 printf("MC2: Start %016llX End %016llX\n", mc_cs_start2,mc_cs_end2); 952 printf("MC3: Start %016llX End %016llX\n", mc_cs_start3,mc_cs_end3); 953 954 printf("-----Memory Timing Register Values-----\n"); 955 printf("System Clock %dMHz\n",plldiv*refclk/2); 956 printf("CAS latency %d.%d\n",dram_cas_latency>>1,(dram_cas_latency&1)?5:0); 957 printf("tMemClk %d.%d ns\n",dram_tMemClk/10,dram_tMemClk%10); 958 printf("mclk_ratio %d.%d [%d]\n",((int)G_BCM1480_MC_CLK_RATIO(mc0_mclkcfg))/4, 959 (((int)G_BCM1480_MC_CLK_RATIO(mc0_mclkcfg))%4)*25, 960 ((int)G_BCM1480_MC_CLK_RATIO(mc0_mclkcfg))); 961 zclk = (plldiv*refclk/2)/2; 962 mclk = (zclk*10*4/((int)G_BCM1480_MC_CLK_RATIO(mc0_mclkcfg))); 963 printf("ZCLK Freq %dMHz\n",zclk); 964 printf("MCLK Freq %d.%dMHz\n",mclk/10,mclk%10); 965 printf("\n"); 966 printf("MC_TIMING1 = %016llX\n",mc0_timing1); 967 printf("MCLK_CONFIG = %016llX\n",mc0_mclkcfg); 968 printf("\n"); 969 970 printf("-----Memory Timing Register Fields-----\n"); 971 dumptiming1(mc0_timing1); 972 973 printf("-----Memory Clock Config Register Fields-----\n"); 974 dumpmclkcfg(mc0_mclkcfg); 975 976 printf("---Done!---\n"); 977 978 printf("%s ",argv[0]); 979 sf = spdfields; 980 while (sf->name) { 981 char buffer[64]; 982 char *p = buffer; 983 984 t = *(sf->data); 985 986 p += sprintf(p,"%s=",sf->name); 987 switch (sf->decimal) { 988 case SPD_DEC_BCD: 989 p += sprintf(p,"%d.%d", 990 t >> 4, t & 0x0F); 991 break; 992 case SPD_DEC_QTR: 993 p += sprintf(p,"%d.%02d", 994 t/4,(t&3)*25); 995 break; 996 case SPD_ENCODED: 997 default: 998 p += sprintf(p,"0x%02X",t); 999 break; 1000 } 1001 1002 printf("%s ",buffer); 1003 sf++; 1004 } 1005 1006 printf("\n"); 1007 1008 return 0; 1009} 1010