changed codec detection and special ICH4 handling

git-svn-id: file:///srv/svn/repos/haiku/trunk/current@793 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
beveloper 2002-08-17 19:59:33 +00:00
parent 1ddfa2f84e
commit 33d6854bee
6 changed files with 98 additions and 63 deletions

View File

@ -29,6 +29,7 @@
#include <stdio.h> #include <stdio.h>
#include <MediaDefs.h> #include <MediaDefs.h>
#include "ac97.h" #include "ac97.h"
#include "config.h"
//#define DEBUG 1 //#define DEBUG 1
@ -114,20 +115,20 @@ ac97_amp_enable(bool yesno)
{ {
LOG(("using Cirrus enable")); LOG(("using Cirrus enable"));
if (yesno) if (yesno)
ich_codec_write(0x68, 0x8004); ich_codec_write(config->codecoffset + 0x68, 0x8004);
else else
ich_codec_write(0x68, 0); ich_codec_write(config->codecoffset + 0x68, 0);
break; break;
} }
default: default:
{ {
LOG(("powerdown register was = %#04x\n",ich_codec_read(AC97_POWERDOWN))); LOG(("powerdown register was = %#04x\n",ich_codec_read(config->codecoffset + AC97_POWERDOWN)));
if (yesno) if (yesno)
ich_codec_write(AC97_POWERDOWN, ich_codec_read(AC97_POWERDOWN) & ~0x8000); /* switch on (low active) */ ich_codec_write(config->codecoffset + AC97_POWERDOWN, ich_codec_read(AC97_POWERDOWN) & ~0x8000); /* switch on (low active) */
else else
ich_codec_write(AC97_POWERDOWN, ich_codec_read(AC97_POWERDOWN) | 0x8000); /* switch off */ ich_codec_write(config->codecoffset + AC97_POWERDOWN, ich_codec_read(AC97_POWERDOWN) | 0x8000); /* switch off */
LOG(("powerdown register is = %#04x\n",ich_codec_read(AC97_POWERDOWN))); LOG(("powerdown register is = %#04x\n",ich_codec_read(config->codecoffset + AC97_POWERDOWN)));
break; break;
} }
} }
@ -140,7 +141,7 @@ ac97_init()
{ {
case 0x41445461: /* Analog Devices AD1886 */ case 0x41445461: /* Analog Devices AD1886 */
LOG(("using AD1886 init")); LOG(("using AD1886 init"));
ich_codec_write(0x72, 0x0010); ich_codec_write(config->codecoffset + 0x72, 0x0010);
break; break;
default: default:
break; break;

View File

@ -82,6 +82,7 @@ status_t probe_device(void)
config->log_mbbar = 0; config->log_mbbar = 0;
config->area_mmbar = -1; config->area_mmbar = -1;
config->area_mbbar = -1; config->area_mbbar = -1;
config->codecoffset = 0;
result = B_ERROR; result = B_ERROR;
cookie = 0; cookie = 0;

View File

@ -43,6 +43,7 @@ typedef struct
void * log_mbbar; // ich4 void * log_mbbar; // ich4
area_id area_mmbar; // ich4 area_id area_mmbar; // ich4
area_id area_mbbar; // ich4 area_id area_mbbar; // ich4
uint32 codecoffset;
} device_config; } device_config;
extern device_config *config; extern device_config *config;

View File

@ -33,7 +33,8 @@ enum ICH_GLOBAL_REGISTER
{ {
ICH_REG_GLOB_CNT = 0x2C, ICH_REG_GLOB_CNT = 0x2C,
ICH_REG_GLOB_STA = 0x30, ICH_REG_GLOB_STA = 0x30,
ICH_REG_ACC_SEMA = 0x34 ICH_REG_ACC_SEMA = 0x34,
ICH_REG_SDM = 0x80
}; };
enum ICH_X_REGISTER_BASE /* base addresses for the following offsets */ enum ICH_X_REGISTER_BASE /* base addresses for the following offsets */
@ -94,10 +95,10 @@ enum REG_GLOB_STA_BITS
STA_PIINT = 0x00000020, /* PCM In Interrupt */ STA_PIINT = 0x00000020, /* PCM In Interrupt */
STA_POINT = 0x00000040, /* PCM Out Interrupt */ STA_POINT = 0x00000040, /* PCM Out Interrupt */
STA_MINT = 0x00000080, /* Mic In Interrupt */ STA_MINT = 0x00000080, /* Mic In Interrupt */
STA_PCR = 0x00000100, /* AC_SDIN0 Codec Ready */ STA_S0CR = 0x00000100, /* AC_SDIN0 Codec Ready */
STA_SCR = 0x00000200, /* AC_SDIN1 Codec Ready */ STA_S1CR = 0x00000200, /* AC_SDIN1 Codec Ready */
STA_PRI = 0x00000400, /* AC_SDIN0 Resume Interrupt */ STA_S0RI = 0x00000400, /* AC_SDIN0 Resume Interrupt */
STA_SRI = 0x00000800, /* AC_SDIN1 Resume Interrupt */ STA_S1RI = 0x00000800, /* AC_SDIN1 Resume Interrupt */
STA_RCS = 0x00008000, /* Read Completition Status */ STA_RCS = 0x00008000, /* Read Completition Status */
STA_AD3 = 0x00010000, STA_AD3 = 0x00010000,
STA_MD3 = 0x00020000, STA_MD3 = 0x00020000,
@ -107,7 +108,7 @@ enum REG_GLOB_STA_BITS
STA_BCS = 0x08000000, /* Bit Clock Stopped */ STA_BCS = 0x08000000, /* Bit Clock Stopped */
STA_S2CR = 0x10000000, /* AC_SDIN2 Codec Ready */ STA_S2CR = 0x10000000, /* AC_SDIN2 Codec Ready */
STA_S2RI = 0x20000000, /* AC_SDIN2 Resume Interrupt */ STA_S2RI = 0x20000000, /* AC_SDIN2 Resume Interrupt */
STA_INTMASK = (STA_MIINT | STA_MOINT | STA_PIINT | STA_POINT | STA_MINT | STA_PRI | STA_SRI | STA_M2INT | STA_P2INT | STA_SPINT | STA_S2RI) STA_INTMASK = (STA_MIINT | STA_MOINT | STA_PIINT | STA_POINT | STA_MINT | STA_S0RI | STA_S1RI | STA_M2INT | STA_P2INT | STA_SPINT | STA_S2RI)
}; };
#define ICH_BD_COUNT 32 #define ICH_BD_COUNT 32

View File

@ -337,6 +337,7 @@ init_driver(void)
{ {
status_t rv; status_t rv;
bigtime_t start; bigtime_t start;
bool s0cr, s1cr, s2cr;
LOG_CREATE(); LOG_CREATE();
@ -374,57 +375,87 @@ init_driver(void)
LOG(("cold reset failed\n")); LOG(("cold reset failed\n"));
} }
/* wait until a codec is ready */ /* detect which codecs are ready */
s0cr = s1cr = s2cr = false;
start = system_time(); start = system_time();
while ((system_time() - start) < 1000000) { do {
rv = ich_reg_read_32(ICH_REG_GLOB_STA); rv = ich_reg_read_32(ICH_REG_GLOB_STA);
if ((rv & STA_PCR) != 0) if (!s0cr && (rv & STA_S0CR)) {
break; s0cr = true;
LOG(("AC_SDIN0 codec ready after %Ld us\n",(system_time() - start)));
}
if (!s1cr && (rv & STA_S1CR)) {
s1cr = true;
LOG(("AC_SDIN1 codec ready after %Ld us\n",(system_time() - start)));
}
if (!s2cr && (rv & STA_S2CR)) {
s2cr = true;
LOG(("AC_SDIN2 codec ready after %Ld us\n",(system_time() - start)));
}
snooze(50000); snooze(50000);
} while ((system_time() - start) < 1000000);
if (!s0cr) {
LOG(("AC_SDIN0 codec not ready\n"));
} }
if ((rv & STA_PCR)) { if (!s1cr) {
LOG(("primary codec ready after %Ld us\n",(system_time() - start))); LOG(("AC_SDIN1 codec not ready\n"));
} else {
LOG(("primary codec not ready after %Ld us\n",(system_time() - start)));
} }
while ((system_time() - start) < 1000000) { if (!s2cr) {
rv = ich_reg_read_32(ICH_REG_GLOB_STA); LOG(("AC_SDIN2 codec not ready\n"));
if ((rv & STA_SCR) != 0)
break;
snooze(50000);
}
if ((rv & STA_SCR)) {
LOG(("secondary codec ready after %Ld us\n",(system_time() - start)));
} else {
LOG(("secondary codec not ready after %Ld us\n",(system_time() - start)));
}
while ((system_time() - start) < 1000000) {
rv = ich_reg_read_32(ICH_REG_GLOB_STA);
if ((rv & STA_S2CR) != 0)
break;
snooze(50000);
}
if ((rv & STA_S2CR)) {
LOG(("tertiary codec ready after %Ld us\n",(system_time() - start)));
} else {
LOG(("tertiary codec not ready after %Ld us\n",(system_time() - start)));
} }
dump_hardware_regs(); dump_hardware_regs();
if ((rv & (STA_PCR | STA_SCR | STA_S2CR)) == 0) { if (!s0cr && !s1cr && !s2cr) {
PRINT(("compatible chipset found, but no codec ready!\n")); PRINT(("compatible chipset found, but no codec ready!\n"));
unmap_io_memory(); unmap_io_memory();
return B_ERROR; return B_ERROR;
} }
if ((rv & STA_PCR) == 0 && (rv & STA_S2CR) != 0) {
LOG(("using tertiary codec!\n")); if (config->type & TYPE_ICH4) {
config->nambar += 0x100; /* we are using a ICH4 chipset, and assume that the codec beeing ready
config->log_mmbar += 0x100; /* ICH 4 */ * is the primary one.
} else if ((rv & STA_PCR) == 0 && (rv & STA_SCR) != 0) { */
LOG(("using secondary codec!\n")); uint8 sdin;
config->nambar += 0x80; uint16 reset;
config->log_mmbar += 0x80; /* ICH 4 */ uint8 id;
reset = ich_codec_read(0x00); /* access the primary codec */
if (reset == 0 || reset == 0xFFFF) {
LOG(("primary codec not present\n"));
} //else {
sdin = 0x02 & ich_reg_read_8(ICH_REG_SDM);
id = 0x02 & (ich_codec_read(0x00 + 0x28) >> 14);
LOG(("primary codec id %d is connected to AC_SDIN%d\n", id, sdin));
//}
reset = ich_codec_read(0x80); /* access the secondary codec */
if (reset == 0 || reset == 0xFFFF) {
LOG(("secondary codec not present\n"));
} //else {
sdin = 0x02 & ich_reg_read_8(ICH_REG_SDM);
id = 0x02 & (ich_codec_read(0x80 + 0x28) >> 14);
LOG(("secondary codec id %d is connected to AC_SDIN%d\n", id, sdin));
//}
reset = ich_codec_read(0x100); /* access the tertiary codec */
if (reset == 0 || reset == 0xFFFF) {
LOG(("tertiary codec not present\n"));
} //else {
sdin = 0x02 & ich_reg_read_8(ICH_REG_SDM);
id = 0x02 & (ich_codec_read(0x100 + 0x28) >> 14);
LOG(("tertiary codec id %d is connected to AC_SDIN%d\n", id, sdin));
//}
/* XXX this may be wrong */
ich_reg_write_8(ICH_REG_SDM, (ich_reg_read_8(ICH_REG_SDM) & 0x0F) | 0x08 | 0x90);
} else {
/* we are using a pre-ICH4 chipset, that has a fixed mapping of
* AC_SDIN0 = primary, AC_SDIN1 = secondary codec.
*/
if (!s0cr && s2cr) {
// is is unknown if this really works, perhaps we should better abort here
LOG(("primary codec doesn't seem to be available, using secondary!\n"));
config->codecoffset = 0x80;
}
} }
dump_hardware_regs(); dump_hardware_regs();
@ -480,9 +511,9 @@ init_driver(void)
chan_po->regbase = ICH_REG_PO_BASE; chan_po->regbase = ICH_REG_PO_BASE;
chan_mc->regbase = ICH_REG_MC_BASE; chan_mc->regbase = ICH_REG_MC_BASE;
/* reset the (primary?) codec */ /* reset the codec */
LOG(("codec reset\n")); LOG(("codec reset\n"));
ich_codec_write(0x00, 0x0000); ich_codec_write(config->codecoffset + 0x00, 0x0000);
snooze(50000); // 50 ms snooze(50000); // 50 ms
ac97_init(); ac97_init();
@ -517,24 +548,24 @@ init_driver(void)
} }
/* enable master output */ /* enable master output */
ich_codec_write(0x02, 0x0000); ich_codec_write(config->codecoffset + 0x02, 0x0000);
/* enable pcm output */ /* enable pcm output */
ich_codec_write(0x18, 0x0404); ich_codec_write(config->codecoffset + 0x18, 0x0404);
#if 0 #if 0
/* enable pcm input */ /* enable pcm input */
ich_codec_write(0x10, 0x0000); ich_codec_write(config->codecoffset + 0x10, 0x0000);
/* enable mic input */ /* enable mic input */
/* ich_codec_write(0x0E, 0x0000); */ /* ich_codec_write(config->codecoffset + 0x0E, 0x0000); */
/* select pcm input record */ /* select pcm input record */
ich_codec_write(0x1A, 4 | (4 << 8)); ich_codec_write(config->codecoffset + 0x1A, 4 | (4 << 8));
/* enable PCM record */ /* enable PCM record */
ich_codec_write(0x1C, 0x0000); ich_codec_write(config->codecoffset + 0x1C, 0x0000);
/* enable mic record */ /* enable mic record */
/* ich_codec_write(0x1E, 0x0000); */ /* ich_codec_write(config->codecoffset + 0x1E, 0x0000); */
#endif #endif
LOG(("init_driver finished!\n")); LOG(("init_driver finished!\n"));
@ -615,9 +646,9 @@ int32 ich_int(void *unused)
if ((sta & STA_INTMASK) == 0) if ((sta & STA_INTMASK) == 0)
return B_UNHANDLED_INTERRUPT; return B_UNHANDLED_INTERRUPT;
if (sta & (STA_PRI | STA_SRI)) { if (sta & (STA_S0RI | STA_S1RI | STA_S2RI)) {
/* ignore and clear resume interrupt(s) */ /* ignore and clear resume interrupt(s) */
ich_reg_write_32(ICH_REG_GLOB_STA, sta & (STA_PRI | STA_SRI)); ich_reg_write_32(ICH_REG_GLOB_STA, sta & (STA_S0RI | STA_S1RI | STA_S2RI));
} }
if (sta & STA_POINT) { // pcm-out if (sta & STA_POINT) { // pcm-out

View File

@ -30,7 +30,7 @@
#include "hardware.h" #include "hardware.h"
#define VERSION "Version 1.3, Copyright (c) 2002 Marcus Overhagen, compiled on " ## __DATE__ ## " " ## __TIME__ #define VERSION "Version 1.4, Copyright (c) 2002 Marcus Overhagen, compiled on " ## __DATE__ ## " " ## __TIME__
#define DRIVER_NAME "ich_ac97" #define DRIVER_NAME "ich_ac97"
#define BUFFER_SIZE 2048 #define BUFFER_SIZE 2048