From 463ee8f95c95e077806d5c838b114135ed3b7922 Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Sat, 14 Oct 2023 13:25:39 +0200 Subject: parisc/c3700: Add support for C3700 workstation with Astro/Elroy Major changes to support 64-bit machines with Astro and Elroy chips. This patch adds support for the C3700 workstation. Changes include: - Detect if the emulated CPU runs as 32-bit PA1.x or 64-bit PA2.x CPU - Add support for Astro and Elroy chips: * build interrupt routing table (IRT) * add PCI irq to pci_device struct - Enhance PCI bus scanning * Add support for various PCI cards (serial, USB, graphics, ...) - Change PCI I/O accessor functions: * readX()/writeX() do byteswapping and take an ioremapped address * __raw_readX()/__raw_writeX() don't byteswap and take an ioremapped address. * gsc_*() don't byteswap and operate on physical addresses Signed-off-by: Helge Deller --- src/boot.c | 6 +- src/fw/pciinit.c | 81 +++- src/hw/pci.c | 67 +++ src/hw/pcidevice.c | 5 +- src/hw/pcidevice.h | 1 + src/parisc/b160l.h | 4 +- src/parisc/c3700.h | 285 +++++++++++++ src/parisc/hppa.h | 67 ++- src/parisc/hppa_hardware.h | 26 +- src/parisc/lasips2.c | 11 +- src/parisc/machine-create.h | 20 + src/parisc/parisc.c | 986 ++++++++++++++++++++++++++++++++++---------- src/parisc/pdc.h | 39 +- src/parisc/stirom.c | 2 +- 14 files changed, 1339 insertions(+), 261 deletions(-) create mode 100644 src/parisc/c3700.h create mode 100644 src/parisc/machine-create.h diff --git a/src/boot.c b/src/boot.c index 3d7f092..cf1b2fe 100644 --- a/src/boot.c +++ b/src/boot.c @@ -50,7 +50,7 @@ glob_prefix(const char *glob, const char *str) } #if CONFIG_PARISC -#define FW_PCI_DOMAIN "/dino-pcihost" +#define FW_PCI_DOMAIN (has_astro ? "/elroy-pcihost" : "/dino-pcihost") #else #define FW_PCI_DOMAIN "/pci@i0cf8" #endif @@ -178,7 +178,7 @@ loadBiosGeometry(void) static BootDeviceLCHS * boot_lchs_find(const char *glob) { - dprintf(1, "Searching bios-geometry for: %s\n", glob); + // dprintf(1, "Searching bios-geometry for: %s\n", glob); int i; for (i = 0; i < BiosGeometryCount; i++) if (glob_prefix(glob, BiosGeometry[i].name)) @@ -291,7 +291,7 @@ loadBootOrder(void) static int find_prio(const char *glob) { - dprintf(1, "Searching bootorder for: %s\n", glob); + // dprintf(1, "Searching bootorder for: %s\n", glob); int i; for (i = 0; i < BootorderCount; i++) if (glob_prefix(glob, Bootorder[i])) diff --git a/src/fw/pciinit.c b/src/fw/pciinit.c index 4c16ea0..d79fb56 100644 --- a/src/fw/pciinit.c +++ b/src/fw/pciinit.c @@ -509,6 +509,12 @@ static void mch_mem_addr_setup(struct pci_device *dev, void *arg) pci_io_low_end = acpi_pm_base; } +/* + * parisc: If mmio bar is bigger than this size, map the bar it into the + * directed ELMMIO instead of the distributed LMMIO region. + */ +#define PARISC_MMIO_LIMIT 0x10000 + #if CONFIG_PARISC static int dino_pci_slot_get_irq(struct pci_device *pci, int pin) { @@ -536,8 +542,64 @@ static void dino_mem_addr_setup(struct pci_device *dev, void *arg) /* setup io address space */ pci_io_low_end = 0xa000; } + +static int astro_pci_slot_get_irq(struct pci_device *pci, int pin) +{ + int bus = pci_bdf_to_bus(pci->bdf); + int slot = pci_bdf_to_dev(pci->bdf); + return (bus + 1) * 4 + (slot & 0x03); +} + +static void astro_mem_addr_setup(struct pci_device *dev, void *arg) +{ + pcimem_start = LMMIO_DIST_BASE_ADDR; + pcimem_end = pcimem_start + LMMIO_DIST_BASE_SIZE / ROPES_PER_IOC; + + MaxPCIBus = 4; + pci_slot_get_irq = astro_pci_slot_get_irq; + + /* setup io address space */ + pci_io_low_end = IOS_DIST_BASE_SIZE / ROPES_PER_IOC; +} + +static void parisc_mem_addr_setup(struct pci_device *dev, void *arg) +{ + if (has_astro) + return astro_mem_addr_setup(dev, arg); + else + return dino_mem_addr_setup(dev, arg); +} #endif /* CONFIG_PARISC */ +static unsigned long add_lmmio_directed_range(unsigned long size, int rope) +{ +#ifdef CONFIG_PARISC + int i; + + /* Astro has 4 directed ranges. */ + for (i = 0; i < 4; i++) { + unsigned long addr; + void *reg = (void *)(unsigned long) (ASTRO_BASE_HPA + i * 0x18); + + addr = readl(reg + LMMIO_DIRECT0_BASE); + if (addr & 1) + continue; /* already used */ + + /* fixme for multiple addresses */ + /* Linux driver currently only allows one distr. range per IOC */ + addr = 0xfa000000; /* graphics card area for parisc, f8 is used by artist */ + addr += i * 0x02000000; + + writel(reg + LMMIO_DIRECT0_BASE, addr | 1); + writel(reg + LMMIO_DIRECT0_ROUTE, rope & (ROPES_PER_IOC - 1)); + size = 0xfff8000000 | ~(size-1); /* is -1 correct? */ + // dprintf(1, "use addr %lx size %lx\n", addr|1, size); + writel(reg + LMMIO_DIRECT0_MASK, size); + return addr; + } +#endif /* CONFIG_PARISC */ + return -1UL; +} static const struct pci_device_id pci_platform_tbl[] = { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82441, @@ -558,7 +620,7 @@ static void pci_bios_init_platform(void) } #if CONFIG_PARISC - dino_mem_addr_setup(NULL, NULL); + parisc_mem_addr_setup(NULL, NULL); #endif } @@ -608,7 +670,7 @@ pci_bios_init_bus_rec(int bus, u8 *pci_bus) int bdf; u16 class; - dprintf(1, "PCI: %s bus = 0x%x\n", __func__, bus); + // dprintf(1, "PCI: %s bus = 0x%x\n", __func__, bus); /* prevent accidental access to unintended devices */ foreachbdf(bdf, bus) { @@ -785,7 +847,8 @@ static u64 pci_region_sum(struct pci_region *r) u64 sum = 0; struct pci_region_entry *entry; hlist_for_each_entry(entry, &r->list, node) { - sum += entry->size; + if (entry->size <= PARISC_MMIO_LIMIT && CONFIG_PARISC) + sum += entry->size; } return sum; } @@ -900,7 +963,7 @@ static int pci_bios_check_devices(struct pci_bus *busses) busses[pci->secondary_bus].bus_dev = pci; struct pci_bus *bus = &busses[pci_bdf_to_bus(pci->bdf)]; - if (!bus->bus_dev) + if (!bus->bus_dev && !CONFIG_PARISC) /* * Resources for all root busses go in busses[0] */ @@ -1095,6 +1158,8 @@ pci_region_map_one_entry(struct pci_region_entry *entry, u64 addr) u16 bdf = entry->dev->bdf; u64 limit = addr + entry->size - 1; + if (!entry->size) + return; if (entry->type == PCI_REGION_TYPE_IO) { pci_config_writeb(bdf, PCI_IO_BASE, addr >> PCI_IO_SHIFT); pci_config_writew(bdf, PCI_IO_BASE_UPPER16, 0); @@ -1119,7 +1184,13 @@ static void pci_region_map_entries(struct pci_bus *busses, struct pci_region *r) struct pci_region_entry *entry; hlist_for_each_entry_safe(entry, n, &r->list, node) { u64 addr = r->base; - r->base += entry->size; + if (entry->size <= PARISC_MMIO_LIMIT && CONFIG_PARISC) + r->base += entry->size; + else { + addr = add_lmmio_directed_range(entry->size, 0); + if (addr == -1UL) + hlt(); + } if (entry->bar == -1) // Update bus base address if entry is a bridge region busses[entry->dev->secondary_bus].r[entry->type].base = addr; diff --git a/src/hw/pci.c b/src/hw/pci.c index ecc724b..3f35250 100644 --- a/src/hw/pci.c +++ b/src/hw/pci.c @@ -31,8 +31,40 @@ static u32 ioconfig_cmd(u16 bdf, u32 addr) return 0x80000000 | (bdf << 8) | (addr & 0xfc); } +/* + * Memory mapped I/O + * + * readX()/writeX() do byteswapping and take an ioremapped address + * __raw_readX()/__raw_writeX() don't byteswap and take an ioremapped address. + * gsc_*() don't byteswap and operate on physical addresses; + * eg dev->hpa or 0xfee00000. + */ + +/* each elroy has 0x2000 offset */ +#define ELROY_MAX_BUSSES 4 +unsigned long elroy_offset(u16 bdf) +{ + static const int elroy_hpa_offsets[ELROY_MAX_BUSSES] = { 0x30000, 0x32000, 0x38000, 0x3c000 }; + int bus = pci_bdf_to_bus(bdf); + if (bus >= ELROY_MAX_BUSSES) + return -1UL; + return elroy_hpa_offsets[bus] - elroy_hpa_offsets[0]; +} + +void *elroy_port(unsigned long port, unsigned long offs) +{ + return (void *)(port + offs); +} + void pci_config_writel(u16 bdf, u32 addr, u32 val) { + if (has_astro) { + unsigned long offs = elroy_offset(bdf); + if (offs == -1UL) + return; + writel(elroy_port(PORT_PCI_CMD, offs), ioconfig_cmd((u8)bdf, addr)); + writel(elroy_port(PORT_PCI_DATA, offs), val); + } else if (!MODESEGMENT && mmconfig) { writel(mmconfig_addr(bdf, addr), val); } else { @@ -43,6 +75,13 @@ void pci_config_writel(u16 bdf, u32 addr, u32 val) void pci_config_writew(u16 bdf, u32 addr, u16 val) { + if (has_astro) { + unsigned long offs = elroy_offset(bdf); + if (offs == -1UL) + return; + writel(elroy_port(PORT_PCI_CMD, offs), ioconfig_cmd((u8)bdf, addr)); + writew(elroy_port(PORT_PCI_DATA + (addr & 2), offs), val); + } else if (!MODESEGMENT && mmconfig) { writew(mmconfig_addr(bdf, addr), val); } else { @@ -53,6 +92,13 @@ void pci_config_writew(u16 bdf, u32 addr, u16 val) void pci_config_writeb(u16 bdf, u32 addr, u8 val) { + if (has_astro) { + unsigned long offs = elroy_offset(bdf); + if (offs == -1UL) + return; + writel(elroy_port(PORT_PCI_CMD, offs), ioconfig_cmd((u8)bdf, addr)); + writeb(elroy_port(PORT_PCI_DATA + (addr & 3), offs), val); + } else if (!MODESEGMENT && mmconfig) { writeb(mmconfig_addr(bdf, addr), val); } else { @@ -63,6 +109,13 @@ void pci_config_writeb(u16 bdf, u32 addr, u8 val) u32 pci_config_readl(u16 bdf, u32 addr) { + if (has_astro) { + unsigned long offs = elroy_offset(bdf); + if (offs == -1UL) + return -1; + writel(elroy_port(PORT_PCI_CMD, offs), ioconfig_cmd((u8)bdf, addr)); + return readl(elroy_port(PORT_PCI_DATA, offs)); + } else if (!MODESEGMENT && mmconfig) { return readl(mmconfig_addr(bdf, addr)); } else { @@ -73,6 +126,13 @@ u32 pci_config_readl(u16 bdf, u32 addr) u16 pci_config_readw(u16 bdf, u32 addr) { + if (has_astro) { + unsigned long offs = elroy_offset(bdf); + if (offs == -1UL) + return -1; + writel(elroy_port(PORT_PCI_CMD, offs), ioconfig_cmd((u8)bdf, addr)); + return readw(elroy_port(PORT_PCI_DATA + (addr & 2), offs)); + } else if (!MODESEGMENT && mmconfig) { return readw(mmconfig_addr(bdf, addr)); } else { @@ -83,6 +143,13 @@ u16 pci_config_readw(u16 bdf, u32 addr) u8 pci_config_readb(u16 bdf, u32 addr) { + if (has_astro) { + unsigned long offs = elroy_offset(bdf); + if (offs == -1UL) + return -1; + writel(elroy_port(PORT_PCI_CMD, offs), ioconfig_cmd((u8)bdf, addr)); + return readb(elroy_port(PORT_PCI_DATA + (addr & 3), offs)); + } else if (!MODESEGMENT && mmconfig) { return readb(mmconfig_addr(bdf, addr)); } else { diff --git a/src/hw/pcidevice.c b/src/hw/pcidevice.c index 8853cf7..ed3e15d 100644 --- a/src/hw/pcidevice.c +++ b/src/hw/pcidevice.c @@ -66,6 +66,7 @@ pci_probe_devices(void) dev->class = classrev >> 16; dev->prog_if = classrev >> 8; dev->revision = classrev & 0xff; + dev->irq = pci_config_readb(bdf, PCI_INTERRUPT_PIN); dev->header_type = pci_config_readb(bdf, PCI_HEADER_TYPE); u8 v = dev->header_type & 0x7f; if (v == PCI_HEADER_TYPE_BRIDGE || v == PCI_HEADER_TYPE_CARDBUS) { @@ -76,8 +77,8 @@ pci_probe_devices(void) if (secbus > MaxPCIBus) MaxPCIBus = secbus; } - dprintf(4, "PCI device %pP (vd=%04x:%04x c=%04x)\n" - , dev, dev->vendor, dev->device, dev->class); + dprintf(4, "PCI device %pP (vd=%04x:%04x c=%04x, irq=%d)\n" + , dev, dev->vendor, dev->device, dev->class, dev->irq); } } dprintf(1, "Found %d PCI devices (max PCI bus is %02x)\n", count, MaxPCIBus); diff --git a/src/hw/pcidevice.h b/src/hw/pcidevice.h index 225d545..eb3de39 100644 --- a/src/hw/pcidevice.h +++ b/src/hw/pcidevice.h @@ -16,6 +16,7 @@ struct pci_device { u8 prog_if, revision; u8 header_type; u8 secondary_bus; + u8 irq; // Local information on device. int have_driver; diff --git a/src/parisc/b160l.h b/src/parisc/b160l.h index 0e057fa..1899590 100644 --- a/src/parisc/b160l.h +++ b/src/parisc/b160l.h @@ -464,7 +464,7 @@ static struct pdc_iodc iodc_data_hpa_fff10000 = { #define HPA_fffbf000_DESCRIPTION "Memory" static struct pdc_system_map_mod_info mod_info_hpa_fffbf000 = { - .mod_addr = 0xfffbf000, + .mod_addr = MEMORY_HPA, .mod_pgs = 0x1, .add_addrs = 0x0, }; @@ -615,7 +615,7 @@ static struct pdc_iodc iodc_data_hpa_fff81000 = { .mod_path = &mod_path_hpa_fff10000,\ .num_addr = HPA_fff10000_num_addr,\ .add_addr = { HPA_fff10000_add_addr } },\ - { .hpa = 0xfffbf000,\ + { .hpa = MEMORY_HPA,\ .iodc = &iodc_data_hpa_fffbf000,\ .mod_info = &mod_info_hpa_fffbf000,\ .mod_path = &mod_path_hpa_fffbf000,\ diff --git a/src/parisc/c3700.h b/src/parisc/c3700.h new file mode 100644 index 0000000..2c1862a --- /dev/null +++ b/src/parisc/c3700.h @@ -0,0 +1,285 @@ +/* AUTO-GENERATED HEADER FILE FOR SEABIOS FIRMWARE */ +/* generated with Linux kernel */ +/* search for PARISC_QEMU_MACHINE_HEADER in Linux */ + +#define PARISC_MODEL "9000/785/C3700" + +#define PARISC_PDC_MODEL 0x5dc0, 0x481, 0x0, 0x2, 0x777c3e84, 0x100000f0, 0x8, 0xb2, 0xb2 + +#define PARISC_PDC_VERSION 0x0301 + +#define PARISC_PDC_CPUID 0x01e8 + +#define PARISC_PDC_CAPABILITIES 0x0007 + +#define PARISC_PDC_ENTRY_ORG 0xf0000018 + +#define PARISC_PDC_CACHE_INFO \ + 0xc0000, 0x91802000, 0x20000, 0x0040, 0x0c00 \ + , 0x0001, 0x180000, 0xb1802000, 0x0000, 0x0040 \ + , 0x6000, 0x0001, 0x00f0, 0xd2300, 0x0000 \ + , 0x0000, 0x0001, 0x0000, 0x0000, 0x0001 \ + , 0x0001, 0x00f0, 0xd2000, 0x0000, 0x0000 \ + , 0x0001, 0x0000, 0x0000, 0x0001, 0x0001 + + +#define HPA_fed00000_DESCRIPTION "Astro BC Runway Port" +static struct pdc_system_map_mod_info mod_info_hpa_fed00000 = { + .mod_addr = 0xfed00000, + .mod_pgs = 0x8, + .add_addrs = 0x0, +}; +static struct pdc_module_path mod_path_hpa_fed00000 = { + .path = { .flags = 0x0, .bc = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }, .mod = ASTRO_BUS_MODULE }, + .layers = { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 } +}; +static struct pdc_iodc iodc_data_hpa_fed00000 = { + .hversion_model = 0x0058, + .hversion = 0x0020, + .spa = 0x0000, + .type = 0x000c, + .sversion_rev = 0x0000, + .sversion_model = 0x0005, + .sversion_opt = 0x0088, + .rev = 0x0000, + .dep = 0x0000, + .features = 0x0000, + .checksum = 0x0000, + .length = 0x0000, + /* pad: 0x0000, 0x0000 */ +}; +#define HPA_fed00000_num_addr 0 +#define HPA_fed00000_add_addr 0 + + +#define HPA_fed30000_DESCRIPTION "Elroy PCI Bridge" +static struct pdc_system_map_mod_info mod_info_hpa_fed30000 = { + .mod_addr = 0xfed30000, + .mod_pgs = 0x2, + .add_addrs = 0x0, +}; +static struct pdc_module_path mod_path_hpa_fed30000 = { + .path = { .flags = 0x0, .bc = { 0xff, 0xff, 0xff, 0xff, 0xff, ASTRO_BUS_MODULE }, .mod = 0x0 }, + .layers = { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 } +}; +static struct pdc_iodc iodc_data_hpa_fed30000 = { + .hversion_model = 0x0078, + .hversion = 0x0020, + .spa = 0x0000, + .type = 0x000d, + .sversion_rev = 0x0000, + .sversion_model = 0x0005, + .sversion_opt = 0x0000, + .rev = 0x0000, + .dep = 0x0000, + .features = 0x0000, + .checksum = 0x0000, + .length = 0x0000, + /* pad: 0x0000, 0x0000 */ +}; +#define HPA_fed30000_num_addr 0 +#define HPA_fed30000_add_addr 0 + + +#define HPA_fed32000_DESCRIPTION "Elroy PCI Bridge" +static struct pdc_system_map_mod_info mod_info_hpa_fed32000 = { + .mod_addr = 0xfed32000, + .mod_pgs = 0x2, + .add_addrs = 0x0, +}; +static struct pdc_module_path mod_path_hpa_fed32000 = { + .path = { .flags = 0x0, .bc = { 0xff, 0xff, 0xff, 0xff, 0xff, ASTRO_BUS_MODULE }, .mod = 0x1 }, + .layers = { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 } +}; +static struct pdc_iodc iodc_data_hpa_fed32000 = { + .hversion_model = 0x0078, + .hversion = 0x0020, + .spa = 0x0000, + .type = 0x000d, + .sversion_rev = 0x0000, + .sversion_model = 0x0005, + .sversion_opt = 0x0000, + .rev = 0x0000, + .dep = 0x0000, + .features = 0x0000, + .checksum = 0x0000, + .length = 0x0000, + /* pad: 0x0000, 0x0000 */ +}; +#define HPA_fed32000_num_addr 0 +#define HPA_fed32000_add_addr 0 + + +#define HPA_fed38000_DESCRIPTION "Elroy PCI Bridge" +static struct pdc_system_map_mod_info mod_info_hpa_fed38000 = { + .mod_addr = 0xfed38000, + .mod_pgs = 0x2, + .add_addrs = 0x0, +}; +static struct pdc_module_path mod_path_hpa_fed38000 = { + .path = { .flags = 0x0, .bc = { 0xff, 0xff, 0xff, 0xff, 0xff, ASTRO_BUS_MODULE }, .mod = 0x4 }, + .layers = { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 } +}; +static struct pdc_iodc iodc_data_hpa_fed38000 = { + .hversion_model = 0x0078, + .hversion = 0x0020, + .spa = 0x0000, + .type = 0x000d, + .sversion_rev = 0x0000, + .sversion_model = 0x0005, + .sversion_opt = 0x0000, + .rev = 0x0000, + .dep = 0x0000, + .features = 0x0000, + .checksum = 0x0000, + .length = 0x0000, + /* pad: 0x0000, 0x0000 */ +}; +#define HPA_fed38000_num_addr 0 +#define HPA_fed38000_add_addr 0 + + +#define HPA_fed3c000_DESCRIPTION "Elroy PCI Bridge" +static struct pdc_system_map_mod_info mod_info_hpa_fed3c000 = { + .mod_addr = 0xfed3c000, + .mod_pgs = 0x2, + .add_addrs = 0x0, +}; +static struct pdc_module_path mod_path_hpa_fed3c000 = { + .path = { .flags = 0x0, .bc = { 0xff, 0xff, 0xff, 0xff, 0xff, ASTRO_BUS_MODULE }, .mod = 0x6 }, + .layers = { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 } +}; +static struct pdc_iodc iodc_data_hpa_fed3c000 = { + .hversion_model = 0x0078, + .hversion = 0x0020, + .spa = 0x0000, + .type = 0x000d, + .sversion_rev = 0x0000, + .sversion_model = 0x0005, + .sversion_opt = 0x0000, + .rev = 0x0000, + .dep = 0x0000, + .features = 0x0000, + .checksum = 0x0000, + .length = 0x0000, + /* pad: 0x0000, 0x0000 */ +}; +#define HPA_fed3c000_num_addr 0 +#define HPA_fed3c000_add_addr 0 + + +#define HPA_fffa0000_DESCRIPTION "Allegro W2" +static struct pdc_system_map_mod_info mod_info_hpa_fffa0000 = { + .mod_addr = CPU_HPA /* 0xfffa0000 */, + .mod_pgs = 0x1, + .add_addrs = 0x0, +}; +static struct pdc_module_path mod_path_hpa_fffa0000 = { + .path = { .flags = 0x0, .bc = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }, .mod = 0x10 }, + .layers = { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 } +}; +static struct pdc_iodc iodc_data_hpa_fffa0000 = { +#if 1 // original C3700: + .hversion_model = 0x005d, + .hversion = 0x00c0, // C3700: c0, B160: 20 +#else + /* this is from B160L */ + .hversion_model = 0x0050, + .hversion = 0x0020, +#endif + .spa = 0x0000, + .type = 0x0040, + .sversion_rev = 0x0000, + .sversion_model = 0x0002, + .sversion_opt = 0x0040, + .rev = 0x0000, + .dep = 0x0000, + .features = 0x0000, + .checksum = 0x0000, + .length = 0x0000, + /* pad: 0x0000, 0x0000 */ +}; +#define HPA_fffa0000_num_addr 0 +#define HPA_fffa0000_add_addr 0 + + +#define HPA_fed10200_DESCRIPTION "Memory" +static struct pdc_system_map_mod_info mod_info_hpa_fed10200 = { + .mod_addr = 0xfed10200, + .mod_pgs = 0x8, + .add_addrs = 0x0, +}; +static struct pdc_module_path mod_path_hpa_fed10200 = { + .path = { .flags = 0x0, .bc = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }, .mod = 0x2f }, + .layers = { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 } +}; +static struct pdc_iodc iodc_data_hpa_fed10200 = { + .hversion_model = 0x0009, + .hversion = 0x00c0, + .spa = 0x001f, + .type = 0x0041, + .sversion_rev = 0x0000, + .sversion_model = 0x0004, + .sversion_opt = 0x0080, + .rev = 0x0000, + .dep = 0x0000, + .features = 0x0000, + .checksum = 0x0000, + .length = 0x0000, + /* pad: 0x0000, 0x0000 */ +}; +#define HPA_fed10200_num_addr 0 +#define HPA_fed10200_add_addr 0 + + + +#define PARISC_DEVICE_LIST \ + { .hpa = 0xfed00000,\ + .iodc = &iodc_data_hpa_fed00000,\ + .mod_info = &mod_info_hpa_fed00000,\ + .mod_path = &mod_path_hpa_fed00000,\ + .num_addr = HPA_fed00000_num_addr,\ + .add_addr = { HPA_fed00000_add_addr } },\ + { .hpa = 0xfed30000,\ + .iodc = &iodc_data_hpa_fed30000,\ + .mod_info = &mod_info_hpa_fed30000,\ + .mod_path = &mod_path_hpa_fed30000,\ + .num_addr = HPA_fed30000_num_addr,\ + .add_addr = { HPA_fed30000_add_addr } },\ + { .hpa = 0xfed32000,\ + .iodc = &iodc_data_hpa_fed32000,\ + .mod_info = &mod_info_hpa_fed32000,\ + .mod_path = &mod_path_hpa_fed32000,\ + .num_addr = HPA_fed32000_num_addr,\ + .add_addr = { HPA_fed32000_add_addr } },\ + { .hpa = 0xfed38000,\ + .iodc = &iodc_data_hpa_fed38000,\ + .mod_info = &mod_info_hpa_fed38000,\ + .mod_path = &mod_path_hpa_fed38000,\ + .num_addr = HPA_fed38000_num_addr,\ + .add_addr = { HPA_fed38000_add_addr } },\ + { .hpa = 0xfed3c000,\ + .iodc = &iodc_data_hpa_fed3c000,\ + .mod_info = &mod_info_hpa_fed3c000,\ + .mod_path = &mod_path_hpa_fed3c000,\ + .num_addr = HPA_fed3c000_num_addr,\ + .add_addr = { HPA_fed3c000_add_addr } },\ + { .hpa = 0xfed10200,\ + .iodc = &iodc_data_hpa_fed10200,\ + .mod_info = &mod_info_hpa_fed10200,\ + .mod_path = &mod_path_hpa_fed10200,\ + .num_addr = HPA_fed10200_num_addr,\ + .add_addr = { HPA_fed10200_add_addr } },\ + { .hpa = 0xf8000000, /* HACKED IN: Coral GSC graphics */ \ + .iodc = &iodc_data_hpa_f8000000,\ + .mod_info = &mod_info_hpa_f8000000,\ + .mod_path = &mod_path_hpa_f8000000,\ + .num_addr = HPA_f8000000_num_addr,\ + .add_addr = { HPA_f8000000_add_addr } },\ + { .hpa = CPU_HPA /* XXX: 0xfffa0000 */ ,\ + .iodc = &iodc_data_hpa_fffa0000,\ + .mod_info = &mod_info_hpa_fffa0000,\ + .mod_path = &mod_path_hpa_fffa0000,\ + .num_addr = HPA_fffa0000_num_addr,\ + .add_addr = { HPA_fffa0000_add_addr } },\ + { 0, } diff --git a/src/parisc/hppa.h b/src/parisc/hppa.h index 0ac0992..036141b 100644 --- a/src/parisc/hppa.h +++ b/src/parisc/hppa.h @@ -14,7 +14,7 @@ #include "byteorder.h" // le16_to_cpu /* Pointer to zero-page of PA-RISC */ -#define PAGE0 ((volatile struct zeropage *) 0UL) +#define PAGE0 ((struct zeropage *) 0UL) #define PSW_I 0x00000001 @@ -204,9 +204,20 @@ static inline u32 ror(u32 word, unsigned int shift) return (word >> (shift & 31)) | (word << ((-shift) & 31)); } +extern char has_astro; /* false for B160L machine with Dino PCI chip */ +extern unsigned long hppa_port_pci_cmd; +extern unsigned long hppa_port_pci_data; + + #define pci_ioport_addr(port) ((port >= 0x1000) && (port < FIRMWARE_START)) +#define is_astro_ioport(port) (has_astro && (port < IOS_DIST_BASE_SIZE)) + +#define astro_ioport_addr(port) ((void *)(portaddr_t)(IOS_DIST_BASE_ADDR + port)) static inline void outl(u32 value, portaddr_t port) { + if (is_astro_ioport(port)) + *(volatile u32 *)(astro_ioport_addr(port)) = value; + else if (!pci_ioport_addr(port)) { *(volatile u32 *)(port) = be32_to_cpu(value); } else { @@ -218,6 +229,9 @@ static inline void outl(u32 value, portaddr_t port) { } static inline void outw(u16 value, portaddr_t port) { + if (is_astro_ioport(port)) + *(volatile u16 *)(astro_ioport_addr(port)) = value; + else if (!pci_ioport_addr(port)) { *(volatile u16 *)(port) = be16_to_cpu(value); } else { @@ -229,6 +243,9 @@ static inline void outw(u16 value, portaddr_t port) { } static inline void outb(u8 value, portaddr_t port) { + if (is_astro_ioport(port)) + *(volatile u8 *)(astro_ioport_addr(port)) = value; + else if (!pci_ioport_addr(port)) { *(volatile u8 *)(port) = value; } else { @@ -240,7 +257,10 @@ static inline void outb(u8 value, portaddr_t port) { } static inline u8 inb(portaddr_t port) { - if (!pci_ioport_addr(port)) { + if (is_astro_ioport(port)) + return *(volatile u8 *)(astro_ioport_addr(port)); + else + if (has_astro || !pci_ioport_addr(port)) { return *(volatile u8 *)(port); } else { /* write PCI I/O address to Dino's PCI_CONFIG_ADDR */ @@ -251,6 +271,9 @@ static inline u8 inb(portaddr_t port) { } static inline u16 inw(portaddr_t port) { + if (is_astro_ioport(port)) + return *(volatile u16 *)(astro_ioport_addr(port)); + else if (!pci_ioport_addr(port)) { return *(volatile u16 *)(port); } else { @@ -261,6 +284,9 @@ static inline u16 inw(portaddr_t port) { } } static inline u32 inl(portaddr_t port) { + if (is_astro_ioport(port)) + return *(volatile u32 *)(astro_ioport_addr(port)); + else if (!pci_ioport_addr(port)) { return *(volatile u32 *)(port); } else { @@ -321,13 +347,15 @@ static inline void smp_wmb(void) { barrier(); } +/* readX()/writeX() do byteswapping */ + static inline void writel(void *addr, u32 val) { barrier(); - *(volatile u32 *)addr = val; + *(volatile u32 *)addr = cpu_to_le32(val); } static inline void writew(void *addr, u16 val) { barrier(); - *(volatile u16 *)addr = val; + *(volatile u16 *)addr = cpu_to_le16(val); } static inline void writeb(void *addr, u8 val) { barrier(); @@ -336,17 +364,17 @@ static inline void writeb(void *addr, u8 val) { static inline u64 readq(const void *addr) { u64 val = *(volatile const u64 *)addr; barrier(); - return val; + return le64_to_cpu(val); } static inline u32 readl(const void *addr) { u32 val = *(volatile const u32 *)addr; barrier(); - return val; + return le32_to_cpu(val); } static inline u16 readw(const void *addr) { u16 val = *(volatile const u16 *)addr; barrier(); - return val; + return le16_to_cpu(val); } static inline u8 readb(const void *addr) { u8 val = *(volatile const u8 *)addr; @@ -354,6 +382,27 @@ static inline u8 readb(const void *addr) { return val; } +/* gsc_readX()/gsc_writeX() do no byteswapping */ + +static inline void gsc_writel(void *addr, u32 val) { + barrier(); + *(volatile u32 *)addr = val; +} +static inline void gsc_writeb(void *addr, u8 val) { + barrier(); + *(volatile u8 *)addr = val; +} +static inline u32 gsc_readl(const void *addr) { + u32 val = *(volatile const u32 *)addr; + barrier(); + return val; +} +static inline u8 gsc_readb(const void *addr) { + u8 val = *(volatile const u8 *)addr; + barrier(); + return val; +} + // FLASH_FLOPPY not supported #define GDT_CODE (0) #define GDT_DATA (0) @@ -378,5 +427,9 @@ static inline void wrmsr(u32 index, u64 val) // x86.c void cpuid(u32 index, u32 *eax, u32 *ebx, u32 *ecx, u32 *edx); +// pci.c +unsigned long elroy_offset(u16 bdf); +void *elroy_port(unsigned long port, unsigned long offs); + #endif // !__ASSEMBLY__ #endif diff --git a/src/parisc/hppa_hardware.h b/src/parisc/hppa_hardware.h index c036d46..cc6b261 100644 --- a/src/parisc/hppa_hardware.h +++ b/src/parisc/hppa_hardware.h @@ -28,16 +28,15 @@ #define CPU_HPA 0xfffb0000 #define MEMORY_HPA 0xfffff000 -#define PCI_HPA DINO_HPA /* PCI bus */ -#define IDE_HPA 0xf9000000 /* Boot disc controller */ +#define SCSI_HPA 0xf1040000 /* emulated SCSI, needs to be in f region */ /* offsets to DINO HPA: */ #define DINO_PCI_ADDR 0x064 #define DINO_CONFIG_DATA 0x068 #define DINO_IO_DATA 0x06c -#define PORT_PCI_CMD (PCI_HPA + DINO_PCI_ADDR) -#define PORT_PCI_DATA (PCI_HPA + DINO_CONFIG_DATA) +#define PORT_PCI_CMD hppa_port_pci_cmd +#define PORT_PCI_DATA hppa_port_pci_data #define FW_CFG_IO_BASE 0xfffa0000 @@ -50,4 +49,23 @@ #define CPU_HPA_CR_REG 7 /* store CPU HPA in cr7 (SeaBIOS internal) */ #define PIM_STORAGE_SIZE 600 /* storage size of pdc_pim_toc_struct (64bit) */ + +#define ASTRO_BUS_MODULE 0x0a /* C3700: 0x0a, others maybe 0 ? */ + +/* ASTRO Memory and I/O regions */ +#define ASTRO_BASE_HPA 0xfffed00000 +#define ELROY0_BASE_HPA 0xfffed30000 + +#define LMMIO_DIST_BASE_ADDR 0xf4000000UL +#define LMMIO_DIST_BASE_SIZE 0x4000000UL + +#define IOS_DIST_BASE_ADDR 0xfee00000UL +#define IOS_DIST_BASE_SIZE 0x10000UL + +#define ROPES_PER_IOC 8 /* per Ike half or Pluto/Astro */ + +#define LMMIO_DIRECT0_BASE 0x300 +#define LMMIO_DIRECT0_MASK 0x308 +#define LMMIO_DIRECT0_ROUTE 0x310 + #endif diff --git a/src/parisc/lasips2.c b/src/parisc/lasips2.c index e86cbff..a7bb9fe 100644 --- a/src/parisc/lasips2.c +++ b/src/parisc/lasips2.c @@ -14,14 +14,15 @@ #include "string.h" #include "lasips2.h" + int lasips2_kbd_in(char *c, int max) { struct bregs regs; volatile int count = 0; // check if PS2 reported new keys, if so queue them up. - while((readl(LASIPS2_KBD_STATUS) & LASIPS2_KBD_STATUS_RBNE)) { - process_key(readb(LASIPS2_KBD_DATA)); + while((gsc_readl(LASIPS2_KBD_STATUS) & LASIPS2_KBD_STATUS_RBNE)) { + process_key(gsc_readb(LASIPS2_KBD_DATA)); } while(count < max) { @@ -50,13 +51,13 @@ int ps2_kbd_command(int command, u8 *param) int lasips2_command(u16 cmd) { - while(readl(LASIPS2_KBD_STATUS) & LASIPS2_KBD_STATUS_TBNE) + while(gsc_readl(LASIPS2_KBD_STATUS) & LASIPS2_KBD_STATUS_TBNE) udelay(10); writeb(LASIPS2_KBD_DATA, cmd & 0xff); - while(!(readl(LASIPS2_KBD_STATUS) & LASIPS2_KBD_STATUS_RBNE)) + while(!(gsc_readl(LASIPS2_KBD_STATUS) & LASIPS2_KBD_STATUS_RBNE)) udelay(10); - return readb(LASIPS2_KBD_DATA); + return gsc_readb(LASIPS2_KBD_DATA); } void ps2port_setup(void) diff --git a/src/parisc/machine-create.h b/src/parisc/machine-create.h new file mode 100644 index 0000000..8b15f3a --- /dev/null +++ b/src/parisc/machine-create.h @@ -0,0 +1,20 @@ +static struct machine_info CONCAT(machine_, MACHINE) = { + .pdc_modelstr = PARISC_MODEL, + .pdc_model = { PARISC_PDC_MODEL }, + .pdc_version = PARISC_PDC_VERSION, + .pdc_cpuid = PARISC_PDC_CPUID, + .pdc_caps = PARISC_PDC_CAPABILITIES, + .pdc_entry = PARISC_PDC_ENTRY_ORG, + .pdc_cache_info = { PARISC_PDC_CACHE_INFO }, + .device_list = { PARISC_DEVICE_LIST }, +}; + +#undef MACHINE +#undef PARISC_MODEL +#undef PARISC_PDC_MODEL +#undef PARISC_PDC_VERSION +#undef PARISC_PDC_CPUID +#undef PARISC_PDC_CAPABILITIES +#undef PARISC_PDC_ENTRY_ORG +#undef PARISC_PDC_CACHE_INFO +#undef PARISC_DEVICE_LIST diff --git a/src/parisc/parisc.c b/src/parisc/parisc.c index 3eaa218..50dc3c3 100644 --- a/src/parisc/parisc.c +++ b/src/parisc/parisc.c @@ -4,6 +4,9 @@ // Copyright (C) 2019 Sven Schnelle // // This file may be distributed under the terms of the GNU LGPLv3 license. +// +// Example command line: +// ./qemu-system-hppa -drive file=../qemu-images/hdd.img -kernel vmlinux -append "root=/dev/sda5 cryptomgr.notests" -smp cpus=2 -snapshot -machine C3700 -vnc :1 -fw_cfg opt/console,string=serial -serial mon:stdio -device secondary-vga #include "biosvar.h" // GET_BDA #include "bregs.h" // struct bregs @@ -19,13 +22,13 @@ #include "hw/pci_ids.h" // PCI IDs #include "hw/pci_regs.h" // PCI_BASE_ADDRESS_0 #include "hw/ata.h" +#include "hw/usb-ohci.h" #include "hw/blockcmd.h" // scsi_is_ready() #include "hw/rtc.h" #include "fw/paravirt.h" // PlatformRunningOn #include "vgahw.h" #include "parisc/hppa_hardware.h" // DINO_UART_BASE #include "parisc/pdc.h" -#include "parisc/b160l.h" #include "parisc/sticore.h" #include "parisc/lasips2.h" @@ -118,6 +121,13 @@ int pdc_console; int sti_font; char qemu_version[16] = "unknown version"; +char qemu_machine[16] = "B160L"; +char cpu_bit_width; +char has_astro; +#define PCI_HPA DINO_HPA /* initial temp. PCI bus */ +unsigned long pci_hpa = PCI_HPA; /* HPA of Dino or Elroy0 */ +unsigned long hppa_port_pci_cmd = (PCI_HPA + DINO_PCI_ADDR); +unsigned long hppa_port_pci_data = (PCI_HPA + DINO_CONFIG_DATA); /* Want PDC boot menu? Enable via qemu "-boot menu=on" option. */ unsigned int show_boot_menu; @@ -173,6 +183,12 @@ static unsigned int chassis_code = 0; int powersw_nop; int *powersw_ptr; +/* + * Real time clock emulation + * Either LASI or Astro will provide access to an emulated RTC clock. + */ +int *rtc_ptr = (int *) (unsigned long) LASI_RTC_HPA; + void __VISIBLE __noreturn hlt(void) { if (pdc_debug) @@ -207,8 +223,10 @@ void __VISIBLE __noreturn reset(void) #undef BUG_ON #define BUG_ON(cond) \ - if (unlikely(cond)) \ -{ printf("ERROR in %s:%d\n", __FUNCTION__, __LINE__); hlt(); } + if (unlikely(cond)) { \ + printf("*ERROR* in SeaBIOS-hppa-v%d:\n%s:%d\n", SEABIOS_HPPA_VERSION, \ + __FUNCTION__, __LINE__); hlt(); \ + } void flush_data_cache(char *start, size_t length) { @@ -252,6 +270,8 @@ static struct pdc_module_path mod_path_emulated_drives = { * FIRMWARE IO Dependent Code (IODC) HANDLER ********************************************************/ +#define MAX_DEVICES HPPA_MAX_CPUS+16 + typedef struct { unsigned long hpa; struct pdc_iodc *iodc; @@ -259,21 +279,46 @@ typedef struct { struct pdc_module_path *mod_path; int num_addr; int add_addr[5]; + struct pci_device *pci; + unsigned long pci_addr; } hppa_device_t; -static hppa_device_t parisc_devices[HPPA_MAX_CPUS+16] = { PARISC_DEVICE_LIST }; +static hppa_device_t *find_hpa_device(unsigned long hpa); + +#define CONCAT2(a, b) a ## b +#define CONCAT(a, b) CONCAT2(a, b) + +struct machine_info { + char pdc_modelstr[16]; + struct pdc_model pdc_model; + int pdc_version; + int pdc_cpuid; + int pdc_caps; + int pdc_entry; + unsigned long pdc_cache_info[30]; + hppa_device_t device_list[MAX_DEVICES]; +}; + + +/* create machine definitions */ +#define MACHINE B160L +#include "parisc/b160l.h" +#include "parisc/machine-create.h" + +#define MACHINE C3700 +#include "parisc/c3700.h" +#include "parisc/machine-create.h" + +struct machine_info *current_machine = &machine_B160L; + +static hppa_device_t *parisc_devices = machine_B160L.device_list; #define PARISC_KEEP_LIST \ - GSC_HPA,\ - DINO_HPA,\ DINO_UART_HPA,\ /* DINO_SCSI_HPA, */ \ - LASI_HPA, \ LASI_UART_HPA, \ LASI_LAN_HPA, \ LASI_LPT_HPA, \ - CPU_HPA,\ - MEMORY_HPA,\ LASI_GFX_HPA,\ LASI_PS2KBD_HPA, \ LASI_PS2MOU_HPA, \ @@ -291,7 +336,7 @@ static const char *hpa_name(unsigned long hpa) DO(DINO_SCSI_HPA) DO(CPU_HPA) DO(MEMORY_HPA) - DO(IDE_HPA) + DO(SCSI_HPA) DO(LASI_HPA) DO(LASI_UART_HPA) DO(LASI_SCSI_HPA) @@ -328,37 +373,274 @@ static const char *hpa_name(unsigned long hpa) return "UNKNOWN HPA"; } +int HPA_is_astro_ioport(unsigned long hpa) +{ + if (!has_astro) + return 0; + return ((hpa - IOS_DIST_BASE_ADDR) < IOS_DIST_BASE_SIZE); +} + +int HPA_is_astro_mmio(unsigned long hpa) +{ + if (!has_astro) + return 0; + return ((hpa - LMMIO_DIST_BASE_ADDR) < LMMIO_DIST_BASE_SIZE); +} + +struct pci_device *find_pci_from_HPA(unsigned long hpa) +{ + struct pci_device *pci = NULL; + int ioport; + + if (HPA_is_astro_ioport(hpa)) { + ioport = 1; + hpa -= IOS_DIST_BASE_ADDR; + } else if (HPA_is_astro_mmio(hpa)) + ioport = 0; + else + return NULL; + + foreachpci(pci) { + int i; + for (i = 0; i < 6; i++) { + unsigned long addr = PCI_BASE_ADDRESS_0 + 4*i; + unsigned long mem; + mem = pci_config_readl(pci->bdf, addr); + if ((mem & PCI_BASE_ADDRESS_SPACE_IO) && + ((mem & PCI_BASE_ADDRESS_IO_MASK) == hpa) && + (ioport == 1)) + return pci; /* found ioport */ + if (((mem & PCI_BASE_ADDRESS_SPACE_IO) == 0) && + ((mem & PCI_BASE_ADDRESS_MEM_MASK) == hpa) && + (ioport == 0)) + return pci; /* found memaddr */ + } + } + dprintf(1, "No PCI device found for HPA %lx\n", hpa); + return NULL; +} + +int DEV_is_storage_device(hppa_device_t *dev) +{ + BUG_ON(!dev); + if (dev->pci) + return (dev->pci->class == PCI_CLASS_STORAGE_SCSI); + return ((dev->iodc->type & 0xf) == 0x04); /* HPHW_A_DMA */ +} + +int DEV_is_serial_device(hppa_device_t *dev) +{ + BUG_ON(!dev); + if (dev->pci) + return (dev->pci->class == PCI_CLASS_COMMUNICATION_SERIAL); + return ((dev->iodc->type & 0xf) == 0x0a); /* HPHW_FIO */ +} + int HPA_is_serial_device(unsigned long hpa) { - return (hpa == DINO_UART_HPA) || (hpa == LASI_UART_HPA); + hppa_device_t *dev; + + dev = find_hpa_device(hpa); + if (!dev) + return 0; + return DEV_is_serial_device(dev); } -int HPA_is_storage_device(unsigned long hpa) +int DEV_is_network_device(hppa_device_t *dev) { - return (hpa == DINO_SCSI_HPA) || (hpa == IDE_HPA) || (hpa == LASI_SCSI_HPA); + BUG_ON(!dev); + if (dev->pci) + return (dev->pci->class == PCI_CLASS_NETWORK_ETHERNET); + return ((dev->iodc->type & 0xf) == 0x0a); /* HPHW_FIO */ } -int HPA_is_keyboard_device(unsigned long hpa) +static int HPA_is_LASI_keyboard(unsigned long hpa) { - return (hpa == LASI_PS2KBD_HPA); + return !has_astro && (hpa == LASI_PS2KBD_HPA); +} + +#if 0 +static int HPA_is_keyboard_device(unsigned long hpa) +{ + struct pci_device *pci; + int ret; + + if (HPA_is_LASI_keyboard(hpa)) + return 1; + pci = find_pci_from_HPA(hpa); + if (!pci) + return 0; + ret = pci->class == PCI_CLASS_COMMUNICATION_SERIAL || + pci->class == PCI_CLASS_INPUT_KEYBOARD; + dprintf(1, "PCI: is_keyboard? %pP -> %s\n", pci, ret?"Yes":"no"); + return ret; } +#endif +int HPA_is_LASI_graphics(unsigned long hpa) +{ + hppa_device_t *dev; + + dev = find_hpa_device(hpa); + if (!dev) + return 0; + return (dev->iodc->sversion_model == 0x003b); /* XXX */ +} #define GFX_NUM_PAGES 0x2000 int HPA_is_graphics_device(unsigned long hpa) { - return (hpa == LASI_GFX_HPA) || (hpa == 0xf4000000) || - (hpa == 0xf8000000) || (hpa == 0xfa000000); + hppa_device_t *dev; + + dev = find_hpa_device(hpa); + if (!dev) + return 0; + if (dev->pci) + return (dev->pci->class >> 8) == PCI_BASE_CLASS_DISPLAY; + return (dev->iodc->sversion_model == 0x3b); /* XXX */ } static const char *hpa_device_name(unsigned long hpa, int output) { - return HPA_is_graphics_device(hpa) ? "GRAPHICS(1)" : - HPA_is_keyboard_device(hpa) ? "PS2" : + return HPA_is_LASI_graphics(hpa) ? "GRAPHICS(1)" : + HPA_is_graphics_device(hpa) ? "VGA" : + HPA_is_LASI_keyboard(hpa) ? "PS2" : ((hpa + 0x800) == PORT_SERIAL1) ? "SERIAL_1.9600.8.none" : "SERIAL_2.9600.8.none"; } -static unsigned long keep_list[] = { PARISC_KEEP_LIST }; +static void print_mod_path(struct pdc_module_path *p) +{ + dprintf(1, "PATH %d/%d/%d/%d/%d/%d/%d:%d.%d.%d ", p->path.bc[0], p->path.bc[1], + p->path.bc[2],p->path.bc[3],p->path.bc[4],p->path.bc[5], + p->path.mod, p->layers[0], p->layers[1], p->layers[2]); +} + +void make_module_path_from_pcidev(struct pci_device *pci, + struct pdc_module_path *p) +{ + memset(p, 0, sizeof(*p)); + memset(&p->path.bc, 0xff, sizeof(p->path.bc)); + + switch (pci->class) { + case PCI_CLASS_COMMUNICATION_SERIAL: + case PCI_CLASS_NETWORK_ETHERNET: + case PCI_CLASS_STORAGE_SCSI: + case PCI_CLASS_SERIAL_USB: + default: +#if 0 +static struct pdc_module_path mod_path_hpa_fed3c000 = { // SCSI + .path = { .flags = 0x0, .bc = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xa }, .mod = 0x6 }, + .layers = { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 } +#endif + p->path.bc[3] = has_astro ? ASTRO_BUS_MODULE : 0x08; /* astro or dino */ + p->path.bc[4] = 0; // elroy index (0,1,4,6) == PCI Bus number (0,1,2,3) + p->path.bc[5] = pci->bdf >> 3; /* slot */ + p->path.mod = pci->bdf & 0x07; /* function */ + break; + } +} + +void make_iodc_from_pcidev(struct pci_device *pci, + struct pdc_iodc *p) +{ + memset(p, 0, sizeof(*p)); + p->hversion_model = 0x0058; + p->hversion = 0x0020; + p->sversion_model = 0; + p->sversion_opt = 0; + p->rev = 0x0099; + p->length = 1; + + switch (pci->class) { + case PCI_CLASS_STORAGE_SCSI: + p->features = 0x0001; + p->type = 0x0084; + break; + case PCI_CLASS_COMMUNICATION_SERIAL: + case PCI_CLASS_NETWORK_ETHERNET: + case PCI_CLASS_SERIAL_USB: + default: + p->type = 0x008a; + break; + } +}; + +void make_modinfo_from_pcidev(struct pci_device *pci, + struct pdc_system_map_mod_info *p, unsigned long pfa) +{ + memset(p, 0, sizeof(*p)); + p->mod_addr = pfa; + p->mod_pgs = 0; + p->add_addrs = HPA_is_graphics_device(pfa) ? GFX_NUM_PAGES : 0; +}; + +#define MAX_PCI_DEVICES 10 +static int curr_pci_devices; /* current number of PCI devices in list */ +static hppa_device_t hppa_pci_devices[MAX_PCI_DEVICES]; +static struct pdc_iodc hppa_pci_iodc[MAX_PCI_DEVICES]; +static struct pdc_system_map_mod_info hppa_pci_mod_info[MAX_PCI_DEVICES]; +static struct pdc_module_path hppa_pci_mod_path[MAX_PCI_DEVICES]; + + +/* create table of PFA (PCI Function address), similiar to HPA */ +static void hppa_pci_build_devices_list(void) +{ + struct pci_device *pci; + + memset(&hppa_pci_devices, 0, sizeof(hppa_pci_devices)); + + curr_pci_devices = 0; + + dprintf(1, "\n PCI DEVICE LIST PFA TABLE\n"); + foreachpci(pci) { + unsigned long pfa, offs; + hppa_device_t *pdev = &hppa_pci_devices[curr_pci_devices]; + + offs = elroy_offset(pci->bdf); + BUG_ON(offs == -1UL); + pfa = (unsigned long) elroy_port(0, offs); + pfa += pci->bdf << 8; + pfa |= SCSI_HPA; + dprintf(1, "PCI device #%d %pP bdf 0x%x at pfa 0x%lx\n", curr_pci_devices, pci, pci->bdf, pfa); + + pdev->hpa = pfa; + pdev->iodc = &hppa_pci_iodc[curr_pci_devices]; + pdev->mod_info = &hppa_pci_mod_info[curr_pci_devices]; + pdev->mod_path = &hppa_pci_mod_path[curr_pci_devices]; + pdev->num_addr = 0; + pdev->pci = pci; + + make_iodc_from_pcidev(pci, pdev->iodc); + make_modinfo_from_pcidev(pci, pdev->mod_info, pfa); + make_module_path_from_pcidev(pci, pdev->mod_path); + + curr_pci_devices++; + BUG_ON(curr_pci_devices >= MAX_PCI_DEVICES); + } +} + +static hppa_device_t *find_hpa_device(unsigned long hpa) +{ + int i; + + /* search classical HPPA devices */ + if (hpa) + for (i = 0; i < (MAX_DEVICES-1); i++) { + if (hpa == parisc_devices[i].hpa) + return &parisc_devices[i]; + if (!parisc_devices[i].hpa) + break; + } + + /* search PCI devices */ + for (i = 0; i < curr_pci_devices; i++) { + if (hpa == hppa_pci_devices[i].hpa) + return &hppa_pci_devices[i]; + } + return NULL; +} + +static unsigned long keep_list[20] = { PARISC_KEEP_LIST }; static void remove_from_keep_list(unsigned long hpa) { @@ -384,6 +666,35 @@ static int keep_this_hpa(unsigned long hpa) return 0; } +/* walk all machine devices and add generic ones to the keep_list[] */ +static int keep_add_generic_devices(void) +{ + hppa_device_t *dev = current_machine->device_list; + int i = 0; + + /* search end of list */ + while (keep_list[i]) i++; + + while (dev->hpa) { + switch (dev->iodc->type) { + case 0x0041: /* Memory. Save HPA in PAGE0 entry. */ + PAGE0->imm_hpa = dev->hpa; + /* fallthrough */ + case 0x0007: /* GSC+ Port bridge */ + case 0x004d: /* Dino PCI bridge */ + case 0x004b: /* Core Bus adapter (LASI) */ + case 0x0040: /* CPU */ + case 0x000d: /* Elroy PCI bridge */ + case 0x000c: /* Runway port */ + keep_list[i++] = dev->hpa; + } + dev++; + } + BUG_ON(i >= ARRAY_SIZE(keep_list)); + + return 0; +} + /* Rebuild hardware list and drop all devices which are not listed in * PARISC_KEEP_LIST. Generate num_cpus CPUs. */ static void remove_parisc_devices(unsigned int num_cpus) @@ -445,28 +756,14 @@ static void remove_parisc_devices(unsigned int num_cpus) t++; } - BUG_ON(t > ARRAY_SIZE(parisc_devices)); + BUG_ON(t > MAX_DEVICES); - while (t < ARRAY_SIZE(parisc_devices)) { - memset(&parisc_devices[t], 0, sizeof(parisc_devices[0])); + while (t < MAX_DEVICES) { + memset(&parisc_devices[t], 0, sizeof(*parisc_devices)); t++; } } -static int find_hpa_index(unsigned long hpa) -{ - int i; - if (!hpa) - return -1; - for (i = 0; i < (ARRAY_SIZE(parisc_devices)-1); i++) { - if (hpa == parisc_devices[i].hpa) - return i; - if (!parisc_devices[i].hpa) - return -1; - } - return -1; -} - static int compare_module_path(struct pdc_module_path *path, struct pdc_module_path *search, int check_layers) @@ -474,47 +771,94 @@ static int compare_module_path(struct pdc_module_path *path, int i; if (path->path.mod != search->path.mod) - return -1; + return 0; for(i = 0; i < ARRAY_SIZE(path->path.bc); i++) { if (path->path.bc[i] != search->path.bc[i]) - return -1; + return 0; } if (check_layers) { for(i = 0; i < ARRAY_SIZE(path->layers); i++) { if (path->layers[i] != search->layers[i]) - return -1; + return 0; } } - return 0; + return 1; } -static hppa_device_t *find_hppa_device_by_path(struct pdc_module_path *search, - unsigned long *index, int check_layers) +static hppa_device_t *find_hppa_device_by_path(unsigned long hpa, + struct pdc_module_path *search, + unsigned long *index, int check_layers) +{ + hppa_device_t *dev; + int i, nr = 0; + + for (i = 0; i < (MAX_DEVICES-1); i++) { + dev = parisc_devices + i; + if (dev->hpa != hpa) + continue; + + if (compare_module_path(dev->mod_path, search, check_layers)) { + if (index) + *index = nr; + return dev; + } + nr++; + } + + /* search PCI devices */ + for (i = 0; i < curr_pci_devices; i++) { + dev = hppa_pci_devices + i; + if (compare_module_path(dev->mod_path, search, check_layers)) { + if (index) + *index = nr; + return dev; + } + nr++; + } + + return NULL; +} + +static hppa_device_t *find_hppa_device_by_index(unsigned int index, int search_pci) { hppa_device_t *dev; int i; - for (i = 0; i < (ARRAY_SIZE(parisc_devices)-1); i++) { + for (i = 0; i < (MAX_DEVICES-1); i++) { dev = parisc_devices + i; if (!dev->hpa) continue; - - if (!compare_module_path(dev->mod_path, search, check_layers)) { - *index = i; + if (index-- == 0) return dev; + } + + /* search PCI devices */ + if (search_pci) { + for (i = 0; i < curr_pci_devices; i++) { + dev = hppa_pci_devices + i; + if (index-- == 0) + return dev; } } + return NULL; } #define SERIAL_TIMEOUT 20 static unsigned long parisc_serial_in(char *c, unsigned long maxchars) { - portaddr_t addr = PAGE0->mem_kbd.hpa + 0x800; /* PARISC_SERIAL_CONSOLE */ + portaddr_t addr = PAGE0->mem_kbd.hpa; unsigned long end = timer_calc(SERIAL_TIMEOUT); unsigned long count = 0; + + if (has_astro) { + hppa_device_t *dev = find_hpa_device(addr); + BUG_ON(!dev); + addr = dev->pci_addr; + } else + addr += 0x800; while (count < maxchars) { u8 lsr = inb(addr+SEROFF_LSR); if (lsr & 0x01) { @@ -533,10 +877,29 @@ static void parisc_serial_out(char c) portaddr_t addr = PAGE0->mem_cons.hpa; /* might not be initialized if problems happen during early bootup */ - if (!addr) - addr = PARISC_SERIAL_CONSOLE; + if (!addr) { + /* use debugoutput instead */ + dprintf(0, "%c", c); + return; + } + if (0) { + dprintf(1,"parisc_serial_out search hpa %x ", PAGE0->mem_cons.hpa); + print_mod_path(&PAGE0->mem_cons.dp); + dprintf(1," \n"); + } + hppa_device_t *dev; + dev = find_hppa_device_by_path(addr, &PAGE0->mem_cons.dp, NULL, 0); + if (0) { + dprintf(1,"parisc_serial_out hpa %x\n", PAGE0->mem_cons.hpa); + print_mod_path(dev->mod_path); + } + if (!dev) hlt(); + BUG_ON(!dev); + if (dev->pci_addr) + addr = dev->pci_addr; else - addr += 0x800; + addr += 0x800; /* add offset for serial port on GSC */ +// dprintf(1," addr %x\n", addr); if (c == '\n') parisc_serial_out('\r'); @@ -553,7 +916,7 @@ static void parisc_serial_out(char c) static void parisc_putchar_internal(char c) { - if (HPA_is_graphics_device(PAGE0->mem_cons.hpa)) + if (HPA_is_LASI_graphics(PAGE0->mem_cons.hpa)) sti_putc(c); else parisc_serial_out(c); @@ -573,10 +936,12 @@ static char parisc_getchar(void) int count; char c; - if (HPA_is_serial_device(PAGE0->mem_kbd.hpa)) + if (HPA_is_LASI_keyboard(PAGE0->mem_kbd.hpa)) + count = lasips2_kbd_in(&c, sizeof(c)); + else if (HPA_is_serial_device(PAGE0->mem_kbd.hpa)) count = parisc_serial_in(&c, sizeof(c)); else - count = lasips2_kbd_in(&c, sizeof(c)); + BUG_ON(1); if (count == 0) c = 0; return c; @@ -600,14 +965,21 @@ int __VISIBLE parisc_iodc_ENTRY_IO(unsigned int *arg FUNC_MANY_ARGS) unsigned long hpa = ARG0; unsigned long option = ARG1; unsigned long *result = (unsigned long *)ARG4; + hppa_device_t *dev; int ret, len; char *c; struct disk_op_s disk_op; + dev = find_hpa_device(hpa); + if (!dev) { + // BUG_ON(1); + return PDC_INVALID_ARG; + } + if (1 && - (((HPA_is_serial_device(hpa) || HPA_is_graphics_device(hpa)) && option == ENTRY_IO_COUT) || - ((HPA_is_serial_device(hpa) || HPA_is_graphics_device(hpa)) && option == ENTRY_IO_CIN) || - ((HPA_is_storage_device(hpa) && option == ENTRY_IO_BOOTIN && !(pdc_debug & DEBUG_BOOT_IO)))) ) { + (((DEV_is_serial_device(dev) || HPA_is_graphics_device(hpa)) && option == ENTRY_IO_COUT) || + ((DEV_is_serial_device(dev) || HPA_is_graphics_device(hpa)) && option == ENTRY_IO_CIN) || + ((DEV_is_storage_device(dev) && option == ENTRY_IO_BOOTIN && !(pdc_debug & DEBUG_BOOT_IO)))) ) { /* avoid debug messages */ } else { iodc_log_call(arg, __FUNCTION__); @@ -618,7 +990,7 @@ int __VISIBLE parisc_iodc_ENTRY_IO(unsigned int *arg FUNC_MANY_ARGS) case ENTRY_IO_COUT: /* console output */ c = (char*)ARG6; result[0] = len = ARG7; - if (HPA_is_serial_device(hpa) || HPA_is_graphics_device(hpa)) { + if (DEV_is_serial_device(dev) || HPA_is_LASI_graphics(hpa)) { while (len--) printf("%c", *c++); } @@ -626,15 +998,15 @@ int __VISIBLE parisc_iodc_ENTRY_IO(unsigned int *arg FUNC_MANY_ARGS) case ENTRY_IO_CIN: /* console input, with 5 seconds timeout */ c = (char*)ARG6; /* FIXME: Add loop to wait for up to 5 seconds for input */ - if (HPA_is_serial_device(hpa)) - result[0] = parisc_serial_in(c, ARG7); - else if (HPA_is_keyboard_device(hpa)) + if (HPA_is_LASI_keyboard(hpa)) result[0] = lasips2_kbd_in(c, ARG7); + else if (DEV_is_serial_device(dev)) + result[0] = parisc_serial_in(c, ARG7); return PDC_OK; } /* boot medium I/O */ - if (HPA_is_storage_device(hpa)) + if (DEV_is_storage_device(dev)) switch (option) { case ENTRY_IO_BOOTIN: /* boot medium IN */ case ENTRY_IO_BBLOCK_IN: /* boot block medium IN */ @@ -692,21 +1064,25 @@ int __VISIBLE parisc_iodc_ENTRY_INIT(unsigned int *arg FUNC_MANY_ARGS) unsigned long hpa = ARG0; unsigned long option = ARG1; unsigned long *result = (unsigned long *)ARG4; - int hpa_index; + hppa_device_t *dev; iodc_log_call(arg, __FUNCTION__); - hpa_index = find_hpa_index(hpa); - if (hpa_index < 0 && hpa != IDE_HPA) + dev = find_hpa_device(hpa); + // dprintf(1, "HPA1 %lx DEV %p pci %p\n", hpa, dev, dev->pci); + + if (!dev || !(DEV_is_storage_device(dev) || DEV_is_serial_device(dev) || DEV_is_network_device(dev))) return PDC_INVALID_ARG; + // dprintf(1, "HPA2 %lx DEV %p\n", hpa, dev); switch (option) { case ENTRY_INIT_SRCH_FRST: /* 2: Search first */ + if (DEV_is_network_device(dev)) + return PDC_NE_BOOTDEV; /* No further boot devices */ memcpy((void *)ARG3, &mod_path_emulated_drives.layers, sizeof(mod_path_emulated_drives.layers)); /* fill ID_addr */ result[0] = 0; - result[1] = HPA_is_serial_device(hpa) ? CL_DUPLEX: - HPA_is_storage_device(hpa) ? CL_RANDOM : 0; + result[1] = DEV_is_serial_device(dev) ? CL_DUPLEX : CL_RANDOM; result[2] = result[3] = 0; /* No network card, so no MAC. */ return PDC_OK; case ENTRY_INIT_SRCH_NEXT: /* 3: Search next */ @@ -714,9 +1090,11 @@ int __VISIBLE parisc_iodc_ENTRY_INIT(unsigned int *arg FUNC_MANY_ARGS) case ENTRY_INIT_MOD_DEV: /* 4: Init & test mod & dev */ case ENTRY_INIT_DEV: /* 5: Init & test dev */ result[0] = 0; /* module IO_STATUS */ - result[1] = HPA_is_serial_device(hpa) ? CL_DUPLEX: - HPA_is_storage_device(hpa) ? CL_RANDOM : 0; - result[2] = result[3] = 0; /* TODO?: MAC of network card. */ + result[1] = DEV_is_serial_device(dev) ? CL_DUPLEX: CL_RANDOM; + if (DEV_is_network_device(dev)) + result[2] = result[3] = 0x11221133; /* TODO?: MAC of network card. */ + else + result[2] = result[3] = 0; return PDC_OK; case ENTRY_INIT_MOD: /* 6: INIT */ result[0] = 0; /* module IO_STATUS */ @@ -734,6 +1112,7 @@ int __VISIBLE parisc_iodc_ENTRY_SPA(unsigned int *arg FUNC_MANY_ARGS) int __VISIBLE parisc_iodc_ENTRY_CONFIG(unsigned int *arg FUNC_MANY_ARGS) { iodc_log_call(arg, __FUNCTION__); + // BUG_ON(1); return PDC_BAD_OPTION; } @@ -742,12 +1121,12 @@ int __VISIBLE parisc_iodc_ENTRY_TEST(unsigned int *arg FUNC_MANY_ARGS) unsigned long hpa = ARG0; unsigned long option = ARG1; unsigned long *result = (unsigned long *)ARG4; - int hpa_index; + hppa_device_t *dev; iodc_log_call(arg, __FUNCTION__); - hpa_index = find_hpa_index(hpa); - if (hpa_index < 0 && hpa != IDE_HPA) + dev = find_hpa_device(hpa); + if (!dev || !(DEV_is_storage_device(dev) || DEV_is_serial_device(dev))) return PDC_INVALID_ARG; /* The options ARG1=0 and ARG1=1 are required. Others are optional. */ @@ -805,16 +1184,6 @@ static void init_stable_storage(void) stable_storage[0x5f] = 0x0f; } -static unsigned long lasi_rtc_read(void) -{ - return *(u32 *)LASI_RTC_HPA; -} - -static void lasi_rtc_write(u32 val) -{ - *(u32 *)LASI_RTC_HPA = val; -} - /* values in PDC_CHASSIS */ const char * const systat[] = { "Off", "Fault", "Test", "Initialize", @@ -926,7 +1295,7 @@ static int pdc_pim(unsigned int *arg) case PDC_PIM_TOC: hpa = mfctl(CPU_HPA_CR_REG); /* get CPU HPA from cr7 */ i = index_of_CPU_HPA(hpa); - if (i < 0 || i >= HPPA_MAX_CPUS) { + if (i < 0 || i >= smp_cpus) { *result = PDC_INVALID_ARG; return PDC_OK; } @@ -949,17 +1318,22 @@ static int pdc_pim(unsigned int *arg) return PDC_BAD_OPTION; } -static struct pdc_model model = { PARISC_PDC_MODEL }; - static int pdc_model(unsigned int *arg) { - static const char model_str[] = PARISC_MODEL; + const char *model_str = current_machine->pdc_modelstr; unsigned long option = ARG1; unsigned long *result = (unsigned long *)ARG2; switch (option) { case PDC_MODEL_INFO: - memcpy(result, &model, sizeof(model)); + /* + * In case we run on a 32-bit only emulation, avoid a kernel crash + * with old qemu versions which will try to run 64-bit instructions + * kernel sr_disable_hash() function + */ + memcpy(result, (cpu_bit_width == 64) ? + ¤t_machine->pdc_model : &machine_B160L.pdc_model, + sizeof(current_machine->pdc_model)); return PDC_OK; case PDC_MODEL_VERSIONS: switch (ARG3) { @@ -967,30 +1341,43 @@ static int pdc_model(unsigned int *arg) result[0] = 35; // TODO! ??? return PDC_OK; case 1: /* return PDC version */ - result[0] = PARISC_PDC_VERSION; + result[0] = current_machine->pdc_version; return PDC_OK; } return -4; // invalid c_index case PDC_MODEL_SYSMODEL: - result[0] = sizeof(model_str) - 1; - strtcpy((char *)ARG4, model_str, sizeof(model_str)); + result[0] = strlen(model_str); + strtcpy((char *)ARG4, model_str, result[0] + 1); return PDC_OK; case PDC_MODEL_ENSPEC: case PDC_MODEL_DISPEC: - if (ARG3 != model.pot_key) + if (ARG3 != current_machine->pdc_model.pot_key) return -20; return PDC_OK; case PDC_MODEL_CPU_ID: - result[0] = PARISC_PDC_CPUID; + result[0] = current_machine->pdc_cpuid; + /* if CPU does not support 64bits, use the B160L CPUID */ + if (cpu_bit_width != 64) + result[0] = machine_B160L.pdc_cpuid; return PDC_OK; case PDC_MODEL_CAPABILITIES: - result[0] = PARISC_PDC_CAPABILITIES; + result[0] = current_machine->pdc_caps; result[0] |= PDC_MODEL_OS32; /* we do support 32-bit */ - result[0] &= ~PDC_MODEL_OS64; /* but not 64-bit (yet) */ + if (cpu_bit_width == 64) /* and maybe 64-bit */ + result[0] |= PDC_MODEL_OS64; + else + result[0] &= ~PDC_MODEL_OS64; return PDC_OK; case PDC_MODEL_GET_INSTALL_KERNEL: // No need to provide a special install kernel during installation of HP-UX return PDC_BAD_OPTION; + case PDC_MODEL_GET_PLATFORM_INFO: + model_str = has_astro ? "A6057A" : "9000/778"; + strtcpy((char *)ARG2, model_str, 16); + strtcpy((char *)ARG3, model_str, 16); + /* use: current_machine->pdc_model.sw_id ? */ + strtcpy((char *)ARG4, "001122334455", 16); + return PDC_OK; } dprintf(0, "\n\nSeaBIOS: Unimplemented PDC_MODEL function %d %x %x %x %x\n", ARG1, ARG2, ARG3, ARG4, ARG5); return PDC_BAD_OPTION; @@ -1000,15 +1387,15 @@ static int pdc_cache(unsigned int *arg) { unsigned long option = ARG1; unsigned long *result = (unsigned long *)ARG2; - static unsigned long cache_info[] = { PARISC_PDC_CACHE_INFO }; - static struct pdc_cache_info *machine_cache_info - = (struct pdc_cache_info *) &cache_info; + struct pdc_cache_info *machine_cache_info + = (struct pdc_cache_info *) current_machine->pdc_cache_info; switch (option) { case PDC_CACHE_INFO: - BUG_ON(sizeof(cache_info) != sizeof(*machine_cache_info)); machine_cache_info->it_size = tlb_entries; machine_cache_info->dt_size = tlb_entries; + machine_cache_info->it_conf = (struct pdc_tlb_cf) { .tc_sh = 3, .tc_page = 1, .tc_cst = 1, .tc_sr = 0, }; + machine_cache_info->dt_conf = (struct pdc_tlb_cf) { .tc_sh = 3, .tc_page = 1, .tc_cst = 1, .tc_sr = 0, }; machine_cache_info->it_loop = 1; machine_cache_info->dt_loop = 1; @@ -1018,20 +1405,25 @@ static int pdc_cache(unsigned int *arg) machine_cache_info->dc_count, machine_cache_info->dc_loop, machine_cache_info->dc_stride); #endif #if 1 - /* Increase cc_block from 1 to 11. This increases icache_stride - * and dcache_stride to 32768 bytes. Revisit for HP-UX. */ - machine_cache_info->dc_conf.cc_block = 11; - machine_cache_info->ic_conf.cc_block = 11; + machine_cache_info->ic_size = 1024; /* no instruction cache */ + machine_cache_info->dc_size = 1024; /* no data cache */ +#elif 0 + machine_cache_info->dc_conf = (struct pdc_cache_cf) { 0 }; // .alias=1, .sh=3, }; + machine_cache_info->ic_conf = (struct pdc_cache_cf) { 0 }; // .alias=1, .sh=3, }; machine_cache_info->ic_size = 0; /* no instruction cache */ machine_cache_info->ic_count = 0; machine_cache_info->ic_loop = 0; + machine_cache_info->ic_base = 0; + machine_cache_info->ic_stride = 0; machine_cache_info->dc_size = 0; /* no data cache */ machine_cache_info->dc_count = 0; machine_cache_info->dc_loop = 0; + machine_cache_info->dc_base = 0; + machine_cache_info->dc_stride = 0; #endif - memcpy(result, cache_info, sizeof(cache_info)); + memcpy(result, machine_cache_info, sizeof(*machine_cache_info)); return PDC_OK; case PDC_CACHE_RET_SPID: /* returns space-ID bits */ memset(result, 0, 32 * sizeof(unsigned long)); @@ -1054,7 +1446,7 @@ static int pdc_hpa(unsigned int *arg) case PDC_HPA_PROCESSOR: hpa = mfctl(CPU_HPA_CR_REG); /* get CPU HPA from cr7 */ i = index_of_CPU_HPA(hpa); - BUG_ON(i < 0); /* ARGH, someone modified cr7! */ + BUG_ON(i < 0 || i >= smp_cpus); /* ARGH, someone modified cr7! */ result[0] = hpa; /* CPU_HPA */ result[1] = i; /* for SMP: 0,1,2,3,4...(num of this cpu) */ return PDC_OK; @@ -1075,12 +1467,12 @@ static int pdc_coproc(unsigned int *arg) /* Set one bit per cpu in ccr_functional and ccr_present. Ignore that specification only mentions 8 bits for cr10 and set all FPUs functional */ - mask = -1UL; + mask = 1UL << 7; mtctl(mask, 10); /* initialize cr10 */ result[0] = mask; result[1] = mask; result[17] = 1; // Revision - result[18] = 19; // Model + result[18] = has_astro ? 0x0f : 0x13; // Model return PDC_OK; } return PDC_BAD_OPTION; @@ -1091,32 +1483,30 @@ static int pdc_iodc(unsigned int *arg) unsigned long option = ARG1; unsigned long *result = (unsigned long *)ARG2; unsigned long hpa; + hppa_device_t *dev; struct pdc_iodc *iodc_p; - int hpa_index; unsigned char *c; - // dprintf(0, "\n\nSeaBIOS: Info PDC_IODC function %ld ARG3=%x ARG4=%x ARG5=%x ARG6=%x\n", option, ARG3, ARG4, ARG5, ARG6); + // dprintf(1, "\n\nSeaBIOS: Info PDC_IODC function %ld ARG3=%x ARG4=%x ARG5=%x ARG6=%x\n", option, ARG3, ARG4, ARG5, ARG6); switch (option) { case PDC_IODC_READ: hpa = ARG3; - if (hpa == IDE_HPA) { // do NOT check for DINO_SCSI_HPA, breaks Linux which scans IO areas for unlisted io modules - iodc_p = &iodc_data_hpa_fff8c000; // workaround for PCI ATA - } else { - hpa_index = find_hpa_index(hpa); - if (hpa_index < 0) - return -4; // not found - iodc_p = parisc_devices[hpa_index].iodc; - } + dev = find_hpa_device(hpa); +// dprintf(1, "pdc_iodc found dev %p\n", dev); + if (!dev) + return -4; // not found + + iodc_p = dev->iodc; if (ARG4 == PDC_IODC_INDEX_DATA) { - // if (hpa == MEMORY_HPA) - // ARG6 = 2; // Memory modules return 2 bytes of IODC memory (result2 ret[0] = 0x6701f41 HI !!) + if (iodc_p->type == 0x0041) // Memory ? + ARG6 = 2; // Memory modules return 2 bytes of IODC memory (result2 ret[0] = 0x6701f41 HI !!) memcpy((void*) ARG5, iodc_p, ARG6); c = (unsigned char *) ARG5; // printf("SeaBIOS: PDC_IODC get: hpa = 0x%lx, HV: 0x%x 0x%x IODC_SPA=0x%x type 0x%x, \n", hpa, c[0], c[1], c[2], c[3]); // c[0] = iodc_p->hversion_model; // FIXME. BROKEN HERE !!! // c[1] = iodc_p->hversion_rev || (iodc_p->hversion << 4); - *result = ARG6; + result[0] = ARG6; return PDC_OK; } @@ -1136,9 +1526,13 @@ static int pdc_iodc(unsigned int *arg) flush_data_cache((char*)ARG5, *result); return PDC_OK; break; - case PDC_IODC_NINIT: /* non-destructive init */ + case PDC_IODC_NINIT: /* non-destructive init - for memory */ case PDC_IODC_DINIT: /* destructive init */ - break; + result[0] = 0; /* IO_STATUS */ + result[1] = 0; /* max_spa */ + result[2] = ram_size; /* max memory */ + result[3] = 0; + return PDC_OK; case PDC_IODC_MEMERR: result[0] = 0; /* IO_STATUS */ result[1] = 0; @@ -1157,11 +1551,11 @@ static int pdc_tod(unsigned int *arg) switch (option) { case PDC_TOD_READ: - result[0] = lasi_rtc_read(); + result[0] = *rtc_ptr; result[1] = result[2] = result[3] = 0; return PDC_OK; case PDC_TOD_WRITE: - lasi_rtc_write(ARG2); + *rtc_ptr = ARG2; return PDC_OK; case 2: /* PDC_TOD_CALIBRATE_TIMERS */ /* double-precision floating-point with frequency of Interval Timer in megahertz: */ @@ -1280,6 +1674,10 @@ static int pdc_block_tlb(unsigned int *arg) { int ret; + /* Block TLB is only supported on 32-bit CPUs */ + if (cpu_bit_width != 32) + return PDC_BAD_PROC; + asm( "ldw (7-0)*%2(%1),%%r26 ! ldw (7-1)*%2(%1),%%r25 ! ldw (7-2)*%2(%1),%%r24 ! ldw (7-3)*%2(%1),%%r23\n" "ldw (7-4)*%2(%1),%%r22 ! ldw (7-5)*%2(%1),%%r21 ! ldw (7-6)*%2(%1),%%r20 ! ldw (7-7)*%2(%1),%%r19\n" @@ -1363,55 +1761,71 @@ static int pdc_system_map(unsigned int *arg) unsigned long option = ARG1; unsigned long *result = (unsigned long *)ARG2; struct pdc_module_path *mod_path; + hppa_device_t *dev; unsigned long hpa; - int hpa_index; + unsigned long hpa_index; // dprintf(0, "\n\nSeaBIOS: Info: PDC_SYSTEM_MAP function %ld ARG3=%x ARG4=%x ARG5=%x\n", option, ARG3, ARG4, ARG5); switch (option) { case PDC_FIND_MODULE: hpa_index = ARG4; - if (hpa_index >= ARRAY_SIZE(parisc_devices)) - return PDC_NE_MOD; // Module not found - hpa = parisc_devices[hpa_index].hpa; - if (!hpa) + dev = find_hppa_device_by_index(hpa_index, 0); + if (!dev) return PDC_NE_MOD; // Module not found + hpa = dev->hpa; + + if (0) { + dprintf(1, "PDC_FIND_MODULE dev=%p hpa=%lx ", dev, dev ? dev->hpa:0UL); + print_mod_path(dev->mod_path); + if (dev->pci) + dprintf(1, "PCI %pP ", dev->pci); + dprintf(1, "\n"); + } + + memset(result, 0, 32*sizeof(long)); mod_path = (struct pdc_module_path *)ARG3; if (mod_path) - *mod_path = *parisc_devices[hpa_index].mod_path; + *mod_path = *dev->mod_path; // *pdc_mod_info = *parisc_devices[hpa_index].mod_info; -> can be dropped. - memset(result, 0, 32*sizeof(long)); - result[0] = hpa; // .mod_addr for PDC_IODC - result[1] = HPA_is_graphics_device(hpa) ? GFX_NUM_PAGES : 1; - result[2] = parisc_devices[hpa_index].num_addr; // additional addresses + result[0] = dev->mod_info->mod_addr; // for PDC_IODC + result[1] = dev->mod_info->mod_pgs; + result[2] = dev->num_addr; // dev->mod_info->add_addr; return PDC_OK; case PDC_FIND_ADDRESS: hpa_index = ARG3; - if (hpa_index >= ARRAY_SIZE(parisc_devices)) - return PDC_NE_MOD; // Module not found - hpa = parisc_devices[hpa_index].hpa; - if (!hpa) + dev = find_hppa_device_by_index(hpa_index, 1); + if (!dev) return PDC_NE_MOD; // Module not found + hpa = dev->hpa; memset(result, 0, 32*sizeof(long)); ARG4 -= 1; - if (ARG4 >= parisc_devices[hpa_index].num_addr) + if (ARG4 >= dev->num_addr) return PDC_INVALID_ARG; - result[0] = parisc_devices[hpa_index].add_addr[ARG4]; + result[0] = dev->add_addr[ARG4]; result[1] = HPA_is_graphics_device(hpa) ? GFX_NUM_PAGES : 1; return PDC_OK; case PDC_TRANSLATE_PATH: mod_path = (struct pdc_module_path *)ARG3; - hppa_device_t *dev = find_hppa_device_by_path(mod_path, result+3, 1); + hppa_device_t *dev = find_hppa_device_by_path(0, mod_path, &hpa_index, 1); // XXX + if (0) { + dprintf(1, "PDC_TRANSLATE_PATH dev=%p hpa=%lx ", dev, dev ? dev->hpa:0UL); + print_mod_path(mod_path); + if (dev && dev->pci) + dprintf(1, "PCI %pP ", dev->pci); + dprintf(1, "\n"); + } if (!dev) return PDC_NE_MOD; - result[0] = dev->hpa; - result[1] = 1; - result[2] = 0; + result[0] = dev->mod_info->mod_addr; // for PDC_IODC + result[1] = dev->mod_info->mod_pgs; + result[2] = dev->num_addr; // dev->mod_info->add_addr; + result[3] = hpa_index; return PDC_OK; } return PDC_BAD_OPTION; @@ -1441,14 +1855,15 @@ static int pdc_mem_map(unsigned int *arg) { unsigned long option = ARG1; struct pdc_memory_map *memmap = (struct pdc_memory_map *) ARG2; - struct device_path *dp = (struct device_path *) ARG3; + struct pdc_module_path *dp = (struct pdc_module_path *) ARG3; hppa_device_t *dev; unsigned long index; switch (option) { case PDC_MEM_MAP_HPA: - // dprintf(0, "\nSeaBIOS: PDC_MEM_MAP_HPA bus = %d, mod = %d\n", dp->bc[4], dp->mod); - dev = find_hppa_device_by_path((struct pdc_module_path *) dp, &index, 0); +// NEEDS FIXING !! + dprintf(0, "\nSeaBIOS: PDC_MEM_MAP_HPA bus = %d, mod = %d\n", dp->path.bc[4], dp->path.mod); + dev = find_hppa_device_by_path(memmap->hpa, (struct pdc_module_path *) dp, &index, 0); // ?? if (!dev) return PDC_NE_MOD; memcpy(memmap, dev->mod_info, sizeof(*memmap)); @@ -1489,31 +1904,83 @@ static int pdc_lan_station_id(unsigned int *arg) return PDC_BAD_OPTION; } + +#if 0 + Interrupt Routing Table (cell 0) + 8b10000f30000002 fffffffffed30800 - 8b 10 00 0f 30 00 00 02 fffffffffed30800 + 8b10000f34000003 fffffffffed30800 - 8b 10 00 0f 34 00 00 03 fffffffffed30800 + 8b10000d3b000000 fffffffffed30800 - 8b 10 00 0d 3b 00 00 00 fffffffffed30800 + 8b10000f3c000001 fffffffffed30800 - 8b 10 00 0f 3c 00 00 01 fffffffffed30800 + 8b10000f3c000001 fffffffffed30800 - 8b 10 00 0f 3c 00 00 01 fffffffffed30800 +#endif +#define MAX_IRT_TABLE_ENTRIES 24 +#define IOSAPIC_HPA 0xfffffffffed30800ULL +#define ELROY_IRQS 8 /* IOSAPIC IRQs */ +static int irt_table_entries; +static u32 irt_table[MAX_IRT_TABLE_ENTRIES * 16/sizeof(u32)]; + +static void iosapic_table_setup(void) +{ + struct pci_device *pci; + u32 *p; + u8 slot = 0, iosapic_intin = 0, irq_devno, bus_id; + + irt_table_entries = 0; + memset(irt_table, 0, sizeof(irt_table)); + p = irt_table; + + foreachpci(pci) { + // if (!pci->irq) continue; + BUG_ON(irt_table_entries >= MAX_IRT_TABLE_ENTRIES); + irt_table_entries++; + dprintf(5, "IRT ENTRY #%d: bdf %02x\n", irt_table_entries, pci->bdf); + /* write the 16 bytes */ + /* 1: entry_type, entry_length, interrupt_type, polarity_trigger */ + *p++ = 0x8b10000f; // oder 0x8b10000d + /* 2: src_bus_irq_devno, src_bus_id, src_seg_id, dest_iosapic_intin */ + /* irq_devno = (slot << 2) | (intr_pin-1); */ + irq_devno = (slot++ << 2) | (pci->irq - 1); + bus_id = 0; + *p++ = (irq_devno << 24) | (bus_id << 16) | (0 << 8) | (iosapic_intin << 0); + *p++ = IOSAPIC_HPA >> 32; + *p++ = (u32) IOSAPIC_HPA; + iosapic_intin++; + iosapic_intin &= (ELROY_IRQS - 1 ); + } +} + static int pdc_pci_index(unsigned int *arg) { unsigned long option = ARG1; unsigned long *result = (unsigned long *)ARG2; + /* machines with Dino don't provide this info */ // dprintf(0, "\n\nSeaBIOS: PDC_PCI_INDEX(%lu) called with ARG2=%x ARG3=%x ARG4=%x\n", option, ARG2, ARG3, ARG4); switch (option) { case PDC_PCI_INTERFACE_INFO: memset(result, 0, 32 * sizeof(unsigned long)); + // BUG_ON(1); result[0] = 2; /* XXX physical hardware returns those ?!? */ - result[16] = 0x60; - result[17] = 0x90; return PDC_OK; case PDC_PCI_GET_INT_TBL_SIZE: + if (!has_astro) + return PDC_BAD_OPTION; + result[0] = irt_table_entries; + return PDC_OK; case PDC_PCI_GET_INT_TBL: - memset(result, 0, 32 * sizeof(unsigned long)); - result[0] = 2; /* Hardware fills in, even though we return PDC_BAD_OPTION below. */ - result[16] = 0x60; - result[17] = 0x90; - return PDC_BAD_OPTION; + if (!has_astro) + return PDC_BAD_OPTION; + result[0] = irt_table_entries; + /* ARG4 is ptr to irt table */ + memcpy((void *)ARG4, irt_table, irt_table_entries * 16); + return PDC_OK; case PDC_PCI_PCI_PATH_TO_PCI_HPA: - result[0] = PCI_HPA; + BUG_ON(1); + result[0] = pci_hpa; return PDC_OK; case PDC_PCI_PCI_HPA_TO_PCI_PATH: BUG_ON(1); + break; } return PDC_BAD_OPTION; } @@ -1525,6 +1992,8 @@ static int pdc_initiator(unsigned int *arg) switch (option) { case PDC_GET_INITIATOR: + /* SCSI controller is on normal PCI bus on machines with Astro */ + if (has_astro) return PDC_BAD_OPTION; // ARG3 points to the hwpath of device for which initiator is asked for. result[0] = 7; // initiator_id/host_id: 7 to 15. result[1] = 10; // scsi_rate: 1, 2, 5 or 10 for 5, 10, 20 or 40 MT/s @@ -2047,56 +2516,112 @@ static struct pz_device mem_kbd_boot = { .cl_class = CL_KEYBD, }; -static const struct pz_device mem_boot_boot = { - .dp.flags = PF_AUTOBOOT, - .hpa = IDE_HPA, // DINO_SCSI_HPA, // IDE_HPA +static struct pz_device mem_boot_boot = { + .dp.path.flags = PF_AUTOBOOT, + .hpa = DINO_SCSI_HPA, // will be overwritten .iodc_io = (unsigned long) &iodc_entry, .cl_class = CL_RANDOM, }; -static void find_pci_slot_for_dev(unsigned int pciid, char *pci_slot) +#if 0 +static void find_pci_slot_for_dev(unsigned int vendor, char *pci_slot) { struct pci_device *pci; foreachpci(pci) - if (pci->vendor == pciid) { + if (pci->vendor == vendor) { *pci_slot = (pci->bdf >> 3) & 0x0f; return; } } +#endif + +/* find serial PCI card (to be used as console) */ +static void find_serial_pci_card(void) +{ + struct pci_device *pci; + hppa_device_t *pdev; + u32 pmem; + + if (!has_astro) /* use built-in LASI serial port for console */ + return; + + pci = pci_find_class(PCI_CLASS_COMMUNICATION_SERIAL); + if (!pci) + return; + + dprintf(1, "PCI: Enabling %pP for primary SERIAL PORT\n", pci); + pci_config_maskw(pci->bdf, PCI_COMMAND, 0, + PCI_COMMAND_IO | PCI_COMMAND_MEMORY); + pmem = pci_enable_iobar(pci, PCI_BASE_ADDRESS_0); + dprintf(1, "PCI: Enabling %pP for primary SERIAL PORT mem %x\n", pci, pmem); + pmem += IOS_DIST_BASE_ADDR; + + /* set serial port for console output and keyboard input */ + pdev = &hppa_pci_devices[0]; + while (pdev->pci != pci) + pdev++; + pdev->pci_addr = pmem; + mem_cons_boot.hpa = pdev->hpa; + mem_kbd_boot.hpa = pdev->hpa; +} + +/* find SCSI PCI card (to be used as boot device) */ +static void find_scsi_pci_card(void) +{ + struct pci_device *pci; + hppa_device_t *pdev; + u32 pmem; + + // if (!has_astro) return; + pci = pci_find_class(PCI_CLASS_STORAGE_SCSI); + if (!pci) + return; + dprintf(1, "PCI: Enabling %pP for primary SCSI PORT\n", pci); + pmem = pci_enable_iobar(pci, PCI_BASE_ADDRESS_0); + dprintf(1, "PCI: Enabling %pP for primary SCSI PORT mem %x\n", pci, pmem); + pmem += IOS_DIST_BASE_ADDR; + + /* set SCSI HPA */ + pdev = &hppa_pci_devices[0]; + while (pdev->pci != pci) + pdev++; + pdev->pci_addr = pmem; + mem_boot_boot.hpa = pdev->hpa; + dprintf(1, "PCI: Enabling BOOT DEVICE HPA %x\n", mem_boot_boot.hpa); +} + /* Prepare boot paths in PAGE0 and stable memory */ static void prepare_boot_path(volatile struct pz_device *dest, const struct pz_device *source, unsigned int stable_offset) { - int hpa_index; + hppa_device_t *dev; unsigned long hpa; struct pdc_module_path *mod_path; hpa = source->hpa; - hpa_index = find_hpa_index(hpa); + dev = find_hpa_device(hpa); + BUG_ON(!dev); - if (HPA_is_storage_device(hpa)) + if (DEV_is_storage_device(dev)) mod_path = &mod_path_emulated_drives; - else if (hpa == LASI_UART_HPA) // HPA_is_serial_device(hpa)) - mod_path = &mod_path_hpa_ffd05000; - else if (hpa == DINO_UART_HPA) // HPA_is_serial_device(hpa)) - mod_path = &mod_path_hpa_fff83000; + else if (dev) + mod_path = dev->mod_path; else { - BUG_ON(hpa_index < 0); - mod_path = parisc_devices[hpa_index].mod_path; + BUG_ON(1); } /* copy device path to entry in PAGE0 */ memcpy((void*)dest, source, sizeof(*source)); - memcpy((void*)&dest->dp, mod_path, sizeof(struct device_path)); + memcpy((void*)&dest->dp, mod_path, sizeof(struct pdc_module_path)); /* copy device path to stable storage */ memcpy(&stable_storage[stable_offset], mod_path, sizeof(*mod_path)); BUG_ON(sizeof(*mod_path) != 0x20); - BUG_ON(sizeof(struct device_path) != 0x20); + BUG_ON(sizeof(struct pdc_module_path) != 0x20); } static int artist_present(void) @@ -2132,6 +2657,14 @@ void __VISIBLE start_parisc_firmware(void) char bootdrive = (char)cmdline; // c = hdd, d = CD/DVD show_boot_menu = (linux_kernel_entry == 1); + // detect if we emulate a 32- or 64-bit CPU. + // set all bits in cr11, read back, and if the return + // value is 63 this is a 64-bit capable CPU. + // A 32-bit only CPU returns 31. + mtctl(-1UL, 11); + cpu_bit_width = (mfctl(11) == 63) ? 64 : 32; + // cpu_bit_width = 64; /* XXX HACK */ + if (smp_cpus > HPPA_MAX_CPUS) smp_cpus = HPPA_MAX_CPUS; num_online_cpus = smp_cpus; @@ -2142,6 +2675,8 @@ void __VISIBLE start_parisc_firmware(void) /* Initialize malloc stack */ malloc_preinit(); + // PlatformRunningOn = PF_QEMU; // emulate runningOnQEMU() + /* Initialize qemu fw_cfg interface */ PORT_QEMU_CFG_CTL = fw_cfg_port; qemu_cfg_init(); @@ -2149,27 +2684,47 @@ void __VISIBLE start_parisc_firmware(void) /* Initialize boot structures. Needs working fw_cfg for bootprio option. */ boot_init(); + DebugOutputPort = romfile_loadint("/etc/hppa/DebugOutputPort", CPU_HPA + 24); + i = romfile_loadint("/etc/firmware-min-version", 0); if (i && i > SEABIOS_HPPA_VERSION) { printf("\nSeaBIOS firmware is version %d, but version %d is required. " "Please update.\n", (int)SEABIOS_HPPA_VERSION, i); hlt(); } - /* Qemu versions which request a SEABIOS_HPPA_VERSION < 6 have the bug that - * they use the DINO UART instead of the LASI UART as serial port #0. - * Fix it up here and switch the serial console code to use PORT_SERIAL2 - * for such Qemu versions, so that we can still use this higher SeaBIOS - * version with older Qemus. */ - if (i < 6) { - mem_cons_boot.hpa = PORT_SERIAL2 - 0x800; - mem_kbd_boot.hpa = PORT_SERIAL2 - 0x800; - } + + /* which machine shall we emulate? */ + str = romfile_loadfile("/etc/hppa/machine", NULL); + if (!str) { + str = "B160L"; + current_machine = &machine_B160L; + pci_hpa = DINO_HPA; + hppa_port_pci_cmd = pci_hpa + DINO_PCI_ADDR; + hppa_port_pci_data = pci_hpa + DINO_CONFIG_DATA; + } + if (strcmp(str, "C3700") == 0) { + has_astro = 1; + current_machine = &machine_C3700; + pci_hpa = (unsigned long) ELROY0_BASE_HPA; + hppa_port_pci_cmd = pci_hpa + 0x040; + hppa_port_pci_data = pci_hpa + 0x048; + /* no serial port for now, will find later */ + mem_cons_boot.hpa = 0; + mem_kbd_boot.hpa = 0; + } + parisc_devices = current_machine->device_list; + strtcpy(qemu_machine, str, sizeof(qemu_machine)); tlb_entries = romfile_loadint("/etc/cpu/tlb_entries", 256); dprintf(0, "fw_cfg: TLB entries %d\n", tlb_entries); powersw_ptr = (int *) (unsigned long) - romfile_loadint("/etc/power-button-addr", (unsigned long)&powersw_nop); + romfile_loadint("/etc/hppa/power-button-addr", (unsigned long)&powersw_nop); + + /* real-time-clock addr */ + rtc_ptr = (int *) (unsigned long) + romfile_loadint("/etc/hppa/rtc-addr", (unsigned long) LASI_RTC_HPA); + // dprintf(0, "RTC PTR 0x%x\n", (int)rtc_ptr); /* use -fw_cfg opt/pdc_debug,string=255 to enable all firmware debug infos */ pdc_debug = romfile_loadstring_to_int("opt/pdc_debug", 0); @@ -2186,8 +2741,9 @@ void __VISIBLE start_parisc_firmware(void) /* 0,1 = default 8x16 font, 2 = 16x32 font */ sti_font = romfile_loadstring_to_int("opt/font", 0); - model.sw_id = romfile_loadstring_to_int("opt/hostid", model.sw_id); - dprintf(0, "fw_cfg: machine hostid %lu\n", model.sw_id); + current_machine->pdc_model.sw_id = romfile_loadstring_to_int("opt/hostid", + current_machine->pdc_model.sw_id); + dprintf(0, "fw_cfg: machine hostid %lu\n", current_machine->pdc_model.sw_id); str = romfile_loadfile("/etc/qemu-version", NULL); if (str) @@ -2220,7 +2776,7 @@ void __VISIBLE start_parisc_firmware(void) PAGE0->pad0[3] = PORT_QEMU_CFG_CTL; *powersw_ptr = 0x01; /* button not pressed, hw controlled. */ - PAGE0->imm_hpa = MEMORY_HPA; + /* PAGE0->imm_hpa - is set later (MEMORY_HPA) */ PAGE0->imm_spa_size = ram_size; PAGE0->imm_max_mem = ram_size; @@ -2229,29 +2785,18 @@ void __VISIBLE start_parisc_firmware(void) sti_rom_init(); sti_console_init(&sti_proc_rom); PAGE0->proc_sti = (u32)&sti_proc_rom; - ps2port_setup(); + if (has_astro) + kbd_init(); + else + ps2port_setup(); } else { remove_from_keep_list(LASI_GFX_HPA); remove_from_keep_list(LASI_PS2KBD_HPA); remove_from_keep_list(LASI_PS2MOU_HPA); } - // Initialize boot paths (graphics & keyboard) - if (pdc_console == CONSOLE_DEFAULT) { - if (artist_present()) - pdc_console = CONSOLE_GRAPHICS; - else - pdc_console = CONSOLE_SERIAL; - } - if (pdc_console == CONSOLE_GRAPHICS) { - prepare_boot_path(&(PAGE0->mem_cons), &mem_cons_sti_boot, 0x60); - prepare_boot_path(&(PAGE0->mem_kbd), &mem_kbd_sti_boot, 0xa0); - } else { - prepare_boot_path(&(PAGE0->mem_cons), &mem_cons_boot, 0x60); - prepare_boot_path(&(PAGE0->mem_kbd), &mem_kbd_boot, 0xa0); - } - /* Initialize device list */ + keep_add_generic_devices(); remove_parisc_devices(smp_cpus); /* Show list of HPA devices which are still returned by firmware. */ @@ -2264,13 +2809,9 @@ void __VISIBLE start_parisc_firmware(void) chassis_code = 0; - // set Qemu serial debug port - DebugOutputPort = PARISC_SERIAL_CONSOLE; - // PlatformRunningOn = PF_QEMU; // emulate runningOnQEMU() - cpu_hz = 100 * PAGE0->mem_10msec; /* Hz of this PARISC */ - dprintf(1, "\nPARISC SeaBIOS Firmware, %d x PA7300LC (PCX-L2) at %d.%06d MHz, %d MB RAM.\n", - smp_cpus, cpu_hz / 1000000, cpu_hz % 1000000, + dprintf(1, "\nPARISC SeaBIOS Firmware, %d x %d-bit PA-RISC CPU at %d.%06d MHz, %d MB RAM.\n", + smp_cpus, cpu_bit_width, cpu_hz / 1000000, cpu_hz % 1000000, ram_size/1024/1024); if (ram_size < MIN_RAM_SIZE) { @@ -2289,10 +2830,36 @@ void __VISIBLE start_parisc_firmware(void) // coreboot_preinit(); pci_setup(); + if (has_astro) { + iosapic_table_setup(); + } + hppa_pci_build_devices_list(); + + /* find serial PCI card when running on Astro */ + find_serial_pci_card(); serial_setup(); + // ohci_setup(); block_setup(); + /* find SCSI PCI card when running on Astro or Dino */ + find_scsi_pci_card(); + + // Initialize boot paths (graphics & keyboard) + if (pdc_console != CONSOLE_SERIAL) { + if (artist_present()) + pdc_console = CONSOLE_GRAPHICS; + else + pdc_console = CONSOLE_SERIAL; + } + if (pdc_console == CONSOLE_GRAPHICS) { + prepare_boot_path(&(PAGE0->mem_cons), &mem_cons_sti_boot, 0x60); + prepare_boot_path(&(PAGE0->mem_kbd), &mem_kbd_sti_boot, 0xa0); + } else { + prepare_boot_path(&(PAGE0->mem_cons), &mem_cons_boot, 0x60); + prepare_boot_path(&(PAGE0->mem_kbd), &mem_kbd_boot, 0xa0); + } + PAGE0->vec_rendz = 0; /* No rendezvous yet. Add MEM_RENDEZ_HI later */ printf("\n"); @@ -2310,8 +2877,10 @@ void __VISIBLE start_parisc_firmware(void) " MHz %s Functional 0 KB\n", i < 10 ? " ":"", i, i?"Idle ":"Active"); printf("\n\n"); - printf(" Available memory: %u MB\n" + printf(" Emulated machine: HP %s (%d-bit %s)\n" + " Available memory: %u MB\n" " Good memory required: %d MB\n\n", + qemu_machine, cpu_bit_width, (cpu_bit_width == 64) ? "PA2.0" : "PA1.1", ram_size/1024/1024, MIN_RAM_SIZE/1024/1024); // search boot devices @@ -2332,8 +2901,7 @@ void __VISIBLE start_parisc_firmware(void) boot_drive = parisc_boot_cdrom; // Find PCI bus id of LSI SCSI card - find_pci_slot_for_dev(PCI_VENDOR_ID_LSI_LOGIC, - &mod_path_emulated_drives.path.bc[5]); + // find_pci_slot_for_dev(PCI_VENDOR_ID_LSI_LOGIC, &mod_path_emulated_drives.path.bc[5]); // Store initial emulated drives path master data if (parisc_boot_harddisc) { diff --git a/src/parisc/pdc.h b/src/parisc/pdc.h index bf6dd64..b152534 100644 --- a/src/parisc/pdc.h +++ b/src/parisc/pdc.h @@ -186,6 +186,9 @@ #define PDC_SCSI_GET_PARMS 0 /* Get SCSI parameters for I/O device */ #define PDC_SCSI_SET_PARMS 1 /* Set SCSI parameters for I/O device */ +#define PDC_PAT_CELL 64 +#define PDC_PAT_CHASSIS_LOG 65 + /* HVERSION dependent */ /* The PDC_MEM_MAP calls */ @@ -363,20 +366,25 @@ #if !defined(__ASSEMBLY__) -/* flags of the device_path */ +/* flags for hardware_path */ #define PF_AUTOBOOT 0x80 #define PF_AUTOSEARCH 0x40 #define PF_TIMER 0x0F -struct device_path { /* page 1-69 */ - unsigned char flags; /* flags see above! */ - unsigned char bc[6]; /* bus converter routing info */ - unsigned char mod; - unsigned int layers[6];/* device-specific layer-info */ -} __attribute__((aligned(8))) ; +struct hardware_path { + unsigned char flags; /* see bit definitions below */ + signed char bc[6]; /* Bus Converter routing info to a specific */ + /* I/O adaptor (< 0 means none, > 63 resvd) */ + signed char mod; /* fixed field of specified module */ +}; + +struct pdc_module_path { /* page 1-69 */ + struct hardware_path path; + unsigned int layers[6]; /* device-specific info (ctlr #, unit # ...) */ +} __attribute__((aligned(8))); struct pz_device { - struct device_path dp; /* see above */ + struct pdc_module_path dp; /* see above */ /* struct iomod *hpa; */ unsigned int hpa; /* HPA base address */ /* char *spa; */ @@ -617,21 +625,6 @@ struct pdc_initiator { /* PDC_INITIATOR */ int mode; }; -struct hardware_path { - char flags; /* see bit definitions below */ - char bc[6]; /* Bus Converter routing info to a specific */ - /* I/O adaptor (< 0 means none, > 63 resvd) */ - char mod; /* fixed field of specified module */ -}; - -/* - * Device path specifications used by PDC. - */ -struct pdc_module_path { - struct hardware_path path; - unsigned int layers[6]; /* device-specific info (ctlr #, unit # ...) */ -}; - /* Only used on some pre-PA2.0 boxes */ struct pdc_memory_map { /* PDC_MEMORY_MAP */ unsigned long hpa; /* mod's register set address */ diff --git a/src/parisc/stirom.c b/src/parisc/stirom.c index 4c41d7c..ddc6285 100644 --- a/src/parisc/stirom.c +++ b/src/parisc/stirom.c @@ -3281,7 +3281,7 @@ struct sti_rom __stiheader sti_proc_rom = { static void __stitext write_artist(struct sti_glob_cfg *cfg, int reg, u32 val) { - writel((void *)cfg->region_ptrs[2] + reg, val); + gsc_writel((void *)cfg->region_ptrs[2] + reg, val); } static int __stifunc("state_mgmt") sti_state_mgmt(struct sti_state_flags *flags, -- cgit v1.1