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