1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23#include <linux/interrupt.h>
24#include <linux/pci.h>
25#include <linux/firmware.h>
26#include <linux/vmalloc.h>
27#include <linux/slab.h>
28#include <linux/module.h>
29#include <linux/io.h>
30#include <sound/core.h>
31#include "mixart.h"
32#include "mixart_mixer.h"
33#include "mixart_core.h"
34#include "mixart_hwdep.h"
35
36
37
38
39
40
41
42
43
44
45
46static int mixart_wait_nice_for_register_value(struct mixart_mgr *mgr,
47 u32 offset, int is_egal,
48 u32 value, unsigned long timeout)
49{
50 unsigned long end_time = jiffies + (timeout * HZ / 100);
51 u32 read;
52
53 do {
54
55
56 cond_resched();
57
58 read = readl_be( MIXART_MEM( mgr, offset ));
59 if(is_egal) {
60 if(read == value) return 0;
61 }
62 else {
63 if(read != value) return 0;
64 }
65 } while ( time_after_eq(end_time, jiffies) );
66
67 return -EBUSY;
68}
69
70
71
72
73
74struct snd_mixart_elf32_ehdr {
75 u8 e_ident[16];
76 __be16 e_type;
77 __be16 e_machine;
78 __be32 e_version;
79 __be32 e_entry;
80 __be32 e_phoff;
81 __be32 e_shoff;
82 __be32 e_flags;
83 __be16 e_ehsize;
84 __be16 e_phentsize;
85 __be16 e_phnum;
86 __be16 e_shentsize;
87 __be16 e_shnum;
88 __be16 e_shstrndx;
89};
90
91struct snd_mixart_elf32_phdr {
92 __be32 p_type;
93 __be32 p_offset;
94 __be32 p_vaddr;
95 __be32 p_paddr;
96 __be32 p_filesz;
97 __be32 p_memsz;
98 __be32 p_flags;
99 __be32 p_align;
100};
101
102static int mixart_load_elf(struct mixart_mgr *mgr, const struct firmware *dsp )
103{
104 char elf32_magic_number[4] = {0x7f,'E','L','F'};
105 struct snd_mixart_elf32_ehdr *elf_header;
106 int i;
107
108 elf_header = (struct snd_mixart_elf32_ehdr *)dsp->data;
109 for( i=0; i<4; i++ )
110 if ( elf32_magic_number[i] != elf_header->e_ident[i] )
111 return -EINVAL;
112
113 if( elf_header->e_phoff != 0 ) {
114 struct snd_mixart_elf32_phdr elf_programheader;
115
116 for( i=0; i < be16_to_cpu(elf_header->e_phnum); i++ ) {
117 u32 pos = be32_to_cpu(elf_header->e_phoff) + (u32)(i * be16_to_cpu(elf_header->e_phentsize));
118
119 memcpy( &elf_programheader, dsp->data + pos, sizeof(elf_programheader) );
120
121 if(elf_programheader.p_type != 0) {
122 if( elf_programheader.p_filesz != 0 ) {
123 memcpy_toio( MIXART_MEM( mgr, be32_to_cpu(elf_programheader.p_vaddr)),
124 dsp->data + be32_to_cpu( elf_programheader.p_offset ),
125 be32_to_cpu( elf_programheader.p_filesz ));
126 }
127 }
128 }
129 }
130 return 0;
131}
132
133
134
135
136
137
138#define MIXART_FIRST_ANA_AUDIO_ID 0
139#define MIXART_FIRST_DIG_AUDIO_ID 8
140
141static int mixart_enum_connectors(struct mixart_mgr *mgr)
142{
143 u32 k;
144 int err;
145 struct mixart_msg request;
146 struct mixart_enum_connector_resp *connector;
147 struct mixart_audio_info_req *audio_info_req;
148 struct mixart_audio_info_resp *audio_info;
149
150 connector = kmalloc(sizeof(*connector), GFP_KERNEL);
151 audio_info_req = kmalloc(sizeof(*audio_info_req), GFP_KERNEL);
152 audio_info = kmalloc(sizeof(*audio_info), GFP_KERNEL);
153 if (! connector || ! audio_info_req || ! audio_info) {
154 err = -ENOMEM;
155 goto __error;
156 }
157
158 audio_info_req->line_max_level = MIXART_FLOAT_P_22_0_TO_HEX;
159 audio_info_req->micro_max_level = MIXART_FLOAT_M_20_0_TO_HEX;
160 audio_info_req->cd_max_level = MIXART_FLOAT____0_0_TO_HEX;
161
162 request.message_id = MSG_SYSTEM_ENUM_PLAY_CONNECTOR;
163 request.uid = (struct mixart_uid){0,0};
164 request.data = NULL;
165 request.size = 0;
166
167 err = snd_mixart_send_msg(mgr, &request, sizeof(*connector), connector);
168 if((err < 0) || (connector->error_code) || (connector->uid_count > MIXART_MAX_PHYS_CONNECTORS)) {
169 dev_err(&mgr->pci->dev,
170 "error MSG_SYSTEM_ENUM_PLAY_CONNECTOR\n");
171 err = -EINVAL;
172 goto __error;
173 }
174
175 for(k=0; k < connector->uid_count; k++) {
176 struct mixart_pipe *pipe;
177
178 if(k < MIXART_FIRST_DIG_AUDIO_ID) {
179 pipe = &mgr->chip[k/2]->pipe_out_ana;
180 } else {
181 pipe = &mgr->chip[(k-MIXART_FIRST_DIG_AUDIO_ID)/2]->pipe_out_dig;
182 }
183 if(k & 1) {
184 pipe->uid_right_connector = connector->uid[k];
185 } else {
186 pipe->uid_left_connector = connector->uid[k];
187 }
188
189
190
191
192 request.message_id = MSG_CONNECTOR_GET_AUDIO_INFO;
193 request.uid = connector->uid[k];
194 request.data = audio_info_req;
195 request.size = sizeof(*audio_info_req);
196
197 err = snd_mixart_send_msg(mgr, &request, sizeof(*audio_info), audio_info);
198 if( err < 0 ) {
199 dev_err(&mgr->pci->dev,
200 "error MSG_CONNECTOR_GET_AUDIO_INFO\n");
201 goto __error;
202 }
203
204 }
205
206 request.message_id = MSG_SYSTEM_ENUM_RECORD_CONNECTOR;
207 request.uid = (struct mixart_uid){0,0};
208 request.data = NULL;
209 request.size = 0;
210
211 err = snd_mixart_send_msg(mgr, &request, sizeof(*connector), connector);
212 if((err < 0) || (connector->error_code) || (connector->uid_count > MIXART_MAX_PHYS_CONNECTORS)) {
213 dev_err(&mgr->pci->dev,
214 "error MSG_SYSTEM_ENUM_RECORD_CONNECTOR\n");
215 err = -EINVAL;
216 goto __error;
217 }
218
219 for(k=0; k < connector->uid_count; k++) {
220 struct mixart_pipe *pipe;
221
222 if(k < MIXART_FIRST_DIG_AUDIO_ID) {
223 pipe = &mgr->chip[k/2]->pipe_in_ana;
224 } else {
225 pipe = &mgr->chip[(k-MIXART_FIRST_DIG_AUDIO_ID)/2]->pipe_in_dig;
226 }
227 if(k & 1) {
228 pipe->uid_right_connector = connector->uid[k];
229 } else {
230 pipe->uid_left_connector = connector->uid[k];
231 }
232
233
234
235
236 request.message_id = MSG_CONNECTOR_GET_AUDIO_INFO;
237 request.uid = connector->uid[k];
238 request.data = audio_info_req;
239 request.size = sizeof(*audio_info_req);
240
241 err = snd_mixart_send_msg(mgr, &request, sizeof(*audio_info), audio_info);
242 if( err < 0 ) {
243 dev_err(&mgr->pci->dev,
244 "error MSG_CONNECTOR_GET_AUDIO_INFO\n");
245 goto __error;
246 }
247
248 }
249 err = 0;
250
251 __error:
252 kfree(connector);
253 kfree(audio_info_req);
254 kfree(audio_info);
255
256 return err;
257}
258
259static int mixart_enum_physio(struct mixart_mgr *mgr)
260{
261 u32 k;
262 int err;
263 struct mixart_msg request;
264 struct mixart_uid get_console_mgr;
265 struct mixart_return_uid console_mgr;
266 struct mixart_uid_enumeration phys_io;
267
268
269 get_console_mgr.object_id = 0;
270 get_console_mgr.desc = MSG_CONSOLE_MANAGER | 0;
271
272 request.message_id = MSG_CONSOLE_GET_CLOCK_UID;
273 request.uid = get_console_mgr;
274 request.data = &get_console_mgr;
275 request.size = sizeof(get_console_mgr);
276
277 err = snd_mixart_send_msg(mgr, &request, sizeof(console_mgr), &console_mgr);
278
279 if( (err < 0) || (console_mgr.error_code != 0) ) {
280 dev_dbg(&mgr->pci->dev,
281 "error MSG_CONSOLE_GET_CLOCK_UID : err=%x\n",
282 console_mgr.error_code);
283 return -EINVAL;
284 }
285
286
287 mgr->uid_console_manager = console_mgr.uid;
288
289 request.message_id = MSG_SYSTEM_ENUM_PHYSICAL_IO;
290 request.uid = (struct mixart_uid){0,0};
291 request.data = &console_mgr.uid;
292 request.size = sizeof(console_mgr.uid);
293
294 err = snd_mixart_send_msg(mgr, &request, sizeof(phys_io), &phys_io);
295 if( (err < 0) || ( phys_io.error_code != 0 ) ) {
296 dev_err(&mgr->pci->dev,
297 "error MSG_SYSTEM_ENUM_PHYSICAL_IO err(%x) error_code(%x)\n",
298 err, phys_io.error_code);
299 return -EINVAL;
300 }
301
302
303 if (phys_io.nb_uid < MIXART_MAX_CARDS * 2)
304 return -EINVAL;
305
306 for(k=0; k<mgr->num_cards; k++) {
307 mgr->chip[k]->uid_in_analog_physio = phys_io.uid[k];
308 mgr->chip[k]->uid_out_analog_physio = phys_io.uid[phys_io.nb_uid/2 + k];
309 }
310
311 return 0;
312}
313
314
315static int mixart_first_init(struct mixart_mgr *mgr)
316{
317 u32 k;
318 int err;
319 struct mixart_msg request;
320
321 if((err = mixart_enum_connectors(mgr)) < 0) return err;
322
323 if((err = mixart_enum_physio(mgr)) < 0) return err;
324
325
326
327 request.message_id = MSG_SYSTEM_SEND_SYNCHRO_CMD;
328 request.uid = (struct mixart_uid){0,0};
329 request.data = NULL;
330 request.size = 0;
331
332 err = snd_mixart_send_msg(mgr, &request, sizeof(k), &k);
333 if( (err < 0) || (k != 0) ) {
334 dev_err(&mgr->pci->dev, "error MSG_SYSTEM_SEND_SYNCHRO_CMD\n");
335 return err == 0 ? -EINVAL : err;
336 }
337
338 return 0;
339}
340
341
342
343#define MIXART_MOTHERBOARD_XLX_BASE_ADDRESS 0x00600000
344
345static int mixart_dsp_load(struct mixart_mgr* mgr, int index, const struct firmware *dsp)
346{
347 int err, card_index;
348 u32 status_xilinx, status_elf, status_daught;
349 u32 val;
350
351
352 status_xilinx = readl_be( MIXART_MEM( mgr,MIXART_PSEUDOREG_MXLX_STATUS_OFFSET ));
353
354 status_elf = readl_be( MIXART_MEM( mgr,MIXART_PSEUDOREG_ELF_STATUS_OFFSET ));
355
356 status_daught = readl_be( MIXART_MEM( mgr,MIXART_PSEUDOREG_DXLX_STATUS_OFFSET ));
357
358
359 if (status_xilinx == 5) {
360 dev_err(&mgr->pci->dev, "miXart is resetting !\n");
361 return -EAGAIN;
362 }
363
364 switch (index) {
365 case MIXART_MOTHERBOARD_XLX_INDEX:
366
367
368 if (status_xilinx == 4) {
369 dev_dbg(&mgr->pci->dev, "xilinx is already loaded !\n");
370 return 0;
371 }
372
373 if (status_xilinx != 0) {
374 dev_err(&mgr->pci->dev,
375 "xilinx load error ! status = %d\n",
376 status_xilinx);
377 return -EIO;
378 }
379
380
381 if (((u32*)(dsp->data))[0] == 0xffffffff)
382 return -EINVAL;
383 if (dsp->size % 4)
384 return -EINVAL;
385
386
387 writel_be( 1, MIXART_MEM( mgr, MIXART_PSEUDOREG_MXLX_STATUS_OFFSET ));
388
389
390 writel_be( MIXART_MOTHERBOARD_XLX_BASE_ADDRESS, MIXART_MEM( mgr,MIXART_PSEUDOREG_MXLX_BASE_ADDR_OFFSET ));
391
392 writel_be( dsp->size, MIXART_MEM( mgr, MIXART_PSEUDOREG_MXLX_SIZE_OFFSET ));
393
394
395 memcpy_toio( MIXART_MEM( mgr, MIXART_MOTHERBOARD_XLX_BASE_ADDRESS), dsp->data, dsp->size);
396
397
398 writel_be( 2, MIXART_MEM( mgr, MIXART_PSEUDOREG_MXLX_STATUS_OFFSET ));
399
400
401 return 0;
402
403 case MIXART_MOTHERBOARD_ELF_INDEX:
404
405 if (status_elf == 4) {
406 dev_dbg(&mgr->pci->dev, "elf file already loaded !\n");
407 return 0;
408 }
409
410
411 if (status_elf != 0) {
412 dev_err(&mgr->pci->dev,
413 "elf load error ! status = %d\n",
414 status_elf);
415 return -EIO;
416 }
417
418
419 err = mixart_wait_nice_for_register_value( mgr, MIXART_PSEUDOREG_MXLX_STATUS_OFFSET, 1, 4, 500);
420 if (err < 0) {
421 dev_err(&mgr->pci->dev, "xilinx was not loaded or "
422 "could not be started\n");
423 return err;
424 }
425
426
427 writel_be( 0, MIXART_MEM( mgr, MIXART_PSEUDOREG_BOARDNUMBER ) );
428 writel_be( 0, MIXART_MEM( mgr, MIXART_FLOWTABLE_PTR ) );
429
430
431 writel_be( 1, MIXART_MEM( mgr, MIXART_PSEUDOREG_ELF_STATUS_OFFSET ));
432
433
434 err = mixart_load_elf( mgr, dsp );
435 if (err < 0) return err;
436
437
438 writel_be( 2, MIXART_MEM( mgr, MIXART_PSEUDOREG_ELF_STATUS_OFFSET ));
439
440
441 err = mixart_wait_nice_for_register_value( mgr, MIXART_PSEUDOREG_ELF_STATUS_OFFSET, 1, 4, 300);
442 if (err < 0) {
443 dev_err(&mgr->pci->dev, "elf could not be started\n");
444 return err;
445 }
446
447
448 writel_be( (u32)mgr->flowinfo.addr, MIXART_MEM( mgr, MIXART_FLOWTABLE_PTR ) );
449
450 return 0;
451
452 case MIXART_AESEBUBOARD_XLX_INDEX:
453 default:
454
455
456 if (status_elf != 4 || status_xilinx != 4) {
457 dev_err(&mgr->pci->dev, "xilinx or elf not "
458 "successfully loaded\n");
459 return -EIO;
460 }
461
462
463 err = mixart_wait_nice_for_register_value( mgr, MIXART_PSEUDOREG_DBRD_PRESENCE_OFFSET, 0, 0, 30);
464 if (err < 0) {
465 dev_err(&mgr->pci->dev, "error starting elf file\n");
466 return err;
467 }
468
469
470 mgr->board_type = (DAUGHTER_TYPE_MASK & readl_be( MIXART_MEM( mgr, MIXART_PSEUDOREG_DBRD_TYPE_OFFSET)));
471
472 if (mgr->board_type == MIXART_DAUGHTER_TYPE_NONE)
473 break;
474
475
476 if (mgr->board_type != MIXART_DAUGHTER_TYPE_AES )
477 return -EINVAL;
478
479
480 if (status_daught != 0) {
481 dev_err(&mgr->pci->dev,
482 "daughter load error ! status = %d\n",
483 status_daught);
484 return -EIO;
485 }
486
487
488 if (((u32*)(dsp->data))[0] == 0xffffffff)
489 return -EINVAL;
490 if (dsp->size % 4)
491 return -EINVAL;
492
493
494 writel_be( dsp->size, MIXART_MEM( mgr, MIXART_PSEUDOREG_DXLX_SIZE_OFFSET ));
495
496
497 writel_be( 1, MIXART_MEM( mgr, MIXART_PSEUDOREG_DXLX_STATUS_OFFSET ));
498
499
500 err = mixart_wait_nice_for_register_value( mgr, MIXART_PSEUDOREG_DXLX_STATUS_OFFSET, 1, 2, 30);
501 if (err < 0) {
502 dev_err(&mgr->pci->dev, "daughter board load error\n");
503 return err;
504 }
505
506
507 val = readl_be( MIXART_MEM( mgr, MIXART_PSEUDOREG_DXLX_BASE_ADDR_OFFSET ));
508 if (!val)
509 return -EINVAL;
510
511
512 memcpy_toio( MIXART_MEM( mgr, val), dsp->data, dsp->size);
513
514
515 writel_be( 4, MIXART_MEM( mgr, MIXART_PSEUDOREG_DXLX_STATUS_OFFSET ));
516
517
518 break;
519 }
520
521
522 err = mixart_wait_nice_for_register_value( mgr, MIXART_PSEUDOREG_DXLX_STATUS_OFFSET, 1, 3, 300);
523 if (err < 0) {
524 dev_err(&mgr->pci->dev,
525 "daughter board could not be initialised\n");
526 return err;
527 }
528
529
530 snd_mixart_init_mailbox(mgr);
531
532
533 err = mixart_first_init(mgr);
534 if (err < 0) {
535 dev_err(&mgr->pci->dev, "miXart could not be set up\n");
536 return err;
537 }
538
539
540 for (card_index = 0; card_index < mgr->num_cards; card_index++) {
541 struct snd_mixart *chip = mgr->chip[card_index];
542
543 if ((err = snd_mixart_create_pcm(chip)) < 0)
544 return err;
545
546 if (card_index == 0) {
547 if ((err = snd_mixart_create_mixer(chip->mgr)) < 0)
548 return err;
549 }
550
551 if ((err = snd_card_register(chip->card)) < 0)
552 return err;
553 }
554
555 dev_dbg(&mgr->pci->dev,
556 "miXart firmware downloaded and successfully set up\n");
557
558 return 0;
559}
560
561
562int snd_mixart_setup_firmware(struct mixart_mgr *mgr)
563{
564 static char *fw_files[3] = {
565 "miXart8.xlx", "miXart8.elf", "miXart8AES.xlx"
566 };
567 char path[32];
568
569 const struct firmware *fw_entry;
570 int i, err;
571
572 for (i = 0; i < 3; i++) {
573 sprintf(path, "mixart/%s", fw_files[i]);
574 if (request_firmware(&fw_entry, path, &mgr->pci->dev)) {
575 dev_err(&mgr->pci->dev,
576 "miXart: can't load firmware %s\n", path);
577 return -ENOENT;
578 }
579
580 err = mixart_dsp_load(mgr, i, fw_entry);
581 release_firmware(fw_entry);
582 if (err < 0)
583 return err;
584 mgr->dsp_loaded |= 1 << i;
585 }
586 return 0;
587}
588
589MODULE_FIRMWARE("mixart/miXart8.xlx");
590MODULE_FIRMWARE("mixart/miXart8.elf");
591MODULE_FIRMWARE("mixart/miXart8AES.xlx");
592