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