Merge commit 'refs/merge-requests/1' of git://gitorious.org/linux-on-wince-htc/linux_...
[htc-linux.git] / drivers / video / msm / mdp_ppp31.c
blobcc7b513ce7343329c73a681ef1ca08af2c0140a8
1 /* drivers/video/msm/mdp_ppp31.c
3 * Copyright (C) 2009 QUALCOMM Incorporated
4 * Copyright (C) 2009 Google Incorporated
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.
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.
16 #include <linux/errno.h>
17 #include <linux/kernel.h>
18 #include <asm/io.h>
19 #include <linux/msm_mdp.h>
21 #include "mdp_hw.h"
22 #include "mdp_ppp.h"
24 #define NUM_COEFFS 32
26 struct mdp_scale_coeffs {
27 uint16_t c[4][NUM_COEFFS];
30 struct mdp_scale_tbl_info {
31 uint16_t offset;
32 uint32_t set:2;
33 int use_pr;
34 struct mdp_scale_coeffs coeffs;
37 enum {
38 MDP_SCALE_PT2TOPT4,
39 MDP_SCALE_PT4TOPT6,
40 MDP_SCALE_PT6TOPT8,
41 MDP_SCALE_PT8TO8,
42 MDP_SCALE_MAX,
45 static struct mdp_scale_coeffs mdp_scale_pr_coeffs = {
46 .c = {
47 [0] = {
48 0, 0, 0, 0, 0, 0, 0, 0,
49 0, 0, 0, 0, 0, 0, 0, 0,
50 0, 0, 0, 0, 0, 0, 0, 0,
51 0, 0, 0, 0, 0, 0, 0, 0,
53 [1] = {
54 511, 511, 511, 511, 511, 511, 511, 511,
55 511, 511, 511, 511, 511, 511, 511, 511,
56 0, 0, 0, 0, 0, 0, 0, 0,
57 0, 0, 0, 0, 0, 0, 0, 0,
59 [2] = {
60 0, 0, 0, 0, 0, 0, 0, 0,
61 0, 0, 0, 0, 0, 0, 0, 0,
62 511, 511, 511, 511, 511, 511, 511, 511,
63 511, 511, 511, 511, 511, 511, 511, 511,
65 [3] = {
66 0, 0, 0, 0, 0, 0, 0, 0,
67 0, 0, 0, 0, 0, 0, 0, 0,
68 0, 0, 0, 0, 0, 0, 0, 0,
69 0, 0, 0, 0, 0, 0, 0, 0,
74 static struct mdp_scale_tbl_info mdp_scale_tbl[MDP_SCALE_MAX] = {
75 [ MDP_SCALE_PT2TOPT4 ] = {
76 .offset = 0,
77 .set = MDP_PPP_SCALE_COEFF_D0_SET,
78 .use_pr = -1,
79 .coeffs.c = {
80 [0] = {
81 131, 131, 130, 129, 128, 127, 127, 126,
82 125, 125, 124, 123, 123, 121, 120, 119,
83 119, 118, 117, 117, 116, 115, 115, 114,
84 113, 112, 111, 110, 109, 109, 108, 107,
86 [1] = {
87 141, 140, 140, 140, 140, 139, 138, 138,
88 138, 137, 137, 137, 136, 137, 137, 137,
89 136, 136, 136, 135, 135, 135, 134, 134,
90 134, 134, 134, 133, 133, 132, 132, 132,
92 [2] = {
93 132, 132, 132, 133, 133, 134, 134, 134,
94 134, 134, 135, 135, 135, 136, 136, 136,
95 137, 137, 137, 136, 137, 137, 137, 138,
96 138, 138, 139, 140, 140, 140, 140, 141,
98 [3] = {
99 107, 108, 109, 109, 110, 111, 112, 113,
100 114, 115, 115, 116, 117, 117, 118, 119,
101 119, 120, 121, 123, 123, 124, 125, 125,
102 126, 127, 127, 128, 129, 130, 131, 131,
106 [ MDP_SCALE_PT4TOPT6 ] = {
107 .offset = 32,
108 .set = MDP_PPP_SCALE_COEFF_D1_SET,
109 .use_pr = -1,
110 .coeffs.c = {
111 [0] = {
112 136, 132, 128, 123, 119, 115, 111, 107,
113 103, 98, 95, 91, 87, 84, 80, 76,
114 73, 69, 66, 62, 59, 57, 54, 50,
115 47, 44, 41, 39, 36, 33, 32, 29,
117 [1] = {
118 206, 205, 204, 204, 201, 200, 199, 197,
119 196, 194, 191, 191, 189, 185, 184, 182,
120 180, 178, 176, 173, 170, 168, 165, 162,
121 160, 157, 155, 152, 148, 146, 142, 140,
123 [2] = {
124 140, 142, 146, 148, 152, 155, 157, 160,
125 162, 165, 168, 170, 173, 176, 178, 180,
126 182, 184, 185, 189, 191, 191, 194, 196,
127 197, 199, 200, 201, 204, 204, 205, 206,
129 [3] = {
130 29, 32, 33, 36, 39, 41, 44, 47,
131 50, 54, 57, 59, 62, 66, 69, 73,
132 76, 80, 84, 87, 91, 95, 98, 103,
133 107, 111, 115, 119, 123, 128, 132, 136,
137 [ MDP_SCALE_PT6TOPT8 ] = {
138 .offset = 64,
139 .set = MDP_PPP_SCALE_COEFF_D2_SET,
140 .use_pr = -1,
141 .coeffs.c = {
142 [0] = {
143 104, 96, 89, 82, 75, 68, 61, 55,
144 49, 43, 38, 33, 28, 24, 20, 16,
145 12, 9, 6, 4, 2, 0, -2, -4,
146 -5, -6, -7, -7, -8, -8, -8, -8,
148 [1] = {
149 303, 303, 302, 300, 298, 296, 293, 289,
150 286, 281, 276, 270, 265, 258, 252, 245,
151 238, 230, 223, 214, 206, 197, 189, 180,
152 172, 163, 154, 145, 137, 128, 120, 112,
154 [2] = {
155 112, 120, 128, 137, 145, 154, 163, 172,
156 180, 189, 197, 206, 214, 223, 230, 238,
157 245, 252, 258, 265, 270, 276, 281, 286,
158 289, 293, 296, 298, 300, 302, 303, 303,
160 [3] = {
161 -8, -8, -8, -8, -7, -7, -6, -5,
162 -4, -2, 0, 2, 4, 6, 9, 12,
163 16, 20, 24, 28, 33, 38, 43, 49,
164 55, 61, 68, 75, 82, 89, 96, 104,
168 [ MDP_SCALE_PT8TO8 ] = {
169 .offset = 96,
170 .set = MDP_PPP_SCALE_COEFF_U1_SET,
171 .use_pr = -1,
172 .coeffs.c = {
173 [0] = {
174 0, -7, -13, -19, -24, -28, -32, -34,
175 -37, -39, -40, -41, -41, -41, -40, -40,
176 -38, -37, -35, -33, -31, -29, -26, -24,
177 -21, -18, -15, -13, -10, -7, -5, -2,
179 [1] = {
180 511, 507, 501, 494, 485, 475, 463, 450,
181 436, 422, 405, 388, 370, 352, 333, 314,
182 293, 274, 253, 233, 213, 193, 172, 152,
183 133, 113, 95, 77, 60, 43, 28, 13,
185 [2] = {
186 0, 13, 28, 43, 60, 77, 95, 113,
187 133, 152, 172, 193, 213, 233, 253, 274,
188 294, 314, 333, 352, 370, 388, 405, 422,
189 436, 450, 463, 475, 485, 494, 501, 507,
191 [3] = {
192 0, -2, -5, -7, -10, -13, -15, -18,
193 -21, -24, -26, -29, -31, -33, -35, -37,
194 -38, -40, -40, -41, -41, -41, -40, -39,
195 -37, -34, -32, -28, -24, -19, -13, -7,
201 static void load_table(const struct mdp_info *mdp, int scale, int use_pr)
203 int i;
204 uint32_t val;
205 struct mdp_scale_coeffs *coeffs;
206 struct mdp_scale_tbl_info *tbl = &mdp_scale_tbl[scale];
208 if (use_pr == tbl->use_pr)
209 return;
211 tbl->use_pr = use_pr;
212 if (!use_pr)
213 coeffs = &tbl->coeffs;
214 else
215 coeffs = &mdp_scale_pr_coeffs;
217 for (i = 0; i < NUM_COEFFS; ++i) {
218 val = ((coeffs->c[1][i] & 0x3ff) << 16) |
219 (coeffs->c[0][i] & 0x3ff);
220 mdp_writel(mdp, val, MDP_PPP_SCALE_COEFF_LSBn(tbl->offset + i));
222 val = ((coeffs->c[3][i] & 0x3ff) << 16) |
223 (coeffs->c[2][i] & 0x3ff);
224 mdp_writel(mdp, val, MDP_PPP_SCALE_COEFF_MSBn(tbl->offset + i));
228 #define SCALER_PHASE_BITS 29
229 static void scale_params(uint32_t dim_in, uint32_t dim_out, uint32_t scaler,
230 uint32_t *phase_init, uint32_t *phase_step)
232 uint64_t src = dim_in;
233 uint64_t dst = dim_out;
234 uint64_t numer;
235 uint64_t denom;
237 *phase_init = 0;
239 if (dst == 1) {
240 /* if destination is 1 pixel wide, the value of phase_step
241 * is unimportant. */
242 *phase_step = (uint32_t) (src << SCALER_PHASE_BITS);
243 if (scaler == MDP_PPP_SCALER_FIR)
244 *phase_init =
245 (uint32_t) ((src - 1) << SCALER_PHASE_BITS);
246 return;
249 if (scaler == MDP_PPP_SCALER_FIR) {
250 numer = (src - 1) << SCALER_PHASE_BITS;
251 denom = dst - 1;
252 /* we want to round up the result*/
253 numer += denom - 1;
254 } else {
255 numer = src << SCALER_PHASE_BITS;
256 denom = dst;
259 do_div(numer, denom);
260 *phase_step = (uint32_t) numer;
263 static int scale_idx(int factor)
265 int idx;
267 if (factor > 80)
268 idx = MDP_SCALE_PT8TO8;
269 else if (factor > 60)
270 idx = MDP_SCALE_PT6TOPT8;
271 else if (factor > 40)
272 idx = MDP_SCALE_PT4TOPT6;
273 else
274 idx = MDP_SCALE_PT2TOPT4;
276 return idx;
279 int mdp_ppp_cfg_scale(const struct mdp_info *mdp, struct ppp_regs *regs,
280 struct mdp_rect *src_rect, struct mdp_rect *dst_rect,
281 uint32_t src_format, uint32_t dst_format)
283 uint32_t x_fac;
284 uint32_t y_fac;
285 uint32_t scaler_x = MDP_PPP_SCALER_FIR;
286 uint32_t scaler_y = MDP_PPP_SCALER_FIR;
287 // Don't use pixel repeat mode, it looks bad
288 int use_pr = 0;
289 int x_idx;
290 int y_idx;
292 if (unlikely(src_rect->w > 2048 || src_rect->h > 2048))
293 return -ENOTSUPP;
295 x_fac = (dst_rect->w * 100) / src_rect->w;
296 y_fac = (dst_rect->h * 100) / src_rect->h;
298 /* if down-scaling by a factor smaller than 1/4, use M/N */
299 scaler_x = x_fac <= 25 ? MDP_PPP_SCALER_MN : MDP_PPP_SCALER_FIR;
300 scaler_y = y_fac <= 25 ? MDP_PPP_SCALER_MN : MDP_PPP_SCALER_FIR;
301 scale_params(src_rect->w, dst_rect->w, scaler_x, &regs->phasex_init,
302 &regs->phasex_step);
303 scale_params(src_rect->h, dst_rect->h, scaler_y, &regs->phasey_init,
304 &regs->phasey_step);
306 x_idx = scale_idx(x_fac);
307 y_idx = scale_idx(y_fac);
308 load_table(mdp, x_idx, use_pr);
309 load_table(mdp, y_idx, use_pr);
311 regs->scale_cfg = 0;
312 // Enable SVI when source or destination is YUV
313 if (!IS_RGB(src_format) && !IS_RGB(dst_format))
314 regs->scale_cfg |= (1 << 6);
315 regs->scale_cfg |= (mdp_scale_tbl[x_idx].set << 2) |
316 (mdp_scale_tbl[x_idx].set << 4);
317 regs->scale_cfg |= (scaler_x << 0) | (scaler_y << 1);
319 return 0;
322 int mdp_ppp_load_blur(const struct mdp_info *mdp)
324 return -ENOTSUPP;
327 void mdp_ppp_init_scale(const struct mdp_info *mdp)
329 int scale;
330 for (scale = 0; scale < MDP_SCALE_MAX; ++scale)
331 load_table(mdp, scale, 0);