blob: 6dc9dab36899c10035af72ea4059043bfa0f376a [file] [log] [blame]
Reinhard Arltff196c12009-06-10 19:09:40 +02001/*
2 * (C) Copyright 2009 Reinhard Arlt, reinhard.arlt@esd-electronics.com
3 *
4 * base on universe.h by
5 *
6 * (C) Copyright 2003 Stefan Roese, stefan.roese@esd-electronics.com
7 *
8 * See file CREDITS for list of people who contributed to this
9 * project.
10 *
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License as
13 * published by the Free Software Foundation; either version 2 of
14 * the License, or (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
24 * MA 02111-1307 USA
25 */
26
Reinhard Arltff196c12009-06-10 19:09:40 +020027#include <common.h>
28#include <command.h>
29#include <malloc.h>
30#include <asm/io.h>
31#include <pci.h>
32
33#include <tsi148.h>
34
35#define PCI_VENDOR PCI_VENDOR_ID_TUNDRA
36#define PCI_DEVICE PCI_DEVICE_ID_TUNDRA_TSI148
37
38typedef struct _TSI148_DEV TSI148_DEV;
39
40struct _TSI148_DEV {
Peter Tyserca2cac22009-07-20 21:51:38 -050041 int bus;
42 pci_dev_t busdevfn;
43 TSI148 *uregs;
44 unsigned int pci_bs;
Reinhard Arltff196c12009-06-10 19:09:40 +020045};
46
47static TSI148_DEV *dev;
48
49/*
50 * Most of the TSI148 register are BIGENDIAN
51 * This is the reason for the __raw_writel(htonl(x), x) usage!
52 */
53
54int tsi148_init(void)
55{
56 int j, result, lastError = 0;
57 pci_dev_t busdevfn;
58 unsigned int val;
59
60 busdevfn = pci_find_device(PCI_VENDOR, PCI_DEVICE, 0);
61 if (busdevfn == -1) {
62 puts("Tsi148: No Tundra Tsi148 found!\n");
63 return -1;
64 }
65
66 /* Lets turn Latency off */
67 pci_write_config_dword(busdevfn, 0x0c, 0);
68
69 dev = malloc(sizeof(*dev));
70 if (NULL == dev) {
71 puts("Tsi148: No memory!\n");
72 result = -1;
73 goto break_20;
74 }
75
76 memset(dev, 0, sizeof(*dev));
77 dev->busdevfn = busdevfn;
78
79 pci_read_config_dword(busdevfn, PCI_BASE_ADDRESS_0, &val);
80 val &= ~0xf;
81 dev->uregs = (TSI148 *)val;
82
83 debug("Tsi148: Base : %p\n", dev->uregs);
84
Peter Tyserca2cac22009-07-20 21:51:38 -050085 /* check mapping */
86 debug("Tsi148: Read via mapping, PCI_ID = %08X\n",
87 readl(&dev->uregs->pci_id));
88 if (((PCI_DEVICE << 16) | PCI_VENDOR) != readl(&dev->uregs->pci_id)) {
Reinhard Arltff196c12009-06-10 19:09:40 +020089 printf("Tsi148: Cannot read PCI-ID via Mapping: %08x\n",
Peter Tyserca2cac22009-07-20 21:51:38 -050090 readl(&dev->uregs->pci_id));
Reinhard Arltff196c12009-06-10 19:09:40 +020091 result = -1;
92 goto break_30;
93 }
94
95 debug("Tsi148: PCI_BS = %08X\n", readl(&dev->uregs->pci_mbarl));
96
97 dev->pci_bs = readl(&dev->uregs->pci_mbarl);
98
99 /* turn off windows */
100 for (j = 0; j < 8; j++) {
101 __raw_writel(htonl(0x00000000), &dev->uregs->outbound[j].otat);
102 __raw_writel(htonl(0x00000000), &dev->uregs->inbound[j].itat);
103 }
104
105 /* Tsi148 VME timeout etc */
106 __raw_writel(htonl(0x00000084), &dev->uregs->vctrl);
107
Peter Tyserca2cac22009-07-20 21:51:38 -0500108#ifdef DEBUG
Reinhard Arltff196c12009-06-10 19:09:40 +0200109 if ((__raw_readl(&dev->uregs->vstat) & 0x00000100) != 0)
Peter Tyserca2cac22009-07-20 21:51:38 -0500110 printf("Tsi148: System Controller!\n");
Reinhard Arltff196c12009-06-10 19:09:40 +0200111 else
Peter Tyserca2cac22009-07-20 21:51:38 -0500112 printf("Tsi148: Not System Controller!\n");
113#endif
Reinhard Arltff196c12009-06-10 19:09:40 +0200114
115 /*
116 * Lets turn off interrupts
117 */
118 /* Disable interrupts in Tsi148 first */
119 __raw_writel(htonl(0x00000000), &dev->uregs->inten);
120 /* Disable interrupt out */
121 __raw_writel(htonl(0x00000000), &dev->uregs->inteo);
122 eieio();
123 /* Reset all IRQ's */
124 __raw_writel(htonl(0x03ff3f00), &dev->uregs->intc);
125 /* Map all ints to 0 */
126 __raw_writel(htonl(0x00000000), &dev->uregs->intm1);
127 __raw_writel(htonl(0x00000000), &dev->uregs->intm2);
128 eieio();
129
Peter Tyserca2cac22009-07-20 21:51:38 -0500130 val = __raw_readl(&dev->uregs->vstat);
Reinhard Arltff196c12009-06-10 19:09:40 +0200131 val &= ~(0x00004000);
132 __raw_writel(val, &dev->uregs->vstat);
133 eieio();
134
135 debug("Tsi148: register struct size %08x\n", sizeof(TSI148));
136
137 return 0;
138
139 break_30:
140 free(dev);
141 dev = NULL;
142 break_20:
143 lastError = result;
144
145 return result;
146}
147
148/*
149 * Create pci slave window (access: pci -> vme)
150 */
Peter Tyserca2cac22009-07-20 21:51:38 -0500151int tsi148_pci_slave_window(unsigned int pciAddr, unsigned int vmeAddr,
152 int size, int vam, int vdw)
Reinhard Arltff196c12009-06-10 19:09:40 +0200153{
154 int result, i;
155 unsigned int ctl = 0;
156
157 if (NULL == dev) {
158 result = -1;
159 goto exit_10;
160 }
161
162 for (i = 0; i < 8; i++) {
163 if (0x00000000 == readl(&dev->uregs->outbound[i].otat))
164 break;
165 }
166
167 if (i > 7) {
168 printf("Tsi148: No Image available\n");
169 result = -1;
170 goto exit_10;
171 }
172
173 debug("Tsi148: Using image %d\n", i);
174
175 printf("Tsi148: Pci addr %08x\n", pciAddr);
176
Peter Tyserca2cac22009-07-20 21:51:38 -0500177 __raw_writel(htonl(pciAddr), &dev->uregs->outbound[i].otsal);
178 __raw_writel(0x00000000, &dev->uregs->outbound[i].otsau);
Reinhard Arltff196c12009-06-10 19:09:40 +0200179 __raw_writel(htonl(pciAddr + size), &dev->uregs->outbound[i].oteal);
Peter Tyserca2cac22009-07-20 21:51:38 -0500180 __raw_writel(0x00000000, &dev->uregs->outbound[i].oteau);
Reinhard Arltff196c12009-06-10 19:09:40 +0200181 __raw_writel(htonl(vmeAddr - pciAddr), &dev->uregs->outbound[i].otofl);
Peter Tyserca2cac22009-07-20 21:51:38 -0500182 __raw_writel(0x00000000, &dev->uregs->outbound[i].otofu);
Reinhard Arltff196c12009-06-10 19:09:40 +0200183
184 switch (vam & VME_AM_Axx) {
185 case VME_AM_A16:
186 ctl = 0x00000000;
187 break;
188 case VME_AM_A24:
189 ctl = 0x00000001;
190 break;
191 case VME_AM_A32:
192 ctl = 0x00000002;
193 break;
194 }
195
196 switch (vam & VME_AM_Mxx) {
197 case VME_AM_DATA:
198 ctl |= 0x00000000;
199 break;
200 case VME_AM_PROG:
201 ctl |= 0x00000010;
202 break;
203 }
204
205 if (vam & VME_AM_SUP)
206 ctl |= 0x00000020;
207
208 switch (vdw & VME_FLAG_Dxx) {
209 case VME_FLAG_D16:
210 ctl |= 0x00000000;
211 break;
212 case VME_FLAG_D32:
213 ctl |= 0x00000040;
214 break;
215 }
216
Peter Tyserca2cac22009-07-20 21:51:38 -0500217 ctl |= 0x80040000; /* enable, no prefetch */
Reinhard Arltff196c12009-06-10 19:09:40 +0200218
219 __raw_writel(htonl(ctl), &dev->uregs->outbound[i].otat);
220
221 debug("Tsi148: window-addr =%p\n",
222 &dev->uregs->outbound[i].otsau);
223 debug("Tsi148: pci slave window[%d] attr =%08x\n",
224 i, ntohl(__raw_readl(&dev->uregs->outbound[i].otat)));
225 debug("Tsi148: pci slave window[%d] start =%08x\n",
226 i, ntohl(__raw_readl(&dev->uregs->outbound[i].otsal)));
227 debug("Tsi148: pci slave window[%d] end =%08x\n",
228 i, ntohl(__raw_readl(&dev->uregs->outbound[i].oteal)));
229 debug("Tsi148: pci slave window[%d] offset=%08x\n",
230 i, ntohl(__raw_readl(&dev->uregs->outbound[i].otofl)));
231
232 return 0;
233
234 exit_10:
235 return -result;
236}
237
238unsigned int tsi148_eval_vam(int vam)
239{
240 unsigned int ctl = 0;
241
242 switch (vam & VME_AM_Axx) {
243 case VME_AM_A16:
244 ctl = 0x00000000;
245 break;
246 case VME_AM_A24:
247 ctl = 0x00000010;
248 break;
249 case VME_AM_A32:
250 ctl = 0x00000020;
251 break;
252 }
253 switch (vam & VME_AM_Mxx) {
254 case VME_AM_DATA:
255 ctl |= 0x00000001;
256 break;
257 case VME_AM_PROG:
258 ctl |= 0x00000002;
259 break;
260 case (VME_AM_PROG | VME_AM_DATA):
261 ctl |= 0x00000003;
262 break;
263 }
264
265 if (vam & VME_AM_SUP)
266 ctl |= 0x00000008;
267 if (vam & VME_AM_USR)
268 ctl |= 0x00000004;
269
270 return ctl;
271}
272
273/*
274 * Create vme slave window (access: vme -> pci)
275 */
Peter Tyserca2cac22009-07-20 21:51:38 -0500276int tsi148_vme_slave_window(unsigned int vmeAddr, unsigned int pciAddr,
277 int size, int vam)
Reinhard Arltff196c12009-06-10 19:09:40 +0200278{
279 int result, i;
280 unsigned int ctl = 0;
281
282 if (NULL == dev) {
283 result = -1;
284 goto exit_10;
285 }
286
287 for (i = 0; i < 8; i++) {
288 if (0x00000000 == readl(&dev->uregs->inbound[i].itat))
289 break;
290 }
291
292 if (i > 7) {
293 printf("Tsi148: No Image available\n");
294 result = -1;
295 goto exit_10;
296 }
297
298 debug("Tsi148: Using image %d\n", i);
299
300 __raw_writel(htonl(vmeAddr), &dev->uregs->inbound[i].itsal);
301 __raw_writel(0x00000000, &dev->uregs->inbound[i].itsau);
302 __raw_writel(htonl(vmeAddr + size), &dev->uregs->inbound[i].iteal);
303 __raw_writel(0x00000000, &dev->uregs->inbound[i].iteau);
304 __raw_writel(htonl(pciAddr - vmeAddr), &dev->uregs->inbound[i].itofl);
305 if (vmeAddr > pciAddr)
306 __raw_writel(0xffffffff, &dev->uregs->inbound[i].itofu);
307 else
308 __raw_writel(0x00000000, &dev->uregs->inbound[i].itofu);
309
310 ctl = tsi148_eval_vam(vam);
Peter Tyserca2cac22009-07-20 21:51:38 -0500311 ctl |= 0x80000000; /* enable */
Reinhard Arltff196c12009-06-10 19:09:40 +0200312 __raw_writel(htonl(ctl), &dev->uregs->inbound[i].itat);
313
314 debug("Tsi148: window-addr =%p\n",
315 &dev->uregs->inbound[i].itsau);
316 debug("Tsi148: vme slave window[%d] attr =%08x\n",
Peter Tyserca2cac22009-07-20 21:51:38 -0500317 i, ntohl(__raw_readl(&dev->uregs->inbound[i].itat)));
Reinhard Arltff196c12009-06-10 19:09:40 +0200318 debug("Tsi148: vme slave window[%d] start =%08x\n",
319 i, ntohl(__raw_readl(&dev->uregs->inbound[i].itsal)));
320 debug("Tsi148: vme slave window[%d] end =%08x\n",
321 i, ntohl(__raw_readl(&dev->uregs->inbound[i].iteal)));
322 debug("Tsi148: vme slave window[%d] offset=%08x\n",
323 i, ntohl(__raw_readl(&dev->uregs->inbound[i].itofl)));
324
325 return 0;
326
327 exit_10:
328 return -result;
329}
330
331/*
332 * Create vme slave window (access: vme -> gcsr)
333 */
334int tsi148_vme_gcsr_window(unsigned int vmeAddr, int vam)
335{
336 int result;
337 unsigned int ctl;
338
339 result = 0;
340
341 if (NULL == dev) {
342 result = 1;
343 } else {
Peter Tyserca2cac22009-07-20 21:51:38 -0500344 __raw_writel(htonl(vmeAddr), &dev->uregs->gbal);
345 __raw_writel(0x00000000, &dev->uregs->gbau);
Reinhard Arltff196c12009-06-10 19:09:40 +0200346
Peter Tyserca2cac22009-07-20 21:51:38 -0500347 ctl = tsi148_eval_vam(vam);
348 ctl |= 0x00000080; /* enable */
349 __raw_writel(htonl(ctl), &dev->uregs->gcsrat);
Reinhard Arltff196c12009-06-10 19:09:40 +0200350 }
351
352 return result;
353}
354
355/*
356 * Create vme slave window (access: vme -> crcsr)
357 */
358int tsi148_vme_crcsr_window(unsigned int vmeAddr)
359{
360 int result;
361 unsigned int ctl;
362
363 result = 0;
364
365 if (NULL == dev) {
366 result = 1;
367 } else {
Peter Tyserca2cac22009-07-20 21:51:38 -0500368 __raw_writel(htonl(vmeAddr), &dev->uregs->crol);
369 __raw_writel(0x00000000, &dev->uregs->crou);
Reinhard Arltff196c12009-06-10 19:09:40 +0200370
Peter Tyserca2cac22009-07-20 21:51:38 -0500371 ctl = 0x00000080; /* enable */
372 __raw_writel(htonl(ctl), &dev->uregs->crat);
Reinhard Arltff196c12009-06-10 19:09:40 +0200373 }
374
375 return result;
376}
377
Reinhard Arltff196c12009-06-10 19:09:40 +0200378/*
379 * Create vme slave window (access: vme -> crg)
380 */
381int tsi148_vme_crg_window(unsigned int vmeAddr, int vam)
382{
383 int result;
384 unsigned int ctl;
385
386 result = 0;
387
388 if (NULL == dev) {
389 result = 1;
390 } else {
Peter Tyserca2cac22009-07-20 21:51:38 -0500391 __raw_writel(htonl(vmeAddr), &dev->uregs->cbal);
392 __raw_writel(0x00000000, &dev->uregs->cbau);
Reinhard Arltff196c12009-06-10 19:09:40 +0200393
Peter Tyserca2cac22009-07-20 21:51:38 -0500394 ctl = tsi148_eval_vam(vam);
395 ctl |= 0x00000080; /* enable */
396 __raw_writel(htonl(ctl), &dev->uregs->crgat);
Reinhard Arltff196c12009-06-10 19:09:40 +0200397 }
398
399 return result;
400}
401
402/*
403 * Tundra Tsi148 configuration
404 */
Wolfgang Denk6262d0212010-06-28 22:00:46 +0200405int do_tsi148(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
Reinhard Arltff196c12009-06-10 19:09:40 +0200406{
407 ulong addr1 = 0, addr2 = 0, size = 0, vam = 0, vdw = 0;
408 char cmd = 'x';
409
410 /* get parameter */
411 if (argc > 1)
412 cmd = argv[1][0];
413 if (argc > 2)
414 addr1 = simple_strtoul(argv[2], NULL, 16);
415 if (argc > 3)
416 addr2 = simple_strtoul(argv[3], NULL, 16);
417 if (argc > 4)
418 size = simple_strtoul(argv[4], NULL, 16);
419 if (argc > 5)
420 vam = simple_strtoul(argv[5], NULL, 16);
421 if (argc > 6)
Brent Darleye711ec22010-09-29 13:50:17 -0500422 vdw = simple_strtoul(argv[6], NULL, 16);
Reinhard Arltff196c12009-06-10 19:09:40 +0200423
424 switch (cmd) {
425 case 'c':
426 if (strcmp(argv[1], "crg") == 0) {
427 vam = addr2;
Peter Tyserca2cac22009-07-20 21:51:38 -0500428 printf("Tsi148: Configuring VME CRG Window "
429 "(VME->CRG):\n");
Reinhard Arltff196c12009-06-10 19:09:40 +0200430 printf(" vme=%08lx vam=%02lx\n", addr1, vam);
431 tsi148_vme_crg_window(addr1, vam);
432 } else {
Peter Tyserca2cac22009-07-20 21:51:38 -0500433 printf("Tsi148: Configuring VME CR/CSR Window "
434 "(VME->CR/CSR):\n");
Reinhard Arltff196c12009-06-10 19:09:40 +0200435 printf(" pci=%08lx\n", addr1);
436 tsi148_vme_crcsr_window(addr1);
437 }
438 break;
439 case 'i': /* init */
440 tsi148_init();
441 break;
442 case 'g':
443 vam = addr2;
444 printf("Tsi148: Configuring VME GCSR Window (VME->GCSR):\n");
445 printf(" vme=%08lx vam=%02lx\n", addr1, vam);
446 tsi148_vme_gcsr_window(addr1, vam);
447 break;
448 case 'v': /* vme */
449 printf("Tsi148: Configuring VME Slave Window (VME->PCI):\n");
450 printf(" vme=%08lx pci=%08lx size=%08lx vam=%02lx\n",
451 addr1, addr2, size, vam);
452 tsi148_vme_slave_window(addr1, addr2, size, vam);
453 break;
454 case 'p': /* pci */
455 printf("Tsi148: Configuring PCI Slave Window (PCI->VME):\n");
456 printf(" pci=%08lx vme=%08lx size=%08lx vam=%02lx vdw=%02lx\n",
457 addr1, addr2, size, vam, vdw);
458 tsi148_pci_slave_window(addr1, addr2, size, vam, vdw);
459 break;
460 default:
461 printf("Tsi148: Command %s not supported!\n", argv[1]);
462 }
463
464 return 0;
465}
466
467U_BOOT_CMD(
Brent Darleye711ec22010-09-29 13:50:17 -0500468 tsi148, 7, 1, do_tsi148,
Peter Tyserca2cac22009-07-20 21:51:38 -0500469 "initialize and configure Turndra Tsi148\n",
Reinhard Arltff196c12009-06-10 19:09:40 +0200470 "init\n"
471 " - initialize tsi148\n"
472 "tsi148 vme [vme_addr] [pci_addr] [size] [vam]\n"
473 " - create vme slave window (access: vme->pci)\n"
474 "tsi148 pci [pci_addr] [vme_addr] [size] [vam] [vdw]\n"
475 " - create pci slave window (access: pci->vme)\n"
476 "tsi148 crg [vme_addr] [vam]\n"
477 " - create vme slave window: (access vme->CRG\n"
478 "tsi148 crcsr [pci_addr]\n"
479 " - create vme slave window: (access vme->CR/CSR\n"
480 "tsi148 gcsr [vme_addr] [vam]\n"
481 " - create vme slave window: (access vme->GCSR\n"
482 " [vam] = VMEbus Address-Modifier: 01 -> A16 Address Space\n"
483 " 02 -> A24 Address Space\n"
484 " 03 -> A32 Address Space\n"
485 " 04 -> Usr AM Code\n"
486 " 08 -> Supervisor AM Code\n"
487 " 10 -> Data AM Code\n"
488 " 20 -> Program AM Code\n"
489 " [vdw] = VMEbus Maximum Datawidth: 02 -> D16 Data Width\n"
490 " 03 -> D32 Data Width\n"
491);