[POWERPC] cpm_uart: Allocate DPRAM memory for SMC ports on CPM2-based platforms.
authorLaurent Pinchart <laurentp@cse-semaphore.com>
Thu, 10 Apr 2008 15:01:27 +0000 (17:01 +0200)
committerKumar Gala <galak@kernel.crashing.org>
Thu, 17 Apr 2008 06:01:36 +0000 (01:01 -0500)
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>
drivers/serial/cpm_uart/cpm_uart.h
drivers/serial/cpm_uart/cpm_uart_core.c
drivers/serial/cpm_uart/cpm_uart_cpm1.c
drivers/serial/cpm_uart/cpm_uart_cpm2.c

index 32b9737..0cc39f8 100644 (file)
@@ -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);
index 236af9d..a638ba0 100644 (file)
@@ -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;
index 6ea0366..74f1432 100644 (file)
@@ -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)
 {
index d9af06a..bb862e2 100644 (file)
@@ -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)
 {