sde_hw_rc.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
  4. * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
  5. */
  6. #define pr_fmt(fmt) "[drm:%s:%d] " fmt, __func__, __LINE__
  7. #include <drm/msm_drm_pp.h>
  8. #include "sde_kms.h"
  9. #include "sde_hw_rc.h"
  10. #include "sde_hw_catalog.h"
  11. #include "sde_hw_util.h"
  12. #include "sde_hw_dspp.h"
  13. #include "sde_hw_color_proc_common_v4.h"
  14. static inline void _sde_hw_rc_reg_write(
  15. struct sde_hw_dspp *hw_dspp,
  16. int offset,
  17. u32 value)
  18. {
  19. u32 address = hw_dspp->cap->sblk->rc.base + offset;
  20. SDE_DEBUG("rc:%u, address:0x%08X, value:0x%08X\n",
  21. RC_IDX(hw_dspp),
  22. hw_dspp->hw.blk_off + address, value);
  23. SDE_REG_WRITE(&hw_dspp->hw, address, value);
  24. }
  25. static int _sde_hw_rc_program_enable_bits(
  26. struct sde_hw_dspp *hw_dspp,
  27. struct drm_msm_rc_mask_cfg *rc_mask_cfg,
  28. enum rc_param_a param_a,
  29. enum rc_param_b param_b,
  30. enum rc_param_r param_r,
  31. int merge_mode,
  32. struct sde_rect *rc_roi)
  33. {
  34. int rc = 0;
  35. u32 val = 0, param_c = 0, rc_merge_mode = 0, ystart = 0;
  36. u64 flags = 0, mask_w = 0, mask_h = 0;
  37. bool r1_valid = false, r2_valid = false;
  38. bool pu_in_r1 = false, pu_in_r2 = false;
  39. bool r1_enable = false, r2_enable = false;
  40. if (!hw_dspp || !rc_mask_cfg || !rc_roi) {
  41. SDE_ERROR("invalid arguments\n");
  42. return -EINVAL;
  43. }
  44. rc = _sde_hw_rc_get_enable_bits(param_a, param_b, &param_c,
  45. merge_mode, &rc_merge_mode);
  46. if (rc) {
  47. SDE_ERROR("invalid enable bits, rc:%d\n", rc);
  48. return rc;
  49. }
  50. flags = rc_mask_cfg->flags;
  51. mask_w = rc_mask_cfg->width;
  52. mask_h = rc_mask_cfg->height;
  53. r1_valid = ((flags & SDE_HW_RC_DISABLE_R1) != SDE_HW_RC_DISABLE_R1);
  54. r2_valid = ((flags & SDE_HW_RC_DISABLE_R2) != SDE_HW_RC_DISABLE_R2);
  55. pu_in_r1 = (param_r == RC_PARAM_R1 || param_r == RC_PARAM_R1R2);
  56. pu_in_r2 = (param_r == RC_PARAM_R2 || param_r == RC_PARAM_R1R2);
  57. r1_enable = (r1_valid && pu_in_r1);
  58. r2_enable = (r2_valid && pu_in_r2);
  59. if (r1_enable)
  60. val |= BIT(0);
  61. if (r2_enable)
  62. val |= BIT(4);
  63. /*corner case for partial update in R2 region*/
  64. if (!r1_enable && r2_enable)
  65. ystart = rc_roi->y;
  66. SDE_DEBUG("idx:%d w:%d h:%d flags:%x, R1:%d, R2:%d, PU R1:%d, PU R2:%d, Y_START:%d\n",
  67. RC_IDX(hw_dspp), mask_w, mask_h, flags, r1_valid, r2_valid, pu_in_r1,
  68. pu_in_r2, ystart);
  69. SDE_EVT32(RC_IDX(hw_dspp), mask_w, mask_h, flags, r1_valid, r2_valid, pu_in_r1, pu_in_r2,
  70. ystart);
  71. val |= param_c;
  72. _sde_hw_rc_reg_write(hw_dspp, SDE_HW_RC_REG1, val);
  73. _sde_hw_rc_reg_write(hw_dspp, SDE_HW_RC_REG13, ystart);
  74. _sde_hw_rc_reg_write(hw_dspp, SDE_HW_RC_REG9, rc_merge_mode);
  75. return rc;
  76. }
  77. static int _sde_hw_rc_program_roi(
  78. struct sde_hw_dspp *hw_dspp,
  79. struct drm_msm_rc_mask_cfg *rc_mask_cfg,
  80. int merge_mode,
  81. struct sde_rect *rc_roi)
  82. {
  83. int rc = 0;
  84. u32 val2 = 0, val3 = 0, val4 = 0;
  85. enum rc_param_r param_r = RC_PARAM_R0;
  86. enum rc_param_a param_a = RC_PARAM_A0;
  87. enum rc_param_b param_b = RC_PARAM_B0;
  88. if (!hw_dspp || !rc_mask_cfg || !rc_roi) {
  89. SDE_ERROR("invalid arguments\n");
  90. return -EINVAL;
  91. }
  92. rc = _sde_hw_rc_get_param_rb(rc_mask_cfg, rc_roi, &param_r,
  93. &param_b);
  94. if (rc) {
  95. SDE_ERROR("invalid rc roi, rc:%d\n", rc);
  96. return rc;
  97. }
  98. param_a = rc_mask_cfg->cfg_param_03;
  99. rc = _sde_hw_rc_program_enable_bits(hw_dspp, rc_mask_cfg,
  100. param_a, param_b, param_r, merge_mode, rc_roi);
  101. if (rc) {
  102. SDE_ERROR("failed to program enable bits, rc:%d\n", rc);
  103. return rc;
  104. }
  105. val2 = ((rc_mask_cfg->cfg_param_01 & 0x0000FFFF) |
  106. ((rc_mask_cfg->cfg_param_02 << 16) & 0xFFFF0000));
  107. if (param_a == RC_PARAM_A1) {
  108. val3 = (rc_mask_cfg->cfg_param_04[0] |
  109. (rc_mask_cfg->cfg_param_04[1] << 16));
  110. val4 = (rc_mask_cfg->cfg_param_04[2] |
  111. (rc_mask_cfg->cfg_param_04[3] << 16));
  112. } else if (param_a == RC_PARAM_A0) {
  113. val3 = (rc_mask_cfg->cfg_param_04[0]);
  114. val4 = (rc_mask_cfg->cfg_param_04[1]);
  115. }
  116. _sde_hw_rc_reg_write(hw_dspp, SDE_HW_RC_REG2, val2);
  117. _sde_hw_rc_reg_write(hw_dspp, SDE_HW_RC_REG3, val3);
  118. _sde_hw_rc_reg_write(hw_dspp, SDE_HW_RC_REG4, val4);
  119. return 0;
  120. }
  121. static int _sde_hw_rc_program_data_offset(
  122. struct sde_hw_dspp *hw_dspp,
  123. struct drm_msm_rc_mask_cfg *rc_mask_cfg)
  124. {
  125. int rc = 0;
  126. u32 val5 = 0, val6 = 0, val7 = 0, val8 = 0;
  127. u32 cfg_param_07;
  128. if (!hw_dspp || !rc_mask_cfg) {
  129. SDE_ERROR("invalid arguments\n");
  130. return -EINVAL;
  131. }
  132. cfg_param_07 = rc_mask_cfg->cfg_param_07;
  133. if (rc_mask_cfg->cfg_param_03 == RC_PARAM_A1) {
  134. val5 = ((rc_mask_cfg->cfg_param_05[0] + cfg_param_07) |
  135. ((rc_mask_cfg->cfg_param_05[1] + cfg_param_07)
  136. << 16));
  137. val6 = ((rc_mask_cfg->cfg_param_05[2] + cfg_param_07)|
  138. ((rc_mask_cfg->cfg_param_05[3] + cfg_param_07)
  139. << 16));
  140. val7 = ((rc_mask_cfg->cfg_param_06[0] + cfg_param_07) |
  141. ((rc_mask_cfg->cfg_param_06[1] + cfg_param_07)
  142. << 16));
  143. val8 = ((rc_mask_cfg->cfg_param_06[2] + cfg_param_07) |
  144. ((rc_mask_cfg->cfg_param_06[3] + cfg_param_07)
  145. << 16));
  146. } else if (rc_mask_cfg->cfg_param_03 == RC_PARAM_A0) {
  147. val5 = (rc_mask_cfg->cfg_param_05[0] + cfg_param_07);
  148. val6 = (rc_mask_cfg->cfg_param_05[1] + cfg_param_07);
  149. val7 = (rc_mask_cfg->cfg_param_06[0] + cfg_param_07);
  150. val8 = (rc_mask_cfg->cfg_param_06[1] + cfg_param_07);
  151. }
  152. _sde_hw_rc_reg_write(hw_dspp, SDE_HW_RC_REG5, val5);
  153. _sde_hw_rc_reg_write(hw_dspp, SDE_HW_RC_REG6, val6);
  154. _sde_hw_rc_reg_write(hw_dspp, SDE_HW_RC_REG7, val7);
  155. _sde_hw_rc_reg_write(hw_dspp, SDE_HW_RC_REG8, val8);
  156. return rc;
  157. }
  158. static int sde_hw_rc_check_mask_cfg(
  159. struct sde_hw_dspp *hw_dspp,
  160. struct sde_hw_cp_cfg *hw_cfg,
  161. struct drm_msm_rc_mask_cfg *rc_mask_cfg)
  162. {
  163. int rc = 0;
  164. u32 i = 0;
  165. u32 panel_width, panel_height, half_panel_width;
  166. u32 mem_total_size, min_region_width;
  167. u64 flags;
  168. u32 cfg_param_01, cfg_param_02, cfg_param_03;
  169. u32 cfg_param_07, cfg_param_08;
  170. u32 *cfg_param_04, *cfg_param_05, *cfg_param_06;
  171. u32 mask_width, mask_height;
  172. bool r1_enable, r2_enable;
  173. if (!hw_dspp || !hw_cfg || !rc_mask_cfg) {
  174. SDE_ERROR("invalid arguments\n");
  175. return -EINVAL;
  176. }
  177. flags = rc_mask_cfg->flags;
  178. cfg_param_01 = rc_mask_cfg->cfg_param_01;
  179. cfg_param_02 = rc_mask_cfg->cfg_param_02;
  180. cfg_param_03 = rc_mask_cfg->cfg_param_03;
  181. cfg_param_04 = rc_mask_cfg->cfg_param_04;
  182. cfg_param_05 = rc_mask_cfg->cfg_param_05;
  183. cfg_param_06 = rc_mask_cfg->cfg_param_06;
  184. cfg_param_07 = rc_mask_cfg->cfg_param_07;
  185. cfg_param_08 = rc_mask_cfg->cfg_param_08;
  186. mask_width = rc_mask_cfg->width;
  187. mask_height = rc_mask_cfg->height;
  188. r1_enable = ((flags & SDE_HW_RC_DISABLE_R1) != SDE_HW_RC_DISABLE_R1);
  189. r2_enable = ((flags & SDE_HW_RC_DISABLE_R2) != SDE_HW_RC_DISABLE_R2);
  190. mem_total_size = hw_dspp->cap->sblk->rc.mem_total_size;
  191. min_region_width = hw_dspp->cap->sblk->rc.min_region_width;
  192. panel_width = hw_cfg->panel_width;
  193. panel_height = hw_cfg->panel_height;
  194. half_panel_width = panel_width / cfg_param_03 * 2;
  195. SDE_EVT32(RC_IDX(hw_dspp), mask_width, mask_height, panel_width, panel_height,
  196. half_panel_width);
  197. SDE_EVT32(RC_IDX(hw_dspp), flags, cfg_param_01, cfg_param_02, cfg_param_03, cfg_param_04,
  198. cfg_param_05, cfg_param_06, cfg_param_07, cfg_param_08);
  199. SDE_EVT32(RC_IDX(hw_dspp), r1_enable, r2_enable, mem_total_size, min_region_width);
  200. if (mask_width != panel_width || mask_height != panel_height) {
  201. SDE_ERROR("RC mask Layer: w %d h %d panel: w %d h %d mismatch\n",
  202. mask_width, mask_height, panel_width, panel_height);
  203. return -EINVAL;
  204. }
  205. if (cfg_param_07 > mem_total_size) {
  206. SDE_ERROR("invalid cfg_param_07:%d\n", cfg_param_07);
  207. return -EINVAL;
  208. }
  209. if (cfg_param_08 > RC_DATA_SIZE_MAX) {
  210. SDE_ERROR("invalid cfg_param_08:%d\n", cfg_param_08);
  211. return -EINVAL;
  212. }
  213. if ((cfg_param_07 + cfg_param_08) > mem_total_size) {
  214. SDE_ERROR("invalid cfg_param_08:%d, cfg_param_07:%d, max:%u\n",
  215. cfg_param_08, cfg_param_07, mem_total_size);
  216. return -EINVAL;
  217. }
  218. if (!(cfg_param_03 == RC_PARAM_A1 || cfg_param_03 == RC_PARAM_A0)) {
  219. SDE_ERROR("invalid cfg_param_03:%d\n", cfg_param_03);
  220. return -EINVAL;
  221. }
  222. for (i = 0; i < cfg_param_03; i++) {
  223. if (cfg_param_04[i] < min_region_width) {
  224. SDE_ERROR("invalid cfg_param_04[%d]:%d\n", i,
  225. cfg_param_04[i]);
  226. return -EINVAL;
  227. }
  228. }
  229. for (i = 0; i < cfg_param_03; i += 2) {
  230. if (cfg_param_04[i] + cfg_param_04[i+1] != half_panel_width) {
  231. SDE_ERROR("invalid ratio [%d]:%d, [%d]:%d, %d\n",
  232. i, cfg_param_04[i], i+1,
  233. cfg_param_04[i+1], half_panel_width);
  234. return -EINVAL;
  235. }
  236. }
  237. if (r1_enable && r2_enable) {
  238. if (cfg_param_01 > cfg_param_02) {
  239. SDE_ERROR("invalid cfg_param_01:%d, cfg_param_02:%d\n",
  240. cfg_param_01, cfg_param_02);
  241. return -EINVAL;
  242. }
  243. } else {
  244. SDE_DEBUG("R1 or R2 disabled, skip overlap check");
  245. }
  246. if (r1_enable) {
  247. if (cfg_param_01 < 1) {
  248. SDE_ERROR("invalid min cfg_param_01:%d\n",
  249. cfg_param_01);
  250. return -EINVAL;
  251. }
  252. for (i = 0; i < cfg_param_03 - 1; i++) {
  253. if (cfg_param_05[i] >= cfg_param_05[i+1]) {
  254. SDE_ERROR("invalid cfg_param_05 %d, %d\n",
  255. cfg_param_05[i],
  256. cfg_param_05[i+1]);
  257. return -EINVAL;
  258. }
  259. }
  260. for (i = 0; i < cfg_param_03; i++) {
  261. if (cfg_param_05[i] > RC_DATA_SIZE_MAX) {
  262. SDE_ERROR("invalid cfg_param_05[%d]:%d\n", i,
  263. cfg_param_05[i]);
  264. return -EINVAL;
  265. }
  266. }
  267. } else {
  268. SDE_DEBUG("R1 is disabled, skip parameter checks\n");
  269. }
  270. if (r2_enable) {
  271. if ((hw_cfg->panel_height - cfg_param_02) < 1) {
  272. SDE_ERROR("invalid max cfg_param_02:%d, panel_height:%d\n",
  273. cfg_param_02, hw_cfg->panel_height);
  274. return -EINVAL;
  275. }
  276. for (i = 0; i < cfg_param_03 - 1; i++) {
  277. if (cfg_param_06[i] >= cfg_param_06[i+1]) {
  278. SDE_ERROR("invalid cfg_param_06 %d, %d\n",
  279. cfg_param_06[i],
  280. cfg_param_06[i+1]);
  281. return -EINVAL;
  282. }
  283. }
  284. for (i = 0; i < cfg_param_03; i++) {
  285. if (cfg_param_06[i] > RC_DATA_SIZE_MAX) {
  286. SDE_ERROR("invalid cfg_param_06[%d]:%d\n", i,
  287. cfg_param_06[i]);
  288. return -EINVAL;
  289. }
  290. }
  291. } else {
  292. SDE_DEBUG("R2 is disabled, skip parameter checks\n");
  293. }
  294. return rc;
  295. }
  296. int sde_hw_rc_check_mask(struct sde_hw_dspp *hw_dspp, void *cfg)
  297. {
  298. int rc = 0;
  299. struct sde_hw_cp_cfg *hw_cfg = cfg;
  300. struct drm_msm_rc_mask_cfg *rc_mask_cfg;
  301. if (!hw_dspp || !hw_cfg) {
  302. SDE_ERROR("invalid arguments\n");
  303. return -EINVAL;
  304. }
  305. if ((hw_cfg->len == 0 && hw_cfg->payload == NULL)) {
  306. SDE_DEBUG("RC feature disabled, skip mask checks\n");
  307. SDE_EVT32(RC_IDX(hw_dspp));
  308. return 0;
  309. }
  310. if (hw_cfg->len != sizeof(struct drm_msm_rc_mask_cfg) ||
  311. !hw_cfg->payload) {
  312. SDE_ERROR("invalid payload len %d exp %zd\n", hw_cfg->len,
  313. sizeof(struct drm_msm_rc_mask_cfg));
  314. return -EINVAL;
  315. }
  316. rc_mask_cfg = hw_cfg->payload;
  317. if (hw_cfg->num_of_mixers != 1 && hw_cfg->num_of_mixers != 2) {
  318. SDE_ERROR("invalid number of mixers:%d\n",
  319. hw_cfg->num_of_mixers);
  320. return -EINVAL;
  321. }
  322. rc = sde_hw_rc_check_mask_cfg(hw_dspp, hw_cfg, rc_mask_cfg);
  323. if (rc) {
  324. SDE_ERROR("invalid rc mask configuration, rc:%d\n", rc);
  325. return rc;
  326. }
  327. return 0;
  328. }
  329. int sde_hw_rc_check_pu_roi(struct sde_hw_dspp *hw_dspp, void *cfg)
  330. {
  331. int rc = 0;
  332. struct sde_hw_cp_cfg *hw_cfg = cfg;
  333. struct msm_roi_list *roi_list;
  334. struct msm_roi_list empty_roi_list;
  335. struct sde_rect rc_roi, merged_roi;
  336. struct drm_msm_rc_mask_cfg *rc_mask_cfg;
  337. enum rc_param_r param_r = RC_PARAM_R0;
  338. enum rc_param_b param_b = RC_PARAM_B0;
  339. if (!hw_dspp || !hw_cfg) {
  340. SDE_ERROR("invalid arguments\n");
  341. return -EINVAL;
  342. }
  343. if (hw_cfg->len != sizeof(struct sde_drm_roi_v1)) {
  344. SDE_ERROR("invalid payload size\n");
  345. return -EINVAL;
  346. }
  347. roi_list = hw_cfg->payload;
  348. if (!roi_list) {
  349. SDE_DEBUG("full frame update\n");
  350. memset(&empty_roi_list, 0, sizeof(struct msm_roi_list));
  351. roi_list = &empty_roi_list;
  352. SDE_EVT32(RC_IDX(hw_dspp));
  353. }
  354. rc_mask_cfg = hw_dspp->rc_state.last_rc_mask_cfg;
  355. /* early return when there is no mask in memory */
  356. if (!rc_mask_cfg || !rc_mask_cfg->cfg_param_03) {
  357. SDE_DEBUG("no previous rc mask programmed\n");
  358. SDE_EVT32(RC_IDX(hw_dspp));
  359. return SDE_HW_RC_PU_SKIP_OP;
  360. }
  361. rc = sde_hw_rc_check_mask_cfg(hw_dspp, hw_cfg, rc_mask_cfg);
  362. if (rc) {
  363. SDE_ERROR("invalid rc mask configuration, rc:%d\n", rc);
  364. return rc;
  365. }
  366. sde_kms_rect_merge_rectangles(roi_list, &merged_roi);
  367. rc = _sde_hw_rc_get_ajusted_roi(hw_cfg, &merged_roi, &rc_roi);
  368. if (rc) {
  369. SDE_ERROR("failed to get adjusted roi, rc:%d\n", rc);
  370. return rc;
  371. }
  372. rc = _sde_hw_rc_get_param_rb(rc_mask_cfg, &rc_roi,
  373. &param_r, &param_b);
  374. if (rc) {
  375. SDE_ERROR("invalid rc roi, rc:%d\n", rc);
  376. return rc;
  377. }
  378. return 0;
  379. }
  380. int sde_hw_rc_setup_pu_roi(struct sde_hw_dspp *hw_dspp, void *cfg)
  381. {
  382. int rc = 0;
  383. struct sde_hw_cp_cfg *hw_cfg = cfg;
  384. struct msm_roi_list *roi_list;
  385. struct msm_roi_list empty_roi_list;
  386. struct sde_rect rc_roi, merged_roi;
  387. struct drm_msm_rc_mask_cfg *rc_mask_cfg;
  388. enum rc_param_r param_r = RC_PARAM_R0;
  389. enum rc_param_a param_a = RC_PARAM_A0;
  390. enum rc_param_b param_b = RC_PARAM_B0;
  391. u32 merge_mode = 0;
  392. if (!hw_dspp || !hw_cfg) {
  393. SDE_ERROR("invalid arguments\n");
  394. return -EINVAL;
  395. }
  396. if (hw_cfg->len != sizeof(struct sde_drm_roi_v1)) {
  397. SDE_ERROR("invalid payload size\n");
  398. return -EINVAL;
  399. }
  400. roi_list = hw_cfg->payload;
  401. if (!roi_list) {
  402. SDE_DEBUG("full frame update\n");
  403. memset(&empty_roi_list, 0, sizeof(struct msm_roi_list));
  404. roi_list = &empty_roi_list;
  405. }
  406. rc_mask_cfg = hw_dspp->rc_state.last_rc_mask_cfg;
  407. SDE_EVT32(RC_IDX(hw_dspp), roi_list, rc_mask_cfg, rc_mask_cfg->cfg_param_03);
  408. /* early return when there is no mask in memory */
  409. if (!rc_mask_cfg || !rc_mask_cfg->cfg_param_03) {
  410. SDE_DEBUG("no previous rc mask programmed\n");
  411. SDE_EVT32(RC_IDX(hw_dspp));
  412. return SDE_HW_RC_PU_SKIP_OP;
  413. }
  414. sde_kms_rect_merge_rectangles(roi_list, &merged_roi);
  415. rc = _sde_hw_rc_get_ajusted_roi(hw_cfg, &merged_roi, &rc_roi);
  416. if (rc) {
  417. SDE_ERROR("failed to get adjusted roi, rc:%d\n", rc);
  418. return rc;
  419. }
  420. rc = _sde_hw_rc_get_merge_mode(hw_cfg, &merge_mode);
  421. if (rc) {
  422. SDE_ERROR("invalid merge_mode, rc:%d\n", rc);
  423. return rc;
  424. }
  425. rc = _sde_hw_rc_get_param_rb(rc_mask_cfg, &rc_roi, &param_r,
  426. &param_b);
  427. if (rc) {
  428. SDE_ERROR("invalid roi, rc:%d\n", rc);
  429. return rc;
  430. }
  431. param_a = rc_mask_cfg->cfg_param_03;
  432. rc = _sde_hw_rc_program_enable_bits(hw_dspp, rc_mask_cfg,
  433. param_a, param_b, param_r, merge_mode, &rc_roi);
  434. if (rc) {
  435. SDE_ERROR("failed to program enable bits, rc:%d\n", rc);
  436. return rc;
  437. }
  438. memcpy(hw_dspp->rc_state.last_roi_list,
  439. roi_list, sizeof(struct msm_roi_list));
  440. return 0;
  441. }
  442. int sde_hw_rc_setup_mask(struct sde_hw_dspp *hw_dspp, void *cfg)
  443. {
  444. int rc = 0;
  445. struct sde_hw_cp_cfg *hw_cfg = cfg;
  446. struct drm_msm_rc_mask_cfg *rc_mask_cfg;
  447. struct sde_rect rc_roi, merged_roi;
  448. struct msm_roi_list *last_roi_list;
  449. u32 merge_mode = 0;
  450. u64 mask_w = 0, mask_h = 0, panel_w = 0, panel_h = 0;
  451. u32 data = 0, cfg_param_07 = 0;
  452. int i = 0;
  453. if (!hw_dspp || !hw_cfg) {
  454. SDE_ERROR("invalid arguments\n");
  455. return -EINVAL;
  456. }
  457. if ((hw_cfg->len == 0 && hw_cfg->payload == NULL)) {
  458. SDE_DEBUG("RC feature disabled\n");
  459. _sde_hw_rc_reg_write(hw_dspp, SDE_HW_RC_REG1, 0);
  460. memset(hw_dspp->rc_state.last_rc_mask_cfg, 0,
  461. sizeof(struct drm_msm_rc_mask_cfg));
  462. memset(hw_dspp->rc_state.last_roi_list, 0,
  463. sizeof(struct msm_roi_list));
  464. SDE_EVT32(RC_IDX(hw_dspp), hw_dspp->rc_state.last_rc_mask_cfg,
  465. hw_dspp->rc_state.last_rc_mask_cfg->cfg_param_03,
  466. hw_dspp->rc_state.last_roi_list->num_rects);
  467. return 0;
  468. }
  469. if (hw_cfg->len != sizeof(struct drm_msm_rc_mask_cfg) ||
  470. !hw_cfg->payload) {
  471. SDE_ERROR("invalid payload\n");
  472. return -EINVAL;
  473. }
  474. rc_mask_cfg = hw_cfg->payload;
  475. last_roi_list = hw_dspp->rc_state.last_roi_list;
  476. mask_w = rc_mask_cfg->width;
  477. mask_h = rc_mask_cfg->height;
  478. panel_w = hw_cfg->panel_width;
  479. panel_h = hw_cfg->panel_height;
  480. if ((panel_w != mask_w || panel_h != mask_h)) {
  481. SDE_ERROR("RC-%d mask: w %d h %d panel: w %d h %d mismatch\n",
  482. RC_IDX(hw_dspp), mask_w, mask_h, panel_w, panel_h);
  483. SDE_EVT32(1);
  484. _sde_hw_rc_reg_write(hw_dspp, SDE_HW_RC_REG1, 0);
  485. return -EINVAL;
  486. }
  487. if (!last_roi_list || !last_roi_list->num_rects) {
  488. SDE_DEBUG("full frame update\n");
  489. memset(&merged_roi, 0, sizeof(struct sde_rect));
  490. } else {
  491. SDE_DEBUG("partial frame update\n");
  492. sde_kms_rect_merge_rectangles(last_roi_list, &merged_roi);
  493. }
  494. SDE_EVT32(RC_IDX(hw_dspp), last_roi_list->num_rects);
  495. rc = _sde_hw_rc_get_ajusted_roi(hw_cfg, &merged_roi, &rc_roi);
  496. if (rc) {
  497. SDE_ERROR("failed to get adjusted roi, rc:%d\n", rc);
  498. return rc;
  499. }
  500. rc = _sde_hw_rc_get_merge_mode(hw_cfg, &merge_mode);
  501. if (rc) {
  502. SDE_ERROR("invalid merge_mode, rc:%d\n", rc);
  503. return rc;
  504. }
  505. rc = _sde_hw_rc_program_roi(hw_dspp, rc_mask_cfg,
  506. merge_mode, &rc_roi);
  507. if (rc) {
  508. SDE_ERROR("unable to program rc roi, rc:%d\n", rc);
  509. return rc;
  510. }
  511. rc = _sde_hw_rc_program_data_offset(hw_dspp, rc_mask_cfg);
  512. if (rc) {
  513. SDE_ERROR("unable to program data offsets, rc:%d\n", rc);
  514. return rc;
  515. }
  516. /* rc data should be programmed once if dspp are in multi-pipe mode */
  517. if (!(rc_mask_cfg->flags & SDE_HW_RC_SKIP_DATA_PROG) &&
  518. (hw_dspp->cap->sblk->rc.idx % hw_cfg->num_of_mixers == 0)) {
  519. cfg_param_07 = rc_mask_cfg->cfg_param_07;
  520. SDE_DEBUG("cfg_param_07:%u\n", cfg_param_07);
  521. for (i = 0; i < rc_mask_cfg->cfg_param_08; i++) {
  522. SDE_DEBUG("cfg_param_09[%d] = 0x%016llX at %u\n", i,
  523. rc_mask_cfg->cfg_param_09[i], i + cfg_param_07);
  524. data = (i == 0) ? (BIT(30) | (cfg_param_07 << 18)) : 0;
  525. data |= (rc_mask_cfg->cfg_param_09[i] & 0x3FFFF);
  526. _sde_hw_rc_reg_write(hw_dspp, SDE_HW_RC_REG10, data);
  527. data = ((rc_mask_cfg->cfg_param_09[i] >>
  528. SDE_HW_RC_DATA_REG_SIZE) & 0x3FFFF);
  529. _sde_hw_rc_reg_write(hw_dspp, SDE_HW_RC_REG10, data);
  530. }
  531. } else {
  532. SDE_DEBUG("skip data programming\n");
  533. SDE_EVT32(RC_IDX(hw_dspp));
  534. }
  535. memcpy(hw_dspp->rc_state.last_rc_mask_cfg, rc_mask_cfg,
  536. sizeof(struct drm_msm_rc_mask_cfg));
  537. return 0;
  538. }
  539. int sde_hw_rc_init(struct sde_hw_dspp *hw_dspp)
  540. {
  541. int rc = 0;
  542. hw_dspp->rc_state.last_roi_list = kzalloc(
  543. sizeof(struct msm_roi_list), GFP_KERNEL);
  544. if (!hw_dspp->rc_state.last_roi_list)
  545. return -ENOMEM;
  546. hw_dspp->rc_state.last_rc_mask_cfg = kzalloc(
  547. sizeof(struct drm_msm_rc_mask_cfg), GFP_KERNEL);
  548. if (!hw_dspp->rc_state.last_rc_mask_cfg)
  549. return -ENOMEM;
  550. return rc;
  551. }