From fd9fed77fcfa1a04f1c1ab19f0ff8fe1e4305904 Mon Sep 17 00:00:00 2001 From: Kay Shinonome <77216999+kayshinonome@users.noreply.github.com> Date: Thu, 4 Aug 2022 02:18:05 -0500 Subject: [PATCH 1/2] A attempt at a LTS kernel patch --- patch-5.15-xenon0.20.diff | 549 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 549 insertions(+) create mode 100644 patch-5.15-xenon0.20.diff diff --git a/patch-5.15-xenon0.20.diff b/patch-5.15-xenon0.20.diff new file mode 100644 index 0000000..d99be45 --- /dev/null +++ b/patch-5.15-xenon0.20.diff @@ -0,0 +1,549 @@ +diff --git a/arch/powerpc/Kconfig.debug b/arch/powerpc/Kconfig.debug +index 192f0ed00..0e10ad9ef 100644 +--- a/arch/powerpc/Kconfig.debug ++++ b/arch/powerpc/Kconfig.debug +@@ -262,6 +262,14 @@ config PPC_EARLY_DEBUG_PS3GELIC + Select this to enable early debugging for the PlayStation3 via + UDP broadcasts sent out through the Ethernet port. + ++config PPC_EARLY_DEBUG_XENON ++ bool "Early debugging through Xenos framebuffer" ++ depends on PPC_XENON ++ select XENON_UDBG ++ help ++ Select this to enable early debugging for the Xenon via ++ early framebuffer support. ++ + config PPC_EARLY_DEBUG_OPAL_RAW + bool "OPAL raw console" + depends on HVC_OPAL +diff --git a/arch/powerpc/boot/.gitignore b/arch/powerpc/boot/.gitignore +index 1eee61b82..9b80e9634 100644 +--- a/arch/powerpc/boot/.gitignore ++++ b/arch/powerpc/boot/.gitignore +@@ -33,6 +33,7 @@ zImage.maple + zImage.miboot + zImage.pmac + zImage.pseries ++zImage.xenon + zconf.h + zlib.h + zutil.h +diff --git a/arch/powerpc/boot/Makefile b/arch/powerpc/boot/Makefile +index 089ee3ea5..5d428f563 100644 +--- a/arch/powerpc/boot/Makefile ++++ b/arch/powerpc/boot/Makefile +@@ -266,6 +266,7 @@ image-$(CONFIG_PPC_POWERNV) += zImage.pseries + image-$(CONFIG_PPC_MAPLE) += zImage.maple + image-$(CONFIG_PPC_IBM_CELL_BLADE) += zImage.pseries + image-$(CONFIG_PPC_PS3) += dtbImage.ps3 ++image-$(CONFIG_PPC_XENON) += zImage.xenon + image-$(CONFIG_PPC_CHRP) += zImage.chrp + image-$(CONFIG_PPC_EFIKA) += zImage.chrp + image-$(CONFIG_PPC_PMAC) += zImage.pmac +@@ -402,6 +403,11 @@ $(obj)/dtbImage.%: vmlinux $(wrapperbits) $(obj)/dts/%.dtb FORCE + $(obj)/vmlinux.strip: vmlinux + $(STRIP) -s -R .comment $< -o $@ + ++$(obj)/zImage.xenon: $(obj)/vmlinux.strip ++ @$(OBJCOPY) -O elf32-powerpc $< $@ ++ @test -e /mnt/e/Misc/tftpd64 && \ ++ cp -f $@ /mnt/e/Misc/tftpd64/vmlinux || true ++ + $(obj)/uImage: vmlinux $(wrapperbits) FORCE + $(call if_changed,wrap,uboot) + +diff --git a/arch/powerpc/include/asm/cputable.h b/arch/powerpc/include/asm/cputable.h +index e85c84921..62e32a38a 100644 +--- a/arch/powerpc/include/asm/cputable.h ++++ b/arch/powerpc/include/asm/cputable.h +@@ -456,6 +456,10 @@ static inline void cpu_feature_keys_init(void) { } + CPU_FTR_ALTIVEC_COMP | CPU_FTR_MMCRA | CPU_FTR_SMT | \ + CPU_FTR_PAUSE_ZERO | CPU_FTR_CELL_TB_BUG | CPU_FTR_CP_USE_DCBTZ | \ + CPU_FTR_UNALIGNED_LD_STD | CPU_FTR_DABRX) ++#define CPU_FTRS_XENON (CPU_FTR_LWSYNC | \ ++ CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | \ ++ CPU_FTR_ALTIVEC_COMP | CPU_FTR_MMCRA | CPU_FTR_SMT | \ ++ CPU_FTR_CELL_TB_BUG ) + #define CPU_FTRS_PA6T (CPU_FTR_LWSYNC | \ + CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_ALTIVEC_COMP | \ + CPU_FTR_PURR | CPU_FTR_REAL_LE | CPU_FTR_DABRX) +@@ -512,6 +516,9 @@ enum { + #endif + #ifdef CONFIG_PPC_E500MC + CPU_FTRS_E500MC | CPU_FTRS_E5500 | CPU_FTRS_E6500 | ++#endif ++#ifdef CONFIG_PPC_XENON ++ CPU_FTRS_XENON | + #endif + 0, + }; +diff --git a/arch/powerpc/include/asm/mmu.h b/arch/powerpc/include/asm/mmu.h +index 8abe8e42e..bd138c2b5 100644 +--- a/arch/powerpc/include/asm/mmu.h ++++ b/arch/powerpc/include/asm/mmu.h +@@ -141,6 +141,8 @@ + #define MMU_FTRS_POWER10 MMU_FTRS_POWER6 + #define MMU_FTRS_CELL MMU_FTRS_DEFAULT_HPTE_ARCH_V2 | \ + MMU_FTR_CI_LARGE_PAGE ++#define MMU_FTRS_XENON MMU_FTRS_DEFAULT_HPTE_ARCH_V2 | \ ++ MMU_FTR_CI_LARGE_PAGE + #define MMU_FTRS_PA6T MMU_FTRS_DEFAULT_HPTE_ARCH_V2 | \ + MMU_FTR_CI_LARGE_PAGE | MMU_FTR_NO_SLBIE_B + #ifndef __ASSEMBLY__ +diff --git a/arch/powerpc/include/asm/udbg.h b/arch/powerpc/include/asm/udbg.h +index 0ea9e70ed..29ab136cc 100644 +--- a/arch/powerpc/include/asm/udbg.h ++++ b/arch/powerpc/include/asm/udbg.h +@@ -53,6 +53,7 @@ extern void __init udbg_init_ehv_bc(void); + extern void __init udbg_init_ps3gelic(void); + extern void __init udbg_init_debug_opal_raw(void); + extern void __init udbg_init_debug_opal_hvsi(void); ++extern void __init udbg_init_xenon(void); + + #endif /* __KERNEL__ */ + #endif /* _ASM_POWERPC_UDBG_H */ +diff --git a/arch/powerpc/kernel/cputable.c b/arch/powerpc/kernel/cputable.c +index ae0fdef0a..e82fb64ec 100644 +--- a/arch/powerpc/kernel/cputable.c ++++ b/arch/powerpc/kernel/cputable.c +@@ -539,6 +539,18 @@ static struct cpu_spec __initdata cpu_specs[] = { + .oprofile_cpu_type = "ppc64/cell-be", + .platform = "ppc-cell-be", + }, ++ { /* Xenon */ ++ .pvr_mask = 0xffff0000, ++ .pvr_value = 0x00710000, ++ .cpu_name = "Xenon", ++ .cpu_features = CPU_FTRS_XENON, ++ .cpu_user_features = COMMON_USER_PPC64 | PPC_FEATURE_HAS_ALTIVEC_COMP | ++ PPC_FEATURE_SMT, ++ .mmu_features = MMU_FTRS_XENON, ++ .icache_bsize = 128, ++ .dcache_bsize = 128, ++ .platform = "xenon", ++ }, + { /* PA Semi PA6T */ + .pvr_mask = 0x7fff0000, + .pvr_value = 0x00900000, +diff --git a/arch/powerpc/kernel/misc_64.S b/arch/powerpc/kernel/misc_64.S +index d38a019b3..ca6a2cacf 100644 +--- a/arch/powerpc/kernel/misc_64.S ++++ b/arch/powerpc/kernel/misc_64.S +@@ -73,7 +73,7 @@ _GLOBAL(rmci_off) + blr + #endif /* CONFIG_PPC_EARLY_DEBUG_BOOTX */ + +-#if defined(CONFIG_PPC_PMAC) || defined(CONFIG_PPC_MAPLE) ++#if defined(CONFIG_PPC_PMAC) || defined(CONFIG_PPC_MAPLE) || defined(CONFIG_PPC_XENON) + + /* + * Do an IO access in real mode +diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c +index 2e67588f6..9f634782f 100644 +--- a/arch/powerpc/kernel/prom.c ++++ b/arch/powerpc/kernel/prom.c +@@ -327,6 +327,7 @@ static int __init early_init_dt_scan_cpus(unsigned long node, + intserv = of_get_flat_dt_prop(node, "reg", &len); + + nthreads = len / sizeof(int); ++ DBG("%s with %d threads \"%s\" v%d", type, nthreads, uname, fdt_version(initial_boot_params)); + + /* + * Now see if any of these threads match our boot cpu. +diff --git a/arch/powerpc/kernel/udbg.c b/arch/powerpc/kernel/udbg.c +index b1544b2f6..08a584df1 100644 +--- a/arch/powerpc/kernel/udbg.c ++++ b/arch/powerpc/kernel/udbg.c +@@ -67,6 +67,8 @@ void __init udbg_early_init(void) + udbg_init_debug_opal_raw(); + #elif defined(CONFIG_PPC_EARLY_DEBUG_OPAL_HVSI) + udbg_init_debug_opal_hvsi(); ++#elif defined(CONFIG_PPC_EARLY_DEBUG_XENON) ++ udbg_init_xenon(); + #endif + + #ifdef CONFIG_PPC_EARLY_DEBUG +diff --git a/arch/powerpc/platforms/Kconfig b/arch/powerpc/platforms/Kconfig +index e02d29a9d..54b774774 100644 +--- a/arch/powerpc/platforms/Kconfig ++++ b/arch/powerpc/platforms/Kconfig +@@ -22,6 +22,7 @@ source "arch/powerpc/platforms/40x/Kconfig" + source "arch/powerpc/platforms/amigaone/Kconfig" + source "arch/powerpc/platforms/book3s/Kconfig" + source "arch/powerpc/platforms/microwatt/Kconfig" ++source "arch/powerpc/platforms/xenon/Kconfig" + + config KVM_GUEST + bool "KVM Guest support" +diff --git a/arch/powerpc/platforms/Makefile b/arch/powerpc/platforms/Makefile +index 94470fb27..23d341ab4 100644 +--- a/arch/powerpc/platforms/Makefile ++++ b/arch/powerpc/platforms/Makefile +@@ -20,6 +20,7 @@ obj-$(CONFIG_PPC_MAPLE) += maple/ + obj-$(CONFIG_PPC_PASEMI) += pasemi/ + obj-$(CONFIG_PPC_CELL) += cell/ + obj-$(CONFIG_PPC_PS3) += ps3/ ++obj-$(CONFIG_PPC_XENON) += xenon/ + obj-$(CONFIG_EMBEDDED6xx) += embedded6xx/ + obj-$(CONFIG_AMIGAONE) += amigaone/ + obj-$(CONFIG_PPC_BOOK3S) += book3s/ +diff --git a/drivers/Makefile b/drivers/Makefile +index a110338c8..feccef1d1 100644 +--- a/drivers/Makefile ++++ b/drivers/Makefile +@@ -138,6 +138,7 @@ obj-y += clocksource/ + obj-$(CONFIG_DCA) += dca/ + obj-$(CONFIG_HID) += hid/ + obj-$(CONFIG_PPC_PS3) += ps3/ ++obj-$(CONFIG_PPC_XENON) += xenon/ + obj-$(CONFIG_OF) += of/ + obj-$(CONFIG_SSB) += ssb/ + obj-$(CONFIG_BCMA) += bcma/ +diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig +index a7da8ea7b..656ff2943 100644 +--- a/drivers/ata/Kconfig ++++ b/drivers/ata/Kconfig +@@ -525,6 +525,14 @@ config SATA_SVW + + If unsure, say N. + ++config SATA_XENON ++ tristate "Xenon SATA support" ++ depends on PCI ++ help ++ This option enables support for Xenon southbridge. ++ ++ If unsure, say N. ++ + config SATA_ULI + tristate "ULi Electronics SATA support" + depends on PCI +diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile +index b8aebfb14..95525b108 100644 +--- a/drivers/ata/Makefile ++++ b/drivers/ata/Makefile +@@ -13,6 +13,7 @@ obj-$(CONFIG_SATA_INIC162X) += sata_inic162x.o + obj-$(CONFIG_SATA_SIL24) += sata_sil24.o + obj-$(CONFIG_SATA_DWC) += sata_dwc_460ex.o + obj-$(CONFIG_SATA_HIGHBANK) += sata_highbank.o libahci.o ++obj-$(CONFIG_SATA_XENON) += sata_xenon.o + obj-$(CONFIG_AHCI_BRCM) += ahci_brcm.o libahci.o libahci_platform.o + obj-$(CONFIG_AHCI_CEVA) += ahci_ceva.o libahci.o libahci_platform.o + obj-$(CONFIG_AHCI_DA850) += ahci_da850.o libahci.o libahci_platform.o +diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig +index d454428f4..f767d7e6b 100644 +--- a/drivers/char/Kconfig ++++ b/drivers/char/Kconfig +@@ -7,6 +7,32 @@ menu "Character devices" + + source "drivers/tty/Kconfig" + ++config XENON_SMC ++ tristate "Xenon System Management Controller (SMC)" ++ depends on PPC_XENON ++ help ++ Character interface to the System Management controller in the ++ Xbox 360. Allows to send arbitrary SMC commands and receive ++ SMC replies. ++ ++config XENON_ANA ++ tristate "Xenon (H)ana Character Device" ++ depends on PPC_XENON ++ help ++ Character interface to the (H)ana chip on the Xbox 360. ++ ++config XENON_PROBE ++ tristate "Xenon Memory Probe Device" ++ depends on PPC_XENON && EXPERIMENTAL ++ help ++ Character interface to do memory probing on the Xbox 360. ++ ++config XENOS_RB ++ tristate "Xenos Ring Buffer Device" ++ depends on PPC_XENON && HAS_DMA ++ help ++ Character device supporting raw ringbuffer writes to the Xenos. ++ + config TTY_PRINTK + tristate "TTY driver to output user messages via printk" + depends on EXPERT && TTY +diff --git a/drivers/char/Makefile b/drivers/char/Makefile +index 264eb398f..08710bfe2 100644 +--- a/drivers/char/Makefile ++++ b/drivers/char/Makefile +@@ -11,6 +11,10 @@ obj-$(CONFIG_VIRTIO_CONSOLE) += virtio_console.o + obj-$(CONFIG_MSPEC) += mspec.o + obj-$(CONFIG_UV_MMTIMER) += uv_mmtimer.o + obj-$(CONFIG_IBM_BSR) += bsr.o ++obj-$(CONFIG_XENON_SMC) += xenon_smc.o ++obj-$(CONFIG_XENON_ANA) += xenon_ana.o ++obj-$(CONFIG_XENON_PROBE) += xenon_probe.o ++obj-$(CONFIG_XENOS_RB) += xenos_rb.o + + obj-$(CONFIG_PRINTER) += lp.o + +diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig +index 51f1caa10..fd1fa53b4 100644 +--- a/drivers/hwmon/Kconfig ++++ b/drivers/hwmon/Kconfig +@@ -2178,6 +2178,13 @@ config SENSORS_INTEL_M10_BMC_HWMON + sensors monitor various telemetry data of different components on the + card, e.g. board temperature, FPGA core temperature/voltage/current. + ++config SENSORS_XENON ++ tristate "Xenon SMC" ++ depends on PPC_XENON ++ help ++ This driver provides support for the Xenon SMC sensors and ++ fan control. ++ + if ACPI + + comment "ACPI drivers" +diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile +index 162940270..f005911d5 100644 +--- a/drivers/hwmon/Makefile ++++ b/drivers/hwmon/Makefile +@@ -200,6 +200,7 @@ obj-$(CONFIG_SENSORS_W83L785TS) += w83l785ts.o + obj-$(CONFIG_SENSORS_W83L786NG) += w83l786ng.o + obj-$(CONFIG_SENSORS_WM831X) += wm831x-hwmon.o + obj-$(CONFIG_SENSORS_WM8350) += wm8350-hwmon.o ++obj-$(CONFIG_SENSORS_XENON) += xenon-hwmon.o + obj-$(CONFIG_SENSORS_XGENE) += xgene-hwmon.o + + obj-$(CONFIG_SENSORS_OCC) += occ/ +diff --git a/drivers/net/ethernet/Kconfig b/drivers/net/ethernet/Kconfig +index 35ac6fe75..c8a58f8e2 100644 +--- a/drivers/net/ethernet/Kconfig ++++ b/drivers/net/ethernet/Kconfig +@@ -185,5 +185,6 @@ source "drivers/net/ethernet/via/Kconfig" + source "drivers/net/ethernet/wiznet/Kconfig" + source "drivers/net/ethernet/xilinx/Kconfig" + source "drivers/net/ethernet/xircom/Kconfig" ++source "drivers/net/ethernet/xenon/Kconfig" + + endif # ETHERNET +diff --git a/drivers/net/ethernet/Makefile b/drivers/net/ethernet/Makefile +index aaa5078cd..a9dd2861b 100644 +--- a/drivers/net/ethernet/Makefile ++++ b/drivers/net/ethernet/Makefile +@@ -95,5 +95,6 @@ obj-$(CONFIG_NET_VENDOR_VIA) += via/ + obj-$(CONFIG_NET_VENDOR_WIZNET) += wiznet/ + obj-$(CONFIG_NET_VENDOR_XILINX) += xilinx/ + obj-$(CONFIG_NET_VENDOR_XIRCOM) += xircom/ ++obj-$(CONFIG_NET_XENON) += xenon/ + obj-$(CONFIG_NET_VENDOR_SYNOPSYS) += synopsys/ + obj-$(CONFIG_NET_VENDOR_PENSANDO) += pensando/ +diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig +index e1bc52144..2a506527e 100644 +--- a/drivers/rtc/Kconfig ++++ b/drivers/rtc/Kconfig +@@ -1639,6 +1639,16 @@ config RTC_DRV_PS3 + This driver can also be built as a module. If so, the module + will be called rtc-ps3. + ++config RTC_DRV_XENON ++ tristate "Xenon RTC" ++ depends on PPC_XENON ++ help ++ If you say yes here you will get support for the RTC on the ++ Xbox 360. ++ ++ This driver can also be built as a module. If so, the module ++ will be called rtc-xenon. ++ + config RTC_DRV_STMP + tristate "Freescale STMP3xxx/i.MX23/i.MX28 RTC" + depends on ARCH_MXS || COMPILE_TEST +diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile +index 5ceeafe4d..8aef02082 100644 +--- a/drivers/rtc/Makefile ++++ b/drivers/rtc/Makefile +@@ -178,5 +178,6 @@ obj-$(CONFIG_RTC_DRV_WILCO_EC) += rtc-wilco-ec.o + obj-$(CONFIG_RTC_DRV_WM831X) += rtc-wm831x.o + obj-$(CONFIG_RTC_DRV_WM8350) += rtc-wm8350.o + obj-$(CONFIG_RTC_DRV_X1205) += rtc-x1205.o ++obj-$(CONFIG_RTC_DRV_XENON) += rtc-xenon.o + obj-$(CONFIG_RTC_DRV_XGENE) += rtc-xgene.o + obj-$(CONFIG_RTC_DRV_ZYNQMP) += rtc-zynqmp.o +diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c +index 9466474ff..565ff86e8 100644 +--- a/drivers/scsi/scsi_scan.c ++++ b/drivers/scsi/scsi_scan.c +@@ -654,6 +654,7 @@ static int scsi_probe_lun(struct scsi_device *sdev, unsigned char *inq_result, + memset(scsi_cmd, 0, 6); + scsi_cmd[0] = INQUIRY; + scsi_cmd[4] = (unsigned char) try_inquiry_len; ++ scsi_cmd[5] = 0xc0; /* HACK */ + + memset(inq_result, 0, try_inquiry_len); + +diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig +index 131a6a587..8c11aec2b 100644 +--- a/drivers/tty/serial/Kconfig ++++ b/drivers/tty/serial/Kconfig +@@ -1528,6 +1528,25 @@ config SERIAL_MILBEAUT_USIO_CONSOLE + receives all kernel messages and warnings and which allows logins in + single user mode). + ++config SERIAL_XENON ++ tristate "Xenon XBOX 360 serial port support" ++ select SERIAL_CORE ++ help ++ If you have an XBOX 360, you can enable its onboard ++ serial port by enabling this options. ++ ++ To compile this driver as a module, choose M here: the ++ module will be called xenon_uart. ++ ++config SERIAL_XENON_CONSOLE ++ bool "Console on XBOX 360 serial port" ++ depends on SERIAL_XENON=y ++ select SERIAL_CORE_CONSOLE ++ help ++ If you have enabled the serial port on the XBOX 360 ++ ++ you can make it the console by answering Y to this option. ++ + config SERIAL_LITEUART + tristate "LiteUART serial port support" + depends on HAS_IOMEM +diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile +index 7da0856cd..6659b3f64 100644 +--- a/drivers/tty/serial/Makefile ++++ b/drivers/tty/serial/Makefile +@@ -65,6 +65,7 @@ obj-$(CONFIG_SERIAL_GRLIB_GAISLER_APBUART) += apbuart.o + obj-$(CONFIG_SERIAL_ALTERA_JTAGUART) += altera_jtaguart.o + obj-$(CONFIG_SERIAL_VT8500) += vt8500_serial.o + obj-$(CONFIG_SERIAL_PCH_UART) += pch_uart.o ++obj-$(CONFIG_SERIAL_XENON) += xenon_uart.o + obj-$(CONFIG_SERIAL_MXS_AUART) += mxs-auart.o + obj-$(CONFIG_SERIAL_LANTIQ) += lantiq.o + obj-$(CONFIG_SERIAL_XILINX_PS_UART) += xilinx_uartps.o +diff --git a/drivers/video/fbdev/Kconfig b/drivers/video/fbdev/Kconfig +index 6ed5e608d..2164d4110 100644 +--- a/drivers/video/fbdev/Kconfig ++++ b/drivers/video/fbdev/Kconfig +@@ -659,6 +659,15 @@ config FB_N411 + This enables support for the Apollo display controller in its + Hecuba form using the n411 devkit. + ++config FB_XENOS ++ tristate "Xbox 360 Framebuffer Support" ++ depends on (FB = y) && PPC ++ select FB_CFB_FILLRECT ++ select FB_CFB_COPYAREA ++ select FB_CFB_IMAGEBLIT ++ help ++ This is the frame buffer device driver for the Microsoft Xbox 360. ++ + config FB_HGA + tristate "Hercules mono graphics support" + depends on FB && X86 +diff --git a/drivers/video/fbdev/Makefile b/drivers/video/fbdev/Makefile +index 477b9624b..2e64a4e20 100644 +--- a/drivers/video/fbdev/Makefile ++++ b/drivers/video/fbdev/Makefile +@@ -123,6 +123,7 @@ obj-$(CONFIG_FB_SM712) += sm712fb.o + obj-$(CONFIG_FB_UVESA) += uvesafb.o + obj-$(CONFIG_FB_VESA) += vesafb.o + obj-$(CONFIG_FB_EFI) += efifb.o ++obj-$(CONFIG_FB_XENOS) += xenosfb.o + obj-$(CONFIG_FB_VGA16) += vga16fb.o + obj-$(CONFIG_FB_OF) += offb.o + obj-$(CONFIG_FB_MX3) += mx3fb.o +diff --git a/include/linux/fb.h b/include/linux/fb.h +index 3d7306c9a..1ef9e953f 100644 +--- a/include/linux/fb.h ++++ b/include/linux/fb.h +@@ -688,6 +688,17 @@ static inline bool fb_be_math(struct fb_info *info) + #endif /* CONFIG_FB_FOREIGN_ENDIAN */ + } + ++static inline int *xenon_convert(struct fb_info *p, int *addr) ++{ ++ int index = ((char*)addr) - ((char*)p->screen_base); ++ int y = index / (p->fix.line_length); ++ int x = index % (p->fix.line_length)/4; ++ unsigned int base = ((((y & ~31)*p->var.xres) + (x & ~31)*32 ) + ++ (((x&3) + ((y&1)<<2) + ((x&28)<<1) + ((y&30)<<5)) ^ ((y&8)<<2))) * 4; ++ ++ return (int*)(((char*)p->screen_base)+base); ++} ++ + /* drivers/video/fbsysfs.c */ + extern struct fb_info *framebuffer_alloc(size_t size, struct device *dev); + extern void framebuffer_release(struct fb_info *info); +diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h +index 011f2f1ea..72aeb830e 100644 +--- a/include/linux/pci_ids.h ++++ b/include/linux/pci_ids.h +@@ -2323,6 +2323,8 @@ + #define PCI_DEVICE_ID_ADDIDATA_APCIe7500 0x7012 + #define PCI_DEVICE_ID_ADDIDATA_APCIe7800 0x7013 + ++#define PCI_VENDOR_ID_MICROSOFT 0x1414 ++ + #define PCI_VENDOR_ID_PDC 0x15e9 + + #define PCI_VENDOR_ID_FARSITE 0x1619 +diff --git a/include/uapi/linux/serial_core.h b/include/uapi/linux/serial_core.h +index 8885e6917..31d95bc1d 100644 +--- a/include/uapi/linux/serial_core.h ++++ b/include/uapi/linux/serial_core.h +@@ -211,6 +211,9 @@ + /* Atheros AR933X SoC */ + #define PORT_AR933X 99 + ++/* Xenon XBOX 360 Southbridge */ ++#define PORT_XENON 91 ++ + /* ARC (Synopsys) on-chip UART */ + #define PORT_ARC 101 + +diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug +index 7fd3fa053..29062d26a 100644 +--- a/lib/Kconfig.debug ++++ b/lib/Kconfig.debug +@@ -89,7 +89,7 @@ config MESSAGE_LOGLEVEL_DEFAULT + + config BOOT_PRINTK_DELAY + bool "Delay each boot printk message by N milliseconds" +- depends on DEBUG_KERNEL && PRINTK && GENERIC_CALIBRATE_DELAY ++ depends on DEBUG_KERNEL && PRINTK + help + This build option allows you to read kernel boot messages + by inserting a short delay after each one. The delay is +diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig +index 41ce12597..b7af45bc1 100644 +--- a/sound/pci/Kconfig ++++ b/sound/pci/Kconfig +@@ -909,6 +909,15 @@ config SND_YMFPCI + To compile this driver as a module, choose M here: the module + will be called snd-ymfpci. + ++config SND_XENON ++ tristate "Xenon XBOX 360 Sound" ++ select SND_PCM ++ help ++ Say Y here to include support for the Xenon XBOX 360 soundcard. ++ ++ To compile this driver as a module, choose M here: the module ++ will be called snd-xenon. ++ + endif # SND_PCI + + source "sound/pci/hda/Kconfig" +diff --git a/sound/pci/Makefile b/sound/pci/Makefile +index 04cac7469..2e3a3e076 100644 +--- a/sound/pci/Makefile ++++ b/sound/pci/Makefile +@@ -54,6 +54,7 @@ obj-$(CONFIG_SND_SIS7019) += snd-sis7019.o + obj-$(CONFIG_SND_SONICVIBES) += snd-sonicvibes.o + obj-$(CONFIG_SND_VIA82XX) += snd-via82xx.o + obj-$(CONFIG_SND_VIA82XX_MODEM) += snd-via82xx-modem.o ++obj-$(CONFIG_SND_XENON) += snd-xenon.o + + obj-$(CONFIG_SND) += \ + ac97/ \ From 1f78869830b919bfd3ec539c3c1046f6fdce25c7 Mon Sep 17 00:00:00 2001 From: Kay Shinonome <77216999+kayshinonome@users.noreply.github.com> Date: Thu, 4 Aug 2022 02:35:32 -0500 Subject: [PATCH 2/2] Added rest of diff file --- patch-5.15-xenon0.20.diff | 6722 +++++++++++++++++++++++++++++++++++-- 1 file changed, 6481 insertions(+), 241 deletions(-) diff --git a/patch-5.15-xenon0.20.diff b/patch-5.15-xenon0.20.diff index d99be45..d6308ca 100644 --- a/patch-5.15-xenon0.20.diff +++ b/patch-5.15-xenon0.20.diff @@ -53,6 +53,144 @@ index 089ee3ea5..5d428f563 100644 $(obj)/uImage: vmlinux $(wrapperbits) FORCE $(call if_changed,wrap,uboot) +diff --git a/arch/powerpc/boot/dts/xenon.dts b/arch/powerpc/boot/dts/xenon.dts +new file mode 100644 +index 000000000..2f1b3146a +--- /dev/null ++++ b/arch/powerpc/boot/dts/xenon.dts +@@ -0,0 +1,131 @@ ++/* ++ * xenon.dts - Xbox360 Game Console device tree. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; version 2 of the License. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++/dts-v1/; ++ ++/ { ++ model = "Xenon Game Console"; ++ compatible = "XENON"; ++ #address-cells = <2>; ++ #size-cells = <1>; ++ ++ /* ++ * Bootargs will be created here, as well as initrd properties if relevant ++ */ ++ chosen { ++ linux,platform = <0x00000801>; ++ }; ++ ++ memory { ++ device_type = "memory"; ++ reg = <0x00000000 0x00000000 0x1e000000>; ++ }; ++ ++ cpus { ++ #cpus = <1>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ Xenon,PPE@0 { ++ device_type = "cpu"; ++ linux,boot-cpu; ++ reg = <0>; ++ ibm,ppc-interrupt-server#s = <0 1>; ++ timebase-frequency = <0x2FAF080>; // 50 MHz ++ i-cache-size = <0x8000>; ++ i-cache-line-size = <0x80>; ++ d-cache-size = <0x8000>; ++ d-cache-line-size = <0x80>; ++ ++ /* this must be configured with regard to the HID6:LB value */ ++ ibm,segment-page-sizes = < ++ 0xC 0 1 0xc 0 // 4k page ++ 0x10 0x100 1 0x10 00 // 64k pages ++ 0x18 0x110 1 0x18 01 // 16M pages ++ >; ++ }; ++ Xenon,PPE@1 { ++ device_type = "cpu"; ++ reg = <2>; ++ ibm,ppc-interrupt-server#s = <2 3>; ++ timebase-frequency = <0x2FAF080>; ++ i-cache-size = <0x8000>; ++ i-cache-line-size = <0x80>; ++ d-cache-size = <0x8000>; ++ d-cache-line-size = <0x80>; ++ }; ++ Xenon,PPE@2 { ++ device_type = "cpu"; ++ reg = <4>; ++ ibm,ppc-interrupt-server#s = <4 5>; ++ timebase-frequency = <0x2FAF080>; ++ i-cache-size = <0x8000>; ++ i-cache-line-size = <0x80>; ++ d-cache-size = <0x8000>; ++ d-cache-line-size = <0x80>; ++ }; ++ }; ++ ++ pci { ++ compatible = "xenon"; ++ device_type = "pci"; ++ #address-cells = <3>; // phy up, mid, low ++ #size-cells = <1>; ++ #interrupt-cells = <1>; ++ ++ interrupt-parent = <0x40000>; ++ // interrupts = <18 2>; ++ interrupt-map-mask = <0xf900 0 0 0>; // type, lower, upper, irq ++ ++ interrupt-map = < ++ 0x0000 0 0 0 0x40000 0x40 // XMA ++ 0x0800 0 0 0 0x40000 0x24 // SATA cdrom ++ 0x1000 0 0 0 0x40000 0x20 // SATA disk ++ 0x2000 0 0 0 0x40000 0x2c // USB OHCI #1 ++ 0x2100 0 0 0 0x40000 0x30 // USB EHCI #1 ++ 0x2800 0 0 0 0x40000 0x34 // USB OHCI #2 ++ 0x2900 0 0 0 0x40000 0x38 // USB EHCI #2 ++ 0x3800 0 0 0 0x40000 0x4c // Enet ++ 0x4000 0 0 0 0x40000 0x18 // Flash ++ 0x4800 0 0 0 0x40000 0x44 // audio out ++ 0x5000 0 0 0 0x40000 0x14 // SMM, GPIO, ... ++ 0x7800 0 0 0 0x40000 0x58 // Xenos ++ >; ++ ++ bus-range = <0 0>; ++ ranges = < ++ 0x02000000 0x00000000 0x80000000 0x00000200 0x80000000 0x80000000 // PCI space at 80000000 is mapped to 200 80000000 ++ 0x02000000 0x00000000 0x00000000 0x00000000 0x00000000 0x20000000 // RAM is 1:1 mapped ++ >; ++ }; ++ ++ interrupt-controller { ++ compatible = "xenon"; ++ linux,phandle = <0x40000>; ++ interrupt-controller; ++ #address-cells = <0>; ++ #interrupt-cells = <1>; ++ built-in; ++ reg = <0x00000200 0x00050000 0x6000>; ++ interrupts = < ++ 0x7c 0x78 0x74 0x70 0x6c 0x68 0x64 0x60 ++ 0x5c 0x58 0x54 0x50 0x4c 0x48 0x44 0x40 ++ 0x3c 0x38 0x34 0x30 0x2c 0x28 0x24 0x20 ++ 0x1c 0x18 0x14 0x10 0x0c 0x08 0x04 ++ >; ++ }; ++}; +\ No newline at end of file diff --git a/arch/powerpc/include/asm/cputable.h b/arch/powerpc/include/asm/cputable.h index e85c84921..62e32a38a 100644 --- a/arch/powerpc/include/asm/cputable.h @@ -188,263 +326,4882 @@ index 94470fb27..23d341ab4 100644 obj-$(CONFIG_EMBEDDED6xx) += embedded6xx/ obj-$(CONFIG_AMIGAONE) += amigaone/ obj-$(CONFIG_PPC_BOOK3S) += book3s/ -diff --git a/drivers/Makefile b/drivers/Makefile -index a110338c8..feccef1d1 100644 ---- a/drivers/Makefile -+++ b/drivers/Makefile -@@ -138,6 +138,7 @@ obj-y += clocksource/ - obj-$(CONFIG_DCA) += dca/ - obj-$(CONFIG_HID) += hid/ - obj-$(CONFIG_PPC_PS3) += ps3/ -+obj-$(CONFIG_PPC_XENON) += xenon/ - obj-$(CONFIG_OF) += of/ - obj-$(CONFIG_SSB) += ssb/ - obj-$(CONFIG_BCMA) += bcma/ -diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig -index a7da8ea7b..656ff2943 100644 ---- a/drivers/ata/Kconfig -+++ b/drivers/ata/Kconfig -@@ -525,6 +525,14 @@ config SATA_SVW - - If unsure, say N. - -+config SATA_XENON -+ tristate "Xenon SATA support" -+ depends on PCI +diff --git a/arch/powerpc/platforms/xenon/Kconfig b/arch/powerpc/platforms/xenon/Kconfig +new file mode 100644 +index 000000000..226c305c3 +--- /dev/null ++++ b/arch/powerpc/platforms/xenon/Kconfig +@@ -0,0 +1,18 @@ ++config PPC_XENON ++ bool "Xenon" ++ depends on PPC64 ++ select PPC_NATIVE ++ select DMA_VIRT_OPS ++ select HAVE_PCI ++ default y + help -+ This option enables support for Xenon southbridge. -+ -+ If unsure, say N. ++ This option enables support for the Xbox 360 game console ++ without a hypervisor. + - config SATA_ULI - tristate "ULi Electronics SATA support" - depends on PCI -diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile -index b8aebfb14..95525b108 100644 ---- a/drivers/ata/Makefile -+++ b/drivers/ata/Makefile -@@ -13,6 +13,7 @@ obj-$(CONFIG_SATA_INIC162X) += sata_inic162x.o - obj-$(CONFIG_SATA_SIL24) += sata_sil24.o - obj-$(CONFIG_SATA_DWC) += sata_dwc_460ex.o - obj-$(CONFIG_SATA_HIGHBANK) += sata_highbank.o libahci.o -+obj-$(CONFIG_SATA_XENON) += sata_xenon.o - obj-$(CONFIG_AHCI_BRCM) += ahci_brcm.o libahci.o libahci_platform.o - obj-$(CONFIG_AHCI_CEVA) += ahci_ceva.o libahci.o libahci_platform.o - obj-$(CONFIG_AHCI_DA850) += ahci_da850.o libahci.o libahci_platform.o -diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig -index d454428f4..f767d7e6b 100644 ---- a/drivers/char/Kconfig -+++ b/drivers/char/Kconfig -@@ -7,6 +7,32 @@ menu "Character devices" - - source "drivers/tty/Kconfig" - -+config XENON_SMC -+ tristate "Xenon System Management Controller (SMC)" ++config XENON_UDBG ++ bool "Xenon Early Console" + depends on PPC_XENON ++ select FONT_SUPPORT + help -+ Character interface to the System Management controller in the -+ Xbox 360. Allows to send arbitrary SMC commands and receive -+ SMC replies. ++ This option enables early debugging over ethernet for the ++ Xenon platform. +\ No newline at end of file +diff --git a/arch/powerpc/platforms/xenon/Makefile b/arch/powerpc/platforms/xenon/Makefile +new file mode 100644 +index 000000000..a67d575f8 +--- /dev/null ++++ b/arch/powerpc/platforms/xenon/Makefile +@@ -0,0 +1,4 @@ ++obj-y += setup.o interrupt.o pci.o time.o hardware.o + -+config XENON_ANA -+ tristate "Xenon (H)ana Character Device" -+ depends on PPC_XENON -+ help -+ Character interface to the (H)ana chip on the Xbox 360. ++obj-$(CONFIG_SMP) += smp.o ++obj-$(CONFIG_XENON_UDBG) += xe_udbg.o +\ No newline at end of file +diff --git a/arch/powerpc/platforms/xenon/hardware.c b/arch/powerpc/platforms/xenon/hardware.c +new file mode 100644 +index 000000000..a46595ce9 +--- /dev/null ++++ b/arch/powerpc/platforms/xenon/hardware.c +@@ -0,0 +1,36 @@ ++/* ++ * Xenon hardware related routines. ++ * ++ * Copyright (C) 2010 Herbert Poetzl ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; version 2 of the License. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ + -+config XENON_PROBE -+ tristate "Xenon Memory Probe Device" -+ depends on PPC_XENON && EXPERIMENTAL -+ help -+ Character interface to do memory probing on the Xbox 360. ++#include ++#include ++#include ++#include + -+config XENOS_RB -+ tristate "Xenos Ring Buffer Device" -+ depends on PPC_XENON && HAS_DMA -+ help -+ Character device supporting raw ringbuffer writes to the Xenos. ++static int __init xenon_hwmon_init(void) ++{ ++ struct platform_device *pdev; + - config TTY_PRINTK - tristate "TTY driver to output user messages via printk" - depends on EXPERT && TTY -diff --git a/drivers/char/Makefile b/drivers/char/Makefile -index 264eb398f..08710bfe2 100644 ---- a/drivers/char/Makefile -+++ b/drivers/char/Makefile -@@ -11,6 +11,10 @@ obj-$(CONFIG_VIRTIO_CONSOLE) += virtio_console.o - obj-$(CONFIG_MSPEC) += mspec.o - obj-$(CONFIG_UV_MMTIMER) += uv_mmtimer.o - obj-$(CONFIG_IBM_BSR) += bsr.o -+obj-$(CONFIG_XENON_SMC) += xenon_smc.o -+obj-$(CONFIG_XENON_ANA) += xenon_ana.o -+obj-$(CONFIG_XENON_PROBE) += xenon_probe.o -+obj-$(CONFIG_XENOS_RB) += xenos_rb.o - - obj-$(CONFIG_PRINTER) += lp.o - -diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig -index 51f1caa10..fd1fa53b4 100644 ---- a/drivers/hwmon/Kconfig -+++ b/drivers/hwmon/Kconfig -@@ -2178,6 +2178,13 @@ config SENSORS_INTEL_M10_BMC_HWMON - sensors monitor various telemetry data of different components on the - card, e.g. board temperature, FPGA core temperature/voltage/current. - -+config SENSORS_XENON -+ tristate "Xenon SMC" -+ depends on PPC_XENON -+ help -+ This driver provides support for the Xenon SMC sensors and -+ fan control. ++ pdev = platform_device_register_simple("xenon-hwmon", -1, NULL, 0); ++ if (IS_ERR(pdev)) ++ return PTR_ERR(pdev); + - if ACPI - - comment "ACPI drivers" -diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile -index 162940270..f005911d5 100644 ---- a/drivers/hwmon/Makefile -+++ b/drivers/hwmon/Makefile -@@ -200,6 +200,7 @@ obj-$(CONFIG_SENSORS_W83L785TS) += w83l785ts.o - obj-$(CONFIG_SENSORS_W83L786NG) += w83l786ng.o - obj-$(CONFIG_SENSORS_WM831X) += wm831x-hwmon.o - obj-$(CONFIG_SENSORS_WM8350) += wm8350-hwmon.o -+obj-$(CONFIG_SENSORS_XENON) += xenon-hwmon.o - obj-$(CONFIG_SENSORS_XGENE) += xgene-hwmon.o - - obj-$(CONFIG_SENSORS_OCC) += occ/ -diff --git a/drivers/net/ethernet/Kconfig b/drivers/net/ethernet/Kconfig -index 35ac6fe75..c8a58f8e2 100644 ---- a/drivers/net/ethernet/Kconfig -+++ b/drivers/net/ethernet/Kconfig -@@ -185,5 +185,6 @@ source "drivers/net/ethernet/via/Kconfig" - source "drivers/net/ethernet/wiznet/Kconfig" - source "drivers/net/ethernet/xilinx/Kconfig" - source "drivers/net/ethernet/xircom/Kconfig" -+source "drivers/net/ethernet/xenon/Kconfig" - - endif # ETHERNET -diff --git a/drivers/net/ethernet/Makefile b/drivers/net/ethernet/Makefile -index aaa5078cd..a9dd2861b 100644 ---- a/drivers/net/ethernet/Makefile -+++ b/drivers/net/ethernet/Makefile -@@ -95,5 +95,6 @@ obj-$(CONFIG_NET_VENDOR_VIA) += via/ - obj-$(CONFIG_NET_VENDOR_WIZNET) += wiznet/ - obj-$(CONFIG_NET_VENDOR_XILINX) += xilinx/ - obj-$(CONFIG_NET_VENDOR_XIRCOM) += xircom/ -+obj-$(CONFIG_NET_XENON) += xenon/ - obj-$(CONFIG_NET_VENDOR_SYNOPSYS) += synopsys/ - obj-$(CONFIG_NET_VENDOR_PENSANDO) += pensando/ -diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig -index e1bc52144..2a506527e 100644 ---- a/drivers/rtc/Kconfig -+++ b/drivers/rtc/Kconfig -@@ -1639,6 +1639,16 @@ config RTC_DRV_PS3 - This driver can also be built as a module. If so, the module - will be called rtc-ps3. - -+config RTC_DRV_XENON -+ tristate "Xenon RTC" -+ depends on PPC_XENON -+ help -+ If you say yes here you will get support for the RTC on the -+ Xbox 360. ++ return 0; ++} + -+ This driver can also be built as a module. If so, the module -+ will be called rtc-xenon. ++module_init(xenon_hwmon_init); +diff --git a/arch/powerpc/platforms/xenon/interrupt.c b/arch/powerpc/platforms/xenon/interrupt.c +new file mode 100644 +index 000000000..67811cf27 +--- /dev/null ++++ b/arch/powerpc/platforms/xenon/interrupt.c +@@ -0,0 +1,371 @@ ++/* ++ * Xenon interrupt controller, ++ * ++ * Maintained by: Felix Domke ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License v2 ++ * as published by the Free Software Foundation. ++ */ + - config RTC_DRV_STMP - tristate "Freescale STMP3xxx/i.MX23/i.MX28 RTC" - depends on ARCH_MXS || COMPILE_TEST -diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile -index 5ceeafe4d..8aef02082 100644 ---- a/drivers/rtc/Makefile -+++ b/drivers/rtc/Makefile -@@ -178,5 +178,6 @@ obj-$(CONFIG_RTC_DRV_WILCO_EC) += rtc-wilco-ec.o - obj-$(CONFIG_RTC_DRV_WM831X) += rtc-wm831x.o - obj-$(CONFIG_RTC_DRV_WM8350) += rtc-wm8350.o - obj-$(CONFIG_RTC_DRV_X1205) += rtc-x1205.o -+obj-$(CONFIG_RTC_DRV_XENON) += rtc-xenon.o - obj-$(CONFIG_RTC_DRV_XGENE) += rtc-xgene.o - obj-$(CONFIG_RTC_DRV_ZYNQMP) += rtc-zynqmp.o -diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c -index 9466474ff..565ff86e8 100644 ---- a/drivers/scsi/scsi_scan.c -+++ b/drivers/scsi/scsi_scan.c -@@ -654,6 +654,7 @@ static int scsi_probe_lun(struct scsi_device *sdev, unsigned char *inq_result, - memset(scsi_cmd, 0, 6); - scsi_cmd[0] = INQUIRY; - scsi_cmd[4] = (unsigned char) try_inquiry_len; -+ scsi_cmd[5] = 0xc0; /* HACK */ - - memset(inq_result, 0, try_inquiry_len); - -diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig -index 131a6a587..8c11aec2b 100644 ---- a/drivers/tty/serial/Kconfig -+++ b/drivers/tty/serial/Kconfig -@@ -1528,6 +1528,25 @@ config SERIAL_MILBEAUT_USIO_CONSOLE - receives all kernel messages and warnings and which allows logins in - single user mode). - -+config SERIAL_XENON -+ tristate "Xenon XBOX 360 serial port support" -+ select SERIAL_CORE -+ help -+ If you have an XBOX 360, you can enable its onboard -+ serial port by enabling this options. ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include + -+ To compile this driver as a module, choose M here: the -+ module will be called xenon_uart. ++#ifdef CONFIG_SMP ++#include ++#endif + -+config SERIAL_XENON_CONSOLE -+ bool "Console on XBOX 360 serial port" -+ depends on SERIAL_XENON=y -+ select SERIAL_CORE_CONSOLE -+ help -+ If you have enabled the serial port on the XBOX 360 ++#include ++#include ++#include ++#include ++#include ++#include + -+ you can make it the console by answering Y to this option. ++#include "interrupt.h" + - config SERIAL_LITEUART - tristate "LiteUART serial port support" - depends on HAS_IOMEM -diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile -index 7da0856cd..6659b3f64 100644 ---- a/drivers/tty/serial/Makefile -+++ b/drivers/tty/serial/Makefile -@@ -65,6 +65,7 @@ obj-$(CONFIG_SERIAL_GRLIB_GAISLER_APBUART) += apbuart.o - obj-$(CONFIG_SERIAL_ALTERA_JTAGUART) += altera_jtaguart.o - obj-$(CONFIG_SERIAL_VT8500) += vt8500_serial.o - obj-$(CONFIG_SERIAL_PCH_UART) += pch_uart.o -+obj-$(CONFIG_SERIAL_XENON) += xenon_uart.o - obj-$(CONFIG_SERIAL_MXS_AUART) += mxs-auart.o - obj-$(CONFIG_SERIAL_LANTIQ) += lantiq.o - obj-$(CONFIG_SERIAL_XILINX_PS_UART) += xilinx_uartps.o -diff --git a/drivers/video/fbdev/Kconfig b/drivers/video/fbdev/Kconfig -index 6ed5e608d..2164d4110 100644 ---- a/drivers/video/fbdev/Kconfig -+++ b/drivers/video/fbdev/Kconfig -@@ -659,6 +659,15 @@ config FB_N411 - This enables support for the Apollo display controller in its - Hecuba form using the n411 devkit. - -+config FB_XENOS -+ tristate "Xbox 360 Framebuffer Support" -+ depends on (FB = y) && PPC -+ select FB_CFB_FILLRECT -+ select FB_CFB_COPYAREA -+ select FB_CFB_IMAGEBLIT -+ help -+ This is the frame buffer device driver for the Microsoft Xbox 360. ++#define DEBUG ++#if defined(DEBUG) ++#define DBG udbg_printf ++#else ++#define DBG pr_debug ++#endif + - config FB_HGA - tristate "Hercules mono graphics support" - depends on FB && X86 -diff --git a/drivers/video/fbdev/Makefile b/drivers/video/fbdev/Makefile -index 477b9624b..2e64a4e20 100644 ---- a/drivers/video/fbdev/Makefile -+++ b/drivers/video/fbdev/Makefile ++static void *iic_base, // 00050000 ++ *bridge_base, // ea000000 ++ *biu, // e1000000 ++ *graphics; // ec800000 ++static struct irq_domain *host; ++ ++#define XENON_NR_IRQS 128 ++ ++#define PRIO_IPI_4 0x08 ++#define PRIO_IPI_3 0x10 ++#define PRIO_SMM 0x14 ++#define PRIO_SFCX 0x18 ++#define PRIO_SATA_HDD 0x20 ++#define PRIO_SATA_CDROM 0x24 ++#define PRIO_OHCI_0 0x2C ++#define PRIO_EHCI_0 0x30 ++#define PRIO_OHCI_1 0x34 ++#define PRIO_EHCI_1 0x38 ++#define PRIO_XMA 0x40 ++#define PRIO_AUDIO 0x44 ++#define PRIO_ENET 0x4C ++#define PRIO_XPS 0x54 ++#define PRIO_GRAPHICS 0x58 ++#define PRIO_PROFILER 0x60 ++#define PRIO_BIU 0x64 ++#define PRIO_IOC 0x68 ++#define PRIO_FSB 0x6C ++#define PRIO_IPI_2 0x70 ++#define PRIO_CLOCK 0x74 ++#define PRIO_IPI_1 0x78 ++#define PRIO_NONE 0x7C ++ ++/* ++ * Important interrupt registers (per CPU): ++ * ++ * 0x00: CPU_WHOAMI ++ * 0x08: CPU_CURRENT_TASK_PRI: only receive interrupts higher than this ++ * 0x10: CPU_IPI_DISPATCH_0 ++ * 0x18: unused(?) ++ * 0x20: ? (read changes) ++ * 0x28: ? (read changes) ++ * 0x30: ? (read changes) ++ * 0x38: same value as 0x20(?) (read changes) ++ * 0x40: unused(?) ++ * 0x48: unused(?) ++ * 0x50: ACK ++ * 0x58: ACK + set CPU_CURRENT_TASK_PRI ++ * 0x60: EOI ++ * 0x68: EOI + set CPU_CURRENT_TASK_PRI ++ * 0x70: interrupt MCACK? mask? max interrupt? CPU dies when writing stuff that isn't 0x7C ++ * 0xF0: ? ++ */ ++ ++/* CPU IRQ -> bridge (PCI) IRQ */ ++static const uint8_t xenon_pci_irq_map[] = { ++ /* 0x00 */ -1, ++ /* 0x04 */ -1, ++ /* PRIO_IPI_4 */ -1, ++ /* 0x0C */ -1, ++ /* PRIO_IPI_3 */ -1, ++ /* PRIO_SMM */ 3, ++ /* PRIO_SFCX */ 13, ++ /* 0x1C */ -1, ++ /* PRIO_SATA_HDD */ 2, ++ /* PRIO_SATA_CDROM */ 1, ++ /* 0x28 */ -1, ++ /* PRIO_OHCI_0 */ 4, ++ /* PRIO_EHCI_0 */ 5, ++ /* PRIO_OHCI_1 */ 6, ++ /* PRIO_EHCI_1 */ 7, ++ /* 0x3C */ -1, ++ /* PRIO_XMA */ 11, ++ /* PRIO_AUDIO */ 12, ++ /* 0x48 */ -1, ++ /* PRIO_ENET */ 10, ++ /* 0x50 */ -1, ++ /* PRIO_XPS */ -1, ++ /* PRIO_GRAPHICS */ -1, ++ /* 0x5C */ -1, ++ /* PRIO_PROFILER */ -1, ++ /* PRIO_BIU */ -1, ++ /* PRIO_IOC */ -1, ++ /* PRIO_FSB */ -1, ++ /* PRIO_IPI_2 */ -1, ++ /* PRIO_CLOCK */ 0, ++ /* PRIO_IPI_1 */ -1, ++ /* PRIO_NONE */ -1, ++}; ++ ++static void disconnect_pci_irq(int prio) ++{ ++ int i; ++ ++ printk(KERN_INFO "xenon IIC: disconnect irq 0x%.2X\n", prio); ++ ++ i = xenon_pci_irq_map[prio >> 2]; ++ if (i != -1) { ++ writel(0, bridge_base + 0x10 + i * 4); ++ } ++} ++ ++/* connects a PCI IRQ to a CPU */ ++static void connect_pci_irq(int prio, int target_cpu) ++{ ++ uint8_t i; ++ ++ printk(KERN_INFO "xenon IIC: connect irq 0x%.2X\n", prio); ++ ++ i = xenon_pci_irq_map[prio >> 2]; ++ if (i != -1) { ++ /* ++ * Bits: ++ * 0x00800000 = enable(?) ++ * 0x00200000 = latched ++ * 0x00003F00 = cpu target ++ * 0x00000080 = level sensitive ++ * 0x0000007F = CPU IRQ ++ */ ++ uint32_t bits = 0x00800080; ++ bits |= ((1 << target_cpu) & 0xFF) << 8; ++ bits |= (prio >> 2) & 0x3F; ++ ++ writel(bits, bridge_base + 0x10 + i * 4); ++ } ++} ++ ++static void iic_mask(struct irq_data *data) ++{ ++ disconnect_pci_irq(data->hwirq); ++} ++ ++static void iic_unmask(struct irq_data *data) ++{ ++ connect_pci_irq(data->hwirq, 0); ++} ++ ++static void xenon_ipi_send_mask(struct irq_data *data, ++ const struct cpumask *dest) ++{ ++ int cpu = hard_smp_processor_id(); ++ out_be64(iic_base + cpu * 0x1000 + 0x10, ++ ((cpumask_bits(dest)[0] << 16) & 0x3F) | (data->hwirq & 0x7C)); ++} ++ ++static struct irq_chip xenon_pic = { ++ .name = " XENON-PIC ", ++ .irq_mask = iic_mask, ++ .irq_unmask = iic_unmask, ++ .ipi_send_mask = xenon_ipi_send_mask, ++ .flags = 0, ++}; ++ ++void xenon_init_irq_on_cpu(int cpu) ++{ ++ printk(KERN_INFO "xenon IIC: init on cpu %i\n", cpu); ++ ++ /* init that cpu's interrupt controller */ ++ out_be64(iic_base + cpu * 0x1000 + 0x70, 0x7C); ++ out_be64(iic_base + cpu * 0x1000 + 0x08, 0); /* Set priority to 0 */ ++ out_be64(iic_base + cpu * 0x1000, 1 << cpu); /* "who am i" */ ++ ++ /* read in and ack all outstanding interrupts */ ++ while (in_be64(iic_base + cpu * 0x1000 + 0x50) != PRIO_NONE); ++ out_be64(iic_base + cpu * 0x1000 + 0x68, 0); /* EOI and set priority to 0 */ ++} ++ ++/* Get an IRQ number from the pending state register of the IIC */ ++static unsigned int iic_get_irq(void) ++{ ++ int cpu = hard_smp_processor_id(); ++ void *my_iic_base; ++ int index; ++ ++ my_iic_base = iic_base + cpu * 0x1000; ++ ++ /* read destructive pending interrupt */ ++ index = in_be64(my_iic_base + 0x50) & 0x7C; ++ out_be64(my_iic_base + 0x60, 0x0); /* EOI this interrupt. */ ++ ++ /* HACK: we will handle some (otherwise unhandled) interrupts here ++ to prevent them flooding. */ ++ switch (index) { ++ case PRIO_GRAPHICS: ++ writel(0, graphics + 0xed0); // RBBM_INT_CNTL ++ writel(0, graphics + 0x6540); // R500_DxMODE_INT_MASK ++ break; ++ case PRIO_IOC: ++ writel(0, biu + 0x4002c); ++ break; ++ case PRIO_CLOCK: ++ writel(0, bridge_base + 0x106C); ++ break; ++ default: ++ break; ++ } ++ ++ /* No interrupt. This really shouldn't happen. */ ++ if (index == PRIO_NONE) { ++ return NO_IRQ; ++ } ++ ++ return irq_linear_revmap(host, index); ++} ++ ++static int xenon_irq_host_map(struct irq_domain *h, unsigned int virq, ++ irq_hw_number_t hw) ++{ ++ irq_set_chip_and_handler(virq, &xenon_pic, handle_percpu_irq); ++ return 0; ++} ++ ++static int xenon_irq_host_match(struct irq_domain *h, struct device_node *node, ++ enum irq_domain_bus_token bus_token) ++{ ++ return h->host_data != NULL && node == h->host_data; ++} ++ ++static const struct irq_domain_ops xenon_irq_host_ops = { ++ .map = xenon_irq_host_map, ++ .match = xenon_irq_host_match, ++}; ++ ++void __init xenon_iic_init_IRQ(void) ++{ ++ int i; ++ struct device_node *dn; ++ struct resource res; ++ ++ printk(KERN_DEBUG "xenon IIC: init\n"); ++ /* search for our interrupt controller inside the device tree */ ++ for (dn = NULL; ++ (dn = of_find_node_by_name(dn, "interrupt-controller")) != NULL;) { ++ if (!of_device_is_compatible(dn, "xenon")) ++ continue; ++ ++ if (of_address_to_resource(dn, 0, &res)) ++ { ++ printk(KERN_WARNING "xenon IIC: Can't resolve addresses\n"); ++ of_node_put(dn); ++ return; ++ } ++ ++ iic_base = ioremap(res.start, 0x10000); ++ ++ host = irq_domain_add_linear(NULL, XENON_NR_IRQS, &xenon_irq_host_ops, NULL); ++ host->host_data = of_node_get(dn); ++ BUG_ON(host == NULL); ++ irq_set_default_host(host); ++ } ++ ++ ppc_md.get_irq = iic_get_irq; ++ ++ bridge_base = ioremap(0xea000000, 0x10000); ++ biu = ioremap(0xe1000000, 0x2000000); ++ graphics = ioremap(0xec800000, 0x10000); ++ ++ /* initialize interrupts */ ++ writel(0, bridge_base); ++ writel(0x40000000, bridge_base + 4); ++ ++ writel(0x40000000, biu + 0x40074); ++ writel(0xea000050, biu + 0x40078); ++ ++ writel(0, bridge_base + 0xc); /* Interrupt mask register */ ++ writel(0x3, bridge_base); ++ ++ /* disconnect all PCI IRQs until they are requested */ ++ for (i=0; i<0x10; ++i) ++ writel(0, bridge_base + 0x10 + i * 4); ++ ++ xenon_init_irq_on_cpu(0); ++} ++ ++#ifdef CONFIG_SMP ++ ++static int ipi_to_prio(int ipi) ++{ ++ switch (ipi) { ++ case PPC_MSG_NMI_IPI: ++ return PRIO_IPI_1; ++ break; ++ case PPC_MSG_CALL_FUNCTION: ++ return PRIO_IPI_2; ++ break; ++ case PPC_MSG_RESCHEDULE: ++ return PRIO_IPI_3; ++ break; ++ case PPC_MSG_TICK_BROADCAST: ++ return PRIO_IPI_4; ++ break; ++ default: ++ printk("unhandled ipi %d\n", ipi); ++ BUG(); ++ } ++ return 0; ++} ++ ++void xenon_cause_IPI(int target_cpu, int msg) ++{ ++ int ipi_prio; ++ int cpu = hard_smp_processor_id(); ++ ++ ipi_prio = ipi_to_prio(msg); ++ out_be64(iic_base + cpu * 0x1000 + 0x10, (0x10000 << target_cpu) | ipi_prio); ++} ++ ++static void xenon_request_ipi(int ipi) ++{ ++ int virq; ++ int prio = ipi_to_prio(ipi); ++ ++ virq = irq_create_mapping(host, prio); ++ if (virq == NO_IRQ) { ++ printk(KERN_ERR "xenon_request_ipi: failed to map IPI%d (%s)\n", ++ prio, smp_ipi_name[ipi]); ++ return; ++ } ++ ++ if (smp_request_message_ipi(virq, ipi)) ++ irq_dispose_mapping(virq); ++} ++ ++void xenon_request_IPIs(void) ++{ ++ xenon_request_ipi(PPC_MSG_TICK_BROADCAST); ++ xenon_request_ipi(PPC_MSG_CALL_FUNCTION); ++ xenon_request_ipi(PPC_MSG_RESCHEDULE); ++ xenon_request_ipi(PPC_MSG_NMI_IPI); ++} ++ ++#endif +diff --git a/arch/powerpc/platforms/xenon/interrupt.h b/arch/powerpc/platforms/xenon/interrupt.h +new file mode 100644 +index 000000000..9eed5dafe +--- /dev/null ++++ b/arch/powerpc/platforms/xenon/interrupt.h +@@ -0,0 +1,9 @@ ++#ifndef XENON_INTERRUPT_H ++#define XENON_INTERRUPT_H ++ ++extern void xenon_init_irq_on_cpu(int cpu); ++extern void __init xenon_iic_init_IRQ(void); ++extern void xenon_cause_IPI(int target, int msg); ++extern void xenon_request_IPIs(void); ++ ++#endif /* ASM_XENON_PIC_H */ +diff --git a/arch/powerpc/platforms/xenon/pci.c b/arch/powerpc/platforms/xenon/pci.c +new file mode 100644 +index 000000000..69b0b216c +--- /dev/null ++++ b/arch/powerpc/platforms/xenon/pci.c +@@ -0,0 +1,306 @@ ++/* ++ * Xenon PCI support ++ * Maintained by: Felix Domke ++ * Minor modification by: wolie ++ * based on: ++ * Copyright (C) 2004 Benjamin Herrenschmuidt (benh@kernel.crashing.org), ++ * IBM Corp. ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License ++ * as published by the Free Software Foundation; either version ++ * 2 of the License, or (at your option) any later version. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#ifdef DEBUG ++#define DBG(x...) printk(x) ++#else ++#define DBG(x...) ++#endif ++ ++#define OFFSET(bus, slot, func) \ ++ ((((bus) << 8) + PCI_DEVFN(slot, func)) << 12) ++ ++static int xenon_pci_read_config(struct pci_bus *bus, unsigned int devfn, ++ int offset, int len, u32 *val) ++{ ++ struct pci_controller *hose; ++ unsigned int slot = PCI_SLOT(devfn); ++ unsigned int func = PCI_FUNC(devfn); ++ void* addr; ++ ++ hose = pci_bus_to_host(bus); ++ if (hose == NULL) ++ return PCIBIOS_DEVICE_NOT_FOUND; ++ ++ DBG("xenon_pci_read_config, slot %d, func %d\n", slot, func); ++ ++#if 0 ++ if (PCI_SLOT(devfn) >= 32) ++ return PCIBIOS_DEVICE_NOT_FOUND; ++ if (PCI_SLOT(devfn) == 3) ++ return PCIBIOS_DEVICE_NOT_FOUND; ++ if (PCI_SLOT(devfn) == 6) ++ return PCIBIOS_DEVICE_NOT_FOUND; ++ if (PCI_SLOT(devfn) == 0xB) ++ return PCIBIOS_DEVICE_NOT_FOUND; ++ if (PCI_FUNC(devfn) >= 2) ++ return PCIBIOS_DEVICE_NOT_FOUND; ++#endif ++ DBG("xenon_pci_read_config, %p, devfn=%d, offset=%d, len=%d\n", bus, devfn, offset, len); ++ ++ addr = ((void*)hose->cfg_addr) + offset; ++ ++ /* map GPU to slot 0x0f */ ++ if (slot == 0x0f) ++ addr += OFFSET(0, 0x02, func); ++ else ++ addr += OFFSET(1, slot, func); ++ ++ /* ++ * Note: the caller has already checked that offset is ++ * suitably aligned and that len is 1, 2 or 4. ++ */ ++ switch (len) { ++ case 1: ++ *val = in_8((u8 *)addr); ++ break; ++ case 2: ++ *val = in_le16((u16 *)addr); ++ break; ++ default: ++ *val = in_le32((u32 *)addr); ++ break; ++ } ++ DBG("->%08x\n", (int)*val); ++ return PCIBIOS_SUCCESSFUL; ++} ++ ++static int xenon_pci_write_config(struct pci_bus *bus, unsigned int devfn, ++ int offset, int len, u32 val) ++{ ++ struct pci_controller *hose; ++ unsigned int slot = PCI_SLOT(devfn); ++ unsigned int func = PCI_FUNC(devfn); ++ void *addr; ++ ++ hose = pci_bus_to_host(bus); ++ if (hose == NULL) ++ return PCIBIOS_DEVICE_NOT_FOUND; ++ ++ DBG("xenon_pci_write_config, slot %d, func %d\n", slot, func); ++ ++ if (PCI_SLOT(devfn) >= 32) ++ return PCIBIOS_DEVICE_NOT_FOUND; ++#if 0 ++ if (PCI_SLOT(devfn) == 3) ++ return PCIBIOS_DEVICE_NOT_FOUND; ++#endif ++ DBG("xenon_pci_write_config, %p, devfn=%d, offset=%x, len=%d, val=%08x\n", bus, devfn, offset, len, val); ++ ++ addr = ((void*)hose->cfg_addr) + offset; ++ ++ /* map GPU to slot 0x0f */ ++ if (slot == 0x0f) ++ addr += OFFSET(0, 0x02, func); ++ else ++ addr += OFFSET(1, slot, func); ++ ++ if (len == 4) ++ DBG("was: %08x\n", readl(addr)); ++ if (len == 2) ++ DBG("was: %04x\n", readw(addr)); ++ if (len == 1) ++ DBG("was: %02x\n", readb(addr)); ++ /* ++ * Note: the caller has already checked that offset is ++ * suitably aligned and that len is 1, 2 or 4. ++ */ ++ switch (len) { ++ case 1: ++ writeb(val, addr); ++ break; ++ case 2: ++ writew(val, addr); ++ break; ++ default: ++ writel(val, addr); ++ break; ++ } ++ return PCIBIOS_SUCCESSFUL; ++} ++ ++static struct pci_ops xenon_pci_ops = ++{ ++ .read = xenon_pci_read_config, ++ .write = xenon_pci_write_config, ++}; ++ ++ ++#if 1 ++void __init xenon_pci_init(void) ++{ ++ struct pci_controller *hose; ++ struct device_node *np, *root; ++ struct device_node *dev = NULL; ++ ++ root = of_find_node_by_path("/"); ++ if (root == NULL) { ++ printk(KERN_CRIT "xenon_pci_init: can't find root of device tree\n"); ++ return; ++ } ++ for (np = NULL; (np = of_get_next_child(root, np)) != NULL;) { ++ if (np->name == NULL) ++ continue; ++ // printk("found node %p %s\n", np, np->name); ++ if (strcmp(np->name, "pci") == 0) { ++ of_node_get(np); ++ dev = np; ++ } ++ } ++ of_node_put(root); ++ ++ if (!dev) ++ { ++ printk("couldn't find PCI node!\n"); ++ return; ++ } ++ ++ hose = pcibios_alloc_controller(dev); ++ if (hose == NULL) ++ { ++ printk("pcibios_alloc_controller failed!\n"); ++ return; ++ } ++ ++ hose->first_busno = 0; ++ hose->last_busno = 1; ++ ++ hose->ops = &xenon_pci_ops; ++ hose->cfg_addr = ioremap(0xd0000000, 0x1000000); ++ ++ pci_process_bridge_OF_ranges(hose, dev, 1); ++ ++// of_rescan_bus(root, ci_bus *bus) ++ ++ /* Tell pci.c to not change any resource allocations. */ ++ pci_set_flags(PCI_PROBE_ONLY); ++ ++ of_node_put(dev); ++ DBG("PCI initialized\n"); ++ ++ pci_io_base = 0; ++ ++ // pcibios_scan_phb(hose, dev); ++ set_pci_dma_ops(&dma_iommu_ops); ++} ++ ++#else ++ ++ ++static int __init xenon_add_bridge(struct device_node *dev) ++{ ++ int len; ++ struct pci_controller *hose; ++ struct resource rsrc; ++ char *disp_name; ++ const int *bus_range; ++ int primary = 1, has_address = 0; ++ ++ printk(KERN_DEBUG "Adding PCI host bridge %s\n", dev->full_name); ++ ++ /* Fetch host bridge registers address */ ++ has_address = (of_address_to_resource(dev, 0, &rsrc) == 0); ++ ++ /* Get bus range if any */ ++ bus_range = of_get_property(dev, "bus-range", &len); ++ if (bus_range == NULL || len < 2 * sizeof(int)) { ++ printk(KERN_WARNING "Can't get bus-range for %s, assume" ++ " bus 0\n", dev->full_name); ++ } ++ ++ hose = pcibios_alloc_controller(dev); ++ if (!hose) ++ return -ENOMEM; ++ hose->first_busno = bus_range ? bus_range[0] : 0; ++ hose->last_busno = bus_range ? bus_range[1] : 0xff; ++ ++ hose->ops = &xenon_pci_ops; ++ ++ /* FIXME: should come from config */ ++ hose->cfg_addr = ioremap(0xd0000000, 0x1000000); ++ ++ disp_name = NULL; ++ ++ printk(KERN_INFO "Found %s PCI host bridge at 0x%016llx. " ++ "Firmware bus number: %d->%d\n", ++ disp_name, (unsigned long long)rsrc.start, hose->first_busno, ++ hose->last_busno); ++ ++ printk(KERN_DEBUG " ->Hose at 0x%p, cfg_addr=0x%p,cfg_data=0x%p\n", ++ hose, hose->cfg_addr, hose->cfg_data); ++ ++ /* Interpret the "ranges" property */ ++ /* This also maps the I/O region and sets isa_io/mem_base */ ++ pci_process_bridge_OF_ranges(hose, dev, primary); ++ ++ /* Fixup "bus-range" OF property */ ++ // fixup_bus_range(dev); ++ ++ return 0; ++} ++ ++void __init xenon_pci_init(void) ++{ ++ struct device_node *np, *root; ++ ++ ppc_pci_set_flags(PPC_PCI_CAN_SKIP_ISA_ALIGN); ++ ++ root = of_find_node_by_path("/"); ++ if (root == NULL) { ++ printk(KERN_CRIT "xenon_pci_init: can't find root " ++ "of device tree\n"); ++ return; ++ } ++ for (np = NULL; (np = of_get_next_child(root, np)) != NULL;) { ++ if (np->name == NULL) ++ continue; ++ if (strcmp(np->name, "pci") == 0) { ++ if (xenon_add_bridge(np) == 0) ++ of_node_get(np); ++ } ++ } ++ of_node_put(root); ++ ++ /* Setup the linkage between OF nodes and PHBs */ ++ pci_devs_phb_init(); ++ ++ ++ /* We can allocate missing resources if any */ ++ pci_probe_only = 0; ++ pci_probe_only = 1; ++ ++ /* do we need that? */ ++ pci_io_base = 0; ++ ++ /* do we need that? */ ++ ppc_md.pci_dma_dev_setup = NULL; ++ ppc_md.pci_dma_bus_setup = NULL; ++ set_pci_dma_ops(&dma_iommu_ops); ++} ++ ++#endif +\ No newline at end of file +diff --git a/arch/powerpc/platforms/xenon/pci.h b/arch/powerpc/platforms/xenon/pci.h +new file mode 100644 +index 000000000..0fea60797 +--- /dev/null ++++ b/arch/powerpc/platforms/xenon/pci.h +@@ -0,0 +1,6 @@ ++#ifndef XENON_PCI_H ++#define XENON_PCI_H ++ ++extern void __init xenon_pci_init(void); ++ ++#endif +diff --git a/arch/powerpc/platforms/xenon/setup.c b/arch/powerpc/platforms/xenon/setup.c +new file mode 100644 +index 000000000..63abe42e3 +--- /dev/null ++++ b/arch/powerpc/platforms/xenon/setup.c +@@ -0,0 +1,169 @@ ++/* ++ * linux/arch/powerpc/platforms/xenon/xenon_setup.c ++ * ++ * Maintained by: Felix Domke ++ * Minor modification by: wolie ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License ++ * as published by the Free Software Foundation; either version ++ * 2 of the License, or (at your option) any later version. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include "interrupt.h" ++#include "pci.h" ++#include "smp.h" ++ ++#ifdef CONFIG_PPC_EARLY_DEBUG_XENON ++void udbg_init_xenon_virtual(void); ++#endif ++ ++static int xenon_early_init(void) ++{ ++ // xenon_smc_early_led(0x01, 0x60); ++ printk("%s\n", __func__); ++ return 0; ++} ++machine_early_initcall(xenon, xenon_early_init); ++ ++static void xenon_show_cpuinfo(struct seq_file *m) ++{ ++ struct device_node *root; ++ const char *model = ""; ++ ++ root = of_find_node_by_path("/"); ++ if (root) ++ model = of_get_property(root, "model", NULL); ++ seq_printf(m, "machine\t\t: %s\n", model); ++ of_node_put(root); ++} ++ ++static void __init xenon_init_irq(void) ++{ ++ xenon_iic_init_IRQ(); ++} ++ ++static void __init xenon_setup_arch(void) ++{ ++#ifdef CONFIG_SMP ++ smp_init_xenon(); ++#endif ++ /* init to some ~sane value until calibrate_delay() runs */ ++ loops_per_jiffy = 50000000; ++ ++ if (ROOT_DEV == 0) ++ ROOT_DEV = Root_SDA1; ++ ++ xenon_pci_init(); ++#ifdef CONFIG_DUMMY_CONSOLE ++ conswitchp = &dummy_con; ++#endif ++} ++ ++int xenon_smc_message(void *msg); ++void xenon_smc_restart(void); ++ ++static void xenon_panic(char *str) ++{ ++ // show a red ring ++ unsigned char msg[16] = {0x99, 0x01, 0x0F, 0}; ++ xenon_smc_message(msg); ++ ++ smp_send_stop(); ++ printk("\n"); ++ printk(" System does not reboot automatically.\n"); ++ printk(" Please press POWER button.\n"); ++ printk("\n"); ++ ++ local_irq_disable(); ++ while (1); ++} ++ ++static void __noreturn xenon_restart(char *cmd) ++{ ++ printk(" System restart ... \n"); ++ ++ smp_send_stop(); ++ xenon_smc_restart(); ++ ++ local_irq_disable(); ++ while (1); ++} ++ ++void xenon_smc_power_off(void); ++ ++static void xenon_power_off(void) ++{ ++ printk(" System power off ... \n"); ++ ++ smp_send_stop(); ++ xenon_smc_power_off(); ++ ++ local_irq_disable(); ++ while (1); ++} ++ ++void xenon_smc_halt(void); ++ ++static void __noreturn xenon_halt(void) ++{ ++ printk(" System halt ... \n"); ++ ++ smp_send_stop(); ++ xenon_smc_halt(); ++ ++ local_irq_disable(); ++ while (1); ++} ++ ++static int __init xenon_probe(void) ++{ ++ if (!of_machine_is_compatible("XENON")) { ++ return 0; ++ } ++ ++#ifdef CONFIG_PPC_EARLY_DEBUG_XENON ++ udbg_init_xenon_virtual(); ++#endif ++ ++ hpte_init_native(); ++ pm_power_off = xenon_power_off; ++ ++ return 1; ++} ++ ++#if 0 ++static int xenon_check_legacy_ioport(unsigned int baseport) ++{ ++ return -ENODEV; ++} ++#endif ++ ++define_machine(xenon) { ++ .name = "Xenon", ++ .probe = xenon_probe, ++ .setup_arch = xenon_setup_arch, ++ .show_cpuinfo = xenon_show_cpuinfo, ++ .calibrate_decr = generic_calibrate_decr, ++ .init_IRQ = xenon_init_irq, ++ .panic = xenon_panic, ++ .restart = xenon_restart, ++ .halt = xenon_halt, ++#if 0 && defined(CONFIG_KEXEC) ++ .machine_kexec = default_machine_kexec, ++ .machine_kexec_prepare = default_machine_kexec_prepare, ++ .machine_crash_shutdown = default_machine_crash_shutdown, ++#endif ++}; +diff --git a/arch/powerpc/platforms/xenon/smp.c b/arch/powerpc/platforms/xenon/smp.c +new file mode 100644 +index 000000000..3416c5f66 +--- /dev/null ++++ b/arch/powerpc/platforms/xenon/smp.c +@@ -0,0 +1,81 @@ ++/* ++ * SMP support for Xenon machines. ++ * ++ * Based on CBE's smp.c. ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License ++ * as published by the Free Software Foundation; either version ++ * 2 of the License, or (at your option) any later version. ++ */ ++ ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++#include "interrupt.h" ++ ++#define DEBUG ++#if defined(DEBUG) ++#define DBG udbg_printf ++#else ++#define DBG pr_debug ++#endif ++ ++extern int boot_cpuid; ++ ++static void __init smp_xenon_probe(void) ++{ ++ xenon_request_IPIs(); ++} ++ ++static void smp_xenon_setup_cpu(int cpu) ++{ ++ /* Boot CPU IRQs are already initialized at this point in ++ * xenon_iic_init_IRQ */ ++ if (cpu != boot_cpuid) ++ xenon_init_irq_on_cpu(cpu); ++} ++ ++static int smp_xenon_cpu_bootable(unsigned int nr) ++{ ++ /* Special case - we inhibit secondary thread startup ++ * during boot if the user requests it. Odd-numbered ++ * cpus are assumed to be secondary threads. ++ */ ++ if (system_state < SYSTEM_RUNNING && cpu_has_feature(CPU_FTR_SMT) ++ && !smt_enabled_at_boot && nr % 2 != 0) ++ return 0; ++ ++ return 1; ++} ++ ++static void smp_xenon_message_pass(int cpu, int msg) ++{ ++ xenon_cause_IPI(cpu, msg); ++} ++ ++static struct smp_ops_t xenon_smp_ops = { ++ .probe = smp_xenon_probe, ++ .message_pass = smp_xenon_message_pass, ++#ifdef CONFIG_HOTPLUG_CPU ++ .cpu_die = generic_cpu_die, ++#endif ++ .kick_cpu = smp_generic_kick_cpu, ++ .setup_cpu = smp_xenon_setup_cpu, ++ .cpu_bootable = smp_xenon_cpu_bootable, ++}; ++ ++/* This is called very early */ ++void __init smp_init_xenon(void) ++{ ++ pr_debug(" -> smp_init_xenon()\n"); ++ ++ smp_ops = &xenon_smp_ops; ++ ++ pr_debug(" <- smp_init_xenon()\n"); ++} +diff --git a/arch/powerpc/platforms/xenon/smp.h b/arch/powerpc/platforms/xenon/smp.h +new file mode 100644 +index 000000000..900af84ae +--- /dev/null ++++ b/arch/powerpc/platforms/xenon/smp.h +@@ -0,0 +1,8 @@ ++#ifndef XENON_SMP_H ++#define XENON_SMP_H ++ ++#ifdef CONFIG_SMP ++extern void smp_init_xenon(void); ++#endif ++ ++#endif +diff --git a/arch/powerpc/platforms/xenon/time.c b/arch/powerpc/platforms/xenon/time.c +new file mode 100644 +index 000000000..247079ec3 +--- /dev/null ++++ b/arch/powerpc/platforms/xenon/time.c +@@ -0,0 +1,36 @@ ++/* ++ * Xenon time and rtc routines. ++ * ++ * Copyright (C) 2010 Herbert Poetzl ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; version 2 of the License. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++#include ++#include ++#include ++#include ++ ++static int __init xenon_rtc_init(void) ++{ ++ struct platform_device *pdev; ++ ++ pdev = platform_device_register_simple("rtc-xenon", -1, NULL, 0); ++ if (IS_ERR(pdev)) ++ return PTR_ERR(pdev); ++ ++ return 0; ++} ++ ++module_init(xenon_rtc_init); +\ No newline at end of file +diff --git a/arch/powerpc/platforms/xenon/xe_udbg.c b/arch/powerpc/platforms/xenon/xe_udbg.c +new file mode 100644 +index 000000000..98dcddbb0 +--- /dev/null ++++ b/arch/powerpc/platforms/xenon/xe_udbg.c +@@ -0,0 +1,162 @@ ++/* ++ * xe_udbg.c: Early debug console via framebuffer ++ * ++ * Copyright 2017 Justin Moore ++ * ++ * Licensed under the GPL v2. ++ */ ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++// ======================================================================== ++// ======================================================================== ++ ++typedef struct console_context { ++ void __iomem *fb; ++ uint32_t width; ++ uint32_t height; ++ ++ uint32_t cursor_x; ++ uint32_t cursor_y; ++} console_context_t; ++static console_context_t console_ctx; ++ ++static void console_clrscr(console_context_t *context) { ++ unsigned int *fb = (unsigned int *)context->fb; ++ int count = context->width * context->height; ++ while (count--) out_be32(fb++, 0x00000000); ++ ++ context->cursor_x = 0; ++ context->cursor_y = 0; ++} ++ ++/* set a pixel to RGB values, must call console_init() first */ ++static inline void console_pset32(console_context_t *context, int x, int y, ++ int color) { ++ uint32_t *fb = ((uint32_t *)context->fb); ++#define base \ ++ (((y >> 5) * 32 * context->width + ((x >> 5) << 10) + (x & 3) + \ ++ ((y & 1) << 2) + (((x & 31) >> 2) << 3) + (((y & 31) >> 1) << 6)) ^ \ ++ ((y & 8) << 2)) ++ fb[base] = color; ++#undef base ++} ++ ++static inline void console_pset(console_context_t *context, int x, int y, ++ unsigned char r, unsigned char g, ++ unsigned char b) { ++ console_pset32(context, x, y, (b << 24) + (g << 16) + (r << 8)); ++} ++ ++static void console_draw_char(console_context_t *context, ++ const uint8_t *fontdata_8x16, const int x, ++ const int y, const unsigned char c) { ++#define font_pixel(ch, x, y) ((fontdata_8x16[ch * 16 + y] >> (7 - x)) & 1) ++ int lx, ly; ++ for (ly = 0; ly < 16; ly++) { ++ for (lx = 0; lx < 8; lx++) { ++ console_pset32(context, x + lx, y + ly, ++ font_pixel(c, lx, ly) == 1 ? 0xFFFFFF00 : 0x00000000); ++ } ++ } ++#undef font_pixel ++} ++ ++static void console_scroll32(console_context_t *context, ++ const unsigned int lines) { ++ int l, bs; ++ uint32_t *fb, *end; ++ uint32_t console_size = context->width * context->height; ++ ++ bs = context->width * 32 * 4; ++ // copy all tile blocks to a higher position ++ for (l = lines; l * 32 < context->height; l++) { ++ memcpy(context->fb + bs * (l - lines), context->fb + bs * l, bs); ++ } ++ ++ // fill up last lines with background color ++ fb = (uint32_t *)(context->fb + console_size * 4 - bs * lines); ++ end = (uint32_t *)(context->fb + console_size * 4); ++ memset(fb, 0x00000000, (end - fb) * 4); ++} ++ ++static void console_newline(console_context_t *context) { ++ /* reset to the left and flush line */ ++ context->cursor_x = 0; ++ context->cursor_y++; ++ ++ if (context->cursor_y >= ((context->height - 32) / 16)) { ++ console_scroll32(context, 1); ++ context->cursor_y -= 2; ++ } ++} ++ ++static void console_putch(const char c) { ++ if (!console_ctx.fb) return; ++ ++ if (c == '\r') { ++ console_ctx.cursor_x = 0; ++ } else if (c == '\n') { ++ console_newline(&console_ctx); ++ } else { ++ console_draw_char(&console_ctx, font_vga_8x16.data, ++ console_ctx.cursor_x * 8 + 32, ++ console_ctx.cursor_y * 16 + 32, c); ++ console_ctx.cursor_x++; ++ if (console_ctx.cursor_x >= (console_ctx.width - 32) / 8) ++ console_newline(&console_ctx); ++ } ++} ++ ++// ======================================================================== ++// ======================================================================== ++ ++void __init udbg_init_xenon(void) { ++ /* ++ * 148x41 ++ * Since we're running in real mode now, we can't enable logging until ++ * we reach virtual mode. Just set up our structure and clear the ++ * screen. This depends on XeLL running before us, and it having already ++ * set up the screen. ++ */ ++ memset(&console_ctx, 0, sizeof(console_context_t)); ++ console_ctx.fb = (void *)0x1E000000ull; ++ console_ctx.width = ((1280 + 31) >> 5) << 5; ++ console_ctx.height = ((720 + 31) >> 5) << 5; ++ console_clrscr(&console_ctx); ++ // udbg_putc = console_putch; ++} ++ ++void __init udbg_init_xenon_virtual(void) { ++ void __iomem *framebuffer = ioremap(0x1E000000, 0x01FFFFFF); ++ if (framebuffer) { ++ console_ctx.fb = framebuffer; ++ udbg_putc = console_putch; ++ } ++} ++EXPORT_SYMBOL(udbg_init_xenon_virtual); ++ ++void udbg_shutdown_xenon(void) { ++ if (console_ctx.fb) { ++ // cannot iounmap early bolted memory ++ // iounmap(console_ctx.fb); ++ console_ctx.fb = NULL; ++ } ++ ++ if (udbg_putc == NULL) { ++ return; ++ } ++ ++ udbg_putc = NULL; ++} ++EXPORT_SYMBOL(udbg_shutdown_xenon); +\ No newline at end of file +diff --git a/drivers/Makefile b/drivers/Makefile +index a110338c8..feccef1d1 100644 +--- a/drivers/Makefile ++++ b/drivers/Makefile +@@ -138,6 +138,7 @@ obj-y += clocksource/ + obj-$(CONFIG_DCA) += dca/ + obj-$(CONFIG_HID) += hid/ + obj-$(CONFIG_PPC_PS3) += ps3/ ++obj-$(CONFIG_PPC_XENON) += xenon/ + obj-$(CONFIG_OF) += of/ + obj-$(CONFIG_SSB) += ssb/ + obj-$(CONFIG_BCMA) += bcma/ +diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig +index a7da8ea7b..656ff2943 100644 +--- a/drivers/ata/Kconfig ++++ b/drivers/ata/Kconfig +@@ -525,6 +525,14 @@ config SATA_SVW + + If unsure, say N. + ++config SATA_XENON ++ tristate "Xenon SATA support" ++ depends on PCI ++ help ++ This option enables support for Xenon southbridge. ++ ++ If unsure, say N. ++ + config SATA_ULI + tristate "ULi Electronics SATA support" + depends on PCI +diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile +index b8aebfb14..95525b108 100644 +--- a/drivers/ata/Makefile ++++ b/drivers/ata/Makefile +@@ -13,6 +13,7 @@ obj-$(CONFIG_SATA_INIC162X) += sata_inic162x.o + obj-$(CONFIG_SATA_SIL24) += sata_sil24.o + obj-$(CONFIG_SATA_DWC) += sata_dwc_460ex.o + obj-$(CONFIG_SATA_HIGHBANK) += sata_highbank.o libahci.o ++obj-$(CONFIG_SATA_XENON) += sata_xenon.o + obj-$(CONFIG_AHCI_BRCM) += ahci_brcm.o libahci.o libahci_platform.o + obj-$(CONFIG_AHCI_CEVA) += ahci_ceva.o libahci.o libahci_platform.o + obj-$(CONFIG_AHCI_DA850) += ahci_da850.o libahci.o libahci_platform.o +diff --git a/drivers/ata/sata_xenon.c b/drivers/ata/sata_xenon.c +new file mode 100644 +index 000000000..a6e6f3786 +--- /dev/null ++++ b/drivers/ata/sata_xenon.c +@@ -0,0 +1,252 @@ ++/* ++ * sata_xenon.c - SATA support for xenon southbridge ++ * ++ * based on sata_sis.c, modifications by Felix Domke ++ * minor modification by: wolie ++ * ++ * Please ALWAYS copy linux-ide@vger.kernel.org ++ * on emails. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2, or (at your option) ++ * any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; see the file COPYING. If not, write to ++ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ * ++ * libata documentation is available via 'make {ps|pdf}docs', ++ * as Documentation/DocBook/libata.* ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define DRV_NAME "sata_xenon" ++#define DRV_VERSION "0.1.1" ++ ++ /* small note: it's completely unknown whether the xenon southbridge sata ++ is really based on SiS technology. ++ Most of SATA is standardized anyway. ++ ++ ++ So, we have these two pci devices, one for each port. ++ ++ They have two BARs, one for the IDE registers (0..7, ++ altstatus/devctl is +0xA), and one for the BMDMA. ++ ++ SCR seem to be sis-like in pci config space, but that should ++ be verified! ++ ++ Note on the DVD-ROM part: ++ ++ The drives usually require some tweaks to be usable under linux. ++ ++ You either need to hack the scsi layer, or, in case of the GDR3120L, ++ set 'modeB' in the bootloader. ++ */ ++ ++enum { ++ /* PCI configuration registers */ ++ SIS_SCR_BASE = 0xc0, /* sata0 phy SCR registers */ ++}; ++ ++static int xenon_init_one (struct pci_dev *pdev, const struct pci_device_id *ent); ++static int xenon_scr_read (struct ata_link *link, unsigned int sc_reg, u32 *val); ++static int xenon_scr_write (struct ata_link *link, unsigned int sc_reg, u32 val);//void ++static void xenon_bmdma_error_handler(struct ata_port *ap); ++ ++static const struct pci_device_id xenon_pci_tbl[] = { ++ { PCI_VDEVICE(MICROSOFT, 0x5803), 0 }, ++ /* { PCI_VDEVICE(MICROSOFT, 0x5802), 0 }, */ ++ ++ { } /* terminate list */ ++}; ++ ++static struct pci_driver xenon_pci_driver = { ++ .name = DRV_NAME, ++ .id_table = xenon_pci_tbl, ++ .probe = xenon_init_one, ++ .remove = ata_pci_remove_one, ++}; ++ ++static struct scsi_host_template xenon_sht = { ++ ATA_BMDMA_SHT(DRV_NAME), ++}; ++ ++static struct ata_port_operations xenon_ops = { ++ .inherits = &ata_bmdma_port_ops, ++// .lost_interrupt = ATA_OP_NULL, ++ .error_handler = xenon_bmdma_error_handler, ++ .scr_read = xenon_scr_read, ++ .scr_write = xenon_scr_write, ++}; ++ ++static const struct ata_port_info xenon_port_info = { ++ .flags = ATA_FLAG_SATA, ++ .pio_mask = ATA_PIO4, ++ .mwdma_mask = ATA_MWDMA2, ++ .udma_mask = ATA_UDMA6, //0x7F ++ .port_ops = &xenon_ops, ++// .irq_handler = ata_interrupt, ++// .private_data = NULL ++}; ++ ++ ++MODULE_DESCRIPTION("low-level driver for Xenon Southbridge SATA controller"); ++MODULE_LICENSE("GPL"); ++MODULE_DEVICE_TABLE(pci, xenon_pci_tbl); ++MODULE_VERSION(DRV_VERSION); ++ ++static unsigned int get_scr_cfg_addr(unsigned int sc_reg) ++{ ++ if ((sc_reg > SCR_CONTROL) || (sc_reg == SCR_ERROR)) /* doesn't exist in PCI cfg space */ ++ return -1; ++ ++ return SIS_SCR_BASE + (4 * sc_reg); ++ ++} ++ ++static int xenon_scr_read (struct ata_link *link, unsigned int sc_reg, u32 *val) //u32 ++{ ++ struct pci_dev *pdev = to_pci_dev(link->ap->host->dev); ++ unsigned int cfg_addr; ++ ++ cfg_addr = get_scr_cfg_addr(sc_reg); ++ ++ if (cfg_addr == -1) ++ return -EINVAL; ++ ++ pci_read_config_dword(pdev, cfg_addr, val); ++ return 0; ++} ++ ++static int xenon_scr_write (struct ata_link *link, unsigned int sc_reg, u32 val) //void ++{ ++ struct pci_dev *pdev = to_pci_dev(link->ap->host->dev); ++ unsigned int cfg_addr; ++ ++ cfg_addr = get_scr_cfg_addr(sc_reg); ++ ++ if (cfg_addr == -1) ++ return -EINVAL; ++ ++ pci_write_config_dword(pdev, cfg_addr, val); ++ return 0; ++} ++ ++static int xenon_softreset(struct ata_link *link, unsigned int *classes, unsigned long deadline) ++{ ++ struct ata_port *ap = link->ap; ++ struct pci_dev *pdev = to_pci_dev(ap->host->dev); ++ /* Host 0 (used for DVD-ROM) has a quirk when used with ++ an Toshiba/Samsung drive: It can hang after a device reset. ++ ++ While the exact reason is unclear (anyone with a SATA port ++ analyzer?), this workaround will not let the reset happen, and ++ emulate the detection of an ATAPI device. ++ ++ When the workaround is enabled, only ATAPI devices are supported ++ on host 0, but on this hardware, nothing else is possible anyway. */ ++ if (pdev->device == 0x5802) ++ { ++ classes[0] = ATA_DEV_ATAPI; ++ classes[1] = ATA_DEV_NONE; ++ printk(KERN_WARNING "Simulating reset of SATA device 0x5802\n"); ++ return -EIO; ++ } else { ++ return ata_sff_softreset(link, classes, deadline); ++ } ++} ++ ++static void xenon_bmdma_error_handler(struct ata_port *ap) ++{ ++ ata_do_eh(ap, ata_std_prereset, xenon_softreset, sata_std_hardreset, ata_std_postreset); ++} ++ ++ ++static int xenon_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) ++{ ++ static int printed_version; ++ struct ata_host *host; ++ struct ata_ioports *ioaddr; ++ struct ata_port_info pi = xenon_port_info; ++ const struct ata_port_info *ppi[] = { &pi, NULL }; ++ int rc; ++ ++ if (!printed_version++) ++ dev_printk(KERN_INFO, &pdev->dev, "version " DRV_VERSION "\n"); ++ ++ rc = pci_enable_device(pdev); ++ if (rc) ++ return rc; ++ ++ rc = pci_request_regions(pdev, DRV_NAME); ++ if (rc) { ++ goto err_out; ++ } ++ ++ rc = pci_set_dma_mask(pdev, ATA_DMA_MASK); ++ if (rc) ++ goto err_out_regions; ++ ++ rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK); ++ if (rc) ++ goto err_out_regions; ++ ++ host = ata_host_alloc_pinfo(&pdev->dev, ppi, 1); ++ if (!host) { ++ rc = -ENOMEM; ++ goto err_out_regions; ++ } ++ ++ ioaddr = &host->ports[0]->ioaddr; ++ ioaddr->cmd_addr = ioremap(pci_resource_start(pdev, 0), PAGE_SIZE); ++ ioaddr->altstatus_addr = ioaddr->cmd_addr + 0xa; ++ ioaddr->ctl_addr = ioaddr->cmd_addr + 0xa; ++ ioaddr->bmdma_addr = ioremap(pci_resource_start(pdev, 1), PAGE_SIZE); ++ ++ ata_sff_std_ports(ioaddr); ++ ++ pci_set_master(pdev); ++ pci_intx(pdev, 1); ++ ++ return ata_host_activate(host, pdev->irq, ata_sff_interrupt, ++ IRQF_SHARED, &xenon_sht); ++ ++err_out_regions: ++ pci_release_regions(pdev); ++ ++err_out: ++ pci_disable_device(pdev); ++ return rc; ++} ++ ++static int __init xenon_init(void) ++{ ++ return pci_register_driver(&xenon_pci_driver); ++} ++ ++static void __exit xenon_exit(void) ++{ ++ pci_unregister_driver(&xenon_pci_driver); ++} ++ ++module_init(xenon_init); ++module_exit(xenon_exit); +diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig +index d454428f4..f767d7e6b 100644 +--- a/drivers/char/Kconfig ++++ b/drivers/char/Kconfig +@@ -7,6 +7,32 @@ menu "Character devices" + + source "drivers/tty/Kconfig" + ++config XENON_SMC ++ tristate "Xenon System Management Controller (SMC)" ++ depends on PPC_XENON ++ help ++ Character interface to the System Management controller in the ++ Xbox 360. Allows to send arbitrary SMC commands and receive ++ SMC replies. ++ ++config XENON_ANA ++ tristate "Xenon (H)ana Character Device" ++ depends on PPC_XENON ++ help ++ Character interface to the (H)ana chip on the Xbox 360. ++ ++config XENON_PROBE ++ tristate "Xenon Memory Probe Device" ++ depends on PPC_XENON && EXPERIMENTAL ++ help ++ Character interface to do memory probing on the Xbox 360. ++ ++config XENOS_RB ++ tristate "Xenos Ring Buffer Device" ++ depends on PPC_XENON && HAS_DMA ++ help ++ Character device supporting raw ringbuffer writes to the Xenos. ++ + config TTY_PRINTK + tristate "TTY driver to output user messages via printk" + depends on EXPERT && TTY +diff --git a/drivers/char/Makefile b/drivers/char/Makefile +index 264eb398f..08710bfe2 100644 +--- a/drivers/char/Makefile ++++ b/drivers/char/Makefile +@@ -11,6 +11,10 @@ obj-$(CONFIG_VIRTIO_CONSOLE) += virtio_console.o + obj-$(CONFIG_MSPEC) += mspec.o + obj-$(CONFIG_UV_MMTIMER) += uv_mmtimer.o + obj-$(CONFIG_IBM_BSR) += bsr.o ++obj-$(CONFIG_XENON_SMC) += xenon_smc.o ++obj-$(CONFIG_XENON_ANA) += xenon_ana.o ++obj-$(CONFIG_XENON_PROBE) += xenon_probe.o ++obj-$(CONFIG_XENOS_RB) += xenos_rb.o + + obj-$(CONFIG_PRINTER) += lp.o + +diff --git a/drivers/char/xenon_ana.c b/drivers/char/xenon_ana.c +new file mode 100644 +index 000000000..79d9f91c1 +--- /dev/null ++++ b/drivers/char/xenon_ana.c +@@ -0,0 +1,209 @@ ++/* ++ * Xenon (H)ana via SMC character driver. ++ * ++ * Copyright (C) 2010 Herbert Poetzl ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; version 2 of the License. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define DRV_NAME "xenon_ana" ++#define DRV_VERSION "0.2" ++ ++ ++int xenon_smc_message_wait(void *msg); ++ ++static uint32_t ana_read_reg(uint8_t addr) ++{ ++ unsigned char msg[16] = { 0x11, ++ 0x10, 0x05, 0x80 | 0x70, 0x00, 0xF0, addr }; ++ ++ xenon_smc_message_wait(msg); ++ return msg[4] | (msg[5] << 8) | (msg[6] << 16) | (msg[7] << 24); ++} ++ ++static int ana_write_reg(uint8_t addr, uint32_t val) ++{ ++ unsigned char msg[16] = { 0x11, ++ 0x60, 0x00, 0x80 | 0x70, 0x00, 0x00, ++ addr, 0x00, val & 0xFF, (val >> 8) & 0xFF, ++ (val >> 16) & 0xFF, (val >> 24) & 0xFF }; ++ ++ xenon_smc_message_wait(msg); ++ return msg[1]; ++} ++ ++static loff_t ana_llseek(struct file *file, loff_t offset, int origin) ++{ ++ switch (origin) { ++ case 1: ++ offset += file->f_pos; ++ break; ++ case 2: ++ offset += 0x400; ++ break; ++ } ++ if (offset < 0) ++ return -EINVAL; ++ ++ file->f_pos = offset; ++ return file->f_pos; ++} ++ ++typedef union { ++ uint32_t val; ++ uint8_t p[4]; ++} ana_reg_t; ++ ++static ssize_t ana_read(struct file *file, char __user *buf, ++ size_t count, loff_t *ppos) ++{ ++ uint32_t ppa = *ppos; ++ ++ if (*ppos >= 0x400UL) ++ return -EINVAL; ++ ++ while (count) { ++ /* optimize reads in same reg */ ++ int addr = ppa/4; ++ int shift = ppa % 4; ++ ana_reg_t r = { .val = ana_read_reg(addr) }; ++ ++ int len = 4 - shift; ++ ++ if (len > count) ++ len = count; ++ if (copy_to_user(buf, &r.p[shift], len)) ++ return -EFAULT; ++ ++ count -= len; ++ buf += len; ++ ppa += len; ++ ++ /* end of register space? */ ++ if (ppa >= 0x400) ++ break; ++ } ++ ++ /* how much data was actually transferred? */ ++ count = ppa - *ppos; ++ *ppos = ppa; ++ return count; ++} ++ ++static ssize_t ana_write(struct file *file, const char __user *buf, ++ size_t count, loff_t *ppos) ++{ ++ uint32_t ppa = *ppos; ++ ++ if (*ppos >= 0x400UL) ++ return -EINVAL; ++ ++ while (count) { ++ /* coalesce writes to same reg */ ++ int addr = ppa/4; ++ int shift = ppa % 4; ++ ana_reg_t r; ++ ++ int len = 4 - shift; ++ ++ if (len > count) ++ len = count; ++ ++ /* handle partial write */ ++ if (len != 4) ++ r.val = ana_read_reg(addr); ++ ++ if (copy_from_user(&r.p[shift], buf, len)) ++ return -EFAULT; ++ ++ /* FIXME: handle return code */ ++ ana_write_reg(addr, r.val); ++ ++ count -= len; ++ buf += len; ++ ppa += len; ++ ++ /* end of register space? */ ++ if (ppa >= 0x400) ++ break; ++ } ++ ++ /* how much data was actually transferred? */ ++ count = ppa - *ppos; ++ *ppos = ppa; ++ return count; ++} ++ ++static long ana_ioctl(struct file *file, ++ unsigned int cmd, unsigned long arg) ++{ ++ return -ENODEV; ++} ++ ++static int ana_open(struct inode *inode, struct file *file) ++{ ++ return nonseekable_open(inode, file); ++} ++ ++static int ana_release(struct inode *inode, struct file *file) ++{ ++ return 0; ++} ++ ++ ++const struct file_operations ana_fops = { ++ .owner = THIS_MODULE, ++ .llseek = ana_llseek, ++ .read = ana_read, ++ .write = ana_write, ++ .unlocked_ioctl = ana_ioctl, ++ .open = ana_open, ++ .release = ana_release, ++}; ++ ++static struct miscdevice ana_dev = { ++ .minor = MISC_DYNAMIC_MINOR, ++ "ana", ++ &ana_fops ++}; ++ ++int __init ana_init(void) ++{ ++ int ret = 0; ++ ++ printk(KERN_INFO "Xenon (H)ana char driver version " DRV_VERSION "\n"); ++ ++ ret = misc_register(&ana_dev); ++ return ret; ++} ++ ++void __exit ana_exit(void) ++{ ++ misc_deregister(&ana_dev); ++} ++ ++module_init(ana_init); ++module_exit(ana_exit); ++ ++MODULE_AUTHOR("Herbert Poetzl "); ++MODULE_DESCRIPTION("Character Interface for Xenon (H)ana"); ++MODULE_LICENSE("GPL"); ++MODULE_VERSION(DRV_VERSION); +diff --git a/drivers/char/xenon_probe.c b/drivers/char/xenon_probe.c +new file mode 100644 +index 000000000..b6237f34d +--- /dev/null ++++ b/drivers/char/xenon_probe.c +@@ -0,0 +1,229 @@ ++/* ++ * Xenon Memory Probe character driver. ++ * ++ * Copyright (C) 2010 Herbert Poetzl ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; version 2 of the License. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define DRV_NAME "xenon_probe" ++#define DRV_VERSION "0.1" ++ ++static unsigned long base = 0xc8000000; ++static unsigned long size = 0x10000; ++static bool little_endian = 0; ++ ++module_param(base, ulong, 0); ++MODULE_PARM_DESC(base, "Probe Memory Base"); ++ ++module_param(size, ulong, 0); ++MODULE_PARM_DESC(size, "Probe Memory Size"); ++ ++module_param(little_endian, bool, 0); ++MODULE_PARM_DESC(little_endian, "Probe Memory Endianess"); ++ ++static void __iomem *mapped = NULL; ++ ++ ++static uint32_t probe_map(uint32_t val) ++{ ++ if (little_endian) ++ return le32_to_cpu(val); ++ else ++ return be32_to_cpu(val); ++} ++ ++static uint32_t probe_rmap(uint32_t val) ++{ ++ if (little_endian) ++ return cpu_to_le32(val); ++ else ++ return cpu_to_be32(val); ++} ++ ++ ++static loff_t probe_llseek(struct file *file, loff_t offset, int origin) ++{ ++ switch (origin) { ++ case 1: ++ offset += file->f_pos; ++ break; ++ case 2: ++ offset += size; ++ break; ++ } ++ if ((offset < 0) || (offset >= size)) ++ return -EINVAL; ++ ++ file->f_pos = offset; ++ return file->f_pos; ++} ++ ++typedef union { ++ uint32_t val; ++ uint8_t p[4]; ++} probe_mem_t; ++ ++static ssize_t probe_read(struct file *file, ++ char __user *buf, size_t count, loff_t *ppos) ++{ ++ uint32_t ppa = *ppos; ++ ++ if (*ppos >= size) ++ return -EINVAL; ++ ++ printk("probe_read(%x,%zx)\n", ppa, count); ++ while (count) { ++ /* optimize reads in same longword */ ++ unsigned long addr = ppa & ~3; ++ int shift = ppa % 4; ++ probe_mem_t r = { .val = probe_map(readl(mapped + addr)) }; ++ ++ int len = 4 - shift; ++ ++ if (len > count) ++ len = count; ++ if (copy_to_user(buf, &r.p[shift], len)) ++ return -EFAULT; ++ ++ count -= len; ++ buf += len; ++ ppa += len; ++ ++ /* end of register space? */ ++ if (ppa >= size) ++ break; ++ } ++ ++ /* how much data was actually transferred? */ ++ count = ppa - *ppos; ++ *ppos = ppa; ++ return count; ++} ++ ++static ssize_t probe_write(struct file *file, ++ const char __user *buf, size_t count, loff_t *ppos) ++{ ++ uint32_t ppa = *ppos; ++ ++ if (*ppos >= size) ++ return -EINVAL; ++ ++ printk("probe_write(%x,%zx)\n", ppa, count); ++ while (count) { ++ /* coalesce writes to same reg */ ++ unsigned long addr = ppa & ~3; ++ int shift = ppa % 4; ++ probe_mem_t r; ++ ++ int len = 4 - shift; ++ ++ if (len > count) ++ len = count; ++ ++ /* handle partial write */ ++ if (len != 4) ++ r.val = probe_map(readl(mapped + addr)); ++ ++ if (copy_from_user(&r.p[shift], buf, len)) ++ return -EFAULT; ++ ++ writel(probe_rmap(r.val), mapped + addr); ++ ++ count -= len; ++ buf += len; ++ ppa += len; ++ ++ /* end of register space? */ ++ if (ppa >= size) ++ break; ++ } ++ ++ /* how much data was actually transferred? */ ++ count = ppa - *ppos; ++ *ppos = ppa; ++ return count; ++} ++ ++static long probe_ioctl(struct file *file, ++ unsigned int cmd, unsigned long arg) ++{ ++ return -ENODEV; ++} ++ ++static int probe_open(struct inode *inode, struct file *file) ++{ ++ return generic_file_open(inode, file); ++} ++ ++static int probe_release(struct inode *inode, struct file *file) ++{ ++ return 0; ++} ++ ++ ++const struct file_operations probe_fops = { ++ .owner = THIS_MODULE, ++ .llseek = probe_llseek, ++ .read = probe_read, ++ .write = probe_write, ++ .unlocked_ioctl = probe_ioctl, ++ .open = probe_open, ++ .release = probe_release, ++}; ++ ++static struct miscdevice probe_dev = { ++ .minor = MISC_DYNAMIC_MINOR, ++ "probe", ++ &probe_fops ++}; ++ ++int __init probe_init(void) ++{ ++ int ret = 0; ++ ++ printk(KERN_INFO "Xenon Memory Probe driver version " DRV_VERSION "\n"); ++ ++ mapped = ioremap(base, size); ++ if (!mapped) ++ return -EINVAL; ++ ++ printk(KERN_INFO "XMP mapped 0x%04lx bytes @0x%08lx\n", ++ size, base); ++ ++ ret = misc_register(&probe_dev); ++ return ret; ++} ++ ++void __exit probe_exit(void) ++{ ++ misc_deregister(&probe_dev); ++} ++ ++module_init(probe_init); ++module_exit(probe_exit); ++ ++MODULE_AUTHOR("Herbert Poetzl "); ++MODULE_DESCRIPTION("Xenon Memory Probe Interface"); ++MODULE_LICENSE("GPL"); ++MODULE_VERSION(DRV_VERSION); ++ +diff --git a/drivers/char/xenon_smc.c b/drivers/char/xenon_smc.c +new file mode 100644 +index 000000000..9d0c86ce9 +--- /dev/null ++++ b/drivers/char/xenon_smc.c +@@ -0,0 +1,121 @@ ++/* ++ * Xenon SMC character driver. ++ * ++ * Copyright (C) 2010 Herbert Poetzl ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; version 2 of the License. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define DRV_NAME "xenon_smc" ++#define DRV_VERSION "0.2" ++ ++ ++/* single access for now */ ++ ++static unsigned long is_active; ++static unsigned char msg[16]; ++ ++static ssize_t smc_read(struct file *file, char __user *buf, ++ size_t count, loff_t *ppos) ++{ ++ if ((count != 16) || *ppos) ++ return -EINVAL; ++ if (copy_to_user(buf, msg, 0x10)) ++ return -EFAULT; ++ ++ return 16; ++} ++ ++int xenon_smc_message_wait(void *msg); ++ ++static ssize_t smc_write(struct file *file, const char __user *buf, ++ size_t count, loff_t *ppos) ++{ ++ if ((count != 16) || *ppos) ++ return -EINVAL; ++ ++ if (copy_from_user(msg, buf, 16)) ++ return -EFAULT; ++ ++ xenon_smc_message_wait(msg); ++ ++ return 16; ++} ++ ++static long smc_ioctl(struct file *file, ++ unsigned int cmd, unsigned long arg) ++{ ++ return -ENODEV; ++} ++ ++static int smc_open(struct inode *inode, struct file *file) ++{ ++ if (test_and_set_bit(0, &is_active)) ++ return -EBUSY; ++ ++ return nonseekable_open(inode, file); ++} ++ ++static int smc_release(struct inode *inode, struct file *file) ++{ ++ clear_bit(0, &is_active); ++ return 0; ++} ++ ++ ++const struct file_operations smc_fops = { ++ .owner = THIS_MODULE, ++ .llseek = no_llseek, ++ .read = smc_read, ++ .write = smc_write, ++ .unlocked_ioctl = smc_ioctl, ++ .open = smc_open, ++ .release = smc_release, ++}; ++ ++static struct miscdevice smc_dev = { ++ .minor = MISC_DYNAMIC_MINOR, ++ "smc", ++ &smc_fops ++}; ++ ++int __init smc_init(void) ++{ ++ int ret = 0; ++ ++ printk(KERN_INFO "Xenon SMC char driver version " DRV_VERSION "\n"); ++ ++ ret = misc_register(&smc_dev); ++ return ret; ++} ++ ++void __exit smc_exit(void) ++{ ++ misc_deregister(&smc_dev); ++} ++ ++module_init(smc_init); ++module_exit(smc_exit); ++ ++MODULE_AUTHOR("Herbert Poetzl "); ++MODULE_DESCRIPTION("Character Interface for Xenon Southbridge SMC"); ++MODULE_LICENSE("GPL"); ++MODULE_VERSION(DRV_VERSION); +diff --git a/drivers/char/xenos_rb.c b/drivers/char/xenos_rb.c +new file mode 100644 +index 000000000..83be22ca6 +--- /dev/null ++++ b/drivers/char/xenos_rb.c +@@ -0,0 +1,937 @@ ++/* ++ * Xenos RingBuffer character driver. ++ * ++ * Copyright (C) 2018 Justin Moore ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; version 2 of the License. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#define DRV_NAME "xenos_rb" ++#define DRV_VERSION "0.1" ++ ++#define IOC_MAGIC 0x58524230 ++#define IOCTL_RESET _IO(IOC_MAGIC, 0) ++ ++static int xenosrb_size = 0x8000; ++module_param(xenosrb_size, int, 0444); ++ ++static uint32_t xenos_pfp_ucode[] = { ++ 0xC60400, 0x7E424B, 0xA00000, 0x7E828B, 0x800001, 0xC60400, 0xCC4003, ++ 0x800000, 0xD60003, 0xC60800, 0xC80C1D, 0x98C007, 0xC61000, 0x978003, ++ 0xCC4003, 0xD60004, 0x800000, 0xCD0003, 0x9783EF, 0xC60400, 0x800000, ++ 0xC60400, 0xC60800, 0x348C08, 0x98C006, 0xC80C1E, 0x98C000, 0xC80C1E, ++ 0x80001F, 0xCC8007, 0xCC8008, 0xCC4003, 0x800000, 0xCC8003, 0xC60400, ++ 0x1AAC07, 0xCA8821, 0x96C015, 0xC8102C, 0x98800A, 0x329418, 0x9A4004, ++ 0xCC6810, 0x42401, 0xD00143, 0xD00162, 0xCD0002, 0x7D514C, 0xCD4003, ++ 0x9B8007, 0x6A801, 0x964003, 0xC28000, 0xCF4003, 0x800001, 0xC60400, ++ 0x800023, 0xC60400, 0x964003, 0x7E424B, 0xD00283, 0xC8102B, 0xC60800, ++ 0x99000E, 0xC80C29, 0x98C00A, 0x345002, 0xCD0002, 0xCC8002, 0xD001E3, ++ 0xD00183, 0xCC8003, 0xCC4018, 0x80004D, 0xCC8019, 0xD00203, 0xD00183, ++ 0x9783B4, 0xC60400, 0xC8102B, 0xC60800, 0x9903AF, 0xC80C2A, 0x98C00A, ++ 0x345002, 0xCD0002, 0xCC8002, 0xD001E3, 0xD001A3, 0xCC8003, 0xCC401A, ++ 0x800000, 0xCC801B, 0xD00203, 0xD001A3, 0x800001, 0xC60400, 0xC60800, ++ 0xC60C00, 0xC8102D, 0x349402, 0x99000B, 0xC8182E, 0xCD4002, 0xCD8002, ++ 0xD001E3, 0xD001C3, 0xCCC003, 0xCC801C, 0xCD801D, 0x800001, 0xC60400, ++ 0xD00203, 0x800000, 0xD001C3, 0xC8081F, 0xC60C00, 0xC80C20, 0x988000, ++ 0xC8081F, 0xCC4003, 0xCCC003, 0xD60003, 0x800000, 0xCCC022, 0xC81C2F, ++ 0xC60400, 0xC60800, 0xC60C00, 0xC81030, 0x99C000, 0xC81C2F, 0xCC8021, ++ 0xCC4020, 0x990011, 0xC107FF, 0xD00223, 0xD00243, 0x345402, 0x7CB18B, ++ 0x7D95CC, 0xCDC002, 0xCCC002, 0xD00263, 0x978005, 0xCCC003, 0xC60800, ++ 0x80008B, 0xC60C00, 0x800000, 0xD00283, 0x97836A, 0xC60400, 0xD6001F, ++ 0x800001, 0xC60400, 0xC60800, 0xC60C00, 0xC61000, 0x348802, 0xCC8002, ++ 0xCC4003, 0xCCC003, 0xCD0002, 0x800000, 0xCD0003, 0xD2000D, 0xCC000D, ++ 0x800000, 0xCC000D, 0xC60800, 0xC60C00, 0xCA1433, 0xD022A0, 0xCCE000, ++ 0x994351, 0xCCE005, 0x800000, 0x62001, 0xC60800, 0xC60C00, 0xD022A0, ++ 0xCCE000, 0xD022AE, 0xCCE029, 0xCCE005, 0x800000, 0x62001, 0x964000, ++ 0xC82435, 0xCA0838, 0x366401, 0x964340, 0xCA0C3A, 0xCCA000, 0xCCE000, ++ 0xCCE029, 0xCCE005, 0x800000, 0x62001, 0xC60800, 0xC60C00, 0xD202C3, ++ 0xCC8003, 0xCCC003, 0xCCE027, 0x800000, 0x62001, 0xCA0831, 0x9883FF, ++ 0xCA0831, 0xD6001F, 0x800001, 0xC60400, 0xD02360, 0xD02380, 0xD02385, ++ 0x800000, 0x62001, 0xA2001, 0xCA0436, 0x9843DF, 0xC82435, 0x800001, ++ 0xC60400, 0xD20009, 0xD2000A, 0xCC001F, 0x800000, 0xCC001F, 0xD2000B, ++ 0xD2000C, 0xCC001F, 0x800000, 0xCC001F, 0xCC0023, 0xCC4003, 0x800000, ++ 0xD60003, 0xD00303, 0xCC0024, 0xCC4003, 0x800000, 0xD60003, 0xD00323, ++ 0xCC0025, 0xCC4003, 0x800000, 0xD60003, 0xD00343, 0xCC0026, 0xCC4003, ++ 0x800000, 0xD60003, 0x800000, 0xD6001F, 0x100EF, 0x200F4, 0x300F9, ++ 0x50004, 0x600D6, 0x1000FE, 0x1700DB, 0x220009, 0x230016, 0x250022, ++ 0x270061, 0x2D0073, 0x2E007D, 0x2F009C, 0x3700C8, 0x3800B3, 0x3B00A6, ++ 0x3F00AA, 0x4800EB, 0x5000E1, 0x5100E6, 0x5500F0, 0x5600F5, 0x5700FA, ++ 0x5D00D0, 6, 6, 6, 6, 6, 6, ++ 6, ++}; ++ ++static uint32_t xenos_me_ucode[] = { ++ 0, 0xC0200400, 0, 0, 0xA0000A, 0, ++ 0x1F3, 0x204411, 0, 0x1000000, 0x204811, 0, ++ 0, 0x400000, 4, 0xFFFF, 0x284621, 0, ++ 0, 0xD9004800, 0, 0, 0x400000, 0, ++ 0, 0x34E00000, 0, 0, 0x600000, 0x24A, ++ 0xFFFF, 0xC0280A20, 0, 0, 0x294582, 0, ++ 0, 0xD9004800, 0, 0, 0x400000, 0, ++ 0, 0x600000, 0x24A, 0xFFFF, 0xC0284620, 0, ++ 0, 0xD9004800, 0, 0, 0x400000, 0, ++ 0, 0x600000, 0x267, 0x21FC, 0x29462C, 0, ++ 0, 0xC0204800, 0, 0, 0x400000, 0, ++ 0, 0x600000, 0x267, 0x21FC, 0x29462C, 0, ++ 0, 0xC0204800, 0, 0x3FFF, 0x2F022F, 0, ++ 0, 0xCE00000, 0, 0xA1FD, 0x29462C, 0, ++ 0, 0xD9004800, 0, 0, 0x400000, 0, ++ 0x394, 0x204411, 0, 1, 0xC0404811, 0, ++ 0, 0x600000, 0x267, 0x21F9, 0x29462C, 0, ++ 8, 0xC0210A20, 0, 0, 0x14E00000, 0x25, ++ 7, 0x404811, 0, 8, 0x404811, 0, ++ 0, 0x600000, 0x267, 0x21FC, 0x29462C, 0, ++ 0, 0xC0204800, 0, 0xA1FD, 0x29462C, 0, ++ 0, 0xC0200800, 0, 0, 0x2F0222, 0, ++ 0, 0xCE00000, 0, 0, 0x40204800, 0, ++ 1, 0x40304A20, 0, 2, 0xC0304A20, 0, ++ 1, 0x530A22, 0x2B, 0x80000000, 0xC0204411, 0, ++ 1, 0x604811, 0x281, 0, 0x400000, 0, ++ 0, 0xC0200000, 0, 0x12B9B0A1, 0xC02F0220, 0, ++ 0, 0xCC00000, 0x3A, 0x1033C4D6, 0xC02F0220, 0, ++ 0, 0xCC00000, 0x3A, 0, 0x400000, 0, ++ 0x1F3, 0x204411, 0, 0x8000000, 0x204811, 0, ++ 0, 0x400000, 0x3C, 0x80000000, 0xC0204411, 0, ++ 0, 0x604811, 0x281, 0, 0x400000, 0, ++ 0x1F, 0x40280A20, 0, 0x1B, 0x2F0222, 0, ++ 0, 0xCE00000, 0x57, 2, 0x2F0222, 0, ++ 0, 0xCE00000, 0x5E, 3, 0x2F0222, 0, ++ 0, 0xCE00000, 0x65, 4, 0x2F0222, 0, ++ 0, 0xCE00000, 0x6C, 0x14, 0x2F0222, 0, ++ 0, 0xCE00000, 0x6C, 0x1A, 0x2F0222, 0, ++ 0, 0xCE00000, 0x74, 0x15, 0x2F0222, 0, ++ 0, 0xCE00000, 0x79, 0x21F9, 0x29462C, 0, ++ 0, 0xC0404802, 0, 0x1F, 0x40280A20, 0, ++ 0x1B, 0x2F0222, 0, 0, 0xCE00000, 0x57, ++ 2, 0x2F0222, 0, 0, 0xCE00000, 0x5E, ++ 0, 0x400000, 0x65, 0x1F, 0xC0210E20, 0, ++ 0x612, 0x204411, 0, 0, 0x204803, 0, ++ 0, 0xC0204800, 0, 0, 0xC0204800, 0, ++ 0x21F9, 0x29462C, 0, 0, 0x404802, 0, ++ 0x1E, 0xC0210E20, 0, 0x600, 0x204411, 0, ++ 0, 0x204803, 0, 0, 0xC0204800, 0, ++ 0, 0xC0204800, 0, 0x21F9, 0x29462C, 0, ++ 0, 0x404802, 0, 0x1E, 0xC0210E20, 0, ++ 0x605, 0x204411, 0, 0, 0x204803, 0, ++ 0, 0xC0204800, 0, 0, 0xC0204800, 0, ++ 0x21F9, 0x29462C, 0, 0, 0x404802, 0, ++ 0x1F, 0x40280A20, 0, 0x1F, 0xC0210E20, 0, ++ 0x60A, 0x204411, 0, 0, 0x204803, 0, ++ 0, 0xC0204800, 0, 0, 0xC0204800, 0, ++ 0x21F9, 0x29462C, 0, 0, 0x404802, 0, ++ 0x1F, 0xC0280A20, 0, 0x611, 0x204411, 0, ++ 0, 0xC0204800, 0, 0x21F9, 0x29462C, 0, ++ 0, 0x404802, 0, 0x1F, 0xC0280A20, 0, ++ 0, 0x600000, 0x267, 0x21F9, 0x29462C, 0, ++ 0, 0x404802, 0, 0x81000000, 0x204411, 0, ++ 1, 0x204811, 0, 0x1FFF, 0x40280A20, 0, ++ 0x80000000, 0x40280E20, 0, 0x40000000, 0xC0281220, 0, ++ 0x40000, 0x294622, 0, 0, 0x600000, 0x282, ++ 0, 0x201410, 0, 0, 0x2F0223, 0, ++ 0, 0xCC00000, 0x88, 0, 0xC0401800, 0x8C, ++ 0x1FFF, 0xC0281A20, 0, 0x40000, 0x294626, 0, ++ 0, 0x600000, 0x282, 0, 0x201810, 0, ++ 0, 0x2F0224, 0, 0, 0xCC00000, 0x8F, ++ 0, 0xC0401C00, 0x93, 0x1FFF, 0xC0281E20, 0, ++ 0x40000, 0x294627, 0, 0, 0x600000, 0x282, ++ 0, 0x201C10, 0, 0, 0x204402, 0, ++ 0, 0x2820C5, 0, 0, 0x4948E8, 0, ++ 0, 0x600000, 0x24A, 0x10, 0x40210A20, 0, ++ 0xFF, 0x280A22, 0, 0x7FF, 0x40280E20, 0, ++ 2, 0x221E23, 0, 5, 0xC0211220, 0, ++ 0x80000, 0x281224, 0, 0x13, 0x210224, 0, ++ 0, 0x14C00000, 0xA1, 0xA1000000, 0x204411, 0, ++ 0, 0x204811, 0, 0, 0x2F0222, 0, ++ 0, 0xCC00000, 0xA5, 8, 0x20162D, 0, ++ 0x4000, 0x500E23, 0xB4, 1, 0x2F0222, 0, ++ 0, 0xCC00000, 0xA9, 9, 0x20162D, 0, ++ 0x4800, 0x500E23, 0xB4, 2, 0x2F0222, 0, ++ 0, 0xCC00000, 0xAD, 0x37, 0x20162D, 0, ++ 0x4900, 0x500E23, 0xB4, 3, 0x2F0222, 0, ++ 0, 0xCC00000, 0xB1, 0x36, 0x20162D, 0, ++ 0x4908, 0x500E23, 0xB4, 0x29, 0x20162D, 0, ++ 0x2000, 0x300E23, 0, 0, 0x290D83, 0, ++ 0x94000000, 0x204411, 0, 0, 0x2948E5, 0, ++ 0, 0x294483, 0, 0, 0x40201800, 0, ++ 0, 0xD9004800, 0, 0x13, 0x210224, 0, ++ 0, 0x14C00000, 0, 0x94000000, 0x204411, 0, ++ 0, 0x2948E5, 0, 0x93000000, 0x204411, 0, ++ 0, 0x404806, 0, 0, 0x600000, 0x24A, ++ 0, 0xC0200800, 0, 0, 0xC0201400, 0, ++ 0x1F, 0x211A25, 0, 0, 0x14E00000, 0, ++ 0x7FF, 0x280E25, 0, 0x10, 0x211225, 0, ++ 0x83000000, 0x204411, 0, 0, 0x2F0224, 0, ++ 0, 0xAE00000, 0xCB, 8, 0x203622, 0, ++ 0x4000, 0x504A23, 0xDA, 1, 0x2F0224, 0, ++ 0, 0xAE00000, 0xCF, 9, 0x203622, 0, ++ 0x4800, 0x504A23, 0xDA, 2, 0x2F0224, 0, ++ 0, 0xAE00000, 0xD3, 0x37, 0x203622, 0, ++ 0x4900, 0x504A23, 0xDA, 3, 0x2F0224, 0, ++ 0, 0xAE00000, 0xD7, 0x36, 0x203622, 0, ++ 0x4908, 0x504A23, 0xDA, 0x29, 0x203622, 0, ++ 0, 0x290D83, 0, 0x2000, 0x304A23, 0, ++ 0x84000000, 0x204411, 0, 0, 0xC0204800, 0, ++ 0, 0x21000000, 0, 0, 0x400000, 0xC1, ++ 0, 0x600000, 0x24A, 0x83000000, 0x204411, 0, ++ 0x4000, 0xC0304A20, 0, 0x84000000, 0x204411, 0, ++ 0, 0xC0204800, 0, 0, 0x21000000, 0, ++ 0, 0x400000, 0, 0x81000000, 0x204411, 0, ++ 1, 0x204811, 0, 0x40578, 0x204411, 0, ++ 0, 0x600000, 0x282, 0, 0xC0400000, 0, ++ 0, 0xC0200C00, 0, 0, 0xC0201000, 0, ++ 0, 0xC0201400, 0, 0, 0xC0201800, 0, ++ 0x7F00, 0x280A21, 0, 0x4500, 0x2F0222, 0, ++ 0, 0xCE00000, 0xF2, 0, 0xC0201C00, 0, ++ 0, 0x17000000, 0, 0x10, 0x280A23, 0, ++ 0x10, 0x2F0222, 0, 0, 0xCE00000, 0xFB, ++ 0x81000000, 0x204411, 0, 1, 0x204811, 0, ++ 0x40000, 0x294624, 0, 0, 0x600000, 0x282, ++ 0, 0x400000, 0x103, 0x81000000, 0x204411, 0, ++ 0, 0x204811, 0, 0x1EA, 0x204411, 0, ++ 0, 0x204804, 0, 0, 0x1AC00000, 0xFF, ++ 0x9E000000, 0x204411, 0, 0xDEADBEEF, 0x204811, 0, ++ 0, 0x1AE00000, 0x102, 0, 0x2820D0, 0, ++ 7, 0x280A23, 0, 1, 0x2F0222, 0, ++ 0, 0xAE00000, 0x10A, 0, 0x2F00A8, 0, ++ 0, 0x4E00000, 0x123, 0, 0x400000, 0x12A, ++ 2, 0x2F0222, 0, 0, 0xAE00000, 0x10F, ++ 0, 0x2F00A8, 0, 0, 0x2E00000, 0x123, ++ 0, 0x400000, 0x12A, 3, 0x2F0222, 0, ++ 0, 0xAE00000, 0x114, 0, 0x2F00A8, 0, ++ 0, 0xCE00000, 0x123, 0, 0x400000, 0x12A, ++ 4, 0x2F0222, 0, 0, 0xAE00000, 0x119, ++ 0, 0x2F00A8, 0, 0, 0xAE00000, 0x123, ++ 0, 0x400000, 0x12A, 5, 0x2F0222, 0, ++ 0, 0xAE00000, 0x11E, 0, 0x2F00A8, 0, ++ 0, 0x6E00000, 0x123, 0, 0x400000, 0x12A, ++ 6, 0x2F0222, 0, 0, 0xAE00000, 0x123, ++ 0, 0x2F00A8, 0, 0, 0x8E00000, 0x123, ++ 0, 0x400000, 0x12A, 0x7F00, 0x280A21, 0, ++ 0x4500, 0x2F0222, 0, 0, 0xAE00000, 0, ++ 8, 0x210A23, 0, 0, 0x14E00000, 0x14A, ++ 0, 0xC0204400, 0, 0, 0xC0404800, 0, ++ 0x7F00, 0x280A21, 0, 0x4500, 0x2F0222, 0, ++ 0, 0xAE00000, 0x12F, 0, 0xC0200000, 0, ++ 0, 0xC0400000, 0, 0, 0x404C07, 0xF2, ++ 0, 0xC0201000, 0, 0, 0xC0201400, 0, ++ 0, 0xC0201800, 0, 0, 0xC0201C00, 0, ++ 0, 0x17000000, 0, 0x81000000, 0x204411, 0, ++ 1, 0x204811, 0, 0x40000, 0x294624, 0, ++ 0, 0x600000, 0x282, 0, 0x2820D0, 0, ++ 0, 0x2F00A8, 0, 0, 0xCE00000, 0, ++ 0, 0x404C07, 0x134, 0, 0xC0201000, 0, ++ 0, 0xC0201400, 0, 0, 0xC0201800, 0, ++ 0, 0xC0201C00, 0, 0, 0x17000000, 0, ++ 0x81000000, 0x204411, 0, 1, 0x204811, 0, ++ 0x40000, 0x294624, 0, 0, 0x600000, 0x282, ++ 0, 0x2820D0, 0, 0, 0x2F00A8, 0, ++ 0, 0x6E00000, 0, 0, 0x404C07, 0x141, ++ 0x60D, 0x204411, 0, 0, 0xC0204800, 0, ++ 0, 0xC0404800, 0, 0x81000000, 0x204411, 0, ++ 9, 0x204811, 0, 0x60D, 0x204411, 0, ++ 0, 0xC0204800, 0, 0, 0x404810, 0, ++ 0x1FFF, 0xC0280A20, 0, 0x20000, 0x294622, 0, ++ 0x18, 0xC0424A20, 0, 0x81000000, 0x204411, 0, ++ 1, 0x204811, 0, 0x40000, 0xC0294620, 0, ++ 0, 0x600000, 0x282, 0x60D, 0x204411, 0, ++ 0, 0xC0204800, 0, 0, 0x404810, 0, ++ 0x1F3, 0x204411, 0, 0xE0000000, 0xC0484A20, 0, ++ 0, 0xD9000000, 0, 0, 0x400000, 0, ++ 0x45D, 0x204411, 0, 0x3F, 0xC0484A20, 0, ++ 0, 0x600000, 0x24A, 0x81000000, 0x204411, 0, ++ 2, 0x204811, 0, 0xFF, 0x280E30, 0, ++ 0, 0x2F0223, 0, 0, 0xCC00000, 0x165, ++ 0, 0x200411, 0, 0x1D, 0x203621, 0, ++ 0x1E, 0x203621, 0, 0, 0xC0200800, 0, ++ 9, 0x210222, 0, 0, 0x14C00000, 0x171, ++ 0, 0x600000, 0x275, 0, 0x200C11, 0, ++ 0x38, 0x203623, 0, 0, 0x210A22, 0, ++ 0, 0x14C00000, 0x17A, 0, 0xC02F0220, 0, ++ 0, 0x400000, 0x177, 0, 0x600000, 0x1D8, ++ 0, 0x400000, 0x178, 0, 0x600000, 0x1DC, ++ 0xA0000000, 0x204411, 0, 0, 0x204811, 0, ++ 1, 0x210A22, 0, 0, 0x14C00000, 0x17F, ++ 0xF1FFFFFF, 0x283A2E, 0, 0x1A, 0xC0220E20, 0, ++ 0, 0x29386E, 0, 1, 0x210A22, 0, ++ 0, 0x14C00000, 0x189, 0xE, 0xC0203620, 0, ++ 0xF, 0xC0203620, 0, 0x10, 0xC0203620, 0, ++ 0x11, 0xC0203620, 0, 0x12, 0xC0203620, 0, ++ 0x13, 0xC0203620, 0, 0x14, 0xC0203620, 0, ++ 0x15, 0xC0203620, 0, 1, 0x210A22, 0, ++ 0, 0x14C00000, 0x1AC, 0, 0xC0200C00, 0, ++ 0x8C000000, 0x204411, 0, 0, 0x204803, 0, ++ 0xFFF, 0x281223, 0, 0x19, 0x203624, 0, ++ 3, 0x381224, 0, 0x5000, 0x301224, 0, ++ 0x18, 0x203624, 0, 0x87000000, 0x204411, 0, ++ 0, 0x204804, 0, 1, 0x331224, 0, ++ 0x86000000, 0x204411, 0, 0, 0x204804, 0, ++ 0x88000000, 0x204411, 0, 0x7FFF, 0x204811, 0, ++ 0x10, 0x211623, 0, 0xFFF, 0x281A23, 0, ++ 0, 0x331CA6, 0, 0x8F000000, 0x204411, 0, ++ 3, 0x384A27, 0, 0x10, 0x211223, 0, ++ 0x17, 0x203624, 0, 0x8B000000, 0x204411, 0, ++ 0, 0x204804, 0, 3, 0x381224, 0, ++ 0x5000, 0x301224, 0, 0x16, 0x203624, 0, ++ 0x85000000, 0x204411, 0, 0, 0x204804, 0, ++ 0x1000, 0x331CD1, 0, 0x90000000, 0x204411, 0, ++ 3, 0x384A27, 0, 0x300000, 0x293A2E, 0, ++ 1, 0x210A22, 0, 0, 0x14C00000, 0x1B9, ++ 0xA3000000, 0x204411, 0, 0, 0x40204800, 0, ++ 0xA, 0xC0220E20, 0, 0x21, 0x203623, 0, ++ 0, 0x600000, 0x1DC, 0xFFFFE000, 0x200411, 0, ++ 0x2E, 0x203621, 0, 0x2F, 0x203621, 0, ++ 0x1FFF, 0x200411, 0, 0x30, 0x203621, 0, ++ 0x31, 0x203621, 0, 1, 0x210A22, 0, ++ 0, 0x14C00000, 0x1BC, 0, 0xC0200000, 0, ++ 1, 0x210A22, 0, 0, 0x14C00000, 0x1C2, ++ 0x9C000000, 0x204411, 0, 0x1F, 0x40214A20, 0, ++ 0x96000000, 0x204411, 0, 0, 0xC0204800, 0, ++ 1, 0x210A22, 0, 0, 0x14C00000, 0x1CB, ++ 0x3FFFFFFF, 0x283A2E, 0, 0xC0000000, 0x40280E20, 0, ++ 0, 0x29386E, 0, 0x18000000, 0x40280E20, 0, ++ 0x38, 0x203623, 0, 0xA4000000, 0x204411, 0, ++ 0, 0xC0204800, 0, 1, 0x210A22, 0, ++ 0, 0x14C00000, 0x1D7, 0, 0xC0200C00, 0, ++ 0x2B, 0x203623, 0, 0x2D, 0x203623, 0, ++ 2, 0x40221220, 0, 0, 0x301083, 0, ++ 0x2C, 0x203624, 0, 3, 0xC0210E20, 0, ++ 0x10000000, 0x280E23, 0, 0xEFFFFFFF, 0x283A2E, 0, ++ 0, 0x29386E, 0, 0, 0x400000, 0, ++ 0x25F4, 0x204411, 0, 0xA, 0x214A2C, 0, ++ 0, 0x600000, 0x273, 0, 0x800000, 0, ++ 0x21F4, 0x204411, 0, 0xA, 0x214A2C, 0, ++ 0, 0x600000, 0x275, 0, 0x800000, 0, ++ 0, 0x600000, 0x24A, 0, 0xC0200800, 0, ++ 0x1F, 0x210E22, 0, 0, 0x14E00000, 0, ++ 0x3FF, 0x280E22, 0, 0x18, 0x211222, 0, ++ 0xE, 0x301224, 0, 0, 0x20108D, 0, ++ 0x2000, 0x291224, 0, 0x83000000, 0x204411, 0, ++ 0, 0x294984, 0, 0x84000000, 0x204411, 0, ++ 0, 0x204803, 0, 0, 0x21000000, 0, ++ 0, 0x400000, 0x1E1, 0x82000000, 0x204411, 0, ++ 1, 0x204811, 0, 0, 0xC0200800, 0, ++ 0x3FFF, 0x40280E20, 0, 0x10, 0xC0211220, 0, ++ 0, 0x2F0222, 0, 0, 0xAE00000, 0x1FE, ++ 0, 0x2AE00000, 0x208, 0x20000080, 0x281E2E, 0, ++ 0x80, 0x2F0227, 0, 0, 0xCE00000, 0x1FB, ++ 0, 0x401C0C, 0x1FC, 0x20, 0x201E2D, 0, ++ 0x21F9, 0x294627, 0, 0, 0x404811, 0x208, ++ 1, 0x2F0222, 0, 0, 0xAE00000, 0x23D, ++ 0, 0x28E00000, 0x208, 0x800080, 0x281E2E, 0, ++ 0x80, 0x2F0227, 0, 0, 0xCE00000, 0x205, ++ 0, 0x401C0C, 0x206, 0x20, 0x201E2D, 0, ++ 0x21F9, 0x294627, 0, 1, 0x204811, 0, ++ 0x81000000, 0x204411, 0, 0, 0x2F0222, 0, ++ 0, 0xAE00000, 0x20F, 3, 0x204811, 0, ++ 0x16, 0x20162D, 0, 0x17, 0x201A2D, 0, ++ 0xFFDFFFFF, 0x483A2E, 0x213, 4, 0x204811, 0, ++ 0x18, 0x20162D, 0, 0x19, 0x201A2D, 0, ++ 0xFFEFFFFF, 0x283A2E, 0, 0, 0x201C10, 0, ++ 0, 0x2F0067, 0, 0, 0x6C00000, 0x208, ++ 0x81000000, 0x204411, 0, 6, 0x204811, 0, ++ 0x83000000, 0x204411, 0, 0, 0x204805, 0, ++ 0x89000000, 0x204411, 0, 0, 0x204806, 0, ++ 0x84000000, 0x204411, 0, 0, 0x204803, 0, ++ 0, 0x21000000, 0, 0, 0x601010, 0x24A, ++ 0xC, 0x221E24, 0, 0, 0x2F0222, 0, ++ 0, 0xAE00000, 0x230, 0x20000000, 0x293A2E, 0, ++ 0x21F7, 0x29462C, 0, 0, 0x2948C7, 0, ++ 0x81000000, 0x204411, 0, 5, 0x204811, 0, ++ 0x16, 0x203630, 0, 7, 0x204811, 0, ++ 0x17, 0x203630, 0, 0x91000000, 0x204411, 0, ++ 0, 0x204803, 0, 0, 0x23000000, 0, ++ 0x8D000000, 0x204411, 0, 0, 0x404803, 0x243, ++ 0x800000, 0x293A2E, 0, 0x21F6, 0x29462C, 0, ++ 0, 0x2948C7, 0, 0x81000000, 0x204411, 0, ++ 5, 0x204811, 0, 0x18, 0x203630, 0, ++ 7, 0x204811, 0, 0x19, 0x203630, 0, ++ 0x92000000, 0x204411, 0, 0, 0x204803, 0, ++ 0, 0x25000000, 0, 0x8E000000, 0x204411, 0, ++ 0, 0x404803, 0x243, 0x83000000, 0x204411, 0, ++ 3, 0x381224, 0, 0x5000, 0x304A24, 0, ++ 0x84000000, 0x204411, 0, 0, 0x204803, 0, ++ 0, 0x21000000, 0, 0x82000000, 0x204411, 0, ++ 0, 0x404811, 0, 0x1F3, 0x204411, 0, ++ 0x4000000, 0x204811, 0, 0, 0x400000, 0x247, ++ 0, 0xC0600000, 0x24A, 0, 0x400000, 0, ++ 0, 0xEE00000, 0x281, 0x21F9, 0x29462C, 0, ++ 5, 0x204811, 0, 0, 0x202C0C, 0, ++ 0x21, 0x20262D, 0, 0, 0x2F012C, 0, ++ 0, 0xCC00000, 0x252, 0, 0x403011, 0x253, ++ 0x400, 0x30322C, 0, 0x81000000, 0x204411, 0, ++ 2, 0x204811, 0, 0xA, 0x21262C, 0, ++ 0, 0x210130, 0, 0, 0x14C00000, 0x25B, ++ 0xA5000000, 0x204411, 0, 1, 0x204811, 0, ++ 0, 0x400000, 0x256, 0xA5000000, 0x204411, 0, ++ 0, 0x204811, 0, 0, 0x2F016C, 0, ++ 0, 0xCE00000, 0x263, 0x21F4, 0x29462C, 0, ++ 0xA, 0x214A2B, 0, 0x4940, 0x204411, 0, ++ 0xDEADBEEF, 0x204811, 0, 0, 0x600000, 0x26E, ++ 0xDFFFFFFF, 0x283A2E, 0, 0xFF7FFFFF, 0x283A2E, 0, ++ 0x20, 0x80362B, 0, 0x97000000, 0x204411, 0, ++ 0, 0x20480C, 0, 0xA2000000, 0x204411, 0, ++ 0, 0x204811, 0, 0x81000000, 0x204411, 0, ++ 2, 0x204811, 0, 0, 0x810130, 0, ++ 0xA2000000, 0x204411, 0, 1, 0x204811, 0, ++ 0x81000000, 0x204411, 0, 2, 0x204811, 0, ++ 0, 0x810130, 0, 0x400, 0x203011, 0, ++ 0x20, 0x80362C, 0, 0, 0x203011, 0, ++ 0x20, 0x80362C, 0, 0x1F, 0x201E2D, 0, ++ 4, 0x291E27, 0, 0x1F, 0x803627, 0, ++ 0x21F9, 0x29462C, 0, 6, 0x204811, 0, ++ 0x5C8, 0x204411, 0, 0x10000, 0x204811, 0, ++ 0xE00, 0x204411, 0, 1, 0x804811, 0, ++ 0, 0xC0400000, 0, 0, 0x800000, 0, ++ 0, 0x1AC00000, 0x282, 0x9F000000, 0x204411, 0, ++ 0xDEADBEEF, 0x204811, 0, 0, 0x1AE00000, 0x285, ++ 0, 0x800000, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, ++ 0x2015E, 0x20002, 0, 0x20002, 0x3D0031, 0, ++ 0x20002, 0x20002, 0, 0x20002, 0x1E00002, 0, ++ 0x7D01F1, 0x200012, 0, 0x20002, 0x2001E, 0, ++ 0x20002, 0x1EF0002, 0, 0x960002, 0xDE0002, 0, ++ 0x20002, 0x20002, 0, 0x20002, 0x20016, 0, ++ 0x20002, 0x20026, 0, 0x14A00EA, 0x20155, 0, ++ 0x2015C, 0x15E0002, 0, 0xEA0002, 0x15E0040, 0, ++ 0xBF0162, 0x20002, 0, 0x1520002, 0x14D0002, 0, ++ 0x20002, 0x13D0130, 0, 0x90160, 0xE000E, 0, ++ 0x6C0051, 0x790074, 0, 0x200E5, 0x20248, 0, ++ 0x20002, 0x20002, 0, 0x20002, 0x20002, 0, ++ 0x20002, 0x20002, 0, 0x20002, 0x20002, 0, ++ 0x20002, 0x20002, 0, 0x20002, 0x20002, 0, ++ 0x20002, 0x20002, 0, 0x50280, 0x20008, 0, ++}; ++ ++static struct { ++ void __iomem *graphics_base; ++ ++ struct circ_buf primary_rb; ++ int rb_size; ++ ++ spinlock_t gfx_lock; ++ spinlock_t write_lock; ++} xenosrb_info; ++ ++/** ++ * xenosrb_reset_ring - Resets ring read/write pointers to 0 ++ * Preferably you would call this with interrupts disabled. ++ */ ++static void xenosrb_reset_ring(void) ++{ ++ int rb_cntl; ++ ++ rb_cntl = in_be32(xenosrb_info.graphics_base + 0x0704); ++ ++ /* CP_RB_CNTL.RB_RPTR_WR_ENA = 1 */ ++ out_be32(xenosrb_info.graphics_base + 0x0704, rb_cntl | 0x80000000); ++ ++ out_be32(xenosrb_info.graphics_base + 0x071C, 0x00000000); /* CP_RB_RPTR_WR */ ++ out_be32(xenosrb_info.graphics_base + 0x0714, 0x00000000); /* CP_RB_WPTR */ ++ udelay(1000); ++ ++ /* CP_RB_CNTL.RB_RPTR_WR_ENA = 0 */ ++ out_be32(xenosrb_info.graphics_base + 0x0704, rb_cntl); ++} ++ ++static void xenosrb_setup_ring(void *buffer_base, size_t buffer_size) ++{ ++ /* CP_RB_CNTL */ ++ /* RB_NO_UPDATE = 1 */ ++ /* BUF_SWAP = 2 */ ++ out_be32(xenosrb_info.graphics_base + 0x0704, ++ 0x08020000 | (ilog2(buffer_size >> 3) & 0xFF)); ++ ++ /* CP_RB_BASE */ ++ out_be32(xenosrb_info.graphics_base + 0x0700, ++ virt_to_phys(buffer_base)); ++} ++ ++/** ++ * xenosrb_wait_gui_idle - Waits for GUI idle or timeout ++ * @timeout_jiffies: maximum number of jiffies to wait ++ * ++ * Returns 0 on success, or %ETIME on timeout. ++ */ ++static int xenosrb_wait_gui_idle(unsigned long timeout_jiffies) ++{ ++ unsigned long start_jiffy = jiffies; ++ ++ /* RBBM_STATUS.GUI_ACTIVE */ ++ while (in_be32(xenosrb_info.graphics_base + 0x1740) & 0x80000000) { ++ if (jiffies - start_jiffy > timeout_jiffies) { ++ return -ETIME; ++ } ++ } ++ ++ return 0; ++} ++ ++/** ++ * xenosrb_upload_pfp_ucode - Upload and verify Prefetch Parser microcode ++ * @ucode: pointer to microcode buffer ++ * ++ * Preferably you would call this with interrupts disabled. ++ * ++ * Returns 0 on success, or %EIO on verification failure. ++ */ ++static int xenosrb_upload_pfp_ucode(const uint32_t *ucode, size_t size) ++{ ++ size_t i; ++ ++ out_be32(xenosrb_info.graphics_base + 0x117C, 0); /* CP_PFP_UCODE_ADDR */ ++ udelay(100); ++ ++ /* Write to CP_PFP_UCODE_DATA */ ++ for (i = 0; i < size; i++) ++ out_be32(xenosrb_info.graphics_base + 0x1180, ucode[i]); ++ ++ /* Readback */ ++ out_be32(xenosrb_info.graphics_base + 0x117C, 0); /* CP_PFP_UCODE_ADDR */ ++ udelay(100); ++ ++ for (i = 0; i < size; i++) { ++ /* Verification doesn't work, as the GPU appears to ignore ++ * CP_PFP_UCODE_ADDR and returns data at an offset :\ */ ++ in_be32(xenosrb_info.graphics_base + 0x1180); ++ } ++ ++ return 0; ++} ++ ++/** ++ * xenosrb_upload_me_ucode - Upload and verify ME microcode ++ * @ucode: pointer to microcode buffer ++ * ++ * Preferably you would call this with interrupts disabled. ++ * ++ * Returns 0 on success, or %EIO on verification failure. ++ */ ++static int xenosrb_upload_me_ucode(const uint32_t *ucode, size_t size) ++{ ++ size_t i; ++ ++ out_be32(xenosrb_info.graphics_base + 0x07E0, 0); /* CP_ME_RAM_WADDR */ ++ udelay(100); ++ ++ /* Write to CP_ME_RAM_DATA */ ++ for (i = 0; i < size; i++) ++ out_be32(xenosrb_info.graphics_base + 0x07E8, ucode[i]); ++ ++ /* Readback and verify from CP_ME_RAM_DATA */ ++ out_be32(xenosrb_info.graphics_base + 0x07E4, 0); /* CP_ME_RAM_RADDR */ ++ udelay(100); ++ ++ for (i = 0; i < size; i++) { ++ if (in_be32(xenosrb_info.graphics_base + 0x07E8) != ucode[i]) { ++ printk(KERN_ERR ++ "%s: failed to verify me microcode @ dword %zu\n", ++ __func__, i); ++ return -EIO; ++ } ++ } ++ ++ return 0; ++} ++ ++static int xenosrb_setup(void *buffer_base, size_t buffer_size) ++{ ++ int rc = 0; ++ ++ out_be32(xenosrb_info.graphics_base + 0x07D8, 0x1000FFFF); /* CP_ME_CNTL.ME_HALT = 1 */ ++ udelay(1000); ++ ++ xenosrb_reset_ring(); ++ xenosrb_setup_ring(buffer_base, buffer_size); ++ ++ rc = xenosrb_upload_pfp_ucode(xenos_pfp_ucode, ++ ARRAY_SIZE(xenos_pfp_ucode)); ++ if (rc) { ++ return rc; ++ } ++ ++ rc = xenosrb_upload_me_ucode(xenos_me_ucode, ++ ARRAY_SIZE(xenos_me_ucode)); ++ if (rc) { ++ return rc; ++ } ++ ++ xenosrb_wait_gui_idle(HZ / 4); ++ ++ out_be32(xenosrb_info.graphics_base + 0x07D8, 0x0000FFFF); /* CP_ME_CNTL.ME_HALT = 0 */ ++ out_be32(xenosrb_info.graphics_base + 0x07D0, 0x0000FFFF); /* CP_INT_ACK.RTS[0..15]ACK = 1 */ ++ out_be32(xenosrb_info.graphics_base + 0x07F0, 0x00000000); /* CP_DEBUG */ ++ out_be32(xenosrb_info.graphics_base + 0x07D8, 0x1000FFFF); /* CP_ME_CNTL.ME_HALT = 1 */ ++ ++ udelay(2000); ++ out_be32(xenosrb_info.graphics_base + 0x00F0, 0x00000001); /* RBBM_SOFT_RESET.SOFT_RESET_CP = 1 */ ++ udelay(1000); ++ out_be32(xenosrb_info.graphics_base + 0x00F0, 0x00000000); /* RBBM_SOFT_RESET.SOFT_RESET_CP = 0 */ ++ udelay(1000); ++ ++ rc = xenosrb_wait_gui_idle(HZ / 4); ++ if (rc) { ++ printk(KERN_ERR "%s: timed out waiting for GUI idle (reset)\n", __func__); ++ return rc; ++ } ++ ++ xenosrb_setup_ring(buffer_base, buffer_size); ++ out_be32(xenosrb_info.graphics_base + 0x07D8, 0x0000FFFF); /* CP_ME_CNTL.ME_HALT = 0 */ ++ ++ rc = xenosrb_wait_gui_idle(HZ / 4); ++ if (rc) { ++ printk(KERN_ERR "%s: timed out waiting for GUI idle (final)\n", __func__); ++ return rc; ++ } ++ ++ return 0; ++} ++ ++static void xenosrb_shutdown(void) ++{ ++ out_be32(xenosrb_info.graphics_base + 0x07D8, 0x10000000); /* CP_ME_CNTL.ME_HALT = 1 */ ++ out_be32(xenosrb_info.graphics_base + 0x0704, 0x00000000); /* CP_RB_CNTL */ ++ out_be32(xenosrb_info.graphics_base + 0x0700, 0x00000000); /* CP_RB_BASE */ ++ xenosrb_reset_ring(); ++} ++ ++static irqreturn_t xenos_interrupt(int irq, void* dev) ++{ ++ return IRQ_HANDLED; ++} ++ ++static ssize_t xenosrb_write(struct file *file, const char __user *buf, ++ size_t count, loff_t *ppos) ++{ ++ struct circ_buf *primary_rb = &xenosrb_info.primary_rb; ++ size_t space; ++ size_t trail_space; ++ int head_ptr; ++ unsigned long flags; ++ ++ if (*ppos || (count & 0x3) != 0x0) ++ return -EINVAL; ++ ++ spin_lock(&xenosrb_info.write_lock); ++ space = CIRC_SPACE(primary_rb->head, primary_rb->tail, ++ xenosrb_info.rb_size); ++ if (space <= count) { ++ /* Update the head pointer and check again */ ++ primary_rb->tail = in_be32(xenosrb_info.graphics_base + 0x0710) / 4; ++ ++ space = CIRC_SPACE(primary_rb->head, primary_rb->tail, ++ xenosrb_info.rb_size); ++ ++ if (space < count) { ++ spin_unlock(&xenosrb_info.write_lock); ++ return -EBUSY; ++ } ++ } ++ ++ trail_space = CIRC_SPACE_TO_END(primary_rb->head, primary_rb->tail, ++ xenosrb_info.rb_size); ++ ++ /* Copy bytes to end of ringbuffer */ ++ if (copy_from_user(primary_rb->buf + primary_rb->head, buf, ++ min(trail_space, count))) { ++ spin_unlock(&xenosrb_info.write_lock); ++ return -EFAULT; ++ } ++ ++ head_ptr = primary_rb->head + min(trail_space, count); ++ ++ if (trail_space < count) { ++ /* Wrap around, copy bytes to beginning of ring buffer. */ ++ if (copy_from_user(primary_rb->buf, buf + trail_space, ++ count - trail_space)) { ++ spin_unlock(&xenosrb_info.write_lock); ++ return -EFAULT; ++ } ++ ++ head_ptr = count - trail_space; ++ } ++ ++ /* Update our tail pointer. */ ++ primary_rb->head = head_ptr & (xenosrb_info.rb_size - 1); ++ ++ /* Flush the CPU cache. */ ++ flush_dcache_range((uintptr_t)primary_rb->buf, ++ (uintptr_t)primary_rb->buf + xenosrb_info.rb_size); ++ ++ spin_lock_irqsave(&xenosrb_info.gfx_lock, flags); ++ out_be32(xenosrb_info.graphics_base + 0x0714, ++ primary_rb->head / 4); /* CP_RB_WPTR */ ++ spin_unlock_irqrestore(&xenosrb_info.gfx_lock, flags); ++ ++ spin_unlock(&xenosrb_info.write_lock); ++ return count; ++} ++ ++static long xenosrb_ioctl(struct file *file, unsigned int cmd, ++ unsigned long arg) ++{ ++ unsigned long flags; ++ ++ switch (cmd) { ++ case IOCTL_RESET: ++ spin_lock_irqsave(&xenosrb_info.gfx_lock, flags); ++ ++ out_be32(xenosrb_info.graphics_base + 0x07D8, 0x1000FFFF); /* CP_ME_CNTL.ME_HALT = 1 */ ++ xenosrb_reset_ring(); ++ xenosrb_info.primary_rb.head = 0; ++ xenosrb_info.primary_rb.tail = 0; ++ out_be32(xenosrb_info.graphics_base + 0x07D8, 0x0000FFFF); /* CP_ME_CNTL.ME_HALT = 0 */ ++ ++ spin_unlock_irqrestore(&xenosrb_info.gfx_lock, flags); ++ return 0; ++ } ++ ++ return -EINVAL; ++} ++ ++static const struct file_operations xenos_fops = { ++ .write = xenosrb_write, ++ .open = nonseekable_open, ++ .unlocked_ioctl = xenosrb_ioctl, ++}; ++ ++static struct miscdevice xenosrb_dev = { ++ .minor = MISC_DYNAMIC_MINOR, ++ "xenosrb", ++ &xenos_fops ++}; ++ ++static int xenosrb_probe(struct pci_dev *dev, ++ const struct pci_device_id *dev_id) ++{ ++ unsigned long flags; ++ unsigned long mmio_start, mmio_len, mmio_flags; ++ int rc = 0; ++ ++ if (!dev) { ++ return -EINVAL; ++ } ++ ++ if ((rc = pci_enable_device(dev))) { ++ goto err_out; ++ } ++ ++ mmio_flags = pci_resource_flags(dev, 0); ++ if (!(mmio_flags & IORESOURCE_MEM)) { ++ dev_err(&dev->dev, ++ "%s: region #0 is not a MEM resource, abort!", ++ __func__); ++ rc = -ENODEV; ++ goto err_release_pci_device; ++ } ++ ++ mmio_start = pci_resource_start(dev, 0); ++ mmio_len = pci_resource_len(dev, 0); ++ ++ /* We're going to request all regions, even though there's only one. */ ++ if (!mmio_len || (rc = pci_request_regions(dev, dev->dev.kobj.name))) { ++ dev_err(&dev->dev, ++ "%s: failed to request I/O regions (code %d)", __func__, ++ rc); ++ rc = -EBUSY; ++ goto err_release_pci_device; ++ } ++ ++ xenosrb_info.graphics_base = ioremap(mmio_start, mmio_len); ++ if (!xenosrb_info.graphics_base) { ++ printk(KERN_ERR "%s: failed to ioremap gfx regs\n", __func__); ++ rc = -EIO; ++ goto err_release_pci_regions; ++ } ++ ++ rc = misc_register(&xenosrb_dev); ++ if (rc) { ++ goto err_release_reg; ++ } ++ ++ xenosrb_info.rb_size = 1 << (ilog2(xenosrb_size) & 0xFF); ++ xenosrb_info.primary_rb.buf = kzalloc(xenosrb_info.rb_size, GFP_KERNEL); ++ if (!xenosrb_info.primary_rb.buf) { ++ rc = -ENOMEM; ++ goto err_unregister_dev; ++ } ++ ++ spin_lock_init(&xenosrb_info.gfx_lock); ++ spin_lock_init(&xenosrb_info.write_lock); ++ ++ /* Setup the ringbuffer with interrupts disabled */ ++ spin_lock_irqsave(&xenosrb_info.gfx_lock, flags); ++ ++ if (xenosrb_setup(xenosrb_info.primary_rb.buf, xenosrb_info.rb_size)) { ++ spin_unlock_irqrestore(&xenosrb_info.gfx_lock, flags); ++ rc = -EIO; ++ goto err_free_rb; ++ } ++ ++ xenosrb_info.primary_rb.head = 0; ++ xenosrb_info.primary_rb.tail = 0; ++ ++ /* CP_RB_WPTR_DELAY */ ++ out_be32(xenosrb_info.graphics_base + 0x0718, 0x0010); ++ ++ spin_unlock_irqrestore(&xenosrb_info.gfx_lock, flags); ++ ++ rc = request_irq(dev->irq, xenos_interrupt, IRQF_SHARED, "Xenos", dev); ++ if (rc) { ++ printk(KERN_ERR "%s: failed to request IRQ 0x%.2X\n", __func__, ++ dev->irq); ++ } ++ ++ printk("XenosRB Character Driver Initialized, ring size = %d\n", ++ xenosrb_info.rb_size); ++ return 0; ++ ++ xenosrb_reset_ring(); ++err_free_rb: ++ kfree(xenosrb_info.primary_rb.buf); ++err_unregister_dev: ++ misc_deregister(&xenosrb_dev); ++err_release_reg: ++ iounmap(xenosrb_info.graphics_base); ++err_release_pci_regions: ++ pci_release_regions(dev); ++err_release_pci_device: ++ pci_disable_device(dev); ++err_out: ++ return rc; ++} ++ ++static void xenosrb_remove(struct pci_dev *dev) ++{ ++ unsigned long flags; ++ ++ disable_irq(dev->irq); ++ free_irq(dev->irq, dev); ++ misc_deregister(&xenosrb_dev); ++ ++ spin_lock_irqsave(&xenosrb_info.gfx_lock, flags); ++ xenosrb_shutdown(); ++ ++ spin_unlock_irqrestore(&xenosrb_info.gfx_lock, flags); ++ ++ kfree(xenosrb_info.primary_rb.buf); ++ iounmap(xenosrb_info.graphics_base); ++ pci_release_regions(dev); ++} ++ ++#define XENOSRB_CHR_DEV_NAME "xenos_rb" ++ ++static const struct pci_device_id xenos_pci_tbl[] = { ++ {PCI_VDEVICE(MICROSOFT, 0x5811), 0}, /* xenon */ ++ {PCI_VDEVICE(MICROSOFT, 0x5821), 0}, /* zephyr/falcon */ ++ {PCI_VDEVICE(MICROSOFT, 0x5831), 0}, /* jasper */ ++ {PCI_VDEVICE(MICROSOFT, 0x5841), 0}, /* slim */ ++ ++ {} /* terminate list */ ++}; ++ ++static struct pci_driver xenosrb_pci = { ++ .name = "xenos_rb", ++ .id_table = xenos_pci_tbl, ++ .probe = xenosrb_probe, ++ .remove = xenosrb_remove, ++}; ++ ++static int __init xenosrb_init(void) ++{ ++ int rc; ++ ++ if ((rc = pci_register_driver(&xenosrb_pci))) { ++ printk(KERN_ERR "%s: pci_register_driver failed with %d", ++ __func__, rc); ++ goto err_out; ++ } ++ ++ return 0; ++ ++err_out: ++ return rc; ++} ++ ++static void __exit xenosrb_exit(void) ++{ ++ pci_unregister_driver(&xenosrb_pci); ++} ++ ++module_init(xenosrb_init); ++module_exit(xenosrb_exit); ++ ++MODULE_AUTHOR("Justin Moore "); ++MODULE_DESCRIPTION("Ring Buffer Driver for Xenos GPU"); ++MODULE_LICENSE("GPL"); ++MODULE_VERSION(DRV_VERSION); +\ No newline at end of file +diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig +index 51f1caa10..fd1fa53b4 100644 +--- a/drivers/hwmon/Kconfig ++++ b/drivers/hwmon/Kconfig +@@ -2178,6 +2178,13 @@ config SENSORS_INTEL_M10_BMC_HWMON + sensors monitor various telemetry data of different components on the + card, e.g. board temperature, FPGA core temperature/voltage/current. + ++config SENSORS_XENON ++ tristate "Xenon SMC" ++ depends on PPC_XENON ++ help ++ This driver provides support for the Xenon SMC sensors and ++ fan control. ++ + if ACPI + + comment "ACPI drivers" +diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile +index 162940270..f005911d5 100644 +--- a/drivers/hwmon/Makefile ++++ b/drivers/hwmon/Makefile +@@ -200,6 +200,7 @@ obj-$(CONFIG_SENSORS_W83L785TS) += w83l785ts.o + obj-$(CONFIG_SENSORS_W83L786NG) += w83l786ng.o + obj-$(CONFIG_SENSORS_WM831X) += wm831x-hwmon.o + obj-$(CONFIG_SENSORS_WM8350) += wm8350-hwmon.o ++obj-$(CONFIG_SENSORS_XENON) += xenon-hwmon.o + obj-$(CONFIG_SENSORS_XGENE) += xgene-hwmon.o + + obj-$(CONFIG_SENSORS_OCC) += occ/ +diff --git a/drivers/hwmon/xenon-hwmon.c b/drivers/hwmon/xenon-hwmon.c +new file mode 100644 +index 000000000..5164f6221 +--- /dev/null ++++ b/drivers/hwmon/xenon-hwmon.c +@@ -0,0 +1,200 @@ ++/* ++ * Xenon HW Monitor via SMC driver. ++ * ++ * Copyright (C) 2010 Herbert Poetzl ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; version 2 of the License. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define DRV_NAME "xenon-hwmon" ++#define DRV_VERSION "0.1" ++ ++#if 0 ++struct hwmon { ++ spinlock_t lock; ++ ++ struct device *xenon_hwmon_dev; ++}; ++#endif ++static unsigned int fan_speed[2]; ++ ++int xenon_smc_message_wait(void *msg); ++ ++static unsigned long xenon_get_temp(unsigned nr) ++{ ++ unsigned char msg[16] = { 0x07 }; ++ static unsigned int temp[4] = { 0 }; ++ ++ /* FIXME: only every N jiffies */ ++ xenon_smc_message_wait(msg); ++ temp[0] = (msg[1] | (msg[2] << 8)) * 1000 / 256; ++ temp[1] = (msg[3] | (msg[4] << 8)) * 1000 / 256; ++ temp[2] = (msg[5] | (msg[6] << 8)) * 1000 / 256; ++ temp[3] = (msg[7] | (msg[8] << 8)) * 1000 / 256; ++ ++ return temp[nr & 3]; ++} ++ ++void xenon_smc_message(void *msg); ++ ++static int xenon_set_cpu_fan_speed(unsigned val) ++{ ++ unsigned char msg[16] = { 0x94, (val & 0x7F) | 0x80 }; ++ ++ xenon_smc_message(msg); ++ return 0; ++} ++ ++static int xenon_set_gpu_fan_speed(unsigned val) ++{ ++ unsigned char msg[16] = { 0x89, (val & 0x7F) | 0x80 }; ++ ++ xenon_smc_message(msg); ++ return 0; ++} ++ ++ ++static ssize_t show_fan_speed(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ int fan_nr = to_sensor_dev_attr(attr)->index; ++ // void *p = dev_get_drvdata(dev); ++ ++ return sprintf(buf, "%u\n", fan_speed[fan_nr]); ++} ++ ++static ssize_t set_fan_speed(struct device *dev, struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ int fan_nr = to_sensor_dev_attr(attr)->index; ++ unsigned int val = simple_strtol(buf, NULL, 10); ++ // void *p = dev_get_drvdata(dev); ++ ++ fan_speed[fan_nr] = val & 0xFF; ++ ++ if (fan_nr == 0) ++ xenon_set_cpu_fan_speed(val); ++ if (fan_nr == 1) ++ xenon_set_gpu_fan_speed(val); ++ ++ return count; ++} ++ ++static SENSOR_DEVICE_ATTR(cpu_fan_speed, S_IRUGO | S_IWUSR, ++ show_fan_speed, set_fan_speed, 0); ++static SENSOR_DEVICE_ATTR(gpu_fan_speed, S_IRUGO | S_IWUSR, ++ show_fan_speed, set_fan_speed, 1); ++ ++static ssize_t show_temp(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ int temp_nr = to_sensor_dev_attr(attr)->index; ++ // struct dev *p = dev_get_drvdata(pdev); ++ unsigned temp = xenon_get_temp(temp_nr); ++ ++ return sprintf(buf, "%d\n", temp); ++} ++ ++static SENSOR_DEVICE_ATTR(cpu_temp, S_IRUGO, show_temp, NULL, 0); ++static SENSOR_DEVICE_ATTR(gpu_temp, S_IRUGO, show_temp, NULL, 1); ++static SENSOR_DEVICE_ATTR(edram_temp, S_IRUGO, show_temp, NULL, 2); ++static SENSOR_DEVICE_ATTR(motherboard_temp, S_IRUGO, show_temp, NULL, 3); ++ ++static ssize_t show_name(struct device *dev, struct device_attribute *attr, char *buf) ++{ ++ return sprintf(buf, "xenon\n"); ++} ++ ++static SENSOR_DEVICE_ATTR(name, S_IRUGO, show_name, NULL, 0); ++ ++static struct attribute *xenon_hwmon_attributes[] = { ++ &sensor_dev_attr_cpu_fan_speed.dev_attr.attr, ++ &sensor_dev_attr_gpu_fan_speed.dev_attr.attr, ++ &sensor_dev_attr_cpu_temp.dev_attr.attr, ++ &sensor_dev_attr_gpu_temp.dev_attr.attr, ++ &sensor_dev_attr_edram_temp.dev_attr.attr, ++ &sensor_dev_attr_motherboard_temp.dev_attr.attr, ++ &sensor_dev_attr_name.dev_attr.attr, ++ NULL, ++}; ++ ++static const struct attribute_group xenon_hwmon_group = { ++ .attrs = xenon_hwmon_attributes, ++}; ++ ++static int __init xenon_hwmon_probe(struct platform_device *pdev) ++{ ++ struct device *dev; ++ int err; ++ ++ err = sysfs_create_group(&pdev->dev.kobj, &xenon_hwmon_group); ++ if (err) ++ goto out; ++ ++ dev = hwmon_device_register(&pdev->dev); ++ if (IS_ERR(dev)) { ++ err = PTR_ERR(dev); ++ goto out_sysfs_remove_group; ++ } ++ ++ platform_set_drvdata(pdev, dev); ++ return 0; ++ ++out_sysfs_remove_group: ++ sysfs_remove_group(&pdev->dev.kobj, &xenon_hwmon_group); ++out: ++ return err; ++} ++ ++static int __exit xenon_hwmon_remove(struct platform_device *pdev) ++{ ++ hwmon_device_unregister(&pdev->dev); ++ sysfs_remove_group(&pdev->dev.kobj, &xenon_hwmon_group); ++ return 0; ++} ++ ++ ++static struct platform_driver xenon_hwmon_driver = { ++ .driver = { ++ .name = DRV_NAME, ++ .owner = THIS_MODULE, ++ }, ++ .remove = __exit_p(xenon_hwmon_remove), ++}; ++ ++static int __init xenon_hwmon_init(void) ++{ ++ int ret = platform_driver_probe(&xenon_hwmon_driver, xenon_hwmon_probe); ++ ++ printk("xenon_hwmon_init() = %d\n", ret); ++ return ret; ++} ++ ++static void __exit xenon_hwmon_exit(void) ++{ ++ platform_driver_unregister(&xenon_hwmon_driver); ++} ++ ++module_init(xenon_hwmon_init); ++module_exit(xenon_hwmon_exit); ++ ++MODULE_AUTHOR("Herbert Poetzl "); ++MODULE_DESCRIPTION("Character Interface for Xenon (H)ana"); ++MODULE_LICENSE("GPL"); ++MODULE_VERSION(DRV_VERSION); +\ No newline at end of file +diff --git a/drivers/net/ethernet/Kconfig b/drivers/net/ethernet/Kconfig +index 35ac6fe75..c8a58f8e2 100644 +--- a/drivers/net/ethernet/Kconfig ++++ b/drivers/net/ethernet/Kconfig +@@ -185,5 +185,6 @@ source "drivers/net/ethernet/via/Kconfig" + source "drivers/net/ethernet/wiznet/Kconfig" + source "drivers/net/ethernet/xilinx/Kconfig" + source "drivers/net/ethernet/xircom/Kconfig" ++source "drivers/net/ethernet/xenon/Kconfig" + + endif # ETHERNET +diff --git a/drivers/net/ethernet/Makefile b/drivers/net/ethernet/Makefile +index aaa5078cd..a9dd2861b 100644 +--- a/drivers/net/ethernet/Makefile ++++ b/drivers/net/ethernet/Makefile +@@ -95,5 +95,6 @@ obj-$(CONFIG_NET_VENDOR_VIA) += via/ + obj-$(CONFIG_NET_VENDOR_WIZNET) += wiznet/ + obj-$(CONFIG_NET_VENDOR_XILINX) += xilinx/ + obj-$(CONFIG_NET_VENDOR_XIRCOM) += xircom/ ++obj-$(CONFIG_NET_XENON) += xenon/ + obj-$(CONFIG_NET_VENDOR_SYNOPSYS) += synopsys/ + obj-$(CONFIG_NET_VENDOR_PENSANDO) += pensando/ +diff --git a/drivers/net/ethernet/xenon/Kconfig b/drivers/net/ethernet/xenon/Kconfig +new file mode 100644 +index 000000000..4fc54caf8 +--- /dev/null ++++ b/drivers/net/ethernet/xenon/Kconfig +@@ -0,0 +1,3 @@ ++config NET_XENON ++ tristate "Xenon Fast Ethernet Adapter support" ++ depends on PCI +diff --git a/drivers/net/ethernet/xenon/Makefile b/drivers/net/ethernet/xenon/Makefile +new file mode 100644 +index 000000000..cf4ca70b9 +--- /dev/null ++++ b/drivers/net/ethernet/xenon/Makefile +@@ -0,0 +1 @@ ++obj-$(CONFIG_NET_XENON) += xenon_net.o +\ No newline at end of file +diff --git a/drivers/net/ethernet/xenon/xenon_net.c b/drivers/net/ethernet/xenon/xenon_net.c +new file mode 100644 +index 000000000..1f2bafe4e +--- /dev/null ++++ b/drivers/net/ethernet/xenon/xenon_net.c +@@ -0,0 +1,768 @@ ++/* ++ * xenon_net.c: Driver for Xenon Southbridge Fast Ethernet ++ * ++ * Copyright 2007 Felix Domke ++ * Minor modification by: wolie ++ * More modifications by: Justin Moore ++ * ++ * Licensed under the GPL v2. ++ */ ++ ++// Documentation for NAPI can be found at: ++// https://wiki.linuxfoundation.org/networking/napi ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++#define DEBUG ++#if defined(DEBUG) ++#define DBG udbg_printf ++#else ++#define DBG pr_debug ++#endif ++ ++#define XENONNET_VERSION "1.0.1" ++#define MODNAME "xenon_net" ++#define XENONNET_DRIVER_LOAD_MSG \ ++ "Xenon Fast Ethernet driver " XENONNET_VERSION " loaded" ++#define PFX MODNAME ": " ++ ++#define RX_RING_SIZE 16 ++#define TX_RING_SIZE 16 ++ ++#define TX_TIMEOUT (6 * HZ) ++ ++static char version[] = KERN_INFO XENONNET_DRIVER_LOAD_MSG "\n"; ++ ++static struct pci_device_id xenon_net_pci_tbl[] = { ++ {PCI_VENDOR_ID_MICROSOFT, 0x580a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, ++ { ++ 0, ++ }}; ++ ++MODULE_DEVICE_TABLE(pci, xenon_net_pci_tbl); ++ ++/* Symbolic offsets to registers. */ ++enum XENONNET_registers { ++ TX_CONFIG = 0x00, ++ TX_DESCRIPTOR_BASE = 0x04, ++ TX_DESCRIPTOR_STATUS = 0x0C, ++ RX_CONFIG = 0x10, ++ RX_DESCRIPTOR_BASE = 0x14, ++ INTERRUPT_STATUS = 0x20, ++ INTERRUPT_MASK = 0x24, ++ CONFIG_0 = 0x28, ++ POWER = 0x30, ++ PHY_CONFIG = 0x40, ++ PHY_CONTROL = 0x44, ++ CONFIG_1 = 0x50, ++ RETRY_COUNT = 0x54, ++ MULTICAST_FILTER_CONTROL = 0x60, ++ ADDRESS_0 = 0x62, ++ MULTICAST_HASH = 0x68, ++ MAX_PACKET_SIZE = 0x78, ++ ADDRESS_1 = 0x7A ++}; ++ ++struct xenon_net_private { ++ void *mmio_addr; ++ ++ struct net_device *dev2; ++ struct napi_struct napi; ++ ++ struct pci_dev *pdev; ++ struct net_device_stats stats; ++ ++ /* we maintain a list of rx and tx descriptors */ ++ void *tx_descriptor_base; ++ void *rx_descriptor_base; ++ dma_addr_t tx_descriptor_base_dma; ++ dma_addr_t rx_descriptor_base_dma; ++ ++ struct sk_buff *rx_skbuff[RX_RING_SIZE]; ++ dma_addr_t rx_skbuff_dma[RX_RING_SIZE]; ++ ++ struct sk_buff *tx_skbuff[TX_RING_SIZE]; ++ dma_addr_t tx_skbuff_dma[TX_RING_SIZE]; ++ ++ atomic_t tx_next_free, tx_next_done; ++ ++ int rx_buf_sz, rx_next; ++ ++ spinlock_t lock; ++}; ++ ++static void xenon_set_tx_descriptor(struct xenon_net_private *tp, int index, ++ u32 len, dma_addr_t addr, int valid) ++{ ++ volatile u32 *descr = tp->tx_descriptor_base + index * 0x10; ++ descr[0] = cpu_to_le32(len); ++ descr[2] = cpu_to_le32(addr); ++ descr[3] = ++ cpu_to_le32(len | ((index == TX_RING_SIZE - 1) ? 0x80000000 : 0)); ++ wmb(); ++ if (valid) ++ descr[1] = cpu_to_le32(0xc0230000); ++ else ++ descr[1] = 0; ++} ++ ++static void xenon_set_rx_descriptor(struct xenon_net_private *tp, int index, ++ u32 len, dma_addr_t addr, int valid) ++{ ++ volatile u32 *descr = tp->rx_descriptor_base + index * 0x10; ++ descr[0] = cpu_to_le32(0); ++ descr[2] = cpu_to_le32(addr); ++ descr[3] = ++ cpu_to_le32(len | ((index == RX_RING_SIZE - 1) ? 0x80000000 : 0)); ++ wmb(); ++ if (valid) ++ descr[1] = cpu_to_le32(0xc0000000); ++ else ++ descr[1] = 0; ++} ++ ++static int xenon_net_tx_interrupt(struct net_device *dev, ++ struct xenon_net_private *tp, void *ioaddr) ++{ ++ int work = 0; ++ ++ BUG_ON(dev == NULL); ++ BUG_ON(tp == NULL); ++ BUG_ON(ioaddr == NULL); ++ ++ while (atomic_read(&tp->tx_next_free) != ++ atomic_read(&tp->tx_next_done)) { ++ int e = atomic_read(&tp->tx_next_done) % TX_RING_SIZE; ++ ++ volatile u32 *descr = tp->tx_descriptor_base + e * 0x10; ++ if (le32_to_cpu(descr[1]) & 0x80000000) ++ break; ++ ++ if (!tp->tx_skbuff[e]) { ++ printk(KERN_WARNING "spurious TX complete?!\n"); ++ break; ++ } ++ ++ work++; ++ pci_unmap_single(tp->pdev, tp->tx_skbuff_dma[e], ++ tp->tx_skbuff[e]->len, PCI_DMA_TODEVICE); ++ dev_kfree_skb_irq(tp->tx_skbuff[e]); ++ ++ tp->tx_skbuff[e] = 0; ++ tp->tx_skbuff_dma[e] = 0; ++ ++ atomic_inc(&tp->tx_next_done); ++ } ++ ++ if ((atomic_read(&tp->tx_next_free) - atomic_read(&tp->tx_next_done)) < ++ TX_RING_SIZE) ++ netif_start_queue(dev); ++ ++ return work; ++} ++ ++static int xenon_net_rx_interrupt(struct net_device *dev, ++ struct xenon_net_private *tp, void *ioaddr, ++ int budget) ++{ ++ int received = 0; // count and send to work_done ++ ++ BUG_ON(dev == NULL); ++ BUG_ON(tp == NULL); ++ BUG_ON(ioaddr == NULL); ++ BUG_ON(tp->rx_descriptor_base == NULL); ++ ++ while (1) { ++ u32 size; ++ dma_addr_t mapping; ++ int index = tp->rx_next; ++ volatile u32 *descr = tp->rx_descriptor_base + index * 0x10; ++ struct sk_buff *skb = tp->rx_skbuff[index], *new_skb; ++ ++ // no data available ++ if (le32_to_cpu(descr[1]) & 0x80000000) ++ break; ++ ++ if (received >= budget) ++ break; /* Over-budget. */ ++ ++ new_skb = netdev_alloc_skb(dev, tp->rx_buf_sz); ++ if (!new_skb) ++ break; /* Failed to alloc memory, we'll break off and try again later. */ ++ ++ size = le32_to_cpu(descr[0]) & 0xFFFF; ++ mapping = tp->rx_skbuff_dma[index]; ++ pci_unmap_single(tp->pdev, mapping, tp->rx_buf_sz, ++ PCI_DMA_FROMDEVICE); ++ ++ skb->ip_summed = CHECKSUM_NONE; ++ skb_put(skb, size); ++ skb->protocol = eth_type_trans(skb, dev); ++ ++ netif_receive_skb(skb); ++ received++; ++ ++ mapping = tp->rx_skbuff_dma[index] = pci_map_single( ++ tp->pdev, new_skb->data, tp->rx_buf_sz, PCI_DMA_FROMDEVICE); ++ tp->rx_skbuff[index] = new_skb; ++ ++ xenon_set_rx_descriptor(tp, index, tp->rx_buf_sz, ++ tp->rx_skbuff_dma[index], 1); ++ ++ tp->rx_next = (tp->rx_next + 1) % RX_RING_SIZE; ++ } ++ ++ if (received > 0) { ++ /* enable RX */ ++ writel(0x00101c11, ioaddr + RX_CONFIG); ++ } ++ ++ return received; ++} ++ ++static int xenon_net_poll(struct napi_struct *napi, int budget) ++{ ++ int work_done; ++ struct xenon_net_private *tp; ++ struct net_device *dev; ++ ++ tp = container_of(napi, struct xenon_net_private, napi); ++ BUG_ON(tp == NULL); ++ ++ dev = tp->dev2; ++ BUG_ON(dev == NULL); ++ ++ work_done = xenon_net_rx_interrupt(dev, tp, tp->mmio_addr, budget); ++ ++ /* Process the transmission ring */ ++ if (xenon_net_tx_interrupt(dev, tp, tp->mmio_addr) == TX_RING_SIZE) { ++ /* We've processed the entire ring, so count it against the rest of the budget. */ ++ work_done = max(work_done, budget); ++ } ++ ++ if (work_done < budget) { ++ /* Re-enable network interrupts. */ ++ writel(0x00010044, tp->mmio_addr + INTERRUPT_MASK); ++ napi_complete(napi); ++ } ++ ++ return work_done; ++} ++ ++static irqreturn_t xenon_net_interrupt(int irq, void *dev_id) ++{ ++ struct net_device *dev = dev_id; ++ struct xenon_net_private *tp = netdev_priv(dev); ++ void *ioaddr = tp->mmio_addr; ++ u32 status; ++ ++ spin_lock(&tp->lock); ++ status = readl(ioaddr + INTERRUPT_STATUS); ++ ++ /* tx or rx interrupt */ ++ if (status & 0x0000004C) { ++ /* Disable interrupts. */ ++ writel(0, ioaddr + INTERRUPT_MASK); ++ ++ if (napi_schedule_prep(&tp->napi)) { ++ __napi_schedule(&tp->napi); ++ } ++ } ++ ++ spin_unlock(&tp->lock); ++ return IRQ_HANDLED; ++} ++ ++#if defined(CONFIG_NET_POLL_CONTROLLER) ++/* ++ * Polling receive - used by netconsole and other diagnostic tools ++ * to allow network i/o with interrupts disabled. ++ */ ++static void xenon_net_poll_controller(struct net_device *dev) ++{ ++ struct xenon_net_private *tp = netdev_priv(dev); ++ napi_schedule(&tp->napi); ++} ++#endif ++ ++/* Initialize the Rx and Tx rings, along with various 'dev' bits. */ ++static void xenon_net_init_ring(struct net_device *dev) ++{ ++ struct xenon_net_private *tp = netdev_priv(dev); ++ int i; ++ ++ tp->rx_next = 0; ++ atomic_set(&tp->tx_next_done, 0); ++ atomic_set(&tp->tx_next_free, 0); ++ ++ for (i = 0; i < TX_RING_SIZE; i++) { ++ tp->tx_skbuff[i] = NULL; ++ tp->tx_skbuff_dma[i] = 0; ++ } ++ ++ /* allocate descriptor memory */ ++ tp->tx_descriptor_base = pci_alloc_consistent( ++ tp->pdev, TX_RING_SIZE * 0x10 + RX_RING_SIZE * 0x10, ++ &tp->tx_descriptor_base_dma); ++ ++ /* rx is right after tx */ ++ tp->rx_descriptor_base = tp->tx_descriptor_base + TX_RING_SIZE * 0x10; ++ tp->rx_descriptor_base_dma = ++ tp->tx_descriptor_base_dma + TX_RING_SIZE * 0x10; ++ ++ for (i = 0; i < TX_RING_SIZE; ++i) ++ xenon_set_tx_descriptor(tp, i, 0, 0, 0); ++ ++ tp->rx_buf_sz = dev->mtu + 32; ++ ++ for (i = 0; i < RX_RING_SIZE; ++i) { ++ struct sk_buff *skb = dev_alloc_skb(tp->rx_buf_sz); ++ tp->rx_skbuff[i] = skb; ++ if (skb == NULL) ++ break; ++ ++ skb->dev = dev; /* Mark as being used by this device. */ ++ tp->rx_skbuff_dma[i] = pci_map_single( ++ tp->pdev, skb->data, tp->rx_buf_sz, PCI_DMA_FROMDEVICE); ++ ++ xenon_set_rx_descriptor(tp, i, tp->rx_buf_sz, ++ tp->rx_skbuff_dma[i], 1); ++ } ++} ++ ++static int xenon_net_set_mac(struct net_device *dev, void *p) ++{ ++ struct xenon_net_private *tp = netdev_priv(dev); ++ void *ioaddr = tp->mmio_addr; ++ struct sockaddr *addr = p; ++ ++ if (!is_valid_ether_addr(addr->sa_data)) ++ return -EADDRNOTAVAIL; ++ ++ /* Write the MAC */ ++ writew(cpu_to_le16(*(u16 *)(addr->sa_data)), ioaddr + ADDRESS_0); ++ writel(cpu_to_le32(*(u32 *)(addr->sa_data + 2)), ++ ioaddr + ADDRESS_0 + 2); ++ ++ writew(cpu_to_le16(*(u16 *)(addr->sa_data)), ioaddr + ADDRESS_1); ++ writel(cpu_to_le32(*(u32 *)(addr->sa_data + 2)), ++ ioaddr + ADDRESS_1 + 2); ++ ++ memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN); ++ return 0; ++} ++ ++/* Start the hardware at open or resume. */ ++static void xenon_net_hw_start(struct net_device *dev) ++{ ++ struct xenon_net_private *tp = netdev_priv(dev); ++ void *ioaddr = tp->mmio_addr; ++ ++ /* Soft reset the chip. */ ++ writel(0, ioaddr + INTERRUPT_MASK); ++ writel(0x08558001, ioaddr + CONFIG_0); ++ udelay(100); ++ writel(0x08550001, ioaddr + CONFIG_0); ++ ++ writel(4, ioaddr + PHY_CONTROL); ++ udelay(100); ++ writel(0, ioaddr + PHY_CONTROL); ++ ++ writew(1522, ioaddr + MAX_PACKET_SIZE); ++ ++ writel(0x2360, ioaddr + CONFIG_1); ++ ++ writew(0x0e38, ioaddr + MULTICAST_FILTER_CONTROL); ++ ++ /* Restore our idea of the MAC address. */ ++ writew(cpu_to_le16(*(u16 *)(dev->dev_addr + 0)), ioaddr + ADDRESS_0); ++ writel(cpu_to_le32(*(u32 *)(dev->dev_addr + 2)), ++ ioaddr + ADDRESS_0 + 2); ++ ++ writew(cpu_to_le16(*(u16 *)(dev->dev_addr + 0)), ioaddr + ADDRESS_1); ++ writel(cpu_to_le32(*(u32 *)(dev->dev_addr + 2)), ++ ioaddr + ADDRESS_1 + 2); ++ ++ writel(0, ioaddr + MULTICAST_HASH); ++ writel(0, ioaddr + MULTICAST_HASH + 4); ++ ++ writel(0x00001c00, ioaddr + TX_CONFIG); ++ writel(0x00101c00, ioaddr + RX_CONFIG); ++ ++ writel(0x04001901, ioaddr + PHY_CONFIG); ++ ++ tp->rx_next = 0; ++ ++ /* write base 0 */ ++ writel(0x00001c00, ioaddr + TX_CONFIG); ++ writel(tp->tx_descriptor_base_dma, ioaddr + TX_DESCRIPTOR_BASE); ++ ++ /* write base 1 */ ++ writel(0x00011c00, ioaddr + TX_CONFIG); ++ writel(tp->tx_descriptor_base_dma, ioaddr + TX_DESCRIPTOR_BASE); ++ writel(0x00001c00, ioaddr + TX_CONFIG); ++ ++ writel(tp->rx_descriptor_base_dma, ioaddr + RX_DESCRIPTOR_BASE); ++ writel(0x04001001, ioaddr + PHY_CONFIG); ++ writel(0, ioaddr + CONFIG_1); ++ ++ writel(0x08550001, ioaddr + CONFIG_0); ++ ++ writel(0x00001c01, ioaddr + TX_CONFIG); /* enable tx */ ++ writel(0x00101c11, ioaddr + RX_CONFIG); /* enable rx */ ++ ++ // Interrupts: ++ // 0x20000000 = ?? ++ // 0x00010000 = multicast related ++ // 0x00000040 = rx ++ // 0x00000008 = tx (1) ++ // 0x00000004 = tx (0) ++ writel(0x00010044, ioaddr + INTERRUPT_MASK); ++ writel(0x00010044, ioaddr + INTERRUPT_STATUS); ++ ++ netif_start_queue(dev); ++} ++ ++static int xenon_net_start_xmit(struct sk_buff *skb, struct net_device *dev) ++{ ++ struct xenon_net_private *tp = netdev_priv(dev); ++ void *ioaddr = tp->mmio_addr; ++ int entry; ++ dma_addr_t mapping; ++ u32 len; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&tp->lock, flags); ++ ++ /* Calculate the next Tx descriptor entry. */ ++ entry = atomic_read(&tp->tx_next_free) % TX_RING_SIZE; ++ ++ BUG_ON(tp->tx_skbuff[entry] != NULL); ++ BUG_ON(tp->tx_skbuff_dma[entry] != 0); ++ BUG_ON(skb_shinfo(skb)->nr_frags != 0); ++ ++ tp->tx_skbuff[entry] = skb; ++ ++ len = skb->len; ++ ++ mapping = pci_map_single(tp->pdev, skb->data, len, PCI_DMA_TODEVICE); ++ tp->tx_skbuff_dma[entry] = mapping; ++ ++ xenon_set_tx_descriptor(tp, entry, skb->len, mapping, 1); ++ ++ atomic_inc(&tp->tx_next_free); ++ if ((atomic_read(&tp->tx_next_free) - atomic_read(&tp->tx_next_done)) >= ++ TX_RING_SIZE) { ++ netif_stop_queue(dev); ++ } ++ ++ writel(0x00101c11, ioaddr + TX_CONFIG); /* enable TX */ ++ ++ spin_unlock_irqrestore(&tp->lock, flags); ++ ++ return NETDEV_TX_OK; ++} ++ ++static void xenon_net_tx_clear(struct xenon_net_private *tp) ++{ ++ int i; ++ ++ atomic_set(&tp->tx_next_free, 0); ++ atomic_set(&tp->tx_next_done, 0); ++ ++ /* Dump the unsent Tx packets. */ ++ for (i = 0; i < TX_RING_SIZE; i++) { ++ if (tp->tx_skbuff_dma[i] != 0) { ++ pci_unmap_single(tp->pdev, tp->tx_skbuff_dma[i], ++ tp->tx_skbuff[i]->len, ++ PCI_DMA_TODEVICE); ++ } ++ if (tp->tx_skbuff[i]) { ++ dev_kfree_skb(tp->tx_skbuff[i]); ++ tp->tx_skbuff[i] = NULL; ++ tp->stats.tx_dropped++; ++ } ++ } ++} ++ ++static void xenon_net_tx_timeout(struct net_device *dev, unsigned int txqueue) ++{ ++ /* Error handling was taken from eexpress.c */ ++ struct xenon_net_private *tp = netdev_priv(dev); ++ void *ioaddr = tp->mmio_addr; ++ unsigned long flags; ++ ++ printk(KERN_INFO "%s: transmit timed out, resetting.\n", dev->name); ++ writel(0, ioaddr + INTERRUPT_MASK); ++ disable_irq(dev->irq); ++ ++ /* Stop a shared interrupt from scavenging while we are. */ ++ spin_lock_irqsave(&tp->lock, flags); ++ xenon_net_tx_clear(tp); ++ xenon_net_hw_start(dev); // this will re-enable interrupts ++ spin_unlock_irqrestore(&tp->lock, flags); ++ enable_irq(dev->irq); ++ ++ tp->stats.tx_errors++; ++ netif_wake_queue(dev); ++} ++ ++static int xenon_net_open(struct net_device *dev) ++{ ++ int retval; ++ ++ struct xenon_net_private *tp = netdev_priv(dev); ++ ++ retval = request_irq(dev->irq, xenon_net_interrupt, IRQF_SHARED, ++ dev->name, dev); ++ if (retval) ++ return retval; ++ ++ xenon_net_init_ring(dev); /* allocates ringbuffer, clears them */ ++ xenon_net_hw_start(dev); /* start HW */ ++ napi_enable(&tp->napi); ++ netif_carrier_on(dev); ++ ++ return 0; ++} ++ ++static int xenon_net_close(struct net_device *dev) ++{ ++ struct xenon_net_private *tp = netdev_priv(dev); ++ void *ioaddr = tp->mmio_addr; ++ ++ // Disable interrupts ++ writel(0, ioaddr + INTERRUPT_MASK); ++ disable_irq(dev->irq); ++ ++ netif_carrier_off(dev); ++ netif_stop_queue(dev); ++ napi_disable(&tp->napi); ++ free_irq(dev->irq, dev); ++ xenon_net_tx_clear(tp); ++ ++ pci_free_consistent(tp->pdev, TX_RING_SIZE * 0x10 + RX_RING_SIZE * 0x10, ++ tp->tx_descriptor_base, tp->tx_descriptor_base_dma); ++ ++ // BUG: Race condition with xenon_net_poll (napi_disable should stop it?) ++ tp->tx_descriptor_base = NULL; ++ tp->rx_descriptor_base = NULL; ++ ++ return 0; ++} ++ ++static struct net_device_ops xenon_netdev_ops = { ++ .ndo_open = xenon_net_open, ++ .ndo_stop = xenon_net_close, ++ .ndo_start_xmit = xenon_net_start_xmit, ++ .ndo_tx_timeout = xenon_net_tx_timeout, ++ .ndo_set_mac_address = xenon_net_set_mac, ++ .ndo_validate_addr = eth_validate_addr, ++ // .ndo_set_multicast_list = xenon_net_set_multicast_list, ++ // .ndo_set_mac_address = eth_mac_addr, ++ // .ndo_change_mtu = xenon_net_change_mtu, ++#if defined(CONFIG_NET_POLL_CONTROLLER) ++ .ndo_poll_controller = xenon_net_poll_controller, ++#endif ++}; ++ ++static int xenon_net_init_board(struct pci_dev *pdev, ++ struct net_device **dev_out, void **ioaddr_out) ++{ ++ void *ioaddr = NULL; ++ struct net_device *dev; ++ struct xenon_net_private *tp; ++ int rc, i; ++ unsigned long mmio_start, mmio_end, mmio_flags, mmio_len; ++ ++ BUG_ON(pdev == NULL); ++ BUG_ON(ioaddr_out == NULL); ++ ++ *ioaddr_out = NULL; ++ *dev_out = NULL; ++ ++ /* dev zeroed in alloc_etherdev */ ++ dev = alloc_etherdev(sizeof(*tp)); ++ if (dev == NULL) { ++ dev_err(&pdev->dev, "unable to alloc new ethernet\n"); ++ return -ENOMEM; ++ } ++ SET_NETDEV_DEV(dev, &pdev->dev); ++ tp = netdev_priv(dev); ++ ++ /* enable device (incl. PCI PM wakeup), and bus-mastering */ ++ rc = pci_enable_device(pdev); ++ if (rc) ++ goto err_out; ++ ++ mmio_start = pci_resource_start(pdev, 0); ++ mmio_end = pci_resource_end(pdev, 0); ++ mmio_flags = pci_resource_flags(pdev, 0); ++ mmio_len = pci_resource_len(pdev, 0); ++ ++ /* make sure PCI base addr 0 is MMIO */ ++ if (!(mmio_flags & IORESOURCE_MEM)) { ++ dev_err(&pdev->dev, ++ "region #0 not an MMIO resource, aborting\n"); ++ rc = -ENODEV; ++ goto err_out; ++ } ++ ++ rc = pci_request_regions(pdev, MODNAME); ++ if (rc) ++ goto err_out; ++ ++ pci_set_master(pdev); ++ ++ /* ioremap MMIO region */ ++ ioaddr = ioremap(mmio_start, mmio_len); ++ if (ioaddr == NULL) { ++ dev_err(&pdev->dev, "cannot remap MMIO, aborting\n"); ++ rc = -EIO; ++ goto err_out_free_res; ++ } ++ ++ dev->netdev_ops = &xenon_netdev_ops; ++ i = register_netdev(dev); ++ if (i) ++ goto err_out_unmap; ++ ++ *ioaddr_out = ioaddr; ++ *dev_out = dev; ++ return 0; ++ ++err_out_unmap: ++#ifndef USE_IO_OPS ++ iounmap(ioaddr); ++err_out_free_res: ++#endif ++ pci_release_regions(pdev); ++err_out: ++ free_netdev(dev); ++ return rc; ++} ++ ++static int xenon_net_init_one(struct pci_dev *pdev, ++ const struct pci_device_id *ent) ++{ ++ struct net_device *dev = NULL; ++ struct xenon_net_private *tp; ++ void *ioaddr = NULL; ++ struct sockaddr addr; ++ int rc; ++ ++/* when built into the kernel, we only print version if device is found */ ++#ifndef MODULE ++ static int printed_version; ++ if (!printed_version++) ++ printk(version); ++#endif ++ ++ BUG_ON(pdev == NULL); ++ BUG_ON(ent == NULL); ++ ++ rc = xenon_net_init_board(pdev, &dev, &ioaddr); ++ if (rc < 0) ++ return rc; ++ ++ tp = netdev_priv(dev); ++ ++ BUG_ON(ioaddr == NULL); ++ BUG_ON(dev == NULL); ++ BUG_ON(tp == NULL); ++ ++ tp->dev2 = dev; ++ // dev->ethtool_ops = &xenon_net_ethtool_ops; ++ dev->watchdog_timeo = TX_TIMEOUT; ++ ++ netif_napi_add(dev, &tp->napi, xenon_net_poll, 64); ++ ++ dev->irq = pdev->irq; ++ dev->base_addr = (unsigned long)ioaddr; ++ ++ /* priv/tp zeroed and aligned in alloc_etherdev */ ++ tp = netdev_priv(dev); ++ ++ tp->pdev = pdev; ++ tp->mmio_addr = ioaddr; ++ spin_lock_init(&tp->lock); ++ ++ pci_set_drvdata(pdev, dev); ++ ++ // FIXME: Need to get the MAC from NAND. ++ memcpy(addr.sa_data, "\x00\x01\x30\x44\x55\x66", 6); /* same as xell */ ++ rc = xenon_net_set_mac(dev, &addr); ++ if (rc) ++ dev_err(&pdev->dev, "Failed to set MAC address: %i\n", rc); ++ ++ printk(KERN_INFO "%s: %pM, IRQ %d\n", ++ dev->name, dev->dev_addr, dev->irq); ++ ++ return 0; ++} ++ ++static void xenon_net_remove_one(struct pci_dev *pdev) ++{ ++ struct net_device *dev = pci_get_drvdata(pdev); ++ struct xenon_net_private *np; ++ ++ BUG_ON(dev == NULL); ++ ++ np = netdev_priv(dev); ++ BUG_ON(np == NULL); ++ ++ unregister_netdev(dev); ++ ++#ifndef USE_IO_OPS ++ iounmap(np->mmio_addr); ++#endif /* !USE_IO_OPS */ ++ ++ pci_release_regions(pdev); ++ ++ free_netdev(dev); ++ ++ pci_set_drvdata(pdev, NULL); ++ ++ pci_disable_device(pdev); ++} ++ ++static struct pci_driver xenon_net_pci_driver = { ++ .name = MODNAME, ++ .id_table = xenon_net_pci_tbl, ++ .probe = xenon_net_init_one, ++ .remove = xenon_net_remove_one, ++}; ++ ++static int __init xenon_net_init_module(void) ++{ ++/* when a module, this is printed whether or not devices are found in probe */ ++#ifdef MODULE ++ printk(version); ++#endif ++ return pci_register_driver(&xenon_net_pci_driver); ++} ++ ++static void __exit xenon_net_cleanup_module(void) ++{ ++ pci_unregister_driver(&xenon_net_pci_driver); ++} ++ ++module_init(xenon_net_init_module); ++module_exit(xenon_net_cleanup_module); ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("Felix Domke "); ++MODULE_DESCRIPTION("Xenon Southbridge Fast Ethernet Driver"); +\ No newline at end of file +diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig +index e1bc52144..2a506527e 100644 +--- a/drivers/rtc/Kconfig ++++ b/drivers/rtc/Kconfig +@@ -1639,6 +1639,16 @@ config RTC_DRV_PS3 + This driver can also be built as a module. If so, the module + will be called rtc-ps3. + ++config RTC_DRV_XENON ++ tristate "Xenon RTC" ++ depends on PPC_XENON ++ help ++ If you say yes here you will get support for the RTC on the ++ Xbox 360. ++ ++ This driver can also be built as a module. If so, the module ++ will be called rtc-xenon. ++ + config RTC_DRV_STMP + tristate "Freescale STMP3xxx/i.MX23/i.MX28 RTC" + depends on ARCH_MXS || COMPILE_TEST +diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile +index 5ceeafe4d..8aef02082 100644 +--- a/drivers/rtc/Makefile ++++ b/drivers/rtc/Makefile +@@ -178,5 +178,6 @@ obj-$(CONFIG_RTC_DRV_WILCO_EC) += rtc-wilco-ec.o + obj-$(CONFIG_RTC_DRV_WM831X) += rtc-wm831x.o + obj-$(CONFIG_RTC_DRV_WM8350) += rtc-wm8350.o + obj-$(CONFIG_RTC_DRV_X1205) += rtc-x1205.o ++obj-$(CONFIG_RTC_DRV_XENON) += rtc-xenon.o + obj-$(CONFIG_RTC_DRV_XGENE) += rtc-xgene.o + obj-$(CONFIG_RTC_DRV_ZYNQMP) += rtc-zynqmp.o +diff --git a/drivers/rtc/rtc-xenon.c b/drivers/rtc/rtc-xenon.c +new file mode 100644 +index 000000000..3546afd1e +--- /dev/null ++++ b/drivers/rtc/rtc-xenon.c +@@ -0,0 +1,126 @@ ++/* ++ * Xenon RTC via SMC driver. ++ * ++ * Copyright (C) 2010 Herbert Poetzl ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; version 2 of the License. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++#include ++#include ++#include ++#include ++ ++ ++#define DRV_NAME "rtc-xenon" ++#define DRV_VERSION "0.1" ++ ++ /* for whatever reason, 15.Nov.2001 00:00 GMT */ ++#define RTC_BASE 1005782400UL ++ ++ ++int xenon_smc_message_wait(void *msg); ++ ++static unsigned long xenon_get_rtc(void) ++{ ++ unsigned char msg[16] = { 0x04 }; ++ unsigned long msec; ++ ++ xenon_smc_message_wait(msg); ++ msec = msg[1] | (msg[2] << 8) | (msg[3] << 16) | ++ (msg[4] << 24) | ((unsigned long)msg[5] << 32); ++ return RTC_BASE + msec/1000; ++} ++ ++void xenon_smc_message(void *msg); ++ ++static int xenon_set_rtc(unsigned long secs) ++{ ++ unsigned long msec = (secs - RTC_BASE) * 1000; ++ unsigned char msg[16] = { ++ 0x85, msec & 0xFF, (msec >> 8) & 0xFF, ++ (msec >> 16) & 0xFF, (msec >> 24) & 0xFF, ++ (msec >> 32) & 0xFF }; ++ ++ xenon_smc_message(msg); ++ return 0; ++} ++ ++static int xenon_read_time(struct device *dev, struct rtc_time *tm) ++{ ++ rtc_time64_to_tm(xenon_get_rtc(), tm); ++ return 0; ++} ++ ++ ++static int xenon_set_time(struct device *dev, struct rtc_time *tm) ++{ ++ unsigned long time = 0; ++ // int err; ++ ++ time = rtc_tm_to_time64(tm); ++ // if (err) ++ // return err; ++ ++ return xenon_set_rtc(time); ++} ++ ++static const struct rtc_class_ops xenon_rtc_ops = { ++ .read_time = xenon_read_time, ++ .set_time = xenon_set_time, ++}; ++ ++static int __init xenon_rtc_probe(struct platform_device *pdev) ++{ ++ struct rtc_device *rtc = devm_rtc_device_register(&pdev->dev, DRV_NAME, ++ &xenon_rtc_ops, THIS_MODULE); ++ ++ printk("xenon_rtc_probe(%p) = %p\n", pdev, rtc); ++ if (IS_ERR(rtc)) ++ return PTR_ERR(rtc); ++ ++ platform_set_drvdata(pdev, rtc); ++ return 0; ++} ++ ++static struct platform_driver xenon_rtc_driver = { ++ .driver = { ++ .name = DRV_NAME, ++ .owner = THIS_MODULE, ++ }, ++ .remove = __exit_p(xenon_rtc_remove), ++}; ++ ++static int __init xenon_rtc_init(void) ++{ ++ int ret = platform_driver_probe(&xenon_rtc_driver, xenon_rtc_probe); ++ ++ printk("xenon_rtc_init() = %d\n", ret); ++ return ret; ++ // return platform_driver_probe(&xenon_rtc_driver, xenon_rtc_probe); ++} ++ ++static void __exit xenon_rtc_exit(void) ++{ ++ platform_driver_unregister(&xenon_rtc_driver); ++} ++ ++module_init(xenon_rtc_init); ++module_exit(xenon_rtc_exit); ++ ++MODULE_AUTHOR("Herbert Poetzl "); ++MODULE_DESCRIPTION("Xenon RTC driver"); ++MODULE_LICENSE("GPL"); ++MODULE_VERSION(DRV_VERSION); ++MODULE_ALIAS("platform:rtc-xenon"); +\ No newline at end of file +diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c +index 9466474ff..565ff86e8 100644 +--- a/drivers/scsi/scsi_scan.c ++++ b/drivers/scsi/scsi_scan.c +@@ -654,6 +654,7 @@ static int scsi_probe_lun(struct scsi_device *sdev, unsigned char *inq_result, + memset(scsi_cmd, 0, 6); + scsi_cmd[0] = INQUIRY; + scsi_cmd[4] = (unsigned char) try_inquiry_len; ++ scsi_cmd[5] = 0xc0; /* HACK */ + + memset(inq_result, 0, try_inquiry_len); + +diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig +index 131a6a587..8c11aec2b 100644 +--- a/drivers/tty/serial/Kconfig ++++ b/drivers/tty/serial/Kconfig +@@ -1528,6 +1528,25 @@ config SERIAL_MILBEAUT_USIO_CONSOLE + receives all kernel messages and warnings and which allows logins in + single user mode). + ++config SERIAL_XENON ++ tristate "Xenon XBOX 360 serial port support" ++ select SERIAL_CORE ++ help ++ If you have an XBOX 360, you can enable its onboard ++ serial port by enabling this options. ++ ++ To compile this driver as a module, choose M here: the ++ module will be called xenon_uart. ++ ++config SERIAL_XENON_CONSOLE ++ bool "Console on XBOX 360 serial port" ++ depends on SERIAL_XENON=y ++ select SERIAL_CORE_CONSOLE ++ help ++ If you have enabled the serial port on the XBOX 360 ++ ++ you can make it the console by answering Y to this option. ++ + config SERIAL_LITEUART + tristate "LiteUART serial port support" + depends on HAS_IOMEM +diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile +index 7da0856cd..6659b3f64 100644 +--- a/drivers/tty/serial/Makefile ++++ b/drivers/tty/serial/Makefile +@@ -65,6 +65,7 @@ obj-$(CONFIG_SERIAL_GRLIB_GAISLER_APBUART) += apbuart.o + obj-$(CONFIG_SERIAL_ALTERA_JTAGUART) += altera_jtaguart.o + obj-$(CONFIG_SERIAL_VT8500) += vt8500_serial.o + obj-$(CONFIG_SERIAL_PCH_UART) += pch_uart.o ++obj-$(CONFIG_SERIAL_XENON) += xenon_uart.o + obj-$(CONFIG_SERIAL_MXS_AUART) += mxs-auart.o + obj-$(CONFIG_SERIAL_LANTIQ) += lantiq.o + obj-$(CONFIG_SERIAL_XILINX_PS_UART) += xilinx_uartps.o +diff --git a/drivers/tty/serial/xenon_uart.c b/drivers/tty/serial/xenon_uart.c +new file mode 100644 +index 000000000..69d3f5378 +--- /dev/null ++++ b/drivers/tty/serial/xenon_uart.c +@@ -0,0 +1,418 @@ ++/* linux/drivers/serial/xenon.c ++ * ++ * Driver for Xenon XBOX 360 Serial ++ * ++ * Copyright (C) 2010 Herbert Poetzl ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++*/ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#if 0 ++#define dprintk(f, x...) do { \ ++ printk(KERN_DEBUG f "\n" , ##x); \ ++ } while (0) ++#else ++#define dprintk(f, x...) do { } while (0) ++#endif ++ ++ ++static int xenon_status(unsigned char __iomem *membase) ++{ ++ // return ((*(volatile uint32_t*)0x80000200ea001018) & 0x02000000); ++ return (*(volatile uint32_t*)(membase + 0x08)); ++} ++ ++static void xenon_putch(unsigned char __iomem *membase, int ch) ++{ ++ /* wait for tx fifo ready */ ++ while (!(xenon_status(membase) & 0x02000000)); ++ ++ /* put character into fifo */ ++ // *(volatile uint32_t*)0x80000200ea001014 = (ch << 24) & 0xFF000000; ++ *(volatile uint32_t*)(membase + 0x04) = (ch << 24) & 0xFF000000; ++} ++ ++static int xenon_getch(unsigned char __iomem *membase) ++{ ++ uint32_t status; ++ ++ /* wait for data ready */ ++ while ((status = xenon_status(membase)) & ~0x03000000); ++ ++ if (status & 0x01000000) ++ return *(volatile uint32_t*)(membase + 0x00) >> 24; ++ return -1; ++} ++ ++ ++ ++static void xenon_stop_rx(struct uart_port *port) ++{ ++ dprintk("Xenon xenon_stop_rx()"); ++} ++ ++static void xenon_enable_ms(struct uart_port *port) ++{ ++ dprintk("Xenon xenon_enable_ms()"); ++} ++ ++static void xenon_stop_tx(struct uart_port *port) ++{ ++ dprintk("Xenon xenon_stop_tx()"); ++} ++ ++static void xenon_tx_chars(struct uart_port *port) ++{ ++ struct circ_buf *xmit = &port->state->xmit; ++ // int count; ++ ++ if (port->x_char) { ++ xenon_putch(port->membase, port->x_char); ++ port->icount.tx++; ++ port->x_char = 0; ++ return; ++ } ++ if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { ++ xenon_stop_tx(port); ++ return; ++ } ++ ++#if 0 ++ count = port->fifosize >> 1; ++ do { ++ xenon_putch(port->membase, xmit->buf[xmit->tail]); ++ xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); ++ port->icount.tx++; ++ if (uart_circ_empty(xmit)) ++ break; ++ } while (--count > 0); ++#else ++ while (!uart_circ_empty(xmit)) { ++ xenon_putch(port->membase, xmit->buf[xmit->tail]); ++ xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); ++ port->icount.tx++; ++ } ++#endif ++ ++ if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) ++ uart_write_wakeup(port); ++ ++ if (uart_circ_empty(xmit)) ++ xenon_stop_tx(port); ++} ++ ++static void xenon_start_tx(struct uart_port *port) ++{ ++ dprintk("Xenon xenon_start_tx()"); ++ xenon_tx_chars(port); ++} ++ ++ ++#if 0 ++static void xenon_send_xchar(struct uart_port *port, char ch) ++{ ++ dprintk("Xenon xenon_send_xchar(%d)", ch); ++ xenon_putch(port->membase, ch); ++} ++#endif ++ ++static unsigned int xenon_tx_empty(struct uart_port *port) ++{ ++ dprintk("Xenon xenon_tx_empty()"); ++ return 0; ++} ++ ++static unsigned int xenon_get_mctrl(struct uart_port *port) ++{ ++ dprintk("Xenon xenon_get_mctrl()"); ++ return 0; ++} ++ ++static void xenon_set_mctrl(struct uart_port *port, unsigned int mctrl) ++{ ++ dprintk("Xenon xenon_set_mctrl()"); ++} ++ ++static void xenon_break_ctl(struct uart_port *port, int break_state) ++{ ++ dprintk("Xenon xenon_break_ctl()"); ++} ++ ++static void xenon_set_termios(struct uart_port *port, ++ struct ktermios *new, struct ktermios *old) ++{ ++ int baud, quot, cflag = new->c_cflag; ++ ++ dprintk("Xenon xenon_set_termios()"); ++ /* get the byte size */ ++ switch (cflag & CSIZE) { ++ case CS5: ++ dprintk(" - data bits = 5"); ++ break; ++ case CS6: ++ dprintk(" - data bits = 6"); ++ break; ++ case CS7: ++ dprintk(" - data bits = 7"); ++ break; ++ default: // CS8 ++ dprintk(" - data bits = 8"); ++ break; ++ } ++ ++ /* determine the parity */ ++ if (cflag & PARENB) ++ if (cflag & PARODD) ++ pr_debug(" - parity = odd\n"); ++ else ++ pr_debug(" - parity = even\n"); ++ else ++ pr_debug(" - parity = none\n"); ++ ++ /* figure out the stop bits requested */ ++ if (cflag & CSTOPB) ++ pr_debug(" - stop bits = 2\n"); ++ else ++ pr_debug(" - stop bits = 1\n"); ++ ++ /* figure out the flow control settings */ ++ if (cflag & CRTSCTS) ++ pr_debug(" - RTS/CTS is enabled\n"); ++ else ++ pr_debug(" - RTS/CTS is disabled\n"); ++ ++ /* Set baud rate */ ++ baud = uart_get_baud_rate(port, new, old, 0, port->uartclk/16); ++ quot = uart_get_divisor(port, baud); ++} ++ ++static int xenon_startup(struct uart_port *port) ++{ ++ dprintk("Xenon xenon_startup()"); ++ /* this is the first time this port is opened */ ++ /* do any hardware initialization needed here */ ++ return 0; ++} ++ ++static void xenon_shutdown(struct uart_port *port) ++{ ++ dprintk("Xenon xenon_shutdown()"); ++ /* The port is being closed by the last user. */ ++ /* Do any hardware specific stuff here */ ++} ++ ++static const char *xenon_type(struct uart_port *port) ++{ ++ return "Xenon SMC"; ++} ++ ++static void xenon_release_port(struct uart_port *port) ++{ ++ dprintk("Xenon xenon_release_port()"); ++} ++ ++static int xenon_request_port(struct uart_port *port) ++{ ++ dprintk("Xenon xenon_request_port()"); ++ return 0; ++} ++ ++static void xenon_config_port(struct uart_port *port, int flags) ++{ ++ dprintk("Xenon xenon_config_port()"); ++ ++ if (flags & UART_CONFIG_TYPE) { ++ port->type = PORT_XENON; ++ } ++} ++ ++static int xenon_verify_port(struct uart_port *port, struct serial_struct *ser) ++{ ++ dprintk("Xenon xenon_verify_port()"); ++ return 0; ++} ++ ++ ++#ifdef CONFIG_CONSOLE_POLL ++ ++static int xenon_poll_get_char(struct uart_port *port) ++{ ++ return xenon_getch(port->membase); ++} ++ ++static void xenon_poll_put_char(struct uart_port *port, unsigned char c) ++{ ++ xenon_putch(port->membase, c); ++} ++ ++#endif ++ ++ ++static struct uart_ops xenon_ops = { ++ .tx_empty = xenon_tx_empty, ++ .set_mctrl = xenon_set_mctrl, ++ .get_mctrl = xenon_get_mctrl, ++ .stop_tx = xenon_stop_tx, ++ .start_tx = xenon_start_tx, ++// .send_xchar = xenon_send_xchar, ++ .stop_rx = xenon_stop_rx, ++ .enable_ms = xenon_enable_ms, ++ .break_ctl = xenon_break_ctl, ++ .startup = xenon_startup, ++ .shutdown = xenon_shutdown, ++// .flush_buffer = xenon_flush_buffer, ++ .set_termios = xenon_set_termios, ++// .set_ldisc = xenon_set_ldisc, ++// .pm = xenon_pm, ++// .set_wake = xenon_set_wake, ++ .type = xenon_type, ++ .release_port = xenon_release_port, ++ .request_port = xenon_request_port, ++ .config_port = xenon_config_port, ++ .verify_port = xenon_verify_port, ++#ifdef CONFIG_CONSOLE_POLL ++ .poll_put_char = xenon_poll_put_char, ++ .poll_get_char = xenon_poll_get_char, ++#endif ++}; ++ ++static struct uart_port xenon_port = { ++ .type = PORT_XENON, ++ .ops = &xenon_ops, ++ .flags = UPF_FIXED_TYPE | UPF_IOREMAP, ++ .mapbase = 0x200ea001010ULL, ++ .iotype = UPIO_MEM, ++ .uartclk = 1843200, ++}; ++ ++static struct console xenon_console; ++ ++static struct uart_driver xenon_reg = { ++ .owner = THIS_MODULE, ++ .driver_name = "xenon_uart", ++ .dev_name = "ttyS", ++ .major = TTY_MAJOR, ++ .minor = 64, ++ .nr = 1, ++#ifdef CONFIG_SERIAL_XENON_CONSOLE ++ .cons = &xenon_console, ++#endif ++}; ++ ++ ++static int __init xenon_init(void) ++{ ++ int result; ++ ++ printk(KERN_INFO "Xenon XBOX 360 serial driver\n"); ++ ++ result = uart_register_driver(&xenon_reg); ++ dprintk("Xenon uart_register_driver() = %d", result); ++ if (result) ++ return result; ++ ++ xenon_port.membase = ioremap(xenon_port.mapbase, 0x10); ++ ++ result = uart_add_one_port(&xenon_reg, &xenon_port); ++ dprintk("Xenon uart_add_one_port() = %d", result); ++ if (result) ++ uart_unregister_driver(&xenon_reg); ++ ++ return result; ++} ++ ++static void __exit xenon_exit(void) ++{ ++ printk(KERN_INFO "Xenon XBOX 360 serial driver exit\n"); ++ uart_remove_one_port(&xenon_reg, &xenon_port); ++ uart_unregister_driver(&xenon_reg); ++} ++ ++module_init(xenon_init); ++module_exit(xenon_exit); ++ ++ ++#ifdef CONFIG_SERIAL_XENON_CONSOLE ++ ++static void xenon_console_putchar(struct uart_port *port, int ch) ++{ ++ xenon_putch(port->membase, ch); ++} ++ ++/* ++ * Print a string to the serial port trying not to disturb ++ * any possible real use of the port... ++ */ ++static void xenon_console_write(struct console *cons, ++ const char *s, unsigned int count) ++{ ++ uart_console_write(&xenon_port, s, count, xenon_console_putchar); ++} ++ ++/* ++ * Setup serial console baud/bits/parity. We do two things here: ++ * - construct a cflag setting for the first uart_open() ++ * - initialise the serial port ++ * Return non-zero if we didn't find a serial port. ++ */ ++static int __init xenon_console_setup(struct console *cons, char *options) ++{ ++ int baud = 38400; ++ int bits = 8; ++ int parity = 'n'; ++ int flow = 'n'; ++#if 0 ++ ret = xenon_map_port(uport); ++ if (ret) ++ return ret; ++ ++ xenon_reset(port); ++ xenon_pm(port, 0, -1); ++#endif ++ ++ if (options) ++ uart_parse_options(options, &baud, &parity, &bits, &flow); ++ return uart_set_options(&xenon_port, cons, baud, parity, bits, flow); ++} ++ ++static struct console xenon_console = { ++ .name = "ttyS", ++ .write = xenon_console_write, ++ .device = uart_console_device, ++ .setup = xenon_console_setup, ++ .flags = CON_PRINTBUFFER, ++ .index = -1, ++ .data = &xenon_reg, ++}; ++ ++static int __init xenon_serial_console_init(void) ++{ ++ xenon_port.membase = ioremap(xenon_port.mapbase, 0x10); ++ ++ register_console(&xenon_console); ++ return 0; ++} ++ ++console_initcall(xenon_serial_console_init); ++ ++#endif /* CONFIG_SERIAL_XENON_CONSOLE */ ++ ++ ++MODULE_AUTHOR("Herbert Poetzl "); ++MODULE_DESCRIPTION("Xenon XBOX 360 Serial port driver"); ++MODULE_LICENSE("GPL v2"); ++// MODULE_ALIAS("platform:xenon-uart"); +\ No newline at end of file +diff --git a/drivers/video/fbdev/Kconfig b/drivers/video/fbdev/Kconfig +index 6ed5e608d..2164d4110 100644 +--- a/drivers/video/fbdev/Kconfig ++++ b/drivers/video/fbdev/Kconfig +@@ -659,6 +659,15 @@ config FB_N411 + This enables support for the Apollo display controller in its + Hecuba form using the n411 devkit. + ++config FB_XENOS ++ tristate "Xbox 360 Framebuffer Support" ++ depends on (FB = y) && PPC ++ select FB_CFB_FILLRECT ++ select FB_CFB_COPYAREA ++ select FB_CFB_IMAGEBLIT ++ help ++ This is the frame buffer device driver for the Microsoft Xbox 360. ++ + config FB_HGA + tristate "Hercules mono graphics support" + depends on FB && X86 +diff --git a/drivers/video/fbdev/Makefile b/drivers/video/fbdev/Makefile +index 477b9624b..2e64a4e20 100644 +--- a/drivers/video/fbdev/Makefile ++++ b/drivers/video/fbdev/Makefile @@ -123,6 +123,7 @@ obj-$(CONFIG_FB_SM712) += sm712fb.o obj-$(CONFIG_FB_UVESA) += uvesafb.o obj-$(CONFIG_FB_VESA) += vesafb.o @@ -453,6 +5210,796 @@ index 477b9624b..2e64a4e20 100644 obj-$(CONFIG_FB_VGA16) += vga16fb.o obj-$(CONFIG_FB_OF) += offb.o obj-$(CONFIG_FB_MX3) += mx3fb.o +diff --git a/drivers/video/fbdev/xenosfb.c b/drivers/video/fbdev/xenosfb.c +new file mode 100644 +index 000000000..5179f55ef +--- /dev/null ++++ b/drivers/video/fbdev/xenosfb.c +@@ -0,0 +1,431 @@ ++/* ++ * framebuffer driver for Microsoft Xbox 360 ++ * ++ * (c) 2006 ... ++ * Original vesafb driver written by Gerd Knorr ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#include