vc4_hvs.c 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  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. static int vc4_hvs_bind(struct device *dev, struct device *master, void *data)
  94. {
  95. struct platform_device *pdev = to_platform_device(dev);
  96. struct drm_device *drm = dev_get_drvdata(master);
  97. struct vc4_dev *vc4 = drm->dev_private;
  98. struct vc4_hvs *hvs = NULL;
  99. hvs = devm_kzalloc(&pdev->dev, sizeof(*hvs), GFP_KERNEL);
  100. if (!hvs)
  101. return -ENOMEM;
  102. hvs->pdev = pdev;
  103. hvs->regs = vc4_ioremap_regs(pdev, 0);
  104. if (IS_ERR(hvs->regs))
  105. return PTR_ERR(hvs->regs);
  106. hvs->dlist = hvs->regs + SCALER_DLIST_START;
  107. vc4->hvs = hvs;
  108. return 0;
  109. }
  110. static void vc4_hvs_unbind(struct device *dev, struct device *master,
  111. void *data)
  112. {
  113. struct drm_device *drm = dev_get_drvdata(master);
  114. struct vc4_dev *vc4 = drm->dev_private;
  115. vc4->hvs = NULL;
  116. }
  117. static const struct component_ops vc4_hvs_ops = {
  118. .bind = vc4_hvs_bind,
  119. .unbind = vc4_hvs_unbind,
  120. };
  121. static int vc4_hvs_dev_probe(struct platform_device *pdev)
  122. {
  123. return component_add(&pdev->dev, &vc4_hvs_ops);
  124. }
  125. static int vc4_hvs_dev_remove(struct platform_device *pdev)
  126. {
  127. component_del(&pdev->dev, &vc4_hvs_ops);
  128. return 0;
  129. }
  130. static const struct of_device_id vc4_hvs_dt_match[] = {
  131. { .compatible = "brcm,bcm2835-hvs" },
  132. {}
  133. };
  134. struct platform_driver vc4_hvs_driver = {
  135. .probe = vc4_hvs_dev_probe,
  136. .remove = vc4_hvs_dev_remove,
  137. .driver = {
  138. .name = "vc4_hvs",
  139. .of_match_table = vc4_hvs_dt_match,
  140. },
  141. };