forked from torvalds/linux
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1 from Razor246/ps4-5.1.0
Ps4 5.1.0
- Loading branch information
Showing
12 changed files
with
318 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.