revert between 56095 -> 55830 in arch
[AROS.git] / workbench / devs / AHI / Drivers / CMI8738 / misc.c
blobc17cfa6ad0b3c531e59e71276cb973cedade4c64
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 INTGW
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 timerequest* TimerIO = NULL;
56 struct MsgPort * replymp;
58 replymp = (struct MsgPort *) CreateMsgPort();
59 if (!replymp)
61 bug("Could not create the reply port!\n");
62 return;
65 TimerIO = (struct timerequest *) CreateIORequest(replymp, sizeof(struct timerequest));
67 if (TimerIO == NULL)
69 DebugPrintF("Out of memory.\n");
70 return;
73 if (OpenDevice((CONST_STRPTR) "timer.device", UNIT_MICROHZ, (struct IORequest *) TimerIO, 0) != 0)
75 DebugPrintF("Unable to open 'timer.device'.\n");
76 return;
79 TimerIO->tr_node.io_Command = TR_ADDREQUEST; /* Add a request. */
80 TimerIO->tr_time.tv_secs = 0; /* 0 seconds. */
81 TimerIO->tr_time.tv_micro = val; /* 'val' micro seconds. */
82 DoIO((struct IORequest *) TimerIO);
83 CloseDevice((struct IORequest *) TimerIO);
84 DeleteIORequest((struct IORequest *) TimerIO);
85 TimerIO = NULL;
87 if (replymp)
89 DeleteMsgPort(replymp);
93 void WritePartialMask(struct PCIDevice *dev, struct CMI8738_DATA* card, unsigned long reg, unsigned long shift, unsigned long mask, unsigned long val)
95 ULONG tmp;
97 tmp = pci_inl(reg, card);
98 tmp &= ~(mask << shift);
99 tmp |= val << shift;
100 pci_outl(tmp, reg, card);
104 void ClearMask(struct PCIDevice *dev, struct CMI8738_DATA* card, unsigned long reg, unsigned long mask)
106 ULONG tmp;
108 tmp = pci_inl(reg, card);
109 tmp &= ~mask;
110 pci_outl(tmp, reg, card);
114 void WriteMask(struct PCIDevice *dev, struct CMI8738_DATA* card, unsigned long reg, unsigned long mask)
116 ULONG tmp;
118 tmp = pci_inl(reg, card);
119 tmp |= mask;
120 pci_outl(tmp, reg, card);
123 void cmimix_wr(struct PCIDevice *dev, struct CMI8738_DATA* card, unsigned char port, unsigned char val)
125 pci_outb(port, CMPCI_REG_SBADDR, card);
126 pci_outb(val, CMPCI_REG_SBDATA, card);
129 unsigned char cmimix_rd(struct PCIDevice *dev, struct CMI8738_DATA* card, unsigned char port)
131 pci_outb(port, CMPCI_REG_SBADDR, card);
132 return (unsigned char) pci_inb(CMPCI_REG_SBDATA, card);
136 /******************************************************************************
137 ** DriverData allocation ******************************************************
138 ******************************************************************************/
140 // This code used to be in _AHIsub_AllocAudio(), but since we're now
141 // handling CAMD support too, it needs to be done at driver loading
142 // time.
144 struct CMI8738_DATA*
145 AllocDriverData( struct PCIDevice *dev,
146 struct DriverBase* AHIsubBase )
148 struct CMI8738_DATA* card;
149 UWORD command_word;
150 ULONG chipvers;
151 #ifndef __AROS__
152 int i, v;
153 #endif
154 unsigned char byte;
156 bug("[CMI8738]: %s()\n", __PRETTY_FUNCTION__);
158 // FIXME: This should be non-cachable, DMA-able memory
159 card = AllocVec( sizeof( *card ), MEMF_PUBLIC | MEMF_CLEAR );
161 if( card == NULL )
163 Req( "Unable to allocate driver structure." );
164 return NULL;
167 card->ahisubbase = AHIsubBase;
169 card->interrupt.is_Node.ln_Type = IRQTYPE;
170 card->interrupt.is_Node.ln_Pri = 0;
171 card->interrupt.is_Node.ln_Name = (STRPTR) LibName;
172 #ifdef INTGW
173 card->interrupt.is_Code = (VOID_FUNC)cardinterrupt;
174 #else
175 card->interrupt.is_Code = (void(*)(void))CardInterrupt;
176 #endif
177 card->interrupt.is_Data = (APTR) card;
179 card->playback_interrupt.is_Node.ln_Type = IRQTYPE;
180 card->playback_interrupt.is_Node.ln_Pri = 0;
181 card->playback_interrupt.is_Node.ln_Name = (STRPTR) LibName;
182 #ifdef INTGW
183 card->playback_interrupt.is_Code = (VOID_FUNC)playbackinterrupt;
184 #else
185 card->playback_interrupt.is_Code = (void(*)(void))PlaybackInterrupt;
186 #endif
187 card->playback_interrupt.is_Data = (APTR) card;
189 card->record_interrupt.is_Node.ln_Type = IRQTYPE;
190 card->record_interrupt.is_Node.ln_Pri = 0;
191 card->record_interrupt.is_Node.ln_Name = (STRPTR) LibName;
192 #ifdef INTGW
193 card->record_interrupt.is_Code = (VOID_FUNC)recordinterrupt;
194 #else
195 card->record_interrupt.is_Code = (void(*)(void))RecordInterrupt;
196 #endif
197 card->record_interrupt.is_Data = (APTR) card;
199 card->pci_dev = dev;
201 command_word = inw_config(PCI_COMMAND, dev);
202 command_word |= PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER;
203 outw_config( PCI_COMMAND, command_word, dev);
205 card->pci_master_enabled = TRUE;
207 /*for (i = 0; i < 6; i++)
209 if (dev->GetResourceRange(i))
210 DebugPrintF("BAR[%ld] = %lx\n", i, dev->GetResourceRange(i)->BaseAddress);
213 card->iobase = ahi_pci_get_base_address(0, dev);
214 card->length = ahi_pci_get_base_size(0, dev);
215 card->irq = ahi_pci_get_irq(dev);
216 card->chiprev = inb_config(PCI_REVISION_ID, dev);
217 card->model = inw_config(PCI_SUBSYSTEM_ID, dev);
219 bug("[CMI8738]: %s: iobase = 0x%p, len = %d\n", __PRETTY_FUNCTION__, card->iobase, card->length);
221 chipvers = pci_inl(CMPCI_REG_INTR_CTRL, card) & CMPCI_REG_VERSION_MASK;
222 if (chipvers)
224 if (chipvers & CMPCI_REG_VERSION_68)
226 card->chipvers = 68;
227 card->channels = 8;
229 if (chipvers & CMPCI_REG_VERSION_55)
231 card->chipvers = 55;
232 card->channels = 6;
234 if (chipvers & CMPCI_REG_VERSION_39)
236 card->chipvers = 39;
237 if (chipvers & CMPCI_REG_VERSION_39B)
239 card->channels = 6;
241 else
243 card->channels = 4;
247 else
249 chipvers = pci_inl(CMPCI_REG_CHANNEL_FORMAT, card) & CMPCI_REG_VERSION_37;
250 if (!chipvers)
252 card->chipvers = 33;
253 card->channels = 2;
255 else
257 card->chipvers = 37;
258 card->channels = 2;
261 /*DebugPrintF("---> chiprev = %u, model = %x, Vendor = %x\n", dev->ReadConfigByte( PCI_REVISION_ID), dev->ReadConfigWord( PCI_SUBSYSTEM_ID),
262 dev->ReadConfigWord( PCI_SUBSYSTEM_VENDOR_ID));*/
264 bug("[CMI8738]: %s: chipvers = %u, chiprev = %u, model = %x, Vendor = %x\n", __PRETTY_FUNCTION__,
265 card->chipvers, card->chiprev,
266 card->model,
267 inw_config( PCI_SUBSYSTEM_VENDOR_ID, dev));
269 bug("[CMI8738]: %s: max channels = %d\n", __PRETTY_FUNCTION__, card->channels);
271 /* Initialize chip */
272 if( card_init( card ) < 0 )
274 DebugPrintF("Unable to initialize Card subsystem.");
275 return NULL;
278 //DebugPrintF("INTERRUPT %lu\n", dev->MapInterrupt());
279 ahi_pci_add_intserver(&card->interrupt, dev);
280 card->interrupt_added = TRUE;
282 card->card_initialized = TRUE;
283 card->input = 0;
284 card->output = 0;
285 card->monitor_volume = Linear2MixerGain( 0, &card->monitor_volume_bits );
286 card->input_gain = Linear2RecordGain( 0x10000, &card->input_gain_bits );
287 card->output_volume = Linear2MixerGain( 0x10000, &card->output_volume_bits );
288 SaveMixerState(card);
290 cmimix_wr(dev, card, CMPCI_SB16_MIXER_RESET, 0);
291 cmimix_wr(dev, card, CMPCI_SB16_MIXER_ADCMIX_L, 0); //(CMPCI_SB16_MIXER_LINE_SRC_R << 1) ); // set input to line
292 cmimix_wr(dev, card, CMPCI_SB16_MIXER_ADCMIX_R, 0); //CMPCI_SB16_MIXER_LINE_SRC_R);
294 cmimix_wr(dev, card, CMPCI_SB16_MIXER_OUTMIX, 0); // set output mute off for line and CD
296 cmimix_wr(dev, card, CMPCI_SB16_MIXER_VOICE_L, 0xFF); // PCM
297 cmimix_wr(dev, card, CMPCI_SB16_MIXER_VOICE_R, 0xFF);
299 cmimix_wr(dev, card, CMPCI_SB16_MIXER_CDDA_L, 0x00);
300 cmimix_wr(dev, card, CMPCI_SB16_MIXER_CDDA_R, 0x00);
302 cmimix_wr(dev, card, CMPCI_SB16_MIXER_LINE_L, 0x00);
303 cmimix_wr(dev, card, CMPCI_SB16_MIXER_LINE_R, 0x00);
305 byte = pci_inb(CMPCI_REG_MIXER25, card);
306 pci_outb(byte & ~0x30, CMPCI_REG_MIXER25, card); // mute Aux
307 pci_outb(byte & ~0x01, CMPCI_REG_MIXER25, card); // turn on mic 20dB boost
308 pci_outb(0x00, CMPCI_REG_MIXER_AUX, card);
310 byte = pci_inb(CMPCI_REG_MIXER24, card);
311 pci_outb(byte | CMPCI_REG_FMMUTE, CMPCI_REG_MIXER24, card);
313 cmimix_wr(dev, card, CMPCI_SB16_MIXER_MIC, 0x00);
315 cmimix_wr(dev, card, CMPCI_SB16_MIXER_MASTER_L, 0xFF);
316 cmimix_wr(dev, card, CMPCI_SB16_MIXER_MASTER_R, 0xFF);
318 card->mixerstate = cmimix_rd(dev, card, CMPCI_SB16_MIXER_OUTMIX);
320 #if !defined(__AROS__)
321 AddResetHandler(card);
322 #endif
324 return card;
328 /******************************************************************************
329 ** DriverData deallocation ****************************************************
330 ******************************************************************************/
332 // And this code used to be in _AHIsub_FreeAudio().
334 void
335 FreeDriverData( struct CMI8738_DATA* card,
336 struct DriverBase* AHIsubBase )
339 bug("[CMI8738]: %s()\n", __PRETTY_FUNCTION__);
341 if( card != NULL )
343 if( card->pci_dev != NULL )
345 if( card->card_initialized )
347 card_cleanup( card );
350 if( card->pci_master_enabled )
352 UWORD cmd;
354 cmd = inw_config(PCI_COMMAND, (struct PCIDevice * ) card->pci_dev);
355 cmd &= ~( PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER );
356 outw_config(PCI_COMMAND, cmd, (struct PCIDevice * ) card->pci_dev );
360 if( card->interrupt_added )
362 ahi_pci_rem_intserver(&card->interrupt, card->pci_dev);
365 FreeVec( card );
370 int card_init(struct CMI8738_DATA *card)
372 struct PCIDevice *dev = (struct PCIDevice *) card->pci_dev;
374 bug("[CMI8738]: %s()\n", __PRETTY_FUNCTION__);
376 ClearMask(dev, card, CMPCI_REG_MISC, CMPCI_REG_POWER_DOWN); // power up
378 WriteMask(dev, card, CMPCI_REG_MISC, CMPCI_REG_BUS_AND_DSP_RESET);
379 udelay(1);
380 ClearMask(dev, card, CMPCI_REG_MISC, CMPCI_REG_BUS_AND_DSP_RESET);
382 /* reset channels */
383 WriteMask(dev, card, CMPCI_REG_FUNC_0, CMPCI_REG_CH0_RESET | CMPCI_REG_CH1_RESET);
384 udelay(1);
385 ClearMask(dev, card, CMPCI_REG_FUNC_0, CMPCI_REG_CH0_RESET | CMPCI_REG_CH1_RESET);
387 /* Disable interrupts and channels */
388 ClearMask(dev, card, CMPCI_REG_FUNC_0,CMPCI_REG_CH0_ENABLE | CMPCI_REG_CH1_ENABLE);
389 ClearMask(dev, card, CMPCI_REG_INTR_CTRL, CMPCI_REG_CH0_INTR_ENABLE | CMPCI_REG_CH1_INTR_ENABLE);
391 /* Configure DMA channels, ch0 = play, ch1 = capture */
392 ClearMask(dev, card, CMPCI_REG_FUNC_0, CMPCI_REG_CH0_DIR);
393 WriteMask(dev, card, CMPCI_REG_FUNC_0, CMPCI_REG_CH1_DIR);
395 // digital I/O
396 ClearMask(dev, card, CMPCI_REG_FUNC_1, CMPCI_REG_SPDIFOUT_DAC | CMPCI_REG_SPDIF0_ENABLE);
397 ClearMask(dev, card, CMPCI_REG_LEGACY_CTRL, CMPCI_REG_LEGACY_SPDIF_ENABLE);
399 ClearMask(dev, card, CMPCI_REG_LEGACY_CTRL, 0x80000000);
400 ClearMask(dev, card, CMPCI_REG_CHANNEL_FORMAT, CM_CHB3D);
401 ClearMask(dev, card, CMPCI_REG_CHANNEL_FORMAT, CM_CHB3D5C);
402 ClearMask(dev, card, CMPCI_REG_LEGACY_CTRL, CMPCI_REG_ENABLE_5_1);
403 ClearMask(dev, card, CMPCI_REG_MISC, CMPCI_REG_2ND_SPDIFIN);
404 ClearMask(dev, card, CMPCI_REG_MISC, CMPCI_REG_N4SPK3D);
405 WriteMask(dev, card, CMPCI_REG_INTR_STATUS, CMPCI_REG_LEGACY_STEREO | CMPCI_REG_LEGACY_HDMA);
407 return 0;
411 void card_cleanup(struct CMI8738_DATA *card)
417 /******************************************************************************
418 ** Misc. **********************************************************************
419 ******************************************************************************/
421 void
422 SaveMixerState( struct CMI8738_DATA* card )
424 bug("[CMI8738]: %s()\n", __PRETTY_FUNCTION__);
426 #if 0
427 card->ac97_mic = codec_read( card, AC97_MIC_VOL );
428 card->ac97_cd = codec_read( card, AC97_CD_VOL );
429 card->ac97_video = codec_read( card, AC97_VIDEO_VOL );
430 card->ac97_aux = codec_read( card, AC97_AUX_VOL );
431 card->ac97_linein = codec_read( card, AC97_LINEIN_VOL );
432 card->ac97_phone = codec_read( card, AC97_PHONE_VOL );
433 #endif
437 void
438 RestoreMixerState( struct CMI8738_DATA* card )
440 bug("[CMI8738]: %s()\n", __PRETTY_FUNCTION__);
442 #if 0
443 codec_write(card, AC97_MIC_VOL, card->ac97_mic );
444 codec_write(card, AC97_CD_VOL, card->ac97_cd );
445 codec_write(card, AC97_VIDEO_VOL, card->ac97_video );
446 codec_write(card, AC97_AUX_VOL, card->ac97_aux );
447 codec_write(card, AC97_LINEIN_VOL, card->ac97_linein );
448 codec_write(card, AC97_PHONE_VOL, card->ac97_phone );
449 #endif
452 void
453 UpdateMonitorMixer( struct CMI8738_DATA* card )
455 bug("[CMI8738]: %s()\n", __PRETTY_FUNCTION__);
457 #if 0
458 int i = InputBits[ card->input ];
459 UWORD m = card->monitor_volume_bits & 0x801f;
460 UWORD s = card->monitor_volume_bits;
461 UWORD mm = AC97_MUTE | 0x0008;
462 UWORD sm = AC97_MUTE | 0x0808;
464 if( i == AC97_RECMUX_STEREO_MIX ||
465 i == AC97_RECMUX_MONO_MIX )
467 // Use the original mixer settings
468 RestoreMixerState( card );
470 else
472 codec_write(card, AC97_MIC_VOL,
473 i == AC97_RECMUX_MIC ? m : mm );
475 codec_write(card, AC97_CD_VOL,
476 i == AC97_RECMUX_CD ? s : sm );
478 codec_write(card, AC97_VIDEO_VOL,
479 i == AC97_RECMUX_VIDEO ? s : sm );
481 codec_write(card, AC97_AUX_VOL,
482 i == AC97_RECMUX_AUX ? s : sm );
484 codec_write(card, AC97_LINEIN_VOL,
485 i == AC97_RECMUX_LINE ? s : sm );
487 codec_write(card, AC97_PHONE_VOL,
488 i == AC97_RECMUX_PHONE ? m : mm );
490 #endif
494 Fixed
495 Linear2MixerGain( Fixed linear,
496 UWORD* bits )
498 static const Fixed gain[ 33 ] =
500 260904, // +12.0 dB
501 219523, // +10.5 dB
502 184706, // +9.0 dB
503 155410, // +7.5 dB
504 130762, // +6.0 dB
505 110022, // +4.5 dB
506 92572, // +3.0 dB
507 77890, // +1.5 dB
508 65536, // ±0.0 dB
509 55142, // -1.5 dB
510 46396, // -3.0 dB
511 39037, // -4.5 dB
512 32846, // -6.0 dB
513 27636, // -7.5 dB
514 23253, // -9.0 dB
515 19565, // -10.5 dB
516 16462, // -12.0 dB
517 13851, // -13.5 dB
518 11654, // -15.0 dB
519 9806, // -16.5 dB
520 8250, // -18.0 dB
521 6942, // -19.5 dB
522 5841, // -21.0 dB
523 4915, // -22.5 dB
524 4135, // -24.0 dB
525 3479, // -25.5 dB
526 2927, // -27.0 dB
527 2463, // -28.5 dB
528 2072, // -30.0 dB
529 1744, // -31.5 dB
530 1467, // -33.0 dB
531 1234, // -34.5 dB
532 0 // -oo dB
535 int v = 0;
537 while( linear < gain[ v ] )
539 ++v;
542 if( v == 32 )
544 *bits = 0x8000; // Mute
546 else
548 *bits = ( v << 8 ) | v;
551 // KPrintF( "l2mg %08lx -> %08lx (%04lx)\n", linear, gain[ v ], *bits );
552 return gain[ v ];
555 Fixed
556 Linear2RecordGain( Fixed linear,
557 UWORD* bits )
559 static const Fixed gain[ 17 ] =
561 873937, // +22.5 dB
562 735326, // +21.0 dB
563 618700, // +19.5 dB
564 520571, // +18.0 dB
565 438006, // +16.5 dB
566 368536, // +15.0 dB
567 310084, // +13.5 dB
568 260904, // +12.0 dB
569 219523, // +10.5 dB
570 184706, // +9.0 dB
571 155410, // +7.5 dB
572 130762, // +6.0 dB
573 110022, // +4.5 dB
574 92572, // +3.0 dB
575 77890, // +1.5 dB
576 65536, // ±0.0 dB
577 0 // -oo dB
580 int v = 0;
582 while( linear < gain[ v ] )
584 ++v;
587 if( v == 16 )
589 *bits = 0x8000; // Mute
591 else
593 *bits = ( ( 15 - v ) << 8 ) | ( 15 - v );
596 return gain[ v ];
600 ULONG
601 SamplerateToLinearPitch( ULONG samplingrate )
603 samplingrate = (samplingrate << 8) / 375;
604 return (samplingrate >> 1) + (samplingrate & 1);
608 APTR DMAheader = 0;
609 #define GFXMEM_BUFFER (64 * 1024) // 64KB should be enough for everyone...
611 void *pci_alloc_consistent(size_t size, APTR *NonAlignedAddress, unsigned int boundary)
613 void* address;
614 unsigned long a;
616 bug("[CMI8738]: %s()\n", __PRETTY_FUNCTION__);
618 address = (void *) AllocVec(size + boundary, MEMF_PUBLIC | MEMF_CLEAR);
620 if (address != NULL)
622 a = (unsigned long) address;
623 a = (a + boundary - 1) & ~(boundary - 1);
624 address = (void *) a;
627 if (NonAlignedAddress)
629 *NonAlignedAddress = address;
632 return address;
636 void pci_free_consistent(void* addr)
638 bug("[CMI8738]: %s()\n", __PRETTY_FUNCTION__);
640 FreeVec(addr);
643 #if !defined(__AROS__)
644 static ULONG ResetHandler(struct ExceptionContext *ctx, struct ExecBase *pExecBase, struct CMI8738_DATA *card)
646 struct PCIDevice *dev = card->pci_dev;
648 bug("[CMI8738]: %s()\n", __PRETTY_FUNCTION__);
650 ClearMask(dev, card, CMPCI_REG_INTR_CTRL, CMPCI_REG_CH0_INTR_ENABLE);
651 ClearMask(dev, card, CMPCI_REG_FUNC_0, CMPCI_REG_CH0_ENABLE);
653 return 0UL;
656 void AddResetHandler(struct CMI8738_DATA *card)
658 static struct Interrupt interrupt;
660 bug("[CMI8738]: %s()\n", __PRETTY_FUNCTION__);
662 interrupt.is_Code = (void (*)())ResetHandler;
663 interrupt.is_Data = (APTR) card;
664 interrupt.is_Node.ln_Pri = 0;
665 interrupt.is_Node.ln_Type = NT_EXTINTERRUPT;
666 interrupt.is_Node.ln_Name = "CMI8738 Reset Handler";
668 AddResetCallback( &interrupt );
670 #endif