0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <linux/platform_device.h>
0010 #include <linux/err.h>
0011 #include <linux/clk.h>
0012 #include <linux/list.h>
0013
0014 #include "clockdomain.h"
0015 #include "powerdomain.h"
0016 #include "common.h"
0017
0018 struct pwrdm_link {
0019 struct device *dev;
0020 struct powerdomain *pwrdm;
0021 struct list_head node;
0022 };
0023
0024 static DEFINE_SPINLOCK(iommu_lock);
0025 static struct clockdomain *emu_clkdm;
0026 static atomic_t emu_count;
0027
0028 static void omap_iommu_dra7_emu_swsup_config(struct platform_device *pdev,
0029 bool enable)
0030 {
0031 struct device_node *np = pdev->dev.of_node;
0032 unsigned long flags;
0033
0034 if (!of_device_is_compatible(np, "ti,dra7-dsp-iommu"))
0035 return;
0036
0037 if (!emu_clkdm) {
0038 emu_clkdm = clkdm_lookup("emu_clkdm");
0039 if (WARN_ON_ONCE(!emu_clkdm))
0040 return;
0041 }
0042
0043 spin_lock_irqsave(&iommu_lock, flags);
0044
0045 if (enable && (atomic_inc_return(&emu_count) == 1))
0046 clkdm_deny_idle(emu_clkdm);
0047 else if (!enable && (atomic_dec_return(&emu_count) == 0))
0048 clkdm_allow_idle(emu_clkdm);
0049
0050 spin_unlock_irqrestore(&iommu_lock, flags);
0051 }
0052
0053 static struct powerdomain *_get_pwrdm(struct device *dev)
0054 {
0055 struct clk *clk;
0056 struct clk_hw_omap *hwclk;
0057 struct clockdomain *clkdm;
0058 struct powerdomain *pwrdm = NULL;
0059 struct pwrdm_link *entry;
0060 unsigned long flags;
0061 static LIST_HEAD(cache);
0062
0063 spin_lock_irqsave(&iommu_lock, flags);
0064
0065 list_for_each_entry(entry, &cache, node) {
0066 if (entry->dev == dev) {
0067 pwrdm = entry->pwrdm;
0068 break;
0069 }
0070 }
0071
0072 spin_unlock_irqrestore(&iommu_lock, flags);
0073
0074 if (pwrdm)
0075 return pwrdm;
0076
0077 clk = of_clk_get(dev->of_node->parent, 0);
0078 if (IS_ERR(clk)) {
0079 dev_err(dev, "no fck found\n");
0080 return NULL;
0081 }
0082
0083 hwclk = to_clk_hw_omap(__clk_get_hw(clk));
0084 clk_put(clk);
0085 if (!hwclk || !hwclk->clkdm_name) {
0086 dev_err(dev, "no hwclk data\n");
0087 return NULL;
0088 }
0089
0090 clkdm = clkdm_lookup(hwclk->clkdm_name);
0091 if (!clkdm) {
0092 dev_err(dev, "clkdm not found: %s\n", hwclk->clkdm_name);
0093 return NULL;
0094 }
0095
0096 pwrdm = clkdm_get_pwrdm(clkdm);
0097 if (!pwrdm) {
0098 dev_err(dev, "pwrdm not found: %s\n", clkdm->name);
0099 return NULL;
0100 }
0101
0102 entry = kmalloc(sizeof(*entry), GFP_KERNEL);
0103 if (entry) {
0104 entry->dev = dev;
0105 entry->pwrdm = pwrdm;
0106 spin_lock_irqsave(&iommu_lock, flags);
0107 list_add(&entry->node, &cache);
0108 spin_unlock_irqrestore(&iommu_lock, flags);
0109 }
0110
0111 return pwrdm;
0112 }
0113
0114 int omap_iommu_set_pwrdm_constraint(struct platform_device *pdev, bool request,
0115 u8 *pwrst)
0116 {
0117 struct powerdomain *pwrdm;
0118 u8 next_pwrst;
0119 int ret = 0;
0120
0121 pwrdm = _get_pwrdm(&pdev->dev);
0122 if (!pwrdm)
0123 return -ENODEV;
0124
0125 if (request) {
0126 *pwrst = pwrdm_read_next_pwrst(pwrdm);
0127 omap_iommu_dra7_emu_swsup_config(pdev, true);
0128 }
0129
0130 if (*pwrst > PWRDM_POWER_RET)
0131 goto out;
0132
0133 next_pwrst = request ? PWRDM_POWER_ON : *pwrst;
0134
0135 ret = pwrdm_set_next_pwrst(pwrdm, next_pwrst);
0136
0137 out:
0138 if (!request)
0139 omap_iommu_dra7_emu_swsup_config(pdev, false);
0140
0141 return ret;
0142 }