soc: qcom: rpmh-rsc: Add RSC version 3 support

RSC major version 3.0 has different register offsets than previous
versions. Add support to read the current version during probe and
use register offsets accordingly.

Change-Id: I8174516ecd2ab7a370e1bb6592d4329c4ff1f81d
Signed-off-by: Maulik Shah <quic_mkshah@quicinc.com>
This commit is contained in:
Maulik Shah 2021-08-15 19:15:10 +05:30 committed by Gerrit - the friendly Code Review server
parent dac9bfe822
commit c02c62a522
2 changed files with 139 additions and 80 deletions

View File

@ -96,7 +96,9 @@ struct rpmh_ctrlr {
* Resource State Coordinator controller (RSC)
*
* @name: Controller identifier.
* @base: Base address of the RSC controller.
* @tcs_base: Start address of the TCS registers in this controller.
* @reg: Register offsets for RSC controller.
* @id: Instance id in the controller (Direct Resource Voter).
* @num_tcs: Number of TCSes in this DRV.
* @irq: IRQ at gic.
@ -123,7 +125,9 @@ struct rpmh_ctrlr {
*/
struct rsc_drv {
const char *name;
void __iomem *base;
void __iomem *tcs_base;
u32 *regs;
int id;
int num_tcs;
int irq;

View File

@ -38,50 +38,23 @@
#define RSC_DRV_IPC_LOG_SIZE 2
#define RSC_DRV_TCS_OFFSET 672
#define RSC_DRV_CMD_OFFSET 20
/* DRV ID Register */
#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
/* DRV HW Solver Configuration Information Register */
#define DRV_SOLVER_CONFIG 0x04
/* DRV HW Solver Configuration Register Mask */
#define DRV_HW_SOLVER_MASK 1
#define DRV_HW_SOLVER_SHIFT 24
/* DRV TCS Configuration Information Register */
#define DRV_PRNT_CHLD_CONFIG 0x0C
/* DRV TCS Configuration Information Register Mask */
#define DRV_NUM_TCS_MASK 0x3F
#define DRV_NUM_TCS_SHIFT 6
#define DRV_NCPT_MASK 0x1F
#define DRV_NCPT_SHIFT 27
/* 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_TRIGGER BIT(24)
@ -158,16 +131,89 @@ bool rpmh_standalone;
* +---------------------------------------------------+
*/
enum {
RSC_DRV_TCS_OFFSET,
RSC_DRV_CMD_OFFSET,
/* DRV HW Solver Configuration Information Register */
DRV_SOLVER_CONFIG,
/* DRV TCS Configuration Information Register */
DRV_PRNT_CHLD_CONFIG,
/* Offsets for common TCS Registers, one bit per TCS */
RSC_DRV_IRQ_ENABLE,
RSC_DRV_IRQ_STATUS,
RSC_DRV_IRQ_CLEAR, /* 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.
*/
RSC_DRV_CMD_WAIT_FOR_CMPL, /* 1 bit per command */
RSC_DRV_CONTROL,
RSC_DRV_STATUS, /* zero if tcs is busy */
RSC_DRV_CMD_ENABLE, /* 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.
*/
RSC_DRV_CMD_MSGID,
RSC_DRV_CMD_ADDR,
RSC_DRV_CMD_DATA,
RSC_DRV_CMD_STATUS,
RSC_DRV_CMD_RESP_DATA,
};
static u32 rpmh_rsc_reg_offsets_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_offsets_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 *
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 *
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,
@ -235,8 +281,7 @@ static void tcs_invalidate(struct rsc_drv *drv, int type)
return;
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);
}
@ -355,18 +400,18 @@ static void __tcs_set_trigger(struct rsc_drv *drv, int tcs_id, bool trigger)
* While clearing ensure that the AMC mode trigger is cleared
* and then the mode enable is cleared.
*/
enable = read_tcs_reg(drv, RSC_DRV_CONTROL, tcs_id);
enable = read_tcs_reg(drv, drv->regs[RSC_DRV_CONTROL], tcs_id);
enable &= ~TCS_AMC_MODE_TRIGGER;
write_tcs_reg_sync(drv, RSC_DRV_CONTROL, tcs_id, enable);
write_tcs_reg_sync(drv, drv->regs[RSC_DRV_CONTROL], tcs_id, enable);
enable &= ~TCS_AMC_MODE_ENABLE;
write_tcs_reg_sync(drv, RSC_DRV_CONTROL, tcs_id, enable);
write_tcs_reg_sync(drv, drv->regs[RSC_DRV_CONTROL], tcs_id, enable);
if (trigger) {
/* Enable the AMC mode on the TCS and then trigger the TCS */
enable = TCS_AMC_MODE_ENABLE;
write_tcs_reg_sync(drv, RSC_DRV_CONTROL, tcs_id, enable);
write_tcs_reg_sync(drv, drv->regs[RSC_DRV_CONTROL], tcs_id, enable);
enable |= TCS_AMC_MODE_TRIGGER;
write_tcs_reg(drv, RSC_DRV_CONTROL, tcs_id, enable);
write_tcs_reg(drv, drv->regs[RSC_DRV_CONTROL], tcs_id, enable);
}
}
@ -383,12 +428,12 @@ static void enable_tcs_irq(struct rsc_drv *drv, int tcs_id, bool enable)
{
u32 data;
data = readl_relaxed(drv->tcs_base + RSC_DRV_IRQ_ENABLE);
data = readl_relaxed(drv->tcs_base + drv->regs[RSC_DRV_IRQ_ENABLE]);
if (enable)
data |= BIT(tcs_id);
else
data &= ~BIT(tcs_id);
writel_relaxed(data, drv->tcs_base + RSC_DRV_IRQ_ENABLE);
writel_relaxed(data, drv->tcs_base + drv->regs[RSC_DRV_IRQ_ENABLE]);
}
/**
@ -408,7 +453,7 @@ static irqreturn_t tcs_tx_done(int irq, void *p)
unsigned long irq_status;
const struct tcs_request *req;
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)) {
req = get_req_from_tcs(drv, i);
@ -427,8 +472,8 @@ static irqreturn_t tcs_tx_done(int irq, void *p)
__tcs_set_trigger(drv, i, false);
skip:
/* Reclaim the TCS */
write_tcs_reg(drv, RSC_DRV_CMD_ENABLE, i, 0);
writel_relaxed(BIT(i), drv->tcs_base + RSC_DRV_IRQ_CLEAR);
write_tcs_reg(drv, drv->regs[RSC_DRV_CMD_ENABLE], i, 0);
writel_relaxed(BIT(i), drv->tcs_base + drv->regs[RSC_DRV_IRQ_CLEAR]);
spin_lock(&drv->lock);
clear_bit(i, drv->tcs_in_use);
/*
@ -479,9 +524,9 @@ static void __tcs_buffer_write(struct rsc_drv *drv, int tcs_id, int cmd_id,
*/
msgid |= cmd->wait ? CMD_MSGID_RESP_REQ : 0;
write_tcs_cmd(drv, 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, RSC_DRV_CMD_DATA, tcs_id, j, cmd->data);
write_tcs_cmd(drv, drv->regs[RSC_DRV_CMD_MSGID], tcs_id, j, msgid);
write_tcs_cmd(drv, drv->regs[RSC_DRV_CMD_ADDR], tcs_id, j, cmd->addr);
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);
ipc_log_string(drv->ipc_log_ctx,
"TCS write: m=%d n=%d msgid=%#x addr=%#x data=%#x wait=%d",
@ -489,8 +534,8 @@ static void __tcs_buffer_write(struct rsc_drv *drv, int tcs_id, int cmd_id,
cmd->data, cmd->wait);
}
cmd_enable |= read_tcs_reg(drv, RSC_DRV_CMD_ENABLE, tcs_id);
write_tcs_reg(drv, RSC_DRV_CMD_ENABLE, tcs_id, cmd_enable);
cmd_enable |= read_tcs_reg(drv, drv->regs[RSC_DRV_CMD_ENABLE], tcs_id);
write_tcs_reg(drv, drv->regs[RSC_DRV_CMD_ENABLE], tcs_id, cmd_enable);
}
/**
@ -522,10 +567,10 @@ static int check_for_req_inflight(struct rsc_drv *drv, struct tcs_group *tcs,
int i = tcs->offset;
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) {
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++) {
if (addr == msg->cmds[k].addr)
return -EBUSY;
@ -642,7 +687,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
* 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);
}
spin_unlock_irqrestore(&drv->lock, flags);
@ -754,16 +799,16 @@ static void print_tcs_info(struct rsc_drv *drv, int tcs_id, unsigned long *accl,
bool in_use = test_bit(tcs_id, drv->tcs_in_use);
int i;
sts = read_tcs_reg(drv, RSC_DRV_STATUS, tcs_id);
cmds_enabled = read_tcs_reg(drv, RSC_DRV_CMD_ENABLE, tcs_id);
sts = read_tcs_reg(drv, drv->regs[RSC_DRV_STATUS], tcs_id);
cmds_enabled = read_tcs_reg(drv, drv->regs[RSC_DRV_CMD_ENABLE], tcs_id);
if (!cmds_enabled)
return;
if (!tcs_grp || !req)
goto print_tcs_data;
data = read_tcs_reg(drv, RSC_DRV_CONTROL, tcs_id);
irq_sts = readl_relaxed(drv->tcs_base + RSC_DRV_IRQ_STATUS);
data = read_tcs_reg(drv, drv->regs[RSC_DRV_CONTROL], tcs_id);
irq_sts = readl_relaxed(drv->tcs_base + drv->regs[RSC_DRV_IRQ_STATUS]);
pr_warn("Request: tcs-in-use:%s active_tcs=%s(%d) state=%d wait_for_compl=%u]\n",
(in_use ? "YES" : "NO"),
((tcs_grp->type == ACTIVE_TCS) ? "YES" : "NO"),
@ -776,10 +821,10 @@ static void print_tcs_info(struct rsc_drv *drv, int tcs_id, unsigned long *accl,
print_tcs_data:
for_each_set_bit(i, &cmds_enabled, MAX_CMDS_PER_TCS) {
addr = read_tcs_cmd(drv, RSC_DRV_CMD_ADDR, tcs_id, i);
data = read_tcs_cmd(drv, RSC_DRV_CMD_DATA, tcs_id, i);
msgid = read_tcs_cmd(drv, RSC_DRV_CMD_MSGID, tcs_id, i);
sts = read_tcs_cmd(drv, RSC_DRV_CMD_STATUS, tcs_id, i);
addr = read_tcs_cmd(drv, drv->regs[RSC_DRV_CMD_ADDR], tcs_id, i);
data = read_tcs_cmd(drv, drv->regs[RSC_DRV_CMD_DATA], tcs_id, i);
msgid = read_tcs_cmd(drv, drv->regs[RSC_DRV_CMD_MSGID], tcs_id, i);
sts = read_tcs_cmd(drv, drv->regs[RSC_DRV_CMD_STATUS], tcs_id, i);
pr_warn("\tCMD=%d [addr=0x%x data=0x%x hdr=0x%x sts=0x%x enabled=1]\n",
i, addr, data, msgid, sts);
if (!(sts & CMD_STATUS_ISSUED))
@ -832,7 +877,7 @@ void rpmh_rsc_debug(struct rsc_drv *drv, struct completion *compl)
/* Show fast path status, if the TCS is busy */
if (drv->tcs[FAST_PATH_TCS].num_tcs) {
int tcs_id = drv->tcs[FAST_PATH_TCS].offset;
bool sts = read_tcs_reg(drv, RSC_DRV_STATUS, tcs_id);
bool sts = read_tcs_reg(drv, drv->regs[RSC_DRV_STATUS], tcs_id);
if (!sts) {
pr_err("Fast-path TCS information:\n");
@ -884,7 +929,7 @@ static bool rpmh_rsc_ctrlr_is_busy(struct rsc_drv *drv)
/* Check if there is pending fastpath transaction */
if (drv->tcs[FAST_PATH_TCS].num_tcs &&
!read_tcs_reg(drv, RSC_DRV_STATUS, drv->tcs[FAST_PATH_TCS].offset))
!read_tcs_reg(drv, drv->regs[RSC_DRV_STATUS], drv->tcs[FAST_PATH_TCS].offset))
return true;
return set < max;
@ -1052,7 +1097,7 @@ int rpmh_rsc_update_fast_path(struct rsc_drv *drv,
/* Ensure the TCS is free before writing to the TCS */
do {
sts = read_tcs_reg(drv, RSC_DRV_STATUS, tcs_id);
sts = read_tcs_reg(drv, drv->regs[RSC_DRV_STATUS], tcs_id);
if (!sts) {
retry--;
/* Report and bail, if it took too many attempts */
@ -1073,7 +1118,7 @@ int rpmh_rsc_update_fast_path(struct rsc_drv *drv,
if (!(mask & BIT(i)))
continue;
cmd = &msg->cmds[i];
write_tcs_cmd(drv, RSC_DRV_CMD_DATA, tcs_id, i, cmd->data);
write_tcs_cmd(drv, drv->regs[RSC_DRV_CMD_DATA], tcs_id, i, cmd->data);
}
/* Trigger the TCS to send the request */
@ -1083,7 +1128,7 @@ int rpmh_rsc_update_fast_path(struct rsc_drv *drv,
}
static int rpmh_probe_tcs_config(struct platform_device *pdev,
struct rsc_drv *drv, void __iomem *base)
struct rsc_drv *drv)
{
struct tcs_type_config {
u32 type;
@ -1097,9 +1142,9 @@ static int rpmh_probe_tcs_config(struct platform_device *pdev,
ret = of_property_read_u32(dn, "qcom,tcs-offset", &offset);
if (ret)
return ret;
drv->tcs_base = base + offset;
drv->tcs_base = drv->base + offset;
config = readl_relaxed(base + DRV_PRNT_CHLD_CONFIG);
config = readl_relaxed(drv->base + drv->regs[DRV_PRNT_CHLD_CONFIG]);
max_tcs = config;
max_tcs &= DRV_NUM_TCS_MASK << (DRV_NUM_TCS_SHIFT * drv->id);
@ -1186,8 +1231,7 @@ static int rpmh_rsc_probe(struct platform_device *pdev)
struct rsc_drv *drv;
char drv_id[10] = {0};
int ret, irq;
u32 solver_config;
void __iomem *base;
u32 rsc_id, major_ver, minor_ver, solver_config;
/*
* Even though RPMh doesn't directly use cmd-db, all of its children
@ -1219,11 +1263,22 @@ static int rpmh_rsc_probe(struct platform_device *pdev)
drv->name = dev_name(&pdev->dev);
snprintf(drv_id, ARRAY_SIZE(drv_id), "drv-%d", drv->id);
base = devm_platform_ioremap_resource_byname(pdev, drv_id);
if (IS_ERR(base))
return PTR_ERR(base);
drv->base = devm_platform_ioremap_resource_byname(pdev, drv_id);
if (IS_ERR(drv->base))
return PTR_ERR(drv->base);
ret = rpmh_probe_tcs_config(pdev, drv, base);
rsc_id = readl_relaxed(drv->base + RSC_DRV_ID);
major_ver = rsc_id & (MAJOR_VER_MASK << MAJOR_VER_SHIFT);
major_ver >>= MAJOR_VER_SHIFT;
minor_ver = rsc_id & (MINOR_VER_MASK << MINOR_VER_SHIFT);
minor_ver >>= MINOR_VER_SHIFT;
if (major_ver >= 3 && minor_ver >= 0)
drv->regs = rpmh_rsc_reg_offsets_ver_3_0;
else
drv->regs = rpmh_rsc_reg_offsets_ver_2_7;
ret = rpmh_probe_tcs_config(pdev, drv);
if (ret)
return ret;
@ -1249,7 +1304,7 @@ static int rpmh_rsc_probe(struct platform_device *pdev)
* 'HW solver' mode where they can be in autonomous mode executing low
* power mode to power down.
*/
solver_config = readl_relaxed(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 = solver_config >> DRV_HW_SOLVER_SHIFT;
if (of_find_property(dn, "power-domains", NULL)) {
@ -1268,7 +1323,7 @@ static int rpmh_rsc_probe(struct platform_device *pdev)
/* Enable the active TCS to send requests immediately */
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);
INIT_LIST_HEAD(&drv->client.cache);