change init code to support multiple cards. small fixes and corrections to code.
[AROS.git] / workbench / devs / AHI / Drivers / CMI8738 / misc.c
blob6972625d9b8fd0a80e0b98ec822c225c160818f2
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 #define DEBUG 1
18 #include <aros/debug.h>
19 #endif
21 #include <proto/exec.h>
22 #include <proto/dos.h>
24 #include <string.h>
26 #include "library.h"
27 #include "regs.h"
28 #include "interrupt.h"
29 #include "misc.h"
31 #include "pci_wrapper.h"
33 #define CACHELINE_SIZE 32
35 #ifdef __AROS__
36 #define DebugPrintF bug
37 INTGW(static, void, playbackinterrupt, PlaybackInterrupt);
38 INTGW(static, void, recordinterrupt, RecordInterrupt);
39 INTGW(static, ULONG, cardinterrupt, CardInterrupt);
40 #endif
42 /* Global in Card.c */
43 extern const UWORD InputBits[];
45 /* Public functions in main.c */
46 int card_init(struct CMI8738_DATA *card);
47 void card_cleanup(struct CMI8738_DATA *card);
49 #if !defined(__AROS__)
50 void AddResetHandler(struct CMI8738_DATA *card);
51 #endif
53 void micro_delay(unsigned int val)
55 struct Device* TimerBase = NULL;
56 struct timerequest* TimerIO = NULL;
57 struct MsgPort * replymp;
59 replymp = (struct MsgPort *) CreateMsgPort();
60 if (!replymp)
62 bug("Could not create the reply port!\n");
63 return;
66 TimerIO = (struct timerequest *) CreateIORequest(replymp, sizeof(struct timerequest));
68 if (TimerIO == NULL)
70 DebugPrintF("Out of memory.\n");
71 return;
74 if (OpenDevice((CONST_STRPTR) "timer.device", UNIT_MICROHZ, (struct IORequest *) TimerIO, 0) != 0)
76 DebugPrintF("Unable to open 'timer.device'.\n");
77 return;
79 else
81 TimerBase = (struct Device *) TimerIO->tr_node.io_Device;
84 if (TimerIO)
86 TimerIO->tr_node.io_Command = TR_ADDREQUEST; /* Add a request. */
87 TimerIO->tr_time.tv_secs = 0; /* 0 seconds. */
88 TimerIO->tr_time.tv_micro = val; /* 'val' micro seconds. */
89 DoIO((struct IORequest *) TimerIO);
90 DeleteIORequest((struct IORequest *) TimerIO);
91 TimerIO = NULL;
92 CloseDevice((struct IORequest *) TimerIO);
95 if (replymp)
97 DeleteMsgPort(replymp);
101 void WritePartialMask(struct PCIDevice *dev, struct CMI8738_DATA* card, unsigned long reg, unsigned long shift, unsigned long mask, unsigned long val)
103 ULONG tmp;
105 tmp = pci_inl(reg, card);
106 tmp &= ~(mask << shift);
107 tmp |= val << shift;
108 pci_outl(tmp, reg, card);
112 void ClearMask(struct PCIDevice *dev, struct CMI8738_DATA* card, unsigned long reg, unsigned long mask)
114 ULONG tmp;
116 tmp = pci_inl(reg, card);
117 tmp &= ~mask;
118 pci_outl(tmp, reg, card);
122 void WriteMask(struct PCIDevice *dev, struct CMI8738_DATA* card, unsigned long reg, unsigned long mask)
124 ULONG tmp;
126 tmp = pci_inl(reg, card);
127 tmp |= mask;
128 pci_outl(tmp, reg, card);
131 void cmimix_wr(struct PCIDevice *dev, struct CMI8738_DATA* card, unsigned char port, unsigned char val)
133 pci_outb(port, CMPCI_REG_SBADDR, card);
134 pci_outb(val, CMPCI_REG_SBDATA, card);
137 unsigned char cmimix_rd(struct PCIDevice *dev, struct CMI8738_DATA* card, unsigned char port)
139 pci_outb(port, CMPCI_REG_SBADDR, card);
140 return (unsigned char) pci_inb(CMPCI_REG_SBDATA, card);
144 /******************************************************************************
145 ** DriverData allocation ******************************************************
146 ******************************************************************************/
148 // This code used to be in _AHIsub_AllocAudio(), but since we're now
149 // handling CAMD support too, it needs to be done at driver loading
150 // time.
152 struct CMI8738_DATA*
153 AllocDriverData( struct PCIDevice *dev,
154 struct DriverBase* AHIsubBase )
156 struct CMI8738Base* CMI8738Base = (struct CMI8738Base*) AHIsubBase;
157 struct CMI8738_DATA* card;
158 UWORD command_word;
159 ULONG chipvers;
160 int i, v;
161 unsigned char byte;
163 bug("[CMI8738]: %s()\n", __PRETTY_FUNCTION__);
165 // FIXME: This should be non-cachable, DMA-able memory
166 card = AllocVec( sizeof( *card ), MEMF_PUBLIC | MEMF_CLEAR );
168 if( card == NULL )
170 Req( "Unable to allocate driver structure." );
171 return NULL;
174 card->ahisubbase = AHIsubBase;
176 card->interrupt.is_Node.ln_Type = IRQTYPE;
177 card->interrupt.is_Node.ln_Pri = 0;
178 card->interrupt.is_Node.ln_Name = (STRPTR) LibName;
179 #ifdef __AROS__
180 card->interrupt.is_Code = (void(*)(void))&cardinterrupt;
181 #else
182 card->interrupt.is_Code = (void(*)(void))CardInterrupt;
183 #endif
184 card->interrupt.is_Data = (APTR) card;
186 card->playback_interrupt.is_Node.ln_Type = IRQTYPE;
187 card->playback_interrupt.is_Node.ln_Pri = 0;
188 card->playback_interrupt.is_Node.ln_Name = (STRPTR) LibName;
189 #ifdef __AROS__
190 card->playback_interrupt.is_Code = (void(*)(void))&playbackinterrupt;
191 #else
192 card->playback_interrupt.is_Code = (void(*)(void))PlaybackInterrupt;
193 #endif
194 card->playback_interrupt.is_Data = (APTR) card;
196 card->record_interrupt.is_Node.ln_Type = IRQTYPE;
197 card->record_interrupt.is_Node.ln_Pri = 0;
198 card->record_interrupt.is_Node.ln_Name = (STRPTR) LibName;
199 #ifdef __AROS__
200 card->record_interrupt.is_Code = (void(*)(void))&recordinterrupt;
201 #else
202 card->record_interrupt.is_Code = (void(*)(void))RecordInterrupt;
203 #endif
204 card->record_interrupt.is_Data = (APTR) card;
206 card->pci_dev = dev;
208 command_word = inw_config(PCI_COMMAND, dev);
209 command_word |= PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER;
210 outw_config( PCI_COMMAND, command_word, dev);
212 card->pci_master_enabled = TRUE;
214 /*for (i = 0; i < 6; i++)
216 if (dev->GetResourceRange(i))
217 DebugPrintF("BAR[%ld] = %lx\n", i, dev->GetResourceRange(i)->BaseAddress);
220 card->iobase = ahi_pci_get_base_address(0, dev);
221 card->length = ahi_pci_get_base_size(0, dev);
222 card->irq = ahi_pci_get_irq(dev);
223 card->chiprev = inb_config(PCI_REVISION_ID, dev);
224 card->model = inw_config(PCI_SUBSYSTEM_ID, dev);
226 bug("[CMI8738]: %s: iobase = 0x%p, len = %d\n", __PRETTY_FUNCTION__, card->iobase, card->length);
228 chipvers = pci_inl(CMPCI_REG_INTR_CTRL, card) & CMPCI_REG_VERSION_MASK;
229 if (chipvers)
231 if (chipvers & CMPCI_REG_VERSION_68)
233 card->chipvers = 68;
234 card->channels = 8;
236 if (chipvers & CMPCI_REG_VERSION_55)
238 card->chipvers = 55;
239 card->channels = 6;
241 if (chipvers & CMPCI_REG_VERSION_39)
243 card->chipvers = 39;
244 if (chipvers & CMPCI_REG_VERSION_39B)
246 card->channels = 6;
248 else
250 card->channels = 4;
254 else
256 chipvers = pci_inl(CMPCI_REG_CHANNEL_FORMAT, card) & CMPCI_REG_VERSION_37;
257 if (!chipvers)
259 card->chipvers = 33;
260 card->channels = 2;
262 else
264 card->chipvers = 37;
265 card->channels = 2;
268 /*DebugPrintF("---> chiprev = %u, model = %x, Vendor = %x\n", dev->ReadConfigByte( PCI_REVISION_ID), dev->ReadConfigWord( PCI_SUBSYSTEM_ID),
269 dev->ReadConfigWord( PCI_SUBSYSTEM_VENDOR_ID));*/
271 bug("[CMI8738]: %s: chipvers = %u, chiprev = %u, model = %x, Vendor = %x\n", __PRETTY_FUNCTION__,
272 card->chipvers, card->chiprev,
273 card->model,
274 inw_config( PCI_SUBSYSTEM_VENDOR_ID, dev));
276 bug("[CMI8738]: %s: max channels = %d\n", __PRETTY_FUNCTION__, card->channels);
278 /* Initialize chip */
279 if( card_init( card ) < 0 )
281 DebugPrintF("Unable to initialize Card subsystem.");
282 return NULL;
285 //DebugPrintF("INTERRUPT %lu\n", dev->MapInterrupt());
286 ahi_pci_add_intserver(&card->interrupt, dev);
287 card->interrupt_added = TRUE;
289 card->card_initialized = TRUE;
290 card->input = 0;
291 card->output = 0;
292 card->monitor_volume = Linear2MixerGain( 0, &card->monitor_volume_bits );
293 card->input_gain = Linear2RecordGain( 0x10000, &card->input_gain_bits );
294 card->output_volume = Linear2MixerGain( 0x10000, &card->output_volume_bits );
295 SaveMixerState(card);
297 cmimix_wr(dev, card, CMPCI_SB16_MIXER_RESET, 0);
298 cmimix_wr(dev, card, CMPCI_SB16_MIXER_ADCMIX_L, 0); //(CMPCI_SB16_MIXER_LINE_SRC_R << 1) ); // set input to line
299 cmimix_wr(dev, card, CMPCI_SB16_MIXER_ADCMIX_R, 0); //CMPCI_SB16_MIXER_LINE_SRC_R);
301 cmimix_wr(dev, card, CMPCI_SB16_MIXER_OUTMIX, 0); // set output mute off for line and CD
303 cmimix_wr(dev, card, CMPCI_SB16_MIXER_VOICE_L, 0xFF); // PCM
304 cmimix_wr(dev, card, CMPCI_SB16_MIXER_VOICE_R, 0xFF);
306 cmimix_wr(dev, card, CMPCI_SB16_MIXER_CDDA_L, 0x00);
307 cmimix_wr(dev, card, CMPCI_SB16_MIXER_CDDA_R, 0x00);
309 cmimix_wr(dev, card, CMPCI_SB16_MIXER_LINE_L, 0x00);
310 cmimix_wr(dev, card, CMPCI_SB16_MIXER_LINE_R, 0x00);
312 byte = pci_inb(CMPCI_REG_MIXER25, card);
313 pci_outb(byte & ~0x30, CMPCI_REG_MIXER25, card); // mute Aux
314 pci_outb(byte & ~0x01, CMPCI_REG_MIXER25, card); // turn on mic 20dB boost
315 pci_outb(0x00, CMPCI_REG_MIXER_AUX, card);
317 byte = pci_inb(CMPCI_REG_MIXER24, card);
318 pci_outb(byte | CMPCI_REG_FMMUTE, CMPCI_REG_MIXER24, card);
320 cmimix_wr(dev, card, CMPCI_SB16_MIXER_MIC, 0x00);
322 cmimix_wr(dev, card, CMPCI_SB16_MIXER_MASTER_L, 0xFF);
323 cmimix_wr(dev, card, CMPCI_SB16_MIXER_MASTER_R, 0xFF);
325 card->mixerstate = cmimix_rd(dev, card, CMPCI_SB16_MIXER_OUTMIX);
327 #if !defined(__AROS__)
328 AddResetHandler(card);
329 #endif
331 return card;
335 /******************************************************************************
336 ** DriverData deallocation ****************************************************
337 ******************************************************************************/
339 // And this code used to be in _AHIsub_FreeAudio().
341 void
342 FreeDriverData( struct CMI8738_DATA* card,
343 struct DriverBase* AHIsubBase )
346 bug("[CMI8738]: %s()\n", __PRETTY_FUNCTION__);
348 if( card != NULL )
350 if( card->pci_dev != NULL )
352 if( card->card_initialized )
354 card_cleanup( card );
357 if( card->pci_master_enabled )
359 UWORD cmd;
361 cmd = inw_config(PCI_COMMAND, (struct PCIDevice * ) card->pci_dev);
362 cmd &= ~( PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER );
363 outw_config(PCI_COMMAND, cmd, (struct PCIDevice * ) card->pci_dev );
367 if( card->interrupt_added )
369 ahi_pci_rem_intserver(&card->interrupt, card->pci_dev);
372 FreeVec( card );
377 int card_init(struct CMI8738_DATA *card)
379 struct PCIDevice *dev = (struct PCIDevice *) card->pci_dev;
380 unsigned short cod;
381 unsigned long val;
383 bug("[CMI8738]: %s()\n", __PRETTY_FUNCTION__);
385 ClearMask(dev, card, CMPCI_REG_MISC, CMPCI_REG_POWER_DOWN); // power up
387 WriteMask(dev, card, CMPCI_REG_MISC, CMPCI_REG_BUS_AND_DSP_RESET);
388 udelay(1);
389 ClearMask(dev, card, CMPCI_REG_MISC, CMPCI_REG_BUS_AND_DSP_RESET);
391 /* reset channels */
392 WriteMask(dev, card, CMPCI_REG_FUNC_0, CMPCI_REG_CH0_RESET | CMPCI_REG_CH1_RESET);
393 udelay(1);
394 ClearMask(dev, card, CMPCI_REG_FUNC_0, CMPCI_REG_CH0_RESET | CMPCI_REG_CH1_RESET);
396 /* Disable interrupts and channels */
397 ClearMask(dev, card, CMPCI_REG_FUNC_0,CMPCI_REG_CH0_ENABLE | CMPCI_REG_CH1_ENABLE);
398 ClearMask(dev, card, CMPCI_REG_INTR_CTRL, CMPCI_REG_CH0_INTR_ENABLE | CMPCI_REG_CH1_INTR_ENABLE);
400 /* Configure DMA channels, ch0 = play, ch1 = capture */
401 ClearMask(dev, card, CMPCI_REG_FUNC_0, CMPCI_REG_CH0_DIR);
402 WriteMask(dev, card, CMPCI_REG_FUNC_0, CMPCI_REG_CH1_DIR);
404 // digital I/O
405 ClearMask(dev, card, CMPCI_REG_FUNC_1, CMPCI_REG_SPDIFOUT_DAC | CMPCI_REG_SPDIF0_ENABLE);
406 ClearMask(dev, card, CMPCI_REG_LEGACY_CTRL, CMPCI_REG_LEGACY_SPDIF_ENABLE);
408 ClearMask(dev, card, CMPCI_REG_LEGACY_CTRL, 0x80000000);
409 ClearMask(dev, card, CMPCI_REG_CHANNEL_FORMAT, CM_CHB3D);
410 ClearMask(dev, card, CMPCI_REG_CHANNEL_FORMAT, CM_CHB3D5C);
411 ClearMask(dev, card, CMPCI_REG_LEGACY_CTRL, CMPCI_REG_ENABLE_5_1);
412 ClearMask(dev, card, CMPCI_REG_MISC, CMPCI_REG_2ND_SPDIFIN);
413 ClearMask(dev, card, CMPCI_REG_MISC, CMPCI_REG_N4SPK3D);
414 WriteMask(dev, card, CMPCI_REG_INTR_STATUS, CMPCI_REG_LEGACY_STEREO | CMPCI_REG_LEGACY_HDMA);
416 return 0;
420 void card_cleanup(struct CMI8738_DATA *card)
426 /******************************************************************************
427 ** Misc. **********************************************************************
428 ******************************************************************************/
430 void
431 SaveMixerState( struct CMI8738_DATA* card )
433 bug("[CMI8738]: %s()\n", __PRETTY_FUNCTION__);
435 #if 0
436 card->ac97_mic = codec_read( card, AC97_MIC_VOL );
437 card->ac97_cd = codec_read( card, AC97_CD_VOL );
438 card->ac97_video = codec_read( card, AC97_VIDEO_VOL );
439 card->ac97_aux = codec_read( card, AC97_AUX_VOL );
440 card->ac97_linein = codec_read( card, AC97_LINEIN_VOL );
441 card->ac97_phone = codec_read( card, AC97_PHONE_VOL );
442 #endif
446 void
447 RestoreMixerState( struct CMI8738_DATA* card )
449 bug("[CMI8738]: %s()\n", __PRETTY_FUNCTION__);
451 #if 0
452 codec_write(card, AC97_MIC_VOL, card->ac97_mic );
453 codec_write(card, AC97_CD_VOL, card->ac97_cd );
454 codec_write(card, AC97_VIDEO_VOL, card->ac97_video );
455 codec_write(card, AC97_AUX_VOL, card->ac97_aux );
456 codec_write(card, AC97_LINEIN_VOL, card->ac97_linein );
457 codec_write(card, AC97_PHONE_VOL, card->ac97_phone );
458 #endif
461 void
462 UpdateMonitorMixer( struct CMI8738_DATA* card )
464 bug("[CMI8738]: %s()\n", __PRETTY_FUNCTION__);
466 #if 0
467 int i = InputBits[ card->input ];
468 UWORD m = card->monitor_volume_bits & 0x801f;
469 UWORD s = card->monitor_volume_bits;
470 UWORD mm = AC97_MUTE | 0x0008;
471 UWORD sm = AC97_MUTE | 0x0808;
473 if( i == AC97_RECMUX_STEREO_MIX ||
474 i == AC97_RECMUX_MONO_MIX )
476 // Use the original mixer settings
477 RestoreMixerState( card );
479 else
481 codec_write(card, AC97_MIC_VOL,
482 i == AC97_RECMUX_MIC ? m : mm );
484 codec_write(card, AC97_CD_VOL,
485 i == AC97_RECMUX_CD ? s : sm );
487 codec_write(card, AC97_VIDEO_VOL,
488 i == AC97_RECMUX_VIDEO ? s : sm );
490 codec_write(card, AC97_AUX_VOL,
491 i == AC97_RECMUX_AUX ? s : sm );
493 codec_write(card, AC97_LINEIN_VOL,
494 i == AC97_RECMUX_LINE ? s : sm );
496 codec_write(card, AC97_PHONE_VOL,
497 i == AC97_RECMUX_PHONE ? m : mm );
499 #endif
503 Fixed
504 Linear2MixerGain( Fixed linear,
505 UWORD* bits )
507 static const Fixed gain[ 33 ] =
509 260904, // +12.0 dB
510 219523, // +10.5 dB
511 184706, // +9.0 dB
512 155410, // +7.5 dB
513 130762, // +6.0 dB
514 110022, // +4.5 dB
515 92572, // +3.0 dB
516 77890, // +1.5 dB
517 65536, // ±0.0 dB
518 55142, // -1.5 dB
519 46396, // -3.0 dB
520 39037, // -4.5 dB
521 32846, // -6.0 dB
522 27636, // -7.5 dB
523 23253, // -9.0 dB
524 19565, // -10.5 dB
525 16462, // -12.0 dB
526 13851, // -13.5 dB
527 11654, // -15.0 dB
528 9806, // -16.5 dB
529 8250, // -18.0 dB
530 6942, // -19.5 dB
531 5841, // -21.0 dB
532 4915, // -22.5 dB
533 4135, // -24.0 dB
534 3479, // -25.5 dB
535 2927, // -27.0 dB
536 2463, // -28.5 dB
537 2072, // -30.0 dB
538 1744, // -31.5 dB
539 1467, // -33.0 dB
540 1234, // -34.5 dB
541 0 // -oo dB
544 int v = 0;
546 while( linear < gain[ v ] )
548 ++v;
551 if( v == 32 )
553 *bits = 0x8000; // Mute
555 else
557 *bits = ( v << 8 ) | v;
560 // KPrintF( "l2mg %08lx -> %08lx (%04lx)\n", linear, gain[ v ], *bits );
561 return gain[ v ];
564 Fixed
565 Linear2RecordGain( Fixed linear,
566 UWORD* bits )
568 static const Fixed gain[ 17 ] =
570 873937, // +22.5 dB
571 735326, // +21.0 dB
572 618700, // +19.5 dB
573 520571, // +18.0 dB
574 438006, // +16.5 dB
575 368536, // +15.0 dB
576 310084, // +13.5 dB
577 260904, // +12.0 dB
578 219523, // +10.5 dB
579 184706, // +9.0 dB
580 155410, // +7.5 dB
581 130762, // +6.0 dB
582 110022, // +4.5 dB
583 92572, // +3.0 dB
584 77890, // +1.5 dB
585 65536, // ±0.0 dB
586 0 // -oo dB
589 int v = 0;
591 while( linear < gain[ v ] )
593 ++v;
596 if( v == 16 )
598 *bits = 0x8000; // Mute
600 else
602 *bits = ( ( 15 - v ) << 8 ) | ( 15 - v );
605 return gain[ v ];
609 ULONG
610 SamplerateToLinearPitch( ULONG samplingrate )
612 samplingrate = (samplingrate << 8) / 375;
613 return (samplingrate >> 1) + (samplingrate & 1);
617 APTR DMAheader = 0;
618 #define GFXMEM_BUFFER (64 * 1024) // 64KB should be enough for everyone...
620 void *pci_alloc_consistent(size_t size, APTR *NonAlignedAddress, unsigned int boundary)
622 void* address;
623 unsigned long a;
625 bug("[CMI8738]: %s()\n", __PRETTY_FUNCTION__);
627 address = (void *) AllocVec(size + boundary, MEMF_PUBLIC | MEMF_CLEAR);
629 if (address != NULL)
631 a = (unsigned long) address;
632 a = (a + boundary - 1) & ~(boundary - 1);
633 address = (void *) a;
636 if (NonAlignedAddress)
638 *NonAlignedAddress = address;
641 return address;
645 void pci_free_consistent(void* addr)
647 bug("[CMI8738]: %s()\n", __PRETTY_FUNCTION__);
649 FreeVec(addr);
652 static ULONG ResetHandler(struct ExceptionContext *ctx, struct ExecBase *pExecBase, struct CMI8738_DATA *card)
654 struct PCIDevice *dev = card->pci_dev;
656 bug("[CMI8738]: %s()\n", __PRETTY_FUNCTION__);
658 ClearMask(dev, card, CMPCI_REG_INTR_CTRL, CMPCI_REG_CH0_INTR_ENABLE);
659 ClearMask(dev, card, CMPCI_REG_FUNC_0, CMPCI_REG_CH0_ENABLE);
661 return 0UL;
664 #if !defined(__AROS__)
665 void AddResetHandler(struct CMI8738_DATA *card)
667 static struct Interrupt interrupt;
669 bug("[CMI8738]: %s()\n", __PRETTY_FUNCTION__);
671 interrupt.is_Code = (void (*)())ResetHandler;
672 interrupt.is_Data = (APTR) card;
673 interrupt.is_Node.ln_Pri = 0;
674 interrupt.is_Node.ln_Type = NT_EXTINTERRUPT;
675 interrupt.is_Node.ln_Name = "CMI8738 Reset Handler";
677 AddResetCallback( &interrupt );
679 #endif