Skip to content

Commit e7a1705

Browse files
njhollinghurstpopcornmix
authored andcommitted
drm: rp1: rp1-dpi: Add interlaced modes and PIO program to fix VSYNC
Implement interlaced modes by wobbling the base pointer and VFP width for every field. This results in correct pixels but incorrect VSYNC. Now use PIO to generate a fixed-up VSYNC by sampling DE and HSYNC. This requires DPI's DE output to be mapped to GPIO1, which we check. When DE is not exposed, the internal fixup is disabled. VSYNC/GPIO2 becomes a modified signal, designed to help an external device or PIO program synthesize CSYNC or VSYNC. Signed-off-by: Nick Hollinghurst <[email protected]>
1 parent ae12c37 commit e7a1705

File tree

5 files changed

+461
-71
lines changed

5 files changed

+461
-71
lines changed

drivers/gpu/drm/rp1/rp1-dpi/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# SPDX-License-Identifier: GPL-2.0-only
22

3-
drm-rp1-dpi-y := rp1_dpi.o rp1_dpi_hw.o rp1_dpi_cfg.o
3+
drm-rp1-dpi-y := rp1_dpi.o rp1_dpi_hw.o rp1_dpi_cfg.o rp1_dpi_pio.o
44

55
obj-$(CONFIG_DRM_RP1_DPI) += drm-rp1-dpi.o

drivers/gpu/drm/rp1/rp1-dpi/rp1_dpi.c

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ static void rp1dpi_pipe_update(struct drm_simple_display_pipe *pipe,
8080
if (dpi->dpi_running &&
8181
fb->format->format != dpi->cur_fmt) {
8282
rp1dpi_hw_stop(dpi);
83+
rp1dpi_pio_stop(dpi);
8384
dpi->dpi_running = false;
8485
}
8586
if (!dpi->dpi_running) {
@@ -88,6 +89,7 @@ static void rp1dpi_pipe_update(struct drm_simple_display_pipe *pipe,
8889
dpi->bus_fmt,
8990
dpi->de_inv,
9091
&pipe->crtc.state->mode);
92+
rp1dpi_pio_start(dpi, &pipe->crtc.state->mode);
9193
dpi->dpi_running = true;
9294
}
9395
dpi->cur_fmt = fb->format->format;
@@ -187,6 +189,7 @@ static void rp1dpi_pipe_disable(struct drm_simple_display_pipe *pipe)
187189
drm_crtc_vblank_off(&pipe->crtc);
188190
if (dpi->dpi_running) {
189191
rp1dpi_hw_stop(dpi);
192+
rp1dpi_pio_stop(dpi);
190193
dpi->dpi_running = false;
191194
}
192195
clk_disable_unprepare(dpi->clocks[RP1DPI_CLK_DPI]);
@@ -236,6 +239,7 @@ static void rp1dpi_stopall(struct drm_device *drm)
236239
if (dpi->dpi_running || rp1dpi_hw_busy(dpi)) {
237240
rp1dpi_hw_stop(dpi);
238241
clk_disable_unprepare(dpi->clocks[RP1DPI_CLK_DPI]);
242+
rp1dpi_pio_stop(dpi);
239243
dpi->dpi_running = false;
240244
}
241245
rp1dpi_vidout_poweroff(dpi);
@@ -273,7 +277,7 @@ static int rp1dpi_platform_probe(struct platform_device *pdev)
273277
struct rp1_dpi *dpi;
274278
struct drm_bridge *bridge = NULL;
275279
struct drm_panel *panel;
276-
int i, ret;
280+
int i, j, ret;
277281

278282
dev_info(dev, __func__);
279283
ret = drm_of_find_panel_or_bridge(pdev->dev.of_node, 0, 0,
@@ -295,6 +299,7 @@ static int rp1dpi_platform_probe(struct platform_device *pdev)
295299
return ret;
296300
}
297301
dpi->pdev = pdev;
302+
spin_lock_init(&dpi->hw_lock);
298303

299304
dpi->bus_fmt = default_bus_fmt;
300305
ret = of_property_read_u32(dev->of_node, "default_bus_fmt", &dpi->bus_fmt);
@@ -332,6 +337,33 @@ static int rp1dpi_platform_probe(struct platform_device *pdev)
332337
if (ret)
333338
goto done_err;
334339

340+
/* Check if PIO can snoop on or override DPI's GPIO1 */
341+
dpi->gpio1_used = false;
342+
for (i = 0; !dpi->gpio1_used; i++) {
343+
u32 p = 0;
344+
const char *str = NULL;
345+
struct device_node *np1 = of_parse_phandle(dev->of_node, "pinctrl-0", i);
346+
347+
if (!np1)
348+
break;
349+
350+
if (!of_property_read_string(np1, "function", &str) && !strcmp(str, "dpi")) {
351+
for (j = 0; !dpi->gpio1_used; j++) {
352+
if (of_property_read_string_index(np1, "pins", j, &str))
353+
break;
354+
if (!strcmp(str, "gpio1"))
355+
dpi->gpio1_used = true;
356+
}
357+
for (j = 0; !dpi->gpio1_used; j++) {
358+
if (of_property_read_u32_index(np1, "brcm,pins", j, &p))
359+
break;
360+
if (p == 1)
361+
dpi->gpio1_used = true;
362+
}
363+
}
364+
of_node_put(np1);
365+
}
366+
335367
/* Now we have all our resources, finish driver initialization */
336368
dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64));
337369
init_completion(&dpi->finished);

drivers/gpu/drm/rp1/rp1-dpi/rp1_dpi.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,18 @@ struct rp1_dpi {
4646
bool de_inv, clk_inv;
4747
bool dpi_running, pipe_enabled;
4848
struct completion finished;
49+
50+
/* Experimental stuff for interlace follows */
51+
struct rp1_pio_client *pio;
52+
bool gpio1_used;
53+
bool pio_stole_gpio2;
54+
55+
spinlock_t hw_lock; /* the following are used in line-match ISR */
56+
dma_addr_t last_dma_addr;
57+
u32 last_stride;
58+
u32 shorter_front_porch;
59+
bool interlaced;
60+
bool lower_field_flag;
4961
};
5062

5163
/* ---------------------------------------------------------------------- */
@@ -67,3 +79,9 @@ void rp1dpi_hw_vblank_ctrl(struct rp1_dpi *dpi, int enable);
6779

6880
void rp1dpi_vidout_setup(struct rp1_dpi *dpi, bool drive_negedge);
6981
void rp1dpi_vidout_poweroff(struct rp1_dpi *dpi);
82+
83+
/* ---------------------------------------------------------------------- */
84+
/* PIO control -- we need PIO to generate VSync (from DE) when interlaced */
85+
86+
int rp1dpi_pio_start(struct rp1_dpi *dpi, const struct drm_display_mode *mode);
87+
void rp1dpi_pio_stop(struct rp1_dpi *dpi);

0 commit comments

Comments
 (0)