headc57d.c 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253
  1. /*
  2. * Copyright 2018 Red Hat Inc.
  3. *
  4. * Permission is hereby granted, free of charge, to any person obtaining a
  5. * copy of this software and associated documentation files (the "Software"),
  6. * to deal in the Software without restriction, including without limitation
  7. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  8. * and/or sell copies of the Software, and to permit persons to whom the
  9. * Software is furnished to do so, subject to the following conditions:
  10. *
  11. * The above copyright notice and this permission notice shall be included in
  12. * all copies or substantial portions of the Software.
  13. *
  14. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  17. * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
  18. * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
  19. * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  20. * OTHER DEALINGS IN THE SOFTWARE.
  21. */
  22. #include "head.h"
  23. #include "atom.h"
  24. #include "core.h"
  25. #include <nvif/pushc37b.h>
  26. #include <nvhw/class/clc57d.h>
  27. static int
  28. headc57d_or(struct nv50_head *head, struct nv50_head_atom *asyh)
  29. {
  30. struct nvif_push *push = nv50_disp(head->base.base.dev)->core->chan.push;
  31. const int i = head->base.index;
  32. u8 depth;
  33. int ret;
  34. /*XXX: This is a dirty hack until OR depth handling is
  35. * improved later for deep colour etc.
  36. */
  37. switch (asyh->or.depth) {
  38. case 6: depth = 5; break;
  39. case 5: depth = 4; break;
  40. case 2: depth = 1; break;
  41. case 0: depth = 4; break;
  42. default:
  43. depth = asyh->or.depth;
  44. WARN_ON(1);
  45. break;
  46. }
  47. if ((ret = PUSH_WAIT(push, 2)))
  48. return ret;
  49. PUSH_MTHD(push, NVC57D, HEAD_SET_CONTROL_OUTPUT_RESOURCE(i),
  50. NVVAL(NVC57D, HEAD_SET_CONTROL_OUTPUT_RESOURCE, CRC_MODE, asyh->or.crc_raster) |
  51. NVVAL(NVC57D, HEAD_SET_CONTROL_OUTPUT_RESOURCE, HSYNC_POLARITY, asyh->or.nhsync) |
  52. NVVAL(NVC57D, HEAD_SET_CONTROL_OUTPUT_RESOURCE, VSYNC_POLARITY, asyh->or.nvsync) |
  53. NVVAL(NVC57D, HEAD_SET_CONTROL_OUTPUT_RESOURCE, PIXEL_DEPTH, depth) |
  54. NVDEF(NVC57D, HEAD_SET_CONTROL_OUTPUT_RESOURCE, COLOR_SPACE_OVERRIDE, DISABLE) |
  55. NVDEF(NVC57D, HEAD_SET_CONTROL_OUTPUT_RESOURCE, EXT_PACKET_WIN, NONE));
  56. return 0;
  57. }
  58. static int
  59. headc57d_procamp(struct nv50_head *head, struct nv50_head_atom *asyh)
  60. {
  61. struct nvif_push *push = nv50_disp(head->base.base.dev)->core->chan.push;
  62. const int i = head->base.index;
  63. int ret;
  64. if ((ret = PUSH_WAIT(push, 2)))
  65. return ret;
  66. //TODO:
  67. PUSH_MTHD(push, NVC57D, HEAD_SET_PROCAMP(i),
  68. NVDEF(NVC57D, HEAD_SET_PROCAMP, COLOR_SPACE, RGB) |
  69. NVDEF(NVC57D, HEAD_SET_PROCAMP, CHROMA_LPF, DISABLE) |
  70. NVDEF(NVC57D, HEAD_SET_PROCAMP, DYNAMIC_RANGE, VESA));
  71. return 0;
  72. }
  73. static int
  74. headc57d_olut_clr(struct nv50_head *head)
  75. {
  76. struct nvif_push *push = nv50_disp(head->base.base.dev)->core->chan.push;
  77. const int i = head->base.index;
  78. int ret;
  79. if ((ret = PUSH_WAIT(push, 2)))
  80. return ret;
  81. PUSH_MTHD(push, NVC57D, HEAD_SET_CONTEXT_DMA_OLUT(i), 0x00000000);
  82. return 0;
  83. }
  84. static int
  85. headc57d_olut_set(struct nv50_head *head, struct nv50_head_atom *asyh)
  86. {
  87. struct nvif_push *push = nv50_disp(head->base.base.dev)->core->chan.push;
  88. const int i = head->base.index;
  89. int ret;
  90. if ((ret = PUSH_WAIT(push, 5)))
  91. return ret;
  92. PUSH_MTHD(push, NVC57D, HEAD_SET_OLUT_CONTROL(i),
  93. NVVAL(NVC57D, HEAD_SET_OLUT_CONTROL, INTERPOLATE, asyh->olut.output_mode) |
  94. NVDEF(NVC57D, HEAD_SET_OLUT_CONTROL, MIRROR, DISABLE) |
  95. NVVAL(NVC57D, HEAD_SET_OLUT_CONTROL, MODE, asyh->olut.mode) |
  96. NVVAL(NVC57D, HEAD_SET_OLUT_CONTROL, SIZE, asyh->olut.size),
  97. HEAD_SET_OLUT_FP_NORM_SCALE(i), 0xffffffff,
  98. HEAD_SET_CONTEXT_DMA_OLUT(i), asyh->olut.handle,
  99. HEAD_SET_OFFSET_OLUT(i), asyh->olut.offset >> 8);
  100. return 0;
  101. }
  102. static void
  103. headc57d_olut_load_8(struct drm_color_lut *in, int size, void __iomem *mem)
  104. {
  105. memset_io(mem, 0x00, 0x20); /* VSS header. */
  106. mem += 0x20;
  107. while (size--) {
  108. u16 r = drm_color_lut_extract(in-> red + 0, 16);
  109. u16 g = drm_color_lut_extract(in->green + 0, 16);
  110. u16 b = drm_color_lut_extract(in-> blue + 0, 16);
  111. u16 ri = 0, gi = 0, bi = 0, i;
  112. if (in++, size) {
  113. ri = (drm_color_lut_extract(in-> red, 16) - r) / 4;
  114. gi = (drm_color_lut_extract(in->green, 16) - g) / 4;
  115. bi = (drm_color_lut_extract(in-> blue, 16) - b) / 4;
  116. }
  117. for (i = 0; i < 4; i++, mem += 8) {
  118. writew(r + ri * i, mem + 0);
  119. writew(g + gi * i, mem + 2);
  120. writew(b + bi * i, mem + 4);
  121. }
  122. }
  123. /* INTERPOLATE modes require a "next" entry to interpolate with,
  124. * so we replicate the last entry to deal with this for now.
  125. */
  126. writew(readw(mem - 8), mem + 0);
  127. writew(readw(mem - 6), mem + 2);
  128. writew(readw(mem - 4), mem + 4);
  129. }
  130. static void
  131. headc57d_olut_load(struct drm_color_lut *in, int size, void __iomem *mem)
  132. {
  133. memset_io(mem, 0x00, 0x20); /* VSS header. */
  134. mem += 0x20;
  135. for (; size--; in++, mem += 0x08) {
  136. writew(drm_color_lut_extract(in-> red, 16), mem + 0);
  137. writew(drm_color_lut_extract(in->green, 16), mem + 2);
  138. writew(drm_color_lut_extract(in-> blue, 16), mem + 4);
  139. }
  140. /* INTERPOLATE modes require a "next" entry to interpolate with,
  141. * so we replicate the last entry to deal with this for now.
  142. */
  143. writew(readw(mem - 8), mem + 0);
  144. writew(readw(mem - 6), mem + 2);
  145. writew(readw(mem - 4), mem + 4);
  146. }
  147. static bool
  148. headc57d_olut(struct nv50_head *head, struct nv50_head_atom *asyh, int size)
  149. {
  150. if (size != 0 && size != 256 && size != 1024)
  151. return false;
  152. asyh->olut.mode = NVC57D_HEAD_SET_OLUT_CONTROL_MODE_DIRECT10;
  153. asyh->olut.size = 4 /* VSS header. */ + 1024 + 1 /* Entries. */;
  154. asyh->olut.output_mode = NVC57D_HEAD_SET_OLUT_CONTROL_INTERPOLATE_ENABLE;
  155. if (size == 256)
  156. asyh->olut.load = headc57d_olut_load_8;
  157. else
  158. asyh->olut.load = headc57d_olut_load;
  159. return true;
  160. }
  161. static int
  162. headc57d_mode(struct nv50_head *head, struct nv50_head_atom *asyh)
  163. {
  164. struct nvif_push *push = nv50_disp(head->base.base.dev)->core->chan.push;
  165. struct nv50_head_mode *m = &asyh->mode;
  166. const int i = head->base.index;
  167. int ret;
  168. if ((ret = PUSH_WAIT(push, 15)))
  169. return ret;
  170. PUSH_MTHD(push, NVC57D, HEAD_SET_RASTER_SIZE(i),
  171. NVVAL(NVC57D, HEAD_SET_RASTER_SIZE, WIDTH, m->h.active) |
  172. NVVAL(NVC57D, HEAD_SET_RASTER_SIZE, HEIGHT, m->v.active),
  173. HEAD_SET_RASTER_SYNC_END(i),
  174. NVVAL(NVC57D, HEAD_SET_RASTER_SYNC_END, X, m->h.synce) |
  175. NVVAL(NVC57D, HEAD_SET_RASTER_SYNC_END, Y, m->v.synce),
  176. HEAD_SET_RASTER_BLANK_END(i),
  177. NVVAL(NVC57D, HEAD_SET_RASTER_BLANK_END, X, m->h.blanke) |
  178. NVVAL(NVC57D, HEAD_SET_RASTER_BLANK_END, Y, m->v.blanke),
  179. HEAD_SET_RASTER_BLANK_START(i),
  180. NVVAL(NVC57D, HEAD_SET_RASTER_BLANK_START, X, m->h.blanks) |
  181. NVVAL(NVC57D, HEAD_SET_RASTER_BLANK_START, Y, m->v.blanks));
  182. //XXX:
  183. PUSH_NVSQ(push, NVC57D, 0x2074 + (i * 0x400), m->v.blank2e << 16 | m->v.blank2s);
  184. PUSH_NVSQ(push, NVC57D, 0x2008 + (i * 0x400), m->interlace);
  185. PUSH_MTHD(push, NVC57D, HEAD_SET_PIXEL_CLOCK_FREQUENCY(i),
  186. NVVAL(NVC57D, HEAD_SET_PIXEL_CLOCK_FREQUENCY, HERTZ, m->clock * 1000));
  187. PUSH_MTHD(push, NVC57D, HEAD_SET_PIXEL_CLOCK_FREQUENCY_MAX(i),
  188. NVVAL(NVC57D, HEAD_SET_PIXEL_CLOCK_FREQUENCY_MAX, HERTZ, m->clock * 1000));
  189. /*XXX: HEAD_USAGE_BOUNDS, doesn't belong here. */
  190. PUSH_MTHD(push, NVC57D, HEAD_SET_HEAD_USAGE_BOUNDS(i),
  191. NVDEF(NVC57D, HEAD_SET_HEAD_USAGE_BOUNDS, CURSOR, USAGE_W256_H256) |
  192. NVDEF(NVC57D, HEAD_SET_HEAD_USAGE_BOUNDS, OLUT_ALLOWED, TRUE) |
  193. NVDEF(NVC57D, HEAD_SET_HEAD_USAGE_BOUNDS, OUTPUT_SCALER_TAPS, TAPS_2) |
  194. NVDEF(NVC57D, HEAD_SET_HEAD_USAGE_BOUNDS, UPSCALING_ALLOWED, TRUE));
  195. return 0;
  196. }
  197. const struct nv50_head_func
  198. headc57d = {
  199. .view = headc37d_view,
  200. .mode = headc57d_mode,
  201. .olut = headc57d_olut,
  202. .ilut_check = head907d_ilut_check,
  203. .olut_identity = true,
  204. .olut_size = 1024,
  205. .olut_set = headc57d_olut_set,
  206. .olut_clr = headc57d_olut_clr,
  207. .curs_layout = head917d_curs_layout,
  208. .curs_format = headc37d_curs_format,
  209. .curs_set = headc37d_curs_set,
  210. .curs_clr = headc37d_curs_clr,
  211. .dither = headc37d_dither,
  212. .procamp = headc57d_procamp,
  213. .or = headc57d_or,
  214. /* TODO: flexible window mappings */
  215. .static_wndw_map = headc37d_static_wndw_map,
  216. };