dcn10_mpc.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446
  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. REG_UPDATE_5(MPCC_CONTROL[mpcc_id],
  60. MPCC_ALPHA_BLND_MODE, blnd_cfg->alpha_mode,
  61. MPCC_ALPHA_MULTIPLIED_MODE, blnd_cfg->pre_multiplied_alpha,
  62. MPCC_BLND_ACTIVE_OVERLAP_ONLY, blnd_cfg->overlap_only,
  63. MPCC_GLOBAL_ALPHA, blnd_cfg->global_alpha,
  64. MPCC_GLOBAL_GAIN, blnd_cfg->global_gain);
  65. mpc1_set_bg_color(mpc, &blnd_cfg->black_color, mpcc_id);
  66. }
  67. void mpc1_update_stereo_mix(
  68. struct mpc *mpc,
  69. struct mpcc_sm_cfg *sm_cfg,
  70. int mpcc_id)
  71. {
  72. struct dcn10_mpc *mpc10 = TO_DCN10_MPC(mpc);
  73. REG_UPDATE_6(MPCC_SM_CONTROL[mpcc_id],
  74. MPCC_SM_EN, sm_cfg->enable,
  75. MPCC_SM_MODE, sm_cfg->sm_mode,
  76. MPCC_SM_FRAME_ALT, sm_cfg->frame_alt,
  77. MPCC_SM_FIELD_ALT, sm_cfg->field_alt,
  78. MPCC_SM_FORCE_NEXT_FRAME_POL, sm_cfg->force_next_frame_porlarity,
  79. MPCC_SM_FORCE_NEXT_TOP_POL, sm_cfg->force_next_field_polarity);
  80. }
  81. void mpc1_assert_idle_mpcc(struct mpc *mpc, int id)
  82. {
  83. struct dcn10_mpc *mpc10 = TO_DCN10_MPC(mpc);
  84. ASSERT(!(mpc10->mpcc_in_use_mask & 1 << id));
  85. REG_WAIT(MPCC_STATUS[id],
  86. MPCC_IDLE, 1,
  87. 1, 100000);
  88. }
  89. struct mpcc *mpc1_get_mpcc(struct mpc *mpc, int mpcc_id)
  90. {
  91. struct dcn10_mpc *mpc10 = TO_DCN10_MPC(mpc);
  92. ASSERT(mpcc_id < mpc10->num_mpcc);
  93. return &(mpc->mpcc_array[mpcc_id]);
  94. }
  95. struct mpcc *mpc1_get_mpcc_for_dpp(struct mpc_tree *tree, int dpp_id)
  96. {
  97. struct mpcc *tmp_mpcc = tree->opp_list;
  98. while (tmp_mpcc != NULL) {
  99. if (tmp_mpcc->dpp_id == dpp_id)
  100. return tmp_mpcc;
  101. tmp_mpcc = tmp_mpcc->mpcc_bot;
  102. }
  103. return NULL;
  104. }
  105. bool mpc1_is_mpcc_idle(struct mpc *mpc, int mpcc_id)
  106. {
  107. struct dcn10_mpc *mpc10 = TO_DCN10_MPC(mpc);
  108. unsigned int top_sel;
  109. unsigned int opp_id;
  110. unsigned int idle;
  111. REG_GET(MPCC_TOP_SEL[mpcc_id], MPCC_TOP_SEL, &top_sel);
  112. REG_GET(MPCC_OPP_ID[mpcc_id], MPCC_OPP_ID, &opp_id);
  113. REG_GET(MPCC_STATUS[mpcc_id], MPCC_IDLE, &idle);
  114. if (top_sel == 0xf && opp_id == 0xf && idle)
  115. return true;
  116. else
  117. return false;
  118. }
  119. void mpc1_assert_mpcc_idle_before_connect(struct mpc *mpc, int mpcc_id)
  120. {
  121. struct dcn10_mpc *mpc10 = TO_DCN10_MPC(mpc);
  122. unsigned int top_sel, mpc_busy, mpc_idle;
  123. REG_GET(MPCC_TOP_SEL[mpcc_id],
  124. MPCC_TOP_SEL, &top_sel);
  125. if (top_sel == 0xf) {
  126. REG_GET_2(MPCC_STATUS[mpcc_id],
  127. MPCC_BUSY, &mpc_busy,
  128. MPCC_IDLE, &mpc_idle);
  129. ASSERT(mpc_busy == 0);
  130. ASSERT(mpc_idle == 1);
  131. }
  132. }
  133. /*
  134. * Insert DPP into MPC tree based on specified blending position.
  135. * Only used for planes that are part of blending chain for OPP output
  136. *
  137. * Parameters:
  138. * [in/out] mpc - MPC context.
  139. * [in/out] tree - MPC tree structure that plane will be added to.
  140. * [in] blnd_cfg - MPCC blending configuration for the new blending layer.
  141. * [in] sm_cfg - MPCC stereo mix configuration for the new blending layer.
  142. * stereo mix must disable for the very bottom layer of the tree config.
  143. * [in] insert_above_mpcc - Insert new plane above this MPCC. If NULL, insert as bottom plane.
  144. * [in] dpp_id - DPP instance for the plane to be added.
  145. * [in] mpcc_id - The MPCC physical instance to use for blending.
  146. *
  147. * Return: struct mpcc* - MPCC that was added.
  148. */
  149. struct mpcc *mpc1_insert_plane(
  150. struct mpc *mpc,
  151. struct mpc_tree *tree,
  152. struct mpcc_blnd_cfg *blnd_cfg,
  153. struct mpcc_sm_cfg *sm_cfg,
  154. struct mpcc *insert_above_mpcc,
  155. int dpp_id,
  156. int mpcc_id)
  157. {
  158. struct dcn10_mpc *mpc10 = TO_DCN10_MPC(mpc);
  159. struct mpcc *new_mpcc = NULL;
  160. /* sanity check parameters */
  161. ASSERT(mpcc_id < mpc10->num_mpcc);
  162. ASSERT(!(mpc10->mpcc_in_use_mask & 1 << mpcc_id));
  163. if (insert_above_mpcc) {
  164. /* check insert_above_mpcc exist in tree->opp_list */
  165. struct mpcc *temp_mpcc = tree->opp_list;
  166. while (temp_mpcc && temp_mpcc->mpcc_bot != insert_above_mpcc)
  167. temp_mpcc = temp_mpcc->mpcc_bot;
  168. if (temp_mpcc == NULL)
  169. return NULL;
  170. }
  171. /* Get and update MPCC struct parameters */
  172. new_mpcc = mpc1_get_mpcc(mpc, mpcc_id);
  173. new_mpcc->dpp_id = dpp_id;
  174. /* program mux and MPCC_MODE */
  175. if (insert_above_mpcc) {
  176. new_mpcc->mpcc_bot = insert_above_mpcc;
  177. REG_SET(MPCC_BOT_SEL[mpcc_id], 0, MPCC_BOT_SEL, insert_above_mpcc->mpcc_id);
  178. REG_UPDATE(MPCC_CONTROL[mpcc_id], MPCC_MODE, MPCC_BLEND_MODE_TOP_BOT_BLENDING);
  179. } else {
  180. new_mpcc->mpcc_bot = NULL;
  181. REG_SET(MPCC_BOT_SEL[mpcc_id], 0, MPCC_BOT_SEL, 0xf);
  182. REG_UPDATE(MPCC_CONTROL[mpcc_id], MPCC_MODE, MPCC_BLEND_MODE_TOP_LAYER_PASSTHROUGH);
  183. }
  184. REG_SET(MPCC_TOP_SEL[mpcc_id], 0, MPCC_TOP_SEL, dpp_id);
  185. REG_SET(MPCC_OPP_ID[mpcc_id], 0, MPCC_OPP_ID, tree->opp_id);
  186. /* update mpc tree mux setting */
  187. if (tree->opp_list == insert_above_mpcc) {
  188. /* insert the toppest mpcc */
  189. tree->opp_list = new_mpcc;
  190. REG_UPDATE(MUX[tree->opp_id], MPC_OUT_MUX, mpcc_id);
  191. } else {
  192. /* find insert position */
  193. struct mpcc *temp_mpcc = tree->opp_list;
  194. while (temp_mpcc && temp_mpcc->mpcc_bot != insert_above_mpcc)
  195. temp_mpcc = temp_mpcc->mpcc_bot;
  196. if (temp_mpcc && temp_mpcc->mpcc_bot == insert_above_mpcc) {
  197. REG_SET(MPCC_BOT_SEL[temp_mpcc->mpcc_id], 0, MPCC_BOT_SEL, mpcc_id);
  198. temp_mpcc->mpcc_bot = new_mpcc;
  199. if (!insert_above_mpcc)
  200. REG_UPDATE(MPCC_CONTROL[temp_mpcc->mpcc_id],
  201. MPCC_MODE, MPCC_BLEND_MODE_TOP_BOT_BLENDING);
  202. }
  203. }
  204. /* update the blending configuration */
  205. new_mpcc->blnd_cfg = *blnd_cfg;
  206. mpc->funcs->update_blending(mpc, &new_mpcc->blnd_cfg, mpcc_id);
  207. /* update the stereo mix settings, if provided */
  208. if (sm_cfg != NULL) {
  209. new_mpcc->sm_cfg = *sm_cfg;
  210. mpc1_update_stereo_mix(mpc, sm_cfg, mpcc_id);
  211. }
  212. /* mark this mpcc as in use */
  213. mpc10->mpcc_in_use_mask |= 1 << mpcc_id;
  214. return new_mpcc;
  215. }
  216. /*
  217. * Remove a specified MPCC from the MPC tree.
  218. *
  219. * Parameters:
  220. * [in/out] mpc - MPC context.
  221. * [in/out] tree - MPC tree structure that plane will be removed from.
  222. * [in/out] mpcc - MPCC to be removed from tree.
  223. *
  224. * Return: void
  225. */
  226. void mpc1_remove_mpcc(
  227. struct mpc *mpc,
  228. struct mpc_tree *tree,
  229. struct mpcc *mpcc_to_remove)
  230. {
  231. struct dcn10_mpc *mpc10 = TO_DCN10_MPC(mpc);
  232. bool found = false;
  233. int mpcc_id = mpcc_to_remove->mpcc_id;
  234. if (tree->opp_list == mpcc_to_remove) {
  235. found = true;
  236. /* remove MPCC from top of tree */
  237. if (mpcc_to_remove->mpcc_bot) {
  238. /* set the next MPCC in list to be the top MPCC */
  239. tree->opp_list = mpcc_to_remove->mpcc_bot;
  240. REG_UPDATE(MUX[tree->opp_id], MPC_OUT_MUX, tree->opp_list->mpcc_id);
  241. } else {
  242. /* there are no other MPCC is list */
  243. tree->opp_list = NULL;
  244. REG_UPDATE(MUX[tree->opp_id], MPC_OUT_MUX, 0xf);
  245. }
  246. } else {
  247. /* find mpcc to remove MPCC list */
  248. struct mpcc *temp_mpcc = tree->opp_list;
  249. while (temp_mpcc && temp_mpcc->mpcc_bot != mpcc_to_remove)
  250. temp_mpcc = temp_mpcc->mpcc_bot;
  251. if (temp_mpcc && temp_mpcc->mpcc_bot == mpcc_to_remove) {
  252. found = true;
  253. temp_mpcc->mpcc_bot = mpcc_to_remove->mpcc_bot;
  254. if (mpcc_to_remove->mpcc_bot) {
  255. /* remove MPCC in middle of list */
  256. REG_SET(MPCC_BOT_SEL[temp_mpcc->mpcc_id], 0,
  257. MPCC_BOT_SEL, mpcc_to_remove->mpcc_bot->mpcc_id);
  258. } else {
  259. /* remove MPCC from bottom of list */
  260. REG_SET(MPCC_BOT_SEL[temp_mpcc->mpcc_id], 0,
  261. MPCC_BOT_SEL, 0xf);
  262. REG_UPDATE(MPCC_CONTROL[temp_mpcc->mpcc_id],
  263. MPCC_MODE, MPCC_BLEND_MODE_TOP_LAYER_PASSTHROUGH);
  264. }
  265. }
  266. }
  267. if (found) {
  268. /* turn off MPCC mux registers */
  269. REG_SET(MPCC_TOP_SEL[mpcc_id], 0, MPCC_TOP_SEL, 0xf);
  270. REG_SET(MPCC_BOT_SEL[mpcc_id], 0, MPCC_BOT_SEL, 0xf);
  271. REG_SET(MPCC_OPP_ID[mpcc_id], 0, MPCC_OPP_ID, 0xf);
  272. /* mark this mpcc as not in use */
  273. mpc10->mpcc_in_use_mask &= ~(1 << mpcc_id);
  274. mpcc_to_remove->dpp_id = 0xf;
  275. mpcc_to_remove->mpcc_bot = NULL;
  276. } else {
  277. /* In case of resume from S3/S4, remove mpcc from bios left over */
  278. REG_SET(MPCC_TOP_SEL[mpcc_id], 0, MPCC_TOP_SEL, 0xf);
  279. REG_SET(MPCC_BOT_SEL[mpcc_id], 0, MPCC_BOT_SEL, 0xf);
  280. REG_SET(MPCC_OPP_ID[mpcc_id], 0, MPCC_OPP_ID, 0xf);
  281. }
  282. }
  283. static void mpc1_init_mpcc(struct mpcc *mpcc, int mpcc_inst)
  284. {
  285. mpcc->mpcc_id = mpcc_inst;
  286. mpcc->dpp_id = 0xf;
  287. mpcc->mpcc_bot = NULL;
  288. mpcc->blnd_cfg.overlap_only = false;
  289. mpcc->blnd_cfg.global_alpha = 0xff;
  290. mpcc->blnd_cfg.global_gain = 0xff;
  291. mpcc->sm_cfg.enable = false;
  292. }
  293. /*
  294. * Reset the MPCC HW status by disconnecting all muxes.
  295. *
  296. * Parameters:
  297. * [in/out] mpc - MPC context.
  298. *
  299. * Return: void
  300. */
  301. void mpc1_mpc_init(struct mpc *mpc)
  302. {
  303. struct dcn10_mpc *mpc10 = TO_DCN10_MPC(mpc);
  304. int mpcc_id;
  305. int opp_id;
  306. mpc10->mpcc_in_use_mask = 0;
  307. for (mpcc_id = 0; mpcc_id < mpc10->num_mpcc; mpcc_id++) {
  308. REG_SET(MPCC_TOP_SEL[mpcc_id], 0, MPCC_TOP_SEL, 0xf);
  309. REG_SET(MPCC_BOT_SEL[mpcc_id], 0, MPCC_BOT_SEL, 0xf);
  310. REG_SET(MPCC_OPP_ID[mpcc_id], 0, MPCC_OPP_ID, 0xf);
  311. mpc1_init_mpcc(&(mpc->mpcc_array[mpcc_id]), mpcc_id);
  312. }
  313. for (opp_id = 0; opp_id < MAX_OPP; opp_id++) {
  314. if (REG(MUX[opp_id]))
  315. REG_UPDATE(MUX[opp_id], MPC_OUT_MUX, 0xf);
  316. }
  317. }
  318. void mpc1_init_mpcc_list_from_hw(
  319. struct mpc *mpc,
  320. struct mpc_tree *tree)
  321. {
  322. struct dcn10_mpc *mpc10 = TO_DCN10_MPC(mpc);
  323. unsigned int opp_id;
  324. unsigned int top_sel;
  325. unsigned int bot_sel;
  326. unsigned int out_mux;
  327. struct mpcc *mpcc;
  328. int mpcc_id;
  329. int bot_mpcc_id;
  330. REG_GET(MUX[tree->opp_id], MPC_OUT_MUX, &out_mux);
  331. if (out_mux != 0xf) {
  332. for (mpcc_id = 0; mpcc_id < mpc10->num_mpcc; mpcc_id++) {
  333. REG_GET(MPCC_OPP_ID[mpcc_id], MPCC_OPP_ID, &opp_id);
  334. REG_GET(MPCC_TOP_SEL[mpcc_id], MPCC_TOP_SEL, &top_sel);
  335. REG_GET(MPCC_BOT_SEL[mpcc_id], MPCC_BOT_SEL, &bot_sel);
  336. if (bot_sel == mpcc_id)
  337. bot_sel = 0xf;
  338. if ((opp_id == tree->opp_id) && (top_sel != 0xf)) {
  339. mpcc = mpc1_get_mpcc(mpc, mpcc_id);
  340. mpcc->dpp_id = top_sel;
  341. mpc10->mpcc_in_use_mask |= 1 << mpcc_id;
  342. if (out_mux == mpcc_id)
  343. tree->opp_list = mpcc;
  344. if (bot_sel != 0xf && bot_sel < mpc10->num_mpcc) {
  345. bot_mpcc_id = bot_sel;
  346. REG_GET(MPCC_OPP_ID[bot_mpcc_id], MPCC_OPP_ID, &opp_id);
  347. REG_GET(MPCC_TOP_SEL[bot_mpcc_id], MPCC_TOP_SEL, &top_sel);
  348. if ((opp_id == tree->opp_id) && (top_sel != 0xf)) {
  349. struct mpcc *mpcc_bottom = mpc1_get_mpcc(mpc, bot_mpcc_id);
  350. mpcc->mpcc_bot = mpcc_bottom;
  351. }
  352. }
  353. }
  354. }
  355. }
  356. }
  357. const struct mpc_funcs dcn10_mpc_funcs = {
  358. .insert_plane = mpc1_insert_plane,
  359. .remove_mpcc = mpc1_remove_mpcc,
  360. .mpc_init = mpc1_mpc_init,
  361. .get_mpcc_for_dpp = mpc1_get_mpcc_for_dpp,
  362. .wait_for_idle = mpc1_assert_idle_mpcc,
  363. .assert_mpcc_idle_before_connect = mpc1_assert_mpcc_idle_before_connect,
  364. .init_mpcc_list_from_hw = mpc1_init_mpcc_list_from_hw,
  365. .update_blending = mpc1_update_blending,
  366. };
  367. void dcn10_mpc_construct(struct dcn10_mpc *mpc10,
  368. struct dc_context *ctx,
  369. const struct dcn_mpc_registers *mpc_regs,
  370. const struct dcn_mpc_shift *mpc_shift,
  371. const struct dcn_mpc_mask *mpc_mask,
  372. int num_mpcc)
  373. {
  374. int i;
  375. mpc10->base.ctx = ctx;
  376. mpc10->base.funcs = &dcn10_mpc_funcs;
  377. mpc10->mpc_regs = mpc_regs;
  378. mpc10->mpc_shift = mpc_shift;
  379. mpc10->mpc_mask = mpc_mask;
  380. mpc10->mpcc_in_use_mask = 0;
  381. mpc10->num_mpcc = num_mpcc;
  382. for (i = 0; i < MAX_MPCC; i++)
  383. mpc1_init_mpcc(&mpc10->base.mpcc_array[i], i);
  384. }