soc: qcom: rpmh: Add HW channel support for camera RSC

This change adds APIs to start/stop camera RSC channels
which can be used by clients.

Update the rpmh_rsc_get_channel() to select unused channel
to flush the cached sleep and wake requests.

Also assume the 'solver' state during probe to disallow
RPMH_ACTIVE_ONLY_STATE requests.

Change-Id: I0ea6aa9f8d2961428636961d3cb53f5e67f37f54
Signed-off-by: Maulik Shah <quic_mkshah@quicinc.com>
This commit is contained in:
Maulik Shah 2021-08-16 09:20:36 +05:30 committed by Gerrit - the friendly Code Review server
parent b6a55a9af0
commit dc365aa135
4 changed files with 225 additions and 4 deletions

View File

@ -25,6 +25,7 @@
/* CTRLR specific flags */
#define SOLVER_PRESENT 1
#define HW_CHANNEL_PRESENT 2
struct rsc_drv;
@ -179,6 +180,8 @@ void rpmh_rsc_invalidate(struct rsc_drv *drv, int ch);
void rpmh_rsc_debug(struct rsc_drv *drv, struct completion *compl);
int rpmh_rsc_mode_solver_set(struct rsc_drv *drv, bool enable);
int rpmh_rsc_get_channel(struct rsc_drv *drv);
int rpmh_rsc_switch_channel(struct rsc_drv *drv, int ch);
int rpmh_rsc_drv_enable(struct rsc_drv *drv, bool enable);
void rpmh_tx_done(const struct tcs_request *msg);
int rpmh_flush(struct rpmh_ctrlr *ctrlr, int ch);

View File

@ -173,6 +173,12 @@ enum {
RSC_DRV_CMD_DATA,
RSC_DRV_CMD_STATUS,
RSC_DRV_CMD_RESP_DATA,
/* DRV channel Registers */
RSC_DRV_CHN_TCS_TRIGGER,
RSC_DRV_CHN_TCS_COMPLETE,
RSC_DRV_CHN_UPDATE,
RSC_DRV_CHN_BUSY,
RSC_DRV_CHN_EN,
};
static u32 rpmh_rsc_reg_offsets_ver_2_7[] = {
@ -192,6 +198,11 @@ static u32 rpmh_rsc_reg_offsets_ver_2_7[] = {
[RSC_DRV_CMD_DATA] = 0x38,
[RSC_DRV_CMD_STATUS] = 0x3C,
[RSC_DRV_CMD_RESP_DATA] = 0x40,
[RSC_DRV_CHN_TCS_TRIGGER] = 0x0,
[RSC_DRV_CHN_TCS_COMPLETE] = 0x0,
[RSC_DRV_CHN_UPDATE] = 0x0,
[RSC_DRV_CHN_BUSY] = 0x0,
[RSC_DRV_CHN_EN] = 0x0,
};
static u32 rpmh_rsc_reg_offsets_ver_3_0[] = {
@ -211,6 +222,35 @@ static u32 rpmh_rsc_reg_offsets_ver_3_0[] = {
[RSC_DRV_CMD_DATA] = 0x3C,
[RSC_DRV_CMD_STATUS] = 0x40,
[RSC_DRV_CMD_RESP_DATA] = 0x44,
[RSC_DRV_CHN_TCS_TRIGGER] = 0x490,
[RSC_DRV_CHN_TCS_COMPLETE] = 0x494,
[RSC_DRV_CHN_UPDATE] = 0x498,
[RSC_DRV_CHN_BUSY] = 0x49C,
[RSC_DRV_CHN_EN] = 0x4A0,
};
static u32 rpmh_rsc_reg_offsets_ver_3_0_hw_channel[] = {
[RSC_DRV_TCS_OFFSET] = 336,
[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,
[RSC_DRV_CHN_TCS_TRIGGER] = 0x490,
[RSC_DRV_CHN_TCS_COMPLETE] = 0x494,
[RSC_DRV_CHN_UPDATE] = 0x498,
[RSC_DRV_CHN_BUSY] = 0x49C,
[RSC_DRV_CHN_EN] = 0x4A0,
};
static inline void __iomem *
@ -303,8 +343,21 @@ static void tcs_invalidate(struct rsc_drv *drv, int type, int ch)
*/
int rpmh_rsc_get_channel(struct rsc_drv *drv)
{
int chn_update, chn_busy;
if (drv->num_channels == 1)
return CH0;
/* Select Unused channel */
do {
chn_update = readl_relaxed(drv->base + drv->regs[RSC_DRV_CHN_UPDATE]);
chn_busy = readl_relaxed(drv->base + drv->regs[RSC_DRV_CHN_BUSY]);
} while (chn_busy != chn_update);
if (chn_busy & CH0_CHN_BUSY)
return CH1;
else if (chn_busy & CH1_CHN_BUSY)
return CH0;
else
return -EBUSY;
}
@ -1101,6 +1154,104 @@ int rpmh_rsc_mode_solver_set(struct rsc_drv *drv, bool enable)
return ret;
}
int rpmh_rsc_is_tcs_completed(struct rsc_drv *drv, int ch)
{
u32 sts;
int retry = 10;
do {
sts = readl_relaxed(drv->base + drv->regs[RSC_DRV_CHN_TCS_COMPLETE]);
if (ch == 0)
sts &= CH0_WAKE_TCS_STATUS;
else
sts &= CH1_WAKE_TCS_STATUS;
retry--;
} while (!sts && retry);
if (!retry)
return -EBUSY;
writel_relaxed(CH_CLEAR_STATUS,
drv->base + drv->regs[RSC_DRV_CHN_TCS_COMPLETE]);
return 0;
}
/**
* rpmh_rsc_switch_channel() - Switch to the channel
* @drv: The controller.
* @ch: The channel number to switch to.
*
* NOTE: Caller should ensure serialization before making this call.
* Return:
* * 0 - success
* * -Error - Error code
*/
int rpmh_rsc_switch_channel(struct rsc_drv *drv, int ch)
{
writel_relaxed(BIT(ch), drv->base + drv->regs[RSC_DRV_CHN_UPDATE]);
return rpmh_rsc_is_tcs_completed(drv, ch);
}
/**
* rpmh_rsc_drv_enable() - Enable the DRV and trigger Wake vote
* @drv: The controller.
*
* NOTE: Caller should ensure serialization before making this call.
* Return:
* * 0 - success
* * -Error - Error code
*/
int rpmh_rsc_drv_enable(struct rsc_drv *drv, bool enable)
{
int ret = 0, ch;
u32 chn_en;
spin_lock(&drv->lock);
chn_en = readl_relaxed(drv->base + drv->regs[RSC_DRV_CHN_EN]);
if (chn_en == enable) {
ret = -EINVAL;
goto exit;
}
if (enable) {
/* Start with channel 0 */
ch = 0;
ret = rpmh_flush(&drv->client, ch);
if (ret)
goto exit;
writel_relaxed(enable, drv->base + drv->regs[RSC_DRV_CHN_EN]);
ret = rpmh_rsc_switch_channel(drv, ch);
if (ret)
goto exit;
} else {
/* Select unused channel */
ch = rpmh_rsc_get_channel(drv);
if (ch < 0)
goto exit;
ret = rpmh_flush(&drv->client, ch);
if (ret)
goto exit;
ret = rpmh_rsc_switch_channel(drv, ch);
if (ret)
goto exit;
writel_relaxed(0, drv->base + drv->regs[RSC_DRV_CHN_UPDATE]);
writel_relaxed(enable, drv->base + drv->regs[RSC_DRV_CHN_EN]);
}
exit:
spin_unlock(&drv->lock);
return ret;
}
/**
* rpmh_rsc_init_fast_path() - Initialize the fast-path TCS contents
* @drv: The controller.
@ -1423,11 +1574,25 @@ static int rpmh_rsc_probe(struct platform_device *pdev)
ret = rpmh_rsc_pd_attach(&drv[i]);
if (ret)
return ret;
} else if (!solver_config) {
} else if (!solver_config &&
!of_find_property(dn, "qcom,hw-channel", NULL)) {
drv[i].rsc_pm.notifier_call = rpmh_rsc_cpu_pm_callback;
cpu_pm_register_notifier(&drv[i].rsc_pm);
} else
} else if (solver_config) {
drv[i].client.flags = SOLVER_PRESENT;
} else {
/*
* The requets for HW channel TCSes has to be either
* RPMH_SLEEP_STATE or RPMH_WAKE_ONLY_STATE.
*
* Assume 'solver' state which does nothing but to disallow
* RPMH_ACTIVE_ONLY_STATE requests.
*/
drv[i].client.flags = SOLVER_PRESENT | HW_CHANNEL_PRESENT;
drv[i].client.in_solver_mode = true;
drv[i].in_solver_mode = true;
drv[i].regs = rpmh_rsc_reg_offsets_ver_3_0_hw_channel;
}
spin_lock_init(&drv[i].lock);
init_waitqueue_head(&drv[i].tcs_wait);

View File

@ -568,13 +568,17 @@ int rpmh_flush(struct rpmh_ctrlr *ctrlr, int ch)
int rpmh_write_sleep_and_wake(const struct device *dev)
{
struct rpmh_ctrlr *ctrlr = get_rpmh_ctrlr(dev);
int ch;
int ch, ret;
ch = rpmh_rsc_get_channel(ctrlr_to_drv(ctrlr));
if (ch < 0)
return ch;
return rpmh_flush(ctrlr, ch);
ret = rpmh_flush(ctrlr, ch);
if (ret || !(ctrlr->flags & HW_CHANNEL_PRESENT))
return ret;
return rpmh_rsc_switch_channel(ctrlr_to_drv(ctrlr), ch);
}
EXPORT_SYMBOL(rpmh_write_sleep_and_wake);
@ -723,3 +727,43 @@ int rpmh_update_fast_path(const struct device *dev,
update_mask, ch);
}
EXPORT_SYMBOL(rpmh_update_fast_path);
/**
* rpmh_drv_start: Start the DRV channel
*
* @dev: The device making the request
*
* Return:
* * 0 - Success
* * Error code - Otherwise
*/
int rpmh_drv_start(const struct device *dev)
{
struct rpmh_ctrlr *ctrlr = get_rpmh_ctrlr(dev);
if (rpmh_standalone)
return 0;
return rpmh_rsc_drv_enable(ctrlr_to_drv(ctrlr), true);
}
EXPORT_SYMBOL(rpmh_drv_start);
/**
* rpmh_drv_stop: Start the DRV channel
*
* @dev: The device making the request
*
* Return:
* * 0 - Success
* * Error code - Otherwise
*/
int rpmh_drv_stop(const struct device *dev)
{
struct rpmh_ctrlr *ctrlr = get_rpmh_ctrlr(dev);
if (rpmh_standalone)
return 0;
return rpmh_rsc_drv_enable(ctrlr_to_drv(ctrlr), false);
}
EXPORT_SYMBOL(rpmh_drv_stop);

View File

@ -31,6 +31,9 @@ int rpmh_init_fast_path(const struct device *dev,
int rpmh_update_fast_path(const struct device *dev,
struct tcs_cmd *cmd, int n, u32 update_mask);
int rpmh_drv_start(const struct device *dev);
int rpmh_drv_stop(const struct device *dev);
#else
static inline int rpmh_write(const struct device *dev, enum rpmh_state state,
@ -66,6 +69,12 @@ static inline int rpmh_update_fast_path(const struct device *dev,
u32 update_mask)
{ return -ENODEV; }
int rpmh_drv_start(const struct device *dev)
{ return -ENODEV; }
int rpmh_drv_stop(const struct device *dev)
{ return -ENODEV; }
#endif /* CONFIG_QCOM_RPMH */
#endif /* __SOC_QCOM_RPMH_H__ */