dcn10_mpc.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466
  1. /*
  2. * Copyright 2012-15 Advanced Micro Devices, Inc.
  3. *
  4. * Permission is hereby granted, free of charge, to any person obtaining a
  5. * copy of this software and associated documentation files (the "Software"),
  6. * to deal in the Software without restriction, including without limitation
  7. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  8. * and/or sell copies of the Software, and to permit persons to whom the
  9. * Software is furnished to do so, subject to the following conditions:
  10. *
  11. * The above copyright notice and this permission notice shall be included in
  12. * all copies or substantial portions of the Software.
  13. *
  14. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  17. * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
  18. * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
  19. * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  20. * OTHER DEALINGS IN THE SOFTWARE.
  21. *
  22. * Authors: AMD
  23. *
  24. */
  25. #include "reg_helper.h"
  26. #include "dcn10_mpc.h"
  27. #define REG(reg)\
  28. mpc10->mpc_regs->reg
  29. #define CTX \
  30. mpc10->base.ctx
  31. #undef FN
  32. #define FN(reg_name, field_name) \
  33. mpc10->mpc_shift->field_name, mpc10->mpc_mask->field_name
  34. void mpc1_set_bg_color(struct mpc *mpc,
  35. struct tg_color *bg_color,
  36. int mpcc_id)
  37. {
  38. struct dcn10_mpc *mpc10 = TO_DCN10_MPC(mpc);
  39. /* mpc color is 12 bit. tg_color is 10 bit */
  40. /* todo: might want to use 16 bit to represent color and have each
  41. * hw block translate to correct color depth.
  42. */
  43. uint32_t bg_r_cr = bg_color->color_r_cr << 2;
  44. uint32_t bg_g_y = bg_color->color_g_y << 2;
  45. uint32_t bg_b_cb = bg_color->color_b_cb << 2;
  46. REG_SET(MPCC_BG_R_CR[mpcc_id], 0,
  47. MPCC_BG_R_CR, bg_r_cr);
  48. REG_SET(MPCC_BG_G_Y[mpcc_id], 0,
  49. MPCC_BG_G_Y, bg_g_y);
  50. REG_SET(MPCC_BG_B_CB[mpcc_id], 0,
  51. MPCC_BG_B_CB, bg_b_cb);
  52. }
  53. static void mpc1_update_blending(
  54. struct mpc *mpc,
  55. struct mpcc_blnd_cfg *blnd_cfg,
  56. int mpcc_id)
  57. {
  58. struct dcn10_mpc *mpc10 = TO_DCN10_MPC(mpc);
  59. struct mpcc *mpcc = mpc1_get_mpcc(mpc, mpcc_id);
  60. REG_UPDATE_5(MPCC_CONTROL[mpcc_id],
  61. MPCC_ALPHA_BLND_MODE, blnd_cfg->alpha_mode,
  62. MPCC_ALPHA_MULTIPLIED_MODE, blnd_cfg->pre_multiplied_alpha,
  63. MPCC_BLND_ACTIVE_OVERLAP_ONLY, blnd_cfg->overlap_only,
  64. MPCC_GLOBAL_ALPHA, blnd_cfg->global_alpha,
  65. MPCC_GLOBAL_GAIN, blnd_cfg->global_gain);
  66. mpc1_set_bg_color(mpc, &blnd_cfg->black_color, mpcc_id);
  67. mpcc->blnd_cfg = *blnd_cfg;
  68. }
  69. void mpc1_update_stereo_mix(
  70. struct mpc *mpc,
  71. struct mpcc_sm_cfg *sm_cfg,
  72. int mpcc_id)
  73. {
  74. struct dcn10_mpc *mpc10 = TO_DCN10_MPC(mpc);
  75. REG_UPDATE_6(MPCC_SM_CONTROL[mpcc_id],
  76. MPCC_SM_EN, sm_cfg->enable,
  77. MPCC_SM_MODE, sm_cfg->sm_mode,
  78. MPCC_SM_FRAME_ALT, sm_cfg->frame_alt,
  79. MPCC_SM_FIELD_ALT, sm_cfg->field_alt,
  80. MPCC_SM_FORCE_NEXT_FRAME_POL, sm_cfg->force_next_frame_porlarity,
  81. MPCC_SM_FORCE_NEXT_TOP_POL, sm_cfg->force_next_field_polarity);
  82. }
  83. void mpc1_assert_idle_mpcc(struct mpc *mpc, int id)
  84. {
  85. struct dcn10_mpc *mpc10 = TO_DCN10_MPC(mpc);
  86. ASSERT(!(mpc10->mpcc_in_use_mask & 1 << id));
  87. REG_WAIT(MPCC_STATUS[id],
  88. MPCC_IDLE, 1,
  89. 1, 100000);
  90. }
  91. struct mpcc *mpc1_get_mpcc(struct mpc *mpc, int mpcc_id)
  92. {
  93. struct dcn10_mpc *mpc10 = TO_DCN10_MPC(mpc);
  94. ASSERT(mpcc_id < mpc10->num_mpcc);
  95. return &(mpc->mpcc_array[mpcc_id]);
  96. }
  97. struct mpcc *mpc1_get_mpcc_for_dpp(struct mpc_tree *tree, int dpp_id)
  98. {
  99. struct mpcc *tmp_mpcc = tree->opp_list;
  100. while (tmp_mpcc != NULL) {
  101. if (tmp_mpcc->dpp_id == dpp_id)
  102. return tmp_mpcc;
  103. tmp_mpcc = tmp_mpcc->mpcc_bot;
  104. }
  105. return NULL;
  106. }
  107. bool mpc1_is_mpcc_idle(struct mpc *mpc, int mpcc_id)
  108. {
  109. struct dcn10_mpc *mpc10 = TO_DCN10_MPC(mpc);
  110. unsigned int top_sel;
  111. unsigned int opp_id;
  112. unsigned int idle;
  113. REG_GET(MPCC_TOP_SEL[mpcc_id], MPCC_TOP_SEL, &top_sel);
  114. REG_GET(MPCC_OPP_ID[mpcc_id], MPCC_OPP_ID, &opp_id);
  115. REG_GET(MPCC_STATUS[mpcc_id], MPCC_IDLE, &idle);
  116. if (top_sel == 0xf && opp_id == 0xf && idle)
  117. return true;
  118. else
  119. return false;
  120. }
  121. void mpc1_assert_mpcc_idle_before_connect(struct mpc *mpc, int mpcc_id)
  122. {
  123. struct dcn10_mpc *mpc10 = TO_DCN10_MPC(mpc);
  124. unsigned int top_sel, mpc_busy, mpc_idle;
  125. REG_GET(MPCC_TOP_SEL[mpcc_id],
  126. MPCC_TOP_SEL, &top_sel);
  127. if (top_sel == 0xf) {
  128. REG_GET_2(MPCC_STATUS[mpcc_id],
  129. MPCC_BUSY, &mpc_busy,
  130. MPCC_IDLE, &mpc_idle);
  131. ASSERT(mpc_busy == 0);
  132. ASSERT(mpc_idle == 1);
  133. }
  134. }
  135. /*
  136. * Insert DPP into MPC tree based on specified blending position.
  137. * Only used for planes that are part of blending chain for OPP output
  138. *
  139. * Parameters:
  140. * [in/out] mpc - MPC context.
  141. * [in/out] tree - MPC tree structure that plane will be added to.
  142. * [in] blnd_cfg - MPCC blending configuration for the new blending layer.
  143. * [in] sm_cfg - MPCC stereo mix configuration for the new blending layer.
  144. * stereo mix must disable for the very bottom layer of the tree config.
  145. * [in] insert_above_mpcc - Insert new plane above this MPCC. If NULL, insert as bottom plane.
  146. * [in] dpp_id - DPP instance for the plane to be added.
  147. * [in] mpcc_id - The MPCC physical instance to use for blending.
  148. *
  149. * Return: struct mpcc* - MPCC that was added.
  150. */
  151. struct mpcc *mpc1_insert_plane(
  152. struct mpc *mpc,
  153. struct mpc_tree *tree,
  154. struct mpcc_blnd_cfg *blnd_cfg,
  155. struct mpcc_sm_cfg *sm_cfg,
  156. struct mpcc *insert_above_mpcc,
  157. int dpp_id,
  158. int mpcc_id)
  159. {
  160. struct dcn10_mpc *mpc10 = TO_DCN10_MPC(mpc);
  161. struct mpcc *new_mpcc = NULL;
  162. /* sanity check parameters */
  163. ASSERT(mpcc_id < mpc10->num_mpcc);
  164. ASSERT(!(mpc10->mpcc_in_use_mask & 1 << mpcc_id));
  165. if (insert_above_mpcc) {
  166. /* check insert_above_mpcc exist in tree->opp_list */
  167. struct mpcc *temp_mpcc = tree->opp_list;
  168. while (temp_mpcc && temp_mpcc->mpcc_bot != insert_above_mpcc)
  169. temp_mpcc = temp_mpcc->mpcc_bot;
  170. if (temp_mpcc == NULL)
  171. return NULL;
  172. }
  173. /* Get and update MPCC struct parameters */
  174. new_mpcc = mpc1_get_mpcc(mpc, mpcc_id);
  175. new_mpcc->dpp_id = dpp_id;
  176. /* program mux and MPCC_MODE */
  177. if (insert_above_mpcc) {
  178. new_mpcc->mpcc_bot = insert_above_mpcc;
  179. REG_SET(MPCC_BOT_SEL[mpcc_id], 0, MPCC_BOT_SEL, insert_above_mpcc->mpcc_id);
  180. REG_UPDATE(MPCC_CONTROL[mpcc_id], MPCC_MODE, MPCC_BLEND_MODE_TOP_BOT_BLENDING);
  181. } else {
  182. new_mpcc->mpcc_bot = NULL;
  183. REG_SET(MPCC_BOT_SEL[mpcc_id], 0, MPCC_BOT_SEL, 0xf);
  184. REG_UPDATE(MPCC_CONTROL[mpcc_id], MPCC_MODE, MPCC_BLEND_MODE_TOP_LAYER_PASSTHROUGH);
  185. }
  186. REG_SET(MPCC_TOP_SEL[mpcc_id], 0, MPCC_TOP_SEL, dpp_id);
  187. REG_SET(MPCC_OPP_ID[mpcc_id], 0, MPCC_OPP_ID, tree->opp_id);
  188. /* update mpc tree mux setting */
  189. if (tree->opp_list == insert_above_mpcc) {
  190. /* insert the toppest mpcc */
  191. tree->opp_list = new_mpcc;
  192. REG_UPDATE(MUX[tree->opp_id], MPC_OUT_MUX, mpcc_id);
  193. } else {
  194. /* find insert position */
  195. struct mpcc *temp_mpcc = tree->opp_list;
  196. while (temp_mpcc && temp_mpcc->mpcc_bot != insert_above_mpcc)
  197. temp_mpcc = temp_mpcc->mpcc_bot;
  198. if (temp_mpcc && temp_mpcc->mpcc_bot == insert_above_mpcc) {
  199. REG_SET(MPCC_BOT_SEL[temp_mpcc->mpcc_id], 0, MPCC_BOT_SEL, mpcc_id);
  200. temp_mpcc->mpcc_bot = new_mpcc;
  201. if (!insert_above_mpcc)
  202. REG_UPDATE(MPCC_CONTROL[temp_mpcc->mpcc_id],
  203. MPCC_MODE, MPCC_BLEND_MODE_TOP_BOT_BLENDING);
  204. }
  205. }
  206. /* update the blending configuration */
  207. mpc->funcs->update_blending(mpc, blnd_cfg, mpcc_id);
  208. /* update the stereo mix settings, if provided */
  209. if (sm_cfg != NULL) {
  210. new_mpcc->sm_cfg = *sm_cfg;
  211. mpc1_update_stereo_mix(mpc, sm_cfg, mpcc_id);
  212. }
  213. /* mark this mpcc as in use */
  214. mpc10->mpcc_in_use_mask |= 1 << mpcc_id;
  215. return new_mpcc;
  216. }
  217. /*
  218. * Remove a specified MPCC from the MPC tree.
  219. *
  220. * Parameters:
  221. * [in/out] mpc - MPC context.
  222. * [in/out] tree - MPC tree structure that plane will be removed from.
  223. * [in/out] mpcc - MPCC to be removed from tree.
  224. *
  225. * Return: void
  226. */
  227. void mpc1_remove_mpcc(
  228. struct mpc *mpc,
  229. struct mpc_tree *tree,
  230. struct mpcc *mpcc_to_remove)
  231. {
  232. struct dcn10_mpc *mpc10 = TO_DCN10_MPC(mpc);
  233. bool found = false;
  234. int mpcc_id = mpcc_to_remove->mpcc_id;
  235. if (tree->opp_list == mpcc_to_remove) {
  236. found = true;
  237. /* remove MPCC from top of tree */
  238. if (mpcc_to_remove->mpcc_bot) {
  239. /* set the next MPCC in list to be the top MPCC */
  240. tree->opp_list = mpcc_to_remove->mpcc_bot;
  241. REG_UPDATE(MUX[tree->opp_id], MPC_OUT_MUX, tree->opp_list->mpcc_id);
  242. } else {
  243. /* there are no other MPCC is list */
  244. tree->opp_list = NULL;
  245. REG_UPDATE(MUX[tree->opp_id], MPC_OUT_MUX, 0xf);
  246. }
  247. } else {
  248. /* find mpcc to remove MPCC list */
  249. struct mpcc *temp_mpcc = tree->opp_list;
  250. while (temp_mpcc && temp_mpcc->mpcc_bot != mpcc_to_remove)
  251. temp_mpcc = temp_mpcc->mpcc_bot;
  252. if (temp_mpcc && temp_mpcc->mpcc_bot == mpcc_to_remove) {
  253. found = true;
  254. temp_mpcc->mpcc_bot = mpcc_to_remove->mpcc_bot;
  255. if (mpcc_to_remove->mpcc_bot) {
  256. /* remove MPCC in middle of list */
  257. REG_SET(MPCC_BOT_SEL[temp_mpcc->mpcc_id], 0,
  258. MPCC_BOT_SEL, mpcc_to_remove->mpcc_bot->mpcc_id);
  259. } else {
  260. /* remove MPCC from bottom of list */
  261. REG_SET(MPCC_BOT_SEL[temp_mpcc->mpcc_id], 0,
  262. MPCC_BOT_SEL, 0xf);
  263. REG_UPDATE(MPCC_CONTROL[temp_mpcc->mpcc_id],
  264. MPCC_MODE, MPCC_BLEND_MODE_TOP_LAYER_PASSTHROUGH);
  265. }
  266. }
  267. }
  268. if (found) {
  269. /* turn off MPCC mux registers */
  270. REG_SET(MPCC_TOP_SEL[mpcc_id], 0, MPCC_TOP_SEL, 0xf);
  271. REG_SET(MPCC_BOT_SEL[mpcc_id], 0, MPCC_BOT_SEL, 0xf);
  272. REG_SET(MPCC_OPP_ID[mpcc_id], 0, MPCC_OPP_ID, 0xf);
  273. /* mark this mpcc as not in use */
  274. mpc10->mpcc_in_use_mask &= ~(1 << mpcc_id);
  275. mpcc_to_remove->dpp_id = 0xf;
  276. mpcc_to_remove->mpcc_bot = NULL;
  277. } else {
  278. /* In case of resume from S3/S4, remove mpcc from bios left over */
  279. REG_SET(MPCC_TOP_SEL[mpcc_id], 0, MPCC_TOP_SEL, 0xf);
  280. REG_SET(MPCC_BOT_SEL[mpcc_id], 0, MPCC_BOT_SEL, 0xf);
  281. REG_SET(MPCC_OPP_ID[mpcc_id], 0, MPCC_OPP_ID, 0xf);
  282. }
  283. }
  284. static void mpc1_init_mpcc(struct mpcc *mpcc, int mpcc_inst)
  285. {
  286. mpcc->mpcc_id = mpcc_inst;
  287. mpcc->dpp_id = 0xf;
  288. mpcc->mpcc_bot = NULL;
  289. mpcc->blnd_cfg.overlap_only = false;
  290. mpcc->blnd_cfg.global_alpha = 0xff;
  291. mpcc->blnd_cfg.global_gain = 0xff;
  292. mpcc->sm_cfg.enable = false;
  293. }
  294. /*
  295. * Reset the MPCC HW status by disconnecting all muxes.
  296. *
  297. * Parameters:
  298. * [in/out] mpc - MPC context.
  299. *
  300. * Return: void
  301. */
  302. void mpc1_mpc_init(struct mpc *mpc)
  303. {
  304. struct dcn10_mpc *mpc10 = TO_DCN10_MPC(mpc);
  305. int mpcc_id;
  306. int opp_id;
  307. mpc10->mpcc_in_use_mask = 0;
  308. for (mpcc_id = 0; mpcc_id < mpc10->num_mpcc; mpcc_id++) {
  309. REG_SET(MPCC_TOP_SEL[mpcc_id], 0, MPCC_TOP_SEL, 0xf);
  310. REG_SET(MPCC_BOT_SEL[mpcc_id], 0, MPCC_BOT_SEL, 0xf);
  311. REG_SET(MPCC_OPP_ID[mpcc_id], 0, MPCC_OPP_ID, 0xf);
  312. mpc1_init_mpcc(&(mpc->mpcc_array[mpcc_id]), mpcc_id);
  313. }
  314. for (opp_id = 0; opp_id < MAX_OPP; opp_id++) {
  315. if (REG(MUX[opp_id]))
  316. REG_UPDATE(MUX[opp_id], MPC_OUT_MUX, 0xf);
  317. }
  318. }
  319. void mpc1_init_mpcc_list_from_hw(
  320. struct mpc *mpc,
  321. struct mpc_tree *tree)
  322. {
  323. struct dcn10_mpc *mpc10 = TO_DCN10_MPC(mpc);
  324. unsigned int opp_id;
  325. unsigned int top_sel;
  326. unsigned int bot_sel;
  327. unsigned int out_mux;
  328. struct mpcc *mpcc;
  329. int mpcc_id;
  330. int bot_mpcc_id;
  331. REG_GET(MUX[tree->opp_id], MPC_OUT_MUX, &out_mux);
  332. if (out_mux != 0xf) {
  333. for (mpcc_id = 0; mpcc_id < mpc10->num_mpcc; mpcc_id++) {
  334. REG_GET(MPCC_OPP_ID[mpcc_id], MPCC_OPP_ID, &opp_id);
  335. REG_GET(MPCC_TOP_SEL[mpcc_id], MPCC_TOP_SEL, &top_sel);
  336. REG_GET(MPCC_BOT_SEL[mpcc_id], MPCC_BOT_SEL, &bot_sel);
  337. if (bot_sel == mpcc_id)
  338. bot_sel = 0xf;
  339. if ((opp_id == tree->opp_id) && (top_sel != 0xf)) {
  340. mpcc = mpc1_get_mpcc(mpc, mpcc_id);
  341. mpcc->dpp_id = top_sel;
  342. mpc10->mpcc_in_use_mask |= 1 << mpcc_id;
  343. if (out_mux == mpcc_id)
  344. tree->opp_list = mpcc;
  345. if (bot_sel != 0xf && bot_sel < mpc10->num_mpcc) {
  346. bot_mpcc_id = bot_sel;
  347. REG_GET(MPCC_OPP_ID[bot_mpcc_id], MPCC_OPP_ID, &opp_id);
  348. REG_GET(MPCC_TOP_SEL[bot_mpcc_id], MPCC_TOP_SEL, &top_sel);
  349. if ((opp_id == tree->opp_id) && (top_sel != 0xf)) {
  350. struct mpcc *mpcc_bottom = mpc1_get_mpcc(mpc, bot_mpcc_id);
  351. mpcc->mpcc_bot = mpcc_bottom;
  352. }
  353. }
  354. }
  355. }
  356. }
  357. }
  358. void mpc1_read_mpcc_state(
  359. struct mpc *mpc,
  360. int mpcc_inst,
  361. struct mpcc_state *s)
  362. {
  363. struct dcn10_mpc *mpc10 = TO_DCN10_MPC(mpc);
  364. REG_GET(MPCC_OPP_ID[mpcc_inst], MPCC_OPP_ID, &s->opp_id);
  365. REG_GET(MPCC_TOP_SEL[mpcc_inst], MPCC_TOP_SEL, &s->dpp_id);
  366. REG_GET(MPCC_BOT_SEL[mpcc_inst], MPCC_BOT_SEL, &s->bot_mpcc_id);
  367. REG_GET_4(MPCC_CONTROL[mpcc_inst], MPCC_MODE, &s->mode,
  368. MPCC_ALPHA_BLND_MODE, &s->alpha_mode,
  369. MPCC_ALPHA_MULTIPLIED_MODE, &s->pre_multiplied_alpha,
  370. MPCC_BLND_ACTIVE_OVERLAP_ONLY, &s->overlap_only);
  371. REG_GET_2(MPCC_STATUS[mpcc_inst], MPCC_IDLE, &s->idle,
  372. MPCC_BUSY, &s->busy);
  373. }
  374. static const struct mpc_funcs dcn10_mpc_funcs = {
  375. .read_mpcc_state = mpc1_read_mpcc_state,
  376. .insert_plane = mpc1_insert_plane,
  377. .remove_mpcc = mpc1_remove_mpcc,
  378. .mpc_init = mpc1_mpc_init,
  379. .get_mpcc_for_dpp = mpc1_get_mpcc_for_dpp,
  380. .wait_for_idle = mpc1_assert_idle_mpcc,
  381. .assert_mpcc_idle_before_connect = mpc1_assert_mpcc_idle_before_connect,
  382. .init_mpcc_list_from_hw = mpc1_init_mpcc_list_from_hw,
  383. .update_blending = mpc1_update_blending,
  384. };
  385. void dcn10_mpc_construct(struct dcn10_mpc *mpc10,
  386. struct dc_context *ctx,
  387. const struct dcn_mpc_registers *mpc_regs,
  388. const struct dcn_mpc_shift *mpc_shift,
  389. const struct dcn_mpc_mask *mpc_mask,
  390. int num_mpcc)
  391. {
  392. int i;
  393. mpc10->base.ctx = ctx;
  394. mpc10->base.funcs = &dcn10_mpc_funcs;
  395. mpc10->mpc_regs = mpc_regs;
  396. mpc10->mpc_shift = mpc_shift;
  397. mpc10->mpc_mask = mpc_mask;
  398. mpc10->mpcc_in_use_mask = 0;
  399. mpc10->num_mpcc = num_mpcc;
  400. for (i = 0; i < MAX_MPCC; i++)
  401. mpc1_init_mpcc(&mpc10->base.mpcc_array[i], i);
  402. }