blob: 5735f4599b736d7d7acbd456ec85e71a72737994 [file] [log] [blame]
Liyuan Lid9736632011-11-11 13:47:59 -08001/* Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 */
13
14#include <linux/module.h>
15#include <linux/types.h>
16#include <linux/msm_mdp.h>
17#include "mdp.h"
18#include "mdp4.h"
19
20/* Definitions */
21#define MDP4_CSC_MV_OFF 0x4400
22#define MDP4_CSC_PRE_BV_OFF 0x4500
23#define MDP4_CSC_POST_BV_OFF 0x4580
24#define MDP4_CSC_PRE_LV_OFF 0x4600
25#define MDP4_CSC_POST_LV_OFF 0x4680
26#define MDP_VG1_BASE (MDP_BASE + MDP4_VIDEO_BASE)
27
28#define MDP_VG1_CSC_MVn(n) (MDP_VG1_BASE + MDP4_CSC_MV_OFF + 4 * (n))
29#define MDP_VG1_CSC_PRE_LVn(n) (MDP_VG1_BASE + MDP4_CSC_PRE_LV_OFF + 4 * (n))
30#define MDP_VG1_CSC_POST_LVn(n) (MDP_VG1_BASE + MDP4_CSC_POST_LV_OFF + 4 * (n))
31#define MDP_VG1_CSC_PRE_BVn(n) (MDP_VG1_BASE + MDP4_CSC_PRE_BV_OFF + 4 * (n))
32#define MDP_VG1_CSC_POST_BVn(n) (MDP_VG1_BASE + MDP4_CSC_POST_BV_OFF + 4 * (n))
33
34#define Q16 (16)
35#define Q16_ONE (1 << Q16)
36
37#define Q16_VALUE(x) ((int32_t)((uint32_t)x << Q16))
38#define Q16_PERCENT_VALUE(x, n) ((int32_t)( \
39 div_s64(((int64_t)x * (int64_t)Q16_ONE), n)))
40
41#define Q16_WHOLE(x) ((int32_t)(x >> 16))
42#define Q16_FRAC(x) ((int32_t)(x & 0xFFFF))
43#define Q16_S1Q16_MUL(x, y) (((x >> 1) * (y >> 1)) >> 14)
44
45#define Q16_MUL(x, y) ((int32_t)((((int64_t)x) * ((int64_t)y)) >> Q16))
46#define Q16_NEGATE(x) (0 - (x))
47
48/*
49 * HSIC Control min/max values
50 * These settings are based on the maximum/minimum allowed modifications to
51 * HSIC controls for layer and display color. Allowing too much variation in
52 * the CSC block will result in color clipping resulting in unwanted color
53 * shifts.
54 */
55#define TRIG_MAX Q16_VALUE(128)
56#define CON_SAT_MAX Q16_VALUE(128)
57#define INTENSITY_MAX (Q16_VALUE(2047) >> 12)
58
59#define HUE_MAX Q16_VALUE(100)
60#define HUE_MIN Q16_VALUE(-100)
61#define HUE_DEF Q16_VALUE(0)
62
63#define SAT_MAX Q16_VALUE(100)
64#define SAT_MIN Q16_VALUE(-100)
65#define SAT_DEF CON_SAT_MAX
66
67#define CON_MAX Q16_VALUE(100)
68#define CON_MIN Q16_VALUE(-100)
69#define CON_DEF CON_SAT_MAX
70
71#define INTEN_MAX Q16_VALUE(100)
72#define INTEN_MIN Q16_VALUE(-100)
73#define INTEN_DEF Q16_VALUE(0)
74
75enum {
76 DIRTY,
77 GENERATED,
78 CLEAN
79};
80
81/* local vars*/
82static int32_t csc_matrix_tab[3][3] = {
83 {0x00012a00, 0x00000000, 0x00019880},
84 {0x00012a00, 0xffff9b80, 0xffff3000},
85 {0x00012a00, 0x00020480, 0x00000000}
86};
87
88static int32_t csc_yuv2rgb_conv_tab[3][3] = {
89 {0x00010000, 0x00000000, 0x000123cb},
90 {0x00010000, 0xffff9af9, 0xffff6b5e},
91 {0x00010000, 0x00020838, 0x00000000}
92};
93
94static int32_t csc_rgb2yuv_conv_tab[3][3] = {
95 {0x00004c8b, 0x00009645, 0x00001d2f},
96 {0xffffda56, 0xffffb60e, 0x00006f9d},
97 {0x00009d70, 0xffff7c2a, 0xffffe666}
98};
99
100static uint32_t csc_pre_bv_tab[3] = {0xfffff800, 0xffffc000, 0xffffc000};
101static uint32_t csc_post_bv_tab[3] = {0x00000000, 0x00000000, 0x00000000};
102
103static uint32_t csc_pre_lv_tab[6] = {0x00000000, 0x00007f80, 0x00000000,
104 0x00007f80, 0x00000000, 0x00007f80};
105static uint32_t csc_post_lv_tab[6] = {0x00000000, 0x00007f80, 0x00000000,
106 0x00007f80, 0x00000000, 0x00007f80};
107
108/* Lookup table for Sin/Cos lookup - Q16*/
109static const int32_t trig_lut[65] = {
110 0x00000000, /* sin((2*M_PI/256) * 0x00);*/
111 0x00000648, /* sin((2*M_PI/256) * 0x01);*/
112 0x00000C90, /* sin((2*M_PI/256) * 0x02);*/
113 0x000012D5,
114 0x00001918,
115 0x00001F56,
116 0x00002590,
117 0x00002BC4,
118 0x000031F1,
119 0x00003817,
120 0x00003E34,
121 0x00004447,
122 0x00004A50,
123 0x0000504D,
124 0x0000563E,
125 0x00005C22,
126 0x000061F8,
127 0x000067BE,
128 0x00006D74,
129 0x0000731A,
130 0x000078AD,
131 0x00007E2F,
132 0x0000839C,
133 0x000088F6,
134 0x00008E3A,
135 0x00009368,
136 0x00009880,
137 0x00009D80,
138 0x0000A268,
139 0x0000A736,
140 0x0000ABEB,
141 0x0000B086,
142 0x0000B505,
143 0x0000B968,
144 0x0000BDAF,
145 0x0000C1D8,
146 0x0000C5E4,
147 0x0000C9D1,
148 0x0000CD9F,
149 0x0000D14D,
150 0x0000D4DB,
151 0x0000D848,
152 0x0000DB94,
153 0x0000DEBE,
154 0x0000E1C6,
155 0x0000E4AA,
156 0x0000E768,
157 0x0000EA0A,
158 0x0000EC83,
159 0x0000EED9,
160 0x0000F109,
161 0x0000F314,
162 0x0000F4FA,
163 0x0000F6BA,
164 0x0000F854,
165 0x0000F9C8,
166 0x0000FB15,
167 0x0000FC3B,
168 0x0000FD3B,
169 0x0000FE13,
170 0x0000FEC4,
171 0x0000FF4E,
172 0x0000FFB1,
173 0x0000FFEC,
174 0x00010000, /* sin((2*M_PI/256) * 0x40);*/
175};
176
177void trig_values_q16(int32_t deg, int32_t *cos, int32_t *sin)
178{
179 int32_t angle;
180 int32_t quad, anglei, anglef;
181 int32_t v0 = 0, v1 = 0;
182 int32_t t1, t2;
183
184 /*
185 * Scale the angle so that 256 is one complete revolution and mask it
186 * to this domain
187 * NOTE: 0xB60B == 256/360
188 */
189 angle = Q16_MUL(deg, 0xB60B) & 0x00FFFFFF;
190
191 /* Obtain a quadrant number, integer, and fractional part */
192 quad = angle >> 22;
193 anglei = (angle >> 16) & 0x3F;
194 anglef = angle & 0xFFFF;
195
196 /*
197 * Using the integer part, obtain the lookup table entry and its
198 * complement. Using the quadrant, swap and negate these as
199 * necessary.
200 * (The values and all derivatives of sine and cosine functions
201 * can be derived from these values)
202 */
203 switch (quad) {
204 case 0x0:
205 v0 += trig_lut[anglei];
206 v1 += trig_lut[0x40-anglei];
207 break;
208
209 case 0x1:
210 v0 += trig_lut[0x40-anglei];
211 v1 -= trig_lut[anglei];
212 break;
213
214 case 0x2:
215 v0 -= trig_lut[anglei];
216 v1 -= trig_lut[0x40-anglei];
217 break;
218
219 case 0x3:
220 v0 -= trig_lut[0x40-anglei];
221 v1 += trig_lut[anglei];
222 break;
223 }
224
225 /*
226 * Multiply the fractional part by 2*PI/256 to move it from lookup
227 * table units to radians, giving us the coefficient for first
228 * derivatives.
229 */
230 t1 = Q16_S1Q16_MUL(anglef, 0x0648);
231
232 /*
233 * Square this and divide by 2 to get the coefficient for second
234 * derivatives
235 */
236 t2 = Q16_S1Q16_MUL(t1, t1) >> 1;
237
238 *sin = v0 + Q16_S1Q16_MUL(v1, t1) - Q16_S1Q16_MUL(v0, t2);
239
240 *cos = v1 - Q16_S1Q16_MUL(v0, t1) - Q16_S1Q16_MUL(v1, t2);
241}
242
243/* Convert input Q16 value to s4.9 */
244int16_t convert_q16_s49(int32_t q16Value)
245{ /* Top half is the whole number, Bottom half is fractional portion*/
246 int16_t whole = Q16_WHOLE(q16Value);
247 int32_t fraction = Q16_FRAC(q16Value);
248
249 /* Clamp whole to 3 bits */
250 if (whole > 7)
251 whole = 7;
252 else if (whole < -7)
253 whole = -7;
254
255 /* Reduce fraction to 9 bits. */
256 fraction = (fraction<<9)>>Q16;
257
258 return (int16_t) ((int16_t)whole<<9) | ((int16_t)fraction);
259}
260
261/* Convert input Q16 value to uint16 */
262int16_t convert_q16_int16(int32_t val)
263{
264 int32_t rounded;
265
266 if (val >= 0) {
267 /* Add 0.5 */
268 rounded = val + (Q16_ONE>>1);
269 } else {
270 /* Subtract 0.5 */
271 rounded = val - (Q16_ONE>>1);
272 }
273
274 /* Truncate rounded value */
275 return (int16_t)(rounded>>Q16);
276}
277
278/*
279 * norm_q16
280 * Return a Q16 value represeting a normalized value
281 *
282 * value -100% 0% +100%
283 * |-----------------|----------------|
284 * ^ ^ ^
285 * q16MinValue q16DefaultValue q16MaxValue
286 *
287 */
288int32_t norm_q16(int32_t value, int32_t min, int32_t default_val, int32_t max,
289 int32_t range)
290{
291 int32_t diff, perc, mul, result;
292
293 if (0 == value) {
294 result = default_val;
295 } else if (value > 0) {
296 /* value is between 0% and +100% represent 1.0 -> QRange Max */
297 diff = range;
298 perc = Q16_PERCENT_VALUE(value, max);
299 mul = Q16_MUL(perc, diff);
300 result = default_val + mul;
301 } else {
302 /* if (value <= 0) */
303 diff = -range;
304 perc = Q16_PERCENT_VALUE(-value, -min);
305 mul = Q16_MUL(perc, diff);
306 result = default_val + mul;
307 }
308 return result;
309}
310
311void matrix_mul_3x3(int32_t dest[][3], int32_t a[][3], int32_t b[][3])
312{
313 int32_t i, j, k;
314 int32_t tmp[3][3];
315
316 for (i = 0; i < 3; i++) {
317 for (j = 0; j < 3; j++) {
318 tmp[i][j] = 0;
319 for (k = 0; k < 3; k++)
320 tmp[i][j] += Q16_MUL(a[i][k], b[k][j]);
321 }
322 }
323
324 /* in case dest = a or b*/
325 for (i = 0; i < 3; i++) {
326 for (j = 0; j < 3; j++)
327 dest[i][j] = tmp[i][j];
328 }
329}
330
331#define CONVERT(x) (x)/*convert_q16_s49((x))*/
332void pr_params(struct mdp4_hsic_regs *regs)
333{
334 int i;
335 if (regs) {
336 for (i = 0; i < NUM_HSIC_PARAM; i++) {
337 pr_info("\t: hsic->params[%d] = 0x%08x [raw = 0x%08x]\n",
338 i, CONVERT(regs->params[i]), regs->params[i]);
339 }
340 }
341}
342
343void pr_3x3_matrix(int32_t in[][3])
344{
345 pr_info("\t[0x%08x\t0x%08x\t0x%08x]\n", CONVERT(in[0][0]),
346 CONVERT(in[0][1]), CONVERT(in[0][2]));
347 pr_info("\t[0x%08x\t0x%08x\t0x%08x]\n", CONVERT(in[1][0]),
348 CONVERT(in[1][1]), CONVERT(in[1][2]));
349 pr_info("\t[0x%08x\t0x%08x\t0x%08x]\n", CONVERT(in[2][0]),
350 CONVERT(in[2][1]), CONVERT(in[2][2]));
351}
352
353void _hsic_get(struct mdp4_hsic_regs *regs, int32_t type, int8_t *val)
354{
355 if (type < 0 || type >= NUM_HSIC_PARAM)
356 BUG_ON(-EINVAL);
357 *val = regs->params[type];
358 pr_info("%s: getting params[%d] = %d\n", __func__, type, *val);
359}
360
361void _hsic_set(struct mdp4_hsic_regs *regs, int32_t type, int8_t val)
362{
363 if (type < 0 || type >= NUM_HSIC_PARAM)
364 BUG_ON(-EINVAL);
365
366 if (regs->params[type] != Q16_VALUE(val)) {
367 regs->params[type] = Q16_VALUE(val);
368 regs->dirty = DIRTY;
369 }
370}
371
372void _hsic_generate_csc_matrix(struct mdp4_overlay_pipe *pipe)
373{
374 int i, j;
375 int32_t sin, cos;
376
377 int32_t hue_matrix[3][3];
378 int32_t con_sat_matrix[3][3];
379 struct mdp4_hsic_regs *regs = &(pipe->hsic_regs);
380
381 memset(con_sat_matrix, 0x0, sizeof(con_sat_matrix));
382 memset(hue_matrix, 0x0, sizeof(hue_matrix));
383
384 /*
385 * HSIC control require matrix multiplication of these two tables
386 * [T 0 0][1 0 0] T = Contrast C=Cos(Hue)
387 * [0 S 0][0 C -N] S = Saturation N=Sin(Hue)
388 * [0 0 S][0 N C]
389 */
390
391 con_sat_matrix[0][0] = norm_q16(regs->params[HSIC_CON], CON_MIN,
392 CON_DEF, CON_MAX, CON_SAT_MAX);
393 con_sat_matrix[1][1] = norm_q16(regs->params[HSIC_SAT], SAT_MIN,
394 SAT_DEF, SAT_MAX, CON_SAT_MAX);
395 con_sat_matrix[2][2] = con_sat_matrix[1][1];
396
397 hue_matrix[0][0] = TRIG_MAX;
398
399 trig_values_q16(norm_q16(regs->params[HSIC_HUE], HUE_MIN, HUE_DEF,
400 HUE_MAX, TRIG_MAX), &cos, &sin);
401
402 cos = Q16_MUL(cos, TRIG_MAX);
403 sin = Q16_MUL(sin, TRIG_MAX);
404
405 hue_matrix[1][1] = cos;
406 hue_matrix[2][2] = cos;
407 hue_matrix[2][1] = sin;
408 hue_matrix[1][2] = Q16_NEGATE(sin);
409
410 /* Generate YUV CSC matrix */
411 matrix_mul_3x3(regs->conv_matrix, con_sat_matrix, hue_matrix);
412
413 if (!(pipe->op_mode & MDP4_OP_SRC_DATA_YCBCR)) {
414 /* Convert input RGB to YUV then apply CSC matrix */
415 pr_info("Pipe %d, has RGB input\n", pipe->pipe_num);
416 matrix_mul_3x3(regs->conv_matrix, regs->conv_matrix,
417 csc_rgb2yuv_conv_tab);
418 }
419
420 /* Normalize the matrix */
421 for (i = 0; i < 3; i++) {
422 for (j = 0; j < 3; j++)
423 regs->conv_matrix[i][j] = (regs->conv_matrix[i][j]>>14);
424 }
425
426 /* Multiply above result by current csc table */
427 matrix_mul_3x3(regs->conv_matrix, regs->conv_matrix, csc_matrix_tab);
428
429 if (!(pipe->op_mode & MDP4_OP_SRC_DATA_YCBCR)) {
430 /*HACK:only "works"for src side*/
431 /* Convert back to RGB */
432 pr_info("Pipe %d, has RGB output\n", pipe->pipe_num);
433 matrix_mul_3x3(regs->conv_matrix, csc_yuv2rgb_conv_tab,
434 regs->conv_matrix);
435 }
436
437 /* Update clamps pre and post. */
438 /* TODO: different tables for different color formats? */
439 for (i = 0; i < 6; i++) {
440 regs->pre_limit[i] = csc_pre_lv_tab[i];
441 regs->post_limit[i] = csc_post_lv_tab[i];
442 }
443
444 /* update bias values, pre and post */
445 for (i = 0; i < 3; i++) {
446 regs->pre_bias[i] = csc_pre_bv_tab[i];
447 regs->post_bias[i] = csc_post_bv_tab[i] +
448 norm_q16(regs->params[HSIC_INT],
449 INTEN_MIN, INTEN_DEF, INTEN_MAX, INTENSITY_MAX);
450 }
451
452 regs->dirty = GENERATED;
453}
454
455void _hsic_update_mdp(struct mdp4_overlay_pipe *pipe)
456{
457 struct mdp4_hsic_regs *regs = &(pipe->hsic_regs);
458 int i, j, k;
459
460 uint32_t *csc_mv;
461 uint32_t *pre_lv;
462 uint32_t *post_lv;
463 uint32_t *pre_bv;
464 uint32_t *post_bv;
465
466 switch (pipe->pipe_num) {
467 case OVERLAY_PIPE_VG2:
468 csc_mv = (uint32_t *) (MDP_VG1_CSC_MVn(0) +
469 MDP4_VIDEO_OFF);
470 pre_lv = (uint32_t *) (MDP_VG1_CSC_PRE_LVn(0) +
471 MDP4_VIDEO_OFF);
472 post_lv = (uint32_t *) (MDP_VG1_CSC_POST_LVn(0) +
473 MDP4_VIDEO_OFF);
474 pre_bv = (uint32_t *) (MDP_VG1_CSC_PRE_BVn(0) +
475 MDP4_VIDEO_OFF);
476 post_bv = (uint32_t *) (MDP_VG1_CSC_POST_BVn(0) +
477 MDP4_VIDEO_OFF);
478 break;
479 case OVERLAY_PIPE_VG1:
480 default:
481 csc_mv = (uint32_t *) MDP_VG1_CSC_MVn(0);
482 pre_lv = (uint32_t *) MDP_VG1_CSC_PRE_LVn(0);
483 post_lv = (uint32_t *) MDP_VG1_CSC_POST_LVn(0);
484 pre_bv = (uint32_t *) MDP_VG1_CSC_PRE_BVn(0);
485 post_bv = (uint32_t *) MDP_VG1_CSC_POST_BVn(0);
486 break;
487 }
488
489 mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
490
491 for (i = 0; i < 3; i++) {
492 for (j = 0; j < 3; j++) {
493 k = (3*i) + j;
494 MDP_OUTP(csc_mv + k, convert_q16_s49(
495 regs->conv_matrix[i][j]));
496 }
497 }
498
499 for (i = 0; i < 6; i++) {
500 MDP_OUTP(pre_lv + i, convert_q16_s49(regs->pre_limit[i]));
501 MDP_OUTP(post_lv + i, convert_q16_s49(regs->post_limit[i]));
502 }
503
504 for (i = 0; i < 3; i++) {
505 MDP_OUTP(pre_bv + i, convert_q16_s49(regs->pre_bias[i]));
506 MDP_OUTP(post_bv + i, convert_q16_s49(regs->post_bias[i]));
507 }
508 mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
509
510 regs->dirty = CLEAN;
511}
512
513void mdp4_hsic_get(struct mdp4_overlay_pipe *pipe, struct dpp_ctrl *ctrl)
514{
515 int i;
516 for (i = 0; i < NUM_HSIC_PARAM; i++)
517 _hsic_get(&(pipe->hsic_regs), i, &(ctrl->hsic_params[i]));
518}
519
520void mdp4_hsic_set(struct mdp4_overlay_pipe *pipe, struct dpp_ctrl *ctrl)
521{
522 int i;
523 for (i = 0; i < NUM_HSIC_PARAM; i++)
524 _hsic_set(&(pipe->hsic_regs), i, ctrl->hsic_params[i]);
525
526 if (pipe->hsic_regs.dirty == DIRTY)
527 _hsic_generate_csc_matrix(pipe);
528}
529
530void mdp4_hsic_update(struct mdp4_overlay_pipe *pipe)
531{
532 if (pipe->hsic_regs.dirty == GENERATED)
533 _hsic_update_mdp(pipe);
534}