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