Permalink
Checking mergeability…
Don’t worry, you can still create the pull request.
Comparing changes
Open a pull request
1
contributor
Unified
Split
Showing
with
3,703 additions
and 121 deletions.
- +8 −0 arch/x86/Kconfig
- +1 −0 arch/x86/include/asm/msi.h
- +60 −0 arch/x86/include/asm/ps4.h
- +6 −0 arch/x86/include/asm/setup.h
- +1 −0 arch/x86/include/uapi/asm/bootparam.h
- +1 −1 arch/x86/kernel/apic/msi.c
- +7 −0 arch/x86/kernel/head64.c
- +1 −0 arch/x86/platform/Makefile
- +1 −0 arch/x86/platform/ps4/Makefile
- +116 −0 arch/x86/platform/ps4/calibrate.c
- +76 −0 arch/x86/platform/ps4/ps4.c
- +1 −0 drivers/Makefile
- +40 −0 drivers/ata/ahci.c
- +1 −1 drivers/gpu/drm/drm_irq.c
- +1 −1 drivers/gpu/drm/drm_pci.c
- +2 −0 drivers/gpu/drm/radeon/Makefile
- +1 −1 drivers/gpu/drm/radeon/atombios_dp.c
- +2 −1 drivers/gpu/drm/radeon/atombios_encoders.c
- +656 −19 drivers/gpu/drm/radeon/cik.c
- +36 −10 drivers/gpu/drm/radeon/cik_sdma.c
- +584 −0 drivers/gpu/drm/radeon/ps4_bridge.c
- +2 −1 drivers/gpu/drm/radeon/radeon.h
- +12 −5 drivers/gpu/drm/radeon/radeon_asic.c
- +5 −0 drivers/gpu/drm/radeon/radeon_audio.c
- +46 −4 drivers/gpu/drm/radeon/radeon_connectors.c
- +1 −0 drivers/gpu/drm/radeon/radeon_device.c
- +1 −1 drivers/gpu/drm/radeon/radeon_display.c
- +14 −0 drivers/gpu/drm/radeon/radeon_drv.c
- +19 −0 drivers/gpu/drm/radeon/radeon_encoders.c
- +1 −0 drivers/gpu/drm/radeon/radeon_family.h
- +1 −1 drivers/gpu/drm/radeon/radeon_ib.c
- +1 −0 drivers/gpu/drm/radeon/radeon_pm.c
- +3 −0 drivers/gpu/drm/radeon/radeon_ucode.h
- +1 −0 drivers/gpu/drm/radeon/radeon_uvd.c
- +1 −0 drivers/gpu/drm/radeon/radeon_vce.c
- +2 −1 drivers/iommu/amd_iommu_init.c
- +69 −4 drivers/mmc/host/sdhci-pci-core.c
- +3 −0 drivers/mmc/host/sdhci-pci.h
- +112 −51 drivers/net/ethernet/marvell/sky2.c
- +7 −0 drivers/net/ethernet/marvell/sky2.h
- +17 −0 drivers/pci/probe.c
- +9 −0 drivers/ps4/Makefile
- +168 −0 drivers/ps4/aeolia.h
- +156 −0 drivers/ps4/icc/i2c.c
- +469 −0 drivers/ps4/ps4-apcie-icc.c
- +69 −0 drivers/ps4/ps4-apcie-pwrbutton.c
- +67 −0 drivers/ps4/ps4-apcie-uart.c
- +522 −0 drivers/ps4/ps4-apcie.c
- +7 −0 drivers/usb/host/Kconfig
- +1 −0 drivers/usb/host/Makefile
- +284 −0 drivers/usb/host/xhci-aeolia.c
- +16 −14 drivers/usb/host/xhci.c
- +1 −0 drivers/usb/host/xhci.h
- +2 −2 drivers/video/logo/logo.c
- +1 −0 include/drm/drm_pciids.h
- +8 −0 include/linux/pci_ids.h
- +3 −3 scripts/pnmtologo.c
| @@ -462,6 +462,14 @@ config X86_NUMACHIP | |||
| enable more than ~168 cores. | |||
| If you don't have one of these, you should say N here. | |||
|
|
|||
| config X86_PS4 | |||
| bool "Sony PlayStation 4" | |||
| depends on X86_64 | |||
| depends on X86_EXTENDED_PLATFORM | |||
| depends on PCI | |||
| ---help--- | |||
| Select to include support for the Sony PlayStation 4 game console. | |||
|
|
|||
| config X86_VSMP | |||
| bool "ScaleMP vSMP" | |||
| select HYPERVISOR_GUEST | |||
| @@ -9,5 +9,6 @@ int pci_msi_prepare(struct irq_domain *domain, struct device *dev, int nvec, | |||
| msi_alloc_info_t *arg); | |||
|
|
|||
| void pci_msi_set_desc(msi_alloc_info_t *arg, struct msi_desc *desc); | |||
| void irq_msi_compose_msg(struct irq_data *data, struct msi_msg *msg); | |||
|
|
|||
| #endif /* _ASM_X86_MSI_H */ | |||
| @@ -0,0 +1,60 @@ | |||
| /* | |||
| * ps4.h: Sony PS4 platform setup code | |||
| * | |||
| * 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. | |||
| */ | |||
| #ifndef _ASM_X86_PS4_H | |||
| #define _ASM_X86_PS4_H | |||
|
|
|||
| #ifdef CONFIG_X86_PS4 | |||
|
|
|||
| #include <linux/irqdomain.h> | |||
|
|
|||
| #define PS4_DEFAULT_TSC_FREQ 1594000000 | |||
|
|
|||
| #define EMC_TIMER_BASE 0xd0281000 | |||
| #define EMC_TIMER_VALUE 0x28 | |||
|
|
|||
| extern unsigned long ps4_calibrate_tsc(void); | |||
|
|
|||
| /* | |||
| * The PS4 Aeolia southbridge device is a composite device containing some | |||
| * standard-ish, some not-so-standard, and some completely custom functions, | |||
| * all using special MSI handling. This function does the equivalent of | |||
| * pci_enable_msi_range and friends, for those devices. Only works after the | |||
| * Aeolia MSR routing function device (function 4) has been probed. | |||
| * Returns 1 or count, depending on IRQ allocation constraints, or negative on | |||
| * error. Assigned IRQ(s) start at dev->irq. | |||
| */ | |||
| extern int apcie_assign_irqs(struct pci_dev *dev, int nvec); | |||
| extern void apcie_free_irqs(unsigned int virq, unsigned int nr_irqs); | |||
|
|
|||
| extern int apcie_status(void); | |||
| extern int apcie_icc_cmd(u8 major, u16 minor, const void *data, | |||
| u16 length, void *reply, u16 reply_length); | |||
|
|
|||
|
|
|||
| #else | |||
|
|
|||
| static inline int apcie_assign_irqs(struct pci_dev *dev, int nvec) | |||
| { | |||
| return -ENODEV; | |||
| } | |||
| static inline void apcie_free_irqs(unsigned int virq, unsigned int nvec) | |||
| { | |||
| } | |||
| static inline int apcie_status(void) | |||
| { | |||
| return -ENODEV; | |||
| } | |||
| static inline int apcie_icc_cmd(u8 major, u16 minor, const void *data, | |||
| u16 length, void *reply, u16 reply_length) | |||
| { | |||
| return -ENODEV; | |||
| } | |||
|
|
|||
| #endif | |||
| #endif | |||
| @@ -58,6 +58,12 @@ extern void x86_ce4100_early_setup(void); | |||
| static inline void x86_ce4100_early_setup(void) { } | |||
| #endif | |||
|
|
|||
| #ifdef CONFIG_X86_PS4 | |||
| extern void x86_ps4_early_setup(void); | |||
| #else | |||
| static inline void x86_ps4_early_setup(void) { } | |||
| #endif | |||
|
|
|||
| #ifndef _SETUP | |||
|
|
|||
| #include <asm/espfix.h> | |||
| @@ -202,6 +202,7 @@ enum x86_hardware_subarch { | |||
| X86_SUBARCH_XEN, | |||
| X86_SUBARCH_INTEL_MID, | |||
| X86_SUBARCH_CE4100, | |||
| X86_SUBARCH_PS4, | |||
| X86_NR_SUBARCHS, | |||
| }; | |||
|
|
|||
| @@ -25,7 +25,7 @@ | |||
|
|
|||
| static struct irq_domain *msi_default_domain; | |||
|
|
|||
| static void irq_msi_compose_msg(struct irq_data *data, struct msi_msg *msg) | |||
| void irq_msi_compose_msg(struct irq_data *data, struct msi_msg *msg) | |||
| { | |||
| struct irq_cfg *cfg = irqd_cfg(data); | |||
|
|
|||
| @@ -192,5 +192,12 @@ void __init x86_64_start_reservations(char *real_mode_data) | |||
| break; | |||
| } | |||
|
|
|||
| /* Call the subarch specific early setup function */ | |||
| switch (boot_params.hdr.hardware_subarch) { | |||
| case X86_SUBARCH_PS4: | |||
| x86_ps4_early_setup(); | |||
| break; | |||
| } | |||
|
|
|||
| start_kernel(); | |||
| } | |||
| @@ -10,6 +10,7 @@ obj-y += intel-mid/ | |||
| obj-y += intel-quark/ | |||
| obj-y += mellanox/ | |||
| obj-y += olpc/ | |||
| obj-y += ps4/ | |||
| obj-y += scx200/ | |||
| obj-y += sfi/ | |||
| obj-y += ts5500/ | |||
| @@ -0,0 +1 @@ | |||
| obj-$(CONFIG_X86_PS4) += ps4.o calibrate.o | |||
| @@ -0,0 +1,116 @@ | |||
| /* | |||
| * calibrate.c: Sony PS4 TSC/LAPIC calibration | |||
| * | |||
| * 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. | |||
| */ | |||
|
|
|||
| #define pr_fmt(fmt) "ps4: " fmt | |||
|
|
|||
| #include <linux/jiffies.h> | |||
| #include <asm/io.h> | |||
| #include <asm/msr.h> | |||
| #include <asm/ps4.h> | |||
| #include <asm/delay.h> | |||
| #include <asm/apic.h> | |||
|
|
|||
| /* The PS4 southbridge (Aeolia) has an EMC timer that ticks at 32.768kHz, | |||
| * which seems to be an appropriate clock reference for calibration. Both TSC | |||
| * and the LAPIC timer are based on the core clock frequency and thus can be | |||
| * calibrated together. */ | |||
| static void __iomem *emc_timer = NULL; | |||
|
|
|||
| static __init inline u32 emctimer_read32(unsigned int reg) | |||
| { | |||
| return ioread32(emc_timer + reg); | |||
| } | |||
|
|
|||
| static __init inline void emctimer_write32(unsigned int reg, u32 val) | |||
| { | |||
| iowrite32(val, emc_timer + reg); | |||
| } | |||
|
|
|||
| static __init inline u32 emctimer_read(void) | |||
| { | |||
| u32 t1, t2; | |||
| t1 = emctimer_read32(EMC_TIMER_VALUE); | |||
| while (1) { | |||
| t2 = emctimer_read32(EMC_TIMER_VALUE); | |||
| if (t1 == t2) | |||
| return t1; | |||
| t1 = t2; | |||
| } | |||
| } | |||
|
|
|||
| static __init unsigned long ps4_measure_tsc_freq(void) | |||
| { | |||
| unsigned long ret = 0; | |||
| u32 t1, t2; | |||
| u64 tsc1, tsc2; | |||
|
|
|||
| // This is part of the Aeolia pcie device, but it's too early to | |||
| // do this in a driver. | |||
| emc_timer = ioremap(EMC_TIMER_BASE, 0x100); | |||
| if (!emc_timer) | |||
| goto fail; | |||
|
|
|||
| // reset/start the timer | |||
| emctimer_write32(0x84, emctimer_read32(0x84) & (~0x01)); | |||
| // udelay is not calibrated yet, so this is likely wildly off, but good | |||
| // enough to work. | |||
| udelay(300); | |||
| emctimer_write32(0x00, emctimer_read32(0x00) | 0x01); | |||
| emctimer_write32(0x84, emctimer_read32(0x84) | 0x01); | |||
|
|
|||
| t1 = emctimer_read(); | |||
| tsc1 = tsc2 = rdtsc(); | |||
|
|
|||
| while (emctimer_read() == t1) { | |||
| // 0.1s timeout should be enough | |||
| tsc2 = rdtsc(); | |||
| if ((tsc2 - tsc1) > (PS4_DEFAULT_TSC_FREQ/10)) { | |||
| pr_warn("EMC timer is broken.\n"); | |||
| goto fail; | |||
| } | |||
| } | |||
| pr_info("EMC timer started in %lld TSC ticks\n", tsc2 - tsc1); | |||
|
|
|||
| // Wait for a tick boundary | |||
| t1 = emctimer_read(); | |||
| while ((t2 = emctimer_read()) == t1); | |||
| tsc1 = rdtsc(); | |||
|
|
|||
| // Wait for 1024 ticks to elapse (31.25ms) | |||
| // We don't need to wait very long, as we are looking for transitions. | |||
| // At this value, a TSC uncertainty of ~50 ticks corresponds to 1ppm of | |||
| // clock accuracy. | |||
| while ((emctimer_read() - t2) < 1024); | |||
| tsc2 = rdtsc(); | |||
|
|
|||
| // TSC rate is 32 times the elapsed time | |||
| ret = (tsc2 - tsc1) * 32; | |||
|
|
|||
| pr_info("Calibrated TSC frequency: %ld kHz\n", ret); | |||
| fail: | |||
| if (emc_timer) { | |||
| iounmap(emc_timer); | |||
| emc_timer = NULL; | |||
| } | |||
| return ret; | |||
| } | |||
|
|
|||
| unsigned long __init ps4_calibrate_tsc(void) | |||
| { | |||
| unsigned long tsc_freq = ps4_measure_tsc_freq(); | |||
|
|
|||
| if (!tsc_freq) { | |||
| pr_warn("Unable to measure TSC frequency, assuming default.\n"); | |||
| tsc_freq = PS4_DEFAULT_TSC_FREQ; | |||
| } | |||
|
|
|||
| lapic_timer_frequency = (tsc_freq + 8 * HZ) / (16 * HZ); | |||
|
|
|||
| return (tsc_freq + 500) / 1000; | |||
| } | |||
| @@ -0,0 +1,76 @@ | |||
| /* | |||
| * ps4.c: Sony PS4 platform setup code | |||
| * | |||
| * 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. | |||
| */ | |||
|
|
|||
| #define pr_fmt(fmt) "ps4: " fmt | |||
|
|
|||
| #include <linux/init.h> | |||
| #include <linux/kernel.h> | |||
| #include <linux/interrupt.h> | |||
| #include <linux/scatterlist.h> | |||
| #include <linux/sfi.h> | |||
| #include <linux/irq.h> | |||
| #include <linux/module.h> | |||
| #include <linux/notifier.h> | |||
|
|
|||
| #include <asm/setup.h> | |||
| #include <asm/mpspec_def.h> | |||
| #include <asm/hw_irq.h> | |||
| #include <asm/apic.h> | |||
| #include <asm/io_apic.h> | |||
| #include <asm/io.h> | |||
| #include <asm/i8259.h> | |||
| #include <asm/apb_timer.h> | |||
| #include <asm/reboot.h> | |||
| #include <asm/msr.h> | |||
| #include <asm/ps4.h> | |||
|
|
|||
| static bool is_ps4; | |||
| bool apcie_initialized; | |||
|
|
|||
| /* | |||
| * The RTC is part of the Aeolia PCI device and will be implemented there as | |||
| * an RTC class device; stub these out. | |||
| */ | |||
| static void dummy_get_wallclock(struct timespec *now) | |||
| { | |||
| now->tv_sec = now->tv_nsec = 0; | |||
| } | |||
| static int dummy_set_wallclock(const struct timespec *now) | |||
| { | |||
| return -ENODEV; | |||
| } | |||
|
|
|||
| /* | |||
| * Provide a way for generic drivers to query for the availability of the | |||
| * PS4 apcie driver/device, which is a dependency for them. | |||
| */ | |||
| int apcie_status(void) | |||
| { | |||
| if (!is_ps4) | |||
| return -ENODEV; | |||
| return apcie_initialized; | |||
| } | |||
| EXPORT_SYMBOL_GPL(apcie_status); | |||
|
|
|||
| void icc_reboot(void); | |||
|
|
|||
| /* | |||
| * PS4 specific x86_init function overrides and early setup calls. | |||
| */ | |||
| void __init x86_ps4_early_setup(void) | |||
| { | |||
| pr_info("x86_ps4_early_setup: PS4 early setup\n"); | |||
| is_ps4 = true; | |||
| x86_platform.calibrate_tsc = ps4_calibrate_tsc; | |||
| x86_platform.get_wallclock = dummy_get_wallclock; | |||
| x86_platform.set_wallclock = dummy_set_wallclock; | |||
|
|
|||
| legacy_pic = &null_legacy_pic; | |||
| machine_ops.emergency_restart = icc_reboot; | |||
| } | |||
| @@ -81,6 +81,7 @@ obj-$(CONFIG_MTD) += mtd/ | |||
| obj-$(CONFIG_SPI) += spi/ | |||
| obj-$(CONFIG_SPMI) += spmi/ | |||
| obj-$(CONFIG_HSI) += hsi/ | |||
| obj-$(CONFIG_X86_PS4) += ps4/ | |||
| obj-y += net/ | |||
| obj-$(CONFIG_ATM) += atm/ | |||
| obj-$(CONFIG_FUSION) += message/ | |||
Oops, something went wrong.