[PATCH v2 03/19] MIPS: SEAD3: Probe UARTs using DT

Paul Burton
2016-08-26T14:17:35Z

Probe the UARTs on SEAD3 boards using device tree rather than platform
code, in order to reduce the amount of the latter. This requires that
CONFIG_SERIAL_OF_PLATFORM be enabled, so enable it in sead3_defconfig.
The SEAD3 DT shim code is extended to read bootloader environment
variables to determine the appropriate UART & mode for kernel console
output & set the stdout-path property of the chosen node accordingly.

In contrast to the old platform code, which appears to have only ever
set "console=ttyS0,38400n8r" with the code in console_config never
having an effect, this will honor the "yamontty" environment variable to
select between the 2 UARTs on the board and then check the "modetty0" or
"modetty1" variable as appropriate to determine the UART configuration.

Signed-off-by: Paul Burton <paul.burton@imgtec.com>

---

Changes in v2:
- #include <asm/fw/fw.h>, thanks kbuild test robot!

arch/mips/boot/dts/mti/sead3.dts | 37 ++++++++++
arch/mips/configs/sead3_defconfig | 2 +
arch/mips/include/asm/mips-boards/sead3int.h | 4 -
arch/mips/mti-sead3/sead3-dtshim.c | 105 ++++++++++++++++++++++++++-
arch/mips/mti-sead3/sead3-init.c | 46 ------------
arch/mips/mti-sead3/sead3-platform.c | 30 --------
6 files changed, 143 insertions(+), 81 deletions(-)

diff --git a/arch/mips/boot/dts/mti/sead3.dts b/arch/mips/boot/dts/mti/sead3.dts
index 051b3a9..3f681c5 100644
--- a/arch/mips/boot/dts/mti/sead3.dts
+++ b/arch/mips/boot/dts/mti/sead3.dts
@@ -12,6 +12,15 @@
compatible = "mti,sead-3";
interrupt-parent = <&gic>;

+ chosen {
+ stdout-path = "uart1:115200";
+ };
+
+ aliases {
+ uart0 = &uart0;
+ uart1 = &uart1;
+ };
+
cpus {
cpu@0 {
compatible = "mti,mips14KEc", "mti,mips14Kc";
@@ -50,4 +59,32 @@
interrupts = <GIC_LOCAL 1 IRQ_TYPE_NONE>;
};
};
+
+ /* UART connected to FTDI & miniUSB socket */
+ uart0: uart@1f000900 {
+ compatible = "ns16550a";
+ reg = <0x1f000900 0x20>;
+ reg-io-width = <4>;
+ reg-shift = <2>;
+
+ clock-frequency = <14745600>;
+
+ interrupts = <3>; /* GIC 3 or CPU 4 */
+
+ no-loopback-test;
+ };
+
+ /* UART connected to RS232 socket */
+ uart1: uart@1f000800 {
+ compatible = "ns16550a";
+ reg = <0x1f000800 0x20>;
+ reg-io-width = <4>;
+ reg-shift = <2>;
+
+ clock-frequency = <14745600>;
+
+ interrupts = <2>; /* GIC 2 or CPU 4 */
+
+ no-loopback-test;
+ };
};
diff --git a/arch/mips/configs/sead3_defconfig b/arch/mips/configs/sead3_defconfig
index dae9354..deb48fb 100644
--- a/arch/mips/configs/sead3_defconfig
+++ b/arch/mips/configs/sead3_defconfig
@@ -39,6 +39,7 @@ CONFIG_MTD_CFI_INTELEXT=y
CONFIG_MTD_PHYSMAP=y
CONFIG_MTD_UBI=y
CONFIG_MTD_UBI_GLUEBI=y
+CONFIG_OF=y
CONFIG_BLK_DEV_LOOP=y
CONFIG_BLK_DEV_CRYPTOLOOP=m
CONFIG_SCSI=y
@@ -70,6 +71,7 @@ CONFIG_SERIAL_8250=y
CONFIG_SERIAL_8250_CONSOLE=y
CONFIG_SERIAL_8250_NR_UARTS=2
CONFIG_SERIAL_8250_RUNTIME_UARTS=2
+CONFIG_SERIAL_OF_PLATFORM=y
# CONFIG_HW_RANDOM is not set
CONFIG_I2C=y
# CONFIG_I2C_COMPAT is not set
diff --git a/arch/mips/include/asm/mips-boards/sead3int.h b/arch/mips/include/asm/mips-boards/sead3int.h
index bd85da3..3a5e079 100644
--- a/arch/mips/include/asm/mips-boards/sead3int.h
+++ b/arch/mips/include/asm/mips-boards/sead3int.h
@@ -14,14 +14,10 @@

/* CPU interrupt offsets */
#define CPU_INT_EHCI 2
-#define CPU_INT_UART0 4
-#define CPU_INT_UART1 4
#define CPU_INT_NET 6

/* GIC interrupt offsets */
#define GIC_INT_NET GIC_SHARED_TO_HWIRQ(0)
-#define GIC_INT_UART1 GIC_SHARED_TO_HWIRQ(2)
-#define GIC_INT_UART0 GIC_SHARED_TO_HWIRQ(3)
#define GIC_INT_EHCI GIC_SHARED_TO_HWIRQ(5)

#endif /* !(_MIPS_SEAD3INT_H) */
diff --git a/arch/mips/mti-sead3/sead3-dtshim.c b/arch/mips/mti-sead3/sead3-dtshim.c
index 3283a7e..b462f65 100644
--- a/arch/mips/mti-sead3/sead3-dtshim.c
+++ b/arch/mips/mti-sead3/sead3-dtshim.c
@@ -14,6 +14,7 @@
#include <linux/libfdt.h>
#include <linux/printk.h>

+#include <asm/fw/fw.h>
#include <asm/io.h>

#define SEAD_CONFIG CKSEG1ADDR(0x1b100110)
@@ -23,7 +24,8 @@ static unsigned char fdt_buf[16 << 10] __initdata;

static int remove_gic(void *fdt)
{
- int gic_off, cpu_off, err;
+ const unsigned int cpu_uart_int = 4;
+ int gic_off, cpu_off, uart_off, err;
uint32_t cfg, cpu_phandle;

/* leave the GIC node intact if a GIC is present */
@@ -62,6 +64,103 @@ static int remove_gic(void *fdt)
return err;
}

+ uart_off = fdt_node_offset_by_compatible(fdt, -1, "ns16550a");
+ while (uart_off >= 0) {
+ err = fdt_setprop_u32(fdt, uart_off, "interrupts",
+ cpu_uart_int);
+ if (err) {
+ pr_err("unable to set UART interrupts property: %d\n",
+ err);
+ return err;
+ }
+
+ uart_off = fdt_node_offset_by_compatible(fdt, uart_off,
+ "ns16550a");
+ }
+ if (uart_off != -FDT_ERR_NOTFOUND) {
+ pr_err("error searching for UART DT node: %d\n", uart_off);
+ return uart_off;
+ }
+
+ return 0;
+}
+
+static int serial_config(void *fdt)
+{
+ const char *yamontty, *mode_var;
+ char mode_var_name[9], path[18], parity;
+ unsigned int uart, baud, stop_bits;
+ bool hw_flow;
+ int chosen_off, err;
+
+ yamontty = fw_getenv("yamontty");
+ if (!yamontty || !strcmp(yamontty, "tty0")) {
+ uart = 0;
+ } else if (!strcmp(yamontty, "tty1")) {
+ uart = 1;
+ } else {
+ pr_warn("yamontty environment variable '%s' invalid\n",
+ yamontty);
+ uart = 0;
+ }
+
+ baud = stop_bits = 0;
+ parity = 0;
+ hw_flow = false;
+
+ snprintf(mode_var_name, sizeof(mode_var_name), "modetty%u", uart);
+ mode_var = fw_getenv(mode_var_name);
+ if (mode_var) {
+ while (mode_var[0] >= '0' && mode_var[0] <= '9') {
+ baud *= 10;
+ baud += mode_var[0] - '0';
+ mode_var++;
+ }
+ if (mode_var[0] == ',')
+ mode_var++;
+ if (mode_var[0])
+ parity = mode_var[0];
+ if (mode_var[0] == ',')
+ mode_var++;
+ if (mode_var[0])
+ stop_bits = mode_var[0] - '0';
+ if (mode_var[0] == ',')
+ mode_var++;
+ if (!strcmp(mode_var, "hw"))
+ hw_flow = true;
+ }
+
+ if (!baud)
+ baud = 38400;
+
+ if (parity != 'e' && parity != 'n' && parity != 'o')
+ parity = 'n';
+
+ if (stop_bits != 7 && stop_bits != 8)
+ stop_bits = 8;
+
+ WARN_ON(snprintf(path, sizeof(path), "uart%u:%u%c%u%s",
+ uart, baud, parity, stop_bits,
+ hw_flow ? "r" : "") >= sizeof(path));
+
+ /* find or add chosen node */
+ chosen_off = fdt_path_offset(fdt, "/chosen");
+ if (chosen_off == -FDT_ERR_NOTFOUND)
+ chosen_off = fdt_path_offset(fdt, "/chosen@0");
+ if (chosen_off == -FDT_ERR_NOTFOUND)
+ chosen_off = fdt_add_subnode(fdt, 0, "chosen");
+ if (chosen_off < 0) {
+ pr_err("Unable to find or add DT chosen node: %d\n",
+ chosen_off);
+ return chosen_off;
+ }
+
+ err = fdt_setprop_string(fdt, chosen_off, "stdout-path", path);
+ if (err) {
+ pr_err("Unable to set stdout-path property: %d\n", err);
+ return err;
+ }
+
return 0;
}

@@ -84,6 +183,10 @@ void __init *sead3_dt_shim(void *fdt)
if (err)
panic("Unable to patch FDT: %d", err);

+ err = serial_config(fdt_buf);
+ if (err)
+ panic("Unable to patch FDT: %d", err);
+
err = fdt_pack(fdt_buf);
if (err)
panic("Unable to pack FDT: %d\n", err);
diff --git a/arch/mips/mti-sead3/sead3-init.c b/arch/mips/mti-sead3/sead3-init.c
index 3572ea3..e81f5b7 100644
--- a/arch/mips/mti-sead3/sead3-init.c
+++ b/arch/mips/mti-sead3/sead3-init.c
@@ -17,47 +17,6 @@
extern char except_vec_nmi;
extern char except_vec_ejtag_debug;

-#ifdef CONFIG_SERIAL_8250_CONSOLE
-static void __init console_config(void)
-{
- char console_string[40];
- int baud = 0;
- char parity = '\0', bits = '\0', flow = '\0';
- char *s;
-
- if ((strstr(fw_getcmdline(), "console=")) == NULL) {
- s = fw_getenv("modetty0");
- if (s) {
- while (*s >= '0' && *s <= '9')
- baud = baud*10 + *s++ - '0';
- if (*s == ',')
- s++;
- if (*s)
- parity = *s++;
- if (*s == ',')
- s++;
- if (*s)
- bits = *s++;
- if (*s == ',')
- s++;
- if (*s == 'h')
- flow = 'r';
- }
- if (baud == 0)
- baud = 38400;
- if (parity != 'n' && parity != 'o' && parity != 'e')
- parity = 'n';
- if (bits != '7' && bits != '8')
- bits = '8';
- if (flow == '\0')
- flow = 'r';
- sprintf(console_string, " console=ttyS0,%d%c%c%c", baud,
- parity, bits, flow);
- strcat(fw_getcmdline(), console_string);
- }
-}
-#endif
-
static void __init mips_nmi_setup(void)
{
void *base;
@@ -140,11 +99,6 @@ void __init prom_init(void)
else if ((strstr(fw_getcmdline(), "console=ttyS1")) != NULL)
fw_init_early_console(1);
#endif
-#ifdef CONFIG_SERIAL_8250_CONSOLE
- if ((strstr(fw_getcmdline(), "console=")) == NULL)
- strcat(fw_getcmdline(), " console=ttyS0,38400n8r");
- console_config();
-#endif
}

void __init prom_free_prom_memory(void)
diff --git a/arch/mips/mti-sead3/sead3-platform.c b/arch/mips/mti-sead3/sead3-platform.c
index d6be029..538a6f8 100644
--- a/arch/mips/mti-sead3/sead3-platform.c
+++ b/arch/mips/mti-sead3/sead3-platform.c
@@ -14,35 +14,10 @@
#include <linux/mtd/physmap.h>
#include <linux/of.h>
#include <linux/platform_device.h>
-#include <linux/serial_8250.h>
#include <linux/smsc911x.h>

#include <asm/mips-boards/sead3int.h>

-#define UART(base) \
-{ \
- .mapbase = base, \
- .irq = -1, \
- .uartclk = 14745600, \
- .iotype = UPIO_MEM32, \
- .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_IOREMAP, \
- .regshift = 2, \
-}
-
-static struct plat_serial8250_port uart8250_data[] = {
- UART(0x1f000900), /* ttyS0 = USB */
- UART(0x1f000800), /* ttyS1 = RS232 */
- { },
-};
-
-static struct platform_device uart8250_device = {
- .name = "serial8250",
- .id = PLAT8250_DEV_PLATFORM2,
- .dev = {
- .platform_data = uart8250_data,
- },
-};
-
static struct smsc911x_platform_config sead3_smsc911x_data = {
.irq_polarity = SMSC911X_IRQ_POLARITY_ACTIVE_LOW,
.irq_type = SMSC911X_IRQ_TYPE_PUSH_PULL,
@@ -195,7 +170,6 @@ static struct platform_device ehci_device = {
};

static struct platform_device *sead3_platform_devices[] __initdata = {
- &uart8250_device,
&sead3_flash,
&pled_device,
&fled_device,
@@ -228,15 +202,11 @@ static int __init sead3_platforms_device_init(void)
}

if (gic_present) {
- uart8250_data[0].irq = irq_create_mapping(irqd, GIC_INT_UART0);
- uart8250_data[1].irq = irq_create_mapping(irqd, GIC_INT_UART1);
ehci_resources[1].start =
irq_create_mapping(irqd, GIC_INT_EHCI);
sead3_net_resources[1].start =
irq_create_mapping(irqd, GIC_INT_NET);
} else {
- uart8250_data[0].irq = irq_create_mapping(irqd, CPU_INT_UART0);
- uart8250_data[1].irq = irq_create_mapping(irqd, CPU_INT_UART1);
ehci_resources[1].start =
irq_create_mapping(irqd, CPU_INT_EHCI);
sead3_net_resources[1].start =
--
2.9.3