Author: wmb Date: Fri Sep 16 02:40:48 2011 New Revision: 2512 URL: http://tracker.coreboot.org/trac/openfirmware/changeset/2512
Log: OLPC XO-1.75 - checkpoint of revised audio code. May still have rough edges.
Modified: cpu/arm/olpc/1.75/alc5631.fth cpu/arm/olpc/1.75/sound.fth dev/hdaudio/noiseburst.fth dev/hdaudio/test.fth
Modified: cpu/arm/olpc/1.75/alc5631.fth ============================================================================== --- cpu/arm/olpc/1.75/alc5631.fth Fri Sep 16 01:34:00 2011 (r2511) +++ cpu/arm/olpc/1.75/alc5631.fth Fri Sep 16 02:40:48 2011 (r2512) @@ -5,38 +5,53 @@ : adc-off ( -- ) h# 0c00 h# 3a codec-clr ; : dac-on ( -- ) h# 0300 h# 3a codec-set ; : dac-off ( -- ) h# 0300 h# 3a codec-clr ; +: adc+dac-on ( -- ) h# 0f00 h# 3a codec-set ; + +: set-routing ( -- ) + h# c0c0 h# 02 codec-set \ SPKMIXLR -> SPKVOLLR, muted + h# c0c0 h# 04 codec-set \ OUTMIXLR -> HPOVOLLR, muted +\ h# a080 h# 06 codec! \ AXO1/AXO2 channel volume select OUTMIXER,0DB by default + h# b0b0 h# 14 codec! \ Record Mixer source from Mic1/Mic2 by default +\ h# 5500 h# 22 codec! \ Mic1/Mic2 boost 20DB by default (done in set-default-gains) + h# dfc0 h# 1a codec! \ DACL -> OUTMIXL - c0 is "don't change it" per datasheet 0.91 + h# dfc0 h# 1c codec! \ DACR -> OUTMIXR - c0 is "don't change it" per datasheet 0.91 + h# d8d8 h# 28 codec! \ DACLR -> SPKMIXLR - 808 is "don't change it" per datasheet 0.91 + h# 6c00 h# 2a codec! \ unmute SPKVOLL -> SPOLMIX, SPKVOLR -> SPORMIX, mute L>R, R>L, and L/R>MONO + h# 0f18 h# 4a codec! \ (undocumented bit 11) enables HP zero-cross detection + + h# 0000 h# 2c codec! \ SPOxMIX -> SPKRMUX, HPOVOL -> HPMUX +;
: codec-on ( -- ) 0 0 codec! \ Reset
- b# 1010.0000.0001.1101 h# 3c codec! \ All on except AX and MONO - d# 110 ms - b# 1110.0000.0001.1101 h# 3c codec! \ Fast VREF control - d# 100 ms + b# 1010.0000.0000.0000 h# 3c codec! \ All on except AX and MONO + d# 80 ms + b# 1110.0000.0000.0000 h# 3c codec! \ Fast VREF control + + set-routing + + h# 8001 h# 34 codec! \ Slave mode, 16 bits, left justified, exchange L and R on playback + + \ The speaker gain ratio must be <= the ratio of SPKVDD to AVDD. + \ In our system, SPKVDD is 5V and AVDD is 3.3V, so we need a gain ratio <= 1.51 . + \ The value 3 gives a ratio of 1.44, and value 4 gives a ratio of 1.56 . We use 3. + h# 3e00 h# 40 codec! \ Speaker Amp Ratio GAIN is 1.44x, no HPFs
- h# 8001 h# 34 codec! \ Slave mode, 16 bits, left justified + h# 0000 h# 42 codec! \ Use MCLK, not PLL +\ b# 1110.1100.1001.0000 h# 52 codec! \ Protection on +\ h# 4000 h# 56 codec! \ HP depop by register control
h# 1010 h# 38 codec! \ Divisors; the values in this register don't seem to make much \ difference unless you set the divisors to very high values. - +; +: elided ( -- ) \ The ADC and DAC will be turned on as needed by adc-on and dac-on, after \ the BCLK clock from the SoC is on. If you turn on the ADC when BCLK is \ not clocking, the ADC often doesn't output any data. b# 1001.0000.1110.0000 h# 3a codec! \ All on except ADC and DAC b# 1111.1100.0011.1100 h# 3b codec! \ All on except PLL b# 1111.1100.0000.0000 h# 3e codec! \ AXI and MONO IN off - -\ h# 8c00 h# 40 codec! \ Speaker Amp Auto Ratio GAIN, use HPFs - h# 4e00 h# 40 codec! \ Speaker Amp Ratio GAIN is 1.44x, no HPFs - h# 0000 h# 42 codec! \ Use MCLK, not PLL -\ b# 1110.1100.1001.0000 h# 52 codec! \ Protection on - h# 8000 h# 56 codec! \ HP depop by register control -; -: codec-off ( -- ) - 0 h# 3a codec! \ All off - 0 h# 3b codec! \ All off - 0 h# 3c codec! \ All off - 0 h# 3e codec! \ All off ; : mic-bias-off ( -- ) h# 000c h# 3b codec-clr ; : mic-bias-on ( -- ) h# 000c h# 3b codec-set ; @@ -46,60 +61,204 @@ : mic2-high-bias ( -- ) h# 08 h# 22 codec-clr mic-bias-on ; \ 0.90*AVDD, e.g. 3V with AVDD=3.3V : mic2-low-bias ( -- ) h# 08 h# 22 codec-set mic-bias-on ; \ 0.75*AVDD, e.g. 2.5V with AVDD=3.3V
+: depop! ( value -- ) h# 54 codec! ; +: pwr3a! ( value -- ) h# 3a codec! ; +: pwr3b! ( value -- ) h# 3b codec! ; +: pwr3c! ( value -- ) h# 3c codec! ; +: pwr3e! ( value -- ) h# 3e codec! ; +: depop( ( current -- ) + h# 0000 h# 5c codec! \ Disable ZCD + h# 0710 h# 4a codec! \ Bit 11=0 disables HP zero-cross detection. 71 is reserved bits. + d# 10 ms + ( current ) h# 56 codec-i! \ Index 56 - depop current control +; +: )depop ( -- ) + h# 04c0 h# 5c codec! \ Power on ZCD, enable ZCD for SPOL/R + h# 0f10 h# 4a codec! \ Bit 11 enables HP zero-cross detection. 71 is reserved bits +; + +0 value headphones-on? +0 value speakers-on? + +: mute-speakers ( -- ) h# 8080 2 codec-set ; +: unmute-speakers ( -- ) h# 8080 2 codec-clr ; + \ The range is from -46.5 db to +12 dB -: gain>lr-12 ( db -- true | regval false ) +: gain>lr-12 ( db -- regval on? ) d# 12 min ( db' ) 2* 3 / ( steps ) \ Converts -46.5 .. 12 db to -31 .. 8 steps dup d# -31 < if ( steps ) - drop true + drop h# 2727 ( regval ) + false ( regval on? ) else ( steps ) 8 swap - ( -steps ) 0 max ( clipped-steps ) dup 8 lshift or ( regval ) - false + true ( regval on? ) then ; +: set-speaker-volume ( n -- ) + gain>lr-12 to speakers-on? h# bfbf 2 codec-field +; + +: mute-headphones ( -- ) h# 8080 4 codec-set ; +: unmute-headphones ( -- ) h# 8080 4 codec-clr ; + \ The range is from -46.5 db to 0 dB -: gain>lr ( db -- true | regval false ) +: gain>lr ( db -- regval on? ) 0 min ( db' ) 2* 3 / ( steps ) \ Converts -46.5 .. 12 db to -31 .. 8 steps dup d# -31 < if ( steps ) - drop true + drop h# 1f1f ( regval ) + false ( regval on? ) else ( steps ) 0 swap - ( -steps ) 0 max ( clipped-steps ) dup 8 lshift or ( regval ) - false + true ( regval on? ) then ; - -\ This sets up a simple routing from the DAC to the headphone and speaker outputs -: output-config ( -- ) - h# df00 h# 1a codec! \ DACL -> OUTMIXL - h# df00 h# 1c codec! \ DACR -> OUTMIXR - h# 4040 h# 04 codec-set \ OUTMIXLR -> HPOVOLLR - h# d0d0 h# 28 codec! \ DACLR -> SPKMIXLR - h# 4040 h# 02 codec-set \ SPKMIXLR -> SPKVOLLR - h# 9000 h# 2a codec! \ SPKVOLL -> SPOLMIX, SPKVOLR -> SPORMIX - h# 0000 h# 2c codec! \ SPOxMIX -> SPKRMUX, HPOVOL -> HPMUX +: set-headphone-volume ( n -- ) + gain>lr to headphones-on? h# 9f9f 4 codec-field ;
-: mute-speakers ( -- ) h# 8080 2 codec-set ; -: set-speaker-volume ( n -- ) \ DONE - gain>lr-12 if h# 8080 then h# bfbf 2 codec-field +: codec-off ( -- ) + mute-speakers + mute-headphones + 0 h# 3a codec! \ All off + 0 h# 3b codec! \ All off + 0 h# 3c codec! \ All off + 0 h# 3e codec! \ All off ; -: mute-headphones ( -- ) h# 8080 4 codec-set ; -: set-headphone-volume ( n -- ) \ DONE - gain>lr if h# 8080 then h# 9f9f 4 codec-field + +: hp-powerup-depop ( -- ) + \ powerup depop + h# 303e depop( \ App note says 303f, engineer says to use 303e + h# e01c pwr3c! \ 1c powers on charge pump, HP Amp L/R + h# 8080 depop! \ Power on HP Soft Generator, (datasheet says 80 bit is "reserved-0", engineer says datasheet is wrong) + d# 100 ms + h# e01e pwr3c! \ Now put HP output in normal, not depop, mode + )depop + + \ unmute depop + h# 302f depop( \ This is the only case where 10 ms delay is actually needed + h# c003 depop! \ Power on HP Soft Generator, HP Softgen Trigger, ena HPOL/R depop + unmute-headphones + d# 160 ms + )depop +; +: hp-powerdown-depop ( -- ) + \ mute depop + h# 302f depop( + h# c003 depop! \ Power on HP Soft Generator, HP Softgen Trigger, ena HPOL/R depop + mute-headphones + d# 150 ms + )depop + + \ powerdown depop + h# 303f depop( + h# c030 depop! \ ..30 enables HPOL/R startup, disables HPOL/R depop + d# 75 ms + h# 8030 depop! \ !4000 powers down HP softgen trigger + h# e01c pwr3c! \ !2 puts HP output in depop mode + h# 80b0 depop! + d# 80 ms + h# 8000 depop! \ !30 disables HPOL/R startup + h# e000 pwr3c! \ !1c powers off charge pump, HP Amp L/R + )depop +; + +: open-common ( -- ) + h# 8080 h# 3a codec-set \ Power on I2S, DAC ref (which is also used for ADC according to the engineer) +; +: close-common ( -- ) + h# 8080 h# 3a codec-clr \ Power off I2S, DAC ref +\ h# 0000 pwr3b! \ Power off PLL +; +: open-out-specific ( -- ) + h# 0060 h# 3a codec-set \ Power on DAC to mixer + speakers-on? if h# 1000 h# 3a codec-set then \ Power on ClassD amp + speakers-on? if h# c000 h# 3e codec-set then \ Power on SPKL/RVOL + headphones-on? if h# 0c00 h# 3e codec-set then \ Power on HPOVOLL/R +\ h# 0300 h# 3a codec-set \ Power on DACL/R - defer until dac-on is called by start-audio-out or out-in + h# c000 pwr3b! \ Power on OUTMIXL/R + speakers-on? if h# 3000 h# 3b codec-set then \ Power on SPKMIXL/R + + speakers-on? if unmute-speakers then + headphones-on? if hp-powerup-depop then +; + +: open-out ( -- ) + open-common + open-out-specific +; + +: close-out-specific ( -- ) + speakers-on? if mute-speakers then + headphones-on? if hp-powerdown-depop then + + h# f000 h# 3b codec-clr \ Power off OUTMIXL/R, SPKMIXL/R + h# 0300 h# 3a codec-clr \ Power off DACs + h# cc00 h# 3e codec-clr \ Power off SPKL/RVOL, HPOVOLL/R + h# 1060 h# 3a codec-clr \ Power off ClassD amp, DAC to mixer +; +: close-out ( -- ) + close-out-specific + close-common +; + +: adc-source ( value -- ) h# c000 h# 4a codec-field ; +: adc-stereo ( -- ) 0 adc-source ; \ L->L, R->R +: adc-mono-left ( -- ) h# 4000 adc-source ; \ L->L+R +: adc-mono-right ( -- ) h# 8000 adc-source ; \ R->L+R +: adc-stereo-reversed ( -- ) h# c000 adc-source ; \ L->R, R->L (channels swapped) + +: open-in-specific ( -- ) + h# 000c h# 3b codec-set \ Power on MIC1/2 bias + adc-stereo + h# 0c00 h# 3b codec-set \ Power on RECMIXLR + h# 0030 h# 3b codec-set \ Power on MIC1/2 boost gain +\ h# 0c00 h# 3a codec-set \ Power on ADCL/R - defer until adc-on is called by audio-in or out-in +; +: open-in ( -- ) +\ h# 46f0 h# 44 codec! \ pll: 256000 -> 2048000 ??? why is this different from playback? - 8khz record? + open-common + open-in-specific +; + +: close-in-specific ( -- ) + h# 0c00 h# 3a codec-clr \ Power off ADCL/R + h# 0030 h# 3b codec-clr \ Power off MIC1/2 boost gain + h# 0c0c h# 3b codec-clr \ Power off RECMIXLR, MIC1/2 bias +; +: close-in ( -- ) + close-in-specific + close-common +; + +: open-out-in ( -- ) + open-common + open-out-specific + open-in-specific +; + +: close-out-in ( -- ) + close-in-specific + close-out-specific + close-common ;
false value force-speakers? : set-volume ( n -- ) + mute-speakers mute-headphones \ Start with both muted, will be unmuted later headphones-inserted? ( force-speakers? 0= and ) if - set-headphone-volume mute-speakers + d# 30 - set-headphone-volume + true false else - set-speaker-volume mute-headphones + set-speaker-volume + false true then + to speakers-on? to headphones-on? ; d# 0 constant default-adc-gain \ 0 dB - range is -96.625 to +28.5 d# 0 constant default-dac-gain \ 0 dB - range is -96.625 to +28.5 @@ -108,9 +267,9 @@ d# -10 constant default-headphone-volume \ -10 dB - range is -46.5 to 0
: speakers-on ( -- ) default-speaker-volume set-speaker-volume ; -: speakers-off ( -- ) d# -100 set-speaker-volume ; +: speakers-off ( -- ) d# -100 set-speaker-volume ; : headphones-on ( -- ) default-headphone-volume set-headphone-volume ; -: headphones-off ( -- ) d# -100 set-headphone-volume ; +: headphones-off ( -- ) d# -100 set-headphone-volume ;
: adc-mute-all ( -- ) h# f0f0 h# 14 codec! ; : adc-mute-mic ( -- ) h# 4040 h# 14 codec-set ; @@ -126,28 +285,40 @@ : outmix-mute-recmix ( -- ) h# 8000 dup h# 1a codec-set h# 1c codec-set ; : outmix-unmute-recmix ( -- ) h# 8000 dup h# 1a codec-clr h# 1c codec-clr ;
-: gain>lr-3/8 ( -- lrgain boost ) - d# 28 min - dup 0>= if ( n ) +: attenuation-3/8 ( db -- lrgain boost ) + dup d# -96 <= if ( db ) + drop ( ) + h# ffff h# 8080 ( lrgain boost-muted ) + else ( db ) + negate 8 3 */ ( steps ) + dup bwjoin ( lrgain ) + 0 ( lrgain boost ) + then ( lrgain boost ) +; +: gain>lr-3/8 ( db -- lrgain boost ) + d# 28 min ( db ) + dup 0>= if ( db ) 8 3 */ ( boost ) \ Convert to .375 dB increments 0 swap ( lrgain boost ) - else ( n ) - dup d# -96 <= if ( n ) - drop ( ) - h# ffff h# 8080 ( lrgain boost ) - else ( n ) - negate 8 3 */ ( steps ) - dup bwjoin ( lrgain ) - 0 ( lrgain boost ) - then ( lrgain boost ) - then ( lrgain boost ) + else ( db ) + attenuation-3/8 ( lrgain boost ) + then ( lrgain boost ) ; -: set-dac-gain ( n -- ) +: set-dac-gain ( db -- ) dup d# -96 < if outmix-mute-dac else outmix-unmute-dac then gain>lr-3/8 h# 0c codec! h# 10 codec! ; -: set-adc-gain ( n -- ) - gain>lr-3/8 h# 12 codec! h# 16 codec! +: gain>lr-3/2+3/8 ( db -- lrgain boost ) + d# 28 min ( db ) + dup 0>= if ( db ) + 2 3 */ ( boost ) \ Convert to 1.5 dB increments + 0 swap ( lrgain boost ) + else ( db ) + attenuation-3/8 ( lrgain boost ) + then ( lrgain boost ) +; +: set-adc-gain ( db -- ) + gain>lr-3/2+3/8 h# 12 codec! h# 16 codec! ; : mic1-balanced ( -- ) h# 8000 h# 8000 h# 0e codec-field ; : mic1-single-ended ( -- ) 0 h# 8000 h# 0e codec-field ; @@ -178,7 +349,6 @@ : mic+0db ( -- ) 0 set-mic-gain ; : mic+20db ( -- ) d# 20 set-mic-gain ; : set-default-gains ( -- ) - output-config headphones-inserted? ( force-speakers? 0= and ) if headphones-on speakers-off
Modified: cpu/arm/olpc/1.75/sound.fth ============================================================================== --- cpu/arm/olpc/1.75/sound.fth Fri Sep 16 01:34:00 2011 (r2511) +++ cpu/arm/olpc/1.75/sound.fth Fri Sep 16 02:40:48 2011 (r2512) @@ -112,8 +112,7 @@ 0 d# 18 lshift or \ External clock - slave configuration (Rx is master) 0 d# 17 lshift or \ Sample on rising edge of clock
-\ Empirically, this needs to be backwards from what we think it should be - 0 d# 16 lshift or \ Active high frame sync (should be active low, but that gives backwards results) + 1 d# 16 lshift or \ Active low frame sync (I2S standard)
d# 31 d# 4 lshift or \ Frame sync period 1 d# 2 lshift or \ Flush the FIFO @@ -259,11 +258,6 @@ : dma-alloc ( len -- adr ) " dma-alloc" $call-parent ; : dma-free ( adr len -- ) " dma-free" $call-parent ;
-: open-in ( -- ) ; -: close-in ( -- ) ; -: open-out ( -- ) ; -: close-out ( -- ) ; - : wait-out ( -- ) buf-timeout 0 do 1 ms h# a0 adma@ 1 and ?leave @@ -292,6 +286,7 @@ stop-out-ring uninstall-playback-alarm false to playing? + close-out ;
: out-ready? ( -- flag ) @@ -387,7 +382,7 @@ disable-sspa-rx ( actual ) reset-rx ( actual ) ; -: read ( adr len -- actual ) open-in audio-in ; +: read ( adr len -- actual ) open-in audio-in close-in ;
0 value mono? 0 value in-adr0 @@ -398,13 +393,15 @@ loop ; : out-in ( out-adr out-len in-adr in-len -- ) + open-out-in + to in-len0 to in-adr0 ( out-adr out-len ) to out-len to out-adr ( )
in-adr0 to in-adr ( ) in-len0 mono? if 2* then to in-len
- audio-clock-on ( ) \ This will mess up any frequency settings + ( audio-clock-on ) ( ) \ This will mess up any frequency settings
setup-sspa-tx ( ) setup-sspa-rx ( ) @@ -421,8 +418,7 @@ master-rx ( ) \ Now the clock is on slave-tx ( )
- adc-on ( ) - dac-on ( ) + adc+dac-on ( )
true to playing?
@@ -439,6 +435,8 @@ dac-off adc-off ( )
mono? if collapse-in then ( ) + + close-out-in ;
0 [if] \ Interactive test words for out-in @@ -527,7 +525,7 @@ 2 value #channels
\ Unless you do the audio-clock-on, the L/R phase is often wrong -: input-test-settings ( -- ) audio-clock-on ; +: input-test-settings ( -- ) ( audio-clock-on ) ; : output-test-settings ( -- ) ;
d# -1 constant case-test-volume
Modified: dev/hdaudio/noiseburst.fth ============================================================================== --- dev/hdaudio/noiseburst.fth Fri Sep 16 01:34:00 2011 (r2511) +++ dev/hdaudio/noiseburst.fth Fri Sep 16 02:40:48 2011 (r2512) @@ -562,8 +562,40 @@ defer analyze-right defer fix-dc
+[ifdef] notdef +fload ${BP}/forth/lib/isin.fth +fload ${BP}/forth/lib/tones.fth + +\ This version puts the tone first into the left channel for +\ half the time, then into the right channel for the remainder +: make-2tones ( adr len freq sample-rate -- ) + 2dup set-freq ( adr len freq sample-rate ) + + 3 pick make-cycle drop ( adr len freq sample-rate ) + + swap 2* swap set-freq ( adr len ) + over wa1+ make-cycle drop ( adr len ) + + + \ Copy the wave template into the remainder of the buffer + over /cycle + over /cycle - bounds ?do ( adr len ) + over i /cycle move ( adr len ) + /cycle +loop ( adr len ) + 2drop +; +1 value debug-analyzer? +[then] + : prepare-signal ( -- out-adr, len in-adr,len ) +[ifdef] debug-analyzer? + debug-analyzer? if + pb /pb d# 1000 d# 48000 make-2tones + else + pb /pb bounds do random-long i l! /l +loop + then +[else] pb /pb bounds do random-long i l! /l +loop +[then] pb /pb -stereo-wmean pb wa1+ /pb -stereo-wmean pb /pb lose-6db
Modified: dev/hdaudio/test.fth ============================================================================== --- dev/hdaudio/test.fth Fri Sep 16 01:34:00 2011 (r2511) +++ dev/hdaudio/test.fth Fri Sep 16 02:40:48 2011 (r2512) @@ -102,7 +102,7 @@ false value plot? \ Set to true to plot the impulse response, for debugging : plot-impulse ( adr -- ) d# 600 ( adr #samples ) - " 0 set-fg h# ffff set-bg single-drawing clear-drawing wave" evaluate + " 0 set-fg h# ffffffff set-bg single-drawing clear-drawing wave" evaluate key ascii d = if debug-me then ;