aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/sysdev/cpm_common.c
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/powerpc/sysdev/cpm_common.c
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/powerpc/sysdev/cpm_common.c')
-rw-r--r--arch/powerpc/sysdev/cpm_common.c159
1 files changed, 159 insertions, 0 deletions
diff --git a/arch/powerpc/sysdev/cpm_common.c b/arch/powerpc/sysdev/cpm_common.c
index 9daa6ac67676..66c8ad4cfce6 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 */