1 | /* |
---|
2 | * BRM driver |
---|
3 | * |
---|
4 | * COPYRIGHT (c) 2006. |
---|
5 | * Gaisler Research. |
---|
6 | * |
---|
7 | * The license and distribution terms for this file may be |
---|
8 | * found in the file LICENSE in this distribution or at |
---|
9 | * http://www.rtems.com/license/LICENSE. |
---|
10 | * |
---|
11 | */ |
---|
12 | |
---|
13 | /********** Set defaults **********/ |
---|
14 | |
---|
15 | /* basic bus/interface of device, |
---|
16 | * Default to direct accessed AMBA bus. |
---|
17 | */ |
---|
18 | #ifndef B1553BRM_NO_AMBA |
---|
19 | #define B1553BRM_AMBA |
---|
20 | #undef B1553BRM_PCI |
---|
21 | #endif |
---|
22 | |
---|
23 | /* default name to /dev/brm */ |
---|
24 | #if !defined(B1553BRM_DEVNAME) || !defined(B1553BRM_DEVNAME_NO) |
---|
25 | #undef B1553BRM_DEVNAME |
---|
26 | #undef B1553BRM_DEVNAME_NO |
---|
27 | #define B1553BRM_DEVNAME "/dev/brm0" |
---|
28 | #define B1553BRM_DEVNAME_NO(devstr,no) ((devstr)[8]='0'+(no)) |
---|
29 | #endif |
---|
30 | |
---|
31 | #ifndef B1553BRM_PREFIX |
---|
32 | #define B1553BRM_PREFIX(name) b1553brm##name |
---|
33 | #endif |
---|
34 | |
---|
35 | /* default to no translation */ |
---|
36 | #ifndef B1553BRM_ADR_TO |
---|
37 | #define memarea_to_hw(x) ((unsigned int)(x)) |
---|
38 | #endif |
---|
39 | |
---|
40 | #ifndef B1553BRM_REG_INT |
---|
41 | #define B1553BRM_REG_INT(handler,irqno,arg) set_vector(handler,(irqno)+0x10,1) |
---|
42 | #undef B1553BRM_DEFINE_INTHANDLER |
---|
43 | #define B1553BRM_DEFINE_INTHANDLER |
---|
44 | #endif |
---|
45 | |
---|
46 | /* default to 128K memory layout */ |
---|
47 | #if !defined(DMA_MEM_16K) |
---|
48 | #define DMA_MEM_128K |
---|
49 | #endif |
---|
50 | |
---|
51 | #include <bsp.h> |
---|
52 | #include <rtems/libio.h> |
---|
53 | #include <stdlib.h> |
---|
54 | #include <stdio.h> |
---|
55 | #include <string.h> |
---|
56 | #include <assert.h> |
---|
57 | #include <ctype.h> |
---|
58 | #include <rtems/bspIo.h> |
---|
59 | |
---|
60 | #include <b1553brm.h> |
---|
61 | #include <ambapp.h> |
---|
62 | |
---|
63 | /* Uncomment for debug output */ |
---|
64 | /*#define DEBUG 1 |
---|
65 | #define FUNCDEBUG 1*/ |
---|
66 | #undef DEBUG |
---|
67 | #undef FUNCDEBUG |
---|
68 | |
---|
69 | /* EVENT_QUEUE_SIZE sets the size of the event queue |
---|
70 | */ |
---|
71 | #define EVENT_QUEUE_SIZE 1024 |
---|
72 | |
---|
73 | |
---|
74 | #define INDEX(x) ( x&(EVENT_QUEUE_SIZE-1) ) |
---|
75 | |
---|
76 | #ifdef DEBUG |
---|
77 | #define DBG(x...) printk(x) |
---|
78 | #else |
---|
79 | #define DBG(x...) |
---|
80 | #endif |
---|
81 | |
---|
82 | #ifdef FUNCDEBUG |
---|
83 | #define FUNCDBG(x...) printk(x) |
---|
84 | #else |
---|
85 | #define FUNCDBG(x...) |
---|
86 | #endif |
---|
87 | |
---|
88 | #define READ_REG(address) _BRM_REG_READ16((unsigned int)address) |
---|
89 | #define READ_DMA(address) _BRM_REG_READ16((unsigned int)address) |
---|
90 | static __inline__ unsigned short _BRM_REG_READ16(unsigned int addr) { |
---|
91 | unsigned short tmp; |
---|
92 | asm(" lduha [%1]1, %0 " |
---|
93 | : "=r"(tmp) |
---|
94 | : "r"(addr) |
---|
95 | ); |
---|
96 | return tmp; |
---|
97 | } |
---|
98 | |
---|
99 | static rtems_device_driver brm_initialize(rtems_device_major_number major, rtems_device_minor_number minor, void *arg); |
---|
100 | static rtems_device_driver brm_open(rtems_device_major_number major, rtems_device_minor_number minor, void *arg); |
---|
101 | static rtems_device_driver brm_close(rtems_device_major_number major, rtems_device_minor_number minor, void *arg); |
---|
102 | static rtems_device_driver brm_read(rtems_device_major_number major, rtems_device_minor_number minor, void *arg); |
---|
103 | static rtems_device_driver brm_write(rtems_device_major_number major, rtems_device_minor_number minor, void *arg); |
---|
104 | static rtems_device_driver brm_control(rtems_device_major_number major, rtems_device_minor_number minor, void *arg); |
---|
105 | |
---|
106 | #define BRM_DRIVER_TABLE_ENTRY { brm_initialize, brm_open, brm_close, brm_read, brm_write, brm_control } |
---|
107 | |
---|
108 | static rtems_driver_address_table brm_driver = BRM_DRIVER_TABLE_ENTRY; |
---|
109 | |
---|
110 | struct msg { |
---|
111 | unsigned short miw; |
---|
112 | unsigned short time; |
---|
113 | unsigned short data[32]; |
---|
114 | }; |
---|
115 | #if defined(DMA_MEM_128K) |
---|
116 | struct circ_buf { |
---|
117 | struct msg msgs[9]; |
---|
118 | }; |
---|
119 | #elif defined(DMA_MEM_16K) |
---|
120 | /* two message queue */ |
---|
121 | struct circ_buf_2 { |
---|
122 | struct msg msgs[2]; |
---|
123 | }; |
---|
124 | /* one message queue */ |
---|
125 | struct circ_buf_1 { |
---|
126 | struct msg msgs[1]; |
---|
127 | }; |
---|
128 | #endif |
---|
129 | |
---|
130 | struct irq_log_list { |
---|
131 | volatile unsigned short iiw; |
---|
132 | volatile unsigned short iaw; |
---|
133 | }; |
---|
134 | |
---|
135 | typedef struct { |
---|
136 | |
---|
137 | unsigned int memarea_base; |
---|
138 | struct brm_reg *regs; |
---|
139 | |
---|
140 | /* BRM descriptors */ |
---|
141 | struct desc_table { |
---|
142 | |
---|
143 | volatile unsigned short ctrl; |
---|
144 | volatile unsigned short top; |
---|
145 | volatile unsigned short cur; |
---|
146 | volatile unsigned short bot; |
---|
147 | |
---|
148 | } *desc; |
---|
149 | |
---|
150 | volatile unsigned short *mem; |
---|
151 | /* bc mem struct */ |
---|
152 | struct { |
---|
153 | /* BC Descriptors */ |
---|
154 | struct { |
---|
155 | unsigned short ctrl; /* control */ |
---|
156 | unsigned short cw1; /* Command word 1*/ |
---|
157 | unsigned short cw2; /* Command word 1*/ |
---|
158 | unsigned short dptr; /* Data pointer in halfword offset from bcmem */ |
---|
159 | unsigned short tsw[2]; /* status word 1 & 2 */ |
---|
160 | unsigned short ba; /* branch address */ |
---|
161 | unsigned short timer; /* timer value */ |
---|
162 | } descs[128]; /* 2k (1024 half words) */ |
---|
163 | |
---|
164 | /* message data */ |
---|
165 | struct { |
---|
166 | unsigned short data[32]; /* 1 message's data */ |
---|
167 | } msg_data[128]; /* 8k */ |
---|
168 | |
---|
169 | #if defined(DMA_MEM_128K) |
---|
170 | /* offset to last 64bytes of 128k */ |
---|
171 | unsigned short unused[(64*1024-(128*8+128*32))-16*2]; |
---|
172 | #elif defined(DMA_MEM_16K) |
---|
173 | unsigned short unused[(8*1024-(128*8+128*32))-16*2]; |
---|
174 | #endif |
---|
175 | /* interrupt log at 64 bytes from end */ |
---|
176 | struct irq_log_list irq_logs[16]; |
---|
177 | } *bcmem; |
---|
178 | |
---|
179 | #if defined(DMA_MEM_128K) |
---|
180 | /* Memory structure of a RT being inited, just used |
---|
181 | * for RT initialization. |
---|
182 | * |
---|
183 | * *mesgs[32] fit each minimally 8 messages per sub address. |
---|
184 | */ |
---|
185 | struct { |
---|
186 | /* RX Sub Address descriptors */ |
---|
187 | struct desc_table rxsubs[32]; |
---|
188 | /* TX Sub Address descriptors */ |
---|
189 | struct desc_table txsubs[32]; |
---|
190 | /* RX mode code descriptors */ |
---|
191 | struct desc_table rxmodes[32]; |
---|
192 | /* TX mode code descriptors */ |
---|
193 | struct desc_table txmodes[32]; |
---|
194 | |
---|
195 | /* RX Sub Address messages */ |
---|
196 | struct circ_buf rxsuba_msgs[32]; |
---|
197 | /* TX Sub Address messages */ |
---|
198 | struct circ_buf txsuba_msgs[32]; |
---|
199 | /* RX Mode Code messages */ |
---|
200 | struct circ_buf rxmode_msgs[32]; |
---|
201 | /* RX Mode Code messages */ |
---|
202 | struct circ_buf txmode_msgs[32]; |
---|
203 | |
---|
204 | |
---|
205 | /* offset to last 64bytes of 128k: tot-used-needed */ |
---|
206 | unsigned short unused[(64*1024-(4*32*4+4*32*9*34))-16*2]; |
---|
207 | |
---|
208 | /* interrupt log at 64 bytes from end */ |
---|
209 | struct irq_log_list irq_logs[16]; |
---|
210 | } *rtmem; |
---|
211 | #elif defined(DMA_MEM_16K) |
---|
212 | /* Memory structure of a RT being inited, just used |
---|
213 | * for RT initialization. |
---|
214 | * |
---|
215 | * circ_buf_2 *mesgs[32] fit each minimally 2 messages per queue. |
---|
216 | * circ_buf_1 *mesgs[32] fit each minimally 1 messages per queue. |
---|
217 | */ |
---|
218 | struct { |
---|
219 | /* RX Sub Address descriptors */ |
---|
220 | struct desc_table rxsubs[32]; |
---|
221 | /* TX Sub Address descriptors */ |
---|
222 | struct desc_table txsubs[32]; |
---|
223 | /* RX mode code descriptors */ |
---|
224 | struct desc_table rxmodes[32]; |
---|
225 | /* TX mode code descriptors */ |
---|
226 | struct desc_table txmodes[32]; |
---|
227 | |
---|
228 | /* RX Sub Address messages */ |
---|
229 | struct circ_buf_2 rxsuba_msgs[32]; |
---|
230 | /* TX Sub Address messages */ |
---|
231 | struct circ_buf_2 txsuba_msgs[32]; |
---|
232 | /* RX Mode Code messages */ |
---|
233 | struct circ_buf_2 rxmode_msgs[32]; |
---|
234 | /* RX Mode Code messages */ |
---|
235 | struct circ_buf_1 txmode_msgs[32]; |
---|
236 | |
---|
237 | |
---|
238 | /* offset to last 64bytes of 16k: tot-used-needed */ |
---|
239 | unsigned short unused[8*1024 -(4*32*4 +3*32*2*34 +1*32*1*34) -16*2]; |
---|
240 | |
---|
241 | /* interrupt log at 64 bytes from end */ |
---|
242 | struct irq_log_list irq_logs[16]; |
---|
243 | } *rtmem; |
---|
244 | #else |
---|
245 | #error You must define one DMA_MEM_???K |
---|
246 | #endif |
---|
247 | |
---|
248 | /* Interrupt log list */ |
---|
249 | struct irq_log_list *irq_log; |
---|
250 | unsigned int irq; |
---|
251 | |
---|
252 | /* Received events waiting to be read */ |
---|
253 | struct rt_msg *rt_event; |
---|
254 | struct bm_msg *bm_event; |
---|
255 | |
---|
256 | unsigned int head, tail; |
---|
257 | |
---|
258 | unsigned int last_read[128]; |
---|
259 | unsigned int written[32]; |
---|
260 | |
---|
261 | struct bc_msg *cur_list; |
---|
262 | |
---|
263 | int tx_blocking, rx_blocking; |
---|
264 | |
---|
265 | rtems_id rx_sem, tx_sem, dev_sem; |
---|
266 | int minor; |
---|
267 | int irqno; |
---|
268 | unsigned int mode; |
---|
269 | #ifdef DEBUG |
---|
270 | unsigned int log[EVENT_QUEUE_SIZE*4]; |
---|
271 | unsigned int log_i; |
---|
272 | #endif |
---|
273 | |
---|
274 | rtems_id event_id; /* event that may be signalled upon errors, needs to be set through ioctl command BRM_SET_EVENTID */ |
---|
275 | unsigned int status; |
---|
276 | int bc_list_fail; |
---|
277 | } brm_priv; |
---|
278 | |
---|
279 | static int brm_cores; |
---|
280 | static unsigned int allbrm_memarea; |
---|
281 | static brm_priv *brms; |
---|
282 | static amba_confarea_type *amba_bus; |
---|
283 | static unsigned int allbrm_cfg_clksel; |
---|
284 | static unsigned int allbrm_cfg_clkdiv; |
---|
285 | static unsigned int allbrm_cfg_freq; |
---|
286 | |
---|
287 | static void brm_interrupt(brm_priv *brm); |
---|
288 | #ifdef B1553BRM_DEFINE_INTHANDLER |
---|
289 | static void b1553brm_interrupt_handler(rtems_vector_number v); |
---|
290 | #endif |
---|
291 | |
---|
292 | #define OFS(ofs) (((unsigned int)&ofs & 0x1ffff)>>1) |
---|
293 | |
---|
294 | static int odd_parity(unsigned int data) { |
---|
295 | unsigned int i=0; |
---|
296 | |
---|
297 | while(data) |
---|
298 | { |
---|
299 | i++; |
---|
300 | data &= (data - 1); |
---|
301 | } |
---|
302 | |
---|
303 | return !(i&1); |
---|
304 | } |
---|
305 | |
---|
306 | |
---|
307 | static void start_operation(brm_priv *brm) { |
---|
308 | unsigned int ctrl = READ_REG(&brm->regs->ctrl); |
---|
309 | brm->regs->ctrl = ctrl | 0x8000; |
---|
310 | } |
---|
311 | |
---|
312 | static void stop_operation(brm_priv *brm) { |
---|
313 | unsigned int ctrl = READ_REG(&brm->regs->ctrl); |
---|
314 | brm->regs->ctrl = ctrl & ~0x8000; |
---|
315 | } |
---|
316 | static int is_executing(brm_priv *brm) { |
---|
317 | unsigned int ctrl = READ_REG(&brm->regs->ctrl); |
---|
318 | return ((ctrl>>15) & 1); |
---|
319 | } |
---|
320 | |
---|
321 | #ifdef LEON3 |
---|
322 | #ifndef DONT_DEF_RAMON |
---|
323 | int brm_register_leon3_ramon_fpga(void){ |
---|
324 | /* Clock div & Clock sel is NOT available. |
---|
325 | * The BRM is always clocked with 24MHz. |
---|
326 | * 3 in BRM enhanced register will select 24MHz |
---|
327 | */ |
---|
328 | return b1553brm_register(&amba_conf,0,0,3); |
---|
329 | } |
---|
330 | |
---|
331 | int brm_register_leon3_ramon_asic(void){ |
---|
332 | /* Clock div & Clock sel is available. |
---|
333 | * Clkdiv only matter when clksel is 1. |
---|
334 | * clksel=2, clkdiv=don't care, brm_frq=24MHz |
---|
335 | * |
---|
336 | * 3 in BRM enhanced register will select 24MHz |
---|
337 | */ |
---|
338 | return b1553brm_register(&amba_conf,2,0,3); |
---|
339 | } |
---|
340 | #endif |
---|
341 | #endif |
---|
342 | |
---|
343 | int B1553BRM_PREFIX(_register)(amba_confarea_type *bus, unsigned int clksel, unsigned int clkdiv, unsigned int brm_freq) |
---|
344 | { |
---|
345 | rtems_status_code r; |
---|
346 | rtems_device_major_number m; |
---|
347 | |
---|
348 | FUNCDBG("brm_register:\n\r"); |
---|
349 | |
---|
350 | /* save amba bus pointer */ |
---|
351 | amba_bus = bus; |
---|
352 | if ( !bus ){ |
---|
353 | printk("brm_register: bus is NULL\n\r"); |
---|
354 | return 1; |
---|
355 | } |
---|
356 | |
---|
357 | #ifdef B1553BRM_LOCAL_MEM |
---|
358 | allbrm_memarea = B1553BRM_LOCAL_MEM_ADR; |
---|
359 | #else |
---|
360 | allbrm_memarea = 0; |
---|
361 | #endif |
---|
362 | |
---|
363 | /* Save clksel, clkdiv and brm_freq for later use */ |
---|
364 | allbrm_cfg_clksel = clksel & CLKSEL_MASK; |
---|
365 | allbrm_cfg_clkdiv = clkdiv & CLKDIV_MASK; |
---|
366 | allbrm_cfg_freq = brm_freq & BRM_FREQ_MASK; |
---|
367 | |
---|
368 | if ((r = rtems_io_register_driver(0, &brm_driver, &m)) == RTEMS_SUCCESSFUL) { |
---|
369 | DBG("BRM: driver successfully registered, major: %d\n",m); |
---|
370 | |
---|
371 | } else { |
---|
372 | switch(r) { |
---|
373 | case RTEMS_TOO_MANY: |
---|
374 | printk("BRM rtems_io_register_driver failed: RTEMS_TOO_MANY\n"); break; |
---|
375 | case RTEMS_INVALID_NUMBER: |
---|
376 | printk("BRM rtems_io_register_driver failed: RTEMS_INVALID_NUMBER\n"); break; |
---|
377 | case RTEMS_RESOURCE_IN_USE: |
---|
378 | printk("BRM rtems_io_register_driver failed: RTEMS_RESOURCE_IN_USE\n"); break; |
---|
379 | default: |
---|
380 | printk("BRM rtems_io_register_driver failed\n"); |
---|
381 | } |
---|
382 | return 1; |
---|
383 | } |
---|
384 | return 0; |
---|
385 | } |
---|
386 | |
---|
387 | static void clr_int_logs(struct irq_log_list *logs){ |
---|
388 | int i; |
---|
389 | for(i=0; i<16; i++){ |
---|
390 | logs[i].iiw = 0xffff; |
---|
391 | logs[i].iaw = 0x0; |
---|
392 | } |
---|
393 | } |
---|
394 | |
---|
395 | static rtems_device_driver rt_init(brm_priv *brm) { |
---|
396 | unsigned int i; |
---|
397 | |
---|
398 | brm->head = brm->tail = 0; |
---|
399 | brm->rx_blocking = brm->tx_blocking = 1; |
---|
400 | |
---|
401 | if ( brm->bm_event ) |
---|
402 | free(brm->bm_event); |
---|
403 | brm->bm_event = NULL; |
---|
404 | |
---|
405 | if ( brm->rt_event ) |
---|
406 | free(brm->rt_event); |
---|
407 | |
---|
408 | brm->bcmem = NULL; |
---|
409 | brm->rtmem = (void *)brm->mem; |
---|
410 | |
---|
411 | brm->rt_event = (struct rt_msg *) malloc(EVENT_QUEUE_SIZE*sizeof(struct rt_msg)); |
---|
412 | |
---|
413 | if (brm->rt_event == NULL) { |
---|
414 | DBG("BRM driver failed to allocated memory."); |
---|
415 | return RTEMS_NO_MEMORY; |
---|
416 | } |
---|
417 | |
---|
418 | brm->irq_log = (struct irq_log_list *)&brm->rtmem->irq_logs[0]; |
---|
419 | |
---|
420 | brm->regs->ctrl = 0x1912; /* enable both buses, circular 1 bufmode, broadcast, interrupt log */ |
---|
421 | brm->regs->oper = 0x0900; /* configure as RT, with addr 1 */ |
---|
422 | brm->regs->imask = BRM_RT_ILLCMD_IRQ|BRM_SUBAD_IRQ|BRM_TAPF_IRQ|BRM_DMAF_IRQ|BRM_WRAPF_IRQ|BRM_MERR_IRQ; |
---|
423 | brm->regs->dpoint = 0; |
---|
424 | brm->regs->ipoint = OFS(brm->rtmem->irq_logs[0]); |
---|
425 | brm->regs->enhanced = 0x0000 | allbrm_cfg_freq; /* BRM clocked with freq = 12,16,20 or 24MHz */ |
---|
426 | brm->regs->w_ctrl = (allbrm_cfg_clksel<<9) | (allbrm_cfg_clkdiv<<5) | 1; |
---|
427 | brm->regs->w_irqctrl = 6; |
---|
428 | brm->regs->w_ahbaddr = (unsigned int) memarea_to_hw(brm->memarea_base); |
---|
429 | |
---|
430 | clr_int_logs(brm->irq_log); |
---|
431 | |
---|
432 | /* Legalize all commands */ |
---|
433 | for (i = 0; i < 16; i++) { |
---|
434 | brm->regs->rt_cmd_leg[i] = 0; |
---|
435 | } |
---|
436 | |
---|
437 | /* Init descriptor table |
---|
438 | * |
---|
439 | * Each circular buffer has room for 8 messages with up to 34 (32 data + miw + time) words (16b) in each. |
---|
440 | * The buffers must separated by 34 words. |
---|
441 | */ |
---|
442 | |
---|
443 | |
---|
444 | /* RX Sub-address 0 - 31 */ |
---|
445 | for (i = 0; i < 32; i++) { |
---|
446 | brm->rtmem->rxsubs[i].ctrl = 0x00E0; /* Interrupt: INTX, IWA, and IBRD */ |
---|
447 | brm->rtmem->rxsubs[i].top = OFS(brm->rtmem->rxsuba_msgs[i]); /* Top address */ |
---|
448 | brm->rtmem->rxsubs[i].cur = OFS(brm->rtmem->rxsuba_msgs[i]); /* Current address */ |
---|
449 | brm->rtmem->rxsubs[i].bot = OFS(brm->rtmem->rxsuba_msgs[i+1]) - sizeof(struct msg)/2; /* Bottom address */ |
---|
450 | brm->last_read[i] = OFS(brm->rtmem->rxsuba_msgs[i]); |
---|
451 | } |
---|
452 | /* TX Sub-address 0 - 31 */ |
---|
453 | for (i = 0; i < 32; i++) { |
---|
454 | brm->rtmem->txsubs[i].ctrl = 0x0060; /* Interrupt: IWA and IBRD */ |
---|
455 | brm->rtmem->txsubs[i].top = OFS(brm->rtmem->txsuba_msgs[i]); /* Top address */ |
---|
456 | brm->rtmem->txsubs[i].cur = OFS(brm->rtmem->txsuba_msgs[i]); /* Current address */ |
---|
457 | brm->rtmem->txsubs[i].bot = OFS(brm->rtmem->txsuba_msgs[i+1]) - sizeof(struct msg)/2; /* Bottom address */ |
---|
458 | brm->last_read[i+32] = OFS(brm->rtmem->txsuba_msgs[i]); |
---|
459 | brm->written[i] = OFS(brm->rtmem->txsuba_msgs[i]); |
---|
460 | } |
---|
461 | /* RX mode code 0 - 31 */ |
---|
462 | for (i = 0; i < 32; i++) { |
---|
463 | brm->rtmem->rxmodes[i].ctrl = 0x00E0; /* Interrupt: INTX, IWA, and IBRD */ |
---|
464 | brm->rtmem->rxmodes[i].top = OFS(brm->rtmem->rxmode_msgs[i]); /* Top address */ |
---|
465 | brm->rtmem->rxmodes[i].cur = OFS(brm->rtmem->rxmode_msgs[i]); /* Current address */ |
---|
466 | brm->rtmem->rxmodes[i].bot = OFS(brm->rtmem->rxmode_msgs[i+1]) - sizeof(struct msg)/2; /* Bottom address */ |
---|
467 | brm->last_read[i+64] = OFS(brm->rtmem->rxmode_msgs[i]); |
---|
468 | } |
---|
469 | /* TX mode code 0 - 31 */ |
---|
470 | for (i = 0; i < 32; i++) { |
---|
471 | brm->rtmem->txmodes[i].ctrl = 0x0060; /* Interrupt: IWA and IBRD */ |
---|
472 | brm->rtmem->txmodes[i].top = OFS(brm->rtmem->txmode_msgs[i]); /* Top address */ |
---|
473 | brm->rtmem->txmodes[i].cur = OFS(brm->rtmem->txmode_msgs[i]); /* Current address */ |
---|
474 | brm->rtmem->txmodes[i].bot = OFS(brm->rtmem->txmode_msgs[i+1]) - sizeof(struct msg)/2; /* Bottom address */ |
---|
475 | brm->last_read[i+96] = OFS(brm->rtmem->txmode_msgs[i]); |
---|
476 | } |
---|
477 | |
---|
478 | brm->mode = BRM_MODE_RT; |
---|
479 | |
---|
480 | return RTEMS_SUCCESSFUL; |
---|
481 | } |
---|
482 | |
---|
483 | static rtems_device_driver bc_init(brm_priv *brm){ |
---|
484 | |
---|
485 | if ( brm->bm_event ) |
---|
486 | free(brm->bm_event); |
---|
487 | brm->bm_event = NULL; |
---|
488 | |
---|
489 | if ( brm->rt_event ) |
---|
490 | free(brm->rt_event); |
---|
491 | brm->rt_event = NULL; |
---|
492 | |
---|
493 | brm->bcmem = (void *)brm->mem; |
---|
494 | brm->rtmem = NULL; |
---|
495 | brm->irq_log = (struct irq_log_list *)&brm->bcmem->irq_logs[0]; |
---|
496 | |
---|
497 | brm->head = brm->tail = 0; |
---|
498 | brm->rx_blocking = brm->tx_blocking = 1; |
---|
499 | |
---|
500 | brm->regs->ctrl = 0x0006; /* ping pong enable and enable interrupt log */ |
---|
501 | brm->regs->oper = 0x0800; /* configure as BC */ |
---|
502 | brm->regs->imask = BRM_EOL_IRQ|BRM_BC_ILLCMD_IRQ|BRM_ILLOP_IRQ|BRM_DMAF_IRQ|BRM_WRAPF_IRQ|BRM_MERR_IRQ; |
---|
503 | brm->regs->dpoint = 0; |
---|
504 | printk("Set BC interrupt log: 0x%lx, 0x%lx, 0x%lx\n",OFS(brm->bcmem->irq_logs[0]),&brm->bcmem->irq_logs[0],brm->bcmem); |
---|
505 | brm->regs->ipoint = OFS(brm->bcmem->irq_logs[0]); |
---|
506 | brm->regs->enhanced = 0x0000 | (allbrm_cfg_freq&0x3); /* freq = 24 */ |
---|
507 | brm->regs->w_ctrl = (allbrm_cfg_clksel<<9) | (allbrm_cfg_clkdiv<<5) | 1; |
---|
508 | brm->regs->w_irqctrl = 6; |
---|
509 | brm->regs->w_ahbaddr = (unsigned int) memarea_to_hw(brm->memarea_base); |
---|
510 | |
---|
511 | clr_int_logs(brm->irq_log); |
---|
512 | |
---|
513 | brm->mode = BRM_MODE_BC; |
---|
514 | |
---|
515 | return RTEMS_SUCCESSFUL; |
---|
516 | } |
---|
517 | |
---|
518 | static rtems_device_driver bm_init(brm_priv *brm) { |
---|
519 | |
---|
520 | |
---|
521 | brm->head = brm->tail = 0; |
---|
522 | brm->rx_blocking = brm->tx_blocking = 1; |
---|
523 | |
---|
524 | if ( brm->rt_event ) |
---|
525 | free(brm->rt_event); |
---|
526 | brm->rt_event = NULL; |
---|
527 | |
---|
528 | if ( brm->bm_event ) |
---|
529 | free(brm->bm_event); |
---|
530 | |
---|
531 | brm->bcmem = NULL; |
---|
532 | brm->rtmem = NULL; |
---|
533 | |
---|
534 | brm->bm_event = (struct bm_msg *) malloc(EVENT_QUEUE_SIZE*sizeof(struct bm_msg)); |
---|
535 | |
---|
536 | if (brm->bm_event == NULL) { |
---|
537 | DBG("BRM driver failed to allocated memory."); |
---|
538 | return RTEMS_NO_MEMORY; |
---|
539 | } |
---|
540 | |
---|
541 | /* end of 16K, fits all current modes (128K, 16K) */ |
---|
542 | brm->irq_log = (struct irq_log_list *)&brm->mem[8*1024-16*2]; |
---|
543 | |
---|
544 | brm->regs->ctrl = 0x0006; /* ping pong enable and enable interrupt log */ |
---|
545 | brm->regs->oper = 0x0A00; /* configure as BM */ |
---|
546 | brm->regs->imask = BRM_MBC_IRQ|BRM_MERR_IRQ|BRM_DMAF_IRQ|BRM_MERR_IRQ; |
---|
547 | brm->regs->dpoint = 0; |
---|
548 | brm->regs->ipoint = OFS(brm->mem[8*1024-16*2]); |
---|
549 | brm->regs->mcpoint = 0; /* Command pointer */ |
---|
550 | brm->regs->mdpoint = 0x100; /* Data pointer */ |
---|
551 | brm->regs->mbc = 1; /* Block count */ |
---|
552 | brm->regs->enhanced = 0x0000 | (allbrm_cfg_freq&0x3); /* freq = 24 */ |
---|
553 | brm->regs->w_ctrl = (allbrm_cfg_clksel<<9) | (allbrm_cfg_clkdiv<<5) | 1; |
---|
554 | brm->regs->w_irqctrl = 6; |
---|
555 | brm->regs->w_ahbaddr = (unsigned int) memarea_to_hw(brm->memarea_base); |
---|
556 | |
---|
557 | clr_int_logs(brm->irq_log); |
---|
558 | |
---|
559 | brm->mode = BRM_MODE_BM; |
---|
560 | |
---|
561 | return RTEMS_SUCCESSFUL; |
---|
562 | } |
---|
563 | |
---|
564 | |
---|
565 | static rtems_device_driver brm_initialize(rtems_device_major_number major, rtems_device_minor_number minor, void *arg) |
---|
566 | { |
---|
567 | rtems_status_code status; |
---|
568 | int dev_cnt; |
---|
569 | char fs_name[20]; |
---|
570 | brm_priv *brm; |
---|
571 | amba_ahb_device ambadev; |
---|
572 | char *mem; |
---|
573 | |
---|
574 | FUNCDBG("brm_initialize\n"); |
---|
575 | |
---|
576 | brm_cores = 0; |
---|
577 | strcpy(fs_name,B1553BRM_DEVNAME); |
---|
578 | |
---|
579 | /* Find all BRM devices */ |
---|
580 | dev_cnt = amba_get_number_ahbslv_devices(amba_bus,VENDOR_GAISLER,GAISLER_BRM); |
---|
581 | if ( dev_cnt < 1 ){ |
---|
582 | /* Failed to find any CAN cores! */ |
---|
583 | printk("BRM: Failed to find any BRM cores\n\r"); |
---|
584 | return -1; |
---|
585 | } |
---|
586 | |
---|
587 | /* allocate & zero memory for the brm devices */ |
---|
588 | brms = (brm_priv *)malloc(sizeof(*brms)*dev_cnt); |
---|
589 | if ( !brms ){ |
---|
590 | printk("BRM: Failed to allocate SW memory\n\r"); |
---|
591 | return -1; |
---|
592 | } |
---|
593 | memset(brms,0,sizeof(*brms)*dev_cnt); |
---|
594 | |
---|
595 | /* Allocate memory for all device's descriptors, |
---|
596 | * they must be aligned to a XXX byte boundary. |
---|
597 | */ |
---|
598 | #define BRM_DESCS_PER_CTRL 128 |
---|
599 | if ( allbrm_memarea ){ |
---|
600 | mem = (char *)allbrm_memarea; |
---|
601 | }else{ |
---|
602 | /* sizeof(struct desc_table) * BRM_DESCS_PER_CTRL * dev_cnt */ |
---|
603 | mem = (char *)malloc( (128*1024) * (dev_cnt+1)); /* 128k per core + 128k for alignment */ |
---|
604 | if ( !mem ){ |
---|
605 | free(brms); |
---|
606 | printk("BRM: Failed to allocate HW memory\n\r"); |
---|
607 | return -1; |
---|
608 | } |
---|
609 | |
---|
610 | /* align memory to 128k boundary */ |
---|
611 | mem = (char *)(((unsigned int)mem+0x1ffff) & ~0x1ffff); |
---|
612 | } |
---|
613 | |
---|
614 | /* clear the used memory */ |
---|
615 | memset(mem,0,(128*1024) * dev_cnt); |
---|
616 | |
---|
617 | /* initialize each brm device, one at a time */ |
---|
618 | for(minor=0; minor<dev_cnt; minor++){ |
---|
619 | brm = &brms[minor]; |
---|
620 | |
---|
621 | /* Get AMBA AHB device info from Plug&Play */ |
---|
622 | amba_find_next_ahbslv(amba_bus,VENDOR_GAISLER,GAISLER_BRM,&ambadev,minor); |
---|
623 | |
---|
624 | /* Copy Basic HW info */ |
---|
625 | brm->regs = (void *)ambadev.start[0]; |
---|
626 | brm->irqno = ambadev.irq; |
---|
627 | brm->minor = minor; |
---|
628 | brm->irq = 0; |
---|
629 | #ifdef DEBUG |
---|
630 | brm->log_i = 0; |
---|
631 | memset(brm->log,0,sizeof(brm->log)); |
---|
632 | #endif |
---|
633 | |
---|
634 | /* Set unique name */ |
---|
635 | B1553BRM_DEVNAME_NO(fs_name,minor); |
---|
636 | |
---|
637 | DBG("Registering BRM core at [0x%x] irq %d, minor %d as %s\n",brm->regs,brm->irqno,minor,fs_name); |
---|
638 | |
---|
639 | /* Bind filesystem name to device number (minor) */ |
---|
640 | status = rtems_io_register_name(fs_name, major, minor); |
---|
641 | if (status != RTEMS_SUCCESSFUL) |
---|
642 | rtems_fatal_error_occurred(status); |
---|
643 | |
---|
644 | /* RX Semaphore created with count = 0 */ |
---|
645 | if ( rtems_semaphore_create(rtems_build_name('B', 'M', 'R', '0'+minor), |
---|
646 | 0, |
---|
647 | RTEMS_FIFO|RTEMS_SIMPLE_BINARY_SEMAPHORE|RTEMS_NO_INHERIT_PRIORITY|RTEMS_LOCAL|RTEMS_NO_PRIORITY_CEILING, |
---|
648 | 0, |
---|
649 | &brm->rx_sem) != RTEMS_SUCCESSFUL ){ |
---|
650 | printk("BRM: Failed to create rx semaphore\n"); |
---|
651 | return RTEMS_INTERNAL_ERROR; |
---|
652 | } |
---|
653 | |
---|
654 | /* TX Semaphore created with count = 1 */ |
---|
655 | if ( rtems_semaphore_create(rtems_build_name('B', 'M', 'T', '0'+minor), |
---|
656 | 1, |
---|
657 | RTEMS_FIFO|RTEMS_SIMPLE_BINARY_SEMAPHORE|RTEMS_NO_INHERIT_PRIORITY|RTEMS_LOCAL|RTEMS_NO_PRIORITY_CEILING, |
---|
658 | 0, |
---|
659 | &brm->tx_sem) != RTEMS_SUCCESSFUL ){ |
---|
660 | printk("BRM: Failed to create tx semaphore\n"); |
---|
661 | return RTEMS_INTERNAL_ERROR; |
---|
662 | } |
---|
663 | |
---|
664 | /* Device Semaphore created with count = 1 */ |
---|
665 | if ( rtems_semaphore_create(rtems_build_name('B', 'M', 'D', '0'+minor), |
---|
666 | 1, |
---|
667 | RTEMS_FIFO|RTEMS_SIMPLE_BINARY_SEMAPHORE|RTEMS_NO_INHERIT_PRIORITY|RTEMS_LOCAL|RTEMS_NO_PRIORITY_CEILING, |
---|
668 | 0, |
---|
669 | &brm->dev_sem) != RTEMS_SUCCESSFUL ){ |
---|
670 | printk("BRM: Failed to create device semaphore\n"); |
---|
671 | return RTEMS_INTERNAL_ERROR; |
---|
672 | } |
---|
673 | |
---|
674 | |
---|
675 | /* Set base address of all descriptors */ |
---|
676 | brm->memarea_base = (unsigned int)&mem[(128*1024) * minor]; |
---|
677 | brm->desc = (struct desc_table *) brm->memarea_base; |
---|
678 | brm->mem = (volatile unsigned short *) brm->memarea_base; |
---|
679 | brm->irq_log = (struct irq_log_list *)(brm->memarea_base + (0xFFE0<<1)); /* last 64byte */ |
---|
680 | |
---|
681 | brm->bm_event = NULL; |
---|
682 | brm->rt_event = NULL; |
---|
683 | |
---|
684 | /* Sel clock so that we can write to BRM's registers */ |
---|
685 | brm->regs->w_ctrl = (allbrm_cfg_clksel<<9) | (allbrm_cfg_clkdiv<<5); |
---|
686 | /* Reset BRM core */ |
---|
687 | brm->regs->w_ctrl = 1<<10 | READ_REG(&brm->regs->w_ctrl); |
---|
688 | |
---|
689 | /* Register interrupt handler */ |
---|
690 | B1553BRM_REG_INT(B1553BRM_PREFIX(_interrupt_handler), brm->irqno, brm); |
---|
691 | |
---|
692 | rt_init(brm); |
---|
693 | |
---|
694 | DBG("BRM: LOG: 0x%lx, 0x%lx\n\r",brm->log,brm); |
---|
695 | } |
---|
696 | |
---|
697 | /* save number of BRM cores found */ |
---|
698 | brm_cores = dev_cnt; |
---|
699 | |
---|
700 | DBG("BRM initialisation done.\n"); |
---|
701 | |
---|
702 | return RTEMS_SUCCESSFUL; |
---|
703 | } |
---|
704 | |
---|
705 | static rtems_device_driver brm_open(rtems_device_major_number major, rtems_device_minor_number minor, void *arg) { |
---|
706 | brm_priv *brm; |
---|
707 | |
---|
708 | FUNCDBG("brm_open\n"); |
---|
709 | |
---|
710 | if (minor >= brm_cores) { |
---|
711 | DBG("Wrong minor %d\n", minor); |
---|
712 | return RTEMS_UNSATISFIED; /* ENODEV */ |
---|
713 | } |
---|
714 | |
---|
715 | brm = &brms[minor]; |
---|
716 | |
---|
717 | if (rtems_semaphore_obtain(brm->dev_sem, RTEMS_NO_WAIT, RTEMS_NO_TIMEOUT) != RTEMS_SUCCESSFUL) { |
---|
718 | DBG("brm_open: resource in use\n"); |
---|
719 | return RTEMS_RESOURCE_IN_USE; /* EBUSY */ |
---|
720 | } |
---|
721 | |
---|
722 | /* Set defaults */ |
---|
723 | brm->event_id = 0; |
---|
724 | |
---|
725 | start_operation(brm); |
---|
726 | |
---|
727 | return RTEMS_SUCCESSFUL; |
---|
728 | } |
---|
729 | |
---|
730 | static rtems_device_driver brm_close(rtems_device_major_number major, rtems_device_minor_number minor, void *arg) |
---|
731 | { |
---|
732 | brm_priv *brm = &brms[minor]; |
---|
733 | FUNCDBG("brm_close"); |
---|
734 | |
---|
735 | stop_operation(brm); |
---|
736 | rtems_semaphore_release(brm->dev_sem); |
---|
737 | |
---|
738 | return RTEMS_SUCCESSFUL; |
---|
739 | } |
---|
740 | |
---|
741 | static int get_rt_messages(brm_priv *brm, void *buf, unsigned int msg_count) { |
---|
742 | |
---|
743 | struct rt_msg *dest = (struct rt_msg *) buf; |
---|
744 | int count = 0; |
---|
745 | |
---|
746 | if (brm->head == brm->tail) { |
---|
747 | return 0; |
---|
748 | } |
---|
749 | |
---|
750 | do { |
---|
751 | |
---|
752 | DBG("rt read - head: %d, tail: %d\n", brm->head, brm->tail); |
---|
753 | dest[count++] = brm->rt_event[INDEX(brm->tail++)]; |
---|
754 | |
---|
755 | } while (brm->head != brm->tail && count < msg_count); |
---|
756 | |
---|
757 | return count; |
---|
758 | |
---|
759 | } |
---|
760 | |
---|
761 | static int get_bm_messages(brm_priv *brm, void *buf, unsigned int msg_count) { |
---|
762 | |
---|
763 | struct bm_msg *dest = (struct bm_msg *) buf; |
---|
764 | int count = 0; |
---|
765 | |
---|
766 | if (brm->head == brm->tail) { |
---|
767 | return 0; |
---|
768 | } |
---|
769 | |
---|
770 | do { |
---|
771 | |
---|
772 | DBG("bm read - head: %d, tail: %d\n", brm->head, brm->tail); |
---|
773 | dest[count++] = brm->bm_event[INDEX(brm->tail++)]; |
---|
774 | |
---|
775 | } while (brm->head != brm->tail && count < msg_count); |
---|
776 | |
---|
777 | return count; |
---|
778 | |
---|
779 | } |
---|
780 | |
---|
781 | static rtems_device_driver brm_read(rtems_device_major_number major, rtems_device_minor_number minor, void *arg) |
---|
782 | { |
---|
783 | rtems_libio_rw_args_t *rw_args; |
---|
784 | int count = 0; |
---|
785 | brm_priv *brm = &brms[minor]; |
---|
786 | int (*get_messages)(brm_priv *brm, void *buf, unsigned int count); |
---|
787 | |
---|
788 | if ( ! (brm->mode & (BRM_MODE_RT | BRM_MODE_BM)) ){ |
---|
789 | return RTEMS_INVALID_NAME; |
---|
790 | } |
---|
791 | |
---|
792 | rw_args = (rtems_libio_rw_args_t *) arg; |
---|
793 | |
---|
794 | if ( ((READ_REG(&brm->regs->oper)>>8) & 3) == 1 ) { /* RT */ |
---|
795 | get_messages = get_rt_messages; |
---|
796 | } |
---|
797 | else { /* BM */ |
---|
798 | get_messages = get_bm_messages; |
---|
799 | } |
---|
800 | |
---|
801 | |
---|
802 | FUNCDBG("brm_read [%i,%i]: buf: 0x%x len: %i\n",major, minor, (unsigned int)rw_args->buffer,rw_args->count); |
---|
803 | |
---|
804 | while ( (count=get_messages(brm,rw_args->buffer, rw_args->count)) == 0 ) { |
---|
805 | |
---|
806 | if (brm->rx_blocking) { |
---|
807 | rtems_semaphore_obtain(brm->rx_sem, RTEMS_WAIT, RTEMS_NO_TIMEOUT); |
---|
808 | } |
---|
809 | else { |
---|
810 | /* Translates to EBUSY */ |
---|
811 | return RTEMS_RESOURCE_IN_USE; |
---|
812 | } |
---|
813 | |
---|
814 | } |
---|
815 | |
---|
816 | rw_args->bytes_moved = count; |
---|
817 | return RTEMS_SUCCESSFUL; |
---|
818 | |
---|
819 | } |
---|
820 | |
---|
821 | |
---|
822 | static rtems_device_driver brm_write(rtems_device_major_number major, rtems_device_minor_number minor, void *arg) |
---|
823 | { |
---|
824 | rtems_libio_rw_args_t *rw_args; |
---|
825 | struct rt_msg *source; |
---|
826 | unsigned int count=0, current, next, descriptor, wc, suba; |
---|
827 | brm_priv *brm = &brms[minor]; |
---|
828 | |
---|
829 | if ( ! (brm->mode & BRM_MODE_RT) ){ |
---|
830 | return RTEMS_INVALID_NAME; |
---|
831 | } |
---|
832 | |
---|
833 | rw_args = (rtems_libio_rw_args_t *) arg; |
---|
834 | source = (struct rt_msg *) rw_args->buffer; |
---|
835 | |
---|
836 | FUNCDBG("brm_write [%i,%i]: buf: 0x%x len: %i\n",major, minor, (unsigned int)rw_args->buffer,rw_args->count); |
---|
837 | |
---|
838 | do { |
---|
839 | |
---|
840 | descriptor = source[count].desc & 0x7F; |
---|
841 | suba = descriptor-32; |
---|
842 | wc = source[count].miw >> 11; |
---|
843 | wc = wc ? wc : 32; |
---|
844 | |
---|
845 | /* Only subaddress transmission is allowed with write */ |
---|
846 | if (descriptor < 32 || descriptor >= 64) |
---|
847 | return RTEMS_INVALID_NAME; |
---|
848 | |
---|
849 | current = brm->desc[descriptor].cur; |
---|
850 | next = brm->written[suba] + 2 + wc; |
---|
851 | |
---|
852 | if (brm->written[suba] < current) { |
---|
853 | |
---|
854 | if (next > current) { |
---|
855 | |
---|
856 | /* No room in transmission buffer */ |
---|
857 | |
---|
858 | if (brm->tx_blocking && count == 0) { |
---|
859 | rtems_semaphore_obtain(brm->tx_sem, RTEMS_WAIT, RTEMS_NO_TIMEOUT); |
---|
860 | } |
---|
861 | else if ( brm->tx_blocking && (count != 0) ){ |
---|
862 | /* return the number of messages sent so far */ |
---|
863 | break; |
---|
864 | } |
---|
865 | else { |
---|
866 | /* Translates to posix EBUSY */ |
---|
867 | return RTEMS_RESOURCE_IN_USE; |
---|
868 | } |
---|
869 | } |
---|
870 | } |
---|
871 | |
---|
872 | memcpy((void *)&brm->mem[brm->written[suba]], &source[count], (2+wc)*2); |
---|
873 | |
---|
874 | count++; |
---|
875 | |
---|
876 | if (next >= brm->desc[descriptor].bot) { |
---|
877 | next = brm->desc[descriptor].top; |
---|
878 | } |
---|
879 | brm->written[suba] = next; |
---|
880 | |
---|
881 | } while (count < rw_args->count); |
---|
882 | |
---|
883 | rw_args->bytes_moved = count; |
---|
884 | |
---|
885 | if (count >= 0) { |
---|
886 | return RTEMS_SUCCESSFUL; |
---|
887 | } |
---|
888 | return RTEMS_UNSATISFIED; |
---|
889 | } |
---|
890 | |
---|
891 | static rtems_device_driver brm_control(rtems_device_major_number major, rtems_device_minor_number minor, void *arg) |
---|
892 | { |
---|
893 | |
---|
894 | unsigned int i=0; |
---|
895 | unsigned short ctrl, oper, cw1, cw2; |
---|
896 | rtems_libio_ioctl_args_t *ioarg = (rtems_libio_ioctl_args_t *) arg; |
---|
897 | unsigned int *data = ioarg->buffer; |
---|
898 | struct bc_msg *cmd_list = (struct bc_msg *) ioarg->buffer; |
---|
899 | brm_priv *brm = &brms[minor]; |
---|
900 | rtems_device_driver ret; |
---|
901 | int len; |
---|
902 | |
---|
903 | FUNCDBG("brm_control[%d]: [%i,%i]\n",minor,major, minor); |
---|
904 | |
---|
905 | if (!ioarg) { |
---|
906 | DBG("brm_control: invalid argument\n"); |
---|
907 | return RTEMS_INVALID_NAME; |
---|
908 | } |
---|
909 | |
---|
910 | ioarg->ioctl_return = 0; |
---|
911 | switch(ioarg->command) { |
---|
912 | |
---|
913 | case BRM_SET_MODE: |
---|
914 | if ( data[0] > 2 ) |
---|
915 | return RTEMS_INVALID_NAME; |
---|
916 | stop_operation(brm); |
---|
917 | if (data[0] == 0) { |
---|
918 | ret = bc_init(brm); |
---|
919 | } |
---|
920 | else if (data[0] == 1) { |
---|
921 | ret = rt_init(brm); |
---|
922 | } |
---|
923 | else if (data[0] == 2) { |
---|
924 | ret = bm_init(brm); |
---|
925 | }else |
---|
926 | ret = RTEMS_INVALID_NAME; |
---|
927 | |
---|
928 | if ( ret != RTEMS_SUCCESSFUL) |
---|
929 | return ret; |
---|
930 | |
---|
931 | if ( brm->mode & (BRM_MODE_RT | BRM_MODE_BM ) ) |
---|
932 | start_operation(brm); |
---|
933 | break; |
---|
934 | |
---|
935 | case BRM_SET_BUS: |
---|
936 | stop_operation(brm); |
---|
937 | ctrl = READ_REG(&brm->regs->ctrl); |
---|
938 | ctrl &= 0xE7FF; /* Clear bit 12-11 ... */ |
---|
939 | ctrl |= (data[0]&0x3)<<11; /* ... OR in new bus status */ |
---|
940 | brm->regs->ctrl = ctrl; |
---|
941 | start_operation(brm); |
---|
942 | break; |
---|
943 | |
---|
944 | case BRM_SET_MSGTO: |
---|
945 | stop_operation(brm); |
---|
946 | ctrl = READ_REG(&brm->regs->ctrl); |
---|
947 | ctrl &= 0xFDFF; /* Clear bit 9 ... */ |
---|
948 | ctrl |= (data[0]&1)<<9; /* ... OR in new MSGTO */ |
---|
949 | brm->regs->ctrl = ctrl; |
---|
950 | start_operation(brm); |
---|
951 | break; |
---|
952 | |
---|
953 | case BRM_SET_RT_ADDR: |
---|
954 | stop_operation(brm); |
---|
955 | oper = READ_REG(&brm->regs->oper); |
---|
956 | oper &= 0x03FF; /* Clear bit 15-10 ... */ |
---|
957 | oper |= (data[0]&0x1f)<<11; /* ... OR in new address */ |
---|
958 | oper |= odd_parity(data[0]&0x1f)<<10; /* ... OR in parity */ |
---|
959 | brm->regs->oper = oper; |
---|
960 | start_operation(brm); |
---|
961 | break; |
---|
962 | |
---|
963 | case BRM_SET_STD: |
---|
964 | stop_operation(brm); |
---|
965 | ctrl = READ_REG(&brm->regs->ctrl); |
---|
966 | ctrl &= 0xFF7F; /* Clear bit 7 ... */ |
---|
967 | ctrl |= (data[0]&1)<<7; /* ... OR in new ABSTD (1=A) */ |
---|
968 | brm->regs->ctrl = ctrl; |
---|
969 | start_operation(brm); |
---|
970 | break; |
---|
971 | |
---|
972 | case BRM_SET_BCE: |
---|
973 | stop_operation(brm); |
---|
974 | ctrl = READ_REG(&brm->regs->ctrl); |
---|
975 | ctrl &= 0xFFEF; /* Clear bit 4 ... */ |
---|
976 | ctrl |= (data[0]&1)<<4; /* ... OR in new BCE */ |
---|
977 | brm->regs->ctrl = ctrl; |
---|
978 | start_operation(brm); |
---|
979 | break; |
---|
980 | |
---|
981 | case BRM_TX_BLOCK: |
---|
982 | brm->tx_blocking = data[0]; |
---|
983 | break; |
---|
984 | |
---|
985 | case BRM_RX_BLOCK: |
---|
986 | brm->rx_blocking = data[0]; |
---|
987 | break; |
---|
988 | |
---|
989 | case BRM_DO_LIST: |
---|
990 | |
---|
991 | if ( brm->mode != BRM_MODE_BC ){ |
---|
992 | return RTEMS_INVALID_NAME; |
---|
993 | } |
---|
994 | |
---|
995 | /* Check if we are bus controller */ |
---|
996 | if ( ((READ_REG(&brm->regs->oper)>>8) & 3) != 0 ) { |
---|
997 | return RTEMS_INVALID_NAME; |
---|
998 | } |
---|
999 | |
---|
1000 | /* Already processing list? */ |
---|
1001 | if (is_executing(brm)) { |
---|
1002 | return RTEMS_RESOURCE_IN_USE; |
---|
1003 | } |
---|
1004 | |
---|
1005 | /* clear any earlier releases */ |
---|
1006 | rtems_semaphore_obtain(brm->tx_sem, RTEMS_NO_WAIT, RTEMS_NO_TIMEOUT); |
---|
1007 | |
---|
1008 | brm->bc_list_fail = 0; |
---|
1009 | brm->cur_list = cmd_list; |
---|
1010 | brm->regs->dpoint = 0; |
---|
1011 | |
---|
1012 | i = 0; |
---|
1013 | while ( (cmd_list[i].ctrl & BC_EOL) == 0) { |
---|
1014 | |
---|
1015 | ctrl = (4<<12) | (((cmd_list[i].ctrl&BC_BUSA)==BC_BUSA)<<9) | (((cmd_list[i].ctrl&BC_RTRT)==BC_RTRT)<<8); |
---|
1016 | |
---|
1017 | if (cmd_list[i].ctrl&BC_RTRT) { |
---|
1018 | cw1 = (cmd_list[i].rtaddr[0]<<11) | (0<<10) | (cmd_list[i].subaddr[0]<<5) | (cmd_list[i].wc & 0x1f); /* receive cw */ |
---|
1019 | cw2 = (cmd_list[i].rtaddr[1]<<11) | (1<<10) | (cmd_list[i].subaddr[1]<<5) | (cmd_list[i].wc & 0x1f); /* transmit cw */ |
---|
1020 | } |
---|
1021 | else { |
---|
1022 | cw1 = (cmd_list[i].rtaddr[0]<<11) | (((cmd_list[i].ctrl&BC_TR)==BC_TR)<<10) | (cmd_list[i].subaddr[0]<<5) | (cmd_list[i].wc&0x1f); |
---|
1023 | cw2 = 0; |
---|
1024 | } |
---|
1025 | |
---|
1026 | |
---|
1027 | /* Set up command block */ |
---|
1028 | brm->bcmem->descs[i].ctrl = ctrl; |
---|
1029 | brm->bcmem->descs[i].cw1 = cw1; |
---|
1030 | brm->bcmem->descs[i].cw2 = cw2; |
---|
1031 | /* data pointer: |
---|
1032 | * (&brm->bcmem->msg_data[i].data[0] & 0x1ffff) / 2 |
---|
1033 | */ |
---|
1034 | brm->bcmem->descs[i].dptr = 1024+i*32; /* data pointer */ |
---|
1035 | brm->bcmem->descs[i].tsw[0] = 0; |
---|
1036 | brm->bcmem->descs[i].tsw[1] = 0; |
---|
1037 | brm->bcmem->descs[i].ba = 0; |
---|
1038 | brm->bcmem->descs[i].timer = 0; |
---|
1039 | |
---|
1040 | memcpy((void *)&brm->bcmem->msg_data[i].data[0], &cmd_list[i].data[0], cmd_list[i].wc*2); |
---|
1041 | |
---|
1042 | i++; |
---|
1043 | } |
---|
1044 | |
---|
1045 | brm->bcmem->descs[i].ctrl = 0; /* end of list */ |
---|
1046 | |
---|
1047 | start_operation(brm); |
---|
1048 | |
---|
1049 | break; |
---|
1050 | |
---|
1051 | case BRM_LIST_DONE: |
---|
1052 | |
---|
1053 | if ( brm->mode != BRM_MODE_BC ){ |
---|
1054 | return RTEMS_INVALID_NAME; |
---|
1055 | } |
---|
1056 | |
---|
1057 | /* Check if we are bus controller */ |
---|
1058 | if ( ((READ_REG(&brm->regs->oper)>>8) & 3) != 0 ) { |
---|
1059 | return RTEMS_INVALID_NAME; |
---|
1060 | } |
---|
1061 | |
---|
1062 | if (is_executing(brm)) { |
---|
1063 | |
---|
1064 | data[0] = 0; |
---|
1065 | if (brm->tx_blocking) { |
---|
1066 | rtems_semaphore_obtain(brm->tx_sem, RTEMS_WAIT, RTEMS_NO_TIMEOUT); |
---|
1067 | data[0] = 1; |
---|
1068 | if ( brm->bc_list_fail ){ |
---|
1069 | return RTEMS_INVALID_NAME; |
---|
1070 | } |
---|
1071 | }else{ |
---|
1072 | return RTEMS_RESOURCE_IN_USE; |
---|
1073 | } |
---|
1074 | |
---|
1075 | |
---|
1076 | } |
---|
1077 | else { |
---|
1078 | data[0] = 1; /* done */ |
---|
1079 | } |
---|
1080 | |
---|
1081 | /* copy finished list results back into bc_msg array */ |
---|
1082 | i = 0; |
---|
1083 | while ( (brm->cur_list[i].ctrl & BC_EOL) == 0) { |
---|
1084 | |
---|
1085 | if (READ_DMA(&brm->bcmem->descs[i].ctrl) & 1) { |
---|
1086 | brm->cur_list[i].ctrl |= 0x8000; /* Set BAME */ |
---|
1087 | } |
---|
1088 | if (brm->cur_list[i].ctrl & BC_TR) { |
---|
1089 | /* RT Transmit command, copy received data */ |
---|
1090 | len = brm->cur_list[i].wc; |
---|
1091 | while( len-- > 0){ |
---|
1092 | brm->cur_list[i].data[len] = READ_DMA(&brm->bcmem->msg_data[i].data[len]); |
---|
1093 | } |
---|
1094 | } |
---|
1095 | brm->cur_list[i].tsw[0] = READ_DMA(&brm->bcmem->descs[i].tsw[0]); |
---|
1096 | brm->cur_list[i].tsw[1] = READ_DMA(&brm->bcmem->descs[i].tsw[1]); |
---|
1097 | |
---|
1098 | i++; |
---|
1099 | } |
---|
1100 | break; |
---|
1101 | |
---|
1102 | |
---|
1103 | case BRM_CLR_STATUS: |
---|
1104 | brm->status = 0; |
---|
1105 | break; |
---|
1106 | |
---|
1107 | case BRM_GET_STATUS: /* copy status */ |
---|
1108 | |
---|
1109 | if ( !ioarg->buffer ) |
---|
1110 | return RTEMS_INVALID_NAME; |
---|
1111 | |
---|
1112 | *(unsigned int *)ioarg->buffer = brm->status; |
---|
1113 | break; |
---|
1114 | |
---|
1115 | case BRM_SET_EVENTID: |
---|
1116 | brm->event_id = (rtems_id)ioarg->buffer; |
---|
1117 | break; |
---|
1118 | |
---|
1119 | default: |
---|
1120 | return RTEMS_NOT_DEFINED; |
---|
1121 | } |
---|
1122 | return RTEMS_SUCCESSFUL; |
---|
1123 | } |
---|
1124 | |
---|
1125 | #ifdef B1553BRM_DEFINE_INTHANDLER |
---|
1126 | static void b1553brm_interrupt_handler(rtems_vector_number v){ |
---|
1127 | int i; |
---|
1128 | /* find minor */ |
---|
1129 | for(i=0; i<brm_cores; i++){ |
---|
1130 | if ( (brms[i].irqno+0x10) == v ){ |
---|
1131 | brm_interrupt(&brms[i]); |
---|
1132 | return; |
---|
1133 | } |
---|
1134 | } |
---|
1135 | } |
---|
1136 | #endif |
---|
1137 | |
---|
1138 | static void brm_interrupt(brm_priv *brm) { |
---|
1139 | unsigned short descriptor, current, pending, miw, wc, tmp; |
---|
1140 | unsigned short msgadr, iaw, iiw; |
---|
1141 | int len; |
---|
1142 | int signal_event=0; |
---|
1143 | unsigned int event_status=0; |
---|
1144 | #define SET_ERROR_DESCRIPTOR(descriptor) (event_status = (event_status & 0x0000ffff) | descriptor<<16) |
---|
1145 | |
---|
1146 | while( (iiw=READ_REG(&brm->irq_log[brm->irq].iiw)) != 0xffff ){ |
---|
1147 | iaw=READ_REG(&brm->irq_log[brm->irq].iaw); |
---|
1148 | |
---|
1149 | /* indicate that the interrupt log entry has been processed */ |
---|
1150 | brm->irq_log[brm->irq].iiw = 0xffff; |
---|
1151 | |
---|
1152 | /* Interpret interrupt log entry */ |
---|
1153 | descriptor = iaw >> 2; |
---|
1154 | pending = iiw; |
---|
1155 | brm->irq = (brm->irq + 1) % 16; |
---|
1156 | |
---|
1157 | /* Clear the log so that we */ |
---|
1158 | |
---|
1159 | |
---|
1160 | /* Subaddress accessed irq (RT only) |
---|
1161 | * |
---|
1162 | * Can be either a receive or transmit command |
---|
1163 | * as well as a mode code. |
---|
1164 | */ |
---|
1165 | if (pending & BRM_SUBAD_IRQ) { |
---|
1166 | |
---|
1167 | /* Pointer to next free message in circular buffer */ |
---|
1168 | current = READ_DMA(&brm->desc[descriptor].cur); |
---|
1169 | |
---|
1170 | while ( (msgadr=brm->last_read[descriptor]) != current) { |
---|
1171 | |
---|
1172 | /* Get word count */ |
---|
1173 | miw = READ_DMA(&brm->mem[msgadr]); |
---|
1174 | wc = miw >> 11; |
---|
1175 | |
---|
1176 | /* Data received */ |
---|
1177 | if (descriptor < 32) { |
---|
1178 | wc = wc ? wc : 32; |
---|
1179 | } |
---|
1180 | /* Data transmitted */ |
---|
1181 | else if (descriptor < 64) { |
---|
1182 | wc = wc ? wc : 32; |
---|
1183 | rtems_semaphore_release(brm->tx_sem); |
---|
1184 | } |
---|
1185 | /* RX Mode code */ |
---|
1186 | else if (descriptor < 96) { |
---|
1187 | wc = (wc>>4); |
---|
1188 | } |
---|
1189 | /* TX Mode code */ |
---|
1190 | else if (descriptor < 128) { |
---|
1191 | wc = (wc>>4); |
---|
1192 | } |
---|
1193 | |
---|
1194 | #ifdef DEBUG |
---|
1195 | brm->log[brm->log_i++ % EVENT_QUEUE_SIZE] = (descriptor << 16) | wc; |
---|
1196 | brm->log[brm->log_i++ % EVENT_QUEUE_SIZE] = current; |
---|
1197 | brm->log[brm->log_i++ % EVENT_QUEUE_SIZE] = msgadr; |
---|
1198 | #endif |
---|
1199 | |
---|
1200 | /* If there is room in the event queue, copy the event there */ |
---|
1201 | if (brm->head - brm->tail != EVENT_QUEUE_SIZE) { |
---|
1202 | |
---|
1203 | /* Copy to event queue */ |
---|
1204 | brm->rt_event[INDEX(brm->head)].miw = READ_DMA(&brm->mem[msgadr]); |
---|
1205 | brm->rt_event[INDEX(brm->head)].time = READ_DMA(&brm->mem[msgadr+1]); |
---|
1206 | len = wc; |
---|
1207 | while( len-- > 0){ |
---|
1208 | brm->rt_event[INDEX(brm->head)].data[len] = READ_DMA(&brm->mem[msgadr+2+len]); |
---|
1209 | } |
---|
1210 | brm->rt_event[INDEX(brm->head)].desc = descriptor; |
---|
1211 | brm->head++; |
---|
1212 | |
---|
1213 | } |
---|
1214 | else { |
---|
1215 | /* Indicate overrun */ |
---|
1216 | brm->rt_event[INDEX(brm->head)].desc |= 0x8000; |
---|
1217 | } |
---|
1218 | |
---|
1219 | msgadr += (2+wc); |
---|
1220 | |
---|
1221 | if (msgadr >= brm->desc[descriptor].bot) { |
---|
1222 | msgadr = brm->desc[descriptor].top; |
---|
1223 | } |
---|
1224 | brm->last_read[descriptor] = msgadr; |
---|
1225 | |
---|
1226 | #ifdef DEBUG |
---|
1227 | brm->log[brm->log_i++ % EVENT_QUEUE_SIZE] = msgadr; |
---|
1228 | #endif |
---|
1229 | |
---|
1230 | /* Wake any blocked rx thread */ |
---|
1231 | rtems_semaphore_release(brm->rx_sem); |
---|
1232 | |
---|
1233 | } |
---|
1234 | |
---|
1235 | } |
---|
1236 | |
---|
1237 | if (pending & BRM_EOL_IRQ) { |
---|
1238 | rtems_semaphore_release(brm->tx_sem); |
---|
1239 | } |
---|
1240 | |
---|
1241 | if (pending & BRM_BC_ILLCMD_IRQ) { |
---|
1242 | brm->bc_list_fail = 1; |
---|
1243 | rtems_semaphore_release(brm->tx_sem); |
---|
1244 | SET_ERROR_DESCRIPTOR(descriptor); |
---|
1245 | FUNCDBG("BRM: ILLCMD IRQ\n\r"); |
---|
1246 | } |
---|
1247 | |
---|
1248 | /* Monitor irq */ |
---|
1249 | if (pending & BRM_MBC_IRQ) { |
---|
1250 | |
---|
1251 | stop_operation(brm); |
---|
1252 | brm->regs->mbc = 1; |
---|
1253 | start_operation(brm); |
---|
1254 | |
---|
1255 | /* If there is room in the event queue, copy the event there */ |
---|
1256 | if (brm->head - brm->tail != EVENT_QUEUE_SIZE) { |
---|
1257 | |
---|
1258 | /* Copy to event queue */ |
---|
1259 | |
---|
1260 | brm->bm_event[INDEX(brm->head)].miw = READ_DMA(&brm->mem[0]); |
---|
1261 | brm->bm_event[INDEX(brm->head)].cw1 = READ_DMA(&brm->mem[1]); |
---|
1262 | brm->bm_event[INDEX(brm->head)].cw2 = READ_DMA(&brm->mem[2]); |
---|
1263 | brm->bm_event[INDEX(brm->head)].sw1 = READ_DMA(&brm->mem[4]); |
---|
1264 | brm->bm_event[INDEX(brm->head)].sw2 = READ_DMA(&brm->mem[5]); |
---|
1265 | brm->bm_event[INDEX(brm->head)].time = READ_DMA(&brm->mem[6]); |
---|
1266 | |
---|
1267 | len = 32; |
---|
1268 | while ( len-- ){ |
---|
1269 | brm->bm_event[INDEX(brm->head)].data[len] = READ_DMA(&brm->mem[0x100+len]); |
---|
1270 | len--; |
---|
1271 | brm->bm_event[INDEX(brm->head)].data[len] = READ_DMA(&brm->mem[0x100+len]); |
---|
1272 | len--; |
---|
1273 | brm->bm_event[INDEX(brm->head)].data[len] = READ_DMA(&brm->mem[0x100+len]); |
---|
1274 | len--; |
---|
1275 | brm->bm_event[INDEX(brm->head)].data[len] = READ_DMA(&brm->mem[0x100+len]); |
---|
1276 | } |
---|
1277 | /* memcpy((void *)brm->bm_event[INDEX(brm->head)].data, &brm->mem[0x100], 32);*/ |
---|
1278 | |
---|
1279 | #ifdef DEBUG |
---|
1280 | brm->log[brm->log_i++ % EVENT_QUEUE_SIZE] = READ_REG(&brm->regs->mbc); |
---|
1281 | brm->log[brm->log_i++ % EVENT_QUEUE_SIZE] = READ_DMA(&brm->mem[0]); |
---|
1282 | brm->log[brm->log_i++ % EVENT_QUEUE_SIZE] = READ_DMA(&brm->mem[1]); |
---|
1283 | brm->log[brm->log_i++ % EVENT_QUEUE_SIZE] = READ_DMA(&brm->mem[4]); |
---|
1284 | #endif |
---|
1285 | |
---|
1286 | brm->head++; |
---|
1287 | |
---|
1288 | } |
---|
1289 | else { |
---|
1290 | /* Indicate overrun */ |
---|
1291 | brm->rt_event[INDEX(brm->head)].miw |= 0x8000; |
---|
1292 | } |
---|
1293 | |
---|
1294 | /* Wake any blocking thread */ |
---|
1295 | rtems_semaphore_release(brm->rx_sem); |
---|
1296 | |
---|
1297 | } |
---|
1298 | |
---|
1299 | /* The reset of the interrupts |
---|
1300 | * cause a event to be signalled |
---|
1301 | * so that user can handle error. |
---|
1302 | */ |
---|
1303 | if ( pending & BRM_RT_ILLCMD_IRQ){ |
---|
1304 | FUNCDBG("BRM: BRM_RT_ILLCMD_IRQ\n\r"); |
---|
1305 | brm->status |= BRM_RT_ILLCMD_IRQ; |
---|
1306 | event_status |= BRM_RT_ILLCMD_IRQ; |
---|
1307 | SET_ERROR_DESCRIPTOR(descriptor); |
---|
1308 | signal_event=1; |
---|
1309 | } |
---|
1310 | |
---|
1311 | if ( pending & BRM_ILLOP_IRQ){ |
---|
1312 | FUNCDBG("BRM: BRM_ILLOP_IRQ\n\r"); |
---|
1313 | brm->bc_list_fail = 1; |
---|
1314 | rtems_semaphore_release(brm->tx_sem); |
---|
1315 | event_status |= BRM_ILLOP_IRQ; |
---|
1316 | SET_ERROR_DESCRIPTOR(descriptor); |
---|
1317 | signal_event=1; |
---|
1318 | } |
---|
1319 | |
---|
1320 | if ( pending & BRM_MERR_IRQ){ |
---|
1321 | FUNCDBG("BRM: BRM_MERR_IRQ\n\r"); |
---|
1322 | event_status |= BRM_MERR_IRQ; |
---|
1323 | SET_ERROR_DESCRIPTOR(descriptor); |
---|
1324 | signal_event=1; |
---|
1325 | } |
---|
1326 | /* Clear Block Accessed Bit */ |
---|
1327 | tmp = READ_REG(&brm->desc[descriptor].ctrl); |
---|
1328 | brm->desc[descriptor].ctrl = tmp & ~0x10; |
---|
1329 | |
---|
1330 | } /* While */ |
---|
1331 | |
---|
1332 | /* clear interrupt flags & handle Hardware errors */ |
---|
1333 | pending = READ_REG(&brm->regs->ipend); |
---|
1334 | |
---|
1335 | if ( pending & BRM_DMAF_IRQ){ |
---|
1336 | FUNCDBG("BRM: BRM_DMAF_IRQ\n\r"); |
---|
1337 | event_status |= BRM_DMAF_IRQ; |
---|
1338 | signal_event=1; |
---|
1339 | } |
---|
1340 | |
---|
1341 | if ( pending & BRM_WRAPF_IRQ){ |
---|
1342 | FUNCDBG("BRM: BRM_WRAPF_IRQ\n\r"); |
---|
1343 | event_status |= BRM_WRAPF_IRQ; |
---|
1344 | signal_event=1; |
---|
1345 | } |
---|
1346 | |
---|
1347 | if ( pending & BRM_TAPF_IRQ){ |
---|
1348 | FUNCDBG("BRM: BRM_TAPF_IRQ\n\r"); |
---|
1349 | event_status |= BRM_TAPF_IRQ; |
---|
1350 | signal_event=1; |
---|
1351 | } |
---|
1352 | |
---|
1353 | /* Copy current mask to status mask */ |
---|
1354 | if ( event_status ){ |
---|
1355 | if ( event_status & 0xffff0000 ) |
---|
1356 | brm->status &= 0x0000ffff; |
---|
1357 | brm->status |= event_status; |
---|
1358 | } |
---|
1359 | |
---|
1360 | /* signal event once */ |
---|
1361 | if ( signal_event && (brm->event_id!=0) ){ |
---|
1362 | rtems_event_send(brm->event_id, event_status); |
---|
1363 | } |
---|
1364 | |
---|
1365 | } |
---|