Subversion Repositories Kolibri OS

Rev

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