| .. | .. |
|---|
| 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); |
|---|