.. | .. |
---|
3 | 3 | * Copyright (c) 2018, The Linux Foundation |
---|
4 | 4 | */ |
---|
5 | 5 | |
---|
| 6 | +#include <linux/irq.h> |
---|
| 7 | +#include <linux/irqchip.h> |
---|
| 8 | +#include <linux/irqdesc.h> |
---|
| 9 | +#include <linux/irqchip/chained_irq.h> |
---|
6 | 10 | #include "dpu_kms.h" |
---|
7 | 11 | |
---|
8 | 12 | #define to_dpu_mdss(x) container_of(x, struct dpu_mdss, base) |
---|
9 | 13 | |
---|
| 14 | +#define HW_REV 0x0 |
---|
10 | 15 | #define HW_INTR_STATUS 0x0010 |
---|
| 16 | + |
---|
| 17 | +#define UBWC_STATIC 0x144 |
---|
| 18 | +#define UBWC_CTRL_2 0x150 |
---|
| 19 | +#define UBWC_PREDICTION_MODE 0x154 |
---|
| 20 | + |
---|
| 21 | +/* Max BW defined in KBps */ |
---|
| 22 | +#define MAX_BW 6800000 |
---|
| 23 | + |
---|
| 24 | +struct dpu_irq_controller { |
---|
| 25 | + unsigned long enabled_mask; |
---|
| 26 | + struct irq_domain *domain; |
---|
| 27 | +}; |
---|
11 | 28 | |
---|
12 | 29 | struct dpu_mdss { |
---|
13 | 30 | struct msm_mdss base; |
---|
14 | 31 | void __iomem *mmio; |
---|
15 | | - unsigned long mmio_len; |
---|
16 | | - u32 hwversion; |
---|
17 | 32 | struct dss_module_power mp; |
---|
18 | 33 | struct dpu_irq_controller irq_controller; |
---|
19 | 34 | }; |
---|
20 | 35 | |
---|
21 | | -static irqreturn_t dpu_mdss_irq(int irq, void *arg) |
---|
| 36 | +static void dpu_mdss_irq(struct irq_desc *desc) |
---|
22 | 37 | { |
---|
23 | | - struct dpu_mdss *dpu_mdss = arg; |
---|
| 38 | + struct dpu_mdss *dpu_mdss = irq_desc_get_handler_data(desc); |
---|
| 39 | + struct irq_chip *chip = irq_desc_get_chip(desc); |
---|
24 | 40 | u32 interrupts; |
---|
| 41 | + |
---|
| 42 | + chained_irq_enter(chip, desc); |
---|
25 | 43 | |
---|
26 | 44 | interrupts = readl_relaxed(dpu_mdss->mmio + HW_INTR_STATUS); |
---|
27 | 45 | |
---|
.. | .. |
---|
34 | 52 | hwirq); |
---|
35 | 53 | if (mapping == 0) { |
---|
36 | 54 | DRM_ERROR("couldn't find irq mapping for %lu\n", hwirq); |
---|
37 | | - return IRQ_NONE; |
---|
| 55 | + break; |
---|
38 | 56 | } |
---|
39 | 57 | |
---|
40 | 58 | rc = generic_handle_irq(mapping); |
---|
41 | 59 | if (rc < 0) { |
---|
42 | 60 | DRM_ERROR("handle irq fail: irq=%lu mapping=%u rc=%d\n", |
---|
43 | 61 | hwirq, mapping, rc); |
---|
44 | | - return IRQ_NONE; |
---|
| 62 | + break; |
---|
45 | 63 | } |
---|
46 | 64 | |
---|
47 | 65 | interrupts &= ~(1 << hwirq); |
---|
48 | 66 | } |
---|
49 | 67 | |
---|
50 | | - return IRQ_HANDLED; |
---|
| 68 | + chained_irq_exit(chip, desc); |
---|
51 | 69 | } |
---|
52 | 70 | |
---|
53 | 71 | static void dpu_mdss_irq_mask(struct irq_data *irqd) |
---|
.. | .. |
---|
78 | 96 | .irq_unmask = dpu_mdss_irq_unmask, |
---|
79 | 97 | }; |
---|
80 | 98 | |
---|
| 99 | +static struct lock_class_key dpu_mdss_lock_key, dpu_mdss_request_key; |
---|
| 100 | + |
---|
81 | 101 | static int dpu_mdss_irqdomain_map(struct irq_domain *domain, |
---|
82 | 102 | unsigned int irq, irq_hw_number_t hwirq) |
---|
83 | 103 | { |
---|
84 | 104 | struct dpu_mdss *dpu_mdss = domain->host_data; |
---|
85 | | - int ret; |
---|
86 | 105 | |
---|
| 106 | + irq_set_lockdep_class(irq, &dpu_mdss_lock_key, &dpu_mdss_request_key); |
---|
87 | 107 | irq_set_chip_and_handler(irq, &dpu_mdss_irq_chip, handle_level_irq); |
---|
88 | | - ret = irq_set_chip_data(irq, dpu_mdss); |
---|
89 | | - |
---|
90 | | - return ret; |
---|
| 108 | + return irq_set_chip_data(irq, dpu_mdss); |
---|
91 | 109 | } |
---|
92 | 110 | |
---|
93 | 111 | static const struct irq_domain_ops dpu_mdss_irqdomain_ops = { |
---|
.. | .. |
---|
115 | 133 | return 0; |
---|
116 | 134 | } |
---|
117 | 135 | |
---|
118 | | -static int _dpu_mdss_irq_domain_fini(struct dpu_mdss *dpu_mdss) |
---|
| 136 | +static void _dpu_mdss_irq_domain_fini(struct dpu_mdss *dpu_mdss) |
---|
119 | 137 | { |
---|
120 | 138 | if (dpu_mdss->irq_controller.domain) { |
---|
121 | 139 | irq_domain_remove(dpu_mdss->irq_controller.domain); |
---|
122 | 140 | dpu_mdss->irq_controller.domain = NULL; |
---|
123 | 141 | } |
---|
124 | | - return 0; |
---|
125 | 142 | } |
---|
126 | 143 | static int dpu_mdss_enable(struct msm_mdss *mdss) |
---|
127 | 144 | { |
---|
.. | .. |
---|
130 | 147 | int ret; |
---|
131 | 148 | |
---|
132 | 149 | ret = msm_dss_enable_clk(mp->clk_config, mp->num_clk, true); |
---|
133 | | - if (ret) |
---|
| 150 | + if (ret) { |
---|
134 | 151 | DPU_ERROR("clock enable failed, ret:%d\n", ret); |
---|
| 152 | + return ret; |
---|
| 153 | + } |
---|
| 154 | + |
---|
| 155 | + /* |
---|
| 156 | + * ubwc config is part of the "mdss" region which is not accessible |
---|
| 157 | + * from the rest of the driver. hardcode known configurations here |
---|
| 158 | + */ |
---|
| 159 | + switch (readl_relaxed(dpu_mdss->mmio + HW_REV)) { |
---|
| 160 | + case DPU_HW_VER_500: |
---|
| 161 | + case DPU_HW_VER_501: |
---|
| 162 | + writel_relaxed(0x420, dpu_mdss->mmio + UBWC_STATIC); |
---|
| 163 | + break; |
---|
| 164 | + case DPU_HW_VER_600: |
---|
| 165 | + /* TODO: 0x102e for LP_DDR4 */ |
---|
| 166 | + writel_relaxed(0x103e, dpu_mdss->mmio + UBWC_STATIC); |
---|
| 167 | + writel_relaxed(2, dpu_mdss->mmio + UBWC_CTRL_2); |
---|
| 168 | + writel_relaxed(1, dpu_mdss->mmio + UBWC_PREDICTION_MODE); |
---|
| 169 | + break; |
---|
| 170 | + case DPU_HW_VER_620: |
---|
| 171 | + writel_relaxed(0x1e, dpu_mdss->mmio + UBWC_STATIC); |
---|
| 172 | + break; |
---|
| 173 | + } |
---|
135 | 174 | |
---|
136 | 175 | return ret; |
---|
137 | 176 | } |
---|
.. | .. |
---|
155 | 194 | struct msm_drm_private *priv = dev->dev_private; |
---|
156 | 195 | struct dpu_mdss *dpu_mdss = to_dpu_mdss(priv->mdss); |
---|
157 | 196 | struct dss_module_power *mp = &dpu_mdss->mp; |
---|
| 197 | + int irq; |
---|
158 | 198 | |
---|
| 199 | + pm_runtime_suspend(dev->dev); |
---|
| 200 | + pm_runtime_disable(dev->dev); |
---|
159 | 201 | _dpu_mdss_irq_domain_fini(dpu_mdss); |
---|
160 | | - |
---|
| 202 | + irq = platform_get_irq(pdev, 0); |
---|
| 203 | + irq_set_chained_handler_and_data(irq, NULL, NULL); |
---|
161 | 204 | msm_dss_put_clk(mp->clk_config, mp->num_clk); |
---|
162 | 205 | devm_kfree(&pdev->dev, mp->clk_config); |
---|
163 | 206 | |
---|
164 | 207 | if (dpu_mdss->mmio) |
---|
165 | 208 | devm_iounmap(&pdev->dev, dpu_mdss->mmio); |
---|
166 | 209 | dpu_mdss->mmio = NULL; |
---|
167 | | - |
---|
168 | | - pm_runtime_disable(dev->dev); |
---|
169 | 210 | priv->mdss = NULL; |
---|
170 | 211 | } |
---|
171 | 212 | |
---|
.. | .. |
---|
179 | 220 | { |
---|
180 | 221 | struct platform_device *pdev = to_platform_device(dev->dev); |
---|
181 | 222 | struct msm_drm_private *priv = dev->dev_private; |
---|
182 | | - struct resource *res; |
---|
183 | 223 | struct dpu_mdss *dpu_mdss; |
---|
184 | 224 | struct dss_module_power *mp; |
---|
185 | | - int ret = 0; |
---|
| 225 | + int ret; |
---|
| 226 | + int irq; |
---|
186 | 227 | |
---|
187 | 228 | dpu_mdss = devm_kzalloc(dev->dev, sizeof(*dpu_mdss), GFP_KERNEL); |
---|
188 | 229 | if (!dpu_mdss) |
---|
.. | .. |
---|
193 | 234 | return PTR_ERR(dpu_mdss->mmio); |
---|
194 | 235 | |
---|
195 | 236 | DRM_DEBUG("mapped mdss address space @%pK\n", dpu_mdss->mmio); |
---|
196 | | - |
---|
197 | | - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mdss"); |
---|
198 | | - if (!res) { |
---|
199 | | - DRM_ERROR("failed to get memory resource for mdss\n"); |
---|
200 | | - return -ENOMEM; |
---|
201 | | - } |
---|
202 | | - dpu_mdss->mmio_len = resource_size(res); |
---|
203 | 237 | |
---|
204 | 238 | mp = &dpu_mdss->mp; |
---|
205 | 239 | ret = msm_dss_parse_clock(pdev, mp); |
---|
.. | .. |
---|
215 | 249 | if (ret) |
---|
216 | 250 | goto irq_domain_error; |
---|
217 | 251 | |
---|
218 | | - ret = devm_request_irq(dev->dev, platform_get_irq(pdev, 0), |
---|
219 | | - dpu_mdss_irq, 0, "dpu_mdss_isr", dpu_mdss); |
---|
220 | | - if (ret) { |
---|
221 | | - DPU_ERROR("failed to init irq: %d\n", ret); |
---|
| 252 | + irq = platform_get_irq(pdev, 0); |
---|
| 253 | + if (irq < 0) { |
---|
| 254 | + ret = irq; |
---|
222 | 255 | goto irq_error; |
---|
223 | 256 | } |
---|
224 | 257 | |
---|
225 | | - pm_runtime_enable(dev->dev); |
---|
226 | | - |
---|
227 | | - pm_runtime_get_sync(dev->dev); |
---|
228 | | - dpu_mdss->hwversion = readl_relaxed(dpu_mdss->mmio); |
---|
229 | | - pm_runtime_put_sync(dev->dev); |
---|
| 258 | + irq_set_chained_handler_and_data(irq, dpu_mdss_irq, |
---|
| 259 | + dpu_mdss); |
---|
230 | 260 | |
---|
231 | 261 | priv->mdss = &dpu_mdss->base; |
---|
232 | 262 | |
---|
233 | | - return ret; |
---|
| 263 | + pm_runtime_enable(dev->dev); |
---|
| 264 | + |
---|
| 265 | + return 0; |
---|
234 | 266 | |
---|
235 | 267 | irq_error: |
---|
236 | 268 | _dpu_mdss_irq_domain_fini(dpu_mdss); |
---|