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 --- Makefile | 9 +- Makefile.parisc | 192 ++++ src/parisc/b160l.h | 630 +++++++++++ src/parisc/head.S | 319 ++++++ src/parisc/hppa.h | 370 +++++++ src/parisc/hppa_hardware.h | 49 + src/parisc/lasips2.c | 66 ++ src/parisc/lasips2.h | 17 + src/parisc/malloc.c | 91 ++ src/parisc/pafirmware.lds.S | 69 ++ src/parisc/parisc.c | 1997 +++++++++++++++++++++++++++++++++++ src/parisc/pdc.h | 694 ++++++++++++ src/parisc/sti.c | 179 ++++ src/parisc/sticore.h | 326 ++++++ src/parisc/stirom.c | 652 ++++++++++++ src/parisc/timer.c | 103 ++ 16 files changed, 5762 insertions(+), 1 deletion(-) create mode 100644 Makefile.parisc create mode 100644 src/parisc/b160l.h create mode 100644 src/parisc/head.S create mode 100644 src/parisc/hppa.h create mode 100644 src/parisc/hppa_hardware.h create mode 100644 src/parisc/lasips2.c create mode 100644 src/parisc/lasips2.h create mode 100644 src/parisc/malloc.c create mode 100644 src/parisc/pafirmware.lds.S create mode 100644 src/parisc/parisc.c create mode 100644 src/parisc/pdc.h create mode 100644 src/parisc/sti.c create mode 100644 src/parisc/sticore.h create mode 100644 src/parisc/stirom.c create mode 100644 src/parisc/timer.c
diff --git a/Makefile b/Makefile index 3d8943e..0f2b432 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(®s, 0, sizeof(regs)); + regs.ah = 0x10; + handle_16(®s); + 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) +{ +} -- 2.29.2