Skip to contentSkip to conversation

Introduce driver model serial uclass

PATCH Superseded Simon Glass 2 participants 21 messages Aug 11, 2014 – Aug 15, 2014

Subsystems (3)

v4 of 6 Superseded Latest is v6 →

lore
Share & tools
lore
#0 lore raw

v4 cover Introduce driver model serial uclass

This series adds support for a serial uclass, enabling serial drivers to be converted to use driver model.

Unfortunately this is quite a complicated process for a number of reasons:

- serial is used before relocation, but driver model does not support this
- stdio member functions are not passed a device pointer, but driver model requires this (so does serial, but it uses an ugly work-around)
- driver model requires malloc() but this is not available before relocation
- for sandbox, if something goes wrong with the console, we still need to get an error message out through the fallback console

So this series relies on quite a few patches to address the above, as well as the serial uclass and an implementation for sandbox.

If you have limited time, please take a look at least at the uclass patch which is 'dm: Add a uclass for serial devices' (see include/serial.h).

With v4, exynos boards all build and a second attempt has been made to add Tegra support via the ns16550 driver, tested on beaver.

To see the current state of driver model, look at u-boot-dm.git branch 'working'.

Changes in v4:
- Add a binding for sandbox serial
- Add a separate Tegra serial driver to deal with the clock issue
- Add new CONFIG_TEGRA_SERIAL option to enable dm driver
- Remove 'clock-frequency' property from serial nodes
- Remove clock frequency setup for ns16550 driver
- Remove pre-reloc fdt property
- Use hard-coded UART clock from Tegra configuration

Changes in v3:
- Add new change to enhance lists_bind_fdt()
- Add new patch for tegra serial port details
- Add new patch to collect common baud rate code in ns16550
- Add new patch to enable driver model for serial on tegra
- Add new patch to move baud rate calculation to ns16550.c
- Add new patch to support driver model in ns16550
- Add new patch to use V_NS16550_CLK only in SPL builds
- Automatically bind the console even if not marked for pre-relocation
- Avoid reordering functions
- Change pre-reloc fdt property to 'u-boot,dm-pre-reloc'
- Fix typo in commit message

Changes in v2:
- Add exynos serial support
- Remove RFC status
- Rename struct device to struct udevice
- Split out core driver model patches into a separate set

Simon Glass (15):
serial: Set up the 'priv' pointer when creating a serial device
dm: Adjust lists_bind_fdt() to return the bound device
dm: Add a uclass for serial devices
Set up stdio earlier when using driver model
sandbox: Convert serial driver to use driver model
sandbox: serial: Support a coloured console
sandbox: dts: Add a serial console node
dm: exynos: Mark exynos5 console as pre-reloc
dm: exynos: Move serial to driver model
dm: Make driver model available before board_init()
dm: serial: Move baud rate calculation to ns16550.c
dm: serial: Collect common baud rate code in ns16550
dm: serial: Add driver model support for ns16550
tegra: dts: Add serial port details
dm: tegra: Enable driver model for serial

 arch/arm/dts/exynos5.dtsi                          |   1 +
 arch/arm/dts/tegra114-dalmore.dts                  |   1 +
 arch/arm/dts/tegra114.dtsi                         |  35 +++
 arch/arm/dts/tegra124-jetson-tk1.dts               |   1 +
 arch/arm/dts/tegra124-venice2.dts                  |   1 +
 arch/arm/dts/tegra124.dtsi                         |  35 +++
 arch/arm/dts/tegra20-colibri_t20_iris.dts          |   1 +
 arch/arm/dts/tegra20-harmony.dts                   |   1 +
 arch/arm/dts/tegra20-medcom-wide.dts               |   1 +
 arch/arm/dts/tegra20-paz00.dts                     |   1 +
 arch/arm/dts/tegra20-plutux.dts                    |   1 +
 arch/arm/dts/tegra20-seaboard.dts                  |   1 +
 arch/arm/dts/tegra20-tec.dts                       |   1 +
 arch/arm/dts/tegra20-trimslice.dts                 |   1 +
 arch/arm/dts/tegra20-ventana.dts                   |   1 +
 arch/arm/dts/tegra20-whistler.dts                  |   1 +
 arch/arm/dts/tegra20.dtsi                          |  10 +-
 arch/arm/dts/tegra30-beaver.dts                    |   1 +
 arch/arm/dts/tegra30-cardhu.dts                    |   1 +
 arch/arm/dts/tegra30-tamonten.dtsi                 |   1 +
 arch/arm/dts/tegra30.dtsi                          |  35 +++
 arch/sandbox/dts/sandbox.dts                       |  10 +
 common/board_r.c                                   |  19 +-
 common/stdio.c                                     |  18 +-
 doc/device-tree-bindings/serial/ns16550.txt        |  10 +
 doc/device-tree-bindings/serial/sandbox-serial.txt |  13 ++
 drivers/core/lists.c                               |  10 +-
 drivers/core/root.c                                |   2 +-
 drivers/serial/Makefile                            |   7 +-
 drivers/serial/ns16550.c                           | 203 ++++++++++++++--
 drivers/serial/sandbox.c                           | 140 ++++++++---
 drivers/serial/serial-uclass.c                     | 211 +++++++++++++++++
 drivers/serial/serial.c                            |   1 +
 drivers/serial/serial_ns16550.c                    |  23 +-
 drivers/serial/serial_s5p.c                        | 255 ++++++---------------
 drivers/serial/serial_tegra.c                      |  38 +++
 include/configs/exynos-common.h                    |   1 +
 include/configs/sandbox.h                          |   3 +
 include/configs/tegra-common.h                     |  10 +-
 include/dm/lists.h                                 |   6 +-
 include/dm/uclass-id.h                             |   1 +
 include/ns16550.h                                  |  64 ++++++
 include/serial.h                                   |  92 ++++++++
 include/stdio_dev.h                                |  24 +-
 44 files changed, 1021 insertions(+), 272 deletions(-)
 create mode 100644 doc/device-tree-bindings/serial/ns16550.txt
 create mode 100644 doc/device-tree-bindings/serial/sandbox-serial.txt
 create mode 100644 drivers/serial/serial-uclass.c
 create mode 100644 drivers/serial/serial_tegra.c
Signature · 1 line
2.0.0.526.g5318336
#1 lore raw

PATCH v4 1/15 serial: Set up the 'priv' pointer when creating a serial device

The stdio_dev structure has a private pointer for its creator, but it is not set up by the serial system. Set it to point to the serial device so that it can be found by code called by stdio.

---

Changes in v4: None
Changes in v3:
- Fix typo in commit message

Changes in v2: None

 drivers/serial/serial.c | 1 +
 1 file changed, 1 insertion(+)
drivers/serial/serial.c +1 -0
index d2eb752..bbe60af 100644
@@ -320,6 +320,7 @@ void serial_stdio_init(void)
 		dev.puts = serial_stub_puts;
 		dev.getc = serial_stub_getc;
 		dev.tstc = serial_stub_tstc;
+		dev.priv = s;
 
 		stdio_register(&dev);
 
Signature · 1 line
2.0.0.526.g5318336
#2 lore raw

PATCH v4 2/15 dm: Adjust lists_bind_fdt() to return the bound device

In reply to Simon Glass

Allow the caller to find out the device that was bound in response to this call.

---

Changes in v4: None
Changes in v3:
- Add new change to enhance lists_bind_fdt()

Changes in v2: None

 drivers/core/lists.c | 10 +++++++---
 drivers/core/root.c  |  2 +-
 include/dm/lists.h   |  6 +++++-
 3 files changed, 13 insertions(+), 5 deletions(-)
drivers/core/lists.c +7 -3
index 0f08bfd..699f94b 100644
@@ -118,7 +118,8 @@ static int driver_check_compatible(const void *blob, int offset,
 	return -ENOENT;
 }
 
-int lists_bind_fdt(struct udevice *parent, const void *blob, int offset)
+int lists_bind_fdt(struct udevice *parent, const void *blob, int offset,
+		   struct udevice **devp)
 {
 	struct driver *driver = ll_entry_start(struct driver, driver);
 	const int n_ents = ll_entry_count(struct driver, driver);
@@ -130,6 +131,8 @@ int lists_bind_fdt(struct udevice *parent, const void *blob, int offset)
 	int ret = 0;
 
 	dm_dbg("bind node %s\n", fdt_get_name(blob, offset, NULL));
+	if (devp)
+		*devp = NULL;
 	for (entry = driver; entry != driver + n_ents; entry++) {
 		ret = driver_check_compatible(blob, offset, entry->of_match);
 		name = fdt_get_name(blob, offset, NULL);
@@ -149,10 +152,11 @@ int lists_bind_fdt(struct udevice *parent, const void *blob, int offset)
 		ret = device_bind(parent, entry, name, NULL, offset, &dev);
 		if (ret) {
 			dm_warn("Error binding driver '%s'\n", entry->name);
-			if (!result || ret != -ENOENT)
-				result = ret;
+			return ret;
 		} else {
 			found = true;
+			if (devp)
+				*devp = dev;
 		}
 		break;
 	}
drivers/core/root.c +1 -1
index 393dd98..a328a48 100644
@@ -91,7 +91,7 @@ int dm_scan_fdt_node(struct udevice *parent, const void *blob, int offset,
 		if (pre_reloc_only &&
 		    !fdt_getprop(blob, offset, "u-boot,dm-pre-reloc", NULL))
 			continue;
-		err = lists_bind_fdt(parent, blob, offset);
+		err = lists_bind_fdt(parent, blob, offset, NULL);
 		if (err && !ret)
 			ret = err;
 	}
include/dm/lists.h +5 -1
index 87a3af5..2356895 100644
@@ -53,7 +53,11 @@ int lists_bind_drivers(struct udevice *parent, bool pre_reloc_only);
  * @parent: parent driver (root)
  * @blob: device tree blob
  * @offset: offset of this device tree node
+ * @devp: if non-NULL, returns a pointer to the bound device
+ * @return 0 if device was bound, -EINVAL if the device tree is invalid,
+ * other -ve value on error
  */
-int lists_bind_fdt(struct udevice *parent, const void *blob, int offset);
+int lists_bind_fdt(struct udevice *parent, const void *blob, int offset,
+		   struct udevice **devp);
 
 #endif
Signature · 1 line
2.0.0.526.g5318336
#3 lore raw

PATCH v4 3/15 dm: Add a uclass for serial devices

In reply to Simon Glass

Serial devices support simple byte input/output and a few operations to find out whether data is available. Add a basic uclass for serial devices to be used by drivers that are converted to driver model.

---

Changes in v4: None
Changes in v3:
- Automatically bind the console even if not marked for pre-relocation

Changes in v2:
- Rename struct device to struct udevice

 drivers/serial/Makefile        |   4 +
 drivers/serial/serial-uclass.c | 211 +++++++++++++++++++++++++++++++++++++++++
 include/dm/uclass-id.h         |   1 +
 include/serial.h               |  92 ++++++++++++++++++
 4 files changed, 308 insertions(+)
 create mode 100644 drivers/serial/serial-uclass.c
drivers/serial/Makefile +4 -0
index 571c18f..4720e1d 100644
@@ -5,7 +5,11 @@
 # SPDX-License-Identifier:	GPL-2.0+
 #
 
+ifdef CONFIG_DM_SERIAL
+obj-y += serial-uclass.o
+else
 obj-y += serial.o
+endif
 
 obj-$(CONFIG_ALTERA_UART) += altera_uart.o
 obj-$(CONFIG_ALTERA_JTAG_UART) += altera_jtag_uart.o
drivers/serial/serial-uclass.c new file +211 -0

211 lines not on this page · raw message

include/dm/uclass-id.h +1 -0
index dd95fca..7f0e37b 100644
@@ -21,6 +21,7 @@ enum uclass_id {
 
 	/* U-Boot uclasses start here */
 	UCLASS_GPIO,		/* Bank of general-purpose I/O pins */
+	UCLASS_SERIAL,		/* Serial UART */
 
 	UCLASS_COUNT,
 	UCLASS_INVALID = -1,
include/serial.h +92 -0

96 lines not on this page · raw message

Signature · 1 line
2.0.0.526.g5318336
#4 lore raw

PATCH v4 4/15 Set up stdio earlier when using driver model

In reply to Simon Glass

Since driver model registers itself with the stdio subsystem, and we want to avoid delayed registration and other complexity associated with the current serial console, move the stdio subsystem init earlier when driver model is used for serial.

This simplifies the implementation. Should there be any problems with this approach they can be dealt with as boards are converted over to use driver model for serial.

---

Changes in v4: None
Changes in v3: None
Changes in v2: None

 common/board_r.c | 17 +++++++++++------
 1 file changed, 11 insertions(+), 6 deletions(-)
common/board_r.c +11 -6
index 8e7a3ac..2eed569 100644
@@ -726,6 +726,15 @@ init_fnc_t init_sequence_r[] = {
 	set_cpu_clk_info, /* Setup clock information */
 #endif
 	initr_reloc_global_data,
+	initr_barrier,
+	initr_malloc,
+	bootstage_relocate,
+#ifdef CONFIG_DM_SERIAL
+	stdio_init,
+#endif
+#ifdef CONFIG_DM
+	initr_dm,
+#endif
 	initr_serial,
 	initr_announce,
 	INIT_FUNC_WATCHDOG_RESET
@@ -762,12 +771,6 @@ init_fnc_t init_sequence_r[] = {
 #ifdef CONFIG_WINBOND_83C553
 	initr_w83c553f,
 #endif
-	initr_barrier,
-	initr_malloc,
-	bootstage_relocate,
-#ifdef CONFIG_DM
-	initr_dm,
-#endif
 #ifdef CONFIG_ARCH_EARLY_INIT_R
 	arch_early_init_r,
 #endif
@@ -817,7 +820,9 @@ init_fnc_t init_sequence_r[] = {
 	 */
 	initr_pci,
 #endif
+#ifndef CONFIG_DM_SERIAL
 	stdio_init,
+#endif
 	initr_jumptable,
 #ifdef CONFIG_API
 	initr_api,
Signature · 1 line
2.0.0.526.g5318336
#5 lore raw

PATCH v4 5/15 sandbox: Convert serial driver to use driver model

In reply to Simon Glass

Adjust the sandbox serial driver to use the new driver model uclass. The driver works much as before, but within the new framework.

---

Changes in v4: None
Changes in v3: None
Changes in v2:
- Rename struct device to struct udevice

 drivers/serial/sandbox.c  | 67 +++++++++++++++++++++++++----------------------
 include/configs/sandbox.h |  3 +++
 2 files changed, 39 insertions(+), 31 deletions(-)
drivers/serial/sandbox.c +36 -31
index 51fd871..ac54e01 100644
@@ -11,12 +11,16 @@
  */
 
 #include <common.h>
+#include <dm.h>
+#include <fdtdec.h>
 #include <lcd.h>
 #include <os.h>
 #include <serial.h>
 #include <linux/compiler.h>
 #include <asm/state.h>
 
+DECLARE_GLOBAL_DATA_PTR;
+
 /*
  *
  *   serial_buf: A buffer that holds keyboard characters for the
@@ -30,27 +34,21 @@ static char serial_buf[16];
 static unsigned int serial_buf_write;
 static unsigned int serial_buf_read;
 
-static int sandbox_serial_init(void)
+static int sandbox_serial_probe(struct udevice *dev)
 {
 	struct sandbox_state *state = state_get_current();
 
 	if (state->term_raw != STATE_TERM_COOKED)
 		os_tty_raw(0, state->term_raw == STATE_TERM_RAW_WITH_SIGS);
-	return 0;
-}
 
-static void sandbox_serial_setbrg(void)
-{
+	return 0;
 }
 
-static void sandbox_serial_putc(const char ch)
+static int sandbox_serial_putc(struct udevice *dev, const char ch)
 {
 	os_write(1, &ch, 1);
-}
 
-static void sandbox_serial_puts(const char *str)
-{
-	os_write(1, str, strlen(str));
+	return 0;
 }
 
 static unsigned int increment_buffer_index(unsigned int index)
@@ -58,12 +56,15 @@ static unsigned int increment_buffer_index(unsigned int index)
 	return (index + 1) % ARRAY_SIZE(serial_buf);
 }
 
-static int sandbox_serial_tstc(void)
+static int sandbox_serial_pending(struct udevice *dev, bool input)
 {
 	const unsigned int next_index =
 		increment_buffer_index(serial_buf_write);
 	ssize_t count;
 
+	if (!input)
+		return 0;
+
 	os_usleep(100);
 #ifdef CONFIG_LCD
 	lcd_sync();
@@ -74,38 +75,42 @@ static int sandbox_serial_tstc(void)
 	count = os_read_no_block(0, &serial_buf[serial_buf_write], 1);
 	if (count == 1)
 		serial_buf_write = next_index;
+
 	return serial_buf_write != serial_buf_read;
 }
 
-static int sandbox_serial_getc(void)
+static int sandbox_serial_getc(struct udevice *dev)
 {
 	int result;
 
-	while (!sandbox_serial_tstc())
-		;	/* buffer empty */
+	if (!sandbox_serial_pending(dev, true))
+		return -EAGAIN;	/* buffer empty */
 
 	result = serial_buf[serial_buf_read];
 	serial_buf_read = increment_buffer_index(serial_buf_read);
 	return result;
 }
 
-static struct serial_device sandbox_serial_drv = {
-	.name	= "sandbox_serial",
-	.start	= sandbox_serial_init,
-	.stop	= NULL,
-	.setbrg	= sandbox_serial_setbrg,
-	.putc	= sandbox_serial_putc,
-	.puts	= sandbox_serial_puts,
-	.getc	= sandbox_serial_getc,
-	.tstc	= sandbox_serial_tstc,
+static const struct dm_serial_ops sandbox_serial_ops = {
+	.putc = sandbox_serial_putc,
+	.pending = sandbox_serial_pending,
+	.getc = sandbox_serial_getc,
 };
 
-void sandbox_serial_initialize(void)
-{
-	serial_register(&sandbox_serial_drv);
-}
+static const struct udevice_id sandbox_serial_ids[] = {
+	{ .compatible = "sandbox,serial" },
+	{ }
+};
 
-__weak struct serial_device *default_serial_console(void)
-{
-	return &sandbox_serial_drv;
-}
+U_BOOT_DRIVER(serial_sandbox) = {
+	.name	= "serial_sandbox",
+	.id	= UCLASS_SERIAL,
+	.of_match = sandbox_serial_ids,
+	.probe = sandbox_serial_probe,
+	.ops	= &sandbox_serial_ops,
+	.flags = DM_FLAG_PRE_RELOC,
+};
+
+U_BOOT_DEVICE(serial_sandbox_non_fdt) = {
+	.name = "serial_sandbox",
+};
include/configs/sandbox.h +3 -0
index bf2d25c..f5fa4b3 100644
@@ -31,6 +31,9 @@
 #define CONFIG_DM_DEMO_SHAPE
 #define CONFIG_DM_GPIO
 #define CONFIG_DM_TEST
+#define CONFIG_DM_SERIAL
+
+#define CONFIG_SYS_STDIO_DEREGISTER
 
 /* Number of bits in a C 'long' on this architecture */
 #define CONFIG_SANDBOX_BITS_PER_LONG	64
Signature · 1 line
2.0.0.526.g5318336
#6 lore raw

PATCH v4 6/15 sandbox: serial: Support a coloured console

In reply to Simon Glass

The current sandbox serial driver is a pretty trivial example and does not have the featues that might be needed for other board serial drivers. To help provide a better example, add a text colour property to the device tree for sandbox. This uses platform data, a device tree node, driver private data and a remove() method.

---

Changes in v4: None
Changes in v3: None
Changes in v2:
- Rename struct device to struct udevice

 drivers/serial/sandbox.c | 83 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 83 insertions(+)
drivers/serial/sandbox.c +83 -0
index ac54e01..cd2f91e 100644
@@ -34,19 +34,67 @@ static char serial_buf[16];
 static unsigned int serial_buf_write;
 static unsigned int serial_buf_read;
 
+struct sandbox_serial_platdata {
+	int colour;	/* Text colour to use for output, -1 for none */
+};
+
+struct sandbox_serial_priv {
+	bool start_of_line;
+};
+
+/**
+ * output_ansi_colour() - Output an ANSI colour code
+ *
+ * @colour: Colour to output (0-7)
+ */
+static void output_ansi_colour(int colour)
+{
+	char ansi_code[] = "\x1b[1;3Xm";
+
+	ansi_code[5] = '0' + colour;
+	os_write(1, ansi_code, sizeof(ansi_code) - 1);
+}
+
+static void output_ansi_reset(void)
+{
+	os_write(1, "\x1b[0m", 4);
+}
+
 static int sandbox_serial_probe(struct udevice *dev)
 {
 	struct sandbox_state *state = state_get_current();
+	struct sandbox_serial_priv *priv = dev_get_priv(dev);
 
 	if (state->term_raw != STATE_TERM_COOKED)
 		os_tty_raw(0, state->term_raw == STATE_TERM_RAW_WITH_SIGS);
+	priv->start_of_line = 0;
+
+	return 0;
+}
+
+static int sandbox_serial_remove(struct udevice *dev)
+{
+	struct sandbox_serial_platdata *plat = dev->platdata;
+
+	if (plat->colour != -1)
+		output_ansi_reset();
 
 	return 0;
 }
 
 static int sandbox_serial_putc(struct udevice *dev, const char ch)
 {
+	struct sandbox_serial_priv *priv = dev_get_priv(dev);
+	struct sandbox_serial_platdata *plat = dev->platdata;
+
+	if (priv->start_of_line && plat->colour != -1) {
+		priv->start_of_line = false;
+		output_ansi_colour(plat->colour);
+	}
+
 	os_write(1, &ch, 1);
+	if (ch == '\n')
+		priv->start_of_line = true;
 
 	return 0;
 }
@@ -91,6 +139,32 @@ static int sandbox_serial_getc(struct udevice *dev)
 	return result;
 }
 
+static const char * const ansi_colour[] = {
+	"black", "red", "green", "yellow", "blue", "megenta", "cyan",
+	"white",
+};
+
+static int sandbox_serial_ofdata_to_platdata(struct udevice *dev)
+{
+	struct sandbox_serial_platdata *plat = dev->platdata;
+	const char *colour;
+	int i;
+
+	plat->colour = -1;
+	colour = fdt_getprop(gd->fdt_blob, dev->of_offset,
+			     "sandbox,text-colour", NULL);
+	if (colour) {
+		for (i = 0; i < ARRAY_SIZE(ansi_colour); i++) {
+			if (!strcmp(colour, ansi_colour[i])) {
+				plat->colour = i;
+				break;
+			}
+		}
+	}
+
+	return 0;
+}
+
 static const struct dm_serial_ops sandbox_serial_ops = {
 	.putc = sandbox_serial_putc,
 	.pending = sandbox_serial_pending,
@@ -106,11 +180,20 @@ U_BOOT_DRIVER(serial_sandbox) = {
 	.name	= "serial_sandbox",
 	.id	= UCLASS_SERIAL,
 	.of_match = sandbox_serial_ids,
+	.ofdata_to_platdata = sandbox_serial_ofdata_to_platdata,
+	.platdata_auto_alloc_size = sizeof(struct sandbox_serial_platdata),
+	.priv_auto_alloc_size = sizeof(struct sandbox_serial_priv),
 	.probe = sandbox_serial_probe,
+	.remove = sandbox_serial_remove,
 	.ops	= &sandbox_serial_ops,
 	.flags = DM_FLAG_PRE_RELOC,
 };
 
+static const struct sandbox_serial_platdata platdata_non_fdt = {
+	.colour = -1,
+};
+
 U_BOOT_DEVICE(serial_sandbox_non_fdt) = {
 	.name = "serial_sandbox",
+	.platdata = &platdata_non_fdt,
 };
Signature · 1 line
2.0.0.526.g5318336
#7 lore raw

PATCH v4 7/15 sandbox: dts: Add a serial console node

In reply to Simon Glass

If the sandbox device tree is provided to U-Boot (with the -d flag) then it will use the device tree version in preference to the built-in device. The only difference is the colour.

---

Changes in v4:
- Add a binding for sandbox serial
- Remove pre-reloc fdt property

Changes in v3:
- Change pre-reloc fdt property to 'u-boot,dm-pre-reloc'

Changes in v2: None

 arch/sandbox/dts/sandbox.dts                       | 10 ++++++++++
 doc/device-tree-bindings/serial/sandbox-serial.txt | 13 +++++++++++++
 2 files changed, 23 insertions(+)
 create mode 100644 doc/device-tree-bindings/serial/sandbox-serial.txt
arch/sandbox/dts/sandbox.dts +10 -0
index efffacb..26503e4 100644
@@ -1,6 +1,16 @@
 /dts-v1/;
 
 / {
+	aliases {
+		console = "/serial";
+	};
+
+	/* Needs to be available prior to relocation */
+	uart0: serial {
+		compatible = "sandbox,serial";
+		sandbox,text-colour = "cyan";
+	};
+
 	triangle {
 		compatible = "demo-shape";
 		colour = "cyan";
doc/device-tree-bindings/serial/sandbox-serial.txt new file +13 -0
new file mode 100644
index 0000000..f429c90
@@ -0,0 +1,13 @@
+Sandbox serial
+
+The sandbox serial device is an emulated device which displays its output
+on the host machine's console, and accepts input from its keyboard.
+
+Required properties:
+  compatible: "sandbox,serial"
+
+Optional properties:
+  sandbox,text-colour: If present, this is the colour of the console text.
+        Supported values are:
+        "black", "red", "green", "yellow", "blue", "megenta", "cyan",
+        "white"
Signature · 1 line
2.0.0.526.g5318336
#8 lore raw

PATCH v4 8/15 dm: exynos: Mark exynos5 console as pre-reloc

In reply to Simon Glass

We will need the console before relocation, so mark it that way.

---

Changes in v4: None
Changes in v3:
- Change pre-reloc fdt property to 'u-boot,dm-pre-reloc'

Changes in v2: None

 arch/arm/dts/exynos5.dtsi | 1 +
 1 file changed, 1 insertion(+)
arch/arm/dts/exynos5.dtsi +1 -0
index dc5405b..e539068 100644
@@ -244,6 +244,7 @@
 		compatible = "samsung,exynos4210-uart";
 		reg = <0x12C30000 0x100>;
 		interrupts = <0 54 0>;
+		u-boot,dm-pre-reloc;
 		id = <3>;
 	};
 
Signature · 1 line
2.0.0.526.g5318336
#9 lore raw

PATCH v4 9/15 dm: exynos: Move serial to driver model

In reply to Simon Glass

Change the Exynos serial driver to work with driver model and switch over all Exynos5 boards to use it.

---

Changes in v4: None
Changes in v3:
- Avoid reordering functions

Changes in v2: None

 drivers/serial/serial_s5p.c     | 255 ++++++++++++----------------------------
 include/configs/exynos-common.h |   1 +
 2 files changed, 73 insertions(+), 183 deletions(-)
drivers/serial/serial_s5p.c +72 -183
index 98c62b4..8469afd 100644
@@ -9,6 +9,8 @@
  */
 
 #include <common.h>
+#include <dm.h>
+#include <errno.h>
 #include <fdtdec.h>
 #include <linux/compiler.h>
 #include <asm/io.h>
@@ -18,26 +20,18 @@
 
 DECLARE_GLOBAL_DATA_PTR;
 
-#define RX_FIFO_COUNT_MASK	0xff
-#define RX_FIFO_FULL_MASK	(1 << 8)
-#define TX_FIFO_FULL_MASK	(1 << 24)
+#define RX_FIFO_COUNT_SHIFT	0
+#define RX_FIFO_COUNT_MASK	(0xff << RX_FIFO_COUNT_SHIFT)
+#define RX_FIFO_FULL		(1 << 8)
+#define TX_FIFO_COUNT_SHIFT	16
+#define TX_FIFO_COUNT_MASK	(0xff << TX_FIFO_COUNT_SHIFT)
+#define TX_FIFO_FULL		(1 << 24)
 
 /* Information about a serial port */
-struct fdt_serial {
-	u32 base_addr;  /* address of registers in physical memory */
+struct s5p_serial_platdata {
+	struct s5p_uart *reg;  /* address of registers in physical memory */
 	u8 port_id;     /* uart port number */
-	u8 enabled;     /* 1 if enabled, 0 if disabled */
-} config __attribute__ ((section(".data")));
-
-static inline struct s5p_uart *s5p_get_base_uart(int dev_index)
-{
-#ifdef CONFIG_OF_CONTROL
-	return (struct s5p_uart *)(config.base_addr);
-#else
-	u32 offset = dev_index * sizeof(struct s5p_uart);
-	return (struct s5p_uart *)(samsung_get_base_uart() + offset);
-#endif
-}
+};
 
 /*
  * The coefficient, used to calculate the baudrate on S5P UARTs is
@@ -65,23 +59,13 @@ static const int udivslot[] = {
 	0xffdf,
 };
 
-static void serial_setbrg_dev(const int dev_index)
+int s5p_serial_setbrg(struct udevice *dev, int baudrate)
 {
-	struct s5p_uart *const uart = s5p_get_base_uart(dev_index);
-	u32 uclk = get_uart_clk(dev_index);
-	u32 baudrate = gd->baudrate;
+	struct s5p_serial_platdata *plat = dev->platdata;
+	struct s5p_uart *const uart = plat->reg;
+	u32 uclk = get_uart_clk(plat->port_id);
 	u32 val;
 
-#if defined(CONFIG_SILENT_CONSOLE) && \
-		defined(CONFIG_OF_CONTROL) && \
-		!defined(CONFIG_SPL_BUILD)
-	if (fdtdec_get_config_int(gd->fdt_blob, "silent_console", 0))
-		gd->flags |= GD_FLG_SILENT;
-#endif
-
-	if (!config.enabled)
-		return;
-
 	val = uclk / baudrate;
 
 	writel(val / 16 - 1, &uart->ubrdiv);
@@ -90,15 +74,14 @@ static void serial_setbrg_dev(const int dev_index)
 		writew(udivslot[val % 16], &uart->rest.slot);
 	else
 		writeb(val % 16, &uart->rest.value);
+
+	return 0;
 }
 
-/*
- * Initialise the serial port with the given baudrate. The settings
- * are always 8 data bits, no parity, 1 stop bit, no start bits.
- */
-static int serial_init_dev(const int dev_index)
+static int s5p_serial_probe(struct udevice *dev)
 {
-	struct s5p_uart *const uart = s5p_get_base_uart(dev_index);
+	struct s5p_serial_platdata *plat = dev->platdata;
+	struct s5p_uart *const uart = plat->reg;
 
 	/* enable FIFOs, auto clear Rx FIFO */
 	writel(0x3, &uart->ufcon);
@@ -108,14 +91,11 @@ static int serial_init_dev(const int dev_index)
 	/* No interrupts, no DMA, pure polling */
 	writel(0x245, &uart->ucon);
 
-	serial_setbrg_dev(dev_index);
-
 	return 0;
 }
 
-static int serial_err_check(const int dev_index, int op)
+static int serial_err_check(const struct s5p_uart *const uart, int op)
 {
-	struct s5p_uart *const uart = s5p_get_base_uart(dev_index);
 	unsigned int mask;
 
 	/*
@@ -133,169 +113,78 @@ static int serial_err_check(const int dev_index, int op)
 	return readl(&uart->uerstat) & mask;
 }
 
-/*
- * Read a single byte from the serial port. Returns 1 on success, 0
- * otherwise. When the function is succesfull, the character read is
- * written into its argument c.
- */
-static int serial_getc_dev(const int dev_index)
+static int s5p_serial_getc(struct udevice *dev)
 {
-	struct s5p_uart *const uart = s5p_get_base_uart(dev_index);
-
-	if (!config.enabled)
-		return 0;
+	struct s5p_serial_platdata *plat = dev->platdata;
+	struct s5p_uart *const uart = plat->reg;
 
-	/* wait for character to arrive */
-	while (!(readl(&uart->ufstat) & (RX_FIFO_COUNT_MASK |
-					 RX_FIFO_FULL_MASK))) {
-		if (serial_err_check(dev_index, 0))
-			return 0;
-	}
+	if (!(readl(&uart->ufstat) & RX_FIFO_COUNT_MASK))
+		return -EAGAIN;
 
+	serial_err_check(uart, 0);
 	return (int)(readb(&uart->urxh) & 0xff);
 }
 
-/*
- * Output a single byte to the serial port.
- */
-static void serial_putc_dev(const char c, const int dev_index)
+static int s5p_serial_putc(struct udevice *dev, const char ch)
 {
-	struct s5p_uart *const uart = s5p_get_base_uart(dev_index);
-
-	if (!config.enabled)
-		return;
-
-	/* wait for room in the tx FIFO */
-	while ((readl(&uart->ufstat) & TX_FIFO_FULL_MASK)) {
-		if (serial_err_check(dev_index, 1))
-			return;
-	}
+	struct s5p_serial_platdata *plat = dev->platdata;
+	struct s5p_uart *const uart = plat->reg;
 
-	writeb(c, &uart->utxh);
+	if (readl(&uart->ufstat) & TX_FIFO_FULL)
+		return -EAGAIN;
 
-	/* If \n, also do \r */
-	if (c == '\n')
-		serial_putc('\r');
-}
-
-/*
- * Test whether a character is in the RX buffer
- */
-static int serial_tstc_dev(const int dev_index)
-{
-	struct s5p_uart *const uart = s5p_get_base_uart(dev_index);
+	writeb(ch, &uart->utxh);
+	serial_err_check(uart, 1);
 
-	if (!config.enabled)
-		return 0;
-
-	return (int)(readl(&uart->utrstat) & 0x1);
+	return 0;
 }
 
-static void serial_puts_dev(const char *s, const int dev_index)
+static int s5p_serial_pending(struct udevice *dev, bool input)
 {
-	while (*s)
-		serial_putc_dev(*s++, dev_index);
-}
+	struct s5p_serial_platdata *plat = dev->platdata;
+	struct s5p_uart *const uart = plat->reg;
+	uint32_t ufstat = readl(&uart->ufstat);
 
-/* Multi serial device functions */
-#define DECLARE_S5P_SERIAL_FUNCTIONS(port) \
-static int s5p_serial##port##_init(void) { return serial_init_dev(port); } \
-static void s5p_serial##port##_setbrg(void) { serial_setbrg_dev(port); } \
-static int s5p_serial##port##_getc(void) { return serial_getc_dev(port); } \
-static int s5p_serial##port##_tstc(void) { return serial_tstc_dev(port); } \
-static void s5p_serial##port##_putc(const char c) { serial_putc_dev(c, port); } \
-static void s5p_serial##port##_puts(const char *s) { serial_puts_dev(s, port); }
-
-#define INIT_S5P_SERIAL_STRUCTURE(port, __name) {	\
-	.name	= __name,				\
-	.start	= s5p_serial##port##_init,		\
-	.stop	= NULL,					\
-	.setbrg	= s5p_serial##port##_setbrg,		\
-	.getc	= s5p_serial##port##_getc,		\
-	.tstc	= s5p_serial##port##_tstc,		\
-	.putc	= s5p_serial##port##_putc,		\
-	.puts	= s5p_serial##port##_puts,		\
+	if (input)
+		return (ufstat & RX_FIFO_COUNT_MASK) >> RX_FIFO_COUNT_SHIFT;
+	else
+		return (ufstat & TX_FIFO_COUNT_MASK) >> TX_FIFO_COUNT_SHIFT;
 }
 
-DECLARE_S5P_SERIAL_FUNCTIONS(0);
-struct serial_device s5p_serial0_device =
-	INIT_S5P_SERIAL_STRUCTURE(0, "s5pser0");
-DECLARE_S5P_SERIAL_FUNCTIONS(1);
-struct serial_device s5p_serial1_device =
-	INIT_S5P_SERIAL_STRUCTURE(1, "s5pser1");
-DECLARE_S5P_SERIAL_FUNCTIONS(2);
-struct serial_device s5p_serial2_device =
-	INIT_S5P_SERIAL_STRUCTURE(2, "s5pser2");
-DECLARE_S5P_SERIAL_FUNCTIONS(3);
-struct serial_device s5p_serial3_device =
-	INIT_S5P_SERIAL_STRUCTURE(3, "s5pser3");
-
-#ifdef CONFIG_OF_CONTROL
-int fdtdec_decode_console(int *index, struct fdt_serial *uart)
+static int s5p_serial_ofdata_to_platdata(struct udevice *dev)
 {
-	const void *blob = gd->fdt_blob;
-	int node;
+	struct s5p_serial_platdata *plat = dev->platdata;
+	fdt_addr_t addr;
 
-	node = fdt_path_offset(blob, "console");
-	if (node < 0)
-		return node;
+	addr = fdtdec_get_addr(gd->fdt_blob, dev->of_offset, "reg");
+	if (addr == FDT_ADDR_T_NONE)
+		return -EINVAL;
 
-	uart->base_addr = fdtdec_get_addr(blob, node, "reg");
-	if (uart->base_addr == FDT_ADDR_T_NONE)
-		return -FDT_ERR_NOTFOUND;
-
-	uart->port_id = fdtdec_get_int(blob, node, "id", -1);
-	uart->enabled = fdtdec_get_is_enabled(blob, node);
+	plat->reg = (struct s5p_uart *)addr;
+	plat->port_id = fdtdec_get_int(gd->fdt_blob, dev->of_offset, "id", -1);
 
 	return 0;
 }
-#endif
 
-__weak struct serial_device *default_serial_console(void)
-{
-#ifdef CONFIG_OF_CONTROL
-	int index = 0;
-
-	if ((!config.base_addr) && (fdtdec_decode_console(&index, &config))) {
-		debug("Cannot decode default console node\n");
-		return NULL;
-	}
-
-	switch (config.port_id) {
-	case 0:
-		return &s5p_serial0_device;
-	case 1:
-		return &s5p_serial1_device;
-	case 2:
-		return &s5p_serial2_device;
-	case 3:
-		return &s5p_serial3_device;
-	default:
-		debug("Unknown config.port_id: %d", config.port_id);
-		break;
-	}
-
-	return NULL;
-#else
-	config.enabled = 1;
-#if defined(CONFIG_SERIAL0)
-	return &s5p_serial0_device;
-#elif defined(CONFIG_SERIAL1)
-	return &s5p_serial1_device;
-#elif defined(CONFIG_SERIAL2)
-	return &s5p_serial2_device;
-#elif defined(CONFIG_SERIAL3)
-	return &s5p_serial3_device;
-#else
-#error "CONFIG_SERIAL? missing."
-#endif
-#endif
-}
+static const struct dm_serial_ops s5p_serial_ops = {
+	.putc = s5p_serial_putc,
+	.pending = s5p_serial_pending,
+	.getc = s5p_serial_getc,
+	.setbrg = s5p_serial_setbrg,
+};
 
-void s5p_serial_initialize(void)
-{
-	serial_register(&s5p_serial0_device);
-	serial_register(&s5p_serial1_device);
-	serial_register(&s5p_serial2_device);
-	serial_register(&s5p_serial3_device);
-}
+static const struct udevice_id s5p_serial_ids[] = {
+	{ .compatible = "samsung,exynos4210-uart" },
+	{ }
+};
+
+U_BOOT_DRIVER(serial_s5p) = {
+	.name	= "serial_s5p",
+	.id	= UCLASS_SERIAL,
+	.of_match = s5p_serial_ids,
+	.ofdata_to_platdata = s5p_serial_ofdata_to_platdata,
+	.platdata_auto_alloc_size = sizeof(struct s5p_serial_platdata),
+	.probe = s5p_serial_probe,
+	.ops	= &s5p_serial_ops,
+	.flags = DM_FLAG_PRE_RELOC,
+};
include/configs/exynos-common.h +1 -0
index 79dd9dc..b8d81c5 100644
@@ -20,6 +20,7 @@
 #define CONFIG_DM
 #define CONFIG_CMD_DM
 #define CONFIG_DM_GPIO
+#define CONFIG_DM_SERIAL
 
 #define CONFIG_ARCH_CPU_INIT
 #define CONFIG_DISPLAY_CPUINFO
Signature · 1 line
2.0.0.526.g5318336
#10 lore raw

PATCH v4 10/15 dm: Make driver model available before board_init()

In reply to Simon Glass

For some boards board_init() will change GPIOs, so we need to have driver model available before then. Adjust the board init to arrange this, but enable it for driver model only, just to be safe.

This does create additional #ifdef logic, but it is safer than trying to make a pervasive change which may cause some boards to break.

---

Changes in v4: None
Changes in v3: None
Changes in v2:
- Add exynos serial support
- Remove RFC status
- Split out core driver model patches into a separate set

 common/board_r.c    | 24 +++++++++++-------------
 common/stdio.c      | 18 ++++++++++++++++--
 include/stdio_dev.h | 24 +++++++++++++++++++++++-
 3 files changed, 50 insertions(+), 16 deletions(-)
common/board_r.c +11 -13
index 2eed569..e98ac9c 100644
@@ -714,6 +714,15 @@ init_fnc_t init_sequence_r[] = {
 	/* TODO: could x86/PPC have this also perhaps? */
 #ifdef CONFIG_ARM
 	initr_caches,
+#endif
+	initr_reloc_global_data,
+	initr_barrier,
+	initr_malloc,
+	bootstage_relocate,
+#ifdef CONFIG_DM
+	initr_dm,
+#endif
+#ifdef CONFIG_ARM
 	board_init,	/* Setup chipselects */
 #endif
 	/*
@@ -725,16 +734,7 @@ init_fnc_t init_sequence_r[] = {
 #ifdef CONFIG_CLOCKS
 	set_cpu_clk_info, /* Setup clock information */
 #endif
-	initr_reloc_global_data,
-	initr_barrier,
-	initr_malloc,
-	bootstage_relocate,
-#ifdef CONFIG_DM_SERIAL
-	stdio_init,
-#endif
-#ifdef CONFIG_DM
-	initr_dm,
-#endif
+	stdio_init_tables,
 	initr_serial,
 	initr_announce,
 	INIT_FUNC_WATCHDOG_RESET
@@ -820,9 +820,7 @@ init_fnc_t init_sequence_r[] = {
 	 */
 	initr_pci,
 #endif
-#ifndef CONFIG_DM_SERIAL
-	stdio_init,
-#endif
+	stdio_add_devices,
 	initr_jumptable,
 #ifdef CONFIG_API
 	initr_api,
common/stdio.c +16 -2
index 692ca7f..c878103 100644
@@ -215,7 +215,7 @@ int stdio_deregister(const char *devname)
 }
 #endif	/* CONFIG_SYS_STDIO_DEREGISTER */
 
-int stdio_init (void)
+int stdio_init_tables(void)
 {
 #if defined(CONFIG_NEEDS_MANUAL_RELOC)
 	/* already relocated for current ARM implementation */
@@ -232,6 +232,11 @@ int stdio_init (void)
 	/* Initialize the list */
 	INIT_LIST_HEAD(&(devs.list));
 
+	return 0;
+}
+
+int stdio_add_devices(void)
+{
 #ifdef CONFIG_SYS_I2C
 	i2c_init_all();
 #else
@@ -265,5 +270,14 @@ int stdio_init (void)
 #ifdef CONFIG_CBMEM_CONSOLE
 	cbmemc_init();
 #endif
-	return (0);
+
+	return 0;
+}
+
+int stdio_init(void)
+{
+	stdio_init_tables();
+	stdio_add_devices();
+
+	return 0;
 }
include/stdio_dev.h +23 -1
index a7d0825..268de8e 100644
@@ -78,7 +78,29 @@ extern char *stdio_names[MAX_FILES];
  */
 int	stdio_register (struct stdio_dev * dev);
 int stdio_register_dev(struct stdio_dev *dev, struct stdio_dev **devp);
-int	stdio_init (void);
+
+/**
+ * stdio_init_tables() - set up stdio tables ready for devices
+ *
+ * This does not add any devices, but just prepares stdio for use.
+ */
+int stdio_init_tables(void);
+
+/**
+ * stdio_add_devices() - Add stdio devices to the table
+ *
+ * This makes calls to all the various subsystems that use stdio, to make
+ * them register with stdio.
+ */
+int stdio_add_devices(void);
+
+/**
+ * stdio_init() - Sets up stdio ready for use
+ *
+ * This calls stdio_init_tables() and stdio_add_devices()
+ */
+int stdio_init(void);
+
 void	stdio_print_current_devices(void);
 #ifdef CONFIG_SYS_STDIO_DEREGISTER
 int	stdio_deregister(const char *devname);
Signature · 1 line
2.0.0.526.g5318336
#11 lore raw

PATCH v4 11/15 dm: serial: Move baud rate calculation to ns16550.c

In reply to Simon Glass

Move the function that calculates the baud rate divisor into ns16550.c so it can be used by that file.

---

Changes in v4: None
Changes in v3:
- Add new patch to move baud rate calculation to ns16550.c

Changes in v2: None

 drivers/serial/ns16550.c        | 18 +++++++++++++++++-
 drivers/serial/serial_ns16550.c | 23 ++++-------------------
 include/ns16550.h               | 13 +++++++++++++
 3 files changed, 34 insertions(+), 20 deletions(-)
drivers/serial/ns16550.c +17 -1
index 8e7052d..dbea5f0 100644
@@ -4,7 +4,7 @@
  * modified to use CONFIG_SYS_ISA_MEM and new defines
  */
 
-#include <config.h>
+#include <common.h>
 #include <ns16550.h>
 #include <watchdog.h>
 #include <linux/types.h>
@@ -45,6 +45,22 @@
 #define CONFIG_SYS_NS16550_IER  0x00
 #endif /* CONFIG_SYS_NS16550_IER */
 
+int ns16550_calc_divisor(NS16550_t port, int clock, int baudrate)
+{
+	const unsigned int mode_x_div = 16;
+
+#ifdef CONFIG_OMAP1510
+	/* If can't cleanly clock 115200 set div to 1 */
+	if ((clock == 12000000) && (baudrate == 115200)) {
+		port->osc_12m_sel = OSC_12M_SEL;  /* enable 6.5 * divisor */
+		return 1;			/* return 1 for base divisor */
+	}
+	port->osc_12m_sel = 0;			/* clear if previsouly set */
+#endif
+
+	return DIV_ROUND_CLOSEST(clock, mode_x_div * baudrate);
+}
+
 void NS16550_init(NS16550_t com_port, int baud_divisor)
 {
 #if (defined(CONFIG_SPL_BUILD) && defined(CONFIG_OMAP34XX))
drivers/serial/serial_ns16550.c +4 -19
index 4413e69..632da4c 100644
@@ -81,7 +81,8 @@ static NS16550_t serial_ports[6] = {
 	static int  eserial##port##_init(void) \
 	{ \
 		int clock_divisor; \
-		clock_divisor = calc_divisor(serial_ports[port-1]); \
+		clock_divisor = ns16550_calc_divisor(serial_ports[port-1], \
+				CONFIG_SYS_NS16550_CLK, gd->baudrate); \
 		NS16550_init(serial_ports[port-1], clock_divisor); \
 		return 0 ; \
 	} \
@@ -118,23 +119,6 @@ static NS16550_t serial_ports[6] = {
 	.puts	= eserial##port##_puts,		\
 }
 
-static int calc_divisor (NS16550_t port)
-{
-	const unsigned int mode_x_div = 16;
-
-#ifdef CONFIG_OMAP1510
-	/* If can't cleanly clock 115200 set div to 1 */
-	if ((CONFIG_SYS_NS16550_CLK == 12000000) && (gd->baudrate == 115200)) {
-		port->osc_12m_sel = OSC_12M_SEL;	/* enable 6.5 * divisor */
-		return (1);				/* return 1 for base divisor */
-	}
-	port->osc_12m_sel = 0;			/* clear if previsouly set */
-#endif
-
-	return DIV_ROUND_CLOSEST(CONFIG_SYS_NS16550_CLK,
-						mode_x_div * gd->baudrate);
-}
-
 void
 _serial_putc(const char c,const int port)
 {
@@ -176,7 +160,8 @@ _serial_setbrg (const int port)
 {
 	int clock_divisor;
 
-	clock_divisor = calc_divisor(PORT);
+	clock_divisor = ns16550_calc_divisor(PORT, CONFIG_SYS_NS16550_CLK,
+					     gd->baudrate);
 	NS16550_reinit(PORT, clock_divisor);
 }
 
include/ns16550.h +13 -0
index 17f829f..b106f8a 100644
@@ -177,3 +177,16 @@ void NS16550_putc(NS16550_t com_port, char c);
 char NS16550_getc(NS16550_t com_port);
 int NS16550_tstc(NS16550_t com_port);
 void NS16550_reinit(NS16550_t com_port, int baud_divisor);
+
+/**
+ * ns16550_calc_divisor() - calculate the divisor given clock and baud rate
+ *
+ * Given the UART input clock and required baudrate, calculate the divisor
+ * that should be used.
+ *
+ * @port:	UART port
+ * @clock:	UART input clock speed in Hz
+ * @baudrate:	Required baud rate
+ * @return baud rate divisor that should be used
+ */
+int ns16550_calc_divisor(NS16550_t port, int clock, int baudrate);
Signature · 1 line
2.0.0.526.g5318336
#12 lore raw

PATCH v4 12/15 dm: serial: Collect common baud rate code in ns16550

In reply to Simon Glass

The same sequence is used in several places, so move it into a function. Note that UART_LCR_BKSE is an alias for UART_LCR_DLAB.

---

Changes in v4: None
Changes in v3:
- Add new patch to collect common baud rate code in ns16550

Changes in v2: None

 drivers/serial/ns16550.c | 33 +++++++++++++--------------------
 1 file changed, 13 insertions(+), 20 deletions(-)
drivers/serial/ns16550.c +13 -20
index dbea5f0..185e7a8 100644
@@ -61,6 +61,14 @@ int ns16550_calc_divisor(NS16550_t port, int clock, int baudrate)
 	return DIV_ROUND_CLOSEST(clock, mode_x_div * baudrate);
 }
 
+static void NS16550_setbrg(NS16550_t com_port, int baud_divisor)
+{
+	serial_out(UART_LCR_BKSE | UART_LCRVAL, &com_port->lcr);
+	serial_out(baud_divisor & 0xff, &com_port->dll);
+	serial_out((baud_divisor >> 8) & 0xff, &com_port->dlm);
+	serial_out(UART_LCRVAL, &com_port->lcr);
+}
+
 void NS16550_init(NS16550_t com_port, int baud_divisor)
 {
 #if (defined(CONFIG_SPL_BUILD) && defined(CONFIG_OMAP34XX))
@@ -71,10 +79,7 @@ void NS16550_init(NS16550_t com_port, int baud_divisor)
 	 */
 	if ((serial_in(&com_port->lsr) & (UART_LSR_TEMT | UART_LSR_THRE))
 	     == UART_LSR_THRE) {
-		serial_out(UART_LCR_DLAB, &com_port->lcr);
-		serial_out(baud_divisor & 0xff, &com_port->dll);
-		serial_out((baud_divisor >> 8) & 0xff, &com_port->dlm);
-		serial_out(UART_LCRVAL, &com_port->lcr);
+		NS16550_setbrg(com_port, baud_divisor);
 		serial_out(0, &com_port->mdr1);
 	}
 #endif
@@ -87,16 +92,10 @@ void NS16550_init(NS16550_t com_port, int baud_divisor)
 			defined(CONFIG_TI81XX) || defined(CONFIG_AM43XX)
 	serial_out(0x7, &com_port->mdr1);	/* mode select reset TL16C750*/
 #endif
-	serial_out(UART_LCR_BKSE | UART_LCRVAL, &com_port->lcr);
-	serial_out(0, &com_port->dll);
-	serial_out(0, &com_port->dlm);
-	serial_out(UART_LCRVAL, &com_port->lcr);
+	NS16550_setbrg(com_port, 0);
 	serial_out(UART_MCRVAL, &com_port->mcr);
 	serial_out(UART_FCRVAL, &com_port->fcr);
-	serial_out(UART_LCR_BKSE | UART_LCRVAL, &com_port->lcr);
-	serial_out(baud_divisor & 0xff, &com_port->dll);
-	serial_out((baud_divisor >> 8) & 0xff, &com_port->dlm);
-	serial_out(UART_LCRVAL, &com_port->lcr);
+	NS16550_setbrg(com_port, baud_divisor);
 #if (defined(CONFIG_OMAP) && !defined(CONFIG_OMAP3_ZOOM2)) || \
 	defined(CONFIG_AM33XX) || defined(CONFIG_SOC_DA8XX) || \
 	defined(CONFIG_TI81XX) || defined(CONFIG_AM43XX)
@@ -113,16 +112,10 @@ void NS16550_init(NS16550_t com_port, int baud_divisor)
 void NS16550_reinit(NS16550_t com_port, int baud_divisor)
 {
 	serial_out(CONFIG_SYS_NS16550_IER, &com_port->ier);
-	serial_out(UART_LCR_BKSE | UART_LCRVAL, &com_port->lcr);
-	serial_out(0, &com_port->dll);
-	serial_out(0, &com_port->dlm);
-	serial_out(UART_LCRVAL, &com_port->lcr);
+	NS16550_setbrg(com_port, 0);
 	serial_out(UART_MCRVAL, &com_port->mcr);
 	serial_out(UART_FCRVAL, &com_port->fcr);
-	serial_out(UART_LCR_BKSE, &com_port->lcr);
-	serial_out(baud_divisor & 0xff, &com_port->dll);
-	serial_out((baud_divisor >> 8) & 0xff, &com_port->dlm);
-	serial_out(UART_LCRVAL, &com_port->lcr);
+	NS16550_setbrg(com_port, baud_divisor);
 }
 #endif /* CONFIG_NS16550_MIN_FUNCTIONS */
 
Signature · 1 line
2.0.0.526.g5318336
#13 lore raw

PATCH v4 13/15 dm: serial: Add driver model support for ns16550

In reply to Simon Glass

Add driver model support so that ns16550 can support operation both with and without driver model.

The driver needs a clock frequency so cannot stand alone unfortunately. The clock frequency must be provided by a separate driver.

---

Changes in v4:
- Remove clock frequency setup for ns16550 driver

Changes in v3:
- Add new patch to support driver model in ns16550

Changes in v2: None

 doc/device-tree-bindings/serial/ns16550.txt |  10 ++
 drivers/serial/Makefile                     |   2 +-
 drivers/serial/ns16550.c                    | 156 +++++++++++++++++++++++++++-
 include/ns16550.h                           |  51 +++++++++
 4 files changed, 216 insertions(+), 3 deletions(-)
 create mode 100644 doc/device-tree-bindings/serial/ns16550.txt
doc/device-tree-bindings/serial/ns16550.txt new file +10 -0
new file mode 100644
index 0000000..ef0b9ae
@@ -0,0 +1,10 @@
+NS16550 UART
+
+This UART driver supports many chip variants and is used in mamy SoCs.
+
+Required properties:
+- compatible: "ns16550" or "nvidia,tegra20-uart"
+- reg: start address and size of registers
+- reg-shift: shift value indicating register size: 0=byte, 1=16bit,2=32bit etc.
+- clock-frequency: input clock frequency for the UART (used to calculate the
+    baud rate divisor)
drivers/serial/Makefile +1 -1
index 4720e1d..5ae6416 100644
@@ -9,6 +9,7 @@ ifdef CONFIG_DM_SERIAL
 obj-y += serial-uclass.o
 else
 obj-y += serial.o
+obj-$(CONFIG_SYS_NS16550_SERIAL) += serial_ns16550.o
 endif
 
 obj-$(CONFIG_ALTERA_UART) += altera_uart.o
@@ -20,7 +21,6 @@ obj-$(CONFIG_MCFUART) += mcfuart.o
 obj-$(CONFIG_OPENCORES_YANU) += opencores_yanu.o
 obj-$(CONFIG_SYS_NS16550) += ns16550.o
 obj-$(CONFIG_S5P) += serial_s5p.o
-obj-$(CONFIG_SYS_NS16550_SERIAL) += serial_ns16550.o
 obj-$(CONFIG_IMX_SERIAL) += serial_imx.o
 obj-$(CONFIG_KS8695_SERIAL) += serial_ks8695.o
 obj-$(CONFIG_MAX3100_SERIAL) += serial_max3100.o
drivers/serial/ns16550.c +154 -2

200 lines not on this page · raw message

include/ns16550.h +51 -0

72 lines not on this page · raw message

Signature · 1 line
2.0.0.526.g5318336
#14 lore raw

PATCH v4 14/15 tegra: dts: Add serial port details

In reply to Simon Glass

Some Tegra device tree files do not include information about the serial ports. Add this and also add information about the input clock speed.

The console alias needs to be set up to indicate which port is used for the console.

Also add a binding file since this is missing.

---

Changes in v4:
- Remove 'clock-frequency' property from serial nodes

Changes in v3:
- Add new patch for tegra serial port details

Changes in v2: None

 arch/arm/dts/tegra114-dalmore.dts         |  1 +
 arch/arm/dts/tegra114.dtsi                | 35 +++++++++++++++++++++++++++++++
 arch/arm/dts/tegra124-jetson-tk1.dts      |  1 +
 arch/arm/dts/tegra124-venice2.dts         |  1 +
 arch/arm/dts/tegra124.dtsi                | 35 +++++++++++++++++++++++++++++++
 arch/arm/dts/tegra20-colibri_t20_iris.dts |  1 +
 arch/arm/dts/tegra20-harmony.dts          |  1 +
 arch/arm/dts/tegra20-medcom-wide.dts      |  1 +
 arch/arm/dts/tegra20-paz00.dts            |  1 +
 arch/arm/dts/tegra20-plutux.dts           |  1 +
 arch/arm/dts/tegra20-seaboard.dts         |  1 +
 arch/arm/dts/tegra20-tec.dts              |  1 +
 arch/arm/dts/tegra20-trimslice.dts        |  1 +
 arch/arm/dts/tegra20-ventana.dts          |  1 +
 arch/arm/dts/tegra20-whistler.dts         |  1 +
 arch/arm/dts/tegra20.dtsi                 | 10 ++++-----
 arch/arm/dts/tegra30-beaver.dts           |  1 +
 arch/arm/dts/tegra30-cardhu.dts           |  1 +
 arch/arm/dts/tegra30-tamonten.dtsi        |  1 +
 arch/arm/dts/tegra30.dtsi                 | 35 +++++++++++++++++++++++++++++++
 20 files changed, 126 insertions(+), 5 deletions(-)
arch/arm/dts/tegra114-dalmore.dts +1 -0
index 435c01e..e2426ef 100644
@@ -7,6 +7,7 @@
 	compatible = "nvidia,dalmore", "nvidia,tegra114";
 
 	aliases {
+		console = &uart_d;
 		i2c0 = "/i2c at 7000d000";
 		i2c1 = "/i2c at 7000c000";
 		i2c2 = "/i2c at 7000c400";
arch/arm/dts/tegra114.dtsi +35 -0
index 59434e0..5f29ded 100644
@@ -116,6 +116,41 @@
 		status = "disabled";
 	};
 
+	uart_a: serial at 70006000 {
+		compatible = "nvidia,tegra20-uart";
+		reg = <0x70006000 0x40>;
+		reg-shift = <2>;
+		interrupts = < 68 >;
+	};
+
+	uart_b: serial at 70006040 {
+		compatible = "nvidia,tegra20-uart";
+		reg = <0x70006040 0x40>;
+		reg-shift = <2>;
+		interrupts = < 69 >;
+	};
+
+	uart_c: serial at 70006200 {
+		compatible = "nvidia,tegra20-uart";
+		reg = <0x70006200 0x100>;
+		reg-shift = <2>;
+		interrupts = < 78 >;
+	};
+
+	uart_d: serial at 70006300 {
+		compatible = "nvidia,tegra20-uart";
+		reg = <0x70006300 0x100>;
+		reg-shift = <2>;
+		interrupts = < 122 >;
+	};
+
+	uart_e: serial at 70006400 {
+		compatible = "nvidia,tegra20-uart";
+		reg = <0x70006400 0x100>;
+		reg-shift = <2>;
+		interrupts = < 123 >;
+	};
+
 	spi at 7000d400 {
 		compatible = "nvidia,tegra114-spi";
 		reg = <0x7000d400 0x200>;
arch/arm/dts/tegra124-jetson-tk1.dts +1 -0
index 464287e..368caaa 100644
@@ -7,6 +7,7 @@
 	compatible = "nvidia,jetson-tk1", "nvidia,tegra124";
 
 	aliases {
+		console = &uart_d;
 		i2c0 = "/i2c at 7000d000";
 		i2c1 = "/i2c at 7000c000";
 		i2c2 = "/i2c at 7000c400";
arch/arm/dts/tegra124-venice2.dts +1 -0
index f003413..4444155 100644
@@ -7,6 +7,7 @@
 	compatible = "nvidia,venice2", "nvidia,tegra124";
 
 	aliases {
+		console = &uart_a;
 		i2c0 = "/i2c at 7000d000";
 		i2c1 = "/i2c at 7000c000";
 		i2c2 = "/i2c at 7000c400";
arch/arm/dts/tegra124.dtsi +35 -0
index 4561c5f..bd26227 100644
@@ -126,6 +126,41 @@
 		status = "disabled";
 	};
 
+	uart_a: serial at 70006000 {
+		compatible = "nvidia,tegra20-uart";
+		reg = <0x70006000 0x40>;
+		reg-shift = <2>;
+		interrupts = < 68 >;
+	};
+
+	uart_b: serial at 70006040 {
+		compatible = "nvidia,tegra20-uart";
+		reg = <0x70006040 0x40>;
+		reg-shift = <2>;
+		interrupts = < 69 >;
+	};
+
+	uart_c: serial at 70006200 {
+		compatible = "nvidia,tegra20-uart";
+		reg = <0x70006200 0x100>;
+		reg-shift = <2>;
+		interrupts = < 78 >;
+	};
+
+	uart_d: serial at 70006300 {
+		compatible = "nvidia,tegra20-uart";
+		reg = <0x70006300 0x100>;
+		reg-shift = <2>;
+		interrupts = < 122 >;
+	};
+
+	uart_e: serial at 70006400 {
+		compatible = "nvidia,tegra20-uart";
+		reg = <0x70006400 0x100>;
+		reg-shift = <2>;
+		interrupts = < 123 >;
+	};
+
 	spi at 7000d400 {
 		compatible = "nvidia,tegra124-spi", "nvidia,tegra114-spi";
 		reg = <0x7000d400 0x200>;
arch/arm/dts/tegra20-colibri_t20_iris.dts +1 -0
index c0e54af..fdf966b 100644
@@ -7,6 +7,7 @@
 	compatible = "toradex,t20", "nvidia,tegra20";
 
 	aliases {
+		console = &uart_a;
 		usb0 = "/usb at c5008000";
 		usb1 = "/usb at c5000000";
 		usb2 = "/usb at c5004000";
arch/arm/dts/tegra20-harmony.dts +1 -0
index b115f87..565045b 100644
@@ -7,6 +7,7 @@
 	compatible = "nvidia,harmony", "nvidia,tegra20";
 
 	aliases {
+		console = &uart_d;
 		usb0 = "/usb at c5008000";
 		usb1 = "/usb at c5004000";
 		sdhci0 = "/sdhci at c8000600";
arch/arm/dts/tegra20-medcom-wide.dts +1 -0
index a9a07f9..b400ce8 100644
@@ -7,6 +7,7 @@
 	compatible = "ad,medcom-wide", "nvidia,tegra20";
 
 	aliases {
+		console = &uart_d;
 		usb0 = "/usb at c5008000";
 		sdhci0 = "/sdhci at c8000600";
 	};
arch/arm/dts/tegra20-paz00.dts +1 -0
index 780203c..95b1ed4 100644
@@ -7,6 +7,7 @@
 	compatible = "compal,paz00", "nvidia,tegra20";
 
 	aliases {
+		console = &uart_a;
 		usb0 = "/usb at c5008000";
 		sdhci0 = "/sdhci at c8000600";
 		sdhci1 = "/sdhci at c8000000";
arch/arm/dts/tegra20-plutux.dts +1 -0
index 20016f2..a4ec20f 100644
@@ -7,6 +7,7 @@
 	compatible = "ad,plutux", "nvidia,tegra20";
 
 	aliases {
+		console = &uart_d;
 		usb0 = "/usb at c5008000";
 		sdhci0 = "/sdhci at c8000600";
 	};
arch/arm/dts/tegra20-seaboard.dts +1 -0
index c0e2e1e..85d485a 100644
@@ -11,6 +11,7 @@
 	};
 
 	aliases {
+		console = &uart_d;
 		/* This defines the order of our ports */
 		usb0 = "/usb at c5008000";
 		usb1 = "/usb at c5000000";
arch/arm/dts/tegra20-tec.dts +1 -0
index 4c1b08d..0e06100 100644
@@ -7,6 +7,7 @@
 	compatible = "ad,tec", "nvidia,tegra20";
 
 	aliases {
+		console = &uart_d;
 		usb0 = "/usb at c5008000";
 		sdhci0 = "/sdhci at c8000600";
 	};
arch/arm/dts/tegra20-trimslice.dts +1 -0
index ee31476..4506e8a 100644
@@ -7,6 +7,7 @@
 	compatible = "compulab,trimslice", "nvidia,tegra20";
 
 	aliases {
+		console = &uart_a;
 		usb0 = "/usb at c5008000";
 		usb1 = "/usb at c5000000";
 		sdhci0 = "/sdhci at c8000600";
arch/arm/dts/tegra20-ventana.dts +1 -0
index 1a526ba..61b45f3 100644
@@ -7,6 +7,7 @@
 	compatible = "nvidia,ventana", "nvidia,tegra20";
 
 	aliases {
+		console = &uart_d;
 		usb0 = "/usb at c5008000";
 		sdhci0 = "/sdhci at c8000600";
 		sdhci1 = "/sdhci at c8000400";
arch/arm/dts/tegra20-whistler.dts +1 -0
index eb92264..6eb68b5 100644
@@ -7,6 +7,7 @@
 	compatible = "nvidia,whistler", "nvidia,tegra20";
 
 	aliases {
+		console = &uart_a;
 		i2c0 = "/i2c at 7000d000";
 		usb0 = "/usb at c5008000";
 		sdhci0 = "/sdhci at c8000600";
arch/arm/dts/tegra20.dtsi +5 -5
index a524f6e..0f263b6 100644
@@ -189,35 +189,35 @@
 		dma-channel = < 1 >;
 	};
 
-	serial at 70006000 {
+	uart_a: serial at 70006000 {
 		compatible = "nvidia,tegra20-uart";
 		reg = <0x70006000 0x40>;
 		reg-shift = <2>;
 		interrupts = < 68 >;
 	};
 
-	serial at 70006040 {
+	uart_b: serial at 70006040 {
 		compatible = "nvidia,tegra20-uart";
 		reg = <0x70006040 0x40>;
 		reg-shift = <2>;
 		interrupts = < 69 >;
 	};
 
-	serial at 70006200 {
+	uart_c: serial at 70006200 {
 		compatible = "nvidia,tegra20-uart";
 		reg = <0x70006200 0x100>;
 		reg-shift = <2>;
 		interrupts = < 78 >;
 	};
 
-	serial at 70006300 {
+	uart_d: serial at 70006300 {
 		compatible = "nvidia,tegra20-uart";
 		reg = <0x70006300 0x100>;
 		reg-shift = <2>;
 		interrupts = < 122 >;
 	};
 
-	serial at 70006400 {
+	uart_e: serial at 70006400 {
 		compatible = "nvidia,tegra20-uart";
 		reg = <0x70006400 0x100>;
 		reg-shift = <2>;
arch/arm/dts/tegra30-beaver.dts +1 -0
index 85e62e9..79a9fff 100644
@@ -7,6 +7,7 @@
 	compatible = "nvidia,beaver", "nvidia,tegra30";
 
 	aliases {
+		console = &uart_a;
 		i2c0 = "/i2c at 7000d000";
 		i2c1 = "/i2c at 7000c000";
 		i2c2 = "/i2c at 7000c400";
arch/arm/dts/tegra30-cardhu.dts +1 -0
index ea2cf76..3f829ba 100644
@@ -7,6 +7,7 @@
 	compatible = "nvidia,cardhu", "nvidia,tegra30";
 
 	aliases {
+		console = &uart_a;
 		i2c0 = "/i2c at 7000d000";
 		i2c1 = "/i2c at 7000c000";
 		i2c2 = "/i2c at 7000c400";
arch/arm/dts/tegra30-tamonten.dtsi +1 -0
index 50d5762..e9ed61c 100644
@@ -9,6 +9,7 @@
 	};
 
 	aliases {
+		console = &uart_d;
 		i2c0 = "/i2c at 7000c000";
 		i2c1 = "/i2c at 7000c700";
 		i2c2 = "/i2c at 7000c400";
arch/arm/dts/tegra30.dtsi +35 -0
index 7be3791..e903d25 100644
@@ -122,6 +122,41 @@
 		status = "disabled";
 	};
 
+	uart_a: serial at 70006000 {
+		compatible = "nvidia,tegra20-uart";
+		reg = <0x70006000 0x40>;
+		reg-shift = <2>;
+		interrupts = < 68 >;
+	};
+
+	uart_b: serial at 70006040 {
+		compatible = "nvidia,tegra20-uart";
+		reg = <0x70006040 0x40>;
+		reg-shift = <2>;
+		interrupts = < 69 >;
+	};
+
+	uart_c: serial at 70006200 {
+		compatible = "nvidia,tegra20-uart";
+		reg = <0x70006200 0x100>;
+		reg-shift = <2>;
+		interrupts = < 78 >;
+	};
+
+	uart_d: serial at 70006300 {
+		compatible = "nvidia,tegra20-uart";
+		reg = <0x70006300 0x100>;
+		reg-shift = <2>;
+		interrupts = < 122 >;
+	};
+
+	uart_e: serial at 70006400 {
+		compatible = "nvidia,tegra20-uart";
+		reg = <0x70006400 0x100>;
+		reg-shift = <2>;
+		interrupts = < 123 >;
+	};
+
 	spi at 7000d400 {
 		compatible = "nvidia,tegra30-slink", "nvidia,tegra20-slink";
 		reg = <0x7000d400 0x200>;
Signature · 1 line
2.0.0.526.g5318336
#15 lore raw

PATCH v4 14/15 tegra: dts: Add serial port details

arch/arm/dts/tegra114-dalmore.dts line 10

Quoted 12 lines · Simon Glass

Some Tegra device tree files do not include information about the serial ports. Add this and also add information about the input clock speed.

The console alias needs to be set up to indicate which port is used for the console.

Also add a binding file since this is missing.

arch/arm/dts/tegra114-dalmore.dts +1 -0
 
  	aliases {
+		console = &uart_d;

Did the use of "console" get OK'd on the devicetree mailing list then?

I know we have this bug in the kernel DTs, but let's fix it here:
phandle values should have <> around them:

		console = <&uart_d>;

arch/arm/dts/tegra114.dtsi line 124

Quoted 8 lines
arch/arm/dts/tegra114.dtsi +6 -0
 
+	uart_a: serial at 70006000 {
+		compatible = "nvidia,tegra20-uart";
+		reg = <0x70006000 0x40>;
+		reg-shift = <2>;
+		interrupts = < 68 >;
+	};

In order to prevent the kernel and U-Boot DT files from diverging, can you copy the entire DT content from the kernel rather than just a subset, i.e.:

         uarta: serial at 70006000 {
                 compatible = "nvidia,tegra114-uart", "nvidia,tegra20-uart";
                 reg = <0x70006000 0x40>;
                 reg-shift = <2>;
                 interrupts = <GIC_SPI 36 IRQ_TYPE_LEVEL_HIGH>;
                 clocks = <&tegra_car TEGRA114_CLK_UARTA>;
                 resets = <&tegra_car 6>;
                 reset-names = "serial";
                 dmas = <&apbdma 8>, <&apbdma 8>;
                 dma-names = "rx", "tx";
                 status = "disabled";
         };
#16 lore raw

PATCH v4 14/15 tegra: dts: Add serial port details

Hi Stephen,

Quoted 15 lines · Stephen Warren
Quoted 12 lines · Simon Glass

Some Tegra device tree files do not include information about the serial ports. Add this and also add information about the input clock speed.

The console alias needs to be set up to indicate which port is used for the console.

Also add a binding file since this is missing.

arch/arm/dts/tegra114-dalmore.dts +0 -0
Quoted 5 lines
Quoted 2 lines
        aliases {

+ console = &uart_d;

Did the use of "console" get OK'd on the devicetree mailing list then?

No, not yet. I copied on you the thread. I'm not necessarily expecting a response.

Quoted 5 lines

I know we have this bug in the kernel DTs, but let's fix it here: phandle values should have <> around them:

                console = <&uart_d>;

This is not a phandle though. Are you wanting to change that?

Quoted 15 lines

arch/arm/dts/tegra114.dtsi line 124

Quoted 10 lines
arch/arm/dts/tegra114.dtsi +6 -0
 
 
+       uart_a: serial at 70006000 {
+               compatible = "nvidia,tegra20-uart";
+               reg = <0x70006000 0x40>;
+               reg-shift = <2>;
+               interrupts = < 68 >;
+       };

In order to prevent the kernel and U-Boot DT files from diverging, can you copy the entire DT content from the kernel rather than just a subset, i.e.:

Quoted 13 lines
        uarta: serial at 70006000 {
                compatible = "nvidia,tegra114-uart", "nvidia,tegra20-uart";

                reg = <0x70006000 0x40>;
                reg-shift = <2>;
                interrupts = <GIC_SPI 36 IRQ_TYPE_LEVEL_HIGH>;
                clocks = <&tegra_car TEGRA114_CLK_UARTA>;
                resets = <&tegra_car 6>;
                reset-names = "serial";
                dmas = <&apbdma 8>, <&apbdma 8>;
                dma-names = "rx", "tx";
                status = "disabled";
        };

OK, that's probably a good idea even if U-Boot doesn't use it. Will need the include files also.

Regards,
Simon

#17 lore raw

PATCH v4 14/15 tegra: dts: Add serial port details

Quoted 28 lines · Simon Glass

Hi Stephen,

Quoted 15 lines · Stephen Warren
Quoted 12 lines · Simon Glass

Some Tegra device tree files do not include information about the serial ports. Add this and also add information about the input clock speed.

The console alias needs to be set up to indicate which port is used for the console.

Also add a binding file since this is missing.

arch/arm/dts/tegra114-dalmore.dts +0 -0
Quoted 5 lines
Quoted 2 lines
         aliases {

+ console = &uart_d;

Did the use of "console" get OK'd on the devicetree mailing list then?

No, not yet. I copied on you the thread. I'm not necessarily expecting a response.

Quoted 1 line
Quoted 6 lines
Quoted 4 lines

I know we have this bug in the kernel DTs, but let's fix it here: phandle values should have <> around them:

                 console = <&uart_d>;

This is not a phandle though. Are you wanting to change that?

The & syntax is a phandle isn't it? Or does plain &label expand to a string? If it does, then ignore my comment.

#18 lore raw

PATCH v4 14/15 tegra: dts: Add serial port details

Hi Stephen,

Quoted 39 lines · Stephen Warren
Quoted 38 lines · Simon Glass

Hi Stephen,

Quoted 19 lines · Stephen Warren
Quoted 14 lines · Simon Glass

Some Tegra device tree files do not include information about the serial ports. Add this and also add information about the input clock speed.

The console alias needs to be set up to indicate which port is used for the console.

Also add a binding file since this is missing.

arch/arm/dts/tegra114-dalmore.dts +0 -0
Quoted 6 lines
Quoted 2 lines
         aliases {

+ console = &uart_d;

Did the use of "console" get OK'd on the devicetree mailing list then?

No, not yet. I copied on you the thread. I'm not necessarily expecting a response.

Quoted 4 lines

I know we have this bug in the kernel DTs, but let's fix it here: phandle values should have <> around them:

Quoted 8 lines
Quoted 4 lines
Quoted 1 line
                 console = <&uart_d>;

This is not a phandle though. Are you wanting to change that?

The & syntax is a phandle isn't it? Or does plain &label expand to a string? If it does, then ignore my comment.

Yes that's a string - it confused me also...nice feature though.

Regards,
Simon

#19 lore raw

PATCH v4 15/15 dm: tegra: Enable driver model for serial

In reply to Simon Glass

Use driver model for serial ports (for test and comment only).

dm: tegra: Use V_NS16550_CLK only in SPL builds

Since Tegra now uses driver model for serial, adjust the definition of V_NS16550_CLK so that it is clear that this is only used for SPL.

---

Changes in v4:
- Add a separate Tegra serial driver to deal with the clock issue
- Add new CONFIG_TEGRA_SERIAL option to enable dm driver
- Use hard-coded UART clock from Tegra configuration

Changes in v3:
- Add new patch to enable driver model for serial on tegra
- Add new patch to use V_NS16550_CLK only in SPL builds

Changes in v2: None

 drivers/serial/Makefile        |  1 +
 drivers/serial/serial_tegra.c  | 38 ++++++++++++++++++++++++++++++++++++++
 include/configs/tegra-common.h | 10 +++++++++-
 3 files changed, 48 insertions(+), 1 deletion(-)
 create mode 100644 drivers/serial/serial_tegra.c
drivers/serial/Makefile +1 -0
index 5ae6416..853a8c6 100644
@@ -38,6 +38,7 @@ obj-$(CONFIG_BFIN_SERIAL) += serial_bfin.o
 obj-$(CONFIG_FSL_LPUART) += serial_lpuart.o
 obj-$(CONFIG_MXS_AUART) += mxs_auart.o
 obj-$(CONFIG_ARC_SERIAL) += serial_arc.o
+obj-$(CONFIG_TEGRA_SERIAL) += serial_tegra.o
 
 ifndef CONFIG_SPL_BUILD
 obj-$(CONFIG_USB_TTY) += usbtty.o
drivers/serial/serial_tegra.c new file +38 -0
new file mode 100644
index 0000000..7eb70e1
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2014 Google, Inc
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <ns16550.h>
+#include <serial.h>
+
+static const struct udevice_id tegra_serial_ids[] = {
+	{ .compatible = "nvidia,tegra20-uart" },
+	{ }
+};
+
+static int tegra_serial_ofdata_to_platdata(struct udevice *dev)
+{
+	struct ns16550_platdata *plat = dev_get_platdata(dev);
+	int ret;
+
+	ret = ns16550_serial_ofdata_to_platdata(dev);
+	if (ret)
+		return ret;
+	plat->clock = V_NS16550_CLK;
+
+	return 0;
+}
+U_BOOT_DRIVER(serial_ns16550) = {
+	.name	= "serial_tegra20",
+	.id	= UCLASS_SERIAL,
+	.of_match = tegra_serial_ids,
+	.ofdata_to_platdata = tegra_serial_ofdata_to_platdata,
+	.platdata_auto_alloc_size = sizeof(struct ns16550_platdata),
+	.priv_auto_alloc_size = sizeof(struct NS16550),
+	.probe = ns16550_serial_probe,
+	.ops	= &ns16550_serial_ops,
+};
include/configs/tegra-common.h +9 -1
index 157d4ca..c1bf4e9 100644
@@ -22,6 +22,9 @@
 #define CONFIG_DM
 #define CONFIG_CMD_DM
 #define CONFIG_DM_GPIO
+#ifndef CONFIG_SPL_BUILD
+#define CONFIG_DM_SERIAL
+#endif
 
 #define CONFIG_SYS_TIMER_RATE		1000000
 #define CONFIG_SYS_TIMER_COUNTER	NV_PA_TMRUS_BASE
@@ -42,14 +45,19 @@
  * Size of malloc() pool
  */
 #define CONFIG_SYS_MALLOC_LEN		(4 << 20)	/* 4MB  */
+#define CONFIG_SYS_MALLOC_F_LEN	(1 << 10)
 
 /*
  * NS16550 Configuration
  */
-#define CONFIG_SYS_NS16550
+#ifdef CONFIG_SPL_BUILD
 #define CONFIG_SYS_NS16550_SERIAL
 #define CONFIG_SYS_NS16550_REG_SIZE	(-4)
 #define CONFIG_SYS_NS16550_CLK		V_NS16550_CLK
+#else
+#define CONFIG_TEGRA_SERIAL
+#endif
+#define CONFIG_SYS_NS16550
 
 /*
  * Common HW configuration.
Signature · 1 line
2.0.0.526.g5318336
#20 lore raw

PATCH v4 15/15 dm: tegra: Enable driver model for serial

Hi Stephen,

Quoted 8 lines · Simon Glass

Use driver model for serial ports (for test and comment only).

dm: tegra: Use V_NS16550_CLK only in SPL builds

Since Tegra now uses driver model for serial, adjust the definition of V_NS16550_CLK so that it is clear that this is only used for SPL.

---

Quoted 6 lines

Changes in v4:
- Add a separate Tegra serial driver to deal with the clock issue
- Add new CONFIG_TEGRA_SERIAL option to enable dm driver
- Use hard-coded UART clock from Tegra configuration

Just checking in to see if this patch looks good?

Regards,
Simon