Subversion Repositories Kolibri OS

Rev

Rev 1028 | Rev 1695 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

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