mdp_ppp31.c 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333
  1. /* drivers/video/msm/mdp_ppp31.c
  2. *
  3. * Copyright (C) 2009 The Linux Foundation. All rights reserved.
  4. * Copyright (C) 2009 Google Incorporated
  5. *
  6. * This software is licensed under the terms of the GNU General Public
  7. * License version 2, as published by the Free Software Foundation, and
  8. * may be copied, distributed, and modified under those terms.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. */
  15. #include <linux/errno.h>
  16. #include <linux/kernel.h>
  17. #include <asm/io.h>
  18. #include <linux/msm_mdp.h>
  19. #include "mdp_hw.h"
  20. #include "mdp_ppp.h"
  21. #define NUM_COEFFS 32
  22. struct mdp_scale_coeffs {
  23. uint16_t c[4][NUM_COEFFS];
  24. };
  25. struct mdp_scale_tbl_info {
  26. uint16_t offset;
  27. uint32_t set:2;
  28. int use_pr;
  29. struct mdp_scale_coeffs coeffs;
  30. };
  31. enum {
  32. MDP_SCALE_PT2TOPT4,
  33. MDP_SCALE_PT4TOPT6,
  34. MDP_SCALE_PT6TOPT8,
  35. MDP_SCALE_PT8TO8,
  36. MDP_SCALE_MAX,
  37. };
  38. static struct mdp_scale_coeffs mdp_scale_pr_coeffs = {
  39. .c = {
  40. [0] = {
  41. 0, 0, 0, 0, 0, 0, 0, 0,
  42. 0, 0, 0, 0, 0, 0, 0, 0,
  43. 0, 0, 0, 0, 0, 0, 0, 0,
  44. 0, 0, 0, 0, 0, 0, 0, 0,
  45. },
  46. [1] = {
  47. 511, 511, 511, 511, 511, 511, 511, 511,
  48. 511, 511, 511, 511, 511, 511, 511, 511,
  49. 0, 0, 0, 0, 0, 0, 0, 0,
  50. 0, 0, 0, 0, 0, 0, 0, 0,
  51. },
  52. [2] = {
  53. 0, 0, 0, 0, 0, 0, 0, 0,
  54. 0, 0, 0, 0, 0, 0, 0, 0,
  55. 511, 511, 511, 511, 511, 511, 511, 511,
  56. 511, 511, 511, 511, 511, 511, 511, 511,
  57. },
  58. [3] = {
  59. 0, 0, 0, 0, 0, 0, 0, 0,
  60. 0, 0, 0, 0, 0, 0, 0, 0,
  61. 0, 0, 0, 0, 0, 0, 0, 0,
  62. 0, 0, 0, 0, 0, 0, 0, 0,
  63. },
  64. },
  65. };
  66. static struct mdp_scale_tbl_info mdp_scale_tbl[MDP_SCALE_MAX] = {
  67. [ MDP_SCALE_PT2TOPT4 ] = {
  68. .offset = 0,
  69. .set = MDP_PPP_SCALE_COEFF_D0_SET,
  70. .use_pr = -1,
  71. .coeffs.c = {
  72. [0] = {
  73. 131, 131, 130, 129, 128, 127, 127, 126,
  74. 125, 125, 124, 123, 123, 121, 120, 119,
  75. 119, 118, 117, 117, 116, 115, 115, 114,
  76. 113, 112, 111, 110, 109, 109, 108, 107,
  77. },
  78. [1] = {
  79. 141, 140, 140, 140, 140, 139, 138, 138,
  80. 138, 137, 137, 137, 136, 137, 137, 137,
  81. 136, 136, 136, 135, 135, 135, 134, 134,
  82. 134, 134, 134, 133, 133, 132, 132, 132,
  83. },
  84. [2] = {
  85. 132, 132, 132, 133, 133, 134, 134, 134,
  86. 134, 134, 135, 135, 135, 136, 136, 136,
  87. 137, 137, 137, 136, 137, 137, 137, 138,
  88. 138, 138, 139, 140, 140, 140, 140, 141,
  89. },
  90. [3] = {
  91. 107, 108, 109, 109, 110, 111, 112, 113,
  92. 114, 115, 115, 116, 117, 117, 118, 119,
  93. 119, 120, 121, 123, 123, 124, 125, 125,
  94. 126, 127, 127, 128, 129, 130, 131, 131,
  95. }
  96. },
  97. },
  98. [ MDP_SCALE_PT4TOPT6 ] = {
  99. .offset = 32,
  100. .set = MDP_PPP_SCALE_COEFF_D1_SET,
  101. .use_pr = -1,
  102. .coeffs.c = {
  103. [0] = {
  104. 136, 132, 128, 123, 119, 115, 111, 107,
  105. 103, 98, 95, 91, 87, 84, 80, 76,
  106. 73, 69, 66, 62, 59, 57, 54, 50,
  107. 47, 44, 41, 39, 36, 33, 32, 29,
  108. },
  109. [1] = {
  110. 206, 205, 204, 204, 201, 200, 199, 197,
  111. 196, 194, 191, 191, 189, 185, 184, 182,
  112. 180, 178, 176, 173, 170, 168, 165, 162,
  113. 160, 157, 155, 152, 148, 146, 142, 140,
  114. },
  115. [2] = {
  116. 140, 142, 146, 148, 152, 155, 157, 160,
  117. 162, 165, 168, 170, 173, 176, 178, 180,
  118. 182, 184, 185, 189, 191, 191, 194, 196,
  119. 197, 199, 200, 201, 204, 204, 205, 206,
  120. },
  121. [3] = {
  122. 29, 32, 33, 36, 39, 41, 44, 47,
  123. 50, 54, 57, 59, 62, 66, 69, 73,
  124. 76, 80, 84, 87, 91, 95, 98, 103,
  125. 107, 111, 115, 119, 123, 128, 132, 136,
  126. },
  127. },
  128. },
  129. [ MDP_SCALE_PT6TOPT8 ] = {
  130. .offset = 64,
  131. .set = MDP_PPP_SCALE_COEFF_D2_SET,
  132. .use_pr = -1,
  133. .coeffs.c = {
  134. [0] = {
  135. 104, 96, 89, 82, 75, 68, 61, 55,
  136. 49, 43, 38, 33, 28, 24, 20, 16,
  137. 12, 9, 6, 4, 2, 0, -2, -4,
  138. -5, -6, -7, -7, -8, -8, -8, -8,
  139. },
  140. [1] = {
  141. 303, 303, 302, 300, 298, 296, 293, 289,
  142. 286, 281, 276, 270, 265, 258, 252, 245,
  143. 238, 230, 223, 214, 206, 197, 189, 180,
  144. 172, 163, 154, 145, 137, 128, 120, 112,
  145. },
  146. [2] = {
  147. 112, 120, 128, 137, 145, 154, 163, 172,
  148. 180, 189, 197, 206, 214, 223, 230, 238,
  149. 245, 252, 258, 265, 270, 276, 281, 286,
  150. 289, 293, 296, 298, 300, 302, 303, 303,
  151. },
  152. [3] = {
  153. -8, -8, -8, -8, -7, -7, -6, -5,
  154. -4, -2, 0, 2, 4, 6, 9, 12,
  155. 16, 20, 24, 28, 33, 38, 43, 49,
  156. 55, 61, 68, 75, 82, 89, 96, 104,
  157. },
  158. },
  159. },
  160. [ MDP_SCALE_PT8TO8 ] = {
  161. .offset = 96,
  162. .set = MDP_PPP_SCALE_COEFF_U1_SET,
  163. .use_pr = -1,
  164. .coeffs.c = {
  165. [0] = {
  166. 0, -7, -13, -19, -24, -28, -32, -34,
  167. -37, -39, -40, -41, -41, -41, -40, -40,
  168. -38, -37, -35, -33, -31, -29, -26, -24,
  169. -21, -18, -15, -13, -10, -7, -5, -2,
  170. },
  171. [1] = {
  172. 511, 507, 501, 494, 485, 475, 463, 450,
  173. 436, 422, 405, 388, 370, 352, 333, 314,
  174. 293, 274, 253, 233, 213, 193, 172, 152,
  175. 133, 113, 95, 77, 60, 43, 28, 13,
  176. },
  177. [2] = {
  178. 0, 13, 28, 43, 60, 77, 95, 113,
  179. 133, 152, 172, 193, 213, 233, 253, 274,
  180. 294, 314, 333, 352, 370, 388, 405, 422,
  181. 436, 450, 463, 475, 485, 494, 501, 507,
  182. },
  183. [3] = {
  184. 0, -2, -5, -7, -10, -13, -15, -18,
  185. -21, -24, -26, -29, -31, -33, -35, -37,
  186. -38, -40, -40, -41, -41, -41, -40, -39,
  187. -37, -34, -32, -28, -24, -19, -13, -7,
  188. },
  189. },
  190. },
  191. };
  192. static void load_table(const struct mdp_info *mdp, int scale, int use_pr)
  193. {
  194. int i;
  195. uint32_t val;
  196. struct mdp_scale_coeffs *coeffs;
  197. struct mdp_scale_tbl_info *tbl = &mdp_scale_tbl[scale];
  198. if (use_pr == tbl->use_pr)
  199. return;
  200. tbl->use_pr = use_pr;
  201. if (!use_pr)
  202. coeffs = &tbl->coeffs;
  203. else
  204. coeffs = &mdp_scale_pr_coeffs;
  205. for (i = 0; i < NUM_COEFFS; ++i) {
  206. val = ((coeffs->c[1][i] & 0x3ff) << 16) |
  207. (coeffs->c[0][i] & 0x3ff);
  208. mdp_writel(mdp, val, MDP_PPP_SCALE_COEFF_LSBn(tbl->offset + i));
  209. val = ((coeffs->c[3][i] & 0x3ff) << 16) |
  210. (coeffs->c[2][i] & 0x3ff);
  211. mdp_writel(mdp, val, MDP_PPP_SCALE_COEFF_MSBn(tbl->offset + i));
  212. }
  213. }
  214. #define SCALER_PHASE_BITS 29
  215. static void scale_params(uint32_t dim_in, uint32_t dim_out, uint32_t scaler,
  216. uint32_t *phase_init, uint32_t *phase_step)
  217. {
  218. uint64_t src = dim_in;
  219. uint64_t dst = dim_out;
  220. uint64_t numer;
  221. uint64_t denom;
  222. *phase_init = 0;
  223. if (dst == 1) {
  224. /* if destination is 1 pixel wide, the value of phase_step
  225. * is unimportant. */
  226. *phase_step = (uint32_t) (src << SCALER_PHASE_BITS);
  227. if (scaler == MDP_PPP_SCALER_FIR)
  228. *phase_init =
  229. (uint32_t) ((src - 1) << SCALER_PHASE_BITS);
  230. return;
  231. }
  232. if (scaler == MDP_PPP_SCALER_FIR) {
  233. numer = (src - 1) << SCALER_PHASE_BITS;
  234. denom = dst - 1;
  235. /* we want to round up the result*/
  236. numer += denom - 1;
  237. } else {
  238. numer = src << SCALER_PHASE_BITS;
  239. denom = dst;
  240. }
  241. do_div(numer, denom);
  242. *phase_step = (uint32_t) numer;
  243. }
  244. static int scale_idx(int factor)
  245. {
  246. int idx;
  247. if (factor > 80)
  248. idx = MDP_SCALE_PT8TO8;
  249. else if (factor > 60)
  250. idx = MDP_SCALE_PT6TOPT8;
  251. else if (factor > 40)
  252. idx = MDP_SCALE_PT4TOPT6;
  253. else
  254. idx = MDP_SCALE_PT2TOPT4;
  255. return idx;
  256. }
  257. int mdp_ppp_cfg_scale(const struct mdp_info *mdp, struct ppp_regs *regs,
  258. struct mdp_rect *src_rect, struct mdp_rect *dst_rect,
  259. uint32_t src_format, uint32_t dst_format)
  260. {
  261. uint32_t x_fac;
  262. uint32_t y_fac;
  263. uint32_t scaler_x = MDP_PPP_SCALER_FIR;
  264. uint32_t scaler_y = MDP_PPP_SCALER_FIR;
  265. // Don't use pixel repeat mode, it looks bad
  266. int use_pr = 0;
  267. int x_idx;
  268. int y_idx;
  269. if (unlikely(src_rect->w > 2048 || src_rect->h > 2048))
  270. return -ENOTSUPP;
  271. x_fac = (dst_rect->w * 100) / src_rect->w;
  272. y_fac = (dst_rect->h * 100) / src_rect->h;
  273. /* if down-scaling by a factor smaller than 1/4, use M/N */
  274. scaler_x = x_fac <= 25 ? MDP_PPP_SCALER_MN : MDP_PPP_SCALER_FIR;
  275. scaler_y = y_fac <= 25 ? MDP_PPP_SCALER_MN : MDP_PPP_SCALER_FIR;
  276. scale_params(src_rect->w, dst_rect->w, scaler_x, &regs->phasex_init,
  277. &regs->phasex_step);
  278. scale_params(src_rect->h, dst_rect->h, scaler_y, &regs->phasey_init,
  279. &regs->phasey_step);
  280. x_idx = scale_idx(x_fac);
  281. y_idx = scale_idx(y_fac);
  282. load_table(mdp, x_idx, use_pr);
  283. load_table(mdp, y_idx, use_pr);
  284. regs->scale_cfg = 0;
  285. // Enable SVI when source or destination is YUV
  286. if (!IS_RGB(src_format) && !IS_RGB(dst_format))
  287. regs->scale_cfg |= (1 << 6);
  288. regs->scale_cfg |= (mdp_scale_tbl[x_idx].set << 2) |
  289. (mdp_scale_tbl[x_idx].set << 4);
  290. regs->scale_cfg |= (scaler_x << 0) | (scaler_y << 1);
  291. return 0;
  292. }
  293. int mdp_ppp_load_blur(const struct mdp_info *mdp)
  294. {
  295. return -ENOTSUPP;
  296. }
  297. void mdp_ppp_init_scale(const struct mdp_info *mdp)
  298. {
  299. int scale;
  300. for (scale = 0; scale < MDP_SCALE_MAX; ++scale)
  301. load_table(mdp, scale, 0);
  302. }