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)

Reply via email to