All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFC v8 0/7] SCU/PMC/PUNIT Inter-Processor Communication(IPC) driver cleanup
@ 2017-10-29  9:49 ` sathyanarayanan.kuppuswamy
  0 siblings, 0 replies; 30+ messages in thread
From: sathyanarayanan.kuppuswamy @ 2017-10-29  9:49 UTC (permalink / raw)
  To: a.zummo, x86, wim, mingo, alexandre.belloni, qipeng.zha, hpa,
	dvhart, tglx, lee.jones, andy, souvik.k.chakravarty
  Cc: linux-rtc, linux-watchdog, linux-kernel, platform-driver-x86,
	sathyaosid, Kuppuswamy Sathyanarayanan

From: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>


Hi All,

Currently intel_pmc_ipc.c, intel_punit_ipc.c, intel_scu_ipc.c drivers implements the same IPC features.
This code duplication could be avoided if we implement the IPC driver as a generic library and let custom
device drivers use API provided by generic driver. This patchset mainly addresses this issue.

Along with above code duplication issue, This patchset also addresses following issues in intel_pmc_ipc and
intel_punit_ipc drivers. 

1. Intel_pmc_ipc.c driver does not use any resource managed (devm_*) calls.
2. In Intel_pmc_ipc.c driver, dependent devices like PUNIT, Telemetry and iTCO are created manually and uses lot of redundant buffer code.
3. Global variable is used to store the IPC device structure and it is used across all functions in intel_pmc_ipc.c and intel_punit_ipc.c.

More info on Intel IPC device library:
-------------------------------------

A generic Intel IPC class driver has been implemented and all common IPC helper functions has been moved to this driver. It exposes APIs to create IPC device channel, send raw IPC command and simple IPC commands. It also creates device attribute to send IPC command from user space.

API for creating a new IPC channel device is,

struct intel_ipc_dev *devm_intel_ipc_dev_create(struct device *dev, const char *devname, struct intel_ipc_dev_cfg *cfg, struct intel_ipc_dev_ops *ops)

The IPC channel drivers (PUNIT/PMC/SCU) when creating a new device can configure their device params like register mapping, irq, irq-mode, channel type,etc  using intel_ipc_dev_cfg and intel_ipc_dev_ops arguments. After a new IPC channel device is created, IPC users can use the generic APIs to make IPC calls.

For example, after using this new model, IPC call to PMC device will look like,

pmc_ipc_dev = intel_ipc_dev_get(INTEL_PMC_IPC_DEV);
ipc_dev_raw_cmd(pmc_ipc_dev, ipc_raw_cmd);
intel_ipc_dev_put(pmc_ipc_dev);

I am still testing the driver in different products. But posted it to get some early comments. I also welcome any PMC/PUNIT driver users to check these patches in their product.

Changes since v7:
 * Fixed checkpatch errors/warnings.

Changes since v6:
 * First two patches of v6 patch set has already been approved, So removed it
   from the list.
 * Rebased rest of the patches on top of testing branch.
 * Fixed some style issues.

Changes since v5:
 * Added intel_ipc_cmd and intel_ipc_raw_cmd structures.
 * Fixed some minor style issues.
 * Rebased "intel_pmc_ipc: Use devm_* calls in driver probe function" patch on top of
   4.14-rc5 kernel.

Changes since v4:
 * Pushed "platform/x86: intel_pmc_ipc: Use spin_lock to protect GCR update" patch
   to the top of the patch list. Also its rebased on top of Andy's review branch.

Changes since v3:
 * Rebased on top of Andy's review branch.
 * Fixed resource ioremap warning in intel_punit_ipc.c.
 * Divided "platform/x86: intel_pmc_ipc: Use regmap calls for GCR updates" patch
   into two patches. One fixing the existing issue and another to add regmap support.
 * Fixed error in resource initalization logic in ipc_create_punit_device.
 * Changed PLATFORM_DEVID_AUTO to PLATFORM_DEVID_NONE in mfd device creation.
 * Added unique name to PUNIT BIOS, GTD, & ISP regmaps.
 * Fixed NULL pointer exception in intel_ipc_dev_get().
 * In intel_ipc_dev.c,
    * Fixed error in check for duplicate intel_ipc_dev.
    * Added custom interrupt handler support.
    * Used char array for error string conversion.
    * Added put dev support.

Changes since v2:
 * Refactored intel_scu_ipc.c to use generic IPC device APIs.
 * Fixed intel_pmc_ipc.c to use pcim_* device managed functions.

Changes since v1:
 * Merged devm_* changes in pmc_plat_probe and pmc_pci_probe functions into a
   single patch.
 * Addressed Andy's comment about keeping the library generic by not implementing
   the low level reg access calls in intel_ipc_dev.c. This version will start using
   the regmap pointer provided by channel drivers instead of fixed memory map.
 * Removed custom IPC APIs in intel_pmc_ipc.c and intel_punit_ipc.c.
 * Cleaned up IPC driver users to use APIs provided by generic library (intel_ipc_dev.c).





Kuppuswamy Sathyanarayanan (7):
  platform/x86: intel_punit_ipc: Fix resource ioremap warning
  platform/x86: intel_pmc_ipc: Use MFD framework to create dependent
    devices
  platform/x86: intel_pmc_ipc: Use regmap calls for GCR updates
  platform: x86: Add generic Intel IPC driver
  platform/x86: intel_punit_ipc: Use generic intel ipc device calls
  platform/x86: intel_pmc_ipc: Use generic Intel IPC device calls
  platform/x86: intel_scu_ipc: Use generic Intel IPC device calls

 MAINTAINERS                                     |   7 +
 arch/x86/include/asm/intel_pmc_ipc.h            |  31 +-
 arch/x86/include/asm/intel_punit_ipc.h          | 125 ++--
 arch/x86/include/asm/intel_scu_ipc.h            |  10 +-
 arch/x86/platform/intel-mid/intel-mid.c         |  15 +-
 drivers/mfd/intel_soc_pmic_bxtwc.c              |  37 +-
 drivers/platform/x86/Kconfig                    |  11 +
 drivers/platform/x86/Makefile                   |   1 +
 drivers/platform/x86/intel_ipc_dev.c            | 563 +++++++++++++++
 drivers/platform/x86/intel_pmc_ipc.c            | 886 +++++++++---------------
 drivers/platform/x86/intel_punit_ipc.c          | 307 +++-----
 drivers/platform/x86/intel_scu_ipc.c            | 488 ++++++-------
 drivers/platform/x86/intel_telemetry_pltdrv.c   | 229 +++---
 drivers/rtc/rtc-mrst.c                          |  16 +-
 drivers/watchdog/intel-mid_wdt.c                |  18 +-
 drivers/watchdog/intel_scu_watchdog.c           |  23 +-
 include/linux/mfd/intel_soc_pmic.h              |   2 +
 include/linux/platform_data/x86/intel_ipc_dev.h | 246 +++++++
 18 files changed, 1741 insertions(+), 1274 deletions(-)
 create mode 100644 drivers/platform/x86/intel_ipc_dev.c
 create mode 100644 include/linux/platform_data/x86/intel_ipc_dev.h

-- 
2.7.4

^ permalink raw reply	[flat|nested] 30+ messages in thread

* [RFC v8 0/7] SCU/PMC/PUNIT Inter-Processor Communication(IPC) driver cleanup
@ 2017-10-29  9:49 ` sathyanarayanan.kuppuswamy
  0 siblings, 0 replies; 30+ messages in thread
From: sathyanarayanan.kuppuswamy @ 2017-10-29  9:49 UTC (permalink / raw)
  To: a.zummo, x86, wim, mingo, alexandre.belloni, qipeng.zha, hpa,
	dvhart, tglx, lee.jones, andy, souvik.k.chakravarty
  Cc: linux-rtc, linux-watchdog, linux-kernel, platform-driver-x86,
	sathyaosid, Kuppuswamy Sathyanarayanan

From: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>


Hi All,

Currently intel_pmc_ipc.c, intel_punit_ipc.c, intel_scu_ipc.c drivers implements the same IPC features.
This code duplication could be avoided if we implement the IPC driver as a generic library and let custom
device drivers use API provided by generic driver. This patchset mainly addresses this issue.

Along with above code duplication issue, This patchset also addresses following issues in intel_pmc_ipc and
intel_punit_ipc drivers. 

1. Intel_pmc_ipc.c driver does not use any resource managed (devm_*) calls.
2. In Intel_pmc_ipc.c driver, dependent devices like PUNIT, Telemetry and iTCO are created manually and uses lot of redundant buffer code.
3. Global variable is used to store the IPC device structure and it is used across all functions in intel_pmc_ipc.c and intel_punit_ipc.c.

More info on Intel IPC device library:
-------------------------------------

A generic Intel IPC class driver has been implemented and all common IPC helper functions has been moved to this driver. It exposes APIs to create IPC device channel, send raw IPC command and simple IPC commands. It also creates device attribute to send IPC command from user space.

API for creating a new IPC channel device is,

struct intel_ipc_dev *devm_intel_ipc_dev_create(struct device *dev, const char *devname, struct intel_ipc_dev_cfg *cfg, struct intel_ipc_dev_ops *ops)

The IPC channel drivers (PUNIT/PMC/SCU) when creating a new device can configure their device params like register mapping, irq, irq-mode, channel type,etc  using intel_ipc_dev_cfg and intel_ipc_dev_ops arguments. After a new IPC channel device is created, IPC users can use the generic APIs to make IPC calls.

For example, after using this new model, IPC call to PMC device will look like,

pmc_ipc_dev = intel_ipc_dev_get(INTEL_PMC_IPC_DEV);
ipc_dev_raw_cmd(pmc_ipc_dev, ipc_raw_cmd);
intel_ipc_dev_put(pmc_ipc_dev);

I am still testing the driver in different products. But posted it to get some early comments. I also welcome any PMC/PUNIT driver users to check these patches in their product.

Changes since v7:
 * Fixed checkpatch errors/warnings.

Changes since v6:
 * First two patches of v6 patch set has already been approved, So removed it
   from the list.
 * Rebased rest of the patches on top of testing branch.
 * Fixed some style issues.

Changes since v5:
 * Added intel_ipc_cmd and intel_ipc_raw_cmd structures.
 * Fixed some minor style issues.
 * Rebased "intel_pmc_ipc: Use devm_* calls in driver probe function" patch on top of
   4.14-rc5 kernel.

Changes since v4:
 * Pushed "platform/x86: intel_pmc_ipc: Use spin_lock to protect GCR update" patch
   to the top of the patch list. Also its rebased on top of Andy's review branch.

Changes since v3:
 * Rebased on top of Andy's review branch.
 * Fixed resource ioremap warning in intel_punit_ipc.c.
 * Divided "platform/x86: intel_pmc_ipc: Use regmap calls for GCR updates" patch
   into two patches. One fixing the existing issue and another to add regmap support.
 * Fixed error in resource initalization logic in ipc_create_punit_device.
 * Changed PLATFORM_DEVID_AUTO to PLATFORM_DEVID_NONE in mfd device creation.
 * Added unique name to PUNIT BIOS, GTD, & ISP regmaps.
 * Fixed NULL pointer exception in intel_ipc_dev_get().
 * In intel_ipc_dev.c,
    * Fixed error in check for duplicate intel_ipc_dev.
    * Added custom interrupt handler support.
    * Used char array for error string conversion.
    * Added put dev support.

Changes since v2:
 * Refactored intel_scu_ipc.c to use generic IPC device APIs.
 * Fixed intel_pmc_ipc.c to use pcim_* device managed functions.

Changes since v1:
 * Merged devm_* changes in pmc_plat_probe and pmc_pci_probe functions into a
   single patch.
 * Addressed Andy's comment about keeping the library generic by not implementing
   the low level reg access calls in intel_ipc_dev.c. This version will start using
   the regmap pointer provided by channel drivers instead of fixed memory map.
 * Removed custom IPC APIs in intel_pmc_ipc.c and intel_punit_ipc.c.
 * Cleaned up IPC driver users to use APIs provided by generic library (intel_ipc_dev.c).





Kuppuswamy Sathyanarayanan (7):
  platform/x86: intel_punit_ipc: Fix resource ioremap warning
  platform/x86: intel_pmc_ipc: Use MFD framework to create dependent
    devices
  platform/x86: intel_pmc_ipc: Use regmap calls for GCR updates
  platform: x86: Add generic Intel IPC driver
  platform/x86: intel_punit_ipc: Use generic intel ipc device calls
  platform/x86: intel_pmc_ipc: Use generic Intel IPC device calls
  platform/x86: intel_scu_ipc: Use generic Intel IPC device calls

 MAINTAINERS                                     |   7 +
 arch/x86/include/asm/intel_pmc_ipc.h            |  31 +-
 arch/x86/include/asm/intel_punit_ipc.h          | 125 ++--
 arch/x86/include/asm/intel_scu_ipc.h            |  10 +-
 arch/x86/platform/intel-mid/intel-mid.c         |  15 +-
 drivers/mfd/intel_soc_pmic_bxtwc.c              |  37 +-
 drivers/platform/x86/Kconfig                    |  11 +
 drivers/platform/x86/Makefile                   |   1 +
 drivers/platform/x86/intel_ipc_dev.c            | 563 +++++++++++++++
 drivers/platform/x86/intel_pmc_ipc.c            | 886 +++++++++---------------
 drivers/platform/x86/intel_punit_ipc.c          | 307 +++-----
 drivers/platform/x86/intel_scu_ipc.c            | 488 ++++++-------
 drivers/platform/x86/intel_telemetry_pltdrv.c   | 229 +++---
 drivers/rtc/rtc-mrst.c                          |  16 +-
 drivers/watchdog/intel-mid_wdt.c                |  18 +-
 drivers/watchdog/intel_scu_watchdog.c           |  23 +-
 include/linux/mfd/intel_soc_pmic.h              |   2 +
 include/linux/platform_data/x86/intel_ipc_dev.h | 246 +++++++
 18 files changed, 1741 insertions(+), 1274 deletions(-)
 create mode 100644 drivers/platform/x86/intel_ipc_dev.c
 create mode 100644 include/linux/platform_data/x86/intel_ipc_dev.h

-- 
2.7.4

^ permalink raw reply	[flat|nested] 30+ messages in thread

* [RFC v8 0/7] SCU/PMC/PUNIT Inter-Processor Communication(IPC) driver cleanup
@ 2017-10-29  9:49 ` sathyanarayanan.kuppuswamy
  0 siblings, 0 replies; 30+ messages in thread
From: sathyanarayanan.kuppuswamy-VuQAYsv1563Yd54FQh9/CA @ 2017-10-29  9:49 UTC (permalink / raw)
  To: a.zummo-BfzFCNDTiLLj+vYz1yj4TQ, x86-DgEjT+Ai2ygdnm+yROfE0A,
	wim-IQzOog9fTRqzQB+pC5nmwQ, mingo-H+wXaHxf7aLQT0dZR+AlfA,
	alexandre.belloni-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
	qipeng.zha-ral2JQCrhuEAvxtiuMwx3w, hpa-YMNOUZJC4hwAvxtiuMwx3w,
	dvhart-wEGCiKHe2LqWVfeAwA7xHQ, tglx-hfZtesqFncYOwBW4kG4KsQ,
	lee.jones-QSEj5FYQhm4dnm+yROfE0A, andy-wEGCiKHe2LqWVfeAwA7xHQ,
	souvik.k.chakravarty-ral2JQCrhuEAvxtiuMwx3w
  Cc: linux-rtc-u79uwXL29TY76Z2rM5mHXA,
	linux-watchdog-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	platform-driver-x86-u79uwXL29TY76Z2rM5mHXA,
	sathyaosid-Re5JQEeQqe8AvxtiuMwx3w, Kuppuswamy Sathyanarayanan

From: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>


Hi All,

Currently intel_pmc_ipc.c, intel_punit_ipc.c, intel_scu_ipc.c drivers implements the same IPC features.
This code duplication could be avoided if we implement the IPC driver as a generic library and let custom
device drivers use API provided by generic driver. This patchset mainly addresses this issue.

Along with above code duplication issue, This patchset also addresses following issues in intel_pmc_ipc and
intel_punit_ipc drivers. 

1. Intel_pmc_ipc.c driver does not use any resource managed (devm_*) calls.
2. In Intel_pmc_ipc.c driver, dependent devices like PUNIT, Telemetry and iTCO are created manually and uses lot of redundant buffer code.
3. Global variable is used to store the IPC device structure and it is used across all functions in intel_pmc_ipc.c and intel_punit_ipc.c.

More info on Intel IPC device library:
-------------------------------------

A generic Intel IPC class driver has been implemented and all common IPC helper functions has been moved to this driver. It exposes APIs to create IPC device channel, send raw IPC command and simple IPC commands. It also creates device attribute to send IPC command from user space.

API for creating a new IPC channel device is,

struct intel_ipc_dev *devm_intel_ipc_dev_create(struct device *dev, const char *devname, struct intel_ipc_dev_cfg *cfg, struct intel_ipc_dev_ops *ops)

The IPC channel drivers (PUNIT/PMC/SCU) when creating a new device can configure their device params like register mapping, irq, irq-mode, channel type,etc  using intel_ipc_dev_cfg and intel_ipc_dev_ops arguments. After a new IPC channel device is created, IPC users can use the generic APIs to make IPC calls.

For example, after using this new model, IPC call to PMC device will look like,

pmc_ipc_dev = intel_ipc_dev_get(INTEL_PMC_IPC_DEV);
ipc_dev_raw_cmd(pmc_ipc_dev, ipc_raw_cmd);
intel_ipc_dev_put(pmc_ipc_dev);

I am still testing the driver in different products. But posted it to get some early comments. I also welcome any PMC/PUNIT driver users to check these patches in their product.

Changes since v7:
 * Fixed checkpatch errors/warnings.

Changes since v6:
 * First two patches of v6 patch set has already been approved, So removed it
   from the list.
 * Rebased rest of the patches on top of testing branch.
 * Fixed some style issues.

Changes since v5:
 * Added intel_ipc_cmd and intel_ipc_raw_cmd structures.
 * Fixed some minor style issues.
 * Rebased "intel_pmc_ipc: Use devm_* calls in driver probe function" patch on top of
   4.14-rc5 kernel.

Changes since v4:
 * Pushed "platform/x86: intel_pmc_ipc: Use spin_lock to protect GCR update" patch
   to the top of the patch list. Also its rebased on top of Andy's review branch.

Changes since v3:
 * Rebased on top of Andy's review branch.
 * Fixed resource ioremap warning in intel_punit_ipc.c.
 * Divided "platform/x86: intel_pmc_ipc: Use regmap calls for GCR updates" patch
   into two patches. One fixing the existing issue and another to add regmap support.
 * Fixed error in resource initalization logic in ipc_create_punit_device.
 * Changed PLATFORM_DEVID_AUTO to PLATFORM_DEVID_NONE in mfd device creation.
 * Added unique name to PUNIT BIOS, GTD, & ISP regmaps.
 * Fixed NULL pointer exception in intel_ipc_dev_get().
 * In intel_ipc_dev.c,
    * Fixed error in check for duplicate intel_ipc_dev.
    * Added custom interrupt handler support.
    * Used char array for error string conversion.
    * Added put dev support.

Changes since v2:
 * Refactored intel_scu_ipc.c to use generic IPC device APIs.
 * Fixed intel_pmc_ipc.c to use pcim_* device managed functions.

Changes since v1:
 * Merged devm_* changes in pmc_plat_probe and pmc_pci_probe functions into a
   single patch.
 * Addressed Andy's comment about keeping the library generic by not implementing
   the low level reg access calls in intel_ipc_dev.c. This version will start using
   the regmap pointer provided by channel drivers instead of fixed memory map.
 * Removed custom IPC APIs in intel_pmc_ipc.c and intel_punit_ipc.c.
 * Cleaned up IPC driver users to use APIs provided by generic library (intel_ipc_dev.c).





Kuppuswamy Sathyanarayanan (7):
  platform/x86: intel_punit_ipc: Fix resource ioremap warning
  platform/x86: intel_pmc_ipc: Use MFD framework to create dependent
    devices
  platform/x86: intel_pmc_ipc: Use regmap calls for GCR updates
  platform: x86: Add generic Intel IPC driver
  platform/x86: intel_punit_ipc: Use generic intel ipc device calls
  platform/x86: intel_pmc_ipc: Use generic Intel IPC device calls
  platform/x86: intel_scu_ipc: Use generic Intel IPC device calls

 MAINTAINERS                                     |   7 +
 arch/x86/include/asm/intel_pmc_ipc.h            |  31 +-
 arch/x86/include/asm/intel_punit_ipc.h          | 125 ++--
 arch/x86/include/asm/intel_scu_ipc.h            |  10 +-
 arch/x86/platform/intel-mid/intel-mid.c         |  15 +-
 drivers/mfd/intel_soc_pmic_bxtwc.c              |  37 +-
 drivers/platform/x86/Kconfig                    |  11 +
 drivers/platform/x86/Makefile                   |   1 +
 drivers/platform/x86/intel_ipc_dev.c            | 563 +++++++++++++++
 drivers/platform/x86/intel_pmc_ipc.c            | 886 +++++++++---------------
 drivers/platform/x86/intel_punit_ipc.c          | 307 +++-----
 drivers/platform/x86/intel_scu_ipc.c            | 488 ++++++-------
 drivers/platform/x86/intel_telemetry_pltdrv.c   | 229 +++---
 drivers/rtc/rtc-mrst.c                          |  16 +-
 drivers/watchdog/intel-mid_wdt.c                |  18 +-
 drivers/watchdog/intel_scu_watchdog.c           |  23 +-
 include/linux/mfd/intel_soc_pmic.h              |   2 +
 include/linux/platform_data/x86/intel_ipc_dev.h | 246 +++++++
 18 files changed, 1741 insertions(+), 1274 deletions(-)
 create mode 100644 drivers/platform/x86/intel_ipc_dev.c
 create mode 100644 include/linux/platform_data/x86/intel_ipc_dev.h

-- 
2.7.4

--
To unsubscribe from this list: send the line "unsubscribe linux-watchdog" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 30+ messages in thread

* [RFC v8 1/7] platform/x86: intel_punit_ipc: Fix resource ioremap warning
  2017-10-29  9:49 ` sathyanarayanan.kuppuswamy
@ 2017-10-29  9:49   ` sathyanarayanan.kuppuswamy
  -1 siblings, 0 replies; 30+ messages in thread
From: sathyanarayanan.kuppuswamy @ 2017-10-29  9:49 UTC (permalink / raw)
  To: a.zummo, x86, wim, mingo, alexandre.belloni, qipeng.zha, hpa,
	dvhart, tglx, lee.jones, andy, souvik.k.chakravarty
  Cc: linux-rtc, linux-watchdog, linux-kernel, platform-driver-x86,
	sathyaosid, Kuppuswamy Sathyanarayanan, Andy Shevchenko

From: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>

For PUNIT device, ISPDRIVER_IPC and GTDDRIVER_IPC resources are not
mandatory. So when PMC IPC driver creates a PUNIT device, if these
resources are not available then it creates dummy resource entries for
these missing resources. But during PUNIT device probe, doing ioremap on
these dummy resources generates following warning messages.

intel_punit_ipc: can't request region for resource [mem 0x00000000]
intel_punit_ipc: can't request region for resource [mem 0x00000000]
intel_punit_ipc: can't request region for resource [mem 0x00000000]
intel_punit_ipc: can't request region for resource [mem 0x00000000]

This patch fixes this issue by adding extra check for resource size
before performing ioremap operation.

Signed-off-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>
Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
---
 drivers/platform/x86/intel_punit_ipc.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

Changes since v7:
 * None

Changes since v6:
 * None

Changes since v5:
 * None

Changes since v4:
 * None

diff --git a/drivers/platform/x86/intel_punit_ipc.c b/drivers/platform/x86/intel_punit_ipc.c
index a47a41f..b5b8901 100644
--- a/drivers/platform/x86/intel_punit_ipc.c
+++ b/drivers/platform/x86/intel_punit_ipc.c
@@ -252,28 +252,28 @@ static int intel_punit_get_bars(struct platform_device *pdev)
 	 * - GTDRIVER_IPC BASE_IFACE
 	 */
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
-	if (res) {
+	if (res && resource_size(res) > 1) {
 		addr = devm_ioremap_resource(&pdev->dev, res);
 		if (!IS_ERR(addr))
 			punit_ipcdev->base[ISPDRIVER_IPC][BASE_DATA] = addr;
 	}
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 3);
-	if (res) {
+	if (res && resource_size(res) > 1) {
 		addr = devm_ioremap_resource(&pdev->dev, res);
 		if (!IS_ERR(addr))
 			punit_ipcdev->base[ISPDRIVER_IPC][BASE_IFACE] = addr;
 	}
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 4);
-	if (res) {
+	if (res && resource_size(res) > 1) {
 		addr = devm_ioremap_resource(&pdev->dev, res);
 		if (!IS_ERR(addr))
 			punit_ipcdev->base[GTDRIVER_IPC][BASE_DATA] = addr;
 	}
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 5);
-	if (res) {
+	if (res && resource_size(res) > 1) {
 		addr = devm_ioremap_resource(&pdev->dev, res);
 		if (!IS_ERR(addr))
 			punit_ipcdev->base[GTDRIVER_IPC][BASE_IFACE] = addr;
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [RFC v8 1/7] platform/x86: intel_punit_ipc: Fix resource ioremap warning
@ 2017-10-29  9:49   ` sathyanarayanan.kuppuswamy
  0 siblings, 0 replies; 30+ messages in thread
From: sathyanarayanan.kuppuswamy @ 2017-10-29  9:49 UTC (permalink / raw)
  To: a.zummo, x86, wim, mingo, alexandre.belloni, qipeng.zha, hpa,
	dvhart, tglx, lee.jones, andy, souvik.k.chakravarty
  Cc: linux-rtc, linux-watchdog, linux-kernel, platform-driver-x86,
	sathyaosid, Kuppuswamy Sathyanarayanan, Andy Shevchenko

From: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>

For PUNIT device, ISPDRIVER_IPC and GTDDRIVER_IPC resources are not
mandatory. So when PMC IPC driver creates a PUNIT device, if these
resources are not available then it creates dummy resource entries for
these missing resources. But during PUNIT device probe, doing ioremap on
these dummy resources generates following warning messages.

intel_punit_ipc: can't request region for resource [mem 0x00000000]
intel_punit_ipc: can't request region for resource [mem 0x00000000]
intel_punit_ipc: can't request region for resource [mem 0x00000000]
intel_punit_ipc: can't request region for resource [mem 0x00000000]

This patch fixes this issue by adding extra check for resource size
before performing ioremap operation.

Signed-off-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>
Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
---
 drivers/platform/x86/intel_punit_ipc.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

Changes since v7:
 * None

Changes since v6:
 * None

Changes since v5:
 * None

Changes since v4:
 * None

diff --git a/drivers/platform/x86/intel_punit_ipc.c b/drivers/platform/x86/intel_punit_ipc.c
index a47a41f..b5b8901 100644
--- a/drivers/platform/x86/intel_punit_ipc.c
+++ b/drivers/platform/x86/intel_punit_ipc.c
@@ -252,28 +252,28 @@ static int intel_punit_get_bars(struct platform_device *pdev)
 	 * - GTDRIVER_IPC BASE_IFACE
 	 */
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
-	if (res) {
+	if (res && resource_size(res) > 1) {
 		addr = devm_ioremap_resource(&pdev->dev, res);
 		if (!IS_ERR(addr))
 			punit_ipcdev->base[ISPDRIVER_IPC][BASE_DATA] = addr;
 	}
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 3);
-	if (res) {
+	if (res && resource_size(res) > 1) {
 		addr = devm_ioremap_resource(&pdev->dev, res);
 		if (!IS_ERR(addr))
 			punit_ipcdev->base[ISPDRIVER_IPC][BASE_IFACE] = addr;
 	}
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 4);
-	if (res) {
+	if (res && resource_size(res) > 1) {
 		addr = devm_ioremap_resource(&pdev->dev, res);
 		if (!IS_ERR(addr))
 			punit_ipcdev->base[GTDRIVER_IPC][BASE_DATA] = addr;
 	}
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 5);
-	if (res) {
+	if (res && resource_size(res) > 1) {
 		addr = devm_ioremap_resource(&pdev->dev, res);
 		if (!IS_ERR(addr))
 			punit_ipcdev->base[GTDRIVER_IPC][BASE_IFACE] = addr;
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [RFC v8 2/7] platform/x86: intel_pmc_ipc: Use MFD framework to create dependent devices
  2017-10-29  9:49 ` sathyanarayanan.kuppuswamy
@ 2017-10-29  9:49   ` sathyanarayanan.kuppuswamy
  -1 siblings, 0 replies; 30+ messages in thread
From: sathyanarayanan.kuppuswamy @ 2017-10-29  9:49 UTC (permalink / raw)
  To: a.zummo, x86, wim, mingo, alexandre.belloni, qipeng.zha, hpa,
	dvhart, tglx, lee.jones, andy, souvik.k.chakravarty
  Cc: linux-rtc, linux-watchdog, linux-kernel, platform-driver-x86,
	sathyaosid, Kuppuswamy Sathyanarayanan, Andy Shevchenko

From: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>

Currently, we have lot of repetitive code in dependent device resource
allocation and device creation handling code. This logic can be improved if
we use MFD framework for dependent device creation. This patch adds this
support.

Signed-off-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>
Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
---
 drivers/platform/x86/intel_pmc_ipc.c | 398 ++++++++++++-----------------------
 1 file changed, 139 insertions(+), 259 deletions(-)

Changes since v7:
 * Fixed style issues.

Changes since v6:
 * Fixed style issues.
 * Used Andy's modified version.

Changes since v5:
 * Changed the order of patches in this patchlist.

Changes since v4:
 * Changed the order of patches in this patchlist.

Changes since v3:
 * Changed PLATFORM_DEVID_AUTO to PLATFORM_DEVID_NONE in mfd device creation.
 * Fixed error in resource initalization logic in ipc_create_punit_device.
 * Removed mfd cell id initialization.

diff --git a/drivers/platform/x86/intel_pmc_ipc.c b/drivers/platform/x86/intel_pmc_ipc.c
index e03fa314..e36144c 100644
--- a/drivers/platform/x86/intel_pmc_ipc.c
+++ b/drivers/platform/x86/intel_pmc_ipc.c
@@ -20,6 +20,7 @@
 #include <linux/errno.h>
 #include <linux/init.h>
 #include <linux/device.h>
+#include <linux/mfd/core.h>
 #include <linux/pm.h>
 #include <linux/pci.h>
 #include <linux/platform_device.h>
@@ -88,6 +89,7 @@
 #define PLAT_RESOURCE_ISP_IFACE_INDEX	5
 #define PLAT_RESOURCE_GTD_DATA_INDEX	6
 #define PLAT_RESOURCE_GTD_IFACE_INDEX	7
+#define PLAT_RESOURCE_MEM_MAX_INDEX	8
 #define PLAT_RESOURCE_ACPI_IO_INDEX	0
 
 /*
@@ -106,8 +108,6 @@
 #define TELEM_SSRAM_SIZE		240
 #define TELEM_PMC_SSRAM_OFFSET		0x1B00
 #define TELEM_PUNIT_SSRAM_OFFSET	0x1A00
-#define TCO_PMC_OFFSET			0x8
-#define TCO_PMC_SIZE			0x4
 
 /* PMC register bit definitions */
 
@@ -124,26 +124,10 @@ static struct intel_pmc_ipc_dev {
 	int cmd;
 	struct completion cmd_complete;
 
-	/* The following PMC BARs share the same ACPI device with the IPC */
-	resource_size_t acpi_io_base;
-	int acpi_io_size;
-	struct platform_device *tco_dev;
-
 	/* gcr */
 	void __iomem *gcr_mem_base;
 	bool has_gcr_regs;
 	spinlock_t gcr_lock;
-
-	/* punit */
-	struct platform_device *punit_dev;
-
-	/* Telemetry */
-	resource_size_t telem_pmc_ssram_base;
-	resource_size_t telem_punit_ssram_base;
-	int telem_pmc_ssram_size;
-	int telem_punit_ssram_size;
-	u8 telem_res_inval;
-	struct platform_device *telemetry_dev;
 } ipcdev;
 
 static char *ipc_err_sources[] = {
@@ -508,7 +492,7 @@ static int ipc_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 	ret = devm_request_irq(&pdev->dev, pdev->irq, ioc, 0, "intel_pmc_ipc",
 				pmc);
 	if (ret) {
-		dev_err(&pdev->dev, "Failed to request irq\n");
+		dev_err(&pdev->dev, "Failed to request IRQ\n");
 		return ret;
 	}
 
@@ -593,44 +577,6 @@ static const struct attribute_group intel_ipc_group = {
 	.attrs = intel_ipc_attrs,
 };
 
-static struct resource punit_res_array[] = {
-	/* Punit BIOS */
-	{
-		.flags = IORESOURCE_MEM,
-	},
-	{
-		.flags = IORESOURCE_MEM,
-	},
-	/* Punit ISP */
-	{
-		.flags = IORESOURCE_MEM,
-	},
-	{
-		.flags = IORESOURCE_MEM,
-	},
-	/* Punit GTD */
-	{
-		.flags = IORESOURCE_MEM,
-	},
-	{
-		.flags = IORESOURCE_MEM,
-	},
-};
-
-#define TCO_RESOURCE_ACPI_IO		0
-#define TCO_RESOURCE_SMI_EN_IO		1
-#define TCO_RESOURCE_GCR_MEM		2
-static struct resource tco_res[] = {
-	/* ACPI - TCO */
-	{
-		.flags = IORESOURCE_IO,
-	},
-	/* ACPI - SMI */
-	{
-		.flags = IORESOURCE_IO,
-	},
-};
-
 static struct itco_wdt_platform_data tco_info = {
 	.name = "Apollo Lake SoC",
 	.version = 5,
@@ -638,234 +584,177 @@ static struct itco_wdt_platform_data tco_info = {
 	.update_no_reboot_bit = update_no_reboot_bit,
 };
 
-#define TELEMETRY_RESOURCE_PUNIT_SSRAM	0
-#define TELEMETRY_RESOURCE_PMC_SSRAM	1
-static struct resource telemetry_res[] = {
-	/*Telemetry*/
-	{
-		.flags = IORESOURCE_MEM,
-	},
-	{
-		.flags = IORESOURCE_MEM,
-	},
-};
-
-static int ipc_create_punit_device(void)
+static int ipc_create_punit_device(struct platform_device *pdev)
 {
-	struct platform_device *pdev;
-	const struct platform_device_info pdevinfo = {
-		.parent = ipcdev.dev,
-		.name = PUNIT_DEVICE_NAME,
-		.id = -1,
-		.res = punit_res_array,
-		.num_res = ARRAY_SIZE(punit_res_array),
+	struct resource punit_res[PLAT_RESOURCE_MEM_MAX_INDEX];
+	struct mfd_cell punit_cell;
+	struct resource *res;
+	int mindex, pindex = 0;
+
+	for (mindex = 0; mindex <= PLAT_RESOURCE_MEM_MAX_INDEX; mindex++) {
+
+		res = platform_get_resource(pdev, IORESOURCE_MEM, mindex);
+
+		switch (mindex) {
+		/* Get PUNIT resources */
+		case PLAT_RESOURCE_BIOS_DATA_INDEX:
+		case PLAT_RESOURCE_BIOS_IFACE_INDEX:
+			/* BIOS resources are required, so return error if not
+			 * available
+			 */
+			if (!res) {
+				dev_err(&pdev->dev,
+					"Failed to get PUNIT MEM resource %d\n",
+					pindex);
+				return -ENXIO;
+			}
+		case PLAT_RESOURCE_ISP_DATA_INDEX:
+		case PLAT_RESOURCE_ISP_IFACE_INDEX:
+		case PLAT_RESOURCE_GTD_DATA_INDEX:
+		case PLAT_RESOURCE_GTD_IFACE_INDEX:
+			/* if valid resource found, copy the resource to PUNIT
+			 * resource
+			 */
+			if (res)
+				memcpy(&punit_res[pindex], res, sizeof(*res));
+			punit_res[pindex].flags = IORESOURCE_MEM;
+			dev_dbg(&pdev->dev, "PUNIT memory res: %pR\n",
+				&punit_res[pindex]);
+			pindex++;
+			break;
 		};
+	}
 
-	pdev = platform_device_register_full(&pdevinfo);
-	if (IS_ERR(pdev))
-		return PTR_ERR(pdev);
-
-	ipcdev.punit_dev = pdev;
+	/* Create PUNIT IPC MFD cell */
+	punit_cell.name = PUNIT_DEVICE_NAME;
+	punit_cell.num_resources = ARRAY_SIZE(punit_res);
+	punit_cell.resources = punit_res;
+	punit_cell.ignore_resource_conflicts = 1;
 
-	return 0;
+	return devm_mfd_add_devices(&pdev->dev, PLATFORM_DEVID_NONE,
+				    &punit_cell, 1, NULL, 0, NULL);
 }
 
-static int ipc_create_tco_device(void)
+static int ipc_create_wdt_device(struct platform_device *pdev)
 {
-	struct platform_device *pdev;
+	static struct resource wdt_ipc_res[2];
 	struct resource *res;
-	const struct platform_device_info pdevinfo = {
-		.parent = ipcdev.dev,
-		.name = TCO_DEVICE_NAME,
-		.id = -1,
-		.res = tco_res,
-		.num_res = ARRAY_SIZE(tco_res),
-		.data = &tco_info,
-		.size_data = sizeof(tco_info),
-		};
+	static struct mfd_cell wdt_cell;
 
-	res = tco_res + TCO_RESOURCE_ACPI_IO;
-	res->start = ipcdev.acpi_io_base + TCO_BASE_OFFSET;
-	res->end = res->start + TCO_REGS_SIZE - 1;
+	/* If we have ACPI based watchdog use that instead, othewise create
+	 * a MFD cell for iTCO watchdog
+	 */
+	if (acpi_has_watchdog())
+		return 0;
 
-	res = tco_res + TCO_RESOURCE_SMI_EN_IO;
-	res->start = ipcdev.acpi_io_base + SMI_EN_OFFSET;
-	res->end = res->start + SMI_EN_SIZE - 1;
+	/* Get iTCO watchdog resources */
+	res = platform_get_resource(pdev, IORESOURCE_IO,
+				    PLAT_RESOURCE_ACPI_IO_INDEX);
+	if (!res) {
+		dev_err(&pdev->dev, "Failed to get WDT resource\n");
+		return -ENXIO;
+	}
 
-	pdev = platform_device_register_full(&pdevinfo);
-	if (IS_ERR(pdev))
-		return PTR_ERR(pdev);
+	wdt_ipc_res[0].start = res->start + TCO_BASE_OFFSET;
+	wdt_ipc_res[0].end = res->start +
+		TCO_BASE_OFFSET + TCO_REGS_SIZE - 1;
+	wdt_ipc_res[0].flags = IORESOURCE_IO;
+	wdt_ipc_res[1].start = res->start + SMI_EN_OFFSET;
+	wdt_ipc_res[1].end = res->start +
+		SMI_EN_OFFSET + SMI_EN_SIZE - 1;
+	wdt_ipc_res[1].flags = IORESOURCE_IO;
 
-	ipcdev.tco_dev = pdev;
+	dev_dbg(&pdev->dev, "watchdog res 0: %pR\n", &wdt_ipc_res[0]);
+	dev_dbg(&pdev->dev, "watchdog res 1: %pR\n", &wdt_ipc_res[1]);
 
-	return 0;
+	wdt_cell.name = TCO_DEVICE_NAME;
+	wdt_cell.platform_data = &tco_info;
+	wdt_cell.pdata_size = sizeof(tco_info);
+	wdt_cell.num_resources = ARRAY_SIZE(wdt_ipc_res);
+	wdt_cell.resources = wdt_ipc_res;
+	wdt_cell.ignore_resource_conflicts = 1;
+
+	return devm_mfd_add_devices(&pdev->dev, PLATFORM_DEVID_NONE,
+				    &wdt_cell, 1, NULL, 0, NULL);
 }
 
-static int ipc_create_telemetry_device(void)
+static int ipc_create_telemetry_device(struct platform_device *pdev)
 {
-	struct platform_device *pdev;
+	struct resource telemetry_ipc_res[2];
+	struct mfd_cell telemetry_cell;
 	struct resource *res;
-	const struct platform_device_info pdevinfo = {
-		.parent = ipcdev.dev,
-		.name = TELEMETRY_DEVICE_NAME,
-		.id = -1,
-		.res = telemetry_res,
-		.num_res = ARRAY_SIZE(telemetry_res),
-		};
 
-	res = telemetry_res + TELEMETRY_RESOURCE_PUNIT_SSRAM;
-	res->start = ipcdev.telem_punit_ssram_base;
-	res->end = res->start + ipcdev.telem_punit_ssram_size - 1;
+	/* Get telemetry resources */
+	res = platform_get_resource(pdev, IORESOURCE_MEM,
+				    PLAT_RESOURCE_TELEM_SSRAM_INDEX);
+	if (!res) {
+		dev_err(&pdev->dev, "Failed to get telemetry resource\n");
+		return -ENXIO;
+	}
 
-	res = telemetry_res + TELEMETRY_RESOURCE_PMC_SSRAM;
-	res->start = ipcdev.telem_pmc_ssram_base;
-	res->end = res->start + ipcdev.telem_pmc_ssram_size - 1;
+	telemetry_ipc_res[0].start = res->start + TELEM_PUNIT_SSRAM_OFFSET;
+	telemetry_ipc_res[0].end = res->start +
+		TELEM_PUNIT_SSRAM_OFFSET + TELEM_SSRAM_SIZE - 1;
+	telemetry_ipc_res[0].flags = IORESOURCE_MEM;
+	telemetry_ipc_res[1].start = res->start + TELEM_PMC_SSRAM_OFFSET;
+	telemetry_ipc_res[1].end = res->start +
+		TELEM_PMC_SSRAM_OFFSET + TELEM_SSRAM_SIZE - 1;
+	telemetry_ipc_res[1].flags = IORESOURCE_MEM;
 
-	pdev = platform_device_register_full(&pdevinfo);
-	if (IS_ERR(pdev))
-		return PTR_ERR(pdev);
+	dev_dbg(&pdev->dev, "Telemetry res 0: %pR\n", &telemetry_ipc_res[0]);
+	dev_dbg(&pdev->dev, "Telemetry res 1: %pR\n", &telemetry_ipc_res[1]);
 
-	ipcdev.telemetry_dev = pdev;
+	telemetry_cell.name = TELEMETRY_DEVICE_NAME;
+	telemetry_cell.num_resources = ARRAY_SIZE(telemetry_ipc_res);
+	telemetry_cell.resources = telemetry_ipc_res;
+	telemetry_cell.ignore_resource_conflicts = 1;
 
-	return 0;
+	return devm_mfd_add_devices(&pdev->dev, PLATFORM_DEVID_NONE,
+				    &telemetry_cell, 1, NULL, 0, NULL);
 }
 
-static int ipc_create_pmc_devices(void)
+static int ipc_create_pmc_devices(struct platform_device *pdev)
 {
 	int ret;
 
-	/* If we have ACPI based watchdog use that instead */
-	if (!acpi_has_watchdog()) {
-		ret = ipc_create_tco_device();
-		if (ret) {
-			dev_err(ipcdev.dev, "Failed to add tco platform device\n");
-			return ret;
-		}
-	}
+	ret = ipc_create_punit_device(pdev);
+	if (ret < 0)
+		return ret;
 
-	ret = ipc_create_punit_device();
-	if (ret) {
-		dev_err(ipcdev.dev, "Failed to add punit platform device\n");
-		platform_device_unregister(ipcdev.tco_dev);
-	}
+	ret = ipc_create_wdt_device(pdev);
+	if (ret < 0)
+		return ret;
 
-	if (!ipcdev.telem_res_inval) {
-		ret = ipc_create_telemetry_device();
-		if (ret)
-			dev_warn(ipcdev.dev,
-				"Failed to add telemetry platform device\n");
-	}
+	ret = ipc_create_telemetry_device(pdev);
+	if (ret < 0)
+		return ret;
 
-	return ret;
+	return 0;
 }
 
 static int ipc_plat_get_res(struct platform_device *pdev)
 {
-	struct resource *res, *punit_res;
+	struct resource *res;
 	void __iomem *addr;
-	int size;
-
-	res = platform_get_resource(pdev, IORESOURCE_IO,
-				    PLAT_RESOURCE_ACPI_IO_INDEX);
-	if (!res) {
-		dev_err(&pdev->dev, "Failed to get io resource\n");
-		return -ENXIO;
-	}
-	size = resource_size(res);
-	ipcdev.acpi_io_base = res->start;
-	ipcdev.acpi_io_size = size;
-	dev_info(&pdev->dev, "io res: %pR\n", res);
-
-	punit_res = punit_res_array;
-	/* This is index 0 to cover BIOS data register */
-	res = platform_get_resource(pdev, IORESOURCE_MEM,
-				    PLAT_RESOURCE_BIOS_DATA_INDEX);
-	if (!res) {
-		dev_err(&pdev->dev, "Failed to get res of punit BIOS data\n");
-		return -ENXIO;
-	}
-	*punit_res = *res;
-	dev_info(&pdev->dev, "punit BIOS data res: %pR\n", res);
-
-	/* This is index 1 to cover BIOS interface register */
-	res = platform_get_resource(pdev, IORESOURCE_MEM,
-				    PLAT_RESOURCE_BIOS_IFACE_INDEX);
-	if (!res) {
-		dev_err(&pdev->dev, "Failed to get res of punit BIOS iface\n");
-		return -ENXIO;
-	}
-	*++punit_res = *res;
-	dev_info(&pdev->dev, "punit BIOS interface res: %pR\n", res);
-
-	/* This is index 2 to cover ISP data register, optional */
-	res = platform_get_resource(pdev, IORESOURCE_MEM,
-				    PLAT_RESOURCE_ISP_DATA_INDEX);
-	++punit_res;
-	if (res) {
-		*punit_res = *res;
-		dev_info(&pdev->dev, "punit ISP data res: %pR\n", res);
-	}
-
-	/* This is index 3 to cover ISP interface register, optional */
-	res = platform_get_resource(pdev, IORESOURCE_MEM,
-				    PLAT_RESOURCE_ISP_IFACE_INDEX);
-	++punit_res;
-	if (res) {
-		*punit_res = *res;
-		dev_info(&pdev->dev, "punit ISP interface res: %pR\n", res);
-	}
-
-	/* This is index 4 to cover GTD data register, optional */
-	res = platform_get_resource(pdev, IORESOURCE_MEM,
-				    PLAT_RESOURCE_GTD_DATA_INDEX);
-	++punit_res;
-	if (res) {
-		*punit_res = *res;
-		dev_info(&pdev->dev, "punit GTD data res: %pR\n", res);
-	}
-
-	/* This is index 5 to cover GTD interface register, optional */
-	res = platform_get_resource(pdev, IORESOURCE_MEM,
-				    PLAT_RESOURCE_GTD_IFACE_INDEX);
-	++punit_res;
-	if (res) {
-		*punit_res = *res;
-		dev_info(&pdev->dev, "punit GTD interface res: %pR\n", res);
-	}
 
+	/* Get IPC resources */
 	res = platform_get_resource(pdev, IORESOURCE_MEM,
 				    PLAT_RESOURCE_IPC_INDEX);
 	if (!res) {
-		dev_err(&pdev->dev, "Failed to get ipc resource\n");
+		dev_err(&pdev->dev, "Failed to get IPC resources\n");
 		return -ENXIO;
 	}
-	size = PLAT_RESOURCE_IPC_SIZE + PLAT_RESOURCE_GCR_SIZE;
-	res->end = res->start + size - 1;
+
+	res->end = res->start +
+		   PLAT_RESOURCE_IPC_SIZE + PLAT_RESOURCE_GCR_SIZE - 1;
 
 	addr = devm_ioremap_resource(&pdev->dev, res);
 	if (IS_ERR(addr))
 		return PTR_ERR(addr);
 
 	ipcdev.ipc_base = addr;
-
 	ipcdev.gcr_mem_base = addr + PLAT_RESOURCE_GCR_OFFSET;
-	dev_info(&pdev->dev, "ipc res: %pR\n", res);
-
-	ipcdev.telem_res_inval = 0;
-	res = platform_get_resource(pdev, IORESOURCE_MEM,
-				    PLAT_RESOURCE_TELEM_SSRAM_INDEX);
-	if (!res) {
-		dev_err(&pdev->dev, "Failed to get telemetry ssram resource\n");
-		ipcdev.telem_res_inval = 1;
-	} else {
-		ipcdev.telem_punit_ssram_base = res->start +
-						TELEM_PUNIT_SSRAM_OFFSET;
-		ipcdev.telem_punit_ssram_size = TELEM_SSRAM_SIZE;
-		ipcdev.telem_pmc_ssram_base = res->start +
-						TELEM_PMC_SSRAM_OFFSET;
-		ipcdev.telem_pmc_ssram_size = TELEM_SSRAM_SIZE;
-		dev_info(&pdev->dev, "telemetry ssram res: %pR\n", res);
-	}
+	dev_dbg(&pdev->dev, "PMC IPC resource %pR\n", res);
 
 	return 0;
 }
@@ -911,7 +800,7 @@ static int ipc_plat_probe(struct platform_device *pdev)
 
 	ipcdev.irq = platform_get_irq(pdev, 0);
 	if (ipcdev.irq < 0) {
-		dev_err(&pdev->dev, "Failed to get irq\n");
+		dev_err(&pdev->dev, "Failed to get IRQ\n");
 		return -EINVAL;
 	}
 
@@ -921,47 +810,38 @@ static int ipc_plat_probe(struct platform_device *pdev)
 		return ret;
 	}
 
-	ret = ipc_create_pmc_devices();
+	ret = ipc_create_pmc_devices(pdev);
 	if (ret) {
-		dev_err(&pdev->dev, "Failed to create pmc devices\n");
+		dev_err(&pdev->dev, "Failed to create PMC devices\n");
 		return ret;
 	}
 
-	if (devm_request_irq(&pdev->dev, ipcdev.irq, ioc, IRQF_NO_SUSPEND,
-			     "intel_pmc_ipc", &ipcdev)) {
-		dev_err(&pdev->dev, "Failed to request irq\n");
-		ret = -EBUSY;
-		goto err_irq;
+	ret = devm_request_irq(&pdev->dev, ipcdev.irq, ioc, IRQF_NO_SUSPEND,
+			       "intel_pmc_ipc", &ipcdev);
+	if (ret) {
+		dev_err(&pdev->dev, "Failed to request IRQ\n");
+		return ret;
 	}
 
 	ret = sysfs_create_group(&pdev->dev.kobj, &intel_ipc_group);
 	if (ret) {
 		dev_err(&pdev->dev, "Failed to create sysfs group %d\n",
 			ret);
-		goto err_sys;
+		devm_free_irq(&pdev->dev, ipcdev.irq, &ipcdev);
+		return ret;
 	}
 
 	ipcdev.has_gcr_regs = true;
 
 	return 0;
-err_sys:
-	devm_free_irq(&pdev->dev, ipcdev.irq, &ipcdev);
-err_irq:
-	platform_device_unregister(ipcdev.tco_dev);
-	platform_device_unregister(ipcdev.punit_dev);
-	platform_device_unregister(ipcdev.telemetry_dev);
-
-	return ret;
 }
 
 static int ipc_plat_remove(struct platform_device *pdev)
 {
 	sysfs_remove_group(&pdev->dev.kobj, &intel_ipc_group);
 	devm_free_irq(&pdev->dev, ipcdev.irq, &ipcdev);
-	platform_device_unregister(ipcdev.tco_dev);
-	platform_device_unregister(ipcdev.punit_dev);
-	platform_device_unregister(ipcdev.telemetry_dev);
 	ipcdev.dev = NULL;
+
 	return 0;
 }
 
@@ -980,12 +860,12 @@ static int __init intel_pmc_ipc_init(void)
 
 	ret = platform_driver_register(&ipc_plat_driver);
 	if (ret) {
-		pr_err("Failed to register PMC ipc platform driver\n");
+		pr_err("Failed to register PMC IPC platform driver\n");
 		return ret;
 	}
 	ret = pci_register_driver(&ipc_pci_driver);
 	if (ret) {
-		pr_err("Failed to register PMC ipc pci driver\n");
+		pr_err("Failed to register PMC IPC PCI driver\n");
 		platform_driver_unregister(&ipc_plat_driver);
 		return ret;
 	}
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [RFC v8 2/7] platform/x86: intel_pmc_ipc: Use MFD framework to create dependent devices
@ 2017-10-29  9:49   ` sathyanarayanan.kuppuswamy
  0 siblings, 0 replies; 30+ messages in thread
From: sathyanarayanan.kuppuswamy @ 2017-10-29  9:49 UTC (permalink / raw)
  To: a.zummo, x86, wim, mingo, alexandre.belloni, qipeng.zha, hpa,
	dvhart, tglx, lee.jones, andy, souvik.k.chakravarty
  Cc: linux-rtc, linux-watchdog, linux-kernel, platform-driver-x86,
	sathyaosid, Kuppuswamy Sathyanarayanan, Andy Shevchenko

From: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>

Currently, we have lot of repetitive code in dependent device resource
allocation and device creation handling code. This logic can be improved if
we use MFD framework for dependent device creation. This patch adds this
support.

Signed-off-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>
Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
---
 drivers/platform/x86/intel_pmc_ipc.c | 398 ++++++++++++-----------------------
 1 file changed, 139 insertions(+), 259 deletions(-)

Changes since v7:
 * Fixed style issues.

Changes since v6:
 * Fixed style issues.
 * Used Andy's modified version.

Changes since v5:
 * Changed the order of patches in this patchlist.

Changes since v4:
 * Changed the order of patches in this patchlist.

Changes since v3:
 * Changed PLATFORM_DEVID_AUTO to PLATFORM_DEVID_NONE in mfd device creation.
 * Fixed error in resource initalization logic in ipc_create_punit_device.
 * Removed mfd cell id initialization.

diff --git a/drivers/platform/x86/intel_pmc_ipc.c b/drivers/platform/x86/intel_pmc_ipc.c
index e03fa314..e36144c 100644
--- a/drivers/platform/x86/intel_pmc_ipc.c
+++ b/drivers/platform/x86/intel_pmc_ipc.c
@@ -20,6 +20,7 @@
 #include <linux/errno.h>
 #include <linux/init.h>
 #include <linux/device.h>
+#include <linux/mfd/core.h>
 #include <linux/pm.h>
 #include <linux/pci.h>
 #include <linux/platform_device.h>
@@ -88,6 +89,7 @@
 #define PLAT_RESOURCE_ISP_IFACE_INDEX	5
 #define PLAT_RESOURCE_GTD_DATA_INDEX	6
 #define PLAT_RESOURCE_GTD_IFACE_INDEX	7
+#define PLAT_RESOURCE_MEM_MAX_INDEX	8
 #define PLAT_RESOURCE_ACPI_IO_INDEX	0
 
 /*
@@ -106,8 +108,6 @@
 #define TELEM_SSRAM_SIZE		240
 #define TELEM_PMC_SSRAM_OFFSET		0x1B00
 #define TELEM_PUNIT_SSRAM_OFFSET	0x1A00
-#define TCO_PMC_OFFSET			0x8
-#define TCO_PMC_SIZE			0x4
 
 /* PMC register bit definitions */
 
@@ -124,26 +124,10 @@ static struct intel_pmc_ipc_dev {
 	int cmd;
 	struct completion cmd_complete;
 
-	/* The following PMC BARs share the same ACPI device with the IPC */
-	resource_size_t acpi_io_base;
-	int acpi_io_size;
-	struct platform_device *tco_dev;
-
 	/* gcr */
 	void __iomem *gcr_mem_base;
 	bool has_gcr_regs;
 	spinlock_t gcr_lock;
-
-	/* punit */
-	struct platform_device *punit_dev;
-
-	/* Telemetry */
-	resource_size_t telem_pmc_ssram_base;
-	resource_size_t telem_punit_ssram_base;
-	int telem_pmc_ssram_size;
-	int telem_punit_ssram_size;
-	u8 telem_res_inval;
-	struct platform_device *telemetry_dev;
 } ipcdev;
 
 static char *ipc_err_sources[] = {
@@ -508,7 +492,7 @@ static int ipc_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 	ret = devm_request_irq(&pdev->dev, pdev->irq, ioc, 0, "intel_pmc_ipc",
 				pmc);
 	if (ret) {
-		dev_err(&pdev->dev, "Failed to request irq\n");
+		dev_err(&pdev->dev, "Failed to request IRQ\n");
 		return ret;
 	}
 
@@ -593,44 +577,6 @@ static const struct attribute_group intel_ipc_group = {
 	.attrs = intel_ipc_attrs,
 };
 
-static struct resource punit_res_array[] = {
-	/* Punit BIOS */
-	{
-		.flags = IORESOURCE_MEM,
-	},
-	{
-		.flags = IORESOURCE_MEM,
-	},
-	/* Punit ISP */
-	{
-		.flags = IORESOURCE_MEM,
-	},
-	{
-		.flags = IORESOURCE_MEM,
-	},
-	/* Punit GTD */
-	{
-		.flags = IORESOURCE_MEM,
-	},
-	{
-		.flags = IORESOURCE_MEM,
-	},
-};
-
-#define TCO_RESOURCE_ACPI_IO		0
-#define TCO_RESOURCE_SMI_EN_IO		1
-#define TCO_RESOURCE_GCR_MEM		2
-static struct resource tco_res[] = {
-	/* ACPI - TCO */
-	{
-		.flags = IORESOURCE_IO,
-	},
-	/* ACPI - SMI */
-	{
-		.flags = IORESOURCE_IO,
-	},
-};
-
 static struct itco_wdt_platform_data tco_info = {
 	.name = "Apollo Lake SoC",
 	.version = 5,
@@ -638,234 +584,177 @@ static struct itco_wdt_platform_data tco_info = {
 	.update_no_reboot_bit = update_no_reboot_bit,
 };
 
-#define TELEMETRY_RESOURCE_PUNIT_SSRAM	0
-#define TELEMETRY_RESOURCE_PMC_SSRAM	1
-static struct resource telemetry_res[] = {
-	/*Telemetry*/
-	{
-		.flags = IORESOURCE_MEM,
-	},
-	{
-		.flags = IORESOURCE_MEM,
-	},
-};
-
-static int ipc_create_punit_device(void)
+static int ipc_create_punit_device(struct platform_device *pdev)
 {
-	struct platform_device *pdev;
-	const struct platform_device_info pdevinfo = {
-		.parent = ipcdev.dev,
-		.name = PUNIT_DEVICE_NAME,
-		.id = -1,
-		.res = punit_res_array,
-		.num_res = ARRAY_SIZE(punit_res_array),
+	struct resource punit_res[PLAT_RESOURCE_MEM_MAX_INDEX];
+	struct mfd_cell punit_cell;
+	struct resource *res;
+	int mindex, pindex = 0;
+
+	for (mindex = 0; mindex <= PLAT_RESOURCE_MEM_MAX_INDEX; mindex++) {
+
+		res = platform_get_resource(pdev, IORESOURCE_MEM, mindex);
+
+		switch (mindex) {
+		/* Get PUNIT resources */
+		case PLAT_RESOURCE_BIOS_DATA_INDEX:
+		case PLAT_RESOURCE_BIOS_IFACE_INDEX:
+			/* BIOS resources are required, so return error if not
+			 * available
+			 */
+			if (!res) {
+				dev_err(&pdev->dev,
+					"Failed to get PUNIT MEM resource %d\n",
+					pindex);
+				return -ENXIO;
+			}
+		case PLAT_RESOURCE_ISP_DATA_INDEX:
+		case PLAT_RESOURCE_ISP_IFACE_INDEX:
+		case PLAT_RESOURCE_GTD_DATA_INDEX:
+		case PLAT_RESOURCE_GTD_IFACE_INDEX:
+			/* if valid resource found, copy the resource to PUNIT
+			 * resource
+			 */
+			if (res)
+				memcpy(&punit_res[pindex], res, sizeof(*res));
+			punit_res[pindex].flags = IORESOURCE_MEM;
+			dev_dbg(&pdev->dev, "PUNIT memory res: %pR\n",
+				&punit_res[pindex]);
+			pindex++;
+			break;
 		};
+	}
 
-	pdev = platform_device_register_full(&pdevinfo);
-	if (IS_ERR(pdev))
-		return PTR_ERR(pdev);
-
-	ipcdev.punit_dev = pdev;
+	/* Create PUNIT IPC MFD cell */
+	punit_cell.name = PUNIT_DEVICE_NAME;
+	punit_cell.num_resources = ARRAY_SIZE(punit_res);
+	punit_cell.resources = punit_res;
+	punit_cell.ignore_resource_conflicts = 1;
 
-	return 0;
+	return devm_mfd_add_devices(&pdev->dev, PLATFORM_DEVID_NONE,
+				    &punit_cell, 1, NULL, 0, NULL);
 }
 
-static int ipc_create_tco_device(void)
+static int ipc_create_wdt_device(struct platform_device *pdev)
 {
-	struct platform_device *pdev;
+	static struct resource wdt_ipc_res[2];
 	struct resource *res;
-	const struct platform_device_info pdevinfo = {
-		.parent = ipcdev.dev,
-		.name = TCO_DEVICE_NAME,
-		.id = -1,
-		.res = tco_res,
-		.num_res = ARRAY_SIZE(tco_res),
-		.data = &tco_info,
-		.size_data = sizeof(tco_info),
-		};
+	static struct mfd_cell wdt_cell;
 
-	res = tco_res + TCO_RESOURCE_ACPI_IO;
-	res->start = ipcdev.acpi_io_base + TCO_BASE_OFFSET;
-	res->end = res->start + TCO_REGS_SIZE - 1;
+	/* If we have ACPI based watchdog use that instead, othewise create
+	 * a MFD cell for iTCO watchdog
+	 */
+	if (acpi_has_watchdog())
+		return 0;
 
-	res = tco_res + TCO_RESOURCE_SMI_EN_IO;
-	res->start = ipcdev.acpi_io_base + SMI_EN_OFFSET;
-	res->end = res->start + SMI_EN_SIZE - 1;
+	/* Get iTCO watchdog resources */
+	res = platform_get_resource(pdev, IORESOURCE_IO,
+				    PLAT_RESOURCE_ACPI_IO_INDEX);
+	if (!res) {
+		dev_err(&pdev->dev, "Failed to get WDT resource\n");
+		return -ENXIO;
+	}
 
-	pdev = platform_device_register_full(&pdevinfo);
-	if (IS_ERR(pdev))
-		return PTR_ERR(pdev);
+	wdt_ipc_res[0].start = res->start + TCO_BASE_OFFSET;
+	wdt_ipc_res[0].end = res->start +
+		TCO_BASE_OFFSET + TCO_REGS_SIZE - 1;
+	wdt_ipc_res[0].flags = IORESOURCE_IO;
+	wdt_ipc_res[1].start = res->start + SMI_EN_OFFSET;
+	wdt_ipc_res[1].end = res->start +
+		SMI_EN_OFFSET + SMI_EN_SIZE - 1;
+	wdt_ipc_res[1].flags = IORESOURCE_IO;
 
-	ipcdev.tco_dev = pdev;
+	dev_dbg(&pdev->dev, "watchdog res 0: %pR\n", &wdt_ipc_res[0]);
+	dev_dbg(&pdev->dev, "watchdog res 1: %pR\n", &wdt_ipc_res[1]);
 
-	return 0;
+	wdt_cell.name = TCO_DEVICE_NAME;
+	wdt_cell.platform_data = &tco_info;
+	wdt_cell.pdata_size = sizeof(tco_info);
+	wdt_cell.num_resources = ARRAY_SIZE(wdt_ipc_res);
+	wdt_cell.resources = wdt_ipc_res;
+	wdt_cell.ignore_resource_conflicts = 1;
+
+	return devm_mfd_add_devices(&pdev->dev, PLATFORM_DEVID_NONE,
+				    &wdt_cell, 1, NULL, 0, NULL);
 }
 
-static int ipc_create_telemetry_device(void)
+static int ipc_create_telemetry_device(struct platform_device *pdev)
 {
-	struct platform_device *pdev;
+	struct resource telemetry_ipc_res[2];
+	struct mfd_cell telemetry_cell;
 	struct resource *res;
-	const struct platform_device_info pdevinfo = {
-		.parent = ipcdev.dev,
-		.name = TELEMETRY_DEVICE_NAME,
-		.id = -1,
-		.res = telemetry_res,
-		.num_res = ARRAY_SIZE(telemetry_res),
-		};
 
-	res = telemetry_res + TELEMETRY_RESOURCE_PUNIT_SSRAM;
-	res->start = ipcdev.telem_punit_ssram_base;
-	res->end = res->start + ipcdev.telem_punit_ssram_size - 1;
+	/* Get telemetry resources */
+	res = platform_get_resource(pdev, IORESOURCE_MEM,
+				    PLAT_RESOURCE_TELEM_SSRAM_INDEX);
+	if (!res) {
+		dev_err(&pdev->dev, "Failed to get telemetry resource\n");
+		return -ENXIO;
+	}
 
-	res = telemetry_res + TELEMETRY_RESOURCE_PMC_SSRAM;
-	res->start = ipcdev.telem_pmc_ssram_base;
-	res->end = res->start + ipcdev.telem_pmc_ssram_size - 1;
+	telemetry_ipc_res[0].start = res->start + TELEM_PUNIT_SSRAM_OFFSET;
+	telemetry_ipc_res[0].end = res->start +
+		TELEM_PUNIT_SSRAM_OFFSET + TELEM_SSRAM_SIZE - 1;
+	telemetry_ipc_res[0].flags = IORESOURCE_MEM;
+	telemetry_ipc_res[1].start = res->start + TELEM_PMC_SSRAM_OFFSET;
+	telemetry_ipc_res[1].end = res->start +
+		TELEM_PMC_SSRAM_OFFSET + TELEM_SSRAM_SIZE - 1;
+	telemetry_ipc_res[1].flags = IORESOURCE_MEM;
 
-	pdev = platform_device_register_full(&pdevinfo);
-	if (IS_ERR(pdev))
-		return PTR_ERR(pdev);
+	dev_dbg(&pdev->dev, "Telemetry res 0: %pR\n", &telemetry_ipc_res[0]);
+	dev_dbg(&pdev->dev, "Telemetry res 1: %pR\n", &telemetry_ipc_res[1]);
 
-	ipcdev.telemetry_dev = pdev;
+	telemetry_cell.name = TELEMETRY_DEVICE_NAME;
+	telemetry_cell.num_resources = ARRAY_SIZE(telemetry_ipc_res);
+	telemetry_cell.resources = telemetry_ipc_res;
+	telemetry_cell.ignore_resource_conflicts = 1;
 
-	return 0;
+	return devm_mfd_add_devices(&pdev->dev, PLATFORM_DEVID_NONE,
+				    &telemetry_cell, 1, NULL, 0, NULL);
 }
 
-static int ipc_create_pmc_devices(void)
+static int ipc_create_pmc_devices(struct platform_device *pdev)
 {
 	int ret;
 
-	/* If we have ACPI based watchdog use that instead */
-	if (!acpi_has_watchdog()) {
-		ret = ipc_create_tco_device();
-		if (ret) {
-			dev_err(ipcdev.dev, "Failed to add tco platform device\n");
-			return ret;
-		}
-	}
+	ret = ipc_create_punit_device(pdev);
+	if (ret < 0)
+		return ret;
 
-	ret = ipc_create_punit_device();
-	if (ret) {
-		dev_err(ipcdev.dev, "Failed to add punit platform device\n");
-		platform_device_unregister(ipcdev.tco_dev);
-	}
+	ret = ipc_create_wdt_device(pdev);
+	if (ret < 0)
+		return ret;
 
-	if (!ipcdev.telem_res_inval) {
-		ret = ipc_create_telemetry_device();
-		if (ret)
-			dev_warn(ipcdev.dev,
-				"Failed to add telemetry platform device\n");
-	}
+	ret = ipc_create_telemetry_device(pdev);
+	if (ret < 0)
+		return ret;
 
-	return ret;
+	return 0;
 }
 
 static int ipc_plat_get_res(struct platform_device *pdev)
 {
-	struct resource *res, *punit_res;
+	struct resource *res;
 	void __iomem *addr;
-	int size;
-
-	res = platform_get_resource(pdev, IORESOURCE_IO,
-				    PLAT_RESOURCE_ACPI_IO_INDEX);
-	if (!res) {
-		dev_err(&pdev->dev, "Failed to get io resource\n");
-		return -ENXIO;
-	}
-	size = resource_size(res);
-	ipcdev.acpi_io_base = res->start;
-	ipcdev.acpi_io_size = size;
-	dev_info(&pdev->dev, "io res: %pR\n", res);
-
-	punit_res = punit_res_array;
-	/* This is index 0 to cover BIOS data register */
-	res = platform_get_resource(pdev, IORESOURCE_MEM,
-				    PLAT_RESOURCE_BIOS_DATA_INDEX);
-	if (!res) {
-		dev_err(&pdev->dev, "Failed to get res of punit BIOS data\n");
-		return -ENXIO;
-	}
-	*punit_res = *res;
-	dev_info(&pdev->dev, "punit BIOS data res: %pR\n", res);
-
-	/* This is index 1 to cover BIOS interface register */
-	res = platform_get_resource(pdev, IORESOURCE_MEM,
-				    PLAT_RESOURCE_BIOS_IFACE_INDEX);
-	if (!res) {
-		dev_err(&pdev->dev, "Failed to get res of punit BIOS iface\n");
-		return -ENXIO;
-	}
-	*++punit_res = *res;
-	dev_info(&pdev->dev, "punit BIOS interface res: %pR\n", res);
-
-	/* This is index 2 to cover ISP data register, optional */
-	res = platform_get_resource(pdev, IORESOURCE_MEM,
-				    PLAT_RESOURCE_ISP_DATA_INDEX);
-	++punit_res;
-	if (res) {
-		*punit_res = *res;
-		dev_info(&pdev->dev, "punit ISP data res: %pR\n", res);
-	}
-
-	/* This is index 3 to cover ISP interface register, optional */
-	res = platform_get_resource(pdev, IORESOURCE_MEM,
-				    PLAT_RESOURCE_ISP_IFACE_INDEX);
-	++punit_res;
-	if (res) {
-		*punit_res = *res;
-		dev_info(&pdev->dev, "punit ISP interface res: %pR\n", res);
-	}
-
-	/* This is index 4 to cover GTD data register, optional */
-	res = platform_get_resource(pdev, IORESOURCE_MEM,
-				    PLAT_RESOURCE_GTD_DATA_INDEX);
-	++punit_res;
-	if (res) {
-		*punit_res = *res;
-		dev_info(&pdev->dev, "punit GTD data res: %pR\n", res);
-	}
-
-	/* This is index 5 to cover GTD interface register, optional */
-	res = platform_get_resource(pdev, IORESOURCE_MEM,
-				    PLAT_RESOURCE_GTD_IFACE_INDEX);
-	++punit_res;
-	if (res) {
-		*punit_res = *res;
-		dev_info(&pdev->dev, "punit GTD interface res: %pR\n", res);
-	}
 
+	/* Get IPC resources */
 	res = platform_get_resource(pdev, IORESOURCE_MEM,
 				    PLAT_RESOURCE_IPC_INDEX);
 	if (!res) {
-		dev_err(&pdev->dev, "Failed to get ipc resource\n");
+		dev_err(&pdev->dev, "Failed to get IPC resources\n");
 		return -ENXIO;
 	}
-	size = PLAT_RESOURCE_IPC_SIZE + PLAT_RESOURCE_GCR_SIZE;
-	res->end = res->start + size - 1;
+
+	res->end = res->start +
+		   PLAT_RESOURCE_IPC_SIZE + PLAT_RESOURCE_GCR_SIZE - 1;
 
 	addr = devm_ioremap_resource(&pdev->dev, res);
 	if (IS_ERR(addr))
 		return PTR_ERR(addr);
 
 	ipcdev.ipc_base = addr;
-
 	ipcdev.gcr_mem_base = addr + PLAT_RESOURCE_GCR_OFFSET;
-	dev_info(&pdev->dev, "ipc res: %pR\n", res);
-
-	ipcdev.telem_res_inval = 0;
-	res = platform_get_resource(pdev, IORESOURCE_MEM,
-				    PLAT_RESOURCE_TELEM_SSRAM_INDEX);
-	if (!res) {
-		dev_err(&pdev->dev, "Failed to get telemetry ssram resource\n");
-		ipcdev.telem_res_inval = 1;
-	} else {
-		ipcdev.telem_punit_ssram_base = res->start +
-						TELEM_PUNIT_SSRAM_OFFSET;
-		ipcdev.telem_punit_ssram_size = TELEM_SSRAM_SIZE;
-		ipcdev.telem_pmc_ssram_base = res->start +
-						TELEM_PMC_SSRAM_OFFSET;
-		ipcdev.telem_pmc_ssram_size = TELEM_SSRAM_SIZE;
-		dev_info(&pdev->dev, "telemetry ssram res: %pR\n", res);
-	}
+	dev_dbg(&pdev->dev, "PMC IPC resource %pR\n", res);
 
 	return 0;
 }
@@ -911,7 +800,7 @@ static int ipc_plat_probe(struct platform_device *pdev)
 
 	ipcdev.irq = platform_get_irq(pdev, 0);
 	if (ipcdev.irq < 0) {
-		dev_err(&pdev->dev, "Failed to get irq\n");
+		dev_err(&pdev->dev, "Failed to get IRQ\n");
 		return -EINVAL;
 	}
 
@@ -921,47 +810,38 @@ static int ipc_plat_probe(struct platform_device *pdev)
 		return ret;
 	}
 
-	ret = ipc_create_pmc_devices();
+	ret = ipc_create_pmc_devices(pdev);
 	if (ret) {
-		dev_err(&pdev->dev, "Failed to create pmc devices\n");
+		dev_err(&pdev->dev, "Failed to create PMC devices\n");
 		return ret;
 	}
 
-	if (devm_request_irq(&pdev->dev, ipcdev.irq, ioc, IRQF_NO_SUSPEND,
-			     "intel_pmc_ipc", &ipcdev)) {
-		dev_err(&pdev->dev, "Failed to request irq\n");
-		ret = -EBUSY;
-		goto err_irq;
+	ret = devm_request_irq(&pdev->dev, ipcdev.irq, ioc, IRQF_NO_SUSPEND,
+			       "intel_pmc_ipc", &ipcdev);
+	if (ret) {
+		dev_err(&pdev->dev, "Failed to request IRQ\n");
+		return ret;
 	}
 
 	ret = sysfs_create_group(&pdev->dev.kobj, &intel_ipc_group);
 	if (ret) {
 		dev_err(&pdev->dev, "Failed to create sysfs group %d\n",
 			ret);
-		goto err_sys;
+		devm_free_irq(&pdev->dev, ipcdev.irq, &ipcdev);
+		return ret;
 	}
 
 	ipcdev.has_gcr_regs = true;
 
 	return 0;
-err_sys:
-	devm_free_irq(&pdev->dev, ipcdev.irq, &ipcdev);
-err_irq:
-	platform_device_unregister(ipcdev.tco_dev);
-	platform_device_unregister(ipcdev.punit_dev);
-	platform_device_unregister(ipcdev.telemetry_dev);
-
-	return ret;
 }
 
 static int ipc_plat_remove(struct platform_device *pdev)
 {
 	sysfs_remove_group(&pdev->dev.kobj, &intel_ipc_group);
 	devm_free_irq(&pdev->dev, ipcdev.irq, &ipcdev);
-	platform_device_unregister(ipcdev.tco_dev);
-	platform_device_unregister(ipcdev.punit_dev);
-	platform_device_unregister(ipcdev.telemetry_dev);
 	ipcdev.dev = NULL;
+
 	return 0;
 }
 
@@ -980,12 +860,12 @@ static int __init intel_pmc_ipc_init(void)
 
 	ret = platform_driver_register(&ipc_plat_driver);
 	if (ret) {
-		pr_err("Failed to register PMC ipc platform driver\n");
+		pr_err("Failed to register PMC IPC platform driver\n");
 		return ret;
 	}
 	ret = pci_register_driver(&ipc_pci_driver);
 	if (ret) {
-		pr_err("Failed to register PMC ipc pci driver\n");
+		pr_err("Failed to register PMC IPC PCI driver\n");
 		platform_driver_unregister(&ipc_plat_driver);
 		return ret;
 	}
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [RFC v8 3/7] platform/x86: intel_pmc_ipc: Use regmap calls for GCR updates
  2017-10-29  9:49 ` sathyanarayanan.kuppuswamy
@ 2017-10-29  9:49   ` sathyanarayanan.kuppuswamy
  -1 siblings, 0 replies; 30+ messages in thread
From: sathyanarayanan.kuppuswamy @ 2017-10-29  9:49 UTC (permalink / raw)
  To: a.zummo, x86, wim, mingo, alexandre.belloni, qipeng.zha, hpa,
	dvhart, tglx, lee.jones, andy, souvik.k.chakravarty
  Cc: linux-rtc, linux-watchdog, linux-kernel, platform-driver-x86,
	sathyaosid, Kuppuswamy Sathyanarayanan

From: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>

This patch adds support for regmap based implementation for GCR
read/write/update APIs.

Signed-off-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>
---
 drivers/platform/x86/Kconfig         |   1 +
 drivers/platform/x86/intel_pmc_ipc.c | 122 +++++++++++++----------------------
 2 files changed, 46 insertions(+), 77 deletions(-)

Changes since v7:
 * Fixed style issues.

Changes since v6:
 * None

Changes since v5:
 * None

Changes since v4:
 * None

diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
index 80b8795..45f4e79 100644
--- a/drivers/platform/x86/Kconfig
+++ b/drivers/platform/x86/Kconfig
@@ -1054,6 +1054,7 @@ config PVPANIC
 config INTEL_PMC_IPC
 	tristate "Intel PMC IPC Driver"
 	depends on ACPI
+	select REGMAP_MMIO
 	---help---
 	This driver provides support for PMC control on some Intel platforms.
 	The PMC is an ARC processor which defines IPC commands for communication
diff --git a/drivers/platform/x86/intel_pmc_ipc.c b/drivers/platform/x86/intel_pmc_ipc.c
index e36144c..df6af1f 100644
--- a/drivers/platform/x86/intel_pmc_ipc.c
+++ b/drivers/platform/x86/intel_pmc_ipc.c
@@ -35,6 +35,8 @@
 #include <linux/acpi.h>
 #include <linux/io-64-nonatomic-lo-hi.h>
 #include <linux/spinlock.h>
+#include <linux/mfd/core.h>
+#include <linux/regmap.h>
 
 #include <asm/intel_pmc_ipc.h>
 
@@ -126,8 +128,7 @@ static struct intel_pmc_ipc_dev {
 
 	/* gcr */
 	void __iomem *gcr_mem_base;
-	bool has_gcr_regs;
-	spinlock_t gcr_lock;
+	struct regmap *gcr_regs;
 } ipcdev;
 
 static char *ipc_err_sources[] = {
@@ -149,6 +150,15 @@ static char *ipc_err_sources[] = {
 		"Unsigned kernel",
 };
 
+static struct regmap_config gcr_regmap_config = {
+	.name = "intel_pmc_gcr",
+	.reg_bits = 32,
+	.reg_stride = 4,
+	.val_bits = 32,
+	.fast_io = true,
+	.max_register = PLAT_RESOURCE_GCR_SIZE,
+};
+
 /* Prevent concurrent calls to the PMC */
 static DEFINE_MUTEX(ipclock);
 
@@ -182,21 +192,6 @@ static inline u32 ipc_data_readl(u32 offset)
 	return readl(ipcdev.ipc_base + IPC_READ_BUFFER + offset);
 }
 
-static inline u64 gcr_data_readq(u32 offset)
-{
-	return readq(ipcdev.gcr_mem_base + offset);
-}
-
-static inline int is_gcr_valid(u32 offset)
-{
-	if (!ipcdev.has_gcr_regs)
-		return -EACCES;
-
-	if (offset > PLAT_RESOURCE_GCR_SIZE)
-		return -EINVAL;
-
-	return 0;
-}
 
 /**
  * intel_pmc_gcr_read() - Read PMC GCR register
@@ -209,21 +204,12 @@ static inline int is_gcr_valid(u32 offset)
  */
 int intel_pmc_gcr_read(u32 offset, u32 *data)
 {
-	int ret;
-
-	spin_lock(&ipcdev.gcr_lock);
-
-	ret = is_gcr_valid(offset);
-	if (ret < 0) {
-		spin_unlock(&ipcdev.gcr_lock);
-		return ret;
-	}
-
-	*data = readl(ipcdev.gcr_mem_base + offset);
+	struct intel_pmc_ipc_dev *pmc = &ipcdev;
 
-	spin_unlock(&ipcdev.gcr_lock);
+	if (!pmc->gcr_regs)
+		return -EACCES;
 
-	return 0;
+	return regmap_read(pmc->gcr_regs, offset, data);
 }
 EXPORT_SYMBOL_GPL(intel_pmc_gcr_read);
 
@@ -239,21 +225,12 @@ EXPORT_SYMBOL_GPL(intel_pmc_gcr_read);
  */
 int intel_pmc_gcr_write(u32 offset, u32 data)
 {
-	int ret;
-
-	spin_lock(&ipcdev.gcr_lock);
-
-	ret = is_gcr_valid(offset);
-	if (ret < 0) {
-		spin_unlock(&ipcdev.gcr_lock);
-		return ret;
-	}
-
-	writel(data, ipcdev.gcr_mem_base + offset);
+	struct intel_pmc_ipc_dev *pmc = &ipcdev;
 
-	spin_unlock(&ipcdev.gcr_lock);
+	if (!pmc->gcr_regs)
+		return -EACCES;
 
-	return 0;
+	return regmap_write(pmc->gcr_regs, offset, data);
 }
 EXPORT_SYMBOL_GPL(intel_pmc_gcr_write);
 
@@ -270,33 +247,12 @@ EXPORT_SYMBOL_GPL(intel_pmc_gcr_write);
  */
 int intel_pmc_gcr_update(u32 offset, u32 mask, u32 val)
 {
-	u32 new_val;
-	int ret = 0;
-
-	spin_lock(&ipcdev.gcr_lock);
-
-	ret = is_gcr_valid(offset);
-	if (ret < 0)
-		goto gcr_ipc_unlock;
-
-	new_val = readl(ipcdev.gcr_mem_base + offset);
-
-	new_val &= ~mask;
-	new_val |= val & mask;
-
-	writel(new_val, ipcdev.gcr_mem_base + offset);
-
-	new_val = readl(ipcdev.gcr_mem_base + offset);
+	struct intel_pmc_ipc_dev *pmc = &ipcdev;
 
-	/* check whether the bit update is successful */
-	if ((new_val & mask) != (val & mask)) {
-		ret = -EIO;
-		goto gcr_ipc_unlock;
-	}
+	if (!pmc->gcr_regs)
+		return -EACCES;
 
-gcr_ipc_unlock:
-	spin_unlock(&ipcdev.gcr_lock);
-	return ret;
+	return regmap_update_bits(pmc->gcr_regs, offset, mask, val);
 }
 EXPORT_SYMBOL_GPL(intel_pmc_gcr_update);
 
@@ -475,8 +431,6 @@ static int ipc_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 
 	pmc->irq_mode = IPC_TRIGGER_MODE_IRQ;
 
-	spin_lock_init(&ipcdev.gcr_lock);
-
 	ret = pcim_enable_device(pdev);
 	if (ret)
 		return ret;
@@ -767,17 +721,26 @@ static int ipc_plat_get_res(struct platform_device *pdev)
  */
 int intel_pmc_s0ix_counter_read(u64 *data)
 {
+	struct intel_pmc_ipc_dev *pmc = &ipcdev;
 	u64 deep, shlw;
+	int ret;
 
-	if (!ipcdev.has_gcr_regs)
+	if (!pmc->gcr_regs)
 		return -EACCES;
 
-	deep = gcr_data_readq(PMC_GCR_TELEM_DEEP_S0IX_REG);
-	shlw = gcr_data_readq(PMC_GCR_TELEM_SHLW_S0IX_REG);
+	ret = regmap_bulk_read(pmc->gcr_regs, PMC_GCR_TELEM_DEEP_S0IX_REG,
+			       &deep, 2);
+	if (ret)
+		return ret;
+
+	ret = regmap_bulk_read(pmc->gcr_regs, PMC_GCR_TELEM_SHLW_S0IX_REG,
+			       &shlw, 2);
+	if (ret)
+		return ret;
 
 	*data = S0IX_RESIDENCY_IN_USECS(deep, shlw);
 
-	return 0;
+	return ret;
 }
 EXPORT_SYMBOL_GPL(intel_pmc_s0ix_counter_read);
 
@@ -796,7 +759,6 @@ static int ipc_plat_probe(struct platform_device *pdev)
 	ipcdev.dev = &pdev->dev;
 	ipcdev.irq_mode = IPC_TRIGGER_MODE_IRQ;
 	init_completion(&ipcdev.cmd_complete);
-	spin_lock_init(&ipcdev.gcr_lock);
 
 	ipcdev.irq = platform_get_irq(pdev, 0);
 	if (ipcdev.irq < 0) {
@@ -810,6 +772,14 @@ static int ipc_plat_probe(struct platform_device *pdev)
 		return ret;
 	}
 
+	ipcdev.gcr_regs = devm_regmap_init_mmio_clk(ipcdev.dev, NULL,
+						    ipcdev.gcr_mem_base,
+						    &gcr_regmap_config);
+	if (IS_ERR(ipcdev.gcr_regs)) {
+		dev_err(ipcdev.dev, "gcr_regs regmap init failed\n");
+		return PTR_ERR(ipcdev.gcr_regs);
+	}
+
 	ret = ipc_create_pmc_devices(pdev);
 	if (ret) {
 		dev_err(&pdev->dev, "Failed to create PMC devices\n");
@@ -831,8 +801,6 @@ static int ipc_plat_probe(struct platform_device *pdev)
 		return ret;
 	}
 
-	ipcdev.has_gcr_regs = true;
-
 	return 0;
 }
 
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [RFC v8 3/7] platform/x86: intel_pmc_ipc: Use regmap calls for GCR updates
@ 2017-10-29  9:49   ` sathyanarayanan.kuppuswamy
  0 siblings, 0 replies; 30+ messages in thread
From: sathyanarayanan.kuppuswamy @ 2017-10-29  9:49 UTC (permalink / raw)
  To: a.zummo, x86, wim, mingo, alexandre.belloni, qipeng.zha, hpa,
	dvhart, tglx, lee.jones, andy, souvik.k.chakravarty
  Cc: linux-rtc, linux-watchdog, linux-kernel, platform-driver-x86,
	sathyaosid, Kuppuswamy Sathyanarayanan

From: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>

This patch adds support for regmap based implementation for GCR
read/write/update APIs.

Signed-off-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>
---
 drivers/platform/x86/Kconfig         |   1 +
 drivers/platform/x86/intel_pmc_ipc.c | 122 +++++++++++++----------------------
 2 files changed, 46 insertions(+), 77 deletions(-)

Changes since v7:
 * Fixed style issues.

Changes since v6:
 * None

Changes since v5:
 * None

Changes since v4:
 * None

diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
index 80b8795..45f4e79 100644
--- a/drivers/platform/x86/Kconfig
+++ b/drivers/platform/x86/Kconfig
@@ -1054,6 +1054,7 @@ config PVPANIC
 config INTEL_PMC_IPC
 	tristate "Intel PMC IPC Driver"
 	depends on ACPI
+	select REGMAP_MMIO
 	---help---
 	This driver provides support for PMC control on some Intel platforms.
 	The PMC is an ARC processor which defines IPC commands for communication
diff --git a/drivers/platform/x86/intel_pmc_ipc.c b/drivers/platform/x86/intel_pmc_ipc.c
index e36144c..df6af1f 100644
--- a/drivers/platform/x86/intel_pmc_ipc.c
+++ b/drivers/platform/x86/intel_pmc_ipc.c
@@ -35,6 +35,8 @@
 #include <linux/acpi.h>
 #include <linux/io-64-nonatomic-lo-hi.h>
 #include <linux/spinlock.h>
+#include <linux/mfd/core.h>
+#include <linux/regmap.h>
 
 #include <asm/intel_pmc_ipc.h>
 
@@ -126,8 +128,7 @@ static struct intel_pmc_ipc_dev {
 
 	/* gcr */
 	void __iomem *gcr_mem_base;
-	bool has_gcr_regs;
-	spinlock_t gcr_lock;
+	struct regmap *gcr_regs;
 } ipcdev;
 
 static char *ipc_err_sources[] = {
@@ -149,6 +150,15 @@ static char *ipc_err_sources[] = {
 		"Unsigned kernel",
 };
 
+static struct regmap_config gcr_regmap_config = {
+	.name = "intel_pmc_gcr",
+	.reg_bits = 32,
+	.reg_stride = 4,
+	.val_bits = 32,
+	.fast_io = true,
+	.max_register = PLAT_RESOURCE_GCR_SIZE,
+};
+
 /* Prevent concurrent calls to the PMC */
 static DEFINE_MUTEX(ipclock);
 
@@ -182,21 +192,6 @@ static inline u32 ipc_data_readl(u32 offset)
 	return readl(ipcdev.ipc_base + IPC_READ_BUFFER + offset);
 }
 
-static inline u64 gcr_data_readq(u32 offset)
-{
-	return readq(ipcdev.gcr_mem_base + offset);
-}
-
-static inline int is_gcr_valid(u32 offset)
-{
-	if (!ipcdev.has_gcr_regs)
-		return -EACCES;
-
-	if (offset > PLAT_RESOURCE_GCR_SIZE)
-		return -EINVAL;
-
-	return 0;
-}
 
 /**
  * intel_pmc_gcr_read() - Read PMC GCR register
@@ -209,21 +204,12 @@ static inline int is_gcr_valid(u32 offset)
  */
 int intel_pmc_gcr_read(u32 offset, u32 *data)
 {
-	int ret;
-
-	spin_lock(&ipcdev.gcr_lock);
-
-	ret = is_gcr_valid(offset);
-	if (ret < 0) {
-		spin_unlock(&ipcdev.gcr_lock);
-		return ret;
-	}
-
-	*data = readl(ipcdev.gcr_mem_base + offset);
+	struct intel_pmc_ipc_dev *pmc = &ipcdev;
 
-	spin_unlock(&ipcdev.gcr_lock);
+	if (!pmc->gcr_regs)
+		return -EACCES;
 
-	return 0;
+	return regmap_read(pmc->gcr_regs, offset, data);
 }
 EXPORT_SYMBOL_GPL(intel_pmc_gcr_read);
 
@@ -239,21 +225,12 @@ EXPORT_SYMBOL_GPL(intel_pmc_gcr_read);
  */
 int intel_pmc_gcr_write(u32 offset, u32 data)
 {
-	int ret;
-
-	spin_lock(&ipcdev.gcr_lock);
-
-	ret = is_gcr_valid(offset);
-	if (ret < 0) {
-		spin_unlock(&ipcdev.gcr_lock);
-		return ret;
-	}
-
-	writel(data, ipcdev.gcr_mem_base + offset);
+	struct intel_pmc_ipc_dev *pmc = &ipcdev;
 
-	spin_unlock(&ipcdev.gcr_lock);
+	if (!pmc->gcr_regs)
+		return -EACCES;
 
-	return 0;
+	return regmap_write(pmc->gcr_regs, offset, data);
 }
 EXPORT_SYMBOL_GPL(intel_pmc_gcr_write);
 
@@ -270,33 +247,12 @@ EXPORT_SYMBOL_GPL(intel_pmc_gcr_write);
  */
 int intel_pmc_gcr_update(u32 offset, u32 mask, u32 val)
 {
-	u32 new_val;
-	int ret = 0;
-
-	spin_lock(&ipcdev.gcr_lock);
-
-	ret = is_gcr_valid(offset);
-	if (ret < 0)
-		goto gcr_ipc_unlock;
-
-	new_val = readl(ipcdev.gcr_mem_base + offset);
-
-	new_val &= ~mask;
-	new_val |= val & mask;
-
-	writel(new_val, ipcdev.gcr_mem_base + offset);
-
-	new_val = readl(ipcdev.gcr_mem_base + offset);
+	struct intel_pmc_ipc_dev *pmc = &ipcdev;
 
-	/* check whether the bit update is successful */
-	if ((new_val & mask) != (val & mask)) {
-		ret = -EIO;
-		goto gcr_ipc_unlock;
-	}
+	if (!pmc->gcr_regs)
+		return -EACCES;
 
-gcr_ipc_unlock:
-	spin_unlock(&ipcdev.gcr_lock);
-	return ret;
+	return regmap_update_bits(pmc->gcr_regs, offset, mask, val);
 }
 EXPORT_SYMBOL_GPL(intel_pmc_gcr_update);
 
@@ -475,8 +431,6 @@ static int ipc_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 
 	pmc->irq_mode = IPC_TRIGGER_MODE_IRQ;
 
-	spin_lock_init(&ipcdev.gcr_lock);
-
 	ret = pcim_enable_device(pdev);
 	if (ret)
 		return ret;
@@ -767,17 +721,26 @@ static int ipc_plat_get_res(struct platform_device *pdev)
  */
 int intel_pmc_s0ix_counter_read(u64 *data)
 {
+	struct intel_pmc_ipc_dev *pmc = &ipcdev;
 	u64 deep, shlw;
+	int ret;
 
-	if (!ipcdev.has_gcr_regs)
+	if (!pmc->gcr_regs)
 		return -EACCES;
 
-	deep = gcr_data_readq(PMC_GCR_TELEM_DEEP_S0IX_REG);
-	shlw = gcr_data_readq(PMC_GCR_TELEM_SHLW_S0IX_REG);
+	ret = regmap_bulk_read(pmc->gcr_regs, PMC_GCR_TELEM_DEEP_S0IX_REG,
+			       &deep, 2);
+	if (ret)
+		return ret;
+
+	ret = regmap_bulk_read(pmc->gcr_regs, PMC_GCR_TELEM_SHLW_S0IX_REG,
+			       &shlw, 2);
+	if (ret)
+		return ret;
 
 	*data = S0IX_RESIDENCY_IN_USECS(deep, shlw);
 
-	return 0;
+	return ret;
 }
 EXPORT_SYMBOL_GPL(intel_pmc_s0ix_counter_read);
 
@@ -796,7 +759,6 @@ static int ipc_plat_probe(struct platform_device *pdev)
 	ipcdev.dev = &pdev->dev;
 	ipcdev.irq_mode = IPC_TRIGGER_MODE_IRQ;
 	init_completion(&ipcdev.cmd_complete);
-	spin_lock_init(&ipcdev.gcr_lock);
 
 	ipcdev.irq = platform_get_irq(pdev, 0);
 	if (ipcdev.irq < 0) {
@@ -810,6 +772,14 @@ static int ipc_plat_probe(struct platform_device *pdev)
 		return ret;
 	}
 
+	ipcdev.gcr_regs = devm_regmap_init_mmio_clk(ipcdev.dev, NULL,
+						    ipcdev.gcr_mem_base,
+						    &gcr_regmap_config);
+	if (IS_ERR(ipcdev.gcr_regs)) {
+		dev_err(ipcdev.dev, "gcr_regs regmap init failed\n");
+		return PTR_ERR(ipcdev.gcr_regs);
+	}
+
 	ret = ipc_create_pmc_devices(pdev);
 	if (ret) {
 		dev_err(&pdev->dev, "Failed to create PMC devices\n");
@@ -831,8 +801,6 @@ static int ipc_plat_probe(struct platform_device *pdev)
 		return ret;
 	}
 
-	ipcdev.has_gcr_regs = true;
-
 	return 0;
 }
 
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [RFC v8 4/7] platform: x86: Add generic Intel IPC driver
  2017-10-29  9:49 ` sathyanarayanan.kuppuswamy
@ 2017-10-29  9:49   ` sathyanarayanan.kuppuswamy
  -1 siblings, 0 replies; 30+ messages in thread
From: sathyanarayanan.kuppuswamy @ 2017-10-29  9:49 UTC (permalink / raw)
  To: a.zummo, x86, wim, mingo, alexandre.belloni, qipeng.zha, hpa,
	dvhart, tglx, lee.jones, andy, souvik.k.chakravarty
  Cc: linux-rtc, linux-watchdog, linux-kernel, platform-driver-x86,
	sathyaosid, Kuppuswamy Sathyanarayanan

From: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>

Currently intel_scu_ipc.c, intel_pmc_ipc.c and intel_punit_ipc.c
redundantly implements the same IPC features and has lot of code
duplication between them. This driver addresses this issue by grouping
the common IPC functionalities under the same driver.

Signed-off-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>
---
 MAINTAINERS                                     |   7 +
 drivers/platform/x86/Kconfig                    |   8 +
 drivers/platform/x86/Makefile                   |   1 +
 drivers/platform/x86/intel_ipc_dev.c            | 563 ++++++++++++++++++++++++
 include/linux/platform_data/x86/intel_ipc_dev.h | 246 +++++++++++
 5 files changed, 825 insertions(+)
 create mode 100644 drivers/platform/x86/intel_ipc_dev.c
 create mode 100644 include/linux/platform_data/x86/intel_ipc_dev.h

Changes since v7:
 * Fixed style issues.
 * Added MAINTAINER info.

Changes since v6:
 * None

Changes since v5:
 * Added structures to group intel_ipc_cmd() intel_ipc_raw_cmd()
   arguments.

Changes since v4:
 * None

Changes since v3:
 * Fixed NULL pointer exception in intel_ipc_dev_get().
 * Fixed error in check for duplicate intel_ipc_dev.
 * Added custom interrupt handler support.
 * Used char array for error string conversion.
 * Added put dev support.
 * Added devm_* variant of intel_ipc_dev_get().

Changes since v2:
 * Added ipc_dev_cmd API support.

diff --git a/MAINTAINERS b/MAINTAINERS
index d85c089..a2a9a9f 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -6970,6 +6970,13 @@ R:	Dan Williams <dan.j.williams@intel.com>
 S:	Odd fixes
 F:	drivers/dma/iop-adma.c
 
+INTEL IPC CORE DRIVER
+M:	Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>
+L:	platform-driver-x86@vger.kernel.org
+S:	Maintained
+F:	drivers/platform/x86/intel_ipc_dev.c
+F:	include/linux/platform_data/x86/intel_ipc_dev.h
+
 INTEL IXP4XX QMGR, NPE, ETHERNET and HSS SUPPORT
 M:	Krzysztof Halasa <khalasa@piap.pl>
 S:	Maintained
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
index 45f4e79..9df7cda 100644
--- a/drivers/platform/x86/Kconfig
+++ b/drivers/platform/x86/Kconfig
@@ -1140,6 +1140,14 @@ config SILEAD_DMI
 	  with the OS-image for the device. This option supplies the missing
 	  information. Enable this for x86 tablets with Silead touchscreens.
 
+config INTEL_IPC_DEV
+	bool "Intel IPC Device Driver"
+	depends on X86_64
+	---help---
+	  This driver implements core features of Intel IPC device. Devices
+	  like PMC, SCU, PUNIT, etc can use interfaces provided by this
+	  driver to implement IPC protocol of their respective device.
+
 endif # X86_PLATFORM_DEVICES
 
 config PMC_ATOM
diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile
index 91cec17..04e11ce 100644
--- a/drivers/platform/x86/Makefile
+++ b/drivers/platform/x86/Makefile
@@ -83,3 +83,4 @@ obj-$(CONFIG_PMC_ATOM)		+= pmc_atom.o
 obj-$(CONFIG_MLX_PLATFORM)	+= mlx-platform.o
 obj-$(CONFIG_MLX_CPLD_PLATFORM)	+= mlxcpld-hotplug.o
 obj-$(CONFIG_INTEL_TURBO_MAX_3) += intel_turbo_max_3.o
+obj-$(CONFIG_INTEL_IPC_DEV)	+= intel_ipc_dev.o
diff --git a/drivers/platform/x86/intel_ipc_dev.c b/drivers/platform/x86/intel_ipc_dev.c
new file mode 100644
index 0000000..0edcf23
--- /dev/null
+++ b/drivers/platform/x86/intel_ipc_dev.c
@@ -0,0 +1,563 @@
+/*
+ * intel_ipc_dev.c: Intel IPC device class driver
+ *
+ * (C) Copyright 2017 Intel Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; version 2
+ * of the License.
+ *
+ */
+
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/export.h>
+#include <linux/idr.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/platform_data/x86/intel_ipc_dev.h>
+#include <linux/regmap.h>
+
+/* mutex to sync different ipc devices in same channel */
+static struct mutex channel_lock[IPC_CHANNEL_MAX];
+
+static char *ipc_err_sources[] = {
+	[IPC_DEV_ERR_NONE] =
+		"No error",
+	[IPC_DEV_ERR_CMD_NOT_SUPPORTED] =
+		"Command not-supported/Invalid",
+	[IPC_DEV_ERR_CMD_NOT_SERVICED] =
+		"Command not-serviced/Invalid param",
+	[IPC_DEV_ERR_UNABLE_TO_SERVICE] =
+		"Unable-to-service/Cmd-timeout",
+	[IPC_DEV_ERR_CMD_INVALID] =
+		"Command-invalid/Cmd-locked",
+	[IPC_DEV_ERR_CMD_FAILED] =
+		"Command-failed/Invalid-VR-id",
+	[IPC_DEV_ERR_EMSECURITY] =
+		"Invalid Battery/VR-Error",
+	[IPC_DEV_ERR_UNSIGNEDKERNEL] =
+		"Unsigned kernel",
+};
+
+static void ipc_channel_lock_init(void)
+{
+	int i;
+
+	for (i = 0; i < IPC_CHANNEL_MAX; i++)
+		mutex_init(&channel_lock[i]);
+}
+
+static struct class intel_ipc_class = {
+	.name = "intel_ipc",
+	.owner = THIS_MODULE,
+};
+
+static int ipc_dev_lock(struct intel_ipc_dev *ipc_dev)
+{
+	int chan_type;
+
+	if (!ipc_dev || !ipc_dev->cfg)
+		return -ENODEV;
+
+	chan_type = ipc_dev->cfg->chan_type;
+	if (chan_type > IPC_CHANNEL_MAX)
+		return -EINVAL;
+
+	/* acquire channel lock */
+	mutex_lock(&channel_lock[chan_type]);
+
+	/* acquire IPC device lock */
+	mutex_lock(&ipc_dev->lock);
+
+	return 0;
+}
+
+static int ipc_dev_unlock(struct intel_ipc_dev *ipc_dev)
+{
+	int chan_type;
+
+	if (!ipc_dev || !ipc_dev->cfg)
+		return -ENODEV;
+
+	chan_type = ipc_dev->cfg->chan_type;
+	if (chan_type > IPC_CHANNEL_MAX)
+		return -EINVAL;
+
+	/* release IPC device lock */
+	mutex_unlock(&ipc_dev->lock);
+
+	/* release channel lock */
+	mutex_unlock(&channel_lock[chan_type]);
+
+	return 0;
+}
+
+static const char *ipc_dev_err_string(struct intel_ipc_dev *ipc_dev,
+	int error)
+{
+	if (error < IPC_DEV_ERR_MAX)
+		return ipc_err_sources[error];
+
+	return "Unknown Command";
+}
+
+/* Helper function to send given command to IPC device */
+static inline void ipc_dev_send_cmd(struct intel_ipc_dev *ipc_dev, u32 cmd)
+{
+	ipc_dev->cmd = cmd;
+
+	if (ipc_dev->cfg->mode == IPC_DEV_MODE_IRQ)
+		reinit_completion(&ipc_dev->cmd_complete);
+
+	if (ipc_dev->ops->enable_msi)
+		cmd = ipc_dev->ops->enable_msi(cmd);
+
+	regmap_write(ipc_dev->cfg->cmd_regs, ipc_dev->cfg->cmd_reg, cmd);
+}
+
+static inline int ipc_dev_status_busy(struct intel_ipc_dev *ipc_dev)
+{
+	int status;
+
+	regmap_read(ipc_dev->cfg->cmd_regs, ipc_dev->cfg->status_reg, &status);
+
+	if (ipc_dev->ops->busy_check)
+		return ipc_dev->ops->busy_check(status);
+
+	return 0;
+}
+
+/* Check the status of IPC command and return err code if failed */
+static int ipc_dev_check_status(struct intel_ipc_dev *ipc_dev)
+{
+	int loop_count = IPC_DEV_CMD_LOOP_CNT;
+	int status;
+	int ret = 0;
+
+	if (ipc_dev->cfg->mode == IPC_DEV_MODE_IRQ) {
+		if (!wait_for_completion_timeout(&ipc_dev->cmd_complete,
+				IPC_DEV_CMD_TIMEOUT))
+			ret = -ETIMEDOUT;
+	} else {
+		while (ipc_dev_status_busy(ipc_dev) && --loop_count)
+			udelay(1);
+		if (!loop_count)
+			ret = -ETIMEDOUT;
+	}
+
+	if (ret < 0) {
+		dev_err(&ipc_dev->dev,
+				"IPC timed out, CMD=0x%x\n", ipc_dev->cmd);
+		return ret;
+	}
+
+	regmap_read(ipc_dev->cfg->cmd_regs, ipc_dev->cfg->status_reg, &status);
+
+	if (ipc_dev->ops->to_err_code)
+		ret = ipc_dev->ops->to_err_code(status);
+
+	if (ret) {
+		dev_err(&ipc_dev->dev,
+				"IPC failed: %s, STS=0x%x, CMD=0x%x\n",
+				ipc_dev_err_string(ipc_dev, ret),
+				status, ipc_dev->cmd);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+/**
+ * ipc_dev_simple_cmd() - Send simple IPC command
+ * @ipc_dev     : Reference to ipc device.
+ * @cmd_list    : IPC command list.
+ * @cmdlen      : Number of cmd/sub-cmds.
+ *
+ * Send a simple IPC command to ipc device.
+ * Use this when don't need to specify input/output data
+ * and source/dest pointers.
+ *
+ * Return:	an IPC error code or 0 on success.
+ */
+
+int ipc_dev_simple_cmd(struct intel_ipc_dev *ipc_dev, u32 *cmd_list,
+		u32 cmdlen)
+{
+	int ret;
+
+	if (!cmd_list)
+		return -EINVAL;
+
+	ret = ipc_dev_lock(ipc_dev);
+	if (ret)
+		return ret;
+
+	/* Call custom pre-processing handler */
+	if (ipc_dev->ops->pre_simple_cmd_fn) {
+		ret = ipc_dev->ops->pre_simple_cmd_fn(cmd_list, cmdlen);
+		if (ret)
+			goto unlock_device;
+	}
+
+	ipc_dev_send_cmd(ipc_dev, cmd_list[0]);
+
+	ret = ipc_dev_check_status(ipc_dev);
+
+unlock_device:
+	ipc_dev_unlock(ipc_dev);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(ipc_dev_simple_cmd);
+
+/**
+ * ipc_dev_cmd() - Send IPC command with data.
+ * @ipc_dev     : Reference to ipc_dev.
+ * @ipc_cmd     : Intel IPC command argument structure.
+ *
+ * Send an IPC command to device with input/output data.
+ *
+ * Return:	an IPC error code or 0 on success.
+ */
+int ipc_dev_cmd(struct intel_ipc_dev *ipc_dev, struct intel_ipc_cmd *ipc_cmd)
+{
+	int ret;
+
+	if (!ipc_cmd || !ipc_cmd->cmd_list || !ipc_cmd->in)
+		return -EINVAL;
+
+	ret = ipc_dev_lock(ipc_dev);
+	if (ret)
+		return ret;
+
+	/* Call custom pre-processing handler. */
+	if (ipc_dev->ops->pre_cmd_fn) {
+		ret = ipc_dev->ops->pre_cmd_fn(ipc_cmd);
+		if (ret)
+			goto unlock_device;
+	}
+
+	/* Write inlen dwords of data to wrbuf_reg. */
+	if (ipc_cmd->inlen > 0)
+		regmap_bulk_write(ipc_dev->cfg->data_regs,
+				ipc_dev->cfg->wrbuf_reg, ipc_cmd->in,
+				ipc_cmd->inlen);
+
+	ipc_dev_send_cmd(ipc_dev, ipc_cmd->cmd_list[0]);
+
+	ret = ipc_dev_check_status(ipc_dev);
+
+	/* Read outlen dwords of data from rbug_reg. */
+	if (!ret && ipc_cmd->outlen > 0)
+		regmap_bulk_read(ipc_dev->cfg->data_regs,
+				ipc_dev->cfg->rbuf_reg, ipc_cmd->out,
+				ipc_cmd->outlen);
+unlock_device:
+	ipc_dev_unlock(ipc_dev);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(ipc_dev_cmd);
+
+/**
+ * ipc_dev_raw_cmd() - Send IPC command with data and pointers.
+ * @ipc_dev        : Reference to ipc_dev.
+ * @ipc_raw_cmd    : Intel IPC raw command argument structure.
+ *
+ * Send an IPC command to device with input/output data and
+ * source/dest pointers.
+ *
+ * Return:	an IPC error code or 0 on success.
+ */
+
+int ipc_dev_raw_cmd(struct intel_ipc_dev *ipc_dev,
+		struct intel_ipc_raw_cmd *ipc_raw_cmd)
+{
+	int ret, inbuflen;
+	u32 *inbuf;
+
+	if (!ipc_raw_cmd || !ipc_raw_cmd->cmd_list || !ipc_raw_cmd->in)
+		return -EINVAL;
+
+	inbuflen = DIV_ROUND_UP(ipc_raw_cmd->inlen, 4);
+
+	inbuf = kzalloc(inbuflen, GFP_KERNEL);
+	if (!inbuf)
+		return -ENOMEM;
+
+	ret = ipc_dev_lock(ipc_dev);
+	if (ret)
+		return ret;
+
+	/* Call custom pre-processing handler. */
+	if (ipc_dev->ops->pre_raw_cmd_fn) {
+		ret = ipc_dev->ops->pre_raw_cmd_fn(ipc_raw_cmd);
+		if (ret)
+			goto unlock_device;
+	}
+
+	/* If supported, write DPTR register.*/
+	if (ipc_dev->cfg->support_dptr)
+		regmap_write(ipc_dev->cfg->cmd_regs, ipc_dev->cfg->dptr_reg,
+				ipc_raw_cmd->dptr);
+
+	/* If supported, write SPTR register. */
+	if (ipc_dev->cfg->support_sptr)
+		regmap_write(ipc_dev->cfg->cmd_regs, ipc_dev->cfg->sptr_reg,
+				ipc_raw_cmd->sptr);
+
+	memcpy(inbuf, ipc_raw_cmd->in, ipc_raw_cmd->inlen);
+
+	/* Write inlen dwords of data to wrbuf_reg. */
+	if (ipc_raw_cmd->inlen > 0)
+		regmap_bulk_write(ipc_dev->cfg->data_regs,
+				ipc_dev->cfg->wrbuf_reg, inbuf, inbuflen);
+
+	ipc_dev_send_cmd(ipc_dev, ipc_raw_cmd->cmd_list[0]);
+
+	ret = ipc_dev_check_status(ipc_dev);
+
+	/* Read outlen dwords of data from rbug_reg. */
+	if (!ret && ipc_raw_cmd->outlen > 0)
+		regmap_bulk_read(ipc_dev->cfg->data_regs,
+				ipc_dev->cfg->rbuf_reg, ipc_raw_cmd->out,
+				ipc_raw_cmd->outlen);
+unlock_device:
+	ipc_dev_unlock(ipc_dev);
+	kfree(inbuf);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(ipc_dev_raw_cmd);
+
+/* sysfs option to send simple IPC commands from userspace */
+static ssize_t ipc_dev_cmd_reg_store(struct device *dev,
+				     struct device_attribute *attr,
+				     const char *buf, size_t count)
+{
+	struct intel_ipc_dev *ipc_dev = dev_get_drvdata(dev);
+	u32 cmd;
+	int ret;
+
+	ret = kstrtou32(buf, 0, &cmd);
+	if (ret < 0)
+		return -EINVAL;
+
+	ret = ipc_dev_simple_cmd(ipc_dev, &cmd, 1);
+	if (ret) {
+		dev_err(dev, "command 0x%x error with %d\n", cmd, ret);
+		return ret;
+	}
+	return (ssize_t)count;
+}
+
+static DEVICE_ATTR(send_cmd, 00200, NULL, ipc_dev_cmd_reg_store);
+
+static struct attribute *ipc_dev_attrs[] = {
+	&dev_attr_send_cmd.attr,
+	NULL
+};
+
+static const struct attribute_group ipc_dev_group = {
+	.attrs = ipc_dev_attrs,
+};
+
+static const struct attribute_group *ipc_dev_groups[] = {
+	&ipc_dev_group,
+	NULL,
+};
+
+/* IPC device IRQ handler */
+static irqreturn_t ipc_dev_irq_handler(int irq, void *dev_id)
+{
+	struct intel_ipc_dev *ipc_dev = (struct intel_ipc_dev *)dev_id;
+
+	if (ipc_dev->ops->pre_irq_handler_fn)
+		ipc_dev->ops->pre_irq_handler_fn(ipc_dev, irq);
+
+	complete(&ipc_dev->cmd_complete);
+
+	return IRQ_HANDLED;
+}
+
+static void devm_intel_ipc_dev_release(struct device *dev, void *res)
+{
+	struct intel_ipc_dev *ipc_dev = *(struct intel_ipc_dev **)res;
+
+	if (!ipc_dev)
+		return;
+
+	device_del(&ipc_dev->dev);
+
+	kfree(ipc_dev);
+}
+
+static int match_name(struct device *dev, const void *data)
+{
+	if (!dev_name(dev))
+		return 0;
+
+	return !strcmp(dev_name(dev), (char *)data);
+}
+
+/**
+ * intel_ipc_dev_get() - Get Intel IPC device from name.
+ * @dev_name    : Name of the IPC device.
+ *
+ * Return       : ERR_PTR/NULL or intel_ipc_dev pointer on success.
+ */
+struct intel_ipc_dev *intel_ipc_dev_get(const char *dev_name)
+{
+	struct device *dev;
+
+	if (!dev_name)
+		return ERR_PTR(-EINVAL);
+
+	dev = class_find_device(&intel_ipc_class, NULL, dev_name, match_name);
+
+	return dev ? dev_get_drvdata(dev) : NULL;
+}
+EXPORT_SYMBOL_GPL(intel_ipc_dev_get);
+
+static void devm_intel_ipc_dev_put(struct device *dev, void *res)
+{
+	intel_ipc_dev_put(*(struct intel_ipc_dev **)res);
+}
+
+/**
+ * devm_intel_ipc_dev_get() - Resource managed version of intel_ipc_dev_get().
+ * @dev         : Device pointer.
+ * @dev_name    : Name of the IPC device.
+ *
+ * Return       : ERR_PTR/NULL or intel_ipc_dev pointer on success.
+ */
+struct intel_ipc_dev *devm_intel_ipc_dev_get(struct device *dev,
+					const char *dev_name)
+{
+	struct intel_ipc_dev **ptr, *ipc_dev;
+
+	ptr = devres_alloc(devm_intel_ipc_dev_put, sizeof(*ptr), GFP_KERNEL);
+	if (!ptr)
+		return ERR_PTR(-ENOMEM);
+
+	ipc_dev = intel_ipc_dev_get(dev_name);
+	if (!IS_ERR_OR_NULL(ipc_dev)) {
+		*ptr = ipc_dev;
+		devres_add(dev, ptr);
+	} else {
+		devres_free(ptr);
+	}
+
+	return ipc_dev;
+}
+EXPORT_SYMBOL_GPL(devm_intel_ipc_dev_get);
+
+/**
+ * devm_intel_ipc_dev_create() - Create IPC device
+ * @dev		: IPC parent device.
+ * @devname	: Name of the IPC device.
+ * @cfg		: IPC device configuration.
+ * @ops		: IPC device ops.
+ *
+ * Resource managed API to create IPC device with
+ * given configuration.
+ *
+ * Return	: IPC device pointer or ERR_PTR(error code).
+ */
+struct intel_ipc_dev *devm_intel_ipc_dev_create(struct device *dev,
+		const char *devname,
+		struct intel_ipc_dev_cfg *cfg,
+		struct intel_ipc_dev_ops *ops)
+{
+	struct intel_ipc_dev **ptr, *ipc_dev;
+	int ret;
+
+	if (!dev && !devname && !cfg)
+		return ERR_PTR(-EINVAL);
+
+	if (intel_ipc_dev_get(devname)) {
+		dev_err(dev, "IPC device %s already exist\n", devname);
+		return ERR_PTR(-EINVAL);
+	}
+
+	ptr = devres_alloc(devm_intel_ipc_dev_release, sizeof(*ptr),
+			GFP_KERNEL);
+	if (!ptr)
+		return ERR_PTR(-ENOMEM);
+
+	ipc_dev = kzalloc(sizeof(*ipc_dev), GFP_KERNEL);
+	if (!ipc_dev) {
+		ret = -ENOMEM;
+		goto err_dev_create;
+	}
+
+	ipc_dev->dev.class = &intel_ipc_class;
+	ipc_dev->dev.parent = dev;
+	ipc_dev->dev.groups = ipc_dev_groups;
+	ipc_dev->cfg = cfg;
+	ipc_dev->ops = ops;
+
+	mutex_init(&ipc_dev->lock);
+	init_completion(&ipc_dev->cmd_complete);
+	dev_set_drvdata(&ipc_dev->dev, ipc_dev);
+	dev_set_name(&ipc_dev->dev, devname);
+	device_initialize(&ipc_dev->dev);
+
+	ret = device_add(&ipc_dev->dev);
+	if (ret < 0) {
+		dev_err(&ipc_dev->dev, "%s device create failed\n",
+				__func__);
+		ret = -ENODEV;
+		goto err_dev_add;
+	}
+
+	if (ipc_dev->cfg->mode == IPC_DEV_MODE_IRQ) {
+		if (devm_request_irq(&ipc_dev->dev,
+				ipc_dev->cfg->irq,
+				ipc_dev_irq_handler,
+				ipc_dev->cfg->irqflags,
+				dev_name(&ipc_dev->dev),
+				ipc_dev)) {
+			dev_err(&ipc_dev->dev,
+					"Failed to request irq\n");
+			goto err_irq_request;
+		}
+	}
+
+	*ptr = ipc_dev;
+
+	devres_add(dev, ptr);
+
+	return ipc_dev;
+
+err_irq_request:
+	device_del(&ipc_dev->dev);
+err_dev_add:
+	kfree(ipc_dev);
+err_dev_create:
+	devres_free(ptr);
+	return ERR_PTR(ret);
+}
+EXPORT_SYMBOL_GPL(devm_intel_ipc_dev_create);
+
+static int __init intel_ipc_init(void)
+{
+	ipc_channel_lock_init();
+	return class_register(&intel_ipc_class);
+}
+
+static void __exit intel_ipc_exit(void)
+{
+	class_unregister(&intel_ipc_class);
+}
+subsys_initcall(intel_ipc_init);
+module_exit(intel_ipc_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Kuppuswamy Sathyanarayanan<sathyanarayanan.kuppuswamy@linux.intel.com>");
+MODULE_DESCRIPTION("Intel IPC device class driver");
diff --git a/include/linux/platform_data/x86/intel_ipc_dev.h b/include/linux/platform_data/x86/intel_ipc_dev.h
new file mode 100644
index 0000000..9e6ce6d
--- /dev/null
+++ b/include/linux/platform_data/x86/intel_ipc_dev.h
@@ -0,0 +1,246 @@
+/*
+ * Intel IPC class device header file.
+ *
+ * (C) Copyright 2017 Intel Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; version 2
+ * of the License.
+ *
+ */
+
+#ifndef INTEL_IPC_DEV_H
+#define INTEL_IPC_DEV_H
+
+#include <linux/module.h>
+#include <linux/device.h>
+
+/* IPC channel type */
+#define IPC_CHANNEL_IA_PMC                      0
+#define IPC_CHANNEL_IA_PUNIT                    1
+#define IPC_CHANNEL_PMC_PUNIT                   2
+#define IPC_CHANNEL_IA_SCU                      3
+#define IPC_CHANNEL_MAX                         4
+
+/* IPC return code */
+#define IPC_DEV_ERR_NONE			0
+#define IPC_DEV_ERR_CMD_NOT_SUPPORTED		1
+#define IPC_DEV_ERR_CMD_NOT_SERVICED		2
+#define IPC_DEV_ERR_UNABLE_TO_SERVICE		3
+#define IPC_DEV_ERR_CMD_INVALID			4
+#define IPC_DEV_ERR_CMD_FAILED			5
+#define IPC_DEV_ERR_EMSECURITY			6
+#define IPC_DEV_ERR_UNSIGNEDKERNEL		7
+#define IPC_DEV_ERR_MAX				8
+
+/* IPC mode */
+#define IPC_DEV_MODE_IRQ			0
+#define IPC_DEV_MODE_POLLING			1
+
+/* IPC dev constants */
+#define IPC_DEV_CMD_LOOP_CNT			3000000
+#define IPC_DEV_CMD_TIMEOUT			(3 * HZ)
+#define IPC_DEV_DATA_BUFFER_SIZE		16
+
+struct intel_ipc_dev;
+struct intel_ipc_raw_cmd;
+
+/**
+ * struct intel_ipc_dev_cfg - IPC device config structure.
+ *
+ * IPC device drivers uses the following config options to
+ * register new IPC device.
+ *
+ * @cmd_regs            : IPC device command base regmap.
+ * @data_regs           : IPC device data base regmap.
+ * @wrbuf_reg           : IPC device data write register address.
+ * @rbuf_reg            : IPC device data read register address.
+ * @sptr_reg            : IPC device source data pointer register address.
+ * @dptr_reg            : IPC device destination data pointer register
+ *                        address.
+ * @status_reg          : IPC command status register address.
+ * @cmd_reg             : IPC command register address.
+ * @mode                : IRQ/POLLING mode.
+ * @irq                 : IPC device IRQ number.
+ * @irqflags            : IPC device IRQ flags.
+ * @chan_type           : IPC device channel type(PMC/PUNIT).
+ * @msi                 : Enable/Disable MSI for IPC commands.
+ * @support_dptr        : Support DPTR update.
+ * @support_sptr        : Support SPTR update.
+ *
+ */
+struct intel_ipc_dev_cfg {
+	struct regmap *cmd_regs;
+	struct regmap *data_regs;
+	unsigned int wrbuf_reg;
+	unsigned int rbuf_reg;
+	unsigned int sptr_reg;
+	unsigned int dptr_reg;
+	unsigned int status_reg;
+	unsigned int cmd_reg;
+	int mode;
+	int irq;
+	int irqflags;
+	int chan_type;
+	bool use_msi;
+	bool support_dptr;
+	bool support_sptr;
+};
+
+/**
+ * struct intel_ipc_raw_cmd - Intel IPC raw command args.
+ *
+ * @cmd_list    : Array of commands/sub-commands.
+ * @cmdlen      : Number of commands.
+ * @in          : Input data of this IPC command.
+ * @inlen       : Input data length in bytes.
+ * @out         : Output data of this IPC command.
+ * @outlen      : Length of output data in dwords.
+ * @dptr        : IPC destination data address.
+ * @sptr        : IPC source data address.
+ *
+ */
+struct intel_ipc_raw_cmd {
+	u32 *cmd_list;
+	u32 cmdlen;
+	u8 *in;
+	u32 inlen;
+	u32 *out;
+	u32 outlen;
+	u32 dptr;
+	u32 sptr;
+};
+
+/**
+ * struct intel_ipc_raw_cmd - Intel IPC command args.
+ *
+ * @cmd_list    : Array of commands/sub-commands.
+ * @cmdlen      : Number of commands.
+ * @in          : Input data of this IPC command.
+ * @inlen       : Input data length in bytes.
+ * @out         : Output data of this IPC command.
+ * @outlen      : Length of output data in dwords.
+ *
+ */
+struct intel_ipc_cmd {
+	u32 *cmd_list;
+	u32 cmdlen;
+	u32 *in;
+	u32 inlen;
+	u32 *out;
+	u32 outlen;
+};
+
+/**
+ * struct intel_ipc_dev_ops - IPC device ops structure.
+ *
+ * Call backs for IPC device specific operations.
+ *
+ * @to_err_code         : Status to error code conversion function.
+ * @busy_check          : Check for IPC busy status.
+ * @enable_msi          : Enable MSI for IPC commands.
+ * @pre_simple_cmd_fn   : Custom pre-processing function for
+ *                        ipc_dev_simple_cmd()
+ * @pre_cmd_fn          : Custom pre-processing function for
+ *                        ipc_dev_cmd()
+ * @pre_raw_cmd_fn      : Custom pre-processing function for
+ *                        ipc_dev_raw_cmd()
+ *
+ */
+struct intel_ipc_dev_ops {
+	int (*to_err_code)(int status);
+	int (*busy_check)(int status);
+	u32 (*enable_msi)(u32 cmd);
+	int (*pre_simple_cmd_fn)(u32 *cmd_list, u32 cmdlen);
+	int (*pre_cmd_fn)(struct intel_ipc_cmd *ipc_cmd);
+	int (*pre_raw_cmd_fn)(struct intel_ipc_raw_cmd *ipc_raw_cmd);
+	int (*pre_irq_handler_fn)(struct intel_ipc_dev *ipc_dev, int irq);
+};
+
+/**
+ * struct intel_ipc_dev - Intel IPC device structure.
+ *
+ * Used with devm_intel_ipc_dev_create() to create new IPC device.
+ *
+ * @dev                 : IPC device object.
+ * @cmd                 : Current IPC device command.
+ * @cmd_complete        : Command completion object.
+ * @lock                : Lock to protect IPC device structure.
+ * @ops                 : IPC device ops pointer.
+ * @cfg                 : IPC device cfg pointer.
+ *
+ */
+struct intel_ipc_dev {
+	struct device dev;
+	int cmd;
+	struct completion cmd_complete;
+	struct mutex lock;
+	struct intel_ipc_dev_ops *ops;
+	struct intel_ipc_dev_cfg *cfg;
+};
+
+#if IS_ENABLED(CONFIG_INTEL_IPC_DEV)
+
+/* API to create new IPC device */
+struct intel_ipc_dev *devm_intel_ipc_dev_create(struct device *dev,
+		const char *devname, struct intel_ipc_dev_cfg *cfg,
+		struct intel_ipc_dev_ops *ops);
+
+int ipc_dev_simple_cmd(struct intel_ipc_dev *ipc_dev, u32 *cmd_list,
+		u32 cmdlen);
+int ipc_dev_cmd(struct intel_ipc_dev *ipc_dev, struct intel_ipc_cmd *ipc_cmd);
+int ipc_dev_raw_cmd(struct intel_ipc_dev *ipc_dev,
+		struct intel_ipc_raw_cmd *ipc_raw_cmd);
+struct intel_ipc_dev *intel_ipc_dev_get(const char *dev_name);
+struct intel_ipc_dev *devm_intel_ipc_dev_get(struct device *dev,
+					const char *dev_name);
+static inline void intel_ipc_dev_put(struct intel_ipc_dev *ipc_dev)
+{
+	put_device(&ipc_dev->dev);
+}
+#else
+
+static inline struct intel_ipc_dev *devm_intel_ipc_dev_create(
+		struct device *dev,
+		const char *devname, struct intel_ipc_dev_cfg *cfg,
+		struct intel_ipc_dev_ops *ops)
+{
+	return -EINVAL;
+}
+
+static inline int ipc_dev_simple_cmd(struct intel_ipc_dev *ipc_dev,
+		u32 *cmd_list, u32 cmdlen)
+{
+	return -EINVAL;
+}
+
+static int ipc_dev_cmd(struct intel_ipc_dev *ipc_dev,
+		struct intel_ipc_cmd *ipc_cmd)
+{
+	return -EINVAL;
+}
+
+static inline int ipc_dev_raw_cmd(struct intel_ipc_dev *ipc_dev,
+		struct intel_ipc_raw_cmd *ipc_raw_cmd);
+{
+	return -EINVAL;
+}
+
+static inline struct intel_ipc_dev *intel_ipc_dev_get(const char *dev_name)
+{
+	return NULL;
+}
+
+static inline struct intel_ipc_dev *devm_intel_ipc_dev_get(struct device *dev,
+					const char *dev_name);
+{
+	return NULL;
+}
+
+static inline void intel_ipc_dev_put(struct intel_ipc_dev *ipc_dev)
+{
+	return NULL;
+}
+#endif /* CONFIG_INTEL_IPC_DEV */
+#endif /* INTEL_IPC_DEV_H */
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [RFC v8 4/7] platform: x86: Add generic Intel IPC driver
@ 2017-10-29  9:49   ` sathyanarayanan.kuppuswamy
  0 siblings, 0 replies; 30+ messages in thread
From: sathyanarayanan.kuppuswamy @ 2017-10-29  9:49 UTC (permalink / raw)
  To: a.zummo, x86, wim, mingo, alexandre.belloni, qipeng.zha, hpa,
	dvhart, tglx, lee.jones, andy, souvik.k.chakravarty
  Cc: linux-rtc, linux-watchdog, linux-kernel, platform-driver-x86,
	sathyaosid, Kuppuswamy Sathyanarayanan

From: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>

Currently intel_scu_ipc.c, intel_pmc_ipc.c and intel_punit_ipc.c
redundantly implements the same IPC features and has lot of code
duplication between them. This driver addresses this issue by grouping
the common IPC functionalities under the same driver.

Signed-off-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>
---
 MAINTAINERS                                     |   7 +
 drivers/platform/x86/Kconfig                    |   8 +
 drivers/platform/x86/Makefile                   |   1 +
 drivers/platform/x86/intel_ipc_dev.c            | 563 ++++++++++++++++++++++++
 include/linux/platform_data/x86/intel_ipc_dev.h | 246 +++++++++++
 5 files changed, 825 insertions(+)
 create mode 100644 drivers/platform/x86/intel_ipc_dev.c
 create mode 100644 include/linux/platform_data/x86/intel_ipc_dev.h

Changes since v7:
 * Fixed style issues.
 * Added MAINTAINER info.

Changes since v6:
 * None

Changes since v5:
 * Added structures to group intel_ipc_cmd() intel_ipc_raw_cmd()
   arguments.

Changes since v4:
 * None

Changes since v3:
 * Fixed NULL pointer exception in intel_ipc_dev_get().
 * Fixed error in check for duplicate intel_ipc_dev.
 * Added custom interrupt handler support.
 * Used char array for error string conversion.
 * Added put dev support.
 * Added devm_* variant of intel_ipc_dev_get().

Changes since v2:
 * Added ipc_dev_cmd API support.

diff --git a/MAINTAINERS b/MAINTAINERS
index d85c089..a2a9a9f 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -6970,6 +6970,13 @@ R:	Dan Williams <dan.j.williams@intel.com>
 S:	Odd fixes
 F:	drivers/dma/iop-adma.c
 
+INTEL IPC CORE DRIVER
+M:	Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>
+L:	platform-driver-x86@vger.kernel.org
+S:	Maintained
+F:	drivers/platform/x86/intel_ipc_dev.c
+F:	include/linux/platform_data/x86/intel_ipc_dev.h
+
 INTEL IXP4XX QMGR, NPE, ETHERNET and HSS SUPPORT
 M:	Krzysztof Halasa <khalasa@piap.pl>
 S:	Maintained
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
index 45f4e79..9df7cda 100644
--- a/drivers/platform/x86/Kconfig
+++ b/drivers/platform/x86/Kconfig
@@ -1140,6 +1140,14 @@ config SILEAD_DMI
 	  with the OS-image for the device. This option supplies the missing
 	  information. Enable this for x86 tablets with Silead touchscreens.
 
+config INTEL_IPC_DEV
+	bool "Intel IPC Device Driver"
+	depends on X86_64
+	---help---
+	  This driver implements core features of Intel IPC device. Devices
+	  like PMC, SCU, PUNIT, etc can use interfaces provided by this
+	  driver to implement IPC protocol of their respective device.
+
 endif # X86_PLATFORM_DEVICES
 
 config PMC_ATOM
diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile
index 91cec17..04e11ce 100644
--- a/drivers/platform/x86/Makefile
+++ b/drivers/platform/x86/Makefile
@@ -83,3 +83,4 @@ obj-$(CONFIG_PMC_ATOM)		+= pmc_atom.o
 obj-$(CONFIG_MLX_PLATFORM)	+= mlx-platform.o
 obj-$(CONFIG_MLX_CPLD_PLATFORM)	+= mlxcpld-hotplug.o
 obj-$(CONFIG_INTEL_TURBO_MAX_3) += intel_turbo_max_3.o
+obj-$(CONFIG_INTEL_IPC_DEV)	+= intel_ipc_dev.o
diff --git a/drivers/platform/x86/intel_ipc_dev.c b/drivers/platform/x86/intel_ipc_dev.c
new file mode 100644
index 0000000..0edcf23
--- /dev/null
+++ b/drivers/platform/x86/intel_ipc_dev.c
@@ -0,0 +1,563 @@
+/*
+ * intel_ipc_dev.c: Intel IPC device class driver
+ *
+ * (C) Copyright 2017 Intel Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; version 2
+ * of the License.
+ *
+ */
+
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/export.h>
+#include <linux/idr.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/platform_data/x86/intel_ipc_dev.h>
+#include <linux/regmap.h>
+
+/* mutex to sync different ipc devices in same channel */
+static struct mutex channel_lock[IPC_CHANNEL_MAX];
+
+static char *ipc_err_sources[] = {
+	[IPC_DEV_ERR_NONE] =
+		"No error",
+	[IPC_DEV_ERR_CMD_NOT_SUPPORTED] =
+		"Command not-supported/Invalid",
+	[IPC_DEV_ERR_CMD_NOT_SERVICED] =
+		"Command not-serviced/Invalid param",
+	[IPC_DEV_ERR_UNABLE_TO_SERVICE] =
+		"Unable-to-service/Cmd-timeout",
+	[IPC_DEV_ERR_CMD_INVALID] =
+		"Command-invalid/Cmd-locked",
+	[IPC_DEV_ERR_CMD_FAILED] =
+		"Command-failed/Invalid-VR-id",
+	[IPC_DEV_ERR_EMSECURITY] =
+		"Invalid Battery/VR-Error",
+	[IPC_DEV_ERR_UNSIGNEDKERNEL] =
+		"Unsigned kernel",
+};
+
+static void ipc_channel_lock_init(void)
+{
+	int i;
+
+	for (i = 0; i < IPC_CHANNEL_MAX; i++)
+		mutex_init(&channel_lock[i]);
+}
+
+static struct class intel_ipc_class = {
+	.name = "intel_ipc",
+	.owner = THIS_MODULE,
+};
+
+static int ipc_dev_lock(struct intel_ipc_dev *ipc_dev)
+{
+	int chan_type;
+
+	if (!ipc_dev || !ipc_dev->cfg)
+		return -ENODEV;
+
+	chan_type = ipc_dev->cfg->chan_type;
+	if (chan_type > IPC_CHANNEL_MAX)
+		return -EINVAL;
+
+	/* acquire channel lock */
+	mutex_lock(&channel_lock[chan_type]);
+
+	/* acquire IPC device lock */
+	mutex_lock(&ipc_dev->lock);
+
+	return 0;
+}
+
+static int ipc_dev_unlock(struct intel_ipc_dev *ipc_dev)
+{
+	int chan_type;
+
+	if (!ipc_dev || !ipc_dev->cfg)
+		return -ENODEV;
+
+	chan_type = ipc_dev->cfg->chan_type;
+	if (chan_type > IPC_CHANNEL_MAX)
+		return -EINVAL;
+
+	/* release IPC device lock */
+	mutex_unlock(&ipc_dev->lock);
+
+	/* release channel lock */
+	mutex_unlock(&channel_lock[chan_type]);
+
+	return 0;
+}
+
+static const char *ipc_dev_err_string(struct intel_ipc_dev *ipc_dev,
+	int error)
+{
+	if (error < IPC_DEV_ERR_MAX)
+		return ipc_err_sources[error];
+
+	return "Unknown Command";
+}
+
+/* Helper function to send given command to IPC device */
+static inline void ipc_dev_send_cmd(struct intel_ipc_dev *ipc_dev, u32 cmd)
+{
+	ipc_dev->cmd = cmd;
+
+	if (ipc_dev->cfg->mode == IPC_DEV_MODE_IRQ)
+		reinit_completion(&ipc_dev->cmd_complete);
+
+	if (ipc_dev->ops->enable_msi)
+		cmd = ipc_dev->ops->enable_msi(cmd);
+
+	regmap_write(ipc_dev->cfg->cmd_regs, ipc_dev->cfg->cmd_reg, cmd);
+}
+
+static inline int ipc_dev_status_busy(struct intel_ipc_dev *ipc_dev)
+{
+	int status;
+
+	regmap_read(ipc_dev->cfg->cmd_regs, ipc_dev->cfg->status_reg, &status);
+
+	if (ipc_dev->ops->busy_check)
+		return ipc_dev->ops->busy_check(status);
+
+	return 0;
+}
+
+/* Check the status of IPC command and return err code if failed */
+static int ipc_dev_check_status(struct intel_ipc_dev *ipc_dev)
+{
+	int loop_count = IPC_DEV_CMD_LOOP_CNT;
+	int status;
+	int ret = 0;
+
+	if (ipc_dev->cfg->mode == IPC_DEV_MODE_IRQ) {
+		if (!wait_for_completion_timeout(&ipc_dev->cmd_complete,
+				IPC_DEV_CMD_TIMEOUT))
+			ret = -ETIMEDOUT;
+	} else {
+		while (ipc_dev_status_busy(ipc_dev) && --loop_count)
+			udelay(1);
+		if (!loop_count)
+			ret = -ETIMEDOUT;
+	}
+
+	if (ret < 0) {
+		dev_err(&ipc_dev->dev,
+				"IPC timed out, CMD=0x%x\n", ipc_dev->cmd);
+		return ret;
+	}
+
+	regmap_read(ipc_dev->cfg->cmd_regs, ipc_dev->cfg->status_reg, &status);
+
+	if (ipc_dev->ops->to_err_code)
+		ret = ipc_dev->ops->to_err_code(status);
+
+	if (ret) {
+		dev_err(&ipc_dev->dev,
+				"IPC failed: %s, STS=0x%x, CMD=0x%x\n",
+				ipc_dev_err_string(ipc_dev, ret),
+				status, ipc_dev->cmd);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+/**
+ * ipc_dev_simple_cmd() - Send simple IPC command
+ * @ipc_dev     : Reference to ipc device.
+ * @cmd_list    : IPC command list.
+ * @cmdlen      : Number of cmd/sub-cmds.
+ *
+ * Send a simple IPC command to ipc device.
+ * Use this when don't need to specify input/output data
+ * and source/dest pointers.
+ *
+ * Return:	an IPC error code or 0 on success.
+ */
+
+int ipc_dev_simple_cmd(struct intel_ipc_dev *ipc_dev, u32 *cmd_list,
+		u32 cmdlen)
+{
+	int ret;
+
+	if (!cmd_list)
+		return -EINVAL;
+
+	ret = ipc_dev_lock(ipc_dev);
+	if (ret)
+		return ret;
+
+	/* Call custom pre-processing handler */
+	if (ipc_dev->ops->pre_simple_cmd_fn) {
+		ret = ipc_dev->ops->pre_simple_cmd_fn(cmd_list, cmdlen);
+		if (ret)
+			goto unlock_device;
+	}
+
+	ipc_dev_send_cmd(ipc_dev, cmd_list[0]);
+
+	ret = ipc_dev_check_status(ipc_dev);
+
+unlock_device:
+	ipc_dev_unlock(ipc_dev);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(ipc_dev_simple_cmd);
+
+/**
+ * ipc_dev_cmd() - Send IPC command with data.
+ * @ipc_dev     : Reference to ipc_dev.
+ * @ipc_cmd     : Intel IPC command argument structure.
+ *
+ * Send an IPC command to device with input/output data.
+ *
+ * Return:	an IPC error code or 0 on success.
+ */
+int ipc_dev_cmd(struct intel_ipc_dev *ipc_dev, struct intel_ipc_cmd *ipc_cmd)
+{
+	int ret;
+
+	if (!ipc_cmd || !ipc_cmd->cmd_list || !ipc_cmd->in)
+		return -EINVAL;
+
+	ret = ipc_dev_lock(ipc_dev);
+	if (ret)
+		return ret;
+
+	/* Call custom pre-processing handler. */
+	if (ipc_dev->ops->pre_cmd_fn) {
+		ret = ipc_dev->ops->pre_cmd_fn(ipc_cmd);
+		if (ret)
+			goto unlock_device;
+	}
+
+	/* Write inlen dwords of data to wrbuf_reg. */
+	if (ipc_cmd->inlen > 0)
+		regmap_bulk_write(ipc_dev->cfg->data_regs,
+				ipc_dev->cfg->wrbuf_reg, ipc_cmd->in,
+				ipc_cmd->inlen);
+
+	ipc_dev_send_cmd(ipc_dev, ipc_cmd->cmd_list[0]);
+
+	ret = ipc_dev_check_status(ipc_dev);
+
+	/* Read outlen dwords of data from rbug_reg. */
+	if (!ret && ipc_cmd->outlen > 0)
+		regmap_bulk_read(ipc_dev->cfg->data_regs,
+				ipc_dev->cfg->rbuf_reg, ipc_cmd->out,
+				ipc_cmd->outlen);
+unlock_device:
+	ipc_dev_unlock(ipc_dev);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(ipc_dev_cmd);
+
+/**
+ * ipc_dev_raw_cmd() - Send IPC command with data and pointers.
+ * @ipc_dev        : Reference to ipc_dev.
+ * @ipc_raw_cmd    : Intel IPC raw command argument structure.
+ *
+ * Send an IPC command to device with input/output data and
+ * source/dest pointers.
+ *
+ * Return:	an IPC error code or 0 on success.
+ */
+
+int ipc_dev_raw_cmd(struct intel_ipc_dev *ipc_dev,
+		struct intel_ipc_raw_cmd *ipc_raw_cmd)
+{
+	int ret, inbuflen;
+	u32 *inbuf;
+
+	if (!ipc_raw_cmd || !ipc_raw_cmd->cmd_list || !ipc_raw_cmd->in)
+		return -EINVAL;
+
+	inbuflen = DIV_ROUND_UP(ipc_raw_cmd->inlen, 4);
+
+	inbuf = kzalloc(inbuflen, GFP_KERNEL);
+	if (!inbuf)
+		return -ENOMEM;
+
+	ret = ipc_dev_lock(ipc_dev);
+	if (ret)
+		return ret;
+
+	/* Call custom pre-processing handler. */
+	if (ipc_dev->ops->pre_raw_cmd_fn) {
+		ret = ipc_dev->ops->pre_raw_cmd_fn(ipc_raw_cmd);
+		if (ret)
+			goto unlock_device;
+	}
+
+	/* If supported, write DPTR register.*/
+	if (ipc_dev->cfg->support_dptr)
+		regmap_write(ipc_dev->cfg->cmd_regs, ipc_dev->cfg->dptr_reg,
+				ipc_raw_cmd->dptr);
+
+	/* If supported, write SPTR register. */
+	if (ipc_dev->cfg->support_sptr)
+		regmap_write(ipc_dev->cfg->cmd_regs, ipc_dev->cfg->sptr_reg,
+				ipc_raw_cmd->sptr);
+
+	memcpy(inbuf, ipc_raw_cmd->in, ipc_raw_cmd->inlen);
+
+	/* Write inlen dwords of data to wrbuf_reg. */
+	if (ipc_raw_cmd->inlen > 0)
+		regmap_bulk_write(ipc_dev->cfg->data_regs,
+				ipc_dev->cfg->wrbuf_reg, inbuf, inbuflen);
+
+	ipc_dev_send_cmd(ipc_dev, ipc_raw_cmd->cmd_list[0]);
+
+	ret = ipc_dev_check_status(ipc_dev);
+
+	/* Read outlen dwords of data from rbug_reg. */
+	if (!ret && ipc_raw_cmd->outlen > 0)
+		regmap_bulk_read(ipc_dev->cfg->data_regs,
+				ipc_dev->cfg->rbuf_reg, ipc_raw_cmd->out,
+				ipc_raw_cmd->outlen);
+unlock_device:
+	ipc_dev_unlock(ipc_dev);
+	kfree(inbuf);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(ipc_dev_raw_cmd);
+
+/* sysfs option to send simple IPC commands from userspace */
+static ssize_t ipc_dev_cmd_reg_store(struct device *dev,
+				     struct device_attribute *attr,
+				     const char *buf, size_t count)
+{
+	struct intel_ipc_dev *ipc_dev = dev_get_drvdata(dev);
+	u32 cmd;
+	int ret;
+
+	ret = kstrtou32(buf, 0, &cmd);
+	if (ret < 0)
+		return -EINVAL;
+
+	ret = ipc_dev_simple_cmd(ipc_dev, &cmd, 1);
+	if (ret) {
+		dev_err(dev, "command 0x%x error with %d\n", cmd, ret);
+		return ret;
+	}
+	return (ssize_t)count;
+}
+
+static DEVICE_ATTR(send_cmd, 00200, NULL, ipc_dev_cmd_reg_store);
+
+static struct attribute *ipc_dev_attrs[] = {
+	&dev_attr_send_cmd.attr,
+	NULL
+};
+
+static const struct attribute_group ipc_dev_group = {
+	.attrs = ipc_dev_attrs,
+};
+
+static const struct attribute_group *ipc_dev_groups[] = {
+	&ipc_dev_group,
+	NULL,
+};
+
+/* IPC device IRQ handler */
+static irqreturn_t ipc_dev_irq_handler(int irq, void *dev_id)
+{
+	struct intel_ipc_dev *ipc_dev = (struct intel_ipc_dev *)dev_id;
+
+	if (ipc_dev->ops->pre_irq_handler_fn)
+		ipc_dev->ops->pre_irq_handler_fn(ipc_dev, irq);
+
+	complete(&ipc_dev->cmd_complete);
+
+	return IRQ_HANDLED;
+}
+
+static void devm_intel_ipc_dev_release(struct device *dev, void *res)
+{
+	struct intel_ipc_dev *ipc_dev = *(struct intel_ipc_dev **)res;
+
+	if (!ipc_dev)
+		return;
+
+	device_del(&ipc_dev->dev);
+
+	kfree(ipc_dev);
+}
+
+static int match_name(struct device *dev, const void *data)
+{
+	if (!dev_name(dev))
+		return 0;
+
+	return !strcmp(dev_name(dev), (char *)data);
+}
+
+/**
+ * intel_ipc_dev_get() - Get Intel IPC device from name.
+ * @dev_name    : Name of the IPC device.
+ *
+ * Return       : ERR_PTR/NULL or intel_ipc_dev pointer on success.
+ */
+struct intel_ipc_dev *intel_ipc_dev_get(const char *dev_name)
+{
+	struct device *dev;
+
+	if (!dev_name)
+		return ERR_PTR(-EINVAL);
+
+	dev = class_find_device(&intel_ipc_class, NULL, dev_name, match_name);
+
+	return dev ? dev_get_drvdata(dev) : NULL;
+}
+EXPORT_SYMBOL_GPL(intel_ipc_dev_get);
+
+static void devm_intel_ipc_dev_put(struct device *dev, void *res)
+{
+	intel_ipc_dev_put(*(struct intel_ipc_dev **)res);
+}
+
+/**
+ * devm_intel_ipc_dev_get() - Resource managed version of intel_ipc_dev_get().
+ * @dev         : Device pointer.
+ * @dev_name    : Name of the IPC device.
+ *
+ * Return       : ERR_PTR/NULL or intel_ipc_dev pointer on success.
+ */
+struct intel_ipc_dev *devm_intel_ipc_dev_get(struct device *dev,
+					const char *dev_name)
+{
+	struct intel_ipc_dev **ptr, *ipc_dev;
+
+	ptr = devres_alloc(devm_intel_ipc_dev_put, sizeof(*ptr), GFP_KERNEL);
+	if (!ptr)
+		return ERR_PTR(-ENOMEM);
+
+	ipc_dev = intel_ipc_dev_get(dev_name);
+	if (!IS_ERR_OR_NULL(ipc_dev)) {
+		*ptr = ipc_dev;
+		devres_add(dev, ptr);
+	} else {
+		devres_free(ptr);
+	}
+
+	return ipc_dev;
+}
+EXPORT_SYMBOL_GPL(devm_intel_ipc_dev_get);
+
+/**
+ * devm_intel_ipc_dev_create() - Create IPC device
+ * @dev		: IPC parent device.
+ * @devname	: Name of the IPC device.
+ * @cfg		: IPC device configuration.
+ * @ops		: IPC device ops.
+ *
+ * Resource managed API to create IPC device with
+ * given configuration.
+ *
+ * Return	: IPC device pointer or ERR_PTR(error code).
+ */
+struct intel_ipc_dev *devm_intel_ipc_dev_create(struct device *dev,
+		const char *devname,
+		struct intel_ipc_dev_cfg *cfg,
+		struct intel_ipc_dev_ops *ops)
+{
+	struct intel_ipc_dev **ptr, *ipc_dev;
+	int ret;
+
+	if (!dev && !devname && !cfg)
+		return ERR_PTR(-EINVAL);
+
+	if (intel_ipc_dev_get(devname)) {
+		dev_err(dev, "IPC device %s already exist\n", devname);
+		return ERR_PTR(-EINVAL);
+	}
+
+	ptr = devres_alloc(devm_intel_ipc_dev_release, sizeof(*ptr),
+			GFP_KERNEL);
+	if (!ptr)
+		return ERR_PTR(-ENOMEM);
+
+	ipc_dev = kzalloc(sizeof(*ipc_dev), GFP_KERNEL);
+	if (!ipc_dev) {
+		ret = -ENOMEM;
+		goto err_dev_create;
+	}
+
+	ipc_dev->dev.class = &intel_ipc_class;
+	ipc_dev->dev.parent = dev;
+	ipc_dev->dev.groups = ipc_dev_groups;
+	ipc_dev->cfg = cfg;
+	ipc_dev->ops = ops;
+
+	mutex_init(&ipc_dev->lock);
+	init_completion(&ipc_dev->cmd_complete);
+	dev_set_drvdata(&ipc_dev->dev, ipc_dev);
+	dev_set_name(&ipc_dev->dev, devname);
+	device_initialize(&ipc_dev->dev);
+
+	ret = device_add(&ipc_dev->dev);
+	if (ret < 0) {
+		dev_err(&ipc_dev->dev, "%s device create failed\n",
+				__func__);
+		ret = -ENODEV;
+		goto err_dev_add;
+	}
+
+	if (ipc_dev->cfg->mode == IPC_DEV_MODE_IRQ) {
+		if (devm_request_irq(&ipc_dev->dev,
+				ipc_dev->cfg->irq,
+				ipc_dev_irq_handler,
+				ipc_dev->cfg->irqflags,
+				dev_name(&ipc_dev->dev),
+				ipc_dev)) {
+			dev_err(&ipc_dev->dev,
+					"Failed to request irq\n");
+			goto err_irq_request;
+		}
+	}
+
+	*ptr = ipc_dev;
+
+	devres_add(dev, ptr);
+
+	return ipc_dev;
+
+err_irq_request:
+	device_del(&ipc_dev->dev);
+err_dev_add:
+	kfree(ipc_dev);
+err_dev_create:
+	devres_free(ptr);
+	return ERR_PTR(ret);
+}
+EXPORT_SYMBOL_GPL(devm_intel_ipc_dev_create);
+
+static int __init intel_ipc_init(void)
+{
+	ipc_channel_lock_init();
+	return class_register(&intel_ipc_class);
+}
+
+static void __exit intel_ipc_exit(void)
+{
+	class_unregister(&intel_ipc_class);
+}
+subsys_initcall(intel_ipc_init);
+module_exit(intel_ipc_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Kuppuswamy Sathyanarayanan<sathyanarayanan.kuppuswamy@linux.intel.com>");
+MODULE_DESCRIPTION("Intel IPC device class driver");
diff --git a/include/linux/platform_data/x86/intel_ipc_dev.h b/include/linux/platform_data/x86/intel_ipc_dev.h
new file mode 100644
index 0000000..9e6ce6d
--- /dev/null
+++ b/include/linux/platform_data/x86/intel_ipc_dev.h
@@ -0,0 +1,246 @@
+/*
+ * Intel IPC class device header file.
+ *
+ * (C) Copyright 2017 Intel Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; version 2
+ * of the License.
+ *
+ */
+
+#ifndef INTEL_IPC_DEV_H
+#define INTEL_IPC_DEV_H
+
+#include <linux/module.h>
+#include <linux/device.h>
+
+/* IPC channel type */
+#define IPC_CHANNEL_IA_PMC                      0
+#define IPC_CHANNEL_IA_PUNIT                    1
+#define IPC_CHANNEL_PMC_PUNIT                   2
+#define IPC_CHANNEL_IA_SCU                      3
+#define IPC_CHANNEL_MAX                         4
+
+/* IPC return code */
+#define IPC_DEV_ERR_NONE			0
+#define IPC_DEV_ERR_CMD_NOT_SUPPORTED		1
+#define IPC_DEV_ERR_CMD_NOT_SERVICED		2
+#define IPC_DEV_ERR_UNABLE_TO_SERVICE		3
+#define IPC_DEV_ERR_CMD_INVALID			4
+#define IPC_DEV_ERR_CMD_FAILED			5
+#define IPC_DEV_ERR_EMSECURITY			6
+#define IPC_DEV_ERR_UNSIGNEDKERNEL		7
+#define IPC_DEV_ERR_MAX				8
+
+/* IPC mode */
+#define IPC_DEV_MODE_IRQ			0
+#define IPC_DEV_MODE_POLLING			1
+
+/* IPC dev constants */
+#define IPC_DEV_CMD_LOOP_CNT			3000000
+#define IPC_DEV_CMD_TIMEOUT			(3 * HZ)
+#define IPC_DEV_DATA_BUFFER_SIZE		16
+
+struct intel_ipc_dev;
+struct intel_ipc_raw_cmd;
+
+/**
+ * struct intel_ipc_dev_cfg - IPC device config structure.
+ *
+ * IPC device drivers uses the following config options to
+ * register new IPC device.
+ *
+ * @cmd_regs            : IPC device command base regmap.
+ * @data_regs           : IPC device data base regmap.
+ * @wrbuf_reg           : IPC device data write register address.
+ * @rbuf_reg            : IPC device data read register address.
+ * @sptr_reg            : IPC device source data pointer register address.
+ * @dptr_reg            : IPC device destination data pointer register
+ *                        address.
+ * @status_reg          : IPC command status register address.
+ * @cmd_reg             : IPC command register address.
+ * @mode                : IRQ/POLLING mode.
+ * @irq                 : IPC device IRQ number.
+ * @irqflags            : IPC device IRQ flags.
+ * @chan_type           : IPC device channel type(PMC/PUNIT).
+ * @msi                 : Enable/Disable MSI for IPC commands.
+ * @support_dptr        : Support DPTR update.
+ * @support_sptr        : Support SPTR update.
+ *
+ */
+struct intel_ipc_dev_cfg {
+	struct regmap *cmd_regs;
+	struct regmap *data_regs;
+	unsigned int wrbuf_reg;
+	unsigned int rbuf_reg;
+	unsigned int sptr_reg;
+	unsigned int dptr_reg;
+	unsigned int status_reg;
+	unsigned int cmd_reg;
+	int mode;
+	int irq;
+	int irqflags;
+	int chan_type;
+	bool use_msi;
+	bool support_dptr;
+	bool support_sptr;
+};
+
+/**
+ * struct intel_ipc_raw_cmd - Intel IPC raw command args.
+ *
+ * @cmd_list    : Array of commands/sub-commands.
+ * @cmdlen      : Number of commands.
+ * @in          : Input data of this IPC command.
+ * @inlen       : Input data length in bytes.
+ * @out         : Output data of this IPC command.
+ * @outlen      : Length of output data in dwords.
+ * @dptr        : IPC destination data address.
+ * @sptr        : IPC source data address.
+ *
+ */
+struct intel_ipc_raw_cmd {
+	u32 *cmd_list;
+	u32 cmdlen;
+	u8 *in;
+	u32 inlen;
+	u32 *out;
+	u32 outlen;
+	u32 dptr;
+	u32 sptr;
+};
+
+/**
+ * struct intel_ipc_raw_cmd - Intel IPC command args.
+ *
+ * @cmd_list    : Array of commands/sub-commands.
+ * @cmdlen      : Number of commands.
+ * @in          : Input data of this IPC command.
+ * @inlen       : Input data length in bytes.
+ * @out         : Output data of this IPC command.
+ * @outlen      : Length of output data in dwords.
+ *
+ */
+struct intel_ipc_cmd {
+	u32 *cmd_list;
+	u32 cmdlen;
+	u32 *in;
+	u32 inlen;
+	u32 *out;
+	u32 outlen;
+};
+
+/**
+ * struct intel_ipc_dev_ops - IPC device ops structure.
+ *
+ * Call backs for IPC device specific operations.
+ *
+ * @to_err_code         : Status to error code conversion function.
+ * @busy_check          : Check for IPC busy status.
+ * @enable_msi          : Enable MSI for IPC commands.
+ * @pre_simple_cmd_fn   : Custom pre-processing function for
+ *                        ipc_dev_simple_cmd()
+ * @pre_cmd_fn          : Custom pre-processing function for
+ *                        ipc_dev_cmd()
+ * @pre_raw_cmd_fn      : Custom pre-processing function for
+ *                        ipc_dev_raw_cmd()
+ *
+ */
+struct intel_ipc_dev_ops {
+	int (*to_err_code)(int status);
+	int (*busy_check)(int status);
+	u32 (*enable_msi)(u32 cmd);
+	int (*pre_simple_cmd_fn)(u32 *cmd_list, u32 cmdlen);
+	int (*pre_cmd_fn)(struct intel_ipc_cmd *ipc_cmd);
+	int (*pre_raw_cmd_fn)(struct intel_ipc_raw_cmd *ipc_raw_cmd);
+	int (*pre_irq_handler_fn)(struct intel_ipc_dev *ipc_dev, int irq);
+};
+
+/**
+ * struct intel_ipc_dev - Intel IPC device structure.
+ *
+ * Used with devm_intel_ipc_dev_create() to create new IPC device.
+ *
+ * @dev                 : IPC device object.
+ * @cmd                 : Current IPC device command.
+ * @cmd_complete        : Command completion object.
+ * @lock                : Lock to protect IPC device structure.
+ * @ops                 : IPC device ops pointer.
+ * @cfg                 : IPC device cfg pointer.
+ *
+ */
+struct intel_ipc_dev {
+	struct device dev;
+	int cmd;
+	struct completion cmd_complete;
+	struct mutex lock;
+	struct intel_ipc_dev_ops *ops;
+	struct intel_ipc_dev_cfg *cfg;
+};
+
+#if IS_ENABLED(CONFIG_INTEL_IPC_DEV)
+
+/* API to create new IPC device */
+struct intel_ipc_dev *devm_intel_ipc_dev_create(struct device *dev,
+		const char *devname, struct intel_ipc_dev_cfg *cfg,
+		struct intel_ipc_dev_ops *ops);
+
+int ipc_dev_simple_cmd(struct intel_ipc_dev *ipc_dev, u32 *cmd_list,
+		u32 cmdlen);
+int ipc_dev_cmd(struct intel_ipc_dev *ipc_dev, struct intel_ipc_cmd *ipc_cmd);
+int ipc_dev_raw_cmd(struct intel_ipc_dev *ipc_dev,
+		struct intel_ipc_raw_cmd *ipc_raw_cmd);
+struct intel_ipc_dev *intel_ipc_dev_get(const char *dev_name);
+struct intel_ipc_dev *devm_intel_ipc_dev_get(struct device *dev,
+					const char *dev_name);
+static inline void intel_ipc_dev_put(struct intel_ipc_dev *ipc_dev)
+{
+	put_device(&ipc_dev->dev);
+}
+#else
+
+static inline struct intel_ipc_dev *devm_intel_ipc_dev_create(
+		struct device *dev,
+		const char *devname, struct intel_ipc_dev_cfg *cfg,
+		struct intel_ipc_dev_ops *ops)
+{
+	return -EINVAL;
+}
+
+static inline int ipc_dev_simple_cmd(struct intel_ipc_dev *ipc_dev,
+		u32 *cmd_list, u32 cmdlen)
+{
+	return -EINVAL;
+}
+
+static int ipc_dev_cmd(struct intel_ipc_dev *ipc_dev,
+		struct intel_ipc_cmd *ipc_cmd)
+{
+	return -EINVAL;
+}
+
+static inline int ipc_dev_raw_cmd(struct intel_ipc_dev *ipc_dev,
+		struct intel_ipc_raw_cmd *ipc_raw_cmd);
+{
+	return -EINVAL;
+}
+
+static inline struct intel_ipc_dev *intel_ipc_dev_get(const char *dev_name)
+{
+	return NULL;
+}
+
+static inline struct intel_ipc_dev *devm_intel_ipc_dev_get(struct device *dev,
+					const char *dev_name);
+{
+	return NULL;
+}
+
+static inline void intel_ipc_dev_put(struct intel_ipc_dev *ipc_dev)
+{
+	return NULL;
+}
+#endif /* CONFIG_INTEL_IPC_DEV */
+#endif /* INTEL_IPC_DEV_H */
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [RFC v8 5/7] platform/x86: intel_punit_ipc: Use generic intel ipc device calls
  2017-10-29  9:49 ` sathyanarayanan.kuppuswamy
  (?)
@ 2017-10-29  9:49   ` sathyanarayanan.kuppuswamy
  -1 siblings, 0 replies; 30+ messages in thread
From: sathyanarayanan.kuppuswamy @ 2017-10-29  9:49 UTC (permalink / raw)
  To: a.zummo, x86, wim, mingo, alexandre.belloni, qipeng.zha, hpa,
	dvhart, tglx, lee.jones, andy, souvik.k.chakravarty
  Cc: linux-rtc, linux-watchdog, linux-kernel, platform-driver-x86,
	sathyaosid, Kuppuswamy Sathyanarayanan

From: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>

Removed redundant IPC helper functions and refactored the driver to use
APIs provided by generic IPC driver. This patch also cleans-up PUNIT IPC
user drivers(intel_telemetry_pltdrv.c) to use APIs provided by generic IPC
driver.

Signed-off-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>
---
 arch/x86/include/asm/intel_punit_ipc.h        | 125 +++++------
 drivers/platform/x86/Kconfig                  |   1 +
 drivers/platform/x86/intel_punit_ipc.c        | 299 +++++++++-----------------
 drivers/platform/x86/intel_telemetry_pltdrv.c | 103 +++++----
 4 files changed, 222 insertions(+), 306 deletions(-)

Changes since v7:
 * Fixed style issues.

Changes since v6:
 * None

Changes since v5:
 * Adapted to change in arguments of ipc_dev_cmd() and ipc_dev_raw_cmd() APIs.

Changes since v4:
 * None

Changes since v2:
 * Added unique name to PUNIT BIOS, GTD, & ISP regmaps.
 * Added intel_ipc_dev_put() support.

Changes since v1:
 * Removed custom APIs.
 * Cleaned up PUNIT IPC user drivers to use APIs provided by generic
   IPC driver.

diff --git a/arch/x86/include/asm/intel_punit_ipc.h b/arch/x86/include/asm/intel_punit_ipc.h
index 201eb9d..8d1ab9e 100644
--- a/arch/x86/include/asm/intel_punit_ipc.h
+++ b/arch/x86/include/asm/intel_punit_ipc.h
@@ -1,10 +1,8 @@
 #ifndef _ASM_X86_INTEL_PUNIT_IPC_H_
 #define  _ASM_X86_INTEL_PUNIT_IPC_H_
 
-/*
- * Three types of 8bit P-Unit IPC commands are supported,
- * bit[7:6]: [00]: BIOS; [01]: GTD; [10]: ISPD.
- */
+#include <linux/platform_data/x86/intel_ipc_dev.h>
+
 typedef enum {
 	BIOS_IPC = 0,
 	GTDRIVER_IPC,
@@ -12,61 +10,60 @@ typedef enum {
 	RESERVED_IPC,
 } IPC_TYPE;
 
-#define IPC_TYPE_OFFSET			6
-#define IPC_PUNIT_BIOS_CMD_BASE		(BIOS_IPC << IPC_TYPE_OFFSET)
-#define IPC_PUNIT_GTD_CMD_BASE		(GTDDRIVER_IPC << IPC_TYPE_OFFSET)
-#define IPC_PUNIT_ISPD_CMD_BASE		(ISPDRIVER_IPC << IPC_TYPE_OFFSET)
-#define IPC_PUNIT_CMD_TYPE_MASK		(RESERVED_IPC << IPC_TYPE_OFFSET)
+#define PUNIT_BIOS_IPC_DEV			"punit_bios_ipc"
+#define PUNIT_GTD_IPC_DEV			"punit_gtd_ipc"
+#define PUNIT_ISP_IPC_DEV			"punit_isp_ipc"
+#define PUNIT_PARAM_LEN				3
 
 /* BIOS => Pcode commands */
-#define IPC_PUNIT_BIOS_ZERO			(IPC_PUNIT_BIOS_CMD_BASE | 0x00)
-#define IPC_PUNIT_BIOS_VR_INTERFACE		(IPC_PUNIT_BIOS_CMD_BASE | 0x01)
-#define IPC_PUNIT_BIOS_READ_PCS			(IPC_PUNIT_BIOS_CMD_BASE | 0x02)
-#define IPC_PUNIT_BIOS_WRITE_PCS		(IPC_PUNIT_BIOS_CMD_BASE | 0x03)
-#define IPC_PUNIT_BIOS_READ_PCU_CONFIG		(IPC_PUNIT_BIOS_CMD_BASE | 0x04)
-#define IPC_PUNIT_BIOS_WRITE_PCU_CONFIG		(IPC_PUNIT_BIOS_CMD_BASE | 0x05)
-#define IPC_PUNIT_BIOS_READ_PL1_SETTING		(IPC_PUNIT_BIOS_CMD_BASE | 0x06)
-#define IPC_PUNIT_BIOS_WRITE_PL1_SETTING	(IPC_PUNIT_BIOS_CMD_BASE | 0x07)
-#define IPC_PUNIT_BIOS_TRIGGER_VDD_RAM		(IPC_PUNIT_BIOS_CMD_BASE | 0x08)
-#define IPC_PUNIT_BIOS_READ_TELE_INFO		(IPC_PUNIT_BIOS_CMD_BASE | 0x09)
-#define IPC_PUNIT_BIOS_READ_TELE_TRACE_CTRL	(IPC_PUNIT_BIOS_CMD_BASE | 0x0a)
-#define IPC_PUNIT_BIOS_WRITE_TELE_TRACE_CTRL	(IPC_PUNIT_BIOS_CMD_BASE | 0x0b)
-#define IPC_PUNIT_BIOS_READ_TELE_EVENT_CTRL	(IPC_PUNIT_BIOS_CMD_BASE | 0x0c)
-#define IPC_PUNIT_BIOS_WRITE_TELE_EVENT_CTRL	(IPC_PUNIT_BIOS_CMD_BASE | 0x0d)
-#define IPC_PUNIT_BIOS_READ_TELE_TRACE		(IPC_PUNIT_BIOS_CMD_BASE | 0x0e)
-#define IPC_PUNIT_BIOS_WRITE_TELE_TRACE		(IPC_PUNIT_BIOS_CMD_BASE | 0x0f)
-#define IPC_PUNIT_BIOS_READ_TELE_EVENT		(IPC_PUNIT_BIOS_CMD_BASE | 0x10)
-#define IPC_PUNIT_BIOS_WRITE_TELE_EVENT		(IPC_PUNIT_BIOS_CMD_BASE | 0x11)
-#define IPC_PUNIT_BIOS_READ_MODULE_TEMP		(IPC_PUNIT_BIOS_CMD_BASE | 0x12)
-#define IPC_PUNIT_BIOS_RESERVED			(IPC_PUNIT_BIOS_CMD_BASE | 0x13)
-#define IPC_PUNIT_BIOS_READ_VOLTAGE_OVER	(IPC_PUNIT_BIOS_CMD_BASE | 0x14)
-#define IPC_PUNIT_BIOS_WRITE_VOLTAGE_OVER	(IPC_PUNIT_BIOS_CMD_BASE | 0x15)
-#define IPC_PUNIT_BIOS_READ_RATIO_OVER		(IPC_PUNIT_BIOS_CMD_BASE | 0x16)
-#define IPC_PUNIT_BIOS_WRITE_RATIO_OVER		(IPC_PUNIT_BIOS_CMD_BASE | 0x17)
-#define IPC_PUNIT_BIOS_READ_VF_GL_CTRL		(IPC_PUNIT_BIOS_CMD_BASE | 0x18)
-#define IPC_PUNIT_BIOS_WRITE_VF_GL_CTRL		(IPC_PUNIT_BIOS_CMD_BASE | 0x19)
-#define IPC_PUNIT_BIOS_READ_FM_SOC_TEMP_THRESH	(IPC_PUNIT_BIOS_CMD_BASE | 0x1a)
-#define IPC_PUNIT_BIOS_WRITE_FM_SOC_TEMP_THRESH	(IPC_PUNIT_BIOS_CMD_BASE | 0x1b)
+#define IPC_PUNIT_BIOS_ZERO			(0x00)
+#define IPC_PUNIT_BIOS_VR_INTERFACE		(0x01)
+#define IPC_PUNIT_BIOS_READ_PCS			(0x02)
+#define IPC_PUNIT_BIOS_WRITE_PCS		(0x03)
+#define IPC_PUNIT_BIOS_READ_PCU_CONFIG		(0x04)
+#define IPC_PUNIT_BIOS_WRITE_PCU_CONFIG		(0x05)
+#define IPC_PUNIT_BIOS_READ_PL1_SETTING		(0x06)
+#define IPC_PUNIT_BIOS_WRITE_PL1_SETTING	(0x07)
+#define IPC_PUNIT_BIOS_TRIGGER_VDD_RAM		(0x08)
+#define IPC_PUNIT_BIOS_READ_TELE_INFO		(0x09)
+#define IPC_PUNIT_BIOS_READ_TELE_TRACE_CTRL	(0x0a)
+#define IPC_PUNIT_BIOS_WRITE_TELE_TRACE_CTRL	(0x0b)
+#define IPC_PUNIT_BIOS_READ_TELE_EVENT_CTRL	(0x0c)
+#define IPC_PUNIT_BIOS_WRITE_TELE_EVENT_CTRL	(0x0d)
+#define IPC_PUNIT_BIOS_READ_TELE_TRACE		(0x0e)
+#define IPC_PUNIT_BIOS_WRITE_TELE_TRACE		(0x0f)
+#define IPC_PUNIT_BIOS_READ_TELE_EVENT		(0x10)
+#define IPC_PUNIT_BIOS_WRITE_TELE_EVENT		(0x11)
+#define IPC_PUNIT_BIOS_READ_MODULE_TEMP		(0x12)
+#define IPC_PUNIT_BIOS_RESERVED			(0x13)
+#define IPC_PUNIT_BIOS_READ_VOLTAGE_OVER	(0x14)
+#define IPC_PUNIT_BIOS_WRITE_VOLTAGE_OVER	(0x15)
+#define IPC_PUNIT_BIOS_READ_RATIO_OVER		(0x16)
+#define IPC_PUNIT_BIOS_WRITE_RATIO_OVER		(0x17)
+#define IPC_PUNIT_BIOS_READ_VF_GL_CTRL		(0x18)
+#define IPC_PUNIT_BIOS_WRITE_VF_GL_CTRL		(0x19)
+#define IPC_PUNIT_BIOS_READ_FM_SOC_TEMP_THRESH	(0x1a)
+#define IPC_PUNIT_BIOS_WRITE_FM_SOC_TEMP_THRESH	(0x1b)
 
 /* GT Driver => Pcode commands */
-#define IPC_PUNIT_GTD_ZERO			(IPC_PUNIT_GTD_CMD_BASE | 0x00)
-#define IPC_PUNIT_GTD_CONFIG			(IPC_PUNIT_GTD_CMD_BASE | 0x01)
-#define IPC_PUNIT_GTD_READ_ICCP_LIC_CDYN_SCAL	(IPC_PUNIT_GTD_CMD_BASE | 0x02)
-#define IPC_PUNIT_GTD_WRITE_ICCP_LIC_CDYN_SCAL	(IPC_PUNIT_GTD_CMD_BASE | 0x03)
-#define IPC_PUNIT_GTD_GET_WM_VAL		(IPC_PUNIT_GTD_CMD_BASE | 0x06)
-#define IPC_PUNIT_GTD_WRITE_CONFIG_WISHREQ	(IPC_PUNIT_GTD_CMD_BASE | 0x07)
-#define IPC_PUNIT_GTD_READ_REQ_DUTY_CYCLE	(IPC_PUNIT_GTD_CMD_BASE | 0x16)
-#define IPC_PUNIT_GTD_DIS_VOL_FREQ_CHG_REQUEST	(IPC_PUNIT_GTD_CMD_BASE | 0x17)
-#define IPC_PUNIT_GTD_DYNA_DUTY_CYCLE_CTRL	(IPC_PUNIT_GTD_CMD_BASE | 0x1a)
-#define IPC_PUNIT_GTD_DYNA_DUTY_CYCLE_TUNING	(IPC_PUNIT_GTD_CMD_BASE | 0x1c)
+#define IPC_PUNIT_GTD_ZERO			(0x00)
+#define IPC_PUNIT_GTD_CONFIG			(0x01)
+#define IPC_PUNIT_GTD_READ_ICCP_LIC_CDYN_SCAL	(0x02)
+#define IPC_PUNIT_GTD_WRITE_ICCP_LIC_CDYN_SCAL	(0x03)
+#define IPC_PUNIT_GTD_GET_WM_VAL		(0x06)
+#define IPC_PUNIT_GTD_WRITE_CONFIG_WISHREQ	(0x07)
+#define IPC_PUNIT_GTD_READ_REQ_DUTY_CYCLE	(0x16)
+#define IPC_PUNIT_GTD_DIS_VOL_FREQ_CHG_REQUEST	(0x17)
+#define IPC_PUNIT_GTD_DYNA_DUTY_CYCLE_CTRL	(0x1a)
+#define IPC_PUNIT_GTD_DYNA_DUTY_CYCLE_TUNING	(0x1c)
 
 /* ISP Driver => Pcode commands */
-#define IPC_PUNIT_ISPD_ZERO			(IPC_PUNIT_ISPD_CMD_BASE | 0x00)
-#define IPC_PUNIT_ISPD_CONFIG			(IPC_PUNIT_ISPD_CMD_BASE | 0x01)
-#define IPC_PUNIT_ISPD_GET_ISP_LTR_VAL		(IPC_PUNIT_ISPD_CMD_BASE | 0x02)
-#define IPC_PUNIT_ISPD_ACCESS_IU_FREQ_BOUNDS	(IPC_PUNIT_ISPD_CMD_BASE | 0x03)
-#define IPC_PUNIT_ISPD_READ_CDYN_LEVEL		(IPC_PUNIT_ISPD_CMD_BASE | 0x04)
-#define IPC_PUNIT_ISPD_WRITE_CDYN_LEVEL		(IPC_PUNIT_ISPD_CMD_BASE | 0x05)
+#define IPC_PUNIT_ISPD_ZERO			(0x00)
+#define IPC_PUNIT_ISPD_CONFIG			(0x01)
+#define IPC_PUNIT_ISPD_GET_ISP_LTR_VAL		(0x02)
+#define IPC_PUNIT_ISPD_ACCESS_IU_FREQ_BOUNDS	(0x03)
+#define IPC_PUNIT_ISPD_READ_CDYN_LEVEL		(0x04)
+#define IPC_PUNIT_ISPD_WRITE_CDYN_LEVEL		(0x05)
 
 /* Error codes */
 #define IPC_PUNIT_ERR_SUCCESS			0
@@ -76,26 +73,4 @@ typedef enum {
 #define IPC_PUNIT_ERR_CMD_LOCKED		4
 #define IPC_PUNIT_ERR_INVALID_VR_ID		5
 #define IPC_PUNIT_ERR_VR_ERR			6
-
-#if IS_ENABLED(CONFIG_INTEL_PUNIT_IPC)
-
-int intel_punit_ipc_simple_command(int cmd, int para1, int para2);
-int intel_punit_ipc_command(u32 cmd, u32 para1, u32 para2, u32 *in, u32 *out);
-
-#else
-
-static inline int intel_punit_ipc_simple_command(int cmd,
-						  int para1, int para2)
-{
-	return -ENODEV;
-}
-
-static inline int intel_punit_ipc_command(u32 cmd, u32 para1, u32 para2,
-					  u32 *in, u32 *out)
-{
-	return -ENODEV;
-}
-
-#endif /* CONFIG_INTEL_PUNIT_IPC */
-
 #endif
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
index 9df7cda..82479ca 100644
--- a/drivers/platform/x86/Kconfig
+++ b/drivers/platform/x86/Kconfig
@@ -1083,6 +1083,7 @@ config SURFACE_3_BUTTON
 
 config INTEL_PUNIT_IPC
 	tristate "Intel P-Unit IPC Driver"
+	select REGMAP_MMIO
 	---help---
 	  This driver provides support for Intel P-Unit Mailbox IPC mechanism,
 	  which is used to bridge the communications between kernel and P-Unit.
diff --git a/drivers/platform/x86/intel_punit_ipc.c b/drivers/platform/x86/intel_punit_ipc.c
index b5b8901..50fd502 100644
--- a/drivers/platform/x86/intel_punit_ipc.c
+++ b/drivers/platform/x86/intel_punit_ipc.c
@@ -18,19 +18,16 @@
 #include <linux/device.h>
 #include <linux/interrupt.h>
 #include <linux/platform_device.h>
+#include <linux/platform_data/x86/intel_ipc_dev.h>
+#include <linux/regmap.h>
 #include <asm/intel_punit_ipc.h>
 
-/* IPC Mailbox registers */
-#define OFFSET_DATA_LOW		0x0
-#define OFFSET_DATA_HIGH	0x4
 /* bit field of interface register */
 #define	CMD_RUN			BIT(31)
 #define	CMD_ERRCODE_MASK	GENMASK(7, 0)
 #define	CMD_PARA1_SHIFT		8
 #define	CMD_PARA2_SHIFT		16
 
-#define CMD_TIMEOUT_SECONDS	1
-
 enum {
 	BASE_DATA = 0,
 	BASE_IFACE,
@@ -39,187 +36,41 @@ enum {
 
 typedef struct {
 	struct device *dev;
-	struct mutex lock;
-	int irq;
-	struct completion cmd_complete;
 	/* base of interface and data registers */
 	void __iomem *base[RESERVED_IPC][BASE_MAX];
+	struct intel_ipc_dev *ipc_dev[RESERVED_IPC];
 	IPC_TYPE type;
 } IPC_DEV;
 
 static IPC_DEV *punit_ipcdev;
 
-static inline u32 ipc_read_status(IPC_DEV *ipcdev, IPC_TYPE type)
-{
-	return readl(ipcdev->base[type][BASE_IFACE]);
-}
-
-static inline void ipc_write_cmd(IPC_DEV *ipcdev, IPC_TYPE type, u32 cmd)
-{
-	writel(cmd, ipcdev->base[type][BASE_IFACE]);
-}
-
-static inline u32 ipc_read_data_low(IPC_DEV *ipcdev, IPC_TYPE type)
-{
-	return readl(ipcdev->base[type][BASE_DATA] + OFFSET_DATA_LOW);
-}
-
-static inline u32 ipc_read_data_high(IPC_DEV *ipcdev, IPC_TYPE type)
-{
-	return readl(ipcdev->base[type][BASE_DATA] + OFFSET_DATA_HIGH);
-}
-
-static inline void ipc_write_data_low(IPC_DEV *ipcdev, IPC_TYPE type, u32 data)
-{
-	writel(data, ipcdev->base[type][BASE_DATA] + OFFSET_DATA_LOW);
-}
-
-static inline void ipc_write_data_high(IPC_DEV *ipcdev, IPC_TYPE type, u32 data)
-{
-	writel(data, ipcdev->base[type][BASE_DATA] + OFFSET_DATA_HIGH);
-}
+const char *ipc_dev_name[RESERVED_IPC] = {
+	PUNIT_BIOS_IPC_DEV,
+	PUNIT_GTD_IPC_DEV,
+	PUNIT_ISP_IPC_DEV
+};
 
-static const char *ipc_err_string(int error)
-{
-	if (error == IPC_PUNIT_ERR_SUCCESS)
-		return "no error";
-	else if (error == IPC_PUNIT_ERR_INVALID_CMD)
-		return "invalid command";
-	else if (error == IPC_PUNIT_ERR_INVALID_PARAMETER)
-		return "invalid parameter";
-	else if (error == IPC_PUNIT_ERR_CMD_TIMEOUT)
-		return "command timeout";
-	else if (error == IPC_PUNIT_ERR_CMD_LOCKED)
-		return "command locked";
-	else if (error == IPC_PUNIT_ERR_INVALID_VR_ID)
-		return "invalid vr id";
-	else if (error == IPC_PUNIT_ERR_VR_ERR)
-		return "vr error";
-	else
-		return "unknown error";
-}
+static struct regmap_config punit_regmap_config = {
+	.reg_bits = 32,
+	.reg_stride = 4,
+	.val_bits = 32,
+};
 
-static int intel_punit_ipc_check_status(IPC_DEV *ipcdev, IPC_TYPE type)
+int pre_simple_cmd_fn(u32 *cmd_list, u32 cmdlen)
 {
-	int loops = CMD_TIMEOUT_SECONDS * USEC_PER_SEC;
-	int errcode;
-	int status;
-
-	if (ipcdev->irq) {
-		if (!wait_for_completion_timeout(&ipcdev->cmd_complete,
-						 CMD_TIMEOUT_SECONDS * HZ)) {
-			dev_err(ipcdev->dev, "IPC timed out\n");
-			return -ETIMEDOUT;
-		}
-	} else {
-		while ((ipc_read_status(ipcdev, type) & CMD_RUN) && --loops)
-			udelay(1);
-		if (!loops) {
-			dev_err(ipcdev->dev, "IPC timed out\n");
-			return -ETIMEDOUT;
-		}
-	}
+	if (!cmd_list || cmdlen != PUNIT_PARAM_LEN)
+		return -EINVAL;
 
-	status = ipc_read_status(ipcdev, type);
-	errcode = status & CMD_ERRCODE_MASK;
-	if (errcode) {
-		dev_err(ipcdev->dev, "IPC failed: %s, IPC_STS=0x%x\n",
-			ipc_err_string(errcode), status);
-		return -EIO;
-	}
+	cmd_list[0] |= CMD_RUN | cmd_list[1] << CMD_PARA1_SHIFT |
+		cmd_list[2] << CMD_PARA2_SHIFT;
 
 	return 0;
 }
 
-/**
- * intel_punit_ipc_simple_command() - Simple IPC command
- * @cmd:	IPC command code.
- * @para1:	First 8bit parameter, set 0 if not used.
- * @para2:	Second 8bit parameter, set 0 if not used.
- *
- * Send a IPC command to P-Unit when there is no data transaction
- *
- * Return:	IPC error code or 0 on success.
- */
-int intel_punit_ipc_simple_command(int cmd, int para1, int para2)
+/* Input data, 32bit for BIOS cmd, two 32bit for GTD and ISPD. */
+int pre_raw_cmd_fn(struct intel_ipc_raw_cmd *ipc_raw_cmd)
 {
-	IPC_DEV *ipcdev = punit_ipcdev;
-	IPC_TYPE type;
-	u32 val;
-	int ret;
-
-	mutex_lock(&ipcdev->lock);
-
-	reinit_completion(&ipcdev->cmd_complete);
-	type = (cmd & IPC_PUNIT_CMD_TYPE_MASK) >> IPC_TYPE_OFFSET;
-
-	val = cmd & ~IPC_PUNIT_CMD_TYPE_MASK;
-	val |= CMD_RUN | para2 << CMD_PARA2_SHIFT | para1 << CMD_PARA1_SHIFT;
-	ipc_write_cmd(ipcdev, type, val);
-	ret = intel_punit_ipc_check_status(ipcdev, type);
-
-	mutex_unlock(&ipcdev->lock);
-
-	return ret;
-}
-EXPORT_SYMBOL(intel_punit_ipc_simple_command);
-
-/**
- * intel_punit_ipc_command() - IPC command with data and pointers
- * @cmd:	IPC command code.
- * @para1:	First 8bit parameter, set 0 if not used.
- * @para2:	Second 8bit parameter, set 0 if not used.
- * @in:		Input data, 32bit for BIOS cmd, two 32bit for GTD and ISPD.
- * @out:	Output data.
- *
- * Send a IPC command to P-Unit with data transaction
- *
- * Return:	IPC error code or 0 on success.
- */
-int intel_punit_ipc_command(u32 cmd, u32 para1, u32 para2, u32 *in, u32 *out)
-{
-	IPC_DEV *ipcdev = punit_ipcdev;
-	IPC_TYPE type;
-	u32 val;
-	int ret;
-
-	mutex_lock(&ipcdev->lock);
-
-	reinit_completion(&ipcdev->cmd_complete);
-	type = (cmd & IPC_PUNIT_CMD_TYPE_MASK) >> IPC_TYPE_OFFSET;
-
-	if (in) {
-		ipc_write_data_low(ipcdev, type, *in);
-		if (type == GTDRIVER_IPC || type == ISPDRIVER_IPC)
-			ipc_write_data_high(ipcdev, type, *++in);
-	}
-
-	val = cmd & ~IPC_PUNIT_CMD_TYPE_MASK;
-	val |= CMD_RUN | para2 << CMD_PARA2_SHIFT | para1 << CMD_PARA1_SHIFT;
-	ipc_write_cmd(ipcdev, type, val);
-
-	ret = intel_punit_ipc_check_status(ipcdev, type);
-	if (ret)
-		goto out;
-
-	if (out) {
-		*out = ipc_read_data_low(ipcdev, type);
-		if (type == GTDRIVER_IPC || type == ISPDRIVER_IPC)
-			*++out = ipc_read_data_high(ipcdev, type);
-	}
-
-out:
-	mutex_unlock(&ipcdev->lock);
-	return ret;
-}
-EXPORT_SYMBOL_GPL(intel_punit_ipc_command);
-
-static irqreturn_t intel_punit_ioc(int irq, void *dev_id)
-{
-	IPC_DEV *ipcdev = dev_id;
-
-	complete(&ipcdev->cmd_complete);
-	return IRQ_HANDLED;
+	return pre_simple_cmd_fn(ipc_raw_cmd->cmd_list, ipc_raw_cmd->cmdlen);
 }
 
 static int intel_punit_get_bars(struct platform_device *pdev)
@@ -282,9 +133,77 @@ static int intel_punit_get_bars(struct platform_device *pdev)
 	return 0;
 }
 
+static int punit_ipc_err_code(int status)
+{
+	return (status & CMD_ERRCODE_MASK);
+}
+
+static int punit_ipc_busy_check(int status)
+{
+	return status | CMD_RUN;
+}
+
+static struct intel_ipc_dev *intel_punit_ipc_dev_create(struct device *dev,
+		const char *devname,
+		int irq,
+		void __iomem *base,
+		void __iomem *data)
+{
+	struct intel_ipc_dev_ops *ops;
+	struct intel_ipc_dev_cfg *cfg;
+	struct regmap *cmd_regs, *data_regs;
+
+	cfg = devm_kzalloc(dev, sizeof(*cfg), GFP_KERNEL);
+	if (!cfg)
+		return ERR_PTR(-ENOMEM);
+
+	ops = devm_kzalloc(dev, sizeof(*ops), GFP_KERNEL);
+	if (!ops)
+		return ERR_PTR(-ENOMEM);
+
+	punit_regmap_config.name = devm_kasprintf(dev, GFP_KERNEL, "%s_%s",
+						  devname, "base");
+
+	cmd_regs = devm_regmap_init_mmio_clk(dev, NULL, base,
+					     &punit_regmap_config);
+	if (IS_ERR(cmd_regs)) {
+		dev_err(dev, "cmd_regs regmap init failed\n");
+		return ERR_CAST(cmd_regs);
+	}
+
+	punit_regmap_config.name = devm_kasprintf(dev, GFP_KERNEL, "%s_%s",
+						  devname, "data");
+
+	data_regs = devm_regmap_init_mmio_clk(dev, NULL, data,
+					      &punit_regmap_config);
+	if (IS_ERR(data_regs)) {
+		dev_err(dev, "data_regs regmap init failed\n");
+		return ERR_CAST(data_regs);
+	}
+
+	/* set IPC dev ops */
+	ops->to_err_code = punit_ipc_err_code;
+	ops->busy_check = punit_ipc_busy_check;
+	ops->pre_simple_cmd_fn = pre_simple_cmd_fn;
+	ops->pre_raw_cmd_fn = pre_raw_cmd_fn;
+
+	if (irq > 0)
+		cfg->mode = IPC_DEV_MODE_IRQ;
+	else
+		cfg->mode = IPC_DEV_MODE_POLLING;
+
+	cfg->chan_type = IPC_CHANNEL_IA_PUNIT;
+	cfg->irq = irq;
+	cfg->irqflags = IRQF_NO_SUSPEND | IRQF_SHARED;
+	cfg->cmd_regs = cmd_regs;
+	cfg->data_regs = data_regs;
+
+	return devm_intel_ipc_dev_create(dev, devname, cfg, ops);
+}
+
 static int intel_punit_ipc_probe(struct platform_device *pdev)
 {
-	int irq, ret;
+	int irq, ret, i;
 
 	punit_ipcdev = devm_kzalloc(&pdev->dev,
 				    sizeof(*punit_ipcdev), GFP_KERNEL);
@@ -294,35 +213,30 @@ static int intel_punit_ipc_probe(struct platform_device *pdev)
 	platform_set_drvdata(pdev, punit_ipcdev);
 
 	irq = platform_get_irq(pdev, 0);
-	if (irq < 0) {
-		punit_ipcdev->irq = 0;
-		dev_warn(&pdev->dev, "Invalid IRQ, using polling mode\n");
-	} else {
-		ret = devm_request_irq(&pdev->dev, irq, intel_punit_ioc,
-				       IRQF_NO_SUSPEND, "intel_punit_ipc",
-				       &punit_ipcdev);
-		if (ret) {
-			dev_err(&pdev->dev, "Failed to request irq: %d\n", irq);
-			return ret;
-		}
-		punit_ipcdev->irq = irq;
-	}
 
 	ret = intel_punit_get_bars(pdev);
 	if (ret)
-		goto out;
+		return ret;
+
+	for (i = 0; i < RESERVED_IPC; i++) {
+		punit_ipcdev->ipc_dev[i] = intel_punit_ipc_dev_create(
+				&pdev->dev,
+				ipc_dev_name[i],
+				irq,
+				punit_ipcdev->base[i][BASE_IFACE],
+				punit_ipcdev->base[i][BASE_DATA]);
+
+		if (IS_ERR(punit_ipcdev->ipc_dev[i])) {
+			dev_err(&pdev->dev, "%s create failed\n",
+				ipc_dev_name[i]);
+			return PTR_ERR(punit_ipcdev->ipc_dev[i]);
+		}
+	}
 
 	punit_ipcdev->dev = &pdev->dev;
-	mutex_init(&punit_ipcdev->lock);
-	init_completion(&punit_ipcdev->cmd_complete);
 
-out:
 	return ret;
-}
 
-static int intel_punit_ipc_remove(struct platform_device *pdev)
-{
-	return 0;
 }
 
 static const struct acpi_device_id punit_ipc_acpi_ids[] = {
@@ -332,7 +246,6 @@ static const struct acpi_device_id punit_ipc_acpi_ids[] = {
 
 static struct platform_driver intel_punit_ipc_driver = {
 	.probe = intel_punit_ipc_probe,
-	.remove = intel_punit_ipc_remove,
 	.driver = {
 		.name = "intel_punit_ipc",
 		.acpi_match_table = ACPI_PTR(punit_ipc_acpi_ids),
diff --git a/drivers/platform/x86/intel_telemetry_pltdrv.c b/drivers/platform/x86/intel_telemetry_pltdrv.c
index e0424d5..0dbd7be 100644
--- a/drivers/platform/x86/intel_telemetry_pltdrv.c
+++ b/drivers/platform/x86/intel_telemetry_pltdrv.c
@@ -98,6 +98,7 @@ struct telem_ssram_region {
 };
 
 static struct telemetry_plt_config *telm_conf;
+static struct intel_ipc_dev *punit_ipc_dev;
 
 /*
  * The following counters are programmed by default during setup.
@@ -127,7 +128,6 @@ static struct telemetry_evtmap
 	{"PMC_S0IX_BLOCK_IPS_CLOCKS",           0x600B},
 };
 
-
 static struct telemetry_evtmap
 	telemetry_apl_pss_default_events[TELEM_MAX_OS_ALLOCATED_EVENTS] = {
 	{"IA_CORE0_C6_RES",			0x0400},
@@ -204,6 +204,28 @@ static const struct x86_cpu_id telemetry_cpu_ids[] = {
 
 MODULE_DEVICE_TABLE(x86cpu, telemetry_cpu_ids);
 
+static int telem_punit_cmd(struct intel_ipc_dev *ipc_dev, u32 cmd, u32 sub,
+		u32 *in, u32 *out)
+{
+	struct intel_ipc_cmd ipc_cmd = {0};
+	u32 cmd_list[PUNIT_PARAM_LEN] = {0};
+
+	cmd_list[0] = cmd;
+	cmd_list[1] = sub;
+
+	ipc_cmd.cmd_list = cmd_list;
+	ipc_cmd.cmdlen = PUNIT_PARAM_LEN;
+	ipc_cmd.in = in;
+	ipc_cmd.out = out;
+
+	if (in)
+		ipc_cmd.inlen = 1;
+	if (out)
+		ipc_cmd.outlen = 1;
+
+	return ipc_dev_cmd(ipc_dev, &ipc_cmd);
+}
+
 static inline int telem_get_unitconfig(enum telemetry_unit telem_unit,
 				     struct telemetry_unit_config **unit_config)
 {
@@ -283,13 +305,11 @@ static inline int telemetry_plt_config_ioss_event(u32 evt_id, int index)
 static inline int telemetry_plt_config_pss_event(u32 evt_id, int index)
 {
 	u32 write_buf;
-	int ret;
 
 	write_buf = evt_id | TELEM_EVENT_ENABLE;
-	ret = intel_punit_ipc_command(IPC_PUNIT_BIOS_WRITE_TELE_EVENT,
-				      index, 0, &write_buf, NULL);
 
-	return ret;
+	return telem_punit_cmd(punit_ipc_dev, IPC_PUNIT_BIOS_WRITE_TELE_EVENT,
+			       index, &write_buf, NULL);
 }
 
 static int telemetry_setup_iossevtconfig(struct telemetry_evtconfig evtconfig,
@@ -442,8 +462,9 @@ static int telemetry_setup_pssevtconfig(struct telemetry_evtconfig evtconfig,
 
 	/* PSS Config */
 	/* Get telemetry EVENT CTL */
-	ret = intel_punit_ipc_command(IPC_PUNIT_BIOS_READ_TELE_EVENT_CTRL,
-				      0, 0, NULL, &telem_ctrl);
+	ret = telem_punit_cmd(punit_ipc_dev,
+			      IPC_PUNIT_BIOS_READ_TELE_EVENT_CTRL,
+			      0, NULL, &telem_ctrl);
 	if (ret) {
 		pr_err("PSS TELEM_CTRL Read Failed\n");
 		return ret;
@@ -451,8 +472,9 @@ static int telemetry_setup_pssevtconfig(struct telemetry_evtconfig evtconfig,
 
 	/* Disable Telemetry */
 	TELEM_DISABLE(telem_ctrl);
-	ret = intel_punit_ipc_command(IPC_PUNIT_BIOS_WRITE_TELE_EVENT_CTRL,
-				      0, 0, &telem_ctrl, NULL);
+	ret = telem_punit_cmd(punit_ipc_dev,
+			      IPC_PUNIT_BIOS_WRITE_TELE_EVENT_CTRL,
+			      0, &telem_ctrl, NULL);
 	if (ret) {
 		pr_err("PSS TELEM_CTRL Event Disable Write Failed\n");
 		return ret;
@@ -463,9 +485,9 @@ static int telemetry_setup_pssevtconfig(struct telemetry_evtconfig evtconfig,
 		/* Clear All Events */
 		TELEM_CLEAR_EVENTS(telem_ctrl);
 
-		ret = intel_punit_ipc_command(
-				IPC_PUNIT_BIOS_WRITE_TELE_EVENT_CTRL,
-				0, 0, &telem_ctrl, NULL);
+		ret = telem_punit_cmd(punit_ipc_dev,
+				      IPC_PUNIT_BIOS_WRITE_TELE_EVENT_CTRL,
+				      0, &telem_ctrl, NULL);
 		if (ret) {
 			pr_err("PSS TELEM_CTRL Event Disable Write Failed\n");
 			return ret;
@@ -489,9 +511,9 @@ static int telemetry_setup_pssevtconfig(struct telemetry_evtconfig evtconfig,
 		/* Clear All Events */
 		TELEM_CLEAR_EVENTS(telem_ctrl);
 
-		ret = intel_punit_ipc_command(
-				IPC_PUNIT_BIOS_WRITE_TELE_EVENT_CTRL,
-				0, 0, &telem_ctrl, NULL);
+		ret = telem_punit_cmd(punit_ipc_dev,
+				      IPC_PUNIT_BIOS_WRITE_TELE_EVENT_CTRL,
+				      0, &telem_ctrl, NULL);
 		if (ret) {
 			pr_err("PSS TELEM_CTRL Event Disable Write Failed\n");
 			return ret;
@@ -540,8 +562,9 @@ static int telemetry_setup_pssevtconfig(struct telemetry_evtconfig evtconfig,
 	TELEM_ENABLE_PERIODIC(telem_ctrl);
 	telem_ctrl |= pss_period;
 
-	ret = intel_punit_ipc_command(IPC_PUNIT_BIOS_WRITE_TELE_EVENT_CTRL,
-				      0, 0, &telem_ctrl, NULL);
+	ret = telem_punit_cmd(punit_ipc_dev,
+			      IPC_PUNIT_BIOS_WRITE_TELE_EVENT_CTRL,
+			      0, &telem_ctrl, NULL);
 	if (ret) {
 		pr_err("PSS TELEM_CTRL Event Enable Write Failed\n");
 		return ret;
@@ -626,8 +649,8 @@ static int telemetry_setup(struct platform_device *pdev)
 	telm_conf->ioss_config.max_period = TELEM_MAX_PERIOD(read_buf);
 
 	/* PUNIT Mailbox Setup */
-	ret = intel_punit_ipc_command(IPC_PUNIT_BIOS_READ_TELE_INFO, 0, 0,
-				      NULL, &read_buf);
+	ret = telem_punit_cmd(punit_ipc_dev, IPC_PUNIT_BIOS_READ_TELE_INFO, 0,
+			      NULL, &read_buf);
 	if (ret) {
 		dev_err(&pdev->dev, "PSS TELEM_INFO Read Failed\n");
 		return ret;
@@ -752,9 +775,9 @@ static int telemetry_plt_set_sampling_period(u8 pss_period, u8 ioss_period)
 		}
 
 		/* Get telemetry EVENT CTL */
-		ret = intel_punit_ipc_command(
-				IPC_PUNIT_BIOS_READ_TELE_EVENT_CTRL,
-				0, 0, NULL, &telem_ctrl);
+		ret = telem_punit_cmd(punit_ipc_dev,
+				      IPC_PUNIT_BIOS_READ_TELE_EVENT_CTRL,
+				      0, NULL, &telem_ctrl);
 		if (ret) {
 			pr_err("PSS TELEM_CTRL Read Failed\n");
 			goto out;
@@ -762,9 +785,9 @@ static int telemetry_plt_set_sampling_period(u8 pss_period, u8 ioss_period)
 
 		/* Disable Telemetry */
 		TELEM_DISABLE(telem_ctrl);
-		ret = intel_punit_ipc_command(
-				IPC_PUNIT_BIOS_WRITE_TELE_EVENT_CTRL,
-				0, 0, &telem_ctrl, NULL);
+		ret = telem_punit_cmd(punit_ipc_dev,
+				      IPC_PUNIT_BIOS_WRITE_TELE_EVENT_CTRL,
+				      0, &telem_ctrl, NULL);
 		if (ret) {
 			pr_err("PSS TELEM_CTRL Event Disable Write Failed\n");
 			goto out;
@@ -776,9 +799,9 @@ static int telemetry_plt_set_sampling_period(u8 pss_period, u8 ioss_period)
 		TELEM_ENABLE_PERIODIC(telem_ctrl);
 		telem_ctrl |= pss_period;
 
-		ret = intel_punit_ipc_command(
-				IPC_PUNIT_BIOS_WRITE_TELE_EVENT_CTRL,
-				0, 0, &telem_ctrl, NULL);
+		ret = telem_punit_cmd(punit_ipc_dev,
+				      IPC_PUNIT_BIOS_WRITE_TELE_EVENT_CTRL,
+				      0, &telem_ctrl, NULL);
 		if (ret) {
 			pr_err("PSS TELEM_CTRL Event Enable Write Failed\n");
 			goto out;
@@ -1020,9 +1043,9 @@ static int telemetry_plt_get_trace_verbosity(enum telemetry_unit telem_unit,
 	mutex_lock(&(telm_conf->telem_trace_lock));
 	switch (telem_unit) {
 	case TELEM_PSS:
-		ret = intel_punit_ipc_command(
-				IPC_PUNIT_BIOS_READ_TELE_TRACE_CTRL,
-				0, 0, NULL, &temp);
+		ret = telem_punit_cmd(punit_ipc_dev,
+				      IPC_PUNIT_BIOS_READ_TELE_TRACE_CTRL,
+				      0, NULL, &temp);
 		if (ret) {
 			pr_err("PSS TRACE_CTRL Read Failed\n");
 			goto out;
@@ -1064,9 +1087,9 @@ static int telemetry_plt_set_trace_verbosity(enum telemetry_unit telem_unit,
 	mutex_lock(&(telm_conf->telem_trace_lock));
 	switch (telem_unit) {
 	case TELEM_PSS:
-		ret = intel_punit_ipc_command(
-				IPC_PUNIT_BIOS_READ_TELE_TRACE_CTRL,
-				0, 0, NULL, &temp);
+		ret = telem_punit_cmd(punit_ipc_dev,
+				      IPC_PUNIT_BIOS_READ_TELE_TRACE_CTRL, 0,
+				      NULL, &temp);
 		if (ret) {
 			pr_err("PSS TRACE_CTRL Read Failed\n");
 			goto out;
@@ -1074,10 +1097,9 @@ static int telemetry_plt_set_trace_verbosity(enum telemetry_unit telem_unit,
 
 		TELEM_CLEAR_VERBOSITY_BITS(temp);
 		TELEM_SET_VERBOSITY_BITS(temp, verbosity);
-
-		ret = intel_punit_ipc_command(
-				IPC_PUNIT_BIOS_WRITE_TELE_TRACE_CTRL,
-				0, 0, &temp, NULL);
+		ret = telem_punit_cmd(punit_ipc_dev,
+				      IPC_PUNIT_BIOS_WRITE_TELE_EVENT_CTRL, 0,
+				      &temp, NULL);
 		if (ret) {
 			pr_err("PSS TRACE_CTRL Verbosity Set Failed\n");
 			goto out;
@@ -1139,6 +1161,10 @@ static int telemetry_pltdrv_probe(struct platform_device *pdev)
 	if (!id)
 		return -ENODEV;
 
+	punit_ipc_dev = intel_ipc_dev_get(PUNIT_BIOS_IPC_DEV);
+	if (IS_ERR_OR_NULL(punit_ipc_dev))
+		return PTR_ERR(punit_ipc_dev);
+
 	telm_conf = (struct telemetry_plt_config *)id->driver_data;
 
 	res0 = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -1218,6 +1244,7 @@ static int telemetry_pltdrv_probe(struct platform_device *pdev)
 static int telemetry_pltdrv_remove(struct platform_device *pdev)
 {
 	telemetry_clear_pltdata();
+	intel_ipc_dev_put(punit_ipc_dev);
 	iounmap(telm_conf->pss_config.regmap);
 	iounmap(telm_conf->ioss_config.regmap);
 
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [RFC v8 5/7] platform/x86: intel_punit_ipc: Use generic intel ipc device calls
@ 2017-10-29  9:49   ` sathyanarayanan.kuppuswamy
  0 siblings, 0 replies; 30+ messages in thread
From: sathyanarayanan.kuppuswamy @ 2017-10-29  9:49 UTC (permalink / raw)
  To: a.zummo, x86, wim, mingo, alexandre.belloni, qipeng.zha, hpa,
	dvhart, tglx, lee.jones, andy, souvik.k.chakravarty
  Cc: linux-rtc, linux-watchdog, linux-kernel, platform-driver-x86,
	sathyaosid, Kuppuswamy Sathyanarayanan

From: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>

Removed redundant IPC helper functions and refactored the driver to use
APIs provided by generic IPC driver. This patch also cleans-up PUNIT IPC
user drivers(intel_telemetry_pltdrv.c) to use APIs provided by generic IPC
driver.

Signed-off-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>
---
 arch/x86/include/asm/intel_punit_ipc.h        | 125 +++++------
 drivers/platform/x86/Kconfig                  |   1 +
 drivers/platform/x86/intel_punit_ipc.c        | 299 +++++++++-----------------
 drivers/platform/x86/intel_telemetry_pltdrv.c | 103 +++++----
 4 files changed, 222 insertions(+), 306 deletions(-)

Changes since v7:
 * Fixed style issues.

Changes since v6:
 * None

Changes since v5:
 * Adapted to change in arguments of ipc_dev_cmd() and ipc_dev_raw_cmd() APIs.

Changes since v4:
 * None

Changes since v2:
 * Added unique name to PUNIT BIOS, GTD, & ISP regmaps.
 * Added intel_ipc_dev_put() support.

Changes since v1:
 * Removed custom APIs.
 * Cleaned up PUNIT IPC user drivers to use APIs provided by generic
   IPC driver.

diff --git a/arch/x86/include/asm/intel_punit_ipc.h b/arch/x86/include/asm/intel_punit_ipc.h
index 201eb9d..8d1ab9e 100644
--- a/arch/x86/include/asm/intel_punit_ipc.h
+++ b/arch/x86/include/asm/intel_punit_ipc.h
@@ -1,10 +1,8 @@
 #ifndef _ASM_X86_INTEL_PUNIT_IPC_H_
 #define  _ASM_X86_INTEL_PUNIT_IPC_H_
 
-/*
- * Three types of 8bit P-Unit IPC commands are supported,
- * bit[7:6]: [00]: BIOS; [01]: GTD; [10]: ISPD.
- */
+#include <linux/platform_data/x86/intel_ipc_dev.h>
+
 typedef enum {
 	BIOS_IPC = 0,
 	GTDRIVER_IPC,
@@ -12,61 +10,60 @@ typedef enum {
 	RESERVED_IPC,
 } IPC_TYPE;
 
-#define IPC_TYPE_OFFSET			6
-#define IPC_PUNIT_BIOS_CMD_BASE		(BIOS_IPC << IPC_TYPE_OFFSET)
-#define IPC_PUNIT_GTD_CMD_BASE		(GTDDRIVER_IPC << IPC_TYPE_OFFSET)
-#define IPC_PUNIT_ISPD_CMD_BASE		(ISPDRIVER_IPC << IPC_TYPE_OFFSET)
-#define IPC_PUNIT_CMD_TYPE_MASK		(RESERVED_IPC << IPC_TYPE_OFFSET)
+#define PUNIT_BIOS_IPC_DEV			"punit_bios_ipc"
+#define PUNIT_GTD_IPC_DEV			"punit_gtd_ipc"
+#define PUNIT_ISP_IPC_DEV			"punit_isp_ipc"
+#define PUNIT_PARAM_LEN				3
 
 /* BIOS => Pcode commands */
-#define IPC_PUNIT_BIOS_ZERO			(IPC_PUNIT_BIOS_CMD_BASE | 0x00)
-#define IPC_PUNIT_BIOS_VR_INTERFACE		(IPC_PUNIT_BIOS_CMD_BASE | 0x01)
-#define IPC_PUNIT_BIOS_READ_PCS			(IPC_PUNIT_BIOS_CMD_BASE | 0x02)
-#define IPC_PUNIT_BIOS_WRITE_PCS		(IPC_PUNIT_BIOS_CMD_BASE | 0x03)
-#define IPC_PUNIT_BIOS_READ_PCU_CONFIG		(IPC_PUNIT_BIOS_CMD_BASE | 0x04)
-#define IPC_PUNIT_BIOS_WRITE_PCU_CONFIG		(IPC_PUNIT_BIOS_CMD_BASE | 0x05)
-#define IPC_PUNIT_BIOS_READ_PL1_SETTING		(IPC_PUNIT_BIOS_CMD_BASE | 0x06)
-#define IPC_PUNIT_BIOS_WRITE_PL1_SETTING	(IPC_PUNIT_BIOS_CMD_BASE | 0x07)
-#define IPC_PUNIT_BIOS_TRIGGER_VDD_RAM		(IPC_PUNIT_BIOS_CMD_BASE | 0x08)
-#define IPC_PUNIT_BIOS_READ_TELE_INFO		(IPC_PUNIT_BIOS_CMD_BASE | 0x09)
-#define IPC_PUNIT_BIOS_READ_TELE_TRACE_CTRL	(IPC_PUNIT_BIOS_CMD_BASE | 0x0a)
-#define IPC_PUNIT_BIOS_WRITE_TELE_TRACE_CTRL	(IPC_PUNIT_BIOS_CMD_BASE | 0x0b)
-#define IPC_PUNIT_BIOS_READ_TELE_EVENT_CTRL	(IPC_PUNIT_BIOS_CMD_BASE | 0x0c)
-#define IPC_PUNIT_BIOS_WRITE_TELE_EVENT_CTRL	(IPC_PUNIT_BIOS_CMD_BASE | 0x0d)
-#define IPC_PUNIT_BIOS_READ_TELE_TRACE		(IPC_PUNIT_BIOS_CMD_BASE | 0x0e)
-#define IPC_PUNIT_BIOS_WRITE_TELE_TRACE		(IPC_PUNIT_BIOS_CMD_BASE | 0x0f)
-#define IPC_PUNIT_BIOS_READ_TELE_EVENT		(IPC_PUNIT_BIOS_CMD_BASE | 0x10)
-#define IPC_PUNIT_BIOS_WRITE_TELE_EVENT		(IPC_PUNIT_BIOS_CMD_BASE | 0x11)
-#define IPC_PUNIT_BIOS_READ_MODULE_TEMP		(IPC_PUNIT_BIOS_CMD_BASE | 0x12)
-#define IPC_PUNIT_BIOS_RESERVED			(IPC_PUNIT_BIOS_CMD_BASE | 0x13)
-#define IPC_PUNIT_BIOS_READ_VOLTAGE_OVER	(IPC_PUNIT_BIOS_CMD_BASE | 0x14)
-#define IPC_PUNIT_BIOS_WRITE_VOLTAGE_OVER	(IPC_PUNIT_BIOS_CMD_BASE | 0x15)
-#define IPC_PUNIT_BIOS_READ_RATIO_OVER		(IPC_PUNIT_BIOS_CMD_BASE | 0x16)
-#define IPC_PUNIT_BIOS_WRITE_RATIO_OVER		(IPC_PUNIT_BIOS_CMD_BASE | 0x17)
-#define IPC_PUNIT_BIOS_READ_VF_GL_CTRL		(IPC_PUNIT_BIOS_CMD_BASE | 0x18)
-#define IPC_PUNIT_BIOS_WRITE_VF_GL_CTRL		(IPC_PUNIT_BIOS_CMD_BASE | 0x19)
-#define IPC_PUNIT_BIOS_READ_FM_SOC_TEMP_THRESH	(IPC_PUNIT_BIOS_CMD_BASE | 0x1a)
-#define IPC_PUNIT_BIOS_WRITE_FM_SOC_TEMP_THRESH	(IPC_PUNIT_BIOS_CMD_BASE | 0x1b)
+#define IPC_PUNIT_BIOS_ZERO			(0x00)
+#define IPC_PUNIT_BIOS_VR_INTERFACE		(0x01)
+#define IPC_PUNIT_BIOS_READ_PCS			(0x02)
+#define IPC_PUNIT_BIOS_WRITE_PCS		(0x03)
+#define IPC_PUNIT_BIOS_READ_PCU_CONFIG		(0x04)
+#define IPC_PUNIT_BIOS_WRITE_PCU_CONFIG		(0x05)
+#define IPC_PUNIT_BIOS_READ_PL1_SETTING		(0x06)
+#define IPC_PUNIT_BIOS_WRITE_PL1_SETTING	(0x07)
+#define IPC_PUNIT_BIOS_TRIGGER_VDD_RAM		(0x08)
+#define IPC_PUNIT_BIOS_READ_TELE_INFO		(0x09)
+#define IPC_PUNIT_BIOS_READ_TELE_TRACE_CTRL	(0x0a)
+#define IPC_PUNIT_BIOS_WRITE_TELE_TRACE_CTRL	(0x0b)
+#define IPC_PUNIT_BIOS_READ_TELE_EVENT_CTRL	(0x0c)
+#define IPC_PUNIT_BIOS_WRITE_TELE_EVENT_CTRL	(0x0d)
+#define IPC_PUNIT_BIOS_READ_TELE_TRACE		(0x0e)
+#define IPC_PUNIT_BIOS_WRITE_TELE_TRACE		(0x0f)
+#define IPC_PUNIT_BIOS_READ_TELE_EVENT		(0x10)
+#define IPC_PUNIT_BIOS_WRITE_TELE_EVENT		(0x11)
+#define IPC_PUNIT_BIOS_READ_MODULE_TEMP		(0x12)
+#define IPC_PUNIT_BIOS_RESERVED			(0x13)
+#define IPC_PUNIT_BIOS_READ_VOLTAGE_OVER	(0x14)
+#define IPC_PUNIT_BIOS_WRITE_VOLTAGE_OVER	(0x15)
+#define IPC_PUNIT_BIOS_READ_RATIO_OVER		(0x16)
+#define IPC_PUNIT_BIOS_WRITE_RATIO_OVER		(0x17)
+#define IPC_PUNIT_BIOS_READ_VF_GL_CTRL		(0x18)
+#define IPC_PUNIT_BIOS_WRITE_VF_GL_CTRL		(0x19)
+#define IPC_PUNIT_BIOS_READ_FM_SOC_TEMP_THRESH	(0x1a)
+#define IPC_PUNIT_BIOS_WRITE_FM_SOC_TEMP_THRESH	(0x1b)
 
 /* GT Driver => Pcode commands */
-#define IPC_PUNIT_GTD_ZERO			(IPC_PUNIT_GTD_CMD_BASE | 0x00)
-#define IPC_PUNIT_GTD_CONFIG			(IPC_PUNIT_GTD_CMD_BASE | 0x01)
-#define IPC_PUNIT_GTD_READ_ICCP_LIC_CDYN_SCAL	(IPC_PUNIT_GTD_CMD_BASE | 0x02)
-#define IPC_PUNIT_GTD_WRITE_ICCP_LIC_CDYN_SCAL	(IPC_PUNIT_GTD_CMD_BASE | 0x03)
-#define IPC_PUNIT_GTD_GET_WM_VAL		(IPC_PUNIT_GTD_CMD_BASE | 0x06)
-#define IPC_PUNIT_GTD_WRITE_CONFIG_WISHREQ	(IPC_PUNIT_GTD_CMD_BASE | 0x07)
-#define IPC_PUNIT_GTD_READ_REQ_DUTY_CYCLE	(IPC_PUNIT_GTD_CMD_BASE | 0x16)
-#define IPC_PUNIT_GTD_DIS_VOL_FREQ_CHG_REQUEST	(IPC_PUNIT_GTD_CMD_BASE | 0x17)
-#define IPC_PUNIT_GTD_DYNA_DUTY_CYCLE_CTRL	(IPC_PUNIT_GTD_CMD_BASE | 0x1a)
-#define IPC_PUNIT_GTD_DYNA_DUTY_CYCLE_TUNING	(IPC_PUNIT_GTD_CMD_BASE | 0x1c)
+#define IPC_PUNIT_GTD_ZERO			(0x00)
+#define IPC_PUNIT_GTD_CONFIG			(0x01)
+#define IPC_PUNIT_GTD_READ_ICCP_LIC_CDYN_SCAL	(0x02)
+#define IPC_PUNIT_GTD_WRITE_ICCP_LIC_CDYN_SCAL	(0x03)
+#define IPC_PUNIT_GTD_GET_WM_VAL		(0x06)
+#define IPC_PUNIT_GTD_WRITE_CONFIG_WISHREQ	(0x07)
+#define IPC_PUNIT_GTD_READ_REQ_DUTY_CYCLE	(0x16)
+#define IPC_PUNIT_GTD_DIS_VOL_FREQ_CHG_REQUEST	(0x17)
+#define IPC_PUNIT_GTD_DYNA_DUTY_CYCLE_CTRL	(0x1a)
+#define IPC_PUNIT_GTD_DYNA_DUTY_CYCLE_TUNING	(0x1c)
 
 /* ISP Driver => Pcode commands */
-#define IPC_PUNIT_ISPD_ZERO			(IPC_PUNIT_ISPD_CMD_BASE | 0x00)
-#define IPC_PUNIT_ISPD_CONFIG			(IPC_PUNIT_ISPD_CMD_BASE | 0x01)
-#define IPC_PUNIT_ISPD_GET_ISP_LTR_VAL		(IPC_PUNIT_ISPD_CMD_BASE | 0x02)
-#define IPC_PUNIT_ISPD_ACCESS_IU_FREQ_BOUNDS	(IPC_PUNIT_ISPD_CMD_BASE | 0x03)
-#define IPC_PUNIT_ISPD_READ_CDYN_LEVEL		(IPC_PUNIT_ISPD_CMD_BASE | 0x04)
-#define IPC_PUNIT_ISPD_WRITE_CDYN_LEVEL		(IPC_PUNIT_ISPD_CMD_BASE | 0x05)
+#define IPC_PUNIT_ISPD_ZERO			(0x00)
+#define IPC_PUNIT_ISPD_CONFIG			(0x01)
+#define IPC_PUNIT_ISPD_GET_ISP_LTR_VAL		(0x02)
+#define IPC_PUNIT_ISPD_ACCESS_IU_FREQ_BOUNDS	(0x03)
+#define IPC_PUNIT_ISPD_READ_CDYN_LEVEL		(0x04)
+#define IPC_PUNIT_ISPD_WRITE_CDYN_LEVEL		(0x05)
 
 /* Error codes */
 #define IPC_PUNIT_ERR_SUCCESS			0
@@ -76,26 +73,4 @@ typedef enum {
 #define IPC_PUNIT_ERR_CMD_LOCKED		4
 #define IPC_PUNIT_ERR_INVALID_VR_ID		5
 #define IPC_PUNIT_ERR_VR_ERR			6
-
-#if IS_ENABLED(CONFIG_INTEL_PUNIT_IPC)
-
-int intel_punit_ipc_simple_command(int cmd, int para1, int para2);
-int intel_punit_ipc_command(u32 cmd, u32 para1, u32 para2, u32 *in, u32 *out);
-
-#else
-
-static inline int intel_punit_ipc_simple_command(int cmd,
-						  int para1, int para2)
-{
-	return -ENODEV;
-}
-
-static inline int intel_punit_ipc_command(u32 cmd, u32 para1, u32 para2,
-					  u32 *in, u32 *out)
-{
-	return -ENODEV;
-}
-
-#endif /* CONFIG_INTEL_PUNIT_IPC */
-
 #endif
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
index 9df7cda..82479ca 100644
--- a/drivers/platform/x86/Kconfig
+++ b/drivers/platform/x86/Kconfig
@@ -1083,6 +1083,7 @@ config SURFACE_3_BUTTON
 
 config INTEL_PUNIT_IPC
 	tristate "Intel P-Unit IPC Driver"
+	select REGMAP_MMIO
 	---help---
 	  This driver provides support for Intel P-Unit Mailbox IPC mechanism,
 	  which is used to bridge the communications between kernel and P-Unit.
diff --git a/drivers/platform/x86/intel_punit_ipc.c b/drivers/platform/x86/intel_punit_ipc.c
index b5b8901..50fd502 100644
--- a/drivers/platform/x86/intel_punit_ipc.c
+++ b/drivers/platform/x86/intel_punit_ipc.c
@@ -18,19 +18,16 @@
 #include <linux/device.h>
 #include <linux/interrupt.h>
 #include <linux/platform_device.h>
+#include <linux/platform_data/x86/intel_ipc_dev.h>
+#include <linux/regmap.h>
 #include <asm/intel_punit_ipc.h>
 
-/* IPC Mailbox registers */
-#define OFFSET_DATA_LOW		0x0
-#define OFFSET_DATA_HIGH	0x4
 /* bit field of interface register */
 #define	CMD_RUN			BIT(31)
 #define	CMD_ERRCODE_MASK	GENMASK(7, 0)
 #define	CMD_PARA1_SHIFT		8
 #define	CMD_PARA2_SHIFT		16
 
-#define CMD_TIMEOUT_SECONDS	1
-
 enum {
 	BASE_DATA = 0,
 	BASE_IFACE,
@@ -39,187 +36,41 @@ enum {
 
 typedef struct {
 	struct device *dev;
-	struct mutex lock;
-	int irq;
-	struct completion cmd_complete;
 	/* base of interface and data registers */
 	void __iomem *base[RESERVED_IPC][BASE_MAX];
+	struct intel_ipc_dev *ipc_dev[RESERVED_IPC];
 	IPC_TYPE type;
 } IPC_DEV;
 
 static IPC_DEV *punit_ipcdev;
 
-static inline u32 ipc_read_status(IPC_DEV *ipcdev, IPC_TYPE type)
-{
-	return readl(ipcdev->base[type][BASE_IFACE]);
-}
-
-static inline void ipc_write_cmd(IPC_DEV *ipcdev, IPC_TYPE type, u32 cmd)
-{
-	writel(cmd, ipcdev->base[type][BASE_IFACE]);
-}
-
-static inline u32 ipc_read_data_low(IPC_DEV *ipcdev, IPC_TYPE type)
-{
-	return readl(ipcdev->base[type][BASE_DATA] + OFFSET_DATA_LOW);
-}
-
-static inline u32 ipc_read_data_high(IPC_DEV *ipcdev, IPC_TYPE type)
-{
-	return readl(ipcdev->base[type][BASE_DATA] + OFFSET_DATA_HIGH);
-}
-
-static inline void ipc_write_data_low(IPC_DEV *ipcdev, IPC_TYPE type, u32 data)
-{
-	writel(data, ipcdev->base[type][BASE_DATA] + OFFSET_DATA_LOW);
-}
-
-static inline void ipc_write_data_high(IPC_DEV *ipcdev, IPC_TYPE type, u32 data)
-{
-	writel(data, ipcdev->base[type][BASE_DATA] + OFFSET_DATA_HIGH);
-}
+const char *ipc_dev_name[RESERVED_IPC] = {
+	PUNIT_BIOS_IPC_DEV,
+	PUNIT_GTD_IPC_DEV,
+	PUNIT_ISP_IPC_DEV
+};
 
-static const char *ipc_err_string(int error)
-{
-	if (error == IPC_PUNIT_ERR_SUCCESS)
-		return "no error";
-	else if (error == IPC_PUNIT_ERR_INVALID_CMD)
-		return "invalid command";
-	else if (error == IPC_PUNIT_ERR_INVALID_PARAMETER)
-		return "invalid parameter";
-	else if (error == IPC_PUNIT_ERR_CMD_TIMEOUT)
-		return "command timeout";
-	else if (error == IPC_PUNIT_ERR_CMD_LOCKED)
-		return "command locked";
-	else if (error == IPC_PUNIT_ERR_INVALID_VR_ID)
-		return "invalid vr id";
-	else if (error == IPC_PUNIT_ERR_VR_ERR)
-		return "vr error";
-	else
-		return "unknown error";
-}
+static struct regmap_config punit_regmap_config = {
+	.reg_bits = 32,
+	.reg_stride = 4,
+	.val_bits = 32,
+};
 
-static int intel_punit_ipc_check_status(IPC_DEV *ipcdev, IPC_TYPE type)
+int pre_simple_cmd_fn(u32 *cmd_list, u32 cmdlen)
 {
-	int loops = CMD_TIMEOUT_SECONDS * USEC_PER_SEC;
-	int errcode;
-	int status;
-
-	if (ipcdev->irq) {
-		if (!wait_for_completion_timeout(&ipcdev->cmd_complete,
-						 CMD_TIMEOUT_SECONDS * HZ)) {
-			dev_err(ipcdev->dev, "IPC timed out\n");
-			return -ETIMEDOUT;
-		}
-	} else {
-		while ((ipc_read_status(ipcdev, type) & CMD_RUN) && --loops)
-			udelay(1);
-		if (!loops) {
-			dev_err(ipcdev->dev, "IPC timed out\n");
-			return -ETIMEDOUT;
-		}
-	}
+	if (!cmd_list || cmdlen != PUNIT_PARAM_LEN)
+		return -EINVAL;
 
-	status = ipc_read_status(ipcdev, type);
-	errcode = status & CMD_ERRCODE_MASK;
-	if (errcode) {
-		dev_err(ipcdev->dev, "IPC failed: %s, IPC_STS=0x%x\n",
-			ipc_err_string(errcode), status);
-		return -EIO;
-	}
+	cmd_list[0] |= CMD_RUN | cmd_list[1] << CMD_PARA1_SHIFT |
+		cmd_list[2] << CMD_PARA2_SHIFT;
 
 	return 0;
 }
 
-/**
- * intel_punit_ipc_simple_command() - Simple IPC command
- * @cmd:	IPC command code.
- * @para1:	First 8bit parameter, set 0 if not used.
- * @para2:	Second 8bit parameter, set 0 if not used.
- *
- * Send a IPC command to P-Unit when there is no data transaction
- *
- * Return:	IPC error code or 0 on success.
- */
-int intel_punit_ipc_simple_command(int cmd, int para1, int para2)
+/* Input data, 32bit for BIOS cmd, two 32bit for GTD and ISPD. */
+int pre_raw_cmd_fn(struct intel_ipc_raw_cmd *ipc_raw_cmd)
 {
-	IPC_DEV *ipcdev = punit_ipcdev;
-	IPC_TYPE type;
-	u32 val;
-	int ret;
-
-	mutex_lock(&ipcdev->lock);
-
-	reinit_completion(&ipcdev->cmd_complete);
-	type = (cmd & IPC_PUNIT_CMD_TYPE_MASK) >> IPC_TYPE_OFFSET;
-
-	val = cmd & ~IPC_PUNIT_CMD_TYPE_MASK;
-	val |= CMD_RUN | para2 << CMD_PARA2_SHIFT | para1 << CMD_PARA1_SHIFT;
-	ipc_write_cmd(ipcdev, type, val);
-	ret = intel_punit_ipc_check_status(ipcdev, type);
-
-	mutex_unlock(&ipcdev->lock);
-
-	return ret;
-}
-EXPORT_SYMBOL(intel_punit_ipc_simple_command);
-
-/**
- * intel_punit_ipc_command() - IPC command with data and pointers
- * @cmd:	IPC command code.
- * @para1:	First 8bit parameter, set 0 if not used.
- * @para2:	Second 8bit parameter, set 0 if not used.
- * @in:		Input data, 32bit for BIOS cmd, two 32bit for GTD and ISPD.
- * @out:	Output data.
- *
- * Send a IPC command to P-Unit with data transaction
- *
- * Return:	IPC error code or 0 on success.
- */
-int intel_punit_ipc_command(u32 cmd, u32 para1, u32 para2, u32 *in, u32 *out)
-{
-	IPC_DEV *ipcdev = punit_ipcdev;
-	IPC_TYPE type;
-	u32 val;
-	int ret;
-
-	mutex_lock(&ipcdev->lock);
-
-	reinit_completion(&ipcdev->cmd_complete);
-	type = (cmd & IPC_PUNIT_CMD_TYPE_MASK) >> IPC_TYPE_OFFSET;
-
-	if (in) {
-		ipc_write_data_low(ipcdev, type, *in);
-		if (type == GTDRIVER_IPC || type == ISPDRIVER_IPC)
-			ipc_write_data_high(ipcdev, type, *++in);
-	}
-
-	val = cmd & ~IPC_PUNIT_CMD_TYPE_MASK;
-	val |= CMD_RUN | para2 << CMD_PARA2_SHIFT | para1 << CMD_PARA1_SHIFT;
-	ipc_write_cmd(ipcdev, type, val);
-
-	ret = intel_punit_ipc_check_status(ipcdev, type);
-	if (ret)
-		goto out;
-
-	if (out) {
-		*out = ipc_read_data_low(ipcdev, type);
-		if (type == GTDRIVER_IPC || type == ISPDRIVER_IPC)
-			*++out = ipc_read_data_high(ipcdev, type);
-	}
-
-out:
-	mutex_unlock(&ipcdev->lock);
-	return ret;
-}
-EXPORT_SYMBOL_GPL(intel_punit_ipc_command);
-
-static irqreturn_t intel_punit_ioc(int irq, void *dev_id)
-{
-	IPC_DEV *ipcdev = dev_id;
-
-	complete(&ipcdev->cmd_complete);
-	return IRQ_HANDLED;
+	return pre_simple_cmd_fn(ipc_raw_cmd->cmd_list, ipc_raw_cmd->cmdlen);
 }
 
 static int intel_punit_get_bars(struct platform_device *pdev)
@@ -282,9 +133,77 @@ static int intel_punit_get_bars(struct platform_device *pdev)
 	return 0;
 }
 
+static int punit_ipc_err_code(int status)
+{
+	return (status & CMD_ERRCODE_MASK);
+}
+
+static int punit_ipc_busy_check(int status)
+{
+	return status | CMD_RUN;
+}
+
+static struct intel_ipc_dev *intel_punit_ipc_dev_create(struct device *dev,
+		const char *devname,
+		int irq,
+		void __iomem *base,
+		void __iomem *data)
+{
+	struct intel_ipc_dev_ops *ops;
+	struct intel_ipc_dev_cfg *cfg;
+	struct regmap *cmd_regs, *data_regs;
+
+	cfg = devm_kzalloc(dev, sizeof(*cfg), GFP_KERNEL);
+	if (!cfg)
+		return ERR_PTR(-ENOMEM);
+
+	ops = devm_kzalloc(dev, sizeof(*ops), GFP_KERNEL);
+	if (!ops)
+		return ERR_PTR(-ENOMEM);
+
+	punit_regmap_config.name = devm_kasprintf(dev, GFP_KERNEL, "%s_%s",
+						  devname, "base");
+
+	cmd_regs = devm_regmap_init_mmio_clk(dev, NULL, base,
+					     &punit_regmap_config);
+	if (IS_ERR(cmd_regs)) {
+		dev_err(dev, "cmd_regs regmap init failed\n");
+		return ERR_CAST(cmd_regs);
+	}
+
+	punit_regmap_config.name = devm_kasprintf(dev, GFP_KERNEL, "%s_%s",
+						  devname, "data");
+
+	data_regs = devm_regmap_init_mmio_clk(dev, NULL, data,
+					      &punit_regmap_config);
+	if (IS_ERR(data_regs)) {
+		dev_err(dev, "data_regs regmap init failed\n");
+		return ERR_CAST(data_regs);
+	}
+
+	/* set IPC dev ops */
+	ops->to_err_code = punit_ipc_err_code;
+	ops->busy_check = punit_ipc_busy_check;
+	ops->pre_simple_cmd_fn = pre_simple_cmd_fn;
+	ops->pre_raw_cmd_fn = pre_raw_cmd_fn;
+
+	if (irq > 0)
+		cfg->mode = IPC_DEV_MODE_IRQ;
+	else
+		cfg->mode = IPC_DEV_MODE_POLLING;
+
+	cfg->chan_type = IPC_CHANNEL_IA_PUNIT;
+	cfg->irq = irq;
+	cfg->irqflags = IRQF_NO_SUSPEND | IRQF_SHARED;
+	cfg->cmd_regs = cmd_regs;
+	cfg->data_regs = data_regs;
+
+	return devm_intel_ipc_dev_create(dev, devname, cfg, ops);
+}
+
 static int intel_punit_ipc_probe(struct platform_device *pdev)
 {
-	int irq, ret;
+	int irq, ret, i;
 
 	punit_ipcdev = devm_kzalloc(&pdev->dev,
 				    sizeof(*punit_ipcdev), GFP_KERNEL);
@@ -294,35 +213,30 @@ static int intel_punit_ipc_probe(struct platform_device *pdev)
 	platform_set_drvdata(pdev, punit_ipcdev);
 
 	irq = platform_get_irq(pdev, 0);
-	if (irq < 0) {
-		punit_ipcdev->irq = 0;
-		dev_warn(&pdev->dev, "Invalid IRQ, using polling mode\n");
-	} else {
-		ret = devm_request_irq(&pdev->dev, irq, intel_punit_ioc,
-				       IRQF_NO_SUSPEND, "intel_punit_ipc",
-				       &punit_ipcdev);
-		if (ret) {
-			dev_err(&pdev->dev, "Failed to request irq: %d\n", irq);
-			return ret;
-		}
-		punit_ipcdev->irq = irq;
-	}
 
 	ret = intel_punit_get_bars(pdev);
 	if (ret)
-		goto out;
+		return ret;
+
+	for (i = 0; i < RESERVED_IPC; i++) {
+		punit_ipcdev->ipc_dev[i] = intel_punit_ipc_dev_create(
+				&pdev->dev,
+				ipc_dev_name[i],
+				irq,
+				punit_ipcdev->base[i][BASE_IFACE],
+				punit_ipcdev->base[i][BASE_DATA]);
+
+		if (IS_ERR(punit_ipcdev->ipc_dev[i])) {
+			dev_err(&pdev->dev, "%s create failed\n",
+				ipc_dev_name[i]);
+			return PTR_ERR(punit_ipcdev->ipc_dev[i]);
+		}
+	}
 
 	punit_ipcdev->dev = &pdev->dev;
-	mutex_init(&punit_ipcdev->lock);
-	init_completion(&punit_ipcdev->cmd_complete);
 
-out:
 	return ret;
-}
 
-static int intel_punit_ipc_remove(struct platform_device *pdev)
-{
-	return 0;
 }
 
 static const struct acpi_device_id punit_ipc_acpi_ids[] = {
@@ -332,7 +246,6 @@ static const struct acpi_device_id punit_ipc_acpi_ids[] = {
 
 static struct platform_driver intel_punit_ipc_driver = {
 	.probe = intel_punit_ipc_probe,
-	.remove = intel_punit_ipc_remove,
 	.driver = {
 		.name = "intel_punit_ipc",
 		.acpi_match_table = ACPI_PTR(punit_ipc_acpi_ids),
diff --git a/drivers/platform/x86/intel_telemetry_pltdrv.c b/drivers/platform/x86/intel_telemetry_pltdrv.c
index e0424d5..0dbd7be 100644
--- a/drivers/platform/x86/intel_telemetry_pltdrv.c
+++ b/drivers/platform/x86/intel_telemetry_pltdrv.c
@@ -98,6 +98,7 @@ struct telem_ssram_region {
 };
 
 static struct telemetry_plt_config *telm_conf;
+static struct intel_ipc_dev *punit_ipc_dev;
 
 /*
  * The following counters are programmed by default during setup.
@@ -127,7 +128,6 @@ static struct telemetry_evtmap
 	{"PMC_S0IX_BLOCK_IPS_CLOCKS",           0x600B},
 };
 
-
 static struct telemetry_evtmap
 	telemetry_apl_pss_default_events[TELEM_MAX_OS_ALLOCATED_EVENTS] = {
 	{"IA_CORE0_C6_RES",			0x0400},
@@ -204,6 +204,28 @@ static const struct x86_cpu_id telemetry_cpu_ids[] = {
 
 MODULE_DEVICE_TABLE(x86cpu, telemetry_cpu_ids);
 
+static int telem_punit_cmd(struct intel_ipc_dev *ipc_dev, u32 cmd, u32 sub,
+		u32 *in, u32 *out)
+{
+	struct intel_ipc_cmd ipc_cmd = {0};
+	u32 cmd_list[PUNIT_PARAM_LEN] = {0};
+
+	cmd_list[0] = cmd;
+	cmd_list[1] = sub;
+
+	ipc_cmd.cmd_list = cmd_list;
+	ipc_cmd.cmdlen = PUNIT_PARAM_LEN;
+	ipc_cmd.in = in;
+	ipc_cmd.out = out;
+
+	if (in)
+		ipc_cmd.inlen = 1;
+	if (out)
+		ipc_cmd.outlen = 1;
+
+	return ipc_dev_cmd(ipc_dev, &ipc_cmd);
+}
+
 static inline int telem_get_unitconfig(enum telemetry_unit telem_unit,
 				     struct telemetry_unit_config **unit_config)
 {
@@ -283,13 +305,11 @@ static inline int telemetry_plt_config_ioss_event(u32 evt_id, int index)
 static inline int telemetry_plt_config_pss_event(u32 evt_id, int index)
 {
 	u32 write_buf;
-	int ret;
 
 	write_buf = evt_id | TELEM_EVENT_ENABLE;
-	ret = intel_punit_ipc_command(IPC_PUNIT_BIOS_WRITE_TELE_EVENT,
-				      index, 0, &write_buf, NULL);
 
-	return ret;
+	return telem_punit_cmd(punit_ipc_dev, IPC_PUNIT_BIOS_WRITE_TELE_EVENT,
+			       index, &write_buf, NULL);
 }
 
 static int telemetry_setup_iossevtconfig(struct telemetry_evtconfig evtconfig,
@@ -442,8 +462,9 @@ static int telemetry_setup_pssevtconfig(struct telemetry_evtconfig evtconfig,
 
 	/* PSS Config */
 	/* Get telemetry EVENT CTL */
-	ret = intel_punit_ipc_command(IPC_PUNIT_BIOS_READ_TELE_EVENT_CTRL,
-				      0, 0, NULL, &telem_ctrl);
+	ret = telem_punit_cmd(punit_ipc_dev,
+			      IPC_PUNIT_BIOS_READ_TELE_EVENT_CTRL,
+			      0, NULL, &telem_ctrl);
 	if (ret) {
 		pr_err("PSS TELEM_CTRL Read Failed\n");
 		return ret;
@@ -451,8 +472,9 @@ static int telemetry_setup_pssevtconfig(struct telemetry_evtconfig evtconfig,
 
 	/* Disable Telemetry */
 	TELEM_DISABLE(telem_ctrl);
-	ret = intel_punit_ipc_command(IPC_PUNIT_BIOS_WRITE_TELE_EVENT_CTRL,
-				      0, 0, &telem_ctrl, NULL);
+	ret = telem_punit_cmd(punit_ipc_dev,
+			      IPC_PUNIT_BIOS_WRITE_TELE_EVENT_CTRL,
+			      0, &telem_ctrl, NULL);
 	if (ret) {
 		pr_err("PSS TELEM_CTRL Event Disable Write Failed\n");
 		return ret;
@@ -463,9 +485,9 @@ static int telemetry_setup_pssevtconfig(struct telemetry_evtconfig evtconfig,
 		/* Clear All Events */
 		TELEM_CLEAR_EVENTS(telem_ctrl);
 
-		ret = intel_punit_ipc_command(
-				IPC_PUNIT_BIOS_WRITE_TELE_EVENT_CTRL,
-				0, 0, &telem_ctrl, NULL);
+		ret = telem_punit_cmd(punit_ipc_dev,
+				      IPC_PUNIT_BIOS_WRITE_TELE_EVENT_CTRL,
+				      0, &telem_ctrl, NULL);
 		if (ret) {
 			pr_err("PSS TELEM_CTRL Event Disable Write Failed\n");
 			return ret;
@@ -489,9 +511,9 @@ static int telemetry_setup_pssevtconfig(struct telemetry_evtconfig evtconfig,
 		/* Clear All Events */
 		TELEM_CLEAR_EVENTS(telem_ctrl);
 
-		ret = intel_punit_ipc_command(
-				IPC_PUNIT_BIOS_WRITE_TELE_EVENT_CTRL,
-				0, 0, &telem_ctrl, NULL);
+		ret = telem_punit_cmd(punit_ipc_dev,
+				      IPC_PUNIT_BIOS_WRITE_TELE_EVENT_CTRL,
+				      0, &telem_ctrl, NULL);
 		if (ret) {
 			pr_err("PSS TELEM_CTRL Event Disable Write Failed\n");
 			return ret;
@@ -540,8 +562,9 @@ static int telemetry_setup_pssevtconfig(struct telemetry_evtconfig evtconfig,
 	TELEM_ENABLE_PERIODIC(telem_ctrl);
 	telem_ctrl |= pss_period;
 
-	ret = intel_punit_ipc_command(IPC_PUNIT_BIOS_WRITE_TELE_EVENT_CTRL,
-				      0, 0, &telem_ctrl, NULL);
+	ret = telem_punit_cmd(punit_ipc_dev,
+			      IPC_PUNIT_BIOS_WRITE_TELE_EVENT_CTRL,
+			      0, &telem_ctrl, NULL);
 	if (ret) {
 		pr_err("PSS TELEM_CTRL Event Enable Write Failed\n");
 		return ret;
@@ -626,8 +649,8 @@ static int telemetry_setup(struct platform_device *pdev)
 	telm_conf->ioss_config.max_period = TELEM_MAX_PERIOD(read_buf);
 
 	/* PUNIT Mailbox Setup */
-	ret = intel_punit_ipc_command(IPC_PUNIT_BIOS_READ_TELE_INFO, 0, 0,
-				      NULL, &read_buf);
+	ret = telem_punit_cmd(punit_ipc_dev, IPC_PUNIT_BIOS_READ_TELE_INFO, 0,
+			      NULL, &read_buf);
 	if (ret) {
 		dev_err(&pdev->dev, "PSS TELEM_INFO Read Failed\n");
 		return ret;
@@ -752,9 +775,9 @@ static int telemetry_plt_set_sampling_period(u8 pss_period, u8 ioss_period)
 		}
 
 		/* Get telemetry EVENT CTL */
-		ret = intel_punit_ipc_command(
-				IPC_PUNIT_BIOS_READ_TELE_EVENT_CTRL,
-				0, 0, NULL, &telem_ctrl);
+		ret = telem_punit_cmd(punit_ipc_dev,
+				      IPC_PUNIT_BIOS_READ_TELE_EVENT_CTRL,
+				      0, NULL, &telem_ctrl);
 		if (ret) {
 			pr_err("PSS TELEM_CTRL Read Failed\n");
 			goto out;
@@ -762,9 +785,9 @@ static int telemetry_plt_set_sampling_period(u8 pss_period, u8 ioss_period)
 
 		/* Disable Telemetry */
 		TELEM_DISABLE(telem_ctrl);
-		ret = intel_punit_ipc_command(
-				IPC_PUNIT_BIOS_WRITE_TELE_EVENT_CTRL,
-				0, 0, &telem_ctrl, NULL);
+		ret = telem_punit_cmd(punit_ipc_dev,
+				      IPC_PUNIT_BIOS_WRITE_TELE_EVENT_CTRL,
+				      0, &telem_ctrl, NULL);
 		if (ret) {
 			pr_err("PSS TELEM_CTRL Event Disable Write Failed\n");
 			goto out;
@@ -776,9 +799,9 @@ static int telemetry_plt_set_sampling_period(u8 pss_period, u8 ioss_period)
 		TELEM_ENABLE_PERIODIC(telem_ctrl);
 		telem_ctrl |= pss_period;
 
-		ret = intel_punit_ipc_command(
-				IPC_PUNIT_BIOS_WRITE_TELE_EVENT_CTRL,
-				0, 0, &telem_ctrl, NULL);
+		ret = telem_punit_cmd(punit_ipc_dev,
+				      IPC_PUNIT_BIOS_WRITE_TELE_EVENT_CTRL,
+				      0, &telem_ctrl, NULL);
 		if (ret) {
 			pr_err("PSS TELEM_CTRL Event Enable Write Failed\n");
 			goto out;
@@ -1020,9 +1043,9 @@ static int telemetry_plt_get_trace_verbosity(enum telemetry_unit telem_unit,
 	mutex_lock(&(telm_conf->telem_trace_lock));
 	switch (telem_unit) {
 	case TELEM_PSS:
-		ret = intel_punit_ipc_command(
-				IPC_PUNIT_BIOS_READ_TELE_TRACE_CTRL,
-				0, 0, NULL, &temp);
+		ret = telem_punit_cmd(punit_ipc_dev,
+				      IPC_PUNIT_BIOS_READ_TELE_TRACE_CTRL,
+				      0, NULL, &temp);
 		if (ret) {
 			pr_err("PSS TRACE_CTRL Read Failed\n");
 			goto out;
@@ -1064,9 +1087,9 @@ static int telemetry_plt_set_trace_verbosity(enum telemetry_unit telem_unit,
 	mutex_lock(&(telm_conf->telem_trace_lock));
 	switch (telem_unit) {
 	case TELEM_PSS:
-		ret = intel_punit_ipc_command(
-				IPC_PUNIT_BIOS_READ_TELE_TRACE_CTRL,
-				0, 0, NULL, &temp);
+		ret = telem_punit_cmd(punit_ipc_dev,
+				      IPC_PUNIT_BIOS_READ_TELE_TRACE_CTRL, 0,
+				      NULL, &temp);
 		if (ret) {
 			pr_err("PSS TRACE_CTRL Read Failed\n");
 			goto out;
@@ -1074,10 +1097,9 @@ static int telemetry_plt_set_trace_verbosity(enum telemetry_unit telem_unit,
 
 		TELEM_CLEAR_VERBOSITY_BITS(temp);
 		TELEM_SET_VERBOSITY_BITS(temp, verbosity);
-
-		ret = intel_punit_ipc_command(
-				IPC_PUNIT_BIOS_WRITE_TELE_TRACE_CTRL,
-				0, 0, &temp, NULL);
+		ret = telem_punit_cmd(punit_ipc_dev,
+				      IPC_PUNIT_BIOS_WRITE_TELE_EVENT_CTRL, 0,
+				      &temp, NULL);
 		if (ret) {
 			pr_err("PSS TRACE_CTRL Verbosity Set Failed\n");
 			goto out;
@@ -1139,6 +1161,10 @@ static int telemetry_pltdrv_probe(struct platform_device *pdev)
 	if (!id)
 		return -ENODEV;
 
+	punit_ipc_dev = intel_ipc_dev_get(PUNIT_BIOS_IPC_DEV);
+	if (IS_ERR_OR_NULL(punit_ipc_dev))
+		return PTR_ERR(punit_ipc_dev);
+
 	telm_conf = (struct telemetry_plt_config *)id->driver_data;
 
 	res0 = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -1218,6 +1244,7 @@ static int telemetry_pltdrv_probe(struct platform_device *pdev)
 static int telemetry_pltdrv_remove(struct platform_device *pdev)
 {
 	telemetry_clear_pltdata();
+	intel_ipc_dev_put(punit_ipc_dev);
 	iounmap(telm_conf->pss_config.regmap);
 	iounmap(telm_conf->ioss_config.regmap);
 
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [RFC v8 5/7] platform/x86: intel_punit_ipc: Use generic intel ipc device calls
@ 2017-10-29  9:49   ` sathyanarayanan.kuppuswamy
  0 siblings, 0 replies; 30+ messages in thread
From: sathyanarayanan.kuppuswamy-VuQAYsv1563Yd54FQh9/CA @ 2017-10-29  9:49 UTC (permalink / raw)
  To: a.zummo-BfzFCNDTiLLj+vYz1yj4TQ, x86-DgEjT+Ai2ygdnm+yROfE0A,
	wim-IQzOog9fTRqzQB+pC5nmwQ, mingo-H+wXaHxf7aLQT0dZR+AlfA,
	alexandre.belloni-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
	qipeng.zha-ral2JQCrhuEAvxtiuMwx3w, hpa-YMNOUZJC4hwAvxtiuMwx3w,
	dvhart-wEGCiKHe2LqWVfeAwA7xHQ, tglx-hfZtesqFncYOwBW4kG4KsQ,
	lee.jones-QSEj5FYQhm4dnm+yROfE0A, andy-wEGCiKHe2LqWVfeAwA7xHQ,
	souvik.k.chakravarty-ral2JQCrhuEAvxtiuMwx3w
  Cc: linux-rtc-u79uwXL29TY76Z2rM5mHXA,
	linux-watchdog-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	platform-driver-x86-u79uwXL29TY76Z2rM5mHXA,
	sathyaosid-Re5JQEeQqe8AvxtiuMwx3w, Kuppuswamy Sathyanarayanan

From: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>

Removed redundant IPC helper functions and refactored the driver to use
APIs provided by generic IPC driver. This patch also cleans-up PUNIT IPC
user drivers(intel_telemetry_pltdrv.c) to use APIs provided by generic IPC
driver.

Signed-off-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
---
 arch/x86/include/asm/intel_punit_ipc.h        | 125 +++++------
 drivers/platform/x86/Kconfig                  |   1 +
 drivers/platform/x86/intel_punit_ipc.c        | 299 +++++++++-----------------
 drivers/platform/x86/intel_telemetry_pltdrv.c | 103 +++++----
 4 files changed, 222 insertions(+), 306 deletions(-)

Changes since v7:
 * Fixed style issues.

Changes since v6:
 * None

Changes since v5:
 * Adapted to change in arguments of ipc_dev_cmd() and ipc_dev_raw_cmd() APIs.

Changes since v4:
 * None

Changes since v2:
 * Added unique name to PUNIT BIOS, GTD, & ISP regmaps.
 * Added intel_ipc_dev_put() support.

Changes since v1:
 * Removed custom APIs.
 * Cleaned up PUNIT IPC user drivers to use APIs provided by generic
   IPC driver.

diff --git a/arch/x86/include/asm/intel_punit_ipc.h b/arch/x86/include/asm/intel_punit_ipc.h
index 201eb9d..8d1ab9e 100644
--- a/arch/x86/include/asm/intel_punit_ipc.h
+++ b/arch/x86/include/asm/intel_punit_ipc.h
@@ -1,10 +1,8 @@
 #ifndef _ASM_X86_INTEL_PUNIT_IPC_H_
 #define  _ASM_X86_INTEL_PUNIT_IPC_H_
 
-/*
- * Three types of 8bit P-Unit IPC commands are supported,
- * bit[7:6]: [00]: BIOS; [01]: GTD; [10]: ISPD.
- */
+#include <linux/platform_data/x86/intel_ipc_dev.h>
+
 typedef enum {
 	BIOS_IPC = 0,
 	GTDRIVER_IPC,
@@ -12,61 +10,60 @@ typedef enum {
 	RESERVED_IPC,
 } IPC_TYPE;
 
-#define IPC_TYPE_OFFSET			6
-#define IPC_PUNIT_BIOS_CMD_BASE		(BIOS_IPC << IPC_TYPE_OFFSET)
-#define IPC_PUNIT_GTD_CMD_BASE		(GTDDRIVER_IPC << IPC_TYPE_OFFSET)
-#define IPC_PUNIT_ISPD_CMD_BASE		(ISPDRIVER_IPC << IPC_TYPE_OFFSET)
-#define IPC_PUNIT_CMD_TYPE_MASK		(RESERVED_IPC << IPC_TYPE_OFFSET)
+#define PUNIT_BIOS_IPC_DEV			"punit_bios_ipc"
+#define PUNIT_GTD_IPC_DEV			"punit_gtd_ipc"
+#define PUNIT_ISP_IPC_DEV			"punit_isp_ipc"
+#define PUNIT_PARAM_LEN				3
 
 /* BIOS => Pcode commands */
-#define IPC_PUNIT_BIOS_ZERO			(IPC_PUNIT_BIOS_CMD_BASE | 0x00)
-#define IPC_PUNIT_BIOS_VR_INTERFACE		(IPC_PUNIT_BIOS_CMD_BASE | 0x01)
-#define IPC_PUNIT_BIOS_READ_PCS			(IPC_PUNIT_BIOS_CMD_BASE | 0x02)
-#define IPC_PUNIT_BIOS_WRITE_PCS		(IPC_PUNIT_BIOS_CMD_BASE | 0x03)
-#define IPC_PUNIT_BIOS_READ_PCU_CONFIG		(IPC_PUNIT_BIOS_CMD_BASE | 0x04)
-#define IPC_PUNIT_BIOS_WRITE_PCU_CONFIG		(IPC_PUNIT_BIOS_CMD_BASE | 0x05)
-#define IPC_PUNIT_BIOS_READ_PL1_SETTING		(IPC_PUNIT_BIOS_CMD_BASE | 0x06)
-#define IPC_PUNIT_BIOS_WRITE_PL1_SETTING	(IPC_PUNIT_BIOS_CMD_BASE | 0x07)
-#define IPC_PUNIT_BIOS_TRIGGER_VDD_RAM		(IPC_PUNIT_BIOS_CMD_BASE | 0x08)
-#define IPC_PUNIT_BIOS_READ_TELE_INFO		(IPC_PUNIT_BIOS_CMD_BASE | 0x09)
-#define IPC_PUNIT_BIOS_READ_TELE_TRACE_CTRL	(IPC_PUNIT_BIOS_CMD_BASE | 0x0a)
-#define IPC_PUNIT_BIOS_WRITE_TELE_TRACE_CTRL	(IPC_PUNIT_BIOS_CMD_BASE | 0x0b)
-#define IPC_PUNIT_BIOS_READ_TELE_EVENT_CTRL	(IPC_PUNIT_BIOS_CMD_BASE | 0x0c)
-#define IPC_PUNIT_BIOS_WRITE_TELE_EVENT_CTRL	(IPC_PUNIT_BIOS_CMD_BASE | 0x0d)
-#define IPC_PUNIT_BIOS_READ_TELE_TRACE		(IPC_PUNIT_BIOS_CMD_BASE | 0x0e)
-#define IPC_PUNIT_BIOS_WRITE_TELE_TRACE		(IPC_PUNIT_BIOS_CMD_BASE | 0x0f)
-#define IPC_PUNIT_BIOS_READ_TELE_EVENT		(IPC_PUNIT_BIOS_CMD_BASE | 0x10)
-#define IPC_PUNIT_BIOS_WRITE_TELE_EVENT		(IPC_PUNIT_BIOS_CMD_BASE | 0x11)
-#define IPC_PUNIT_BIOS_READ_MODULE_TEMP		(IPC_PUNIT_BIOS_CMD_BASE | 0x12)
-#define IPC_PUNIT_BIOS_RESERVED			(IPC_PUNIT_BIOS_CMD_BASE | 0x13)
-#define IPC_PUNIT_BIOS_READ_VOLTAGE_OVER	(IPC_PUNIT_BIOS_CMD_BASE | 0x14)
-#define IPC_PUNIT_BIOS_WRITE_VOLTAGE_OVER	(IPC_PUNIT_BIOS_CMD_BASE | 0x15)
-#define IPC_PUNIT_BIOS_READ_RATIO_OVER		(IPC_PUNIT_BIOS_CMD_BASE | 0x16)
-#define IPC_PUNIT_BIOS_WRITE_RATIO_OVER		(IPC_PUNIT_BIOS_CMD_BASE | 0x17)
-#define IPC_PUNIT_BIOS_READ_VF_GL_CTRL		(IPC_PUNIT_BIOS_CMD_BASE | 0x18)
-#define IPC_PUNIT_BIOS_WRITE_VF_GL_CTRL		(IPC_PUNIT_BIOS_CMD_BASE | 0x19)
-#define IPC_PUNIT_BIOS_READ_FM_SOC_TEMP_THRESH	(IPC_PUNIT_BIOS_CMD_BASE | 0x1a)
-#define IPC_PUNIT_BIOS_WRITE_FM_SOC_TEMP_THRESH	(IPC_PUNIT_BIOS_CMD_BASE | 0x1b)
+#define IPC_PUNIT_BIOS_ZERO			(0x00)
+#define IPC_PUNIT_BIOS_VR_INTERFACE		(0x01)
+#define IPC_PUNIT_BIOS_READ_PCS			(0x02)
+#define IPC_PUNIT_BIOS_WRITE_PCS		(0x03)
+#define IPC_PUNIT_BIOS_READ_PCU_CONFIG		(0x04)
+#define IPC_PUNIT_BIOS_WRITE_PCU_CONFIG		(0x05)
+#define IPC_PUNIT_BIOS_READ_PL1_SETTING		(0x06)
+#define IPC_PUNIT_BIOS_WRITE_PL1_SETTING	(0x07)
+#define IPC_PUNIT_BIOS_TRIGGER_VDD_RAM		(0x08)
+#define IPC_PUNIT_BIOS_READ_TELE_INFO		(0x09)
+#define IPC_PUNIT_BIOS_READ_TELE_TRACE_CTRL	(0x0a)
+#define IPC_PUNIT_BIOS_WRITE_TELE_TRACE_CTRL	(0x0b)
+#define IPC_PUNIT_BIOS_READ_TELE_EVENT_CTRL	(0x0c)
+#define IPC_PUNIT_BIOS_WRITE_TELE_EVENT_CTRL	(0x0d)
+#define IPC_PUNIT_BIOS_READ_TELE_TRACE		(0x0e)
+#define IPC_PUNIT_BIOS_WRITE_TELE_TRACE		(0x0f)
+#define IPC_PUNIT_BIOS_READ_TELE_EVENT		(0x10)
+#define IPC_PUNIT_BIOS_WRITE_TELE_EVENT		(0x11)
+#define IPC_PUNIT_BIOS_READ_MODULE_TEMP		(0x12)
+#define IPC_PUNIT_BIOS_RESERVED			(0x13)
+#define IPC_PUNIT_BIOS_READ_VOLTAGE_OVER	(0x14)
+#define IPC_PUNIT_BIOS_WRITE_VOLTAGE_OVER	(0x15)
+#define IPC_PUNIT_BIOS_READ_RATIO_OVER		(0x16)
+#define IPC_PUNIT_BIOS_WRITE_RATIO_OVER		(0x17)
+#define IPC_PUNIT_BIOS_READ_VF_GL_CTRL		(0x18)
+#define IPC_PUNIT_BIOS_WRITE_VF_GL_CTRL		(0x19)
+#define IPC_PUNIT_BIOS_READ_FM_SOC_TEMP_THRESH	(0x1a)
+#define IPC_PUNIT_BIOS_WRITE_FM_SOC_TEMP_THRESH	(0x1b)
 
 /* GT Driver => Pcode commands */
-#define IPC_PUNIT_GTD_ZERO			(IPC_PUNIT_GTD_CMD_BASE | 0x00)
-#define IPC_PUNIT_GTD_CONFIG			(IPC_PUNIT_GTD_CMD_BASE | 0x01)
-#define IPC_PUNIT_GTD_READ_ICCP_LIC_CDYN_SCAL	(IPC_PUNIT_GTD_CMD_BASE | 0x02)
-#define IPC_PUNIT_GTD_WRITE_ICCP_LIC_CDYN_SCAL	(IPC_PUNIT_GTD_CMD_BASE | 0x03)
-#define IPC_PUNIT_GTD_GET_WM_VAL		(IPC_PUNIT_GTD_CMD_BASE | 0x06)
-#define IPC_PUNIT_GTD_WRITE_CONFIG_WISHREQ	(IPC_PUNIT_GTD_CMD_BASE | 0x07)
-#define IPC_PUNIT_GTD_READ_REQ_DUTY_CYCLE	(IPC_PUNIT_GTD_CMD_BASE | 0x16)
-#define IPC_PUNIT_GTD_DIS_VOL_FREQ_CHG_REQUEST	(IPC_PUNIT_GTD_CMD_BASE | 0x17)
-#define IPC_PUNIT_GTD_DYNA_DUTY_CYCLE_CTRL	(IPC_PUNIT_GTD_CMD_BASE | 0x1a)
-#define IPC_PUNIT_GTD_DYNA_DUTY_CYCLE_TUNING	(IPC_PUNIT_GTD_CMD_BASE | 0x1c)
+#define IPC_PUNIT_GTD_ZERO			(0x00)
+#define IPC_PUNIT_GTD_CONFIG			(0x01)
+#define IPC_PUNIT_GTD_READ_ICCP_LIC_CDYN_SCAL	(0x02)
+#define IPC_PUNIT_GTD_WRITE_ICCP_LIC_CDYN_SCAL	(0x03)
+#define IPC_PUNIT_GTD_GET_WM_VAL		(0x06)
+#define IPC_PUNIT_GTD_WRITE_CONFIG_WISHREQ	(0x07)
+#define IPC_PUNIT_GTD_READ_REQ_DUTY_CYCLE	(0x16)
+#define IPC_PUNIT_GTD_DIS_VOL_FREQ_CHG_REQUEST	(0x17)
+#define IPC_PUNIT_GTD_DYNA_DUTY_CYCLE_CTRL	(0x1a)
+#define IPC_PUNIT_GTD_DYNA_DUTY_CYCLE_TUNING	(0x1c)
 
 /* ISP Driver => Pcode commands */
-#define IPC_PUNIT_ISPD_ZERO			(IPC_PUNIT_ISPD_CMD_BASE | 0x00)
-#define IPC_PUNIT_ISPD_CONFIG			(IPC_PUNIT_ISPD_CMD_BASE | 0x01)
-#define IPC_PUNIT_ISPD_GET_ISP_LTR_VAL		(IPC_PUNIT_ISPD_CMD_BASE | 0x02)
-#define IPC_PUNIT_ISPD_ACCESS_IU_FREQ_BOUNDS	(IPC_PUNIT_ISPD_CMD_BASE | 0x03)
-#define IPC_PUNIT_ISPD_READ_CDYN_LEVEL		(IPC_PUNIT_ISPD_CMD_BASE | 0x04)
-#define IPC_PUNIT_ISPD_WRITE_CDYN_LEVEL		(IPC_PUNIT_ISPD_CMD_BASE | 0x05)
+#define IPC_PUNIT_ISPD_ZERO			(0x00)
+#define IPC_PUNIT_ISPD_CONFIG			(0x01)
+#define IPC_PUNIT_ISPD_GET_ISP_LTR_VAL		(0x02)
+#define IPC_PUNIT_ISPD_ACCESS_IU_FREQ_BOUNDS	(0x03)
+#define IPC_PUNIT_ISPD_READ_CDYN_LEVEL		(0x04)
+#define IPC_PUNIT_ISPD_WRITE_CDYN_LEVEL		(0x05)
 
 /* Error codes */
 #define IPC_PUNIT_ERR_SUCCESS			0
@@ -76,26 +73,4 @@ typedef enum {
 #define IPC_PUNIT_ERR_CMD_LOCKED		4
 #define IPC_PUNIT_ERR_INVALID_VR_ID		5
 #define IPC_PUNIT_ERR_VR_ERR			6
-
-#if IS_ENABLED(CONFIG_INTEL_PUNIT_IPC)
-
-int intel_punit_ipc_simple_command(int cmd, int para1, int para2);
-int intel_punit_ipc_command(u32 cmd, u32 para1, u32 para2, u32 *in, u32 *out);
-
-#else
-
-static inline int intel_punit_ipc_simple_command(int cmd,
-						  int para1, int para2)
-{
-	return -ENODEV;
-}
-
-static inline int intel_punit_ipc_command(u32 cmd, u32 para1, u32 para2,
-					  u32 *in, u32 *out)
-{
-	return -ENODEV;
-}
-
-#endif /* CONFIG_INTEL_PUNIT_IPC */
-
 #endif
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
index 9df7cda..82479ca 100644
--- a/drivers/platform/x86/Kconfig
+++ b/drivers/platform/x86/Kconfig
@@ -1083,6 +1083,7 @@ config SURFACE_3_BUTTON
 
 config INTEL_PUNIT_IPC
 	tristate "Intel P-Unit IPC Driver"
+	select REGMAP_MMIO
 	---help---
 	  This driver provides support for Intel P-Unit Mailbox IPC mechanism,
 	  which is used to bridge the communications between kernel and P-Unit.
diff --git a/drivers/platform/x86/intel_punit_ipc.c b/drivers/platform/x86/intel_punit_ipc.c
index b5b8901..50fd502 100644
--- a/drivers/platform/x86/intel_punit_ipc.c
+++ b/drivers/platform/x86/intel_punit_ipc.c
@@ -18,19 +18,16 @@
 #include <linux/device.h>
 #include <linux/interrupt.h>
 #include <linux/platform_device.h>
+#include <linux/platform_data/x86/intel_ipc_dev.h>
+#include <linux/regmap.h>
 #include <asm/intel_punit_ipc.h>
 
-/* IPC Mailbox registers */
-#define OFFSET_DATA_LOW		0x0
-#define OFFSET_DATA_HIGH	0x4
 /* bit field of interface register */
 #define	CMD_RUN			BIT(31)
 #define	CMD_ERRCODE_MASK	GENMASK(7, 0)
 #define	CMD_PARA1_SHIFT		8
 #define	CMD_PARA2_SHIFT		16
 
-#define CMD_TIMEOUT_SECONDS	1
-
 enum {
 	BASE_DATA = 0,
 	BASE_IFACE,
@@ -39,187 +36,41 @@ enum {
 
 typedef struct {
 	struct device *dev;
-	struct mutex lock;
-	int irq;
-	struct completion cmd_complete;
 	/* base of interface and data registers */
 	void __iomem *base[RESERVED_IPC][BASE_MAX];
+	struct intel_ipc_dev *ipc_dev[RESERVED_IPC];
 	IPC_TYPE type;
 } IPC_DEV;
 
 static IPC_DEV *punit_ipcdev;
 
-static inline u32 ipc_read_status(IPC_DEV *ipcdev, IPC_TYPE type)
-{
-	return readl(ipcdev->base[type][BASE_IFACE]);
-}
-
-static inline void ipc_write_cmd(IPC_DEV *ipcdev, IPC_TYPE type, u32 cmd)
-{
-	writel(cmd, ipcdev->base[type][BASE_IFACE]);
-}
-
-static inline u32 ipc_read_data_low(IPC_DEV *ipcdev, IPC_TYPE type)
-{
-	return readl(ipcdev->base[type][BASE_DATA] + OFFSET_DATA_LOW);
-}
-
-static inline u32 ipc_read_data_high(IPC_DEV *ipcdev, IPC_TYPE type)
-{
-	return readl(ipcdev->base[type][BASE_DATA] + OFFSET_DATA_HIGH);
-}
-
-static inline void ipc_write_data_low(IPC_DEV *ipcdev, IPC_TYPE type, u32 data)
-{
-	writel(data, ipcdev->base[type][BASE_DATA] + OFFSET_DATA_LOW);
-}
-
-static inline void ipc_write_data_high(IPC_DEV *ipcdev, IPC_TYPE type, u32 data)
-{
-	writel(data, ipcdev->base[type][BASE_DATA] + OFFSET_DATA_HIGH);
-}
+const char *ipc_dev_name[RESERVED_IPC] = {
+	PUNIT_BIOS_IPC_DEV,
+	PUNIT_GTD_IPC_DEV,
+	PUNIT_ISP_IPC_DEV
+};
 
-static const char *ipc_err_string(int error)
-{
-	if (error == IPC_PUNIT_ERR_SUCCESS)
-		return "no error";
-	else if (error == IPC_PUNIT_ERR_INVALID_CMD)
-		return "invalid command";
-	else if (error == IPC_PUNIT_ERR_INVALID_PARAMETER)
-		return "invalid parameter";
-	else if (error == IPC_PUNIT_ERR_CMD_TIMEOUT)
-		return "command timeout";
-	else if (error == IPC_PUNIT_ERR_CMD_LOCKED)
-		return "command locked";
-	else if (error == IPC_PUNIT_ERR_INVALID_VR_ID)
-		return "invalid vr id";
-	else if (error == IPC_PUNIT_ERR_VR_ERR)
-		return "vr error";
-	else
-		return "unknown error";
-}
+static struct regmap_config punit_regmap_config = {
+	.reg_bits = 32,
+	.reg_stride = 4,
+	.val_bits = 32,
+};
 
-static int intel_punit_ipc_check_status(IPC_DEV *ipcdev, IPC_TYPE type)
+int pre_simple_cmd_fn(u32 *cmd_list, u32 cmdlen)
 {
-	int loops = CMD_TIMEOUT_SECONDS * USEC_PER_SEC;
-	int errcode;
-	int status;
-
-	if (ipcdev->irq) {
-		if (!wait_for_completion_timeout(&ipcdev->cmd_complete,
-						 CMD_TIMEOUT_SECONDS * HZ)) {
-			dev_err(ipcdev->dev, "IPC timed out\n");
-			return -ETIMEDOUT;
-		}
-	} else {
-		while ((ipc_read_status(ipcdev, type) & CMD_RUN) && --loops)
-			udelay(1);
-		if (!loops) {
-			dev_err(ipcdev->dev, "IPC timed out\n");
-			return -ETIMEDOUT;
-		}
-	}
+	if (!cmd_list || cmdlen != PUNIT_PARAM_LEN)
+		return -EINVAL;
 
-	status = ipc_read_status(ipcdev, type);
-	errcode = status & CMD_ERRCODE_MASK;
-	if (errcode) {
-		dev_err(ipcdev->dev, "IPC failed: %s, IPC_STS=0x%x\n",
-			ipc_err_string(errcode), status);
-		return -EIO;
-	}
+	cmd_list[0] |= CMD_RUN | cmd_list[1] << CMD_PARA1_SHIFT |
+		cmd_list[2] << CMD_PARA2_SHIFT;
 
 	return 0;
 }
 
-/**
- * intel_punit_ipc_simple_command() - Simple IPC command
- * @cmd:	IPC command code.
- * @para1:	First 8bit parameter, set 0 if not used.
- * @para2:	Second 8bit parameter, set 0 if not used.
- *
- * Send a IPC command to P-Unit when there is no data transaction
- *
- * Return:	IPC error code or 0 on success.
- */
-int intel_punit_ipc_simple_command(int cmd, int para1, int para2)
+/* Input data, 32bit for BIOS cmd, two 32bit for GTD and ISPD. */
+int pre_raw_cmd_fn(struct intel_ipc_raw_cmd *ipc_raw_cmd)
 {
-	IPC_DEV *ipcdev = punit_ipcdev;
-	IPC_TYPE type;
-	u32 val;
-	int ret;
-
-	mutex_lock(&ipcdev->lock);
-
-	reinit_completion(&ipcdev->cmd_complete);
-	type = (cmd & IPC_PUNIT_CMD_TYPE_MASK) >> IPC_TYPE_OFFSET;
-
-	val = cmd & ~IPC_PUNIT_CMD_TYPE_MASK;
-	val |= CMD_RUN | para2 << CMD_PARA2_SHIFT | para1 << CMD_PARA1_SHIFT;
-	ipc_write_cmd(ipcdev, type, val);
-	ret = intel_punit_ipc_check_status(ipcdev, type);
-
-	mutex_unlock(&ipcdev->lock);
-
-	return ret;
-}
-EXPORT_SYMBOL(intel_punit_ipc_simple_command);
-
-/**
- * intel_punit_ipc_command() - IPC command with data and pointers
- * @cmd:	IPC command code.
- * @para1:	First 8bit parameter, set 0 if not used.
- * @para2:	Second 8bit parameter, set 0 if not used.
- * @in:		Input data, 32bit for BIOS cmd, two 32bit for GTD and ISPD.
- * @out:	Output data.
- *
- * Send a IPC command to P-Unit with data transaction
- *
- * Return:	IPC error code or 0 on success.
- */
-int intel_punit_ipc_command(u32 cmd, u32 para1, u32 para2, u32 *in, u32 *out)
-{
-	IPC_DEV *ipcdev = punit_ipcdev;
-	IPC_TYPE type;
-	u32 val;
-	int ret;
-
-	mutex_lock(&ipcdev->lock);
-
-	reinit_completion(&ipcdev->cmd_complete);
-	type = (cmd & IPC_PUNIT_CMD_TYPE_MASK) >> IPC_TYPE_OFFSET;
-
-	if (in) {
-		ipc_write_data_low(ipcdev, type, *in);
-		if (type == GTDRIVER_IPC || type == ISPDRIVER_IPC)
-			ipc_write_data_high(ipcdev, type, *++in);
-	}
-
-	val = cmd & ~IPC_PUNIT_CMD_TYPE_MASK;
-	val |= CMD_RUN | para2 << CMD_PARA2_SHIFT | para1 << CMD_PARA1_SHIFT;
-	ipc_write_cmd(ipcdev, type, val);
-
-	ret = intel_punit_ipc_check_status(ipcdev, type);
-	if (ret)
-		goto out;
-
-	if (out) {
-		*out = ipc_read_data_low(ipcdev, type);
-		if (type == GTDRIVER_IPC || type == ISPDRIVER_IPC)
-			*++out = ipc_read_data_high(ipcdev, type);
-	}
-
-out:
-	mutex_unlock(&ipcdev->lock);
-	return ret;
-}
-EXPORT_SYMBOL_GPL(intel_punit_ipc_command);
-
-static irqreturn_t intel_punit_ioc(int irq, void *dev_id)
-{
-	IPC_DEV *ipcdev = dev_id;
-
-	complete(&ipcdev->cmd_complete);
-	return IRQ_HANDLED;
+	return pre_simple_cmd_fn(ipc_raw_cmd->cmd_list, ipc_raw_cmd->cmdlen);
 }
 
 static int intel_punit_get_bars(struct platform_device *pdev)
@@ -282,9 +133,77 @@ static int intel_punit_get_bars(struct platform_device *pdev)
 	return 0;
 }
 
+static int punit_ipc_err_code(int status)
+{
+	return (status & CMD_ERRCODE_MASK);
+}
+
+static int punit_ipc_busy_check(int status)
+{
+	return status | CMD_RUN;
+}
+
+static struct intel_ipc_dev *intel_punit_ipc_dev_create(struct device *dev,
+		const char *devname,
+		int irq,
+		void __iomem *base,
+		void __iomem *data)
+{
+	struct intel_ipc_dev_ops *ops;
+	struct intel_ipc_dev_cfg *cfg;
+	struct regmap *cmd_regs, *data_regs;
+
+	cfg = devm_kzalloc(dev, sizeof(*cfg), GFP_KERNEL);
+	if (!cfg)
+		return ERR_PTR(-ENOMEM);
+
+	ops = devm_kzalloc(dev, sizeof(*ops), GFP_KERNEL);
+	if (!ops)
+		return ERR_PTR(-ENOMEM);
+
+	punit_regmap_config.name = devm_kasprintf(dev, GFP_KERNEL, "%s_%s",
+						  devname, "base");
+
+	cmd_regs = devm_regmap_init_mmio_clk(dev, NULL, base,
+					     &punit_regmap_config);
+	if (IS_ERR(cmd_regs)) {
+		dev_err(dev, "cmd_regs regmap init failed\n");
+		return ERR_CAST(cmd_regs);
+	}
+
+	punit_regmap_config.name = devm_kasprintf(dev, GFP_KERNEL, "%s_%s",
+						  devname, "data");
+
+	data_regs = devm_regmap_init_mmio_clk(dev, NULL, data,
+					      &punit_regmap_config);
+	if (IS_ERR(data_regs)) {
+		dev_err(dev, "data_regs regmap init failed\n");
+		return ERR_CAST(data_regs);
+	}
+
+	/* set IPC dev ops */
+	ops->to_err_code = punit_ipc_err_code;
+	ops->busy_check = punit_ipc_busy_check;
+	ops->pre_simple_cmd_fn = pre_simple_cmd_fn;
+	ops->pre_raw_cmd_fn = pre_raw_cmd_fn;
+
+	if (irq > 0)
+		cfg->mode = IPC_DEV_MODE_IRQ;
+	else
+		cfg->mode = IPC_DEV_MODE_POLLING;
+
+	cfg->chan_type = IPC_CHANNEL_IA_PUNIT;
+	cfg->irq = irq;
+	cfg->irqflags = IRQF_NO_SUSPEND | IRQF_SHARED;
+	cfg->cmd_regs = cmd_regs;
+	cfg->data_regs = data_regs;
+
+	return devm_intel_ipc_dev_create(dev, devname, cfg, ops);
+}
+
 static int intel_punit_ipc_probe(struct platform_device *pdev)
 {
-	int irq, ret;
+	int irq, ret, i;
 
 	punit_ipcdev = devm_kzalloc(&pdev->dev,
 				    sizeof(*punit_ipcdev), GFP_KERNEL);
@@ -294,35 +213,30 @@ static int intel_punit_ipc_probe(struct platform_device *pdev)
 	platform_set_drvdata(pdev, punit_ipcdev);
 
 	irq = platform_get_irq(pdev, 0);
-	if (irq < 0) {
-		punit_ipcdev->irq = 0;
-		dev_warn(&pdev->dev, "Invalid IRQ, using polling mode\n");
-	} else {
-		ret = devm_request_irq(&pdev->dev, irq, intel_punit_ioc,
-				       IRQF_NO_SUSPEND, "intel_punit_ipc",
-				       &punit_ipcdev);
-		if (ret) {
-			dev_err(&pdev->dev, "Failed to request irq: %d\n", irq);
-			return ret;
-		}
-		punit_ipcdev->irq = irq;
-	}
 
 	ret = intel_punit_get_bars(pdev);
 	if (ret)
-		goto out;
+		return ret;
+
+	for (i = 0; i < RESERVED_IPC; i++) {
+		punit_ipcdev->ipc_dev[i] = intel_punit_ipc_dev_create(
+				&pdev->dev,
+				ipc_dev_name[i],
+				irq,
+				punit_ipcdev->base[i][BASE_IFACE],
+				punit_ipcdev->base[i][BASE_DATA]);
+
+		if (IS_ERR(punit_ipcdev->ipc_dev[i])) {
+			dev_err(&pdev->dev, "%s create failed\n",
+				ipc_dev_name[i]);
+			return PTR_ERR(punit_ipcdev->ipc_dev[i]);
+		}
+	}
 
 	punit_ipcdev->dev = &pdev->dev;
-	mutex_init(&punit_ipcdev->lock);
-	init_completion(&punit_ipcdev->cmd_complete);
 
-out:
 	return ret;
-}
 
-static int intel_punit_ipc_remove(struct platform_device *pdev)
-{
-	return 0;
 }
 
 static const struct acpi_device_id punit_ipc_acpi_ids[] = {
@@ -332,7 +246,6 @@ static const struct acpi_device_id punit_ipc_acpi_ids[] = {
 
 static struct platform_driver intel_punit_ipc_driver = {
 	.probe = intel_punit_ipc_probe,
-	.remove = intel_punit_ipc_remove,
 	.driver = {
 		.name = "intel_punit_ipc",
 		.acpi_match_table = ACPI_PTR(punit_ipc_acpi_ids),
diff --git a/drivers/platform/x86/intel_telemetry_pltdrv.c b/drivers/platform/x86/intel_telemetry_pltdrv.c
index e0424d5..0dbd7be 100644
--- a/drivers/platform/x86/intel_telemetry_pltdrv.c
+++ b/drivers/platform/x86/intel_telemetry_pltdrv.c
@@ -98,6 +98,7 @@ struct telem_ssram_region {
 };
 
 static struct telemetry_plt_config *telm_conf;
+static struct intel_ipc_dev *punit_ipc_dev;
 
 /*
  * The following counters are programmed by default during setup.
@@ -127,7 +128,6 @@ static struct telemetry_evtmap
 	{"PMC_S0IX_BLOCK_IPS_CLOCKS",           0x600B},
 };
 
-
 static struct telemetry_evtmap
 	telemetry_apl_pss_default_events[TELEM_MAX_OS_ALLOCATED_EVENTS] = {
 	{"IA_CORE0_C6_RES",			0x0400},
@@ -204,6 +204,28 @@ static const struct x86_cpu_id telemetry_cpu_ids[] = {
 
 MODULE_DEVICE_TABLE(x86cpu, telemetry_cpu_ids);
 
+static int telem_punit_cmd(struct intel_ipc_dev *ipc_dev, u32 cmd, u32 sub,
+		u32 *in, u32 *out)
+{
+	struct intel_ipc_cmd ipc_cmd = {0};
+	u32 cmd_list[PUNIT_PARAM_LEN] = {0};
+
+	cmd_list[0] = cmd;
+	cmd_list[1] = sub;
+
+	ipc_cmd.cmd_list = cmd_list;
+	ipc_cmd.cmdlen = PUNIT_PARAM_LEN;
+	ipc_cmd.in = in;
+	ipc_cmd.out = out;
+
+	if (in)
+		ipc_cmd.inlen = 1;
+	if (out)
+		ipc_cmd.outlen = 1;
+
+	return ipc_dev_cmd(ipc_dev, &ipc_cmd);
+}
+
 static inline int telem_get_unitconfig(enum telemetry_unit telem_unit,
 				     struct telemetry_unit_config **unit_config)
 {
@@ -283,13 +305,11 @@ static inline int telemetry_plt_config_ioss_event(u32 evt_id, int index)
 static inline int telemetry_plt_config_pss_event(u32 evt_id, int index)
 {
 	u32 write_buf;
-	int ret;
 
 	write_buf = evt_id | TELEM_EVENT_ENABLE;
-	ret = intel_punit_ipc_command(IPC_PUNIT_BIOS_WRITE_TELE_EVENT,
-				      index, 0, &write_buf, NULL);
 
-	return ret;
+	return telem_punit_cmd(punit_ipc_dev, IPC_PUNIT_BIOS_WRITE_TELE_EVENT,
+			       index, &write_buf, NULL);
 }
 
 static int telemetry_setup_iossevtconfig(struct telemetry_evtconfig evtconfig,
@@ -442,8 +462,9 @@ static int telemetry_setup_pssevtconfig(struct telemetry_evtconfig evtconfig,
 
 	/* PSS Config */
 	/* Get telemetry EVENT CTL */
-	ret = intel_punit_ipc_command(IPC_PUNIT_BIOS_READ_TELE_EVENT_CTRL,
-				      0, 0, NULL, &telem_ctrl);
+	ret = telem_punit_cmd(punit_ipc_dev,
+			      IPC_PUNIT_BIOS_READ_TELE_EVENT_CTRL,
+			      0, NULL, &telem_ctrl);
 	if (ret) {
 		pr_err("PSS TELEM_CTRL Read Failed\n");
 		return ret;
@@ -451,8 +472,9 @@ static int telemetry_setup_pssevtconfig(struct telemetry_evtconfig evtconfig,
 
 	/* Disable Telemetry */
 	TELEM_DISABLE(telem_ctrl);
-	ret = intel_punit_ipc_command(IPC_PUNIT_BIOS_WRITE_TELE_EVENT_CTRL,
-				      0, 0, &telem_ctrl, NULL);
+	ret = telem_punit_cmd(punit_ipc_dev,
+			      IPC_PUNIT_BIOS_WRITE_TELE_EVENT_CTRL,
+			      0, &telem_ctrl, NULL);
 	if (ret) {
 		pr_err("PSS TELEM_CTRL Event Disable Write Failed\n");
 		return ret;
@@ -463,9 +485,9 @@ static int telemetry_setup_pssevtconfig(struct telemetry_evtconfig evtconfig,
 		/* Clear All Events */
 		TELEM_CLEAR_EVENTS(telem_ctrl);
 
-		ret = intel_punit_ipc_command(
-				IPC_PUNIT_BIOS_WRITE_TELE_EVENT_CTRL,
-				0, 0, &telem_ctrl, NULL);
+		ret = telem_punit_cmd(punit_ipc_dev,
+				      IPC_PUNIT_BIOS_WRITE_TELE_EVENT_CTRL,
+				      0, &telem_ctrl, NULL);
 		if (ret) {
 			pr_err("PSS TELEM_CTRL Event Disable Write Failed\n");
 			return ret;
@@ -489,9 +511,9 @@ static int telemetry_setup_pssevtconfig(struct telemetry_evtconfig evtconfig,
 		/* Clear All Events */
 		TELEM_CLEAR_EVENTS(telem_ctrl);
 
-		ret = intel_punit_ipc_command(
-				IPC_PUNIT_BIOS_WRITE_TELE_EVENT_CTRL,
-				0, 0, &telem_ctrl, NULL);
+		ret = telem_punit_cmd(punit_ipc_dev,
+				      IPC_PUNIT_BIOS_WRITE_TELE_EVENT_CTRL,
+				      0, &telem_ctrl, NULL);
 		if (ret) {
 			pr_err("PSS TELEM_CTRL Event Disable Write Failed\n");
 			return ret;
@@ -540,8 +562,9 @@ static int telemetry_setup_pssevtconfig(struct telemetry_evtconfig evtconfig,
 	TELEM_ENABLE_PERIODIC(telem_ctrl);
 	telem_ctrl |= pss_period;
 
-	ret = intel_punit_ipc_command(IPC_PUNIT_BIOS_WRITE_TELE_EVENT_CTRL,
-				      0, 0, &telem_ctrl, NULL);
+	ret = telem_punit_cmd(punit_ipc_dev,
+			      IPC_PUNIT_BIOS_WRITE_TELE_EVENT_CTRL,
+			      0, &telem_ctrl, NULL);
 	if (ret) {
 		pr_err("PSS TELEM_CTRL Event Enable Write Failed\n");
 		return ret;
@@ -626,8 +649,8 @@ static int telemetry_setup(struct platform_device *pdev)
 	telm_conf->ioss_config.max_period = TELEM_MAX_PERIOD(read_buf);
 
 	/* PUNIT Mailbox Setup */
-	ret = intel_punit_ipc_command(IPC_PUNIT_BIOS_READ_TELE_INFO, 0, 0,
-				      NULL, &read_buf);
+	ret = telem_punit_cmd(punit_ipc_dev, IPC_PUNIT_BIOS_READ_TELE_INFO, 0,
+			      NULL, &read_buf);
 	if (ret) {
 		dev_err(&pdev->dev, "PSS TELEM_INFO Read Failed\n");
 		return ret;
@@ -752,9 +775,9 @@ static int telemetry_plt_set_sampling_period(u8 pss_period, u8 ioss_period)
 		}
 
 		/* Get telemetry EVENT CTL */
-		ret = intel_punit_ipc_command(
-				IPC_PUNIT_BIOS_READ_TELE_EVENT_CTRL,
-				0, 0, NULL, &telem_ctrl);
+		ret = telem_punit_cmd(punit_ipc_dev,
+				      IPC_PUNIT_BIOS_READ_TELE_EVENT_CTRL,
+				      0, NULL, &telem_ctrl);
 		if (ret) {
 			pr_err("PSS TELEM_CTRL Read Failed\n");
 			goto out;
@@ -762,9 +785,9 @@ static int telemetry_plt_set_sampling_period(u8 pss_period, u8 ioss_period)
 
 		/* Disable Telemetry */
 		TELEM_DISABLE(telem_ctrl);
-		ret = intel_punit_ipc_command(
-				IPC_PUNIT_BIOS_WRITE_TELE_EVENT_CTRL,
-				0, 0, &telem_ctrl, NULL);
+		ret = telem_punit_cmd(punit_ipc_dev,
+				      IPC_PUNIT_BIOS_WRITE_TELE_EVENT_CTRL,
+				      0, &telem_ctrl, NULL);
 		if (ret) {
 			pr_err("PSS TELEM_CTRL Event Disable Write Failed\n");
 			goto out;
@@ -776,9 +799,9 @@ static int telemetry_plt_set_sampling_period(u8 pss_period, u8 ioss_period)
 		TELEM_ENABLE_PERIODIC(telem_ctrl);
 		telem_ctrl |= pss_period;
 
-		ret = intel_punit_ipc_command(
-				IPC_PUNIT_BIOS_WRITE_TELE_EVENT_CTRL,
-				0, 0, &telem_ctrl, NULL);
+		ret = telem_punit_cmd(punit_ipc_dev,
+				      IPC_PUNIT_BIOS_WRITE_TELE_EVENT_CTRL,
+				      0, &telem_ctrl, NULL);
 		if (ret) {
 			pr_err("PSS TELEM_CTRL Event Enable Write Failed\n");
 			goto out;
@@ -1020,9 +1043,9 @@ static int telemetry_plt_get_trace_verbosity(enum telemetry_unit telem_unit,
 	mutex_lock(&(telm_conf->telem_trace_lock));
 	switch (telem_unit) {
 	case TELEM_PSS:
-		ret = intel_punit_ipc_command(
-				IPC_PUNIT_BIOS_READ_TELE_TRACE_CTRL,
-				0, 0, NULL, &temp);
+		ret = telem_punit_cmd(punit_ipc_dev,
+				      IPC_PUNIT_BIOS_READ_TELE_TRACE_CTRL,
+				      0, NULL, &temp);
 		if (ret) {
 			pr_err("PSS TRACE_CTRL Read Failed\n");
 			goto out;
@@ -1064,9 +1087,9 @@ static int telemetry_plt_set_trace_verbosity(enum telemetry_unit telem_unit,
 	mutex_lock(&(telm_conf->telem_trace_lock));
 	switch (telem_unit) {
 	case TELEM_PSS:
-		ret = intel_punit_ipc_command(
-				IPC_PUNIT_BIOS_READ_TELE_TRACE_CTRL,
-				0, 0, NULL, &temp);
+		ret = telem_punit_cmd(punit_ipc_dev,
+				      IPC_PUNIT_BIOS_READ_TELE_TRACE_CTRL, 0,
+				      NULL, &temp);
 		if (ret) {
 			pr_err("PSS TRACE_CTRL Read Failed\n");
 			goto out;
@@ -1074,10 +1097,9 @@ static int telemetry_plt_set_trace_verbosity(enum telemetry_unit telem_unit,
 
 		TELEM_CLEAR_VERBOSITY_BITS(temp);
 		TELEM_SET_VERBOSITY_BITS(temp, verbosity);
-
-		ret = intel_punit_ipc_command(
-				IPC_PUNIT_BIOS_WRITE_TELE_TRACE_CTRL,
-				0, 0, &temp, NULL);
+		ret = telem_punit_cmd(punit_ipc_dev,
+				      IPC_PUNIT_BIOS_WRITE_TELE_EVENT_CTRL, 0,
+				      &temp, NULL);
 		if (ret) {
 			pr_err("PSS TRACE_CTRL Verbosity Set Failed\n");
 			goto out;
@@ -1139,6 +1161,10 @@ static int telemetry_pltdrv_probe(struct platform_device *pdev)
 	if (!id)
 		return -ENODEV;
 
+	punit_ipc_dev = intel_ipc_dev_get(PUNIT_BIOS_IPC_DEV);
+	if (IS_ERR_OR_NULL(punit_ipc_dev))
+		return PTR_ERR(punit_ipc_dev);
+
 	telm_conf = (struct telemetry_plt_config *)id->driver_data;
 
 	res0 = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -1218,6 +1244,7 @@ static int telemetry_pltdrv_probe(struct platform_device *pdev)
 static int telemetry_pltdrv_remove(struct platform_device *pdev)
 {
 	telemetry_clear_pltdata();
+	intel_ipc_dev_put(punit_ipc_dev);
 	iounmap(telm_conf->pss_config.regmap);
 	iounmap(telm_conf->ioss_config.regmap);
 
-- 
2.7.4

--
To unsubscribe from this list: send the line "unsubscribe linux-watchdog" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [RFC v8 6/7] platform/x86: intel_pmc_ipc: Use generic Intel IPC device calls
  2017-10-29  9:49 ` sathyanarayanan.kuppuswamy
@ 2017-10-29  9:49   ` sathyanarayanan.kuppuswamy
  -1 siblings, 0 replies; 30+ messages in thread
From: sathyanarayanan.kuppuswamy @ 2017-10-29  9:49 UTC (permalink / raw)
  To: a.zummo, x86, wim, mingo, alexandre.belloni, qipeng.zha, hpa,
	dvhart, tglx, lee.jones, andy, souvik.k.chakravarty
  Cc: linux-rtc, linux-watchdog, linux-kernel, platform-driver-x86,
	sathyaosid, Kuppuswamy Sathyanarayanan

From: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>

Removed redundant IPC helper functions and refactored the driver to use
generic IPC device driver APIs. Also, cleaned up the driver to minimize
the usage of global variable ipcdev by propogating the struct
intel_pmc_ipc_dev pointer or by getting it from device private data.

This patch also cleans-up PMC IPC user drivers(intel_telemetry_pltdrv.c,
intel_soc_pmic_bxtwc.c) to use APIs provided by generic IPC driver.

Signed-off-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>
Acked-by: Lee Jones <lee.jones@linaro.org>
---
 arch/x86/include/asm/intel_pmc_ipc.h          |  31 +--
 drivers/mfd/intel_soc_pmic_bxtwc.c            |  37 ++-
 drivers/platform/x86/intel_pmc_ipc.c          | 382 ++++++++++----------------
 drivers/platform/x86/intel_telemetry_pltdrv.c | 128 ++++-----
 include/linux/mfd/intel_soc_pmic.h            |   2 +
 5 files changed, 247 insertions(+), 333 deletions(-)

Changes since v7:
 * Fixed style issues.

Changes since v6:
 * Fixed some style and rebase issues.

Changes since v5:
 * Adapted to change in arguments of ipc_dev_cmd() and ipc_dev_raw_cmd() APIs.

Changes since v4:
 * None

Changes since v3:
 * Added unique name to PMC regmaps.
 * Added support to clear interrupt bit.
 * Added intel_ipc_dev_put() support.

Changes since v1:
 * Removed custom APIs.
 * Cleaned up PMC IPC user drivers to use APIs provided by generic
   IPC driver.

diff --git a/arch/x86/include/asm/intel_pmc_ipc.h b/arch/x86/include/asm/intel_pmc_ipc.h
index fac89eb..ca2f5e3 100644
--- a/arch/x86/include/asm/intel_pmc_ipc.h
+++ b/arch/x86/include/asm/intel_pmc_ipc.h
@@ -1,10 +1,15 @@
 #ifndef _ASM_X86_INTEL_PMC_IPC_H_
 #define  _ASM_X86_INTEL_PMC_IPC_H_
 
+#include <linux/platform_data/x86/intel_ipc_dev.h>
+
+#define INTEL_PMC_IPC_DEV		"intel_pmc_ipc"
+#define PMC_PARAM_LEN			2
+
 /* Commands */
 #define PMC_IPC_PMIC_ACCESS		0xFF
-#define		PMC_IPC_PMIC_ACCESS_READ	0x0
-#define		PMC_IPC_PMIC_ACCESS_WRITE	0x1
+#define	PMC_IPC_PMIC_ACCESS_READ	0x0
+#define	PMC_IPC_PMIC_ACCESS_WRITE	0x1
 #define PMC_IPC_USB_PWR_CTRL		0xF0
 #define PMC_IPC_PMIC_BLACKLIST_SEL	0xEF
 #define PMC_IPC_PHY_CONFIG		0xEE
@@ -30,11 +35,6 @@
 
 #if IS_ENABLED(CONFIG_INTEL_PMC_IPC)
 
-int intel_pmc_ipc_simple_command(int cmd, int sub);
-int intel_pmc_ipc_raw_cmd(u32 cmd, u32 sub, u8 *in, u32 inlen,
-		u32 *out, u32 outlen, u32 dptr, u32 sptr);
-int intel_pmc_ipc_command(u32 cmd, u32 sub, u8 *in, u32 inlen,
-		u32 *out, u32 outlen);
 int intel_pmc_s0ix_counter_read(u64 *data);
 int intel_pmc_gcr_read(u32 offset, u32 *data);
 int intel_pmc_gcr_write(u32 offset, u32 data);
@@ -42,23 +42,6 @@ int intel_pmc_gcr_update(u32 offset, u32 mask, u32 val);
 
 #else
 
-static inline int intel_pmc_ipc_simple_command(int cmd, int sub)
-{
-	return -EINVAL;
-}
-
-static inline int intel_pmc_ipc_raw_cmd(u32 cmd, u32 sub, u8 *in, u32 inlen,
-		u32 *out, u32 outlen, u32 dptr, u32 sptr)
-{
-	return -EINVAL;
-}
-
-static inline int intel_pmc_ipc_command(u32 cmd, u32 sub, u8 *in, u32 inlen,
-		u32 *out, u32 outlen)
-{
-	return -EINVAL;
-}
-
 static inline int intel_pmc_s0ix_counter_read(u64 *data)
 {
 	return -EINVAL;
diff --git a/drivers/mfd/intel_soc_pmic_bxtwc.c b/drivers/mfd/intel_soc_pmic_bxtwc.c
index 15bc052..55ffcae 100644
--- a/drivers/mfd/intel_soc_pmic_bxtwc.c
+++ b/drivers/mfd/intel_soc_pmic_bxtwc.c
@@ -271,6 +271,9 @@ static int regmap_ipc_byte_reg_read(void *context, unsigned int reg,
 	u8 ipc_in[2];
 	u8 ipc_out[4];
 	struct intel_soc_pmic *pmic = context;
+	struct intel_ipc_raw_cmd ipc_raw_cmd;
+	u32 cmd[PMC_PARAM_LEN] = {PMC_IPC_PMIC_ACCESS,
+		PMC_IPC_PMIC_ACCESS_READ};
 
 	if (!pmic)
 		return -EINVAL;
@@ -284,9 +287,15 @@ static int regmap_ipc_byte_reg_read(void *context, unsigned int reg,
 
 	ipc_in[0] = reg;
 	ipc_in[1] = i2c_addr;
-	ret = intel_pmc_ipc_command(PMC_IPC_PMIC_ACCESS,
-			PMC_IPC_PMIC_ACCESS_READ,
-			ipc_in, sizeof(ipc_in), (u32 *)ipc_out, 1);
+
+	ipc_raw_cmd.cmd_list = cmd;
+	ipc_raw_cmd.cmdlen = PMC_PARAM_LEN;
+	ipc_raw_cmd.in = ipc_in;
+	ipc_raw_cmd.inlen = sizeof(ipc_in);
+	ipc_raw_cmd.out = (u32 *)ipc_out;
+	ipc_raw_cmd.outlen = 1;
+
+	ret = ipc_dev_raw_cmd(pmic->ipc_dev, &ipc_raw_cmd);
 	if (ret) {
 		dev_err(pmic->dev, "Failed to read from PMIC\n");
 		return ret;
@@ -303,6 +312,9 @@ static int regmap_ipc_byte_reg_write(void *context, unsigned int reg,
 	int i2c_addr;
 	u8 ipc_in[3];
 	struct intel_soc_pmic *pmic = context;
+	struct intel_ipc_raw_cmd ipc_raw_cmd;
+	u32 cmd[PMC_PARAM_LEN] = {PMC_IPC_PMIC_ACCESS,
+		PMC_IPC_PMIC_ACCESS_WRITE};
 
 	if (!pmic)
 		return -EINVAL;
@@ -317,9 +329,15 @@ static int regmap_ipc_byte_reg_write(void *context, unsigned int reg,
 	ipc_in[0] = reg;
 	ipc_in[1] = i2c_addr;
 	ipc_in[2] = val;
-	ret = intel_pmc_ipc_command(PMC_IPC_PMIC_ACCESS,
-			PMC_IPC_PMIC_ACCESS_WRITE,
-			ipc_in, sizeof(ipc_in), NULL, 0);
+
+	ipc_raw_cmd.cmd_list = cmd;
+	ipc_raw_cmd.cmdlen = PMC_PARAM_LEN;
+	ipc_raw_cmd.in = ipc_in;
+	ipc_raw_cmd.inlen = sizeof(ipc_in);
+	ipc_raw_cmd.out = NULL;
+	ipc_raw_cmd.outlen = 0;
+
+	ret = ipc_dev_raw_cmd(pmic->ipc_dev, &ipc_raw_cmd);
 	if (ret) {
 		dev_err(pmic->dev, "Failed to write to PMIC\n");
 		return ret;
@@ -445,6 +463,10 @@ static int bxtwc_probe(struct platform_device *pdev)
 	if (!pmic)
 		return -ENOMEM;
 
+	pmic->ipc_dev = intel_ipc_dev_get(INTEL_PMC_IPC_DEV);
+	if (IS_ERR_OR_NULL(pmic->ipc_dev))
+		return PTR_ERR(pmic->ipc_dev);
+
 	ret = platform_get_irq(pdev, 0);
 	if (ret < 0) {
 		dev_err(&pdev->dev, "Invalid IRQ\n");
@@ -562,7 +584,10 @@ static int bxtwc_probe(struct platform_device *pdev)
 
 static int bxtwc_remove(struct platform_device *pdev)
 {
+	struct intel_soc_pmic *pmic = dev_get_drvdata(&pdev->dev);
+
 	sysfs_remove_group(&pdev->dev.kobj, &bxtwc_group);
+	intel_ipc_dev_put(pmic->ipc_dev);
 
 	return 0;
 }
diff --git a/drivers/platform/x86/intel_pmc_ipc.c b/drivers/platform/x86/intel_pmc_ipc.c
index df6af1f..7d6a82d 100644
--- a/drivers/platform/x86/intel_pmc_ipc.c
+++ b/drivers/platform/x86/intel_pmc_ipc.c
@@ -48,18 +48,8 @@
  * The ARC handles the interrupt and services it, writing optional data to
  * the IPC1 registers, updates the IPC_STS response register with the status.
  */
-#define IPC_CMD			0x0
-#define		IPC_CMD_MSI		0x100
 #define		IPC_CMD_SIZE		16
 #define		IPC_CMD_SUBCMD		12
-#define IPC_STATUS		0x04
-#define		IPC_STATUS_IRQ		0x4
-#define		IPC_STATUS_ERR		0x2
-#define		IPC_STATUS_BUSY		0x1
-#define IPC_SPTR		0x08
-#define IPC_DPTR		0x0C
-#define IPC_WRITE_BUFFER	0x80
-#define IPC_READ_BUFFER		0x90
 
 /* Residency with clock rate at 19.2MHz to usecs */
 #define S0IX_RESIDENCY_IN_USECS(d, s)		\
@@ -74,11 +64,6 @@
  */
 #define IPC_DATA_BUFFER_SIZE	16
 
-#define IPC_LOOP_CNT		3000000
-#define IPC_MAX_SEC		3
-
-#define IPC_TRIGGER_MODE_IRQ		true
-
 /* exported resources from IFWI */
 #define PLAT_RESOURCE_IPC_INDEX		0
 #define PLAT_RESOURCE_IPC_SIZE		0x1000
@@ -118,36 +103,41 @@
 #define PMC_CFG_NO_REBOOT_EN		(1 << 4)
 #define PMC_CFG_NO_REBOOT_DIS		(0 << 4)
 
+/* IPC PMC commands */
+#define	IPC_DEV_PMC_CMD_MSI			BIT(8)
+#define	IPC_DEV_PMC_CMD_SIZE			16
+#define	IPC_DEV_PMC_CMD_SUBCMD			12
+#define	IPC_DEV_PMC_CMD_STATUS			BIT(2)
+#define	IPC_DEV_PMC_CMD_STATUS_IRQ		BIT(2)
+#define	IPC_DEV_PMC_CMD_STATUS_ERR		BIT(1)
+#define	IPC_DEV_PMC_CMD_STATUS_ERR_MASK		GENMASK(7, 0)
+#define	IPC_DEV_PMC_CMD_STATUS_BUSY		BIT(0)
+
+/*IPC PMC reg offsets */
+#define IPC_DEV_PMC_STATUS_OFFSET		0x04
+#define IPC_DEV_PMC_SPTR_OFFSET			0x08
+#define IPC_DEV_PMC_DPTR_OFFSET			0x0C
+#define IPC_DEV_PMC_WRBUF_OFFSET		0x80
+#define IPC_DEV_PMC_RBUF_OFFSET			0x90
+
 static struct intel_pmc_ipc_dev {
 	struct device *dev;
+	struct intel_ipc_dev *pmc_ipc_dev;
+	struct intel_ipc_dev_ops ops;
+	struct intel_ipc_dev_cfg cfg;
 	void __iomem *ipc_base;
-	bool irq_mode;
-	int irq;
-	int cmd;
-	struct completion cmd_complete;
 
 	/* gcr */
 	void __iomem *gcr_mem_base;
 	struct regmap *gcr_regs;
 } ipcdev;
 
-static char *ipc_err_sources[] = {
-	[IPC_ERR_NONE] =
-		"no error",
-	[IPC_ERR_CMD_NOT_SUPPORTED] =
-		"command not supported",
-	[IPC_ERR_CMD_NOT_SERVICED] =
-		"command not serviced",
-	[IPC_ERR_UNABLE_TO_SERVICE] =
-		"unable to service",
-	[IPC_ERR_CMD_INVALID] =
-		"command invalid",
-	[IPC_ERR_CMD_FAILED] =
-		"command failed",
-	[IPC_ERR_EMSECURITY] =
-		"Invalid Battery",
-	[IPC_ERR_UNSIGNEDKERNEL] =
-		"Unsigned kernel",
+static struct regmap_config pmc_regmap_config = {
+	.name = "intel_pmc_regs",
+	.reg_bits = 32,
+	.reg_stride = 4,
+	.val_bits = 32,
+	.fast_io = true,
 };
 
 static struct regmap_config gcr_regmap_config = {
@@ -159,40 +149,6 @@ static struct regmap_config gcr_regmap_config = {
 	.max_register = PLAT_RESOURCE_GCR_SIZE,
 };
 
-/* Prevent concurrent calls to the PMC */
-static DEFINE_MUTEX(ipclock);
-
-static inline void ipc_send_command(u32 cmd)
-{
-	ipcdev.cmd = cmd;
-	if (ipcdev.irq_mode) {
-		reinit_completion(&ipcdev.cmd_complete);
-		cmd |= IPC_CMD_MSI;
-	}
-	writel(cmd, ipcdev.ipc_base + IPC_CMD);
-}
-
-static inline u32 ipc_read_status(void)
-{
-	return readl(ipcdev.ipc_base + IPC_STATUS);
-}
-
-static inline void ipc_data_writel(u32 data, u32 offset)
-{
-	writel(data, ipcdev.ipc_base + IPC_WRITE_BUFFER + offset);
-}
-
-static inline u8 __maybe_unused ipc_data_readb(u32 offset)
-{
-	return readb(ipcdev.ipc_base + IPC_READ_BUFFER + offset);
-}
-
-static inline u32 ipc_data_readl(u32 offset)
-{
-	return readl(ipcdev.ipc_base + IPC_READ_BUFFER + offset);
-}
-
-
 /**
  * intel_pmc_gcr_read() - Read PMC GCR register
  * @offset:	offset of GCR register from GCR address base
@@ -264,160 +220,109 @@ static int update_no_reboot_bit(void *priv, bool set)
 				    PMC_CFG_NO_REBOOT_MASK, value);
 }
 
-static int intel_pmc_ipc_check_status(void)
+static int pre_simple_cmd_fn(u32 *cmd_list, u32 cmdlen)
 {
-	int status;
-	int ret = 0;
-
-	if (ipcdev.irq_mode) {
-		if (0 == wait_for_completion_timeout(
-				&ipcdev.cmd_complete, IPC_MAX_SEC * HZ))
-			ret = -ETIMEDOUT;
-	} else {
-		int loop_count = IPC_LOOP_CNT;
-
-		while ((ipc_read_status() & IPC_STATUS_BUSY) && --loop_count)
-			udelay(1);
-		if (loop_count == 0)
-			ret = -ETIMEDOUT;
-	}
-
-	status = ipc_read_status();
-	if (ret == -ETIMEDOUT) {
-		dev_err(ipcdev.dev,
-			"IPC timed out, TS=0x%x, CMD=0x%x\n",
-			status, ipcdev.cmd);
-		return ret;
-	}
+	if (!cmd_list || cmdlen != PMC_PARAM_LEN)
+		return -EINVAL;
 
-	if (status & IPC_STATUS_ERR) {
-		int i;
-
-		ret = -EIO;
-		i = (status >> IPC_CMD_SIZE) & 0xFF;
-		if (i < ARRAY_SIZE(ipc_err_sources))
-			dev_err(ipcdev.dev,
-				"IPC failed: %s, STS=0x%x, CMD=0x%x\n",
-				ipc_err_sources[i], status, ipcdev.cmd);
-		else
-			dev_err(ipcdev.dev,
-				"IPC failed: unknown, STS=0x%x, CMD=0x%x\n",
-				status, ipcdev.cmd);
-		if ((i == IPC_ERR_UNSIGNEDKERNEL) || (i == IPC_ERR_EMSECURITY))
-			ret = -EACCES;
-	}
+	cmd_list[0] |= (cmd_list[1] << IPC_CMD_SUBCMD);
 
-	return ret;
+	return 0;
 }
 
-/**
- * intel_pmc_ipc_simple_command() - Simple IPC command
- * @cmd:	IPC command code.
- * @sub:	IPC command sub type.
- *
- * Send a simple IPC command to PMC when don't need to specify
- * input/output data and source/dest pointers.
- *
- * Return:	an IPC error code or 0 on success.
- */
-int intel_pmc_ipc_simple_command(int cmd, int sub)
+static int pre_raw_cmd_fn(struct intel_ipc_raw_cmd *ipc_raw_cmd)
 {
 	int ret;
 
-	mutex_lock(&ipclock);
-	if (ipcdev.dev == NULL) {
-		mutex_unlock(&ipclock);
-		return -ENODEV;
-	}
-	ipc_send_command(sub << IPC_CMD_SUBCMD | cmd);
-	ret = intel_pmc_ipc_check_status();
-	mutex_unlock(&ipclock);
+	if (ipc_raw_cmd->inlen > IPC_DATA_BUFFER_SIZE ||
+	    ipc_raw_cmd->outlen > (IPC_DATA_BUFFER_SIZE / 4))
+		return -EINVAL;
 
-	return ret;
-}
-EXPORT_SYMBOL_GPL(intel_pmc_ipc_simple_command);
+	ret = pre_simple_cmd_fn(ipc_raw_cmd->cmd_list, ipc_raw_cmd->cmdlen);
+	if (ret < 0)
+		return ret;
 
-/**
- * intel_pmc_ipc_raw_cmd() - IPC command with data and pointers
- * @cmd:	IPC command code.
- * @sub:	IPC command sub type.
- * @in:		input data of this IPC command.
- * @inlen:	input data length in bytes.
- * @out:	output data of this IPC command.
- * @outlen:	output data length in dwords.
- * @sptr:	data writing to SPTR register.
- * @dptr:	data writing to DPTR register.
- *
- * Send an IPC command to PMC with input/output data and source/dest pointers.
- *
- * Return:	an IPC error code or 0 on success.
- */
-int intel_pmc_ipc_raw_cmd(u32 cmd, u32 sub, u8 *in, u32 inlen, u32 *out,
-			  u32 outlen, u32 dptr, u32 sptr)
-{
-	u32 wbuf[4] = { 0 };
-	int ret;
-	int i;
+	ipc_raw_cmd->cmd_list[0] |= (ipc_raw_cmd->inlen << IPC_CMD_SIZE);
 
-	if (inlen > IPC_DATA_BUFFER_SIZE || outlen > IPC_DATA_BUFFER_SIZE / 4)
-		return -EINVAL;
+	return 0;
+}
 
-	mutex_lock(&ipclock);
-	if (ipcdev.dev == NULL) {
-		mutex_unlock(&ipclock);
-		return -ENODEV;
-	}
-	memcpy(wbuf, in, inlen);
-	writel(dptr, ipcdev.ipc_base + IPC_DPTR);
-	writel(sptr, ipcdev.ipc_base + IPC_SPTR);
-	/* The input data register is 32bit register and inlen is in Byte */
-	for (i = 0; i < ((inlen + 3) / 4); i++)
-		ipc_data_writel(wbuf[i], 4 * i);
-	ipc_send_command((inlen << IPC_CMD_SIZE) |
-			(sub << IPC_CMD_SUBCMD) | cmd);
-	ret = intel_pmc_ipc_check_status();
-	if (!ret) {
-		/* out is read from 32bit register and outlen is in 32bit */
-		for (i = 0; i < outlen; i++)
-			*out++ = ipc_data_readl(4 * i);
-	}
-	mutex_unlock(&ipclock);
+static int pre_irq_handler_fn(struct intel_ipc_dev *ipc_dev, int irq)
+{
+	return regmap_write_bits(ipc_dev->cfg->cmd_regs,
+				 ipc_dev->cfg->status_reg,
+				 IPC_DEV_PMC_CMD_STATUS_IRQ,
+				 IPC_DEV_PMC_CMD_STATUS_IRQ);
+}
 
-	return ret;
+static int pmc_ipc_err_code(int status)
+{
+	return ((status >> IPC_DEV_PMC_CMD_SIZE) &
+		IPC_DEV_PMC_CMD_STATUS_ERR_MASK);
 }
-EXPORT_SYMBOL_GPL(intel_pmc_ipc_raw_cmd);
 
-/**
- * intel_pmc_ipc_command() -  IPC command with input/output data
- * @cmd:	IPC command code.
- * @sub:	IPC command sub type.
- * @in:		input data of this IPC command.
- * @inlen:	input data length in bytes.
- * @out:	output data of this IPC command.
- * @outlen:	output data length in dwords.
- *
- * Send an IPC command to PMC with input/output data.
- *
- * Return:	an IPC error code or 0 on success.
- */
-int intel_pmc_ipc_command(u32 cmd, u32 sub, u8 *in, u32 inlen,
-			  u32 *out, u32 outlen)
+static int pmc_ipc_busy_check(int status)
 {
-	return intel_pmc_ipc_raw_cmd(cmd, sub, in, inlen, out, outlen, 0, 0);
+	return status | IPC_DEV_PMC_CMD_STATUS_BUSY;
 }
-EXPORT_SYMBOL_GPL(intel_pmc_ipc_command);
 
-static irqreturn_t ioc(int irq, void *dev_id)
+static u32 pmc_ipc_enable_msi(u32 cmd)
 {
-	int status;
+	return cmd | IPC_DEV_PMC_CMD_MSI;
+}
 
-	if (ipcdev.irq_mode) {
-		status = ipc_read_status();
-		writel(status | IPC_STATUS_IRQ, ipcdev.ipc_base + IPC_STATUS);
+static struct intel_ipc_dev *intel_pmc_ipc_dev_create(
+		struct device *pmc_dev,
+		void __iomem *base,
+		int irq)
+{
+	struct intel_ipc_dev_ops *ops;
+	struct intel_ipc_dev_cfg *cfg;
+	struct regmap *cmd_regs;
+
+	cfg = devm_kzalloc(pmc_dev, sizeof(*cfg), GFP_KERNEL);
+	if (!cfg)
+		return ERR_PTR(-ENOMEM);
+
+	ops = devm_kzalloc(pmc_dev, sizeof(*ops), GFP_KERNEL);
+	if (!ops)
+		return ERR_PTR(-ENOMEM);
+
+	cmd_regs = devm_regmap_init_mmio_clk(pmc_dev, NULL, base,
+					     &pmc_regmap_config);
+	if (IS_ERR(cmd_regs)) {
+		dev_err(pmc_dev, "cmd_regs regmap init failed\n");
+		return ERR_CAST(cmd_regs);
 	}
-	complete(&ipcdev.cmd_complete);
 
-	return IRQ_HANDLED;
+	/* set IPC dev ops */
+	ops->to_err_code = pmc_ipc_err_code;
+	ops->busy_check = pmc_ipc_busy_check;
+	ops->enable_msi = pmc_ipc_enable_msi;
+	ops->pre_raw_cmd_fn = pre_raw_cmd_fn;
+	ops->pre_simple_cmd_fn = pre_simple_cmd_fn;
+	ops->pre_irq_handler_fn = pre_irq_handler_fn;
+
+	/* set cfg options */
+	if (irq > 0)
+		cfg->mode = IPC_DEV_MODE_IRQ;
+	else
+		cfg->mode = IPC_DEV_MODE_POLLING;
+
+	cfg->chan_type = IPC_CHANNEL_IA_PMC;
+	cfg->irq = irq;
+	cfg->use_msi = true;
+	cfg->support_sptr = true;
+	cfg->support_dptr = true;
+	cfg->cmd_regs = cmd_regs;
+	cfg->data_regs = cmd_regs;
+	cfg->wrbuf_reg = IPC_DEV_PMC_WRBUF_OFFSET;
+	cfg->rbuf_reg = IPC_DEV_PMC_RBUF_OFFSET;
+	cfg->sptr_reg = IPC_DEV_PMC_SPTR_OFFSET;
+	cfg->dptr_reg = IPC_DEV_PMC_DPTR_OFFSET;
+	cfg->status_reg = IPC_DEV_PMC_STATUS_OFFSET;
+
+	return devm_intel_ipc_dev_create(pmc_dev, INTEL_PMC_IPC_DEV, cfg, ops);
 }
 
 static int ipc_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
@@ -429,8 +334,6 @@ static int ipc_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 	if (pmc->dev)
 		return -EBUSY;
 
-	pmc->irq_mode = IPC_TRIGGER_MODE_IRQ;
-
 	ret = pcim_enable_device(pdev);
 	if (ret)
 		return ret;
@@ -439,15 +342,13 @@ static int ipc_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 	if (ret)
 		return ret;
 
-	init_completion(&pmc->cmd_complete);
-
 	pmc->ipc_base = pcim_iomap_table(pdev)[0];
 
-	ret = devm_request_irq(&pdev->dev, pdev->irq, ioc, 0, "intel_pmc_ipc",
-				pmc);
-	if (ret) {
-		dev_err(&pdev->dev, "Failed to request IRQ\n");
-		return ret;
+	pmc->pmc_ipc_dev = intel_pmc_ipc_dev_create(&pdev->dev, pmc->ipc_base,
+						    pdev->irq);
+	if (IS_ERR(pmc->pmc_ipc_dev)) {
+		dev_err(&pdev->dev, "Failed to create PMC IPC device\n");
+		return PTR_ERR(pmc->pmc_ipc_dev);
 	}
 
 	pmc->dev = &pdev->dev;
@@ -475,19 +376,19 @@ static ssize_t intel_pmc_ipc_simple_cmd_store(struct device *dev,
 					      struct device_attribute *attr,
 					      const char *buf, size_t count)
 {
-	int subcmd;
-	int cmd;
+	struct intel_pmc_ipc_dev *pmc = dev_get_drvdata(dev);
+	int cmd[2];
 	int ret;
 
-	ret = sscanf(buf, "%d %d", &cmd, &subcmd);
+	ret = sscanf(buf, "%d %d", &cmd[0], &cmd[2]);
 	if (ret != 2) {
 		dev_err(dev, "Error args\n");
 		return -EINVAL;
 	}
 
-	ret = intel_pmc_ipc_simple_command(cmd, subcmd);
+	ret = ipc_dev_simple_cmd(pmc->pmc_ipc_dev, cmd, 2);
 	if (ret) {
-		dev_err(dev, "command %d error with %d\n", cmd, ret);
+		dev_err(dev, "command %d error with %d\n", cmd[0], ret);
 		return ret;
 	}
 	return (ssize_t)count;
@@ -497,22 +398,23 @@ static ssize_t intel_pmc_ipc_northpeak_store(struct device *dev,
 					     struct device_attribute *attr,
 					     const char *buf, size_t count)
 {
+	struct intel_pmc_ipc_dev *pmc = dev_get_drvdata(dev);
 	unsigned long val;
-	int subcmd;
+	int cmd[2] = {PMC_IPC_NORTHPEAK_CTRL, 0};
 	int ret;
 
 	if (kstrtoul(buf, 0, &val))
 		return -EINVAL;
 
 	if (val)
-		subcmd = 1;
-	else
-		subcmd = 0;
-	ret = intel_pmc_ipc_simple_command(PMC_IPC_NORTHPEAK_CTRL, subcmd);
+		cmd[1] = 1;
+
+	ret = ipc_dev_simple_cmd(pmc->pmc_ipc_dev, cmd, 2);
 	if (ret) {
-		dev_err(dev, "command north %d error with %d\n", subcmd, ret);
+		dev_err(dev, "command north %d error with %d\n", cmd[1], ret);
 		return ret;
 	}
+
 	return (ssize_t)count;
 }
 
@@ -688,6 +590,7 @@ static int ipc_create_pmc_devices(struct platform_device *pdev)
 
 static int ipc_plat_get_res(struct platform_device *pdev)
 {
+	struct intel_pmc_ipc_dev *pmc = dev_get_drvdata(&pdev->dev);
 	struct resource *res;
 	void __iomem *addr;
 
@@ -706,9 +609,9 @@ static int ipc_plat_get_res(struct platform_device *pdev)
 	if (IS_ERR(addr))
 		return PTR_ERR(addr);
 
-	ipcdev.ipc_base = addr;
-	ipcdev.gcr_mem_base = addr + PLAT_RESOURCE_GCR_OFFSET;
-	dev_dbg(&pdev->dev, "PMC IPC resource %pR\n", res);
+	pmc->ipc_base = addr;
+	pmc->gcr_mem_base = addr + PLAT_RESOURCE_GCR_OFFSET;
+	dev_info(&pdev->dev, "PMC IPC resource %pR\n", res);
 
 	return 0;
 }
@@ -754,14 +657,15 @@ MODULE_DEVICE_TABLE(acpi, ipc_acpi_ids);
 
 static int ipc_plat_probe(struct platform_device *pdev)
 {
-	int ret;
+	int ret, irq;
+	struct intel_pmc_ipc_dev *pmc = &ipcdev;
 
-	ipcdev.dev = &pdev->dev;
-	ipcdev.irq_mode = IPC_TRIGGER_MODE_IRQ;
-	init_completion(&ipcdev.cmd_complete);
+	pmc->dev = &pdev->dev;
 
-	ipcdev.irq = platform_get_irq(pdev, 0);
-	if (ipcdev.irq < 0) {
+	dev_set_drvdata(&pdev->dev, pmc);
+
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0) {
 		dev_err(&pdev->dev, "Failed to get IRQ\n");
 		return -EINVAL;
 	}
@@ -786,28 +690,26 @@ static int ipc_plat_probe(struct platform_device *pdev)
 		return ret;
 	}
 
-	ret = devm_request_irq(&pdev->dev, ipcdev.irq, ioc, IRQF_NO_SUSPEND,
-			       "intel_pmc_ipc", &ipcdev);
-	if (ret) {
-		dev_err(&pdev->dev, "Failed to request IRQ\n");
-		return ret;
-	}
-
 	ret = sysfs_create_group(&pdev->dev.kobj, &intel_ipc_group);
 	if (ret) {
 		dev_err(&pdev->dev, "Failed to create sysfs group %d\n",
 			ret);
-		devm_free_irq(&pdev->dev, ipcdev.irq, &ipcdev);
 		return ret;
 	}
 
+	ipcdev.pmc_ipc_dev = intel_pmc_ipc_dev_create(&pdev->dev,
+			pmc->ipc_base, irq);
+	if (IS_ERR(pmc->pmc_ipc_dev)) {
+		dev_err(&pdev->dev, "Failed to create PMC IPC device\n");
+		return PTR_ERR(pmc->pmc_ipc_dev);
+	}
+
 	return 0;
 }
 
 static int ipc_plat_remove(struct platform_device *pdev)
 {
 	sysfs_remove_group(&pdev->dev.kobj, &intel_ipc_group);
-	devm_free_irq(&pdev->dev, ipcdev.irq, &ipcdev);
 	ipcdev.dev = NULL;
 
 	return 0;
diff --git a/drivers/platform/x86/intel_telemetry_pltdrv.c b/drivers/platform/x86/intel_telemetry_pltdrv.c
index 0dbd7be..74868bb 100644
--- a/drivers/platform/x86/intel_telemetry_pltdrv.c
+++ b/drivers/platform/x86/intel_telemetry_pltdrv.c
@@ -56,10 +56,6 @@
 #define IOSS_TELEM_TRACE_CTL_WRITE	0x6
 #define IOSS_TELEM_EVENT_CTL_READ	0x7
 #define IOSS_TELEM_EVENT_CTL_WRITE	0x8
-#define IOSS_TELEM_EVT_CTRL_WRITE_SIZE	0x4
-#define IOSS_TELEM_READ_WORD		0x1
-#define IOSS_TELEM_WRITE_FOURBYTES	0x4
-#define IOSS_TELEM_EVT_WRITE_SIZE	0x3
 
 #define TELEM_INFO_SRAMEVTS_MASK	0xFF00
 #define TELEM_INFO_SRAMEVTS_SHIFT	0x8
@@ -98,7 +94,7 @@ struct telem_ssram_region {
 };
 
 static struct telemetry_plt_config *telm_conf;
-static struct intel_ipc_dev *punit_ipc_dev;
+static struct intel_ipc_dev *punit_ipc_dev, *pmc_ipc_dev;
 
 /*
  * The following counters are programmed by default during setup.
@@ -226,6 +222,29 @@ static int telem_punit_cmd(struct intel_ipc_dev *ipc_dev, u32 cmd, u32 sub,
 	return ipc_dev_cmd(ipc_dev, &ipc_cmd);
 }
 
+static int telem_pmc_cmd(struct intel_ipc_dev *ipc_dev, u32 cmd, u32 sub,
+			 u8 *in, u32 *out)
+{
+	struct intel_ipc_raw_cmd ipc_raw_cmd = {0};
+	u32 cmd_list[PMC_PARAM_LEN] = {0};
+
+	cmd_list[0] = cmd;
+	cmd_list[1] = sub;
+
+	ipc_raw_cmd.cmd_list = cmd_list;
+	ipc_raw_cmd.cmdlen = PMC_PARAM_LEN;
+	ipc_raw_cmd.in = in;
+	ipc_raw_cmd.out = out;
+
+	if (in)
+		ipc_raw_cmd.inlen = 4;
+	if (out)
+		ipc_raw_cmd.outlen = 1;
+
+	return ipc_dev_raw_cmd(ipc_dev, &ipc_raw_cmd);
+}
+
+
 static inline int telem_get_unitconfig(enum telemetry_unit telem_unit,
 				     struct telemetry_unit_config **unit_config)
 {
@@ -289,17 +308,13 @@ static int telemetry_check_evtid(enum telemetry_unit telem_unit,
 static inline int telemetry_plt_config_ioss_event(u32 evt_id, int index)
 {
 	u32 write_buf;
-	int ret;
 
 	write_buf = evt_id | TELEM_EVENT_ENABLE;
 	write_buf <<= BITS_PER_BYTE;
 	write_buf |= index;
 
-	ret = intel_pmc_ipc_command(PMC_IPC_PMC_TELEMTRY,
-				    IOSS_TELEM_EVENT_WRITE, (u8 *)&write_buf,
-				    IOSS_TELEM_EVT_WRITE_SIZE, NULL, 0);
-
-	return ret;
+	return telem_pmc_cmd(pmc_ipc_dev, PMC_IPC_PMC_TELEMTRY,
+			     IOSS_TELEM_EVENT_WRITE, (u8 *)&write_buf, NULL);
 }
 
 static inline int telemetry_plt_config_pss_event(u32 evt_id, int index)
@@ -325,9 +340,8 @@ static int telemetry_setup_iossevtconfig(struct telemetry_evtconfig evtconfig,
 	ioss_evtmap = evtconfig.evtmap;
 
 	/* Get telemetry EVENT CTL */
-	ret = intel_pmc_ipc_command(PMC_IPC_PMC_TELEMTRY,
-				    IOSS_TELEM_EVENT_CTL_READ, NULL, 0,
-				    &telem_ctrl, IOSS_TELEM_READ_WORD);
+	ret = telem_pmc_cmd(pmc_ipc_dev, PMC_IPC_PMC_TELEMTRY,
+			    IOSS_TELEM_EVENT_CTL_READ, NULL, &telem_ctrl);
 	if (ret) {
 		pr_err("IOSS TELEM_CTRL Read Failed\n");
 		return ret;
@@ -335,12 +349,9 @@ static int telemetry_setup_iossevtconfig(struct telemetry_evtconfig evtconfig,
 
 	/* Disable Telemetry */
 	TELEM_DISABLE(telem_ctrl);
-
-	ret = intel_pmc_ipc_command(PMC_IPC_PMC_TELEMTRY,
-				    IOSS_TELEM_EVENT_CTL_WRITE,
-				    (u8 *)&telem_ctrl,
-				    IOSS_TELEM_EVT_CTRL_WRITE_SIZE,
-				    NULL, 0);
+	ret = telem_pmc_cmd(pmc_ipc_dev, PMC_IPC_PMC_TELEMTRY,
+			    IOSS_TELEM_EVENT_CTL_WRITE, (u8 *)&telem_ctrl,
+			    NULL);
 	if (ret) {
 		pr_err("IOSS TELEM_CTRL Event Disable Write Failed\n");
 		return ret;
@@ -351,12 +362,9 @@ static int telemetry_setup_iossevtconfig(struct telemetry_evtconfig evtconfig,
 	if (action == TELEM_RESET) {
 		/* Clear All Events */
 		TELEM_CLEAR_EVENTS(telem_ctrl);
-
-		ret = intel_pmc_ipc_command(PMC_IPC_PMC_TELEMTRY,
-					    IOSS_TELEM_EVENT_CTL_WRITE,
-					    (u8 *)&telem_ctrl,
-					    IOSS_TELEM_EVT_CTRL_WRITE_SIZE,
-					    NULL, 0);
+		ret = telem_pmc_cmd(pmc_ipc_dev, PMC_IPC_PMC_TELEMTRY,
+				    IOSS_TELEM_EVENT_CTL_WRITE,
+				    (u8 *)&telem_ctrl, NULL);
 		if (ret) {
 			pr_err("IOSS TELEM_CTRL Event Disable Write Failed\n");
 			return ret;
@@ -380,12 +388,9 @@ static int telemetry_setup_iossevtconfig(struct telemetry_evtconfig evtconfig,
 	if (action == TELEM_UPDATE) {
 		/* Clear All Events */
 		TELEM_CLEAR_EVENTS(telem_ctrl);
-
-		ret = intel_pmc_ipc_command(PMC_IPC_PMC_TELEMTRY,
-					    IOSS_TELEM_EVENT_CTL_WRITE,
-					    (u8 *)&telem_ctrl,
-					    IOSS_TELEM_EVT_CTRL_WRITE_SIZE,
-					    NULL, 0);
+		ret = telem_pmc_cmd(pmc_ipc_dev, PMC_IPC_PMC_TELEMTRY,
+				    IOSS_TELEM_EVENT_CTL_WRITE,
+				    (u8 *)&telem_ctrl, NULL);
 		if (ret) {
 			pr_err("IOSS TELEM_CTRL Event Disable Write Failed\n");
 			return ret;
@@ -432,11 +437,9 @@ static int telemetry_setup_iossevtconfig(struct telemetry_evtconfig evtconfig,
 	TELEM_ENABLE_SRAM_EVT_TRACE(telem_ctrl);
 	TELEM_ENABLE_PERIODIC(telem_ctrl);
 	telem_ctrl |= ioss_period;
-
-	ret = intel_pmc_ipc_command(PMC_IPC_PMC_TELEMTRY,
-				    IOSS_TELEM_EVENT_CTL_WRITE,
-				    (u8 *)&telem_ctrl,
-				    IOSS_TELEM_EVT_CTRL_WRITE_SIZE, NULL, 0);
+	ret = telem_pmc_cmd(pmc_ipc_dev, PMC_IPC_PMC_TELEMTRY,
+			    IOSS_TELEM_EVENT_CTL_WRITE, (u8 *)&telem_ctrl,
+			    NULL);
 	if (ret) {
 		pr_err("IOSS TELEM_CTRL Event Enable Write Failed\n");
 		return ret;
@@ -626,8 +629,8 @@ static int telemetry_setup(struct platform_device *pdev)
 	u32 read_buf, events, event_regs;
 	int ret;
 
-	ret = intel_pmc_ipc_command(PMC_IPC_PMC_TELEMTRY, IOSS_TELEM_INFO_READ,
-				    NULL, 0, &read_buf, IOSS_TELEM_READ_WORD);
+	ret = telem_pmc_cmd(pmc_ipc_dev, PMC_IPC_PMC_TELEMTRY,
+			    IOSS_TELEM_INFO_READ, NULL, &read_buf);
 	if (ret) {
 		dev_err(&pdev->dev, "IOSS TELEM_INFO Read Failed\n");
 		return ret;
@@ -728,9 +731,9 @@ static int telemetry_plt_set_sampling_period(u8 pss_period, u8 ioss_period)
 		}
 
 		/* Get telemetry EVENT CTL */
-		ret = intel_pmc_ipc_command(PMC_IPC_PMC_TELEMTRY,
-					    IOSS_TELEM_EVENT_CTL_READ, NULL, 0,
-					    &telem_ctrl, IOSS_TELEM_READ_WORD);
+		ret = telem_pmc_cmd(pmc_ipc_dev, PMC_IPC_PMC_TELEMTRY,
+				    IOSS_TELEM_EVENT_CTL_READ, NULL,
+				    &telem_ctrl);
 		if (ret) {
 			pr_err("IOSS TELEM_CTRL Read Failed\n");
 			goto out;
@@ -738,12 +741,9 @@ static int telemetry_plt_set_sampling_period(u8 pss_period, u8 ioss_period)
 
 		/* Disable Telemetry */
 		TELEM_DISABLE(telem_ctrl);
-
-		ret = intel_pmc_ipc_command(PMC_IPC_PMC_TELEMTRY,
-					    IOSS_TELEM_EVENT_CTL_WRITE,
-					    (u8 *)&telem_ctrl,
-					    IOSS_TELEM_EVT_CTRL_WRITE_SIZE,
-					    NULL, 0);
+		ret = telem_pmc_cmd(pmc_ipc_dev, PMC_IPC_PMC_TELEMTRY,
+				    IOSS_TELEM_EVENT_CTL_WRITE,
+				    (u8 *)&telem_ctrl, NULL);
 		if (ret) {
 			pr_err("IOSS TELEM_CTRL Event Disable Write Failed\n");
 			goto out;
@@ -755,11 +755,9 @@ static int telemetry_plt_set_sampling_period(u8 pss_period, u8 ioss_period)
 		TELEM_ENABLE_PERIODIC(telem_ctrl);
 		telem_ctrl |= ioss_period;
 
-		ret = intel_pmc_ipc_command(PMC_IPC_PMC_TELEMTRY,
-					    IOSS_TELEM_EVENT_CTL_WRITE,
-					    (u8 *)&telem_ctrl,
-					    IOSS_TELEM_EVT_CTRL_WRITE_SIZE,
-					    NULL, 0);
+		ret = telem_pmc_cmd(pmc_ipc_dev, PMC_IPC_PMC_TELEMTRY,
+				    IOSS_TELEM_EVENT_CTL_WRITE,
+				    (u8 *)&telem_ctrl, NULL);
 		if (ret) {
 			pr_err("IOSS TELEM_CTRL Event Enable Write Failed\n");
 			goto out;
@@ -1054,9 +1052,9 @@ static int telemetry_plt_get_trace_verbosity(enum telemetry_unit telem_unit,
 		break;
 
 	case TELEM_IOSS:
-		ret = intel_pmc_ipc_command(PMC_IPC_PMC_TELEMTRY,
-				IOSS_TELEM_TRACE_CTL_READ, NULL, 0, &temp,
-				IOSS_TELEM_READ_WORD);
+		ret = telem_pmc_cmd(pmc_ipc_dev, PMC_IPC_PMC_TELEMTRY,
+				    IOSS_TELEM_TRACE_CTL_READ,
+				    NULL, &temp);
 		if (ret) {
 			pr_err("IOSS TRACE_CTL Read Failed\n");
 			goto out;
@@ -1107,9 +1105,9 @@ static int telemetry_plt_set_trace_verbosity(enum telemetry_unit telem_unit,
 		break;
 
 	case TELEM_IOSS:
-		ret = intel_pmc_ipc_command(PMC_IPC_PMC_TELEMTRY,
-				IOSS_TELEM_TRACE_CTL_READ, NULL, 0, &temp,
-				IOSS_TELEM_READ_WORD);
+		ret = telem_pmc_cmd(pmc_ipc_dev, PMC_IPC_PMC_TELEMTRY,
+				    IOSS_TELEM_TRACE_CTL_READ,
+				    NULL, &temp);
 		if (ret) {
 			pr_err("IOSS TRACE_CTL Read Failed\n");
 			goto out;
@@ -1117,10 +1115,9 @@ static int telemetry_plt_set_trace_verbosity(enum telemetry_unit telem_unit,
 
 		TELEM_CLEAR_VERBOSITY_BITS(temp);
 		TELEM_SET_VERBOSITY_BITS(temp, verbosity);
-
-		ret = intel_pmc_ipc_command(PMC_IPC_PMC_TELEMTRY,
-				IOSS_TELEM_TRACE_CTL_WRITE, (u8 *)&temp,
-				IOSS_TELEM_WRITE_FOURBYTES, NULL, 0);
+		ret = telem_pmc_cmd(pmc_ipc_dev, PMC_IPC_PMC_TELEMTRY,
+				    IOSS_TELEM_TRACE_CTL_WRITE,
+				    (u8 *)&temp, NULL);
 		if (ret) {
 			pr_err("IOSS TRACE_CTL Verbosity Set Failed\n");
 			goto out;
@@ -1165,6 +1162,10 @@ static int telemetry_pltdrv_probe(struct platform_device *pdev)
 	if (IS_ERR_OR_NULL(punit_ipc_dev))
 		return PTR_ERR(punit_ipc_dev);
 
+	pmc_ipc_dev = intel_ipc_dev_get(INTEL_PMC_IPC_DEV);
+	if (IS_ERR_OR_NULL(pmc_ipc_dev))
+		return PTR_ERR(pmc_ipc_dev);
+
 	telm_conf = (struct telemetry_plt_config *)id->driver_data;
 
 	res0 = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -1244,6 +1245,7 @@ static int telemetry_pltdrv_probe(struct platform_device *pdev)
 static int telemetry_pltdrv_remove(struct platform_device *pdev)
 {
 	telemetry_clear_pltdata();
+	intel_ipc_dev_put(pmc_ipc_dev);
 	intel_ipc_dev_put(punit_ipc_dev);
 	iounmap(telm_conf->pss_config.regmap);
 	iounmap(telm_conf->ioss_config.regmap);
diff --git a/include/linux/mfd/intel_soc_pmic.h b/include/linux/mfd/intel_soc_pmic.h
index 5aacdb0..7cc39b6 100644
--- a/include/linux/mfd/intel_soc_pmic.h
+++ b/include/linux/mfd/intel_soc_pmic.h
@@ -20,6 +20,7 @@
 #define __INTEL_SOC_PMIC_H__
 
 #include <linux/regmap.h>
+#include <linux/platform_data/x86/intel_ipc_dev.h>
 
 struct intel_soc_pmic {
 	int irq;
@@ -31,6 +32,7 @@ struct intel_soc_pmic {
 	struct regmap_irq_chip_data *irq_chip_data_chgr;
 	struct regmap_irq_chip_data *irq_chip_data_crit;
 	struct device *dev;
+	struct intel_ipc_dev *ipc_dev;
 };
 
 #endif	/* __INTEL_SOC_PMIC_H__ */
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [RFC v8 6/7] platform/x86: intel_pmc_ipc: Use generic Intel IPC device calls
@ 2017-10-29  9:49   ` sathyanarayanan.kuppuswamy
  0 siblings, 0 replies; 30+ messages in thread
From: sathyanarayanan.kuppuswamy @ 2017-10-29  9:49 UTC (permalink / raw)
  To: a.zummo, x86, wim, mingo, alexandre.belloni, qipeng.zha, hpa,
	dvhart, tglx, lee.jones, andy, souvik.k.chakravarty
  Cc: linux-rtc, linux-watchdog, linux-kernel, platform-driver-x86,
	sathyaosid, Kuppuswamy Sathyanarayanan

From: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>

Removed redundant IPC helper functions and refactored the driver to use
generic IPC device driver APIs. Also, cleaned up the driver to minimize
the usage of global variable ipcdev by propogating the struct
intel_pmc_ipc_dev pointer or by getting it from device private data.

This patch also cleans-up PMC IPC user drivers(intel_telemetry_pltdrv.c,
intel_soc_pmic_bxtwc.c) to use APIs provided by generic IPC driver.

Signed-off-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>
Acked-by: Lee Jones <lee.jones@linaro.org>
---
 arch/x86/include/asm/intel_pmc_ipc.h          |  31 +--
 drivers/mfd/intel_soc_pmic_bxtwc.c            |  37 ++-
 drivers/platform/x86/intel_pmc_ipc.c          | 382 ++++++++++----------------
 drivers/platform/x86/intel_telemetry_pltdrv.c | 128 ++++-----
 include/linux/mfd/intel_soc_pmic.h            |   2 +
 5 files changed, 247 insertions(+), 333 deletions(-)

Changes since v7:
 * Fixed style issues.

Changes since v6:
 * Fixed some style and rebase issues.

Changes since v5:
 * Adapted to change in arguments of ipc_dev_cmd() and ipc_dev_raw_cmd() APIs.

Changes since v4:
 * None

Changes since v3:
 * Added unique name to PMC regmaps.
 * Added support to clear interrupt bit.
 * Added intel_ipc_dev_put() support.

Changes since v1:
 * Removed custom APIs.
 * Cleaned up PMC IPC user drivers to use APIs provided by generic
   IPC driver.

diff --git a/arch/x86/include/asm/intel_pmc_ipc.h b/arch/x86/include/asm/intel_pmc_ipc.h
index fac89eb..ca2f5e3 100644
--- a/arch/x86/include/asm/intel_pmc_ipc.h
+++ b/arch/x86/include/asm/intel_pmc_ipc.h
@@ -1,10 +1,15 @@
 #ifndef _ASM_X86_INTEL_PMC_IPC_H_
 #define  _ASM_X86_INTEL_PMC_IPC_H_
 
+#include <linux/platform_data/x86/intel_ipc_dev.h>
+
+#define INTEL_PMC_IPC_DEV		"intel_pmc_ipc"
+#define PMC_PARAM_LEN			2
+
 /* Commands */
 #define PMC_IPC_PMIC_ACCESS		0xFF
-#define		PMC_IPC_PMIC_ACCESS_READ	0x0
-#define		PMC_IPC_PMIC_ACCESS_WRITE	0x1
+#define	PMC_IPC_PMIC_ACCESS_READ	0x0
+#define	PMC_IPC_PMIC_ACCESS_WRITE	0x1
 #define PMC_IPC_USB_PWR_CTRL		0xF0
 #define PMC_IPC_PMIC_BLACKLIST_SEL	0xEF
 #define PMC_IPC_PHY_CONFIG		0xEE
@@ -30,11 +35,6 @@
 
 #if IS_ENABLED(CONFIG_INTEL_PMC_IPC)
 
-int intel_pmc_ipc_simple_command(int cmd, int sub);
-int intel_pmc_ipc_raw_cmd(u32 cmd, u32 sub, u8 *in, u32 inlen,
-		u32 *out, u32 outlen, u32 dptr, u32 sptr);
-int intel_pmc_ipc_command(u32 cmd, u32 sub, u8 *in, u32 inlen,
-		u32 *out, u32 outlen);
 int intel_pmc_s0ix_counter_read(u64 *data);
 int intel_pmc_gcr_read(u32 offset, u32 *data);
 int intel_pmc_gcr_write(u32 offset, u32 data);
@@ -42,23 +42,6 @@ int intel_pmc_gcr_update(u32 offset, u32 mask, u32 val);
 
 #else
 
-static inline int intel_pmc_ipc_simple_command(int cmd, int sub)
-{
-	return -EINVAL;
-}
-
-static inline int intel_pmc_ipc_raw_cmd(u32 cmd, u32 sub, u8 *in, u32 inlen,
-		u32 *out, u32 outlen, u32 dptr, u32 sptr)
-{
-	return -EINVAL;
-}
-
-static inline int intel_pmc_ipc_command(u32 cmd, u32 sub, u8 *in, u32 inlen,
-		u32 *out, u32 outlen)
-{
-	return -EINVAL;
-}
-
 static inline int intel_pmc_s0ix_counter_read(u64 *data)
 {
 	return -EINVAL;
diff --git a/drivers/mfd/intel_soc_pmic_bxtwc.c b/drivers/mfd/intel_soc_pmic_bxtwc.c
index 15bc052..55ffcae 100644
--- a/drivers/mfd/intel_soc_pmic_bxtwc.c
+++ b/drivers/mfd/intel_soc_pmic_bxtwc.c
@@ -271,6 +271,9 @@ static int regmap_ipc_byte_reg_read(void *context, unsigned int reg,
 	u8 ipc_in[2];
 	u8 ipc_out[4];
 	struct intel_soc_pmic *pmic = context;
+	struct intel_ipc_raw_cmd ipc_raw_cmd;
+	u32 cmd[PMC_PARAM_LEN] = {PMC_IPC_PMIC_ACCESS,
+		PMC_IPC_PMIC_ACCESS_READ};
 
 	if (!pmic)
 		return -EINVAL;
@@ -284,9 +287,15 @@ static int regmap_ipc_byte_reg_read(void *context, unsigned int reg,
 
 	ipc_in[0] = reg;
 	ipc_in[1] = i2c_addr;
-	ret = intel_pmc_ipc_command(PMC_IPC_PMIC_ACCESS,
-			PMC_IPC_PMIC_ACCESS_READ,
-			ipc_in, sizeof(ipc_in), (u32 *)ipc_out, 1);
+
+	ipc_raw_cmd.cmd_list = cmd;
+	ipc_raw_cmd.cmdlen = PMC_PARAM_LEN;
+	ipc_raw_cmd.in = ipc_in;
+	ipc_raw_cmd.inlen = sizeof(ipc_in);
+	ipc_raw_cmd.out = (u32 *)ipc_out;
+	ipc_raw_cmd.outlen = 1;
+
+	ret = ipc_dev_raw_cmd(pmic->ipc_dev, &ipc_raw_cmd);
 	if (ret) {
 		dev_err(pmic->dev, "Failed to read from PMIC\n");
 		return ret;
@@ -303,6 +312,9 @@ static int regmap_ipc_byte_reg_write(void *context, unsigned int reg,
 	int i2c_addr;
 	u8 ipc_in[3];
 	struct intel_soc_pmic *pmic = context;
+	struct intel_ipc_raw_cmd ipc_raw_cmd;
+	u32 cmd[PMC_PARAM_LEN] = {PMC_IPC_PMIC_ACCESS,
+		PMC_IPC_PMIC_ACCESS_WRITE};
 
 	if (!pmic)
 		return -EINVAL;
@@ -317,9 +329,15 @@ static int regmap_ipc_byte_reg_write(void *context, unsigned int reg,
 	ipc_in[0] = reg;
 	ipc_in[1] = i2c_addr;
 	ipc_in[2] = val;
-	ret = intel_pmc_ipc_command(PMC_IPC_PMIC_ACCESS,
-			PMC_IPC_PMIC_ACCESS_WRITE,
-			ipc_in, sizeof(ipc_in), NULL, 0);
+
+	ipc_raw_cmd.cmd_list = cmd;
+	ipc_raw_cmd.cmdlen = PMC_PARAM_LEN;
+	ipc_raw_cmd.in = ipc_in;
+	ipc_raw_cmd.inlen = sizeof(ipc_in);
+	ipc_raw_cmd.out = NULL;
+	ipc_raw_cmd.outlen = 0;
+
+	ret = ipc_dev_raw_cmd(pmic->ipc_dev, &ipc_raw_cmd);
 	if (ret) {
 		dev_err(pmic->dev, "Failed to write to PMIC\n");
 		return ret;
@@ -445,6 +463,10 @@ static int bxtwc_probe(struct platform_device *pdev)
 	if (!pmic)
 		return -ENOMEM;
 
+	pmic->ipc_dev = intel_ipc_dev_get(INTEL_PMC_IPC_DEV);
+	if (IS_ERR_OR_NULL(pmic->ipc_dev))
+		return PTR_ERR(pmic->ipc_dev);
+
 	ret = platform_get_irq(pdev, 0);
 	if (ret < 0) {
 		dev_err(&pdev->dev, "Invalid IRQ\n");
@@ -562,7 +584,10 @@ static int bxtwc_probe(struct platform_device *pdev)
 
 static int bxtwc_remove(struct platform_device *pdev)
 {
+	struct intel_soc_pmic *pmic = dev_get_drvdata(&pdev->dev);
+
 	sysfs_remove_group(&pdev->dev.kobj, &bxtwc_group);
+	intel_ipc_dev_put(pmic->ipc_dev);
 
 	return 0;
 }
diff --git a/drivers/platform/x86/intel_pmc_ipc.c b/drivers/platform/x86/intel_pmc_ipc.c
index df6af1f..7d6a82d 100644
--- a/drivers/platform/x86/intel_pmc_ipc.c
+++ b/drivers/platform/x86/intel_pmc_ipc.c
@@ -48,18 +48,8 @@
  * The ARC handles the interrupt and services it, writing optional data to
  * the IPC1 registers, updates the IPC_STS response register with the status.
  */
-#define IPC_CMD			0x0
-#define		IPC_CMD_MSI		0x100
 #define		IPC_CMD_SIZE		16
 #define		IPC_CMD_SUBCMD		12
-#define IPC_STATUS		0x04
-#define		IPC_STATUS_IRQ		0x4
-#define		IPC_STATUS_ERR		0x2
-#define		IPC_STATUS_BUSY		0x1
-#define IPC_SPTR		0x08
-#define IPC_DPTR		0x0C
-#define IPC_WRITE_BUFFER	0x80
-#define IPC_READ_BUFFER		0x90
 
 /* Residency with clock rate at 19.2MHz to usecs */
 #define S0IX_RESIDENCY_IN_USECS(d, s)		\
@@ -74,11 +64,6 @@
  */
 #define IPC_DATA_BUFFER_SIZE	16
 
-#define IPC_LOOP_CNT		3000000
-#define IPC_MAX_SEC		3
-
-#define IPC_TRIGGER_MODE_IRQ		true
-
 /* exported resources from IFWI */
 #define PLAT_RESOURCE_IPC_INDEX		0
 #define PLAT_RESOURCE_IPC_SIZE		0x1000
@@ -118,36 +103,41 @@
 #define PMC_CFG_NO_REBOOT_EN		(1 << 4)
 #define PMC_CFG_NO_REBOOT_DIS		(0 << 4)
 
+/* IPC PMC commands */
+#define	IPC_DEV_PMC_CMD_MSI			BIT(8)
+#define	IPC_DEV_PMC_CMD_SIZE			16
+#define	IPC_DEV_PMC_CMD_SUBCMD			12
+#define	IPC_DEV_PMC_CMD_STATUS			BIT(2)
+#define	IPC_DEV_PMC_CMD_STATUS_IRQ		BIT(2)
+#define	IPC_DEV_PMC_CMD_STATUS_ERR		BIT(1)
+#define	IPC_DEV_PMC_CMD_STATUS_ERR_MASK		GENMASK(7, 0)
+#define	IPC_DEV_PMC_CMD_STATUS_BUSY		BIT(0)
+
+/*IPC PMC reg offsets */
+#define IPC_DEV_PMC_STATUS_OFFSET		0x04
+#define IPC_DEV_PMC_SPTR_OFFSET			0x08
+#define IPC_DEV_PMC_DPTR_OFFSET			0x0C
+#define IPC_DEV_PMC_WRBUF_OFFSET		0x80
+#define IPC_DEV_PMC_RBUF_OFFSET			0x90
+
 static struct intel_pmc_ipc_dev {
 	struct device *dev;
+	struct intel_ipc_dev *pmc_ipc_dev;
+	struct intel_ipc_dev_ops ops;
+	struct intel_ipc_dev_cfg cfg;
 	void __iomem *ipc_base;
-	bool irq_mode;
-	int irq;
-	int cmd;
-	struct completion cmd_complete;
 
 	/* gcr */
 	void __iomem *gcr_mem_base;
 	struct regmap *gcr_regs;
 } ipcdev;
 
-static char *ipc_err_sources[] = {
-	[IPC_ERR_NONE] =
-		"no error",
-	[IPC_ERR_CMD_NOT_SUPPORTED] =
-		"command not supported",
-	[IPC_ERR_CMD_NOT_SERVICED] =
-		"command not serviced",
-	[IPC_ERR_UNABLE_TO_SERVICE] =
-		"unable to service",
-	[IPC_ERR_CMD_INVALID] =
-		"command invalid",
-	[IPC_ERR_CMD_FAILED] =
-		"command failed",
-	[IPC_ERR_EMSECURITY] =
-		"Invalid Battery",
-	[IPC_ERR_UNSIGNEDKERNEL] =
-		"Unsigned kernel",
+static struct regmap_config pmc_regmap_config = {
+	.name = "intel_pmc_regs",
+	.reg_bits = 32,
+	.reg_stride = 4,
+	.val_bits = 32,
+	.fast_io = true,
 };
 
 static struct regmap_config gcr_regmap_config = {
@@ -159,40 +149,6 @@ static struct regmap_config gcr_regmap_config = {
 	.max_register = PLAT_RESOURCE_GCR_SIZE,
 };
 
-/* Prevent concurrent calls to the PMC */
-static DEFINE_MUTEX(ipclock);
-
-static inline void ipc_send_command(u32 cmd)
-{
-	ipcdev.cmd = cmd;
-	if (ipcdev.irq_mode) {
-		reinit_completion(&ipcdev.cmd_complete);
-		cmd |= IPC_CMD_MSI;
-	}
-	writel(cmd, ipcdev.ipc_base + IPC_CMD);
-}
-
-static inline u32 ipc_read_status(void)
-{
-	return readl(ipcdev.ipc_base + IPC_STATUS);
-}
-
-static inline void ipc_data_writel(u32 data, u32 offset)
-{
-	writel(data, ipcdev.ipc_base + IPC_WRITE_BUFFER + offset);
-}
-
-static inline u8 __maybe_unused ipc_data_readb(u32 offset)
-{
-	return readb(ipcdev.ipc_base + IPC_READ_BUFFER + offset);
-}
-
-static inline u32 ipc_data_readl(u32 offset)
-{
-	return readl(ipcdev.ipc_base + IPC_READ_BUFFER + offset);
-}
-
-
 /**
  * intel_pmc_gcr_read() - Read PMC GCR register
  * @offset:	offset of GCR register from GCR address base
@@ -264,160 +220,109 @@ static int update_no_reboot_bit(void *priv, bool set)
 				    PMC_CFG_NO_REBOOT_MASK, value);
 }
 
-static int intel_pmc_ipc_check_status(void)
+static int pre_simple_cmd_fn(u32 *cmd_list, u32 cmdlen)
 {
-	int status;
-	int ret = 0;
-
-	if (ipcdev.irq_mode) {
-		if (0 == wait_for_completion_timeout(
-				&ipcdev.cmd_complete, IPC_MAX_SEC * HZ))
-			ret = -ETIMEDOUT;
-	} else {
-		int loop_count = IPC_LOOP_CNT;
-
-		while ((ipc_read_status() & IPC_STATUS_BUSY) && --loop_count)
-			udelay(1);
-		if (loop_count == 0)
-			ret = -ETIMEDOUT;
-	}
-
-	status = ipc_read_status();
-	if (ret == -ETIMEDOUT) {
-		dev_err(ipcdev.dev,
-			"IPC timed out, TS=0x%x, CMD=0x%x\n",
-			status, ipcdev.cmd);
-		return ret;
-	}
+	if (!cmd_list || cmdlen != PMC_PARAM_LEN)
+		return -EINVAL;
 
-	if (status & IPC_STATUS_ERR) {
-		int i;
-
-		ret = -EIO;
-		i = (status >> IPC_CMD_SIZE) & 0xFF;
-		if (i < ARRAY_SIZE(ipc_err_sources))
-			dev_err(ipcdev.dev,
-				"IPC failed: %s, STS=0x%x, CMD=0x%x\n",
-				ipc_err_sources[i], status, ipcdev.cmd);
-		else
-			dev_err(ipcdev.dev,
-				"IPC failed: unknown, STS=0x%x, CMD=0x%x\n",
-				status, ipcdev.cmd);
-		if ((i == IPC_ERR_UNSIGNEDKERNEL) || (i == IPC_ERR_EMSECURITY))
-			ret = -EACCES;
-	}
+	cmd_list[0] |= (cmd_list[1] << IPC_CMD_SUBCMD);
 
-	return ret;
+	return 0;
 }
 
-/**
- * intel_pmc_ipc_simple_command() - Simple IPC command
- * @cmd:	IPC command code.
- * @sub:	IPC command sub type.
- *
- * Send a simple IPC command to PMC when don't need to specify
- * input/output data and source/dest pointers.
- *
- * Return:	an IPC error code or 0 on success.
- */
-int intel_pmc_ipc_simple_command(int cmd, int sub)
+static int pre_raw_cmd_fn(struct intel_ipc_raw_cmd *ipc_raw_cmd)
 {
 	int ret;
 
-	mutex_lock(&ipclock);
-	if (ipcdev.dev == NULL) {
-		mutex_unlock(&ipclock);
-		return -ENODEV;
-	}
-	ipc_send_command(sub << IPC_CMD_SUBCMD | cmd);
-	ret = intel_pmc_ipc_check_status();
-	mutex_unlock(&ipclock);
+	if (ipc_raw_cmd->inlen > IPC_DATA_BUFFER_SIZE ||
+	    ipc_raw_cmd->outlen > (IPC_DATA_BUFFER_SIZE / 4))
+		return -EINVAL;
 
-	return ret;
-}
-EXPORT_SYMBOL_GPL(intel_pmc_ipc_simple_command);
+	ret = pre_simple_cmd_fn(ipc_raw_cmd->cmd_list, ipc_raw_cmd->cmdlen);
+	if (ret < 0)
+		return ret;
 
-/**
- * intel_pmc_ipc_raw_cmd() - IPC command with data and pointers
- * @cmd:	IPC command code.
- * @sub:	IPC command sub type.
- * @in:		input data of this IPC command.
- * @inlen:	input data length in bytes.
- * @out:	output data of this IPC command.
- * @outlen:	output data length in dwords.
- * @sptr:	data writing to SPTR register.
- * @dptr:	data writing to DPTR register.
- *
- * Send an IPC command to PMC with input/output data and source/dest pointers.
- *
- * Return:	an IPC error code or 0 on success.
- */
-int intel_pmc_ipc_raw_cmd(u32 cmd, u32 sub, u8 *in, u32 inlen, u32 *out,
-			  u32 outlen, u32 dptr, u32 sptr)
-{
-	u32 wbuf[4] = { 0 };
-	int ret;
-	int i;
+	ipc_raw_cmd->cmd_list[0] |= (ipc_raw_cmd->inlen << IPC_CMD_SIZE);
 
-	if (inlen > IPC_DATA_BUFFER_SIZE || outlen > IPC_DATA_BUFFER_SIZE / 4)
-		return -EINVAL;
+	return 0;
+}
 
-	mutex_lock(&ipclock);
-	if (ipcdev.dev == NULL) {
-		mutex_unlock(&ipclock);
-		return -ENODEV;
-	}
-	memcpy(wbuf, in, inlen);
-	writel(dptr, ipcdev.ipc_base + IPC_DPTR);
-	writel(sptr, ipcdev.ipc_base + IPC_SPTR);
-	/* The input data register is 32bit register and inlen is in Byte */
-	for (i = 0; i < ((inlen + 3) / 4); i++)
-		ipc_data_writel(wbuf[i], 4 * i);
-	ipc_send_command((inlen << IPC_CMD_SIZE) |
-			(sub << IPC_CMD_SUBCMD) | cmd);
-	ret = intel_pmc_ipc_check_status();
-	if (!ret) {
-		/* out is read from 32bit register and outlen is in 32bit */
-		for (i = 0; i < outlen; i++)
-			*out++ = ipc_data_readl(4 * i);
-	}
-	mutex_unlock(&ipclock);
+static int pre_irq_handler_fn(struct intel_ipc_dev *ipc_dev, int irq)
+{
+	return regmap_write_bits(ipc_dev->cfg->cmd_regs,
+				 ipc_dev->cfg->status_reg,
+				 IPC_DEV_PMC_CMD_STATUS_IRQ,
+				 IPC_DEV_PMC_CMD_STATUS_IRQ);
+}
 
-	return ret;
+static int pmc_ipc_err_code(int status)
+{
+	return ((status >> IPC_DEV_PMC_CMD_SIZE) &
+		IPC_DEV_PMC_CMD_STATUS_ERR_MASK);
 }
-EXPORT_SYMBOL_GPL(intel_pmc_ipc_raw_cmd);
 
-/**
- * intel_pmc_ipc_command() -  IPC command with input/output data
- * @cmd:	IPC command code.
- * @sub:	IPC command sub type.
- * @in:		input data of this IPC command.
- * @inlen:	input data length in bytes.
- * @out:	output data of this IPC command.
- * @outlen:	output data length in dwords.
- *
- * Send an IPC command to PMC with input/output data.
- *
- * Return:	an IPC error code or 0 on success.
- */
-int intel_pmc_ipc_command(u32 cmd, u32 sub, u8 *in, u32 inlen,
-			  u32 *out, u32 outlen)
+static int pmc_ipc_busy_check(int status)
 {
-	return intel_pmc_ipc_raw_cmd(cmd, sub, in, inlen, out, outlen, 0, 0);
+	return status | IPC_DEV_PMC_CMD_STATUS_BUSY;
 }
-EXPORT_SYMBOL_GPL(intel_pmc_ipc_command);
 
-static irqreturn_t ioc(int irq, void *dev_id)
+static u32 pmc_ipc_enable_msi(u32 cmd)
 {
-	int status;
+	return cmd | IPC_DEV_PMC_CMD_MSI;
+}
 
-	if (ipcdev.irq_mode) {
-		status = ipc_read_status();
-		writel(status | IPC_STATUS_IRQ, ipcdev.ipc_base + IPC_STATUS);
+static struct intel_ipc_dev *intel_pmc_ipc_dev_create(
+		struct device *pmc_dev,
+		void __iomem *base,
+		int irq)
+{
+	struct intel_ipc_dev_ops *ops;
+	struct intel_ipc_dev_cfg *cfg;
+	struct regmap *cmd_regs;
+
+	cfg = devm_kzalloc(pmc_dev, sizeof(*cfg), GFP_KERNEL);
+	if (!cfg)
+		return ERR_PTR(-ENOMEM);
+
+	ops = devm_kzalloc(pmc_dev, sizeof(*ops), GFP_KERNEL);
+	if (!ops)
+		return ERR_PTR(-ENOMEM);
+
+	cmd_regs = devm_regmap_init_mmio_clk(pmc_dev, NULL, base,
+					     &pmc_regmap_config);
+	if (IS_ERR(cmd_regs)) {
+		dev_err(pmc_dev, "cmd_regs regmap init failed\n");
+		return ERR_CAST(cmd_regs);
 	}
-	complete(&ipcdev.cmd_complete);
 
-	return IRQ_HANDLED;
+	/* set IPC dev ops */
+	ops->to_err_code = pmc_ipc_err_code;
+	ops->busy_check = pmc_ipc_busy_check;
+	ops->enable_msi = pmc_ipc_enable_msi;
+	ops->pre_raw_cmd_fn = pre_raw_cmd_fn;
+	ops->pre_simple_cmd_fn = pre_simple_cmd_fn;
+	ops->pre_irq_handler_fn = pre_irq_handler_fn;
+
+	/* set cfg options */
+	if (irq > 0)
+		cfg->mode = IPC_DEV_MODE_IRQ;
+	else
+		cfg->mode = IPC_DEV_MODE_POLLING;
+
+	cfg->chan_type = IPC_CHANNEL_IA_PMC;
+	cfg->irq = irq;
+	cfg->use_msi = true;
+	cfg->support_sptr = true;
+	cfg->support_dptr = true;
+	cfg->cmd_regs = cmd_regs;
+	cfg->data_regs = cmd_regs;
+	cfg->wrbuf_reg = IPC_DEV_PMC_WRBUF_OFFSET;
+	cfg->rbuf_reg = IPC_DEV_PMC_RBUF_OFFSET;
+	cfg->sptr_reg = IPC_DEV_PMC_SPTR_OFFSET;
+	cfg->dptr_reg = IPC_DEV_PMC_DPTR_OFFSET;
+	cfg->status_reg = IPC_DEV_PMC_STATUS_OFFSET;
+
+	return devm_intel_ipc_dev_create(pmc_dev, INTEL_PMC_IPC_DEV, cfg, ops);
 }
 
 static int ipc_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
@@ -429,8 +334,6 @@ static int ipc_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 	if (pmc->dev)
 		return -EBUSY;
 
-	pmc->irq_mode = IPC_TRIGGER_MODE_IRQ;
-
 	ret = pcim_enable_device(pdev);
 	if (ret)
 		return ret;
@@ -439,15 +342,13 @@ static int ipc_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 	if (ret)
 		return ret;
 
-	init_completion(&pmc->cmd_complete);
-
 	pmc->ipc_base = pcim_iomap_table(pdev)[0];
 
-	ret = devm_request_irq(&pdev->dev, pdev->irq, ioc, 0, "intel_pmc_ipc",
-				pmc);
-	if (ret) {
-		dev_err(&pdev->dev, "Failed to request IRQ\n");
-		return ret;
+	pmc->pmc_ipc_dev = intel_pmc_ipc_dev_create(&pdev->dev, pmc->ipc_base,
+						    pdev->irq);
+	if (IS_ERR(pmc->pmc_ipc_dev)) {
+		dev_err(&pdev->dev, "Failed to create PMC IPC device\n");
+		return PTR_ERR(pmc->pmc_ipc_dev);
 	}
 
 	pmc->dev = &pdev->dev;
@@ -475,19 +376,19 @@ static ssize_t intel_pmc_ipc_simple_cmd_store(struct device *dev,
 					      struct device_attribute *attr,
 					      const char *buf, size_t count)
 {
-	int subcmd;
-	int cmd;
+	struct intel_pmc_ipc_dev *pmc = dev_get_drvdata(dev);
+	int cmd[2];
 	int ret;
 
-	ret = sscanf(buf, "%d %d", &cmd, &subcmd);
+	ret = sscanf(buf, "%d %d", &cmd[0], &cmd[2]);
 	if (ret != 2) {
 		dev_err(dev, "Error args\n");
 		return -EINVAL;
 	}
 
-	ret = intel_pmc_ipc_simple_command(cmd, subcmd);
+	ret = ipc_dev_simple_cmd(pmc->pmc_ipc_dev, cmd, 2);
 	if (ret) {
-		dev_err(dev, "command %d error with %d\n", cmd, ret);
+		dev_err(dev, "command %d error with %d\n", cmd[0], ret);
 		return ret;
 	}
 	return (ssize_t)count;
@@ -497,22 +398,23 @@ static ssize_t intel_pmc_ipc_northpeak_store(struct device *dev,
 					     struct device_attribute *attr,
 					     const char *buf, size_t count)
 {
+	struct intel_pmc_ipc_dev *pmc = dev_get_drvdata(dev);
 	unsigned long val;
-	int subcmd;
+	int cmd[2] = {PMC_IPC_NORTHPEAK_CTRL, 0};
 	int ret;
 
 	if (kstrtoul(buf, 0, &val))
 		return -EINVAL;
 
 	if (val)
-		subcmd = 1;
-	else
-		subcmd = 0;
-	ret = intel_pmc_ipc_simple_command(PMC_IPC_NORTHPEAK_CTRL, subcmd);
+		cmd[1] = 1;
+
+	ret = ipc_dev_simple_cmd(pmc->pmc_ipc_dev, cmd, 2);
 	if (ret) {
-		dev_err(dev, "command north %d error with %d\n", subcmd, ret);
+		dev_err(dev, "command north %d error with %d\n", cmd[1], ret);
 		return ret;
 	}
+
 	return (ssize_t)count;
 }
 
@@ -688,6 +590,7 @@ static int ipc_create_pmc_devices(struct platform_device *pdev)
 
 static int ipc_plat_get_res(struct platform_device *pdev)
 {
+	struct intel_pmc_ipc_dev *pmc = dev_get_drvdata(&pdev->dev);
 	struct resource *res;
 	void __iomem *addr;
 
@@ -706,9 +609,9 @@ static int ipc_plat_get_res(struct platform_device *pdev)
 	if (IS_ERR(addr))
 		return PTR_ERR(addr);
 
-	ipcdev.ipc_base = addr;
-	ipcdev.gcr_mem_base = addr + PLAT_RESOURCE_GCR_OFFSET;
-	dev_dbg(&pdev->dev, "PMC IPC resource %pR\n", res);
+	pmc->ipc_base = addr;
+	pmc->gcr_mem_base = addr + PLAT_RESOURCE_GCR_OFFSET;
+	dev_info(&pdev->dev, "PMC IPC resource %pR\n", res);
 
 	return 0;
 }
@@ -754,14 +657,15 @@ MODULE_DEVICE_TABLE(acpi, ipc_acpi_ids);
 
 static int ipc_plat_probe(struct platform_device *pdev)
 {
-	int ret;
+	int ret, irq;
+	struct intel_pmc_ipc_dev *pmc = &ipcdev;
 
-	ipcdev.dev = &pdev->dev;
-	ipcdev.irq_mode = IPC_TRIGGER_MODE_IRQ;
-	init_completion(&ipcdev.cmd_complete);
+	pmc->dev = &pdev->dev;
 
-	ipcdev.irq = platform_get_irq(pdev, 0);
-	if (ipcdev.irq < 0) {
+	dev_set_drvdata(&pdev->dev, pmc);
+
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0) {
 		dev_err(&pdev->dev, "Failed to get IRQ\n");
 		return -EINVAL;
 	}
@@ -786,28 +690,26 @@ static int ipc_plat_probe(struct platform_device *pdev)
 		return ret;
 	}
 
-	ret = devm_request_irq(&pdev->dev, ipcdev.irq, ioc, IRQF_NO_SUSPEND,
-			       "intel_pmc_ipc", &ipcdev);
-	if (ret) {
-		dev_err(&pdev->dev, "Failed to request IRQ\n");
-		return ret;
-	}
-
 	ret = sysfs_create_group(&pdev->dev.kobj, &intel_ipc_group);
 	if (ret) {
 		dev_err(&pdev->dev, "Failed to create sysfs group %d\n",
 			ret);
-		devm_free_irq(&pdev->dev, ipcdev.irq, &ipcdev);
 		return ret;
 	}
 
+	ipcdev.pmc_ipc_dev = intel_pmc_ipc_dev_create(&pdev->dev,
+			pmc->ipc_base, irq);
+	if (IS_ERR(pmc->pmc_ipc_dev)) {
+		dev_err(&pdev->dev, "Failed to create PMC IPC device\n");
+		return PTR_ERR(pmc->pmc_ipc_dev);
+	}
+
 	return 0;
 }
 
 static int ipc_plat_remove(struct platform_device *pdev)
 {
 	sysfs_remove_group(&pdev->dev.kobj, &intel_ipc_group);
-	devm_free_irq(&pdev->dev, ipcdev.irq, &ipcdev);
 	ipcdev.dev = NULL;
 
 	return 0;
diff --git a/drivers/platform/x86/intel_telemetry_pltdrv.c b/drivers/platform/x86/intel_telemetry_pltdrv.c
index 0dbd7be..74868bb 100644
--- a/drivers/platform/x86/intel_telemetry_pltdrv.c
+++ b/drivers/platform/x86/intel_telemetry_pltdrv.c
@@ -56,10 +56,6 @@
 #define IOSS_TELEM_TRACE_CTL_WRITE	0x6
 #define IOSS_TELEM_EVENT_CTL_READ	0x7
 #define IOSS_TELEM_EVENT_CTL_WRITE	0x8
-#define IOSS_TELEM_EVT_CTRL_WRITE_SIZE	0x4
-#define IOSS_TELEM_READ_WORD		0x1
-#define IOSS_TELEM_WRITE_FOURBYTES	0x4
-#define IOSS_TELEM_EVT_WRITE_SIZE	0x3
 
 #define TELEM_INFO_SRAMEVTS_MASK	0xFF00
 #define TELEM_INFO_SRAMEVTS_SHIFT	0x8
@@ -98,7 +94,7 @@ struct telem_ssram_region {
 };
 
 static struct telemetry_plt_config *telm_conf;
-static struct intel_ipc_dev *punit_ipc_dev;
+static struct intel_ipc_dev *punit_ipc_dev, *pmc_ipc_dev;
 
 /*
  * The following counters are programmed by default during setup.
@@ -226,6 +222,29 @@ static int telem_punit_cmd(struct intel_ipc_dev *ipc_dev, u32 cmd, u32 sub,
 	return ipc_dev_cmd(ipc_dev, &ipc_cmd);
 }
 
+static int telem_pmc_cmd(struct intel_ipc_dev *ipc_dev, u32 cmd, u32 sub,
+			 u8 *in, u32 *out)
+{
+	struct intel_ipc_raw_cmd ipc_raw_cmd = {0};
+	u32 cmd_list[PMC_PARAM_LEN] = {0};
+
+	cmd_list[0] = cmd;
+	cmd_list[1] = sub;
+
+	ipc_raw_cmd.cmd_list = cmd_list;
+	ipc_raw_cmd.cmdlen = PMC_PARAM_LEN;
+	ipc_raw_cmd.in = in;
+	ipc_raw_cmd.out = out;
+
+	if (in)
+		ipc_raw_cmd.inlen = 4;
+	if (out)
+		ipc_raw_cmd.outlen = 1;
+
+	return ipc_dev_raw_cmd(ipc_dev, &ipc_raw_cmd);
+}
+
+
 static inline int telem_get_unitconfig(enum telemetry_unit telem_unit,
 				     struct telemetry_unit_config **unit_config)
 {
@@ -289,17 +308,13 @@ static int telemetry_check_evtid(enum telemetry_unit telem_unit,
 static inline int telemetry_plt_config_ioss_event(u32 evt_id, int index)
 {
 	u32 write_buf;
-	int ret;
 
 	write_buf = evt_id | TELEM_EVENT_ENABLE;
 	write_buf <<= BITS_PER_BYTE;
 	write_buf |= index;
 
-	ret = intel_pmc_ipc_command(PMC_IPC_PMC_TELEMTRY,
-				    IOSS_TELEM_EVENT_WRITE, (u8 *)&write_buf,
-				    IOSS_TELEM_EVT_WRITE_SIZE, NULL, 0);
-
-	return ret;
+	return telem_pmc_cmd(pmc_ipc_dev, PMC_IPC_PMC_TELEMTRY,
+			     IOSS_TELEM_EVENT_WRITE, (u8 *)&write_buf, NULL);
 }
 
 static inline int telemetry_plt_config_pss_event(u32 evt_id, int index)
@@ -325,9 +340,8 @@ static int telemetry_setup_iossevtconfig(struct telemetry_evtconfig evtconfig,
 	ioss_evtmap = evtconfig.evtmap;
 
 	/* Get telemetry EVENT CTL */
-	ret = intel_pmc_ipc_command(PMC_IPC_PMC_TELEMTRY,
-				    IOSS_TELEM_EVENT_CTL_READ, NULL, 0,
-				    &telem_ctrl, IOSS_TELEM_READ_WORD);
+	ret = telem_pmc_cmd(pmc_ipc_dev, PMC_IPC_PMC_TELEMTRY,
+			    IOSS_TELEM_EVENT_CTL_READ, NULL, &telem_ctrl);
 	if (ret) {
 		pr_err("IOSS TELEM_CTRL Read Failed\n");
 		return ret;
@@ -335,12 +349,9 @@ static int telemetry_setup_iossevtconfig(struct telemetry_evtconfig evtconfig,
 
 	/* Disable Telemetry */
 	TELEM_DISABLE(telem_ctrl);
-
-	ret = intel_pmc_ipc_command(PMC_IPC_PMC_TELEMTRY,
-				    IOSS_TELEM_EVENT_CTL_WRITE,
-				    (u8 *)&telem_ctrl,
-				    IOSS_TELEM_EVT_CTRL_WRITE_SIZE,
-				    NULL, 0);
+	ret = telem_pmc_cmd(pmc_ipc_dev, PMC_IPC_PMC_TELEMTRY,
+			    IOSS_TELEM_EVENT_CTL_WRITE, (u8 *)&telem_ctrl,
+			    NULL);
 	if (ret) {
 		pr_err("IOSS TELEM_CTRL Event Disable Write Failed\n");
 		return ret;
@@ -351,12 +362,9 @@ static int telemetry_setup_iossevtconfig(struct telemetry_evtconfig evtconfig,
 	if (action == TELEM_RESET) {
 		/* Clear All Events */
 		TELEM_CLEAR_EVENTS(telem_ctrl);
-
-		ret = intel_pmc_ipc_command(PMC_IPC_PMC_TELEMTRY,
-					    IOSS_TELEM_EVENT_CTL_WRITE,
-					    (u8 *)&telem_ctrl,
-					    IOSS_TELEM_EVT_CTRL_WRITE_SIZE,
-					    NULL, 0);
+		ret = telem_pmc_cmd(pmc_ipc_dev, PMC_IPC_PMC_TELEMTRY,
+				    IOSS_TELEM_EVENT_CTL_WRITE,
+				    (u8 *)&telem_ctrl, NULL);
 		if (ret) {
 			pr_err("IOSS TELEM_CTRL Event Disable Write Failed\n");
 			return ret;
@@ -380,12 +388,9 @@ static int telemetry_setup_iossevtconfig(struct telemetry_evtconfig evtconfig,
 	if (action == TELEM_UPDATE) {
 		/* Clear All Events */
 		TELEM_CLEAR_EVENTS(telem_ctrl);
-
-		ret = intel_pmc_ipc_command(PMC_IPC_PMC_TELEMTRY,
-					    IOSS_TELEM_EVENT_CTL_WRITE,
-					    (u8 *)&telem_ctrl,
-					    IOSS_TELEM_EVT_CTRL_WRITE_SIZE,
-					    NULL, 0);
+		ret = telem_pmc_cmd(pmc_ipc_dev, PMC_IPC_PMC_TELEMTRY,
+				    IOSS_TELEM_EVENT_CTL_WRITE,
+				    (u8 *)&telem_ctrl, NULL);
 		if (ret) {
 			pr_err("IOSS TELEM_CTRL Event Disable Write Failed\n");
 			return ret;
@@ -432,11 +437,9 @@ static int telemetry_setup_iossevtconfig(struct telemetry_evtconfig evtconfig,
 	TELEM_ENABLE_SRAM_EVT_TRACE(telem_ctrl);
 	TELEM_ENABLE_PERIODIC(telem_ctrl);
 	telem_ctrl |= ioss_period;
-
-	ret = intel_pmc_ipc_command(PMC_IPC_PMC_TELEMTRY,
-				    IOSS_TELEM_EVENT_CTL_WRITE,
-				    (u8 *)&telem_ctrl,
-				    IOSS_TELEM_EVT_CTRL_WRITE_SIZE, NULL, 0);
+	ret = telem_pmc_cmd(pmc_ipc_dev, PMC_IPC_PMC_TELEMTRY,
+			    IOSS_TELEM_EVENT_CTL_WRITE, (u8 *)&telem_ctrl,
+			    NULL);
 	if (ret) {
 		pr_err("IOSS TELEM_CTRL Event Enable Write Failed\n");
 		return ret;
@@ -626,8 +629,8 @@ static int telemetry_setup(struct platform_device *pdev)
 	u32 read_buf, events, event_regs;
 	int ret;
 
-	ret = intel_pmc_ipc_command(PMC_IPC_PMC_TELEMTRY, IOSS_TELEM_INFO_READ,
-				    NULL, 0, &read_buf, IOSS_TELEM_READ_WORD);
+	ret = telem_pmc_cmd(pmc_ipc_dev, PMC_IPC_PMC_TELEMTRY,
+			    IOSS_TELEM_INFO_READ, NULL, &read_buf);
 	if (ret) {
 		dev_err(&pdev->dev, "IOSS TELEM_INFO Read Failed\n");
 		return ret;
@@ -728,9 +731,9 @@ static int telemetry_plt_set_sampling_period(u8 pss_period, u8 ioss_period)
 		}
 
 		/* Get telemetry EVENT CTL */
-		ret = intel_pmc_ipc_command(PMC_IPC_PMC_TELEMTRY,
-					    IOSS_TELEM_EVENT_CTL_READ, NULL, 0,
-					    &telem_ctrl, IOSS_TELEM_READ_WORD);
+		ret = telem_pmc_cmd(pmc_ipc_dev, PMC_IPC_PMC_TELEMTRY,
+				    IOSS_TELEM_EVENT_CTL_READ, NULL,
+				    &telem_ctrl);
 		if (ret) {
 			pr_err("IOSS TELEM_CTRL Read Failed\n");
 			goto out;
@@ -738,12 +741,9 @@ static int telemetry_plt_set_sampling_period(u8 pss_period, u8 ioss_period)
 
 		/* Disable Telemetry */
 		TELEM_DISABLE(telem_ctrl);
-
-		ret = intel_pmc_ipc_command(PMC_IPC_PMC_TELEMTRY,
-					    IOSS_TELEM_EVENT_CTL_WRITE,
-					    (u8 *)&telem_ctrl,
-					    IOSS_TELEM_EVT_CTRL_WRITE_SIZE,
-					    NULL, 0);
+		ret = telem_pmc_cmd(pmc_ipc_dev, PMC_IPC_PMC_TELEMTRY,
+				    IOSS_TELEM_EVENT_CTL_WRITE,
+				    (u8 *)&telem_ctrl, NULL);
 		if (ret) {
 			pr_err("IOSS TELEM_CTRL Event Disable Write Failed\n");
 			goto out;
@@ -755,11 +755,9 @@ static int telemetry_plt_set_sampling_period(u8 pss_period, u8 ioss_period)
 		TELEM_ENABLE_PERIODIC(telem_ctrl);
 		telem_ctrl |= ioss_period;
 
-		ret = intel_pmc_ipc_command(PMC_IPC_PMC_TELEMTRY,
-					    IOSS_TELEM_EVENT_CTL_WRITE,
-					    (u8 *)&telem_ctrl,
-					    IOSS_TELEM_EVT_CTRL_WRITE_SIZE,
-					    NULL, 0);
+		ret = telem_pmc_cmd(pmc_ipc_dev, PMC_IPC_PMC_TELEMTRY,
+				    IOSS_TELEM_EVENT_CTL_WRITE,
+				    (u8 *)&telem_ctrl, NULL);
 		if (ret) {
 			pr_err("IOSS TELEM_CTRL Event Enable Write Failed\n");
 			goto out;
@@ -1054,9 +1052,9 @@ static int telemetry_plt_get_trace_verbosity(enum telemetry_unit telem_unit,
 		break;
 
 	case TELEM_IOSS:
-		ret = intel_pmc_ipc_command(PMC_IPC_PMC_TELEMTRY,
-				IOSS_TELEM_TRACE_CTL_READ, NULL, 0, &temp,
-				IOSS_TELEM_READ_WORD);
+		ret = telem_pmc_cmd(pmc_ipc_dev, PMC_IPC_PMC_TELEMTRY,
+				    IOSS_TELEM_TRACE_CTL_READ,
+				    NULL, &temp);
 		if (ret) {
 			pr_err("IOSS TRACE_CTL Read Failed\n");
 			goto out;
@@ -1107,9 +1105,9 @@ static int telemetry_plt_set_trace_verbosity(enum telemetry_unit telem_unit,
 		break;
 
 	case TELEM_IOSS:
-		ret = intel_pmc_ipc_command(PMC_IPC_PMC_TELEMTRY,
-				IOSS_TELEM_TRACE_CTL_READ, NULL, 0, &temp,
-				IOSS_TELEM_READ_WORD);
+		ret = telem_pmc_cmd(pmc_ipc_dev, PMC_IPC_PMC_TELEMTRY,
+				    IOSS_TELEM_TRACE_CTL_READ,
+				    NULL, &temp);
 		if (ret) {
 			pr_err("IOSS TRACE_CTL Read Failed\n");
 			goto out;
@@ -1117,10 +1115,9 @@ static int telemetry_plt_set_trace_verbosity(enum telemetry_unit telem_unit,
 
 		TELEM_CLEAR_VERBOSITY_BITS(temp);
 		TELEM_SET_VERBOSITY_BITS(temp, verbosity);
-
-		ret = intel_pmc_ipc_command(PMC_IPC_PMC_TELEMTRY,
-				IOSS_TELEM_TRACE_CTL_WRITE, (u8 *)&temp,
-				IOSS_TELEM_WRITE_FOURBYTES, NULL, 0);
+		ret = telem_pmc_cmd(pmc_ipc_dev, PMC_IPC_PMC_TELEMTRY,
+				    IOSS_TELEM_TRACE_CTL_WRITE,
+				    (u8 *)&temp, NULL);
 		if (ret) {
 			pr_err("IOSS TRACE_CTL Verbosity Set Failed\n");
 			goto out;
@@ -1165,6 +1162,10 @@ static int telemetry_pltdrv_probe(struct platform_device *pdev)
 	if (IS_ERR_OR_NULL(punit_ipc_dev))
 		return PTR_ERR(punit_ipc_dev);
 
+	pmc_ipc_dev = intel_ipc_dev_get(INTEL_PMC_IPC_DEV);
+	if (IS_ERR_OR_NULL(pmc_ipc_dev))
+		return PTR_ERR(pmc_ipc_dev);
+
 	telm_conf = (struct telemetry_plt_config *)id->driver_data;
 
 	res0 = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -1244,6 +1245,7 @@ static int telemetry_pltdrv_probe(struct platform_device *pdev)
 static int telemetry_pltdrv_remove(struct platform_device *pdev)
 {
 	telemetry_clear_pltdata();
+	intel_ipc_dev_put(pmc_ipc_dev);
 	intel_ipc_dev_put(punit_ipc_dev);
 	iounmap(telm_conf->pss_config.regmap);
 	iounmap(telm_conf->ioss_config.regmap);
diff --git a/include/linux/mfd/intel_soc_pmic.h b/include/linux/mfd/intel_soc_pmic.h
index 5aacdb0..7cc39b6 100644
--- a/include/linux/mfd/intel_soc_pmic.h
+++ b/include/linux/mfd/intel_soc_pmic.h
@@ -20,6 +20,7 @@
 #define __INTEL_SOC_PMIC_H__
 
 #include <linux/regmap.h>
+#include <linux/platform_data/x86/intel_ipc_dev.h>
 
 struct intel_soc_pmic {
 	int irq;
@@ -31,6 +32,7 @@ struct intel_soc_pmic {
 	struct regmap_irq_chip_data *irq_chip_data_chgr;
 	struct regmap_irq_chip_data *irq_chip_data_crit;
 	struct device *dev;
+	struct intel_ipc_dev *ipc_dev;
 };
 
 #endif	/* __INTEL_SOC_PMIC_H__ */
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [RFC v8 7/7] platform/x86: intel_scu_ipc: Use generic Intel IPC device calls
  2017-10-29  9:49 ` sathyanarayanan.kuppuswamy
@ 2017-10-29  9:50   ` sathyanarayanan.kuppuswamy
  -1 siblings, 0 replies; 30+ messages in thread
From: sathyanarayanan.kuppuswamy @ 2017-10-29  9:50 UTC (permalink / raw)
  To: a.zummo, x86, wim, mingo, alexandre.belloni, qipeng.zha, hpa,
	dvhart, tglx, lee.jones, andy, souvik.k.chakravarty
  Cc: linux-rtc, linux-watchdog, linux-kernel, platform-driver-x86,
	sathyaosid, Kuppuswamy Sathyanarayanan

From: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>

Removed redundant IPC helper functions and refactored the driver to use
generic IPC device driver APIs.

This patch also cleans-up SCU IPC user drivers(rtc-mrst.c, intel-mid_wdt.c,
intel-mid_wdt.c, intel-mid.c) to use APIs provided by generic IPC driver.

Signed-off-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>
Acked-by: Alexandre Belloni <alexandre.belloni@free-electrons.com>
---
 arch/x86/include/asm/intel_scu_ipc.h    |  10 +-
 arch/x86/platform/intel-mid/intel-mid.c |  15 +-
 drivers/platform/x86/Kconfig            |   1 +
 drivers/platform/x86/intel_scu_ipc.c    | 488 ++++++++++++++------------------
 drivers/rtc/rtc-mrst.c                  |  16 +-
 drivers/watchdog/intel-mid_wdt.c        |  18 +-
 drivers/watchdog/intel_scu_watchdog.c   |  23 +-
 7 files changed, 267 insertions(+), 304 deletions(-)

Changes since v7:
 * Fixed some style issues.

Changes since v6:
 * Fixed some style issues.

Changes since v5:
 * Adapted to change in arguments of ipc_dev_cmd() and ipc_dev_raw_cmd() APIs.

Changes since v4:
 * None

Changes since v3:
 * Added intel_ipc_dev_put() support.

diff --git a/arch/x86/include/asm/intel_scu_ipc.h b/arch/x86/include/asm/intel_scu_ipc.h
index 81d3d87..68b5c77 100644
--- a/arch/x86/include/asm/intel_scu_ipc.h
+++ b/arch/x86/include/asm/intel_scu_ipc.h
@@ -18,6 +18,9 @@
 	#define IPC_CMD_VRTC_SETTIME      1 /* Set time */
 	#define IPC_CMD_VRTC_SETALARM     2 /* Set alarm */
 
+#define INTEL_SCU_IPC_DEV	"intel_scu_ipc"
+#define SCU_PARAM_LEN		2
+
 /* Read single register */
 int intel_scu_ipc_ioread8(u16 addr, u8 *data);
 
@@ -45,13 +48,6 @@ int intel_scu_ipc_writev(u16 *addr, u8 *data, int len);
 /* Update single register based on the mask */
 int intel_scu_ipc_update_register(u16 addr, u8 data, u8 mask);
 
-/* Issue commands to the SCU with or without data */
-int intel_scu_ipc_simple_command(int cmd, int sub);
-int intel_scu_ipc_command(int cmd, int sub, u32 *in, int inlen,
-			  u32 *out, int outlen);
-int intel_scu_ipc_raw_command(int cmd, int sub, u8 *in, int inlen,
-			      u32 *out, int outlen, u32 dptr, u32 sptr);
-
 /* I2C control api */
 int intel_scu_ipc_i2c_cntrl(u32 addr, u32 *data);
 
diff --git a/arch/x86/platform/intel-mid/intel-mid.c b/arch/x86/platform/intel-mid/intel-mid.c
index 86676ce..23b3ab3 100644
--- a/arch/x86/platform/intel-mid/intel-mid.c
+++ b/arch/x86/platform/intel-mid/intel-mid.c
@@ -22,6 +22,7 @@
 #include <linux/irq.h>
 #include <linux/export.h>
 #include <linux/notifier.h>
+#include <linux/platform_data/x86/intel_ipc_dev.h>
 
 #include <asm/setup.h>
 #include <asm/mpspec_def.h>
@@ -70,16 +71,26 @@ EXPORT_SYMBOL_GPL(__intel_mid_cpu_chip);
 
 static void intel_mid_power_off(void)
 {
+	struct intel_ipc_dev *ipc_dev;
+	u32 cmds[SCU_PARAM_LEN] = {IPCMSG_COLD_OFF, 1};
+
 	/* Shut down South Complex via PWRMU */
 	intel_mid_pwr_power_off();
 
+	ipc_dev = intel_ipc_dev_get(INTEL_SCU_IPC_DEV);
 	/* Only for Tangier, the rest will ignore this command */
-	intel_scu_ipc_simple_command(IPCMSG_COLD_OFF, 1);
+	ipc_dev_simple_cmd(ipc_dev, cmds, SCU_PARAM_LEN);
+	intel_ipc_dev_put(ipc_dev);
 };
 
 static void intel_mid_reboot(void)
 {
-	intel_scu_ipc_simple_command(IPCMSG_COLD_BOOT, 0);
+	struct intel_ipc_dev *ipc_dev;
+	u32 cmds[SCU_PARAM_LEN] = {IPCMSG_COLD_BOOT, 0};
+
+	ipc_dev = intel_ipc_dev_get(INTEL_SCU_IPC_DEV);
+	ipc_dev_simple_cmd(ipc_dev, cmds, SCU_PARAM_LEN);
+	intel_ipc_dev_put(ipc_dev);
 }
 
 static unsigned long __init intel_mid_calibrate_tsc(void)
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
index 82479ca..e4e5822 100644
--- a/drivers/platform/x86/Kconfig
+++ b/drivers/platform/x86/Kconfig
@@ -850,6 +850,7 @@ config INTEL_VBTN
 config INTEL_SCU_IPC
 	bool "Intel SCU IPC Support"
 	depends on X86_INTEL_MID
+	select REGMAP_MMIO
 	default y
 	---help---
 	  IPC is used to bridge the communications between kernel and SCU on
diff --git a/drivers/platform/x86/intel_scu_ipc.c b/drivers/platform/x86/intel_scu_ipc.c
index 2c85f75..21607e0 100644
--- a/drivers/platform/x86/intel_scu_ipc.c
+++ b/drivers/platform/x86/intel_scu_ipc.c
@@ -24,6 +24,8 @@
 #include <linux/pci.h>
 #include <linux/interrupt.h>
 #include <linux/sfi.h>
+#include <linux/regmap.h>
+#include <linux/platform_data/x86/intel_ipc_dev.h>
 #include <asm/intel-mid.h>
 #include <asm/intel_scu_ipc.h>
 
@@ -39,6 +41,25 @@
 #define IPC_CMD_PCNTRL_R      1 /* Register read */
 #define IPC_CMD_PCNTRL_M      2 /* Register read-modify-write */
 
+/* IPC dev register offsets */
+/*
+ * IPC Read Buffer (Read Only):
+ * 16 byte buffer for receiving data from SCU, if IPC command
+ * processing results in response data
+ */
+#define IPC_DEV_SCU_RBUF_OFFSET			0x90
+#define IPC_DEV_SCU_WRBUF_OFFSET		0x80
+#define IPC_DEV_SCU_SPTR_OFFSET			0x08
+#define IPC_DEV_SCU_DPTR_OFFSET			0x0C
+#define IPC_DEV_SCU_STATUS_OFFSET		0x04
+
+/* IPC dev commands */
+/* IPC command register IOC bit */
+#define	IPC_DEV_SCU_CMD_MSI			BIT(8)
+#define	IPC_DEV_SCU_CMD_STATUS_ERR		BIT(1)
+#define	IPC_DEV_SCU_CMD_STATUS_ERR_MASK		GENMASK(7, 0)
+#define	IPC_DEV_SCU_CMD_STATUS_BUSY		BIT(0)
+
 /*
  * IPC register summary
  *
@@ -59,6 +80,11 @@
 #define IPC_WWBUF_SIZE    20		/* IPC Write buffer Size */
 #define IPC_RWBUF_SIZE    20		/* IPC Read buffer Size */
 #define IPC_IOC	          0x100		/* IPC command register IOC bit */
+#define	IPC_CMD_SIZE            16
+#define	IPC_CMD_SUBCMD          12
+#define	IPC_RWBUF_SIZE_DWORD    5
+#define	IPC_WWBUF_SIZE_DWORD    5
+
 
 #define PCI_DEVICE_ID_LINCROFT		0x082a
 #define PCI_DEVICE_ID_PENWELL		0x080e
@@ -93,120 +119,50 @@ static const struct intel_scu_ipc_pdata_t intel_scu_ipc_tangier_pdata = {
 
 struct intel_scu_ipc_dev {
 	struct device *dev;
+	struct intel_ipc_dev *ipc_dev;
 	void __iomem *ipc_base;
 	void __iomem *i2c_base;
-	struct completion cmd_complete;
+	struct regmap *ipc_regs;
+	struct regmap *i2c_regs;
 	u8 irq_mode;
 };
 
-static struct intel_scu_ipc_dev  ipcdev; /* Only one for now */
+static struct regmap_config ipc_regmap_config = {
+	.reg_bits = 32,
+	.reg_stride = 4,
+	.val_bits = 32,
+};
 
-/*
- * IPC Read Buffer (Read Only):
- * 16 byte buffer for receiving data from SCU, if IPC command
- * processing results in response data
- */
-#define IPC_READ_BUFFER		0x90
+static struct regmap_config i2c_regmap_config = {
+	.reg_bits = 32,
+	.reg_stride = 4,
+	.val_bits = 32,
+	.fast_io = true,
+};
+
+static struct intel_scu_ipc_dev  ipcdev; /* Only one for now */
 
 #define IPC_I2C_CNTRL_ADDR	0
 #define I2C_DATA_ADDR		0x04
 
-static DEFINE_MUTEX(ipclock); /* lock used to prevent multiple call to SCU */
-
-/*
- * Send ipc command
- * Command Register (Write Only):
- * A write to this register results in an interrupt to the SCU core processor
- * Format:
- * |rfu2(8) | size(8) | command id(4) | rfu1(3) | ioc(1) | command(8)|
- */
-static inline void ipc_command(struct intel_scu_ipc_dev *scu, u32 cmd)
+static int scu_ipc_cmd(u32 cmd, u32 sub, u8 *in, u32 inlen, u32 *out,
+		       u32 outlen)
 {
-	if (scu->irq_mode) {
-		reinit_completion(&scu->cmd_complete);
-		writel(cmd | IPC_IOC, scu->ipc_base);
-	}
-	writel(cmd, scu->ipc_base);
-}
-
-/*
- * Write ipc data
- * IPC Write Buffer (Write Only):
- * 16-byte buffer for sending data associated with IPC command to
- * SCU. Size of the data is specified in the IPC_COMMAND_REG register
- */
-static inline void ipc_data_writel(struct intel_scu_ipc_dev *scu, u32 data, u32 offset)
-{
-	writel(data, scu->ipc_base + 0x80 + offset);
-}
-
-/*
- * Status Register (Read Only):
- * Driver will read this register to get the ready/busy status of the IPC
- * block and error status of the IPC command that was just processed by SCU
- * Format:
- * |rfu3(8)|error code(8)|initiator id(8)|cmd id(4)|rfu1(2)|error(1)|busy(1)|
- */
-static inline u8 ipc_read_status(struct intel_scu_ipc_dev *scu)
-{
-	return __raw_readl(scu->ipc_base + 0x04);
-}
-
-/* Read ipc byte data */
-static inline u8 ipc_data_readb(struct intel_scu_ipc_dev *scu, u32 offset)
-{
-	return readb(scu->ipc_base + IPC_READ_BUFFER + offset);
-}
-
-/* Read ipc u32 data */
-static inline u32 ipc_data_readl(struct intel_scu_ipc_dev *scu, u32 offset)
-{
-	return readl(scu->ipc_base + IPC_READ_BUFFER + offset);
-}
-
-/* Wait till scu status is busy */
-static inline int busy_loop(struct intel_scu_ipc_dev *scu)
-{
-	u32 status = ipc_read_status(scu);
-	u32 loop_count = 100000;
-
-	/* break if scu doesn't reset busy bit after huge retry */
-	while ((status & BIT(0)) && --loop_count) {
-		udelay(1); /* scu processing time is in few u secods */
-		status = ipc_read_status(scu);
-	}
-
-	if (status & BIT(0)) {
-		dev_err(scu->dev, "IPC timed out");
-		return -ETIMEDOUT;
-	}
-
-	if (status & BIT(1))
-		return -EIO;
-
-	return 0;
-}
-
-/* Wait till ipc ioc interrupt is received or timeout in 3 HZ */
-static inline int ipc_wait_for_interrupt(struct intel_scu_ipc_dev *scu)
-{
-	int status;
+	struct intel_scu_ipc_dev *scu = &ipcdev;
+	struct intel_ipc_raw_cmd ipc_raw_cmd = {0};
+	u32 cmd_list[SCU_PARAM_LEN] = {0};
 
-	if (!wait_for_completion_timeout(&scu->cmd_complete, 3 * HZ)) {
-		dev_err(scu->dev, "IPC timed out\n");
-		return -ETIMEDOUT;
-	}
+	cmd_list[0] = cmd;
+	cmd_list[1] = sub;
 
-	status = ipc_read_status(scu);
-	if (status & BIT(1))
-		return -EIO;
-
-	return 0;
-}
+	ipc_raw_cmd.cmd_list = cmd_list;
+	ipc_raw_cmd.cmdlen = SCU_PARAM_LEN;
+	ipc_raw_cmd.in = in;
+	ipc_raw_cmd.inlen = inlen;
+	ipc_raw_cmd.out = out;
+	ipc_raw_cmd.outlen = outlen;
 
-static int intel_scu_ipc_check_status(struct intel_scu_ipc_dev *scu)
-{
-	return scu->irq_mode ? ipc_wait_for_interrupt(scu) : busy_loop(scu);
+	return ipc_dev_raw_cmd(scu->ipc_dev, &ipc_raw_cmd);
 }
 
 /* Read/Write power control(PMIC in Langwell, MSIC in PenWell) registers */
@@ -215,49 +171,42 @@ static int pwr_reg_rdwr(u16 *addr, u8 *data, u32 count, u32 op, u32 id)
 	struct intel_scu_ipc_dev *scu = &ipcdev;
 	int nc;
 	u32 offset = 0;
-	int err;
+	int err = -EIO;
 	u8 cbuf[IPC_WWBUF_SIZE];
 	u32 *wbuf = (u32 *)&cbuf;
+	/* max rbuf size is 20 bytes */
+	u8 rbuf[IPC_RWBUF_SIZE] = {0};
+	u32 rbuflen = DIV_ROUND_UP(count, 4);
 
 	memset(cbuf, 0, sizeof(cbuf));
 
-	mutex_lock(&ipclock);
-
-	if (scu->dev == NULL) {
-		mutex_unlock(&ipclock);
-		return -ENODEV;
-	}
-
 	for (nc = 0; nc < count; nc++, offset += 2) {
 		cbuf[offset] = addr[nc];
 		cbuf[offset + 1] = addr[nc] >> 8;
 	}
 
 	if (id == IPC_CMD_PCNTRL_R) {
-		for (nc = 0, offset = 0; nc < count; nc++, offset += 4)
-			ipc_data_writel(scu, wbuf[nc], offset);
-		ipc_command(scu, (count * 2) << 16 | id << 12 | 0 << 8 | op);
+		err = scu_ipc_cmd(op, id, (u8 *)wbuf, count * 2,
+				  (u32 *)rbuf, IPC_RWBUF_SIZE_DWORD);
 	} else if (id == IPC_CMD_PCNTRL_W) {
 		for (nc = 0; nc < count; nc++, offset += 1)
 			cbuf[offset] = data[nc];
-		for (nc = 0, offset = 0; nc < count; nc++, offset += 4)
-			ipc_data_writel(scu, wbuf[nc], offset);
-		ipc_command(scu, (count * 3) << 16 | id << 12 | 0 << 8 | op);
+		err = scu_ipc_cmd(op, id, (u8 *)wbuf, count * 3, NULL, 0);
+
 	} else if (id == IPC_CMD_PCNTRL_M) {
 		cbuf[offset] = data[0];
 		cbuf[offset + 1] = data[1];
-		ipc_data_writel(scu, wbuf[0], 0); /* Write wbuff */
-		ipc_command(scu, 4 << 16 | id << 12 | 0 << 8 | op);
+		err = scu_ipc_cmd(op, id, (u8 *)wbuf, 4, NULL, 0);
 	}
 
-	err = intel_scu_ipc_check_status(scu);
 	if (!err && id == IPC_CMD_PCNTRL_R) { /* Read rbuf */
 		/* Workaround: values are read as 0 without memcpy_fromio */
 		memcpy_fromio(cbuf, scu->ipc_base + 0x90, 16);
-		for (nc = 0; nc < count; nc++)
-			data[nc] = ipc_data_readb(scu, nc);
+		regmap_bulk_read(scu->ipc_regs, IPC_DEV_SCU_RBUF_OFFSET, rbuf,
+				 rbuflen);
+		memcpy(data, rbuf, count);
 	}
-	mutex_unlock(&ipclock);
+
 	return err;
 }
 
@@ -422,138 +371,6 @@ int intel_scu_ipc_update_register(u16 addr, u8 bits, u8 mask)
 }
 EXPORT_SYMBOL(intel_scu_ipc_update_register);
 
-/**
- *	intel_scu_ipc_simple_command	-	send a simple command
- *	@cmd: command
- *	@sub: sub type
- *
- *	Issue a simple command to the SCU. Do not use this interface if
- *	you must then access data as any data values may be overwritten
- *	by another SCU access by the time this function returns.
- *
- *	This function may sleep. Locking for SCU accesses is handled for
- *	the caller.
- */
-int intel_scu_ipc_simple_command(int cmd, int sub)
-{
-	struct intel_scu_ipc_dev *scu = &ipcdev;
-	int err;
-
-	mutex_lock(&ipclock);
-	if (scu->dev == NULL) {
-		mutex_unlock(&ipclock);
-		return -ENODEV;
-	}
-	ipc_command(scu, sub << 12 | cmd);
-	err = intel_scu_ipc_check_status(scu);
-	mutex_unlock(&ipclock);
-	return err;
-}
-EXPORT_SYMBOL(intel_scu_ipc_simple_command);
-
-/**
- *	intel_scu_ipc_command	-	command with data
- *	@cmd: command
- *	@sub: sub type
- *	@in: input data
- *	@inlen: input length in dwords
- *	@out: output data
- *	@outlein: output length in dwords
- *
- *	Issue a command to the SCU which involves data transfers. Do the
- *	data copies under the lock but leave it for the caller to interpret
- */
-int intel_scu_ipc_command(int cmd, int sub, u32 *in, int inlen,
-			  u32 *out, int outlen)
-{
-	struct intel_scu_ipc_dev *scu = &ipcdev;
-	int i, err;
-
-	mutex_lock(&ipclock);
-	if (scu->dev == NULL) {
-		mutex_unlock(&ipclock);
-		return -ENODEV;
-	}
-
-	for (i = 0; i < inlen; i++)
-		ipc_data_writel(scu, *in++, 4 * i);
-
-	ipc_command(scu, (inlen << 16) | (sub << 12) | cmd);
-	err = intel_scu_ipc_check_status(scu);
-
-	if (!err) {
-		for (i = 0; i < outlen; i++)
-			*out++ = ipc_data_readl(scu, 4 * i);
-	}
-
-	mutex_unlock(&ipclock);
-	return err;
-}
-EXPORT_SYMBOL(intel_scu_ipc_command);
-
-#define IPC_SPTR		0x08
-#define IPC_DPTR		0x0C
-
-/**
- * intel_scu_ipc_raw_command() - IPC command with data and pointers
- * @cmd:	IPC command code.
- * @sub:	IPC command sub type.
- * @in:		input data of this IPC command.
- * @inlen:	input data length in dwords.
- * @out:	output data of this IPC command.
- * @outlen:	output data length in dwords.
- * @sptr:	data writing to SPTR register.
- * @dptr:	data writing to DPTR register.
- *
- * Send an IPC command to SCU with input/output data and source/dest pointers.
- *
- * Return:	an IPC error code or 0 on success.
- */
-int intel_scu_ipc_raw_command(int cmd, int sub, u8 *in, int inlen,
-			      u32 *out, int outlen, u32 dptr, u32 sptr)
-{
-	struct intel_scu_ipc_dev *scu = &ipcdev;
-	int inbuflen = DIV_ROUND_UP(inlen, 4);
-	u32 inbuf[4];
-	int i, err;
-
-	/* Up to 16 bytes */
-	if (inbuflen > 4)
-		return -EINVAL;
-
-	mutex_lock(&ipclock);
-	if (scu->dev == NULL) {
-		mutex_unlock(&ipclock);
-		return -ENODEV;
-	}
-
-	writel(dptr, scu->ipc_base + IPC_DPTR);
-	writel(sptr, scu->ipc_base + IPC_SPTR);
-
-	/*
-	 * SRAM controller doesn't support 8-bit writes, it only
-	 * supports 32-bit writes, so we have to copy input data into
-	 * the temporary buffer, and SCU FW will use the inlen to
-	 * determine the actual input data length in the temporary
-	 * buffer.
-	 */
-	memcpy(inbuf, in, inlen);
-
-	for (i = 0; i < inbuflen; i++)
-		ipc_data_writel(scu, inbuf[i], 4 * i);
-
-	ipc_command(scu, (inlen << 16) | (sub << 12) | cmd);
-	err = intel_scu_ipc_check_status(scu);
-	if (!err) {
-		for (i = 0; i < outlen; i++)
-			*out++ = ipc_data_readl(scu, 4 * i);
-	}
-
-	mutex_unlock(&ipclock);
-	return err;
-}
-EXPORT_SYMBOL_GPL(intel_scu_ipc_raw_command);
-
 /* I2C commands */
 #define IPC_I2C_WRITE 1 /* I2C Write command */
 #define IPC_I2C_READ  2 /* I2C Read command */
@@ -575,48 +392,143 @@ int intel_scu_ipc_i2c_cntrl(u32 addr, u32 *data)
 	struct intel_scu_ipc_dev *scu = &ipcdev;
 	u32 cmd = 0;
 
-	mutex_lock(&ipclock);
-	if (scu->dev == NULL) {
-		mutex_unlock(&ipclock);
-		return -ENODEV;
-	}
 	cmd = (addr >> 24) & 0xFF;
 	if (cmd == IPC_I2C_READ) {
-		writel(addr, scu->i2c_base + IPC_I2C_CNTRL_ADDR);
+		regmap_write(scu->i2c_regs, IPC_I2C_CNTRL_ADDR, addr);
 		/* Write not getting updated without delay */
 		mdelay(1);
-		*data = readl(scu->i2c_base + I2C_DATA_ADDR);
+		regmap_read(scu->i2c_regs, I2C_DATA_ADDR, data);
 	} else if (cmd == IPC_I2C_WRITE) {
-		writel(*data, scu->i2c_base + I2C_DATA_ADDR);
+		regmap_write(scu->i2c_regs, I2C_DATA_ADDR, *data);
 		mdelay(1);
-		writel(addr, scu->i2c_base + IPC_I2C_CNTRL_ADDR);
+		regmap_write(scu->i2c_regs, IPC_I2C_CNTRL_ADDR, addr);
 	} else {
 		dev_err(scu->dev,
 			"intel_scu_ipc: I2C INVALID_CMD = 0x%x\n", cmd);
 
-		mutex_unlock(&ipclock);
 		return -EIO;
 	}
-	mutex_unlock(&ipclock);
 	return 0;
 }
 EXPORT_SYMBOL(intel_scu_ipc_i2c_cntrl);
 
-/*
- * Interrupt handler gets called when ioc bit of IPC_COMMAND_REG set to 1
- * When ioc bit is set to 1, caller api must wait for interrupt handler called
- * which in turn unlocks the caller api. Currently this is not used
- *
- * This is edge triggered so we need take no action to clear anything
- */
-static irqreturn_t ioc(int irq, void *dev_id)
+static int pre_simple_cmd_fn(u32 *cmd_list, u32 cmdlen)
 {
-	struct intel_scu_ipc_dev *scu = dev_id;
+	if (!cmd_list || cmdlen != SCU_PARAM_LEN)
+		return -EINVAL;
 
-	if (scu->irq_mode)
-		complete(&scu->cmd_complete);
+	cmd_list[0] |= (cmd_list[1] << IPC_CMD_SUBCMD);
+
+	return 0;
+}
+
+static int pre_cmd_fn(struct intel_ipc_cmd *ipc_cmd)
+{
+	int ret;
 
-	return IRQ_HANDLED;
+	if (ipc_cmd->inlen > IPC_WWBUF_SIZE_DWORD ||
+	    ipc_cmd->outlen > IPC_RWBUF_SIZE_DWORD)
+		return -EINVAL;
+
+	ret = pre_simple_cmd_fn(ipc_cmd->cmd_list, ipc_cmd->cmdlen);
+	if (ret < 0)
+		return ret;
+
+	ipc_cmd->cmd_list[0] |= (ipc_cmd->inlen << IPC_CMD_SIZE);
+
+	return 0;
+}
+
+static int pre_raw_cmd_fn(struct intel_ipc_raw_cmd *ipc_raw_cmd)
+{
+	int ret;
+
+	if (ipc_raw_cmd->inlen > IPC_WWBUF_SIZE ||
+	    ipc_raw_cmd->outlen > IPC_RWBUF_SIZE_DWORD)
+		return -EINVAL;
+
+	ret = pre_simple_cmd_fn(ipc_raw_cmd->cmd_list, ipc_raw_cmd->cmdlen);
+	if (ret < 0)
+		return ret;
+
+	ipc_raw_cmd->cmd_list[0] |= (ipc_raw_cmd->inlen << IPC_CMD_SIZE);
+
+	return 0;
+}
+
+static int scu_ipc_err_code(int status)
+{
+	if (status & IPC_DEV_SCU_CMD_STATUS_ERR)
+		return (status & IPC_DEV_SCU_CMD_STATUS_ERR_MASK);
+	else
+		return 0;
+}
+
+static int scu_ipc_busy_check(int status)
+{
+	return status | IPC_DEV_SCU_CMD_STATUS_BUSY;
+}
+
+static u32 scu_ipc_enable_msi(u32 cmd)
+{
+	return cmd | IPC_DEV_SCU_CMD_MSI;
+}
+
+static struct intel_ipc_dev *intel_scu_ipc_dev_create(
+		struct device *dev,
+		void __iomem *base,
+		int irq)
+{
+	struct intel_ipc_dev_ops *ops;
+	struct intel_ipc_dev_cfg *cfg;
+	struct regmap *ipc_regs;
+	struct intel_scu_ipc_dev *scu = dev_get_drvdata(dev);
+
+	cfg = devm_kzalloc(dev, sizeof(*cfg), GFP_KERNEL);
+	if (!cfg)
+		return ERR_PTR(-ENOMEM);
+
+	ops = devm_kzalloc(dev, sizeof(*ops), GFP_KERNEL);
+	if (!ops)
+		return ERR_PTR(-ENOMEM);
+
+	ipc_regs = devm_regmap_init_mmio_clk(dev, NULL, base,
+					     &ipc_regmap_config);
+	if (IS_ERR(ipc_regs)) {
+		dev_err(dev, "ipc_regs regmap init failed\n");
+		return ERR_CAST(ipc_regs);
+	}
+
+	scu->ipc_regs = ipc_regs;
+
+	/* set IPC dev ops */
+	ops->to_err_code = scu_ipc_err_code;
+	ops->busy_check = scu_ipc_busy_check;
+	ops->enable_msi = scu_ipc_enable_msi;
+	ops->pre_cmd_fn = pre_cmd_fn;
+	ops->pre_raw_cmd_fn = pre_raw_cmd_fn;
+	ops->pre_simple_cmd_fn = pre_simple_cmd_fn;
+
+	/* set cfg options */
+	if (scu->irq_mode)
+		cfg->mode = IPC_DEV_MODE_IRQ;
+	else
+		cfg->mode = IPC_DEV_MODE_POLLING;
+
+	cfg->chan_type = IPC_CHANNEL_IA_SCU;
+	cfg->irq = irq;
+	cfg->use_msi = true;
+	cfg->support_sptr = true;
+	cfg->support_dptr = true;
+	cfg->cmd_regs = ipc_regs;
+	cfg->data_regs = ipc_regs;
+	cfg->wrbuf_reg = IPC_DEV_SCU_WRBUF_OFFSET;
+	cfg->rbuf_reg = IPC_DEV_SCU_RBUF_OFFSET;
+	cfg->sptr_reg = IPC_DEV_SCU_SPTR_OFFSET;
+	cfg->dptr_reg = IPC_DEV_SCU_DPTR_OFFSET;
+	cfg->status_reg = IPC_DEV_SCU_STATUS_OFFSET;
+
+	return devm_intel_ipc_dev_create(dev, INTEL_SCU_IPC_DEV, cfg, ops);
 }
 
 /**
@@ -650,25 +562,35 @@ static int ipc_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 	if (err)
 		return err;
 
-	init_completion(&scu->cmd_complete);
-
 	scu->ipc_base = pcim_iomap_table(pdev)[0];
 
-	scu->i2c_base = ioremap_nocache(pdata->i2c_base, pdata->i2c_len);
+	scu->i2c_base = devm_ioremap_nocache(&pdev->dev, pdata->i2c_base,
+					     pdata->i2c_len);
 	if (!scu->i2c_base)
 		return -ENOMEM;
 
-	err = devm_request_irq(&pdev->dev, pdev->irq, ioc, 0, "intel_scu_ipc",
-			       scu);
-	if (err)
-		return err;
+	pci_set_drvdata(pdev, scu);
+
+	scu->i2c_regs = devm_regmap_init_mmio_clk(&pdev->dev, NULL,
+						  scu->i2c_base,
+						  &i2c_regmap_config);
+	if (IS_ERR(scu->i2c_regs)) {
+		dev_err(&pdev->dev, "i2c_regs regmap init failed\n");
+		return PTR_ERR(scu->i2c_regs);
+	}
+
+	scu->ipc_dev = intel_scu_ipc_dev_create(&pdev->dev, scu->ipc_base,
+						pdev->irq);
+	if (IS_ERR(scu->ipc_dev)) {
+		dev_err(&pdev->dev, "Failed to create SCU IPC device\n");
+		return PTR_ERR(scu->ipc_dev);
+	}
 
 	/* Assign device at last */
 	scu->dev = &pdev->dev;
 
 	intel_scu_devices_create();
 
-	pci_set_drvdata(pdev, scu);
 	return 0;
 }
 
diff --git a/drivers/rtc/rtc-mrst.c b/drivers/rtc/rtc-mrst.c
index 7334c44..37595c4 100644
--- a/drivers/rtc/rtc-mrst.c
+++ b/drivers/rtc/rtc-mrst.c
@@ -36,6 +36,7 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/sfi.h>
+#include <linux/platform_data/x86/intel_ipc_dev.h>
 
 #include <asm/intel_scu_ipc.h>
 #include <asm/intel-mid.h>
@@ -46,6 +47,7 @@ struct mrst_rtc {
 	struct device		*dev;
 	int			irq;
 	struct resource		*iomem;
+	struct intel_ipc_dev	*ipc_dev;
 
 	u8			enabled_wake;
 	u8			suspend_ctrl;
@@ -110,10 +112,11 @@ static int mrst_read_time(struct device *dev, struct rtc_time *time)
 
 static int mrst_set_time(struct device *dev, struct rtc_time *time)
 {
-	int ret;
 	unsigned long flags;
 	unsigned char mon, day, hrs, min, sec;
 	unsigned int yrs;
+	struct mrst_rtc	*mrst = dev_get_drvdata(dev);
+	u32 cmds[SCU_PARAM_LEN] = {IPCMSG_VRTC, IPC_CMD_VRTC_SETTIME};
 
 	yrs = time->tm_year;
 	mon = time->tm_mon + 1;   /* tm_mon starts at zero */
@@ -137,8 +140,7 @@ static int mrst_set_time(struct device *dev, struct rtc_time *time)
 
 	spin_unlock_irqrestore(&rtc_lock, flags);
 
-	ret = intel_scu_ipc_simple_command(IPCMSG_VRTC, IPC_CMD_VRTC_SETTIME);
-	return ret;
+	return ipc_dev_simple_cmd(mrst->ipc_dev, cmds, SCU_PARAM_LEN);
 }
 
 static int mrst_read_alarm(struct device *dev, struct rtc_wkalrm *t)
@@ -210,6 +212,7 @@ static int mrst_set_alarm(struct device *dev, struct rtc_wkalrm *t)
 	struct mrst_rtc	*mrst = dev_get_drvdata(dev);
 	unsigned char hrs, min, sec;
 	int ret = 0;
+	u32 cmds[SCU_PARAM_LEN] = {IPCMSG_VRTC, IPC_CMD_VRTC_SETALARM};
 
 	if (!mrst->irq)
 		return -EIO;
@@ -229,7 +232,7 @@ static int mrst_set_alarm(struct device *dev, struct rtc_wkalrm *t)
 
 	spin_unlock_irq(&rtc_lock);
 
-	ret = intel_scu_ipc_simple_command(IPCMSG_VRTC, IPC_CMD_VRTC_SETALARM);
+	ret = ipc_dev_simple_cmd(mrst->ipc_dev, cmds, SCU_PARAM_LEN);
 	if (ret)
 		return ret;
 
@@ -329,6 +332,10 @@ static int vrtc_mrst_do_probe(struct device *dev, struct resource *iomem,
 	if (!iomem)
 		return -ENODEV;
 
+	mrst_rtc.ipc_dev = intel_ipc_dev_get(INTEL_SCU_IPC_DEV);
+	if (IS_ERR_OR_NULL(mrst_rtc.ipc_dev))
+		return PTR_ERR(mrst_rtc.ipc_dev);
+
 	iomem = request_mem_region(iomem->start, resource_size(iomem),
 				   driver_name);
 	if (!iomem) {
@@ -394,6 +401,7 @@ static void rtc_mrst_do_remove(struct device *dev)
 
 	rtc_mrst_do_shutdown();
 
+	intel_ipc_dev_put(mrst->ipc_dev);
 	if (mrst->irq)
 		free_irq(mrst->irq, mrst->rtc);
 
diff --git a/drivers/watchdog/intel-mid_wdt.c b/drivers/watchdog/intel-mid_wdt.c
index 72c108a..d6f2993 100644
--- a/drivers/watchdog/intel-mid_wdt.c
+++ b/drivers/watchdog/intel-mid_wdt.c
@@ -18,6 +18,7 @@
 #include <linux/platform_device.h>
 #include <linux/watchdog.h>
 #include <linux/platform_data/intel-mid_wdt.h>
+#include <linux/platform_data/x86/intel_ipc_dev.h>
 
 #include <asm/intel_scu_ipc.h>
 #include <asm/intel-mid.h>
@@ -29,6 +30,8 @@
 #define MID_WDT_TIMEOUT_MAX		170
 #define MID_WDT_DEFAULT_TIMEOUT		90
 
+static struct intel_ipc_dev *scu_ipc_dev;
+
 /* SCU watchdog messages */
 enum {
 	SCU_WATCHDOG_START = 0,
@@ -38,7 +41,16 @@ enum {
 
 static inline int wdt_command(int sub, u32 *in, int inlen)
 {
-	return intel_scu_ipc_command(IPC_WATCHDOG, sub, in, inlen, NULL, 0);
+	u32 cmds[SCU_PARAM_LEN] = {IPC_WATCHDOG, sub};
+	struct intel_ipc_cmd ipc_cmd = {0};
+
+	ipc_cmd.cmd_list = cmds;
+	ipc_cmd.cmdlen = SCU_PARAM_LEN;
+	ipc_cmd.in = in;
+	ipc_cmd.out = NULL;
+	ipc_cmd.inlen = inlen;
+
+	return ipc_dev_cmd(scu_ipc_dev, &ipc_cmd);
 }
 
 static int wdt_start(struct watchdog_device *wd)
@@ -129,6 +141,10 @@ static int mid_wdt_probe(struct platform_device *pdev)
 	if (!wdt_dev)
 		return -ENOMEM;
 
+	scu_ipc_dev = devm_intel_ipc_dev_get(&pdev->dev, INTEL_SCU_IPC_DEV);
+	if (IS_ERR_OR_NULL(scu_ipc_dev))
+		return PTR_ERR(scu_ipc_dev);
+
 	wdt_dev->info = &mid_wdt_info;
 	wdt_dev->ops = &mid_wdt_ops;
 	wdt_dev->min_timeout = MID_WDT_TIMEOUT_MIN;
diff --git a/drivers/watchdog/intel_scu_watchdog.c b/drivers/watchdog/intel_scu_watchdog.c
index 0caab62..1210961a7 100644
--- a/drivers/watchdog/intel_scu_watchdog.c
+++ b/drivers/watchdog/intel_scu_watchdog.c
@@ -49,6 +49,7 @@
 #include <asm/intel_scu_ipc.h>
 #include <asm/apb_timer.h>
 #include <asm/intel-mid.h>
+#include <linux/platform_data/x86/intel_ipc_dev.h>
 
 #include "intel_scu_watchdog.h"
 
@@ -94,6 +95,8 @@ MODULE_PARM_DESC(force_boot,
 
 static struct intel_scu_watchdog_dev watchdog_device;
 
+static struct intel_ipc_dev *scu_ipc_dev;
+
 /* Forces restart, if force_reboot is set */
 static void watchdog_fire(void)
 {
@@ -128,19 +131,20 @@ static int watchdog_set_ipc(int soft_threshold, int threshold)
 	u32	*ipc_wbuf;
 	u8	 cbuf[16] = { '\0' };
 	int	 ipc_ret = 0;
+	u32 cmds[SCU_PARAM_LEN] = {IPC_SET_WATCHDOG_TIMER, 0};
+	struct intel_ipc_cmd ipc_cmd;
 
 	ipc_wbuf = (u32 *)&cbuf;
 	ipc_wbuf[0] = soft_threshold;
 	ipc_wbuf[1] = threshold;
 
-	ipc_ret = intel_scu_ipc_command(
-			IPC_SET_WATCHDOG_TIMER,
-			0,
-			ipc_wbuf,
-			2,
-			NULL,
-			0);
+	ipc_cmd.cmd_list = cmds;
+	ipc_cmd.cmdlen = SCU_PARAM_LEN;
+	ipc_cmd.in = ipc_wbuf;
+	ipc_cmd.inlen = 2;
+	ipc_cmd.out = NULL;
 
+	ipc_ret = ipc_dev_cmd(scu_ipc_dev, &ipc_cmd);
 	if (ipc_ret != 0)
 		pr_err("Error setting SCU watchdog timer: %x\n", ipc_ret);
 
@@ -460,6 +464,10 @@ static int __init intel_scu_watchdog_init(void)
 	if (check_timer_margin(timer_margin))
 		return -EINVAL;
 
+	scu_ipc_dev = intel_ipc_dev_get(INTEL_SCU_IPC_DEV);
+	if (IS_ERR_OR_NULL(scu_ipc_dev))
+		return PTR_ERR(scu_ipc_dev);
+
 	watchdog_device.timer_tbl_ptr = sfi_get_mtmr(sfi_mtimer_num-1);
 
 	if (watchdog_device.timer_tbl_ptr == NULL) {
@@ -550,6 +558,7 @@ static void __exit intel_scu_watchdog_exit(void)
 {
 
 	misc_deregister(&watchdog_device.miscdev);
+	intel_ipc_dev_put(scu_ipc_dev);
 	unregister_reboot_notifier(&watchdog_device.intel_scu_notifier);
 	/* disable the timer */
 	iowrite32(0x00000002, watchdog_device.timer_control_addr);
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [RFC v8 7/7] platform/x86: intel_scu_ipc: Use generic Intel IPC device calls
@ 2017-10-29  9:50   ` sathyanarayanan.kuppuswamy
  0 siblings, 0 replies; 30+ messages in thread
From: sathyanarayanan.kuppuswamy @ 2017-10-29  9:50 UTC (permalink / raw)
  To: a.zummo, x86, wim, mingo, alexandre.belloni, qipeng.zha, hpa,
	dvhart, tglx, lee.jones, andy, souvik.k.chakravarty
  Cc: linux-rtc, linux-watchdog, linux-kernel, platform-driver-x86,
	sathyaosid, Kuppuswamy Sathyanarayanan

From: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>

Removed redundant IPC helper functions and refactored the driver to use
generic IPC device driver APIs.

This patch also cleans-up SCU IPC user drivers(rtc-mrst.c, intel-mid_wdt.c,
intel-mid_wdt.c, intel-mid.c) to use APIs provided by generic IPC driver.

Signed-off-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>
Acked-by: Alexandre Belloni <alexandre.belloni@free-electrons.com>
---
 arch/x86/include/asm/intel_scu_ipc.h    |  10 +-
 arch/x86/platform/intel-mid/intel-mid.c |  15 +-
 drivers/platform/x86/Kconfig            |   1 +
 drivers/platform/x86/intel_scu_ipc.c    | 488 ++++++++++++++------------------
 drivers/rtc/rtc-mrst.c                  |  16 +-
 drivers/watchdog/intel-mid_wdt.c        |  18 +-
 drivers/watchdog/intel_scu_watchdog.c   |  23 +-
 7 files changed, 267 insertions(+), 304 deletions(-)

Changes since v7:
 * Fixed some style issues.

Changes since v6:
 * Fixed some style issues.

Changes since v5:
 * Adapted to change in arguments of ipc_dev_cmd() and ipc_dev_raw_cmd() APIs.

Changes since v4:
 * None

Changes since v3:
 * Added intel_ipc_dev_put() support.

diff --git a/arch/x86/include/asm/intel_scu_ipc.h b/arch/x86/include/asm/intel_scu_ipc.h
index 81d3d87..68b5c77 100644
--- a/arch/x86/include/asm/intel_scu_ipc.h
+++ b/arch/x86/include/asm/intel_scu_ipc.h
@@ -18,6 +18,9 @@
 	#define IPC_CMD_VRTC_SETTIME      1 /* Set time */
 	#define IPC_CMD_VRTC_SETALARM     2 /* Set alarm */
 
+#define INTEL_SCU_IPC_DEV	"intel_scu_ipc"
+#define SCU_PARAM_LEN		2
+
 /* Read single register */
 int intel_scu_ipc_ioread8(u16 addr, u8 *data);
 
@@ -45,13 +48,6 @@ int intel_scu_ipc_writev(u16 *addr, u8 *data, int len);
 /* Update single register based on the mask */
 int intel_scu_ipc_update_register(u16 addr, u8 data, u8 mask);
 
-/* Issue commands to the SCU with or without data */
-int intel_scu_ipc_simple_command(int cmd, int sub);
-int intel_scu_ipc_command(int cmd, int sub, u32 *in, int inlen,
-			  u32 *out, int outlen);
-int intel_scu_ipc_raw_command(int cmd, int sub, u8 *in, int inlen,
-			      u32 *out, int outlen, u32 dptr, u32 sptr);
-
 /* I2C control api */
 int intel_scu_ipc_i2c_cntrl(u32 addr, u32 *data);
 
diff --git a/arch/x86/platform/intel-mid/intel-mid.c b/arch/x86/platform/intel-mid/intel-mid.c
index 86676ce..23b3ab3 100644
--- a/arch/x86/platform/intel-mid/intel-mid.c
+++ b/arch/x86/platform/intel-mid/intel-mid.c
@@ -22,6 +22,7 @@
 #include <linux/irq.h>
 #include <linux/export.h>
 #include <linux/notifier.h>
+#include <linux/platform_data/x86/intel_ipc_dev.h>
 
 #include <asm/setup.h>
 #include <asm/mpspec_def.h>
@@ -70,16 +71,26 @@ EXPORT_SYMBOL_GPL(__intel_mid_cpu_chip);
 
 static void intel_mid_power_off(void)
 {
+	struct intel_ipc_dev *ipc_dev;
+	u32 cmds[SCU_PARAM_LEN] = {IPCMSG_COLD_OFF, 1};
+
 	/* Shut down South Complex via PWRMU */
 	intel_mid_pwr_power_off();
 
+	ipc_dev = intel_ipc_dev_get(INTEL_SCU_IPC_DEV);
 	/* Only for Tangier, the rest will ignore this command */
-	intel_scu_ipc_simple_command(IPCMSG_COLD_OFF, 1);
+	ipc_dev_simple_cmd(ipc_dev, cmds, SCU_PARAM_LEN);
+	intel_ipc_dev_put(ipc_dev);
 };
 
 static void intel_mid_reboot(void)
 {
-	intel_scu_ipc_simple_command(IPCMSG_COLD_BOOT, 0);
+	struct intel_ipc_dev *ipc_dev;
+	u32 cmds[SCU_PARAM_LEN] = {IPCMSG_COLD_BOOT, 0};
+
+	ipc_dev = intel_ipc_dev_get(INTEL_SCU_IPC_DEV);
+	ipc_dev_simple_cmd(ipc_dev, cmds, SCU_PARAM_LEN);
+	intel_ipc_dev_put(ipc_dev);
 }
 
 static unsigned long __init intel_mid_calibrate_tsc(void)
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
index 82479ca..e4e5822 100644
--- a/drivers/platform/x86/Kconfig
+++ b/drivers/platform/x86/Kconfig
@@ -850,6 +850,7 @@ config INTEL_VBTN
 config INTEL_SCU_IPC
 	bool "Intel SCU IPC Support"
 	depends on X86_INTEL_MID
+	select REGMAP_MMIO
 	default y
 	---help---
 	  IPC is used to bridge the communications between kernel and SCU on
diff --git a/drivers/platform/x86/intel_scu_ipc.c b/drivers/platform/x86/intel_scu_ipc.c
index 2c85f75..21607e0 100644
--- a/drivers/platform/x86/intel_scu_ipc.c
+++ b/drivers/platform/x86/intel_scu_ipc.c
@@ -24,6 +24,8 @@
 #include <linux/pci.h>
 #include <linux/interrupt.h>
 #include <linux/sfi.h>
+#include <linux/regmap.h>
+#include <linux/platform_data/x86/intel_ipc_dev.h>
 #include <asm/intel-mid.h>
 #include <asm/intel_scu_ipc.h>
 
@@ -39,6 +41,25 @@
 #define IPC_CMD_PCNTRL_R      1 /* Register read */
 #define IPC_CMD_PCNTRL_M      2 /* Register read-modify-write */
 
+/* IPC dev register offsets */
+/*
+ * IPC Read Buffer (Read Only):
+ * 16 byte buffer for receiving data from SCU, if IPC command
+ * processing results in response data
+ */
+#define IPC_DEV_SCU_RBUF_OFFSET			0x90
+#define IPC_DEV_SCU_WRBUF_OFFSET		0x80
+#define IPC_DEV_SCU_SPTR_OFFSET			0x08
+#define IPC_DEV_SCU_DPTR_OFFSET			0x0C
+#define IPC_DEV_SCU_STATUS_OFFSET		0x04
+
+/* IPC dev commands */
+/* IPC command register IOC bit */
+#define	IPC_DEV_SCU_CMD_MSI			BIT(8)
+#define	IPC_DEV_SCU_CMD_STATUS_ERR		BIT(1)
+#define	IPC_DEV_SCU_CMD_STATUS_ERR_MASK		GENMASK(7, 0)
+#define	IPC_DEV_SCU_CMD_STATUS_BUSY		BIT(0)
+
 /*
  * IPC register summary
  *
@@ -59,6 +80,11 @@
 #define IPC_WWBUF_SIZE    20		/* IPC Write buffer Size */
 #define IPC_RWBUF_SIZE    20		/* IPC Read buffer Size */
 #define IPC_IOC	          0x100		/* IPC command register IOC bit */
+#define	IPC_CMD_SIZE            16
+#define	IPC_CMD_SUBCMD          12
+#define	IPC_RWBUF_SIZE_DWORD    5
+#define	IPC_WWBUF_SIZE_DWORD    5
+
 
 #define PCI_DEVICE_ID_LINCROFT		0x082a
 #define PCI_DEVICE_ID_PENWELL		0x080e
@@ -93,120 +119,50 @@ static const struct intel_scu_ipc_pdata_t intel_scu_ipc_tangier_pdata = {
 
 struct intel_scu_ipc_dev {
 	struct device *dev;
+	struct intel_ipc_dev *ipc_dev;
 	void __iomem *ipc_base;
 	void __iomem *i2c_base;
-	struct completion cmd_complete;
+	struct regmap *ipc_regs;
+	struct regmap *i2c_regs;
 	u8 irq_mode;
 };
 
-static struct intel_scu_ipc_dev  ipcdev; /* Only one for now */
+static struct regmap_config ipc_regmap_config = {
+	.reg_bits = 32,
+	.reg_stride = 4,
+	.val_bits = 32,
+};
 
-/*
- * IPC Read Buffer (Read Only):
- * 16 byte buffer for receiving data from SCU, if IPC command
- * processing results in response data
- */
-#define IPC_READ_BUFFER		0x90
+static struct regmap_config i2c_regmap_config = {
+	.reg_bits = 32,
+	.reg_stride = 4,
+	.val_bits = 32,
+	.fast_io = true,
+};
+
+static struct intel_scu_ipc_dev  ipcdev; /* Only one for now */
 
 #define IPC_I2C_CNTRL_ADDR	0
 #define I2C_DATA_ADDR		0x04
 
-static DEFINE_MUTEX(ipclock); /* lock used to prevent multiple call to SCU */
-
-/*
- * Send ipc command
- * Command Register (Write Only):
- * A write to this register results in an interrupt to the SCU core processor
- * Format:
- * |rfu2(8) | size(8) | command id(4) | rfu1(3) | ioc(1) | command(8)|
- */
-static inline void ipc_command(struct intel_scu_ipc_dev *scu, u32 cmd)
+static int scu_ipc_cmd(u32 cmd, u32 sub, u8 *in, u32 inlen, u32 *out,
+		       u32 outlen)
 {
-	if (scu->irq_mode) {
-		reinit_completion(&scu->cmd_complete);
-		writel(cmd | IPC_IOC, scu->ipc_base);
-	}
-	writel(cmd, scu->ipc_base);
-}
-
-/*
- * Write ipc data
- * IPC Write Buffer (Write Only):
- * 16-byte buffer for sending data associated with IPC command to
- * SCU. Size of the data is specified in the IPC_COMMAND_REG register
- */
-static inline void ipc_data_writel(struct intel_scu_ipc_dev *scu, u32 data, u32 offset)
-{
-	writel(data, scu->ipc_base + 0x80 + offset);
-}
-
-/*
- * Status Register (Read Only):
- * Driver will read this register to get the ready/busy status of the IPC
- * block and error status of the IPC command that was just processed by SCU
- * Format:
- * |rfu3(8)|error code(8)|initiator id(8)|cmd id(4)|rfu1(2)|error(1)|busy(1)|
- */
-static inline u8 ipc_read_status(struct intel_scu_ipc_dev *scu)
-{
-	return __raw_readl(scu->ipc_base + 0x04);
-}
-
-/* Read ipc byte data */
-static inline u8 ipc_data_readb(struct intel_scu_ipc_dev *scu, u32 offset)
-{
-	return readb(scu->ipc_base + IPC_READ_BUFFER + offset);
-}
-
-/* Read ipc u32 data */
-static inline u32 ipc_data_readl(struct intel_scu_ipc_dev *scu, u32 offset)
-{
-	return readl(scu->ipc_base + IPC_READ_BUFFER + offset);
-}
-
-/* Wait till scu status is busy */
-static inline int busy_loop(struct intel_scu_ipc_dev *scu)
-{
-	u32 status = ipc_read_status(scu);
-	u32 loop_count = 100000;
-
-	/* break if scu doesn't reset busy bit after huge retry */
-	while ((status & BIT(0)) && --loop_count) {
-		udelay(1); /* scu processing time is in few u secods */
-		status = ipc_read_status(scu);
-	}
-
-	if (status & BIT(0)) {
-		dev_err(scu->dev, "IPC timed out");
-		return -ETIMEDOUT;
-	}
-
-	if (status & BIT(1))
-		return -EIO;
-
-	return 0;
-}
-
-/* Wait till ipc ioc interrupt is received or timeout in 3 HZ */
-static inline int ipc_wait_for_interrupt(struct intel_scu_ipc_dev *scu)
-{
-	int status;
+	struct intel_scu_ipc_dev *scu = &ipcdev;
+	struct intel_ipc_raw_cmd ipc_raw_cmd = {0};
+	u32 cmd_list[SCU_PARAM_LEN] = {0};
 
-	if (!wait_for_completion_timeout(&scu->cmd_complete, 3 * HZ)) {
-		dev_err(scu->dev, "IPC timed out\n");
-		return -ETIMEDOUT;
-	}
+	cmd_list[0] = cmd;
+	cmd_list[1] = sub;
 
-	status = ipc_read_status(scu);
-	if (status & BIT(1))
-		return -EIO;
-
-	return 0;
-}
+	ipc_raw_cmd.cmd_list = cmd_list;
+	ipc_raw_cmd.cmdlen = SCU_PARAM_LEN;
+	ipc_raw_cmd.in = in;
+	ipc_raw_cmd.inlen = inlen;
+	ipc_raw_cmd.out = out;
+	ipc_raw_cmd.outlen = outlen;
 
-static int intel_scu_ipc_check_status(struct intel_scu_ipc_dev *scu)
-{
-	return scu->irq_mode ? ipc_wait_for_interrupt(scu) : busy_loop(scu);
+	return ipc_dev_raw_cmd(scu->ipc_dev, &ipc_raw_cmd);
 }
 
 /* Read/Write power control(PMIC in Langwell, MSIC in PenWell) registers */
@@ -215,49 +171,42 @@ static int pwr_reg_rdwr(u16 *addr, u8 *data, u32 count, u32 op, u32 id)
 	struct intel_scu_ipc_dev *scu = &ipcdev;
 	int nc;
 	u32 offset = 0;
-	int err;
+	int err = -EIO;
 	u8 cbuf[IPC_WWBUF_SIZE];
 	u32 *wbuf = (u32 *)&cbuf;
+	/* max rbuf size is 20 bytes */
+	u8 rbuf[IPC_RWBUF_SIZE] = {0};
+	u32 rbuflen = DIV_ROUND_UP(count, 4);
 
 	memset(cbuf, 0, sizeof(cbuf));
 
-	mutex_lock(&ipclock);
-
-	if (scu->dev == NULL) {
-		mutex_unlock(&ipclock);
-		return -ENODEV;
-	}
-
 	for (nc = 0; nc < count; nc++, offset += 2) {
 		cbuf[offset] = addr[nc];
 		cbuf[offset + 1] = addr[nc] >> 8;
 	}
 
 	if (id == IPC_CMD_PCNTRL_R) {
-		for (nc = 0, offset = 0; nc < count; nc++, offset += 4)
-			ipc_data_writel(scu, wbuf[nc], offset);
-		ipc_command(scu, (count * 2) << 16 | id << 12 | 0 << 8 | op);
+		err = scu_ipc_cmd(op, id, (u8 *)wbuf, count * 2,
+				  (u32 *)rbuf, IPC_RWBUF_SIZE_DWORD);
 	} else if (id == IPC_CMD_PCNTRL_W) {
 		for (nc = 0; nc < count; nc++, offset += 1)
 			cbuf[offset] = data[nc];
-		for (nc = 0, offset = 0; nc < count; nc++, offset += 4)
-			ipc_data_writel(scu, wbuf[nc], offset);
-		ipc_command(scu, (count * 3) << 16 | id << 12 | 0 << 8 | op);
+		err = scu_ipc_cmd(op, id, (u8 *)wbuf, count * 3, NULL, 0);
+
 	} else if (id == IPC_CMD_PCNTRL_M) {
 		cbuf[offset] = data[0];
 		cbuf[offset + 1] = data[1];
-		ipc_data_writel(scu, wbuf[0], 0); /* Write wbuff */
-		ipc_command(scu, 4 << 16 | id << 12 | 0 << 8 | op);
+		err = scu_ipc_cmd(op, id, (u8 *)wbuf, 4, NULL, 0);
 	}
 
-	err = intel_scu_ipc_check_status(scu);
 	if (!err && id == IPC_CMD_PCNTRL_R) { /* Read rbuf */
 		/* Workaround: values are read as 0 without memcpy_fromio */
 		memcpy_fromio(cbuf, scu->ipc_base + 0x90, 16);
-		for (nc = 0; nc < count; nc++)
-			data[nc] = ipc_data_readb(scu, nc);
+		regmap_bulk_read(scu->ipc_regs, IPC_DEV_SCU_RBUF_OFFSET, rbuf,
+				 rbuflen);
+		memcpy(data, rbuf, count);
 	}
-	mutex_unlock(&ipclock);
+
 	return err;
 }
 
@@ -422,138 +371,6 @@ int intel_scu_ipc_update_register(u16 addr, u8 bits, u8 mask)
 }
 EXPORT_SYMBOL(intel_scu_ipc_update_register);
 
-/**
- *	intel_scu_ipc_simple_command	-	send a simple command
- *	@cmd: command
- *	@sub: sub type
- *
- *	Issue a simple command to the SCU. Do not use this interface if
- *	you must then access data as any data values may be overwritten
- *	by another SCU access by the time this function returns.
- *
- *	This function may sleep. Locking for SCU accesses is handled for
- *	the caller.
- */
-int intel_scu_ipc_simple_command(int cmd, int sub)
-{
-	struct intel_scu_ipc_dev *scu = &ipcdev;
-	int err;
-
-	mutex_lock(&ipclock);
-	if (scu->dev == NULL) {
-		mutex_unlock(&ipclock);
-		return -ENODEV;
-	}
-	ipc_command(scu, sub << 12 | cmd);
-	err = intel_scu_ipc_check_status(scu);
-	mutex_unlock(&ipclock);
-	return err;
-}
-EXPORT_SYMBOL(intel_scu_ipc_simple_command);
-
-/**
- *	intel_scu_ipc_command	-	command with data
- *	@cmd: command
- *	@sub: sub type
- *	@in: input data
- *	@inlen: input length in dwords
- *	@out: output data
- *	@outlein: output length in dwords
- *
- *	Issue a command to the SCU which involves data transfers. Do the
- *	data copies under the lock but leave it for the caller to interpret
- */
-int intel_scu_ipc_command(int cmd, int sub, u32 *in, int inlen,
-			  u32 *out, int outlen)
-{
-	struct intel_scu_ipc_dev *scu = &ipcdev;
-	int i, err;
-
-	mutex_lock(&ipclock);
-	if (scu->dev == NULL) {
-		mutex_unlock(&ipclock);
-		return -ENODEV;
-	}
-
-	for (i = 0; i < inlen; i++)
-		ipc_data_writel(scu, *in++, 4 * i);
-
-	ipc_command(scu, (inlen << 16) | (sub << 12) | cmd);
-	err = intel_scu_ipc_check_status(scu);
-
-	if (!err) {
-		for (i = 0; i < outlen; i++)
-			*out++ = ipc_data_readl(scu, 4 * i);
-	}
-
-	mutex_unlock(&ipclock);
-	return err;
-}
-EXPORT_SYMBOL(intel_scu_ipc_command);
-
-#define IPC_SPTR		0x08
-#define IPC_DPTR		0x0C
-
-/**
- * intel_scu_ipc_raw_command() - IPC command with data and pointers
- * @cmd:	IPC command code.
- * @sub:	IPC command sub type.
- * @in:		input data of this IPC command.
- * @inlen:	input data length in dwords.
- * @out:	output data of this IPC command.
- * @outlen:	output data length in dwords.
- * @sptr:	data writing to SPTR register.
- * @dptr:	data writing to DPTR register.
- *
- * Send an IPC command to SCU with input/output data and source/dest pointers.
- *
- * Return:	an IPC error code or 0 on success.
- */
-int intel_scu_ipc_raw_command(int cmd, int sub, u8 *in, int inlen,
-			      u32 *out, int outlen, u32 dptr, u32 sptr)
-{
-	struct intel_scu_ipc_dev *scu = &ipcdev;
-	int inbuflen = DIV_ROUND_UP(inlen, 4);
-	u32 inbuf[4];
-	int i, err;
-
-	/* Up to 16 bytes */
-	if (inbuflen > 4)
-		return -EINVAL;
-
-	mutex_lock(&ipclock);
-	if (scu->dev == NULL) {
-		mutex_unlock(&ipclock);
-		return -ENODEV;
-	}
-
-	writel(dptr, scu->ipc_base + IPC_DPTR);
-	writel(sptr, scu->ipc_base + IPC_SPTR);
-
-	/*
-	 * SRAM controller doesn't support 8-bit writes, it only
-	 * supports 32-bit writes, so we have to copy input data into
-	 * the temporary buffer, and SCU FW will use the inlen to
-	 * determine the actual input data length in the temporary
-	 * buffer.
-	 */
-	memcpy(inbuf, in, inlen);
-
-	for (i = 0; i < inbuflen; i++)
-		ipc_data_writel(scu, inbuf[i], 4 * i);
-
-	ipc_command(scu, (inlen << 16) | (sub << 12) | cmd);
-	err = intel_scu_ipc_check_status(scu);
-	if (!err) {
-		for (i = 0; i < outlen; i++)
-			*out++ = ipc_data_readl(scu, 4 * i);
-	}
-
-	mutex_unlock(&ipclock);
-	return err;
-}
-EXPORT_SYMBOL_GPL(intel_scu_ipc_raw_command);
-
 /* I2C commands */
 #define IPC_I2C_WRITE 1 /* I2C Write command */
 #define IPC_I2C_READ  2 /* I2C Read command */
@@ -575,48 +392,143 @@ int intel_scu_ipc_i2c_cntrl(u32 addr, u32 *data)
 	struct intel_scu_ipc_dev *scu = &ipcdev;
 	u32 cmd = 0;
 
-	mutex_lock(&ipclock);
-	if (scu->dev == NULL) {
-		mutex_unlock(&ipclock);
-		return -ENODEV;
-	}
 	cmd = (addr >> 24) & 0xFF;
 	if (cmd == IPC_I2C_READ) {
-		writel(addr, scu->i2c_base + IPC_I2C_CNTRL_ADDR);
+		regmap_write(scu->i2c_regs, IPC_I2C_CNTRL_ADDR, addr);
 		/* Write not getting updated without delay */
 		mdelay(1);
-		*data = readl(scu->i2c_base + I2C_DATA_ADDR);
+		regmap_read(scu->i2c_regs, I2C_DATA_ADDR, data);
 	} else if (cmd == IPC_I2C_WRITE) {
-		writel(*data, scu->i2c_base + I2C_DATA_ADDR);
+		regmap_write(scu->i2c_regs, I2C_DATA_ADDR, *data);
 		mdelay(1);
-		writel(addr, scu->i2c_base + IPC_I2C_CNTRL_ADDR);
+		regmap_write(scu->i2c_regs, IPC_I2C_CNTRL_ADDR, addr);
 	} else {
 		dev_err(scu->dev,
 			"intel_scu_ipc: I2C INVALID_CMD = 0x%x\n", cmd);
 
-		mutex_unlock(&ipclock);
 		return -EIO;
 	}
-	mutex_unlock(&ipclock);
 	return 0;
 }
 EXPORT_SYMBOL(intel_scu_ipc_i2c_cntrl);
 
-/*
- * Interrupt handler gets called when ioc bit of IPC_COMMAND_REG set to 1
- * When ioc bit is set to 1, caller api must wait for interrupt handler called
- * which in turn unlocks the caller api. Currently this is not used
- *
- * This is edge triggered so we need take no action to clear anything
- */
-static irqreturn_t ioc(int irq, void *dev_id)
+static int pre_simple_cmd_fn(u32 *cmd_list, u32 cmdlen)
 {
-	struct intel_scu_ipc_dev *scu = dev_id;
+	if (!cmd_list || cmdlen != SCU_PARAM_LEN)
+		return -EINVAL;
 
-	if (scu->irq_mode)
-		complete(&scu->cmd_complete);
+	cmd_list[0] |= (cmd_list[1] << IPC_CMD_SUBCMD);
+
+	return 0;
+}
+
+static int pre_cmd_fn(struct intel_ipc_cmd *ipc_cmd)
+{
+	int ret;
 
-	return IRQ_HANDLED;
+	if (ipc_cmd->inlen > IPC_WWBUF_SIZE_DWORD ||
+	    ipc_cmd->outlen > IPC_RWBUF_SIZE_DWORD)
+		return -EINVAL;
+
+	ret = pre_simple_cmd_fn(ipc_cmd->cmd_list, ipc_cmd->cmdlen);
+	if (ret < 0)
+		return ret;
+
+	ipc_cmd->cmd_list[0] |= (ipc_cmd->inlen << IPC_CMD_SIZE);
+
+	return 0;
+}
+
+static int pre_raw_cmd_fn(struct intel_ipc_raw_cmd *ipc_raw_cmd)
+{
+	int ret;
+
+	if (ipc_raw_cmd->inlen > IPC_WWBUF_SIZE ||
+	    ipc_raw_cmd->outlen > IPC_RWBUF_SIZE_DWORD)
+		return -EINVAL;
+
+	ret = pre_simple_cmd_fn(ipc_raw_cmd->cmd_list, ipc_raw_cmd->cmdlen);
+	if (ret < 0)
+		return ret;
+
+	ipc_raw_cmd->cmd_list[0] |= (ipc_raw_cmd->inlen << IPC_CMD_SIZE);
+
+	return 0;
+}
+
+static int scu_ipc_err_code(int status)
+{
+	if (status & IPC_DEV_SCU_CMD_STATUS_ERR)
+		return (status & IPC_DEV_SCU_CMD_STATUS_ERR_MASK);
+	else
+		return 0;
+}
+
+static int scu_ipc_busy_check(int status)
+{
+	return status | IPC_DEV_SCU_CMD_STATUS_BUSY;
+}
+
+static u32 scu_ipc_enable_msi(u32 cmd)
+{
+	return cmd | IPC_DEV_SCU_CMD_MSI;
+}
+
+static struct intel_ipc_dev *intel_scu_ipc_dev_create(
+		struct device *dev,
+		void __iomem *base,
+		int irq)
+{
+	struct intel_ipc_dev_ops *ops;
+	struct intel_ipc_dev_cfg *cfg;
+	struct regmap *ipc_regs;
+	struct intel_scu_ipc_dev *scu = dev_get_drvdata(dev);
+
+	cfg = devm_kzalloc(dev, sizeof(*cfg), GFP_KERNEL);
+	if (!cfg)
+		return ERR_PTR(-ENOMEM);
+
+	ops = devm_kzalloc(dev, sizeof(*ops), GFP_KERNEL);
+	if (!ops)
+		return ERR_PTR(-ENOMEM);
+
+	ipc_regs = devm_regmap_init_mmio_clk(dev, NULL, base,
+					     &ipc_regmap_config);
+	if (IS_ERR(ipc_regs)) {
+		dev_err(dev, "ipc_regs regmap init failed\n");
+		return ERR_CAST(ipc_regs);
+	}
+
+	scu->ipc_regs = ipc_regs;
+
+	/* set IPC dev ops */
+	ops->to_err_code = scu_ipc_err_code;
+	ops->busy_check = scu_ipc_busy_check;
+	ops->enable_msi = scu_ipc_enable_msi;
+	ops->pre_cmd_fn = pre_cmd_fn;
+	ops->pre_raw_cmd_fn = pre_raw_cmd_fn;
+	ops->pre_simple_cmd_fn = pre_simple_cmd_fn;
+
+	/* set cfg options */
+	if (scu->irq_mode)
+		cfg->mode = IPC_DEV_MODE_IRQ;
+	else
+		cfg->mode = IPC_DEV_MODE_POLLING;
+
+	cfg->chan_type = IPC_CHANNEL_IA_SCU;
+	cfg->irq = irq;
+	cfg->use_msi = true;
+	cfg->support_sptr = true;
+	cfg->support_dptr = true;
+	cfg->cmd_regs = ipc_regs;
+	cfg->data_regs = ipc_regs;
+	cfg->wrbuf_reg = IPC_DEV_SCU_WRBUF_OFFSET;
+	cfg->rbuf_reg = IPC_DEV_SCU_RBUF_OFFSET;
+	cfg->sptr_reg = IPC_DEV_SCU_SPTR_OFFSET;
+	cfg->dptr_reg = IPC_DEV_SCU_DPTR_OFFSET;
+	cfg->status_reg = IPC_DEV_SCU_STATUS_OFFSET;
+
+	return devm_intel_ipc_dev_create(dev, INTEL_SCU_IPC_DEV, cfg, ops);
 }
 
 /**
@@ -650,25 +562,35 @@ static int ipc_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 	if (err)
 		return err;
 
-	init_completion(&scu->cmd_complete);
-
 	scu->ipc_base = pcim_iomap_table(pdev)[0];
 
-	scu->i2c_base = ioremap_nocache(pdata->i2c_base, pdata->i2c_len);
+	scu->i2c_base = devm_ioremap_nocache(&pdev->dev, pdata->i2c_base,
+					     pdata->i2c_len);
 	if (!scu->i2c_base)
 		return -ENOMEM;
 
-	err = devm_request_irq(&pdev->dev, pdev->irq, ioc, 0, "intel_scu_ipc",
-			       scu);
-	if (err)
-		return err;
+	pci_set_drvdata(pdev, scu);
+
+	scu->i2c_regs = devm_regmap_init_mmio_clk(&pdev->dev, NULL,
+						  scu->i2c_base,
+						  &i2c_regmap_config);
+	if (IS_ERR(scu->i2c_regs)) {
+		dev_err(&pdev->dev, "i2c_regs regmap init failed\n");
+		return PTR_ERR(scu->i2c_regs);
+	}
+
+	scu->ipc_dev = intel_scu_ipc_dev_create(&pdev->dev, scu->ipc_base,
+						pdev->irq);
+	if (IS_ERR(scu->ipc_dev)) {
+		dev_err(&pdev->dev, "Failed to create SCU IPC device\n");
+		return PTR_ERR(scu->ipc_dev);
+	}
 
 	/* Assign device at last */
 	scu->dev = &pdev->dev;
 
 	intel_scu_devices_create();
 
-	pci_set_drvdata(pdev, scu);
 	return 0;
 }
 
diff --git a/drivers/rtc/rtc-mrst.c b/drivers/rtc/rtc-mrst.c
index 7334c44..37595c4 100644
--- a/drivers/rtc/rtc-mrst.c
+++ b/drivers/rtc/rtc-mrst.c
@@ -36,6 +36,7 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/sfi.h>
+#include <linux/platform_data/x86/intel_ipc_dev.h>
 
 #include <asm/intel_scu_ipc.h>
 #include <asm/intel-mid.h>
@@ -46,6 +47,7 @@ struct mrst_rtc {
 	struct device		*dev;
 	int			irq;
 	struct resource		*iomem;
+	struct intel_ipc_dev	*ipc_dev;
 
 	u8			enabled_wake;
 	u8			suspend_ctrl;
@@ -110,10 +112,11 @@ static int mrst_read_time(struct device *dev, struct rtc_time *time)
 
 static int mrst_set_time(struct device *dev, struct rtc_time *time)
 {
-	int ret;
 	unsigned long flags;
 	unsigned char mon, day, hrs, min, sec;
 	unsigned int yrs;
+	struct mrst_rtc	*mrst = dev_get_drvdata(dev);
+	u32 cmds[SCU_PARAM_LEN] = {IPCMSG_VRTC, IPC_CMD_VRTC_SETTIME};
 
 	yrs = time->tm_year;
 	mon = time->tm_mon + 1;   /* tm_mon starts at zero */
@@ -137,8 +140,7 @@ static int mrst_set_time(struct device *dev, struct rtc_time *time)
 
 	spin_unlock_irqrestore(&rtc_lock, flags);
 
-	ret = intel_scu_ipc_simple_command(IPCMSG_VRTC, IPC_CMD_VRTC_SETTIME);
-	return ret;
+	return ipc_dev_simple_cmd(mrst->ipc_dev, cmds, SCU_PARAM_LEN);
 }
 
 static int mrst_read_alarm(struct device *dev, struct rtc_wkalrm *t)
@@ -210,6 +212,7 @@ static int mrst_set_alarm(struct device *dev, struct rtc_wkalrm *t)
 	struct mrst_rtc	*mrst = dev_get_drvdata(dev);
 	unsigned char hrs, min, sec;
 	int ret = 0;
+	u32 cmds[SCU_PARAM_LEN] = {IPCMSG_VRTC, IPC_CMD_VRTC_SETALARM};
 
 	if (!mrst->irq)
 		return -EIO;
@@ -229,7 +232,7 @@ static int mrst_set_alarm(struct device *dev, struct rtc_wkalrm *t)
 
 	spin_unlock_irq(&rtc_lock);
 
-	ret = intel_scu_ipc_simple_command(IPCMSG_VRTC, IPC_CMD_VRTC_SETALARM);
+	ret = ipc_dev_simple_cmd(mrst->ipc_dev, cmds, SCU_PARAM_LEN);
 	if (ret)
 		return ret;
 
@@ -329,6 +332,10 @@ static int vrtc_mrst_do_probe(struct device *dev, struct resource *iomem,
 	if (!iomem)
 		return -ENODEV;
 
+	mrst_rtc.ipc_dev = intel_ipc_dev_get(INTEL_SCU_IPC_DEV);
+	if (IS_ERR_OR_NULL(mrst_rtc.ipc_dev))
+		return PTR_ERR(mrst_rtc.ipc_dev);
+
 	iomem = request_mem_region(iomem->start, resource_size(iomem),
 				   driver_name);
 	if (!iomem) {
@@ -394,6 +401,7 @@ static void rtc_mrst_do_remove(struct device *dev)
 
 	rtc_mrst_do_shutdown();
 
+	intel_ipc_dev_put(mrst->ipc_dev);
 	if (mrst->irq)
 		free_irq(mrst->irq, mrst->rtc);
 
diff --git a/drivers/watchdog/intel-mid_wdt.c b/drivers/watchdog/intel-mid_wdt.c
index 72c108a..d6f2993 100644
--- a/drivers/watchdog/intel-mid_wdt.c
+++ b/drivers/watchdog/intel-mid_wdt.c
@@ -18,6 +18,7 @@
 #include <linux/platform_device.h>
 #include <linux/watchdog.h>
 #include <linux/platform_data/intel-mid_wdt.h>
+#include <linux/platform_data/x86/intel_ipc_dev.h>
 
 #include <asm/intel_scu_ipc.h>
 #include <asm/intel-mid.h>
@@ -29,6 +30,8 @@
 #define MID_WDT_TIMEOUT_MAX		170
 #define MID_WDT_DEFAULT_TIMEOUT		90
 
+static struct intel_ipc_dev *scu_ipc_dev;
+
 /* SCU watchdog messages */
 enum {
 	SCU_WATCHDOG_START = 0,
@@ -38,7 +41,16 @@ enum {
 
 static inline int wdt_command(int sub, u32 *in, int inlen)
 {
-	return intel_scu_ipc_command(IPC_WATCHDOG, sub, in, inlen, NULL, 0);
+	u32 cmds[SCU_PARAM_LEN] = {IPC_WATCHDOG, sub};
+	struct intel_ipc_cmd ipc_cmd = {0};
+
+	ipc_cmd.cmd_list = cmds;
+	ipc_cmd.cmdlen = SCU_PARAM_LEN;
+	ipc_cmd.in = in;
+	ipc_cmd.out = NULL;
+	ipc_cmd.inlen = inlen;
+
+	return ipc_dev_cmd(scu_ipc_dev, &ipc_cmd);
 }
 
 static int wdt_start(struct watchdog_device *wd)
@@ -129,6 +141,10 @@ static int mid_wdt_probe(struct platform_device *pdev)
 	if (!wdt_dev)
 		return -ENOMEM;
 
+	scu_ipc_dev = devm_intel_ipc_dev_get(&pdev->dev, INTEL_SCU_IPC_DEV);
+	if (IS_ERR_OR_NULL(scu_ipc_dev))
+		return PTR_ERR(scu_ipc_dev);
+
 	wdt_dev->info = &mid_wdt_info;
 	wdt_dev->ops = &mid_wdt_ops;
 	wdt_dev->min_timeout = MID_WDT_TIMEOUT_MIN;
diff --git a/drivers/watchdog/intel_scu_watchdog.c b/drivers/watchdog/intel_scu_watchdog.c
index 0caab62..1210961a7 100644
--- a/drivers/watchdog/intel_scu_watchdog.c
+++ b/drivers/watchdog/intel_scu_watchdog.c
@@ -49,6 +49,7 @@
 #include <asm/intel_scu_ipc.h>
 #include <asm/apb_timer.h>
 #include <asm/intel-mid.h>
+#include <linux/platform_data/x86/intel_ipc_dev.h>
 
 #include "intel_scu_watchdog.h"
 
@@ -94,6 +95,8 @@ MODULE_PARM_DESC(force_boot,
 
 static struct intel_scu_watchdog_dev watchdog_device;
 
+static struct intel_ipc_dev *scu_ipc_dev;
+
 /* Forces restart, if force_reboot is set */
 static void watchdog_fire(void)
 {
@@ -128,19 +131,20 @@ static int watchdog_set_ipc(int soft_threshold, int threshold)
 	u32	*ipc_wbuf;
 	u8	 cbuf[16] = { '\0' };
 	int	 ipc_ret = 0;
+	u32 cmds[SCU_PARAM_LEN] = {IPC_SET_WATCHDOG_TIMER, 0};
+	struct intel_ipc_cmd ipc_cmd;
 
 	ipc_wbuf = (u32 *)&cbuf;
 	ipc_wbuf[0] = soft_threshold;
 	ipc_wbuf[1] = threshold;
 
-	ipc_ret = intel_scu_ipc_command(
-			IPC_SET_WATCHDOG_TIMER,
-			0,
-			ipc_wbuf,
-			2,
-			NULL,
-			0);
+	ipc_cmd.cmd_list = cmds;
+	ipc_cmd.cmdlen = SCU_PARAM_LEN;
+	ipc_cmd.in = ipc_wbuf;
+	ipc_cmd.inlen = 2;
+	ipc_cmd.out = NULL;
 
+	ipc_ret = ipc_dev_cmd(scu_ipc_dev, &ipc_cmd);
 	if (ipc_ret != 0)
 		pr_err("Error setting SCU watchdog timer: %x\n", ipc_ret);
 
@@ -460,6 +464,10 @@ static int __init intel_scu_watchdog_init(void)
 	if (check_timer_margin(timer_margin))
 		return -EINVAL;
 
+	scu_ipc_dev = intel_ipc_dev_get(INTEL_SCU_IPC_DEV);
+	if (IS_ERR_OR_NULL(scu_ipc_dev))
+		return PTR_ERR(scu_ipc_dev);
+
 	watchdog_device.timer_tbl_ptr = sfi_get_mtmr(sfi_mtimer_num-1);
 
 	if (watchdog_device.timer_tbl_ptr == NULL) {
@@ -550,6 +558,7 @@ static void __exit intel_scu_watchdog_exit(void)
 {
 
 	misc_deregister(&watchdog_device.miscdev);
+	intel_ipc_dev_put(scu_ipc_dev);
 	unregister_reboot_notifier(&watchdog_device.intel_scu_notifier);
 	/* disable the timer */
 	iowrite32(0x00000002, watchdog_device.timer_control_addr);
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 30+ messages in thread

* Re: [RFC v8 1/7] platform/x86: intel_punit_ipc: Fix resource ioremap warning
  2017-10-29  9:49   ` sathyanarayanan.kuppuswamy
  (?)
@ 2017-11-03 12:13     ` Andy Shevchenko
  -1 siblings, 0 replies; 30+ messages in thread
From: Andy Shevchenko @ 2017-11-03 12:13 UTC (permalink / raw)
  To: Kuppuswamy Sathyanarayanan
  Cc: Alessandro Zummo, x86, Wim Van Sebroeck, Ingo Molnar,
	Alexandre Belloni, Zha Qipeng, H. Peter Anvin, dvhart,
	Thomas Gleixner, Lee Jones, Andy Shevchenko,
	Souvik Kumar Chakravarty, linux-rtc, linux-watchdog,
	linux-kernel, Platform Driver,
	Sathyanarayanan Kuppuswamy Natarajan, Andy Shevchenko

On Sun, Oct 29, 2017 at 11:49 AM,
<sathyanarayanan.kuppuswamy@linux.intel.com> wrote:
> From: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>
>
> For PUNIT device, ISPDRIVER_IPC and GTDDRIVER_IPC resources are not
> mandatory. So when PMC IPC driver creates a PUNIT device, if these
> resources are not available then it creates dummy resource entries for
> these missing resources. But during PUNIT device probe, doing ioremap on
> these dummy resources generates following warning messages.
>
> intel_punit_ipc: can't request region for resource [mem 0x00000000]
> intel_punit_ipc: can't request region for resource [mem 0x00000000]
> intel_punit_ipc: can't request region for resource [mem 0x00000000]
> intel_punit_ipc: can't request region for resource [mem 0x00000000]
>
> This patch fixes this issue by adding extra check for resource size
> before performing ioremap operation.

I think I already told that this one had been pushed to my review and
testing queue, thanks!

>
> Signed-off-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>
> Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
> ---
>  drivers/platform/x86/intel_punit_ipc.c | 8 ++++----
>  1 file changed, 4 insertions(+), 4 deletions(-)
>
> Changes since v7:
>  * None
>
> Changes since v6:
>  * None
>
> Changes since v5:
>  * None
>
> Changes since v4:
>  * None
>
> diff --git a/drivers/platform/x86/intel_punit_ipc.c b/drivers/platform/x86/intel_punit_ipc.c
> index a47a41f..b5b8901 100644
> --- a/drivers/platform/x86/intel_punit_ipc.c
> +++ b/drivers/platform/x86/intel_punit_ipc.c
> @@ -252,28 +252,28 @@ static int intel_punit_get_bars(struct platform_device *pdev)
>          * - GTDRIVER_IPC BASE_IFACE
>          */
>         res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
> -       if (res) {
> +       if (res && resource_size(res) > 1) {
>                 addr = devm_ioremap_resource(&pdev->dev, res);
>                 if (!IS_ERR(addr))
>                         punit_ipcdev->base[ISPDRIVER_IPC][BASE_DATA] = addr;
>         }
>
>         res = platform_get_resource(pdev, IORESOURCE_MEM, 3);
> -       if (res) {
> +       if (res && resource_size(res) > 1) {
>                 addr = devm_ioremap_resource(&pdev->dev, res);
>                 if (!IS_ERR(addr))
>                         punit_ipcdev->base[ISPDRIVER_IPC][BASE_IFACE] = addr;
>         }
>
>         res = platform_get_resource(pdev, IORESOURCE_MEM, 4);
> -       if (res) {
> +       if (res && resource_size(res) > 1) {
>                 addr = devm_ioremap_resource(&pdev->dev, res);
>                 if (!IS_ERR(addr))
>                         punit_ipcdev->base[GTDRIVER_IPC][BASE_DATA] = addr;
>         }
>
>         res = platform_get_resource(pdev, IORESOURCE_MEM, 5);
> -       if (res) {
> +       if (res && resource_size(res) > 1) {
>                 addr = devm_ioremap_resource(&pdev->dev, res);
>                 if (!IS_ERR(addr))
>                         punit_ipcdev->base[GTDRIVER_IPC][BASE_IFACE] = addr;
> --
> 2.7.4
>



-- 
With Best Regards,
Andy Shevchenko

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [RFC v8 1/7] platform/x86: intel_punit_ipc: Fix resource ioremap warning
@ 2017-11-03 12:13     ` Andy Shevchenko
  0 siblings, 0 replies; 30+ messages in thread
From: Andy Shevchenko @ 2017-11-03 12:13 UTC (permalink / raw)
  To: Kuppuswamy Sathyanarayanan
  Cc: Alessandro Zummo, x86, Wim Van Sebroeck, Ingo Molnar,
	Alexandre Belloni, Zha Qipeng, H. Peter Anvin, dvhart,
	Thomas Gleixner, Lee Jones, Andy Shevchenko,
	Souvik Kumar Chakravarty, linux-rtc, linux-watchdog,
	linux-kernel, Platform Driver,
	Sathyanarayanan Kuppuswamy Natarajan, Andy Shevchenko

On Sun, Oct 29, 2017 at 11:49 AM,
<sathyanarayanan.kuppuswamy@linux.intel.com> wrote:
> From: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>
>
> For PUNIT device, ISPDRIVER_IPC and GTDDRIVER_IPC resources are not
> mandatory. So when PMC IPC driver creates a PUNIT device, if these
> resources are not available then it creates dummy resource entries for
> these missing resources. But during PUNIT device probe, doing ioremap on
> these dummy resources generates following warning messages.
>
> intel_punit_ipc: can't request region for resource [mem 0x00000000]
> intel_punit_ipc: can't request region for resource [mem 0x00000000]
> intel_punit_ipc: can't request region for resource [mem 0x00000000]
> intel_punit_ipc: can't request region for resource [mem 0x00000000]
>
> This patch fixes this issue by adding extra check for resource size
> before performing ioremap operation.

I think I already told that this one had been pushed to my review and
testing queue, thanks!

>
> Signed-off-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>
> Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
> ---
>  drivers/platform/x86/intel_punit_ipc.c | 8 ++++----
>  1 file changed, 4 insertions(+), 4 deletions(-)
>
> Changes since v7:
>  * None
>
> Changes since v6:
>  * None
>
> Changes since v5:
>  * None
>
> Changes since v4:
>  * None
>
> diff --git a/drivers/platform/x86/intel_punit_ipc.c b/drivers/platform/x86/intel_punit_ipc.c
> index a47a41f..b5b8901 100644
> --- a/drivers/platform/x86/intel_punit_ipc.c
> +++ b/drivers/platform/x86/intel_punit_ipc.c
> @@ -252,28 +252,28 @@ static int intel_punit_get_bars(struct platform_device *pdev)
>          * - GTDRIVER_IPC BASE_IFACE
>          */
>         res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
> -       if (res) {
> +       if (res && resource_size(res) > 1) {
>                 addr = devm_ioremap_resource(&pdev->dev, res);
>                 if (!IS_ERR(addr))
>                         punit_ipcdev->base[ISPDRIVER_IPC][BASE_DATA] = addr;
>         }
>
>         res = platform_get_resource(pdev, IORESOURCE_MEM, 3);
> -       if (res) {
> +       if (res && resource_size(res) > 1) {
>                 addr = devm_ioremap_resource(&pdev->dev, res);
>                 if (!IS_ERR(addr))
>                         punit_ipcdev->base[ISPDRIVER_IPC][BASE_IFACE] = addr;
>         }
>
>         res = platform_get_resource(pdev, IORESOURCE_MEM, 4);
> -       if (res) {
> +       if (res && resource_size(res) > 1) {
>                 addr = devm_ioremap_resource(&pdev->dev, res);
>                 if (!IS_ERR(addr))
>                         punit_ipcdev->base[GTDRIVER_IPC][BASE_DATA] = addr;
>         }
>
>         res = platform_get_resource(pdev, IORESOURCE_MEM, 5);
> -       if (res) {
> +       if (res && resource_size(res) > 1) {
>                 addr = devm_ioremap_resource(&pdev->dev, res);
>                 if (!IS_ERR(addr))
>                         punit_ipcdev->base[GTDRIVER_IPC][BASE_IFACE] = addr;
> --
> 2.7.4
>



-- 
With Best Regards,
Andy Shevchenko

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [RFC v8 1/7] platform/x86: intel_punit_ipc: Fix resource ioremap warning
@ 2017-11-03 12:13     ` Andy Shevchenko
  0 siblings, 0 replies; 30+ messages in thread
From: Andy Shevchenko @ 2017-11-03 12:13 UTC (permalink / raw)
  To: Kuppuswamy Sathyanarayanan
  Cc: Alessandro Zummo, x86, Wim Van Sebroeck, Ingo Molnar,
	Alexandre Belloni, Zha Qipeng, H. Peter Anvin, dvhart,
	Thomas Gleixner, Lee Jones, Andy Shevchenko,
	Souvik Kumar Chakravarty, linux-rtc, linux-watchdog,
	linux-kernel, Platform Driver,
	Sathyanarayanan Kuppuswamy Natarajan, Andy Shevchenko

On Sun, Oct 29, 2017 at 11:49 AM,
<sathyanarayanan.kuppuswamy@linux.intel.com> wrote:
> From: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>
>
> For PUNIT device, ISPDRIVER_IPC and GTDDRIVER_IPC resources are not
> mandatory. So when PMC IPC driver creates a PUNIT device, if these
> resources are not available then it creates dummy resource entries for
> these missing resources. But during PUNIT device probe, doing ioremap on
> these dummy resources generates following warning messages.
>
> intel_punit_ipc: can't request region for resource [mem 0x00000000]
> intel_punit_ipc: can't request region for resource [mem 0x00000000]
> intel_punit_ipc: can't request region for resource [mem 0x00000000]
> intel_punit_ipc: can't request region for resource [mem 0x00000000]
>
> This patch fixes this issue by adding extra check for resource size
> before performing ioremap operation.

I think I already told that this one had been pushed to my review and
testing queue, thanks!

>
> Signed-off-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>
> Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
> ---
>  drivers/platform/x86/intel_punit_ipc.c | 8 ++++----
>  1 file changed, 4 insertions(+), 4 deletions(-)
>
> Changes since v7:
>  * None
>
> Changes since v6:
>  * None
>
> Changes since v5:
>  * None
>
> Changes since v4:
>  * None
>
> diff --git a/drivers/platform/x86/intel_punit_ipc.c b/drivers/platform/x86/intel_punit_ipc.c
> index a47a41f..b5b8901 100644
> --- a/drivers/platform/x86/intel_punit_ipc.c
> +++ b/drivers/platform/x86/intel_punit_ipc.c
> @@ -252,28 +252,28 @@ static int intel_punit_get_bars(struct platform_device *pdev)
>          * - GTDRIVER_IPC BASE_IFACE
>          */
>         res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
> -       if (res) {
> +       if (res && resource_size(res) > 1) {
>                 addr = devm_ioremap_resource(&pdev->dev, res);
>                 if (!IS_ERR(addr))
>                         punit_ipcdev->base[ISPDRIVER_IPC][BASE_DATA] = addr;
>         }
>
>         res = platform_get_resource(pdev, IORESOURCE_MEM, 3);
> -       if (res) {
> +       if (res && resource_size(res) > 1) {
>                 addr = devm_ioremap_resource(&pdev->dev, res);
>                 if (!IS_ERR(addr))
>                         punit_ipcdev->base[ISPDRIVER_IPC][BASE_IFACE] = addr;
>         }
>
>         res = platform_get_resource(pdev, IORESOURCE_MEM, 4);
> -       if (res) {
> +       if (res && resource_size(res) > 1) {
>                 addr = devm_ioremap_resource(&pdev->dev, res);
>                 if (!IS_ERR(addr))
>                         punit_ipcdev->base[GTDRIVER_IPC][BASE_DATA] = addr;
>         }
>
>         res = platform_get_resource(pdev, IORESOURCE_MEM, 5);
> -       if (res) {
> +       if (res && resource_size(res) > 1) {
>                 addr = devm_ioremap_resource(&pdev->dev, res);
>                 if (!IS_ERR(addr))
>                         punit_ipcdev->base[GTDRIVER_IPC][BASE_IFACE] = addr;
> --
> 2.7.4
>



-- 
With Best Regards,
Andy Shevchenko

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [RFC v8 1/7] platform/x86: intel_punit_ipc: Fix resource ioremap warning
  2017-11-03 12:13     ` Andy Shevchenko
  (?)
  (?)
@ 2017-11-03 15:31     ` Kuppuswamy, Sathyanarayanan
  -1 siblings, 0 replies; 30+ messages in thread
From: Kuppuswamy, Sathyanarayanan @ 2017-11-03 15:31 UTC (permalink / raw)
  To: Andy Shevchenko, Kuppuswamy Sathyanarayanan
  Cc: Alessandro Zummo, x86, Wim Van Sebroeck, Ingo Molnar,
	Alexandre Belloni, Zha Qipeng, H. Peter Anvin, dvhart,
	Thomas Gleixner, Lee Jones, Andy Shevchenko,
	Souvik Kumar Chakravarty, linux-rtc, linux-watchdog,
	linux-kernel, Platform Driver, Andy Shevchenko

[-- Attachment #1: Type: text/plain, Size: 567 bytes --]

Hi Andy,


On 11/3/2017 5:13 AM, Andy Shevchenko wrote:
> I think I already told that this one had been pushed to my review and
> testing queue, thanks!
I thought you specifically asked me to include this patch in next set. 
Following is your previous comment. Patch 3 in your reply points to this 
patch.

>> I have applied this patch with  some modifications to my review-andy branch.
>> Please, take it from there (and  probably patch 3) and resend new
>> version of the series based on  our testing branch.

-- 
-
Sathyanarayan Kuppuswamy
Linux kernel developer


[-- Attachment #2: Type: text/html, Size: 3787 bytes --]

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [RFC v8 2/7] platform/x86: intel_pmc_ipc: Use MFD framework to create dependent devices
  2017-10-29  9:49   ` sathyanarayanan.kuppuswamy
  (?)
@ 2017-11-23 11:49   ` Heikki Krogerus
  2017-11-23 17:08     ` Guenter Roeck
  2018-01-21  4:42     ` sathya
  -1 siblings, 2 replies; 30+ messages in thread
From: Heikki Krogerus @ 2017-11-23 11:49 UTC (permalink / raw)
  To: sathyanarayanan.kuppuswamy
  Cc: a.zummo, x86, wim, mingo, alexandre.belloni, qipeng.zha, hpa,
	dvhart, tglx, lee.jones, andy, souvik.k.chakravarty, linux-rtc,
	linux-watchdog, linux-kernel, platform-driver-x86, sathyaosid,
	Andy Shevchenko

[-- Attachment #1: Type: text/plain, Size: 10696 bytes --]

Hi,

On Sun, Oct 29, 2017 at 02:49:55AM -0700, sathyanarayanan.kuppuswamy@linux.intel.com wrote:
> From: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>
> 
> Currently, we have lot of repetitive code in dependent device resource
> allocation and device creation handling code. This logic can be improved if
> we use MFD framework for dependent device creation. This patch adds this
> support.
> 
> Signed-off-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>
> Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
> ---
>  drivers/platform/x86/intel_pmc_ipc.c | 398 ++++++++++++-----------------------
>  1 file changed, 139 insertions(+), 259 deletions(-)
> 
> Changes since v7:
>  * Fixed style issues.
> 
> Changes since v6:
>  * Fixed style issues.
>  * Used Andy's modified version.
> 
> Changes since v5:
>  * Changed the order of patches in this patchlist.
> 
> Changes since v4:
>  * Changed the order of patches in this patchlist.
> 
> Changes since v3:
>  * Changed PLATFORM_DEVID_AUTO to PLATFORM_DEVID_NONE in mfd device creation.
>  * Fixed error in resource initalization logic in ipc_create_punit_device.
>  * Removed mfd cell id initialization.
> 
> diff --git a/drivers/platform/x86/intel_pmc_ipc.c b/drivers/platform/x86/intel_pmc_ipc.c
> index e03fa314..e36144c 100644
> --- a/drivers/platform/x86/intel_pmc_ipc.c
> +++ b/drivers/platform/x86/intel_pmc_ipc.c
> @@ -20,6 +20,7 @@
>  #include <linux/errno.h>
>  #include <linux/init.h>
>  #include <linux/device.h>
> +#include <linux/mfd/core.h>
>  #include <linux/pm.h>
>  #include <linux/pci.h>
>  #include <linux/platform_device.h>
> @@ -88,6 +89,7 @@
>  #define PLAT_RESOURCE_ISP_IFACE_INDEX	5
>  #define PLAT_RESOURCE_GTD_DATA_INDEX	6
>  #define PLAT_RESOURCE_GTD_IFACE_INDEX	7
> +#define PLAT_RESOURCE_MEM_MAX_INDEX	8
>  #define PLAT_RESOURCE_ACPI_IO_INDEX	0
>  
>  /*
> @@ -106,8 +108,6 @@
>  #define TELEM_SSRAM_SIZE		240
>  #define TELEM_PMC_SSRAM_OFFSET		0x1B00
>  #define TELEM_PUNIT_SSRAM_OFFSET	0x1A00
> -#define TCO_PMC_OFFSET			0x8
> -#define TCO_PMC_SIZE			0x4
>  
>  /* PMC register bit definitions */
>  
> @@ -124,26 +124,10 @@ static struct intel_pmc_ipc_dev {
>  	int cmd;
>  	struct completion cmd_complete;
>  
> -	/* The following PMC BARs share the same ACPI device with the IPC */
> -	resource_size_t acpi_io_base;
> -	int acpi_io_size;
> -	struct platform_device *tco_dev;
> -
>  	/* gcr */
>  	void __iomem *gcr_mem_base;
>  	bool has_gcr_regs;
>  	spinlock_t gcr_lock;
> -
> -	/* punit */
> -	struct platform_device *punit_dev;
> -
> -	/* Telemetry */
> -	resource_size_t telem_pmc_ssram_base;
> -	resource_size_t telem_punit_ssram_base;
> -	int telem_pmc_ssram_size;
> -	int telem_punit_ssram_size;
> -	u8 telem_res_inval;
> -	struct platform_device *telemetry_dev;
>  } ipcdev;
>  
>  static char *ipc_err_sources[] = {
> @@ -508,7 +492,7 @@ static int ipc_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
>  	ret = devm_request_irq(&pdev->dev, pdev->irq, ioc, 0, "intel_pmc_ipc",
>  				pmc);
>  	if (ret) {
> -		dev_err(&pdev->dev, "Failed to request irq\n");
> +		dev_err(&pdev->dev, "Failed to request IRQ\n");
>  		return ret;
>  	}
>  
> @@ -593,44 +577,6 @@ static const struct attribute_group intel_ipc_group = {
>  	.attrs = intel_ipc_attrs,
>  };
>  
> -static struct resource punit_res_array[] = {
> -	/* Punit BIOS */
> -	{
> -		.flags = IORESOURCE_MEM,
> -	},
> -	{
> -		.flags = IORESOURCE_MEM,
> -	},
> -	/* Punit ISP */
> -	{
> -		.flags = IORESOURCE_MEM,
> -	},
> -	{
> -		.flags = IORESOURCE_MEM,
> -	},
> -	/* Punit GTD */
> -	{
> -		.flags = IORESOURCE_MEM,
> -	},
> -	{
> -		.flags = IORESOURCE_MEM,
> -	},
> -};
> -
> -#define TCO_RESOURCE_ACPI_IO		0
> -#define TCO_RESOURCE_SMI_EN_IO		1
> -#define TCO_RESOURCE_GCR_MEM		2
> -static struct resource tco_res[] = {
> -	/* ACPI - TCO */
> -	{
> -		.flags = IORESOURCE_IO,
> -	},
> -	/* ACPI - SMI */
> -	{
> -		.flags = IORESOURCE_IO,
> -	},
> -};
> -
>  static struct itco_wdt_platform_data tco_info = {
>  	.name = "Apollo Lake SoC",
>  	.version = 5,
> @@ -638,234 +584,177 @@ static struct itco_wdt_platform_data tco_info = {
>  	.update_no_reboot_bit = update_no_reboot_bit,
>  };
>  
> -#define TELEMETRY_RESOURCE_PUNIT_SSRAM	0
> -#define TELEMETRY_RESOURCE_PMC_SSRAM	1
> -static struct resource telemetry_res[] = {
> -	/*Telemetry*/
> -	{
> -		.flags = IORESOURCE_MEM,
> -	},
> -	{
> -		.flags = IORESOURCE_MEM,
> -	},
> -};
> -
> -static int ipc_create_punit_device(void)
> +static int ipc_create_punit_device(struct platform_device *pdev)
>  {
> -	struct platform_device *pdev;
> -	const struct platform_device_info pdevinfo = {
> -		.parent = ipcdev.dev,
> -		.name = PUNIT_DEVICE_NAME,
> -		.id = -1,
> -		.res = punit_res_array,
> -		.num_res = ARRAY_SIZE(punit_res_array),
> +	struct resource punit_res[PLAT_RESOURCE_MEM_MAX_INDEX];
> +	struct mfd_cell punit_cell;
> +	struct resource *res;

That's where you have the bug I reported earlier. You would need to
introduce those structures as static struct..

But instead of fixing those, drop them and introduce the resources and
the cells out side of these functions:

static struct resource punit_resources[PLAT_RESOURCE_MEM_MAX_INDEX];
static struct resource telemetry_resources[2];
static struct resource wdt_resources[2];

static struct mfd_cell pmc_cell[] = {
        {
                .name = "intel_punit_ipc",
                .resources = punit_resources,
                .num_resources = PLAT_RESOURCE_MEM_MAX_INDEX,
                .ignore_resource_conflicts = true,
        },
        {
                .name = "intel_telemetry",
                .resources = telemetry_resources,
                .num_resources = 2,
                .ignore_resource_conflicts = true,
        },
        {
                .name = "iTCO_wdt",
                .resources = wdt_resources,
                .num_resources = 2,
                .ignore_resource_conflicts = true,
                .platform_data = &tco_info,
                .pdata_size = sizeof(tco_info),
        },
};

Note that I'm not using the definitions for the name strings on
purpose. Please get rid of those definitions while at it.

Use these functions - ipc_create_punit/wdt/telemetry_device() - to just
collect the resources. Then you call devm_mfd_add_devices() only ones
in ipc_create_pmc_devices(). That should make this driver a bit more
easier to read and understand.

> +	int mindex, pindex = 0;
> +
> +	for (mindex = 0; mindex <= PLAT_RESOURCE_MEM_MAX_INDEX; mindex++) {
> +
> +		res = platform_get_resource(pdev, IORESOURCE_MEM, mindex);
> +
> +		switch (mindex) {
> +		/* Get PUNIT resources */
> +		case PLAT_RESOURCE_BIOS_DATA_INDEX:
> +		case PLAT_RESOURCE_BIOS_IFACE_INDEX:
> +			/* BIOS resources are required, so return error if not
> +			 * available
> +			 */
> +			if (!res) {
> +				dev_err(&pdev->dev,
> +					"Failed to get PUNIT MEM resource %d\n",
> +					pindex);
> +				return -ENXIO;
> +			}
> +		case PLAT_RESOURCE_ISP_DATA_INDEX:
> +		case PLAT_RESOURCE_ISP_IFACE_INDEX:
> +		case PLAT_RESOURCE_GTD_DATA_INDEX:
> +		case PLAT_RESOURCE_GTD_IFACE_INDEX:
> +			/* if valid resource found, copy the resource to PUNIT
> +			 * resource
> +			 */
> +			if (res)
> +				memcpy(&punit_res[pindex], res, sizeof(*res));
> +			punit_res[pindex].flags = IORESOURCE_MEM;
> +			dev_dbg(&pdev->dev, "PUNIT memory res: %pR\n",
> +				&punit_res[pindex]);

I don't see how is that useful information?

> +			pindex++;
> +			break;
>  		};
> +	}
>  
> -	pdev = platform_device_register_full(&pdevinfo);
> -	if (IS_ERR(pdev))
> -		return PTR_ERR(pdev);
> -
> -	ipcdev.punit_dev = pdev;
> +	/* Create PUNIT IPC MFD cell */
> +	punit_cell.name = PUNIT_DEVICE_NAME;
> +	punit_cell.num_resources = ARRAY_SIZE(punit_res);
> +	punit_cell.resources = punit_res;
> +	punit_cell.ignore_resource_conflicts = 1;
>  
> -	return 0;
> +	return devm_mfd_add_devices(&pdev->dev, PLATFORM_DEVID_NONE,
> +				    &punit_cell, 1, NULL, 0, NULL);
>  }
>  
> -static int ipc_create_tco_device(void)
> +static int ipc_create_wdt_device(struct platform_device *pdev)
>  {
> -	struct platform_device *pdev;
> +	static struct resource wdt_ipc_res[2];
>  	struct resource *res;
> -	const struct platform_device_info pdevinfo = {
> -		.parent = ipcdev.dev,
> -		.name = TCO_DEVICE_NAME,
> -		.id = -1,
> -		.res = tco_res,
> -		.num_res = ARRAY_SIZE(tco_res),
> -		.data = &tco_info,
> -		.size_data = sizeof(tco_info),
> -		};
> +	static struct mfd_cell wdt_cell;
>  
> -	res = tco_res + TCO_RESOURCE_ACPI_IO;
> -	res->start = ipcdev.acpi_io_base + TCO_BASE_OFFSET;
> -	res->end = res->start + TCO_REGS_SIZE - 1;
> +	/* If we have ACPI based watchdog use that instead, othewise create
> +	 * a MFD cell for iTCO watchdog
> +	 */
> +	if (acpi_has_watchdog())
> +		return 0;
>  
> -	res = tco_res + TCO_RESOURCE_SMI_EN_IO;
> -	res->start = ipcdev.acpi_io_base + SMI_EN_OFFSET;
> -	res->end = res->start + SMI_EN_SIZE - 1;
> +	/* Get iTCO watchdog resources */
> +	res = platform_get_resource(pdev, IORESOURCE_IO,
> +				    PLAT_RESOURCE_ACPI_IO_INDEX);
> +	if (!res) {
> +		dev_err(&pdev->dev, "Failed to get WDT resource\n");
> +		return -ENXIO;
> +	}
>  
> -	pdev = platform_device_register_full(&pdevinfo);
> -	if (IS_ERR(pdev))
> -		return PTR_ERR(pdev);
> +	wdt_ipc_res[0].start = res->start + TCO_BASE_OFFSET;
> +	wdt_ipc_res[0].end = res->start +
> +		TCO_BASE_OFFSET + TCO_REGS_SIZE - 1;
> +	wdt_ipc_res[0].flags = IORESOURCE_IO;
> +	wdt_ipc_res[1].start = res->start + SMI_EN_OFFSET;
> +	wdt_ipc_res[1].end = res->start +
> +		SMI_EN_OFFSET + SMI_EN_SIZE - 1;
> +	wdt_ipc_res[1].flags = IORESOURCE_IO;
>  
> -	ipcdev.tco_dev = pdev;
> +	dev_dbg(&pdev->dev, "watchdog res 0: %pR\n", &wdt_ipc_res[0]);
> +	dev_dbg(&pdev->dev, "watchdog res 1: %pR\n", &wdt_ipc_res[1]);

That definitely is not useful information. Please drop all dev_dbg
calls from these patches.

> -	return 0;
> +	wdt_cell.name = TCO_DEVICE_NAME;
> +	wdt_cell.platform_data = &tco_info;
> +	wdt_cell.pdata_size = sizeof(tco_info);
> +	wdt_cell.num_resources = ARRAY_SIZE(wdt_ipc_res);
> +	wdt_cell.resources = wdt_ipc_res;
> +	wdt_cell.ignore_resource_conflicts = 1;
> +
> +	return devm_mfd_add_devices(&pdev->dev, PLATFORM_DEVID_NONE,
> +				    &wdt_cell, 1, NULL, 0, NULL);
>  }
>  
> -static int ipc_create_telemetry_device(void)
> +static int ipc_create_telemetry_device(struct platform_device *pdev)
>  {
> -	struct platform_device *pdev;
> +	struct resource telemetry_ipc_res[2];
> +	struct mfd_cell telemetry_cell;

This is also broken. I'm attaching a diff with the changes to this
patch I used when I tested this on my Broxton board.


Thanks,

-- 
heikki

[-- Attachment #2: intel_pmc_ipc.diff --]
[-- Type: text/plain, Size: 6060 bytes --]

diff --git a/drivers/platform/x86/intel_pmc_ipc.c b/drivers/platform/x86/intel_pmc_ipc.c
index e36144c337cd..a51684f4bf0b 100644
--- a/drivers/platform/x86/intel_pmc_ipc.c
+++ b/drivers/platform/x86/intel_pmc_ipc.c
@@ -584,10 +584,35 @@ static struct itco_wdt_platform_data tco_info = {
 	.update_no_reboot_bit = update_no_reboot_bit,
 };
 
-static int ipc_create_punit_device(struct platform_device *pdev)
+static struct resource punit_resources[PLAT_RESOURCE_MEM_MAX_INDEX];
+static struct resource telemetry_resources[2];
+static struct resource wdt_resources[2];
+
+static struct mfd_cell pmc_cell[] = {
+	{
+		.name = "intel_punit_ipc",
+		.resources = punit_resources,
+		.num_resources = PLAT_RESOURCE_MEM_MAX_INDEX,
+		.ignore_resource_conflicts = true,
+	},
+	{
+		.name = "intel_telemetry",
+		.resources = telemetry_resources,
+		.num_resources = 2,
+		.ignore_resource_conflicts = true,
+	},
+	{
+		.name = "iTCO_wdt",
+		.resources = wdt_resources,
+		.num_resources = 2,
+		.ignore_resource_conflicts = true,
+		.platform_data = &tco_info,
+		.pdata_size = sizeof(tco_info),
+	},
+};
+
+static int ipc_get_punit_resources(struct platform_device *pdev)
 {
-	struct resource punit_res[PLAT_RESOURCE_MEM_MAX_INDEX];
-	struct mfd_cell punit_cell;
 	struct resource *res;
 	int mindex, pindex = 0;
 
@@ -616,30 +641,20 @@ static int ipc_create_punit_device(struct platform_device *pdev)
 			 * resource
 			 */
 			if (res)
-				memcpy(&punit_res[pindex], res, sizeof(*res));
-			punit_res[pindex].flags = IORESOURCE_MEM;
-			dev_dbg(&pdev->dev, "PUNIT memory res: %pR\n",
-				&punit_res[pindex]);
+				memcpy(&punit_resources[pindex], res,
+				       sizeof(*res));
+			punit_resources[pindex].flags = IORESOURCE_MEM;
 			pindex++;
 			break;
 		};
 	}
 
-	/* Create PUNIT IPC MFD cell */
-	punit_cell.name = PUNIT_DEVICE_NAME;
-	punit_cell.num_resources = ARRAY_SIZE(punit_res);
-	punit_cell.resources = punit_res;
-	punit_cell.ignore_resource_conflicts = 1;
-
-	return devm_mfd_add_devices(&pdev->dev, PLATFORM_DEVID_NONE,
-				    &punit_cell, 1, NULL, 0, NULL);
+	return 0;
 }
 
-static int ipc_create_wdt_device(struct platform_device *pdev)
+static int ipc_get_wdt_resources(struct platform_device *pdev)
 {
-	static struct resource wdt_ipc_res[2];
 	struct resource *res;
-	static struct mfd_cell wdt_cell;
 
 	/* If we have ACPI based watchdog use that instead, othewise create
 	 * a MFD cell for iTCO watchdog
@@ -655,33 +670,18 @@ static int ipc_create_wdt_device(struct platform_device *pdev)
 		return -ENXIO;
 	}
 
-	wdt_ipc_res[0].start = res->start + TCO_BASE_OFFSET;
-	wdt_ipc_res[0].end = res->start +
-		TCO_BASE_OFFSET + TCO_REGS_SIZE - 1;
-	wdt_ipc_res[0].flags = IORESOURCE_IO;
-	wdt_ipc_res[1].start = res->start + SMI_EN_OFFSET;
-	wdt_ipc_res[1].end = res->start +
-		SMI_EN_OFFSET + SMI_EN_SIZE - 1;
-	wdt_ipc_res[1].flags = IORESOURCE_IO;
-
-	dev_dbg(&pdev->dev, "watchdog res 0: %pR\n", &wdt_ipc_res[0]);
-	dev_dbg(&pdev->dev, "watchdog res 1: %pR\n", &wdt_ipc_res[1]);
-
-	wdt_cell.name = TCO_DEVICE_NAME;
-	wdt_cell.platform_data = &tco_info;
-	wdt_cell.pdata_size = sizeof(tco_info);
-	wdt_cell.num_resources = ARRAY_SIZE(wdt_ipc_res);
-	wdt_cell.resources = wdt_ipc_res;
-	wdt_cell.ignore_resource_conflicts = 1;
-
-	return devm_mfd_add_devices(&pdev->dev, PLATFORM_DEVID_NONE,
-				    &wdt_cell, 1, NULL, 0, NULL);
+	wdt_resources[0].start = res->start + TCO_BASE_OFFSET;
+	wdt_resources[0].end = res->start + TCO_BASE_OFFSET + TCO_REGS_SIZE - 1;
+	wdt_resources[0].flags = IORESOURCE_IO;
+	wdt_resources[1].start = res->start + SMI_EN_OFFSET;
+	wdt_resources[1].end = res->start + SMI_EN_OFFSET + SMI_EN_SIZE - 1;
+	wdt_resources[1].flags = IORESOURCE_IO;
+
+	return 0;
 }
 
-static int ipc_create_telemetry_device(struct platform_device *pdev)
+static int ipc_get_telemetry_resources(struct platform_device *pdev)
 {
-	struct resource telemetry_ipc_res[2];
-	struct mfd_cell telemetry_cell;
 	struct resource *res;
 
 	/* Get telemetry resources */
@@ -692,44 +692,36 @@ static int ipc_create_telemetry_device(struct platform_device *pdev)
 		return -ENXIO;
 	}
 
-	telemetry_ipc_res[0].start = res->start + TELEM_PUNIT_SSRAM_OFFSET;
-	telemetry_ipc_res[0].end = res->start +
-		TELEM_PUNIT_SSRAM_OFFSET + TELEM_SSRAM_SIZE - 1;
-	telemetry_ipc_res[0].flags = IORESOURCE_MEM;
-	telemetry_ipc_res[1].start = res->start + TELEM_PMC_SSRAM_OFFSET;
-	telemetry_ipc_res[1].end = res->start +
-		TELEM_PMC_SSRAM_OFFSET + TELEM_SSRAM_SIZE - 1;
-	telemetry_ipc_res[1].flags = IORESOURCE_MEM;
-
-	dev_dbg(&pdev->dev, "Telemetry res 0: %pR\n", &telemetry_ipc_res[0]);
-	dev_dbg(&pdev->dev, "Telemetry res 1: %pR\n", &telemetry_ipc_res[1]);
-
-	telemetry_cell.name = TELEMETRY_DEVICE_NAME;
-	telemetry_cell.num_resources = ARRAY_SIZE(telemetry_ipc_res);
-	telemetry_cell.resources = telemetry_ipc_res;
-	telemetry_cell.ignore_resource_conflicts = 1;
-
-	return devm_mfd_add_devices(&pdev->dev, PLATFORM_DEVID_NONE,
-				    &telemetry_cell, 1, NULL, 0, NULL);
+	telemetry_resources[0].start = res->start + TELEM_PUNIT_SSRAM_OFFSET;
+	telemetry_resources[0].end = res->start + TELEM_PUNIT_SSRAM_OFFSET +
+					TELEM_SSRAM_SIZE - 1;
+	telemetry_resources[0].flags = IORESOURCE_MEM;
+	telemetry_resources[1].start = res->start + TELEM_PMC_SSRAM_OFFSET;
+	telemetry_resources[1].end = res->start + TELEM_PMC_SSRAM_OFFSET +
+					TELEM_SSRAM_SIZE - 1;
+	telemetry_resources[1].flags = IORESOURCE_MEM;
+
+	return 0;
 }
 
 static int ipc_create_pmc_devices(struct platform_device *pdev)
 {
 	int ret;
 
-	ret = ipc_create_punit_device(pdev);
+	ret = ipc_get_wdt_resources(pdev);
 	if (ret < 0)
 		return ret;
 
-	ret = ipc_create_wdt_device(pdev);
+	ret = ipc_get_punit_resources(pdev);
 	if (ret < 0)
 		return ret;
 
-	ret = ipc_create_telemetry_device(pdev);
+	ret = ipc_get_telemetry_resources(pdev);
 	if (ret < 0)
 		return ret;
 
-	return 0;
+	return devm_mfd_add_devices(&pdev->dev, PLATFORM_DEVID_NONE, pmc_cell,
+				    ARRAY_SIZE(pmc_cell), NULL, 0, NULL);
 }
 
 static int ipc_plat_get_res(struct platform_device *pdev)

^ permalink raw reply related	[flat|nested] 30+ messages in thread

* Re: [RFC v8 3/7] platform/x86: intel_pmc_ipc: Use regmap calls for GCR updates
  2017-10-29  9:49   ` sathyanarayanan.kuppuswamy
  (?)
@ 2017-11-23 12:29   ` Heikki Krogerus
  -1 siblings, 0 replies; 30+ messages in thread
From: Heikki Krogerus @ 2017-11-23 12:29 UTC (permalink / raw)
  To: sathyanarayanan.kuppuswamy
  Cc: a.zummo, x86, wim, mingo, alexandre.belloni, qipeng.zha, hpa,
	dvhart, tglx, lee.jones, andy, souvik.k.chakravarty, linux-rtc,
	linux-watchdog, linux-kernel, platform-driver-x86, sathyaosid

On Sun, Oct 29, 2017 at 02:49:56AM -0700, sathyanarayanan.kuppuswamy@linux.intel.com wrote:
> From: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>
> 
> This patch adds support for regmap based implementation for GCR
> read/write/update APIs.
> 
> Signed-off-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>
> ---
>  drivers/platform/x86/Kconfig         |   1 +
>  drivers/platform/x86/intel_pmc_ipc.c | 122 +++++++++++++----------------------
>  2 files changed, 46 insertions(+), 77 deletions(-)
> 
> Changes since v7:
>  * Fixed style issues.
> 
> Changes since v6:
>  * None
> 
> Changes since v5:
>  * None
> 
> Changes since v4:
>  * None
> 
> diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
> index 80b8795..45f4e79 100644
> --- a/drivers/platform/x86/Kconfig
> +++ b/drivers/platform/x86/Kconfig
> @@ -1054,6 +1054,7 @@ config PVPANIC
>  config INTEL_PMC_IPC
>  	tristate "Intel PMC IPC Driver"
>  	depends on ACPI
> +	select REGMAP_MMIO
>  	---help---
>  	This driver provides support for PMC control on some Intel platforms.
>  	The PMC is an ARC processor which defines IPC commands for communication
> diff --git a/drivers/platform/x86/intel_pmc_ipc.c b/drivers/platform/x86/intel_pmc_ipc.c
> index e36144c..df6af1f 100644
> --- a/drivers/platform/x86/intel_pmc_ipc.c
> +++ b/drivers/platform/x86/intel_pmc_ipc.c
> @@ -35,6 +35,8 @@
>  #include <linux/acpi.h>
>  #include <linux/io-64-nonatomic-lo-hi.h>
>  #include <linux/spinlock.h>
> +#include <linux/mfd/core.h>

You already included that in the previous patch.


Thanks,

-- 
heikki

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [RFC v8 4/7] platform: x86: Add generic Intel IPC driver
  2017-10-29  9:49   ` sathyanarayanan.kuppuswamy
  (?)
@ 2017-11-23 13:29   ` Heikki Krogerus
  2018-01-21  4:59     ` sathya
  -1 siblings, 1 reply; 30+ messages in thread
From: Heikki Krogerus @ 2017-11-23 13:29 UTC (permalink / raw)
  To: sathyanarayanan.kuppuswamy
  Cc: a.zummo, x86, wim, mingo, alexandre.belloni, qipeng.zha, hpa,
	dvhart, tglx, lee.jones, andy, souvik.k.chakravarty, linux-rtc,
	linux-watchdog, linux-kernel, platform-driver-x86, sathyaosid

Hi,

On Sun, Oct 29, 2017 at 02:49:57AM -0700, sathyanarayanan.kuppuswamy@linux.intel.com wrote:
> +/**
> + * devm_intel_ipc_dev_create() - Create IPC device
> + * @dev		: IPC parent device.
> + * @devname	: Name of the IPC device.
> + * @cfg		: IPC device configuration.
> + * @ops		: IPC device ops.
> + *
> + * Resource managed API to create IPC device with
> + * given configuration.
> + *
> + * Return	: IPC device pointer or ERR_PTR(error code).
> + */
> +struct intel_ipc_dev *devm_intel_ipc_dev_create(struct device *dev,
> +		const char *devname,
> +		struct intel_ipc_dev_cfg *cfg,
> +		struct intel_ipc_dev_ops *ops)
> +{
> +	struct intel_ipc_dev **ptr, *ipc_dev;
> +	int ret;
> +
> +	if (!dev && !devname && !cfg)
> +		return ERR_PTR(-EINVAL);
> +
> +	if (intel_ipc_dev_get(devname)) {
> +		dev_err(dev, "IPC device %s already exist\n", devname);
> +		return ERR_PTR(-EINVAL);
> +	}
> +
> +	ptr = devres_alloc(devm_intel_ipc_dev_release, sizeof(*ptr),
> +			GFP_KERNEL);
> +	if (!ptr)
> +		return ERR_PTR(-ENOMEM);
> +
> +	ipc_dev = kzalloc(sizeof(*ipc_dev), GFP_KERNEL);
> +	if (!ipc_dev) {
> +		ret = -ENOMEM;
> +		goto err_dev_create;
> +	}
> +
> +	ipc_dev->dev.class = &intel_ipc_class;
> +	ipc_dev->dev.parent = dev;
> +	ipc_dev->dev.groups = ipc_dev_groups;
> +	ipc_dev->cfg = cfg;
> +	ipc_dev->ops = ops;
> +
> +	mutex_init(&ipc_dev->lock);
> +	init_completion(&ipc_dev->cmd_complete);
> +	dev_set_drvdata(&ipc_dev->dev, ipc_dev);
> +	dev_set_name(&ipc_dev->dev, devname);
> +	device_initialize(&ipc_dev->dev);
> +
> +	ret = device_add(&ipc_dev->dev);
> +	if (ret < 0) {
> +		dev_err(&ipc_dev->dev, "%s device create failed\n",
> +				__func__);
> +		ret = -ENODEV;
> +		goto err_dev_add;
> +	}
> +
> +	if (ipc_dev->cfg->mode == IPC_DEV_MODE_IRQ) {
> +		if (devm_request_irq(&ipc_dev->dev,
> +				ipc_dev->cfg->irq,
> +				ipc_dev_irq_handler,
> +				ipc_dev->cfg->irqflags,
> +				dev_name(&ipc_dev->dev),
> +				ipc_dev)) {
> +			dev_err(&ipc_dev->dev,
> +					"Failed to request irq\n");
> +			goto err_irq_request;
> +		}
> +	}

That looks really wrong to me. This is the class driver, so why are
you handling the interrupts of the devices in it? You are clearly
making assumption that the interrupt will always be used only for
command completion, but that may not be the case. No assumptions.

Just define completion callbacks, and let the drivers handle the
actual interrupts.

> +	*ptr = ipc_dev;
> +
> +	devres_add(dev, ptr);
> +	return ipc_dev;
> +
> +err_irq_request:
> +	device_del(&ipc_dev->dev);
> +err_dev_add:
> +	kfree(ipc_dev);
> +err_dev_create:
> +	devres_free(ptr);
> +	return ERR_PTR(ret);
> +}
> +EXPORT_SYMBOL_GPL(devm_intel_ipc_dev_create);
> +
> +static int __init intel_ipc_init(void)
> +{
> +	ipc_channel_lock_init();
> +	return class_register(&intel_ipc_class);
> +}
> +
> +static void __exit intel_ipc_exit(void)
> +{
> +	class_unregister(&intel_ipc_class);
> +}
> +subsys_initcall(intel_ipc_init);
> +module_exit(intel_ipc_exit);
> +
> +MODULE_LICENSE("GPL v2");
> +MODULE_AUTHOR("Kuppuswamy Sathyanarayanan<sathyanarayanan.kuppuswamy@linux.intel.com>");
> +MODULE_DESCRIPTION("Intel IPC device class driver");

To be honest, creating an extra logical device for the IPC hosts, and
the entire class, all feel unnecessarily complex to me.

The goal of this patch should be possible to achieve in a much simpler
and flexible way. IMO this patch needs to be redesigned.


Thanks,

-- 
heikki

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [RFC v8 0/7] SCU/PMC/PUNIT Inter-Processor Communication(IPC) driver cleanup
@ 2017-11-23 13:56   ` Heikki Krogerus
  0 siblings, 0 replies; 30+ messages in thread
From: Heikki Krogerus @ 2017-11-23 13:56 UTC (permalink / raw)
  To: sathyanarayanan.kuppuswamy
  Cc: a.zummo, x86, wim, mingo, alexandre.belloni, qipeng.zha, hpa,
	dvhart, tglx, lee.jones, andy, souvik.k.chakravarty, linux-rtc,
	linux-watchdog, linux-kernel, platform-driver-x86, sathyaosid

Hi,

On Sun, Oct 29, 2017 at 02:49:53AM -0700, sathyanarayanan.kuppuswamy@linux.intel.com wrote:
> Currently intel_pmc_ipc.c, intel_punit_ipc.c, intel_scu_ipc.c drivers
> implements the same IPC features. This code duplication could be avoided if we
> implement the IPC driver as a generic library and let custom device drivers
> use API provided by generic driver. This patchset mainly addresses this issue.
> 
> Along with above code duplication issue, This patchset also addresses
> following issues in intel_pmc_ipc and intel_punit_ipc drivers.
> 
> 1. Intel_pmc_ipc.c driver does not use any resource managed (devm_*) calls.
> 2. In Intel_pmc_ipc.c driver, dependent devices like PUNIT, Telemetry and iTCO
> are created manually and uses lot of redundant buffer code.
> 3. Global variable is used to store the IPC device structure and it is used
> across all functions in intel_pmc_ipc.c and intel_punit_ipc.c.

I think those changes are definitely welcome. On top of those, I want
to have regmap for using the IPC. It does not make any sense that the
drivers for the devices attached to for example the PMC, like the
WhiskeyCove PMIC, have to implement their own regmaps.

But a class for the IPC library does feel like overkill to me.


Thanks,

-- 
heikki

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [RFC v8 0/7] SCU/PMC/PUNIT Inter-Processor Communication(IPC) driver cleanup
@ 2017-11-23 13:56   ` Heikki Krogerus
  0 siblings, 0 replies; 30+ messages in thread
From: Heikki Krogerus @ 2017-11-23 13:56 UTC (permalink / raw)
  To: sathyanarayanan.kuppuswamy-VuQAYsv1563Yd54FQh9/CA
  Cc: a.zummo-BfzFCNDTiLLj+vYz1yj4TQ, x86-DgEjT+Ai2ygdnm+yROfE0A,
	wim-IQzOog9fTRqzQB+pC5nmwQ, mingo-H+wXaHxf7aLQT0dZR+AlfA,
	alexandre.belloni-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
	qipeng.zha-ral2JQCrhuEAvxtiuMwx3w, hpa-YMNOUZJC4hwAvxtiuMwx3w,
	dvhart-wEGCiKHe2LqWVfeAwA7xHQ, tglx-hfZtesqFncYOwBW4kG4KsQ,
	lee.jones-QSEj5FYQhm4dnm+yROfE0A, andy-wEGCiKHe2LqWVfeAwA7xHQ,
	souvik.k.chakravarty-ral2JQCrhuEAvxtiuMwx3w,
	linux-rtc-u79uwXL29TY76Z2rM5mHXA,
	linux-watchdog-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	platform-driver-x86-u79uwXL29TY76Z2rM5mHXA,
	sathyaosid-Re5JQEeQqe8AvxtiuMwx3w

Hi,

On Sun, Oct 29, 2017 at 02:49:53AM -0700, sathyanarayanan.kuppuswamy-VuQAYsv1563Yd54FQh9/CA@public.gmane.org wrote:
> Currently intel_pmc_ipc.c, intel_punit_ipc.c, intel_scu_ipc.c drivers
> implements the same IPC features. This code duplication could be avoided if we
> implement the IPC driver as a generic library and let custom device drivers
> use API provided by generic driver. This patchset mainly addresses this issue.
> 
> Along with above code duplication issue, This patchset also addresses
> following issues in intel_pmc_ipc and intel_punit_ipc drivers.
> 
> 1. Intel_pmc_ipc.c driver does not use any resource managed (devm_*) calls.
> 2. In Intel_pmc_ipc.c driver, dependent devices like PUNIT, Telemetry and iTCO
> are created manually and uses lot of redundant buffer code.
> 3. Global variable is used to store the IPC device structure and it is used
> across all functions in intel_pmc_ipc.c and intel_punit_ipc.c.

I think those changes are definitely welcome. On top of those, I want
to have regmap for using the IPC. It does not make any sense that the
drivers for the devices attached to for example the PMC, like the
WhiskeyCove PMIC, have to implement their own regmaps.

But a class for the IPC library does feel like overkill to me.


Thanks,

-- 
heikki
--
To unsubscribe from this list: send the line "unsubscribe linux-watchdog" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [RFC v8 2/7] platform/x86: intel_pmc_ipc: Use MFD framework to create dependent devices
  2017-11-23 11:49   ` Heikki Krogerus
@ 2017-11-23 17:08     ` Guenter Roeck
  2018-01-21  4:42     ` sathya
  1 sibling, 0 replies; 30+ messages in thread
From: Guenter Roeck @ 2017-11-23 17:08 UTC (permalink / raw)
  To: Heikki Krogerus, sathyanarayanan.kuppuswamy
  Cc: a.zummo, x86, wim, mingo, alexandre.belloni, qipeng.zha, hpa,
	dvhart, tglx, lee.jones, andy, souvik.k.chakravarty, linux-rtc,
	linux-watchdog, linux-kernel, platform-driver-x86, sathyaosid,
	Andy Shevchenko

On 11/23/2017 03:49 AM, Heikki Krogerus wrote:
> Hi,
> 
> On Sun, Oct 29, 2017 at 02:49:55AM -0700, sathyanarayanan.kuppuswamy@linux.intel.com wrote:
>> From: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>
>>
>> Currently, we have lot of repetitive code in dependent device resource
>> allocation and device creation handling code. This logic can be improved if
>> we use MFD framework for dependent device creation. This patch adds this
>> support.
>>
>> Signed-off-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>
>> Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
>> ---
>>   drivers/platform/x86/intel_pmc_ipc.c | 398 ++++++++++++-----------------------
>>   1 file changed, 139 insertions(+), 259 deletions(-)
>>
>> Changes since v7:
>>   * Fixed style issues.
>>
>> Changes since v6:
>>   * Fixed style issues.
>>   * Used Andy's modified version.
>>
>> Changes since v5:
>>   * Changed the order of patches in this patchlist.
>>
>> Changes since v4:
>>   * Changed the order of patches in this patchlist.
>>
>> Changes since v3:
>>   * Changed PLATFORM_DEVID_AUTO to PLATFORM_DEVID_NONE in mfd device creation.
>>   * Fixed error in resource initalization logic in ipc_create_punit_device.
>>   * Removed mfd cell id initialization.
>>
>> diff --git a/drivers/platform/x86/intel_pmc_ipc.c b/drivers/platform/x86/intel_pmc_ipc.c
>> index e03fa314..e36144c 100644
>> --- a/drivers/platform/x86/intel_pmc_ipc.c
>> +++ b/drivers/platform/x86/intel_pmc_ipc.c
>> @@ -20,6 +20,7 @@
>>   #include <linux/errno.h>
>>   #include <linux/init.h>
>>   #include <linux/device.h>
>> +#include <linux/mfd/core.h>
>>   #include <linux/pm.h>
>>   #include <linux/pci.h>
>>   #include <linux/platform_device.h>
>> @@ -88,6 +89,7 @@
>>   #define PLAT_RESOURCE_ISP_IFACE_INDEX	5
>>   #define PLAT_RESOURCE_GTD_DATA_INDEX	6
>>   #define PLAT_RESOURCE_GTD_IFACE_INDEX	7
>> +#define PLAT_RESOURCE_MEM_MAX_INDEX	8
>>   #define PLAT_RESOURCE_ACPI_IO_INDEX	0
>>   
>>   /*
>> @@ -106,8 +108,6 @@
>>   #define TELEM_SSRAM_SIZE		240
>>   #define TELEM_PMC_SSRAM_OFFSET		0x1B00
>>   #define TELEM_PUNIT_SSRAM_OFFSET	0x1A00
>> -#define TCO_PMC_OFFSET			0x8
>> -#define TCO_PMC_SIZE			0x4
>>   
>>   /* PMC register bit definitions */
>>   
>> @@ -124,26 +124,10 @@ static struct intel_pmc_ipc_dev {
>>   	int cmd;
>>   	struct completion cmd_complete;
>>   
>> -	/* The following PMC BARs share the same ACPI device with the IPC */
>> -	resource_size_t acpi_io_base;
>> -	int acpi_io_size;
>> -	struct platform_device *tco_dev;
>> -
>>   	/* gcr */
>>   	void __iomem *gcr_mem_base;
>>   	bool has_gcr_regs;
>>   	spinlock_t gcr_lock;
>> -
>> -	/* punit */
>> -	struct platform_device *punit_dev;
>> -
>> -	/* Telemetry */
>> -	resource_size_t telem_pmc_ssram_base;
>> -	resource_size_t telem_punit_ssram_base;
>> -	int telem_pmc_ssram_size;
>> -	int telem_punit_ssram_size;
>> -	u8 telem_res_inval;
>> -	struct platform_device *telemetry_dev;
>>   } ipcdev;
>>   
>>   static char *ipc_err_sources[] = {
>> @@ -508,7 +492,7 @@ static int ipc_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
>>   	ret = devm_request_irq(&pdev->dev, pdev->irq, ioc, 0, "intel_pmc_ipc",
>>   				pmc);
>>   	if (ret) {
>> -		dev_err(&pdev->dev, "Failed to request irq\n");
>> +		dev_err(&pdev->dev, "Failed to request IRQ\n");
>>   		return ret;
>>   	}
>>   
>> @@ -593,44 +577,6 @@ static const struct attribute_group intel_ipc_group = {
>>   	.attrs = intel_ipc_attrs,
>>   };
>>   
>> -static struct resource punit_res_array[] = {
>> -	/* Punit BIOS */
>> -	{
>> -		.flags = IORESOURCE_MEM,
>> -	},
>> -	{
>> -		.flags = IORESOURCE_MEM,
>> -	},
>> -	/* Punit ISP */
>> -	{
>> -		.flags = IORESOURCE_MEM,
>> -	},
>> -	{
>> -		.flags = IORESOURCE_MEM,
>> -	},
>> -	/* Punit GTD */
>> -	{
>> -		.flags = IORESOURCE_MEM,
>> -	},
>> -	{
>> -		.flags = IORESOURCE_MEM,
>> -	},
>> -};
>> -
>> -#define TCO_RESOURCE_ACPI_IO		0
>> -#define TCO_RESOURCE_SMI_EN_IO		1
>> -#define TCO_RESOURCE_GCR_MEM		2
>> -static struct resource tco_res[] = {
>> -	/* ACPI - TCO */
>> -	{
>> -		.flags = IORESOURCE_IO,
>> -	},
>> -	/* ACPI - SMI */
>> -	{
>> -		.flags = IORESOURCE_IO,
>> -	},
>> -};
>> -
>>   static struct itco_wdt_platform_data tco_info = {
>>   	.name = "Apollo Lake SoC",
>>   	.version = 5,
>> @@ -638,234 +584,177 @@ static struct itco_wdt_platform_data tco_info = {
>>   	.update_no_reboot_bit = update_no_reboot_bit,
>>   };
>>   
>> -#define TELEMETRY_RESOURCE_PUNIT_SSRAM	0
>> -#define TELEMETRY_RESOURCE_PMC_SSRAM	1
>> -static struct resource telemetry_res[] = {
>> -	/*Telemetry*/
>> -	{
>> -		.flags = IORESOURCE_MEM,
>> -	},
>> -	{
>> -		.flags = IORESOURCE_MEM,
>> -	},
>> -};
>> -
>> -static int ipc_create_punit_device(void)
>> +static int ipc_create_punit_device(struct platform_device *pdev)
>>   {
>> -	struct platform_device *pdev;
>> -	const struct platform_device_info pdevinfo = {
>> -		.parent = ipcdev.dev,
>> -		.name = PUNIT_DEVICE_NAME,
>> -		.id = -1,
>> -		.res = punit_res_array,
>> -		.num_res = ARRAY_SIZE(punit_res_array),
>> +	struct resource punit_res[PLAT_RESOURCE_MEM_MAX_INDEX];
>> +	struct mfd_cell punit_cell;
>> +	struct resource *res;
> 
> That's where you have the bug I reported earlier. You would need to
> introduce those structures as static struct..
> 
> But instead of fixing those, drop them and introduce the resources and
> the cells out side of these functions:
> 
> static struct resource punit_resources[PLAT_RESOURCE_MEM_MAX_INDEX];
> static struct resource telemetry_resources[2];
> static struct resource wdt_resources[2];
> 
> static struct mfd_cell pmc_cell[] = {
>          {
>                  .name = "intel_punit_ipc",
>                  .resources = punit_resources,
>                  .num_resources = PLAT_RESOURCE_MEM_MAX_INDEX,
>                  .ignore_resource_conflicts = true,
>          },
>          {
>                  .name = "intel_telemetry",
>                  .resources = telemetry_resources,
>                  .num_resources = 2,
>                  .ignore_resource_conflicts = true,
>          },
>          {
>                  .name = "iTCO_wdt",
>                  .resources = wdt_resources,
>                  .num_resources = 2,
>                  .ignore_resource_conflicts = true,
>                  .platform_data = &tco_info,
>                  .pdata_size = sizeof(tco_info),
>          },
> };
> 
> Note that I'm not using the definitions for the name strings on
> purpose. Please get rid of those definitions while at it.
> 
> Use these functions - ipc_create_punit/wdt/telemetry_device() - to just
> collect the resources. Then you call devm_mfd_add_devices() only ones
> in ipc_create_pmc_devices(). That should make this driver a bit more
> easier to read and understand.
> 
>> +	int mindex, pindex = 0;
>> +
>> +	for (mindex = 0; mindex <= PLAT_RESOURCE_MEM_MAX_INDEX; mindex++) {
>> +
>> +		res = platform_get_resource(pdev, IORESOURCE_MEM, mindex);
>> +
>> +		switch (mindex) {
>> +		/* Get PUNIT resources */
>> +		case PLAT_RESOURCE_BIOS_DATA_INDEX:
>> +		case PLAT_RESOURCE_BIOS_IFACE_INDEX:
>> +			/* BIOS resources are required, so return error if not
>> +			 * available
>> +			 */
>> +			if (!res) {
>> +				dev_err(&pdev->dev,
>> +					"Failed to get PUNIT MEM resource %d\n",
>> +					pindex);
>> +				return -ENXIO;
>> +			}
>> +		case PLAT_RESOURCE_ISP_DATA_INDEX:
>> +		case PLAT_RESOURCE_ISP_IFACE_INDEX:
>> +		case PLAT_RESOURCE_GTD_DATA_INDEX:
>> +		case PLAT_RESOURCE_GTD_IFACE_INDEX:
>> +			/* if valid resource found, copy the resource to PUNIT
>> +			 * resource
>> +			 */
>> +			if (res)
>> +				memcpy(&punit_res[pindex], res, sizeof(*res));
>> +			punit_res[pindex].flags = IORESOURCE_MEM;
>> +			dev_dbg(&pdev->dev, "PUNIT memory res: %pR\n",
>> +				&punit_res[pindex]);
> 
> I don't see how is that useful information?
> 
>> +			pindex++;
>> +			break;
>>   		};
>> +	}
>>   
>> -	pdev = platform_device_register_full(&pdevinfo);
>> -	if (IS_ERR(pdev))
>> -		return PTR_ERR(pdev);
>> -
>> -	ipcdev.punit_dev = pdev;
>> +	/* Create PUNIT IPC MFD cell */
>> +	punit_cell.name = PUNIT_DEVICE_NAME;
>> +	punit_cell.num_resources = ARRAY_SIZE(punit_res);
>> +	punit_cell.resources = punit_res;
>> +	punit_cell.ignore_resource_conflicts = 1;
>>   
>> -	return 0;
>> +	return devm_mfd_add_devices(&pdev->dev, PLATFORM_DEVID_NONE,
>> +				    &punit_cell, 1, NULL, 0, NULL);
>>   }
>>   
>> -static int ipc_create_tco_device(void)
>> +static int ipc_create_wdt_device(struct platform_device *pdev)
>>   {
>> -	struct platform_device *pdev;
>> +	static struct resource wdt_ipc_res[2];
>>   	struct resource *res;
>> -	const struct platform_device_info pdevinfo = {
>> -		.parent = ipcdev.dev,
>> -		.name = TCO_DEVICE_NAME,
>> -		.id = -1,
>> -		.res = tco_res,
>> -		.num_res = ARRAY_SIZE(tco_res),
>> -		.data = &tco_info,
>> -		.size_data = sizeof(tco_info),
>> -		};
>> +	static struct mfd_cell wdt_cell;
>>   
>> -	res = tco_res + TCO_RESOURCE_ACPI_IO;
>> -	res->start = ipcdev.acpi_io_base + TCO_BASE_OFFSET;
>> -	res->end = res->start + TCO_REGS_SIZE - 1;
>> +	/* If we have ACPI based watchdog use that instead, othewise create
>> +	 * a MFD cell for iTCO watchdog
>> +	 */
>> +	if (acpi_has_watchdog())
>> +		return 0;
>>   
>> -	res = tco_res + TCO_RESOURCE_SMI_EN_IO;
>> -	res->start = ipcdev.acpi_io_base + SMI_EN_OFFSET;
>> -	res->end = res->start + SMI_EN_SIZE - 1;
>> +	/* Get iTCO watchdog resources */
>> +	res = platform_get_resource(pdev, IORESOURCE_IO,
>> +				    PLAT_RESOURCE_ACPI_IO_INDEX);
>> +	if (!res) {
>> +		dev_err(&pdev->dev, "Failed to get WDT resource\n");
>> +		return -ENXIO;
>> +	}
>>   
>> -	pdev = platform_device_register_full(&pdevinfo);
>> -	if (IS_ERR(pdev))
>> -		return PTR_ERR(pdev);
>> +	wdt_ipc_res[0].start = res->start + TCO_BASE_OFFSET;
>> +	wdt_ipc_res[0].end = res->start +
>> +		TCO_BASE_OFFSET + TCO_REGS_SIZE - 1;
>> +	wdt_ipc_res[0].flags = IORESOURCE_IO;
>> +	wdt_ipc_res[1].start = res->start + SMI_EN_OFFSET;
>> +	wdt_ipc_res[1].end = res->start +
>> +		SMI_EN_OFFSET + SMI_EN_SIZE - 1;
>> +	wdt_ipc_res[1].flags = IORESOURCE_IO;
>>   
>> -	ipcdev.tco_dev = pdev;
>> +	dev_dbg(&pdev->dev, "watchdog res 0: %pR\n", &wdt_ipc_res[0]);
>> +	dev_dbg(&pdev->dev, "watchdog res 1: %pR\n", &wdt_ipc_res[1]);
> 
> That definitely is not useful information. Please drop all dev_dbg
> calls from these patches.
> 
>> -	return 0;
>> +	wdt_cell.name = TCO_DEVICE_NAME;
>> +	wdt_cell.platform_data = &tco_info;
>> +	wdt_cell.pdata_size = sizeof(tco_info);
>> +	wdt_cell.num_resources = ARRAY_SIZE(wdt_ipc_res);
>> +	wdt_cell.resources = wdt_ipc_res;
>> +	wdt_cell.ignore_resource_conflicts = 1;
>> +
>> +	return devm_mfd_add_devices(&pdev->dev, PLATFORM_DEVID_NONE,
>> +				    &wdt_cell, 1, NULL, 0, NULL);

Whatever you do, don't tell the mfd maintainer that you are doing this.
You are not supposed to call mfd functions from outside the mfd directory.

Guenter

>>   }
>>   
>> -static int ipc_create_telemetry_device(void)
>> +static int ipc_create_telemetry_device(struct platform_device *pdev)
>>   {
>> -	struct platform_device *pdev;
>> +	struct resource telemetry_ipc_res[2];
>> +	struct mfd_cell telemetry_cell;
> 
> This is also broken. I'm attaching a diff with the changes to this
> patch I used when I tested this on my Broxton board.
> 
> 
> Thanks,
> 

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [RFC v8 2/7] platform/x86: intel_pmc_ipc: Use MFD framework to create dependent devices
  2017-11-23 11:49   ` Heikki Krogerus
  2017-11-23 17:08     ` Guenter Roeck
@ 2018-01-21  4:42     ` sathya
  1 sibling, 0 replies; 30+ messages in thread
From: sathya @ 2018-01-21  4:42 UTC (permalink / raw)
  To: Heikki Krogerus, sathyanarayanan.kuppuswamy
  Cc: a.zummo, x86, wim, mingo, alexandre.belloni, qipeng.zha, hpa,
	dvhart, tglx, lee.jones, andy, souvik.k.chakravarty, linux-rtc,
	linux-watchdog, linux-kernel, platform-driver-x86,
	Andy Shevchenko

Hi Heikki,

Thanks for the review.


On 11/23/2017 03:49 AM, Heikki Krogerus wrote:
> Hi,
>
> On Sun, Oct 29, 2017 at 02:49:55AM -0700, sathyanarayanan.kuppuswamy@linux.intel.com wrote:
>> From: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>
>>
>> Currently, we have lot of repetitive code in dependent device resource
>> allocation and device creation handling code. This logic can be improved if
>> we use MFD framework for dependent device creation. This patch adds this
>> support.
>>
>> Signed-off-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>
>> Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
>> ---
>>   drivers/platform/x86/intel_pmc_ipc.c | 398 ++++++++++++-----------------------
>>   1 file changed, 139 insertions(+), 259 deletions(-)
>>
>> Changes since v7:
>>   * Fixed style issues.
>>
>> Changes since v6:
>>   * Fixed style issues.
>>   * Used Andy's modified version.
>>
>> Changes since v5:
>>   * Changed the order of patches in this patchlist.
>>
>> Changes since v4:
>>   * Changed the order of patches in this patchlist.
>>
>> Changes since v3:
>>   * Changed PLATFORM_DEVID_AUTO to PLATFORM_DEVID_NONE in mfd device creation.
>>   * Fixed error in resource initalization logic in ipc_create_punit_device.
>>   * Removed mfd cell id initialization.
>>
>> diff --git a/drivers/platform/x86/intel_pmc_ipc.c b/drivers/platform/x86/intel_pmc_ipc.c
>> index e03fa314..e36144c 100644
>> --- a/drivers/platform/x86/intel_pmc_ipc.c
>> +++ b/drivers/platform/x86/intel_pmc_ipc.c
>> @@ -20,6 +20,7 @@
>>   #include <linux/errno.h>
>>   #include <linux/init.h>
>>   #include <linux/device.h>
>> +#include <linux/mfd/core.h>
>>   #include <linux/pm.h>
>>   #include <linux/pci.h>
>>   #include <linux/platform_device.h>
>> @@ -88,6 +89,7 @@
>>   #define PLAT_RESOURCE_ISP_IFACE_INDEX	5
>>   #define PLAT_RESOURCE_GTD_DATA_INDEX	6
>>   #define PLAT_RESOURCE_GTD_IFACE_INDEX	7
>> +#define PLAT_RESOURCE_MEM_MAX_INDEX	8
>>   #define PLAT_RESOURCE_ACPI_IO_INDEX	0
>>   
>>   /*
>> @@ -106,8 +108,6 @@
>>   #define TELEM_SSRAM_SIZE		240
>>   #define TELEM_PMC_SSRAM_OFFSET		0x1B00
>>   #define TELEM_PUNIT_SSRAM_OFFSET	0x1A00
>> -#define TCO_PMC_OFFSET			0x8
>> -#define TCO_PMC_SIZE			0x4
>>   
>>   /* PMC register bit definitions */
>>   
>> @@ -124,26 +124,10 @@ static struct intel_pmc_ipc_dev {
>>   	int cmd;
>>   	struct completion cmd_complete;
>>   
>> -	/* The following PMC BARs share the same ACPI device with the IPC */
>> -	resource_size_t acpi_io_base;
>> -	int acpi_io_size;
>> -	struct platform_device *tco_dev;
>> -
>>   	/* gcr */
>>   	void __iomem *gcr_mem_base;
>>   	bool has_gcr_regs;
>>   	spinlock_t gcr_lock;
>> -
>> -	/* punit */
>> -	struct platform_device *punit_dev;
>> -
>> -	/* Telemetry */
>> -	resource_size_t telem_pmc_ssram_base;
>> -	resource_size_t telem_punit_ssram_base;
>> -	int telem_pmc_ssram_size;
>> -	int telem_punit_ssram_size;
>> -	u8 telem_res_inval;
>> -	struct platform_device *telemetry_dev;
>>   } ipcdev;
>>   
>>   static char *ipc_err_sources[] = {
>> @@ -508,7 +492,7 @@ static int ipc_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
>>   	ret = devm_request_irq(&pdev->dev, pdev->irq, ioc, 0, "intel_pmc_ipc",
>>   				pmc);
>>   	if (ret) {
>> -		dev_err(&pdev->dev, "Failed to request irq\n");
>> +		dev_err(&pdev->dev, "Failed to request IRQ\n");
>>   		return ret;
>>   	}
>>   
>> @@ -593,44 +577,6 @@ static const struct attribute_group intel_ipc_group = {
>>   	.attrs = intel_ipc_attrs,
>>   };
>>   
>> -static struct resource punit_res_array[] = {
>> -	/* Punit BIOS */
>> -	{
>> -		.flags = IORESOURCE_MEM,
>> -	},
>> -	{
>> -		.flags = IORESOURCE_MEM,
>> -	},
>> -	/* Punit ISP */
>> -	{
>> -		.flags = IORESOURCE_MEM,
>> -	},
>> -	{
>> -		.flags = IORESOURCE_MEM,
>> -	},
>> -	/* Punit GTD */
>> -	{
>> -		.flags = IORESOURCE_MEM,
>> -	},
>> -	{
>> -		.flags = IORESOURCE_MEM,
>> -	},
>> -};
>> -
>> -#define TCO_RESOURCE_ACPI_IO		0
>> -#define TCO_RESOURCE_SMI_EN_IO		1
>> -#define TCO_RESOURCE_GCR_MEM		2
>> -static struct resource tco_res[] = {
>> -	/* ACPI - TCO */
>> -	{
>> -		.flags = IORESOURCE_IO,
>> -	},
>> -	/* ACPI - SMI */
>> -	{
>> -		.flags = IORESOURCE_IO,
>> -	},
>> -};
>> -
>>   static struct itco_wdt_platform_data tco_info = {
>>   	.name = "Apollo Lake SoC",
>>   	.version = 5,
>> @@ -638,234 +584,177 @@ static struct itco_wdt_platform_data tco_info = {
>>   	.update_no_reboot_bit = update_no_reboot_bit,
>>   };
>>   
>> -#define TELEMETRY_RESOURCE_PUNIT_SSRAM	0
>> -#define TELEMETRY_RESOURCE_PMC_SSRAM	1
>> -static struct resource telemetry_res[] = {
>> -	/*Telemetry*/
>> -	{
>> -		.flags = IORESOURCE_MEM,
>> -	},
>> -	{
>> -		.flags = IORESOURCE_MEM,
>> -	},
>> -};
>> -
>> -static int ipc_create_punit_device(void)
>> +static int ipc_create_punit_device(struct platform_device *pdev)
>>   {
>> -	struct platform_device *pdev;
>> -	const struct platform_device_info pdevinfo = {
>> -		.parent = ipcdev.dev,
>> -		.name = PUNIT_DEVICE_NAME,
>> -		.id = -1,
>> -		.res = punit_res_array,
>> -		.num_res = ARRAY_SIZE(punit_res_array),
>> +	struct resource punit_res[PLAT_RESOURCE_MEM_MAX_INDEX];
>> +	struct mfd_cell punit_cell;
>> +	struct resource *res;
> That's where you have the bug I reported earlier. You would need to
> introduce those structures as static struct..
May be I missed the bug message. Can you please send me the link?
>
> But instead of fixing those, drop them and introduce the resources and
> the cells out side of these functions:
>
> static struct resource punit_resources[PLAT_RESOURCE_MEM_MAX_INDEX];
> static struct resource telemetry_resources[2];
> static struct resource wdt_resources[2];
>
> static struct mfd_cell pmc_cell[] = {
>          {
>                  .name = "intel_punit_ipc",
>                  .resources = punit_resources,
>                  .num_resources = PLAT_RESOURCE_MEM_MAX_INDEX,
>                  .ignore_resource_conflicts = true,
>          },
>          {
>                  .name = "intel_telemetry",
>                  .resources = telemetry_resources,
>                  .num_resources = 2,
>                  .ignore_resource_conflicts = true,
>          },
>          {
>                  .name = "iTCO_wdt",
>                  .resources = wdt_resources,
>                  .num_resources = 2,
>                  .ignore_resource_conflicts = true,
>                  .platform_data = &tco_info,
>                  .pdata_size = sizeof(tco_info),
>          },
> };
>
> Note that I'm not using the definitions for the name strings on
> purpose. Please get rid of those definitions while at it.
>
> Use these functions - ipc_create_punit/wdt/telemetry_device() - to just
> collect the resources. Then you call devm_mfd_add_devices() only ones
There are certain cases where we should skip device enumeration for some of
these devices. For example,

1. If we get any issues when extracting the resource information.
2. In case of itco_wdt, we should skip device creation if acpi driver 
handles the watchdog.

So using single array and creating all these devices in one shot is not 
feasible. Please let me
know if I missed anything.
> in ipc_create_pmc_devices(). That should make this driver a bit more
> easier to read and understand..
>
>> +	int mindex, pindex = 0;
>> +
>> +	for (mindex = 0; mindex <= PLAT_RESOURCE_MEM_MAX_INDEX; mindex++) {
>> +
>> +		res = platform_get_resource(pdev, IORESOURCE_MEM, mindex);
>> +
>> +		switch (mindex) {
>> +		/* Get PUNIT resources */
>> +		case PLAT_RESOURCE_BIOS_DATA_INDEX:
>> +		case PLAT_RESOURCE_BIOS_IFACE_INDEX:
>> +			/* BIOS resources are required, so return error if not
>> +			 * available
>> +			 */
>> +			if (!res) {
>> +				dev_err(&pdev->dev,
>> +					"Failed to get PUNIT MEM resource %d\n",
>> +					pindex);
>> +				return -ENXIO;
>> +			}
>> +		case PLAT_RESOURCE_ISP_DATA_INDEX:
>> +		case PLAT_RESOURCE_ISP_IFACE_INDEX:
>> +		case PLAT_RESOURCE_GTD_DATA_INDEX:
>> +		case PLAT_RESOURCE_GTD_IFACE_INDEX:
>> +			/* if valid resource found, copy the resource to PUNIT
>> +			 * resource
>> +			 */
>> +			if (res)
>> +				memcpy(&punit_res[pindex], res, sizeof(*res));
>> +			punit_res[pindex].flags = IORESOURCE_MEM;
>> +			dev_dbg(&pdev->dev, "PUNIT memory res: %pR\n",
>> +				&punit_res[pindex]);
> I don't see how is that useful information?
ISP and GTD related resources are optional. So I added a debug message 
to know the details if
these resources exist.
>
>> +			pindex++;
>> +			break;
>>   		};
>> +	}
>>   
>> -	pdev = platform_device_register_full(&pdevinfo);
>> -	if (IS_ERR(pdev))
>> -		return PTR_ERR(pdev);
>> -
>> -	ipcdev.punit_dev = pdev;
>> +	/* Create PUNIT IPC MFD cell */
>> +	punit_cell.name = PUNIT_DEVICE_NAME;
>> +	punit_cell.num_resources = ARRAY_SIZE(punit_res);
>> +	punit_cell.resources = punit_res;
>> +	punit_cell.ignore_resource_conflicts = 1;
>>   
>> -	return 0;
>> +	return devm_mfd_add_devices(&pdev->dev, PLATFORM_DEVID_NONE,
>> +				    &punit_cell, 1, NULL, 0, NULL);
>>   }
>>   
>> -static int ipc_create_tco_device(void)
>> +static int ipc_create_wdt_device(struct platform_device *pdev)
>>   {
>> -	struct platform_device *pdev;
>> +	static struct resource wdt_ipc_res[2];
>>   	struct resource *res;
>> -	const struct platform_device_info pdevinfo = {
>> -		.parent = ipcdev.dev,
>> -		.name = TCO_DEVICE_NAME,
>> -		.id = -1,
>> -		.res = tco_res,
>> -		.num_res = ARRAY_SIZE(tco_res),
>> -		.data = &tco_info,
>> -		.size_data = sizeof(tco_info),
>> -		};
>> +	static struct mfd_cell wdt_cell;
>>   
>> -	res = tco_res + TCO_RESOURCE_ACPI_IO;
>> -	res->start = ipcdev.acpi_io_base + TCO_BASE_OFFSET;
>> -	res->end = res->start + TCO_REGS_SIZE - 1;
>> +	/* If we have ACPI based watchdog use that instead, othewise create
>> +	 * a MFD cell for iTCO watchdog
>> +	 */
>> +	if (acpi_has_watchdog())
>> +		return 0;
>>   
>> -	res = tco_res + TCO_RESOURCE_SMI_EN_IO;
>> -	res->start = ipcdev.acpi_io_base + SMI_EN_OFFSET;
>> -	res->end = res->start + SMI_EN_SIZE - 1;
>> +	/* Get iTCO watchdog resources */
>> +	res = platform_get_resource(pdev, IORESOURCE_IO,
>> +				    PLAT_RESOURCE_ACPI_IO_INDEX);
>> +	if (!res) {
>> +		dev_err(&pdev->dev, "Failed to get WDT resource\n");
>> +		return -ENXIO;
>> +	}
>>   
>> -	pdev = platform_device_register_full(&pdevinfo);
>> -	if (IS_ERR(pdev))
>> -		return PTR_ERR(pdev);
>> +	wdt_ipc_res[0].start = res->start + TCO_BASE_OFFSET;
>> +	wdt_ipc_res[0].end = res->start +
>> +		TCO_BASE_OFFSET + TCO_REGS_SIZE - 1;
>> +	wdt_ipc_res[0].flags = IORESOURCE_IO;
>> +	wdt_ipc_res[1].start = res->start + SMI_EN_OFFSET;
>> +	wdt_ipc_res[1].end = res->start +
>> +		SMI_EN_OFFSET + SMI_EN_SIZE - 1;
>> +	wdt_ipc_res[1].flags = IORESOURCE_IO;
>>   
>> -	ipcdev.tco_dev = pdev;
>> +	dev_dbg(&pdev->dev, "watchdog res 0: %pR\n", &wdt_ipc_res[0]);
>> +	dev_dbg(&pdev->dev, "watchdog res 1: %pR\n", &wdt_ipc_res[1]);
> That definitely is not useful information. Please drop all dev_dbg
> calls from these patches.
I can remove them.
>
>> -	return 0;
>> +	wdt_cell.name = TCO_DEVICE_NAME;
>> +	wdt_cell.platform_data = &tco_info;
>> +	wdt_cell.pdata_size = sizeof(tco_info);
>> +	wdt_cell.num_resources = ARRAY_SIZE(wdt_ipc_res);
>> +	wdt_cell.resources = wdt_ipc_res;
>> +	wdt_cell.ignore_resource_conflicts = 1;
>> +
>> +	return devm_mfd_add_devices(&pdev->dev, PLATFORM_DEVID_NONE,
>> +				    &wdt_cell, 1, NULL, 0, NULL);
>>   }
>>   
>> -static int ipc_create_telemetry_device(void)
>> +static int ipc_create_telemetry_device(struct platform_device *pdev)
>>   {
>> -	struct platform_device *pdev;
>> +	struct resource telemetry_ipc_res[2];
>> +	struct mfd_cell telemetry_cell;
> This is also broken. I'm attaching a diff with the changes to this
> patch I used when I tested this on my Broxton board.
Thanks let me go over it.
>
>
> Thanks,
>

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [RFC v8 4/7] platform: x86: Add generic Intel IPC driver
  2017-11-23 13:29   ` Heikki Krogerus
@ 2018-01-21  4:59     ` sathya
  0 siblings, 0 replies; 30+ messages in thread
From: sathya @ 2018-01-21  4:59 UTC (permalink / raw)
  To: Heikki Krogerus, sathyanarayanan.kuppuswamy
  Cc: a.zummo, x86, wim, mingo, alexandre.belloni, qipeng.zha, hpa,
	dvhart, tglx, lee.jones, andy, souvik.k.chakravarty, linux-rtc,
	linux-watchdog, linux-kernel, platform-driver-x86

Hi Heikki,


On 11/23/2017 05:29 AM, Heikki Krogerus wrote:
> Hi,
>
> On Sun, Oct 29, 2017 at 02:49:57AM -0700, sathyanarayanan.kuppuswamy@linux.intel.com wrote:
>> +/**
>> + * devm_intel_ipc_dev_create() - Create IPC device
>> + * @dev		: IPC parent device.
>> + * @devname	: Name of the IPC device.
>> + * @cfg		: IPC device configuration.
>> + * @ops		: IPC device ops.
>> + *
>> + * Resource managed API to create IPC device with
>> + * given configuration.
>> + *
>> + * Return	: IPC device pointer or ERR_PTR(error code).
>> + */
>> +struct intel_ipc_dev *devm_intel_ipc_dev_create(struct device *dev,
>> +		const char *devname,
>> +		struct intel_ipc_dev_cfg *cfg,
>> +		struct intel_ipc_dev_ops *ops)
>> +{
>> +	struct intel_ipc_dev **ptr, *ipc_dev;
>> +	int ret;
>> +
>> +	if (!dev && !devname && !cfg)
>> +		return ERR_PTR(-EINVAL);
>> +
>> +	if (intel_ipc_dev_get(devname)) {
>> +		dev_err(dev, "IPC device %s already exist\n", devname);
>> +		return ERR_PTR(-EINVAL);
>> +	}
>> +
>> +	ptr = devres_alloc(devm_intel_ipc_dev_release, sizeof(*ptr),
>> +			GFP_KERNEL);
>> +	if (!ptr)
>> +		return ERR_PTR(-ENOMEM);
>> +
>> +	ipc_dev = kzalloc(sizeof(*ipc_dev), GFP_KERNEL);
>> +	if (!ipc_dev) {
>> +		ret = -ENOMEM;
>> +		goto err_dev_create;
>> +	}
>> +
>> +	ipc_dev->dev.class = &intel_ipc_class;
>> +	ipc_dev->dev.parent = dev;
>> +	ipc_dev->dev.groups = ipc_dev_groups;
>> +	ipc_dev->cfg = cfg;
>> +	ipc_dev->ops = ops;
>> +
>> +	mutex_init(&ipc_dev->lock);
>> +	init_completion(&ipc_dev->cmd_complete);
>> +	dev_set_drvdata(&ipc_dev->dev, ipc_dev);
>> +	dev_set_name(&ipc_dev->dev, devname);
>> +	device_initialize(&ipc_dev->dev);
>> +
>> +	ret = device_add(&ipc_dev->dev);
>> +	if (ret < 0) {
>> +		dev_err(&ipc_dev->dev, "%s device create failed\n",
>> +				__func__);
>> +		ret = -ENODEV;
>> +		goto err_dev_add;
>> +	}
>> +
>> +	if (ipc_dev->cfg->mode == IPC_DEV_MODE_IRQ) {
>> +		if (devm_request_irq(&ipc_dev->dev,
>> +				ipc_dev->cfg->irq,
>> +				ipc_dev_irq_handler,
>> +				ipc_dev->cfg->irqflags,
>> +				dev_name(&ipc_dev->dev),
>> +				ipc_dev)) {
>> +			dev_err(&ipc_dev->dev,
>> +					"Failed to request irq\n");
>> +			goto err_irq_request;
>> +		}
>> +	}
> That looks really wrong to me. This is the class driver, so why are
> you handling the interrupts of the devices in it? You are clearly
> making assumption that the interrupt will always be used only for
> command completion, but that may not be the case. No assumptions.
Yes. I only considered the current usage. But I agree with your
comment. I will fix it in next version.
>
> Just define completion callbacks, and let the drivers handle the
> actual interrupts.
>
>> +	*ptr = ipc_dev;
>> +
>> +	devres_add(dev, ptr);
>> +	return ipc_dev;
>> +
>> +err_irq_request:
>> +	device_del(&ipc_dev->dev);
>> +err_dev_add:
>> +	kfree(ipc_dev);
>> +err_dev_create:
>> +	devres_free(ptr);
>> +	return ERR_PTR(ret);
>> +}
>> +EXPORT_SYMBOL_GPL(devm_intel_ipc_dev_create);
>> +
>> +static int __init intel_ipc_init(void)
>> +{
>> +	ipc_channel_lock_init();
>> +	return class_register(&intel_ipc_class);
>> +}
>> +
>> +static void __exit intel_ipc_exit(void)
>> +{
>> +	class_unregister(&intel_ipc_class);
>> +}
>> +subsys_initcall(intel_ipc_init);
>> +module_exit(intel_ipc_exit);
>> +
>> +MODULE_LICENSE("GPL v2");
>> +MODULE_AUTHOR("Kuppuswamy Sathyanarayanan<sathyanarayanan.kuppuswamy@linux.intel.com>");
>> +MODULE_DESCRIPTION("Intel IPC device class driver");
> To be honest, creating an extra logical device for the IPC hosts, and
> the entire class, all feel unnecessarily complex to me.

I want to avoid client drivers using different APIs to call everyone of 
these IPC drivers. One
solution for this issue is to use name of the device to get the device 
pointer and then use
that pointer in common API to make IPC calls. This solution is similar 
to whats used in
extcon framework.

To implement this model either we have to use class type to group all 
these devices or
implement a custom list to keep the references for all these devices.

I preferred to go with class based grouping, so that I can use 
class_find_device() API to
get the device pointer.

>
> The goal of this patch should be possible to achieve in a much simpler
> and flexible way. IMO this patch needs to be redesigned.
I am open for suggestions. I will send a separate mail to you discuss 
about the further
details.
>
>
> Thanks,
>

^ permalink raw reply	[flat|nested] 30+ messages in thread

end of thread, other threads:[~2018-01-21  4:59 UTC | newest]

Thread overview: 30+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-10-29  9:49 [RFC v8 0/7] SCU/PMC/PUNIT Inter-Processor Communication(IPC) driver cleanup sathyanarayanan.kuppuswamy
2017-10-29  9:49 ` sathyanarayanan.kuppuswamy-VuQAYsv1563Yd54FQh9/CA
2017-10-29  9:49 ` sathyanarayanan.kuppuswamy
2017-10-29  9:49 ` [RFC v8 1/7] platform/x86: intel_punit_ipc: Fix resource ioremap warning sathyanarayanan.kuppuswamy
2017-10-29  9:49   ` sathyanarayanan.kuppuswamy
2017-11-03 12:13   ` Andy Shevchenko
2017-11-03 12:13     ` Andy Shevchenko
2017-11-03 12:13     ` Andy Shevchenko
2017-11-03 15:31     ` Kuppuswamy, Sathyanarayanan
2017-10-29  9:49 ` [RFC v8 2/7] platform/x86: intel_pmc_ipc: Use MFD framework to create dependent devices sathyanarayanan.kuppuswamy
2017-10-29  9:49   ` sathyanarayanan.kuppuswamy
2017-11-23 11:49   ` Heikki Krogerus
2017-11-23 17:08     ` Guenter Roeck
2018-01-21  4:42     ` sathya
2017-10-29  9:49 ` [RFC v8 3/7] platform/x86: intel_pmc_ipc: Use regmap calls for GCR updates sathyanarayanan.kuppuswamy
2017-10-29  9:49   ` sathyanarayanan.kuppuswamy
2017-11-23 12:29   ` Heikki Krogerus
2017-10-29  9:49 ` [RFC v8 4/7] platform: x86: Add generic Intel IPC driver sathyanarayanan.kuppuswamy
2017-10-29  9:49   ` sathyanarayanan.kuppuswamy
2017-11-23 13:29   ` Heikki Krogerus
2018-01-21  4:59     ` sathya
2017-10-29  9:49 ` [RFC v8 5/7] platform/x86: intel_punit_ipc: Use generic intel ipc device calls sathyanarayanan.kuppuswamy
2017-10-29  9:49   ` sathyanarayanan.kuppuswamy-VuQAYsv1563Yd54FQh9/CA
2017-10-29  9:49   ` sathyanarayanan.kuppuswamy
2017-10-29  9:49 ` [RFC v8 6/7] platform/x86: intel_pmc_ipc: Use generic Intel IPC " sathyanarayanan.kuppuswamy
2017-10-29  9:49   ` sathyanarayanan.kuppuswamy
2017-10-29  9:50 ` [RFC v8 7/7] platform/x86: intel_scu_ipc: " sathyanarayanan.kuppuswamy
2017-10-29  9:50   ` sathyanarayanan.kuppuswamy
2017-11-23 13:56 ` [RFC v8 0/7] SCU/PMC/PUNIT Inter-Processor Communication(IPC) driver cleanup Heikki Krogerus
2017-11-23 13:56   ` Heikki Krogerus

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.