Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+21 −0
Original line number Diff line number Diff line
@@ -23,6 +23,9 @@
#define IPC_ERR_EMSECURITY		6
#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)

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,
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);
int intel_pmc_gcr_update(u32 offset, u32 mask, u32 val);

#else

@@ -56,6 +62,21 @@ static inline int intel_pmc_s0ix_counter_read(u64 *data)
	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
+115 −0
Original line number Diff line number Diff line
@@ -128,6 +128,7 @@ static struct intel_pmc_ipc_dev {
	/* gcr */
	resource_size_t gcr_base;
	int gcr_size;
	void __iomem *gcr_mem_base;
	bool has_gcr_regs;

	/* punit */
@@ -199,6 +200,119 @@ static inline u64 gcr_data_readq(u32 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)
{
	int status;
@@ -747,6 +861,7 @@ static int ipc_plat_get_res(struct platform_device *pdev)
	ipcdev.ipc_base = addr;

	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;
	dev_info(&pdev->dev, "ipc res: %pR\n", res);