atmel_hlcdc_plane.c 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140
  1. /*
  2. * Copyright (C) 2014 Free Electrons
  3. * Copyright (C) 2014 Atmel
  4. *
  5. * Author: Boris BREZILLON <boris.brezillon@free-electrons.com>
  6. *
  7. * This program is free software; you can redistribute it and/or modify it
  8. * under the terms of the GNU General Public License version 2 as published by
  9. * the Free Software Foundation.
  10. *
  11. * This program is distributed in the hope that it will be useful, but WITHOUT
  12. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13. * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
  14. * more details.
  15. *
  16. * You should have received a copy of the GNU General Public License along with
  17. * this program. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. #include "atmel_hlcdc_dc.h"
  20. /**
  21. * Atmel HLCDC Plane state structure.
  22. *
  23. * @base: DRM plane state
  24. * @crtc_x: x position of the plane relative to the CRTC
  25. * @crtc_y: y position of the plane relative to the CRTC
  26. * @crtc_w: visible width of the plane
  27. * @crtc_h: visible height of the plane
  28. * @src_x: x buffer position
  29. * @src_y: y buffer position
  30. * @src_w: buffer width
  31. * @src_h: buffer height
  32. * @alpha: alpha blending of the plane
  33. * @bpp: bytes per pixel deduced from pixel_format
  34. * @offsets: offsets to apply to the GEM buffers
  35. * @xstride: value to add to the pixel pointer between each line
  36. * @pstride: value to add to the pixel pointer between each pixel
  37. * @nplanes: number of planes (deduced from pixel_format)
  38. * @prepared: plane update has been prepared
  39. */
  40. struct atmel_hlcdc_plane_state {
  41. struct drm_plane_state base;
  42. int crtc_x;
  43. int crtc_y;
  44. unsigned int crtc_w;
  45. unsigned int crtc_h;
  46. uint32_t src_x;
  47. uint32_t src_y;
  48. uint32_t src_w;
  49. uint32_t src_h;
  50. u8 alpha;
  51. bool disc_updated;
  52. int disc_x;
  53. int disc_y;
  54. int disc_w;
  55. int disc_h;
  56. int ahb_id;
  57. /* These fields are private and should not be touched */
  58. int bpp[ATMEL_HLCDC_MAX_PLANES];
  59. unsigned int offsets[ATMEL_HLCDC_MAX_PLANES];
  60. int xstride[ATMEL_HLCDC_MAX_PLANES];
  61. int pstride[ATMEL_HLCDC_MAX_PLANES];
  62. int nplanes;
  63. bool prepared;
  64. };
  65. static inline struct atmel_hlcdc_plane_state *
  66. drm_plane_state_to_atmel_hlcdc_plane_state(struct drm_plane_state *s)
  67. {
  68. return container_of(s, struct atmel_hlcdc_plane_state, base);
  69. }
  70. #define SUBPIXEL_MASK 0xffff
  71. static uint32_t rgb_formats[] = {
  72. DRM_FORMAT_XRGB4444,
  73. DRM_FORMAT_ARGB4444,
  74. DRM_FORMAT_RGBA4444,
  75. DRM_FORMAT_ARGB1555,
  76. DRM_FORMAT_RGB565,
  77. DRM_FORMAT_RGB888,
  78. DRM_FORMAT_XRGB8888,
  79. DRM_FORMAT_ARGB8888,
  80. DRM_FORMAT_RGBA8888,
  81. };
  82. struct atmel_hlcdc_formats atmel_hlcdc_plane_rgb_formats = {
  83. .formats = rgb_formats,
  84. .nformats = ARRAY_SIZE(rgb_formats),
  85. };
  86. static uint32_t rgb_and_yuv_formats[] = {
  87. DRM_FORMAT_XRGB4444,
  88. DRM_FORMAT_ARGB4444,
  89. DRM_FORMAT_RGBA4444,
  90. DRM_FORMAT_ARGB1555,
  91. DRM_FORMAT_RGB565,
  92. DRM_FORMAT_RGB888,
  93. DRM_FORMAT_XRGB8888,
  94. DRM_FORMAT_ARGB8888,
  95. DRM_FORMAT_RGBA8888,
  96. DRM_FORMAT_AYUV,
  97. DRM_FORMAT_YUYV,
  98. DRM_FORMAT_UYVY,
  99. DRM_FORMAT_YVYU,
  100. DRM_FORMAT_VYUY,
  101. DRM_FORMAT_NV21,
  102. DRM_FORMAT_NV61,
  103. DRM_FORMAT_YUV422,
  104. DRM_FORMAT_YUV420,
  105. };
  106. struct atmel_hlcdc_formats atmel_hlcdc_plane_rgb_and_yuv_formats = {
  107. .formats = rgb_and_yuv_formats,
  108. .nformats = ARRAY_SIZE(rgb_and_yuv_formats),
  109. };
  110. static int atmel_hlcdc_format_to_plane_mode(u32 format, u32 *mode)
  111. {
  112. switch (format) {
  113. case DRM_FORMAT_XRGB4444:
  114. *mode = ATMEL_HLCDC_XRGB4444_MODE;
  115. break;
  116. case DRM_FORMAT_ARGB4444:
  117. *mode = ATMEL_HLCDC_ARGB4444_MODE;
  118. break;
  119. case DRM_FORMAT_RGBA4444:
  120. *mode = ATMEL_HLCDC_RGBA4444_MODE;
  121. break;
  122. case DRM_FORMAT_RGB565:
  123. *mode = ATMEL_HLCDC_RGB565_MODE;
  124. break;
  125. case DRM_FORMAT_RGB888:
  126. *mode = ATMEL_HLCDC_RGB888_MODE;
  127. break;
  128. case DRM_FORMAT_ARGB1555:
  129. *mode = ATMEL_HLCDC_ARGB1555_MODE;
  130. break;
  131. case DRM_FORMAT_XRGB8888:
  132. *mode = ATMEL_HLCDC_XRGB8888_MODE;
  133. break;
  134. case DRM_FORMAT_ARGB8888:
  135. *mode = ATMEL_HLCDC_ARGB8888_MODE;
  136. break;
  137. case DRM_FORMAT_RGBA8888:
  138. *mode = ATMEL_HLCDC_RGBA8888_MODE;
  139. break;
  140. case DRM_FORMAT_AYUV:
  141. *mode = ATMEL_HLCDC_AYUV_MODE;
  142. break;
  143. case DRM_FORMAT_YUYV:
  144. *mode = ATMEL_HLCDC_YUYV_MODE;
  145. break;
  146. case DRM_FORMAT_UYVY:
  147. *mode = ATMEL_HLCDC_UYVY_MODE;
  148. break;
  149. case DRM_FORMAT_YVYU:
  150. *mode = ATMEL_HLCDC_YVYU_MODE;
  151. break;
  152. case DRM_FORMAT_VYUY:
  153. *mode = ATMEL_HLCDC_VYUY_MODE;
  154. break;
  155. case DRM_FORMAT_NV21:
  156. *mode = ATMEL_HLCDC_NV21_MODE;
  157. break;
  158. case DRM_FORMAT_NV61:
  159. *mode = ATMEL_HLCDC_NV61_MODE;
  160. break;
  161. case DRM_FORMAT_YUV420:
  162. *mode = ATMEL_HLCDC_YUV420_MODE;
  163. break;
  164. case DRM_FORMAT_YUV422:
  165. *mode = ATMEL_HLCDC_YUV422_MODE;
  166. break;
  167. default:
  168. return -ENOTSUPP;
  169. }
  170. return 0;
  171. }
  172. static bool atmel_hlcdc_format_embeds_alpha(u32 format)
  173. {
  174. int i;
  175. for (i = 0; i < sizeof(format); i++) {
  176. char tmp = (format >> (8 * i)) & 0xff;
  177. if (tmp == 'A')
  178. return true;
  179. }
  180. return false;
  181. }
  182. static u32 heo_downscaling_xcoef[] = {
  183. 0x11343311,
  184. 0x000000f7,
  185. 0x1635300c,
  186. 0x000000f9,
  187. 0x1b362c08,
  188. 0x000000fb,
  189. 0x1f372804,
  190. 0x000000fe,
  191. 0x24382400,
  192. 0x00000000,
  193. 0x28371ffe,
  194. 0x00000004,
  195. 0x2c361bfb,
  196. 0x00000008,
  197. 0x303516f9,
  198. 0x0000000c,
  199. };
  200. static u32 heo_downscaling_ycoef[] = {
  201. 0x00123737,
  202. 0x00173732,
  203. 0x001b382d,
  204. 0x001f3928,
  205. 0x00243824,
  206. 0x0028391f,
  207. 0x002d381b,
  208. 0x00323717,
  209. };
  210. static u32 heo_upscaling_xcoef[] = {
  211. 0xf74949f7,
  212. 0x00000000,
  213. 0xf55f33fb,
  214. 0x000000fe,
  215. 0xf5701efe,
  216. 0x000000ff,
  217. 0xf87c0dff,
  218. 0x00000000,
  219. 0x00800000,
  220. 0x00000000,
  221. 0x0d7cf800,
  222. 0x000000ff,
  223. 0x1e70f5ff,
  224. 0x000000fe,
  225. 0x335ff5fe,
  226. 0x000000fb,
  227. };
  228. static u32 heo_upscaling_ycoef[] = {
  229. 0x00004040,
  230. 0x00075920,
  231. 0x00056f0c,
  232. 0x00027b03,
  233. 0x00008000,
  234. 0x00037b02,
  235. 0x000c6f05,
  236. 0x00205907,
  237. };
  238. static void
  239. atmel_hlcdc_plane_update_pos_and_size(struct atmel_hlcdc_plane *plane,
  240. struct atmel_hlcdc_plane_state *state)
  241. {
  242. const struct atmel_hlcdc_layer_cfg_layout *layout =
  243. &plane->layer.desc->layout;
  244. if (layout->size)
  245. atmel_hlcdc_layer_update_cfg(&plane->layer,
  246. layout->size,
  247. 0xffffffff,
  248. (state->crtc_w - 1) |
  249. ((state->crtc_h - 1) << 16));
  250. if (layout->memsize)
  251. atmel_hlcdc_layer_update_cfg(&plane->layer,
  252. layout->memsize,
  253. 0xffffffff,
  254. (state->src_w - 1) |
  255. ((state->src_h - 1) << 16));
  256. if (layout->pos)
  257. atmel_hlcdc_layer_update_cfg(&plane->layer,
  258. layout->pos,
  259. 0xffffffff,
  260. state->crtc_x |
  261. (state->crtc_y << 16));
  262. /* TODO: rework the rescaling part */
  263. if (state->crtc_w != state->src_w || state->crtc_h != state->src_h) {
  264. u32 factor_reg = 0;
  265. if (state->crtc_w != state->src_w) {
  266. int i;
  267. u32 factor;
  268. u32 *coeff_tab = heo_upscaling_xcoef;
  269. u32 max_memsize;
  270. if (state->crtc_w < state->src_w)
  271. coeff_tab = heo_downscaling_xcoef;
  272. for (i = 0; i < ARRAY_SIZE(heo_upscaling_xcoef); i++)
  273. atmel_hlcdc_layer_update_cfg(&plane->layer,
  274. 17 + i,
  275. 0xffffffff,
  276. coeff_tab[i]);
  277. factor = ((8 * 256 * state->src_w) - (256 * 4)) /
  278. state->crtc_w;
  279. factor++;
  280. max_memsize = ((factor * state->crtc_w) + (256 * 4)) /
  281. 2048;
  282. if (max_memsize > state->src_w)
  283. factor--;
  284. factor_reg |= factor | 0x80000000;
  285. }
  286. if (state->crtc_h != state->src_h) {
  287. int i;
  288. u32 factor;
  289. u32 *coeff_tab = heo_upscaling_ycoef;
  290. u32 max_memsize;
  291. if (state->crtc_h < state->src_h)
  292. coeff_tab = heo_downscaling_ycoef;
  293. for (i = 0; i < ARRAY_SIZE(heo_upscaling_ycoef); i++)
  294. atmel_hlcdc_layer_update_cfg(&plane->layer,
  295. 33 + i,
  296. 0xffffffff,
  297. coeff_tab[i]);
  298. factor = ((8 * 256 * state->src_h) - (256 * 4)) /
  299. state->crtc_h;
  300. factor++;
  301. max_memsize = ((factor * state->crtc_h) + (256 * 4)) /
  302. 2048;
  303. if (max_memsize > state->src_h)
  304. factor--;
  305. factor_reg |= (factor << 16) | 0x80000000;
  306. }
  307. atmel_hlcdc_layer_update_cfg(&plane->layer, 13, 0xffffffff,
  308. factor_reg);
  309. } else {
  310. atmel_hlcdc_layer_update_cfg(&plane->layer, 13, 0xffffffff, 0);
  311. }
  312. }
  313. static void
  314. atmel_hlcdc_plane_update_general_settings(struct atmel_hlcdc_plane *plane,
  315. struct atmel_hlcdc_plane_state *state)
  316. {
  317. const struct atmel_hlcdc_layer_cfg_layout *layout =
  318. &plane->layer.desc->layout;
  319. unsigned int cfg = ATMEL_HLCDC_LAYER_DMA;
  320. if (plane->base.type != DRM_PLANE_TYPE_PRIMARY) {
  321. cfg |= ATMEL_HLCDC_LAYER_OVR | ATMEL_HLCDC_LAYER_ITER2BL |
  322. ATMEL_HLCDC_LAYER_ITER;
  323. if (atmel_hlcdc_format_embeds_alpha(state->base.fb->format->format))
  324. cfg |= ATMEL_HLCDC_LAYER_LAEN;
  325. else
  326. cfg |= ATMEL_HLCDC_LAYER_GAEN |
  327. ATMEL_HLCDC_LAYER_GA(state->alpha);
  328. }
  329. atmel_hlcdc_layer_update_cfg(&plane->layer,
  330. ATMEL_HLCDC_LAYER_DMA_CFG_ID,
  331. ATMEL_HLCDC_LAYER_DMA_BLEN_MASK |
  332. ATMEL_HLCDC_LAYER_DMA_SIF,
  333. ATMEL_HLCDC_LAYER_DMA_BLEN_INCR16 |
  334. state->ahb_id);
  335. atmel_hlcdc_layer_update_cfg(&plane->layer, layout->general_config,
  336. ATMEL_HLCDC_LAYER_ITER2BL |
  337. ATMEL_HLCDC_LAYER_ITER |
  338. ATMEL_HLCDC_LAYER_GAEN |
  339. ATMEL_HLCDC_LAYER_GA_MASK |
  340. ATMEL_HLCDC_LAYER_LAEN |
  341. ATMEL_HLCDC_LAYER_OVR |
  342. ATMEL_HLCDC_LAYER_DMA, cfg);
  343. }
  344. static void atmel_hlcdc_plane_update_format(struct atmel_hlcdc_plane *plane,
  345. struct atmel_hlcdc_plane_state *state)
  346. {
  347. u32 cfg;
  348. int ret;
  349. ret = atmel_hlcdc_format_to_plane_mode(state->base.fb->format->format,
  350. &cfg);
  351. if (ret)
  352. return;
  353. if ((state->base.fb->format->format == DRM_FORMAT_YUV422 ||
  354. state->base.fb->format->format == DRM_FORMAT_NV61) &&
  355. drm_rotation_90_or_270(state->base.rotation))
  356. cfg |= ATMEL_HLCDC_YUV422ROT;
  357. atmel_hlcdc_layer_update_cfg(&plane->layer,
  358. ATMEL_HLCDC_LAYER_FORMAT_CFG_ID,
  359. 0xffffffff,
  360. cfg);
  361. /*
  362. * Rotation optimization is not working on RGB888 (rotation is still
  363. * working but without any optimization).
  364. */
  365. if (state->base.fb->format->format == DRM_FORMAT_RGB888)
  366. cfg = ATMEL_HLCDC_LAYER_DMA_ROTDIS;
  367. else
  368. cfg = 0;
  369. atmel_hlcdc_layer_update_cfg(&plane->layer,
  370. ATMEL_HLCDC_LAYER_DMA_CFG_ID,
  371. ATMEL_HLCDC_LAYER_DMA_ROTDIS, cfg);
  372. }
  373. static void atmel_hlcdc_plane_update_buffers(struct atmel_hlcdc_plane *plane,
  374. struct atmel_hlcdc_plane_state *state)
  375. {
  376. struct atmel_hlcdc_layer *layer = &plane->layer;
  377. const struct atmel_hlcdc_layer_cfg_layout *layout =
  378. &layer->desc->layout;
  379. int i;
  380. atmel_hlcdc_layer_update_set_fb(&plane->layer, state->base.fb,
  381. state->offsets);
  382. for (i = 0; i < state->nplanes; i++) {
  383. if (layout->xstride[i]) {
  384. atmel_hlcdc_layer_update_cfg(&plane->layer,
  385. layout->xstride[i],
  386. 0xffffffff,
  387. state->xstride[i]);
  388. }
  389. if (layout->pstride[i]) {
  390. atmel_hlcdc_layer_update_cfg(&plane->layer,
  391. layout->pstride[i],
  392. 0xffffffff,
  393. state->pstride[i]);
  394. }
  395. }
  396. }
  397. int atmel_hlcdc_plane_prepare_ahb_routing(struct drm_crtc_state *c_state)
  398. {
  399. unsigned int ahb_load[2] = { };
  400. struct drm_plane *plane;
  401. drm_atomic_crtc_state_for_each_plane(plane, c_state) {
  402. struct atmel_hlcdc_plane_state *plane_state;
  403. struct drm_plane_state *plane_s;
  404. unsigned int pixels, load = 0;
  405. int i;
  406. plane_s = drm_atomic_get_plane_state(c_state->state, plane);
  407. if (IS_ERR(plane_s))
  408. return PTR_ERR(plane_s);
  409. plane_state =
  410. drm_plane_state_to_atmel_hlcdc_plane_state(plane_s);
  411. pixels = (plane_state->src_w * plane_state->src_h) -
  412. (plane_state->disc_w * plane_state->disc_h);
  413. for (i = 0; i < plane_state->nplanes; i++)
  414. load += pixels * plane_state->bpp[i];
  415. if (ahb_load[0] <= ahb_load[1])
  416. plane_state->ahb_id = 0;
  417. else
  418. plane_state->ahb_id = 1;
  419. ahb_load[plane_state->ahb_id] += load;
  420. }
  421. return 0;
  422. }
  423. int
  424. atmel_hlcdc_plane_prepare_disc_area(struct drm_crtc_state *c_state)
  425. {
  426. int disc_x = 0, disc_y = 0, disc_w = 0, disc_h = 0;
  427. const struct atmel_hlcdc_layer_cfg_layout *layout;
  428. struct atmel_hlcdc_plane_state *primary_state;
  429. struct drm_plane_state *primary_s;
  430. struct atmel_hlcdc_plane *primary;
  431. struct drm_plane *ovl;
  432. primary = drm_plane_to_atmel_hlcdc_plane(c_state->crtc->primary);
  433. layout = &primary->layer.desc->layout;
  434. if (!layout->disc_pos || !layout->disc_size)
  435. return 0;
  436. primary_s = drm_atomic_get_plane_state(c_state->state,
  437. &primary->base);
  438. if (IS_ERR(primary_s))
  439. return PTR_ERR(primary_s);
  440. primary_state = drm_plane_state_to_atmel_hlcdc_plane_state(primary_s);
  441. drm_atomic_crtc_state_for_each_plane(ovl, c_state) {
  442. struct atmel_hlcdc_plane_state *ovl_state;
  443. struct drm_plane_state *ovl_s;
  444. if (ovl == c_state->crtc->primary)
  445. continue;
  446. ovl_s = drm_atomic_get_plane_state(c_state->state, ovl);
  447. if (IS_ERR(ovl_s))
  448. return PTR_ERR(ovl_s);
  449. ovl_state = drm_plane_state_to_atmel_hlcdc_plane_state(ovl_s);
  450. if (!ovl_s->fb ||
  451. atmel_hlcdc_format_embeds_alpha(ovl_s->fb->format->format) ||
  452. ovl_state->alpha != 255)
  453. continue;
  454. /* TODO: implement a smarter hidden area detection */
  455. if (ovl_state->crtc_h * ovl_state->crtc_w < disc_h * disc_w)
  456. continue;
  457. disc_x = ovl_state->crtc_x;
  458. disc_y = ovl_state->crtc_y;
  459. disc_h = ovl_state->crtc_h;
  460. disc_w = ovl_state->crtc_w;
  461. }
  462. if (disc_x == primary_state->disc_x &&
  463. disc_y == primary_state->disc_y &&
  464. disc_w == primary_state->disc_w &&
  465. disc_h == primary_state->disc_h)
  466. return 0;
  467. primary_state->disc_x = disc_x;
  468. primary_state->disc_y = disc_y;
  469. primary_state->disc_w = disc_w;
  470. primary_state->disc_h = disc_h;
  471. primary_state->disc_updated = true;
  472. return 0;
  473. }
  474. static void
  475. atmel_hlcdc_plane_update_disc_area(struct atmel_hlcdc_plane *plane,
  476. struct atmel_hlcdc_plane_state *state)
  477. {
  478. const struct atmel_hlcdc_layer_cfg_layout *layout =
  479. &plane->layer.desc->layout;
  480. int disc_surface = 0;
  481. if (!state->disc_updated)
  482. return;
  483. disc_surface = state->disc_h * state->disc_w;
  484. atmel_hlcdc_layer_update_cfg(&plane->layer, layout->general_config,
  485. ATMEL_HLCDC_LAYER_DISCEN,
  486. disc_surface ? ATMEL_HLCDC_LAYER_DISCEN : 0);
  487. if (!disc_surface)
  488. return;
  489. atmel_hlcdc_layer_update_cfg(&plane->layer,
  490. layout->disc_pos,
  491. 0xffffffff,
  492. state->disc_x | (state->disc_y << 16));
  493. atmel_hlcdc_layer_update_cfg(&plane->layer,
  494. layout->disc_size,
  495. 0xffffffff,
  496. (state->disc_w - 1) |
  497. ((state->disc_h - 1) << 16));
  498. }
  499. static int atmel_hlcdc_plane_atomic_check(struct drm_plane *p,
  500. struct drm_plane_state *s)
  501. {
  502. struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
  503. struct atmel_hlcdc_plane_state *state =
  504. drm_plane_state_to_atmel_hlcdc_plane_state(s);
  505. const struct atmel_hlcdc_layer_cfg_layout *layout =
  506. &plane->layer.desc->layout;
  507. struct drm_framebuffer *fb = state->base.fb;
  508. const struct drm_display_mode *mode;
  509. struct drm_crtc_state *crtc_state;
  510. unsigned int patched_crtc_w;
  511. unsigned int patched_crtc_h;
  512. unsigned int patched_src_w;
  513. unsigned int patched_src_h;
  514. unsigned int tmp;
  515. int x_offset = 0;
  516. int y_offset = 0;
  517. int hsub = 1;
  518. int vsub = 1;
  519. int i;
  520. if (!state->base.crtc || !fb)
  521. return 0;
  522. crtc_state = drm_atomic_get_existing_crtc_state(s->state, s->crtc);
  523. mode = &crtc_state->adjusted_mode;
  524. state->src_x = s->src_x;
  525. state->src_y = s->src_y;
  526. state->src_h = s->src_h;
  527. state->src_w = s->src_w;
  528. state->crtc_x = s->crtc_x;
  529. state->crtc_y = s->crtc_y;
  530. state->crtc_h = s->crtc_h;
  531. state->crtc_w = s->crtc_w;
  532. if ((state->src_x | state->src_y | state->src_w | state->src_h) &
  533. SUBPIXEL_MASK)
  534. return -EINVAL;
  535. state->src_x >>= 16;
  536. state->src_y >>= 16;
  537. state->src_w >>= 16;
  538. state->src_h >>= 16;
  539. state->nplanes = fb->format->num_planes;
  540. if (state->nplanes > ATMEL_HLCDC_MAX_PLANES)
  541. return -EINVAL;
  542. /*
  543. * Swap width and size in case of 90 or 270 degrees rotation
  544. */
  545. if (drm_rotation_90_or_270(state->base.rotation)) {
  546. tmp = state->crtc_w;
  547. state->crtc_w = state->crtc_h;
  548. state->crtc_h = tmp;
  549. tmp = state->src_w;
  550. state->src_w = state->src_h;
  551. state->src_h = tmp;
  552. }
  553. if (state->crtc_x + state->crtc_w > mode->hdisplay)
  554. patched_crtc_w = mode->hdisplay - state->crtc_x;
  555. else
  556. patched_crtc_w = state->crtc_w;
  557. if (state->crtc_x < 0) {
  558. patched_crtc_w += state->crtc_x;
  559. x_offset = -state->crtc_x;
  560. state->crtc_x = 0;
  561. }
  562. if (state->crtc_y + state->crtc_h > mode->vdisplay)
  563. patched_crtc_h = mode->vdisplay - state->crtc_y;
  564. else
  565. patched_crtc_h = state->crtc_h;
  566. if (state->crtc_y < 0) {
  567. patched_crtc_h += state->crtc_y;
  568. y_offset = -state->crtc_y;
  569. state->crtc_y = 0;
  570. }
  571. patched_src_w = DIV_ROUND_CLOSEST(patched_crtc_w * state->src_w,
  572. state->crtc_w);
  573. patched_src_h = DIV_ROUND_CLOSEST(patched_crtc_h * state->src_h,
  574. state->crtc_h);
  575. hsub = drm_format_horz_chroma_subsampling(fb->format->format);
  576. vsub = drm_format_vert_chroma_subsampling(fb->format->format);
  577. for (i = 0; i < state->nplanes; i++) {
  578. unsigned int offset = 0;
  579. int xdiv = i ? hsub : 1;
  580. int ydiv = i ? vsub : 1;
  581. state->bpp[i] = fb->format->cpp[i];
  582. if (!state->bpp[i])
  583. return -EINVAL;
  584. switch (state->base.rotation & DRM_ROTATE_MASK) {
  585. case DRM_ROTATE_90:
  586. offset = ((y_offset + state->src_y + patched_src_w - 1) /
  587. ydiv) * fb->pitches[i];
  588. offset += ((x_offset + state->src_x) / xdiv) *
  589. state->bpp[i];
  590. state->xstride[i] = ((patched_src_w - 1) / ydiv) *
  591. fb->pitches[i];
  592. state->pstride[i] = -fb->pitches[i] - state->bpp[i];
  593. break;
  594. case DRM_ROTATE_180:
  595. offset = ((y_offset + state->src_y + patched_src_h - 1) /
  596. ydiv) * fb->pitches[i];
  597. offset += ((x_offset + state->src_x + patched_src_w - 1) /
  598. xdiv) * state->bpp[i];
  599. state->xstride[i] = ((((patched_src_w - 1) / xdiv) - 1) *
  600. state->bpp[i]) - fb->pitches[i];
  601. state->pstride[i] = -2 * state->bpp[i];
  602. break;
  603. case DRM_ROTATE_270:
  604. offset = ((y_offset + state->src_y) / ydiv) *
  605. fb->pitches[i];
  606. offset += ((x_offset + state->src_x + patched_src_h - 1) /
  607. xdiv) * state->bpp[i];
  608. state->xstride[i] = -(((patched_src_w - 1) / ydiv) *
  609. fb->pitches[i]) -
  610. (2 * state->bpp[i]);
  611. state->pstride[i] = fb->pitches[i] - state->bpp[i];
  612. break;
  613. case DRM_ROTATE_0:
  614. default:
  615. offset = ((y_offset + state->src_y) / ydiv) *
  616. fb->pitches[i];
  617. offset += ((x_offset + state->src_x) / xdiv) *
  618. state->bpp[i];
  619. state->xstride[i] = fb->pitches[i] -
  620. ((patched_src_w / xdiv) *
  621. state->bpp[i]);
  622. state->pstride[i] = 0;
  623. break;
  624. }
  625. state->offsets[i] = offset + fb->offsets[i];
  626. }
  627. state->src_w = patched_src_w;
  628. state->src_h = patched_src_h;
  629. state->crtc_w = patched_crtc_w;
  630. state->crtc_h = patched_crtc_h;
  631. if (!layout->size &&
  632. (mode->hdisplay != state->crtc_w ||
  633. mode->vdisplay != state->crtc_h))
  634. return -EINVAL;
  635. if (plane->layer.desc->max_height &&
  636. state->crtc_h > plane->layer.desc->max_height)
  637. return -EINVAL;
  638. if (plane->layer.desc->max_width &&
  639. state->crtc_w > plane->layer.desc->max_width)
  640. return -EINVAL;
  641. if ((state->crtc_h != state->src_h || state->crtc_w != state->src_w) &&
  642. (!layout->memsize ||
  643. atmel_hlcdc_format_embeds_alpha(state->base.fb->format->format)))
  644. return -EINVAL;
  645. if (state->crtc_x < 0 || state->crtc_y < 0)
  646. return -EINVAL;
  647. if (state->crtc_w + state->crtc_x > mode->hdisplay ||
  648. state->crtc_h + state->crtc_y > mode->vdisplay)
  649. return -EINVAL;
  650. return 0;
  651. }
  652. static int atmel_hlcdc_plane_prepare_fb(struct drm_plane *p,
  653. struct drm_plane_state *new_state)
  654. {
  655. /*
  656. * FIXME: we should avoid this const -> non-const cast but it's
  657. * currently the only solution we have to modify the ->prepared
  658. * state and rollback the update request.
  659. * Ideally, we should rework the code to attach all the resources
  660. * to atmel_hlcdc_plane_state (including the DMA desc allocation),
  661. * but this require a complete rework of the atmel_hlcdc_layer
  662. * code.
  663. */
  664. struct drm_plane_state *s = (struct drm_plane_state *)new_state;
  665. struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
  666. struct atmel_hlcdc_plane_state *state =
  667. drm_plane_state_to_atmel_hlcdc_plane_state(s);
  668. int ret;
  669. ret = atmel_hlcdc_layer_update_start(&plane->layer);
  670. if (!ret)
  671. state->prepared = true;
  672. return ret;
  673. }
  674. static void atmel_hlcdc_plane_cleanup_fb(struct drm_plane *p,
  675. struct drm_plane_state *old_state)
  676. {
  677. /*
  678. * FIXME: we should avoid this const -> non-const cast but it's
  679. * currently the only solution we have to modify the ->prepared
  680. * state and rollback the update request.
  681. * Ideally, we should rework the code to attach all the resources
  682. * to atmel_hlcdc_plane_state (including the DMA desc allocation),
  683. * but this require a complete rework of the atmel_hlcdc_layer
  684. * code.
  685. */
  686. struct drm_plane_state *s = (struct drm_plane_state *)old_state;
  687. struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
  688. struct atmel_hlcdc_plane_state *state =
  689. drm_plane_state_to_atmel_hlcdc_plane_state(s);
  690. /*
  691. * The Request has already been applied or cancelled, nothing to do
  692. * here.
  693. */
  694. if (!state->prepared)
  695. return;
  696. atmel_hlcdc_layer_update_rollback(&plane->layer);
  697. state->prepared = false;
  698. }
  699. static void atmel_hlcdc_plane_atomic_update(struct drm_plane *p,
  700. struct drm_plane_state *old_s)
  701. {
  702. struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
  703. struct atmel_hlcdc_plane_state *state =
  704. drm_plane_state_to_atmel_hlcdc_plane_state(p->state);
  705. if (!p->state->crtc || !p->state->fb)
  706. return;
  707. atmel_hlcdc_plane_update_pos_and_size(plane, state);
  708. atmel_hlcdc_plane_update_general_settings(plane, state);
  709. atmel_hlcdc_plane_update_format(plane, state);
  710. atmel_hlcdc_plane_update_buffers(plane, state);
  711. atmel_hlcdc_plane_update_disc_area(plane, state);
  712. atmel_hlcdc_layer_update_commit(&plane->layer);
  713. }
  714. static void atmel_hlcdc_plane_atomic_disable(struct drm_plane *p,
  715. struct drm_plane_state *old_state)
  716. {
  717. struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
  718. atmel_hlcdc_layer_disable(&plane->layer);
  719. }
  720. static void atmel_hlcdc_plane_destroy(struct drm_plane *p)
  721. {
  722. struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
  723. if (plane->base.fb)
  724. drm_framebuffer_unreference(plane->base.fb);
  725. atmel_hlcdc_layer_cleanup(p->dev, &plane->layer);
  726. drm_plane_cleanup(p);
  727. devm_kfree(p->dev->dev, plane);
  728. }
  729. static int atmel_hlcdc_plane_atomic_set_property(struct drm_plane *p,
  730. struct drm_plane_state *s,
  731. struct drm_property *property,
  732. uint64_t val)
  733. {
  734. struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
  735. struct atmel_hlcdc_plane_properties *props = plane->properties;
  736. struct atmel_hlcdc_plane_state *state =
  737. drm_plane_state_to_atmel_hlcdc_plane_state(s);
  738. if (property == props->alpha)
  739. state->alpha = val;
  740. else
  741. return -EINVAL;
  742. return 0;
  743. }
  744. static int atmel_hlcdc_plane_atomic_get_property(struct drm_plane *p,
  745. const struct drm_plane_state *s,
  746. struct drm_property *property,
  747. uint64_t *val)
  748. {
  749. struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
  750. struct atmel_hlcdc_plane_properties *props = plane->properties;
  751. const struct atmel_hlcdc_plane_state *state =
  752. container_of(s, const struct atmel_hlcdc_plane_state, base);
  753. if (property == props->alpha)
  754. *val = state->alpha;
  755. else
  756. return -EINVAL;
  757. return 0;
  758. }
  759. static int atmel_hlcdc_plane_init_properties(struct atmel_hlcdc_plane *plane,
  760. const struct atmel_hlcdc_layer_desc *desc,
  761. struct atmel_hlcdc_plane_properties *props)
  762. {
  763. struct regmap *regmap = plane->layer.hlcdc->regmap;
  764. if (desc->type == ATMEL_HLCDC_OVERLAY_LAYER ||
  765. desc->type == ATMEL_HLCDC_CURSOR_LAYER) {
  766. drm_object_attach_property(&plane->base.base,
  767. props->alpha, 255);
  768. /* Set default alpha value */
  769. regmap_update_bits(regmap,
  770. desc->regs_offset +
  771. ATMEL_HLCDC_LAYER_GENERAL_CFG(&plane->layer),
  772. ATMEL_HLCDC_LAYER_GA_MASK,
  773. ATMEL_HLCDC_LAYER_GA_MASK);
  774. }
  775. if (desc->layout.xstride && desc->layout.pstride) {
  776. int ret;
  777. ret = drm_plane_create_rotation_property(&plane->base,
  778. DRM_ROTATE_0,
  779. DRM_ROTATE_0 |
  780. DRM_ROTATE_90 |
  781. DRM_ROTATE_180 |
  782. DRM_ROTATE_270);
  783. if (ret)
  784. return ret;
  785. }
  786. if (desc->layout.csc) {
  787. /*
  788. * TODO: decare a "yuv-to-rgb-conv-factors" property to let
  789. * userspace modify these factors (using a BLOB property ?).
  790. */
  791. regmap_write(regmap,
  792. desc->regs_offset +
  793. ATMEL_HLCDC_LAYER_CSC_CFG(&plane->layer, 0),
  794. 0x4c900091);
  795. regmap_write(regmap,
  796. desc->regs_offset +
  797. ATMEL_HLCDC_LAYER_CSC_CFG(&plane->layer, 1),
  798. 0x7a5f5090);
  799. regmap_write(regmap,
  800. desc->regs_offset +
  801. ATMEL_HLCDC_LAYER_CSC_CFG(&plane->layer, 2),
  802. 0x40040890);
  803. }
  804. return 0;
  805. }
  806. static struct drm_plane_helper_funcs atmel_hlcdc_layer_plane_helper_funcs = {
  807. .prepare_fb = atmel_hlcdc_plane_prepare_fb,
  808. .cleanup_fb = atmel_hlcdc_plane_cleanup_fb,
  809. .atomic_check = atmel_hlcdc_plane_atomic_check,
  810. .atomic_update = atmel_hlcdc_plane_atomic_update,
  811. .atomic_disable = atmel_hlcdc_plane_atomic_disable,
  812. };
  813. static void atmel_hlcdc_plane_reset(struct drm_plane *p)
  814. {
  815. struct atmel_hlcdc_plane_state *state;
  816. if (p->state) {
  817. state = drm_plane_state_to_atmel_hlcdc_plane_state(p->state);
  818. if (state->base.fb)
  819. drm_framebuffer_unreference(state->base.fb);
  820. kfree(state);
  821. p->state = NULL;
  822. }
  823. state = kzalloc(sizeof(*state), GFP_KERNEL);
  824. if (state) {
  825. state->alpha = 255;
  826. p->state = &state->base;
  827. p->state->plane = p;
  828. }
  829. }
  830. static struct drm_plane_state *
  831. atmel_hlcdc_plane_atomic_duplicate_state(struct drm_plane *p)
  832. {
  833. struct atmel_hlcdc_plane_state *state =
  834. drm_plane_state_to_atmel_hlcdc_plane_state(p->state);
  835. struct atmel_hlcdc_plane_state *copy;
  836. copy = kmemdup(state, sizeof(*state), GFP_KERNEL);
  837. if (!copy)
  838. return NULL;
  839. copy->disc_updated = false;
  840. copy->prepared = false;
  841. if (copy->base.fb)
  842. drm_framebuffer_reference(copy->base.fb);
  843. return &copy->base;
  844. }
  845. static void atmel_hlcdc_plane_atomic_destroy_state(struct drm_plane *plane,
  846. struct drm_plane_state *s)
  847. {
  848. struct atmel_hlcdc_plane_state *state =
  849. drm_plane_state_to_atmel_hlcdc_plane_state(s);
  850. if (s->fb)
  851. drm_framebuffer_unreference(s->fb);
  852. kfree(state);
  853. }
  854. static struct drm_plane_funcs layer_plane_funcs = {
  855. .update_plane = drm_atomic_helper_update_plane,
  856. .disable_plane = drm_atomic_helper_disable_plane,
  857. .set_property = drm_atomic_helper_plane_set_property,
  858. .destroy = atmel_hlcdc_plane_destroy,
  859. .reset = atmel_hlcdc_plane_reset,
  860. .atomic_duplicate_state = atmel_hlcdc_plane_atomic_duplicate_state,
  861. .atomic_destroy_state = atmel_hlcdc_plane_atomic_destroy_state,
  862. .atomic_set_property = atmel_hlcdc_plane_atomic_set_property,
  863. .atomic_get_property = atmel_hlcdc_plane_atomic_get_property,
  864. };
  865. static struct atmel_hlcdc_plane *
  866. atmel_hlcdc_plane_create(struct drm_device *dev,
  867. const struct atmel_hlcdc_layer_desc *desc,
  868. struct atmel_hlcdc_plane_properties *props)
  869. {
  870. struct atmel_hlcdc_plane *plane;
  871. enum drm_plane_type type;
  872. int ret;
  873. plane = devm_kzalloc(dev->dev, sizeof(*plane), GFP_KERNEL);
  874. if (!plane)
  875. return ERR_PTR(-ENOMEM);
  876. ret = atmel_hlcdc_layer_init(dev, &plane->layer, desc);
  877. if (ret)
  878. return ERR_PTR(ret);
  879. if (desc->type == ATMEL_HLCDC_BASE_LAYER)
  880. type = DRM_PLANE_TYPE_PRIMARY;
  881. else if (desc->type == ATMEL_HLCDC_CURSOR_LAYER)
  882. type = DRM_PLANE_TYPE_CURSOR;
  883. else
  884. type = DRM_PLANE_TYPE_OVERLAY;
  885. ret = drm_universal_plane_init(dev, &plane->base, 0,
  886. &layer_plane_funcs,
  887. desc->formats->formats,
  888. desc->formats->nformats, type, NULL);
  889. if (ret)
  890. return ERR_PTR(ret);
  891. drm_plane_helper_add(&plane->base,
  892. &atmel_hlcdc_layer_plane_helper_funcs);
  893. /* Set default property values*/
  894. ret = atmel_hlcdc_plane_init_properties(plane, desc, props);
  895. if (ret)
  896. return ERR_PTR(ret);
  897. return plane;
  898. }
  899. static struct atmel_hlcdc_plane_properties *
  900. atmel_hlcdc_plane_create_properties(struct drm_device *dev)
  901. {
  902. struct atmel_hlcdc_plane_properties *props;
  903. props = devm_kzalloc(dev->dev, sizeof(*props), GFP_KERNEL);
  904. if (!props)
  905. return ERR_PTR(-ENOMEM);
  906. props->alpha = drm_property_create_range(dev, 0, "alpha", 0, 255);
  907. if (!props->alpha)
  908. return ERR_PTR(-ENOMEM);
  909. return props;
  910. }
  911. struct atmel_hlcdc_planes *
  912. atmel_hlcdc_create_planes(struct drm_device *dev)
  913. {
  914. struct atmel_hlcdc_dc *dc = dev->dev_private;
  915. struct atmel_hlcdc_plane_properties *props;
  916. struct atmel_hlcdc_planes *planes;
  917. const struct atmel_hlcdc_layer_desc *descs = dc->desc->layers;
  918. int nlayers = dc->desc->nlayers;
  919. int i;
  920. planes = devm_kzalloc(dev->dev, sizeof(*planes), GFP_KERNEL);
  921. if (!planes)
  922. return ERR_PTR(-ENOMEM);
  923. for (i = 0; i < nlayers; i++) {
  924. if (descs[i].type == ATMEL_HLCDC_OVERLAY_LAYER)
  925. planes->noverlays++;
  926. }
  927. if (planes->noverlays) {
  928. planes->overlays = devm_kzalloc(dev->dev,
  929. planes->noverlays *
  930. sizeof(*planes->overlays),
  931. GFP_KERNEL);
  932. if (!planes->overlays)
  933. return ERR_PTR(-ENOMEM);
  934. }
  935. props = atmel_hlcdc_plane_create_properties(dev);
  936. if (IS_ERR(props))
  937. return ERR_CAST(props);
  938. planes->noverlays = 0;
  939. for (i = 0; i < nlayers; i++) {
  940. struct atmel_hlcdc_plane *plane;
  941. if (descs[i].type == ATMEL_HLCDC_PP_LAYER)
  942. continue;
  943. plane = atmel_hlcdc_plane_create(dev, &descs[i], props);
  944. if (IS_ERR(plane))
  945. return ERR_CAST(plane);
  946. plane->properties = props;
  947. switch (descs[i].type) {
  948. case ATMEL_HLCDC_BASE_LAYER:
  949. if (planes->primary)
  950. return ERR_PTR(-EINVAL);
  951. planes->primary = plane;
  952. break;
  953. case ATMEL_HLCDC_OVERLAY_LAYER:
  954. planes->overlays[planes->noverlays++] = plane;
  955. break;
  956. case ATMEL_HLCDC_CURSOR_LAYER:
  957. if (planes->cursor)
  958. return ERR_PTR(-EINVAL);
  959. planes->cursor = plane;
  960. break;
  961. default:
  962. break;
  963. }
  964. }
  965. return planes;
  966. }