Importing CMI8738-20072011
[AROS.git] / workbench / devs / AHI / Drivers / CMI8738 / misc.c
blobe4831e60891194b17e6328c2ad2571babd9e1eba
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>
15 #ifdef __amigaos4__
16 #undef __USE_INLINE__
17 #include <proto/expansion.h>
18 #else
19 #include <libraries/openpci.h>
20 #include <proto/openpci.h>
21 #endif
23 #include <proto/exec.h>
24 #include <proto/dos.h>
25 #include <proto/fakedma.h>
26 #include <string.h>
28 #include "library_card.h"
29 #include "regs.h"
30 #include "interrupt.h"
31 #include "misc.h"
32 #include "DriverData.h"
34 #define CACHELINE_SIZE 32
36 /* Global in Card.c */
37 extern const UWORD InputBits[];
38 extern struct DOSIFace *IDOS;
39 extern struct FakeDMAIFace *IFakeDMA;
41 /* Public functions in main.c */
42 int card_init(struct CardData *card);
43 void card_cleanup(struct CardData *card);
44 void AddResetHandler(struct CardData *card);
47 void WritePartialMask(struct PCIDevice *dev, struct CardData* card, unsigned long reg, unsigned long shift, unsigned long mask, unsigned long val)
49 ULONG tmp;
51 tmp = dev->InLong(card->iobase + reg);
52 tmp &= ~(mask << shift);
53 tmp |= val << shift;
54 dev->OutLong(card->iobase + reg, tmp);
58 void ClearMask(struct PCIDevice *dev, struct CardData* card, unsigned long reg, unsigned long mask)
60 ULONG tmp;
62 tmp = dev->InLong(card->iobase + reg);
63 tmp &= ~mask;
64 dev->OutLong(card->iobase + reg, tmp);
68 void WriteMask(struct PCIDevice *dev, struct CardData* card, unsigned long reg, unsigned long mask)
70 ULONG tmp;
72 tmp = dev->InLong(card->iobase + reg);
73 tmp |= mask;
74 dev->OutLong(card->iobase + reg, tmp);
77 void cmimix_wr(struct PCIDevice *dev, struct CardData* card, unsigned char port, unsigned char val)
79 dev->OutByte(card->iobase + CMPCI_REG_SBADDR, port);
80 dev->OutByte(card->iobase + CMPCI_REG_SBDATA, val);
83 unsigned char cmimix_rd(struct PCIDevice *dev, struct CardData* card, unsigned char port)
85 dev->OutByte(card->iobase + CMPCI_REG_SBADDR, port);
86 return (unsigned char) dev->InByte(card->iobase + CMPCI_REG_SBDATA);
90 /******************************************************************************
91 ** DriverData allocation ******************************************************
92 ******************************************************************************/
94 // This code used to be in _AHIsub_AllocAudio(), but since we're now
95 // handling CAMD support too, it needs to be done at driver loading
96 // time.
98 struct CardData*
99 AllocDriverData( struct PCIDevice *dev,
100 struct DriverBase* AHIsubBase )
102 struct CardBase* CardBase = (struct CardBase*) AHIsubBase;
103 struct CardData* card;
104 UWORD command_word;
105 int i, v;
106 unsigned char byte;
108 // FIXME: This should be non-cachable, DMA-able memory
109 card = IExec->AllocVec( sizeof( *card ), MEMF_PUBLIC | MEMF_CLEAR );
111 if( card == NULL )
113 Req( "Unable to allocate driver structure." );
114 return NULL;
117 card->ahisubbase = AHIsubBase;
119 card->interrupt.is_Node.ln_Type = NT_EXTINTERRUPT;
120 card->interrupt.is_Node.ln_Pri = 0;
121 card->interrupt.is_Node.ln_Name = (STRPTR) LibName;
122 card->interrupt.is_Code = (void(*)(void)) CardInterrupt;
123 card->interrupt.is_Data = (APTR) card;
125 card->playback_interrupt.is_Node.ln_Type = NT_EXTINTERRUPT;
126 card->playback_interrupt.is_Node.ln_Pri = 0;
127 card->playback_interrupt.is_Node.ln_Name = (STRPTR) LibName;
128 card->playback_interrupt.is_Code = PlaybackInterrupt;
129 card->playback_interrupt.is_Data = (APTR) card;
131 card->record_interrupt.is_Node.ln_Type = NT_EXTINTERRUPT;
132 card->record_interrupt.is_Node.ln_Pri = 0;
133 card->record_interrupt.is_Node.ln_Name = (STRPTR) LibName;
134 card->record_interrupt.is_Code = RecordInterrupt;
135 card->record_interrupt.is_Data = (APTR) card;
137 card->pci_dev = dev;
139 command_word = dev->ReadConfigWord( PCI_COMMAND );
140 command_word |= PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER;
141 dev->WriteConfigWord( PCI_COMMAND, command_word );
143 card->pci_master_enabled = TRUE;
145 /*for (i = 0; i < 6; i++)
147 if (dev->GetResourceRange(i))
148 IExec->DebugPrintF("BAR[%ld] = %lx\n", i, dev->GetResourceRange(i)->BaseAddress);
151 card->iobase = dev->GetResourceRange(0)->BaseAddress;
152 card->length = ~( dev->GetResourceRange(0)->Size & PCI_BASE_ADDRESS_IO_MASK );
153 card->irq = dev->MapInterrupt();
154 card->chiprev = dev->ReadConfigByte( PCI_REVISION_ID);
155 card->model = dev->ReadConfigWord( PCI_SUBSYSTEM_ID);
157 /*IExec->DebugPrintF("---> chiprev = %u, model = %x, Vendor = %x\n", dev->ReadConfigByte( PCI_REVISION_ID), dev->ReadConfigWord( PCI_SUBSYSTEM_ID),
158 dev->ReadConfigWord( PCI_SUBSYSTEM_VENDOR_ID));*/
161 /* Initialize chip */
162 if( card_init( card ) < 0 )
164 IExec->DebugPrintF("Unable to initialize Card subsystem.");
165 return NULL;
169 //IExec->DebugPrintF("INTERRUPT %lu\n", dev->MapInterrupt());
170 IExec->AddIntServer(dev->MapInterrupt(), &card->interrupt );
171 card->interrupt_added = TRUE;
174 card->card_initialized = TRUE;
175 card->input = 0;
176 card->output = 0;
177 card->monitor_volume = Linear2MixerGain( 0, &card->monitor_volume_bits );
178 card->input_gain = Linear2RecordGain( 0x10000, &card->input_gain_bits );
179 card->output_volume = Linear2MixerGain( 0x10000, &card->output_volume_bits );
180 SaveMixerState(card);
182 cmimix_wr(dev, card, CMPCI_SB16_MIXER_RESET, 0);
183 cmimix_wr(dev, card, CMPCI_SB16_MIXER_ADCMIX_L, 0); //(CMPCI_SB16_MIXER_LINE_SRC_R << 1) ); // set input to line
184 cmimix_wr(dev, card, CMPCI_SB16_MIXER_ADCMIX_R, 0); //CMPCI_SB16_MIXER_LINE_SRC_R);
186 cmimix_wr(dev, card, CMPCI_SB16_MIXER_OUTMIX, 0); // set output mute off for line and CD
188 cmimix_wr(dev, card, CMPCI_SB16_MIXER_VOICE_L, 0xFF); // PCM
189 cmimix_wr(dev, card, CMPCI_SB16_MIXER_VOICE_R, 0xFF);
191 cmimix_wr(dev, card, CMPCI_SB16_MIXER_CDDA_L, 0x00);
192 cmimix_wr(dev, card, CMPCI_SB16_MIXER_CDDA_R, 0x00);
194 cmimix_wr(dev, card, CMPCI_SB16_MIXER_LINE_L, 0x00);
195 cmimix_wr(dev, card, CMPCI_SB16_MIXER_LINE_R, 0x00);
197 byte = dev->InByte(card->iobase + CMPCI_REG_MIXER25);
198 dev->OutByte(card->iobase + CMPCI_REG_MIXER25, byte & ~0x30); // mute Aux
199 dev->OutByte(card->iobase + CMPCI_REG_MIXER25, byte & ~0x01); // turn on mic 20dB boost
200 dev->OutByte(card->iobase + CMPCI_REG_MIXER_AUX, 0x00);
202 byte = dev->InByte(card->iobase + CMPCI_REG_MIXER24);
203 dev->OutByte(card->iobase + CMPCI_REG_MIXER24, byte | CMPCI_REG_FMMUTE);
205 cmimix_wr(dev, card, CMPCI_SB16_MIXER_MIC, 0x00);
207 cmimix_wr(dev, card, CMPCI_SB16_MIXER_MASTER_L, 0xFF);
208 cmimix_wr(dev, card, CMPCI_SB16_MIXER_MASTER_R, 0xFF);
210 card->mixerstate = cmimix_rd(dev, card, CMPCI_SB16_MIXER_OUTMIX);
212 AddResetHandler(card);
214 return card;
218 /******************************************************************************
219 ** DriverData deallocation ****************************************************
220 ******************************************************************************/
222 // And this code used to be in _AHIsub_FreeAudio().
224 void
225 FreeDriverData( struct CardData* card,
226 struct DriverBase* AHIsubBase )
228 if( card != NULL )
230 if( card->pci_dev != NULL )
232 if( card->card_initialized )
234 card_cleanup( card );
237 if( card->pci_master_enabled )
239 UWORD cmd;
241 cmd = ((struct PCIDevice * ) card->pci_dev)->ReadConfigWord( PCI_COMMAND );
242 cmd &= ~( PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER );
243 ((struct PCIDevice * ) card->pci_dev)->WriteConfigWord( PCI_COMMAND, cmd );
247 if( card->interrupt_added )
249 IExec->RemIntServer(((struct PCIDevice * ) card->pci_dev)->MapInterrupt(), &card->interrupt );
252 IExec->FreeVec( card );
257 int card_init(struct CardData *card)
259 struct PCIDevice *dev = (struct PCIDevice *) card->pci_dev;
260 unsigned short cod;
261 unsigned long val;
263 ClearMask(dev, card, CMPCI_REG_MISC, CMPCI_REG_POWER_DOWN); // power up
265 WriteMask(dev, card, CMPCI_REG_MISC, CMPCI_REG_BUS_AND_DSP_RESET);
266 IDOS->Delay(1);
267 ClearMask(dev, card, CMPCI_REG_MISC, CMPCI_REG_BUS_AND_DSP_RESET);
269 /* reset channels */
270 WriteMask(dev, card, CMPCI_REG_FUNC_0, CMPCI_REG_CH0_RESET | CMPCI_REG_CH1_RESET);
271 IDOS->Delay(1);
272 ClearMask(dev, card, CMPCI_REG_FUNC_0, CMPCI_REG_CH0_RESET | CMPCI_REG_CH1_RESET);
274 /* Disable interrupts and channels */
275 ClearMask(dev, card, CMPCI_REG_FUNC_0,CMPCI_REG_CH0_ENABLE | CMPCI_REG_CH1_ENABLE);
276 ClearMask(dev, card, CMPCI_REG_INTR_CTRL, CMPCI_REG_CH0_INTR_ENABLE | CMPCI_REG_CH1_INTR_ENABLE);
278 /* Configure DMA channels, ch0 = play, ch1 = capture */
279 ClearMask(dev, card, CMPCI_REG_FUNC_0, CMPCI_REG_CH0_DIR);
280 WriteMask(dev, card, CMPCI_REG_FUNC_0, CMPCI_REG_CH1_DIR);
282 // digital I/O
283 ClearMask(dev, card, CMPCI_REG_FUNC_1, CMPCI_REG_SPDIFOUT_DAC | CMPCI_REG_SPDIF0_ENABLE);
284 ClearMask(dev, card, CMPCI_REG_LEGACY_CTRL, CMPCI_REG_LEGACY_SPDIF_ENABLE);
286 ClearMask(dev, card, CMPCI_REG_LEGACY_CTRL, 0x80000000);
287 ClearMask(dev, card, CMPCI_REG_CHANNEL_FORMAT, CM_CHB3D);
288 ClearMask(dev, card, CMPCI_REG_CHANNEL_FORMAT, CM_CHB3D5C);
289 ClearMask(dev, card, CMPCI_REG_LEGACY_CTRL, CMPCI_REG_ENABLE_5_1);
290 ClearMask(dev, card, CMPCI_REG_MISC, 0x100);
291 ClearMask(dev, card, CMPCI_REG_MISC, CMPCI_REG_N4SPK3D);
292 WriteMask(dev, card, CMPCI_REG_INTR_STATUS, CMPCI_REG_LEGACY_STEREO | CMPCI_REG_LEGACY_HDMA);
294 return 0;
298 void card_cleanup(struct CardData *card)
304 /******************************************************************************
305 ** Misc. **********************************************************************
306 ******************************************************************************/
308 void
309 SaveMixerState( struct CardData* card )
311 #if 0
312 card->ac97_mic = codec_read( card, AC97_MIC_VOL );
313 card->ac97_cd = codec_read( card, AC97_CD_VOL );
314 card->ac97_video = codec_read( card, AC97_VIDEO_VOL );
315 card->ac97_aux = codec_read( card, AC97_AUX_VOL );
316 card->ac97_linein = codec_read( card, AC97_LINEIN_VOL );
317 card->ac97_phone = codec_read( card, AC97_PHONE_VOL );
318 #endif
322 void
323 RestoreMixerState( struct CardData* card )
325 #if 0
326 codec_write(card, AC97_MIC_VOL, card->ac97_mic );
327 codec_write(card, AC97_CD_VOL, card->ac97_cd );
328 codec_write(card, AC97_VIDEO_VOL, card->ac97_video );
329 codec_write(card, AC97_AUX_VOL, card->ac97_aux );
330 codec_write(card, AC97_LINEIN_VOL, card->ac97_linein );
331 codec_write(card, AC97_PHONE_VOL, card->ac97_phone );
332 #endif
335 void
336 UpdateMonitorMixer( struct CardData* card )
338 #if 0
339 int i = InputBits[ card->input ];
340 UWORD m = card->monitor_volume_bits & 0x801f;
341 UWORD s = card->monitor_volume_bits;
342 UWORD mm = AC97_MUTE | 0x0008;
343 UWORD sm = AC97_MUTE | 0x0808;
345 if( i == AC97_RECMUX_STEREO_MIX ||
346 i == AC97_RECMUX_MONO_MIX )
348 // Use the original mixer settings
349 RestoreMixerState( card );
351 else
353 codec_write(card, AC97_MIC_VOL,
354 i == AC97_RECMUX_MIC ? m : mm );
356 codec_write(card, AC97_CD_VOL,
357 i == AC97_RECMUX_CD ? s : sm );
359 codec_write(card, AC97_VIDEO_VOL,
360 i == AC97_RECMUX_VIDEO ? s : sm );
362 codec_write(card, AC97_AUX_VOL,
363 i == AC97_RECMUX_AUX ? s : sm );
365 codec_write(card, AC97_LINEIN_VOL,
366 i == AC97_RECMUX_LINE ? s : sm );
368 codec_write(card, AC97_PHONE_VOL,
369 i == AC97_RECMUX_PHONE ? m : mm );
371 #endif
375 Fixed
376 Linear2MixerGain( Fixed linear,
377 UWORD* bits )
379 static const Fixed gain[ 33 ] =
381 260904, // +12.0 dB
382 219523, // +10.5 dB
383 184706, // +9.0 dB
384 155410, // +7.5 dB
385 130762, // +6.0 dB
386 110022, // +4.5 dB
387 92572, // +3.0 dB
388 77890, // +1.5 dB
389 65536, // ±0.0 dB
390 55142, // -1.5 dB
391 46396, // -3.0 dB
392 39037, // -4.5 dB
393 32846, // -6.0 dB
394 27636, // -7.5 dB
395 23253, // -9.0 dB
396 19565, // -10.5 dB
397 16462, // -12.0 dB
398 13851, // -13.5 dB
399 11654, // -15.0 dB
400 9806, // -16.5 dB
401 8250, // -18.0 dB
402 6942, // -19.5 dB
403 5841, // -21.0 dB
404 4915, // -22.5 dB
405 4135, // -24.0 dB
406 3479, // -25.5 dB
407 2927, // -27.0 dB
408 2463, // -28.5 dB
409 2072, // -30.0 dB
410 1744, // -31.5 dB
411 1467, // -33.0 dB
412 1234, // -34.5 dB
413 0 // -oo dB
416 int v = 0;
418 while( linear < gain[ v ] )
420 ++v;
423 if( v == 32 )
425 *bits = 0x8000; // Mute
427 else
429 *bits = ( v << 8 ) | v;
432 // KPrintF( "l2mg %08lx -> %08lx (%04lx)\n", linear, gain[ v ], *bits );
433 return gain[ v ];
436 Fixed
437 Linear2RecordGain( Fixed linear,
438 UWORD* bits )
440 static const Fixed gain[ 17 ] =
442 873937, // +22.5 dB
443 735326, // +21.0 dB
444 618700, // +19.5 dB
445 520571, // +18.0 dB
446 438006, // +16.5 dB
447 368536, // +15.0 dB
448 310084, // +13.5 dB
449 260904, // +12.0 dB
450 219523, // +10.5 dB
451 184706, // +9.0 dB
452 155410, // +7.5 dB
453 130762, // +6.0 dB
454 110022, // +4.5 dB
455 92572, // +3.0 dB
456 77890, // +1.5 dB
457 65536, // ±0.0 dB
458 0 // -oo dB
461 int v = 0;
463 while( linear < gain[ v ] )
465 ++v;
468 if( v == 16 )
470 *bits = 0x8000; // Mute
472 else
474 *bits = ( ( 15 - v ) << 8 ) | ( 15 - v );
477 return gain[ v ];
481 ULONG
482 SamplerateToLinearPitch( ULONG samplingrate )
484 samplingrate = (samplingrate << 8) / 375;
485 return (samplingrate >> 1) + (samplingrate & 1);
489 APTR DMAheader = 0;
490 #define GFXMEM_BUFFER (64 * 1024) // 64KB should be enough for everyone...
492 void *pci_alloc_consistent(size_t size, APTR *NonAlignedAddress)
494 void* address;
495 unsigned long a;
497 if (IFakeDMA)
499 if (size > GFXMEM_BUFFER)
501 IExec->DebugPrintF("Error allocating memory! Asking %ld bytes\n", size);
504 if (DMAheader == 0)
506 DMAheader = IFakeDMA->AllocDMABuffer(GFXMEM_BUFFER); // alloc once
509 if (DMAheader)
511 APTR bufStart = IFakeDMA->GetDMABufferAttr(DMAheader, DMAB_PUDDLE );
512 ULONG bufSize = (ULONG)IFakeDMA->GetDMABufferAttr(DMAheader, DMAB_SIZE );
514 address = bufStart;
515 *NonAlignedAddress = address;
517 a = (unsigned long) address;
518 a = (a + CACHELINE_SIZE - 1) & ~(CACHELINE_SIZE - 1);
519 address = (void *) a;
521 return address;
525 IExec->DebugPrintF("No gfx mem\n");
526 if (IExec->OpenResource("newmemory.resource"))
528 address = IExec->AllocVecTags(size, AVT_Type, MEMF_SHARED, AVT_Contiguous, TRUE, AVT_Lock, TRUE,
529 AVT_PhysicalAlignment, 32, AVT_Clear, 0, TAG_DONE);
531 else
533 address = IExec->AllocVec( size + CACHELINE_SIZE, MEMF_PUBLIC | MEMF_CLEAR);
535 if( address != NULL )
537 a = (unsigned long) address;
538 a = (a + CACHELINE_SIZE - 1) & ~(CACHELINE_SIZE - 1);
539 address = (void *) a;
543 *NonAlignedAddress = address;
545 return address;
549 void pci_free_consistent(void* addr)
551 if (IFakeDMA)
554 else
556 IExec->FreeVec( addr );
560 static ULONG ResetHandler(struct ExceptionContext *ctx, struct ExecBase *pExecBase, struct CardData *card)
562 struct PCIDevice *dev = card->pci_dev;
564 ClearMask(dev, card, CMPCI_REG_INTR_CTRL, CMPCI_REG_CH0_INTR_ENABLE);
565 ClearMask(dev, card, CMPCI_REG_FUNC_0, CMPCI_REG_CH0_ENABLE);
567 return 0UL;
571 void AddResetHandler(struct CardData *card)
573 static struct Interrupt interrupt;
575 interrupt.is_Code = (void (*)())ResetHandler;
576 interrupt.is_Data = (APTR) card;
577 interrupt.is_Node.ln_Pri = 0;
578 interrupt.is_Node.ln_Type = NT_EXTINTERRUPT;
579 interrupt.is_Node.ln_Name = "reset handler";
581 IExec->AddResetCallback( &interrupt );