| /* | |
| * (C) Copyright 2003 Stefan Roese, stefan.roese@esd-electronics.com | |
| * | |
| * See file CREDITS for list of people who contributed to this | |
| * project. | |
| * | |
| * This program is free software; you can redistribute it and/or | |
| * modify it under the terms of the GNU General Public License as | |
| * published by the Free Software Foundation; either version 2 of | |
| * the License, or (at your option) any later version. | |
| * | |
| * This program is distributed in the hope that it will be useful, | |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| * GNU General Public License for more details. | |
| * | |
| * You should have received a copy of the GNU General Public License | |
| * along with this program; if not, write to the Free Software | |
| * Foundation, Inc., 59 Temple Place, Suite 330, Boston, | |
| * MA 02111-1307 USA | |
| */ | |
| #include <common.h> | |
| #include <command.h> | |
| #include <malloc.h> | |
| #include <asm/io.h> | |
| #include <pci.h> | |
| #include <universe.h> | |
| #define PCI_VENDOR PCI_VENDOR_ID_TUNDRA | |
| #define PCI_DEVICE PCI_DEVICE_ID_TUNDRA_CA91C042 | |
| typedef struct _UNI_DEV UNI_DEV; | |
| struct _UNI_DEV { | |
| int bus; | |
| pci_dev_t busdevfn; | |
| UNIVERSE *uregs; | |
| unsigned int pci_bs; | |
| }; | |
| static UNI_DEV *dev; | |
| int universe_init(void) | |
| { | |
| int j, result, lastError = 0; | |
| pci_dev_t busdevfn; | |
| unsigned int val; | |
| busdevfn = pci_find_device(PCI_VENDOR, PCI_DEVICE, 0); | |
| if (busdevfn == -1) { | |
| puts("No Tundra Universe found!\n"); | |
| return -1; | |
| } | |
| /* Lets turn Latency off */ | |
| pci_write_config_dword(busdevfn, 0x0c, 0); | |
| dev = malloc(sizeof(*dev)); | |
| if (NULL == dev) { | |
| puts("UNIVERSE: No memory!\n"); | |
| result = -1; | |
| goto break_20; | |
| } | |
| memset(dev, 0, sizeof(*dev)); | |
| dev->busdevfn = busdevfn; | |
| pci_read_config_dword(busdevfn, PCI_BASE_ADDRESS_1, &val); | |
| if (val & 1) { | |
| pci_read_config_dword(busdevfn, PCI_BASE_ADDRESS_0, &val); | |
| } | |
| val &= ~0xf; | |
| dev->uregs = (UNIVERSE *)val; | |
| debug ("UNIVERSE-Base : %p\n", dev->uregs); | |
| /* check mapping */ | |
| debug (" Read via mapping, PCI_ID = %08X\n", readl(&dev->uregs->pci_id)); | |
| if (((PCI_DEVICE <<16) | PCI_VENDOR) != readl(&dev->uregs->pci_id)) { | |
| printf ("UNIVERSE: Cannot read PCI-ID via Mapping: %08x\n", | |
| readl(&dev->uregs->pci_id)); | |
| result = -1; | |
| goto break_30; | |
| } | |
| debug ("PCI_BS = %08X\n", readl(&dev->uregs->pci_bs)); | |
| dev->pci_bs = readl(&dev->uregs->pci_bs); | |
| /* turn off windows */ | |
| for (j=0; j <4; j ++) { | |
| writel(0x00800000, &dev->uregs->lsi[j].ctl); | |
| writel(0x00800000, &dev->uregs->vsi[j].ctl); | |
| } | |
| /* | |
| * Write to Misc Register | |
| * Set VME Bus Time-out | |
| * Arbitration Mode | |
| * DTACK Enable | |
| */ | |
| writel(0x15040000 | (readl(&dev->uregs->misc_ctl) & 0x00020000), &dev->uregs->misc_ctl); | |
| if (readl(&dev->uregs->misc_ctl) & 0x00020000) { | |
| debug ("System Controller!\n"); /* test-only */ | |
| } else { | |
| debug ("Not System Controller!\n"); /* test-only */ | |
| } | |
| /* | |
| * Lets turn off interrupts | |
| */ | |
| writel(0x00000000,&dev->uregs->lint_en); /* Disable interrupts in the Universe first */ | |
| writel(0x0000FFFF,&dev->uregs->lint_stat); /* Clear Any Pending Interrupts */ | |
| eieio(); | |
| writel(0x0000, &dev->uregs->lint_map0); /* Map all ints to 0 */ | |
| writel(0x0000, &dev->uregs->lint_map1); /* Map all ints to 0 */ | |
| eieio(); | |
| return 0; | |
| break_30: | |
| free(dev); | |
| break_20: | |
| lastError = result; | |
| return result; | |
| } | |
| /* | |
| * Create pci slave window (access: pci -> vme) | |
| */ | |
| int universe_pci_slave_window(unsigned int pciAddr, unsigned int vmeAddr, int size, int vam, int pms, int vdw) | |
| { | |
| int result, i; | |
| unsigned int ctl = 0; | |
| if (NULL == dev) { | |
| result = -1; | |
| goto exit_10; | |
| } | |
| for (i = 0; i < 4; i++) { | |
| if (0x00800000 == readl(&dev->uregs->lsi[i].ctl)) | |
| break; | |
| } | |
| if (i == 4) { | |
| printf ("universe: No Image available\n"); | |
| result = -1; | |
| goto exit_10; | |
| } | |
| debug ("universe: Using image %d\n", i); | |
| writel(pciAddr , &dev->uregs->lsi[i].bs); | |
| writel((pciAddr + size), &dev->uregs->lsi[i].bd); | |
| writel((vmeAddr - pciAddr), &dev->uregs->lsi[i].to); | |
| switch (vam & VME_AM_Axx) { | |
| case VME_AM_A16: | |
| ctl = 0x00000000; | |
| break; | |
| case VME_AM_A24: | |
| ctl = 0x00010000; | |
| break; | |
| case VME_AM_A32: | |
| ctl = 0x00020000; | |
| break; | |
| } | |
| switch (vam & VME_AM_Mxx) { | |
| case VME_AM_DATA: | |
| ctl |= 0x00000000; | |
| break; | |
| case VME_AM_PROG: | |
| ctl |= 0x00008000; | |
| break; | |
| } | |
| if (vam & VME_AM_SUP) { | |
| ctl |= 0x00001000; | |
| } | |
| switch (vdw & VME_FLAG_Dxx) { | |
| case VME_FLAG_D8: | |
| ctl |= 0x00000000; | |
| break; | |
| case VME_FLAG_D16: | |
| ctl |= 0x00400000; | |
| break; | |
| case VME_FLAG_D32: | |
| ctl |= 0x00800000; | |
| break; | |
| } | |
| switch (pms & PCI_MS_Mxx) { | |
| case PCI_MS_MEM: | |
| ctl |= 0x00000000; | |
| break; | |
| case PCI_MS_IO: | |
| ctl |= 0x00000001; | |
| break; | |
| case PCI_MS_CONFIG: | |
| ctl |= 0x00000002; | |
| break; | |
| } | |
| ctl |= 0x80000000; /* enable */ | |
| writel(ctl, &dev->uregs->lsi[i].ctl); | |
| debug ("universe: window-addr=%p\n", &dev->uregs->lsi[i].ctl); | |
| debug ("universe: pci slave window[%d] ctl=%08x\n", i, readl(&dev->uregs->lsi[i].ctl)); | |
| debug ("universe: pci slave window[%d] bs=%08x\n", i, readl(&dev->uregs->lsi[i].bs)); | |
| debug ("universe: pci slave window[%d] bd=%08x\n", i, readl(&dev->uregs->lsi[i].bd)); | |
| debug ("universe: pci slave window[%d] to=%08x\n", i, readl(&dev->uregs->lsi[i].to)); | |
| return 0; | |
| exit_10: | |
| return -result; | |
| } | |
| /* | |
| * Create vme slave window (access: vme -> pci) | |
| */ | |
| int universe_vme_slave_window(unsigned int vmeAddr, unsigned int pciAddr, int size, int vam, int pms) | |
| { | |
| int result, i; | |
| unsigned int ctl = 0; | |
| if (NULL == dev) { | |
| result = -1; | |
| goto exit_10; | |
| } | |
| for (i = 0; i < 4; i++) { | |
| if (0x00800000 == readl(&dev->uregs->vsi[i].ctl)) | |
| break; | |
| } | |
| if (i == 4) { | |
| printf ("universe: No Image available\n"); | |
| result = -1; | |
| goto exit_10; | |
| } | |
| debug ("universe: Using image %d\n", i); | |
| writel(vmeAddr , &dev->uregs->vsi[i].bs); | |
| writel((vmeAddr + size), &dev->uregs->vsi[i].bd); | |
| writel((pciAddr - vmeAddr), &dev->uregs->vsi[i].to); | |
| switch (vam & VME_AM_Axx) { | |
| case VME_AM_A16: | |
| ctl = 0x00000000; | |
| break; | |
| case VME_AM_A24: | |
| ctl = 0x00010000; | |
| break; | |
| case VME_AM_A32: | |
| ctl = 0x00020000; | |
| break; | |
| } | |
| switch (vam & VME_AM_Mxx) { | |
| case VME_AM_DATA: | |
| ctl |= 0x00000000; | |
| break; | |
| case VME_AM_PROG: | |
| ctl |= 0x00800000; | |
| break; | |
| } | |
| if (vam & VME_AM_SUP) { | |
| ctl |= 0x00100000; | |
| } | |
| switch (pms & PCI_MS_Mxx) { | |
| case PCI_MS_MEM: | |
| ctl |= 0x00000000; | |
| break; | |
| case PCI_MS_IO: | |
| ctl |= 0x00000001; | |
| break; | |
| case PCI_MS_CONFIG: | |
| ctl |= 0x00000002; | |
| break; | |
| } | |
| ctl |= 0x80f00000; /* enable */ | |
| writel(ctl, &dev->uregs->vsi[i].ctl); | |
| debug ("universe: window-addr=%p\n", &dev->uregs->vsi[i].ctl); | |
| debug ("universe: vme slave window[%d] ctl=%08x\n", i, readl(&dev->uregs->vsi[i].ctl)); | |
| debug ("universe: vme slave window[%d] bs=%08x\n", i, readl(&dev->uregs->vsi[i].bs)); | |
| debug ("universe: vme slave window[%d] bd=%08x\n", i, readl(&dev->uregs->vsi[i].bd)); | |
| debug ("universe: vme slave window[%d] to=%08x\n", i, readl(&dev->uregs->vsi[i].to)); | |
| return 0; | |
| exit_10: | |
| return -result; | |
| } | |
| /* | |
| * Tundra Universe configuration | |
| */ | |
| int do_universe(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) | |
| { | |
| ulong addr1 = 0, addr2 = 0, size = 0, vam = 0, pms = 0, vdw = 0; | |
| char cmd = 'x'; | |
| /* get parameter */ | |
| if (argc > 1) | |
| cmd = argv[1][0]; | |
| if (argc > 2) | |
| addr1 = simple_strtoul(argv[2], NULL, 16); | |
| if (argc > 3) | |
| addr2 = simple_strtoul(argv[3], NULL, 16); | |
| if (argc > 4) | |
| size = simple_strtoul(argv[4], NULL, 16); | |
| if (argc > 5) | |
| vam = simple_strtoul(argv[5], NULL, 16); | |
| if (argc > 6) | |
| pms = simple_strtoul(argv[6], NULL, 16); | |
| if (argc > 7) | |
| vdw = simple_strtoul(argv[7], NULL, 16); | |
| switch (cmd) { | |
| case 'i': /* init */ | |
| universe_init(); | |
| break; | |
| case 'v': /* vme */ | |
| printf("Configuring Universe VME Slave Window (VME->PCI):\n"); | |
| printf(" vme=%08lx pci=%08lx size=%08lx vam=%02lx pms=%02lx\n", | |
| addr1, addr2, size, vam, pms); | |
| universe_vme_slave_window(addr1, addr2, size, vam, pms); | |
| break; | |
| case 'p': /* pci */ | |
| printf("Configuring Universe PCI Slave Window (PCI->VME):\n"); | |
| printf(" pci=%08lx vme=%08lx size=%08lx vam=%02lx pms=%02lx vdw=%02lx\n", | |
| addr1, addr2, size, vam, pms, vdw); | |
| universe_pci_slave_window(addr1, addr2, size, vam, pms, vdw); | |
| break; | |
| default: | |
| printf("Universe command %s not supported!\n", argv[1]); | |
| } | |
| return 0; | |
| } | |
| U_BOOT_CMD( | |
| universe, 8, 1, do_universe, | |
| "universe- initialize and configure Turndra Universe\n", | |
| "init\n" | |
| " - initialize universe\n" | |
| "universe vme [vme_addr] [pci_addr] [size] [vam] [pms]\n" | |
| " - create vme slave window (access: vme->pci)\n" | |
| "universe pci [pci_addr] [vme_addr] [size] [vam] [pms] [vdw]\n" | |
| " - create pci slave window (access: pci->vme)\n" | |
| " [vam] = VMEbus Address-Modifier: 01 -> A16 Address Space\n" | |
| " 02 -> A24 Address Space\n" | |
| " 03 -> A32 Address Space\n" | |
| " 04 -> Supervisor AM Code\n" | |
| " 10 -> Data AM Code\n" | |
| " 20 -> Program AM Code\n" | |
| " [pms] = PCI Memory Space: 01 -> Memory Space\n" | |
| " 02 -> I/O Space\n" | |
| " 03 -> Configuration Space\n" | |
| " [vdw] = VMEbus Maximum Datawidth: 01 -> D8 Data Width\n" | |
| " 02 -> D16 Data Width\n" | |
| " 03 -> D32 Data Width\n" | |
| ); |