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 #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/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..731fed163a83 --- /dev/null +++ b/arch/x86/platform/ps5/ps5.c @@ -0,0 +1,51 @@ +#include +#include + +#include +#include +#include +#include + +#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 +#include +#include +#include +#include +#include +#include +#include + +#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 +#include +#include +#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 +#include + +#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 #include +#ifdef CONFIG_X86_PS5 +#include +#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 #include +#ifdef CONFIG_X86_PS5 +#include +#endif + #include #include #include @@ -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 +#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 +#include +#include +#include +#include +#include + +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 +#include +#include +#include +#include +#include +#include +#include + +#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 +#include +#include +#include +#include +#include +#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..d2c25e461bf7 --- /dev/null +++ b/drivers/ps5/autoservo_param.h @@ -0,0 +1,1902 @@ +#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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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..33a48c664f73 --- /dev/null +++ b/drivers/ps5/fan.c @@ -0,0 +1,193 @@ +// SPDX-License-Identifier: GPL-2.0-only + +#include +#include +#include +#include +#include +#include +#include "ps5-fan.h" + +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); + +#define PS5_FAN_BOOT_TARGET_TEMP 75 + +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..8f094490d677 --- /dev/null +++ b/drivers/ps5/hdmi.c @@ -0,0 +1,1237 @@ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include + +#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 + +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 +#include +#include +#include +#include +#include +#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 "); +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 +#include +#include +#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 + +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..4af890c842a7 --- /dev/null +++ b/drivers/ps5/mp1.c @@ -0,0 +1,488 @@ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include + +#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 + +#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..4a28451f89eb --- /dev/null +++ b/drivers/ps5/spcie.c @@ -0,0 +1,1146 @@ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include "autoservo_param.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) + +#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 + +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 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); +} + +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); + +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 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..3fd58e9a6609 --- /dev/null +++ b/drivers/ps5/svm.c @@ -0,0 +1,169 @@ +#include +#include + +#include +#include +#include +#include + +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..23de43ea4b00 --- /dev/null +++ b/drivers/ps5/tpcie.c @@ -0,0 +1,303 @@ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include + +#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..f5348c0d7e82 --- /dev/null +++ b/drivers/ps5/vmenter.S @@ -0,0 +1,30 @@ +#include +#include + +.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 +#include +#include +#include +#include +#include +#include +#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 +#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 #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..24adcd953ab3 --- /dev/null +++ b/include/linux/ps5.h @@ -0,0 +1,95 @@ +#ifndef _LINUX_PS5_H +#define _LINUX_PS5_H + +#include +#include + +#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),