Skip to content

Commit 78fa479

Browse files
committed
drm/bridge: adv7533: Use internal timing generator
ADV7533 provides an internal timing generator for certain modes that it can't use the DSI clock directly. We've observed that HDMI is more stable with the internal timing generator, especially if there are instabilities in the DSI clock source. The data spec also seems to recommend the usage of the timing generator for all modes. However, on some platforms, it's reported that enabling the timing generator causes instabilities with the HDMI output. Create a DT parameter that lets a platform explicitly disable the timing generator. The timing generator is enabled by default. Signed-off-by: Archit Taneja <[email protected]>
1 parent 1e4d58c commit 78fa479

File tree

3 files changed

+63
-2
lines changed

3 files changed

+63
-2
lines changed

drivers/gpu/drm/bridge/adv7511/adv7511.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,8 @@ struct adv7511 {
306306
enum drm_connector_status status;
307307
bool powered;
308308

309+
struct drm_display_mode curr_mode;
310+
309311
unsigned int f_tmds;
310312

311313
unsigned int current_edid_segment;
@@ -329,6 +331,7 @@ struct adv7511 {
329331
struct device_node *host_node;
330332
struct mipi_dsi_device *dsi;
331333
u8 num_dsi_lanes;
334+
bool use_timing_gen;
332335

333336
enum adv7511_type type;
334337
};

drivers/gpu/drm/bridge/adv7511/adv7511_drv.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -712,6 +712,8 @@ static void adv7511_mode_set(struct adv7511 *adv7511,
712712
regmap_update_bits(adv7511->regmap, 0x17,
713713
0x60, (vsync_polarity << 6) | (hsync_polarity << 5));
714714

715+
drm_mode_copy(&adv7511->curr_mode, adj_mode);
716+
715717
/*
716718
* TODO Test first order 4:2:2 to 4:4:4 up conversion method, which is
717719
* supposed to give better results.

drivers/gpu/drm/bridge/adv7511/adv7533.c

Lines changed: 58 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,14 +39,65 @@ static const struct regmap_config adv7533_cec_regmap_config = {
3939
.cache_type = REGCACHE_RBTREE,
4040
};
4141

42+
static void adv7511_dsi_config_timing_gen(struct adv7511 *adv)
43+
{
44+
struct mipi_dsi_device *dsi = adv->dsi;
45+
struct drm_display_mode *mode = &adv->curr_mode;
46+
unsigned int hsw, hfp, hbp, vsw, vfp, vbp;
47+
u8 clock_div_by_lanes[] = { 6, 4, 3 }; /* 2, 3, 4 lanes */
48+
49+
hsw = mode->hsync_end - mode->hsync_start;
50+
hfp = mode->hsync_start - mode->hdisplay;
51+
hbp = mode->htotal - mode->hsync_end;
52+
vsw = mode->vsync_end - mode->vsync_start;
53+
vfp = mode->vsync_start - mode->vdisplay;
54+
vbp = mode->vtotal - mode->vsync_end;
55+
56+
/* set pixel clock divider mode */
57+
regmap_write(adv->regmap_cec, 0x16,
58+
clock_div_by_lanes[dsi->lanes - 2] << 3);
59+
60+
/* horizontal porch params */
61+
regmap_write(adv->regmap_cec, 0x28, mode->htotal >> 4);
62+
regmap_write(adv->regmap_cec, 0x29, (mode->htotal << 4) & 0xff);
63+
regmap_write(adv->regmap_cec, 0x2a, hsw >> 4);
64+
regmap_write(adv->regmap_cec, 0x2b, (hsw << 4) & 0xff);
65+
regmap_write(adv->regmap_cec, 0x2c, hfp >> 4);
66+
regmap_write(adv->regmap_cec, 0x2d, (hfp << 4) & 0xff);
67+
regmap_write(adv->regmap_cec, 0x2e, hbp >> 4);
68+
regmap_write(adv->regmap_cec, 0x2f, (hbp << 4) & 0xff);
69+
70+
/* vertical porch params */
71+
regmap_write(adv->regmap_cec, 0x30, mode->vtotal >> 4);
72+
regmap_write(adv->regmap_cec, 0x31, (mode->vtotal << 4) & 0xff);
73+
regmap_write(adv->regmap_cec, 0x32, vsw >> 4);
74+
regmap_write(adv->regmap_cec, 0x33, (vsw << 4) & 0xff);
75+
regmap_write(adv->regmap_cec, 0x34, vfp >> 4);
76+
regmap_write(adv->regmap_cec, 0x35, (vfp << 4) & 0xff);
77+
regmap_write(adv->regmap_cec, 0x36, vbp >> 4);
78+
regmap_write(adv->regmap_cec, 0x37, (vbp << 4) & 0xff);
79+
}
80+
4281
void adv7533_dsi_power_on(struct adv7511 *adv)
4382
{
4483
struct mipi_dsi_device *dsi = adv->dsi;
4584

85+
if (adv->use_timing_gen)
86+
adv7511_dsi_config_timing_gen(adv);
87+
4688
/* set number of dsi lanes */
4789
regmap_write(adv->regmap_cec, 0x1c, dsi->lanes << 4);
48-
/* disable internal timing generator */
49-
regmap_write(adv->regmap_cec, 0x27, 0x0b);
90+
91+
if (adv->use_timing_gen) {
92+
/* reset internal timing generator */
93+
regmap_write(adv->regmap_cec, 0x27, 0xcb);
94+
regmap_write(adv->regmap_cec, 0x27, 0x8b);
95+
regmap_write(adv->regmap_cec, 0x27, 0xcb);
96+
} else {
97+
/* disable internal timing generator */
98+
regmap_write(adv->regmap_cec, 0x27, 0x0b);
99+
}
100+
50101
/* enable hdmi */
51102
regmap_write(adv->regmap_cec, 0x03, 0x89);
52103
/* disable test mode */
@@ -60,6 +111,8 @@ void adv7533_dsi_power_off(struct adv7511 *adv)
60111
{
61112
/* disable hdmi */
62113
regmap_write(adv->regmap_cec, 0x03, 0x0b);
114+
/* disable internal timing generator */
115+
regmap_write(adv->regmap_cec, 0x27, 0x0b);
63116
}
64117

65118
int adv7533_patch_registers(struct adv7511 *adv)
@@ -179,6 +232,9 @@ int adv7533_parse_dt(struct device_node *np, struct adv7511 *adv)
179232
of_node_put(endpoint);
180233
of_node_put(adv->host_node);
181234

235+
adv->use_timing_gen = !of_property_read_bool(np,
236+
"adi,disable-timing-generator");
237+
182238
/* TODO: Check if these need to be parsed by DT or not */
183239
adv->rgb = true;
184240
adv->embedded_sync = false;

0 commit comments

Comments
 (0)