OpenCores
URL https://opencores.org/ocsvn/or1k_soc_on_altera_embedded_dev_kit/or1k_soc_on_altera_embedded_dev_kit/trunk

Subversion Repositories or1k_soc_on_altera_embedded_dev_kit

[/] [or1k_soc_on_altera_embedded_dev_kit/] [trunk/] [linux-2.6/] [linux-2.6.24/] [arch/] [powerpc/] [sysdev/] [qe_lib/] [qe.c] - Blame information for rev 3

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 3 xianfeng
/*
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
 
36
static void qe_snums_init(void);
37
static void qe_muram_init(void);
38
static int qe_sdma_init(void);
39
 
40
static DEFINE_SPINLOCK(qe_lock);
41
 
42
/* QE snum state */
43
enum qe_snum_state {
44
        QE_SNUM_STATE_USED,
45
        QE_SNUM_STATE_FREE
46
};
47
 
48
/* QE snum */
49
struct 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
 */
57
struct qe_immap *qe_immr = NULL;
58
EXPORT_SYMBOL(qe_immr);
59
 
60
static struct qe_snum snums[QE_NUM_OF_SNUM];    /* Dynamically allocated SNUMs */
61
 
62
static phys_addr_t qebase = -1;
63
 
64
phys_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 = of_get_property(qe, "reg", &size);
75
                qebase = of_translate_address(qe, prop);
76
                of_node_put(qe);
77
        };
78
 
79
        return qebase;
80
}
81
 
82
EXPORT_SYMBOL(get_qe_base);
83
 
84
void 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
 
101
int 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, cmd_input);
126
                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
}
138
EXPORT_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.
144
 * The BRG clock is the QE clock divided by 2.
145
 * 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
 */
150
static unsigned int brg_clk = 0;
151
 
152
unsigned 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;
161
                const u32 *prop = of_get_property(qe, "brg-frequency", &size);
162
                brg_clk = *prop;
163
                of_node_put(qe);
164
        };
165
        return brg_clk;
166
}
167
 
168
/* Program the BRG to the given sampling rate and multiplier
169
 *
170
 * @brg: the BRG, 1-16
171
 * @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.
175
 *
176
 * Also note that the value programmed into the BRGC register must be even.
177
 */
178
void qe_setbrg(unsigned int brg, unsigned int rate, unsigned int multiplier)
179
{
180
        u32 divisor, tempval;
181
        u32 div16 = 0;
182
 
183
        divisor = get_brg_clk() / (rate * multiplier);
184
 
185
        if (divisor > QE_BRGC_DIVISOR_MAX + 1) {
186
                div16 = QE_BRGC_DIV16;
187
                divisor /= 16;
188
        }
189
 
190
        /* Errata QE_General4, which affects some MPC832x and MPC836x SOCs, says
191
           that the BRG divisor must be even if you're not using divide-by-16
192
           mode. */
193
        if (!div16 && (divisor & 1))
194
                divisor++;
195
 
196
        tempval = ((divisor - 1) << QE_BRGC_DIVISOR_SHIFT) |
197
                QE_BRGC_ENABLE | div16;
198
 
199
        out_be32(&qe_immr->brg.brgc[brg - 1], tempval);
200
}
201
 
202
/* Initialize SNUMs (thread serial numbers) according to
203
 * QE Module Control chapter, SNUM table
204
 */
205
static void qe_snums_init(void)
206
{
207
        int i;
208
        static const u8 snum_init[] = {
209
                0x04, 0x05, 0x0C, 0x0D, 0x14, 0x15, 0x1C, 0x1D,
210
                0x24, 0x25, 0x2C, 0x2D, 0x34, 0x35, 0x88, 0x89,
211
                0x98, 0x99, 0xA8, 0xA9, 0xB8, 0xB9, 0xC8, 0xC9,
212
                0xD8, 0xD9, 0xE8, 0xE9,
213
        };
214
 
215
        for (i = 0; i < QE_NUM_OF_SNUM; i++) {
216
                snums[i].num = snum_init[i];
217
                snums[i].state = QE_SNUM_STATE_FREE;
218
        }
219
}
220
 
221
int qe_get_snum(void)
222
{
223
        unsigned long flags;
224
        int snum = -EBUSY;
225
        int i;
226
 
227
        spin_lock_irqsave(&qe_lock, flags);
228
        for (i = 0; i < QE_NUM_OF_SNUM; i++) {
229
                if (snums[i].state == QE_SNUM_STATE_FREE) {
230
                        snums[i].state = QE_SNUM_STATE_USED;
231
                        snum = snums[i].num;
232
                        break;
233
                }
234
        }
235
        spin_unlock_irqrestore(&qe_lock, flags);
236
 
237
        return snum;
238
}
239
EXPORT_SYMBOL(qe_get_snum);
240
 
241
void qe_put_snum(u8 snum)
242
{
243
        int i;
244
 
245
        for (i = 0; i < QE_NUM_OF_SNUM; i++) {
246
                if (snums[i].num == snum) {
247
                        snums[i].state = QE_SNUM_STATE_FREE;
248
                        break;
249
                }
250
        }
251
}
252
EXPORT_SYMBOL(qe_put_snum);
253
 
254
static int qe_sdma_init(void)
255
{
256
        struct sdma *sdma = &qe_immr->sdma;
257
        unsigned long sdma_buf_offset;
258
 
259
        if (!sdma)
260
                return -ENODEV;
261
 
262
        /* allocate 2 internal temporary buffers (512 bytes size each) for
263
         * the SDMA */
264
        sdma_buf_offset = qe_muram_alloc(512 * 2, 4096);
265
        if (IS_ERR_VALUE(sdma_buf_offset))
266
                return -ENOMEM;
267
 
268
        out_be32(&sdma->sdebcr, (u32) sdma_buf_offset & QE_SDEBCR_BA_MASK);
269
        out_be32(&sdma->sdmr, (QE_SDMR_GLB_1_MSK |
270
                                        (0x1 << QE_SDMR_CEN_SHIFT)));
271
 
272
        return 0;
273
}
274
 
275
/*
276
 * muram_alloc / muram_free bits.
277
 */
278
static DEFINE_SPINLOCK(qe_muram_lock);
279
 
280
/* 16 blocks should be enough to satisfy all requests
281
 * until the memory subsystem goes up... */
282
static rh_block_t qe_boot_muram_rh_block[16];
283
static rh_info_t qe_muram_info;
284
 
285
static void qe_muram_init(void)
286
{
287
        struct device_node *np;
288
        u32 address;
289
        u64 size;
290
        unsigned int flags;
291
 
292
        /* initialize the info header */
293
        rh_init(&qe_muram_info, 1,
294
                sizeof(qe_boot_muram_rh_block) /
295
                sizeof(qe_boot_muram_rh_block[0]), qe_boot_muram_rh_block);
296
 
297
        /* Attach the usable muram area */
298
        /* XXX: This is a subset of the available muram. It
299
         * varies with the processor and the microcode patches activated.
300
         */
301
        if ((np = of_find_node_by_name(NULL, "data-only")) != NULL) {
302
                address = *of_get_address(np, 0, &size, &flags);
303
                of_node_put(np);
304
                rh_attach_region(&qe_muram_info, address, (int) size);
305
        }
306
}
307
 
308
/* This function returns an index into the MURAM area.
309
 */
310
unsigned long qe_muram_alloc(int size, int align)
311
{
312
        unsigned long start;
313
        unsigned long flags;
314
 
315
        spin_lock_irqsave(&qe_muram_lock, flags);
316
        start = rh_alloc_align(&qe_muram_info, size, align, "QE");
317
        spin_unlock_irqrestore(&qe_muram_lock, flags);
318
 
319
        return start;
320
}
321
EXPORT_SYMBOL(qe_muram_alloc);
322
 
323
int qe_muram_free(unsigned long offset)
324
{
325
        int ret;
326
        unsigned long flags;
327
 
328
        spin_lock_irqsave(&qe_muram_lock, flags);
329
        ret = rh_free(&qe_muram_info, offset);
330
        spin_unlock_irqrestore(&qe_muram_lock, flags);
331
 
332
        return ret;
333
}
334
EXPORT_SYMBOL(qe_muram_free);
335
 
336
/* not sure if this is ever needed */
337
unsigned long qe_muram_alloc_fixed(unsigned long offset, int size)
338
{
339
        unsigned long start;
340
        unsigned long flags;
341
 
342
        spin_lock_irqsave(&qe_muram_lock, flags);
343
        start = rh_alloc_fixed(&qe_muram_info, offset, size, "commproc");
344
        spin_unlock_irqrestore(&qe_muram_lock, flags);
345
 
346
        return start;
347
}
348
EXPORT_SYMBOL(qe_muram_alloc_fixed);
349
 
350
void qe_muram_dump(void)
351
{
352
        rh_dump(&qe_muram_info);
353
}
354
EXPORT_SYMBOL(qe_muram_dump);
355
 
356
void *qe_muram_addr(unsigned long offset)
357
{
358
        return (void *)&qe_immr->muram[offset];
359
}
360
EXPORT_SYMBOL(qe_muram_addr);

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.