mdp5_plane.c 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878
  1. /*
  2. * Copyright (C) 2014-2015 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 <drm/drm_print.h>
  19. #include "mdp5_kms.h"
  20. struct mdp5_plane {
  21. struct drm_plane base;
  22. uint32_t nformats;
  23. uint32_t formats[32];
  24. };
  25. #define to_mdp5_plane(x) container_of(x, struct mdp5_plane, base)
  26. static int mdp5_plane_mode_set(struct drm_plane *plane,
  27. struct drm_crtc *crtc, struct drm_framebuffer *fb,
  28. int crtc_x, int crtc_y,
  29. unsigned int crtc_w, unsigned int crtc_h,
  30. uint32_t src_x, uint32_t src_y,
  31. uint32_t src_w, uint32_t src_h);
  32. static void set_scanout_locked(struct drm_plane *plane,
  33. struct drm_framebuffer *fb);
  34. static struct mdp5_kms *get_kms(struct drm_plane *plane)
  35. {
  36. struct msm_drm_private *priv = plane->dev->dev_private;
  37. return to_mdp5_kms(to_mdp_kms(priv->kms));
  38. }
  39. static bool plane_enabled(struct drm_plane_state *state)
  40. {
  41. return state->fb && state->crtc;
  42. }
  43. static void mdp5_plane_destroy(struct drm_plane *plane)
  44. {
  45. struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane);
  46. drm_plane_helper_disable(plane);
  47. drm_plane_cleanup(plane);
  48. kfree(mdp5_plane);
  49. }
  50. static void mdp5_plane_install_rotation_property(struct drm_device *dev,
  51. struct drm_plane *plane)
  52. {
  53. drm_plane_create_rotation_property(plane,
  54. DRM_ROTATE_0,
  55. DRM_ROTATE_0 |
  56. DRM_ROTATE_180 |
  57. DRM_REFLECT_X |
  58. DRM_REFLECT_Y);
  59. }
  60. /* helper to install properties which are common to planes and crtcs */
  61. static void mdp5_plane_install_properties(struct drm_plane *plane,
  62. struct drm_mode_object *obj)
  63. {
  64. struct drm_device *dev = plane->dev;
  65. struct msm_drm_private *dev_priv = dev->dev_private;
  66. struct drm_property *prop;
  67. #define INSTALL_PROPERTY(name, NAME, init_val, fnc, ...) do { \
  68. prop = dev_priv->plane_property[PLANE_PROP_##NAME]; \
  69. if (!prop) { \
  70. prop = drm_property_##fnc(dev, 0, #name, \
  71. ##__VA_ARGS__); \
  72. if (!prop) { \
  73. dev_warn(dev->dev, \
  74. "Create property %s failed\n", \
  75. #name); \
  76. return; \
  77. } \
  78. dev_priv->plane_property[PLANE_PROP_##NAME] = prop; \
  79. } \
  80. drm_object_attach_property(&plane->base, prop, init_val); \
  81. } while (0)
  82. #define INSTALL_RANGE_PROPERTY(name, NAME, min, max, init_val) \
  83. INSTALL_PROPERTY(name, NAME, init_val, \
  84. create_range, min, max)
  85. #define INSTALL_ENUM_PROPERTY(name, NAME, init_val) \
  86. INSTALL_PROPERTY(name, NAME, init_val, \
  87. create_enum, name##_prop_enum_list, \
  88. ARRAY_SIZE(name##_prop_enum_list))
  89. INSTALL_RANGE_PROPERTY(zpos, ZPOS, 1, 255, 1);
  90. mdp5_plane_install_rotation_property(dev, plane);
  91. #undef INSTALL_RANGE_PROPERTY
  92. #undef INSTALL_ENUM_PROPERTY
  93. #undef INSTALL_PROPERTY
  94. }
  95. static int mdp5_plane_atomic_set_property(struct drm_plane *plane,
  96. struct drm_plane_state *state, struct drm_property *property,
  97. uint64_t val)
  98. {
  99. struct drm_device *dev = plane->dev;
  100. struct mdp5_plane_state *pstate;
  101. struct msm_drm_private *dev_priv = dev->dev_private;
  102. int ret = 0;
  103. pstate = to_mdp5_plane_state(state);
  104. #define SET_PROPERTY(name, NAME, type) do { \
  105. if (dev_priv->plane_property[PLANE_PROP_##NAME] == property) { \
  106. pstate->name = (type)val; \
  107. DBG("Set property %s %d", #name, (type)val); \
  108. goto done; \
  109. } \
  110. } while (0)
  111. SET_PROPERTY(zpos, ZPOS, uint8_t);
  112. dev_err(dev->dev, "Invalid property\n");
  113. ret = -EINVAL;
  114. done:
  115. return ret;
  116. #undef SET_PROPERTY
  117. }
  118. static int mdp5_plane_atomic_get_property(struct drm_plane *plane,
  119. const struct drm_plane_state *state,
  120. struct drm_property *property, uint64_t *val)
  121. {
  122. struct drm_device *dev = plane->dev;
  123. struct mdp5_plane_state *pstate;
  124. struct msm_drm_private *dev_priv = dev->dev_private;
  125. int ret = 0;
  126. pstate = to_mdp5_plane_state(state);
  127. #define GET_PROPERTY(name, NAME, type) do { \
  128. if (dev_priv->plane_property[PLANE_PROP_##NAME] == property) { \
  129. *val = pstate->name; \
  130. DBG("Get property %s %lld", #name, *val); \
  131. goto done; \
  132. } \
  133. } while (0)
  134. GET_PROPERTY(zpos, ZPOS, uint8_t);
  135. dev_err(dev->dev, "Invalid property\n");
  136. ret = -EINVAL;
  137. done:
  138. return ret;
  139. #undef SET_PROPERTY
  140. }
  141. static void
  142. mdp5_plane_atomic_print_state(struct drm_printer *p,
  143. const struct drm_plane_state *state)
  144. {
  145. struct mdp5_plane_state *pstate = to_mdp5_plane_state(state);
  146. drm_printf(p, "\thwpipe=%s\n", pstate->hwpipe ?
  147. pstate->hwpipe->name : "(null)");
  148. drm_printf(p, "\tpremultiplied=%u\n", pstate->premultiplied);
  149. drm_printf(p, "\tzpos=%u\n", pstate->zpos);
  150. drm_printf(p, "\talpha=%u\n", pstate->alpha);
  151. drm_printf(p, "\tstage=%s\n", stage2name(pstate->stage));
  152. }
  153. static void mdp5_plane_reset(struct drm_plane *plane)
  154. {
  155. struct mdp5_plane_state *mdp5_state;
  156. if (plane->state && plane->state->fb)
  157. drm_framebuffer_unreference(plane->state->fb);
  158. kfree(to_mdp5_plane_state(plane->state));
  159. mdp5_state = kzalloc(sizeof(*mdp5_state), GFP_KERNEL);
  160. /* assign default blend parameters */
  161. mdp5_state->alpha = 255;
  162. mdp5_state->premultiplied = 0;
  163. if (plane->type == DRM_PLANE_TYPE_PRIMARY)
  164. mdp5_state->zpos = STAGE_BASE;
  165. else
  166. mdp5_state->zpos = STAGE0 + drm_plane_index(plane);
  167. mdp5_state->base.plane = plane;
  168. plane->state = &mdp5_state->base;
  169. }
  170. static struct drm_plane_state *
  171. mdp5_plane_duplicate_state(struct drm_plane *plane)
  172. {
  173. struct mdp5_plane_state *mdp5_state;
  174. if (WARN_ON(!plane->state))
  175. return NULL;
  176. mdp5_state = kmemdup(to_mdp5_plane_state(plane->state),
  177. sizeof(*mdp5_state), GFP_KERNEL);
  178. if (mdp5_state && mdp5_state->base.fb)
  179. drm_framebuffer_reference(mdp5_state->base.fb);
  180. return &mdp5_state->base;
  181. }
  182. static void mdp5_plane_destroy_state(struct drm_plane *plane,
  183. struct drm_plane_state *state)
  184. {
  185. struct mdp5_plane_state *pstate = to_mdp5_plane_state(state);
  186. if (state->fb)
  187. drm_framebuffer_unreference(state->fb);
  188. kfree(pstate);
  189. }
  190. static const struct drm_plane_funcs mdp5_plane_funcs = {
  191. .update_plane = drm_atomic_helper_update_plane,
  192. .disable_plane = drm_atomic_helper_disable_plane,
  193. .destroy = mdp5_plane_destroy,
  194. .set_property = drm_atomic_helper_plane_set_property,
  195. .atomic_set_property = mdp5_plane_atomic_set_property,
  196. .atomic_get_property = mdp5_plane_atomic_get_property,
  197. .reset = mdp5_plane_reset,
  198. .atomic_duplicate_state = mdp5_plane_duplicate_state,
  199. .atomic_destroy_state = mdp5_plane_destroy_state,
  200. .atomic_print_state = mdp5_plane_atomic_print_state,
  201. };
  202. static int mdp5_plane_prepare_fb(struct drm_plane *plane,
  203. struct drm_plane_state *new_state)
  204. {
  205. struct mdp5_kms *mdp5_kms = get_kms(plane);
  206. struct drm_framebuffer *fb = new_state->fb;
  207. if (!new_state->fb)
  208. return 0;
  209. DBG("%s: prepare: FB[%u]", plane->name, fb->base.id);
  210. return msm_framebuffer_prepare(fb, mdp5_kms->id);
  211. }
  212. static void mdp5_plane_cleanup_fb(struct drm_plane *plane,
  213. struct drm_plane_state *old_state)
  214. {
  215. struct mdp5_kms *mdp5_kms = get_kms(plane);
  216. struct drm_framebuffer *fb = old_state->fb;
  217. if (!fb)
  218. return;
  219. DBG("%s: cleanup: FB[%u]", plane->name, fb->base.id);
  220. msm_framebuffer_cleanup(fb, mdp5_kms->id);
  221. }
  222. static int mdp5_plane_atomic_check(struct drm_plane *plane,
  223. struct drm_plane_state *state)
  224. {
  225. struct mdp5_plane_state *mdp5_state = to_mdp5_plane_state(state);
  226. struct drm_plane_state *old_state = plane->state;
  227. struct mdp5_cfg *config = mdp5_cfg_get_config(get_kms(plane)->cfg);
  228. bool new_hwpipe = false;
  229. uint32_t max_width, max_height;
  230. uint32_t caps = 0;
  231. DBG("%s: check (%d -> %d)", plane->name,
  232. plane_enabled(old_state), plane_enabled(state));
  233. max_width = config->hw->lm.max_width << 16;
  234. max_height = config->hw->lm.max_height << 16;
  235. /* Make sure source dimensions are within bounds. */
  236. if ((state->src_w > max_width) || (state->src_h > max_height)) {
  237. struct drm_rect src = drm_plane_state_src(state);
  238. DBG("Invalid source size "DRM_RECT_FP_FMT,
  239. DRM_RECT_FP_ARG(&src));
  240. return -ERANGE;
  241. }
  242. if (plane_enabled(state)) {
  243. unsigned int rotation;
  244. const struct mdp_format *format;
  245. struct mdp5_kms *mdp5_kms = get_kms(plane);
  246. uint32_t blkcfg = 0;
  247. format = to_mdp_format(msm_framebuffer_format(state->fb));
  248. if (MDP_FORMAT_IS_YUV(format))
  249. caps |= MDP_PIPE_CAP_SCALE | MDP_PIPE_CAP_CSC;
  250. if (((state->src_w >> 16) != state->crtc_w) ||
  251. ((state->src_h >> 16) != state->crtc_h))
  252. caps |= MDP_PIPE_CAP_SCALE;
  253. rotation = drm_rotation_simplify(state->rotation,
  254. DRM_ROTATE_0 |
  255. DRM_REFLECT_X |
  256. DRM_REFLECT_Y);
  257. if (rotation & DRM_REFLECT_X)
  258. caps |= MDP_PIPE_CAP_HFLIP;
  259. if (rotation & DRM_REFLECT_Y)
  260. caps |= MDP_PIPE_CAP_VFLIP;
  261. /* (re)allocate hw pipe if we don't have one or caps-mismatch: */
  262. if (!mdp5_state->hwpipe || (caps & ~mdp5_state->hwpipe->caps))
  263. new_hwpipe = true;
  264. if (mdp5_kms->smp) {
  265. const struct mdp_format *format =
  266. to_mdp_format(msm_framebuffer_format(state->fb));
  267. blkcfg = mdp5_smp_calculate(mdp5_kms->smp, format,
  268. state->src_w >> 16, false);
  269. if (mdp5_state->hwpipe && (mdp5_state->hwpipe->blkcfg != blkcfg))
  270. new_hwpipe = true;
  271. }
  272. /* (re)assign hwpipe if needed, otherwise keep old one: */
  273. if (new_hwpipe) {
  274. /* TODO maybe we want to re-assign hwpipe sometimes
  275. * in cases when we no-longer need some caps to make
  276. * it available for other planes?
  277. */
  278. struct mdp5_hw_pipe *old_hwpipe = mdp5_state->hwpipe;
  279. mdp5_state->hwpipe = mdp5_pipe_assign(state->state,
  280. plane, caps, blkcfg);
  281. if (IS_ERR(mdp5_state->hwpipe)) {
  282. DBG("%s: failed to assign hwpipe!", plane->name);
  283. return PTR_ERR(mdp5_state->hwpipe);
  284. }
  285. mdp5_pipe_release(state->state, old_hwpipe);
  286. }
  287. }
  288. return 0;
  289. }
  290. static void mdp5_plane_atomic_update(struct drm_plane *plane,
  291. struct drm_plane_state *old_state)
  292. {
  293. struct drm_plane_state *state = plane->state;
  294. DBG("%s: update", plane->name);
  295. if (plane_enabled(state)) {
  296. int ret;
  297. ret = mdp5_plane_mode_set(plane,
  298. state->crtc, state->fb,
  299. state->crtc_x, state->crtc_y,
  300. state->crtc_w, state->crtc_h,
  301. state->src_x, state->src_y,
  302. state->src_w, state->src_h);
  303. /* atomic_check should have ensured that this doesn't fail */
  304. WARN_ON(ret < 0);
  305. }
  306. }
  307. static const struct drm_plane_helper_funcs mdp5_plane_helper_funcs = {
  308. .prepare_fb = mdp5_plane_prepare_fb,
  309. .cleanup_fb = mdp5_plane_cleanup_fb,
  310. .atomic_check = mdp5_plane_atomic_check,
  311. .atomic_update = mdp5_plane_atomic_update,
  312. };
  313. static void set_scanout_locked(struct drm_plane *plane,
  314. struct drm_framebuffer *fb)
  315. {
  316. struct mdp5_kms *mdp5_kms = get_kms(plane);
  317. struct mdp5_hw_pipe *hwpipe = to_mdp5_plane_state(plane->state)->hwpipe;
  318. enum mdp5_pipe pipe = hwpipe->pipe;
  319. mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_STRIDE_A(pipe),
  320. MDP5_PIPE_SRC_STRIDE_A_P0(fb->pitches[0]) |
  321. MDP5_PIPE_SRC_STRIDE_A_P1(fb->pitches[1]));
  322. mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_STRIDE_B(pipe),
  323. MDP5_PIPE_SRC_STRIDE_B_P2(fb->pitches[2]) |
  324. MDP5_PIPE_SRC_STRIDE_B_P3(fb->pitches[3]));
  325. mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC0_ADDR(pipe),
  326. msm_framebuffer_iova(fb, mdp5_kms->id, 0));
  327. mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC1_ADDR(pipe),
  328. msm_framebuffer_iova(fb, mdp5_kms->id, 1));
  329. mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC2_ADDR(pipe),
  330. msm_framebuffer_iova(fb, mdp5_kms->id, 2));
  331. mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC3_ADDR(pipe),
  332. msm_framebuffer_iova(fb, mdp5_kms->id, 3));
  333. plane->fb = fb;
  334. }
  335. /* Note: mdp5_plane->pipe_lock must be locked */
  336. static void csc_disable(struct mdp5_kms *mdp5_kms, enum mdp5_pipe pipe)
  337. {
  338. uint32_t value = mdp5_read(mdp5_kms, REG_MDP5_PIPE_OP_MODE(pipe)) &
  339. ~MDP5_PIPE_OP_MODE_CSC_1_EN;
  340. mdp5_write(mdp5_kms, REG_MDP5_PIPE_OP_MODE(pipe), value);
  341. }
  342. /* Note: mdp5_plane->pipe_lock must be locked */
  343. static void csc_enable(struct mdp5_kms *mdp5_kms, enum mdp5_pipe pipe,
  344. struct csc_cfg *csc)
  345. {
  346. uint32_t i, mode = 0; /* RGB, no CSC */
  347. uint32_t *matrix;
  348. if (unlikely(!csc))
  349. return;
  350. if ((csc->type == CSC_YUV2RGB) || (CSC_YUV2YUV == csc->type))
  351. mode |= MDP5_PIPE_OP_MODE_CSC_SRC_DATA_FORMAT(DATA_FORMAT_YUV);
  352. if ((csc->type == CSC_RGB2YUV) || (CSC_YUV2YUV == csc->type))
  353. mode |= MDP5_PIPE_OP_MODE_CSC_DST_DATA_FORMAT(DATA_FORMAT_YUV);
  354. mode |= MDP5_PIPE_OP_MODE_CSC_1_EN;
  355. mdp5_write(mdp5_kms, REG_MDP5_PIPE_OP_MODE(pipe), mode);
  356. matrix = csc->matrix;
  357. mdp5_write(mdp5_kms, REG_MDP5_PIPE_CSC_1_MATRIX_COEFF_0(pipe),
  358. MDP5_PIPE_CSC_1_MATRIX_COEFF_0_COEFF_11(matrix[0]) |
  359. MDP5_PIPE_CSC_1_MATRIX_COEFF_0_COEFF_12(matrix[1]));
  360. mdp5_write(mdp5_kms, REG_MDP5_PIPE_CSC_1_MATRIX_COEFF_1(pipe),
  361. MDP5_PIPE_CSC_1_MATRIX_COEFF_1_COEFF_13(matrix[2]) |
  362. MDP5_PIPE_CSC_1_MATRIX_COEFF_1_COEFF_21(matrix[3]));
  363. mdp5_write(mdp5_kms, REG_MDP5_PIPE_CSC_1_MATRIX_COEFF_2(pipe),
  364. MDP5_PIPE_CSC_1_MATRIX_COEFF_2_COEFF_22(matrix[4]) |
  365. MDP5_PIPE_CSC_1_MATRIX_COEFF_2_COEFF_23(matrix[5]));
  366. mdp5_write(mdp5_kms, REG_MDP5_PIPE_CSC_1_MATRIX_COEFF_3(pipe),
  367. MDP5_PIPE_CSC_1_MATRIX_COEFF_3_COEFF_31(matrix[6]) |
  368. MDP5_PIPE_CSC_1_MATRIX_COEFF_3_COEFF_32(matrix[7]));
  369. mdp5_write(mdp5_kms, REG_MDP5_PIPE_CSC_1_MATRIX_COEFF_4(pipe),
  370. MDP5_PIPE_CSC_1_MATRIX_COEFF_4_COEFF_33(matrix[8]));
  371. for (i = 0; i < ARRAY_SIZE(csc->pre_bias); i++) {
  372. uint32_t *pre_clamp = csc->pre_clamp;
  373. uint32_t *post_clamp = csc->post_clamp;
  374. mdp5_write(mdp5_kms, REG_MDP5_PIPE_CSC_1_PRE_CLAMP(pipe, i),
  375. MDP5_PIPE_CSC_1_PRE_CLAMP_REG_HIGH(pre_clamp[2*i+1]) |
  376. MDP5_PIPE_CSC_1_PRE_CLAMP_REG_LOW(pre_clamp[2*i]));
  377. mdp5_write(mdp5_kms, REG_MDP5_PIPE_CSC_1_POST_CLAMP(pipe, i),
  378. MDP5_PIPE_CSC_1_POST_CLAMP_REG_HIGH(post_clamp[2*i+1]) |
  379. MDP5_PIPE_CSC_1_POST_CLAMP_REG_LOW(post_clamp[2*i]));
  380. mdp5_write(mdp5_kms, REG_MDP5_PIPE_CSC_1_PRE_BIAS(pipe, i),
  381. MDP5_PIPE_CSC_1_PRE_BIAS_REG_VALUE(csc->pre_bias[i]));
  382. mdp5_write(mdp5_kms, REG_MDP5_PIPE_CSC_1_POST_BIAS(pipe, i),
  383. MDP5_PIPE_CSC_1_POST_BIAS_REG_VALUE(csc->post_bias[i]));
  384. }
  385. }
  386. #define PHASE_STEP_SHIFT 21
  387. #define DOWN_SCALE_RATIO_MAX 32 /* 2^(26-21) */
  388. static int calc_phase_step(uint32_t src, uint32_t dst, uint32_t *out_phase)
  389. {
  390. uint32_t unit;
  391. if (src == 0 || dst == 0)
  392. return -EINVAL;
  393. /*
  394. * PHASE_STEP_X/Y is coded on 26 bits (25:0),
  395. * where 2^21 represents the unity "1" in fixed-point hardware design.
  396. * This leaves 5 bits for the integer part (downscale case):
  397. * -> maximum downscale ratio = 0b1_1111 = 31
  398. */
  399. if (src > (dst * DOWN_SCALE_RATIO_MAX))
  400. return -EOVERFLOW;
  401. unit = 1 << PHASE_STEP_SHIFT;
  402. *out_phase = mult_frac(unit, src, dst);
  403. return 0;
  404. }
  405. static int calc_scalex_steps(struct drm_plane *plane,
  406. uint32_t pixel_format, uint32_t src, uint32_t dest,
  407. uint32_t phasex_steps[COMP_MAX])
  408. {
  409. struct mdp5_kms *mdp5_kms = get_kms(plane);
  410. struct device *dev = mdp5_kms->dev->dev;
  411. uint32_t phasex_step;
  412. unsigned int hsub;
  413. int ret;
  414. ret = calc_phase_step(src, dest, &phasex_step);
  415. if (ret) {
  416. dev_err(dev, "X scaling (%d->%d) failed: %d\n", src, dest, ret);
  417. return ret;
  418. }
  419. hsub = drm_format_horz_chroma_subsampling(pixel_format);
  420. phasex_steps[COMP_0] = phasex_step;
  421. phasex_steps[COMP_3] = phasex_step;
  422. phasex_steps[COMP_1_2] = phasex_step / hsub;
  423. return 0;
  424. }
  425. static int calc_scaley_steps(struct drm_plane *plane,
  426. uint32_t pixel_format, uint32_t src, uint32_t dest,
  427. uint32_t phasey_steps[COMP_MAX])
  428. {
  429. struct mdp5_kms *mdp5_kms = get_kms(plane);
  430. struct device *dev = mdp5_kms->dev->dev;
  431. uint32_t phasey_step;
  432. unsigned int vsub;
  433. int ret;
  434. ret = calc_phase_step(src, dest, &phasey_step);
  435. if (ret) {
  436. dev_err(dev, "Y scaling (%d->%d) failed: %d\n", src, dest, ret);
  437. return ret;
  438. }
  439. vsub = drm_format_vert_chroma_subsampling(pixel_format);
  440. phasey_steps[COMP_0] = phasey_step;
  441. phasey_steps[COMP_3] = phasey_step;
  442. phasey_steps[COMP_1_2] = phasey_step / vsub;
  443. return 0;
  444. }
  445. static uint32_t get_scale_config(const struct mdp_format *format,
  446. uint32_t src, uint32_t dst, bool horz)
  447. {
  448. bool scaling = format->is_yuv ? true : (src != dst);
  449. uint32_t sub, pix_fmt = format->base.pixel_format;
  450. uint32_t ya_filter, uv_filter;
  451. bool yuv = format->is_yuv;
  452. if (!scaling)
  453. return 0;
  454. if (yuv) {
  455. sub = horz ? drm_format_horz_chroma_subsampling(pix_fmt) :
  456. drm_format_vert_chroma_subsampling(pix_fmt);
  457. uv_filter = ((src / sub) <= dst) ?
  458. SCALE_FILTER_BIL : SCALE_FILTER_PCMN;
  459. }
  460. ya_filter = (src <= dst) ? SCALE_FILTER_BIL : SCALE_FILTER_PCMN;
  461. if (horz)
  462. return MDP5_PIPE_SCALE_CONFIG_SCALEX_EN |
  463. MDP5_PIPE_SCALE_CONFIG_SCALEX_FILTER_COMP_0(ya_filter) |
  464. MDP5_PIPE_SCALE_CONFIG_SCALEX_FILTER_COMP_3(ya_filter) |
  465. COND(yuv, MDP5_PIPE_SCALE_CONFIG_SCALEX_FILTER_COMP_1_2(uv_filter));
  466. else
  467. return MDP5_PIPE_SCALE_CONFIG_SCALEY_EN |
  468. MDP5_PIPE_SCALE_CONFIG_SCALEY_FILTER_COMP_0(ya_filter) |
  469. MDP5_PIPE_SCALE_CONFIG_SCALEY_FILTER_COMP_3(ya_filter) |
  470. COND(yuv, MDP5_PIPE_SCALE_CONFIG_SCALEY_FILTER_COMP_1_2(uv_filter));
  471. }
  472. static void calc_pixel_ext(const struct mdp_format *format,
  473. uint32_t src, uint32_t dst, uint32_t phase_step[2],
  474. int pix_ext_edge1[COMP_MAX], int pix_ext_edge2[COMP_MAX],
  475. bool horz)
  476. {
  477. bool scaling = format->is_yuv ? true : (src != dst);
  478. int i;
  479. /*
  480. * Note:
  481. * We assume here that:
  482. * 1. PCMN filter is used for downscale
  483. * 2. bilinear filter is used for upscale
  484. * 3. we are in a single pipe configuration
  485. */
  486. for (i = 0; i < COMP_MAX; i++) {
  487. pix_ext_edge1[i] = 0;
  488. pix_ext_edge2[i] = scaling ? 1 : 0;
  489. }
  490. }
  491. static void mdp5_write_pixel_ext(struct mdp5_kms *mdp5_kms, enum mdp5_pipe pipe,
  492. const struct mdp_format *format,
  493. uint32_t src_w, int pe_left[COMP_MAX], int pe_right[COMP_MAX],
  494. uint32_t src_h, int pe_top[COMP_MAX], int pe_bottom[COMP_MAX])
  495. {
  496. uint32_t pix_fmt = format->base.pixel_format;
  497. uint32_t lr, tb, req;
  498. int i;
  499. for (i = 0; i < COMP_MAX; i++) {
  500. uint32_t roi_w = src_w;
  501. uint32_t roi_h = src_h;
  502. if (format->is_yuv && i == COMP_1_2) {
  503. roi_w /= drm_format_horz_chroma_subsampling(pix_fmt);
  504. roi_h /= drm_format_vert_chroma_subsampling(pix_fmt);
  505. }
  506. lr = (pe_left[i] >= 0) ?
  507. MDP5_PIPE_SW_PIX_EXT_LR_LEFT_RPT(pe_left[i]) :
  508. MDP5_PIPE_SW_PIX_EXT_LR_LEFT_OVF(pe_left[i]);
  509. lr |= (pe_right[i] >= 0) ?
  510. MDP5_PIPE_SW_PIX_EXT_LR_RIGHT_RPT(pe_right[i]) :
  511. MDP5_PIPE_SW_PIX_EXT_LR_RIGHT_OVF(pe_right[i]);
  512. tb = (pe_top[i] >= 0) ?
  513. MDP5_PIPE_SW_PIX_EXT_TB_TOP_RPT(pe_top[i]) :
  514. MDP5_PIPE_SW_PIX_EXT_TB_TOP_OVF(pe_top[i]);
  515. tb |= (pe_bottom[i] >= 0) ?
  516. MDP5_PIPE_SW_PIX_EXT_TB_BOTTOM_RPT(pe_bottom[i]) :
  517. MDP5_PIPE_SW_PIX_EXT_TB_BOTTOM_OVF(pe_bottom[i]);
  518. req = MDP5_PIPE_SW_PIX_EXT_REQ_PIXELS_LEFT_RIGHT(roi_w +
  519. pe_left[i] + pe_right[i]);
  520. req |= MDP5_PIPE_SW_PIX_EXT_REQ_PIXELS_TOP_BOTTOM(roi_h +
  521. pe_top[i] + pe_bottom[i]);
  522. mdp5_write(mdp5_kms, REG_MDP5_PIPE_SW_PIX_EXT_LR(pipe, i), lr);
  523. mdp5_write(mdp5_kms, REG_MDP5_PIPE_SW_PIX_EXT_TB(pipe, i), tb);
  524. mdp5_write(mdp5_kms, REG_MDP5_PIPE_SW_PIX_EXT_REQ_PIXELS(pipe, i), req);
  525. DBG("comp-%d (L/R): rpt=%d/%d, ovf=%d/%d, req=%d", i,
  526. FIELD(lr, MDP5_PIPE_SW_PIX_EXT_LR_LEFT_RPT),
  527. FIELD(lr, MDP5_PIPE_SW_PIX_EXT_LR_RIGHT_RPT),
  528. FIELD(lr, MDP5_PIPE_SW_PIX_EXT_LR_LEFT_OVF),
  529. FIELD(lr, MDP5_PIPE_SW_PIX_EXT_LR_RIGHT_OVF),
  530. FIELD(req, MDP5_PIPE_SW_PIX_EXT_REQ_PIXELS_LEFT_RIGHT));
  531. DBG("comp-%d (T/B): rpt=%d/%d, ovf=%d/%d, req=%d", i,
  532. FIELD(tb, MDP5_PIPE_SW_PIX_EXT_TB_TOP_RPT),
  533. FIELD(tb, MDP5_PIPE_SW_PIX_EXT_TB_BOTTOM_RPT),
  534. FIELD(tb, MDP5_PIPE_SW_PIX_EXT_TB_TOP_OVF),
  535. FIELD(tb, MDP5_PIPE_SW_PIX_EXT_TB_BOTTOM_OVF),
  536. FIELD(req, MDP5_PIPE_SW_PIX_EXT_REQ_PIXELS_TOP_BOTTOM));
  537. }
  538. }
  539. static int mdp5_plane_mode_set(struct drm_plane *plane,
  540. struct drm_crtc *crtc, struct drm_framebuffer *fb,
  541. int crtc_x, int crtc_y,
  542. unsigned int crtc_w, unsigned int crtc_h,
  543. uint32_t src_x, uint32_t src_y,
  544. uint32_t src_w, uint32_t src_h)
  545. {
  546. struct drm_plane_state *pstate = plane->state;
  547. struct mdp5_hw_pipe *hwpipe = to_mdp5_plane_state(pstate)->hwpipe;
  548. struct mdp5_kms *mdp5_kms = get_kms(plane);
  549. enum mdp5_pipe pipe = hwpipe->pipe;
  550. const struct mdp_format *format;
  551. uint32_t nplanes, config = 0;
  552. uint32_t phasex_step[COMP_MAX] = {0,}, phasey_step[COMP_MAX] = {0,};
  553. bool pe = hwpipe->caps & MDP_PIPE_CAP_SW_PIX_EXT;
  554. int pe_left[COMP_MAX], pe_right[COMP_MAX];
  555. int pe_top[COMP_MAX], pe_bottom[COMP_MAX];
  556. uint32_t hdecm = 0, vdecm = 0;
  557. uint32_t pix_format;
  558. unsigned int rotation;
  559. bool vflip, hflip;
  560. unsigned long flags;
  561. int ret;
  562. nplanes = fb->format->num_planes;
  563. /* bad formats should already be rejected: */
  564. if (WARN_ON(nplanes > pipe2nclients(pipe)))
  565. return -EINVAL;
  566. format = to_mdp_format(msm_framebuffer_format(fb));
  567. pix_format = format->base.pixel_format;
  568. /* src values are in Q16 fixed point, convert to integer: */
  569. src_x = src_x >> 16;
  570. src_y = src_y >> 16;
  571. src_w = src_w >> 16;
  572. src_h = src_h >> 16;
  573. DBG("%s: FB[%u] %u,%u,%u,%u -> CRTC[%u] %d,%d,%u,%u", plane->name,
  574. fb->base.id, src_x, src_y, src_w, src_h,
  575. crtc->base.id, crtc_x, crtc_y, crtc_w, crtc_h);
  576. ret = calc_scalex_steps(plane, pix_format, src_w, crtc_w, phasex_step);
  577. if (ret)
  578. return ret;
  579. ret = calc_scaley_steps(plane, pix_format, src_h, crtc_h, phasey_step);
  580. if (ret)
  581. return ret;
  582. if (hwpipe->caps & MDP_PIPE_CAP_SW_PIX_EXT) {
  583. calc_pixel_ext(format, src_w, crtc_w, phasex_step,
  584. pe_left, pe_right, true);
  585. calc_pixel_ext(format, src_h, crtc_h, phasey_step,
  586. pe_top, pe_bottom, false);
  587. }
  588. /* TODO calc hdecm, vdecm */
  589. /* SCALE is used to both scale and up-sample chroma components */
  590. config |= get_scale_config(format, src_w, crtc_w, true);
  591. config |= get_scale_config(format, src_h, crtc_h, false);
  592. DBG("scale config = %x", config);
  593. rotation = drm_rotation_simplify(pstate->rotation,
  594. DRM_ROTATE_0 |
  595. DRM_REFLECT_X |
  596. DRM_REFLECT_Y);
  597. hflip = !!(rotation & DRM_REFLECT_X);
  598. vflip = !!(rotation & DRM_REFLECT_Y);
  599. spin_lock_irqsave(&hwpipe->pipe_lock, flags);
  600. mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_IMG_SIZE(pipe),
  601. MDP5_PIPE_SRC_IMG_SIZE_WIDTH(min(fb->width, src_w)) |
  602. MDP5_PIPE_SRC_IMG_SIZE_HEIGHT(min(fb->height, src_h)));
  603. mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_SIZE(pipe),
  604. MDP5_PIPE_SRC_SIZE_WIDTH(src_w) |
  605. MDP5_PIPE_SRC_SIZE_HEIGHT(src_h));
  606. mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_XY(pipe),
  607. MDP5_PIPE_SRC_XY_X(src_x) |
  608. MDP5_PIPE_SRC_XY_Y(src_y));
  609. mdp5_write(mdp5_kms, REG_MDP5_PIPE_OUT_SIZE(pipe),
  610. MDP5_PIPE_OUT_SIZE_WIDTH(crtc_w) |
  611. MDP5_PIPE_OUT_SIZE_HEIGHT(crtc_h));
  612. mdp5_write(mdp5_kms, REG_MDP5_PIPE_OUT_XY(pipe),
  613. MDP5_PIPE_OUT_XY_X(crtc_x) |
  614. MDP5_PIPE_OUT_XY_Y(crtc_y));
  615. mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_FORMAT(pipe),
  616. MDP5_PIPE_SRC_FORMAT_A_BPC(format->bpc_a) |
  617. MDP5_PIPE_SRC_FORMAT_R_BPC(format->bpc_r) |
  618. MDP5_PIPE_SRC_FORMAT_G_BPC(format->bpc_g) |
  619. MDP5_PIPE_SRC_FORMAT_B_BPC(format->bpc_b) |
  620. COND(format->alpha_enable, MDP5_PIPE_SRC_FORMAT_ALPHA_ENABLE) |
  621. MDP5_PIPE_SRC_FORMAT_CPP(format->cpp - 1) |
  622. MDP5_PIPE_SRC_FORMAT_UNPACK_COUNT(format->unpack_count - 1) |
  623. COND(format->unpack_tight, MDP5_PIPE_SRC_FORMAT_UNPACK_TIGHT) |
  624. MDP5_PIPE_SRC_FORMAT_FETCH_TYPE(format->fetch_type) |
  625. MDP5_PIPE_SRC_FORMAT_CHROMA_SAMP(format->chroma_sample));
  626. mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_UNPACK(pipe),
  627. MDP5_PIPE_SRC_UNPACK_ELEM0(format->unpack[0]) |
  628. MDP5_PIPE_SRC_UNPACK_ELEM1(format->unpack[1]) |
  629. MDP5_PIPE_SRC_UNPACK_ELEM2(format->unpack[2]) |
  630. MDP5_PIPE_SRC_UNPACK_ELEM3(format->unpack[3]));
  631. mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_OP_MODE(pipe),
  632. (hflip ? MDP5_PIPE_SRC_OP_MODE_FLIP_LR : 0) |
  633. (vflip ? MDP5_PIPE_SRC_OP_MODE_FLIP_UD : 0) |
  634. COND(pe, MDP5_PIPE_SRC_OP_MODE_SW_PIX_EXT_OVERRIDE) |
  635. MDP5_PIPE_SRC_OP_MODE_BWC(BWC_LOSSLESS));
  636. /* not using secure mode: */
  637. mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_ADDR_SW_STATUS(pipe), 0);
  638. if (hwpipe->caps & MDP_PIPE_CAP_SW_PIX_EXT)
  639. mdp5_write_pixel_ext(mdp5_kms, pipe, format,
  640. src_w, pe_left, pe_right,
  641. src_h, pe_top, pe_bottom);
  642. if (hwpipe->caps & MDP_PIPE_CAP_SCALE) {
  643. mdp5_write(mdp5_kms, REG_MDP5_PIPE_SCALE_PHASE_STEP_X(pipe),
  644. phasex_step[COMP_0]);
  645. mdp5_write(mdp5_kms, REG_MDP5_PIPE_SCALE_PHASE_STEP_Y(pipe),
  646. phasey_step[COMP_0]);
  647. mdp5_write(mdp5_kms, REG_MDP5_PIPE_SCALE_CR_PHASE_STEP_X(pipe),
  648. phasex_step[COMP_1_2]);
  649. mdp5_write(mdp5_kms, REG_MDP5_PIPE_SCALE_CR_PHASE_STEP_Y(pipe),
  650. phasey_step[COMP_1_2]);
  651. mdp5_write(mdp5_kms, REG_MDP5_PIPE_DECIMATION(pipe),
  652. MDP5_PIPE_DECIMATION_VERT(vdecm) |
  653. MDP5_PIPE_DECIMATION_HORZ(hdecm));
  654. mdp5_write(mdp5_kms, REG_MDP5_PIPE_SCALE_CONFIG(pipe), config);
  655. }
  656. if (hwpipe->caps & MDP_PIPE_CAP_CSC) {
  657. if (MDP_FORMAT_IS_YUV(format))
  658. csc_enable(mdp5_kms, pipe,
  659. mdp_get_default_csc_cfg(CSC_YUV2RGB));
  660. else
  661. csc_disable(mdp5_kms, pipe);
  662. }
  663. set_scanout_locked(plane, fb);
  664. spin_unlock_irqrestore(&hwpipe->pipe_lock, flags);
  665. return ret;
  666. }
  667. enum mdp5_pipe mdp5_plane_pipe(struct drm_plane *plane)
  668. {
  669. struct mdp5_plane_state *pstate = to_mdp5_plane_state(plane->state);
  670. if (WARN_ON(!pstate->hwpipe))
  671. return 0;
  672. return pstate->hwpipe->pipe;
  673. }
  674. uint32_t mdp5_plane_get_flush(struct drm_plane *plane)
  675. {
  676. struct mdp5_plane_state *pstate = to_mdp5_plane_state(plane->state);
  677. if (WARN_ON(!pstate->hwpipe))
  678. return 0;
  679. return pstate->hwpipe->flush_mask;
  680. }
  681. /* initialize plane */
  682. struct drm_plane *mdp5_plane_init(struct drm_device *dev, bool primary)
  683. {
  684. struct drm_plane *plane = NULL;
  685. struct mdp5_plane *mdp5_plane;
  686. int ret;
  687. enum drm_plane_type type;
  688. mdp5_plane = kzalloc(sizeof(*mdp5_plane), GFP_KERNEL);
  689. if (!mdp5_plane) {
  690. ret = -ENOMEM;
  691. goto fail;
  692. }
  693. plane = &mdp5_plane->base;
  694. mdp5_plane->nformats = mdp_get_formats(mdp5_plane->formats,
  695. ARRAY_SIZE(mdp5_plane->formats), false);
  696. type = primary ? DRM_PLANE_TYPE_PRIMARY : DRM_PLANE_TYPE_OVERLAY;
  697. ret = drm_universal_plane_init(dev, plane, 0xff, &mdp5_plane_funcs,
  698. mdp5_plane->formats, mdp5_plane->nformats,
  699. type, NULL);
  700. if (ret)
  701. goto fail;
  702. drm_plane_helper_add(plane, &mdp5_plane_helper_funcs);
  703. mdp5_plane_install_properties(plane, &plane->base);
  704. return plane;
  705. fail:
  706. if (plane)
  707. mdp5_plane_destroy(plane);
  708. return ERR_PTR(ret);
  709. }