mirror of
https://github.com/torvalds/linux.git
synced 2026-07-31 11:37:06 +02:00
Merge "drivers: qcom: rpmh-rsc: Add hibernation support"
This commit is contained in:
commit
3e4fe509e1
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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__ */
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user