From e2f30062dd35c8c1c3ae0ddddebef15e81341462 Mon Sep 17 00:00:00 2001 From: "Sergey Semyonov (Serge)" Date: Sun, 28 Dec 2008 14:01:01 +0000 Subject: [PATCH] AMD Geode 5536 ac97 support git-svn-id: svn://kolibrios.org@981 a494cfbc-eb01-0410-851d-a64ba20cac60 --- drivers/a5536/geode.asm | 37 +++ drivers/a5536/geode.bat | 3 + drivers/a5536/geode.c | 551 ++++++++++++++++++++++++++++++++++++++++ drivers/a5536/geode.h | 200 +++++++++++++++ drivers/a5536/makefile | 30 +++ drivers/a5536/pci.h | 182 +++++++++++++ 6 files changed, 1003 insertions(+) create mode 100644 drivers/a5536/geode.asm create mode 100644 drivers/a5536/geode.bat create mode 100644 drivers/a5536/geode.c create mode 100644 drivers/a5536/geode.h create mode 100644 drivers/a5536/makefile create mode 100644 drivers/a5536/pci.h diff --git a/drivers/a5536/geode.asm b/drivers/a5536/geode.asm new file mode 100644 index 0000000000..529fd683ac --- /dev/null +++ b/drivers/a5536/geode.asm @@ -0,0 +1,37 @@ + +use32 + +db 'MENUET01' +dd 1 +dd start +dd i_end +dd mem +dd mem +dd 0 +dd 0 + +start: + mov eax, 68 + mov ebx, 16 + mov ecx, sz_sound + int 0x40 + test eax, eax + jnz .exit + + mov eax, 68 + mov ebx, 21 + mov ecx, sz_path + int 0x40 + +.exit: + mov eax, -1 + int 0x40 + + +sz_sound db 'SOUND',0 +sz_path db '/rd/1/drivers/geode.drv',0 + +align 4 +i_end: +rb 128 +mem: diff --git a/drivers/a5536/geode.bat b/drivers/a5536/geode.bat new file mode 100644 index 0000000000..7ec2ec5f3b --- /dev/null +++ b/drivers/a5536/geode.bat @@ -0,0 +1,3 @@ +del geode.dll +make +@pause diff --git a/drivers/a5536/geode.c b/drivers/a5536/geode.c new file mode 100644 index 0000000000..66a69e6696 --- /dev/null +++ b/drivers/a5536/geode.c @@ -0,0 +1,551 @@ + + +#define FORCED_PIO + +#include "types.h" + +#include "pci.h" +#include "syscall.h" + +#include "geode.h" + +#ifdef DEBUG + #define DBG(format,...) dbgprintf(format,##__VA_ARGS__) +#else + #define DBG(format,...) +#endif + +#define BM0_IRQ 0x04 +#define BM1_IRQ 0x08 +#define BITS_8_TO_16(x) ( ( (long) ((unsigned char) x - 128) ) << 8 ) + +#define PCI_VENDOR_ID_NS 0x100b +#define PCI_VENDOR_ID_AMD 0x1022 + + +#ifndef PCI_DEVICE_ID_NS_CS5535_AUDIO + #define PCI_DEVICE_ID_NS_CS5535_AUDIO 0x002e +#endif +#ifndef PCI_DEVICE_ID_AMD_CS5536_AUDIO + #define PCI_DEVICE_ID_AMD_CS5536_AUDIO 0x2093 +#endif + +#define ID_DEV_1 ((PCI_DEVICE_ID_NS_CS5535_AUDIO << 16)|PCI_VENDOR_ID_NS) +#define ID_DEV_2 ((PCI_DEVICE_ID_AMD_CS5536_AUDIO << 16)|PCI_VENDOR_ID_AMD) + +#define SET 1 +#define CLEAR 0 + +int __stdcall srv_sound(ioctl_t *io); + + +PRD_ENTRY __attribute__((aligned(16))) prd_tab[5]; + + +typedef struct +{ + PCITAG pciTag; + Bool is_iomapped; + addr_t F3BAR0; + + Bool fAD1819A; + + int CurrentPowerState; + + addr_t buffer; + addr_t prd_dma; + + addr_t irq_line; + u32_t irq_mask; + + void __stdcall (*callback)(addr_t buffer); +}geode_t; + +geode_t geode; + + +static inline void ctrl_write_32(addr_t reg, u32_t data) +{ + reg+= geode.F3BAR0; + +#ifdef FORCED_PIO + out32((u16_t)reg, data); +#else + if(geode.is_iomapped) + out32((u16_t)reg, data); + else + *(u32_t*)reg = data; +#endif +} + +static inline u32_t ctrl_read_32(addr_t reg) +{ + reg+= geode.F3BAR0; +#ifdef FORCED_PIO + return in32((u16_t)reg); +#else + if(geode.is_iomapped) + return in32((u16_t)reg); + else + return *(u32_t*)reg; +#endif +} + + + +Bool snd_hw_WaitForBit(addr_t offset, u32_t Bit, + unsigned char Operation, + count_t timeout, + u32_t *pReturnValue) +{ + volatile u32_t tmp; + + tmp = ctrl_read_32(offset); + + while (timeout) + { + if (Operation==CLEAR){ + if (!(tmp & Bit)) + break; + } else if (tmp & Bit) + break; + + /*If the Bit is not clear yet, we wait for 10 milisecond and try again*/ + delay(10/10); + + tmp = ctrl_read_32(offset); + + timeout--; + }; + + if (pReturnValue) + *pReturnValue=tmp; + + if (!timeout) + return FALSE; + + return TRUE; +} + +u16_t snd_hw_CodecRead ( u8_t CodecRegister ) +{ + u32_t CodecRegister_data = 0; + u32_t timeout=10; + volatile u32_t val=0; + + CodecRegister_data = ((u32_t)CodecRegister)<<24; + CodecRegister_data |= 0x80000000; /* High-bit set (p.106) is a CODEC reg READ.*/ + +/* Set the bit. We are going to access the CODEC...*/ + CodecRegister_data |= BIT_5535_CODEC_COMMAND_NEW; + +/*Request the data*/ + ctrl_write_32(CODEC_CONTROL_REG_5535, CodecRegister_data); + +/* Now we need to wait for BIT_5535_CODEC_COMMAND_NEW of the Codec control register to clear + (For subsequent Reads/Writes)*/ + if (!snd_hw_WaitForBit (CODEC_CONTROL_REG_5535, + BIT_5535_CODEC_COMMAND_NEW, CLEAR, 50, NULL)) + DBG("BIT_5535_CODEC_COMMAND_NEW did not clear!!\n"); + +/* Wait for CODEC_STATUS_NEW and confirm the read of the requested register*/ + timeout = 50; + do + { + val = ctrl_read_32(CODEC_STATUS_REG_5535); + if ((val & BIT_5535_CODEC_STATUS_NEW) && + ((u32_t) CodecRegister == ((0xFF000000 & val)>>24))) + break; + else + /*Wait for 10 miliseconds and try again*/ + delay(10/10); + } while ( --timeout); + + if (!timeout) + DBG("Could not read the CODEC!! Returning what we got.\n"); + + return( (u16_t)val ); +} + +void snd_hw_CodecWrite( u8_t CodecRegister, u16_t CodecData ) +{ + u32_t CodecRegister_data; + u32_t Temp, timeout; + + CodecRegister_data = ((u32_t) CodecRegister)<<24; + CodecRegister_data |= (u32_t) CodecData; + CodecRegister_data &= CODEC_COMMAND_MASK; + + /*Set the bit. We are going to access the CODEC...*/ + CodecRegister_data |= BIT_5535_CODEC_COMMAND_NEW; + + /*Write the data*/ + ctrl_write_32(CODEC_CONTROL_REG_5535, CodecRegister_data); + //OS_DbgMsg("Writing: %08X\n", CodecRegister_data); + + /*We need to wait for bit16 of the Codec control register to clear*/ + Temp = ctrl_read_32(CODEC_CONTROL_REG_5535); + + timeout = 50; + + while ((Temp & BIT_5535_CODEC_COMMAND_NEW) && timeout-- ) + Temp = ctrl_read_32(CODEC_CONTROL_REG_5535); + + if (!timeout) + DBG("Could not Write the CODEC!!\n" + "BIT_5535_CODEC_COMMAND_NEW did not clear!\n"); +} + + +void snd_hw_SetCodecRate(u32_t SampleRate) +{ + u16_t val; + + DBG("Rate: %d\n", SampleRate); + + /*If Double-Rate is supported (Bit 2 on register 28h)...*/ + val=snd_hw_CodecRead(EXTENDED_AUDIO_ID); + + if (val & 0x02) + { + DBG("Codec supports Double rate.\n"); + val=snd_hw_CodecRead(EXT_AUDIO_CTRL_STAT); + + if (SampleRate>48000) + { + snd_hw_CodecWrite(EXT_AUDIO_CTRL_STAT, (u16_t) (val|0x0002)); + SampleRate/=2; + } + else + snd_hw_CodecWrite(EXT_AUDIO_CTRL_STAT, (u16_t) (val&0xFFFD)); + } + if (geode.fAD1819A) + { + DBG("AD1819...\n"); + snd_hw_CodecWrite(AD1819A_PCM_SR0,(u16_t)SampleRate); + } + else + snd_hw_CodecWrite(PCM_FRONT_DAC_RATE,(u16_t)SampleRate); +} + +Bool init_device() +{ + u32_t io_base = pciReadLong(geode.pciTag, 0x10); + + if( PCI_MAP_IS_IO(io_base)) + { + geode.is_iomapped = TRUE; + geode.F3BAR0 = PCIGETIO(io_base); + DBG("io mapped F3BAR0 %x\n", geode.F3BAR0); + } + else if(PCI_MAP_IS_MEM(io_base)) + { + geode.is_iomapped = FALSE; + io_base = PCIGETMEMORY(io_base); + geode.F3BAR0 = MapIoMem(io_base, 128, PG_SW+PG_NOCACHE); + DBG("memory mapped F3BAR0 %x\n", geode.F3BAR0); + } + + geode.buffer = KernelAlloc(64*1024); + + addr_t buffer = geode.buffer; + addr_t dma = GetPgAddr(geode.buffer); + + geode.prd_dma = (((addr_t)prd_tab) & 4095) + GetPgAddr((void*)prd_tab); + + prd_tab[0].ulPhysAddr = dma; + prd_tab[0].SizeFlags = 16384 | PRD_EOP_BIT ; + + prd_tab[1].ulPhysAddr = dma + 16384; + prd_tab[1].SizeFlags = 16384 | PRD_EOP_BIT ; + + prd_tab[2].ulPhysAddr = dma + 16384*2; + prd_tab[2].SizeFlags = 16384 | PRD_EOP_BIT ; + + prd_tab[3].ulPhysAddr = dma + 16384*3; + prd_tab[3].SizeFlags = 16384 | PRD_EOP_BIT ; + + prd_tab[4].ulPhysAddr = geode.prd_dma; + prd_tab[4].SizeFlags = PRD_JMP_BIT ; + + ctrl_write_32(0x24, geode.prd_dma); + + __clear((void*)buffer,64*1024); +// u32_t tmp = ctrl_read_32(0x24); + +// dbgprintf("Create primary buffer at %x dma at %x\n", geode.buffer, dma ); + +// dbgprintf("Set prd dma %x, read prd dma %x\n", geode.prd_dma, tmp); + + geode.irq_line = pciReadLong(geode.pciTag, 0x3C) & 0xFF; + geode.irq_mask = ~(1<>8) | + AD1819A_SER_CONF_DRQEN); + DBG("detect AD1819A audio codec\n"); + } + else + { + geode.fAD1819A = FALSE; + snd_hw_CodecWrite (EXT_AUDIO_CTRL_STAT, + (snd_hw_CodecRead(EXT_AUDIO_CTRL_STAT) | 0x0001)); + /* set the VRA bit to ON*/ + } + + /* set default volume*/ + snd_hw_CodecWrite( MASTER_VOLUME, 0x0B0B); + snd_hw_CodecWrite( PCM_OUT_VOL, 0x0808); + snd_hw_CodecWrite( PC_BEEP_VOLUME, 0x0000); + snd_hw_CodecWrite( PHONE_VOLUME, 0x8000); + snd_hw_CodecWrite( MIC_VOLUME, 0x8048); + snd_hw_CodecWrite( LINE_IN_VOLUME, 0x0808); + snd_hw_CodecWrite( CD_VOLUME, 0x8000); + snd_hw_CodecWrite( VIDEO_VOLUME, 0x8000); + snd_hw_CodecWrite( TV_VOLUME, 0x8000); + snd_hw_CodecWrite( RECORD_SELECT, 0x0000); + snd_hw_CodecWrite( RECORD_GAIN, 0x0a0a); + snd_hw_CodecWrite( GENERAL_PURPOSE, 0x0200); + snd_hw_CodecWrite( MASTER_VOLUME_MONO, 0x0000); + + snd_hw_SetCodecRate(48000); + /*Set all the power state bits to 0 (Reg 26h)*/ + snd_hw_CodecWrite (POWERDOWN_CTRL_STAT, 0x0000); + geode.CurrentPowerState = GEODEAUDIO_D0; +// OS_DbgMsg("<--snd_hw_InitAudioRegs\n"); + + + return TRUE; +} + +static int snd_StartDMA () +{ + +#ifdef FORCED_PIO + out8( (u16_t)(geode.F3BAR0+0x20),PCI_READS | ENABLE_BUSMASTER); +#else + if (geode.is_iomapped) + out8( (u16_t)(geode.F3BAR0+0x20),PCI_READS | ENABLE_BUSMASTER); + else + *(u8_t*)(geode.F3BAR0+0x20)= PCI_READS | ENABLE_BUSMASTER; +#endif + return 0; +}; + +static u8_t snd_hw_InterruptID () +{ + volatile u8_t *TempInterruptID, ID; + +#ifdef FORCED_PIO + ID=(u8_t) in16((u16_t)(geode.F3BAR0 + 0x12)); +#else + if (geode.is_iomapped) + ID=(u8_t) in16((u16_t)(geode.F3BAR0 + 0x12)); + else + { + TempInterruptID=(u8_t*)(geode.F3BAR0 + 0x12); + ID=*TempInterruptID; + } +#endif + return (ID); +} + + +static u8_t snd_hw_ClearStat(int Channel) +{ + volatile u8_t status; /*Volatile to force read-to-clear.*/ + + /*Read to clear*/ + +#ifdef FORCED_PIO + status = in8((u16_t) geode.F3BAR0 + 0x21); +#else + if (geode.is_iomapped) + status = in8((u16_t) geode.F3BAR0 + 0x21); + else + status = *((u8_t*)geode.F3BAR0 + 0x21); +#endif + return status; +} + + +void snd_interrupt() +{ + u8_t IntID; + + IntID = snd_hw_InterruptID(); + +// dbgprintf("IRQ id %x\n", IntID); + + snd_hw_ClearStat(CHANNEL0_PLAYBACK); +// snd_hw_ClearStat(CHANNEL1_RECORD); + + if(IntID & BM0_IRQ) + { + addr_t prd, offset, base; + + prd = ctrl_read_32(0x24); + offset = (1 + (prd - geode.prd_dma)>>3) & 3; + + base = geode.buffer + 16384*offset; + + geode.callback(base); + __asm__ volatile("":::"ebx","esi","edi"); + +// dbgprintf(">>BM0_IRQ prd %x offset %x base %x\n", prd, offset, base); + }; +}; + +Bool FindPciDevice() +{ + u32_t bus, last_bus; + PCITAG tag; + + if( (last_bus = PciApi(1))==-1) + return FALSE; + + for(bus=0;bus<=last_bus;bus++) + { + u32_t devfn; + + for(devfn=0;devfn<256;devfn++) + { + u32_t pciId=0; + + pciId = PciRead32(bus,devfn, 0); + + if( (pciId == ID_DEV_1) || + (pciId == ID_DEV_2) ) + { + DBG("detect companion audio device %x\n", pciId); + geode.pciTag = pciTag(bus,(devfn>>3)&0x1F,devfn&0x7); + return TRUE; + }; + }; + }; + return FALSE; +}; + + +u32_t __stdcall drvEntry(int action) +{ + u32_t retval; + + int i; + + if(action != 1) + return 0; + +#ifdef DEBUG + if(!dbg_open("/rd/1/drivers/geode.log")) + { + printf("Can't open /rd/1/drivers/geode.log\nExit\n"); + return 0; + } +#endif + + if( FindPciDevice() == FALSE) + { + DBG("Device not found\n"); + return 0; + }; + + init_device(); + + retval = RegService("SOUND", srv_sound); + + AttachIntHandler(geode.irq_line, snd_interrupt, 0); + + DBG("reg service %s as: %x\n", "SOUND", retval); + + return retval; +}; + + +#define API_VERSION 0x01000100 + +#define SRV_GETVERSION 0 +#define DEV_PLAY 1 +#define DEV_STOP 2 +#define DEV_CALLBACK 3 +#define DEV_SET_BUFF 4 +#define DEV_NOTIFY 5 +#define DEV_SET_MASTERVOL 6 +#define DEV_GET_MASTERVOL 7 +#define DEV_GET_INFO 8 + + +int __stdcall srv_sound(ioctl_t *io) +{ + u32_t *inp; + u32_t *outp; + + inp = io->input; + outp = io->output; + + switch(io->io_code) + { + case SRV_GETVERSION: + if(io->out_size==4) + { + *outp = API_VERSION; + return 0; + } + break; + + case DEV_PLAY: + return snd_StartDMA(); + break; + + case DEV_STOP: + break; + + case DEV_CALLBACK: + if(io->inp_size==4) + { + geode.callback = (void*)(*inp); + return 0; + } + break; + + default: + return ERR_PARAM; + }; + return ERR_PARAM; +} + + diff --git a/drivers/a5536/geode.h b/drivers/a5536/geode.h new file mode 100644 index 0000000000..0d7ace7cbf --- /dev/null +++ b/drivers/a5536/geode.h @@ -0,0 +1,200 @@ + + +// +// Device and Vendor IDs - Needed like this for OSS only +// +#define CYRIX_VENDOR_ID 0x1078 +#define NATIONAL_VENDOR_ID 0x100B + +// +// Audio Device IDs +// +#define CX5530_DEV_ID 0x0103 +#define SC1200_DEV_ID 0x0503 +#define CS5535_DEV_ID 0x002E + +// +// Function 3 of 5530 PCI dev is Audio (ISA idx). +// +#define PCI_FUNC3_AUDIO 0x300 +#define PCI_AUDIO_CMD_REG 0x04 + +typedef unsigned char AUDIO_STATE; + +#define AUDIO_STATE_IGNORE 0 +#define AUDIO_STATE_IN_RECORDING 0x01 +#define AUDIO_STATE_IN_OVERFLOW 0x02 +#define AUDIO_STATE_IN_STOPPED 0x03 +#define AUDIO_STATE_IN_MASK 0x0F +#define AUDIO_STATE_OUT_PLAYING 0x10 +#define AUDIO_STATE_OUT_UNDERFLOW 0x20 +#define AUDIO_STATE_OUT_STOPPED 0x30 +#define AUDIO_STATE_OUT_MASK 0xF0 + +#define RECORD_RUNNING 0x01 +#define RECORD_OVERFLOW 0x02 +#define RECORD_STOPPED 0x03 + +#define PLAYBACK_RUNNING 0x10 +#define PLAYBACK_UNDERFLOW 0x20 +#define PLAYBACK_STOPPED 0x30 + +// +// The CODEC commands are actually 16-bit words, into which is inserted +// the codec "target" register, identified by a byte. The 5530 Codec +// controller writes a command unsigned short of 32-bits, that includes the codec +// command unsigned short. +// +#define CODEC_COMMAND_MASK 0xFF00FFFF + +// +// The Interaction with the CODEC is a bit cumbersome +// because of the serial interface. +// +#define CODEC_STATUS_REG 0x08 // In Audio mem-map. +#define CODEC_CMD_REG 0x0c // In audio mem-map. +#define CODEC_CMD_VALID 0x00010000 +#define CODEC_STATUS_VALID 0x00020000 +#define CODEC_STATUS_NEW 0x00010000 +#define BIT_CODEC_READY 0x00800000 + +// +// Registers for the 5535 +// +#define CODEC_STATUS_REG_5535 0x08 +#define CODEC_CONTROL_REG_5535 0x0c + +// +// 5535 Bits +// +#define BIT_5535_CODEC_COMMAND_NEW 0x00010000 +#define BIT_5535_CODEC_STATUS_NEW 0x00020000 +#define BIT_5535_ACLINK_SHUTDOWN 0x00040000 +#define BIT_5535_ACLINK_WARM_RESET 0x00020000 +#define BIT_5535_CODEC_READY_PRIM 0x00800000 + +// +// Codec register indexes. Note these are all shifted left by 16 bits. +// +#define RESET 0x00 +#define MASTER_VOLUME 0x02 +#define LINE_LEV_OUT_VOL 0x04 +#define MASTER_VOLUME_MONO 0x06 +#define MASTER_TONE_RL 0x08 +#define PC_BEEP_VOLUME 0x0a +#define PHONE_VOLUME 0x0c +#define MIC_VOLUME 0x0e +#define LINE_IN_VOLUME 0x10 +#define CD_VOLUME 0x12 +#define VIDEO_VOLUME 0x14 +#define TV_VOLUME 0x16 +#define PCM_OUT_VOL 0x18 +#define RECORD_SELECT 0x1a +#define RECORD_GAIN 0x1c +#define RECORD_MIC_GAIN 0x1e +#define GENERAL_PURPOSE 0x20 +#define CONTROL_3D 0x22 +#define MODEM_RATE 0x24 +#define POWERDOWN_CTRL_STAT 0x26 +#define EXTENDED_AUDIO_ID 0x28 +#define EXT_AUDIO_CTRL_STAT 0x2A +#define PCM_FRONT_DAC_RATE 0x2C +#define PCM_LR_ADC_RATE 0x32 +#define VENDOR_ID1 0x7c +#define VENDOR_ID2 0x7e + +#define MUTE_MASK 0x8000 +#define HEADHONE_AVAIL 0x0010 +#define LINE_LEV_RESET_VOL 0x0000 // the reset without the mask + +#ifdef AC97_2DOT1_6BIT_COMPLIANT +# define MASTER_ATTEN_CTL_BITS 6 +#else +# define MASTER_ATTEN_CTL_BITS 5 +#endif + +#define MASTER_VOLUME_MAX ( ( 1 << MASTER_ATTEN_CTL_BITS ) - 1 ) +#define LINE_LEV_OUT_MAX ( ( 1 << MASTER_ATTEN_CTL_BITS ) - 1 ) + +// +// AD1819A registers +// +#define AD1819A_SER_CONF 0x74 +#define AD1819A_SER_CONF_DRQEN 0x08 +#define AD1819A_MISC 0x76 +#define AD1819A_PCM_SR0 0x78 +#define AD1819A_PCM_SR1 0x7A +#define AD1819A_VENDORID1 0x7C +#define AD1819A_VENDORID2 0x7E + +// +// Power Management bits +// +#define GEODEAUDIO_PWR_PR0 0x0100 // PCM in ADC's & input Mux Powerdown +#define GEODEAUDIO_PWR_PR1 0x0200 // PCM out DACs Powerdown +#define GEODEAUDIO_PWR_PR2 0x0400 // Analog Mixer powerdown (Vref still on) +#define GEODEAUDIO_PWR_PR3 0x0800 // Analog Mxer powerdown (Vref off) +#define GEODEAUDIO_PWR_PR4 0x1000 // Digital interface (AC-link) powerdown (external clk off) +#define GEODEAUDIO_PWR_PR5 0x2000 // Internal Clk disable +#define GEODEAUDIO_PWR_PR6 0x4000 // HP amp powerdown +#define GEODEAUDIO_PWR_PR7 0x8000 // External Amplifier Power Down + +#define GEODEAUDIO_PWR_D0 0x0000 +#define GEODEAUDIO_PWR_D1 GEODEAUDIO_PWR_EXTOFF +#define GEODEAUDIO_PWR_D2 GEODEAUDIO_PWR_PR0|GEODEAUDIO_PWR_PR1|GEODEAUDIO_PWR_PR2|GEODEAUDIO_PWR_PR6|GEODEAUDIO_PWR_PR7 +#define GEODEAUDIO_PWR_D3 GEODEAUDIO_PWR_PR0|GEODEAUDIO_PWR_PR1|GEODEAUDIO_PWR_PR2|GEODEAUDIO_PWR_PR6|GEODEAUDIO_PWR_PR7 +#define GEODEAUDIO_PWR_D4 GEODEAUDIO_PWR_PR0|GEODEAUDIO_PWR_PR1|GEODEAUDIO_PWR_PR2|GEODEAUDIO_PWR_PR3|GEODEAUDIO_PWR_PR4|GEODEAUDIO_PWR_PR5|GEODEAUDIO_PWR_PR6|GEODEAUDIO_PWR_PR7 +#define GEODEAUDIO_PWR_ANLOFF GEODEAUDIO_PWR_PR2|GEODEAUDIO_PWR_PR3 // Analog section OFF +#define GEODEAUDIO_PWR_EXTOFF GEODEAUDIO_PWR_PR6|GEODEAUDIO_PWR_PR7 // HP amp and External Amplifier OFF +#define GEODEAUDIO_PWR_D1_HAWK GEODEAUDIO_PWR_PR0|GEODEAUDIO_PWR_PR1|GEODEAUDIO_PWR_PR2|GEODEAUDIO_PWR_PR3|GEODEAUDIO_PWR_PR4 +#define GEODEAUDIO_PWR_DIGOFF GEODEAUDIO_PWR_PR0|GEODEAUDIO_PWR_PR1 // Digital section OFF + +#define GEODEAUDIO_PWRUP_STEP1 0x0F00 // Clear EAPD,PR6 and AC-link to power up external and HP amp and Digital interface +#define GEODEAUDIO_PWRUP_STEP2 0x0700 // Clear PR3 to power up Analog (Vref off) +#define GEODEAUDIO_PWRUP_STEP3 0x0300 // Clear PR2 to power up Analog (Vref on) +#define GEODEAUDIO_PWRUP_STEP4 0x0100 // Clear PR1 to power up DAC +#define GEODEAUDIO_PWRUP_STEP5 0x0000 // Clear PR0 to power up ADC + +#define GEODEAUDIO_CODEC_POWER_ADC 0x0001 +#define GEODEAUDIO_CODEC_POWER_DAC 0x0002 +#define GEODEAUDIO_CODEC_POWER_ANL 0x0004 +#define GEODEAUDIO_CODEC_POWER_REF 0x0008 + +// +// Device Power States +// +typedef enum _GEODEAUDIO_POWER_STATE +{ + GEODEAUDIO_D0 = 0, // Full On: full power, full functionality + GEODEAUDIO_D1, // Low Power On: fully functional at low power/performance + GEODEAUDIO_D2, // Standby: partially powered with automatic wake + GEODEAUDIO_D3, // Sleep: partially powered with device initiated wake + GEODEAUDIO_D4, // Off: unpowered +} GEODEAUDIO_POWER_STATE, *PGEODEAUDIO_POWER_STATE; + +// PRD table flags +#define PRD_JMP_BIT 0x20000000 +#define PRD_EOP_BIT 0x40000000 +#define PRD_EOT_BIT 0x80000000 + +typedef struct tagPRDEntry +{ + unsigned long ulPhysAddr; + unsigned long SizeFlags; +} PRD_ENTRY, *PPRD_ENTRY; + + +// +// Command register bits +// +#define PCI_READS 0x00 +#define PCI_WRITES 0x08 + +#define ENABLE_BUSMASTER 0x01 +#define PAUSE_BUSMASTER 0x03 +#define STOP_BUSMASTER 0x00 + +#define CHANNEL0_PLAYBACK 0 +#define CHANNEL1_RECORD 1 +#define MAX_CHANNELS 2 + diff --git a/drivers/a5536/makefile b/drivers/a5536/makefile new file mode 100644 index 0000000000..f1ce75adb4 --- /dev/null +++ b/drivers/a5536/makefile @@ -0,0 +1,30 @@ + +CC = gcc +FASM = e:/fasm/fasm.exe +CFLAGS = -c -O2 -fomit-frame-pointer -fno-builtin-printf +LDRHD = -shared -T ld.x -s --file-alignment 32 + +INCLUDES = -I ../include + +HFILES:= ../include/types.h \ + ../include/syscall.h \ + geode.h \ + pci.h + +SRC_DEP:= +GEODE_SRC:= amd_geode.h + +NAME:= geode +GEODE:= geode.dll + +all: $(GEODE) + +$(GEODE): geode.obj $(SRC_DEP) $(HFILES) Makefile + wlink name $(GEODE) SYS nt_dll lib libdrv op offset=0 op nod op maxe=25 op el op STUB=stub.exe op START=_drvEntry @$(NAME).lk + kpack.exe geode.dll geode.drv + +geode.obj : geode.c $(SRC_DEP) $(HFILES) Makefile + $(CC) $(INCLUDES) $(CFLAGS) -o geode.obj geode.c + + + diff --git a/drivers/a5536/pci.h b/drivers/a5536/pci.h new file mode 100644 index 0000000000..90a2efedc4 --- /dev/null +++ b/drivers/a5536/pci.h @@ -0,0 +1,182 @@ + + +#pragma pack(push, 1) +typedef struct +{ + u16_t device; + u16_t ChipSet; +}PciChipset_t; +#pragma pack(pop) + +#define VENDOR_ATI 0x1002 + + +#define PCI_CLASS_DISPLAY_VGA 0x0300 +/* + * Under PCI, each device has 256 bytes of configuration address space, + * of which the first 64 bytes are standardized as follows: + */ +#define PCI_VENDOR_ID 0x00 /* 16 bits */ +#define PCI_DEVICE_ID 0x02 /* 16 bits */ +#define PCI_COMMAND 0x04 /* 16 bits */ +#define PCI_COMMAND_IO 0x01 /* Enable response in I/O space */ +#define PCI_COMMAND_MEMORY 0x02 /* Enable response in Memory space */ +#define PCI_COMMAND_MASTER 0x04 /* Enable bus mastering */ +#define PCI_COMMAND_SPECIAL 0x08 /* Enable response to special cycles */ +#define PCI_COMMAND_INVALIDATE 0x10 /* Use memory write and invalidate */ +#define PCI_COMMAND_VGA_PALETTE 0x20 /* Enable palette snooping */ +#define PCI_COMMAND_PARITY 0x40 /* Enable parity checking */ +#define PCI_COMMAND_WAIT 0x80 /* Enable address/data stepping */ +#define PCI_COMMAND_SERR 0x100 /* Enable SERR */ +#define PCI_COMMAND_FAST_BACK 0x200 /* Enable back-to-back writes */ +#define PCI_COMMAND_INTX_DISABLE 0x400 /* INTx Emulation Disable */ + +#define PCI_STATUS 0x06 /* 16 bits */ +#define PCI_STATUS_CAP_LIST 0x10 /* Support Capability List */ +#define PCI_STATUS_66MHZ 0x20 /* Support 66 Mhz PCI 2.1 bus */ +#define PCI_STATUS_UDF 0x40 /* Support User Definable Features [obsolete] */ +#define PCI_STATUS_FAST_BACK 0x80 /* Accept fast-back to back */ +#define PCI_STATUS_PARITY 0x100 /* Detected parity error */ +#define PCI_STATUS_DEVSEL_MASK 0x600 /* DEVSEL timing */ +#define PCI_STATUS_DEVSEL_FAST 0x000 +#define PCI_STATUS_DEVSEL_MEDIUM 0x200 +#define PCI_STATUS_DEVSEL_SLOW 0x400 +#define PCI_STATUS_SIG_TARGET_ABORT 0x800 /* Set on target abort */ +#define PCI_STATUS_REC_TARGET_ABORT 0x1000 /* Master ack of " */ +#define PCI_STATUS_REC_MASTER_ABORT 0x2000 /* Set on master abort */ +#define PCI_STATUS_SIG_SYSTEM_ERROR 0x4000 /* Set when we drive SERR */ +#define PCI_STATUS_DETECTED_PARITY 0x8000 /* Set on parity error */ + +#define PCI_CLASS_REVISION 0x08 /* High 24 bits are class, low 8 revision */ +#define PCI_REVISION_ID 0x08 /* Revision ID */ +#define PCI_CLASS_PROG 0x09 /* Reg. Level Programming Interface */ +#define PCI_CLASS_DEVICE 0x0a /* Device class */ + +#define PCI_CACHE_LINE_SIZE 0x0c /* 8 bits */ +#define PCI_LATENCY_TIMER 0x0d /* 8 bits */ +#define PCI_HEADER_TYPE 0x0e /* 8 bits */ +#define PCI_HEADER_TYPE_NORMAL 0 +#define PCI_HEADER_TYPE_BRIDGE 1 +#define PCI_HEADER_TYPE_CARDBUS 2 + +#define PCI_BIST 0x0f /* 8 bits */ +#define PCI_BIST_CODE_MASK 0x0f /* Return result */ +#define PCI_BIST_START 0x40 /* 1 to start BIST, 2 secs or less */ +#define PCI_BIST_CAPABLE 0x80 /* 1 if BIST capable */ + +#define PCI_CAPABILITY_LIST 0x34 /* Offset of first capability list entry */ +#define PCI_CB_CAPABILITY_LIST 0x14 +/* Capability lists */ + +#define PCI_CAP_LIST_ID 0 /* Capability ID */ +#define PCI_CAP_ID_PM 0x01 /* Power Management */ +#define PCI_CAP_ID_AGP 0x02 /* Accelerated Graphics Port */ +#define PCI_CAP_ID_VPD 0x03 /* Vital Product Data */ +#define PCI_CAP_ID_SLOTID 0x04 /* Slot Identification */ +#define PCI_CAP_ID_MSI 0x05 /* Message Signalled Interrupts */ +#define PCI_CAP_ID_CHSWP 0x06 /* CompactPCI HotSwap */ +#define PCI_CAP_ID_PCIX 0x07 /* PCI-X */ +#define PCI_CAP_ID_HT 0x08 /* HyperTransport */ +#define PCI_CAP_ID_VNDR 0x09 /* Vendor specific capability */ +#define PCI_CAP_ID_SHPC 0x0C /* PCI Standard Hot-Plug Controller */ +#define PCI_CAP_ID_EXP 0x10 /* PCI Express */ +#define PCI_CAP_ID_MSIX 0x11 /* MSI-X */ +#define PCI_CAP_LIST_NEXT 1 /* Next capability in the list */ +#define PCI_CAP_FLAGS 2 /* Capability defined flags (16 bits) */ +#define PCI_CAP_SIZEOF 4 + + +/* AGP registers */ + +#define PCI_AGP_VERSION 2 /* BCD version number */ +#define PCI_AGP_RFU 3 /* Rest of capability flags */ +#define PCI_AGP_STATUS 4 /* Status register */ +#define PCI_AGP_STATUS_RQ_MASK 0xff000000 /* Maximum number of requests - 1 */ +#define PCI_AGP_STATUS_SBA 0x0200 /* Sideband addressing supported */ +#define PCI_AGP_STATUS_64BIT 0x0020 /* 64-bit addressing supported */ +#define PCI_AGP_STATUS_FW 0x0010 /* FW transfers supported */ +#define PCI_AGP_STATUS_RATE4 0x0004 /* 4x transfer rate supported */ +#define PCI_AGP_STATUS_RATE2 0x0002 /* 2x transfer rate supported */ +#define PCI_AGP_STATUS_RATE1 0x0001 /* 1x transfer rate supported */ +#define PCI_AGP_COMMAND 8 /* Control register */ +#define PCI_AGP_COMMAND_RQ_MASK 0xff000000 /* Master: Maximum number of requests */ +#define PCI_AGP_COMMAND_SBA 0x0200 /* Sideband addressing enabled */ +#define PCI_AGP_COMMAND_AGP 0x0100 /* Allow processing of AGP transactions */ +#define PCI_AGP_COMMAND_64BIT 0x0020 /* Allow processing of 64-bit addresses */ +#define PCI_AGP_COMMAND_FW 0x0010 /* Force FW transfers */ +#define PCI_AGP_COMMAND_RATE4 0x0004 /* Use 4x rate */ +#define PCI_AGP_COMMAND_RATE2 0x0002 /* Use 2x rate */ +#define PCI_AGP_COMMAND_RATE1 0x0001 /* Use 1x rate */ +#define PCI_AGP_SIZEOF 12 + + +#define PCI_MAP_REG_START 0x10 +#define PCI_MAP_REG_END 0x28 +#define PCI_MAP_ROM_REG 0x30 + +#define PCI_MAP_MEMORY 0x00000000 +#define PCI_MAP_IO 0x00000001 + +#define PCI_MAP_MEMORY_TYPE 0x00000007 +#define PCI_MAP_IO_TYPE 0x00000003 + +#define PCI_MAP_MEMORY_TYPE_32BIT 0x00000000 +#define PCI_MAP_MEMORY_TYPE_32BIT_1M 0x00000002 +#define PCI_MAP_MEMORY_TYPE_64BIT 0x00000004 +#define PCI_MAP_MEMORY_TYPE_MASK 0x00000006 +#define PCI_MAP_MEMORY_CACHABLE 0x00000008 +#define PCI_MAP_MEMORY_ATTR_MASK 0x0000000e +#define PCI_MAP_MEMORY_ADDRESS_MASK 0xfffffff0 + +#define PCI_MAP_IO_ATTR_MASK 0x00000003 + +#define PCI_MAP_IS_IO(b) ((b) & PCI_MAP_IO) +#define PCI_MAP_IS_MEM(b) (!PCI_MAP_IS_IO(b)) + +#define PCI_MAP_IS64BITMEM(b) \ + (((b) & PCI_MAP_MEMORY_TYPE_MASK) == PCI_MAP_MEMORY_TYPE_64BIT) + +#define PCIGETMEMORY(b) ((b) & PCI_MAP_MEMORY_ADDRESS_MASK) +#define PCIGETMEMORY64HIGH(b) (*((CARD32*)&b + 1)) +#define PCIGETMEMORY64(b) \ + (PCIGETMEMORY(b) | ((CARD64)PCIGETMEMORY64HIGH(b) << 32)) + +#define PCI_MAP_IO_ADDRESS_MASK 0xfffffffc + +#define PCIGETIO(b) ((b) & PCI_MAP_IO_ADDRESS_MASK) + +#define PCI_MAP_ROM_DECODE_ENABLE 0x00000001 +#define PCI_MAP_ROM_ADDRESS_MASK 0xfffff800 + +#define PCIGETROM(b) ((b) & PCI_MAP_ROM_ADDRESS_MASK) + + +#ifndef PCI_DOM_MASK +# define PCI_DOM_MASK 0x0ffu +#endif +#define PCI_DOMBUS_MASK (((PCI_DOM_MASK) << 8) | 0x0ffu) + +#define PCI_MAKE_TAG(b,d,f) ((((b) & (PCI_DOMBUS_MASK)) << 16) | \ + (((d) & 0x00001fu) << 11) | \ + (((f) & 0x000007u) << 8)) + +#define PCI_BUS_FROM_TAG(tag) (((tag) >> 16) & (PCI_DOMBUS_MASK)) +#define PCI_DEV_FROM_TAG(tag) (((tag) & 0x0000f800u) >> 11) +#define PCI_FUNC_FROM_TAG(tag) (((tag) & 0x00000700u) >> 8) +#define PCI_DFN_FROM_TAG(tag) (((tag) & 0x0000ff00u) >> 8) + + +typedef unsigned int PCITAG; + +extern inline PCITAG +pciTag(int busnum, int devnum, int funcnum) +{ + return(PCI_MAKE_TAG(busnum,devnum,funcnum)); +} + +const PciChipset_t *PciDevMatch(u16_t dev,const PciChipset_t *list); +u32_t pciGetBaseSize(int bus, int devfn, int index, Bool destructive, Bool *min); + +#define PCI_ANY_ID (~0) + +#define for_each_pci_dev(d) while ((d = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, d))!=-1)