aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/sysdev
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
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')
-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
3 files changed, 181 insertions, 24 deletions
diff --git a/arch/powerpc/sysdev/commproc.c b/arch/powerpc/sysdev/commproc.c
index 428eb8c151b9..f6a63780bbde 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 fc4c99565381..859362fecb7c 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 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 */