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

Configure Feed

Select the types of activity you want to include in your feed.

at v4.11-rc8 924 lines 22 kB view raw
1/* 2 * intel_pmc_ipc.c: Driver for the Intel PMC IPC mechanism 3 * 4 * (C) Copyright 2014-2015 Intel Corporation 5 * 6 * This driver is based on Intel SCU IPC driver(intel_scu_opc.c) by 7 * Sreedhara DS <sreedhara.ds@intel.com> 8 * 9 * This program is free software; you can redistribute it and/or 10 * modify it under the terms of the GNU General Public License 11 * as published by the Free Software Foundation; version 2 12 * of the License. 13 * 14 * PMC running in ARC processor communicates with other entity running in IA 15 * core through IPC mechanism which in turn messaging between IA core ad PMC. 16 */ 17 18#include <linux/module.h> 19#include <linux/delay.h> 20#include <linux/errno.h> 21#include <linux/init.h> 22#include <linux/device.h> 23#include <linux/pm.h> 24#include <linux/pci.h> 25#include <linux/platform_device.h> 26#include <linux/interrupt.h> 27#include <linux/pm_qos.h> 28#include <linux/kernel.h> 29#include <linux/bitops.h> 30#include <linux/sched.h> 31#include <linux/atomic.h> 32#include <linux/notifier.h> 33#include <linux/suspend.h> 34#include <linux/acpi.h> 35#include <linux/io-64-nonatomic-lo-hi.h> 36 37#include <asm/intel_pmc_ipc.h> 38 39#include <linux/platform_data/itco_wdt.h> 40 41/* 42 * IPC registers 43 * The IA write to IPC_CMD command register triggers an interrupt to the ARC, 44 * The ARC handles the interrupt and services it, writing optional data to 45 * the IPC1 registers, updates the IPC_STS response register with the status. 46 */ 47#define IPC_CMD 0x0 48#define IPC_CMD_MSI 0x100 49#define IPC_CMD_SIZE 16 50#define IPC_CMD_SUBCMD 12 51#define IPC_STATUS 0x04 52#define IPC_STATUS_IRQ 0x4 53#define IPC_STATUS_ERR 0x2 54#define IPC_STATUS_BUSY 0x1 55#define IPC_SPTR 0x08 56#define IPC_DPTR 0x0C 57#define IPC_WRITE_BUFFER 0x80 58#define IPC_READ_BUFFER 0x90 59 60/* PMC Global Control Registers */ 61#define GCR_TELEM_DEEP_S0IX_OFFSET 0x1078 62#define GCR_TELEM_SHLW_S0IX_OFFSET 0x1080 63 64/* Residency with clock rate at 19.2MHz to usecs */ 65#define S0IX_RESIDENCY_IN_USECS(d, s) \ 66({ \ 67 u64 result = 10ull * ((d) + (s)); \ 68 do_div(result, 192); \ 69 result; \ 70}) 71 72/* 73 * 16-byte buffer for sending data associated with IPC command. 74 */ 75#define IPC_DATA_BUFFER_SIZE 16 76 77#define IPC_LOOP_CNT 3000000 78#define IPC_MAX_SEC 3 79 80#define IPC_TRIGGER_MODE_IRQ true 81 82/* exported resources from IFWI */ 83#define PLAT_RESOURCE_IPC_INDEX 0 84#define PLAT_RESOURCE_IPC_SIZE 0x1000 85#define PLAT_RESOURCE_GCR_OFFSET 0x1008 86#define PLAT_RESOURCE_GCR_SIZE 0x1000 87#define PLAT_RESOURCE_BIOS_DATA_INDEX 1 88#define PLAT_RESOURCE_BIOS_IFACE_INDEX 2 89#define PLAT_RESOURCE_TELEM_SSRAM_INDEX 3 90#define PLAT_RESOURCE_ISP_DATA_INDEX 4 91#define PLAT_RESOURCE_ISP_IFACE_INDEX 5 92#define PLAT_RESOURCE_GTD_DATA_INDEX 6 93#define PLAT_RESOURCE_GTD_IFACE_INDEX 7 94#define PLAT_RESOURCE_ACPI_IO_INDEX 0 95 96/* 97 * BIOS does not create an ACPI device for each PMC function, 98 * but exports multiple resources from one ACPI device(IPC) for 99 * multiple functions. This driver is responsible to create a 100 * platform device and to export resources for those functions. 101 */ 102#define TCO_DEVICE_NAME "iTCO_wdt" 103#define SMI_EN_OFFSET 0x40 104#define SMI_EN_SIZE 4 105#define TCO_BASE_OFFSET 0x60 106#define TCO_REGS_SIZE 16 107#define PUNIT_DEVICE_NAME "intel_punit_ipc" 108#define TELEMETRY_DEVICE_NAME "intel_telemetry" 109#define TELEM_SSRAM_SIZE 240 110#define TELEM_PMC_SSRAM_OFFSET 0x1B00 111#define TELEM_PUNIT_SSRAM_OFFSET 0x1A00 112#define TCO_PMC_OFFSET 0x8 113#define TCO_PMC_SIZE 0x4 114 115static struct intel_pmc_ipc_dev { 116 struct device *dev; 117 void __iomem *ipc_base; 118 bool irq_mode; 119 int irq; 120 int cmd; 121 struct completion cmd_complete; 122 123 /* The following PMC BARs share the same ACPI device with the IPC */ 124 resource_size_t acpi_io_base; 125 int acpi_io_size; 126 struct platform_device *tco_dev; 127 128 /* gcr */ 129 resource_size_t gcr_base; 130 int gcr_size; 131 bool has_gcr_regs; 132 133 /* punit */ 134 struct platform_device *punit_dev; 135 136 /* Telemetry */ 137 resource_size_t telem_pmc_ssram_base; 138 resource_size_t telem_punit_ssram_base; 139 int telem_pmc_ssram_size; 140 int telem_punit_ssram_size; 141 u8 telem_res_inval; 142 struct platform_device *telemetry_dev; 143} ipcdev; 144 145static char *ipc_err_sources[] = { 146 [IPC_ERR_NONE] = 147 "no error", 148 [IPC_ERR_CMD_NOT_SUPPORTED] = 149 "command not supported", 150 [IPC_ERR_CMD_NOT_SERVICED] = 151 "command not serviced", 152 [IPC_ERR_UNABLE_TO_SERVICE] = 153 "unable to service", 154 [IPC_ERR_CMD_INVALID] = 155 "command invalid", 156 [IPC_ERR_CMD_FAILED] = 157 "command failed", 158 [IPC_ERR_EMSECURITY] = 159 "Invalid Battery", 160 [IPC_ERR_UNSIGNEDKERNEL] = 161 "Unsigned kernel", 162}; 163 164/* Prevent concurrent calls to the PMC */ 165static DEFINE_MUTEX(ipclock); 166 167static inline void ipc_send_command(u32 cmd) 168{ 169 ipcdev.cmd = cmd; 170 if (ipcdev.irq_mode) { 171 reinit_completion(&ipcdev.cmd_complete); 172 cmd |= IPC_CMD_MSI; 173 } 174 writel(cmd, ipcdev.ipc_base + IPC_CMD); 175} 176 177static inline u32 ipc_read_status(void) 178{ 179 return readl(ipcdev.ipc_base + IPC_STATUS); 180} 181 182static inline void ipc_data_writel(u32 data, u32 offset) 183{ 184 writel(data, ipcdev.ipc_base + IPC_WRITE_BUFFER + offset); 185} 186 187static inline u8 ipc_data_readb(u32 offset) 188{ 189 return readb(ipcdev.ipc_base + IPC_READ_BUFFER + offset); 190} 191 192static inline u32 ipc_data_readl(u32 offset) 193{ 194 return readl(ipcdev.ipc_base + IPC_READ_BUFFER + offset); 195} 196 197static inline u64 gcr_data_readq(u32 offset) 198{ 199 return readq(ipcdev.ipc_base + offset); 200} 201 202static int intel_pmc_ipc_check_status(void) 203{ 204 int status; 205 int ret = 0; 206 207 if (ipcdev.irq_mode) { 208 if (0 == wait_for_completion_timeout( 209 &ipcdev.cmd_complete, IPC_MAX_SEC * HZ)) 210 ret = -ETIMEDOUT; 211 } else { 212 int loop_count = IPC_LOOP_CNT; 213 214 while ((ipc_read_status() & IPC_STATUS_BUSY) && --loop_count) 215 udelay(1); 216 if (loop_count == 0) 217 ret = -ETIMEDOUT; 218 } 219 220 status = ipc_read_status(); 221 if (ret == -ETIMEDOUT) { 222 dev_err(ipcdev.dev, 223 "IPC timed out, TS=0x%x, CMD=0x%x\n", 224 status, ipcdev.cmd); 225 return ret; 226 } 227 228 if (status & IPC_STATUS_ERR) { 229 int i; 230 231 ret = -EIO; 232 i = (status >> IPC_CMD_SIZE) & 0xFF; 233 if (i < ARRAY_SIZE(ipc_err_sources)) 234 dev_err(ipcdev.dev, 235 "IPC failed: %s, STS=0x%x, CMD=0x%x\n", 236 ipc_err_sources[i], status, ipcdev.cmd); 237 else 238 dev_err(ipcdev.dev, 239 "IPC failed: unknown, STS=0x%x, CMD=0x%x\n", 240 status, ipcdev.cmd); 241 if ((i == IPC_ERR_UNSIGNEDKERNEL) || (i == IPC_ERR_EMSECURITY)) 242 ret = -EACCES; 243 } 244 245 return ret; 246} 247 248/** 249 * intel_pmc_ipc_simple_command() - Simple IPC command 250 * @cmd: IPC command code. 251 * @sub: IPC command sub type. 252 * 253 * Send a simple IPC command to PMC when don't need to specify 254 * input/output data and source/dest pointers. 255 * 256 * Return: an IPC error code or 0 on success. 257 */ 258int intel_pmc_ipc_simple_command(int cmd, int sub) 259{ 260 int ret; 261 262 mutex_lock(&ipclock); 263 if (ipcdev.dev == NULL) { 264 mutex_unlock(&ipclock); 265 return -ENODEV; 266 } 267 ipc_send_command(sub << IPC_CMD_SUBCMD | cmd); 268 ret = intel_pmc_ipc_check_status(); 269 mutex_unlock(&ipclock); 270 271 return ret; 272} 273EXPORT_SYMBOL_GPL(intel_pmc_ipc_simple_command); 274 275/** 276 * intel_pmc_ipc_raw_cmd() - IPC command with data and pointers 277 * @cmd: IPC command code. 278 * @sub: IPC command sub type. 279 * @in: input data of this IPC command. 280 * @inlen: input data length in bytes. 281 * @out: output data of this IPC command. 282 * @outlen: output data length in dwords. 283 * @sptr: data writing to SPTR register. 284 * @dptr: data writing to DPTR register. 285 * 286 * Send an IPC command to PMC with input/output data and source/dest pointers. 287 * 288 * Return: an IPC error code or 0 on success. 289 */ 290int intel_pmc_ipc_raw_cmd(u32 cmd, u32 sub, u8 *in, u32 inlen, u32 *out, 291 u32 outlen, u32 dptr, u32 sptr) 292{ 293 u32 wbuf[4] = { 0 }; 294 int ret; 295 int i; 296 297 if (inlen > IPC_DATA_BUFFER_SIZE || outlen > IPC_DATA_BUFFER_SIZE / 4) 298 return -EINVAL; 299 300 mutex_lock(&ipclock); 301 if (ipcdev.dev == NULL) { 302 mutex_unlock(&ipclock); 303 return -ENODEV; 304 } 305 memcpy(wbuf, in, inlen); 306 writel(dptr, ipcdev.ipc_base + IPC_DPTR); 307 writel(sptr, ipcdev.ipc_base + IPC_SPTR); 308 /* The input data register is 32bit register and inlen is in Byte */ 309 for (i = 0; i < ((inlen + 3) / 4); i++) 310 ipc_data_writel(wbuf[i], 4 * i); 311 ipc_send_command((inlen << IPC_CMD_SIZE) | 312 (sub << IPC_CMD_SUBCMD) | cmd); 313 ret = intel_pmc_ipc_check_status(); 314 if (!ret) { 315 /* out is read from 32bit register and outlen is in 32bit */ 316 for (i = 0; i < outlen; i++) 317 *out++ = ipc_data_readl(4 * i); 318 } 319 mutex_unlock(&ipclock); 320 321 return ret; 322} 323EXPORT_SYMBOL_GPL(intel_pmc_ipc_raw_cmd); 324 325/** 326 * intel_pmc_ipc_command() - IPC command with input/output data 327 * @cmd: IPC command code. 328 * @sub: IPC command sub type. 329 * @in: input data of this IPC command. 330 * @inlen: input data length in bytes. 331 * @out: output data of this IPC command. 332 * @outlen: output data length in dwords. 333 * 334 * Send an IPC command to PMC with input/output data. 335 * 336 * Return: an IPC error code or 0 on success. 337 */ 338int intel_pmc_ipc_command(u32 cmd, u32 sub, u8 *in, u32 inlen, 339 u32 *out, u32 outlen) 340{ 341 return intel_pmc_ipc_raw_cmd(cmd, sub, in, inlen, out, outlen, 0, 0); 342} 343EXPORT_SYMBOL_GPL(intel_pmc_ipc_command); 344 345static irqreturn_t ioc(int irq, void *dev_id) 346{ 347 int status; 348 349 if (ipcdev.irq_mode) { 350 status = ipc_read_status(); 351 writel(status | IPC_STATUS_IRQ, ipcdev.ipc_base + IPC_STATUS); 352 } 353 complete(&ipcdev.cmd_complete); 354 355 return IRQ_HANDLED; 356} 357 358static int ipc_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) 359{ 360 resource_size_t pci_resource; 361 int ret; 362 int len; 363 364 ipcdev.dev = &pci_dev_get(pdev)->dev; 365 ipcdev.irq_mode = IPC_TRIGGER_MODE_IRQ; 366 367 ret = pci_enable_device(pdev); 368 if (ret) 369 return ret; 370 371 ret = pci_request_regions(pdev, "intel_pmc_ipc"); 372 if (ret) 373 return ret; 374 375 pci_resource = pci_resource_start(pdev, 0); 376 len = pci_resource_len(pdev, 0); 377 if (!pci_resource || !len) { 378 dev_err(&pdev->dev, "Failed to get resource\n"); 379 return -ENOMEM; 380 } 381 382 init_completion(&ipcdev.cmd_complete); 383 384 if (request_irq(pdev->irq, ioc, 0, "intel_pmc_ipc", &ipcdev)) { 385 dev_err(&pdev->dev, "Failed to request irq\n"); 386 return -EBUSY; 387 } 388 389 ipcdev.ipc_base = ioremap_nocache(pci_resource, len); 390 if (!ipcdev.ipc_base) { 391 dev_err(&pdev->dev, "Failed to ioremap ipc base\n"); 392 free_irq(pdev->irq, &ipcdev); 393 ret = -ENOMEM; 394 } 395 396 return ret; 397} 398 399static void ipc_pci_remove(struct pci_dev *pdev) 400{ 401 free_irq(pdev->irq, &ipcdev); 402 pci_release_regions(pdev); 403 pci_dev_put(pdev); 404 iounmap(ipcdev.ipc_base); 405 ipcdev.dev = NULL; 406} 407 408static const struct pci_device_id ipc_pci_ids[] = { 409 {PCI_VDEVICE(INTEL, 0x0a94), 0}, 410 {PCI_VDEVICE(INTEL, 0x1a94), 0}, 411 {PCI_VDEVICE(INTEL, 0x5a94), 0}, 412 { 0,} 413}; 414MODULE_DEVICE_TABLE(pci, ipc_pci_ids); 415 416static struct pci_driver ipc_pci_driver = { 417 .name = "intel_pmc_ipc", 418 .id_table = ipc_pci_ids, 419 .probe = ipc_pci_probe, 420 .remove = ipc_pci_remove, 421}; 422 423static ssize_t intel_pmc_ipc_simple_cmd_store(struct device *dev, 424 struct device_attribute *attr, 425 const char *buf, size_t count) 426{ 427 int subcmd; 428 int cmd; 429 int ret; 430 431 ret = sscanf(buf, "%d %d", &cmd, &subcmd); 432 if (ret != 2) { 433 dev_err(dev, "Error args\n"); 434 return -EINVAL; 435 } 436 437 ret = intel_pmc_ipc_simple_command(cmd, subcmd); 438 if (ret) { 439 dev_err(dev, "command %d error with %d\n", cmd, ret); 440 return ret; 441 } 442 return (ssize_t)count; 443} 444 445static ssize_t intel_pmc_ipc_northpeak_store(struct device *dev, 446 struct device_attribute *attr, 447 const char *buf, size_t count) 448{ 449 unsigned long val; 450 int subcmd; 451 int ret; 452 453 if (kstrtoul(buf, 0, &val)) 454 return -EINVAL; 455 456 if (val) 457 subcmd = 1; 458 else 459 subcmd = 0; 460 ret = intel_pmc_ipc_simple_command(PMC_IPC_NORTHPEAK_CTRL, subcmd); 461 if (ret) { 462 dev_err(dev, "command north %d error with %d\n", subcmd, ret); 463 return ret; 464 } 465 return (ssize_t)count; 466} 467 468static DEVICE_ATTR(simplecmd, S_IWUSR, 469 NULL, intel_pmc_ipc_simple_cmd_store); 470static DEVICE_ATTR(northpeak, S_IWUSR, 471 NULL, intel_pmc_ipc_northpeak_store); 472 473static struct attribute *intel_ipc_attrs[] = { 474 &dev_attr_northpeak.attr, 475 &dev_attr_simplecmd.attr, 476 NULL 477}; 478 479static const struct attribute_group intel_ipc_group = { 480 .attrs = intel_ipc_attrs, 481}; 482 483static struct resource punit_res_array[] = { 484 /* Punit BIOS */ 485 { 486 .flags = IORESOURCE_MEM, 487 }, 488 { 489 .flags = IORESOURCE_MEM, 490 }, 491 /* Punit ISP */ 492 { 493 .flags = IORESOURCE_MEM, 494 }, 495 { 496 .flags = IORESOURCE_MEM, 497 }, 498 /* Punit GTD */ 499 { 500 .flags = IORESOURCE_MEM, 501 }, 502 { 503 .flags = IORESOURCE_MEM, 504 }, 505}; 506 507#define TCO_RESOURCE_ACPI_IO 0 508#define TCO_RESOURCE_SMI_EN_IO 1 509#define TCO_RESOURCE_GCR_MEM 2 510static struct resource tco_res[] = { 511 /* ACPI - TCO */ 512 { 513 .flags = IORESOURCE_IO, 514 }, 515 /* ACPI - SMI */ 516 { 517 .flags = IORESOURCE_IO, 518 }, 519 /* GCS */ 520 { 521 .flags = IORESOURCE_MEM, 522 }, 523}; 524 525static struct itco_wdt_platform_data tco_info = { 526 .name = "Apollo Lake SoC", 527 .version = 5, 528}; 529 530#define TELEMETRY_RESOURCE_PUNIT_SSRAM 0 531#define TELEMETRY_RESOURCE_PMC_SSRAM 1 532static struct resource telemetry_res[] = { 533 /*Telemetry*/ 534 { 535 .flags = IORESOURCE_MEM, 536 }, 537 { 538 .flags = IORESOURCE_MEM, 539 }, 540}; 541 542static int ipc_create_punit_device(void) 543{ 544 struct platform_device *pdev; 545 const struct platform_device_info pdevinfo = { 546 .parent = ipcdev.dev, 547 .name = PUNIT_DEVICE_NAME, 548 .id = -1, 549 .res = punit_res_array, 550 .num_res = ARRAY_SIZE(punit_res_array), 551 }; 552 553 pdev = platform_device_register_full(&pdevinfo); 554 if (IS_ERR(pdev)) 555 return PTR_ERR(pdev); 556 557 ipcdev.punit_dev = pdev; 558 559 return 0; 560} 561 562static int ipc_create_tco_device(void) 563{ 564 struct platform_device *pdev; 565 struct resource *res; 566 const struct platform_device_info pdevinfo = { 567 .parent = ipcdev.dev, 568 .name = TCO_DEVICE_NAME, 569 .id = -1, 570 .res = tco_res, 571 .num_res = ARRAY_SIZE(tco_res), 572 .data = &tco_info, 573 .size_data = sizeof(tco_info), 574 }; 575 576 res = tco_res + TCO_RESOURCE_ACPI_IO; 577 res->start = ipcdev.acpi_io_base + TCO_BASE_OFFSET; 578 res->end = res->start + TCO_REGS_SIZE - 1; 579 580 res = tco_res + TCO_RESOURCE_SMI_EN_IO; 581 res->start = ipcdev.acpi_io_base + SMI_EN_OFFSET; 582 res->end = res->start + SMI_EN_SIZE - 1; 583 584 res = tco_res + TCO_RESOURCE_GCR_MEM; 585 res->start = ipcdev.gcr_base + TCO_PMC_OFFSET; 586 res->end = res->start + TCO_PMC_SIZE - 1; 587 588 pdev = platform_device_register_full(&pdevinfo); 589 if (IS_ERR(pdev)) 590 return PTR_ERR(pdev); 591 592 ipcdev.tco_dev = pdev; 593 594 return 0; 595} 596 597static int ipc_create_telemetry_device(void) 598{ 599 struct platform_device *pdev; 600 struct resource *res; 601 const struct platform_device_info pdevinfo = { 602 .parent = ipcdev.dev, 603 .name = TELEMETRY_DEVICE_NAME, 604 .id = -1, 605 .res = telemetry_res, 606 .num_res = ARRAY_SIZE(telemetry_res), 607 }; 608 609 res = telemetry_res + TELEMETRY_RESOURCE_PUNIT_SSRAM; 610 res->start = ipcdev.telem_punit_ssram_base; 611 res->end = res->start + ipcdev.telem_punit_ssram_size - 1; 612 613 res = telemetry_res + TELEMETRY_RESOURCE_PMC_SSRAM; 614 res->start = ipcdev.telem_pmc_ssram_base; 615 res->end = res->start + ipcdev.telem_pmc_ssram_size - 1; 616 617 pdev = platform_device_register_full(&pdevinfo); 618 if (IS_ERR(pdev)) 619 return PTR_ERR(pdev); 620 621 ipcdev.telemetry_dev = pdev; 622 623 return 0; 624} 625 626static int ipc_create_pmc_devices(void) 627{ 628 int ret; 629 630 /* If we have ACPI based watchdog use that instead */ 631 if (!acpi_has_watchdog()) { 632 ret = ipc_create_tco_device(); 633 if (ret) { 634 dev_err(ipcdev.dev, "Failed to add tco platform device\n"); 635 return ret; 636 } 637 } 638 639 ret = ipc_create_punit_device(); 640 if (ret) { 641 dev_err(ipcdev.dev, "Failed to add punit platform device\n"); 642 platform_device_unregister(ipcdev.tco_dev); 643 } 644 645 if (!ipcdev.telem_res_inval) { 646 ret = ipc_create_telemetry_device(); 647 if (ret) 648 dev_warn(ipcdev.dev, 649 "Failed to add telemetry platform device\n"); 650 } 651 652 return ret; 653} 654 655static int ipc_plat_get_res(struct platform_device *pdev) 656{ 657 struct resource *res, *punit_res; 658 void __iomem *addr; 659 int size; 660 661 res = platform_get_resource(pdev, IORESOURCE_IO, 662 PLAT_RESOURCE_ACPI_IO_INDEX); 663 if (!res) { 664 dev_err(&pdev->dev, "Failed to get io resource\n"); 665 return -ENXIO; 666 } 667 size = resource_size(res); 668 ipcdev.acpi_io_base = res->start; 669 ipcdev.acpi_io_size = size; 670 dev_info(&pdev->dev, "io res: %pR\n", res); 671 672 punit_res = punit_res_array; 673 /* This is index 0 to cover BIOS data register */ 674 res = platform_get_resource(pdev, IORESOURCE_MEM, 675 PLAT_RESOURCE_BIOS_DATA_INDEX); 676 if (!res) { 677 dev_err(&pdev->dev, "Failed to get res of punit BIOS data\n"); 678 return -ENXIO; 679 } 680 *punit_res = *res; 681 dev_info(&pdev->dev, "punit BIOS data res: %pR\n", res); 682 683 /* This is index 1 to cover BIOS interface register */ 684 res = platform_get_resource(pdev, IORESOURCE_MEM, 685 PLAT_RESOURCE_BIOS_IFACE_INDEX); 686 if (!res) { 687 dev_err(&pdev->dev, "Failed to get res of punit BIOS iface\n"); 688 return -ENXIO; 689 } 690 *++punit_res = *res; 691 dev_info(&pdev->dev, "punit BIOS interface res: %pR\n", res); 692 693 /* This is index 2 to cover ISP data register, optional */ 694 res = platform_get_resource(pdev, IORESOURCE_MEM, 695 PLAT_RESOURCE_ISP_DATA_INDEX); 696 ++punit_res; 697 if (res) { 698 *punit_res = *res; 699 dev_info(&pdev->dev, "punit ISP data res: %pR\n", res); 700 } 701 702 /* This is index 3 to cover ISP interface register, optional */ 703 res = platform_get_resource(pdev, IORESOURCE_MEM, 704 PLAT_RESOURCE_ISP_IFACE_INDEX); 705 ++punit_res; 706 if (res) { 707 *punit_res = *res; 708 dev_info(&pdev->dev, "punit ISP interface res: %pR\n", res); 709 } 710 711 /* This is index 4 to cover GTD data register, optional */ 712 res = platform_get_resource(pdev, IORESOURCE_MEM, 713 PLAT_RESOURCE_GTD_DATA_INDEX); 714 ++punit_res; 715 if (res) { 716 *punit_res = *res; 717 dev_info(&pdev->dev, "punit GTD data res: %pR\n", res); 718 } 719 720 /* This is index 5 to cover GTD interface register, optional */ 721 res = platform_get_resource(pdev, IORESOURCE_MEM, 722 PLAT_RESOURCE_GTD_IFACE_INDEX); 723 ++punit_res; 724 if (res) { 725 *punit_res = *res; 726 dev_info(&pdev->dev, "punit GTD interface res: %pR\n", res); 727 } 728 729 res = platform_get_resource(pdev, IORESOURCE_MEM, 730 PLAT_RESOURCE_IPC_INDEX); 731 if (!res) { 732 dev_err(&pdev->dev, "Failed to get ipc resource\n"); 733 return -ENXIO; 734 } 735 size = PLAT_RESOURCE_IPC_SIZE + PLAT_RESOURCE_GCR_SIZE; 736 737 if (!request_mem_region(res->start, size, pdev->name)) { 738 dev_err(&pdev->dev, "Failed to request ipc resource\n"); 739 return -EBUSY; 740 } 741 addr = ioremap_nocache(res->start, size); 742 if (!addr) { 743 dev_err(&pdev->dev, "I/O memory remapping failed\n"); 744 release_mem_region(res->start, size); 745 return -ENOMEM; 746 } 747 ipcdev.ipc_base = addr; 748 749 ipcdev.gcr_base = res->start + PLAT_RESOURCE_GCR_OFFSET; 750 ipcdev.gcr_size = PLAT_RESOURCE_GCR_SIZE; 751 dev_info(&pdev->dev, "ipc res: %pR\n", res); 752 753 ipcdev.telem_res_inval = 0; 754 res = platform_get_resource(pdev, IORESOURCE_MEM, 755 PLAT_RESOURCE_TELEM_SSRAM_INDEX); 756 if (!res) { 757 dev_err(&pdev->dev, "Failed to get telemetry ssram resource\n"); 758 ipcdev.telem_res_inval = 1; 759 } else { 760 ipcdev.telem_punit_ssram_base = res->start + 761 TELEM_PUNIT_SSRAM_OFFSET; 762 ipcdev.telem_punit_ssram_size = TELEM_SSRAM_SIZE; 763 ipcdev.telem_pmc_ssram_base = res->start + 764 TELEM_PMC_SSRAM_OFFSET; 765 ipcdev.telem_pmc_ssram_size = TELEM_SSRAM_SIZE; 766 dev_info(&pdev->dev, "telemetry ssram res: %pR\n", res); 767 } 768 769 return 0; 770} 771 772/** 773 * intel_pmc_s0ix_counter_read() - Read S0ix residency. 774 * @data: Out param that contains current S0ix residency count. 775 * 776 * Return: an error code or 0 on success. 777 */ 778int intel_pmc_s0ix_counter_read(u64 *data) 779{ 780 u64 deep, shlw; 781 782 if (!ipcdev.has_gcr_regs) 783 return -EACCES; 784 785 deep = gcr_data_readq(GCR_TELEM_DEEP_S0IX_OFFSET); 786 shlw = gcr_data_readq(GCR_TELEM_SHLW_S0IX_OFFSET); 787 788 *data = S0IX_RESIDENCY_IN_USECS(deep, shlw); 789 790 return 0; 791} 792EXPORT_SYMBOL_GPL(intel_pmc_s0ix_counter_read); 793 794#ifdef CONFIG_ACPI 795static const struct acpi_device_id ipc_acpi_ids[] = { 796 { "INT34D2", 0}, 797 { } 798}; 799MODULE_DEVICE_TABLE(acpi, ipc_acpi_ids); 800#endif 801 802static int ipc_plat_probe(struct platform_device *pdev) 803{ 804 struct resource *res; 805 int ret; 806 807 ipcdev.dev = &pdev->dev; 808 ipcdev.irq_mode = IPC_TRIGGER_MODE_IRQ; 809 init_completion(&ipcdev.cmd_complete); 810 811 ipcdev.irq = platform_get_irq(pdev, 0); 812 if (ipcdev.irq < 0) { 813 dev_err(&pdev->dev, "Failed to get irq\n"); 814 return -EINVAL; 815 } 816 817 ret = ipc_plat_get_res(pdev); 818 if (ret) { 819 dev_err(&pdev->dev, "Failed to request resource\n"); 820 return ret; 821 } 822 823 ret = ipc_create_pmc_devices(); 824 if (ret) { 825 dev_err(&pdev->dev, "Failed to create pmc devices\n"); 826 goto err_device; 827 } 828 829 if (request_irq(ipcdev.irq, ioc, IRQF_NO_SUSPEND, 830 "intel_pmc_ipc", &ipcdev)) { 831 dev_err(&pdev->dev, "Failed to request irq\n"); 832 ret = -EBUSY; 833 goto err_irq; 834 } 835 836 ret = sysfs_create_group(&pdev->dev.kobj, &intel_ipc_group); 837 if (ret) { 838 dev_err(&pdev->dev, "Failed to create sysfs group %d\n", 839 ret); 840 goto err_sys; 841 } 842 843 ipcdev.has_gcr_regs = true; 844 845 return 0; 846err_sys: 847 free_irq(ipcdev.irq, &ipcdev); 848err_irq: 849 platform_device_unregister(ipcdev.tco_dev); 850 platform_device_unregister(ipcdev.punit_dev); 851 platform_device_unregister(ipcdev.telemetry_dev); 852err_device: 853 iounmap(ipcdev.ipc_base); 854 res = platform_get_resource(pdev, IORESOURCE_MEM, 855 PLAT_RESOURCE_IPC_INDEX); 856 if (res) { 857 release_mem_region(res->start, 858 PLAT_RESOURCE_IPC_SIZE + 859 PLAT_RESOURCE_GCR_SIZE); 860 } 861 return ret; 862} 863 864static int ipc_plat_remove(struct platform_device *pdev) 865{ 866 struct resource *res; 867 868 sysfs_remove_group(&pdev->dev.kobj, &intel_ipc_group); 869 free_irq(ipcdev.irq, &ipcdev); 870 platform_device_unregister(ipcdev.tco_dev); 871 platform_device_unregister(ipcdev.punit_dev); 872 platform_device_unregister(ipcdev.telemetry_dev); 873 iounmap(ipcdev.ipc_base); 874 res = platform_get_resource(pdev, IORESOURCE_MEM, 875 PLAT_RESOURCE_IPC_INDEX); 876 if (res) { 877 release_mem_region(res->start, 878 PLAT_RESOURCE_IPC_SIZE + 879 PLAT_RESOURCE_GCR_SIZE); 880 } 881 ipcdev.dev = NULL; 882 return 0; 883} 884 885static struct platform_driver ipc_plat_driver = { 886 .remove = ipc_plat_remove, 887 .probe = ipc_plat_probe, 888 .driver = { 889 .name = "pmc-ipc-plat", 890 .acpi_match_table = ACPI_PTR(ipc_acpi_ids), 891 }, 892}; 893 894static int __init intel_pmc_ipc_init(void) 895{ 896 int ret; 897 898 ret = platform_driver_register(&ipc_plat_driver); 899 if (ret) { 900 pr_err("Failed to register PMC ipc platform driver\n"); 901 return ret; 902 } 903 ret = pci_register_driver(&ipc_pci_driver); 904 if (ret) { 905 pr_err("Failed to register PMC ipc pci driver\n"); 906 platform_driver_unregister(&ipc_plat_driver); 907 return ret; 908 } 909 return ret; 910} 911 912static void __exit intel_pmc_ipc_exit(void) 913{ 914 pci_unregister_driver(&ipc_pci_driver); 915 platform_driver_unregister(&ipc_plat_driver); 916} 917 918MODULE_AUTHOR("Zha Qipeng <qipeng.zha@intel.com>"); 919MODULE_DESCRIPTION("Intel PMC IPC driver"); 920MODULE_LICENSE("GPL"); 921 922/* Some modules are dependent on this, so init earlier */ 923fs_initcall(intel_pmc_ipc_init); 924module_exit(intel_pmc_ipc_exit);