mirror of
https://github.com/torvalds/linux.git
synced 2026-07-31 03:27:03 +02:00
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:
parent
b6a55a9af0
commit
dc365aa135
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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__ */
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user