Files
ps5-linux-patches/linux.patch

10768 lines
378 KiB
Diff

diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index f3f7cb01d69d..15d2e0de3bf6 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -601,6 +601,14 @@ config X86_NUMACHIP
enable more than ~168 cores.
If you don't have one of these, you should say N here.
+config X86_PS5
+ bool "Sony PlayStation 5"
+ depends on X86_64
+ depends on X86_EXTENDED_PLATFORM
+ depends on PCI
+ help
+ Select to include support for the Sony PlayStation 5 game console.
+
config X86_VSMP
bool "ScaleMP vSMP"
select HYPERVISOR_GUEST
diff --git a/arch/x86/include/asm/msr-index.h b/arch/x86/include/asm/msr-index.h
index 86554de9a3f5..70b0eb8e32c9 100644
--- a/arch/x86/include/asm/msr-index.h
+++ b/arch/x86/include/asm/msr-index.h
@@ -26,6 +26,7 @@
#define _EFER_LMSLE 13 /* Long Mode Segment Limit Enable */
#define _EFER_FFXSR 14 /* Enable Fast FXSAVE/FXRSTOR */
#define _EFER_TCE 15 /* Enable Translation Cache Extensions */
+#define _EFER_NDA 16 /* No data access enable */
#define _EFER_AUTOIBRS 21 /* Enable Automatic IBRS */
#define EFER_SCE (1<<_EFER_SCE)
@@ -36,6 +37,7 @@
#define EFER_LMSLE (1<<_EFER_LMSLE)
#define EFER_FFXSR (1<<_EFER_FFXSR)
#define EFER_TCE (1<<_EFER_TCE)
+#define EFER_NDA (1<<_EFER_NDA)
#define EFER_AUTOIBRS (1<<_EFER_AUTOIBRS)
/*
diff --git a/arch/x86/include/asm/pgtable_types.h b/arch/x86/include/asm/pgtable_types.h
index 2ec250ba467e..f4654b2e63d0 100644
--- a/arch/x86/include/asm/pgtable_types.h
+++ b/arch/x86/include/asm/pgtable_types.h
@@ -21,8 +21,9 @@
#define _PAGE_BIT_SOFTW2 10 /* " */
#define _PAGE_BIT_SOFTW3 11 /* " */
#define _PAGE_BIT_PAT_LARGE 12 /* On 2MB or 1GB pages */
-#define _PAGE_BIT_SOFTW4 57 /* available for programmer */
-#define _PAGE_BIT_SOFTW5 58 /* available for programmer */
+#define _PAGE_BIT_SOFTW4 56 /* available for programmer */
+#define _PAGE_BIT_SOFTW5 57 /* available for programmer */
+#define _PAGE_BIT_NDA 58 /* No data access */
#define _PAGE_BIT_PKEY_BIT0 59 /* Protection Keys, bit 1/4 */
#define _PAGE_BIT_PKEY_BIT1 60 /* Protection Keys, bit 2/4 */
#define _PAGE_BIT_PKEY_BIT2 61 /* Protection Keys, bit 3/4 */
@@ -65,6 +66,7 @@
#define _PAGE_SPECIAL (_AT(pteval_t, 1) << _PAGE_BIT_SPECIAL)
#define _PAGE_CPA_TEST (_AT(pteval_t, 1) << _PAGE_BIT_CPA_TEST)
#define _PAGE_KERNEL_4K (_AT(pteval_t, 1) << _PAGE_BIT_KERNEL_4K)
+#define _PAGE_NDA (_AT(pteval_t, 1) << _PAGE_BIT_NDA)
#ifdef CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS
#define _PAGE_PKEY_BIT0 (_AT(pteval_t, 1) << _PAGE_BIT_PKEY_BIT0)
#define _PAGE_PKEY_BIT1 (_AT(pteval_t, 1) << _PAGE_BIT_PKEY_BIT1)
@@ -192,6 +194,7 @@ enum page_cache_mode {
#define ___D _PAGE_DIRTY
#define ___G _PAGE_GLOBAL
#define __NX _PAGE_NX
+#define _NDA _PAGE_NDA
#define _ENC _PAGE_ENC
#define __WP _PAGE_CACHE_WP
@@ -210,6 +213,7 @@ enum page_cache_mode {
#define PAGE_COPY __pg(__PP| 0|_USR|___A|__NX| 0| 0| 0)
#define PAGE_READONLY __pg(__PP| 0|_USR|___A|__NX| 0| 0| 0)
#define PAGE_READONLY_EXEC __pg(__PP| 0|_USR|___A| 0| 0| 0| 0)
+#define PAGE_EXECONLY __pg(__PP| 0|_USR|___A|_NDA| 0| 0| 0)
/*
* Page tables needs to have Write=1 in order for any lower PTEs to be
diff --git a/arch/x86/include/asm/setup.h b/arch/x86/include/asm/setup.h
index 914eb32581c7..1199b0762d60 100644
--- a/arch/x86/include/asm/setup.h
+++ b/arch/x86/include/asm/setup.h
@@ -69,6 +69,12 @@ extern void x86_ce4100_early_setup(void);
static inline void x86_ce4100_early_setup(void) { }
#endif
+#ifdef CONFIG_X86_PS5
+extern void x86_ps5_early_setup(void);
+#else
+static inline void x86_ps5_early_setup(void) { }
+#endif
+
#include <linux/kexec_handover.h>
#ifndef _SETUP
diff --git a/arch/x86/include/uapi/asm/bootparam.h b/arch/x86/include/uapi/asm/bootparam.h
index dafbf581c515..791687363cbf 100644
--- a/arch/x86/include/uapi/asm/bootparam.h
+++ b/arch/x86/include/uapi/asm/bootparam.h
@@ -207,6 +207,7 @@ enum x86_hardware_subarch {
X86_SUBARCH_XEN,
X86_SUBARCH_INTEL_MID,
X86_SUBARCH_CE4100,
+ X86_SUBARCH_PS5,
X86_NR_SUBARCHS,
};
diff --git a/arch/x86/kernel/cpu/amd.c b/arch/x86/kernel/cpu/amd.c
index 31f01e9c7114..ec3c32893cca 100644
--- a/arch/x86/kernel/cpu/amd.c
+++ b/arch/x86/kernel/cpu/amd.c
@@ -1163,6 +1163,10 @@ static void init_amd(struct cpuinfo_x86 *c)
/* AMD CPUs don't need fencing after x2APIC/TSC_DEADLINE MSR writes. */
clear_cpu_cap(c, X86_FEATURE_APIC_MSRS_FENCE);
+ if (c->x86 == 0x17 && c->x86_model == 0x46)
+ strscpy(c->x86_model_id, "AMD Custom Zen 2 (Oberon)",
+ sizeof(c->x86_model_id));
+
/* Enable Translation Cache Extension */
if (cpu_has(c, X86_FEATURE_TCE))
msr_set_bit(MSR_EFER, _EFER_TCE);
diff --git a/arch/x86/kernel/head64.c b/arch/x86/kernel/head64.c
index fd28b53dbac5..569fc764d267 100644
--- a/arch/x86/kernel/head64.c
+++ b/arch/x86/kernel/head64.c
@@ -303,6 +303,11 @@ void __init __noreturn x86_64_start_reservations(char *real_mode_data)
case X86_SUBARCH_INTEL_MID:
x86_intel_mid_early_setup();
break;
+#ifdef CONFIG_X86_PS5
+ case X86_SUBARCH_PS5:
+ x86_ps5_early_setup();
+ break;
+#endif
default:
break;
}
diff --git a/arch/x86/kernel/i8253.c b/arch/x86/kernel/i8253.c
index cb9852ad6098..83bb0cf9e40b 100644
--- a/arch/x86/kernel/i8253.c
+++ b/arch/x86/kernel/i8253.c
@@ -31,6 +31,11 @@ struct clock_event_device *global_clock_event;
*/
static bool __init use_pit(void)
{
+#ifdef CONFIG_X86_PS5
+ /* PIT is not available. */
+ return false;
+#endif
+
if (!IS_ENABLED(CONFIG_X86_TSC) || !boot_cpu_has(X86_FEATURE_TSC))
return true;
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 0550359ed798..297ac533e017 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -114,7 +114,11 @@ EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_host);
*/
#ifdef CONFIG_X86_64
static
+#ifdef CONFIG_X86_PS5
+u64 __read_mostly efer_reserved_bits = ~((u64)(EFER_SCE | EFER_LME | EFER_LMA | EFER_NDA));
+#else
u64 __read_mostly efer_reserved_bits = ~((u64)(EFER_SCE | EFER_LME | EFER_LMA));
+#endif
#else
static u64 __read_mostly efer_reserved_bits = ~((u64)EFER_SCE);
#endif
diff --git a/arch/x86/mm/pgprot.c b/arch/x86/mm/pgprot.c
index dc1afd5c839d..745db92fb2c1 100644
--- a/arch/x86/mm/pgprot.c
+++ b/arch/x86/mm/pgprot.c
@@ -10,7 +10,11 @@ static pgprot_t protection_map[16] __ro_after_init = {
[VM_READ] = PAGE_READONLY,
[VM_WRITE] = PAGE_COPY,
[VM_WRITE | VM_READ] = PAGE_COPY,
+#ifdef CONFIG_X86_PS5
+ [VM_EXEC] = PAGE_EXECONLY,
+#else
[VM_EXEC] = PAGE_READONLY_EXEC,
+#endif
[VM_EXEC | VM_READ] = PAGE_READONLY_EXEC,
[VM_EXEC | VM_WRITE] = PAGE_COPY_EXEC,
[VM_EXEC | VM_WRITE | VM_READ] = PAGE_COPY_EXEC,
@@ -18,7 +22,11 @@ static pgprot_t protection_map[16] __ro_after_init = {
[VM_SHARED | VM_READ] = PAGE_READONLY,
[VM_SHARED | VM_WRITE] = PAGE_SHARED,
[VM_SHARED | VM_WRITE | VM_READ] = PAGE_SHARED,
+#ifdef CONFIG_X86_PS5
+ [VM_SHARED | VM_EXEC] = PAGE_EXECONLY,
+#else
[VM_SHARED | VM_EXEC] = PAGE_READONLY_EXEC,
+#endif
[VM_SHARED | VM_EXEC | VM_READ] = PAGE_READONLY_EXEC,
[VM_SHARED | VM_EXEC | VM_WRITE] = PAGE_SHARED_EXEC,
[VM_SHARED | VM_EXEC | VM_WRITE | VM_READ] = PAGE_SHARED_EXEC
diff --git a/arch/x86/pci/common.c b/arch/x86/pci/common.c
index 63105b29fbf5..f38e2601531c 100644
--- a/arch/x86/pci/common.c
+++ b/arch/x86/pci/common.c
@@ -57,14 +57,100 @@ int raw_pci_write(unsigned int domain, unsigned int bus, unsigned int devfn,
return -EINVAL;
}
+#ifdef CONFIG_X86_PS5
+static DEFINE_RAW_SPINLOCK(pci_lock);
+
+static int sfc_read(unsigned int domain, unsigned int bus, unsigned int rid,
+ int reg, int len, u32 *val)
+{
+ int busno;
+ int slot;
+ int func;
+
+ busno = (rid >> 8) & 0xff;
+ slot = (rid & 0xff) >> 3;
+ func = rid & 0x07;
+
+ if (busno == 0 || busno == 32) {
+ raw_pci_write(domain, bus, 0, 0xd90, 4, 4);
+ raw_pci_write(domain, bus, 0, 0xd80, 4, (32 << 24) | (slot << 19) | (func << 16) | (reg & 0xf80));
+ return raw_pci_read(domain, bus, 0, (reg & 0x7f) | 0xf80, len, val);
+ } else if (busno < 32) {
+ raw_pci_write(domain, bus, 0, 0xd10, 4, busno == 1 ? 4 : 5);
+ raw_pci_write(domain, bus, 0, 0xd00, 4, (busno << 24) | (slot << 19) | (func << 16) | (reg & 0xf80));
+ return raw_pci_read(domain, bus, 0, (reg & 0x7f) | 0xf00, len, val);
+ } else {
+ panic("wrong bus number");
+ }
+}
+
+static int sfc_write(unsigned int domain, unsigned int bus, unsigned int rid,
+ int reg, int len, u32 val)
+{
+ int busno;
+ int slot;
+ int func;
+
+ busno = (rid >> 8) & 0xff;
+ slot = (rid & 0xff) >> 3;
+ func = rid & 0x07;
+
+ if (busno == 0 || busno == 32) {
+ raw_pci_write(domain, bus, 0, 0xd90, 4, 4);
+ raw_pci_write(domain, bus, 0, 0xd80, 4, (32 << 24) | (slot << 19) | (func << 16) | (reg & 0xf80));
+ return raw_pci_write(domain, bus, 0, (reg & 0x7f) | 0xf80, len, val);
+ } else if (busno < 32) {
+ raw_pci_write(domain, bus, 0, 0xd10, 4, busno == 1 ? 4 : 5);
+ raw_pci_write(domain, bus, 0, 0xd00, 4, (busno << 24) | (slot << 19) | (func << 16) | (reg & 0xf80));
+ return raw_pci_write(domain, bus, 0, (reg & 0x7f) | 0xf00, len, val);
+ } else {
+ panic("wrong bus number");
+ }
+}
+#endif
+
static int pci_read(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 *value)
{
+ int ret;
+ unsigned long flags;
+
+#ifdef CONFIG_X86_PS5
+ if (pci_ari_enabled(bus)) {
+ u32 rid = 0;
+ raw_spin_lock_irqsave(&pci_lock, flags);
+ raw_pci_read(pci_domain_nr(bus), bus->number, devfn, 0x150, 2, &rid);
+ if (rid != 0 && rid != 0xffff) {
+ ret = sfc_read(pci_domain_nr(bus), bus->number, rid, where, size, value);
+ raw_spin_unlock_irqrestore(&pci_lock, flags);
+ return ret;
+ }
+ raw_spin_unlock_irqrestore(&pci_lock, flags);
+ }
+#endif
+
return raw_pci_read(pci_domain_nr(bus), bus->number,
devfn, where, size, value);
}
static int pci_write(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 value)
{
+ int ret;
+ unsigned long flags;
+
+#ifdef CONFIG_X86_PS5
+ if (pci_ari_enabled(bus)) {
+ u32 rid = 0;
+ raw_spin_lock_irqsave(&pci_lock, flags);
+ raw_pci_read(pci_domain_nr(bus), bus->number, devfn, 0x150, 2, &rid);
+ if (rid != 0 && rid != 0xffff) {
+ ret = sfc_write(pci_domain_nr(bus), bus->number, rid, where, size, value);
+ raw_spin_unlock_irqrestore(&pci_lock, flags);
+ return ret;
+ }
+ raw_spin_unlock_irqrestore(&pci_lock, flags);
+ }
+#endif
+
return raw_pci_write(pci_domain_nr(bus), bus->number,
devfn, where, size, value);
}
diff --git a/arch/x86/pci/irq.c b/arch/x86/pci/irq.c
index 0de436316a1d..dde625251c99 100644
--- a/arch/x86/pci/irq.c
+++ b/arch/x86/pci/irq.c
@@ -1720,6 +1720,11 @@ static int pirq_enable_irq(struct pci_dev *dev)
{
u8 pin = 0;
+#ifdef CONFIG_X86_PS5
+ /* Legacy IRQ is not available. */
+ return 0;
+#endif
+
pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
if (pin && !pcibios_lookup_irq(dev, 1)) {
char *msg = "";
@@ -1801,6 +1806,11 @@ bool mp_should_keep_irq(struct device *dev)
static void pirq_disable_irq(struct pci_dev *dev)
{
+#ifdef CONFIG_X86_PS5
+ /* Legacy IRQ is not available. */
+ return;
+#endif
+
if (io_apic_assign_pci_irqs && !mp_should_keep_irq(&dev->dev) &&
dev->irq_managed && dev->irq) {
mp_unmap_irq(dev->irq);
diff --git a/arch/x86/platform/Makefile b/arch/x86/platform/Makefile
index 3ed03a2552d0..40ffa1a2156a 100644
--- a/arch/x86/platform/Makefile
+++ b/arch/x86/platform/Makefile
@@ -9,6 +9,7 @@ obj-y += intel/
obj-y += intel-mid/
obj-y += intel-quark/
obj-y += olpc/
+obj-y += ps5/
obj-y += scx200/
obj-y += ts5500/
obj-y += uv/
diff --git a/arch/x86/platform/ps5/Makefile b/arch/x86/platform/ps5/Makefile
new file mode 100644
index 000000000000..5263181876f8
--- /dev/null
+++ b/arch/x86/platform/ps5/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_X86_PS5) += ps5.o
diff --git a/arch/x86/platform/ps5/ps5.c b/arch/x86/platform/ps5/ps5.c
new file mode 100644
index 000000000000..acfbaf873315
--- /dev/null
+++ b/arch/x86/platform/ps5/ps5.c
@@ -0,0 +1,53 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include <linux/module.h>
+#include <linux/ps5.h>
+
+#include <asm/apic.h>
+#include <asm/i8259.h>
+#include <asm/reboot.h>
+#include <asm/setup.h>
+
+#define PS5_DEFAULT_TSC_FREQ 1596300000
+
+static __noreturn void ps5_power_off(void) {
+ icc_power_shutdown();
+}
+
+static __noreturn void ps5_emergency_restart(void) {
+ icc_power_reboot();
+}
+
+static __noreturn void ps5_restart(char *cmd) {
+ ps5_emergency_restart();
+}
+
+static unsigned long __init ps5_calibrate_tsc(void)
+{
+ return PS5_DEFAULT_TSC_FREQ / 1000;
+}
+
+static void ps5_get_wallclock(struct timespec64 *now)
+{
+ now->tv_sec = now->tv_nsec = 0;
+}
+
+static int ps5_set_wallclock(const struct timespec64 *now)
+{
+ return -ENODEV;
+}
+
+void __init x86_ps5_early_setup(void)
+{
+ x86_platform.calibrate_tsc = ps5_calibrate_tsc;
+ x86_platform.get_wallclock = ps5_get_wallclock;
+ x86_platform.set_wallclock = ps5_set_wallclock;
+ x86_platform.legacy.rtc = 0;
+
+ machine_ops.restart = ps5_restart;
+ machine_ops.power_off = ps5_power_off;
+ machine_ops.emergency_restart = ps5_emergency_restart;
+ pm_power_off = ps5_power_off;
+
+ legacy_pic = &null_legacy_pic;
+}
diff --git a/block/partitions/efi.c b/block/partitions/efi.c
index 9865d59093fa..5ffe7fefeae6 100644
--- a/block/partitions/efi.c
+++ b/block/partitions/efi.c
@@ -90,6 +90,9 @@
#include "check.h"
#include "efi.h"
+#define PS5_M2_PART44_LBA_OFFSET 34224
+#define PS5_M2_MBR_LBA 65536
+
/* This allows a kernel command line option 'gpt' to override
* the test for invalid PMBR. Not __initdata because reloading
* the partition tables happens after init too.
@@ -133,6 +136,12 @@ efi_crc32(const void *buf, unsigned long len)
*/
static u64 last_lba(struct gendisk *disk)
{
+#ifdef CONFIG_X86_PS5
+ if (strncmp(disk->disk_name, "nvme", 4) == 0) {
+ return div_u64(bdev_nr_bytes(disk->part0),
+ queue_logical_block_size(disk->queue)) - 1ULL - PS5_M2_PART44_LBA_OFFSET;
+ } else
+#endif
return div_u64(bdev_nr_bytes(disk->part0),
queue_logical_block_size(disk->queue)) - 1ULL;
}
@@ -143,8 +152,14 @@ static inline int pmbr_part_valid(gpt_mbr_record *part)
goto invalid;
/* set to 0x00000001 (i.e., the LBA of the GPT Partition Header) */
+#ifdef CONFIG_X86_PS5
+ if (le32_to_cpu(part->starting_lba) != GPT_PRIMARY_PARTITION_TABLE_LBA &&
+ le32_to_cpu(part->starting_lba) != PS5_M2_MBR_LBA + GPT_PRIMARY_PARTITION_TABLE_LBA)
+ goto invalid;
+#else
if (le32_to_cpu(part->starting_lba) != GPT_PRIMARY_PARTITION_TABLE_LBA)
goto invalid;
+#endif
return GPT_MBR_PROTECTIVE;
invalid:
@@ -599,6 +614,11 @@ static int find_valid_gpt(struct parsed_partitions *state, gpt_header **gpt,
if (!legacymbr)
goto fail;
+#ifdef CONFIG_X86_PS5
+ if (strncmp(state->disk->disk_name, "nvme", 4) == 0) {
+ read_lba(state, PS5_M2_MBR_LBA, (u8 *)legacymbr, sizeof(*legacymbr));
+ } else
+#endif
read_lba(state, 0, (u8 *)legacymbr, sizeof(*legacymbr));
good_pmbr = is_pmbr_valid(legacymbr, total_sectors);
kfree(legacymbr);
@@ -611,6 +631,12 @@ static int find_valid_gpt(struct parsed_partitions *state, gpt_header **gpt,
"protective" : "hybrid");
}
+#ifdef CONFIG_X86_PS5
+ if (strncmp(state->disk->disk_name, "nvme", 4) == 0) {
+ good_pgpt = is_gpt_valid(state, PS5_M2_MBR_LBA + GPT_PRIMARY_PARTITION_TABLE_LBA,
+ &pgpt, &pptes);
+ } else
+#endif
good_pgpt = is_gpt_valid(state, GPT_PRIMARY_PARTITION_TABLE_LBA,
&pgpt, &pptes);
if (good_pgpt)
diff --git a/drivers/Makefile b/drivers/Makefile
index 0841ea851847..02052a6cb226 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -198,3 +198,5 @@ obj-y += resctrl/
obj-$(CONFIG_DIBS) += dibs/
obj-$(CONFIG_S390) += s390/
+
+obj-$(CONFIG_X86_PS5) += ps5/
diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig
index fff305ec1e78..eb91eacbe159 100644
--- a/drivers/ata/Kconfig
+++ b/drivers/ata/Kconfig
@@ -298,6 +298,18 @@ config AHCI_QORIQ
If unsure, say N.
+config AHCI_SALINA
+ tristate "Sony PlayStation 5 Salina SATA / BD-ROM AHCI support"
+ depends on PCI
+ depends on X86_PS5 || COMPILE_TEST
+ select SATA_HOST
+ help
+ This option enables support for the PlayStation 5 "Salina" SATA
+ AHCI controller (PCI 104d:9105 / 104d:9106) that fronts the
+ internal Blu-ray drive.
+
+ If unsure, say N.
+
config SATA_FSL
tristate "Freescale 3.0Gbps SATA support"
depends on FSL_SOC || COMPILE_TEST
diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile
index 20e6645ab737..bc98a92325b7 100644
--- a/drivers/ata/Makefile
+++ b/drivers/ata/Makefile
@@ -27,6 +27,8 @@ obj-$(CONFIG_AHCI_ST) += ahci_st.o libahci.o libahci_platform.o
obj-$(CONFIG_AHCI_TEGRA) += ahci_tegra.o libahci.o libahci_platform.o
obj-$(CONFIG_AHCI_XGENE) += ahci_xgene.o libahci.o libahci_platform.o
obj-$(CONFIG_AHCI_QORIQ) += ahci_qoriq.o libahci.o libahci_platform.o
+obj-$(CONFIG_AHCI_SALINA) += ahci_salina_drv.o libahci.o
+ahci_salina_drv-y := ahci_salina.o ahci_salina_phy.o
# SFF w/ custom DMA
obj-$(CONFIG_PDC_ADMA) += pdc_adma.o
diff --git a/drivers/ata/ahci_salina.c b/drivers/ata/ahci_salina.c
new file mode 100644
index 000000000000..c020194eb44a
--- /dev/null
+++ b/drivers/ata/ahci_salina.c
@@ -0,0 +1,340 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * PlayStation 5 Salina SATA / BD-ROM AHCI host driver
+ *
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/io.h>
+#include <linux/dma-mapping.h>
+#include <linux/pm.h>
+#include <linux/libata.h>
+#include <linux/ps5.h>
+#include <scsi/scsi_host.h>
+
+#include "ahci.h"
+#include "ahci_salina_phy.h"
+
+#define PCI_DEVICE_ID_SPCIE 0x9107
+
+#define SALINA_ICC_DEV_BD 0x01
+
+struct salina_ahci {
+ struct salina_sata_phy phy;
+ struct pci_dev *glue;
+};
+
+static int salina_glue_map(struct salina_ahci *sa)
+{
+ struct pci_dev *glue;
+
+ glue = pci_get_device(PCI_VENDOR_ID_SONY, PCI_DEVICE_ID_SPCIE, NULL);
+ if (!glue)
+ return -ENODEV;
+
+ if (!(pci_resource_flags(glue, 2) & IORESOURCE_MEM) ||
+ !(pci_resource_flags(glue, 4) & IORESOURCE_MEM)) {
+ pci_dev_put(glue);
+ return -ENODEV;
+ }
+
+ sa->phy.glue_phy = ioremap(pci_resource_start(glue, 2),
+ pci_resource_len(glue, 2));
+ if (!sa->phy.glue_phy) {
+ pci_dev_put(glue);
+ return -ENOMEM;
+ }
+
+ sa->phy.glue_pcs = ioremap(pci_resource_start(glue, 4),
+ pci_resource_len(glue, 4));
+ if (!sa->phy.glue_pcs) {
+ iounmap(sa->phy.glue_phy);
+ sa->phy.glue_phy = NULL;
+ pci_dev_put(glue);
+ return -ENOMEM;
+ }
+
+ sa->glue = glue;
+ return 0;
+}
+
+static void salina_glue_unmap(struct salina_ahci *sa)
+{
+ if (sa->phy.glue_pcs) {
+ iounmap(sa->phy.glue_pcs);
+ sa->phy.glue_pcs = NULL;
+ }
+ if (sa->phy.glue_phy) {
+ iounmap(sa->phy.glue_phy);
+ sa->phy.glue_phy = NULL;
+ }
+ if (sa->glue) {
+ pci_dev_put(sa->glue);
+ sa->glue = NULL;
+ }
+}
+
+static int salina_pick_bar(u16 devid, u32 chip_id, unsigned int *abar,
+ u32 *port_off)
+{
+ bool is_9106 = (devid == PCI_DEVICE_ID_AHCI_B);
+
+ if (!is_9106 && chip_id == SALINA_CHIP_SALINA2)
+ return -ENODEV;
+
+ *abar = 0;
+ *port_off = is_9106 ? 0x2000 : 0;
+ return 0;
+}
+
+static struct ata_port_operations salina_ahci_ops = {
+ .inherits = &ahci_ops,
+};
+
+static const struct ata_port_info salina_port_info = {
+ .flags = AHCI_FLAG_COMMON,
+ .pio_mask = ATA_PIO4,
+ .udma_mask = ATA_UDMA6,
+ .port_ops = &salina_ahci_ops,
+};
+
+static const struct scsi_host_template salina_ahci_sht = {
+ AHCI_SHT(KBUILD_MODNAME),
+};
+
+static int salina_ahci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+ struct device *dev = &pdev->dev;
+ const struct ata_port_info *ppi[] = { &salina_port_info, NULL };
+ struct ahci_host_priv *hpriv;
+ struct ata_host *host;
+ struct salina_ahci *sa;
+ unsigned int abar, n_ports;
+ u32 chip_id;
+ u8 state;
+ int rc;
+
+ if (!spcie_is_initialized()) {
+ dev_warn(dev, "spcie not initialized yet, deferring\n");
+ return -EPROBE_DEFER;
+ }
+
+ rc = pcim_enable_device(pdev);
+ if (rc)
+ return rc;
+
+ pci_set_master(pdev);
+
+ rc = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32));
+ if (rc)
+ return rc;
+
+ sa = devm_kzalloc(dev, sizeof(*sa), GFP_KERNEL);
+ if (!sa)
+ return -ENOMEM;
+
+ rc = salina_glue_map(sa);
+ if (rc) {
+ dev_err(dev, "glue (104d:9107) map failed: %d\n", rc);
+ return rc;
+ }
+
+ chip_id = spcie_get_chip_id();
+ if (chip_id != SALINA_CHIP_SALINA && chip_id != SALINA_CHIP_SALINA2) {
+ dev_err(dev, "unknown Salina chip id %#x\n", chip_id);
+ rc = -ENODEV;
+ goto err_glue;
+ }
+
+ rc = salina_pick_bar(pdev->device, chip_id, &abar, &sa->phy.port_off);
+ if (rc) {
+ dev_info(dev, "SALINA2 SATA0 dummy device, claiming but not attaching\n");
+ pci_set_drvdata(pdev, NULL);
+ salina_glue_unmap(sa);
+ return 0;
+ }
+
+ rc = pcim_iomap_regions(pdev, BIT(abar), KBUILD_MODNAME);
+ if (rc)
+ goto err_glue;
+
+ sa->phy.ctrl = pcim_iomap_table(pdev)[abar];
+ sa->phy.chip_id = chip_id;
+ sa->phy.devid = (pdev->device << 16) | pdev->vendor;
+ sa->phy.is_bd = true;
+ sa->phy.rx_tracelen = 0xff;
+ sa->phy.tx_tracelen = 0xff;
+
+ icc_device_power_get(SALINA_ICC_DEV_BD, &state);
+ if (state != 1)
+ icc_device_power_control(SALINA_ICC_DEV_BD, 1);
+
+ rc = salina_sata_phy_init(&sa->phy);
+ if (rc) {
+ dev_err(dev, "Salina SATA PHY init failed: %d\n", rc);
+ goto err_glue;
+ }
+
+ hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL);
+ if (!hpriv) {
+ rc = -ENOMEM;
+ goto err_glue;
+ }
+
+ hpriv->mmio = sa->phy.ctrl + sa->phy.port_off;
+ hpriv->plat_data = sa;
+ hpriv->flags = AHCI_HFLAG_NO_PMP;
+
+ ahci_save_initial_config(dev, hpriv);
+
+ rc = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_MSI | PCI_IRQ_INTX);
+ if (rc < 0) {
+ dev_err(dev, "irq alloc failed: %d\n", rc);
+ goto err_glue;
+ }
+ hpriv->irq = pci_irq_vector(pdev, 0);
+
+ n_ports = max(ahci_nr_ports(hpriv->cap), fls(hpriv->port_map));
+
+ host = ata_host_alloc_pinfo(dev, ppi, n_ports);
+ if (!host) {
+ rc = -ENOMEM;
+ goto err_glue;
+ }
+ host->private_data = hpriv;
+
+ if (!(hpriv->cap & HOST_CAP_SSS))
+ host->flags |= ATA_HOST_PARALLEL_SCAN;
+
+ rc = ahci_reset_controller(host);
+ if (rc)
+ goto err_glue;
+
+ ahci_init_controller(host);
+ ahci_print_info(host, "Salina");
+
+ pci_set_drvdata(pdev, host);
+
+ dev_info(dev,
+ "Salina SATA up (chip %#x, devid %#x, BAR%u, port_off %#x, %u ports)\n",
+ sa->phy.chip_id, sa->phy.devid, abar, sa->phy.port_off, n_ports);
+
+ return ahci_host_activate(host, &salina_ahci_sht);
+
+err_glue:
+ salina_glue_unmap(sa);
+ return rc;
+}
+
+static void salina_ahci_remove(struct pci_dev *pdev)
+{
+ struct ata_host *host = pci_get_drvdata(pdev);
+ struct ahci_host_priv *hpriv;
+ struct salina_ahci *sa;
+
+ if (!host)
+ return;
+
+ hpriv = host->private_data;
+ sa = hpriv->plat_data;
+
+ ata_host_detach(host);
+ pci_free_irq_vectors(pdev);
+ salina_glue_unmap(sa);
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int salina_ahci_suspend(struct device *dev)
+{
+ struct pci_dev *pdev = to_pci_dev(dev);
+ struct ata_host *host = pci_get_drvdata(pdev);
+ struct ahci_host_priv *hpriv;
+ void __iomem *mmio;
+ u32 ctl;
+ int rc;
+
+ if (!host)
+ return 0;
+
+ hpriv = host->private_data;
+ mmio = hpriv->mmio;
+
+ ctl = readl(mmio + HOST_CTL);
+ ctl &= ~HOST_IRQ_EN;
+ writel(ctl, mmio + HOST_CTL);
+ readl(mmio + HOST_CTL);
+
+ rc = ata_host_suspend(host, PMSG_SUSPEND);
+ if (rc)
+ return rc;
+
+ pci_save_state(pdev);
+ pci_set_power_state(pdev, PCI_D3hot);
+ return 0;
+}
+
+static int salina_ahci_resume(struct device *dev)
+{
+ struct pci_dev *pdev = to_pci_dev(dev);
+ struct ata_host *host = pci_get_drvdata(pdev);
+ struct ahci_host_priv *hpriv;
+ struct salina_ahci *sa;
+ int rc;
+
+ if (!host)
+ return 0;
+
+ hpriv = host->private_data;
+ sa = hpriv->plat_data;
+
+ rc = pci_set_power_state(pdev, PCI_D0);
+ if (rc)
+ return rc;
+ pci_restore_state(pdev);
+ pci_set_master(pdev);
+
+ rc = salina_sata_phy_init(&sa->phy);
+ if (rc) {
+ dev_err(dev, "PHY re-init on resume failed: %d\n", rc);
+ return rc;
+ }
+
+ rc = ahci_reset_controller(host);
+ if (rc)
+ return rc;
+
+ ahci_init_controller(host);
+ ata_host_resume(host);
+
+ return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(salina_ahci_pm, salina_ahci_suspend, salina_ahci_resume);
+
+static const struct pci_device_id salina_ahci_tbl[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_SONY, PCI_DEVICE_ID_AHCI_A) },
+ { PCI_DEVICE(PCI_VENDOR_ID_SONY, PCI_DEVICE_ID_AHCI_B) },
+ { }
+};
+MODULE_DEVICE_TABLE(pci, salina_ahci_tbl);
+
+static struct pci_driver salina_ahci_driver = {
+ .name = KBUILD_MODNAME,
+ .id_table = salina_ahci_tbl,
+ .probe = salina_ahci_probe,
+ .remove = salina_ahci_remove,
+ .driver = {
+ .pm = &salina_ahci_pm,
+ },
+};
+
+module_pci_driver(salina_ahci_driver);
+
+MODULE_AUTHOR("Armandas Kvietkus");
+MODULE_DESCRIPTION("PlayStation 5 Salina SATA / BD-ROM AHCI driver");
+MODULE_LICENSE("GPL");
+MODULE_SOFTDEP("pre: libahci spcie");
diff --git a/drivers/ata/ahci_salina_phy.c b/drivers/ata/ahci_salina_phy.c
new file mode 100644
index 000000000000..c5e85ae102ea
--- /dev/null
+++ b/drivers/ata/ahci_salina_phy.c
@@ -0,0 +1,183 @@
+// SPDX-License-Identifier: GPL-2.0-only
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include "ahci_salina_phy.h"
+
+static inline u32 phy_rd(struct salina_sata_phy *p, u32 off)
+{
+ return readl(p->ctrl + off);
+}
+
+static inline void phy_wr(struct salina_sata_phy *p, u32 off, u32 val)
+{
+ writel(val, p->ctrl + off);
+}
+
+static inline void phy_rmw(struct salina_sata_phy *p, u32 off, u32 keep, u32 set)
+{
+ phy_wr(p, off, (phy_rd(p, off) & keep) | set);
+}
+
+static inline u32 port_rd(struct salina_sata_phy *p, u32 off)
+{
+ return readl(p->ctrl + p->port_off + off);
+}
+
+static inline void port_wr(struct salina_sata_phy *p, u32 off, u32 val)
+{
+ writel(val, p->ctrl + p->port_off + off);
+}
+
+static inline void lane_sel(struct salina_sata_phy *p, u32 sel, u32 val)
+{
+ writel(val, p->glue_phy + SALINA_GLUE_PHY_BASE + sel);
+}
+
+static inline u32 efuse_rd(struct salina_sata_phy *p, u32 off)
+{
+ return readl(p->glue_pcs + SALINA_GLUE_PCS_BASE + off);
+}
+
+static u32 trace_len(struct salina_sata_phy *p, u32 raw)
+{
+ u32 def = p->is_bd ? 10 : 4;
+
+ if (raw == 0 || raw > 0xfe)
+ return def;
+ return (raw >> 5 & 7) + (raw & 0x1f);
+}
+
+int salina_sata_phy_init(struct salina_sata_phy *p)
+{
+ u32 trim[6];
+ u32 efuse, valid, sel, lane;
+ u32 rx, tx;
+ u32 a, b, c, d, e, f, rc;
+ bool tx_hi;
+
+ sel = (p->devid != SALINA_DEVID_A) ? SALINA_PHY_SEL_B : SALINA_PHY_SEL_A;
+ lane_sel(p, sel, 2);
+ lane_sel(p, sel, 3);
+ lane_sel(p, sel, 1);
+
+ efuse = efuse_rd(p, SALINA_EFUSE_TRIM);
+ valid = efuse_rd(p, SALINA_EFUSE_VALID);
+
+ trim[0] = trim[1] = trim[2] = trim[3] = 0x10;
+ trim[4] = trim[5] = 0x28;
+
+ if (valid & SALINA_EFUSE_VALID_A) {
+ trim[4] = efuse & 0x3f;
+ trim[2] = efuse >> 6 & 0x1f;
+ trim[0] = efuse >> 0xb & 0x1f;
+ }
+ if (valid & SALINA_EFUSE_VALID_B) {
+ trim[5] = efuse >> 0x10 & 0x3f;
+ trim[3] = efuse >> 0x16 & 0x1f;
+ trim[1] = efuse >> 0x1b;
+ }
+
+ lane = (p->devid != SALINA_DEVID_A) ? 1 : 0;
+
+ phy_rmw(p, 0xa0, 0xfbff03ff, (trim[lane + 4] << 10) | 0x4000000);
+ phy_rmw(p, 0x14, ~0u, 0x100000);
+ phy_rmw(p, 0x54, 0xfffff07f, trim[lane + 2] << 7);
+ phy_rmw(p, 0x1c, ~0u, 4);
+ phy_rmw(p, 0x78, 0xfffffe0f, trim[lane] << 4);
+
+ rx = trace_len(p, p->rx_tracelen);
+ tx = trace_len(p, p->tx_tracelen);
+
+ tx_hi = tx > 5;
+ if (tx_hi) {
+ c = 0x2000;
+ if (tx < 9) {
+ b = 0x1000000;
+ a = 0x200000;
+ } else {
+ a = (tx <= 0xc) ? 0x230000 : 0x260000;
+ b = (tx > 0xc) ? 0x9000000 : 0x5000000;
+ }
+ } else {
+ b = 0;
+ a = (tx >= 3) ? 0x1e0000 : 0x1d0000;
+ c = (tx < 3) ? 0x4000 : 0x2000;
+ }
+
+ e = (tx > 8) ? 0x4000 : 0;
+ f = (tx > 8) ? 0x80 : 0;
+ d = e | 0x12000;
+ rc = f | 0x900;
+ e += 0x6000;
+ f += 0x8c0;
+ if (tx < 6) {
+ u32 ge3 = (tx >= 3) ? 1 : 0;
+
+ d = ge3 * 0x1000 + 0xd000;
+ rc = (ge3 * 0x40) | 0x880;
+ e = ge3 << 0xd;
+ f = ge3 * 0x40 + 0x800;
+ }
+
+ phy_rmw(p, 0x4c, 0xffc0ffff, a);
+ phy_rmw(p, 0x4c, 0xc0ffffff, b);
+ phy_rmw(p, 0x54, 0xffff9fff, c);
+ phy_rmw(p, 0x7c, 0xfffff03f, f);
+ phy_rmw(p, 0x7c, 0xfffc0fff, e);
+ phy_rmw(p, 0x5c, 0x0fffffff, (tx < 3) ? 0x60000000 : 0x50000000);
+ phy_rmw(p, 0x80, 0xfffff03f, rc);
+ phy_rmw(p, 0x80, 0xfffc0fff, d);
+ phy_rmw(p, 0x4c, 0xfffffff0, tx_hi ? 5 : 3);
+
+ {
+ u32 rx_coef, rx_amp, rx_eq;
+
+ if (rx < 3) {
+ rx_coef = 0x100;
+ rx_amp = 0x40;
+ rx_eq = 2;
+ } else if (rx < 6) {
+ rx_coef = 0x100;
+ rx_amp = 0x50;
+ rx_eq = 3;
+ } else {
+ rx_amp = 0x60;
+ rx_coef = 0x200;
+ rx_eq = 5;
+ }
+ phy_rmw(p, 0x6c, 0xfffff0ff, rx_coef);
+ phy_rmw(p, 0x84, 0xffffff00, rx_amp | rx_eq);
+ }
+
+ phy_rmw(p, 0x40, 0xffffffe0, 0x12);
+ phy_rmw(p, 0x40, 0xffffc0ff, 0x3100);
+ phy_rmw(p, 0x40, 0xffe0ffff, 0xe0000);
+ phy_rmw(p, 0x40, 0xffffff1f, 0x80);
+ phy_rmw(p, 0x3c, 0x1fffefff, 0xa0000000);
+ phy_rmw(p, 0x44, 0xffffef80, 0x23);
+ phy_rmw(p, 0x1c, 0xff0fffff, 0x200000);
+ phy_rmw(p, 0xdc, 0xffffe0ff, 0x400);
+ phy_rmw(p, 0x24, ~0u, 0x30);
+
+ lane_sel(p, sel, 0);
+
+ {
+ int i;
+
+ for (i = 0; i < 100; i++) {
+ if (port_rd(p, SALINA_PHY_RDY_REG) & SALINA_PHY_RDY)
+ break;
+ udelay(10);
+ }
+ if (i == 100)
+ return -ETIMEDOUT;
+ }
+
+ port_wr(p, 0, port_rd(p, 0) & 0xe7ffffff);
+ port_wr(p, 0xc, 1);
+ port_wr(p, 0xb8, port_rd(p, 0xb8) | 0x20000);
+ port_wr(p, 0x118, (port_rd(p, 0x118) & 0xffe3ffff) | 0x40000);
+
+ return 0;
+}
diff --git a/drivers/ata/ahci_salina_phy.h b/drivers/ata/ahci_salina_phy.h
new file mode 100644
index 000000000000..39cc76f39e06
--- /dev/null
+++ b/drivers/ata/ahci_salina_phy.h
@@ -0,0 +1,45 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef _SALINA_SATA_PHY_H
+#define _SALINA_SATA_PHY_H
+
+#include <linux/types.h>
+#include <linux/io.h>
+
+#define PCI_DEVICE_ID_AHCI_A 0x9105
+#define PCI_DEVICE_ID_AHCI_B 0x9106
+
+#define SALINA_DEVID_A 0x9105104d
+#define SALINA_DEVID_B 0x9106104d
+
+#define SALINA_CHIP_SALINA 0x110000
+#define SALINA_CHIP_SALINA2 0x120000
+
+#define SALINA_GLUE_PHY_BASE 0x180000
+#define SALINA_GLUE_PCS_BASE 0x4000
+
+#define SALINA_EFUSE_TRIM 0x48
+#define SALINA_EFUSE_VALID 0x6c
+#define SALINA_EFUSE_VALID_A 0x40000
+#define SALINA_EFUSE_VALID_B 0x4000000
+
+#define SALINA_PHY_SEL_A 0x2c
+#define SALINA_PHY_SEL_B 0x30
+
+#define SALINA_PHY_RDY BIT(0)
+#define SALINA_PHY_RDY_REG 0xdc
+
+struct salina_sata_phy {
+ void __iomem *ctrl;
+ void __iomem *glue_phy;
+ void __iomem *glue_pcs;
+ u32 port_off;
+ u32 chip_id;
+ u32 devid;
+ u32 rx_tracelen;
+ u32 tx_tracelen;
+ bool is_bd;
+};
+
+int salina_sata_phy_init(struct salina_sata_phy *p);
+
+#endif
diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
index 830fefb342c6..380bc421583d 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -67,6 +67,10 @@ static struct usb_driver btusb_driver;
#define BTUSB_INTEL_NO_WBS_SUPPORT BIT(26)
#define BTUSB_ACTIONS_SEMI BIT(27)
#define BTUSB_BARROT BIT(28)
+#define BTUSB_IFNUM_0 BIT(29)
+#define BTUSB_BROKEN_LE_DEFAULT_PHY BIT(30)
+#define BTUSB_BROKEN_READ_LOCAL_NAME BIT(31)
+#define BTUSB_NO_AUTOSUSPEND BIT(32)
static const struct usb_device_id btusb_table[] = {
/* Generic Bluetooth USB device */
@@ -172,6 +176,14 @@ static const struct usb_device_id btusb_table[] = {
{ USB_DEVICE(0x8087, 0x0a5a),
.driver_info = BTUSB_INTEL_BOOT | BTUSB_BROKEN_ISOC },
+ /* PS5 IW620 Bluetooth device */
+ { USB_DEVICE(0x1286, 0x2059),
+ .driver_info = BTUSB_MARVELL |
+ BTUSB_IFNUM_0 |
+ BTUSB_BROKEN_LE_DEFAULT_PHY |
+ BTUSB_BROKEN_READ_LOCAL_NAME |
+ BTUSB_NO_AUTOSUSPEND },
+
{ } /* Terminating entry */
};
@@ -472,6 +484,11 @@ static const struct usb_device_id quirks_table[] = {
{ USB_DEVICE(0x1286, 0x2044), .driver_info = BTUSB_MARVELL },
{ USB_DEVICE(0x1286, 0x2046), .driver_info = BTUSB_MARVELL },
{ USB_DEVICE(0x1286, 0x204e), .driver_info = BTUSB_MARVELL },
+ { USB_DEVICE(0x1286, 0x2059), .driver_info = BTUSB_MARVELL |
+ BTUSB_IFNUM_0 |
+ BTUSB_BROKEN_LE_DEFAULT_PHY |
+ BTUSB_BROKEN_READ_LOCAL_NAME |
+ BTUSB_NO_AUTOSUSPEND },
/* Intel Bluetooth devices */
{ USB_DEVICE(0x8087, 0x0025), .driver_info = BTUSB_INTEL_COMBINED },
@@ -4055,6 +4072,10 @@ static int btusb_probe(struct usb_interface *intf,
(intf->cur_altsetting->desc.bInterfaceNumber != 2))
return -ENODEV;
+ if ((id->driver_info & BTUSB_IFNUM_0) &&
+ intf->cur_altsetting->desc.bInterfaceNumber != 0)
+ return -ENODEV;
+
ifnum_base = intf->cur_altsetting->desc.bInterfaceNumber;
if (!id->driver_info) {
@@ -4344,6 +4365,12 @@ static int btusb_probe(struct usb_interface *intf,
if (id->driver_info & BTUSB_INVALID_LE_STATES)
hci_set_quirk(hdev, HCI_QUIRK_BROKEN_LE_STATES);
+ if (id->driver_info & BTUSB_BROKEN_LE_DEFAULT_PHY)
+ hci_set_quirk(hdev, HCI_QUIRK_BROKEN_SET_DEFAULT_PHY);
+
+ if (id->driver_info & BTUSB_BROKEN_READ_LOCAL_NAME)
+ hci_set_quirk(hdev, HCI_QUIRK_BROKEN_READ_LOCAL_NAME);
+
if (id->driver_info & BTUSB_DIGIANSWER) {
data->cmdreq_type = USB_TYPE_VENDOR;
hci_set_quirk(hdev, HCI_QUIRK_RESET_ON_CLOSE);
@@ -4400,7 +4427,7 @@ static int btusb_probe(struct usb_interface *intf,
data->diag = NULL;
}
- if (enable_autosuspend)
+ if (enable_autosuspend && !(id->driver_info & BTUSB_NO_AUTOSUSPEND))
usb_enable_autosuspend(data->udev);
data->poll_sync = enable_poll_sync;
diff --git a/drivers/firmware/dmi-id.c b/drivers/firmware/dmi-id.c
index 477a37e2ef80..e1af70946c89 100644
--- a/drivers/firmware/dmi-id.c
+++ b/drivers/firmware/dmi-id.c
@@ -228,8 +228,16 @@ static int __init dmi_id_init(void)
{
int ret;
+#ifdef CONFIG_X86_PS5
+ dmi_set_system_info(DMI_SYS_VENDOR, "Sony Interactive Entertainment");
+ dmi_set_system_info(DMI_PRODUCT_NAME, "PlayStation 5");
+ /* Filled by spcie.c */
+ dmi_set_system_info(DMI_PRODUCT_VERSION, "Unknown");
+ dmi_set_system_info(DMI_PRODUCT_SERIAL, "Unknown");
+#else
if (!dmi_available)
return -ENODEV;
+#endif
dmi_id_init_attr_table();
diff --git a/drivers/firmware/dmi_scan.c b/drivers/firmware/dmi_scan.c
index a3f7dabd4955..77f616a11b1c 100644
--- a/drivers/firmware/dmi_scan.c
+++ b/drivers/firmware/dmi_scan.c
@@ -957,6 +957,14 @@ const char *dmi_get_system_info(int field)
}
EXPORT_SYMBOL(dmi_get_system_info);
+#ifdef CONFIG_X86_PS5
+void dmi_set_system_info(int field, const char *str)
+{
+ dmi_ident[field] = str;
+}
+EXPORT_SYMBOL(dmi_set_system_info);
+#endif
+
/**
* dmi_name_in_serial - Check if string is in the DMI product serial information
* @str: string to check for
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
index fd50da4c7b18..caf9cce37100 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
@@ -270,6 +270,10 @@ extern int amdgpu_user_queue;
extern uint amdgpu_hdmi_hpd_debounce_delay_ms;
+#ifdef CONFIG_X86_PS5
+extern int amdgpu_force_1080p;
+#endif
+
#define AMDGPU_VM_MAX_NUM_CTX 4096
#define AMDGPU_SG_THRESHOLD (256*1024*1024)
#define AMDGPU_WAIT_IDLE_TIMEOUT_IN_MS 3000
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c
index 35d04e69aec0..314ceaaaab9f 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c
@@ -221,8 +221,14 @@ static bool amdgpu_read_bios_from_rom(struct amdgpu_device *adev)
static bool amdgpu_read_platform_bios(struct amdgpu_device *adev)
{
+#ifdef CONFIG_X86_PS5
+ /* Hardcode vbios rom address. */
+ phys_addr_t rom = 0xc0000;
+ size_t romlen = 0x10000;
+#else
phys_addr_t rom = adev->pdev->rom;
size_t romlen = adev->pdev->romlen;
+#endif
void __iomem *bios;
adev->bios = NULL;
@@ -436,6 +442,7 @@ static inline bool amdgpu_acpi_vfct_bios(struct amdgpu_device *adev)
static bool amdgpu_get_bios_apu(struct amdgpu_device *adev)
{
+#ifndef CONFIG_X86_PS5
if (amdgpu_acpi_vfct_bios(adev)) {
dev_info(adev->dev, "Fetched VBIOS from VFCT\n");
goto success;
@@ -450,6 +457,7 @@ static bool amdgpu_get_bios_apu(struct amdgpu_device *adev)
dev_info(adev->dev, "Fetched VBIOS from ROM BAR\n");
goto success;
}
+#endif
if (amdgpu_read_platform_bios(adev)) {
dev_info(adev->dev, "Fetched VBIOS from platform\n");
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
index feab90e3efd1..4ebde822fca2 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
@@ -1814,6 +1814,26 @@ static int amdgpu_device_parse_gpu_info_fw(struct amdgpu_device *adev)
case CHIP_CYAN_SKILLFISH:
if (adev->discovery.bin)
return 0;
+#ifdef CONFIG_X86_PS5
+ /* Hardcode gfxinfo. */
+ adev->gfx.config.max_shader_engines = 2;
+ adev->gfx.config.max_cu_per_sh = 10;
+ adev->gfx.config.max_sh_per_se = 2;
+ adev->gfx.config.max_backends_per_se = 8;
+ adev->gfx.config.max_texture_channel_caches = 16;
+ adev->gfx.config.max_gprs = 1024;
+ adev->gfx.config.max_gs_threads = 32;
+ adev->gfx.config.gs_vgt_table_depth = 32;
+ adev->gfx.config.gs_prim_buffer_depth = 1792;
+ adev->gfx.config.double_offchip_lds_buf = 1;
+ adev->gfx.cu_info.wave_front_size = 32;
+ adev->gfx.cu_info.max_waves_per_simd = 20;
+ adev->gfx.cu_info.max_scratch_slots_per_cu = 32;
+ adev->gfx.cu_info.lds_size = 64;
+ adev->gfx.config.num_sc_per_sh = 1;
+ adev->gfx.config.num_packer_per_sc = 2;
+ return 0;
+#endif
chip_name = "cyan_skillfish";
break;
}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c
index 80efeca0ab73..e0683340ff12 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c
@@ -3018,6 +3018,9 @@ int amdgpu_discovery_set_ip_blocks(struct amdgpu_device *adev)
adev->ip_versions[SMUIO_HWIP][0] = IP_VERSION(11, 0, 8);
adev->ip_versions[GC_HWIP][0] = IP_VERSION(10, 1, 3);
adev->ip_versions[UVD_HWIP][0] = IP_VERSION(2, 0, 3);
+#ifdef CONFIG_X86_PS5
+ adev->ip_versions[DCE_HWIP][0] = IP_VERSION(2, 0, 3);
+#endif
}
break;
default:
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
index 60debd543e44..3af3b36f4b60 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
@@ -41,6 +41,10 @@
#include <linux/suspend.h>
#include <linux/vga_switcheroo.h>
+#ifdef CONFIG_X86_PS5
+#include <linux/ps5.h>
+#endif
+
#include "amdgpu.h"
#include "amdgpu_amdkfd.h"
#include "amdgpu_dma_buf.h"
@@ -1112,6 +1116,12 @@ module_param_named(user_queue, amdgpu_user_queue, int, 0444);
MODULE_PARM_DESC(hdmi_hpd_debounce_delay_ms, "HDMI HPD disconnect debounce delay in milliseconds (0 to disable (by default), 1500 is common)");
module_param_named(hdmi_hpd_debounce_delay_ms, amdgpu_hdmi_hpd_debounce_delay_ms, uint, 0644);
+#ifdef CONFIG_X86_PS5
+int amdgpu_force_1080p = 0;
+MODULE_PARM_DESC(force_1080p, "Force 1080p (0 = disabled (default), 1 = enabled)");
+module_param_named(force_1080p, amdgpu_force_1080p, int, 0444);
+#endif
+
/* These devices are not supported by amdgpu.
* They are supported by the mach64, r128, radeon drivers
*/
@@ -2157,6 +2167,7 @@ static const struct pci_device_id pciidlist[] = {
{0x1002, 0x7410, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ALDEBARAN},
/* CYAN_SKILLFISH */
+ {0x1002, 0x13DA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CYAN_SKILLFISH|AMD_IS_APU},
{0x1002, 0x13DB, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CYAN_SKILLFISH|AMD_IS_APU},
{0x1002, 0x13F9, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CYAN_SKILLFISH|AMD_IS_APU},
{0x1002, 0x13FA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CYAN_SKILLFISH|AMD_IS_APU},
@@ -2370,6 +2381,11 @@ static int amdgpu_pci_probe(struct pci_dev *pdev,
int ret, retry = 0, i;
bool supports_atomic = false;
+#ifdef CONFIG_X86_PS5
+ if (!spcie_is_initialized())
+ return -EPROBE_DEFER;
+#endif
+
if ((pdev->class >> 8) == PCI_CLASS_DISPLAY_VGA ||
(pdev->class >> 8) == PCI_CLASS_DISPLAY_OTHER) {
if (drm_firmware_drivers_only() && amdgpu_modeset == -1)
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c
index b8ca876694ff..02c04136f293 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c
@@ -2434,6 +2434,11 @@ void amdgpu_gfx_profile_ring_begin_use(struct amdgpu_ring *ring)
enum PP_SMC_POWER_PROFILE profile;
int r;
+#ifdef CONFIG_X86_PS5
+ /* DPM is not supported. */
+ return;
+#endif
+
if (amdgpu_dpm_is_overdrive_enabled(adev))
return;
@@ -2469,6 +2474,11 @@ void amdgpu_gfx_profile_ring_end_use(struct amdgpu_ring *ring)
{
struct amdgpu_device *adev = ring->adev;
+#ifdef CONFIG_X86_PS5
+ /* DPM is not supported. */
+ return;
+#endif
+
if (amdgpu_dpm_is_overdrive_enabled(adev))
return;
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_sdma.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_sdma.c
index 321310ba2c08..764da52902ac 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_sdma.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_sdma.c
@@ -210,6 +210,9 @@ int amdgpu_sdma_init_microcode(struct amdgpu_device *adev,
const struct sdma_firmware_header_v3_0 *sdma_hv3;
uint16_t version_major;
char ucode_prefix[30];
+#ifdef CONFIG_X86_PS5
+ struct common_firmware_header *hdr;
+#endif
amdgpu_ucode_ip_version_decode(adev, SDMA0_HWIP, ucode_prefix, sizeof(ucode_prefix));
if (instance == 0)
@@ -222,6 +225,11 @@ int amdgpu_sdma_init_microcode(struct amdgpu_device *adev,
"amdgpu/%s%d.bin", ucode_prefix, instance);
if (err)
goto out;
+#ifdef CONFIG_X86_PS5
+ hdr = (struct common_firmware_header *)adev->sdma.instance[instance].fw->data;
+ hdr->ucode_array_offset_bytes = cpu_to_le32(le32_to_cpu(hdr->ucode_array_offset_bytes) + 0x100);
+ hdr->ucode_size_bytes = cpu_to_le32(le32_to_cpu(hdr->ucode_size_bytes) - 0x200);
+#endif
header = (const struct common_firmware_header *)
adev->sdma.instance[instance].fw->data;
diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c
index 8b60299b73ef..7ecf928cae8e 100644
--- a/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c
@@ -4202,6 +4202,14 @@ static void gfx_v10_0_check_gfxoff_flag(struct amdgpu_device *adev)
}
}
+static void gfx_v10_0_patch_ucode(const u8 *data)
+{
+ struct common_firmware_header *hdr;
+ hdr = (struct common_firmware_header *)data;
+ hdr->ucode_array_offset_bytes = cpu_to_le32(le32_to_cpu(hdr->ucode_array_offset_bytes) + 0x100);
+ hdr->ucode_size_bytes = cpu_to_le32(le32_to_cpu(hdr->ucode_size_bytes) - 0x200);
+}
+
static int gfx_v10_0_init_microcode(struct amdgpu_device *adev)
{
char fw_name[53];
@@ -4224,6 +4232,9 @@ static int gfx_v10_0_init_microcode(struct amdgpu_device *adev)
"amdgpu/%s_pfp%s.bin", ucode_prefix, wks);
if (err)
goto out;
+#ifdef CONFIG_X86_PS5
+ gfx_v10_0_patch_ucode(adev->gfx.pfp_fw->data);
+#endif
amdgpu_gfx_cp_init_microcode(adev, AMDGPU_UCODE_ID_CP_PFP);
err = amdgpu_ucode_request(adev, &adev->gfx.me_fw,
@@ -4231,6 +4242,9 @@ static int gfx_v10_0_init_microcode(struct amdgpu_device *adev)
"amdgpu/%s_me%s.bin", ucode_prefix, wks);
if (err)
goto out;
+#ifdef CONFIG_X86_PS5
+ gfx_v10_0_patch_ucode(adev->gfx.me_fw->data);
+#endif
amdgpu_gfx_cp_init_microcode(adev, AMDGPU_UCODE_ID_CP_ME);
err = amdgpu_ucode_request(adev, &adev->gfx.ce_fw,
@@ -4238,6 +4252,9 @@ static int gfx_v10_0_init_microcode(struct amdgpu_device *adev)
"amdgpu/%s_ce%s.bin", ucode_prefix, wks);
if (err)
goto out;
+#ifdef CONFIG_X86_PS5
+ gfx_v10_0_patch_ucode(adev->gfx.ce_fw->data);
+#endif
amdgpu_gfx_cp_init_microcode(adev, AMDGPU_UCODE_ID_CP_CE);
if (!amdgpu_sriov_vf(adev)) {
@@ -4245,6 +4262,9 @@ static int gfx_v10_0_init_microcode(struct amdgpu_device *adev)
err = request_firmware(&adev->gfx.rlc_fw, fw_name, adev->dev);
if (err)
goto out;
+#ifdef CONFIG_X86_PS5
+ gfx_v10_0_patch_ucode(adev->gfx.rlc_fw->data);
+#endif
/* don't validate this firmware. There are apparently firmwares
* in the wild with incorrect size in the header
@@ -4262,6 +4282,9 @@ static int gfx_v10_0_init_microcode(struct amdgpu_device *adev)
"amdgpu/%s_mec%s.bin", ucode_prefix, wks);
if (err)
goto out;
+#ifdef CONFIG_X86_PS5
+ gfx_v10_0_patch_ucode(adev->gfx.mec_fw->data);
+#endif
amdgpu_gfx_cp_init_microcode(adev, AMDGPU_UCODE_ID_CP_MEC1);
amdgpu_gfx_cp_init_microcode(adev, AMDGPU_UCODE_ID_CP_MEC1_JT);
@@ -4269,6 +4292,9 @@ static int gfx_v10_0_init_microcode(struct amdgpu_device *adev)
AMDGPU_UCODE_REQUIRED,
"amdgpu/%s_mec2%s.bin", ucode_prefix, wks);
if (!err) {
+#ifdef CONFIG_X86_PS5
+ gfx_v10_0_patch_ucode(adev->gfx.mec2_fw->data);
+#endif
amdgpu_gfx_cp_init_microcode(adev, AMDGPU_UCODE_ID_CP_MEC2);
amdgpu_gfx_cp_init_microcode(adev, AMDGPU_UCODE_ID_CP_MEC2_JT);
} else {
@@ -10104,6 +10130,21 @@ static u32 gfx_v10_0_get_cu_active_bitmap_per_sh(struct amdgpu_device *adev)
return cu_active_bitmap;
}
+/* PS5 harvested-CU unlock.
+ * 0 = disabled
+ * 1 = probe only (write then restore, log values)
+ * 2 = unlock SE0/SH0 only
+ * 3 = unlock all SE/SH (default)
+ * 4 = probe only, all SE/SH
+ * Override on the kernel command line, e.g.:
+ * amdgpu.ps5_cu_unlock=0 (disable)
+ * amdgpu.ps5_cu_unlock=1 (probe)
+ */
+static int ps5_cu_unlock = 0;
+module_param(ps5_cu_unlock, int, 0444);
+MODULE_PARM_DESC(ps5_cu_unlock,
+ "PS5 harvested-CU unlock (0=off (default), 1=probe, 2=SE0/SH0, 3=all, 4=probe-all)");
+
static int gfx_v10_0_get_cu_info(struct amdgpu_device *adev,
struct amdgpu_cu_info *cu_info)
{
@@ -10117,6 +10158,43 @@ static int gfx_v10_0_get_cu_info(struct amdgpu_device *adev,
amdgpu_gfx_parse_disable_cu(adev, disable_masks, 4, 2);
mutex_lock(&adev->grbm_idx_mutex);
+ /* PS5: unlock harvested CUs. CC alone updates enumeration but SPI
+ * still dispatches only to enabled WGPs; both writes are required
+ * (verified empirically on BC-250). */
+ if (ps5_cu_unlock > 0) {
+ int ps5_se, ps5_sh;
+ for (ps5_se = 0; ps5_se < adev->gfx.config.max_shader_engines; ps5_se++) {
+ for (ps5_sh = 0; ps5_sh < adev->gfx.config.max_sh_per_se; ps5_sh++) {
+ u32 ps5_cc_orig, ps5_cc_after, ps5_spi_orig, ps5_spi_after;
+ if (ps5_cu_unlock == 2 && (ps5_se > 0 || ps5_sh > 0))
+ continue;
+ gfx_v10_0_select_se_sh(adev, ps5_se, ps5_sh, 0xffffffff, 0);
+ ps5_cc_orig = RREG32_SOC15(GC, 0, mmCC_GC_SHADER_ARRAY_CONFIG);
+ WREG32_SOC15(GC, 0, mmCC_GC_SHADER_ARRAY_CONFIG, 0);
+ ps5_cc_after = RREG32_SOC15(GC, 0, mmCC_GC_SHADER_ARRAY_CONFIG);
+ ps5_spi_orig = RREG32_SOC15(GC, 0, mmSPI_PG_ENABLE_STATIC_WGP_MASK);
+ WREG32_SOC15(GC, 0, mmSPI_PG_ENABLE_STATIC_WGP_MASK, 0x1f);
+ ps5_spi_after = RREG32_SOC15(GC, 0, mmSPI_PG_ENABLE_STATIC_WGP_MASK);
+ WREG32_SOC15(GC, 0, mmRLC_PG_ALWAYS_ON_WGP_MASK, 0x1f);
+ if (ps5_cu_unlock == 1 || ps5_cu_unlock == 4) {
+ WREG32_SOC15(GC, 0, mmCC_GC_SHADER_ARRAY_CONFIG, ps5_cc_orig);
+ WREG32_SOC15(GC, 0, mmSPI_PG_ENABLE_STATIC_WGP_MASK, ps5_spi_orig);
+ dev_info(adev->dev,
+ "ps5-40cu-probe: se=%d sh=%d CC=0x%08x->0x%08x SPI=0x%08x->0x%08x (restored)",
+ ps5_se, ps5_sh,
+ ps5_cc_orig, ps5_cc_after,
+ ps5_spi_orig, ps5_spi_after);
+ } else {
+ dev_info(adev->dev,
+ "ps5-40cu-enable: mode=%d se=%d sh=%d CC=0x%08x->0x%08x SPI=0x%08x->0x%08x",
+ ps5_cu_unlock, ps5_se, ps5_sh,
+ ps5_cc_orig, ps5_cc_after,
+ ps5_spi_orig, ps5_spi_after);
+ }
+ }
+ }
+ gfx_v10_0_select_se_sh(adev, 0xffffffff, 0xffffffff, 0xffffffff, 0);
+ }
for (i = 0; i < adev->gfx.config.max_shader_engines; i++) {
for (j = 0; j < adev->gfx.config.max_sh_per_se; j++) {
bitmap = i * adev->gfx.config.max_sh_per_se + j;
diff --git a/drivers/gpu/drm/amd/amdgpu/nv.c b/drivers/gpu/drm/amd/amdgpu/nv.c
index 7ce1a1b95606..0bef516616ee 100644
--- a/drivers/gpu/drm/amd/amdgpu/nv.c
+++ b/drivers/gpu/drm/amd/amdgpu/nv.c
@@ -862,6 +862,10 @@ static int nv_common_early_init(struct amdgpu_ip_block *ip_block)
adev->cg_flags = 0;
adev->pg_flags = 0;
adev->external_rev_id = adev->rev_id + 0x82;
+#ifdef CONFIG_X86_PS5
+ /* Hardcode bc250's id. Remove when mesa's patch is widely available. */
+ adev->external_rev_id = 0x84;
+#endif
break;
case IP_VERSION(10, 3, 6):
adev->cg_flags = AMD_CG_SUPPORT_GFX_MGCG |
diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v5_0.c b/drivers/gpu/drm/amd/amdgpu/sdma_v5_0.c
index 52f4e9e099cb..6e4ff7444536 100644
--- a/drivers/gpu/drm/amd/amdgpu/sdma_v5_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/sdma_v5_0.c
@@ -1368,6 +1368,12 @@ static int sdma_v5_0_early_init(struct amdgpu_ip_block *ip_block)
struct amdgpu_device *adev = ip_block->adev;
int r;
+#ifdef CONFIG_X86_PS5
+ /* Reset SDMA to prevent ring test failures after reload. */
+ sdma_v5_0_soft_reset_engine(adev, 0);
+ sdma_v5_0_soft_reset_engine(adev, 1);
+#endif
+
r = sdma_v5_0_init_microcode(adev);
if (r)
return r;
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
index f8c13bad4ac2..1a9cccc5fa5c 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -80,6 +80,10 @@
#include <linux/component.h>
#include <linux/sort.h>
+#ifdef CONFIG_X86_PS5
+#include <linux/ps5.h>
+#endif
+
#include <drm/drm_privacy_screen_consumer.h>
#include <drm/display/drm_dp_mst_helper.h>
#include <drm/display/drm_hdmi_helper.h>
@@ -3093,7 +3097,10 @@ static int dm_hw_init(struct amdgpu_ip_block *ip_block)
r = amdgpu_dm_init(adev);
if (r)
return r;
+#ifndef CONFIG_X86_PS5
+ /* HPD is not supported. */
amdgpu_dm_hpd_init(adev);
+#endif
r = dm_oem_i2c_hw_init(adev);
if (r)
@@ -3114,7 +3121,10 @@ static int dm_hw_fini(struct amdgpu_ip_block *ip_block)
{
struct amdgpu_device *adev = ip_block->adev;
+#ifndef CONFIG_X86_PS5
+ /* HPD is not supported. */
amdgpu_dm_hpd_fini(adev);
+#endif
amdgpu_dm_irq_fini(adev);
amdgpu_dm_fini(adev);
@@ -6880,6 +6890,12 @@ static void fill_stream_properties_from_drm_display_mode(
stream->output_color_space = get_output_color_space(timing_out, connector_state);
stream->content_type = get_output_content_type(connector_state);
+
+#ifdef CONFIG_X86_PS5
+ /* Hardcode RGB888. */
+ // timing_out->pixel_encoding = PIXEL_ENCODING_RGB;
+ // timing_out->display_color_depth = COLOR_DEPTH_888;
+#endif
}
static void fill_audio_info(struct audio_info *audio_info,
@@ -8269,6 +8285,11 @@ enum drm_mode_status amdgpu_dm_connector_mode_valid(struct drm_connector *connec
*/
struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector);
+#ifdef CONFIG_X86_PS5
+ if (!isHdmiModeValid(mode, amdgpu_force_1080p))
+ return MODE_ERROR;
+#endif
+
if ((mode->flags & DRM_MODE_FLAG_INTERLACE) ||
(mode->flags & DRM_MODE_FLAG_DBLSCAN))
return result;
@@ -10957,12 +10978,64 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state)
drm_atomic_helper_update_legacy_modeset_state(dev, state);
drm_dp_mst_atomic_wait_for_dependencies(state);
+#ifdef CONFIG_X86_PS5
+ for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state,
+ new_crtc_state, i) {
+ dm_new_crtc_state = to_dm_crtc_state(new_crtc_state);
+ dm_old_crtc_state = to_dm_crtc_state(old_crtc_state);
+
+ if ((new_crtc_state->active &&
+ (!old_crtc_state->active ||
+ drm_atomic_crtc_needs_modeset(new_crtc_state))) ||
+ (old_crtc_state->active &&
+ (!new_crtc_state->active ||
+ drm_atomic_crtc_needs_modeset(new_crtc_state)))) {
+ if (dm_new_crtc_state->stream && dc_is_dp_signal(dm_new_crtc_state->stream->signal)) {
+ sceHdmiSetAudioMute(1);
+ sceHdmiDeviceSetVideoMute(1);
+ sceHdmiInitVideoConfig();
+ }
+ }
+ }
+#endif
+
dm_state = dm_atomic_get_new_state(state);
if (dm_state && dm_state->context) {
dc_state = dm_state->context;
amdgpu_dm_commit_streams(state, dc_state);
}
+#ifdef CONFIG_X86_PS5
+ for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state,
+ new_crtc_state, i) {
+ dm_new_crtc_state = to_dm_crtc_state(new_crtc_state);
+ dm_old_crtc_state = to_dm_crtc_state(old_crtc_state);
+
+ if (new_crtc_state->active &&
+ (!old_crtc_state->active ||
+ drm_atomic_crtc_needs_modeset(new_crtc_state))) {
+ if (dm_new_crtc_state->stream && dc_is_dp_signal(dm_new_crtc_state->stream->signal)) {
+ struct dc_stream_state *stream = dm_new_crtc_state->stream;
+ int channels = 0, j;
+
+ for (j = 0; j < stream->audio_info.mode_count; j++) {
+ if (stream->audio_info.modes[j].channel_count > channels)
+ channels = stream->audio_info.modes[j].channel_count;
+ }
+
+ /* Fallback to stereo if EDID has no audio modes */
+ if (channels == 0)
+ channels = 2;
+
+ sceHdmiSetVideoConfig(&new_crtc_state->mode);
+ sceHdmiDeviceSetVideoMute(0);
+ sceHdmiSetAudioConfig(channels);
+ sceHdmiSetAudioMute(0);
+ }
+ }
+ }
+#endif
+
amdgpu_dm_update_hdcp(state);
/* Handle connector state changes */
diff --git a/drivers/gpu/drm/amd/display/dc/bios/command_table2.c b/drivers/gpu/drm/amd/display/dc/bios/command_table2.c
index 17ef515c6c69..8b9c1f6509fd 100644
--- a/drivers/gpu/drm/amd/display/dc/bios/command_table2.c
+++ b/drivers/gpu/drm/amd/display/dc/bios/command_table2.c
@@ -40,6 +40,10 @@
#include "dc_dmub_srv.h"
#include "dc.h"
+#ifdef CONFIG_X86_PS5
+#include <linux/ps5.h>
+#endif
+
#define DC_LOGGER \
bp->base.ctx->logger
@@ -222,6 +226,17 @@ static enum bp_result transmitter_control_fallback(
struct bios_parser *bp,
struct bp_transmitter_control *cntl);
+#ifdef CONFIG_X86_PS5
+
+static enum bp_result svm_transmitter_control_v1_6(
+ struct bios_parser *bp,
+ struct bp_transmitter_control *cntl)
+{
+ return svm_execute_guest((void *)transmitter_control_v1_6, (u64)bp, (u64)cntl, 0, 0);
+}
+
+#endif
+
static void init_transmitter_control(struct bios_parser *bp)
{
uint8_t frev;
@@ -232,7 +247,11 @@ static void init_transmitter_control(struct bios_parser *bp)
switch (crev) {
case 6:
+#ifdef CONFIG_X86_PS5
+ bp->cmd_tbl.transmitter_control = svm_transmitter_control_v1_6;
+#else
bp->cmd_tbl.transmitter_control = transmitter_control_v1_6;
+#endif
break;
case 7:
bp->cmd_tbl.transmitter_control = transmitter_control_v1_7;
diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn201/dcn201_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn201/dcn201_clk_mgr.c
index 76c612ecfe3c..953cd538402b 100644
--- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn201/dcn201_clk_mgr.c
+++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn201/dcn201_clk_mgr.c
@@ -214,4 +214,8 @@ void dcn201_clk_mgr_construct(struct dc_context *ctx,
clk_mgr->dfs_bypass_enabled = true;
dce_clock_read_ss_info(clk_mgr);
+#ifdef CONFIG_X86_PS5
+ clk_mgr->ss_on_dprefclk = false;
+ clk_mgr->dprefclk_ss_percentage = 0;
+#endif
}
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c
index 05991a10f8bf..777593dddd56 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c
@@ -205,6 +205,7 @@ enum dce_version resource_parse_asic_id(struct hw_asic_id asic_id)
asic_id.chip_id == DEVICE_ID_NV_13FA ||
asic_id.chip_id == DEVICE_ID_NV_13FB ||
asic_id.chip_id == DEVICE_ID_NV_13FC ||
+ asic_id.chip_id == DEVICE_ID_NV_13DA ||
asic_id.chip_id == DEVICE_ID_NV_13DB) {
dc_version = DCN_VERSION_2_01;
break;
diff --git a/drivers/gpu/drm/amd/display/dc/dcn201/dcn201_link_encoder.c b/drivers/gpu/drm/amd/display/dc/dcn201/dcn201_link_encoder.c
index 9459e8f28338..063e4a4eefdd 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn201/dcn201_link_encoder.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn201/dcn201_link_encoder.c
@@ -98,8 +98,11 @@ static const struct link_encoder_funcs dcn201_link_enc_funcs = {
.disable_hpd = dcn10_link_encoder_disable_hpd,
.is_dig_enabled = dcn10_is_dig_enabled,
.destroy = dcn10_link_encoder_destroy,
+#ifndef CONFIG_X86_PS5
+ /* Ignore this to prevent blackscreen. */
.fec_set_enable = enc2_fec_set_enable,
.fec_set_ready = enc2_fec_set_ready,
+#endif
.get_dig_frontend = dcn10_get_dig_frontend,
.fec_is_active = enc2_fec_is_active,
.is_in_alt_mode = dcn201_link_encoder_is_in_alt_mode,
diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_capability.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_capability.c
index 782a45caa13d..444259795140 100644
--- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_capability.c
+++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_capability.c
@@ -1018,6 +1018,12 @@ bool link_decide_link_settings(struct dc_stream_state *stream,
decide_dp_link_settings(link, link_setting, req_bw);
}
+#ifdef CONFIG_X86_PS5
+ /* Hardcode HBR3x4 link setting. */
+ link_setting->link_rate = LINK_RATE_HIGH3;
+ link_setting->lane_count = LANE_COUNT_FOUR;
+#endif
+
return link_setting->lane_count != LANE_COUNT_UNKNOWN &&
link_setting->link_rate != LINK_RATE_UNKNOWN;
}
@@ -1458,6 +1464,8 @@ void dpcd_set_source_specific_data(struct dc_link *link)
(uint8_t *)(&amd_device_id),
sizeof(amd_device_id));
+#ifndef CONFIG_X86_PS5
+ /* Ignore unsupported dpcd address. */
if (link->ctx->dce_version >= DCN_VERSION_2_0 &&
link->dc->caps.min_horizontal_blanking_period != 0) {
@@ -1467,6 +1475,7 @@ void dpcd_set_source_specific_data(struct dc_link *link)
DP_SOURCE_MINIMUM_HBLANK_SUPPORTED, (uint8_t *)(&hblank_size),
sizeof(hblank_size));
}
+#endif
DC_TRACE_LEVEL_MESSAGE(DAL_TRACE_LEVEL_INFORMATION,
WPP_BIT_FLAG_DC_DETECTION_DP_CAPS,
"result=%u link_index=%u enum dce_version=%d DPCD=0x%04X min_hblank=%u branch_dev_id=0x%x branch_dev_name='%c%c%c%c%c%c'",
diff --git a/drivers/gpu/drm/amd/display/include/dal_asic_id.h b/drivers/gpu/drm/amd/display/include/dal_asic_id.h
index 92510af1bd65..85c9e587834d 100644
--- a/drivers/gpu/drm/amd/display/include/dal_asic_id.h
+++ b/drivers/gpu/drm/amd/display/include/dal_asic_id.h
@@ -217,6 +217,7 @@ enum {
#define DEVICE_ID_NV_13FA 0x13FA
#define DEVICE_ID_NV_13FB 0x13FB
#define DEVICE_ID_NV_13FC 0x13FC
+#define DEVICE_ID_NV_13DA 0x13DA
#define DEVICE_ID_NV_13DB 0x13DB
#define FAMILY_VGH 144
#define DEVICE_ID_VGH_163F 0x163F
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
index 404208bf23a6..85718d593c42 100644
--- a/drivers/gpu/drm/drm_edid.c
+++ b/drivers/gpu/drm/drm_edid.c
@@ -2242,6 +2242,10 @@ static void connector_bad_edid(struct drm_connector *connector,
edid_block_dump(KERN_DEBUG, edid + i, i);
}
+#ifdef CONFIG_X86_PS5
+extern struct drm_edid *real_edid;
+#endif
+
/* Get override or firmware EDID */
static const struct drm_edid *drm_edid_override_get(struct drm_connector *connector)
{
@@ -2257,6 +2261,11 @@ static const struct drm_edid *drm_edid_override_get(struct drm_connector *connec
if (!override)
override = drm_edid_load_firmware(connector);
+#ifdef CONFIG_X86_PS5
+ if (IS_ERR(override) && real_edid)
+ override = drm_edid_dup(real_edid);
+#endif
+
return IS_ERR(override) ? NULL : override;
}
diff --git a/drivers/hwmon/k10temp.c b/drivers/hwmon/k10temp.c
index a5d8f45b7881..3c7b76af13e4 100644
--- a/drivers/hwmon/k10temp.c
+++ b/drivers/hwmon/k10temp.c
@@ -476,6 +476,7 @@ static int k10temp_probe(struct pci_dev *pdev, const struct pci_device_id *id)
break;
case 0x31: /* Zen2 Threadripper */
case 0x47: /* Cyan Skillfish */
+ case 0x48: /* PS5 */
case 0x60: /* Renoir */
case 0x68: /* Lucienne */
case 0x71: /* Zen2 */
diff --git a/drivers/iommu/amd/init.c b/drivers/iommu/amd/init.c
index 3bdb380d23e9..e25db11bb1e5 100644
--- a/drivers/iommu/amd/init.c
+++ b/drivers/iommu/amd/init.c
@@ -3107,6 +3107,8 @@ static void __init free_iommu_resources(void)
free_pci_segments();
}
+#ifndef CONFIG_X86_PS5
+
/* SB IOAPIC is always on this device in AMD systems */
#define IOAPIC_SB_DEVID ((0x00 << 8) | PCI_DEVFN(0x14, 0))
@@ -3159,6 +3161,8 @@ static bool __init check_ioapic_information(void)
return ret;
}
+#endif
+
static void __init free_dma_resources(void)
{
amd_iommu_pdom_id_destroy();
@@ -3283,8 +3287,11 @@ static int __init early_amd_iommu_init(void)
if (!is_kdump_kernel() || amd_iommu_disabled)
disable_iommus();
+#ifndef CONFIG_X86_PS5
+ /* IOAPIC is not available. */
if (amd_iommu_irq_remap)
amd_iommu_irq_remap = check_ioapic_information();
+#endif
if (amd_iommu_irq_remap) {
struct amd_iommu_pci_seg *pci_seg;
diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
index b5ee338b620d..5e3b12332ef0 100644
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -465,3 +465,4 @@ config XILINX_GMII2RGMII
Ethernet physical media devices and the Gigabit Ethernet controller.
endif # PHYLIB
+source "drivers/net/phy/mts/Kconfig"
diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile
index 05e4878af27a..3a61917ba549 100644
--- a/drivers/net/phy/Makefile
+++ b/drivers/net/phy/Makefile
@@ -71,6 +71,7 @@ obj-$(CONFIG_MARVELL_88X2222_PHY) += marvell-88x2222.o
obj-$(CONFIG_MAXLINEAR_GPHY) += mxl-gpy.o
obj-$(CONFIG_MAXLINEAR_86110_PHY) += mxl-86110.o
obj-y += mediatek/
+obj-$(CONFIG_MTS) += mts/
obj-$(CONFIG_MESON_GXL_PHY) += meson-gxl.o
obj-$(CONFIG_MICREL_PHY) += micrel.o
obj-$(CONFIG_MICROCHIP_PHY) += microchip.o
diff --git a/drivers/net/phy/mts/Kconfig b/drivers/net/phy/mts/Kconfig
new file mode 100644
index 000000000000..94cb839814cb
--- /dev/null
+++ b/drivers/net/phy/mts/Kconfig
@@ -0,0 +1,10 @@
+# SPDX-License-Identifier: GPL-2.0-only
+config MTS
+ tristate "MediaTek Star Gigabit Ethernet"
+ depends on PCI && X86_PS5
+ help
+ Driver for the MediaTek Star based Gigabit Ethernet controller
+ (104d:9104) found on the PlayStation 5.
+
+ To compile this driver as a module, choose M here. The module
+ will be called mts.
diff --git a/drivers/net/phy/mts/Makefile b/drivers/net/phy/mts/Makefile
new file mode 100644
index 000000000000..e01771be845b
--- /dev/null
+++ b/drivers/net/phy/mts/Makefile
@@ -0,0 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0-only
+obj-$(CONFIG_MTS) += mts.o
+mts-y := mts_main.o mts_phy.o
diff --git a/drivers/net/phy/mts/mts.h b/drivers/net/phy/mts/mts.h
new file mode 100644
index 000000000000..a0e41029aea2
--- /dev/null
+++ b/drivers/net/phy/mts/mts.h
@@ -0,0 +1,186 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * PlayStation 5 Gigabit Ethernet driver
+ *
+ * Based on the MediaTek Star Ethernet MAC (mtk_star_emac).
+ */
+
+#ifndef _MTS_H
+#define _MTS_H
+
+#include <linux/types.h>
+#include <linux/bits.h>
+#include <linux/io.h>
+#include <linux/spinlock.h>
+#include <linux/netdevice.h>
+#include <linux/workqueue.h>
+
+struct pci_dev;
+struct sk_buff;
+
+#define GBE_REG_SMI 0x00
+#define GBE_REG_LINK 0x04
+#define GBE_REG_CLK_CTRL 0x08
+#define GBE_REG_CTRL 0x0c
+#define GBE_REG_MODE 0x10
+#define GBE_REG_MAC_HI 0x14
+#define GBE_REG_MAC_LO 0x18
+#define GBE_REG_RXBUF 0x30
+#define GBE_REG_TX_DMA_CTRL 0x34
+#define GBE_REG_RX_DMA_CTRL 0x38
+#define GBE_REG_TX_RING_CUR 0x3c
+#define GBE_REG_RX_RING_CUR 0x40
+#define GBE_REG_TX_RING_BASE 0x44
+#define GBE_REG_RX_RING_BASE 0x48
+#define GBE_REG_ISR 0x50
+#define GBE_REG_IER 0x54
+#define GBE_REG_SERDES 0x74
+#define GBE_REG_RX_PCODE 0x78
+#define GBE_REG_TXKICK 0x9c
+#define GBE_REG_RESET 0xac
+#define GBE_REG_TX_EN 0x1b8
+#define GBE_REG_FILT_CTRL 0x1c4
+#define GBE_REG_FILT_DATA 0x1c8
+#define GBE_REG_RX_EN 0x1d4
+#define GBE_REG_COAL 0x204
+
+#define GBE_PCS_BASE 0x4000
+
+#define GBE_CLK_ENABLE 0x7597c00
+
+#define GBE_SERDES_1G 0x303277
+#define GBE_SERDES_OTHER 0x304277
+
+#define GBE_ISR_LINK BIT(2)
+#define GBE_ISR_TX_DONE BIT(7)
+#define GBE_ISR_RX_DONE BIT(6)
+#define GBE_ISR_ERRORS 0x7be600
+#define GBE_ISR_LSO_RECOVER 0x500000
+
+#define GBE_ST_LSO_RECOVER 0
+
+#define GBE_ERR_LSO_FIFO 0x200000
+#define GBE_ERR_LSO_PROTO 0x80000
+#define GBE_ERR_RX_AXI 0x20000
+#define GBE_ERR_IP_CKSUM 0x8000
+#define GBE_ERR_TCP_CKSUM 0x4000
+#define GBE_ERR_UDP_CKSUM 0x2000
+#define GBE_ERR_RX_PCODE 0x400
+
+#define GBE_COAL_VAL 0x10001388
+
+/* this chip has no intx pin and its msi sometimes never fires (cold boot). when
+ * we detect that, the link_poll work becomes the only way to service the rings,
+ * so it polls this often (ms) instead of once a second to stay responsive. */
+#define GBE_POLL_FALLBACK_MS 10
+
+/* excludes bit2 (LINK) - polling link state avoids IRQ storm from autoneg pulses */
+#define GBE_IER_MASK 0x5014fa
+
+#define GBE_DMA_STOP BIT(1)
+#define GBE_DMA_KICK BIT(2)
+
+struct gbe_desc {
+ __le32 flags;
+ __le32 buf_addr;
+ __le32 word2;
+ __le32 word3;
+};
+
+#define GBE_DESC_DONE BIT(31)
+#define GBE_DESC_WRAP BIT(30)
+#define GBE_DESC_SOP BIT(29)
+#define GBE_DESC_EOP BIT(28)
+#define GBE_DESC_LEN_MASK 0xffff
+#define GBE_DESC_RX_LEN 0x600
+#define GBE_DESC_RX_LEN_MASK 0x7ff
+/* idle TX descriptor word2 - chip treats anything >= 0xffff0000 as free */
+#define GBE_DESC_W2_ARM 0xffff0000
+/* active TX descriptor word2 */
+#define GBE_DESC_W2_TX 0x4
+
+#define GBE_RING_SIZE 256
+#define GBE_DESC_RING_BYTES (GBE_RING_SIZE * sizeof(struct gbe_desc))
+#define GBE_RX_BUF_LEN 1536
+
+#define GBE_TX_SCRATCH_SIZE 0xa0000
+#define GBE_RX_POOL_SIZE (GBE_RING_SIZE * GBE_DESC_RX_LEN)
+
+struct gbe_priv {
+ struct net_device *netdev;
+ struct pci_dev *pdev;
+ void __iomem *base;
+ /* PCS/SerDes regs live in Salina Glue (104d:9107) BAR4, not BAR0 */
+ void __iomem *glue_base;
+ struct pci_dev *glue_pdev;
+
+ /* tx goes through a bounce scratch region, the chip wants contiguous buffers */
+ struct gbe_desc *tx_ring;
+ dma_addr_t tx_ring_dma;
+ void *tx_scratch;
+ dma_addr_t tx_scratch_dma;
+ unsigned int tx_scratch_off;
+ unsigned int tx_head;
+ unsigned int tx_tail;
+
+ /* rx just has the chip dma straight into a slotted pool */
+ struct gbe_desc *rx_ring;
+ dma_addr_t rx_ring_dma;
+ void *rx_pool;
+ dma_addr_t rx_pool_dma;
+ unsigned int rx_head;
+
+ struct napi_struct napi;
+ int irq;
+ int link_up;
+ unsigned long state;
+ struct delayed_work link_poll;
+ spinlock_t lock;
+
+ /* debug counters, dumped every now and then by the link poll work */
+ u32 cnt_irq;
+ u32 cnt_irq_link;
+ u32 cnt_irq_tx;
+ u32 cnt_irq_rx;
+ u32 cnt_irq_err;
+ u32 cnt_irq_lso;
+ u32 cnt_tx_pkts;
+ u32 cnt_tx_busy;
+ u32 cnt_tx_drop_big;
+ u32 cnt_tx_completed;
+ u32 cnt_rx_pkts;
+ u32 cnt_rx_bcast;
+ u32 cnt_rx_mcast;
+ u32 cnt_rx_bad_len;
+ u32 cnt_rx_nomem;
+ u32 cnt_lso_recover;
+ u32 cnt_link_up;
+ u32 cnt_link_down;
+ unsigned int poll_tick;
+ /* used by link_poll_work to detect frozen IRQ delivery on cold boot */
+ u32 irq_watchdog;
+};
+
+static inline u32 gbe_rd(struct gbe_priv *p, u32 reg)
+{
+ return readl(p->base + reg);
+}
+
+static inline void gbe_wr(struct gbe_priv *p, u32 reg, u32 val)
+{
+ writel(val, p->base + reg);
+}
+
+static inline void gbe_set(struct gbe_priv *p, u32 reg, u32 bits)
+{
+ gbe_wr(p, reg, gbe_rd(p, reg) | bits);
+}
+
+static inline void gbe_clr(struct gbe_priv *p, u32 reg, u32 bits)
+{
+ gbe_wr(p, reg, gbe_rd(p, reg) & ~bits);
+}
+
+int gbe_phy_init(struct gbe_priv *p);
+
+#endif /* _MTS_H */
diff --git a/drivers/net/phy/mts/mts_main.c b/drivers/net/phy/mts/mts_main.c
new file mode 100644
index 000000000000..c193cb2d1bd4
--- /dev/null
+++ b/drivers/net/phy/mts/mts_main.c
@@ -0,0 +1,823 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * PlayStation 5 Gigabit Ethernet driver
+ *
+ * Based on the MediaTek Star Ethernet MAC (mtk_star_emac).
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/ps5.h>
+
+#include "mts.h"
+
+#define PCI_DEVICE_ID_GBE 0x9104
+#define PCI_DEVICE_ID_SPCIE 0x9107
+
+static void gbe_write_mac(struct gbe_priv *p, const u8 *addr)
+{
+ gbe_wr(p, GBE_REG_MAC_HI, (addr[0] << 8) | addr[1]);
+ gbe_wr(p, GBE_REG_MAC_LO,
+ (addr[2] << 24) | (addr[3] << 16) | (addr[4] << 8) | addr[5]);
+}
+
+/* the glue is a seperate pci function, grab it too :) */
+static int gbe_glue_map(struct gbe_priv *p)
+{
+ struct pci_dev *glue;
+
+ glue = pci_get_device(PCI_VENDOR_ID_SONY, PCI_DEVICE_ID_SPCIE, NULL);
+ if (!glue)
+ return -ENODEV;
+
+ if (!(pci_resource_flags(glue, 4) & IORESOURCE_MEM)) {
+ pci_dev_put(glue);
+ return -ENODEV;
+ }
+
+ p->glue_base = ioremap(pci_resource_start(glue, 4),
+ pci_resource_len(glue, 4));
+ if (!p->glue_base) {
+ pci_dev_put(glue);
+ return -ENOMEM;
+ }
+
+ p->glue_pdev = glue;
+ return 0;
+}
+
+static void gbe_glue_unmap(struct gbe_priv *p)
+{
+ if (p->glue_base) {
+ iounmap(p->glue_base);
+ p->glue_base = NULL;
+ }
+ if (p->glue_pdev) {
+ pci_dev_put(p->glue_pdev);
+ p->glue_pdev = NULL;
+ }
+}
+
+/* MAC address lives at offset 0x3000 in Salina Glue BAR4 scratchpad */
+static int gbe_read_glue_mac(struct gbe_priv *p, u8 *addr)
+{
+ int i;
+
+ if (!p->glue_base)
+ return -ENODEV;
+
+ for (i = 0; i < ETH_ALEN; i++)
+ addr[i] = readb(p->glue_base + 0x3000 + i);
+ return 0;
+}
+
+/* writing 9 to the reset reg pulses the whole MAC, needs a short settle */
+static void gbe_reset(struct gbe_priv *p)
+{
+ gbe_wr(p, GBE_REG_RESET, 9);
+ usleep_range(680, 1000);
+}
+
+/* mark every tx slot done+free so the chip leaves em alone till we arm one */
+static void gbe_init_tx_ring(struct gbe_priv *p)
+{
+ int i;
+
+ for (i = 0; i < GBE_RING_SIZE; i++) {
+ p->tx_ring[i].flags = cpu_to_le32(GBE_DESC_DONE |
+ (i == GBE_RING_SIZE - 1 ? GBE_DESC_WRAP : 0));
+ p->tx_ring[i].buf_addr = 0;
+ p->tx_ring[i].word2 = cpu_to_le32(GBE_DESC_W2_ARM);
+ p->tx_ring[i].word3 = 0;
+ }
+ p->tx_head = p->tx_tail = 0;
+ p->tx_scratch_off = 0;
+}
+
+/* point each rx slot at its pool buffer and give it back to teh chip */
+static void gbe_rx_fill(struct gbe_priv *p)
+{
+ int i;
+
+ for (i = 0; i < GBE_RING_SIZE; i++) {
+ p->rx_ring[i].buf_addr = cpu_to_le32(p->rx_pool_dma +
+ i * GBE_DESC_RX_LEN);
+ p->rx_ring[i].word2 = 0;
+ p->rx_ring[i].word3 = 0;
+ dma_wmb();
+ p->rx_ring[i].flags = cpu_to_le32(GBE_DESC_RX_LEN |
+ (i == GBE_RING_SIZE - 1 ? GBE_DESC_WRAP : 0));
+ }
+ p->rx_head = 0;
+}
+
+static void gbe_init_rings_hw(struct gbe_priv *p)
+{
+ gbe_init_tx_ring(p);
+
+ wmb();
+
+ gbe_wr(p, GBE_REG_TX_RING_BASE, p->tx_ring_dma);
+ gbe_wr(p, GBE_REG_TX_RING_CUR, p->tx_ring_dma);
+ gbe_wr(p, GBE_REG_RX_RING_BASE, p->rx_ring_dma);
+ gbe_wr(p, GBE_REG_RX_RING_CUR, p->rx_ring_dma);
+
+ /* toggle bit6 to clear any stale LSO cause latched from before init */
+ gbe_clr(p, GBE_REG_TXKICK, BIT(6));
+ gbe_set(p, GBE_REG_TXKICK, BIT(6));
+
+ gbe_set(p, GBE_REG_TX_DMA_CTRL, BIT(0));
+ gbe_set(p, GBE_REG_RX_DMA_CTRL, BIT(0));
+ gbe_wr(p, GBE_REG_IER, GBE_IER_MASK);
+}
+
+/* tell both dma engines to stop, then jsut spin till the bit clears */
+static void gbe_stop_dma(struct gbe_priv *p)
+{
+ int i;
+
+ gbe_wr(p, GBE_REG_IER, 0);
+
+ gbe_set(p, GBE_REG_TX_DMA_CTRL, GBE_DMA_STOP);
+ for (i = 0; i < 1000000 &&
+ (gbe_rd(p, GBE_REG_TX_DMA_CTRL) & GBE_DMA_STOP); i++)
+ udelay(1);
+
+ gbe_set(p, GBE_REG_RX_DMA_CTRL, GBE_DMA_STOP);
+ for (i = 0; i < 1000000 &&
+ (gbe_rd(p, GBE_REG_RX_DMA_CTRL) & GBE_DMA_STOP); i++)
+ udelay(1);
+}
+
+/* full bringup: reset, clocks, phy, then the magic mode/serdes vaules */
+static void gbe_init_hw(struct gbe_priv *p)
+{
+ gbe_reset(p);
+ gbe_set(p, GBE_REG_CLK_CTRL, GBE_CLK_ENABLE);
+ gbe_phy_init(p);
+ gbe_clr(p, GBE_REG_CTRL, BIT(7));
+ gbe_wr(p, GBE_REG_SERDES, GBE_SERDES_1G);
+ gbe_wr(p, GBE_REG_MODE, (gbe_rd(p, GBE_REG_MODE) & 0xffffff6e) | 0x81);
+ gbe_wr(p, GBE_REG_RXBUF, 0x10100);
+ gbe_write_mac(p, p->netdev->dev_addr);
+ gbe_wr(p, GBE_REG_COAL, GBE_COAL_VAL);
+}
+
+/* the two rings + tx bounce scratch + rx pool, all dma coherent */
+static int gbe_alloc_rings(struct gbe_priv *p)
+{
+ p->tx_ring = dma_alloc_coherent(&p->pdev->dev, GBE_DESC_RING_BYTES,
+ &p->tx_ring_dma, GFP_KERNEL);
+ if (!p->tx_ring)
+ return -ENOMEM;
+
+ p->rx_ring = dma_alloc_coherent(&p->pdev->dev, GBE_DESC_RING_BYTES,
+ &p->rx_ring_dma, GFP_KERNEL);
+ if (!p->rx_ring)
+ goto err_rx;
+
+ p->tx_scratch = dma_alloc_coherent(&p->pdev->dev, GBE_TX_SCRATCH_SIZE,
+ &p->tx_scratch_dma, GFP_KERNEL);
+ if (!p->tx_scratch)
+ goto err_scratch;
+
+ p->rx_pool = dma_alloc_coherent(&p->pdev->dev, GBE_RX_POOL_SIZE,
+ &p->rx_pool_dma, GFP_KERNEL);
+ if (!p->rx_pool)
+ goto err_pool;
+
+ return 0;
+
+err_pool:
+ dma_free_coherent(&p->pdev->dev, GBE_TX_SCRATCH_SIZE,
+ p->tx_scratch, p->tx_scratch_dma);
+err_scratch:
+ dma_free_coherent(&p->pdev->dev, GBE_DESC_RING_BYTES,
+ p->rx_ring, p->rx_ring_dma);
+err_rx:
+ dma_free_coherent(&p->pdev->dev, GBE_DESC_RING_BYTES,
+ p->tx_ring, p->tx_ring_dma);
+ return -ENOMEM;
+}
+
+static void gbe_free_rings(struct gbe_priv *p)
+{
+ if (p->tx_ring)
+ dma_free_coherent(&p->pdev->dev, GBE_DESC_RING_BYTES,
+ p->tx_ring, p->tx_ring_dma);
+ if (p->rx_ring)
+ dma_free_coherent(&p->pdev->dev, GBE_DESC_RING_BYTES,
+ p->rx_ring, p->rx_ring_dma);
+ if (p->tx_scratch)
+ dma_free_coherent(&p->pdev->dev, GBE_TX_SCRATCH_SIZE,
+ p->tx_scratch, p->tx_scratch_dma);
+ if (p->rx_pool)
+ dma_free_coherent(&p->pdev->dev, GBE_RX_POOL_SIZE,
+ p->rx_pool, p->rx_pool_dma);
+}
+
+/* clean up the tx descriptors the chip finished, wake the queue if we stopped it */
+static void gbe_tx_complete(struct gbe_priv *p)
+{
+ unsigned int tail = p->tx_tail;
+
+ while (tail != p->tx_head) {
+ struct gbe_desc *d = &p->tx_ring[tail];
+ u32 flags = le32_to_cpu(d->flags);
+ u32 w2 = le32_to_cpu(d->word2);
+
+ if (!(flags & GBE_DESC_DONE))
+ break;
+
+ /* chip reuses word2 < 0xffff0000 as ownership sentinel on ring wrap */
+ if (w2 >= 0xffff0000)
+ break;
+
+ /* re-arm it so the slot reads free next time round the ring */
+ d->word2 = cpu_to_le32(w2 | 0xffff0000);
+
+ p->cnt_tx_completed++;
+ tail = (tail + 1) % GBE_RING_SIZE;
+ }
+ p->tx_tail = tail;
+
+ if (netif_queue_stopped(p->netdev))
+ netif_wake_queue(p->netdev);
+}
+
+/* grab whatever rx slots are done up to budget, copy em out and re-arm */
+static int gbe_rx_poll(struct gbe_priv *p, int budget)
+{
+ struct net_device *dev = p->netdev;
+ unsigned int i = p->rx_head;
+ int done = 0;
+
+ while (done < budget &&
+ (le32_to_cpu(p->rx_ring[i].flags) & GBE_DESC_DONE)) {
+ u32 flags = le32_to_cpu(p->rx_ring[i].flags);
+ u32 len = flags & GBE_DESC_RX_LEN_MASK;
+
+ netdev_dbg(dev, "rx[%u] len=%u flags=%#x w2=%#x\n", i, len,
+ flags, le32_to_cpu(p->rx_ring[i].word2));
+
+ if (len >= ETH_ZLEN && len <= GBE_DESC_RX_LEN) {
+ struct sk_buff *skb;
+ const u8 *src = (const u8 *)p->rx_pool +
+ i * GBE_DESC_RX_LEN;
+
+ p->cnt_rx_pkts++;
+ if (is_broadcast_ether_addr(src))
+ p->cnt_rx_bcast++;
+ else if (is_multicast_ether_addr(src))
+ p->cnt_rx_mcast++;
+
+ skb = netdev_alloc_skb_ip_align(dev, len);
+ if (skb) {
+ skb_put_data(skb, src, len);
+ skb->protocol = eth_type_trans(skb, dev);
+ netif_rx(skb);
+ dev->stats.rx_packets++;
+ dev->stats.rx_bytes += len;
+ } else {
+ p->cnt_rx_nomem++;
+ dev->stats.rx_dropped++;
+ }
+ } else {
+ p->cnt_rx_bad_len++;
+ dev->stats.rx_errors++;
+ }
+
+ /* hand the slot back to the chip */
+ p->rx_ring[i].word2 = 0;
+ p->rx_ring[i].word3 = 0;
+ dma_wmb();
+ p->rx_ring[i].flags = cpu_to_le32(GBE_DESC_RX_LEN |
+ (i == GBE_RING_SIZE - 1 ? GBE_DESC_WRAP : 0));
+
+ done++;
+ i = (i + 1) % GBE_RING_SIZE;
+ }
+ p->rx_head = i;
+
+ if (done)
+ gbe_set(p, GBE_REG_RX_DMA_CTRL, GBE_DMA_KICK);
+
+ return done;
+}
+
+static netdev_tx_t gbe_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ struct gbe_priv *p = netdev_priv(dev);
+ unsigned int head, off, aligned;
+ unsigned int len = skb->len;
+ unsigned long flags;
+
+ if (len < ETH_ZLEN)
+ len = ETH_ZLEN;
+ if (len > GBE_RX_BUF_LEN) {
+ p->cnt_tx_drop_big++;
+ dev->stats.tx_dropped++;
+ dev_kfree_skb_any(skb);
+ return NETDEV_TX_OK;
+ }
+
+ spin_lock_irqsave(&p->lock, flags);
+
+ /* free up whatever the chip already finished before we go looking for room */
+ gbe_tx_complete(p);
+
+ head = p->tx_head;
+ if (((head + 1) % GBE_RING_SIZE) == p->tx_tail) {
+ p->cnt_tx_busy++;
+ netif_stop_queue(dev);
+ spin_unlock_irqrestore(&p->lock, flags);
+ return NETDEV_TX_BUSY;
+ }
+
+ p->cnt_tx_pkts++;
+
+ /* wrap scratch offset if packet doesn't fit at the end */
+ aligned = (len + 0x7f) & ~0x7fu;
+ off = p->tx_scratch_off;
+ if (off + aligned > GBE_TX_SCRATCH_SIZE)
+ off = 0;
+ p->tx_scratch_off = off + aligned;
+ if (p->tx_scratch_off >= GBE_TX_SCRATCH_SIZE)
+ p->tx_scratch_off = 0;
+
+ /* copy into the bounce region and zero-pad shrot frames */
+ skb_copy_bits(skb, 0, (u8 *)p->tx_scratch + off, skb->len);
+ if (len > skb->len)
+ memset((u8 *)p->tx_scratch + off + skb->len, 0, len - skb->len);
+
+ p->tx_ring[head].buf_addr = cpu_to_le32(p->tx_scratch_dma + off);
+ p->tx_ring[head].word2 = cpu_to_le32(GBE_DESC_W2_TX);
+ p->tx_ring[head].word3 = 0;
+ dma_wmb();
+ p->tx_ring[head].flags = cpu_to_le32((len & GBE_DESC_LEN_MASK) |
+ GBE_DESC_SOP | GBE_DESC_EOP |
+ (head == GBE_RING_SIZE - 1 ? GBE_DESC_WRAP : 0));
+
+ netdev_dbg(dev, "tx[%u] len=%u off=%#x flags=%#x\n", head, len,
+ off, le32_to_cpu(p->tx_ring[head].flags));
+
+ p->tx_head = (head + 1) % GBE_RING_SIZE;
+
+ /* if the ring is filling up clean it again so we dont wedge under load :C */
+ if ((p->tx_head + GBE_RING_SIZE - p->tx_tail) % GBE_RING_SIZE > GBE_RING_SIZE / 2)
+ gbe_tx_complete(p);
+
+ gbe_set(p, GBE_REG_TX_DMA_CTRL, GBE_DMA_KICK);
+
+ dev->stats.tx_packets++;
+ dev->stats.tx_bytes += len;
+
+ spin_unlock_irqrestore(&p->lock, flags);
+ dev_consume_skb_any(skb);
+ return NETDEV_TX_OK;
+}
+
+static int gbe_set_mac_address(struct net_device *dev, void *addr)
+{
+ struct gbe_priv *p = netdev_priv(dev);
+ struct sockaddr *sa = addr;
+
+ if (!is_valid_ether_addr(sa->sa_data))
+ return -EADDRNOTAVAIL;
+
+ eth_hw_addr_set(dev, sa->sa_data);
+ gbe_write_mac(p, dev->dev_addr);
+ return 0;
+}
+
+/* no hw filter wired up yet, just log what got asked for */
+static void gbe_set_rx_mode(struct net_device *dev)
+{
+ struct gbe_priv *p = netdev_priv(dev);
+ struct netdev_hw_addr *ha;
+ int mc_count = 0;
+
+ netdev_for_each_mc_addr(ha, dev)
+ mc_count++;
+
+ netdev_info(dev,
+ "rx_mode: flags=%#x %s%s%s%s mc_count=%d\n",
+ dev->flags,
+ (dev->flags & IFF_PROMISC) ? "PROMISC " : "",
+ (dev->flags & IFF_ALLMULTI) ? "ALLMULTI " : "",
+ (dev->flags & IFF_MULTICAST) ? "MULTICAST " : "",
+ (dev->flags & IFF_BROADCAST) ? "BROADCAST " : "",
+ mc_count);
+
+ (void)p;
+}
+
+static void gbe_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
+{
+ strscpy(info->driver, KBUILD_MODNAME, sizeof(info->driver));
+}
+
+static const struct ethtool_ops gbe_ethtool_ops = {
+ .get_drvinfo = gbe_get_drvinfo,
+ .get_link = ethtool_op_get_link,
+};
+
+/* bit0 of the link reg is carrier, just mirror it into netdev */
+static void gbe_link_change(struct gbe_priv *p)
+{
+ u32 link_reg = gbe_rd(p, GBE_REG_LINK);
+ int up = link_reg & BIT(0);
+
+ if (up == p->link_up)
+ return;
+
+ p->link_up = up;
+ if (up) {
+ p->cnt_link_up++;
+ netif_carrier_on(p->netdev);
+ netdev_info(p->netdev, "link up (reg=%#x)\n", link_reg);
+ } else {
+ p->cnt_link_down++;
+ netif_carrier_off(p->netdev);
+ netdev_info(p->netdev, "link down (reg=%#x)\n", link_reg);
+ }
+}
+
+static void gbe_dump_stats(struct gbe_priv *p)
+{
+ netdev_dbg(p->netdev,
+ "stats: irq=%u (link=%u tx=%u rx=%u err=%u lso=%u) "
+ "tx=%u (busy=%u drop_big=%u done=%u) "
+ "rx=%u (bcast=%u mcast=%u badlen=%u nomem=%u) "
+ "link_up=%u link_down=%u lso_recover=%u link_reg=%#x\n",
+ p->cnt_irq, p->cnt_irq_link, p->cnt_irq_tx, p->cnt_irq_rx,
+ p->cnt_irq_err, p->cnt_irq_lso,
+ p->cnt_tx_pkts, p->cnt_tx_busy, p->cnt_tx_drop_big,
+ p->cnt_tx_completed,
+ p->cnt_rx_pkts, p->cnt_rx_bcast, p->cnt_rx_mcast,
+ p->cnt_rx_bad_len, p->cnt_rx_nomem,
+ p->cnt_link_up, p->cnt_link_down, p->cnt_lso_recover,
+ gbe_rd(p, GBE_REG_LINK));
+}
+
+/* link irq is masked off (autoneg pulses storm it lol), so poll it once a sec */
+static void gbe_link_poll_work(struct work_struct *work)
+{
+ struct gbe_priv *p = container_of(to_delayed_work(work),
+ struct gbe_priv, link_poll);
+ unsigned long delay = HZ;
+
+ gbe_link_change(p);
+
+ /*
+ * on a cold boot the chip sometimes just never fires its first irq and
+ * napi sits there doing nothing. if the irq count hasnt moved since last
+ * tick the msi is dead -- kick napi by hand and re-arm the mask. msi is the
+ * only irq source (no intx pin), so while it stays dead we keep polling fast
+ * (GBE_POLL_FALLBACK_MS) instead of once a second, or interactive rx lags by
+ * up to a second. as soon as real irqs start arriving we drop back to HZ.
+ */
+ if (netif_running(p->netdev) && p->cnt_irq == p->irq_watchdog) {
+ napi_schedule(&p->napi);
+ gbe_wr(p, GBE_REG_IER, GBE_IER_MASK);
+ delay = max_t(unsigned long, 1, msecs_to_jiffies(GBE_POLL_FALLBACK_MS));
+ }
+ p->irq_watchdog = p->cnt_irq;
+
+ /* dump stats roughly every 10s regardless of the current poll cadence */
+ if (++p->poll_tick >= 10 * HZ / delay) {
+ gbe_dump_stats(p);
+ p->poll_tick = 0;
+ }
+
+ schedule_delayed_work(&p->link_poll, delay);
+}
+
+/*
+ * the chip latches an lso error and then just sulks, wont tx until the
+ * ring gets rebuilt. so tear it down and stand it back up, same toggle as init.
+ */
+static void gbe_lso_recover(struct gbe_priv *p)
+{
+ p->cnt_lso_recover++;
+ netdev_warn(p->netdev, "LSO error, rebuilding TX ring (cnt=%u)\n",
+ p->cnt_lso_recover);
+
+ spin_lock(&p->lock);
+ netif_stop_queue(p->netdev);
+
+ gbe_clr(p, GBE_REG_TXKICK, BIT(6));
+ gbe_set(p, GBE_REG_TXKICK, BIT(6));
+
+ gbe_init_tx_ring(p);
+ dma_wmb();
+
+ gbe_wr(p, GBE_REG_TX_RING_BASE, p->tx_ring_dma);
+ gbe_wr(p, GBE_REG_TX_RING_CUR, p->tx_ring_dma);
+ gbe_set(p, GBE_REG_TX_DMA_CTRL, BIT(0));
+
+ netif_wake_queue(p->netdev);
+ spin_unlock(&p->lock);
+}
+
+/* napi: do tx, then rx, turn irqs back on once we drop under budget */
+static int gbe_poll(struct napi_struct *napi, int budget)
+{
+ struct gbe_priv *p = container_of(napi, struct gbe_priv, napi);
+ int rx_done;
+
+ /* isr flags this when it sees an lso cause, deal with it out of hardirq */
+ if (test_and_clear_bit(GBE_ST_LSO_RECOVER, &p->state))
+ gbe_lso_recover(p);
+
+ spin_lock(&p->lock);
+ gbe_tx_complete(p);
+ gbe_set(p, GBE_REG_TX_DMA_CTRL, GBE_DMA_KICK);
+ spin_unlock(&p->lock);
+
+ rx_done = gbe_rx_poll(p, budget);
+
+ if (rx_done < budget) {
+ u32 isr;
+
+ napi_complete_done(napi, rx_done);
+ gbe_wr(p, GBE_REG_IER, GBE_IER_MASK);
+ /* chip wont send a fresh msi for stuff that landed while ier was
+ off, so re-check isr and re-kick or interrupts just freeze.
+ ACK the causes (W1C) first: otherwise a latched/undelivered
+ cause (the msi-silent cold-boot case) keeps this condition
+ permanently true and spins napi at ~30k polls/s, pinning a cpu. */
+ isr = gbe_rd(p, GBE_REG_ISR) & GBE_IER_MASK;
+ if (isr) {
+ gbe_wr(p, GBE_REG_ISR, isr);
+ if (napi_schedule_prep(&p->napi)) {
+ gbe_wr(p, GBE_REG_IER, 0);
+ __napi_schedule(&p->napi);
+ }
+ }
+ }
+ return rx_done;
+}
+
+static irqreturn_t gbe_isr(int irq, void *data)
+{
+ struct gbe_priv *p = data;
+ u32 status;
+
+ status = gbe_rd(p, GBE_REG_ISR);
+ if (!status)
+ return IRQ_NONE;
+
+ /* ack everyhting we just read off */
+ gbe_wr(p, GBE_REG_ISR, status);
+
+ p->cnt_irq++;
+ if (status & GBE_ISR_LINK)
+ p->cnt_irq_link++;
+ if (status & GBE_ISR_TX_DONE)
+ p->cnt_irq_tx++;
+ if (status & GBE_ISR_RX_DONE)
+ p->cnt_irq_rx++;
+ if (status & GBE_ISR_ERRORS)
+ p->cnt_irq_err++;
+ if (status & GBE_ISR_LSO_RECOVER)
+ p->cnt_irq_lso++;
+
+ if (status & GBE_ISR_LINK)
+ gbe_link_change(p);
+
+ if (status & GBE_ISR_ERRORS) {
+ u32 err = status & GBE_ISR_ERRORS;
+
+ net_err_ratelimited("%s: HW error %#x%s%s%s%s%s%s%s\n",
+ netdev_name(p->netdev), err,
+ err & GBE_ERR_LSO_FIFO ? " lso-fifo-empty" : "",
+ err & GBE_ERR_LSO_PROTO ? " lso-proto" : "",
+ err & GBE_ERR_RX_AXI ? " rx-axi" : "",
+ err & GBE_ERR_IP_CKSUM ? " ip-cksum" : "",
+ err & GBE_ERR_TCP_CKSUM ? " tcp-cksum" : "",
+ err & GBE_ERR_UDP_CKSUM ? " udp-cksum" : "",
+ err & GBE_ERR_RX_PCODE ? " rx-pcode" : "");
+ p->netdev->stats.rx_errors++;
+ }
+
+ if (status & GBE_ISR_LSO_RECOVER)
+ set_bit(GBE_ST_LSO_RECOVER, &p->state);
+
+ /* mask irqs and let napi do the ring work out of hardirq */
+ if (napi_schedule_prep(&p->napi)) {
+ gbe_wr(p, GBE_REG_IER, 0);
+ __napi_schedule(&p->napi);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static int gbe_open(struct net_device *dev)
+{
+ struct gbe_priv *p = netdev_priv(dev);
+ int ret;
+
+ ret = request_irq(p->irq, gbe_isr, IRQF_SHARED, dev->name, p);
+ if (ret)
+ return ret;
+
+ p->link_up = 0;
+ netif_carrier_off(dev);
+
+ gbe_init_hw(p);
+ gbe_rx_fill(p);
+ gbe_init_rings_hw(p);
+ napi_enable(&p->napi);
+ netif_start_queue(dev);
+
+ gbe_link_change(p);
+ schedule_delayed_work(&p->link_poll, HZ);
+
+ return 0;
+}
+
+static int gbe_stop(struct net_device *dev)
+{
+ struct gbe_priv *p = netdev_priv(dev);
+
+ netif_stop_queue(dev);
+ netif_carrier_off(dev);
+
+ cancel_delayed_work_sync(&p->link_poll);
+
+ gbe_stop_dma(p);
+
+ free_irq(p->irq, p);
+ napi_disable(&p->napi);
+ return 0;
+}
+
+/* stack gave up on us, stop tx dma and stand the ring back up */
+static void gbe_tx_timeout(struct net_device *dev, unsigned int txqueue)
+{
+ struct gbe_priv *p = netdev_priv(dev);
+ int i;
+
+ spin_lock_bh(&p->lock);
+
+ gbe_set(p, GBE_REG_TX_DMA_CTRL, GBE_DMA_STOP);
+ for (i = 0; i < 1000 && (gbe_rd(p, GBE_REG_TX_DMA_CTRL) & GBE_DMA_STOP); i++)
+ ;
+
+ gbe_init_tx_ring(p);
+ dma_wmb();
+
+ gbe_wr(p, GBE_REG_TX_RING_BASE, p->tx_ring_dma);
+ gbe_wr(p, GBE_REG_TX_RING_CUR, p->tx_ring_dma);
+
+ gbe_clr(p, GBE_REG_TXKICK, BIT(6));
+ gbe_set(p, GBE_REG_TXKICK, BIT(6));
+
+ gbe_set(p, GBE_REG_TX_DMA_CTRL, BIT(0) | GBE_DMA_KICK);
+
+ netif_wake_queue(dev);
+ spin_unlock_bh(&p->lock);
+}
+
+static const struct net_device_ops gbe_netdev_ops = {
+ .ndo_open = gbe_open,
+ .ndo_stop = gbe_stop,
+ .ndo_start_xmit = gbe_xmit,
+ .ndo_tx_timeout = gbe_tx_timeout,
+ .ndo_set_mac_address = gbe_set_mac_address,
+ .ndo_set_rx_mode = gbe_set_rx_mode,
+ .ndo_validate_addr = eth_validate_addr,
+};
+
+static int gbe_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+ struct net_device *netdev;
+ struct gbe_priv *p;
+ u8 mac[ETH_ALEN];
+ int ret;
+
+ if (!spcie_is_initialized())
+ return -EPROBE_DEFER;
+
+ ret = pcim_enable_device(pdev);
+ if (ret)
+ return ret;
+
+ /* GBE registers are in BAR0 */
+ ret = pcim_iomap_regions(pdev, BIT(0), KBUILD_MODNAME);
+ if (ret)
+ return ret;
+
+ pci_set_master(pdev);
+
+ ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
+ if (ret)
+ return ret;
+
+ netdev = alloc_etherdev(sizeof(*p));
+ if (!netdev)
+ return -ENOMEM;
+
+ SET_NETDEV_DEV(netdev, &pdev->dev);
+
+ p = netdev_priv(netdev);
+ p->netdev = netdev;
+ p->pdev = pdev;
+ p->base = pcim_iomap_table(pdev)[0];
+ spin_lock_init(&p->lock);
+
+ ret = gbe_alloc_rings(p);
+ if (ret)
+ goto err_free;
+
+ ret = gbe_glue_map(p);
+ if (ret) {
+ dev_err(&pdev->dev, "probe: glue BAR4 map failed: %d\n", ret);
+ goto err_rings;
+ }
+
+ if (gbe_read_glue_mac(p, mac) == 0 && is_valid_ether_addr(mac)) {
+ eth_hw_addr_set(netdev, mac);
+ } else {
+ eth_hw_addr_random(netdev);
+ dev_warn(&pdev->dev, "no MAC from Salina Glue, using random %pM\n",
+ netdev->dev_addr);
+ }
+
+ netdev->netdev_ops = &gbe_netdev_ops;
+ netdev->ethtool_ops = &gbe_ethtool_ops;
+ netdev->watchdog_timeo = 5 * HZ;
+
+ netif_napi_add(netdev, &p->napi, gbe_poll);
+ INIT_DELAYED_WORK(&p->link_poll, gbe_link_poll_work);
+
+ /* device has no intx pin so msi is the only optoin here */
+ ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_MSI | PCI_IRQ_INTX);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "probe: no IRQ vectors: %d\n", ret);
+ goto err_napi;
+ }
+ p->irq = pci_irq_vector(pdev, 0);
+
+ pci_set_drvdata(pdev, netdev);
+
+ ret = register_netdev(netdev);
+ if (ret)
+ goto err_irq;
+
+ netif_carrier_off(netdev);
+
+ dev_info(&pdev->dev, "Salina GBE (chip %#x)\n", spcie_get_chip_id());
+ return 0;
+
+err_irq:
+ pci_free_irq_vectors(pdev);
+err_napi:
+ netif_napi_del(&p->napi);
+ gbe_glue_unmap(p);
+err_rings:
+ gbe_free_rings(p);
+err_free:
+ free_netdev(netdev);
+ return ret;
+}
+
+static void gbe_remove(struct pci_dev *pdev)
+{
+ struct net_device *netdev = pci_get_drvdata(pdev);
+ struct gbe_priv *p = netdev_priv(netdev);
+
+ unregister_netdev(netdev);
+ netif_napi_del(&p->napi);
+ pci_free_irq_vectors(pdev);
+ gbe_glue_unmap(p);
+ gbe_free_rings(p);
+ free_netdev(netdev);
+}
+
+static const struct pci_device_id gbe_pci_tbl[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_SONY, PCI_DEVICE_ID_GBE) },
+ { }
+};
+MODULE_DEVICE_TABLE(pci, gbe_pci_tbl);
+
+static struct pci_driver gbe_driver = {
+ .name = KBUILD_MODNAME,
+ .id_table = gbe_pci_tbl,
+ .probe = gbe_probe,
+ .remove = gbe_remove,
+};
+
+module_pci_driver(gbe_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Armandas Kvietkus");
+MODULE_DESCRIPTION("PlayStation 5 Gigabit Ethernet driver");
diff --git a/drivers/net/phy/mts/mts_phy.c b/drivers/net/phy/mts/mts_phy.c
new file mode 100644
index 000000000000..91fedcca4589
--- /dev/null
+++ b/drivers/net/phy/mts/mts_phy.c
@@ -0,0 +1,404 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * PlayStation 5 Gigabit Ethernet driver
+ *
+ * Based on the MediaTek Star Ethernet MAC (mtk_star_emac).
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/kernel.h>
+#include <linux/minmax.h>
+#include <linux/delay.h>
+#include <linux/mii.h>
+#include <linux/netdevice.h>
+#include <linux/ps5.h>
+#include "mts.h"
+
+/* bit 15 is write-arm on write and done-flag on read */
+#define SMI_ARM BIT(15)
+#define SMI_DONE BIT(15)
+#define SMI_BUSY BIT(15)
+#define SMI_TIMEOUT 10000
+
+static int gbe_smi_wait(struct gbe_priv *p)
+{
+ int i;
+
+ for (i = 0; i < SMI_TIMEOUT; i++) {
+ if (gbe_rd(p, GBE_REG_SMI) & SMI_DONE)
+ return 0;
+ udelay(1);
+ }
+ return -ETIMEDOUT;
+}
+
+/* plain clause-22 mii read */
+static u16 gbe_cl22_read(struct gbe_priv *p, u8 reg)
+{
+ gbe_wr(p, GBE_REG_SMI, SMI_BUSY);
+ gbe_wr(p, GBE_REG_SMI, ((reg & 0x1f) << 8) | 0x4000);
+ if (gbe_smi_wait(p))
+ return 0;
+ return gbe_rd(p, GBE_REG_SMI) >> 16;
+}
+
+static void gbe_smi_write(struct gbe_priv *p, u8 reg, u16 val)
+{
+ gbe_wr(p, GBE_REG_SMI, SMI_BUSY);
+ gbe_wr(p, GBE_REG_SMI, ((u32)val << 16) | ((reg & 0x1f) << 8) | 0x2000);
+ gbe_smi_wait(p);
+}
+
+/* clause-45 is indirect, set the adress first then read/write the data */
+static int gbe_cl45_addr(struct gbe_priv *p, u32 sel)
+{
+ gbe_wr(p, GBE_REG_SMI, SMI_BUSY);
+ gbe_wr(p, GBE_REG_SMI, (sel & 0xffff0000) | ((sel & 0x1f) << 8) | 0x20);
+ return gbe_smi_wait(p);
+}
+
+static void gbe_cl45_write(struct gbe_priv *p, u32 sel, u16 val)
+{
+ if (gbe_cl45_addr(p, sel))
+ return;
+ gbe_wr(p, GBE_REG_SMI, SMI_BUSY);
+ gbe_wr(p, GBE_REG_SMI, ((u32)val << 16) | ((sel & 0x1f) << 8) | 0x60);
+ gbe_smi_wait(p);
+}
+
+static u16 gbe_cl45_read(struct gbe_priv *p, u32 sel)
+{
+ if (gbe_cl45_addr(p, sel))
+ return 0;
+ gbe_wr(p, GBE_REG_SMI, SMI_BUSY);
+ gbe_wr(p, GBE_REG_SMI, ((sel & 0x1f) << 8) | 0xe0);
+ if (gbe_smi_wait(p))
+ return 0;
+ return gbe_rd(p, GBE_REG_SMI) >> 16;
+}
+
+/* PCS/SerDes regs live in Salina Glue BAR4 at offset GBE_PCS_BASE */
+static u32 gbe_pcs_rd(struct gbe_priv *p, u32 off)
+{
+ return readl(p->glue_base + GBE_PCS_BASE + off);
+}
+
+/* maps a measured serdes field to its analog setting */
+static const u8 gbe_cal_lut[64] = {
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7b, 0x7a, 0x75, 0x73, 0x70, 0x67, 0x64, 0x62,
+ 0x57, 0x55, 0x53, 0x51, 0x48, 0x46, 0x44, 0x42,
+ 0x40, 0x37, 0x35, 0x34, 0x32, 0x31, 0x30, 0x26,
+ 0x24, 0x23, 0x22, 0x21, 0x20, 0x16, 0x15, 0x14,
+ 0x13, 0x12, 0x11, 0x10, 0x07, 0x06, 0x05, 0x04,
+ 0x03, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+
+static u8 gbe_cal_lut_idx(u32 field)
+{
+ field &= 0x7f;
+ if (field < 2)
+ field = 1;
+ if (field >= 0x40)
+ field = 0x40;
+ return gbe_cal_lut[field - 1];
+}
+
+/* shove a cal value into the high or low byte of a lane reg */
+static void gbe_cal_lane(struct gbe_priv *p, u32 sel, u8 cal, bool high)
+{
+ u16 cur = gbe_cl45_read(p, sel);
+
+ if (high)
+ gbe_cl45_write(p, sel, (cur & 0x00ff) | (cal << 8) | 0x8000);
+ else
+ gbe_cl45_write(p, sel, (cur & 0xff00) | cal | 0x80);
+}
+
+static u16 gbe_eq_preset(u32 field)
+{
+ return (min_t(u32, field & 0x3f, 0x3c) + 3) & 0xff;
+}
+
+/* feed the measured serdes status back into the analog tunning regs :) */
+static void gbe_phy_calibrate(struct gbe_priv *p)
+{
+ u32 v;
+
+ v = gbe_pcs_rd(p, 0x68);
+ gbe_cl45_write(p, 0x000e001e, (v & 0x3f) << 8);
+ v = gbe_pcs_rd(p, 0x68);
+ gbe_cl45_write(p, 0x0115001f, (v >> 6) & 7);
+
+ v = gbe_pcs_rd(p, 0x60);
+ gbe_cal_lane(p, 0x0174001e, gbe_cal_lut_idx(v), true);
+ v = gbe_pcs_rd(p, 0x60);
+ gbe_cal_lane(p, 0x0174001e, gbe_cal_lut_idx(v >> 0x13), false);
+ v = gbe_pcs_rd(p, 0x64);
+ gbe_cal_lane(p, 0x0175001e, gbe_cal_lut_idx(v >> 6), true);
+ v = gbe_pcs_rd(p, 0x64);
+ gbe_cal_lane(p, 0x0175001e, gbe_cal_lut_idx(v >> 0x19), false);
+
+ v = gbe_pcs_rd(p, 0x5c);
+ gbe_cl45_write(p, 0x0172001e,
+ (gbe_cl45_read(p, 0x0172001e) & 0xc0ff) | ((v >> 0xc) & 0x3f00));
+ v = gbe_pcs_rd(p, 0x60);
+ gbe_cl45_write(p, 0x0172001e,
+ (gbe_cl45_read(p, 0x0172001e) & 0xffc0) | ((v >> 7) & 0x3f));
+ v = gbe_pcs_rd(p, 0x60);
+ gbe_cl45_write(p, 0x0173001e,
+ (gbe_cl45_read(p, 0x0173001e) & 0xc0ff) | ((v >> 0x12) & 0x3f00));
+ v = gbe_pcs_rd(p, 0x64);
+ gbe_cl45_write(p, 0x0173001e,
+ (gbe_cl45_read(p, 0x0173001e) & 0xffc0) | ((v >> 0xd) & 0x3f));
+
+ v = gbe_pcs_rd(p, 0x5c) >> 0x1a;
+ gbe_cl45_write(p, 0x0012001e, (v << 0xa) | v);
+ gbe_cl45_write(p, 0x0016001e, (gbe_eq_preset(v) << 0xa) | v);
+ v = gbe_pcs_rd(p, 0x60) >> 0xd;
+ gbe_cl45_write(p, 0x0017001e, ((v & 0x3f) << 8) | (v & 0x3f));
+ gbe_cl45_write(p, 0x0018001e, (gbe_eq_preset(v) << 8) | (v & 0x3f));
+ v = gbe_pcs_rd(p, 0x64);
+ gbe_cl45_write(p, 0x0019001e, ((v & 0x3f) << 8) | (v & 0x3f));
+ gbe_cl45_write(p, 0x0020001e, (gbe_eq_preset(v) << 8) | (v & 0x3f));
+ v = gbe_pcs_rd(p, 0x64) >> 0x13;
+ gbe_cl45_write(p, 0x0021001e, ((v & 0x3f) << 8) | (v & 0x3f));
+ gbe_cl45_write(p, 0x0022001e, (gbe_eq_preset(v) << 8) | (v & 0x3f));
+
+ gbe_cl45_write(p, 0x0096001e, 0x8000);
+ gbe_cl45_write(p, 0x0037001e, 0x0033);
+ gbe_cl45_write(p, 0x0039001e, gbe_cl45_read(p, 0x0039001e) & 0xb7ff);
+ gbe_cl45_write(p, 0x0107001f, gbe_cl45_read(p, 0x0107001f) & 0xefff);
+ gbe_cl45_write(p, 0x0171001e, gbe_cl45_read(p, 0x0171001e) | 0x0180);
+ gbe_cl45_write(p, 0x0039001e, gbe_cl45_read(p, 0x0039001e) | 0x2000);
+ gbe_cl45_write(p, 0x0039001e, gbe_cl45_read(p, 0x0039001e) & 0xdfff);
+ udelay(50);
+ gbe_cl45_write(p, 0x0171001e, gbe_cl45_read(p, 0x0171001e) & 0xfe7f);
+}
+
+/* poking a paged register block needs this 3-write form, comes up alot */
+static void gbe_smi_paged(struct gbe_priv *p, u16 a, u16 b, u16 c)
+{
+ u16 page = gbe_cl22_read(p, 0x1f);
+
+ gbe_smi_write(p, 0x1f, 0x52b5);
+ gbe_smi_write(p, 0x11, a);
+ gbe_smi_write(p, 0x12, b);
+ gbe_smi_write(p, 0x10, c);
+ gbe_smi_write(p, 0x1f, page);
+}
+
+/* split version of the above for when the final reg 0x10 write is conditional */
+static u16 gbe_paged_begin(struct gbe_priv *p, u16 r11, u16 r12)
+{
+ u16 page = gbe_cl22_read(p, 0x1f);
+
+ gbe_smi_write(p, 0x1f, 0x52b5);
+ gbe_smi_write(p, 0x11, r11);
+ gbe_smi_write(p, 0x12, r12);
+ return page;
+}
+
+static void gbe_paged_finish(struct gbe_priv *p, u16 r10, u16 page)
+{
+ gbe_smi_write(p, 0x10, r10);
+ gbe_smi_write(p, 0x1f, page);
+}
+
+/*
+ * Analog PHY tuning sequence - pile of magic values that make link work.
+ * 4-way branch on (chip_id, revision_id), not sure which ps5 rev is which:
+ * 0x110000 / 0x0100 path A PS5
+ * 0x110000 / 0x0200 path C PS5
+ * 0x110000 / other path B PS5 (other rev)
+ * != 0x110000 path D other chip
+ */
+static void gbe_phy_static_init(struct gbe_priv *p)
+{
+ u32 chip, rev;
+
+ gbe_cl45_write(p, 0x003e001e, 0xf8f8);
+ gbe_cl45_write(p, 0x0189001e, 0x0110);
+ gbe_smi_paged(p, 0xb90a, 0x006f, 0x8f82);
+ gbe_smi_paged(p, 0xbaef, 0x002e, 0x968c);
+
+ /* page-3 LED config */
+ gbe_smi_write(p, 0x1f, 0x0003);
+ gbe_smi_write(p, 0x1c, 0x0c92);
+ gbe_smi_write(p, 0x1f, 0x0000);
+
+ gbe_wr(p, GBE_REG_RX_PCODE + 4, 25000000);
+
+ gbe_cl45_write(p, 0x0122001e, 0xffff);
+ gbe_cl45_write(p, 0x0234001e, 0x0180);
+ gbe_smi_paged(p, 0x2e00, 0x000e, 0x8fb0);
+
+ gbe_cl45_write(p, 0x0238001e, 0x0120);
+ if (spcie_get_chip_id() == 0x110000)
+ gbe_cl45_write(p, 0x0120001e, 0x9014);
+ gbe_cl45_write(p, 0x0239001e, 0x0117);
+ gbe_smi_paged(p, 0x0001, 0x0004, 0x96a2);
+
+ gbe_clr(p, GBE_REG_RX_PCODE, BIT(0));
+
+ gbe_cl45_write(p, 0x003c0007, 0x0000);
+ gbe_cl45_write(p, 0x0033001e, gbe_cl45_read(p, 0x0033001e) & 0xefff);
+ gbe_cl45_write(p, 0x0268001f, 0x07f4);
+
+ gbe_smi_paged(p, 0x0004, 0x0000, 0x9686);
+ gbe_smi_paged(p, 0x0671, 0x0006, 0x8fae);
+ gbe_smi_paged(p, 0x55a0, 0x0000, 0x83aa);
+
+ gbe_cl45_write(p, 0x0123001e, 0xffff);
+
+ gbe_smi_paged(p, 0x8670, 0x0001, 0x96a6);
+ gbe_smi_paged(p, 0x0072, 0x0000, 0x96b6);
+ gbe_smi_paged(p, 0x3210, 0x0000, 0x96b8);
+ gbe_smi_paged(p, 0x024a, 0x0000, 0x96a8);
+
+ chip = spcie_get_chip_id();
+ rev = spcie_get_revision_id();
+ netdev_info(p->netdev, "PHY tune: chip=%#x rev=%#x\n", chip, rev);
+
+ if (chip == 0x110000) {
+ if (rev == 0x0100) {
+ u16 page;
+
+ netdev_info(p->netdev, "PHY tune: path A (0x110100)\n");
+ gbe_smi_paged(p, 0x704d, 0x0000, 0x9698);
+ gbe_smi_paged(p, 0x314f, 0x0002, 0x969a);
+ page = gbe_paged_begin(p, 0x4444, 0x0044);
+ gbe_paged_finish(p, 0x8ecc, page);
+ } else if (rev == 0x0200) {
+ u16 page;
+
+ netdev_info(p->netdev, "PHY tune: path C (0x110200)\n");
+ gbe_smi_paged(p, 0x5010, 0x0000, 0x96a0);
+ gbe_smi_paged(p, 0x3028, 0x0000, 0x969e);
+ gbe_smi_paged(p, 0x504d, 0x0000, 0x9698);
+ page = gbe_paged_begin(p, 0x194f, 0x0002);
+ gbe_paged_finish(p, 0x969a, page);
+ } else {
+ /* path B: PS5 - this rev skips the final reg 0x10 write */
+ netdev_info(p->netdev, "PHY tune: path B (subsys %#x)\n", rev);
+ gbe_smi_paged(p, 0x5010, 0x0000, 0x96a0);
+ gbe_smi_paged(p, 0x3028, 0x0000, 0x969e);
+ gbe_smi_paged(p, 0x504d, 0x0000, 0x9698);
+ gbe_smi_paged(p, 0x194f, 0x0002, 0x969a);
+ gbe_cl45_write(p, 0x014a001e, 0xee20);
+ gbe_cl45_write(p, 0x019b001e, 0x0111);
+ goto skip_path_d_continuation;
+ }
+ } else {
+ u16 page;
+
+ netdev_info(p->netdev, "PHY tune: path D (chip %#x)\n", chip);
+ gbe_smi_paged(p, 0x5010, 0x0000, 0x96a0);
+ gbe_smi_paged(p, 0x3028, 0x0000, 0x969e);
+ gbe_smi_paged(p, 0x504d, 0x0000, 0x9698);
+ gbe_smi_paged(p, 0x194f, 0x0002, 0x969a);
+
+ gbe_cl45_write(p, 0x014a001e, 0xee20);
+ gbe_cl45_write(p, 0x019b001e, 0x0111);
+ gbe_cl45_write(p, 0x0144001e, 0x0200);
+
+ gbe_smi_write(p, 0x1f, 0x0003);
+ gbe_smi_write(p, 0x1d, 0x03fb);
+ gbe_smi_write(p, 0x1f, 0x0000);
+
+ gbe_cl45_write(p, 0x0323001e, 0x0011);
+ gbe_smi_paged(p, 0x0036, 0x0000, 0x8f80);
+
+ gbe_cl45_write(p, 0x0120001e, 0x8014);
+
+ page = gbe_paged_begin(p, 0xff3f, 0x0000);
+ gbe_paged_finish(p, 0x83ae, page);
+
+ gbe_cl45_write(p, 0x0000001e, 0x0186);
+ gbe_cl45_write(p, 0x0001001e, 0x01c5);
+ gbe_cl45_write(p, 0x0002001e, 0x01c8);
+ gbe_cl45_write(p, 0x0003001e, 0x010e);
+ gbe_cl45_write(p, 0x0004001e, 0x0202);
+ gbe_cl45_write(p, 0x0005001e, 0x0207);
+ gbe_cl45_write(p, 0x0006001e, 0x0386);
+ gbe_cl45_write(p, 0x0007001e, 0x03c5);
+ gbe_cl45_write(p, 0x0008001e, 0x03c8);
+ gbe_cl45_write(p, 0x0009001e, 0x030a);
+ gbe_cl45_write(p, 0x000a001e, 0x0005);
+ gbe_cl45_write(p, 0x000b001e, 0x0008);
+ }
+
+skip_path_d_continuation:
+ gbe_cl45_write(p, 0x003e001e, 0x0000);
+}
+
+int gbe_phy_init(struct gbe_priv *p)
+{
+ u16 bmcr;
+
+ gbe_cl22_read(p, MII_PHYSID1);
+ gbe_cl22_read(p, MII_PHYSID2);
+
+ gbe_wr(p, GBE_REG_RESET, 9);
+ usleep_range(680, 1000);
+
+ /* both SerDes lanes must be locked before calibraton is valid */
+ if (~gbe_pcs_rd(p, 0x6c) & 0x80800000)
+ netdev_info(p->netdev, "SerDes not locked, skipping calibration\n");
+ else
+ gbe_phy_calibrate(p);
+
+ gbe_phy_static_init(p);
+
+ {
+ u16 adv = gbe_cl22_read(p, MII_ADVERTISE);
+
+ gbe_smi_write(p, MII_ADVERTISE, adv & 0xf3ff);
+ }
+
+ /* clear bits 12-13 and bit 31 in LINK reg to let the link state machien settle */
+ {
+ u32 v = gbe_rd(p, GBE_REG_LINK);
+
+ gbe_wr(p, GBE_REG_LINK, v & 0x7fffcfff);
+ }
+
+ gbe_cl22_read(p, MII_ADVERTISE);
+ gbe_cl22_read(p, MII_CTRL1000);
+ gbe_smi_write(p, MII_BMCR, BMCR_PDOWN);
+
+ {
+ u16 adv = gbe_cl22_read(p, MII_ADVERTISE);
+
+ adv = (adv & 0xfe1f) | 0x01e0;
+ gbe_smi_write(p, MII_ADVERTISE, adv);
+ }
+ {
+ u16 c1000 = gbe_cl22_read(p, MII_CTRL1000);
+
+ c1000 = (c1000 & 0xfcff) | 0x0200;
+ gbe_smi_write(p, MII_CTRL1000, c1000);
+ }
+ gbe_smi_write(p, MII_BMCR, 0x1340);
+
+ bmcr = gbe_cl22_read(p, MII_BMCR);
+ gbe_smi_write(p, MII_BMCR, bmcr | (BMCR_ANENABLE | BMCR_ANRESTART));
+
+ {
+ u16 id1 = gbe_cl22_read(p, MII_PHYSID1);
+ u16 id2 = gbe_cl22_read(p, MII_PHYSID2);
+ u16 b_bmcr = gbe_cl22_read(p, MII_BMCR);
+ u16 b_bmsr = gbe_cl22_read(p, MII_BMSR);
+ u16 b_adv = gbe_cl22_read(p, MII_ADVERTISE);
+ u16 b_c1k = gbe_cl22_read(p, MII_CTRL1000);
+
+ netdev_info(p->netdev,
+ "phy id=%04x:%04x bmcr=%04x bmsr=%04x adv=%04x ctrl1000=%04x link_reg=%08x\n",
+ id1, id2, b_bmcr, b_bmsr, b_adv, b_c1k,
+ gbe_rd(p, GBE_REG_LINK));
+ }
+
+ return 0;
+}
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index b63cd0c310bc..495b2714838b 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -2806,6 +2806,14 @@ static int next_ari_fn(struct pci_bus *bus, struct pci_dev *dev, int fn)
u16 cap = 0;
unsigned int next_fn;
+#ifdef CONFIG_X86_PS5
+ /* ARI capability is broken, so we just assume contiguous functions until 45. */
+ if (fn < 45)
+ return fn + 1;
+ else
+ return -ENODEV;
+#endif
+
if (!dev)
return -ENODEV;
diff --git a/drivers/ps5/Makefile b/drivers/ps5/Makefile
new file mode 100644
index 000000000000..b4b42394aed9
--- /dev/null
+++ b/drivers/ps5/Makefile
@@ -0,0 +1,2 @@
+obj-y += spcie.o tpcie.o hdmi.o mp1.o buzzer.o svm.o vmenter.o fan.o
+obj-y += led/
diff --git a/drivers/ps5/autoservo_param.h b/drivers/ps5/autoservo_param.h
new file mode 100644
index 000000000000..612aee5b273a
--- /dev/null
+++ b/drivers/ps5/autoservo_param.h
@@ -0,0 +1,1904 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef _AUTOSERVO_PARAM_H
+#define _AUTOSERVO_PARAM_H
+
+static const u8 autoservo_param_sancarlo[] = {
+ 0x00, 0x04, 0x33, 0x01, 0x33, 0x01, 0xe1, 0x00, 0x33, 0x01, 0xe1, 0x00,
+ 0x00, 0x04, 0x33, 0x01, 0x00, 0x04, 0x33, 0x01, 0x33, 0x01, 0x00, 0x04,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x45, 0x00, 0x00,
+ 0x82, 0x16, 0x00, 0x00, 0xc8, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00,
+ 0x00, 0x00, 0xd8, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0x00, 0x48, 0x00, 0x00, 0xf4, 0x01, 0x00, 0x00,
+ 0x14, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x50, 0x00, 0x00,
+ 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0xd8, 0x00,
+ 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x3b, 0x00, 0x00, 0x82, 0x16, 0x00, 0x00, 0x69, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0x00, 0x50, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00,
+ 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0xd8, 0x00, 0x00, 0x64, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x48, 0x00, 0x00,
+ 0xf4, 0x01, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0x00, 0x50, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00,
+ 0x00, 0x00, 0xd8, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0x00, 0x04, 0x33, 0x01, 0x33, 0x01, 0xe1, 0x00,
+ 0x33, 0x01, 0xe1, 0x00, 0x00, 0x04, 0x33, 0x01, 0x00, 0x04, 0x33, 0x01,
+ 0x33, 0x01, 0x00, 0x04, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x45, 0x00, 0x00, 0x82, 0x16, 0x00, 0x00, 0xc8, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00,
+ 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0xd8, 0x00, 0x00, 0x64, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x48, 0x00, 0x00,
+ 0xf4, 0x01, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0x00, 0x50, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00,
+ 0x00, 0x00, 0xd8, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0x00, 0x3b, 0x00, 0x00, 0x82, 0x16, 0x00, 0x00,
+ 0x69, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x50, 0x00, 0x00,
+ 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0xd8, 0x00,
+ 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x48, 0x00, 0x00, 0xf4, 0x01, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0x00, 0x50, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00,
+ 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0xd8, 0x00, 0x00, 0x64, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x04, 0x33, 0x01,
+ 0x33, 0x01, 0xe1, 0x00, 0x33, 0x01, 0xe1, 0x00, 0x00, 0x04, 0x33, 0x01,
+ 0x00, 0x04, 0x33, 0x01, 0x33, 0x01, 0x00, 0x04, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0x00, 0x45, 0x00, 0x00, 0x82, 0x16, 0x00, 0x00,
+ 0xc8, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0xd8, 0x00,
+ 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x48, 0x00, 0x00, 0xf4, 0x01, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0x00, 0x50, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00,
+ 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0xd8, 0x00, 0x00, 0x64, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x3b, 0x00, 0x00,
+ 0x82, 0x16, 0x00, 0x00, 0x69, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0x00, 0x50, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00,
+ 0x00, 0x00, 0xd8, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0x00, 0x48, 0x00, 0x00, 0xf4, 0x01, 0x00, 0x00,
+ 0x14, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x50, 0x00, 0x00,
+ 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0xd8, 0x00,
+ 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x04, 0x33, 0x01, 0x33, 0x01, 0xe1, 0x00, 0x33, 0x01, 0xe1, 0x00,
+ 0x00, 0x04, 0x33, 0x01, 0x00, 0x04, 0x33, 0x01, 0x33, 0x01, 0x00, 0x04,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x45, 0x00, 0x00,
+ 0x82, 0x16, 0x00, 0x00, 0xc8, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00,
+ 0x00, 0x00, 0xd8, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0x00, 0x48, 0x00, 0x00, 0xf4, 0x01, 0x00, 0x00,
+ 0x14, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x50, 0x00, 0x00,
+ 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0xd8, 0x00,
+ 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x3b, 0x00, 0x00, 0x82, 0x16, 0x00, 0x00, 0x69, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0x00, 0x50, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00,
+ 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0xd8, 0x00, 0x00, 0x64, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x48, 0x00, 0x00,
+ 0xf4, 0x01, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0x00, 0x50, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00,
+ 0x00, 0x00, 0xd8, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x04, 0xe1, 0x00, 0x00, 0x04, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x50, 0x00, 0x00,
+ 0xfa, 0x2d, 0x00, 0x00, 0xc1, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0x01, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00,
+ 0x00, 0x00, 0xd8, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+};
+
+static const u8 autoservo_param_a_eiger_samsung[] = {
+ 0x00, 0x04, 0x67, 0x00, 0x00, 0x04, 0x67, 0x00, 0x00, 0x04, 0x67, 0x00,
+ 0x00, 0x04, 0x67, 0x00, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x5b, 0x00, 0x00,
+ 0x05, 0x17, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xe8, 0x5d, 0x00, 0x00, 0x50, 0x46, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00,
+ 0xe0, 0x9c, 0x41, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0x00, 0x4c, 0x00, 0x00, 0x3b, 0x0a, 0x00, 0x00,
+ 0x03, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x50, 0x00, 0x00,
+ 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0xd8, 0x00,
+ 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x27, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00,
+ 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0xd8, 0x00, 0x00, 0x27, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x45, 0x00, 0x00,
+ 0x3b, 0x0a, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0x00, 0x50, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00,
+ 0x00, 0x00, 0xd8, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0x00, 0x04, 0xbe, 0x00, 0x00, 0x04, 0xbe, 0x00,
+ 0x00, 0x04, 0xbe, 0x00, 0x00, 0x04, 0xbe, 0x00, 0x00, 0x04, 0x00, 0x04,
+ 0xd5, 0x00, 0x00, 0x04, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x5b, 0x00, 0x00, 0x05, 0x17, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xe8, 0x5d, 0x00, 0x00, 0x50, 0x46, 0x00, 0x00,
+ 0x00, 0x80, 0x02, 0x00, 0xe0, 0x9c, 0x41, 0x00, 0x00, 0x64, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x4c, 0x00, 0x00,
+ 0x3b, 0x0a, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0x00, 0x50, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00,
+ 0x00, 0x00, 0xd8, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0x00, 0x27, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x50, 0x00, 0x00,
+ 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0xd8, 0x00,
+ 0x00, 0x27, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0xa5, 0x21, 0x00, 0x00,
+ 0x7f, 0x0b, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x45, 0x00, 0x00, 0x3b, 0x0a, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0x00, 0x50, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00,
+ 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0xd8, 0x00, 0x00, 0x64, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x04, 0x67, 0x00,
+ 0x00, 0x04, 0x67, 0x00, 0x00, 0x04, 0x67, 0x00, 0x00, 0x04, 0x67, 0x00,
+ 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0x00, 0x5b, 0x00, 0x00, 0x05, 0x17, 0x00, 0x00,
+ 0x25, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xe8, 0x5d, 0x00, 0x00,
+ 0x50, 0x46, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0xe0, 0x9c, 0x41, 0x00,
+ 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x4c, 0x00, 0x00, 0x3b, 0x0a, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0x00, 0x50, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00,
+ 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0xd8, 0x00, 0x00, 0x64, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x27, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0x00, 0x50, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00,
+ 0x00, 0x00, 0xd8, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xcd, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0x00, 0x45, 0x00, 0x00, 0x3b, 0x0a, 0x00, 0x00,
+ 0x03, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x50, 0x00, 0x00,
+ 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0xd8, 0x00,
+ 0x00, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x04, 0xbe, 0x00, 0x00, 0x04, 0xbe, 0x00, 0x00, 0x04, 0xbe, 0x00,
+ 0x00, 0x04, 0xbe, 0x00, 0x00, 0x04, 0x00, 0x04, 0xd5, 0x00, 0x00, 0x04,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x56, 0x00, 0x00,
+ 0x05, 0x17, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xe8, 0x5d, 0x00, 0x00, 0x50, 0x46, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00,
+ 0x00, 0x00, 0xd8, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0x00, 0x4a, 0x00, 0x00, 0x3b, 0x0a, 0x00, 0x00,
+ 0x06, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x50, 0x00, 0x00,
+ 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0xd8, 0x00,
+ 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x27, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0x00, 0x50, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00,
+ 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0xd8, 0x00, 0x00, 0x27, 0x00, 0x00,
+ 0x00, 0x17, 0x00, 0x00, 0xa5, 0x21, 0x00, 0x00, 0x7f, 0x0b, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x40, 0x00, 0x00,
+ 0x3b, 0x0a, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0x00, 0x50, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00,
+ 0x00, 0x00, 0xd8, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x04, 0x67, 0x00, 0x00, 0x04, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x50, 0x00, 0x00,
+ 0xfa, 0x2d, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0x01, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00,
+ 0x00, 0x00, 0xd8, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+};
+
+static const u8 autoservo_param_a_eiger_hynix[] = {
+ 0x00, 0x04, 0x67, 0x00, 0x00, 0x04, 0x67, 0x00, 0x00, 0x04, 0x67, 0x00,
+ 0x00, 0x04, 0x67, 0x00, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x5b, 0x00, 0x00,
+ 0x05, 0x17, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xe8, 0x5d, 0x00, 0x00, 0x50, 0x46, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00,
+ 0xe0, 0x9c, 0x41, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0x80, 0x4e, 0x00, 0x00, 0x3b, 0x0a, 0x00, 0x00,
+ 0x03, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x50, 0x00, 0x00,
+ 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0xd8, 0x00,
+ 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x27, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00,
+ 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0xd8, 0x00, 0x00, 0x27, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x45, 0x00, 0x00,
+ 0x3b, 0x0a, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0x00, 0x50, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00,
+ 0x00, 0x00, 0xd8, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0x00, 0x04, 0xbe, 0x00, 0x00, 0x04, 0xbe, 0x00,
+ 0x00, 0x04, 0xbe, 0x00, 0x00, 0x04, 0xbe, 0x00, 0x00, 0x04, 0x00, 0x04,
+ 0xd5, 0x00, 0x00, 0x04, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x5b, 0x00, 0x00, 0x05, 0x17, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xe8, 0x5d, 0x00, 0x00, 0x50, 0x46, 0x00, 0x00,
+ 0x00, 0x80, 0x02, 0x00, 0xe0, 0x9c, 0x41, 0x00, 0x00, 0x64, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x4e, 0x00, 0x00,
+ 0x3b, 0x0a, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0x00, 0x50, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00,
+ 0x00, 0x00, 0xd8, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0x00, 0x27, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x50, 0x00, 0x00,
+ 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0xd8, 0x00,
+ 0x00, 0x27, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0xa5, 0x21, 0x00, 0x00,
+ 0x7f, 0x0b, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x45, 0x00, 0x00, 0x3b, 0x0a, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0x00, 0x50, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00,
+ 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0xd8, 0x00, 0x00, 0x64, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x04, 0x67, 0x00,
+ 0x00, 0x04, 0x67, 0x00, 0x00, 0x04, 0x67, 0x00, 0x00, 0x04, 0x67, 0x00,
+ 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0x00, 0x5b, 0x00, 0x00, 0x05, 0x17, 0x00, 0x00,
+ 0x25, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xe8, 0x5d, 0x00, 0x00,
+ 0x50, 0x46, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0xe0, 0x9c, 0x41, 0x00,
+ 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x80, 0x4e, 0x00, 0x00, 0x3b, 0x0a, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0x00, 0x50, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00,
+ 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0xd8, 0x00, 0x00, 0x64, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x27, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0x00, 0x50, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00,
+ 0x00, 0x00, 0xd8, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xcd, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0x00, 0x45, 0x00, 0x00, 0x3b, 0x0a, 0x00, 0x00,
+ 0x03, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x50, 0x00, 0x00,
+ 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0xd8, 0x00,
+ 0x00, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x04, 0xbe, 0x00, 0x00, 0x04, 0xbe, 0x00, 0x00, 0x04, 0xbe, 0x00,
+ 0x00, 0x04, 0xbe, 0x00, 0x00, 0x04, 0x00, 0x04, 0xd5, 0x00, 0x00, 0x04,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x56, 0x00, 0x00,
+ 0x05, 0x17, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xe8, 0x5d, 0x00, 0x00, 0x50, 0x46, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00,
+ 0x00, 0x00, 0xd8, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0x80, 0x4c, 0x00, 0x00, 0x3b, 0x0a, 0x00, 0x00,
+ 0x06, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x50, 0x00, 0x00,
+ 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0xd8, 0x00,
+ 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x27, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0x00, 0x50, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00,
+ 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0xd8, 0x00, 0x00, 0x27, 0x00, 0x00,
+ 0x00, 0x17, 0x00, 0x00, 0xa5, 0x21, 0x00, 0x00, 0x7f, 0x0b, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x40, 0x00, 0x00,
+ 0x3b, 0x0a, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0x00, 0x50, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00,
+ 0x00, 0x00, 0xd8, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x04, 0x67, 0x00, 0x00, 0x04, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x50, 0x00, 0x00,
+ 0xfa, 0x2d, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0x01, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00,
+ 0x00, 0x00, 0xd8, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+};
+
+static const u8 autoservo_param_a_eiger_micron[] = {
+ 0x00, 0x04, 0x67, 0x00, 0x00, 0x04, 0x67, 0x00, 0x00, 0x04, 0x67, 0x00,
+ 0x00, 0x04, 0x67, 0x00, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x5b, 0x00, 0x00,
+ 0x05, 0x17, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xe8, 0x5d, 0x00, 0x00, 0x50, 0x46, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00,
+ 0xe0, 0x9c, 0x41, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0x00, 0x52, 0x00, 0x00, 0x3b, 0x0a, 0x00, 0x00,
+ 0x03, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x50, 0x00, 0x00,
+ 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0xd8, 0x00,
+ 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x27, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00,
+ 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0xd8, 0x00, 0x00, 0x27, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x45, 0x00, 0x00,
+ 0x3b, 0x0a, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0x00, 0x50, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00,
+ 0x00, 0x00, 0xd8, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0x00, 0x04, 0xbe, 0x00, 0x00, 0x04, 0xbe, 0x00,
+ 0x00, 0x04, 0xbe, 0x00, 0x00, 0x04, 0xbe, 0x00, 0x00, 0x04, 0x00, 0x04,
+ 0xd5, 0x00, 0x00, 0x04, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x5b, 0x00, 0x00, 0x05, 0x17, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xe8, 0x5d, 0x00, 0x00, 0x50, 0x46, 0x00, 0x00,
+ 0x00, 0x80, 0x02, 0x00, 0xe0, 0x9c, 0x41, 0x00, 0x00, 0x64, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x52, 0x00, 0x00,
+ 0x3b, 0x0a, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0x00, 0x50, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00,
+ 0x00, 0x00, 0xd8, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0x00, 0x27, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x50, 0x00, 0x00,
+ 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0xd8, 0x00,
+ 0x00, 0x27, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0xa5, 0x21, 0x00, 0x00,
+ 0x7f, 0x0b, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x45, 0x00, 0x00, 0x3b, 0x0a, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0x00, 0x50, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00,
+ 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0xd8, 0x00, 0x00, 0x64, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x04, 0x67, 0x00,
+ 0x00, 0x04, 0x67, 0x00, 0x00, 0x04, 0x67, 0x00, 0x00, 0x04, 0x67, 0x00,
+ 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0x00, 0x5b, 0x00, 0x00, 0x05, 0x17, 0x00, 0x00,
+ 0x25, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xe8, 0x5d, 0x00, 0x00,
+ 0x50, 0x46, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0xe0, 0x9c, 0x41, 0x00,
+ 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x52, 0x00, 0x00, 0x3b, 0x0a, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0x00, 0x50, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00,
+ 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0xd8, 0x00, 0x00, 0x64, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x27, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0x00, 0x50, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00,
+ 0x00, 0x00, 0xd8, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xcd, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0x00, 0x45, 0x00, 0x00, 0x3b, 0x0a, 0x00, 0x00,
+ 0x03, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x50, 0x00, 0x00,
+ 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0xd8, 0x00,
+ 0x00, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x04, 0xbe, 0x00, 0x00, 0x04, 0xbe, 0x00, 0x00, 0x04, 0xbe, 0x00,
+ 0x00, 0x04, 0xbe, 0x00, 0x00, 0x04, 0x00, 0x04, 0xd5, 0x00, 0x00, 0x04,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x56, 0x00, 0x00,
+ 0x05, 0x17, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xe8, 0x5d, 0x00, 0x00, 0x50, 0x46, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00,
+ 0x00, 0x00, 0xd8, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0x00, 0x50, 0x00, 0x00, 0x3b, 0x0a, 0x00, 0x00,
+ 0x06, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x50, 0x00, 0x00,
+ 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0xd8, 0x00,
+ 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x27, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0x00, 0x50, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00,
+ 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0xd8, 0x00, 0x00, 0x27, 0x00, 0x00,
+ 0x00, 0x13, 0x00, 0x00, 0xa5, 0x21, 0x00, 0x00, 0x7f, 0x0b, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x40, 0x00, 0x00,
+ 0x3b, 0x0a, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0x00, 0x50, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00,
+ 0x00, 0x00, 0xd8, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x04, 0x67, 0x00, 0x00, 0x04, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x50, 0x00, 0x00,
+ 0xfa, 0x2d, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0x01, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00,
+ 0x00, 0x00, 0xd8, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+};
+
+static const u8 autoservo_param_a_denali_samsung[] = {
+ 0x00, 0x04, 0x67, 0x00, 0x00, 0x04, 0x67, 0x00, 0x00, 0x04, 0x67, 0x00,
+ 0x00, 0x04, 0x67, 0x00, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x5b, 0x00, 0x00,
+ 0x05, 0x17, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xe8, 0x5d, 0x00, 0x00, 0x50, 0x46, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00,
+ 0xe0, 0x9c, 0x41, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0x80, 0x4c, 0x00, 0x00, 0x3b, 0x0a, 0x00, 0x00,
+ 0x03, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x50, 0x00, 0x00,
+ 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0xd8, 0x00,
+ 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x27, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00,
+ 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0xd8, 0x00, 0x00, 0x27, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x45, 0x00, 0x00,
+ 0x3b, 0x0a, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0x00, 0x50, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00,
+ 0x00, 0x00, 0xd8, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0x00, 0x04, 0xbe, 0x00, 0x00, 0x04, 0xbe, 0x00,
+ 0x00, 0x04, 0xbe, 0x00, 0x00, 0x04, 0xbe, 0x00, 0x00, 0x04, 0x00, 0x04,
+ 0xd5, 0x00, 0x00, 0x04, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x5b, 0x00, 0x00, 0x05, 0x17, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xe8, 0x5d, 0x00, 0x00, 0x50, 0x46, 0x00, 0x00,
+ 0x00, 0x80, 0x02, 0x00, 0xe0, 0x9c, 0x41, 0x00, 0x00, 0x64, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x4c, 0x00, 0x00,
+ 0x3b, 0x0a, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0x00, 0x50, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00,
+ 0x00, 0x00, 0xd8, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0x00, 0x27, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x50, 0x00, 0x00,
+ 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0xd8, 0x00,
+ 0x00, 0x27, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0xa5, 0x21, 0x00, 0x00,
+ 0x7f, 0x0b, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x45, 0x00, 0x00, 0x3b, 0x0a, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0x00, 0x50, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00,
+ 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0xd8, 0x00, 0x00, 0x64, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x04, 0x67, 0x00,
+ 0x00, 0x04, 0x67, 0x00, 0x00, 0x04, 0x67, 0x00, 0x00, 0x04, 0x67, 0x00,
+ 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0x00, 0x5b, 0x00, 0x00, 0x05, 0x17, 0x00, 0x00,
+ 0x25, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xe8, 0x5d, 0x00, 0x00,
+ 0x50, 0x46, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0xe0, 0x9c, 0x41, 0x00,
+ 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x80, 0x4c, 0x00, 0x00, 0x3b, 0x0a, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0x00, 0x50, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00,
+ 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0xd8, 0x00, 0x00, 0x64, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x27, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0x00, 0x50, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00,
+ 0x00, 0x00, 0xd8, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xcd, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0x00, 0x45, 0x00, 0x00, 0x3b, 0x0a, 0x00, 0x00,
+ 0x03, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x50, 0x00, 0x00,
+ 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0xd8, 0x00,
+ 0x00, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x04, 0xbe, 0x00, 0x00, 0x04, 0xbe, 0x00, 0x00, 0x04, 0xbe, 0x00,
+ 0x00, 0x04, 0xbe, 0x00, 0x00, 0x04, 0x00, 0x04, 0xd5, 0x00, 0x00, 0x04,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x56, 0x00, 0x00,
+ 0x05, 0x17, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xe8, 0x5d, 0x00, 0x00, 0x50, 0x46, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00,
+ 0x00, 0x00, 0xd8, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0x80, 0x4a, 0x00, 0x00, 0x3b, 0x0a, 0x00, 0x00,
+ 0x06, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x50, 0x00, 0x00,
+ 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0xd8, 0x00,
+ 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x27, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0x00, 0x50, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00,
+ 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0xd8, 0x00, 0x00, 0x27, 0x00, 0x00,
+ 0x00, 0x16, 0x00, 0x00, 0xa5, 0x21, 0x00, 0x00, 0x7f, 0x0b, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x40, 0x00, 0x00,
+ 0x3b, 0x0a, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0x00, 0x50, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00,
+ 0x00, 0x00, 0xd8, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x04, 0x67, 0x00, 0x00, 0x04, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x50, 0x00, 0x00,
+ 0xfa, 0x2d, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0x01, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00,
+ 0x00, 0x00, 0xd8, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+};
+
+static const u8 autoservo_param_a_denali_hynix[] = {
+ 0x00, 0x04, 0x67, 0x00, 0x00, 0x04, 0x67, 0x00, 0x00, 0x04, 0x67, 0x00,
+ 0x00, 0x04, 0x67, 0x00, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x5b, 0x00, 0x00,
+ 0x05, 0x17, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xe8, 0x5d, 0x00, 0x00, 0x50, 0x46, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00,
+ 0xe0, 0x9c, 0x41, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0x00, 0x50, 0x00, 0x00, 0x3b, 0x0a, 0x00, 0x00,
+ 0x03, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x50, 0x00, 0x00,
+ 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0xd8, 0x00,
+ 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x27, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00,
+ 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0xd8, 0x00, 0x00, 0x27, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x45, 0x00, 0x00,
+ 0x3b, 0x0a, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0x00, 0x50, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00,
+ 0x00, 0x00, 0xd8, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0x00, 0x04, 0xbe, 0x00, 0x00, 0x04, 0xbe, 0x00,
+ 0x00, 0x04, 0xbe, 0x00, 0x00, 0x04, 0xbe, 0x00, 0x00, 0x04, 0x00, 0x04,
+ 0xd5, 0x00, 0x00, 0x04, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x5b, 0x00, 0x00, 0x05, 0x17, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xe8, 0x5d, 0x00, 0x00, 0x50, 0x46, 0x00, 0x00,
+ 0x00, 0x80, 0x02, 0x00, 0xe0, 0x9c, 0x41, 0x00, 0x00, 0x64, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x50, 0x00, 0x00,
+ 0x3b, 0x0a, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0x00, 0x50, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00,
+ 0x00, 0x00, 0xd8, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0x00, 0x27, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x50, 0x00, 0x00,
+ 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0xd8, 0x00,
+ 0x00, 0x27, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0xa5, 0x21, 0x00, 0x00,
+ 0x7f, 0x0b, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x45, 0x00, 0x00, 0x3b, 0x0a, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0x00, 0x50, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00,
+ 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0xd8, 0x00, 0x00, 0x64, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x04, 0x67, 0x00,
+ 0x00, 0x04, 0x67, 0x00, 0x00, 0x04, 0x67, 0x00, 0x00, 0x04, 0x67, 0x00,
+ 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0x00, 0x5b, 0x00, 0x00, 0x05, 0x17, 0x00, 0x00,
+ 0x25, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xe8, 0x5d, 0x00, 0x00,
+ 0x50, 0x46, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0xe0, 0x9c, 0x41, 0x00,
+ 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x50, 0x00, 0x00, 0x3b, 0x0a, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0x00, 0x50, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00,
+ 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0xd8, 0x00, 0x00, 0x64, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x27, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0x00, 0x50, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00,
+ 0x00, 0x00, 0xd8, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xcd, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0x00, 0x45, 0x00, 0x00, 0x3b, 0x0a, 0x00, 0x00,
+ 0x03, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x50, 0x00, 0x00,
+ 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0xd8, 0x00,
+ 0x00, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x04, 0xbe, 0x00, 0x00, 0x04, 0xbe, 0x00, 0x00, 0x04, 0xbe, 0x00,
+ 0x00, 0x04, 0xbe, 0x00, 0x00, 0x04, 0x00, 0x04, 0xd5, 0x00, 0x00, 0x04,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x56, 0x00, 0x00,
+ 0x05, 0x17, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xe8, 0x5d, 0x00, 0x00, 0x50, 0x46, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00,
+ 0x00, 0x00, 0xd8, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0x00, 0x4e, 0x00, 0x00, 0x3b, 0x0a, 0x00, 0x00,
+ 0x06, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x50, 0x00, 0x00,
+ 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0xd8, 0x00,
+ 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x27, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0x00, 0x50, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00,
+ 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0xd8, 0x00, 0x00, 0x27, 0x00, 0x00,
+ 0x00, 0x16, 0x00, 0x00, 0xa5, 0x21, 0x00, 0x00, 0x7f, 0x0b, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x40, 0x00, 0x00,
+ 0x3b, 0x0a, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0x00, 0x50, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00,
+ 0x00, 0x00, 0xd8, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x04, 0x67, 0x00, 0x00, 0x04, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x50, 0x00, 0x00,
+ 0xfa, 0x2d, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0x01, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00,
+ 0x00, 0x00, 0xd8, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+};
+
+static const u8 autoservo_param_a_denali_micron[] = {
+ 0x00, 0x04, 0x67, 0x00, 0x00, 0x04, 0x67, 0x00, 0x00, 0x04, 0x67, 0x00,
+ 0x00, 0x04, 0x67, 0x00, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x5b, 0x00, 0x00,
+ 0x05, 0x17, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xe8, 0x5d, 0x00, 0x00, 0x50, 0x46, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00,
+ 0xe0, 0x9c, 0x41, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0x40, 0x53, 0x00, 0x00, 0x3b, 0x0a, 0x00, 0x00,
+ 0x03, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x50, 0x00, 0x00,
+ 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0xd8, 0x00,
+ 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x27, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00,
+ 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0xd8, 0x00, 0x00, 0x27, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x45, 0x00, 0x00,
+ 0x3b, 0x0a, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0x00, 0x50, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00,
+ 0x00, 0x00, 0xd8, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0x00, 0x04, 0xbe, 0x00, 0x00, 0x04, 0xbe, 0x00,
+ 0x00, 0x04, 0xbe, 0x00, 0x00, 0x04, 0xbe, 0x00, 0x00, 0x04, 0x00, 0x04,
+ 0xe3, 0x00, 0x00, 0x04, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x5b, 0x00, 0x00, 0x05, 0x17, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xe8, 0x5d, 0x00, 0x00, 0x50, 0x46, 0x00, 0x00,
+ 0x00, 0x80, 0x02, 0x00, 0xe0, 0x9c, 0x41, 0x00, 0x00, 0x64, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x40, 0x53, 0x00, 0x00,
+ 0x3b, 0x0a, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0x00, 0x50, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00,
+ 0x00, 0x00, 0xd8, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0x00, 0x27, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x50, 0x00, 0x00,
+ 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0xd8, 0x00,
+ 0x00, 0x27, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0xa5, 0x21, 0x00, 0x00,
+ 0x84, 0x12, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x45, 0x00, 0x00, 0x3b, 0x0a, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0x00, 0x50, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00,
+ 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0xd8, 0x00, 0x00, 0x64, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x04, 0x67, 0x00,
+ 0x00, 0x04, 0x67, 0x00, 0x00, 0x04, 0x67, 0x00, 0x00, 0x04, 0x67, 0x00,
+ 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0x00, 0x5b, 0x00, 0x00, 0x05, 0x17, 0x00, 0x00,
+ 0x25, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xe8, 0x5d, 0x00, 0x00,
+ 0x50, 0x46, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0xe0, 0x9c, 0x41, 0x00,
+ 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x40, 0x53, 0x00, 0x00, 0x3b, 0x0a, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0x00, 0x50, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00,
+ 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0xd8, 0x00, 0x00, 0x64, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x27, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0x00, 0x50, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00,
+ 0x00, 0x00, 0xd8, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xcd, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0x00, 0x45, 0x00, 0x00, 0x3b, 0x0a, 0x00, 0x00,
+ 0x03, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x50, 0x00, 0x00,
+ 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0xd8, 0x00,
+ 0x00, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x04, 0xbe, 0x00, 0x00, 0x04, 0xbe, 0x00, 0x00, 0x04, 0xbe, 0x00,
+ 0x00, 0x04, 0xbe, 0x00, 0x00, 0x04, 0x00, 0x04, 0xe3, 0x00, 0x00, 0x04,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x56, 0x00, 0x00,
+ 0x05, 0x17, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xe8, 0x5d, 0x00, 0x00, 0x50, 0x46, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00,
+ 0x00, 0x00, 0xd8, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0x40, 0x51, 0x00, 0x00, 0x3b, 0x0a, 0x00, 0x00,
+ 0x06, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x50, 0x00, 0x00,
+ 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0xd8, 0x00,
+ 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x27, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0x00, 0x50, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00,
+ 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0xd8, 0x00, 0x00, 0x27, 0x00, 0x00,
+ 0x00, 0x13, 0x00, 0x00, 0xa5, 0x21, 0x00, 0x00, 0x84, 0x12, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x40, 0x00, 0x00,
+ 0x3b, 0x0a, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0x00, 0x50, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00,
+ 0x00, 0x00, 0xd8, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x04, 0x67, 0x00, 0x00, 0x04, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x50, 0x00, 0x00,
+ 0xfa, 0x2d, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0x01, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00,
+ 0x00, 0x00, 0xd8, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+};
+
+static const u8 autoservo_param_b_eiger_denali_samsung_d1x[] = {
+ 0x00, 0x04, 0x67, 0x00, 0x00, 0x04, 0x67, 0x00, 0x00, 0x04, 0x67, 0x00,
+ 0x00, 0x04, 0x67, 0x00, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x5b, 0x00, 0x00,
+ 0x05, 0x17, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xe8, 0x5d, 0x00, 0x00, 0x50, 0x46, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00,
+ 0xe0, 0x9c, 0x41, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0x00, 0x56, 0x00, 0x00, 0xb1, 0x1e, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x50, 0x00, 0x00,
+ 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0xd8, 0x00,
+ 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x27, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00,
+ 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0xd8, 0x00, 0x00, 0x27, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x48, 0x00, 0x00,
+ 0xb1, 0x1e, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0x00, 0x50, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00,
+ 0x00, 0x00, 0xd8, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0x00, 0x04, 0xbe, 0x00, 0x00, 0x04, 0xbe, 0x00,
+ 0x00, 0x04, 0xbe, 0x00, 0x00, 0x04, 0xbe, 0x00, 0x00, 0x04, 0x00, 0x04,
+ 0xce, 0x00, 0x00, 0x04, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x5b, 0x00, 0x00, 0x05, 0x17, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xe8, 0x5d, 0x00, 0x00, 0x50, 0x46, 0x00, 0x00,
+ 0x00, 0x80, 0x02, 0x00, 0xe0, 0x9c, 0x41, 0x00, 0x00, 0x64, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x56, 0x00, 0x00,
+ 0xb1, 0x1e, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0x00, 0x50, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00,
+ 0x00, 0x00, 0xd8, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0x00, 0x27, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x50, 0x00, 0x00,
+ 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0xd8, 0x00,
+ 0x00, 0x27, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0xa5, 0x21, 0x00, 0x00,
+ 0x04, 0x10, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x48, 0x00, 0x00, 0xb1, 0x1e, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0x00, 0x50, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00,
+ 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0xd8, 0x00, 0x00, 0x64, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x04, 0x67, 0x00,
+ 0x00, 0x04, 0x67, 0x00, 0x00, 0x04, 0x67, 0x00, 0x00, 0x04, 0x67, 0x00,
+ 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0x00, 0x5b, 0x00, 0x00, 0x05, 0x17, 0x00, 0x00,
+ 0x25, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xe8, 0x5d, 0x00, 0x00,
+ 0x50, 0x46, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0xe0, 0x9c, 0x41, 0x00,
+ 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x56, 0x00, 0x00, 0xb1, 0x1e, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0x00, 0x50, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00,
+ 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0xd8, 0x00, 0x00, 0x64, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x27, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0x00, 0x50, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00,
+ 0x00, 0x00, 0xd8, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xcd, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0x00, 0x48, 0x00, 0x00, 0xb1, 0x1e, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x50, 0x00, 0x00,
+ 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0xd8, 0x00,
+ 0x00, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x04, 0xbe, 0x00, 0x00, 0x04, 0xbe, 0x00, 0x00, 0x04, 0xbe, 0x00,
+ 0x00, 0x04, 0xbe, 0x00, 0x00, 0x04, 0x00, 0x04, 0xce, 0x00, 0x00, 0x04,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x56, 0x00, 0x00,
+ 0x05, 0x17, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xe8, 0x5d, 0x00, 0x00, 0x50, 0x46, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00,
+ 0x00, 0x00, 0xd8, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0x00, 0x51, 0x00, 0x00, 0xb1, 0x1e, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x50, 0x00, 0x00,
+ 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0xd8, 0x00,
+ 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x27, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0x00, 0x50, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00,
+ 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0xd8, 0x00, 0x00, 0x27, 0x00, 0x00,
+ 0x00, 0x17, 0x00, 0x00, 0xa5, 0x21, 0x00, 0x00, 0x04, 0x10, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x43, 0x00, 0x00,
+ 0xb1, 0x1e, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0x00, 0x50, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00,
+ 0x00, 0x00, 0xd8, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x04, 0x67, 0x00, 0x00, 0x04, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x50, 0x00, 0x00,
+ 0xfa, 0x2d, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0x01, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00,
+ 0x00, 0x00, 0xd8, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+};
+
+static const u8 autoservo_param_b_eiger_denali_hynix_1x_micron_120s[] = {
+ 0x00, 0x04, 0x67, 0x00, 0x00, 0x04, 0x67, 0x00, 0x00, 0x04, 0x67, 0x00,
+ 0x00, 0x04, 0x67, 0x00, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x5b, 0x00, 0x00,
+ 0x05, 0x17, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xe8, 0x5d, 0x00, 0x00, 0x50, 0x46, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00,
+ 0xe0, 0x9c, 0x41, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0x00, 0x58, 0x00, 0x00, 0xb1, 0x1e, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x50, 0x00, 0x00,
+ 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0xd8, 0x00,
+ 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x27, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00,
+ 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0xd8, 0x00, 0x00, 0x27, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x4b, 0x00, 0x00,
+ 0xb1, 0x1e, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0x00, 0x50, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00,
+ 0x00, 0x00, 0xd8, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0x00, 0x04, 0xbe, 0x00, 0x00, 0x04, 0xbe, 0x00,
+ 0x00, 0x04, 0xbe, 0x00, 0x00, 0x04, 0xbe, 0x00, 0x00, 0x04, 0x00, 0x04,
+ 0xce, 0x00, 0x00, 0x04, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x5b, 0x00, 0x00, 0x05, 0x17, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xe8, 0x5d, 0x00, 0x00, 0x50, 0x46, 0x00, 0x00,
+ 0x00, 0x80, 0x02, 0x00, 0xe0, 0x9c, 0x41, 0x00, 0x00, 0x64, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x58, 0x00, 0x00,
+ 0xb1, 0x1e, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0x00, 0x50, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00,
+ 0x00, 0x00, 0xd8, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0x00, 0x27, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x50, 0x00, 0x00,
+ 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0xd8, 0x00,
+ 0x00, 0x27, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0xa5, 0x21, 0x00, 0x00,
+ 0x04, 0x10, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x4b, 0x00, 0x00, 0xb1, 0x1e, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0x00, 0x50, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00,
+ 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0xd8, 0x00, 0x00, 0x64, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x04, 0x67, 0x00,
+ 0x00, 0x04, 0x67, 0x00, 0x00, 0x04, 0x67, 0x00, 0x00, 0x04, 0x67, 0x00,
+ 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0x00, 0x5b, 0x00, 0x00, 0x05, 0x17, 0x00, 0x00,
+ 0x25, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xe8, 0x5d, 0x00, 0x00,
+ 0x50, 0x46, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0xe0, 0x9c, 0x41, 0x00,
+ 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x58, 0x00, 0x00, 0xb1, 0x1e, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0x00, 0x50, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00,
+ 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0xd8, 0x00, 0x00, 0x64, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x27, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0x00, 0x50, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00,
+ 0x00, 0x00, 0xd8, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xcd, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0x00, 0x4b, 0x00, 0x00, 0xb1, 0x1e, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x50, 0x00, 0x00,
+ 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0xd8, 0x00,
+ 0x00, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x04, 0xbe, 0x00, 0x00, 0x04, 0xbe, 0x00, 0x00, 0x04, 0xbe, 0x00,
+ 0x00, 0x04, 0xbe, 0x00, 0x00, 0x04, 0x00, 0x04, 0xce, 0x00, 0x00, 0x04,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x56, 0x00, 0x00,
+ 0x05, 0x17, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xe8, 0x5d, 0x00, 0x00, 0x50, 0x46, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00,
+ 0x00, 0x00, 0xd8, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0x00, 0x53, 0x00, 0x00, 0xb1, 0x1e, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x50, 0x00, 0x00,
+ 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0xd8, 0x00,
+ 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x27, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0x00, 0x50, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00,
+ 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0xd8, 0x00, 0x00, 0x27, 0x00, 0x00,
+ 0x00, 0x17, 0x00, 0x00, 0xa5, 0x21, 0x00, 0x00, 0x04, 0x10, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x46, 0x00, 0x00,
+ 0xb1, 0x1e, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0x00, 0x50, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00,
+ 0x00, 0x00, 0xd8, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x04, 0x67, 0x00, 0x00, 0x04, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x50, 0x00, 0x00,
+ 0xfa, 0x2d, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0x01, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00,
+ 0x00, 0x00, 0xd8, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+};
+
+static const u8 autoservo_param_b_eiger_denali_hynix_1y_micron_130s[] = {
+ 0x00, 0x04, 0x67, 0x00, 0x00, 0x04, 0x67, 0x00, 0x00, 0x04, 0x67, 0x00,
+ 0x00, 0x04, 0x67, 0x00, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x5b, 0x00, 0x00,
+ 0x05, 0x17, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xe8, 0x5d, 0x00, 0x00, 0x50, 0x46, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00,
+ 0xe0, 0x9c, 0x41, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0x00, 0x54, 0x00, 0x00, 0xb1, 0x1e, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x50, 0x00, 0x00,
+ 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0xd8, 0x00,
+ 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x27, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00,
+ 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0xd8, 0x00, 0x00, 0x27, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x48, 0x00, 0x00,
+ 0xb1, 0x1e, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0x00, 0x50, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00,
+ 0x00, 0x00, 0xd8, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0x00, 0x04, 0xbe, 0x00, 0x00, 0x04, 0xbe, 0x00,
+ 0x00, 0x04, 0xbe, 0x00, 0x00, 0x04, 0xbe, 0x00, 0x00, 0x04, 0x00, 0x04,
+ 0xce, 0x00, 0x00, 0x04, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x5b, 0x00, 0x00, 0x05, 0x17, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xe8, 0x5d, 0x00, 0x00, 0x50, 0x46, 0x00, 0x00,
+ 0x00, 0x80, 0x02, 0x00, 0xe0, 0x9c, 0x41, 0x00, 0x00, 0x64, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x54, 0x00, 0x00,
+ 0xb1, 0x1e, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0x00, 0x50, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00,
+ 0x00, 0x00, 0xd8, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0x00, 0x27, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x50, 0x00, 0x00,
+ 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0xd8, 0x00,
+ 0x00, 0x27, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0xa5, 0x21, 0x00, 0x00,
+ 0x04, 0x10, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x48, 0x00, 0x00, 0xb1, 0x1e, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0x00, 0x50, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00,
+ 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0xd8, 0x00, 0x00, 0x64, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x04, 0x67, 0x00,
+ 0x00, 0x04, 0x67, 0x00, 0x00, 0x04, 0x67, 0x00, 0x00, 0x04, 0x67, 0x00,
+ 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0x00, 0x5b, 0x00, 0x00, 0x05, 0x17, 0x00, 0x00,
+ 0x25, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xe8, 0x5d, 0x00, 0x00,
+ 0x50, 0x46, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0xe0, 0x9c, 0x41, 0x00,
+ 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x54, 0x00, 0x00, 0xb1, 0x1e, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0x00, 0x50, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00,
+ 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0xd8, 0x00, 0x00, 0x64, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x27, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0x00, 0x50, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00,
+ 0x00, 0x00, 0xd8, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xcd, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0x00, 0x48, 0x00, 0x00, 0xb1, 0x1e, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x50, 0x00, 0x00,
+ 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0xd8, 0x00,
+ 0x00, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x04, 0xbe, 0x00, 0x00, 0x04, 0xbe, 0x00, 0x00, 0x04, 0xbe, 0x00,
+ 0x00, 0x04, 0xbe, 0x00, 0x00, 0x04, 0x00, 0x04, 0xce, 0x00, 0x00, 0x04,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x56, 0x00, 0x00,
+ 0x05, 0x17, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xe8, 0x5d, 0x00, 0x00, 0x50, 0x46, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00,
+ 0x00, 0x00, 0xd8, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0x00, 0x4f, 0x00, 0x00, 0xb1, 0x1e, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x50, 0x00, 0x00,
+ 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0xd8, 0x00,
+ 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x27, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0x00, 0x50, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00,
+ 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0xd8, 0x00, 0x00, 0x27, 0x00, 0x00,
+ 0x00, 0x17, 0x00, 0x00, 0xa5, 0x21, 0x00, 0x00, 0x04, 0x10, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x43, 0x00, 0x00,
+ 0xb1, 0x1e, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0x00, 0x50, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00,
+ 0x00, 0x00, 0xd8, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x04, 0x67, 0x00, 0x00, 0x04, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x50, 0x00, 0x00,
+ 0xfa, 0x2d, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0x01, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00,
+ 0x00, 0x00, 0xd8, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+};
+
+static const u8 autoservo_param_d_eiger_denali_samsung_d1z[] = {
+ 0x00, 0x04, 0x83, 0x00, 0x00, 0x04, 0x67, 0x00, 0x00, 0x04, 0x67, 0x00,
+ 0x00, 0x04, 0x67, 0x00, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x5b, 0x00, 0x00,
+ 0x9f, 0x1b, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xe8, 0x5d, 0x00, 0x00, 0x50, 0x46, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00,
+ 0xe0, 0x9c, 0x41, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0x80, 0x55, 0x00, 0x00, 0xb1, 0x1e, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x50, 0x00, 0x00,
+ 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0xd8, 0x00,
+ 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00,
+ 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0xd8, 0x00, 0x00, 0x64, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x49, 0x00, 0x00,
+ 0xb1, 0x1e, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0x00, 0x50, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00,
+ 0x00, 0x00, 0xd8, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0x00, 0x04, 0xec, 0x00, 0x00, 0x04, 0xec, 0x00,
+ 0x00, 0x04, 0xec, 0x00, 0x00, 0x04, 0xec, 0x00, 0x00, 0x04, 0x00, 0x04,
+ 0x1a, 0x01, 0x00, 0x04, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x5b, 0x00, 0x00, 0x9f, 0x1b, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xe8, 0x5d, 0x00, 0x00, 0x50, 0x46, 0x00, 0x00,
+ 0x00, 0x80, 0x02, 0x00, 0xe0, 0x9c, 0x41, 0x00, 0x00, 0x64, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x55, 0x00, 0x00,
+ 0xb1, 0x1e, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0x00, 0x50, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00,
+ 0x00, 0x00, 0xd8, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x50, 0x00, 0x00,
+ 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0xd8, 0x00,
+ 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x80, 0x49, 0x00, 0x00, 0xb1, 0x1e, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0x00, 0x50, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00,
+ 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0xd8, 0x00, 0x00, 0x64, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x04, 0x83, 0x00,
+ 0x00, 0x04, 0x67, 0x00, 0x00, 0x04, 0x67, 0x00, 0x00, 0x04, 0x67, 0x00,
+ 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0x00, 0x5b, 0x00, 0x00, 0x9f, 0x1b, 0x00, 0x00,
+ 0x33, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xe8, 0x5d, 0x00, 0x00,
+ 0x50, 0x46, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0xe0, 0x9c, 0x41, 0x00,
+ 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x80, 0x55, 0x00, 0x00, 0xb1, 0x1e, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0x00, 0x50, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00,
+ 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0xd8, 0x00, 0x00, 0x64, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x64, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0x00, 0x50, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00,
+ 0x00, 0x00, 0xd8, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0x80, 0x49, 0x00, 0x00, 0xb1, 0x1e, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x50, 0x00, 0x00,
+ 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0xd8, 0x00,
+ 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x04, 0xec, 0x00, 0x00, 0x04, 0xec, 0x00, 0x00, 0x04, 0xec, 0x00,
+ 0x00, 0x04, 0xec, 0x00, 0x00, 0x04, 0x00, 0x04, 0xce, 0x00, 0x00, 0x04,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x56, 0x00, 0x00,
+ 0x05, 0x17, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xe8, 0x5d, 0x00, 0x00, 0x50, 0x46, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00,
+ 0x00, 0x00, 0xd8, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0x80, 0x50, 0x00, 0x00, 0xb1, 0x1e, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x50, 0x00, 0x00,
+ 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0xd8, 0x00,
+ 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0x00, 0x50, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00,
+ 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0xd8, 0x00, 0x00, 0x64, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x44, 0x00, 0x00,
+ 0xb1, 0x1e, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0x00, 0x50, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00,
+ 0x00, 0x00, 0xd8, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x04, 0x67, 0x00, 0x00, 0x04, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x50, 0x00, 0x00,
+ 0xfa, 0x2d, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0x01, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00,
+ 0x00, 0x00, 0xd8, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x64, 0x00, 0x63, 0x00, 0x02, 0x00,
+ 0x64, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x04, 0x67,
+ 0x00, 0x00, 0x04, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x80, 0x36, 0x00, 0x00, 0xb1, 0x1e, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0x00, 0x50, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00,
+ 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0xd8, 0x00, 0x00, 0x64, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x64, 0x00,
+ 0x63, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x04, 0x67, 0x00, 0x00, 0x04, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff,
+ 0xff, 0x0f, 0x01, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff,
+ 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00,
+ 0xd8, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+static const u8 autoservo_param_d_eiger_denali_hynix_1y[] = {
+ 0x00, 0x04, 0x83, 0x00, 0x00, 0x04, 0x67, 0x00, 0x00, 0x04, 0x67, 0x00,
+ 0x00, 0x04, 0x67, 0x00, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x5b, 0x00, 0x00,
+ 0x9f, 0x1b, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xe8, 0x5d, 0x00, 0x00, 0x50, 0x46, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00,
+ 0xe0, 0x9c, 0x41, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0x80, 0x56, 0x00, 0x00, 0xb1, 0x1e, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x50, 0x00, 0x00,
+ 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0xd8, 0x00,
+ 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00,
+ 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0xd8, 0x00, 0x00, 0x64, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x49, 0x00, 0x00,
+ 0xb1, 0x1e, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0x00, 0x50, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00,
+ 0x00, 0x00, 0xd8, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0x00, 0x04, 0xec, 0x00, 0x00, 0x04, 0xec, 0x00,
+ 0x00, 0x04, 0xec, 0x00, 0x00, 0x04, 0xec, 0x00, 0x00, 0x04, 0x00, 0x04,
+ 0x1a, 0x01, 0x00, 0x04, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x5b, 0x00, 0x00, 0x9f, 0x1b, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xe8, 0x5d, 0x00, 0x00, 0x50, 0x46, 0x00, 0x00,
+ 0x00, 0x80, 0x02, 0x00, 0xe0, 0x9c, 0x41, 0x00, 0x00, 0x64, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x56, 0x00, 0x00,
+ 0xb1, 0x1e, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0x00, 0x50, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00,
+ 0x00, 0x00, 0xd8, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x50, 0x00, 0x00,
+ 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0xd8, 0x00,
+ 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x80, 0x49, 0x00, 0x00, 0xb1, 0x1e, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0x00, 0x50, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00,
+ 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0xd8, 0x00, 0x00, 0x64, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x04, 0x83, 0x00,
+ 0x00, 0x04, 0x67, 0x00, 0x00, 0x04, 0x67, 0x00, 0x00, 0x04, 0x67, 0x00,
+ 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0x00, 0x5b, 0x00, 0x00, 0x9f, 0x1b, 0x00, 0x00,
+ 0x33, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xe8, 0x5d, 0x00, 0x00,
+ 0x50, 0x46, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0xe0, 0x9c, 0x41, 0x00,
+ 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x80, 0x56, 0x00, 0x00, 0xb1, 0x1e, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0x00, 0x50, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00,
+ 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0xd8, 0x00, 0x00, 0x64, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x64, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0x00, 0x50, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00,
+ 0x00, 0x00, 0xd8, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0x80, 0x49, 0x00, 0x00, 0xb1, 0x1e, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x50, 0x00, 0x00,
+ 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0xd8, 0x00,
+ 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x04, 0xec, 0x00, 0x00, 0x04, 0xec, 0x00, 0x00, 0x04, 0xec, 0x00,
+ 0x00, 0x04, 0xec, 0x00, 0x00, 0x04, 0x00, 0x04, 0xce, 0x00, 0x00, 0x04,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x56, 0x00, 0x00,
+ 0x05, 0x17, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xe8, 0x5d, 0x00, 0x00, 0x50, 0x46, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00,
+ 0x00, 0x00, 0xd8, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0x80, 0x51, 0x00, 0x00, 0xb1, 0x1e, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x50, 0x00, 0x00,
+ 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0xd8, 0x00,
+ 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0x00, 0x50, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00,
+ 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0xd8, 0x00, 0x00, 0x64, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x44, 0x00, 0x00,
+ 0xb1, 0x1e, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0x00, 0x50, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00,
+ 0x00, 0x00, 0xd8, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x04, 0x67, 0x00, 0x00, 0x04, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x50, 0x00, 0x00,
+ 0xfa, 0x2d, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0x01, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00,
+ 0x00, 0x00, 0xd8, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x64, 0x00, 0x63, 0x00, 0x02, 0x00,
+ 0x64, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x04, 0x67,
+ 0x00, 0x00, 0x04, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x80, 0x36, 0x00, 0x00, 0xb1, 0x1e, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0x00, 0x50, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00,
+ 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0xd8, 0x00, 0x00, 0x64, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x64, 0x00,
+ 0x63, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x04, 0x67, 0x00, 0x00, 0x04, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff,
+ 0xff, 0x0f, 0x01, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff,
+ 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00,
+ 0xd8, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+static const u8 autoservo_param_d_eiger_denali_micron_130s_y31j[] = {
+ 0x00, 0x04, 0x83, 0x00, 0x00, 0x04, 0x67, 0x00, 0x00, 0x04, 0x67, 0x00,
+ 0x00, 0x04, 0x67, 0x00, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x5b, 0x00, 0x00,
+ 0x9f, 0x1b, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xe8, 0x5d, 0x00, 0x00, 0x50, 0x46, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00,
+ 0xe0, 0x9c, 0x41, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0x00, 0x55, 0x00, 0x00, 0xb1, 0x1e, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x50, 0x00, 0x00,
+ 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0xd8, 0x00,
+ 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00,
+ 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0xd8, 0x00, 0x00, 0x64, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x47, 0x00, 0x00,
+ 0xb1, 0x1e, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0x00, 0x50, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00,
+ 0x00, 0x00, 0xd8, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0x00, 0x04, 0xec, 0x00, 0x00, 0x04, 0xec, 0x00,
+ 0x00, 0x04, 0xec, 0x00, 0x00, 0x04, 0xec, 0x00, 0x00, 0x04, 0x00, 0x04,
+ 0x1a, 0x01, 0x00, 0x04, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x5b, 0x00, 0x00, 0x9f, 0x1b, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xe8, 0x5d, 0x00, 0x00, 0x50, 0x46, 0x00, 0x00,
+ 0x00, 0x80, 0x02, 0x00, 0xe0, 0x9c, 0x41, 0x00, 0x00, 0x64, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x55, 0x00, 0x00,
+ 0xb1, 0x1e, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0x00, 0x50, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00,
+ 0x00, 0x00, 0xd8, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x50, 0x00, 0x00,
+ 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0xd8, 0x00,
+ 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x80, 0x47, 0x00, 0x00, 0xb1, 0x1e, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0x00, 0x50, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00,
+ 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0xd8, 0x00, 0x00, 0x64, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x04, 0x83, 0x00,
+ 0x00, 0x04, 0x67, 0x00, 0x00, 0x04, 0x67, 0x00, 0x00, 0x04, 0x67, 0x00,
+ 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0x00, 0x5b, 0x00, 0x00, 0x9f, 0x1b, 0x00, 0x00,
+ 0x33, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xe8, 0x5d, 0x00, 0x00,
+ 0x50, 0x46, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0xe0, 0x9c, 0x41, 0x00,
+ 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x55, 0x00, 0x00, 0xb1, 0x1e, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0x00, 0x50, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00,
+ 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0xd8, 0x00, 0x00, 0x64, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x64, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0x00, 0x50, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00,
+ 0x00, 0x00, 0xd8, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0x80, 0x47, 0x00, 0x00, 0xb1, 0x1e, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x50, 0x00, 0x00,
+ 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0xd8, 0x00,
+ 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x04, 0xec, 0x00, 0x00, 0x04, 0xec, 0x00, 0x00, 0x04, 0xec, 0x00,
+ 0x00, 0x04, 0xec, 0x00, 0x00, 0x04, 0x00, 0x04, 0xce, 0x00, 0x00, 0x04,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x56, 0x00, 0x00,
+ 0x05, 0x17, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xe8, 0x5d, 0x00, 0x00, 0x50, 0x46, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00,
+ 0x00, 0x00, 0xd8, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0x00, 0x50, 0x00, 0x00, 0xb1, 0x1e, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x50, 0x00, 0x00,
+ 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0xd8, 0x00,
+ 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0x00, 0x50, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00,
+ 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0xd8, 0x00, 0x00, 0x64, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x42, 0x00, 0x00,
+ 0xb1, 0x1e, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0x00, 0x50, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00,
+ 0x00, 0x00, 0xd8, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x04, 0x67, 0x00, 0x00, 0x04, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x50, 0x00, 0x00,
+ 0xfa, 0x2d, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0x01, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00,
+ 0x00, 0x00, 0xd8, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x64, 0x00, 0x63, 0x00, 0x02, 0x00,
+ 0x64, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x04, 0x67,
+ 0x00, 0x00, 0x04, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x80, 0x36, 0x00, 0x00, 0xb1, 0x1e, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
+ 0xff, 0xff, 0xff, 0x0f, 0x00, 0x50, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00,
+ 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0xd8, 0x00, 0x00, 0x64, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x64, 0x00,
+ 0x63, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x04, 0x67, 0x00, 0x00, 0x04, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff,
+ 0xff, 0x0f, 0x01, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff,
+ 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00,
+ 0xd8, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+#endif /* _AUTOSERVO_PARAM_H */
diff --git a/drivers/ps5/buzzer.c b/drivers/ps5/buzzer.c
new file mode 100644
index 000000000000..f48ad6f92534
--- /dev/null
+++ b/drivers/ps5/buzzer.c
@@ -0,0 +1,291 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/miscdevice.h>
+#include <linux/fs.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+#include <linux/input.h>
+#include <linux/delay.h>
+#include <linux/kthread.h>
+#include <linux/mutex.h>
+#include <linux/device.h>
+#include <linux/ps5.h>
+
+#define BUZZER_IOC_MAGIC 'B'
+
+#define PS5_BUZZ_SILENT 0
+#define PS5_BUZZ_SHORT 1
+#define PS5_BUZZ_ERROR 2
+#define PS5_BUZZ_LONG 3
+
+struct ps5_buzzer_step {
+ __u8 value;
+ __u16 hold_ms;
+} __attribute__((packed));
+
+struct ps5_buzzer_pattern {
+ __u32 nsteps;
+ struct ps5_buzzer_step steps[];
+};
+
+#define PS5_BUZZER_BEEP _IOW(BUZZER_IOC_MAGIC, 1, __u8)
+#define PS5_BUZZER_PLAY _IOW(BUZZER_IOC_MAGIC, 2, struct ps5_buzzer_pattern)
+#define PS5_BUZZER_STOP _IO(BUZZER_IOC_MAGIC, 3)
+
+#define MAX_PATTERN_STEPS 1024
+
+static struct input_dev *snd_idev;
+static struct task_struct *play_thread;
+static DEFINE_MUTEX(play_lock);
+
+static int ps5_buzz_raw(u8 level)
+{
+ u8 buf[ICC_MSG_MAX_SIZE] = {};
+ struct icc_msg *msg = (struct icc_msg *)buf;
+
+ if (level > PS5_BUZZ_LONG)
+ return -EINVAL;
+
+ msg->service_id = ICC_SERVICE_ID_INDICATOR;
+ msg->msg_type = 0x00;
+ msg->length = 0x20;
+ msg->data[0] = level;
+
+ return icc_query(buf, buf);
+}
+
+struct play_ctx {
+ struct ps5_buzzer_step *steps;
+ u32 nsteps;
+};
+
+static int play_fn(void *data)
+{
+ struct play_ctx *ctx = data;
+ u32 i;
+
+ for (i = 0; i < ctx->nsteps && !kthread_should_stop(); i++) {
+ ps5_buzz_raw(ctx->steps[i].value);
+ if (ctx->steps[i].hold_ms)
+ msleep_interruptible(ctx->steps[i].hold_ms);
+ }
+
+ kfree(ctx->steps);
+ kfree(ctx);
+
+ mutex_lock(&play_lock);
+ play_thread = NULL;
+ mutex_unlock(&play_lock);
+ return 0;
+}
+
+static int play_start(struct ps5_buzzer_step *steps, u32 nsteps)
+{
+ struct play_ctx *ctx;
+ struct task_struct *t;
+
+ mutex_lock(&play_lock);
+ if (play_thread) {
+ mutex_unlock(&play_lock);
+ return -EBUSY;
+ }
+
+ ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+ if (!ctx) {
+ mutex_unlock(&play_lock);
+ return -ENOMEM;
+ }
+ ctx->steps = steps;
+ ctx->nsteps = nsteps;
+
+ t = kthread_run(play_fn, ctx, "ps5_buzz_play");
+ if (IS_ERR(t)) {
+ kfree(ctx);
+ mutex_unlock(&play_lock);
+ return PTR_ERR(t);
+ }
+ play_thread = t;
+ mutex_unlock(&play_lock);
+ return 0;
+}
+
+static int play_stop(void)
+{
+ mutex_lock(&play_lock);
+ if (play_thread) {
+ kthread_stop(play_thread);
+ play_thread = NULL;
+ }
+ mutex_unlock(&play_lock);
+ return 0;
+}
+
+static ssize_t buzz_write(struct file *f, const char __user *ubuf,
+ size_t n, loff_t *pos)
+{
+ char c;
+ int ret;
+
+ if (n < 1)
+ return -EINVAL;
+ if (get_user(c, ubuf))
+ return -EFAULT;
+ if (c < '0' || c > '3')
+ return -EINVAL;
+
+ ret = ps5_buzz_raw(c - '0');
+ return ret ? ret : n;
+}
+
+static long buzz_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
+{
+ switch (cmd) {
+ case PS5_BUZZER_BEEP: {
+ u8 level;
+ if (get_user(level, (u8 __user *)arg))
+ return -EFAULT;
+ return ps5_buzz_raw(level);
+ }
+ case PS5_BUZZER_PLAY: {
+ struct ps5_buzzer_pattern hdr;
+ struct ps5_buzzer_step *steps;
+ size_t bytes;
+ int ret;
+
+ if (copy_from_user(&hdr, (void __user *)arg, sizeof(hdr)))
+ return -EFAULT;
+ if (!hdr.nsteps || hdr.nsteps > MAX_PATTERN_STEPS)
+ return -EINVAL;
+
+ bytes = hdr.nsteps * sizeof(struct ps5_buzzer_step);
+ steps = kmalloc(bytes, GFP_KERNEL);
+ if (!steps)
+ return -ENOMEM;
+ if (copy_from_user(steps,
+ (void __user *)(arg + sizeof(hdr)), bytes)) {
+ kfree(steps);
+ return -EFAULT;
+ }
+ ret = play_start(steps, hdr.nsteps);
+ if (ret)
+ kfree(steps);
+ return ret;
+ }
+ case PS5_BUZZER_STOP:
+ return play_stop();
+ }
+ return -ENOTTY;
+}
+
+static const struct file_operations buzz_fops = {
+ .owner = THIS_MODULE,
+ .write = buzz_write,
+ .unlocked_ioctl = buzz_ioctl,
+ .llseek = noop_llseek,
+};
+
+static struct miscdevice buzz_misc = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "ps5_buzzer",
+ .fops = &buzz_fops,
+ .mode = 0660,
+};
+
+static int snd_event(struct input_dev *dev, unsigned int type,
+ unsigned int code, int value)
+{
+ if (type == EV_SND && code == SND_BELL)
+ ps5_buzz_raw(value ? PS5_BUZZ_SHORT : PS5_BUZZ_SILENT);
+ return 0;
+}
+
+static ssize_t beep_store(struct device *d, struct device_attribute *a,
+ const char *buf, size_t n)
+{
+ u8 level;
+ int ret;
+
+ if (kstrtou8(buf, 0, &level))
+ return -EINVAL;
+ ret = ps5_buzz_raw(level);
+ return ret ? ret : n;
+}
+static DEVICE_ATTR_WO(beep);
+
+static ssize_t stop_store(struct device *d, struct device_attribute *a,
+ const char *buf, size_t n)
+{
+ play_stop();
+ return n;
+}
+static DEVICE_ATTR_WO(stop);
+
+static struct attribute *buzz_attrs[] = {
+ &dev_attr_beep.attr,
+ &dev_attr_stop.attr,
+ NULL,
+};
+
+static const struct attribute_group buzz_attr_group = {
+ .attrs = buzz_attrs,
+};
+
+static int __init ps5_buzzer_init(void)
+{
+ int ret;
+
+ ret = misc_register(&buzz_misc);
+ if (ret)
+ return ret;
+
+ ret = sysfs_create_group(&buzz_misc.this_device->kobj, &buzz_attr_group);
+ if (ret)
+ goto err_misc;
+
+ snd_idev = input_allocate_device();
+ if (!snd_idev) {
+ ret = -ENOMEM;
+ goto err_sysfs;
+ }
+ snd_idev->name = "PS5 Chassis Buzzer";
+ snd_idev->phys = "ps5_buzzer/input0";
+ snd_idev->id.bustype = BUS_VIRTUAL;
+ snd_idev->event = snd_event;
+ input_set_capability(snd_idev, EV_SND, SND_BELL);
+
+ ret = input_register_device(snd_idev);
+ if (ret)
+ goto err_input;
+
+ return 0;
+
+err_input:
+ input_free_device(snd_idev);
+ snd_idev = NULL;
+err_sysfs:
+ sysfs_remove_group(&buzz_misc.this_device->kobj, &buzz_attr_group);
+err_misc:
+ misc_deregister(&buzz_misc);
+ return ret;
+}
+
+static void __exit ps5_buzzer_exit(void)
+{
+ play_stop();
+ if (snd_idev)
+ input_unregister_device(snd_idev);
+ sysfs_remove_group(&buzz_misc.this_device->kobj, &buzz_attr_group);
+ misc_deregister(&buzz_misc);
+}
+
+module_init(ps5_buzzer_init);
+module_exit(ps5_buzzer_exit);
+
+MODULE_AUTHOR("Armandas Kvietkus");
+MODULE_DESCRIPTION("PlayStation 5 chassis piezo buzzer");
+MODULE_LICENSE("GPL");
diff --git a/drivers/ps5/fan.c b/drivers/ps5/fan.c
new file mode 100644
index 000000000000..e68819f9e32a
--- /dev/null
+++ b/drivers/ps5/fan.c
@@ -0,0 +1,368 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/unaligned.h>
+#include <linux/ps5.h>
+#include <linux/io.h>
+#include "ps5-fan.h"
+#include "autoservo_param.h"
+
+#define PS5_FAN_BOOT_TARGET_TEMP 80
+
+#define GDDR6_SAMSUNG 0x01
+#define GDDR6_HYNIX 0x06
+#define GDDR6_MICRON 0x0f
+
+#define BOARD_MASK_A 0xffffffffffffff00
+#define BOARD_MASK_B 0xffffffffff00ff00
+
+#define BOARD_SANCARLO_1 0x2001010104010400
+#define BOARD_SANCARLO_2 0x2001010104010500
+#define BOARD_A_EIGER_1 0x3002010104010400
+#define BOARD_A_EIGER_2 0x3002010104010500
+#define BOARD_A_DENALI_1 0x3002010104030400
+#define BOARD_A_DENALI_2 0x3002010104030500
+#define BOARD_B_EIGER_DENALI_1 0x3002020101000400
+#define BOARD_B_EIGER_DENALI_2 0x3002020101000500
+#define BOARD_D_EIGER_DENALI_1 0x3002040101000400
+#define BOARD_D_EIGER_DENALI_2 0x3002040101000500
+
+static void bootparam_get_config_board_id(u64 *board_id)
+{
+ void __iomem *bootparam = ioremap(0x9b000, 0x2000);
+ *board_id = readq(bootparam + 0x328);
+ iounmap(bootparam);
+}
+
+static void bootparam_get_config_gddr6_id(u16 *gddr6_id)
+{
+ void __iomem *bootparam = ioremap(0x9b000, 0x2000);
+ *gddr6_id = readw(bootparam + 0x1184);
+ iounmap(bootparam);
+}
+
+int icc_fan_update_param(const u8 *param)
+{
+ u8 buf[ICC_MSG_MAX_SIZE] = {};
+ struct icc_msg *msg = (struct icc_msg *)buf;
+
+ msg->service_id = ICC_SERVICE_ID_FAN;
+ msg->msg_type = 0xe;
+ msg->length = sizeof(*msg) + 0x6ae;
+ memcpy(msg->data, param, 0x6ae);
+
+ return icc_query(buf, buf);
+}
+EXPORT_SYMBOL(icc_fan_update_param);
+
+int icc_fan_update_autoservo_param(void)
+{
+ u64 board_id, board_mask_a, board_mask_b;
+ u16 gddr6_id;
+ u8 gddr6_vendor, gddr6_revision;
+ const char *board_name = NULL;
+ const char *gddr6_name = NULL;
+ const u8 *param = NULL;
+ int ret;
+
+ bootparam_get_config_board_id(&board_id);
+ board_id = be64_to_cpu(board_id);
+ board_mask_a = board_id & BOARD_MASK_A;
+ board_mask_b = board_id & BOARD_MASK_B;
+
+ bootparam_get_config_gddr6_id(&gddr6_id);
+ gddr6_vendor = gddr6_id & 0xf;
+ gddr6_revision = gddr6_id >> 4;
+
+ if (board_mask_a == BOARD_SANCARLO_1 || board_mask_a == BOARD_SANCARLO_2) {
+ board_name = "Sancarlo";
+ param = autoservo_param_sancarlo;
+ } else if (board_mask_a == BOARD_A_EIGER_1 || board_mask_a == BOARD_A_EIGER_2) {
+ board_name = "A-Eiger";
+ switch (gddr6_vendor) {
+ case GDDR6_SAMSUNG:
+ gddr6_name = "Samsung";
+ param = autoservo_param_a_eiger_samsung;
+ break;
+ case GDDR6_HYNIX:
+ gddr6_name = "Hynix";
+ param = autoservo_param_a_eiger_hynix;
+ break;
+ case GDDR6_MICRON:
+ gddr6_name = "Micron";
+ param = autoservo_param_a_eiger_micron;
+ break;
+ default:
+ pr_info("FanServo: %s Unknown Vendor 0x%x\n", board_name, gddr6_vendor);
+ goto not_updated;
+ }
+ } else if (board_mask_a == BOARD_A_DENALI_1 || board_mask_a == BOARD_A_DENALI_2) {
+ board_name = "A-Denali";
+ switch (gddr6_vendor) {
+ case GDDR6_SAMSUNG:
+ gddr6_name = "Samsung";
+ param = autoservo_param_a_denali_samsung;
+ break;
+ case GDDR6_HYNIX:
+ gddr6_name = "Hynix";
+ param = autoservo_param_a_denali_hynix;
+ break;
+ case GDDR6_MICRON:
+ gddr6_name = "Micron";
+ param = autoservo_param_a_denali_micron;
+ break;
+ default:
+ pr_info("FanServo: %s Unknown Vendor 0x%x\n", board_name, gddr6_vendor);
+ goto not_updated;
+ }
+ } else if (board_mask_b == BOARD_B_EIGER_DENALI_1 || board_mask_b == BOARD_B_EIGER_DENALI_2) {
+ board_name = "B-Eiger/Denali";
+ if (gddr6_vendor == GDDR6_SAMSUNG && gddr6_revision == 8) {
+ gddr6_name = "Samsung D1x";
+ param = autoservo_param_b_eiger_denali_samsung_d1x;
+ } else if (gddr6_vendor == GDDR6_SAMSUNG && gddr6_revision == 9) {
+ gddr6_name = "Samsung D1z";
+ param = NULL;
+ } else if (gddr6_vendor == GDDR6_HYNIX && gddr6_revision == 0) {
+ gddr6_name = "Hynix 1x";
+ param = autoservo_param_b_eiger_denali_hynix_1x_micron_120s;
+ } else if (gddr6_vendor == GDDR6_HYNIX && gddr6_revision == 1) {
+ gddr6_name = "Hynix 1y";
+ param = autoservo_param_b_eiger_denali_hynix_1y_micron_130s;
+ } else if (gddr6_vendor == GDDR6_MICRON && gddr6_revision == 0) {
+ gddr6_name = "Micron 120s";
+ param = autoservo_param_b_eiger_denali_hynix_1x_micron_120s;
+ } else if (gddr6_vendor == GDDR6_MICRON && gddr6_revision == 1) {
+ gddr6_name = "Micron 130s";
+ param = autoservo_param_b_eiger_denali_hynix_1y_micron_130s;
+ } else {
+ pr_info("FanServo: %s Unknown Vendor/Revision 0x%x/0x%x\n", board_name, gddr6_vendor, gddr6_revision);
+ goto not_updated;
+ }
+ } else if (board_mask_b == BOARD_D_EIGER_DENALI_1 || board_mask_b == BOARD_D_EIGER_DENALI_2) {
+ board_name = "D-Eiger/Denali";
+ if (gddr6_vendor == GDDR6_SAMSUNG && gddr6_revision == 9) {
+ gddr6_name = "Samsung D1z";
+ param = autoservo_param_d_eiger_denali_samsung_d1z;
+ } else if (gddr6_vendor == GDDR6_HYNIX && gddr6_revision == 1) {
+ gddr6_name = "Hynix 1y";
+ param = autoservo_param_d_eiger_denali_hynix_1y;
+ } else if (gddr6_vendor == GDDR6_MICRON && gddr6_revision == 1) {
+ gddr6_name = "Micron 130s";
+ param = autoservo_param_d_eiger_denali_micron_130s_y31j;
+ } else if (gddr6_vendor == GDDR6_MICRON && gddr6_revision == 2) {
+ gddr6_name = "Micron Y31J";
+ param = autoservo_param_d_eiger_denali_micron_130s_y31j;
+ } else {
+ pr_info("FanServo: %s Unknown Vendor/Revision 0x%x/0x%x\n", board_name, gddr6_vendor, gddr6_revision);
+ goto not_updated;
+ }
+ } else {
+ pr_info("FanServo: 0x%016llX\n", board_id);
+ goto not_updated;
+ }
+
+ if (gddr6_name)
+ pr_info("FanServo: %s %s\n", board_name, gddr6_name);
+ else
+ pr_info("FanServo: %s\n", board_name);
+
+ if (!param)
+ goto not_updated;
+
+ ret = icc_fan_update_param(param);
+ if (ret)
+ pr_err("Error: %s: %d\n", __func__, ret);
+
+ return ret;
+
+not_updated:
+ pr_info("FanServo: Not update\n");
+ return 0;
+}
+EXPORT_SYMBOL(icc_fan_update_autoservo_param);
+
+static int icc_fan_txn(u8 svc, u16 mt, u16 len,
+ const u8 *data, size_t dlen,
+ u8 *reply_out, size_t rlen)
+{
+ u8 *buf;
+ struct icc_msg *msg;
+ int ret;
+
+ buf = kzalloc(ICC_MSG_MAX_SIZE, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+ msg = (struct icc_msg *)buf;
+
+ msg->service_id = svc;
+ msg->msg_type = mt;
+ msg->length = len;
+ if (data && dlen)
+ memcpy(msg->data, data, dlen);
+
+ ret = icc_query(buf, buf);
+ if (!ret && reply_out && rlen)
+ memcpy(reply_out, msg->data, rlen);
+
+ kfree(buf);
+ return ret;
+}
+
+static int icc_fan_get_curset(u8 zone, u32 out[PS5_CURSET_COUNT])
+{
+ u8 req[ICC_MSG_MAX_SIZE - sizeof(struct icc_msg)] = {};
+ u8 reply[ICC_MSG_MIN_SIZE] = {};
+ int ret, i;
+
+ req[PS5_FAN_ZONE_OFF] = zone;
+
+ ret = icc_fan_txn(ICC_SERVICE_ID_FAN, PS5_FAN_MT_CURSET_GET,
+ PS5_FAN_CURSET_GET_LEN, req, sizeof(req),
+ reply, sizeof(reply));
+ if (ret)
+ return ret;
+
+ for (i = 0; i < PS5_CURSET_COUNT; i++)
+ out[i] = get_unaligned_le32(reply +
+ PS5_FAN_CURSET_GET_OFF + i * 4);
+ return 0;
+}
+
+static int icc_fan_set_curset(u8 zone, u8 config, const u32 in[PS5_CURSET_COUNT])
+{
+ u8 req[ICC_MSG_MAX_SIZE - sizeof(struct icc_msg)] = {};
+ int i;
+
+ req[PS5_FAN_ZONE_OFF] = zone;
+ req[PS5_FAN_CONFIG_OFF] = config;
+ for (i = 0; i < PS5_CURSET_COUNT; i++)
+ put_unaligned_le32(in[i], req + PS5_FAN_CURSET_SET_OFF + i * 4);
+
+ return icc_fan_txn(ICC_SERVICE_ID_FAN, PS5_FAN_MT_CURSET_SET,
+ PS5_FAN_CURSET_SET_LEN, req, sizeof(req), NULL, 0);
+}
+
+static DEFINE_MUTEX(fan_lock);
+
+static int fan_get_target_temp(u8 zone, u16 *celsius)
+{
+ u32 cs[PS5_CURSET_COUNT];
+ int ret;
+
+ mutex_lock(&fan_lock);
+ ret = icc_fan_get_curset(zone, cs);
+ mutex_unlock(&fan_lock);
+ if (ret)
+ return ret;
+
+ *celsius = cs[PS5_CURSET_TARGETTEMP] >> PS5_TARGETTEMP_SHIFT;
+ return 0;
+}
+
+static int fan_set_target_temp(u8 zone, u8 config, u16 celsius)
+{
+ u32 cs[PS5_CURSET_COUNT];
+ int ret;
+
+ mutex_lock(&fan_lock);
+ ret = icc_fan_get_curset(zone, cs);
+ if (!ret) {
+ cs[PS5_CURSET_TARGETTEMP] = (u32)celsius << PS5_TARGETTEMP_SHIFT;
+ ret = icc_fan_set_curset(zone, config, cs);
+ }
+ mutex_unlock(&fan_lock);
+ return ret;
+}
+
+static ssize_t target_temp_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ u16 c;
+ int ret = fan_get_target_temp(PS5_ZONE_MAINSOC, &c);
+
+ if (ret)
+ return ret;
+ return sysfs_emit(buf, "%u\n", c);
+}
+
+static ssize_t target_temp_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ u16 c;
+ int ret;
+
+ if (kstrtou16(buf, 10, &c))
+ return -EINVAL;
+ if (c > 100)
+ return -ERANGE;
+
+ ret = fan_set_target_temp(PS5_ZONE_MAINSOC, 0, c);
+ return ret ? ret : count;
+}
+static DEVICE_ATTR_RW(target_temp);
+
+static struct attribute *ps5_fan_attrs[] = {
+ &dev_attr_target_temp.attr,
+ NULL,
+};
+ATTRIBUTE_GROUPS(ps5_fan);
+
+static int ps5_fan_probe(struct platform_device *pdev)
+{
+ int ret = icc_fan_update_autoservo_param();
+
+ if (ret)
+ dev_warn(&pdev->dev, "autoservo param load failed: %d\n", ret);
+
+ ret = fan_set_target_temp(PS5_ZONE_MAINSOC, 0, PS5_FAN_BOOT_TARGET_TEMP);
+ if (ret)
+ dev_warn(&pdev->dev, "boot target temp set failed: %d\n", ret);
+
+ return 0;
+}
+
+static struct platform_driver ps5_fan_driver = {
+ .probe = ps5_fan_probe,
+ .driver = {
+ .name = "ps5-fan",
+ .dev_groups = ps5_fan_groups,
+ },
+};
+
+static struct platform_device *ps5_fan_pdev;
+
+static int __init ps5_fan_init(void)
+{
+ int ret = platform_driver_register(&ps5_fan_driver);
+
+ if (ret)
+ return ret;
+
+ ps5_fan_pdev = platform_device_register_simple("ps5-fan", -1, NULL, 0);
+ if (IS_ERR(ps5_fan_pdev)) {
+ ret = PTR_ERR(ps5_fan_pdev);
+ platform_driver_unregister(&ps5_fan_driver);
+ ps5_fan_pdev = NULL;
+ return ret;
+ }
+ return 0;
+}
+
+static void __exit ps5_fan_exit(void)
+{
+ if (ps5_fan_pdev)
+ platform_device_unregister(ps5_fan_pdev);
+ platform_driver_unregister(&ps5_fan_driver);
+}
+
+module_init(ps5_fan_init);
+module_exit(ps5_fan_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("PS5 fan driver");
+MODULE_ALIAS("platform:ps5-fan");
diff --git a/drivers/ps5/hdmi.c b/drivers/ps5/hdmi.c
new file mode 100644
index 000000000000..67871f238abe
--- /dev/null
+++ b/drivers/ps5/hdmi.c
@@ -0,0 +1,1239 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/module.h>
+#include <linux/ps5.h>
+#include <drm/drm_edid.h>
+
+#define HDMI_IC_TYPE_FLAVA3 2
+#define HDMI_IC_TYPE_VERDE 3
+
+struct icc_i2c_msg {
+ u8 code;
+ u16 length;
+ u8 count;
+ u8 data[];
+} __packed;
+
+struct i2c_cmd_hdr {
+ u8 major;
+ u8 length;
+ u8 minor;
+ u8 count;
+ u8 data[];
+} __packed;
+
+struct i2c_cmd_2_1 {
+ u8 length;
+ u8 reg_high;
+ u8 reg_low;
+ u8 data[];
+} __packed;
+
+struct i2c_cmd_write {
+ u8 length;
+ u8 reg_high;
+ u8 reg_low;
+ u8 data[];
+} __packed;
+
+struct i2c_cmd_mask {
+ u8 length;
+ u8 reg_high;
+ u8 reg_low;
+ u8 value;
+ u8 mask[];
+} __packed;
+
+struct i2c_cmd_delay {
+ u8 length;
+ u8 time_low;
+ u8 time_high;
+ u8 unk_03;
+} __packed;
+
+struct i2c_cmd_waitset {
+ u8 length;
+ u8 reg_high;
+ u8 reg_low;
+ u8 value;
+} __packed;
+
+struct i2c_cmd_waitclear {
+ u8 length;
+ u8 reg_high;
+ u8 reg_low;
+ u8 value;
+} __packed;
+
+struct i2c_cmd_3_5 {
+ u8 length;
+ u8 reg_high;
+ u8 reg_low;
+ u8 value;
+} __packed;
+
+struct i2c_cmd_5_3 {
+ u8 value;
+} __packed;
+
+struct i2c_cmd_5_4 {
+ u8 value;
+} __packed;
+
+struct i2c_cmd_5_5 {
+ u8 value;
+} __packed;
+
+struct i2c_block {
+ u8 length;
+ u16 reg;
+ u8 data[32];
+};
+
+struct i2c_context {
+ struct i2c_block blocks[128];
+ int block_index;
+ u8 msg_buf[ICC_MSG_MAX_SIZE - sizeof(struct icc_msg)];
+ u8 *msg_cur;
+ struct icc_i2c_msg *msg_hdr;
+};
+
+static struct i2c_context i2c_ctx;
+
+static u8 hdmi_ic_type;
+static u8 tmds_polarity;
+static u8 tmds_ch_swap;
+static u8 dp_polarity;
+static u8 dp_ch_swap;
+
+static void i2c_init(u8 code)
+{
+ i2c_ctx.msg_cur = i2c_ctx.msg_buf;
+ i2c_ctx.msg_hdr = (struct icc_i2c_msg *)i2c_ctx.msg_cur;
+
+ i2c_ctx.msg_hdr->code = code;
+ i2c_ctx.msg_hdr->length = 0;
+ i2c_ctx.msg_hdr->count = 0;
+ i2c_ctx.block_index = -1;
+
+ i2c_ctx.msg_cur += sizeof(*i2c_ctx.msg_hdr);
+}
+
+static int i2c_exec(void)
+{
+ u8 buf[ICC_MSG_MAX_SIZE] = {};
+ struct icc_msg *msg = (struct icc_msg *)buf;
+ int ret;
+
+ i2c_ctx.msg_hdr->length = i2c_ctx.msg_cur - i2c_ctx.msg_buf;
+
+ msg->service_id = ICC_SERVICE_ID_HDMI;
+ msg->msg_type = 0;
+ msg->length = sizeof(*msg) + i2c_ctx.msg_hdr->length;
+ memcpy(msg->data, i2c_ctx.msg_hdr, i2c_ctx.msg_hdr->length);
+
+ ret = icc_query(buf, buf);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static void i2c_write_block(struct i2c_block *block, size_t count)
+{
+ struct i2c_cmd_hdr *hdr = (struct i2c_cmd_hdr *)i2c_ctx.msg_cur;
+ int i;
+
+ hdr->major = 2;
+ hdr->minor = 2;
+ hdr->count = count;
+ hdr->length = sizeof(*hdr);
+ i2c_ctx.msg_cur += sizeof(*hdr);
+
+ for (i = 0; i < count; i++) {
+ struct i2c_cmd_write *cmd = (struct i2c_cmd_write *)i2c_ctx.msg_cur;
+
+ cmd->length = block[i].length;
+ cmd->reg_low = block[i].reg & 0xff;
+ cmd->reg_high = block[i].reg >> 8;
+ memcpy(cmd->data, block[i].data, block[i].length);
+
+ i2c_ctx.msg_cur += sizeof(*cmd) + cmd->length;
+ hdr->length += sizeof(*cmd) + cmd->length;
+ }
+
+ i2c_ctx.msg_hdr->count++;
+}
+
+static void i2c_begin_block(void)
+{
+ i2c_ctx.block_index = 0;
+}
+
+static void i2c_end_block(void)
+{
+ if (i2c_ctx.block_index > 0)
+ i2c_write_block(i2c_ctx.blocks, i2c_ctx.block_index);
+ i2c_ctx.block_index = -1;
+}
+
+static void i2c_write_data(u16 reg, u8 value[], size_t count)
+{
+ struct i2c_block *block;
+ bool new_block = i2c_ctx.block_index == -1;
+
+ if (new_block)
+ i2c_begin_block();
+
+ block = &i2c_ctx.blocks[i2c_ctx.block_index++];
+ block->reg = reg;
+ block->length = count;
+ memcpy(block->data, value, count);
+
+ if (new_block)
+ i2c_end_block();
+}
+
+static void i2c_write(u16 reg, u8 value)
+{
+ i2c_write_data(reg, &value, 1);
+}
+
+static void i2c_cmd_2_1(u16 reg, u8 unk)
+{
+ struct i2c_cmd_hdr *hdr = (struct i2c_cmd_hdr *)i2c_ctx.msg_cur;
+ hdr->major = 2;
+ hdr->minor = 1;
+ hdr->count = 1;
+ hdr->length = sizeof(*hdr);
+ i2c_ctx.msg_cur += sizeof(*hdr);
+
+ struct i2c_cmd_2_1 *cmd = (struct i2c_cmd_2_1 *)i2c_ctx.msg_cur;
+ cmd->length = 1;
+ cmd->reg_low = reg & 0xff;
+ cmd->reg_high = reg >> 8;
+ cmd->data[0] = unk;
+ i2c_ctx.msg_cur += sizeof(*cmd) + cmd->length;
+ hdr->length += sizeof(*cmd) + cmd->length;
+
+ i2c_ctx.msg_hdr->count++;
+}
+
+static void i2c_delay(u16 time)
+{
+ struct i2c_cmd_hdr *hdr = (struct i2c_cmd_hdr *)i2c_ctx.msg_cur;
+ hdr->major = 3;
+ hdr->minor = 1;
+ hdr->count = 1;
+ hdr->length = sizeof(*hdr);
+ i2c_ctx.msg_cur += sizeof(*hdr);
+
+ struct i2c_cmd_delay *cmd = (struct i2c_cmd_delay *)i2c_ctx.msg_cur;
+ cmd->length = 0;
+ cmd->time_low = time & 0xff;
+ cmd->time_high = time >> 8;
+ cmd->unk_03 = 0;
+ i2c_ctx.msg_cur += sizeof(*cmd) + cmd->length;
+ hdr->length += sizeof(*cmd) + cmd->length;
+
+ i2c_ctx.msg_hdr->count++;
+}
+
+static void i2c_mask(u16 reg, u8 value, u8 mask)
+{
+ struct i2c_cmd_hdr *hdr = (struct i2c_cmd_hdr *)i2c_ctx.msg_cur;
+ hdr->major = 2;
+ hdr->minor = 3;
+ hdr->count = 1;
+ hdr->length = sizeof(*hdr);
+ i2c_ctx.msg_cur += sizeof(*hdr);
+
+ struct i2c_cmd_mask *cmd = (struct i2c_cmd_mask *)i2c_ctx.msg_cur;
+ cmd->length = 1;
+ cmd->reg_low = reg & 0xff;
+ cmd->reg_high = reg >> 8;
+ cmd->value = value;
+ cmd->mask[0] = mask;
+ i2c_ctx.msg_cur += sizeof(*cmd) + cmd->length;
+ hdr->length += sizeof(*cmd) + cmd->length;
+
+ i2c_ctx.msg_hdr->count++;
+}
+
+static void i2c_waitset(u16 reg, u8 value)
+{
+ struct i2c_cmd_hdr *hdr = (struct i2c_cmd_hdr *)i2c_ctx.msg_cur;
+ hdr->major = 3;
+ hdr->minor = 2;
+ hdr->count = 1;
+ hdr->length = sizeof(*hdr);
+ i2c_ctx.msg_cur += sizeof(*hdr);
+
+ struct i2c_cmd_waitset *cmd = (struct i2c_cmd_waitset *)i2c_ctx.msg_cur;
+ cmd->length = 0;
+ cmd->reg_low = reg & 0xff;
+ cmd->reg_high = reg >> 8;
+ cmd->value = value;
+ i2c_ctx.msg_cur += sizeof(*cmd) + cmd->length;
+ hdr->length += sizeof(*cmd) + cmd->length;
+
+ i2c_ctx.msg_hdr->count++;
+}
+
+static void i2c_waitclear(u16 reg, u8 value)
+{
+ struct i2c_cmd_hdr *hdr = (struct i2c_cmd_hdr *)i2c_ctx.msg_cur;
+ hdr->major = 3;
+ hdr->minor = 3;
+ hdr->count = 1;
+ hdr->length = sizeof(*hdr);
+ i2c_ctx.msg_cur += sizeof(*hdr);
+
+ struct i2c_cmd_waitclear *cmd = (struct i2c_cmd_waitclear *)i2c_ctx.msg_cur;
+ cmd->length = 0;
+ cmd->reg_low = reg & 0xff;
+ cmd->reg_high = reg >> 8;
+ cmd->value = value;
+ i2c_ctx.msg_cur += sizeof(*cmd) + cmd->length;
+ hdr->length += sizeof(*cmd) + cmd->length;
+
+ i2c_ctx.msg_hdr->count++;
+}
+
+static void i2c_cmd_3_5(u16 reg, u8 value)
+{
+ struct i2c_cmd_hdr *hdr = (struct i2c_cmd_hdr *)i2c_ctx.msg_cur;
+ hdr->major = 3;
+ hdr->minor = 5;
+ hdr->count = 1;
+ hdr->length = sizeof(*hdr);
+ i2c_ctx.msg_cur += sizeof(*hdr);
+
+ struct i2c_cmd_3_5 *cmd = (struct i2c_cmd_3_5 *)i2c_ctx.msg_cur;
+ cmd->length = 0;
+ cmd->reg_low = reg & 0xff;
+ cmd->reg_high = reg >> 8;
+ cmd->value = value;
+ i2c_ctx.msg_cur += sizeof(*cmd) + cmd->length;
+ hdr->length += sizeof(*cmd) + cmd->length;
+
+ i2c_ctx.msg_hdr->count++;
+}
+
+static void i2c_cmd_4_16(void *data, size_t size)
+{
+ struct i2c_cmd_hdr *hdr = (struct i2c_cmd_hdr *)i2c_ctx.msg_cur;
+ hdr->major = 4;
+ hdr->minor = 16;
+ hdr->count = 1;
+ hdr->length = sizeof(*hdr);
+ i2c_ctx.msg_cur += sizeof(*hdr);
+
+ memcpy(i2c_ctx.msg_cur, data, size);
+ i2c_ctx.msg_cur += size;
+ hdr->length += size;
+
+ i2c_ctx.msg_hdr->count++;
+}
+
+static void i2c_cmd_5_3(u8 unk)
+{
+ struct i2c_cmd_hdr *hdr = (struct i2c_cmd_hdr *)i2c_ctx.msg_cur;
+ hdr->major = 5;
+ hdr->minor = 3;
+ hdr->count = 1;
+ hdr->length = sizeof(*hdr);
+ i2c_ctx.msg_cur += sizeof(*hdr);
+
+ struct i2c_cmd_5_3 *cmd = (struct i2c_cmd_5_3 *)i2c_ctx.msg_cur;
+ cmd->value = unk;
+ i2c_ctx.msg_cur += sizeof(*cmd);
+ hdr->length += sizeof(*cmd);
+
+ i2c_ctx.msg_hdr->count++;
+}
+
+static void i2c_cmd_5_4(u8 event)
+{
+ struct i2c_cmd_hdr *hdr = (struct i2c_cmd_hdr *)i2c_ctx.msg_cur;
+ hdr->major = 5;
+ hdr->minor = 4;
+ hdr->count = 1;
+ hdr->length = sizeof(*hdr);
+ i2c_ctx.msg_cur += sizeof(*hdr);
+
+ struct i2c_cmd_5_4 *cmd = (struct i2c_cmd_5_4 *)i2c_ctx.msg_cur;
+ cmd->value = event;
+ i2c_ctx.msg_cur += sizeof(*cmd);
+ hdr->length += sizeof(*cmd);
+
+ i2c_ctx.msg_hdr->count++;
+}
+
+static void i2c_cmd_5_5(u8 event)
+{
+ struct i2c_cmd_hdr *hdr = (struct i2c_cmd_hdr *)i2c_ctx.msg_cur;
+ hdr->major = 5;
+ hdr->minor = 5;
+ hdr->count = 1;
+ hdr->length = sizeof(*hdr);
+ i2c_ctx.msg_cur += sizeof(*hdr);
+
+ struct i2c_cmd_5_5 *cmd = (struct i2c_cmd_5_5 *)i2c_ctx.msg_cur;
+ cmd->value = event;
+ i2c_ctx.msg_cur += sizeof(*cmd);
+ hdr->length += sizeof(*cmd);
+
+ i2c_ctx.msg_hdr->count++;
+}
+
+static int stopHdcpHw(void)
+{
+ u8 buf[ICC_MSG_MAX_SIZE] = {};
+ struct icc_msg *msg = (struct icc_msg *)buf;
+
+ msg->service_id = ICC_SERVICE_ID_GENERAL;
+ msg->msg_type = 0x1f;
+ msg->length = ICC_MSG_MIN_SIZE;
+
+ return icc_query(buf, buf);
+}
+
+static void sceSetBackToUnpluggedSequence(void)
+{
+ static u8 data[] = {0x11, 0x51, 0x09, 0x00, 0x02, 0x09, 0x03, 0x01, 0x01, 0x70, 0x5f, 0x80, 0x80, 0x03, 0x08, 0x01, 0x01, 0x00, 0x32, 0x00, 0x00, 0x02, 0x09, 0x03, 0x01, 0x01, 0x7a, 0x88, 0xff, 0xff, 0x03, 0x08, 0x03, 0x01, 0x00, 0x7a, 0x84, 0x01, 0x02, 0x09, 0x03, 0x01, 0x01, 0x74, 0x0a, 0xff, 0xff, 0x03, 0x08, 0x03, 0x01, 0x00, 0x74, 0x0a, 0xff, 0x02, 0x09, 0x03, 0x01, 0x01, 0x74, 0x19, 0x05, 0x07, 0x02, 0x09, 0x03, 0x01, 0x01, 0x7a, 0x8b, 0x00, 0x07, 0x03, 0x08, 0x01, 0x01, 0x00, 0x32, 0x00, 0x00};
+ i2c_init(0);
+ i2c_cmd_4_16(data, sizeof(data));
+ i2c_exec();
+}
+
+static void sceSetBackToWaitResolutionSequence(void)
+{
+ static u8 data[] = {0x12, 0x47, 0x08, 0x00, 0x02, 0x09, 0x03, 0x01, 0x01, 0x70, 0x5f, 0x80, 0x80, 0x02, 0x08, 0x02, 0x01, 0x01, 0x7a, 0x88, 0xff, 0x03, 0x08, 0x03, 0x01, 0x00, 0x7a, 0x84, 0x01, 0x02, 0x08, 0x02, 0x01, 0x01, 0x74, 0x0a, 0xff, 0x03, 0x08, 0x03, 0x01, 0x00, 0x74, 0x0a, 0xff, 0x02, 0x09, 0x03, 0x01, 0x01, 0x74, 0x19, 0x05, 0x07, 0x02, 0x09, 0x03, 0x01, 0x01, 0x7a, 0x8b, 0x00, 0x07, 0x03, 0x08, 0x01, 0x01, 0x00, 0x64, 0x00, 0x00};
+ i2c_init(0);
+ i2c_cmd_4_16(data, sizeof(data));
+ i2c_exec();
+}
+
+static void i2c_cmd_4_2(void)
+{
+ static u8 data[] = {0x31, 0x7a, 0xb8, 0x08, 0x32, 0x7a, 0xb0, 0x05, 0x33, 0x7a, 0xa0, 0x05, 0x34, 0x7a, 0xe1, 0x01, 0x35, 0x7a, 0xe2, 0x01, 0x36, 0x7a, 0xe0, 0x01, 0x37, 0x7c, 0x00, 0x05};
+
+ i2c_init(0);
+
+ struct i2c_cmd_hdr *hdr = (struct i2c_cmd_hdr *)i2c_ctx.msg_cur;
+ hdr->major = 4;
+ hdr->minor = 2;
+ hdr->count = 7;
+ hdr->length = sizeof(*hdr);
+ i2c_ctx.msg_cur += sizeof(*hdr);
+
+ memcpy(i2c_ctx.msg_cur, data, sizeof(data));
+ i2c_ctx.msg_cur += sizeof(data);
+ hdr->length += sizeof(data);
+
+ i2c_ctx.msg_hdr->count++;
+
+ i2c_exec();
+}
+
+static void sceSetHdcpSequence1st(void)
+{
+ static u8 data[] = {0x0b, 0x91, 0x0f, 0x00, 0x02, 0x0c, 0x02, 0x02, 0x01, 0x7a, 0x8b, 0x05, 0x01, 0x7a, 0x88, 0xff, 0x03, 0x08, 0x03, 0x01, 0x00, 0x7a, 0x84, 0x01, 0x02, 0x11, 0x02, 0x03, 0x02, 0x10, 0xe5, 0xff, 0xff, 0x01, 0x7a, 0x85, 0x00, 0x01, 0x7a, 0x83, 0x84, 0x03, 0x08, 0x02, 0x01, 0x00, 0x7a, 0x84, 0xa0, 0x03, 0x08, 0x03, 0x01, 0x00, 0x7a, 0x84, 0x01, 0x02, 0x08, 0x01, 0x01, 0x01, 0x7a, 0x83, 0x83, 0x03, 0x08, 0x02, 0x01, 0x00, 0x7a, 0x84, 0xa0, 0x03, 0x08, 0x03, 0x01, 0x00, 0x7a, 0x84, 0x01, 0x03, 0x08, 0x01, 0x01, 0x00, 0x0f, 0x00, 0x00, 0x02, 0x08, 0x01, 0x01, 0x01, 0x7a, 0x83, 0x84, 0x03, 0x08, 0x02, 0x01, 0x00, 0x7a, 0x84, 0xa0, 0x03, 0x08, 0x03, 0x01, 0x00, 0x7a, 0x84, 0x01, 0x02, 0x10, 0x02, 0x03, 0x01, 0x10, 0xe6, 0xff, 0x01, 0x7a, 0x85, 0x00, 0x01, 0x7a, 0x83, 0xe3, 0x03, 0x08, 0x02, 0x01, 0x00, 0x7a, 0x84, 0xa0, 0x03, 0x08, 0x03, 0x01, 0x00, 0x7a, 0x84, 0x01};
+
+ i2c_init(0);
+ i2c_cmd_4_16(data, sizeof(data));
+ i2c_exec();
+}
+
+static void sceSetHdcpSequence2nd(void)
+{
+ static u8 data[] = {0x0c, 0x39, 0x06, 0x00, 0x02, 0x0d, 0x02, 0x02, 0x02, 0x10, 0xe5, 0xff, 0xff, 0x01, 0x7a, 0x83, 0xdc, 0x03, 0x08, 0x02, 0x01, 0x00, 0x7a, 0x84, 0xa0, 0x03, 0x08, 0x03, 0x01, 0x00, 0x7a, 0x84, 0x01, 0x02, 0x08, 0x01, 0x01, 0x01, 0x7a, 0x83, 0xc4, 0x03, 0x08, 0x02, 0x01, 0x00, 0x7a, 0x84, 0xa0, 0x03, 0x08, 0x03, 0x01, 0x00, 0x7a, 0x84, 0x01};
+ i2c_init(0);
+ i2c_cmd_4_16(data, sizeof(data));
+ i2c_exec();
+}
+
+static void sceSetHdcpSequence3rd(void)
+{
+ static u8 data[] = {0x0d, 0x21, 0x01, 0x00, 0x02, 0x1d, 0x02, 0x06, 0x01, 0x10, 0xe7, 0xff, 0x01, 0x7a, 0x8b, 0x03, 0x02, 0x10, 0xe5, 0xff, 0xff, 0x01, 0x7a, 0x9d, 0x4f, 0x01, 0x7a, 0x83, 0x8e, 0x01, 0x7e, 0x03, 0x10};
+ i2c_init(0);
+ i2c_cmd_4_16(data, sizeof(data));
+ i2c_exec();
+}
+
+static void sceSetEdidSequence(int sequence)
+{
+ static u8 seq_0[] = {0x04, 0x3f, 0x06, 0x00, 0x02, 0x0c, 0x02, 0x02, 0x01, 0x7a, 0x88, 0xff, 0x01, 0x7a, 0x83, 0x88, 0x03, 0x08, 0x02, 0x01, 0x00, 0x7a, 0x84, 0xa0, 0x03, 0x08, 0x03, 0x01, 0x00, 0x7a, 0x84, 0x01, 0x02, 0x0f, 0x02, 0x02, 0x01, 0x7a, 0x9c, 0x0e, 0x04, 0x7a, 0x80, 0x00, 0x00, 0x7f, 0x82, 0x03, 0x08, 0x02, 0x01, 0x00, 0x7a, 0x84, 0xa0, 0x03, 0x08, 0x03, 0x01, 0x00, 0x7a, 0x84, 0x01};
+ static u8 seq_1[] = {0x05, 0x3f, 0x06, 0x00, 0x02, 0x0c, 0x02, 0x02, 0x01, 0x7a, 0x88, 0xff, 0x01, 0x7a, 0x83, 0x88, 0x03, 0x08, 0x02, 0x01, 0x00, 0x7a, 0x84, 0xa0, 0x03, 0x08, 0x03, 0x01, 0x00, 0x7a, 0x84, 0x01, 0x02, 0x0f, 0x02, 0x02, 0x01, 0x7a, 0x9c, 0x0e, 0x04, 0x7a, 0x80, 0x00, 0x80, 0x7f, 0x82, 0x03, 0x08, 0x02, 0x01, 0x00, 0x7a, 0x84, 0xa0, 0x03, 0x08, 0x03, 0x01, 0x00, 0x7a, 0x84, 0x01};
+ static u8 seq_2[] = {0x06, 0x3f, 0x06, 0x00, 0x02, 0x0c, 0x02, 0x02, 0x01, 0x7a, 0x88, 0xff, 0x01, 0x7a, 0x83, 0x88, 0x03, 0x08, 0x02, 0x01, 0x00, 0x7a, 0x84, 0xa0, 0x03, 0x08, 0x03, 0x01, 0x00, 0x7a, 0x84, 0x01, 0x02, 0x0f, 0x02, 0x02, 0x01, 0x7a, 0x9c, 0x0e, 0x04, 0x7a, 0x80, 0x01, 0x00, 0x7f, 0x82, 0x03, 0x08, 0x02, 0x01, 0x00, 0x7a, 0x84, 0xa0, 0x03, 0x08, 0x03, 0x01, 0x00, 0x7a, 0x84, 0x01};
+ static u8 seq_3[] = {0x07, 0x3f, 0x06, 0x00, 0x02, 0x0c, 0x02, 0x02, 0x01, 0x7a, 0x88, 0xff, 0x01, 0x7a, 0x83, 0x88, 0x03, 0x08, 0x02, 0x01, 0x00, 0x7a, 0x84, 0xa0, 0x03, 0x08, 0x03, 0x01, 0x00, 0x7a, 0x84, 0x01, 0x02, 0x0f, 0x02, 0x02, 0x01, 0x7a, 0x9c, 0x0e, 0x04, 0x7a, 0x80, 0x01, 0x80, 0x7f, 0x82, 0x03, 0x08, 0x02, 0x01, 0x00, 0x7a, 0x84, 0xa0, 0x03, 0x08, 0x03, 0x01, 0x00, 0x7a, 0x84, 0x01};
+
+ i2c_init(0);
+ if (sequence == 0) {
+ i2c_cmd_4_16(seq_0, sizeof(seq_0));
+ } else if (sequence == 1) {
+ i2c_cmd_4_16(seq_1, sizeof(seq_1));
+ } else if (sequence == 2) {
+ i2c_cmd_4_16(seq_2, sizeof(seq_2));
+ } else if (sequence == 3) {
+ i2c_cmd_4_16(seq_3, sizeof(seq_3));
+ }
+ i2c_exec();
+}
+
+static void sceSetWaitPllSequence(void)
+{
+ static u8 data[] = {0x0a, 0x15, 0x02, 0x00, 0x02, 0x09, 0x03, 0x01, 0x01, 0x70, 0x21, 0xff, 0xff, 0x03, 0x08, 0x01, 0x01, 0x00, 0x64, 0x00, 0x00};
+ i2c_init(0);
+ i2c_cmd_4_16(data, sizeof(data));
+ i2c_exec();
+}
+
+static void unk_akv(void)
+{
+ i2c_init(4);
+ i2c_begin_block();
+ i2c_write(0x7006, 0x12);
+ i2c_write(0x7a88, 0xff);
+ i2c_end_block();
+ i2c_waitclear(0x7a84, 0x01);
+ i2c_cmd_2_1(0x7a83, 0x88);
+ i2c_waitset(0x7a84, 0xa0);
+ i2c_waitclear(0x7a84, 0x01);
+ i2c_begin_block();
+ i2c_write(0x7a8b, 0x05);
+ i2c_write(0x7a89, 0x01);
+ i2c_end_block();
+ i2c_delay(20);
+ i2c_cmd_2_1(0x7a83, 0x0e);
+ i2c_waitset(0x7a84, 0xa0);
+ i2c_exec();
+}
+
+static void sceControlHdmiEvent(u8 enable)
+{
+ i2c_init(4);
+ i2c_cmd_5_4(enable);
+ i2c_exec();
+}
+
+void hdmiSystemResume(void)
+{
+ // sceSetBackToUnpluggedSequence();
+ // sceSetBackToWaitResolutionSequence();
+ if (hdmi_ic_type == HDMI_IC_TYPE_FLAVA3) {
+ i2c_cmd_4_2();
+ // sceSetHdcpSequence1st();
+ // sceSetHdcpSequence2nd();
+ // sceSetHdcpSequence3rd();
+ sceSetEdidSequence(0);
+ sceSetEdidSequence(1);
+ sceSetEdidSequence(2);
+ sceSetEdidSequence(3);
+ sceSetWaitPllSequence();
+ unk_akv();
+ }
+ sceControlHdmiEvent(1);
+}
+EXPORT_SYMBOL(hdmiSystemResume);
+
+static void sceDisableEncode(void)
+{
+ i2c_init(4);
+ i2c_mask(0x705f, 0x80, 0x80);
+ i2c_cmd_5_3(0x00);
+ i2c_mask(0x7021, 0x00, 0xf0);
+ i2c_cmd_2_1(0x7a88, 0xff);
+ i2c_waitclear(0x7a84, 0x01);
+ i2c_cmd_2_1(0x740a, 0xff);
+ i2c_waitclear(0x740a, 0xff);
+ i2c_mask(0x7419, 0x05, 0x07);
+ i2c_mask(0x7a8b, 0x00, 0x07);
+ i2c_delay(100);
+ i2c_exec();
+}
+
+static void initIsrForFlava3(void)
+{
+ i2c_init(0);
+ i2c_begin_block();
+ i2c_write(0x705f, 0x12);
+ i2c_write(0x6004, 0x80);
+ i2c_write(0x6020, 0x00);
+ i2c_write(0x7007, 0xff);
+ i2c_write(0x100c, 0x01);
+ i2c_write(0x6008, 0xc0);
+ i2c_write(0x6207, 0x00);
+ i2c_write(0x621b, 0x00);
+ i2c_write_data(0x6080, (u8[]){0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, 6);
+ i2c_write_data(0x6090, (u8[]){0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, 8);
+ i2c_write_data(0x10e7, (u8[]){0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, 8);
+ i2c_write_data(0x10e9, (u8[]){0xff, 0xff}, 2);
+ i2c_write_data(0x10f0, (u8[]){0xff, 0x07, 0x00, 0x0f, 0x00, 0x56, 0x00, 0x00, 0xd0, 0x00}, 10);
+ i2c_write(0x7018, (tmds_polarity == 1) << 1);
+ i2c_end_block();
+ if (tmds_ch_swap == 1) {
+ i2c_mask(0x701a, 0xb1, 0xff);
+ }
+ i2c_exec();
+}
+
+static void initDpForFlava3(void)
+{
+ i2c_init(0);
+ i2c_begin_block();
+ i2c_write(0x6a03, 0x04);
+ i2c_write(0x60a2, 0xf1);
+ i2c_write(0x60bf, 0x03);
+ i2c_write(0x60c0, 0xef);
+ i2c_write(0x60c3, 0x4d);
+ i2c_write(0x60c7, 0x85);
+ i2c_write(0x60bf, 0x04);
+ i2c_write(0x60c7, 0x84);
+ if (dp_polarity != 0xff) {
+ i2c_write(0x600e, dp_polarity << 4);
+ }
+ if (dp_ch_swap != 0xff) {
+ i2c_write(0x600b, dp_ch_swap);
+ }
+ i2c_write_data(0x6220, (u8[]){0x40, 0x00, 0x80, 0x00, 0x00, 0x01, 0x02}, 7);
+ i2c_write_data(0x6028, (u8[]){0x01, 0x02}, 2);
+ i2c_write_data(0x6058, (u8[]){0x01, 0x02, 0x03, 0x04}, 4);
+ i2c_write(0x62af, 0x01);
+ i2c_write(0x6207, 0x00);
+ i2c_write(0x621b, 0x00);
+ i2c_write(0x60e0, 0x1e);
+ i2c_write(0x603c, 0x04);
+ i2c_write(0x100e, 0x10);
+ i2c_end_block();
+ i2c_delay(2);
+ i2c_write(0x6005, 0x01);
+ i2c_delay(2);
+ i2c_write(0x6008, 0x00);
+ i2c_exec();
+}
+
+static void configVSyncSettingFlava3(void)
+{
+ i2c_init(1);
+ i2c_begin_block();
+ i2c_write(0x1047, 0x00);
+ i2c_write(0x6064, 0x01);
+ i2c_write_data(0x600c, (u8[]){0x01, 0x00}, 2);
+ i2c_write(0x6c07, 0x00);
+ i2c_write_data(0x7214, (u8[]){0x00, 0x00}, 2);
+ i2c_end_block();
+ i2c_exec();
+}
+
+static void configParamFlava3Pre(void)
+{
+ i2c_init(1);
+ i2c_begin_block();
+ i2c_write_data(0x6224, (u8[]){0x00, 0x01}, 2);
+ i2c_write_data(0x1047, (u8[]){0x00}, 1);
+ i2c_write_data(0x1050, (u8[]){0x00, 0x00, 0x00, 0x00}, 4);
+ i2c_write(0x7215, 0x00);
+ i2c_write(0x7077, 0x00);
+ i2c_write(0x7079, 0x80);
+ i2c_end_block();
+ i2c_exec();
+}
+
+static void configLinkTrainingFlava3(void)
+{
+ i2c_init(1);
+ i2c_begin_block();
+ i2c_write_data(0x600c, (u8[]){0x01, 0x00}, 2);
+ i2c_write_data(0x6c00, (u8[]){0x1e, 0x84, 0x00}, 3);
+ i2c_end_block();
+ i2c_mask(0x6005, 0x01, 0x01);
+ i2c_delay(2);
+ i2c_mask(0x6006, 0x04, 0x04);
+ i2c_delay(2);
+ i2c_write(0x6a03, 0x47);
+ i2c_delay(10);
+ i2c_waitset(0x60f8, 0xff);
+ i2c_waitset(0x60f9, 0x01);
+ i2c_write(0x6a01, 0x4d);
+ i2c_waitset(0x60f9, 0x1a);
+ i2c_waitset(0x6083, 0x02);
+ i2c_exec();
+}
+
+static void initHdmiPhyForFlava3_1st(void)
+{
+ i2c_init(0);
+ i2c_begin_block();
+ i2c_write(0x7022, 0x03);
+ i2c_write(0x7030, 0x40);
+ i2c_write_data(0x7024, (u8[]){0x04, 0x54}, 2);
+ i2c_write(0x7030, 0x41);
+ i2c_write_data(0x7024, (u8[]){0x04, 0x54}, 2);
+ i2c_write(0x7030, 0x42);
+ i2c_write_data(0x7024, (u8[]){0x04, 0x34}, 2);
+ i2c_write(0x7030, 0x43);
+ i2c_write_data(0x7024, (u8[]){0x04, 0x34}, 2);
+ i2c_write(0x7030, 0x04);
+ i2c_write_data(0x7024, (u8[]){0x04, 0x71}, 2);
+ i2c_write(0x7030, 0x14);
+ i2c_write(0x7025, 0x71);
+ i2c_write(0x7030, 0x24);
+ i2c_write(0x7025, 0x70);
+ i2c_write(0x7030, 0x34);
+ i2c_write(0x7025, 0x77);
+ i2c_write(0x7030, 0x05);
+ i2c_write_data(0x7024, (u8[]){0x04, 0x71}, 2);
+ i2c_write(0x7030, 0x15);
+ i2c_write(0x7025, 0x71);
+ i2c_write(0x7030, 0x25);
+ i2c_write(0x7025, 0x70);
+ i2c_write(0x7030, 0x35);
+ i2c_write(0x7025, 0x77);
+ i2c_write(0x7030, 0x06);
+ i2c_write_data(0x7024, (u8[]){0x04, 0x71}, 2);
+ i2c_write(0x7030, 0x16);
+ i2c_write(0x7025, 0x70);
+ i2c_write(0x7030, 0x26);
+ i2c_write(0x7025, 0x70);
+ i2c_write(0x7030, 0x36);
+ i2c_write(0x7025, 0x77);
+ i2c_end_block();
+ i2c_exec();
+}
+
+static void initHdmiPhyForFlava3_2nd(void)
+{
+ i2c_init(0);
+ i2c_begin_block();
+ i2c_write(0x7030, 0x47);
+ i2c_write(0x7024, 0x04);
+ i2c_write(0x7025, 0x37);
+ i2c_write(0x7027, 0x17);
+ i2c_write(0x7030, 0x37);
+ i2c_write(0x7025, 0x71);
+ i2c_write(0x7027, 0x14);
+ i2c_write(0x7030, 0x48);
+ i2c_write(0x7024, 0x04);
+ i2c_write(0x7025, 0x37);
+ i2c_write(0x7027, 0x17);
+ i2c_write(0x7030, 0x38);
+ i2c_write(0x7025, 0x77);
+ i2c_write(0x7027, 0x14);
+ i2c_write(0x7030, 0x49);
+ i2c_write(0x7024, 0x01);
+ i2c_write(0x7030, 0x19);
+ i2c_write(0x7026, 0xcc);
+ i2c_write(0x7030, 0x29);
+ i2c_write(0x7026, 0xdd);
+ i2c_write(0x7030, 0x39);
+ i2c_write(0x7026, 0xef);
+ i2c_write(0x7030, 0x4a);
+ i2c_write(0x7024, 0x01);
+ i2c_write(0x7030, 0x1a);
+ i2c_write(0x7026, 0xcc);
+ i2c_write(0x7030, 0x2a);
+ i2c_write(0x7026, 0xdd);
+ i2c_write(0x7030, 0x3a);
+ i2c_write(0x7026, 0xef);
+ i2c_write(0x7030, 0x4b);
+ i2c_write(0x7024, 0x01);
+ i2c_write(0x7030, 0x1b);
+ i2c_write(0x7026, 0xcc);
+ i2c_write(0x7030, 0x2b);
+ i2c_write(0x7026, 0xdd);
+ i2c_write(0x7030, 0x3b);
+ i2c_write(0x7026, 0xef);
+ i2c_end_block();
+ i2c_exec();
+}
+
+static void mask_7203(void)
+{
+ i2c_init(1);
+ i2c_mask(0x7203, 0x00, 0x80);
+ i2c_exec();
+}
+
+static void setHdmiBasicVideoConfigFlava3(const struct drm_display_mode *mode)
+{
+ u8 vic = drm_match_cea_mode(mode);
+ int hz = drm_mode_vrefresh(mode);
+
+ i2c_init(1);
+ i2c_mask(0x7021, 0x00, 0xf0);
+ i2c_delay(500);
+ i2c_begin_block();
+ i2c_write(0x100c, 0x01);
+ i2c_write_data(0x68a0, (u8[]){0x96, 0x04}, 2);
+ i2c_write(0x7005, 0x80);
+ i2c_write(0x7019, 0x00);
+ i2c_write(0x100c, 0x01);
+ i2c_write(0x7005, 0x80);
+ i2c_write(0x7009, 0x00);
+ i2c_write(0x7040, 0x42);
+ i2c_write(0x7225, 0x28);
+ if (vic == 16 || vic == 63) {
+ /* Set VIC and content type */
+ i2c_write_data(0x7227, (u8[]){vic, 0x00}, 2);
+ i2c_write_data(0x7070, (u8[]){vic, vic, 0x00, 0x00, 0x00, 0x00}, 6);
+ } else if (mode->hdisplay == 2560 && mode->vdisplay == 1440) {
+ /* Set VIC and content type */
+ i2c_write_data(0x7227, (u8[]){0x04, 0x00}, 2);
+ i2c_write_data(0x7070, (u8[]){0x00, 0x00, 0x00, 0x00, 0x00, 0xfb}, 6);
+ } else if (vic == 97) {
+ /* Set VIC and content type */
+ i2c_write_data(0x7227, (u8[]){0x06, 0x00}, 2);
+ i2c_write_data(0x7070, (u8[]){0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 6);
+ }
+ i2c_write(0x70c0, 0xdc);
+ i2c_write(0x621b, 0x00);
+ i2c_write(0x629a, 0x00);
+ i2c_write_data(0x70c4, (u8[]){0x08, 0x08}, 2);
+ i2c_write(0x70c2, 0x00);
+ i2c_write(0x70fe, 0x02);
+ i2c_write(0x70c3, 0x00);
+ i2c_write(0x7018, (tmds_polarity == 1) << 1);
+ if (tmds_ch_swap == 1) {
+ i2c_end_block();
+ i2c_mask(0x701a, 0xb1, 0xff);
+ i2c_begin_block();
+ }
+ i2c_write(0x10e7, 0xff);
+ i2c_write(0x7202, 0x20);
+ if (vic == 97) {
+ i2c_write(0x7072, 0x01);
+ i2c_write(0x7074, 0x07);
+ i2c_write(0x7206, 0x80);
+ i2c_write(0x7203, 0x60);
+ i2c_write(0x7011, 0xff);
+ } else {
+ i2c_write(0x7203, 0x60);
+ i2c_write(0x7011, 0xd5);
+ }
+ i2c_end_block();
+ i2c_waitclear(0x7011, 0xff);
+ i2c_exec();
+}
+
+static void setVideoAdditionalConfigFlava3(const struct drm_display_mode *mode)
+{
+ u8 vic = drm_match_cea_mode(mode);
+
+ i2c_init(1);
+ i2c_waitset(0x10e7, 0x80);
+ if (vic == 97) {
+ /* Set VIC */
+ i2c_mask(0x7227, vic, 0xff);
+ }
+ /* Enable IT content */
+ i2c_mask(0x7226, 1 << 7, 0x80);
+ /* Set content type (game) */
+ i2c_mask(0x7228, 3 << 4, 0x30);
+ i2c_write(0x7204, 0x40);
+ i2c_waitclear(0x7204, 0x40);
+ i2c_delay(10);
+ i2c_begin_block();
+ if (vic == 97) {
+ i2c_write(0x7019, 0x01);
+ } else {
+ i2c_write(0x7019, 0x00);
+ }
+ i2c_write(0x7419, 0x05);
+ i2c_write(0x740a, 0xff);
+ i2c_end_block();
+ i2c_waitclear(0x740a, 0xff);
+ i2c_begin_block();
+ i2c_write(0x7404, 0x00);
+ i2c_write(0x7a88, 0xff);
+ i2c_end_block();
+ i2c_waitclear(0x7a84, 0x01);
+ i2c_begin_block();
+ i2c_write(0x7a8b, 0x05);
+ if (vic == 97) {
+ i2c_write(0x7c00, 0x03);
+ i2c_write_data(0x7a80, (u8[]){0xa8, 0x20, 0x00, 0x80}, 4);
+ }
+ i2c_end_block();
+ if (vic == 97) {
+ i2c_waitclear(0x7a84, 0x01);
+ }
+ i2c_begin_block();
+ i2c_write(0x7021, 0xff);
+ i2c_write(0x700a, 0x02);
+ i2c_write(0x705f, 0x80);
+ i2c_end_block();
+ i2c_delay(700);
+ i2c_write(0x7a8b, 0x00);
+ i2c_cmd_5_3(0x01);
+ i2c_exec();
+}
+
+static void setHdmiVideoConfigFlava3(const struct drm_display_mode *mode)
+{
+ configParamFlava3Pre();
+ configLinkTrainingFlava3();
+ setHdmiBasicVideoConfigFlava3(mode);
+ initHdmiPhyForFlava3_1st();
+ initHdmiPhyForFlava3_2nd();
+ mask_7203();
+ setVideoAdditionalConfigFlava3(mode);
+}
+
+static void setHdmiAudioConfigBasic(int channels)
+{
+ i2c_init(2);
+ i2c_begin_block();
+ i2c_write(0x62a0, 0x06);
+ i2c_write(0x62a7, 0x13);
+ i2c_write(0x62ac, 0x82);
+ i2c_write(0x62cb, 0x02);
+ i2c_write(0x62cb, 0x03);
+ i2c_write(0x62cb, 0x00);
+ i2c_write(0x70ad, 0x00);
+ i2c_write(0x70af, 0x07);
+ i2c_write(0x70a9, 0x5e);
+ i2c_end_block();
+ i2c_mask(0x70af, 0x06, 0x06);
+ i2c_mask(0x70b3, 0x02, 0x0f);
+ i2c_mask(0x70ae, 0x80, 0xe0);
+ i2c_mask(0x70ae, max(1, channels - 1), 0x07);
+ i2c_mask(0x70ac, 0x01, 0x21);
+ i2c_mask(0x70ab, 0x81, 0x89);
+ i2c_mask(0x70a9, 0x08, 0x08);
+ i2c_exec();
+}
+
+static void setAudioConfigAdditional(int channels)
+{
+ u8 val = 0x00;
+ switch (channels) {
+ case 3: val = 0x02; break;
+ case 4: val = 0x03; break;
+ case 5: val = 0x09; break;
+ case 6: val = 0x0b; break;
+ case 7: val = 0x11; break;
+ case 8: val = 0x13; break;
+ }
+ i2c_init(2);
+ i2c_mask(0x70b0, 0x00, 0xff);
+ i2c_mask(0x70b1, 0x79, 0xff);
+ i2c_mask(0x70b2, 0x00, 0xff);
+ i2c_mask(0x70b3, 0x02, 0xff);
+ i2c_mask(0x70b4, 0x0b, 0x0f);
+ i2c_mask(0x70b5, 0x00, 0xff);
+ i2c_mask(0x70b6, 0x00, 0xff);
+ i2c_begin_block();
+ i2c_write(0x10e7, 0xff);
+ i2c_write(0x7011, 0xa2);
+ i2c_end_block();
+ i2c_waitset(0x10e7, 0xa2);
+ i2c_mask(0x7267, val, 0xff);
+ i2c_write(0x7204, 0x10);
+ i2c_waitclear(0x7204, 0x10);
+ i2c_write(0x10e7, 0xff);
+ i2c_mask(0x7203, 0x10, 0x10);
+ i2c_delay(30);
+ i2c_write(0x70a8, 0xc0);
+ i2c_exec();
+}
+
+static void sceHdmiSetAudioConfigFlava3(int channels)
+{
+ setHdmiAudioConfigBasic(channels);
+ setAudioConfigAdditional(channels);
+}
+
+static void initVerde(void)
+{
+ i2c_init(0);
+ i2c_mask(0x105, 0x00, 0x03);
+ i2c_mask(0x104, 0x00, 0x02);
+ i2c_cmd_2_1(0x400, 0x00);
+ i2c_cmd_2_1(0x3261, 0x02);
+ i2c_begin_block();
+ i2c_write(0x11, 0x03);
+ i2c_write(0x13, 0xff);
+ i2c_write_data(0x8000, (u8[]){0x00, 0x01, 0x07, 0x00}, 4);
+ i2c_write(0x108, 0x80);
+ i2c_write(0x9000, 0x01);
+ i2c_end_block();
+ i2c_cmd_5_3(0x00);
+ i2c_exec();
+}
+
+static void linkConfigVerde(const struct drm_display_mode *mode)
+{
+ i2c_init(0);
+ i2c_mask(0x105, 0x00, 0x40);
+ if (mode->hdisplay == 2560 && mode->vdisplay == 1440) {
+ i2c_cmd_2_1(0x400, 0x03);
+ }
+ i2c_begin_block();
+ i2c_write_data(0x9003, (u8[]){0x1e, 0x04, 0x01, 0x01, 0x00, 0x00, 0x00}, 7);
+ i2c_write(0x4002, 0x03);
+ i2c_end_block();
+ i2c_exec();
+}
+
+static void configDpLinkTrainingVerde(void)
+{
+ i2c_init(0);
+ i2c_cmd_2_1(0x9002, 0x01);
+ i2c_waitset(0x4001, 0x02);
+ i2c_cmd_2_1(0x11, 0x01);
+ i2c_exec();
+}
+
+static void setTmdsConfigVerde(void)
+{
+ i2c_init(0);
+ i2c_cmd_2_1(0x9200, 0x00);
+ i2c_begin_block();
+ i2c_write(0x9800, 0x00);
+ i2c_write(0x33b3, 0x1a);
+ i2c_write(0x9831, 0x80);
+ i2c_write_data(0x9810, (u8[]){0x00, 0x79, 0x00, 0x02, 0x0b, 0x00, 0x00}, 7);
+ i2c_end_block();
+ i2c_waitclear(0x9830, 0x80);
+ i2c_cmd_2_1(0x9830, 0x80);
+ i2c_waitclear(0x9830, 0x80);
+ i2c_cmd_2_1(0x9830, 0x81);
+ i2c_waitclear(0x9830, 0x80);
+ i2c_waitclear(0x108, 0x10);
+ i2c_mask(0x108, 0x11, 0x17);
+ i2c_waitset(0x13, 0x40);
+ i2c_cmd_2_1(0x13, 0x40);
+ i2c_cmd_3_5(0x4001, 0x03);
+ i2c_cmd_2_1(0x11, 0x01);
+ i2c_exec();
+}
+
+static void setHdmiBasicVideoConfigVerde(const struct drm_display_mode *mode)
+{
+ u8 vic = drm_match_cea_mode(mode);
+
+ i2c_init(0);
+ i2c_begin_block();
+ if (vic == 16) {
+ i2c_write_data(0x3058, (u8[]){0x02, 0x0d, 0xef, 0x00, 0x28, 0x08, 0x10, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 18);
+ } else if (mode->hdisplay == 2560 && mode->vdisplay == 1440) {
+ i2c_write_data(0x3058, (u8[]){0x02, 0x0d, 0xff, 0x00, 0x28, 0x08, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 18);
+ } else if (vic == 97) {
+ i2c_write_data(0x3058, (u8[]){0x02, 0x0d, 0x9e, 0x00, 0x28, 0x08, 0x61, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 18);
+ }
+ i2c_write_data(0x31d0, (u8[]){0x01, 0x19, 0x5f, 0x53, 0x43, 0x45, 0x49, 0x00, 0x00, 0x00, 0x00, 0x50, 0x53, 0x35, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08}, 28);
+ i2c_end_block();
+ i2c_begin_block();
+ i2c_write_data(0x3033, (u8[]){0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 9);
+ i2c_write_data(0x307a, (u8[]){0x01, 0x0a, 0x70, 0x01, 0x00, 0x00, 0x00, 0x00}, 8);
+ i2c_write_data(0x3000, (u8[]){0x56, 0xaa, 0x00, 0x24, 0x00, 0xa8, 0x00, 0x00, 0x08, 0x80}, 10);
+ i2c_end_block();
+ i2c_cmd_2_1(0x300a, 0x01);
+ i2c_waitclear(0x300c, 0xf3);
+ i2c_waitclear(0x300d, 0xff);
+ i2c_waitclear(0x300e, 0xff);
+ i2c_waitclear(0x300f, 0xff);
+ i2c_waitclear(0x3010, 0xff);
+ i2c_waitclear(0x3011, 0xff);
+ i2c_waitset(0x13, 0x80);
+ i2c_cmd_2_1(0x13, 0x80);
+ i2c_mask(0x105, 0x01, 0x03);
+ i2c_delay(700);
+ i2c_cmd_5_3(0x01);
+ i2c_exec();
+}
+
+static void setHdmiVideoConfigVerde(const struct drm_display_mode *mode)
+{
+ linkConfigVerde(mode);
+ configDpLinkTrainingVerde();
+ setTmdsConfigVerde();
+ setHdmiBasicVideoConfigVerde(mode);
+}
+
+static void setAudioConfigForVerde(int channels)
+{
+ i2c_init(2);
+ i2c_waitclear(0x102, 0x80);
+ i2c_cmd_2_1(0xf1, 0x01);
+ i2c_waitset(0xf2, 0x01);
+ i2c_waitset(0x16, 0x08);
+ i2c_cmd_2_1(0x16, 0x08);
+ i2c_begin_block();
+ i2c_write(0x9800, 0x00);
+ i2c_write(0x33b3, 0x1a);
+ i2c_write(0x9831, 0x80);
+ i2c_write_data(0x9810, (u8[]){0x00, 0x79, 0x00, 0x02, 0x0b, 0x00, 0x00}, 7);
+ i2c_end_block();
+ i2c_waitclear(0x9830, 0x80);
+ i2c_cmd_2_1(0x9830, 0x80);
+ i2c_waitclear(0x9830, 0x80);
+ i2c_cmd_2_1(0x9830, 0x81);
+ i2c_waitclear(0x9830, 0x80);
+ i2c_waitclear(0x108, 0x10);
+ i2c_mask(0x108, 0x10, 0x10);
+ i2c_waitclear(0x108, 0x10);
+ i2c_write_data(0x307a, (u8[]){0x01, 0x0a, 0x70, 0x01, 0x00, 0x00, 0x00, 0x00}, 8);
+ i2c_mask(0x3000, 0x40, 0xc0);
+ i2c_mask(0x3005, 0x80, 0xc0);
+ i2c_cmd_2_1(0x300a, 0x01);
+ i2c_waitset(0x13, 0x80);
+ i2c_cmd_2_1(0x13, 0x80);
+ i2c_exec();
+}
+
+static void sceHdmiSetAudioConfigVerde(int channels)
+{
+ setAudioConfigForVerde(channels);
+}
+
+void sceHdmiInitVideoConfig(void)
+{
+ stopHdcpHw();
+ if (hdmi_ic_type == HDMI_IC_TYPE_FLAVA3) {
+ sceDisableEncode();
+ initIsrForFlava3();
+ initDpForFlava3();
+ configVSyncSettingFlava3();
+ } else {
+ initVerde();
+ }
+}
+EXPORT_SYMBOL(sceHdmiInitVideoConfig);
+
+void sceHdmiSetVideoConfig(const struct drm_display_mode *mode)
+{
+ if (hdmi_ic_type == HDMI_IC_TYPE_FLAVA3) {
+ setHdmiVideoConfigFlava3(mode);
+ } else {
+ setHdmiVideoConfigVerde(mode);
+ }
+}
+EXPORT_SYMBOL(sceHdmiSetVideoConfig);
+
+void sceHdmiDeviceSetVideoMute(int mute)
+{
+ i2c_init(4);
+ if (hdmi_ic_type == HDMI_IC_TYPE_FLAVA3) {
+ i2c_write(0x705f, (mute == 1) << 7);
+ } else {
+ i2c_mask(0x105, mute != 1, 0x03);
+ }
+ i2c_exec();
+}
+EXPORT_SYMBOL(sceHdmiDeviceSetVideoMute);
+
+void sceHdmiSetAudioConfig(int channels)
+{
+ if (hdmi_ic_type == HDMI_IC_TYPE_FLAVA3) {
+ sceHdmiSetAudioConfigFlava3(channels);
+ } else {
+ sceHdmiSetAudioConfigVerde(channels);
+ }
+}
+EXPORT_SYMBOL(sceHdmiSetAudioConfig);
+
+void sceHdmiSetAudioMute(int mute)
+{
+ i2c_init(4);
+ if (hdmi_ic_type == HDMI_IC_TYPE_FLAVA3) {
+ i2c_mask(0x70a8, (mute == 1) << 2, 0x04);
+ } else {
+ i2c_cmd_5_5(mute == 1);
+ }
+ i2c_exec();
+}
+EXPORT_SYMBOL(sceHdmiSetAudioMute);
+
+void sceHdmiOutputMode(void)
+{
+ i2c_init(4);
+ if (hdmi_ic_type == HDMI_IC_TYPE_FLAVA3) {
+ i2c_write(0x7005, 0x80);
+ }
+ i2c_exec();
+}
+EXPORT_SYMBOL(sceHdmiOutputMode);
+
+int getHdmiConfiguration(void)
+{
+ u8 buf[ICC_MSG_MAX_SIZE] = {};
+ struct icc_msg *msg = (struct icc_msg *)buf;
+ int ret;
+
+ msg->service_id = ICC_SERVICE_ID_GENERAL;
+ msg->msg_type = 0x16;
+ msg->length = ICC_MSG_MIN_SIZE;
+ msg->data[0] = 0x10;
+
+ ret = icc_query(buf, buf);
+ if (ret)
+ return ret;
+
+ hdmi_ic_type = (msg->data[0x3] == 1) | 2;
+ tmds_polarity = msg->data[0x4] == 1;
+ tmds_ch_swap = msg->data[0x5] == 1;
+ dp_polarity = msg->data[0x6];
+ dp_ch_swap = msg->data[0x7];
+
+ pr_info("HDMI IC Type [%s]\n", hdmi_ic_type == HDMI_IC_TYPE_FLAVA3 ? "FLAVA3" : "VERDE");
+ pr_info("TMDS Polarity [%s]\n", tmds_polarity ? "Reverse" : "Normal");
+ pr_info("TMDS Ch Swap [%s]\n", tmds_ch_swap ? "Swap" : "Normal");
+ pr_info("DP Polarity [0x%x]\n", dp_polarity);
+ pr_info("DP Ch Swap [0x%x]\n", dp_ch_swap);
+
+ return 0;
+}
+EXPORT_SYMBOL(getHdmiConfiguration);
+
+bool isHdmiModeValid(const struct drm_display_mode *mode, int force_1080p)
+{
+ u8 vic = drm_match_cea_mode(mode);
+
+ if (force_1080p)
+ return vic == 16; /* 1080p60 */
+
+ /* 1440p */
+ if (mode->hdisplay == 2560 && mode->vdisplay == 1440) {
+ return mode->clock == 241500 || mode->clock == 241700;
+ }
+
+ switch (vic) {
+ case 16: /* 1080p60 */
+ case 63: /* 1080p120 */
+ case 97: /* 2160p60 */
+ return true;
+ }
+
+ return false;
+}
+EXPORT_SYMBOL(isHdmiModeValid);
+
+const struct drm_edid *real_edid = NULL;
+
+static void fix_edid(u8 *edid)
+{
+ int i;
+ u32 sum = 0;
+
+ /* For some reason, PS5 sets 0x01. */
+ edid[0] = 0x00;
+ for (i = 0; i < 0x7f; i++)
+ sum += edid[i];
+ edid[0x7f] = -sum & 0xff;
+}
+
+void hdmi_notification_handler(struct icc_msg *msg)
+{
+ if (msg->data[1] == 0x02) {
+ fix_edid(&msg->data[4]);
+ real_edid = drm_edid_alloc(&msg->data[4], *(u16 *)&msg->data[2]);
+ pr_info("got real edid\n");
+ sceHdmiOutputMode();
+ }
+}
+EXPORT_SYMBOL(hdmi_notification_handler);
diff --git a/drivers/ps5/led.h b/drivers/ps5/led.h
new file mode 100644
index 000000000000..a1a205147478
--- /dev/null
+++ b/drivers/ps5/led.h
@@ -0,0 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef _PS5_LED_H
+#define _PS5_LED_H
+
+#include <linux/types.h>
+
+int ps5_led_set_raw(u8 blue, u8 white, u8 orange);
+int ps5_led_set_preset(const char *name);
+
+#endif
diff --git a/drivers/ps5/led/Makefile b/drivers/ps5/led/Makefile
new file mode 100644
index 000000000000..38cfacb315b2
--- /dev/null
+++ b/drivers/ps5/led/Makefile
@@ -0,0 +1 @@
+obj-y += core.o presets.o
diff --git a/drivers/ps5/led/core.c b/drivers/ps5/led/core.c
new file mode 100644
index 000000000000..796cc0edc859
--- /dev/null
+++ b/drivers/ps5/led/core.c
@@ -0,0 +1,158 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include <linux/module.h>
+#include <linux/leds.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/ps5.h>
+#include "../led.h"
+#include "presets.h"
+
+static const u8 ps5_led_off_payload[] = {
+ 0x03, 0x00, 0x00, 0x00,
+ 0x10, 0x01, 0x02, 0x00, 0x05, 0x04, 0x00,
+ 0x11, 0x01, 0x02, 0x00, 0x05, 0x04, 0x00,
+ 0x12, 0x01, 0x02, 0x00, 0x05, 0x04, 0x00,
+};
+
+struct ps5_led_node {
+ struct led_classdev cdev;
+ const u8 *payload;
+ size_t size;
+};
+
+static DEFINE_MUTEX(ps5_led_lock);
+static const u8 *ps5_led_current;
+
+static int ps5_led_brightness_set(struct led_classdev *cdev,
+ enum led_brightness value)
+{
+ struct ps5_led_node *node =
+ container_of(cdev, struct ps5_led_node, cdev);
+ const u8 *data = (value == LED_OFF) ? ps5_led_off_payload : node->payload;
+ size_t size = (value == LED_OFF) ? sizeof(ps5_led_off_payload) : node->size;
+ int ret;
+
+ if (!spcie_is_initialized())
+ return -ENODEV;
+
+ mutex_lock(&ps5_led_lock);
+
+ if (ps5_led_current == data) {
+ mutex_unlock(&ps5_led_lock);
+ return 0;
+ }
+
+ if (value != LED_OFF)
+ icc_indicator_set_led(ps5_led_off_payload,
+ sizeof(ps5_led_off_payload));
+
+ ret = icc_indicator_set_led(data, size);
+ if (!ret)
+ ps5_led_current = data;
+
+ mutex_unlock(&ps5_led_lock);
+ return ret;
+}
+
+int ps5_led_set_raw(u8 blue, u8 white, u8 orange)
+{
+ u8 buf[25];
+
+ if (!spcie_is_initialized())
+ return -ENODEV;
+
+ if (!blue && !white && !orange)
+ return icc_indicator_set_led(ps5_led_off_payload,
+ sizeof(ps5_led_off_payload));
+
+ buf[0] = 0x03; buf[1] = 0x00; buf[2] = 0x00; buf[3] = 0x00;
+ buf[4] = 0x10; buf[5] = 0x01; buf[6] = 0x02; buf[7] = blue;
+ buf[8] = 0x05; buf[9] = 0x03; buf[10] = 0x00;
+ buf[11] = 0x11; buf[12] = 0x01; buf[13] = 0x02; buf[14] = white;
+ buf[15] = 0x05; buf[16] = 0x03; buf[17] = 0x00;
+ buf[18] = 0x12; buf[19] = 0x01; buf[20] = 0x02; buf[21] = orange;
+ buf[22] = 0x05; buf[23] = 0x03; buf[24] = 0x00;
+
+ return icc_indicator_set_led(buf, sizeof(buf));
+}
+EXPORT_SYMBOL(ps5_led_set_raw);
+
+static int ps5_led_probe(struct platform_device *pdev)
+{
+ size_t i;
+ int ret;
+
+ for (i = 0; i < ps5_num_presets; i++) {
+ struct ps5_led_node *node;
+ char *name;
+
+ node = devm_kzalloc(&pdev->dev, sizeof(*node), GFP_KERNEL);
+ if (!node)
+ return -ENOMEM;
+
+ name = devm_kasprintf(&pdev->dev, GFP_KERNEL,
+ "ps5:%s:indicator",
+ ps5_presets[i].name);
+ if (!name)
+ return -ENOMEM;
+
+ node->payload = ps5_presets[i].data;
+ node->size = ps5_presets[i].size;
+ node->cdev.name = name;
+ node->cdev.max_brightness = 255;
+ node->cdev.brightness_set_blocking = ps5_led_brightness_set;
+ node->cdev.flags = LED_CORE_SUSPENDRESUME;
+
+ ret = devm_led_classdev_register(&pdev->dev, &node->cdev);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static struct platform_driver ps5_led_driver = {
+ .probe = ps5_led_probe,
+ .driver = {
+ .name = "ps5-led",
+ },
+};
+
+static struct platform_device *ps5_led_pdev;
+
+static int __init ps5_led_init(void)
+{
+ int ret;
+
+ ret = platform_driver_register(&ps5_led_driver);
+ if (ret)
+ return ret;
+
+ ps5_led_pdev = platform_device_register_simple("ps5-led", -1,
+ NULL, 0);
+ if (IS_ERR(ps5_led_pdev)) {
+ ret = PTR_ERR(ps5_led_pdev);
+ platform_driver_unregister(&ps5_led_driver);
+ ps5_led_pdev = NULL;
+ return ret;
+ }
+
+ return 0;
+}
+
+static void __exit ps5_led_exit(void)
+{
+ if (ps5_led_pdev)
+ platform_device_unregister(ps5_led_pdev);
+ platform_driver_unregister(&ps5_led_driver);
+}
+
+module_init(ps5_led_init);
+module_exit(ps5_led_exit);
+
+MODULE_AUTHOR("Armandas Kvietkus <armandas.kvietkus@proton.me>");
+MODULE_DESCRIPTION("PlayStation 5 indicator LED driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:ps5-led");
diff --git a/drivers/ps5/led/presets.c b/drivers/ps5/led/presets.c
new file mode 100644
index 000000000000..218da5ecb31e
--- /dev/null
+++ b/drivers/ps5/led/presets.c
@@ -0,0 +1,300 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/ps5.h>
+#include "../led.h"
+#include "presets.h"
+
+
+static const u8 payload_off[] = {
+ 0x03, 0x00, 0x00, 0x00,
+ 0x10, 0x01, 0x02, 0x00, 0x05, 0x04, 0x00,
+ 0x11, 0x01, 0x02, 0x00, 0x05, 0x04, 0x00,
+ 0x12, 0x01, 0x02, 0x00, 0x05, 0x04, 0x00,
+};
+
+static const u8 payload_white_dim[] = {
+ 0x01, 0x00, 0x00, 0x00,
+ 0x11, 0x01, 0x02, 0x20, 0x05, 0x03, 0x00,
+};
+
+static const u8 payload_white_medium[] = {
+ 0x01, 0x00, 0x00, 0x00,
+ 0x11, 0x01, 0x02, 0x5f, 0x05, 0x03, 0x00,
+};
+
+static const u8 payload_white_bright[] = {
+ 0x01, 0x00, 0x00, 0x00,
+ 0x11, 0x01, 0x02, 0xff, 0x05, 0x03, 0x00,
+};
+
+static const u8 payload_blue_rich[] = {
+ 0x01, 0x00, 0x00, 0x00,
+ 0x10, 0x01, 0x02, 0xff, 0x05, 0x03, 0x00,
+};
+
+static const u8 payload_orange_dim[] = {
+ 0x01, 0x00, 0x00, 0x00,
+ 0x12, 0x01, 0x02, 0xff, 0x05, 0x03, 0x00,
+};
+
+static const u8 payload_soft_blue_purple_1[] = {
+ 0x03, 0x00, 0x00, 0x00,
+ 0x10, 0x01, 0x02, 0xff, 0x05, 0x03, 0x00,
+ 0x11, 0x01, 0x02, 0x40, 0x05, 0x03, 0x00,
+ 0x12, 0x01, 0x02, 0x20, 0x05, 0x03, 0x00,
+};
+
+static const u8 payload_soft_blue_purple_2[] = {
+ 0x03, 0x00, 0x00, 0x00,
+ 0x10, 0x01, 0x02, 0xff, 0x05, 0x03, 0x00,
+ 0x11, 0x01, 0x02, 0xc0, 0x05, 0x03, 0x00,
+ 0x12, 0x01, 0x02, 0x00, 0x05, 0x03, 0x00,
+};
+
+static const u8 payload_salmon_pink[] = {
+ 0x02, 0x00, 0x00, 0x00,
+ 0x11, 0x01, 0x02, 0x30, 0x05, 0x03, 0x00,
+ 0x12, 0x01, 0x02, 0xff, 0x05, 0x03, 0x00,
+};
+
+static const u8 payload_pink_purple[] = {
+ 0x03, 0x00, 0x00, 0x00,
+ 0x10, 0x01, 0x02, 0x20, 0x05, 0x03, 0x00,
+ 0x11, 0x01, 0x02, 0x18, 0x05, 0x03, 0x00,
+ 0x12, 0x01, 0x02, 0xff, 0x05, 0x03, 0x00,
+};
+
+static const u8 payload_warm_pink_dim[] = {
+ 0x02, 0x00, 0x00, 0x00,
+ 0x10, 0x01, 0x02, 0x10, 0x05, 0x03, 0x00,
+ 0x12, 0x01, 0x02, 0xff, 0x05, 0x03, 0x00,
+};
+
+static const u8 payload_blue_hint_purple[] = {
+ 0x02, 0x00, 0x00, 0x00,
+ 0x10, 0x01, 0x02, 0x80, 0x05, 0x03, 0x00,
+ 0x12, 0x01, 0x02, 0xff, 0x05, 0x03, 0x00,
+};
+
+static const u8 payload_purple[] = {
+ 0x02, 0x00, 0x00, 0x00,
+ 0x10, 0x01, 0x02, 0x40, 0x05, 0x03, 0x00,
+ 0x12, 0x01, 0x02, 0xff, 0x05, 0x03, 0x00,
+};
+
+static const u8 payload_soft_purple[] = {
+ 0x02, 0x00, 0x00, 0x00,
+ 0x10, 0x01, 0x02, 0x50, 0x05, 0x03, 0x00,
+ 0x12, 0x01, 0x02, 0xff, 0x05, 0x03, 0x00,
+};
+
+static const u8 payload_pink_violet_dim[] = {
+ 0x02, 0x00, 0x00, 0x00,
+ 0x10, 0x01, 0x02, 0x20, 0x05, 0x03, 0x00,
+ 0x12, 0x01, 0x02, 0xff, 0x05, 0x03, 0x00,
+};
+
+static const u8 payload_purple_white[] = {
+ 0x03, 0x00, 0x00, 0x00,
+ 0x10, 0x01, 0x02, 0x40, 0x05, 0x03, 0x00,
+ 0x11, 0x01, 0x02, 0x20, 0x05, 0x03, 0x00,
+ 0x12, 0x01, 0x02, 0xff, 0x05, 0x03, 0x00,
+};
+
+static const u8 payload_soft_orange_dim[] = {
+ 0x02, 0x00, 0x00, 0x00,
+ 0x11, 0x01, 0x02, 0x20, 0x05, 0x03, 0x00,
+ 0x12, 0x01, 0x02, 0xff, 0x05, 0x03, 0x00,
+};
+
+static const u8 payload_purplish_blue_white[] = {
+ 0x02, 0x00, 0x00, 0x00,
+ 0x10, 0x01, 0x02, 0xff, 0x05, 0x03, 0x00,
+ 0x11, 0x01, 0x02, 0x80, 0x05, 0x03, 0x00,
+};
+
+static const u8 payload_dim_cool_white[] = {
+ 0x02, 0x00, 0x00, 0x00,
+ 0x10, 0x01, 0x02, 0x40, 0x05, 0x03, 0x00,
+ 0x11, 0x01, 0x02, 0x40, 0x05, 0x03, 0x00,
+};
+
+static const u8 payload_all_dim_purplish[] = {
+ 0x03, 0x00, 0x00, 0x00,
+ 0x10, 0x01, 0x02, 0x20, 0x05, 0x03, 0x00,
+ 0x11, 0x01, 0x02, 0x20, 0x05, 0x03, 0x00,
+ 0x12, 0x01, 0x02, 0x20, 0x05, 0x03, 0x00,
+};
+
+
+#define BREATHE_SLOW \
+ 0x00, 0x00, 0x00, 0x56, 0x00, 0x02, 0x02, 0x02, 0x04, 0x01, \
+ 0x02, 0x0e, 0x02, 0x03, 0x06, 0x02, 0x25, 0x04, 0x03, 0x05, \
+ 0x02, 0x6c, 0x05, 0x03, 0x0d, 0x02, 0xb9, 0x03, 0x02, 0x18, \
+ 0x02, 0xe7, 0x05, 0x04, 0x08, 0x02, 0xff, 0x03, 0x05, 0x08
+
+#define BREATHE_FAST \
+ 0x00, 0x00, 0x00, 0x20, 0x00, 0x02, 0x02, 0x02, 0x04, 0x01, \
+ 0x02, 0x0e, 0x02, 0x03, 0x06, 0x02, 0x25, 0x04, 0x03, 0x05, \
+ 0x02, 0x6c, 0x05, 0x03, 0x0d, 0x02, 0xb9, 0x03, 0x02, 0x18, \
+ 0x02, 0xe7, 0x05, 0x04, 0x08, 0x02, 0xff, 0x03, 0x05, 0x08
+
+static const u8 payload_blue_breathe[] = {
+ 0x03, 0x00, 0x00, 0x00,
+ 0x10, 0x08, BREATHE_SLOW,
+ 0x11, 0x01, 0x02, 0x00, 0x05, 0x03, 0x00,
+ 0x12, 0x01, 0x02, 0x00, 0x06, 0x02, 0x15,
+};
+
+static const u8 payload_white_breathe[] = {
+ 0x03, 0x00, 0x00, 0x00,
+ 0x11, 0x08, BREATHE_SLOW,
+ 0x10, 0x01, 0x02, 0x00, 0x05, 0x03, 0x00,
+ 0x12, 0x01, 0x02, 0x00, 0x06, 0x02, 0x15,
+};
+
+static const u8 payload_orange_breathe[] = {
+ 0x03, 0x00, 0x00, 0x00,
+ 0x12, 0x08, BREATHE_SLOW,
+ 0x10, 0x01, 0x02, 0x00, 0x05, 0x03, 0x00,
+ 0x11, 0x01, 0x02, 0x00, 0x06, 0x02, 0x15,
+};
+
+static const u8 payload_pink_breathe[] = {
+ 0x03, 0x00, 0x00, 0x00,
+ 0x12, 0x08, BREATHE_SLOW,
+ 0x10, 0x01, 0x02, 0x20, 0x05, 0x03, 0x00,
+ 0x11, 0x01, 0x02, 0x18, 0x06, 0x02, 0x15,
+};
+
+static const u8 payload_pink_breathe_fast[] = {
+ 0x03, 0x00, 0x00, 0x00,
+ 0x12, 0x08, BREATHE_FAST,
+ 0x10, 0x01, 0x02, 0x20, 0x05, 0x03, 0x00,
+ 0x11, 0x01, 0x02, 0x18, 0x06, 0x02, 0x15,
+};
+
+static const u8 payload_salmon_pink_breathe[] = {
+ 0x03, 0x00, 0x00, 0x00,
+ 0x12, 0x08, BREATHE_SLOW,
+ 0x10, 0x01, 0x02, 0x00, 0x05, 0x03, 0x00,
+ 0x11, 0x01, 0x02, 0x30, 0x06, 0x02, 0x15,
+};
+
+static const u8 payload_blue_to_richblue[] = {
+ 0x03, 0x00, 0x00, 0x00,
+ 0x10, 0x08, BREATHE_SLOW,
+ 0x11, 0x01, 0x02, 0x00, 0x05, 0x03, 0x00,
+ 0x12, 0x01, 0x02, 0xff, 0x06, 0x02, 0x15,
+};
+
+static const u8 payload_sunrise[] = {
+ 0x03, 0x00, 0x00, 0x00,
+ 0x11, 0x08, BREATHE_SLOW,
+ 0x10, 0x01, 0x02, 0x00, 0x05, 0x03, 0x00,
+ 0x12, 0x01, 0x02, 0x40, 0x06, 0x02, 0x15,
+};
+
+static const u8 payload_blue_white_anim[] = {
+ 0x02, 0x01, 0x00, 0x00,
+ 0x10, 0x03, 0x02, 0x2d, 0x01, 0x01, 0xd1, 0x02, 0x12, 0x03,
+ 0x05, 0x08, 0x02, 0x00, 0x02, 0x05, 0x08,
+ 0x11, 0x05, 0x02, 0x21, 0x01, 0x04, 0x20, 0x02, 0x58, 0x02,
+ 0x03, 0x1b, 0x02, 0xab, 0x05, 0x04, 0x10, 0x02, 0xe2, 0x05,
+ 0x05, 0x0b, 0x02, 0xff, 0x01, 0x02, 0x1d,
+};
+
+
+static const u8 payload_zoneb_white_pulse[] = {
+ 0x01, 0x01, 0x00, 0x00,
+ 0x01, 0x08, 0x02, 0xd3, 0x02, 0x02, 0x16, 0x02, 0x5b, 0x05,
+ 0x02, 0x18, 0x02, 0x18, 0x04, 0x02, 0x0f, 0x02, 0x11, 0x01,
+ 0x01, 0x06, 0x02, 0x0d, 0x01, 0x02, 0x03, 0x02, 0x12, 0x02,
+ 0x02, 0x02, 0x02, 0x42, 0x03, 0x01, 0x10, 0x02, 0xff, 0x0b,
+ 0x02, 0x11,
+};
+
+static const u8 payload_zoneb_orange_pulse[] = {
+ 0x01, 0x01, 0x00, 0x00,
+ 0x02, 0x08, 0x02, 0x18, 0x08, 0x03, 0x0d, 0x02, 0x11, 0x02,
+ 0x01, 0x03, 0x02, 0x0d, 0x01, 0x02, 0x03, 0x02, 0x12, 0x01,
+ 0x02, 0x04, 0x02, 0x41, 0x03, 0x01, 0x0e, 0x02, 0xff, 0x0e,
+ 0x02, 0x0d, 0x02, 0xd5, 0x04, 0x04, 0x09, 0x02, 0x80, 0x03,
+ 0x01, 0x1c,
+};
+
+static const u8 payload_zoneb_both_pulse[] = {
+ 0x02, 0x01, 0x00, 0x00,
+ 0x01, 0x08, 0x02, 0xd3, 0x02, 0x02, 0x16, 0x02, 0x5b, 0x05,
+ 0x02, 0x18, 0x02, 0x18, 0x04, 0x02, 0x0f, 0x02, 0x11, 0x01,
+ 0x01, 0x06, 0x02, 0x0d, 0x01, 0x02, 0x03, 0x02, 0x12, 0x02,
+ 0x02, 0x02, 0x02, 0x42, 0x03, 0x01, 0x10, 0x02, 0xff, 0x0b,
+ 0x02, 0x11,
+ 0x02, 0x08, 0x02, 0x18, 0x08, 0x03, 0x0d, 0x02, 0x11, 0x02,
+ 0x01, 0x03, 0x02, 0x0d, 0x01, 0x02, 0x03, 0x02, 0x12, 0x01,
+ 0x02, 0x04, 0x02, 0x41, 0x03, 0x01, 0x0e, 0x02, 0xff, 0x0e,
+ 0x02, 0x0d, 0x02, 0xd5, 0x04, 0x04, 0x09, 0x02, 0x80, 0x03,
+ 0x01, 0x1c,
+};
+
+
+#define PRESET(n) { .name = #n, .data = payload_##n, .size = sizeof(payload_##n) }
+
+const struct ps5_led_preset ps5_presets[] = {
+ PRESET(off),
+ PRESET(white_dim),
+ PRESET(white_medium),
+ PRESET(white_bright),
+ PRESET(blue_rich),
+ PRESET(orange_dim),
+ PRESET(soft_blue_purple_1),
+ PRESET(soft_blue_purple_2),
+ PRESET(salmon_pink),
+ PRESET(pink_purple),
+ PRESET(warm_pink_dim),
+ PRESET(blue_hint_purple),
+ PRESET(purple),
+ PRESET(soft_purple),
+ PRESET(pink_violet_dim),
+ PRESET(purple_white),
+ PRESET(soft_orange_dim),
+ PRESET(purplish_blue_white),
+ PRESET(dim_cool_white),
+ PRESET(all_dim_purplish),
+ PRESET(blue_breathe),
+ PRESET(white_breathe),
+ PRESET(orange_breathe),
+ PRESET(pink_breathe),
+ PRESET(pink_breathe_fast),
+ PRESET(salmon_pink_breathe),
+ PRESET(blue_to_richblue),
+ PRESET(sunrise),
+ PRESET(blue_white_anim),
+ PRESET(zoneb_white_pulse),
+ PRESET(zoneb_orange_pulse),
+ PRESET(zoneb_both_pulse),
+};
+
+const size_t ps5_num_presets = ARRAY_SIZE(ps5_presets);
+
+int ps5_led_set_preset(const char *name)
+{
+ size_t i;
+
+ if (!spcie_is_initialized())
+ return -ENODEV;
+
+ for (i = 0; i < ps5_num_presets; i++) {
+ if (!strcmp(ps5_presets[i].name, name)) {
+ if (i != 0)
+ icc_indicator_set_led(payload_off,
+ sizeof(payload_off));
+ return icc_indicator_set_led(ps5_presets[i].data,
+ ps5_presets[i].size);
+ }
+ }
+ return -EINVAL;
+}
+EXPORT_SYMBOL(ps5_led_set_preset);
diff --git a/drivers/ps5/led/presets.h b/drivers/ps5/led/presets.h
new file mode 100644
index 000000000000..a234788e9990
--- /dev/null
+++ b/drivers/ps5/led/presets.h
@@ -0,0 +1,16 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef _PS5_LED_PRESETS_H
+#define _PS5_LED_PRESETS_H
+
+#include <linux/types.h>
+
+struct ps5_led_preset {
+ const char *name;
+ const u8 *data;
+ size_t size;
+};
+
+extern const struct ps5_led_preset ps5_presets[];
+extern const size_t ps5_num_presets;
+
+#endif
diff --git a/drivers/ps5/mp1.c b/drivers/ps5/mp1.c
new file mode 100644
index 000000000000..3bd1375a444c
--- /dev/null
+++ b/drivers/ps5/mp1.c
@@ -0,0 +1,490 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/module.h>
+#include <linux/miscdevice.h>
+#include <linux/delay.h>
+#include <linux/smp.h>
+#include <linux/ps5.h>
+#include <asm/amd/node.h>
+
+#define MP1_IOC_MAGIC 'M'
+
+#define MP1_BOOST_ENTER _IO(MP1_IOC_MAGIC, 1)
+#define MP1_BOOST_EXIT _IO(MP1_IOC_MAGIC, 2)
+
+#define CPU_MHZ_MIN 3200
+#define CPU_MHZ_MAX 3500
+
+#define GPU_MHZ_MIN 2000
+#define GPU_MHZ_MAX 2230
+
+#define MSR_ACCESS_DIS BIT_ULL(62)
+
+#define MSR_DPM_CFG 0xC0011074
+#define MSR_DPM_WAC_ACC_INDEX 0xC0011076
+#define MSR_DPM_WAC_DATA 0xC0011077
+
+#define MP1_C2PMSG_56 0x3b109e0
+#define MP1_C2PMSG_57 0x3b109e4
+#define MP1_C2PMSG_58 0x3b109e8
+#define MP1_C2PMSG_59 0x3b109ec
+#define MP1_C2PMSG_66 0x3b10a08
+#define MP1_C2PMSG_72 0x3b10a20
+#define MP1_C2PMSG_81 0x3b10a44
+#define MP1_C2PMSG_82 0x3b10a48
+#define MP1_C2PMSG_90 0x3b10a68
+#define MP1_C2PMSG_96 0x3b10a80
+#define MP1_C2PMSG_98 0x3b10a88
+
+#define PPSMC_MSG_ConfigureS3PwrOffRegisterAddressHigh 0x16
+#define PPSMC_MSG_ConfigureS3PwrOffRegisterAddressLow 0x17
+#define PPSMC_MSG_UniversalModeEntry 0x22
+#define PPSMC_MSG_UniversalModeExit 0x23
+#define PPSMC_MSG_SleepEntry 0x24
+#define PPSMC_MSG_GfxCacWeightOperation 0x2F
+#define PPSMC_MSG_L3CacWeightOperation 0x30
+
+struct mp1_msg {
+ u32 arg;
+ u32 resp;
+ u32 resp_val;
+ u32 extra_arg;
+ u32 extra;
+};
+
+struct bapm_param_set {
+ u64 dpm_wac[21];
+ u32 l3_cacw[80];
+ u32 gfx_cacw[88];
+ u64 gfx_cacw_len;
+ u32 bapm_param[176][2];
+};
+
+static const struct bapm_param_set bapm_param_set_1 = {
+ .dpm_wac = {
+ 0x0000bca79c8d0000, 0x0097000000000000, 0x007f0000000000ad,
+ 0x00930000c700bb00, 0x000000e0cad5ee00, 0x0000c60099ca00d1,
+ 0x00bab80000d8ff00, 0x000000000000a689, 0x0000b59d007300b1,
+ 0x0000009600ad0000, 0x00a000b1f8000000, 0x00000000d400b200,
+ 0x00a5000000980000, 0x0000969f00b49a00, 0xa48761a100b30000,
+ 0x8500869500008f00, 0x7a009700008400a1, 0x00000000a90031ac,
+ 0x00b7bd00a10000b5, 0xb000b2c8c3b1a500, 0xa600000000000000
+ },
+ .l3_cacw = {
+ [71] = 0x3ff80000
+ },
+ .gfx_cacw = {
+ [0] = 0x17, 0x0, 0xa1,
+ [5] = 0x3f0000,
+ [14] = 0x1c80000,
+ [19] = 0x22, 0x12,
+ [23] = 0x7019d, 0x28001e,
+ [28] = 0x35, 0x15d, 0x1ab, 0x7f0000,
+ [35] = 0xc4,
+ [49] = 0x310000,
+ [54] = 0x76
+ },
+ .gfx_cacw_len = 64,
+ .bapm_param = {
+ {1, 0x3d14a6f2}, {1, 0x00000000}, {1, 0x3ed4eb53}, {1, 0x3e16ae78},
+ {1, 0xbe4d4746}, {1, 0x3f34470b}, {1, 0x37178941}, {1, 0x3f726e59},
+ {1, 0x3f3ebeef}, {1, 0x00000000}, {1, 0x3f8e9ad0}, {1, 0xbc2c0ab6},
+ {1, 0x3d1582c2}, {1, 0x35937309}, {1, 0x3f0f45c5}, {1, 0x3ee17477},
+ {1, 0x00000000}, {1, 0x3f8e9ad0}, {1, 0xbc2c0ab6}, {1, 0x3d1582c2},
+ {1, 0x387ba882}, {1, 0x40b1089a}, {1, 0x41751b15}, {1, 0x4287d1bc},
+ {1, 0x3fb89949}, {1, 0x411eefdf}, {1, 0xbc816b59}, {1, 0x3d41513a},
+ [49] =
+ {1, 0x41751b15}, {1, 0x4287d1bc}, {1, 0x3fb89949}, {1, 0x412d973c},
+ {1, 0xbc816b59}, {1, 0x3d41513a}, {1, 0x3e0654c8}, {1, 0xbe27b465},
+ {1, 0x3f2d3daa}, {1, 0x41751b15}, {1, 0x4287d1bc}, {1, 0x3fb89949},
+ {1, 0x4061d4cc}, {1, 0xbc816b59}, {1, 0x3d41513a}, {1, 0x3e97c980},
+ {1, 0xbf1d9856}, {1, 0x3f828e45}, {1, 0x41751b15}, {1, 0x4287d1bc},
+ {1, 0x3fb89949}, {1, 0x409c4b3c}, {1, 0xbc816b59}, {1, 0x3d41513a},
+ {1, 0x3e7a6107}, {1, 0xbeedd766}, {1, 0x3f67aa70}, {1, 0x41751b15},
+ {1, 0x4287d1bc}, {1, 0x3fb89949}, {1, 0x40ccf558}, {1, 0xbc816b59},
+ {1, 0x3d41513a}, {1, 0x3e600a8a}, {1, 0xbecbe79c}, {1, 0x3f5b627c},
+ {1, 0x41751b15}, {1, 0x4287d1bc}, {1, 0x3fb89949}, {1, 0x41050555},
+ {1, 0xbc816b59}, {1, 0x3d41513a}, {1, 0x3e379205}, {1, 0xbe94367e},
+ {1, 0x3f46233f}, {1, 0x3f726e59}, {1, 0x3f3ebeef}, {1, 0x00000000},
+ {1, 0x3f8e9ad0}, {1, 0xbc2c0ab6}, {1, 0x3d1582c2}, {1, 0x3d14a6f2},
+ {1, 0x00000000}, {1, 0x3ed4eb53}, {1, 0x3f726e59}, {1, 0x3f3ebeef},
+ {1, 0x00000000}, {1, 0x3f8e9ad0}, {1, 0xbc2c0ab6}, {1, 0x3d1582c2},
+ {1, 0x3d14a6f2}, {1, 0x00000000}, {1, 0x3ed4eb53}, {1, 0x3f726e59},
+ {1, 0x3f3ebeef}, {1, 0x00000000}, {1, 0x3f8e9ad0}, {1, 0xbc2c0ab6},
+ {1, 0x3d1582c2}, {1, 0x3d14a6f2}, {1, 0x00000000}, {1, 0x3ed4eb53},
+ {1, 0x3f726e59}, {1, 0x3f3ebeef}, {1, 0x00000000}, {1, 0x3f8e9ad0},
+ {1, 0xbc2c0ab6}, {1, 0x3d1582c2}, {1, 0x3d14a6f2}, {1, 0x00000000},
+ {1, 0x3ed4eb53}, {1, 0x3f726e59}, {1, 0x3f3ebeef}, {1, 0x00000000},
+ {1, 0x3f8e9ad0}, {1, 0xbc2c0ab6}, {1, 0x3d1582c2}, {1, 0x3d14a6f2},
+ {1, 0x00000000}, {1, 0x3ed4eb53}, {1, 0x3f0f45c5}, {1, 0x3ee17477},
+ {1, 0x00000000}, {1, 0x3f8e9ad0}, {1, 0xbc2c0ab6}, {1, 0x3d1582c2},
+ {1, 0x3f0f45c5}, {1, 0x3ee17477}, {1, 0x00000000}, {1, 0x3f8e9ad0},
+ {1, 0xbc2c0ab6}, {1, 0x3d1582c2}, {1, 0x3f0f45c5}, {1, 0x3ee17477},
+ {1, 0x00000000}, {1, 0x3f8e9ad0}, {1, 0xbc2c0ab6}, {1, 0x3d1582c2},
+ {1, 0x3f0f45c5}, {1, 0x3ee17477}, {1, 0x00000000}, {1, 0x3f8e9ad0},
+ {1, 0xbc2c0ab6}, {1, 0x3d1582c2}, {1, 0x3f0f45c5}, {1, 0x3ee17477},
+ {1, 0x00000000}, {1, 0x3f8e9ad0}, {1, 0xbc2c0ab6}, {1, 0x3d1582c2},
+ {1, 0x3c437be5}, {1, 0x00000000}, {1, 0x00000000}, {1, 0x00000000},
+ {1, 0x00000000}, {1, 0x00000000}, {1, 0x00000000}
+ }
+};
+
+static const struct bapm_param_set bapm_param_set_2 = {
+ .dpm_wac = {
+ 0x0000c3adb08d0000, 0x00a800008d000000, 0xa000008e000000a6,
+ 0x00000000c900a500, 0xc8d000d3b8daea00, 0x0000d000a3d200dc,
+ 0x00bfc80000c6f100, 0x00fe00000000ad00, 0x0000abb300000000,
+ 0x00008600000000cf, 0x00ae0095ff000000, 0x000000000000ac00,
+ 0x00b00000008500ad, 0x0098849600b18000, 0xa2a38bac00b00000,
+ 0x97007479000092ab, 0x0095a30000008f00, 0x000000b5000000a0,
+ 0x0000c200a80000bd, 0x0000bcc1c4b2a300, 0xa700000000000000
+ },
+ .l3_cacw = {
+ [71] = 0x3ff80000,
+ },
+ .gfx_cacw = {
+ [2] = 0xefa,
+ [6] = 0x7bf,
+ [12] = 0x14d10000,
+ [14] = 0x287b0000,
+ [20] = 0x2f2,
+ [22] = 0x1085ffff, 0xcd80e51, 0x4b86145a,
+ [27] = 0x15a7,
+ [29] = 0x13c2, 0x2d02,
+ [34] = 0x78ad0000, 0x2ea0,
+ [54] = 0x257d, 0x8c8,
+ [58] = 0x799e,
+ [63] = 0x152,
+ },
+ .gfx_cacw_len = 64,
+ .bapm_param = {
+ {1, 0xbc22f028}, {1, 0x3e113314}, {1, 0xbe8d0750}, {1, 0x3e16ae78},
+ {1, 0xbe4d4746}, {1, 0x3f34470b}, {1, 0x3704564c}, {1, 0x3f516a34},
+ {1, 0x3f3fdd1c}, {1, 0x3f74f5de}, {1, 0x3dec9763}, {1, 0xbc2c0ab6},
+ {1, 0x3d1582c2}, {1, 0x367468e6}, {1, 0x3f059935}, {1, 0x3ef4cd95},
+ {1, 0x3f74f5de}, {1, 0x3d524dae}, {1, 0xbc2c0ab6}, {1, 0x3d1582c2},
+ {1, 0x357db71b}, {1, 0x40b1089a}, {1, 0x41751b15}, {1, 0x4287d1bc},
+ {1, 0x3fb89949}, {1, 0x411eefdf}, {1, 0xbc816b59}, {1, 0x3d41513a},
+ [49] =
+ {1, 0x41751b15}, {1, 0x4287d1bc}, {1, 0x3fb89949}, {1, 0x412d973c},
+ {1, 0xbc816b59}, {1, 0x3d41513a}, {1, 0x3e0654c8}, {1, 0xbe27b465},
+ {1, 0x3f2d3daa}, {1, 0x41751b15}, {1, 0x4287d1bc}, {1, 0x3fb89949},
+ {1, 0x4061d4cc}, {1, 0xbc816b59}, {1, 0x3d41513a}, {1, 0x3e97c980},
+ {1, 0xbf1d9856}, {1, 0x3f828e45}, {1, 0x41751b15}, {1, 0x4287d1bc},
+ {1, 0x3fb89949}, {1, 0x409c4b3c}, {1, 0xbc816b59}, {1, 0x3d41513a},
+ {1, 0x3e7a6107}, {1, 0xbeedd766}, {1, 0x3f67aa70}, {1, 0x41751b15},
+ {1, 0x4287d1bc}, {1, 0x3fb89949}, {1, 0x40ccf558}, {1, 0xbc816b59},
+ {1, 0x3d41513a}, {1, 0x3e600a8a}, {1, 0xbecbe79c}, {1, 0x3f5b627c},
+ {1, 0x41751b15}, {1, 0x4287d1bc}, {1, 0x3fb89949}, {1, 0x41050555},
+ {1, 0xbc816b59}, {1, 0x3d41513a}, {1, 0x3e379205}, {1, 0xbe94367e},
+ {1, 0x3f46233f}, {1, 0x3f96c5af}, {1, 0x3eb99add}, {1, 0x3f85bb54},
+ {1, 0x3e6a30f6}, {1, 0xbc2c0ab6}, {1, 0x3d1582c2}, {1, 0xbbda394d},
+ {1, 0x3dff4eb1}, {1, 0xbe8b186c}, {1, 0x3f8fbf3f}, {1, 0x3ee87500},
+ {1, 0x3f7c5aff}, {1, 0x3e92470e}, {1, 0xbc2c0ab6}, {1, 0x3d1582c2},
+ {1, 0x396640ab}, {1, 0x3dad4b04}, {1, 0xbe6283c5}, {1, 0x3f8051ba},
+ {1, 0x3f13f766}, {1, 0x3f87a42b}, {1, 0x3e52acf5}, {1, 0xbc2c0ab6},
+ {1, 0x3d1582c2}, {1, 0xbbd8e837}, {1, 0x3e005ec6}, {1, 0xbe8c6197},
+ {1, 0x3f61d86e}, {1, 0x3f276f79}, {1, 0x3f7b0bf0}, {1, 0x3e25ca59},
+ {1, 0xbc2c0ab6}, {1, 0x3d1582c2}, {1, 0xbbc01a0e}, {1, 0x3dfb13b3},
+ {1, 0xbe84dd83}, {1, 0x3fa32142}, {1, 0x3ea341fd}, {1, 0x3f85d724},
+ {1, 0x3e8c3c1d}, {1, 0xbc2c0ab6}, {1, 0x3d1582c2}, {1, 0xbaa01624},
+ {1, 0x3dbebfaf}, {1, 0xbe6f57f4}, {1, 0x3f43c147}, {1, 0x3e70fae5},
+ {1, 0x3f85bb54}, {1, 0x3dd02b85}, {1, 0xbc2c0ab6}, {1, 0x3d1582c2},
+ {1, 0x3f364cb6}, {1, 0x3e936695}, {1, 0x3f7c5aff}, {1, 0x3e020645},
+ {1, 0xbc2c0ab6}, {1, 0x3d1582c2}, {1, 0x3f226119}, {1, 0x3ebb3dcd},
+ {1, 0x3f87a42b}, {1, 0x3dbb4468}, {1, 0xbc2c0ab6}, {1, 0x3d1582c2},
+ {1, 0x3f1302b3}, {1, 0x3ed9fa9b}, {1, 0x3f7b0bf0}, {1, 0x3d935e88},
+ {1, 0xbc2c0ab6}, {1, 0x3d1582c2}, {1, 0x3f4cc495}, {1, 0x3e4cedab},
+ {1, 0x3f85d724}, {1, 0x3df94e6d}, {1, 0xbc2c0ab6}, {1, 0x3d1582c2},
+ {1, 0x3c437be5}, {1, 0x3f3de47f}, {1, 0x3f40c129}, {1, 0x3f3cc9e7},
+ {1, 0x3f41350f}, {1, 0x3f3dcec6}, {1, 0x3f3e1c51}
+ }
+};
+
+static u32 pcirc_smn_read(u32 reg)
+{
+ u32 val = 0;
+ if (amd_smn_read(0, reg, &val)) {
+ panic("amd_smn_read failed");
+ }
+ return val;
+}
+
+static void pcirc_smn_write(u32 reg, u32 val)
+{
+ if (amd_smn_write(0, reg, val)) {
+ panic("amd_smn_write failed");
+ }
+}
+
+static int mp1fw_waitmsg(u32 reg, u8 msgid)
+{
+ int timeout = 0;
+
+ while (!pcirc_smn_read(reg)) {
+ udelay(10);
+ if (++timeout == 200000) {
+ return 1;
+ }
+ }
+
+ if (timeout >= 10000) {
+ pr_err("[MP1] wait %d msec (msgid=0x%X)\n", timeout / 100, msgid);
+ return 0;
+ }
+
+ return 0;
+}
+
+static int mp1fw_sendmsg(struct mp1_msg *msg, u8 msgid)
+{
+ if (mp1fw_waitmsg(MP1_C2PMSG_90, msgid)) {
+ pr_err("[MP1ERROR] : %s: Error : busy msgid=0x%X, arg=0x%08X\n", __func__, msgid, msg->arg);
+ return -EBUSY;
+ }
+
+ pcirc_smn_write(MP1_C2PMSG_90, 0);
+ pcirc_smn_write(MP1_C2PMSG_82, msg->arg);
+ if (msg->extra == 1)
+ pcirc_smn_write(MP1_C2PMSG_81, msg->extra_arg);
+ pcirc_smn_write(MP1_C2PMSG_66, msgid);
+
+ if (mp1fw_waitmsg(MP1_C2PMSG_90, msgid)) {
+ pr_err("[MP1ERROR] : %s: Error : retry over msgid=0x%X, arg=0x%08X\n", __func__, msgid, msg->arg);
+ return -EBUSY;
+ }
+
+ u32 resp = pcirc_smn_read(MP1_C2PMSG_90);
+ u32 resp_val = pcirc_smn_read(MP1_C2PMSG_82);
+ if (resp != 1) {
+ pr_err("[MP1ERROR] : %s: invalid response msgid=0x%X, resp=0x%08X\n", __func__, msgid, resp);
+ return -EINVAL;
+ }
+
+ msg->resp = resp;
+ msg->resp_val = resp_val;
+
+ return 0;
+}
+
+static int mp1fw_test_sendmsg(struct mp1_msg *msg, uint8_t msgid)
+{
+ if (mp1fw_waitmsg(MP1_C2PMSG_96, msgid)) {
+ printk("[MP1ERROR] : %s: Error : busy msgid=0x%X, arg=0x%08X\n", __func__, msgid, msg->arg);
+ return -EBUSY;
+ }
+ pcirc_smn_write(MP1_C2PMSG_96, 0);
+ pcirc_smn_write(MP1_C2PMSG_98, msg->arg);
+ pcirc_smn_write(MP1_C2PMSG_72, msgid);
+ if (mp1fw_waitmsg(MP1_C2PMSG_96, msgid)) {
+ printk("[MP1ERROR] : %s: retry over msgid=0x%X, arg=0x%08X\n", __func__, msgid, msg->arg);
+ return -EBUSY;
+ }
+ u32 resp = pcirc_smn_read(MP1_C2PMSG_96);
+ u32 resp_val = pcirc_smn_read(MP1_C2PMSG_98);
+ if ((msgid != 0x75 && resp != 1) || (msgid == 0x75 && resp != 1 && resp != 0xf8)) {
+ printk("[MP1ERROR] : %s: invalid response msgid=0x%X, resp=0x%08X\n", __func__, msgid, resp);
+ return -EINVAL;
+ }
+
+ msg->resp = resp;
+ msg->resp_val = resp_val;
+
+ return 0;
+}
+
+static int mp1_set_wc_cpu(int mode)
+{
+ struct mp1_msg msg = {};
+ msg.arg = mode;
+ return mp1fw_test_sendmsg(&msg, 0x9b);
+}
+
+static int mp1_get_wc_cpu(int *mode)
+{
+ struct mp1_msg msg = {};
+ int ret;
+ ret = mp1fw_test_sendmsg(&msg, 0x9c);
+ *mode = msg.resp_val;
+ return ret;
+}
+
+static int mp1_configure_s3_pwr_off_reg_addr_high(u64 addr)
+{
+ struct mp1_msg msg = {};
+ msg.arg = addr >> 32;
+ return mp1fw_sendmsg(&msg, PPSMC_MSG_ConfigureS3PwrOffRegisterAddressHigh);
+}
+
+static int mp1_configure_s3_pwr_off_reg_addr_low(u64 addr)
+{
+ struct mp1_msg msg = {};
+ msg.arg = addr & 0xffffffff;
+ return mp1fw_sendmsg(&msg, PPSMC_MSG_ConfigureS3PwrOffRegisterAddressLow);
+}
+
+void mp1_set_pm1_addr(u64 addr)
+{
+ mp1_configure_s3_pwr_off_reg_addr_high(addr);
+ mp1_configure_s3_pwr_off_reg_addr_low(addr);
+}
+EXPORT_SYMBOL(mp1_set_pm1_addr);
+
+int mp1_set_sleep_entry(void)
+{
+ struct mp1_msg msg = {};
+ msg.arg = 3; /* S3 */
+ return mp1fw_sendmsg(&msg, PPSMC_MSG_SleepEntry);
+}
+EXPORT_SYMBOL(mp1_set_sleep_entry);
+
+static int mp1_universal_mode_enter(u32 *params)
+{
+ struct mp1_msg msg = {};
+
+ pcirc_smn_write(MP1_C2PMSG_56, params[1]);
+ pcirc_smn_write(MP1_C2PMSG_57, params[2]);
+ pcirc_smn_write(MP1_C2PMSG_58, params[3]);
+ pcirc_smn_write(MP1_C2PMSG_59, params[4]);
+
+ msg.arg = params[0];
+ return mp1fw_sendmsg(&msg, PPSMC_MSG_UniversalModeEntry);
+}
+
+static int mp1_universal_mode_exit(void)
+{
+ struct mp1_msg msg = {};
+ return mp1fw_sendmsg(&msg, PPSMC_MSG_UniversalModeExit);
+}
+
+static int mp1_bapm_set_gfx_cacw(int index, int weight)
+{
+ struct mp1_msg msg = {};
+ msg.arg = index | 0x20000;
+ msg.extra_arg = weight;
+ msg.extra = 1;
+ return mp1fw_sendmsg(&msg, PPSMC_MSG_GfxCacWeightOperation);
+}
+
+static int mp1_bapm_set_l3_cacw(int index, int weight)
+{
+ struct mp1_msg msg = {};
+ msg.arg = index | 0x20000;
+ msg.extra_arg = weight;
+ msg.extra = 1;
+ return mp1fw_sendmsg(&msg, PPSMC_MSG_L3CacWeightOperation);
+}
+
+static int mp1_bapm_write_param(int index, int param)
+{
+ struct mp1_msg msg = {};
+ msg.arg = index;
+ msg.extra_arg = param;
+ msg.extra = 1;
+ return mp1fw_sendmsg(&msg, 0x33);
+}
+
+static void update_bapm_weights_smp(void *info)
+{
+ u64 msr_dpm_cfg;
+ int i;
+
+ rdmsrq(MSR_DPM_CFG, msr_dpm_cfg);
+ wrmsrq(MSR_DPM_CFG, msr_dpm_cfg & ~MSR_ACCESS_DIS);
+
+ for (i = 0; i < 21; i++) {
+ wrmsrq(MSR_DPM_WAC_ACC_INDEX, i);
+ wrmsrq(MSR_DPM_WAC_DATA, bapm_param_set_2.dpm_wac[i]);
+ }
+
+ wrmsrq(MSR_DPM_CFG, msr_dpm_cfg);
+}
+
+static void mp1_set_bapm_param_set_all(void)
+{
+ int i;
+
+ on_each_cpu(update_bapm_weights_smp, NULL, 1);
+
+ for (i = 0; i < 80; i++) {
+ mp1_bapm_set_l3_cacw(i, bapm_param_set_2.l3_cacw[i]);
+ }
+
+ for (i = 0; i < bapm_param_set_2.gfx_cacw_len; i++) {
+ mp1_bapm_set_gfx_cacw(i, bapm_param_set_2.gfx_cacw[i]);
+ }
+
+ for (i = 0; i < 176; i++) {
+ if (bapm_param_set_2.bapm_param[i][0])
+ mp1_bapm_write_param(i, bapm_param_set_2.bapm_param[i][1]);
+ }
+}
+
+static long mp1_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ switch (cmd) {
+ case MP1_BOOST_ENTER:
+ {
+ u32 params[5];
+ params[0] = 0x0;
+ params[1] = 0x449cd;
+ params[2] = (GPU_MHZ_MIN << 16) | CPU_MHZ_MIN;
+ params[3] = (GPU_MHZ_MAX << 16) | CPU_MHZ_MAX;
+ params[4] = 0x25c6a3c8;
+ return mp1_universal_mode_enter(params);
+ }
+
+ case MP1_BOOST_EXIT:
+ return mp1_universal_mode_exit();
+
+ default:
+ return -ENOTTY;
+ }
+}
+
+static const struct file_operations mp1_fops = {
+ .owner = THIS_MODULE,
+ .unlocked_ioctl = mp1_ioctl,
+};
+
+static struct miscdevice mp1_misc_device = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "mp1",
+ .fops = &mp1_fops,
+};
+
+static int __init mp1_init(void)
+{
+ int ret;
+ int mode = 0;
+
+ mp1_universal_mode_exit();
+
+ pr_info("Set BAPM params\n");
+ mp1_get_wc_cpu(&mode);
+ if (mode != 1) {
+ mp1_set_wc_cpu(1);
+ }
+ mp1_set_bapm_param_set_all();
+
+ ret = misc_register(&mp1_misc_device);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static void __exit mp1_exit(void)
+{
+ misc_deregister(&mp1_misc_device);
+ mp1_universal_mode_exit();
+}
+
+module_init(mp1_init);
+module_exit(mp1_exit);
+
+MODULE_AUTHOR("Andy Nguyen");
+MODULE_DESCRIPTION("PlayStation 5 MP1 SMU driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/ps5/ps5-fan.h b/drivers/ps5/ps5-fan.h
new file mode 100644
index 000000000000..5ea1519823c3
--- /dev/null
+++ b/drivers/ps5/ps5-fan.h
@@ -0,0 +1,53 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef _PS5_FAN_H
+#define _PS5_FAN_H
+
+#include <linux/ps5.h>
+
+#define PS5_FAN_MT_MODE_SET 0x02
+#define PS5_FAN_MT_MODE_GET 0x03
+#define PS5_FAN_MT_CURSET_SET 0x06
+#define PS5_FAN_MT_CURSET_GET 0x07
+
+#define PS5_FAN_CURSET_SET_LEN 0x40
+#define PS5_FAN_CURSET_GET_LEN ICC_MSG_MIN_SIZE
+
+enum ps5_fan_zone {
+ PS5_ZONE_MAINSOC = 0,
+ PS5_ZONE_LOCAL1 = 1,
+ PS5_ZONE_LOCAL2 = 2,
+ PS5_ZONE_LOCAL3 = 3,
+ PS5_ZONE_COUNT = 4,
+};
+
+enum ps5_fan_mode {
+ PS5_FAN_MODE_AUTO = 1,
+ PS5_FAN_MODE_MAXIMUM = 2,
+ PS5_FAN_MODE_MINIMUM = 3,
+ PS5_FAN_MODE_MANUAL = 4,
+ PS5_FAN_MODE_SP1 = 5,
+};
+#define PS5_FAN_MODE_MIN PS5_FAN_MODE_AUTO
+#define PS5_FAN_MODE_MAX PS5_FAN_MODE_SP1
+
+enum ps5_curset_id {
+ PS5_CURSET_TARGETTEMP = 0,
+ PS5_CURSET_PGAIN = 1,
+ PS5_CURSET_IGAIN = 2,
+ PS5_CURSET_ILIMIT = 3,
+ PS5_CURSET_ULIMIT = 4,
+ PS5_CURSET_DLIMIT = 5,
+ PS5_CURSET_COUNT = 6,
+};
+
+#define PS5_FAN_ZONE_OFF 0
+#define PS5_FAN_MODE_OFF 1
+#define PS5_FAN_SETTING_OFF 1
+#define PS5_FAN_CONFIG_OFF 1
+#define PS5_FAN_CURSET_OFF 0x04
+#define PS5_FAN_CURSET_GET_OFF PS5_FAN_CURSET_OFF
+#define PS5_FAN_CURSET_SET_OFF PS5_FAN_CURSET_OFF
+
+#define PS5_TARGETTEMP_SHIFT 8
+
+#endif /* _PS5_FAN_H */
diff --git a/drivers/ps5/spcie.c b/drivers/ps5/spcie.c
new file mode 100644
index 000000000000..547b1457ac62
--- /dev/null
+++ b/drivers/ps5/spcie.c
@@ -0,0 +1,974 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/module.h>
+#include <linux/miscdevice.h>
+#include <linux/input.h>
+#include <linux/pci.h>
+#include <linux/ps5.h>
+#include <linux/dmi.h>
+#include <linux/delay.h>
+#include <linux/kfifo.h>
+
+#define PCI_DEVICE_ID_SPCIE 0x9107
+#define SPCIE_SUBFUNC_ICC 12
+#define NUM_IRQS 16
+
+#define ICC_QUERY_OFFSET 0
+#define ICC_REPLY_OFFSET 0x800
+
+#define ICC_DOORBELL_OFFSET 0x108000
+
+#define ICC_REG_SOW 0x7f0
+#define ICC_REG_SOR 0x7f4
+#define ICC_REG_EMW 0xff0
+#define ICC_REG_EMR 0xff4
+
+#define ICC_REG_DOORBELL 0x04
+#define ICC_REG_INTR_STATUS 0x14
+#define ICC_REG_INTR_MASK 0x24
+
+#define ICC_SEND 0x01
+#define ICC_ACK 0x02
+
+#define ICC_MSG_TYPE_REPLY 0x4000
+#define ICC_MSG_TYPE_NOTIF 0x8000
+
+#define ICC_TIMEOUT_MSECS 12000
+
+#define ICC_IOC_MAGIC 'I'
+
+#define ICC_FAN_CHANGE_SERVO_PATTERN _IOW(ICC_IOC_MAGIC, 1, u8)
+
+struct spcie_dev;
+
+struct spcie_icc_dev {
+ struct pci_dev *pdev;
+ struct spcie_dev *sdev;
+ struct input_dev *idev;
+ struct mutex lock;
+ wait_queue_head_t wq;
+ void __iomem *icc_doorbell_base;
+ void __iomem *icc_base;
+ u16 icc_send_xtn_id;
+ u8 notification[ICC_MSG_MAX_SIZE];
+ u16 notification_length;
+ u8 reply[ICC_MSG_MAX_SIZE];
+ u16 reply_length;
+ bool reply_ready;
+};
+
+struct spcie_dev {
+ struct pci_dev *pdev;
+ struct spcie_icc_dev *icc_dev;
+ void __iomem *bar2;
+ void __iomem *pervasive0;
+};
+
+struct icc_notification {
+ u8 service_id;
+ u8 notification[ICC_MSG_MAX_SIZE];
+};
+
+#define ICC_NOTIFICATION_FIFO_SIZE 32
+static DEFINE_KFIFO(icc_notification_fifo, struct icc_notification, ICC_NOTIFICATION_FIFO_SIZE);
+static DEFINE_SPINLOCK(icc_notification_lock);
+static struct work_struct icc_notification_work;
+
+static struct spcie_dev *sdev;
+static struct spcie_icc_dev *icc_dev;
+
+static bool spcie_initialized = false;
+static u32 spcie_chip_revision_id = 0;
+
+static const u8 indicator_white_dim[] = {
+ 0x03, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x11,
+ 0x01, 0x00, 0x20, 0x00, 0x01, 0x00, 0x12, 0x01, 0x00, 0x00, 0x00, 0x02,
+ 0x00
+};
+
+static const u8 indicator_white_medium[] = {
+ 0x03, 0x00, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x11,
+ 0x01, 0x00, 0x5F, 0x00, 0x01, 0x00, 0x12, 0x01, 0x00, 0x00, 0x00, 0x02,
+ 0x00
+};
+
+static const u8 indicator_white_bright[] = {
+ 0x03, 0x00, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x11,
+ 0x01, 0x00, 0xFF, 0x00, 0x01, 0x00, 0x12, 0x01, 0x00, 0x00, 0x00, 0x02,
+ 0x00
+};
+
+static u16 icc_checksum(struct icc_msg *msg)
+{
+ u16 i;
+ u16 checksum = 0;
+ for (i = 0; i < msg->length; i++)
+ checksum += ((u8 *)msg)[i];
+ return checksum;
+}
+
+static int icc_send(u8 *query)
+{
+ struct icc_msg *msg;
+
+ msg = (struct icc_msg *)query;
+ if (msg->length < ICC_MSG_MIN_SIZE)
+ msg->length = ICC_MSG_MIN_SIZE;
+ msg->magic = 0x42;
+ msg->unk_04 = 3;
+ msg->id = icc_dev->icc_send_xtn_id++;
+ msg->checksum = icc_checksum(msg);
+
+ writew(0, icc_dev->icc_base + ICC_REG_SOR);
+
+ for (u16 i = 0; i < msg->length; i++)
+ writeb(query[i], icc_dev->icc_base + ICC_QUERY_OFFSET + i);
+
+ writew(1, icc_dev->icc_base + ICC_REG_SOW);
+
+ writel(ICC_SEND, icc_dev->icc_doorbell_base + ICC_REG_DOORBELL);
+
+ return 0;
+}
+
+int icc_query(u8 *query, u8 *reply)
+{
+ struct icc_msg *msg;
+ u16 checksum, expected;
+ int ret;
+
+ mutex_lock(&icc_dev->lock);
+
+ icc_dev->reply_ready = false;
+
+ icc_send(query);
+
+ ret = wait_event_timeout(icc_dev->wq, icc_dev->reply_ready,
+ msecs_to_jiffies(ICC_TIMEOUT_MSECS));
+ if (ret == 0) {
+ dev_err(&icc_dev->pdev->dev, "timeout\n");
+ mutex_unlock(&icc_dev->lock);
+ return -ETIMEDOUT;
+ }
+
+ memcpy(reply, icc_dev->reply, icc_dev->reply_length);
+
+ msg = (struct icc_msg *)reply;
+ expected = msg->checksum;
+ msg->checksum = 0;
+ checksum = icc_checksum(msg);
+ if (checksum != expected) {
+ dev_err(&icc_dev->pdev->dev, "checksum mismatch\n");
+ mutex_unlock(&icc_dev->lock);
+ return -EINVAL;
+ }
+
+ mutex_unlock(&icc_dev->lock);
+ return 0;
+}
+EXPORT_SYMBOL(icc_query);
+
+int icc_nvs_write(u32 partition, u16 offset, u16 length, const void *data)
+{
+ u8 buf[ICC_MSG_MAX_SIZE] = {};
+ struct icc_msg *msg = (struct icc_msg *)buf;
+
+ msg->service_id = ICC_SERVICE_ID_NVS;
+ msg->msg_type = 0;
+ msg->length = sizeof(*msg) + 6 + length;
+ msg->data[0] = 0;
+ msg->data[1] = partition;
+ *(u16 *)&msg->data[2] = offset;
+ *(u16 *)&msg->data[4] = length;
+ memcpy(&msg->data[6], data, length);
+
+ return icc_query(buf, buf);
+}
+EXPORT_SYMBOL(icc_nvs_write);
+
+int icc_nvs_read(u32 partition, u16 offset, u16 length, void *data)
+{
+ u8 buf[ICC_MSG_MAX_SIZE] = {};
+ struct icc_msg *msg = (struct icc_msg *)buf;
+ int ret;
+
+ msg->service_id = ICC_SERVICE_ID_NVS;
+ msg->msg_type = 1;
+ msg->length = ICC_MSG_MIN_SIZE;
+ msg->data[0] = 0;
+ msg->data[1] = partition;
+ *(u16 *)&msg->data[2] = offset;
+ *(u16 *)&msg->data[4] = length;
+
+ ret = icc_query(buf, buf);
+ if (ret)
+ return ret;
+
+ memcpy(data, &msg->data[2], length);
+
+ return 0;
+}
+EXPORT_SYMBOL(icc_nvs_read);
+
+int icc_usbc_set_pdcon_op_mode(u8 PortId, u8 OpMode)
+{
+ u8 buf[ICC_MSG_MAX_SIZE] = {};
+ struct icc_msg *msg = (struct icc_msg *)buf;
+
+ msg->service_id = ICC_SERVICE_ID_USBC;
+ msg->msg_type = 0x10;
+ msg->length = ICC_MSG_MIN_SIZE;
+ msg->data[0] = PortId;
+ msg->data[1] = OpMode;
+
+ return icc_query(buf, buf);
+}
+EXPORT_SYMBOL(icc_usbc_set_pdcon_op_mode);
+
+int icc_configuration_set_cpu_info_bit(u8 *bit)
+{
+ u8 buf[ICC_MSG_MAX_SIZE] = {};
+ struct icc_msg *msg = (struct icc_msg *)buf;
+
+ msg->service_id = ICC_SERVICE_ID_GENERAL;
+ msg->msg_type = 0x10;
+ msg->length = ICC_MSG_MIN_SIZE;
+ msg->data[0] = bit[1];
+ msg->data[1] = bit[0];
+
+ return icc_query(buf, buf);
+}
+EXPORT_SYMBOL(icc_configuration_set_cpu_info_bit);
+
+int icc_configuration_clear_cpu_info_bit(void)
+{
+ u8 bit[2];
+ int ret;
+
+ bit[0] = 0;
+ bit[1] = 0;
+ ret = icc_configuration_set_cpu_info_bit(bit);
+ if (ret)
+ return ret;
+
+ bit[0] = 0;
+ bit[1] = 1;
+ ret = icc_configuration_set_cpu_info_bit(bit);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+EXPORT_SYMBOL(icc_configuration_clear_cpu_info_bit);
+
+__noreturn void icc_power_suspend(int keep)
+{
+ u8 buf[ICC_MSG_MAX_SIZE] = {};
+ struct icc_msg *msg = (struct icc_msg *)buf;
+
+ msg->service_id = ICC_SERVICE_ID_POWER;
+ msg->msg_type = 1;
+ msg->length = ICC_MSG_MIN_SIZE;
+ msg->data[0] = 1; // with eap
+ msg->data[1] = 1;
+ msg->data[2] = 1;
+ msg->data[3] = 0;
+ msg->data[4] = 1;
+ *(u16 *)&msg->data[5] = (2 * (keep != 0)) | 0x30;
+ *(u16 *)&msg->data[7] = 0;
+
+ icc_query(buf, buf);
+ local_irq_disable();
+ wbinvd();
+ mp1_set_sleep_entry();
+ while (1);
+}
+EXPORT_SYMBOL(icc_power_suspend);
+
+__noreturn void icc_power_shutdown(void)
+{
+ u8 buf[ICC_MSG_MAX_SIZE] = {};
+ struct icc_msg *msg = (struct icc_msg *)buf;
+
+ icc_configuration_clear_cpu_info_bit();
+
+ msg->service_id = ICC_SERVICE_ID_POWER;
+ msg->msg_type = 1;
+ msg->length = ICC_MSG_MIN_SIZE;
+ msg->data[0] = 0;
+ msg->data[1] = 0; // shutdown
+ msg->data[2] = 2; // depth
+ msg->data[3] = 0; // cause
+ msg->data[4] = 1; // hand
+ *(u32 *)&msg->data[5] = 0;
+
+ icc_query(buf, buf);
+ while (1);
+}
+EXPORT_SYMBOL(icc_power_shutdown);
+
+__noreturn void icc_power_reboot(void)
+{
+ u8 buf[ICC_MSG_MAX_SIZE] = {};
+ struct icc_msg *msg = (struct icc_msg *)buf;
+
+ icc_configuration_clear_cpu_info_bit();
+
+ msg->service_id = ICC_SERVICE_ID_POWER;
+ msg->msg_type = 1;
+ msg->length = ICC_MSG_MIN_SIZE;
+ msg->data[0] = 0;
+ msg->data[1] = 1; // reboot
+ msg->data[2] = 2; // depth
+ msg->data[3] = 0; // cause
+ msg->data[4] = 1; // hand
+ *(u32 *)&msg->data[5] = 0;
+
+ icc_query(buf, buf);
+ while (1);
+}
+EXPORT_SYMBOL(icc_power_reboot);
+
+int icc_button_enable_notification(u8 type, u8 enable)
+{
+ u8 buf[ICC_MSG_MAX_SIZE] = {};
+ struct icc_msg *msg = (struct icc_msg *)buf;
+
+ msg->service_id = ICC_SERVICE_ID_BUTTON;
+ msg->msg_type = 1;
+ msg->length = 0x20;
+ msg->data[0] = type;
+ msg->data[1] = enable;
+
+ return icc_query(buf, buf);
+}
+EXPORT_SYMBOL(icc_button_enable_notification);
+
+int icc_button_enable_all_notifications(u8 enable)
+{
+ int ret;
+
+ /* power button */
+ ret = icc_button_enable_notification(0, enable);
+ if (ret)
+ return ret;
+
+ /* eject button */
+ ret = icc_button_enable_notification(1, enable);
+ if (ret)
+ return ret;
+
+ /* reset button */
+ ret = icc_button_enable_notification(2, enable);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+EXPORT_SYMBOL(icc_button_enable_all_notifications);
+
+int icc_thermal_enable_notification(u8 enable)
+{
+ u8 buf[ICC_MSG_MAX_SIZE] = {};
+ struct icc_msg *msg = (struct icc_msg *)buf;
+
+ msg->service_id = ICC_SERVICE_ID_THERMAL;
+ msg->msg_type = 2;
+ msg->length = 0x20;
+ msg->data[0] = enable;
+
+ return icc_query(buf, buf);
+}
+EXPORT_SYMBOL(icc_thermal_enable_notification);
+
+int icc_device_power_control(u8 device, u8 state)
+{
+ u8 buf[ICC_MSG_MAX_SIZE] = {};
+ struct icc_msg *msg = (struct icc_msg *)buf;
+
+ msg->service_id = ICC_SERVICE_ID_DEVICE;
+ msg->msg_type = 0;
+ msg->length = 0x20;
+ msg->data[0] = device;
+ msg->data[1] = state;
+
+ return icc_query(buf, buf);
+}
+EXPORT_SYMBOL(icc_device_power_control);
+
+int icc_device_power_get(u8 device, u8 *state)
+{
+ u8 buf[ICC_MSG_MAX_SIZE] = {};
+ struct icc_msg *msg = (struct icc_msg *)buf;
+ int ret;
+
+ msg->service_id = ICC_SERVICE_ID_DEVICE;
+ msg->msg_type = 1;
+ msg->length = 0x20;
+ msg->data[0] = device;
+
+ ret = icc_query(buf, buf);
+ if (ret)
+ return ret;
+
+ *state = msg->data[2];
+
+ return 0;
+}
+EXPORT_SYMBOL(icc_device_power_get);
+
+int icc_indicator_set_led(const u8 setting[], size_t setting_size)
+{
+ u8 buf[ICC_MSG_MAX_SIZE] = {};
+ struct icc_msg *msg = (struct icc_msg *)buf;
+
+ msg->service_id = ICC_SERVICE_ID_INDICATOR;
+ msg->msg_type = 0x20;
+ msg->length = sizeof(*msg) + setting_size;
+ memcpy(msg->data, setting, setting_size);
+
+ return icc_query(buf, buf);
+}
+EXPORT_SYMBOL(icc_indicator_set_led);
+
+int icc_indicator_set_led_white(u8 level)
+{
+ switch (level) {
+ case 0:
+ return icc_indicator_set_led(indicator_white_dim, sizeof(indicator_white_dim));
+ case 1:
+ return icc_indicator_set_led(indicator_white_medium, sizeof(indicator_white_medium));
+ case 2:
+ return icc_indicator_set_led(indicator_white_bright, sizeof(indicator_white_bright));
+ default:
+ return -EINVAL;
+ }
+}
+EXPORT_SYMBOL(icc_indicator_set_led_white);
+
+int icc_fan_change_servo_pattern(u8 pattern)
+{
+ u8 buf[ICC_MSG_MAX_SIZE] = {};
+ struct icc_msg *msg = (struct icc_msg *)buf;
+
+ msg->service_id = ICC_SERVICE_ID_FAN;
+ msg->msg_type = 0xb;
+ msg->length = 0x20;
+ msg->data[0] = pattern;
+ msg->data[1] = pattern;
+ msg->data[2] = pattern;
+ msg->data[3] = pattern;
+
+ return icc_query(buf, buf);
+}
+EXPORT_SYMBOL(icc_fan_change_servo_pattern);
+
+static void button_notification_handler(struct icc_msg *msg)
+{
+ if (msg->msg_type == 0x8010) { // power button down
+ input_report_key(icc_dev->idev, KEY_POWER, 1);
+ input_sync(icc_dev->idev);
+ } else if (msg->msg_type == 0x8011) { // power button up
+ input_report_key(icc_dev->idev, KEY_POWER, 0);
+ input_sync(icc_dev->idev);
+ }
+}
+
+static void icc_notification_work_func(struct work_struct *work)
+{
+ struct icc_msg *msg;
+ struct icc_notification entry;
+
+ while (kfifo_out_spinlocked(&icc_notification_fifo, &entry, 1, &icc_notification_lock)) {
+ msg = (struct icc_msg *)entry.notification;
+ if (entry.service_id == ICC_SERVICE_ID_HDMI) {
+ hdmi_notification_handler(msg);
+ } else if (entry.service_id == ICC_SERVICE_ID_BUTTON) {
+ button_notification_handler(msg);
+ } else {
+ pr_info("service id: %x\n", entry.service_id);
+ print_hex_dump(KERN_INFO, "event: ", DUMP_PREFIX_OFFSET, 16, 1,
+ msg->data, msg->length - sizeof(*msg), true);
+ }
+
+ }
+}
+
+static int icc_notification_handler(u8 service_id, u8 *notification)
+{
+ struct icc_msg *msg = (struct icc_msg *)notification;
+ struct icc_notification entry;
+
+ entry.service_id = service_id;
+ memcpy(entry.notification, msg, msg->length);
+
+ if (kfifo_in_spinlocked(&icc_notification_fifo, &entry, 1, &icc_notification_lock)) {
+ schedule_work(&icc_notification_work);
+ } else {
+ pr_warn_ratelimited("icc notification buffer full\n");
+ }
+
+ return 0;
+}
+
+static irqreturn_t icc_interrupt(int irq, void *dev)
+{
+ struct spcie_icc_dev *icc_dev = dev;
+ struct icc_msg *msg;
+ u32 intr_status;
+
+ while (1) {
+ intr_status = readl(icc_dev->icc_doorbell_base + ICC_REG_INTR_STATUS);
+ if (!intr_status)
+ break;
+
+ /* Ack the interrupt */
+ writel(intr_status, icc_dev->icc_doorbell_base + ICC_REG_INTR_STATUS);
+
+ if (intr_status & ICC_SEND) {
+ msg = (struct icc_msg *)(icc_dev->icc_base + ICC_REPLY_OFFSET);
+
+ if (msg->msg_type & ICC_MSG_TYPE_NOTIF) {
+ icc_dev->notification_length = min(msg->length, ICC_MSG_MAX_SIZE);
+ memcpy(icc_dev->notification, msg, icc_dev->notification_length);
+
+ writew(0, icc_dev->icc_base + ICC_REG_EMW);
+ writew(1, icc_dev->icc_base + ICC_REG_EMR);
+
+ writel(ICC_ACK, icc_dev->icc_doorbell_base + ICC_REG_DOORBELL);
+
+ icc_notification_handler(msg->service_id, icc_dev->notification);
+ } else if (msg->msg_type & ICC_MSG_TYPE_REPLY) {
+ icc_dev->reply_length = min(msg->length, ICC_MSG_MAX_SIZE);
+ memcpy(icc_dev->reply, msg, icc_dev->reply_length);
+
+ writew(0, icc_dev->icc_base + ICC_REG_EMW);
+ writew(1, icc_dev->icc_base + ICC_REG_EMR);
+
+ writel(ICC_ACK, icc_dev->icc_doorbell_base + ICC_REG_DOORBELL);
+
+ icc_dev->reply_ready = true;
+ wake_up(&icc_dev->wq);
+ } else {
+ dev_err(&icc_dev->pdev->dev, "unknown query\n");
+ }
+ }
+ }
+
+ return IRQ_HANDLED;
+}
+
+static long icc_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ switch (cmd) {
+ case ICC_FAN_CHANGE_SERVO_PATTERN:
+ {
+ u8 pattern;
+ if (copy_from_user(&pattern, (u8 __user *)arg, sizeof(u8)))
+ return -EFAULT;
+ return icc_fan_change_servo_pattern(pattern);
+ }
+
+ default:
+ return -ENOTTY;
+ }
+}
+
+static const struct file_operations icc_fops = {
+ .owner = THIS_MODULE,
+ .unlocked_ioctl = icc_ioctl,
+};
+
+static struct miscdevice icc_misc_device = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "icc",
+ .fops = &icc_fops,
+};
+
+static int spcie_power_button_init(struct spcie_icc_dev *icc_dev)
+{
+ icc_dev->idev = input_allocate_device();
+ if (!icc_dev->idev)
+ return -ENOMEM;
+
+ icc_dev->idev->name = "Power Button";
+ icc_dev->idev->phys = "pm/button/input0";
+ icc_dev->idev->id.bustype = BUS_HOST;
+ icc_dev->idev->dev.parent = NULL;
+ input_set_capability(icc_dev->idev, EV_KEY, KEY_POWER);
+
+ return input_register_device(icc_dev->idev);
+}
+
+static void spcie_power_button_remove(struct spcie_icc_dev *icc_dev)
+{
+ input_free_device(icc_dev->idev);
+}
+
+static int spcie_icc_init(struct spcie_dev *sdev)
+{
+ int vector, ret;
+
+ icc_dev = devm_kzalloc(&sdev->pdev->dev, sizeof(*icc_dev), GFP_KERNEL);
+ if (!icc_dev)
+ return -ENOMEM;
+
+ icc_dev->pdev = sdev->pdev;
+ icc_dev->sdev = sdev;
+
+ sdev->icc_dev = icc_dev;
+
+ INIT_WORK(&icc_notification_work, icc_notification_work_func);
+
+ mutex_init(&icc_dev->lock);
+ init_waitqueue_head(&icc_dev->wq);
+
+ icc_dev->icc_doorbell_base = sdev->bar2 + ICC_DOORBELL_OFFSET;
+ icc_dev->icc_base = sdev->pervasive0;
+
+ ret = spcie_power_button_init(icc_dev);
+ if (ret)
+ return ret;
+
+ /* Clear status */
+ writel(ICC_SEND | ICC_ACK, icc_dev->icc_doorbell_base + ICC_REG_INTR_STATUS);
+
+ /* Request IRQ for icc subfunc */
+ vector = pci_irq_vector(sdev->pdev, SPCIE_SUBFUNC_ICC);
+ ret = devm_request_irq(&sdev->pdev->dev, vector, icc_interrupt, 0, "icc", icc_dev);
+ if (ret)
+ return ret;
+
+ /* Enable IRQs */
+ writel(ICC_SEND | ICC_ACK, icc_dev->icc_doorbell_base + ICC_REG_INTR_MASK);
+
+ /* Set DMI info */
+ static char hw_model[32] = {0}, hw_info[32] = {0};
+ if (icc_nvs_read(2, 0x30, 0x20, hw_model) == 0) {
+ dmi_set_system_info(DMI_PRODUCT_VERSION, hw_model);
+ }
+ if (icc_nvs_read(2, 0x10, 0x11, hw_info) == 0) {
+ dmi_set_system_info(DMI_PRODUCT_SERIAL, hw_info);
+ }
+
+ /* Enable notifications */
+ icc_button_enable_all_notifications(1);
+ icc_thermal_enable_notification(1);
+
+ /* Set LED to white dim */
+ icc_indicator_set_led_white(0);
+
+ /* Enable SuperSpeed-USB-C port */
+ icc_usbc_set_pdcon_op_mode(0, 5);
+
+ /* Initialize HDMI */
+ getHdmiConfiguration();
+ hdmiSystemResume();
+ sceHdmiInitVideoConfig();
+
+ ret = misc_register(&icc_misc_device);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int spcie_icc_remove(struct spcie_dev *sdev)
+{
+ spcie_power_button_remove(sdev->icc_dev);
+ misc_deregister(&icc_misc_device);
+ return 0;
+}
+
+static int spcie_icc_shutdown(struct spcie_dev *sdev)
+{
+ icc_fan_change_servo_pattern(0);
+
+ /* Disable IRQs */
+ writel(0, icc_dev->icc_doorbell_base + ICC_REG_INTR_MASK);
+
+ return 0;
+}
+
+bool spcie_is_initialized(void)
+{
+ return spcie_initialized;
+}
+EXPORT_SYMBOL(spcie_is_initialized);
+
+u32 spcie_get_chip_id(void)
+{
+ return spcie_chip_revision_id & 0xff0000;
+}
+EXPORT_SYMBOL(spcie_get_chip_id);
+
+u32 spcie_get_revision_id(void)
+{
+ return spcie_chip_revision_id & 0xffff;
+}
+EXPORT_SYMBOL(spcie_get_revision_id);
+
+u32 spcie_bar2_180000_read(u32 reg)
+{
+ return readl(sdev->bar2 + 0x180000 + reg);
+}
+EXPORT_SYMBOL(spcie_bar2_180000_read);
+
+void spcie_bar2_180000_write(u32 reg, u32 val)
+{
+ writel(val, sdev->bar2 + 0x180000 + reg);
+}
+EXPORT_SYMBOL(spcie_bar2_180000_write);
+
+u32 spcie_pervasive0_4000_read(u32 reg)
+{
+ return readl(sdev->pervasive0 + 0x4000 + reg);
+}
+EXPORT_SYMBOL(spcie_pervasive0_4000_read);
+
+static int spcie_init_dev(struct spcie_dev *sdev, int dev_ip)
+{
+ void __iomem *bar;
+ u32 offset0, offset1, offset2;
+ u32 val;
+ int retries = 10000;
+
+ switch (dev_ip) {
+ case 0:
+ bar = sdev->bar2;
+ offset0 = 0x142020;
+ offset1 = 0x142028;
+ offset2 = 0x180020;
+ break;
+ case 1:
+ bar = sdev->bar2;
+ offset0 = 0x143820;
+ offset1 = 0x143828;
+ offset2 = 0x18002c;
+ break;
+ case 2:
+ bar = sdev->bar2;
+ offset0 = 0x144820;
+ offset1 = 0x144828;
+ offset2 = 0x180030;
+ break;
+ case 3:
+ bar = sdev->bar2;
+ offset0 = 0x144020;
+ offset1 = 0x144028;
+ offset2 = 0x180024;
+ break;
+ case 4:
+ bar = sdev->pervasive0;
+ offset0 = 0x42420;
+ offset1 = 0x42428;
+ offset2 = 0x7010;
+ break;
+ }
+
+ writel(readl(bar + offset0) | 0x10, bar + offset0);
+
+ while (1) {
+ val = readl(bar + offset1);
+ if ((val & 0x10) == 0 && (val & 0x20) == 0 && (val & 0x40) == 0 && (val & 0x80) == 0)
+ break;
+ udelay(10);
+ if (!--retries) {
+ printk("[ERROR]: cannot stop the transaction(%X): %X\n", offset0, val);
+ break;
+ }
+ }
+
+ writel(readl(bar + offset0) | 0x1, bar + offset0);
+
+ if (dev_ip == 4) {
+ writel(1, sdev->pervasive0 + offset2);
+ writel(3, sdev->pervasive0 + 0x74b4);
+ } else {
+ writel(3, sdev->bar2 + offset2);
+
+ switch (dev_ip) {
+ case 0:
+ writel(1, sdev->pervasive0 + 0x74c8);
+ writel(0x1f, sdev->pervasive0 + 0x7c28);
+ break;
+ case 1:
+ writel(3, sdev->pervasive0 + 0x74c4);
+ writel(7, sdev->pervasive0 + 0x7c14);
+ break;
+ case 2:
+ writel(3, sdev->pervasive0 + 0x7498);
+ writel(7, sdev->pervasive0 + 0x7c18);
+ break;
+ case 3:
+ if (spcie_get_chip_id() == 0x110000) {
+ writel(7, sdev->pervasive0 + 0x74cc);
+ } else {
+ writel(1, sdev->pervasive0 + 0x74cc);
+ }
+ writel(0xf, sdev->pervasive0 + 0x7c1c);
+ break;
+ }
+ }
+
+ writel(readl(bar + offset0) & ~0x11, bar + offset0);
+
+ if (dev_ip == 4) {
+ writel(0, sdev->pervasive0 + offset2);
+ } else if (dev_ip == 0) {
+ writel(0, sdev->bar2 + offset2);
+
+ writel(readl(sdev->pervasive0 + 0x7c28) & ~8, sdev->pervasive0 + 0x7c28);
+ writel(readl(sdev->pervasive0 + 0x7c28) & ~1, sdev->pervasive0 + 0x7c28);
+
+ writel(1, sdev->bar2 + offset2);
+ writel(0, sdev->bar2 + offset2);
+
+ writel(readl(sdev->pervasive0 + 0x7c28) | 8, sdev->pervasive0 + 0x7c28);
+ writel(readl(sdev->pervasive0 + 0x7c28) | 1, sdev->pervasive0 + 0x7c28);
+
+ udelay(680);
+ }
+
+ return 0;
+}
+
+static int spcie_init(struct spcie_dev *sdev)
+{
+ writel(1, sdev->pervasive0 + 0x22004);
+ while ((readl(sdev->pervasive0 + 0x22000) & 7) != 4);
+
+ spcie_init_dev(sdev, 0);
+ if (spcie_get_chip_id() == 0x110000)
+ spcie_init_dev(sdev, 1);
+ spcie_init_dev(sdev, 2);
+ spcie_init_dev(sdev, 3);
+ spcie_init_dev(sdev, 4);
+
+ writel(1, sdev->bar2 + 0x18004c);
+ writel(1, sdev->pervasive0 + 0x7c08);
+
+ writel(0, sdev->bar2 + 0x18004c);
+ writel(0, sdev->pervasive0 + 0x22004);
+ while ((readl(sdev->pervasive0 + 0x22000) & 4) != 0);
+
+ return 0;
+}
+
+static int spcie_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+ u32 chip_revision, chip_id0, chip_id1;
+ char *chip_name, *rev_name;
+ int ret;
+
+ ret = pcim_enable_device(pdev);
+ if (ret)
+ return ret;
+
+ sdev = devm_kzalloc(&pdev->dev, sizeof(*sdev), GFP_KERNEL);
+ if (!sdev)
+ return -ENOMEM;
+
+ sdev->pdev = pdev;
+
+ sdev->bar2 = pcim_iomap(pdev, 2, 0);
+ if (!sdev->bar2)
+ return -ENOMEM;
+
+ sdev->pervasive0 = pcim_iomap(pdev, 4, 0);
+ if (!sdev->pervasive0)
+ return -ENOMEM;
+
+ pci_set_master(pdev);
+
+ chip_revision = readl(sdev->pervasive0 + 0x4000);
+ dev_info(&sdev->pdev->dev, "Chip revision: %08x\n", chip_revision);
+
+ chip_id0 = readl(sdev->pervasive0 + 0x4008);
+ dev_info(&sdev->pdev->dev, "Chip ID0: %08x\n", chip_id0);
+
+ chip_id1 = readl(sdev->pervasive0 + 0x4004);
+ dev_info(&sdev->pdev->dev, "Chip ID1: %08x\n", chip_id1);
+
+ if ((chip_revision & 0xff000000) == 0x11000000) {
+ chip_name = "Salina";
+ spcie_chip_revision_id = 0x110000;
+ } else if ((chip_revision & 0xff000000) == 0x12000000) {
+ chip_name = "Salina2";
+ spcie_chip_revision_id = 0x120000;
+ } else {
+ panic("unknown subsys %08x\n", chip_revision);
+ }
+
+ switch (chip_revision & 0xffff) {
+ case 0x100: rev_name = "A0"; break;
+ case 0x101: rev_name = "A1"; break;
+ case 0x200: rev_name = "B0"; break;
+ case 0x201: rev_name = "B1"; break;
+ case 0x300: rev_name = "C0"; break;
+ default:
+ panic("unknown subsys %08x\n", chip_revision);
+ }
+
+ spcie_chip_revision_id |= (chip_revision & 0xffff);
+
+ dev_info(&sdev->pdev->dev, "%s %s\n", chip_name, rev_name);
+
+ ret = spcie_init(sdev);
+ if (ret)
+ return ret;
+
+ ret = pci_alloc_irq_vectors(pdev, NUM_IRQS, NUM_IRQS, PCI_IRQ_MSI);
+ if (ret < 0)
+ return ret;
+
+ ret = spcie_icc_init(sdev);
+ if (ret) {
+ pci_free_irq_vectors(pdev);
+ return ret;
+ }
+
+ spcie_initialized = true;
+
+ pci_set_drvdata(pdev, sdev);
+ return 0;
+}
+
+static void spcie_remove(struct pci_dev *pdev)
+{
+ struct spcie_dev *sdev = pci_get_drvdata(pdev);
+ if (sdev) {
+ spcie_icc_remove(sdev);
+ pci_free_irq_vectors(pdev);
+ }
+}
+
+static void spcie_shutdown(struct pci_dev *pdev)
+{
+ struct spcie_dev *sdev = pci_get_drvdata(pdev);
+ if (sdev) {
+ spcie_icc_shutdown(sdev);
+ }
+}
+
+static const struct pci_device_id spcie_ids[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_SONY, PCI_DEVICE_ID_SPCIE) },
+ { 0, }
+};
+MODULE_DEVICE_TABLE(pci, spcie_ids);
+
+static struct pci_driver spcie_driver = {
+ .name = "spcie",
+ .id_table = spcie_ids,
+ .probe = spcie_probe,
+ .remove = spcie_remove,
+ .shutdown = spcie_shutdown,
+};
+
+module_pci_driver(spcie_driver);
+
+MODULE_AUTHOR("Andy Nguyen");
+MODULE_DESCRIPTION("PlayStation 5 Salina PCI Express glue driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/ps5/svm.c b/drivers/ps5/svm.c
new file mode 100644
index 000000000000..b9e7def39ef7
--- /dev/null
+++ b/drivers/ps5/svm.c
@@ -0,0 +1,171 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include <linux/module.h>
+#include <linux/ps5.h>
+
+#include <asm/svm.h>
+#include <asm/desc.h>
+#include <asm/io.h>
+#include <asm/debugreg.h>
+
+void svm_run_guest(u64 a0, u64 a1, u64 a2, u64 a3, u64 vmcb_phys);
+
+static DEFINE_SPINLOCK(svm_execute_lock);
+
+static void svm_set_vmcb_seg(struct vmcb_seg *s, u16 selector, u64 base, u32 limit,
+ struct desc_struct *d)
+{
+ s->base = base;
+ s->limit = limit;
+ s->selector = selector;
+ s->attrib = 0;
+
+ if (d) {
+ if (d->g)
+ s->limit = (limit << 12) | 0xfff;
+
+ s->attrib |= (d->type & SVM_SELECTOR_TYPE_MASK);
+ s->attrib |= (d->s & 1) << SVM_SELECTOR_S_SHIFT;
+ s->attrib |= (d->dpl & 3) << SVM_SELECTOR_DPL_SHIFT;
+ s->attrib |= (d->p & 1) << SVM_SELECTOR_P_SHIFT;
+ s->attrib |= (d->avl & 1) << SVM_SELECTOR_AVL_SHIFT;
+ s->attrib |= (d->l & 1) << SVM_SELECTOR_L_SHIFT;
+ s->attrib |= (d->d & 1) << SVM_SELECTOR_DB_SHIFT;
+ s->attrib |= (d->g & 1) << SVM_SELECTOR_G_SHIFT;
+ }
+}
+
+static void svm_set_segment(struct vmcb_seg *seg, u16 selector, struct desc_ptr *desc)
+{
+ struct desc_struct *d = NULL;
+ u64 base = 0;
+ u32 limit = 0;
+
+ if (selector) {
+ d = &((struct desc_struct *)desc->address)[selector >> 3];
+ base = get_desc_base(d);
+ limit = get_desc_limit(d);
+ }
+
+ svm_set_vmcb_seg(seg, selector, base, limit, d);
+}
+
+static void svm_guest_entry(void)
+{
+ asm volatile(
+ ANNOTATE_RETPOLINE_SAFE "\n\t"
+ "call *%%rax\n\t"
+ "vmmcall\n\t"
+ : ASM_CALL_CONSTRAINT
+ :
+ : "memory"
+ );
+}
+
+static void svm_init_vmcb(struct vmcb *vmcb, void *guest_func, void *guest_stack)
+{
+ struct vmcb_save_area *save = &vmcb->save;
+ struct vmcb_control_area *ctrl = &vmcb->control;
+ u64 vmcb_phys = virt_to_phys(vmcb);
+ struct desc_ptr gdt_ptr, idt_ptr;
+ u16 sel;
+ unsigned long dr6, dr7;
+
+ memset(vmcb, 0, PAGE_SIZE);
+
+ asm volatile("vmsave %0" : : "a"(vmcb_phys) : "memory");
+
+ native_store_gdt(&gdt_ptr);
+ store_idt(&idt_ptr);
+
+ savesegment(es, sel); svm_set_segment(&save->es, sel, &gdt_ptr);
+ savesegment(cs, sel); svm_set_segment(&save->cs, sel, &gdt_ptr);
+ savesegment(ss, sel); svm_set_segment(&save->ss, sel, &gdt_ptr);
+ savesegment(ds, sel); svm_set_segment(&save->ds, sel, &gdt_ptr);
+
+ svm_set_vmcb_seg(&save->gdtr, 0, gdt_ptr.address, gdt_ptr.size, NULL);
+ svm_set_vmcb_seg(&save->idtr, 0, idt_ptr.address, idt_ptr.size, NULL);
+
+ save->cr0 = read_cr0();
+ save->cr2 = read_cr2();
+ save->cr3 = __read_cr3();
+ save->cr4 = __read_cr4();
+
+ get_debugreg(dr6, 6);
+ get_debugreg(dr7, 7);
+ save->dr6 = dr6;
+ save->dr7 = dr7;
+
+ save->rflags = native_save_fl();
+
+ save->rip = (u64)svm_guest_entry;
+ save->rax = (u64)guest_func;
+ save->rsp = (u64)guest_stack + PAGE_SIZE;
+
+ rdmsrl(MSR_EFER, save->efer);
+ rdmsrl(MSR_IA32_CR_PAT, save->g_pat);
+
+ __set_bit(INTERCEPT_VMRUN, (unsigned long *)ctrl->intercepts);
+ __set_bit(INTERCEPT_VMMCALL, (unsigned long *)ctrl->intercepts);
+
+ ctrl->asid = 1;
+ ctrl->tlb_ctl = TLB_CONTROL_FLUSH_ASID;
+}
+
+u64 svm_execute_guest(void *guest_func, u64 a0, u64 a1, u64 a2, u64 a3)
+{
+ unsigned long flags;
+ u64 efer, hsave_pa;
+ u64 exit_code;
+ u64 ret = -1;
+ struct vmcb *vmcb = NULL;
+ void *hsave_area = NULL;
+ void *guest_stack = NULL;
+
+ vmcb = (struct vmcb *)get_zeroed_page(GFP_KERNEL);
+ if (!vmcb)
+ goto err_free;
+
+ hsave_area = (void *)get_zeroed_page(GFP_KERNEL);
+ if (!hsave_area)
+ goto err_free;
+
+ guest_stack = (void *)get_zeroed_page(GFP_KERNEL);
+ if (!guest_stack)
+ goto err_free;
+
+ spin_lock_irqsave(&svm_execute_lock, flags);
+
+ rdmsrl(MSR_EFER, efer);
+ wrmsrl(MSR_EFER, efer | EFER_SVME);
+
+ rdmsrl(MSR_VM_HSAVE_PA, hsave_pa);
+ wrmsrl(MSR_VM_HSAVE_PA, virt_to_phys(hsave_area));
+
+ svm_init_vmcb(vmcb, guest_func, guest_stack);
+
+ svm_run_guest(a0, a1, a2, a3, virt_to_phys(vmcb));
+
+ exit_code = vmcb->control.exit_code;
+ if (exit_code == SVM_EXIT_VMMCALL) {
+ ret = vmcb->save.rax;
+ } else {
+ pr_warn("svm: unexpected exit code 0x%llx\n", exit_code);
+ }
+
+ wrmsrl(MSR_VM_HSAVE_PA, hsave_pa);
+ wrmsrl(MSR_EFER, efer);
+
+ spin_unlock_irqrestore(&svm_execute_lock, flags);
+
+err_free:
+ if (guest_stack)
+ free_page((unsigned long)guest_stack);
+ if (hsave_area)
+ free_page((unsigned long)hsave_area);
+ if (vmcb)
+ free_page((unsigned long)vmcb);
+
+ return ret;
+}
+EXPORT_SYMBOL(svm_execute_guest);
diff --git a/drivers/ps5/tpcie.c b/drivers/ps5/tpcie.c
new file mode 100644
index 000000000000..7e933c30fc3e
--- /dev/null
+++ b/drivers/ps5/tpcie.c
@@ -0,0 +1,305 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/console.h>
+#include <linux/module.h>
+#include <linux/msi.h>
+#include <linux/pci.h>
+#include <linux/ps5.h>
+#include <linux/serial_core.h>
+#include <linux/tty_flip.h>
+
+#define PCI_DEVICE_ID_TPCIE 0x90ec
+#define TPCIE_SUBFUNC_UART 6
+#define NUM_IRQS 8
+
+#define UART_OFFSET 0x1010100
+
+struct tpcie_dev;
+
+struct tpcie_uart_dev {
+ struct pci_dev *pdev;
+ struct tpcie_dev *tdev;
+ void __iomem *uart_base;
+ struct tty_driver *tty_drv;
+ struct tty_port tty_port;
+};
+
+struct tpcie_dev {
+ struct pci_dev *pdev;
+ void __iomem *bar4;
+ struct tpcie_uart_dev *uart_dev;
+};
+
+static struct tpcie_uart_dev *uart_dev;
+
+static bool tpcie_uart_rx_ready(void)
+{
+ return (readl(uart_dev->uart_base + 0xc) & 0x10) != 0;
+}
+
+static bool tpcie_uart_tx_ready(void)
+{
+ return (readl(uart_dev->uart_base + 0xc) & 0x800) == 0;
+}
+
+static void tpcie_uart_putc(char c)
+{
+ unsigned timeout = 0xffff;
+ while (!tpcie_uart_tx_ready() && --timeout)
+ cpu_relax();
+ writel(c, uart_dev->uart_base + 0x4);
+}
+
+static void tpcie_uart_write(struct console *con, const char *s, unsigned int n)
+{
+ int i;
+ for (i = 0; i < n; ++i) {
+ if (s[i] == '\n')
+ tpcie_uart_putc('\r');
+ tpcie_uart_putc(s[i]);
+ }
+}
+
+static ssize_t tpcie_uart_tty_write(struct tty_struct *tty, const u8 *buf, size_t count)
+{
+ int i;
+ for (i = 0; i < count; i++) {
+ tpcie_uart_putc(buf[i]);
+ }
+ tty_port_tty_wakeup(&uart_dev->tty_port);
+ return count;
+}
+
+static unsigned int tpcie_uart_tty_write_room(struct tty_struct *tty)
+{
+ return 2048;
+}
+
+static int tpcie_uart_tty_open(struct tty_struct *tty, struct file *file)
+{
+ return tty_port_open(&uart_dev->tty_port, tty, file);
+}
+
+static void tpcie_uart_tty_close(struct tty_struct *tty, struct file *file)
+{
+ tty_port_close(&uart_dev->tty_port, tty, file);
+}
+
+static void tpcie_uart_tty_hangup(struct tty_struct *tty)
+{
+ tty_port_hangup(&uart_dev->tty_port);
+}
+
+static struct tty_operations tpcie_uart_tty_ops = {
+ .open = tpcie_uart_tty_open,
+ .close = tpcie_uart_tty_close,
+ .write = tpcie_uart_tty_write,
+ .write_room = tpcie_uart_tty_write_room,
+ .hangup = tpcie_uart_tty_hangup,
+};
+
+static const struct tty_port_operations tpcie_uart_port_ops = {};
+
+static struct tty_driver *tpcie_uart_device(struct console *c, int *index)
+{
+ *index = 0;
+ return uart_dev->tty_drv;
+}
+
+static struct console tpcie_uart_console = {
+ .name = "ttyTitania",
+ .device = tpcie_uart_device,
+ .write = tpcie_uart_write,
+ .flags = CON_PRINTBUFFER,
+ .index = -1,
+};
+
+static irqreturn_t uart_interrupt(int irq, void *dev)
+{
+ u8 ch;
+ while (tpcie_uart_rx_ready()) {
+ ch = readl(uart_dev->uart_base + 0x0);
+ tty_insert_flip_char(&uart_dev->tty_port, ch, TTY_NORMAL);
+ }
+ tty_flip_buffer_push(&uart_dev->tty_port);
+ return IRQ_HANDLED;
+}
+
+static void tcpie_config_msi(struct tpcie_dev *tdev, int subfunc, struct msi_msg *msg)
+{
+ writel(0xffffffff, tdev->bar4 + 0x120214);
+ writel(0, tdev->bar4 + 0x12020c);
+
+ writel(msg->address_lo, tdev->bar4 + 0x120204);
+ writel(msg->address_hi, tdev->bar4 + 0x120208);
+
+ writel(msg->data & ~0x1f, tdev->bar4 + 0x120210);
+ if (subfunc == TPCIE_SUBFUNC_UART) {
+ writel(msg->data & 0x1f, tdev->bar4 + 0x120230);
+ }
+ writel(msg->data & 0x1f, tdev->bar4 + 0x120210 + subfunc * 4);
+
+ writel(0x33, tdev->bar4 + 0x120200);
+}
+
+static int tpcie_uart_init(struct tpcie_dev *tdev)
+{
+ struct tty_driver *drv;
+ struct msi_msg msg;
+ int vector, ret;
+
+ uart_dev = devm_kzalloc(&tdev->pdev->dev, sizeof(*uart_dev), GFP_KERNEL);
+ if (!uart_dev)
+ return -ENOMEM;
+
+ uart_dev->pdev = tdev->pdev;
+ uart_dev->tdev = tdev;
+ tdev->uart_dev = uart_dev;
+ uart_dev->uart_base = tdev->bar4 + UART_OFFSET;
+
+ drv = tty_alloc_driver(1, TTY_DRIVER_REAL_RAW);
+ if (IS_ERR(drv))
+ return PTR_ERR(drv);
+
+ drv->driver_name = "tpcie_uart";
+ drv->name = "ttyTitania";
+ drv->type = TTY_DRIVER_TYPE_SERIAL;
+ drv->major = 0;
+ drv->minor_start = 0;
+ drv->num = 1;
+ drv->subtype = SERIAL_TYPE_NORMAL;
+ drv->flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW;
+ drv->init_termios = tty_std_termios;
+ tty_set_operations(drv, &tpcie_uart_tty_ops);
+ uart_dev->tty_drv = drv;
+
+ tty_port_init(&uart_dev->tty_port);
+ uart_dev->tty_port.ops = &tpcie_uart_port_ops;
+ tty_port_link_device(&uart_dev->tty_port, drv, 0);
+
+ ret = tty_register_driver(drv);
+ if (ret) {
+ tty_driver_kref_put(drv);
+ return ret;
+ }
+
+ register_console(&tpcie_uart_console);
+
+ /* Request IRQ for uart subfunc */
+ vector = pci_irq_vector(tdev->pdev, TPCIE_SUBFUNC_UART);
+ ret = devm_request_irq(&tdev->pdev->dev, vector, uart_interrupt, 0, "uart", uart_dev);
+ if (ret)
+ goto err_unreg_tty;
+
+ /* Special MSI configuration */
+ ret = irq_chip_compose_msi_msg(irq_get_irq_data(vector), &msg);
+ if (ret)
+ goto err_unreg_tty;
+
+ tcpie_config_msi(tdev, TPCIE_SUBFUNC_UART, &msg);
+
+ /* Enable IRQs */
+ writel(0x10, uart_dev->uart_base + 0x8);
+
+ return 0;
+
+err_unreg_tty:
+ unregister_console(&tpcie_uart_console);
+ tty_unregister_driver(drv);
+ tty_driver_kref_put(drv);
+ return ret;
+}
+
+static void tpcie_uart_remove(struct tpcie_dev *tdev)
+{
+ unregister_console(&tpcie_uart_console);
+
+ if (uart_dev->tty_drv) {
+ tty_unregister_driver(uart_dev->tty_drv);
+ tty_driver_kref_put(uart_dev->tty_drv);
+ }
+
+ tty_port_destroy(&uart_dev->tty_port);
+}
+
+static void tpcie_uart_shutdown(struct tpcie_dev *tdev)
+{
+ /* Disable IRQs */
+ writel(0, uart_dev->uart_base + 0x8);
+}
+
+static int tpcie_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+ struct tpcie_dev *tdev;
+ int ret;
+
+ ret = pcim_enable_device(pdev);
+ if (ret)
+ return ret;
+
+ tdev = devm_kzalloc(&pdev->dev, sizeof(*tdev), GFP_KERNEL);
+ if (!tdev)
+ return -ENOMEM;
+
+ tdev->pdev = pdev;
+ tdev->bar4 = pcim_iomap(pdev, 4, 0);
+ if (!tdev->bar4)
+ return -ENOMEM;
+
+ pci_set_master(pdev);
+
+ ret = pci_alloc_irq_vectors(pdev, NUM_IRQS, NUM_IRQS, PCI_IRQ_MSI);
+ if (ret < 0)
+ return ret;
+
+ writel(0xf, tdev->bar4 + 0x1142000 + 0x100);
+ writel(0xf, tdev->bar4 + 0x1142000 + 0x104);
+
+ ret = tpcie_uart_init(tdev);
+ if (ret) {
+ pci_free_irq_vectors(pdev);
+ return ret;
+ }
+
+ pci_set_drvdata(pdev, tdev);
+ return 0;
+}
+
+static void tpcie_remove(struct pci_dev *pdev)
+{
+ struct tpcie_dev *tdev = pci_get_drvdata(pdev);
+ if (tdev) {
+ tpcie_uart_remove(tdev);
+ pci_free_irq_vectors(pdev);
+ }
+}
+
+static void tpcie_shutdown(struct pci_dev *pdev)
+{
+ struct tpcie_dev *tdev = pci_get_drvdata(pdev);
+ if (tdev) {
+ tpcie_uart_shutdown(tdev);
+ }
+}
+
+static const struct pci_device_id tpcie_ids[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_SONY, PCI_DEVICE_ID_TPCIE) },
+ { 0, }
+};
+MODULE_DEVICE_TABLE(pci, tpcie_ids);
+
+static struct pci_driver tpcie_driver = {
+ .name = "tpcie",
+ .id_table = tpcie_ids,
+ .probe = tpcie_probe,
+ .remove = tpcie_remove,
+ .shutdown = tpcie_shutdown,
+};
+
+module_pci_driver(tpcie_driver);
+
+MODULE_AUTHOR("Andy Nguyen");
+MODULE_DESCRIPTION("PlayStation 5 Titania PCI Express glue driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/ps5/vmenter.S b/drivers/ps5/vmenter.S
new file mode 100644
index 000000000000..e3fd6f3e59b6
--- /dev/null
+++ b/drivers/ps5/vmenter.S
@@ -0,0 +1,32 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#include <linux/linkage.h>
+#include <asm/asm.h>
+
+.section .noinstr.text, "ax"
+
+SYM_FUNC_START(svm_run_guest)
+ push %_ASM_BP
+ mov %_ASM_SP, %_ASM_BP
+ push %r15
+ push %r14
+ push %r13
+ push %r12
+ push %_ASM_BX
+
+ mov %r8, %_ASM_AX
+
+ clgi
+ vmload %_ASM_AX
+ vmrun %_ASM_AX
+ vmsave %_ASM_AX
+ stgi
+
+ pop %_ASM_BX
+ pop %r12
+ pop %r13
+ pop %r14
+ pop %r15
+ pop %_ASM_BP
+ RET
+SYM_FUNC_END(svm_run_guest)
diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile
index a07e7ba9cd53..4c020957b7a7 100644
--- a/drivers/usb/host/Makefile
+++ b/drivers/usb/host/Makefile
@@ -71,6 +71,7 @@ obj-$(CONFIG_USB_UHCI_HCD) += uhci-hcd.o
obj-$(CONFIG_USB_FHCI_HCD) += fhci.o
obj-$(CONFIG_USB_XHCI_HCD) += xhci-hcd.o
obj-$(CONFIG_USB_XHCI_PCI) += xhci-pci.o
+obj-$(CONFIG_USB_XHCI_PCI) += xhci-ps5.o
obj-$(CONFIG_USB_XHCI_PCI_RENESAS) += xhci-pci-renesas.o
obj-$(CONFIG_USB_XHCI_PLATFORM) += xhci-plat-hcd.o
obj-$(CONFIG_USB_XHCI_HISTB) += xhci-histb.o
diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c
index 585b2f3117b0..16d5e2178ae0 100644
--- a/drivers/usb/host/xhci-pci.c
+++ b/drivers/usb/host/xhci-pci.c
@@ -18,6 +18,7 @@
#include "xhci.h"
#include "xhci-trace.h"
#include "xhci-pci.h"
+#include "xhci-ps5.h"
#define SSIC_PORT_NUM 2
#define SSIC_PORT_CFG2 0x880c
@@ -94,6 +95,9 @@
#define PCI_DEVICE_ID_ASMEDIA_3042_XHCI 0x3042
#define PCI_DEVICE_ID_ASMEDIA_3242_XHCI 0x3242
+#define PCI_VENDOR_ID_SONY 0x104d
+#define PCI_DEVICE_ID_PS5_SALINA_XHCI 0x9108
+
static const char hcd_name[] = "xhci_hcd";
static struct hc_driver __read_mostly xhci_pci_hc_driver;
@@ -511,6 +515,13 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
if (xhci->hci_version >= 0x120)
xhci->quirks |= XHCI_DEFAULT_PM_RUNTIME_ALLOW;
+ if (pdev->vendor == PCI_VENDOR_ID_SONY &&
+ pdev->device == PCI_DEVICE_ID_PS5_SALINA_XHCI) {
+ xhci_dbg_trace(xhci, trace_xhci_dbg_init, "%s detected Salina USB PHY setting quirk", __func__);
+ xhci->quirks |= XHCI_PS5_SALINA_PHY;
+ xhci->quirks |= XHCI_WRITE_64_HI_LO;
+ }
+
if (xhci->quirks & XHCI_RESET_ON_RESUME)
xhci_dbg_trace(xhci, trace_xhci_dbg_quirks,
"QUIRK: Resetting on resume");
@@ -575,6 +586,13 @@ static int xhci_pci_setup(struct usb_hcd *hcd)
/* imod_interval is the interrupt moderation value in nanoseconds. */
xhci->imod_interval = 40000;
+ if (pdev->vendor == PCI_VENDOR_ID_SONY &&
+ pdev->device == PCI_DEVICE_ID_PS5_SALINA_XHCI) {
+ retval = xhci_salina_init(pdev);
+ if (retval)
+ return retval;
+ }
+
retval = xhci_gen_setup(hcd, xhci_pci_quirks);
if (retval)
return retval;
@@ -713,6 +731,11 @@ void xhci_pci_remove(struct pci_dev *dev)
xhci = hcd_to_xhci(pci_get_drvdata(dev));
set_power_d3 = xhci->quirks & XHCI_SPURIOUS_WAKEUP;
+ if(xhci->quirks & XHCI_PS5_SALINA_PHY) {
+ salina_stop_xhci_poller();
+ xhci_salina_exit();
+ }
+
xhci->xhc_state |= XHCI_STATE_REMOVING;
if (pci_choose_state(dev, PMSG_SUSPEND) == PCI_D0)
@@ -945,6 +968,7 @@ static const struct pci_device_id pci_ids[] = {
/* handle any USB 3.0 xHCI controller */
{ PCI_DEVICE_CLASS(PCI_CLASS_SERIAL_USB_XHCI, ~0),
},
+ { PCI_DEVICE(PCI_VENDOR_ID_SONY, PCI_DEVICE_ID_PS5_SALINA_XHCI) },
{ /* end: all zeroes */ }
};
MODULE_DEVICE_TABLE(pci, pci_ids);
diff --git a/drivers/usb/host/xhci-ps5.c b/drivers/usb/host/xhci-ps5.c
new file mode 100644
index 000000000000..b1c2ff265c7e
--- /dev/null
+++ b/drivers/usb/host/xhci-ps5.c
@@ -0,0 +1,516 @@
+/*
+* Playstation 5 Salina XHCI driver helper
+* Author: https://github.com/c0w-ar
+*/
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/pci.h>
+#include <linux/types.h>
+#include <linux/io.h>
+#include <linux/usb.h>
+#include <linux/usb/hcd.h>
+#include <linux/workqueue.h>
+#include <asm/delay.h>
+#include "xhci-ps5.h"
+#include "xhci.h"
+#include "xhci-trace.h"
+#include "xhci-ring.h"
+
+/* External SPCIE driver functions */
+extern bool spcie_is_initialized(void);
+extern u32 spcie_get_chip_id(void);
+extern u32 spcie_bar2_180000_read(u32 reg);
+extern void spcie_bar2_180000_write(u32 reg, u32 val);
+extern u32 spcie_pervasive0_4000_read(u32 reg);
+
+#define SALINA_XHCI_BAR_SIZE 0x140000
+#define SALINA_POLL_INTERVAL_MS 20
+
+struct salina_xhci_dev {
+ void __iomem *spcie_bar2;
+ void __iomem *spcie_pervasive0;
+ void __iomem *xhci_bar;
+ u32 revision;
+};
+static struct salina_xhci_dev salina_xhci;
+
+struct salina_xhci_poller {
+ struct xhci_hcd *xhci;
+ struct delayed_work work;
+ bool running;
+};
+static struct salina_xhci_poller salina_poll;
+
+static int dev_ioremap_bar(struct pci_dev *dev, int bar_nr, resource_size_t min_size, void __iomem **bar) {
+ resource_size_t start = pci_resource_start(dev, bar_nr);
+ resource_size_t len = pci_resource_len(dev, bar_nr);
+
+ if (start == 0) {
+ return -EINVAL;
+ }
+
+ if (len < min_size) {
+ return -ENODEV;
+ }
+
+ *bar = ioremap(start, min_size);
+ if (!*bar) {
+ pr_err("Could not ioremap memory\n");
+ release_mem_region(start, min_size);
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+static void unmap_bar(void) {
+ if(salina_xhci.xhci_bar) {
+ iounmap(salina_xhci.xhci_bar);
+ salina_xhci.xhci_bar = NULL;
+ }
+}
+
+static int init_bar(struct pci_dev *own_pdev) {
+ int ret = dev_ioremap_bar(own_pdev, 0, SALINA_XHCI_BAR_SIZE, &salina_xhci.xhci_bar);
+ if (ret)
+ goto unmap;
+ return 0;
+
+unmap:
+ unmap_bar();
+ return ret;
+}
+
+static u32 phys_readl(u64 addr) {
+ void __iomem *ptr = ioremap(addr, 4);
+ if (!ptr) {
+ pr_err("Could not ioremap memory\n");
+ return 0;
+ }
+ u32 val = readl(ptr);
+ iounmap(ptr);
+ return val;
+}
+
+static u8 usb_get_length(u8 usb_n) {
+ return (u8)((phys_readl(0x9bf44) >> (usb_n*8))&0x1f);
+}
+
+inline void spcie_phy_bit_set(u32 reg, u32 bit) {
+ u32 val_old = spcie_bar2_180000_read(reg);
+ spcie_bar2_180000_write(reg, val_old | BIT(bit));
+}
+
+inline void spcie_phy_bit_unset(u32 reg, u32 bit) {
+ u32 val_old = spcie_bar2_180000_read(reg);
+ spcie_bar2_180000_write(reg, val_old & ~BIT(bit));
+}
+
+inline u32 spcie_config_read(u32 reg) {
+ return spcie_pervasive0_4000_read(reg);
+}
+
+inline u32 xhci_read(u64 offset, u32 reg) {
+ if (salina_xhci.xhci_bar)
+ return readl(salina_xhci.xhci_bar + offset + reg);
+ else
+ return -1;
+}
+
+inline void xhci_write(u64 offset, u32 reg, u32 val) {
+ if (salina_xhci.xhci_bar)
+ writel(val, salina_xhci.xhci_bar + offset + reg);
+}
+
+inline void xhci_or(u64 offset, u32 reg, u32 val) {
+ if (salina_xhci.xhci_bar) {
+ u32 val_old = readl(salina_xhci.xhci_bar + offset + reg);
+ writel(val_old | val, salina_xhci.xhci_bar + offset + reg);
+ }
+}
+
+inline void xhci_and(u64 offset, u32 reg, u32 val) {
+ if (salina_xhci.xhci_bar) {
+ u32 val_old = readl(salina_xhci.xhci_bar + offset + reg);
+ writel(val_old & val, salina_xhci.xhci_bar + offset + reg);
+ }
+}
+
+inline void xhci_bit_set(u64 offset, u32 reg, u32 bit) {
+ if (salina_xhci.xhci_bar) {
+ u32 val_old = readl(salina_xhci.xhci_bar + offset + reg);
+ writel(val_old | BIT(bit), salina_xhci.xhci_bar + offset + reg);
+ }
+}
+
+inline void xhci_bit_unset(u64 offset, u32 reg, u32 bit) {
+ if (salina_xhci.xhci_bar) {
+ u32 val_old = readl(salina_xhci.xhci_bar + offset + reg);
+ writel(val_old & ~BIT(bit), salina_xhci.xhci_bar + offset + reg);
+ }
+}
+
+inline void xhci_bit_toggle(u64 offset, u32 reg, u32 bit) {
+ xhci_bit_set(offset, reg, bit);
+ xhci_bit_unset(offset, reg, bit);
+}
+
+static inline u64 usb_phy_offset (u8 usb_n) {
+ switch (usb_n) {
+ case 0: return 0x120000;
+ case 1: return 0x124000;
+ case 2: return 0x128000;
+ default: return 0x120000;
+ }
+}
+
+static inline u32 usb_trace_trim(u8 usb_n, u32 usb_length) {
+ if (usb_length < 3)
+ return 8;
+ else if (usb_length < 6)
+ return 7;
+ else if (usb_length < 8)
+ return 6;
+ else if (usb_length < 10)
+ return 5;
+ else if (usb_length < 13)
+ return 4;
+ else {
+ switch (usb_n) {
+ case 0: return 4;
+ case 1: return 6;
+ case 2: return 7;
+ default: return 4;
+ }
+ }
+}
+
+static void salina_usb_phy_config_step_1(u8 usb_n) {
+
+ u64 offset = usb_phy_offset(usb_n);
+ u32 val32;
+ u32 usb_efuse;
+ u32 usb_length;
+
+ val32 = spcie_config_read(0x6c);
+ if ((val32 >> 0x19 & val32 >> 0x11 & 1) == 0) {
+ printk("[USB%d] eFuse not blown for usb\n", usb_n);
+ usb_efuse = 0x98;
+ }
+ else {
+ usb_efuse = (spcie_config_read(0x44) >> (usb_n*5+0x10)) & 0x1f;
+ }
+
+ xhci_write(offset, 0x800, 0x480a);
+
+ xhci_write(offset, 0x814, 0x10a01000);
+
+ xhci_bit_unset(offset, 0x818, 23);
+
+ xhci_bit_set(offset, 0x800, 5);
+
+ xhci_bit_unset(offset, 0x868, 18);
+
+ xhci_and(offset, 0x804, 0xff07ffff);
+ xhci_or(offset, 0x804, usb_efuse << 0x13);
+
+ usb_length = usb_trace_trim(usb_n, usb_get_length(usb_n));
+
+ xhci_and(offset, 0x818, 0xffffff0f);
+ xhci_or(offset, 0x818, 0xa0);
+
+ xhci_and(offset, 0x818, 0xfffffff0);
+ xhci_or(offset, 0x818, usb_length);
+}
+
+static int salina_usb_phy_config_step_2(u8 usb_n) {
+
+ u64 offset = usb_phy_offset(usb_n);
+
+ xhci_bit_set(offset, 0x814, 15);
+
+ udelay(2);
+
+ xhci_bit_set(offset, 0x110, 8);
+
+ xhci_and(offset, 0x100, 0xff000000);
+ xhci_or(offset, 0x100, 0x400);
+
+ xhci_bit_set(offset, 0x100, 24);
+
+ int attemps = 100;
+ u32 measure;
+ do {
+ measure = xhci_read(offset, 0x10c);
+ udelay(2);
+ if (measure!=0) break;
+ attemps--;
+ } while(attemps!=0);
+
+ xhci_bit_unset(offset, 0x100, 24);
+
+ xhci_bit_unset(offset, 0x110, 8);
+
+ if (!measure) {
+ printk("Something went wrong while waiting for USB init\n");
+ return -1;
+ }
+
+ u32 calibration = (u32)((0xb9000 / (u64)measure) / 1000);
+
+ xhci_and(offset, 0x814, 0xffff8fff);
+ xhci_or(offset, 0x814, calibration<<12);
+
+ xhci_bit_unset(offset, 0x814, 15);
+
+ return 0;
+}
+
+static void salina_usb_phy_config_step_3(u8 usb_n) {
+ u32 offset = usb_phy_offset(usb_n);
+ xhci_bit_set(offset, 0x800, 0);
+ xhci_bit_unset(offset, 0x808, 17);
+ xhci_bit_set(offset, 0x880, 0);
+}
+
+static void salina_usb_phy_config_step_4(void) {
+ xhci_and(0, 0xc100, 0xfffffff0);
+ xhci_or(0, 0xc100, 0xe);
+ xhci_write(0, 0xc12c, 0x7fc0c010);
+ xhci_write(0, 0xc200, 0x1548);
+ if (salina_xhci.revision == 0x110000) {
+ xhci_write(0, 0xc204, 0x1548);
+ xhci_write(0, 0xc208, 0x1548);
+ }
+}
+
+static int xhci_salina_phy_init(void) {
+
+ spcie_phy_bit_set(0x24, 1);
+ spcie_phy_bit_set(0x24, 0);
+ spcie_phy_bit_unset(0x24, 1);
+
+ salina_usb_phy_config_step_1(0);
+ if (salina_xhci.revision == 0x110000) {
+ salina_usb_phy_config_step_1(1);
+ salina_usb_phy_config_step_1(2);
+ }
+
+ spcie_phy_bit_unset(0x24, 0);
+
+ udelay(2000);
+
+ if(salina_usb_phy_config_step_2(0)) return -1;
+ if (salina_xhci.revision == 0x110000) {
+ if(salina_usb_phy_config_step_2(1)) return -1;
+ if(salina_usb_phy_config_step_2(2)) return -1;
+ }
+
+ salina_usb_phy_config_step_3(0);
+ if (salina_xhci.revision == 0x110000) {
+ salina_usb_phy_config_step_3(1);
+ salina_usb_phy_config_step_3(2);
+ }
+
+ xhci_bit_unset(0x100000, 0x4, 0);
+
+ salina_usb_phy_config_step_4();
+
+ return 0;
+}
+
+int xhci_salina_init(struct pci_dev *pdev) {
+
+ int ret;
+
+ if (!spcie_is_initialized()) {
+ dev_warn(&pdev->dev, "spcie not initialized, deferring\n");
+ return -EPROBE_DEFER;
+ }
+
+ salina_xhci.revision = spcie_get_chip_id();
+ if (salina_xhci.revision!=0x110000 && salina_xhci.revision!=0x120000) {
+ dev_warn(&pdev->dev, "PS5 Salina revision unknown %08x\n", salina_xhci.revision);
+ return ENODEV;
+ }
+
+ ret = init_bar(pdev);
+ if (ret) {
+ pr_err("PS5 Salina could not map BAR\n");
+ return ret;
+ }
+
+ xhci_salina_phy_init();
+
+ dev_info(&pdev->dev, "PS5 Salina xHCI PHY initialized\n");
+ return 0;
+}
+
+int xhci_salina_reset(struct xhci_hcd *xhci, u64 timeout_us) {
+
+ u32 state;
+ int ret;
+
+ if (salina_xhci.revision == 0x110000) {
+ xhci_bit_unset(0x100000, 0x0, 2);
+ }
+
+ state = readl(&xhci->op_regs->status);
+
+ if (state == ~(u32)0) {
+ if (!(xhci->xhc_state & XHCI_STATE_DYING))
+ xhci_warn(xhci, "Host not accessible, reset failed.\n");
+ return -ENODEV;
+ }
+
+ if ((state & STS_HALT) == 0) {
+ xhci_warn(xhci, "Host controller not halted, aborting reset.\n");
+ return 0;
+ }
+
+ xhci_info(xhci, "// Reset the HC on custom Salina Reset");
+ writel(CMD_RESET, &xhci->op_regs->command);
+
+ udelay(1000);
+
+ ret = xhci_handshake(&xhci->op_regs->command, CMD_RESET, 0, timeout_us);
+ if (ret)
+ return ret;
+
+ ret = xhci_handshake(&xhci->op_regs->status, STS_CNR, 0, timeout_us);
+ if (ret)
+ return ret;
+
+ if (salina_xhci.revision == 0x110000) {
+ xhci_bit_toggle(0x100000, 0x0, 1);
+ xhci_bit_toggle(0x100000, 0x0, 17);
+ xhci_bit_toggle(0x100000, 0x0, 25);
+ udelay(10000);
+ udelay(10000);
+ udelay(10000);
+ }
+
+ xhci_bit_unset(0x100000, 0x0, 1);
+ udelay(10000);
+ udelay(10000);
+
+ if (salina_xhci.revision == 0x110000) {
+ xhci_bit_set(0x100000, 0x0, 2);
+ udelay(10000);
+ udelay(10000);
+ }
+
+ salina_usb_phy_config_step_4();
+
+ // Reset software state
+ xhci->usb2_rhub.bus_state.port_c_suspend = 0;
+ xhci->usb2_rhub.bus_state.suspended_ports = 0;
+ xhci->usb2_rhub.bus_state.resuming_ports = 0;
+ xhci->usb3_rhub.bus_state.port_c_suspend = 0;
+ xhci->usb3_rhub.bus_state.suspended_ports = 0;
+ xhci->usb3_rhub.bus_state.resuming_ports = 0;
+
+ return 0;
+}
+
+void xhci_salina_exit(void)
+{
+ unmap_bar();
+}
+
+static bool ring_has_event_pending(struct xhci_ring *ring)
+{
+ struct xhci_segment *seg;
+ u32 idx;
+ u32 ccs;
+
+ if (!ring || !ring->deq_seg || !ring->dequeue)
+ return false;
+
+ seg = ring->deq_seg;
+ idx = ring->dequeue - ring->deq_seg->trbs;
+ ccs = ring->cycle_state;
+
+ if (idx >= TRBS_PER_SEGMENT)
+ return false;
+
+ u32 trb_cycle = le32_to_cpu(seg->trbs[idx].generic.field[3]) & TRB_CYCLE;
+ return trb_cycle == ccs;
+}
+
+static void salina_xhci_poll_fn(struct work_struct *w)
+{
+ struct salina_xhci_poller *p =
+ container_of(w, struct salina_xhci_poller, work.work);
+ struct xhci_hcd *xhci = p->xhci;
+ struct xhci_ring *er;
+ unsigned long flags;
+
+ if (!p->running || !xhci)
+ return;
+
+ er = xhci->interrupters[0]->event_ring;
+ if (!er)
+ goto resched;
+
+ if (!spin_trylock_irqsave(&xhci->lock, flags)) {
+ printk(KERN_INFO "Salina poller: lock busy, rescheduling\n");
+ goto resched;
+ }
+
+ u32 status = readl(&xhci->op_regs->status);
+ if (status == ~(u32)0) {
+ xhci_hc_died(xhci);
+ goto unlock;
+ }
+
+ if (status & STS_HCE) {
+ xhci_warn(xhci, "WARNING: Host Controller Error\n");
+ xhci_halt(xhci);
+ goto unlock;
+ }
+
+ if (status & STS_FATAL) {
+ xhci_warn(xhci, "WARNING: Host System Error\n");
+ xhci_halt(xhci);
+ goto unlock;
+ }
+
+ if (ring_has_event_pending(er)) {
+ xhci_handle_events(xhci, xhci->interrupters[0], false);
+ }
+
+unlock:
+ spin_unlock_irqrestore(&xhci->lock, flags);
+
+resched:
+ schedule_delayed_work(&p->work,
+ msecs_to_jiffies(SALINA_POLL_INTERVAL_MS));
+}
+
+void salina_start_xhci_poller(struct xhci_hcd *xhci)
+{
+ if (salina_poll.running)
+ return;
+
+ memset(&salina_poll, 0, sizeof(salina_poll));
+ salina_poll.xhci = xhci;
+ salina_poll.running = true;
+
+ INIT_DELAYED_WORK(&salina_poll.work, salina_xhci_poll_fn);
+
+ schedule_delayed_work(&salina_poll.work,
+ msecs_to_jiffies(SALINA_POLL_INTERVAL_MS));
+
+ xhci_info(xhci, "Salina: software IRQ poller enabled\n");
+}
+
+void salina_stop_xhci_poller(void)
+{
+ if (!salina_poll.running)
+ return;
+ cancel_delayed_work_sync(&salina_poll.work);
+ salina_poll.running = false;
+ salina_poll.xhci = NULL;
+}
diff --git a/drivers/usb/host/xhci-ps5.h b/drivers/usb/host/xhci-ps5.h
new file mode 100755
index 000000000000..90d41d3dc524
--- /dev/null
+++ b/drivers/usb/host/xhci-ps5.h
@@ -0,0 +1,9 @@
+#include <linux/pci.h>
+#include "xhci.h"
+
+int xhci_salina_reset(struct xhci_hcd *xhci, u64 timeout_us);
+int xhci_salina_init(struct pci_dev *pdev);
+void xhci_salina_exit(void);
+
+void salina_start_xhci_poller(struct xhci_hcd *xhci);
+void salina_stop_xhci_poller(void);
\ No newline at end of file
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index e47e644b296e..774c4955b2bb 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -59,6 +59,8 @@
#include <linux/dma-mapping.h>
#include "xhci.h"
#include "xhci-trace.h"
+#include "xhci-ring.h"
+#include "xhci-ps5.h"
static int queue_command(struct xhci_hcd *xhci, struct xhci_command *cmd,
u32 field1, u32 field2,
@@ -3083,12 +3085,14 @@ static void xhci_clear_interrupt_pending(struct xhci_interrupter *ir)
* Handle all OS-owned events on an interrupter event ring. It may drop
* and reaquire xhci->lock between event processing.
*/
-static int xhci_handle_events(struct xhci_hcd *xhci, struct xhci_interrupter *ir,
+int xhci_handle_events(struct xhci_hcd *xhci, struct xhci_interrupter *ir,
bool skip_events)
{
int event_loop = 0;
int err = 0;
u64 temp;
+ int iters = 0;
+ const int max_iters = 32;
xhci_clear_interrupt_pending(ir);
@@ -3131,11 +3135,27 @@ static int xhci_handle_events(struct xhci_hcd *xhci, struct xhci_interrupter *ir
if (err)
break;
+
+ if (xhci->quirks & XHCI_PS5_SALINA_PHY) {
+ if (++iters > max_iters) {
+ xhci_warn(xhci,
+ "Salina: event ring appears stuck after %d TRBs\n",
+ iters);
+ goto salina_stuck;
+ }
+ }
}
xhci_update_erst_dequeue(xhci, ir, true);
return 0;
+
+salina_stuck:
+ /* mark host dying so we don't deadlock future URBs */
+ xhci->xhc_state |= XHCI_STATE_DYING;
+
+ xhci_update_erst_dequeue(xhci, ir, true);
+ return -EIO;
}
/*
diff --git a/drivers/usb/host/xhci-ring.h b/drivers/usb/host/xhci-ring.h
new file mode 100755
index 000000000000..193ac03a3074
--- /dev/null
+++ b/drivers/usb/host/xhci-ring.h
@@ -0,0 +1,4 @@
+#include "xhci.h"
+
+dma_addr_t xhci_trb_virt_to_dma(struct xhci_segment *seg, union xhci_trb *trb);
+int xhci_handle_events(struct xhci_hcd *xhci, struct xhci_interrupter *ir, bool skip_events);
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index a54f5b57f205..0d99186ec967 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -26,6 +26,7 @@
#include "xhci-trace.h"
#include "xhci-debugfs.h"
#include "xhci-dbgcap.h"
+#include "xhci-ps5.h"
#define DRIVER_AUTHOR "Sarah Sharp"
#define DRIVER_DESC "'eXtensible' Host Controller (xHC) Driver"
@@ -191,6 +192,10 @@ int xhci_reset(struct xhci_hcd *xhci, u64 timeout_us)
u32 state;
int ret;
+ if (xhci->quirks & XHCI_PS5_SALINA_PHY) {
+ return xhci_salina_reset(xhci, 5000);
+ }
+
state = readl(&xhci->op_regs->status);
if (state == ~(u32)0) {
@@ -615,6 +620,10 @@ static int xhci_run_finished(struct xhci_hcd *xhci)
spin_unlock_irqrestore(&xhci->lock, flags);
+ if(xhci->quirks & XHCI_PS5_SALINA_PHY) {
+ salina_start_xhci_poller(xhci);
+ }
+
return 0;
}
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
index aeecd301f207..e202fbdd2f41 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -1645,6 +1645,7 @@ struct xhci_hcd {
#define XHCI_CDNS_SCTX_QUIRK BIT_ULL(48)
#define XHCI_ETRON_HOST BIT_ULL(49)
#define XHCI_LIMIT_ENDPOINT_INTERVAL_9 BIT_ULL(50)
+#define XHCI_PS5_SALINA_PHY BIT_ULL(51)
unsigned int num_active_eps;
unsigned int limit_active_eps;
diff --git a/include/linux/dmi.h b/include/linux/dmi.h
index c8700e6a694d..7d0afd378c4e 100644
--- a/include/linux/dmi.h
+++ b/include/linux/dmi.h
@@ -120,6 +120,9 @@ extern struct kobject *dmi_kobj;
extern int dmi_check_system(const struct dmi_system_id *list);
const struct dmi_system_id *dmi_first_match(const struct dmi_system_id *list);
extern const char * dmi_get_system_info(int field);
+#ifdef CONFIG_X86_PS5
+extern void dmi_set_system_info(int field, const char *str);
+#endif
extern const struct dmi_device * dmi_find_device(int type, const char *name,
const struct dmi_device *from);
extern void dmi_setup(void);
diff --git a/include/linux/ps5.h b/include/linux/ps5.h
new file mode 100644
index 000000000000..75a2d6dace5d
--- /dev/null
+++ b/include/linux/ps5.h
@@ -0,0 +1,97 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef _LINUX_PS5_H
+#define _LINUX_PS5_H
+
+#include <linux/types.h>
+#include <drm/drm_modes.h>
+
+#define ICC_MSG_MIN_SIZE 0x20
+#define ICC_MSG_MAX_SIZE 0x7f0
+
+struct icc_msg {
+ u8 magic;
+ u8 service_id;
+ u16 msg_type;
+ u16 unk_04;
+ u16 id;
+ u16 length;
+ u16 checksum;
+ u8 data[];
+};
+
+enum icc_service_id {
+ ICC_SERVICE_ID_CONFIGURATION = 0x01,
+ ICC_SERVICE_ID_GENERAL = 0x02,
+ ICC_SERVICE_ID_NVS = 0x03,
+ ICC_SERVICE_ID_POWER = 0x04,
+ ICC_SERVICE_ID_DEVICE = 0x05,
+ ICC_SERVICE_ID_UNKNOWN_07 = 0x07,
+ ICC_SERVICE_ID_BUTTON = 0x08,
+ ICC_SERVICE_ID_INDICATOR = 0x09,
+ ICC_SERVICE_ID_FAN = 0x0a,
+ ICC_SERVICE_ID_THERMAL = 0x0b,
+ ICC_SERVICE_ID_HDMI = 0x10,
+ ICC_SERVICE_ID_USBC = 0x12,
+ ICC_SERVICE_ID_UNKNOWN_13 = 0x13,
+ ICC_SERVICE_ID_CRASH_REPORT = 0x14,
+ ICC_SERVICE_ID_BDDRIVE = 0x15,
+ ICC_SERVICE_ID_UNKNOWN_8C = 0x8c,
+ ICC_SERVICE_ID_UNKNOWN_8D = 0x8d,
+ ICC_SERVICE_ID_SC_CONFIG = 0x8e,
+ ICC_SERVICE_ID_FLOYD = 0x9a,
+};
+
+bool spcie_is_initialized(void);
+
+u32 spcie_get_chip_id(void);
+u32 spcie_get_revision_id(void);
+u32 spcie_bar2_180000_read(u32 reg);
+void spcie_bar2_180000_write(u32 reg, u32 val);
+u32 spcie_pervasive0_4000_read(u32 reg);
+
+int icc_query(u8 *query, u8 *reply);
+
+void hdmiSystemResume(void);
+void sceHdmiInitVideoConfig(void);
+void sceHdmiSetVideoConfig(const struct drm_display_mode *mode);
+void sceHdmiSetAudioConfig(int channels);
+void sceHdmiDeviceSetVideoMute(int mute);
+void sceHdmiSetAudioMute(int mute);
+void sceHdmiOutputMode(void);
+int getHdmiConfiguration(void);
+bool isHdmiModeValid(const struct drm_display_mode *mode, int force_1080p);
+
+int icc_nvs_write(u32 partition, u16 offset, u16 length, const void *data);
+int icc_nvs_read(u32 partition, u16 offset, u16 length, void *data);
+
+int icc_usbc_set_pdcon_op_mode(u8 PortId, u8 OpMode);
+int icc_configuration_set_cpu_info_bit(u8 *bit);
+int icc_configuration_clear_cpu_info_bit(void);
+
+__noreturn void icc_power_suspend(int keep);
+void __noreturn icc_power_shutdown(void);
+void __noreturn icc_power_reboot(void);
+
+int icc_button_enable_notification(u8 type, u8 enable);
+int icc_button_enable_all_notifications(u8 enable);
+int icc_thermal_enable_notification(u8 enable);
+
+int icc_device_power_control(u8 device, u8 state);
+int icc_device_power_get(u8 device, u8 *state);
+
+int icc_indicator_set_led(const u8 setting[], size_t setting_size);
+int icc_indicator_set_led_white(u8 level);
+
+int icc_fan_change_servo_pattern(u8 pattern);
+int icc_fan_update_param(const u8 *param);
+int icc_fan_update_autoservo_param(void);
+
+void hdmi_notification_handler(struct icc_msg *msg);
+
+void mp1_set_pm1_addr(u64 addr);
+int mp1_set_sleep_entry(void);
+
+u64 svm_execute_guest(void *guest_func, u64 a0, u64 a1, u64 a2, u64 a3);
+
+#endif /* _LINUX_PS5_H */
diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
index 572b1c620c5d..b776491a1241 100644
--- a/include/net/bluetooth/hci.h
+++ b/include/net/bluetooth/hci.h
@@ -309,6 +309,22 @@ enum {
*/
HCI_QUIRK_BROKEN_SET_RPA_TIMEOUT,
+ /* When this quirk is set, the HCI_OP_LE_SET_DEFAULT_PHY command is
+ * skipped during initialization. This is required for controllers
+ * which advertise the command but reject the default 1M PHY request.
+ *
+ * This quirk can be set before hci_register_dev is called.
+ */
+ HCI_QUIRK_BROKEN_SET_DEFAULT_PHY,
+
+ /* When this quirk is set, the HCI_OP_READ_LOCAL_NAME command is
+ * skipped during initialization. This is required for controllers
+ * which become unstable when queried for the local name.
+ *
+ * This quirk can be set before hci_register_dev is called.
+ */
+ HCI_QUIRK_BROKEN_READ_LOCAL_NAME,
+
/*
* When this quirk is set, the HCI_OP_LE_EXT_CREATE_CONN command is
* disabled. This is required for the Actions Semiconductor ATS2851
diff --git a/net/bluetooth/hci_sync.c b/net/bluetooth/hci_sync.c
index df23245d6ccd..1248c3735900 100644
--- a/net/bluetooth/hci_sync.c
+++ b/net/bluetooth/hci_sync.c
@@ -3787,6 +3787,9 @@ static int hci_read_dev_class_sync(struct hci_dev *hdev)
/* Read Local Name */
static int hci_read_local_name_sync(struct hci_dev *hdev)
{
+ if (hci_test_quirk(hdev, HCI_QUIRK_BROKEN_READ_LOCAL_NAME))
+ return 0;
+
return __hci_cmd_sync_status(hdev, HCI_OP_READ_LOCAL_NAME,
0, NULL, HCI_CMD_TIMEOUT);
}
@@ -4874,6 +4877,12 @@ static int hci_le_set_default_phy_sync(struct hci_dev *hdev)
{
struct hci_cp_le_set_default_phy cp;
+ if (hci_test_quirk(hdev, HCI_QUIRK_BROKEN_SET_DEFAULT_PHY)) {
+ hdev->le_tx_def_phys = HCI_LE_SET_PHY_1M;
+ hdev->le_rx_def_phys = HCI_LE_SET_PHY_1M;
+ return 0;
+ }
+
if (!(hdev->commands[35] & 0x20)) {
/* If the command is not supported it means only 1M PHY is
* supported.
diff --git a/scripts/setlocalversion b/scripts/setlocalversion
index 28169d7e143b..44f516daa21d 100755
--- a/scripts/setlocalversion
+++ b/scripts/setlocalversion
@@ -61,6 +61,9 @@ scm_version()
local no_dirty=false
local tag
+ # Do not add any suffix for ps5-linux.
+ return
+
while [ $# -gt 0 ];
do
case "$1" in
diff --git a/sound/hda/controllers/intel.c b/sound/hda/controllers/intel.c
index 4b03c64e72ab..4cb7d285ccd6 100644
--- a/sound/hda/controllers/intel.c
+++ b/sound/hda/controllers/intel.c
@@ -2643,6 +2643,8 @@ static const struct pci_device_id azx_ids[] = {
AZX_DCAPS_PM_RUNTIME },
{ PCI_VDEVICE(ATI, 0x1308),
.driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS },
+ { PCI_VDEVICE(ATI, 0x13ea),
+ .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS },
{ PCI_VDEVICE(ATI, 0x157a),
.driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS },
{ PCI_VDEVICE(ATI, 0x15b3),