diff options
author | Andy Shevchenko <andriy.shevchenko@linux.intel.com> | 2020-04-24 13:56:46 +0300 |
---|---|---|
committer | Andy Shevchenko <andriy.shevchenko@linux.intel.com> | 2020-04-24 13:56:46 +0300 |
commit | 4a65ed6562bcfa58fe0c2ca5855c45268f40d365 (patch) | |
tree | 072de56917dc218b75a4796f4605428959ec0dc9 /drivers | |
parent | b5f7311d3a2ed153f26b21c56d54a46d07a4da3f (diff) | |
parent | 2f72d35ea75ee8bf8c9e63fb43d43d5bfb4ac8fd (diff) |
Merge branch 'ib-mfd-x86-usb-watchdog-v5.7'
Merge branch 'ib-mfd-x86-usb-watchdog-v5.7' of
git://git.kernel.org/pub/scm/linux/kernel/git/lee/mfd.git
to avoid conflicts in PDx86.
Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/mfd/Kconfig | 20 | ||||
-rw-r--r-- | drivers/mfd/Makefile | 1 | ||||
-rw-r--r-- | drivers/mfd/intel_pmc_bxt.c | 468 | ||||
-rw-r--r-- | drivers/mfd/intel_soc_pmic_bxtwc.c | 34 | ||||
-rw-r--r-- | drivers/mfd/intel_soc_pmic_mrfld.c | 10 | ||||
-rw-r--r-- | drivers/platform/x86/Kconfig | 46 | ||||
-rw-r--r-- | drivers/platform/x86/Makefile | 2 | ||||
-rw-r--r-- | drivers/platform/x86/intel_mid_powerbtn.c | 15 | ||||
-rw-r--r-- | drivers/platform/x86/intel_pmc_ipc.c | 949 | ||||
-rw-r--r-- | drivers/platform/x86/intel_scu_ipc.c | 447 | ||||
-rw-r--r-- | drivers/platform/x86/intel_scu_ipcutil.c | 43 | ||||
-rw-r--r-- | drivers/platform/x86/intel_scu_pcidrv.c | 68 | ||||
-rw-r--r-- | drivers/platform/x86/intel_telemetry_core.c | 17 | ||||
-rw-r--r-- | drivers/platform/x86/intel_telemetry_debugfs.c | 15 | ||||
-rw-r--r-- | drivers/platform/x86/intel_telemetry_pltdrv.c | 97 | ||||
-rw-r--r-- | drivers/usb/typec/mux/Kconfig | 2 | ||||
-rw-r--r-- | drivers/usb/typec/mux/intel_pmc_mux.c | 12 | ||||
-rw-r--r-- | drivers/usb/typec/tcpm/Kconfig | 2 | ||||
-rw-r--r-- | drivers/watchdog/iTCO_wdt.c | 25 | ||||
-rw-r--r-- | drivers/watchdog/intel-mid_wdt.c | 53 |
20 files changed, 1136 insertions, 1190 deletions
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 0a59249198d3..54b6aa4aaab1 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -551,7 +551,7 @@ config INTEL_SOC_PMIC config INTEL_SOC_PMIC_BXTWC tristate "Support for Intel Broxton Whiskey Cove PMIC" - depends on INTEL_PMC_IPC + depends on MFD_INTEL_PMC_BXT select MFD_CORE select REGMAP_IRQ help @@ -593,7 +593,7 @@ config INTEL_SOC_PMIC_MRFLD tristate "Support for Intel Merrifield Basin Cove PMIC" depends on GPIOLIB depends on ACPI - depends on INTEL_SCU_IPC + depends on INTEL_SCU select MFD_CORE select REGMAP_IRQ help @@ -625,13 +625,27 @@ config MFD_INTEL_LPSS_PCI config MFD_INTEL_MSIC bool "Intel MSIC" - depends on INTEL_SCU_IPC + depends on INTEL_SCU select MFD_CORE help Select this option to enable access to Intel MSIC (Avatele Passage) chip. This chip embeds audio, battery, GPIO, etc. devices used in Intel Medfield platforms. +config MFD_INTEL_PMC_BXT + tristate "Intel PMC Driver for Broxton" + depends on X86 + depends on X86_PLATFORM_DEVICES + depends on ACPI + select INTEL_SCU_IPC + select MFD_CORE + help + This driver provides support for the PMC (Power Management + Controller) on Intel Broxton and Apollo Lake. The PMC is a + multi-function device that exposes IPC, General Control + Register and P-unit access. In addition this creates devices + for iTCO watchdog and telemetry that are part of the PMC. + config MFD_IPAQ_MICRO bool "Atmel Micro ASIC (iPAQ h3100/h3600/h3700) Support" depends on SA1100_H3100 || SA1100_H3600 diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index f935d10cbf0f..7761f84a96eb 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -212,6 +212,7 @@ obj-$(CONFIG_MFD_INTEL_LPSS) += intel-lpss.o obj-$(CONFIG_MFD_INTEL_LPSS_PCI) += intel-lpss-pci.o obj-$(CONFIG_MFD_INTEL_LPSS_ACPI) += intel-lpss-acpi.o obj-$(CONFIG_MFD_INTEL_MSIC) += intel_msic.o +obj-$(CONFIG_MFD_INTEL_PMC_BXT) += intel_pmc_bxt.o obj-$(CONFIG_MFD_PALMAS) += palmas.o obj-$(CONFIG_MFD_VIPERBOARD) += viperboard.o obj-$(CONFIG_MFD_RC5T583) += rc5t583.o rc5t583-irq.o diff --git a/drivers/mfd/intel_pmc_bxt.c b/drivers/mfd/intel_pmc_bxt.c new file mode 100644 index 000000000000..9f01d38acc7f --- /dev/null +++ b/drivers/mfd/intel_pmc_bxt.c @@ -0,0 +1,468 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Driver for the Intel Broxton PMC + * + * (C) Copyright 2014 - 2020 Intel Corporation + * + * This driver is based on Intel SCU IPC driver (intel_scu_ipc.c) by + * Sreedhara DS <sreedhara.ds@intel.com> + * + * The PMC (Power Management Controller) running on the ARC processor + * communicates with another entity running in the IA (Intel Architecture) + * core through an IPC (Intel Processor Communications) mechanism which in + * turn sends messages between the IA and the PMC. + */ + +#include <linux/acpi.h> +#include <linux/delay.h> +#include <linux/errno.h> +#include <linux/interrupt.h> +#include <linux/io-64-nonatomic-lo-hi.h> +#include <linux/mfd/core.h> +#include <linux/mfd/intel_pmc_bxt.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/platform_data/itco_wdt.h> + +#include <asm/intel_scu_ipc.h> + +/* Residency with clock rate at 19.2MHz to usecs */ +#define S0IX_RESIDENCY_IN_USECS(d, s) \ +({ \ + u64 result = 10ull * ((d) + (s)); \ + do_div(result, 192); \ + result; \ +}) + +/* Resources exported from IFWI */ +#define PLAT_RESOURCE_IPC_INDEX 0 +#define PLAT_RESOURCE_IPC_SIZE 0x1000 +#define PLAT_RESOURCE_GCR_OFFSET 0x1000 +#define PLAT_RESOURCE_GCR_SIZE 0x1000 +#define PLAT_RESOURCE_BIOS_DATA_INDEX 1 +#define PLAT_RESOURCE_BIOS_IFACE_INDEX 2 +#define PLAT_RESOURCE_TELEM_SSRAM_INDEX 3 +#define PLAT_RESOURCE_ISP_DATA_INDEX 4 +#define PLAT_RESOURCE_ISP_IFACE_INDEX 5 +#define PLAT_RESOURCE_GTD_DATA_INDEX 6 +#define PLAT_RESOURCE_GTD_IFACE_INDEX 7 +#define PLAT_RESOURCE_ACPI_IO_INDEX 0 + +/* + * BIOS does not create an ACPI device for each PMC function, but + * exports multiple resources from one ACPI device (IPC) for multiple + * functions. This driver is responsible for creating a child device and + * to export resources for those functions. + */ +#define SMI_EN_OFFSET 0x0040 +#define SMI_EN_SIZE 4 +#define TCO_BASE_OFFSET 0x0060 +#define TCO_REGS_SIZE 16 +#define TELEM_SSRAM_SIZE 240 +#define TELEM_PMC_SSRAM_OFFSET 0x1b00 +#define TELEM_PUNIT_SSRAM_OFFSET 0x1a00 + +/* Commands */ +#define PMC_NORTHPEAK_CTRL 0xed + +static inline bool is_gcr_valid(u32 offset) +{ + return offset < PLAT_RESOURCE_GCR_SIZE - 8; +} + +/** + * intel_pmc_gcr_read64() - Read a 64-bit PMC GCR register + * @pmc: PMC device pointer + * @offset: offset of GCR register from GCR address base + * @data: data pointer for storing the register output + * + * Reads the 64-bit PMC GCR register at given offset. + * + * Return: Negative value on error or 0 on success. + */ +int intel_pmc_gcr_read64(struct intel_pmc_dev *pmc, u32 offset, u64 *data) +{ + if (!is_gcr_valid(offset)) + return -EINVAL; + + spin_lock(&pmc->gcr_lock); + *data = readq(pmc->gcr_mem_base + offset); + spin_unlock(&pmc->gcr_lock); + + return 0; +} +EXPORT_SYMBOL_GPL(intel_pmc_gcr_read64); + +/** + * intel_pmc_gcr_update() - Update PMC GCR register bits + * @pmc: PMC device pointer + * @offset: offset of GCR register from GCR address base + * @mask: bit mask for update operation + * @val: update value + * + * Updates the bits of given GCR register as specified by + * @mask and @val. + * + * Return: Negative value on error or 0 on success. + */ +int intel_pmc_gcr_update(struct intel_pmc_dev *pmc, u32 offset, u32 mask, u32 val) +{ + u32 new_val; + + if (!is_gcr_valid(offset)) + return -EINVAL; + + spin_lock(&pmc->gcr_lock); + new_val = readl(pmc->gcr_mem_base + offset); + + new_val = (new_val & ~mask) | (val & mask); + writel(new_val, pmc->gcr_mem_base + offset); + + new_val = readl(pmc->gcr_mem_base + offset); + spin_unlock(&pmc->gcr_lock); + + /* Check whether the bit update is successful */ + return (new_val & mask) != (val & mask) ? -EIO : 0; +} +EXPORT_SYMBOL_GPL(intel_pmc_gcr_update); + +/** + * intel_pmc_s0ix_counter_read() - Read S0ix residency + * @pmc: PMC device pointer + * @data: Out param that contains current S0ix residency count. + * + * Writes to @data how many usecs the system has been in low-power S0ix + * state. + * + * Return: An error code or 0 on success. + */ +int intel_pmc_s0ix_counter_read(struct intel_pmc_dev *pmc, u64 *data) +{ + u64 deep, shlw; + + spin_lock(&pmc->gcr_lock); + deep = readq(pmc->gcr_mem_base + PMC_GCR_TELEM_DEEP_S0IX_REG); + shlw = readq(pmc->gcr_mem_base + PMC_GCR_TELEM_SHLW_S0IX_REG); + spin_unlock(&pmc->gcr_lock); + + *data = S0IX_RESIDENCY_IN_USECS(deep, shlw); + return 0; +} +EXPORT_SYMBOL_GPL(intel_pmc_s0ix_counter_read); + +/** + * simplecmd_store() - Send a simple IPC command + * @dev: Device under the attribute is + * @attr: Attribute in question + * @buf: Buffer holding data to be stored to the attribute + * @count: Number of bytes in @buf + * + * Expects a string with two integers separated with space. These two + * values hold command and subcommand that is send to PMC. + * + * Return: Number number of bytes written (@count) or negative errno in + * case of error. + */ +static ssize_t simplecmd_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct intel_pmc_dev *pmc = dev_get_drvdata(dev); + struct intel_scu_ipc_dev *scu = pmc->scu; + int subcmd; + int cmd; + int ret; + + ret = sscanf(buf, "%d %d", &cmd, &subcmd); + if (ret != 2) { + dev_err(dev, "Invalid values, expected: cmd subcmd\n"); + return -EINVAL; + } + + ret = intel_scu_ipc_dev_simple_command(scu, cmd, subcmd); + if (ret) + return ret; + + return count; +} +static DEVICE_ATTR_WO(simplecmd); + +/** + * northpeak_store() - Enable or disable Northpeak + * @dev: Device under the attribute is + * @attr: Attribute in question + * @buf: Buffer holding data to be stored to the attribute + * @count: Number of bytes in @buf + * + * Expects an unsigned integer. Non-zero enables Northpeak and zero + * disables it. + * + * Return: Number number of bytes written (@count) or negative errno in + * case of error. + */ +static ssize_t northpeak_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct intel_pmc_dev *pmc = dev_get_drvdata(dev); + struct intel_scu_ipc_dev *scu = pmc->scu; + unsigned long val; + int subcmd; + int ret; + + ret = kstrtoul(buf, 0, &val); + if (ret) + return ret; + + /* Northpeak is enabled if subcmd == 1 and disabled if it is 0 */ + if (val) + subcmd = 1; + else + subcmd = 0; + + ret = intel_scu_ipc_dev_simple_command(scu, PMC_NORTHPEAK_CTRL, subcmd); + if (ret) + return ret; + + return count; +} +static DEVICE_ATTR_WO(northpeak); + +static struct attribute *intel_pmc_attrs[] = { + &dev_attr_northpeak.attr, + &dev_attr_simplecmd.attr, + NULL +}; + +static const struct attribute_group intel_pmc_group = { + .attrs = intel_pmc_attrs, +}; + +static const struct attribute_group *intel_pmc_groups[] = { + &intel_pmc_group, + NULL +}; + +static struct resource punit_res[6]; + +static struct mfd_cell punit = { + .name = "intel_punit_ipc", + .resources = punit_res, +}; + +static struct itco_wdt_platform_data tco_pdata = { + .name = "Apollo Lake SoC", + .version = 5, + .no_reboot_use_pmc = true, +}; + +static struct resource tco_res[2]; + +static const struct mfd_cell tco = { + .name = "iTCO_wdt", + .ignore_resource_conflicts = true, + .resources = tco_res, + .num_resources = ARRAY_SIZE(tco_res), + .platform_data = &tco_pdata, + .pdata_size = sizeof(tco_pdata), +}; + +static const struct resource telem_res[] = { + DEFINE_RES_MEM(TELEM_PUNIT_SSRAM_OFFSET, TELEM_SSRAM_SIZE), + DEFINE_RES_MEM(TELEM_PMC_SSRAM_OFFSET, TELEM_SSRAM_SIZE), +}; + +static const struct mfd_cell telem = { + .name = "intel_telemetry", + .resources = telem_res, + .num_resources = ARRAY_SIZE(telem_res), +}; + +static int intel_pmc_get_tco_resources(struct platform_device *pdev) +{ + struct resource *res; + + if (acpi_has_watchdog()) + return 0; + + res = platform_get_resource(pdev, IORESOURCE_IO, + PLAT_RESOURCE_ACPI_IO_INDEX); + if (!res) { + dev_err(&pdev->dev, "Failed to get IO resource\n"); + return -EINVAL; + } + + tco_res[0].flags = IORESOURCE_IO; + tco_res[0].start = res->start + TCO_BASE_OFFSET; + tco_res[0].end = tco_res[0].start + TCO_REGS_SIZE - 1; + tco_res[1].flags = IORESOURCE_IO; + tco_res[1].start = res->start + SMI_EN_OFFSET; + tco_res[1].end = tco_res[1].start + SMI_EN_SIZE - 1; + + return 0; +} + +static int intel_pmc_get_resources(struct platform_device *pdev, + struct intel_pmc_dev *pmc, + struct intel_scu_ipc_data *scu_data) +{ + struct resource gcr_res; + size_t npunit_res = 0; + struct resource *res; + int ret; + + scu_data->irq = platform_get_irq_optional(pdev, 0); + + res = platform_get_resource(pdev, IORESOURCE_MEM, + PLAT_RESOURCE_IPC_INDEX); + if (!res) { + dev_err(&pdev->dev, "Failed to get IPC resource\n"); + return -EINVAL; + } + + /* IPC registers */ + scu_data->mem.flags = res->flags; + scu_data->mem.start = res->start; + scu_data->mem.end = res->start + PLAT_RESOURCE_IPC_SIZE - 1; + + /* GCR registers */ + gcr_res.flags = res->flags; + gcr_res.start = res->start + PLAT_RESOURCE_GCR_OFFSET; + gcr_res.end = gcr_res.start + PLAT_RESOURCE_GCR_SIZE - 1; + + pmc->gcr_mem_base = devm_ioremap_resource(&pdev->dev, &gcr_res); + if (IS_ERR(pmc->gcr_mem_base)) + return PTR_ERR(pmc->gcr_mem_base); + + /* Only register iTCO watchdog if there is no WDAT ACPI table */ + ret = intel_pmc_get_tco_resources(pdev); + if (ret) + return ret; + + /* BIOS data register */ + res = platform_get_resource(pdev, IORESOURCE_MEM, + PLAT_RESOURCE_BIOS_DATA_INDEX); + if (!res) { + dev_err(&pdev->dev, "Failed to get resource of P-unit BIOS data\n"); + return -EINVAL; + } + punit_res[npunit_res++] = *res; + + /* BIOS interface register */ + res = platform_get_resource(pdev, IORESOURCE_MEM, + PLAT_RESOURCE_BIOS_IFACE_INDEX); + if (!res) { + dev_err(&pdev->dev, "Failed to get resource of P-unit BIOS interface\n"); + return -EINVAL; + } + punit_res[npunit_res++] = *res; + + /* ISP data register, optional */ + res = platform_get_resource(pdev, IORESOURCE_MEM, + PLAT_RESOURCE_ISP_DATA_INDEX); + if (res) + punit_res[npunit_res++] = *res; + + /* ISP interface register, optional */ + res = platform_get_resource(pdev, IORESOURCE_MEM, + PLAT_RESOURCE_ISP_IFACE_INDEX); + if (res) + punit_res[npunit_res++] = *res; + + /* GTD data register, optional */ + res = platform_get_resource(pdev, IORESOURCE_MEM, + PLAT_RESOURCE_GTD_DATA_INDEX); + if (res) + punit_res[npunit_res++] = *res; + + /* GTD interface register, optional */ + res = platform_get_resource(pdev, IORESOURCE_MEM, + PLAT_RESOURCE_GTD_IFACE_INDEX); + if (res) + punit_res[npunit_res++] = *res; + + punit.num_resources = npunit_res; + + /* Telemetry SSRAM is optional */ + res = platform_get_resource(pdev, IORESOURCE_MEM, + PLAT_RESOURCE_TELEM_SSRAM_INDEX); + if (res) + pmc->telem_base = res; + + return 0; +} + +static int intel_pmc_create_devices(struct intel_pmc_dev *pmc) +{ + int ret; + + if (!acpi_has_watchdog()) { + ret = devm_mfd_add_devices(pmc->dev, PLATFORM_DEVID_AUTO, &tco, + 1, NULL, 0, NULL); + if (ret) + return ret; + } + + ret = devm_mfd_add_devices(pmc->dev, PLATFORM_DEVID_AUTO, &punit, 1, + NULL, 0, NULL); + if (ret) + return ret; + + if (pmc->telem_base) { + ret = devm_mfd_add_devices(pmc->dev, PLATFORM_DEVID_AUTO, + &telem, 1, pmc->telem_base, 0, NULL); + } + + return ret; +} + +static const struct acpi_device_id intel_pmc_acpi_ids[] = { + { "INT34D2" }, + { } +}; +MODULE_DEVICE_TABLE(acpi, intel_pmc_acpi_ids); + +static int intel_pmc_probe(struct platform_device *pdev) +{ + struct intel_scu_ipc_data scu_data = {}; + struct intel_pmc_dev *pmc; + int ret; + + pmc = devm_kzalloc(&pdev->dev, sizeof(*pmc), GFP_KERNEL); + if (!pmc) + return -ENOMEM; + + pmc->dev = &pdev->dev; + spin_lock_init(&pmc->gcr_lock); + + ret = intel_pmc_get_resources(pdev, pmc, &scu_data); + if (ret) { + dev_err(&pdev->dev, "Failed to request resources\n"); + return ret; + } + + pmc->scu = devm_intel_scu_ipc_register(&pdev->dev, &scu_data); + if (IS_ERR(pmc->scu)) + return PTR_ERR(pmc->scu); + + platform_set_drvdata(pdev, pmc); + + ret = intel_pmc_create_devices(pmc); + if (ret) + dev_err(&pdev->dev, "Failed to create PMC devices\n"); + + return ret; +} + +static struct platform_driver intel_pmc_driver = { + .probe = intel_pmc_probe, + .driver = { + .name = "intel_pmc_bxt", + .acpi_match_table = intel_pmc_acpi_ids, + .dev_groups = intel_pmc_groups, + }, +}; +module_platform_driver(intel_pmc_driver); + +MODULE_AUTHOR("Mika Westerberg <mika.westerberg@linux.intel.com>"); +MODULE_AUTHOR("Zha Qipeng <qipeng.zha@intel.com>"); +MODULE_DESCRIPTION("Intel Broxton PMC driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/mfd/intel_soc_pmic_bxtwc.c b/drivers/mfd/intel_soc_pmic_bxtwc.c index 739cfb5b69fe..eba89780dbe7 100644 --- a/drivers/mfd/intel_soc_pmic_bxtwc.c +++ b/drivers/mfd/intel_soc_pmic_bxtwc.c @@ -15,7 +15,7 @@ #include <linux/mfd/intel_soc_pmic_bxtwc.h> #include <linux/module.h> -#include <asm/intel_pmc_ipc.h> +#include <asm/intel_scu_ipc.h> /* PMIC device registers */ #define REG_ADDR_MASK 0xFF00 @@ -58,6 +58,10 @@ /* Whiskey Cove PMIC share same ACPI ID between different platforms */ #define BROXTON_PMIC_WC_HRV 4 +#define PMC_PMIC_ACCESS 0xFF +#define PMC_PMIC_READ 0x0 +#define PMC_PMIC_WRITE 0x1 + enum bxtwc_irqs { BXTWC_PWRBTN_LVL1_IRQ = 0, BXTWC_TMU_LVL1_IRQ, @@ -288,13 +292,12 @@ static int regmap_ipc_byte_reg_read(void *context, unsigned int reg, ipc_in[0] = reg; ipc_in[1] = i2c_addr; - ret = intel_pmc_ipc_command(PMC_IPC_PMIC_ACCESS, - PMC_IPC_PMIC_ACCESS_READ, - ipc_in, sizeof(ipc_in), (u32 *)ipc_out, 1); - if (ret) { - dev_err(pmic->dev, "Failed to read from PMIC\n"); + ret = intel_scu_ipc_dev_command(pmic->scu, PMC_PMIC_ACCESS, + PMC_PMIC_READ, ipc_in, sizeof(ipc_in), + ipc_out, sizeof(ipc_out)); + if (ret) return ret; - } + *val = ipc_out[0]; return 0; @@ -303,7 +306,6 @@ static int regmap_ipc_byte_reg_read(void *context, unsigned int reg, static int regmap_ipc_byte_reg_write(void *context, unsigned int reg, unsigned int val) { - int ret; int i2c_addr; u8 ipc_in[3]; struct intel_soc_pmic *pmic = context; @@ -321,15 +323,9 @@ static int regmap_ipc_byte_reg_write(void *context, unsigned int reg, ipc_in[0] = reg; ipc_in[1] = i2c_addr; ipc_in[2] = val; - ret = intel_pmc_ipc_command(PMC_IPC_PMIC_ACCESS, - PMC_IPC_PMIC_ACCESS_WRITE, - ipc_in, sizeof(ipc_in), NULL, 0); - if (ret) { - dev_err(pmic->dev, "Failed to write to PMIC\n"); - return ret; - } - - return 0; + return intel_scu_ipc_dev_command(pmic->scu, PMC_PMIC_ACCESS, + PMC_PMIC_WRITE, ipc_in, sizeof(ipc_in), + NULL, 0); } /* sysfs interfaces to r/w PMIC registers, required by initial script */ @@ -457,6 +453,10 @@ static int bxtwc_probe(struct platform_device *pdev) dev_set_drvdata(&pdev->dev, pmic); pmic->dev = &pdev->dev; + pmic->scu = devm_intel_scu_ipc_dev_get(&pdev->dev); + if (!pmic->scu) + return -EPROBE_DEFER; + pmic->regmap = devm_regmap_init(&pdev->dev, NULL, pmic, &bxtwc_regmap_config); if (IS_ERR(pmic->regmap)) { diff --git a/drivers/mfd/intel_soc_pmic_mrfld.c b/drivers/mfd/intel_soc_pmic_mrfld.c index 26a1551c5faf..bd94c989d232 100644 --- a/drivers/mfd/intel_soc_pmic_mrfld.c +++ b/drivers/mfd/intel_soc_pmic_mrfld.c @@ -74,10 +74,11 @@ static const struct mfd_cell bcove_dev[] = { static int bcove_ipc_byte_reg_read(void *context, unsigned int reg, unsigned int *val) { + struct intel_soc_pmic *pmic = context; u8 ipc_out; int ret; - ret = intel_scu_ipc_ioread8(reg, &ipc_out); + ret = intel_scu_ipc_dev_ioread8(pmic->scu, reg, &ipc_out); if (ret) return ret; @@ -88,10 +89,11 @@ static int bcove_ipc_byte_reg_read(void *context, unsigned int reg, static int bcove_ipc_byte_reg_write(void *context, unsigned int reg, unsigned int val) { + struct intel_soc_pmic *pmic = context; u8 ipc_in = val; int ret; - ret = intel_scu_ipc_iowrite8(reg, ipc_in); + ret = intel_scu_ipc_dev_iowrite8(pmic->scu, reg, ipc_in); if (ret) return ret; @@ -117,6 +119,10 @@ static int bcove_probe(struct platform_device *pdev) if (!pmic) return -ENOMEM; + pmic->scu = devm_intel_scu_ipc_dev_get(dev); + if (!pmic->scu) + return -ENOMEM; + platform_set_drvdata(pdev, pmic); pmic->dev = &pdev->dev; diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index 0ad7ad8cf8e1..642316761443 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -1269,7 +1269,8 @@ config INTEL_UNCORE_FREQ_CONTROL config INTEL_BXTWC_PMIC_TMU tristate "Intel BXT Whiskey Cove TMU Driver" depends on REGMAP - depends on INTEL_SOC_PMIC_BXTWC && INTEL_PMC_IPC + depends on MFD_INTEL_PMC_BXT + depends on INTEL_SOC_PMIC_BXTWC ---help--- Select this driver to use Intel BXT Whiskey Cove PMIC TMU feature. This driver enables the alarm wakeup functionality in the TMU unit @@ -1295,7 +1296,7 @@ config INTEL_MFLD_THERMAL config INTEL_MID_POWER_BUTTON tristate "power button driver for Intel MID platforms" - depends on INTEL_SCU_IPC && INPUT + depends on INTEL_SCU && INPUT help This driver handles the power button on the Intel MID platforms. @@ -1327,14 +1328,6 @@ config INTEL_PMC_CORE - LTR Ignore - MPHY/PLL gating status (Sunrisepoint PCH only) -config INTEL_PMC_IPC - tristate "Intel PMC IPC Driver" - depends on ACPI && PCI - ---help--- - This driver provides support for PMC control on some Intel platforms. - The PMC is an ARC processor which defines IPC commands for communication - with other entities in the CPU. - config INTEL_PUNIT_IPC tristate "Intel P-Unit IPC Driver" ---help--- @@ -1342,17 +1335,30 @@ config INTEL_PUNIT_IPC which is used to bridge the communications between kernel and P-Unit. config INTEL_SCU_IPC - bool "Intel SCU IPC Support" - depends on X86_INTEL_MID - default y - ---help--- - IPC is used to bridge the communications between kernel and SCU on - some embedded Intel x86 platforms. This is not needed for PC-type - machines. + bool + +config INTEL_SCU + bool + select INTEL_SCU_IPC + +config INTEL_SCU_PCI + bool "Intel SCU PCI driver" + depends on PCI + select INTEL_SCU + help + This driver is used to bridge the communications between kernel + and SCU on some embedded Intel x86 platforms. It also creates + devices that are connected to the SoC through the SCU. + Platforms supported: + Medfield + Clovertrail + Merrifield + Broxton + Apollo Lake config INTEL_SCU_IPC_UTIL tristate "Intel SCU IPC utility driver" - depends on INTEL_SCU_IPC + depends on INTEL_SCU ---help--- The IPC Util driver provides an interface with the SCU enabling low level access for debug work and updating the firmware. Say @@ -1360,7 +1366,9 @@ config INTEL_SCU_IPC_UTIL config INTEL_TELEMETRY tristate "Intel SoC Telemetry Driver" - depends on INTEL_PMC_IPC && INTEL_PUNIT_IPC && X86_64 + depends on X86_64 + depends on MFD_INTEL_PMC_BXT + depends on INTEL_PUNIT_IPC ---help--- This driver provides interfaces to configure and use telemetry for INTEL SoC from APL onwards. It is also diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile index 53408d965874..04db27a25946 100644 --- a/drivers/platform/x86/Makefile +++ b/drivers/platform/x86/Makefile @@ -138,9 +138,9 @@ obj-$(CONFIG_INTEL_MFLD_THERMAL) += intel_mid_thermal.o obj-$(CONFIG_INTEL_MID_POWER_BUTTON) += intel_mid_powerbtn.o obj-$(CONFIG_INTEL_MRFLD_PWRBTN) += intel_mrfld_pwrbtn.o obj-$(CONFIG_INTEL_PMC_CORE) += intel_pmc_core.o intel_pmc_core_pltdrv.o -obj-$(CONFIG_INTEL_PMC_IPC) += intel_pmc_ipc.o obj-$(CONFIG_INTEL_PUNIT_IPC) += intel_punit_ipc.o obj-$(CONFIG_INTEL_SCU_IPC) += intel_scu_ipc.o +obj-$(CONFIG_INTEL_SCU_PCI) += intel_scu_pcidrv.o obj-$(CONFIG_INTEL_SCU_IPC_UTIL) += intel_scu_ipcutil.o obj-$(CONFIG_INTEL_TELEMETRY) += intel_telemetry_core.o \ intel_telemetry_pltdrv.o \ diff --git a/drivers/platform/x86/intel_mid_powerbtn.c b/drivers/platform/x86/intel_mid_powerbtn.c index 9c9f209c8a33..df434abbb66f 100644 --- a/drivers/platform/x86/intel_mid_powerbtn.c +++ b/drivers/platform/x86/intel_mid_powerbtn.c @@ -46,6 +46,7 @@ struct mid_pb_ddata { unsigned short mirqlvl1_addr; unsigned short pbstat_addr; u8 pbstat_mask; + struct intel_scu_ipc_dev *scu; int (*setup)(struct mid_pb_ddata *ddata); }; @@ -55,7 +56,8 @@ static int mid_pbstat(struct mid_pb_ddata *ddata, int *value) int ret; u8 pbstat; - ret = intel_scu_ipc_ioread8(ddata->pbstat_addr, &pbstat); + ret = intel_scu_ipc_dev_ioread8(ddata->scu, ddata->pbstat_addr, + &pbstat); if (ret) return ret; @@ -67,14 +69,15 @@ static int mid_pbstat(struct mid_pb_ddata *ddata, int *value) static int mid_irq_ack(struct mid_pb_ddata *ddata) { - return intel_scu_ipc_update_register(ddata->mirqlvl1_addr, 0, MSIC_PWRBTNM); + return intel_scu_ipc_dev_update(ddata->scu, ddata->mirqlvl1_addr, 0, + MSIC_PWRBTNM); } static int mrfld_setup(struct mid_pb_ddata *ddata) { /* Unmask the PBIRQ and MPBIRQ on Tangier */ - intel_scu_ipc_update_register(BCOVE_PBIRQ, 0, MSIC_PWRBTNM); - intel_scu_ipc_update_register(BCOVE_PBIRQMASK, 0, MSIC_PWRBTNM); + intel_scu_ipc_dev_update(ddata->scu, BCOVE_PBIRQ, 0, MSIC_PWRBTNM); + intel_scu_ipc_dev_update(ddata->scu, BCOVE_PBIRQMASK, 0, MSIC_PWRBTNM); return 0; } @@ -161,6 +164,10 @@ static int mid_pb_probe(struct platform_device *pdev) return error; } + ddata->scu = devm_intel_scu_ipc_dev_get(&pdev->dev); + if (!ddata->scu) + return -EPROBE_DEFER; + error = devm_request_threaded_irq(&pdev->dev, irq, NULL, mid_pb_isr, IRQF_ONESHOT, DRIVER_NAME, ddata); if (error) { diff --git a/drivers/platform/x86/intel_pmc_ipc.c b/drivers/platform/x86/intel_pmc_ipc.c deleted file mode 100644 index 2433bf73f1ed..000000000000 --- a/drivers/platform/x86/intel_pmc_ipc.c +++ /dev/null @@ -1,949 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Driver for the Intel PMC IPC mechanism - * - * (C) Copyright 2014-2015 Intel Corporation - * - * This driver is based on Intel SCU IPC driver(intel_scu_ipc.c) by - * Sreedhara DS <sreedhara.ds@intel.com> - * - * PMC running in ARC processor communicates with other entity running in IA - * core through IPC mechanism which in turn messaging between IA core ad PMC. - */ - -#include <linux/acpi.h> -#include <linux/delay.h> -#include <linux/errno.h> -#include <linux/interrupt.h> -#include <linux/io-64-nonatomic-lo-hi.h> -#include <linux/module.h> -#include <linux/pci.h> -#include <linux/platform_device.h> - -#include <asm/intel_pmc_ipc.h> - -#include <linux/platform_data/itco_wdt.h> - -/* - * IPC registers - * The IA write to IPC_CMD command register triggers an interrupt to the ARC, - * The ARC handles the interrupt and services it, writing optional data to - * the IPC1 registers, updates the IPC_STS response register with the status. - */ -#define IPC_CMD 0x00 -#define IPC_CMD_MSI BIT(8) -#define IPC_CMD_SIZE 16 -#define IPC_CMD_SUBCMD 12 -#define IPC_STATUS 0x04 -#define IPC_STATUS_IRQ BIT(2) -#define IPC_STATUS_ERR BIT(1) -#define IPC_STATUS_BUSY BIT(0) -#define IPC_SPTR 0x08 -#define IPC_DPTR 0x0C -#define IPC_WRITE_BUFFER 0x80 -#define IPC_READ_BUFFER 0x90 - -/* Residency with clock rate at 19.2MHz to usecs */ -#define S0IX_RESIDENCY_IN_USECS(d, s) \ -({ \ - u64 result = 10ull * ((d) + (s)); \ - do_div(result, 192); \ - result; \ -}) - -/* - * 16-byte buffer for sending data associated with IPC command. - */ -#define IPC_DATA_BUFFER_SIZE 16 - -#define IPC_LOOP_CNT 3000000 -#define IPC_MAX_SEC 3 - -#define IPC_TRIGGER_MODE_IRQ true - -/* exported resources from IFWI */ -#define PLAT_RESOURCE_IPC_INDEX 0 -#define PLAT_RESOURCE_IPC_SIZE 0x1000 -#define PLAT_RESOURCE_GCR_OFFSET 0x1000 -#define PLAT_RESOURCE_GCR_SIZE 0x1000 -#define PLAT_RESOURCE_BIOS_DATA_INDEX 1 -#define PLAT_RESOURCE_BIOS_IFACE_INDEX 2 -#define PLAT_RESOURCE_TELEM_SSRAM_INDEX 3 -#define PLAT_RESOURCE_ISP_DATA_INDEX 4 -#define PLAT_RESOURCE_ISP_IFACE_INDEX 5 -#define PLAT_RESOURCE_GTD_DATA_INDEX 6 -#define PLAT_RESOURCE_GTD_IFACE_INDEX 7 -#define PLAT_RESOURCE_ACPI_IO_INDEX 0 - -/* - * BIOS does not create an ACPI device for each PMC function, - * but exports multiple resources from one ACPI device(IPC) for - * multiple functions. This driver is responsible to create a - * platform device and to export resources for those functions. - */ -#define TCO_DEVICE_NAME "iTCO_wdt" -#define SMI_EN_OFFSET 0x40 -#define SMI_EN_SIZE 4 -#define TCO_BASE_OFFSET 0x60 -#define TCO_REGS_SIZE 16 -#define PUNIT_DEVICE_NAME "intel_punit_ipc" -#define TELEMETRY_DEVICE_NAME "intel_telemetry" -#define TELEM_SSRAM_SIZE 240 -#define TELEM_PMC_SSRAM_OFFSET 0x1B00 -#define TELEM_PUNIT_SSRAM_OFFSET 0x1A00 -#define TCO_PMC_OFFSET 0x08 -#define TCO_PMC_SIZE 0x04 - -/* PMC register bit definitions */ - -/* PMC_CFG_REG bit masks */ -#define PMC_CFG_NO_REBOOT_MASK BIT_MASK(4) -#define PMC_CFG_NO_REBOOT_EN (1 << 4) -#define PMC_CFG_NO_REBOOT_DIS (0 << 4) - -static struct intel_pmc_ipc_dev { - struct device *dev; - void __iomem *ipc_base; - bool irq_mode; - int irq; - int cmd; - struct completion cmd_complete; - - /* The following PMC BARs share the same ACPI device with the IPC */ - resource_size_t acpi_io_base; - int acpi_io_size; - struct platform_device *tco_dev; - - /* gcr */ - void __iomem *gcr_mem_base; - bool has_gcr_regs; - spinlock_t gcr_lock; - - /* punit */ - struct platform_device *punit_dev; - unsigned int punit_res_count; - - /* Telemetry */ - resource_size_t telem_pmc_ssram_base; - resource_size_t telem_p |