plane.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482
  1. /*
  2. * Copyright (C) 2017 NVIDIA CORPORATION. All rights reserved.
  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. #include <drm/drm_atomic.h>
  9. #include <drm/drm_atomic_helper.h>
  10. #include <drm/drm_plane_helper.h>
  11. #include "dc.h"
  12. #include "plane.h"
  13. static void tegra_plane_destroy(struct drm_plane *plane)
  14. {
  15. struct tegra_plane *p = to_tegra_plane(plane);
  16. drm_plane_cleanup(plane);
  17. kfree(p);
  18. }
  19. static void tegra_plane_reset(struct drm_plane *plane)
  20. {
  21. struct tegra_plane *p = to_tegra_plane(plane);
  22. struct tegra_plane_state *state;
  23. if (plane->state)
  24. __drm_atomic_helper_plane_destroy_state(plane->state);
  25. kfree(plane->state);
  26. plane->state = NULL;
  27. state = kzalloc(sizeof(*state), GFP_KERNEL);
  28. if (state) {
  29. plane->state = &state->base;
  30. plane->state->plane = plane;
  31. plane->state->zpos = p->index;
  32. plane->state->normalized_zpos = p->index;
  33. }
  34. }
  35. static struct drm_plane_state *
  36. tegra_plane_atomic_duplicate_state(struct drm_plane *plane)
  37. {
  38. struct tegra_plane_state *state = to_tegra_plane_state(plane->state);
  39. struct tegra_plane_state *copy;
  40. unsigned int i;
  41. copy = kmalloc(sizeof(*copy), GFP_KERNEL);
  42. if (!copy)
  43. return NULL;
  44. __drm_atomic_helper_plane_duplicate_state(plane, &copy->base);
  45. copy->tiling = state->tiling;
  46. copy->format = state->format;
  47. copy->swap = state->swap;
  48. copy->bottom_up = state->bottom_up;
  49. copy->opaque = state->opaque;
  50. for (i = 0; i < 2; i++)
  51. copy->blending[i] = state->blending[i];
  52. return &copy->base;
  53. }
  54. static void tegra_plane_atomic_destroy_state(struct drm_plane *plane,
  55. struct drm_plane_state *state)
  56. {
  57. __drm_atomic_helper_plane_destroy_state(state);
  58. kfree(state);
  59. }
  60. static bool tegra_plane_format_mod_supported(struct drm_plane *plane,
  61. uint32_t format,
  62. uint64_t modifier)
  63. {
  64. const struct drm_format_info *info = drm_format_info(format);
  65. if (modifier == DRM_FORMAT_MOD_LINEAR)
  66. return true;
  67. if (info->num_planes == 1)
  68. return true;
  69. return false;
  70. }
  71. const struct drm_plane_funcs tegra_plane_funcs = {
  72. .update_plane = drm_atomic_helper_update_plane,
  73. .disable_plane = drm_atomic_helper_disable_plane,
  74. .destroy = tegra_plane_destroy,
  75. .reset = tegra_plane_reset,
  76. .atomic_duplicate_state = tegra_plane_atomic_duplicate_state,
  77. .atomic_destroy_state = tegra_plane_atomic_destroy_state,
  78. .format_mod_supported = tegra_plane_format_mod_supported,
  79. };
  80. int tegra_plane_state_add(struct tegra_plane *plane,
  81. struct drm_plane_state *state)
  82. {
  83. struct drm_crtc_state *crtc_state;
  84. struct tegra_dc_state *tegra;
  85. int err;
  86. /* Propagate errors from allocation or locking failures. */
  87. crtc_state = drm_atomic_get_crtc_state(state->state, state->crtc);
  88. if (IS_ERR(crtc_state))
  89. return PTR_ERR(crtc_state);
  90. /* Check plane state for visibility and calculate clipping bounds */
  91. err = drm_atomic_helper_check_plane_state(state, crtc_state,
  92. 0, INT_MAX, true, true);
  93. if (err < 0)
  94. return err;
  95. tegra = to_dc_state(crtc_state);
  96. tegra->planes |= WIN_A_ACT_REQ << plane->index;
  97. return 0;
  98. }
  99. int tegra_plane_format(u32 fourcc, u32 *format, u32 *swap)
  100. {
  101. /* assume no swapping of fetched data */
  102. if (swap)
  103. *swap = BYTE_SWAP_NOSWAP;
  104. switch (fourcc) {
  105. case DRM_FORMAT_ARGB4444:
  106. *format = WIN_COLOR_DEPTH_B4G4R4A4;
  107. break;
  108. case DRM_FORMAT_ARGB1555:
  109. *format = WIN_COLOR_DEPTH_B5G5R5A1;
  110. break;
  111. case DRM_FORMAT_RGB565:
  112. *format = WIN_COLOR_DEPTH_B5G6R5;
  113. break;
  114. case DRM_FORMAT_RGBA5551:
  115. *format = WIN_COLOR_DEPTH_A1B5G5R5;
  116. break;
  117. case DRM_FORMAT_ARGB8888:
  118. *format = WIN_COLOR_DEPTH_B8G8R8A8;
  119. break;
  120. case DRM_FORMAT_ABGR8888:
  121. *format = WIN_COLOR_DEPTH_R8G8B8A8;
  122. break;
  123. case DRM_FORMAT_ABGR4444:
  124. *format = WIN_COLOR_DEPTH_R4G4B4A4;
  125. break;
  126. case DRM_FORMAT_ABGR1555:
  127. *format = WIN_COLOR_DEPTH_R5G5B5A;
  128. break;
  129. case DRM_FORMAT_BGRA5551:
  130. *format = WIN_COLOR_DEPTH_AR5G5B5;
  131. break;
  132. case DRM_FORMAT_XRGB1555:
  133. *format = WIN_COLOR_DEPTH_B5G5R5X1;
  134. break;
  135. case DRM_FORMAT_RGBX5551:
  136. *format = WIN_COLOR_DEPTH_X1B5G5R5;
  137. break;
  138. case DRM_FORMAT_XBGR1555:
  139. *format = WIN_COLOR_DEPTH_R5G5B5X1;
  140. break;
  141. case DRM_FORMAT_BGRX5551:
  142. *format = WIN_COLOR_DEPTH_X1R5G5B5;
  143. break;
  144. case DRM_FORMAT_BGR565:
  145. *format = WIN_COLOR_DEPTH_R5G6B5;
  146. break;
  147. case DRM_FORMAT_BGRA8888:
  148. *format = WIN_COLOR_DEPTH_A8R8G8B8;
  149. break;
  150. case DRM_FORMAT_RGBA8888:
  151. *format = WIN_COLOR_DEPTH_A8B8G8R8;
  152. break;
  153. case DRM_FORMAT_XRGB8888:
  154. *format = WIN_COLOR_DEPTH_B8G8R8X8;
  155. break;
  156. case DRM_FORMAT_XBGR8888:
  157. *format = WIN_COLOR_DEPTH_R8G8B8X8;
  158. break;
  159. case DRM_FORMAT_UYVY:
  160. *format = WIN_COLOR_DEPTH_YCbCr422;
  161. break;
  162. case DRM_FORMAT_YUYV:
  163. if (!swap)
  164. return -EINVAL;
  165. *format = WIN_COLOR_DEPTH_YCbCr422;
  166. *swap = BYTE_SWAP_SWAP2;
  167. break;
  168. case DRM_FORMAT_YUV420:
  169. *format = WIN_COLOR_DEPTH_YCbCr420P;
  170. break;
  171. case DRM_FORMAT_YUV422:
  172. *format = WIN_COLOR_DEPTH_YCbCr422P;
  173. break;
  174. default:
  175. return -EINVAL;
  176. }
  177. return 0;
  178. }
  179. bool tegra_plane_format_is_yuv(unsigned int format, bool *planar)
  180. {
  181. switch (format) {
  182. case WIN_COLOR_DEPTH_YCbCr422:
  183. case WIN_COLOR_DEPTH_YUV422:
  184. if (planar)
  185. *planar = false;
  186. return true;
  187. case WIN_COLOR_DEPTH_YCbCr420P:
  188. case WIN_COLOR_DEPTH_YUV420P:
  189. case WIN_COLOR_DEPTH_YCbCr422P:
  190. case WIN_COLOR_DEPTH_YUV422P:
  191. case WIN_COLOR_DEPTH_YCbCr422R:
  192. case WIN_COLOR_DEPTH_YUV422R:
  193. case WIN_COLOR_DEPTH_YCbCr422RA:
  194. case WIN_COLOR_DEPTH_YUV422RA:
  195. if (planar)
  196. *planar = true;
  197. return true;
  198. }
  199. if (planar)
  200. *planar = false;
  201. return false;
  202. }
  203. static bool __drm_format_has_alpha(u32 format)
  204. {
  205. switch (format) {
  206. case DRM_FORMAT_ARGB1555:
  207. case DRM_FORMAT_RGBA5551:
  208. case DRM_FORMAT_ABGR8888:
  209. case DRM_FORMAT_ARGB8888:
  210. return true;
  211. }
  212. return false;
  213. }
  214. static int tegra_plane_format_get_alpha(unsigned int opaque,
  215. unsigned int *alpha)
  216. {
  217. if (tegra_plane_format_is_yuv(opaque, NULL)) {
  218. *alpha = opaque;
  219. return 0;
  220. }
  221. switch (opaque) {
  222. case WIN_COLOR_DEPTH_B5G5R5X1:
  223. *alpha = WIN_COLOR_DEPTH_B5G5R5A1;
  224. return 0;
  225. case WIN_COLOR_DEPTH_X1B5G5R5:
  226. *alpha = WIN_COLOR_DEPTH_A1B5G5R5;
  227. return 0;
  228. case WIN_COLOR_DEPTH_R8G8B8X8:
  229. *alpha = WIN_COLOR_DEPTH_R8G8B8A8;
  230. return 0;
  231. case WIN_COLOR_DEPTH_B8G8R8X8:
  232. *alpha = WIN_COLOR_DEPTH_B8G8R8A8;
  233. return 0;
  234. case WIN_COLOR_DEPTH_B5G6R5:
  235. *alpha = opaque;
  236. return 0;
  237. }
  238. return -EINVAL;
  239. }
  240. /*
  241. * This is applicable to Tegra20 and Tegra30 only where the opaque formats can
  242. * be emulated using the alpha formats and alpha blending disabled.
  243. */
  244. static int tegra_plane_setup_opacity(struct tegra_plane *tegra,
  245. struct tegra_plane_state *state)
  246. {
  247. unsigned int format;
  248. int err;
  249. switch (state->format) {
  250. case WIN_COLOR_DEPTH_B5G5R5A1:
  251. case WIN_COLOR_DEPTH_A1B5G5R5:
  252. case WIN_COLOR_DEPTH_R8G8B8A8:
  253. case WIN_COLOR_DEPTH_B8G8R8A8:
  254. state->opaque = false;
  255. break;
  256. default:
  257. err = tegra_plane_format_get_alpha(state->format, &format);
  258. if (err < 0)
  259. return err;
  260. state->format = format;
  261. state->opaque = true;
  262. break;
  263. }
  264. return 0;
  265. }
  266. static int tegra_plane_check_transparency(struct tegra_plane *tegra,
  267. struct tegra_plane_state *state)
  268. {
  269. struct drm_plane_state *old, *plane_state;
  270. struct drm_plane *plane;
  271. old = drm_atomic_get_old_plane_state(state->base.state, &tegra->base);
  272. /* check if zpos / transparency changed */
  273. if (old->normalized_zpos == state->base.normalized_zpos &&
  274. to_tegra_plane_state(old)->opaque == state->opaque)
  275. return 0;
  276. /* include all sibling planes into this commit */
  277. drm_for_each_plane(plane, tegra->base.dev) {
  278. struct tegra_plane *p = to_tegra_plane(plane);
  279. /* skip this plane and planes on different CRTCs */
  280. if (p == tegra || p->dc != tegra->dc)
  281. continue;
  282. plane_state = drm_atomic_get_plane_state(state->base.state,
  283. plane);
  284. if (IS_ERR(plane_state))
  285. return PTR_ERR(plane_state);
  286. }
  287. return 1;
  288. }
  289. static unsigned int tegra_plane_get_overlap_index(struct tegra_plane *plane,
  290. struct tegra_plane *other)
  291. {
  292. unsigned int index = 0, i;
  293. WARN_ON(plane == other);
  294. for (i = 0; i < 3; i++) {
  295. if (i == plane->index)
  296. continue;
  297. if (i == other->index)
  298. break;
  299. index++;
  300. }
  301. return index;
  302. }
  303. static void tegra_plane_update_transparency(struct tegra_plane *tegra,
  304. struct tegra_plane_state *state)
  305. {
  306. struct drm_plane_state *new;
  307. struct drm_plane *plane;
  308. unsigned int i;
  309. for_each_new_plane_in_state(state->base.state, plane, new, i) {
  310. struct tegra_plane *p = to_tegra_plane(plane);
  311. unsigned index;
  312. /* skip this plane and planes on different CRTCs */
  313. if (p == tegra || p->dc != tegra->dc)
  314. continue;
  315. index = tegra_plane_get_overlap_index(tegra, p);
  316. if (new->fb && __drm_format_has_alpha(new->fb->format->format))
  317. state->blending[index].alpha = true;
  318. else
  319. state->blending[index].alpha = false;
  320. if (new->normalized_zpos > state->base.normalized_zpos)
  321. state->blending[index].top = true;
  322. else
  323. state->blending[index].top = false;
  324. /*
  325. * Missing framebuffer means that plane is disabled, in this
  326. * case mark B / C window as top to be able to differentiate
  327. * windows indices order in regards to zPos for the middle
  328. * window X / Y registers programming.
  329. */
  330. if (!new->fb)
  331. state->blending[index].top = (index == 1);
  332. }
  333. }
  334. static int tegra_plane_setup_transparency(struct tegra_plane *tegra,
  335. struct tegra_plane_state *state)
  336. {
  337. struct tegra_plane_state *tegra_state;
  338. struct drm_plane_state *new;
  339. struct drm_plane *plane;
  340. int err;
  341. /*
  342. * If planes zpos / transparency changed, sibling planes blending
  343. * state may require adjustment and in this case they will be included
  344. * into this atom commit, otherwise blending state is unchanged.
  345. */
  346. err = tegra_plane_check_transparency(tegra, state);
  347. if (err <= 0)
  348. return err;
  349. /*
  350. * All planes are now in the atomic state, walk them up and update
  351. * transparency state for each plane.
  352. */
  353. drm_for_each_plane(plane, tegra->base.dev) {
  354. struct tegra_plane *p = to_tegra_plane(plane);
  355. /* skip planes on different CRTCs */
  356. if (p->dc != tegra->dc)
  357. continue;
  358. new = drm_atomic_get_new_plane_state(state->base.state, plane);
  359. tegra_state = to_tegra_plane_state(new);
  360. /*
  361. * There is no need to update blending state for the disabled
  362. * plane.
  363. */
  364. if (new->fb)
  365. tegra_plane_update_transparency(p, tegra_state);
  366. }
  367. return 0;
  368. }
  369. int tegra_plane_setup_legacy_state(struct tegra_plane *tegra,
  370. struct tegra_plane_state *state)
  371. {
  372. int err;
  373. err = tegra_plane_setup_opacity(tegra, state);
  374. if (err < 0)
  375. return err;
  376. err = tegra_plane_setup_transparency(tegra, state);
  377. if (err < 0)
  378. return err;
  379. return 0;
  380. }