diff options
Diffstat (limited to 'drivers/firmware')
-rw-r--r-- | drivers/firmware/arm_scpi.c | 63 | ||||
-rw-r--r-- | drivers/firmware/tegra/bpmp.c | 32 |
2 files changed, 85 insertions, 10 deletions
diff --git a/drivers/firmware/arm_scpi.c b/drivers/firmware/arm_scpi.c index f6cfc31d34c7..8043e51de897 100644 --- a/drivers/firmware/arm_scpi.c +++ b/drivers/firmware/arm_scpi.c @@ -39,6 +39,7 @@ #include <linux/of_address.h> #include <linux/of_platform.h> #include <linux/printk.h> +#include <linux/pm_opp.h> #include <linux/scpi_protocol.h> #include <linux/slab.h> #include <linux/sort.h> @@ -684,6 +685,65 @@ static struct scpi_dvfs_info *scpi_dvfs_get_info(u8 domain) return info; } +static int scpi_dev_domain_id(struct device *dev) +{ + struct of_phandle_args clkspec; + + if (of_parse_phandle_with_args(dev->of_node, "clocks", "#clock-cells", + 0, &clkspec)) + return -EINVAL; + + return clkspec.args[0]; +} + +static struct scpi_dvfs_info *scpi_dvfs_info(struct device *dev) +{ + int domain = scpi_dev_domain_id(dev); + + if (domain < 0) + return ERR_PTR(domain); + + return scpi_dvfs_get_info(domain); +} + +static int scpi_dvfs_get_transition_latency(struct device *dev) +{ + struct scpi_dvfs_info *info = scpi_dvfs_info(dev); + + if (IS_ERR(info)) + return PTR_ERR(info); + + if (!info->latency) + return 0; + + return info->latency; +} + +static int scpi_dvfs_add_opps_to_device(struct device *dev) +{ + int idx, ret; + struct scpi_opp *opp; + struct scpi_dvfs_info *info = scpi_dvfs_info(dev); + + if (IS_ERR(info)) + return PTR_ERR(info); + + if (!info->opps) + return -EIO; + + for (opp = info->opps, idx = 0; idx < info->count; idx++, opp++) { + ret = dev_pm_opp_add(dev, opp->freq, opp->m_volt * 1000); + if (ret) { + dev_warn(dev, "failed to add opp %uHz %umV\n", + opp->freq, opp->m_volt); + while (idx-- > 0) + dev_pm_opp_remove(dev, (--opp)->freq); + return ret; + } + } + return 0; +} + static int scpi_sensor_get_capability(u16 *sensors) { struct sensor_capabilities cap_buf; @@ -765,6 +825,9 @@ static struct scpi_ops scpi_ops = { .dvfs_get_idx = scpi_dvfs_get_idx, .dvfs_set_idx = scpi_dvfs_set_idx, .dvfs_get_info = scpi_dvfs_get_info, + .device_domain_id = scpi_dev_domain_id, + .get_transition_latency = scpi_dvfs_get_transition_latency, + .add_opps_to_device = scpi_dvfs_add_opps_to_device, .sensor_get_capability = scpi_sensor_get_capability, .sensor_get_info = scpi_sensor_get_info, .sensor_get_value = scpi_sensor_get_value, diff --git a/drivers/firmware/tegra/bpmp.c b/drivers/firmware/tegra/bpmp.c index 84e4c9a58a0c..b25179517cc5 100644 --- a/drivers/firmware/tegra/bpmp.c +++ b/drivers/firmware/tegra/bpmp.c @@ -211,14 +211,17 @@ static ssize_t tegra_bpmp_channel_read(struct tegra_bpmp_channel *channel, int index; index = tegra_bpmp_channel_get_thread_index(channel); - if (index < 0) - return index; + if (index < 0) { + err = index; + goto unlock; + } spin_lock_irqsave(&bpmp->lock, flags); err = __tegra_bpmp_channel_read(channel, data, size); clear_bit(index, bpmp->threaded.allocated); spin_unlock_irqrestore(&bpmp->lock, flags); +unlock: up(&bpmp->threaded.lock); return err; @@ -256,18 +259,18 @@ tegra_bpmp_write_threaded(struct tegra_bpmp *bpmp, unsigned int mrq, index = find_first_zero_bit(bpmp->threaded.allocated, count); if (index == count) { - channel = ERR_PTR(-EBUSY); + err = -EBUSY; goto unlock; } channel = tegra_bpmp_channel_get_thread(bpmp, index); if (!channel) { - channel = ERR_PTR(-EINVAL); + err = -EINVAL; goto unlock; } if (!tegra_bpmp_master_free(channel)) { - channel = ERR_PTR(-EBUSY); + err = -EBUSY; goto unlock; } @@ -275,16 +278,21 @@ tegra_bpmp_write_threaded(struct tegra_bpmp *bpmp, unsigned int mrq, err = __tegra_bpmp_channel_write(channel, mrq, MSG_ACK | MSG_RING, data, size); - if (err < 0) { - clear_bit(index, bpmp->threaded.allocated); - goto unlock; - } + if (err < 0) + goto clear_allocated; set_bit(index, bpmp->threaded.busy); -unlock: spin_unlock_irqrestore(&bpmp->lock, flags); return channel; + +clear_allocated: + clear_bit(index, bpmp->threaded.allocated); +unlock: + spin_unlock_irqrestore(&bpmp->lock, flags); + up(&bpmp->threaded.lock); + + return ERR_PTR(err); } static ssize_t tegra_bpmp_channel_write(struct tegra_bpmp_channel *channel, @@ -810,6 +818,10 @@ static int tegra_bpmp_probe(struct platform_device *pdev) if (err < 0) goto free_mrq; + err = tegra_bpmp_init_powergates(bpmp); + if (err < 0) + goto free_mrq; + platform_set_drvdata(pdev, bpmp); return 0; |