vc4_hvs.c 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277
  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. * DOC: VC4 HVS module.
  10. *
  11. * The Hardware Video Scaler (HVS) is the piece of hardware that does
  12. * translation, scaling, colorspace conversion, and compositing of
  13. * pixels stored in framebuffers into a FIFO of pixels going out to
  14. * the Pixel Valve (CRTC). It operates at the system clock rate (the
  15. * system audio clock gate, specifically), which is much higher than
  16. * the pixel clock rate.
  17. *
  18. * There is a single global HVS, with multiple output FIFOs that can
  19. * be consumed by the PVs. This file just manages the resources for
  20. * the HVS, while the vc4_crtc.c code actually drives HVS setup for
  21. * each CRTC.
  22. */
  23. #include <linux/component.h>
  24. #include "vc4_drv.h"
  25. #include "vc4_regs.h"
  26. #define HVS_REG(reg) { reg, #reg }
  27. static const struct {
  28. u32 reg;
  29. const char *name;
  30. } hvs_regs[] = {
  31. HVS_REG(SCALER_DISPCTRL),
  32. HVS_REG(SCALER_DISPSTAT),
  33. HVS_REG(SCALER_DISPID),
  34. HVS_REG(SCALER_DISPECTRL),
  35. HVS_REG(SCALER_DISPPROF),
  36. HVS_REG(SCALER_DISPDITHER),
  37. HVS_REG(SCALER_DISPEOLN),
  38. HVS_REG(SCALER_DISPLIST0),
  39. HVS_REG(SCALER_DISPLIST1),
  40. HVS_REG(SCALER_DISPLIST2),
  41. HVS_REG(SCALER_DISPLSTAT),
  42. HVS_REG(SCALER_DISPLACT0),
  43. HVS_REG(SCALER_DISPLACT1),
  44. HVS_REG(SCALER_DISPLACT2),
  45. HVS_REG(SCALER_DISPCTRL0),
  46. HVS_REG(SCALER_DISPBKGND0),
  47. HVS_REG(SCALER_DISPSTAT0),
  48. HVS_REG(SCALER_DISPBASE0),
  49. HVS_REG(SCALER_DISPCTRL1),
  50. HVS_REG(SCALER_DISPBKGND1),
  51. HVS_REG(SCALER_DISPSTAT1),
  52. HVS_REG(SCALER_DISPBASE1),
  53. HVS_REG(SCALER_DISPCTRL2),
  54. HVS_REG(SCALER_DISPBKGND2),
  55. HVS_REG(SCALER_DISPSTAT2),
  56. HVS_REG(SCALER_DISPBASE2),
  57. HVS_REG(SCALER_DISPALPHA2),
  58. HVS_REG(SCALER_OLEDOFFS),
  59. HVS_REG(SCALER_OLEDCOEF0),
  60. HVS_REG(SCALER_OLEDCOEF1),
  61. HVS_REG(SCALER_OLEDCOEF2),
  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. for (i = 0; i < ARRAY_SIZE(hvs_regs); i++) {
  68. DRM_INFO("0x%04x (%s): 0x%08x\n",
  69. hvs_regs[i].reg, hvs_regs[i].name,
  70. HVS_READ(hvs_regs[i].reg));
  71. }
  72. DRM_INFO("HVS ctx:\n");
  73. for (i = 0; i < 64; i += 4) {
  74. DRM_INFO("0x%08x (%s): 0x%08x 0x%08x 0x%08x 0x%08x\n",
  75. i * 4, i < HVS_BOOTLOADER_DLIST_END ? "B" : "D",
  76. readl((u32 __iomem *)vc4->hvs->dlist + i + 0),
  77. readl((u32 __iomem *)vc4->hvs->dlist + i + 1),
  78. readl((u32 __iomem *)vc4->hvs->dlist + i + 2),
  79. readl((u32 __iomem *)vc4->hvs->dlist + i + 3));
  80. }
  81. }
  82. #ifdef CONFIG_DEBUG_FS
  83. int vc4_hvs_debugfs_regs(struct seq_file *m, void *unused)
  84. {
  85. struct drm_info_node *node = (struct drm_info_node *)m->private;
  86. struct drm_device *dev = node->minor->dev;
  87. struct vc4_dev *vc4 = to_vc4_dev(dev);
  88. int i;
  89. for (i = 0; i < ARRAY_SIZE(hvs_regs); i++) {
  90. seq_printf(m, "%s (0x%04x): 0x%08x\n",
  91. hvs_regs[i].name, hvs_regs[i].reg,
  92. HVS_READ(hvs_regs[i].reg));
  93. }
  94. return 0;
  95. }
  96. #endif
  97. /* The filter kernel is composed of dwords each containing 3 9-bit
  98. * signed integers packed next to each other.
  99. */
  100. #define VC4_INT_TO_COEFF(coeff) (coeff & 0x1ff)
  101. #define VC4_PPF_FILTER_WORD(c0, c1, c2) \
  102. ((((c0) & 0x1ff) << 0) | \
  103. (((c1) & 0x1ff) << 9) | \
  104. (((c2) & 0x1ff) << 18))
  105. /* The whole filter kernel is arranged as the coefficients 0-16 going
  106. * up, then a pad, then 17-31 going down and reversed within the
  107. * dwords. This means that a linear phase kernel (where it's
  108. * symmetrical at the boundary between 15 and 16) has the last 5
  109. * dwords matching the first 5, but reversed.
  110. */
  111. #define VC4_LINEAR_PHASE_KERNEL(c0, c1, c2, c3, c4, c5, c6, c7, c8, \
  112. c9, c10, c11, c12, c13, c14, c15) \
  113. {VC4_PPF_FILTER_WORD(c0, c1, c2), \
  114. VC4_PPF_FILTER_WORD(c3, c4, c5), \
  115. VC4_PPF_FILTER_WORD(c6, c7, c8), \
  116. VC4_PPF_FILTER_WORD(c9, c10, c11), \
  117. VC4_PPF_FILTER_WORD(c12, c13, c14), \
  118. VC4_PPF_FILTER_WORD(c15, c15, 0)}
  119. #define VC4_LINEAR_PHASE_KERNEL_DWORDS 6
  120. #define VC4_KERNEL_DWORDS (VC4_LINEAR_PHASE_KERNEL_DWORDS * 2 - 1)
  121. /* Recommended B=1/3, C=1/3 filter choice from Mitchell/Netravali.
  122. * http://www.cs.utexas.edu/~fussell/courses/cs384g/lectures/mitchell/Mitchell.pdf
  123. */
  124. static const u32 mitchell_netravali_1_3_1_3_kernel[] =
  125. VC4_LINEAR_PHASE_KERNEL(0, -2, -6, -8, -10, -8, -3, 2, 18,
  126. 50, 82, 119, 155, 187, 213, 227);
  127. static int vc4_hvs_upload_linear_kernel(struct vc4_hvs *hvs,
  128. struct drm_mm_node *space,
  129. const u32 *kernel)
  130. {
  131. int ret, i;
  132. u32 __iomem *dst_kernel;
  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. dst_kernel = hvs->dlist + space->start;
  140. for (i = 0; i < VC4_KERNEL_DWORDS; i++) {
  141. if (i < VC4_LINEAR_PHASE_KERNEL_DWORDS)
  142. writel(kernel[i], &dst_kernel[i]);
  143. else {
  144. writel(kernel[VC4_KERNEL_DWORDS - i - 1],
  145. &dst_kernel[i]);
  146. }
  147. }
  148. return 0;
  149. }
  150. static int vc4_hvs_bind(struct device *dev, struct device *master, void *data)
  151. {
  152. struct platform_device *pdev = to_platform_device(dev);
  153. struct drm_device *drm = dev_get_drvdata(master);
  154. struct vc4_dev *vc4 = drm->dev_private;
  155. struct vc4_hvs *hvs = NULL;
  156. int ret;
  157. u32 dispctrl;
  158. hvs = devm_kzalloc(&pdev->dev, sizeof(*hvs), GFP_KERNEL);
  159. if (!hvs)
  160. return -ENOMEM;
  161. hvs->pdev = pdev;
  162. hvs->regs = vc4_ioremap_regs(pdev, 0);
  163. if (IS_ERR(hvs->regs))
  164. return PTR_ERR(hvs->regs);
  165. hvs->dlist = hvs->regs + SCALER_DLIST_START;
  166. spin_lock_init(&hvs->mm_lock);
  167. /* Set up the HVS display list memory manager. We never
  168. * overwrite the setup from the bootloader (just 128b out of
  169. * our 16K), since we don't want to scramble the screen when
  170. * transitioning from the firmware's boot setup to runtime.
  171. */
  172. drm_mm_init(&hvs->dlist_mm,
  173. HVS_BOOTLOADER_DLIST_END,
  174. (SCALER_DLIST_SIZE >> 2) - HVS_BOOTLOADER_DLIST_END);
  175. /* Set up the HVS LBM memory manager. We could have some more
  176. * complicated data structure that allowed reuse of LBM areas
  177. * between planes when they don't overlap on the screen, but
  178. * for now we just allocate globally.
  179. */
  180. drm_mm_init(&hvs->lbm_mm, 0, 96 * 1024);
  181. /* Upload filter kernels. We only have the one for now, so we
  182. * keep it around for the lifetime of the driver.
  183. */
  184. ret = vc4_hvs_upload_linear_kernel(hvs,
  185. &hvs->mitchell_netravali_filter,
  186. mitchell_netravali_1_3_1_3_kernel);
  187. if (ret)
  188. return ret;
  189. vc4->hvs = hvs;
  190. dispctrl = HVS_READ(SCALER_DISPCTRL);
  191. dispctrl |= SCALER_DISPCTRL_ENABLE;
  192. /* Set DSP3 (PV1) to use HVS channel 2, which would otherwise
  193. * be unused.
  194. */
  195. dispctrl &= ~SCALER_DISPCTRL_DSP3_MUX_MASK;
  196. dispctrl |= VC4_SET_FIELD(2, SCALER_DISPCTRL_DSP3_MUX);
  197. HVS_WRITE(SCALER_DISPCTRL, dispctrl);
  198. return 0;
  199. }
  200. static void vc4_hvs_unbind(struct device *dev, struct device *master,
  201. void *data)
  202. {
  203. struct drm_device *drm = dev_get_drvdata(master);
  204. struct vc4_dev *vc4 = drm->dev_private;
  205. if (vc4->hvs->mitchell_netravali_filter.allocated)
  206. drm_mm_remove_node(&vc4->hvs->mitchell_netravali_filter);
  207. drm_mm_takedown(&vc4->hvs->dlist_mm);
  208. drm_mm_takedown(&vc4->hvs->lbm_mm);
  209. vc4->hvs = NULL;
  210. }
  211. static const struct component_ops vc4_hvs_ops = {
  212. .bind = vc4_hvs_bind,
  213. .unbind = vc4_hvs_unbind,
  214. };
  215. static int vc4_hvs_dev_probe(struct platform_device *pdev)
  216. {
  217. return component_add(&pdev->dev, &vc4_hvs_ops);
  218. }
  219. static int vc4_hvs_dev_remove(struct platform_device *pdev)
  220. {
  221. component_del(&pdev->dev, &vc4_hvs_ops);
  222. return 0;
  223. }
  224. static const struct of_device_id vc4_hvs_dt_match[] = {
  225. { .compatible = "brcm,bcm2835-hvs" },
  226. {}
  227. };
  228. struct platform_driver vc4_hvs_driver = {
  229. .probe = vc4_hvs_dev_probe,
  230. .remove = vc4_hvs_dev_remove,
  231. .driver = {
  232. .name = "vc4_hvs",
  233. .of_match_table = vc4_hvs_dt_match,
  234. },
  235. };