1/*
2 * General Purpose functions for the global management of the
3 * 8260 Communication Processor Module.
4 * Copyright (c) 1999-2001 Dan Malek <dan@embeddedalley.com>
5 * Copyright (c) 2000 MontaVista Software, Inc (source@mvista.com)
6 *	2.3.99 Updates
7 *
8 * 2006 (c) MontaVista Software, Inc.
9 * Vitaly Bordug <vbordug@ru.mvista.com>
10 * 	Merged to arch/powerpc from arch/ppc/syslib/cpm2_common.c
11 *
12 * This file is licensed under the terms of the GNU General Public License
13 * version 2. This program is licensed "as is" without any warranty of any
14 * kind, whether express or implied.
15 */
16
17/*
18 *
19 * In addition to the individual control of the communication
20 * channels, there are a few functions that globally affect the
21 * communication processor.
22 *
23 * Buffer descriptors must be allocated from the dual ported memory
24 * space.  The allocator for that is here.  When the communication
25 * process is reset, we reclaim the memory available.  There is
26 * currently no deallocator for this memory.
27 */
28#include <linux/errno.h>
29#include <linux/sched.h>
30#include <linux/kernel.h>
31#include <linux/param.h>
32#include <linux/string.h>
33#include <linux/mm.h>
34#include <linux/interrupt.h>
35#include <linux/module.h>
36#include <asm/io.h>
37#include <asm/irq.h>
38#include <asm/mpc8260.h>
39#include <asm/page.h>
40#include <asm/pgtable.h>
41#include <asm/cpm2.h>
42#include <asm/rheap.h>
43#include <asm/fs_pd.h>
44
45#include <sysdev/fsl_soc.h>
46
47static void cpm2_dpinit(void);
48cpm_cpm2_t	*cpmp;		/* Pointer to comm processor space */
49
50/* We allocate this here because it is used almost exclusively for
51 * the communication processor devices.
52 */
53cpm2_map_t *cpm2_immr;
54intctl_cpm2_t *cpm2_intctl;
55
56#define CPM_MAP_SIZE	(0x40000)	/* 256k - the PQ3 reserve this amount
57					   of space for CPM as it is larger
58					   than on PQ2 */
59
60void
61cpm2_reset(void)
62{
63	cpm2_immr = (cpm2_map_t *)ioremap(CPM_MAP_ADDR, CPM_MAP_SIZE);
64	cpm2_intctl = cpm2_map(im_intctl);
65
66	/* Reclaim the DP memory for our use.
67	 */
68	cpm2_dpinit();
69
70	/* Tell everyone where the comm processor resides.
71	 */
72	cpmp = &cpm2_immr->im_cpm;
73}
74
75/* Set a baud rate generator.  This needs lots of work.  There are
76 * eight BRGs, which can be connected to the CPM channels or output
77 * as clocks.  The BRGs are in two different block of internal
78 * memory mapped space.
79 * The baud rate clock is the system clock divided by something.
80 * It was set up long ago during the initial boot phase and is
81 * is given to us.
82 * Baud rate clocks are zero-based in the driver code (as that maps
83 * to port numbers).  Documentation uses 1-based numbering.
84 */
85#define BRG_INT_CLK	(get_brgfreq())
86#define BRG_UART_CLK	(BRG_INT_CLK/16)
87
88/* This function is used by UARTS, or anything else that uses a 16x
89 * oversampled clock.
90 */
91void
92cpm_setbrg(uint brg, uint rate)
93{
94	volatile uint	*bp;
95
96	/* This is good enough to get SMCs running.....
97	*/
98	if (brg < 4) {
99		bp = cpm2_map_size(im_brgc1, 16);
100	} else {
101		bp = cpm2_map_size(im_brgc5, 16);
102		brg -= 4;
103	}
104	bp += brg;
105	*bp = ((BRG_UART_CLK / rate) << 1) | CPM_BRG_EN;
106
107	cpm2_unmap(bp);
108}
109
110/* This function is used to set high speed synchronous baud rate
111 * clocks.
112 */
113void
114cpm2_fastbrg(uint brg, uint rate, int div16)
115{
116	volatile uint	*bp;
117
118	if (brg < 4) {
119		bp = cpm2_map_size(im_brgc1, 16);
120	}
121	else {
122		bp = cpm2_map_size(im_brgc5, 16);
123		brg -= 4;
124	}
125	bp += brg;
126	*bp = ((BRG_INT_CLK / rate) << 1) | CPM_BRG_EN;
127	if (div16)
128		*bp |= CPM_BRG_DIV16;
129
130	cpm2_unmap(bp);
131}
132
133int cpm2_clk_setup(enum cpm_clk_target target, int clock, int mode)
134{
135	int ret = 0;
136	int shift;
137	int i, bits = 0;
138	cpmux_t *im_cpmux;
139	u32 *reg;
140	u32 mask = 7;
141	u8 clk_map [24][3] = {
142		{CPM_CLK_FCC1, CPM_BRG5, 0},
143		{CPM_CLK_FCC1, CPM_BRG6, 1},
144		{CPM_CLK_FCC1, CPM_BRG7, 2},
145		{CPM_CLK_FCC1, CPM_BRG8, 3},
146		{CPM_CLK_FCC1, CPM_CLK9, 4},
147		{CPM_CLK_FCC1, CPM_CLK10, 5},
148		{CPM_CLK_FCC1, CPM_CLK11, 6},
149		{CPM_CLK_FCC1, CPM_CLK12, 7},
150		{CPM_CLK_FCC2, CPM_BRG5, 0},
151		{CPM_CLK_FCC2, CPM_BRG6, 1},
152		{CPM_CLK_FCC2, CPM_BRG7, 2},
153		{CPM_CLK_FCC2, CPM_BRG8, 3},
154		{CPM_CLK_FCC2, CPM_CLK13, 4},
155		{CPM_CLK_FCC2, CPM_CLK14, 5},
156		{CPM_CLK_FCC2, CPM_CLK15, 6},
157		{CPM_CLK_FCC2, CPM_CLK16, 7},
158		{CPM_CLK_FCC3, CPM_BRG5, 0},
159		{CPM_CLK_FCC3, CPM_BRG6, 1},
160		{CPM_CLK_FCC3, CPM_BRG7, 2},
161		{CPM_CLK_FCC3, CPM_BRG8, 3},
162		{CPM_CLK_FCC3, CPM_CLK13, 4},
163		{CPM_CLK_FCC3, CPM_CLK14, 5},
164		{CPM_CLK_FCC3, CPM_CLK15, 6},
165		{CPM_CLK_FCC3, CPM_CLK16, 7}
166		};
167
168	im_cpmux = cpm2_map(im_cpmux);
169
170	switch (target) {
171	case CPM_CLK_SCC1:
172		reg = &im_cpmux->cmx_scr;
173		shift = 24;
174	case CPM_CLK_SCC2:
175		reg = &im_cpmux->cmx_scr;
176		shift = 16;
177		break;
178	case CPM_CLK_SCC3:
179		reg = &im_cpmux->cmx_scr;
180		shift = 8;
181		break;
182	case CPM_CLK_SCC4:
183		reg = &im_cpmux->cmx_scr;
184		shift = 0;
185		break;
186	case CPM_CLK_FCC1:
187		reg = &im_cpmux->cmx_fcr;
188		shift = 24;
189		break;
190	case CPM_CLK_FCC2:
191		reg = &im_cpmux->cmx_fcr;
192		shift = 16;
193		break;
194	case CPM_CLK_FCC3:
195		reg = &im_cpmux->cmx_fcr;
196		shift = 8;
197		break;
198	default:
199		printk(KERN_ERR "cpm2_clock_setup: invalid clock target\n");
200		return -EINVAL;
201	}
202
203	if (mode == CPM_CLK_RX)
204		shift +=3;
205
206	for (i=0; i<24; i++) {
207		if (clk_map[i][0] == target && clk_map[i][1] == clock) {
208			bits = clk_map[i][2];
209			break;
210		}
211	}
212	if (i == sizeof(clk_map)/3)
213	    ret = -EINVAL;
214
215	bits <<= shift;
216	mask <<= shift;
217	out_be32(reg, (in_be32(reg) & ~mask) | bits);
218
219	cpm2_unmap(im_cpmux);
220	return ret;
221}
222
223/*
224 * dpalloc / dpfree bits.
225 */
226static spinlock_t cpm_dpmem_lock;
227/* 16 blocks should be enough to satisfy all requests
228 * until the memory subsystem goes up... */
229static rh_block_t cpm_boot_dpmem_rh_block[16];
230static rh_info_t cpm_dpmem_info;
231static u8* im_dprambase;
232
233static void cpm2_dpinit(void)
234{
235	spin_lock_init(&cpm_dpmem_lock);
236
237	im_dprambase = ioremap(CPM_MAP_ADDR, CPM_DATAONLY_BASE + CPM_DATAONLY_SIZE);
238
239	/* initialize the info header */
240	rh_init(&cpm_dpmem_info, 1,
241			sizeof(cpm_boot_dpmem_rh_block) /
242			sizeof(cpm_boot_dpmem_rh_block[0]),
243			cpm_boot_dpmem_rh_block);
244
245	/* Attach the usable dpmem area */
246	rh_attach_region(&cpm_dpmem_info, CPM_DATAONLY_BASE, CPM_DATAONLY_SIZE);
247}
248
249/* This function returns an index into the DPRAM area.
250 */
251unsigned long cpm_dpalloc(uint size, uint align)
252{
253	unsigned long start;
254	unsigned long flags;
255
256	spin_lock_irqsave(&cpm_dpmem_lock, flags);
257	cpm_dpmem_info.alignment = align;
258	start = rh_alloc(&cpm_dpmem_info, size, "commproc");
259	spin_unlock_irqrestore(&cpm_dpmem_lock, flags);
260
261	return (uint)start;
262}
263EXPORT_SYMBOL(cpm_dpalloc);
264
265int cpm_dpfree(unsigned long offset)
266{
267	int ret;
268	unsigned long flags;
269
270	spin_lock_irqsave(&cpm_dpmem_lock, flags);
271	ret = rh_free(&cpm_dpmem_info, offset);
272	spin_unlock_irqrestore(&cpm_dpmem_lock, flags);
273
274	return ret;
275}
276EXPORT_SYMBOL(cpm_dpfree);
277
278/* not sure if this is ever needed */
279unsigned long cpm_dpalloc_fixed(unsigned long offset, uint size, uint align)
280{
281	unsigned long start;
282	unsigned long flags;
283
284	spin_lock_irqsave(&cpm_dpmem_lock, flags);
285	cpm_dpmem_info.alignment = align;
286	start = rh_alloc_fixed(&cpm_dpmem_info, offset, size, "commproc");
287	spin_unlock_irqrestore(&cpm_dpmem_lock, flags);
288
289	return start;
290}
291EXPORT_SYMBOL(cpm_dpalloc_fixed);
292
293void cpm_dpdump(void)
294{
295	rh_dump(&cpm_dpmem_info);
296}
297EXPORT_SYMBOL(cpm_dpdump);
298
299void *cpm_dpram_addr(unsigned long offset)
300{
301	return (void *)(im_dprambase + offset);
302}
303EXPORT_SYMBOL(cpm_dpram_addr);
304