Commit c11e3b48 authored by Paul Burton's avatar Paul Burton Committed by Ralf Baechle

MIPS: SEAD3: Probe UARTs using DT

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: default avatarPaul Burton <paul.burton@imgtec.com>
Cc: Rob Herring <robh+dt@kernel.org>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: linux-mips@linux-mips.org
Cc: devicetree@vger.kernel.org
Cc: linux-kernel@vger.kernel.org
Patchwork: https://patchwork.linux-mips.org/patch/14048/Signed-off-by: default avatarRalf Baechle <ralf@linux-mips.org>
parent b6d5e47e
......@@ -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 @@ timer {
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;
};
};
......@@ -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
......
......@@ -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) */
......@@ -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);
......
......@@ -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)
......
......@@ -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 =
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment