vc4_hvs.c 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261
  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 HVS is the piece of hardware that does translation, scaling,
  12. * colorspace conversion, and compositing of pixels stored in
  13. * framebuffers into a FIFO of pixels going out to the Pixel Valve
  14. * (CRTC). It operates at the system clock rate (the system audio
  15. * clock gate, specifically), which is much higher than the pixel
  16. * 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. };
  59. void vc4_hvs_dump_state(struct drm_device *dev)
  60. {
  61. struct vc4_dev *vc4 = to_vc4_dev(dev);
  62. int i;
  63. for (i = 0; i < ARRAY_SIZE(hvs_regs); i++) {
  64. DRM_INFO("0x%04x (%s): 0x%08x\n",
  65. hvs_regs[i].reg, hvs_regs[i].name,
  66. HVS_READ(hvs_regs[i].reg));
  67. }
  68. DRM_INFO("HVS ctx:\n");
  69. for (i = 0; i < 64; i += 4) {
  70. DRM_INFO("0x%08x (%s): 0x%08x 0x%08x 0x%08x 0x%08x\n",
  71. i * 4, i < HVS_BOOTLOADER_DLIST_END ? "B" : "D",
  72. readl((u32 __iomem *)vc4->hvs->dlist + i + 0),
  73. readl((u32 __iomem *)vc4->hvs->dlist + i + 1),
  74. readl((u32 __iomem *)vc4->hvs->dlist + i + 2),
  75. readl((u32 __iomem *)vc4->hvs->dlist + i + 3));
  76. }
  77. }
  78. #ifdef CONFIG_DEBUG_FS
  79. int vc4_hvs_debugfs_regs(struct seq_file *m, void *unused)
  80. {
  81. struct drm_info_node *node = (struct drm_info_node *)m->private;
  82. struct drm_device *dev = node->minor->dev;
  83. struct vc4_dev *vc4 = to_vc4_dev(dev);
  84. int i;
  85. for (i = 0; i < ARRAY_SIZE(hvs_regs); i++) {
  86. seq_printf(m, "%s (0x%04x): 0x%08x\n",
  87. hvs_regs[i].name, hvs_regs[i].reg,
  88. HVS_READ(hvs_regs[i].reg));
  89. }
  90. return 0;
  91. }
  92. #endif
  93. /* The filter kernel is composed of dwords each containing 3 9-bit
  94. * signed integers packed next to each other.
  95. */
  96. #define VC4_INT_TO_COEFF(coeff) (coeff & 0x1ff)
  97. #define VC4_PPF_FILTER_WORD(c0, c1, c2) \
  98. ((((c0) & 0x1ff) << 0) | \
  99. (((c1) & 0x1ff) << 9) | \
  100. (((c2) & 0x1ff) << 18))
  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. #define VC4_LINEAR_PHASE_KERNEL_DWORDS 6
  116. #define VC4_KERNEL_DWORDS (VC4_LINEAR_PHASE_KERNEL_DWORDS * 2 - 1)
  117. /* Recommended B=1/3, C=1/3 filter choice from Mitchell/Netravali.
  118. * http://www.cs.utexas.edu/~fussell/courses/cs384g/lectures/mitchell/Mitchell.pdf
  119. */
  120. static const u32 mitchell_netravali_1_3_1_3_kernel[] =
  121. VC4_LINEAR_PHASE_KERNEL(0, -2, -6, -8, -10, -8, -3, 2, 18,
  122. 50, 82, 119, 155, 187, 213, 227);
  123. static int vc4_hvs_upload_linear_kernel(struct vc4_hvs *hvs,
  124. struct drm_mm_node *space,
  125. const u32 *kernel)
  126. {
  127. int ret, i;
  128. u32 __iomem *dst_kernel;
  129. ret = drm_mm_insert_node(&hvs->dlist_mm, space, VC4_KERNEL_DWORDS, 1,
  130. 0);
  131. if (ret) {
  132. DRM_ERROR("Failed to allocate space for filter kernel: %d\n",
  133. ret);
  134. return ret;
  135. }
  136. dst_kernel = hvs->dlist + space->start;
  137. for (i = 0; i < VC4_KERNEL_DWORDS; i++) {
  138. if (i < VC4_LINEAR_PHASE_KERNEL_DWORDS)
  139. writel(kernel[i], &dst_kernel[i]);
  140. else {
  141. writel(kernel[VC4_KERNEL_DWORDS - i - 1],
  142. &dst_kernel[i]);
  143. }
  144. }
  145. return 0;
  146. }
  147. static int vc4_hvs_bind(struct device *dev, struct device *master, void *data)
  148. {
  149. struct platform_device *pdev = to_platform_device(dev);
  150. struct drm_device *drm = dev_get_drvdata(master);
  151. struct vc4_dev *vc4 = drm->dev_private;
  152. struct vc4_hvs *hvs = NULL;
  153. int ret;
  154. hvs = devm_kzalloc(&pdev->dev, sizeof(*hvs), GFP_KERNEL);
  155. if (!hvs)
  156. return -ENOMEM;
  157. hvs->pdev = pdev;
  158. hvs->regs = vc4_ioremap_regs(pdev, 0);
  159. if (IS_ERR(hvs->regs))
  160. return PTR_ERR(hvs->regs);
  161. hvs->dlist = hvs->regs + SCALER_DLIST_START;
  162. spin_lock_init(&hvs->mm_lock);
  163. /* Set up the HVS display list memory manager. We never
  164. * overwrite the setup from the bootloader (just 128b out of
  165. * our 16K), since we don't want to scramble the screen when
  166. * transitioning from the firmware's boot setup to runtime.
  167. */
  168. drm_mm_init(&hvs->dlist_mm,
  169. HVS_BOOTLOADER_DLIST_END,
  170. (SCALER_DLIST_SIZE >> 2) - HVS_BOOTLOADER_DLIST_END);
  171. /* Set up the HVS LBM memory manager. We could have some more
  172. * complicated data structure that allowed reuse of LBM areas
  173. * between planes when they don't overlap on the screen, but
  174. * for now we just allocate globally.
  175. */
  176. drm_mm_init(&hvs->lbm_mm, 0, 96 * 1024);
  177. /* Upload filter kernels. We only have the one for now, so we
  178. * keep it around for the lifetime of the driver.
  179. */
  180. ret = vc4_hvs_upload_linear_kernel(hvs,
  181. &hvs->mitchell_netravali_filter,
  182. mitchell_netravali_1_3_1_3_kernel);
  183. if (ret)
  184. return ret;
  185. vc4->hvs = hvs;
  186. return 0;
  187. }
  188. static void vc4_hvs_unbind(struct device *dev, struct device *master,
  189. void *data)
  190. {
  191. struct drm_device *drm = dev_get_drvdata(master);
  192. struct vc4_dev *vc4 = drm->dev_private;
  193. if (vc4->hvs->mitchell_netravali_filter.allocated)
  194. drm_mm_remove_node(&vc4->hvs->mitchell_netravali_filter);
  195. drm_mm_takedown(&vc4->hvs->dlist_mm);
  196. drm_mm_takedown(&vc4->hvs->lbm_mm);
  197. vc4->hvs = NULL;
  198. }
  199. static const struct component_ops vc4_hvs_ops = {
  200. .bind = vc4_hvs_bind,
  201. .unbind = vc4_hvs_unbind,
  202. };
  203. static int vc4_hvs_dev_probe(struct platform_device *pdev)
  204. {
  205. return component_add(&pdev->dev, &vc4_hvs_ops);
  206. }
  207. static int vc4_hvs_dev_remove(struct platform_device *pdev)
  208. {
  209. component_del(&pdev->dev, &vc4_hvs_ops);
  210. return 0;
  211. }
  212. static const struct of_device_id vc4_hvs_dt_match[] = {
  213. { .compatible = "brcm,bcm2835-hvs" },
  214. {}
  215. };
  216. struct platform_driver vc4_hvs_driver = {
  217. .probe = vc4_hvs_dev_probe,
  218. .remove = vc4_hvs_dev_remove,
  219. .driver = {
  220. .name = "vc4_hvs",
  221. .of_match_table = vc4_hvs_dt_match,
  222. },
  223. };