aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/omapdrm
diff options
context:
space:
mode:
authorJyri Sarha <jsarha@ti.com>2016-06-07 08:09:16 -0400
committerTomi Valkeinen <tomi.valkeinen@ti.com>2016-06-07 10:10:49 -0400
commitfbff010bd0b4492af4ba85093602d8bd91752453 (patch)
tree44b2930b345f28bcc51ca58908270c6bd3970fc4 /drivers/gpu/drm/omapdrm
parentacc3a231d3d145b23d1f975b9be89b7cfb09885b (diff)
drm/omapdrm: Workaround for errata i734 (LCD1 Gamma) in DSS dispc
Workaround for errata i734 in DSS dispc - LCD1 Gamma Correction Is Not Working When GFX Pipe Is Disabled For gamma tables to work on LCD1 the GFX plane has to be used at least once after DSS HW has come out of reset. The workaround sets up a minimal LCD setup with GFX plane and waits for one vertical sync irq before disabling the setup and continuing with the context restore. The physical outputs are gated during the operation. For details see: OMAP543x Multimedia Device Silicon Revision 2.0 Silicon Errata Literature Number: SWPZ037E Or some other relevant errata document for the DSS IP version. Signed-off-by: Jyri Sarha <jsarha@ti.com> Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
Diffstat (limited to 'drivers/gpu/drm/omapdrm')
-rw-r--r--drivers/gpu/drm/omapdrm/dss/dispc.c174
1 files changed, 174 insertions, 0 deletions
diff --git a/drivers/gpu/drm/omapdrm/dss/dispc.c b/drivers/gpu/drm/omapdrm/dss/dispc.c
index cdd227c8bed3..535240fba671 100644
--- a/drivers/gpu/drm/omapdrm/dss/dispc.c
+++ b/drivers/gpu/drm/omapdrm/dss/dispc.c
@@ -114,6 +114,8 @@ struct dispc_features {
114 bool reverse_ilace_field_order:1; 114 bool reverse_ilace_field_order:1;
115 115
116 bool has_gamma_table:1; 116 bool has_gamma_table:1;
117
118 bool has_gamma_i734_bug:1;
117}; 119};
118 120
119#define DISPC_MAX_NR_FIFOS 5 121#define DISPC_MAX_NR_FIFOS 5
@@ -4074,6 +4076,7 @@ static const struct dispc_features omap44xx_dispc_feats = {
4074 .supports_double_pixel = true, 4076 .supports_double_pixel = true,
4075 .reverse_ilace_field_order = true, 4077 .reverse_ilace_field_order = true,
4076 .has_gamma_table = true, 4078 .has_gamma_table = true,
4079 .has_gamma_i734_bug = true,
4077}; 4080};
4078 4081
4079static const struct dispc_features omap54xx_dispc_feats = { 4082static const struct dispc_features omap54xx_dispc_feats = {
@@ -4100,6 +4103,7 @@ static const struct dispc_features omap54xx_dispc_feats = {
4100 .supports_double_pixel = true, 4103 .supports_double_pixel = true,
4101 .reverse_ilace_field_order = true, 4104 .reverse_ilace_field_order = true,
4102 .has_gamma_table = true, 4105 .has_gamma_table = true,
4106 .has_gamma_i734_bug = true,
4103}; 4107};
4104 4108
4105static int dispc_init_features(struct platform_device *pdev) 4109static int dispc_init_features(struct platform_device *pdev)
@@ -4191,6 +4195,168 @@ void dispc_free_irq(void *dev_id)
4191} 4195}
4192EXPORT_SYMBOL(dispc_free_irq); 4196EXPORT_SYMBOL(dispc_free_irq);
4193 4197
4198/*
4199 * Workaround for errata i734 in DSS dispc
4200 * - LCD1 Gamma Correction Is Not Working When GFX Pipe Is Disabled
4201 *
4202 * For gamma tables to work on LCD1 the GFX plane has to be used at
4203 * least once after DSS HW has come out of reset. The workaround
4204 * sets up a minimal LCD setup with GFX plane and waits for one
4205 * vertical sync irq before disabling the setup and continuing with
4206 * the context restore. The physical outputs are gated during the
4207 * operation. This workaround requires that gamma table's LOADMODE
4208 * is set to 0x2 in DISPC_CONTROL1 register.
4209 *
4210 * For details see:
4211 * OMAP543x Multimedia Device Silicon Revision 2.0 Silicon Errata
4212 * Literature Number: SWPZ037E
4213 * Or some other relevant errata document for the DSS IP version.
4214 */
4215
4216static const struct dispc_errata_i734_data {
4217 struct omap_video_timings timings;
4218 struct omap_overlay_info ovli;
4219 struct omap_overlay_manager_info mgri;
4220 struct dss_lcd_mgr_config lcd_conf;
4221} i734 = {
4222 .timings = {
4223 .x_res = 8, .y_res = 1,
4224 .pixelclock = 16000000,
4225 .hsw = 8, .hfp = 4, .hbp = 4,
4226 .vsw = 1, .vfp = 1, .vbp = 1,
4227 .vsync_level = OMAPDSS_SIG_ACTIVE_LOW,
4228 .hsync_level = OMAPDSS_SIG_ACTIVE_LOW,
4229 .interlace = false,
4230 .data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE,
4231 .de_level = OMAPDSS_SIG_ACTIVE_HIGH,
4232 .sync_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE,
4233 .double_pixel = false,
4234 },
4235 .ovli = {
4236 .screen_width = 1,
4237 .width = 1, .height = 1,
4238 .color_mode = OMAP_DSS_COLOR_RGB24U,
4239 .rotation = OMAP_DSS_ROT_0,
4240 .rotation_type = OMAP_DSS_ROT_DMA,
4241 .mirror = 0,
4242 .pos_x = 0, .pos_y = 0,
4243 .out_width = 0, .out_height = 0,
4244 .global_alpha = 0xff,
4245 .pre_mult_alpha = 0,
4246 .zorder = 0,
4247 },
4248 .mgri = {
4249 .default_color = 0,
4250 .trans_enabled = false,
4251 .partial_alpha_enabled = false,
4252 .cpr_enable = false,
4253 },
4254 .lcd_conf = {
4255 .io_pad_mode = DSS_IO_PAD_MODE_BYPASS,
4256 .stallmode = false,
4257 .fifohandcheck = false,
4258 .clock_info = {
4259 .lck_div = 1,
4260 .pck_div = 2,
4261 },
4262 .video_port_width = 24,
4263 .lcden_sig_polarity = 0,
4264 },
4265};
4266
4267static struct i734_buf {
4268 size_t size;
4269 dma_addr_t paddr;
4270 void *vaddr;
4271} i734_buf;
4272
4273static int dispc_errata_i734_wa_init(void)
4274{
4275 if (!dispc.feat->has_gamma_i734_bug)
4276 return 0;
4277
4278 i734_buf.size = i734.ovli.width * i734.ovli.height *
4279 color_mode_to_bpp(i734.ovli.color_mode) / 8;
4280
4281 i734_buf.vaddr = dma_alloc_writecombine(&dispc.pdev->dev, i734_buf.size,
4282 &i734_buf.paddr, GFP_KERNEL);
4283 if (!i734_buf.vaddr) {
4284 dev_err(&dispc.pdev->dev, "%s: dma_alloc_writecombine failed",
4285 __func__);
4286 return -ENOMEM;
4287 }
4288
4289 return 0;
4290}
4291
4292static void dispc_errata_i734_wa_fini(void)
4293{
4294 if (!dispc.feat->has_gamma_i734_bug)
4295 return;
4296
4297 dma_free_writecombine(&dispc.pdev->dev, i734_buf.size, i734_buf.vaddr,
4298 i734_buf.paddr);
4299}
4300
4301static void dispc_errata_i734_wa(void)
4302{
4303 u32 framedone_irq = dispc_mgr_get_framedone_irq(OMAP_DSS_CHANNEL_LCD);
4304 struct omap_overlay_info ovli;
4305 struct dss_lcd_mgr_config lcd_conf;
4306 u32 gatestate;
4307 unsigned int count;
4308
4309 if (!dispc.feat->has_gamma_i734_bug)
4310 return;
4311
4312 gatestate = REG_GET(DISPC_CONFIG, 8, 4);
4313
4314 ovli = i734.ovli;
4315 ovli.paddr = i734_buf.paddr;
4316 lcd_conf = i734.lcd_conf;
4317
4318 /* Gate all LCD1 outputs */
4319 REG_FLD_MOD(DISPC_CONFIG, 0x1f, 8, 4);
4320
4321 /* Setup and enable GFX plane */
4322 dispc_ovl_set_channel_out(OMAP_DSS_GFX, OMAP_DSS_CHANNEL_LCD);
4323 dispc_ovl_setup(OMAP_DSS_GFX, &ovli, false, &i734.timings, false);
4324 dispc_ovl_enable(OMAP_DSS_GFX, true);
4325
4326 /* Set up and enable display manager for LCD1 */
4327 dispc_mgr_setup(OMAP_DSS_CHANNEL_LCD, &i734.mgri);
4328 dispc_calc_clock_rates(dss_get_dispc_clk_rate(),
4329 &lcd_conf.clock_info);
4330 dispc_mgr_set_lcd_config(OMAP_DSS_CHANNEL_LCD, &lcd_conf);
4331 dispc_mgr_set_timings(OMAP_DSS_CHANNEL_LCD, &i734.timings);
4332
4333 dispc_clear_irqstatus(framedone_irq);
4334
4335 /* Enable and shut the channel to produce just one frame */
4336 dispc_mgr_enable(OMAP_DSS_CHANNEL_LCD, true);
4337 dispc_mgr_enable(OMAP_DSS_CHANNEL_LCD, false);
4338
4339 /* Busy wait for framedone. We can't fiddle with irq handlers
4340 * in PM resume. Typically the loop runs less than 5 times and
4341 * waits less than a micro second.
4342 */
4343 count = 0;
4344 while (!(dispc_read_irqstatus() & framedone_irq)) {
4345 if (count++ > 10000) {
4346 dev_err(&dispc.pdev->dev, "%s: framedone timeout\n",
4347 __func__);
4348 break;
4349 }
4350 }
4351 dispc_ovl_enable(OMAP_DSS_GFX, false);
4352
4353 /* Clear all irq bits before continuing */
4354 dispc_clear_irqstatus(0xffffffff);
4355
4356 /* Restore the original state to LCD1 output gates */
4357 REG_FLD_MOD(DISPC_CONFIG, gatestate, 8, 4);
4358}
4359
4194/* DISPC HW IP initialisation */ 4360/* DISPC HW IP initialisation */
4195static int dispc_bind(struct device *dev, struct device *master, void *data) 4361static int dispc_bind(struct device *dev, struct device *master, void *data)
4196{ 4362{
@@ -4208,6 +4374,10 @@ static int dispc_bind(struct device *dev, struct device *master, void *data)
4208 if (r) 4374 if (r)
4209 return r; 4375 return r;
4210 4376
4377 r = dispc_errata_i734_wa_init();
4378 if (r)
4379 return r;
4380
4211 dispc_mem = platform_get_resource(dispc.pdev, IORESOURCE_MEM, 0); 4381 dispc_mem = platform_get_resource(dispc.pdev, IORESOURCE_MEM, 0);
4212 if (!dispc_mem) { 4382 if (!dispc_mem) {
4213 DSSERR("can't get IORESOURCE_MEM DISPC\n"); 4383 DSSERR("can't get IORESOURCE_MEM DISPC\n");
@@ -4272,6 +4442,8 @@ static void dispc_unbind(struct device *dev, struct device *master,
4272 void *data) 4442 void *data)
4273{ 4443{
4274 pm_runtime_disable(dev); 4444 pm_runtime_disable(dev);
4445
4446 dispc_errata_i734_wa_fini();
4275} 4447}
4276 4448
4277static const struct component_ops dispc_component_ops = { 4449static const struct component_ops dispc_component_ops = {
@@ -4314,6 +4486,8 @@ static int dispc_runtime_resume(struct device *dev)
4314 if (REG_GET(DISPC_CONFIG, 2, 1) != OMAP_DSS_LOAD_FRAME_ONLY) { 4486 if (REG_GET(DISPC_CONFIG, 2, 1) != OMAP_DSS_LOAD_FRAME_ONLY) {
4315 _omap_dispc_initial_config(); 4487 _omap_dispc_initial_config();
4316 4488
4489 dispc_errata_i734_wa();
4490
4317 dispc_restore_context(); 4491 dispc_restore_context();
4318 4492
4319 dispc_restore_gamma_tables(); 4493 dispc_restore_gamma_tables();