diff options
author | Laurent Pinchart <laurentp@cse-semaphore.com> | 2008-04-10 17:01:27 +0200 |
---|---|---|
committer | Kumar Gala <galak@kernel.crashing.org> | 2008-04-17 01:01:36 -0500 |
commit | d464df2667cf181419604e656773f80996cf0470 (patch) | |
tree | fedca2185763550331f0a73450c1d82f0c146ad6 | |
parent | 1028d4f162796a99b87565b6b40b5fec79c242d0 (diff) |
[POWERPC] cpm_uart: Allocate DPRAM memory for SMC ports on CPM2-based platforms.
This patch allocates parameter RAM for SMC serial ports without relying on
previous initialisation by a boot loader or a wrapper layer.
SMC parameter RAM on CPM2-based platforms can be allocated anywhere in the
general-purpose areas of the dual-port RAM. The current code relies on the
boot loader to allocate a section of general-purpose CPM RAM and gets the
section address from the device tree.
This patch modifies the device tree address usage to reference the SMC
parameter RAM base pointer instead of a pre-allocated RAM section and
allocates memory from the CPM dual-port RAM when initialising the SMC port.
CPM1-based platforms are not affected.
Signed-off-by: Laurent Pinchart <laurentp@cse-semaphore.com>
Acked-by: Scott Wood <scottwood@freescale.com>
Signed-off-by: Kumar Gala <galak@kernel.crashing.org>
-rw-r--r-- | drivers/serial/cpm_uart/cpm_uart.h | 3 | ||||
-rw-r--r-- | drivers/serial/cpm_uart/cpm_uart_core.c | 19 | ||||
-rw-r--r-- | drivers/serial/cpm_uart/cpm_uart_cpm1.c | 14 | ||||
-rw-r--r-- | drivers/serial/cpm_uart/cpm_uart_cpm2.c | 52 |
4 files changed, 78 insertions, 10 deletions
diff --git a/drivers/serial/cpm_uart/cpm_uart.h b/drivers/serial/cpm_uart/cpm_uart.h index 32b9737759c..0cc39f82d7c 100644 --- a/drivers/serial/cpm_uart/cpm_uart.h +++ b/drivers/serial/cpm_uart/cpm_uart.h @@ -92,6 +92,9 @@ extern struct uart_cpm_port cpm_uart_ports[UART_NR]; /* these are located in their respective files */ void cpm_line_cr_cmd(struct uart_cpm_port *port, int cmd); +void __iomem *cpm_uart_map_pram(struct uart_cpm_port *port, + struct device_node *np); +void cpm_uart_unmap_pram(struct uart_cpm_port *port, void __iomem *pram); int cpm_uart_init_portdesc(void); int cpm_uart_allocbuf(struct uart_cpm_port *pinfo, unsigned int is_con); void cpm_uart_freebuf(struct uart_cpm_port *pinfo); diff --git a/drivers/serial/cpm_uart/cpm_uart_core.c b/drivers/serial/cpm_uart/cpm_uart_core.c index 236af9d3385..a638ba0679a 100644 --- a/drivers/serial/cpm_uart/cpm_uart_core.c +++ b/drivers/serial/cpm_uart/cpm_uart_core.c @@ -966,24 +966,23 @@ static int cpm_uart_init_port(struct device_node *np, if (!mem) return -ENOMEM; - pram = of_iomap(np, 1); - if (!pram) { - ret = -ENOMEM; - goto out_mem; - } - if (of_device_is_compatible(np, "fsl,cpm1-scc-uart") || of_device_is_compatible(np, "fsl,cpm2-scc-uart")) { pinfo->sccp = mem; - pinfo->sccup = pram; + pinfo->sccup = pram = cpm_uart_map_pram(pinfo, np); } else if (of_device_is_compatible(np, "fsl,cpm1-smc-uart") || of_device_is_compatible(np, "fsl,cpm2-smc-uart")) { pinfo->flags |= FLAG_SMC; pinfo->smcp = mem; - pinfo->smcup = pram; + pinfo->smcup = pram = cpm_uart_map_pram(pinfo, np); } else { ret = -ENODEV; - goto out_pram; + goto out_mem; + } + + if (!pram) { + ret = -ENOMEM; + goto out_mem; } pinfo->tx_nrfifos = TX_NUM_FIFO; @@ -1007,7 +1006,7 @@ static int cpm_uart_init_port(struct device_node *np, return cpm_uart_request_port(&pinfo->port); out_pram: - iounmap(pram); + cpm_uart_unmap_pram(pinfo, pram); out_mem: iounmap(mem); return ret; diff --git a/drivers/serial/cpm_uart/cpm_uart_cpm1.c b/drivers/serial/cpm_uart/cpm_uart_cpm1.c index 6ea0366e26a..74f1432bb24 100644 --- a/drivers/serial/cpm_uart/cpm_uart_cpm1.c +++ b/drivers/serial/cpm_uart/cpm_uart_cpm1.c @@ -45,6 +45,8 @@ #include <linux/serial_core.h> #include <linux/kernel.h> +#include <linux/of.h> + #include "cpm_uart.h" /**************************************************************/ @@ -54,6 +56,18 @@ void cpm_line_cr_cmd(struct uart_cpm_port *port, int cmd) { cpm_command(port->command, cmd); } + +void __iomem *cpm_uart_map_pram(struct uart_cpm_port *port, + struct device_node *np) +{ + return of_iomap(np, 1); +} + +void cpm_uart_unmap_pram(struct uart_cpm_port *port, void __iomem *pram) +{ + iounmap(pram); +} + #else void cpm_line_cr_cmd(struct uart_cpm_port *port, int cmd) { diff --git a/drivers/serial/cpm_uart/cpm_uart_cpm2.c b/drivers/serial/cpm_uart/cpm_uart_cpm2.c index d9af06a791b..bb862e2f54c 100644 --- a/drivers/serial/cpm_uart/cpm_uart_cpm2.c +++ b/drivers/serial/cpm_uart/cpm_uart_cpm2.c @@ -41,6 +41,9 @@ #include <asm/io.h> #include <asm/irq.h> #include <asm/fs_pd.h> +#ifdef CONFIG_PPC_CPM_NEW_BINDING +#include <asm/prom.h> +#endif #include <linux/serial_core.h> #include <linux/kernel.h> @@ -54,6 +57,55 @@ void cpm_line_cr_cmd(struct uart_cpm_port *port, int cmd) { cpm_command(port->command, cmd); } + +void __iomem *cpm_uart_map_pram(struct uart_cpm_port *port, + struct device_node *np) +{ + void __iomem *pram; + unsigned long offset; + struct resource res; + unsigned long len; + + /* Don't remap parameter RAM if it has already been initialized + * during console setup. + */ + if (IS_SMC(port) && port->smcup) + return port->smcup; + else if (!IS_SMC(port) && port->sccup) + return port->sccup; + + if (of_address_to_resource(np, 1, &res)) + return NULL; + + len = 1 + res.end - res.start; + pram = ioremap(res.start, len); + if (!pram) + return NULL; + + if (!IS_SMC(port)) + return pram; + + if (len != 2) { + printk(KERN_WARNING "cpm_uart[%d]: device tree references " + "SMC pram, using boot loader/wrapper pram mapping. " + "Please fix your device tree to reference the pram " + "base register instead.\n", + port->port.line); + return pram; + } + + offset = cpm_dpalloc(PROFF_SMC_SIZE, 64); + out_be16(pram, offset); + iounmap(pram); + return cpm_muram_addr(offset); +} + +void cpm_uart_unmap_pram(struct uart_cpm_port *port, void __iomem *pram) +{ + if (!IS_SMC(port)) + iounmap(pram); +} + #else void cpm_line_cr_cmd(struct uart_cpm_port *port, int cmd) { |