Module Name: src Committed By: bouyer Date: Sun Oct 16 17:08:47 UTC 2022
Modified Files: src/sys/arch/arm/sunxi [bouyer-sunxi-drm]: sunxi_lcdc.c sunxi_tcon.c Log Message: Abandon sunxi_lcdc for the A20, there's too much pieces missing. Convert sunxi_tcon to drm. Actually it's connected to DRM only when in LVDS mode; for HDMI sunxi_hdmi does the interface. To generate a diff of this commit: cvs rdiff -u -r1.15.2.1 -r1.15.2.2 src/sys/arch/arm/sunxi/sunxi_lcdc.c cvs rdiff -u -r1.13 -r1.13.2.1 src/sys/arch/arm/sunxi/sunxi_tcon.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/arch/arm/sunxi/sunxi_lcdc.c diff -u src/sys/arch/arm/sunxi/sunxi_lcdc.c:1.15.2.1 src/sys/arch/arm/sunxi/sunxi_lcdc.c:1.15.2.2 --- src/sys/arch/arm/sunxi/sunxi_lcdc.c:1.15.2.1 Sun Oct 2 10:37:12 2022 +++ src/sys/arch/arm/sunxi/sunxi_lcdc.c Sun Oct 16 17:08:46 2022 @@ -1,4 +1,4 @@ -/* $NetBSD: sunxi_lcdc.c,v 1.15.2.1 2022/10/02 10:37:12 bouyer Exp $ */ +/* $NetBSD: sunxi_lcdc.c,v 1.15.2.2 2022/10/16 17:08:46 bouyer Exp $ */ /*- * Copyright (c) 2019 Jared D. McNeill <jmcne...@invisible.ca> @@ -27,7 +27,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: sunxi_lcdc.c,v 1.15.2.1 2022/10/02 10:37:12 bouyer Exp $"); +__KERNEL_RCSID(0, "$NetBSD: sunxi_lcdc.c,v 1.15.2.2 2022/10/16 17:08:46 bouyer Exp $"); #include <sys/param.h> #include <sys/bus.h> @@ -112,8 +112,6 @@ static const struct device_compatible_en { .compat = "allwinner,sun8i-v3s-tcon", .value = TYPE_TCON0 }, { .compat = "allwinner,sun50i-a64-tcon-lcd", .value = TYPE_TCON0 }, { .compat = "allwinner,sun50i-a64-tcon-tv", .value = TYPE_TCON1 }, - { .compat = "allwinner,sun7i-a20-tcon0", .value = TYPE_TCON0 }, - { .compat = "allwinner,sun7i-a20-tcon1", .value = TYPE_TCON1 }, DEVICE_COMPAT_EOL }; Index: src/sys/arch/arm/sunxi/sunxi_tcon.c diff -u src/sys/arch/arm/sunxi/sunxi_tcon.c:1.13 src/sys/arch/arm/sunxi/sunxi_tcon.c:1.13.2.1 --- src/sys/arch/arm/sunxi/sunxi_tcon.c:1.13 Fri Aug 20 20:25:27 2021 +++ src/sys/arch/arm/sunxi/sunxi_tcon.c Sun Oct 16 17:08:46 2022 @@ -1,4 +1,4 @@ -/* $NetBSD: sunxi_tcon.c,v 1.13 2021/08/20 20:25:27 andvar Exp $ */ +/* $NetBSD: sunxi_tcon.c,v 1.13.2.1 2022/10/16 17:08:46 bouyer Exp $ */ /*- * Copyright (c) 2018 Manuel Bouyer <bou...@antioche.eu.org> @@ -30,7 +30,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: sunxi_tcon.c,v 1.13 2021/08/20 20:25:27 andvar Exp $"); +__KERNEL_RCSID(0, "$NetBSD: sunxi_tcon.c,v 1.13.2.1 2022/10/16 17:08:46 bouyer Exp $"); #include <sys/param.h> #include <sys/bus.h> @@ -45,11 +45,14 @@ __KERNEL_RCSID(0, "$NetBSD: sunxi_tcon.c #include <dev/fdt/fdt_port.h> #include <dev/fdt/panel_fdt.h> -#include <dev/videomode/videomode.h> - #include <arm/sunxi/sunxi_tconreg.h> #include <arm/sunxi/sunxi_display.h> +#include <drm/drm_bridge.h> +#include <drm/drm_connector.h> +#include <drm/drm_drv.h> +#include <drm/drm_modes.h> + #define DIVIDE(x,y) (((x) + ((y) / 2)) / (y)) enum sunxi_tcon_type { @@ -75,6 +78,8 @@ struct sunxi_tcon_softc { struct fdt_endpoint *sc_in_ep; struct fdt_endpoint *sc_in_rep; struct fdt_endpoint *sc_out_ep; + struct drm_encoder sc_encoder; + struct drm_connector sc_connector; }; static bus_space_handle_t tcon_mux_bsh; @@ -88,6 +93,70 @@ static int sunxi_tcon0_enable(struct su static int sunxi_tcon1_enable(struct sunxi_tcon_softc *, bool); void sunxi_tcon_dump_regs(int); +#define encoder_to_tcon(x) container_of(x, struct sunxi_tcon_softc, sc_encoder) +#define connector_to_tcon(x) container_of(x, struct sunxi_tcon_softc, sc_connector) + +static void +sunxi_tcon_destroy(struct drm_encoder *encoder) +{ + drm_encoder_cleanup(encoder); +} + +static const struct drm_encoder_funcs sunxi_tcon_enc_funcs = { + .destroy = sunxi_tcon_destroy, +}; + +static int sunxi_tcon_atomic_check(struct drm_encoder *, + struct drm_crtc_state *, struct drm_connector_state *); +static void sunxi_tcon_disable(struct drm_encoder *); +static void sunxi_tcon_enable(struct drm_encoder *); +static void sunxi_tcon_mode_set(struct drm_encoder *, + struct drm_display_mode *, struct drm_display_mode *); +static void sunxi_tcon_mode_valid(struct drm_encoder *, + struct drm_display_mode *); + +static void +sunxi_tcon_encoder_disable(struct drm_encoder *encoder) +{ + int ret; + struct sunxi_tcon_softc *sc = encoder_to_tcon(encoder); + ret = sunxi_tcon0_enable(sc, false); + if (ret) + device_printf(sc->sc_dev, "failed to disable tcon0: %d\n", ret); +} +static void +sunci_tcon_encoder_enable(struct drm_encoder *encoder) +{ + int ret; + struct sunxi_tcon_softc *sc = encoder_to_tcon(encoder); + ret = sunxi_tcon0_enable(sc, true); + if (ret) + device_printf(sc->sc_dev, "failed to enable tcon0: %d\n", ret); +} + +static const struct drm_encoder_helper_funcs sunxi_tcon_enc_helper_funcs = { + .disable = sunxi_tcon_disable, + .enable = sunxi_tcon_enable, +}; + +static enum drm_connector_status sunxi_tcon_connector_detect( + struct drm_connector *, bool); + +static const struct drm_connector_funcs sunxi_tcon_connector_funcs = { + .fill_modes = drm_helper_probe_single_connector_modes, + .destroy = drm_connector_cleanup, + .reset = drm_atomic_helper_connector_reset, + .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, +}; + +static int sunxi_tcon_get_modes(struct drm_connector *); + +static const struct drm_connector_helper_funcs sunxi_tcon_connector_helper_funcs + = { + .get_modes = sunxi_tcon_get_modes, +}; + #define TCON_READ(sc, reg) \ bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, (reg)) #define TCON_WRITE(sc, reg, val) \ @@ -96,6 +165,8 @@ void sunxi_tcon_dump_regs(int); static const struct device_compatible_entry compat_data[] = { { .compat = "allwinner,sun4i-a10-tcon", .value = TCON_A10}, { .compat = "allwinner,sun7i-a20-tcon", .value = TCON_A10}, + { .compat = "allwinner,sun7i-a20-tcon0", .value = TCON_A10 }, + { .compat = "allwinner,sun7i-a20-tcon1", .value = TCON_A10 }, DEVICE_COMPAT_EOL }; @@ -320,6 +391,29 @@ sunxi_tcon_ep_connect(device_t self, str } } +static int +sunxi_tcon0_drm_register(struct sunxi_tcon_softc *sc) +{ + struct drm_crtc *crtc = sunxi_tcon_get_crtc(sc->sc_dev); + KASSERT(crtc != NULL); + int error; + + sc->sc_encoder.possible_crtcs = 1 << drm_crtc_index(crtc); + drm_encoder_helper_add(&sc->sc_encoder, sunxi_tcon_enc_helper_funcs); + error = drm_encoder_init(crtc->dev, &sc->sc_encoder, + sunxi_tcon_enc_funcs, DRM_MODE_ENCODER_LVDS, NULL); + if (error) + return -error; + drm_connector_helper_add(&sc->sc_connector, + &sunxi_tcon_connector_helper_funcs); + error = drm_connector_init(crtc->dev, &sc->sc_connector, + DRM_MODE_CONNECTOR_LVDS); + if (error) + return -error; + drm_connector_attach_encoder(&sc->sc_connector, &sc->sc_encoder.base); + return sunxi_tcon0_set_video(sc); +} + static int sunxi_tcon_ep_activate(device_t dev, struct fdt_endpoint *ep, bool activate) { @@ -376,7 +470,7 @@ sunxi_tcon_ep_activate(device_t dev, str device_xname(fdt_endpoint_device(rep))); sc->sc_out_ep = out_ep; if (outi == 0) - return sunxi_tcon0_set_video(sc); + return sunxi_tcon0_drm_register(sc); /* XXX should check VGA here */ sc->sc_output_type = OUTPUT_HDMI; return 0; @@ -878,6 +972,47 @@ bad: return is_console; } +struct drm_crtc * +sunxi_tcon_get_crtc(device_t dev) +{ + struct sunxi_tcon_softc *sc = device_private(dev); + return sunxi_debe_get_crtc(fdt_endpoint_device(sc->sc_in_rep)); +} + +static int +sunxi_tcon_get_modes(struct drm_connector * conn) +{ + struct drm_display_mode *mode; + const struct fdt_panel * panel; + + panel = fdt_endpoint_get_data(fdt_endpoint_remote(sc->sc_out_ep)); + KASSERT(panel != NULL); + KASSERT(panel->panel_type == PANEL_DUAL_LVDS || + panel->panel_type == PANEL_LVDS); + sc->sc_output_type = OUTPUT_LVDS; + + mode = drm_mode_create(connector->dev); + if (mode == NULL) + return ENOMEM; + + mode->hdisplay = panel->panel_timing.hactive; + mode->hsync_start = mode->hdisplay + panel->panel_timing.hfront_porch; + mode->hsync_end = mode->hsync_start + panel->panel_timing.hsync_len; + mode->htotal = mode->hsync_end + panel->panel_timing.back_porch; + mode->vdisplay = panel->panel_timing.vactive; + mode->vsync_start = mode->vdisplay + panel->panel_timing.vfront_porch; + mode->vsync_end = mode->vsync_start + panel->panel_timing.vsync_len; + mode->vtotal = mode->vsync_end + panel->panel_timing.vback_porch; + + mode->clock = panel->panel_timing.clock_freq / 1000; + + /* XXX */ + mode->flags |= DRM_MODE_FLAG_PHSYNC; + mode->flags |= DRM_MODE_FLAG_PVSYNC; + drm_mode_set_name(mode); + return 0; +} + #if defined(DDB) || defined(SUNXI_TCON_DEBUG) void sunxi_tcon_dump_regs(int u)