linux/drivers/platform/x86/intel_pmc_ipc.c
<<
>>
Prefs
   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        const struct platform_device_info pdevinfo = {
 526                .parent = ipcdev.dev,
 527                .name = PUNIT_DEVICE_NAME,
 528                .id = -1,
 529                .res = punit_res_array,
 530                .num_res = ARRAY_SIZE(punit_res_array),
 531                };
 532
 533        pdev = platform_device_register_full(&pdevinfo);
 534        if (IS_ERR(pdev))
 535                return PTR_ERR(pdev);
 536
 537        ipcdev.punit_dev = pdev;
 538
 539        return 0;
 540}
 541
 542static int ipc_create_tco_device(void)
 543{
 544        struct platform_device *pdev;
 545        struct resource *res;
 546        const struct platform_device_info pdevinfo = {
 547                .parent = ipcdev.dev,
 548                .name = TCO_DEVICE_NAME,
 549                .id = -1,
 550                .res = tco_res,
 551                .num_res = ARRAY_SIZE(tco_res),
 552                .data = &tco_info,
 553                .size_data = sizeof(tco_info),
 554                };
 555
 556        res = tco_res + TCO_RESOURCE_ACPI_IO;
 557        res->start = ipcdev.acpi_io_base + TCO_BASE_OFFSET;
 558        res->end = res->start + TCO_REGS_SIZE - 1;
 559
 560        res = tco_res + TCO_RESOURCE_SMI_EN_IO;
 561        res->start = ipcdev.acpi_io_base + SMI_EN_OFFSET;
 562        res->end = res->start + SMI_EN_SIZE - 1;
 563
 564        res = tco_res + TCO_RESOURCE_GCR_MEM;
 565        res->start = ipcdev.gcr_base + TCO_PMC_OFFSET;
 566        res->end = res->start + TCO_PMC_SIZE - 1;
 567
 568        pdev = platform_device_register_full(&pdevinfo);
 569        if (IS_ERR(pdev))
 570                return PTR_ERR(pdev);
 571
 572        ipcdev.tco_dev = pdev;
 573
 574        return 0;
 575}
 576
 577static int ipc_create_telemetry_device(void)
 578{
 579        struct platform_device *pdev;
 580        struct resource *res;
 581        const struct platform_device_info pdevinfo = {
 582                .parent = ipcdev.dev,
 583                .name = TELEMETRY_DEVICE_NAME,
 584                .id = -1,
 585                .res = telemetry_res,
 586                .num_res = ARRAY_SIZE(telemetry_res),
 587                };
 588
 589        res = telemetry_res + TELEMETRY_RESOURCE_PUNIT_SSRAM;
 590        res->start = ipcdev.telem_punit_ssram_base;
 591        res->end = res->start + ipcdev.telem_punit_ssram_size - 1;
 592
 593        res = telemetry_res + TELEMETRY_RESOURCE_PMC_SSRAM;
 594        res->start = ipcdev.telem_pmc_ssram_base;
 595        res->end = res->start + ipcdev.telem_pmc_ssram_size - 1;
 596
 597        pdev = platform_device_register_full(&pdevinfo);
 598        if (IS_ERR(pdev))
 599                return PTR_ERR(pdev);
 600
 601        ipcdev.telemetry_dev = pdev;
 602
 603        return 0;
 604}
 605
 606static int ipc_create_pmc_devices(void)
 607{
 608        int ret;
 609
 610        /* If we have ACPI based watchdog use that instead */
 611        if (!acpi_has_watchdog()) {
 612                ret = ipc_create_tco_device();
 613                if (ret) {
 614                        dev_err(ipcdev.dev, "Failed to add tco platform device\n");
 615                        return ret;
 616                }
 617        }
 618
 619        ret = ipc_create_punit_device();
 620        if (ret) {
 621                dev_err(ipcdev.dev, "Failed to add punit platform device\n");
 622                platform_device_unregister(ipcdev.tco_dev);
 623        }
 624
 625        if (!ipcdev.telem_res_inval) {
 626                ret = ipc_create_telemetry_device();
 627                if (ret)
 628                        dev_warn(ipcdev.dev,
 629                                "Failed to add telemetry platform device\n");
 630        }
 631
 632        return ret;
 633}
 634
 635static int ipc_plat_get_res(struct platform_device *pdev)
 636{
 637        struct resource *res, *punit_res;
 638        void __iomem *addr;
 639        int size;
 640
 641        res = platform_get_resource(pdev, IORESOURCE_IO,
 642                                    PLAT_RESOURCE_ACPI_IO_INDEX);
 643        if (!res) {
 644                dev_err(&pdev->dev, "Failed to get io resource\n");
 645                return -ENXIO;
 646        }
 647        size = resource_size(res);
 648        ipcdev.acpi_io_base = res->start;
 649        ipcdev.acpi_io_size = size;
 650        dev_info(&pdev->dev, "io res: %pR\n", res);
 651
 652        punit_res = punit_res_array;
 653        /* This is index 0 to cover BIOS data register */
 654        res = platform_get_resource(pdev, IORESOURCE_MEM,
 655                                    PLAT_RESOURCE_BIOS_DATA_INDEX);
 656        if (!res) {
 657                dev_err(&pdev->dev, "Failed to get res of punit BIOS data\n");
 658                return -ENXIO;
 659        }
 660        *punit_res = *res;
 661        dev_info(&pdev->dev, "punit BIOS data res: %pR\n", res);
 662
 663        /* This is index 1 to cover BIOS interface register */
 664        res = platform_get_resource(pdev, IORESOURCE_MEM,
 665                                    PLAT_RESOURCE_BIOS_IFACE_INDEX);
 666        if (!res) {
 667                dev_err(&pdev->dev, "Failed to get res of punit BIOS iface\n");
 668                return -ENXIO;
 669        }
 670        *++punit_res = *res;
 671        dev_info(&pdev->dev, "punit BIOS interface res: %pR\n", res);
 672
 673        /* This is index 2 to cover ISP data register, optional */
 674        res = platform_get_resource(pdev, IORESOURCE_MEM,
 675                                    PLAT_RESOURCE_ISP_DATA_INDEX);
 676        ++punit_res;
 677        if (res) {
 678                *punit_res = *res;
 679                dev_info(&pdev->dev, "punit ISP data res: %pR\n", res);
 680        }
 681
 682        /* This is index 3 to cover ISP interface register, optional */
 683        res = platform_get_resource(pdev, IORESOURCE_MEM,
 684                                    PLAT_RESOURCE_ISP_IFACE_INDEX);
 685        ++punit_res;
 686        if (res) {
 687                *punit_res = *res;
 688                dev_info(&pdev->dev, "punit ISP interface res: %pR\n", res);
 689        }
 690
 691        /* This is index 4 to cover GTD data register, optional */
 692        res = platform_get_resource(pdev, IORESOURCE_MEM,
 693                                    PLAT_RESOURCE_GTD_DATA_INDEX);
 694        ++punit_res;
 695        if (res) {
 696                *punit_res = *res;
 697                dev_info(&pdev->dev, "punit GTD data res: %pR\n", res);
 698        }
 699
 700        /* This is index 5 to cover GTD interface register, optional */
 701        res = platform_get_resource(pdev, IORESOURCE_MEM,
 702                                    PLAT_RESOURCE_GTD_IFACE_INDEX);
 703        ++punit_res;
 704        if (res) {
 705                *punit_res = *res;
 706                dev_info(&pdev->dev, "punit GTD interface res: %pR\n", res);
 707        }
 708
 709        res = platform_get_resource(pdev, IORESOURCE_MEM,
 710                                    PLAT_RESOURCE_IPC_INDEX);
 711        if (!res) {
 712                dev_err(&pdev->dev, "Failed to get ipc resource\n");
 713                return -ENXIO;
 714        }
 715        size = PLAT_RESOURCE_IPC_SIZE;
 716        if (!request_mem_region(res->start, size, pdev->name)) {
 717                dev_err(&pdev->dev, "Failed to request ipc resource\n");
 718                return -EBUSY;
 719        }
 720        addr = ioremap_nocache(res->start, size);
 721        if (!addr) {
 722                dev_err(&pdev->dev, "I/O memory remapping failed\n");
 723                release_mem_region(res->start, size);
 724                return -ENOMEM;
 725        }
 726        ipcdev.ipc_base = addr;
 727
 728        ipcdev.gcr_base = res->start + PLAT_RESOURCE_GCR_OFFSET;
 729        ipcdev.gcr_size = PLAT_RESOURCE_GCR_SIZE;
 730        dev_info(&pdev->dev, "ipc res: %pR\n", res);
 731
 732        ipcdev.telem_res_inval = 0;
 733        res = platform_get_resource(pdev, IORESOURCE_MEM,
 734                                    PLAT_RESOURCE_TELEM_SSRAM_INDEX);
 735        if (!res) {
 736                dev_err(&pdev->dev, "Failed to get telemetry ssram resource\n");
 737                ipcdev.telem_res_inval = 1;
 738        } else {
 739                ipcdev.telem_punit_ssram_base = res->start +
 740                                                TELEM_PUNIT_SSRAM_OFFSET;
 741                ipcdev.telem_punit_ssram_size = TELEM_SSRAM_SIZE;
 742                ipcdev.telem_pmc_ssram_base = res->start +
 743                                                TELEM_PMC_SSRAM_OFFSET;
 744                ipcdev.telem_pmc_ssram_size = TELEM_SSRAM_SIZE;
 745                dev_info(&pdev->dev, "telemetry ssram res: %pR\n", res);
 746        }
 747
 748        return 0;
 749}
 750
 751#ifdef CONFIG_ACPI
 752static const struct acpi_device_id ipc_acpi_ids[] = {
 753        { "INT34D2", 0},
 754        { }
 755};
 756MODULE_DEVICE_TABLE(acpi, ipc_acpi_ids);
 757#endif
 758
 759static int ipc_plat_probe(struct platform_device *pdev)
 760{
 761        struct resource *res;
 762        int ret;
 763
 764        ipcdev.dev = &pdev->dev;
 765        ipcdev.irq_mode = IPC_TRIGGER_MODE_IRQ;
 766        init_completion(&ipcdev.cmd_complete);
 767
 768        ipcdev.irq = platform_get_irq(pdev, 0);
 769        if (ipcdev.irq < 0) {
 770                dev_err(&pdev->dev, "Failed to get irq\n");
 771                return -EINVAL;
 772        }
 773
 774        ret = ipc_plat_get_res(pdev);
 775        if (ret) {
 776                dev_err(&pdev->dev, "Failed to request resource\n");
 777                return ret;
 778        }
 779
 780        ret = ipc_create_pmc_devices();
 781        if (ret) {
 782                dev_err(&pdev->dev, "Failed to create pmc devices\n");
 783                goto err_device;
 784        }
 785
 786        if (request_irq(ipcdev.irq, ioc, IRQF_NO_SUSPEND,
 787                        "intel_pmc_ipc", &ipcdev)) {
 788                dev_err(&pdev->dev, "Failed to request irq\n");
 789                ret = -EBUSY;
 790                goto err_irq;
 791        }
 792
 793        ret = sysfs_create_group(&pdev->dev.kobj, &intel_ipc_group);
 794        if (ret) {
 795                dev_err(&pdev->dev, "Failed to create sysfs group %d\n",
 796                        ret);
 797                goto err_sys;
 798        }
 799
 800        return 0;
 801err_sys:
 802        free_irq(ipcdev.irq, &ipcdev);
 803err_irq:
 804        platform_device_unregister(ipcdev.tco_dev);
 805        platform_device_unregister(ipcdev.punit_dev);
 806        platform_device_unregister(ipcdev.telemetry_dev);
 807err_device:
 808        iounmap(ipcdev.ipc_base);
 809        res = platform_get_resource(pdev, IORESOURCE_MEM,
 810                                    PLAT_RESOURCE_IPC_INDEX);
 811        if (res)
 812                release_mem_region(res->start, PLAT_RESOURCE_IPC_SIZE);
 813        return ret;
 814}
 815
 816static int ipc_plat_remove(struct platform_device *pdev)
 817{
 818        struct resource *res;
 819
 820        sysfs_remove_group(&pdev->dev.kobj, &intel_ipc_group);
 821        free_irq(ipcdev.irq, &ipcdev);
 822        platform_device_unregister(ipcdev.tco_dev);
 823        platform_device_unregister(ipcdev.punit_dev);
 824        platform_device_unregister(ipcdev.telemetry_dev);
 825        iounmap(ipcdev.ipc_base);
 826        res = platform_get_resource(pdev, IORESOURCE_MEM,
 827                                    PLAT_RESOURCE_IPC_INDEX);
 828        if (res)
 829                release_mem_region(res->start, PLAT_RESOURCE_IPC_SIZE);
 830        ipcdev.dev = NULL;
 831        return 0;
 832}
 833
 834static struct platform_driver ipc_plat_driver = {
 835        .remove = ipc_plat_remove,
 836        .probe = ipc_plat_probe,
 837        .driver = {
 838                .name = "pmc-ipc-plat",
 839                .acpi_match_table = ACPI_PTR(ipc_acpi_ids),
 840        },
 841};
 842
 843static int __init intel_pmc_ipc_init(void)
 844{
 845        int ret;
 846
 847        ret = platform_driver_register(&ipc_plat_driver);
 848        if (ret) {
 849                pr_err("Failed to register PMC ipc platform driver\n");
 850                return ret;
 851        }
 852        ret = pci_register_driver(&ipc_pci_driver);
 853        if (ret) {
 854                pr_err("Failed to register PMC ipc pci driver\n");
 855                platform_driver_unregister(&ipc_plat_driver);
 856                return ret;
 857        }
 858        return ret;
 859}
 860
 861static void __exit intel_pmc_ipc_exit(void)
 862{
 863        pci_unregister_driver(&ipc_pci_driver);
 864        platform_driver_unregister(&ipc_plat_driver);
 865}
 866
 867MODULE_AUTHOR("Zha Qipeng <qipeng.zha@intel.com>");
 868MODULE_DESCRIPTION("Intel PMC IPC driver");
 869MODULE_LICENSE("GPL");
 870
 871/* Some modules are dependent on this, so init earlier */
 872fs_initcall(intel_pmc_ipc_init);
 873module_exit(intel_pmc_ipc_exit);
 874