diff --git a/.github/workflows/build-kernel-arm64.yml b/.github/workflows/build-kernel-arm64.yml index 5ee82c85d87bc..14f0a5929ebb4 100644 --- a/.github/workflows/build-kernel-arm64.yml +++ b/.github/workflows/build-kernel-arm64.yml @@ -30,10 +30,16 @@ jobs: run: | # .config make deepin_arm64_desktop_defconfig + scripts/config --enable CONFIG_DEBUG_INFO_NONE + scripts/config --disable CONFIG_DEBUG_INFO_DWARF5 + make olddefconfig make -j$(nproc) - name: 'Clang build kernel' run: | # .config make LLVM=-18 deepin_arm64_desktop_defconfig + scripts/config --enable CONFIG_DEBUG_INFO_NONE + scripts/config --disable CONFIG_DEBUG_INFO_DWARF5 + make LLVM=-18 olddefconfig make LLVM=-18 -j$(nproc) diff --git a/MAINTAINERS b/MAINTAINERS index f2c5a9ee20ad8..c7ebccca27be8 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -17551,6 +17551,7 @@ F: drivers/usb/phytium/* F: drivers/usb/phytium/phytium_usb_v2* F: drivers/usb/typec/role-switch-phytium.c F: arch/arm64/boot/dts/phytium/* +F: arch/arm64/include/asm/phytium_cputype.h F: drivers/gpio/gpio-phytium* QAT DRIVER diff --git a/arch/arm64/configs/deepin_arm64_desktop_defconfig b/arch/arm64/configs/deepin_arm64_desktop_defconfig index 3de1e5f7c8c9c..e76edbbc314b8 100644 --- a/arch/arm64/configs/deepin_arm64_desktop_defconfig +++ b/arch/arm64/configs/deepin_arm64_desktop_defconfig @@ -4089,6 +4089,8 @@ CONFIG_DEVFREQ_GOV_SIMPLE_ONDEMAND=y CONFIG_DEVFREQ_GOV_PERFORMANCE=m CONFIG_DEVFREQ_GOV_POWERSAVE=m CONFIG_DEVFREQ_GOV_USERSPACE=m +CONFIG_ARM_PHYTIUM_NOC_DEVFREQ=m +CONFIG_ARM_PHYTIUM_DMU_DEVFREQ=m CONFIG_PM_DEVFREQ_EVENT=y CONFIG_EXTCON_GPIO=m CONFIG_EXTCON_MAX14577=m diff --git a/arch/arm64/include/asm/cputype.h b/arch/arm64/include/asm/cputype.h index 410bb0b5a0308..8c8d8558c6700 100644 --- a/arch/arm64/include/asm/cputype.h +++ b/arch/arm64/include/asm/cputype.h @@ -156,7 +156,7 @@ #define MICROSOFT_CPU_PART_AZURE_COBALT_100 0xD49 /* Based on r0p0 of ARM Neoverse N2 */ -#define PHYTIUM_CPU_PART_FTC303 0x303 +#define PHYTIUM_CPU_PART_FTC310 0x303 #define PHYTIUM_CPU_PART_FTC660 0x660 #define PHYTIUM_CPU_PART_FTC661 0x661 #define PHYTIUM_CPU_PART_FTC662 0x662 @@ -240,7 +240,7 @@ #define MIDR_APPLE_M2_AVALANCHE_MAX MIDR_CPU_MODEL(ARM_CPU_IMP_APPLE, APPLE_CPU_PART_M2_AVALANCHE_MAX) #define MIDR_AMPERE1 MIDR_CPU_MODEL(ARM_CPU_IMP_AMPERE, AMPERE_CPU_PART_AMPERE1) #define MIDR_AMPERE1A MIDR_CPU_MODEL(ARM_CPU_IMP_AMPERE, AMPERE_CPU_PART_AMPERE1A) -#define MIDR_PHYTIUM_FTC303 MIDR_CPU_MODEL(ARM_CPU_IMP_PHYTIUM, PHYTIUM_CPU_PART_FTC303) +#define MIDR_PHYTIUM_FTC310 MIDR_CPU_MODEL(ARM_CPU_IMP_PHYTIUM, PHYTIUM_CPU_PART_FTC310) #define MIDR_PHYTIUM_FTC660 MIDR_CPU_MODEL(ARM_CPU_IMP_PHYTIUM, PHYTIUM_CPU_PART_FTC660) #define MIDR_PHYTIUM_FTC661 MIDR_CPU_MODEL(ARM_CPU_IMP_PHYTIUM, PHYTIUM_CPU_PART_FTC661) #define MIDR_PHYTIUM_PS17064 MIDR_CPU_MODEL(ARM_CPU_IMP_PHYTIUM, PHYTIUM_CPU_PART_FTC662) diff --git a/arch/arm64/include/asm/phytium_cputype.h b/arch/arm64/include/asm/phytium_cputype.h new file mode 100644 index 0000000000000..c4edec454597d --- /dev/null +++ b/arch/arm64/include/asm/phytium_cputype.h @@ -0,0 +1,241 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2025, Phytium Technology Co., Ltd. + */ +#ifndef __ASM_PHYTIUM_CPUTYPE_H +#define __ASM_PHYTIUM_CPUTYPE_H + +#include +#include + +#define SOC_ID_PE1702 0x1 +#define SOC_ID_PS17064 0x2 +#define SOC_ID_PD1904 0x3 +#define SOC_ID_PS20064 0x4 + +#define SOC_ID_PD2008 0x5 +#define SOC_ID_PS21064 0x6 +#define SOC_ID_PE220X 0x7 +#define SOC_ID_PS23064 0x8 +#define SOC_ID_PD2308 0x9 +#define SOC_ID_PS2480 0xa +#define SOC_ID_PD2408 0xb + +#define SYS_REG_VAL_PS24080 0x6 +#define SYS_REG_VAL_PS23064 0x8 + +#define SMCCC_SUCCESS 0 +#define SMCCC_FAILURE (-1) +#define FUNC_ID_GET_CPU_VERSION 0xc2000002 + +enum phyt_soc_type { + PE1702 = 1, + PS17064, + PD1904, + PS20064, + PD2008, + PS21064, + PE220X, + PS23064, + PD2308, + PS24080, + PD2408, + PS15016, + UNKNOWN_SOC +}; + +extern enum phyt_soc_type phyt_soc_type_t; + +static enum phyt_soc_type do_smccc_res(struct arm_smccc_res res) +{ + unsigned long smc_cpu_ver = res.a1; + + smc_cpu_ver = (smc_cpu_ver >> 8); + switch (smc_cpu_ver) { + case SOC_ID_PE1702: + return PE1702; + case SOC_ID_PS17064: + return PS17064; + case SOC_ID_PD1904: + return PD1904; + case SOC_ID_PS20064: + return PS20064; + case SOC_ID_PD2008: + return PD2008; + case SOC_ID_PS21064: + return PS21064; + case SOC_ID_PE220X: + return PE220X; + case SOC_ID_PS23064: + return PS23064; + case SOC_ID_PD2308: + return PD2308; + case SOC_ID_PS2480: + return PS24080; + case SOC_ID_PD2408: + return PD2408; + default: + return UNKNOWN_SOC; + } +} + +static enum phyt_soc_type do_read_sysreg(void) +{ + u32 aidr_reg_val = read_sysreg(aidr_el1); + + switch (aidr_reg_val) { + case SYS_REG_VAL_PS24080: + return PS24080; + case SYS_REG_VAL_PS23064: + return PS23064; + default: + return UNKNOWN_SOC; + } +} + +static enum phyt_soc_type do_read_mpidr(void) +{ + u32 part_id = read_cpuid_part_number(); + + switch (part_id) { + case PHYTIUM_CPU_PART_FTC310: + return PE220X; + case PHYTIUM_CPU_PART_FTC660: + return PS15016; + case PHYTIUM_CPU_PART_FTC661: + return PE1702; + case PHYTIUM_CPU_PART_FTC662: + return PS17064; + case PHYTIUM_CPU_PART_FTC663: + return PD1904; + case PHYTIUM_CPU_PART_FTC862: + return PD2408; + default: + return UNKNOWN_SOC; + } +} + +static inline bool is_phytium_soc(void) +{ + if (read_cpuid_implementor() == ARM_CPU_IMP_PHYTIUM) + return true; + return false; +} + +static inline enum phyt_soc_type phyt_read_soc_type(void) +{ + enum phyt_soc_type ctype; + struct arm_smccc_res res; + + if (!is_phytium_soc()) + return UNKNOWN_SOC; + + arm_smccc_smc(FUNC_ID_GET_CPU_VERSION, 0, 0, 0, 0, 0, 0, 0, &res); + switch (res.a0) { + case SMCCC_SUCCESS: + ctype = do_smccc_res(res); + if (ctype != UNKNOWN_SOC) + break; + fallthrough; + case SMCCC_FAILURE: + ctype = do_read_sysreg(); + if (ctype != UNKNOWN_SOC) + break; + fallthrough; + default: + ctype = do_read_mpidr(); + break; + } + return ctype; +} + +static inline void phyt_soc_type_init(void) +{ + enum phyt_soc_type ctype = phyt_read_soc_type(); + + switch (ctype) { + case PE1702: + phyt_soc_type_t = PE1702; + break; + case PS17064: + phyt_soc_type_t = PS17064; + break; + case PD1904: + phyt_soc_type_t = PD1904; + break; + case PS20064: + phyt_soc_type_t = PS20064; + break; + case PD2008: + phyt_soc_type_t = PD2008; + break; + case PS21064: + phyt_soc_type_t = PS21064; + break; + case PE220X: + phyt_soc_type_t = PE220X; + break; + case PS23064: + phyt_soc_type_t = PS23064; + break; + case PD2308: + phyt_soc_type_t = PD2308; + break; + case PS24080: + phyt_soc_type_t = PS24080; + break; + case PD2408: + phyt_soc_type_t = PD2408; + break; + case PS15016: + phyt_soc_type_t = PS15016; + break; + default: + phyt_soc_type_t = UNKNOWN_SOC; + break; + } +} + +static inline bool is_pd2408(void) +{ + + if (phyt_soc_type_t == PD2408) + return true; + return false; +} + +static inline bool is_ps23064(void) +{ + + if (phyt_soc_type_t == PS23064) + return true; + return false; +} + +static inline bool is_ps24080(void) +{ + + if (phyt_soc_type_t == PS24080) + return true; + return false; +} + +static inline bool is_pd2308(void) +{ + + if (phyt_soc_type_t == PD2308) + return true; + return false; +} + +static inline bool is_pe220x(void) +{ + + if (phyt_soc_type_t == PE220X) + return true; + return false; +} + +#endif + + diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c index 9ea67d6565a78..6e7926724866d 100644 --- a/arch/arm64/kernel/cpufeature.c +++ b/arch/arm64/kernel/cpufeature.c @@ -1722,7 +1722,7 @@ static bool unmap_kernel_at_el0(const struct arm64_cpu_capabilities *entry, MIDR_ALL_VERSIONS(MIDR_CORTEX_A73), MIDR_ALL_VERSIONS(MIDR_HISI_TSV110), MIDR_ALL_VERSIONS(MIDR_NVIDIA_CARMEL), - MIDR_ALL_VERSIONS(MIDR_PHYTIUM_FTC303), + MIDR_ALL_VERSIONS(MIDR_PHYTIUM_FTC310), MIDR_ALL_VERSIONS(MIDR_PHYTIUM_FTC660), MIDR_ALL_VERSIONS(MIDR_PHYTIUM_FTC661), MIDR_ALL_VERSIONS(MIDR_PHYTIUM_PS17064), diff --git a/arch/arm64/kernel/proton-pack.c b/arch/arm64/kernel/proton-pack.c index d31a13664b3a1..af04a1739aab4 100644 --- a/arch/arm64/kernel/proton-pack.c +++ b/arch/arm64/kernel/proton-pack.c @@ -163,7 +163,7 @@ static enum mitigation_state spectre_v2_get_cpu_hw_mitigation_state(void) MIDR_ALL_VERSIONS(MIDR_CORTEX_A55), MIDR_ALL_VERSIONS(MIDR_BRAHMA_B53), MIDR_ALL_VERSIONS(MIDR_HISI_TSV110), - MIDR_ALL_VERSIONS(MIDR_PHYTIUM_FTC303), + MIDR_ALL_VERSIONS(MIDR_PHYTIUM_FTC310), MIDR_ALL_VERSIONS(MIDR_QCOM_KRYO_2XX_SILVER), MIDR_ALL_VERSIONS(MIDR_QCOM_KRYO_3XX_SILVER), MIDR_ALL_VERSIONS(MIDR_QCOM_KRYO_4XX_SILVER), @@ -474,7 +474,7 @@ static enum mitigation_state spectre_v4_get_cpu_hw_mitigation_state(void) MIDR_ALL_VERSIONS(MIDR_CORTEX_A53), MIDR_ALL_VERSIONS(MIDR_CORTEX_A55), MIDR_ALL_VERSIONS(MIDR_BRAHMA_B53), - MIDR_ALL_VERSIONS(MIDR_PHYTIUM_FTC303), + MIDR_ALL_VERSIONS(MIDR_PHYTIUM_FTC310), MIDR_ALL_VERSIONS(MIDR_QCOM_KRYO_3XX_SILVER), MIDR_ALL_VERSIONS(MIDR_QCOM_KRYO_4XX_SILVER), { /* sentinel */ }, diff --git a/arch/arm64/kernel/setup.c b/arch/arm64/kernel/setup.c index 3a2d9d822d12d..c6adf753e6d00 100644 --- a/arch/arm64/kernel/setup.c +++ b/arch/arm64/kernel/setup.c @@ -57,6 +57,12 @@ #include #endif +#ifdef CONFIG_ARCH_PHYTIUM +#include +enum phyt_soc_type phyt_soc_type_t; +EXPORT_SYMBOL(phyt_soc_type_t); +#endif + static int num_standard_resources; static struct resource *standard_resources; @@ -349,6 +355,9 @@ void __init __no_sanitize_address setup_arch(char **cmdline_p) FW_BUG "Booted with MMU enabled!"); } +#ifdef CONFIG_ARCH_PHYTIUM + phyt_soc_type_init(); +#endif arm64_memblock_init(); paging_init(); diff --git a/arch/x86/kernel/cpu/microcode/zhaoxin.c b/arch/x86/kernel/cpu/microcode/zhaoxin.c index ec00451f21bc5..5a925ef04a055 100644 --- a/arch/x86/kernel/cpu/microcode/zhaoxin.c +++ b/arch/x86/kernel/cpu/microcode/zhaoxin.c @@ -176,7 +176,6 @@ static int zhaoxin_microcode_sanity_check(void *mc, bool print_err, int hdr_type static void save_microcode_patch(struct microcode_zhaoxin *patch) { unsigned int size = patch->hdr.total_size; - struct microcode_zhaoxin *mc = NULL; struct page *pg = NULL; void *dst = NULL; @@ -186,18 +185,14 @@ static void save_microcode_patch(struct microcode_zhaoxin *patch) * the memory allocation to this range. */ pg = alloc_pages(GFP_DMA32 | GFP_KERNEL, get_order(size)); - - if (pg) { - dst = page_address(pg); - memcpy(dst, patch, size); - mc = dst; - if (mc) { - zhaoxin_ucode_patch = mc; - return; - } + if (!pg) { + pr_err("Unable to allocate microcode memory size: %u\n", size); + return; } - pr_err("Unable to allocate microcode memory size: %u\n", size); + dst = page_address(pg); + memcpy(dst, patch, size); + zhaoxin_ucode_patch = dst; } static inline u32 @@ -495,6 +490,7 @@ void __init load_ucode_zhaoxin_bsp(struct early_load_data *ed) if (uci.mc && apply_microcode_early(&uci) == UCODE_UPDATED) { zhaoxin_ucode_patch = UCODE_BSP_LOADED; + x86_cpuinit.parallel_bringup = false; ed->new_rev = uci.cpu_sig.rev; } else if (uci.mc) { pr_debug("%s: BSP CPU %d early update failed due to application failure\n", diff --git a/drivers/acpi/apei/ghes.c b/drivers/acpi/apei/ghes.c index 14c3add985264..6c27bc5df4a9f 100644 --- a/drivers/acpi/apei/ghes.c +++ b/drivers/acpi/apei/ghes.c @@ -1611,6 +1611,8 @@ void __init acpi_ghes_init(void) */ static struct acpi_platform_list plat_list[] = { {"HPE ", "Server ", 0, ACPI_SIG_FADT, all_versions}, + {"__ZX__", "EDK2 ", 3, ACPI_SIG_FADT, greater_than_or_equal}, + {"_BYO_ ", "BYOSOFT ", 3, ACPI_SIG_FADT, greater_than_or_equal}, { } /* End */ }; diff --git a/drivers/devfreq/Kconfig b/drivers/devfreq/Kconfig index 3c4862a752b5a..043ec397de524 100644 --- a/drivers/devfreq/Kconfig +++ b/drivers/devfreq/Kconfig @@ -150,6 +150,24 @@ config ARM_SUN8I_A33_MBUS_DEVFREQ This adds the DEVFREQ driver for the MBUS controller in some Allwinner sun8i (A33 through H3) and sun50i (A64 and H5) SoCs. +config ARM_PHYTIUM_NOC_DEVFREQ + tristate "ARM PHYTIUM NOC DEVFREQ Driver" + depends on ARCH_PHYTIUM + depends on ACPI + select DEVFREQ_GOV_SIMPLE_ONDEMAND + help + This adds the DEVFREQ driver for Phytium Net On Chip. + It adjusts frequency for noc based on load bandwidth obtained from register. + +config ARM_PHYTIUM_DMU_DEVFREQ + tristate "ARM PHYTIUM DMU DEVFREQ Driver" + depends on ARCH_PHYTIUM + depends on ACPI + select DEVFREQ_GOV_SIMPLE_ONDEMAND + help + This adds the DEVFREQ driver for Phytium DDR Memory Unit. + It adjusts frequency for dmu based on load bandwidth obtained from register. + source "drivers/devfreq/event/Kconfig" endif # PM_DEVFREQ diff --git a/drivers/devfreq/Makefile b/drivers/devfreq/Makefile index bf40d04928d03..c57455f9b4818 100644 --- a/drivers/devfreq/Makefile +++ b/drivers/devfreq/Makefile @@ -12,6 +12,8 @@ obj-$(CONFIG_ARM_EXYNOS_BUS_DEVFREQ) += exynos-bus.o obj-$(CONFIG_ARM_IMX_BUS_DEVFREQ) += imx-bus.o obj-$(CONFIG_ARM_IMX8M_DDRC_DEVFREQ) += imx8m-ddrc.o obj-$(CONFIG_ARM_MEDIATEK_CCI_DEVFREQ) += mtk-cci-devfreq.o +obj-$(CONFIG_ARM_PHYTIUM_DMU_DEVFREQ) += phytium_dmu.o +obj-$(CONFIG_ARM_PHYTIUM_NOC_DEVFREQ) += phytium_noc.o obj-$(CONFIG_ARM_RK3399_DMC_DEVFREQ) += rk3399_dmc.o obj-$(CONFIG_ARM_SUN8I_A33_MBUS_DEVFREQ) += sun8i-a33-mbus.o obj-$(CONFIG_ARM_TEGRA_DEVFREQ) += tegra30-devfreq.o diff --git a/drivers/devfreq/phytium_dmu.c b/drivers/devfreq/phytium_dmu.c new file mode 100644 index 0000000000000..e85cd43f9511f --- /dev/null +++ b/drivers/devfreq/phytium_dmu.c @@ -0,0 +1,654 @@ +// SPDX-License-Identifier: GPL-1.0 +/* + * Phytium Processor DMU Frequency Driver (v1/v2 unified) + * + * Copyright (C) 2024, Phytium Technology Co.,Ltd. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DEVICE_TYPE 9 + +#define DMUFREQ_DRIVER_VERSION "1.1.0" + +/* v1 Register definition */ +#define DMU_V1_PMU_STRIDE 0x80000 +#define DMU_V1_AXI_MONITOR2_L 0x084 +#define DMU_V1_AXI_MONITOR3_L 0x08c +#define DMU_V1_AXI_MONITOR_EN 0x01c +#define DMU_V1_TIMER_START 0x000 +#define DMU_V1_TIMER_STOP 0x004 +#define DMU_V1_CLEAR_EVENT 0x008 + +#define DDR_PMU_NOTICE_START 0x0 +#define DDR_PMU_NOTICE_STOP 0x1 + +/* v2 Register definition */ +#define DMU_V2_PDM_START 0xC0000 +#define DMU_V2_PDM_STRIDE 0x1000 +#define DMU_V2_MONITOR_START 0x304 +#define DMU_V2_MONITOR_SNAPSHOT 0x30c +#define DMU_V2_EVENT_CLEAR 0x308 +#define DMU_V2_EVENT_L_CNT 0x310 +#define DMU_V2_EVENT_H_CNT 0x314 + +enum phytium_dmu_type { + PHYTIUM_DMU_V1, + PHYTIUM_DMU_V2, +}; + +struct phytium_dmufreq_info { + enum phytium_dmu_type type; + const char *name; +}; + +struct phytium_dmufreq { + struct device *dev; + const struct phytium_dmufreq_info *info; + + struct devfreq *devfreq; + struct devfreq_dev_profile profile; + struct devfreq_simple_ondemand_data ondemand_data; + + unsigned long rate; + unsigned long bandwidth; + unsigned long single_threshold_value; + int max_count; + int cnt; + + /* v1: multichannel,v2: Single-channel multiple instances */ + union { + void __iomem **basev1; + void __iomem *basev2; + }; + + /* v1 only */ + unsigned long *read_bw; + unsigned long *write_bw; + struct notifier_block nb; + bool pmu_active; + unsigned long last_bust_time; + + /* v2 only */ + unsigned int uid; + struct mutex lock; + + unsigned int freq_count; + unsigned long freq_table[]; +}; + +struct acpi_result { + int status; + unsigned long long value; +}; + +/* v1/v2 Distinguishing-type register access */ +static inline void dmu_v1_write32(struct phytium_dmufreq *priv, + int dmu, unsigned long offset, unsigned long value) +{ + writel_relaxed(value, priv->basev1[dmu] + offset); +} + +static inline unsigned long dmu_v1_read32(struct phytium_dmufreq *priv, + int dmu, unsigned long offset) +{ + return readl_relaxed(priv->basev1[dmu] + offset); +} + +static inline void dmu_v2_write32(struct phytium_dmufreq *priv, + unsigned long offset, unsigned long value) +{ + writel_relaxed(value, priv->basev2 + offset); +} + +static inline unsigned long dmu_v2_read32(struct phytium_dmufreq *priv, + unsigned long offset) +{ + return readl_relaxed(priv->basev2 + offset); +} + +/* ACPI/BIOS Related general methods */ +static struct acpi_result phytium_acpi_eval_integer(struct device *dev, const char *method) +{ + acpi_handle handle = ACPI_HANDLE(dev); + acpi_status status; + unsigned long long val; + struct acpi_result result; + + status = acpi_evaluate_integer(handle, (char *)method, NULL, &val); + if (ACPI_FAILURE(status)) { + dev_err(dev, "Failed to evaluate %s: ACPI status 0x%x\n", method, status); + result.status = -EIO; + result.value = 0; + return result; + } + result.status = 0; + result.value = val; + return result; +} + +/* V1 PMU notification chain, only V1 is registered */ +BLOCKING_NOTIFIER_HEAD(dmu_pmu_notifier_chain); +EXPORT_SYMBOL(dmu_pmu_notifier_chain); + +static int dmu_pmu_notifier_call(struct notifier_block *nb, unsigned long event, void *data) +{ + struct phytium_dmufreq *priv = container_of(nb, struct phytium_dmufreq, nb); + struct device *dev = priv->dev; + + switch (event) { + case DDR_PMU_NOTICE_START: + priv->pmu_active = false; + dev_dbg(dev, "DDR PMU START: Stopping monitoring\n"); + break; + case DDR_PMU_NOTICE_STOP: + priv->cnt = 0; + priv->pmu_active = true; + dev_dbg(dev, "DDR PMU STOP: Resuming monitoring\n"); + break; + default: + break; + } + return NOTIFY_OK; +} + +/* v1/v2 General ACPI Frequency Settings */ +static int phytium_dmu_set_freq(struct device *dev, unsigned long freq) +{ + acpi_handle handle = ACPI_HANDLE(dev); + struct phytium_dmufreq *priv = dev_get_drvdata(dev); + union acpi_object args[4]; + struct acpi_object_list arg_list = { + .pointer = args, + .count = ARRAY_SIZE(args), + }; + acpi_status status; + unsigned long long ret; + + args[0].type = ACPI_TYPE_INTEGER; + args[0].integer.value = DEVICE_TYPE; + args[1].type = ACPI_TYPE_INTEGER; + args[1].integer.value = freq; + if (priv->info->type == PHYTIUM_DMU_V2) + args[2].integer.value = priv->uid; + else + args[2].integer.value = 0; + args[2].type = ACPI_TYPE_INTEGER; + args[3].type = ACPI_TYPE_INTEGER; + args[3].integer.value = 0; + + if (priv->info->type == PHYTIUM_DMU_V2) + mutex_lock(&priv->lock); + status = acpi_evaluate_integer(handle, "PSCF", &arg_list, &ret); + if (priv->info->type == PHYTIUM_DMU_V2) + mutex_unlock(&priv->lock); + + if (ACPI_FAILURE(status)) { + dev_err(dev, "No PSCF method\n"); + return -EIO; + } + return 0; +} + +static int phytium_dmu_target(struct device *dev, unsigned long *freq, u32 flags) +{ + struct phytium_dmufreq *priv = dev_get_drvdata(dev); + unsigned long old_freq = priv->rate; + unsigned long target_rate; + struct dev_pm_opp *opp; + int ret; + + opp = devfreq_recommended_opp(dev, freq, flags); + if (IS_ERR(opp)) + return PTR_ERR(opp); + + target_rate = dev_pm_opp_get_freq(opp); + dev_pm_opp_put(opp); + + if (target_rate == old_freq) + return 0; + + dev_dbg(dev, "target_rate = %lu\n", target_rate); + ret = phytium_dmu_set_freq(dev, target_rate); + + if (ret) { + dev_warn(dev, "failed to set DRAM frequency: %lu\n", target_rate); + return ret; + } + priv->rate = target_rate; + return ret; +} + +static int phytium_dmu_get_cur_freq(struct device *dev, unsigned long *freq) +{ + struct phytium_dmufreq *priv = dev_get_drvdata(dev); + + *freq = priv->rate; + return 0; +} + +/* v1/v2 General ACPI Method */ +static int get_freq_count(struct device *dev) +{ + struct acpi_result result; + struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; + union acpi_object args[3], *package, *element; + struct acpi_object_list arg_list = { + .pointer = args, + .count = ARRAY_SIZE(args), + }; + acpi_handle handle = ACPI_HANDLE(dev); + acpi_status status; + + args[0].type = ACPI_TYPE_INTEGER; + args[0].integer.value = DEVICE_TYPE; + args[1].type = ACPI_TYPE_INTEGER; + args[1].integer.value = 0; + args[2].type = ACPI_TYPE_INTEGER; + args[2].integer.value = 0; + + status = acpi_evaluate_object(handle, "PGCL", &arg_list, &buffer); + if (ACPI_FAILURE(status)) { + dev_err(dev, "No PGCL method, status = %d\n", status); + return -EIO; + } + package = buffer.pointer; + element = &package->package.elements[1]; + result.value = element->integer.value; + + kfree(buffer.pointer); + return result.value; +} + +static int phytium_dmu_get_freq_info(struct device *dev) +{ + struct phytium_dmufreq *priv = dev_get_drvdata(dev); + struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; + union acpi_object args[3], *package, *element; + struct acpi_object_list arg_list = { + .pointer = args, + .count = ARRAY_SIZE(args), + }; + acpi_handle handle = ACPI_HANDLE(dev); + acpi_status status; + int i; + + args[0].type = ACPI_TYPE_INTEGER; + args[0].integer.value = DEVICE_TYPE; + args[1].type = ACPI_TYPE_INTEGER; + args[1].integer.value = 0; + args[2].type = ACPI_TYPE_INTEGER; + args[2].integer.value = 0; + + status = acpi_evaluate_object(handle, "PGCL", &arg_list, &buffer); + if (ACPI_FAILURE(status)) { + dev_err(dev, "No PGCL method\n"); + return -EIO; + } + + package = buffer.pointer; + element = &package->package.elements[1]; + priv->freq_count = element->integer.value; + + for (i = 0; i < priv->freq_count; i++) { + element = &package->package.elements[i+2]; + priv->freq_table[i] = element->integer.value; + dev_dbg(dev, "freq_table[%d] = %llu\n", i, element->integer.value); + } + kfree(buffer.pointer); + return 0; +} + +/* v1/v2 General ACPI State */ +static struct acpi_result phytium_dmufreq_state(struct device *dev) +{ + return phytium_acpi_eval_integer(dev, "STAT"); +} +static struct acpi_result phytium_current_enabled_channels(struct device *dev) +{ + return phytium_acpi_eval_integer(dev, "CHAN"); +} +static struct acpi_result phytium_read_threshold_value(struct device *dev) +{ + return phytium_acpi_eval_integer(dev, "BAND"); +} + +/* v1 Bandwidth acquisition with PMU notification chain */ +static u64 phytium_dmufreq_get_real_bw_v1(struct phytium_dmufreq *priv) +{ + unsigned long peak_bw = 0; + unsigned long sum_peak_bw = 0; + int i; + + for (i = 0; i < priv->max_count; i++) { + priv->read_bw[i] = dmu_v1_read32(priv, i, DMU_V1_AXI_MONITOR2_L); + priv->write_bw[i] = dmu_v1_read32(priv, i, DMU_V1_AXI_MONITOR3_L); + + dmu_v1_write32(priv, i, DMU_V1_CLEAR_EVENT, 0x1); + dmu_v1_write32(priv, i, DMU_V1_TIMER_START, 0x1); + sum_peak_bw = priv->read_bw[i] + priv->write_bw[i]; + if (sum_peak_bw > peak_bw) + peak_bw = sum_peak_bw; + } + dev_dbg(priv->dev, "peak_bw = %lu\n", peak_bw); + return peak_bw; +} + +static void polling_handle_v1(struct phytium_dmufreq *priv) +{ + int i; + if (!priv->pmu_active) { + priv->bandwidth = priv->last_bust_time; + return; + } + if (priv->cnt > 0) { + for (i = 0; i < priv->max_count ; i++) { + dmu_v1_write32(priv, i, DMU_V1_AXI_MONITOR_EN, 0x101); + dmu_v1_write32(priv, i, DMU_V1_TIMER_STOP, 0x1); + } + priv->bandwidth = phytium_dmufreq_get_real_bw_v1(priv); + } + priv->cnt = 1; +} + +/* v2 Multi-instance bandwidth acquisition */ +static void phytium_dmufreq_restart_clear_timer_v2(struct phytium_dmufreq *priv) +{ + dmu_v2_write32(priv, DMU_V2_PDM_START + DMU_V2_EVENT_CLEAR, 0x1); + dmu_v2_write32(priv, DMU_V2_PDM_START + + DMU_V2_PDM_STRIDE + DMU_V2_EVENT_CLEAR, 0x1); + dmu_v2_write32(priv, DMU_V2_PDM_START + DMU_V2_EVENT_CLEAR, 0x0); + dmu_v2_write32(priv, DMU_V2_PDM_START + + DMU_V2_PDM_STRIDE + DMU_V2_EVENT_CLEAR, 0x0); +} + +static u64 phytium_dmufreq_get_real_bw_v2(struct phytium_dmufreq *priv) +{ + u32 lo, hi; + u64 cnt_0, cnt_1, peak_bw; + + lo = dmu_v2_read32(priv, DMU_V2_PDM_START + DMU_V2_EVENT_L_CNT); + hi = dmu_v2_read32(priv, DMU_V2_PDM_START + DMU_V2_EVENT_H_CNT); + cnt_0 = ((u64)hi << 32) | lo; + lo = dmu_v2_read32(priv, DMU_V2_PDM_START + + DMU_V2_PDM_STRIDE + DMU_V2_EVENT_L_CNT); + hi = dmu_v2_read32(priv, DMU_V2_PDM_START + + DMU_V2_PDM_STRIDE + DMU_V2_EVENT_H_CNT); + cnt_1 = ((u64)hi << 32) | lo; + peak_bw = (cnt_0 + cnt_1) * 64UL; + + dev_dbg(priv->dev, "peak_bw = %llu\n", peak_bw); + return peak_bw; +} + +static void polling_handle_v2(struct phytium_dmufreq *priv) +{ + dmu_v2_write32(priv, DMU_V2_PDM_START + DMU_V2_MONITOR_SNAPSHOT, 0x1); + dmu_v2_write32(priv, DMU_V2_PDM_START + + DMU_V2_PDM_STRIDE + DMU_V2_MONITOR_SNAPSHOT, 0x1); + priv->bandwidth = phytium_dmufreq_get_real_bw_v2(priv); + dmu_v2_write32(priv, DMU_V2_PDM_START + DMU_V2_MONITOR_SNAPSHOT, 0x0); + dmu_v2_write32(priv, DMU_V2_PDM_START + + DMU_V2_PDM_STRIDE + DMU_V2_MONITOR_SNAPSHOT, 0x0); +} + +/* devfreq Framework interface */ +static int phytium_dmu_get_dev_status(struct device *dev, struct devfreq_dev_status *stat) +{ + struct phytium_dmufreq *priv = dev_get_drvdata(dev); + + if (priv->info->type == PHYTIUM_DMU_V1) { + polling_handle_v1(priv); + priv->last_bust_time = stat->busy_time = priv->bandwidth; + } else { + polling_handle_v2(priv); + stat->busy_time = priv->bandwidth; + phytium_dmufreq_restart_clear_timer_v2(priv); + } + stat->total_time = (priv->single_threshold_value * priv->rate) / priv->freq_table[0]; + stat->current_frequency = priv->rate; + return 0; +} + +/* Power Management */ +static __maybe_unused int phytium_dmufreq_suspend(struct device *dev) +{ + struct phytium_dmufreq *priv = dev_get_drvdata(dev); + int ret = devfreq_suspend_device(priv->devfreq); + + if (ret < 0) + dev_err(dev, "failed to suspend the devfreq devices\n"); + return ret; +} + +static __maybe_unused int phytium_dmufreq_resume(struct device *dev) +{ + struct phytium_dmufreq *priv = dev_get_drvdata(dev); + int ret = devfreq_resume_device(priv->devfreq); + + if (ret < 0) + dev_err(dev, "failed to resume the devfreq devices\n"); + return ret; +} + +static SIMPLE_DEV_PM_OPS(phytium_dmufreq_pm, phytium_dmufreq_suspend, phytium_dmufreq_resume); + +static int phytium_dmufreq_probe(struct platform_device *pdev) +{ + struct phytium_dmufreq *priv; + struct device *dev = &pdev->dev; + const struct phytium_dmufreq_info *info; + struct acpi_result result; + struct resource *res; + const char *gov; + void *gov_data = NULL; + int i, ret; + unsigned int max_state; + + info = device_get_match_data(dev); + if (!info) { + dev_err(dev, "No match data for this device\n"); + return -ENODEV; + } + + max_state = get_freq_count(dev); + if (max_state <= 0) + return -EINVAL; + + result = phytium_dmufreq_state(dev); + if (result.value == 0) { + dev_err(dev, "DMUFREQ is not enabled\n"); + return -ENODEV; + } + + priv = devm_kzalloc(dev, struct_size(priv, freq_table, max_state), GFP_KERNEL); + if (!priv) + return -ENOMEM; + priv->info = info; + + if (info->type == PHYTIUM_DMU_V1) { + gov = DEVFREQ_GOV_PERFORMANCE; + gov_data = NULL; + } else { + gov = DEVFREQ_GOV_SIMPLE_ONDEMAND; + gov_data = &priv->ondemand_data; + } + + result = phytium_current_enabled_channels(dev); + if (result.status) { + dev_err(dev, "Failed to get enabled channels\n"); + return -EINVAL; + } + + priv->max_count = result.value; + result = phytium_read_threshold_value(dev); + if (result.status) { + dev_err(dev, "Failed to get threshold value\n"); + return -EINVAL; + } + priv->single_threshold_value = result.value; + priv->single_threshold_value = (priv->single_threshold_value * 1024 * 1024) / 10; + platform_set_drvdata(pdev, priv); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + + if (info->type == PHYTIUM_DMU_V1) { + /* V1: Multi-channel, allocation base/read_bw/write_bw */ + priv->basev1 = devm_kcalloc(dev, priv->max_count, + sizeof(void __iomem *), GFP_KERNEL); + priv->read_bw = devm_kcalloc(dev, priv->max_count, + sizeof(unsigned long), GFP_KERNEL); + priv->write_bw = devm_kcalloc(dev, priv->max_count, + sizeof(unsigned long), GFP_KERNEL); + if (!priv->basev1 || !priv->read_bw || !priv->write_bw) + return -ENOMEM; + for (i = 0; i < priv->max_count; i++) { + resource_size_t offset = res->start + i * DMU_V1_PMU_STRIDE; + + priv->basev1[i] = devm_ioremap(dev, offset, resource_size(res)); + if (IS_ERR(priv->basev1[i])) + return PTR_ERR(priv->basev1[i]); + } + /* Register PMU notification chain */ + priv->nb.notifier_call = dmu_pmu_notifier_call; + ret = blocking_notifier_chain_register(&dmu_pmu_notifier_chain, &priv->nb); + if (ret) { + dev_err(dev, "Failed to register notifier\n"); + return ret; + } + priv->pmu_active = true; + priv->cnt = 1; + dev->init_name = "dmufreq"; + } else { + /* V2: Single-channel multi-instance, allocate base, get uid */ + unsigned long long uid; + + mutex_init(&priv->lock); + acpi_evaluate_integer(ACPI_HANDLE(dev), "_UID", NULL, &uid); + priv->uid = uid; + priv->basev2 = devm_ioremap(dev, res->start, resource_size(res)); + if (IS_ERR(priv->basev2)) + return PTR_ERR(priv->basev2); + dev_set_name(dev, "dmu%u", priv->uid); + } + + ret = phytium_dmu_get_freq_info(dev); + if (ret) + return ret; + + priv->profile.initial_freq = priv->freq_table[0]; + priv->profile.polling_ms = 100; + priv->profile.timer = DEVFREQ_TIMER_DELAYED; + priv->profile.target = phytium_dmu_target; + priv->profile.get_cur_freq = phytium_dmu_get_cur_freq; + priv->profile.get_dev_status = phytium_dmu_get_dev_status; + priv->profile.freq_table = priv->freq_table; + priv->rate = priv->profile.initial_freq; + priv->profile.max_state = priv->freq_count; + priv->ondemand_data.upthreshold = 80; + priv->ondemand_data.downdifferential = 10; + + for (i = 0; i < max_state; ++i) { + ret = dev_pm_opp_add(dev, priv->freq_table[i], 0); + if (ret < 0) + goto err; + } + + priv->devfreq = devm_devfreq_add_device(dev, &priv->profile, gov, gov_data); + if (IS_ERR(priv->devfreq)) { + ret = PTR_ERR(priv->devfreq); + goto err; + } + + /* v1: Enable PMU */ + if (info->type == PHYTIUM_DMU_V1 && priv->pmu_active) { + for (i = 0; i < priv->max_count; i++) { + dmu_v1_write32(priv, i, DMU_V1_AXI_MONITOR_EN, 0x101); + dmu_v1_write32(priv, i, DMU_V1_CLEAR_EVENT, 0x1); + dmu_v1_write32(priv, i, DMU_V1_TIMER_START, 0x1); + } + } + + /* v2: Enable Monitoring */ + if (info->type == PHYTIUM_DMU_V2) { + dmu_v2_write32(priv, DMU_V2_PDM_START + + DMU_V2_MONITOR_START, 0x1); + dmu_v2_write32(priv, DMU_V2_PDM_START + + DMU_V2_PDM_STRIDE + DMU_V2_MONITOR_START, 0x1); + } + + priv->dev = dev; + return 0; +err: + dev_pm_opp_of_remove_table(dev); + return ret; +} + +static int phytium_dmufreq_remove(struct platform_device *pdev) +{ + struct phytium_dmufreq *priv = platform_get_drvdata(pdev); + struct device *dev = &pdev->dev; + int i; + + if (priv->info->type == PHYTIUM_DMU_V1) { + for (i = 0; i < priv->max_count; i++) { + dmu_v1_write32(priv, i, DMU_V1_TIMER_STOP, 0x1); + dmu_v1_write32(priv, i, DMU_V1_AXI_MONITOR_EN, 0x0); + } + blocking_notifier_chain_unregister(&dmu_pmu_notifier_chain, &priv->nb); + } + if (!priv->devfreq) + return 0; + dev_pm_opp_remove_all_dynamic(dev); + return 0; +} + +/* Matching Type Table */ +static const struct phytium_dmufreq_info phytium_dmu_v1_info = { + .type = PHYTIUM_DMU_V1, + .name = "phytium_dmu_v1", +}; + +static const struct phytium_dmufreq_info phytium_dmu_v2_info = { + .type = PHYTIUM_DMU_V2, + .name = "phytium_dmu_v2", +}; + +#ifdef CONFIG_ACPI +static const struct acpi_device_id phytium_dmufreq_acpi_ids[] = { + { "PHYT0063", (kernel_ulong_t)&phytium_dmu_v1_info }, + { "PHYT3011", (kernel_ulong_t)&phytium_dmu_v2_info }, + {}, +}; +MODULE_DEVICE_TABLE(acpi, phytium_dmufreq_acpi_ids); +#endif + +static struct platform_driver phytium_dmufreq_driver = { + .probe = phytium_dmufreq_probe, + .remove = phytium_dmufreq_remove, + .driver = { + .name = "phytium_dmufreq", + .pm = &phytium_dmufreq_pm, + +#ifdef CONFIG_ACPI + .acpi_match_table = phytium_dmufreq_acpi_ids, +#endif + .suppress_bind_attrs = true, + } +}; +module_platform_driver(phytium_dmufreq_driver); + +MODULE_DESCRIPTION("Phytium DDR Memory Unit frequency driver (v1/v2 unified)"); +MODULE_AUTHOR("Li Mingzhe "); +MODULE_LICENSE("GPL"); +MODULE_VERSION(DMUFREQ_DRIVER_VERSION); diff --git a/drivers/devfreq/phytium_noc.c b/drivers/devfreq/phytium_noc.c new file mode 100644 index 0000000000000..e9a60aea0ca4c --- /dev/null +++ b/drivers/devfreq/phytium_noc.c @@ -0,0 +1,635 @@ +// SPDX-License-Identifier: GPL-1.0 +/* + * Phytium Processor NOC Frequency Driver (v1/v2 unified) + * + * Copyright (C) 2024, Phytium Technology Co.,Ltd. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define NOCFREQ_DRIVER_VERSION "1.1.0" + +enum phytium_noc_type { + PHYTIUM_NOC_V1, + PHYTIUM_NOC_V2, +}; + +struct phytium_nocfreq_info { + enum phytium_noc_type type; + const char *name; +}; + +#define DEVICE_TYPE_V1 7 +#define DEVICE_TYPE_V2 7 + +/* v1 Register definition */ +#define V1_MINI_SIZE 0x400 +#define V1_CNT_ENABLE 0x000 +#define V1_WORK_STATE 0X004 +#define V1_CLR_EN 0X010 +#define V1_SNAPSHOT_EN 0X014 +#define V1_INT_CTRL_CLR 0x024 +#define V1_WR_NOLAST_HANDSHARK_NUM 0x44 + +/* v2 Register definition */ +#define V2_REG_NOC_STATUS 0x0 +#define V2_BUSY_CODE_MASK 0x1f +#define V2_BUSY_CODE_MAX 16 + +/* Fast ramp-up thresholds on each level (busy code out of 16) */ +#define V2_UP_225_TO_450_BUSY 4 +#define V2_UP_450_TO_900_BUSY 8 +#define V2_UP_900_TO_1800_BUSY 12 + +/* Hysteresis hold/down thresholds */ +#define V2_DOWN_450_TO_225_BUSY 2 +#define V2_DOWN_900_TO_450_BUSY 6 +#define V2_DOWN_1800_TO_900_BUSY 10 + +struct phytium_nocfreq { + struct device *dev; + const struct phytium_nocfreq_info *info; + + struct devfreq *devfreq; + struct devfreq_dev_profile profile; + struct devfreq_simple_ondemand_data ondemand_data; + + /* v1 only */ + void __iomem *reg_noc_v1; + + /* v2 only */ + void __iomem *reg_noc_v2; + unsigned int uid; + unsigned int v2_busy_code; + + struct mutex lock; + + unsigned long rate, target_rate, suspend_freq; + unsigned int freq_count; + unsigned long freq_table[]; +}; + +/* v1 Bandwidth acquisition */ +static u32 phytium_nocfreq_get_peak_bw_v1(struct phytium_nocfreq *priv) +{ + unsigned long peak_bw, bw_0, bw_1, bw_2, bw_3; + + bw_0 = readl_relaxed(priv->reg_noc_v1 + V1_WR_NOLAST_HANDSHARK_NUM); + bw_1 = readl_relaxed(priv->reg_noc_v1 + V1_MINI_SIZE*1 + + V1_WR_NOLAST_HANDSHARK_NUM); + bw_2 = readl_relaxed(priv->reg_noc_v1 + V1_MINI_SIZE*2 + + V1_WR_NOLAST_HANDSHARK_NUM); + bw_3 = readl_relaxed(priv->reg_noc_v1 + V1_MINI_SIZE*3 + + V1_WR_NOLAST_HANDSHARK_NUM); + + peak_bw = bw_0; + if (bw_1 > peak_bw) + peak_bw = bw_1; + if (bw_2 > peak_bw) + peak_bw = bw_2; + if (bw_3 > peak_bw) + peak_bw = bw_3; + return peak_bw; +} + +static void phytium_nocfreq_restart_handshark_counters_v1(struct phytium_nocfreq *priv) +{ + writel_relaxed(0x80000000, priv->reg_noc_v1 + V1_INT_CTRL_CLR); + writel_relaxed(0x80000000, priv->reg_noc_v1 + V1_MINI_SIZE*1 + V1_INT_CTRL_CLR); + writel_relaxed(0x80000000, priv->reg_noc_v1 + V1_MINI_SIZE*2 + V1_INT_CTRL_CLR); + writel_relaxed(0x80000000, priv->reg_noc_v1 + V1_MINI_SIZE*3 + V1_INT_CTRL_CLR); + + writel_relaxed(0x1, priv->reg_noc_v1 + V1_CLR_EN); + writel_relaxed(0x1, priv->reg_noc_v1 + V1_MINI_SIZE*1 + V1_CLR_EN); + writel_relaxed(0x1, priv->reg_noc_v1 + V1_MINI_SIZE*2 + V1_CLR_EN); + writel_relaxed(0x1, priv->reg_noc_v1 + V1_MINI_SIZE*3 + V1_CLR_EN); +} + +/* v2 Bandwidth acquisition */ +static u32 phytium_nocfreq_get_peak_bw_v2(struct phytium_nocfreq *priv) +{ + return readl_relaxed(priv->reg_noc_v2 + V2_REG_NOC_STATUS); +} + +static unsigned long phytium_nocfreq_min_rate(struct phytium_nocfreq *priv) +{ + unsigned long min_rate = priv->freq_table[0]; + int i; + + for (i = 1; i < priv->freq_count; i++) { + if (priv->freq_table[i] < min_rate) + min_rate = priv->freq_table[i]; + } + + return min_rate; +} + +static unsigned long phytium_nocfreq_max_rate(struct phytium_nocfreq *priv) +{ + unsigned long max_rate = priv->freq_table[0]; + int i; + + for (i = 1; i < priv->freq_count; i++) { + if (priv->freq_table[i] > max_rate) + max_rate = priv->freq_table[i]; + } + + return max_rate; +} + +static unsigned long phytium_nocfreq_next_higher_rate(struct phytium_nocfreq *priv, + unsigned long rate) +{ + unsigned long next_rate = ~0UL; + int i; + + for (i = 0; i < priv->freq_count; i++) { + if (priv->freq_table[i] > rate && priv->freq_table[i] < next_rate) + next_rate = priv->freq_table[i]; + } + + if (next_rate == ~0UL) + return rate; + + return next_rate; +} + +/* v1/v2 General frequency setting */ +static int phytium_noc_set_freq(struct device *dev, unsigned long freq) +{ + struct phytium_nocfreq *priv = dev_get_drvdata(dev); + acpi_handle handle = ACPI_HANDLE(dev); + union acpi_object args[4]; + struct acpi_object_list arg_list = { + .pointer = args, + .count = ARRAY_SIZE(args), + }; + acpi_status status; + unsigned long long ret; + + args[0].type = ACPI_TYPE_INTEGER; + args[0].integer.value = DEVICE_TYPE_V1; + args[1].type = ACPI_TYPE_INTEGER; + args[1].integer.value = freq; + + if (priv->info->type == PHYTIUM_NOC_V2) { + args[2].type = ACPI_TYPE_INTEGER; + args[2].integer.value = priv->uid; + } else { + args[2].type = ACPI_TYPE_INTEGER; + args[2].integer.value = 0; + } + args[3].type = ACPI_TYPE_INTEGER; + args[3].integer.value = 0; + + mutex_lock(&priv->lock); + status = acpi_evaluate_integer(handle, "PSCF", &arg_list, &ret); + mutex_unlock(&priv->lock); + + if (ACPI_FAILURE(status)) { + dev_err(dev, "No PSCF method\n"); + return -EIO; + } + if (ret) { + dev_err(dev, "Failed to set the freq to %lu\n", freq); + return -EIO; + } + dev_dbg(dev, "set target_freq = %lu khz\n", freq); + return 0; +} + +static int phytium_noc_target(struct device *dev, unsigned long *freq, u32 flags) +{ + struct phytium_nocfreq *priv = dev_get_drvdata(dev); + unsigned long old_freq = priv->rate; + unsigned long target_rate; + struct dev_pm_opp *opp; + int ret; + + opp = devfreq_recommended_opp(dev, freq, flags); + if (IS_ERR(opp)) + return PTR_ERR(opp); + + target_rate = dev_pm_opp_get_freq(opp); + dev_pm_opp_put(opp); + + if (priv->info->type == PHYTIUM_NOC_V2) { + unsigned long low = phytium_nocfreq_min_rate(priv); + unsigned long mid1 = phytium_nocfreq_next_higher_rate(priv, low); + unsigned long mid2 = phytium_nocfreq_next_higher_rate(priv, mid1); + unsigned long high = phytium_nocfreq_max_rate(priv); + + if (old_freq == low) { + if (priv->v2_busy_code >= V2_UP_225_TO_450_BUSY && mid1 > low && + target_rate < mid1) + target_rate = mid1; + } else if (old_freq == mid1) { + if (priv->v2_busy_code >= V2_UP_450_TO_900_BUSY && mid2 > mid1 && + target_rate < mid2) + target_rate = mid2; + else if (priv->v2_busy_code > V2_DOWN_450_TO_225_BUSY && + priv->v2_busy_code < V2_UP_450_TO_900_BUSY) + target_rate = mid1; + } else if (old_freq == mid2) { + if (priv->v2_busy_code >= V2_UP_900_TO_1800_BUSY && high > mid2 && + target_rate < high) + target_rate = high; + else if (priv->v2_busy_code > V2_DOWN_900_TO_450_BUSY && + priv->v2_busy_code < V2_UP_900_TO_1800_BUSY) + target_rate = mid2; + } else if (old_freq == high) { + if (priv->v2_busy_code > V2_DOWN_1800_TO_900_BUSY) + target_rate = high; + } + } + + if (target_rate == old_freq) + return 0; + + ret = phytium_noc_set_freq(dev, target_rate); + if (ret) { + dev_warn(dev, "failed to set noc frequency: %d\n", ret); + *freq = old_freq; + } + priv->rate = target_rate; + return ret; +} + +static int phytium_noc_get_cur_freq(struct device *dev, unsigned long *freq) +{ + struct phytium_nocfreq *priv = dev_get_drvdata(dev); + acpi_handle handle = ACPI_HANDLE(dev); + union acpi_object args[3]; + struct acpi_object_list arg_list = { + .pointer = args, + .count = ARRAY_SIZE(args), + }; + acpi_status status; + unsigned long long ret; + + args[0].type = ACPI_TYPE_INTEGER; + args[0].integer.value = DEVICE_TYPE_V1; + args[1].type = ACPI_TYPE_INTEGER; + args[1].integer.value = 0; + args[2].type = ACPI_TYPE_INTEGER; + args[2].integer.value = 0; + + mutex_lock(&priv->lock); + status = acpi_evaluate_integer(handle, "PGCF", &arg_list, &ret); + mutex_unlock(&priv->lock); + if (ACPI_FAILURE(status)) { + dev_err(dev, "No PGCF method\n"); + return -EIO; + } + if (ret < 0) { + dev_err(dev, "Failed to get the freq\n"); + return -EIO; + } + *freq = ret; + return 0; +} + +static int phytium_noc_get_freq_info(struct device *dev, u32 flags) +{ + struct phytium_nocfreq *priv = dev_get_drvdata(dev); + struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; + union acpi_object args[3], *package, *element; + struct acpi_object_list arg_list = { + .pointer = args, + .count = ARRAY_SIZE(args), + }; + acpi_handle handle = ACPI_HANDLE(dev); + acpi_status status; + int i; + + args[0].type = ACPI_TYPE_INTEGER; + args[0].integer.value = flags; + args[1].type = ACPI_TYPE_INTEGER; + args[1].integer.value = 0; + args[2].type = ACPI_TYPE_INTEGER; + args[2].integer.value = 0; + + status = acpi_evaluate_object(handle, "PGCL", &arg_list, &buffer); + if (ACPI_FAILURE(status)) { + dev_err(dev, "No PGCL method\n"); + return -EIO; + } + if (!buffer.length) { + dev_err(dev, "buffer is NULL\n"); + return -EINVAL; + } + + package = buffer.pointer; + element = &package->package.elements[1]; + priv->freq_count = element->integer.value; + + for (i = 0; i < priv->freq_count; i++) { + element = &package->package.elements[i+2]; + priv->freq_table[i] = element->integer.value; + dev_dbg(dev, "freq_table[%d] = %llu\n", i, element->integer.value); + } + kfree(buffer.pointer); + return 0; +} + +static int get_freq_count(struct device *dev) +{ + int freq_count = -1; + struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; + union acpi_object args[3], *package, *element; + struct acpi_object_list arg_list = { + .pointer = args, + .count = ARRAY_SIZE(args), + }; + acpi_handle handle = ACPI_HANDLE(dev); + acpi_status status; + + args[0].type = ACPI_TYPE_INTEGER; + args[0].integer.value = DEVICE_TYPE_V1; + args[1].type = ACPI_TYPE_INTEGER; + args[1].integer.value = 0; + args[2].type = ACPI_TYPE_INTEGER; + args[2].integer.value = 0; + + status = acpi_evaluate_object(handle, "PGCL", &arg_list, &buffer); + if (ACPI_FAILURE(status)) { + dev_err(dev, "No PGCL method\n"); + return -EIO; + } + if (!buffer.length) { + dev_err(dev, "buffer is NULL\n"); + return -EINVAL; + } + + package = buffer.pointer; + element = &package->package.elements[1]; + freq_count = element->integer.value; + dev_dbg(dev, "freq_count = %d\n", freq_count); + kfree(buffer.pointer); + return freq_count; +} + +static int phytium_noc_get_dev_status(struct device *dev, struct devfreq_dev_status *stat) +{ + struct phytium_nocfreq *priv = dev_get_drvdata(dev); + + if (priv->info->type == PHYTIUM_NOC_V1) { + writel_relaxed(0x1, priv->reg_noc_v1 + V1_SNAPSHOT_EN); + writel_relaxed(0x1, priv->reg_noc_v1 + V1_MINI_SIZE*1 + V1_SNAPSHOT_EN); + writel_relaxed(0x1, priv->reg_noc_v1 + V1_MINI_SIZE*2 + V1_SNAPSHOT_EN); + writel_relaxed(0x1, priv->reg_noc_v1 + V1_MINI_SIZE*3 + V1_SNAPSHOT_EN); + + stat->busy_time = phytium_nocfreq_get_peak_bw_v1(priv); + stat->total_time = 320000 * DIV_ROUND_CLOSEST(priv->rate * 100, + priv->profile.initial_freq); + stat->current_frequency = priv->rate; + + phytium_nocfreq_restart_handshark_counters_v1(priv); + } else { + u32 raw_busy = phytium_nocfreq_get_peak_bw_v2(priv); + u32 busy_code = raw_busy & V2_BUSY_CODE_MASK; + + if (busy_code > V2_BUSY_CODE_MAX) + busy_code = V2_BUSY_CODE_MAX; + + priv->v2_busy_code = busy_code; + stat->busy_time = busy_code; + stat->total_time = V2_BUSY_CODE_MAX; + stat->current_frequency = priv->rate; + } + return 0; +} + +static __maybe_unused int phytium_nocfreq_suspend(struct device *dev) +{ + struct phytium_nocfreq *priv = dev_get_drvdata(dev); + int ret = 0; + + ret = phytium_noc_get_cur_freq(dev, &priv->suspend_freq); + if (ret) + dev_warn(dev, "failed to get suspend freq\n"); + + ret = devfreq_suspend_device(priv->devfreq); + if (ret < 0) + dev_err(dev, "failed to suspend the devfreq devices\n"); + priv->devfreq->stop_polling = true; + + if (priv->info->type == PHYTIUM_NOC_V1) { + writel_relaxed(0x0, priv->reg_noc_v1 + V1_CNT_ENABLE); + writel_relaxed(0x0, priv->reg_noc_v1 + V1_MINI_SIZE*1+V1_CNT_ENABLE); + writel_relaxed(0x0, priv->reg_noc_v1 + V1_MINI_SIZE*2+V1_CNT_ENABLE); + writel_relaxed(0x0, priv->reg_noc_v1 + V1_MINI_SIZE*3+V1_CNT_ENABLE); + } + return ret; +} + +static __maybe_unused int phytium_nocfreq_resume(struct device *dev) +{ + struct phytium_nocfreq *priv = dev_get_drvdata(dev); + int ret = 0; + + ret = devfreq_resume_device(priv->devfreq); + if (ret < 0) + dev_err(dev, "failed to resume the devfreq devices\n"); + if (!delayed_work_pending(&priv->devfreq->work) && priv->devfreq->profile->polling_ms) + priv->devfreq->stop_polling = true; + + if (priv->info->type == PHYTIUM_NOC_V1) { + writel_relaxed(0x02, priv->reg_noc_v1 + V1_WORK_STATE); + writel_relaxed(0x02, priv->reg_noc_v1 + V1_MINI_SIZE*1 + V1_WORK_STATE); + writel_relaxed(0x02, priv->reg_noc_v1 + V1_MINI_SIZE*2 + V1_WORK_STATE); + writel_relaxed(0x02, priv->reg_noc_v1 + V1_MINI_SIZE*3 + V1_WORK_STATE); + + writel_relaxed(0x3f, priv->reg_noc_v1 + V1_CNT_ENABLE); + writel_relaxed(0x3f, priv->reg_noc_v1 + V1_MINI_SIZE*1+V1_CNT_ENABLE); + writel_relaxed(0x3f, priv->reg_noc_v1 + V1_MINI_SIZE*2+V1_CNT_ENABLE); + writel_relaxed(0x3f, priv->reg_noc_v1 + V1_MINI_SIZE*3+V1_CNT_ENABLE); + } + if (priv->suspend_freq) { + ret = phytium_noc_set_freq(dev, priv->suspend_freq); + if (ret < 0) + dev_warn(dev, "failed to restore suspend freq %lu\n", priv->suspend_freq); + else + priv->rate = priv->suspend_freq; + } + return ret; +} + +static SIMPLE_DEV_PM_OPS(phytium_nocfreq_pm, phytium_nocfreq_suspend, phytium_nocfreq_resume); + +static int phytium_nocfreq_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct phytium_nocfreq *priv; + const struct phytium_nocfreq_info *info; + const char *gov = DEVFREQ_GOV_SIMPLE_ONDEMAND; + int i, ret; + unsigned int max_state; + struct resource *mem; + + info = device_get_match_data(dev); + if (!info) { + dev_err(dev, "No match data for this device\n"); + return -ENODEV; + } + + max_state = get_freq_count(dev); + if (max_state <= 0) + return -EINVAL; + priv = devm_kzalloc(dev, struct_size(priv, freq_table, max_state), GFP_KERNEL); + if (!priv) + return -ENOMEM; + priv->info = info; + mutex_init(&priv->lock); + + platform_set_drvdata(pdev, priv); + + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!mem) { + dev_err(dev, "no mem resource"); + return -EINVAL; + } + + if (info->type == PHYTIUM_NOC_V1) { + priv->reg_noc_v1 = devm_ioremap_resource(dev, mem); + if (!priv->reg_noc_v1) + return PTR_ERR(priv->reg_noc_v1); + dev->init_name = "nocfreq"; + } else { + acpi_handle handle = ACPI_HANDLE(dev); + unsigned long long uid; + + ret = acpi_evaluate_integer(handle, "_UID", NULL, &uid); + priv->uid = uid; + priv->reg_noc_v2 = devm_ioremap_resource(dev, mem); + if (IS_ERR(priv->reg_noc_v2)) + return PTR_ERR(priv->reg_noc_v2); + dev_set_name(dev, "noc-%u", priv->uid); + } + + ret = phytium_noc_get_freq_info(dev, DEVICE_TYPE_V1); + if (ret) + return ret; + priv->profile.initial_freq = priv->freq_table[0]; + priv->profile.polling_ms = 100; + priv->profile.target = phytium_noc_target; + priv->profile.get_cur_freq = phytium_noc_get_cur_freq; + priv->profile.get_dev_status = phytium_noc_get_dev_status; + priv->profile.freq_table = priv->freq_table; + priv->profile.max_state = priv->freq_count; + priv->rate = priv->freq_table[0]; + + if (info->type == PHYTIUM_NOC_V1) { + priv->ondemand_data.upthreshold = 80; + priv->ondemand_data.downdifferential = 10; + } else { + priv->ondemand_data.upthreshold = 80; + priv->ondemand_data.downdifferential = 10; + } + + for (i = 0; i < max_state; ++i) { + ret = dev_pm_opp_add(dev, priv->freq_table[i], 0); + if (ret < 0) + goto err; + } + priv->devfreq = devm_devfreq_add_device(dev, &priv->profile, gov, &priv->ondemand_data); + if (IS_ERR(priv->devfreq)) { + ret = PTR_ERR(priv->devfreq); + goto err; + } + ret = phytium_noc_set_freq(dev, priv->profile.initial_freq); + if (ret) + dev_warn(dev, "failed to init noc frequency: %d\n", ret); + + if (info->type == PHYTIUM_NOC_V1) { + writel_relaxed(0x02, priv->reg_noc_v1 + V1_WORK_STATE); + writel_relaxed(0x02, priv->reg_noc_v1 + V1_MINI_SIZE*1 + V1_WORK_STATE); + writel_relaxed(0x02, priv->reg_noc_v1 + V1_MINI_SIZE*2 + V1_WORK_STATE); + writel_relaxed(0x02, priv->reg_noc_v1 + V1_MINI_SIZE*3 + V1_WORK_STATE); + + writel_relaxed(0x3f, priv->reg_noc_v1 + V1_CNT_ENABLE); + writel_relaxed(0x3f, priv->reg_noc_v1 + V1_MINI_SIZE*1 + V1_CNT_ENABLE); + writel_relaxed(0x3f, priv->reg_noc_v1 + V1_MINI_SIZE*2 + V1_CNT_ENABLE); + writel_relaxed(0x3f, priv->reg_noc_v1 + V1_MINI_SIZE*3 + V1_CNT_ENABLE); + } + return 0; +err: + dev_pm_opp_of_remove_table(dev); + return ret; +} + +static int phytium_nocfreq_remove(struct platform_device *pdev) +{ + struct phytium_nocfreq *priv = platform_get_drvdata(pdev); + unsigned long initial_freq = priv->profile.initial_freq; + struct device *dev = &pdev->dev; + int ret; + + if (priv->info->type == PHYTIUM_NOC_V1) { + writel_relaxed(0x0, priv->reg_noc_v1 + V1_CNT_ENABLE); + writel_relaxed(0x0, priv->reg_noc_v1 + V1_MINI_SIZE*1 + V1_CNT_ENABLE); + writel_relaxed(0x0, priv->reg_noc_v1 + V1_MINI_SIZE*2 + V1_CNT_ENABLE); + writel_relaxed(0x0, priv->reg_noc_v1 + V1_MINI_SIZE*3 + V1_CNT_ENABLE); + + writel_relaxed(0x1, priv->reg_noc_v1 + V1_CLR_EN); + writel_relaxed(0x1, priv->reg_noc_v1 + V1_MINI_SIZE*1 + V1_CLR_EN); + writel_relaxed(0x1, priv->reg_noc_v1 + V1_MINI_SIZE*2 + V1_CLR_EN); + writel_relaxed(0x1, priv->reg_noc_v1 + V1_MINI_SIZE*3 + V1_CLR_EN); + } + + ret = phytium_noc_set_freq(dev, initial_freq); + if (ret) + dev_warn(dev, "failed to restore NOC frequency: %d\n", ret); + + if (!priv->devfreq) + return 0; + dev_pm_opp_remove_all_dynamic(dev); + return 0; +} + +/* Matching Type Table */ +static const struct phytium_nocfreq_info phytium_noc_v1_info = { + .type = PHYTIUM_NOC_V1, + .name = "phytium_noc_v1", +}; +static const struct phytium_nocfreq_info phytium_noc_v2_info = { + .type = PHYTIUM_NOC_V2, + .name = "phytium_noc_v2", +}; + +#ifdef CONFIG_ACPI +static const struct acpi_device_id phytium_noc_acpi_ids[] = { + { "PHYT0047", (kernel_ulong_t)&phytium_noc_v1_info }, + { "PHYT3010", (kernel_ulong_t)&phytium_noc_v2_info }, + {}, +}; +MODULE_DEVICE_TABLE(acpi, phytium_noc_acpi_ids); +#endif + +static struct platform_driver phytium_nocfreq_driver = { + .probe = phytium_nocfreq_probe, + .remove = phytium_nocfreq_remove, + .driver = { + .name = "phytium_nocfreq", + .pm = &phytium_nocfreq_pm, +#ifdef CONFIG_ACPI + .acpi_match_table = phytium_noc_acpi_ids, +#endif + .suppress_bind_attrs = true, + }, +}; +module_platform_driver(phytium_nocfreq_driver); + +MODULE_DESCRIPTION("Phytium NOC Controller frequency driver (v1/v2 unified)"); +MODULE_AUTHOR("Li Mingzhe "); +MODULE_LICENSE("GPL"); +MODULE_VERSION(NOCFREQ_DRIVER_VERSION); diff --git a/drivers/firmware/efi/cper.c b/drivers/firmware/efi/cper.c index 511309542d245..5d31b602ef42c 100644 --- a/drivers/firmware/efi/cper.c +++ b/drivers/firmware/efi/cper.c @@ -547,12 +547,17 @@ static void cper_print_pcie(const char *pfx, const struct cper_sec_pcie *pcie, "%s""bridge: secondary_status: 0x%04x, control: 0x%04x\n", pfx, pcie->bridge.secondary_status, pcie->bridge.control); - /* Fatal errors call __ghes_panic() before AER handler prints this */ - if ((pcie->validation_bits & CPER_PCIE_VALID_AER_INFO) && - (gdata->error_severity & CPER_SEV_FATAL)) { + /* + * Print all valid AER info. Record may be from BERT (boot-time) or GHES (run-time). + * + * Fatal errors call __ghes_panic() before AER handler prints this. + */ + if (pcie->validation_bits & CPER_PCIE_VALID_AER_INFO) { struct aer_capability_regs *aer; aer = (struct aer_capability_regs *)pcie->aer_info; + printk("%saer_cor_status: 0x%08x, aer_cor_mask: 0x%08x\n", + pfx, aer->cor_status, aer->cor_mask); printk("%saer_uncor_status: 0x%08x, aer_uncor_mask: 0x%08x\n", pfx, aer->uncor_status, aer->uncor_mask); printk("%saer_uncor_severity: 0x%08x\n", diff --git a/drivers/hwmon/zhaoxin-cputemp.c b/drivers/hwmon/zhaoxin-cputemp.c index 8286665f2c55d..9eca3a3efaa19 100644 --- a/drivers/hwmon/zhaoxin-cputemp.c +++ b/drivers/hwmon/zhaoxin-cputemp.c @@ -122,7 +122,7 @@ static int zhaoxin_cputemp_probe(struct platform_device *pdev) data->id = pdev->id; data->name = "zhaoxin_cputemp"; data->msr_temp = 0x1423; - if (c->x86_model == 0x6b || c->x86_model == 0x7b) { + if (c->x86_model == 0x6b || c->x86_model == 0x7b || c->x86_model == 0x8b) { data->msr_crit = 0x175b; data->msr_max = 0x175a; } else { @@ -265,6 +265,8 @@ static const struct x86_cpu_id __initconst cputemp_ids[] = { X86_MATCH_VENDOR_FAM_MODEL(ZHAOXIN, 7, 0x6b, NULL), X86_MATCH_VENDOR_FAM_MODEL(CENTAUR, 7, 0x7b, NULL), X86_MATCH_VENDOR_FAM_MODEL(ZHAOXIN, 7, 0x7b, NULL), + X86_MATCH_VENDOR_FAM_MODEL(CENTAUR, 7, 0x8b, NULL), + X86_MATCH_VENDOR_FAM_MODEL(ZHAOXIN, 7, 0x8b, NULL), {} }; MODULE_DEVICE_TABLE(x86cpu, cputemp_ids); diff --git a/drivers/pinctrl/zhaoxin/pinctrl-kh50000.c b/drivers/pinctrl/zhaoxin/pinctrl-kh50000.c index 8c607953eaf30..279110cd56d3d 100644 --- a/drivers/pinctrl/zhaoxin/pinctrl-kh50000.c +++ b/drivers/pinctrl/zhaoxin/pinctrl-kh50000.c @@ -16,166 +16,184 @@ #include "pinctrl-zhaoxin.h" +#define KH50000_SOCKET_PINS(sock) \ + SOCKET_PINCTRL_PIN(sock, 0, "IOD_CLK27M_G0"), \ + SOCKET_PINCTRL_PIN(sock, 1, "IOD_CLK27M_G1"), \ + SOCKET_PINCTRL_PIN(sock, 2, "IOD_CLK27M_G2"), \ + SOCKET_PINCTRL_PIN(sock, 3, "IOD_CLK27M_G3"), \ + SOCKET_PINCTRL_PIN(sock, 4, "IOD_CPURST_G0"), \ + SOCKET_PINCTRL_PIN(sock, 5, "IOD_CPURST_G1"), \ + SOCKET_PINCTRL_PIN(sock, 6, "IOD_CPURST_G2"), \ + SOCKET_PINCTRL_PIN(sock, 7, "IOD_CPURST_G3"), \ + SOCKET_PINCTRL_PIN(sock, 8, "IOD_RSMRST_G0"), \ + SOCKET_PINCTRL_PIN(sock, 9, "IOD_RSMRST_G1"), \ + SOCKET_PINCTRL_PIN(sock, 10, "IOD_RSMRST_G2"), \ + SOCKET_PINCTRL_PIN(sock, 11, "IOD_RSMRST_G3"), \ + SOCKET_PINCTRL_PIN(sock, 12, "IOD_PWROK_G0"), \ + SOCKET_PINCTRL_PIN(sock, 13, "IOD_PWROK_G1"), \ + SOCKET_PINCTRL_PIN(sock, 14, "IOD_PWROK_G2"), \ + SOCKET_PINCTRL_PIN(sock, 15, "IOD_PWROK_G3"), \ + SOCKET_PINCTRL_PIN(sock, 16, "IOD_THRMTRIP_G0"), \ + SOCKET_PINCTRL_PIN(sock, 17, "IOD_THRMTRIP_G1"), \ + SOCKET_PINCTRL_PIN(sock, 18, "IOD_THRMTRIP_G2"), \ + SOCKET_PINCTRL_PIN(sock, 19, "IOD_THRMTRIP_G3"), \ + SOCKET_PINCTRL_PIN(sock, 20, "IOD_CLK50M_G0"), \ + SOCKET_PINCTRL_PIN(sock, 21, "IOD_CLK50M_G1"), \ + SOCKET_PINCTRL_PIN(sock, 22, "IOD_CLK50M_G2"), \ + SOCKET_PINCTRL_PIN(sock, 23, "IOD_CLK50M_G3"), \ + /*GPIO range 0 */ \ + SOCKET_PINCTRL_PIN(sock, 24, "USBHOC0"), /*PGPIO0------gpio36*/ \ + SOCKET_PINCTRL_PIN(sock, 25, "USBHOC1"), /*PGPIO1------gpio37*/ \ + SOCKET_PINCTRL_PIN(sock, 26, "USBHOC2"), /*PGPIO2------gpio38*/ \ + SOCKET_PINCTRL_PIN(sock, 27, "USBHOC3"), /*PGPIO3------gpio39*/ \ + SOCKET_PINCTRL_PIN(sock, 28, "I3C0DT"), \ + SOCKET_PINCTRL_PIN(sock, 29, "I3C0CK"), \ + SOCKET_PINCTRL_PIN(sock, 30, "I3C1DT"), \ + SOCKET_PINCTRL_PIN(sock, 31, "I3C1CK"), \ + SOCKET_PINCTRL_PIN(sock, 32, "I3C2DT"), \ + SOCKET_PINCTRL_PIN(sock, 33, "I3C2CK"), \ + SOCKET_PINCTRL_PIN(sock, 34, "I3C3DT"), \ + SOCKET_PINCTRL_PIN(sock, 35, "I3C3CK"), \ + SOCKET_PINCTRL_PIN(sock, 36, "SMBDT0"), \ + /*GPIO range 1*/ \ + SOCKET_PINCTRL_PIN(sock, 37, "SMBCK0"), /*PGPIO11------gpio47*/ \ + SOCKET_PINCTRL_PIN(sock, 38, "SMBDT1"), /*PGPIO12------gpio48*/ \ + SOCKET_PINCTRL_PIN(sock, 39, "SMBCK1"), /*PGPIO13------gpio49*/ \ + SOCKET_PINCTRL_PIN(sock, 40, "SMBDT2"), /*PGPIO7------gpio43*/ \ + SOCKET_PINCTRL_PIN(sock, 41, "SMBCK2"), /*PGPIO8------gpio44*/ \ + SOCKET_PINCTRL_PIN(sock, 42, "SMBALRT"), /*PGPIO14------gpio50*/ \ + SOCKET_PINCTRL_PIN(sock, 43, "SME_I2CDT_S"), \ + SOCKET_PINCTRL_PIN(sock, 44, "SME_I2CCK_S"), \ + /*GPIO range 2*/ \ + SOCKET_PINCTRL_PIN(sock, 45, "GPIO0"), /*GPIO0--------gpio0*/ \ + SOCKET_PINCTRL_PIN(sock, 46, "GPIO1"), /*GPIO1--------gpio1*/ \ + SOCKET_PINCTRL_PIN(sock, 47, "GPIO2"), /*GPIO2--------gpio2*/ \ + SOCKET_PINCTRL_PIN(sock, 48, "GPIO3"), /*GPIO3--------gpio3*/ \ + SOCKET_PINCTRL_PIN(sock, 49, "GPIO4"), /*GPIO4--------gpio4*/ \ + SOCKET_PINCTRL_PIN(sock, 50, "GPIO5"), /*GPIO5--------gpio5*/ \ + SOCKET_PINCTRL_PIN(sock, 51, "GPIO6"), /*GPIO6--------gpio6*/ \ + SOCKET_PINCTRL_PIN(sock, 52, "GPIO7"), /*GPIO7--------gpio7*/ \ + SOCKET_PINCTRL_PIN(sock, 53, "GPIO8"), /*GPIO8--------gpio8*/ \ + SOCKET_PINCTRL_PIN(sock, 54, "GPIO9"), /*GPIO9--------gpio9*/ \ + SOCKET_PINCTRL_PIN(sock, 55, "GPIO10"), /*GPIO10-------gpio10*/ \ + SOCKET_PINCTRL_PIN(sock, 56, "GPIO11"), /*GPIO11-------gpio11*/ \ + SOCKET_PINCTRL_PIN(sock, 57, "GPIO12"), /*GPIO12-------gpio12*/ \ + SOCKET_PINCTRL_PIN(sock, 58, "GPIO13"), /*GPIO13-------gpio13*/ \ + SOCKET_PINCTRL_PIN(sock, 59, "GPIO14"), /*GPIO14-------gpio14*/ \ + SOCKET_PINCTRL_PIN(sock, 60, "GPIO15"), /*GPIO15-------gpio15*/ \ + SOCKET_PINCTRL_PIN(sock, 61, "GPIO16"), /*GPIO16-------gpio16*/ \ + SOCKET_PINCTRL_PIN(sock, 62, "GPIO17"), /*GPIO17-------gpio17*/ \ + SOCKET_PINCTRL_PIN(sock, 63, "GPIO18"), /*GPIO18-------gpio18*/ \ + SOCKET_PINCTRL_PIN(sock, 64, "GPIO19"), /*GPIO19-------gpio19*/ \ + SOCKET_PINCTRL_PIN(sock, 65, "GPIO20"), /*GPIO20-------gpio20*/ \ + SOCKET_PINCTRL_PIN(sock, 66, "GPIO21"), /*GPIO21-------gpio21*/ \ + SOCKET_PINCTRL_PIN(sock, 67, "GPIO22"), /*GPIO22-------gpio22*/ \ + SOCKET_PINCTRL_PIN(sock, 68, "GPIO23"), /*GPIO23-------gpio23*/ \ + SOCKET_PINCTRL_PIN(sock, 69, "GPIO24"), /*GPIO24-------gpio24*/ \ + SOCKET_PINCTRL_PIN(sock, 70, "GPIO25"), /*GPIO25-------gpio25*/ \ + SOCKET_PINCTRL_PIN(sock, 71, "GPIO26"), /*GPIO26-------gpio26*/ \ + SOCKET_PINCTRL_PIN(sock, 72, "GPIO27"), /*GPIO27-------gpio27*/ \ + SOCKET_PINCTRL_PIN(sock, 73, "GPIO28"), /*GPIO28-------gpio28*/ \ + SOCKET_PINCTRL_PIN(sock, 74, "GPIO29"), /*GPIO29-------gpio29*/ \ + SOCKET_PINCTRL_PIN(sock, 75, "GPIO30"), /*GPIO30-------gpio30*/ \ + SOCKET_PINCTRL_PIN(sock, 76, "GPIO31"), /*GPIO31-------gpio31*/ \ + SOCKET_PINCTRL_PIN(sock, 77, "GPIO32"), /*GPIO32-------gpio32*/ \ + SOCKET_PINCTRL_PIN(sock, 78, "GPIO33"), /*GPIO33-------gpio33*/ \ + SOCKET_PINCTRL_PIN(sock, 79, "GPIO34"), /*GPIO34-------gpio34*/ \ + SOCKET_PINCTRL_PIN(sock, 80, "GPIO35"), /*GPIO35-------gpio35*/ \ + /*GPIO range 3*/ \ + SOCKET_PINCTRL_PIN(sock, 81, "LPCCLK"), /*PGPIO16------gpio52*/ \ + SOCKET_PINCTRL_PIN(sock, 82, "LPCDRQ1"), /*PGPIO17------gpio53*/ \ + SOCKET_PINCTRL_PIN(sock, 83, "LPCDRQ0"), /*PGPIO18------gpio54*/ \ + SOCKET_PINCTRL_PIN(sock, 84, "LPCFRAME"), /*PGPIO19------gpio55*/ \ + SOCKET_PINCTRL_PIN(sock, 85, "LPCAD3"), /*PGPIO20------gpio56*/ \ + SOCKET_PINCTRL_PIN(sock, 86, "LPCAD2"), /*PGPIO21------gpio57*/ \ + SOCKET_PINCTRL_PIN(sock, 87, "LPCAD1"), /*PGPIO22------gpio58*/ \ + SOCKET_PINCTRL_PIN(sock, 88, "LPCAD0"), /*PGPIO23------gpio59*/ \ + SOCKET_PINCTRL_PIN(sock, 89, "SERIRQ"), /*PGPIO24------gpio60*/ \ + /*GPIO range 4*/ \ + SOCKET_PINCTRL_PIN(sock, 90, "ESPICLK"), /*PGPIO15------gpio51*/ \ + /*GPIO range 5*/ \ + SOCKET_PINCTRL_PIN(sock, 91, "ESPIRST"), /*PGPIO29------gpio65*/ \ + SOCKET_PINCTRL_PIN(sock, 92, "ESPICS"), /*PGPIO30------gpio66*/ \ + SOCKET_PINCTRL_PIN(sock, 93, "ESPIIO3"), /*PGPIO31------gpio67*/ \ + /*GPIO range 6*/ \ + SOCKET_PINCTRL_PIN(sock, 94, "ESPIIO2"), /*PGPIO4------gpio40*/ \ + SOCKET_PINCTRL_PIN(sock, 95, "ESPIIO1"), /*PGPIO5------gpio41*/ \ + SOCKET_PINCTRL_PIN(sock, 96, "ESPIIO0"), /*PGPIO6------gpio42*/ \ + /* jump */ \ + SOCKET_PINCTRL_PIN(sock, 97, "SPIDI"), \ + SOCKET_PINCTRL_PIN(sock, 98, "SPIDO"), \ + SOCKET_PINCTRL_PIN(sock, 99, "SPICLK"), \ + SOCKET_PINCTRL_PIN(sock, 100, "SPISS"), \ + SOCKET_PINCTRL_PIN(sock, 101, "TPMRST"), \ + SOCKET_PINCTRL_PIN(sock, 102, "TPMIRQ"), \ + SOCKET_PINCTRL_PIN(sock, 103, "MSPIDI"), \ + SOCKET_PINCTRL_PIN(sock, 104, "MSPIDO"), \ + SOCKET_PINCTRL_PIN(sock, 105, "MSPIIO2"), \ + SOCKET_PINCTRL_PIN(sock, 106, "MSPIIO3"), \ + SOCKET_PINCTRL_PIN(sock, 107, "MSPICLK"), \ + SOCKET_PINCTRL_PIN(sock, 108, "MSPISS0"), \ + /*GPIO range 7*/ \ + SOCKET_PINCTRL_PIN(sock, 109, "MSPISS1"), /*PGPIO9------gpio45*/ \ + /*GPIO range 8 */ \ + SOCKET_PINCTRL_PIN(sock, 110, "MSPISS2"), /*PGPIO22------gpio58*/ \ + /*GPIO range 9*/ \ + SOCKET_PINCTRL_PIN(sock, 111, "SPIDEVINT"), /*PGPIO25------gpio61*/ \ + /*jump*/ \ + SOCKET_PINCTRL_PIN(sock, 112, "ZLSDATA_TX_P0"), \ + SOCKET_PINCTRL_PIN(sock, 113, "ZLSDATA_RX_P0"), \ + SOCKET_PINCTRL_PIN(sock, 114, "ZLSDATA_TX_P1"), \ + SOCKET_PINCTRL_PIN(sock, 115, "ZLSDATA_RX_P1"), \ + SOCKET_PINCTRL_PIN(sock, 116, "ZLSDATA_TX_P2"), \ + SOCKET_PINCTRL_PIN(sock, 117, "ZLSDATA_RX_P2"), \ + SOCKET_PINCTRL_PIN(sock, 118, "BOOT_EN"), \ + SOCKET_PINCTRL_PIN(sock, 119, "BOOT_DONE"), \ + SOCKET_PINCTRL_PIN(sock, 120, "MST_SKT"), \ + SOCKET_PINCTRL_PIN(sock, 121, "HRX_BEVO_CLK"), \ + SOCKET_PINCTRL_PIN(sock, 122, "HRX_BEVO_DATA"), \ + SOCKET_PINCTRL_PIN(sock, 123, "HTX_BEVO_CLK"), \ + SOCKET_PINCTRL_PIN(sock, 124, "HTX_BEVO_DATA"), \ + SOCKET_PINCTRL_PIN(sock, 125, "THRMTRIP_I"), \ + SOCKET_PINCTRL_PIN(sock, 126, "CLK50M_I"), \ + SOCKET_PINCTRL_PIN(sock, 127, "CLK50M_O"), \ + SOCKET_PINCTRL_PIN(sock, 128, "PCIRST_IO"), \ + SOCKET_PINCTRL_PIN(sock, 129, "RSMRST_IO"), \ + SOCKET_PINCTRL_PIN(sock, 130, "PWRGD_IO"), \ + SOCKET_PINCTRL_PIN(sock, 131, "CLK32K_IO"), \ + SOCKET_PINCTRL_PIN(sock, 132, "BIOSSEL"), \ + SOCKET_PINCTRL_PIN(sock, 133, "THRMRIP"), \ + /*GPIO range 10 */ \ + SOCKET_PINCTRL_PIN(sock, 134, "THRM"), /*PGPIO26------gpio62*/ \ + /*GPIO range 11*/ \ + SOCKET_PINCTRL_PIN(sock, 135, "PEXWAKE"), /*PGPIO10------gpio46*/ \ + /*jump*/ \ + SOCKET_PINCTRL_PIN(sock, 136, "PWRBTN"), \ + SOCKET_PINCTRL_PIN(sock, 137, "PCIRST"), \ + /*GPIO range 12*/ \ + SOCKET_PINCTRL_PIN(sock, 138, "SPKR"), /*PGPIO27------gpio63*/ \ + SOCKET_PINCTRL_PIN(sock, 139, "PME"), /*PGPIO28------gpio64*/ \ + SOCKET_PINCTRL_PIN(sock, 140, "SUSA"), \ + SOCKET_PINCTRL_PIN(sock, 141, "SUSB"), \ + SOCKET_PINCTRL_PIN(sock, 142, "SUSC"), \ + SOCKET_PINCTRL_PIN(sock, 143, "SVID0_VREN"), \ + SOCKET_PINCTRL_PIN(sock, 144, "SVID1_VREN"), + /* kh50000 pin define */ -static const struct pinctrl_pin_desc kh50000_pins[] = { - PINCTRL_PIN(0, "IOD_CLK27M_G0"), - PINCTRL_PIN(1, "IOD_CLK27M_G1"), - PINCTRL_PIN(2, "IOD_CLK27M_G2"), - PINCTRL_PIN(3, "IOD_CLK27M_G3"), - PINCTRL_PIN(4, "IOD_CPURST_G0"), - PINCTRL_PIN(5, "IOD_CPURST_G1"), - PINCTRL_PIN(6, "IOD_CPURST_G2"), - PINCTRL_PIN(7, "IOD_CPURST_G3"), - PINCTRL_PIN(8, "IOD_RSMRST_G0"), - PINCTRL_PIN(9, "IOD_RSMRST_G1"), - PINCTRL_PIN(10, "IOD_RSMRST_G2"), - PINCTRL_PIN(11, "IOD_RSMRST_G3"), - PINCTRL_PIN(12, "IOD_PWROK_G0"), - PINCTRL_PIN(13, "IOD_PWROK_G1"), - PINCTRL_PIN(14, "IOD_PWROK_G2"), - PINCTRL_PIN(15, "IOD_PWROK_G3"), - PINCTRL_PIN(16, "IOD_THRMTRIP_G0"), - PINCTRL_PIN(17, "IOD_THRMTRIP_G1"), - PINCTRL_PIN(18, "IOD_THRMTRIP_G2"), - PINCTRL_PIN(19, "IOD_THRMTRIP_G3"), - PINCTRL_PIN(20, "IOD_CLK50M_G0"), - PINCTRL_PIN(21, "IOD_CLK50M_G1"), - PINCTRL_PIN(22, "IOD_CLK50M_G2"), - PINCTRL_PIN(23, "IOD_CLK50M_G3"), - /* GPIO range 0 */ - PINCTRL_PIN(24, "USBHOC0"), - PINCTRL_PIN(25, "USBHOC1"), - PINCTRL_PIN(26, "USBHOC2"), - PINCTRL_PIN(27, "USBHOC3"), - PINCTRL_PIN(28, "I3C0DT"), - PINCTRL_PIN(29, "I3C0CK"), - PINCTRL_PIN(30, "I3C1DT"), - PINCTRL_PIN(31, "I3C1CK"), - PINCTRL_PIN(32, "I3C2DT"), - PINCTRL_PIN(33, "I3C2CK"), - PINCTRL_PIN(34, "I3C3DT"), - PINCTRL_PIN(35, "I3C3CK"), - PINCTRL_PIN(36, "SMBDT0"), - /* GPIO range 1 */ - PINCTRL_PIN(37, "SMBCK0"), - PINCTRL_PIN(38, "SMBDT1"), - PINCTRL_PIN(39, "SMBCK1"), - PINCTRL_PIN(40, "SMBDT2"), - PINCTRL_PIN(41, "SMBCK2"), - PINCTRL_PIN(42, "SMBALRT"), - PINCTRL_PIN(43, "SME_I2CDT_S"), - PINCTRL_PIN(44, "SME_I2CCK_S"), - /* GPIO range 2 */ - PINCTRL_PIN(45, "GPIO0"), - PINCTRL_PIN(46, "GPIO1"), - PINCTRL_PIN(47, "GPIO2"), - PINCTRL_PIN(48, "GPIO3"), - PINCTRL_PIN(49, "GPIO4"), - PINCTRL_PIN(50, "GPIO5"), - PINCTRL_PIN(51, "GPIO6"), - PINCTRL_PIN(52, "GPIO7"), - PINCTRL_PIN(53, "GPIO8"), - PINCTRL_PIN(54, "GPIO9"), - PINCTRL_PIN(55, "GPIO10"), - PINCTRL_PIN(56, "GPIO11"), - PINCTRL_PIN(57, "GPIO12"), - PINCTRL_PIN(58, "GPIO13"), - PINCTRL_PIN(59, "GPIO14"), - PINCTRL_PIN(60, "GPIO15"), - PINCTRL_PIN(61, "GPIO16"), - PINCTRL_PIN(62, "GPIO17"), - PINCTRL_PIN(63, "GPIO18"), - PINCTRL_PIN(64, "GPIO19"), - PINCTRL_PIN(65, "GPIO20"), - PINCTRL_PIN(66, "GPIO21"), - PINCTRL_PIN(67, "GPIO22"), - PINCTRL_PIN(68, "GPIO23"), - PINCTRL_PIN(69, "GPIO24"), - PINCTRL_PIN(70, "GPIO25"), - PINCTRL_PIN(71, "GPIO26"), - PINCTRL_PIN(72, "GPIO27"), - PINCTRL_PIN(73, "GPIO28"), - PINCTRL_PIN(74, "GPIO29"), - PINCTRL_PIN(75, "GPIO30"), - PINCTRL_PIN(76, "GPIO31"), - PINCTRL_PIN(77, "GPIO32"), - PINCTRL_PIN(78, "GPIO33"), - PINCTRL_PIN(79, "GPIO34"), - PINCTRL_PIN(80, "GPIO35"), - /* GPIO range 3 */ - PINCTRL_PIN(81, "LPCCLK"), - PINCTRL_PIN(82, "LPCDRQ1"), - PINCTRL_PIN(83, "LPCDRQ0"), - PINCTRL_PIN(84, "LPCFRAME"), - PINCTRL_PIN(85, "LPCAD3"), - PINCTRL_PIN(86, "LPCAD2"), - PINCTRL_PIN(87, "LPCAD1"), - PINCTRL_PIN(88, "LPCAD0"), - PINCTRL_PIN(89, "SERIRQ"), - /* GPIO range 4 */ - PINCTRL_PIN(90, "ESPICLK"), - /* GPIO range 5 */ - PINCTRL_PIN(91, "ESPIRST"), - PINCTRL_PIN(92, "ESPICS"), - PINCTRL_PIN(93, "ESPIIO3"), - /* GPIO range 6 */ - PINCTRL_PIN(94, "ESPIIO2"), - PINCTRL_PIN(95, "ESPIIO1"), - PINCTRL_PIN(96, "ESPIIO0"), - PINCTRL_PIN(97, "SPIDI"), - PINCTRL_PIN(98, "SPIDO"), - PINCTRL_PIN(99, "SPICLK"), - PINCTRL_PIN(100, "SPISS"), - PINCTRL_PIN(101, "TPMRST"), - PINCTRL_PIN(102, "TPMIRQ"), - PINCTRL_PIN(103, "MSPIDI"), - PINCTRL_PIN(104, "MSPIDO"), - PINCTRL_PIN(105, "MSPIIO2"), - PINCTRL_PIN(106, "MSPIIO3"), - PINCTRL_PIN(107, "MSPICLK"), - PINCTRL_PIN(108, "MSPISS0"), - /* GPIO range 7 */ - PINCTRL_PIN(109, "MSPISS1"), - /* GPIO range 8 */ - PINCTRL_PIN(110, "MSPISS2"), - /* GPIO range 9 */ - PINCTRL_PIN(111, "SPIDEVINT"), - PINCTRL_PIN(112, "ZLSDATA_TX_P0"), - PINCTRL_PIN(113, "ZLSDATA_RX_P0"), - PINCTRL_PIN(114, "ZLSDATA_TX_P1"), - PINCTRL_PIN(115, "ZLSDATA_RX_P1"), - PINCTRL_PIN(116, "ZLSDATA_TX_P2"), - PINCTRL_PIN(117, "ZLSDATA_RX_P2"), - PINCTRL_PIN(118, "BOOT_EN"), - PINCTRL_PIN(119, "BOOT_DONE"), - PINCTRL_PIN(120, "MST_SKT"), - PINCTRL_PIN(121, "HRX_BEVO_CLK"), - PINCTRL_PIN(122, "HRX_BEVO_DATA"), - PINCTRL_PIN(123, "HTX_BEVO_CLK"), - PINCTRL_PIN(124, "HTX_BEVO_DATA"), - PINCTRL_PIN(125, "THRMTRIP_I"), - PINCTRL_PIN(126, "CLK50M_I"), - PINCTRL_PIN(127, "CLK50M_O"), - PINCTRL_PIN(128, "PCIRST_IO"), - PINCTRL_PIN(129, "RSMRST_IO"), - PINCTRL_PIN(130, "PWRGD_IO"), - PINCTRL_PIN(131, "CLK32K_IO"), - PINCTRL_PIN(132, "BIOSSEL"), - PINCTRL_PIN(133, "THRMRIP"), - /* GPIO range 10 */ - PINCTRL_PIN(134, "THRM"), - /* GPIO range 11 */ - PINCTRL_PIN(135, "PEXWAKE"), - PINCTRL_PIN(136, "PWRBTN"), - PINCTRL_PIN(137, "PCIRST"), - /* GPIO range 12 */ - PINCTRL_PIN(138, "SPKR"), - PINCTRL_PIN(139, "PME"), - PINCTRL_PIN(140, "SUSA"), - PINCTRL_PIN(141, "SUSB"), - PINCTRL_PIN(142, "SUSC"), - PINCTRL_PIN(143, "SVID0_VREN"), - PINCTRL_PIN(144, "SVID1_VREN"), +static const struct pinctrl_pin_desc kh50000_pins_0[] = { + KH50000_SOCKET_PINS(0) +}; + +static const struct pinctrl_pin_desc kh50000_pins_1[] = { + KH50000_SOCKET_PINS(1) +}; + +static const struct pinctrl_pin_desc kh50000_pins_2[] = { + KH50000_SOCKET_PINS(2) +}; + +static const struct pinctrl_pin_desc kh50000_pins_3[] = { + KH50000_SOCKET_PINS(3) }; #define NOT_DEFINE -30000 @@ -326,23 +344,75 @@ static zx_gpio_type kh50000_gpio_type(struct zhaoxin_pinctrl *pctrl, unsigned in static void kh50000_gpio_init(struct zhaoxin_pinctrl *pctrl) { - pctrl->pmio_base = 0x800; - pctrl->pmio_rx90 = 0x90; - pctrl->pmio_rx8c = 0x8c; + struct resource *res_pmio; + struct platform_device *pdev = to_platform_device(pctrl->dev); + + res_pmio = platform_get_resource(pdev, IORESOURCE_IO, 0); + if (!res_pmio) { + dev_err(&pdev->dev, "can't fetch device pmio resource info\n"); + return; + } + + if (!request_region(res_pmio->start, resource_size(res_pmio), pdev->name)) { + dev_err(&pdev->dev, "can't request region\n"); + return; + } + pctrl->pmio_base = res_pmio->start; + pctrl->pmio_rx90 = 4; + pctrl->pmio_rx8c = 0; zx_pad_write16(pctrl, 0xF8, 0x7F); dev_info(pctrl->dev, "KH50000 private init\n"); } -static const struct zhaoxin_pinctrl_soc_data kh50000_soc_data = { - .pins = kh50000_pins, - .npins = ARRAY_SIZE(kh50000_pins), +static const struct zhaoxin_pinctrl_soc_data socket_0_soc_data = { + .uid = "0", + .pins = kh50000_pins_0, + .npins = ARRAY_SIZE(kh50000_pins_0), .pin_topologys = kh50000_pin_topologys, .gpio_type = kh50000_gpio_type, .private_init = kh50000_gpio_init, .zhaoxin_pin_maps = kh50000_pinmap_gpps, .pin_map_size = ARRAY_SIZE(kh50000_pinmap_gpps), }; +static const struct zhaoxin_pinctrl_soc_data socket_1_soc_data = { + .uid = "1", + .pins = kh50000_pins_1, + .npins = ARRAY_SIZE(kh50000_pins_1), + .pin_topologys = kh50000_pin_topologys, + .gpio_type = kh50000_gpio_type, + .private_init = kh50000_gpio_init, + .zhaoxin_pin_maps = kh50000_pinmap_gpps, + .pin_map_size = ARRAY_SIZE(kh50000_pinmap_gpps), +}; +static const struct zhaoxin_pinctrl_soc_data socket_2_soc_data = { + .uid = "2", + .pins = kh50000_pins_2, + .npins = ARRAY_SIZE(kh50000_pins_2), + .pin_topologys = kh50000_pin_topologys, + .gpio_type = kh50000_gpio_type, + .private_init = kh50000_gpio_init, + .zhaoxin_pin_maps = kh50000_pinmap_gpps, + .pin_map_size = ARRAY_SIZE(kh50000_pinmap_gpps), +}; +static const struct zhaoxin_pinctrl_soc_data socket_3_soc_data = { + .uid = "3", + .pins = kh50000_pins_3, + .npins = ARRAY_SIZE(kh50000_pins_3), + .pin_topologys = kh50000_pin_topologys, + .gpio_type = kh50000_gpio_type, + .private_init = kh50000_gpio_init, + .zhaoxin_pin_maps = kh50000_pinmap_gpps, + .pin_map_size = ARRAY_SIZE(kh50000_pinmap_gpps), +}; + +static const struct zhaoxin_pinctrl_soc_data *kh50000_soc_data[] = { + &socket_0_soc_data, + &socket_1_soc_data, + &socket_2_soc_data, + &socket_3_soc_data, + NULL, +}; static const struct acpi_device_id kh50000_pinctrl_acpi_match[] = { { "KH8344B", (kernel_ulong_t)&kh50000_soc_data }, @@ -355,7 +425,7 @@ static const struct dev_pm_ops kh50000_pinctrl_pm_ops = { }; static struct platform_driver kh50000_pinctrl_driver = { - .probe = zhaoxin_pinctrl_probe_by_hid, + .probe = zhaoxin_pinctrl_probe_by_uid, .driver = { .name = "kh50000-pinctrl", .acpi_match_table = kh50000_pinctrl_acpi_match, diff --git a/drivers/pinctrl/zhaoxin/pinctrl-zhaoxin.h b/drivers/pinctrl/zhaoxin/pinctrl-zhaoxin.h index c0516daa5897a..1525d10cc53f5 100644 --- a/drivers/pinctrl/zhaoxin/pinctrl-zhaoxin.h +++ b/drivers/pinctrl/zhaoxin/pinctrl-zhaoxin.h @@ -20,6 +20,8 @@ struct platform_device; struct device; struct zhaoxin_pinctrl; +#define SOCKET_PINCTRL_PIN(sock, a, b) PINCTRL_PIN(a, b"_"#sock) + #define PMIO_RX90 100 #define PMIO_RX8C 200 diff --git a/security/lockdown/lockdown.c b/security/lockdown/lockdown.c index 67cc9839952f8..4b509af6d3439 100644 --- a/security/lockdown/lockdown.c +++ b/security/lockdown/lockdown.c @@ -99,10 +99,12 @@ static ssize_t lockdown_read(struct file *filp, char __user *buf, size_t count, if (lockdown_reasons[level]) { const char *label = lockdown_reasons[level]; + if (offset >= sizeof(temp) - 1) + break; if (kernel_locked_down == level) - offset += sprintf(temp+offset, "[%s] ", label); + offset += scnprintf(temp + offset, sizeof(temp) - (size_t)offset, "[%s] ", label); else - offset += sprintf(temp+offset, "%s ", label); + offset += scnprintf(temp + offset, sizeof(temp) - (size_t)offset, "%s ", label); } } diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index d6587e42518b8..0775d3fdc11d3 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -1646,7 +1646,8 @@ static int check_position_fix(struct azx *chip, int fix) } /* Check VIA/ATI HD Audio Controller exist */ - if (chip->driver_type == AZX_DRIVER_VIA) { + if (chip->driver_type == AZX_DRIVER_VIA || + chip->driver_type == AZX_DRIVER_ZHAOXIN) { dev_dbg(chip->card->dev, "Using VIACOMBO position fix\n"); return POS_FIX_VIACOMBO; } @@ -1800,7 +1801,8 @@ static void azx_check_snoop_available(struct azx *chip) snoop = true; if (azx_get_snoop_type(chip) == AZX_SNOOP_TYPE_NONE && - chip->driver_type == AZX_DRIVER_VIA) { + (chip->driver_type == AZX_DRIVER_VIA || + chip->driver_type == AZX_DRIVER_ZHAOXIN)) { /* force to non-snoop mode for a new VIA controller * when BIOS is set */ @@ -2846,6 +2848,21 @@ static const struct pci_device_id azx_ids[] = { { PCI_VDEVICE(VIA, 0x9170), .driver_data = AZX_DRIVER_GENERIC }, /* VIA GFX VT6122/VX11 */ { PCI_VDEVICE(VIA, 0x9140), .driver_data = AZX_DRIVER_GENERIC }, + { PCI_VDEVICE(VIA, 0x9141), + .driver_data = AZX_DRIVER_ZHAOXINHDMI | AZX_DCAPS_POSFIX_LPIB | + AZX_DCAPS_NO_MSI | AZX_DCAPS_NO_64BIT }, + { PCI_VDEVICE(VIA, 0x9142), + .driver_data = AZX_DRIVER_ZHAOXINHDMI | AZX_DCAPS_POSFIX_LPIB | + AZX_DCAPS_NO_MSI | AZX_DCAPS_NO_64BIT }, + { PCI_VDEVICE(VIA, 0x9144), + .driver_data = AZX_DRIVER_ZHAOXINHDMI | AZX_DCAPS_POSFIX_LPIB | + AZX_DCAPS_NO_MSI | AZX_DCAPS_NO_64BIT }, + { PCI_VDEVICE(VIA, 0x9145), + .driver_data = AZX_DRIVER_ZHAOXINHDMI | AZX_DCAPS_POSFIX_LPIB | + AZX_DCAPS_NO_MSI | AZX_DCAPS_NO_64BIT }, + { PCI_VDEVICE(VIA, 0x9146), + .driver_data = AZX_DRIVER_ZHAOXINHDMI | AZX_DCAPS_POSFIX_LPIB | + AZX_DCAPS_NO_MSI | AZX_DCAPS_NO_64BIT }, /* SIS966 */ { PCI_VDEVICE(SI, 0x7502), .driver_data = AZX_DRIVER_SIS }, /* ULI M5461 */ diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index d679154a6d8a8..aa8fc88cdf769 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -4641,6 +4641,17 @@ HDA_CODEC_ENTRY(0x11069f80, "VX900 HDMI/DP", patch_via_hdmi), HDA_CODEC_ENTRY(0x11069f81, "VX900 HDMI/DP", patch_via_hdmi), HDA_CODEC_ENTRY(0x11069f84, "VX11 HDMI/DP", patch_generic_hdmi), HDA_CODEC_ENTRY(0x11069f85, "VX11 HDMI/DP", patch_generic_hdmi), +HDA_CODEC_ENTRY(0x11069f86, "ZX-100S HDMI/DP", patch_gf_hdmi), +HDA_CODEC_ENTRY(0x11069f87, "ZX-100S HDMI/DP", patch_gf_hdmi), +HDA_CODEC_ENTRY(0x11069f88, "KX-5000 HDMI/DP", patch_gf_hdmi), +HDA_CODEC_ENTRY(0x11069f89, "KX-5000 HDMI/DP", patch_gf_hdmi), +HDA_CODEC_ENTRY(0x11069f8a, "KX-6000 HDMI/DP", patch_gf_hdmi), +HDA_CODEC_ENTRY(0x11069f8b, "KX-6000 HDMI/DP", patch_gf_hdmi), +HDA_CODEC_ENTRY(0x11069f8c, "KX-6000G HDMI/DP", patch_gf_hdmi), +HDA_CODEC_ENTRY(0x11069f8d, "KX-6000G HDMI/DP", patch_gf_hdmi), +HDA_CODEC_ENTRY(0x11069f8e, "KX-7000 HDMI/DP", patch_gf_hdmi), +HDA_CODEC_ENTRY(0x11069f8f, "KX-7000 HDMI/DP", patch_gf_hdmi), +HDA_CODEC_ENTRY(0x11069f90, "KX-7000 HDMI/DP", patch_gf_hdmi), HDA_CODEC_ENTRY(0x1d179f86, "ZX-100S HDMI/DP", patch_gf_hdmi), HDA_CODEC_ENTRY(0x1d179f87, "ZX-100S HDMI/DP", patch_gf_hdmi), HDA_CODEC_ENTRY(0x1d179f88, "KX-5000 HDMI/DP", patch_gf_hdmi), diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 4a22fb36ca367..3c00c149df39c 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -1381,6 +1381,7 @@ config SND_SOC_PEB2466 config SND_SOC_PHYTIUM_CODEC_V2 tristate "Phytium Codec V2 driver" + depends on ARCH_PHYTIUM help Select Y if you want to add Phytium codec V2 driver. diff --git a/sound/soc/codecs/es8388.c b/sound/soc/codecs/es8388.c index d9b1c80e3c38e..f086e2c52ad2e 100644 --- a/sound/soc/codecs/es8388.c +++ b/sound/soc/codecs/es8388.c @@ -23,7 +23,7 @@ #include #include -#define ES8388_V1_VERSION "1.0.0" +#define ES8388_V1_VERSION "1.0.1" static const unsigned int rates_12288[] = { 8000, 12000, 16000, 24000, 32000, 48000, 96000, @@ -720,8 +720,13 @@ static int es8388_resume(struct snd_soc_component *component) static int es8388_component_probe(struct snd_soc_component *component) { - snd_soc_component_write(component, ES8388_ADCPOWER, 0xf0); - snd_soc_component_write(component, ES8388_CONTROL1, 0x30); + int ret = 0; + + ret = snd_soc_component_write(component, ES8388_ADCPOWER, 0xf0); + if (ret) + return ret; + + snd_soc_component_write(component, ES8388_CONTROL1, 0x20); snd_soc_component_write(component, ES8388_DACCONTROL21, 0x80); snd_soc_component_write(component, ES8388_ADCCONTROL10, 0xda); diff --git a/sound/soc/codecs/phytium-codec-v2.c b/sound/soc/codecs/phytium-codec-v2.c index ab63ceb2c826f..88dd9e81a89e8 100644 --- a/sound/soc/codecs/phytium-codec-v2.c +++ b/sound/soc/codecs/phytium-codec-v2.c @@ -101,17 +101,20 @@ static const struct snd_soc_dapm_route phyt_dapm_routes[] = { static void phyt_codec_show_status(uint8_t status) { switch (status) { - case 0: + case ERR_CODEC_SUCCESS: pr_err("success\n"); break; - case 2: + case ERR_CODEC_DEV_BUSY: pr_err("device busy\n"); break; - case 3: + case ERR_CODEC_RW_ERROR: pr_err("read/write error\n"); break; - case 4: - pr_err("no device\n"); + case ERR_CODEC_NODEV: + pr_err("no hw device\n"); + break; + case ERR_CODEC_NO_INIT: + pr_err("no init\n"); break; default: pr_err("unknown error: %d\n", status); @@ -325,6 +328,9 @@ static int phyt_get_cmd(struct phytium_codec *priv, unsigned int cmd) static int phyt_probe(struct snd_soc_component *component) { struct phytium_codec *priv = snd_soc_component_get_drvdata(component); + struct phytcodec_cmd *msg = priv->sharemem_base; + + memset(msg, 0, sizeof(struct phytcodec_cmd)); return phyt_set_cmd(priv, PHYTCODEC_MSG_CMD_SET_PROBE); } @@ -332,6 +338,9 @@ static int phyt_probe(struct snd_soc_component *component) static void phyt_remove(struct snd_soc_component *component) { struct phytium_codec *priv = snd_soc_component_get_drvdata(component); + struct phytcodec_cmd *msg = priv->sharemem_base; + + memset(msg, 0, sizeof(struct phytcodec_cmd)); phyt_set_cmd(priv, PHYTCODEC_MSG_CMD_SET_REMOVE); } @@ -339,6 +348,9 @@ static void phyt_remove(struct snd_soc_component *component) static int phyt_suspend(struct snd_soc_component *component) { struct phytium_codec *priv = snd_soc_component_get_drvdata(component); + struct phytcodec_cmd *msg = priv->sharemem_base; + + memset(msg, 0, sizeof(struct phytcodec_cmd)); return phyt_pm_cmd(priv, PHYTCODEC_MSG_CMD_SET_SUSPEND); } @@ -346,6 +358,9 @@ static int phyt_suspend(struct snd_soc_component *component) static int phyt_resume(struct snd_soc_component *component) { struct phytium_codec *priv = snd_soc_component_get_drvdata(component); + struct phytcodec_cmd *msg = priv->sharemem_base; + + memset(msg, 0, sizeof(struct phytcodec_cmd)); return phyt_pm_cmd(priv, PHYTCODEC_MSG_CMD_SET_RESUME); } @@ -425,6 +440,9 @@ static int phyt_startup(struct snd_pcm_substream *substream, int ret; struct snd_soc_component *component = dai->component; struct phytium_codec *priv = snd_soc_component_get_drvdata(component); + struct phytcodec_cmd *msg = priv->sharemem_base; + + memset(msg, 0, sizeof(struct phytcodec_cmd)); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ret = phyt_set_cmd(priv, PHYTCODEC_MSG_CMD_SET_STARTUP); @@ -440,6 +458,9 @@ static void phyt_shutdown(struct snd_pcm_substream *substream, int ret; struct snd_soc_component *component = dai->component; struct phytium_codec *priv = snd_soc_component_get_drvdata(component); + struct phytcodec_cmd *msg = priv->sharemem_base; + + memset(msg, 0, sizeof(struct phytcodec_cmd)); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ret = phyt_set_cmd(priv, PHYTCODEC_MSG_CMD_SET_SHUTDOWN); @@ -492,6 +513,9 @@ static int phyt_set_dai_fmt(struct snd_soc_dai *codec_dai, int ret; struct snd_soc_component *component = codec_dai->component; struct phytium_codec *priv = snd_soc_component_get_drvdata(component); + struct phytcodec_cmd *msg = priv->sharemem_base; + + memset(msg, 0, sizeof(struct phytcodec_cmd)); if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS) return -EINVAL; @@ -742,6 +766,7 @@ static ssize_t debug_store(struct device *dev, struct device_attribute *da, dev_err(dev, "dump command requires one argument\n"); goto error; } + memset(priv->sharemem_base, 0, sizeof(struct phytcodec_cmd)); phyt_get_cmd(priv, PHYTCODEC_MSG_CMD_GET_ALL_REGS); } else if (strcmp(cmd, "help") == 0) { dev_info(dev, "Available commands:\n" @@ -801,8 +826,9 @@ static void phyt_codec_init(struct phytium_codec *priv) if (sysfs_create_group(&priv->dev->kobj, &phyt_codec_device_group)) dev_warn(priv->dev, "failed to create sysfs\n"); - phyt_dai.playback.channels_max = phyt_get_channels(priv); - phyt_dai.capture.channels_max = phyt_dai.playback.channels_max; + priv->channels = phyt_get_channels(priv); + phyt_dai.playback.channels_max = priv->channels; + phyt_dai.capture.channels_max = priv->channels; phyt_writel_reg(priv->regfile_base, PHYTIUM_CODEC_INT_MASK, 0x0); phyt_writel_reg(priv->regfile_base, PHYTIUM_CODEC_INT_ENABLE, 0x1); diff --git a/sound/soc/codecs/phytium-codec-v2.h b/sound/soc/codecs/phytium-codec-v2.h index f0515d0cfabbb..e9b20079975cc 100644 --- a/sound/soc/codecs/phytium-codec-v2.h +++ b/sound/soc/codecs/phytium-codec-v2.h @@ -95,6 +95,15 @@ enum phytcodec_complete { PHYTCODEC_COMPLETE_INVALID_PARAMETERS, }; +enum phytcodec_status { + ERR_CODEC_SUCCESS = 0, + ERR_CODEC_BUS_BUSY, + ERR_CODEC_DEV_BUSY, + ERR_CODEC_RW_ERROR, + ERR_CODEC_NODEV, //HW + ERR_CODEC_NO_INIT, //SW +}; + struct phytcodec_rw_data { uint8_t addr; uint8_t reg; diff --git a/sound/soc/phytium/Kconfig b/sound/soc/phytium/Kconfig index c567699bcb568..a30c865d4af53 100644 --- a/sound/soc/phytium/Kconfig +++ b/sound/soc/phytium/Kconfig @@ -27,18 +27,19 @@ config SND_PMDK_ES8336 ES8336 codecs. config SND_SOC_PHYTIUM_I2S_V2 - tristate "Phytium I2S V2 Device Driver" - help - Say Y or M if you want to add support for I2S v2 driver for - Phytium I2S device . The device supports 2 channels each - for play and record. + tristate "Phytium I2S V2 Device Driver" + depends on ARCH_PHYTIUM + help + Say Y or M if you want to add support for I2S v2 driver for + Phytium I2S device . The device supports 2 channels each + for play and record. config SND_SOC_PHYTIUM_MACHINE_V2 - tristate "Phytium Machine V2 Driver" - depends on SND_SOC_PHYTIUM_I2S_V2 - help - Say Y or M if you want to add Phytium machine v2 support for - codecs. + tristate "Phytium Machine V2 Driver" + depends on SND_SOC_PHYTIUM_I2S_V2 + help + Say Y or M if you want to add Phytium machine v2 support for + codecs. config SND_PMDK_DP tristate "Phytium machine support with DP" diff --git a/sound/soc/phytium/phytium-i2s-v2.c b/sound/soc/phytium/phytium-i2s-v2.c index 83c4ee1ae65d1..d0074a81a874d 100644 --- a/sound/soc/phytium/phytium-i2s-v2.c +++ b/sound/soc/phytium/phytium-i2s-v2.c @@ -30,7 +30,7 @@ #include #include "phytium-i2s-v2.h" -#define PHYT_I2S_V2_VERSION "1.0.6" +#define PHYT_I2S_V2_VERSION "1.0.9" static struct snd_soc_jack hs_jack; static irqreturn_t phyt_i2s_gpio_interrupt(int irq, void *dev_id); @@ -539,6 +539,8 @@ static int phyt_pcm_component_probe(struct snd_soc_component *component) static const struct snd_soc_component_driver phytium_i2s_component = { .name = "phytium-i2s", + .use_dai_pcm_id = true, + .probe_order = SND_SOC_COMP_ORDER_LATE, .pcm_construct = phyt_pcm_new, .pcm_destruct = phyt_pcm_free, .suspend = phyt_pcm_suspend, @@ -951,8 +953,54 @@ static ssize_t phyt_i2s_debug_store(struct device *dev, static DEVICE_ATTR_RW(phyt_i2s_debug); +static ssize_t phyt_i2s_control_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + struct phytium_i2s *priv = dev_get_drvdata(dev); + char *p, *token; + u8 loc; + int ret; + long value; + + p = kmalloc(size, GFP_KERNEL); + if (p == NULL) + return -EINVAL; + strscpy(p, buf, sizeof(p)); + + token = strsep(&p, " "); + if (!token) { + ret = -EINVAL; + goto error; + } + + ret = kstrtol(token, 0, &value); + if (ret) + goto error; + loc = (u8)value; + + if (loc == 1) { + //Enable I2S and DMA + phyt_writel_reg(priv->dma_reg_base, PHYTIUM_DMA_CTL, 1); + phyt_writel_reg(priv->regfile_base, PHYTIUM_REGFILE_ITER, TX_EN); + } else if (loc == 0) { + //Disable I2S and DMA + phyt_writel_reg(priv->regfile_base, PHYTIUM_REGFILE_ITER, TX_DIS); + phyt_writel_reg(priv->dma_reg_base, PHYTIUM_DMA_CTL, 0); + } + + kfree(p); + return size; +error: + kfree(p); + return ret; +} + +static DEVICE_ATTR_WO(phyt_i2s_control); + static struct attribute *phyt_i2s_device_attrs[] = { &dev_attr_phyt_i2s_debug.attr, + &dev_attr_phyt_i2s_control.attr, NULL, }; diff --git a/sound/soc/phytium/phytium-machine-v2.c b/sound/soc/phytium/phytium-machine-v2.c index d02ae022e5591..12f08b4ba445a 100644 --- a/sound/soc/phytium/phytium-machine-v2.c +++ b/sound/soc/phytium/phytium-machine-v2.c @@ -48,6 +48,7 @@ SND_SOC_DAILINK_DEFS(phyt_machine, static struct snd_soc_dai_link phyt_machine_dai[] = { { .name = "PHYTIUM HIFI V2", + .id = 0, .stream_name = "PHYTIUM HIFT V2", .dai_fmt = PMDK_DAI_FMT, SND_SOC_DAILINK_REG(phyt_machine), diff --git a/sound/soc/phytium/pmdk_dp.c b/sound/soc/phytium/pmdk_dp.c index c0760d3a7cd5f..c00b2c7069950 100644 --- a/sound/soc/phytium/pmdk_dp.c +++ b/sound/soc/phytium/pmdk_dp.c @@ -67,7 +67,8 @@ static int pmdk_dp0_init(struct snd_soc_pcm_runtime *runtime) dev_err(card->dev, "Jack creation failed %d\n", ret); return ret; } - snd_soc_component_set_jack(component, &priv->jack0, NULL); + ret = snd_soc_component_set_jack(component, &priv->jack0, NULL); + return ret; } @@ -85,7 +86,8 @@ static int pmdk_dp1_init(struct snd_soc_pcm_runtime *runtime) dev_err(card->dev, "Jack creation failed %d\n", ret); return ret; } - snd_soc_component_set_jack(component, &priv->jack1, NULL); + ret = snd_soc_component_set_jack(component, &priv->jack1, NULL); + return ret; } @@ -103,7 +105,8 @@ static int pmdk_dp2_init(struct snd_soc_pcm_runtime *runtime) dev_err(card->dev, "Jack creation failed %d\n", ret); return ret; } - snd_soc_component_set_jack(component, &priv->jack2, NULL); + ret = snd_soc_component_set_jack(component, &priv->jack2, NULL); + return ret; } @@ -124,6 +127,7 @@ SND_SOC_DAILINK_DEFS(pmdk_dp2_dai, static struct snd_soc_dai_link pmdk_dai0 = { .name = "Phytium dp0-audio", + .id = 0, .stream_name = "Playback", .dai_fmt = SMDK_DAI_FMT, .init = pmdk_dp0_init, @@ -133,6 +137,7 @@ static struct snd_soc_dai_link pmdk_dai0 = { static struct snd_soc_dai_link pmdk_dai1 = { .name = "Phytium dp1-audio", + .id = 1, .stream_name = "Playback", .dai_fmt = SMDK_DAI_FMT, .init = pmdk_dp1_init, @@ -142,6 +147,7 @@ static struct snd_soc_dai_link pmdk_dai1 = { static struct snd_soc_dai_link pmdk_dai2 = { .name = "Phytium dp2-audio", + .id = 2, .stream_name = "Playback", .dai_fmt = SMDK_DAI_FMT, .init = pmdk_dp2_init,