head.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639
  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 "base.h"
  24. #include "core.h"
  25. #include "curs.h"
  26. #include "ovly.h"
  27. #include "crc.h"
  28. #include <nvif/class.h>
  29. #include <nvif/event.h>
  30. #include <nvif/cl0046.h>
  31. #include <drm/drm_atomic.h>
  32. #include <drm/drm_atomic_helper.h>
  33. #include <drm/drm_crtc_helper.h>
  34. #include <drm/drm_vblank.h>
  35. #include "nouveau_connector.h"
  36. void
  37. nv50_head_flush_clr(struct nv50_head *head,
  38. struct nv50_head_atom *asyh, bool flush)
  39. {
  40. union nv50_head_atom_mask clr = {
  41. .mask = asyh->clr.mask & ~(flush ? 0 : asyh->set.mask),
  42. };
  43. if (clr.crc) nv50_crc_atomic_clr(head);
  44. if (clr.olut) head->func->olut_clr(head);
  45. if (clr.core) head->func->core_clr(head);
  46. if (clr.curs) head->func->curs_clr(head);
  47. }
  48. void
  49. nv50_head_flush_set_wndw(struct nv50_head *head, struct nv50_head_atom *asyh)
  50. {
  51. if (asyh->set.curs ) head->func->curs_set(head, asyh);
  52. if (asyh->set.olut ) {
  53. asyh->olut.offset = nv50_lut_load(&head->olut,
  54. asyh->olut.buffer,
  55. asyh->state.gamma_lut,
  56. asyh->olut.load);
  57. head->func->olut_set(head, asyh);
  58. }
  59. }
  60. void
  61. nv50_head_flush_set(struct nv50_head *head, struct nv50_head_atom *asyh)
  62. {
  63. if (asyh->set.view ) head->func->view (head, asyh);
  64. if (asyh->set.mode ) head->func->mode (head, asyh);
  65. if (asyh->set.core ) head->func->core_set(head, asyh);
  66. if (asyh->set.base ) head->func->base (head, asyh);
  67. if (asyh->set.ovly ) head->func->ovly (head, asyh);
  68. if (asyh->set.dither ) head->func->dither (head, asyh);
  69. if (asyh->set.procamp) head->func->procamp (head, asyh);
  70. if (asyh->set.crc ) nv50_crc_atomic_set (head, asyh);
  71. if (asyh->set.or ) head->func->or (head, asyh);
  72. }
  73. static void
  74. nv50_head_atomic_check_procamp(struct nv50_head_atom *armh,
  75. struct nv50_head_atom *asyh,
  76. struct nouveau_conn_atom *asyc)
  77. {
  78. const int vib = asyc->procamp.color_vibrance - 100;
  79. const int hue = asyc->procamp.vibrant_hue - 90;
  80. const int adj = (vib > 0) ? 50 : 0;
  81. asyh->procamp.sat.cos = ((vib * 2047 + adj) / 100) & 0xfff;
  82. asyh->procamp.sat.sin = ((hue * 2047) / 100) & 0xfff;
  83. asyh->set.procamp = true;
  84. }
  85. static void
  86. nv50_head_atomic_check_dither(struct nv50_head_atom *armh,
  87. struct nv50_head_atom *asyh,
  88. struct nouveau_conn_atom *asyc)
  89. {
  90. u32 mode = 0x00;
  91. if (asyc->dither.mode) {
  92. if (asyc->dither.mode == DITHERING_MODE_AUTO) {
  93. if (asyh->base.depth > asyh->or.bpc * 3)
  94. mode = DITHERING_MODE_DYNAMIC2X2;
  95. } else {
  96. mode = asyc->dither.mode;
  97. }
  98. if (asyc->dither.depth == DITHERING_DEPTH_AUTO) {
  99. if (asyh->or.bpc >= 8)
  100. mode |= DITHERING_DEPTH_8BPC;
  101. } else {
  102. mode |= asyc->dither.depth;
  103. }
  104. }
  105. asyh->dither.enable = NVVAL_GET(mode, NV507D, HEAD_SET_DITHER_CONTROL, ENABLE);
  106. asyh->dither.bits = NVVAL_GET(mode, NV507D, HEAD_SET_DITHER_CONTROL, BITS);
  107. asyh->dither.mode = NVVAL_GET(mode, NV507D, HEAD_SET_DITHER_CONTROL, MODE);
  108. asyh->set.dither = true;
  109. }
  110. static void
  111. nv50_head_atomic_check_view(struct nv50_head_atom *armh,
  112. struct nv50_head_atom *asyh,
  113. struct nouveau_conn_atom *asyc)
  114. {
  115. struct drm_connector *connector = asyc->state.connector;
  116. struct drm_display_mode *omode = &asyh->state.adjusted_mode;
  117. struct drm_display_mode *umode = &asyh->state.mode;
  118. int mode = asyc->scaler.mode;
  119. struct edid *edid;
  120. int umode_vdisplay, omode_hdisplay, omode_vdisplay;
  121. if (connector->edid_blob_ptr)
  122. edid = (struct edid *)connector->edid_blob_ptr->data;
  123. else
  124. edid = NULL;
  125. if (!asyc->scaler.full) {
  126. if (mode == DRM_MODE_SCALE_NONE)
  127. omode = umode;
  128. } else {
  129. /* Non-EDID LVDS/eDP mode. */
  130. mode = DRM_MODE_SCALE_FULLSCREEN;
  131. }
  132. /* For the user-specified mode, we must ignore doublescan and
  133. * the like, but honor frame packing.
  134. */
  135. umode_vdisplay = umode->vdisplay;
  136. if ((umode->flags & DRM_MODE_FLAG_3D_MASK) == DRM_MODE_FLAG_3D_FRAME_PACKING)
  137. umode_vdisplay += umode->vtotal;
  138. asyh->view.iW = umode->hdisplay;
  139. asyh->view.iH = umode_vdisplay;
  140. /* For the output mode, we can just use the stock helper. */
  141. drm_mode_get_hv_timing(omode, &omode_hdisplay, &omode_vdisplay);
  142. asyh->view.oW = omode_hdisplay;
  143. asyh->view.oH = omode_vdisplay;
  144. /* Add overscan compensation if necessary, will keep the aspect
  145. * ratio the same as the backend mode unless overridden by the
  146. * user setting both hborder and vborder properties.
  147. */
  148. if ((asyc->scaler.underscan.mode == UNDERSCAN_ON ||
  149. (asyc->scaler.underscan.mode == UNDERSCAN_AUTO &&
  150. drm_detect_hdmi_monitor(edid)))) {
  151. u32 bX = asyc->scaler.underscan.hborder;
  152. u32 bY = asyc->scaler.underscan.vborder;
  153. u32 r = (asyh->view.oH << 19) / asyh->view.oW;
  154. if (bX) {
  155. asyh->view.oW -= (bX * 2);
  156. if (bY) asyh->view.oH -= (bY * 2);
  157. else asyh->view.oH = ((asyh->view.oW * r) + (r / 2)) >> 19;
  158. } else {
  159. asyh->view.oW -= (asyh->view.oW >> 4) + 32;
  160. if (bY) asyh->view.oH -= (bY * 2);
  161. else asyh->view.oH = ((asyh->view.oW * r) + (r / 2)) >> 19;
  162. }
  163. }
  164. /* Handle CENTER/ASPECT scaling, taking into account the areas
  165. * removed already for overscan compensation.
  166. */
  167. switch (mode) {
  168. case DRM_MODE_SCALE_CENTER:
  169. /* NOTE: This will cause scaling when the input is
  170. * larger than the output.
  171. */
  172. asyh->view.oW = min(asyh->view.iW, asyh->view.oW);
  173. asyh->view.oH = min(asyh->view.iH, asyh->view.oH);
  174. break;
  175. case DRM_MODE_SCALE_ASPECT:
  176. /* Determine whether the scaling should be on width or on
  177. * height. This is done by comparing the aspect ratios of the
  178. * sizes. If the output AR is larger than input AR, that means
  179. * we want to change the width (letterboxed on the
  180. * left/right), otherwise on the height (letterboxed on the
  181. * top/bottom).
  182. *
  183. * E.g. 4:3 (1.333) AR image displayed on a 16:10 (1.6) AR
  184. * screen will have letterboxes on the left/right. However a
  185. * 16:9 (1.777) AR image on that same screen will have
  186. * letterboxes on the top/bottom.
  187. *
  188. * inputAR = iW / iH; outputAR = oW / oH
  189. * outputAR > inputAR is equivalent to oW * iH > iW * oH
  190. */
  191. if (asyh->view.oW * asyh->view.iH > asyh->view.iW * asyh->view.oH) {
  192. /* Recompute output width, i.e. left/right letterbox */
  193. u32 r = (asyh->view.iW << 19) / asyh->view.iH;
  194. asyh->view.oW = ((asyh->view.oH * r) + (r / 2)) >> 19;
  195. } else {
  196. /* Recompute output height, i.e. top/bottom letterbox */
  197. u32 r = (asyh->view.iH << 19) / asyh->view.iW;
  198. asyh->view.oH = ((asyh->view.oW * r) + (r / 2)) >> 19;
  199. }
  200. break;
  201. default:
  202. break;
  203. }
  204. asyh->set.view = true;
  205. }
  206. static int
  207. nv50_head_atomic_check_lut(struct nv50_head *head,
  208. struct nv50_head_atom *asyh)
  209. {
  210. struct drm_device *dev = head->base.base.dev;
  211. struct drm_crtc *crtc = &head->base.base;
  212. struct nv50_disp *disp = nv50_disp(dev);
  213. struct nouveau_drm *drm = nouveau_drm(dev);
  214. struct drm_property_blob *olut = asyh->state.gamma_lut,
  215. *ilut = asyh->state.degamma_lut;
  216. int size;
  217. /* Ensure that the ilut is valid */
  218. if (ilut) {
  219. size = drm_color_lut_size(ilut);
  220. if (!head->func->ilut_check(size)) {
  221. NV_ATOMIC(drm, "Invalid size %d for degamma on [CRTC:%d:%s]\n",
  222. size, crtc->base.id, crtc->name);
  223. return -EINVAL;
  224. }
  225. }
  226. /* Determine whether core output LUT should be enabled. */
  227. if (olut) {
  228. /* Check if any window(s) have stolen the core output LUT
  229. * to as an input LUT for legacy gamma + I8 colour format.
  230. */
  231. if (asyh->wndw.olut) {
  232. /* If any window has stolen the core output LUT,
  233. * all of them must.
  234. */
  235. if (asyh->wndw.olut != asyh->wndw.mask)
  236. return -EINVAL;
  237. olut = NULL;
  238. }
  239. }
  240. if (!olut) {
  241. if (!head->func->olut_identity) {
  242. asyh->olut.handle = 0;
  243. return 0;
  244. }
  245. size = 0;
  246. } else {
  247. size = drm_color_lut_size(olut);
  248. }
  249. if (!head->func->olut(head, asyh, size)) {
  250. NV_ATOMIC(drm, "Invalid size %d for gamma on [CRTC:%d:%s]\n",
  251. size, crtc->base.id, crtc->name);
  252. return -EINVAL;
  253. }
  254. asyh->olut.handle = disp->core->chan.vram.handle;
  255. asyh->olut.buffer = !asyh->olut.buffer;
  256. return 0;
  257. }
  258. static void
  259. nv50_head_atomic_check_mode(struct nv50_head *head, struct nv50_head_atom *asyh)
  260. {
  261. struct drm_display_mode *mode = &asyh->state.adjusted_mode;
  262. struct nv50_head_mode *m = &asyh->mode;
  263. u32 blankus;
  264. drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V | CRTC_STEREO_DOUBLE);
  265. /*
  266. * DRM modes are defined in terms of a repeating interval
  267. * starting with the active display area. The hardware modes
  268. * are defined in terms of a repeating interval starting one
  269. * unit (pixel or line) into the sync pulse. So, add bias.
  270. */
  271. m->h.active = mode->crtc_htotal;
  272. m->h.synce = mode->crtc_hsync_end - mode->crtc_hsync_start - 1;
  273. m->h.blanke = mode->crtc_hblank_end - mode->crtc_hsync_start - 1;
  274. m->h.blanks = m->h.blanke + mode->crtc_hdisplay;
  275. m->v.active = mode->crtc_vtotal;
  276. m->v.synce = mode->crtc_vsync_end - mode->crtc_vsync_start - 1;
  277. m->v.blanke = mode->crtc_vblank_end - mode->crtc_vsync_start - 1;
  278. m->v.blanks = m->v.blanke + mode->crtc_vdisplay;
  279. /*XXX: Safe underestimate, even "0" works */
  280. blankus = (m->v.active - mode->crtc_vdisplay - 2) * m->h.active;
  281. blankus *= 1000;
  282. blankus /= mode->crtc_clock;
  283. m->v.blankus = blankus;
  284. if (mode->flags & DRM_MODE_FLAG_INTERLACE) {
  285. m->v.blank2e = m->v.active + m->v.blanke;
  286. m->v.blank2s = m->v.blank2e + mode->crtc_vdisplay;
  287. m->v.active = (m->v.active * 2) + 1;
  288. m->interlace = true;
  289. } else {
  290. m->v.blank2e = 0;
  291. m->v.blank2s = 1;
  292. m->interlace = false;
  293. }
  294. m->clock = mode->crtc_clock;
  295. asyh->or.nhsync = !!(mode->flags & DRM_MODE_FLAG_NHSYNC);
  296. asyh->or.nvsync = !!(mode->flags & DRM_MODE_FLAG_NVSYNC);
  297. asyh->set.or = head->func->or != NULL;
  298. asyh->set.mode = true;
  299. }
  300. static int
  301. nv50_head_atomic_check(struct drm_crtc *crtc, struct drm_atomic_state *state)
  302. {
  303. struct drm_crtc_state *old_crtc_state = drm_atomic_get_old_crtc_state(state,
  304. crtc);
  305. struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state,
  306. crtc);
  307. struct nouveau_drm *drm = nouveau_drm(crtc->dev);
  308. struct nv50_head *head = nv50_head(crtc);
  309. struct nv50_head_atom *armh = nv50_head_atom(old_crtc_state);
  310. struct nv50_head_atom *asyh = nv50_head_atom(crtc_state);
  311. struct nouveau_conn_atom *asyc = NULL;
  312. struct drm_connector_state *conns;
  313. struct drm_connector *conn;
  314. int i, ret;
  315. bool check_lut = asyh->state.color_mgmt_changed ||
  316. memcmp(&armh->wndw, &asyh->wndw, sizeof(asyh->wndw));
  317. NV_ATOMIC(drm, "%s atomic_check %d\n", crtc->name, asyh->state.active);
  318. if (check_lut) {
  319. ret = nv50_head_atomic_check_lut(head, asyh);
  320. if (ret)
  321. return ret;
  322. }
  323. if (asyh->state.active) {
  324. for_each_new_connector_in_state(asyh->state.state, conn, conns, i) {
  325. if (conns->crtc == crtc) {
  326. asyc = nouveau_conn_atom(conns);
  327. break;
  328. }
  329. }
  330. if (armh->state.active) {
  331. if (asyc) {
  332. if (asyh->state.mode_changed)
  333. asyc->set.scaler = true;
  334. if (armh->base.depth != asyh->base.depth)
  335. asyc->set.dither = true;
  336. }
  337. } else {
  338. if (asyc)
  339. asyc->set.mask = ~0;
  340. asyh->set.mask = ~0;
  341. asyh->set.or = head->func->or != NULL;
  342. }
  343. if (asyh->state.mode_changed || asyh->state.connectors_changed)
  344. nv50_head_atomic_check_mode(head, asyh);
  345. if (check_lut)
  346. asyh->olut.visible = asyh->olut.handle != 0;
  347. if (asyc) {
  348. if (asyc->set.scaler)
  349. nv50_head_atomic_check_view(armh, asyh, asyc);
  350. if (asyc->set.dither)
  351. nv50_head_atomic_check_dither(armh, asyh, asyc);
  352. if (asyc->set.procamp)
  353. nv50_head_atomic_check_procamp(armh, asyh, asyc);
  354. }
  355. if (head->func->core_calc) {
  356. head->func->core_calc(head, asyh);
  357. if (!asyh->core.visible)
  358. asyh->olut.visible = false;
  359. }
  360. asyh->set.base = armh->base.cpp != asyh->base.cpp;
  361. asyh->set.ovly = armh->ovly.cpp != asyh->ovly.cpp;
  362. } else {
  363. asyh->olut.visible = false;
  364. asyh->core.visible = false;
  365. asyh->curs.visible = false;
  366. asyh->base.cpp = 0;
  367. asyh->ovly.cpp = 0;
  368. }
  369. if (!drm_atomic_crtc_needs_modeset(&asyh->state)) {
  370. if (asyh->core.visible) {
  371. if (memcmp(&armh->core, &asyh->core, sizeof(asyh->core)))
  372. asyh->set.core = true;
  373. } else
  374. if (armh->core.visible) {
  375. asyh->clr.core = true;
  376. }
  377. if (asyh->curs.visible) {
  378. if (memcmp(&armh->curs, &asyh->curs, sizeof(asyh->curs)))
  379. asyh->set.curs = true;
  380. } else
  381. if (armh->curs.visible) {
  382. asyh->clr.curs = true;
  383. }
  384. if (asyh->olut.visible) {
  385. if (memcmp(&armh->olut, &asyh->olut, sizeof(asyh->olut)))
  386. asyh->set.olut = true;
  387. } else
  388. if (armh->olut.visible) {
  389. asyh->clr.olut = true;
  390. }
  391. } else {
  392. asyh->clr.olut = armh->olut.visible;
  393. asyh->clr.core = armh->core.visible;
  394. asyh->clr.curs = armh->curs.visible;
  395. asyh->set.olut = asyh->olut.visible;
  396. asyh->set.core = asyh->core.visible;
  397. asyh->set.curs = asyh->curs.visible;
  398. }
  399. ret = nv50_crc_atomic_check_head(head, asyh, armh);
  400. if (ret)
  401. return ret;
  402. if (asyh->clr.mask || asyh->set.mask)
  403. nv50_atom(asyh->state.state)->lock_core = true;
  404. return 0;
  405. }
  406. static const struct drm_crtc_helper_funcs
  407. nv50_head_help = {
  408. .atomic_check = nv50_head_atomic_check,
  409. .get_scanout_position = nouveau_display_scanoutpos,
  410. };
  411. static void
  412. nv50_head_atomic_destroy_state(struct drm_crtc *crtc,
  413. struct drm_crtc_state *state)
  414. {
  415. struct nv50_head_atom *asyh = nv50_head_atom(state);
  416. __drm_atomic_helper_crtc_destroy_state(&asyh->state);
  417. kfree(asyh);
  418. }
  419. static struct drm_crtc_state *
  420. nv50_head_atomic_duplicate_state(struct drm_crtc *crtc)
  421. {
  422. struct nv50_head_atom *armh = nv50_head_atom(crtc->state);
  423. struct nv50_head_atom *asyh;
  424. if (!(asyh = kmalloc(sizeof(*asyh), GFP_KERNEL)))
  425. return NULL;
  426. __drm_atomic_helper_crtc_duplicate_state(crtc, &asyh->state);
  427. asyh->wndw = armh->wndw;
  428. asyh->view = armh->view;
  429. asyh->mode = armh->mode;
  430. asyh->olut = armh->olut;
  431. asyh->core = armh->core;
  432. asyh->curs = armh->curs;
  433. asyh->base = armh->base;
  434. asyh->ovly = armh->ovly;
  435. asyh->dither = armh->dither;
  436. asyh->procamp = armh->procamp;
  437. asyh->crc = armh->crc;
  438. asyh->or = armh->or;
  439. asyh->dp = armh->dp;
  440. asyh->clr.mask = 0;
  441. asyh->set.mask = 0;
  442. return &asyh->state;
  443. }
  444. static void
  445. nv50_head_reset(struct drm_crtc *crtc)
  446. {
  447. struct nv50_head_atom *asyh;
  448. if (WARN_ON(!(asyh = kzalloc(sizeof(*asyh), GFP_KERNEL))))
  449. return;
  450. if (crtc->state)
  451. nv50_head_atomic_destroy_state(crtc, crtc->state);
  452. __drm_atomic_helper_crtc_reset(crtc, &asyh->state);
  453. }
  454. static int
  455. nv50_head_late_register(struct drm_crtc *crtc)
  456. {
  457. return nv50_head_crc_late_register(nv50_head(crtc));
  458. }
  459. static void
  460. nv50_head_destroy(struct drm_crtc *crtc)
  461. {
  462. struct nv50_head *head = nv50_head(crtc);
  463. nvif_notify_dtor(&head->base.vblank);
  464. nv50_lut_fini(&head->olut);
  465. drm_crtc_cleanup(crtc);
  466. kfree(head);
  467. }
  468. static const struct drm_crtc_funcs
  469. nv50_head_func = {
  470. .reset = nv50_head_reset,
  471. .destroy = nv50_head_destroy,
  472. .set_config = drm_atomic_helper_set_config,
  473. .page_flip = drm_atomic_helper_page_flip,
  474. .atomic_duplicate_state = nv50_head_atomic_duplicate_state,
  475. .atomic_destroy_state = nv50_head_atomic_destroy_state,
  476. .enable_vblank = nouveau_display_vblank_enable,
  477. .disable_vblank = nouveau_display_vblank_disable,
  478. .get_vblank_timestamp = drm_crtc_vblank_helper_get_vblank_timestamp,
  479. .late_register = nv50_head_late_register,
  480. };
  481. static const struct drm_crtc_funcs
  482. nvd9_head_func = {
  483. .reset = nv50_head_reset,
  484. .destroy = nv50_head_destroy,
  485. .set_config = drm_atomic_helper_set_config,
  486. .page_flip = drm_atomic_helper_page_flip,
  487. .atomic_duplicate_state = nv50_head_atomic_duplicate_state,
  488. .atomic_destroy_state = nv50_head_atomic_destroy_state,
  489. .enable_vblank = nouveau_display_vblank_enable,
  490. .disable_vblank = nouveau_display_vblank_disable,
  491. .get_vblank_timestamp = drm_crtc_vblank_helper_get_vblank_timestamp,
  492. .verify_crc_source = nv50_crc_verify_source,
  493. .get_crc_sources = nv50_crc_get_sources,
  494. .set_crc_source = nv50_crc_set_source,
  495. .late_register = nv50_head_late_register,
  496. };
  497. static int nv50_head_vblank_handler(struct nvif_notify *notify)
  498. {
  499. struct nouveau_crtc *nv_crtc =
  500. container_of(notify, struct nouveau_crtc, vblank);
  501. if (drm_crtc_handle_vblank(&nv_crtc->base))
  502. nv50_crc_handle_vblank(nv50_head(&nv_crtc->base));
  503. return NVIF_NOTIFY_KEEP;
  504. }
  505. struct nv50_head *
  506. nv50_head_create(struct drm_device *dev, int index)
  507. {
  508. struct nouveau_drm *drm = nouveau_drm(dev);
  509. struct nv50_disp *disp = nv50_disp(dev);
  510. struct nv50_head *head;
  511. struct nv50_wndw *base, *ovly, *curs;
  512. struct nouveau_crtc *nv_crtc;
  513. struct drm_crtc *crtc;
  514. const struct drm_crtc_funcs *funcs;
  515. int ret;
  516. head = kzalloc(sizeof(*head), GFP_KERNEL);
  517. if (!head)
  518. return ERR_PTR(-ENOMEM);
  519. head->func = disp->core->func->head;
  520. head->base.index = index;
  521. if (disp->disp->object.oclass < GF110_DISP)
  522. funcs = &nv50_head_func;
  523. else
  524. funcs = &nvd9_head_func;
  525. if (disp->disp->object.oclass < GV100_DISP) {
  526. ret = nv50_base_new(drm, head->base.index, &base);
  527. ret = nv50_ovly_new(drm, head->base.index, &ovly);
  528. } else {
  529. ret = nv50_wndw_new(drm, DRM_PLANE_TYPE_PRIMARY,
  530. head->base.index * 2 + 0, &base);
  531. ret = nv50_wndw_new(drm, DRM_PLANE_TYPE_OVERLAY,
  532. head->base.index * 2 + 1, &ovly);
  533. }
  534. if (ret == 0)
  535. ret = nv50_curs_new(drm, head->base.index, &curs);
  536. if (ret) {
  537. kfree(head);
  538. return ERR_PTR(ret);
  539. }
  540. nv_crtc = &head->base;
  541. crtc = &nv_crtc->base;
  542. drm_crtc_init_with_planes(dev, crtc, &base->plane, &curs->plane,
  543. funcs, "head-%d", head->base.index);
  544. drm_crtc_helper_add(crtc, &nv50_head_help);
  545. /* Keep the legacy gamma size at 256 to avoid compatibility issues */
  546. drm_mode_crtc_set_gamma_size(crtc, 256);
  547. drm_crtc_enable_color_mgmt(crtc, base->func->ilut_size,
  548. disp->disp->object.oclass >= GF110_DISP,
  549. head->func->olut_size);
  550. if (head->func->olut_set) {
  551. ret = nv50_lut_init(disp, &drm->client.mmu, &head->olut);
  552. if (ret) {
  553. nv50_head_destroy(crtc);
  554. return ERR_PTR(ret);
  555. }
  556. }
  557. ret = nvif_notify_ctor(&disp->disp->object, "kmsVbl", nv50_head_vblank_handler,
  558. false, NV04_DISP_NTFY_VBLANK,
  559. &(struct nvif_notify_head_req_v0) {
  560. .head = nv_crtc->index,
  561. },
  562. sizeof(struct nvif_notify_head_req_v0),
  563. sizeof(struct nvif_notify_head_rep_v0),
  564. &nv_crtc->vblank);
  565. if (ret)
  566. return ERR_PTR(ret);
  567. return head;
  568. }