blob: 1df3b4a6832f7ef5d2dd0fff50ee5739824ff8b2 [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
206/* Initialize SNUMs (thread serial numbers) according to
207 * QE Module Control chapter, SNUM table
208 */
209static void qe_snums_init(void)
210{
211 int i;
212 static const u8 snum_init[] = {
213 0x04, 0x05, 0x0C, 0x0D, 0x14, 0x15, 0x1C, 0x1D,
214 0x24, 0x25, 0x2C, 0x2D, 0x34, 0x35, 0x88, 0x89,
215 0x98, 0x99, 0xA8, 0xA9, 0xB8, 0xB9, 0xC8, 0xC9,
216 0xD8, 0xD9, 0xE8, 0xE9,
217 };
218
219 for (i = 0; i < QE_NUM_OF_SNUM; i++) {
220 snums[i].num = snum_init[i];
221 snums[i].state = QE_SNUM_STATE_FREE;
222 }
223}
224
225int qe_get_snum(void)
226{
227 unsigned long flags;
228 int snum = -EBUSY;
229 int i;
230
231 spin_lock_irqsave(&qe_lock, flags);
232 for (i = 0; i < QE_NUM_OF_SNUM; i++) {
233 if (snums[i].state == QE_SNUM_STATE_FREE) {
234 snums[i].state = QE_SNUM_STATE_USED;
235 snum = snums[i].num;
236 break;
237 }
238 }
239 spin_unlock_irqrestore(&qe_lock, flags);
240
241 return snum;
242}
243EXPORT_SYMBOL(qe_get_snum);
244
245void qe_put_snum(u8 snum)
246{
247 int i;
248
249 for (i = 0; i < QE_NUM_OF_SNUM; i++) {
250 if (snums[i].num == snum) {
251 snums[i].state = QE_SNUM_STATE_FREE;
252 break;
253 }
254 }
255}
256EXPORT_SYMBOL(qe_put_snum);
257
258static int qe_sdma_init(void)
259{
260 struct sdma *sdma = &qe_immr->sdma;
Timur Tabi4c356302007-05-08 14:46:36 -0500261 unsigned long sdma_buf_offset;
Li Yang98658532006-10-03 23:10:46 -0500262
263 if (!sdma)
264 return -ENODEV;
265
266 /* allocate 2 internal temporary buffers (512 bytes size each) for
267 * the SDMA */
Chuck Meade7f013bc2007-03-27 10:46:10 -0400268 sdma_buf_offset = qe_muram_alloc(512 * 2, 4096);
Timur Tabi4c356302007-05-08 14:46:36 -0500269 if (IS_ERR_VALUE(sdma_buf_offset))
Li Yang98658532006-10-03 23:10:46 -0500270 return -ENOMEM;
271
Timur Tabi4c356302007-05-08 14:46:36 -0500272 out_be32(&sdma->sdebcr, (u32) sdma_buf_offset & QE_SDEBCR_BA_MASK);
Chuck Meade7f013bc2007-03-27 10:46:10 -0400273 out_be32(&sdma->sdmr, (QE_SDMR_GLB_1_MSK |
274 (0x1 << QE_SDMR_CEN_SHIFT)));
Li Yang98658532006-10-03 23:10:46 -0500275
276 return 0;
277}
278
279/*
280 * muram_alloc / muram_free bits.
281 */
282static DEFINE_SPINLOCK(qe_muram_lock);
283
284/* 16 blocks should be enough to satisfy all requests
285 * until the memory subsystem goes up... */
286static rh_block_t qe_boot_muram_rh_block[16];
287static rh_info_t qe_muram_info;
288
289static void qe_muram_init(void)
290{
291 struct device_node *np;
292 u32 address;
293 u64 size;
294 unsigned int flags;
295
296 /* initialize the info header */
297 rh_init(&qe_muram_info, 1,
298 sizeof(qe_boot_muram_rh_block) /
299 sizeof(qe_boot_muram_rh_block[0]), qe_boot_muram_rh_block);
300
301 /* Attach the usable muram area */
302 /* XXX: This is a subset of the available muram. It
303 * varies with the processor and the microcode patches activated.
304 */
305 if ((np = of_find_node_by_name(NULL, "data-only")) != NULL) {
306 address = *of_get_address(np, 0, &size, &flags);
307 of_node_put(np);
Timur Tabi4c356302007-05-08 14:46:36 -0500308 rh_attach_region(&qe_muram_info, address, (int) size);
Li Yang98658532006-10-03 23:10:46 -0500309 }
310}
311
312/* This function returns an index into the MURAM area.
313 */
Timur Tabi4c356302007-05-08 14:46:36 -0500314unsigned long qe_muram_alloc(int size, int align)
Li Yang98658532006-10-03 23:10:46 -0500315{
Timur Tabi4c356302007-05-08 14:46:36 -0500316 unsigned long start;
Li Yang98658532006-10-03 23:10:46 -0500317 unsigned long flags;
318
319 spin_lock_irqsave(&qe_muram_lock, flags);
320 start = rh_alloc_align(&qe_muram_info, size, align, "QE");
321 spin_unlock_irqrestore(&qe_muram_lock, flags);
322
Timur Tabi4c356302007-05-08 14:46:36 -0500323 return start;
Li Yang98658532006-10-03 23:10:46 -0500324}
325EXPORT_SYMBOL(qe_muram_alloc);
326
Timur Tabi4c356302007-05-08 14:46:36 -0500327int qe_muram_free(unsigned long offset)
Li Yang98658532006-10-03 23:10:46 -0500328{
329 int ret;
330 unsigned long flags;
331
332 spin_lock_irqsave(&qe_muram_lock, flags);
Timur Tabi4c356302007-05-08 14:46:36 -0500333 ret = rh_free(&qe_muram_info, offset);
Li Yang98658532006-10-03 23:10:46 -0500334 spin_unlock_irqrestore(&qe_muram_lock, flags);
335
336 return ret;
337}
338EXPORT_SYMBOL(qe_muram_free);
339
340/* not sure if this is ever needed */
Timur Tabi4c356302007-05-08 14:46:36 -0500341unsigned long qe_muram_alloc_fixed(unsigned long offset, int size)
Li Yang98658532006-10-03 23:10:46 -0500342{
Timur Tabi4c356302007-05-08 14:46:36 -0500343 unsigned long start;
Li Yang98658532006-10-03 23:10:46 -0500344 unsigned long flags;
345
346 spin_lock_irqsave(&qe_muram_lock, flags);
Timur Tabi4c356302007-05-08 14:46:36 -0500347 start = rh_alloc_fixed(&qe_muram_info, offset, size, "commproc");
Li Yang98658532006-10-03 23:10:46 -0500348 spin_unlock_irqrestore(&qe_muram_lock, flags);
349
Timur Tabi4c356302007-05-08 14:46:36 -0500350 return start;
Li Yang98658532006-10-03 23:10:46 -0500351}
352EXPORT_SYMBOL(qe_muram_alloc_fixed);
353
354void qe_muram_dump(void)
355{
356 rh_dump(&qe_muram_info);
357}
358EXPORT_SYMBOL(qe_muram_dump);
359
Timur Tabi4c356302007-05-08 14:46:36 -0500360void *qe_muram_addr(unsigned long offset)
Li Yang98658532006-10-03 23:10:46 -0500361{
362 return (void *)&qe_immr->muram[offset];
363}
364EXPORT_SYMBOL(qe_muram_addr);