aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorScott Wood <scottwood@freescale.com>2007-09-28 15:06:16 -0400
committerKumar Gala <galak@kernel.crashing.org>2007-10-04 16:47:05 -0400
commit15f8c604a79c4840ed76eecf3af5d88b7c1dee9e (patch)
treed86815bc2daf835fee081ee7dac92cef8784f6a3 /arch
parent3c5df5c26ed17828760945d59653a2e22e3fb63f (diff)
[POWERPC] cpm: Describe multi-user ram in its own device node.
The way the current CPM binding describes available multi-user (a.k.a. dual-ported) RAM doesn't work well when there are multiple free regions, and it doesn't work at all if the region doesn't begin at the start of the muram area (as the hardware needs to be programmed with offsets into this area). The latter situation can happen with SMC UARTs on CPM2, as its parameter RAM is relocatable, u-boot puts it at zero, and the kernel doesn't support moving it. It is now described with a muram node, similar to QE. The current CPM binding is sufficiently recent (i.e. never appeared in an official release) that compatibility with existing device trees is not an issue. The code supporting the new binding is shared between cpm1 and cpm2, rather than remain separated. QE should be able to use this code as well, once minor fixes are made to its device trees. Signed-off-by: Scott Wood <scottwood@freescale.com> Signed-off-by: Kumar Gala <galak@kernel.crashing.org>
Diffstat (limited to 'arch')
-rw-r--r--arch/powerpc/Kconfig.debug6
-rw-r--r--arch/powerpc/boot/cpm-serial.c44
-rw-r--r--arch/powerpc/boot/dts/ep88xc.dts13
-rw-r--r--arch/powerpc/boot/dts/mpc8272ads.dts11
-rw-r--r--arch/powerpc/boot/dts/mpc885ads.dts13
-rw-r--r--arch/powerpc/boot/dts/pq2fads.dts13
-rw-r--r--arch/powerpc/sysdev/commproc.c11
-rw-r--r--arch/powerpc/sysdev/cpm2_common.c35
-rw-r--r--arch/powerpc/sysdev/cpm_common.c159
9 files changed, 263 insertions, 42 deletions
diff --git a/arch/powerpc/Kconfig.debug b/arch/powerpc/Kconfig.debug
index f4e5d22312a..464f9b4b316 100644
--- a/arch/powerpc/Kconfig.debug
+++ b/arch/powerpc/Kconfig.debug
@@ -245,9 +245,9 @@ config PPC_EARLY_DEBUG_44x_PHYSHIGH
245config PPC_EARLY_DEBUG_CPM_ADDR 245config PPC_EARLY_DEBUG_CPM_ADDR
246 hex "CPM UART early debug transmit descriptor address" 246 hex "CPM UART early debug transmit descriptor address"
247 depends on PPC_EARLY_DEBUG_CPM 247 depends on PPC_EARLY_DEBUG_CPM
248 default "0xfa202808" if PPC_EP88XC 248 default "0xfa202008" if PPC_EP88XC
249 default "0xf0000808" if CPM2 249 default "0xf0000008" if CPM2
250 default "0xff002808" if CPM1 250 default "0xff002008" if CPM1
251 help 251 help
252 This specifies the address of the transmit descriptor 252 This specifies the address of the transmit descriptor
253 used for early debug output. Because it is needed before 253 used for early debug output. Because it is needed before
diff --git a/arch/powerpc/boot/cpm-serial.c b/arch/powerpc/boot/cpm-serial.c
index fcb8b5e956b..28296facb2a 100644
--- a/arch/powerpc/boot/cpm-serial.c
+++ b/arch/powerpc/boot/cpm-serial.c
@@ -56,7 +56,8 @@ static struct cpm_smc *smc;
56static struct cpm_scc *scc; 56static struct cpm_scc *scc;
57struct cpm_bd *tbdf, *rbdf; 57struct cpm_bd *tbdf, *rbdf;
58static u32 cpm_cmd; 58static u32 cpm_cmd;
59static u8 *dpram_start; 59static u8 *muram_start;
60static u32 muram_offset;
60 61
61static void (*do_cmd)(int op); 62static void (*do_cmd)(int op);
62static void (*enable_port)(void); 63static void (*enable_port)(void);
@@ -114,13 +115,12 @@ static void scc_enable_port(void)
114 115
115static int cpm_serial_open(void) 116static int cpm_serial_open(void)
116{ 117{
117 int dpaddr = 0x800;
118 disable_port(); 118 disable_port();
119 119
120 out_8(&param->rfcr, 0x10); 120 out_8(&param->rfcr, 0x10);
121 out_8(&param->tfcr, 0x10); 121 out_8(&param->tfcr, 0x10);
122 122
123 rbdf = (struct cpm_bd *)(dpram_start + dpaddr); 123 rbdf = (struct cpm_bd *)muram_start;
124 rbdf->addr = (u8 *)(rbdf + 2); 124 rbdf->addr = (u8 *)(rbdf + 2);
125 rbdf->sc = 0xa000; 125 rbdf->sc = 0xa000;
126 rbdf->len = 1; 126 rbdf->len = 1;
@@ -131,8 +131,8 @@ static int cpm_serial_open(void)
131 tbdf->len = 1; 131 tbdf->len = 1;
132 132
133 sync(); 133 sync();
134 out_be16(&param->rbase, dpaddr); 134 out_be16(&param->rbase, muram_offset);
135 out_be16(&param->tbase, dpaddr + sizeof(struct cpm_bd)); 135 out_be16(&param->tbase, muram_offset + sizeof(struct cpm_bd));
136 136
137 do_cmd(CPM_CMD_INIT_RX_TX); 137 do_cmd(CPM_CMD_INIT_RX_TX);
138 138
@@ -178,7 +178,7 @@ int cpm_console_init(void *devp, struct serial_console_data *scdp)
178 void *reg_virt[2]; 178 void *reg_virt[2];
179 int is_smc = 0, is_cpm2 = 0, n; 179 int is_smc = 0, is_cpm2 = 0, n;
180 unsigned long reg_phys; 180 unsigned long reg_phys;
181 void *parent; 181 void *parent, *muram;
182 182
183 if (dt_is_compatible(devp, "fsl,cpm1-smc-uart")) { 183 if (dt_is_compatible(devp, "fsl,cpm1-smc-uart")) {
184 is_smc = 1; 184 is_smc = 1;
@@ -229,16 +229,36 @@ int cpm_console_init(void *devp, struct serial_console_data *scdp)
229 229
230 n = getprop(parent, "virtual-reg", reg_virt, sizeof(reg_virt)); 230 n = getprop(parent, "virtual-reg", reg_virt, sizeof(reg_virt));
231 if (n < (int)sizeof(reg_virt)) { 231 if (n < (int)sizeof(reg_virt)) {
232 for (n = 0; n < 2; n++) { 232 if (!dt_xlate_reg(parent, 0, &reg_phys, NULL))
233 if (!dt_xlate_reg(parent, n, &reg_phys, NULL)) 233 return -1;
234 return -1;
235 234
236 reg_virt[n] = (void *)reg_phys; 235 reg_virt[0] = (void *)reg_phys;
237 }
238 } 236 }
239 237
240 cpcr = reg_virt[0]; 238 cpcr = reg_virt[0];
241 dpram_start = reg_virt[1]; 239
240 muram = finddevice("/soc/cpm/muram/data");
241 if (!muram)
242 return -1;
243
244 /* For bootwrapper-compatible device trees, we assume that the first
245 * entry has at least 18 bytes, and that #address-cells/#data-cells
246 * is one for both parent and child.
247 */
248
249 n = getprop(muram, "virtual-reg", reg_virt, sizeof(reg_virt));
250 if (n < (int)sizeof(reg_virt)) {
251 if (!dt_xlate_reg(muram, 0, &reg_phys, NULL))
252 return -1;
253
254 reg_virt[0] = (void *)reg_phys;
255 }
256
257 muram_start = reg_virt[0];
258
259 n = getprop(muram, "reg", &muram_offset, 4);
260 if (n < 4)
261 return -1;
242 262
243 scdp->open = cpm_serial_open; 263 scdp->open = cpm_serial_open;
244 scdp->putc = cpm_serial_putc; 264 scdp->putc = cpm_serial_putc;
diff --git a/arch/powerpc/boot/dts/ep88xc.dts b/arch/powerpc/boot/dts/ep88xc.dts
index 0406fc50b2a..02705f29979 100644
--- a/arch/powerpc/boot/dts/ep88xc.dts
+++ b/arch/powerpc/boot/dts/ep88xc.dts
@@ -142,9 +142,20 @@
142 command-proc = <9c0>; 142 command-proc = <9c0>;
143 interrupts = <0>; // cpm error interrupt 143 interrupts = <0>; // cpm error interrupt
144 interrupt-parent = <&CPM_PIC>; 144 interrupt-parent = <&CPM_PIC>;
145 reg = <9c0 40 2000 1c00>; 145 reg = <9c0 40>;
146 ranges; 146 ranges;
147 147
148 muram@2000 {
149 #address-cells = <1>;
150 #size-cells = <1>;
151 ranges = <0 2000 2000>;
152
153 data@0 {
154 compatible = "fsl,cpm-muram-data";
155 reg = <0 1c00>;
156 };
157 };
158
148 brg@9f0 { 159 brg@9f0 {
149 compatible = "fsl,mpc885-brg", 160 compatible = "fsl,mpc885-brg",
150 "fsl,cpm1-brg", 161 "fsl,cpm1-brg",
diff --git a/arch/powerpc/boot/dts/mpc8272ads.dts b/arch/powerpc/boot/dts/mpc8272ads.dts
index 3fe991d4cb0..188179df084 100644
--- a/arch/powerpc/boot/dts/mpc8272ads.dts
+++ b/arch/powerpc/boot/dts/mpc8272ads.dts
@@ -124,6 +124,17 @@
124 reg = <119c0 30 0 2000>; 124 reg = <119c0 30 0 2000>;
125 ranges; 125 ranges;
126 126
127 muram@0 {
128 #address-cells = <1>;
129 #size-cells = <1>;
130 ranges = <0 0 10000>;
131
132 data@0 {
133 compatible = "fsl,cpm-muram-data";
134 reg = <0 2000 9800 800>;
135 };
136 };
137
127 brg@119f0 { 138 brg@119f0 {
128 compatible = "fsl,mpc8272-brg", 139 compatible = "fsl,mpc8272-brg",
129 "fsl,cpm2-brg", 140 "fsl,cpm2-brg",
diff --git a/arch/powerpc/boot/dts/mpc885ads.dts b/arch/powerpc/boot/dts/mpc885ads.dts
index cbcd16f74c4..8848e637293 100644
--- a/arch/powerpc/boot/dts/mpc885ads.dts
+++ b/arch/powerpc/boot/dts/mpc885ads.dts
@@ -148,9 +148,20 @@
148 command-proc = <9c0>; 148 command-proc = <9c0>;
149 interrupts = <0>; // cpm error interrupt 149 interrupts = <0>; // cpm error interrupt
150 interrupt-parent = <&CPM_PIC>; 150 interrupt-parent = <&CPM_PIC>;
151 reg = <9c0 40 2000 1c00>; 151 reg = <9c0 40>;
152 ranges; 152 ranges;
153 153
154 muram@2000 {
155 #address-cells = <1>;
156 #size-cells = <1>;
157 ranges = <0 2000 2000>;
158
159 data@0 {
160 compatible = "fsl,cpm-muram-data";
161 reg = <0 1c00>;
162 };
163 };
164
154 brg@9f0 { 165 brg@9f0 {
155 compatible = "fsl,mpc885-brg", 166 compatible = "fsl,mpc885-brg",
156 "fsl,cpm1-brg", 167 "fsl,cpm1-brg",
diff --git a/arch/powerpc/boot/dts/pq2fads.dts b/arch/powerpc/boot/dts/pq2fads.dts
index 54e8bd1ae22..2d564921897 100644
--- a/arch/powerpc/boot/dts/pq2fads.dts
+++ b/arch/powerpc/boot/dts/pq2fads.dts
@@ -119,9 +119,20 @@
119 #size-cells = <1>; 119 #size-cells = <1>;
120 #interrupt-cells = <2>; 120 #interrupt-cells = <2>;
121 compatible = "fsl,mpc8280-cpm", "fsl,cpm2"; 121 compatible = "fsl,mpc8280-cpm", "fsl,cpm2";
122 reg = <119c0 30 0 2000>; 122 reg = <119c0 30>;
123 ranges; 123 ranges;
124 124
125 muram@0 {
126 #address-cells = <1>;
127 #size-cells = <1>;
128 ranges = <0 0 10000>;
129
130 data@0 {
131 compatible = "fsl,cpm-muram-data";
132 reg = <0 2000 9800 800>;
133 };
134 };
135
125 brg@119f0 { 136 brg@119f0 {
126 compatible = "fsl,mpc8280-brg", 137 compatible = "fsl,mpc8280-brg",
127 "fsl,cpm2-brg", 138 "fsl,cpm2-brg",
diff --git a/arch/powerpc/sysdev/commproc.c b/arch/powerpc/sysdev/commproc.c
index 428eb8c151b..f6a63780bbd 100644
--- a/arch/powerpc/sysdev/commproc.c
+++ b/arch/powerpc/sysdev/commproc.c
@@ -39,12 +39,15 @@
39#include <asm/tlbflush.h> 39#include <asm/tlbflush.h>
40#include <asm/rheap.h> 40#include <asm/rheap.h>
41#include <asm/prom.h> 41#include <asm/prom.h>
42#include <asm/cpm.h>
42 43
43#include <asm/fs_pd.h> 44#include <asm/fs_pd.h>
44 45
45#define CPM_MAP_SIZE (0x4000) 46#define CPM_MAP_SIZE (0x4000)
46 47
48#ifndef CONFIG_PPC_CPM_NEW_BINDING
47static void m8xx_cpm_dpinit(void); 49static void m8xx_cpm_dpinit(void);
50#endif
48static uint host_buffer; /* One page of host buffer */ 51static uint host_buffer; /* One page of host buffer */
49static uint host_end; /* end + 1 */ 52static uint host_end; /* end + 1 */
50cpm8xx_t __iomem *cpmp; /* Pointer to comm processor space */ 53cpm8xx_t __iomem *cpmp; /* Pointer to comm processor space */
@@ -193,7 +196,7 @@ end:
193 return sirq; 196 return sirq;
194} 197}
195 198
196void cpm_reset(void) 199void __init cpm_reset(void)
197{ 200{
198 sysconf8xx_t __iomem *siu_conf; 201 sysconf8xx_t __iomem *siu_conf;
199 202
@@ -229,8 +232,12 @@ void cpm_reset(void)
229 out_be32(&siu_conf->sc_sdcr, 1); 232 out_be32(&siu_conf->sc_sdcr, 1);
230 immr_unmap(siu_conf); 233 immr_unmap(siu_conf);
231 234
235#ifdef CONFIG_PPC_CPM_NEW_BINDING
236 cpm_muram_init();
237#else
232 /* Reclaim the DP memory for our use. */ 238 /* Reclaim the DP memory for our use. */
233 m8xx_cpm_dpinit(); 239 m8xx_cpm_dpinit();
240#endif
234} 241}
235 242
236/* We used to do this earlier, but have to postpone as long as possible 243/* We used to do this earlier, but have to postpone as long as possible
@@ -296,6 +303,7 @@ cpm_setbrg(uint brg, uint rate)
296 CPM_BRG_EN | CPM_BRG_DIV16); 303 CPM_BRG_EN | CPM_BRG_DIV16);
297} 304}
298 305
306#ifndef CONFIG_PPC_CPM_NEW_BINDING
299/* 307/*
300 * dpalloc / dpfree bits. 308 * dpalloc / dpfree bits.
301 */ 309 */
@@ -397,6 +405,7 @@ uint cpm_dpram_phys(u8 *addr)
397 return (dpram_pbase + (uint)(addr - dpram_vbase)); 405 return (dpram_pbase + (uint)(addr - dpram_vbase));
398} 406}
399EXPORT_SYMBOL(cpm_dpram_phys); 407EXPORT_SYMBOL(cpm_dpram_phys);
408#endif /* !CONFIG_PPC_CPM_NEW_BINDING */
400 409
401struct cpm_ioport16 { 410struct cpm_ioport16 {
402 __be16 dir, par, sor, dat, intr; 411 __be16 dir, par, sor, dat, intr;
diff --git a/arch/powerpc/sysdev/cpm2_common.c b/arch/powerpc/sysdev/cpm2_common.c
index fc4c9956538..859362fecb7 100644
--- a/arch/powerpc/sysdev/cpm2_common.c
+++ b/arch/powerpc/sysdev/cpm2_common.c
@@ -46,7 +46,10 @@
46 46
47#include <sysdev/fsl_soc.h> 47#include <sysdev/fsl_soc.h>
48 48
49#ifndef CONFIG_PPC_CPM_NEW_BINDING
49static void cpm2_dpinit(void); 50static void cpm2_dpinit(void);
51#endif
52
50cpm_cpm2_t __iomem *cpmp; /* Pointer to comm processor space */ 53cpm_cpm2_t __iomem *cpmp; /* Pointer to comm processor space */
51 54
52/* We allocate this here because it is used almost exclusively for 55/* We allocate this here because it is used almost exclusively for
@@ -69,7 +72,11 @@ cpm2_reset(void)
69 72
70 /* Reclaim the DP memory for our use. 73 /* Reclaim the DP memory for our use.
71 */ 74 */
75#ifdef CONFIG_PPC_CPM_NEW_BINDING
76 cpm_muram_init();
77#else
72 cpm2_dpinit(); 78 cpm2_dpinit();
79#endif
73 80
74 /* Tell everyone where the comm processor resides. 81 /* Tell everyone where the comm processor resides.
75 */ 82 */
@@ -316,6 +323,7 @@ int cpm2_smc_clk_setup(enum cpm_clk_target target, int clock)
316 return ret; 323 return ret;
317} 324}
318 325
326#ifndef CONFIG_PPC_CPM_NEW_BINDING
319/* 327/*
320 * dpalloc / dpfree bits. 328 * dpalloc / dpfree bits.
321 */ 329 */
@@ -328,28 +336,6 @@ static u8 __iomem *im_dprambase;
328 336
329static void cpm2_dpinit(void) 337static void cpm2_dpinit(void)
330{ 338{
331 struct resource r;
332
333#ifdef CONFIG_PPC_CPM_NEW_BINDING
334 struct device_node *np;
335
336 np = of_find_compatible_node(NULL, NULL, "fsl,cpm2");
337 if (!np)
338 panic("Cannot find CPM2 node");
339
340 if (of_address_to_resource(np, 1, &r))
341 panic("Cannot get CPM2 resource 1");
342
343 of_node_put(np);
344#else
345 r.start = CPM_MAP_ADDR;
346 r.end = r.start + CPM_DATAONLY_BASE + CPM_DATAONLY_SIZE - 1;
347#endif
348
349 im_dprambase = ioremap(r.start, r.end - r.start + 1);
350 if (!im_dprambase)
351 panic("Cannot map DPRAM");
352
353 spin_lock_init(&cpm_dpmem_lock); 339 spin_lock_init(&cpm_dpmem_lock);
354 340
355 /* initialize the info header */ 341 /* initialize the info header */
@@ -358,13 +344,15 @@ static void cpm2_dpinit(void)
358 sizeof(cpm_boot_dpmem_rh_block[0]), 344 sizeof(cpm_boot_dpmem_rh_block[0]),
359 cpm_boot_dpmem_rh_block); 345 cpm_boot_dpmem_rh_block);
360 346
347 im_dprambase = cpm2_immr;
348
361 /* Attach the usable dpmem area */ 349 /* Attach the usable dpmem area */
362 /* XXX: This is actually crap. CPM_DATAONLY_BASE and 350 /* XXX: This is actually crap. CPM_DATAONLY_BASE and
363 * CPM_DATAONLY_SIZE is only a subset of the available dpram. It 351 * CPM_DATAONLY_SIZE is only a subset of the available dpram. It
364 * varies with the processor and the microcode patches activated. 352 * varies with the processor and the microcode patches activated.
365 * But the following should be at least safe. 353 * But the following should be at least safe.
366 */ 354 */
367 rh_attach_region(&cpm_dpmem_info, 0, r.end - r.start + 1); 355 rh_attach_region(&cpm_dpmem_info, CPM_DATAONLY_BASE, CPM_DATAONLY_SIZE);
368} 356}
369 357
370/* This function returns an index into the DPRAM area. 358/* This function returns an index into the DPRAM area.
@@ -422,6 +410,7 @@ void *cpm_dpram_addr(unsigned long offset)
422 return (void *)(im_dprambase + offset); 410 return (void *)(im_dprambase + offset);
423} 411}
424EXPORT_SYMBOL(cpm_dpram_addr); 412EXPORT_SYMBOL(cpm_dpram_addr);
413#endif /* !CONFIG_PPC_CPM_NEW_BINDING */
425 414
426struct cpm2_ioports { 415struct cpm2_ioports {
427 u32 dir, par, sor, odr, dat; 416 u32 dir, par, sor, odr, dat;
diff --git a/arch/powerpc/sysdev/cpm_common.c b/arch/powerpc/sysdev/cpm_common.c
index 9daa6ac6767..66c8ad4cfce 100644
--- a/arch/powerpc/sysdev/cpm_common.c
+++ b/arch/powerpc/sysdev/cpm_common.c
@@ -5,15 +5,27 @@
5 * 5 *
6 * Copyright 2007 Freescale Semiconductor, Inc. 6 * Copyright 2007 Freescale Semiconductor, Inc.
7 * 7 *
8 * Some parts derived from commproc.c/cpm2_common.c, which is:
9 * Copyright (c) 1997 Dan error_act (dmalek@jlc.net)
10 * Copyright (c) 1999-2001 Dan Malek <dan@embeddedalley.com>
11 * Copyright (c) 2000 MontaVista Software, Inc (source@mvista.com)
12 * 2006 (c) MontaVista Software, Inc.
13 * Vitaly Bordug <vbordug@ru.mvista.com>
14 *
8 * This program is free software; you can redistribute it and/or modify 15 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of version 2 of the GNU General Public License as 16 * it under the terms of version 2 of the GNU General Public License as
10 * published by the Free Software Foundation. 17 * published by the Free Software Foundation.
11 */ 18 */
12 19
13#include <linux/init.h> 20#include <linux/init.h>
21#include <linux/of_device.h>
22
14#include <asm/udbg.h> 23#include <asm/udbg.h>
15#include <asm/io.h> 24#include <asm/io.h>
16#include <asm/system.h> 25#include <asm/system.h>
26#include <asm/rheap.h>
27#include <asm/cpm.h>
28
17#include <mm/mmu_decl.h> 29#include <mm/mmu_decl.h>
18 30
19#ifdef CONFIG_PPC_EARLY_DEBUG_CPM 31#ifdef CONFIG_PPC_EARLY_DEBUG_CPM
@@ -41,6 +53,153 @@ void __init udbg_init_cpm(void)
41 setbat(1, 0xf0000000, 0xf0000000, 1024*1024, _PAGE_IO); 53 setbat(1, 0xf0000000, 0xf0000000, 1024*1024, _PAGE_IO);
42#endif 54#endif
43 udbg_putc = udbg_putc_cpm; 55 udbg_putc = udbg_putc_cpm;
56 udbg_putc('X');
44 } 57 }
45} 58}
46#endif 59#endif
60
61#ifdef CONFIG_PPC_CPM_NEW_BINDING
62static spinlock_t cpm_muram_lock;
63static rh_block_t cpm_boot_muram_rh_block[16];
64static rh_info_t cpm_muram_info;
65static u8 __iomem *muram_vbase;
66static phys_addr_t muram_pbase;
67
68/* Max address size we deal with */
69#define OF_MAX_ADDR_CELLS 4
70
71int __init cpm_muram_init(void)
72{
73 struct device_node *np;
74 struct resource r;
75 u32 zero[OF_MAX_ADDR_CELLS] = {};
76 resource_size_t max = 0;
77 int i = 0;
78 int ret = 0;
79
80 printk("cpm_muram_init\n");
81
82 spin_lock_init(&cpm_muram_lock);
83 /* initialize the info header */
84 rh_init(&cpm_muram_info, 1,
85 sizeof(cpm_boot_muram_rh_block) /
86 sizeof(cpm_boot_muram_rh_block[0]),
87 cpm_boot_muram_rh_block);
88
89 np = of_find_compatible_node(NULL, NULL, "fsl,cpm-muram-data");
90 if (!np) {
91 printk(KERN_ERR "Cannot find CPM muram data node");
92 ret = -ENODEV;
93 goto out;
94 }
95
96 muram_pbase = of_translate_address(np, zero);
97 if (muram_pbase == (phys_addr_t)OF_BAD_ADDR) {
98 printk(KERN_ERR "Cannot translate zero through CPM muram node");
99 ret = -ENODEV;
100 goto out;
101 }
102
103 while (of_address_to_resource(np, i++, &r) == 0) {
104 if (r.end > max)
105 max = r.end;
106
107 rh_attach_region(&cpm_muram_info, r.start - muram_pbase,
108 r.end - r.start + 1);
109 }
110
111 muram_vbase = ioremap(muram_pbase, max - muram_pbase + 1);
112 if (!muram_vbase) {
113 printk(KERN_ERR "Cannot map CPM muram");
114 ret = -ENOMEM;
115 }
116
117out:
118 of_node_put(np);
119 return ret;
120}
121
122/**
123 * cpm_muram_alloc - allocate the requested size worth of multi-user ram
124 * @size: number of bytes to allocate
125 * @align: requested alignment, in bytes
126 *
127 * This function returns an offset into the muram area.
128 * Use cpm_dpram_addr() to get the virtual address of the area.
129 * Use cpm_muram_free() to free the allocation.
130 */
131unsigned long cpm_muram_alloc(unsigned long size, unsigned long align)
132{
133 unsigned long start;
134 unsigned long flags;
135
136 spin_lock_irqsave(&cpm_muram_lock, flags);
137 cpm_muram_info.alignment = align;
138 start = rh_alloc(&cpm_muram_info, size, "commproc");
139 spin_unlock_irqrestore(&cpm_muram_lock, flags);
140
141 return start;
142}
143EXPORT_SYMBOL(cpm_muram_alloc);
144
145/**
146 * cpm_muram_free - free a chunk of multi-user ram
147 * @offset: The beginning of the chunk as returned by cpm_muram_alloc().
148 */
149int cpm_muram_free(unsigned long offset)
150{
151 int ret;
152 unsigned long flags;
153
154 spin_lock_irqsave(&cpm_muram_lock, flags);
155 ret = rh_free(&cpm_muram_info, offset);
156 spin_unlock_irqrestore(&cpm_muram_lock, flags);
157
158 return ret;
159}
160EXPORT_SYMBOL(cpm_muram_free);
161
162/**
163 * cpm_muram_alloc_fixed - reserve a specific region of multi-user ram
164 * @offset: the offset into the muram area to reserve
165 * @size: the number of bytes to reserve
166 *
167 * This function returns "start" on success, -ENOMEM on failure.
168 * Use cpm_dpram_addr() to get the virtual address of the area.
169 * Use cpm_muram_free() to free the allocation.
170 */
171unsigned long cpm_muram_alloc_fixed(unsigned long offset, unsigned long size)
172{
173 unsigned long start;
174 unsigned long flags;
175
176 spin_lock_irqsave(&cpm_muram_lock, flags);
177 cpm_muram_info.alignment = 1;
178 start = rh_alloc_fixed(&cpm_muram_info, offset, size, "commproc");
179 spin_unlock_irqrestore(&cpm_muram_lock, flags);
180
181 return start;
182}
183EXPORT_SYMBOL(cpm_muram_alloc_fixed);
184
185/**
186 * cpm_muram_addr - turn a muram offset into a virtual address
187 * @offset: muram offset to convert
188 */
189void __iomem *cpm_muram_addr(unsigned long offset)
190{
191 return muram_vbase + offset;
192}
193EXPORT_SYMBOL(cpm_muram_addr);
194
195/**
196 * cpm_muram_phys - turn a muram virtual address into a DMA address
197 * @offset: virtual address from cpm_muram_addr() to convert
198 */
199dma_addr_t cpm_muram_dma(void __iomem *addr)
200{
201 return muram_pbase + ((u8 __iomem *)addr - muram_vbase);
202}
203EXPORT_SYMBOL(cpm_muram_dma);
204
205#endif /* CONFIG_PPC_CPM_NEW_BINDING */