blob: 21e01061aca92735f8dd276824cf6a146dded2cd [file] [log] [blame]
Li Yang98658532006-10-03 23:10:46 -05001/*
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;
Stephen Rothwelle2eb6392007-04-03 22:26:41 +100074 const void *prop = of_get_property(qe, "reg", &size);
Li Yang98658532006-10-03 23:10:46 -050075 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
Timur Tabi302439d2006-10-31 17:53:42 +0800125 out_be32(&qe_immr->cp.cecdr, cmd_input);
Li Yang98658532006-10-03 23:10:46 -0500126 out_be32(&qe_immr->cp.cecr,
127 (cmd | QE_CR_FLG | ((u32) device << dev_shift) | (u32)
128 mcn_protocol << mcn_shift));
129 }
130
131 /* wait for the QE_CR_FLG to clear */
132 while(in_be32(&qe_immr->cp.cecr) & QE_CR_FLG)
133 cpu_relax();
134 spin_unlock_irqrestore(&qe_lock, flags);
135
136 return 0;
137}
138EXPORT_SYMBOL(qe_issue_cmd);
139
140/* Set a baud rate generator. This needs lots of work. There are
141 * 16 BRGs, which can be connected to the QE channels or output
142 * as clocks. The BRGs are in two different block of internal
143 * memory mapped space.
Timur Tabi6b0b5942007-10-03 11:34:59 -0500144 * The BRG clock is the QE clock divided by 2.
Li Yang98658532006-10-03 23:10:46 -0500145 * It was set up long ago during the initial boot phase and is
146 * is given to us.
147 * Baud rate clocks are zero-based in the driver code (as that maps
148 * to port numbers). Documentation uses 1-based numbering.
149 */
150static unsigned int brg_clk = 0;
151
152unsigned int get_brg_clk(void)
153{
154 struct device_node *qe;
155 if (brg_clk)
156 return brg_clk;
157
158 qe = of_find_node_by_type(NULL, "qe");
159 if (qe) {
160 unsigned int size;
Stephen Rothwelle2eb6392007-04-03 22:26:41 +1000161 const u32 *prop = of_get_property(qe, "brg-frequency", &size);
Li Yang98658532006-10-03 23:10:46 -0500162 brg_clk = *prop;
163 of_node_put(qe);
164 };
165 return brg_clk;
166}
167
Timur Tabi6b0b5942007-10-03 11:34:59 -0500168/* Program the BRG to the given sampling rate and multiplier
169 *
Timur Tabi7264ec42007-11-29 17:26:30 -0600170 * @brg: the BRG, QE_BRG1 - QE_BRG16
Timur Tabi6b0b5942007-10-03 11:34:59 -0500171 * @rate: the desired sampling rate
172 * @multiplier: corresponds to the value programmed in GUMR_L[RDCR] or
173 * GUMR_L[TDCR]. E.g., if this BRG is the RX clock, and GUMR_L[RDCR]=01,
174 * then 'multiplier' should be 8.
Li Yang98658532006-10-03 23:10:46 -0500175 */
Timur Tabi7264ec42007-11-29 17:26:30 -0600176int qe_setbrg(enum qe_clock brg, unsigned int rate, unsigned int multiplier)
Li Yang98658532006-10-03 23:10:46 -0500177{
Li Yang98658532006-10-03 23:10:46 -0500178 u32 divisor, tempval;
Timur Tabi6b0b5942007-10-03 11:34:59 -0500179 u32 div16 = 0;
Li Yang98658532006-10-03 23:10:46 -0500180
Timur Tabi7264ec42007-11-29 17:26:30 -0600181 if ((brg < QE_BRG1) || (brg > QE_BRG16))
182 return -EINVAL;
183
Timur Tabi6b0b5942007-10-03 11:34:59 -0500184 divisor = get_brg_clk() / (rate * multiplier);
Li Yang98658532006-10-03 23:10:46 -0500185
Li Yang98658532006-10-03 23:10:46 -0500186 if (divisor > QE_BRGC_DIVISOR_MAX + 1) {
Timur Tabi6b0b5942007-10-03 11:34:59 -0500187 div16 = QE_BRGC_DIV16;
Li Yang98658532006-10-03 23:10:46 -0500188 divisor /= 16;
189 }
190
Timur Tabi6b0b5942007-10-03 11:34:59 -0500191 /* Errata QE_General4, which affects some MPC832x and MPC836x SOCs, says
192 that the BRG divisor must be even if you're not using divide-by-16
193 mode. */
194 if (!div16 && (divisor & 1))
195 divisor++;
Li Yang98658532006-10-03 23:10:46 -0500196
Timur Tabi6b0b5942007-10-03 11:34:59 -0500197 tempval = ((divisor - 1) << QE_BRGC_DIVISOR_SHIFT) |
198 QE_BRGC_ENABLE | div16;
199
Timur Tabi7264ec42007-11-29 17:26:30 -0600200 out_be32(&qe_immr->brg.brgc[brg - QE_BRG1], tempval);
201
202 return 0;
Li Yang98658532006-10-03 23:10:46 -0500203}
Timur Tabi7264ec42007-11-29 17:26:30 -0600204EXPORT_SYMBOL(qe_setbrg);
Li Yang98658532006-10-03 23:10:46 -0500205
Timur Tabi174b0da2007-12-03 15:17:58 -0600206/* Convert a string to a QE clock source enum
207 *
208 * This function takes a string, typically from a property in the device
209 * tree, and returns the corresponding "enum qe_clock" value.
210*/
211enum qe_clock qe_clock_source(const char *source)
212{
213 unsigned int i;
214
215 if (strcasecmp(source, "none") == 0)
216 return QE_CLK_NONE;
217
218 if (strncasecmp(source, "brg", 3) == 0) {
219 i = simple_strtoul(source + 3, NULL, 10);
220 if ((i >= 1) && (i <= 16))
221 return (QE_BRG1 - 1) + i;
222 else
223 return QE_CLK_DUMMY;
224 }
225
226 if (strncasecmp(source, "clk", 3) == 0) {
227 i = simple_strtoul(source + 3, NULL, 10);
228 if ((i >= 1) && (i <= 24))
229 return (QE_CLK1 - 1) + i;
230 else
231 return QE_CLK_DUMMY;
232 }
233
234 return QE_CLK_DUMMY;
235}
236EXPORT_SYMBOL(qe_clock_source);
237
Li Yang98658532006-10-03 23:10:46 -0500238/* Initialize SNUMs (thread serial numbers) according to
239 * QE Module Control chapter, SNUM table
240 */
241static void qe_snums_init(void)
242{
243 int i;
244 static const u8 snum_init[] = {
245 0x04, 0x05, 0x0C, 0x0D, 0x14, 0x15, 0x1C, 0x1D,
246 0x24, 0x25, 0x2C, 0x2D, 0x34, 0x35, 0x88, 0x89,
247 0x98, 0x99, 0xA8, 0xA9, 0xB8, 0xB9, 0xC8, 0xC9,
248 0xD8, 0xD9, 0xE8, 0xE9,
249 };
250
251 for (i = 0; i < QE_NUM_OF_SNUM; i++) {
252 snums[i].num = snum_init[i];
253 snums[i].state = QE_SNUM_STATE_FREE;
254 }
255}
256
257int qe_get_snum(void)
258{
259 unsigned long flags;
260 int snum = -EBUSY;
261 int i;
262
263 spin_lock_irqsave(&qe_lock, flags);
264 for (i = 0; i < QE_NUM_OF_SNUM; i++) {
265 if (snums[i].state == QE_SNUM_STATE_FREE) {
266 snums[i].state = QE_SNUM_STATE_USED;
267 snum = snums[i].num;
268 break;
269 }
270 }
271 spin_unlock_irqrestore(&qe_lock, flags);
272
273 return snum;
274}
275EXPORT_SYMBOL(qe_get_snum);
276
277void qe_put_snum(u8 snum)
278{
279 int i;
280
281 for (i = 0; i < QE_NUM_OF_SNUM; i++) {
282 if (snums[i].num == snum) {
283 snums[i].state = QE_SNUM_STATE_FREE;
284 break;
285 }
286 }
287}
288EXPORT_SYMBOL(qe_put_snum);
289
290static int qe_sdma_init(void)
291{
292 struct sdma *sdma = &qe_immr->sdma;
Timur Tabi4c356302007-05-08 14:46:36 -0500293 unsigned long sdma_buf_offset;
Li Yang98658532006-10-03 23:10:46 -0500294
295 if (!sdma)
296 return -ENODEV;
297
298 /* allocate 2 internal temporary buffers (512 bytes size each) for
299 * the SDMA */
Chuck Meade7f013bc2007-03-27 10:46:10 -0400300 sdma_buf_offset = qe_muram_alloc(512 * 2, 4096);
Timur Tabi4c356302007-05-08 14:46:36 -0500301 if (IS_ERR_VALUE(sdma_buf_offset))
Li Yang98658532006-10-03 23:10:46 -0500302 return -ENOMEM;
303
Timur Tabi4c356302007-05-08 14:46:36 -0500304 out_be32(&sdma->sdebcr, (u32) sdma_buf_offset & QE_SDEBCR_BA_MASK);
Chuck Meade7f013bc2007-03-27 10:46:10 -0400305 out_be32(&sdma->sdmr, (QE_SDMR_GLB_1_MSK |
306 (0x1 << QE_SDMR_CEN_SHIFT)));
Li Yang98658532006-10-03 23:10:46 -0500307
308 return 0;
309}
310
311/*
312 * muram_alloc / muram_free bits.
313 */
314static DEFINE_SPINLOCK(qe_muram_lock);
315
316/* 16 blocks should be enough to satisfy all requests
317 * until the memory subsystem goes up... */
318static rh_block_t qe_boot_muram_rh_block[16];
319static rh_info_t qe_muram_info;
320
321static void qe_muram_init(void)
322{
323 struct device_node *np;
324 u32 address;
325 u64 size;
326 unsigned int flags;
327
328 /* initialize the info header */
329 rh_init(&qe_muram_info, 1,
330 sizeof(qe_boot_muram_rh_block) /
331 sizeof(qe_boot_muram_rh_block[0]), qe_boot_muram_rh_block);
332
333 /* Attach the usable muram area */
334 /* XXX: This is a subset of the available muram. It
335 * varies with the processor and the microcode patches activated.
336 */
337 if ((np = of_find_node_by_name(NULL, "data-only")) != NULL) {
338 address = *of_get_address(np, 0, &size, &flags);
339 of_node_put(np);
Timur Tabi4c356302007-05-08 14:46:36 -0500340 rh_attach_region(&qe_muram_info, address, (int) size);
Li Yang98658532006-10-03 23:10:46 -0500341 }
342}
343
344/* This function returns an index into the MURAM area.
345 */
Timur Tabi4c356302007-05-08 14:46:36 -0500346unsigned long qe_muram_alloc(int size, int align)
Li Yang98658532006-10-03 23:10:46 -0500347{
Timur Tabi4c356302007-05-08 14:46:36 -0500348 unsigned long start;
Li Yang98658532006-10-03 23:10:46 -0500349 unsigned long flags;
350
351 spin_lock_irqsave(&qe_muram_lock, flags);
352 start = rh_alloc_align(&qe_muram_info, size, align, "QE");
353 spin_unlock_irqrestore(&qe_muram_lock, flags);
354
Timur Tabi4c356302007-05-08 14:46:36 -0500355 return start;
Li Yang98658532006-10-03 23:10:46 -0500356}
357EXPORT_SYMBOL(qe_muram_alloc);
358
Timur Tabi4c356302007-05-08 14:46:36 -0500359int qe_muram_free(unsigned long offset)
Li Yang98658532006-10-03 23:10:46 -0500360{
361 int ret;
362 unsigned long flags;
363
364 spin_lock_irqsave(&qe_muram_lock, flags);
Timur Tabi4c356302007-05-08 14:46:36 -0500365 ret = rh_free(&qe_muram_info, offset);
Li Yang98658532006-10-03 23:10:46 -0500366 spin_unlock_irqrestore(&qe_muram_lock, flags);
367
368 return ret;
369}
370EXPORT_SYMBOL(qe_muram_free);
371
372/* not sure if this is ever needed */
Timur Tabi4c356302007-05-08 14:46:36 -0500373unsigned long qe_muram_alloc_fixed(unsigned long offset, int size)
Li Yang98658532006-10-03 23:10:46 -0500374{
Timur Tabi4c356302007-05-08 14:46:36 -0500375 unsigned long start;
Li Yang98658532006-10-03 23:10:46 -0500376 unsigned long flags;
377
378 spin_lock_irqsave(&qe_muram_lock, flags);
Timur Tabi4c356302007-05-08 14:46:36 -0500379 start = rh_alloc_fixed(&qe_muram_info, offset, size, "commproc");
Li Yang98658532006-10-03 23:10:46 -0500380 spin_unlock_irqrestore(&qe_muram_lock, flags);
381
Timur Tabi4c356302007-05-08 14:46:36 -0500382 return start;
Li Yang98658532006-10-03 23:10:46 -0500383}
384EXPORT_SYMBOL(qe_muram_alloc_fixed);
385
386void qe_muram_dump(void)
387{
388 rh_dump(&qe_muram_info);
389}
390EXPORT_SYMBOL(qe_muram_dump);
391
Timur Tabi4c356302007-05-08 14:46:36 -0500392void *qe_muram_addr(unsigned long offset)
Li Yang98658532006-10-03 23:10:46 -0500393{
394 return (void *)&qe_immr->muram[offset];
395}
396EXPORT_SYMBOL(qe_muram_addr);