1 /*
2  * (C) Copyright 2007-2008
3  * Matthias Fuchs, esd Gmbh, matthias.fuchs@esd-electronics.com.
4  *
5  * SPDX-License-Identifier:	GPL-2.0+
6  */
7 #include <common.h>
8 #include <command.h>
9 #include <asm/io.h>
10 #include <asm/cache.h>
11 #include <asm/processor.h>
12 #if defined(CONFIG_LOGBUFFER)
13 #include <logbuff.h>
14 #endif
15 
16 #include "pmc440.h"
17 
18 int is_monarch(void);
19 int bootstrap_eeprom_write(unsigned dev_addr, unsigned offset,
20 			   uchar *buffer, unsigned cnt);
21 int eeprom_write_enable(unsigned dev_addr, int state);
22 
23 DECLARE_GLOBAL_DATA_PTR;
24 
25 #if defined(CONFIG_CMD_BSP)
26 
27 static int got_fifoirq;
28 static int got_hcirq;
29 
fpga_interrupt(u32 arg)30 int fpga_interrupt(u32 arg)
31 {
32 	pmc440_fpga_t *fpga = (pmc440_fpga_t *)arg;
33 	int rc = -1; /* not for us */
34 	u32 status = FPGA_IN32(&fpga->status);
35 
36 	/* check for interrupt from fifo module */
37 	if (status & STATUS_FIFO_ISF) {
38 		/* disable this int source */
39 		FPGA_OUT32(&fpga->hostctrl, HOSTCTRL_FIFOIE_GATE);
40 		rc = 0;
41 		got_fifoirq = 1; /* trigger backend */
42 	}
43 
44 	if (status & STATUS_HOST_ISF) {
45 		FPGA_OUT32(&fpga->hostctrl, HOSTCTRL_HCINT_GATE);
46 		rc = 0;
47 		got_hcirq = 1;
48 	}
49 
50 	return rc;
51 }
52 
do_waithci(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])53 int do_waithci(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
54 {
55 	pmc440_fpga_t *fpga = (pmc440_fpga_t *)FPGA_BA;
56 
57 	got_hcirq = 0;
58 
59 	FPGA_CLRBITS(&fpga->ctrla, CTRL_HOST_IE);
60 	FPGA_OUT32(&fpga->hostctrl, HOSTCTRL_HCINT_GATE);
61 
62 	irq_install_handler(IRQ0_FPGA,
63 			    (interrupt_handler_t *)fpga_interrupt,
64 			    fpga);
65 
66 	FPGA_SETBITS(&fpga->ctrla, CTRL_HOST_IE);
67 
68 	while (!got_hcirq) {
69 		/* Abort if ctrl-c was pressed */
70 		if (ctrlc()) {
71 			puts("\nAbort\n");
72 			break;
73 		}
74 	}
75 	if (got_hcirq)
76 		printf("Got interrupt!\n");
77 
78 	FPGA_CLRBITS(&fpga->ctrla, CTRL_HOST_IE);
79 	irq_free_handler(IRQ0_FPGA);
80 	return 0;
81 }
82 U_BOOT_CMD(
83 	waithci,	1,	1,	do_waithci,
84 	"Wait for host control interrupt",
85 	""
86 );
87 
dump_fifo(pmc440_fpga_t * fpga,int f,int * n)88 void dump_fifo(pmc440_fpga_t *fpga, int f, int *n)
89 {
90 	u32 ctrl;
91 
92 	while (!((ctrl = FPGA_IN32(&fpga->fifo[f].ctrl)) & FIFO_EMPTY)) {
93 		printf("%5d  %d    %3d  %08x",
94 		       (*n)++, f, ctrl & (FIFO_LEVEL_MASK | FIFO_FULL),
95 		       FPGA_IN32(&fpga->fifo[f].data));
96 		if (ctrl & FIFO_OVERFLOW) {
97 			printf(" OVERFLOW\n");
98 			FPGA_CLRBITS(&fpga->fifo[f].ctrl, FIFO_OVERFLOW);
99 		} else
100 			printf("\n");
101 	}
102 }
103 
do_fifo(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])104 int do_fifo(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
105 {
106 	pmc440_fpga_t *fpga = (pmc440_fpga_t *)FPGA_BA;
107 	int i;
108 	int n = 0;
109 	u32 ctrl, data, f;
110 	char str[] = "\\|/-";
111 	int abort = 0;
112 	int count = 0;
113 	int count2 = 0;
114 
115 	switch (argc) {
116 	case 1:
117 		/* print all fifos status information */
118 		printf("fifo level status\n");
119 		printf("______________________________\n");
120 		for (i=0; i<FIFO_COUNT; i++) {
121 			ctrl = FPGA_IN32(&fpga->fifo[i].ctrl);
122 			printf(" %d    %3d  %s%s%s %s\n",
123 			       i, ctrl & (FIFO_LEVEL_MASK | FIFO_FULL),
124 			       ctrl & FIFO_FULL ? "FULL     " : "",
125 			       ctrl & FIFO_EMPTY ? "EMPTY    " : "",
126 			       ctrl & (FIFO_FULL|FIFO_EMPTY) ? "" : "NOT EMPTY",
127 			       ctrl & FIFO_OVERFLOW ? "OVERFLOW" : "");
128 		}
129 		break;
130 
131 	case 2:
132 		/* completely read out fifo 'n' */
133 		if (!strcmp(argv[1],"read")) {
134 			printf("  #   fifo level data\n");
135 			printf("______________________________\n");
136 
137 			for (i=0; i<FIFO_COUNT; i++)
138 				dump_fifo(fpga, i, &n);
139 
140 		} else if (!strcmp(argv[1],"wait")) {
141 			got_fifoirq = 0;
142 
143 			irq_install_handler(IRQ0_FPGA,
144 					    (interrupt_handler_t *)fpga_interrupt,
145 					    fpga);
146 
147 			printf("  #   fifo level data\n");
148 			printf("______________________________\n");
149 
150 			/* enable all fifo interrupts */
151 			FPGA_OUT32(&fpga->hostctrl,
152 				   HOSTCTRL_FIFOIE_GATE | HOSTCTRL_FIFOIE_FLAG);
153 			for (i=0; i<FIFO_COUNT; i++) {
154 				/* enable interrupts from all fifos */
155 				FPGA_SETBITS(&fpga->fifo[i].ctrl, FIFO_IE);
156 			}
157 
158 			while (1) {
159 				/* wait loop */
160 				while (!got_fifoirq) {
161 					count++;
162 					if (!(count % 100)) {
163 						count2++;
164 						putc(0x08); /* backspace */
165 						putc(str[count2 % 4]);
166 					}
167 
168 					/* Abort if ctrl-c was pressed */
169 					if ((abort = ctrlc())) {
170 						puts("\nAbort\n");
171 						break;
172 					}
173 					udelay(1000);
174 				}
175 				if (abort)
176 					break;
177 
178 				/* simple fifo backend */
179 				if (got_fifoirq) {
180 					for (i=0; i<FIFO_COUNT; i++)
181 						dump_fifo(fpga, i, &n);
182 
183 					got_fifoirq = 0;
184 					/* unmask global fifo irq */
185 					FPGA_OUT32(&fpga->hostctrl,
186 						   HOSTCTRL_FIFOIE_GATE |
187 						   HOSTCTRL_FIFOIE_FLAG);
188 				}
189 			}
190 
191 			/* disable all fifo interrupts */
192 			FPGA_OUT32(&fpga->hostctrl, HOSTCTRL_FIFOIE_GATE);
193 			for (i=0; i<FIFO_COUNT; i++)
194 				FPGA_CLRBITS(&fpga->fifo[i].ctrl, FIFO_IE);
195 
196 			irq_free_handler(IRQ0_FPGA);
197 
198 		} else {
199 			printf("Usage:\nfifo %s\n", cmdtp->help);
200 			return 1;
201 		}
202 		break;
203 
204 	case 4:
205 	case 5:
206 		if (!strcmp(argv[1],"write")) {
207 			/* get fifo number or fifo address */
208 			f = simple_strtoul(argv[2], NULL, 16);
209 
210 			/* data paramter */
211 			data = simple_strtoul(argv[3], NULL, 16);
212 
213 			/* get optional count parameter */
214 			n = 1;
215 			if (argc >= 5)
216 				n = (int)simple_strtoul(argv[4], NULL, 10);
217 
218 			if (f < FIFO_COUNT) {
219 				printf("writing %d x %08x to fifo %d\n",
220 				       n, data, f);
221 				for (i=0; i<n; i++)
222 					FPGA_OUT32(&fpga->fifo[f].data, data);
223 			} else {
224 				printf("writing %d x %08x to fifo port at "
225 				       "address %08x\n",
226 				       n, data, f);
227 				for (i=0; i<n; i++)
228 					out_be32((void *)f, data);
229 			}
230 		} else {
231 			printf("Usage:\nfifo %s\n", cmdtp->help);
232 			return 1;
233 		}
234 		break;
235 
236 	default:
237 		printf("Usage:\nfifo %s\n", cmdtp->help);
238 		return 1;
239 	}
240 	return 0;
241 }
242 U_BOOT_CMD(
243 	fifo,	5,	1,	do_fifo,
244 	"Fifo module operations",
245 	"wait\nfifo read\n"
246 	"fifo write fifo(0..3) data [cnt=1]\n"
247 	"fifo write address(>=4) data [cnt=1]\n"
248 	"  - without arguments: print all fifo's status\n"
249 	"  - with 'wait' argument: interrupt driven read from all fifos\n"
250 	"  - with 'read' argument: read current contents from all fifos\n"
251 	"  - with 'write' argument: write 'data' 'cnt' times to "
252 	"'fifo' or 'address'"
253 );
254 
do_setup_bootstrap_eeprom(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])255 int do_setup_bootstrap_eeprom(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
256 {
257 	ulong sdsdp[5];
258 	ulong delay;
259 	int count=16;
260 
261 	if (argc < 2) {
262 		printf("Usage:\nsbe %s\n", cmdtp->help);
263 		return -1;
264 	}
265 
266 	if (argc > 1) {
267 		if (!strcmp(argv[1], "400")) {
268 			/* PLB=133MHz, PLB/PCI=3 */
269 			printf("Bootstrapping for 400MHz\n");
270 			sdsdp[0]=0x8678624e;
271 			sdsdp[1]=0x095fa030;
272 			sdsdp[2]=0x40082350;
273 			sdsdp[3]=0x0d050000;
274 		} else if (!strcmp(argv[1], "533")) {
275 			/* PLB=133MHz, PLB/PCI=3 */
276 			printf("Bootstrapping for 533MHz\n");
277 			sdsdp[0]=0x87788252;
278 			sdsdp[1]=0x095fa030;
279 			sdsdp[2]=0x40082350;
280 			sdsdp[3]=0x0d050000;
281 		} else if (!strcmp(argv[1], "667")) {
282 			/* PLB=133MHz, PLB/PCI=3 */
283 			printf("Bootstrapping for 667MHz\n");
284 			sdsdp[0]=0x8778a256;
285 			sdsdp[1]=0x095fa030;
286 			sdsdp[2]=0x40082350;
287 			sdsdp[3]=0x0d050000;
288 		} else {
289 			printf("Usage:\nsbe %s\n", cmdtp->help);
290 			return -1;
291 		}
292 	}
293 
294 	if (argc > 2) {
295 		sdsdp[4] = 0;
296 		if (argv[2][0]=='1')
297 			sdsdp[4]=0x19750100;
298 		else if (argv[2][0]=='0')
299 			sdsdp[4]=0x19750000;
300 		if (sdsdp[4])
301 			count += 4;
302 	}
303 
304 	if (argc > 3) {
305 		delay = simple_strtoul(argv[3], NULL, 10);
306 		if (delay > 20)
307 			delay = 20;
308 		sdsdp[4] |= delay;
309 	}
310 
311 	printf("Writing boot EEPROM ...\n");
312 	if (bootstrap_eeprom_write(CONFIG_SYS_I2C_BOOT_EEPROM_ADDR,
313 				   0, (uchar*)sdsdp, count) != 0)
314 		printf("bootstrap_eeprom_write failed\n");
315 	else
316 		printf("done (dump via 'i2c md 52 0.1 14')\n");
317 
318 	return 0;
319 }
320 U_BOOT_CMD(
321 	sbe, 4, 0, do_setup_bootstrap_eeprom,
322 	"setup bootstrap eeprom",
323 	"<cpufreq:400|533|667> [<console-uart:0|1> [<bringup delay (0..20s)>]]"
324 );
325 
326 #if defined(CONFIG_PRAM)
327 #include <environment.h>
328 #include <search.h>
329 #include <errno.h>
330 
do_painit(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])331 int do_painit(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
332 {
333 	u32 pram, nextbase, base;
334 	char *v;
335 	u32 param;
336 	ulong *lptr;
337 
338 	env_t *envp;
339 	char *res;
340 	int len;
341 
342 	v = getenv("pram");
343 	if (v)
344 		pram = simple_strtoul(v, NULL, 10);
345 	else {
346 		printf("Error: pram undefined. Please define pram in KiB\n");
347 		return 1;
348 	}
349 
350 	base = (u32)gd->ram_size;
351 #if defined(CONFIG_LOGBUFFER)
352 	base -= LOGBUFF_LEN + LOGBUFF_OVERHEAD;
353 #endif
354 	/*
355 	 * gd->ram_size == physical ram size - CONFIG_SYS_MEM_TOP_HIDE
356 	 */
357 	param = base - (pram << 10);
358 	printf("PARAM: @%08x\n", param);
359 	debug("memsize=0x%08x, base=0x%08x\n", (u32)gd->ram_size, base);
360 
361 	/* clear entire PA ram */
362 	memset((void*)param, 0, (pram << 10));
363 
364 	/* reserve 4k for pointer field */
365 	nextbase = base - 4096;
366 	lptr = (ulong*)(base);
367 
368 	/*
369 	 * *(--lptr) = item_size;
370 	 * *(--lptr) = base - item_base = distance from field top;
371 	 */
372 
373 	/* env is first (4k aligned) */
374 	nextbase -= ((CONFIG_ENV_SIZE + 4096 - 1) & ~(4096 - 1));
375 	envp = (env_t *)nextbase;
376 	res = (char *)envp->data;
377 	len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL);
378 	if (len < 0) {
379 		error("Cannot export environment: errno = %d\n", errno);
380 		return 1;
381 	}
382 	envp->crc = crc32(0, envp->data, ENV_SIZE);
383 
384 	*(--lptr) = CONFIG_ENV_SIZE;     /* size */
385 	*(--lptr) = base - nextbase;  /* offset | type=0 */
386 
387 	/* free section */
388 	*(--lptr) = nextbase - param; /* size */
389 	*(--lptr) = (base - param) | 126; /* offset | type=126 */
390 
391 	/* terminate pointer field */
392 	*(--lptr) = crc32(0, (void*)(base - 0x10), 0x10);
393 	*(--lptr) = 0;                /* offset=0 -> terminator */
394 	return 0;
395 }
396 U_BOOT_CMD(
397 	painit,	1,	1,	do_painit,
398 	"prepare PciAccess system",
399 	""
400 );
401 #endif /* CONFIG_PRAM */
402 
do_selfreset(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])403 int do_selfreset(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
404 {
405 	in_be32((void*)CONFIG_SYS_RESET_BASE);
406 	return 0;
407 }
408 U_BOOT_CMD(
409 	selfreset,	1,	1,	do_selfreset,
410 	"assert self-reset# signal",
411 	""
412 );
413 
do_resetout(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])414 int do_resetout(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
415 {
416 	pmc440_fpga_t *fpga = (pmc440_fpga_t *)FPGA_BA;
417 
418 	/* requiers bootet FPGA and PLD_IOEN_N active */
419 	if (in_be32((void*)GPIO1_OR) & GPIO1_IOEN_N) {
420 		printf("Error: resetout requires a bootet FPGA\n");
421 		return -1;
422 	}
423 
424 	if (argc > 1) {
425 		if (argv[1][0] == '0') {
426 			/* assert */
427 			printf("PMC-RESETOUT# asserted\n");
428 			FPGA_OUT32(&fpga->hostctrl,
429 				   HOSTCTRL_PMCRSTOUT_GATE);
430 		} else {
431 			/* deassert */
432 			printf("PMC-RESETOUT# deasserted\n");
433 			FPGA_OUT32(&fpga->hostctrl,
434 				   HOSTCTRL_PMCRSTOUT_GATE |
435 				   HOSTCTRL_PMCRSTOUT_FLAG);
436 		}
437 	} else {
438 		printf("PMC-RESETOUT# is %s\n",
439 		       FPGA_IN32(&fpga->hostctrl) & HOSTCTRL_PMCRSTOUT_FLAG ?
440 		       "inactive" : "active");
441 	}
442 
443 	return 0;
444 }
445 U_BOOT_CMD(
446 	resetout,	2,	1,	do_resetout,
447 	"assert PMC-RESETOUT# signal",
448 	""
449 );
450 
do_inta(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])451 int do_inta(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
452 {
453 	if (is_monarch()) {
454 		printf("This command is only supported in non-monarch mode\n");
455 		return -1;
456 	}
457 
458 	if (argc > 1) {
459 		if (argv[1][0] == '0') {
460 			/* assert */
461 			printf("inta# asserted\n");
462 			out_be32((void*)GPIO1_TCR,
463 				 in_be32((void*)GPIO1_TCR) | GPIO1_INTA_FAKE);
464 		} else {
465 			/* deassert */
466 			printf("inta# deasserted\n");
467 			out_be32((void*)GPIO1_TCR,
468 				 in_be32((void*)GPIO1_TCR) & ~GPIO1_INTA_FAKE);
469 		}
470 	} else {
471 		printf("inta# is %s\n",
472 		       in_be32((void*)GPIO1_TCR) & GPIO1_INTA_FAKE ?
473 		       "active" : "inactive");
474 	}
475 	return 0;
476 }
477 U_BOOT_CMD(
478 	inta,	2,	1,	do_inta,
479 	"Assert/Deassert or query INTA# state in non-monarch mode",
480 	""
481 );
482 
483 /* test-only */
do_pmm(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])484 int do_pmm(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
485 {
486 	ulong pciaddr;
487 
488 	if (argc > 1) {
489 		pciaddr = simple_strtoul(argv[1], NULL, 16);
490 
491 		pciaddr &= 0xf0000000;
492 
493 		/* map PCI address at 0xc0000000 in PLB space */
494 
495 		/* PMM1 Mask/Attribute - disabled b4 setting */
496 		out32r(PCIL0_PMM1MA, 0x00000000);
497 		/* PMM1 Local Address */
498 		out32r(PCIL0_PMM1LA, 0xc0000000);
499 		/* PMM1 PCI Low Address */
500 		out32r(PCIL0_PMM1PCILA, pciaddr);
501 		/* PMM1 PCI High Address */
502 		out32r(PCIL0_PMM1PCIHA, 0x00000000);
503 		/* 256MB + No prefetching, and enable region */
504 		out32r(PCIL0_PMM1MA, 0xf0000001);
505 	} else {
506 		printf("Usage:\npmm %s\n", cmdtp->help);
507 	}
508 	return 0;
509 }
510 U_BOOT_CMD(
511 	pmm,	2,	1,	do_pmm,
512 	"Setup pmm[1] registers",
513 	"<pciaddr> (pciaddr will be aligned to 256MB)"
514 );
515 
516 #if defined(CONFIG_SYS_EEPROM_WREN)
do_eep_wren(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])517 int do_eep_wren(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
518 {
519 	int query = argc == 1;
520 	int state = 0;
521 
522 	if (query) {
523 		/* Query write access state. */
524 		state = eeprom_write_enable(CONFIG_SYS_I2C_EEPROM_ADDR, -1);
525 		if (state < 0) {
526 			puts("Query of write access state failed.\n");
527 		} else {
528 			printf("Write access for device 0x%0x is %sabled.\n",
529 			       CONFIG_SYS_I2C_EEPROM_ADDR, state ? "en" : "dis");
530 			state = 0;
531 		}
532 	} else {
533 		if ('0' == argv[1][0]) {
534 			/* Disable write access. */
535 			state = eeprom_write_enable(CONFIG_SYS_I2C_EEPROM_ADDR, 0);
536 		} else {
537 			/* Enable write access. */
538 			state = eeprom_write_enable(CONFIG_SYS_I2C_EEPROM_ADDR, 1);
539 		}
540 		if (state < 0) {
541 			puts("Setup of write access state failed.\n");
542 		}
543 	}
544 
545 	return state;
546 }
547 U_BOOT_CMD(eepwren, 2, 0, do_eep_wren,
548 	"Enable / disable / query EEPROM write access",
549 	""
550 );
551 #endif /* #if defined(CONFIG_SYS_EEPROM_WREN) */
552 
553 #endif /* CONFIG_CMD_BSP */
554