diff options
-rw-r--r-- | drivers/video/tegra/dc/dc.c | 46 | ||||
-rw-r--r-- | drivers/video/tegra/dc/ext/dev.c | 71 | ||||
-rw-r--r-- | include/video/tegra_dc_ext.h | 25 |
3 files changed, 141 insertions, 1 deletions
diff --git a/drivers/video/tegra/dc/dc.c b/drivers/video/tegra/dc/dc.c index b1899a517..e2daa826e 100644 --- a/drivers/video/tegra/dc/dc.c +++ b/drivers/video/tegra/dc/dc.c | |||
@@ -665,6 +665,48 @@ int tegra_dc_update_csc(struct tegra_dc *dc, int win_idx) | |||
665 | } | 665 | } |
666 | EXPORT_SYMBOL(tegra_dc_update_csc); | 666 | EXPORT_SYMBOL(tegra_dc_update_csc); |
667 | 667 | ||
668 | static void tegra_dc_init_lut_defaults(struct tegra_dc_lut *lut) | ||
669 | { | ||
670 | int i; | ||
671 | for(i=0; i<256; i++) { | ||
672 | lut->r[i] = lut->g[i] = lut->b[i] = (u8)i; | ||
673 | } | ||
674 | } | ||
675 | |||
676 | static void tegra_dc_set_lut(struct tegra_dc *dc, | ||
677 | struct tegra_dc_lut *lut, | ||
678 | int start, | ||
679 | int len) | ||
680 | { | ||
681 | int i; | ||
682 | for (i = start, len += start; i < len; i++) { | ||
683 | u32 rgb = ((u32)lut->r[i]) | | ||
684 | ((u32)lut->g[i]<<8) | | ||
685 | ((u32)lut->b[i]<<16); | ||
686 | tegra_dc_writel(dc, rgb, DC_WIN_COLOR_PALETTE(i)); | ||
687 | } | ||
688 | } | ||
689 | |||
690 | int tegra_dc_update_lut(struct tegra_dc *dc, int win_idx, int start, int len) | ||
691 | { | ||
692 | mutex_lock(&dc->lock); | ||
693 | |||
694 | if (!dc->enabled) { | ||
695 | mutex_unlock(&dc->lock); | ||
696 | return -EFAULT; | ||
697 | } | ||
698 | |||
699 | tegra_dc_writel(dc, WINDOW_A_SELECT << win_idx, | ||
700 | DC_CMD_DISPLAY_WINDOW_HEADER); | ||
701 | |||
702 | tegra_dc_set_lut(dc, &dc->windows[win_idx].lut, start, len); | ||
703 | |||
704 | mutex_unlock(&dc->lock); | ||
705 | |||
706 | return 0; | ||
707 | } | ||
708 | EXPORT_SYMBOL(tegra_dc_update_lut); | ||
709 | |||
668 | static void tegra_dc_set_scaling_filter(struct tegra_dc *dc) | 710 | static void tegra_dc_set_scaling_filter(struct tegra_dc *dc) |
669 | { | 711 | { |
670 | unsigned i; | 712 | unsigned i; |
@@ -1075,7 +1117,7 @@ int tegra_dc_update_windows(struct tegra_dc_win *windows[], int n) | |||
1075 | DC_WIN_BUFFER_ADDR_MODE_LINEAR_UV, | 1117 | DC_WIN_BUFFER_ADDR_MODE_LINEAR_UV, |
1076 | DC_WIN_BUFFER_ADDR_MODE); | 1118 | DC_WIN_BUFFER_ADDR_MODE); |
1077 | 1119 | ||
1078 | val = WIN_ENABLE; | 1120 | val = WIN_ENABLE | CP_ENABLE; |
1079 | if (yuvp) | 1121 | if (yuvp) |
1080 | val |= CSC_ENABLE; | 1122 | val |= CSC_ENABLE; |
1081 | else if (tegra_dc_fmt_bpp(win->fmt) < 24) | 1123 | else if (tegra_dc_fmt_bpp(win->fmt) < 24) |
@@ -2155,6 +2197,8 @@ static void tegra_dc_init(struct tegra_dc *dc) | |||
2155 | DC_CMD_DISPLAY_WINDOW_HEADER); | 2197 | DC_CMD_DISPLAY_WINDOW_HEADER); |
2156 | tegra_dc_init_csc_defaults(&dc->windows[i].csc); | 2198 | tegra_dc_init_csc_defaults(&dc->windows[i].csc); |
2157 | tegra_dc_set_csc(dc, &dc->windows[i].csc); | 2199 | tegra_dc_set_csc(dc, &dc->windows[i].csc); |
2200 | tegra_dc_init_lut_defaults(&dc->windows[i].lut); | ||
2201 | tegra_dc_set_lut(dc, &dc->windows[i].lut, 0, 256); | ||
2158 | tegra_dc_set_scaling_filter(dc); | 2202 | tegra_dc_set_scaling_filter(dc); |
2159 | } | 2203 | } |
2160 | 2204 | ||
diff --git a/drivers/video/tegra/dc/ext/dev.c b/drivers/video/tegra/dc/ext/dev.c index 4e631d112..c0429b37f 100644 --- a/drivers/video/tegra/dc/ext/dev.c +++ b/drivers/video/tegra/dc/ext/dev.c | |||
@@ -521,6 +521,67 @@ static int tegra_dc_ext_set_csc(struct tegra_dc_ext_user *user, | |||
521 | return 0; | 521 | return 0; |
522 | } | 522 | } |
523 | 523 | ||
524 | static int set_lut_channel(u16 *channel_from_user, | ||
525 | u8 *channel_to, | ||
526 | u32 start, | ||
527 | u32 len) | ||
528 | { | ||
529 | int i; | ||
530 | u16 lut16bpp[256]; | ||
531 | |||
532 | if (copy_from_user(lut16bpp, channel_from_user, len<<1)) | ||
533 | return 1; | ||
534 | |||
535 | for (i=0; i<len; i++) | ||
536 | channel_to[start+i] = lut16bpp[i]>>8; | ||
537 | |||
538 | return 0; | ||
539 | } | ||
540 | |||
541 | static int tegra_dc_ext_set_lut(struct tegra_dc_ext_user *user, | ||
542 | struct tegra_dc_ext_lut *new_lut) | ||
543 | { | ||
544 | int err; | ||
545 | unsigned int index = new_lut->win_index; | ||
546 | u32 start = new_lut->start; | ||
547 | u32 len = new_lut->len; | ||
548 | |||
549 | struct tegra_dc *dc = user->ext->dc; | ||
550 | struct tegra_dc_ext_win *ext_win; | ||
551 | struct tegra_dc_lut *lut; | ||
552 | |||
553 | if (index >= DC_N_WINDOWS) | ||
554 | return -EINVAL; | ||
555 | |||
556 | if ((start >= 256) || (len > 256) || ((start + len) > 256)) | ||
557 | return -EINVAL; | ||
558 | |||
559 | ext_win = &user->ext->win[index]; | ||
560 | lut = &dc->windows[index].lut; | ||
561 | |||
562 | mutex_lock(&ext_win->lock); | ||
563 | |||
564 | if (ext_win->user != user) { | ||
565 | mutex_unlock(&ext_win->lock); | ||
566 | return -EACCES; | ||
567 | } | ||
568 | |||
569 | err = set_lut_channel(new_lut->r, lut->r, start, len) | | ||
570 | set_lut_channel(new_lut->g, lut->g, start, len) | | ||
571 | set_lut_channel(new_lut->b, lut->b, start, len); | ||
572 | |||
573 | if (err) { | ||
574 | mutex_unlock(&ext_win->lock); | ||
575 | return -EFAULT; | ||
576 | } | ||
577 | |||
578 | tegra_dc_update_lut(dc, index, start, len); | ||
579 | |||
580 | mutex_unlock(&ext_win->lock); | ||
581 | |||
582 | return 0; | ||
583 | } | ||
584 | |||
524 | static u32 tegra_dc_ext_get_vblank_syncpt(struct tegra_dc_ext_user *user) | 585 | static u32 tegra_dc_ext_get_vblank_syncpt(struct tegra_dc_ext_user *user) |
525 | { | 586 | { |
526 | struct tegra_dc *dc = user->ext->dc; | 587 | struct tegra_dc *dc = user->ext->dc; |
@@ -628,6 +689,16 @@ static long tegra_dc_ioctl(struct file *filp, unsigned int cmd, | |||
628 | return ret; | 689 | return ret; |
629 | } | 690 | } |
630 | 691 | ||
692 | case TEGRA_DC_EXT_SET_LUT: | ||
693 | { | ||
694 | struct tegra_dc_ext_lut args; | ||
695 | |||
696 | if (copy_from_user(&args, user_arg, sizeof(args))) | ||
697 | return -EFAULT; | ||
698 | |||
699 | return tegra_dc_ext_set_lut(user, &args); | ||
700 | } | ||
701 | |||
631 | default: | 702 | default: |
632 | return -EINVAL; | 703 | return -EINVAL; |
633 | } | 704 | } |
diff --git a/include/video/tegra_dc_ext.h b/include/video/tegra_dc_ext.h index bdfebaeb3..77d4e62d7 100644 --- a/include/video/tegra_dc_ext.h +++ b/include/video/tegra_dc_ext.h | |||
@@ -164,6 +164,29 @@ struct tegra_dc_ext_csc { | |||
164 | __u16 kvb; /* s.2.8 */ | 164 | __u16 kvb; /* s.2.8 */ |
165 | }; | 165 | }; |
166 | 166 | ||
167 | /* | ||
168 | * RGB Lookup table | ||
169 | * | ||
170 | * In true-color and YUV modes this is used for post-CSC RGB->RGB lookup, i.e. | ||
171 | * gamma-correction. In palette-indexed RGB modes, this table designates the | ||
172 | * mode's color palette. | ||
173 | * | ||
174 | * To convert 8-bit per channel RGB values to 16-bit, duplicate the 8 bits | ||
175 | * in low and high byte, e.g. r=r|(r<<8) | ||
176 | * | ||
177 | * Current Tegra DC hardware supports 8-bit per channel to 8-bit per channel, | ||
178 | * and each hardware window (overlay) uses its own lookup table. | ||
179 | * | ||
180 | */ | ||
181 | struct tegra_dc_ext_lut { | ||
182 | __u32 win_index; /* window index to set lut for */ | ||
183 | __u32 start; /* start index to update lut from */ | ||
184 | __u32 len; /* number of valid lut entries */ | ||
185 | __u16* r; /* array of size 16-bit red values */ | ||
186 | __u16* g; /* array of size 16-bit green values */ | ||
187 | __u16* b; /* array of size 16-bit blue values */ | ||
188 | }; | ||
189 | |||
167 | 190 | ||
168 | #define TEGRA_DC_EXT_FLAGS_ENABLED 1 | 191 | #define TEGRA_DC_EXT_FLAGS_ENABLED 1 |
169 | struct tegra_dc_ext_status { | 192 | struct tegra_dc_ext_status { |
@@ -205,6 +228,8 @@ struct tegra_dc_ext_status { | |||
205 | #define TEGRA_DC_EXT_GET_VBLANK_SYNCPT \ | 228 | #define TEGRA_DC_EXT_GET_VBLANK_SYNCPT \ |
206 | _IOR('D', 0x09, __u32) | 229 | _IOR('D', 0x09, __u32) |
207 | 230 | ||
231 | #define TEGRA_DC_EXT_SET_LUT \ | ||
232 | _IOR('D', 0x0A, struct tegra_dc_ext_lut) | ||
208 | 233 | ||
209 | enum tegra_dc_ext_control_output_type { | 234 | enum tegra_dc_ext_control_output_type { |
210 | TEGRA_DC_EXT_DSI, | 235 | TEGRA_DC_EXT_DSI, |