// SPDX-License-Identifier: GPL-2.0 /* * pcic.c: MicroSPARC-IIep PCI controller support * * Copyright (C) 1998 V. Roganov and G. Raiko * * Code is derived from Ultra/PCI PSYCHO controller support, see that * for author info. * * Support for diverse IIep based platforms by Pete Zaitcev. * CP-1200 by Eric Brower.
*/
/* * I studied different documents and many live PROMs both from 2.30 * family and 3.xx versions. I came to the amazing conclusion: there is * absolutely no way to route interrupts in IIep systems relying on * information which PROM presents. We must hardcode interrupt routing * schematics. And this actually sucks. -- zaitcev 1999/05/12 * * To find irq for a device we determine which routing map * is in effect or, in other words, on which machine we are running. * We use PROM name for this although other techniques may be used * in special cases (Gleb reports a PROMless IIep based system). * Once we know the map we take device configuration address and * find PCIC pin number where INT line goes. Then we may either program * preferred irq into the PCIC or supply the preexisting irq to the device.
*/ struct pcic_ca2irq { unsignedchar busno; /* PCI bus number */ unsignedchar devfn; /* Configuration address */ unsignedchar pin; /* PCIC external interrupt pin */ unsignedchar irq; /* Preferred IRQ (mappable in PCIC) */ unsignedint force; /* Enforce preferred IRQ */
};
/* * JavaEngine-1 apparently has different versions. * * According to communications with Sun folks, for P2 build 501-4628-03: * pin 0 - parallel, audio; * pin 1 - Ethernet; * pin 2 - su; * pin 3 - PS/2 kbd and mouse. * * OEM manual (805-1486): * pin 0: Ethernet * pin 1: All EBus * pin 2: IGA (unused) * pin 3: Not connected * OEM manual says that 501-4628 & 501-4811 are the same thing, * only the latter has NAND flash in place. * * So far unofficial Sun wins over the OEM manual. Poor OEMs...
*/ staticstruct pcic_ca2irq pcic_i_je1a[] = { /* 501-4811-03 */
{ 0, 0x00, 2, 12, 0 }, /* EBus: hogs all */
{ 0, 0x01, 1, 6, 1 }, /* Happy Meal */
{ 0, 0x80, 0, 7, 0 }, /* IGA (unused) */
};
/* XXX JS-E entry is incomplete - PCI Slot 2 address (pin 7)? */ staticstruct pcic_ca2irq pcic_i_jse[] = {
{ 0, 0x00, 0, 13, 0 }, /* Ebus - serial and keyboard */
{ 0, 0x01, 1, 6, 0 }, /* hme */
{ 0, 0x08, 2, 9, 0 }, /* VGA - we hope not used :) */
{ 0, 0x10, 6, 8, 0 }, /* PCI INTA# in Slot 1 */
{ 0, 0x18, 7, 12, 0 }, /* PCI INTA# in Slot 2, shared w. RTC */
{ 0, 0x38, 4, 9, 0 }, /* All ISA devices. Read 8259. */
{ 0, 0x80, 5, 11, 0 }, /* EIDE */ /* {0,0x88, 0,0,0} - unknown device... PMU? Probably no interrupt. */
{ 0, 0xA0, 4, 9, 0 }, /* USB */ /* * Some pins belong to non-PCI devices, we hardcode them in drivers. * sun4m timers - irq 10, 14 * PC style RTC - pin 7, irq 4 ? * Smart card, Parallel - pin 4 shared with USB, ISA * audio - pin 3, irq 5 ?
*/
};
/* SPARCengine-6 was the original release name of CP1200. * The documentation differs between the two versions
*/ staticstruct pcic_ca2irq pcic_i_se6[] = {
{ 0, 0x08, 0, 2, 0 }, /* SCSI */
{ 0, 0x01, 1, 6, 0 }, /* HME */
{ 0, 0x00, 3, 13, 0 }, /* EBus */
};
/* * Krups (courtesy of Varol Kaptan) * No documentation available, but it was easy to guess * because it was very similar to Espresso. * * pin 0 - kbd, mouse, serial; * pin 1 - Ethernet; * pin 2 - igs (we do not use it); * pin 3 - audio; * pin 4,5,6 - unused; * pin 7 - RTC (from P2 onwards as David B. says).
*/ staticstruct pcic_ca2irq pcic_i_jk[] = {
{ 0, 0x00, 0, 13, 0 }, /* Ebus - serial and keyboard */
{ 0, 0x01, 1, 6, 0 }, /* hme */
};
/* * Several entries in this list may point to the same routing map * as several PROMs may be installed on the same physical board.
*/ #define SN2L_INIT(name, map) \
{ name, map, ARRAY_SIZE(map) }
/* * On sparc64 pcibios_init() calls pci_controller_probe(). * We want PCIC probed little ahead so that interrupt controller * would be operational.
*/ int __init pcic_probe(void)
{ struct linux_pcic *pcic; struct linux_prom_registers regs[PROMREG_MAX]; struct linux_pbm_info* pbm; char namebuf[64];
phandle node; int err;
if (pcic0_up) {
prom_printf("PCIC: called twice!\n");
prom_halt();
}
pcic = &pcic0;
node = prom_getchild (prom_root_node);
node = prom_searchsiblings (node, "pci"); if (node == 0) return -ENODEV; /* * Map in PCIC register set, config space, and IO base
*/
err = prom_getproperty(node, "reg", (char*)regs, sizeof(regs)); if (err == 0 || err == -1) {
prom_printf("PCIC: Error, cannot get PCIC registers " "from PROM.\n");
prom_halt();
}
/* * Docs say three least significant bits in address and data * must be the same. Thus, we need adjust size of data.
*/
pcic->pcic_res_cfg_data.name = "pcic_cfg_data"; if ((pcic->pcic_config_space_data =
ioremap(regs[3].phys_addr, regs[3].reg_size * 2)) == NULL) {
prom_printf("PCIC: Error, cannot map " "PCI Configuration Space Data.\n");
prom_halt();
}
for (p = pcic_known_sysnames; p->sysname != NULL; p++) { if (strcmp(namebuf, p->sysname) == 0) break;
}
pcic->pcic_imap = p->intmap;
pcic->pcic_imdim = p->mapdim;
} if (pcic->pcic_imap == NULL) { /* * We do not panic here for the sake of embedded systems.
*/
printk("PCIC: System %s is unknown, cannot route interrupts\n",
namebuf);
}
/* * Main entry point from the PCI subsystem.
*/ staticint __init pcic_init(void)
{ struct linux_pcic *pcic;
/* * PCIC should be initialized at start of the timer. * So, here we report the presence of PCIC and do some magic passes.
*/ if(!pcic0_up) return 0;
pcic = &pcic0;
/* * Switch off IOTLB translation.
*/
writeb(PCI_DVMA_CONTROL_IOTLB_DISABLE,
pcic->pcic_regs+PCI_DVMA_CONTROL);
/* * Increase mapped size for PCI memory space (DMA access). * Should be done in that order (size first, address second). * Why we couldn't set up 4GB and forget about it? XXX
*/
writel(0xF0000000UL, pcic->pcic_regs+PCI_SIZE_0);
writel(0+PCI_BASE_ADDRESS_SPACE_MEMORY,
pcic->pcic_regs+PCI_BASE_ADDRESS_0);
for (j = 0; j < 6; j++) {
address = dev->resource[j].start; if (address == 0) break; /* are sequential */
flags = dev->resource[j].flags; if ((flags & IORESOURCE_IO) != 0) { if (address < 0x10000) { /* * A device responds to I/O cycles on PCI. * We generate these cycles with memory * access into the fixed map (phys 0x30000000). * * Since a device driver does not want to * do ioremap() before accessing PC-style I/O, * we supply virtual, ready to access address. * * Note that request_region() * works for these devices. * * XXX Neat trick, but it's a *bad* idea * to shit into regions like that. * What if we want to allocate one more * PCI base address...
*/
dev->resource[j].start =
pcic->pcic_io + address;
dev->resource[j].end = 1; /* XXX */
dev->resource[j].flags =
(flags & ~IORESOURCE_IO) | IORESOURCE_MEM;
} else { /* * OOPS... PCI Spec allows this. Sun does * not have any devices getting above 64K * so it must be user with a weird I/O * board in a PCI slot. We must remap it * under 64K but it is not done yet. XXX
*/
pci_info(dev, "PCIC: Skipping I/O space at " "0x%lx, this will Oops if a driver " "attaches device '%s'\n", address,
namebuf);
}
}
}
}
staticvoid
pcic_fill_irq(struct linux_pcic *pcic, struct pci_dev *dev, int node)
{ struct pcic_ca2irq *p; unsignedint real_irq; int i, ivec; char namebuf[64];
if ((p = pcic->pcic_imap) == NULL) {
dev->irq = 0; return;
} for (i = 0; i < pcic->pcic_imdim; i++) { if (p->busno == dev->bus->number && p->devfn == dev->devfn) break;
p++;
} if (i >= pcic->pcic_imdim) {
pci_info(dev, "PCIC: device %s not found in %d\n", namebuf,
pcic->pcic_imdim);
dev->irq = 0; return;
}
i = p->pin; if (i >= 0 && i < 4) {
ivec = readw(pcic->pcic_regs+PCI_INT_SELECT_LO);
real_irq = ivec >> (i << 2) & 0xF;
} elseif (i >= 4 && i < 8) {
ivec = readw(pcic->pcic_regs+PCI_INT_SELECT_HI);
real_irq = ivec >> ((i-4) << 2) & 0xF;
} else { /* Corrupted map */
pci_info(dev, "PCIC: BAD PIN %d\n", i); for (;;) {}
} /* P3 */ /* printk("PCIC: device %s pin %d ivec 0x%x irq %x\n", namebuf, i, ivec, dev->irq); */
/* real_irq means PROM did not bother to program the upper * half of PCIC. This happens on JS-E with PROM 3.11, for instance.
*/ if (real_irq == 0 || p->force) { if (p->irq == 0 || p->irq >= 15) { /* Corrupted map */
pci_info(dev, "PCIC: BAD IRQ %d\n", p->irq); for (;;) {}
}
pci_info(dev, "PCIC: setting irq %d at pin %d\n", p->irq,
p->pin);
real_irq = p->irq;
/* * Normally called from {do_}pci_scan_bus...
*/ void pcibios_fixup_bus(struct pci_bus *bus)
{ struct pci_dev *dev; struct linux_pcic *pcic; /* struct linux_pbm_info* pbm = &pcic->pbm; */ int node; struct pcidev_cookie *pcp;
if (!pcic0_up) {
pci_info(bus, "pcibios_fixup_bus: no PCIC\n"); return;
}
pcic = &pcic0;
/* * Next crud is an equivalent of pbm = pcic_bus_to_pbm(bus);
*/ if (bus->number != 0) {
pci_info(bus, "pcibios_fixup_bus: nonzero bus 0x%x\n",
bus->number); return;
}
value = readl(pcic0.pcic_regs + PCI_SYS_COUNTER);
count = value & ~PCI_SYS_COUNTER_OVERFLOW;
if (value & PCI_SYS_COUNTER_OVERFLOW)
count += TICK_TIMER_LIMIT; /* * We divide all by HZ * to have microsecond resolution and to avoid overflow
*/
count = ((count / HZ) * USECS_PER_JIFFY) / (TICK_TIMER_LIMIT / HZ);
/* Coordinate with the sparc_config.clock_rate setting */ return count * 2;
}
void __init pci_time_init(void)
{ struct linux_pcic *pcic = &pcic0; unsignedlong v; int timer_irq, irq; int err;
#ifndef CONFIG_SMP /* * The clock_rate is in SBUS dimension. * We take into account this in pcic_cycles_offset()
*/
sparc_config.clock_rate = SBUS_CLOCK_RATE / HZ;
sparc_config.features |= FEAT_L10_CLOCKEVENT; #endif
sparc_config.features |= FEAT_L10_CLOCKSOURCE;
sparc_config.get_cycles_offset = pcic_cycles_offset;
writel (TICK_TIMER_LIMIT, pcic->pcic_regs+PCI_SYS_LIMIT); /* PROM should set appropriate irq */
v = readb(pcic->pcic_regs+PCI_COUNTER_IRQ);
timer_irq = PCI_COUNTER_IRQ_SYS(v);
writel (PCI_COUNTER_IRQ_SET(timer_irq, 0),
pcic->pcic_regs+PCI_COUNTER_IRQ);
irq = pcic_build_device_irq(NULL, timer_irq);
err = request_irq(irq, timer_interrupt,
IRQF_TIMER, "timer", NULL); if (err) {
prom_printf("time_init: unable to attach IRQ%d\n", timer_irq);
prom_halt();
}
local_irq_enable();
}
if (!pcic_speculative || (pend & PCI_SYS_INT_PENDING_PIO) == 0) { /* * XXX On CP-1200 PCI #SERR may happen, we do not know * what to do about it yet.
*/
printk("Aiee, NMI pend 0x%x pc 0x%x spec %d, hanging\n",
pend, (int)regs->pc, pcic_speculative); for (;;) { }
}
pcic_speculative = 0;
pcic_trapped = 1;
regs->pc = regs->npc;
regs->npc += 4;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.