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: Paul 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: Ralf Baechle <ralf@linux-mips.org>
This commit is contained in:
parent
b6d5e47e67
commit
c11e3b48db
@ -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;
|
||||
};
|
||||
};
|
||||
|
@ -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 =
|
||||
|
Loading…
Reference in New Issue
Block a user