140123Sdes// SPDX-License-Identifier: GPL-2.0-or-later
250472Speter/*
3709Swollman * Driver for Digigram miXart soundcards
437Srgrimes *
537Srgrimes * DSP firmware management
637Srgrimes *
737Srgrimes * Copyright (c) 2003 by Digigram <alsa@digigram.com>
837Srgrimes */
937Srgrimes
1051231Ssheldonh#include <linux/interrupt.h>
1151231Ssheldonh#include <linux/pci.h>
1251231Ssheldonh#include <linux/firmware.h>
1351231Ssheldonh#include <linux/vmalloc.h>
148460Sjkh#include <linux/slab.h>
1537Srgrimes#include <linux/module.h>
1637Srgrimes#include <linux/io.h>
1737Srgrimes#include <sound/core.h>
1837Srgrimes#include "mixart.h"
1951231Ssheldonh#include "mixart_mixer.h"
2037Srgrimes#include "mixart_core.h"
2137Srgrimes#include "mixart_hwdep.h"
2237Srgrimes
2351231Ssheldonh
2420684Sjoerg/**
2551231Ssheldonh * mixart_wait_nice_for_register_value - wait for a value on a peudo register,
2637Srgrimes * exit with a timeout
2743179Sdillon *
2843803Sdillon * @mgr: pointer to miXart manager structure
2943179Sdillon * @offset: unsigned pseudo_register base + offset of value
3051231Ssheldonh * @is_egal: wait for the equal value
3143375Sdillon * @value: value
3243375Sdillon * @timeout: timeout in centisenconds
3343803Sdillon */
3443179Sdillonstatic int mixart_wait_nice_for_register_value(struct mixart_mgr *mgr,
3543179Sdillon					       u32 offset, int is_egal,
3643179Sdillon					       u32 value, unsigned long timeout)
3743219Speter{
3843219Speter	unsigned long end_time = jiffies + (timeout * HZ / 100);
3951231Ssheldonh	u32 read;
4043849Sjkh
4151231Ssheldonh	do {	/* we may take too long time in this loop.
4243219Speter		 * so give controls back to kernel if needed.
4343219Speter		 */
4443219Speter		cond_resched();
4515568Sasami
4651231Ssheldonh		read = readl_be( MIXART_MEM( mgr, offset ));
4751231Ssheldonh		if(is_egal) {
4815568Sasami			if(read == value) return 0;
4915568Sasami		}
5015568Sasami		else { /* wait for different value */
5151231Ssheldonh			if(read != value) return 0;
5251231Ssheldonh		}
5345239Sgrog	} while ( time_after_eq(end_time, jiffies) );
5451231Ssheldonh
5551231Ssheldonh	return -EBUSY;
5642741Sgrog}
5743803Sdillon
583843Sdg
5951231Ssheldonh/*
6051231Ssheldonh  structures needed to upload elf code packets
6137Srgrimes */
6237Srgrimesstruct snd_mixart_elf32_ehdr {
6337Srgrimes	u8      e_ident[16];
6437Srgrimes	__be16  e_type;
6537Srgrimes	__be16  e_machine;
6637Srgrimes	__be32  e_version;
6737Srgrimes	__be32  e_entry;
6837Srgrimes	__be32  e_phoff;
6937Srgrimes	__be32  e_shoff;
7037Srgrimes	__be32  e_flags;
7137Srgrimes	__be16  e_ehsize;
7237Srgrimes	__be16  e_phentsize;
7337Srgrimes	__be16  e_phnum;
7437Srgrimes	__be16  e_shentsize;
7537Srgrimes	__be16  e_shnum;
7637Srgrimes	__be16  e_shstrndx;
7737Srgrimes};
7837Srgrimes
7937Srgrimesstruct snd_mixart_elf32_phdr {
8037Srgrimes	__be32  p_type;
8137Srgrimes	__be32  p_offset;
8237Srgrimes	__be32  p_vaddr;
8337Srgrimes	__be32  p_paddr;
8437Srgrimes	__be32  p_filesz;
8537Srgrimes	__be32  p_memsz;
8637Srgrimes	__be32  p_flags;
8737Srgrimes	__be32  p_align;
8837Srgrimes};
8937Srgrimes
9037Srgrimesstatic int mixart_load_elf(struct mixart_mgr *mgr, const struct firmware *dsp )
9151231Ssheldonh{
9251231Ssheldonh	char                    elf32_magic_number[4] = {0x7f,'E','L','F'};
932164Sdg	struct snd_mixart_elf32_ehdr *elf_header;
9451231Ssheldonh	int                     i;
9551231Ssheldonh
9637Srgrimes	elf_header = (struct snd_mixart_elf32_ehdr *)dsp->data;
9745222Scracauer	for( i=0; i<4; i++ )
9837Srgrimes		if ( elf32_magic_number[i] != elf_header->e_ident[i] )
9937Srgrimes			return -EINVAL;
10043197Sdillon
10143197Sdillon	if( elf_header->e_phoff != 0 ) {
10243197Sdillon		struct snd_mixart_elf32_phdr     elf_programheader;
10351231Ssheldonh
10451231Ssheldonh		for( i=0; i < be16_to_cpu(elf_header->e_phnum); i++ ) {
10551231Ssheldonh			u32 pos = be32_to_cpu(elf_header->e_phoff) + (u32)(i * be16_to_cpu(elf_header->e_phentsize));
10651231Ssheldonh
10751231Ssheldonh			memcpy( &elf_programheader, dsp->data + pos, sizeof(elf_programheader) );
10851231Ssheldonh
10951231Ssheldonh			if(elf_programheader.p_type != 0) {
11051231Ssheldonh				if( elf_programheader.p_filesz != 0 ) {
11151231Ssheldonh					memcpy_toio( MIXART_MEM( mgr, be32_to_cpu(elf_programheader.p_vaddr)),
11251231Ssheldonh						     dsp->data + be32_to_cpu( elf_programheader.p_offset ),
1131692Sphk						     be32_to_cpu( elf_programheader.p_filesz ));
11443803Sdillon				}
11543197Sdillon			}
11656038Sgreen		}
11756038Sgreen	}
11851231Ssheldonh	return 0;
11951231Ssheldonh}
12051231Ssheldonh
12151231Ssheldonh/*
12251231Ssheldonh * get basic information and init miXart
12351231Ssheldonh */
12443803Sdillon
12551231Ssheldonh/* audio IDs for request to the board */
12651231Ssheldonh#define MIXART_FIRST_ANA_AUDIO_ID       0
12737Srgrimes#define MIXART_FIRST_DIG_AUDIO_ID       8
12843197Sdillon
12943197Sdillonstatic int mixart_enum_connectors(struct mixart_mgr *mgr)
13051231Ssheldonh{
13150357Ssheldonh	u32 k;
13243197Sdillon	int err;
13343197Sdillon	struct mixart_msg request;
1344091Sache	struct mixart_enum_connector_resp *connector;
135872Sache	struct mixart_audio_info_req  *audio_info_req;
13638237Sbrian	struct mixart_audio_info_resp *audio_info;
13739384Sbrian
13839384Sbrian	connector = kmalloc(sizeof(*connector), GFP_KERNEL);
13939384Sbrian	audio_info_req = kmalloc(sizeof(*audio_info_req), GFP_KERNEL);
14039384Sbrian	audio_info = kmalloc(sizeof(*audio_info), GFP_KERNEL);
14139384Sbrian	if (! connector || ! audio_info_req || ! audio_info) {
14239384Sbrian		err = -ENOMEM;
14339384Sbrian		goto __error;
14451231Ssheldonh	}
14539384Sbrian
14639384Sbrian	audio_info_req->line_max_level = MIXART_FLOAT_P_22_0_TO_HEX;
14738237Sbrian	audio_info_req->micro_max_level = MIXART_FLOAT_M_20_0_TO_HEX;
14826450Sache	audio_info_req->cd_max_level = MIXART_FLOAT____0_0_TO_HEX;
14938237Sbrian
15039384Sbrian	request.message_id = MSG_SYSTEM_ENUM_PLAY_CONNECTOR;
15139384Sbrian	request.uid = (struct mixart_uid){0,0};  /* board num = 0 */
15239384Sbrian	request.data = NULL;
15339384Sbrian	request.size = 0;
15438237Sbrian
15521197Sphk	err = snd_mixart_send_msg(mgr, &request, sizeof(*connector), connector);
15617767Sjkh	if((err < 0) || (connector->error_code) || (connector->uid_count > MIXART_MAX_PHYS_CONNECTORS)) {
15751231Ssheldonh		dev_err(&mgr->pci->dev,
15851231Ssheldonh			"error MSG_SYSTEM_ENUM_PLAY_CONNECTOR\n");
15951231Ssheldonh		err = -EINVAL;
16051231Ssheldonh		goto __error;
16151231Ssheldonh	}
16251231Ssheldonh
16351231Ssheldonh	for(k=0; k < connector->uid_count; k++) {
16451231Ssheldonh		struct mixart_pipe *pipe;
16551231Ssheldonh
16651231Ssheldonh		if(k < MIXART_FIRST_DIG_AUDIO_ID) {
16751231Ssheldonh			pipe = &mgr->chip[k/2]->pipe_out_ana;
16817767Sjkh		} else {
16951231Ssheldonh			pipe = &mgr->chip[(k-MIXART_FIRST_DIG_AUDIO_ID)/2]->pipe_out_dig;
17051231Ssheldonh		}
17151231Ssheldonh		if(k & 1) {
17245096Simp			pipe->uid_right_connector = connector->uid[k];   /* odd */
17345096Simp		} else {
17445096Simp			pipe->uid_left_connector = connector->uid[k];    /* even */
17551231Ssheldonh		}
17651231Ssheldonh
17751231Ssheldonh		/* dev_dbg(&mgr->pci->dev, "playback connector[%d].object_id = %x\n", k, connector->uid[k].object_id); */
1787293Sjkh
1791675Sache		/* TODO: really need send_msg MSG_CONNECTOR_GET_AUDIO_INFO for each connector ? perhaps for analog level caps ? */
1801675Sache		request.message_id = MSG_CONNECTOR_GET_AUDIO_INFO;
18151231Ssheldonh		request.uid = connector->uid[k];
18251231Ssheldonh		request.data = audio_info_req;
18351231Ssheldonh		request.size = sizeof(*audio_info_req);
18414624Snate
18514596Snate		err = snd_mixart_send_msg(mgr, &request, sizeof(*audio_info), audio_info);
18614596Snate		if( err < 0 ) {
18751231Ssheldonh			dev_err(&mgr->pci->dev,
18851231Ssheldonh				"error MSG_CONNECTOR_GET_AUDIO_INFO\n");
18951231Ssheldonh			goto __error;
19025184Sjkh		}
19125184Sjkh		/*dev_dbg(&mgr->pci->dev, "play  analog_info.analog_level_present = %x\n", audio_info->info.analog_info.analog_level_present);*/
1927460Sjkh	}
1937460Sjkh
19456038Sgreen	request.message_id = MSG_SYSTEM_ENUM_RECORD_CONNECTOR;
19538456Sphk	request.uid = (struct mixart_uid){0,0};  /* board num = 0 */
19656038Sgreen	request.data = NULL;
19738456Sphk	request.size = 0;
1987487Srgrimes
1997487Srgrimes	err = snd_mixart_send_msg(mgr, &request, sizeof(*connector), connector);
20051231Ssheldonh	if((err < 0) || (connector->error_code) || (connector->uid_count > MIXART_MAX_PHYS_CONNECTORS)) {
20149366Simp		dev_err(&mgr->pci->dev,
20220828Sjoerg			"error MSG_SYSTEM_ENUM_RECORD_CONNECTOR\n");
20344752Sdes		err = -EINVAL;
2047487Srgrimes		goto __error;
20551231Ssheldonh	}
20651231Ssheldonh
20738237Sbrian	for(k=0; k < connector->uid_count; k++) {
20838237Sbrian		struct mixart_pipe *pipe;
20938237Sbrian
21031192Ssteve		if(k < MIXART_FIRST_DIG_AUDIO_ID) {
21131192Ssteve			pipe = &mgr->chip[k/2]->pipe_in_ana;
21231192Ssteve		} else {
21331192Ssteve			pipe = &mgr->chip[(k-MIXART_FIRST_DIG_AUDIO_ID)/2]->pipe_in_dig;
21431192Ssteve		}
21531192Ssteve		if(k & 1) {
21631192Ssteve			pipe->uid_right_connector = connector->uid[k];   /* odd */
21751231Ssheldonh		} else {
21851231Ssheldonh			pipe->uid_left_connector = connector->uid[k];    /* even */
21931192Ssteve		}
22031192Ssteve
22131192Ssteve		/* dev_dbg(&mgr->pci->dev, "capture connector[%d].object_id = %x\n", k, connector->uid[k].object_id); */
22231192Ssteve
22351231Ssheldonh		/* TODO: really need send_msg MSG_CONNECTOR_GET_AUDIO_INFO for each connector ? perhaps for analog level caps ? */
22451231Ssheldonh		request.message_id = MSG_CONNECTOR_GET_AUDIO_INFO;
22551231Ssheldonh		request.uid = connector->uid[k];
22651231Ssheldonh		request.data = audio_info_req;
22731192Ssteve		request.size = sizeof(*audio_info_req);
22851231Ssheldonh
22938915Scracauer		err = snd_mixart_send_msg(mgr, &request, sizeof(*audio_info), audio_info);
23051231Ssheldonh		if( err < 0 ) {
23138915Scracauer			dev_err(&mgr->pci->dev,
23238915Scracauer				"error MSG_CONNECTOR_GET_AUDIO_INFO\n");
23351231Ssheldonh			goto __error;
23451231Ssheldonh		}
2357487Srgrimes		/*dev_dbg(&mgr->pci->dev, "rec  analog_info.analog_level_present = %x\n", audio_info->info.analog_info.analog_level_present);*/
23625339Sjkh	}
23751231Ssheldonh	err = 0;
23851231Ssheldonh
23951231Ssheldonh __error:
2407259Sjkh	kfree(connector);
24151231Ssheldonh	kfree(audio_info_req);
24251231Ssheldonh	kfree(audio_info);
24324463Spst
24451231Ssheldonh	return err;
24551231Ssheldonh}
24624463Spst
24724463Spststatic int mixart_enum_physio(struct mixart_mgr *mgr)
24824463Spst{
24924463Spst	u32 k;
25024463Spst	int err;
25151231Ssheldonh	struct mixart_msg request;
25251231Ssheldonh	struct mixart_uid get_console_mgr;
25351231Ssheldonh	struct mixart_return_uid console_mgr;
25451231Ssheldonh	struct mixart_uid_enumeration phys_io;
25525339Sjkh
25625339Sjkh	/* get the uid for the console manager */
25751231Ssheldonh	get_console_mgr.object_id = 0;
25832340Sjoerg	get_console_mgr.desc = MSG_CONSOLE_MANAGER | 0; /* cardindex = 0 */
25932340Sjoerg
26051231Ssheldonh	request.message_id = MSG_CONSOLE_GET_CLOCK_UID;
26151231Ssheldonh	request.uid = get_console_mgr;
26251231Ssheldonh	request.data = &get_console_mgr;
26351231Ssheldonh	request.size = sizeof(get_console_mgr);
26451231Ssheldonh
26551231Ssheldonh	err = snd_mixart_send_msg(mgr, &request, sizeof(console_mgr), &console_mgr);
26651231Ssheldonh
26751231Ssheldonh	if( (err < 0) || (console_mgr.error_code != 0) ) {
26851231Ssheldonh		dev_dbg(&mgr->pci->dev,
26951231Ssheldonh			"error MSG_CONSOLE_GET_CLOCK_UID : err=%x\n",
27051231Ssheldonh			console_mgr.error_code);
27151231Ssheldonh		return -EINVAL;
27232340Sjoerg	}
27350357Ssheldonh
27439384Sbrian	/* used later for clock issues ! */
275857Sdg	mgr->uid_console_manager = console_mgr.uid;
27637Srgrimes
27744818Sbillf	request.message_id = MSG_SYSTEM_ENUM_PHYSICAL_IO;
27851231Ssheldonh	request.uid = (struct mixart_uid){0,0};
27951231Ssheldonh	request.data = &console_mgr.uid;
28051231Ssheldonh	request.size = sizeof(console_mgr.uid);
28151231Ssheldonh
28251231Ssheldonh	err = snd_mixart_send_msg(mgr, &request, sizeof(phys_io), &phys_io);
28351231Ssheldonh	if( (err < 0) || ( phys_io.error_code != 0 ) ) {
28451231Ssheldonh		dev_err(&mgr->pci->dev,
28551231Ssheldonh			"error MSG_SYSTEM_ENUM_PHYSICAL_IO err(%x) error_code(%x)\n",
28651231Ssheldonh			err, phys_io.error_code);
28751231Ssheldonh		return -EINVAL;
28844818Sbillf	}
28951231Ssheldonh
29051231Ssheldonh	/* min 2 phys io per card (analog in + analog out) */
29151231Ssheldonh	if (phys_io.nb_uid < MIXART_MAX_CARDS * 2)
29251231Ssheldonh		return -EINVAL;
29351231Ssheldonh
29444818Sbillf	for(k=0; k<mgr->num_cards; k++) {
29550357Ssheldonh		mgr->chip[k]->uid_in_analog_physio = phys_io.uid[k];
29639384Sbrian		mgr->chip[k]->uid_out_analog_physio = phys_io.uid[phys_io.nb_uid/2 + k];
2977477Sache	}
2987477Sache
29951231Ssheldonh	return 0;
30051231Ssheldonh}
3017487Srgrimes
3027487Srgrimes
30351231Ssheldonhstatic int mixart_first_init(struct mixart_mgr *mgr)
30451231Ssheldonh{
30551231Ssheldonh	u32 k;
3067487Srgrimes	int err;
3077487Srgrimes	struct mixart_msg request;
3087238Sache
3097238Sache	err = mixart_enum_connectors(mgr);
31051231Ssheldonh	if (err < 0)
31151231Ssheldonh		return err;
31251231Ssheldonh
31351231Ssheldonh	err = mixart_enum_physio(mgr);
31451231Ssheldonh	if (err < 0)
31551231Ssheldonh		return err;
31651231Ssheldonh
31751231Ssheldonh	/* send a synchro command to card (necessary to do this before first MSG_STREAM_START_STREAM_GRP_PACKET) */
31811992Sache	/* though why not here */
31951231Ssheldonh	request.message_id = MSG_SYSTEM_SEND_SYNCHRO_CMD;
32051231Ssheldonh	request.uid = (struct mixart_uid){0,0};
3217238Sache	request.data = NULL;
32227365Sjkh	request.size = 0;
32327365Sjkh	/* this command has no data. response is a 32 bit status */
32451231Ssheldonh	err = snd_mixart_send_msg(mgr, &request, sizeof(k), &k);
32538512Sgpalmer	if( (err < 0) || (k != 0) ) {
32651231Ssheldonh		dev_err(&mgr->pci->dev, "error MSG_SYSTEM_SEND_SYNCHRO_CMD\n");
32751231Ssheldonh		return err == 0 ? -EINVAL : err;
32839329Sjdp	}
32950357Ssheldonh
33051231Ssheldonh	return 0;
33150357Ssheldonh}
33239329Sjdp
33339329Sjdp
33439329Sjdp/* firmware base addresses (when hard coded) */
33539329Sjdp#define MIXART_MOTHERBOARD_XLX_BASE_ADDRESS   0x00600000
33651231Ssheldonh
33751231Ssheldonhstatic int mixart_dsp_load(struct mixart_mgr* mgr, int index, const struct firmware *dsp)
33839329Sjdp{
33941648Sjb	int           err, card_index;
34051231Ssheldonh	u32           status_xilinx, status_elf, status_daught;
34151231Ssheldonh	u32           val;
34243951Sjkh
34341648Sjb	/* read motherboard xilinx status */
34441648Sjb	status_xilinx = readl_be( MIXART_MEM( mgr,MIXART_PSEUDOREG_MXLX_STATUS_OFFSET ));
34550357Ssheldonh	/* read elf status */
34651231Ssheldonh	status_elf = readl_be( MIXART_MEM( mgr,MIXART_PSEUDOREG_ELF_STATUS_OFFSET ));
34750357Ssheldonh	/* read daughterboard xilinx status */
34841648Sjb	status_daught = readl_be( MIXART_MEM( mgr,MIXART_PSEUDOREG_DXLX_STATUS_OFFSET ));
34941648Sjb
35041648Sjb	/* motherboard xilinx status 5 will say that the board is performing a reset */
35141648Sjb	if (status_xilinx == 5) {
35251231Ssheldonh		dev_err(&mgr->pci->dev, "miXart is resetting !\n");
35351231Ssheldonh		return -EAGAIN; /* try again later */
35438512Sgpalmer	}
3557296Sjkh
35617210Spst	switch (index)   {
35717210Spst	case MIXART_MOTHERBOARD_XLX_INDEX:
35825339Sjkh
35951231Ssheldonh		/* xilinx already loaded ? */
36051231Ssheldonh		if (status_xilinx == 4) {
36151231Ssheldonh			dev_dbg(&mgr->pci->dev, "xilinx is already loaded !\n");
36251231Ssheldonh			return 0;
36326727Spst		}
36451231Ssheldonh		/* the status should be 0 == "idle" */
36551231Ssheldonh		if (status_xilinx != 0) {
36617210Spst			dev_err(&mgr->pci->dev,
36751231Ssheldonh				"xilinx load error ! status = %d\n",
36851231Ssheldonh				   status_xilinx);
36951231Ssheldonh			return -EIO; /* modprob -r may help ? */
37051231Ssheldonh		}
37126727Spst
37251231Ssheldonh		/* check xilinx validity */
37351231Ssheldonh		if (((u32*)(dsp->data))[0] == 0xffffffff)
37426727Spst			return -EINVAL;
37551231Ssheldonh		if (dsp->size % 4)
37651231Ssheldonh			return -EINVAL;
37751231Ssheldonh
37851231Ssheldonh		/* set xilinx status to copying */
37951231Ssheldonh		writel_be( 1, MIXART_MEM( mgr, MIXART_PSEUDOREG_MXLX_STATUS_OFFSET ));
38017210Spst
38151231Ssheldonh		/* setup xilinx base address */
38251231Ssheldonh		writel_be( MIXART_MOTHERBOARD_XLX_BASE_ADDRESS, MIXART_MEM( mgr,MIXART_PSEUDOREG_MXLX_BASE_ADDR_OFFSET ));
38354843Sobrien		/* setup code size for xilinx file */
38451231Ssheldonh		writel_be( dsp->size, MIXART_MEM( mgr, MIXART_PSEUDOREG_MXLX_SIZE_OFFSET ));
38551231Ssheldonh
38651231Ssheldonh		/* copy xilinx code */
38751231Ssheldonh		memcpy_toio(  MIXART_MEM( mgr, MIXART_MOTHERBOARD_XLX_BASE_ADDRESS),  dsp->data,  dsp->size);
38817161Spst
38951231Ssheldonh		/* set xilinx status to copy finished */
39051231Ssheldonh		writel_be( 2, MIXART_MEM( mgr, MIXART_PSEUDOREG_MXLX_STATUS_OFFSET ));
39142498Sn_hibma
39251231Ssheldonh		/* return, because no further processing needed */
39351231Ssheldonh		return 0;
39442498Sn_hibma
39517161Spst	case MIXART_MOTHERBOARD_ELF_INDEX:
39617161Spst
39716671Spst		if (status_elf == 4) {
39850612Simp			dev_dbg(&mgr->pci->dev, "elf file already loaded !\n");
39919314Speter			return 0;
40050357Ssheldonh		}
40116671Spst
40255511Speter		/* the status should be 0 == "idle" */
40319314Speter		if (status_elf != 0) {
40451231Ssheldonh			dev_err(&mgr->pci->dev,
40519314Speter				"elf load error ! status = %d\n",
40619314Speter				   status_elf);
40719314Speter			return -EIO; /* modprob -r may help ? */
40819314Speter		}
40919314Speter
41051231Ssheldonh		/* wait for xilinx status == 4 */
41155451Speter		err = mixart_wait_nice_for_register_value( mgr, MIXART_PSEUDOREG_MXLX_STATUS_OFFSET, 1, 4, 500); /* 5sec */
41219314Speter		if (err < 0) {
41316671Spst			dev_err(&mgr->pci->dev, "xilinx was not loaded or "
41419314Speter				   "could not be started\n");
41519314Speter			return err;
41619314Speter		}
41719314Speter
41850357Ssheldonh		/* init some data on the card */
41955511Speter		writel_be( 0, MIXART_MEM( mgr, MIXART_PSEUDOREG_BOARDNUMBER ) ); /* set miXart boardnumber to 0 */
42019314Speter		writel_be( 0, MIXART_MEM( mgr, MIXART_FLOWTABLE_PTR ) );         /* reset pointer to flow table on miXart */
42151231Ssheldonh
42219314Speter		/* set elf status to copying */
42319314Speter		writel_be( 1, MIXART_MEM( mgr, MIXART_PSEUDOREG_ELF_STATUS_OFFSET ));
42419314Speter
42519314Speter		/* process the copying of the elf packets */
42619314Speter		err = mixart_load_elf( mgr, dsp );
42719314Speter		if (err < 0) return err;
42855453Speter
42951231Ssheldonh		/* set elf status to copy finished */
43055451Speter		writel_be( 2, MIXART_MEM( mgr, MIXART_PSEUDOREG_ELF_STATUS_OFFSET ));
43119314Speter
43255451Speter		/* wait for elf status == 4 */
43319314Speter		err = mixart_wait_nice_for_register_value( mgr, MIXART_PSEUDOREG_ELF_STATUS_OFFSET, 1, 4, 300); /* 3sec */
43419314Speter		if (err < 0) {
43519314Speter			dev_err(&mgr->pci->dev, "elf could not be started\n");
43616671Spst			return err;
43716671Spst		}
43851231Ssheldonh
43951231Ssheldonh		/* miXart waits at this point on the pointer to the flow table */
44051231Ssheldonh		writel_be( (u32)mgr->flowinfo.addr, MIXART_MEM( mgr, MIXART_FLOWTABLE_PTR ) ); /* give pointer of flow table to miXart */
44151231Ssheldonh
44237899Snectar		return 0;  /* return, another xilinx file has to be loaded before */
44337899Snectar
44437899Snectar	case MIXART_AESEBUBOARD_XLX_INDEX:
44551231Ssheldonh	default:
44651231Ssheldonh
44751231Ssheldonh		/* elf and xilinx should be loaded */
44851231Ssheldonh		if (status_elf != 4 || status_xilinx != 4) {
44951231Ssheldonh			dev_err(&mgr->pci->dev, "xilinx or elf not "
45050357Ssheldonh			       "successfully loaded\n");
45150357Ssheldonh			return -EIO; /* modprob -r may help ? */
45250357Ssheldonh		}
45350357Ssheldonh
45449451Speter		/* wait for daughter detection != 0 */
45549451Speter		err = mixart_wait_nice_for_register_value( mgr, MIXART_PSEUDOREG_DBRD_PRESENCE_OFFSET, 0, 0, 30); /* 300msec */
45650357Ssheldonh		if (err < 0) {
45749451Speter			dev_err(&mgr->pci->dev, "error starting elf file\n");
45851231Ssheldonh			return err;
45951231Ssheldonh		}
46051231Ssheldonh
46151617Snsayer		/* the board type can now be retrieved */
46251617Snsayer		mgr->board_type = (DAUGHTER_TYPE_MASK & readl_be( MIXART_MEM( mgr, MIXART_PSEUDOREG_DBRD_TYPE_OFFSET)));
46351617Snsayer
46451617Snsayer		if (mgr->board_type == MIXART_DAUGHTER_TYPE_NONE)
46551617Snsayer			break;  /* no daughter board; the file does not have to be loaded, continue after the switch */
46651617Snsayer
46751617Snsayer		/* only if aesebu daughter board presence (elf code must run)  */
46851231Ssheldonh		if (mgr->board_type != MIXART_DAUGHTER_TYPE_AES )
46951231Ssheldonh			return -EINVAL;
47051231Ssheldonh
47151231Ssheldonh		/* daughter should be idle */
47241704Sdillon		if (status_daught != 0) {
47341704Sdillon			dev_err(&mgr->pci->dev,
47441704Sdillon				"daughter load error ! status = %d\n",
47543951Sjkh			       status_daught);
47643951Sjkh			return -EIO; /* modprob -r may help ? */
47743951Sjkh		}
47841704Sdillon
47941704Sdillon		/* check daughterboard xilinx validity */
48051231Ssheldonh		if (((u32*)(dsp->data))[0] == 0xffffffff)
48151231Ssheldonh			return -EINVAL;
48251231Ssheldonh		if (dsp->size % 4)
48351231Ssheldonh			return -EINVAL;
48451231Ssheldonh
48551231Ssheldonh		/* inform mixart about the size of the file */
48651231Ssheldonh		writel_be( dsp->size, MIXART_MEM( mgr, MIXART_PSEUDOREG_DXLX_SIZE_OFFSET ));
48751231Ssheldonh
48851231Ssheldonh		/* set daughterboard status to 1 */
48943197Sdillon		writel_be( 1, MIXART_MEM( mgr, MIXART_PSEUDOREG_DXLX_STATUS_OFFSET ));
49051231Ssheldonh
49143197Sdillon		/* wait for status == 2 */
49241704Sdillon		err = mixart_wait_nice_for_register_value( mgr, MIXART_PSEUDOREG_DXLX_STATUS_OFFSET, 1, 2, 30); /* 300msec */
49341704Sdillon		if (err < 0) {
49451617Snsayer			dev_err(&mgr->pci->dev, "daughter board load error\n");
49551617Snsayer			return err;
49651617Snsayer		}
49751617Snsayer
49851617Snsayer		/* get the address where to write the file */
49951617Snsayer		val = readl_be( MIXART_MEM( mgr, MIXART_PSEUDOREG_DXLX_BASE_ADDR_OFFSET ));
50051617Snsayer		if (!val)
50151617Snsayer			return -EINVAL;
50251617Snsayer
50351617Snsayer		/* copy daughterboard xilinx code */
50451617Snsayer		memcpy_toio(  MIXART_MEM( mgr, val),  dsp->data,  dsp->size);
50551617Snsayer
50651617Snsayer		/* set daughterboard status to 4 */
50751617Snsayer		writel_be( 4, MIXART_MEM( mgr, MIXART_PSEUDOREG_DXLX_STATUS_OFFSET ));
50851617Snsayer
50951617Snsayer		/* continue with init */
51051617Snsayer		break;
51151617Snsayer	} /* end of switch file index*/
51251617Snsayer
51351617Snsayer        /* wait for daughter status == 3 */
51451617Snsayer        err = mixart_wait_nice_for_register_value( mgr, MIXART_PSEUDOREG_DXLX_STATUS_OFFSET, 1, 3, 300); /* 3sec */
51551617Snsayer        if (err < 0) {
51653314Sache		dev_err(&mgr->pci->dev,
51753314Sache			   "daughter board could not be initialised\n");
51853314Sache		return err;
51953314Sache	}
52037106Sjkoshy
52137106Sjkoshy	/* init mailbox (communication with embedded) */
52251231Ssheldonh	snd_mixart_init_mailbox(mgr);
52351231Ssheldonh
52451231Ssheldonh	/* first communication with embedded */
52551231Ssheldonh	err = mixart_first_init(mgr);
52651231Ssheldonh        if (err < 0) {
52751231Ssheldonh		dev_err(&mgr->pci->dev, "miXart could not be set up\n");
52851231Ssheldonh		return err;
52951231Ssheldonh	}
53051231Ssheldonh
53137106Sjkoshy       	/* create devices and mixer in accordance with HW options*/
53237Srgrimes        for (card_index = 0; card_index < mgr->num_cards; card_index++) {
53337Srgrimes		struct snd_mixart *chip = mgr->chip[card_index];
534
535		err = snd_mixart_create_pcm(chip);
536		if (err < 0)
537			return err;
538
539		if (card_index == 0) {
540			err = snd_mixart_create_mixer(chip->mgr);
541			if (err < 0)
542	        		return err;
543		}
544
545		err = snd_card_register(chip->card);
546		if (err < 0)
547			return err;
548	}
549
550	dev_dbg(&mgr->pci->dev,
551		"miXart firmware downloaded and successfully set up\n");
552
553	return 0;
554}
555
556
557int snd_mixart_setup_firmware(struct mixart_mgr *mgr)
558{
559	static const char * const fw_files[3] = {
560		"miXart8.xlx", "miXart8.elf", "miXart8AES.xlx"
561	};
562	char path[32];
563
564	const struct firmware *fw_entry;
565	int i, err;
566
567	for (i = 0; i < 3; i++) {
568		sprintf(path, "mixart/%s", fw_files[i]);
569		if (request_firmware(&fw_entry, path, &mgr->pci->dev)) {
570			dev_err(&mgr->pci->dev,
571				"miXart: can't load firmware %s\n", path);
572			return -ENOENT;
573		}
574		/* fake hwdep dsp record */
575		err = mixart_dsp_load(mgr, i, fw_entry);
576		release_firmware(fw_entry);
577		if (err < 0)
578			return err;
579		mgr->dsp_loaded |= 1 << i;
580	}
581	return 0;
582}
583
584MODULE_FIRMWARE("mixart/miXart8.xlx");
585MODULE_FIRMWARE("mixart/miXart8.elf");
586MODULE_FIRMWARE("mixart/miXart8AES.xlx");
587