1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * (C) Copyright 2009 Reinhard Arlt, reinhard.arlt@esd-electronics.com
4  *
5  * base on universe.h by
6  *
7  * (C) Copyright 2003 Stefan Roese, stefan.roese@esd-electronics.com
8  */
9 
10 #include <common.h>
11 #include <command.h>
12 #include <log.h>
13 #include <malloc.h>
14 #include <asm/io.h>
15 #include <pci.h>
16 
17 #include <tsi148.h>
18 
19 #define LPCI_VENDOR PCI_VENDOR_ID_TUNDRA
20 #define LPCI_DEVICE PCI_DEVICE_ID_TUNDRA_TSI148
21 
22 typedef struct _TSI148_DEV TSI148_DEV;
23 
24 struct _TSI148_DEV {
25 	int           bus;
26 	pci_dev_t     busdevfn;
27 	TSI148       *uregs;
28 	unsigned int  pci_bs;
29 };
30 
31 static TSI148_DEV *dev;
32 
33 /*
34  * Most of the TSI148 register are BIGENDIAN
35  * This is the reason for the __raw_writel(htonl(x), x) usage!
36  */
37 
tsi148_init(void)38 int tsi148_init(void)
39 {
40 	int j, result;
41 	pci_dev_t busdevfn;
42 	unsigned int val;
43 
44 	busdevfn = pci_find_device(LPCI_VENDOR, LPCI_DEVICE, 0);
45 	if (busdevfn == -1) {
46 		puts("Tsi148: No Tundra Tsi148 found!\n");
47 		return -1;
48 	}
49 
50 	/* Lets turn Latency off */
51 	pci_write_config_dword(busdevfn, 0x0c, 0);
52 
53 	dev = malloc(sizeof(*dev));
54 	if (NULL == dev) {
55 		puts("Tsi148: No memory!\n");
56 		return -1;
57 	}
58 
59 	memset(dev, 0, sizeof(*dev));
60 	dev->busdevfn = busdevfn;
61 
62 	pci_read_config_dword(busdevfn, PCI_BASE_ADDRESS_0, &val);
63 	val &= ~0xf;
64 	dev->uregs = (TSI148 *)val;
65 
66 	debug("Tsi148: Base    : %p\n", dev->uregs);
67 
68 	/* check mapping */
69 	debug("Tsi148: Read via mapping, PCI_ID = %08X\n",
70 	      readl(&dev->uregs->pci_id));
71 	if (((LPCI_DEVICE << 16) | LPCI_VENDOR) != readl(&dev->uregs->pci_id)) {
72 		printf("Tsi148: Cannot read PCI-ID via Mapping: %08x\n",
73 		       readl(&dev->uregs->pci_id));
74 		result = -1;
75 		goto break_30;
76 	}
77 
78 	debug("Tsi148: PCI_BS = %08X\n", readl(&dev->uregs->pci_mbarl));
79 
80 	dev->pci_bs = readl(&dev->uregs->pci_mbarl);
81 
82 	/* turn off windows */
83 	for (j = 0; j < 8; j++) {
84 		__raw_writel(htonl(0x00000000), &dev->uregs->outbound[j].otat);
85 		__raw_writel(htonl(0x00000000), &dev->uregs->inbound[j].itat);
86 	}
87 
88 	/* Tsi148 VME timeout etc */
89 	__raw_writel(htonl(0x00000084), &dev->uregs->vctrl);
90 
91 #ifdef DEBUG
92 	if ((__raw_readl(&dev->uregs->vstat) & 0x00000100) != 0)
93 		printf("Tsi148: System Controller!\n");
94 	else
95 		printf("Tsi148: Not System Controller!\n");
96 #endif
97 
98 	/*
99 	 * Lets turn off interrupts
100 	 */
101 	/* Disable interrupts in Tsi148 first */
102 	__raw_writel(htonl(0x00000000), &dev->uregs->inten);
103 	/* Disable interrupt out */
104 	__raw_writel(htonl(0x00000000), &dev->uregs->inteo);
105 	eieio();
106 	/* Reset all IRQ's */
107 	__raw_writel(htonl(0x03ff3f00), &dev->uregs->intc);
108 	/* Map all ints to 0 */
109 	__raw_writel(htonl(0x00000000), &dev->uregs->intm1);
110 	__raw_writel(htonl(0x00000000), &dev->uregs->intm2);
111 	eieio();
112 
113 	val = __raw_readl(&dev->uregs->vstat);
114 	val &= ~(0x00004000);
115 	__raw_writel(val, &dev->uregs->vstat);
116 	eieio();
117 
118 	debug("Tsi148: register struct size %08x\n", sizeof(TSI148));
119 
120 	return 0;
121 
122  break_30:
123 	free(dev);
124 	dev = NULL;
125 
126 	return result;
127 }
128 
129 /*
130  * Create pci slave window (access: pci -> vme)
131  */
tsi148_pci_slave_window(unsigned int pciAddr,unsigned int vmeAddr,int size,int vam,int vdw)132 int tsi148_pci_slave_window(unsigned int pciAddr, unsigned int vmeAddr,
133 			    int size, int vam, int vdw)
134 {
135 	int result, i;
136 	unsigned int ctl = 0;
137 
138 	if (NULL == dev) {
139 		result = -1;
140 		goto exit_10;
141 	}
142 
143 	for (i = 0; i < 8; i++) {
144 		if (0x00000000 == readl(&dev->uregs->outbound[i].otat))
145 			break;
146 	}
147 
148 	if (i > 7) {
149 		printf("Tsi148: No Image available\n");
150 		result = -1;
151 		goto exit_10;
152 	}
153 
154 	debug("Tsi148: Using image %d\n", i);
155 
156 	printf("Tsi148: Pci addr %08x\n", pciAddr);
157 
158 	__raw_writel(htonl(pciAddr), &dev->uregs->outbound[i].otsal);
159 	__raw_writel(0x00000000, &dev->uregs->outbound[i].otsau);
160 	__raw_writel(htonl(pciAddr + size), &dev->uregs->outbound[i].oteal);
161 	__raw_writel(0x00000000, &dev->uregs->outbound[i].oteau);
162 	__raw_writel(htonl(vmeAddr - pciAddr), &dev->uregs->outbound[i].otofl);
163 	__raw_writel(0x00000000, &dev->uregs->outbound[i].otofu);
164 
165 	switch (vam & VME_AM_Axx) {
166 	case VME_AM_A16:
167 		ctl = 0x00000000;
168 		break;
169 	case VME_AM_A24:
170 		ctl = 0x00000001;
171 		break;
172 	case VME_AM_A32:
173 		ctl = 0x00000002;
174 		break;
175 	}
176 
177 	switch (vam & VME_AM_Mxx) {
178 	case VME_AM_DATA:
179 		ctl |= 0x00000000;
180 		break;
181 	case VME_AM_PROG:
182 		ctl |= 0x00000010;
183 		break;
184 	}
185 
186 	if (vam & VME_AM_SUP)
187 		ctl |= 0x00000020;
188 
189 	switch (vdw & VME_FLAG_Dxx) {
190 	case VME_FLAG_D16:
191 		ctl |= 0x00000000;
192 		break;
193 	case VME_FLAG_D32:
194 		ctl |= 0x00000040;
195 		break;
196 	}
197 
198 	ctl |= 0x80040000;	/* enable, no prefetch */
199 
200 	__raw_writel(htonl(ctl), &dev->uregs->outbound[i].otat);
201 
202 	debug("Tsi148: window-addr                =%p\n",
203 	      &dev->uregs->outbound[i].otsau);
204 	debug("Tsi148: pci slave window[%d] attr  =%08x\n",
205 	      i, ntohl(__raw_readl(&dev->uregs->outbound[i].otat)));
206 	debug("Tsi148: pci slave window[%d] start =%08x\n",
207 	      i, ntohl(__raw_readl(&dev->uregs->outbound[i].otsal)));
208 	debug("Tsi148: pci slave window[%d] end   =%08x\n",
209 	      i, ntohl(__raw_readl(&dev->uregs->outbound[i].oteal)));
210 	debug("Tsi148: pci slave window[%d] offset=%08x\n",
211 	      i, ntohl(__raw_readl(&dev->uregs->outbound[i].otofl)));
212 
213 	return 0;
214 
215  exit_10:
216 	return -result;
217 }
218 
tsi148_eval_vam(int vam)219 unsigned int tsi148_eval_vam(int vam)
220 {
221 	unsigned int ctl = 0;
222 
223 	switch (vam & VME_AM_Axx) {
224 	case VME_AM_A16:
225 		ctl = 0x00000000;
226 		break;
227 	case VME_AM_A24:
228 		ctl = 0x00000010;
229 		break;
230 	case VME_AM_A32:
231 		ctl = 0x00000020;
232 		break;
233 	}
234 	switch (vam & VME_AM_Mxx) {
235 	case VME_AM_DATA:
236 		ctl |= 0x00000001;
237 		break;
238 	case VME_AM_PROG:
239 		ctl |= 0x00000002;
240 		break;
241 	case (VME_AM_PROG | VME_AM_DATA):
242 		ctl |= 0x00000003;
243 		break;
244 	}
245 
246 	if (vam & VME_AM_SUP)
247 		ctl |= 0x00000008;
248 	if (vam & VME_AM_USR)
249 		ctl |= 0x00000004;
250 
251 	return ctl;
252 }
253 
254 /*
255  * Create vme slave window (access: vme -> pci)
256  */
tsi148_vme_slave_window(unsigned int vmeAddr,unsigned int pciAddr,int size,int vam)257 int tsi148_vme_slave_window(unsigned int vmeAddr, unsigned int pciAddr,
258 			    int size, int vam)
259 {
260 	int result, i;
261 	unsigned int ctl = 0;
262 
263 	if (NULL == dev) {
264 		result = -1;
265 		goto exit_10;
266 	}
267 
268 	for (i = 0; i < 8; i++) {
269 		if (0x00000000 == readl(&dev->uregs->inbound[i].itat))
270 			break;
271 	}
272 
273 	if (i > 7) {
274 		printf("Tsi148: No Image available\n");
275 		result = -1;
276 		goto exit_10;
277 	}
278 
279 	debug("Tsi148: Using image %d\n", i);
280 
281 	__raw_writel(htonl(vmeAddr), &dev->uregs->inbound[i].itsal);
282 	__raw_writel(0x00000000, &dev->uregs->inbound[i].itsau);
283 	__raw_writel(htonl(vmeAddr + size), &dev->uregs->inbound[i].iteal);
284 	__raw_writel(0x00000000, &dev->uregs->inbound[i].iteau);
285 	__raw_writel(htonl(pciAddr - vmeAddr), &dev->uregs->inbound[i].itofl);
286 	if (vmeAddr > pciAddr)
287 		__raw_writel(0xffffffff, &dev->uregs->inbound[i].itofu);
288 	else
289 		__raw_writel(0x00000000, &dev->uregs->inbound[i].itofu);
290 
291 	ctl = tsi148_eval_vam(vam);
292 	ctl |= 0x80000000;	/* enable */
293 	__raw_writel(htonl(ctl), &dev->uregs->inbound[i].itat);
294 
295 	debug("Tsi148: window-addr                =%p\n",
296 	      &dev->uregs->inbound[i].itsau);
297 	debug("Tsi148: vme slave window[%d] attr  =%08x\n",
298 	      i, ntohl(__raw_readl(&dev->uregs->inbound[i].itat)));
299 	debug("Tsi148: vme slave window[%d] start =%08x\n",
300 	      i, ntohl(__raw_readl(&dev->uregs->inbound[i].itsal)));
301 	debug("Tsi148: vme slave window[%d] end   =%08x\n",
302 	      i, ntohl(__raw_readl(&dev->uregs->inbound[i].iteal)));
303 	debug("Tsi148: vme slave window[%d] offset=%08x\n",
304 	      i, ntohl(__raw_readl(&dev->uregs->inbound[i].itofl)));
305 
306 	return 0;
307 
308  exit_10:
309 	return -result;
310 }
311 
312 /*
313  * Create vme slave window (access: vme -> gcsr)
314  */
tsi148_vme_gcsr_window(unsigned int vmeAddr,int vam)315 int tsi148_vme_gcsr_window(unsigned int vmeAddr, int vam)
316 {
317 	int result;
318 	unsigned int ctl;
319 
320 	result = 0;
321 
322 	if (NULL == dev) {
323 		result = 1;
324 	} else {
325 		__raw_writel(htonl(vmeAddr), &dev->uregs->gbal);
326 		__raw_writel(0x00000000, &dev->uregs->gbau);
327 
328 		ctl = tsi148_eval_vam(vam);
329 		ctl |= 0x00000080;	/* enable */
330 		__raw_writel(htonl(ctl), &dev->uregs->gcsrat);
331 	}
332 
333 	return result;
334 }
335 
336 /*
337  * Create vme slave window (access: vme -> crcsr)
338  */
tsi148_vme_crcsr_window(unsigned int vmeAddr)339 int tsi148_vme_crcsr_window(unsigned int vmeAddr)
340 {
341 	int result;
342 	unsigned int ctl;
343 
344 	result = 0;
345 
346 	if (NULL == dev) {
347 		result = 1;
348 	} else {
349 		__raw_writel(htonl(vmeAddr), &dev->uregs->crol);
350 		__raw_writel(0x00000000, &dev->uregs->crou);
351 
352 		ctl = 0x00000080;	/* enable */
353 		__raw_writel(htonl(ctl), &dev->uregs->crat);
354 	}
355 
356 	return result;
357 }
358 
359 /*
360  * Create vme slave window (access: vme -> crg)
361  */
tsi148_vme_crg_window(unsigned int vmeAddr,int vam)362 int tsi148_vme_crg_window(unsigned int vmeAddr, int vam)
363 {
364 	int result;
365 	unsigned int ctl;
366 
367 	result = 0;
368 
369 	if (NULL == dev) {
370 		result = 1;
371 	} else {
372 		__raw_writel(htonl(vmeAddr), &dev->uregs->cbal);
373 		__raw_writel(0x00000000, &dev->uregs->cbau);
374 
375 		ctl = tsi148_eval_vam(vam);
376 		ctl |= 0x00000080;	/* enable */
377 		__raw_writel(htonl(ctl), &dev->uregs->crgat);
378 	}
379 
380 	return result;
381 }
382 
383 /*
384  * Tundra Tsi148 configuration
385  */
do_tsi148(struct cmd_tbl * cmdtp,int flag,int argc,char * const argv[])386 int do_tsi148(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
387 {
388 	ulong addr1 = 0, addr2 = 0, size = 0, vam = 0, vdw = 0;
389 	char cmd = 'x';
390 
391 	/* get parameter */
392 	if (argc > 1)
393 		cmd = argv[1][0];
394 	if (argc > 2)
395 		addr1 = simple_strtoul(argv[2], NULL, 16);
396 	if (argc > 3)
397 		addr2 = simple_strtoul(argv[3], NULL, 16);
398 	if (argc > 4)
399 		size = simple_strtoul(argv[4], NULL, 16);
400 	if (argc > 5)
401 		vam = simple_strtoul(argv[5], NULL, 16);
402 	if (argc > 6)
403 		vdw = simple_strtoul(argv[6], NULL, 16);
404 
405 	switch (cmd) {
406 	case 'c':
407 		if (strcmp(argv[1], "crg") == 0) {
408 			vam = addr2;
409 			printf("Tsi148: Configuring VME CRG Window "
410 			       "(VME->CRG):\n");
411 			printf("  vme=%08lx vam=%02lx\n", addr1, vam);
412 			tsi148_vme_crg_window(addr1, vam);
413 		} else {
414 			printf("Tsi148: Configuring VME CR/CSR Window "
415 			       "(VME->CR/CSR):\n");
416 			printf("  pci=%08lx\n", addr1);
417 			tsi148_vme_crcsr_window(addr1);
418 		}
419 		break;
420 	case 'i':		/* init */
421 		tsi148_init();
422 		break;
423 	case 'g':
424 		vam = addr2;
425 		printf("Tsi148: Configuring VME GCSR Window (VME->GCSR):\n");
426 		printf("  vme=%08lx vam=%02lx\n", addr1, vam);
427 		tsi148_vme_gcsr_window(addr1, vam);
428 		break;
429 	case 'v':		/* vme */
430 		printf("Tsi148: Configuring VME Slave Window (VME->PCI):\n");
431 		printf("  vme=%08lx pci=%08lx size=%08lx vam=%02lx\n",
432 		       addr1, addr2, size, vam);
433 		tsi148_vme_slave_window(addr1, addr2, size, vam);
434 		break;
435 	case 'p':		/* pci */
436 		printf("Tsi148: Configuring PCI Slave Window (PCI->VME):\n");
437 		printf("  pci=%08lx vme=%08lx size=%08lx vam=%02lx vdw=%02lx\n",
438 		       addr1, addr2, size, vam, vdw);
439 		tsi148_pci_slave_window(addr1, addr2, size, vam, vdw);
440 		break;
441 	default:
442 		printf("Tsi148: Command %s not supported!\n", argv[1]);
443 	}
444 
445 	return 0;
446 }
447 
448 U_BOOT_CMD(
449 	tsi148,	7,	1,	do_tsi148,
450 	"initialize and configure Turndra Tsi148\n",
451 	"init\n"
452 	"    - initialize tsi148\n"
453 	"tsi148 vme   [vme_addr] [pci_addr] [size] [vam]\n"
454 	"    - create vme slave window (access: vme->pci)\n"
455 	"tsi148 pci   [pci_addr] [vme_addr] [size] [vam] [vdw]\n"
456 	"    - create pci slave window (access: pci->vme)\n"
457 	"tsi148 crg   [vme_addr] [vam]\n"
458 	"    - create vme slave window: (access vme->CRG\n"
459 	"tsi148 crcsr [pci_addr]\n"
460 	"    - create vme slave window: (access vme->CR/CSR\n"
461 	"tsi148 gcsr  [vme_addr] [vam]\n"
462 	"    - create vme slave window: (access vme->GCSR\n"
463 	"    [vam] = VMEbus Address-Modifier:  01 -> A16 Address Space\n"
464 	"                                      02 -> A24 Address Space\n"
465 	"                                      03 -> A32 Address Space\n"
466 	"                                      04 -> Usr        AM Code\n"
467 	"                                      08 -> Supervisor AM Code\n"
468 	"                                      10 -> Data AM Code\n"
469 	"                                      20 -> Program AM Code\n"
470 	"    [vdw] = VMEbus Maximum Datawidth: 02 -> D16 Data Width\n"
471 	"                                      03 -> D32 Data Width\n"
472 );
473