aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHelge Deller <deller@gmx.de>2023-10-14 13:25:39 +0200
committerHelge Deller <deller@gmx.de>2023-10-14 13:39:42 +0200
commit463ee8f95c95e077806d5c838b114135ed3b7922 (patch)
tree9cbbbd81b21eec14b8b2ba2fe2598b3d9f1e5bd4
parent54bb4a2b60916685ae3b29c7920cf9e8047a3efe (diff)
downloadseabios-hppa-463ee8f95c95e077806d5c838b114135ed3b7922.zip
seabios-hppa-463ee8f95c95e077806d5c838b114135ed3b7922.tar.gz
seabios-hppa-463ee8f95c95e077806d5c838b114135ed3b7922.tar.bz2
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 <deller@gmx.de>
-rw-r--r--src/boot.c6
-rw-r--r--src/fw/pciinit.c81
-rw-r--r--src/hw/pci.c67
-rw-r--r--src/hw/pcidevice.c5
-rw-r--r--src/hw/pcidevice.h1
-rw-r--r--src/parisc/b160l.h4
-rw-r--r--src/parisc/c3700.h285
-rw-r--r--src/parisc/hppa.h67
-rw-r--r--src/parisc/hppa_hardware.h26
-rw-r--r--src/parisc/lasips2.c11
-rw-r--r--src/parisc/machine-create.h20
-rw-r--r--src/parisc/parisc.c986
-rw-r--r--src/parisc/pdc.h39
-rw-r--r--src/parisc/stirom.c2
14 files changed, 1339 insertions, 261 deletions
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 <svens@stackframe.org>
//
// 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) ?
+ &current_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,