Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

platform/x86: intel_pmc_ipc: Convert to MFD

This driver only creates a bunch of platform devices sharing resources
belonging to the PMC device. This is pretty much what MFD subsystem is
for so move the driver there, renaming it to intel_pmc_bxt.c which
should be more clear what it is.

MFD subsystem provides nice helper APIs for subdevice creation so
convert the driver to use those. Unfortunately the ACPI device includes
separate resources for most of the subdevices so we cannot simply call
mfd_add_devices() to create all of them but instead we need to call it
separately for each device.

The new MFD driver continues to expose two sysfs attributes that allow
userspace to send IPC commands to the PMC/SCU to avoid breaking any
existing applications that may use these. Generally this is bad idea so
document this in the ABI documentation.

Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Signed-off-by: Lee Jones <lee.jones@linaro.org>

authored by

Mika Westerberg and committed by
Lee Jones
25f1ca31 0759a873

+603 -721
+22
Documentation/ABI/obsolete/sysfs-driver-intel_pmc_bxt
··· 1 + These files allow sending arbitrary IPC commands to the PMC/SCU which 2 + may be dangerous. These will be removed eventually and should not be 3 + used in any new applications. 4 + 5 + What: /sys/bus/platform/devices/INT34D2:00/simplecmd 6 + Date: Jun 2015 7 + KernelVersion: 4.1 8 + Contact: Mika Westerberg <mika.westerberg@linux.intel.com> 9 + Description: This interface allows userspace to send an arbitrary 10 + IPC command to the PMC/SCU. 11 + 12 + Format: %d %d where first number is command and 13 + second number is subcommand. 14 + 15 + What: /sys/bus/platform/devices/INT34D2:00/northpeak 16 + Date: Jun 2015 17 + KernelVersion: 4.1 18 + Contact: Mika Westerberg <mika.westerberg@linux.intel.com> 19 + Description: This interface allows userspace to enable and disable 20 + Northpeak through the PMC/SCU. 21 + 22 + Format: %u.
-47
arch/x86/include/asm/intel_pmc_ipc.h
··· 1 - /* SPDX-License-Identifier: GPL-2.0 */ 2 - #ifndef _ASM_X86_INTEL_PMC_IPC_H_ 3 - #define _ASM_X86_INTEL_PMC_IPC_H_ 4 - 5 - /* Commands */ 6 - #define PMC_IPC_USB_PWR_CTRL 0xF0 7 - #define PMC_IPC_PMIC_BLACKLIST_SEL 0xEF 8 - #define PMC_IPC_PHY_CONFIG 0xEE 9 - #define PMC_IPC_NORTHPEAK_CTRL 0xED 10 - #define PMC_IPC_PM_DEBUG 0xEC 11 - #define PMC_IPC_PMC_FW_MSG_CTRL 0xEA 12 - 13 - /* IPC return code */ 14 - #define IPC_ERR_NONE 0 15 - #define IPC_ERR_CMD_NOT_SUPPORTED 1 16 - #define IPC_ERR_CMD_NOT_SERVICED 2 17 - #define IPC_ERR_UNABLE_TO_SERVICE 3 18 - #define IPC_ERR_CMD_INVALID 4 19 - #define IPC_ERR_CMD_FAILED 5 20 - #define IPC_ERR_EMSECURITY 6 21 - #define IPC_ERR_UNSIGNEDKERNEL 7 22 - 23 - /* GCR reg offsets from gcr base*/ 24 - #define PMC_GCR_PMC_CFG_REG 0x08 25 - #define PMC_GCR_TELEM_DEEP_S0IX_REG 0x78 26 - #define PMC_GCR_TELEM_SHLW_S0IX_REG 0x80 27 - 28 - #if IS_ENABLED(CONFIG_INTEL_PMC_IPC) 29 - 30 - int intel_pmc_s0ix_counter_read(u64 *data); 31 - int intel_pmc_gcr_read64(u32 offset, u64 *data); 32 - 33 - #else 34 - 35 - static inline int intel_pmc_s0ix_counter_read(u64 *data) 36 - { 37 - return -EINVAL; 38 - } 39 - 40 - static inline int intel_pmc_gcr_read64(u32 offset, u64 *data) 41 - { 42 - return -EINVAL; 43 - } 44 - 45 - #endif /*CONFIG_INTEL_PMC_IPC*/ 46 - 47 - #endif
+1
arch/x86/include/asm/intel_telemetry.h
··· 53 53 struct telemetry_unit_config ioss_config; 54 54 struct mutex telem_trace_lock; 55 55 struct mutex telem_lock; 56 + struct intel_pmc_dev *pmc; 56 57 struct intel_scu_ipc_dev *scu; 57 58 bool telem_in_use; 58 59 };
+15 -1
drivers/mfd/Kconfig
··· 551 551 552 552 config INTEL_SOC_PMIC_BXTWC 553 553 tristate "Support for Intel Broxton Whiskey Cove PMIC" 554 - depends on INTEL_PMC_IPC 554 + depends on MFD_INTEL_PMC_BXT 555 555 select MFD_CORE 556 556 select REGMAP_IRQ 557 557 help ··· 631 631 Select this option to enable access to Intel MSIC (Avatele 632 632 Passage) chip. This chip embeds audio, battery, GPIO, etc. 633 633 devices used in Intel Medfield platforms. 634 + 635 + config MFD_INTEL_PMC_BXT 636 + tristate "Intel PMC Driver for Broxton" 637 + depends on X86 638 + depends on X86_PLATFORM_DEVICES 639 + depends on ACPI 640 + select INTEL_SCU_IPC 641 + select MFD_CORE 642 + help 643 + This driver provides support for the PMC (Power Management 644 + Controller) on Intel Broxton and Apollo Lake. The PMC is a 645 + multi-function device that exposes IPC, General Control 646 + Register and P-unit access. In addition this creates devices 647 + for iTCO watchdog and telemetry that are part of the PMC. 634 648 635 649 config MFD_IPAQ_MICRO 636 650 bool "Atmel Micro ASIC (iPAQ h3100/h3600/h3700) Support"
+1
drivers/mfd/Makefile
··· 212 212 obj-$(CONFIG_MFD_INTEL_LPSS_PCI) += intel-lpss-pci.o 213 213 obj-$(CONFIG_MFD_INTEL_LPSS_ACPI) += intel-lpss-acpi.o 214 214 obj-$(CONFIG_MFD_INTEL_MSIC) += intel_msic.o 215 + obj-$(CONFIG_MFD_INTEL_PMC_BXT) += intel_pmc_bxt.o 215 216 obj-$(CONFIG_MFD_PALMAS) += palmas.o 216 217 obj-$(CONFIG_MFD_VIPERBOARD) += viperboard.o 217 218 obj-$(CONFIG_MFD_RC5T583) += rc5t583.o rc5t583-irq.o
+468
drivers/mfd/intel_pmc_bxt.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Driver for the Intel Broxton PMC 4 + * 5 + * (C) Copyright 2014 - 2020 Intel Corporation 6 + * 7 + * This driver is based on Intel SCU IPC driver (intel_scu_ipc.c) by 8 + * Sreedhara DS <sreedhara.ds@intel.com> 9 + * 10 + * The PMC (Power Management Controller) running on the ARC processor 11 + * communicates with another entity running in the IA (Intel Architecture) 12 + * core through an IPC (Intel Processor Communications) mechanism which in 13 + * turn sends messages between the IA and the PMC. 14 + */ 15 + 16 + #include <linux/acpi.h> 17 + #include <linux/delay.h> 18 + #include <linux/errno.h> 19 + #include <linux/interrupt.h> 20 + #include <linux/io-64-nonatomic-lo-hi.h> 21 + #include <linux/mfd/core.h> 22 + #include <linux/mfd/intel_pmc_bxt.h> 23 + #include <linux/module.h> 24 + #include <linux/platform_device.h> 25 + #include <linux/platform_data/itco_wdt.h> 26 + 27 + #include <asm/intel_scu_ipc.h> 28 + 29 + /* Residency with clock rate at 19.2MHz to usecs */ 30 + #define S0IX_RESIDENCY_IN_USECS(d, s) \ 31 + ({ \ 32 + u64 result = 10ull * ((d) + (s)); \ 33 + do_div(result, 192); \ 34 + result; \ 35 + }) 36 + 37 + /* Resources exported from IFWI */ 38 + #define PLAT_RESOURCE_IPC_INDEX 0 39 + #define PLAT_RESOURCE_IPC_SIZE 0x1000 40 + #define PLAT_RESOURCE_GCR_OFFSET 0x1000 41 + #define PLAT_RESOURCE_GCR_SIZE 0x1000 42 + #define PLAT_RESOURCE_BIOS_DATA_INDEX 1 43 + #define PLAT_RESOURCE_BIOS_IFACE_INDEX 2 44 + #define PLAT_RESOURCE_TELEM_SSRAM_INDEX 3 45 + #define PLAT_RESOURCE_ISP_DATA_INDEX 4 46 + #define PLAT_RESOURCE_ISP_IFACE_INDEX 5 47 + #define PLAT_RESOURCE_GTD_DATA_INDEX 6 48 + #define PLAT_RESOURCE_GTD_IFACE_INDEX 7 49 + #define PLAT_RESOURCE_ACPI_IO_INDEX 0 50 + 51 + /* 52 + * BIOS does not create an ACPI device for each PMC function, but 53 + * exports multiple resources from one ACPI device (IPC) for multiple 54 + * functions. This driver is responsible for creating a child device and 55 + * to export resources for those functions. 56 + */ 57 + #define SMI_EN_OFFSET 0x0040 58 + #define SMI_EN_SIZE 4 59 + #define TCO_BASE_OFFSET 0x0060 60 + #define TCO_REGS_SIZE 16 61 + #define TELEM_SSRAM_SIZE 240 62 + #define TELEM_PMC_SSRAM_OFFSET 0x1b00 63 + #define TELEM_PUNIT_SSRAM_OFFSET 0x1a00 64 + 65 + /* Commands */ 66 + #define PMC_NORTHPEAK_CTRL 0xed 67 + 68 + static inline bool is_gcr_valid(u32 offset) 69 + { 70 + return offset < PLAT_RESOURCE_GCR_SIZE - 8; 71 + } 72 + 73 + /** 74 + * intel_pmc_gcr_read64() - Read a 64-bit PMC GCR register 75 + * @pmc: PMC device pointer 76 + * @offset: offset of GCR register from GCR address base 77 + * @data: data pointer for storing the register output 78 + * 79 + * Reads the 64-bit PMC GCR register at given offset. 80 + * 81 + * Return: Negative value on error or 0 on success. 82 + */ 83 + int intel_pmc_gcr_read64(struct intel_pmc_dev *pmc, u32 offset, u64 *data) 84 + { 85 + if (!is_gcr_valid(offset)) 86 + return -EINVAL; 87 + 88 + spin_lock(&pmc->gcr_lock); 89 + *data = readq(pmc->gcr_mem_base + offset); 90 + spin_unlock(&pmc->gcr_lock); 91 + 92 + return 0; 93 + } 94 + EXPORT_SYMBOL_GPL(intel_pmc_gcr_read64); 95 + 96 + /** 97 + * intel_pmc_gcr_update() - Update PMC GCR register bits 98 + * @pmc: PMC device pointer 99 + * @offset: offset of GCR register from GCR address base 100 + * @mask: bit mask for update operation 101 + * @val: update value 102 + * 103 + * Updates the bits of given GCR register as specified by 104 + * @mask and @val. 105 + * 106 + * Return: Negative value on error or 0 on success. 107 + */ 108 + int intel_pmc_gcr_update(struct intel_pmc_dev *pmc, u32 offset, u32 mask, u32 val) 109 + { 110 + u32 new_val; 111 + 112 + if (!is_gcr_valid(offset)) 113 + return -EINVAL; 114 + 115 + spin_lock(&pmc->gcr_lock); 116 + new_val = readl(pmc->gcr_mem_base + offset); 117 + 118 + new_val = (new_val & ~mask) | (val & mask); 119 + writel(new_val, pmc->gcr_mem_base + offset); 120 + 121 + new_val = readl(pmc->gcr_mem_base + offset); 122 + spin_unlock(&pmc->gcr_lock); 123 + 124 + /* Check whether the bit update is successful */ 125 + return (new_val & mask) != (val & mask) ? -EIO : 0; 126 + } 127 + EXPORT_SYMBOL_GPL(intel_pmc_gcr_update); 128 + 129 + /** 130 + * intel_pmc_s0ix_counter_read() - Read S0ix residency 131 + * @pmc: PMC device pointer 132 + * @data: Out param that contains current S0ix residency count. 133 + * 134 + * Writes to @data how many usecs the system has been in low-power S0ix 135 + * state. 136 + * 137 + * Return: An error code or 0 on success. 138 + */ 139 + int intel_pmc_s0ix_counter_read(struct intel_pmc_dev *pmc, u64 *data) 140 + { 141 + u64 deep, shlw; 142 + 143 + spin_lock(&pmc->gcr_lock); 144 + deep = readq(pmc->gcr_mem_base + PMC_GCR_TELEM_DEEP_S0IX_REG); 145 + shlw = readq(pmc->gcr_mem_base + PMC_GCR_TELEM_SHLW_S0IX_REG); 146 + spin_unlock(&pmc->gcr_lock); 147 + 148 + *data = S0IX_RESIDENCY_IN_USECS(deep, shlw); 149 + return 0; 150 + } 151 + EXPORT_SYMBOL_GPL(intel_pmc_s0ix_counter_read); 152 + 153 + /** 154 + * simplecmd_store() - Send a simple IPC command 155 + * @dev: Device under the attribute is 156 + * @attr: Attribute in question 157 + * @buf: Buffer holding data to be stored to the attribute 158 + * @count: Number of bytes in @buf 159 + * 160 + * Expects a string with two integers separated with space. These two 161 + * values hold command and subcommand that is send to PMC. 162 + * 163 + * Return: Number number of bytes written (@count) or negative errno in 164 + * case of error. 165 + */ 166 + static ssize_t simplecmd_store(struct device *dev, struct device_attribute *attr, 167 + const char *buf, size_t count) 168 + { 169 + struct intel_pmc_dev *pmc = dev_get_drvdata(dev); 170 + struct intel_scu_ipc_dev *scu = pmc->scu; 171 + int subcmd; 172 + int cmd; 173 + int ret; 174 + 175 + ret = sscanf(buf, "%d %d", &cmd, &subcmd); 176 + if (ret != 2) { 177 + dev_err(dev, "Invalid values, expected: cmd subcmd\n"); 178 + return -EINVAL; 179 + } 180 + 181 + ret = intel_scu_ipc_dev_simple_command(scu, cmd, subcmd); 182 + if (ret) 183 + return ret; 184 + 185 + return count; 186 + } 187 + static DEVICE_ATTR_WO(simplecmd); 188 + 189 + /** 190 + * northpeak_store() - Enable or disable Northpeak 191 + * @dev: Device under the attribute is 192 + * @attr: Attribute in question 193 + * @buf: Buffer holding data to be stored to the attribute 194 + * @count: Number of bytes in @buf 195 + * 196 + * Expects an unsigned integer. Non-zero enables Northpeak and zero 197 + * disables it. 198 + * 199 + * Return: Number number of bytes written (@count) or negative errno in 200 + * case of error. 201 + */ 202 + static ssize_t northpeak_store(struct device *dev, struct device_attribute *attr, 203 + const char *buf, size_t count) 204 + { 205 + struct intel_pmc_dev *pmc = dev_get_drvdata(dev); 206 + struct intel_scu_ipc_dev *scu = pmc->scu; 207 + unsigned long val; 208 + int subcmd; 209 + int ret; 210 + 211 + ret = kstrtoul(buf, 0, &val); 212 + if (ret) 213 + return ret; 214 + 215 + /* Northpeak is enabled if subcmd == 1 and disabled if it is 0 */ 216 + if (val) 217 + subcmd = 1; 218 + else 219 + subcmd = 0; 220 + 221 + ret = intel_scu_ipc_dev_simple_command(scu, PMC_NORTHPEAK_CTRL, subcmd); 222 + if (ret) 223 + return ret; 224 + 225 + return count; 226 + } 227 + static DEVICE_ATTR_WO(northpeak); 228 + 229 + static struct attribute *intel_pmc_attrs[] = { 230 + &dev_attr_northpeak.attr, 231 + &dev_attr_simplecmd.attr, 232 + NULL 233 + }; 234 + 235 + static const struct attribute_group intel_pmc_group = { 236 + .attrs = intel_pmc_attrs, 237 + }; 238 + 239 + static const struct attribute_group *intel_pmc_groups[] = { 240 + &intel_pmc_group, 241 + NULL 242 + }; 243 + 244 + static struct resource punit_res[6]; 245 + 246 + static struct mfd_cell punit = { 247 + .name = "intel_punit_ipc", 248 + .resources = punit_res, 249 + }; 250 + 251 + static struct itco_wdt_platform_data tco_pdata = { 252 + .name = "Apollo Lake SoC", 253 + .version = 5, 254 + .no_reboot_use_pmc = true, 255 + }; 256 + 257 + static struct resource tco_res[2]; 258 + 259 + static const struct mfd_cell tco = { 260 + .name = "iTCO_wdt", 261 + .ignore_resource_conflicts = true, 262 + .resources = tco_res, 263 + .num_resources = ARRAY_SIZE(tco_res), 264 + .platform_data = &tco_pdata, 265 + .pdata_size = sizeof(tco_pdata), 266 + }; 267 + 268 + static const struct resource telem_res[] = { 269 + DEFINE_RES_MEM(TELEM_PUNIT_SSRAM_OFFSET, TELEM_SSRAM_SIZE), 270 + DEFINE_RES_MEM(TELEM_PMC_SSRAM_OFFSET, TELEM_SSRAM_SIZE), 271 + }; 272 + 273 + static const struct mfd_cell telem = { 274 + .name = "intel_telemetry", 275 + .resources = telem_res, 276 + .num_resources = ARRAY_SIZE(telem_res), 277 + }; 278 + 279 + static int intel_pmc_get_tco_resources(struct platform_device *pdev) 280 + { 281 + struct resource *res; 282 + 283 + if (acpi_has_watchdog()) 284 + return 0; 285 + 286 + res = platform_get_resource(pdev, IORESOURCE_IO, 287 + PLAT_RESOURCE_ACPI_IO_INDEX); 288 + if (!res) { 289 + dev_err(&pdev->dev, "Failed to get IO resource\n"); 290 + return -EINVAL; 291 + } 292 + 293 + tco_res[0].flags = IORESOURCE_IO; 294 + tco_res[0].start = res->start + TCO_BASE_OFFSET; 295 + tco_res[0].end = tco_res[0].start + TCO_REGS_SIZE - 1; 296 + tco_res[1].flags = IORESOURCE_IO; 297 + tco_res[1].start = res->start + SMI_EN_OFFSET; 298 + tco_res[1].end = tco_res[1].start + SMI_EN_SIZE - 1; 299 + 300 + return 0; 301 + } 302 + 303 + static int intel_pmc_get_resources(struct platform_device *pdev, 304 + struct intel_pmc_dev *pmc, 305 + struct intel_scu_ipc_data *scu_data) 306 + { 307 + struct resource gcr_res; 308 + size_t npunit_res = 0; 309 + struct resource *res; 310 + int ret; 311 + 312 + scu_data->irq = platform_get_irq_optional(pdev, 0); 313 + 314 + res = platform_get_resource(pdev, IORESOURCE_MEM, 315 + PLAT_RESOURCE_IPC_INDEX); 316 + if (!res) { 317 + dev_err(&pdev->dev, "Failed to get IPC resource\n"); 318 + return -EINVAL; 319 + } 320 + 321 + /* IPC registers */ 322 + scu_data->mem.flags = res->flags; 323 + scu_data->mem.start = res->start; 324 + scu_data->mem.end = res->start + PLAT_RESOURCE_IPC_SIZE - 1; 325 + 326 + /* GCR registers */ 327 + gcr_res.flags = res->flags; 328 + gcr_res.start = res->start + PLAT_RESOURCE_GCR_OFFSET; 329 + gcr_res.end = gcr_res.start + PLAT_RESOURCE_GCR_SIZE - 1; 330 + 331 + pmc->gcr_mem_base = devm_ioremap_resource(&pdev->dev, &gcr_res); 332 + if (IS_ERR(pmc->gcr_mem_base)) 333 + return PTR_ERR(pmc->gcr_mem_base); 334 + 335 + /* Only register iTCO watchdog if there is no WDAT ACPI table */ 336 + ret = intel_pmc_get_tco_resources(pdev); 337 + if (ret) 338 + return ret; 339 + 340 + /* BIOS data register */ 341 + res = platform_get_resource(pdev, IORESOURCE_MEM, 342 + PLAT_RESOURCE_BIOS_DATA_INDEX); 343 + if (!res) { 344 + dev_err(&pdev->dev, "Failed to get resource of P-unit BIOS data\n"); 345 + return -EINVAL; 346 + } 347 + punit_res[npunit_res++] = *res; 348 + 349 + /* BIOS interface register */ 350 + res = platform_get_resource(pdev, IORESOURCE_MEM, 351 + PLAT_RESOURCE_BIOS_IFACE_INDEX); 352 + if (!res) { 353 + dev_err(&pdev->dev, "Failed to get resource of P-unit BIOS interface\n"); 354 + return -EINVAL; 355 + } 356 + punit_res[npunit_res++] = *res; 357 + 358 + /* ISP data register, optional */ 359 + res = platform_get_resource(pdev, IORESOURCE_MEM, 360 + PLAT_RESOURCE_ISP_DATA_INDEX); 361 + if (res) 362 + punit_res[npunit_res++] = *res; 363 + 364 + /* ISP interface register, optional */ 365 + res = platform_get_resource(pdev, IORESOURCE_MEM, 366 + PLAT_RESOURCE_ISP_IFACE_INDEX); 367 + if (res) 368 + punit_res[npunit_res++] = *res; 369 + 370 + /* GTD data register, optional */ 371 + res = platform_get_resource(pdev, IORESOURCE_MEM, 372 + PLAT_RESOURCE_GTD_DATA_INDEX); 373 + if (res) 374 + punit_res[npunit_res++] = *res; 375 + 376 + /* GTD interface register, optional */ 377 + res = platform_get_resource(pdev, IORESOURCE_MEM, 378 + PLAT_RESOURCE_GTD_IFACE_INDEX); 379 + if (res) 380 + punit_res[npunit_res++] = *res; 381 + 382 + punit.num_resources = npunit_res; 383 + 384 + /* Telemetry SSRAM is optional */ 385 + res = platform_get_resource(pdev, IORESOURCE_MEM, 386 + PLAT_RESOURCE_TELEM_SSRAM_INDEX); 387 + if (res) 388 + pmc->telem_base = res; 389 + 390 + return 0; 391 + } 392 + 393 + static int intel_pmc_create_devices(struct intel_pmc_dev *pmc) 394 + { 395 + int ret; 396 + 397 + if (!acpi_has_watchdog()) { 398 + ret = devm_mfd_add_devices(pmc->dev, PLATFORM_DEVID_AUTO, &tco, 399 + 1, NULL, 0, NULL); 400 + if (ret) 401 + return ret; 402 + } 403 + 404 + ret = devm_mfd_add_devices(pmc->dev, PLATFORM_DEVID_AUTO, &punit, 1, 405 + NULL, 0, NULL); 406 + if (ret) 407 + return ret; 408 + 409 + if (pmc->telem_base) { 410 + ret = devm_mfd_add_devices(pmc->dev, PLATFORM_DEVID_AUTO, 411 + &telem, 1, pmc->telem_base, 0, NULL); 412 + } 413 + 414 + return ret; 415 + } 416 + 417 + static const struct acpi_device_id intel_pmc_acpi_ids[] = { 418 + { "INT34D2" }, 419 + { } 420 + }; 421 + MODULE_DEVICE_TABLE(acpi, intel_pmc_acpi_ids); 422 + 423 + static int intel_pmc_probe(struct platform_device *pdev) 424 + { 425 + struct intel_scu_ipc_data scu_data = {}; 426 + struct intel_pmc_dev *pmc; 427 + int ret; 428 + 429 + pmc = devm_kzalloc(&pdev->dev, sizeof(*pmc), GFP_KERNEL); 430 + if (!pmc) 431 + return -ENOMEM; 432 + 433 + pmc->dev = &pdev->dev; 434 + spin_lock_init(&pmc->gcr_lock); 435 + 436 + ret = intel_pmc_get_resources(pdev, pmc, &scu_data); 437 + if (ret) { 438 + dev_err(&pdev->dev, "Failed to request resources\n"); 439 + return ret; 440 + } 441 + 442 + pmc->scu = devm_intel_scu_ipc_register(&pdev->dev, &scu_data); 443 + if (IS_ERR(pmc->scu)) 444 + return PTR_ERR(pmc->scu); 445 + 446 + platform_set_drvdata(pdev, pmc); 447 + 448 + ret = intel_pmc_create_devices(pmc); 449 + if (ret) 450 + dev_err(&pdev->dev, "Failed to create PMC devices\n"); 451 + 452 + return ret; 453 + } 454 + 455 + static struct platform_driver intel_pmc_driver = { 456 + .probe = intel_pmc_probe, 457 + .driver = { 458 + .name = "intel_pmc_bxt", 459 + .acpi_match_table = intel_pmc_acpi_ids, 460 + .dev_groups = intel_pmc_groups, 461 + }, 462 + }; 463 + module_platform_driver(intel_pmc_driver); 464 + 465 + MODULE_AUTHOR("Mika Westerberg <mika.westerberg@linux.intel.com>"); 466 + MODULE_AUTHOR("Zha Qipeng <qipeng.zha@intel.com>"); 467 + MODULE_DESCRIPTION("Intel Broxton PMC driver"); 468 + MODULE_LICENSE("GPL v2");
+5 -11
drivers/platform/x86/Kconfig
··· 1269 1269 config INTEL_BXTWC_PMIC_TMU 1270 1270 tristate "Intel BXT Whiskey Cove TMU Driver" 1271 1271 depends on REGMAP 1272 - depends on INTEL_SOC_PMIC_BXTWC && INTEL_PMC_IPC 1272 + depends on MFD_INTEL_PMC_BXT 1273 + depends on INTEL_SOC_PMIC_BXTWC 1273 1274 ---help--- 1274 1275 Select this driver to use Intel BXT Whiskey Cove PMIC TMU feature. 1275 1276 This driver enables the alarm wakeup functionality in the TMU unit ··· 1328 1327 - LTR Ignore 1329 1328 - MPHY/PLL gating status (Sunrisepoint PCH only) 1330 1329 1331 - config INTEL_PMC_IPC 1332 - tristate "Intel PMC IPC Driver" 1333 - depends on ACPI 1334 - select INTEL_SCU_IPC 1335 - ---help--- 1336 - This driver provides support for PMC control on some Intel platforms. 1337 - The PMC is an ARC processor which defines IPC commands for communication 1338 - with other entities in the CPU. 1339 - 1340 1330 config INTEL_PUNIT_IPC 1341 1331 tristate "Intel P-Unit IPC Driver" 1342 1332 ---help--- ··· 1366 1374 1367 1375 config INTEL_TELEMETRY 1368 1376 tristate "Intel SoC Telemetry Driver" 1369 - depends on INTEL_PMC_IPC && INTEL_PUNIT_IPC && X86_64 1377 + depends on X86_64 1378 + depends on MFD_INTEL_PMC_BXT 1379 + depends on INTEL_PUNIT_IPC 1370 1380 ---help--- 1371 1381 This driver provides interfaces to configure and use 1372 1382 telemetry for INTEL SoC from APL onwards. It is also
-1
drivers/platform/x86/Makefile
··· 138 138 obj-$(CONFIG_INTEL_MID_POWER_BUTTON) += intel_mid_powerbtn.o 139 139 obj-$(CONFIG_INTEL_MRFLD_PWRBTN) += intel_mrfld_pwrbtn.o 140 140 obj-$(CONFIG_INTEL_PMC_CORE) += intel_pmc_core.o intel_pmc_core_pltdrv.o 141 - obj-$(CONFIG_INTEL_PMC_IPC) += intel_pmc_ipc.o 142 141 obj-$(CONFIG_INTEL_PUNIT_IPC) += intel_punit_ipc.o 143 142 obj-$(CONFIG_INTEL_SCU_IPC) += intel_scu_ipc.o 144 143 obj-$(CONFIG_INTEL_SCU_PCI) += intel_scu_pcidrv.o
-645
drivers/platform/x86/intel_pmc_ipc.c
··· 1 - // SPDX-License-Identifier: GPL-2.0 2 - /* 3 - * Driver for the Intel PMC IPC mechanism 4 - * 5 - * (C) Copyright 2014-2015 Intel Corporation 6 - * 7 - * This driver is based on Intel SCU IPC driver(intel_scu_ipc.c) by 8 - * Sreedhara DS <sreedhara.ds@intel.com> 9 - * 10 - * PMC running in ARC processor communicates with other entity running in IA 11 - * core through IPC mechanism which in turn messaging between IA core ad PMC. 12 - */ 13 - 14 - #include <linux/acpi.h> 15 - #include <linux/delay.h> 16 - #include <linux/errno.h> 17 - #include <linux/interrupt.h> 18 - #include <linux/io-64-nonatomic-lo-hi.h> 19 - #include <linux/module.h> 20 - #include <linux/platform_device.h> 21 - 22 - #include <asm/intel_pmc_ipc.h> 23 - #include <asm/intel_scu_ipc.h> 24 - 25 - #include <linux/platform_data/itco_wdt.h> 26 - 27 - /* Residency with clock rate at 19.2MHz to usecs */ 28 - #define S0IX_RESIDENCY_IN_USECS(d, s) \ 29 - ({ \ 30 - u64 result = 10ull * ((d) + (s)); \ 31 - do_div(result, 192); \ 32 - result; \ 33 - }) 34 - 35 - /* exported resources from IFWI */ 36 - #define PLAT_RESOURCE_IPC_INDEX 0 37 - #define PLAT_RESOURCE_IPC_SIZE 0x1000 38 - #define PLAT_RESOURCE_GCR_OFFSET 0x1000 39 - #define PLAT_RESOURCE_GCR_SIZE 0x1000 40 - #define PLAT_RESOURCE_BIOS_DATA_INDEX 1 41 - #define PLAT_RESOURCE_BIOS_IFACE_INDEX 2 42 - #define PLAT_RESOURCE_TELEM_SSRAM_INDEX 3 43 - #define PLAT_RESOURCE_ISP_DATA_INDEX 4 44 - #define PLAT_RESOURCE_ISP_IFACE_INDEX 5 45 - #define PLAT_RESOURCE_GTD_DATA_INDEX 6 46 - #define PLAT_RESOURCE_GTD_IFACE_INDEX 7 47 - #define PLAT_RESOURCE_ACPI_IO_INDEX 0 48 - 49 - /* 50 - * BIOS does not create an ACPI device for each PMC function, 51 - * but exports multiple resources from one ACPI device(IPC) for 52 - * multiple functions. This driver is responsible to create a 53 - * platform device and to export resources for those functions. 54 - */ 55 - #define TCO_DEVICE_NAME "iTCO_wdt" 56 - #define SMI_EN_OFFSET 0x40 57 - #define SMI_EN_SIZE 4 58 - #define TCO_BASE_OFFSET 0x60 59 - #define TCO_REGS_SIZE 16 60 - #define PUNIT_DEVICE_NAME "intel_punit_ipc" 61 - #define TELEMETRY_DEVICE_NAME "intel_telemetry" 62 - #define TELEM_SSRAM_SIZE 240 63 - #define TELEM_PMC_SSRAM_OFFSET 0x1B00 64 - #define TELEM_PUNIT_SSRAM_OFFSET 0x1A00 65 - #define TCO_PMC_OFFSET 0x08 66 - #define TCO_PMC_SIZE 0x04 67 - 68 - /* PMC register bit definitions */ 69 - 70 - /* PMC_CFG_REG bit masks */ 71 - #define PMC_CFG_NO_REBOOT_MASK BIT_MASK(4) 72 - #define PMC_CFG_NO_REBOOT_EN (1 << 4) 73 - #define PMC_CFG_NO_REBOOT_DIS (0 << 4) 74 - 75 - static struct intel_pmc_ipc_dev { 76 - struct device *dev; 77 - 78 - /* The following PMC BARs share the same ACPI device with the IPC */ 79 - resource_size_t acpi_io_base; 80 - int acpi_io_size; 81 - struct platform_device *tco_dev; 82 - 83 - /* gcr */ 84 - void __iomem *gcr_mem_base; 85 - bool has_gcr_regs; 86 - spinlock_t gcr_lock; 87 - 88 - /* punit */ 89 - struct platform_device *punit_dev; 90 - unsigned int punit_res_count; 91 - 92 - /* Telemetry */ 93 - resource_size_t telem_pmc_ssram_base; 94 - resource_size_t telem_punit_ssram_base; 95 - int telem_pmc_ssram_size; 96 - int telem_punit_ssram_size; 97 - u8 telem_res_inval; 98 - struct platform_device *telemetry_dev; 99 - } ipcdev; 100 - 101 - static inline u64 gcr_data_readq(u32 offset) 102 - { 103 - return readq(ipcdev.gcr_mem_base + offset); 104 - } 105 - 106 - static inline int is_gcr_valid(u32 offset) 107 - { 108 - if (!ipcdev.has_gcr_regs) 109 - return -EACCES; 110 - 111 - if (offset > PLAT_RESOURCE_GCR_SIZE) 112 - return -EINVAL; 113 - 114 - return 0; 115 - } 116 - 117 - /** 118 - * intel_pmc_gcr_read64() - Read a 64-bit PMC GCR register 119 - * @offset: offset of GCR register from GCR address base 120 - * @data: data pointer for storing the register output 121 - * 122 - * Reads the 64-bit PMC GCR register at given offset. 123 - * 124 - * Return: negative value on error or 0 on success. 125 - */ 126 - int intel_pmc_gcr_read64(u32 offset, u64 *data) 127 - { 128 - int ret; 129 - 130 - spin_lock(&ipcdev.gcr_lock); 131 - 132 - ret = is_gcr_valid(offset); 133 - if (ret < 0) { 134 - spin_unlock(&ipcdev.gcr_lock); 135 - return ret; 136 - } 137 - 138 - *data = readq(ipcdev.gcr_mem_base + offset); 139 - 140 - spin_unlock(&ipcdev.gcr_lock); 141 - 142 - return 0; 143 - } 144 - EXPORT_SYMBOL_GPL(intel_pmc_gcr_read64); 145 - 146 - /** 147 - * intel_pmc_gcr_update() - Update PMC GCR register bits 148 - * @offset: offset of GCR register from GCR address base 149 - * @mask: bit mask for update operation 150 - * @val: update value 151 - * 152 - * Updates the bits of given GCR register as specified by 153 - * @mask and @val. 154 - * 155 - * Return: negative value on error or 0 on success. 156 - */ 157 - static int intel_pmc_gcr_update(u32 offset, u32 mask, u32 val) 158 - { 159 - u32 new_val; 160 - int ret = 0; 161 - 162 - spin_lock(&ipcdev.gcr_lock); 163 - 164 - ret = is_gcr_valid(offset); 165 - if (ret < 0) 166 - goto gcr_ipc_unlock; 167 - 168 - new_val = readl(ipcdev.gcr_mem_base + offset); 169 - 170 - new_val &= ~mask; 171 - new_val |= val & mask; 172 - 173 - writel(new_val, ipcdev.gcr_mem_base + offset); 174 - 175 - new_val = readl(ipcdev.gcr_mem_base + offset); 176 - 177 - /* check whether the bit update is successful */ 178 - if ((new_val & mask) != (val & mask)) { 179 - ret = -EIO; 180 - goto gcr_ipc_unlock; 181 - } 182 - 183 - gcr_ipc_unlock: 184 - spin_unlock(&ipcdev.gcr_lock); 185 - return ret; 186 - } 187 - 188 - static int update_no_reboot_bit(void *priv, bool set) 189 - { 190 - u32 value = set ? PMC_CFG_NO_REBOOT_EN : PMC_CFG_NO_REBOOT_DIS; 191 - 192 - return intel_pmc_gcr_update(PMC_GCR_PMC_CFG_REG, 193 - PMC_CFG_NO_REBOOT_MASK, value); 194 - } 195 - 196 - static ssize_t intel_pmc_ipc_simple_cmd_store(struct device *dev, 197 - struct device_attribute *attr, 198 - const char *buf, size_t count) 199 - { 200 - struct intel_scu_ipc_dev *scu = dev_get_drvdata(dev); 201 - int subcmd; 202 - int cmd; 203 - int ret; 204 - 205 - ret = sscanf(buf, "%d %d", &cmd, &subcmd); 206 - if (ret != 2) { 207 - dev_err(dev, "Error args\n"); 208 - return -EINVAL; 209 - } 210 - 211 - ret = intel_scu_ipc_dev_simple_command(scu, cmd, subcmd); 212 - if (ret) { 213 - dev_err(dev, "command %d error with %d\n", cmd, ret); 214 - return ret; 215 - } 216 - return (ssize_t)count; 217 - } 218 - static DEVICE_ATTR(simplecmd, 0200, NULL, intel_pmc_ipc_simple_cmd_store); 219 - 220 - static ssize_t intel_pmc_ipc_northpeak_store(struct device *dev, 221 - struct device_attribute *attr, 222 - const char *buf, size_t count) 223 - { 224 - struct intel_scu_ipc_dev *scu = dev_get_drvdata(dev); 225 - unsigned long val; 226 - int subcmd; 227 - int ret; 228 - 229 - ret = kstrtoul(buf, 0, &val); 230 - if (ret) 231 - return ret; 232 - 233 - if (val) 234 - subcmd = 1; 235 - else 236 - subcmd = 0; 237 - ret = intel_scu_ipc_dev_simple_command(scu, PMC_IPC_NORTHPEAK_CTRL, subcmd); 238 - if (ret) { 239 - dev_err(dev, "command north %d error with %d\n", subcmd, ret); 240 - return ret; 241 - } 242 - return (ssize_t)count; 243 - } 244 - static DEVICE_ATTR(northpeak, 0200, NULL, intel_pmc_ipc_northpeak_store); 245 - 246 - static struct attribute *intel_ipc_attrs[] = { 247 - &dev_attr_northpeak.attr, 248 - &dev_attr_simplecmd.attr, 249 - NULL 250 - }; 251 - 252 - static const struct attribute_group intel_ipc_group = { 253 - .attrs = intel_ipc_attrs, 254 - }; 255 - 256 - static const struct attribute_group *intel_ipc_groups[] = { 257 - &intel_ipc_group, 258 - NULL 259 - }; 260 - 261 - static struct resource punit_res_array[] = { 262 - /* Punit BIOS */ 263 - { 264 - .flags = IORESOURCE_MEM, 265 - }, 266 - { 267 - .flags = IORESOURCE_MEM, 268 - }, 269 - /* Punit ISP */ 270 - { 271 - .flags = IORESOURCE_MEM, 272 - }, 273 - { 274 - .flags = IORESOURCE_MEM, 275 - }, 276 - /* Punit GTD */ 277 - { 278 - .flags = IORESOURCE_MEM, 279 - }, 280 - { 281 - .flags = IORESOURCE_MEM, 282 - }, 283 - }; 284 - 285 - #define TCO_RESOURCE_ACPI_IO 0 286 - #define TCO_RESOURCE_SMI_EN_IO 1 287 - #define TCO_RESOURCE_GCR_MEM 2 288 - static struct resource tco_res[] = { 289 - /* ACPI - TCO */ 290 - { 291 - .flags = IORESOURCE_IO, 292 - }, 293 - /* ACPI - SMI */ 294 - { 295 - .flags = IORESOURCE_IO, 296 - }, 297 - }; 298 - 299 - static struct itco_wdt_platform_data tco_info = { 300 - .name = "Apollo Lake SoC", 301 - .version = 5, 302 - .no_reboot_priv = &ipcdev, 303 - .update_no_reboot_bit = update_no_reboot_bit, 304 - }; 305 - 306 - #define TELEMETRY_RESOURCE_PUNIT_SSRAM 0 307 - #define TELEMETRY_RESOURCE_PMC_SSRAM 1 308 - static struct resource telemetry_res[] = { 309 - /*Telemetry*/ 310 - { 311 - .flags = IORESOURCE_MEM, 312 - }, 313 - { 314 - .flags = IORESOURCE_MEM, 315 - }, 316 - }; 317 - 318 - static int ipc_create_punit_device(void) 319 - { 320 - struct platform_device *pdev; 321 - const struct platform_device_info pdevinfo = { 322 - .parent = ipcdev.dev, 323 - .name = PUNIT_DEVICE_NAME, 324 - .id = -1, 325 - .res = punit_res_array, 326 - .num_res = ipcdev.punit_res_count, 327 - }; 328 - 329 - pdev = platform_device_register_full(&pdevinfo); 330 - if (IS_ERR(pdev)) 331 - return PTR_ERR(pdev); 332 - 333 - ipcdev.punit_dev = pdev; 334 - 335 - return 0; 336 - } 337 - 338 - static int ipc_create_tco_device(void) 339 - { 340 - struct platform_device *pdev; 341 - struct resource *res; 342 - const struct platform_device_info pdevinfo = { 343 - .parent = ipcdev.dev, 344 - .name = TCO_DEVICE_NAME, 345 - .id = -1, 346 - .res = tco_res, 347 - .num_res = ARRAY_SIZE(tco_res), 348 - .data = &tco_info, 349 - .size_data = sizeof(tco_info), 350 - }; 351 - 352 - res = tco_res + TCO_RESOURCE_ACPI_IO; 353 - res->start = ipcdev.acpi_io_base + TCO_BASE_OFFSET; 354 - res->end = res->start + TCO_REGS_SIZE - 1; 355 - 356 - res = tco_res + TCO_RESOURCE_SMI_EN_IO; 357 - res->start = ipcdev.acpi_io_base + SMI_EN_OFFSET; 358 - res->end = res->start + SMI_EN_SIZE - 1; 359 - 360 - pdev = platform_device_register_full(&pdevinfo); 361 - if (IS_ERR(pdev)) 362 - return PTR_ERR(pdev); 363 - 364 - ipcdev.tco_dev = pdev; 365 - 366 - return 0; 367 - } 368 - 369 - static int ipc_create_telemetry_device(void) 370 - { 371 - struct platform_device *pdev; 372 - struct resource *res; 373 - const struct platform_device_info pdevinfo = { 374 - .parent = ipcdev.dev, 375 - .name = TELEMETRY_DEVICE_NAME, 376 - .id = -1, 377 - .res = telemetry_res, 378 - .num_res = ARRAY_SIZE(telemetry_res), 379 - }; 380 - 381 - res = telemetry_res + TELEMETRY_RESOURCE_PUNIT_SSRAM; 382 - res->start = ipcdev.telem_punit_ssram_base; 383 - res->end = res->start + ipcdev.telem_punit_ssram_size - 1; 384 - 385 - res = telemetry_res + TELEMETRY_RESOURCE_PMC_SSRAM; 386 - res->start = ipcdev.telem_pmc_ssram_base; 387 - res->end = res->start + ipcdev.telem_pmc_ssram_size - 1; 388 - 389 - pdev = platform_device_register_full(&pdevinfo); 390 - if (IS_ERR(pdev)) 391 - return PTR_ERR(pdev); 392 - 393 - ipcdev.telemetry_dev = pdev; 394 - 395 - return 0; 396 - } 397 - 398 - static int ipc_create_pmc_devices(void) 399 - { 400 - int ret; 401 - 402 - /* If we have ACPI based watchdog use that instead */ 403 - if (!acpi_has_watchdog()) { 404 - ret = ipc_create_tco_device(); 405 - if (ret) { 406 - dev_err(ipcdev.dev, "Failed to add tco platform device\n"); 407 - return ret; 408 - } 409 - } 410 - 411 - ret = ipc_create_punit_device(); 412 - if (ret) { 413 - dev_err(ipcdev.dev, "Failed to add punit platform device\n"); 414 - platform_device_unregister(ipcdev.tco_dev); 415 - return ret; 416 - } 417 - 418 - if (!ipcdev.telem_res_inval) { 419 - ret = ipc_create_telemetry_device(); 420 - if (ret) { 421 - dev_warn(ipcdev.dev, 422 - "Failed to add telemetry platform device\n"); 423 - platform_device_unregister(ipcdev.punit_dev); 424 - platform_device_unregister(ipcdev.tco_dev); 425 - } 426 - } 427 - 428 - return ret; 429 - } 430 - 431 - static int ipc_plat_get_res(struct platform_device *pdev, 432 - struct intel_scu_ipc_data *scu_data) 433 - { 434 - struct resource *res, *punit_res = punit_res_array; 435 - resource_size_t start; 436 - void __iomem *addr; 437 - int size; 438 - 439 - res = platform_get_resource(pdev, IORESOURCE_IO, 440 - PLAT_RESOURCE_ACPI_IO_INDEX); 441 - if (!res) { 442 - dev_err(&pdev->dev, "Failed to get io resource\n"); 443 - return -ENXIO; 444 - } 445 - size = resource_size(res); 446 - ipcdev.acpi_io_base = res->start; 447 - ipcdev.acpi_io_size = size; 448 - dev_info(&pdev->dev, "io res: %pR\n", res); 449 - 450 - ipcdev.punit_res_count = 0; 451 - 452 - /* This is index 0 to cover BIOS data register */ 453 - res = platform_get_resource(pdev, IORESOURCE_MEM, 454 - PLAT_RESOURCE_BIOS_DATA_INDEX); 455 - if (!res) { 456 - dev_err(&pdev->dev, "Failed to get res of punit BIOS data\n"); 457 - return -ENXIO; 458 - } 459 - punit_res[ipcdev.punit_res_count++] = *res; 460 - dev_info(&pdev->dev, "punit BIOS data res: %pR\n", res); 461 - 462 - /* This is index 1 to cover BIOS interface register */ 463 - res = platform_get_resource(pdev, IORESOURCE_MEM, 464 - PLAT_RESOURCE_BIOS_IFACE_INDEX); 465 - if (!res) { 466 - dev_err(&pdev->dev, "Failed to get res of punit BIOS iface\n"); 467 - return -ENXIO; 468 - } 469 - punit_res[ipcdev.punit_res_count++] = *res; 470 - dev_info(&pdev->dev, "punit BIOS interface res: %pR\n", res); 471 - 472 - /* This is index 2 to cover ISP data register, optional */ 473 - res = platform_get_resource(pdev, IORESOURCE_MEM, 474 - PLAT_RESOURCE_ISP_DATA_INDEX); 475 - if (res) { 476 - punit_res[ipcdev.punit_res_count++] = *res; 477 - dev_info(&pdev->dev, "punit ISP data res: %pR\n", res); 478 - } 479 - 480 - /* This is index 3 to cover ISP interface register, optional */ 481 - res = platform_get_resource(pdev, IORESOURCE_MEM, 482 - PLAT_RESOURCE_ISP_IFACE_INDEX); 483 - if (res) { 484 - punit_res[ipcdev.punit_res_count++] = *res; 485 - dev_info(&pdev->dev, "punit ISP interface res: %pR\n", res); 486 - } 487 - 488 - /* This is index 4 to cover GTD data register, optional */ 489 - res = platform_get_resource(pdev, IORESOURCE_MEM, 490 - PLAT_RESOURCE_GTD_DATA_INDEX); 491 - if (res) { 492 - punit_res[ipcdev.punit_res_count++] = *res; 493 - dev_info(&pdev->dev, "punit GTD data res: %pR\n", res); 494 - } 495 - 496 - /* This is index 5 to cover GTD interface register, optional */ 497 - res = platform_get_resource(pdev, IORESOURCE_MEM, 498 - PLAT_RESOURCE_GTD_IFACE_INDEX); 499 - if (res) { 500 - punit_res[ipcdev.punit_res_count++] = *res; 501 - dev_info(&pdev->dev, "punit GTD interface res: %pR\n", res); 502 - } 503 - 504 - scu_data->irq = platform_get_irq(pdev, 0); 505 - 506 - res = platform_get_resource(pdev, IORESOURCE_MEM, 507 - PLAT_RESOURCE_IPC_INDEX); 508 - if (!res) { 509 - dev_err(&pdev->dev, "Failed to get ipc resource\n"); 510 - return -ENXIO; 511 - } 512 - dev_info(&pdev->dev, "ipc res: %pR\n", res); 513 - 514 - scu_data->mem.flags = res->flags; 515 - scu_data->mem.start = res->start; 516 - scu_data->mem.end = res->start + PLAT_RESOURCE_IPC_SIZE - 1; 517 - 518 - start = res->start + PLAT_RESOURCE_GCR_OFFSET; 519 - if (!devm_request_mem_region(&pdev->dev, start, PLAT_RESOURCE_GCR_SIZE, 520 - "pmc_ipc_plat")) 521 - return -EBUSY; 522 - 523 - addr = devm_ioremap(&pdev->dev, start, PLAT_RESOURCE_GCR_SIZE); 524 - if (!addr) 525 - return -ENOMEM; 526 - 527 - ipcdev.gcr_mem_base = addr; 528 - 529 - ipcdev.telem_res_inval = 0; 530 - res = platform_get_resource(pdev, IORESOURCE_MEM, 531 - PLAT_RESOURCE_TELEM_SSRAM_INDEX); 532 - if (!res) { 533 - dev_err(&pdev->dev, "Failed to get telemetry ssram resource\n"); 534 - ipcdev.telem_res_inval = 1; 535 - } else { 536 - ipcdev.telem_punit_ssram_base = res->start + 537 - TELEM_PUNIT_SSRAM_OFFSET; 538 - ipcdev.telem_punit_ssram_size = TELEM_SSRAM_SIZE; 539 - ipcdev.telem_pmc_ssram_base = res->start + 540 - TELEM_PMC_SSRAM_OFFSET; 541 - ipcdev.telem_pmc_ssram_size = TELEM_SSRAM_SIZE; 542 - dev_info(&pdev->dev, "telemetry ssram res: %pR\n", res); 543 - } 544 - 545 - return 0; 546 - } 547 - 548 - /** 549 - * intel_pmc_s0ix_counter_read() - Read S0ix residency. 550 - * @data: Out param that contains current S0ix residency count. 551 - * 552 - * Return: an error code or 0 on success. 553 - */ 554 - int intel_pmc_s0ix_counter_read(u64 *data) 555 - { 556 - u64 deep, shlw; 557 - 558 - if (!ipcdev.has_gcr_regs) 559 - return -EACCES; 560 - 561 - deep = gcr_data_readq(PMC_GCR_TELEM_DEEP_S0IX_REG); 562 - shlw = gcr_data_readq(PMC_GCR_TELEM_SHLW_S0IX_REG); 563 - 564 - *data = S0IX_RESIDENCY_IN_USECS(deep, shlw); 565 - 566 - return 0; 567 - } 568 - EXPORT_SYMBOL_GPL(intel_pmc_s0ix_counter_read); 569 - 570 - #ifdef CONFIG_ACPI 571 - static const struct acpi_device_id ipc_acpi_ids[] = { 572 - { "INT34D2", 0}, 573 - { } 574 - }; 575 - MODULE_DEVICE_TABLE(acpi, ipc_acpi_ids); 576 - #endif 577 - 578 - static int ipc_plat_probe(struct platform_device *pdev) 579 - { 580 - struct intel_scu_ipc_data scu_data = {}; 581 - struct intel_scu_ipc_dev *scu; 582 - int ret; 583 - 584 - ipcdev.dev = &pdev->dev; 585 - spin_lock_init(&ipcdev.gcr_lock); 586 - 587 - ret = ipc_plat_get_res(pdev, &scu_data); 588 - if (ret) { 589 - dev_err(&pdev->dev, "Failed to request resource\n"); 590 - return ret; 591 - } 592 - 593 - scu = devm_intel_scu_ipc_register(&pdev->dev, &scu_data); 594 - if (IS_ERR(scu)) 595 - return PTR_ERR(scu); 596 - 597 - platform_set_drvdata(pdev, scu); 598 - 599 - ret = ipc_create_pmc_devices(); 600 - if (ret) { 601 - dev_err(&pdev->dev, "Failed to create pmc devices\n"); 602 - return ret; 603 - } 604 - 605 - ipcdev.has_gcr_regs = true; 606 - 607 - return 0; 608 - } 609 - 610 - static int ipc_plat_remove(struct platform_device *pdev) 611 - { 612 - platform_device_unregister(ipcdev.tco_dev); 613 - platform_device_unregister(ipcdev.punit_dev); 614 - platform_device_unregister(ipcdev.telemetry_dev); 615 - ipcdev.dev = NULL; 616 - return 0; 617 - } 618 - 619 - static struct platform_driver ipc_plat_driver = { 620 - .remove = ipc_plat_remove, 621 - .probe = ipc_plat_probe, 622 - .driver = { 623 - .name = "pmc-ipc-plat", 624 - .acpi_match_table = ACPI_PTR(ipc_acpi_ids), 625 - .dev_groups = intel_ipc_groups, 626 - }, 627 - }; 628 - 629 - static int __init intel_pmc_ipc_init(void) 630 - { 631 - return platform_driver_register(&ipc_plat_driver); 632 - } 633 - 634 - static void __exit intel_pmc_ipc_exit(void) 635 - { 636 - platform_driver_unregister(&ipc_plat_driver); 637 - } 638 - 639 - MODULE_AUTHOR("Zha Qipeng <qipeng.zha@intel.com>"); 640 - MODULE_DESCRIPTION("Intel PMC IPC driver"); 641 - MODULE_LICENSE("GPL v2"); 642 - 643 - /* Some modules are dependent on this, so init earlier */ 644 - fs_initcall(intel_pmc_ipc_init); 645 - module_exit(intel_pmc_ipc_exit);
+8 -4
drivers/platform/x86/intel_telemetry_debugfs.c
··· 15 15 */ 16 16 #include <linux/debugfs.h> 17 17 #include <linux/device.h> 18 + #include <linux/mfd/intel_pmc_bxt.h> 18 19 #include <linux/module.h> 19 20 #include <linux/pci.h> 20 21 #include <linux/seq_file.h> ··· 23 22 24 23 #include <asm/cpu_device_id.h> 25 24 #include <asm/intel-family.h> 26 - #include <asm/intel_pmc_ipc.h> 27 25 #include <asm/intel_telemetry.h> 28 26 29 27 #define DRIVER_NAME "telemetry_soc_debugfs" ··· 647 647 648 648 static int telem_s0ix_res_get(void *data, u64 *val) 649 649 { 650 + struct telemetry_plt_config *plt_config = telemetry_get_pltdata(); 650 651 u64 s0ix_total_res; 651 652 int ret; 652 653 653 - ret = intel_pmc_s0ix_counter_read(&s0ix_total_res); 654 + ret = intel_pmc_s0ix_counter_read(plt_config->pmc, &s0ix_total_res); 654 655 if (ret) { 655 656 pr_err("Failed to read S0ix residency"); 656 657 return ret; ··· 838 837 */ 839 838 if (suspend_shlw_ctr_exit == suspend_shlw_ctr_temp && 840 839 suspend_deep_ctr_exit == suspend_deep_ctr_temp) { 841 - ret = intel_pmc_gcr_read64(PMC_GCR_TELEM_SHLW_S0IX_REG, 840 + struct telemetry_plt_config *plt_config = telemetry_get_pltdata(); 841 + struct intel_pmc_dev *pmc = plt_config->pmc; 842 + 843 + ret = intel_pmc_gcr_read64(pmc, PMC_GCR_TELEM_SHLW_S0IX_REG, 842 844 &suspend_shlw_res_exit); 843 845 if (ret < 0) 844 846 goto out; 845 847 846 - ret = intel_pmc_gcr_read64(PMC_GCR_TELEM_DEEP_S0IX_REG, 848 + ret = intel_pmc_gcr_read64(pmc, PMC_GCR_TELEM_DEEP_S0IX_REG, 847 849 &suspend_deep_res_exit); 848 850 if (ret < 0) 849 851 goto out;
+2
drivers/platform/x86/intel_telemetry_pltdrv.c
··· 1115 1115 1116 1116 telm_conf = (struct telemetry_plt_config *)id->driver_data; 1117 1117 1118 + telm_conf->pmc = dev_get_drvdata(pdev->dev.parent); 1119 + 1118 1120 mem = devm_platform_ioremap_resource(pdev, 0); 1119 1121 if (IS_ERR(mem)) 1120 1122 return PTR_ERR(mem);
+1 -1
drivers/usb/typec/tcpm/Kconfig
··· 41 41 config TYPEC_WCOVE 42 42 tristate "Intel WhiskeyCove PMIC USB Type-C PHY driver" 43 43 depends on ACPI 44 + depends on MFD_INTEL_PMC_BXT 44 45 depends on INTEL_SOC_PMIC 45 - depends on INTEL_PMC_IPC 46 46 depends on BXT_WC_PMIC_OPREGION 47 47 help 48 48 This driver adds support for USB Type-C on Intel Broxton platforms
+20 -7
drivers/watchdog/iTCO_wdt.c
··· 64 64 #include <linux/uaccess.h> /* For copy_to_user/put_user/... */ 65 65 #include <linux/io.h> /* For inb/outb/... */ 66 66 #include <linux/platform_data/itco_wdt.h> 67 + #include <linux/mfd/intel_pmc_bxt.h> 67 68 68 69 #include "iTCO_vendor.h" 69 70 ··· 234 233 return val != newval ? -EIO : 0; 235 234 } 236 235 237 - static void iTCO_wdt_no_reboot_bit_setup(struct iTCO_wdt_private *p, 238 - struct itco_wdt_platform_data *pdata) 236 + static int update_no_reboot_bit_pmc(void *priv, bool set) 239 237 { 240 - if (pdata->update_no_reboot_bit) { 241 - p->update_no_reboot_bit = pdata->update_no_reboot_bit; 242 - p->no_reboot_priv = pdata->no_reboot_priv; 238 + struct intel_pmc_dev *pmc = priv; 239 + u32 bits = PMC_CFG_NO_REBOOT_EN; 240 + u32 value = set ? bits : 0; 241 + 242 + return intel_pmc_gcr_update(pmc, PMC_GCR_PMC_CFG_REG, bits, value); 243 + } 244 + 245 + static void iTCO_wdt_no_reboot_bit_setup(struct iTCO_wdt_private *p, 246 + struct platform_device *pdev, 247 + struct itco_wdt_platform_data *pdata) 248 + { 249 + if (pdata->no_reboot_use_pmc) { 250 + struct intel_pmc_dev *pmc = dev_get_drvdata(pdev->dev.parent); 251 + 252 + p->update_no_reboot_bit = update_no_reboot_bit_pmc; 253 + p->no_reboot_priv = pmc; 243 254 return; 244 255 } 245 256 ··· 491 478 return -ENODEV; 492 479 } 493 480 494 - iTCO_wdt_no_reboot_bit_setup(p, pdata); 481 + iTCO_wdt_no_reboot_bit_setup(p, pdev, pdata); 495 482 496 483 /* 497 484 * Get the Memory-Mapped GCS or PMC register, we need it for the 498 485 * NO_REBOOT flag (TCO v2 and v3). 499 486 */ 500 487 if (p->iTCO_version >= 2 && p->iTCO_version < 6 && 501 - !pdata->update_no_reboot_bit) { 488 + !pdata->no_reboot_use_pmc) { 502 489 p->gcs_pmc_res = platform_get_resource(pdev, 503 490 IORESOURCE_MEM, 504 491 ICH_RES_MEM_GCS_PMC);
+53
include/linux/mfd/intel_pmc_bxt.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + #ifndef MFD_INTEL_PMC_BXT_H 3 + #define MFD_INTEL_PMC_BXT_H 4 + 5 + /* GCR reg offsets from GCR base */ 6 + #define PMC_GCR_PMC_CFG_REG 0x08 7 + #define PMC_GCR_TELEM_DEEP_S0IX_REG 0x78 8 + #define PMC_GCR_TELEM_SHLW_S0IX_REG 0x80 9 + 10 + /* PMC_CFG_REG bit masks */ 11 + #define PMC_CFG_NO_REBOOT_EN BIT(4) 12 + 13 + /** 14 + * struct intel_pmc_dev - Intel PMC device structure 15 + * @dev: Pointer to the parent PMC device 16 + * @scu: Pointer to the SCU IPC device data structure 17 + * @gcr_mem_base: Virtual base address of GCR (Global Configuration Registers) 18 + * @gcr_lock: Lock used to serialize access to GCR registers 19 + * @telem_base: Pointer to telemetry SSRAM base resource or %NULL if not 20 + * available 21 + */ 22 + struct intel_pmc_dev { 23 + struct device *dev; 24 + struct intel_scu_ipc_dev *scu; 25 + void __iomem *gcr_mem_base; 26 + spinlock_t gcr_lock; 27 + struct resource *telem_base; 28 + }; 29 + 30 + #if IS_ENABLED(CONFIG_MFD_INTEL_PMC_BXT) 31 + int intel_pmc_gcr_read64(struct intel_pmc_dev *pmc, u32 offset, u64 *data); 32 + int intel_pmc_gcr_update(struct intel_pmc_dev *pmc, u32 offset, u32 mask, u32 val); 33 + int intel_pmc_s0ix_counter_read(struct intel_pmc_dev *pmc, u64 *data); 34 + #else 35 + static inline int intel_pmc_gcr_read64(struct intel_pmc_dev *pmc, u32 offset, 36 + u64 *data) 37 + { 38 + return -ENOTSUPP; 39 + } 40 + 41 + static inline int intel_pmc_gcr_update(struct intel_pmc_dev *pmc, u32 offset, 42 + u32 mask, u32 val) 43 + { 44 + return -ENOTSUPP; 45 + } 46 + 47 + static inline int intel_pmc_s0ix_counter_read(struct intel_pmc_dev *pmc, u64 *data) 48 + { 49 + return -ENOTSUPP; 50 + } 51 + #endif 52 + 53 + #endif /* MFD_INTEL_PMC_BXT_H */
+7 -4
include/linux/platform_data/itco_wdt.h
··· 12 12 #define ICH_RES_MEM_OFF 2 13 13 #define ICH_RES_MEM_GCS_PMC 0 14 14 15 + /** 16 + * struct itco_wdt_platform_data - iTCO_wdt platform data 17 + * @name: Name of the platform 18 + * @version: iTCO version 19 + * @no_reboot_use_pmc: Use PMC BXT API to set and clear NO_REBOOT bit 20 + */ 15 21 struct itco_wdt_platform_data { 16 22 char name[32]; 17 23 unsigned int version; 18 - /* private data to be passed to update_no_reboot_bit API */ 19 - void *no_reboot_priv; 20 - /* pointer for platform specific no reboot update function */ 21 - int (*update_no_reboot_bit)(void *priv, bool set); 24 + bool no_reboot_use_pmc; 22 25 }; 23 26 24 27 #endif /* _ITCO_WDT_H_ */