dcn10_mpc.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374
  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. #include "dc.h"
  28. #include "mem_input.h"
  29. #define REG(reg)\
  30. mpc10->mpc_regs->reg
  31. #define CTX \
  32. mpc10->base.ctx
  33. #undef FN
  34. #define FN(reg_name, field_name) \
  35. mpc10->mpc_shift->field_name, mpc10->mpc_mask->field_name
  36. #define MODE_TOP_ONLY 1
  37. #define MODE_BLEND 3
  38. #define BLND_PP_ALPHA 0
  39. #define BLND_GLOBAL_ALPHA 2
  40. static void mpc10_set_bg_color(
  41. struct dcn10_mpc *mpc10,
  42. struct tg_color *bg_color,
  43. int id)
  44. {
  45. /* mpc color is 12 bit. tg_color is 10 bit */
  46. /* todo: might want to use 16 bit to represent color and have each
  47. * hw block translate to correct color depth.
  48. */
  49. uint32_t bg_r_cr = bg_color->color_r_cr << 2;
  50. uint32_t bg_g_y = bg_color->color_g_y << 2;
  51. uint32_t bg_b_cb = bg_color->color_b_cb << 2;
  52. REG_SET(MPCC_BG_R_CR[id], 0,
  53. MPCC_BG_R_CR, bg_r_cr);
  54. REG_SET(MPCC_BG_G_Y[id], 0,
  55. MPCC_BG_G_Y, bg_g_y);
  56. REG_SET(MPCC_BG_B_CB[id], 0,
  57. MPCC_BG_B_CB, bg_b_cb);
  58. }
  59. void mpc10_assert_idle_mpcc(struct mpc *mpc, int id)
  60. {
  61. struct dcn10_mpc *mpc10 = TO_DCN10_MPC(mpc);
  62. ASSERT(!(mpc10->mpcc_in_use_mask & 1 << id));
  63. REG_WAIT(MPCC_STATUS[id],
  64. MPCC_IDLE, 1,
  65. 1, 100000);
  66. }
  67. static int mpc10_get_idle_mpcc_id(struct dcn10_mpc *mpc10)
  68. {
  69. int i;
  70. int last_free_mpcc_id = -1;
  71. for (i = 0; i < mpc10->num_mpcc; i++) {
  72. uint32_t is_idle = 0;
  73. if (mpc10->mpcc_in_use_mask & 1 << i)
  74. continue;
  75. last_free_mpcc_id = i;
  76. REG_GET(MPCC_STATUS[i], MPCC_IDLE, &is_idle);
  77. if (is_idle)
  78. return i;
  79. }
  80. /* This assert should never trigger, we have mpcc leak if it does */
  81. ASSERT(last_free_mpcc_id != -1);
  82. mpc10_assert_idle_mpcc(&mpc10->base, last_free_mpcc_id);
  83. return last_free_mpcc_id;
  84. }
  85. static void mpc10_assert_mpcc_idle_before_connect(struct dcn10_mpc *mpc10, int id)
  86. {
  87. unsigned int top_sel, mpc_busy, mpc_idle;
  88. REG_GET(MPCC_TOP_SEL[id],
  89. MPCC_TOP_SEL, &top_sel);
  90. if (top_sel == 0xf) {
  91. REG_GET_2(MPCC_STATUS[id],
  92. MPCC_BUSY, &mpc_busy,
  93. MPCC_IDLE, &mpc_idle);
  94. ASSERT(mpc_busy == 0);
  95. ASSERT(mpc_idle == 1);
  96. }
  97. }
  98. void mpc10_mpcc_remove(
  99. struct mpc *mpc,
  100. struct mpc_tree_cfg *tree_cfg,
  101. int opp_id,
  102. int dpp_id)
  103. {
  104. struct dcn10_mpc *mpc10 = TO_DCN10_MPC(mpc);
  105. int mpcc_id, z_idx;
  106. /* find z_idx for the dpp to be removed */
  107. for (z_idx = 0; z_idx < tree_cfg->num_pipes; z_idx++)
  108. if (tree_cfg->dpp[z_idx] == dpp_id)
  109. break;
  110. if (z_idx == tree_cfg->num_pipes) {
  111. /* In case of resume from S3/S4, remove mpcc from bios left over */
  112. REG_SET(MPCC_OPP_ID[dpp_id], 0,
  113. MPCC_OPP_ID, 0xf);
  114. REG_SET(MPCC_TOP_SEL[dpp_id], 0,
  115. MPCC_TOP_SEL, 0xf);
  116. REG_SET(MPCC_BOT_SEL[dpp_id], 0,
  117. MPCC_BOT_SEL, 0xf);
  118. return;
  119. }
  120. mpcc_id = tree_cfg->mpcc[z_idx];
  121. REG_SET(MPCC_OPP_ID[mpcc_id], 0,
  122. MPCC_OPP_ID, 0xf);
  123. REG_SET(MPCC_TOP_SEL[mpcc_id], 0,
  124. MPCC_TOP_SEL, 0xf);
  125. REG_SET(MPCC_BOT_SEL[mpcc_id], 0,
  126. MPCC_BOT_SEL, 0xf);
  127. if (z_idx > 0) {
  128. int top_mpcc_id = tree_cfg->mpcc[z_idx - 1];
  129. if (z_idx + 1 < tree_cfg->num_pipes)
  130. /* mpcc to be removed is in the middle of the tree */
  131. REG_SET(MPCC_BOT_SEL[top_mpcc_id], 0,
  132. MPCC_BOT_SEL, tree_cfg->mpcc[z_idx + 1]);
  133. else {
  134. /* mpcc to be removed is at the bottom of the tree */
  135. REG_SET(MPCC_BOT_SEL[top_mpcc_id], 0,
  136. MPCC_BOT_SEL, 0xf);
  137. REG_UPDATE(MPCC_CONTROL[top_mpcc_id],
  138. MPCC_MODE, MODE_TOP_ONLY);
  139. }
  140. } else if (tree_cfg->num_pipes > 1)
  141. /* mpcc to be removed is at the top of the tree */
  142. REG_SET(MUX[opp_id], 0,
  143. MPC_OUT_MUX, tree_cfg->mpcc[z_idx + 1]);
  144. else
  145. /* mpcc to be removed is the only one in the tree */
  146. REG_SET(MUX[opp_id], 0, MPC_OUT_MUX, 0xf);
  147. /* mark this mpcc as not in use */
  148. mpc10->mpcc_in_use_mask &= ~(1 << mpcc_id);
  149. tree_cfg->num_pipes--;
  150. for (; z_idx < tree_cfg->num_pipes; z_idx++) {
  151. tree_cfg->dpp[z_idx] = tree_cfg->dpp[z_idx + 1];
  152. tree_cfg->mpcc[z_idx] = tree_cfg->mpcc[z_idx + 1];
  153. }
  154. tree_cfg->dpp[tree_cfg->num_pipes] = 0xdeadbeef;
  155. tree_cfg->mpcc[tree_cfg->num_pipes] = 0xdeadbeef;
  156. }
  157. static void mpc10_add_to_tree_cfg(
  158. struct mpc *mpc,
  159. struct mpcc_cfg *cfg,
  160. int mpcc_id)
  161. {
  162. struct dcn10_mpc *mpc10 = TO_DCN10_MPC(mpc);
  163. int mpcc_mode = MODE_TOP_ONLY;
  164. int position = cfg->z_index;
  165. struct mpc_tree_cfg *tree_cfg = cfg->tree_cfg;
  166. int alpha_blnd_mode = cfg->per_pixel_alpha ?
  167. BLND_PP_ALPHA : BLND_GLOBAL_ALPHA;
  168. int z_idx;
  169. REG_SET(MPCC_OPP_ID[mpcc_id], 0,
  170. MPCC_OPP_ID, cfg->opp_id);
  171. REG_SET(MPCC_TOP_SEL[mpcc_id], 0,
  172. MPCC_TOP_SEL, cfg->dpp_id);
  173. if (position == 0) {
  174. /* idle dpp/mpcc is added to the top layer of tree */
  175. if (tree_cfg->num_pipes > 0) {
  176. /* get instance of previous top mpcc */
  177. int prev_top_mpcc_id = tree_cfg->mpcc[0];
  178. REG_SET(MPCC_BOT_SEL[mpcc_id], 0,
  179. MPCC_BOT_SEL, prev_top_mpcc_id);
  180. mpcc_mode = MODE_BLEND;
  181. }
  182. /* opp will get new output. from new added mpcc */
  183. REG_SET(MUX[cfg->opp_id], 0, MPC_OUT_MUX, mpcc_id);
  184. } else if (position == tree_cfg->num_pipes) {
  185. /* idle dpp/mpcc is added to the bottom layer of tree */
  186. /* get instance of previous bottom mpcc, set to middle layer */
  187. int prev_bot_mpcc_id = tree_cfg->mpcc[tree_cfg->num_pipes - 1];
  188. REG_SET(MPCC_BOT_SEL[prev_bot_mpcc_id], 0,
  189. MPCC_BOT_SEL, mpcc_id);
  190. REG_UPDATE(MPCC_CONTROL[prev_bot_mpcc_id],
  191. MPCC_MODE, MODE_BLEND);
  192. /* mpcc_id become new bottom mpcc*/
  193. REG_SET(MPCC_BOT_SEL[mpcc_id], 0,
  194. MPCC_BOT_SEL, 0xf);
  195. } else {
  196. /* idle dpp/mpcc is added to middle of tree */
  197. int above_mpcc_id = tree_cfg->mpcc[position - 1];
  198. int below_mpcc_id = tree_cfg->mpcc[position];
  199. /* mpcc above new mpcc_id has new bottom mux*/
  200. REG_SET(MPCC_BOT_SEL[above_mpcc_id], 0,
  201. MPCC_BOT_SEL, mpcc_id);
  202. REG_UPDATE(MPCC_CONTROL[above_mpcc_id],
  203. MPCC_MODE, MODE_BLEND);
  204. /* mpcc_id bottom mux is from below mpcc*/
  205. REG_SET(MPCC_BOT_SEL[mpcc_id], 0,
  206. MPCC_BOT_SEL, below_mpcc_id);
  207. mpcc_mode = MODE_BLEND;
  208. }
  209. REG_SET_4(MPCC_CONTROL[mpcc_id], 0xffffffff,
  210. MPCC_MODE, mpcc_mode,
  211. MPCC_ALPHA_BLND_MODE, alpha_blnd_mode,
  212. MPCC_ALPHA_MULTIPLIED_MODE, cfg->pre_multiplied_alpha,
  213. MPCC_BLND_ACTIVE_OVERLAP_ONLY, false);
  214. /* update mpc_tree_cfg with new mpcc */
  215. for (z_idx = tree_cfg->num_pipes; z_idx > position; z_idx--) {
  216. tree_cfg->dpp[z_idx] = tree_cfg->dpp[z_idx - 1];
  217. tree_cfg->mpcc[z_idx] = tree_cfg->mpcc[z_idx - 1];
  218. }
  219. tree_cfg->dpp[position] = cfg->dpp_id;
  220. tree_cfg->mpcc[position] = mpcc_id;
  221. tree_cfg->num_pipes++;
  222. }
  223. int mpc10_mpcc_add(struct mpc *mpc, struct mpcc_cfg *cfg)
  224. {
  225. struct dcn10_mpc *mpc10 = TO_DCN10_MPC(mpc);
  226. int mpcc_id, z_idx;
  227. ASSERT(cfg->z_index < mpc10->num_mpcc);
  228. /* check in dpp already exists in mpc tree */
  229. for (z_idx = 0; z_idx < cfg->tree_cfg->num_pipes; z_idx++)
  230. if (cfg->tree_cfg->dpp[z_idx] == cfg->dpp_id)
  231. break;
  232. if (z_idx == cfg->tree_cfg->num_pipes) {
  233. ASSERT(cfg->z_index <= cfg->tree_cfg->num_pipes);
  234. mpcc_id = mpc10_get_idle_mpcc_id(mpc10);
  235. /*
  236. * TODO: remove hack
  237. * Note: currently there is a bug in init_hw such that
  238. * on resume from hibernate, BIOS sets up MPCC0, and
  239. * we do mpcc_remove but the mpcc cannot go to idle
  240. * after remove. This cause us to pick mpcc1 here,
  241. * which causes a pstate hang for yet unknown reason.
  242. */
  243. mpcc_id = cfg->dpp_id;
  244. /* end hack*/
  245. ASSERT(!(mpc10->mpcc_in_use_mask & 1 << mpcc_id));
  246. if (mpc->ctx->dc->debug.sanity_checks)
  247. mpc10_assert_mpcc_idle_before_connect(mpc10, mpcc_id);
  248. } else {
  249. ASSERT(cfg->z_index < cfg->tree_cfg->num_pipes);
  250. mpcc_id = cfg->tree_cfg->mpcc[z_idx];
  251. mpc10_mpcc_remove(mpc, cfg->tree_cfg, cfg->opp_id, cfg->dpp_id);
  252. }
  253. /* add dpp/mpcc pair to mpc_tree_cfg and update mpcc registers */
  254. mpc10_add_to_tree_cfg(mpc, cfg, mpcc_id);
  255. /* set background color */
  256. mpc10_set_bg_color(mpc10, &cfg->black_color, mpcc_id);
  257. /* mark this mpcc as in use */
  258. mpc10->mpcc_in_use_mask |= 1 << mpcc_id;
  259. return mpcc_id;
  260. }
  261. void mpc10_update_blend_mode(
  262. struct mpc *mpc,
  263. struct mpcc_cfg *cfg)
  264. {
  265. struct dcn10_mpc *mpc10 = TO_DCN10_MPC(mpc);
  266. int mpcc_id, z_idx;
  267. int alpha_blnd_mode = cfg->per_pixel_alpha ?
  268. BLND_PP_ALPHA : BLND_GLOBAL_ALPHA;
  269. /* find z_idx for the dpp that requires blending mode update*/
  270. for (z_idx = 0; z_idx < cfg->tree_cfg->num_pipes; z_idx++)
  271. if (cfg->tree_cfg->dpp[z_idx] == cfg->dpp_id)
  272. break;
  273. ASSERT(z_idx < cfg->tree_cfg->num_pipes);
  274. mpcc_id = cfg->tree_cfg->mpcc[z_idx];
  275. REG_UPDATE_2(MPCC_CONTROL[mpcc_id],
  276. MPCC_ALPHA_BLND_MODE, alpha_blnd_mode,
  277. MPCC_ALPHA_MULTIPLIED_MODE, cfg->pre_multiplied_alpha);
  278. }
  279. int mpc10_get_opp_id(struct mpc *mpc, int mpcc_id)
  280. {
  281. struct dcn10_mpc *mpc10 = TO_DCN10_MPC(mpc);
  282. int opp_id = 0xF;
  283. REG_GET(MPCC_OPP_ID[mpcc_id], MPCC_OPP_ID, &opp_id);
  284. return opp_id;
  285. }
  286. const struct mpc_funcs dcn10_mpc_funcs = {
  287. .add = mpc10_mpcc_add,
  288. .remove = mpc10_mpcc_remove,
  289. .wait_for_idle = mpc10_assert_idle_mpcc,
  290. .update_blend_mode = mpc10_update_blend_mode,
  291. .get_opp_id = mpc10_get_opp_id,
  292. };
  293. void dcn10_mpc_construct(struct dcn10_mpc *mpc10,
  294. struct dc_context *ctx,
  295. const struct dcn_mpc_registers *mpc_regs,
  296. const struct dcn_mpc_shift *mpc_shift,
  297. const struct dcn_mpc_mask *mpc_mask,
  298. int num_mpcc)
  299. {
  300. mpc10->base.ctx = ctx;
  301. mpc10->base.funcs = &dcn10_mpc_funcs;
  302. mpc10->mpc_regs = mpc_regs;
  303. mpc10->mpc_shift = mpc_shift;
  304. mpc10->mpc_mask = mpc_mask;
  305. mpc10->mpcc_in_use_mask = 0;
  306. mpc10->num_mpcc = num_mpcc;
  307. }