aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHelge Deller <deller@gmx.de>2021-02-11 05:55:50 +0100
committerHelge Deller <deller@gmx.de>2021-09-24 11:10:17 +0200
commit9ad8204cdee38c403de1f40b189388fdd3daba7c (patch)
tree22455d506089c9553a22fe6ac957ae58251f26de
parentd58fd429bfa6b94442907132519bfe07dd21b219 (diff)
downloadseabios-hppa-9ad8204cdee38c403de1f40b189388fdd3daba7c.zip
seabios-hppa-9ad8204cdee38c403de1f40b189388fdd3daba7c.tar.gz
seabios-hppa-9ad8204cdee38c403de1f40b189388fdd3daba7c.tar.bz2
parisc: Add PA-RISC related code
This patch adds the various drivers for PA-RISC. To build the parisc firmware enable CONFIG_PARISC and run "make parisc". Signed-off-by: Helge Deller <deller@gmx.de>
-rw-r--r--Makefile9
-rw-r--r--Makefile.parisc192
-rw-r--r--src/parisc/b160l.h630
-rw-r--r--src/parisc/head.S319
-rw-r--r--src/parisc/hppa.h370
-rw-r--r--src/parisc/hppa_hardware.h49
-rw-r--r--src/parisc/lasips2.c66
-rw-r--r--src/parisc/lasips2.h17
-rw-r--r--src/parisc/malloc.c91
-rw-r--r--src/parisc/pafirmware.lds.S69
-rw-r--r--src/parisc/parisc.c1997
-rw-r--r--src/parisc/pdc.h694
-rw-r--r--src/parisc/sti.c179
-rw-r--r--src/parisc/sticore.h326
-rw-r--r--src/parisc/stirom.c652
-rw-r--r--src/parisc/timer.c103
16 files changed, 5762 insertions, 1 deletions
diff --git a/Makefile b/Makefile
index c108f87..4eae0f2 100644
--- a/Makefile
+++ b/Makefile
@@ -95,6 +95,7 @@ endif
-include $(KCONFIG_CONFIG)
target-y :=
+target-$(CONFIG_PARISC) += $(OUT)hppa-warning.bin
target-$(CONFIG_QEMU) += $(OUT)bios.bin
target-$(CONFIG_CSM) += $(OUT)Csm16.bin
target-$(CONFIG_COREBOOT) += $(OUT)bios.bin.elf
@@ -102,8 +103,11 @@ target-$(CONFIG_BUILD_VGABIOS) += $(OUT)vgabios.bin
all: $(target-y)
+parisc: FORCE
+ DIRS="" $(MAKE) -f Makefile.parisc all
+
# Make definitions
-.PHONY : all clean distclean FORCE
+.PHONY : all clean distclean parisc FORCE
.DELETE_ON_ERROR:
@@ -209,6 +213,9 @@ $(OUT)bios.bin.elf: $(OUT)rom.o $(OUT)bios.bin.prep
@echo " Creating $@"
$(Q)$(STRIP) -R .comment $< -o $(OUT)bios.bin.elf
+$(OUT)hppa-warning.bin:
+ @echo " Run 'make parisc' to build parisc firmware"
+ @/bin/false
################ VGA build rules
diff --git a/Makefile.parisc b/Makefile.parisc
new file mode 100644
index 0000000..af4bb8e
--- /dev/null
+++ b/Makefile.parisc
@@ -0,0 +1,192 @@
+# SeaBIOS build system for PA-RISC
+#
+# Copyright (C) 2017-2021 Helge Deller <deller@gmx.de> for PA-RISC
+#
+# This file may be distributed under the terms of the GNU LGPLv3 license.
+
+# Output directory
+OUT=out/
+
+# Common command definitions
+export HOSTCC := $(CC)
+export CONFIG_SHELL := sh
+export KCONFIG_AUTOHEADER := autoconf.h
+export KCONFIG_CONFIG := $(CURDIR)/.config
+export LC_ALL := C
+CROSS_PREFIX=hppa-linux-gnu-
+ifneq ($(CROSS_PREFIX),)
+CC=$(CROSS_PREFIX)gcc
+LIBGCC = $(shell $(CC) $(KBUILD_CFLAGS) -print-libgcc-file-name)
+endif
+AS=$(CROSS_PREFIX)as
+LD=$(CROSS_PREFIX)ld
+OBJCOPY=$(CROSS_PREFIX)objcopy
+OBJDUMP=$(CROSS_PREFIX)objdump
+STRIP=$(CROSS_PREFIX)strip
+PYTHON=python
+CPP=cpp
+IASL:=iasl
+LD32BIT_FLAG:=
+
+# Source files
+# misc.c stacks.c system.c resume.c pcibios.c hw/timer.c
+SRCBOTH=output.c string.c block.c cdrom.c disk.c kbd.c \
+ serial.c sercon.c clock.c vgahooks.c \
+ apm.c cp437.c \
+ hw/pci.c hw/rtc.c hw/dma.c hw/pic.c hw/serialio.c \
+ hw/usb.c hw/usb-uhci.c hw/usb-ohci.c hw/usb-ehci.c \
+ hw/usb-hid.c hw/usb-msc.c hw/usb-uas.c \
+ hw/blockcmd.c hw/floppy.c hw/ata.c hw/ramdisk.c \
+ hw/lsi-scsi.c hw/esp-scsi.c hw/megasas.c hw/mpt-scsi.c \
+ parisc/timer.c
+# x86.c fw/smp.c fw/mttr.c malloc.c
+SRC32FLAT=$(SRCBOTH) post.c e820map.c romfile.c optionroms.c \
+ pmm.c font.c boot.c bootsplash.c jpeg.c bmp.c tcgbios.c sha1.c \
+ hw/pcidevice.c hw/ahci.c hw/pvscsi.c hw/usb-xhci.c hw/usb-hub.c hw/sdcard.c \
+ fw/coreboot.c fw/lzmadecode.c fw/multiboot.c fw/csm.c fw/biostables.c \
+ fw/paravirt.c fw/shadow.c fw/pciinit.c fw/smm.c fw/xen.c \
+ fw/acpi.c fw/mptable.c fw/pirtable.c fw/smbios.c fw/romfile_loader.c \
+ hw/virtio-ring.c hw/virtio-pci.c hw/virtio-blk.c hw/virtio-scsi.c \
+ hw/tpm_drivers.c hw/nvme.c \
+ version.c parisc/malloc.c parisc/parisc.c parisc/sti.c parisc/lasips2.c parisc/stirom.c
+DIRS=src src/hw src/fw vgasrc src/parisc
+
+# VGA src files
+SRCVGA=vgasrc/vgainit.c vgasrc/vgabios.c vgasrc/vgafb.c vgasrc/swcursor.c \
+ vgasrc/vgafonts.c vgasrc/vbe.c \
+ vgasrc/stdvga.c vgasrc/stdvgamodes.c vgasrc/stdvgaio.c \
+ vgasrc/clext.c vgasrc/bochsvga.c \
+ vgasrc/cbvga.c
+
+
+# Default compiler flags
+cc-option=$(shell if test -z "`$(1) $(2) -S -o /dev/null -xc /dev/null 2>&1`" \
+ ; then echo "$(2)"; else echo "$(3)"; fi ;)
+
+EXTRAVERSION=
+
+CPPFLAGS = -P -MD -MT $@
+
+COMMONCFLAGS := -I$(OUT) -Isrc -Ivgasrc -Os -MD -g \
+ -Wall -Wno-strict-aliasing -Wold-style-definition \
+ $(call cc-option,$(CC),-Wtype-limits,) \
+ -fomit-frame-pointer \
+ -freg-struct-return -ffreestanding -fno-delete-null-pointer-checks \
+ -fdata-sections -fno-common -fno-merge-constants -mdisable-fpregs \
+ -fno-builtin-printf -fno-ipa-sra
+COMMONCFLAGS += $(call cc-option,$(CC),-nopie,)
+COMMONCFLAGS += $(call cc-option,$(CC),-fno-pie,)
+COMMONCFLAGS += $(call cc-option,$(CC),-fno-stack-protector,)
+COMMONCFLAGS += $(call cc-option,$(CC),-fno-stack-protector-all,)
+COMMONCFLAGS += $(call cc-option,$(CC),-fstack-check=no,)
+COMMONCFLAGS += $(call cc-option,$(CC),-mfast-indirect-calls,)
+COMMA := ,
+
+CFLAGS32FLAT := $(COMMONCFLAGS) -DMODE16=0 -DMODESEGMENT=0
+CFLAGS16 := $(CFLAGS32FLAT) -I$(OUT)
+
+# Run with "make V=1" to see the actual compile commands
+ifdef V
+Q=
+else
+Q=@
+MAKEFLAGS += --no-print-directory
+endif
+
+# Default targets
+-include $(KCONFIG_CONFIG)
+
+target-y :=
+target-$(CONFIG_PARISC) += $(OUT)hppa-firmware.img
+
+all: $(target-y)
+
+# Make definitions
+.PHONY : all clean distclean FORCE
+.DELETE_ON_ERROR:
+
+
+################ Common build rules
+
+# Verify the build environment works.
+TESTGCC:=$(shell OUT="$(OUT)" CC="$(CC)" LD="$(LD)" IASL="$(IASL)" scripts/test-build.sh)
+ifeq "$(TESTGCC)" "-1"
+$(error "Please upgrade the build environment")
+endif
+
+ifeq "$(TESTGCC)" "0"
+# Use -fwhole-program
+CFLAGSWHOLE=-fwhole-program -DWHOLE_PROGRAM
+endif
+
+# Do a whole file compile by textually including all C code.
+define whole-compile
+@echo " Compiling whole program $3"
+$(Q)printf '$(foreach i,$2,#include "$i"\n)' > $3.tmp.c
+$(Q)$(CC) -I. $1 $(CFLAGSWHOLE) -c $3.tmp.c -o $3
+endef
+
+%.strip.o: %.o
+ @echo " Stripping $@"
+ $(Q)$(STRIP) $< -o $@
+
+$(OUT)%.s: %.c
+ @echo " Compiling to assembler $@"
+ $(Q)$(CC) $(CFLAGS16) -S -c $< -o $@
+
+$(OUT)%.o: %.c $(OUT)autoconf.h
+ @echo " Compile checking $@"
+ $(Q)$(CC) $(CFLAGS32FLAT) -c $< -o $@
+
+$(OUT)%.lds: %.lds.S
+ @echo " Precompiling $@"
+ $(Q)$(CPP) $(CPPFLAGS) -D__ASSEMBLY__ $< -o $@
+
+$(OUT)head.o: src/parisc/head.S $(OUT)autoconf.h $(OUT)autoversion.h
+ @echo " Compile checking $@"
+ $(Q)$(CC) $(CFLAGS32FLAT) -D__ASSEMBLY__ -c $< -o $@
+
+
+################ Main BIOS build rules
+
+$(OUT)asm-offsets.s: $(OUT)autoconf.h
+
+$(OUT)asm-offsets.h: $(OUT)src/asm-offsets.s
+ @echo " Generating offset file $@"
+ $(Q)./scripts/gen-offsets.sh $< $@
+
+$(OUT)ccode32flat.o: $(OUT)autoversion.h $(OUT)autoconf.h $(patsubst %.c, $(OUT)src/%.o,$(SRC32FLAT)) ; $(call whole-compile, $(CFLAGS32FLAT), $(addprefix src/, $(SRC32FLAT)) $(SRCVGA),$@)
+
+$(OUT)autoversion.h:
+ $(Q)$(PYTHON) ./scripts/buildversion.py -e "$(EXTRAVERSION)" -t "$(CC);$(AS);$(LD);$(OBJCOPY);$(OBJDUMP);$(STRIP)" $(OUT)autoversion.h
+
+$(OUT)hppa-firmware.img: $(OUT)autoconf.h $(OUT)head.o $(OUT)ccode32flat.o src/version.c
+ @echo " Linking $@"
+ $(Q)$(CPP) $(CPPFLAGS) -Isrc -D__ASSEMBLY__ src/parisc/pafirmware.lds.S -o $(OUT)pafirmware.lds
+ $(Q)$(CC) $(CFLAGS32FLAT) -c src/version.c -o $(OUT)version.o
+ $(Q)$(LD) -N -T $(OUT)pafirmware.lds $(OUT)head.o $(OUT)version.o -X -o $@ -e startup --as-needed $(OUT)ccode32flat.o $(LIBGCC)
+
+################ Kconfig rules
+
+define do-kconfig
+$(Q)mkdir -p $(OUT)/scripts/kconfig/lxdialog
+$(Q)mkdir -p $(OUT)/include/config
+$(Q)mkdir -p $(addprefix $(OUT), $(DIRS))
+$(Q)$(MAKE) -C $(OUT) -f $(CURDIR)/scripts/kconfig/Makefile srctree=$(CURDIR) src=scripts/kconfig obj=scripts/kconfig Q=$(Q) Kconfig=$(CURDIR)/src/Kconfig $1
+endef
+
+$(OUT)autoconf.h : $(KCONFIG_CONFIG) ; $(call do-kconfig, silentoldconfig)
+$(KCONFIG_CONFIG): src/Kconfig vgasrc/Kconfig ; $(call do-kconfig, olddefconfig)
+%onfig: ; $(call do-kconfig, $@)
+help: ; $(call do-kconfig, $@)
+
+
+################ Generic rules
+
+clean:
+ $(Q)rm -rf $(OUT)
+
+distclean: clean
+ $(Q)rm -f .config .config.old
+
+-include $(OUT)*.d $(patsubst %,$(OUT)%/*.d,$(DIRS))
diff --git a/src/parisc/b160l.h b/src/parisc/b160l.h
new file mode 100644
index 0000000..0e057fa
--- /dev/null
+++ b/src/parisc/b160l.h
@@ -0,0 +1,630 @@
+/* AUTO-GENERATED FILE FOR QEMU */
+#define PARISC_MODEL "9000/778/B160L"
+#define PARISC_PDC_MODEL 0x5020, 0x481, 0x0,\
+0x2020202, 0x7794d7fe, 0x100000f0, 0x4, 0xba, 0xba
+#define PARISC_PDC_VERSION 0x0008
+#define PARISC_PDC_CPUID 0x01e8
+#define PARISC_PDC_CAPABILITIES 0x0002
+#define PARISC_PDC_ENTRY_ORG 0x4800
+#define PARISC_PDC_CACHE_INFO\
+ 0x10000, 0x41402000, 0x0000, 0x0020, 0x0400\
+ , 0x0002, 0x10000, 0x41402000, 0x0000, 0x0020\
+ , 0x0400, 0x0002, 0x0060, 0xd2000, 0x0000\
+ , 0x0000, 0x0001, 0x0000, 0x0000, 0x0001\
+ , 0x0001, 0x0060, 0xd2000, 0x0000, 0x0000\
+ , 0x0001, 0x0000, 0x0000, 0x0001, 0x0001
+
+#define HPA_ffc00000_DESCRIPTION "Phantom PseudoBC GSC+ Port"
+static struct pdc_system_map_mod_info mod_info_hpa_ffc00000 = {
+ .mod_addr = 0xffc00000,
+ .mod_pgs = 0x1,
+ .add_addrs = 0x0,
+};
+static struct pdc_module_path mod_path_hpa_ffc00000 = {
+ .path = { .flags = 0x0, .bc = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }, .mod = 0x8 },
+ .layers = { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }
+};
+static struct pdc_iodc iodc_data_hpa_ffc00000 = {
+ .hversion_model = 0x0050,
+ .hversion = 0x0040,
+ .spa = 0x0000,
+ .type = 0x0007,
+ .sversion_rev = 0x0000,
+ .sversion_model = 0x0000,
+ .sversion_opt = 0x0000,
+ .rev = 0x0000,
+ .dep = 0x0000,
+ .features = 0x0000,
+ .checksum = 0x0000,
+ .length = 0x0000,
+ /* pad: 0x0000, 0x0000 */
+};
+#define HPA_ffc00000_num_addr 0
+#define HPA_ffc00000_add_addr 0
+
+#define HPA_fff80000_DESCRIPTION "Dino PCI Bridge"
+static struct pdc_system_map_mod_info mod_info_hpa_fff80000 = {
+ .mod_addr = 0xfff80000,
+ .mod_pgs = 0x1,
+ .add_addrs = 0x0,
+};
+static struct pdc_module_path mod_path_hpa_fff80000 = {
+ .path = { .flags = 0x0, .bc = { 0xff, 0xff, 0xff, 0xff, 0xff, 0x8 }, .mod = 0x0 },
+ .layers = { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }
+};
+static struct pdc_iodc iodc_data_hpa_fff80000 = {
+ .hversion_model = 0x0068,
+ .hversion = 0x0003,
+ .spa = 0x0000,
+ .type = 0x004d,
+ .sversion_rev = 0x0000,
+ .sversion_model = 0x0005,
+ .sversion_opt = 0x0000,
+ .rev = 0x0000,
+ .dep = 0x0000,
+ .features = 0x0000,
+ .checksum = 0x0000,
+ .length = 0x0000,
+ /* pad: 0x0000, 0x0000 */
+};
+#define HPA_fff80000_num_addr 0
+#define HPA_fff80000_add_addr 0
+
+#define HPA_fff83000_DESCRIPTION "Merlin+ 132 Dino RS-232"
+static struct pdc_system_map_mod_info mod_info_hpa_fff83000 = {
+ .mod_addr = 0xfff83000,
+ .mod_pgs = 0x1,
+ .add_addrs = 0x0,
+};
+static struct pdc_module_path mod_path_hpa_fff83000 = {
+ .path = { .flags = 0x0, .bc = { 0xff, 0xff, 0xff, 0xff, 0x8, 0x0 }, .mod = 0x3f },
+ .layers = { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }
+};
+static struct pdc_iodc iodc_data_hpa_fff83000 = {
+ .hversion_model = 0x0002,
+ .hversion = 0x0020,
+ .spa = 0x0000,
+ .type = 0x008a,
+ .sversion_rev = 0x0000,
+ .sversion_model = 0x0046,
+ .sversion_opt = 0x0000,
+ .rev = 0x0000,
+ .dep = 0x0000,
+ .features = 0x0000,
+ .checksum = 0x6729,
+ .length = 0x0002,
+ /* pad: 0x0000, 0x0000 */
+};
+#define HPA_fff83000_num_addr 0
+#define HPA_fff83000_add_addr 0
+
+#define HPA_fff8c000_DESCRIPTION "Merlin 160 Core FW-SCSI"
+static struct pdc_system_map_mod_info mod_info_hpa_fff8c000 = {
+ .mod_addr = 0xfff8c000,
+ .mod_pgs = 0x1,
+ .add_addrs = 0x0,
+};
+static struct pdc_module_path mod_path_hpa_fff8c000 = {
+ .path = { .flags = 0x0, .bc = { 0xff, 0xff, 0xff, 0xff, 0xff, 0x8 }, .mod = 0xc },
+ .layers = { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }
+};
+static struct pdc_iodc iodc_data_hpa_fff8c000 = {
+ .hversion_model = 0x0003,
+ .hversion = 0x00d0,
+ .spa = 0x0000,
+ .type = 0x0084,
+ .sversion_rev = 0x0000,
+ .sversion_model = 0x0044,
+ .sversion_opt = 0x00c0,
+ .rev = 0x0099,
+ .dep = 0x0000,
+ .features = 0x0001,
+ .checksum = 0xc5e9,
+ .length = 0x0002,
+ /* pad: 0x0000, 0x0000 */
+};
+#define HPA_fff8c000_num_addr 0
+#define HPA_fff8c000_add_addr 0
+
+#define HPA_ffd00000_DESCRIPTION "Merlin 160 Core BA"
+static struct pdc_system_map_mod_info mod_info_hpa_ffd00000 = {
+ .mod_addr = 0xffd00000,
+ .mod_pgs = 0x1,
+ .add_addrs = 0x2,
+};
+static struct pdc_module_path mod_path_hpa_ffd00000 = {
+ .path = { .flags = 0x0, .bc = { 0xff, 0xff, 0xff, 0xff, 0xff, 0x8 }, .mod = 0x10 },
+ .layers = { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }
+};
+static struct pdc_iodc iodc_data_hpa_ffd00000 = {
+ .hversion_model = 0x0003,
+ .hversion = 0x00d0,
+ .spa = 0x0080,
+ .type = 0x004b,
+ .sversion_rev = 0x0000,
+ .sversion_model = 0x0040,
+ .sversion_opt = 0x0080,
+ .rev = 0x0000,
+ .dep = 0x0000,
+ .features = 0x0000,
+ .checksum = 0x0000,
+ .length = 0x0000,
+ /* pad: 0x0000, 0x0000 */
+};
+#define HPA_ffd00000_num_addr 2
+#define HPA_ffd00000_add_addr 0xffd0c000, 0xffc00000,
+
+#define HPA_ffd05000_DESCRIPTION "Merlin 160 Core RS-232"
+static struct pdc_system_map_mod_info mod_info_hpa_ffd05000 = {
+ .mod_addr = 0xffd05000,
+ .mod_pgs = 0x1,
+ .add_addrs = 0x0,
+};
+static struct pdc_module_path mod_path_hpa_ffd05000 = {
+ .path = { .flags = 0x0, .bc = { 0xff, 0xff, 0xff, 0xff, 0x8, 0x10 }, .mod = 0x4 },
+ .layers = { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }
+};
+static struct pdc_iodc iodc_data_hpa_ffd05000 = {
+ .hversion_model = 0x0003,
+ .hversion = 0x00d0,
+ .spa = 0x0000,
+ .type = 0x008a,
+ .sversion_rev = 0x0000,
+ .sversion_model = 0x0046,
+ .sversion_opt = 0x0000,
+ .rev = 0x0001,
+ .dep = 0x0000,
+ .features = 0x0000,
+ .checksum = 0x6309,
+ .length = 0x0002,
+ /* pad: 0x0000, 0x0000 */
+};
+#define HPA_ffd05000_num_addr 0
+#define HPA_ffd05000_add_addr 0
+
+#define HPA_ffd06000_DESCRIPTION "Merlin 160 Core SCSI"
+static struct pdc_system_map_mod_info mod_info_hpa_ffd06000 = {
+ .mod_addr = 0xffd06000,
+ .mod_pgs = 0x1,
+ .add_addrs = 0x0,
+};
+static struct pdc_module_path mod_path_hpa_ffd06000 = {
+ .path = { .flags = 0x0, .bc = { 0xff, 0xff, 0xff, 0xff, 0x8, 0x10 }, .mod = 0x5 },
+ .layers = { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }
+};
+static struct pdc_iodc iodc_data_hpa_ffd06000 = {
+ .hversion_model = 0x0003,
+ .hversion = 0x00d0,
+ .spa = 0x0080,
+ .type = 0x008a,
+ .sversion_rev = 0x0000,
+ .sversion_model = 0x0041,
+ .sversion_opt = 0x0000,
+ .rev = 0x0099,
+ .dep = 0x0000,
+ .features = 0x0001,
+ .checksum = 0x4d41,
+ .length = 0x0002,
+ /* pad: 0x0000, 0x0000 */
+};
+#define HPA_ffd06000_num_addr 0
+#define HPA_ffd06000_add_addr 0
+
+#define HPA_ffd07000_DESCRIPTION "Merlin 160 Core LAN (802.3)"
+static struct pdc_system_map_mod_info mod_info_hpa_ffd07000 = {
+ .mod_addr = 0xffd07000,
+ .mod_pgs = 0x1,
+ .add_addrs = 0x0,
+};
+static struct pdc_module_path mod_path_hpa_ffd07000 = {
+ .path = { .flags = 0x0, .bc = { 0xff, 0xff, 0xff, 0xff, 0x8, 0x10 }, .mod = 0x6 },
+ .layers = { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }
+};
+static struct pdc_iodc iodc_data_hpa_ffd07000 = {
+ .hversion_model = 0x0003,
+ .hversion = 0x00d0,
+ .spa = 0x0080,
+ .type = 0x008a,
+ .sversion_rev = 0x0000,
+ .sversion_model = 0x0045,
+ .sversion_opt = 0x0000,
+ .rev = 0x0002,
+ .dep = 0x0000,
+ .features = 0x0000,
+ .checksum = 0xd8fa,
+ .length = 0x0002,
+ /* pad: 0x0000, 0x0000 */
+};
+#define HPA_ffd07000_num_addr 0
+#define HPA_ffd07000_add_addr 0
+
+#define HPA_ffd02000_DESCRIPTION "Merlin 160 Core Centronics"
+static struct pdc_system_map_mod_info mod_info_hpa_ffd02000 = {
+ .mod_addr = 0xffd02000,
+ .mod_pgs = 0x1,
+ .add_addrs = 0x2,
+};
+static struct pdc_module_path mod_path_hpa_ffd02000 = {
+ .path = { .flags = 0x0, .bc = { 0xff, 0xff, 0xff, 0xff, 0x8, 0x10 }, .mod = 0x0 },
+ .layers = { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }
+};
+static struct pdc_iodc iodc_data_hpa_ffd02000 = {
+ .hversion_model = 0x0003,
+ .hversion = 0x00d0,
+ .spa = 0x0080,
+ .type = 0x000a,
+ .sversion_rev = 0x0000,
+ .sversion_model = 0x003a,
+ .sversion_opt = 0x0000,
+ .rev = 0x0000,
+ .dep = 0x0000,
+ .features = 0x0000,
+ .checksum = 0x0000,
+ .length = 0x0000,
+ /* pad: 0x0000, 0x0000 */
+};
+#define HPA_ffd02000_num_addr 2
+#define HPA_ffd02000_add_addr 0xffd01000, 0xffd03000,
+
+#define HPA_ffd04000_DESCRIPTION "Merlin 160 Core Audio"
+static struct pdc_system_map_mod_info mod_info_hpa_ffd04000 = {
+ .mod_addr = 0xffd04000,
+ .mod_pgs = 0x1,
+ .add_addrs = 0x0,
+};
+static struct pdc_module_path mod_path_hpa_ffd04000 = {
+ .path = { .flags = 0x0, .bc = { 0xff, 0xff, 0xff, 0xff, 0x8, 0x10 }, .mod = 0x1 },
+ .layers = { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }
+};
+static struct pdc_iodc iodc_data_hpa_ffd04000 = {
+ .hversion_model = 0x0003,
+ .hversion = 0x00d4,
+ .spa = 0x0080,
+ .type = 0x000a,
+ .sversion_rev = 0x0000,
+ .sversion_model = 0x003d,
+ .sversion_opt = 0x0080,
+ .rev = 0x0000,
+ .dep = 0x0000,
+ .features = 0x0000,
+ .checksum = 0x0000,
+ .length = 0x0000,
+ /* pad: 0x0000, 0x0000 */
+};
+#define HPA_ffd04000_num_addr 0
+#define HPA_ffd04000_add_addr 0
+
+#define HPA_ffd08000_DESCRIPTION "Merlin 160 Core PS/2 Port"
+static struct pdc_system_map_mod_info mod_info_hpa_ffd08000 = {
+ .mod_addr = 0xffd08000,
+ .mod_pgs = 0x1,
+ .add_addrs = 0x0,
+};
+static struct pdc_module_path mod_path_hpa_ffd08000 = {
+ .path = { .flags = 0x0, .bc = { 0xff, 0xff, 0xff, 0xff, 0x8, 0x10 }, .mod = 0x7 },
+ .layers = { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }
+};
+static struct pdc_iodc iodc_data_hpa_ffd08000 = {
+ .hversion_model = 0x0003,
+ .hversion = 0x00d0,
+ .spa = 0x0000,
+ .type = 0x008a,
+ .sversion_rev = 0x0000,
+ .sversion_model = 0x0042,
+ .sversion_opt = 0x0000,
+ .rev = 0x0000,
+ .dep = 0x0000,
+ .features = 0x0000,
+ .checksum = 0x6e05,
+ .length = 0x0002,
+ /* pad: 0x0000, 0x0000 */
+};
+#define HPA_ffd08000_num_addr 0
+#define HPA_ffd08000_add_addr 0
+
+#define HPA_ffd08100_DESCRIPTION "Merlin 160 Core PS/2 Port"
+static struct pdc_system_map_mod_info mod_info_hpa_ffd08100 = {
+ .mod_addr = 0xffd08100,
+ .mod_pgs = 0x1,
+ .add_addrs = 0x0,
+};
+static struct pdc_module_path mod_path_hpa_ffd08100 = {
+ .path = { .flags = 0x0, .bc = { 0xff, 0xff, 0xff, 0xff, 0x8, 0x10 }, .mod = 0x8 },
+ .layers = { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }
+};
+static struct pdc_iodc iodc_data_hpa_ffd08100 = {
+ .hversion_model = 0x0003,
+ .hversion = 0x00d0,
+ .spa = 0x0000,
+ .type = 0x000a,
+ .sversion_rev = 0x0000,
+ .sversion_model = 0x0042,
+ .sversion_opt = 0x0000,
+ .rev = 0x0000,
+ .dep = 0x0000,
+ .features = 0x0000,
+ .checksum = 0x0000,
+ .length = 0x0000,
+ /* pad: 0x0000, 0x0000 */
+};
+#define HPA_ffd08100_num_addr 0
+#define HPA_ffd08100_add_addr 0
+
+#define HPA_fa000000_DESCRIPTION "Coral SGC Graphics"
+static struct pdc_system_map_mod_info mod_info_hpa_fa000000 = {
+ .mod_addr = 0xfa000000,
+ .mod_pgs = 0x2000,
+ .add_addrs = 0x0,
+};
+static struct pdc_module_path mod_path_hpa_fa000000 = {
+ .path = { .flags = 0x0, .bc = { 0xff, 0xff, 0xff, 0xff, 0xff, 0x8 }, .mod = 0x4 },
+ .layers = { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }
+};
+static struct pdc_iodc iodc_data_hpa_fa000000 = {
+ .hversion_model = 0x0000,
+ .hversion = 0x0040,
+ .spa = 0x0000,
+ .type = 0x008a,
+ .sversion_rev = 0x0000,
+ .sversion_model = 0x003b,
+ .sversion_opt = 0x0080,
+ .rev = 0x00fa,
+ .dep = 0x0000,
+ .features = 0x0000,
+ .checksum = 0x67d0,
+ .length = 0x0002,
+ /* pad: 0x0000, 0x0000 */
+};
+#define HPA_fa000000_num_addr 0
+#define HPA_fa000000_add_addr 0
+
+#define HPA_f4000000_DESCRIPTION "Coral SGC Graphics"
+static struct pdc_system_map_mod_info mod_info_hpa_f4000000 = {
+ .mod_addr = 0xf4000000,
+ .mod_pgs = 0x2000,
+ .add_addrs = 0x0,
+};
+static struct pdc_module_path mod_path_hpa_f4000000 = {
+ .path = { .flags = 0x0, .bc = { 0xff, 0xff, 0xff, 0xff, 0xff, 0x8 }, .mod = 0x8 },
+ .layers = { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }
+};
+static struct pdc_iodc iodc_data_hpa_f4000000 = {
+ .hversion_model = 0x0000,
+ .hversion = 0x0040,
+ .spa = 0x0000,
+ .type = 0x008a,
+ .sversion_rev = 0x0000,
+ .sversion_model = 0x003b,
+ .sversion_opt = 0x0080,
+ .rev = 0x00f4,
+ .dep = 0x0000,
+ .features = 0x0000,
+ .checksum = 0x67d0,
+ .length = 0x0002,
+ /* pad: 0x0000, 0x0000 */
+};
+#define HPA_f4000000_num_addr 0
+#define HPA_f4000000_add_addr 0
+
+#define HPA_f8000000_DESCRIPTION "Gecko GSC Core Graphics"
+static struct pdc_system_map_mod_info mod_info_hpa_f8000000 = {
+ .mod_addr = 0xf8000000,
+ .mod_pgs = 0x2000,
+ .add_addrs = 0x1,
+};
+static struct pdc_module_path mod_path_hpa_f8000000 = {
+ .path = { .flags = 0x0, .bc = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }, .mod = 0x1 },
+ .layers = { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }
+};
+static struct pdc_iodc iodc_data_hpa_f8000000 = {
+ .hversion_model = 0x0001,
+ .hversion = 0x0060,
+ .spa = 0x0000,
+ .type = 0x008a,
+ .sversion_rev = 0x0000,
+ .sversion_model = 0x0042,
+ .sversion_opt = 0x0080,
+ .rev = 0x0001,
+ .dep = 0x0000,
+ .features = 0x0000,
+ .checksum = 0x67d0,
+ .length = 0x0002,
+ /* pad: 0x0000, 0x0000 */
+};
+#define HPA_f8000000_num_addr 0
+#define HPA_f8000000_add_addr 0
+
+#define HPA_fff10000_DESCRIPTION "Merlin L2 160 (9000/778/B160L)"
+static struct pdc_system_map_mod_info mod_info_hpa_fff10000 = {
+ .mod_addr = CPU_HPA,
+ .mod_pgs = 0x1,
+ .add_addrs = 0x0,
+};
+static struct pdc_module_path mod_path_hpa_fff10000 = {
+ .path = { .flags = 0x0, .bc = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }, .mod = 0x3e },
+ .layers = { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }
+};
+static struct pdc_iodc iodc_data_hpa_fff10000 = {
+ .hversion_model = 0x0050,
+ .hversion = 0x0020,
+ .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_fff10000_num_addr 0
+#define HPA_fff10000_add_addr 0
+
+#define HPA_fffbf000_DESCRIPTION "Memory"
+static struct pdc_system_map_mod_info mod_info_hpa_fffbf000 = {
+ .mod_addr = 0xfffbf000,
+ .mod_pgs = 0x1,
+ .add_addrs = 0x0,
+};
+static struct pdc_module_path mod_path_hpa_fffbf000 = {
+ .path = { .flags = 0x0, .bc = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }, .mod = 0x3f },
+ .layers = { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }
+};
+static struct pdc_iodc iodc_data_hpa_fffbf000 = {
+ .hversion_model = 0x0006,
+ .hversion = 0x0070,
+ .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_fffbf000_num_addr 0
+#define HPA_fffbf000_add_addr 0
+
+#define HPA_fff81000_DESCRIPTION "Merlin+ 132 Dino PS/2 Port"
+static struct pdc_system_map_mod_info mod_info_hpa_fff81000 = {
+ .mod_addr = 0x0,
+ .mod_pgs = 0x0,
+ .add_addrs = 0x0,
+};
+static struct pdc_module_path mod_path_hpa_fff81000 = {
+ .path = { .flags = 0x0, .bc = { 0xff, 0xff, 0xff, 0xff, 0xff, 0x8 }, .mod = 0x0 },
+ .layers = { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }
+};
+static struct pdc_iodc iodc_data_hpa_fff81000 = {
+ .hversion_model = 0x0002,
+ .hversion = 0x0020,
+ .spa = 0x0080,
+ .type = 0x004a,
+ .sversion_rev = 0x0000,
+ .sversion_model = 0x004b,
+ .sversion_opt = 0x0000,
+ .rev = 0x0000,
+ .dep = 0x0000,
+ .features = 0x0000,
+ .checksum = 0x0000,
+ .length = 0x0000,
+ /* pad: 0x0000, 0x0000 */
+};
+#define HPA_fff81000_num_addr 0
+#define HPA_fff81000_add_addr 0
+
+#define PARISC_DEVICE_LIST \
+ { .hpa = 0xffc00000,\
+ .iodc = &iodc_data_hpa_ffc00000,\
+ .mod_info = &mod_info_hpa_ffc00000,\
+ .mod_path = &mod_path_hpa_ffc00000,\
+ .num_addr = HPA_ffc00000_num_addr,\
+ .add_addr = { HPA_ffc00000_add_addr } },\
+ { .hpa = 0xfff80000,\
+ .iodc = &iodc_data_hpa_fff80000,\
+ .mod_info = &mod_info_hpa_fff80000,\
+ .mod_path = &mod_path_hpa_fff80000,\
+ .num_addr = HPA_fff80000_num_addr,\
+ .add_addr = { HPA_fff80000_add_addr } },\
+ { .hpa = 0xfff83000,\
+ .iodc = &iodc_data_hpa_fff83000,\
+ .mod_info = &mod_info_hpa_fff83000,\
+ .mod_path = &mod_path_hpa_fff83000,\
+ .num_addr = HPA_fff83000_num_addr,\
+ .add_addr = { HPA_fff83000_add_addr } },\
+ { .hpa = 0xfff8c000,\
+ .iodc = &iodc_data_hpa_fff8c000,\
+ .mod_info = &mod_info_hpa_fff8c000,\
+ .mod_path = &mod_path_hpa_fff8c000,\
+ .num_addr = HPA_fff8c000_num_addr,\
+ .add_addr = { HPA_fff8c000_add_addr } },\
+ { .hpa = 0xffd00000,\
+ .iodc = &iodc_data_hpa_ffd00000,\
+ .mod_info = &mod_info_hpa_ffd00000,\
+ .mod_path = &mod_path_hpa_ffd00000,\
+ .num_addr = HPA_ffd00000_num_addr,\
+ .add_addr = { HPA_ffd00000_add_addr } },\
+ { .hpa = 0xffd05000,\
+ .iodc = &iodc_data_hpa_ffd05000,\
+ .mod_info = &mod_info_hpa_ffd05000,\
+ .mod_path = &mod_path_hpa_ffd05000,\
+ .num_addr = HPA_ffd05000_num_addr,\
+ .add_addr = { HPA_ffd05000_add_addr } },\
+ { .hpa = 0xffd06000,\
+ .iodc = &iodc_data_hpa_ffd06000,\
+ .mod_info = &mod_info_hpa_ffd06000,\
+ .mod_path = &mod_path_hpa_ffd06000,\
+ .num_addr = HPA_ffd06000_num_addr,\
+ .add_addr = { HPA_ffd06000_add_addr } },\
+ { .hpa = 0xffd07000,\
+ .iodc = &iodc_data_hpa_ffd07000,\
+ .mod_info = &mod_info_hpa_ffd07000,\
+ .mod_path = &mod_path_hpa_ffd07000,\
+ .num_addr = HPA_ffd07000_num_addr,\
+ .add_addr = { HPA_ffd07000_add_addr } },\
+ { .hpa = 0xffd02000,\
+ .iodc = &iodc_data_hpa_ffd02000,\
+ .mod_info = &mod_info_hpa_ffd02000,\
+ .mod_path = &mod_path_hpa_ffd02000,\
+ .num_addr = HPA_ffd02000_num_addr,\
+ .add_addr = { HPA_ffd02000_add_addr } },\
+ { .hpa = 0xffd04000,\
+ .iodc = &iodc_data_hpa_ffd04000,\
+ .mod_info = &mod_info_hpa_ffd04000,\
+ .mod_path = &mod_path_hpa_ffd04000,\
+ .num_addr = HPA_ffd04000_num_addr,\
+ .add_addr = { HPA_ffd04000_add_addr } },\
+ { .hpa = 0xffd08000,\
+ .iodc = &iodc_data_hpa_ffd08000,\
+ .mod_info = &mod_info_hpa_ffd08000,\
+ .mod_path = &mod_path_hpa_ffd08000,\
+ .num_addr = HPA_ffd08000_num_addr,\
+ .add_addr = { HPA_ffd08000_add_addr } },\
+ { .hpa = 0xffd08100,\
+ .iodc = &iodc_data_hpa_ffd08100,\
+ .mod_info = &mod_info_hpa_ffd08100,\
+ .mod_path = &mod_path_hpa_ffd08100,\
+ .num_addr = HPA_ffd08100_num_addr,\
+ .add_addr = { HPA_ffd08100_add_addr } },\
+ { .hpa = 0xfa000000,\
+ .iodc = &iodc_data_hpa_fa000000,\
+ .mod_info = &mod_info_hpa_fa000000,\
+ .mod_path = &mod_path_hpa_fa000000,\
+ .num_addr = HPA_fa000000_num_addr,\
+ .add_addr = { HPA_fa000000_add_addr } },\
+ { .hpa = 0xf4000000,\
+ .iodc = &iodc_data_hpa_f4000000,\
+ .mod_info = &mod_info_hpa_f4000000,\
+ .mod_path = &mod_path_hpa_f4000000,\
+ .num_addr = HPA_f4000000_num_addr,\
+ .add_addr = { HPA_f4000000_add_addr } },\
+ { .hpa = 0xf8000000,\
+ .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,\
+ .iodc = &iodc_data_hpa_fff10000,\
+ .mod_info = &mod_info_hpa_fff10000,\
+ .mod_path = &mod_path_hpa_fff10000,\
+ .num_addr = HPA_fff10000_num_addr,\
+ .add_addr = { HPA_fff10000_add_addr } },\
+ { .hpa = 0xfffbf000,\
+ .iodc = &iodc_data_hpa_fffbf000,\
+ .mod_info = &mod_info_hpa_fffbf000,\
+ .mod_path = &mod_path_hpa_fffbf000,\
+ .num_addr = HPA_fffbf000_num_addr,\
+ .add_addr = { HPA_fffbf000_add_addr } },\
+ { .hpa = 0xfff81000,\
+ .iodc = &iodc_data_hpa_fff81000,\
+ .mod_info = &mod_info_hpa_fff81000,\
+ .mod_path = &mod_path_hpa_fff81000,\
+ .num_addr = HPA_fff81000_num_addr,\
+ .add_addr = { HPA_fff81000_add_addr } },\
+ { 0, }
diff --git a/src/parisc/head.S b/src/parisc/head.S
new file mode 100644
index 0000000..4869946
--- /dev/null
+++ b/src/parisc/head.S
@@ -0,0 +1,319 @@
+/*
+ * Startup glue code for parisc firmware
+ *
+ * (C) 2017-2021 Helge Deller <deller@gmx.de>
+ */
+
+#include "parisc/hppa_hardware.h"
+#include "autoconf.h"
+#include "autoversion.h"
+
+ /* load 32-bit 'value' into 'reg' compensating for the ldil
+ * sign-extension when running in wide mode.
+ * WARNING!! neither 'value' nor 'reg' can be expressions
+ * containing '.'!!!! */
+ .macro load32 value, reg
+ ldil L%\value, \reg
+ ldo R%\value(\reg), \reg
+ .endm
+
+#define ENTRY(name) \
+ .export name !\
+ .align 4 !\
+name:
+
+#define END(name) \
+ .size name, .-name
+
+#define ENDPROC(name) \
+ .type name, @function !\
+ END(name)
+
+#define BOOTADDR(x) (x)
+
+ .macro loadgp
+ ldil L%$global$, %r27
+ ldo R%$global$(%r27), %r27
+ .endm
+
+#ifdef CONFIG_64BIT
+#define LDREG ldd
+#define STREG std
+#define LDREGX ldd,s
+#define LDREGM ldd,mb
+#define STREGM std,ma
+#define SHRREG shrd
+#define SHLREG shld
+#define ANDCM andcm,*
+#define COND(x) * ## x
+#define RP_OFFSET 16
+#define FRAME_SIZE 128
+#define CALLEE_REG_FRAME_SIZE 144
+#define ASM_ULONG_INSN .dword
+#else /* CONFIG_64BIT */
+#define LDREG ldw
+#define STREG stw
+#define LDREGX ldwx,s
+#define LDREGM ldwm
+#define STREGM stwm
+#define SHRREG shr
+#define SHLREG shlw
+#define ANDCM andcm
+#define COND(x) x
+#define RP_OFFSET 20
+#define FRAME_SIZE 64
+#define CALLEE_REG_FRAME_SIZE 128
+#define ASM_ULONG_INSN .word
+#endif
+
+ .import $global$
+ .section ".head.text","ax"
+ .level 1.1
+
+ /* On HPMC, the CPUs will start here at 0xf0000000 */
+hpmc_entry:
+ b,n . /* TODO! */
+
+reset_entry:
+ /* at reset, the CPU begins fetching instructions from address 0xf0000004. */
+ b,n startup
+
+ /* file identification */
+ .stringz "PA-RISC/HPPA PDC Firmware (SeaBIOS fork)"
+ .stringz "https://github.com/hdeller/seabios-hppa"
+ .stringz BUILD_VERSION
+
+/*******************************************************
+ Firmware startup code
+ *******************************************************/
+
+ .align 0x80
+ENTRY(startup)
+ /* Make sure space registers are set to zero */
+ mtsp %r0,%sr0
+ mtsp %r0,%sr1
+ mtsp %r0,%sr2
+ mtsp %r0,%sr3
+ mtsp %r0,%sr4
+ mtsp %r0,%sr5
+ mtsp %r0,%sr6
+ mtsp %r0,%sr7
+
+#define PSW_W_SM 0x200
+#define PSW_W_BIT 36
+
+ ;! nuke the W bit
+ .level 2.0
+ rsm PSW_W_SM, %r0
+ .level 1.1
+
+ /* Save CPU HPA in cr7, hopefully HP-UX will not use that register. */
+ mtctl %r5, CPU_HPA_CR_REG /* store CPU HPA */
+
+ /* branch if this is the monarch cpu */
+ load32 CPU_HPA,%r1
+ comb,= %r5,%r1,$is_monarch_cpu
+ nop
+
+ENTRY(enter_smp_idle_loop)
+ /* IDLE LOOP for SMP CPUs - wait for rendenzvous. */
+ mfctl CPU_HPA_CR_REG, %r25 /* get CPU HPA from cr7 */
+
+ /* Load IVT for SMT tiny loop exit */
+#define CR_IVA 14
+ load32 BOOTADDR(smp_ivt),%r1
+ mtctl %r1, CR_IVA
+
+ /* enable CPU local interrupts */
+#define CR_EIEM 15
+#define PSW_I 1
+ ldi -1, %r1 /* allow IRQ0 (Timer) */
+ mtctl %r1, CR_EIEM
+ ssm PSW_I, %r9
+
+ /* endless idle loop, exits to $smp_exit_loop by IRQ only */
+$smp_idle_loop:
+ b $smp_idle_loop
+ or %r10,%r10,%r10
+
+$smp_exit_loop:
+ mtsm %r9
+ mtctl %r0, CR_EIEM
+
+ /* on 64bit: Address of PDCE_PROC for each non-monarch processor in GR26. */
+ load32 BOOTADDR(pdc_entry), %r26
+
+ /* jump to rendevouz */
+ ldw 0x10(%r0),%r3 /* MEM_RENDEZ */
+ /* ldw 0x28(%r0),%r0 MEM_RENDEZ_HI - assume addr < 4GB */
+ bv 0(%r3)
+ copy %r0,%r2
+
+
+$is_monarch_cpu:
+ /* Initialize stack pointer */
+ load32 BOOTADDR(parisc_stack),%r1
+ ldo FRAME_SIZE(%r1),%sp
+
+ /* Initialize the global data pointer */
+ loadgp
+
+ /* Clear BSS on monarch CPU */
+ .import _bss,data
+ .import _ebss,data
+
+ load32 BOOTADDR(_bss),%r3
+ load32 BOOTADDR(_ebss),%r4
+$bss_loop:
+ cmpb,<<,n %r3,%r4,$bss_loop
+ stw,ma %r0,4(%r3)
+
+ /* Save boot args */
+ load32 BOOTADDR(boot_args),%r1
+ stw,ma %r26,4(%r1)
+ stw,ma %r25,4(%r1)
+ stw,ma %r24,4(%r1)
+ stw,ma %r23,4(%r1)
+ stw,ma %r22,4(%r1)
+ stw,ma %r21,4(%r1)
+ stw,ma %r20,4(%r1)
+ stw,ma %r19,4(%r1)
+
+ load32 BOOTADDR(start_parisc_firmware),%r3
+ bv 0(%r3)
+ copy %r0,%r2
+END(startup)
+
+
+/*******************************************************
+ SMP Interrupt vector table (IVT)
+ *******************************************************/
+
+ .macro DEF_IVA_ENTRY
+ .align 32
+ load32 BOOTADDR($smp_exit_loop),%r1
+ bv 0(%r1)
+ nop
+ .endm
+
+ .align 32 /* should be 4k aligned but qemu does not check */
+ENTRY(smp_ivt)
+ .rept 32
+ DEF_IVA_ENTRY
+ .endr
+END(smp_ivt)
+
+
+/*******************************************************
+ PDC and IODC entry
+ *******************************************************/
+
+ENTRY(pdc_entry)
+ stw %rp,-20(%sp)
+ stw %dp,-32(%sp)
+ stw %arg0,-36(%sp)
+ stw %arg1,-40(%sp)
+ stw %arg2,-44(%sp)
+ stw %arg3,-48(%sp)
+ ldo -FRAME_SIZE(%sp),%arg0
+
+ loadgp
+ b,l parisc_pdc_entry, %rp
+ ldo FRAME_SIZE(%sp),%sp
+
+ ldo -FRAME_SIZE(%sp),%sp
+ ldw -20(%sp),%rp
+ bv %r0(%rp)
+ ldw -32(%sp),%dp
+END(pdc_entry)
+
+/* pdc_entry_table will be copied into low memory. */
+ENTRY(pdc_entry_table)
+ load32 pdc_entry,%r1
+ bv,n %r0(%r1)
+END(pdc_entry_table)
+
+ENTRY(iodc_entry_table)
+ load32 parisc_iodc_ENTRY_INIT, %r1
+ load32 parisc_iodc_ENTRY_IO, %r1
+ load32 parisc_iodc_ENTRY_SPA, %r1
+ load32 parisc_iodc_ENTRY_CONFIG, %r1
+ load32 hlt, %r1 /* obsolete */
+ load32 parisc_iodc_ENTRY_TEST, %r1
+ load32 parisc_iodc_ENTRY_TLB, %r1
+END(iodc_entry_table)
+
+ENTRY(iodc_entry)
+ load32 parisc_iodc_ENTRY_IO, %r1
+
+ stw %rp,-20(%sp)
+ stw %dp,-32(%sp)
+ stw %arg0,-36(%sp)
+ stw %arg1,-40(%sp)
+ stw %arg2,-44(%sp)
+ stw %arg3,-48(%sp)
+ ldo -FRAME_SIZE(%sp),%arg0
+
+ loadgp
+ load32 .iodc_ret, %rp
+ bv %r0(%r1)
+ ldo FRAME_SIZE(%sp),%sp
+.iodc_ret:
+ ldo -FRAME_SIZE(%sp),%sp
+ ldw -20(%sp),%rp
+ bv %r0(%rp)
+ ldw -32(%sp),%dp
+END(iodc_entry)
+
+ .data
+ENTRY(boot_args)
+ .word 0 /* r26: ramsize */
+ .word 0 /* r25: kernel entry point */
+ .word 0 /* r24: cmdline */
+ .word 0 /* r23: initrd_start */
+ .word 0 /* r22: initrd_end */
+ .word 0 /* r21: num CPUs */
+ .word 0 /* r20: pdc_debug */
+ .word 0 /* r19: fw_cfg port */
+END(boot_args)
+
+
+/****************************************************************
+ * Rom Header for VGA / STI
+ ****************************************************************/
+
+#if 0 // def CONFIG_BUILD_VGABIOS
+
+ .section .rom.header
+ .global _rom_header, _rom_header_size, _rom_header_checksum
+_rom_header:
+ .word 0xaa55
+_rom_header_size:
+ .byte 0
+_rom_header_entry:
+ .word _optionrom_entry // b,n ?
+_rom_header_checksum:
+ .byte 0
+_rom_header_other:
+ .space 17
+_rom_header_pcidata:
+#if CONFIG_VGA_PCI == 1
+ .word rom_pci_data
+#else
+ .word 0
+#endif
+_rom_header_pnpdata:
+ .word 0
+_rom_header_other2:
+ .word 0
+_rom_header_signature:
+ .asciz "IBM"
+
+
+ENTRY(_optionrom_entry)
+ .import vga_post
+ load32 BOOTADDR(vga_post), %r1
+ bv,n %r0(%r1)
+END(_optionrom_entry)
+
+#endif /* CONFIG_BUILD_VGABIOS */
diff --git a/src/parisc/hppa.h b/src/parisc/hppa.h
new file mode 100644
index 0000000..fa1b907
--- /dev/null
+++ b/src/parisc/hppa.h
@@ -0,0 +1,370 @@
+#ifndef HPPA_H
+#define HPPA_H
+/* this file is included by x86.h */
+
+#include "parisc/hppa_hardware.h"
+
+#ifndef __ASSEMBLY__
+
+#include "types.h" // u32
+#include "byteorder.h" // le16_to_cpu
+
+#define PSW_I 0x00000001
+
+static inline unsigned long arch_local_save_flags(void)
+{
+ unsigned long flags;
+ asm volatile("ssm 0, %0" : "=r" (flags) : : "memory");
+ return flags;
+}
+
+static inline void arch_local_irq_disable(void)
+{
+ asm volatile("rsm %0,%%r0\n" : : "i" (PSW_I) : "memory");
+}
+
+static inline void arch_local_irq_enable(void)
+{
+ asm volatile("ssm %0,%%r0\n" : : "i" (PSW_I) : "memory");
+}
+
+static inline unsigned long arch_local_irq_save(void)
+{
+ unsigned long flags;
+ asm volatile("rsm %1,%0" : "=r" (flags) : "i" (PSW_I) : "memory");
+ return flags;
+}
+
+static inline void arch_local_irq_restore(unsigned long flags)
+{
+ asm volatile("mtsm %0" : : "r" (flags) : "memory");
+}
+
+static inline void irq_disable(void)
+{
+ arch_local_irq_disable();
+}
+
+static inline void irq_enable(void)
+{
+ arch_local_irq_enable();
+}
+
+static inline u32 save_flags(void)
+{
+ return arch_local_irq_save();
+}
+
+static inline void restore_flags(u32 flags)
+{
+ arch_local_irq_restore(flags);
+}
+
+
+
+static inline void cpu_relax(void)
+{
+ asm volatile("nop": : :"memory");
+}
+
+static inline void nop(void)
+{
+ asm volatile("nop");
+}
+
+extern void hlt(void);
+
+static inline void wbinvd(void)
+{
+ asm volatile("sync": : :"memory");
+}
+
+#define mfctl(reg) ({ \
+ unsigned long cr; \
+ __asm__ __volatile__( \
+ "mfctl %1,%0" : \
+ "=r" (cr) : "i" (reg) \
+ ); \
+ cr; \
+})
+
+#define mtctl(gr, cr) \
+ __asm__ __volatile__("mtctl %0,%1" \
+ : /* no outputs */ \
+ : "r" (gr), "i" (cr) : "memory")
+
+/* these are here to de-mystefy the calling code, and to provide hooks */
+/* which I needed for debugging EIEM problems -PB */
+#define get_eiem() mfctl(15)
+static inline void set_eiem(unsigned long val)
+{
+ mtctl(val, 15);
+}
+
+#define mfsp(reg) ({ \
+ unsigned long cr; \
+ __asm__ __volatile__( \
+ "mfsp " #reg ",%0" : \
+ "=r" (cr) \
+ ); \
+ cr; \
+})
+
+#define mtsp(val, cr) \
+ { if (__builtin_constant_p(val) && ((val) == 0)) \
+ __asm__ __volatile__("mtsp %%r0,%0" : : "i" (cr) : "memory"); \
+ else \
+ __asm__ __volatile__("mtsp %0,%1" \
+ : /* no outputs */ \
+ : "r" (val), "i" (cr) : "memory"); }
+
+static inline unsigned long rdtscll(void)
+{
+ return mfctl(16);
+}
+
+static inline u32 __ffs(u32 x)
+{
+ unsigned long ret;
+
+ if (!x)
+ return 0;
+
+ __asm__(
+#ifdef CONFIG_64BIT
+ " ldi 63,%1\n"
+ " extrd,u,*<> %0,63,32,%%r0\n"
+ " extrd,u,*TR %0,31,32,%0\n" /* move top 32-bits down */
+ " addi -32,%1,%1\n"
+#else
+ " ldi 31,%1\n"
+#endif
+ " extru,<> %0,31,16,%%r0\n"
+ " extru,TR %0,15,16,%0\n" /* xxxx0000 -> 0000xxxx */
+ " addi -16,%1,%1\n"
+ " extru,<> %0,31,8,%%r0\n"
+ " extru,TR %0,23,8,%0\n" /* 0000xx00 -> 000000xx */
+ " addi -8,%1,%1\n"
+ " extru,<> %0,31,4,%%r0\n"
+ " extru,TR %0,27,4,%0\n" /* 000000x0 -> 0000000x */
+ " addi -4,%1,%1\n"
+ " extru,<> %0,31,2,%%r0\n"
+ " extru,TR %0,29,2,%0\n" /* 0000000y, 1100b -> 0011b */
+ " addi -2,%1,%1\n"
+ " extru,= %0,31,1,%%r0\n" /* check last bit */
+ " addi -1,%1,%1\n"
+ : "+r" (x), "=r" (ret) );
+ return ret;
+}
+
+static inline u32 __fls(u32 x)
+{
+ int ret;
+ if (!x)
+ return 0;
+
+ __asm__(
+ " ldi 1,%1\n"
+ " extru,<> %0,15,16,%%r0\n"
+ " zdep,TR %0,15,16,%0\n" /* xxxx0000 */
+ " addi 16,%1,%1\n"
+ " extru,<> %0,7,8,%%r0\n"
+ " zdep,TR %0,23,24,%0\n" /* xx000000 */
+ " addi 8,%1,%1\n"
+ " extru,<> %0,3,4,%%r0\n"
+ " zdep,TR %0,27,28,%0\n" /* x0000000 */
+ " addi 4,%1,%1\n"
+ " extru,<> %0,1,2,%%r0\n"
+ " zdep,TR %0,29,30,%0\n" /* y0000000 (y&3 = 0) */
+ " addi 2,%1,%1\n"
+ " extru,= %0,0,1,%%r0\n"
+ " addi 1,%1,%1\n" /* if y & 8, add 1 */
+ : "+r" (x), "=r" (ret) );
+
+ return ret;
+}
+
+static inline u32 rol(u32 val, u16 rol) {
+ u32 res, resr;
+ res = val << rol;
+ resr = val >> (32-rol);
+ res |= resr;
+ return res;
+}
+
+#define pci_ioport_addr(port) ((port >= 0x1000) && (port < FIRMWARE_START))
+
+static inline void outl(u32 value, portaddr_t port) {
+ if (!pci_ioport_addr(port)) {
+ *(volatile u32 *)(port) = be32_to_cpu(value);
+ } else {
+ /* write PCI I/O address to Dino's PCI_CONFIG_ADDR */
+ outl(port, DINO_HPA + 0x064);
+ /* write value to PCI_IO_DATA */
+ outl(value, DINO_HPA + 0x06c);
+ }
+}
+
+static inline void outw(u16 value, portaddr_t port) {
+ if (!pci_ioport_addr(port)) {
+ *(volatile u16 *)(port) = be16_to_cpu(value);
+ } else {
+ /* write PCI I/O address to Dino's PCI_CONFIG_ADDR */
+ outl(port, DINO_HPA + 0x064);
+ /* write value to PCI_IO_DATA */
+ outw(value, DINO_HPA + 0x06c);
+ }
+}
+
+static inline void outb(u8 value, portaddr_t port) {
+ if (!pci_ioport_addr(port)) {
+ *(volatile u8 *)(port) = value;
+ } else {
+ /* write PCI I/O address to Dino's PCI_CONFIG_ADDR */
+ outl(port & ~3U, DINO_HPA + 0x064);
+ /* write value to PCI_IO_DATA */
+ outb(value, DINO_HPA + 0x06c + (port & 3));
+ }
+}
+
+static inline u8 inb(portaddr_t port) {
+ if (!pci_ioport_addr(port)) {
+ return *(volatile u8 *)(port);
+ } else {
+ /* write PCI I/O address to Dino's PCI_CONFIG_ADDR */
+ outl(port & ~3U, DINO_HPA + 0x064);
+ /* read value to PCI_IO_DATA */
+ return inb(DINO_HPA + 0x06c + (port & 3));
+ }
+}
+
+static inline u16 inw(portaddr_t port) {
+ if (!pci_ioport_addr(port)) {
+ return *(volatile u16 *)(port);
+ } else {
+ /* write PCI I/O address to Dino's PCI_CONFIG_ADDR */
+ outl(port & ~3U, DINO_HPA + 0x064);
+ /* read value to PCI_IO_DATA */
+ return inw(DINO_HPA + 0x06c + (port & 3));
+ }
+}
+static inline u32 inl(portaddr_t port) {
+ if (!pci_ioport_addr(port)) {
+ return *(volatile u32 *)(port);
+ } else {
+ /* write PCI I/O address to Dino's PCI_CONFIG_ADDR */
+ outl(port & ~3U, DINO_HPA + 0x064);
+ /* read value to PCI_IO_DATA */
+ return inl(DINO_HPA + 0x06c + (port & 3));
+ }
+}
+
+static inline void insb(portaddr_t port, u8 *data, u32 count) {
+ while (count--)
+ *data++ = inb(port);
+}
+static inline void insw(portaddr_t port, u16 *data, u32 count) {
+ while (count--)
+ if (pci_ioport_addr(port))
+ *data++ = be16_to_cpu(inw(port));
+ else
+ *data++ = inw(port);
+}
+static inline void insl(portaddr_t port, u32 *data, u32 count) {
+ while (count--)
+ if (pci_ioport_addr(port))
+ *data++ = be32_to_cpu(inl(port));
+ else
+ *data++ = inl(port);
+}
+// XXX - outs not limited to es segment
+static inline void outsb(portaddr_t port, u8 *data, u32 count) {
+ while (count--)
+ outb(*data++, port);
+}
+static inline void outsw(portaddr_t port, u16 *data, u32 count) {
+ while (count--) {
+ if (pci_ioport_addr(port))
+ outw(cpu_to_be16(*data), port);
+ else
+ outw(*data, port);
+ data++;
+ }
+}
+static inline void outsl(portaddr_t port, u32 *data, u32 count) {
+ while (count--) {
+ if (pci_ioport_addr(port))
+ outl(cpu_to_be32(*data), port);
+ else
+ outl(*data, port);
+ data++;
+ }
+}
+
+/* Compiler barrier is enough as an x86 CPU does not reorder reads or writes */
+static inline void smp_rmb(void) {
+ barrier();
+}
+static inline void smp_wmb(void) {
+ barrier();
+}
+
+static inline void writel(void *addr, u32 val) {
+ barrier();
+ *(volatile u32 *)addr = val;
+}
+static inline void writew(void *addr, u16 val) {
+ barrier();
+ *(volatile u16 *)addr = val;
+}
+static inline void writeb(void *addr, u8 val) {
+ barrier();
+ *(volatile u8 *)addr = val;
+}
+static inline u64 readq(const void *addr) {
+ u64 val = *(volatile const u64 *)addr;
+ barrier();
+ return val;
+}
+static inline u32 readl(const void *addr) {
+ u32 val = *(volatile const u32 *)addr;
+ barrier();
+ return val;
+}
+static inline u16 readw(const void *addr) {
+ u16 val = *(volatile const u16 *)addr;
+ barrier();
+ return val;
+}
+static inline u8 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)
+#define GDT_B (0)
+#define GDT_G (0)
+#define GDT_BASE(v) ((v) & 0)
+#define GDT_LIMIT(v) ((v) & 0)
+#define GDT_GRANLIMIT(v) ((v) & 0)
+
+static inline u8 get_a20(void) {
+ return 0;
+}
+
+static inline u8 set_a20(u8 cond) {
+ return 0;
+}
+
+static inline void wrmsr(u32 index, u64 val)
+{
+}
+
+// x86.c
+void cpuid(u32 index, u32 *eax, u32 *ebx, u32 *ecx, u32 *edx);
+
+#endif // !__ASSEMBLY__
+#endif
diff --git a/src/parisc/hppa_hardware.h b/src/parisc/hppa_hardware.h
new file mode 100644
index 0000000..099a492
--- /dev/null
+++ b/src/parisc/hppa_hardware.h
@@ -0,0 +1,49 @@
+/* HPPA cores and system support chips. */
+
+#ifndef HW_HPPA_HPPA_HARDWARE_H
+#define HW_HPPA_HPPA_HARDWARE_H
+
+#define FIRMWARE_START 0xf0000000
+#define FIRMWARE_END 0xf0800000
+
+#define DEVICE_HPA_LEN 0x00100000
+
+#define GSC_HPA 0xffc00000
+#define DINO_HPA 0xfff80000
+#define DINO_UART_HPA 0xfff83000
+#define DINO_UART_BASE 0xfff83800
+#define DINO_SCSI_HPA 0xfff8c000
+#define LASI_HPA 0xffd00000
+#define LASI_UART_HPA 0xffd05000
+#define LASI_SCSI_HPA 0xffd06000
+#define LASI_LAN_HPA 0xffd07000
+#define LASI_RTC_HPA 0xffd09000
+#define LASI_LPT_HPA 0xffd02000
+#define LASI_AUDIO_HPA 0xffd04000
+#define LASI_PS2KBD_HPA 0xffd08000
+#define LASI_PS2MOU_HPA 0xffd08100
+#define LASI_GFX_HPA 0xf8000000
+#define ARTIST_FB_ADDR 0xf9000000
+#define CPU_HPA 0xfffb0000
+#define MEMORY_HPA 0xfffbf000
+
+#define PCI_HPA DINO_HPA /* PCI bus */
+#define IDE_HPA 0xf9000000 /* Boot disc controller */
+
+/* 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_SERIAL1 (DINO_UART_HPA + 0x800)
+#define PORT_SERIAL2 (LASI_UART_HPA + 0x800)
+
+#define HPPA_MAX_CPUS 8 /* max. number of SMP CPUs */
+#define CPU_CLOCK_MHZ 250 /* emulate a 250 MHz CPU */
+
+#define CPU_HPA_CR_REG 7 /* store CPU HPA in cr7 (SeaBIOS internal) */
+
+#endif
diff --git a/src/parisc/lasips2.c b/src/parisc/lasips2.c
new file mode 100644
index 0000000..119c214
--- /dev/null
+++ b/src/parisc/lasips2.c
@@ -0,0 +1,66 @@
+/* LASI PS2 keyboard support code
+ *
+ * Copyright (C) 2019 Sven Schnelle <svens@stackframe.org>
+ *
+ * This file may be distributed under the terms of the GNU LGPLv2 license.
+ */
+
+#include "bregs.h"
+#include "autoconf.h"
+#include "types.h"
+#include "output.h"
+#include "hw/ps2port.h"
+#include "util.h"
+#include "string.h"
+#include "lasips2.h"
+
+int lasips2_kbd_in(char *c, int max)
+{
+ struct bregs regs;
+ volatile int count = 0;
+
+ while((readl(LASIPS2_KBD_STATUS) & LASIPS2_KBD_STATUS_RBNE)) {
+ process_key(readb(LASIPS2_KBD_DATA));
+ }
+
+ while(count < max) {
+ memset(&regs, 0, sizeof(regs));
+ regs.ah = 0x10;
+ handle_16(&regs);
+ if (!regs.ah)
+ break;
+ *c++ = regs.ah;
+ count++;
+ }
+ return count;
+}
+
+
+int ps2_kbd_command(int command, u8 *param)
+{
+ return 0;
+}
+
+int lasips2_command(u16 cmd)
+{
+ while(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))
+ udelay(10);
+ return readb(LASIPS2_KBD_DATA);
+}
+
+void ps2port_setup(void)
+{
+ writeb(LASIPS2_KBD_RESET, 0);
+ udelay(1000);
+ writeb(LASIPS2_KBD_CONTROL, LASIPS2_KBD_CONTROL_EN);
+ lasips2_command(ATKBD_CMD_RESET_BAT);
+ lasips2_command(ATKBD_CMD_RESET_DIS);
+ lasips2_command(ATKBD_CMD_SSCANSET);
+ lasips2_command(0x01);
+ lasips2_command(ATKBD_CMD_ENABLE);
+ kbd_init();
+}
diff --git a/src/parisc/lasips2.h b/src/parisc/lasips2.h
new file mode 100644
index 0000000..efdd66b
--- /dev/null
+++ b/src/parisc/lasips2.h
@@ -0,0 +1,17 @@
+#ifndef PARISC_LASIPS2_H
+#define PARISC_LASIPS2_H
+
+void ps2port_setup(void);
+
+int lasips2_kbd_in(char *c, int max);
+
+#define LASIPS2_KBD_RESET ((void *)(LASI_PS2KBD_HPA+0x00))
+#define LASIPS2_KBD_DATA ((void *)(LASI_PS2KBD_HPA+0x04))
+#define LASIPS2_KBD_CONTROL ((void *)(LASI_PS2KBD_HPA+0x08))
+#define LASIPS2_KBD_STATUS ((void *)(LASI_PS2KBD_HPA+0x0c))
+
+#define LASIPS2_KBD_CONTROL_EN 0x01
+#define LASIPS2_KBD_STATUS_RBNE 0x01
+#define LASIPS2_KBD_STATUS_TBNE 0x02
+
+#endif
diff --git a/src/parisc/malloc.c b/src/parisc/malloc.c
new file mode 100644
index 0000000..c4e46e6
--- /dev/null
+++ b/src/parisc/malloc.c
@@ -0,0 +1,91 @@
+// Internal dynamic memory allocations.
+//
+// Copyright (C) 2009-2013 Kevin O'Connor <kevin@koconnor.net>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "biosvar.h" // GET_BDA
+#include "config.h" // BUILD_BIOS_ADDR
+#include "e820map.h" // struct e820entry
+#include "list.h" // hlist_node
+#include "malloc.h" // _malloc
+#include "memmap.h" // PAGE_SIZE
+#include "output.h" // dprintf
+#include "stacks.h" // wait_preempt
+#include "std/optionrom.h" // OPTION_ROM_ALIGN
+#include "string.h" // memset
+
+static unsigned long stackptr;
+
+/****************************************************************
+ * tracked memory allocations
+ ****************************************************************/
+
+// Allocate physical memory from the given zone and track it as a PMM allocation
+unsigned long
+malloc_palloc(struct zone_s *zone, u32 size, u32 align)
+{
+ unsigned long data;
+
+ ASSERT32FLAT();
+ if (!size)
+ return 0;
+
+ stackptr = (stackptr + align-1) & ~(align-1);
+ data = stackptr;
+ stackptr += size;
+
+ dprintf(8, "size=%d align=%d ret=0x%lx\n" , size, align, data);
+
+ return data;
+}
+
+// Allocate virtual memory from the given zone
+void * __malloc
+parisc_malloc(u32 size, u32 align)
+{
+ return (void*) malloc_palloc(NULL, size, align);
+}
+
+// Free a data block allocated with phys_alloc
+int
+malloc_pfree(u32 data)
+{
+ return 0;
+}
+
+void
+free(void *data)
+{
+}
+
+
+
+/****************************************************************
+ * Setup
+ ****************************************************************/
+
+void
+malloc_preinit(void)
+{
+ ASSERT32FLAT();
+ dprintf(3, "malloc preinit\n");
+ extern u8 _ebss;
+ stackptr = (unsigned long) &_ebss;
+}
+
+u32 LegacyRamSize VARFSEG;
+
+void
+malloc_init(void)
+{
+ ASSERT32FLAT();
+ dprintf(3, "malloc init\n");
+}
+
+void
+malloc_prepboot(void)
+{
+ ASSERT32FLAT();
+ dprintf(3, "malloc finalize\n");
+}
diff --git a/src/parisc/pafirmware.lds.S b/src/parisc/pafirmware.lds.S
new file mode 100644
index 0000000..e246c84
--- /dev/null
+++ b/src/parisc/pafirmware.lds.S
@@ -0,0 +1,69 @@
+#include "parisc/hppa_hardware.h"
+
+OUTPUT_FORMAT("elf32-hppa-linux")
+OUTPUT_ARCH(hppa)
+ENTRY(startup)
+SECTIONS
+{
+ . = FIRMWARE_START;
+
+ /* align on next page boundary */
+ . = ALIGN(4096);
+ .text : {
+ _text = .; /* Text */
+ *(.head.text)
+ *(.text)
+ *(.text.*)
+ _etext = . ;
+ }
+
+ . = ALIGN(4096);
+ .sti : {
+ _sti_rom_start = .;
+ *(.sti.hdr)
+ *(.sti.text.init_graph)
+ *(.sti.text.state_mgmt)
+ *(.sti.text.font_unpmv)
+ *(.sti.text.block_move)
+ *(.sti.text.self_test)
+ *(.sti.text.excep_hdlr)
+ *(.sti.text.inq_conf)
+ *(.sti.text.set_cm_entry)
+ *(.sti.text.dma_ctrl)
+ *(.sti.text)
+ *(.sti.data)
+ *(.sti.text.end)
+ . = ALIGN(4096);
+ _sti_rom_end = .;
+ }
+
+ . = ALIGN(8);
+ .rodata : {
+ _rodata = . ;
+ *(.rodata) /* read-only data */
+ *(.rodata.*)
+ _erodata = . ;
+ }
+ . = ALIGN(8);
+ .data : {
+ _data = . ;
+ *(.data)
+ *(.data.*)
+ _edata = . ;
+ }
+ . = ALIGN(8);
+ .bss : {
+ _bss = . ;
+ *(.bss)
+ *(.bss.*)
+ *(COMMON)
+ _ebss = .;
+ }
+
+ /* STABS_DEBUG */
+ .note 0 : { *(.note) }
+
+ /* Sections to be discarded */
+ /DISCARD/ : {
+ }
+}
diff --git a/src/parisc/parisc.c b/src/parisc/parisc.c
new file mode 100644
index 0000000..ac69904
--- /dev/null
+++ b/src/parisc/parisc.c
@@ -0,0 +1,1997 @@
+// Glue code for parisc architecture
+//
+// Copyright (C) 2017-2021 Helge Deller <deller@gmx.de>
+// Copyright (C) 2019 Sven Schnelle <svens@stackframe.org>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "biosvar.h" // GET_BDA
+#include "bregs.h" // struct bregs
+#include "hw/pic.h" // enable_hwirq
+#include "output.h" // debug_enter
+#include "stacks.h" // call16_int
+#include "string.h" // memset
+#include "util.h" // serial_setup
+#include "malloc.h" // malloc
+#include "hw/serialio.h" // qemu_debug_port
+#include "hw/pcidevice.h" // foreachpci
+#include "hw/pci.h" // pci_config_readl
+#include "hw/pci_ids.h" // PCI IDs
+#include "hw/pci_regs.h" // PCI_BASE_ADDRESS_0
+#include "hw/ata.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"
+
+#include "vgabios.h"
+
+#define SEABIOS_HPPA_VERSION 1
+
+/*
+ * Various variables which are needed by x86 code.
+ * Defined here to be able to link seabios.
+ */
+int HaveRunPost;
+u8 ExtraStack[BUILD_EXTRA_STACK_SIZE+1] __aligned(8);
+u8 *StackPos;
+u8 __VISIBLE parisc_stack[32*1024] __aligned(64);
+
+u8 BiosChecksum;
+
+char zonefseg_start, zonefseg_end; // SYMBOLS
+char varlow_start, varlow_end, final_varlow_start;
+char final_readonly_start;
+char code32flat_start, code32flat_end;
+char zonelow_base;
+
+struct bios_data_area_s __VISIBLE bios_data_area;
+struct vga_bda_s __VISIBLE vga_bios_data_area;
+struct floppy_dbt_s diskette_param_table;
+struct bregs regs;
+unsigned long parisc_vga_mem;
+unsigned long parisc_vga_mmio;
+struct segoff_s ivt_table[256];
+
+void mtrr_setup(void) { }
+void mouse_init(void) { }
+void pnp_init(void) { }
+u16 get_pnp_offset(void) { return 0; }
+void mathcp_setup(void) { }
+void smp_setup(void) { }
+void bios32_init(void) { }
+void yield_toirq(void) { }
+void farcall16(struct bregs *callregs) { }
+void farcall16big(struct bregs *callregs) { }
+void mutex_lock(struct mutex_s *mutex) { }
+void mutex_unlock(struct mutex_s *mutex) { }
+void start_preempt(void) { }
+void finish_preempt(void) { }
+int wait_preempt(void) { return 0; }
+
+void cpuid(u32 index, u32 *eax, u32 *ebx, u32 *ecx, u32 *edx)
+{
+ *eax = *ebx = *ecx = *edx = 0;
+}
+
+void wrmsr_smp(u32 index, u64 val) { }
+
+/********************************************************
+ * PA-RISC specific constants and functions.
+ ********************************************************/
+
+/* Pointer to zero-page of PA-RISC */
+#define PAGE0 ((volatile struct zeropage *) 0UL)
+
+/* variables provided by qemu */
+extern unsigned long boot_args[];
+#define ram_size (boot_args[0])
+#define linux_kernel_entry (boot_args[1])
+#define cmdline (boot_args[2])
+#define initrd_start (boot_args[3])
+#define initrd_end (boot_args[4])
+#define smp_cpus (boot_args[5])
+#define pdc_debug (boot_args[6])
+#define fw_cfg_port (boot_args[7])
+
+/* flags for pdc_debug */
+#define DEBUG_PDC 0x0001
+#define DEBUG_IODC 0x0002
+
+unsigned long PORT_QEMU_CFG_CTL;
+unsigned int tlb_entries = 256;
+unsigned int btlb_entries = 8;
+
+#define PARISC_SERIAL_CONSOLE PORT_SERIAL1
+
+extern char pdc_entry;
+extern char pdc_entry_table[12];
+extern char iodc_entry[512];
+extern char iodc_entry_table[14*4];
+
+/* args as handed over for firmware calls */
+#define ARG0 arg[7-0]
+#define ARG1 arg[7-1]
+#define ARG2 arg[7-2]
+#define ARG3 arg[7-3]
+#define ARG4 arg[7-4]
+#define ARG5 arg[7-5]
+#define ARG6 arg[7-6]
+#define ARG7 arg[7-7]
+
+/* size of I/O block used in HP firmware */
+#define FW_BLOCKSIZE 2048
+
+#define MIN_RAM_SIZE (16*1024*1024) // 16 MB
+
+#define MEM_PDC_ENTRY 0x4800 /* as in a B160L */
+
+#define CPU_HPA_IDX(i) (CPU_HPA + (i)*0x1000) /* CPU_HPA of CPU#i */
+
+static int index_of_CPU_HPA(unsigned long hpa) {
+ int i;
+ for (i = 0; i < smp_cpus; i++) {
+ if (hpa == CPU_HPA_IDX(i))
+ return i;
+ }
+ return -1;
+}
+
+static unsigned long GoldenMemory = MIN_RAM_SIZE;
+
+static unsigned int chassis_code = 0;
+
+/*
+ * Emulate the power switch button flag in head section of firmware.
+ * Bit 31 (the lowest bit) is the status of the power switch.
+ * This bit is "1" if the button is NOT pressed.
+ */
+int powersw_nop;
+int *powersw_ptr;
+
+void __VISIBLE __noreturn hlt(void)
+{
+ if (pdc_debug)
+ printf("HALT initiated from %p\n", __builtin_return_address(0));
+ printf("SeaBIOS wants SYSTEM HALT.\n\n");
+ asm volatile("\t.word 0xfffdead0": : :"memory");
+ while (1);
+}
+
+static void check_powersw_button(void)
+{
+ /* halt immediately if power button was pressed. */
+ if ((*powersw_ptr & 1) == 0) {
+ printf("SeaBIOS machine power switch was pressed.\n");
+ hlt();
+ }
+}
+
+void __noreturn reset(void)
+{
+ if (pdc_debug)
+ printf("RESET initiated from %p\n", __builtin_return_address(0));
+ printf("SeaBIOS wants SYSTEM RESET.\n"
+ "***************************\n");
+ check_powersw_button();
+ PAGE0->imm_soft_boot = 1;
+ asm volatile("\t.word 0xfffdead1": : :"memory");
+ while (1);
+}
+
+#undef BUG_ON
+#define BUG_ON(cond) \
+ if (unlikely(cond)) \
+{ printf("ERROR in %s:%d\n", __FUNCTION__, __LINE__); hlt(); }
+
+void flush_data_cache(char *start, size_t length)
+{
+ char *end = start + length;
+
+ do
+ {
+ asm volatile("fdc 0(%0)" : : "r" (start));
+ asm volatile("fic 0(%%sr0,%0)" : : "r" (start));
+ start += 16;
+ } while (start < end);
+ asm volatile("fdc 0(%0)" : : "r" (end));
+
+ asm ("sync");
+}
+
+void memdump(void *mem, unsigned long len)
+{
+ printf("memdump @ 0x%x : ", (unsigned int) mem);
+ while (len--) {
+ printf("0x%x ", (unsigned int) *(unsigned char *)mem);
+ mem++;
+ }
+ printf("\n");
+}
+
+/********************************************************
+ * Boot drives
+ ********************************************************/
+
+static struct drive_s *boot_drive; // really currently booted drive
+static struct drive_s *parisc_boot_harddisc; // first hard disc
+static struct drive_s *parisc_boot_cdrom; // first DVD or CD-ROM
+
+static struct pdc_module_path mod_path_emulated_drives = {
+ .path = { .flags = 0x0, .bc = { 0xff, 0xff, 0xff, 0x8, 0x0, 0x0 }, .mod = 0x0 },
+ .layers = { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 } // first two layer entries get replaced
+};
+
+/********************************************************
+ * FIRMWARE IO Dependent Code (IODC) HANDLER
+ ********************************************************/
+
+typedef struct {
+ unsigned long hpa;
+ struct pdc_iodc *iodc;
+ struct pdc_system_map_mod_info *mod_info;
+ struct pdc_module_path *mod_path;
+ int num_addr;
+ int add_addr[5];
+} hppa_device_t;
+
+static hppa_device_t parisc_devices[HPPA_MAX_CPUS+16] = { PARISC_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, \
+ 0
+
+static const char *hpa_name(unsigned long hpa)
+{
+ struct pci_device *pci;
+ int i;
+
+ #define DO(x) if (hpa == x) return #x;
+ DO(GSC_HPA)
+ DO(DINO_HPA)
+ DO(DINO_UART_HPA)
+ DO(DINO_SCSI_HPA)
+ DO(CPU_HPA)
+ DO(MEMORY_HPA)
+ DO(IDE_HPA)
+ DO(LASI_HPA)
+ DO(LASI_UART_HPA)
+ DO(LASI_SCSI_HPA)
+ DO(LASI_LAN_HPA)
+ DO(LASI_LPT_HPA)
+ DO(LASI_AUDIO_HPA)
+ DO(LASI_PS2KBD_HPA)
+ DO(LASI_PS2MOU_HPA)
+ DO(LASI_GFX_HPA)
+ #undef DO
+
+ /* could be one of the SMP CPUs */
+ for (i = 1; i < smp_cpus; i++) {
+ static char CPU_TXT[] = "CPU_HPA_x";
+ if (hpa == CPU_HPA_IDX(i)) {
+ CPU_TXT[8] = '0'+i;
+ return CPU_TXT;
+ }
+ }
+
+ /* could be a PCI device */
+ foreachpci(pci) {
+ unsigned long mem, mmio;
+ mem = pci_config_readl(pci->bdf, PCI_BASE_ADDRESS_0);
+ mem &= PCI_BASE_ADDRESS_MEM_MASK;
+ if (hpa == mem)
+ return "HPA_PCI_CARD_MEM";
+ mmio = pci_config_readl(pci->bdf, PCI_BASE_ADDRESS_2);
+ mmio &= PCI_BASE_ADDRESS_MEM_MASK;
+ if (hpa == mem)
+ return "HPA_PCI_CARD_MMIO";
+ }
+
+ return "UNKNOWN HPA";
+}
+
+int HPA_is_serial_device(unsigned long hpa)
+{
+ return (hpa == DINO_UART_HPA) || (hpa == LASI_UART_HPA);
+}
+
+int HPA_is_storage_device(unsigned long hpa)
+{
+ return (hpa == DINO_SCSI_HPA) || (hpa == IDE_HPA) || (hpa == LASI_SCSI_HPA);
+}
+
+int HPA_is_keyboard_device(unsigned long hpa)
+{
+ return (hpa == LASI_PS2KBD_HPA);
+}
+
+#define GFX_NUM_PAGES 0x2000
+int HPA_is_graphics_device(unsigned long hpa)
+{
+ return (hpa == LASI_GFX_HPA) || (hpa == 0xf4000000) ||
+ (hpa == 0xf8000000) || (hpa == 0xfa000000);
+}
+
+static unsigned long keep_list[] = { PARISC_KEEP_LIST };
+
+static void remove_from_keep_list(unsigned long hpa)
+{
+ int i = 0;
+
+ while (keep_list[i] && keep_list[i] != hpa)
+ i++;
+ while (keep_list[i]) {
+ ++i;
+ keep_list[i-1] = keep_list[i];
+ }
+}
+
+static int keep_this_hpa(unsigned long hpa)
+{
+ int i = 0;
+
+ while (keep_list[i]) {
+ if (keep_list[i] == hpa)
+ return 1;
+ i++;
+ }
+ 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)
+{
+ static struct pdc_system_map_mod_info modinfo[HPPA_MAX_CPUS] = { {1,}, };
+ static struct pdc_module_path modpath[HPPA_MAX_CPUS] = { {{1,}} };
+ hppa_device_t *cpu_dev = NULL;
+ unsigned long hpa;
+ int i, p, t;
+
+ /* already initialized? */
+ static int uninitialized = 1;
+ if (!uninitialized)
+ return;
+ uninitialized = 0;
+
+ /* check if qemu emulates LASI chip (LASI_IAR exists) */
+ if (*(unsigned long *)(LASI_HPA+16) == 0) {
+ remove_from_keep_list(LASI_UART_HPA);
+ remove_from_keep_list(LASI_LAN_HPA);
+ remove_from_keep_list(LASI_LPT_HPA);
+ } else {
+ /* check if qemu emulates LASI i82596 LAN card */
+ if (*(unsigned long *)(LASI_LAN_HPA+12) != 0xBEEFBABE)
+ remove_from_keep_list(LASI_LAN_HPA);
+ }
+
+ p = t = 0;
+ while ((hpa = parisc_devices[p].hpa) != 0) {
+ if (keep_this_hpa(hpa)) {
+ parisc_devices[t] = parisc_devices[p];
+ if (hpa == CPU_HPA)
+ cpu_dev = &parisc_devices[t];
+ t++;
+ }
+ p++;
+ }
+
+ /* Fix monarch CPU */
+ BUG_ON(!cpu_dev);
+ cpu_dev->mod_info->mod_addr = CPU_HPA;
+ cpu_dev->mod_path->path.mod = (CPU_HPA - DINO_HPA) / 0x1000;
+
+ /* Generate other CPU devices */
+ for (i = 1; i < num_cpus; i++) {
+ unsigned long hpa = CPU_HPA_IDX(i);
+
+ parisc_devices[t] = *cpu_dev;
+ parisc_devices[t].hpa = hpa;
+
+ modinfo[i] = *cpu_dev->mod_info;
+ modinfo[i].mod_addr = hpa;
+ parisc_devices[t].mod_info = &modinfo[i];
+
+ modpath[i] = *cpu_dev->mod_path;
+ modpath[i].path.mod = (hpa - DINO_HPA) / 0x1000;
+ parisc_devices[t].mod_path = &modpath[i];
+
+ t++;
+ }
+
+ BUG_ON(t > ARRAY_SIZE(parisc_devices));
+
+ while (t < ARRAY_SIZE(parisc_devices)) {
+ memset(&parisc_devices[t], 0, sizeof(parisc_devices[0]));
+ 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)
+{
+ int i;
+
+ if (path->path.mod != search->path.mod)
+ return -1;
+
+ for(i = 0; i < ARRAY_SIZE(path->path.bc); i++) {
+ if (path->path.bc[i] != search->path.bc[i])
+ return -1;
+ }
+
+ if (check_layers) {
+ for(i = 0; i < ARRAY_SIZE(path->layers); i++) {
+ if (path->layers[i] != search->layers[i])
+ return -1;
+ }
+ }
+ return 0;
+}
+
+static hppa_device_t *find_hppa_device_by_path(struct pdc_module_path *search,
+ unsigned long *index, int check_layers)
+{
+ hppa_device_t *dev;
+ int i;
+
+ for (i = 0; i < (ARRAY_SIZE(parisc_devices)-1); i++) {
+ dev = parisc_devices + i;
+ if (!dev->hpa)
+ continue;
+
+ if (!compare_module_path(dev->mod_path, search, check_layers)) {
+ *index = i;
+ return dev;
+ }
+ }
+ return NULL;
+}
+
+#define SERIAL_TIMEOUT 20
+static unsigned long parisc_serial_in(char *c, unsigned long maxchars)
+{
+ const portaddr_t addr = PARISC_SERIAL_CONSOLE;
+ unsigned long end = timer_calc(SERIAL_TIMEOUT);
+ unsigned long count = 0;
+ while (count < maxchars) {
+ u8 lsr = inb(addr+SEROFF_LSR);
+ if (lsr & 0x01) {
+ // Success - can read data
+ *c++ = inb(addr+SEROFF_DATA);
+ count++;
+ }
+ if (timer_check(end))
+ break;
+ }
+ return count;
+}
+
+static void parisc_serial_out(char c)
+{
+ for (;;) {
+ if (c == '\n')
+ parisc_serial_out('\r');
+ const portaddr_t addr = PORT_SERIAL1;
+ u8 lsr = inb(addr+SEROFF_LSR);
+ if ((lsr & 0x60) == 0x60) {
+ // Success - can write data
+ outb(c, addr+SEROFF_DATA);
+ break;
+ }
+ }
+}
+
+void parisc_screenc(char c)
+{
+ if (HPA_is_graphics_device(PAGE0->mem_cons.hpa))
+ sti_putc(c);
+ else
+ parisc_serial_out(c);
+}
+
+void iodc_log_call(unsigned int *arg, const char *func)
+{
+ if (pdc_debug & DEBUG_IODC) {
+ printf("\nIODC %s called: hpa=0x%x (%s) option=0x%x arg2=0x%x arg3=0x%x ", func, ARG0, hpa_name(ARG0), ARG1, ARG2, ARG3);
+ printf("result=0x%x arg5=0x%x arg6=0x%x arg7=0x%x\n", ARG4, ARG5, ARG6, ARG7);
+ }
+}
+
+#define FUNC_MANY_ARGS , \
+ int a0, int a1, int a2, int a3, int a4, int a5, int a6, \
+ int a7, int a8, int a9, int a10, int a11, int a12
+
+
+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;
+ int ret, len;
+ char *c;
+ struct disk_op_s disk_op;
+
+ 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))) {
+ /* avoid debug messages */
+ } else {
+ iodc_log_call(arg, __FUNCTION__);
+ }
+
+ /* console I/O */
+ switch (option) {
+ case ENTRY_IO_COUT: /* console output */
+ c = (char*)ARG6;
+ result[0] = len = ARG7;
+ if (HPA_is_serial_device(hpa) || HPA_is_graphics_device(hpa)) {
+ while (len--)
+ printf("%c", *c++);
+ }
+ return PDC_OK;
+ case ENTRY_IO_CIN: /* console input, with 5 seconds timeout */
+ c = (char*)ARG6;
+ if (HPA_is_serial_device(hpa))
+ result[0] = parisc_serial_in(c, ARG7);
+ else if (HPA_is_keyboard_device(hpa))
+ result[0] = lasips2_kbd_in(c, ARG7);
+ return PDC_OK;
+ }
+
+ /* boot medium I/O */
+ if (HPA_is_storage_device(hpa))
+ switch (option) {
+ case ENTRY_IO_BOOTIN: /* boot medium IN */
+ case ENTRY_IO_BBLOCK_IN: /* boot block medium IN */
+ disk_op.drive_fl = boot_drive;
+ disk_op.buf_fl = (void*)ARG6;
+ disk_op.command = CMD_READ;
+ if (option == ENTRY_IO_BBLOCK_IN) { /* in 2k blocks */
+ disk_op.count = (ARG7 * ((u64)FW_BLOCKSIZE / disk_op.drive_fl->blksize));
+ disk_op.lba = (ARG5 * ((u64)FW_BLOCKSIZE / disk_op.drive_fl->blksize));
+ } else {
+ disk_op.count = (ARG7 / disk_op.drive_fl->blksize);
+ disk_op.lba = (ARG5 / disk_op.drive_fl->blksize);
+ }
+ // ARG8 = maxsize !!!
+ ret = process_op(&disk_op);
+ // dprintf(0, "\nBOOT IO res %d count = %d\n", ret, ARG7);
+ result[0] = ARG7;
+ if (ret)
+ return PDC_ERROR;
+ return PDC_OK;
+ }
+
+ if (option == ENTRY_IO_CLOSE)
+ return PDC_OK;
+
+ // BUG_ON(1);
+ iodc_log_call(arg, __FUNCTION__);
+
+ return PDC_BAD_OPTION;
+}
+
+
+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;
+
+ iodc_log_call(arg, __FUNCTION__);
+
+ hpa_index = find_hpa_index(hpa);
+ if (hpa_index < 0 && hpa != IDE_HPA)
+ return PDC_INVALID_ARG;
+
+ switch (option) {
+ case ENTRY_INIT_SRCH_FRST: /* 2: Search first */
+ 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[2] = result[3] = 0; /* No network card, so no MAC. */
+ return PDC_OK;
+ case ENTRY_INIT_SRCH_NEXT: /* 3: Search next */
+ return PDC_NE_BOOTDEV; /* No further boot devices */
+ 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. */
+ return PDC_OK;
+ case ENTRY_INIT_MOD: /* 6: INIT */
+ result[0] = 0; /* module IO_STATUS */
+ return PDC_OK;
+ }
+ return PDC_BAD_OPTION;
+}
+
+int __VISIBLE parisc_iodc_ENTRY_SPA(unsigned int *arg FUNC_MANY_ARGS)
+{
+ iodc_log_call(arg, __FUNCTION__);
+ return PDC_BAD_OPTION;
+}
+
+int __VISIBLE parisc_iodc_ENTRY_CONFIG(unsigned int *arg FUNC_MANY_ARGS)
+{
+ iodc_log_call(arg, __FUNCTION__);
+ return PDC_BAD_OPTION;
+}
+
+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;
+
+ iodc_log_call(arg, __FUNCTION__);
+
+ hpa_index = find_hpa_index(hpa);
+ if (hpa_index < 0 && hpa != IDE_HPA)
+ return PDC_INVALID_ARG;
+
+ /* The options ARG1=0 and ARG1=1 are required. Others are optional. */
+ if (option == 0) { // Return info
+ unsigned long *list_addr = (unsigned long *)ARG5;
+ list_addr[0] = 0; // no test lists available.
+ result[0] = 0; // data buffer size, no bytes required.
+ result[1] = 0; // message buffer size, no bytes required.
+ return PDC_OK;
+ }
+
+ if (option == 1) { // Execute step
+ result[0] = 0; // fixed address of remote por
+ return PDC_OK;
+ }
+
+ return PDC_BAD_OPTION;
+}
+
+int __VISIBLE parisc_iodc_ENTRY_TLB(unsigned int *arg FUNC_MANY_ARGS)
+{
+ unsigned long option = ARG1;
+ unsigned long *result = (unsigned long *)ARG4;
+
+ iodc_log_call(arg, __FUNCTION__);
+
+ if (option == 0) {
+ result[0] = 0; /* no TLB */
+ result[1] = 0;
+ return PDC_OK;
+ }
+ return PDC_BAD_OPTION;
+}
+
+/********************************************************
+ * FIRMWARE PDC HANDLER
+ ********************************************************/
+
+#define STABLE_STORAGE_SIZE 512
+static unsigned char stable_storage[STABLE_STORAGE_SIZE];
+
+#define NVOLATILE_STORAGE_SIZE 512
+static unsigned char nvolatile_storage[NVOLATILE_STORAGE_SIZE];
+
+static void init_stable_storage(void)
+{
+ /* see ENGINEERING NOTE on page 4-92 in PDC2.0 doc */
+ memset(&stable_storage, 0, STABLE_STORAGE_SIZE);
+ // no intial paths
+ stable_storage[0x07] = 0xff;
+ stable_storage[0x67] = 0xff;
+ stable_storage[0x87] = 0xff;
+ stable_storage[0xa7] = 0xff;
+ // 0x0e/0x0f => fastsize = all, needed for HPUX
+ 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",
+ "Shutdown", "Warning", "Run", "All On"
+};
+
+static const char *pdc_name(unsigned long num)
+{
+#define DO(x) if (num == x) return #x;
+ DO(PDC_POW_FAIL)
+ DO(PDC_CHASSIS)
+ DO(PDC_PIM)
+ DO(PDC_MODEL)
+ DO(PDC_CACHE)
+ DO(PDC_HPA)
+ DO(PDC_COPROC)
+ DO(PDC_IODC)
+ DO(PDC_TOD)
+ DO(PDC_STABLE)
+ DO(PDC_NVOLATILE)
+ DO(PDC_ADD_VALID)
+ DO(PDC_INSTR)
+ DO(PDC_PROC)
+ DO(PDC_BLOCK_TLB)
+ DO(PDC_TLB)
+ DO(PDC_MEM)
+ DO(PDC_PSW)
+ DO(PDC_SYSTEM_MAP)
+ DO(PDC_SOFT_POWER)
+ DO(PDC_CRASH_PREP)
+ DO(PDC_MEM_MAP)
+ DO(PDC_EEPROM)
+ DO(PDC_NVM)
+ DO(PDC_SEED_ERROR)
+ DO(PDC_IO)
+ DO(PDC_BROADCAST_RESET)
+ DO(PDC_LAN_STATION_ID)
+ DO(PDC_CHECK_RANGES)
+ DO(PDC_NV_SECTIONS)
+ DO(PDC_PERFORMANCE)
+ DO(PDC_SYSTEM_INFO)
+ DO(PDC_RDR)
+ DO(PDC_INTRIGUE)
+ DO(PDC_STI)
+ DO(PDC_PCI_INDEX)
+ DO(PDC_RELOCATE)
+ DO(PDC_INITIATOR)
+ DO(PDC_LINK)
+#undef DO
+ return "UNKNOWN!";
+}
+
+static int pdc_chassis(unsigned int *arg)
+{
+ unsigned long option = ARG1;
+ unsigned long *result = (unsigned long *)ARG2;
+ short *display_model = (short *)ARG3;
+
+ switch (option) {
+ case PDC_CHASSIS_DISP:
+ ARG3 = ARG2;
+ result = (unsigned long *)&ARG4; // do not write to ARG2, use &ARG4 instead
+ // fall through
+ case PDC_CHASSIS_DISPWARN:
+ ARG4 = (ARG3 >> 17) & 7;
+ chassis_code = ARG3 & 0xffff;
+ if (0) printf("\nPDC_CHASSIS: %s (%d), %sCHASSIS %0x\n",
+ systat[ARG4], ARG4, (ARG3>>16)&1 ? "blank display, ":"", chassis_code);
+ // fall through
+ case PDC_CHASSIS_WARN:
+ // return warnings regarding fans, batteries and temperature: None!
+ result[0] = 0;
+ return PDC_OK;
+ case PDC_RETURN_CHASSIS_INFO: /* return chassis LED/LCD info */
+ // XXX: Later we could emulate an LCD display here.
+ result[0] = result[1] = 4; // actcnt & maxcnt
+ memset((char *)ARG3, 0, ARG4);
+ display_model[0] = 1; // 1=DISPLAY_MODEL_NONE
+ display_model[1] = 0; // 0=LCD WIDTH is 0
+ return PDC_OK;
+ }
+ return PDC_BAD_PROC;
+}
+
+static int pdc_pim(unsigned int *arg)
+{
+ unsigned long option = ARG1;
+ unsigned long *result = (unsigned long *)ARG2;
+
+ switch (option) {
+ case PDC_PIM_HPMC:
+ break;
+ case PDC_PIM_RETURN_SIZE:
+ *result = sizeof(struct pdc_hpmc_pim_11); // FIXME 64bit!
+ // B160 returns only "2". Why?
+ return PDC_OK;
+ case PDC_PIM_LPMC:
+ case PDC_PIM_SOFT_BOOT:
+ return PDC_BAD_OPTION;
+ case PDC_PIM_TOC:
+ break;
+ }
+ return PDC_BAD_PROC;
+}
+
+static int pdc_model(unsigned int *arg)
+{
+ static unsigned long model[] = { PARISC_PDC_MODEL };
+ static const char model_str[] = PARISC_MODEL;
+ unsigned long option = ARG1;
+ unsigned long *result = (unsigned long *)ARG2;
+
+ switch (option) {
+ case PDC_MODEL_INFO:
+ memcpy(result, model, sizeof(model));
+ return PDC_OK;
+ case PDC_MODEL_VERSIONS:
+ switch (ARG3) {
+ case 0: /* return CPU0 version */
+ result[0] = 35; // TODO! ???
+ return PDC_OK;
+ case 1: /* return PDC version */
+ result[0] = PARISC_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));
+ return PDC_OK;
+ case PDC_MODEL_ENSPEC:
+ case PDC_MODEL_DISPEC:
+ if (ARG3 != model[7])
+ return -20;
+ return PDC_OK;
+ case PDC_MODEL_CPU_ID:
+ result[0] = PARISC_PDC_CPUID;
+ return PDC_OK;
+ case PDC_MODEL_CAPABILITIES:
+ result[0] = PARISC_PDC_CAPABILITIES;
+ result[0] |= PDC_MODEL_OS32; /* we do support 32-bit */
+ result[0] &= ~PDC_MODEL_OS64; /* but not 64-bit (yet) */
+ 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;
+ }
+ dprintf(0, "\n\nSeaBIOS: Unimplemented PDC_MODEL function %d %x %x %x %x\n", ARG1, ARG2, ARG3, ARG4, ARG5);
+ return PDC_BAD_OPTION;
+}
+
+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;
+
+ 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_loop = 1;
+ machine_cache_info->dt_loop = 1;
+
+#if 0
+ dprintf(0, "\n\nCACHE IC: %ld %ld %ld DC: %ld %ld %ld\n",
+ machine_cache_info->ic_count, machine_cache_info->ic_loop, machine_cache_info->ic_stride,
+ 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 = 0; /* no instruction cache */
+ machine_cache_info->ic_count = 0;
+ machine_cache_info->ic_loop = 0;
+ machine_cache_info->dc_size = 0; /* no data cache */
+ machine_cache_info->dc_count = 0;
+ machine_cache_info->dc_loop = 0;
+#endif
+
+ memcpy(result, cache_info, sizeof(cache_info));
+ return PDC_OK;
+ }
+ dprintf(0, "\n\nSeaBIOS: Unimplemented PDC_CACHE function %d %x %x %x %x\n", ARG1, ARG2, ARG3, ARG4, ARG5);
+ return PDC_BAD_OPTION;
+}
+
+static int pdc_hpa(unsigned int *arg)
+{
+ unsigned long option = ARG1;
+ unsigned long *result = (unsigned long *)ARG2;
+ unsigned long hpa;
+ int i;
+
+ switch (option) {
+ 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! */
+ result[0] = hpa; /* CPU_HPA */
+ result[1] = i; /* for SMP: 0,1,2,3,4...(num of this cpu) */
+ return PDC_OK;
+ case PDC_HPA_MODULES:
+ return PDC_BAD_OPTION; // all modules on same board as the processor.
+ }
+ return PDC_BAD_OPTION;
+}
+
+static int pdc_coproc(unsigned int *arg)
+{
+ unsigned long option = ARG1;
+ unsigned long *result = (unsigned long *)ARG2;
+ unsigned char mask;
+ switch (option) {
+ case PDC_COPROC_CFG:
+ memset(result, 0, 32 * sizeof(unsigned long));
+ mask = ~((1 << (8-smp_cpus))-1);
+ /* set bit per cpu in ccr_functional and ccr_present: */
+ mtctl(mask, 10); /* initialize cr10 */
+ result[0] = mask;
+ result[1] = mask;
+ result[17] = 1; // Revision
+ result[18] = 19; // Model
+ return PDC_OK;
+ }
+ return PDC_BAD_OPTION;
+}
+
+static int pdc_iodc(unsigned int *arg)
+{
+ unsigned long option = ARG1;
+ unsigned long *result = (unsigned long *)ARG2;
+ unsigned long hpa;
+ 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);
+ 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;
+ }
+
+ 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 !!)
+ 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;
+ return PDC_OK;
+ }
+
+ // ARG4 is IODC function to copy.
+ if (ARG4 < PDC_IODC_RI_INIT || ARG4 > PDC_IODC_RI_TLB)
+ return PDC_IODC_INVALID_INDEX;
+
+ *result = 512; /* max size of function iodc_entry */
+ if (ARG6 < *result)
+ return PDC_IODC_COUNT;
+ memcpy((void*) ARG5, &iodc_entry, *result);
+ c = (unsigned char *) &iodc_entry_table;
+ /* calculate offset into jump table. */
+ c += (ARG4 - PDC_IODC_RI_INIT) * 2 * sizeof(unsigned int);
+ memcpy((void*) ARG5, c, 2 * sizeof(unsigned int));
+ // dprintf(0, "\n\nSeaBIOS: Info PDC_IODC function OK\n");
+ flush_data_cache((char*)ARG5, *result);
+ return PDC_OK;
+ break;
+ case PDC_IODC_NINIT: /* non-destructive init */
+ case PDC_IODC_DINIT: /* destructive init */
+ break;
+ case PDC_IODC_MEMERR:
+ result[0] = 0; /* IO_STATUS */
+ result[1] = 0;
+ result[2] = 0;
+ result[3] = 0;
+ return PDC_OK;
+ }
+ dprintf(0, "\n\nSeaBIOS: Unimplemented PDC_IODC function %ld ARG3=%x ARG4=%x ARG5=%x ARG6=%x\n", option, ARG3, ARG4, ARG5, ARG6);
+ return PDC_BAD_OPTION;
+}
+
+static int pdc_tod(unsigned int *arg)
+{
+ unsigned long option = ARG1;
+ unsigned long *result = (unsigned long *)ARG2;
+
+ switch (option) {
+ case PDC_TOD_READ:
+ result[0] = lasi_rtc_read();
+ result[1] = result[2] = result[3] = 0;
+ return PDC_OK;
+ case PDC_TOD_WRITE:
+ lasi_rtc_write(ARG2);
+ return PDC_OK;
+ case 2: /* PDC_TOD_CALIBRATE_TIMERS */
+ /* double-precision floating-point with frequency of Interval Timer in megahertz: */
+ *(double*)&result[0] = (double)CPU_CLOCK_MHZ;
+ /* unsigned 64-bit integers representing clock accuracy in parts per billion: */
+ result[2] = 1000000000; /* TOD_acc */
+ result[3] = 0x5a6c; /* CR_acc (interval timer) */
+ return PDC_OK;
+ }
+ dprintf(0, "\n\nSeaBIOS: Unimplemented PDC_TOD function %ld ARG2=%x ARG3=%x ARG4=%x\n", option, ARG2, ARG3, ARG4);
+ return PDC_BAD_OPTION;
+}
+
+static int pdc_stable(unsigned int *arg)
+{
+ unsigned long option = ARG1;
+ unsigned long *result = (unsigned long *)ARG2;
+
+ // dprintf(0, "\n\nSeaBIOS: PDC_STABLE function %ld ARG2=%x ARG3=%x ARG4=%x\n", option, ARG2, ARG3, ARG4);
+ switch (option) {
+ case PDC_STABLE_READ:
+ if ((ARG2 + ARG4) > STABLE_STORAGE_SIZE)
+ return PDC_INVALID_ARG;
+ memcpy((unsigned char *) ARG3, &stable_storage[ARG2], ARG4);
+ return PDC_OK;
+ case PDC_STABLE_WRITE:
+ if ((ARG2 + ARG4) > STABLE_STORAGE_SIZE)
+ return PDC_INVALID_ARG;
+ memcpy(&stable_storage[ARG2], (unsigned char *) ARG3, ARG4);
+ return PDC_OK;
+ case PDC_STABLE_RETURN_SIZE:
+ result[0] = STABLE_STORAGE_SIZE;
+ return PDC_OK;
+ case PDC_STABLE_VERIFY_CONTENTS:
+ return PDC_OK;
+ case PDC_STABLE_INITIALIZE:
+ init_stable_storage();
+ return PDC_OK;
+ }
+ return PDC_BAD_OPTION;
+}
+
+static int pdc_nvolatile(unsigned int *arg)
+{
+ unsigned long option = ARG1;
+ unsigned long *result = (unsigned long *)ARG2;
+
+ switch (option) {
+ case PDC_NVOLATILE_READ:
+ if ((ARG2 + ARG4) > NVOLATILE_STORAGE_SIZE)
+ return PDC_INVALID_ARG;
+ memcpy((unsigned char *) ARG3, &nvolatile_storage[ARG2], ARG4);
+ return PDC_OK;
+ case PDC_NVOLATILE_WRITE:
+ if ((ARG2 + ARG4) > NVOLATILE_STORAGE_SIZE)
+ return PDC_INVALID_ARG;
+ memcpy(&nvolatile_storage[ARG2], (unsigned char *) ARG3, ARG4);
+ return PDC_OK;
+ case PDC_NVOLATILE_RETURN_SIZE:
+ result[0] = NVOLATILE_STORAGE_SIZE;
+ return PDC_OK;
+ case PDC_NVOLATILE_VERIFY_CONTENTS:
+ return PDC_OK;
+ case PDC_NVOLATILE_INITIALIZE:
+ memset(nvolatile_storage, 0, sizeof(nvolatile_storage));
+ return PDC_OK;
+ }
+ return PDC_BAD_OPTION;
+}
+
+static int pdc_add_valid(unsigned int *arg)
+{
+ unsigned long option = ARG1;
+
+ // dprintf(0, "\n\nSeaBIOS: PDC_ADD_VALID function %ld ARG2=%x called.\n", option, ARG2);
+ if (option != 0)
+ return PDC_BAD_OPTION;
+ if (0 && ARG2 == 0) // should PAGE0 be valid? HP-UX asks for it, but maybe due a bug in our code...
+ return 1;
+ // if (ARG2 < PAGE_SIZE) return PDC_ERROR;
+ if (ARG2 < ram_size)
+ return PDC_OK;
+ if (ARG2 >= (unsigned long)_sti_rom_start &&
+ ARG2 <= (unsigned long)_sti_rom_end)
+ return PDC_OK;
+ if (ARG2 < FIRMWARE_END)
+ return 1;
+ if (ARG2 <= 0xffffffff)
+ return PDC_OK;
+ dprintf(0, "\n\nSeaBIOS: FAILED!!!! PDC_ADD_VALID function %ld ARG2=%x called.\n", option, ARG2);
+ return PDC_REQ_ERR_0; /* Operation completed with a requestor bus error. */
+}
+
+static int pdc_proc(unsigned int *arg)
+{
+ extern void enter_smp_idle_loop(void);
+ unsigned long option = ARG1;
+
+ switch (option) {
+ case 1:
+ if (ARG2 != 0)
+ return PDC_BAD_PROC;
+ /* let the current CPU sleep until rendenzvous. */
+ enter_smp_idle_loop();
+ return PDC_OK;
+ }
+ return PDC_BAD_OPTION;
+}
+
+static int pdc_block_tlb(unsigned int *arg)
+{
+ unsigned long option = ARG1;
+ struct pdc_btlb_info *info = (struct pdc_btlb_info *) ARG2;
+
+ switch (option) {
+ case PDC_BTLB_INFO:
+ memset(info, 0, sizeof(*info));
+ if (btlb_entries) {
+ /* TODO: fill in BTLB info */
+ }
+ return PDC_OK;
+ case PDC_BTLB_INSERT:
+ case PDC_BTLB_PURGE:
+ case PDC_BTLB_PURGE_ALL:
+ /* TODO: implement above functions */
+ return PDC_BAD_OPTION;
+
+ }
+ return PDC_BAD_OPTION;
+}
+
+static int pdc_tlb(unsigned int *arg)
+{
+#if 0
+ /* still buggy, let's avoid it to keep things simple. */
+ switch (option) {
+ case PDC_TLB_INFO:
+ result[0] = PAGE_SIZE;
+ result[0] = PAGE_SIZE << 2;
+ return PDC_OK;
+ case PDC_TLB_SETUP:
+ result[0] = ARG5 & 1;
+ result[1] = 0;
+ return PDC_OK;
+ }
+#endif
+ return PDC_BAD_PROC;
+}
+
+static int pdc_mem(unsigned int *arg)
+{
+ unsigned long option = ARG1;
+ unsigned long *result = (unsigned long *)ARG2;
+
+ // only implemented on 64bit PDC!
+ if (sizeof(unsigned long) == sizeof(unsigned int))
+ return PDC_BAD_PROC;
+
+ switch (option) {
+ case PDC_MEM_MEMINFO:
+ result[0] = 0; // no PDT entries
+ result[1] = 0; // page entries
+ result[2] = 0; // PDT status
+ result[3] = (unsigned long)-1ULL; // dbe_loc
+ result[4] = GoldenMemory; // good_mem
+ return PDC_OK;
+ case PDC_MEM_READ_PDT:
+ result[0] = 0; // no PDT entries
+ return PDC_OK;
+ case PDC_MEM_GOODMEM:
+ GoldenMemory = ARG3;
+ return PDC_OK;
+ }
+ dprintf(0, "\n\nSeaBIOS: Check PDC_MEM option %ld ARG3=%x ARG4=%x ARG5=%x\n", option, ARG3, ARG4, ARG5);
+ return PDC_BAD_PROC;
+}
+
+static int pdc_psw(unsigned int *arg)
+{
+ static unsigned long psw_defaults = PDC_PSW_ENDIAN_BIT;
+ unsigned long option = ARG1;
+ unsigned long *result = (unsigned long *)ARG2;
+
+ if (option > PDC_PSW_SET_DEFAULTS)
+ return PDC_BAD_OPTION;
+ /* FIXME: For 64bit support enable PDC_PSW_WIDE_BIT too! */
+ if (option == PDC_PSW_MASK)
+ *result = PDC_PSW_ENDIAN_BIT;
+ if (option == PDC_PSW_GET_DEFAULTS)
+ *result = psw_defaults;
+ if (option == PDC_PSW_SET_DEFAULTS) {
+ psw_defaults = ARG2;
+ }
+ return PDC_OK;
+}
+
+static int pdc_system_map(unsigned int *arg)
+{
+ unsigned long option = ARG1;
+ unsigned long *result = (unsigned long *)ARG2;
+ struct pdc_module_path *mod_path;
+ unsigned long hpa;
+ int 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)
+ return PDC_NE_MOD; // Module not found
+
+ mod_path = (struct pdc_module_path *)ARG3;
+ if (mod_path)
+ *mod_path = *parisc_devices[hpa_index].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
+ 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)
+ return PDC_NE_MOD; // Module not found
+
+ memset(result, 0, 32*sizeof(long));
+ ARG4 -= 1;
+ if (ARG4 >= parisc_devices[hpa_index].num_addr)
+ return PDC_INVALID_ARG;
+ result[0] = parisc_devices[hpa_index].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);
+ if (!dev)
+ return PDC_NE_MOD;
+
+ result[0] = dev->hpa;
+ result[1] = 1;
+ result[2] = 0;
+ return PDC_OK;
+ }
+ return PDC_BAD_OPTION;
+}
+
+static int pdc_soft_power(unsigned int *arg)
+{
+ unsigned long option = ARG1;
+ unsigned long *result = (unsigned long *)ARG2;
+
+ switch (option) {
+ case PDC_SOFT_POWER_INFO:
+ result[0] = (unsigned long) powersw_ptr;
+ return PDC_OK;
+ case PDC_SOFT_POWER_ENABLE:
+ /* put soft power button under hardware (ARG3=0) or
+ * software (ARG3=1) control. */
+ *powersw_ptr = (ARG3 & 1) << 8 | (*powersw_ptr & 1);
+ check_powersw_button();
+ return PDC_OK;
+ }
+ // dprintf(0, "\n\nSeaBIOS: PDC_SOFT_POWER called with ARG2=%x ARG3=%x ARG4=%x\n", ARG2, ARG3, ARG4);
+ return PDC_BAD_OPTION;
+}
+
+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;
+ 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);
+ if (!dev)
+ return PDC_NE_MOD;
+ memcpy(memmap, dev->mod_info, sizeof(*memmap));
+ return PDC_OK;
+ }
+ return PDC_BAD_OPTION;
+}
+
+static int pdc_io(unsigned int *arg)
+{
+ unsigned long option = ARG1;
+
+ switch (option) {
+ case PDC_IO_READ_AND_CLEAR_ERRORS:
+ dprintf(0, "\n\nSeaBIOS: PDC_IO called with ARG2=%x ARG3=%x ARG4=%x\n", ARG2, ARG3, ARG4);
+ // return PDC_BAD_OPTION;
+ case PDC_IO_RESET:
+ case PDC_IO_RESET_DEVICES:
+ return PDC_OK;
+ }
+ return PDC_BAD_OPTION;
+}
+
+static int pdc_lan_station_id(unsigned int *arg)
+{
+ unsigned long option = ARG1;
+
+ switch (option) {
+ case PDC_LAN_STATION_ID_READ:
+ if (ARG3 != LASI_LAN_HPA)
+ return PDC_INVALID_ARG;
+ if (!keep_this_hpa(LASI_LAN_HPA))
+ return PDC_INVALID_ARG;
+ /* Let qemu store the MAC of NIC to address @ARG2 */
+ *(unsigned long *)(LASI_LAN_HPA+12) = ARG2;
+ return PDC_OK;
+ }
+ return PDC_BAD_OPTION;
+}
+
+static int pdc_pci_index(unsigned int *arg)
+{
+ unsigned long option = ARG1;
+ unsigned long *result = (unsigned long *)ARG2;
+
+ // 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));
+ result[0] = 2; /* XXX physical hardware returns those ?!? */
+ result[16] = 0x60;
+ result[17] = 0x90;
+ return PDC_OK;
+ case PDC_PCI_GET_INT_TBL_SIZE:
+ 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;
+ case PDC_PCI_PCI_PATH_TO_PCI_HPA:
+ result[0] = PCI_HPA;
+ return PDC_OK;
+ case PDC_PCI_PCI_HPA_TO_PCI_PATH:
+ BUG_ON(1);
+ }
+ return PDC_BAD_OPTION;
+}
+
+static int pdc_initiator(unsigned int *arg)
+{
+ unsigned long option = ARG1;
+ unsigned long *result = (unsigned long *)ARG2;
+
+ switch (option) {
+ case PDC_GET_INITIATOR:
+ // 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
+ result[2] = 7; // firmware suggested value for initiator_id
+ result[3] = 10; // firmware suggested value for scsi_rate
+ result[4] = 0; // width: 0:"Narrow, 1:"Wide"
+ result[5] = 0; // mode: 0:SMODE_SE, 1:SMODE_HVD, 2:SMODE_LVD
+ return PDC_OK;
+ case PDC_SET_INITIATOR:
+ case PDC_DELETE_INITIATOR:
+ case PDC_RETURN_TABLE_SIZE:
+ case PDC_RETURN_TABLE:
+ break;
+ }
+ dprintf(0, "\n\nSeaBIOS: Unimplemented PDC_INITIATOR function %ld ARG3=%x ARG4=%x ARG5=%x\n", option, ARG3, ARG4, ARG5);
+ return PDC_BAD_OPTION;
+}
+
+
+int __VISIBLE parisc_pdc_entry(unsigned int *arg FUNC_MANY_ARGS)
+{
+ unsigned long proc = ARG0;
+ unsigned long option = ARG1;
+
+ if (pdc_debug & DEBUG_PDC) {
+ printf("\nSeaBIOS: Start PDC proc %s(%d) option %d result=0x%x ARG3=0x%x %s ",
+ pdc_name(ARG0), ARG0, ARG1, ARG2, ARG3, (proc == PDC_IODC)?hpa_name(ARG3):"");
+ printf("ARG4=0x%x ARG5=0x%x ARG6=0x%x ARG7=0x%x\n", ARG4, ARG5, ARG6, ARG7);
+ }
+
+ switch (proc) {
+ case PDC_POW_FAIL:
+ break;
+
+ case PDC_CHASSIS: /* chassis functions */
+ return pdc_chassis(arg);
+
+ case PDC_PIM:
+ return pdc_pim(arg);
+
+ case PDC_MODEL: /* model information */
+ return pdc_model(arg);
+
+ case PDC_CACHE:
+ return pdc_cache(arg);
+
+ case PDC_HPA:
+ return pdc_hpa(arg);
+
+ case PDC_COPROC:
+ return pdc_coproc(arg);
+
+ case PDC_IODC: /* Call IODC functions */
+ return pdc_iodc(arg);
+
+ case PDC_TOD: /* Time of day */
+ return pdc_tod(arg);
+
+ case PDC_STABLE:
+ return pdc_stable(arg);
+
+ case PDC_NVOLATILE:
+ return pdc_nvolatile(arg);
+
+ case PDC_ADD_VALID:
+ return pdc_add_valid(arg);
+
+ case PDC_INSTR:
+ return PDC_BAD_PROC;
+
+ case PDC_PROC:
+ return pdc_proc(arg);
+
+ case PDC_CONFIG: /* Obsolete */
+ return PDC_BAD_PROC;
+
+ case PDC_BLOCK_TLB:
+ return pdc_block_tlb(arg);
+
+ case PDC_TLB: /* hardware TLB not used on Linux, but on HP-UX (if available) */
+ return pdc_tlb(arg);
+
+ case PDC_MEM:
+ return pdc_mem(arg);
+
+ case PDC_PSW: /* Get/Set default System Mask */
+ return pdc_psw(arg);
+
+ case PDC_SYSTEM_MAP:
+ return pdc_system_map(arg);
+
+ case PDC_SOFT_POWER: // don't have a soft-power switch
+ return pdc_soft_power(arg);
+
+ case PDC_CRASH_PREP:
+ /* This should actually quiesce all I/O and prepare the System for crash dumping.
+ Ignoring it for now, otherwise the BUG_ON below would quit qemu before we have
+ a chance to see the kernel panic */
+ return PDC_OK;
+
+ case 26: // PDC_SCSI_PARMS is the architected firmware interface to replace the Hversion PDC_INITIATOR procedure.
+ return PDC_BAD_PROC;
+
+ case 64: // Called by HP-UX 11 bootcd during boot. Probably checks PDC_PAT_CELL (even if we are not PAT firmware)
+ case 65: // Called by HP-UX 11 bootcd during boot. Probably checks PDC_PAT_CHASSIS_LOG (even if we are not PAT firmware)
+ dprintf(0, "\n\nSeaBIOS: UNKNOWN PDC proc %lu OPTION %lu called with ARG2=%x ARG3=%x ARG4=%x\n", proc, option, ARG2, ARG3, ARG4);
+ return PDC_BAD_PROC;
+
+ case PDC_MEM_MAP:
+ return pdc_mem_map(arg);
+
+ case 134:
+ if (ARG1 == 1 || ARG1 == 513) /* HP-UX 11.11 ask for it. */
+ return PDC_BAD_PROC;
+ break;
+
+ case PDC_IO:
+ return pdc_io(arg);
+
+ case PDC_BROADCAST_RESET:
+ dprintf(0, "\n\nSeaBIOS: PDC_BROADCAST_RESET (reset system) called with ARG3=%x ARG4=%x\n", ARG3, ARG4);
+ reset();
+ return PDC_OK;
+
+ case PDC_LAN_STATION_ID:
+ return pdc_lan_station_id(arg);
+
+ case PDC_SYSTEM_INFO:
+ if (ARG1 == PDC_SYSINFO_RETURN_INFO_SIZE)
+ return PDC_BAD_PROC;
+ break;
+
+ case PDC_PCI_INDEX:
+ return pdc_pci_index(arg);
+
+ case PDC_RELOCATE:
+ /* We don't want to relocate any firmware. */
+ return PDC_BAD_PROC;
+
+ case PDC_INITIATOR:
+ return pdc_initiator(arg);
+ }
+
+ printf("\n** WARNING **: SeaBIOS: Unimplemented PDC proc %s(%d) option %d result=%x ARG3=%x ",
+ pdc_name(ARG0), ARG0, ARG1, ARG2, ARG3);
+ printf("ARG4=%x ARG5=%x ARG6=%x ARG7=%x\n", ARG4, ARG5, ARG6, ARG7);
+
+ BUG_ON(pdc_debug);
+ return PDC_BAD_PROC;
+}
+
+
+/********************************************************
+ * BOOT MENU
+ ********************************************************/
+
+extern void find_initial_parisc_boot_drives(
+ struct drive_s **harddisc,
+ struct drive_s **cdrom);
+extern struct drive_s *select_parisc_boot_drive(char bootdrive);
+
+static int parisc_boot_menu(unsigned long *iplstart, unsigned long *iplend,
+ char bootdrive)
+{
+ int ret;
+ unsigned int *target = (void *)(PAGE0->mem_free + 32*1024);
+ struct disk_op_s disk_op = {
+ .buf_fl = target,
+ .command = CMD_SEEK,
+ .count = 0,
+ .lba = 0,
+ };
+
+ boot_drive = select_parisc_boot_drive(bootdrive);
+ disk_op.drive_fl = boot_drive;
+ if (boot_drive == NULL) {
+ printf("SeaBIOS: No boot device.\n");
+ return 0;
+ }
+
+ /* seek to beginning of disc/CD */
+ disk_op.drive_fl = boot_drive;
+ ret = process_op(&disk_op);
+ // printf("DISK_SEEK returned %d\n", ret);
+ if (ret)
+ return 0;
+
+ // printf("Boot disc type is 0x%x\n", boot_drive->type);
+ disk_op.drive_fl = boot_drive;
+ if (boot_drive->type == DTYPE_ATA_ATAPI ||
+ boot_drive->type == DTYPE_ATA) {
+ disk_op.command = CMD_ISREADY;
+ ret = process_op(&disk_op);
+ } else {
+ ret = scsi_is_ready(&disk_op);
+ }
+ // printf("DISK_READY returned %d\n", ret);
+
+ /* read boot sector of disc/CD */
+ disk_op.drive_fl = boot_drive;
+ disk_op.buf_fl = target;
+ disk_op.command = CMD_READ;
+ disk_op.count = (FW_BLOCKSIZE / disk_op.drive_fl->blksize);
+ disk_op.lba = 0;
+ // printf("blocksize is %d, count is %d\n", disk_op.drive_fl->blksize, disk_op.count);
+ ret = process_op(&disk_op);
+ // printf("DISK_READ(count=%d) = %d\n", disk_op.count, ret);
+ if (ret)
+ return 0;
+
+ unsigned int ipl_addr = be32_to_cpu(target[0xf0/sizeof(int)]); /* offset 0xf0 in bootblock */
+ unsigned int ipl_size = be32_to_cpu(target[0xf4/sizeof(int)]);
+ unsigned int ipl_entry= be32_to_cpu(target[0xf8/sizeof(int)]);
+
+ /* check LIF header of bootblock */
+ if ((target[0]>>16) != 0x8000) {
+ printf("Not a PA-RISC boot image. LIF magic is 0x%x, should be 0x8000.\n", target[0]>>16);
+ return 0;
+ }
+ // printf("ipl start at 0x%x, size %d, entry 0x%x\n", ipl_addr, ipl_size, ipl_entry);
+ // TODO: check ipl values for out of range. Rules are:
+ // IPL_ADDR - 2 Kbyte aligned, nonzero.
+ // IPL_SIZE - Multiple of 2 Kbytes, nonzero, less than or equal to 256 Kbytes.
+ // IPL_ENTRY- Word aligned, less than IPL_SIZE
+
+ /* seek to beginning of IPL */
+ disk_op.drive_fl = boot_drive;
+ disk_op.command = CMD_SEEK;
+ disk_op.count = 0; // (ipl_size / disk_op.drive_fl->blksize);
+ disk_op.lba = (ipl_addr / disk_op.drive_fl->blksize);
+ ret = process_op(&disk_op);
+ // printf("DISK_SEEK to IPL returned %d\n", ret);
+
+ /* read IPL */
+ disk_op.drive_fl = boot_drive;
+ disk_op.buf_fl = target;
+ disk_op.command = CMD_READ;
+ disk_op.count = (ipl_size / disk_op.drive_fl->blksize);
+ disk_op.lba = (ipl_addr / disk_op.drive_fl->blksize);
+ ret = process_op(&disk_op);
+ // printf("DISK_READ IPL returned %d\n", ret);
+
+ // printf("First word at %p is 0x%x\n", target, target[0]);
+
+ /* execute IPL */
+ // TODO: flush D- and I-cache, not needed in emulation ?
+ *iplstart = *iplend = (unsigned long) target;
+ *iplstart += ipl_entry;
+ *iplend += ALIGN(ipl_size, sizeof(unsigned long));
+ return 1;
+}
+
+
+/********************************************************
+ * FIRMWARE MAIN ENTRY POINT
+ ********************************************************/
+
+static const struct pz_device mem_cons_sti_boot = {
+ .hpa = LASI_GFX_HPA,
+ .iodc_io = (unsigned long)&iodc_entry,
+ .cl_class = CL_DISPL,
+};
+
+static const struct pz_device mem_kbd_sti_boot = {
+ .hpa = LASI_PS2KBD_HPA,
+ .iodc_io = (unsigned long)&iodc_entry,
+ .cl_class = CL_KEYBD,
+};
+
+static const struct pz_device mem_cons_boot = {
+ .hpa = PARISC_SERIAL_CONSOLE - 0x800,
+ .iodc_io = (unsigned long)&iodc_entry,
+ .cl_class = CL_DUPLEX,
+};
+
+static const struct pz_device mem_kbd_boot = {
+ .hpa = PARISC_SERIAL_CONSOLE - 0x800,
+ .iodc_io = (unsigned long)&iodc_entry,
+ .cl_class = CL_KEYBD,
+};
+
+static const struct pz_device mem_boot_boot = {
+ .dp.flags = PF_AUTOBOOT,
+ .hpa = IDE_HPA, // DINO_SCSI_HPA, // IDE_HPA
+ .iodc_io = (unsigned long) &iodc_entry,
+ .cl_class = CL_RANDOM,
+};
+
+static void find_pci_slot_for_dev(unsigned int pciid, char *pci_slot)
+{
+ struct pci_device *pci;
+
+ foreachpci(pci)
+ if (pci->vendor == pciid) {
+ *pci_slot = (pci->bdf >> 3) & 0x0f;
+ return;
+ }
+}
+
+/* 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;
+ unsigned long hpa;
+ struct pdc_module_path *mod_path;
+
+ hpa = source->hpa;
+ hpa_index = find_hpa_index(hpa);
+
+ if (HPA_is_storage_device(hpa))
+ 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 {
+ BUG_ON(hpa_index < 0);
+ mod_path = parisc_devices[hpa_index].mod_path;
+ }
+
+ /* copy device path to entry in PAGE0 */
+ memcpy((void*)dest, source, sizeof(*source));
+ memcpy((void*)&dest->dp, mod_path, sizeof(struct device_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);
+}
+
+static int artist_present(void)
+{
+ return !!(*(u32 *)0xf8380004 == 0x6dc20006);
+}
+
+unsigned long _atoul(char *str)
+{
+ unsigned long val = 0;
+ while (*str) {
+ val *= 10;
+ val += *str - '0';
+ str++;
+ }
+ return val;
+}
+
+unsigned long romfile_loadstring_to_int(const char *name, unsigned long defval)
+{
+ char *str = romfile_loadfile(name, NULL);
+ if (str)
+ return _atoul(str);
+ return defval;
+}
+
+void __VISIBLE start_parisc_firmware(void)
+{
+ unsigned int i, cpu_hz;
+ unsigned long iplstart, iplend;
+
+ unsigned long interactive = (linux_kernel_entry == 1) ? 1:0;
+ char bootdrive = (char)cmdline; // c = hdd, d = CD/DVD
+
+ if (smp_cpus > HPPA_MAX_CPUS)
+ smp_cpus = HPPA_MAX_CPUS;
+
+ if (ram_size >= FIRMWARE_START)
+ ram_size = FIRMWARE_START;
+
+ /* Initialize qemu fw_cfg interface */
+ PORT_QEMU_CFG_CTL = fw_cfg_port;
+ qemu_cfg_init();
+
+ 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();
+ }
+
+ tlb_entries = romfile_loadint("/etc/cpu/tlb_entries", 256);
+ dprintf(0, "fw_cfg: TLB entries %d\n", tlb_entries);
+
+ btlb_entries = romfile_loadint("/etc/cpu/btlb_entries", 8);
+ dprintf(0, "fw_cfg: BTLB entries %d\n", btlb_entries);
+
+ powersw_ptr = (int *) (unsigned long)
+ romfile_loadint("/etc/power-button-addr", (unsigned long)&powersw_nop);
+
+ pdc_debug = romfile_loadstring_to_int("opt/pdc_debug", 0);
+
+ /* Initialize PAGE0 */
+ memset((void*)PAGE0, 0, sizeof(*PAGE0));
+
+ /* copy pdc_entry entry into low memory. */
+ memcpy((void*)MEM_PDC_ENTRY, &pdc_entry_table, 3*4);
+ flush_data_cache((char*)MEM_PDC_ENTRY, 3*4);
+
+ PAGE0->memc_cont = ram_size;
+ PAGE0->memc_phsize = ram_size;
+ PAGE0->memc_adsize = ram_size;
+ PAGE0->mem_pdc_hi = (MEM_PDC_ENTRY + 0ULL) >> 32;
+ PAGE0->mem_free = 0x6000; // min PAGE_SIZE
+ PAGE0->mem_hpa = CPU_HPA; // HPA of boot-CPU
+ PAGE0->mem_pdc = MEM_PDC_ENTRY;
+ PAGE0->mem_10msec = CPU_CLOCK_MHZ*(1000000ULL/100);
+
+ BUG_ON(PAGE0->mem_free <= MEM_PDC_ENTRY);
+ BUG_ON(smp_cpus < 1 || smp_cpus > HPPA_MAX_CPUS);
+
+ /* Put QEMU/SeaBIOS marker in PAGE0.
+ * The Linux kernel will search for it. */
+ memcpy((char*)&PAGE0->pad0, "SeaBIOS", 8);
+ PAGE0->pad0[2] = ((unsigned long long)PORT_QEMU_CFG_CTL) >> 32; /* store as 64bit value */
+ PAGE0->pad0[3] = PORT_QEMU_CFG_CTL;
+ *powersw_ptr = 0x01; /* button not pressed, hw controlled. */
+
+ PAGE0->imm_hpa = MEMORY_HPA;
+ PAGE0->imm_spa_size = ram_size;
+ PAGE0->imm_max_mem = ram_size;
+
+ // Initialize boot paths (disc, display & keyboard)
+ if (artist_present()) {
+ sti_rom_init();
+ sti_console_init(&sti_proc_rom);
+ ps2port_setup();
+ prepare_boot_path(&(PAGE0->mem_cons), &mem_cons_sti_boot, 0x60);
+ prepare_boot_path(&(PAGE0->mem_kbd), &mem_kbd_sti_boot, 0xa0);
+ PAGE0->proc_sti = (u32)&sti_proc_rom;
+ } else {
+ remove_from_keep_list(LASI_GFX_HPA);
+ remove_from_keep_list(LASI_PS2KBD_HPA);
+ remove_from_keep_list(LASI_PS2MOU_HPA);
+ prepare_boot_path(&(PAGE0->mem_cons), &mem_cons_boot, 0x60);
+ prepare_boot_path(&(PAGE0->mem_kbd), &mem_kbd_boot, 0xa0);
+ }
+
+ /* Initialize device list */
+ remove_parisc_devices(smp_cpus);
+
+ /* Show list of HPA devices which are still returned by firmware. */
+ if (0) { for (i=0; parisc_devices[i].hpa; i++)
+ printf("Kept #%d at 0x%lx\n", i, parisc_devices[i].hpa);
+ }
+
+ // Initialize stable storage
+ init_stable_storage();
+
+ chassis_code = 0;
+
+ malloc_preinit();
+
+ // 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, %ld x PA7300LC (PCX-L2) at %d.%06d MHz, %lu MB RAM.\n",
+ smp_cpus, cpu_hz / 1000000, cpu_hz % 1000000,
+ ram_size/1024/1024);
+
+ if (ram_size < MIN_RAM_SIZE) {
+ printf("\nSeaBIOS: Machine configured with too little "
+ "memory (%ld MB), minimum is %d MB.\n\n",
+ ram_size/1024/1024, MIN_RAM_SIZE/1024/1024);
+ hlt();
+ }
+
+ // handle_post();
+ serial_debug_preinit();
+ debug_banner();
+ // maininit();
+ qemu_preinit();
+ RamSize = ram_size;
+ // coreboot_preinit();
+
+ pci_setup();
+
+ serial_setup();
+ block_setup();
+
+ printf("\n");
+ printf("SeaBIOS PA-RISC Firmware Version %d\n"
+ "\n"
+ "Duplex Console IO Dependent Code (IODC) revision 1\n"
+ "\n"
+ "Memory Test/Initialization Completed\n\n", SEABIOS_HPPA_VERSION);
+ printf("------------------------------------------------------------------------------\n"
+ " (c) Copyright 2017-2021 Helge Deller <deller@gmx.de> and SeaBIOS developers.\n"
+ "------------------------------------------------------------------------------\n\n");
+ printf( " Processor Speed State Coprocessor State Cache Size\n"
+ " --------- -------- --------------------- ----------------- ----------\n");
+ for (i = 0; i < smp_cpus; i++)
+ printf(" %s%d " __stringify(CPU_CLOCK_MHZ)
+ " MHz %s Functional 0 KB\n",
+ i < 10 ? " ":"", i, i?"Idle ":"Active");
+ printf("\n\n");
+ printf(" Available memory: %llu MB\n"
+ " Good memory required: %d MB\n\n",
+ (unsigned long long)ram_size/1024/1024, MIN_RAM_SIZE/1024/1024);
+
+ // search boot devices
+ find_initial_parisc_boot_drives(&parisc_boot_harddisc, &parisc_boot_cdrom);
+
+ printf(" Primary boot path: FWSCSI.%d.%d\n"
+ " Alternate boot path: FWSCSI.%d.%d\n"
+ " Console path: %s\n"
+ " Keyboard path: PS2\n\n",
+ parisc_boot_harddisc->target, parisc_boot_harddisc->lun,
+ parisc_boot_cdrom->target, parisc_boot_cdrom->lun,
+ HPA_is_graphics_device(PAGE0->mem_cons.hpa) ? "GRAPHICS(1)" :
+ ((PARISC_SERIAL_CONSOLE == PORT_SERIAL1) ? "SERIAL_1.9600.8.none" : "SERIAL_2.9600.8.none"));
+
+ if (bootdrive == 'c')
+ boot_drive = parisc_boot_harddisc;
+ else
+ 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]);
+
+ // Store initial emulated drives path master data
+ if (parisc_boot_harddisc) {
+ mod_path_emulated_drives.layers[0] = parisc_boot_harddisc->target;
+ mod_path_emulated_drives.layers[1] = parisc_boot_harddisc->lun;
+ }
+
+ prepare_boot_path(&(PAGE0->mem_boot), &mem_boot_boot, 0x0);
+
+ // copy primary boot path to alt boot path
+ memcpy(&stable_storage[0x80], &stable_storage[0], 0x20);
+ if (parisc_boot_cdrom) {
+ stable_storage[0x80 + 11] = parisc_boot_cdrom->target;
+ stable_storage[0x80 + 12] = parisc_boot_cdrom->lun;
+ }
+ // currently booted path == CD in PAGE0->mem_boot
+ if (boot_drive) {
+ PAGE0->mem_boot.dp.layers[0] = boot_drive->target;
+ PAGE0->mem_boot.dp.layers[1] = boot_drive->lun;
+ }
+
+ /* directly start Linux kernel if it was given on qemu command line. */
+ if (linux_kernel_entry > 1) {
+ void (*start_kernel)(unsigned long mem_free, unsigned long cline,
+ unsigned long rdstart, unsigned long rdend);
+
+ printf("Autobooting Linux kernel which was loaded by qemu...\n\n");
+ start_kernel = (void *) linux_kernel_entry;
+ start_kernel(PAGE0->mem_free, cmdline, initrd_start, initrd_end);
+ hlt(); /* this ends the emulator */
+ }
+
+#if 0
+ printf("------- Main Menu -------------------------------------------------------------\n\n"
+ " Command Description\n"
+ " ------- -----------\n"
+ " BOot [PRI|ALT|<path>] Boot from specified path\n"
+ " PAth [PRI|ALT|CON|KEY] [<path>] Display or modify a path\n"
+ " SEArch [DIsplay|IPL] [<path>] Search for boot devices\n\n"
+ " COnfiguration [<command>] Access Configuration menu/commands\n"
+ " INformation [<command>] Access Information menu/commands\n"
+ " SERvice [<command>] Access Service menu/commands\n\n"
+ " DIsplay Redisplay the current menu\n"
+ " HElp [<menu>|<command>] Display help for menu or command\n"
+ " RESET Restart the system\n"
+ "-------\n"
+ "Main Menu: Enter command > ");
+#endif
+
+ /* check for bootable drives, and load and start IPL bootloader if possible */
+ if (parisc_boot_menu(&iplstart, &iplend, bootdrive)) {
+ void (*start_ipl)(long interactive, long iplend);
+
+ PAGE0->mem_boot.dp.layers[0] = boot_drive->target;
+ PAGE0->mem_boot.dp.layers[1] = boot_drive->lun;
+
+ printf("\nBooting...\n"
+ "Boot IO Dependent Code (IODC) revision 153\n\n"
+ "%s Booted.\n", PAGE0->imm_soft_boot ? "SOFT":"HARD");
+ start_ipl = (void *) iplstart;
+ start_ipl(interactive, iplend);
+ }
+
+ hlt(); /* this ends the emulator */
+}
diff --git a/src/parisc/pdc.h b/src/parisc/pdc.h
new file mode 100644
index 0000000..2d03189
--- /dev/null
+++ b/src/parisc/pdc.h
@@ -0,0 +1,694 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+#ifndef _UAPI_PARISC_PDC_H
+#define _UAPI_PARISC_PDC_H
+
+/*
+ * PDC return values ...
+ * All PDC calls return a subset of these errors.
+ */
+
+#define PDC_WARN 3 /* Call completed with a warning */
+#define PDC_REQ_ERR_1 2 /* See above */
+#define PDC_REQ_ERR_0 1 /* Call would generate a requestor error */
+#define PDC_OK 0 /* Call completed successfully */
+#define PDC_BAD_PROC -1 /* Called non-existent procedure*/
+#define PDC_BAD_OPTION -2 /* Called with non-existent option */
+#define PDC_ERROR -3 /* Call could not complete without an error */
+#define PDC_NE_MOD -5 /* Module not found */
+#define PDC_NE_CELL_MOD -7 /* Cell module not found */
+#define PDC_NE_BOOTDEV -9 /* Cannot locate a console device or boot device */
+#define PDC_INVALID_ARG -10 /* Called with an invalid argument */
+#define PDC_BUS_POW_WARN -12 /* Call could not complete in allowed power budget */
+#define PDC_NOT_NARROW -17 /* Narrow mode not supported */
+
+/*
+ * PDC entry points...
+ */
+
+#define PDC_POW_FAIL 1 /* perform a power-fail */
+#define PDC_POW_FAIL_PREPARE 0 /* prepare for powerfail */
+
+#define PDC_CHASSIS 2 /* PDC-chassis functions */
+#define PDC_CHASSIS_DISP 0 /* update chassis display */
+#define PDC_CHASSIS_WARN 1 /* return chassis warnings */
+#define PDC_CHASSIS_DISPWARN 2 /* update&return chassis status */
+#define PDC_RETURN_CHASSIS_INFO 128 /* HVERSION dependent: return chassis LED/LCD info */
+
+#define PDC_PIM 3 /* Get PIM data */
+#define PDC_PIM_HPMC 0 /* Transfer HPMC data */
+#define PDC_PIM_RETURN_SIZE 1 /* Get Max buffer needed for PIM*/
+#define PDC_PIM_LPMC 2 /* Transfer HPMC data */
+#define PDC_PIM_SOFT_BOOT 3 /* Transfer Soft Boot data */
+#define PDC_PIM_TOC 4 /* Transfer TOC data */
+
+#define PDC_MODEL 4 /* PDC model information call */
+#define PDC_MODEL_INFO 0 /* returns information */
+#define PDC_MODEL_BOOTID 1 /* set the BOOT_ID */
+#define PDC_MODEL_VERSIONS 2 /* returns cpu-internal versions*/
+#define PDC_MODEL_SYSMODEL 3 /* return system model info */
+#define PDC_MODEL_ENSPEC 4 /* enable specific option */
+#define PDC_MODEL_DISPEC 5 /* disable specific option */
+#define PDC_MODEL_CPU_ID 6 /* returns cpu-id (only newer machines!) */
+#define PDC_MODEL_CAPABILITIES 7 /* returns OS32/OS64-flags */
+/* Values for PDC_MODEL_CAPABILITIES non-equivalent virtual aliasing support */
+#define PDC_MODEL_OS64 (1 << 0)
+#define PDC_MODEL_OS32 (1 << 1)
+#define PDC_MODEL_IOPDIR_FDC (1 << 2)
+#define PDC_MODEL_NVA_MASK (3 << 4)
+#define PDC_MODEL_NVA_SUPPORTED (0 << 4)
+#define PDC_MODEL_NVA_SLOW (1 << 4)
+#define PDC_MODEL_NVA_UNSUPPORTED (3 << 4)
+#define PDC_MODEL_GET_BOOT__OP 8 /* returns boot test options */
+#define PDC_MODEL_SET_BOOT__OP 9 /* set boot test options */
+#define PDC_MODEL_GET_PLATFORM_INFO 10 /* returns platform info */
+#define PDC_MODEL_GET_INSTALL_KERNEL 11 /* returns kernel for installation */
+
+#define PA89_INSTRUCTION_SET 0x4 /* capabilities returned */
+#define PA90_INSTRUCTION_SET 0x8
+
+#define PDC_CACHE 5 /* return/set cache (& TLB) info*/
+#define PDC_CACHE_INFO 0 /* returns information */
+#define PDC_CACHE_SET_COH 1 /* set coherence state */
+#define PDC_CACHE_RET_SPID 2 /* returns space-ID bits */
+
+#define PDC_HPA 6 /* return HPA of processor */
+#define PDC_HPA_PROCESSOR 0
+#define PDC_HPA_MODULES 1
+
+#define PDC_COPROC 7 /* Co-Processor (usually FP unit(s)) */
+#define PDC_COPROC_CFG 0 /* Co-Processor Cfg (FP unit(s) enabled?) */
+
+#define PDC_IODC 8 /* talk to IODC */
+#define PDC_IODC_READ 0 /* read IODC entry point */
+/* PDC_IODC_RI_ * INDEX parameter of PDC_IODC_READ */
+#define PDC_IODC_RI_DATA_BYTES 0 /* IODC Data Bytes */
+/* 1, 2 obsolete - HVERSION dependent*/
+#define PDC_IODC_RI_INIT 3 /* Initialize module */
+#define PDC_IODC_RI_IO 4 /* Module input/output */
+#define PDC_IODC_RI_SPA 5 /* Module input/output */
+#define PDC_IODC_RI_CONFIG 6 /* Module input/output */
+/* 7 obsolete - HVERSION dependent */
+#define PDC_IODC_RI_TEST 8 /* Module input/output */
+#define PDC_IODC_RI_TLB 9 /* Module input/output */
+#define PDC_IODC_NINIT 2 /* non-destructive init */
+#define PDC_IODC_DINIT 3 /* destructive init */
+#define PDC_IODC_MEMERR 4 /* check for memory errors */
+#define PDC_IODC_INDEX_DATA 0 /* get first 16 bytes from mod IODC */
+#define PDC_IODC_BUS_ERROR -4 /* bus error return value */
+#define PDC_IODC_INVALID_INDEX -5 /* invalid index return value */
+#define PDC_IODC_COUNT -6 /* count is too small */
+
+#define PDC_TOD 9 /* time-of-day clock (TOD) */
+#define PDC_TOD_READ 0 /* read TOD */
+#define PDC_TOD_WRITE 1 /* write TOD */
+#define PDC_TOD_CALIBRATE 2 /* calibrate timers */
+
+#define PDC_STABLE 10 /* stable storage (sprockets) */
+#define PDC_STABLE_READ 0
+#define PDC_STABLE_WRITE 1
+#define PDC_STABLE_RETURN_SIZE 2
+#define PDC_STABLE_VERIFY_CONTENTS 3
+#define PDC_STABLE_INITIALIZE 4
+
+#define PDC_NVOLATILE 11 /* often not implemented */
+#define PDC_NVOLATILE_READ 0
+#define PDC_NVOLATILE_WRITE 1
+#define PDC_NVOLATILE_RETURN_SIZE 2
+#define PDC_NVOLATILE_VERIFY_CONTENTS 3
+#define PDC_NVOLATILE_INITIALIZE 4
+
+#define PDC_ADD_VALID 12 /* Memory validation PDC call */
+#define PDC_ADD_VALID_VERIFY 0 /* Make PDC_ADD_VALID verify region */
+
+#define PDC_DEBUG 14 /* Obsolete */
+
+#define PDC_INSTR 15 /* get instr to invoke PDCE_CHECK() */
+
+#define PDC_PROC 16 /* (sprockets) */
+
+#define PDC_CONFIG 17 /* (sprockets) */
+#define PDC_CONFIG_DECONFIG 0
+#define PDC_CONFIG_DRECONFIG 1
+#define PDC_CONFIG_DRETURN_CONFIG 2
+
+#define PDC_BLOCK_TLB 18 /* manage hardware block-TLB */
+#define PDC_BTLB_INFO 0 /* returns parameter */
+#define PDC_BTLB_INSERT 1 /* insert BTLB entry */
+#define PDC_BTLB_PURGE 2 /* purge BTLB entries */
+#define PDC_BTLB_PURGE_ALL 3 /* purge all BTLB entries */
+
+#define PDC_TLB 19 /* manage hardware TLB miss handling */
+#define PDC_TLB_INFO 0 /* returns parameter */
+#define PDC_TLB_SETUP 1 /* set up miss handling */
+
+#define PDC_MEM 20 /* Manage memory */
+#define PDC_MEM_MEMINFO 0 /* Return PDT info */
+#define PDC_MEM_ADD_PAGE 1 /* Add page to PDT */
+#define PDC_MEM_CLEAR_PDT 2 /* Clear PDT */
+#define PDC_MEM_READ_PDT 3 /* Read PDT entry */
+#define PDC_MEM_RESET_CLEAR 4 /* Reset PDT clear flag */
+#define PDC_MEM_GOODMEM 5 /* Set good_mem value */
+#define PDC_MEM_TABLE 128 /* Non contig mem map (sprockets) */
+#define PDC_MEM_RETURN_ADDRESS_TABLE PDC_MEM_TABLE
+#define PDC_MEM_GET_MEMORY_SYSTEM_TABLES_SIZE 131
+#define PDC_MEM_GET_MEMORY_SYSTEM_TABLES 132
+#define PDC_MEM_GET_PHYSICAL_LOCATION_FROM_MEMORY_ADDRESS 133
+
+#define PDC_MEM_RET_SBE_REPLACED 5 /* PDC_MEM return values */
+#define PDC_MEM_RET_DUPLICATE_ENTRY 4
+#define PDC_MEM_RET_BUF_SIZE_SMALL 1
+#define PDC_MEM_RET_PDT_FULL -11
+#define PDC_MEM_RET_INVALID_PHYSICAL_LOCATION ~0ULL
+
+#define PDC_PSW 21 /* Get/Set default System Mask */
+#define PDC_PSW_MASK 0 /* Return mask */
+#define PDC_PSW_GET_DEFAULTS 1 /* Return defaults */
+#define PDC_PSW_SET_DEFAULTS 2 /* Set default */
+#define PDC_PSW_ENDIAN_BIT 1 /* set for big endian */
+#define PDC_PSW_WIDE_BIT 2 /* set for wide mode */
+
+#define PDC_SYSTEM_MAP 22 /* find system modules */
+#define PDC_FIND_MODULE 0
+#define PDC_FIND_ADDRESS 1
+#define PDC_TRANSLATE_PATH 2
+
+#define PDC_SOFT_POWER 23 /* soft power switch */
+#define PDC_SOFT_POWER_INFO 0 /* return info about the soft power switch */
+#define PDC_SOFT_POWER_ENABLE 1 /* enable/disable soft power switch */
+
+#define PDC_ALLOC 24 /* allocate static storage for PDC & IODC */
+
+#define PDC_CRASH_PREP 25 /* Prepare system for crash dump */
+#define PDC_CRASH_DUMP 0 /* Do platform specific preparations for dump */
+#define PDC_CRASH_LOG_CEC_ERROR 1 /* Dump hardware registers */
+
+#define PDC_SCSI_PARMS 26 /* Get and set SCSI parameters */
+#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 */
+
+/* HVERSION dependent */
+
+/* The PDC_MEM_MAP calls */
+#define PDC_MEM_MAP 128 /* on s700: return page info */
+#define PDC_MEM_MAP_HPA 0 /* returns hpa of a module */
+
+#define PDC_EEPROM 129 /* EEPROM access */
+#define PDC_EEPROM_READ_WORD 0
+#define PDC_EEPROM_WRITE_WORD 1
+#define PDC_EEPROM_READ_BYTE 2
+#define PDC_EEPROM_WRITE_BYTE 3
+#define PDC_EEPROM_EEPROM_PASSWORD -1000
+
+#define PDC_NVM 130 /* NVM (non-volatile memory) access */
+#define PDC_NVM_READ_WORD 0
+#define PDC_NVM_WRITE_WORD 1
+#define PDC_NVM_READ_BYTE 2
+#define PDC_NVM_WRITE_BYTE 3
+
+#define PDC_SEED_ERROR 132 /* (sprockets) */
+
+#define PDC_IO 135 /* log error info, reset IO system */
+#define PDC_IO_READ_AND_CLEAR_ERRORS 0
+#define PDC_IO_RESET 1
+#define PDC_IO_RESET_DEVICES 2
+/* sets bits 6&7 (little endian) of the HcControl Register */
+#define PDC_IO_USB_SUSPEND 0xC000000000000000
+#define PDC_IO_EEPROM_IO_ERR_TABLE_FULL -5 /* return value */
+#define PDC_IO_NO_SUSPEND -6 /* return value */
+
+#define PDC_BROADCAST_RESET 136 /* reset all processors */
+#define PDC_DO_RESET 0 /* option: perform a broadcast reset */
+#define PDC_DO_FIRM_TEST_RESET 1 /* Do broadcast reset with bitmap */
+#define PDC_BR_RECONFIGURATION 2 /* reset w/reconfiguration */
+#define PDC_FIRM_TEST_MAGIC 0xab9ec36fUL /* for this reboot only */
+
+#define PDC_LAN_STATION_ID 138 /* Hversion dependent mechanism for */
+#define PDC_LAN_STATION_ID_READ 0 /* getting the lan station address */
+
+#define PDC_LAN_STATION_ID_SIZE 6
+
+#define PDC_CHECK_RANGES 139 /* (sprockets) */
+
+#define PDC_NV_SECTIONS 141 /* (sprockets) */
+
+#define PDC_PERFORMANCE 142 /* performance monitoring */
+
+#define PDC_SYSTEM_INFO 143 /* system information */
+#define PDC_SYSINFO_RETURN_INFO_SIZE 0
+#define PDC_SYSINFO_RRETURN_SYS_INFO 1
+#define PDC_SYSINFO_RRETURN_ERRORS 2
+#define PDC_SYSINFO_RRETURN_WARNINGS 3
+#define PDC_SYSINFO_RETURN_REVISIONS 4
+#define PDC_SYSINFO_RRETURN_DIAGNOSE 5
+#define PDC_SYSINFO_RRETURN_HV_DIAGNOSE 1005
+
+#define PDC_RDR 144 /* (sprockets) */
+#define PDC_RDR_READ_BUFFER 0
+#define PDC_RDR_READ_SINGLE 1
+#define PDC_RDR_WRITE_SINGLE 2
+
+#define PDC_INTRIGUE 145 /* (sprockets) */
+#define PDC_INTRIGUE_WRITE_BUFFER 0
+#define PDC_INTRIGUE_GET_SCRATCH_BUFSIZE 1
+#define PDC_INTRIGUE_START_CPU_COUNTERS 2
+#define PDC_INTRIGUE_STOP_CPU_COUNTERS 3
+
+#define PDC_STI 146 /* STI access */
+/* same as PDC_PCI_XXX values (see below) */
+
+/* Legacy PDC definitions for same stuff */
+#define PDC_PCI_INDEX 147
+#define PDC_PCI_INTERFACE_INFO 0
+#define PDC_PCI_SLOT_INFO 1
+#define PDC_PCI_INFLIGHT_BYTES 2
+#define PDC_PCI_READ_CONFIG 3
+#define PDC_PCI_WRITE_CONFIG 4
+#define PDC_PCI_READ_PCI_IO 5
+#define PDC_PCI_WRITE_PCI_IO 6
+#define PDC_PCI_READ_CONFIG_DELAY 7
+#define PDC_PCI_UPDATE_CONFIG_DELAY 8
+#define PDC_PCI_PCI_PATH_TO_PCI_HPA 9
+#define PDC_PCI_PCI_HPA_TO_PCI_PATH 10
+#define PDC_PCI_PCI_PATH_TO_PCI_BUS 11
+#define PDC_PCI_PCI_RESERVED 12
+#define PDC_PCI_PCI_INT_ROUTE_SIZE 13
+#define PDC_PCI_GET_INT_TBL_SIZE PDC_PCI_PCI_INT_ROUTE_SIZE
+#define PDC_PCI_PCI_INT_ROUTE 14
+#define PDC_PCI_GET_INT_TBL PDC_PCI_PCI_INT_ROUTE
+#define PDC_PCI_READ_MON_TYPE 15
+#define PDC_PCI_WRITE_MON_TYPE 16
+
+#define PDC_RELOCATE 149 /* (sprockets) */
+#define PDC_RELOCATE_GET_RELOCINFO 0
+#define PDC_RELOCATE_CHECKSUM 1
+#define PDC_RELOCATE_RELOCATE 2
+
+/* Get SCSI Interface Card info: SDTR, SCSI ID, mode (SE vs LVD) */
+#define PDC_INITIATOR 163
+#define PDC_GET_INITIATOR 0
+#define PDC_SET_INITIATOR 1
+#define PDC_DELETE_INITIATOR 2
+#define PDC_RETURN_TABLE_SIZE 3
+#define PDC_RETURN_TABLE 4
+
+#define PDC_LINK 165 /* (sprockets) */
+#define PDC_LINK_PCI_ENTRY_POINTS 0 /* list (Arg1) = 0 */
+#define PDC_LINK_USB_ENTRY_POINTS 1 /* list (Arg1) = 1 */
+
+/* cl_class
+ * page 3-33 of IO-Firmware ARS
+ * IODC ENTRY_INIT(Search first) RET[1]
+ */
+#define CL_NULL 0 /* invalid */
+#define CL_RANDOM 1 /* random access (as disk) */
+#define CL_SEQU 2 /* sequential access (as tape) */
+#define CL_DUPLEX 7 /* full-duplex point-to-point (RS-232, Net) */
+#define CL_KEYBD 8 /* half-duplex console (HIL Keyboard) */
+#define CL_DISPL 9 /* half-duplex console (display) */
+#define CL_FC 10 /* FiberChannel access media */
+
+/* IODC ENTRY_INIT() */
+#define ENTRY_INIT_SRCH_FRST 2
+#define ENTRY_INIT_SRCH_NEXT 3
+#define ENTRY_INIT_MOD_DEV 4
+#define ENTRY_INIT_DEV 5
+#define ENTRY_INIT_MOD 6
+#define ENTRY_INIT_MSG 9
+
+/* IODC ENTRY_IO() */
+#define ENTRY_IO_BOOTIN 0
+#define ENTRY_IO_BOOTOUT 1
+#define ENTRY_IO_CIN 2
+#define ENTRY_IO_COUT 3
+#define ENTRY_IO_CLOSE 4
+#define ENTRY_IO_GETMSG 9
+#define ENTRY_IO_BBLOCK_IN 16
+#define ENTRY_IO_BBLOCK_OUT 17
+
+/* IODC ENTRY_SPA() */
+
+/* IODC ENTRY_CONFIG() */
+
+/* IODC ENTRY_TEST() */
+
+/* IODC ENTRY_TLB() */
+
+/* constants for OS (NVM...) */
+#define OS_ID_NONE 0 /* Undefined OS ID */
+#define OS_ID_HPUX 1 /* HP-UX OS */
+#define OS_ID_MPEXL 2 /* MPE XL OS */
+#define OS_ID_OSF 3 /* OSF OS */
+#define OS_ID_HPRT 4 /* HP-RT OS */
+#define OS_ID_NOVEL 5 /* NOVELL OS */
+#define OS_ID_LINUX 6 /* Linux */
+
+
+/* constants for PDC_CHASSIS */
+#define OSTAT_OFF 0
+#define OSTAT_FLT 1
+#define OSTAT_TEST 2
+#define OSTAT_INIT 3
+#define OSTAT_SHUT 4
+#define OSTAT_WARN 5
+#define OSTAT_RUN 6
+#define OSTAT_ON 7
+
+/* Page Zero constant offsets used by the HPMC handler */
+#define BOOT_CONSOLE_HPA_OFFSET 0x3c0
+#define BOOT_CONSOLE_SPA_OFFSET 0x3c4
+#define BOOT_CONSOLE_PATH_OFFSET 0x3a8
+
+/* size of the pdc_result buffer for firmware.c */
+#define NUM_PDC_RESULT 32
+
+#if !defined(__ASSEMBLY__)
+
+/* flags of the device_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 pz_device {
+ struct device_path dp; /* see above */
+ /* struct iomod *hpa; */
+ unsigned int hpa; /* HPA base address */
+ /* char *spa; */
+ unsigned int spa; /* SPA base address */
+ /* int (*iodc_io)(struct iomod*, ...); */
+ unsigned int iodc_io; /* device entry point */
+ short pad; /* reserved */
+ unsigned short cl_class;/* see below */
+} __attribute__((aligned(8))) ;
+
+struct zeropage {
+ /* [0x000] initialize vectors (VEC) */
+ unsigned int vec_special; /* must be zero */
+ /* int (*vec_pow_fail)(void);*/
+ unsigned int vec_pow_fail; /* power failure handler */
+ /* int (*vec_toc)(void); */
+ unsigned int vec_toc;
+ unsigned int vec_toclen;
+ /* int (*vec_rendz)(void); */
+ unsigned int vec_rendz;
+ int vec_pow_fail_flen;
+ int vec_pad[10];
+
+ /* [0x040] reserved processor dependent */
+ int pad0[112]; /* in QEMU pad0[0] holds "SeaBIOS\0" */
+
+ /* [0x200] reserved */
+ int pad1[84];
+
+ /* [0x350] memory configuration (MC) */
+ int memc_cont; /* contiguous mem size (bytes) */
+ int memc_phsize; /* physical memory size */
+ int memc_adsize; /* additional mem size, bytes of SPA space used by PDC */
+ unsigned int mem_pdc_hi; /* used for 64-bit */
+
+ /* [0x360] various parameters for the boot-CPU */
+ /* unsigned int *mem_booterr[8]; */
+ unsigned int mem_booterr[8]; /* ptr to boot errors */
+ unsigned int mem_free; /* first location, where OS can be loaded */
+ /* struct iomod *mem_hpa; */
+ unsigned int mem_hpa; /* HPA of the boot-CPU */
+ /* int (*mem_pdc)(int, ...); */
+ unsigned int mem_pdc; /* PDC entry point */
+ unsigned int mem_10msec; /* number of clock ticks in 10msec */
+
+ /* [0x390] initial memory module (IMM) */
+ /* struct iomod *imm_hpa; */
+ unsigned int imm_hpa; /* HPA of the IMM */
+ int imm_soft_boot; /* 0 = was hard boot, 1 = was soft boot */
+ unsigned int imm_spa_size; /* SPA size of the IMM in bytes */
+ unsigned int imm_max_mem; /* bytes of mem in IMM */
+
+ /* [0x3A0] boot console, display device and keyboard */
+ struct pz_device mem_cons; /* description of console device */
+ struct pz_device mem_boot; /* description of boot device */
+ struct pz_device mem_kbd; /* description of keyboard device */
+
+ /* [0x430] reserved */
+ int pad430[116];
+
+ /* [0x600] processor dependent */
+ unsigned int pad600[1];
+ unsigned int proc_sti; /* pointer to STI ROM */
+ unsigned int pad608[126];
+};
+
+struct pdc_chassis_info { /* for PDC_CHASSIS_INFO */
+ unsigned long actcnt; /* actual number of bytes returned */
+ unsigned long maxcnt; /* maximum number of bytes that could be returned */
+};
+
+struct pdc_coproc_cfg { /* for PDC_COPROC_CFG */
+ unsigned long ccr_functional;
+ unsigned long ccr_present;
+ unsigned long revision;
+ unsigned long model;
+};
+
+struct pdc_model { /* for PDC_MODEL */
+ unsigned long hversion;
+ unsigned long sversion;
+ unsigned long hw_id;
+ unsigned long boot_id;
+ unsigned long sw_id;
+ unsigned long sw_cap;
+ unsigned long arch_rev;
+ unsigned long pot_key;
+ unsigned long curr_key;
+};
+
+struct pdc_cache_cf { /* for PDC_CACHE (I/D-caches) */
+ unsigned long
+#ifdef __LP64__
+ cc_padW:32,
+#endif
+ cc_alias: 4, /* alias boundaries for virtual addresses */
+ cc_block: 4, /* to determine most efficient stride */
+ cc_line : 3, /* maximum amount written back as a result of store (multiple of 16 bytes) */
+ cc_shift: 2, /* how much to shift cc_block left */
+ cc_wt : 1, /* 0 = WT-Dcache, 1 = WB-Dcache */
+ cc_sh : 2, /* 0 = separate I/D-cache, else shared I/D-cache */
+ cc_cst : 3, /* 0 = incoherent D-cache, 1=coherent D-cache */
+ cc_pad1 : 10, /* reserved */
+ cc_hv : 3; /* hversion dependent */
+};
+
+struct pdc_tlb_cf { /* for PDC_CACHE (I/D-TLB's) */
+ unsigned long tc_pad0:12, /* reserved */
+#ifdef __LP64__
+ tc_padW:32,
+#endif
+ tc_sh : 2, /* 0 = separate I/D-TLB, else shared I/D-TLB */
+ tc_hv : 1, /* HV */
+ tc_page : 1, /* 0 = 2K page-size-machine, 1 = 4k page size */
+ tc_cst : 3, /* 0 = incoherent operations, else coherent operations */
+ tc_aid : 5, /* ITLB: width of access ids of processor (encoded!) */
+ tc_sr : 8; /* ITLB: width of space-registers (encoded) */
+};
+
+struct pdc_cache_info { /* main-PDC_CACHE-structure (caches & TLB's) */
+ /* I-cache */
+ unsigned long ic_size; /* size in bytes */
+ struct pdc_cache_cf ic_conf; /* configuration */
+ unsigned long ic_base; /* base-addr */
+ unsigned long ic_stride;
+ unsigned long ic_count;
+ unsigned long ic_loop;
+ /* D-cache */
+ unsigned long dc_size; /* size in bytes */
+ struct pdc_cache_cf dc_conf; /* configuration */
+ unsigned long dc_base; /* base-addr */
+ unsigned long dc_stride;
+ unsigned long dc_count;
+ unsigned long dc_loop;
+ /* Instruction-TLB */
+ unsigned long it_size; /* number of entries in I-TLB */
+ struct pdc_tlb_cf it_conf; /* I-TLB-configuration */
+ unsigned long it_sp_base;
+ unsigned long it_sp_stride;
+ unsigned long it_sp_count;
+ unsigned long it_off_base;
+ unsigned long it_off_stride;
+ unsigned long it_off_count;
+ unsigned long it_loop;
+ /* data-TLB */
+ unsigned long dt_size; /* number of entries in D-TLB */
+ struct pdc_tlb_cf dt_conf; /* D-TLB-configuration */
+ unsigned long dt_sp_base;
+ unsigned long dt_sp_stride;
+ unsigned long dt_sp_count;
+ unsigned long dt_off_base;
+ unsigned long dt_off_stride;
+ unsigned long dt_off_count;
+ unsigned long dt_loop;
+};
+
+/* Might need adjustment to work with 64-bit firmware */
+struct pdc_iodc { /* PDC_IODC */
+ unsigned char hversion_model;
+ unsigned char hversion;
+ unsigned char spa;
+ unsigned char type;
+ unsigned int sversion_rev:4;
+ unsigned int sversion_model:19;
+ unsigned int sversion_opt:8;
+ unsigned char rev;
+ unsigned char dep;
+ unsigned char features;
+ unsigned char pad1;
+ unsigned int checksum:16;
+ unsigned int length:16;
+ unsigned int pad[15];
+} __attribute__((aligned(8))) ;
+
+/* no BLTBs in pa2.0 processors */
+struct pdc_btlb_info_range {
+ unsigned char res00;
+ unsigned char num_i;
+ unsigned char num_d;
+ unsigned char num_comb;
+};
+
+struct pdc_btlb_info { /* PDC_BLOCK_TLB, return of PDC_BTLB_INFO */
+ unsigned int min_size; /* minimum size of BTLB in pages */
+ unsigned int max_size; /* maximum size of BTLB in pages */
+ struct pdc_btlb_info_range fixed_range_info;
+ struct pdc_btlb_info_range variable_range_info;
+};
+
+struct pdc_mem_retinfo { /* PDC_MEM/PDC_MEM_MEMINFO (return info) */
+ unsigned long pdt_size;
+ unsigned long pdt_entries;
+ unsigned long pdt_status;
+ unsigned long first_dbe_loc;
+ unsigned long good_mem;
+};
+
+struct pdc_mem_read_pdt { /* PDC_MEM/PDC_MEM_READ_PDT (return info) */
+ unsigned long pdt_entries;
+};
+
+#ifdef __LP64__
+struct pdc_memory_table_raddr { /* PDC_MEM/PDC_MEM_TABLE (return info) */
+ unsigned long entries_returned;
+ unsigned long entries_total;
+};
+
+struct pdc_memory_table { /* PDC_MEM/PDC_MEM_TABLE (arguments) */
+ unsigned long paddr;
+ unsigned int pages;
+ unsigned int reserved;
+};
+#endif /* __LP64__ */
+
+struct pdc_system_map_mod_info { /* PDC_SYSTEM_MAP/FIND_MODULE */
+ unsigned long mod_addr;
+ unsigned long mod_pgs;
+ unsigned long add_addrs;
+};
+
+struct pdc_system_map_addr_info { /* PDC_SYSTEM_MAP/FIND_ADDRESS */
+ unsigned long mod_addr;
+ unsigned long mod_pgs;
+};
+
+struct pdc_initiator { /* PDC_INITIATOR */
+ int host_id;
+ int factor;
+ int width;
+ 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 */
+ unsigned long more_pgs; /* number of additional I/O pgs */
+};
+
+struct pdc_tod {
+ unsigned long tod_sec;
+ unsigned long tod_usec;
+};
+
+/* architected results from PDC_PIM/transfer hpmc on a PA1.1 machine */
+
+struct pdc_hpmc_pim_11 { /* PDC_PIM */
+ unsigned int gr[32];
+ unsigned int cr[32];
+ unsigned int sr[8];
+ unsigned int iasq_back;
+ unsigned int iaoq_back;
+ unsigned int check_type;
+ unsigned int cpu_state;
+ unsigned int rsvd1;
+ unsigned int cache_check;
+ unsigned int tlb_check;
+ unsigned int bus_check;
+ unsigned int assists_check;
+ unsigned int rsvd2;
+ unsigned int assist_state;
+ unsigned int responder_addr;
+ unsigned int requestor_addr;
+ unsigned int path_info;
+ unsigned long long fr[32];
+};
+
+/*
+ * architected results from PDC_PIM/transfer hpmc on a PA2.0 machine
+ *
+ * Note that PDC_PIM doesn't care whether or not wide mode was enabled
+ * so the results are different on PA1.1 vs. PA2.0 when in narrow mode.
+ *
+ * Note also that there are unarchitected results available, which
+ * are hversion dependent. Do a "ser pim 0 hpmc" after rebooting, since
+ * the firmware is probably the best way of printing hversion dependent
+ * data.
+ */
+
+struct pdc_hpmc_pim_20 { /* PDC_PIM */
+ unsigned long long gr[32];
+ unsigned long long cr[32];
+ unsigned long long sr[8];
+ unsigned long long iasq_back;
+ unsigned long long iaoq_back;
+ unsigned int check_type;
+ unsigned int cpu_state;
+ unsigned int cache_check;
+ unsigned int tlb_check;
+ unsigned int bus_check;
+ unsigned int assists_check;
+ unsigned int assist_state;
+ unsigned int path_info;
+ unsigned long long responder_addr;
+ unsigned long long requestor_addr;
+ unsigned long long fr[32];
+};
+
+#endif /* !defined(__ASSEMBLY__) */
+
+#endif /* _UAPI_PARISC_PDC_H */
diff --git a/src/parisc/sti.c b/src/parisc/sti.c
new file mode 100644
index 0000000..7c7fb54
--- /dev/null
+++ b/src/parisc/sti.c
@@ -0,0 +1,179 @@
+/* STI console code
+ *
+ * Copyright (C) 2019 Sven Schnelle <svens@stackframe.org>
+ *
+ * This file may be distributed under the terms of the GNU LGPLv3 license.
+ */
+
+#include "autoconf.h"
+#include "types.h"
+#include "std/optionrom.h"
+#include "vgahw.h"
+#include "parisc/sticore.h"
+#include "parisc/hppa_hardware.h"
+#include "output.h"
+#include "pdc.h"
+
+#define PAGE0 ((volatile struct zeropage *) 0UL)
+
+static int sti_enabled;
+
+static struct sti_init_flags sti_init_flags = {
+ .wait = 1,
+ .reset = 1,
+ .text = 1,
+ .nontext = 1,
+ .cmap_blk = 1,
+ .no_chg_bet = 1,
+ .no_chg_bei = 1,
+ .init_cmap_tx = 1,
+ .clear = 1,
+};
+
+static struct sti_glob_cfg_ext sti_glob_ext_cfg = {
+};
+
+static struct sti_glob_cfg sti_glob_cfg = {
+ .region_ptrs = { 0, ARTIST_FB_ADDR, 0xf8100000, 0xf8380000, 0, 0, 0, 0 },
+ .ext_ptr = (u32)&sti_glob_ext_cfg,
+};
+
+static struct sti_init_inptr_ext sti_init_inptr_ext = {
+ .config_mon_type = 1,
+};
+
+static struct sti_init_inptr sti_init_inptr = {
+ .text_planes = 3,
+ .ext_ptr = (u32)&sti_init_inptr_ext,
+};
+
+static struct sti_init_outptr sti_init_outptr = {
+};
+
+static struct sti_font_flags sti_font_flags = {
+ .wait = 1,
+};
+
+static struct sti_font_inptr sti_font_inptr = {
+ .fg_color = 1,
+ .bg_color = 0,
+};
+
+static struct sti_font_outptr sti_font_outptr = {
+};
+
+static struct sti_blkmv_flags sti_blkmv_flags = {
+ .wait = 1,
+};
+
+static struct sti_blkmv_inptr sti_blkmv_inptr = {
+};
+
+static struct sti_blkmv_outptr sti_blkmv_outptr = {
+};
+
+static void sti_putchar(struct sti_rom *rom, int row, int column, const char c)
+{
+ int (*sti_unpmv)(struct sti_font_flags *,
+ struct sti_font_inptr *,
+ struct sti_font_outptr *,
+ struct sti_glob_cfg *);
+
+ struct sti_rom_font *font = (void *)rom + rom->font_start;
+ sti_unpmv = (void *)rom + rom->font_unpmv;
+
+ sti_font_inptr.dest_x = column * font->width;
+ sti_font_inptr.dest_y = row * font->height;
+ sti_font_inptr.index = c;
+ sti_font_inptr.font_start_addr = (u32)rom + rom->font_start;
+
+ sti_unpmv(&sti_font_flags, &sti_font_inptr,
+ &sti_font_outptr, &sti_glob_cfg);
+}
+
+static void sti_block_move(struct sti_rom *rom, int src_x, int src_y,
+ int dest_x, int dest_y,
+ int width, int height,
+ int clear)
+{
+ int (*sti_block_move)(struct sti_blkmv_flags *,
+ struct sti_blkmv_inptr *,
+ struct sti_blkmv_outptr *,
+ struct sti_glob_cfg *);
+ sti_block_move = (void *)rom + rom->block_move;
+
+ sti_blkmv_inptr.src_x = src_x;
+ sti_blkmv_inptr.src_y = src_y;
+ sti_blkmv_inptr.dest_x = dest_x;
+ sti_blkmv_inptr.dest_y = dest_y;
+ sti_blkmv_inptr.width = width;
+ sti_blkmv_inptr.height = height;
+ sti_blkmv_flags.clear = clear;
+
+ sti_block_move(&sti_blkmv_flags, &sti_blkmv_inptr,
+ &sti_blkmv_outptr, &sti_glob_cfg);
+}
+
+void sti_console_init(struct sti_rom *rom)
+{
+ int (*sti_init)(struct sti_init_flags *,
+ struct sti_init_inptr *,
+ struct sti_init_outptr *,
+ struct sti_glob_cfg *);
+
+ sti_init = (void *)rom + rom->init_graph;
+
+ sti_init(&sti_init_flags, &sti_init_inptr,
+ &sti_init_outptr, &sti_glob_cfg);
+
+ sti_enabled = 1;
+}
+
+void sti_putc(const char c)
+{
+ struct sti_rom *rom = (struct sti_rom *)PAGE0->proc_sti;
+ struct sti_rom_font *font = (void *)rom + rom->font_start;
+ static int row, col;
+
+ if (!sti_enabled)
+ return;
+
+ if (c == '\r') {
+ col = 0;
+ return;
+ }
+
+ if (c == 0x08) {
+ if (col > 0)
+ col--;
+ return;
+ }
+
+ if (c == '\n') {
+ col = 0;
+ row++;
+
+ if (row >= sti_glob_cfg.onscreen_y / font->height) {
+ sti_block_move(rom,
+ 0, font->height,
+ 0, 0,
+ sti_glob_cfg.total_x, sti_glob_cfg.onscreen_y - font->height, 0);
+
+ /* clear new line at bottom */
+ sti_block_move(rom,
+ 0, 0, /* source */
+ 0, sti_glob_cfg.onscreen_y - font->height, /* dest */
+ sti_glob_cfg.onscreen_x, font->height,
+ 1);
+
+ row = (sti_glob_cfg.onscreen_y / font->height)-1;
+ }
+ return;
+ }
+
+ /* wrap to next line or scroll screen if EOL reached */
+ if (col >= ((sti_glob_cfg.onscreen_x / font->width) - 1))
+ sti_putc('\n');
+
+ sti_putchar(rom, row, col++, c);
+}
diff --git a/src/parisc/sticore.h b/src/parisc/sticore.h
new file mode 100644
index 0000000..0c5556b
--- /dev/null
+++ b/src/parisc/sticore.h
@@ -0,0 +1,326 @@
+/* SPDX-License-Identifier:GPL-2.0 */
+#ifndef STICORE_H
+#define STICORE_H
+
+#include "types.h"
+
+/* generic STI structures & functions */
+
+#define MAX_STI_ROMS 4 /* max no. of ROMs which this driver handles */
+
+#define STI_REGION_MAX 8 /* hardcoded STI constants */
+#define STI_DEV_NAME_LENGTH 32
+#define STI_MONITOR_MAX 256
+
+#define STI_FONT_HPROMAN8 1
+#define STI_FONT_KANA8 2
+
+#define ALT_CODE_TYPE_UNKNOWN 0x00 /* alt code type values */
+#define ALT_CODE_TYPE_PA_RISC_64 0x01
+
+#define STI_WAIT 1
+
+/* STI function configuration structs */
+
+typedef union region {
+ struct {
+ u32 offset:14; /* offset in 4kbyte page */
+ u32 sys_only:1; /* don't map to user space */
+ u32 cache:1; /* map to data cache */
+ u32 btlb:1; /* map to block tlb */
+ u32 last:1; /* last region in list */
+ u32 length:14; /* length in 4kbyte page */
+ } region_desc;
+
+ u32 region; /* complete region value */
+} region_t;
+
+struct sti_glob_cfg_ext {
+ u8 curr_mon; /* current monitor configured */
+ u8 friendly_boot; /* in friendly boot mode */
+ s16 power; /* power calculation (in Watts) */
+ s32 freq_ref; /* frequency reference */
+ u32 sti_mem_addr; /* pointer to global sti memory (size=sti_mem_request) */
+ u32 future_ptr; /* pointer to future data */
+};
+
+struct sti_glob_cfg {
+ s32 text_planes; /* number of planes used for text */
+ s16 onscreen_x; /* screen width in pixels */
+ s16 onscreen_y; /* screen height in pixels */
+ s16 offscreen_x; /* offset width in pixels */
+ s16 offscreen_y; /* offset height in pixels */
+ s16 total_x; /* frame buffer width in pixels */
+ s16 total_y; /* frame buffer height in pixels */
+ u32 region_ptrs[STI_REGION_MAX]; /* region pointers */
+ s32 reent_lvl; /* storage for reentry level value */
+ u32 save_addr; /* where to save or restore reentrant state */
+ u32 ext_ptr; /* pointer to extended glob_cfg data structure */
+};
+
+
+/* STI init function structs */
+
+struct sti_init_flags {
+ u32 wait:1; /* should routine idle wait or not */
+ u32 reset:1; /* hard reset the device? */
+ u32 text:1; /* turn on text display planes? */
+ u32 nontext:1; /* turn on non-text display planes? */
+ u32 clear:1; /* clear text display planes? */
+ u32 cmap_blk:1; /* non-text planes cmap black? */
+ u32 enable_be_timer:1; /* enable bus error timer */
+ u32 enable_be_int:1; /* enable bus error timer interrupt */
+ u32 no_chg_tx:1; /* don't change text settings */
+ u32 no_chg_ntx:1; /* don't change non-text settings */
+ u32 no_chg_bet:1; /* don't change berr timer settings */
+ u32 no_chg_bei:1; /* don't change berr int settings */
+ u32 init_cmap_tx:1; /* initialize cmap for text planes */
+ u32 cmt_chg:1; /* change current monitor type */
+ u32 retain_ie:1; /* don't allow reset to clear int enables */
+ u32 caller_bootrom:1; /* set only by bootrom for each call */
+ u32 caller_kernel:1; /* set only by kernel for each call */
+ u32 caller_other:1; /* set only by non-[BR/K] caller */
+ u32 pad:14; /* pad to word boundary */
+ u32 future_ptr; /* pointer to future data */
+};
+
+struct sti_init_inptr_ext {
+ u8 config_mon_type; /* configure to monitor type */
+ u8 pad[1]; /* pad to word boundary */
+ u16 inflight_data; /* inflight data possible on PCI */
+ u32 future_ptr; /* pointer to future data */
+};
+
+struct sti_init_inptr {
+ s32 text_planes; /* number of planes to use for text */
+ u32 ext_ptr; /* pointer to extended init_graph inptr data structure*/
+};
+
+
+struct sti_init_outptr {
+ s32 errno; /* error number on failure */
+ s32 text_planes; /* number of planes used for text */
+ u32 future_ptr; /* pointer to future data */
+};
+
+/* STI configuration function structs */
+
+struct sti_conf_flags {
+ u32 wait:1; /* should routine idle wait or not */
+ u32 pad:31; /* pad to word boundary */
+ u32 future_ptr; /* pointer to future data */
+};
+
+struct sti_conf_inptr {
+ u32 future_ptr; /* pointer to future data */
+};
+
+struct sti_conf_outptr_ext {
+ u32 crt_config[3]; /* hardware specific X11/OGL information */
+ u32 crt_hdw[3];
+ u32 future_ptr;
+};
+
+struct sti_conf_outptr {
+ s32 errno; /* error number on failure */
+ s16 onscreen_x; /* screen width in pixels */
+ s16 onscreen_y; /* screen height in pixels */
+ s16 offscreen_x; /* offscreen width in pixels */
+ s16 offscreen_y; /* offscreen height in pixels */
+ s16 total_x; /* frame buffer width in pixels */
+ s16 total_y; /* frame buffer height in pixels */
+ s32 bits_per_pixel; /* bits/pixel device has configured */
+ s32 bits_used; /* bits which can be accessed */
+ s32 planes; /* number of fb planes in system */
+ u8 dev_name[STI_DEV_NAME_LENGTH]; /* null terminated product name */
+ u32 attributes; /* flags denoting attributes */
+ u32 ext_ptr; /* pointer to future data */
+};
+
+typedef struct {
+ u32 x:12;
+ u32 y:12;
+ u32 hz:7;
+ u32 class_flat:1;
+ u32 class_vesa:1;
+ u32 class_grey:1;
+ u32 class_dbl:1;
+ u32 class_user:1;
+ u32 class_stereo:1;
+ u32 class_sam:1;
+ u32 pad:15;
+ u32 hz_upper:3;
+ u32 index:8;
+} mon_tbl_desc;
+
+struct sti_rom {
+ u8 type[4];
+ u8 res004;
+ u8 num_mons;
+ u8 revno[2];
+ u32 graphics_id[2];
+
+ u32 font_start;
+ u32 statesize;
+ u32 last_addr;
+ u32 region_list;
+
+ u16 reentsize;
+ u16 maxtime;
+ u32 mon_tbl_addr;
+ u32 user_data_addr;
+ u32 sti_mem_req;
+
+ u32 user_data_size;
+ u16 power;
+ u8 bus_support;
+ u8 ext_bus_support;
+ u8 alt_code_type;
+ u8 ext_dd_struct[3];
+ u32 cfb_addr;
+
+ u32 init_graph;
+ u32 state_mgmt;
+ u32 font_unpmv;
+ u32 block_move;
+ u32 self_test;
+ u32 excep_hdlr;
+ u32 inq_conf;
+ u32 set_cm_entry;
+ u32 dma_ctrl;
+ u32 flow_ctrl;
+ u32 user_timing;
+ u32 process_mgr;
+ u32 sti_util;
+ u32 end;
+
+ u32 res040[2];
+
+ u32 init_graph_addr;
+ u32 state_mgmt_addr;
+ u32 font_unp_addr;
+ u32 block_move_addr;
+ u32 self_test_addr;
+ u32 excep_hdlr_addr;
+ u32 inq_conf_addr;
+ u32 set_cm_entry_addr;
+ u32 image_unpack_addr;
+ u32 pa_risx_addrs[7];
+};
+
+
+struct sti_rom_font {
+ u16 first_char;
+ u16 last_char;
+ u8 width;
+ u8 height;
+ u8 font_type; /* language type */
+ u8 bytes_per_char;
+ u32 next_font;
+ u8 underline_height;
+ u8 underline_pos;
+ u8 res008[2];
+};
+
+struct font {
+ struct sti_rom_font hdr;
+ unsigned char font[16*256];
+};
+
+/* STI font printing function structs */
+
+struct sti_font_inptr {
+ u32 font_start_addr; /* address of font start */
+ s16 index; /* index into font table of character */
+ u8 fg_color; /* foreground color of character */
+ u8 bg_color; /* background color of character */
+ s16 dest_x; /* X location of character upper left */
+ s16 dest_y; /* Y location of character upper left */
+ u32 future_ptr; /* pointer to future data */
+};
+
+struct sti_font_flags {
+ u32 wait:1; /* should routine idle wait or not */
+ u32 non_text:1; /* font unpack/move in non_text planes =1, text =0 */
+ u32 pad:30; /* pad to word boundary */
+ u32 future_ptr; /* pointer to future data */
+};
+
+struct sti_font_outptr {
+ s32 errno; /* error number on failure */
+ u32 future_ptr; /* pointer to future data */
+};
+
+/* STI blockmove structs */
+
+struct sti_blkmv_flags {
+ u32 wait:1; /* should routine idle wait or not */
+ u32 color:1; /* change color during move? */
+ u32 clear:1; /* clear during move? */
+ u32 non_text:1; /* block move in non_text planes =1, text =0 */
+ u32 pad:28; /* pad to word boundary */
+ u32 future_ptr; /* pointer to future data */
+};
+
+struct sti_blkmv_inptr {
+ u8 fg_color; /* foreground color after move */
+ u8 bg_color; /* background color after move */
+ s16 src_x; /* source upper left pixel x location */
+ s16 src_y; /* source upper left pixel y location */
+ s16 dest_x; /* dest upper left pixel x location */
+ s16 dest_y; /* dest upper left pixel y location */
+ s16 width; /* block width in pixels */
+ s16 height; /* block height in pixels */
+ u32 future_ptr; /* pointer to future data */
+};
+
+struct sti_blkmv_outptr {
+ s32 errno; /* error number on failure */
+ u32 future_ptr; /* pointer to future data */
+};
+
+struct sti_state_flags {
+ u32 wait:1; /* should routing idle wait or not */
+ u32 save:1; /* save (1) or restore (0) state */
+ u32 res_disp:1; /* restore all display planes */
+ u32 pad:29; /* pad to word boundary */
+ s32 *future_ptr; /* pointer to future data */
+};
+
+struct sti_state_inptr {
+ s32 *save_addr; /* where to save or restore state */
+ s32 *future_ptr; /* pointer to future data */
+};
+
+struct sti_state_outptr {
+ s32 errno; /* error number on failure */
+ s32 *future_ptr; /* pointer to future data */
+};
+
+struct setcm_flags {
+ u32 wait:1; /* should routine idle wait or not */
+ u32 pad:31; /* pad to word boundary */
+ s32 *future_ptr; /* pointer to future data */
+};
+
+struct setcm_inptr {
+ s32 entry; /* entry number */
+ u32 value; /* entry value */
+ s32 *future_ptr; /* pointer to future data */
+};
+
+struct setcm_outptr {
+ s32 errno; /* error number on failure */
+ s32 *future_ptr; /* pointer to future data */
+};
+
+void sti_rom_init(void);
+void sti_console_init(struct sti_rom *rom);
+void sti_putc(const char c);
+
+extern struct sti_rom sti_proc_rom;
+extern char _sti_rom_end[];
+extern char _sti_rom_start[];
+extern void parisc_screenc(char c);
+
+#endif /* STICORE_H */
diff --git a/src/parisc/stirom.c b/src/parisc/stirom.c
new file mode 100644
index 0000000..07e89c3
--- /dev/null
+++ b/src/parisc/stirom.c
@@ -0,0 +1,652 @@
+#include "sticore.h"
+#include "hppa.h"
+
+#define ARTIST_VRAM_IDX 0x4a0
+#define ARTIST_VRAM_BITMASK 0x5a0
+#define ARTIST_VRAM_WRITE_INCR_X 0x600
+#define ARTIST_VRAM_BYTE_WRITE 0x620
+#define ARTIST_CMAP_ACCESS 0x18000
+#define ARTIST_DST_BM_ACCESS 0x18004
+#define ARTIST_SRC_BM_ACCESS 0x18008
+#define ARTIST_BGCOLOR 0x18014
+#define ARTIST_FGCOLOR 0x18010
+#define ARTIST_BITMAP_OP 0x1801c
+#define ARTIST_PLANE_BITMASK 0x18018
+#define ARTIST_VRAM_DEST 0x800
+#define ARTIST_VRAM_SIZE 0x804
+#define ARTIST_VRAM_SRC 0x808
+
+#define ARTIST_VRAM_SIZE_TRIGGER_WINFILL 0xa04
+#define ARTIST_VRAM_DEST_TRIGGER_BLOCKMOVE 0xb00
+
+#define __stiheader __attribute__((section(".sti.hdr")))
+#define __stidata __attribute__((section(".sti.data")))
+#define __stitext __attribute__((section(".sti.text")))
+
+/* Don't ask - HP-UX assumes a certain order of functions
+ * when it copies them to RAM. So we put the functions into
+ * different sections and order them in the linker script.
+ */
+
+#define __stifunc(_name) __attribute__((section(".sti.text." _name)))
+
+static const __stidata char user_data[256] __aligned(32);
+
+static const region_t sti_region_list[STI_REGION_MAX] __stidata __aligned(32) = {
+ { .region_desc = { .offset = 0, .btlb = 1, .length = 2 }, },
+ { .region_desc = { .offset = (ARTIST_FB_ADDR - LASI_GFX_HPA) / 4096, .btlb = 1, .length = (ARTIST_FB_ADDR - LASI_GFX_HPA) / 4096} },
+ { .region_desc = { .offset = (0xf8100000 - LASI_GFX_HPA)/ 4096, .btlb = 1, .length = ((0xf8380000-0xf8100000) / 4096), } },
+ { .region_desc = { .offset = (0xf8380000 - LASI_GFX_HPA)/ 4096, .sys_only = 1, .length = 1, .last = 1, } }
+};
+
+static const struct font __stidata __aligned(32) sti_rom_font = {
+ .hdr = {
+ .first_char = 0,
+ .last_char = 255,
+ .width = 8,
+ .height = 16,
+ .font_type = STI_FONT_HPROMAN8,
+ .bytes_per_char = 16,
+ .underline_height = 1,
+ .underline_pos = 15,
+ },
+ .font = {
+ 0x00, 0x48, 0x68, 0x58, 0x48, 0x48, 0x00, 0x12, 0x12, 0x12, 0x12, 0x0c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x38, 0x40, 0x30, 0x08, 0x70, 0x00, 0x12, 0x12, 0x1e, 0x12, 0x12, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x38, 0x40, 0x30, 0x08, 0x70, 0x00, 0x22, 0x14, 0x08, 0x14, 0x22, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x78, 0x40, 0x70, 0x40, 0x78, 0x00, 0x22, 0x14, 0x08, 0x14, 0x22, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x78, 0x40, 0x70, 0x40, 0x78, 0x00, 0x3e, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x78, 0x40, 0x70, 0x40, 0x78, 0x00, 0x1c, 0x22, 0x22, 0x2a, 0x1c, 0x04, 0x00, 0x00, 0x00,
+ 0x00, 0x30, 0x48, 0x78, 0x48, 0x48, 0x00, 0x12, 0x14, 0x18, 0x14, 0x12, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0xfe, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x70, 0x48, 0x70, 0x48, 0x70, 0x00, 0x0e, 0x10, 0x0c, 0x02, 0x1c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x48, 0x48, 0x78, 0x48, 0x48, 0x00, 0x3e, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x40, 0x40, 0x40, 0x40, 0x78, 0x00, 0x1e, 0x10, 0x1c, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x44, 0x44, 0x28, 0x28, 0x10, 0x00, 0x3e, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x78, 0x40, 0x70, 0x40, 0x40, 0x00, 0x1e, 0x10, 0x1c, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x38, 0x40, 0x40, 0x40, 0x38, 0x00, 0x1c, 0x12, 0x1c, 0x14, 0x12, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x38, 0x40, 0x30, 0x08, 0x70, 0x00, 0x0c, 0x12, 0x12, 0x12, 0x0c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x38, 0x40, 0x30, 0x08, 0x70, 0x00, 0x0e, 0x04, 0x04, 0x04, 0x0e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x70, 0x48, 0x48, 0x48, 0x70, 0x00, 0x10, 0x10, 0x10, 0x10, 0x1e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x70, 0x48, 0x48, 0x48, 0x70, 0x00, 0x04, 0x0c, 0x04, 0x04, 0x0e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x70, 0x48, 0x48, 0x48, 0x70, 0x0c, 0x12, 0x02, 0x0c, 0x10, 0x1e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x70, 0x48, 0x48, 0x48, 0x70, 0x00, 0x1c, 0x02, 0x0c, 0x02, 0x1c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x70, 0x48, 0x48, 0x48, 0x70, 0x00, 0x14, 0x14, 0x1e, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x48, 0x68, 0x58, 0x48, 0x48, 0x00, 0x12, 0x14, 0x18, 0x14, 0x12, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x38, 0x40, 0x30, 0x08, 0x70, 0x00, 0x22, 0x14, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x78, 0x40, 0x70, 0x40, 0x78, 0x00, 0x1c, 0x12, 0x1c, 0x12, 0x1c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x38, 0x40, 0x40, 0x40, 0x38, 0x00, 0x12, 0x1a, 0x16, 0x12, 0x12, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x78, 0x40, 0x70, 0x40, 0x78, 0x00, 0x22, 0x36, 0x2a, 0x22, 0x22, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x38, 0x40, 0x30, 0x08, 0x70, 0x00, 0x1c, 0x12, 0x1c, 0x12, 0x1c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x78, 0x40, 0x70, 0x40, 0x78, 0x00, 0x0e, 0x10, 0x10, 0x10, 0x0e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x78, 0x40, 0x70, 0x40, 0x40, 0x00, 0x0e, 0x10, 0x0c, 0x02, 0x1c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x38, 0x40, 0x58, 0x48, 0x38, 0x00, 0x0e, 0x10, 0x0c, 0x02, 0x1c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x70, 0x48, 0x70, 0x50, 0x48, 0x00, 0x0e, 0x10, 0x0c, 0x02, 0x1c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x48, 0x48, 0x48, 0x48, 0x30, 0x00, 0x0e, 0x10, 0x0c, 0x02, 0x1c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x28, 0x28, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x24, 0x24, 0x7e, 0x24, 0x24, 0x24, 0x24, 0x7e, 0x24, 0x24, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x10, 0x38, 0x54, 0x50, 0x30, 0x18, 0x14, 0x54, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x24, 0x54, 0x28, 0x08, 0x10, 0x10, 0x20, 0x24, 0x4a, 0x44, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x30, 0x48, 0x48, 0x50, 0x20, 0x50, 0x8a, 0x84, 0x8c, 0x72, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x08, 0x10, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x08, 0x10, 0x10, 0x20, 0x20, 0x20, 0x20, 0x10, 0x10, 0x08, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x20, 0x10, 0x10, 0x08, 0x08, 0x08, 0x08, 0x10, 0x10, 0x20, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x10, 0x54, 0x38, 0x7c, 0x38, 0x54, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0xfe, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x10, 0x20, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x04, 0x04, 0x08, 0x08, 0x10, 0x10, 0x20, 0x20, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x24, 0x42, 0x42, 0x5a, 0x5a, 0x42, 0x42, 0x24, 0x18, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x08, 0x18, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x1c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x42, 0x02, 0x02, 0x0c, 0x10, 0x20, 0x40, 0x40, 0x7e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x42, 0x02, 0x02, 0x1c, 0x02, 0x02, 0x02, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x04, 0x0c, 0x14, 0x24, 0x44, 0x7e, 0x04, 0x04, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7e, 0x40, 0x40, 0x40, 0x7c, 0x02, 0x02, 0x02, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x42, 0x40, 0x40, 0x7c, 0x42, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7e, 0x02, 0x02, 0x04, 0x08, 0x08, 0x10, 0x10, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x42, 0x42, 0x42, 0x3c, 0x42, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x42, 0x42, 0x42, 0x3e, 0x02, 0x02, 0x02, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00, 0x30, 0x30, 0x10, 0x20, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x08, 0x10, 0x20, 0x40, 0x20, 0x10, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x20, 0x10, 0x08, 0x04, 0x08, 0x10, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x42, 0x02, 0x02, 0x04, 0x08, 0x10, 0x10, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x42, 0x4e, 0x52, 0x52, 0x52, 0x4c, 0x40, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x42, 0x42, 0x42, 0x7e, 0x42, 0x42, 0x42, 0x42, 0x42, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0x42, 0x42, 0x42, 0x7c, 0x42, 0x42, 0x42, 0x42, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x42, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7e, 0x40, 0x40, 0x40, 0x7c, 0x40, 0x40, 0x40, 0x40, 0x7e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7e, 0x40, 0x40, 0x40, 0x78, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x42, 0x40, 0x40, 0x40, 0x4e, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x42, 0x42, 0x42, 0x42, 0x7e, 0x42, 0x42, 0x42, 0x42, 0x42, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x38, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x0e, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x44, 0x38, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x42, 0x42, 0x44, 0x48, 0x50, 0x70, 0x48, 0x44, 0x42, 0x42, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x7e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x42, 0x42, 0x66, 0x5a, 0x5a, 0x42, 0x42, 0x42, 0x42, 0x42, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x42, 0x62, 0x62, 0x52, 0x52, 0x4a, 0x4a, 0x46, 0x46, 0x42, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0x42, 0x42, 0x42, 0x7c, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x4a, 0x3c, 0x04, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0x42, 0x42, 0x42, 0x7c, 0x50, 0x48, 0x44, 0x42, 0x42, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x42, 0x40, 0x40, 0x3c, 0x02, 0x02, 0x02, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xfe, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x82, 0x82, 0x44, 0x44, 0x44, 0x28, 0x28, 0x28, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x42, 0x42, 0x42, 0x42, 0x42, 0x5a, 0x5a, 0x66, 0x42, 0x42, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x42, 0x42, 0x42, 0x24, 0x18, 0x18, 0x24, 0x42, 0x42, 0x42, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x82, 0x82, 0x44, 0x44, 0x28, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7e, 0x02, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x40, 0x7e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x40, 0x40, 0x20, 0x20, 0x10, 0x10, 0x08, 0x08, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x10, 0x28, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0x00, 0x20, 0x10, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x02, 0x3e, 0x42, 0x42, 0x3e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x40, 0x40, 0x40, 0x40, 0x7c, 0x42, 0x42, 0x42, 0x42, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x42, 0x40, 0x40, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x3e, 0x42, 0x42, 0x42, 0x42, 0x3e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x42, 0x7e, 0x40, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x1c, 0x22, 0x20, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x42, 0x42, 0x42, 0x42, 0x3e, 0x02, 0x02, 0x3c, 0x00,
+ 0x00, 0x00, 0x40, 0x40, 0x40, 0x40, 0x7c, 0x42, 0x42, 0x42, 0x42, 0x42, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x30, 0x10, 0x10, 0x10, 0x10, 0x38, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x0c, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x18, 0x00,
+ 0x00, 0x00, 0x40, 0x40, 0x40, 0x40, 0x44, 0x48, 0x50, 0x68, 0x44, 0x42, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x1c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xec, 0x92, 0x92, 0x92, 0x92, 0x92, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5c, 0x62, 0x42, 0x42, 0x42, 0x42, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x42, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5c, 0x62, 0x42, 0x42, 0x42, 0x7c, 0x40, 0x40, 0x40, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3a, 0x46, 0x42, 0x42, 0x42, 0x3e, 0x02, 0x02, 0x02, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6c, 0x32, 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x40, 0x3c, 0x02, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x7c, 0x10, 0x10, 0x10, 0x10, 0x0c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x82, 0x44, 0x44, 0x28, 0x28, 0x10, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x92, 0x92, 0x92, 0x92, 0x92, 0x6c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x24, 0x18, 0x18, 0x24, 0x42, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3e, 0x02, 0x02, 0x3c, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x04, 0x08, 0x10, 0x20, 0x7e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x0c, 0x10, 0x10, 0x10, 0x10, 0x20, 0x10, 0x10, 0x10, 0x0c, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
+ 0x00, 0x00, 0x30, 0x08, 0x08, 0x08, 0x08, 0x04, 0x08, 0x08, 0x08, 0x30, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x32, 0x4c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x2a, 0x54, 0x2a, 0x54, 0x2a, 0x54, 0x2a, 0x54, 0x2a, 0x54, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x38, 0x40, 0x40, 0x40, 0x38, 0x00, 0x10, 0x10, 0x10, 0x10, 0x1e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x70, 0x20, 0x20, 0x20, 0x70, 0x00, 0x22, 0x22, 0x14, 0x14, 0x08, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x70, 0x48, 0x70, 0x48, 0x70, 0x00, 0x0c, 0x10, 0x16, 0x12, 0x0c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x70, 0x20, 0x20, 0x20, 0x70, 0x00, 0x1c, 0x12, 0x1c, 0x12, 0x1c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x48, 0x48, 0x48, 0x48, 0x30, 0x00, 0x10, 0x10, 0x10, 0x10, 0x1e, 0x00, 0xff, 0x00, 0x00,
+ 0x00, 0x70, 0x20, 0x20, 0x20, 0x70, 0x00, 0x22, 0x22, 0x14, 0x14, 0x08, 0x00, 0xff, 0x00, 0x00,
+ 0x00, 0x70, 0x48, 0x70, 0x48, 0x70, 0x00, 0x0c, 0x10, 0x16, 0x12, 0x0c, 0x00, 0xff, 0x00, 0x00,
+ 0x00, 0x70, 0x20, 0x20, 0x20, 0x70, 0x00, 0x1c, 0x12, 0x1c, 0x12, 0x1c, 0x00, 0xff, 0x00, 0x00,
+ 0x00, 0xa8, 0xa8, 0xa8, 0xa8, 0x50, 0x00, 0x12, 0x12, 0x1e, 0x12, 0x12, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x70, 0x48, 0x70, 0x50, 0x48, 0x00, 0x1c, 0x12, 0x12, 0x12, 0x1c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x48, 0x48, 0x30, 0x10, 0x10, 0x00, 0x1e, 0x10, 0x1c, 0x10, 0x1e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x30, 0x40, 0x58, 0x48, 0x30, 0x00, 0x1c, 0x12, 0x1c, 0x14, 0x12, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x38, 0x40, 0x40, 0x40, 0x38, 0x00, 0x12, 0x12, 0x0c, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x70, 0x48, 0x70, 0x48, 0x70, 0x00, 0x12, 0x12, 0x12, 0x12, 0x0c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x88, 0xd8, 0xa8, 0x88, 0x88, 0x00, 0x0c, 0x10, 0x16, 0x12, 0x0c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x70, 0x48, 0x70, 0x48, 0x70, 0x00, 0x12, 0x14, 0x18, 0x14, 0x12, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x30, 0x48, 0x38, 0x08, 0x30, 0x00, 0x0c, 0x12, 0x12, 0x12, 0x0c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x30, 0x48, 0x38, 0x08, 0x30, 0x00, 0x04, 0x0c, 0x04, 0x04, 0x0e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x30, 0x48, 0x38, 0x08, 0x30, 0x00, 0x0c, 0x12, 0x04, 0x08, 0x1e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x30, 0x48, 0x38, 0x08, 0x30, 0x00, 0x1c, 0x02, 0x1c, 0x02, 0x1c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x30, 0x48, 0x38, 0x08, 0x30, 0x00, 0x14, 0x14, 0x1e, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x30, 0x48, 0x38, 0x08, 0x30, 0x00, 0x1e, 0x10, 0x1c, 0x02, 0x1c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x30, 0x48, 0x38, 0x08, 0x30, 0x00, 0x0c, 0x10, 0x1c, 0x12, 0x0c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x30, 0x48, 0x38, 0x08, 0x30, 0x00, 0x1e, 0x02, 0x04, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x30, 0x48, 0x38, 0x08, 0x30, 0x00, 0x0c, 0x12, 0x0c, 0x12, 0x0c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x30, 0x48, 0x38, 0x08, 0x30, 0x00, 0x0c, 0x12, 0x0e, 0x02, 0x0c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x30, 0x48, 0x78, 0x08, 0x30, 0x00, 0x0c, 0x12, 0x1e, 0x12, 0x12, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x30, 0x48, 0x38, 0x08, 0x30, 0x00, 0x1c, 0x12, 0x1c, 0x12, 0x1c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x30, 0x48, 0x38, 0x08, 0x30, 0x00, 0x0e, 0x10, 0x10, 0x10, 0x0e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x30, 0x48, 0x38, 0x08, 0x30, 0x00, 0x1c, 0x12, 0x12, 0x12, 0x1c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x30, 0x48, 0x38, 0x08, 0x30, 0x00, 0x1e, 0x10, 0x1c, 0x10, 0x1e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x30, 0x48, 0x38, 0x08, 0x30, 0x00, 0x1e, 0x10, 0x1c, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x08, 0x00, 0x3c, 0x42, 0x42, 0x42, 0x7e, 0x42, 0x42, 0x42, 0x42, 0x00, 0x00, 0x00, 0x00,
+ 0x08, 0x14, 0x00, 0x3c, 0x42, 0x42, 0x42, 0x7e, 0x42, 0x42, 0x42, 0x42, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x08, 0x00, 0x7e, 0x40, 0x40, 0x40, 0x78, 0x40, 0x40, 0x40, 0x7e, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x28, 0x00, 0x7e, 0x40, 0x40, 0x40, 0x78, 0x40, 0x40, 0x40, 0x7e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x24, 0x00, 0x7e, 0x40, 0x40, 0x40, 0x78, 0x40, 0x40, 0x40, 0x7e, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x28, 0x00, 0x38, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x38, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x28, 0x00, 0x38, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x38, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x20, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x32, 0x4c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x10, 0x08, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x28, 0x00, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x0c, 0x12, 0x10, 0x3c, 0x10, 0x3c, 0x10, 0x70, 0x91, 0x6e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x70, 0x48, 0x70, 0x48, 0x70, 0x00, 0x04, 0x0c, 0x04, 0x04, 0x0e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x02, 0x06, 0x0e, 0x1e, 0x3e, 0x1e, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x24, 0x24, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x42, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x42, 0x3c, 0x10, 0x08, 0x10, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x42, 0x40, 0x40, 0x42, 0x3c, 0x10, 0x08, 0x10, 0x00,
+ 0x32, 0x4c, 0x00, 0x42, 0x62, 0x52, 0x52, 0x4a, 0x4a, 0x46, 0x42, 0x42, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x32, 0x4c, 0x00, 0x5c, 0x62, 0x42, 0x42, 0x42, 0x42, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x10, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x10, 0x00, 0x10, 0x10, 0x10, 0x20, 0x40, 0x40, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x41, 0x22, 0x1c, 0x22, 0x22, 0x22, 0x22, 0x1c, 0x22, 0x41, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x0c, 0x12, 0x10, 0x10, 0x3c, 0x10, 0x10, 0x70, 0x91, 0x6e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x82, 0x44, 0x28, 0x10, 0x7c, 0x10, 0x7c, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x1c, 0x20, 0x20, 0x10, 0x18, 0x24, 0x24, 0x18, 0x08, 0x04, 0x38, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x07, 0x08, 0x10, 0x10, 0x7c, 0x10, 0x10, 0x10, 0x20, 0xc0, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x08, 0x3e, 0x49, 0x48, 0x48, 0x49, 0x3e, 0x08, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x08, 0x14, 0x00, 0x3c, 0x02, 0x3e, 0x42, 0x42, 0x3e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x08, 0x14, 0x00, 0x3c, 0x42, 0x7e, 0x40, 0x40, 0x3e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x10, 0x28, 0x00, 0x3c, 0x42, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x10, 0x28, 0x00, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x08, 0x10, 0x00, 0x3c, 0x02, 0x3e, 0x42, 0x42, 0x3e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x08, 0x10, 0x00, 0x3c, 0x42, 0x7e, 0x40, 0x40, 0x3e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x08, 0x10, 0x00, 0x3c, 0x42, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x08, 0x10, 0x00, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x10, 0x08, 0x00, 0x3c, 0x02, 0x3e, 0x42, 0x42, 0x3e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x10, 0x08, 0x00, 0x3c, 0x42, 0x7e, 0x40, 0x40, 0x3e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x10, 0x08, 0x00, 0x3c, 0x42, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x10, 0x08, 0x00, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x24, 0x00, 0x3c, 0x02, 0x3e, 0x42, 0x42, 0x3e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x24, 0x00, 0x3c, 0x42, 0x7e, 0x40, 0x40, 0x3e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x24, 0x00, 0x3c, 0x42, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x24, 0x00, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3e, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x24, 0x18, 0x3c, 0x42, 0x42, 0x42, 0x7e, 0x42, 0x42, 0x42, 0x42, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x10, 0x28, 0x00, 0x30, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3d, 0x42, 0x46, 0x4a, 0x4a, 0x52, 0x52, 0x62, 0x42, 0xbc, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3f, 0x48, 0x48, 0x48, 0x7e, 0x48, 0x48, 0x48, 0x48, 0x4f, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x08, 0x14, 0x08, 0x00, 0x3c, 0x02, 0x3e, 0x42, 0x42, 0x3e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x08, 0x10, 0x00, 0x30, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3d, 0x42, 0x4e, 0x72, 0x42, 0xbc, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x09, 0x3f, 0x48, 0x49, 0x3e, 0x00, 0x00, 0x00, 0x00,
+ 0x24, 0x00, 0x3c, 0x42, 0x42, 0x42, 0x7e, 0x42, 0x42, 0x42, 0x42, 0x42, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x20, 0x10, 0x00, 0x30, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00,
+ 0x24, 0x00, 0x3c, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x24, 0x00, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x08, 0x10, 0x00, 0x7e, 0x40, 0x40, 0x40, 0x78, 0x40, 0x40, 0x40, 0x7e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x30, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x24, 0x44, 0x48, 0x70, 0x48, 0x44, 0x44, 0x64, 0x58, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x28, 0x00, 0x3c, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x08, 0x10, 0x00, 0x3c, 0x42, 0x42, 0x42, 0x7e, 0x42, 0x42, 0x42, 0x42, 0x00, 0x00, 0x00, 0x00,
+ 0x32, 0x4c, 0x00, 0x3c, 0x42, 0x42, 0x42, 0x7e, 0x42, 0x42, 0x42, 0x42, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x32, 0x4c, 0x00, 0x3c, 0x02, 0x3e, 0x42, 0x42, 0x3e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7c, 0x42, 0x42, 0x42, 0xe2, 0x42, 0x42, 0x42, 0x42, 0x7c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x02, 0x07, 0x02, 0x3e, 0x42, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x08, 0x10, 0x00, 0x38, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x38, 0x00, 0x00, 0x00, 0x00,
+ 0x20, 0x10, 0x00, 0x38, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x38, 0x00, 0x00, 0x00, 0x00,
+ 0x08, 0x10, 0x00, 0x3c, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x10, 0x08, 0x00, 0x3c, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x32, 0x4c, 0x00, 0x3c, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x32, 0x4c, 0x00, 0x3c, 0x42, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x28, 0x10, 0x00, 0x3c, 0x42, 0x40, 0x40, 0x3c, 0x02, 0x02, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x28, 0x10, 0x00, 0x3c, 0x40, 0x3c, 0x02, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x08, 0x10, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00,
+ 0x24, 0x00, 0x41, 0x41, 0x22, 0x14, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x24, 0x00, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3e, 0x02, 0x02, 0x3c, 0x00,
+ 0x00, 0x00, 0x38, 0x10, 0x10, 0x1c, 0x12, 0x12, 0x1c, 0x10, 0x10, 0x38, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x1c, 0x12, 0x12, 0x1c, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x78, 0x40, 0x70, 0x40, 0x40, 0x00, 0x0c, 0x12, 0x04, 0x08, 0x1e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x78, 0x40, 0x70, 0x40, 0x40, 0x00, 0x1c, 0x02, 0x0c, 0x02, 0x1c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x78, 0x40, 0x70, 0x40, 0x40, 0x00, 0x14, 0x14, 0x1e, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x70, 0x20, 0x20, 0x20, 0x70, 0x00, 0x0c, 0x12, 0x12, 0x12, 0x0c, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x20, 0x60, 0x22, 0x24, 0x28, 0x14, 0x2c, 0x54, 0x1e, 0x04, 0x0e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x20, 0x60, 0x22, 0x24, 0x28, 0x10, 0x2c, 0x52, 0x04, 0x08, 0x1e, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x02, 0x3e, 0x42, 0x3e, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3c, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x09, 0x12, 0x24, 0x48, 0x24, 0x12, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x48, 0x24, 0x12, 0x09, 0x12, 0x24, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x7c, 0x10, 0x10, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x7e, 0x5a, 0x5a, 0x56, 0x4e, 0x56, 0x5a, 0x5a, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00,
+ }
+};
+
+static const mon_tbl_desc __stidata sti_mon_table[] = {
+ { .x = 1280, .y = 1024, .hz = 72, .class_vesa = 1, .index = 0 },
+ { .x = 1024, .y = 768, .hz = 72, .class_vesa = 1, .index = 0 },
+ { .x = 768, .y = 600, .hz = 72, .class_vesa = 1, .index = 0 },
+ { .x = 640, .y = 480, .hz = 72, .class_vesa = 1, .index = 0 },
+};
+
+struct sti_rom __stiheader sti_proc_rom = {
+ .type = { 0x03, 0x03, 0x03, 0x03 },
+ .num_mons = ARRAY_SIZE(sti_mon_table),
+ .revno = { 0x84, 0x07 },
+ .graphics_id = { 0x2b4ded6d, 0x40a00499 },
+};
+
+static void __stitext write_artist(struct sti_glob_cfg *cfg,
+ int reg, u32 val)
+{
+ writel((void *)cfg->region_ptrs[2] + reg, val);
+}
+
+static int __stifunc("state_mgmt") sti_state_mgmt(struct sti_state_flags *flags,
+ struct sti_state_inptr *in,
+ struct sti_state_outptr *out,
+ struct sti_glob_cfg *cfg)
+{
+ (void)flags;
+ (void)in;
+ (void)cfg;
+ out->errno = 0;
+ return 0;
+}
+
+static u32 __stifunc("block_move") sti_bmove(struct sti_blkmv_flags *flags,
+ struct sti_blkmv_inptr *in,
+ struct sti_blkmv_outptr *out,
+ struct sti_glob_cfg *cfg)
+{
+ write_artist(cfg, ARTIST_PLANE_BITMASK, 0xffffffff);
+ write_artist(cfg, ARTIST_BITMAP_OP, 0x03000300);
+ write_artist(cfg, ARTIST_SRC_BM_ACCESS, 0x2ea01000);
+ write_artist(cfg, ARTIST_DST_BM_ACCESS, 0x2ea01000);
+ write_artist(cfg, ARTIST_FGCOLOR, in->fg_color);
+ write_artist(cfg, ARTIST_BGCOLOR, in->bg_color);
+
+ if (flags->clear) {
+ write_artist(cfg, ARTIST_VRAM_DEST, (in->dest_x << 16) | (in->dest_y));
+ barrier();
+ write_artist(cfg, ARTIST_VRAM_SIZE_TRIGGER_WINFILL,
+ (in->width << 16) | (in->height));
+ } else {
+ write_artist(cfg, ARTIST_VRAM_SIZE, (in->width << 16) | (in->height));
+ write_artist(cfg, ARTIST_VRAM_SRC, (in->src_x << 16) | (in->src_y));
+ barrier();
+ write_artist(cfg, ARTIST_VRAM_DEST_TRIGGER_BLOCKMOVE,
+ (in->dest_x << 16) | (in->dest_y));
+ }
+ out->errno = 0;
+ return 0;
+}
+
+/* can not call millicode routines in STI ROM code */
+static inline int inline_mul(int val, int mul)
+{
+ switch (mul) {
+ case 7: return (val << 3) - val;
+ case 6: return (val << 2) + (val << 1);
+ case 5: return (val << 2) + val;
+ case 4: return (val << 2);
+ case 3: return (val << 1) + val;
+ case 2: return (val << 1);
+ case 1: return val;
+ case 0: return 0;
+ default: return 0;
+ }
+}
+
+static int __stifunc("font_unpmv") sti_font_unpmv(struct sti_font_flags *flags,
+ struct sti_font_inptr *in,
+ struct sti_font_outptr *out,
+ struct sti_glob_cfg *cfg)
+{
+ struct font *font = (struct font *) in->font_start_addr;
+ int bpc = font->hdr.bytes_per_char;
+ int width = font->hdr.width;
+ unsigned char *src;
+ int c, y, pitch;
+ (void)flags;
+
+ /* same as: src = &font->font[in->index * bpc]; */
+ c = in->index;
+ y = inline_mul(c, bpc & 7);
+ if (bpc & 8) y += c << 3;
+ if (bpc & 16) y += c << 4;
+ if (bpc & 32) y += c << 5;
+ if (bpc & 64) y += c << 6;
+ if (bpc & 128) y += c << 7;
+ src = &font->font[y];
+
+ write_artist(cfg, ARTIST_VRAM_IDX,
+ (in->dest_y << 13) | (in->dest_x << 2));
+
+ write_artist(cfg, ARTIST_FGCOLOR, in->fg_color);
+ write_artist(cfg, ARTIST_BGCOLOR, in->bg_color);
+ write_artist(cfg, ARTIST_BITMAP_OP, 0x23000300);
+ write_artist(cfg, ARTIST_VRAM_BITMASK, 0xffffffff << (32 - width));
+ write_artist(cfg, ARTIST_DST_BM_ACCESS, 0x2ea01000);
+ write_artist(cfg, ARTIST_PLANE_BITMASK, 7);
+ barrier();
+
+ pitch = (width + 7) / 8;
+ for (y = 0; y < bpc; y += pitch) {
+ u32 val = 0;
+ switch (pitch) {
+ case 4: val |= src[y+3] << 0; /* fall through */
+ case 3: val |= src[y+2] << 8; /* fall through */
+ case 2: val |= src[y+1] << 16; /* fall through */
+ default: val |= src[y+0] << 24; /* fall through */
+ }
+ write_artist(cfg, ARTIST_VRAM_BYTE_WRITE, val);
+ barrier();
+ }
+ out->errno = 0;
+ return 0;
+}
+
+static int __stifunc("init_graph") sti_init_graph(struct sti_init_flags *flags,
+ struct sti_init_inptr *in,
+ struct sti_init_outptr *out,
+ struct sti_glob_cfg *cfg)
+{
+ u32 *cmap = (u32 *)cfg->region_ptrs[1];
+ u32 resolution = *(u32 *)(cfg->region_ptrs[2] + 0x111110);
+
+ out->errno = 0;
+ if (resolution & (1 << 31)) {
+ cfg->text_planes = 1;
+ } else {
+ cfg->text_planes = in->text_planes;
+ if (cfg->text_planes < 0 || cfg->text_planes > 3)
+ cfg->text_planes = 3;
+ }
+ out->text_planes = cfg->text_planes;
+
+ cfg->onscreen_x = (resolution >> 16) & 0xfff;
+ cfg->onscreen_y = resolution & 0xfff;
+ cfg->offscreen_x = 0;
+ cfg->offscreen_y = 0;
+ cfg->total_x = 2048; /* hardcoded width */
+ cfg->total_y = cfg->onscreen_y;
+ if (cfg->total_y < 1024)
+ cfg->total_y = 1024;
+
+ if (flags->clear) {
+ /* clear screen */
+ write_artist(cfg, ARTIST_VRAM_BITMASK, 0xffffffff);
+ write_artist(cfg, ARTIST_FGCOLOR, 1);
+ write_artist(cfg, ARTIST_BGCOLOR, 0);
+ write_artist(cfg, ARTIST_VRAM_DEST, 0);
+ barrier();
+ write_artist(cfg, ARTIST_VRAM_SIZE_TRIGGER_WINFILL,
+ (cfg->total_x << 16) | cfg->total_y);
+ }
+
+ if (flags->init_cmap_tx) {
+ /* STI color map */
+ write_artist(cfg, ARTIST_CMAP_ACCESS, 0x3ba0f000);
+ cmap[0x100] = 0x000000; /* black */
+ cmap[0x101] = 0xffffff; /* white */
+ cmap[0x102] = 0xff0000; /* red */
+ cmap[0x103] = 0xffff00; /* yellow */
+ cmap[0x104] = 0x00ff00; /* green */
+ cmap[0x105] = 0x00ffff; /* cyan */
+ cmap[0x106] = 0x0000ff; /* blue */
+ cmap[0x107] = 0xff00ff; /* magenta */
+ write_artist(cfg, ARTIST_DST_BM_ACCESS, 0x2ea0f000);
+ }
+ return 0;
+}
+
+static __stifunc("self_test") int sti_self_test(struct sti_init_flags *flags,
+ struct sti_init_inptr *in,
+ struct sti_init_outptr *out,
+ struct sti_glob_cfg *cfg)
+{
+ (void)flags;
+ (void)in;
+ (void)cfg;
+
+ out->errno = 0;
+ return 0;
+}
+
+static __stifunc("inq_conf") int sti_inq_conf(struct sti_conf_flags *flags,
+ struct sti_conf_inptr *in,
+ struct sti_conf_outptr *out,
+ struct sti_glob_cfg *cfg)
+{
+ (void)in;
+ (void)flags;
+
+ out->errno = 0;
+ out->onscreen_x = cfg->onscreen_x;
+ out->onscreen_y = cfg->onscreen_y;
+ out->total_x = cfg->total_x;
+ out->total_y = cfg->total_y;
+ out->bits_per_pixel = 8;
+ out->bits_used = 8;
+ out->planes = cfg->text_planes;
+ /* attributes for GCDESCRIBE. See graphics.h and framebuf.h include files. */
+ out->attributes = 0x1836;
+ out->dev_name[0] = 'H';
+ out->dev_name[1] = 'P';
+ out->dev_name[2] = 'A';
+ out->dev_name[3] = '2';
+ out->dev_name[4] = '0';
+ out->dev_name[5] = '8';
+ out->dev_name[6] = 'L';
+ out->dev_name[7] = 'C';
+
+ switch(cfg->total_x) {
+ default:
+ /* default to 1280 if user gave some odd resolution */
+ out->dev_name[8] = '1';
+ out->dev_name[9] = '2';
+ out->dev_name[10] = '8';
+ out->dev_name[11] = '0';
+ out->dev_name[12] = '\0';
+ break;
+
+ case 1024:
+ out->dev_name[8] = '1';
+ out->dev_name[9] = '0';
+ out->dev_name[10] = '2';
+ out->dev_name[11] = '4';
+ out->dev_name[12] = '\0';
+ break;
+
+ case 800:
+ out->dev_name[8] = '8';
+ out->dev_name[9] = '0';
+ out->dev_name[10] = '0';
+ out->dev_name[11] = '\0';
+ break;
+
+ case 640:
+ out->dev_name[8] = '6';
+ out->dev_name[9] = '4';
+ out->dev_name[10] = '0';
+ out->dev_name[11] = '\0';
+ break;
+
+ }
+ return 0;
+}
+
+int __stifunc("excep_hdlr") sti_excep_hdlr(void)
+{
+ return 0;
+}
+
+int __stifunc("set_cm_entry") sti_set_cm_entry(struct setcm_flags *flags,
+ struct setcm_inptr *in,
+ struct setcm_outptr *out,
+ struct sti_glob_cfg *cfg)
+{
+ u32 *cmap = (u32 *)cfg->region_ptrs[1];
+ (void)flags;
+ (void)cfg;
+
+ cmap[in->entry & 0xffff] = in->value;
+ out->errno = 0;
+ return 0;
+}
+
+int __stifunc("dma_ctrl") sti_dma_ctrl(void)
+{
+ return 0;
+}
+
+void __stifunc("end") sti_end(void)
+{
+}
+
+static void update_crc(struct sti_rom *rom)
+{
+ u8 *c, *romend = (u8 *)rom + rom->last_addr - 2;
+ u16 code = 0, poly = 0x8408, accum = 0;
+ int i, j;
+
+ for (c = (u8 *)rom, j = 0; c <= romend; c++, j++) {
+ accum = (accum << 8) | (*c & 0xff);
+ if (j & 1) {
+ accum ^= code;
+ for (i = 0; i < 16; i++) {
+ /* do a left rotate */
+ if (accum & 0x8000) {
+ accum = (accum << 1) | 0x0001;
+ accum ^= poly;
+ } else {
+ accum <<= 1;
+ }
+ }
+ code = accum;
+ }
+ }
+ *(u16 *)(romend+1) = code;
+}
+
+#define STI_OFFSET(_x) ((u32)&(_x) - (u32)&_sti_rom_start)
+
+void sti_rom_init(void)
+{
+ unsigned int sti_rom_size;
+
+ sti_rom_size = (_sti_rom_end - _sti_rom_start) / 4096;
+ if (sti_region_list[0].region_desc.length != sti_rom_size) {
+ /* The STI ROM size is wrong. Try to fix it.
+ * If it's not writeable, we have to patch the source code. */
+ region_t *rp = (region_t *) &sti_region_list[0];
+ rp->region_desc.length = sti_rom_size;
+ }
+
+ sti_proc_rom.last_addr = _sti_rom_end - _sti_rom_start - 1;
+
+ sti_proc_rom.font_start = STI_OFFSET(sti_rom_font);
+ sti_proc_rom.state_mgmt = STI_OFFSET(sti_state_mgmt);
+ sti_proc_rom.inq_conf = STI_OFFSET(sti_inq_conf);
+ sti_proc_rom.init_graph = STI_OFFSET(sti_init_graph);
+ sti_proc_rom.block_move = STI_OFFSET(sti_bmove);
+ sti_proc_rom.region_list = STI_OFFSET(sti_region_list);
+ sti_proc_rom.font_unpmv = STI_OFFSET(sti_font_unpmv);
+ sti_proc_rom.self_test = STI_OFFSET(sti_self_test);
+ sti_proc_rom.mon_tbl_addr = STI_OFFSET(sti_mon_table);
+ sti_proc_rom.user_data_addr = STI_OFFSET(user_data);
+ sti_proc_rom.excep_hdlr = STI_OFFSET(sti_excep_hdlr);
+ sti_proc_rom.set_cm_entry = STI_OFFSET(sti_set_cm_entry);
+ sti_proc_rom.dma_ctrl = STI_OFFSET(sti_dma_ctrl);
+ sti_proc_rom.end = STI_OFFSET(sti_end);
+ update_crc(&sti_proc_rom);
+}
diff --git a/src/parisc/timer.c b/src/parisc/timer.c
new file mode 100644
index 0000000..ea8214f
--- /dev/null
+++ b/src/parisc/timer.c
@@ -0,0 +1,103 @@
+// Internal timer
+//
+// Copyright (C) 2008-2013 Kevin O'Connor <kevin@koconnor.net>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "config.h" // CONFIG_*
+#include "x86.h" // rdtscll()
+#include "util.h" // timer_setup
+#include "parisc/pdc.h"
+
+#define PAGE0 ((volatile struct zeropage *) 0UL)
+
+// Setup internal timers.
+void
+timer_setup(void)
+{
+}
+
+void
+pmtimer_setup(u16 ioport)
+{
+}
+
+// Return the number of milliseconds in 'ticks' number of timer irqs.
+u32 ticks_to_ms(u32 ticks)
+{
+ return (10 * ticks / PAGE0->mem_10msec);
+}
+
+
+u32 ticks_from_ms(u32 ms)
+{
+ return (ms * PAGE0->mem_10msec / 10);
+}
+
+
+/****************************************************************
+ * Internal timer reading
+ ****************************************************************/
+
+u32 TimerLast VARLOW;
+
+// Sample the current timer value.
+static u32
+timer_read(void)
+{
+ return rdtscll();
+}
+
+// Check if the current time is past a previously calculated end time.
+int
+timer_check(u32 end)
+{
+ return (s32)(timer_read() - end) > 0;
+}
+
+static void
+timer_sleep(u32 diff)
+{
+ u32 start = timer_read();
+ u32 end = start + diff;
+ while (!timer_check(end))
+ /* idle wait */;
+}
+
+void ndelay(u32 count) {
+ timer_sleep((count * PAGE0->mem_10msec / 10) / 1000 / 1000);
+}
+void udelay(u32 count) {
+ timer_sleep((count * PAGE0->mem_10msec / 10) / 1000);
+}
+void mdelay(u32 count) {
+ timer_sleep((count * PAGE0->mem_10msec / 10));
+}
+
+void nsleep(u32 count) {
+ ndelay(count);
+}
+void usleep(u32 count) {
+ udelay(count);
+}
+void msleep(u32 count) {
+ mdelay(count);
+}
+
+// Return the TSC value that is 'msecs' time in the future.
+u32
+timer_calc(u32 msecs)
+{
+ return (msecs * PAGE0->mem_10msec / 10) + timer_read();
+}
+u32
+timer_calc_usec(u32 usecs)
+{
+ return ((usecs * PAGE0->mem_10msec / 10) / 1000) + timer_read();
+}
+
+
+void
+pit_setup(void)
+{
+}