mtk_disp_rsz.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643
  1. /*
  2. * Copyright (c) 2015 MediaTek Inc.
  3. *
  4. * This program is free software; you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License version 2 as
  6. * published by the Free Software Foundation.
  7. *
  8. * This program is distributed in the hope that it will be useful,
  9. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. * GNU General Public License for more details.
  12. */
  13. #include <drm/drmP.h>
  14. #include <linux/clk.h>
  15. #include <linux/component.h>
  16. #include <linux/of_device.h>
  17. #include <linux/of_irq.h>
  18. #include <linux/platform_device.h>
  19. #include <linux/pm_runtime.h>
  20. #include <linux/soc/mediatek/mtk-cmdq.h>
  21. #include "mtk_drm_crtc.h"
  22. #include "mtk_drm_ddp_comp.h"
  23. #include "mtk_dump.h"
  24. #include "mtk_rect.h"
  25. #include "mtk_drm_drv.h"
  26. #define DISP_REG_RSZ_ENABLE (0x000)
  27. #define FLD_RSZ_RST REG_FLD_MSB_LSB(16, 16)
  28. #define FLD_RSZ_EN REG_FLD_MSB_LSB(0, 0)
  29. #define DISP_REG_RSZ_CONTROL_1 (0x004)
  30. #define FLD_RSZ_INT_WCLR_EN REG_FLD_MSB_LSB(31, 31)
  31. #define FLD_RSZ_INTEN REG_FLD_MSB_LSB(30, 28)
  32. #define FLD_RSZ_DCM_DIS REG_FLD_MSB_LSB(27, 27)
  33. #define FLD_RSZ_VERTICAL_TABLE_SELECT REG_FLD_MSB_LSB(25, 21)
  34. #define FLD_RSZ_HORIZONTAL_TABLE_SELECT REG_FLD_MSB_LSB(20, 16)
  35. #define FLD_RSZ_VERTICAL_EN REG_FLD_MSB_LSB(1, 1)
  36. #define FLD_RSZ_HORIZONTAL_EN REG_FLD_MSB_LSB(0, 0)
  37. #define DISP_REG_RSZ_CONTROL_2 (0x008)
  38. #define FLD_RSZ_RGB_BIT_MODE REG_FLD_MSB_LSB(28, 28)
  39. #define FLD_RSZ_POWER_SAVING REG_FLD_MSB_LSB(9, 9)
  40. #define DISP_REG_RSZ_INT_FLAG (0x00c)
  41. #define FLD_RSZ_SOF_RESET REG_FLD_MSB_LSB(5, 5)
  42. #define FLD_RSZ_SIZE_ERR REG_FLD_MSB_LSB(4, 4)
  43. #define FLD_RSZ_FRAME_END REG_FLD_MSB_LSB(1, 1)
  44. #define FLD_RSZ_FRAME_START REG_FLD_MSB_LSB(0, 0)
  45. #define DISP_REG_RSZ_INPUT_IMAGE (0x010)
  46. #define FLD_RSZ_INPUT_IMAGE_H REG_FLD_MSB_LSB(31, 16)
  47. #define FLD_RSZ_INPUT_IMAGE_W REG_FLD_MSB_LSB(15, 0)
  48. #define DISP_REG_RSZ_OUTPUT_IMAGE (0x014)
  49. #define FLD_RSZ_OUTPUT_IMAGE_H REG_FLD_MSB_LSB(31, 16)
  50. #define FLD_RSZ_OUTPUT_IMAGE_W REG_FLD_MSB_LSB(15, 0)
  51. #define DISP_REG_RSZ_HORIZONTAL_COEFF_STEP (0x018)
  52. #define DISP_REG_RSZ_VERTICAL_COEFF_STEP (0x01c)
  53. #define DISP_REG_RSZ_LUMA_HORIZONTAL_INTEGER_OFFSET (0x020)
  54. #define DISP_REG_RSZ_LUMA_HORIZONTAL_SUBPIXEL_OFFSET (0x024)
  55. #define DISP_REG_RSZ_LUMA_VERTICAL_INTEGER_OFFSET (0x028)
  56. #define DISP_REG_RSZ_LUMA_VERTICAL_SUBPIXEL_OFFSET (0x02c)
  57. #define DISP_REG_RSZ_DEBUG_SEL (0x044)
  58. #define DISP_REG_RSZ_DEBUG (0x048)
  59. #define DISP_REG_RSZ_SHADOW_CTRL (0x0f0)
  60. #define FLD_RSZ_READ_WRK_REG REG_FLD_MSB_LSB(2, 2)
  61. #define FLD_RSZ_FORCE_COMMIT REG_FLD_MSB_LSB(1, 1)
  62. #define FLD_RSZ_BYPASS_SHADOW REG_FLD_MSB_LSB(0, 0)
  63. #define RSZ_READ_WRK_REG BIT(2)
  64. #define RSZ_FORCE_COMMIT BIT(1)
  65. #define RSZ_BYPASS_SHADOW BIT(0)
  66. #define UNIT 32768
  67. #define TILE_LOSS 4
  68. #define TILE_LOSS_LEFT 4
  69. #define TILE_LOSS_RIGHT 4
  70. struct mtk_disp_rsz_data {
  71. unsigned int tile_length;
  72. unsigned int in_max_height;
  73. bool support_shadow;
  74. };
  75. enum mtk_rsz_color_format {
  76. ARGB8101010,
  77. RGB999,
  78. RGB888,
  79. UNKNOWN_RSZ_CFMT,
  80. };
  81. struct rsz_tile_params {
  82. u32 step;
  83. u32 int_offset;
  84. u32 sub_offset;
  85. u32 in_len;
  86. u32 out_len;
  87. };
  88. struct mtk_rsz_config_struct {
  89. struct rsz_tile_params tw[2];
  90. struct rsz_tile_params th[1];
  91. enum mtk_rsz_color_format fmt;
  92. u32 frm_in_w;
  93. u32 frm_in_h;
  94. u32 frm_out_w;
  95. u32 frm_out_h;
  96. };
  97. /**
  98. * struct mtk_disp_rsz - DISP_RSZ driver structure
  99. * @ddp_comp - structure containing type enum and hardware resources
  100. * @crtc - associated crtc to report irq events to
  101. */
  102. struct mtk_disp_rsz {
  103. struct mtk_ddp_comp ddp_comp;
  104. struct drm_crtc *crtc;
  105. const struct mtk_disp_rsz_data *data;
  106. };
  107. static inline struct mtk_disp_rsz *comp_to_rsz(struct mtk_ddp_comp *comp)
  108. {
  109. return container_of(comp, struct mtk_disp_rsz, ddp_comp);
  110. }
  111. static void mtk_rsz_start(struct mtk_ddp_comp *comp, struct cmdq_pkt *handle)
  112. {
  113. int ret;
  114. ret = pm_runtime_get_sync(comp->dev);
  115. if (ret < 0)
  116. DRM_ERROR("Failed to enable power domain: %d\n", ret);
  117. cmdq_pkt_write(handle, comp->cmdq_base,
  118. comp->regs_pa + DISP_REG_RSZ_ENABLE, 0x1, ~0);
  119. cmdq_pkt_write(handle, comp->cmdq_base,
  120. comp->regs_pa + DISP_REG_RSZ_DEBUG_SEL, 0x3, ~0);
  121. }
  122. static void mtk_rsz_stop(struct mtk_ddp_comp *comp, struct cmdq_pkt *handle)
  123. {
  124. int ret;
  125. ret = pm_runtime_put(comp->dev);
  126. if (ret < 0)
  127. DRM_ERROR("Failed to disable power domain: %d\n", ret);
  128. cmdq_pkt_write(handle, comp->cmdq_base,
  129. comp->regs_pa + DISP_REG_RSZ_ENABLE, 0x0, ~0);
  130. }
  131. int mtk_rsz_calc_tile_params(u32 frm_in_len, u32 frm_out_len, bool tile_mode,
  132. struct rsz_tile_params t[])
  133. {
  134. u32 tile_loss = 0;
  135. u32 step = 0;
  136. s32 init_phase = 0;
  137. s32 offset[2] = {0};
  138. s32 int_offset[2] = {0};
  139. s32 sub_offset[2] = {0};
  140. u32 tile_in_len[2] = {0};
  141. u32 tile_out_len = 0;
  142. if (tile_mode)
  143. tile_loss = TILE_LOSS;
  144. if (frm_out_len > 1)
  145. step = (UNIT * (frm_in_len - 1) + (frm_out_len - 2)) /
  146. (frm_out_len - 1);
  147. else {
  148. DRM_ERROR("%s:%d Division by zero\n", __func__, __LINE__);
  149. return -1;
  150. }
  151. /* left half */
  152. offset[0] = (step * (frm_out_len - 1) - UNIT * (frm_in_len - 1)) / 2;
  153. init_phase = UNIT - offset[0];
  154. sub_offset[0] = -offset[0];
  155. if (sub_offset[0] < 0) {
  156. int_offset[0]--;
  157. sub_offset[0] = UNIT + sub_offset[0];
  158. }
  159. if (sub_offset[0] >= UNIT) {
  160. int_offset[0]++;
  161. sub_offset[0] = sub_offset[0] - UNIT;
  162. }
  163. if (tile_mode) {
  164. tile_in_len[0] = frm_in_len / 2 + tile_loss;
  165. tile_out_len = frm_out_len / 2;
  166. } else {
  167. tile_in_len[0] = frm_in_len;
  168. tile_out_len = frm_out_len;
  169. }
  170. t[0].step = step;
  171. t[0].int_offset = (u32)(int_offset[0] & 0xffff);
  172. t[0].sub_offset = (u32)(sub_offset[0] & 0x1fffff);
  173. t[0].in_len = tile_in_len[0];
  174. t[0].out_len = tile_out_len;
  175. DDPDBG("%s:%s:step:%u,offset:%u.%u,len:%u->%u\n", __func__,
  176. tile_mode ? "dual" : "single", t[0].step, t[0].int_offset,
  177. t[0].sub_offset, t[0].in_len, t[0].out_len);
  178. if (!tile_mode)
  179. return 0;
  180. /* right half */
  181. offset[1] =
  182. (init_phase + frm_out_len / 2 * step) -
  183. (frm_in_len / 2 - tile_loss - (offset[0] ? 1 : 0) + 1) * UNIT +
  184. UNIT;
  185. int_offset[1] = offset[1] / UNIT;
  186. sub_offset[1] = offset[1] - UNIT * int_offset[1];
  187. tile_in_len[1] = frm_in_len / 2 + tile_loss + (offset[0] ? 1 : 0);
  188. if (int_offset[1] & 0x1) {
  189. int_offset[1]++;
  190. tile_in_len[1]++;
  191. DDPMSG("right tile int_offset: make odd to even\n");
  192. }
  193. t[1].step = step;
  194. t[1].int_offset = (u32)(int_offset[1] & 0xffff);
  195. t[1].sub_offset = (u32)(sub_offset[1] & 0x1fffff);
  196. t[1].in_len = tile_in_len[1];
  197. t[1].out_len = tile_out_len;
  198. DDPDBG("%s:%s:step:%u,offset:%u.%u,len:%u->%u\n", __func__,
  199. tile_mode ? "dual" : "single", t[1].step, t[1].int_offset,
  200. t[1].sub_offset, t[1].in_len, t[1].out_len);
  201. return 0;
  202. }
  203. static int mtk_rsz_set_color_format(enum mtk_rsz_color_format fmt)
  204. {
  205. u32 reg_val = 0;
  206. switch (fmt) {
  207. case ARGB8101010:
  208. reg_val = REG_FLD_VAL(FLD_RSZ_POWER_SAVING, 0x0);
  209. reg_val |= REG_FLD_VAL(FLD_RSZ_RGB_BIT_MODE, 0x0);
  210. break;
  211. case RGB999:
  212. reg_val = REG_FLD_VAL(FLD_RSZ_POWER_SAVING, 0x1);
  213. reg_val |= REG_FLD_VAL(FLD_RSZ_RGB_BIT_MODE, 0x0);
  214. break;
  215. case RGB888:
  216. reg_val = REG_FLD_VAL(FLD_RSZ_POWER_SAVING, 0x1);
  217. reg_val |= REG_FLD_VAL(FLD_RSZ_RGB_BIT_MODE, 0x1);
  218. break;
  219. default:
  220. DDPMSG("unknown resize color format\n");
  221. break;
  222. }
  223. return reg_val;
  224. }
  225. static int mtk_rsz_check_params(struct mtk_rsz_config_struct *rsz_config,
  226. unsigned int tile_length)
  227. {
  228. if ((rsz_config->frm_in_w != rsz_config->frm_out_w ||
  229. rsz_config->frm_in_h != rsz_config->frm_out_h) &&
  230. rsz_config->frm_in_w > tile_length) {
  231. DDPPR_ERR("%s:need rsz but input width(%u) > limit(%u)\n",
  232. __func__, rsz_config->frm_in_w, tile_length);
  233. return -EINVAL;
  234. }
  235. return 0;
  236. }
  237. static void mtk_rsz_addon_config(struct mtk_ddp_comp *comp,
  238. enum mtk_ddp_comp_id prev,
  239. enum mtk_ddp_comp_id next,
  240. union mtk_addon_config *addon_config,
  241. struct cmdq_pkt *handle)
  242. {
  243. struct mtk_addon_rsz_config config = addon_config->addon_rsz_config;
  244. struct mtk_rsz_config_struct *rsz_config = NULL;
  245. struct mtk_disp_rsz *rsz = comp_to_rsz(comp);
  246. enum mtk_rsz_color_format fmt = RGB888;
  247. bool tile_mode = false;
  248. u32 reg_val = 0;
  249. u32 tile_idx = 0;
  250. u32 in_w = 0, in_h = 0, out_w = 0, out_h = 0;
  251. rsz_config = kzalloc(sizeof(struct mtk_rsz_config_struct), GFP_KERNEL);
  252. if (!rsz_config) {
  253. DDPPR_ERR("fail to create rsz_config!\n");
  254. return;
  255. }
  256. rsz_config->frm_in_w = config.rsz_src_roi.width;
  257. rsz_config->frm_in_h = config.rsz_src_roi.height;
  258. rsz_config->frm_out_w = config.rsz_dst_roi.width;
  259. rsz_config->frm_out_h = config.rsz_dst_roi.height;
  260. if (mtk_rsz_check_params(rsz_config, rsz->data->tile_length)) {
  261. kfree(rsz_config);
  262. return;
  263. }
  264. mtk_rsz_calc_tile_params(rsz_config->frm_in_w, rsz_config->frm_out_w,
  265. tile_mode, rsz_config->tw);
  266. mtk_rsz_calc_tile_params(rsz_config->frm_in_h, rsz_config->frm_out_h,
  267. tile_mode, rsz_config->th);
  268. in_w = rsz_config->tw[tile_idx].in_len;
  269. in_h = rsz_config->th[0].in_len;
  270. out_w = rsz_config->tw[tile_idx].out_len;
  271. out_h = rsz_config->th[0].out_len;
  272. if (in_w > out_w || in_h > out_h) {
  273. DDPPR_ERR("DISP_RSZ only supports scale-up,(%ux%u)->(%ux%u)\n",
  274. in_w, in_h, out_w, out_h);
  275. kfree(rsz_config);
  276. return;
  277. }
  278. reg_val = 0;
  279. reg_val |= REG_FLD_VAL(FLD_RSZ_HORIZONTAL_EN, (in_w != out_w));
  280. reg_val |= REG_FLD_VAL(FLD_RSZ_VERTICAL_EN, (in_h != out_h));
  281. cmdq_pkt_write(handle, comp->cmdq_base,
  282. comp->regs_pa + DISP_REG_RSZ_CONTROL_1, reg_val, ~0);
  283. DDPDBG("%s:CONTROL_1:0x%x\n", __func__, reg_val);
  284. reg_val = mtk_rsz_set_color_format(fmt);
  285. cmdq_pkt_write(handle, comp->cmdq_base,
  286. comp->regs_pa + DISP_REG_RSZ_CONTROL_2, reg_val, ~0);
  287. DDPDBG("%s:CONTROL_2:0x%x\n", __func__, reg_val);
  288. cmdq_pkt_write(handle, comp->cmdq_base,
  289. comp->regs_pa + DISP_REG_RSZ_INPUT_IMAGE,
  290. in_h << 16 | in_w, ~0);
  291. cmdq_pkt_write(handle, comp->cmdq_base,
  292. comp->regs_pa + DISP_REG_RSZ_OUTPUT_IMAGE,
  293. out_h << 16 | out_w, ~0);
  294. DDPDBG("%s:%s:(%ux%u)->(%ux%u)\n", __func__, mtk_dump_comp_str(comp),
  295. in_w, in_h, out_w, out_h);
  296. cmdq_pkt_write(handle, comp->cmdq_base,
  297. comp->regs_pa + DISP_REG_RSZ_HORIZONTAL_COEFF_STEP,
  298. rsz_config->tw[tile_idx].step, ~0);
  299. cmdq_pkt_write(handle, comp->cmdq_base,
  300. comp->regs_pa + DISP_REG_RSZ_VERTICAL_COEFF_STEP,
  301. rsz_config->th[0].step, ~0);
  302. cmdq_pkt_write(handle, comp->cmdq_base,
  303. comp->regs_pa +
  304. DISP_REG_RSZ_LUMA_HORIZONTAL_INTEGER_OFFSET,
  305. rsz_config->tw[tile_idx].int_offset, ~0);
  306. cmdq_pkt_write(handle, comp->cmdq_base,
  307. comp->regs_pa +
  308. DISP_REG_RSZ_LUMA_HORIZONTAL_SUBPIXEL_OFFSET,
  309. rsz_config->tw[tile_idx].sub_offset, ~0);
  310. cmdq_pkt_write(handle, comp->cmdq_base,
  311. comp->regs_pa +
  312. DISP_REG_RSZ_LUMA_VERTICAL_INTEGER_OFFSET,
  313. rsz_config->th[0].int_offset, ~0);
  314. cmdq_pkt_write(handle, comp->cmdq_base,
  315. comp->regs_pa +
  316. DISP_REG_RSZ_LUMA_VERTICAL_SUBPIXEL_OFFSET,
  317. rsz_config->th[0].sub_offset, ~0);
  318. kfree(rsz_config);
  319. }
  320. int mtk_rsz_dump(struct mtk_ddp_comp *comp)
  321. {
  322. void __iomem *baddr = comp->regs;
  323. int i = 0;
  324. DDPDUMP("== DISP %s REGS ==\n", mtk_dump_comp_str(comp));
  325. for (i = 0; i < 3; i++) {
  326. DDPDUMP("0x%03X: 0x%08x 0x%08x 0x%08x 0x%08x\n", i * 0x10,
  327. readl(baddr + i * 0x10), readl(baddr + i * 0x10 + 0x4),
  328. readl(baddr + i * 0x10 + 0x8),
  329. readl(baddr + i * 0x10 + 0xC));
  330. }
  331. DDPDUMP("0x044: 0x%08x 0x%08x; 0x0F0: 0x%08x\n", readl(baddr + 0x44),
  332. readl(baddr + 0x48), readl(baddr + 0xF0));
  333. return 0;
  334. }
  335. int mtk_rsz_analysis(struct mtk_ddp_comp *comp)
  336. {
  337. void __iomem *baddr = comp->regs;
  338. u32 enable = 0;
  339. u32 con1 = 0;
  340. u32 con2 = 0;
  341. u32 int_flag = 0;
  342. u32 in_size = 0;
  343. u32 out_size = 0;
  344. u32 in_pos = 0;
  345. u32 shadow = 0;
  346. const int len = 100;
  347. char msg[len];
  348. int n = 0;
  349. enable = readl(baddr + DISP_REG_RSZ_ENABLE);
  350. con1 = readl(baddr + DISP_REG_RSZ_CONTROL_1);
  351. con2 = readl(baddr + DISP_REG_RSZ_CONTROL_2);
  352. int_flag = readl(baddr + DISP_REG_RSZ_INT_FLAG);
  353. in_size = readl(baddr + DISP_REG_RSZ_INPUT_IMAGE);
  354. out_size = readl(baddr + DISP_REG_RSZ_OUTPUT_IMAGE);
  355. in_pos = readl(baddr + DISP_REG_RSZ_DEBUG);
  356. shadow = readl(baddr + DISP_REG_RSZ_SHADOW_CTRL);
  357. DDPDUMP("== DISP %s ANALYSIS ==\n", mtk_dump_comp_str(comp));
  358. writel(0x3, baddr + DISP_REG_RSZ_DEBUG_SEL);
  359. n = snprintf(msg, len,
  360. "en:%d,rst:%d,h_en:%d,v_en:%d,h_table:%d,v_table:%d,",
  361. REG_FLD_VAL_GET(FLD_RSZ_EN, enable),
  362. REG_FLD_VAL_GET(FLD_RSZ_RST, enable),
  363. REG_FLD_VAL_GET(FLD_RSZ_HORIZONTAL_EN, con1),
  364. REG_FLD_VAL_GET(FLD_RSZ_VERTICAL_EN, con1),
  365. REG_FLD_VAL_GET(FLD_RSZ_HORIZONTAL_TABLE_SELECT, con1),
  366. REG_FLD_VAL_GET(FLD_RSZ_VERTICAL_TABLE_SELECT, con1));
  367. n += snprintf(msg + n, len - n, "dcm_dis:%d,int_en:%d,wclr_en:%d\n",
  368. REG_FLD_VAL_GET(FLD_RSZ_DCM_DIS, con1),
  369. REG_FLD_VAL_GET(FLD_RSZ_INTEN, con1),
  370. REG_FLD_VAL_GET(FLD_RSZ_INT_WCLR_EN, con1));
  371. DDPDUMP("%s", msg);
  372. n = snprintf(msg, len,
  373. "power_saving:%d,rgb_bit_mode:%d,frm_start:%d,frm_end:%d,",
  374. REG_FLD_VAL_GET(FLD_RSZ_POWER_SAVING, con2),
  375. REG_FLD_VAL_GET(FLD_RSZ_RGB_BIT_MODE, con2),
  376. REG_FLD_VAL_GET(FLD_RSZ_FRAME_START, int_flag),
  377. REG_FLD_VAL_GET(FLD_RSZ_FRAME_END, int_flag));
  378. n += snprintf(msg + n, len - n, "size_err:%d,sof_rst:%d\n",
  379. REG_FLD_VAL_GET(FLD_RSZ_SIZE_ERR, int_flag),
  380. REG_FLD_VAL_GET(FLD_RSZ_SOF_RESET, int_flag));
  381. DDPDUMP("%s", msg);
  382. n = snprintf(msg, len, "in(%ux%u),out(%ux%u),h_step:%d,v_step:%d\n",
  383. REG_FLD_VAL_GET(FLD_RSZ_INPUT_IMAGE_W, in_size),
  384. REG_FLD_VAL_GET(FLD_RSZ_INPUT_IMAGE_H, in_size),
  385. REG_FLD_VAL_GET(FLD_RSZ_OUTPUT_IMAGE_W, out_size),
  386. REG_FLD_VAL_GET(FLD_RSZ_OUTPUT_IMAGE_H, out_size),
  387. readl(baddr + DISP_REG_RSZ_HORIZONTAL_COEFF_STEP),
  388. readl(baddr + DISP_REG_RSZ_VERTICAL_COEFF_STEP));
  389. DDPDUMP("%s", msg);
  390. n = snprintf(
  391. msg, len, "luma_h:%d.%d,luma_v:%d.%d\n",
  392. readl(baddr + DISP_REG_RSZ_LUMA_HORIZONTAL_INTEGER_OFFSET),
  393. readl(baddr + DISP_REG_RSZ_LUMA_HORIZONTAL_SUBPIXEL_OFFSET),
  394. readl(baddr + DISP_REG_RSZ_LUMA_VERTICAL_INTEGER_OFFSET),
  395. readl(baddr + DISP_REG_RSZ_LUMA_VERTICAL_SUBPIXEL_OFFSET));
  396. DDPDUMP("%s", msg);
  397. n = snprintf(msg, len,
  398. "dbg_sel:%d, in(%u,%u);shadow_ctrl:bypass:%d,force:%d,",
  399. readl(baddr + DISP_REG_RSZ_DEBUG_SEL), in_pos & 0xFFFF,
  400. (in_pos >> 16) & 0xFFFF,
  401. REG_FLD_VAL_GET(FLD_RSZ_BYPASS_SHADOW, shadow),
  402. REG_FLD_VAL_GET(FLD_RSZ_FORCE_COMMIT, shadow));
  403. n += snprintf(msg + n, len - n, "read_working:%d\n",
  404. REG_FLD_VAL_GET(FLD_RSZ_READ_WRK_REG, shadow));
  405. DDPDUMP("%s", msg);
  406. return 0;
  407. }
  408. static void mtk_rsz_prepare(struct mtk_ddp_comp *comp)
  409. {
  410. #if defined(CONFIG_DRM_MTK_SHADOW_REGISTER_SUPPORT)
  411. struct mtk_disp_rsz *rsz = comp_to_rsz(comp);
  412. #endif
  413. mtk_ddp_comp_clk_prepare(comp);
  414. #if defined(CONFIG_DRM_MTK_SHADOW_REGISTER_SUPPORT)
  415. if (rsz->data->support_shadow) {
  416. /* Enable shadow register and read shadow register */
  417. mtk_ddp_write_mask_cpu(comp, 0x0,
  418. DISP_REG_RSZ_SHADOW_CTRL, RSZ_BYPASS_SHADOW);
  419. } else {
  420. /* Bypass shadow register and read shadow register */
  421. mtk_ddp_write_mask_cpu(comp, RSZ_BYPASS_SHADOW,
  422. DISP_REG_RSZ_SHADOW_CTRL, RSZ_BYPASS_SHADOW);
  423. }
  424. #else
  425. #if defined(CONFIG_MACH_MT6873) || defined(CONFIG_MACH_MT6853) \
  426. || defined(CONFIG_MACH_MT6833)
  427. /* Bypass shadow register and read shadow register */
  428. mtk_ddp_write_mask_cpu(comp, RSZ_BYPASS_SHADOW,
  429. DISP_REG_RSZ_SHADOW_CTRL, RSZ_BYPASS_SHADOW);
  430. #endif
  431. #endif
  432. }
  433. static void mtk_rsz_unprepare(struct mtk_ddp_comp *comp)
  434. {
  435. mtk_ddp_comp_clk_unprepare(comp);
  436. }
  437. static const struct mtk_ddp_comp_funcs mtk_disp_rsz_funcs = {
  438. .start = mtk_rsz_start,
  439. .stop = mtk_rsz_stop,
  440. .addon_config = mtk_rsz_addon_config,
  441. .prepare = mtk_rsz_prepare,
  442. .unprepare = mtk_rsz_unprepare,
  443. };
  444. static int mtk_disp_rsz_bind(struct device *dev, struct device *master,
  445. void *data)
  446. {
  447. struct mtk_disp_rsz *priv = dev_get_drvdata(dev);
  448. struct drm_device *drm_dev = data;
  449. struct mtk_drm_private *private = drm_dev->dev_private;
  450. int ret;
  451. pr_info("%s\n", __func__);
  452. ret = mtk_ddp_comp_register(drm_dev, &priv->ddp_comp);
  453. if (ret < 0) {
  454. dev_err(dev, "Failed to register component %s: %d\n",
  455. dev->of_node->full_name, ret);
  456. return ret;
  457. }
  458. private->rsz_in_max[0] = priv->data->tile_length;
  459. private->rsz_in_max[1] = priv->data->in_max_height;
  460. return 0;
  461. }
  462. static void mtk_disp_rsz_unbind(struct device *dev, struct device *master,
  463. void *data)
  464. {
  465. struct mtk_disp_rsz *priv = dev_get_drvdata(dev);
  466. struct drm_device *drm_dev = data;
  467. mtk_ddp_comp_unregister(drm_dev, &priv->ddp_comp);
  468. }
  469. static const struct component_ops mtk_disp_rsz_component_ops = {
  470. .bind = mtk_disp_rsz_bind, .unbind = mtk_disp_rsz_unbind,
  471. };
  472. static int mtk_disp_rsz_probe(struct platform_device *pdev)
  473. {
  474. struct device *dev = &pdev->dev;
  475. struct mtk_disp_rsz *priv;
  476. enum mtk_ddp_comp_id comp_id;
  477. int ret;
  478. DDPINFO("%s+\n", __func__);
  479. priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
  480. if (!priv)
  481. return -ENOMEM;
  482. comp_id = mtk_ddp_comp_get_id(dev->of_node, MTK_DISP_RSZ);
  483. if ((int)comp_id < 0) {
  484. dev_err(dev, "Failed to identify by alias: %d\n", comp_id);
  485. return comp_id;
  486. }
  487. ret = mtk_ddp_comp_init(dev, dev->of_node, &priv->ddp_comp, comp_id,
  488. &mtk_disp_rsz_funcs);
  489. if (ret) {
  490. dev_err(dev, "Failed to initialize component: %d\n", ret);
  491. return ret;
  492. }
  493. priv->data = of_device_get_match_data(dev);
  494. platform_set_drvdata(pdev, priv);
  495. pm_runtime_enable(dev);
  496. ret = component_add(dev, &mtk_disp_rsz_component_ops);
  497. if (ret != 0) {
  498. dev_err(dev, "Failed to add component: %d\n", ret);
  499. pm_runtime_disable(dev);
  500. }
  501. DDPINFO("%s-\n", __func__);
  502. return ret;
  503. }
  504. static int mtk_disp_rsz_remove(struct platform_device *pdev)
  505. {
  506. component_del(&pdev->dev, &mtk_disp_rsz_component_ops);
  507. pm_runtime_disable(&pdev->dev);
  508. return 0;
  509. }
  510. static const struct mtk_disp_rsz_data mt6779_rsz_driver_data = {
  511. .tile_length = 1088, .in_max_height = 4096,
  512. .support_shadow = false,
  513. };
  514. static const struct mtk_disp_rsz_data mt6885_rsz_driver_data = {
  515. .tile_length = 1440, .in_max_height = 4096,
  516. .support_shadow = false,
  517. };
  518. static const struct mtk_disp_rsz_data mt6873_rsz_driver_data = {
  519. .tile_length = 1440, .in_max_height = 4096,
  520. .support_shadow = false,
  521. };
  522. static const struct mtk_disp_rsz_data mt6853_rsz_driver_data = {
  523. .tile_length = 1088, .in_max_height = 4096,
  524. .support_shadow = false,
  525. };
  526. static const struct mtk_disp_rsz_data mt6833_rsz_driver_data = {
  527. .tile_length = 1088, .in_max_height = 4096,
  528. .support_shadow = false,
  529. };
  530. static const struct of_device_id mtk_disp_rsz_driver_dt_match[] = {
  531. {.compatible = "mediatek,mt6779-disp-rsz",
  532. .data = &mt6779_rsz_driver_data},
  533. {.compatible = "mediatek,mt6885-disp-rsz",
  534. .data = &mt6885_rsz_driver_data},
  535. {.compatible = "mediatek,mt6873-disp-rsz",
  536. .data = &mt6873_rsz_driver_data},
  537. {.compatible = "mediatek,mt6853-disp-rsz",
  538. .data = &mt6853_rsz_driver_data},
  539. {.compatible = "mediatek,mt6833-disp-rsz",
  540. .data = &mt6833_rsz_driver_data},
  541. {},
  542. };
  543. MODULE_DEVICE_TABLE(of, mtk_disp_rsz_driver_dt_match);
  544. struct platform_driver mtk_disp_rsz_driver = {
  545. .probe = mtk_disp_rsz_probe,
  546. .remove = mtk_disp_rsz_remove,
  547. .driver = {
  548. .name = "mediatek-disp-rsz",
  549. .owner = THIS_MODULE,
  550. .of_match_table = mtk_disp_rsz_driver_dt_match,
  551. },
  552. };