Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/arch/powerpc/sysdev/cpm2.c
26485 views
1
/*
2
* General Purpose functions for the global management of the
3
* 8260 Communication Processor Module.
4
* Copyright (c) 1999-2001 Dan Malek <[email protected]>
5
* Copyright (c) 2000 MontaVista Software, Inc ([email protected])
6
* 2.3.99 Updates
7
*
8
* 2006 (c) MontaVista Software, Inc.
9
* Vitaly Bordug <[email protected]>
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 <linux/of.h>
37
38
#include <asm/io.h>
39
#include <asm/irq.h>
40
#include <asm/page.h>
41
#include <asm/cpm2.h>
42
#include <asm/rheap.h>
43
44
#include <sysdev/fsl_soc.h>
45
46
cpm_cpm2_t __iomem *cpmp; /* Pointer to comm processor space */
47
48
/* We allocate this here because it is used almost exclusively for
49
* the communication processor devices.
50
*/
51
cpm2_map_t __iomem *cpm2_immr;
52
EXPORT_SYMBOL(cpm2_immr);
53
54
#define CPM_MAP_SIZE (0x40000) /* 256k - the PQ3 reserve this amount
55
of space for CPM as it is larger
56
than on PQ2 */
57
58
void __init cpm2_reset(void)
59
{
60
#ifdef CONFIG_PPC_85xx
61
cpm2_immr = ioremap(get_immrbase() + 0x80000, CPM_MAP_SIZE);
62
#else
63
cpm2_immr = ioremap(get_immrbase(), CPM_MAP_SIZE);
64
#endif
65
66
/* Tell everyone where the comm processor resides.
67
*/
68
cpmp = &cpm2_immr->im_cpm;
69
70
#ifndef CONFIG_PPC_EARLY_DEBUG_CPM
71
/* Reset the CPM.
72
*/
73
cpm_command(CPM_CR_RST, 0);
74
#endif
75
}
76
77
static DEFINE_SPINLOCK(cmd_lock);
78
79
#define MAX_CR_CMD_LOOPS 10000
80
81
int cpm_command(u32 command, u8 opcode)
82
{
83
int i, ret;
84
unsigned long flags;
85
86
spin_lock_irqsave(&cmd_lock, flags);
87
88
ret = 0;
89
out_be32(&cpmp->cp_cpcr, command | opcode | CPM_CR_FLG);
90
for (i = 0; i < MAX_CR_CMD_LOOPS; i++)
91
if ((in_be32(&cpmp->cp_cpcr) & CPM_CR_FLG) == 0)
92
goto out;
93
94
printk(KERN_ERR "%s(): Not able to issue CPM command\n", __func__);
95
ret = -EIO;
96
out:
97
spin_unlock_irqrestore(&cmd_lock, flags);
98
return ret;
99
}
100
EXPORT_SYMBOL(cpm_command);
101
102
/* Set a baud rate generator. This needs lots of work. There are
103
* eight BRGs, which can be connected to the CPM channels or output
104
* as clocks. The BRGs are in two different block of internal
105
* memory mapped space.
106
* The baud rate clock is the system clock divided by something.
107
* It was set up long ago during the initial boot phase and is
108
* given to us.
109
* Baud rate clocks are zero-based in the driver code (as that maps
110
* to port numbers). Documentation uses 1-based numbering.
111
*/
112
void __cpm2_setbrg(uint brg, uint rate, uint clk, int div16, int src)
113
{
114
u32 __iomem *bp;
115
u32 val;
116
117
/* This is good enough to get SMCs running.....
118
*/
119
if (brg < 4) {
120
bp = &cpm2_immr->im_brgc1;
121
} else {
122
bp = &cpm2_immr->im_brgc5;
123
brg -= 4;
124
}
125
bp += brg;
126
/* Round the clock divider to the nearest integer. */
127
val = (((clk * 2 / rate) - 1) & ~1) | CPM_BRG_EN | src;
128
if (div16)
129
val |= CPM_BRG_DIV16;
130
131
out_be32(bp, val);
132
}
133
EXPORT_SYMBOL(__cpm2_setbrg);
134
135
int __init cpm2_clk_setup(enum cpm_clk_target target, int clock, int mode)
136
{
137
int ret = 0;
138
int shift;
139
int i, bits = 0;
140
u32 __iomem *reg;
141
u32 mask = 7;
142
143
u8 clk_map[][3] = {
144
{CPM_CLK_FCC1, CPM_BRG5, 0},
145
{CPM_CLK_FCC1, CPM_BRG6, 1},
146
{CPM_CLK_FCC1, CPM_BRG7, 2},
147
{CPM_CLK_FCC1, CPM_BRG8, 3},
148
{CPM_CLK_FCC1, CPM_CLK9, 4},
149
{CPM_CLK_FCC1, CPM_CLK10, 5},
150
{CPM_CLK_FCC1, CPM_CLK11, 6},
151
{CPM_CLK_FCC1, CPM_CLK12, 7},
152
{CPM_CLK_FCC2, CPM_BRG5, 0},
153
{CPM_CLK_FCC2, CPM_BRG6, 1},
154
{CPM_CLK_FCC2, CPM_BRG7, 2},
155
{CPM_CLK_FCC2, CPM_BRG8, 3},
156
{CPM_CLK_FCC2, CPM_CLK13, 4},
157
{CPM_CLK_FCC2, CPM_CLK14, 5},
158
{CPM_CLK_FCC2, CPM_CLK15, 6},
159
{CPM_CLK_FCC2, CPM_CLK16, 7},
160
{CPM_CLK_FCC3, CPM_BRG5, 0},
161
{CPM_CLK_FCC3, CPM_BRG6, 1},
162
{CPM_CLK_FCC3, CPM_BRG7, 2},
163
{CPM_CLK_FCC3, CPM_BRG8, 3},
164
{CPM_CLK_FCC3, CPM_CLK13, 4},
165
{CPM_CLK_FCC3, CPM_CLK14, 5},
166
{CPM_CLK_FCC3, CPM_CLK15, 6},
167
{CPM_CLK_FCC3, CPM_CLK16, 7},
168
{CPM_CLK_SCC1, CPM_BRG1, 0},
169
{CPM_CLK_SCC1, CPM_BRG2, 1},
170
{CPM_CLK_SCC1, CPM_BRG3, 2},
171
{CPM_CLK_SCC1, CPM_BRG4, 3},
172
{CPM_CLK_SCC1, CPM_CLK11, 4},
173
{CPM_CLK_SCC1, CPM_CLK12, 5},
174
{CPM_CLK_SCC1, CPM_CLK3, 6},
175
{CPM_CLK_SCC1, CPM_CLK4, 7},
176
{CPM_CLK_SCC2, CPM_BRG1, 0},
177
{CPM_CLK_SCC2, CPM_BRG2, 1},
178
{CPM_CLK_SCC2, CPM_BRG3, 2},
179
{CPM_CLK_SCC2, CPM_BRG4, 3},
180
{CPM_CLK_SCC2, CPM_CLK11, 4},
181
{CPM_CLK_SCC2, CPM_CLK12, 5},
182
{CPM_CLK_SCC2, CPM_CLK3, 6},
183
{CPM_CLK_SCC2, CPM_CLK4, 7},
184
{CPM_CLK_SCC3, CPM_BRG1, 0},
185
{CPM_CLK_SCC3, CPM_BRG2, 1},
186
{CPM_CLK_SCC3, CPM_BRG3, 2},
187
{CPM_CLK_SCC3, CPM_BRG4, 3},
188
{CPM_CLK_SCC3, CPM_CLK5, 4},
189
{CPM_CLK_SCC3, CPM_CLK6, 5},
190
{CPM_CLK_SCC3, CPM_CLK7, 6},
191
{CPM_CLK_SCC3, CPM_CLK8, 7},
192
{CPM_CLK_SCC4, CPM_BRG1, 0},
193
{CPM_CLK_SCC4, CPM_BRG2, 1},
194
{CPM_CLK_SCC4, CPM_BRG3, 2},
195
{CPM_CLK_SCC4, CPM_BRG4, 3},
196
{CPM_CLK_SCC4, CPM_CLK5, 4},
197
{CPM_CLK_SCC4, CPM_CLK6, 5},
198
{CPM_CLK_SCC4, CPM_CLK7, 6},
199
{CPM_CLK_SCC4, CPM_CLK8, 7},
200
};
201
202
switch (target) {
203
case CPM_CLK_SCC1:
204
reg = &cpm2_immr->im_cpmux.cmx_scr;
205
shift = 24;
206
break;
207
case CPM_CLK_SCC2:
208
reg = &cpm2_immr->im_cpmux.cmx_scr;
209
shift = 16;
210
break;
211
case CPM_CLK_SCC3:
212
reg = &cpm2_immr->im_cpmux.cmx_scr;
213
shift = 8;
214
break;
215
case CPM_CLK_SCC4:
216
reg = &cpm2_immr->im_cpmux.cmx_scr;
217
shift = 0;
218
break;
219
case CPM_CLK_FCC1:
220
reg = &cpm2_immr->im_cpmux.cmx_fcr;
221
shift = 24;
222
break;
223
case CPM_CLK_FCC2:
224
reg = &cpm2_immr->im_cpmux.cmx_fcr;
225
shift = 16;
226
break;
227
case CPM_CLK_FCC3:
228
reg = &cpm2_immr->im_cpmux.cmx_fcr;
229
shift = 8;
230
break;
231
default:
232
printk(KERN_ERR "cpm2_clock_setup: invalid clock target\n");
233
return -EINVAL;
234
}
235
236
for (i = 0; i < ARRAY_SIZE(clk_map); i++) {
237
if (clk_map[i][0] == target && clk_map[i][1] == clock) {
238
bits = clk_map[i][2];
239
break;
240
}
241
}
242
if (i == ARRAY_SIZE(clk_map))
243
ret = -EINVAL;
244
245
bits <<= shift;
246
mask <<= shift;
247
248
if (mode == CPM_CLK_RTX) {
249
bits |= bits << 3;
250
mask |= mask << 3;
251
} else if (mode == CPM_CLK_RX) {
252
bits <<= 3;
253
mask <<= 3;
254
}
255
256
out_be32(reg, (in_be32(reg) & ~mask) | bits);
257
258
return ret;
259
}
260
261
int __init cpm2_smc_clk_setup(enum cpm_clk_target target, int clock)
262
{
263
int ret = 0;
264
int shift;
265
int i, bits = 0;
266
u8 __iomem *reg;
267
u8 mask = 3;
268
269
u8 clk_map[][3] = {
270
{CPM_CLK_SMC1, CPM_BRG1, 0},
271
{CPM_CLK_SMC1, CPM_BRG7, 1},
272
{CPM_CLK_SMC1, CPM_CLK7, 2},
273
{CPM_CLK_SMC1, CPM_CLK9, 3},
274
{CPM_CLK_SMC2, CPM_BRG2, 0},
275
{CPM_CLK_SMC2, CPM_BRG8, 1},
276
{CPM_CLK_SMC2, CPM_CLK4, 2},
277
{CPM_CLK_SMC2, CPM_CLK15, 3},
278
};
279
280
switch (target) {
281
case CPM_CLK_SMC1:
282
reg = &cpm2_immr->im_cpmux.cmx_smr;
283
mask = 3;
284
shift = 4;
285
break;
286
case CPM_CLK_SMC2:
287
reg = &cpm2_immr->im_cpmux.cmx_smr;
288
mask = 3;
289
shift = 0;
290
break;
291
default:
292
printk(KERN_ERR "cpm2_smc_clock_setup: invalid clock target\n");
293
return -EINVAL;
294
}
295
296
for (i = 0; i < ARRAY_SIZE(clk_map); i++) {
297
if (clk_map[i][0] == target && clk_map[i][1] == clock) {
298
bits = clk_map[i][2];
299
break;
300
}
301
}
302
if (i == ARRAY_SIZE(clk_map))
303
ret = -EINVAL;
304
305
bits <<= shift;
306
mask <<= shift;
307
308
out_8(reg, (in_8(reg) & ~mask) | bits);
309
310
return ret;
311
}
312
313
struct cpm2_ioports {
314
u32 dir, par, sor, odr, dat;
315
u32 res[3];
316
};
317
318
void __init cpm2_set_pin(int port, int pin, int flags)
319
{
320
struct cpm2_ioports __iomem *iop =
321
(struct cpm2_ioports __iomem *)&cpm2_immr->im_ioport;
322
323
pin = 1 << (31 - pin);
324
325
if (flags & CPM_PIN_OUTPUT)
326
setbits32(&iop[port].dir, pin);
327
else
328
clrbits32(&iop[port].dir, pin);
329
330
if (!(flags & CPM_PIN_GPIO))
331
setbits32(&iop[port].par, pin);
332
else
333
clrbits32(&iop[port].par, pin);
334
335
if (flags & CPM_PIN_SECONDARY)
336
setbits32(&iop[port].sor, pin);
337
else
338
clrbits32(&iop[port].sor, pin);
339
340
if (flags & CPM_PIN_OPENDRAIN)
341
setbits32(&iop[port].odr, pin);
342
else
343
clrbits32(&iop[port].odr, pin);
344
}
345
346