Merge branch 'elf_reloc'
[platform/kernel/u-boot.git] / common / cmd_tsi148.c
1 /*
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
27 #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
38 typedef struct _TSI148_DEV TSI148_DEV;
39
40 struct _TSI148_DEV {
41         int           bus;
42         pci_dev_t     busdevfn;
43         TSI148       *uregs;
44         unsigned int  pci_bs;
45 };
46
47 static 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
54 int 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
85         /* 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)) {
89                 printf("Tsi148: Cannot read PCI-ID via Mapping: %08x\n",
90                        readl(&dev->uregs->pci_id));
91                 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
108 #ifdef DEBUG
109         if ((__raw_readl(&dev->uregs->vstat) & 0x00000100) != 0)
110                 printf("Tsi148: System Controller!\n");
111         else
112                 printf("Tsi148: Not System Controller!\n");
113 #endif
114
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
130         val = __raw_readl(&dev->uregs->vstat);
131         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  */
151 int tsi148_pci_slave_window(unsigned int pciAddr, unsigned int vmeAddr,
152                             int size, int vam, int vdw)
153 {
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
177         __raw_writel(htonl(pciAddr), &dev->uregs->outbound[i].otsal);
178         __raw_writel(0x00000000, &dev->uregs->outbound[i].otsau);
179         __raw_writel(htonl(pciAddr + size), &dev->uregs->outbound[i].oteal);
180         __raw_writel(0x00000000, &dev->uregs->outbound[i].oteau);
181         __raw_writel(htonl(vmeAddr - pciAddr), &dev->uregs->outbound[i].otofl);
182         __raw_writel(0x00000000, &dev->uregs->outbound[i].otofu);
183
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
217         ctl |= 0x80040000;      /* enable, no prefetch */
218
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
238 unsigned 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  */
276 int tsi148_vme_slave_window(unsigned int vmeAddr, unsigned int pciAddr,
277                             int size, int vam)
278 {
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);
311         ctl |= 0x80000000;      /* enable */
312         __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",
317               i, ntohl(__raw_readl(&dev->uregs->inbound[i].itat)));
318         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  */
334 int 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 {
344                 __raw_writel(htonl(vmeAddr), &dev->uregs->gbal);
345                 __raw_writel(0x00000000, &dev->uregs->gbau);
346
347                 ctl = tsi148_eval_vam(vam);
348                 ctl |= 0x00000080;      /* enable */
349                 __raw_writel(htonl(ctl), &dev->uregs->gcsrat);
350         }
351
352         return result;
353 }
354
355 /*
356  * Create vme slave window (access: vme -> crcsr)
357  */
358 int 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 {
368                 __raw_writel(htonl(vmeAddr), &dev->uregs->crol);
369                 __raw_writel(0x00000000, &dev->uregs->crou);
370
371                 ctl = 0x00000080;       /* enable */
372                 __raw_writel(htonl(ctl), &dev->uregs->crat);
373         }
374
375         return result;
376 }
377
378 /*
379  * Create vme slave window (access: vme -> crg)
380  */
381 int 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 {
391                 __raw_writel(htonl(vmeAddr), &dev->uregs->cbal);
392                 __raw_writel(0x00000000, &dev->uregs->cbau);
393
394                 ctl = tsi148_eval_vam(vam);
395                 ctl |= 0x00000080;      /* enable */
396                 __raw_writel(htonl(ctl), &dev->uregs->crgat);
397         }
398
399         return result;
400 }
401
402 /*
403  * Tundra Tsi148 configuration
404  */
405 int do_tsi148(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
406 {
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)
422                 vdw = simple_strtoul(argv[6], NULL, 16);
423
424         switch (cmd) {
425         case 'c':
426                 if (strcmp(argv[1], "crg") == 0) {
427                         vam = addr2;
428                         printf("Tsi148: Configuring VME CRG Window "
429                                "(VME->CRG):\n");
430                         printf("  vme=%08lx vam=%02lx\n", addr1, vam);
431                         tsi148_vme_crg_window(addr1, vam);
432                 } else {
433                         printf("Tsi148: Configuring VME CR/CSR Window "
434                                "(VME->CR/CSR):\n");
435                         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
467 U_BOOT_CMD(
468         tsi148, 7,      1,      do_tsi148,
469         "initialize and configure Turndra Tsi148\n",
470         "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 );