Skip to content

Commit 54f3cdc

Browse files
authored
Merge pull request #70 from jiyunomegami/forupstream2
Heuristic to switch problematic chipsets to PIO
2 parents e5470b6 + 1219f12 commit 54f3cdc

File tree

1 file changed

+77
-24
lines changed

1 file changed

+77
-24
lines changed

mpxplay/au_cards/sc_inthd.c

Lines changed: 77 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ struct intelhd_card_s
6666
long pcmout_bufsize;
6767
unsigned long* corb_buffer;
6868
unsigned long long* rirb_buffer;
69+
int first_rirb;
6970
unsigned long pcmout_dmasize;
7071
unsigned int pcmout_num_periods;
7172
unsigned long pcmout_period_size;
@@ -278,24 +279,57 @@ static unsigned int azx_get_response(struct intelhd_card_s *chip)
278279
#endif
279280
return azx_readl(chip, IR);
280281
} else { //Immediate Commands are optional, some devices don't have it, use CORB
281-
do{
282+
if (chip->first_rirb) {
282283
azx_writeb(chip, RIRBCTL, 0x3);
284+
}
285+
do{
283286
if(azx_readb(chip, RIRBSTS)&1)
284287
break;
285288
pds_delay_10us(10);
286-
}while(--timeout);
289+
}while(--timeout);
287290
if(!timeout){
288291
mpxplay_debugf(IHD_DEBUG_OUTPUT,"read response timeout %d", timeout);
292+
if (chip->first_rirb) {
293+
// Some chipsets will freeze if you now try to read the RIRB
294+
chip->first_rirb = 0;
295+
return 0;
296+
}
289297
chip->config_select |= AUCARDSCONFIG_IHD_USE_PIO;
298+
chip->first_rirb = 0;
290299
return 0xffffffff;
291300
}
301+
chip->first_rirb = 0;
292302
int rirbindex = azx_readw(chip, RIRBWP);
293303
long long data = chip->rirb_buffer[rirbindex];
294304
azx_writeb(chip, RIRBSTS, 1);
295305
return (unsigned int)(data);
296306
}
297307
}
298308

309+
static void switch_to_pio(struct intelhd_card_s *chip)
310+
{
311+
int timeout = 2000; // 200 ms
312+
printf("Intel HDA: Switching to PIO.\n");
313+
azx_writeb(chip, CORBCTL, 0); // DMA Stop
314+
int c;
315+
do {
316+
c = azx_readb(chip, CORBCTL);
317+
pds_delay_10us(10);
318+
if ((c & 2) == 0) {
319+
break;
320+
}
321+
} while (--timeout);
322+
azx_writew(chip, RIRBCTL, 0); // DMA Stop, Disable Interrupt
323+
do {
324+
c = azx_readb(chip, RIRBCTL);
325+
if ((c & 2) == 0) {
326+
break;
327+
}
328+
pds_delay_10us(10);
329+
} while (--timeout);
330+
azx_writel(chip, GCTL, (azx_readl(chip, GCTL) & (~ICH6_GCTL_UREN)));
331+
}
332+
299333
static unsigned int snd_hda_codec_read(struct intelhd_card_s *chip, hda_nid_t nid,
300334
uint32_t direct,
301335
unsigned int verb, unsigned int parm)
@@ -306,26 +340,7 @@ static unsigned int snd_hda_codec_read(struct intelhd_card_s *chip, hda_nid_t ni
306340
snd_hda_codec_write(chip,nid,direct,verb,parm);
307341
unsigned int r = azx_get_response(chip);
308342
if (r == 0xffffffff && pio != (chip->config_select & AUCARDSCONFIG_IHD_USE_PIO)) {
309-
int timeout = 2000; // 200 ms
310-
printf("Intel HDA: Switching to PIO.\n");
311-
azx_writeb(chip, CORBCTL, 0); // DMA Stop
312-
int c;
313-
do {
314-
c = azx_readb(chip, CORBCTL);
315-
pds_delay_10us(10);
316-
if ((c & 2) == 0) {
317-
break;
318-
}
319-
} while (--timeout);
320-
azx_writew(chip, RIRBCTL, 0); // DMA Stop, Disable Interrupt
321-
do {
322-
c = azx_readb(chip, RIRBCTL);
323-
if ((c & 2) == 0) {
324-
break;
325-
}
326-
pds_delay_10us(10);
327-
} while (--timeout);
328-
azx_writel(chip, GCTL, (azx_readl(chip, GCTL) & (~ICH6_GCTL_UREN)));
343+
switch_to_pio(chip);
329344
goto retry;
330345
}
331346
return r;
@@ -807,6 +822,7 @@ static unsigned int snd_ihd_buffer_init(struct mpxplay_audioout_info_s *aui,stru
807822
#if SBEMU_USE_CORB
808823
card->corb_buffer = (long*)(((uint32_t)card->pcmout_buffer + card->pcmout_bufsize + HDA_CORB_ALIGN-1)&(~(HDA_CORB_ALIGN-1)));
809824
card->rirb_buffer = (long long*)(((uint32_t)card->corb_buffer + HDA_CORB_MAXSIZE + HDA_RIRB_ALGIN-1)&(~(HDA_RIRB_ALGIN-1)));
825+
card->first_rirb = 1;
810826
#endif
811827

812828
gcap = (unsigned long)azx_readw(card,GCAP);
@@ -858,8 +874,45 @@ static unsigned int snd_ihd_mixer_init(struct intelhd_card_s *card)
858874
mpxplay_debugf(IHD_DEBUG_OUTPUT,"snd_ihd_mixer_init start");
859875

860876
card->codec_vendor_id = snd_hda_param_read(card, AC_NODE_ROOT,AC_PAR_VENDOR_ID);
861-
if(card->codec_vendor_id <=0)
862-
card->codec_vendor_id = snd_hda_param_read(card, AC_NODE_ROOT,AC_PAR_VENDOR_ID);
877+
if(card->codec_vendor_id <=0){
878+
// Heuristic to switch problematic chipsets to PIO
879+
azx_writeb(card, CORBCTL, 0); // DMA Stop
880+
int timeout = 2000;
881+
int c;
882+
do {
883+
c = azx_readb(card, CORBCTL);
884+
pds_delay_10us(10);
885+
if ((c & 2) == 0) {
886+
break;
887+
}
888+
} while (--timeout);
889+
azx_writel(card, CORBRP, 1<<15); // Reset
890+
//pds_delay_10us(100); // need this delay? -> no
891+
timeout = 2000;
892+
do {
893+
int rp = azx_readl(card, CORBRP);
894+
if (rp & (1<<15)) break;
895+
pds_delay_10us(10);
896+
} while (--timeout);
897+
//printf("Intel HDA: CORBRP timeout %d\n", timeout);
898+
mpxplay_debugf(IHD_DEBUG_OUTPUT,"corbrp timeout %d\n", timeout);
899+
if (timeout > 0) {
900+
card->config_select |= AUCARDSCONFIG_IHD_USE_PIO;
901+
switch_to_pio(card);
902+
azx_writel(card, CORBRP, 0); // No sound without this!
903+
pds_delay_10us(100);
904+
card->codec_vendor_id = snd_hda_param_read(card, AC_NODE_ROOT,AC_PAR_VENDOR_ID);
905+
} else {
906+
timeout = 2000;
907+
azx_writel(card, CORBRP, 0);
908+
do {
909+
int rp = azx_readl(card, CORBRP);
910+
if (rp & (1<<15) == 0) break;
911+
pds_delay_10us(10);
912+
} while (--timeout);
913+
card->codec_vendor_id = snd_hda_param_read(card, AC_NODE_ROOT,AC_PAR_VENDOR_ID);
914+
}
915+
}
863916
mpxplay_debugf(IHD_DEBUG_OUTPUT,"codec vendor id:%8.8X",card->codec_vendor_id);
864917

865918
snd_hda_search_audio_node(card);

0 commit comments

Comments
 (0)