aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu')
-rw-r--r--drivers/gpu/drm/omapdrm/dss/dispc.c203
-rw-r--r--drivers/gpu/drm/omapdrm/dss/dispc.h5
-rw-r--r--drivers/gpu/drm/omapdrm/dss/hdmi4.c3
-rw-r--r--drivers/gpu/drm/omapdrm/dss/hdmi5.c3
-rw-r--r--drivers/gpu/drm/omapdrm/dss/omapdss.h5
5 files changed, 197 insertions, 22 deletions
diff --git a/drivers/gpu/drm/omapdrm/dss/dispc.c b/drivers/gpu/drm/omapdrm/dss/dispc.c
index 0aecce2c6ba0..cdd227c8bed3 100644
--- a/drivers/gpu/drm/omapdrm/dss/dispc.c
+++ b/drivers/gpu/drm/omapdrm/dss/dispc.c
@@ -112,9 +112,12 @@ struct dispc_features {
112 * never both, we can just use this flag for now. 112 * never both, we can just use this flag for now.
113 */ 113 */
114 bool reverse_ilace_field_order:1; 114 bool reverse_ilace_field_order:1;
115
116 bool has_gamma_table:1;
115}; 117};
116 118
117#define DISPC_MAX_NR_FIFOS 5 119#define DISPC_MAX_NR_FIFOS 5
120#define DISPC_MAX_CHANNEL_GAMMA 4
118 121
119static struct { 122static struct {
120 struct platform_device *pdev; 123 struct platform_device *pdev;
@@ -134,6 +137,8 @@ static struct {
134 bool ctx_valid; 137 bool ctx_valid;
135 u32 ctx[DISPC_SZ_REGS / sizeof(u32)]; 138 u32 ctx[DISPC_SZ_REGS / sizeof(u32)];
136 139
140 u32 *gamma_table[DISPC_MAX_CHANNEL_GAMMA];
141
137 const struct dispc_features *feat; 142 const struct dispc_features *feat;
138 143
139 bool is_enabled; 144 bool is_enabled;
@@ -177,11 +182,19 @@ struct dispc_reg_field {
177 u8 low; 182 u8 low;
178}; 183};
179 184
185struct dispc_gamma_desc {
186 u32 len;
187 u32 bits;
188 u16 reg;
189 bool has_index;
190};
191
180static const struct { 192static const struct {
181 const char *name; 193 const char *name;
182 u32 vsync_irq; 194 u32 vsync_irq;
183 u32 framedone_irq; 195 u32 framedone_irq;
184 u32 sync_lost_irq; 196 u32 sync_lost_irq;
197 struct dispc_gamma_desc gamma;
185 struct dispc_reg_field reg_desc[DISPC_MGR_FLD_NUM]; 198 struct dispc_reg_field reg_desc[DISPC_MGR_FLD_NUM];
186} mgr_desc[] = { 199} mgr_desc[] = {
187 [OMAP_DSS_CHANNEL_LCD] = { 200 [OMAP_DSS_CHANNEL_LCD] = {
@@ -189,6 +202,12 @@ static const struct {
189 .vsync_irq = DISPC_IRQ_VSYNC, 202 .vsync_irq = DISPC_IRQ_VSYNC,
190 .framedone_irq = DISPC_IRQ_FRAMEDONE, 203 .framedone_irq = DISPC_IRQ_FRAMEDONE,
191 .sync_lost_irq = DISPC_IRQ_SYNC_LOST, 204 .sync_lost_irq = DISPC_IRQ_SYNC_LOST,
205 .gamma = {
206 .len = 256,
207 .bits = 8,
208 .reg = DISPC_GAMMA_TABLE0,
209 .has_index = true,
210 },
192 .reg_desc = { 211 .reg_desc = {
193 [DISPC_MGR_FLD_ENABLE] = { DISPC_CONTROL, 0, 0 }, 212 [DISPC_MGR_FLD_ENABLE] = { DISPC_CONTROL, 0, 0 },
194 [DISPC_MGR_FLD_STNTFT] = { DISPC_CONTROL, 3, 3 }, 213 [DISPC_MGR_FLD_STNTFT] = { DISPC_CONTROL, 3, 3 },
@@ -206,6 +225,12 @@ static const struct {
206 .vsync_irq = DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_EVSYNC_EVEN, 225 .vsync_irq = DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_EVSYNC_EVEN,
207 .framedone_irq = DISPC_IRQ_FRAMEDONETV, 226 .framedone_irq = DISPC_IRQ_FRAMEDONETV,
208 .sync_lost_irq = DISPC_IRQ_SYNC_LOST_DIGIT, 227 .sync_lost_irq = DISPC_IRQ_SYNC_LOST_DIGIT,
228 .gamma = {
229 .len = 1024,
230 .bits = 10,
231 .reg = DISPC_GAMMA_TABLE2,
232 .has_index = false,
233 },
209 .reg_desc = { 234 .reg_desc = {
210 [DISPC_MGR_FLD_ENABLE] = { DISPC_CONTROL, 1, 1 }, 235 [DISPC_MGR_FLD_ENABLE] = { DISPC_CONTROL, 1, 1 },
211 [DISPC_MGR_FLD_STNTFT] = { }, 236 [DISPC_MGR_FLD_STNTFT] = { },
@@ -223,6 +248,12 @@ static const struct {
223 .vsync_irq = DISPC_IRQ_VSYNC2, 248 .vsync_irq = DISPC_IRQ_VSYNC2,
224 .framedone_irq = DISPC_IRQ_FRAMEDONE2, 249 .framedone_irq = DISPC_IRQ_FRAMEDONE2,
225 .sync_lost_irq = DISPC_IRQ_SYNC_LOST2, 250 .sync_lost_irq = DISPC_IRQ_SYNC_LOST2,
251 .gamma = {
252 .len = 256,
253 .bits = 8,
254 .reg = DISPC_GAMMA_TABLE1,
255 .has_index = true,
256 },
226 .reg_desc = { 257 .reg_desc = {
227 [DISPC_MGR_FLD_ENABLE] = { DISPC_CONTROL2, 0, 0 }, 258 [DISPC_MGR_FLD_ENABLE] = { DISPC_CONTROL2, 0, 0 },
228 [DISPC_MGR_FLD_STNTFT] = { DISPC_CONTROL2, 3, 3 }, 259 [DISPC_MGR_FLD_STNTFT] = { DISPC_CONTROL2, 3, 3 },
@@ -240,6 +271,12 @@ static const struct {
240 .vsync_irq = DISPC_IRQ_VSYNC3, 271 .vsync_irq = DISPC_IRQ_VSYNC3,
241 .framedone_irq = DISPC_IRQ_FRAMEDONE3, 272 .framedone_irq = DISPC_IRQ_FRAMEDONE3,
242 .sync_lost_irq = DISPC_IRQ_SYNC_LOST3, 273 .sync_lost_irq = DISPC_IRQ_SYNC_LOST3,
274 .gamma = {
275 .len = 256,
276 .bits = 8,
277 .reg = DISPC_GAMMA_TABLE3,
278 .has_index = true,
279 },
243 .reg_desc = { 280 .reg_desc = {
244 [DISPC_MGR_FLD_ENABLE] = { DISPC_CONTROL3, 0, 0 }, 281 [DISPC_MGR_FLD_ENABLE] = { DISPC_CONTROL3, 0, 0 },
245 [DISPC_MGR_FLD_STNTFT] = { DISPC_CONTROL3, 3, 3 }, 282 [DISPC_MGR_FLD_STNTFT] = { DISPC_CONTROL3, 3, 3 },
@@ -1083,20 +1120,6 @@ static u32 dispc_ovl_get_burst_size(enum omap_plane plane)
1083 return unit * 8; 1120 return unit * 8;
1084} 1121}
1085 1122
1086void dispc_enable_gamma_table(bool enable)
1087{
1088 /*
1089 * This is partially implemented to support only disabling of
1090 * the gamma table.
1091 */
1092 if (enable) {
1093 DSSWARN("Gamma table enabling for TV not yet supported");
1094 return;
1095 }
1096
1097 REG_FLD_MOD(DISPC_CONFIG, enable, 9, 9);
1098}
1099
1100static void dispc_mgr_enable_cpr(enum omap_channel channel, bool enable) 1123static void dispc_mgr_enable_cpr(enum omap_channel channel, bool enable)
1101{ 1124{
1102 if (channel == OMAP_DSS_CHANNEL_DIGIT) 1125 if (channel == OMAP_DSS_CHANNEL_DIGIT)
@@ -3790,6 +3813,139 @@ void dispc_disable_sidle(void)
3790 REG_FLD_MOD(DISPC_SYSCONFIG, 1, 4, 3); /* SIDLEMODE: no idle */ 3813 REG_FLD_MOD(DISPC_SYSCONFIG, 1, 4, 3); /* SIDLEMODE: no idle */
3791} 3814}
3792 3815
3816u32 dispc_mgr_gamma_size(enum omap_channel channel)
3817{
3818 const struct dispc_gamma_desc *gdesc = &mgr_desc[channel].gamma;
3819
3820 if (!dispc.feat->has_gamma_table)
3821 return 0;
3822
3823 return gdesc->len;
3824}
3825EXPORT_SYMBOL(dispc_mgr_gamma_size);
3826
3827static void dispc_mgr_write_gamma_table(enum omap_channel channel)
3828{
3829 const struct dispc_gamma_desc *gdesc = &mgr_desc[channel].gamma;
3830 u32 *table = dispc.gamma_table[channel];
3831 unsigned int i;
3832
3833 DSSDBG("%s: channel %d\n", __func__, channel);
3834
3835 for (i = 0; i < gdesc->len; ++i) {
3836 u32 v = table[i];
3837
3838 if (gdesc->has_index)
3839 v |= i << 24;
3840 else if (i == 0)
3841 v |= 1 << 31;
3842
3843 dispc_write_reg(gdesc->reg, v);
3844 }
3845}
3846
3847static void dispc_restore_gamma_tables(void)
3848{
3849 DSSDBG("%s()\n", __func__);
3850
3851 if (!dispc.feat->has_gamma_table)
3852 return;
3853
3854 dispc_mgr_write_gamma_table(OMAP_DSS_CHANNEL_LCD);
3855
3856 dispc_mgr_write_gamma_table(OMAP_DSS_CHANNEL_DIGIT);
3857
3858 if (dss_has_feature(FEAT_MGR_LCD2))
3859 dispc_mgr_write_gamma_table(OMAP_DSS_CHANNEL_LCD2);
3860
3861 if (dss_has_feature(FEAT_MGR_LCD3))
3862 dispc_mgr_write_gamma_table(OMAP_DSS_CHANNEL_LCD3);
3863}
3864
3865static const struct drm_color_lut dispc_mgr_gamma_default_lut[] = {
3866 { .red = 0, .green = 0, .blue = 0, },
3867 { .red = U16_MAX, .green = U16_MAX, .blue = U16_MAX, },
3868};
3869
3870void dispc_mgr_set_gamma(enum omap_channel channel,
3871 const struct drm_color_lut *lut,
3872 unsigned int length)
3873{
3874 const struct dispc_gamma_desc *gdesc = &mgr_desc[channel].gamma;
3875 u32 *table = dispc.gamma_table[channel];
3876 uint i;
3877
3878 DSSDBG("%s: channel %d, lut len %u, hw len %u\n", __func__,
3879 channel, length, gdesc->len);
3880
3881 if (!dispc.feat->has_gamma_table)
3882 return;
3883
3884 if (lut == NULL || length < 2) {
3885 lut = dispc_mgr_gamma_default_lut;
3886 length = ARRAY_SIZE(dispc_mgr_gamma_default_lut);
3887 }
3888
3889 for (i = 0; i < length - 1; ++i) {
3890 uint first = i * (gdesc->len - 1) / (length - 1);
3891 uint last = (i + 1) * (gdesc->len - 1) / (length - 1);
3892 uint w = last - first;
3893 u16 r, g, b;
3894 uint j;
3895
3896 if (w == 0)
3897 continue;
3898
3899 for (j = 0; j <= w; j++) {
3900 r = (lut[i].red * (w - j) + lut[i+1].red * j) / w;
3901 g = (lut[i].green * (w - j) + lut[i+1].green * j) / w;
3902 b = (lut[i].blue * (w - j) + lut[i+1].blue * j) / w;
3903
3904 r >>= 16 - gdesc->bits;
3905 g >>= 16 - gdesc->bits;
3906 b >>= 16 - gdesc->bits;
3907
3908 table[first + j] = (r << (gdesc->bits * 2)) |
3909 (g << gdesc->bits) | b;
3910 }
3911 }
3912
3913 if (dispc.is_enabled)
3914 dispc_mgr_write_gamma_table(channel);
3915}
3916EXPORT_SYMBOL(dispc_mgr_set_gamma);
3917
3918static int dispc_init_gamma_tables(void)
3919{
3920 int channel;
3921
3922 if (!dispc.feat->has_gamma_table)
3923 return 0;
3924
3925 for (channel = 0; channel < ARRAY_SIZE(dispc.gamma_table); channel++) {
3926 const struct dispc_gamma_desc *gdesc = &mgr_desc[channel].gamma;
3927 u32 *gt;
3928
3929 if (channel == OMAP_DSS_CHANNEL_LCD2 &&
3930 !dss_has_feature(FEAT_MGR_LCD2))
3931 continue;
3932
3933 if (channel == OMAP_DSS_CHANNEL_LCD3 &&
3934 !dss_has_feature(FEAT_MGR_LCD3))
3935 continue;
3936
3937 gt = devm_kmalloc_array(&dispc.pdev->dev, gdesc->len,
3938 sizeof(u32), GFP_KERNEL);
3939 if (!gt)
3940 return -ENOMEM;
3941
3942 dispc.gamma_table[channel] = gt;
3943
3944 dispc_mgr_set_gamma(channel, NULL, 0);
3945 }
3946 return 0;
3947}
3948
3793static void _omap_dispc_initial_config(void) 3949static void _omap_dispc_initial_config(void)
3794{ 3950{
3795 u32 l; 3951 u32 l;
@@ -3805,8 +3961,15 @@ static void _omap_dispc_initial_config(void)
3805 dispc.core_clk_rate = dispc_fclk_rate(); 3961 dispc.core_clk_rate = dispc_fclk_rate();
3806 } 3962 }
3807 3963
3808 /* FUNCGATED */ 3964 /* Use gamma table mode, instead of palette mode */
3809 if (dss_has_feature(FEAT_FUNCGATED)) 3965 if (dispc.feat->has_gamma_table)
3966 REG_FLD_MOD(DISPC_CONFIG, 1, 3, 3);
3967
3968 /* For older DSS versions (FEAT_FUNCGATED) this enables
3969 * func-clock auto-gating. For newer versions
3970 * (dispc.feat->has_gamma_table) this enables tv-out gamma tables.
3971 */
3972 if (dss_has_feature(FEAT_FUNCGATED) || dispc.feat->has_gamma_table)
3810 REG_FLD_MOD(DISPC_CONFIG, 1, 9, 9); 3973 REG_FLD_MOD(DISPC_CONFIG, 1, 9, 9);
3811 3974
3812 dispc_setup_color_conv_coef(); 3975 dispc_setup_color_conv_coef();
@@ -3910,6 +4073,7 @@ static const struct dispc_features omap44xx_dispc_feats = {
3910 .has_writeback = true, 4073 .has_writeback = true,
3911 .supports_double_pixel = true, 4074 .supports_double_pixel = true,
3912 .reverse_ilace_field_order = true, 4075 .reverse_ilace_field_order = true,
4076 .has_gamma_table = true,
3913}; 4077};
3914 4078
3915static const struct dispc_features omap54xx_dispc_feats = { 4079static const struct dispc_features omap54xx_dispc_feats = {
@@ -3935,6 +4099,7 @@ static const struct dispc_features omap54xx_dispc_feats = {
3935 .has_writeback = true, 4099 .has_writeback = true,
3936 .supports_double_pixel = true, 4100 .supports_double_pixel = true,
3937 .reverse_ilace_field_order = true, 4101 .reverse_ilace_field_order = true,
4102 .has_gamma_table = true,
3938}; 4103};
3939 4104
3940static int dispc_init_features(struct platform_device *pdev) 4105static int dispc_init_features(struct platform_device *pdev)
@@ -4076,6 +4241,10 @@ static int dispc_bind(struct device *dev, struct device *master, void *data)
4076 } 4241 }
4077 } 4242 }
4078 4243
4244 r = dispc_init_gamma_tables();
4245 if (r)
4246 return r;
4247
4079 pm_runtime_enable(&pdev->dev); 4248 pm_runtime_enable(&pdev->dev);
4080 4249
4081 r = dispc_runtime_get(); 4250 r = dispc_runtime_get();
@@ -4146,6 +4315,8 @@ static int dispc_runtime_resume(struct device *dev)
4146 _omap_dispc_initial_config(); 4315 _omap_dispc_initial_config();
4147 4316
4148 dispc_restore_context(); 4317 dispc_restore_context();
4318
4319 dispc_restore_gamma_tables();
4149 } 4320 }
4150 4321
4151 dispc.is_enabled = true; 4322 dispc.is_enabled = true;
diff --git a/drivers/gpu/drm/omapdrm/dss/dispc.h b/drivers/gpu/drm/omapdrm/dss/dispc.h
index 483744223dd1..bc1d8126ee87 100644
--- a/drivers/gpu/drm/omapdrm/dss/dispc.h
+++ b/drivers/gpu/drm/omapdrm/dss/dispc.h
@@ -42,6 +42,11 @@
42#define DISPC_MSTANDBY_CTRL 0x0858 42#define DISPC_MSTANDBY_CTRL 0x0858
43#define DISPC_GLOBAL_MFLAG_ATTRIBUTE 0x085C 43#define DISPC_GLOBAL_MFLAG_ATTRIBUTE 0x085C
44 44
45#define DISPC_GAMMA_TABLE0 0x0630
46#define DISPC_GAMMA_TABLE1 0x0634
47#define DISPC_GAMMA_TABLE2 0x0638
48#define DISPC_GAMMA_TABLE3 0x0850
49
45/* DISPC overlay registers */ 50/* DISPC overlay registers */
46#define DISPC_OVL_BA0(n) (DISPC_OVL_BASE(n) + \ 51#define DISPC_OVL_BA0(n) (DISPC_OVL_BASE(n) + \
47 DISPC_BA0_OFFSET(n)) 52 DISPC_BA0_OFFSET(n))
diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi4.c b/drivers/gpu/drm/omapdrm/dss/hdmi4.c
index 2cfd70dee1b2..cbd28dfdb86a 100644
--- a/drivers/gpu/drm/omapdrm/dss/hdmi4.c
+++ b/drivers/gpu/drm/omapdrm/dss/hdmi4.c
@@ -208,9 +208,6 @@ static int hdmi_power_on_full(struct omap_dss_device *dssdev)
208 208
209 hdmi4_configure(&hdmi.core, &hdmi.wp, &hdmi.cfg); 209 hdmi4_configure(&hdmi.core, &hdmi.wp, &hdmi.cfg);
210 210
211 /* bypass TV gamma table */
212 dispc_enable_gamma_table(0);
213
214 /* tv size */ 211 /* tv size */
215 dss_mgr_set_timings(channel, p); 212 dss_mgr_set_timings(channel, p);
216 213
diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi5.c b/drivers/gpu/drm/omapdrm/dss/hdmi5.c
index d4892d84424e..061f9bab4c9b 100644
--- a/drivers/gpu/drm/omapdrm/dss/hdmi5.c
+++ b/drivers/gpu/drm/omapdrm/dss/hdmi5.c
@@ -226,9 +226,6 @@ static int hdmi_power_on_full(struct omap_dss_device *dssdev)
226 226
227 hdmi5_configure(&hdmi.core, &hdmi.wp, &hdmi.cfg); 227 hdmi5_configure(&hdmi.core, &hdmi.wp, &hdmi.cfg);
228 228
229 /* bypass TV gamma table */
230 dispc_enable_gamma_table(0);
231
232 /* tv size */ 229 /* tv size */
233 dss_mgr_set_timings(channel, p); 230 dss_mgr_set_timings(channel, p);
234 231
diff --git a/drivers/gpu/drm/omapdrm/dss/omapdss.h b/drivers/gpu/drm/omapdrm/dss/omapdss.h
index 9263283952b9..6eaf1adbd606 100644
--- a/drivers/gpu/drm/omapdrm/dss/omapdss.h
+++ b/drivers/gpu/drm/omapdrm/dss/omapdss.h
@@ -24,6 +24,7 @@
24#include <linux/interrupt.h> 24#include <linux/interrupt.h>
25#include <video/videomode.h> 25#include <video/videomode.h>
26#include <linux/platform_data/omapdss.h> 26#include <linux/platform_data/omapdss.h>
27#include <uapi/drm/drm_mode.h>
27 28
28#define DISPC_IRQ_FRAMEDONE (1 << 0) 29#define DISPC_IRQ_FRAMEDONE (1 << 0)
29#define DISPC_IRQ_VSYNC (1 << 1) 30#define DISPC_IRQ_VSYNC (1 << 1)
@@ -908,6 +909,10 @@ void dispc_mgr_set_timings(enum omap_channel channel,
908 const struct omap_video_timings *timings); 909 const struct omap_video_timings *timings);
909void dispc_mgr_setup(enum omap_channel channel, 910void dispc_mgr_setup(enum omap_channel channel,
910 const struct omap_overlay_manager_info *info); 911 const struct omap_overlay_manager_info *info);
912u32 dispc_mgr_gamma_size(enum omap_channel channel);
913void dispc_mgr_set_gamma(enum omap_channel channel,
914 const struct drm_color_lut *lut,
915 unsigned int length);
911 916
912int dispc_ovl_enable(enum omap_plane plane, bool enable); 917int dispc_ovl_enable(enum omap_plane plane, bool enable);
913bool dispc_ovl_enabled(enum omap_plane plane); 918bool dispc_ovl_enabled(enum omap_plane plane);