drivers: qcom: rpmh-rsc: Add hibernation support

Add hibernation support for rpmh-rsc driver.

Change-Id: I55904c2332016815dcf1e127d2ae8a8510d48e38
Signed-off-by: Maulik Shah <quic_mkshah@quicinc.com>
This commit is contained in:
Maulik Shah 2022-05-09 13:41:37 +05:30 committed by Gerrit - the friendly Code Review server
parent 55a98392c2
commit 50922dfe8f
4 changed files with 173 additions and 2 deletions

View File

@ -111,6 +111,23 @@ struct drv_channel {
bool initialized;
};
/**
* struct rsc_drv_top: our representation of the top RSC device
*
* @name: Controller RSC device name.
* @drv_count: No. of DRV controllers in the RSC device
* @drv: Controller for each DRV
* @dev: RSC top device
* @list: RSC device added in rpmh_rsc_dev_list.
*/
struct rsc_drv_top {
char name[MAX_NAME_LENGTH];
int drv_count;
struct rsc_drv *drv;
struct device *dev;
struct list_head list;
};
/**
* struct rsc_drv: the Direct Resource Voter (DRV) of the
* Resource State Coordinator controller (RSC)
@ -182,6 +199,7 @@ 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);
const struct device *rpmh_rsc_get_device(const char *name, u32 drv_id);
void rpmh_tx_done(const struct tcs_request *msg);
int rpmh_flush(struct rpmh_ctrlr *ctrlr, int ch);

View File

@ -82,6 +82,7 @@ static const char * const accl_str[] = {
"", "", "", "CLK", "VREG", "BUS",
};
static LIST_HEAD(rpmh_rsc_dev_list);
static struct rsc_drv *__rsc_drv[MAX_RSC_COUNT];
static int __rsc_count;
bool rpmh_standalone;
@ -1345,6 +1346,73 @@ int rpmh_rsc_update_fast_path(struct rsc_drv *drv,
return 0;
}
static int rpmh_rsc_poweroff_noirq(struct device *dev)
{
return 0;
}
static void rpmh_rsc_tcs_irq_enable(struct rsc_drv *drv)
{
u32 tcs_mask;
int ch;
for (ch = 0; ch < MAX_CHANNEL; ch++) {
if (!drv->ch[ch].initialized)
continue;
tcs_mask = readl_relaxed(drv->tcs_base + drv->regs[RSC_DRV_IRQ_ENABLE]);
tcs_mask |= drv->ch[ch].tcs[ACTIVE_TCS].mask;
writel_relaxed(tcs_mask, drv->tcs_base + drv->regs[RSC_DRV_IRQ_ENABLE]);
}
}
static int rpmh_rsc_restore_noirq(struct device *dev)
{
struct rsc_drv_top *rsc_top = dev_get_drvdata(dev);
int i;
for (i = 0; i < rsc_top->drv_count; i++) {
if (rsc_top->drv[i].initialized)
rpmh_rsc_tcs_irq_enable(&rsc_top->drv[i]);
}
return 0;
}
static struct rsc_drv_top *rpmh_rsc_get_top_device(const char *name)
{
struct rsc_drv_top *rsc_top;
bool rsc_dev_present = false;
list_for_each_entry(rsc_top, &rpmh_rsc_dev_list, list) {
if (!strcmp(name, rsc_top->name)) {
rsc_dev_present = true;
break;
}
}
if (!rsc_dev_present)
return ERR_PTR(-ENODEV);
return rsc_top;
}
const struct device *rpmh_rsc_get_device(const char *name, u32 drv_id)
{
struct rsc_drv_top *rsc_top = rpmh_rsc_get_top_device(name);
int i;
if (IS_ERR(rsc_top))
return ERR_PTR(-ENODEV);
for (i = 0; i < rsc_top->drv_count; i++) {
if (i == drv_id && rsc_top->drv[i].initialized)
return rsc_top->drv[i].dev;
}
return ERR_PTR(-ENODEV);
}
static int rpmh_probe_channel_tcs_config(struct device_node *np,
struct rsc_drv *drv,
u32 max_tcs, u32 ncpt, int ch)
@ -1481,6 +1549,7 @@ static int rpmh_rsc_probe(struct platform_device *pdev)
{
struct device_node *np, *dn = pdev->dev.of_node;
struct rsc_drv *drv;
struct rsc_drv_top *rsc_top;
int ret, irq;
u32 rsc_id, major_ver, minor_ver, solver_config;
int i, drv_count;
@ -1503,6 +1572,10 @@ static int rpmh_rsc_probe(struct platform_device *pdev)
dev_info(&pdev->dev, "RPMH is running in standalone mode.\n");
rsc_top = devm_kzalloc(&pdev->dev, sizeof(*rsc_top), GFP_KERNEL);
if (!rsc_top)
return -ENOMEM;
ret = of_property_read_u32(dn, "qcom,drv-count", &drv_count);
if (ret)
return ret;
@ -1515,6 +1588,11 @@ static int rpmh_rsc_probe(struct platform_device *pdev)
if (!name)
name = dev_name(&pdev->dev);
rsc_top->drv_count = drv_count;
rsc_top->drv = drv;
rsc_top->dev = &pdev->dev;
scnprintf(rsc_top->name, sizeof(rsc_top->name), "%s", name);
for_each_child_of_node(dn, np) {
struct device *drv_dev;
@ -1633,9 +1711,18 @@ static int rpmh_rsc_probe(struct platform_device *pdev)
return ret;
}
INIT_LIST_HEAD(&rsc_top->list);
list_add_tail(&rsc_top->list, &rpmh_rsc_dev_list);
dev_set_drvdata(&pdev->dev, &rsc_top);
return devm_of_platform_populate(&pdev->dev);
}
static const struct dev_pm_ops rpmh_rsc_dev_pm_ops = {
.poweroff_noirq = rpmh_rsc_poweroff_noirq,
.restore_noirq = rpmh_rsc_restore_noirq,
};
static const struct of_device_id rpmh_drv_match[] = {
{ .compatible = "qcom,rpmh-rsc", },
{ }
@ -1647,6 +1734,7 @@ static struct platform_driver rpmh_driver = {
.driver = {
.name = "rpmh",
.of_match_table = rpmh_drv_match,
.pm = &rpmh_rsc_dev_pm_ops,
.suppress_bind_attrs = true,
},
};

View File

@ -76,6 +76,13 @@ static struct rpmh_ctrlr *get_rpmh_ctrlr(const struct device *dev)
return &drv->client;
}
static struct rpmh_ctrlr *get_rpmh_ctrlr_no_child(const struct device *dev)
{
struct rsc_drv *drv = dev_get_drvdata(dev);
return &drv->client;
}
static int check_ctrlr_state(struct rpmh_ctrlr *ctrlr, enum rpmh_state state)
{
int ret = 0;
@ -582,6 +589,34 @@ int rpmh_write_sleep_and_wake(const struct device *dev)
}
EXPORT_SYMBOL(rpmh_write_sleep_and_wake);
/**
* rpmh_write_sleep_and_wake_no_child: Writes the buffered wake and sleep sets to TCSes
*
* Used when the client calling this is not a child device of RSC device.
* Use it only after getting the device using rpmh_get_device().
* @dev: The device making the request
*
* Return:
* * 0 - Success
* * Error code - Otherwise
*/
int rpmh_write_sleep_and_wake_no_child(const struct device *dev)
{
struct rpmh_ctrlr *ctrlr = get_rpmh_ctrlr_no_child(dev);
int ch, ret;
ch = rpmh_rsc_get_channel(ctrlr_to_drv(ctrlr));
if (ch < 0)
return 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_no_child);
/**
* rpmh_invalidate: Invalidate sleep and wake sets in batch_cache
*
@ -728,6 +763,27 @@ int rpmh_update_fast_path(const struct device *dev,
}
EXPORT_SYMBOL(rpmh_update_fast_path);
/**
* rpmh_get_device: Get the DRV device
*
* @name: The RSC device used for DRV DRV
* @drv_id: The index of DRV
*
* Used when the device voting to RPMh is not a child device
* of RSC device. Such device can get RSC device using this API.
* but will be able to use only rpmh_drv_start(), rpmh_drv_stop()
* and rpmh_write_sleep_and_wake_no_child().
*
* Return:
* * dev - Device to use when calling above APIs
* * Error - Error pointer
*/
const struct device *rpmh_get_device(const char *name, u32 drv_id)
{
return rpmh_rsc_get_device(name, drv_id);
}
EXPORT_SYMBOL(rpmh_get_device);
/**
* rpmh_drv_start: Start the DRV channel
*
@ -739,7 +795,7 @@ EXPORT_SYMBOL(rpmh_update_fast_path);
*/
int rpmh_drv_start(const struct device *dev)
{
struct rpmh_ctrlr *ctrlr = get_rpmh_ctrlr(dev);
struct rpmh_ctrlr *ctrlr = get_rpmh_ctrlr_no_child(dev);
if (rpmh_standalone)
return 0;
@ -759,7 +815,7 @@ EXPORT_SYMBOL(rpmh_drv_start);
*/
int rpmh_drv_stop(const struct device *dev)
{
struct rpmh_ctrlr *ctrlr = get_rpmh_ctrlr(dev);
struct rpmh_ctrlr *ctrlr = get_rpmh_ctrlr_no_child(dev);
if (rpmh_standalone)
return 0;

View File

@ -24,6 +24,8 @@ int rpmh_mode_solver_set(const struct device *dev, bool enable);
int rpmh_write_sleep_and_wake(const struct device *dev);
int rpmh_write_sleep_and_wake_no_child(const struct device *dev);
void rpmh_invalidate(const struct device *dev);
int rpmh_init_fast_path(const struct device *dev,
@ -34,6 +36,8 @@ int rpmh_update_fast_path(const struct device *dev,
int rpmh_drv_start(const struct device *dev);
int rpmh_drv_stop(const struct device *dev);
const struct device *rpmh_get_device(const char *name, u32 drv_id);
#else
static inline int rpmh_write(const struct device *dev, enum rpmh_state state,
@ -56,6 +60,9 @@ static int rpmh_mode_solver_set(const struct device *dev, bool enable)
static int rpmh_write_sleep_and_wake(const struct device *dev)
{ return -ENODEV; }
static int rpmh_write_sleep_and_wake_no_child(const struct device *dev)
{ return -ENODEV; }
static inline void rpmh_invalidate(const struct device *dev)
{
}
@ -75,6 +82,8 @@ int rpmh_drv_start(const struct device *dev)
int rpmh_drv_stop(const struct device *dev)
{ return -ENODEV; }
static const struct device *rpmh_get_device(char *name, u32 drv_id)
{ return ERR_PTR(-ENODEV); }
#endif /* CONFIG_QCOM_RPMH */
#endif /* __SOC_QCOM_RPMH_H__ */