mdp5_plane.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650
  1. /*
  2. * Copyright (c) 2014 The Linux Foundation. All rights reserved.
  3. * Copyright (C) 2013 Red Hat
  4. * Author: Rob Clark <robdclark@gmail.com>
  5. *
  6. * This program is free software; you can redistribute it and/or modify it
  7. * under the terms of the GNU General Public License version 2 as published by
  8. * the Free Software Foundation.
  9. *
  10. * This program is distributed in the hope that it will be useful, but WITHOUT
  11. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  12. * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
  13. * more details.
  14. *
  15. * You should have received a copy of the GNU General Public License along with
  16. * this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. #include "mdp5_kms.h"
  19. struct mdp5_plane {
  20. struct drm_plane base;
  21. const char *name;
  22. enum mdp5_pipe pipe;
  23. spinlock_t pipe_lock; /* protect REG_MDP5_PIPE_* registers */
  24. uint32_t reg_offset;
  25. uint32_t flush_mask; /* used to commit pipe registers */
  26. uint32_t nformats;
  27. uint32_t formats[32];
  28. bool enabled;
  29. };
  30. #define to_mdp5_plane(x) container_of(x, struct mdp5_plane, base)
  31. static int mdp5_plane_mode_set(struct drm_plane *plane,
  32. struct drm_crtc *crtc, struct drm_framebuffer *fb,
  33. int crtc_x, int crtc_y,
  34. unsigned int crtc_w, unsigned int crtc_h,
  35. uint32_t src_x, uint32_t src_y,
  36. uint32_t src_w, uint32_t src_h);
  37. static void set_scanout_locked(struct drm_plane *plane,
  38. struct drm_framebuffer *fb);
  39. static struct mdp5_kms *get_kms(struct drm_plane *plane)
  40. {
  41. struct msm_drm_private *priv = plane->dev->dev_private;
  42. return to_mdp5_kms(to_mdp_kms(priv->kms));
  43. }
  44. static bool plane_enabled(struct drm_plane_state *state)
  45. {
  46. return state->fb && state->crtc;
  47. }
  48. static int mdp5_plane_disable(struct drm_plane *plane)
  49. {
  50. struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane);
  51. struct mdp5_kms *mdp5_kms = get_kms(plane);
  52. enum mdp5_pipe pipe = mdp5_plane->pipe;
  53. DBG("%s: disable", mdp5_plane->name);
  54. if (mdp5_kms) {
  55. /* Release the memory we requested earlier from the SMP: */
  56. mdp5_smp_release(mdp5_kms->smp, pipe);
  57. }
  58. return 0;
  59. }
  60. static void mdp5_plane_destroy(struct drm_plane *plane)
  61. {
  62. struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane);
  63. drm_plane_helper_disable(plane);
  64. drm_plane_cleanup(plane);
  65. kfree(mdp5_plane);
  66. }
  67. /* helper to install properties which are common to planes and crtcs */
  68. void mdp5_plane_install_properties(struct drm_plane *plane,
  69. struct drm_mode_object *obj)
  70. {
  71. // XXX
  72. }
  73. int mdp5_plane_set_property(struct drm_plane *plane,
  74. struct drm_property *property, uint64_t val)
  75. {
  76. // XXX
  77. return -EINVAL;
  78. }
  79. static void mdp5_plane_reset(struct drm_plane *plane)
  80. {
  81. struct mdp5_plane_state *mdp5_state;
  82. if (plane->state && plane->state->fb)
  83. drm_framebuffer_unreference(plane->state->fb);
  84. kfree(to_mdp5_plane_state(plane->state));
  85. mdp5_state = kzalloc(sizeof(*mdp5_state), GFP_KERNEL);
  86. if (plane->type == DRM_PLANE_TYPE_PRIMARY) {
  87. mdp5_state->zpos = 0;
  88. } else {
  89. mdp5_state->zpos = 1 + drm_plane_index(plane);
  90. }
  91. mdp5_state->base.plane = plane;
  92. plane->state = &mdp5_state->base;
  93. }
  94. static struct drm_plane_state *
  95. mdp5_plane_duplicate_state(struct drm_plane *plane)
  96. {
  97. struct mdp5_plane_state *mdp5_state;
  98. if (WARN_ON(!plane->state))
  99. return NULL;
  100. mdp5_state = kmemdup(to_mdp5_plane_state(plane->state),
  101. sizeof(*mdp5_state), GFP_KERNEL);
  102. if (mdp5_state && mdp5_state->base.fb)
  103. drm_framebuffer_reference(mdp5_state->base.fb);
  104. mdp5_state->mode_changed = false;
  105. mdp5_state->pending = false;
  106. return &mdp5_state->base;
  107. }
  108. static void mdp5_plane_destroy_state(struct drm_plane *plane,
  109. struct drm_plane_state *state)
  110. {
  111. if (state->fb)
  112. drm_framebuffer_unreference(state->fb);
  113. kfree(to_mdp5_plane_state(state));
  114. }
  115. static const struct drm_plane_funcs mdp5_plane_funcs = {
  116. .update_plane = drm_atomic_helper_update_plane,
  117. .disable_plane = drm_atomic_helper_disable_plane,
  118. .destroy = mdp5_plane_destroy,
  119. .set_property = mdp5_plane_set_property,
  120. .reset = mdp5_plane_reset,
  121. .atomic_duplicate_state = mdp5_plane_duplicate_state,
  122. .atomic_destroy_state = mdp5_plane_destroy_state,
  123. };
  124. static int mdp5_plane_prepare_fb(struct drm_plane *plane,
  125. struct drm_framebuffer *fb,
  126. const struct drm_plane_state *new_state)
  127. {
  128. struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane);
  129. struct mdp5_kms *mdp5_kms = get_kms(plane);
  130. DBG("%s: prepare: FB[%u]", mdp5_plane->name, fb->base.id);
  131. return msm_framebuffer_prepare(fb, mdp5_kms->id);
  132. }
  133. static void mdp5_plane_cleanup_fb(struct drm_plane *plane,
  134. struct drm_framebuffer *fb,
  135. const struct drm_plane_state *old_state)
  136. {
  137. struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane);
  138. struct mdp5_kms *mdp5_kms = get_kms(plane);
  139. DBG("%s: cleanup: FB[%u]", mdp5_plane->name, fb->base.id);
  140. msm_framebuffer_cleanup(fb, mdp5_kms->id);
  141. }
  142. static int mdp5_plane_atomic_check(struct drm_plane *plane,
  143. struct drm_plane_state *state)
  144. {
  145. struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane);
  146. struct drm_plane_state *old_state = plane->state;
  147. DBG("%s: check (%d -> %d)", mdp5_plane->name,
  148. plane_enabled(old_state), plane_enabled(state));
  149. if (plane_enabled(state) && plane_enabled(old_state)) {
  150. /* we cannot change SMP block configuration during scanout: */
  151. bool full_modeset = false;
  152. if (state->fb->pixel_format != old_state->fb->pixel_format) {
  153. DBG("%s: pixel_format change!", mdp5_plane->name);
  154. full_modeset = true;
  155. }
  156. if (state->src_w != old_state->src_w) {
  157. DBG("%s: src_w change!", mdp5_plane->name);
  158. full_modeset = true;
  159. }
  160. if (to_mdp5_plane_state(old_state)->pending) {
  161. DBG("%s: still pending!", mdp5_plane->name);
  162. full_modeset = true;
  163. }
  164. if (full_modeset) {
  165. struct drm_crtc_state *crtc_state =
  166. drm_atomic_get_crtc_state(state->state, state->crtc);
  167. crtc_state->mode_changed = true;
  168. to_mdp5_plane_state(state)->mode_changed = true;
  169. }
  170. } else {
  171. to_mdp5_plane_state(state)->mode_changed = true;
  172. }
  173. return 0;
  174. }
  175. static void mdp5_plane_atomic_update(struct drm_plane *plane,
  176. struct drm_plane_state *old_state)
  177. {
  178. struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane);
  179. struct drm_plane_state *state = plane->state;
  180. DBG("%s: update", mdp5_plane->name);
  181. if (!plane_enabled(state)) {
  182. to_mdp5_plane_state(state)->pending = true;
  183. mdp5_plane_disable(plane);
  184. } else if (to_mdp5_plane_state(state)->mode_changed) {
  185. int ret;
  186. to_mdp5_plane_state(state)->pending = true;
  187. ret = mdp5_plane_mode_set(plane,
  188. state->crtc, state->fb,
  189. state->crtc_x, state->crtc_y,
  190. state->crtc_w, state->crtc_h,
  191. state->src_x, state->src_y,
  192. state->src_w, state->src_h);
  193. /* atomic_check should have ensured that this doesn't fail */
  194. WARN_ON(ret < 0);
  195. } else {
  196. unsigned long flags;
  197. spin_lock_irqsave(&mdp5_plane->pipe_lock, flags);
  198. set_scanout_locked(plane, state->fb);
  199. spin_unlock_irqrestore(&mdp5_plane->pipe_lock, flags);
  200. }
  201. }
  202. static const struct drm_plane_helper_funcs mdp5_plane_helper_funcs = {
  203. .prepare_fb = mdp5_plane_prepare_fb,
  204. .cleanup_fb = mdp5_plane_cleanup_fb,
  205. .atomic_check = mdp5_plane_atomic_check,
  206. .atomic_update = mdp5_plane_atomic_update,
  207. };
  208. static void set_scanout_locked(struct drm_plane *plane,
  209. struct drm_framebuffer *fb)
  210. {
  211. struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane);
  212. struct mdp5_kms *mdp5_kms = get_kms(plane);
  213. enum mdp5_pipe pipe = mdp5_plane->pipe;
  214. mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_STRIDE_A(pipe),
  215. MDP5_PIPE_SRC_STRIDE_A_P0(fb->pitches[0]) |
  216. MDP5_PIPE_SRC_STRIDE_A_P1(fb->pitches[1]));
  217. mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_STRIDE_B(pipe),
  218. MDP5_PIPE_SRC_STRIDE_B_P2(fb->pitches[2]) |
  219. MDP5_PIPE_SRC_STRIDE_B_P3(fb->pitches[3]));
  220. mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC0_ADDR(pipe),
  221. msm_framebuffer_iova(fb, mdp5_kms->id, 0));
  222. mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC1_ADDR(pipe),
  223. msm_framebuffer_iova(fb, mdp5_kms->id, 1));
  224. mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC2_ADDR(pipe),
  225. msm_framebuffer_iova(fb, mdp5_kms->id, 2));
  226. mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC3_ADDR(pipe),
  227. msm_framebuffer_iova(fb, mdp5_kms->id, 3));
  228. plane->fb = fb;
  229. }
  230. /* Note: mdp5_plane->pipe_lock must be locked */
  231. static void csc_disable(struct mdp5_kms *mdp5_kms, enum mdp5_pipe pipe)
  232. {
  233. uint32_t value = mdp5_read(mdp5_kms, REG_MDP5_PIPE_OP_MODE(pipe)) &
  234. ~MDP5_PIPE_OP_MODE_CSC_1_EN;
  235. mdp5_write(mdp5_kms, REG_MDP5_PIPE_OP_MODE(pipe), value);
  236. }
  237. /* Note: mdp5_plane->pipe_lock must be locked */
  238. static void csc_enable(struct mdp5_kms *mdp5_kms, enum mdp5_pipe pipe,
  239. struct csc_cfg *csc)
  240. {
  241. uint32_t i, mode = 0; /* RGB, no CSC */
  242. uint32_t *matrix;
  243. if (unlikely(!csc))
  244. return;
  245. if ((csc->type == CSC_YUV2RGB) || (CSC_YUV2YUV == csc->type))
  246. mode |= MDP5_PIPE_OP_MODE_CSC_SRC_DATA_FORMAT(DATA_FORMAT_YUV);
  247. if ((csc->type == CSC_RGB2YUV) || (CSC_YUV2YUV == csc->type))
  248. mode |= MDP5_PIPE_OP_MODE_CSC_DST_DATA_FORMAT(DATA_FORMAT_YUV);
  249. mode |= MDP5_PIPE_OP_MODE_CSC_1_EN;
  250. mdp5_write(mdp5_kms, REG_MDP5_PIPE_OP_MODE(pipe), mode);
  251. matrix = csc->matrix;
  252. mdp5_write(mdp5_kms, REG_MDP5_PIPE_CSC_1_MATRIX_COEFF_0(pipe),
  253. MDP5_PIPE_CSC_1_MATRIX_COEFF_0_COEFF_11(matrix[0]) |
  254. MDP5_PIPE_CSC_1_MATRIX_COEFF_0_COEFF_12(matrix[1]));
  255. mdp5_write(mdp5_kms, REG_MDP5_PIPE_CSC_1_MATRIX_COEFF_1(pipe),
  256. MDP5_PIPE_CSC_1_MATRIX_COEFF_1_COEFF_13(matrix[2]) |
  257. MDP5_PIPE_CSC_1_MATRIX_COEFF_1_COEFF_21(matrix[3]));
  258. mdp5_write(mdp5_kms, REG_MDP5_PIPE_CSC_1_MATRIX_COEFF_2(pipe),
  259. MDP5_PIPE_CSC_1_MATRIX_COEFF_2_COEFF_22(matrix[4]) |
  260. MDP5_PIPE_CSC_1_MATRIX_COEFF_2_COEFF_23(matrix[5]));
  261. mdp5_write(mdp5_kms, REG_MDP5_PIPE_CSC_1_MATRIX_COEFF_3(pipe),
  262. MDP5_PIPE_CSC_1_MATRIX_COEFF_3_COEFF_31(matrix[6]) |
  263. MDP5_PIPE_CSC_1_MATRIX_COEFF_3_COEFF_32(matrix[7]));
  264. mdp5_write(mdp5_kms, REG_MDP5_PIPE_CSC_1_MATRIX_COEFF_4(pipe),
  265. MDP5_PIPE_CSC_1_MATRIX_COEFF_4_COEFF_33(matrix[8]));
  266. for (i = 0; i < ARRAY_SIZE(csc->pre_bias); i++) {
  267. uint32_t *pre_clamp = csc->pre_clamp;
  268. uint32_t *post_clamp = csc->post_clamp;
  269. mdp5_write(mdp5_kms, REG_MDP5_PIPE_CSC_1_PRE_CLAMP(pipe, i),
  270. MDP5_PIPE_CSC_1_PRE_CLAMP_REG_HIGH(pre_clamp[2*i+1]) |
  271. MDP5_PIPE_CSC_1_PRE_CLAMP_REG_LOW(pre_clamp[2*i]));
  272. mdp5_write(mdp5_kms, REG_MDP5_PIPE_CSC_1_POST_CLAMP(pipe, i),
  273. MDP5_PIPE_CSC_1_POST_CLAMP_REG_HIGH(post_clamp[2*i+1]) |
  274. MDP5_PIPE_CSC_1_POST_CLAMP_REG_LOW(post_clamp[2*i]));
  275. mdp5_write(mdp5_kms, REG_MDP5_PIPE_CSC_1_PRE_BIAS(pipe, i),
  276. MDP5_PIPE_CSC_1_PRE_BIAS_REG_VALUE(csc->pre_bias[i]));
  277. mdp5_write(mdp5_kms, REG_MDP5_PIPE_CSC_1_POST_BIAS(pipe, i),
  278. MDP5_PIPE_CSC_1_POST_BIAS_REG_VALUE(csc->post_bias[i]));
  279. }
  280. }
  281. #define PHASE_STEP_SHIFT 21
  282. #define DOWN_SCALE_RATIO_MAX 32 /* 2^(26-21) */
  283. static int calc_phase_step(uint32_t src, uint32_t dst, uint32_t *out_phase)
  284. {
  285. uint32_t unit;
  286. if (src == 0 || dst == 0)
  287. return -EINVAL;
  288. /*
  289. * PHASE_STEP_X/Y is coded on 26 bits (25:0),
  290. * where 2^21 represents the unity "1" in fixed-point hardware design.
  291. * This leaves 5 bits for the integer part (downscale case):
  292. * -> maximum downscale ratio = 0b1_1111 = 31
  293. */
  294. if (src > (dst * DOWN_SCALE_RATIO_MAX))
  295. return -EOVERFLOW;
  296. unit = 1 << PHASE_STEP_SHIFT;
  297. *out_phase = mult_frac(unit, src, dst);
  298. return 0;
  299. }
  300. static int calc_scalex_steps(uint32_t pixel_format, uint32_t src, uint32_t dest,
  301. uint32_t phasex_steps[2])
  302. {
  303. uint32_t phasex_step;
  304. unsigned int hsub;
  305. int ret;
  306. ret = calc_phase_step(src, dest, &phasex_step);
  307. if (ret)
  308. return ret;
  309. hsub = drm_format_horz_chroma_subsampling(pixel_format);
  310. phasex_steps[0] = phasex_step;
  311. phasex_steps[1] = phasex_step / hsub;
  312. return 0;
  313. }
  314. static int calc_scaley_steps(uint32_t pixel_format, uint32_t src, uint32_t dest,
  315. uint32_t phasey_steps[2])
  316. {
  317. uint32_t phasey_step;
  318. unsigned int vsub;
  319. int ret;
  320. ret = calc_phase_step(src, dest, &phasey_step);
  321. if (ret)
  322. return ret;
  323. vsub = drm_format_vert_chroma_subsampling(pixel_format);
  324. phasey_steps[0] = phasey_step;
  325. phasey_steps[1] = phasey_step / vsub;
  326. return 0;
  327. }
  328. static uint32_t get_scalex_config(uint32_t src, uint32_t dest)
  329. {
  330. uint32_t filter;
  331. filter = (src <= dest) ? SCALE_FILTER_BIL : SCALE_FILTER_PCMN;
  332. return MDP5_PIPE_SCALE_CONFIG_SCALEX_EN |
  333. MDP5_PIPE_SCALE_CONFIG_SCALEX_MIN_FILTER(filter) |
  334. MDP5_PIPE_SCALE_CONFIG_SCALEX_CR_FILTER(filter) |
  335. MDP5_PIPE_SCALE_CONFIG_SCALEX_MAX_FILTER(filter);
  336. }
  337. static uint32_t get_scaley_config(uint32_t src, uint32_t dest)
  338. {
  339. uint32_t filter;
  340. filter = (src <= dest) ? SCALE_FILTER_BIL : SCALE_FILTER_PCMN;
  341. return MDP5_PIPE_SCALE_CONFIG_SCALEY_EN |
  342. MDP5_PIPE_SCALE_CONFIG_SCALEY_MIN_FILTER(filter) |
  343. MDP5_PIPE_SCALE_CONFIG_SCALEY_CR_FILTER(filter) |
  344. MDP5_PIPE_SCALE_CONFIG_SCALEY_MAX_FILTER(filter);
  345. }
  346. static int mdp5_plane_mode_set(struct drm_plane *plane,
  347. struct drm_crtc *crtc, struct drm_framebuffer *fb,
  348. int crtc_x, int crtc_y,
  349. unsigned int crtc_w, unsigned int crtc_h,
  350. uint32_t src_x, uint32_t src_y,
  351. uint32_t src_w, uint32_t src_h)
  352. {
  353. struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane);
  354. struct mdp5_kms *mdp5_kms = get_kms(plane);
  355. struct device *dev = mdp5_kms->dev->dev;
  356. enum mdp5_pipe pipe = mdp5_plane->pipe;
  357. const struct mdp_format *format;
  358. uint32_t nplanes, config = 0;
  359. /* below array -> index 0: comp 0/3 ; index 1: comp 1/2 */
  360. uint32_t phasex_step[2] = {0,}, phasey_step[2] = {0,};
  361. uint32_t hdecm = 0, vdecm = 0;
  362. uint32_t pix_format;
  363. unsigned long flags;
  364. int ret;
  365. nplanes = drm_format_num_planes(fb->pixel_format);
  366. /* bad formats should already be rejected: */
  367. if (WARN_ON(nplanes > pipe2nclients(pipe)))
  368. return -EINVAL;
  369. format = to_mdp_format(msm_framebuffer_format(fb));
  370. pix_format = format->base.pixel_format;
  371. /* src values are in Q16 fixed point, convert to integer: */
  372. src_x = src_x >> 16;
  373. src_y = src_y >> 16;
  374. src_w = src_w >> 16;
  375. src_h = src_h >> 16;
  376. DBG("%s: FB[%u] %u,%u,%u,%u -> CRTC[%u] %d,%d,%u,%u", mdp5_plane->name,
  377. fb->base.id, src_x, src_y, src_w, src_h,
  378. crtc->base.id, crtc_x, crtc_y, crtc_w, crtc_h);
  379. /* Request some memory from the SMP: */
  380. ret = mdp5_smp_request(mdp5_kms->smp,
  381. mdp5_plane->pipe, fb->pixel_format, src_w);
  382. if (ret)
  383. return ret;
  384. /*
  385. * Currently we update the hw for allocations/requests immediately,
  386. * but once atomic modeset/pageflip is in place, the allocation
  387. * would move into atomic->check_plane_state(), while updating the
  388. * hw would remain here:
  389. */
  390. mdp5_smp_configure(mdp5_kms->smp, pipe);
  391. /* SCALE is used to both scale and up-sample chroma components */
  392. if ((src_w != crtc_w) || MDP_FORMAT_IS_YUV(format)) {
  393. /* TODO calc hdecm */
  394. ret = calc_scalex_steps(pix_format, src_w, crtc_w, phasex_step);
  395. if (ret) {
  396. dev_err(dev, "X scaling (%d -> %d) failed: %d\n",
  397. src_w, crtc_w, ret);
  398. return ret;
  399. }
  400. config |= get_scalex_config(src_w, crtc_w);
  401. }
  402. if ((src_h != crtc_h) || MDP_FORMAT_IS_YUV(format)) {
  403. /* TODO calc vdecm */
  404. ret = calc_scaley_steps(pix_format, src_h, crtc_h, phasey_step);
  405. if (ret) {
  406. dev_err(dev, "Y scaling (%d -> %d) failed: %d\n",
  407. src_h, crtc_h, ret);
  408. return ret;
  409. }
  410. config |= get_scaley_config(src_h, crtc_h);
  411. }
  412. spin_lock_irqsave(&mdp5_plane->pipe_lock, flags);
  413. mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_IMG_SIZE(pipe),
  414. MDP5_PIPE_SRC_IMG_SIZE_WIDTH(fb->width) |
  415. MDP5_PIPE_SRC_IMG_SIZE_HEIGHT(fb->height));
  416. mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_SIZE(pipe),
  417. MDP5_PIPE_SRC_SIZE_WIDTH(src_w) |
  418. MDP5_PIPE_SRC_SIZE_HEIGHT(src_h));
  419. mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_XY(pipe),
  420. MDP5_PIPE_SRC_XY_X(src_x) |
  421. MDP5_PIPE_SRC_XY_Y(src_y));
  422. mdp5_write(mdp5_kms, REG_MDP5_PIPE_OUT_SIZE(pipe),
  423. MDP5_PIPE_OUT_SIZE_WIDTH(crtc_w) |
  424. MDP5_PIPE_OUT_SIZE_HEIGHT(crtc_h));
  425. mdp5_write(mdp5_kms, REG_MDP5_PIPE_OUT_XY(pipe),
  426. MDP5_PIPE_OUT_XY_X(crtc_x) |
  427. MDP5_PIPE_OUT_XY_Y(crtc_y));
  428. mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_FORMAT(pipe),
  429. MDP5_PIPE_SRC_FORMAT_A_BPC(format->bpc_a) |
  430. MDP5_PIPE_SRC_FORMAT_R_BPC(format->bpc_r) |
  431. MDP5_PIPE_SRC_FORMAT_G_BPC(format->bpc_g) |
  432. MDP5_PIPE_SRC_FORMAT_B_BPC(format->bpc_b) |
  433. COND(format->alpha_enable, MDP5_PIPE_SRC_FORMAT_ALPHA_ENABLE) |
  434. MDP5_PIPE_SRC_FORMAT_CPP(format->cpp - 1) |
  435. MDP5_PIPE_SRC_FORMAT_UNPACK_COUNT(format->unpack_count - 1) |
  436. COND(format->unpack_tight, MDP5_PIPE_SRC_FORMAT_UNPACK_TIGHT) |
  437. MDP5_PIPE_SRC_FORMAT_NUM_PLANES(format->fetch_type) |
  438. MDP5_PIPE_SRC_FORMAT_CHROMA_SAMP(format->chroma_sample));
  439. mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_UNPACK(pipe),
  440. MDP5_PIPE_SRC_UNPACK_ELEM0(format->unpack[0]) |
  441. MDP5_PIPE_SRC_UNPACK_ELEM1(format->unpack[1]) |
  442. MDP5_PIPE_SRC_UNPACK_ELEM2(format->unpack[2]) |
  443. MDP5_PIPE_SRC_UNPACK_ELEM3(format->unpack[3]));
  444. mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_OP_MODE(pipe),
  445. MDP5_PIPE_SRC_OP_MODE_BWC(BWC_LOSSLESS));
  446. /* not using secure mode: */
  447. mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_ADDR_SW_STATUS(pipe), 0);
  448. mdp5_write(mdp5_kms, REG_MDP5_PIPE_SCALE_PHASE_STEP_X(pipe),
  449. phasex_step[0]);
  450. mdp5_write(mdp5_kms, REG_MDP5_PIPE_SCALE_PHASE_STEP_Y(pipe),
  451. phasey_step[0]);
  452. mdp5_write(mdp5_kms, REG_MDP5_PIPE_SCALE_CR_PHASE_STEP_X(pipe),
  453. phasex_step[1]);
  454. mdp5_write(mdp5_kms, REG_MDP5_PIPE_SCALE_CR_PHASE_STEP_Y(pipe),
  455. phasey_step[1]);
  456. mdp5_write(mdp5_kms, REG_MDP5_PIPE_DECIMATION(pipe),
  457. MDP5_PIPE_DECIMATION_VERT(vdecm) |
  458. MDP5_PIPE_DECIMATION_HORZ(hdecm));
  459. mdp5_write(mdp5_kms, REG_MDP5_PIPE_SCALE_CONFIG(pipe), config);
  460. if (MDP_FORMAT_IS_YUV(format))
  461. csc_enable(mdp5_kms, pipe,
  462. mdp_get_default_csc_cfg(CSC_YUV2RGB));
  463. else
  464. csc_disable(mdp5_kms, pipe);
  465. set_scanout_locked(plane, fb);
  466. spin_unlock_irqrestore(&mdp5_plane->pipe_lock, flags);
  467. return ret;
  468. }
  469. void mdp5_plane_complete_flip(struct drm_plane *plane)
  470. {
  471. struct mdp5_kms *mdp5_kms = get_kms(plane);
  472. struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane);
  473. enum mdp5_pipe pipe = mdp5_plane->pipe;
  474. DBG("%s: complete flip", mdp5_plane->name);
  475. mdp5_smp_commit(mdp5_kms->smp, pipe);
  476. to_mdp5_plane_state(plane->state)->pending = false;
  477. }
  478. enum mdp5_pipe mdp5_plane_pipe(struct drm_plane *plane)
  479. {
  480. struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane);
  481. return mdp5_plane->pipe;
  482. }
  483. uint32_t mdp5_plane_get_flush(struct drm_plane *plane)
  484. {
  485. struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane);
  486. return mdp5_plane->flush_mask;
  487. }
  488. /* initialize plane */
  489. struct drm_plane *mdp5_plane_init(struct drm_device *dev,
  490. enum mdp5_pipe pipe, bool private_plane, uint32_t reg_offset)
  491. {
  492. struct drm_plane *plane = NULL;
  493. struct mdp5_plane *mdp5_plane;
  494. int ret;
  495. enum drm_plane_type type;
  496. mdp5_plane = kzalloc(sizeof(*mdp5_plane), GFP_KERNEL);
  497. if (!mdp5_plane) {
  498. ret = -ENOMEM;
  499. goto fail;
  500. }
  501. plane = &mdp5_plane->base;
  502. mdp5_plane->pipe = pipe;
  503. mdp5_plane->name = pipe2name(pipe);
  504. mdp5_plane->nformats = mdp5_get_formats(pipe, mdp5_plane->formats,
  505. ARRAY_SIZE(mdp5_plane->formats));
  506. mdp5_plane->flush_mask = mdp_ctl_flush_mask_pipe(pipe);
  507. mdp5_plane->reg_offset = reg_offset;
  508. spin_lock_init(&mdp5_plane->pipe_lock);
  509. type = private_plane ? DRM_PLANE_TYPE_PRIMARY : DRM_PLANE_TYPE_OVERLAY;
  510. ret = drm_universal_plane_init(dev, plane, 0xff, &mdp5_plane_funcs,
  511. mdp5_plane->formats, mdp5_plane->nformats,
  512. type);
  513. if (ret)
  514. goto fail;
  515. drm_plane_helper_add(plane, &mdp5_plane_helper_funcs);
  516. mdp5_plane_install_properties(plane, &plane->base);
  517. return plane;
  518. fail:
  519. if (plane)
  520. mdp5_plane_destroy(plane);
  521. return ERR_PTR(ret);
  522. }