Skip to content

Commit f11adce

Browse files
net147mripard
authored andcommitted
drm/sun4i: tcon: Add dithering support for RGB565/RGB666 LCD panels
The hardware supports dithering on TCON channel 0 which is used for LCD panels. Dithering is a method of approximating a color from a mixture of other colors when the required color isn't available. It reduces color banding artifacts that can be observed when displaying gradients (e.g. grayscale gradients). This may occur when the image that needs to be displayed is 24-bit but the LCD panel is a lower bit depth and does not perform dithering on its own. Signed-off-by: Jonathan Liu <net147@gmail.com> [wens@csie.org: check display_info.bpc first; handle LVDS and MIPI DSI] Signed-off-by: Chen-Yu Tsai <wens@csie.org> Signed-off-by: Maxime Ripard <maxime.ripard@bootlin.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180907041948.19913-4-wens@csie.org
1 parent 5869d90 commit f11adce

File tree

1 file changed

+61
-0
lines changed

1 file changed

+61
-0
lines changed

drivers/gpu/drm/sun4i/sun4i_tcon.c

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
#include <drm/drmP.h>
1414
#include <drm/drm_atomic_helper.h>
15+
#include <drm/drm_connector.h>
1516
#include <drm/drm_crtc.h>
1617
#include <drm/drm_crtc_helper.h>
1718
#include <drm/drm_encoder.h>
@@ -277,6 +278,57 @@ static void sun4i_tcon0_mode_set_common(struct sun4i_tcon *tcon,
277278
SUN4I_TCON0_BASIC0_Y(mode->crtc_vdisplay));
278279
}
279280

281+
static void sun4i_tcon0_mode_set_dithering(struct sun4i_tcon *tcon,
282+
const struct drm_connector *connector)
283+
{
284+
u32 bus_format = 0;
285+
u32 val = 0;
286+
287+
/* XXX Would this ever happen? */
288+
if (!connector)
289+
return;
290+
291+
/*
292+
* FIXME: Undocumented bits
293+
*
294+
* The whole dithering process and these parameters are not
295+
* explained in the vendor documents or BSP kernel code.
296+
*/
297+
regmap_write(tcon->regs, SUN4I_TCON0_FRM_SEED_PR_REG, 0x11111111);
298+
regmap_write(tcon->regs, SUN4I_TCON0_FRM_SEED_PG_REG, 0x11111111);
299+
regmap_write(tcon->regs, SUN4I_TCON0_FRM_SEED_PB_REG, 0x11111111);
300+
regmap_write(tcon->regs, SUN4I_TCON0_FRM_SEED_LR_REG, 0x11111111);
301+
regmap_write(tcon->regs, SUN4I_TCON0_FRM_SEED_LG_REG, 0x11111111);
302+
regmap_write(tcon->regs, SUN4I_TCON0_FRM_SEED_LB_REG, 0x11111111);
303+
regmap_write(tcon->regs, SUN4I_TCON0_FRM_TBL0_REG, 0x01010000);
304+
regmap_write(tcon->regs, SUN4I_TCON0_FRM_TBL1_REG, 0x15151111);
305+
regmap_write(tcon->regs, SUN4I_TCON0_FRM_TBL2_REG, 0x57575555);
306+
regmap_write(tcon->regs, SUN4I_TCON0_FRM_TBL3_REG, 0x7f7f7777);
307+
308+
/* Do dithering if panel only supports 6 bits per color */
309+
if (connector->display_info.bpc == 6)
310+
val |= SUN4I_TCON0_FRM_CTL_EN;
311+
312+
if (connector->display_info.num_bus_formats == 1)
313+
bus_format = connector->display_info.bus_formats[0];
314+
315+
/* Check the connection format */
316+
switch (bus_format) {
317+
case MEDIA_BUS_FMT_RGB565_1X16:
318+
/* R and B components are only 5 bits deep */
319+
val |= SUN4I_TCON0_FRM_CTL_MODE_R;
320+
val |= SUN4I_TCON0_FRM_CTL_MODE_B;
321+
case MEDIA_BUS_FMT_RGB666_1X18:
322+
case MEDIA_BUS_FMT_RGB666_1X7X3_SPWG:
323+
/* Fall through: enable dithering */
324+
val |= SUN4I_TCON0_FRM_CTL_EN;
325+
break;
326+
}
327+
328+
/* Write dithering settings */
329+
regmap_write(tcon->regs, SUN4I_TCON_FRM_CTL_REG, val);
330+
}
331+
280332
static void sun4i_tcon0_mode_set_cpu(struct sun4i_tcon *tcon,
281333
const struct drm_encoder *encoder,
282334
const struct drm_display_mode *mode)
@@ -294,6 +346,9 @@ static void sun4i_tcon0_mode_set_cpu(struct sun4i_tcon *tcon,
294346

295347
sun4i_tcon0_mode_set_common(tcon, mode);
296348

349+
/* Set dithering if needed */
350+
sun4i_tcon0_mode_set_dithering(tcon, sun4i_tcon_get_connector(encoder));
351+
297352
regmap_update_bits(tcon->regs, SUN4I_TCON0_CTL_REG,
298353
SUN4I_TCON0_CTL_IF_MASK,
299354
SUN4I_TCON0_CTL_IF_8080);
@@ -359,6 +414,9 @@ static void sun4i_tcon0_mode_set_lvds(struct sun4i_tcon *tcon,
359414
tcon->dclk_max_div = 7;
360415
sun4i_tcon0_mode_set_common(tcon, mode);
361416

417+
/* Set dithering if needed */
418+
sun4i_tcon0_mode_set_dithering(tcon, sun4i_tcon_get_connector(encoder));
419+
362420
/* Adjust clock delay */
363421
clk_delay = sun4i_tcon_get_clk_delay(mode, 0);
364422
regmap_update_bits(tcon->regs, SUN4I_TCON0_CTL_REG,
@@ -432,6 +490,9 @@ static void sun4i_tcon0_mode_set_rgb(struct sun4i_tcon *tcon,
432490
tcon->dclk_max_div = 127;
433491
sun4i_tcon0_mode_set_common(tcon, mode);
434492

493+
/* Set dithering if needed */
494+
sun4i_tcon0_mode_set_dithering(tcon, tcon->panel->connector);
495+
435496
/* Adjust clock delay */
436497
clk_delay = sun4i_tcon_get_clk_delay(mode, 0);
437498
regmap_update_bits(tcon->regs, SUN4I_TCON0_CTL_REG,

0 commit comments

Comments
 (0)