--- trunk/src/devices/bus_pci.c 2007/10/08 16:19:37 22 +++ trunk/src/devices/bus_pci.c 2007/10/13 12:51:47 62 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2006 Anders Gavare. All rights reserved. + * Copyright (C) 2004-2007 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -25,10 +25,12 @@ * SUCH DAMAGE. * * - * $Id: bus_pci.c,v 1.62 2006/02/18 21:03:12 debug Exp $ + * $Id: bus_pci.c,v 1.85 2007/06/16 14:39:18 debug Exp $ * - * Generic PCI bus framework. This is not a normal "device", but is used by - * individual PCI controllers and devices. + * COMMENT: Generic PCI bus framework + * + * This is not a normal "device", but is used by individual PCI controllers + * and devices. * * See NetBSD's pcidevs.h for more PCI vendor and device identifiers. * @@ -48,6 +50,7 @@ #define BUS_PCI_C +#include "bus_isa.h" #include "bus_pci.h" #include "cpu.h" #include "device.h" @@ -57,10 +60,15 @@ #include "memory.h" #include "misc.h" +#include "cpc700reg.h" +#include "wdc.h" + extern int verbose; -/* #define debug fatal */ +#ifdef UNSTABLE_DEVEL +#define debug fatal +#endif /* @@ -145,15 +153,27 @@ pci_data->last_was_write_ffffffff = 1; return; } - /* Writes are not really supported yet: */ - if (idata != x) { + + if (dev->cfg_reg_write != NULL) { + dev->cfg_reg_write(dev, pci_data->cur_reg, *data); + } else { + /* Print a warning for unhandled writes: */ debug("[ bus_pci: write to PCI DATA: data = 0x%08llx" - " differs from current value 0x%08llx; NOT YET" + " (current value = 0x%08llx); NOT YET" " SUPPORTED. bus %i, device %i, function %i (%s)" " register 0x%02x ]\n", (long long)idata, (long long)x, pci_data->cur_bus, pci_data->cur_device, pci_data->cur_func, dev->name, pci_data->cur_reg); + + /* Special warning, to detect if NetBSD's special + detection of PCI devices fails: */ + if (pci_data->cur_reg == PCI_COMMAND_STATUS_REG + && !((*data) & PCI_COMMAND_IO_ENABLE)) { + fatal("\n[ NetBSD PCI detection stuff not" + " yet implemented for device '%s' ]\n", + dev->name); + } } return; } @@ -164,9 +184,9 @@ pci_data->last_was_write_ffffffff = 0; debug("[ bus_pci: read from PCI DATA, bus %i, device " - "%i, function %i (%s) register 0x%02x: 0x%08lx ]\n", (long) - pci_data->cur_bus, pci_data->cur_device, - pci_data->cur_func, dev->name, pci_data->cur_reg, (long)*data); + "%i, function %i (%s) register 0x%02x: (len=%i) 0x%08lx ]\n", + pci_data->cur_bus, pci_data->cur_device, pci_data->cur_func, + dev->name, pci_data->cur_reg, len, (long)*data); } @@ -187,6 +207,7 @@ pci_data->cur_device = device; pci_data->cur_func = function; pci_data->cur_reg = reg; + debug("bus_pci_setaddr( bus %d device 0x%x func 0x%x reg 0x%x )\n", bus, device, function, reg ); } @@ -205,7 +226,7 @@ if (pci_data == NULL) { fatal("bus_pci_add(): pci_data == NULL!\n"); - exit(1); + abort(); } /* Find the PCI device: */ @@ -223,20 +244,15 @@ pd = pd->next; } - pd = malloc(sizeof(struct pci_device)); - if (pd == NULL) { - fprintf(stderr, "out of memory\n"); - exit(1); - } - + CHECK_ALLOCATION(pd = malloc(sizeof(struct pci_device))); memset(pd, 0, sizeof(struct pci_device)); /* Add the new device first in the PCI bus' chain: */ pd->next = pci_data->first_device; pci_data->first_device = pd; + CHECK_ALLOCATION(pd->name = strdup(name)); pd->pcibus = pci_data; - pd->name = strdup(name); pd->bus = bus; pd->device = device; pd->function = function; @@ -286,7 +302,7 @@ PCI_SET_DATA(PCI_MAPREG_START + pd->cur_mapreg_offset, port | PCI_MAPREG_TYPE_IO); PCI_SET_DATA_SIZE(PCI_MAPREG_START + pd->cur_mapreg_offset, - portsize - 1); + ((portsize - 1) & ~0xf) | 0xd); pd->cur_mapreg_offset += sizeof(uint32_t); } @@ -297,7 +313,7 @@ pd->pcibus->cur_pci_membase = mem; PCI_SET_DATA(PCI_MAPREG_START + pd->cur_mapreg_offset, mem); PCI_SET_DATA_SIZE(PCI_MAPREG_START + pd->cur_mapreg_offset, - memsize - 1); + ((memsize - 1) & ~0xf) | 0x0); pd->cur_mapreg_offset += sizeof(uint32_t); } @@ -322,45 +338,13 @@ } -static void bus_pci_debug_dump__2(struct pci_device *pd) -{ - if (pd == NULL) - return; - bus_pci_debug_dump__2(pd->next); - debug("bus %3i, dev %2i, func %i: %s\n", - pd->bus, pd->device, pd->function, pd->name); -} - - -/* - * bus_pci_debug_dump(): - * - * Lists the attached PCI devices (in reverse). - */ -void bus_pci_debug_dump(void *extra) -{ - struct pci_data *d = (struct pci_data *) extra; - int iadd = DEBUG_INDENTATION; - - debug("pci:\n"); - debug_indentation(iadd); - - if (d->first_device == NULL) - debug("no devices!\n"); - else - bus_pci_debug_dump__2(d->first_device); - - debug_indentation(-iadd); -} - - /* * bus_pci_init(): * * This doesn't register a device, but instead returns a pointer to a struct * which should be passed to other bus_pci functions when accessing the bus. * - * irq_nr is the (optional) IRQ nr that this PCI bus interrupts at. + * irq_path is the interrupt path to the PCI controller. * * pci_portbase, pci_membase, and pci_irqbase are the port, memory, and * interrupt bases for PCI devices (as found in the configuration registers). @@ -371,35 +355,37 @@ * isa_portbase, isa_membase, and isa_irqbase are the port, memory, and * interrupt bases for legacy ISA devices. */ -struct pci_data *bus_pci_init(struct machine *machine, int irq_nr, +struct pci_data *bus_pci_init(struct machine *machine, char *irq_path, uint64_t pci_actual_io_offset, uint64_t pci_actual_mem_offset, - uint64_t pci_portbase, uint64_t pci_membase, int pci_irqbase, - uint64_t isa_portbase, uint64_t isa_membase, int isa_irqbase) + uint64_t pci_portbase, uint64_t pci_membase, char *pci_irqbase, + uint64_t isa_portbase, uint64_t isa_membase, char *isa_irqbase) { struct pci_data *d; - d = malloc(sizeof(struct pci_data)); - if (d == NULL) { - fprintf(stderr, "out of memory\n"); - exit(1); - } + CHECK_ALLOCATION(d = malloc(sizeof(struct pci_data))); memset(d, 0, sizeof(struct pci_data)); - d->irq_nr = irq_nr; + + CHECK_ALLOCATION(d->irq_path = strdup(irq_path)); + CHECK_ALLOCATION(d->irq_path_isa = strdup(isa_irqbase)); + CHECK_ALLOCATION(d->irq_path_pci = strdup(pci_irqbase)); + d->pci_actual_io_offset = pci_actual_io_offset; d->pci_actual_mem_offset = pci_actual_mem_offset; d->pci_portbase = pci_portbase; d->pci_membase = pci_membase; - d->pci_irqbase = pci_irqbase; d->isa_portbase = isa_portbase; d->isa_membase = isa_membase; - d->isa_irqbase = isa_irqbase; - /* Register the bus: */ - machine_bus_register(machine, "pci", bus_pci_debug_dump, d); + d->cur_pci_portbase = d->pci_portbase; + d->cur_pci_membase = d->pci_membase; /* Assume that the first 64KB could be used by legacy ISA devices: */ - d->cur_pci_portbase = d->pci_portbase + 0x10000; - d->cur_pci_membase = d->pci_membase + 0x10000; + if (d->isa_portbase != 0 || d->isa_membase != 0) { + d->cur_pci_portbase += 0x10000; + d->cur_pci_membase += 0x10000; + } + + debug("bus_pci_init( pci_actual_io_offset %x pci_actual_mem_offset 0x%x pci_portbase 0x%x pci_membase 0x%x isa_portbase %x isa_membase %x )\n", pci_actual_io_offset, pci_actual_mem_offset, pci_portbase, pci_membase, isa_portbase, isa_membase ); return d; } @@ -418,15 +404,16 @@ /* - * Integraphics Systems "igsfb" Framebuffer (graphics) card. - * - * TODO + * Integraphics Systems "igsfb" Framebuffer (graphics) card, used in at + * least the NetWinder. */ #define PCI_VENDOR_INTEGRAPHICS 0x10ea PCIINIT(igsfb) { + char tmpstr[200]; + PCI_SET_DATA(PCI_ID_REG, PCI_ID_CODE(PCI_VENDOR_INTEGRAPHICS, 0x2010)); @@ -437,8 +424,9 @@ /* TODO */ PCI_SET_DATA(0x10, 0x08000000); - dev_vga_init(machine, mem, pd->pcibus->isa_membase + 0xa0000, - 0x88800000 + 0x3c0, machine->machine_name); + snprintf(tmpstr, sizeof(tmpstr), "igsfb addr=0x%llx", + (long long)(pd->pcibus->isa_membase + 0x08000000)); + device_add(machine, tmpstr); } @@ -491,11 +479,21 @@ /* Linux uses these to detect which IRQ the IDE controller uses: */ PCI_SET_DATA(0x44, 0x0000000e); PCI_SET_DATA(0x58, 0x00000003); + + switch (machine->machine_type) { + case MACHINE_CATS: + bus_isa_init(machine, pd->pcibus->irq_path_isa, + BUS_ISA_PCKBC_FORCE_USE | BUS_ISA_PCKBC_NONPCSTYLE, + 0x7c000000, 0x80000000); + break; + default:fatal("ali_m1543 init: unimplemented machine type\n"); + exit(1); + } } PCIINIT(ali_m5229) { - char tmpstr[300]; + char tmpstr[300], irqstr[300]; PCI_SET_DATA(PCI_ID_REG, PCI_ID_CODE(PCI_VENDOR_ALI, PCI_PRODUCT_ALI_M5229)); @@ -503,11 +501,21 @@ PCI_SET_DATA(PCI_CLASS_REG, PCI_CLASS_CODE(PCI_CLASS_MASS_STORAGE, PCI_SUBCLASS_MASS_STORAGE_IDE, 0x60) + 0xc1); + switch (machine->machine_type) { + case MACHINE_CATS: + /* CATS ISA interrupts are at footbridge irq 10: */ + snprintf(irqstr, sizeof(irqstr), "%s.10.isa", + pd->pcibus->irq_path); + break; + default:fatal("ali_m5229 init: unimplemented machine type\n"); + exit(1); + } + if (diskimage_exist(machine, 0, DISKIMAGE_IDE) || diskimage_exist(machine, 1, DISKIMAGE_IDE)) { - snprintf(tmpstr, sizeof(tmpstr), "wdc addr=0x%llx irq=%i", + snprintf(tmpstr, sizeof(tmpstr), "wdc addr=0x%llx irq=%s.%i", (long long)(pd->pcibus->isa_portbase + 0x1f0), - pd->pcibus->isa_irqbase + 14); + irqstr, 14); device_add(machine, tmpstr); } @@ -625,6 +633,47 @@ /* + * AMD PCnet Ethernet card. + * + * "Am79c970A PCnet-PCI II rev 0" or similar. + */ + +#define PCI_VENDOR_AMD 0x1022 /* Advanced Micro Devices */ +#define PCI_PRODUCT_AMD_PCNET_PCI 0x2000 /* PCnet-PCI Ethernet */ + +PCIINIT(pcn) +{ + int irq; + + PCI_SET_DATA(PCI_ID_REG, PCI_ID_CODE(PCI_VENDOR_AMD, + PCI_PRODUCT_AMD_PCNET_PCI)); + + PCI_SET_DATA(PCI_CLASS_REG, PCI_CLASS_CODE(PCI_CLASS_NETWORK, + PCI_SUBCLASS_NETWORK_ETHERNET, 0) + 0x00); /* Revision 0 */ + + switch (machine->machine_type) { + + case MACHINE_EVBMIPS: + irq = (1 << 8) + 10; /* TODO */ + break; + + default:fatal("pcn in non-implemented machine type %i\n", + machine->machine_type); + exit(1); + } + + PCI_SET_DATA(PCI_INTERRUPT_REG, 0x01100000 | irq); + + /* + * TODO: Add the pcn device here. The pcn device will need to work as + * a wrapper for dev_le + all the DMA magic and whatever is required. + * It's too much to implement right now. + */ +} + + + +/* * Intel 31244 Serial ATA Controller * Intel 82371SB PIIX3 PCI-ISA bridge * Intel 82371AB PIIX4 PCI-ISA bridge @@ -644,6 +693,7 @@ PCIINIT(i31244) { uint64_t port, memaddr; + int irq = 0; PCI_SET_DATA(PCI_ID_REG, PCI_ID_CODE(PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_31244)); @@ -653,25 +703,26 @@ switch (machine->machine_type) { case MACHINE_IQ80321: - /* S-PCI-X slot uses PCI IRQ A */ + /* S-PCI-X slot uses PCI IRQ A, int 29 */ + irq = (1 << 8) + 29; break; default:fatal("i31244 in non-implemented machine type %i\n", machine->machine_type); exit(1); } - PCI_SET_DATA(PCI_INTERRUPT_REG, 0x28140100); + PCI_SET_DATA(PCI_INTERRUPT_REG, 0x01100000 | irq); - allocate_device_space(pd, 0x400, 0, &port, &memaddr); - allocate_device_space(pd, 0x400, 0, &port, &memaddr); + allocate_device_space(pd, 0x1000, 0, &port, &memaddr); + allocate_device_space(pd, 0x1000, 0, &port, &memaddr); /* PCI IDE using dev_wdc: */ if (diskimage_exist(machine, 0, DISKIMAGE_IDE) || diskimage_exist(machine, 1, DISKIMAGE_IDE)) { char tmpstr[150]; - snprintf(tmpstr, sizeof(tmpstr), "wdc addr=0x%llx irq=%i", + snprintf(tmpstr, sizeof(tmpstr), "wdc addr=0x%llx irq=%s.%i", (long long)(pd->pcibus->pci_actual_io_offset + 0), - pd->pcibus->pci_irqbase + 0); + pd->pcibus->irq_path_pci, irq & 255); device_add(machine, tmpstr); } } @@ -717,6 +768,31 @@ PCI_SET_DATA(0x60, 0x0f0e0b0a); } +struct piix_ide_extra { + void *wdc0; + void *wdc1; +}; + +int piix_ide_cfg_reg_write(struct pci_device *pd, int reg, uint32_t value) +{ + void *wdc0 = ((struct piix_ide_extra *)pd->extra)->wdc0; + void *wdc1 = ((struct piix_ide_extra *)pd->extra)->wdc1; + int enabled = 0; + + switch (reg) { + case PCI_COMMAND_STATUS_REG: + if (value & PCI_COMMAND_IO_ENABLE) + enabled = 1; + if (wdc0 != NULL) + wdc_set_io_enabled(wdc0, enabled); + if (wdc1 != NULL) + wdc_set_io_enabled(wdc1, enabled); + return 1; + } + + return 0; +} + PCIINIT(piix3_ide) { char tmpstr[100]; @@ -732,21 +808,29 @@ /* channel 0 and 1 enabled as IDE */ PCI_SET_DATA(0x40, 0x80008000); + CHECK_ALLOCATION(pd->extra = malloc(sizeof(struct piix_ide_extra))); + ((struct piix_ide_extra *)pd->extra)->wdc0 = NULL; + ((struct piix_ide_extra *)pd->extra)->wdc1 = NULL; + if (diskimage_exist(machine, 0, DISKIMAGE_IDE) || diskimage_exist(machine, 1, DISKIMAGE_IDE)) { - snprintf(tmpstr, sizeof(tmpstr), "wdc addr=0x%llx irq=%i", - (long long)(pd->pcibus->isa_portbase + 0x1f0), - pd->pcibus->isa_irqbase + 14); - device_add(machine, tmpstr); + snprintf(tmpstr, sizeof(tmpstr), "wdc addr=0x%llx " + "irq=%s.isa.%i", (long long)(pd->pcibus->isa_portbase + + 0x1f0), pd->pcibus->irq_path_isa, 14); + ((struct piix_ide_extra *)pd->extra)->wdc0 = + device_add(machine, tmpstr); } if (diskimage_exist(machine, 2, DISKIMAGE_IDE) || diskimage_exist(machine, 3, DISKIMAGE_IDE)) { - snprintf(tmpstr, sizeof(tmpstr), "wdc addr=0x%llx irq=%i", - (long long)(pd->pcibus->isa_portbase + 0x170), - pd->pcibus->isa_irqbase + 15); - device_add(machine, tmpstr); + snprintf(tmpstr, sizeof(tmpstr), "wdc addr=0x%llx " + "irq=%s.isa.%i", (long long)(pd->pcibus->isa_portbase + + 0x170), pd->pcibus->irq_path_isa, 15); + ((struct piix_ide_extra *)pd->extra)->wdc1 = + device_add(machine, tmpstr); } + + pd->cfg_reg_write = piix_ide_cfg_reg_write; } PCIINIT(piix4_ide) @@ -764,21 +848,29 @@ /* channel 0 and 1 enabled as IDE */ PCI_SET_DATA(0x40, 0x80008000); + CHECK_ALLOCATION(pd->extra = malloc(sizeof(struct piix_ide_extra))); + ((struct piix_ide_extra *)pd->extra)->wdc0 = NULL; + ((struct piix_ide_extra *)pd->extra)->wdc1 = NULL; + if (diskimage_exist(machine, 0, DISKIMAGE_IDE) || diskimage_exist(machine, 1, DISKIMAGE_IDE)) { - snprintf(tmpstr, sizeof(tmpstr), "wdc addr=0x%llx irq=%i", - (long long)(pd->pcibus->isa_portbase + 0x1f0), - pd->pcibus->isa_irqbase + 14); - device_add(machine, tmpstr); + snprintf(tmpstr, sizeof(tmpstr), "wdc addr=0x%llx irq=%s." + "isa.%i", (long long)(pd->pcibus->isa_portbase + 0x1f0), + pd->pcibus->irq_path_isa, 14); + ((struct piix_ide_extra *)pd->extra)->wdc0 = + device_add(machine, tmpstr); } if (diskimage_exist(machine, 2, DISKIMAGE_IDE) || diskimage_exist(machine, 3, DISKIMAGE_IDE)) { - snprintf(tmpstr, sizeof(tmpstr), "wdc addr=0x%llx irq=%i", - (long long)(pd->pcibus->isa_portbase + 0x170), - pd->pcibus->isa_irqbase + 15); - device_add(machine, tmpstr); + snprintf(tmpstr, sizeof(tmpstr), "wdc addr=0x%llx irq=%s." + "isa.%i", (long long)(pd->pcibus->isa_portbase + 0x170), + pd->pcibus->irq_path_isa, 15); + ((struct piix_ide_extra *)pd->extra)->wdc1 = + device_add(machine, tmpstr); } + + pd->cfg_reg_write = piix_ide_cfg_reg_write; } @@ -823,6 +915,36 @@ PCI_BHLC_CODE(0,0, 1 /* multi-function */, 0x40,0)); } +/* + * Sandpoint host bridge based on uninorth + */ + +#define PCI_VENDOR_MOT 0x1057 +#define PCI_DEVICE_ID_MOTOROLA_MPC106 0x0002 +#define PCI_DEVICE_ID_MOTOROLA_MPC107 0x0004 + +PCIINIT(mpc10x) +{ + uint64_t port, memaddr; + + debug("sandpoint mpx10x host bridge\n"); + + PCI_SET_DATA(PCI_ID_REG, PCI_ID_CODE(PCI_VENDOR_MOT, + PCI_DEVICE_ID_MOTOROLA_MPC107)); /* FIXME MPC106 ?? */ + + PCI_SET_DATA(PCI_CLASS_REG, PCI_CLASS_CODE(PCI_CLASS_BRIDGE, + PCI_SUBCLASS_BRIDGE_HOST, 0) + 0x00); /* Revision? */ + + PCI_SET_DATA(PCI_BHLC_REG, + PCI_BHLC_CODE(0,0, 1 /* multi-function */, 0x40,0)); + + allocate_device_space(pd, 0x1000, 0, &port, &memaddr); + allocate_device_space(pd, 0x1000, 0, &port, &memaddr); + allocate_device_space(pd, 0x1000, 0, &port, &memaddr); + allocate_device_space(pd, 0x1000, 0, &port, &memaddr); + +} + /* @@ -852,6 +974,31 @@ PCI_BHLC_CODE(0,0, 1 /* multi-function */, 0x40,0)); } +struct vt82c586_ide_extra { + void *wdc0; + void *wdc1; +}; + +int vt82c586_ide_cfg_reg_write(struct pci_device *pd, int reg, uint32_t value) +{ + void *wdc0 = ((struct vt82c586_ide_extra *)pd->extra)->wdc0; + void *wdc1 = ((struct vt82c586_ide_extra *)pd->extra)->wdc1; + int enabled = 0; + + switch (reg) { + case PCI_COMMAND_STATUS_REG: + if (value & PCI_COMMAND_IO_ENABLE) + enabled = 1; + if (wdc0 != NULL) + wdc_set_io_enabled(wdc0, enabled); + if (wdc1 != NULL) + wdc_set_io_enabled(wdc1, enabled); + return 1; + } + + return 0; +} + PCIINIT(vt82c586_ide) { char tmpstr[100]; @@ -867,21 +1014,29 @@ /* channel 0 and 1 enabled */ PCI_SET_DATA(0x40, 0x00000003); + CHECK_ALLOCATION(pd->extra = malloc(sizeof(struct vt82c586_ide_extra))); + ((struct vt82c586_ide_extra *)pd->extra)->wdc0 = NULL; + ((struct vt82c586_ide_extra *)pd->extra)->wdc1 = NULL; + if (diskimage_exist(machine, 0, DISKIMAGE_IDE) || diskimage_exist(machine, 1, DISKIMAGE_IDE)) { - snprintf(tmpstr, sizeof(tmpstr), "wdc addr=0x%llx irq=%i", - (long long)(pd->pcibus->isa_portbase + 0x1f0), - pd->pcibus->isa_irqbase + 14); - device_add(machine, tmpstr); + snprintf(tmpstr, sizeof(tmpstr), "wdc addr=0x%llx irq=%s." + "isa.%i", (long long)(pd->pcibus->isa_portbase + 0x1f0), + pd->pcibus->irq_path_isa, 14); + ((struct vt82c586_ide_extra *)pd->extra)->wdc0 = + device_add(machine, tmpstr); } if (diskimage_exist(machine, 2, DISKIMAGE_IDE) || diskimage_exist(machine, 3, DISKIMAGE_IDE)) { - snprintf(tmpstr, sizeof(tmpstr), "wdc addr=0x%llx irq=%i", - (long long)(pd->pcibus->isa_portbase + 0x170), - pd->pcibus->isa_irqbase + 15); - device_add(machine, tmpstr); + snprintf(tmpstr, sizeof(tmpstr), "wdc addr=0x%llx irq=%s." + "isa.%i", (long long)(pd->pcibus->isa_portbase + 0x170), + pd->pcibus->irq_path_isa, 15); + ((struct vt82c586_ide_extra *)pd->extra)->wdc1 = + device_add(machine, tmpstr); } + + pd->cfg_reg_write = vt82c586_ide_cfg_reg_write; } @@ -905,6 +1060,53 @@ PCI_SET_DATA(PCI_BHLC_REG, PCI_BHLC_CODE(0,0, 1 /* multi-function */, 0x40,0)); + + switch (machine->machine_type) { + case MACHINE_NETWINDER: + bus_isa_init(machine, pd->pcibus->irq_path_isa, + 0, 0x7c000000, 0x80000000); + break; + default:fatal("symphony_83c553 init: unimplemented machine type\n"); + exit(1); + } +} + +struct symphony_82c105_extra { + void *wdc0; + void *wdc1; +}; + +int symphony_82c105_cfg_reg_write(struct pci_device *pd, int reg, + uint32_t value) +{ + void *wdc0 = ((struct symphony_82c105_extra *)pd->extra)->wdc0; + void *wdc1 = ((struct symphony_82c105_extra *)pd->extra)->wdc1; + int enabled = 0; + +printf("reg = 0x%x\n", reg); + switch (reg) { + case PCI_COMMAND_STATUS_REG: + if (value & PCI_COMMAND_IO_ENABLE) + enabled = 1; +printf(" value = 0x%"PRIx32"\n", value); + if (wdc0 != NULL) + wdc_set_io_enabled(wdc0, enabled); + if (wdc1 != NULL) + wdc_set_io_enabled(wdc1, enabled); + /* Set all bits: */ + PCI_SET_DATA(reg, value); + return 1; + case PCI_MAPREG_START: + case PCI_MAPREG_START + 4: + case PCI_MAPREG_START + 8: + case PCI_MAPREG_START + 12: + case PCI_MAPREG_START + 16: + case PCI_MAPREG_START + 20: + PCI_SET_DATA(reg, value); + return 1; + } + + return 0; } PCIINIT(symphony_82c105) @@ -918,25 +1120,82 @@ PCI_SET_DATA(PCI_CLASS_REG, PCI_CLASS_CODE(PCI_CLASS_MASS_STORAGE, PCI_SUBCLASS_MASS_STORAGE_IDE, 0x00) + 0x05); + /* TODO: Interrupt line: */ + /* PCI_SET_DATA(PCI_INTERRUPT_REG, 0x28140000); */ + /* APO_IDECONF */ /* channel 0 and 1 enabled */ PCI_SET_DATA(0x40, 0x00000003); + CHECK_ALLOCATION(pd->extra = + malloc(sizeof(struct symphony_82c105_extra))); + ((struct symphony_82c105_extra *)pd->extra)->wdc0 = NULL; + ((struct symphony_82c105_extra *)pd->extra)->wdc1 = NULL; + if (diskimage_exist(machine, 0, DISKIMAGE_IDE) || diskimage_exist(machine, 1, DISKIMAGE_IDE)) { - snprintf(tmpstr, sizeof(tmpstr), "wdc addr=0x%llx irq=%i", - (long long)(pd->pcibus->isa_portbase + 0x1f0), - pd->pcibus->isa_irqbase + 14); - device_add(machine, tmpstr); + snprintf(tmpstr, sizeof(tmpstr), "wdc addr=0x%llx irq=%s." + "isa.%i", (long long)(pd->pcibus->isa_portbase + 0x1f0), + pd->pcibus->irq_path_isa, 14); + ((struct symphony_82c105_extra *)pd->extra)->wdc0 = + device_add(machine, tmpstr); } if (diskimage_exist(machine, 2, DISKIMAGE_IDE) || diskimage_exist(machine, 3, DISKIMAGE_IDE)) { - snprintf(tmpstr, sizeof(tmpstr), "wdc addr=0x%llx irq=%i", - (long long)(pd->pcibus->isa_portbase + 0x170), - pd->pcibus->isa_irqbase + 15); - device_add(machine, tmpstr); + snprintf(tmpstr, sizeof(tmpstr), "wdc addr=0x%llx irq=%s." + "isa.%i", (long long)(pd->pcibus->isa_portbase + 0x170), + pd->pcibus->irq_path_isa, 15); + ((struct symphony_82c105_extra *)pd->extra)->wdc1 = + device_add(machine, tmpstr); } + + pd->cfg_reg_write = symphony_82c105_cfg_reg_write; +} + + + +/* + * Realtek 8139C+ PCI ethernet. + */ + +#define PCI_VENDOR_REALTEK 0x10ec +#define PCI_PRODUCT_REALTEK_RT8139 0x8139 + +PCIINIT(rtl8139c) +{ + uint64_t port, memaddr; + int pci_int_line = 0x101, irq = 0; + char irqstr[200]; + char tmpstr[200]; + + PCI_SET_DATA(PCI_ID_REG, PCI_ID_CODE(PCI_VENDOR_REALTEK, + PCI_PRODUCT_REALTEK_RT8139)); + + PCI_SET_DATA(PCI_CLASS_REG, PCI_CLASS_CODE(PCI_CLASS_NETWORK, + PCI_SUBCLASS_NETWORK_ETHERNET, 0x00) + 0x20); + + switch (machine->machine_type) { + case MACHINE_LANDISK: + irq = 5; + pci_int_line = 0x105; + break; + default:fatal("rtl8139c for this machine has not been " + "implemented yet\n"); + exit(1); + } + + PCI_SET_DATA(PCI_INTERRUPT_REG, 0x28140000 | pci_int_line); + + allocate_device_space(pd, 0x100, 0, &port, &memaddr); + + snprintf(irqstr, sizeof(irqstr), "%s.%i", + pd->pcibus->irq_path_pci, irq); + + snprintf(tmpstr, sizeof(tmpstr), "rtl8139c addr=0x%llx " + "irq=%s pci_little_endian=1", (long long)port, irqstr); + + device_add(machine, tmpstr); } @@ -951,8 +1210,8 @@ PCIINIT(dec21143) { uint64_t port, memaddr; - int irq = 0; /* TODO */ - int pci_int_line = 0x101; + int pci_int_line = 0x101, irq = 0, isa = 0; + char irqstr[200]; char tmpstr[200]; PCI_SET_DATA(PCI_ID_REG, PCI_ID_CODE(PCI_VENDOR_DEC, @@ -976,24 +1235,20 @@ irq = 8 + 7; pci_int_line = 0x407; break; - case MACHINE_ALGOR: - /* TODO */ - irq = 8 + 7; - pci_int_line = 0x407; - break; case MACHINE_PREP: - irq = 32 + 10; + irq = 10; + isa = 1; pci_int_line = 0x20a; break; case MACHINE_MVMEPPC: /* TODO */ - irq = 32 + 10; + irq = 10; pci_int_line = 0x40a; break; case MACHINE_PMPPC: /* TODO, not working yet */ - irq = 31 - 21; - pci_int_line = 0x201; + irq = 31 - CPC_IB_EXT1; + pci_int_line = 0x101; break; case MACHINE_MACPPC: /* TODO, not working yet */ @@ -1006,9 +1261,17 @@ allocate_device_space(pd, 0x100, 0x100, &port, &memaddr); + if (isa) + snprintf(irqstr, sizeof(irqstr), "%s.isa.%i", + pd->pcibus->irq_path_isa, irq); + else + snprintf(irqstr, sizeof(irqstr), "%s.%i", + pd->pcibus->irq_path_pci, irq); + snprintf(tmpstr, sizeof(tmpstr), "dec21143 addr=0x%llx addr2=0x%llx " - "irq=%i pci_little_endian=1", (long long)port, (long long)memaddr, - irq); + "irq=%s pci_little_endian=1", (long long)port, + (long long)memaddr, irqstr); + device_add(machine, tmpstr); }