Suman Anna | 3846a3b9 | 2019-08-07 11:26:45 +0300 | [diff] [blame] | 1 | // SPDX-License-Identifier: GPL-2.0-only |
| 2 | /* |
| 3 | * OMAP IOMMU quirks for various TI SoCs |
| 4 | * |
Alexander A. Klimov | 83bf6db | 2020-07-19 12:30:33 +0200 | [diff] [blame] | 5 | * Copyright (C) 2015-2019 Texas Instruments Incorporated - https://www.ti.com/ |
Suman Anna | 3846a3b9 | 2019-08-07 11:26:45 +0300 | [diff] [blame] | 6 | * Suman Anna <s-anna@ti.com> |
| 7 | */ |
| 8 | |
| 9 | #include <linux/platform_device.h> |
| 10 | #include <linux/err.h> |
Tero Kristo | 4ea3711 | 2019-12-12 15:05:40 +0200 | [diff] [blame] | 11 | #include <linux/clk.h> |
| 12 | #include <linux/list.h> |
Suman Anna | 3846a3b9 | 2019-08-07 11:26:45 +0300 | [diff] [blame] | 13 | |
Suman Anna | 2f14101 | 2019-12-12 15:05:39 +0200 | [diff] [blame] | 14 | #include "clockdomain.h" |
Suman Anna | 3846a3b9 | 2019-08-07 11:26:45 +0300 | [diff] [blame] | 15 | #include "powerdomain.h" |
| 16 | |
Tero Kristo | 4ea3711 | 2019-12-12 15:05:40 +0200 | [diff] [blame] | 17 | struct pwrdm_link { |
| 18 | struct device *dev; |
| 19 | struct powerdomain *pwrdm; |
| 20 | struct list_head node; |
| 21 | }; |
| 22 | |
| 23 | static DEFINE_SPINLOCK(iommu_lock); |
| 24 | static struct clockdomain *emu_clkdm; |
| 25 | static atomic_t emu_count; |
| 26 | |
Suman Anna | 2f14101 | 2019-12-12 15:05:39 +0200 | [diff] [blame] | 27 | static void omap_iommu_dra7_emu_swsup_config(struct platform_device *pdev, |
| 28 | bool enable) |
| 29 | { |
Suman Anna | 2f14101 | 2019-12-12 15:05:39 +0200 | [diff] [blame] | 30 | struct device_node *np = pdev->dev.of_node; |
Tero Kristo | 4ea3711 | 2019-12-12 15:05:40 +0200 | [diff] [blame] | 31 | unsigned long flags; |
Suman Anna | 2f14101 | 2019-12-12 15:05:39 +0200 | [diff] [blame] | 32 | |
| 33 | if (!of_device_is_compatible(np, "ti,dra7-dsp-iommu")) |
| 34 | return; |
| 35 | |
| 36 | if (!emu_clkdm) { |
| 37 | emu_clkdm = clkdm_lookup("emu_clkdm"); |
| 38 | if (WARN_ON_ONCE(!emu_clkdm)) |
| 39 | return; |
| 40 | } |
| 41 | |
Tero Kristo | 4ea3711 | 2019-12-12 15:05:40 +0200 | [diff] [blame] | 42 | spin_lock_irqsave(&iommu_lock, flags); |
Suman Anna | 2f14101 | 2019-12-12 15:05:39 +0200 | [diff] [blame] | 43 | |
Tero Kristo | 4ea3711 | 2019-12-12 15:05:40 +0200 | [diff] [blame] | 44 | if (enable && (atomic_inc_return(&emu_count) == 1)) |
Suman Anna | 2f14101 | 2019-12-12 15:05:39 +0200 | [diff] [blame] | 45 | clkdm_deny_idle(emu_clkdm); |
Tero Kristo | 4ea3711 | 2019-12-12 15:05:40 +0200 | [diff] [blame] | 46 | else if (!enable && (atomic_dec_return(&emu_count) == 0)) |
Suman Anna | 2f14101 | 2019-12-12 15:05:39 +0200 | [diff] [blame] | 47 | clkdm_allow_idle(emu_clkdm); |
| 48 | |
Tero Kristo | 4ea3711 | 2019-12-12 15:05:40 +0200 | [diff] [blame] | 49 | spin_unlock_irqrestore(&iommu_lock, flags); |
| 50 | } |
| 51 | |
| 52 | static struct powerdomain *_get_pwrdm(struct device *dev) |
| 53 | { |
| 54 | struct clk *clk; |
| 55 | struct clk_hw_omap *hwclk; |
| 56 | struct clockdomain *clkdm; |
| 57 | struct powerdomain *pwrdm = NULL; |
| 58 | struct pwrdm_link *entry; |
| 59 | unsigned long flags; |
| 60 | static LIST_HEAD(cache); |
| 61 | |
| 62 | spin_lock_irqsave(&iommu_lock, flags); |
| 63 | |
| 64 | list_for_each_entry(entry, &cache, node) { |
| 65 | if (entry->dev == dev) { |
| 66 | pwrdm = entry->pwrdm; |
| 67 | break; |
| 68 | } |
| 69 | } |
| 70 | |
| 71 | spin_unlock_irqrestore(&iommu_lock, flags); |
| 72 | |
| 73 | if (pwrdm) |
| 74 | return pwrdm; |
| 75 | |
| 76 | clk = of_clk_get(dev->of_node->parent, 0); |
Jing Xiangfeng | a58cfdb | 2020-07-24 11:54:30 +0800 | [diff] [blame] | 77 | if (IS_ERR(clk)) { |
Tero Kristo | 4ea3711 | 2019-12-12 15:05:40 +0200 | [diff] [blame] | 78 | dev_err(dev, "no fck found\n"); |
| 79 | return NULL; |
| 80 | } |
| 81 | |
| 82 | hwclk = to_clk_hw_omap(__clk_get_hw(clk)); |
| 83 | clk_put(clk); |
| 84 | if (!hwclk || !hwclk->clkdm_name) { |
| 85 | dev_err(dev, "no hwclk data\n"); |
| 86 | return NULL; |
| 87 | } |
| 88 | |
| 89 | clkdm = clkdm_lookup(hwclk->clkdm_name); |
| 90 | if (!clkdm) { |
| 91 | dev_err(dev, "clkdm not found: %s\n", hwclk->clkdm_name); |
| 92 | return NULL; |
| 93 | } |
| 94 | |
| 95 | pwrdm = clkdm_get_pwrdm(clkdm); |
| 96 | if (!pwrdm) { |
| 97 | dev_err(dev, "pwrdm not found: %s\n", clkdm->name); |
| 98 | return NULL; |
| 99 | } |
| 100 | |
| 101 | entry = kmalloc(sizeof(*entry), GFP_KERNEL); |
| 102 | if (entry) { |
| 103 | entry->dev = dev; |
| 104 | entry->pwrdm = pwrdm; |
| 105 | spin_lock_irqsave(&iommu_lock, flags); |
| 106 | list_add(&entry->node, &cache); |
| 107 | spin_unlock_irqrestore(&iommu_lock, flags); |
| 108 | } |
| 109 | |
| 110 | return pwrdm; |
Suman Anna | 2f14101 | 2019-12-12 15:05:39 +0200 | [diff] [blame] | 111 | } |
| 112 | |
Suman Anna | 3846a3b9 | 2019-08-07 11:26:45 +0300 | [diff] [blame] | 113 | int omap_iommu_set_pwrdm_constraint(struct platform_device *pdev, bool request, |
| 114 | u8 *pwrst) |
| 115 | { |
| 116 | struct powerdomain *pwrdm; |
Suman Anna | 3846a3b9 | 2019-08-07 11:26:45 +0300 | [diff] [blame] | 117 | u8 next_pwrst; |
Suman Anna | 2f14101 | 2019-12-12 15:05:39 +0200 | [diff] [blame] | 118 | int ret = 0; |
Suman Anna | 3846a3b9 | 2019-08-07 11:26:45 +0300 | [diff] [blame] | 119 | |
Tero Kristo | 4ea3711 | 2019-12-12 15:05:40 +0200 | [diff] [blame] | 120 | pwrdm = _get_pwrdm(&pdev->dev); |
Suman Anna | 3846a3b9 | 2019-08-07 11:26:45 +0300 | [diff] [blame] | 121 | if (!pwrdm) |
Tero Kristo | 4ea3711 | 2019-12-12 15:05:40 +0200 | [diff] [blame] | 122 | return -ENODEV; |
Suman Anna | 3846a3b9 | 2019-08-07 11:26:45 +0300 | [diff] [blame] | 123 | |
Suman Anna | 2f14101 | 2019-12-12 15:05:39 +0200 | [diff] [blame] | 124 | if (request) { |
Suman Anna | 3846a3b9 | 2019-08-07 11:26:45 +0300 | [diff] [blame] | 125 | *pwrst = pwrdm_read_next_pwrst(pwrdm); |
Suman Anna | 2f14101 | 2019-12-12 15:05:39 +0200 | [diff] [blame] | 126 | omap_iommu_dra7_emu_swsup_config(pdev, true); |
| 127 | } |
Suman Anna | 3846a3b9 | 2019-08-07 11:26:45 +0300 | [diff] [blame] | 128 | |
| 129 | if (*pwrst > PWRDM_POWER_RET) |
Suman Anna | 2f14101 | 2019-12-12 15:05:39 +0200 | [diff] [blame] | 130 | goto out; |
Suman Anna | 3846a3b9 | 2019-08-07 11:26:45 +0300 | [diff] [blame] | 131 | |
| 132 | next_pwrst = request ? PWRDM_POWER_ON : *pwrst; |
| 133 | |
Suman Anna | 2f14101 | 2019-12-12 15:05:39 +0200 | [diff] [blame] | 134 | ret = pwrdm_set_next_pwrst(pwrdm, next_pwrst); |
| 135 | |
| 136 | out: |
| 137 | if (!request) |
| 138 | omap_iommu_dra7_emu_swsup_config(pdev, false); |
| 139 | |
| 140 | return ret; |
Suman Anna | 3846a3b9 | 2019-08-07 11:26:45 +0300 | [diff] [blame] | 141 | } |