1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (C) 2015 Broadcom 4 */ 5 6 /** 7 * DOC: VC4 HVS module. 8 * 9 * The Hardware Video Scaler (HVS) is the piece of hardware that does 10 * translation, scaling, colorspace conversion, and compositing of 11 * pixels stored in framebuffers into a FIFO of pixels going out to 12 * the Pixel Valve (CRTC). It operates at the system clock rate (the 13 * system audio clock gate, specifically), which is much higher than 14 * the pixel clock rate. 15 * 16 * There is a single global HVS, with multiple output FIFOs that can 17 * be consumed by the PVs. This file just manages the resources for 18 * the HVS, while the vc4_crtc.c code actually drives HVS setup for 19 * each CRTC. 20 */ 21 22 #include <drm/drm_atomic_helper.h> 23 #include <linux/component.h> 24 #include "vc4_drv.h" 25 #include "vc4_regs.h" 26 27 static const struct debugfs_reg32 hvs_regs[] = { 28 VC4_REG32(SCALER_DISPCTRL), 29 VC4_REG32(SCALER_DISPSTAT), 30 VC4_REG32(SCALER_DISPID), 31 VC4_REG32(SCALER_DISPECTRL), 32 VC4_REG32(SCALER_DISPPROF), 33 VC4_REG32(SCALER_DISPDITHER), 34 VC4_REG32(SCALER_DISPEOLN), 35 VC4_REG32(SCALER_DISPLIST0), 36 VC4_REG32(SCALER_DISPLIST1), 37 VC4_REG32(SCALER_DISPLIST2), 38 VC4_REG32(SCALER_DISPLSTAT), 39 VC4_REG32(SCALER_DISPLACT0), 40 VC4_REG32(SCALER_DISPLACT1), 41 VC4_REG32(SCALER_DISPLACT2), 42 VC4_REG32(SCALER_DISPCTRL0), 43 VC4_REG32(SCALER_DISPBKGND0), 44 VC4_REG32(SCALER_DISPSTAT0), 45 VC4_REG32(SCALER_DISPBASE0), 46 VC4_REG32(SCALER_DISPCTRL1), 47 VC4_REG32(SCALER_DISPBKGND1), 48 VC4_REG32(SCALER_DISPSTAT1), 49 VC4_REG32(SCALER_DISPBASE1), 50 VC4_REG32(SCALER_DISPCTRL2), 51 VC4_REG32(SCALER_DISPBKGND2), 52 VC4_REG32(SCALER_DISPSTAT2), 53 VC4_REG32(SCALER_DISPBASE2), 54 VC4_REG32(SCALER_DISPALPHA2), 55 VC4_REG32(SCALER_OLEDOFFS), 56 VC4_REG32(SCALER_OLEDCOEF0), 57 VC4_REG32(SCALER_OLEDCOEF1), 58 VC4_REG32(SCALER_OLEDCOEF2), 59 }; 60 61 void vc4_hvs_dump_state(struct drm_device *dev) 62 { 63 struct vc4_dev *vc4 = to_vc4_dev(dev); 64 struct drm_printer p = drm_info_printer(&vc4->hvs->pdev->dev); 65 int i; 66 67 drm_print_regset32(&p, &vc4->hvs->regset); 68 69 DRM_INFO("HVS ctx:\n"); 70 for (i = 0; i < 64; i += 4) { 71 DRM_INFO("0x%08x (%s): 0x%08x 0x%08x 0x%08x 0x%08x\n", 72 i * 4, i < HVS_BOOTLOADER_DLIST_END ? "B" : "D", 73 readl((u32 __iomem *)vc4->hvs->dlist + i + 0), 74 readl((u32 __iomem *)vc4->hvs->dlist + i + 1), 75 readl((u32 __iomem *)vc4->hvs->dlist + i + 2), 76 readl((u32 __iomem *)vc4->hvs->dlist + i + 3)); 77 } 78 } 79 80 static int vc4_hvs_debugfs_underrun(struct seq_file *m, void *data) 81 { 82 struct drm_info_node *node = m->private; 83 struct drm_device *dev = node->minor->dev; 84 struct vc4_dev *vc4 = to_vc4_dev(dev); 85 struct drm_printer p = drm_seq_file_printer(m); 86 87 drm_printf(&p, "%d\n", atomic_read(&vc4->underrun)); 88 89 return 0; 90 } 91 92 /* The filter kernel is composed of dwords each containing 3 9-bit 93 * signed integers packed next to each other. 94 */ 95 #define VC4_INT_TO_COEFF(coeff) (coeff & 0x1ff) 96 #define VC4_PPF_FILTER_WORD(c0, c1, c2) \ 97 ((((c0) & 0x1ff) << 0) | \ 98 (((c1) & 0x1ff) << 9) | \ 99 (((c2) & 0x1ff) << 18)) 100 101 /* The whole filter kernel is arranged as the coefficients 0-16 going 102 * up, then a pad, then 17-31 going down and reversed within the 103 * dwords. This means that a linear phase kernel (where it's 104 * symmetrical at the boundary between 15 and 16) has the last 5 105 * dwords matching the first 5, but reversed. 106 */ 107 #define VC4_LINEAR_PHASE_KERNEL(c0, c1, c2, c3, c4, c5, c6, c7, c8, \ 108 c9, c10, c11, c12, c13, c14, c15) \ 109 {VC4_PPF_FILTER_WORD(c0, c1, c2), \ 110 VC4_PPF_FILTER_WORD(c3, c4, c5), \ 111 VC4_PPF_FILTER_WORD(c6, c7, c8), \ 112 VC4_PPF_FILTER_WORD(c9, c10, c11), \ 113 VC4_PPF_FILTER_WORD(c12, c13, c14), \ 114 VC4_PPF_FILTER_WORD(c15, c15, 0)} 115 116 #define VC4_LINEAR_PHASE_KERNEL_DWORDS 6 117 #define VC4_KERNEL_DWORDS (VC4_LINEAR_PHASE_KERNEL_DWORDS * 2 - 1) 118 119 /* Recommended B=1/3, C=1/3 filter choice from Mitchell/Netravali. 120 * http://www.cs.utexas.edu/~fussell/courses/cs384g/lectures/mitchell/Mitchell.pdf 121 */ 122 static const u32 mitchell_netravali_1_3_1_3_kernel[] = 123 VC4_LINEAR_PHASE_KERNEL(0, -2, -6, -8, -10, -8, -3, 2, 18, 124 50, 82, 119, 155, 187, 213, 227); 125 126 static int vc4_hvs_upload_linear_kernel(struct vc4_hvs *hvs, 127 struct drm_mm_node *space, 128 const u32 *kernel) 129 { 130 int ret, i; 131 u32 __iomem *dst_kernel; 132 133 ret = drm_mm_insert_node(&hvs->dlist_mm, space, VC4_KERNEL_DWORDS); 134 if (ret) { 135 DRM_ERROR("Failed to allocate space for filter kernel: %d\n", 136 ret); 137 return ret; 138 } 139 140 dst_kernel = hvs->dlist + space->start; 141 142 for (i = 0; i < VC4_KERNEL_DWORDS; i++) { 143 if (i < VC4_LINEAR_PHASE_KERNEL_DWORDS) 144 writel(kernel[i], &dst_kernel[i]); 145 else { 146 writel(kernel[VC4_KERNEL_DWORDS - i - 1], 147 &dst_kernel[i]); 148 } 149 } 150 151 return 0; 152 } 153 154 void vc4_hvs_mask_underrun(struct drm_device *dev, int channel) 155 { 156 struct vc4_dev *vc4 = to_vc4_dev(dev); 157 u32 dispctrl = HVS_READ(SCALER_DISPCTRL); 158 159 dispctrl &= ~SCALER_DISPCTRL_DSPEISLUR(channel); 160 161 HVS_WRITE(SCALER_DISPCTRL, dispctrl); 162 } 163 164 void vc4_hvs_unmask_underrun(struct drm_device *dev, int channel) 165 { 166 struct vc4_dev *vc4 = to_vc4_dev(dev); 167 u32 dispctrl = HVS_READ(SCALER_DISPCTRL); 168 169 dispctrl |= SCALER_DISPCTRL_DSPEISLUR(channel); 170 171 HVS_WRITE(SCALER_DISPSTAT, 172 SCALER_DISPSTAT_EUFLOW(channel)); 173 HVS_WRITE(SCALER_DISPCTRL, dispctrl); 174 } 175 176 static void vc4_hvs_report_underrun(struct drm_device *dev) 177 { 178 struct vc4_dev *vc4 = to_vc4_dev(dev); 179 180 atomic_inc(&vc4->underrun); 181 DRM_DEV_ERROR(dev->dev, "HVS underrun\n"); 182 } 183 184 static irqreturn_t vc4_hvs_irq_handler(int irq, void *data) 185 { 186 struct drm_device *dev = data; 187 struct vc4_dev *vc4 = to_vc4_dev(dev); 188 irqreturn_t irqret = IRQ_NONE; 189 int channel; 190 u32 control; 191 u32 status; 192 193 status = HVS_READ(SCALER_DISPSTAT); 194 control = HVS_READ(SCALER_DISPCTRL); 195 196 for (channel = 0; channel < SCALER_CHANNELS_COUNT; channel++) { 197 /* Interrupt masking is not always honored, so check it here. */ 198 if (status & SCALER_DISPSTAT_EUFLOW(channel) && 199 control & SCALER_DISPCTRL_DSPEISLUR(channel)) { 200 vc4_hvs_mask_underrun(dev, channel); 201 vc4_hvs_report_underrun(dev); 202 203 irqret = IRQ_HANDLED; 204 } 205 } 206 207 /* Clear every per-channel interrupt flag. */ 208 HVS_WRITE(SCALER_DISPSTAT, SCALER_DISPSTAT_IRQMASK(0) | 209 SCALER_DISPSTAT_IRQMASK(1) | 210 SCALER_DISPSTAT_IRQMASK(2)); 211 212 return irqret; 213 } 214 215 static int vc4_hvs_bind(struct device *dev, struct device *master, void *data) 216 { 217 struct platform_device *pdev = to_platform_device(dev); 218 struct drm_device *drm = dev_get_drvdata(master); 219 struct vc4_dev *vc4 = drm->dev_private; 220 struct vc4_hvs *hvs = NULL; 221 int ret; 222 u32 dispctrl; 223 224 hvs = devm_kzalloc(&pdev->dev, sizeof(*hvs), GFP_KERNEL); 225 if (!hvs) 226 return -ENOMEM; 227 228 hvs->pdev = pdev; 229 230 hvs->regs = vc4_ioremap_regs(pdev, 0); 231 if (IS_ERR(hvs->regs)) 232 return PTR_ERR(hvs->regs); 233 234 hvs->regset.base = hvs->regs; 235 hvs->regset.regs = hvs_regs; 236 hvs->regset.nregs = ARRAY_SIZE(hvs_regs); 237 238 hvs->dlist = hvs->regs + SCALER_DLIST_START; 239 240 spin_lock_init(&hvs->mm_lock); 241 242 /* Set up the HVS display list memory manager. We never 243 * overwrite the setup from the bootloader (just 128b out of 244 * our 16K), since we don't want to scramble the screen when 245 * transitioning from the firmware's boot setup to runtime. 246 */ 247 drm_mm_init(&hvs->dlist_mm, 248 HVS_BOOTLOADER_DLIST_END, 249 (SCALER_DLIST_SIZE >> 2) - HVS_BOOTLOADER_DLIST_END); 250 251 /* Set up the HVS LBM memory manager. We could have some more 252 * complicated data structure that allowed reuse of LBM areas 253 * between planes when they don't overlap on the screen, but 254 * for now we just allocate globally. 255 */ 256 drm_mm_init(&hvs->lbm_mm, 0, 96 * 1024); 257 258 /* Upload filter kernels. We only have the one for now, so we 259 * keep it around for the lifetime of the driver. 260 */ 261 ret = vc4_hvs_upload_linear_kernel(hvs, 262 &hvs->mitchell_netravali_filter, 263 mitchell_netravali_1_3_1_3_kernel); 264 if (ret) 265 return ret; 266 267 vc4->hvs = hvs; 268 269 dispctrl = HVS_READ(SCALER_DISPCTRL); 270 271 dispctrl |= SCALER_DISPCTRL_ENABLE; 272 dispctrl |= SCALER_DISPCTRL_DISPEIRQ(0) | 273 SCALER_DISPCTRL_DISPEIRQ(1) | 274 SCALER_DISPCTRL_DISPEIRQ(2); 275 276 /* Set DSP3 (PV1) to use HVS channel 2, which would otherwise 277 * be unused. 278 */ 279 dispctrl &= ~SCALER_DISPCTRL_DSP3_MUX_MASK; 280 dispctrl &= ~(SCALER_DISPCTRL_DMAEIRQ | 281 SCALER_DISPCTRL_SLVWREIRQ | 282 SCALER_DISPCTRL_SLVRDEIRQ | 283 SCALER_DISPCTRL_DSPEIEOF(0) | 284 SCALER_DISPCTRL_DSPEIEOF(1) | 285 SCALER_DISPCTRL_DSPEIEOF(2) | 286 SCALER_DISPCTRL_DSPEIEOLN(0) | 287 SCALER_DISPCTRL_DSPEIEOLN(1) | 288 SCALER_DISPCTRL_DSPEIEOLN(2) | 289 SCALER_DISPCTRL_DSPEISLUR(0) | 290 SCALER_DISPCTRL_DSPEISLUR(1) | 291 SCALER_DISPCTRL_DSPEISLUR(2) | 292 SCALER_DISPCTRL_SCLEIRQ); 293 dispctrl |= VC4_SET_FIELD(2, SCALER_DISPCTRL_DSP3_MUX); 294 295 HVS_WRITE(SCALER_DISPCTRL, dispctrl); 296 297 ret = devm_request_irq(dev, platform_get_irq(pdev, 0), 298 vc4_hvs_irq_handler, 0, "vc4 hvs", drm); 299 if (ret) 300 return ret; 301 302 vc4_debugfs_add_regset32(drm, "hvs_regs", &hvs->regset); 303 vc4_debugfs_add_file(drm, "hvs_underrun", vc4_hvs_debugfs_underrun, 304 NULL); 305 306 return 0; 307 } 308 309 static void vc4_hvs_unbind(struct device *dev, struct device *master, 310 void *data) 311 { 312 struct drm_device *drm = dev_get_drvdata(master); 313 struct vc4_dev *vc4 = drm->dev_private; 314 315 if (vc4->hvs->mitchell_netravali_filter.allocated) 316 drm_mm_remove_node(&vc4->hvs->mitchell_netravali_filter); 317 318 drm_mm_takedown(&vc4->hvs->dlist_mm); 319 drm_mm_takedown(&vc4->hvs->lbm_mm); 320 321 vc4->hvs = NULL; 322 } 323 324 static const struct component_ops vc4_hvs_ops = { 325 .bind = vc4_hvs_bind, 326 .unbind = vc4_hvs_unbind, 327 }; 328 329 static int vc4_hvs_dev_probe(struct platform_device *pdev) 330 { 331 return component_add(&pdev->dev, &vc4_hvs_ops); 332 } 333 334 static int vc4_hvs_dev_remove(struct platform_device *pdev) 335 { 336 component_del(&pdev->dev, &vc4_hvs_ops); 337 return 0; 338 } 339 340 static const struct of_device_id vc4_hvs_dt_match[] = { 341 { .compatible = "brcm,bcm2835-hvs" }, 342 {} 343 }; 344 345 struct platform_driver vc4_hvs_driver = { 346 .probe = vc4_hvs_dev_probe, 347 .remove = vc4_hvs_dev_remove, 348 .driver = { 349 .name = "vc4_hvs", 350 .of_match_table = vc4_hvs_dt_match, 351 }, 352 }; 353