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