From: Arnd Bergmann Date: Mon, 16 Nov 2015 15:48:14 +0000 (+0100) Subject: serial: 8250: move of_serial code to 8250 directory X-Git-Url: http://drtracing.org/?a=commitdiff_plain;h=afd7f88f157796e586fc99d62da13a54024e0731;p=deliverable%2Flinux.git serial: 8250: move of_serial code to 8250 directory As the of-serial driver is now 8250 specific, we can move the file to a more appropriate place in teh 8250 subdirectory and adapt the Kconfig help text and file name. I'm leaving the CONFIG_SERIAL_OF_PLATFORM symbol unchanged to avoid breaking user configuration files unnecessarily. Signed-off-by: Arnd Bergmann Signed-off-by: Greg Kroah-Hartman --- diff --git a/drivers/tty/serial/8250/8250_of.c b/drivers/tty/serial/8250/8250_of.c new file mode 100644 index 000000000000..d66fd24f87cf --- /dev/null +++ b/drivers/tty/serial/8250/8250_of.c @@ -0,0 +1,348 @@ +/* + * Serial Port driver for Open Firmware platform devices + * + * Copyright (C) 2006 Arnd Bergmann , IBM Corp. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "8250/8250.h" + +struct of_serial_info { + struct clk *clk; + int type; + int line; +}; + +#ifdef CONFIG_ARCH_TEGRA +void tegra_serial_handle_break(struct uart_port *p) +{ + unsigned int status, tmout = 10000; + + do { + status = p->serial_in(p, UART_LSR); + if (status & (UART_LSR_FIFOE | UART_LSR_BRK_ERROR_BITS)) + status = p->serial_in(p, UART_RX); + else + break; + if (--tmout == 0) + break; + udelay(1); + } while (1); +} +#else +static inline void tegra_serial_handle_break(struct uart_port *port) +{ +} +#endif + +/* + * Fill a struct uart_port for a given device node + */ +static int of_platform_serial_setup(struct platform_device *ofdev, + int type, struct uart_port *port, + struct of_serial_info *info) +{ + struct resource resource; + struct device_node *np = ofdev->dev.of_node; + u32 clk, spd, prop; + int ret; + + memset(port, 0, sizeof *port); + if (of_property_read_u32(np, "clock-frequency", &clk)) { + + /* Get clk rate through clk driver if present */ + info->clk = devm_clk_get(&ofdev->dev, NULL); + if (IS_ERR(info->clk)) { + dev_warn(&ofdev->dev, + "clk or clock-frequency not defined\n"); + return PTR_ERR(info->clk); + } + + ret = clk_prepare_enable(info->clk); + if (ret < 0) + return ret; + + clk = clk_get_rate(info->clk); + } + /* If current-speed was set, then try not to change it. */ + if (of_property_read_u32(np, "current-speed", &spd) == 0) + port->custom_divisor = clk / (16 * spd); + + ret = of_address_to_resource(np, 0, &resource); + if (ret) { + dev_warn(&ofdev->dev, "invalid address\n"); + goto out; + } + + spin_lock_init(&port->lock); + port->mapbase = resource.start; + port->mapsize = resource_size(&resource); + + /* Check for shifted address mapping */ + if (of_property_read_u32(np, "reg-offset", &prop) == 0) + port->mapbase += prop; + + /* Check for registers offset within the devices address range */ + if (of_property_read_u32(np, "reg-shift", &prop) == 0) + port->regshift = prop; + + /* Check for fifo size */ + if (of_property_read_u32(np, "fifo-size", &prop) == 0) + port->fifosize = prop; + + /* Check for a fixed line number */ + ret = of_alias_get_id(np, "serial"); + if (ret >= 0) + port->line = ret; + + port->irq = irq_of_parse_and_map(np, 0); + port->iotype = UPIO_MEM; + if (of_property_read_u32(np, "reg-io-width", &prop) == 0) { + switch (prop) { + case 1: + port->iotype = UPIO_MEM; + break; + case 2: + port->iotype = UPIO_MEM16; + break; + case 4: + port->iotype = of_device_is_big_endian(np) ? + UPIO_MEM32BE : UPIO_MEM32; + break; + default: + dev_warn(&ofdev->dev, "unsupported reg-io-width (%d)\n", + prop); + ret = -EINVAL; + goto out; + } + } + + port->type = type; + port->uartclk = clk; + port->flags = UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF | UPF_IOREMAP + | UPF_FIXED_PORT | UPF_FIXED_TYPE; + + if (of_find_property(np, "no-loopback-test", NULL)) + port->flags |= UPF_SKIP_TEST; + + port->dev = &ofdev->dev; + + switch (type) { + case PORT_TEGRA: + port->handle_break = tegra_serial_handle_break; + break; + + case PORT_RT2880: + port->iotype = UPIO_AU; + break; + } + + if (IS_ENABLED(CONFIG_SERIAL_8250_FSL) && + (of_device_is_compatible(np, "fsl,ns16550") || + of_device_is_compatible(np, "fsl,16550-FIFO64"))) + port->handle_irq = fsl8250_handle_irq; + + return 0; +out: + if (info->clk) + clk_disable_unprepare(info->clk); + return ret; +} + +/* + * Try to register a serial port + */ +static const struct of_device_id of_platform_serial_table[]; +static int of_platform_serial_probe(struct platform_device *ofdev) +{ + const struct of_device_id *match; + struct of_serial_info *info; + struct uart_port port; + int port_type; + int ret; + + match = of_match_device(of_platform_serial_table, &ofdev->dev); + if (!match) + return -EINVAL; + + if (of_find_property(ofdev->dev.of_node, "used-by-rtas", NULL)) + return -EBUSY; + + info = kzalloc(sizeof(*info), GFP_KERNEL); + if (info == NULL) + return -ENOMEM; + + port_type = (unsigned long)match->data; + ret = of_platform_serial_setup(ofdev, port_type, &port, info); + if (ret) + goto out; + + switch (port_type) { + case PORT_8250 ... PORT_MAX_8250: + { + struct uart_8250_port port8250; + memset(&port8250, 0, sizeof(port8250)); + port8250.port = port; + + if (port.fifosize) + port8250.capabilities = UART_CAP_FIFO; + + if (of_property_read_bool(ofdev->dev.of_node, + "auto-flow-control")) + port8250.capabilities |= UART_CAP_AFE; + + ret = serial8250_register_8250_port(&port8250); + break; + } + default: + /* need to add code for these */ + case PORT_UNKNOWN: + dev_info(&ofdev->dev, "Unknown serial port found, ignored\n"); + ret = -ENODEV; + break; + } + if (ret < 0) + goto out; + + info->type = port_type; + info->line = ret; + platform_set_drvdata(ofdev, info); + return 0; +out: + kfree(info); + irq_dispose_mapping(port.irq); + return ret; +} + +/* + * Release a line + */ +static int of_platform_serial_remove(struct platform_device *ofdev) +{ + struct of_serial_info *info = platform_get_drvdata(ofdev); + switch (info->type) { + case PORT_8250 ... PORT_MAX_8250: + serial8250_unregister_port(info->line); + break; + default: + /* need to add code for these */ + break; + } + + if (info->clk) + clk_disable_unprepare(info->clk); + kfree(info); + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static void of_serial_suspend_8250(struct of_serial_info *info) +{ + struct uart_8250_port *port8250 = serial8250_get_port(info->line); + struct uart_port *port = &port8250->port; + + serial8250_suspend_port(info->line); + if (info->clk && (!uart_console(port) || console_suspend_enabled)) + clk_disable_unprepare(info->clk); +} + +static void of_serial_resume_8250(struct of_serial_info *info) +{ + struct uart_8250_port *port8250 = serial8250_get_port(info->line); + struct uart_port *port = &port8250->port; + + if (info->clk && (!uart_console(port) || console_suspend_enabled)) + clk_prepare_enable(info->clk); + + serial8250_resume_port(info->line); +} + +static int of_serial_suspend(struct device *dev) +{ + struct of_serial_info *info = dev_get_drvdata(dev); + + switch (info->type) { + case PORT_8250 ... PORT_MAX_8250: + of_serial_suspend_8250(info); + break; + default: + break; + } + + return 0; +} + +static int of_serial_resume(struct device *dev) +{ + struct of_serial_info *info = dev_get_drvdata(dev); + + switch (info->type) { + case PORT_8250 ... PORT_MAX_8250: + of_serial_resume_8250(info); + break; + default: + break; + } + + return 0; +} +#endif +static SIMPLE_DEV_PM_OPS(of_serial_pm_ops, of_serial_suspend, of_serial_resume); + +/* + * A few common types, add more as needed. + */ +static const struct of_device_id of_platform_serial_table[] = { + { .compatible = "ns8250", .data = (void *)PORT_8250, }, + { .compatible = "ns16450", .data = (void *)PORT_16450, }, + { .compatible = "ns16550a", .data = (void *)PORT_16550A, }, + { .compatible = "ns16550", .data = (void *)PORT_16550, }, + { .compatible = "ns16750", .data = (void *)PORT_16750, }, + { .compatible = "ns16850", .data = (void *)PORT_16850, }, + { .compatible = "nvidia,tegra20-uart", .data = (void *)PORT_TEGRA, }, + { .compatible = "nxp,lpc3220-uart", .data = (void *)PORT_LPC3220, }, + { .compatible = "ralink,rt2880-uart", .data = (void *)PORT_RT2880, }, + { .compatible = "altr,16550-FIFO32", + .data = (void *)PORT_ALTR_16550_F32, }, + { .compatible = "altr,16550-FIFO64", + .data = (void *)PORT_ALTR_16550_F64, }, + { .compatible = "altr,16550-FIFO128", + .data = (void *)PORT_ALTR_16550_F128, }, + { .compatible = "mrvl,mmp-uart", + .data = (void *)PORT_XSCALE, }, + { .compatible = "mrvl,pxa-uart", + .data = (void *)PORT_XSCALE, }, + { /* end of list */ }, +}; +MODULE_DEVICE_TABLE(of, of_platform_serial_table); + +static struct platform_driver of_platform_serial_driver = { + .driver = { + .name = "of_serial", + .of_match_table = of_platform_serial_table, + }, + .probe = of_platform_serial_probe, + .remove = of_platform_serial_remove, +}; + +module_platform_driver(of_platform_serial_driver); + +MODULE_AUTHOR("Arnd Bergmann "); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Serial Port driver for Open Firmware platform devices"); diff --git a/drivers/tty/serial/8250/Kconfig b/drivers/tty/serial/8250/Kconfig index 25da430bb58b..54f8af8ab4fb 100644 --- a/drivers/tty/serial/8250/Kconfig +++ b/drivers/tty/serial/8250/Kconfig @@ -377,3 +377,12 @@ config SERIAL_8250_MID Selecting this option will enable handling of the extra features present on the UART found on Intel Medfield SOC and various other Intel platforms. + +config SERIAL_OF_PLATFORM + tristate "Devicetree based probing for 8250 ports" + depends on SERIAL_8250 && OF + help + This option is used for all 8250 compatible serial ports that + are probed through devicetree, including Open Firmware based + PowerPC systems and embedded systems on architectures using the + flattened device tree format. diff --git a/drivers/tty/serial/8250/Makefile b/drivers/tty/serial/8250/Makefile index e177f8681ada..4ecb80d3549a 100644 --- a/drivers/tty/serial/8250/Makefile +++ b/drivers/tty/serial/8250/Makefile @@ -28,5 +28,6 @@ obj-$(CONFIG_SERIAL_8250_MT6577) += 8250_mtk.o obj-$(CONFIG_SERIAL_8250_UNIPHIER) += 8250_uniphier.o obj-$(CONFIG_SERIAL_8250_INGENIC) += 8250_ingenic.o obj-$(CONFIG_SERIAL_8250_MID) += 8250_mid.o +obj-$(CONFIG_SERIAL_8250_OF) += 8250_of.o CFLAGS_8250_ingenic.o += -I$(srctree)/scripts/dtc/libfdt diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index 643fc50bb741..0bdf4d5c7c65 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -1096,16 +1096,6 @@ config SERIAL_NETX_CONSOLE If you have enabled the serial port on the Hilscher NetX SoC you can make it the console by answering Y to this option. -config SERIAL_OF_PLATFORM - tristate "Serial port on Open Firmware platform bus" - depends on OF - depends on SERIAL_8250 - help - If you have a PowerPC based system that has serial ports - on a platform specific bus, you should enable this option. - Currently, only 8250 compatible ports are supported, but - others can easily be added. - config SERIAL_OMAP tristate "OMAP serial port support" depends on ARCH_OMAP2PLUS diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile index ee8893317433..b391c9b31960 100644 --- a/drivers/tty/serial/Makefile +++ b/drivers/tty/serial/Makefile @@ -63,7 +63,6 @@ obj-$(CONFIG_SERIAL_ATMEL) += atmel_serial.o obj-$(CONFIG_SERIAL_UARTLITE) += uartlite.o obj-$(CONFIG_SERIAL_MSM) += msm_serial.o obj-$(CONFIG_SERIAL_NETX) += netx-serial.o -obj-$(CONFIG_SERIAL_OF_PLATFORM) += of_serial.o obj-$(CONFIG_SERIAL_KGDB_NMI) += kgdb_nmi.o obj-$(CONFIG_SERIAL_KS8695) += serial_ks8695.o obj-$(CONFIG_SERIAL_OMAP) += omap-serial.o diff --git a/drivers/tty/serial/of_serial.c b/drivers/tty/serial/of_serial.c deleted file mode 100644 index d66fd24f87cf..000000000000 --- a/drivers/tty/serial/of_serial.c +++ /dev/null @@ -1,348 +0,0 @@ -/* - * Serial Port driver for Open Firmware platform devices - * - * Copyright (C) 2006 Arnd Bergmann , IBM Corp. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "8250/8250.h" - -struct of_serial_info { - struct clk *clk; - int type; - int line; -}; - -#ifdef CONFIG_ARCH_TEGRA -void tegra_serial_handle_break(struct uart_port *p) -{ - unsigned int status, tmout = 10000; - - do { - status = p->serial_in(p, UART_LSR); - if (status & (UART_LSR_FIFOE | UART_LSR_BRK_ERROR_BITS)) - status = p->serial_in(p, UART_RX); - else - break; - if (--tmout == 0) - break; - udelay(1); - } while (1); -} -#else -static inline void tegra_serial_handle_break(struct uart_port *port) -{ -} -#endif - -/* - * Fill a struct uart_port for a given device node - */ -static int of_platform_serial_setup(struct platform_device *ofdev, - int type, struct uart_port *port, - struct of_serial_info *info) -{ - struct resource resource; - struct device_node *np = ofdev->dev.of_node; - u32 clk, spd, prop; - int ret; - - memset(port, 0, sizeof *port); - if (of_property_read_u32(np, "clock-frequency", &clk)) { - - /* Get clk rate through clk driver if present */ - info->clk = devm_clk_get(&ofdev->dev, NULL); - if (IS_ERR(info->clk)) { - dev_warn(&ofdev->dev, - "clk or clock-frequency not defined\n"); - return PTR_ERR(info->clk); - } - - ret = clk_prepare_enable(info->clk); - if (ret < 0) - return ret; - - clk = clk_get_rate(info->clk); - } - /* If current-speed was set, then try not to change it. */ - if (of_property_read_u32(np, "current-speed", &spd) == 0) - port->custom_divisor = clk / (16 * spd); - - ret = of_address_to_resource(np, 0, &resource); - if (ret) { - dev_warn(&ofdev->dev, "invalid address\n"); - goto out; - } - - spin_lock_init(&port->lock); - port->mapbase = resource.start; - port->mapsize = resource_size(&resource); - - /* Check for shifted address mapping */ - if (of_property_read_u32(np, "reg-offset", &prop) == 0) - port->mapbase += prop; - - /* Check for registers offset within the devices address range */ - if (of_property_read_u32(np, "reg-shift", &prop) == 0) - port->regshift = prop; - - /* Check for fifo size */ - if (of_property_read_u32(np, "fifo-size", &prop) == 0) - port->fifosize = prop; - - /* Check for a fixed line number */ - ret = of_alias_get_id(np, "serial"); - if (ret >= 0) - port->line = ret; - - port->irq = irq_of_parse_and_map(np, 0); - port->iotype = UPIO_MEM; - if (of_property_read_u32(np, "reg-io-width", &prop) == 0) { - switch (prop) { - case 1: - port->iotype = UPIO_MEM; - break; - case 2: - port->iotype = UPIO_MEM16; - break; - case 4: - port->iotype = of_device_is_big_endian(np) ? - UPIO_MEM32BE : UPIO_MEM32; - break; - default: - dev_warn(&ofdev->dev, "unsupported reg-io-width (%d)\n", - prop); - ret = -EINVAL; - goto out; - } - } - - port->type = type; - port->uartclk = clk; - port->flags = UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF | UPF_IOREMAP - | UPF_FIXED_PORT | UPF_FIXED_TYPE; - - if (of_find_property(np, "no-loopback-test", NULL)) - port->flags |= UPF_SKIP_TEST; - - port->dev = &ofdev->dev; - - switch (type) { - case PORT_TEGRA: - port->handle_break = tegra_serial_handle_break; - break; - - case PORT_RT2880: - port->iotype = UPIO_AU; - break; - } - - if (IS_ENABLED(CONFIG_SERIAL_8250_FSL) && - (of_device_is_compatible(np, "fsl,ns16550") || - of_device_is_compatible(np, "fsl,16550-FIFO64"))) - port->handle_irq = fsl8250_handle_irq; - - return 0; -out: - if (info->clk) - clk_disable_unprepare(info->clk); - return ret; -} - -/* - * Try to register a serial port - */ -static const struct of_device_id of_platform_serial_table[]; -static int of_platform_serial_probe(struct platform_device *ofdev) -{ - const struct of_device_id *match; - struct of_serial_info *info; - struct uart_port port; - int port_type; - int ret; - - match = of_match_device(of_platform_serial_table, &ofdev->dev); - if (!match) - return -EINVAL; - - if (of_find_property(ofdev->dev.of_node, "used-by-rtas", NULL)) - return -EBUSY; - - info = kzalloc(sizeof(*info), GFP_KERNEL); - if (info == NULL) - return -ENOMEM; - - port_type = (unsigned long)match->data; - ret = of_platform_serial_setup(ofdev, port_type, &port, info); - if (ret) - goto out; - - switch (port_type) { - case PORT_8250 ... PORT_MAX_8250: - { - struct uart_8250_port port8250; - memset(&port8250, 0, sizeof(port8250)); - port8250.port = port; - - if (port.fifosize) - port8250.capabilities = UART_CAP_FIFO; - - if (of_property_read_bool(ofdev->dev.of_node, - "auto-flow-control")) - port8250.capabilities |= UART_CAP_AFE; - - ret = serial8250_register_8250_port(&port8250); - break; - } - default: - /* need to add code for these */ - case PORT_UNKNOWN: - dev_info(&ofdev->dev, "Unknown serial port found, ignored\n"); - ret = -ENODEV; - break; - } - if (ret < 0) - goto out; - - info->type = port_type; - info->line = ret; - platform_set_drvdata(ofdev, info); - return 0; -out: - kfree(info); - irq_dispose_mapping(port.irq); - return ret; -} - -/* - * Release a line - */ -static int of_platform_serial_remove(struct platform_device *ofdev) -{ - struct of_serial_info *info = platform_get_drvdata(ofdev); - switch (info->type) { - case PORT_8250 ... PORT_MAX_8250: - serial8250_unregister_port(info->line); - break; - default: - /* need to add code for these */ - break; - } - - if (info->clk) - clk_disable_unprepare(info->clk); - kfree(info); - return 0; -} - -#ifdef CONFIG_PM_SLEEP -static void of_serial_suspend_8250(struct of_serial_info *info) -{ - struct uart_8250_port *port8250 = serial8250_get_port(info->line); - struct uart_port *port = &port8250->port; - - serial8250_suspend_port(info->line); - if (info->clk && (!uart_console(port) || console_suspend_enabled)) - clk_disable_unprepare(info->clk); -} - -static void of_serial_resume_8250(struct of_serial_info *info) -{ - struct uart_8250_port *port8250 = serial8250_get_port(info->line); - struct uart_port *port = &port8250->port; - - if (info->clk && (!uart_console(port) || console_suspend_enabled)) - clk_prepare_enable(info->clk); - - serial8250_resume_port(info->line); -} - -static int of_serial_suspend(struct device *dev) -{ - struct of_serial_info *info = dev_get_drvdata(dev); - - switch (info->type) { - case PORT_8250 ... PORT_MAX_8250: - of_serial_suspend_8250(info); - break; - default: - break; - } - - return 0; -} - -static int of_serial_resume(struct device *dev) -{ - struct of_serial_info *info = dev_get_drvdata(dev); - - switch (info->type) { - case PORT_8250 ... PORT_MAX_8250: - of_serial_resume_8250(info); - break; - default: - break; - } - - return 0; -} -#endif -static SIMPLE_DEV_PM_OPS(of_serial_pm_ops, of_serial_suspend, of_serial_resume); - -/* - * A few common types, add more as needed. - */ -static const struct of_device_id of_platform_serial_table[] = { - { .compatible = "ns8250", .data = (void *)PORT_8250, }, - { .compatible = "ns16450", .data = (void *)PORT_16450, }, - { .compatible = "ns16550a", .data = (void *)PORT_16550A, }, - { .compatible = "ns16550", .data = (void *)PORT_16550, }, - { .compatible = "ns16750", .data = (void *)PORT_16750, }, - { .compatible = "ns16850", .data = (void *)PORT_16850, }, - { .compatible = "nvidia,tegra20-uart", .data = (void *)PORT_TEGRA, }, - { .compatible = "nxp,lpc3220-uart", .data = (void *)PORT_LPC3220, }, - { .compatible = "ralink,rt2880-uart", .data = (void *)PORT_RT2880, }, - { .compatible = "altr,16550-FIFO32", - .data = (void *)PORT_ALTR_16550_F32, }, - { .compatible = "altr,16550-FIFO64", - .data = (void *)PORT_ALTR_16550_F64, }, - { .compatible = "altr,16550-FIFO128", - .data = (void *)PORT_ALTR_16550_F128, }, - { .compatible = "mrvl,mmp-uart", - .data = (void *)PORT_XSCALE, }, - { .compatible = "mrvl,pxa-uart", - .data = (void *)PORT_XSCALE, }, - { /* end of list */ }, -}; -MODULE_DEVICE_TABLE(of, of_platform_serial_table); - -static struct platform_driver of_platform_serial_driver = { - .driver = { - .name = "of_serial", - .of_match_table = of_platform_serial_table, - }, - .probe = of_platform_serial_probe, - .remove = of_platform_serial_remove, -}; - -module_platform_driver(of_platform_serial_driver); - -MODULE_AUTHOR("Arnd Bergmann "); -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("Serial Port driver for Open Firmware platform devices");