Commit 40482e4f authored by Abel Vesa's avatar Abel Vesa Committed by Bjorn Andersson
Browse files

soc: qcom: rpmh-rsc: Add support for RSC v3 register offsets



The SM8550 RSC has a new set of register offsets due to its version bump.
So read the version from HW and use the proper register offsets based on
that.

Signed-off-by: default avatarAbel Vesa <abel.vesa@linaro.org>
Signed-off-by: default avatarBjorn Andersson <andersson@kernel.org>
Link: https://lore.kernel.org/r/20221116112246.2640648-1-abel.vesa@linaro.org
parent d1d9d62b
Loading
Loading
Loading
Loading
+7 −0
Original line number Original line Diff line number Diff line
@@ -86,6 +86,11 @@ struct rpmh_ctrlr {
	struct list_head batch_cache;
	struct list_head batch_cache;
};
};


struct rsc_ver {
	u32 major;
	u32 minor;
};

/**
/**
 * struct rsc_drv: the Direct Resource Voter (DRV) of the
 * struct rsc_drv: the Direct Resource Voter (DRV) of the
 * Resource State Coordinator controller (RSC)
 * Resource State Coordinator controller (RSC)
@@ -129,6 +134,8 @@ struct rsc_drv {
	wait_queue_head_t tcs_wait;
	wait_queue_head_t tcs_wait;
	struct rpmh_ctrlr client;
	struct rpmh_ctrlr client;
	struct device *dev;
	struct device *dev;
	struct rsc_ver ver;
	u32 *regs;
};
};


int rpmh_rsc_send_data(struct rsc_drv *drv, const struct tcs_request *msg);
int rpmh_rsc_send_data(struct rsc_drv *drv, const struct tcs_request *msg);
+103 −58
Original line number Original line Diff line number Diff line
@@ -36,16 +36,38 @@
#define CREATE_TRACE_POINTS
#define CREATE_TRACE_POINTS
#include "trace-rpmh.h"
#include "trace-rpmh.h"


#define RSC_DRV_TCS_OFFSET		672

#define RSC_DRV_CMD_OFFSET		20
#define RSC_DRV_ID			0

#define MAJOR_VER_MASK			0xFF
#define MAJOR_VER_SHIFT			16
#define MINOR_VER_MASK			0xFF
#define MINOR_VER_SHIFT			8

enum {
	RSC_DRV_TCS_OFFSET,
	RSC_DRV_CMD_OFFSET,
	DRV_SOLVER_CONFIG,
	DRV_PRNT_CHLD_CONFIG,
	RSC_DRV_IRQ_ENABLE,
	RSC_DRV_IRQ_STATUS,
	RSC_DRV_IRQ_CLEAR,
	RSC_DRV_CMD_WAIT_FOR_CMPL,
	RSC_DRV_CONTROL,
	RSC_DRV_STATUS,
	RSC_DRV_CMD_ENABLE,
	RSC_DRV_CMD_MSGID,
	RSC_DRV_CMD_ADDR,
	RSC_DRV_CMD_DATA,
	RSC_DRV_CMD_STATUS,
	RSC_DRV_CMD_RESP_DATA,
};


/* DRV HW Solver Configuration Information Register */
/* DRV HW Solver Configuration Information Register */
#define DRV_SOLVER_CONFIG		0x04
#define DRV_HW_SOLVER_MASK		1
#define DRV_HW_SOLVER_MASK		1
#define DRV_HW_SOLVER_SHIFT		24
#define DRV_HW_SOLVER_SHIFT		24


/* DRV TCS Configuration Information Register */
/* DRV TCS Configuration Information Register */
#define DRV_PRNT_CHLD_CONFIG		0x0C
#define DRV_NUM_TCS_MASK		0x3F
#define DRV_NUM_TCS_MASK		0x3F
#define DRV_NUM_TCS_SHIFT		6
#define DRV_NUM_TCS_SHIFT		6
#define DRV_NCPT_MASK			0x1F
#define DRV_NCPT_MASK			0x1F
@@ -59,35 +81,6 @@
#define RSC_DRV_CTL_TCS_DATA_LO_MASK	0xFFFFFFFF
#define RSC_DRV_CTL_TCS_DATA_LO_MASK	0xFFFFFFFF
#define RSC_DRV_CTL_TCS_DATA_SIZE	32
#define RSC_DRV_CTL_TCS_DATA_SIZE	32


/* Offsets for common TCS Registers, one bit per TCS */
#define RSC_DRV_IRQ_ENABLE		0x00
#define RSC_DRV_IRQ_STATUS		0x04
#define RSC_DRV_IRQ_CLEAR		0x08	/* w/o; write 1 to clear */

/*
 * Offsets for per TCS Registers.
 *
 * TCSes start at 0x10 from tcs_base and are stored one after another.
 * Multiply tcs_id by RSC_DRV_TCS_OFFSET to find a given TCS and add one
 * of the below to find a register.
 */
#define RSC_DRV_CMD_WAIT_FOR_CMPL	0x10	/* 1 bit per command */
#define RSC_DRV_CONTROL			0x14
#define RSC_DRV_STATUS			0x18	/* zero if tcs is busy */
#define RSC_DRV_CMD_ENABLE		0x1C	/* 1 bit per command */

/*
 * Offsets for per command in a TCS.
 *
 * Commands (up to 16) start at 0x30 in a TCS; multiply command index
 * by RSC_DRV_CMD_OFFSET and add one of the below to find a register.
 */
#define RSC_DRV_CMD_MSGID		0x30
#define RSC_DRV_CMD_ADDR		0x34
#define RSC_DRV_CMD_DATA		0x38
#define RSC_DRV_CMD_STATUS		0x3C
#define RSC_DRV_CMD_RESP_DATA		0x40

#define TCS_AMC_MODE_ENABLE		BIT(16)
#define TCS_AMC_MODE_ENABLE		BIT(16)
#define TCS_AMC_MODE_TRIGGER		BIT(24)
#define TCS_AMC_MODE_TRIGGER		BIT(24)


@@ -160,16 +153,54 @@ static inline unsigned long xloops_to_cycles(u64 xloops)
	return (xloops * loops_per_jiffy * HZ) >> 32;
	return (xloops * loops_per_jiffy * HZ) >> 32;
}
}


static u32 rpmh_rsc_reg_offset_ver_2_7[] = {
	[RSC_DRV_TCS_OFFSET]		= 672,
	[RSC_DRV_CMD_OFFSET]		= 20,
	[DRV_SOLVER_CONFIG]		= 0x04,
	[DRV_PRNT_CHLD_CONFIG]		= 0x0C,
	[RSC_DRV_IRQ_ENABLE]		= 0x00,
	[RSC_DRV_IRQ_STATUS]		= 0x04,
	[RSC_DRV_IRQ_CLEAR]		= 0x08,
	[RSC_DRV_CMD_WAIT_FOR_CMPL]	= 0x10,
	[RSC_DRV_CONTROL]		= 0x14,
	[RSC_DRV_STATUS]		= 0x18,
	[RSC_DRV_CMD_ENABLE]		= 0x1C,
	[RSC_DRV_CMD_MSGID]		= 0x30,
	[RSC_DRV_CMD_ADDR]		= 0x34,
	[RSC_DRV_CMD_DATA]		= 0x38,
	[RSC_DRV_CMD_STATUS]		= 0x3C,
	[RSC_DRV_CMD_RESP_DATA]		= 0x40,
};

static u32 rpmh_rsc_reg_offset_ver_3_0[] = {
	[RSC_DRV_TCS_OFFSET]		= 672,
	[RSC_DRV_CMD_OFFSET]		= 24,
	[DRV_SOLVER_CONFIG]		= 0x04,
	[DRV_PRNT_CHLD_CONFIG]		= 0x0C,
	[RSC_DRV_IRQ_ENABLE]		= 0x00,
	[RSC_DRV_IRQ_STATUS]		= 0x04,
	[RSC_DRV_IRQ_CLEAR]		= 0x08,
	[RSC_DRV_CMD_WAIT_FOR_CMPL]	= 0x20,
	[RSC_DRV_CONTROL]		= 0x24,
	[RSC_DRV_STATUS]		= 0x28,
	[RSC_DRV_CMD_ENABLE]		= 0x2C,
	[RSC_DRV_CMD_MSGID]		= 0x34,
	[RSC_DRV_CMD_ADDR]		= 0x38,
	[RSC_DRV_CMD_DATA]		= 0x3C,
	[RSC_DRV_CMD_STATUS]		= 0x40,
	[RSC_DRV_CMD_RESP_DATA]		= 0x44,
};

static inline void __iomem *
static inline void __iomem *
tcs_reg_addr(const struct rsc_drv *drv, int reg, int tcs_id)
tcs_reg_addr(const struct rsc_drv *drv, int reg, int tcs_id)
{
{
	return drv->tcs_base + RSC_DRV_TCS_OFFSET * tcs_id + reg;
	return drv->tcs_base + drv->regs[RSC_DRV_TCS_OFFSET] * tcs_id + reg;
}
}


static inline void __iomem *
static inline void __iomem *
tcs_cmd_addr(const struct rsc_drv *drv, int reg, int tcs_id, int cmd_id)
tcs_cmd_addr(const struct rsc_drv *drv, int reg, int tcs_id, int cmd_id)
{
{
	return tcs_reg_addr(drv, reg, tcs_id) + RSC_DRV_CMD_OFFSET * cmd_id;
	return tcs_reg_addr(drv, reg, tcs_id) + drv->regs[RSC_DRV_CMD_OFFSET] * cmd_id;
}
}


static u32 read_tcs_cmd(const struct rsc_drv *drv, int reg, int tcs_id,
static u32 read_tcs_cmd(const struct rsc_drv *drv, int reg, int tcs_id,
@@ -237,7 +268,7 @@ static void tcs_invalidate(struct rsc_drv *drv, int type)
		return;
		return;


	for (m = tcs->offset; m < tcs->offset + tcs->num_tcs; m++)
	for (m = tcs->offset; m < tcs->offset + tcs->num_tcs; m++)
		write_tcs_reg_sync(drv, RSC_DRV_CMD_ENABLE, m, 0);
		write_tcs_reg_sync(drv, drv->regs[RSC_DRV_CMD_ENABLE], m, 0);


	bitmap_zero(tcs->slots, MAX_TCS_SLOTS);
	bitmap_zero(tcs->slots, MAX_TCS_SLOTS);
}
}
@@ -351,24 +382,25 @@ static const struct tcs_request *get_req_from_tcs(struct rsc_drv *drv,
static void __tcs_set_trigger(struct rsc_drv *drv, int tcs_id, bool trigger)
static void __tcs_set_trigger(struct rsc_drv *drv, int tcs_id, bool trigger)
{
{
	u32 enable;
	u32 enable;
	u32 reg = drv->regs[RSC_DRV_CONTROL];


	/*
	/*
	 * HW req: Clear the DRV_CONTROL and enable TCS again
	 * HW req: Clear the DRV_CONTROL and enable TCS again
	 * While clearing ensure that the AMC mode trigger is cleared
	 * While clearing ensure that the AMC mode trigger is cleared
	 * and then the mode enable is cleared.
	 * and then the mode enable is cleared.
	 */
	 */
	enable = read_tcs_reg(drv, RSC_DRV_CONTROL, tcs_id);
	enable = read_tcs_reg(drv, reg, tcs_id);
	enable &= ~TCS_AMC_MODE_TRIGGER;
	enable &= ~TCS_AMC_MODE_TRIGGER;
	write_tcs_reg_sync(drv, RSC_DRV_CONTROL, tcs_id, enable);
	write_tcs_reg_sync(drv, reg, tcs_id, enable);
	enable &= ~TCS_AMC_MODE_ENABLE;
	enable &= ~TCS_AMC_MODE_ENABLE;
	write_tcs_reg_sync(drv, RSC_DRV_CONTROL, tcs_id, enable);
	write_tcs_reg_sync(drv, reg, tcs_id, enable);


	if (trigger) {
	if (trigger) {
		/* Enable the AMC mode on the TCS and then trigger the TCS */
		/* Enable the AMC mode on the TCS and then trigger the TCS */
		enable = TCS_AMC_MODE_ENABLE;
		enable = TCS_AMC_MODE_ENABLE;
		write_tcs_reg_sync(drv, RSC_DRV_CONTROL, tcs_id, enable);
		write_tcs_reg_sync(drv, reg, tcs_id, enable);
		enable |= TCS_AMC_MODE_TRIGGER;
		enable |= TCS_AMC_MODE_TRIGGER;
		write_tcs_reg(drv, RSC_DRV_CONTROL, tcs_id, enable);
		write_tcs_reg(drv, reg, tcs_id, enable);
	}
	}
}
}


@@ -384,13 +416,14 @@ static void __tcs_set_trigger(struct rsc_drv *drv, int tcs_id, bool trigger)
static void enable_tcs_irq(struct rsc_drv *drv, int tcs_id, bool enable)
static void enable_tcs_irq(struct rsc_drv *drv, int tcs_id, bool enable)
{
{
	u32 data;
	u32 data;
	u32 reg = drv->regs[RSC_DRV_IRQ_ENABLE];


	data = readl_relaxed(drv->tcs_base + RSC_DRV_IRQ_ENABLE);
	data = readl_relaxed(drv->tcs_base + reg);
	if (enable)
	if (enable)
		data |= BIT(tcs_id);
		data |= BIT(tcs_id);
	else
	else
		data &= ~BIT(tcs_id);
		data &= ~BIT(tcs_id);
	writel_relaxed(data, drv->tcs_base + RSC_DRV_IRQ_ENABLE);
	writel_relaxed(data, drv->tcs_base + reg);
}
}


/**
/**
@@ -411,7 +444,7 @@ static irqreturn_t tcs_tx_done(int irq, void *p)
	const struct tcs_request *req;
	const struct tcs_request *req;
	struct tcs_cmd *cmd;
	struct tcs_cmd *cmd;


	irq_status = readl_relaxed(drv->tcs_base + RSC_DRV_IRQ_STATUS);
	irq_status = readl_relaxed(drv->tcs_base + drv->regs[RSC_DRV_IRQ_STATUS]);


	for_each_set_bit(i, &irq_status, BITS_PER_TYPE(u32)) {
	for_each_set_bit(i, &irq_status, BITS_PER_TYPE(u32)) {
		req = get_req_from_tcs(drv, i);
		req = get_req_from_tcs(drv, i);
@@ -423,7 +456,7 @@ static irqreturn_t tcs_tx_done(int irq, void *p)
			u32 sts;
			u32 sts;


			cmd = &req->cmds[j];
			cmd = &req->cmds[j];
			sts = read_tcs_cmd(drv, RSC_DRV_CMD_STATUS, i, j);
			sts = read_tcs_cmd(drv, drv->regs[RSC_DRV_CMD_STATUS], i, j);
			if (!(sts & CMD_STATUS_ISSUED) ||
			if (!(sts & CMD_STATUS_ISSUED) ||
			   ((req->wait_for_compl || cmd->wait) &&
			   ((req->wait_for_compl || cmd->wait) &&
			   !(sts & CMD_STATUS_COMPL))) {
			   !(sts & CMD_STATUS_COMPL))) {
@@ -444,8 +477,8 @@ static irqreturn_t tcs_tx_done(int irq, void *p)
			__tcs_set_trigger(drv, i, false);
			__tcs_set_trigger(drv, i, false);
skip:
skip:
		/* Reclaim the TCS */
		/* Reclaim the TCS */
		write_tcs_reg(drv, RSC_DRV_CMD_ENABLE, i, 0);
		write_tcs_reg(drv, drv->regs[RSC_DRV_CMD_ENABLE], i, 0);
		writel_relaxed(BIT(i), drv->tcs_base + RSC_DRV_IRQ_CLEAR);
		writel_relaxed(BIT(i), drv->tcs_base + drv->regs[RSC_DRV_IRQ_CLEAR]);
		spin_lock(&drv->lock);
		spin_lock(&drv->lock);
		clear_bit(i, drv->tcs_in_use);
		clear_bit(i, drv->tcs_in_use);
		/*
		/*
@@ -496,14 +529,14 @@ static void __tcs_buffer_write(struct rsc_drv *drv, int tcs_id, int cmd_id,
		 */
		 */
		msgid |= cmd->wait ? CMD_MSGID_RESP_REQ : 0;
		msgid |= cmd->wait ? CMD_MSGID_RESP_REQ : 0;


		write_tcs_cmd(drv, RSC_DRV_CMD_MSGID, tcs_id, j, msgid);
		write_tcs_cmd(drv, drv->regs[RSC_DRV_CMD_MSGID], tcs_id, j, msgid);
		write_tcs_cmd(drv, RSC_DRV_CMD_ADDR, tcs_id, j, cmd->addr);
		write_tcs_cmd(drv, drv->regs[RSC_DRV_CMD_ADDR], tcs_id, j, cmd->addr);
		write_tcs_cmd(drv, RSC_DRV_CMD_DATA, tcs_id, j, cmd->data);
		write_tcs_cmd(drv, drv->regs[RSC_DRV_CMD_DATA], tcs_id, j, cmd->data);
		trace_rpmh_send_msg(drv, tcs_id, j, msgid, cmd);
		trace_rpmh_send_msg(drv, tcs_id, j, msgid, cmd);
	}
	}


	cmd_enable |= read_tcs_reg(drv, RSC_DRV_CMD_ENABLE, tcs_id);
	cmd_enable |= read_tcs_reg(drv, drv->regs[RSC_DRV_CMD_ENABLE], tcs_id);
	write_tcs_reg(drv, RSC_DRV_CMD_ENABLE, tcs_id, cmd_enable);
	write_tcs_reg(drv, drv->regs[RSC_DRV_CMD_ENABLE], tcs_id, cmd_enable);
}
}


/**
/**
@@ -535,10 +568,10 @@ static int check_for_req_inflight(struct rsc_drv *drv, struct tcs_group *tcs,
	int i = tcs->offset;
	int i = tcs->offset;


	for_each_set_bit_from(i, drv->tcs_in_use, tcs->offset + tcs->num_tcs) {
	for_each_set_bit_from(i, drv->tcs_in_use, tcs->offset + tcs->num_tcs) {
		curr_enabled = read_tcs_reg(drv, RSC_DRV_CMD_ENABLE, i);
		curr_enabled = read_tcs_reg(drv, drv->regs[RSC_DRV_CMD_ENABLE], i);


		for_each_set_bit(j, &curr_enabled, MAX_CMDS_PER_TCS) {
		for_each_set_bit(j, &curr_enabled, MAX_CMDS_PER_TCS) {
			addr = read_tcs_cmd(drv, RSC_DRV_CMD_ADDR, i, j);
			addr = read_tcs_cmd(drv, drv->regs[RSC_DRV_CMD_ADDR], i, j);
			for (k = 0; k < msg->num_cmds; k++) {
			for (k = 0; k < msg->num_cmds; k++) {
				if (addr == msg->cmds[k].addr)
				if (addr == msg->cmds[k].addr)
					return -EBUSY;
					return -EBUSY;
@@ -649,7 +682,7 @@ int rpmh_rsc_send_data(struct rsc_drv *drv, const struct tcs_request *msg)
		 * repurposed TCS to avoid triggering them. tcs->slots will be
		 * repurposed TCS to avoid triggering them. tcs->slots will be
		 * cleaned from rpmh_flush() by invoking rpmh_rsc_invalidate()
		 * cleaned from rpmh_flush() by invoking rpmh_rsc_invalidate()
		 */
		 */
		write_tcs_reg_sync(drv, RSC_DRV_CMD_ENABLE, tcs_id, 0);
		write_tcs_reg_sync(drv, drv->regs[RSC_DRV_CMD_ENABLE], tcs_id, 0);
		enable_tcs_irq(drv, tcs_id, true);
		enable_tcs_irq(drv, tcs_id, true);
	}
	}
	spin_unlock_irqrestore(&drv->lock, flags);
	spin_unlock_irqrestore(&drv->lock, flags);
@@ -957,7 +990,7 @@ static int rpmh_probe_tcs_config(struct platform_device *pdev, struct rsc_drv *d
		return ret;
		return ret;
	drv->tcs_base = drv->base + offset;
	drv->tcs_base = drv->base + offset;


	config = readl_relaxed(drv->base + DRV_PRNT_CHLD_CONFIG);
	config = readl_relaxed(drv->base + drv->regs[DRV_PRNT_CHLD_CONFIG]);


	max_tcs = config;
	max_tcs = config;
	max_tcs &= DRV_NUM_TCS_MASK << (DRV_NUM_TCS_SHIFT * drv->id);
	max_tcs &= DRV_NUM_TCS_MASK << (DRV_NUM_TCS_SHIFT * drv->id);
@@ -1019,6 +1052,7 @@ static int rpmh_rsc_probe(struct platform_device *pdev)
	char drv_id[10] = {0};
	char drv_id[10] = {0};
	int ret, irq;
	int ret, irq;
	u32 solver_config;
	u32 solver_config;
	u32 rsc_id;


	/*
	/*
	 * Even though RPMh doesn't directly use cmd-db, all of its children
	 * Even though RPMh doesn't directly use cmd-db, all of its children
@@ -1049,6 +1083,17 @@ static int rpmh_rsc_probe(struct platform_device *pdev)
	if (IS_ERR(drv->base))
	if (IS_ERR(drv->base))
		return PTR_ERR(drv->base);
		return PTR_ERR(drv->base);


	rsc_id = readl_relaxed(drv->base + RSC_DRV_ID);
	drv->ver.major = rsc_id & (MAJOR_VER_MASK << MAJOR_VER_SHIFT);
	drv->ver.major >>= MAJOR_VER_SHIFT;
	drv->ver.minor = rsc_id & (MINOR_VER_MASK << MINOR_VER_SHIFT);
	drv->ver.minor >>= MINOR_VER_SHIFT;

	if (drv->ver.major == 3 && drv->ver.minor == 0)
		drv->regs = rpmh_rsc_reg_offset_ver_3_0;
	else
		drv->regs = rpmh_rsc_reg_offset_ver_2_7;

	ret = rpmh_probe_tcs_config(pdev, drv);
	ret = rpmh_probe_tcs_config(pdev, drv);
	if (ret)
	if (ret)
		return ret;
		return ret;
@@ -1072,7 +1117,7 @@ static int rpmh_rsc_probe(struct platform_device *pdev)
	 * 'HW solver' mode where they can be in autonomous mode executing low
	 * 'HW solver' mode where they can be in autonomous mode executing low
	 * power mode to power down.
	 * power mode to power down.
	 */
	 */
	solver_config = readl_relaxed(drv->base + DRV_SOLVER_CONFIG);
	solver_config = readl_relaxed(drv->base + drv->regs[DRV_SOLVER_CONFIG]);
	solver_config &= DRV_HW_SOLVER_MASK << DRV_HW_SOLVER_SHIFT;
	solver_config &= DRV_HW_SOLVER_MASK << DRV_HW_SOLVER_SHIFT;
	solver_config = solver_config >> DRV_HW_SOLVER_SHIFT;
	solver_config = solver_config >> DRV_HW_SOLVER_SHIFT;
	if (!solver_config) {
	if (!solver_config) {
@@ -1088,7 +1133,7 @@ static int rpmh_rsc_probe(struct platform_device *pdev)


	/* Enable the active TCS to send requests immediately */
	/* Enable the active TCS to send requests immediately */
	writel_relaxed(drv->tcs[ACTIVE_TCS].mask,
	writel_relaxed(drv->tcs[ACTIVE_TCS].mask,
		       drv->tcs_base + RSC_DRV_IRQ_ENABLE);
		       drv->tcs_base + drv->regs[RSC_DRV_IRQ_ENABLE]);


	spin_lock_init(&drv->client.cache_lock);
	spin_lock_init(&drv->client.cache_lock);
	INIT_LIST_HEAD(&drv->client.cache);
	INIT_LIST_HEAD(&drv->client.cache);