aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJyri Sarha <jsarha@ti.com>2016-06-07 08:09:15 -0400
committerTomi Valkeinen <tomi.valkeinen@ti.com>2016-06-07 10:10:49 -0400
commitacc3a231d3d145b23d1f975b9be89b7cfb09885b (patch)
tree0c8ff7ff364413e528a1ffb4cdf08263aacd7576
parentf8ed34ac7b453296cf36d6eb7ae911de353e1351 (diff)
drm/omapdrm: Add gamma table support to DSS dispc
Add gamma table support to DSS dispc. DSS driver initializes the default gamma table at component bind time and holds a copy of all gamma tables in its internal data structure. Each call to dispc_mgr_set_gamma() updates the internal table and triggers write to the HW, if it is enabled. The tables are restored to HW in PM resume callback. The drivers internal data structure match the HW tables in size and in number of significant bits per color component. The dispc_mgr_set_gamma() converts the size of any given table for the internal data structure using linear interpolation. Default gamma table is restored if NULL is given in place of gamma lut. dispc_mgr_gamma_size() gives HW gamma table size for the channel and returns 0 if gamma table is not supported by the HW or the DSS driver. Signed-off-by: Jyri Sarha <jsarha@ti.com> Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
-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);