1 /* 2 * Copyright (C) 2015 Broadcom 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License version 2 as 6 * published by the Free Software Foundation. 7 */ 8 9 /** 10 * DOC: VC4 HVS module. 11 * 12 * The HVS is the piece of hardware that does translation, scaling, 13 * colorspace conversion, and compositing of pixels stored in 14 * framebuffers into a FIFO of pixels going out to the Pixel Valve 15 * (CRTC). It operates at the system clock rate (the system audio 16 * clock gate, specifically), which is much higher than the pixel 17 * clock rate. 18 * 19 * There is a single global HVS, with multiple output FIFOs that can 20 * be consumed by the PVs. This file just manages the resources for 21 * the HVS, while the vc4_crtc.c code actually drives HVS setup for 22 * each CRTC. 23 */ 24 25 #include "linux/component.h" 26 #include "vc4_drv.h" 27 #include "vc4_regs.h" 28 29 #define HVS_REG(reg) { reg, #reg } 30 static const struct { 31 u32 reg; 32 const char *name; 33 } hvs_regs[] = { 34 HVS_REG(SCALER_DISPCTRL), 35 HVS_REG(SCALER_DISPSTAT), 36 HVS_REG(SCALER_DISPID), 37 HVS_REG(SCALER_DISPECTRL), 38 HVS_REG(SCALER_DISPPROF), 39 HVS_REG(SCALER_DISPDITHER), 40 HVS_REG(SCALER_DISPEOLN), 41 HVS_REG(SCALER_DISPLIST0), 42 HVS_REG(SCALER_DISPLIST1), 43 HVS_REG(SCALER_DISPLIST2), 44 HVS_REG(SCALER_DISPLSTAT), 45 HVS_REG(SCALER_DISPLACT0), 46 HVS_REG(SCALER_DISPLACT1), 47 HVS_REG(SCALER_DISPLACT2), 48 HVS_REG(SCALER_DISPCTRL0), 49 HVS_REG(SCALER_DISPBKGND0), 50 HVS_REG(SCALER_DISPSTAT0), 51 HVS_REG(SCALER_DISPBASE0), 52 HVS_REG(SCALER_DISPCTRL1), 53 HVS_REG(SCALER_DISPBKGND1), 54 HVS_REG(SCALER_DISPSTAT1), 55 HVS_REG(SCALER_DISPBASE1), 56 HVS_REG(SCALER_DISPCTRL2), 57 HVS_REG(SCALER_DISPBKGND2), 58 HVS_REG(SCALER_DISPSTAT2), 59 HVS_REG(SCALER_DISPBASE2), 60 HVS_REG(SCALER_DISPALPHA2), 61 }; 62 63 void vc4_hvs_dump_state(struct drm_device *dev) 64 { 65 struct vc4_dev *vc4 = to_vc4_dev(dev); 66 int i; 67 68 for (i = 0; i < ARRAY_SIZE(hvs_regs); i++) { 69 DRM_INFO("0x%04x (%s): 0x%08x\n", 70 hvs_regs[i].reg, hvs_regs[i].name, 71 HVS_READ(hvs_regs[i].reg)); 72 } 73 74 DRM_INFO("HVS ctx:\n"); 75 for (i = 0; i < 64; i += 4) { 76 DRM_INFO("0x%08x (%s): 0x%08x 0x%08x 0x%08x 0x%08x\n", 77 i * 4, i < HVS_BOOTLOADER_DLIST_END ? "B" : "D", 78 ((uint32_t *)vc4->hvs->dlist)[i + 0], 79 ((uint32_t *)vc4->hvs->dlist)[i + 1], 80 ((uint32_t *)vc4->hvs->dlist)[i + 2], 81 ((uint32_t *)vc4->hvs->dlist)[i + 3]); 82 } 83 } 84 85 #ifdef CONFIG_DEBUG_FS 86 int vc4_hvs_debugfs_regs(struct seq_file *m, void *unused) 87 { 88 struct drm_info_node *node = (struct drm_info_node *)m->private; 89 struct drm_device *dev = node->minor->dev; 90 struct vc4_dev *vc4 = to_vc4_dev(dev); 91 int i; 92 93 for (i = 0; i < ARRAY_SIZE(hvs_regs); i++) { 94 seq_printf(m, "%s (0x%04x): 0x%08x\n", 95 hvs_regs[i].name, hvs_regs[i].reg, 96 HVS_READ(hvs_regs[i].reg)); 97 } 98 99 return 0; 100 } 101 #endif 102 103 static int vc4_hvs_bind(struct device *dev, struct device *master, void *data) 104 { 105 struct platform_device *pdev = to_platform_device(dev); 106 struct drm_device *drm = dev_get_drvdata(master); 107 struct vc4_dev *vc4 = drm->dev_private; 108 struct vc4_hvs *hvs = NULL; 109 110 hvs = devm_kzalloc(&pdev->dev, sizeof(*hvs), GFP_KERNEL); 111 if (!hvs) 112 return -ENOMEM; 113 114 hvs->pdev = pdev; 115 116 hvs->regs = vc4_ioremap_regs(pdev, 0); 117 if (IS_ERR(hvs->regs)) 118 return PTR_ERR(hvs->regs); 119 120 hvs->dlist = hvs->regs + SCALER_DLIST_START; 121 122 vc4->hvs = hvs; 123 return 0; 124 } 125 126 static void vc4_hvs_unbind(struct device *dev, struct device *master, 127 void *data) 128 { 129 struct drm_device *drm = dev_get_drvdata(master); 130 struct vc4_dev *vc4 = drm->dev_private; 131 132 vc4->hvs = NULL; 133 } 134 135 static const struct component_ops vc4_hvs_ops = { 136 .bind = vc4_hvs_bind, 137 .unbind = vc4_hvs_unbind, 138 }; 139 140 static int vc4_hvs_dev_probe(struct platform_device *pdev) 141 { 142 return component_add(&pdev->dev, &vc4_hvs_ops); 143 } 144 145 static int vc4_hvs_dev_remove(struct platform_device *pdev) 146 { 147 component_del(&pdev->dev, &vc4_hvs_ops); 148 return 0; 149 } 150 151 static const struct of_device_id vc4_hvs_dt_match[] = { 152 { .compatible = "brcm,bcm2835-hvs" }, 153 {} 154 }; 155 156 struct platform_driver vc4_hvs_driver = { 157 .probe = vc4_hvs_dev_probe, 158 .remove = vc4_hvs_dev_remove, 159 .driver = { 160 .name = "vc4_hvs", 161 .of_match_table = vc4_hvs_dt_match, 162 }, 163 }; 164