Subversion Repositories Kolibri OS

Rev

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