1/2 : 8250 serial: dynamic port table from arch
PATCH 1/1 1/2 : 8250 serial: dynamic port table from arch
Hi !
This patch adds the possibility for the arch code to provide a function that gives the list of default motherboard 8250 serial ports instead of relying on a static #define. It was posted earlier, this version takes into account Russell comments, so I hope he's ok with it as-is. It won't change anything for existing archs.
drivers/serial/8250.c +27 -11
@@ -41,7 +41,7 @@#endif #include <linux/serial_core.h> -#include "8250.h" +#include <linux/8250.h> /* * Configuration:
@@ -112,11 +112,18 @@#define SERIAL_PORT_DFNS #endif +#ifndef ARCH_HAS_GET_LEGACY_SERIAL_PORTS static struct old_serial_port old_serial_port[] = {SERIAL_PORT_DFNS /* defined in asm/serial.h */ }; - +static inline struct old_serial_port *get_legacy_serial_ports (unsigned int *count) +{ + *count =ARRAY_SIZE (old_serial_port); +return old_serial_port; +}#define UART_NR (ARRAY_SIZE(old_serial_port) + CONFIG_SERIAL_8250_NR_UARTS) +#endif /* ARCH_HAS_DYNAMIC_LEGACY_SERIAL_PORTS */ +#ifdef CONFIG_SERIAL_8250_RSA
@@ -1839,22 +1846,28 @@ {struct uart_8250_port *up;static int first =1 ; +struct old_serial_port *old_ports; +int count;int i;if (!first)return ; first =0 ; -for (i =0 , up = serial8250_ports; i <ARRAY_SIZE (old_serial_port); + old_ports =get_legacy_serial_ports (&count); +if (old_ports ==NULL ) +return ; + +for (i =0 , up = serial8250_ports; i < count; i++, up++) { - up->port.iobase = old_serial_port[i].port; - up->port.irq =irq_canonicalize (old_serial_port[i].irq); - up->port.uartclk = old_serial_port[i].baud_base *16 ; - up->port.flags = old_serial_port[i].flags; - up->port.hub6 = old_serial_port[i].hub6; - up->port.membase = old_serial_port[i].iomem_base; - up->port.iotype = old_serial_port[i].io_type; - up->port.regshift = old_serial_port[i].iomem_reg_shift; + up->port.iobase = old_ports[i].port; + up->port.irq =irq_canonicalize (old_ports[i].irq); + up->port.uartclk = old_ports[i].baud_base *16 ; + up->port.flags = old_ports[i].flags; + up->port.hub6 = old_ports[i].hub6; + up->port.membase = old_ports[i].iomem_base; + up->port.iotype = old_ports[i].io_type; + up->port.regshift = old_ports[i].iomem_reg_shift; up->port.ops = &serial8250_pops;if (share_irqs) up->port.flags |=UPF_SHARE_IRQ ;
@@ -1870,6 +1883,9 @@for (i =0 ; i <UART_NR ; i++) {struct uart_8250_port *up = &serial8250_ports[i]; +if (!up->port.iobase) +continue ; + up->port.line = i; up->port.ops = &serial8250_pops;init_timer (&up->timer);
dev/null1970-01-01 00:00:00.000000000 +0000 renamed from drivers/serial/8250.h +0 -71
71 lines not on this page · raw message
drivers/serial/8250_pci.c +1 -2
@@ -25,13 +25,12 @@#include <linux/serial.h> #include <linux/serial_core.h> #include <linux/8250_pci.h> +#include <linux/8250.h> #include <asm/bitops.h> #include <asm/byteorder.h> #include <asm/io.h> -#include "8250.h" -/* * Definitions for PCI support. */
drivers/serial/8250_pnp.c +1 -2
@@ -25,13 +25,12 @@#include <linux/serial.h> #include <linux/serialP.h> #include <linux/serial_core.h> +#include <linux/8250.h> #include <asm/bitops.h> #include <asm/byteorder.h> #include <asm/serial.h> -#include "8250.h" -#define UNKNOWN_DEV 0x3000
drivers/serial/au1x00_uart.c +1 -1
@@ -40,7 +40,7 @@#endif #include <linux/serial_core.h> -#include "8250.h" +#include <linux/8250.h> /* * Debugging.
drivers/serial/serial_cs.c +1 -2
@@ -44,6 +44,7 @@#include <linux/serial.h> #include <linux/serial_core.h> #include <linux/major.h> +#include <linux/8250.h> #include <asm/io.h> #include <asm/system.h>
@@ -55,8 +56,6 @@#include <pcmcia/ds.h> #include <pcmcia/cisreg.h> -#include "8250.h" -#ifdef PCMCIA_DEBUG static int pc_debug =PCMCIA_DEBUG ;MODULE_PARM (pc_debug,"i" );
include/linux/8250.h new file +74 -0
74 lines not on this page · raw message
PATCH 1/1 2/2 : 8250 serial: dynamic port table from arch
Hi !
This patch adds a ppc64 implementation of the routine providing the list of default 8250 serial ports. It provides a empty list by default unless the platform code fills it, and it provides a generic function for user by Open Firmware based machines which fills the list based on serial ports found in the OF device-tree.
It depends on the previous patch adding the generic support for this to the 8250 driver.
arch/ppc64/kernel/setup.c +174 -0
@@ -30,6 +30,8 @@#include <linux/notifier.h> #include <linux/cpu.h> #include <linux/unistd.h> +#include <linux/serial.h> +#include <linux/8250.h> #include <asm/io.h> #include <asm/prom.h> #include <asm/processor.h>
@@ -51,6 +53,7 @@#include <asm/system.h> #include <asm/rtas.h> #include <asm/iommu.h> +#include <asm/serial.h> #ifdef DEBUG #define DBG(fmt...) udbg_printf(fmt)
@@ -1106,6 +1109,177 @@__setup ("decr_overclock_proc0=" , set_decr_overclock_proc0 );__setup ("decr_overclock=" , set_decr_overclock ); +/* +* This function can be used by platforms to "find" legacy serial ports. +* It works for "serial" nodes under an "isa" node, and will try to +* respect the "ibm,aix-loc" property if any. It works with up to 8 +* ports. +*/ + +#define MAX_LEGACY_SERIAL_PORTS 8 +static struct old_serial_port old_serial_ports[MAX_LEGACY_SERIAL_PORTS ]; +static unsigned int old_serial_count; + +void __init generic_find_legacy_serial_ports (unsigned int *default_speed) +{ +struct device_node *np; +u32 *sizeprop; + +struct isa_reg_property { +u32 space; +u32 address; +u32 size; + }; +struct pci_reg_property { +struct pci_address addr; +u32 size_hi; +u32 size_lo; + }; + +DBG (" -> generic_find_legacy_serial_port()\n" ); + + naca->serialPortAddr =0 ; +if (default_speed) + *default_speed =0 ; + + np =of_find_node_by_path ("/" ); +if (!np) +return ; + +/* First fill our array */ +for (np =NULL ; (np =of_find_node_by_type (np,"serial" ));) { +struct device_node *isa, *pci; +struct isa_reg_property *reg; +unsigned long phys_size, addr_size, io_base; +u32 *rangesp; +u32 *interrupts, *clk, *spd; +char *typep; +int index, rlen, rentsize; + +/* Ok, first check if it's under an "isa" parent */ + isa =of_get_parent (np); +if (!isa ||strcmp (isa->name,"isa" )) { +DBG ("%s: no isa parent found\n" , np->full_name); +continue ; + } + +/* Now look for an "ibm,aix-loc" property that gives us ordering +* if any... +*/ + typep = (char *)get_property (np,"ibm,aix-loc" ,NULL ); + +/* Get the ISA port number */ + reg = (struct isa_reg_property *)get_property (np,"reg" ,NULL ); +if (reg ==NULL ) + goto next_port; +/* We assume the interrupt number isn't translated ... */ + interrupts = (u32 *)get_property (np,"interrupts" ,NULL ); +/* get clock freq. if present */ + clk = (u32 *)get_property (np,"clock-frequency" ,NULL ); +/* get default speed if present */ + spd = (u32 *)get_property (np,"current-speed" ,NULL ); +/* Default to locate at end of array */ + index = old_serial_count;/* end of the array by default */ + +/* If we have a location index, then use it */ +if (typep && *typep =='S' ) { + index =simple_strtol (typep+1 ,NULL ,0 ) -1 ; +/* if index is out of range, use end of array instead */ +if (index >=MAX_LEGACY_SERIAL_PORTS ) + index = old_serial_count; +/* if our index is still out of range, that mean that +* array is full, we could scan for a free slot but that +* make little sense to bother, just skip the port +*/ +if (index >=MAX_LEGACY_SERIAL_PORTS ) + goto next_port; +if (index >= old_serial_count) + old_serial_count = index +1 ; +/* Check if there is a port who already claimed our slot */ +if (old_serial_ports[index].port !=0 ) { +/* if we still have some room, move it, else override */ +if (old_serial_count <MAX_LEGACY_SERIAL_PORTS ) { +DBG ("Moved legacy port %d -> %d\n" , index, + old_serial_count); + old_serial_ports[old_serial_count++] = + old_serial_ports[index]; + }else { +DBG ("Replacing legacy port %d\n" , index); + } + } + } +if (index >=MAX_LEGACY_SERIAL_PORTS ) + goto next_port; +if (index >= old_serial_count) + old_serial_count = index +1 ; + +/* Now fill the entry */ +memset (&old_serial_ports[index],0 ,sizeof (struct old_serial_port )); + old_serial_ports[index].uart =0 ; + old_serial_ports[index].baud_base = clk ? (*clk /16 ) :BASE_BAUD ; + old_serial_ports[index].port = reg->address; + old_serial_ports[index].irq = interrupts ? interrupts[0 ] :0 ; + old_serial_ports[index].flags =ASYNC_BOOT_AUTOCONF ; + +DBG ("Added legacy port, index: %d, port: %x, irq: %d, clk: %d\n" , + index, + old_serial_ports[index].port, + old_serial_ports[index].irq, + old_serial_ports[index].baud_base *16 ); + +/* Get phys address of IO reg for port 1 */ +if (index !=0 ) + goto next_port; + + pci =of_get_parent (isa); +if (!pci) { +DBG ("%s: no pci parent found\n" , np->full_name); + goto next_port; + } + + rangesp = (u32 *)get_property (pci,"ranges" , &rlen); +if (rangesp ==NULL ) { +of_node_put (pci); + goto next_port; + } + rlen /=4 ; + +/* we need the #size-cells of the PCI bridge node itself */ + phys_size =1 ; + sizeprop = (u32 *)get_property (pci,"#size-cells" ,NULL ); +if (sizeprop !=NULL ) + phys_size = *sizeprop; +/* we need the parent #addr-cells */ + addr_size =prom_n_addr_cells (pci); + rentsize =3 + addr_size + phys_size; + io_base =0 ; +for (;rlen >= rentsize; rlen -= rentsize,rangesp += rentsize) { +if (((rangesp[0 ] >>24 ) &0x3 ) !=1 ) +continue ;/* not IO space */ + io_base = rangesp[3 ]; +if (addr_size ==2 ) + io_base = (io_base <<32 ) | rangesp[4 ]; + } +if (io_base !=0 ) { + naca->serialPortAddr = io_base + reg->address; +if (default_speed && spd) + *default_speed = *spd; + } +of_node_put (pci); + next_port: +of_node_put (isa); + } + +DBG (" <- generic_find_legacy_serial_port()\n" ); +} + +struct old_serial_port *get_legacy_serial_ports (unsigned int *count) +{ + *count = old_serial_count; +return old_serial_ports; +} +EXPORT_SYMBOL (get_legacy_serial_ports); +#ifdef CONFIG_XMON static int __init early_xmon (char *p) {
arch/ppc64/kernel/udbg.c +15 -2
@@ -49,15 +49,28 @@static volatile struct NS16550 *udbg_comport; -void udbg_init_uart (void *comport) +void udbg_init_uart (void *comport,unsigned int speed) { +u8 dll =12 ; + +switch (speed) { +case 115200 : + dll =1 ; +break ; +case 57600 : + dll =2 ; +break ; +case 38400 : + dll =3 ; +break ; + }if (comport) { udbg_comport = (struct NS16550 *)comport; udbg_comport->lcr =0x00 ;eieio (); udbg_comport->ier =0xFF ;eieio (); udbg_comport->ier =0x00 ;eieio (); udbg_comport->lcr =0x80 ;eieio ();/* Access baud rate */ - udbg_comport->dll =12 ;eieio ();/* 1 = 115200, 2 = 57600, 3 = 38400, 12 = 9600 baud */ + udbg_comport->dll = dll;eieio ();/* 1 = 115200, 2 = 57600, 3 = 38400, 12 = 9600 baud */ udbg_comport->dlm =0 ;eieio ();/* dll >> 8 which should be zero for fast rates; */ udbg_comport->lcr =0x03 ;eieio ();/* 8 data, 1 stop, no parity */ udbg_comport->mcr =0x03 ;eieio ();/* RTS/DTR */
include/asm-ppc64/serial.h +6 -106
119 lines not on this page · raw message
arch/ppc64/kernel/pSeries_setup.c +5 -71
106 lines not on this page · raw message
include/asm-ppc64/udbg.h +1 -1
@@ -10,7 +10,7 @@* 2 of the License, or (at your option) any later version. */ -void udbg_init_uart (void *comport); +void udbg_init_uart (void *comport,unsigned int speed);void udbg_putc (unsigned char c);unsigned char udbg_getc (void );int udbg_getc_poll (void );