aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/sysdev/qe_lib/qe.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/powerpc/sysdev/qe_lib/qe.c')
-rw-r--r--arch/powerpc/sysdev/qe_lib/qe.c353
1 files changed, 353 insertions, 0 deletions
diff --git a/arch/powerpc/sysdev/qe_lib/qe.c b/arch/powerpc/sysdev/qe_lib/qe.c
new file mode 100644
index 000000000000..2bae632d3ad7
--- /dev/null
+++ b/arch/powerpc/sysdev/qe_lib/qe.c
@@ -0,0 +1,353 @@
1/*
2 * Copyright (C) 2006 Freescale Semicondutor, Inc. All rights reserved.
3 *
4 * Authors: Shlomi Gridish <gridish@freescale.com>
5 * Li Yang <leoli@freescale.com>
6 * Based on cpm2_common.c from Dan Malek (dmalek@jlc.net)
7 *
8 * Description:
9 * General Purpose functions for the global management of the
10 * QUICC Engine (QE).
11 *
12 * This program is free software; you can redistribute it and/or modify it
13 * under the terms of the GNU General Public License as published by the
14 * Free Software Foundation; either version 2 of the License, or (at your
15 * option) any later version.
16 */
17#include <linux/errno.h>
18#include <linux/sched.h>
19#include <linux/kernel.h>
20#include <linux/param.h>
21#include <linux/string.h>
22#include <linux/mm.h>
23#include <linux/interrupt.h>
24#include <linux/bootmem.h>
25#include <linux/module.h>
26#include <linux/delay.h>
27#include <linux/ioport.h>
28#include <asm/irq.h>
29#include <asm/page.h>
30#include <asm/pgtable.h>
31#include <asm/immap_qe.h>
32#include <asm/qe.h>
33#include <asm/prom.h>
34#include <asm/rheap.h>
35
36static void qe_snums_init(void);
37static void qe_muram_init(void);
38static int qe_sdma_init(void);
39
40static DEFINE_SPINLOCK(qe_lock);
41
42/* QE snum state */
43enum qe_snum_state {
44 QE_SNUM_STATE_USED,
45 QE_SNUM_STATE_FREE
46};
47
48/* QE snum */
49struct qe_snum {
50 u8 num;
51 enum qe_snum_state state;
52};
53
54/* We allocate this here because it is used almost exclusively for
55 * the communication processor devices.
56 */
57struct qe_immap *qe_immr = NULL;
58EXPORT_SYMBOL(qe_immr);
59
60static struct qe_snum snums[QE_NUM_OF_SNUM]; /* Dynamically allocated SNUMs */
61
62static phys_addr_t qebase = -1;
63
64phys_addr_t get_qe_base(void)
65{
66 struct device_node *qe;
67
68 if (qebase != -1)
69 return qebase;
70
71 qe = of_find_node_by_type(NULL, "qe");
72 if (qe) {
73 unsigned int size;
74 const void *prop = get_property(qe, "reg", &size);
75 qebase = of_translate_address(qe, prop);
76 of_node_put(qe);
77 };
78
79 return qebase;
80}
81
82EXPORT_SYMBOL(get_qe_base);
83
84void qe_reset(void)
85{
86 if (qe_immr == NULL)
87 qe_immr = ioremap(get_qe_base(), QE_IMMAP_SIZE);
88
89 qe_snums_init();
90
91 qe_issue_cmd(QE_RESET, QE_CR_SUBBLOCK_INVALID,
92 QE_CR_PROTOCOL_UNSPECIFIED, 0);
93
94 /* Reclaim the MURAM memory for our use. */
95 qe_muram_init();
96
97 if (qe_sdma_init())
98 panic("sdma init failed!");
99}
100
101int qe_issue_cmd(u32 cmd, u32 device, u8 mcn_protocol, u32 cmd_input)
102{
103 unsigned long flags;
104 u8 mcn_shift = 0, dev_shift = 0;
105
106 spin_lock_irqsave(&qe_lock, flags);
107 if (cmd == QE_RESET) {
108 out_be32(&qe_immr->cp.cecr, (u32) (cmd | QE_CR_FLG));
109 } else {
110 if (cmd == QE_ASSIGN_PAGE) {
111 /* Here device is the SNUM, not sub-block */
112 dev_shift = QE_CR_SNUM_SHIFT;
113 } else if (cmd == QE_ASSIGN_RISC) {
114 /* Here device is the SNUM, and mcnProtocol is
115 * e_QeCmdRiscAssignment value */
116 dev_shift = QE_CR_SNUM_SHIFT;
117 mcn_shift = QE_CR_MCN_RISC_ASSIGN_SHIFT;
118 } else {
119 if (device == QE_CR_SUBBLOCK_USB)
120 mcn_shift = QE_CR_MCN_USB_SHIFT;
121 else
122 mcn_shift = QE_CR_MCN_NORMAL_SHIFT;
123 }
124
125 out_be32(&qe_immr->cp.cecdr,
126 immrbar_virt_to_phys((void *)cmd_input));
127 out_be32(&qe_immr->cp.cecr,
128 (cmd | QE_CR_FLG | ((u32) device << dev_shift) | (u32)
129 mcn_protocol << mcn_shift));
130 }
131
132 /* wait for the QE_CR_FLG to clear */
133 while(in_be32(&qe_immr->cp.cecr) & QE_CR_FLG)
134 cpu_relax();
135 spin_unlock_irqrestore(&qe_lock, flags);
136
137 return 0;
138}
139EXPORT_SYMBOL(qe_issue_cmd);
140
141/* Set a baud rate generator. This needs lots of work. There are
142 * 16 BRGs, which can be connected to the QE channels or output
143 * as clocks. The BRGs are in two different block of internal
144 * memory mapped space.
145 * The baud rate clock is the system clock divided by something.
146 * It was set up long ago during the initial boot phase and is
147 * is given to us.
148 * Baud rate clocks are zero-based in the driver code (as that maps
149 * to port numbers). Documentation uses 1-based numbering.
150 */
151static unsigned int brg_clk = 0;
152
153unsigned int get_brg_clk(void)
154{
155 struct device_node *qe;
156 if (brg_clk)
157 return brg_clk;
158
159 qe = of_find_node_by_type(NULL, "qe");
160 if (qe) {
161 unsigned int size;
162 const u32 *prop = get_property(qe, "brg-frequency", &size);
163 brg_clk = *prop;
164 of_node_put(qe);
165 };
166 return brg_clk;
167}
168
169/* This function is used by UARTS, or anything else that uses a 16x
170 * oversampled clock.
171 */
172void qe_setbrg(u32 brg, u32 rate)
173{
174 volatile u32 *bp;
175 u32 divisor, tempval;
176 int div16 = 0;
177
178 bp = &qe_immr->brg.brgc1;
179 bp += brg;
180
181 divisor = (get_brg_clk() / rate);
182 if (divisor > QE_BRGC_DIVISOR_MAX + 1) {
183 div16 = 1;
184 divisor /= 16;
185 }
186
187 tempval = ((divisor - 1) << QE_BRGC_DIVISOR_SHIFT) | QE_BRGC_ENABLE;
188 if (div16)
189 tempval |= QE_BRGC_DIV16;
190
191 out_be32(bp, tempval);
192}
193
194/* Initialize SNUMs (thread serial numbers) according to
195 * QE Module Control chapter, SNUM table
196 */
197static void qe_snums_init(void)
198{
199 int i;
200 static const u8 snum_init[] = {
201 0x04, 0x05, 0x0C, 0x0D, 0x14, 0x15, 0x1C, 0x1D,
202 0x24, 0x25, 0x2C, 0x2D, 0x34, 0x35, 0x88, 0x89,
203 0x98, 0x99, 0xA8, 0xA9, 0xB8, 0xB9, 0xC8, 0xC9,
204 0xD8, 0xD9, 0xE8, 0xE9,
205 };
206
207 for (i = 0; i < QE_NUM_OF_SNUM; i++) {
208 snums[i].num = snum_init[i];
209 snums[i].state = QE_SNUM_STATE_FREE;
210 }
211}
212
213int qe_get_snum(void)
214{
215 unsigned long flags;
216 int snum = -EBUSY;
217 int i;
218
219 spin_lock_irqsave(&qe_lock, flags);
220 for (i = 0; i < QE_NUM_OF_SNUM; i++) {
221 if (snums[i].state == QE_SNUM_STATE_FREE) {
222 snums[i].state = QE_SNUM_STATE_USED;
223 snum = snums[i].num;
224 break;
225 }
226 }
227 spin_unlock_irqrestore(&qe_lock, flags);
228
229 return snum;
230}
231EXPORT_SYMBOL(qe_get_snum);
232
233void qe_put_snum(u8 snum)
234{
235 int i;
236
237 for (i = 0; i < QE_NUM_OF_SNUM; i++) {
238 if (snums[i].num == snum) {
239 snums[i].state = QE_SNUM_STATE_FREE;
240 break;
241 }
242 }
243}
244EXPORT_SYMBOL(qe_put_snum);
245
246static int qe_sdma_init(void)
247{
248 struct sdma *sdma = &qe_immr->sdma;
249 u32 sdma_buf_offset;
250
251 if (!sdma)
252 return -ENODEV;
253
254 /* allocate 2 internal temporary buffers (512 bytes size each) for
255 * the SDMA */
256 sdma_buf_offset = qe_muram_alloc(512 * 2, 64);
257 if (IS_MURAM_ERR(sdma_buf_offset))
258 return -ENOMEM;
259
260 out_be32(&sdma->sdebcr, sdma_buf_offset & QE_SDEBCR_BA_MASK);
261 out_be32(&sdma->sdmr, (QE_SDMR_GLB_1_MSK | (0x1 >>
262 QE_SDMR_CEN_SHIFT)));
263
264 return 0;
265}
266
267/*
268 * muram_alloc / muram_free bits.
269 */
270static DEFINE_SPINLOCK(qe_muram_lock);
271
272/* 16 blocks should be enough to satisfy all requests
273 * until the memory subsystem goes up... */
274static rh_block_t qe_boot_muram_rh_block[16];
275static rh_info_t qe_muram_info;
276
277static void qe_muram_init(void)
278{
279 struct device_node *np;
280 u32 address;
281 u64 size;
282 unsigned int flags;
283
284 /* initialize the info header */
285 rh_init(&qe_muram_info, 1,
286 sizeof(qe_boot_muram_rh_block) /
287 sizeof(qe_boot_muram_rh_block[0]), qe_boot_muram_rh_block);
288
289 /* Attach the usable muram area */
290 /* XXX: This is a subset of the available muram. It
291 * varies with the processor and the microcode patches activated.
292 */
293 if ((np = of_find_node_by_name(NULL, "data-only")) != NULL) {
294 address = *of_get_address(np, 0, &size, &flags);
295 of_node_put(np);
296 rh_attach_region(&qe_muram_info,
297 (void *)address, (int)size);
298 }
299}
300
301/* This function returns an index into the MURAM area.
302 */
303u32 qe_muram_alloc(u32 size, u32 align)
304{
305 void *start;
306 unsigned long flags;
307
308 spin_lock_irqsave(&qe_muram_lock, flags);
309 start = rh_alloc_align(&qe_muram_info, size, align, "QE");
310 spin_unlock_irqrestore(&qe_muram_lock, flags);
311
312 return (u32) start;
313}
314EXPORT_SYMBOL(qe_muram_alloc);
315
316int qe_muram_free(u32 offset)
317{
318 int ret;
319 unsigned long flags;
320
321 spin_lock_irqsave(&qe_muram_lock, flags);
322 ret = rh_free(&qe_muram_info, (void *)offset);
323 spin_unlock_irqrestore(&qe_muram_lock, flags);
324
325 return ret;
326}
327EXPORT_SYMBOL(qe_muram_free);
328
329/* not sure if this is ever needed */
330u32 qe_muram_alloc_fixed(u32 offset, u32 size)
331{
332 void *start;
333 unsigned long flags;
334
335 spin_lock_irqsave(&qe_muram_lock, flags);
336 start = rh_alloc_fixed(&qe_muram_info, (void *)offset, size, "commproc");
337 spin_unlock_irqrestore(&qe_muram_lock, flags);
338
339 return (u32) start;
340}
341EXPORT_SYMBOL(qe_muram_alloc_fixed);
342
343void qe_muram_dump(void)
344{
345 rh_dump(&qe_muram_info);
346}
347EXPORT_SYMBOL(qe_muram_dump);
348
349void *qe_muram_addr(u32 offset)
350{
351 return (void *)&qe_immr->muram[offset];
352}
353EXPORT_SYMBOL(qe_muram_addr);