Commit 49670206 authored by Kuppuswamy Sathyanarayanan's avatar Kuppuswamy Sathyanarayanan Committed by Andy Shevchenko

platform/x86: intel_pmc_ipc: Add pmc gcr read/write/update api's

This patch adds API's to read/write/update PMC GC registers.
PMC dependent devices like iTCO_wdt, Telemetry has requirement
to acces GCR registers. These API's can be used for this
purpose.
Signed-off-by: default avatarKuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>
Signed-off-by: default avatarAndy Shevchenko <andriy.shevchenko@linux.intel.com>
parent e6749c89
...@@ -23,6 +23,9 @@ ...@@ -23,6 +23,9 @@
#define IPC_ERR_EMSECURITY 6 #define IPC_ERR_EMSECURITY 6
#define IPC_ERR_UNSIGNEDKERNEL 7 #define IPC_ERR_UNSIGNEDKERNEL 7
/* GCR reg offsets from gcr base*/
#define PMC_GCR_PMC_CFG_REG 0x08
#if IS_ENABLED(CONFIG_INTEL_PMC_IPC) #if IS_ENABLED(CONFIG_INTEL_PMC_IPC)
int intel_pmc_ipc_simple_command(int cmd, int sub); int intel_pmc_ipc_simple_command(int cmd, int sub);
...@@ -31,6 +34,9 @@ int intel_pmc_ipc_raw_cmd(u32 cmd, u32 sub, u8 *in, u32 inlen, ...@@ -31,6 +34,9 @@ int intel_pmc_ipc_raw_cmd(u32 cmd, u32 sub, u8 *in, u32 inlen,
int intel_pmc_ipc_command(u32 cmd, u32 sub, u8 *in, u32 inlen, int intel_pmc_ipc_command(u32 cmd, u32 sub, u8 *in, u32 inlen,
u32 *out, u32 outlen); u32 *out, u32 outlen);
int intel_pmc_s0ix_counter_read(u64 *data); 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);
int intel_pmc_gcr_update(u32 offset, u32 mask, u32 val);
#else #else
...@@ -56,6 +62,21 @@ static inline int intel_pmc_s0ix_counter_read(u64 *data) ...@@ -56,6 +62,21 @@ static inline int intel_pmc_s0ix_counter_read(u64 *data)
return -EINVAL; return -EINVAL;
} }
static inline int intel_pmc_gcr_read(u32 offset, u32 *data)
{
return -EINVAL;
}
static inline int intel_pmc_gcr_write(u32 offset, u32 data)
{
return -EINVAL;
}
static inline int intel_pmc_gcr_update(u32 offset, u32 mask, u32 val)
{
return -EINVAL;
}
#endif /*CONFIG_INTEL_PMC_IPC*/ #endif /*CONFIG_INTEL_PMC_IPC*/
#endif #endif
...@@ -128,6 +128,7 @@ static struct intel_pmc_ipc_dev { ...@@ -128,6 +128,7 @@ static struct intel_pmc_ipc_dev {
/* gcr */ /* gcr */
resource_size_t gcr_base; resource_size_t gcr_base;
int gcr_size; int gcr_size;
void __iomem *gcr_mem_base;
bool has_gcr_regs; bool has_gcr_regs;
/* punit */ /* punit */
...@@ -199,6 +200,119 @@ static inline u64 gcr_data_readq(u32 offset) ...@@ -199,6 +200,119 @@ static inline u64 gcr_data_readq(u32 offset)
return readq(ipcdev.ipc_base + offset); return readq(ipcdev.ipc_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
* @offset: offset of GCR register from GCR address base
* @data: data pointer for storing the register output
*
* Reads the PMC GCR register of given offset.
*
* Return: negative value on error or 0 on success.
*/
int intel_pmc_gcr_read(u32 offset, u32 *data)
{
int ret;
mutex_lock(&ipclock);
ret = is_gcr_valid(offset);
if (ret < 0) {
mutex_unlock(&ipclock);
return ret;
}
*data = readl(ipcdev.gcr_mem_base + offset);
mutex_unlock(&ipclock);
return 0;
}
EXPORT_SYMBOL_GPL(intel_pmc_gcr_read);
/**
* intel_pmc_gcr_write() - Write PMC GCR register
* @offset: offset of GCR register from GCR address base
* @data: register update value
*
* Writes the PMC GCR register of given offset with given
* value.
*
* Return: negative value on error or 0 on success.
*/
int intel_pmc_gcr_write(u32 offset, u32 data)
{
int ret;
mutex_lock(&ipclock);
ret = is_gcr_valid(offset);
if (ret < 0) {
mutex_unlock(&ipclock);
return ret;
}
writel(data, ipcdev.gcr_mem_base + offset);
mutex_unlock(&ipclock);
return 0;
}
EXPORT_SYMBOL_GPL(intel_pmc_gcr_write);
/**
* intel_pmc_gcr_update() - Update PMC GCR register bits
* @offset: offset of GCR register from GCR address base
* @mask: bit mask for update operation
* @val: update value
*
* Updates the bits of given GCR register as specified by
* @mask and @val.
*
* Return: negative value on error or 0 on success.
*/
int intel_pmc_gcr_update(u32 offset, u32 mask, u32 val)
{
u32 new_val;
int ret = 0;
mutex_lock(&ipclock);
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);
/* check whether the bit update is successful */
if ((new_val & mask) != (val & mask)) {
ret = -EIO;
goto gcr_ipc_unlock;
}
gcr_ipc_unlock:
mutex_unlock(&ipclock);
return ret;
}
EXPORT_SYMBOL_GPL(intel_pmc_gcr_update);
static int intel_pmc_ipc_check_status(void) static int intel_pmc_ipc_check_status(void)
{ {
int status; int status;
...@@ -747,6 +861,7 @@ static int ipc_plat_get_res(struct platform_device *pdev) ...@@ -747,6 +861,7 @@ static int ipc_plat_get_res(struct platform_device *pdev)
ipcdev.ipc_base = addr; ipcdev.ipc_base = addr;
ipcdev.gcr_base = res->start + PLAT_RESOURCE_GCR_OFFSET; ipcdev.gcr_base = res->start + PLAT_RESOURCE_GCR_OFFSET;
ipcdev.gcr_mem_base = addr + PLAT_RESOURCE_GCR_OFFSET;
ipcdev.gcr_size = PLAT_RESOURCE_GCR_SIZE; ipcdev.gcr_size = PLAT_RESOURCE_GCR_SIZE;
dev_info(&pdev->dev, "ipc res: %pR\n", res); dev_info(&pdev->dev, "ipc res: %pR\n", res);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment