Skip to content

Commit

Permalink
drm: rp1: rp1-dpi: Add interlaced modes and PIO program to fix VSYNC
Browse files Browse the repository at this point in the history
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]>
  • Loading branch information
njhollinghurst committed Dec 11, 2024
1 parent ff5732d commit af0679f
Show file tree
Hide file tree
Showing 5 changed files with 461 additions and 71 deletions.
2 changes: 1 addition & 1 deletion drivers/gpu/drm/rp1/rp1-dpi/Makefile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-only

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

obj-$(CONFIG_DRM_RP1_DPI) += drm-rp1-dpi.o
34 changes: 33 additions & 1 deletion drivers/gpu/drm/rp1/rp1-dpi/rp1_dpi.c
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ static void rp1dpi_pipe_update(struct drm_simple_display_pipe *pipe,
if (dpi->dpi_running &&
fb->format->format != dpi->cur_fmt) {
rp1dpi_hw_stop(dpi);
rp1dpi_pio_stop(dpi);
dpi->dpi_running = false;
}
if (!dpi->dpi_running) {
Expand All @@ -88,6 +89,7 @@ static void rp1dpi_pipe_update(struct drm_simple_display_pipe *pipe,
dpi->bus_fmt,
dpi->de_inv,
&pipe->crtc.state->mode);
rp1dpi_pio_start(dpi, &pipe->crtc.state->mode);
dpi->dpi_running = true;
}
dpi->cur_fmt = fb->format->format;
Expand Down Expand Up @@ -187,6 +189,7 @@ static void rp1dpi_pipe_disable(struct drm_simple_display_pipe *pipe)
drm_crtc_vblank_off(&pipe->crtc);
if (dpi->dpi_running) {
rp1dpi_hw_stop(dpi);
rp1dpi_pio_stop(dpi);
dpi->dpi_running = false;
}
clk_disable_unprepare(dpi->clocks[RP1DPI_CLK_DPI]);
Expand Down Expand Up @@ -236,6 +239,7 @@ static void rp1dpi_stopall(struct drm_device *drm)
if (dpi->dpi_running || rp1dpi_hw_busy(dpi)) {
rp1dpi_hw_stop(dpi);
clk_disable_unprepare(dpi->clocks[RP1DPI_CLK_DPI]);
rp1dpi_pio_stop(dpi);
dpi->dpi_running = false;
}
rp1dpi_vidout_poweroff(dpi);
Expand Down Expand Up @@ -273,7 +277,7 @@ static int rp1dpi_platform_probe(struct platform_device *pdev)
struct rp1_dpi *dpi;
struct drm_bridge *bridge = NULL;
struct drm_panel *panel;
int i, ret;
int i, j, ret;

dev_info(dev, __func__);
ret = drm_of_find_panel_or_bridge(pdev->dev.of_node, 0, 0,
Expand All @@ -295,6 +299,7 @@ static int rp1dpi_platform_probe(struct platform_device *pdev)
return ret;
}
dpi->pdev = pdev;
spin_lock_init(&dpi->hw_lock);

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

/* Check if PIO can snoop on or override DPI's GPIO1 */
dpi->gpio1_used = false;
for (i = 0; !dpi->gpio1_used; i++) {
u32 p = 0;
const char *str = NULL;
struct device_node *np1 = of_parse_phandle(dev->of_node, "pinctrl-0", i);

if (!np1)
break;

if (!of_property_read_string(np1, "function", &str) && !strcmp(str, "dpi")) {
for (j = 0; !dpi->gpio1_used; j++) {
if (of_property_read_string_index(np1, "pins", j, &str))
break;
if (!strcmp(str, "gpio1"))
dpi->gpio1_used = true;
}
for (j = 0; !dpi->gpio1_used; j++) {
if (of_property_read_u32_index(np1, "brcm,pins", j, &p))
break;
if (p == 1)
dpi->gpio1_used = true;
}
}
of_node_put(np1);
}

/* Now we have all our resources, finish driver initialization */
dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64));
init_completion(&dpi->finished);
Expand Down
18 changes: 18 additions & 0 deletions drivers/gpu/drm/rp1/rp1-dpi/rp1_dpi.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,18 @@ struct rp1_dpi {
bool de_inv, clk_inv;
bool dpi_running, pipe_enabled;
struct completion finished;

/* Experimental stuff for interlace follows */
struct rp1_pio_client *pio;
bool gpio1_used;
bool pio_stole_gpio2;

spinlock_t hw_lock; /* the following are used in line-match ISR */
dma_addr_t last_dma_addr;
u32 last_stride;
u32 shorter_front_porch;
bool interlaced;
bool lower_field_flag;
};

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

void rp1dpi_vidout_setup(struct rp1_dpi *dpi, bool drive_negedge);
void rp1dpi_vidout_poweroff(struct rp1_dpi *dpi);

/* ---------------------------------------------------------------------- */
/* PIO control -- we need PIO to generate VSync (from DE) when interlaced */

int rp1dpi_pio_start(struct rp1_dpi *dpi, const struct drm_display_mode *mode);
void rp1dpi_pio_stop(struct rp1_dpi *dpi);
Loading

0 comments on commit af0679f

Please sign in to comment.