Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* |
2 | * General Purpose functions for the global management of the | |
3 | * Communication Processor Module. | |
4 | * | |
5 | * Copyright (c) 2000 Michael Leslie <mleslie@lineo.com> | |
6 | * Copyright (c) 1997 Dan Malek (dmalek@jlc.net) | |
7 | * | |
8 | * In addition to the individual control of the communication | |
9 | * channels, there are a few functions that globally affect the | |
10 | * communication processor. | |
11 | * | |
12 | * Buffer descriptors must be allocated from the dual ported memory | |
13 | * space. The allocator for that is here. When the communication | |
14 | * process is reset, we reclaim the memory available. There is | |
15 | * currently no deallocator for this memory. | |
16 | * The amount of space available is platform dependent. On the | |
17 | * MBX, the EPPC software loads additional microcode into the | |
18 | * communication processor, and uses some of the DP ram for this | |
19 | * purpose. Current, the first 512 bytes and the last 256 bytes of | |
20 | * memory are used. Right now I am conservative and only use the | |
21 | * memory that can never be used for microcode. If there are | |
22 | * applications that require more DP ram, we can expand the boundaries | |
23 | * but then we have to be careful of any downloaded microcode. | |
24 | * | |
25 | */ | |
26 | ||
27 | /* | |
28 | * Michael Leslie <mleslie@lineo.com> | |
29 | * adapted Dan Malek's ppc8xx drivers to M68360 | |
30 | * | |
31 | */ | |
32 | ||
33 | #include <linux/errno.h> | |
34 | #include <linux/sched.h> | |
35 | #include <linux/kernel.h> | |
36 | #include <linux/param.h> | |
37 | #include <linux/string.h> | |
38 | #include <linux/mm.h> | |
39 | #include <linux/interrupt.h> | |
40 | #include <asm/irq.h> | |
41 | #include <asm/m68360.h> | |
42 | #include <asm/commproc.h> | |
43 | ||
44 | /* #include <asm/page.h> */ | |
45 | /* #include <asm/pgtable.h> */ | |
46 | extern void *_quicc_base; | |
47 | extern unsigned int system_clock; | |
48 | ||
49 | ||
50 | static uint dp_alloc_base; /* Starting offset in DP ram */ | |
51 | static uint dp_alloc_top; /* Max offset + 1 */ | |
52 | ||
53 | #if 0 | |
54 | static void *host_buffer; /* One page of host buffer */ | |
55 | static void *host_end; /* end + 1 */ | |
56 | #endif | |
57 | ||
58 | /* struct cpm360_t *cpmp; */ /* Pointer to comm processor space */ | |
59 | ||
60 | QUICC *pquicc; | |
61 | /* QUICC *quicc_dpram; */ /* mleslie - temporary; use extern pquicc elsewhere instead */ | |
62 | ||
63 | ||
64 | /* CPM interrupt vector functions. */ | |
65 | struct cpm_action { | |
66 | void (*handler)(void *); | |
67 | void *dev_id; | |
68 | }; | |
69 | static struct cpm_action cpm_vecs[CPMVEC_NR]; | |
70 | static void cpm_interrupt(int irq, void * dev, struct pt_regs * regs); | |
71 | static void cpm_error_interrupt(void *); | |
72 | ||
73 | /* prototypes: */ | |
74 | void cpm_install_handler(int vec, void (*handler)(), void *dev_id); | |
75 | void m360_cpm_reset(void); | |
76 | ||
77 | ||
78 | ||
79 | ||
80 | void m360_cpm_reset() | |
81 | { | |
82 | /* pte_t *pte; */ | |
83 | ||
84 | pquicc = (struct quicc *)(_quicc_base); /* initialized in crt0_rXm.S */ | |
85 | ||
86 | /* Perform a CPM reset. */ | |
87 | pquicc->cp_cr = (SOFTWARE_RESET | CMD_FLAG); | |
88 | ||
89 | /* Wait for CPM to become ready (should be 2 clocks). */ | |
90 | while (pquicc->cp_cr & CMD_FLAG); | |
91 | ||
92 | /* On the recommendation of the 68360 manual, p. 7-60 | |
93 | * - Set sdma interrupt service mask to 7 | |
94 | * - Set sdma arbitration ID to 4 | |
95 | */ | |
96 | pquicc->sdma_sdcr = 0x0740; | |
97 | ||
98 | ||
99 | /* Claim the DP memory for our use. | |
100 | */ | |
101 | dp_alloc_base = CPM_DATAONLY_BASE; | |
102 | dp_alloc_top = dp_alloc_base + CPM_DATAONLY_SIZE; | |
103 | ||
104 | ||
105 | /* Set the host page for allocation. | |
106 | */ | |
107 | /* host_buffer = host_page_addr; */ | |
108 | /* host_end = host_page_addr + PAGE_SIZE; */ | |
109 | ||
110 | /* pte = find_pte(&init_mm, host_page_addr); */ | |
111 | /* pte_val(*pte) |= _PAGE_NO_CACHE; */ | |
112 | /* flush_tlb_page(current->mm->mmap, host_buffer); */ | |
724b62b5 | 113 | |
1da177e4 LT |
114 | /* Tell everyone where the comm processor resides. |
115 | */ | |
116 | /* cpmp = (cpm360_t *)commproc; */ | |
117 | } | |
118 | ||
119 | ||
120 | /* This is called during init_IRQ. We used to do it above, but this | |
121 | * was too early since init_IRQ was not yet called. | |
122 | */ | |
123 | void | |
124 | cpm_interrupt_init(void) | |
125 | { | |
126 | /* Initialize the CPM interrupt controller. | |
127 | * NOTE THAT pquicc had better have been initialized! | |
128 | * reference: MC68360UM p. 7-377 | |
129 | */ | |
130 | pquicc->intr_cicr = | |
131 | (CICR_SCD_SCC4 | CICR_SCC_SCC3 | CICR_SCB_SCC2 | CICR_SCA_SCC1) | | |
132 | (CPM_INTERRUPT << 13) | | |
133 | CICR_HP_MASK | | |
134 | (CPM_VECTOR_BASE << 5) | | |
135 | CICR_SPS; | |
136 | ||
137 | /* mask all CPM interrupts from reaching the cpu32 core: */ | |
138 | pquicc->intr_cimr = 0; | |
139 | ||
140 | ||
141 | /* mles - If I understand correctly, the 360 just pops over to the CPM | |
142 | * specific vector, obviating the necessity to vector through the IRQ | |
143 | * whose priority the CPM is set to. This needs a closer look, though. | |
144 | */ | |
145 | ||
146 | /* Set our interrupt handler with the core CPU. */ | |
147 | /* if (request_irq(CPM_INTERRUPT, cpm_interrupt, 0, "cpm", NULL) != 0) */ | |
148 | /* panic("Could not allocate CPM IRQ!"); */ | |
149 | ||
150 | /* Install our own error handler. | |
151 | */ | |
152 | /* I think we want to hold off on this one for the moment - mles */ | |
153 | /* cpm_install_handler(CPMVEC_ERROR, cpm_error_interrupt, NULL); */ | |
154 | ||
155 | /* master CPM interrupt enable */ | |
156 | /* pquicc->intr_cicr |= CICR_IEN; */ /* no such animal for 360 */ | |
157 | } | |
158 | ||
159 | ||
160 | ||
161 | /* CPM interrupt controller interrupt. | |
162 | */ | |
163 | static void | |
164 | cpm_interrupt(int irq, void * dev, struct pt_regs * regs) | |
165 | { | |
166 | /* uint vec; */ | |
167 | ||
168 | /* mles: Note that this stuff is currently being performed by | |
169 | * M68360_do_irq(int vec, struct pt_regs *fp), in ../ints.c */ | |
170 | ||
171 | /* figure out the vector */ | |
172 | /* call that vector's handler */ | |
173 | /* clear the irq's bit in the service register */ | |
174 | ||
175 | #if 0 /* old 860 stuff: */ | |
176 | /* Get the vector by setting the ACK bit and then reading | |
177 | * the register. | |
178 | */ | |
179 | ((volatile immap_t *)IMAP_ADDR)->im_cpic.cpic_civr = 1; | |
180 | vec = ((volatile immap_t *)IMAP_ADDR)->im_cpic.cpic_civr; | |
181 | vec >>= 11; | |
182 | ||
183 | ||
184 | if (cpm_vecs[vec].handler != 0) | |
185 | (*cpm_vecs[vec].handler)(cpm_vecs[vec].dev_id); | |
186 | else | |
187 | ((immap_t *)IMAP_ADDR)->im_cpic.cpic_cimr &= ~(1 << vec); | |
188 | ||
189 | /* After servicing the interrupt, we have to remove the status | |
190 | * indicator. | |
191 | */ | |
192 | ((immap_t *)IMAP_ADDR)->im_cpic.cpic_cisr |= (1 << vec); | |
193 | #endif | |
724b62b5 | 194 | |
1da177e4 LT |
195 | } |
196 | ||
197 | /* The CPM can generate the error interrupt when there is a race condition | |
198 | * between generating and masking interrupts. All we have to do is ACK it | |
199 | * and return. This is a no-op function so we don't need any special | |
200 | * tests in the interrupt handler. | |
201 | */ | |
202 | static void | |
203 | cpm_error_interrupt(void *dev) | |
204 | { | |
205 | } | |
206 | ||
207 | /* Install a CPM interrupt handler. | |
208 | */ | |
209 | void | |
210 | cpm_install_handler(int vec, void (*handler)(), void *dev_id) | |
211 | { | |
212 | ||
4531dab4 | 213 | request_irq(vec, handler, 0, "timer", dev_id); |
1da177e4 LT |
214 | |
215 | /* if (cpm_vecs[vec].handler != 0) */ | |
216 | /* printk(KERN_INFO "CPM interrupt %x replacing %x\n", */ | |
217 | /* (uint)handler, (uint)cpm_vecs[vec].handler); */ | |
218 | /* cpm_vecs[vec].handler = handler; */ | |
219 | /* cpm_vecs[vec].dev_id = dev_id; */ | |
220 | ||
221 | /* ((immap_t *)IMAP_ADDR)->im_cpic.cpic_cimr |= (1 << vec); */ | |
222 | /* pquicc->intr_cimr |= (1 << vec); */ | |
223 | ||
224 | } | |
225 | ||
226 | /* Free a CPM interrupt handler. | |
227 | */ | |
228 | void | |
229 | cpm_free_handler(int vec) | |
230 | { | |
231 | cpm_vecs[vec].handler = NULL; | |
232 | cpm_vecs[vec].dev_id = NULL; | |
233 | /* ((immap_t *)IMAP_ADDR)->im_cpic.cpic_cimr &= ~(1 << vec); */ | |
234 | pquicc->intr_cimr &= ~(1 << vec); | |
235 | } | |
236 | ||
237 | ||
238 | ||
239 | ||
240 | /* Allocate some memory from the dual ported ram. We may want to | |
241 | * enforce alignment restrictions, but right now everyone is a good | |
242 | * citizen. | |
243 | */ | |
244 | uint | |
245 | m360_cpm_dpalloc(uint size) | |
246 | { | |
247 | uint retloc; | |
248 | ||
249 | if ((dp_alloc_base + size) >= dp_alloc_top) | |
250 | return(CPM_DP_NOSPACE); | |
251 | ||
252 | retloc = dp_alloc_base; | |
253 | dp_alloc_base += size; | |
254 | ||
255 | return(retloc); | |
256 | } | |
257 | ||
258 | ||
259 | #if 0 /* mleslie - for now these are simply kmalloc'd */ | |
260 | /* We also own one page of host buffer space for the allocation of | |
261 | * UART "fifos" and the like. | |
262 | */ | |
263 | uint | |
264 | m360_cpm_hostalloc(uint size) | |
265 | { | |
266 | uint retloc; | |
267 | ||
268 | if ((host_buffer + size) >= host_end) | |
269 | return(0); | |
270 | ||
271 | retloc = host_buffer; | |
272 | host_buffer += size; | |
273 | ||
274 | return(retloc); | |
275 | } | |
276 | #endif | |
277 | ||
278 | ||
279 | /* Set a baud rate generator. This needs lots of work. There are | |
280 | * four BRGs, any of which can be wired to any channel. | |
281 | * The internal baud rate clock is the system clock divided by 16. | |
282 | * This assumes the baudrate is 16x oversampled by the uart. | |
283 | */ | |
284 | /* #define BRG_INT_CLK (((bd_t *)__res)->bi_intfreq * 1000000) */ | |
285 | #define BRG_INT_CLK system_clock | |
286 | #define BRG_UART_CLK (BRG_INT_CLK/16) | |
287 | ||
288 | void | |
289 | m360_cpm_setbrg(uint brg, uint rate) | |
290 | { | |
291 | volatile uint *bp; | |
292 | ||
293 | /* This is good enough to get SMCs running..... | |
294 | */ | |
295 | /* bp = (uint *)&cpmp->cp_brgc1; */ | |
296 | bp = (volatile uint *)(&pquicc->brgc[0].l); | |
297 | bp += brg; | |
298 | *bp = ((BRG_UART_CLK / rate - 1) << 1) | CPM_BRG_EN; | |
299 | } | |
300 | ||
301 | ||
302 | /* | |
303 | * Local variables: | |
304 | * c-indent-level: 4 | |
305 | * c-basic-offset: 4 | |
306 | * tab-width: 4 | |
307 | * End: | |
308 | */ |