diff --git a/drivers/soc/qcom/rpmh-internal.h b/drivers/soc/qcom/rpmh-internal.h index 7c1a13db3ce0..6fb7e0618f7d 100644 --- a/drivers/soc/qcom/rpmh-internal.h +++ b/drivers/soc/qcom/rpmh-internal.h @@ -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; diff --git a/drivers/soc/qcom/rpmh-rsc.c b/drivers/soc/qcom/rpmh-rsc.c index 27ed00539bae..917cb7e216a1 100644 --- a/drivers/soc/qcom/rpmh-rsc.c +++ b/drivers/soc/qcom/rpmh-rsc.c @@ -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);