1/*  *********************************************************************
2    *  Broadcom Common Firmware Environment (CFE)
3    *
4    *  Memory Config Utility			File: memconfig.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 "sb1250_mc.h"
69#include "sb1250_draminit.h"
70#include "sb1250_regs.h"
71#include "sb1250_scd.h"
72
73/*  *********************************************************************
74    *  BCD macros
75    ********************************************************************* */
76
77#define DECTO10THS(x) ((((x) >> 4)*10)+((x) & 0x0F))
78
79/*  *********************************************************************
80    *  Global defaults
81    ********************************************************************* */
82
83#define MIN_tMEMCLK DRT10(8,0)
84#define tROUNDTRIP DRT10(2,5)
85
86/*  *********************************************************************
87    *  Types
88    ********************************************************************* */
89
90typedef struct encvalue_s {
91    char *name;
92    uint8_t val;
93} encvalue_t;
94
95typedef struct spdbyte_s {
96    char *name;
97    uint8_t *data;
98    int decimal;
99    encvalue_t *values;
100    char *units;
101    char *description;
102    char *deflt;
103} spdbyte_t;
104
105#define SPD_DEC_BCD	1
106#define SPD_DEC_QTR	2
107#define SPD_ENCODED	3
108#define SPD_ENCODED2	4
109
110#define SPD_SIZE	64
111
112/*  *********************************************************************
113    *  Globals
114    ********************************************************************* */
115
116
117uint8_t spd[SPD_SIZE] = {0};		/* SPD data */
118uint8_t mintmemclk = MIN_tMEMCLK;	/* Default value: 8.0ns */
119uint8_t roundtrip = tROUNDTRIP;		/* Default value: 2.5ns */
120uint8_t dramtype = JEDEC;		/* Regular DDR SDRAMs */
121uint8_t plldiv = 16;			/* 500 MHz using 100Mhz refclk */
122uint8_t refclk = 100;			/* 100Mhz reference clock */
123uint8_t portintlv = 0;			/* no port interleaving */
124
125uint8_t addrskew = 0x8;
126uint8_t dqoskew = 0x8;
127uint8_t dqiskew = 0x8;
128uint8_t addrdrive = 0xF;
129uint8_t datadrive = 0xF;
130uint8_t clkdrive = 0xF;
131
132uint64_t mc0_mclkcfg;			/* Value programmed by draminit */
133uint64_t mc0_timing1;			/* Value programmed by draminit */
134uint64_t mc1_mclkcfg;			/* Value programmed by draminit */
135uint64_t mc1_timing1;			/* Value programmed by draminit */
136uint64_t mc0_config,mc1_config;
137uint64_t mc0_cs_start,mc0_cs_end;
138uint64_t mc1_cs_start,mc1_cs_end;
139uint64_t smbus0_start = 0;		/* Rememberd SMBus register value */
140uint64_t smbus0_cmd = 0;		/* Rememberd SMBus register value */
141
142extern int sb1250_refclk;		/* from draminit - reference clock */
143extern int dram_cas_latency;		/* from draminit - calc'd cas latency */
144extern int dram_tMemClk;		/* from draminit - calc'd tMemClk */
145
146draminittab_t inittab[16];		/* our init tab */
147
148static uint8_t csels = 1;
149static uint8_t channels = 1;
150
151int debug = 0;
152int asmout = 0;
153FILE *asmoutfile = NULL;
154
155uint64_t sbreadcsr(uint64_t reg);
156void sbwritecsr(uint64_t reg,uint64_t val);
157void sbdelay(void);
158uint64_t sb1250_dram_init(draminittab_t *tab,void *data);
159
160/*  *********************************************************************
161    *  Parameter and value tables
162    ********************************************************************* */
163
164encvalue_t caslatencies[] = {
165    {"3.5",JEDEC_CASLAT_35},
166    {"3.0",JEDEC_CASLAT_30},
167    {"2.5",JEDEC_CASLAT_25},
168    {"2.0",JEDEC_CASLAT_20},
169    {"1.5",JEDEC_CASLAT_15},
170    {"1.0",JEDEC_CASLAT_10},
171    {NULL,0}};
172
173encvalue_t refreshrates[] = {
174    {"64",JEDEC_RFSH_64khz},
175    {"256",JEDEC_RFSH_256khz},
176    {"128",JEDEC_RFSH_128khz},
177    {"32",JEDEC_RFSH_32khz},
178    {"16",JEDEC_RFSH_16khz},
179    {"8",JEDEC_RFSH_8khz},
180    {NULL,0}};
181
182encvalue_t modattribs[] = {
183    {"none",0},
184    {"reg",JEDEC_ATTRIB_REG},
185    {"diffclk",0x20},
186    {NULL,0}};
187
188encvalue_t dramtypes[] = {
189    {"jedec",JEDEC},
190    {"fcram",FCRAM},
191    {"sgram",SGRAM},
192    {NULL,0}};
193
194spdbyte_t spdfields[] = {
195    {"plldiv",    &plldiv,    0,NULL,"","PLL Ratio (System Config Register)","16"},
196    {"refclk",    &refclk,    0,NULL,"Mhz","Reference clock, usually 100Mhz","100"},
197    {"mintmemclk",&mintmemclk,SPD_DEC_BCD,NULL,"ns","Minimum value for tMEMCLK","8.0"},
198    {"roundtrip", &roundtrip, SPD_DEC_BCD,NULL,"ns","Round trip time from CLK to returned DQS","2.5"},
199    {"chans",     &channels,  0,NULL,"","Bitmask of enabled channels (bit0=chan0)","1"},
200    {"csels",     &csels,     0,NULL,"","Bitmask of enabled chipsels","1"},
201    {"portintlv", &portintlv, 0,NULL,"","Port interleave (1=on)","0"},
202    {"memtype",   &dramtype,  SPD_ENCODED,dramtypes,"","Memory type (jedec, fcram, sgram)","jedec"},
203    {"rows",      &spd[JEDEC_SPD_ROWS],0,NULL,"","[3 ] Number of row bits","13"},
204    {"cols",      &spd[JEDEC_SPD_COLS],0,NULL,"","[4 ] Number of column bits","9"},
205    {"banks",     &spd[JEDEC_SPD_BANKS],0,NULL,"","[17] Number of banks","4"},
206    {"tCK25",     &spd[JEDEC_SPD_tCK25],SPD_DEC_BCD,NULL,"ns","[9 ] tCK value for CAS Latency 2.5","7.5"},
207    {"tCK20",     &spd[JEDEC_SPD_tCK20],SPD_DEC_BCD,NULL,"ns","[23] tCK value for CAS Latency 2.0","0"},
208    {"tCK10",     &spd[JEDEC_SPD_tCK10],SPD_DEC_BCD,NULL,"ns","[25] tCK value for CAS Latency 1.0","0"},
209    {"rfsh",      &spd[JEDEC_SPD_RFSH],SPD_ENCODED,refreshrates,"","[12] Refresh rate (KHz)","8"},
210    {"caslat",    &spd[JEDEC_SPD_CASLATENCIES],SPD_ENCODED2,caslatencies,"","[18] CAS Latencies supported","2.5"},
211    {"attrib",    &spd[JEDEC_SPD_ATTRIBUTES],SPD_ENCODED,modattribs,"","[21] Module attributes","none"},
212    {"tRAS",      &spd[JEDEC_SPD_tRAS],0,NULL,"ns","[30]","45"},
213    {"tRP",       &spd[JEDEC_SPD_tRP],SPD_DEC_QTR,NULL,"ns","[27]","20.0"},
214    {"tRRD",      &spd[JEDEC_SPD_tRRD],SPD_DEC_QTR,NULL,"ns","[28]","15.0"},
215    {"tRCD",      &spd[JEDEC_SPD_tRCD],SPD_DEC_QTR,NULL,"ns","[29]","20.0"},
216    {"tRFC",      &spd[JEDEC_SPD_tRFC],0,NULL,"ns","[42]","0"},
217    {"tRC",       &spd[JEDEC_SPD_tRC],0,NULL,"ns","[41]","0"},
218
219    {"addrskew",  &addrskew, 0, NULL, "","Address Skew","0x0F"},
220    {"dqoskew",   &dqoskew, 0, NULL, "","DQO Skew","0x08"},
221    {"dqikew",    &dqiskew, 0, NULL, "","DQI Skew","0x08"},
222    {"addrdrive", &addrdrive, 0, NULL, "","Address Drive","0x0F"},
223    {"datadrive", &datadrive, 0, NULL, "","Data Drive","0x0F"},
224    {"clkdrive",  &clkdrive, 0, NULL, "","Clock Drive","0"},
225    {NULL,0,0,NULL,NULL,NULL,NULL}};
226
227static char *lookupstr(encvalue_t *ev,uint8_t val)
228{
229    while (ev->name) {
230	if (ev->val == val) return ev->name;
231	ev++;
232	}
233    return "unknown";
234}
235
236uint64_t sbreadcsr(uint64_t reg)
237{
238    uint64_t val = 0;
239
240    if (debug) printf("READ %08X\n",(uint32_t) reg);
241
242
243    switch ((uint32_t) reg) {
244	case A_SCD_SYSTEM_REVISION:
245	    val = V_SYS_PART(0x1250) | V_SYS_WID(0) | V_SYS_REVISION(K_SYS_REVISION_PASS2) | 0xFF;
246	    break;
247	case A_SCD_SYSTEM_CFG:
248	    val = V_SYS_PLL_DIV(plldiv);
249	    break;
250	case A_SMB_STATUS_0:
251	    val = 0;
252	    break;
253	case A_SMB_CMD_0:
254	    val = smbus0_cmd;
255	    break;
256	case A_SMB_START_0:
257	    val = smbus0_start;
258	    break;
259	case A_SMB_DATA_0:
260	    val = spd[smbus0_cmd & 0x3F];
261	    break;
262	case A_MC_REGISTER(0,R_MC_CS_START):
263	    val = mc0_cs_start;
264	    break;
265	case A_MC_REGISTER(0,R_MC_CS_END):
266	    val = mc0_cs_end;
267	    break;
268	case A_MC_REGISTER(0,R_MC_CONFIG):
269	    val = mc0_config;
270	    break;
271	case A_MC_REGISTER(1,R_MC_CS_START):
272	    val = mc1_cs_start;
273	    break;
274	case A_MC_REGISTER(1,R_MC_CS_END):
275	    val = mc1_cs_end;
276	    break;
277	case A_MC_REGISTER(1,R_MC_CONFIG):
278	    val = mc1_config;
279	    break;
280	default:
281	    printf("Warning: CSR %08X not supported by emulated SBREADCSR\n",(uint32_t)reg);
282	}
283    return val;
284}
285
286void sbdelay(void)
287{
288    if (asmoutfile) fprintf(asmoutfile,"\t.dword 0xFFFFFFFFFFFFFFFF,0xFFFFFFFFFFFFFFFF /* Insert delay here */\n");
289}
290
291void sbwritecsr(uint64_t reg,uint64_t val)
292{
293    if (debug) printf("WRITE %08X  %016llX\n",(uint32_t) reg,val);
294
295    if (asmoutfile) fprintf(asmoutfile,"\t.dword 0x%016llX,0x%016llX\n",reg,val);
296
297    switch ((uint32_t) reg) {
298	case A_MC_REGISTER(0,R_MC_MCLK_CFG):
299	    mc0_mclkcfg = val;
300	    break;
301	case A_MC_REGISTER(0,R_MC_TIMING1):
302	    mc0_timing1 = val;
303	    break;
304	case A_MC_REGISTER(1,R_MC_MCLK_CFG):
305	    mc1_mclkcfg = val;
306	    break;
307	case A_MC_REGISTER(1,R_MC_TIMING1):
308	    mc1_timing1 = val;
309	    break;
310	case A_SMB_CMD_0:
311	    smbus0_cmd = val;
312	    break;
313	case A_SMB_START_0:
314	    smbus0_start = val;
315	    break;
316	case A_MC_REGISTER(0,R_MC_CS_START):
317	    mc0_cs_start = val;
318	    break;
319	case A_MC_REGISTER(0,R_MC_CS_END):
320	    mc0_cs_end = val;
321	    break;
322	case A_MC_REGISTER(0,R_MC_CONFIG):
323	    mc0_config = val;
324	    break;
325	case A_MC_REGISTER(1,R_MC_CS_START):
326	    mc1_cs_start = val;
327	    break;
328	case A_MC_REGISTER(1,R_MC_CS_END):
329	    mc1_cs_end = val;
330	    break;
331	case A_MC_REGISTER(1,R_MC_CONFIG):
332	    mc1_config = val;
333	    break;
334	default:
335	    break;
336	}
337}
338
339static int readspdfile(uint8_t *spd,char *fname)
340{
341    FILE *str;
342    char line[500];
343    char *x;
344    unsigned int addr,val;
345    int idx;
346    uint8_t ttl;
347
348    str = fopen(fname,"r");
349    if (!str) {
350	perror(fname);
351	return -1;
352	}
353
354    memset(spd,0,SPD_SIZE);
355
356    while (!feof(str)) {
357	if (!fgets(line,sizeof(line),str)) break;
358	if ((x = strchr(line,'\r'))) *x = '\0';
359	if (line[0] == '\0') continue;	/* blank line */
360	if (line[0] == '#') continue;	/* comment */
361	if (strchr(line,'=') == NULL) continue;
362	if (sscanf(line,"%u=%02x",&addr,&val) != 2) {
363	    printf("Incorrect line format: %s\n",line);
364	    continue;
365	    }
366	if ((addr >= SPD_SIZE) || (val >= 0x100)) {
367	    printf("Values out of range: %s\n",line);
368	    continue;
369	    }
370
371	spd[addr] = val;
372	}
373
374    ttl = 0;
375    for (idx = 0; idx < 63; idx++) ttl += spd[idx];
376
377    if (ttl != spd[63]) printf("Warning: checksum mismatch on SPD file: %02X\n",ttl);
378
379    fclose(str);
380    return 0;
381}
382
383
384static int procfield(char *txt)
385{
386    int num = 0;
387    int a,b;
388    spdbyte_t *sf;
389    encvalue_t *ev;
390    char *x;
391    char *tok;
392
393    x = strchr(txt,'=');
394    if (!x) {
395	printf("Fields must be specified as 'name=value'\n");
396	exit(1);
397	}
398    *x++ = '\0';
399
400    sf = spdfields;
401    while (sf->name) {
402	if (strcmp(sf->name,txt) == 0) break;
403	sf++;
404	}
405
406    if (sf->name == NULL) {
407	printf("Invalid field name: %s\n",txt);
408	return -1;
409	}
410
411    if (memcmp(x,"0x",2) == 0) {
412	sscanf(x+2,"%x",&num);
413	}
414    else {
415	if (strchr(x,'.')) {
416	    if (sscanf(x,"%d.%d",&a,&b) != 2) {
417		printf("%s: invalid number: %s\n",sf->name,x);
418		return -1;
419		}
420	    }
421	else {
422	    a = atoi(x);
423	    b = 0;
424	    }
425
426	switch (sf->decimal) {
427	    case SPD_DEC_BCD:
428		if ((b < 0) || (b > 9)) {
429		    printf("%s: Invalid BCD number: %s\n",sf->name,x);
430		    return -1;
431		    }
432		num = (a*16)+b;
433		break;
434	    case SPD_DEC_QTR:
435		if ((b != 0) && (b != 25) && (b != 50) && (b != 75)) {
436		    printf("%s: Invalid 2-bit fraction number: %s\n",sf->name,x);
437		    printf("(number after decimal should be 0,25,50,75)\n");
438		    exit(1);
439		    }
440		num = (a*4)+(b/25);
441		break;
442	    case SPD_ENCODED:
443		ev = sf->values;
444		while (ev->name) {
445		    if (strcmp(ev->name,x) == 0) break;
446		    ev++;
447		    }
448		if (!ev->name) {
449		    printf("%s: Invalid value.  Valid values are: ",x);
450		    ev = sf->values;
451		    while (ev->name) { printf("%s ",ev->name); ev++; }
452		    printf("\n");
453		    return -1;
454		    }
455		num = ev->val;
456		break;
457	    case SPD_ENCODED2:
458		tok = strtok(x," ,");
459		num = 0;
460		while (tok) {
461		    ev = sf->values;
462		    while (ev->name) {
463			if (strcmp(ev->name,tok) == 0) break;
464			ev++;
465			}
466		    if (!ev->name) {
467			printf("%s: Invalid value.  Valid values are: ",tok);
468			ev = sf->values;
469			while (ev->name) { printf("%s ",ev->name); ev++; }
470			printf("\n");
471			return -1;
472			}
473		    num |= ev->val;
474		    tok = strtok(NULL," ,");
475		    }
476		break;
477	    default:
478		num = a;
479		break;
480	    }
481	}
482
483    *(sf->data) = num;
484
485    return 0;
486}
487
488static void interactive(int spdfilemode)
489{
490    spdbyte_t *sf;
491    char field[100];
492    char ask[100];
493    char prompt[100];
494    char *x;
495
496    sf = spdfields;
497
498    printf("%-65.65s: Value\n","Parameter");
499    printf("%-65.65s: -----\n","-----------------------------------------------------------------");
500
501    while (sf->name) {
502	/*
503	 * Gross hack: If in SPD file mode, skip parameters that will be placed
504	 * in the SPD.
505	 */
506
507	if (spdfilemode && (sf->data >= &spd[0]) && (sf->data < &spd[SPD_SIZE])) {
508	    sf++;
509	    continue;
510	    }
511
512	for (;;) {
513	    x = prompt;
514	    x += sprintf(x,"%s (%s", sf->name,sf->description);
515	    if (sf->units && sf->units[0]) {
516		if (sf->description && sf->description[0]) x += sprintf(x,", ");
517		x += sprintf(x,"%s",sf->units);
518		}
519	    x += sprintf(x,"): [%s]", sf->deflt);
520	    printf("%-65.65s: ",prompt);
521
522	    fgets(ask,sizeof(ask),stdin);
523	    if ((x = strchr(ask,'\n'))) *x = '\0';
524	    if (ask[0] == 0) strcpy(ask,sf->deflt);
525	    sprintf(field,"%s=%s",sf->name,ask);
526	    if (procfield(field) < 0) continue;
527	    break;
528	    }
529	sf++;
530	}
531
532    printf("\n\n");
533}
534
535int swcnt = 0;
536char *swnames[32];
537
538static int proc_args(int argc,char *argv[])
539{
540    int inidx,outidx;
541
542    outidx = 1;
543
544    for (inidx = 1; inidx < argc; inidx++) {
545	if (argv[inidx][0] != '-') {
546	    argv[outidx++] = argv[inidx];
547	    }
548	else {
549	    swnames[swcnt] = argv[inidx];
550	    swcnt++;
551	    }
552	}
553
554    return outidx;
555}
556
557static int swisset(char *x)
558{
559    int idx;
560    char tempname[500];
561    char *zz;
562
563
564    for (idx = 0; idx < swcnt; idx++) {
565	strcpy(tempname,swnames[idx]);
566	if ((zz = strchr(tempname,'='))) *zz = '\0';
567	if (strcmp(x,tempname) == 0) return 1;
568	}
569    return 0;
570}
571
572static int swvalue(char *x,char **val)
573{
574    int idx;
575    char tempname[500];
576    char *zz;
577
578    for (idx = 0; idx < swcnt; idx++) {
579	strcpy(tempname,swnames[idx]);
580	if ((zz = strchr(tempname,'='))) *zz = '\0';
581	if (strcmp(x,tempname) == 0) {
582	    zz = strchr(swnames[idx],'=');	/* should never return NULL*/
583	    *val = (zz+1);
584	    return 1;
585	    }
586	}
587    return 0;
588}
589
590static void dumpmclkcfg(uint64_t val)
591{
592    printf("clk_ratio = %d\n",(int)G_MC_CLK_RATIO(val));
593    printf("ref_rate  = %d\n",(int)G_MC_REF_RATE(val));
594
595}
596
597static void dumptiming1(uint64_t val)
598{
599    printf("w2rIdle     = %d\n",(val & M_MC_w2rIDLE_TWOCYCLES) ? 1 : 0);
600    printf("r2rIdle     = %d\n",(val & M_MC_r2rIDLE_TWOCYCLES) ? 1 : 0);
601    printf("r2wIdle     = %d\n",(val & M_MC_r2wIDLE_TWOCYCLES) ? 1 : 0);
602    printf("tCrD        = %d\n",(int)G_MC_tCrD(val));
603    printf("tCrDh       = %d\n",(val & M_MC_tCrDh) ? 1 : 0);
604    printf("tFIFO       = %d\n",(int)G_MC_tFIFO(val));
605    printf("tCwD        = %d\n",(int)G_MC_tCwD(val));
606
607    printf("tRP         = %d\n",(int)G_MC_tRP(val));
608    printf("tRRD        = %d\n",(int)G_MC_tRRD(val));
609    printf("tRCD        = %d\n",(int)G_MC_tRCD(val));
610
611    printf("tRFC        = %d\n",(int)G_MC_tRFC(val));
612    printf("tRFC_PLUS16 = %d\n", ((val & M_MC_tRFC_PLUS16) != 0 ? 1 : 0));
613    printf("tRCw        = %d\n",(int)G_MC_tRCw(val));
614    printf("tRCr        = %d\n",(int)G_MC_tRCr(val));
615    printf("tCwCr       = %d\n",(int)G_MC_tCwCr(val));
616}
617
618int main(int argc,char *argv[])
619{
620    spdbyte_t *sf;
621    uint8_t t;
622    int idx;
623    int csidx;
624    int chidx;
625    int mclk;
626    draminittab_t *init;
627    int spdmode = 0;
628    char *spdname = NULL;
629
630    spd[JEDEC_SPD_MEMTYPE] = JEDEC_MEMTYPE_DDRSDRAM2;
631    spd[JEDEC_SPD_ROWS]	   = 13;
632    spd[JEDEC_SPD_COLS]    = 9;
633    spd[JEDEC_SPD_BANKS]   = 2;
634    spd[JEDEC_SPD_SIDES]   = 1;
635    spd[JEDEC_SPD_WIDTH]   = 72;
636
637    argc = proc_args(argc,argv);
638
639    if (swvalue("-spd",&spdname)) {
640	printf("[Reading SPD file: %s]\n",spdname);
641	readspdfile(spd,spdname);
642	}
643
644    if ((argc == 1) && !swisset("-i")) {
645	printf("usage: memconfig name=value name=value ...\n");
646	printf("\n");
647	printf("Available fields: ");
648	sf = spdfields;
649	while (sf->name) {
650	    printf("%s ",sf->name);
651	    sf++;
652	    }
653	printf("\n");
654	exit(1);
655	}
656
657    if (swisset("-i")) {
658	interactive((spdname != NULL));
659	}
660    else {
661	for (idx = 1; idx < argc; idx++) {
662	    if (procfield(argv[idx]) < 0) exit(1);
663	    }
664	}
665
666    debug = swisset("-d");
667
668    spdmode = swisset("-spd");
669
670    asmout = swisset("-a");
671    if (asmout) {
672	char fname[100];
673	sprintf(fname,"%s.inc",argv[0]);
674	asmoutfile = fopen(fname,"w");
675	if (asmoutfile) printf("[Writing memory init sequence to file '%s']\n",fname);
676	}
677
678    printf("-------Memory Parameters---------\n");
679
680    sf = spdfields;
681    while (sf->name) {
682	char buffer[64];
683	char *p = buffer;
684
685	t = *(sf->data);
686	printf("%-10.10s = 0x%02X  ",sf->name,t);
687	switch (sf->decimal) {
688	    case SPD_DEC_BCD:
689		p += sprintf(p,"(%d.%d)",
690		       t >> 4, t & 0x0F);
691		break;
692	    case SPD_DEC_QTR:
693		p += sprintf(p,"(%d.%02d)",
694		       t/4,(t&3)*25);
695		break;
696	    case SPD_ENCODED:
697		p += sprintf(p,"(%s)",lookupstr(sf->values,t));
698		break;
699	    default:
700		p += sprintf(p,"(%d)",t);
701		break;
702	    }
703
704	p += sprintf(p," %s",sf->units);
705	printf("%-16.16s  %s\n",buffer,sf->description);
706	sf++;
707	}
708
709    printf("\n");
710
711    init = &inittab[0];
712    memset(inittab,0,sizeof(inittab));
713
714    init->gbl.gbl_type = MCR_GLOBALS;
715    init->gbl.gbl_intlv_ch = portintlv;
716    init++;
717
718    for (chidx = 0; chidx < 2; chidx++) {
719	if (channels & (1<<chidx)) {
720
721	    init->cfg.cfg_type = MCR_CHCFG;
722	    init->cfg.cfg_chan = chidx;
723	    init->cfg.cfg_mintmemclk = mintmemclk;
724	    init->cfg.cfg_dramtype = dramtype;
725	    init->cfg.cfg_pagepolicy = CASCHECK;
726	    init->cfg.cfg_blksize = BLKSIZE32;
727	    init->cfg.cfg_intlv_cs = NOCSINTLV;
728	    init->cfg.cfg_ecc = 0;
729	    init->cfg.cfg_roundtrip = roundtrip;
730	    init++;
731
732	    init->clk.clk_type = MCR_CLKCFG;
733	    init->clk.clk_addrskew = addrskew;
734	    init->clk.clk_dqoskew = dqoskew;
735	    init->clk.clk_dqiskew = dqiskew;
736	    init->clk.clk_addrdrive = addrdrive;
737	    init->clk.clk_datadrive = datadrive;
738	    init->clk.clk_clkdrive = clkdrive;
739	    init++;
740
741	    for (csidx = 0; csidx < 4; csidx++) {
742
743		if (spdmode) {
744		    /* Assume double sided dimm support and dimms on even chip selects */
745		    if ((csels & (1<<csidx)) && ((csidx & 1) == 0)) {
746			init->spd.spd_type = MCR_SPD;
747			init->spd.spd_csel = csidx;
748			init->spd.spd_flags = 0;
749			init->spd.spd_smbuschan = 0;
750			init->spd.spd_smbusdev = 0x50;
751			init++;
752			}
753		    }
754		else {
755		    if (csels & (1<<csidx)) {
756			init->geom.geom_type = MCR_GEOM;
757			init->geom.geom_csel = csidx;
758			init->geom.geom_rows = spd[JEDEC_SPD_ROWS];
759			init->geom.geom_cols = spd[JEDEC_SPD_COLS];
760			init->geom.geom_banks = spd[JEDEC_SPD_BANKS];
761			init++;
762
763			init->tmg.tmg_type = MCR_TIMING;
764			init->tmg.tmg_tCK =  spd[JEDEC_SPD_tCK25];
765			init->tmg.tmg_rfsh = spd[JEDEC_SPD_RFSH];
766			init->tmg.tmg_caslatency = spd[JEDEC_SPD_CASLATENCIES];
767			init->tmg.tmg_attributes = spd[JEDEC_SPD_ATTRIBUTES];
768			init->tmg.tmg_tRAS = spd[JEDEC_SPD_tRAS];
769			init->tmg.tmg_tRP = spd[JEDEC_SPD_tRP];
770			init->tmg.tmg_tRRD = spd[JEDEC_SPD_tRRD];
771			init->tmg.tmg_tRCD = spd[JEDEC_SPD_tRCD];
772			init->tmg.tmg_tRFC = spd[JEDEC_SPD_tRFC];
773			init->tmg.tmg_tRC = spd[JEDEC_SPD_tRC];
774			init++;
775			}
776		    }
777		}
778	    }
779	}
780
781    init->mcr.mcr_type = MCR_EOT;
782
783
784    sb1250_refclk = (int) refclk;
785
786    sb1250_dram_init(inittab,NULL);
787
788
789    printf("-----Memory Timing Register Values-----\n");
790    printf("System Clock    %dMHz\n",plldiv*refclk/2);
791    printf("CAS latency     %d.%d\n",dram_cas_latency>>1,(dram_cas_latency&1)?5:0);
792    printf("tMemClk         %d.%d ns\n",dram_tMemClk/10,dram_tMemClk%10);
793    if (channels & 1) mclk = (plldiv*refclk)*10/2/((int)G_MC_CLK_RATIO(mc0_mclkcfg));
794    else if (channels & 2) mclk = (plldiv*refclk)*10/2/((int)G_MC_CLK_RATIO(mc1_mclkcfg));
795    else mclk = 0;
796    printf("MCLK Freq       %d.%dMHz\n",mclk/10,mclk%10);
797    printf("\n");
798    if (channels & 1) {
799	printf("MC_TIMING1  = %016llX\n",mc0_timing1);
800	printf("MCLK_CONFIG = %016llX\n",mc0_mclkcfg);
801	}
802    else if (channels & 2) {
803	printf("MC_TIMING1  = %016llX\n",mc1_timing1);
804	printf("MCLK_CONFIG = %016llX\n",mc1_mclkcfg);
805	}
806    printf("\n");
807
808    printf("-----Memory Timing Register Fields-----\n");
809    if (channels & 1) dumptiming1(mc0_timing1);
810    else if (channels & 2) dumptiming1(mc1_timing1);
811
812    printf("-----Memory Clock Config Register Fields-----\n");
813    if (channels & 1) dumpmclkcfg(mc0_mclkcfg);
814    else if (channels & 2) dumpmclkcfg(mc1_mclkcfg);
815
816    printf("---Done!---\n");
817
818    printf("%s ",argv[0]);
819    if (spdmode) {
820	if (spdname) printf("-spd=%s ",spdname);
821	else printf("-spd ");
822	}
823    sf = spdfields;
824    while (sf->name) {
825	char buffer[64];
826	char *p = buffer;
827
828	if (spdname && (sf->data >= &spd[0]) && (sf->data < &spd[SPD_SIZE])) {
829	    sf++;
830	    continue;
831	    }
832
833	t = *(sf->data);
834
835	p += sprintf(p,"%s=",sf->name);
836	switch (sf->decimal) {
837	    case SPD_DEC_BCD:
838		p += sprintf(p,"%d.%d",
839		       t >> 4, t & 0x0F);
840		break;
841	    case SPD_DEC_QTR:
842		p += sprintf(p,"%d.%02d",
843		       t/4,(t&3)*25);
844		break;
845	    case SPD_ENCODED:
846	    default:
847		p += sprintf(p,"0x%02X",t);
848		break;
849	    }
850
851	printf("%s ",buffer);
852	sf++;
853	}
854
855    printf("\n");
856
857    if (asmoutfile) {
858	fprintf(asmoutfile,"\t.dword 0,0  /* End of Table */\n");
859	fclose(asmoutfile);
860	}
861
862    return 0;
863}
864