mdp5_plane.c 32 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127
  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. struct drm_rect *src, struct drm_rect *dest);
  29. static struct mdp5_kms *get_kms(struct drm_plane *plane)
  30. {
  31. struct msm_drm_private *priv = plane->dev->dev_private;
  32. return to_mdp5_kms(to_mdp_kms(priv->kms));
  33. }
  34. static bool plane_enabled(struct drm_plane_state *state)
  35. {
  36. return state->visible;
  37. }
  38. static void mdp5_plane_destroy(struct drm_plane *plane)
  39. {
  40. struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane);
  41. drm_plane_helper_disable(plane);
  42. drm_plane_cleanup(plane);
  43. kfree(mdp5_plane);
  44. }
  45. static void mdp5_plane_install_rotation_property(struct drm_device *dev,
  46. struct drm_plane *plane)
  47. {
  48. drm_plane_create_rotation_property(plane,
  49. DRM_MODE_ROTATE_0,
  50. DRM_MODE_ROTATE_0 |
  51. DRM_MODE_ROTATE_180 |
  52. DRM_MODE_REFLECT_X |
  53. DRM_MODE_REFLECT_Y);
  54. }
  55. /* helper to install properties which are common to planes and crtcs */
  56. static void mdp5_plane_install_properties(struct drm_plane *plane,
  57. struct drm_mode_object *obj)
  58. {
  59. struct drm_device *dev = plane->dev;
  60. struct msm_drm_private *dev_priv = dev->dev_private;
  61. struct drm_property *prop;
  62. #define INSTALL_PROPERTY(name, NAME, init_val, fnc, ...) do { \
  63. prop = dev_priv->plane_property[PLANE_PROP_##NAME]; \
  64. if (!prop) { \
  65. prop = drm_property_##fnc(dev, 0, #name, \
  66. ##__VA_ARGS__); \
  67. if (!prop) { \
  68. dev_warn(dev->dev, \
  69. "Create property %s failed\n", \
  70. #name); \
  71. return; \
  72. } \
  73. dev_priv->plane_property[PLANE_PROP_##NAME] = prop; \
  74. } \
  75. drm_object_attach_property(&plane->base, prop, init_val); \
  76. } while (0)
  77. #define INSTALL_RANGE_PROPERTY(name, NAME, min, max, init_val) \
  78. INSTALL_PROPERTY(name, NAME, init_val, \
  79. create_range, min, max)
  80. #define INSTALL_ENUM_PROPERTY(name, NAME, init_val) \
  81. INSTALL_PROPERTY(name, NAME, init_val, \
  82. create_enum, name##_prop_enum_list, \
  83. ARRAY_SIZE(name##_prop_enum_list))
  84. INSTALL_RANGE_PROPERTY(zpos, ZPOS, 1, 255, 1);
  85. mdp5_plane_install_rotation_property(dev, plane);
  86. #undef INSTALL_RANGE_PROPERTY
  87. #undef INSTALL_ENUM_PROPERTY
  88. #undef INSTALL_PROPERTY
  89. }
  90. static int mdp5_plane_atomic_set_property(struct drm_plane *plane,
  91. struct drm_plane_state *state, struct drm_property *property,
  92. uint64_t val)
  93. {
  94. struct drm_device *dev = plane->dev;
  95. struct mdp5_plane_state *pstate;
  96. struct msm_drm_private *dev_priv = dev->dev_private;
  97. int ret = 0;
  98. pstate = to_mdp5_plane_state(state);
  99. #define SET_PROPERTY(name, NAME, type) do { \
  100. if (dev_priv->plane_property[PLANE_PROP_##NAME] == property) { \
  101. pstate->name = (type)val; \
  102. DBG("Set property %s %d", #name, (type)val); \
  103. goto done; \
  104. } \
  105. } while (0)
  106. SET_PROPERTY(zpos, ZPOS, uint8_t);
  107. dev_err(dev->dev, "Invalid property\n");
  108. ret = -EINVAL;
  109. done:
  110. return ret;
  111. #undef SET_PROPERTY
  112. }
  113. static int mdp5_plane_atomic_get_property(struct drm_plane *plane,
  114. const struct drm_plane_state *state,
  115. struct drm_property *property, uint64_t *val)
  116. {
  117. struct drm_device *dev = plane->dev;
  118. struct mdp5_plane_state *pstate;
  119. struct msm_drm_private *dev_priv = dev->dev_private;
  120. int ret = 0;
  121. pstate = to_mdp5_plane_state(state);
  122. #define GET_PROPERTY(name, NAME, type) do { \
  123. if (dev_priv->plane_property[PLANE_PROP_##NAME] == property) { \
  124. *val = pstate->name; \
  125. DBG("Get property %s %lld", #name, *val); \
  126. goto done; \
  127. } \
  128. } while (0)
  129. GET_PROPERTY(zpos, ZPOS, uint8_t);
  130. dev_err(dev->dev, "Invalid property\n");
  131. ret = -EINVAL;
  132. done:
  133. return ret;
  134. #undef SET_PROPERTY
  135. }
  136. static void
  137. mdp5_plane_atomic_print_state(struct drm_printer *p,
  138. const struct drm_plane_state *state)
  139. {
  140. struct mdp5_plane_state *pstate = to_mdp5_plane_state(state);
  141. struct mdp5_kms *mdp5_kms = get_kms(state->plane);
  142. drm_printf(p, "\thwpipe=%s\n", pstate->hwpipe ?
  143. pstate->hwpipe->name : "(null)");
  144. if (mdp5_kms->caps & MDP_CAP_SRC_SPLIT)
  145. drm_printf(p, "\tright-hwpipe=%s\n",
  146. pstate->r_hwpipe ? pstate->r_hwpipe->name :
  147. "(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)
  179. return NULL;
  180. __drm_atomic_helper_plane_duplicate_state(plane, &mdp5_state->base);
  181. return &mdp5_state->base;
  182. }
  183. static void mdp5_plane_destroy_state(struct drm_plane *plane,
  184. struct drm_plane_state *state)
  185. {
  186. struct mdp5_plane_state *pstate = to_mdp5_plane_state(state);
  187. if (state->fb)
  188. drm_framebuffer_unreference(state->fb);
  189. kfree(pstate);
  190. }
  191. static const struct drm_plane_funcs mdp5_plane_funcs = {
  192. .update_plane = drm_atomic_helper_update_plane,
  193. .disable_plane = drm_atomic_helper_disable_plane,
  194. .destroy = mdp5_plane_destroy,
  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 msm_kms *kms = &mdp5_kms->base.base;
  207. struct drm_framebuffer *fb = new_state->fb;
  208. if (!new_state->fb)
  209. return 0;
  210. DBG("%s: prepare: FB[%u]", plane->name, fb->base.id);
  211. return msm_framebuffer_prepare(fb, kms->aspace);
  212. }
  213. static void mdp5_plane_cleanup_fb(struct drm_plane *plane,
  214. struct drm_plane_state *old_state)
  215. {
  216. struct mdp5_kms *mdp5_kms = get_kms(plane);
  217. struct msm_kms *kms = &mdp5_kms->base.base;
  218. struct drm_framebuffer *fb = old_state->fb;
  219. if (!fb)
  220. return;
  221. DBG("%s: cleanup: FB[%u]", plane->name, fb->base.id);
  222. msm_framebuffer_cleanup(fb, kms->aspace);
  223. }
  224. #define FRAC_16_16(mult, div) (((mult) << 16) / (div))
  225. static int mdp5_plane_atomic_check_with_state(struct drm_crtc_state *crtc_state,
  226. struct drm_plane_state *state)
  227. {
  228. struct mdp5_plane_state *mdp5_state = to_mdp5_plane_state(state);
  229. struct drm_plane *plane = state->plane;
  230. struct drm_plane_state *old_state = plane->state;
  231. struct mdp5_cfg *config = mdp5_cfg_get_config(get_kms(plane)->cfg);
  232. bool new_hwpipe = false;
  233. bool need_right_hwpipe = false;
  234. uint32_t max_width, max_height;
  235. bool out_of_bounds = false;
  236. uint32_t caps = 0;
  237. int min_scale, max_scale;
  238. int ret;
  239. DBG("%s: check (%d -> %d)", plane->name,
  240. plane_enabled(old_state), plane_enabled(state));
  241. max_width = config->hw->lm.max_width << 16;
  242. max_height = config->hw->lm.max_height << 16;
  243. /* Make sure source dimensions are within bounds. */
  244. if (state->src_h > max_height)
  245. out_of_bounds = true;
  246. if (state->src_w > max_width) {
  247. /* If source split is supported, we can go up to 2x
  248. * the max LM width, but we'd need to stage another
  249. * hwpipe to the right LM. So, the drm_plane would
  250. * consist of 2 hwpipes.
  251. */
  252. if (config->hw->mdp.caps & MDP_CAP_SRC_SPLIT &&
  253. (state->src_w <= 2 * max_width))
  254. need_right_hwpipe = true;
  255. else
  256. out_of_bounds = true;
  257. }
  258. if (out_of_bounds) {
  259. struct drm_rect src = drm_plane_state_src(state);
  260. DBG("Invalid source size "DRM_RECT_FP_FMT,
  261. DRM_RECT_FP_ARG(&src));
  262. return -ERANGE;
  263. }
  264. min_scale = FRAC_16_16(1, 8);
  265. max_scale = FRAC_16_16(8, 1);
  266. ret = drm_atomic_helper_check_plane_state(state, crtc_state,
  267. min_scale, max_scale,
  268. true, true);
  269. if (ret)
  270. return ret;
  271. if (plane_enabled(state)) {
  272. unsigned int rotation;
  273. const struct mdp_format *format;
  274. struct mdp5_kms *mdp5_kms = get_kms(plane);
  275. uint32_t blkcfg = 0;
  276. format = to_mdp_format(msm_framebuffer_format(state->fb));
  277. if (MDP_FORMAT_IS_YUV(format))
  278. caps |= MDP_PIPE_CAP_SCALE | MDP_PIPE_CAP_CSC;
  279. if (((state->src_w >> 16) != state->crtc_w) ||
  280. ((state->src_h >> 16) != state->crtc_h))
  281. caps |= MDP_PIPE_CAP_SCALE;
  282. rotation = drm_rotation_simplify(state->rotation,
  283. DRM_MODE_ROTATE_0 |
  284. DRM_MODE_REFLECT_X |
  285. DRM_MODE_REFLECT_Y);
  286. if (rotation & DRM_MODE_REFLECT_X)
  287. caps |= MDP_PIPE_CAP_HFLIP;
  288. if (rotation & DRM_MODE_REFLECT_Y)
  289. caps |= MDP_PIPE_CAP_VFLIP;
  290. if (plane->type == DRM_PLANE_TYPE_CURSOR)
  291. caps |= MDP_PIPE_CAP_CURSOR;
  292. /* (re)allocate hw pipe if we don't have one or caps-mismatch: */
  293. if (!mdp5_state->hwpipe || (caps & ~mdp5_state->hwpipe->caps))
  294. new_hwpipe = true;
  295. /*
  296. * (re)allocte hw pipe if we're either requesting for 2 hw pipes
  297. * or we're switching from 2 hw pipes to 1 hw pipe because the
  298. * new src_w can be supported by 1 hw pipe itself.
  299. */
  300. if ((need_right_hwpipe && !mdp5_state->r_hwpipe) ||
  301. (!need_right_hwpipe && mdp5_state->r_hwpipe))
  302. new_hwpipe = true;
  303. if (mdp5_kms->smp) {
  304. const struct mdp_format *format =
  305. to_mdp_format(msm_framebuffer_format(state->fb));
  306. blkcfg = mdp5_smp_calculate(mdp5_kms->smp, format,
  307. state->src_w >> 16, false);
  308. if (mdp5_state->hwpipe && (mdp5_state->hwpipe->blkcfg != blkcfg))
  309. new_hwpipe = true;
  310. }
  311. /* (re)assign hwpipe if needed, otherwise keep old one: */
  312. if (new_hwpipe) {
  313. /* TODO maybe we want to re-assign hwpipe sometimes
  314. * in cases when we no-longer need some caps to make
  315. * it available for other planes?
  316. */
  317. struct mdp5_hw_pipe *old_hwpipe = mdp5_state->hwpipe;
  318. struct mdp5_hw_pipe *old_right_hwpipe =
  319. mdp5_state->r_hwpipe;
  320. struct mdp5_hw_pipe *new_hwpipe = NULL;
  321. struct mdp5_hw_pipe *new_right_hwpipe = NULL;
  322. ret = mdp5_pipe_assign(state->state, plane, caps,
  323. blkcfg, &new_hwpipe,
  324. need_right_hwpipe ?
  325. &new_right_hwpipe : NULL);
  326. if (ret) {
  327. DBG("%s: failed to assign hwpipe(s)!",
  328. plane->name);
  329. return ret;
  330. }
  331. mdp5_state->hwpipe = new_hwpipe;
  332. if (need_right_hwpipe)
  333. mdp5_state->r_hwpipe = new_right_hwpipe;
  334. else
  335. /*
  336. * set it to NULL so that the driver knows we
  337. * don't have a right hwpipe when committing a
  338. * new state
  339. */
  340. mdp5_state->r_hwpipe = NULL;
  341. mdp5_pipe_release(state->state, old_hwpipe);
  342. mdp5_pipe_release(state->state, old_right_hwpipe);
  343. }
  344. } else {
  345. mdp5_pipe_release(state->state, mdp5_state->hwpipe);
  346. mdp5_pipe_release(state->state, mdp5_state->r_hwpipe);
  347. mdp5_state->hwpipe = mdp5_state->r_hwpipe = NULL;
  348. }
  349. return 0;
  350. }
  351. static int mdp5_plane_atomic_check(struct drm_plane *plane,
  352. struct drm_plane_state *state)
  353. {
  354. struct drm_crtc *crtc;
  355. struct drm_crtc_state *crtc_state;
  356. crtc = state->crtc ? state->crtc : plane->state->crtc;
  357. if (!crtc)
  358. return 0;
  359. crtc_state = drm_atomic_get_existing_crtc_state(state->state, crtc);
  360. if (WARN_ON(!crtc_state))
  361. return -EINVAL;
  362. return mdp5_plane_atomic_check_with_state(crtc_state, state);
  363. }
  364. static void mdp5_plane_atomic_update(struct drm_plane *plane,
  365. struct drm_plane_state *old_state)
  366. {
  367. struct drm_plane_state *state = plane->state;
  368. DBG("%s: update", plane->name);
  369. if (plane_enabled(state)) {
  370. int ret;
  371. ret = mdp5_plane_mode_set(plane,
  372. state->crtc, state->fb,
  373. &state->src, &state->dst);
  374. /* atomic_check should have ensured that this doesn't fail */
  375. WARN_ON(ret < 0);
  376. }
  377. }
  378. static int mdp5_plane_atomic_async_check(struct drm_plane *plane,
  379. struct drm_plane_state *state)
  380. {
  381. struct mdp5_plane_state *mdp5_state = to_mdp5_plane_state(state);
  382. struct drm_crtc_state *crtc_state;
  383. int min_scale, max_scale;
  384. int ret;
  385. crtc_state = drm_atomic_get_existing_crtc_state(state->state,
  386. state->crtc);
  387. if (WARN_ON(!crtc_state))
  388. return -EINVAL;
  389. if (!crtc_state->active)
  390. return -EINVAL;
  391. mdp5_state = to_mdp5_plane_state(state);
  392. /* don't use fast path if we don't have a hwpipe allocated yet */
  393. if (!mdp5_state->hwpipe)
  394. return -EINVAL;
  395. /* only allow changing of position(crtc x/y or src x/y) in fast path */
  396. if (plane->state->crtc != state->crtc ||
  397. plane->state->src_w != state->src_w ||
  398. plane->state->src_h != state->src_h ||
  399. plane->state->crtc_w != state->crtc_w ||
  400. plane->state->crtc_h != state->crtc_h ||
  401. !plane->state->fb ||
  402. plane->state->fb != state->fb)
  403. return -EINVAL;
  404. min_scale = FRAC_16_16(1, 8);
  405. max_scale = FRAC_16_16(8, 1);
  406. ret = drm_atomic_helper_check_plane_state(state, crtc_state,
  407. min_scale, max_scale,
  408. true, true);
  409. if (ret)
  410. return ret;
  411. /*
  412. * if the visibility of the plane changes (i.e, if the cursor is
  413. * clipped out completely, we can't take the async path because
  414. * we need to stage/unstage the plane from the Layer Mixer(s). We
  415. * also assign/unassign the hwpipe(s) tied to the plane. We avoid
  416. * taking the fast path for both these reasons.
  417. */
  418. if (state->visible != plane->state->visible)
  419. return -EINVAL;
  420. return 0;
  421. }
  422. static void mdp5_plane_atomic_async_update(struct drm_plane *plane,
  423. struct drm_plane_state *new_state)
  424. {
  425. plane->state->src_x = new_state->src_x;
  426. plane->state->src_y = new_state->src_y;
  427. plane->state->crtc_x = new_state->crtc_x;
  428. plane->state->crtc_y = new_state->crtc_y;
  429. if (plane_enabled(new_state)) {
  430. struct mdp5_ctl *ctl;
  431. struct mdp5_pipeline *pipeline =
  432. mdp5_crtc_get_pipeline(plane->crtc);
  433. int ret;
  434. ret = mdp5_plane_mode_set(plane, new_state->crtc, new_state->fb,
  435. &new_state->src, &new_state->dst);
  436. WARN_ON(ret < 0);
  437. ctl = mdp5_crtc_get_ctl(new_state->crtc);
  438. mdp5_ctl_commit(ctl, pipeline, mdp5_plane_get_flush(plane), true);
  439. }
  440. *to_mdp5_plane_state(plane->state) =
  441. *to_mdp5_plane_state(new_state);
  442. }
  443. static const struct drm_plane_helper_funcs mdp5_plane_helper_funcs = {
  444. .prepare_fb = mdp5_plane_prepare_fb,
  445. .cleanup_fb = mdp5_plane_cleanup_fb,
  446. .atomic_check = mdp5_plane_atomic_check,
  447. .atomic_update = mdp5_plane_atomic_update,
  448. .atomic_async_check = mdp5_plane_atomic_async_check,
  449. .atomic_async_update = mdp5_plane_atomic_async_update,
  450. };
  451. static void set_scanout_locked(struct mdp5_kms *mdp5_kms,
  452. enum mdp5_pipe pipe,
  453. struct drm_framebuffer *fb)
  454. {
  455. struct msm_kms *kms = &mdp5_kms->base.base;
  456. mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_STRIDE_A(pipe),
  457. MDP5_PIPE_SRC_STRIDE_A_P0(fb->pitches[0]) |
  458. MDP5_PIPE_SRC_STRIDE_A_P1(fb->pitches[1]));
  459. mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_STRIDE_B(pipe),
  460. MDP5_PIPE_SRC_STRIDE_B_P2(fb->pitches[2]) |
  461. MDP5_PIPE_SRC_STRIDE_B_P3(fb->pitches[3]));
  462. mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC0_ADDR(pipe),
  463. msm_framebuffer_iova(fb, kms->aspace, 0));
  464. mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC1_ADDR(pipe),
  465. msm_framebuffer_iova(fb, kms->aspace, 1));
  466. mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC2_ADDR(pipe),
  467. msm_framebuffer_iova(fb, kms->aspace, 2));
  468. mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC3_ADDR(pipe),
  469. msm_framebuffer_iova(fb, kms->aspace, 3));
  470. }
  471. /* Note: mdp5_plane->pipe_lock must be locked */
  472. static void csc_disable(struct mdp5_kms *mdp5_kms, enum mdp5_pipe pipe)
  473. {
  474. uint32_t value = mdp5_read(mdp5_kms, REG_MDP5_PIPE_OP_MODE(pipe)) &
  475. ~MDP5_PIPE_OP_MODE_CSC_1_EN;
  476. mdp5_write(mdp5_kms, REG_MDP5_PIPE_OP_MODE(pipe), value);
  477. }
  478. /* Note: mdp5_plane->pipe_lock must be locked */
  479. static void csc_enable(struct mdp5_kms *mdp5_kms, enum mdp5_pipe pipe,
  480. struct csc_cfg *csc)
  481. {
  482. uint32_t i, mode = 0; /* RGB, no CSC */
  483. uint32_t *matrix;
  484. if (unlikely(!csc))
  485. return;
  486. if ((csc->type == CSC_YUV2RGB) || (CSC_YUV2YUV == csc->type))
  487. mode |= MDP5_PIPE_OP_MODE_CSC_SRC_DATA_FORMAT(DATA_FORMAT_YUV);
  488. if ((csc->type == CSC_RGB2YUV) || (CSC_YUV2YUV == csc->type))
  489. mode |= MDP5_PIPE_OP_MODE_CSC_DST_DATA_FORMAT(DATA_FORMAT_YUV);
  490. mode |= MDP5_PIPE_OP_MODE_CSC_1_EN;
  491. mdp5_write(mdp5_kms, REG_MDP5_PIPE_OP_MODE(pipe), mode);
  492. matrix = csc->matrix;
  493. mdp5_write(mdp5_kms, REG_MDP5_PIPE_CSC_1_MATRIX_COEFF_0(pipe),
  494. MDP5_PIPE_CSC_1_MATRIX_COEFF_0_COEFF_11(matrix[0]) |
  495. MDP5_PIPE_CSC_1_MATRIX_COEFF_0_COEFF_12(matrix[1]));
  496. mdp5_write(mdp5_kms, REG_MDP5_PIPE_CSC_1_MATRIX_COEFF_1(pipe),
  497. MDP5_PIPE_CSC_1_MATRIX_COEFF_1_COEFF_13(matrix[2]) |
  498. MDP5_PIPE_CSC_1_MATRIX_COEFF_1_COEFF_21(matrix[3]));
  499. mdp5_write(mdp5_kms, REG_MDP5_PIPE_CSC_1_MATRIX_COEFF_2(pipe),
  500. MDP5_PIPE_CSC_1_MATRIX_COEFF_2_COEFF_22(matrix[4]) |
  501. MDP5_PIPE_CSC_1_MATRIX_COEFF_2_COEFF_23(matrix[5]));
  502. mdp5_write(mdp5_kms, REG_MDP5_PIPE_CSC_1_MATRIX_COEFF_3(pipe),
  503. MDP5_PIPE_CSC_1_MATRIX_COEFF_3_COEFF_31(matrix[6]) |
  504. MDP5_PIPE_CSC_1_MATRIX_COEFF_3_COEFF_32(matrix[7]));
  505. mdp5_write(mdp5_kms, REG_MDP5_PIPE_CSC_1_MATRIX_COEFF_4(pipe),
  506. MDP5_PIPE_CSC_1_MATRIX_COEFF_4_COEFF_33(matrix[8]));
  507. for (i = 0; i < ARRAY_SIZE(csc->pre_bias); i++) {
  508. uint32_t *pre_clamp = csc->pre_clamp;
  509. uint32_t *post_clamp = csc->post_clamp;
  510. mdp5_write(mdp5_kms, REG_MDP5_PIPE_CSC_1_PRE_CLAMP(pipe, i),
  511. MDP5_PIPE_CSC_1_PRE_CLAMP_REG_HIGH(pre_clamp[2*i+1]) |
  512. MDP5_PIPE_CSC_1_PRE_CLAMP_REG_LOW(pre_clamp[2*i]));
  513. mdp5_write(mdp5_kms, REG_MDP5_PIPE_CSC_1_POST_CLAMP(pipe, i),
  514. MDP5_PIPE_CSC_1_POST_CLAMP_REG_HIGH(post_clamp[2*i+1]) |
  515. MDP5_PIPE_CSC_1_POST_CLAMP_REG_LOW(post_clamp[2*i]));
  516. mdp5_write(mdp5_kms, REG_MDP5_PIPE_CSC_1_PRE_BIAS(pipe, i),
  517. MDP5_PIPE_CSC_1_PRE_BIAS_REG_VALUE(csc->pre_bias[i]));
  518. mdp5_write(mdp5_kms, REG_MDP5_PIPE_CSC_1_POST_BIAS(pipe, i),
  519. MDP5_PIPE_CSC_1_POST_BIAS_REG_VALUE(csc->post_bias[i]));
  520. }
  521. }
  522. #define PHASE_STEP_SHIFT 21
  523. #define DOWN_SCALE_RATIO_MAX 32 /* 2^(26-21) */
  524. static int calc_phase_step(uint32_t src, uint32_t dst, uint32_t *out_phase)
  525. {
  526. uint32_t unit;
  527. if (src == 0 || dst == 0)
  528. return -EINVAL;
  529. /*
  530. * PHASE_STEP_X/Y is coded on 26 bits (25:0),
  531. * where 2^21 represents the unity "1" in fixed-point hardware design.
  532. * This leaves 5 bits for the integer part (downscale case):
  533. * -> maximum downscale ratio = 0b1_1111 = 31
  534. */
  535. if (src > (dst * DOWN_SCALE_RATIO_MAX))
  536. return -EOVERFLOW;
  537. unit = 1 << PHASE_STEP_SHIFT;
  538. *out_phase = mult_frac(unit, src, dst);
  539. return 0;
  540. }
  541. static int calc_scalex_steps(struct drm_plane *plane,
  542. uint32_t pixel_format, uint32_t src, uint32_t dest,
  543. uint32_t phasex_steps[COMP_MAX])
  544. {
  545. struct mdp5_kms *mdp5_kms = get_kms(plane);
  546. struct device *dev = mdp5_kms->dev->dev;
  547. uint32_t phasex_step;
  548. unsigned int hsub;
  549. int ret;
  550. ret = calc_phase_step(src, dest, &phasex_step);
  551. if (ret) {
  552. dev_err(dev, "X scaling (%d->%d) failed: %d\n", src, dest, ret);
  553. return ret;
  554. }
  555. hsub = drm_format_horz_chroma_subsampling(pixel_format);
  556. phasex_steps[COMP_0] = phasex_step;
  557. phasex_steps[COMP_3] = phasex_step;
  558. phasex_steps[COMP_1_2] = phasex_step / hsub;
  559. return 0;
  560. }
  561. static int calc_scaley_steps(struct drm_plane *plane,
  562. uint32_t pixel_format, uint32_t src, uint32_t dest,
  563. uint32_t phasey_steps[COMP_MAX])
  564. {
  565. struct mdp5_kms *mdp5_kms = get_kms(plane);
  566. struct device *dev = mdp5_kms->dev->dev;
  567. uint32_t phasey_step;
  568. unsigned int vsub;
  569. int ret;
  570. ret = calc_phase_step(src, dest, &phasey_step);
  571. if (ret) {
  572. dev_err(dev, "Y scaling (%d->%d) failed: %d\n", src, dest, ret);
  573. return ret;
  574. }
  575. vsub = drm_format_vert_chroma_subsampling(pixel_format);
  576. phasey_steps[COMP_0] = phasey_step;
  577. phasey_steps[COMP_3] = phasey_step;
  578. phasey_steps[COMP_1_2] = phasey_step / vsub;
  579. return 0;
  580. }
  581. static uint32_t get_scale_config(const struct mdp_format *format,
  582. uint32_t src, uint32_t dst, bool horz)
  583. {
  584. bool scaling = format->is_yuv ? true : (src != dst);
  585. uint32_t sub, pix_fmt = format->base.pixel_format;
  586. uint32_t ya_filter, uv_filter;
  587. bool yuv = format->is_yuv;
  588. if (!scaling)
  589. return 0;
  590. if (yuv) {
  591. sub = horz ? drm_format_horz_chroma_subsampling(pix_fmt) :
  592. drm_format_vert_chroma_subsampling(pix_fmt);
  593. uv_filter = ((src / sub) <= dst) ?
  594. SCALE_FILTER_BIL : SCALE_FILTER_PCMN;
  595. }
  596. ya_filter = (src <= dst) ? SCALE_FILTER_BIL : SCALE_FILTER_PCMN;
  597. if (horz)
  598. return MDP5_PIPE_SCALE_CONFIG_SCALEX_EN |
  599. MDP5_PIPE_SCALE_CONFIG_SCALEX_FILTER_COMP_0(ya_filter) |
  600. MDP5_PIPE_SCALE_CONFIG_SCALEX_FILTER_COMP_3(ya_filter) |
  601. COND(yuv, MDP5_PIPE_SCALE_CONFIG_SCALEX_FILTER_COMP_1_2(uv_filter));
  602. else
  603. return MDP5_PIPE_SCALE_CONFIG_SCALEY_EN |
  604. MDP5_PIPE_SCALE_CONFIG_SCALEY_FILTER_COMP_0(ya_filter) |
  605. MDP5_PIPE_SCALE_CONFIG_SCALEY_FILTER_COMP_3(ya_filter) |
  606. COND(yuv, MDP5_PIPE_SCALE_CONFIG_SCALEY_FILTER_COMP_1_2(uv_filter));
  607. }
  608. static void calc_pixel_ext(const struct mdp_format *format,
  609. uint32_t src, uint32_t dst, uint32_t phase_step[2],
  610. int pix_ext_edge1[COMP_MAX], int pix_ext_edge2[COMP_MAX],
  611. bool horz)
  612. {
  613. bool scaling = format->is_yuv ? true : (src != dst);
  614. int i;
  615. /*
  616. * Note:
  617. * We assume here that:
  618. * 1. PCMN filter is used for downscale
  619. * 2. bilinear filter is used for upscale
  620. * 3. we are in a single pipe configuration
  621. */
  622. for (i = 0; i < COMP_MAX; i++) {
  623. pix_ext_edge1[i] = 0;
  624. pix_ext_edge2[i] = scaling ? 1 : 0;
  625. }
  626. }
  627. static void mdp5_write_pixel_ext(struct mdp5_kms *mdp5_kms, enum mdp5_pipe pipe,
  628. const struct mdp_format *format,
  629. uint32_t src_w, int pe_left[COMP_MAX], int pe_right[COMP_MAX],
  630. uint32_t src_h, int pe_top[COMP_MAX], int pe_bottom[COMP_MAX])
  631. {
  632. uint32_t pix_fmt = format->base.pixel_format;
  633. uint32_t lr, tb, req;
  634. int i;
  635. for (i = 0; i < COMP_MAX; i++) {
  636. uint32_t roi_w = src_w;
  637. uint32_t roi_h = src_h;
  638. if (format->is_yuv && i == COMP_1_2) {
  639. roi_w /= drm_format_horz_chroma_subsampling(pix_fmt);
  640. roi_h /= drm_format_vert_chroma_subsampling(pix_fmt);
  641. }
  642. lr = (pe_left[i] >= 0) ?
  643. MDP5_PIPE_SW_PIX_EXT_LR_LEFT_RPT(pe_left[i]) :
  644. MDP5_PIPE_SW_PIX_EXT_LR_LEFT_OVF(pe_left[i]);
  645. lr |= (pe_right[i] >= 0) ?
  646. MDP5_PIPE_SW_PIX_EXT_LR_RIGHT_RPT(pe_right[i]) :
  647. MDP5_PIPE_SW_PIX_EXT_LR_RIGHT_OVF(pe_right[i]);
  648. tb = (pe_top[i] >= 0) ?
  649. MDP5_PIPE_SW_PIX_EXT_TB_TOP_RPT(pe_top[i]) :
  650. MDP5_PIPE_SW_PIX_EXT_TB_TOP_OVF(pe_top[i]);
  651. tb |= (pe_bottom[i] >= 0) ?
  652. MDP5_PIPE_SW_PIX_EXT_TB_BOTTOM_RPT(pe_bottom[i]) :
  653. MDP5_PIPE_SW_PIX_EXT_TB_BOTTOM_OVF(pe_bottom[i]);
  654. req = MDP5_PIPE_SW_PIX_EXT_REQ_PIXELS_LEFT_RIGHT(roi_w +
  655. pe_left[i] + pe_right[i]);
  656. req |= MDP5_PIPE_SW_PIX_EXT_REQ_PIXELS_TOP_BOTTOM(roi_h +
  657. pe_top[i] + pe_bottom[i]);
  658. mdp5_write(mdp5_kms, REG_MDP5_PIPE_SW_PIX_EXT_LR(pipe, i), lr);
  659. mdp5_write(mdp5_kms, REG_MDP5_PIPE_SW_PIX_EXT_TB(pipe, i), tb);
  660. mdp5_write(mdp5_kms, REG_MDP5_PIPE_SW_PIX_EXT_REQ_PIXELS(pipe, i), req);
  661. DBG("comp-%d (L/R): rpt=%d/%d, ovf=%d/%d, req=%d", i,
  662. FIELD(lr, MDP5_PIPE_SW_PIX_EXT_LR_LEFT_RPT),
  663. FIELD(lr, MDP5_PIPE_SW_PIX_EXT_LR_RIGHT_RPT),
  664. FIELD(lr, MDP5_PIPE_SW_PIX_EXT_LR_LEFT_OVF),
  665. FIELD(lr, MDP5_PIPE_SW_PIX_EXT_LR_RIGHT_OVF),
  666. FIELD(req, MDP5_PIPE_SW_PIX_EXT_REQ_PIXELS_LEFT_RIGHT));
  667. DBG("comp-%d (T/B): rpt=%d/%d, ovf=%d/%d, req=%d", i,
  668. FIELD(tb, MDP5_PIPE_SW_PIX_EXT_TB_TOP_RPT),
  669. FIELD(tb, MDP5_PIPE_SW_PIX_EXT_TB_BOTTOM_RPT),
  670. FIELD(tb, MDP5_PIPE_SW_PIX_EXT_TB_TOP_OVF),
  671. FIELD(tb, MDP5_PIPE_SW_PIX_EXT_TB_BOTTOM_OVF),
  672. FIELD(req, MDP5_PIPE_SW_PIX_EXT_REQ_PIXELS_TOP_BOTTOM));
  673. }
  674. }
  675. struct pixel_ext {
  676. int left[COMP_MAX];
  677. int right[COMP_MAX];
  678. int top[COMP_MAX];
  679. int bottom[COMP_MAX];
  680. };
  681. struct phase_step {
  682. u32 x[COMP_MAX];
  683. u32 y[COMP_MAX];
  684. };
  685. static void mdp5_hwpipe_mode_set(struct mdp5_kms *mdp5_kms,
  686. struct mdp5_hw_pipe *hwpipe,
  687. struct drm_framebuffer *fb,
  688. struct phase_step *step,
  689. struct pixel_ext *pe,
  690. u32 scale_config, u32 hdecm, u32 vdecm,
  691. bool hflip, bool vflip,
  692. int crtc_x, int crtc_y,
  693. unsigned int crtc_w, unsigned int crtc_h,
  694. u32 src_img_w, u32 src_img_h,
  695. u32 src_x, u32 src_y,
  696. u32 src_w, u32 src_h)
  697. {
  698. enum mdp5_pipe pipe = hwpipe->pipe;
  699. bool has_pe = hwpipe->caps & MDP_PIPE_CAP_SW_PIX_EXT;
  700. const struct mdp_format *format =
  701. to_mdp_format(msm_framebuffer_format(fb));
  702. mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_IMG_SIZE(pipe),
  703. MDP5_PIPE_SRC_IMG_SIZE_WIDTH(src_img_w) |
  704. MDP5_PIPE_SRC_IMG_SIZE_HEIGHT(src_img_h));
  705. mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_SIZE(pipe),
  706. MDP5_PIPE_SRC_SIZE_WIDTH(src_w) |
  707. MDP5_PIPE_SRC_SIZE_HEIGHT(src_h));
  708. mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_XY(pipe),
  709. MDP5_PIPE_SRC_XY_X(src_x) |
  710. MDP5_PIPE_SRC_XY_Y(src_y));
  711. mdp5_write(mdp5_kms, REG_MDP5_PIPE_OUT_SIZE(pipe),
  712. MDP5_PIPE_OUT_SIZE_WIDTH(crtc_w) |
  713. MDP5_PIPE_OUT_SIZE_HEIGHT(crtc_h));
  714. mdp5_write(mdp5_kms, REG_MDP5_PIPE_OUT_XY(pipe),
  715. MDP5_PIPE_OUT_XY_X(crtc_x) |
  716. MDP5_PIPE_OUT_XY_Y(crtc_y));
  717. mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_FORMAT(pipe),
  718. MDP5_PIPE_SRC_FORMAT_A_BPC(format->bpc_a) |
  719. MDP5_PIPE_SRC_FORMAT_R_BPC(format->bpc_r) |
  720. MDP5_PIPE_SRC_FORMAT_G_BPC(format->bpc_g) |
  721. MDP5_PIPE_SRC_FORMAT_B_BPC(format->bpc_b) |
  722. COND(format->alpha_enable, MDP5_PIPE_SRC_FORMAT_ALPHA_ENABLE) |
  723. MDP5_PIPE_SRC_FORMAT_CPP(format->cpp - 1) |
  724. MDP5_PIPE_SRC_FORMAT_UNPACK_COUNT(format->unpack_count - 1) |
  725. COND(format->unpack_tight, MDP5_PIPE_SRC_FORMAT_UNPACK_TIGHT) |
  726. MDP5_PIPE_SRC_FORMAT_FETCH_TYPE(format->fetch_type) |
  727. MDP5_PIPE_SRC_FORMAT_CHROMA_SAMP(format->chroma_sample));
  728. mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_UNPACK(pipe),
  729. MDP5_PIPE_SRC_UNPACK_ELEM0(format->unpack[0]) |
  730. MDP5_PIPE_SRC_UNPACK_ELEM1(format->unpack[1]) |
  731. MDP5_PIPE_SRC_UNPACK_ELEM2(format->unpack[2]) |
  732. MDP5_PIPE_SRC_UNPACK_ELEM3(format->unpack[3]));
  733. mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_OP_MODE(pipe),
  734. (hflip ? MDP5_PIPE_SRC_OP_MODE_FLIP_LR : 0) |
  735. (vflip ? MDP5_PIPE_SRC_OP_MODE_FLIP_UD : 0) |
  736. COND(has_pe, MDP5_PIPE_SRC_OP_MODE_SW_PIX_EXT_OVERRIDE) |
  737. MDP5_PIPE_SRC_OP_MODE_BWC(BWC_LOSSLESS));
  738. /* not using secure mode: */
  739. mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_ADDR_SW_STATUS(pipe), 0);
  740. if (hwpipe->caps & MDP_PIPE_CAP_SW_PIX_EXT)
  741. mdp5_write_pixel_ext(mdp5_kms, pipe, format,
  742. src_w, pe->left, pe->right,
  743. src_h, pe->top, pe->bottom);
  744. if (hwpipe->caps & MDP_PIPE_CAP_SCALE) {
  745. mdp5_write(mdp5_kms, REG_MDP5_PIPE_SCALE_PHASE_STEP_X(pipe),
  746. step->x[COMP_0]);
  747. mdp5_write(mdp5_kms, REG_MDP5_PIPE_SCALE_PHASE_STEP_Y(pipe),
  748. step->y[COMP_0]);
  749. mdp5_write(mdp5_kms, REG_MDP5_PIPE_SCALE_CR_PHASE_STEP_X(pipe),
  750. step->x[COMP_1_2]);
  751. mdp5_write(mdp5_kms, REG_MDP5_PIPE_SCALE_CR_PHASE_STEP_Y(pipe),
  752. step->y[COMP_1_2]);
  753. mdp5_write(mdp5_kms, REG_MDP5_PIPE_DECIMATION(pipe),
  754. MDP5_PIPE_DECIMATION_VERT(vdecm) |
  755. MDP5_PIPE_DECIMATION_HORZ(hdecm));
  756. mdp5_write(mdp5_kms, REG_MDP5_PIPE_SCALE_CONFIG(pipe),
  757. scale_config);
  758. }
  759. if (hwpipe->caps & MDP_PIPE_CAP_CSC) {
  760. if (MDP_FORMAT_IS_YUV(format))
  761. csc_enable(mdp5_kms, pipe,
  762. mdp_get_default_csc_cfg(CSC_YUV2RGB));
  763. else
  764. csc_disable(mdp5_kms, pipe);
  765. }
  766. set_scanout_locked(mdp5_kms, pipe, fb);
  767. }
  768. static int mdp5_plane_mode_set(struct drm_plane *plane,
  769. struct drm_crtc *crtc, struct drm_framebuffer *fb,
  770. struct drm_rect *src, struct drm_rect *dest)
  771. {
  772. struct drm_plane_state *pstate = plane->state;
  773. struct mdp5_hw_pipe *hwpipe = to_mdp5_plane_state(pstate)->hwpipe;
  774. struct mdp5_kms *mdp5_kms = get_kms(plane);
  775. enum mdp5_pipe pipe = hwpipe->pipe;
  776. struct mdp5_hw_pipe *right_hwpipe;
  777. const struct mdp_format *format;
  778. uint32_t nplanes, config = 0;
  779. struct phase_step step = { { 0 } };
  780. struct pixel_ext pe = { { 0 } };
  781. uint32_t hdecm = 0, vdecm = 0;
  782. uint32_t pix_format;
  783. unsigned int rotation;
  784. bool vflip, hflip;
  785. int crtc_x, crtc_y;
  786. unsigned int crtc_w, crtc_h;
  787. uint32_t src_x, src_y;
  788. uint32_t src_w, src_h;
  789. uint32_t src_img_w, src_img_h;
  790. int ret;
  791. nplanes = fb->format->num_planes;
  792. /* bad formats should already be rejected: */
  793. if (WARN_ON(nplanes > pipe2nclients(pipe)))
  794. return -EINVAL;
  795. format = to_mdp_format(msm_framebuffer_format(fb));
  796. pix_format = format->base.pixel_format;
  797. src_x = src->x1;
  798. src_y = src->y1;
  799. src_w = drm_rect_width(src);
  800. src_h = drm_rect_height(src);
  801. crtc_x = dest->x1;
  802. crtc_y = dest->y1;
  803. crtc_w = drm_rect_width(dest);
  804. crtc_h = drm_rect_height(dest);
  805. /* src values are in Q16 fixed point, convert to integer: */
  806. src_x = src_x >> 16;
  807. src_y = src_y >> 16;
  808. src_w = src_w >> 16;
  809. src_h = src_h >> 16;
  810. src_img_w = min(fb->width, src_w);
  811. src_img_h = min(fb->height, src_h);
  812. DBG("%s: FB[%u] %u,%u,%u,%u -> CRTC[%u] %d,%d,%u,%u", plane->name,
  813. fb->base.id, src_x, src_y, src_w, src_h,
  814. crtc->base.id, crtc_x, crtc_y, crtc_w, crtc_h);
  815. right_hwpipe = to_mdp5_plane_state(pstate)->r_hwpipe;
  816. if (right_hwpipe) {
  817. /*
  818. * if the plane comprises of 2 hw pipes, assume that the width
  819. * is split equally across them. The only parameters that varies
  820. * between the 2 pipes are src_x and crtc_x
  821. */
  822. crtc_w /= 2;
  823. src_w /= 2;
  824. src_img_w /= 2;
  825. }
  826. ret = calc_scalex_steps(plane, pix_format, src_w, crtc_w, step.x);
  827. if (ret)
  828. return ret;
  829. ret = calc_scaley_steps(plane, pix_format, src_h, crtc_h, step.y);
  830. if (ret)
  831. return ret;
  832. if (hwpipe->caps & MDP_PIPE_CAP_SW_PIX_EXT) {
  833. calc_pixel_ext(format, src_w, crtc_w, step.x,
  834. pe.left, pe.right, true);
  835. calc_pixel_ext(format, src_h, crtc_h, step.y,
  836. pe.top, pe.bottom, false);
  837. }
  838. /* TODO calc hdecm, vdecm */
  839. /* SCALE is used to both scale and up-sample chroma components */
  840. config |= get_scale_config(format, src_w, crtc_w, true);
  841. config |= get_scale_config(format, src_h, crtc_h, false);
  842. DBG("scale config = %x", config);
  843. rotation = drm_rotation_simplify(pstate->rotation,
  844. DRM_MODE_ROTATE_0 |
  845. DRM_MODE_REFLECT_X |
  846. DRM_MODE_REFLECT_Y);
  847. hflip = !!(rotation & DRM_MODE_REFLECT_X);
  848. vflip = !!(rotation & DRM_MODE_REFLECT_Y);
  849. mdp5_hwpipe_mode_set(mdp5_kms, hwpipe, fb, &step, &pe,
  850. config, hdecm, vdecm, hflip, vflip,
  851. crtc_x, crtc_y, crtc_w, crtc_h,
  852. src_img_w, src_img_h,
  853. src_x, src_y, src_w, src_h);
  854. if (right_hwpipe)
  855. mdp5_hwpipe_mode_set(mdp5_kms, right_hwpipe, fb, &step, &pe,
  856. config, hdecm, vdecm, hflip, vflip,
  857. crtc_x + crtc_w, crtc_y, crtc_w, crtc_h,
  858. src_img_w, src_img_h,
  859. src_x + src_w, src_y, src_w, src_h);
  860. plane->fb = fb;
  861. return ret;
  862. }
  863. /*
  864. * Use this func and the one below only after the atomic state has been
  865. * successfully swapped
  866. */
  867. enum mdp5_pipe mdp5_plane_pipe(struct drm_plane *plane)
  868. {
  869. struct mdp5_plane_state *pstate = to_mdp5_plane_state(plane->state);
  870. if (WARN_ON(!pstate->hwpipe))
  871. return SSPP_NONE;
  872. return pstate->hwpipe->pipe;
  873. }
  874. enum mdp5_pipe mdp5_plane_right_pipe(struct drm_plane *plane)
  875. {
  876. struct mdp5_plane_state *pstate = to_mdp5_plane_state(plane->state);
  877. if (!pstate->r_hwpipe)
  878. return SSPP_NONE;
  879. return pstate->r_hwpipe->pipe;
  880. }
  881. uint32_t mdp5_plane_get_flush(struct drm_plane *plane)
  882. {
  883. struct mdp5_plane_state *pstate = to_mdp5_plane_state(plane->state);
  884. u32 mask;
  885. if (WARN_ON(!pstate->hwpipe))
  886. return 0;
  887. mask = pstate->hwpipe->flush_mask;
  888. if (pstate->r_hwpipe)
  889. mask |= pstate->r_hwpipe->flush_mask;
  890. return mask;
  891. }
  892. /* initialize plane */
  893. struct drm_plane *mdp5_plane_init(struct drm_device *dev,
  894. enum drm_plane_type type)
  895. {
  896. struct drm_plane *plane = NULL;
  897. struct mdp5_plane *mdp5_plane;
  898. int ret;
  899. mdp5_plane = kzalloc(sizeof(*mdp5_plane), GFP_KERNEL);
  900. if (!mdp5_plane) {
  901. ret = -ENOMEM;
  902. goto fail;
  903. }
  904. plane = &mdp5_plane->base;
  905. mdp5_plane->nformats = mdp_get_formats(mdp5_plane->formats,
  906. ARRAY_SIZE(mdp5_plane->formats), false);
  907. ret = drm_universal_plane_init(dev, plane, 0xff, &mdp5_plane_funcs,
  908. mdp5_plane->formats, mdp5_plane->nformats,
  909. NULL, type, NULL);
  910. if (ret)
  911. goto fail;
  912. drm_plane_helper_add(plane, &mdp5_plane_helper_funcs);
  913. mdp5_plane_install_properties(plane, &plane->base);
  914. return plane;
  915. fail:
  916. if (plane)
  917. mdp5_plane_destroy(plane);
  918. return ERR_PTR(ret);
  919. }