Subversion Repositories Kolibri OS

Rev

Rev 1692 | Rev 2968 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1.  
  2.  
  3. #define FORCED_PIO
  4.  
  5. #include <ddk.h>
  6. #include "pci.h"
  7. #include <syscall.h>
  8.  
  9. #include "geode.h"
  10.  
  11. #define DBG(format,...) dbgprintf(format,##__VA_ARGS__)
  12.  
  13. #define  BM0_IRQ            0x04
  14. #define  BM1_IRQ            0x08
  15. #define BITS_8_TO_16(x) ( ( (long) ((unsigned char) x - 128) ) << 8 )
  16.  
  17. #define PCI_VENDOR_ID_NS  0x100b
  18. #define PCI_VENDOR_ID_AMD 0x1022
  19.  
  20.  
  21. #ifndef PCI_DEVICE_ID_NS_CS5535_AUDIO
  22.     #define PCI_DEVICE_ID_NS_CS5535_AUDIO 0x002e
  23. #endif
  24. #ifndef PCI_DEVICE_ID_AMD_CS5536_AUDIO
  25.     #define PCI_DEVICE_ID_AMD_CS5536_AUDIO 0x2093
  26. #endif
  27.  
  28. #define  ID_DEV_1   ((PCI_DEVICE_ID_NS_CS5535_AUDIO  << 16)|PCI_VENDOR_ID_NS)
  29. #define  ID_DEV_2   ((PCI_DEVICE_ID_AMD_CS5536_AUDIO << 16)|PCI_VENDOR_ID_AMD)
  30.  
  31. #define SET                 1
  32. #define CLEAR                           0
  33.  
  34. int __stdcall srv_sound(ioctl_t *io);
  35.  
  36.  
  37. PRD_ENTRY __attribute__((aligned(16))) prd_tab[5];
  38.  
  39.  
  40. typedef struct
  41. {
  42.     PCITAG  pciTag;
  43.     Bool    is_iomapped;
  44.     addr_t  F3BAR0;
  45.  
  46.     Bool    fAD1819A;
  47.  
  48.     int     CurrentPowerState;
  49.  
  50.     addr_t  buffer;
  51.     addr_t  buffer_dma;
  52.     addr_t  prd_dma;
  53.  
  54.     addr_t  irq_line;
  55.     u32_t   irq_mask;
  56.  
  57.     void    __stdcall (*callback)(addr_t buffer);
  58. }geode_t;
  59.  
  60. geode_t  geode;
  61.  
  62.  
  63. static inline void ctrl_write_32(addr_t reg, u32_t data)
  64. {
  65.     reg+= geode.F3BAR0;
  66.  
  67. #ifdef FORCED_PIO
  68.        out32((u16_t)reg, data);
  69. #else
  70.     if(geode.is_iomapped)
  71.        out32((u16_t)reg, data);
  72.     else
  73.         *(u32_t*)reg = data;
  74. #endif
  75. }
  76.  
  77. static inline u32_t ctrl_read_32(addr_t reg)
  78. {
  79.     reg+= geode.F3BAR0;
  80. #ifdef FORCED_PIO
  81.         return in32((u16_t)reg);
  82. #else
  83.     if(geode.is_iomapped)
  84.         return in32((u16_t)reg);
  85.     else
  86.         return *(u32_t*)reg;
  87. #endif
  88. }
  89.  
  90.  
  91.  
  92. Bool snd_hw_WaitForBit(addr_t offset, u32_t Bit,
  93.                               unsigned char Operation,
  94.                               count_t timeout,
  95.                               u32_t *pReturnValue)
  96. {
  97.     volatile u32_t  tmp;
  98.  
  99.     tmp = ctrl_read_32(offset);
  100.  
  101.     while (timeout)
  102.     {
  103.         if (Operation==CLEAR){
  104.             if (!(tmp & Bit))
  105.                 break;
  106.         } else if (tmp & Bit)
  107.                 break;
  108.  
  109.         /*If the Bit is not clear yet, we wait for 10 milisecond and try again*/
  110.         delay(10/10);
  111.  
  112.         tmp = ctrl_read_32(offset);
  113.  
  114.         timeout--;
  115.     };
  116.  
  117.     if (pReturnValue)
  118.         *pReturnValue=tmp;
  119.  
  120.     if (!timeout)
  121.         return FALSE;
  122.  
  123.     return TRUE;
  124. }
  125.  
  126. u16_t snd_hw_CodecRead ( u8_t CodecRegister )
  127. {
  128.     u32_t CodecRegister_data = 0;
  129.     u32_t timeout=10;
  130.     volatile u32_t val=0;
  131.  
  132.     CodecRegister_data  = ((u32_t)CodecRegister)<<24;
  133.     CodecRegister_data |= 0x80000000;   /* High-bit set (p.106) is a CODEC reg READ.*/
  134.  
  135. /*  Set the bit.  We are going to access the CODEC...*/
  136.     CodecRegister_data |= BIT_5535_CODEC_COMMAND_NEW;
  137.  
  138. /*Request the data*/
  139.     ctrl_write_32(CODEC_CONTROL_REG_5535, CodecRegister_data);
  140.  
  141. /*  Now we need to wait for BIT_5535_CODEC_COMMAND_NEW of the Codec control register to clear
  142.     (For subsequent Reads/Writes)*/
  143.     if (!snd_hw_WaitForBit (CODEC_CONTROL_REG_5535,
  144.                             BIT_5535_CODEC_COMMAND_NEW, CLEAR, 50, NULL))
  145.         DBG("BIT_5535_CODEC_COMMAND_NEW did not clear!!\n");
  146.  
  147. /* Wait for CODEC_STATUS_NEW and confirm the read of the requested register*/
  148.     timeout = 50;
  149.     do
  150.     {
  151.         val = ctrl_read_32(CODEC_STATUS_REG_5535);
  152.         if ((val & BIT_5535_CODEC_STATUS_NEW) &&
  153.             ((u32_t) CodecRegister == ((0xFF000000 & val)>>24)))
  154.             break;
  155.         else
  156.             /*Wait for 10 miliseconds and try again*/
  157.             delay(10/10);
  158.     } while ( --timeout);
  159.  
  160.     if (!timeout)
  161.        DBG("Could not read the CODEC!!  Returning what we got.\n");
  162.  
  163.     return( (u16_t)val );
  164. }
  165.  
  166. void snd_hw_CodecWrite( u8_t CodecRegister, u16_t CodecData  )
  167. {
  168.     u32_t CodecRegister_data;
  169.     u32_t Temp, timeout;
  170.  
  171.     CodecRegister_data = ((u32_t) CodecRegister)<<24;
  172.     CodecRegister_data |= (u32_t) CodecData;
  173.     CodecRegister_data &= CODEC_COMMAND_MASK;
  174.  
  175.     /*Set the bit.  We are going to access the CODEC...*/
  176.     CodecRegister_data |= BIT_5535_CODEC_COMMAND_NEW;
  177.  
  178.     /*Write the data*/
  179.     ctrl_write_32(CODEC_CONTROL_REG_5535, CodecRegister_data);
  180.     //OS_DbgMsg("Writing: %08X\n", CodecRegister_data);
  181.  
  182.     /*We need to wait for bit16 of the Codec control register to clear*/
  183.     Temp = ctrl_read_32(CODEC_CONTROL_REG_5535);
  184.  
  185.     timeout = 50;
  186.  
  187.     while ((Temp & BIT_5535_CODEC_COMMAND_NEW) && timeout-- )
  188.         Temp = ctrl_read_32(CODEC_CONTROL_REG_5535);
  189.  
  190.     if (!timeout)
  191.         DBG("Could not Write the CODEC!!\n"
  192.                   "BIT_5535_CODEC_COMMAND_NEW did not clear!\n");
  193. }
  194.  
  195.  
  196. void snd_hw_SetCodecRate(u32_t SampleRate)
  197. {
  198.     u16_t val;
  199.  
  200.     DBG("Rate: %d\n", SampleRate);
  201.  
  202.     /*If Double-Rate is supported (Bit 2 on register 28h)...*/
  203.     val=snd_hw_CodecRead(EXTENDED_AUDIO_ID);
  204.  
  205.     if (val & 0x02)
  206.     {
  207.         DBG("Codec supports Double rate.\n");
  208.         val=snd_hw_CodecRead(EXT_AUDIO_CTRL_STAT);
  209.  
  210.         if (SampleRate>48000)
  211.         {
  212.             snd_hw_CodecWrite(EXT_AUDIO_CTRL_STAT, (u16_t) (val|0x0002));
  213.             SampleRate/=2;
  214.         }
  215.         else
  216.             snd_hw_CodecWrite(EXT_AUDIO_CTRL_STAT, (u16_t) (val&0xFFFD));
  217.     }
  218.     if (geode.fAD1819A)
  219.     {
  220.         DBG("AD1819...\n");
  221.         snd_hw_CodecWrite(AD1819A_PCM_SR0,(u16_t)SampleRate);
  222.     }
  223.     else
  224.         snd_hw_CodecWrite(PCM_FRONT_DAC_RATE,(u16_t)SampleRate);
  225. }
  226.  
  227. Bool init_device()
  228. {
  229.     u32_t io_base = pciReadLong(geode.pciTag, 0x10);
  230.  
  231.     if( PCI_MAP_IS_IO(io_base))
  232.     {
  233.         geode.is_iomapped = TRUE;
  234.         geode.F3BAR0 = PCIGETIO(io_base);
  235.         DBG("io mapped F3BAR0 %x\n", geode.F3BAR0);
  236.     }
  237.     else if(PCI_MAP_IS_MEM(io_base))
  238.     {
  239.         geode.is_iomapped = FALSE;
  240.         io_base = PCIGETMEMORY(io_base);
  241.         geode.F3BAR0 = MapIoMem(io_base, 128, PG_SW+PG_NOCACHE);
  242.         DBG("memory mapped F3BAR0 %x\n", geode.F3BAR0);
  243.     }
  244.  
  245.     geode.buffer = KernelAlloc(64*1024);
  246.  
  247.     addr_t buffer = geode.buffer;
  248.     addr_t dma = GetPgAddr(geode.buffer);
  249.     geode.buffer_dma = dma;
  250.  
  251.     geode.prd_dma  = (((addr_t)prd_tab) & 4095) + GetPgAddr((void*)prd_tab);
  252.  
  253.     prd_tab[0].ulPhysAddr = dma;
  254.     prd_tab[0].SizeFlags = 16384 | PRD_EOP_BIT ;
  255.  
  256.     prd_tab[1].ulPhysAddr = dma + 16384;
  257.     prd_tab[1].SizeFlags = 16384 | PRD_EOP_BIT ;
  258.  
  259.     prd_tab[2].ulPhysAddr = dma + 16384*2;
  260.     prd_tab[2].SizeFlags = 16384 | PRD_EOP_BIT ;
  261.  
  262.     prd_tab[3].ulPhysAddr = dma + 16384*3;
  263.     prd_tab[3].SizeFlags = 16384 | PRD_EOP_BIT ;
  264.  
  265.     prd_tab[4].ulPhysAddr = geode.prd_dma;
  266.     prd_tab[4].SizeFlags = PRD_JMP_BIT ;
  267.  
  268.     ctrl_write_32(0x24, geode.prd_dma);
  269.  
  270.     __clear((void*)buffer,64*1024);
  271. //    u32_t tmp = ctrl_read_32(0x24);
  272.  
  273. //    dbgprintf("Create primary buffer at %x dma at %x\n", geode.buffer, dma );
  274.  
  275. //    dbgprintf("Set prd dma %x, read prd dma %x\n", geode.prd_dma, tmp);
  276.  
  277.     geode.irq_line = pciReadLong(geode.pciTag, 0x3C) & 0xFF;
  278.     geode.irq_mask = ~(1<<geode.irq_line);
  279.  
  280.     DBG("Irq line %d, mask %x\n", geode.irq_line, geode.irq_mask);
  281.  
  282.  
  283. /*
  284.     geode.CommandRegister  = geode.F3BAR0+0x20;
  285.     geode.PRDTableAddress  = geode.F3BAR0+0x24;
  286.     geode.DMAPointer       = geode.F3BAR0+0x60;
  287.  
  288.     geode.IRQControlRegister        = geode.F3BAR0+0x1C;
  289.     geode.InternalIRQEnableRegister = geode.F3BAR0+0x1A;
  290.     geode.SMI_StatusRegister        = geode.F3BAR0+0x21;
  291. */
  292.  
  293.  
  294.  
  295. /*CODEC - RESET and volumes initalization.*/
  296. /*Set the Warm RESET and CODEC_COMMAND_NEW bits.*/
  297.  
  298.     DBG("reset codec...\n");
  299.  
  300.     ctrl_write_32(CODEC_CONTROL_REG_5535, 0x00030000 );
  301.  
  302.     if (!snd_hw_WaitForBit (CODEC_STATUS_REG_5535, BIT_CODEC_READY, SET, 40, NULL))
  303.     {
  304.        DBG("Primary Codec NOT Ready...Aborting\n");
  305.        return FALSE;
  306.     }
  307.  
  308.     u16_t id7c, id7e;
  309.  
  310.     id7c = snd_hw_CodecRead(AD1819A_VENDORID1);
  311.     id7e = snd_hw_CodecRead(AD1819A_VENDORID2);
  312.  
  313.     dbgprintf("codec id 0x7C %x  0x7E %x\n", id7c, id7e);
  314.  
  315.     /*Check which codec is being used */
  316.     if ( (id7c == 0x4144) &&
  317.          (id7e == 0x5303) )
  318.     {
  319.         geode.fAD1819A = TRUE;
  320.         /*  Enable non-48kHz sample rates. */
  321.         snd_hw_CodecWrite (AD1819A_SER_CONF,
  322.                            snd_hw_CodecRead(AD1819A_SER_CONF>>8) |
  323.                            AD1819A_SER_CONF_DRQEN);
  324.         DBG("detect AD1819A audio codec\n");
  325.     }
  326.     else
  327.     {
  328.         geode.fAD1819A = FALSE;
  329.         snd_hw_CodecWrite(EXT_AUDIO_CTRL_STAT,
  330.         (snd_hw_CodecRead(EXT_AUDIO_CTRL_STAT) | 0x0001));
  331.         /* set the VRA bit to ON*/
  332.     }
  333.  
  334.     /* set default volume*/
  335.     snd_hw_CodecWrite( MASTER_VOLUME,       0x0909);
  336.     snd_hw_CodecWrite( PCM_OUT_VOL,         0x0606);
  337.     snd_hw_CodecWrite( PC_BEEP_VOLUME,      0x0000);
  338.     snd_hw_CodecWrite( PHONE_VOLUME,        0x0606);
  339.     snd_hw_CodecWrite( MIC_VOLUME,          0x8048);
  340.     snd_hw_CodecWrite( LINE_IN_VOLUME,      0x0808);
  341.     snd_hw_CodecWrite( CD_VOLUME,           0x8000);
  342.     snd_hw_CodecWrite( VIDEO_VOLUME,        0x8000);
  343.     snd_hw_CodecWrite( TV_VOLUME,           0x8000);
  344.     snd_hw_CodecWrite( RECORD_SELECT,       0x0000);
  345.     snd_hw_CodecWrite( RECORD_GAIN,         0x0a0a);
  346.     snd_hw_CodecWrite( GENERAL_PURPOSE,     0x0200);
  347.     snd_hw_CodecWrite( MASTER_VOLUME_MONO,  0x0000);
  348.  
  349.     snd_hw_SetCodecRate(48000);
  350.     /*Set all the power state bits to 0 (Reg 26h)*/
  351.     snd_hw_CodecWrite (POWERDOWN_CTRL_STAT, 0x0000);
  352.     geode.CurrentPowerState = GEODEAUDIO_D0;
  353. //    OS_DbgMsg("<--snd_hw_InitAudioRegs\n");
  354.  
  355.  
  356.     return TRUE;
  357. }
  358.  
  359. static int snd_StartDMA ()
  360. {
  361.  
  362. #ifdef FORCED_PIO
  363.         out8( (u16_t)(geode.F3BAR0+0x20),PCI_READS | ENABLE_BUSMASTER);
  364. #else
  365.     if (geode.is_iomapped)
  366.         out8( (u16_t)(geode.F3BAR0+0x20),PCI_READS | ENABLE_BUSMASTER);
  367.     else
  368.         *(u8_t*)(geode.F3BAR0+0x20)= PCI_READS | ENABLE_BUSMASTER;
  369. #endif
  370.     return 0;
  371. };
  372.  
  373. static u8_t snd_hw_InterruptID ()
  374. {
  375.     volatile u8_t *TempInterruptID, ID;
  376.  
  377. #ifdef FORCED_PIO
  378.         ID=(u8_t) in16((u16_t)(geode.F3BAR0 + 0x12));
  379. #else
  380.     if (geode.is_iomapped)
  381.         ID=(u8_t) in16((u16_t)(geode.F3BAR0 + 0x12));
  382.     else
  383.     {
  384.         TempInterruptID=(u8_t*)(geode.F3BAR0 + 0x12);
  385.         ID=*TempInterruptID;
  386.     }
  387. #endif
  388.     return (ID);
  389. }
  390.  
  391.  
  392. static u8_t snd_hw_ClearStat(int Channel)
  393. {
  394.     volatile u8_t status;      /*Volatile to force read-to-clear.*/
  395.  
  396.     /*Read to clear*/
  397.  
  398. #ifdef FORCED_PIO
  399.         status = in8((u16_t) geode.F3BAR0 + 0x21);
  400. #else
  401.     if (geode.is_iomapped)
  402.         status = in8((u16_t) geode.F3BAR0 + 0x21);
  403.     else
  404.         status = *((u8_t*)geode.F3BAR0 + 0x21);
  405. #endif
  406.     return status;
  407. }
  408.  
  409.  
  410. void snd_interrupt()
  411. {
  412.     u8_t IntID;
  413.  
  414.     IntID = snd_hw_InterruptID();
  415.  
  416. //    dbgprintf("IRQ id %x\n", IntID);
  417.  
  418.     snd_hw_ClearStat(CHANNEL0_PLAYBACK);
  419. //    snd_hw_ClearStat(CHANNEL1_RECORD);
  420.  
  421.     if(IntID & BM0_IRQ)
  422.     {
  423.       addr_t prd, offset, base;
  424.  
  425.       prd = ctrl_read_32(0x24);
  426.       offset = (1 + (prd - geode.prd_dma)>>3) & 3;
  427.  
  428.       base = geode.buffer + 16384*offset;
  429.  
  430.       geode.callback(base);
  431.       __asm__ volatile("":::"ebx","esi","edi");
  432.  
  433. //      dbgprintf(">>BM0_IRQ prd %x offset %x base %x\n", prd, offset, base);
  434.     };
  435. };
  436.  
  437. Bool FindPciDevice()
  438. {
  439.     u32_t bus, last_bus;
  440.     PCITAG tag;
  441.  
  442.     if( (last_bus = PciApi(1))==-1)
  443.         return FALSE;
  444.  
  445.     for(bus=0;bus<=last_bus;bus++)
  446.     {
  447.         u32_t devfn;
  448.  
  449.         for(devfn=0;devfn<256;devfn++)
  450.         {
  451.             u32_t pciId=0;
  452.  
  453.             pciId = PciRead32(bus,devfn, 0);
  454.  
  455.             if( (pciId == ID_DEV_1) ||
  456.                 (pciId == ID_DEV_2) )
  457.             {
  458.                 DBG("detect companion audio device %x\n", pciId);
  459.                 geode.pciTag = pciTag(bus,(devfn>>3)&0x1F,devfn&0x7);
  460.                 return TRUE;
  461.             };
  462.         };
  463.     };
  464.     return FALSE;
  465. };
  466.  
  467.  
  468. u32_t drvEntry(int action, char *cmdline)
  469. {
  470.     u32_t retval;
  471.  
  472.     int i;
  473.  
  474.     if(action != 1)
  475.         return 0;
  476.  
  477.     if(!dbg_open("/rd/1/drivers/geode.log"))
  478.     {
  479.         printf("Can't open /rd/1/drivers/geode.log\nExit\n");
  480.         return 0;
  481.     }
  482.  
  483.     printf("AMD Geode CS5536 audio driver\n");
  484.  
  485.     if( FindPciDevice() == FALSE)
  486.     {
  487.         dbgprintf("Device not found\n");
  488.         return 0;
  489.     };
  490.  
  491.     init_device();
  492.  
  493.     retval = RegService("SOUND", srv_sound);
  494.  
  495.     AttachIntHandler(geode.irq_line, snd_interrupt, 0);
  496.  
  497.     DBG("reg service %s as: %x\n", "SOUND", retval);
  498.  
  499.     return retval;
  500. };
  501.  
  502.  
  503. #define API_VERSION     0x01000100
  504.  
  505. #define SRV_GETVERSION         0
  506. #define DEV_PLAY               1
  507. #define DEV_STOP               2
  508. #define DEV_CALLBACK           3
  509. #define DEV_SET_BUFF           4
  510. #define DEV_NOTIFY             5
  511. #define DEV_SET_MASTERVOL      6
  512. #define DEV_GET_MASTERVOL      7
  513. #define DEV_GET_INFO           8
  514. #define DEV_GET_POS            9
  515.  
  516. int __stdcall srv_sound(ioctl_t *io)
  517. {
  518.     u32_t *inp;
  519.     u32_t *outp;
  520.  
  521.     inp = io->input;
  522.     outp = io->output;
  523.  
  524.     switch(io->io_code)
  525.     {
  526.         case SRV_GETVERSION:
  527.             if(io->out_size==4)
  528.             {
  529.                 *outp = API_VERSION;
  530.                 return 0;
  531.             }
  532.             break;
  533.  
  534.         case DEV_PLAY:
  535.                 return snd_StartDMA();
  536.             break;
  537.  
  538.         case DEV_STOP:
  539.             break;
  540.  
  541.         case DEV_CALLBACK:
  542.             if(io->inp_size==4)
  543.             {
  544.                 geode.callback = (void*)(*inp);
  545.                 return 0;
  546.             }
  547.             break;
  548.  
  549.         case DEV_GET_POS:
  550.             if(io->out_size==4)
  551.             {
  552.                 u32_t  dma;
  553.                 dma = ctrl_read_32(0x60);
  554.                 dma-= geode.buffer_dma;
  555.                 *outp = (dma & 16383)>>2;
  556.                 return 0;
  557.             }
  558.             break;
  559.  
  560.     default:
  561.       return ERR_PARAM;
  562.   };
  563.   return ERR_PARAM;
  564. }
  565.  
  566.  
  567.