tech-kern archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
sunxi graphic console, try 2
Hello,
with Jared's feedback, I reimplemented console handling for the sunxi graphic
drivers. There are 3 problems to solve:
- proper handling for console=xxx in the bootargs. I want to switch from
graphic to serial, or back, from bootargs without changing
/chosen/stdout-path entry in the device tree each time.
The kernel can change stdout-path early in the boot process,
and at this time it's not pratical to make it point to anything
but serial or /chosen/framebuffer (we don't want to parse the whole
device tree at this time).
So I just change sunxi_platform_bootstrap() to understand console=serial
in bootargs, so is stdout-path points to some graphic device in the
device tree we can switch back to serial.
- attaching the graphic console to the graphic pipeline instead of simplefb.
The graphic driver doesn't want to claim the consle at FDT_CONSOLE() time,
because at this time it doens't know if it will be active or not
(not to mention which of the 2 pipelines will be active, and will be console).
In addition, simplefb may be functional until the graphic driver takes over.
So in sunxi_debe I use FDT_CONSOLE() only to remember the
simple-framebuffer phandle, which sunxi_debe will need to decide if
it's console later.
- preventing simplefb from attaching. Once the graphic drivers have attached
simplefb is not functional any more. So even if there is an active
simple-framebuffer compatible not in the fdt, we should not attach it.
I could add a sunxi_simplefb driver which return a higther match
score, but I don't like the idea of adding a void driver just
to prevent another one from attaching. Among others, this could
cause strange effects if the kernel config omits it, hard to debug as
this is touching the console.
Basically we have several fdt nodes pointing to the same hardware,
and we don't want to use them all.
I added public fdt functions to explicitely inactivate arbitrary
fdt nodes (here I remove them from the node list but that's implementation
detail). There is fdt_remove_bycompat(const char *[]) to remove nodes
matching on compatible strings; for completeness I also added
fdt_remove_byhandle(int) but I don't need it.
--
Manuel Bouyer <bouyer%antioche.eu.org@localhost>
NetBSD: 26 ans d'experience feront toujours la difference
--
Index: dev/fdt/fdtbus.c
===================================================================
RCS file: /cvsroot/src/sys/dev/fdt/fdtbus.c,v
retrieving revision 1.15
diff -u -p -u -r1.15 fdtbus.c
--- dev/fdt/fdtbus.c 27 Aug 2017 19:13:31 -0000 1.15
+++ dev/fdt/fdtbus.c 7 Apr 2018 11:37:47 -0000
@@ -265,6 +265,31 @@ fdt_add_node(struct fdt_node *new_node)
TAILQ_INSERT_TAIL(&fdt_nodes, new_node, n_nodes);
}
+void
+fdt_remove_byhandle(int phandle)
+{
+ struct fdt_node *node;
+
+ TAILQ_FOREACH(node, &fdt_nodes, n_nodes) {
+ if (node->n_phandle == phandle) {
+ TAILQ_REMOVE(&fdt_nodes, node, n_nodes);
+ return;
+ }
+ }
+}
+
+void
+fdt_remove_bycompat(const char *compatible[])
+{
+ struct fdt_node *node, *next;
+
+ TAILQ_FOREACH_SAFE(node, &fdt_nodes, n_nodes, next) {
+ if (of_match_compatible(node->n_phandle, compatible)) {
+ TAILQ_REMOVE(&fdt_nodes, node, n_nodes);
+ }
+ }
+}
+
static u_int
fdt_get_order(int phandle)
{
Index: dev/fdt/fdtvar.h
===================================================================
RCS file: /cvsroot/src/sys/dev/fdt/fdtvar.h,v
retrieving revision 1.28
diff -u -p -u -r1.28 fdtvar.h
--- dev/fdt/fdtvar.h 10 Dec 2017 21:38:27 -0000 1.28
+++ dev/fdt/fdtvar.h 7 Apr 2018 11:37:47 -0000
@@ -321,6 +321,8 @@ const void * fdtbus_get_prop(int, const
const char * fdtbus_get_string(int, const char *);
const char * fdtbus_get_string_index(int, const char *, u_int);
+void fdt_remove_byhandle(int);
+void fdt_remove_bycompat(const char *[]);
int fdtbus_print(void *, const char *);
#endif /* _DEV_FDT_FDTVAR_H */
Index: arch/arm/sunxi/sunxi_debe.c
===================================================================
RCS file: /cvsroot/src/sys/arch/arm/sunxi/sunxi_debe.c,v
retrieving revision 1.7
diff -u -p -u -r1.7 sunxi_debe.c
--- arch/arm/sunxi/sunxi_debe.c 5 Apr 2018 10:21:39 -0000 1.7
+++ arch/arm/sunxi/sunxi_debe.c 7 Apr 2018 11:37:47 -0000
@@ -58,6 +58,8 @@ __KERNEL_RCSID(0, "$NetBSD: sunxi_debe.c
#include <arm/sunxi/sunxi_debereg.h>
#include <arm/sunxi/sunxi_display.h>
+#include <arm/sunxi/sunxi_platform.h>
+#include <machine/bootconfig.h>
enum sunxi_debe_type {
DEBE_A10 = 1,
@@ -128,6 +130,9 @@ static int sunxi_debe_ioctl(device_t, u_
static void sunxi_befb_set_videomode(device_t, u_int, u_int);
void sunxi_debe_dump_regs(int);
+static struct sunxi_debe_softc *debe_console_sc;
+static int sunxi_simplefb_phandle = -1;
+
CFATTACH_DECL_NEW(sunxi_debe, sizeof(struct sunxi_debe_softc),
sunxi_debe_match, sunxi_debe_attach, NULL, NULL);
@@ -242,8 +247,6 @@ sunxi_debe_attach(device_t parent, devic
}
}
-
-
static void
sunxi_debe_ep_connect(device_t self, struct fdt_endpoint *ep, bool connect)
{
@@ -337,6 +340,32 @@ sunxi_debe_setup_fbdev(struct sunxi_debe
const u_int fb_height = (mode->vdisplay << interlace_p);
if (mode && sc->sc_fbdev == NULL) {
+ /* see if we are the console */
+ if (sunxi_simplefb_phandle >= 0) {
+ const char *cons_pipeline =
+ fdtbus_get_string(sunxi_simplefb_phandle,
+ "allwinner,pipeline");
+ struct fdt_endpoint *ep = fdt_endpoint_get_from_index(
+ &sc->sc_ports, SUNXI_PORT_OUTPUT, sc->sc_unit);
+ struct fdt_endpoint *rep = fdt_endpoint_remote(ep);
+ if (sunxi_tcon_is_console(
+ fdt_endpoint_device(rep), cons_pipeline))
+ debe_console_sc = sc;
+ } else if (debe_console_sc == NULL) {
+ if (match_bootconf_option(boot_args,
+ "console", "fb0")) {
+ if (sc->sc_unit == 0)
+ debe_console_sc = sc;
+ } else if (match_bootconf_option(boot_args,
+ "console", "fb1")) {
+ if (sc->sc_unit == 1)
+ debe_console_sc = sc;
+ } else if (match_bootconf_option(boot_args,
+ "console", "fb")) {
+ /* match first activated */
+ debe_console_sc = sc;
+ }
+ }
struct sunxifb_attach_args afb = {
.afb_fb = sc->sc_dmap,
.afb_width = fb_width,
@@ -684,9 +713,6 @@ sunxi_befb_attach(device_t parent, devic
prop_dictionary_t cfg = device_properties(self);
struct genfb_ops ops;
- if (sunxi_befb_consoledev == NULL)
- sunxi_befb_consoledev = self;
-
sc->sc_gen.sc_dev = self;
sc->sc_debedev = parent;
sc->sc_dmat = afb->afb_dmat;
@@ -716,14 +742,27 @@ sunxi_befb_attach(device_t parent, devic
aprint_naive("\n");
- bool is_console = false;
- prop_dictionary_set_bool(cfg, "is_console", is_console);
-
+ bool is_console = (debe_console_sc == device_private(parent));
if (is_console)
aprint_normal(": switching to framebuffer console\n");
else
aprint_normal("\n");
+#ifdef WSDISPLAY_MULTICONS
+ /*
+ * if we support multicons, only the first framebuffer is console,
+ * unless we already know which framebuffer will be the console
+ */
+ if (!is_console && debe_console_sc == NULL &&
+ sunxi_befb_consoledev == NULL)
+ is_console = true;
+#endif
+ prop_dictionary_set_bool(cfg, "is_console", is_console);
+ if (is_console) {
+ KASSERT(sunxi_befb_consoledev == NULL);
+ sunxi_befb_consoledev = self;
+ }
+
genfb_attach(&sc->sc_gen, &ops);
}
@@ -829,13 +868,47 @@ sunxi_debe_pipeline(int phandle, bool ac
return ENODEV;
}
error = fdt_endpoint_activate(ep, true);
- if (error == 0) {
- sc->sc_out_ep = ep;
- fdt_endpoint_enable(ep, true);
- }
+ if (error)
+ return error;
+
+ sc->sc_out_ep = ep;
+ error = fdt_endpoint_enable(ep, true);
return error;
}
+/*
+ * we don't want to take over console at this time - simplefb will
+ * do a better job than us. We will take over later.
+ * But we want to record the /chose/framebuffer phandle if there is one
+ */
+
+static const char * const simplefb_compatible[] = {
+ "allwinner,simple-framebuffer",
+ NULL
+};
+
+static int
+sunxidebe_console_match(int phandle)
+{
+ if (of_match_compatible(phandle, simplefb_compatible)) {
+ sunxi_simplefb_phandle = phandle;
+ }
+ return 0;
+}
+
+static void
+sunxidebe_console_consinit(struct fdt_attach_args *faa, u_int uart_freq)
+{
+ panic("sunxidebe_console_consinit");
+}
+
+static const struct fdt_console sunxidebe_fdt_console = {
+ .match = sunxidebe_console_match,
+ .consinit = sunxidebe_console_consinit
+};
+
+FDT_CONSOLE(sunxidebe, &sunxidebe_fdt_console);
+
#if defined(SUNXI_DEBE_DEBUG)
void
sunxi_debe_dump_regs(int u)
Index: arch/arm/sunxi/sunxi_dep.c
===================================================================
RCS file: /cvsroot/src/sys/arch/arm/sunxi/sunxi_dep.c,v
retrieving revision 1.2
diff -u -p -u -r1.2 sunxi_dep.c
--- arch/arm/sunxi/sunxi_dep.c 3 Apr 2018 13:38:13 -0000 1.2
+++ arch/arm/sunxi/sunxi_dep.c 7 Apr 2018 11:37:47 -0000
@@ -57,6 +57,11 @@ static const struct of_compat_data compa
{NULL}
};
+static const char *fb_compat[] = {
+ "allwinner,simple-framebuffer",
+ NULL
+};
+
static int sunxi_dep_match(device_t, cfdata_t, void *);
static void sunxi_dep_attach(device_t, device_t, void *);
@@ -68,9 +73,8 @@ sunxi_dep_match(device_t parent, cfdata_
{
#if NSUNXI_DEBE > 0
struct fdt_attach_args * const faa = aux;
- if (!of_match_compat_data(faa->faa_phandle, compat_data))
- return 0;
- return 1;
+
+ return of_match_compat_data(faa->faa_phandle, compat_data);
#else
return 0;
#endif
@@ -82,6 +86,7 @@ sunxi_dep_attach(device_t parent, device
struct sunxi_dep_softc * const sc = device_private(self);
struct fdt_attach_args * const faa = aux;
const int phandle = faa->faa_phandle;
+ int sunxi_dep_npipelines = 0;
int len;
const u_int *buf;
u_int ref;
@@ -95,7 +100,6 @@ sunxi_dep_attach(device_t parent, device
aprint_error("bad/missing allwinner,pipelines property\n");
return;
}
- aprint_naive("\n");
aprint_normal(": ");
#if NSUNXI_DEBE > 0
for (int i = 0; i < (len / sizeof(ref)); i++) {
@@ -106,7 +110,12 @@ sunxi_dep_attach(device_t parent, device
fdtbus_get_phandle_from_native(ref), true);
if (error)
aprint_error("can't activate pipeline %d\n", i);
+ else
+ sunxi_dep_npipelines++;
}
+ aprint_naive("\n");
+ if (sunxi_dep_npipelines > 0)
+ fdt_remove_bycompat(fb_compat);
#else
aprint_error("debe not configured\n");
return;
Index: arch/arm/sunxi/sunxi_display.h
===================================================================
RCS file: /cvsroot/src/sys/arch/arm/sunxi/sunxi_display.h,v
retrieving revision 1.1
diff -u -p -u -r1.1 sunxi_display.h
--- arch/arm/sunxi/sunxi_display.h 3 Apr 2018 12:52:16 -0000 1.1
+++ arch/arm/sunxi/sunxi_display.h 7 Apr 2018 11:37:47 -0000
@@ -37,3 +37,4 @@ struct videomode;
int sunxi_debe_pipeline(int, bool);
void sunxi_tcon1_set_videomode(device_t, const struct videomode *);
void sunxi_debe_set_videomode(device_t, const struct videomode *);
+bool sunxi_tcon_is_console(device_t, const char *);
Index: arch/arm/sunxi/sunxi_platform.c
===================================================================
RCS file: /cvsroot/src/sys/arch/arm/sunxi/sunxi_platform.c,v
retrieving revision 1.22
diff -u -p -u -r1.22 sunxi_platform.c
--- arch/arm/sunxi/sunxi_platform.c 1 Apr 2018 04:35:04 -0000 1.22
+++ arch/arm/sunxi/sunxi_platform.c 7 Apr 2018 11:37:47 -0000
@@ -176,12 +176,15 @@ sunxi_platform_uart_freq(void)
static void
sunxi_platform_bootstrap(void)
{
+ void *fdt_data = __UNCONST(fdtbus_get_data());
+ const int chosen_off = fdt_path_offset(fdt_data, "/chosen");
+ if (chosen_off < 0)
+ return;
+
if (match_bootconf_option(boot_args, "console", "fb")) {
- void *fdt_data = __UNCONST(fdtbus_get_data());
- const int chosen_off = fdt_path_offset(fdt_data, "/chosen");
const int framebuffer_off =
fdt_path_offset(fdt_data, "/chosen/framebuffer");
- if (chosen_off >= 0 && framebuffer_off >= 0) {
+ if (framebuffer_off >= 0) {
const char *status = fdt_getprop(fdt_data,
framebuffer_off, "status", NULL);
if (status == NULL || strncmp(status, "ok", 2) == 0) {
@@ -189,6 +192,9 @@ sunxi_platform_bootstrap(void)
"stdout-path", "/chosen/framebuffer");
}
}
+ } else if (match_bootconf_option(boot_args, "console", "serial")) {
+ fdt_setprop_string(fdt_data, chosen_off,
+ "stdout-path", "serial0:115200n8");
}
}
Index: arch/arm/sunxi/sunxi_tcon.c
===================================================================
RCS file: /cvsroot/src/sys/arch/arm/sunxi/sunxi_tcon.c,v
retrieving revision 1.4
diff -u -p -u -r1.4 sunxi_tcon.c
--- arch/arm/sunxi/sunxi_tcon.c 4 Apr 2018 16:01:05 -0000 1.4
+++ arch/arm/sunxi/sunxi_tcon.c 7 Apr 2018 11:37:47 -0000
@@ -812,6 +812,55 @@ sunxi_tcon1_set_videomode(device_t dev,
}
}
+/* check if this tcon is the console chosen by firmare */
+bool
+sunxi_tcon_is_console(device_t dev, const char *pipeline)
+{
+ struct sunxi_tcon_softc *sc = device_private(dev);
+ char p[64];
+ char *e, *n = p;
+ bool is_console = false;
+
+ KASSERT(device_is_a(dev, "sunxitcon"));
+ strncpy(p, pipeline, sizeof(p) - 1);
+ p[sizeof(p) - 1] = '\0';
+
+ /*
+ * pipeline is like "de_be0-lcd0-hdmi"
+ * of "de_be0-lcd1".
+ * In the first case check output type
+ * In the second check tcon unit number
+ */
+ n = p;
+ e = strsep(&n, "-");
+ if (e == NULL || memcmp(e, "de_be", 5) != 0)
+ goto bad;
+ e = strsep(&n, "-");
+ if (e == NULL)
+ goto bad;
+ if (n == NULL) {
+ /* second case */
+ if (strcmp(e, "lcd0") == 0) {
+ if (sc->sc_unit == 0)
+ is_console = true;
+ } else if (strcmp(e, "lcd1") == 0) {
+ if (sc->sc_unit == 1)
+ is_console = true;
+ } else
+ goto bad;
+ return is_console;
+ }
+ /* first case */
+ if (strcmp(n, "hdmi") == 0) {
+ if (sc->sc_output_type == OUTPUT_HDMI)
+ is_console = true;
+ return is_console;
+ }
+bad:
+ aprint_error("warning: can't parse pipeline %s\n", pipeline);
+ return is_console;
+}
+
#if defined(DDB) || defined(SUNXI_TCON_DEBUG)
void
sunxi_tcon_dump_regs(int u)
Home |
Main Index |
Thread Index |
Old Index