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