Build for AROS..
[AROS.git] / workbench / devs / AHI / Drivers / CMI8738 / misc.c
bloba83f537c937336f7442d4186c7a006530ad12e7c
1 /*
2 The contents of this file are subject to the AROS Public License Version 1.1 (the "License");
3 you may not use this file except in compliance with the License. You may obtain a copy of the License at
4 http://www.aros.org/license.html
5 Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF
6 ANY KIND, either express or implied. See the License for the specific language governing rights and
7 limitations under the License.
9 The Original Code is written by Davy Wentzler.
12 //#include <config.h>
14 #include <exec/memory.h>
16 #ifdef __AROS__
17 #include <aros/debug.h>
18 #endif
20 #include <proto/exec.h>
21 #include <proto/dos.h>
23 #include <string.h>
25 #include "library.h"
26 #include "regs.h"
27 #include "interrupt.h"
28 #include "misc.h"
30 #include "pci_wrapper.h"
32 #define CACHELINE_SIZE 32
34 #ifdef __AROS__
35 #define DebugPrintF bug
36 INTGW(static, void, playbackinterrupt, PlaybackInterrupt);
37 INTGW(static, void, recordinterrupt, RecordInterrupt);
38 INTGW(static, ULONG, cardinterrupt, CardInterrupt);
39 #endif
41 /* Global in Card.c */
42 extern const UWORD InputBits[];
44 /* Public functions in main.c */
45 int card_init(struct CMI8738_DATA *card);
46 void card_cleanup(struct CMI8738_DATA *card);
47 #if !defined(__AROS__)
48 void AddResetHandler(struct CMI8738_DATA *card);
49 #endif
51 void WritePartialMask(struct PCIDevice *dev, struct CMI8738_DATA* card, unsigned long reg, unsigned long shift, unsigned long mask, unsigned long val)
53 ULONG tmp;
55 tmp = pci_inl(reg, card);
56 tmp &= ~(mask << shift);
57 tmp |= val << shift;
58 pci_outl(tmp, reg, card);
62 void ClearMask(struct PCIDevice *dev, struct CMI8738_DATA* card, unsigned long reg, unsigned long mask)
64 ULONG tmp;
66 tmp = pci_inl(reg, card);
67 tmp &= ~mask;
68 pci_outl(tmp, reg, card);
72 void WriteMask(struct PCIDevice *dev, struct CMI8738_DATA* card, unsigned long reg, unsigned long mask)
74 ULONG tmp;
76 tmp = pci_inl(reg, card);
77 tmp |= mask;
78 pci_outl(tmp, reg, card);
81 void cmimix_wr(struct PCIDevice *dev, struct CMI8738_DATA* card, unsigned char port, unsigned char val)
83 pci_outb(port, CMPCI_REG_SBADDR, card);
84 pci_outb(val, CMPCI_REG_SBDATA, card);
87 unsigned char cmimix_rd(struct PCIDevice *dev, struct CMI8738_DATA* card, unsigned char port)
89 pci_outb(port, CMPCI_REG_SBADDR, card);
90 return (unsigned char) pci_inb(CMPCI_REG_SBDATA, card);
94 /******************************************************************************
95 ** DriverData allocation ******************************************************
96 ******************************************************************************/
98 // This code used to be in _AHIsub_AllocAudio(), but since we're now
99 // handling CAMD support too, it needs to be done at driver loading
100 // time.
102 struct CMI8738_DATA*
103 AllocDriverData( struct PCIDevice *dev,
104 struct DriverBase* AHIsubBase )
106 struct CMI8738Base* CMI8738Base = (struct CMI8738Base*) AHIsubBase;
107 struct CMI8738_DATA* card;
108 UWORD command_word;
109 int i, v;
110 unsigned char byte;
112 // FIXME: This should be non-cachable, DMA-able memory
113 card = AllocVec( sizeof( *card ), MEMF_PUBLIC | MEMF_CLEAR );
115 if( card == NULL )
117 Req( "Unable to allocate driver structure." );
118 return NULL;
121 card->ahisubbase = AHIsubBase;
123 card->interrupt.is_Node.ln_Type = IRQTYPE;
124 card->interrupt.is_Node.ln_Pri = 0;
125 card->interrupt.is_Node.ln_Name = (STRPTR) LibName;
126 #ifdef __AROS__
127 card->interrupt.is_Code = (void(*)(void)) &cardinterrupt;
128 #else
129 card->interrupt.is_Code = (void(*)(void)) CardInterrupt;
130 #endif
131 card->interrupt.is_Data = (APTR) card;
133 card->playback_interrupt.is_Node.ln_Type = IRQTYPE;
134 card->playback_interrupt.is_Node.ln_Pri = 0;
135 card->playback_interrupt.is_Node.ln_Name = (STRPTR) LibName;
136 #ifdef __AROS__
137 card->playback_interrupt.is_Code = &playbackinterrupt;
138 #else
139 card->interrupt.is_Code = PlaybackInterrupt;
140 #endif
141 card->playback_interrupt.is_Data = (APTR) card;
143 card->record_interrupt.is_Node.ln_Type = IRQTYPE;
144 card->record_interrupt.is_Node.ln_Pri = 0;
145 card->record_interrupt.is_Node.ln_Name = (STRPTR) LibName;
146 #ifdef __AROS__
147 card->record_interrupt.is_Code = &recordinterrupt;
148 #else
149 card->interrupt.is_Code = RecordInterrupt;
150 #endif
151 card->record_interrupt.is_Data = (APTR) card;
153 card->pci_dev = dev;
155 command_word = inw_config(PCI_COMMAND, dev);
156 command_word |= PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER;
157 outw_config( PCI_COMMAND, command_word, dev);
159 card->pci_master_enabled = TRUE;
161 /*for (i = 0; i < 6; i++)
163 if (dev->GetResourceRange(i))
164 DebugPrintF("BAR[%ld] = %lx\n", i, dev->GetResourceRange(i)->BaseAddress);
167 card->iobase = ahi_pci_get_base_address(0, dev);
168 card->length = ahi_pci_get_base_size(0, dev);
169 card->irq = ahi_pci_get_irq(dev);
170 card->chiprev = inb_config(PCI_REVISION_ID, dev);
171 card->model = inw_config(PCI_SUBSYSTEM_ID, dev);
173 /*DebugPrintF("---> chiprev = %u, model = %x, Vendor = %x\n", dev->ReadConfigByte( PCI_REVISION_ID), dev->ReadConfigWord( PCI_SUBSYSTEM_ID),
174 dev->ReadConfigWord( PCI_SUBSYSTEM_VENDOR_ID));*/
177 /* Initialize chip */
178 if( card_init( card ) < 0 )
180 DebugPrintF("Unable to initialize Card subsystem.");
181 return NULL;
184 //DebugPrintF("INTERRUPT %lu\n", dev->MapInterrupt());
185 ahi_pci_add_intserver(&card->interrupt, dev);
186 card->interrupt_added = TRUE;
188 card->card_initialized = TRUE;
189 card->input = 0;
190 card->output = 0;
191 card->monitor_volume = Linear2MixerGain( 0, &card->monitor_volume_bits );
192 card->input_gain = Linear2RecordGain( 0x10000, &card->input_gain_bits );
193 card->output_volume = Linear2MixerGain( 0x10000, &card->output_volume_bits );
194 SaveMixerState(card);
196 cmimix_wr(dev, card, CMPCI_SB16_MIXER_RESET, 0);
197 cmimix_wr(dev, card, CMPCI_SB16_MIXER_ADCMIX_L, 0); //(CMPCI_SB16_MIXER_LINE_SRC_R << 1) ); // set input to line
198 cmimix_wr(dev, card, CMPCI_SB16_MIXER_ADCMIX_R, 0); //CMPCI_SB16_MIXER_LINE_SRC_R);
200 cmimix_wr(dev, card, CMPCI_SB16_MIXER_OUTMIX, 0); // set output mute off for line and CD
202 cmimix_wr(dev, card, CMPCI_SB16_MIXER_VOICE_L, 0xFF); // PCM
203 cmimix_wr(dev, card, CMPCI_SB16_MIXER_VOICE_R, 0xFF);
205 cmimix_wr(dev, card, CMPCI_SB16_MIXER_CDDA_L, 0x00);
206 cmimix_wr(dev, card, CMPCI_SB16_MIXER_CDDA_R, 0x00);
208 cmimix_wr(dev, card, CMPCI_SB16_MIXER_LINE_L, 0x00);
209 cmimix_wr(dev, card, CMPCI_SB16_MIXER_LINE_R, 0x00);
211 byte = pci_inb(CMPCI_REG_MIXER25, card);
212 pci_outb(byte & ~0x30, CMPCI_REG_MIXER25, card); // mute Aux
213 pci_outb(byte & ~0x01, CMPCI_REG_MIXER25, card); // turn on mic 20dB boost
214 pci_outb(0x00, CMPCI_REG_MIXER_AUX, card);
216 byte = pci_inb(CMPCI_REG_MIXER24, card);
217 pci_outb(byte | CMPCI_REG_FMMUTE, CMPCI_REG_MIXER24, card);
219 cmimix_wr(dev, card, CMPCI_SB16_MIXER_MIC, 0x00);
221 cmimix_wr(dev, card, CMPCI_SB16_MIXER_MASTER_L, 0xFF);
222 cmimix_wr(dev, card, CMPCI_SB16_MIXER_MASTER_R, 0xFF);
224 card->mixerstate = cmimix_rd(dev, card, CMPCI_SB16_MIXER_OUTMIX);
226 #if !defined(__AROS__)
227 AddResetHandler(card);
228 #endif
230 return card;
234 /******************************************************************************
235 ** DriverData deallocation ****************************************************
236 ******************************************************************************/
238 // And this code used to be in _AHIsub_FreeAudio().
240 void
241 FreeDriverData( struct CMI8738_DATA* card,
242 struct DriverBase* AHIsubBase )
244 if( card != NULL )
246 if( card->pci_dev != NULL )
248 if( card->card_initialized )
250 card_cleanup( card );
253 if( card->pci_master_enabled )
255 UWORD cmd;
257 cmd = inw_config(PCI_COMMAND, (struct PCIDevice * ) card->pci_dev);
258 cmd &= ~( PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER );
259 outw_config(PCI_COMMAND, cmd, (struct PCIDevice * ) card->pci_dev );
263 if( card->interrupt_added )
265 ahi_pci_rem_intserver(&card->interrupt, card->pci_dev);
268 FreeVec( card );
273 int card_init(struct CMI8738_DATA *card)
275 struct PCIDevice *dev = (struct PCIDevice *) card->pci_dev;
276 unsigned short cod;
277 unsigned long val;
279 ClearMask(dev, card, CMPCI_REG_MISC, CMPCI_REG_POWER_DOWN); // power up
281 WriteMask(dev, card, CMPCI_REG_MISC, CMPCI_REG_BUS_AND_DSP_RESET);
282 // IDOS->Delay(1);
283 ClearMask(dev, card, CMPCI_REG_MISC, CMPCI_REG_BUS_AND_DSP_RESET);
285 /* reset channels */
286 WriteMask(dev, card, CMPCI_REG_FUNC_0, CMPCI_REG_CH0_RESET | CMPCI_REG_CH1_RESET);
287 // IDOS->Delay(1);
288 ClearMask(dev, card, CMPCI_REG_FUNC_0, CMPCI_REG_CH0_RESET | CMPCI_REG_CH1_RESET);
290 /* Disable interrupts and channels */
291 ClearMask(dev, card, CMPCI_REG_FUNC_0,CMPCI_REG_CH0_ENABLE | CMPCI_REG_CH1_ENABLE);
292 ClearMask(dev, card, CMPCI_REG_INTR_CTRL, CMPCI_REG_CH0_INTR_ENABLE | CMPCI_REG_CH1_INTR_ENABLE);
294 /* Configure DMA channels, ch0 = play, ch1 = capture */
295 ClearMask(dev, card, CMPCI_REG_FUNC_0, CMPCI_REG_CH0_DIR);
296 WriteMask(dev, card, CMPCI_REG_FUNC_0, CMPCI_REG_CH1_DIR);
298 // digital I/O
299 ClearMask(dev, card, CMPCI_REG_FUNC_1, CMPCI_REG_SPDIFOUT_DAC | CMPCI_REG_SPDIF0_ENABLE);
300 ClearMask(dev, card, CMPCI_REG_LEGACY_CTRL, CMPCI_REG_LEGACY_SPDIF_ENABLE);
302 ClearMask(dev, card, CMPCI_REG_LEGACY_CTRL, 0x80000000);
303 ClearMask(dev, card, CMPCI_REG_CHANNEL_FORMAT, CM_CHB3D);
304 ClearMask(dev, card, CMPCI_REG_CHANNEL_FORMAT, CM_CHB3D5C);
305 ClearMask(dev, card, CMPCI_REG_LEGACY_CTRL, CMPCI_REG_ENABLE_5_1);
306 ClearMask(dev, card, CMPCI_REG_MISC, 0x100);
307 ClearMask(dev, card, CMPCI_REG_MISC, CMPCI_REG_N4SPK3D);
308 WriteMask(dev, card, CMPCI_REG_INTR_STATUS, CMPCI_REG_LEGACY_STEREO | CMPCI_REG_LEGACY_HDMA);
310 return 0;
314 void card_cleanup(struct CMI8738_DATA *card)
320 /******************************************************************************
321 ** Misc. **********************************************************************
322 ******************************************************************************/
324 void
325 SaveMixerState( struct CMI8738_DATA* card )
327 #if 0
328 card->ac97_mic = codec_read( card, AC97_MIC_VOL );
329 card->ac97_cd = codec_read( card, AC97_CD_VOL );
330 card->ac97_video = codec_read( card, AC97_VIDEO_VOL );
331 card->ac97_aux = codec_read( card, AC97_AUX_VOL );
332 card->ac97_linein = codec_read( card, AC97_LINEIN_VOL );
333 card->ac97_phone = codec_read( card, AC97_PHONE_VOL );
334 #endif
338 void
339 RestoreMixerState( struct CMI8738_DATA* card )
341 #if 0
342 codec_write(card, AC97_MIC_VOL, card->ac97_mic );
343 codec_write(card, AC97_CD_VOL, card->ac97_cd );
344 codec_write(card, AC97_VIDEO_VOL, card->ac97_video );
345 codec_write(card, AC97_AUX_VOL, card->ac97_aux );
346 codec_write(card, AC97_LINEIN_VOL, card->ac97_linein );
347 codec_write(card, AC97_PHONE_VOL, card->ac97_phone );
348 #endif
351 void
352 UpdateMonitorMixer( struct CMI8738_DATA* card )
354 #if 0
355 int i = InputBits[ card->input ];
356 UWORD m = card->monitor_volume_bits & 0x801f;
357 UWORD s = card->monitor_volume_bits;
358 UWORD mm = AC97_MUTE | 0x0008;
359 UWORD sm = AC97_MUTE | 0x0808;
361 if( i == AC97_RECMUX_STEREO_MIX ||
362 i == AC97_RECMUX_MONO_MIX )
364 // Use the original mixer settings
365 RestoreMixerState( card );
367 else
369 codec_write(card, AC97_MIC_VOL,
370 i == AC97_RECMUX_MIC ? m : mm );
372 codec_write(card, AC97_CD_VOL,
373 i == AC97_RECMUX_CD ? s : sm );
375 codec_write(card, AC97_VIDEO_VOL,
376 i == AC97_RECMUX_VIDEO ? s : sm );
378 codec_write(card, AC97_AUX_VOL,
379 i == AC97_RECMUX_AUX ? s : sm );
381 codec_write(card, AC97_LINEIN_VOL,
382 i == AC97_RECMUX_LINE ? s : sm );
384 codec_write(card, AC97_PHONE_VOL,
385 i == AC97_RECMUX_PHONE ? m : mm );
387 #endif
391 Fixed
392 Linear2MixerGain( Fixed linear,
393 UWORD* bits )
395 static const Fixed gain[ 33 ] =
397 260904, // +12.0 dB
398 219523, // +10.5 dB
399 184706, // +9.0 dB
400 155410, // +7.5 dB
401 130762, // +6.0 dB
402 110022, // +4.5 dB
403 92572, // +3.0 dB
404 77890, // +1.5 dB
405 65536, // ±0.0 dB
406 55142, // -1.5 dB
407 46396, // -3.0 dB
408 39037, // -4.5 dB
409 32846, // -6.0 dB
410 27636, // -7.5 dB
411 23253, // -9.0 dB
412 19565, // -10.5 dB
413 16462, // -12.0 dB
414 13851, // -13.5 dB
415 11654, // -15.0 dB
416 9806, // -16.5 dB
417 8250, // -18.0 dB
418 6942, // -19.5 dB
419 5841, // -21.0 dB
420 4915, // -22.5 dB
421 4135, // -24.0 dB
422 3479, // -25.5 dB
423 2927, // -27.0 dB
424 2463, // -28.5 dB
425 2072, // -30.0 dB
426 1744, // -31.5 dB
427 1467, // -33.0 dB
428 1234, // -34.5 dB
429 0 // -oo dB
432 int v = 0;
434 while( linear < gain[ v ] )
436 ++v;
439 if( v == 32 )
441 *bits = 0x8000; // Mute
443 else
445 *bits = ( v << 8 ) | v;
448 // KPrintF( "l2mg %08lx -> %08lx (%04lx)\n", linear, gain[ v ], *bits );
449 return gain[ v ];
452 Fixed
453 Linear2RecordGain( Fixed linear,
454 UWORD* bits )
456 static const Fixed gain[ 17 ] =
458 873937, // +22.5 dB
459 735326, // +21.0 dB
460 618700, // +19.5 dB
461 520571, // +18.0 dB
462 438006, // +16.5 dB
463 368536, // +15.0 dB
464 310084, // +13.5 dB
465 260904, // +12.0 dB
466 219523, // +10.5 dB
467 184706, // +9.0 dB
468 155410, // +7.5 dB
469 130762, // +6.0 dB
470 110022, // +4.5 dB
471 92572, // +3.0 dB
472 77890, // +1.5 dB
473 65536, // ±0.0 dB
474 0 // -oo dB
477 int v = 0;
479 while( linear < gain[ v ] )
481 ++v;
484 if( v == 16 )
486 *bits = 0x8000; // Mute
488 else
490 *bits = ( ( 15 - v ) << 8 ) | ( 15 - v );
493 return gain[ v ];
497 ULONG
498 SamplerateToLinearPitch( ULONG samplingrate )
500 samplingrate = (samplingrate << 8) / 375;
501 return (samplingrate >> 1) + (samplingrate & 1);
505 APTR DMAheader = 0;
506 #define GFXMEM_BUFFER (64 * 1024) // 64KB should be enough for everyone...
508 void *pci_alloc_consistent(size_t size, APTR *NonAlignedAddress, unsigned int boundary)
510 void* address;
511 unsigned long a;
513 address = (void *) AllocVec(size + boundary, MEMF_PUBLIC | MEMF_CLEAR);
515 if (address != NULL)
517 a = (unsigned long) address;
518 a = (a + boundary - 1) & ~(boundary - 1);
519 address = (void *) a;
522 if (NonAlignedAddress)
524 *NonAlignedAddress = address;
527 return address;
531 void pci_free_consistent(void* addr)
533 FreeVec(addr);
536 static ULONG ResetHandler(struct ExceptionContext *ctx, struct ExecBase *pExecBase, struct CMI8738_DATA *card)
538 struct PCIDevice *dev = card->pci_dev;
540 ClearMask(dev, card, CMPCI_REG_INTR_CTRL, CMPCI_REG_CH0_INTR_ENABLE);
541 ClearMask(dev, card, CMPCI_REG_FUNC_0, CMPCI_REG_CH0_ENABLE);
543 return 0UL;
546 #if !defined(__AROS__)
547 void AddResetHandler(struct CMI8738_DATA *card)
549 static struct Interrupt interrupt;
551 interrupt.is_Code = (void (*)())ResetHandler;
552 interrupt.is_Data = (APTR) card;
553 interrupt.is_Node.ln_Pri = 0;
554 interrupt.is_Node.ln_Type = IRQTYPE;
555 interrupt.is_Node.ln_Name = "reset handler";
557 AddResetCallback( &interrupt );
559 #endif