aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLubomir Rintel <lkundrak@v3.sk>2020-08-14 01:37:38 +0200
committerLubomir Rintel <lkundrak@v3.sk>2020-08-14 01:55:44 +0200
commit5735582eb2d85fdc41205b376c7296a23e95ef9f (patch)
tree3f6453f297acf78e7f3235400c395de2f5847c78
parentfb83c095500924dd073fd8d7897856f0fefaa45e (diff)
downloadopenfirmware-lr/ariel.tar.gz
olpc/sound: split off the OLPC specific partslr/ariel
-rw-r--r--cpu/arm/mmp2/sound.fth1039
-rw-r--r--cpu/arm/olpc/alc5624.fth29
-rw-r--r--cpu/arm/olpc/alc5631.fth33
-rw-r--r--cpu/arm/olpc/sound.fth1030
4 files changed, 1110 insertions, 1021 deletions
diff --git a/cpu/arm/mmp2/sound.fth b/cpu/arm/mmp2/sound.fth
new file mode 100644
index 00000000..5da316e6
--- /dev/null
+++ b/cpu/arm/mmp2/sound.fth
@@ -0,0 +1,1039 @@
+\ "mav" stands for M(DMA), A(DMA), V(DMA), distinct from
+\ the 16 "peripheral" PDMA channels.
+\ The number space for mmp-mav-dma-channels is as follows:
+\ 0: MDMA0
+\ 1: MDMA1
+\ 2: ADMA1_CH0 (out)
+\ 3: ADMA1_CH1 (in)
+\ 4: ADMA2_CH0 (out)
+\ 5: ADMA2_CH1 (in)
+\ 6: VDMA1_CH0
+\ 7: VDMA1_CH1
+\ That's consistent with the enumeration mmp_tdma_type in
+\ Linux:arch/arm/mach-mmp/include/mach/mmp_dma.h
+\ and also reflects the bit numbering (+16) in the various
+\ DMA IRQ status and mask registers, e.g. ICU_DMA_IRQ1_STATUS
+
+dev /
+1 [if]
+new-device
+ " adma" device-name
+ h# 900 +audio h# 100 reg
+ 5 encode-int 4 encode-int encode+ " mmp-mav-dma-channels" property
+ " marvell,mmp-audio-dma" +compatible
+ " marvell,adma-1.0" +compatible
+ 1 " #dma-cells" integer-property
+
+[ifdef] mmp3
+ " /interrupt-controller@128" encode-phandle " interrupt-parent" property
+ d# 20 encode-int d# 21 encode-int encode+ " interrupts" property
+[else]
+ d# 48 " interrupts" integer-property
+[then]
+
+ " disabled" " status" string-property
+ current-device ( adma1-ph )
+finish-device
+
+new-device
+ ( adma1-ph ) encode-int " adma-node" property
+ " pcm" device-name
+ 1 0 reg
+
+ \ This binds to the platform driver, a single point that collects
+ \ the Audio DMA resources
+ " marvell,mmp-pcm-audio" +compatible \ snd_soc_dai_link.cpu_dai_of_node
+ " disabled" " status" string-property
+
+finish-device
+[then]
+
+new-device
+ " asram" device-name
+ audio-sram-pa /audio-sram reg
+
+ " marvell,mmp-asram" +compatible
+ " mmio-sram" +compatible
+ 1 " #address-cells" integer-property
+ 1 " #size-cells" integer-property
+
+ 0 encode-int
+ audio-sram-pa encode-int encode+
+ /audio-sram encode-int encode+
+ " ranges" property
+finish-device
+
+new-device
+ " adma" device-name
+ h# 800 +audio h# 100 reg
+ 3 encode-int 2 encode-int encode+ " mmp-mav-dma-channels" property
+ " marvell,mmp-audio-dma" +compatible
+ " marvell,adma-1.0" +compatible
+ 1 " #dma-cells" integer-property
+
+[ifdef] mmp3
+ " /interrupt-controller@128" encode-phandle " interrupt-parent" property
+ d# 18 encode-int d# 19 encode-int encode+ " interrupts" property
+[else]
+ d# 48 " interrupts" integer-property
+[then]
+
+ " /asram" encode-phandle " asram" property
+ " /asram" encode-phandle " iram" property
+ current-device ( adma0-ph )
+finish-device
+
+new-device
+ ( adma0-ph ) encode-int " adma-node" property
+ " pcm" device-name
+ 0 0 reg
+
+ \ This binds to the platform driver, a single point that collects
+ \ the Audio DMA resources
+ " marvell,mmp-pcm-audio" +compatible \ snd_soc_dai_link.cpu_dai_of_node
+
+[ifdef] mmp3
+ \ Our asram node (below) declares that /audio-sram bytes of SRAM
+ \ are assigned to the audio function. We divide that here, roughly
+ \ half to playback and half to recording.
+
+ \ Even though we choose big buffers, we do leave a little bit of
+ \ free space for the DMA engine which also needs to use a bit of
+ \ the SRAM area for DMA descriptors. Therefore we choose 62kb for
+ \ each buffer, leaving 4kb available for DMA descriptors.
+
+ \ For the max period size, we don't have any justification other
+ \ than 2048 is the value we've been using all along.
+
+ /audio-sram-pcm encode-int
+ /audio-sram-mps encode-int encode+
+ /audio-sram-pcm encode-int encode+
+ /audio-sram-mps encode-int encode+
+ " marvell,buffer-sizes" property
+[then]
+finish-device
+
+new-device
+ " sspa" name
+ h# d00 +audio encode-int h# 30 encode-int encode+
+ h# d80 +audio encode-int encode+ h# 30 encode-int encode+
+ " reg" property
+
+ " marvell,mmp-sspa-dai" +compatible
+[ifdef] mmp2 " marvell,mmp2-sspa-dai" +compatible [then]
+[ifdef] mmp3 " marvell,mmp3-sspa-dai" +compatible [then]
+
+ " unused" " status" string-property
+
+ d# 3 " interrupts" integer-property
+ 0 0 encode-bytes
+ " /clocks" encode-phandle encode+ mmp2-audio-clk# encode-int encode+
+ " /audio-clocks" encode-phandle encode+ mmp2-audio-sspa1-clk# encode-int encode+
+ " clocks" property
+ 0 0 encode-bytes
+ " audio" encode-string encode+
+ " bitclk" encode-string encode+
+ " clock-names" property
+ " /clocks" encode-phandle mmp2-audio-pd# encode-int encode+
+ " power-domains" property
+ 0 " #sound-dai-cells" integer-property
+finish-device
+
+new-device
+
+" audio" name
+h# c00 +audio encode-int h# 30 encode-int encode+
+ h# c80 +audio encode-int encode+ h# 30 encode-int encode+
+ " reg" property
+
+" marvell,mmp-sspa-dai" +compatible
+[ifdef] mmp2 " marvell,mmp2-sspa-dai" +compatible [then]
+[ifdef] mmp3 " marvell,mmp3-sspa-dai" +compatible [then]
+" marvell,mmp-sspa" +compatible
+
+d# 2 " interrupts" integer-property
+
+0 0 encode-bytes
+ " /clocks" encode-phandle encode+ mmp2-audio-clk# encode-int encode+
+ " /audio-clocks" encode-phandle encode+ mmp2-audio-sspa0-clk# encode-int encode+
+ " clocks" property
+0 0 encode-bytes
+ " audio" encode-string encode+
+ " bitclk" encode-string encode+
+ " clock-names" property
+" /clocks" encode-phandle mmp2-audio-pd# encode-int encode+
+ " power-domains" property
+0 " #sound-dai-cells" integer-property
+
+0 0 encode-bytes
+ " /adma" encode-phandle encode+ 0 encode-int encode+
+ " /adma" encode-phandle encode+ 1 encode-int encode+
+" dmas" property
+" tx" encode-string " rx" encode-string encode+ " dma-names" property
+
+new-device
+ " port" device-name
+ new-device
+ " endpoint" device-name
+ " i2s" " dai-format" string-property
+ 0 0 " bitclock-master" property
+ 0 0 " frame-master" property
+ finish-device
+finish-device
+
+0 value sspa-base \ E.g. h# 2a.0c00 +io
+0 value adma-base \ E.g. h# 2a.0800 +io
+: sspa! ( n offset -- ) sspa-base + rl! ; \ Write a register in SSPA1
+: sspa@ ( offset -- n ) sspa-base + rl@ ; \ Read a register in SSPA1
+: adma! ( n offset -- ) adma-base + rl! ;
+: adma@ ( offset -- n ) adma-base + rl@ ;
+
+: audio-clock-off ( -- )
+ 0 h# 38 sspa!
+ " /clocks" " audio-island-off" execute-device-method drop
+;
+: start-audio-pll ( -- error? )
+ \ For VCXO=26 MHz, OCLK=12.2880 MHz
+ \ MMP2: DIV_OCLK_MODULO=010 FRACT=00da1 ENA_DITHER=1 ICP=0 DIV_FBCCLK=01 DIV_MCLK=0 PU=1
+ \ MMP2: DIV_OCLK_MODULO=010 FRACT=00da1 ENA_DITHER=1 ICP=0 DIV_FBCCLK=01 DIV_MCLK=011 PU=1
+ [ifdef] mmp3 h# a00d.a18d [else] h# 200d.a189 [then] h# 38 sspa!
+ h# 0000.0801 h# 3c sspa! \ CLK_SEL=1 (AudioPLL) DIV_OCLK_PATTERN=01
+ d# 50 0 do
+ h# 3c sspa@ h# 10000 and if
+ false unloop exit
+ then
+ d# 10 us
+ loop
+ ." Audio PLL did not start" cr
+ true
+;
+
+: dly d# 10 us ;
+
+true value use-audio-pll?
+: audio-clock-on ( -- error? )
+ " /clocks" " audio-island-on" execute-device-method drop
+
+ use-audio-pll? if
+ start-audio-pll if true exit then
+
+ \ Bits 14:9 set the divisor from SYSCLK to BITCLK. The setting below
+ \ is d# 8, which gives BITCLK = 1.536 MHz. That's 32x 48000, just enough
+ \ for two (stereo) 16-bit samples.
+ \ The 80 bit is 0, choosing the AudioPLL instead of the I2SCLK
+ h# 1103 h# 34 sspa! \ SSPA_AUD_CTRL0
+ else
+ \ This section of the code uses I2SCLK instead of the Audio PLL. Marvell
+ \ says that I2SCLK is prone to jitter so the Audio PLL is preferred.
+
+ \ * 10 / 27 gives about 147.456
+ \ The M/N divisor gets 199.33 MHz (Figure 283 - clock tree - in Datasheet)
+ \ But the M/N divisors always have an implicit /2 (section 7.3.7 in datasheet),
+ \ so the input frequency is 99.67 with respect to NOM (sic) and DENOM.
+ \ we want 12.288 MHz SYSCLK. 99.67 * 9 / 73 = 12.2876 so 50 ppm error.
+ d# 9 d# 15 lshift d# 73 or h# d000.0000 or h# 40 mpmu!
+
+ \ The manual says that bit 5 enables I2SCLK to SSPA1, but empirically, bit 21 seems to do it
+ \ That is true on both MMP2 and MMP3
+ h# 20.0000 h# 1024 +mpmu io-set \ Enable 12S clock out to SSPA1
+
+ \ h# 10800 h# 38 sspa! \ Appears unnecessary; not sure what it does
+
+ \ Bits 14:9 set the divisor from SYSCLK to BITCLK. The setting below
+ \ is d# 8, which gives BITCLK = 1.536 MHz. That's 32x 48000, just enough
+ \ for two (stereo) 16-bit samples.
+ \ The 80 bit is 1, choosing the I2SCLK instead of the AudioPLL
+ h# 1183 h# 34 sspa! \ SSPA_AUD_CTRL0
+ then
+ false
+;
+\ This is a grotesque workaround for a hardware problem. The audio
+\ subsystem (SSPA + ADMA) works reasonably reliably right after the
+\ audio island is powered on, but subsequent tries tend to get
+\ confused about which channel is which, and possibly about the
+\ initial SSPA FIFO contents. Resetting between test phases makes
+\ the test work more reliably. Attempts to get help from the vendor,
+\ over a long period of time, were unsuccessful.
+: reset-audio ( -- ) audio-clock-off d# 50 ms audio-clock-on drop ;
+
+: reset-rx ( -- ) h# 8000.0002 h# 0c sspa! ;
+
+: active-low-rx-fs ( -- )
+ h# 0c sspa@ h# 8001.0000 or h# 0c sspa!
+;
+: active-high-rx-fs ( -- )
+ h# 0c sspa@ h# 10000 invert and h# 8000.0000 or h# 0c sspa!
+;
+: setup-sspa-rx ( -- )
+ reset-rx
+
+ h# 8000.0000 \ Dual phase (stereo)
+ 0 d# 24 lshift or \ 1 word in phase 2
+ 2 d# 21 lshift or \ 16 bit word in phase 2
+ 0 d# 19 lshift or \ 0 bit delay
+ 2 d# 16 lshift or \ 16-bit audio sample in phase 2
+ 0 d# 8 lshift or \ 1 word in phase 1
+ 2 d# 5 lshift or \ 16 bit word in phase 1
+ 0 d# 3 lshift or \ Left justified data
+ 2 d# 0 lshift or \ 16-bit audio sample in phase 1
+ h# 08 sspa! \ Receive control register
+
+ h# 8000.0000 \ Enable writes
+ d# 15 d# 20 lshift or \ Frame sync width
+\ We choose the master/slave configuration later, in enable-sspa-rx
+ 0 d# 18 lshift or \ Internal clock - master configuration
+ 0 d# 17 lshift or \ Sample on rising edge of clock
+ 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
+ h# 0c sspa!
+
+ h# 10 h# 10 sspa! \ Rx FIFO limit
+;
+: master-rx ( -- ) h# 0c sspa@ h# 8004.0001 or h# 0c sspa! ; \ Master, on
+: slave-rx ( -- ) h# 0c sspa@ h# 8000.0001 or h# 0c sspa! ; \ Slave, on
+: flush-rx ( -- ) h# 0c sspa@ h# 8000.0004 or h# 0c sspa! ; \ Hit the flush bit
+: disable-sspa-rx ( -- ) h# 0c sspa@ h# 8000.0004 or h# 4.0001 invert and h# 0c sspa! ;
+
+: reset-tx ( -- ) h# 8000.0002 h# 8c sspa! ;
+
+: active-low-tx-fs ( -- )
+ h# 8c sspa@ h# 8001.0000 or h# 8c sspa!
+;
+: active-high-tx-fs ( -- )
+ h# 8c sspa@ h# 10000 and h# 8000.0000 or h# 8c sspa!
+;
+: setup-sspa-tx ( -- )
+ reset-tx
+
+ h# 8000.0000 \ Dual phase (stereo)
+ 0 d# 24 lshift or \ 1 word in phase 2
+ 2 d# 21 lshift or \ 16 bit word in phase 2
+ 0 d# 19 lshift or \ 0 bit delay
+ 2 d# 16 lshift or \ 16-bit audio sample in phase 2
+ 1 d# 15 lshift or \ Transmit last sample when FIFO empty
+ 0 d# 8 lshift or \ 1 word in phase 1
+ 2 d# 5 lshift or \ 16 bit word in phase 1
+ 0 d# 3 lshift or \ Left justified data
+ 2 d# 0 lshift or \ 16-bit audio sample in phase 1
+ h# 88 sspa! \ Transmit control register
+
+ h# 8000.0000 \ Enable writes
+ d# 15 d# 20 lshift or \ Frame sync width
+\ We choose the master/slave configuration later, in master-tx
+ 0 d# 18 lshift or \ External clock - slave configuration (Rx is master)
+ 0 d# 17 lshift or \ Sample on rising edge of clock
+
+ 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
+ h# 8c sspa!
+
+ h# 10 h# 90 sspa! \ Tx FIFO limit
+;
+: master-tx ( -- ) h# 8c sspa@ h# 8004.0001 or h# 8c sspa! ; \ Master, on
+: slave-tx ( -- ) h# 8c sspa@ h# 8000.0001 or h# 8c sspa! ; \ Slave, on
+: flush-tx ( -- ) h# 8c sspa@ h# 8000.0004 or h# 8c sspa! ; \ Hit the flush bit
+: disable-sspa-tx ( -- ) h# 8c sspa@ h# 8000.0004 or h# 4.0001 invert and h# 8c sspa! ;
+
+h# fc0 constant /audio-buf
+audio-sram-va constant out-bufs
+audio-sram-va h# 1f80 + constant out-desc
+audio-sram-va h# 2000 + constant in-bufs
+audio-sram-va h# 3f80 + constant in-desc
+
+\ Descriptor format:
+\ Byte count
+\ Source
+\ Destination
+\ link
+
+0 value my-out-desc \ out-desc or out-desc h# 20 +
+0 value out-adr
+0 value out-len
+0 value my-in-desc \ in-desc or in-desc h# 20 +
+0 value in-adr
+0 value in-len
+: set-descriptor ( next dest source length adr -- )
+ >r r@ l! r@ la1+ l! r@ 2 la+ l! r> 3 la+ l!
+;
+: make-out-ring ( -- )
+ out-desc h# 10 + sspa-base h# 80 + out-bufs /audio-buf out-desc set-descriptor
+ out-desc sspa-base h# 80 + out-bufs /audio-buf + /audio-buf out-desc h# 10 + set-descriptor
+ out-desc h# 30 adma! \ Link to first descriptor
+ out-desc to my-out-desc
+;
+
+0 value use-packmod?
+
+: start-out-ring ( -- )
+ 1 h# 80 adma! \ Enable DMA completion interrupts
+ h# 0080.3020 \ 16 bits, fetch next, enable, chain, hold dest, inc src
+ use-packmod? if h# 1.0000 or then
+ h# 40 adma!
+;
+: stop-out-ring ( -- ) h# 100000 h# 40 adma! 0 h# 80 adma! ;
+
+: make-in-ring ( -- )
+ in-desc h# 10 + in-bufs sspa-base /audio-buf in-desc set-descriptor
+ in-desc in-bufs /audio-buf + sspa-base /audio-buf in-desc h# 10 + set-descriptor
+ in-desc h# 34 adma! \ Link to first descriptor
+ in-desc to my-in-desc
+;
+: start-in-ring ( -- )
+ 1 h# 84 adma! \ Enable DMA completion interrupts
+\ h# 0081.3008 h# 44 adma! \ 16 bits, pack, fetch next, enable, chain, inc dest, hold src
+
+ h# 00a0.31c8 \ 16 bits, fetch next, enable, chain, burst32, inc dest, hold src
+ use-packmod? if h# 1.0000 or then
+ h# 44 adma!
+;
+: stop-in-ring ( -- ) h# 100000 h# 44 adma! 0 h# 84 adma! ;
+
+: unpack-move ( src dst packed-len -- )
+ 1 rshift 0 ?do ( src dst )
+ over i wa+ w@ ( src dst sample )
+ over i la+ wa1+ w! ( src dst )
+ loop ( src dst )
+ 2drop ( )
+;
+
+: pack-move ( src dst packed-len -- )
+ 1 rshift 0 ?do ( src dst )
+ over i la+ wa1+ w@ ( src dst sample )
+ over i wa+ w! ( src dst )
+ loop ( src dst )
+ 2drop ( )
+;
+
+: copy-out ( -- )
+ my-out-desc >r ( r: desc )
+ use-packmod? if
+ out-len /audio-buf min ( this-packed-len r: desc )
+ dup r@ l! ( this-packed-len r: desc )
+ out-adr r@ la1+ l@ third move ( this-packed-len r: desc )
+ else
+ out-len /audio-buf 2/ min ( this-packed-len r: desc )
+ dup 2* r@ l! ( this-packed-len r: desc )
+ out-adr r@ la1+ l@ third unpack-move ( this-packed-len r: desc )
+ then
+
+ out-adr over + to out-adr ( this-packed-len r: desc )
+ out-len swap - to out-len ( r: desc )
+ out-len if
+ r> 3 la+ l@ to my-out-desc
+ else
+ 0 r> 3 la+ l! \ When there is no more data, terminate the list
+ then
+;
+
+: copy-in ( -- )
+ use-packmod? if
+ in-len /audio-buf min ( this-packed-len )
+ my-in-desc 2 la+ l@ in-adr third move ( this-packed-len )
+ else
+ in-len /audio-buf 2/ min ( this-packed-len )
+ my-in-desc 2 la+ l@ in-adr third pack-move ( this-packed-len )
+ then
+ in-adr over + to in-adr ( this-packed-len )
+ in-len over - to in-len ( this-packed-len )
+ drop ( )
+ my-in-desc 3 la+ l@ to my-in-desc
+;
+
+\ Reset is unconnected on current boards
+\ : audio-reset ( -- ) audio-reset-gpio# gpio-clr ;
+\ : audio-unreset ( -- ) audio-reset-gpio# gpio-set ;
+0 value codec-ih
+: $call-codec ( ? -- ? ) codec-ih $call-method ;
+
+: codec@ ( reg# -- w ) " codec@" $call-codec ;
+: codec! ( w reg# -- ) " codec!" $call-codec ;
+
+: close-in ( -- ) " close-in" $call-codec ;
+: close-out ( -- ) " close-out" $call-codec ;
+: close-out-in ( -- ) " close-out-in" $call-codec ;
+: codec-clr ( bitmask reg# -- ) " codec-clr" $call-codec ;
+: codec-off ( -- ) " codec-off" $call-codec ;
+: codec-on ( -- ) " codec-on" $call-codec ;
+: default-adc-gain " default-adc-gain" $call-codec ;
+: mic1-high-bias ( -- ) " mic1-high-bias" $call-codec ;
+: mic2-high-bias ( -- ) " mic2-high-bias" $call-codec ;
+: mic-bias? " mic-bias?" $call-codec ;
+: open-in ( -- ) " open-in" $call-codec ;
+: open-out-in ( -- ) " open-out-in" $call-codec ;
+: open-out ( -- ) " open-out" $call-codec ;
+: set-adc-gain ( db -- ) " set-adc-gain" $call-codec ;
+: set-codec-sample-rate ( rate -- ) " set-codec-sample-rate" $call-codec ;
+: set-default-gains ( -- ) " set-default-gains" $call-codec ;
+: set-mic-gain ( db -- ) " set-mic-gain" $call-codec ;
+: set-volume ( n -- ) " set-volume" $call-codec ;
+
+: mic+20db ( -- ) " mic+20db" $call-codec ;
+: mic+0db ( -- ) " mic+0db" $call-codec ;
+
+: force-speakers? " force-speakers?" $call-codec ;
+: speakers-on ( -- ) " speakers-on" $call-codec ;
+: speakers-off ( -- ) " speakers-off" $call-codec ;
+: mic-bias-on ( -- ) " mic-bias-on" $call-codec ;
+: mic-bias-off ( -- ) " mic-bias-off" $call-codec ;
+
+d# 48000 value sample-rate
+
+\ Longest time to wait for a buffer event - a little more
+\ than the time it takes to output /audio-buf samples
+\ at the current sample rate.
+0 value buf-timeout
+
+: set-ctlr-sample-rate ( rate -- )
+ case
+ d# 8000 of d# 48 d# 129 endof
+ d# 16000 of d# 24 d# 65 endof
+ d# 32000 of d# 12 d# 33 endof
+ d# 48000 of d# 8 d# 23 endof
+ ( default ) true abort" Unsupported audio sample rate"
+ endcase ( sspareg34val timeout )
+ to buf-timeout
+ 9 lshift h# 34 sspa@ h# 7e00 invert and or h# 34 sspa!
+;
+
+: dma-alloc ( len -- adr ) " dma-alloc" $call-parent ;
+: dma-free ( adr len -- ) " dma-free" $call-parent ;
+
+: wait-out ( -- )
+ buf-timeout 0 do
+ 1 ms h# a0 adma@ 1 and ?leave
+ loop
+ 0 h# a0 adma!
+;
+
+defer playback-alarm
+0 value alarmed?
+
+: install-playback-alarm ( -- )
+ true to alarmed? ['] playback-alarm d# 2 alarm
+;
+: uninstall-playback-alarm ( -- )
+ alarmed? if
+ false to alarmed?
+ ['] playback-alarm d# 0 alarm
+ then
+;
+
+false value playing?
+
+: stop-out ( -- )
+ disable-sspa-tx
+ reset-tx
+ stop-out-ring
+ uninstall-playback-alarm
+ false to playing?
+ close-out
+;
+
+: out-ready? ( -- flag )
+ h# a0 adma@ 1 and 0<>
+ dup if 0 h# a0 adma! then
+;
+: out-dma-done? ( -- flag ) h# 40 adma@ h# 4000 and 0= ;
+
+: ?end-playing ( -- )
+ out-ready? if
+ out-len if copy-out then
+ out-dma-done? if stop-out then
+ then
+;
+
+: set-out-in-mic ( -- )
+ h# 80 h# 12 codec! \ Mute right channel
+ h# 00 h# 16 codec! \ Full digital gain
+ h# 6688 h# 22 codec! \ No mic boost, low bias
+;
+
+: playback-continue-alarm ( -- )
+ playing? if
+ ?end-playing
+ else
+ \ If playback has already stopped as a result of
+ \ someone else having waited for completion, we
+ \ just uninstall ourself.
+ uninstall-playback-alarm
+ then
+;
+' playback-continue-alarm to playback-alarm
+
+: start-audio-out ( adr len -- )
+ to out-len ( adr )
+ to out-adr ( )
+ setup-sspa-tx ( )
+ make-out-ring
+ copy-out
+ out-len if copy-out then \ Prefill the second buffer
+ start-out-ring
+ master-tx
+ true to playing?
+ install-playback-alarm
+;
+
+: audio-out ( adr len -- actual ) tuck start-audio-out ;
+
+: stop-sound ( -- )
+ lock[
+ playing? if stop-out then
+ ]unlock
+;
+
+0 value time-limit
+: set-time-limit ( ms -- ) get-msecs + to time-limit ;
+: 1sec-time-limit ( -- ) d# 1000 set-time-limit ;
+: ?timeout ( -- )
+ get-msecs time-limit - 0> if
+ ." Audio device timeout!" cr
+ abort
+ then
+;
+: wait-out-done ( -- )
+ d# 20,000 set-time-limit begin ?timeout playing? 0= until
+;
+: write-done ( -- ) wait-out-done stop-out ;
+
+: write ( adr len -- actual ) open-out audio-out ;
+
+: in-ready? ( -- flag )
+ h# a4 adma@ 1 and 0<>
+ dup if 0 h# a4 adma! then
+;
+: wait-in ( -- )
+ buf-timeout 0 do
+ 1 ms in-ready? ?leave
+ loop
+;
+
+: audio-in ( adr len -- actual )
+ tuck to in-len to in-adr ( actual )
+ setup-sspa-rx ( actual )
+ make-in-ring ( actual )
+ start-in-ring ( actual )
+ master-rx ( actual )
+ begin in-len while ( actual )
+ wait-in ( actual )
+ copy-in ( actual )
+ repeat ( actual )
+ disable-sspa-rx ( actual )
+ stop-in-ring ( actual )
+ reset-rx ( actual )
+;
+: read ( adr len -- actual ) open-in audio-in close-in ;
+
+0 value mono?
+: stereo false to mono? ;
+: mono true to mono? ;
+
+: average-channel ( adr -- n )
+ 0 swap /audio-buf bounds do ( accum )
+ i <w@ + ( accum' )
+ /l +loop ( accum )
+ /audio-buf /l / / ( average )
+;
+: average-in ( -- )
+ my-in-desc 2 la+ l@ ( adr )
+ (cr push-decimal ( adr )
+ dup average-channel ( adr average )
+ 6 .r space ( adr )
+ wa1+ average-channel ( average )
+ 6 .r ( )
+ pop-base ( )
+ my-in-desc 3 la+ l@ to my-in-desc
+;
+: audio-watch ( -- )
+ setup-sspa-rx ( )
+ make-in-ring ( )
+ start-in-ring ( )
+ master-rx ( )
+ begin ( )
+ wait-in ( )
+ average-in ( )
+ key? until ( )
+ disable-sspa-rx ( )
+ stop-in-ring ( )
+ reset-rx ( )
+;
+: watch-dc ( bias? -- )
+ to mic-bias?
+ mic-ac/dc-gpio# gpio-set \ DC input mode
+ h# 0400 h# 40 codec-clr
+ open-in
+ stereo 0 set-adc-gain 0 set-mic-gain
+ \ High bias gets us closer to the top of the digital range - but bias can
+ \ be turned off completely with "false to mic-bias?"
+ mic1-high-bias mic2-high-bias
+ audio-watch
+ close-in
+;
+
+0 value in-adr0
+0 value in-len0
+: collapse-in ( -- )
+ in-len0 0 ?do
+ in-adr0 i la+ w@ in-adr0 i wa+ w!
+ loop
+;
+code startit ( sspa-adr -- )
+ set r0,#0x80f101f1
+ set r1,#0x80f501f1
+ str r0,[tos,#0x8c]
+ str r1,[tos,#0x0c]
+ pop tos,sp
+c;
+: startoutin ( -- ) disable-interrupts sspa-base startit enable-interrupts ;
+: xstartoutin ( -- ) slave-tx master-rx ;
+
+: out-in0 ( 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
+
+ \ Resetting the clock at this point seems to prevent intermittent channel
+ \ reversal on reception.
+\ audio-clock-on drop ( ) \ This will mess up any frequency settings
+
+ setup-sspa-tx ( )
+ setup-sspa-rx ( )
+
+ make-in-ring ( )
+ make-out-ring ( )
+ copy-out ( ) \ Prefill the first Tx buffer
+ out-len if copy-out then ( ) \ Prefill the second Tx buffer
+
+ start-in-ring ( )
+ start-out-ring ( )
+
+ xstartoutin
+\ slave-tx ( )
+\ master-rx ( ) \ Now the clock is on
+
+ true to playing?
+
+ begin in-len playing? or while ( )
+ in-ready? if copy-in then ( )
+ playing? if ?end-playing then ( )
+ repeat ( )
+ disable-sspa-rx ( )
+ disable-sspa-tx ( )
+
+ stop-in-ring
+ stop-out-ring
+
+ reset-rx
+ reset-tx
+
+ close-out-in
+ mono? if collapse-in then ( )
+;
+
+: out-in1 ( 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
+
+ \ Resetting the clock at this point seems to prevent intermittent channel
+ \ reversal on reception.
+\ audio-clock-on drop ( ) \ This will mess up any frequency settings
+
+ make-out-ring ( )
+ copy-out ( ) \ Prefill the first Tx buffer
+ out-len if copy-out then ( ) \ Prefill the second Tx buffer
+
+ setup-sspa-rx ( )
+ make-in-ring ( )
+ start-in-ring ( )
+ master-rx ( ) \ Now the clock is on
+
+ start-out-ring ( )
+ setup-sspa-tx ( )
+ slave-tx ( )
+
+ true to playing?
+
+ begin in-len playing? or while ( )
+ in-ready? if copy-in then ( )
+ playing? if ?end-playing then ( )
+ repeat ( )
+ disable-sspa-rx ( )
+ disable-sspa-tx ( )
+
+ stop-in-ring
+ stop-out-ring
+
+ reset-rx
+ reset-tx
+
+ close-out-in
+ mono? if collapse-in then ( )
+;
+
+d# 20 value audio-dly
+: out-in2 ( 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
+
+ \ Resetting the clock at this point seems to prevent intermittent channel
+ \ reversal on reception.
+\ audio-clock-on drop ( ) \ This will mess up any frequency settings
+
+ setup-sspa-tx ( )
+ setup-sspa-rx ( )
+
+ make-in-ring ( )
+ make-out-ring ( )
+ copy-out ( ) \ Prefill the first Tx buffer
+ out-len if copy-out then ( ) \ Prefill the second Tx buffer
+
+ xstartoutin
+
+ audio-dly us
+ flush-rx
+ flush-tx
+ start-in-ring ( )
+ start-out-ring ( )
+
+
+ true to playing?
+
+ begin in-len playing? or while ( )
+ in-ready? if copy-in then ( )
+ playing? if ?end-playing then ( )
+ repeat ( )
+ disable-sspa-rx ( )
+ disable-sspa-tx ( )
+
+ stop-in-ring
+ stop-out-ring
+
+ reset-rx
+ reset-tx
+
+ close-out-in
+ mono? if collapse-in then ( )
+;
+
+defer out-in ' out-in0 to out-in
+
+0 [if]
+working recipe: only one out-in in test-common
+out-in2
+disable-interrupts before audio-clock-on and enable after reset-rx
+dly 73 us
+read and discard rx fifo depth before flush-rx
+
+also works with dly 10 us
+reliably swaps with dly 1 us
+swaps with dly 5
+swap with dly 7
+not swap with dly 8
+
+Hmmm, maybe the basic issue is the double out-in in test-common -
+Try out-in0 using one out-in
+Try out-in2 without read/discard fifo depth using one out-in
+
+Swap alternates every 10 or so us, flipping at about 8 or 9 mod 10
+An extra 2 samples appear ever 10 or so us, at about 1 or 2 mod 10
+
+04 us is stable with swapping
+14 us is stable with no swapping
+
+If you remove flush-rx from fr ( : fr 1c sspa@ foo ! flush-rx ; )
+swapping always happens - 04, 14, 24 us all swap
+ This is because when you flush-rx with fifo depth 2, 6, a, etc,
+ that loses an odd number of channel samples
+[then]
+
+0 [if] \ Interactive test words for out-in
+h# 20000 constant tlen
+: xb load-base 1meg + ;
+: ob load-base ;
+: sb load-base 1meg 2* + ;
+: px xb tlen write drop ;
+: po ob tlen write drop ;
+: ps sb tlen write drop ;
+: shiftit xb 1+ sb tlen move ;
+: oi ob tlen xb tlen out-in ;
+[then]
+
+: wait-sound ( -- )
+ lock[
+ begin playing? while d# 2 ms ?end-playing repeat
+ ]unlock
+;
+
+0 [if]
+\ Notes:
+\ Page 1504 - what does "RTC (and WTC) for sync fifo" mean?
+\ Page 1508 - SSPA_AUD_PLL_CTRL1 bit 17 refers to "zsp_clk_gen" <- undefined term appears nowhere else in either document
+\ Page 1501 - do the Frame-Sync Width and Frame-Sync Active fields matter in slave mode, or are they only relevant in master mode??? If they matter in slave mode, what do they control, considering that the external code is driving FSYNC and thus controls its width.
+\ Page 1506 - For I2S_RXDATA, the connection from the pin driver to RX_DATA_IN(18) is shown going to the (disabled) output driver. I think it should come from the input (left-pointing triangle) instead.
+\ Page 1506 - The "18" and "19" notation is unexplained and unclear. I sort of think that 18 means the Rx direction and 19 the Tx direction. If so, and the diagram is correct, then you cannot drive FSYNC from the Tx direction. If that is the case, it ought to be explained elsewhere too. In particular, if you can't drive FSYNC from Tx, what are the FWID and FPER fields in SSPA_TX_SP_CTRL for?
+\ Page 1506 - The diagram shows the ENB for the I2S_BITCLK driver coming from M/S_19 in SSPA. But the Master/Slave bits in both SSPA_TX_SP_CTRL and SSPA_RX_SP_CTRL have no effect on whether BITCLK is driven. It seems to be controlled by bit 8 in SSPA_AUD_CTRL0 (which is misnamed as enabling the SYSCLK Divider, not the BITCLK output. Which makes me wonder what enables the I2S_FSYNC signal, which is shown as being enabled along with I2S_BITCLK. But I can't seem to get FSYNC to come out.
+\ What is the relationship between Rx master mode and Tx master mode with regards to whether FSYNC is driven? Empirically, if I turn on and enable the Rx portion, FSYNC comes on, but if I then turn on the Tx portion, FSYNC turns off until I enable the Tx portion. After that, Tx seems to control FSYNC and nothing I do seems to let Rx control it.
+\ Page 1502 - S_RST is listed as W, but empirically it is readable. When you write 1 to it, the 1 sticks and you have to write 0 again. It's unclear which of the registers it really resets. It doesn't reset the register it is in.
+\ Page 1498 - The data transmit register is listed as RO. How can a transmit register be RO????
+[then]
+
+: set-sample-rate ( rate -- )
+ dup to sample-rate
+ dup set-ctlr-sample-rate
+ set-codec-sample-rate
+;
+: set-get-sample-rate ( rate -- actual-rate )
+ drop d# 48000 ( actual-rate )
+ dup set-sample-rate ( actual-rate )
+;
+
+\ This is called from "record" in "mic-test" in "selftest"
+: set-record-gain ( db -- )
+ \ translate value from ac97 selftest code into our default value
+ dup h# 808 = if ( db )
+ drop default-adc-gain ( db' )
+ d# 40 set-mic-gain ( db )
+ then ( db )
+ set-adc-gain
+;
+
+: init-codec ( -- )
+ codec-on
+ set-default-gains
+ d# 48000 set-sample-rate
+;
+: (close)
+ audio-clock-off
+ adma-base h# 100 " map-out" $call-parent
+ sspa-base h# 100 " map-out" $call-parent
+ 0 to adma-base 0 to sspa-base
+;
+
+0 value open-count
+: open ( -- flag )
+ open-count 0= if
+ my-unit h# 400 - h# 100 " map-in" $call-parent to adma-base
+ my-unit h# 100 " map-in" $call-parent to sspa-base
+ audio-clock-on if (close) false exit then
+ " /audio-codec" open-dev to codec-ih
+ codec-ih 0= if (close) false exit then
+ init-codec
+ then
+ open-count 1+ to open-count
+ true
+;
+: close ( -- )
+ open-count 1 = if
+ uninstall-playback-alarm codec-off
+ codec-ih close-dev
+ (close)
+ then
+ open-count 1- 0 max to open-count
+;
+
+fload ${BP}/forth/lib/isin.fth
+fload ${BP}/forth/lib/tones.fth
+fload ${BP}/dev/geode/ac97/selftest.fth
+
+false value force-internal-mic? \ Can't be implemented on OLPC boards
+2 value #channels
+
+: input-test-settings ( -- ) ;
+: output-test-settings ( -- ) ;
+
+d# -1 constant case-test-volume
+d# -13 constant fixture-test-volume
+d# -22 constant loopback-test-volume
+
+create analysis-parameters
+d# -23 , \ 0 Sample delay
+d# 40 , \ 1 #fixture
+d# 50 , \ 2 fixture-threshold
+d# 60 , \ 3 case-start-left
+d# 83 , \ 4 case-start-right
+d# 400 , \ 5 case-start-quiet
+d# 60 , \ 6 #case-left
+d# 30 , \ 7 #case-right
+d# 25 , \ 8 case-threshold-left
+d# 25 , \ 9 case-threshold-right
+d# 20 , \ 10 #loopback
+d# 70 , \ 11 loopback-threshold
+
+[ifndef] cl2-a1
+warning @ warning off
+fload ${BP}/dev/hdaudio/test.fth
+warning !
+[then]
+
+: wro
+ wlan-reset-gpio# gpio-dir-in \ So it doesn't fight the cross-wire
+;
+: input-normal ( -- )
+ \ Reconnect pin 36 to WLAN_RESET#
+ wlan-reset-gpio# af@ 7 invert and wlan-reset-gpio# af!
+
+ \ Reconnect pin 26 back to SSPA1 I2S_DATA_IN
+ d# 28 af@ 7 invert and 1 or d# 28 af!
+;
+: input-from-lrclk ( -- )
+ \ Move pin 26 from SSPA1 I2S_DATA_IN to SSPA2 I2S_DATA_IN
+ \ so it doesn't conflict with pin 36.
+ d# 28 af@ 7 invert and 3 or d# 28 af!
+
+ \ Connect pin 36 to SSPA1 I2S_DATA_IN
+ wlan-reset-gpio# af@ 7 invert and 2 or wlan-reset-gpio# af!
+;
+
+finish-device
+
+device-end
+
+: (watch-dc) ( bias? -- )
+ " /audio" open-dev >r ( bias? r: ihandle )
+ " watch-dc" r@ $call-method ( r: ihandle )
+ r> close-dev ( )
+;
+: watch-dc-biased ( -- ) true (watch-dc) ;
+: watch-dc-unbiased ( -- ) false (watch-dc) ;
+
+" /audio/port/endpoint" " /audio-codec/port/endpoint" link-endpoints
+
+\ LICENSE_BEGIN
+\ Copyright (c) 2011 FirmWorks
+\
+\ Permission is hereby granted, free of charge, to any person obtaining
+\ a copy of this software and associated documentation files (the
+\ "Software"), to deal in the Software without restriction, including
+\ without limitation the rights to use, copy, modify, merge, publish,
+\ distribute, sublicense, and/or sell copies of the Software, and to
+\ permit persons to whom the Software is furnished to do so, subject to
+\ the following conditions:
+\
+\ The above copyright notice and this permission notice shall be
+\ included in all copies or substantial portions of the Software.
+\
+\ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+\ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+\ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+\ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+\ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+\ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+\ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+\
+\ LICENSE_END
diff --git a/cpu/arm/olpc/alc5624.fth b/cpu/arm/olpc/alc5624.fth
index 94d9fdb1..9c2d3d22 100644
--- a/cpu/arm/olpc/alc5624.fth
+++ b/cpu/arm/olpc/alc5624.fth
@@ -1,6 +1,24 @@
\ See license at end of file
purpose: Driver for Realtek ALC5624 audio CODEC chip
+" audio-codec" name
+" realtek,alc5624" +compatible
+h# 1a 1 reg
+" rt5624-hifi" " dai-name" string-property \ snd_soc_dai_link.codec_dai_name
+: open ( -- true ) my-unit " set-address" $call-parent true ;
+: close ( -- ) ;
+: codec@ ( reg# -- w ) " reg-w@" $call-parent ;
+: codec! ( w reg# -- ) " reg-w!" $call-parent ;
+
+: codec-set ( bitmask reg# -- ) tuck codec@ or swap codec! ;
+: codec-clr ( bitmask reg# -- ) tuck codec@ swap invert and swap codec! ;
+: codec-field ( value-mask field-mask reg# -- )
+ >r r@ codec@ ( value-mask field-mask value r: reg# )
+ swap invert and ( value-mask masked-value r: reg# )
+ or ( final-value r: reg# )
+ r> codec! ( )
+;
+
: codec-bias-off ( -- )
h# 8080 h# 02 codec-set
h# 8080 h# 04 codec-set
@@ -169,6 +187,17 @@ false value external-mic?
h# 60 codec! h# 62 codec!
;
+new-device
+ " port" device-name
+ new-device
+ " endpoint" device-name
+ d# 256 " mclk-fs" integer-property
+ " /audio-clocks" encode-phandle
+ mmp2-audio-sys-clk# encode-int encode+
+ " clocks" property
+ finish-device
+finish-device
+
\ LICENSE_BEGIN
\ Copyright (c) 2011 FirmWorks
\
diff --git a/cpu/arm/olpc/alc5631.fth b/cpu/arm/olpc/alc5631.fth
index 28c1a061..6098d473 100644
--- a/cpu/arm/olpc/alc5631.fth
+++ b/cpu/arm/olpc/alc5631.fth
@@ -1,6 +1,28 @@
\ See license at end of file
purpose: Driver for Realtek ALC5631Q audio CODEC chip
+" audio-codec" name
+" realtek,alc5631" +compatible
+" realtek,rt5631" +compatible
+h# 1a 1 reg
+" rt5631-hifi" " dai-name" string-property \ snd_soc_dai_link.codec_dai_name
+: open ( -- true ) my-unit " set-address" $call-parent true ;
+: close ( -- ) ;
+: codec@ ( reg# -- w ) " reg-w@" $call-parent ;
+: codec! ( w reg# -- ) " reg-w!" $call-parent ;
+
+: codec-i@ ( index# -- w ) h# 6a codec! h# 6c codec@ ;
+: codec-i! ( w index# -- ) h# 6a codec! h# 6c codec! ;
+
+: codec-set ( bitmask reg# -- ) tuck codec@ or swap codec! ;
+: codec-clr ( bitmask reg# -- ) tuck codec@ swap invert and swap codec! ;
+: codec-field ( value-mask field-mask reg# -- )
+ >r r@ codec@ ( value-mask field-mask value r: reg# )
+ swap invert and ( value-mask masked-value r: reg# )
+ or ( final-value r: reg# )
+ r> codec! ( )
+;
+
: set-routing ( -- )
h# c0c0 h# 02 codec-set \ SPKMIXLR -> SPKVOLLR, muted
h# c0c0 h# 04 codec-set \ OUTMIXLR -> HPOVOLLR, muted
@@ -371,6 +393,17 @@ false value external-mic?
\ h# 60 codec! h# 62 codec!
;
+new-device
+ " port" device-name
+ new-device
+ " endpoint" device-name
+ d# 256 " mclk-fs" integer-property
+ " /audio-clocks" encode-phandle
+ mmp2-audio-sys-clk# encode-int encode+
+ " clocks" property
+ finish-device
+finish-device
+
\ LICENSE_BEGIN
\ Copyright (c) 2011 FirmWorks
\
diff --git a/cpu/arm/olpc/sound.fth b/cpu/arm/olpc/sound.fth
index 3410e428..88289957 100644
--- a/cpu/arm/olpc/sound.fth
+++ b/cpu/arm/olpc/sound.fth
@@ -1,496 +1,6 @@
-dev /i2c@d4011000
-new-device
- " audio-codec" name
- " realtek,alc5631" +compatible
- " realtek,rt5631" +compatible
- h# 1a 1 reg
- " rt5631-hifi" " dai-name" string-property \ snd_soc_dai_link.codec_dai_name
- : open ( -- true ) my-unit " set-address" $call-parent true ;
- : close ( -- ) ;
- : codec@ ( reg# -- w ) " reg-w@" $call-parent ;
- : codec! ( w reg# -- ) " reg-w!" $call-parent ;
-
- new-device
- " port" device-name
- new-device
- " endpoint" device-name
- d# 256 " mclk-fs" integer-property
- " /audio-clocks" encode-phandle
- mmp2-audio-sys-clk# encode-int encode+
- " clocks" property
- finish-device
- finish-device
-finish-device
-device-end
-
-\ "mav" stands for M(DMA), A(DMA), V(DMA), distinct from
-\ the 16 "peripheral" PDMA channels.
-\ The number space for mmp-mav-dma-channels is as follows:
-\ 0: MDMA0
-\ 1: MDMA1
-\ 2: ADMA1_CH0 (out)
-\ 3: ADMA1_CH1 (in)
-\ 4: ADMA2_CH0 (out)
-\ 5: ADMA2_CH1 (in)
-\ 6: VDMA1_CH0
-\ 7: VDMA1_CH1
-\ That's consistent with the enumeration mmp_tdma_type in
-\ Linux:arch/arm/mach-mmp/include/mach/mmp_dma.h
-\ and also reflects the bit numbering (+16) in the various
-\ DMA IRQ status and mask registers, e.g. ICU_DMA_IRQ1_STATUS
-
-dev /
-1 [if]
-new-device
- " adma" device-name
- h# 900 +audio h# 100 reg
- 5 encode-int 4 encode-int encode+ " mmp-mav-dma-channels" property
- " marvell,mmp-audio-dma" +compatible
- " marvell,adma-1.0" +compatible
- 1 " #dma-cells" integer-property
-
-[ifdef] mmp3
- " /interrupt-controller@128" encode-phandle " interrupt-parent" property
- d# 20 encode-int d# 21 encode-int encode+ " interrupts" property
-[else]
- d# 48 " interrupts" integer-property
-[then]
-
- " disabled" " status" string-property
- current-device ( adma1-ph )
-finish-device
-
-new-device
- ( adma1-ph ) encode-int " adma-node" property
- " pcm" device-name
- 1 0 reg
-
- \ This binds to the platform driver, a single point that collects
- \ the Audio DMA resources
- " marvell,mmp-pcm-audio" +compatible \ snd_soc_dai_link.cpu_dai_of_node
- " disabled" " status" string-property
-
-finish-device
-[then]
-
-new-device
- " asram" device-name
- audio-sram-pa /audio-sram reg
-
- " marvell,mmp-asram" +compatible
- " mmio-sram" +compatible
- 1 " #address-cells" integer-property
- 1 " #size-cells" integer-property
-
- 0 encode-int
- audio-sram-pa encode-int encode+
- /audio-sram encode-int encode+
- " ranges" property
-finish-device
-
-new-device
- " adma" device-name
- h# 800 +audio h# 100 reg
- 3 encode-int 2 encode-int encode+ " mmp-mav-dma-channels" property
- " marvell,mmp-audio-dma" +compatible
- " marvell,adma-1.0" +compatible
- 1 " #dma-cells" integer-property
-
-[ifdef] mmp3
- " /interrupt-controller@128" encode-phandle " interrupt-parent" property
- d# 18 encode-int d# 19 encode-int encode+ " interrupts" property
-[else]
- d# 48 " interrupts" integer-property
-[then]
-
- " /asram" encode-phandle " asram" property
- " /asram" encode-phandle " iram" property
- current-device ( adma0-ph )
-finish-device
-
-new-device
- ( adma0-ph ) encode-int " adma-node" property
- " pcm" device-name
- 0 0 reg
-
- \ This binds to the platform driver, a single point that collects
- \ the Audio DMA resources
- " marvell,mmp-pcm-audio" +compatible \ snd_soc_dai_link.cpu_dai_of_node
-
-[ifdef] mmp3
- \ Our asram node (below) declares that /audio-sram bytes of SRAM
- \ are assigned to the audio function. We divide that here, roughly
- \ half to playback and half to recording.
-
- \ Even though we choose big buffers, we do leave a little bit of
- \ free space for the DMA engine which also needs to use a bit of
- \ the SRAM area for DMA descriptors. Therefore we choose 62kb for
- \ each buffer, leaving 4kb available for DMA descriptors.
-
- \ For the max period size, we don't have any justification other
- \ than 2048 is the value we've been using all along.
-
- /audio-sram-pcm encode-int
- /audio-sram-mps encode-int encode+
- /audio-sram-pcm encode-int encode+
- /audio-sram-mps encode-int encode+
- " marvell,buffer-sizes" property
-[then]
-finish-device
-
-new-device
- " sspa" name
- h# d00 +audio encode-int h# 30 encode-int encode+
- h# d80 +audio encode-int encode+ h# 30 encode-int encode+
- " reg" property
-
- " marvell,mmp-sspa-dai" +compatible
-[ifdef] mmp2 " marvell,mmp2-sspa-dai" +compatible [then]
-[ifdef] mmp3 " marvell,mmp3-sspa-dai" +compatible [then]
-
- " unused" " status" string-property
-
- d# 3 " interrupts" integer-property
- 0 0 encode-bytes
- " /clocks" encode-phandle encode+ mmp2-audio-clk# encode-int encode+
- " /audio-clocks" encode-phandle encode+ mmp2-audio-sspa1-clk# encode-int encode+
- " clocks" property
- 0 0 encode-bytes
- " audio" encode-string encode+
- " bitclk" encode-string encode+
- " clock-names" property
- " /clocks" encode-phandle mmp2-audio-pd# encode-int encode+
- " power-domains" property
- 0 " #sound-dai-cells" integer-property
-finish-device
-
-new-device
-
-" audio" name
-h# c00 +audio encode-int h# 30 encode-int encode+
- h# c80 +audio encode-int encode+ h# 30 encode-int encode+
- " reg" property
-
-" marvell,mmp-sspa-dai" +compatible
-[ifdef] mmp2 " marvell,mmp2-sspa-dai" +compatible [then]
-[ifdef] mmp3 " marvell,mmp3-sspa-dai" +compatible [then]
-" marvell,mmp-sspa" +compatible
-
-d# 2 " interrupts" integer-property
-
-0 0 encode-bytes
- " /clocks" encode-phandle encode+ mmp2-audio-clk# encode-int encode+
- " /audio-clocks" encode-phandle encode+ mmp2-audio-sspa0-clk# encode-int encode+
- " clocks" property
-0 0 encode-bytes
- " audio" encode-string encode+
- " bitclk" encode-string encode+
- " clock-names" property
-" /clocks" encode-phandle mmp2-audio-pd# encode-int encode+
- " power-domains" property
-0 " #sound-dai-cells" integer-property
-
-0 0 encode-bytes
- " /adma" encode-phandle encode+ 0 encode-int encode+
- " /adma" encode-phandle encode+ 1 encode-int encode+
-" dmas" property
-" tx" encode-string " rx" encode-string encode+ " dma-names" property
-
-new-device
- " port" device-name
- new-device
- " endpoint" device-name
- " i2s" " dai-format" string-property
- 0 0 " bitclock-master" property
- 0 0 " frame-master" property
- finish-device
-finish-device
-
-0 value sspa-base \ E.g. h# 2a.0c00 +io
-0 value adma-base \ E.g. h# 2a.0800 +io
-: sspa! ( n offset -- ) sspa-base + rl! ; \ Write a register in SSPA1
-: sspa@ ( offset -- n ) sspa-base + rl@ ; \ Read a register in SSPA1
-: adma! ( n offset -- ) adma-base + rl! ;
-: adma@ ( offset -- n ) adma-base + rl@ ;
-
-: audio-clock-off ( -- )
- 0 h# 38 sspa!
- " /clocks" " audio-island-off" execute-device-method drop
-;
-: start-audio-pll ( -- error? )
- \ For VCXO=26 MHz, OCLK=12.2880 MHz
- \ MMP2: DIV_OCLK_MODULO=010 FRACT=00da1 ENA_DITHER=1 ICP=0 DIV_FBCCLK=01 DIV_MCLK=0 PU=1
- \ MMP2: DIV_OCLK_MODULO=010 FRACT=00da1 ENA_DITHER=1 ICP=0 DIV_FBCCLK=01 DIV_MCLK=011 PU=1
- [ifdef] mmp3 h# a00d.a18d [else] h# 200d.a189 [then] h# 38 sspa!
- h# 0000.0801 h# 3c sspa! \ CLK_SEL=1 (AudioPLL) DIV_OCLK_PATTERN=01
- d# 50 0 do
- h# 3c sspa@ h# 10000 and if
- false unloop exit
- then
- d# 10 us
- loop
- ." Audio PLL did not start" cr
- true
-;
-
-: dly d# 10 us ;
+\ See license at end of file
-true value use-audio-pll?
-: audio-clock-on ( -- error? )
- " /clocks" " audio-island-on" execute-device-method drop
-
- use-audio-pll? if
- start-audio-pll if true exit then
-
- \ Bits 14:9 set the divisor from SYSCLK to BITCLK. The setting below
- \ is d# 8, which gives BITCLK = 1.536 MHz. That's 32x 48000, just enough
- \ for two (stereo) 16-bit samples.
- \ The 80 bit is 0, choosing the AudioPLL instead of the I2SCLK
- h# 1103 h# 34 sspa! \ SSPA_AUD_CTRL0
- else
- \ This section of the code uses I2SCLK instead of the Audio PLL. Marvell
- \ says that I2SCLK is prone to jitter so the Audio PLL is preferred.
-
- \ * 10 / 27 gives about 147.456
- \ The M/N divisor gets 199.33 MHz (Figure 283 - clock tree - in Datasheet)
- \ But the M/N divisors always have an implicit /2 (section 7.3.7 in datasheet),
- \ so the input frequency is 99.67 with respect to NOM (sic) and DENOM.
- \ we want 12.288 MHz SYSCLK. 99.67 * 9 / 73 = 12.2876 so 50 ppm error.
- d# 9 d# 15 lshift d# 73 or h# d000.0000 or h# 40 mpmu!
-
- \ The manual says that bit 5 enables I2SCLK to SSPA1, but empirically, bit 21 seems to do it
- \ That is true on both MMP2 and MMP3
- h# 20.0000 h# 1024 +mpmu io-set \ Enable 12S clock out to SSPA1
-
- \ h# 10800 h# 38 sspa! \ Appears unnecessary; not sure what it does
-
- \ Bits 14:9 set the divisor from SYSCLK to BITCLK. The setting below
- \ is d# 8, which gives BITCLK = 1.536 MHz. That's 32x 48000, just enough
- \ for two (stereo) 16-bit samples.
- \ The 80 bit is 1, choosing the I2SCLK instead of the AudioPLL
- h# 1183 h# 34 sspa! \ SSPA_AUD_CTRL0
- then
- false
-;
-\ This is a grotesque workaround for a hardware problem. The audio
-\ subsystem (SSPA + ADMA) works reasonably reliably right after the
-\ audio island is powered on, but subsequent tries tend to get
-\ confused about which channel is which, and possibly about the
-\ initial SSPA FIFO contents. Resetting between test phases makes
-\ the test work more reliably. Attempts to get help from the vendor,
-\ over a long period of time, were unsuccessful.
-: reset-audio ( -- ) audio-clock-off d# 50 ms audio-clock-on drop ;
-
-: reset-rx ( -- ) h# 8000.0002 h# 0c sspa! ;
-
-: active-low-rx-fs ( -- )
- h# 0c sspa@ h# 8001.0000 or h# 0c sspa!
-;
-: active-high-rx-fs ( -- )
- h# 0c sspa@ h# 10000 invert and h# 8000.0000 or h# 0c sspa!
-;
-: setup-sspa-rx ( -- )
- reset-rx
-
- h# 8000.0000 \ Dual phase (stereo)
- 0 d# 24 lshift or \ 1 word in phase 2
- 2 d# 21 lshift or \ 16 bit word in phase 2
- 0 d# 19 lshift or \ 0 bit delay
- 2 d# 16 lshift or \ 16-bit audio sample in phase 2
- 0 d# 8 lshift or \ 1 word in phase 1
- 2 d# 5 lshift or \ 16 bit word in phase 1
- 0 d# 3 lshift or \ Left justified data
- 2 d# 0 lshift or \ 16-bit audio sample in phase 1
- h# 08 sspa! \ Receive control register
-
- h# 8000.0000 \ Enable writes
- d# 15 d# 20 lshift or \ Frame sync width
-\ We choose the master/slave configuration later, in enable-sspa-rx
- 0 d# 18 lshift or \ Internal clock - master configuration
- 0 d# 17 lshift or \ Sample on rising edge of clock
- 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
- h# 0c sspa!
-
- h# 10 h# 10 sspa! \ Rx FIFO limit
-;
-: master-rx ( -- ) h# 0c sspa@ h# 8004.0001 or h# 0c sspa! ; \ Master, on
-: slave-rx ( -- ) h# 0c sspa@ h# 8000.0001 or h# 0c sspa! ; \ Slave, on
-: flush-rx ( -- ) h# 0c sspa@ h# 8000.0004 or h# 0c sspa! ; \ Hit the flush bit
-: disable-sspa-rx ( -- ) h# 0c sspa@ h# 8000.0004 or h# 4.0001 invert and h# 0c sspa! ;
-
-: reset-tx ( -- ) h# 8000.0002 h# 8c sspa! ;
-
-: active-low-tx-fs ( -- )
- h# 8c sspa@ h# 8001.0000 or h# 8c sspa!
-;
-: active-high-tx-fs ( -- )
- h# 8c sspa@ h# 10000 and h# 8000.0000 or h# 8c sspa!
-;
-: setup-sspa-tx ( -- )
- reset-tx
-
- h# 8000.0000 \ Dual phase (stereo)
- 0 d# 24 lshift or \ 1 word in phase 2
- 2 d# 21 lshift or \ 16 bit word in phase 2
- 0 d# 19 lshift or \ 0 bit delay
- 2 d# 16 lshift or \ 16-bit audio sample in phase 2
- 1 d# 15 lshift or \ Transmit last sample when FIFO empty
- 0 d# 8 lshift or \ 1 word in phase 1
- 2 d# 5 lshift or \ 16 bit word in phase 1
- 0 d# 3 lshift or \ Left justified data
- 2 d# 0 lshift or \ 16-bit audio sample in phase 1
- h# 88 sspa! \ Transmit control register
-
- h# 8000.0000 \ Enable writes
- d# 15 d# 20 lshift or \ Frame sync width
-\ We choose the master/slave configuration later, in master-tx
- 0 d# 18 lshift or \ External clock - slave configuration (Rx is master)
- 0 d# 17 lshift or \ Sample on rising edge of clock
-
- 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
- h# 8c sspa!
-
- h# 10 h# 90 sspa! \ Tx FIFO limit
-;
-: master-tx ( -- ) h# 8c sspa@ h# 8004.0001 or h# 8c sspa! ; \ Master, on
-: slave-tx ( -- ) h# 8c sspa@ h# 8000.0001 or h# 8c sspa! ; \ Slave, on
-: flush-tx ( -- ) h# 8c sspa@ h# 8000.0004 or h# 8c sspa! ; \ Hit the flush bit
-: disable-sspa-tx ( -- ) h# 8c sspa@ h# 8000.0004 or h# 4.0001 invert and h# 8c sspa! ;
-
-h# fc0 constant /audio-buf
-audio-sram-va constant out-bufs
-audio-sram-va h# 1f80 + constant out-desc
-audio-sram-va h# 2000 + constant in-bufs
-audio-sram-va h# 3f80 + constant in-desc
-
-\ Descriptor format:
-\ Byte count
-\ Source
-\ Destination
-\ link
-
-0 value my-out-desc \ out-desc or out-desc h# 20 +
-0 value out-adr
-0 value out-len
-0 value my-in-desc \ in-desc or in-desc h# 20 +
-0 value in-adr
-0 value in-len
-: set-descriptor ( next dest source length adr -- )
- >r r@ l! r@ la1+ l! r@ 2 la+ l! r> 3 la+ l!
-;
-: make-out-ring ( -- )
- out-desc h# 10 + sspa-base h# 80 + out-bufs /audio-buf out-desc set-descriptor
- out-desc sspa-base h# 80 + out-bufs /audio-buf + /audio-buf out-desc h# 10 + set-descriptor
- out-desc h# 30 adma! \ Link to first descriptor
- out-desc to my-out-desc
-;
-
-0 value use-packmod?
-
-: start-out-ring ( -- )
- 1 h# 80 adma! \ Enable DMA completion interrupts
- h# 0080.3020 \ 16 bits, fetch next, enable, chain, hold dest, inc src
- use-packmod? if h# 1.0000 or then
- h# 40 adma!
-;
-: stop-out-ring ( -- ) h# 100000 h# 40 adma! 0 h# 80 adma! ;
-
-: make-in-ring ( -- )
- in-desc h# 10 + in-bufs sspa-base /audio-buf in-desc set-descriptor
- in-desc in-bufs /audio-buf + sspa-base /audio-buf in-desc h# 10 + set-descriptor
- in-desc h# 34 adma! \ Link to first descriptor
- in-desc to my-in-desc
-;
-: start-in-ring ( -- )
- 1 h# 84 adma! \ Enable DMA completion interrupts
-\ h# 0081.3008 h# 44 adma! \ 16 bits, pack, fetch next, enable, chain, inc dest, hold src
-
- h# 00a0.31c8 \ 16 bits, fetch next, enable, chain, burst32, inc dest, hold src
- use-packmod? if h# 1.0000 or then
- h# 44 adma!
-;
-: stop-in-ring ( -- ) h# 100000 h# 44 adma! 0 h# 84 adma! ;
-
-: unpack-move ( src dst packed-len -- )
- 1 rshift 0 ?do ( src dst )
- over i wa+ w@ ( src dst sample )
- over i la+ wa1+ w! ( src dst )
- loop ( src dst )
- 2drop ( )
-;
-
-: pack-move ( src dst packed-len -- )
- 1 rshift 0 ?do ( src dst )
- over i la+ wa1+ w@ ( src dst sample )
- over i wa+ w! ( src dst )
- loop ( src dst )
- 2drop ( )
-;
-
-: copy-out ( -- )
- my-out-desc >r ( r: desc )
- use-packmod? if
- out-len /audio-buf min ( this-packed-len r: desc )
- dup r@ l! ( this-packed-len r: desc )
- out-adr r@ la1+ l@ third move ( this-packed-len r: desc )
- else
- out-len /audio-buf 2/ min ( this-packed-len r: desc )
- dup 2* r@ l! ( this-packed-len r: desc )
- out-adr r@ la1+ l@ third unpack-move ( this-packed-len r: desc )
- then
-
- out-adr over + to out-adr ( this-packed-len r: desc )
- out-len swap - to out-len ( r: desc )
- out-len if
- r> 3 la+ l@ to my-out-desc
- else
- 0 r> 3 la+ l! \ When there is no more data, terminate the list
- then
-;
-
-: copy-in ( -- )
- use-packmod? if
- in-len /audio-buf min ( this-packed-len )
- my-in-desc 2 la+ l@ in-adr third move ( this-packed-len )
- else
- in-len /audio-buf 2/ min ( this-packed-len )
- my-in-desc 2 la+ l@ in-adr third pack-move ( this-packed-len )
- then
- in-adr over + to in-adr ( this-packed-len )
- in-len over - to in-len ( this-packed-len )
- drop ( )
- my-in-desc 3 la+ l@ to my-in-desc
-;
-
-\ Reset is unconnected on current boards
-\ : audio-reset ( -- ) audio-reset-gpio# gpio-clr ;
-\ : audio-unreset ( -- ) audio-reset-gpio# gpio-set ;
-0 value codec-ih
-: $call-codec ( ? -- ? ) codec-ih $call-method ;
-
-: codec@ ( reg# -- w ) " codec@" $call-codec ;
-: codec! ( w reg# -- ) " codec!" $call-codec ;
-
-: codec-i@ ( index# -- w ) h# 6a codec! h# 6c codec@ ;
-: codec-i! ( w index# -- ) h# 6a codec! h# 6c codec! ;
-
-: codec-set ( bitmask reg# -- ) tuck codec@ or swap codec! ;
-: codec-clr ( bitmask reg# -- ) tuck codec@ swap invert and swap codec! ;
-: codec-field ( value-mask field-mask reg# -- )
- >r r@ codec@ ( value-mask field-mask value r: reg# )
- swap invert and ( value-mask masked-value r: reg# )
- or ( final-value r: reg# )
- r> codec! ( )
-;
-
-[ifdef] cl2-a1
-fload ${BP}/cpu/arm/olpc/alc5624.fth \ Realtek ALC5624 CODEC
-[else]
+[ifndef] cl2-a1
hp-plug-gpio# constant headphone-jack
mic-plug-gpio# constant external-mic
: pin-sense? ( gpio# -- flag ) gpio-pin@ ;
@@ -499,541 +9,21 @@ mic-plug-gpio# constant external-mic
external-mic pin-sense?
\+ olpc-cl3 0=
;
-
-fload ${BP}/cpu/arm/olpc/alc5631.fth \ Realtek ALC5631Q CODEC
[then]
-
-d# 48000 value sample-rate
-\ Longest time to wait for a buffer event - a little more
-\ than the time it takes to output /audio-buf samples
-\ at the current sample rate.
-0 value buf-timeout
-
-: set-ctlr-sample-rate ( rate -- )
- case
- d# 8000 of d# 48 d# 129 endof
- d# 16000 of d# 24 d# 65 endof
- d# 32000 of d# 12 d# 33 endof
- d# 48000 of d# 8 d# 23 endof
- ( default ) true abort" Unsupported audio sample rate"
- endcase ( sspareg34val timeout )
- to buf-timeout
- 9 lshift h# 34 sspa@ h# 7e00 invert and or h# 34 sspa!
-;
-
-: dma-alloc ( len -- adr ) " dma-alloc" $call-parent ;
-: dma-free ( adr len -- ) " dma-free" $call-parent ;
-
-: wait-out ( -- )
- buf-timeout 0 do
- 1 ms h# a0 adma@ 1 and ?leave
- loop
- 0 h# a0 adma!
-;
-
-defer playback-alarm
-0 value alarmed?
-
-: install-playback-alarm ( -- )
- true to alarmed? ['] playback-alarm d# 2 alarm
-;
-: uninstall-playback-alarm ( -- )
- alarmed? if
- false to alarmed?
- ['] playback-alarm d# 0 alarm
- then
-;
-
-false value playing?
-
-: stop-out ( -- )
- disable-sspa-tx
- reset-tx
- stop-out-ring
- uninstall-playback-alarm
- false to playing?
- close-out
-;
-
-: out-ready? ( -- flag )
- h# a0 adma@ 1 and 0<>
- dup if 0 h# a0 adma! then
-;
-: out-dma-done? ( -- flag ) h# 40 adma@ h# 4000 and 0= ;
-
-: ?end-playing ( -- )
- out-ready? if
- out-len if copy-out then
- out-dma-done? if stop-out then
- then
-;
-
-: set-out-in-mic ( -- )
- h# 80 h# 12 codec! \ Mute right channel
- h# 00 h# 16 codec! \ Full digital gain
- h# 6688 h# 22 codec! \ No mic boost, low bias
-;
-
-: playback-continue-alarm ( -- )
- playing? if
- ?end-playing
- else
- \ If playback has already stopped as a result of
- \ someone else having waited for completion, we
- \ just uninstall ourself.
- uninstall-playback-alarm
- then
-;
-' playback-continue-alarm to playback-alarm
-
-: start-audio-out ( adr len -- )
- to out-len ( adr )
- to out-adr ( )
- setup-sspa-tx ( )
- make-out-ring
- copy-out
- out-len if copy-out then \ Prefill the second buffer
- start-out-ring
- master-tx
- true to playing?
- install-playback-alarm
-;
-
-: audio-out ( adr len -- actual ) tuck start-audio-out ;
-
-: stop-sound ( -- )
- lock[
- playing? if stop-out then
- ]unlock
-;
-
-0 value time-limit
-: set-time-limit ( ms -- ) get-msecs + to time-limit ;
-: 1sec-time-limit ( -- ) d# 1000 set-time-limit ;
-: ?timeout ( -- )
- get-msecs time-limit - 0> if
- ." Audio device timeout!" cr
- abort
- then
-;
-: wait-out-done ( -- )
- d# 20,000 set-time-limit begin ?timeout playing? 0= until
-;
-: write-done ( -- ) wait-out-done stop-out ;
-
-: write ( adr len -- actual ) open-out audio-out ;
-
-: in-ready? ( -- flag )
- h# a4 adma@ 1 and 0<>
- dup if 0 h# a4 adma! then
-;
-: wait-in ( -- )
- buf-timeout 0 do
- 1 ms in-ready? ?leave
- loop
-;
-
-: audio-in ( adr len -- actual )
- tuck to in-len to in-adr ( actual )
- setup-sspa-rx ( actual )
- make-in-ring ( actual )
- start-in-ring ( actual )
- master-rx ( actual )
- begin in-len while ( actual )
- wait-in ( actual )
- copy-in ( actual )
- repeat ( actual )
- disable-sspa-rx ( actual )
- stop-in-ring ( actual )
- reset-rx ( actual )
-;
-: read ( adr len -- actual ) open-in audio-in close-in ;
-
-0 value mono?
-: stereo false to mono? ;
-: mono true to mono? ;
-
-: average-channel ( adr -- n )
- 0 swap /audio-buf bounds do ( accum )
- i <w@ + ( accum' )
- /l +loop ( accum )
- /audio-buf /l / / ( average )
-;
-: average-in ( -- )
- my-in-desc 2 la+ l@ ( adr )
- (cr push-decimal ( adr )
- dup average-channel ( adr average )
- 6 .r space ( adr )
- wa1+ average-channel ( average )
- 6 .r ( )
- pop-base ( )
- my-in-desc 3 la+ l@ to my-in-desc
-;
-: audio-watch ( -- )
- setup-sspa-rx ( )
- make-in-ring ( )
- start-in-ring ( )
- master-rx ( )
- begin ( )
- wait-in ( )
- average-in ( )
- key? until ( )
- disable-sspa-rx ( )
- stop-in-ring ( )
- reset-rx ( )
-;
-: watch-dc ( bias? -- )
- to mic-bias?
- mic-ac/dc-gpio# gpio-set \ DC input mode
- h# 0400 h# 40 codec-clr
- open-in
- stereo 0 set-adc-gain 0 set-mic-gain
- \ High bias gets us closer to the top of the digital range - but bias can
- \ be turned off completely with "false to mic-bias?"
- mic1-high-bias mic2-high-bias
- audio-watch
- close-in
-;
-
-0 value in-adr0
-0 value in-len0
-: collapse-in ( -- )
- in-len0 0 ?do
- in-adr0 i la+ w@ in-adr0 i wa+ w!
- loop
-;
-code startit ( sspa-adr -- )
- set r0,#0x80f101f1
- set r1,#0x80f501f1
- str r0,[tos,#0x8c]
- str r1,[tos,#0x0c]
- pop tos,sp
-c;
-: startoutin ( -- ) disable-interrupts sspa-base startit enable-interrupts ;
-: xstartoutin ( -- ) slave-tx master-rx ;
-
-: out-in0 ( 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
-
- \ Resetting the clock at this point seems to prevent intermittent channel
- \ reversal on reception.
-\ audio-clock-on drop ( ) \ This will mess up any frequency settings
-
- setup-sspa-tx ( )
- setup-sspa-rx ( )
-
- make-in-ring ( )
- make-out-ring ( )
- copy-out ( ) \ Prefill the first Tx buffer
- out-len if copy-out then ( ) \ Prefill the second Tx buffer
-
- start-in-ring ( )
- start-out-ring ( )
-
- xstartoutin
-\ slave-tx ( )
-\ master-rx ( ) \ Now the clock is on
-
- true to playing?
-
- begin in-len playing? or while ( )
- in-ready? if copy-in then ( )
- playing? if ?end-playing then ( )
- repeat ( )
- disable-sspa-rx ( )
- disable-sspa-tx ( )
-
- stop-in-ring
- stop-out-ring
-
- reset-rx
- reset-tx
-
- close-out-in
- mono? if collapse-in then ( )
-;
-
-: out-in1 ( 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
-
- \ Resetting the clock at this point seems to prevent intermittent channel
- \ reversal on reception.
-\ audio-clock-on drop ( ) \ This will mess up any frequency settings
-
- make-out-ring ( )
- copy-out ( ) \ Prefill the first Tx buffer
- out-len if copy-out then ( ) \ Prefill the second Tx buffer
-
- setup-sspa-rx ( )
- make-in-ring ( )
- start-in-ring ( )
- master-rx ( ) \ Now the clock is on
-
- start-out-ring ( )
- setup-sspa-tx ( )
- slave-tx ( )
-
- true to playing?
-
- begin in-len playing? or while ( )
- in-ready? if copy-in then ( )
- playing? if ?end-playing then ( )
- repeat ( )
- disable-sspa-rx ( )
- disable-sspa-tx ( )
-
- stop-in-ring
- stop-out-ring
-
- reset-rx
- reset-tx
-
- close-out-in
- mono? if collapse-in then ( )
-;
-
-d# 20 value audio-dly
-: out-in2 ( 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
-
- \ Resetting the clock at this point seems to prevent intermittent channel
- \ reversal on reception.
-\ audio-clock-on drop ( ) \ This will mess up any frequency settings
-
- setup-sspa-tx ( )
- setup-sspa-rx ( )
-
- make-in-ring ( )
- make-out-ring ( )
- copy-out ( ) \ Prefill the first Tx buffer
- out-len if copy-out then ( ) \ Prefill the second Tx buffer
-
- xstartoutin
-
- audio-dly us
- flush-rx
- flush-tx
- start-in-ring ( )
- start-out-ring ( )
-
-
- true to playing?
-
- begin in-len playing? or while ( )
- in-ready? if copy-in then ( )
- playing? if ?end-playing then ( )
- repeat ( )
- disable-sspa-rx ( )
- disable-sspa-tx ( )
-
- stop-in-ring
- stop-out-ring
-
- reset-rx
- reset-tx
-
- close-out-in
- mono? if collapse-in then ( )
-;
-
-defer out-in ' out-in0 to out-in
-
-0 [if]
-working recipe: only one out-in in test-common
-out-in2
-disable-interrupts before audio-clock-on and enable after reset-rx
-dly 73 us
-read and discard rx fifo depth before flush-rx
-
-also works with dly 10 us
-reliably swaps with dly 1 us
-swaps with dly 5
-swap with dly 7
-not swap with dly 8
-
-Hmmm, maybe the basic issue is the double out-in in test-common -
-Try out-in0 using one out-in
-Try out-in2 without read/discard fifo depth using one out-in
-
-Swap alternates every 10 or so us, flipping at about 8 or 9 mod 10
-An extra 2 samples appear ever 10 or so us, at about 1 or 2 mod 10
-
-04 us is stable with swapping
-14 us is stable with no swapping
-
-If you remove flush-rx from fr ( : fr 1c sspa@ foo ! flush-rx ; )
-swapping always happens - 04, 14, 24 us all swap
- This is because when you flush-rx with fifo depth 2, 6, a, etc,
- that loses an odd number of channel samples
-[then]
-
-0 [if] \ Interactive test words for out-in
-h# 20000 constant tlen
-: xb load-base 1meg + ;
-: ob load-base ;
-: sb load-base 1meg 2* + ;
-: px xb tlen write drop ;
-: po ob tlen write drop ;
-: ps sb tlen write drop ;
-: shiftit xb 1+ sb tlen move ;
-: oi ob tlen xb tlen out-in ;
-[then]
-
-: wait-sound ( -- )
- lock[
- begin playing? while d# 2 ms ?end-playing repeat
- ]unlock
-;
+dev /i2c@d4011000
+new-device
-0 [if]
-\ Notes:
-\ Page 1504 - what does "RTC (and WTC) for sync fifo" mean?
-\ Page 1508 - SSPA_AUD_PLL_CTRL1 bit 17 refers to "zsp_clk_gen" <- undefined term appears nowhere else in either document
-\ Page 1501 - do the Frame-Sync Width and Frame-Sync Active fields matter in slave mode, or are they only relevant in master mode??? If they matter in slave mode, what do they control, considering that the external code is driving FSYNC and thus controls its width.
-\ Page 1506 - For I2S_RXDATA, the connection from the pin driver to RX_DATA_IN(18) is shown going to the (disabled) output driver. I think it should come from the input (left-pointing triangle) instead.
-\ Page 1506 - The "18" and "19" notation is unexplained and unclear. I sort of think that 18 means the Rx direction and 19 the Tx direction. If so, and the diagram is correct, then you cannot drive FSYNC from the Tx direction. If that is the case, it ought to be explained elsewhere too. In particular, if you can't drive FSYNC from Tx, what are the FWID and FPER fields in SSPA_TX_SP_CTRL for?
-\ Page 1506 - The diagram shows the ENB for the I2S_BITCLK driver coming from M/S_19 in SSPA. But the Master/Slave bits in both SSPA_TX_SP_CTRL and SSPA_RX_SP_CTRL have no effect on whether BITCLK is driven. It seems to be controlled by bit 8 in SSPA_AUD_CTRL0 (which is misnamed as enabling the SYSCLK Divider, not the BITCLK output. Which makes me wonder what enables the I2S_FSYNC signal, which is shown as being enabled along with I2S_BITCLK. But I can't seem to get FSYNC to come out.
-\ What is the relationship between Rx master mode and Tx master mode with regards to whether FSYNC is driven? Empirically, if I turn on and enable the Rx portion, FSYNC comes on, but if I then turn on the Tx portion, FSYNC turns off until I enable the Tx portion. After that, Tx seems to control FSYNC and nothing I do seems to let Rx control it.
-\ Page 1502 - S_RST is listed as W, but empirically it is readable. When you write 1 to it, the 1 sticks and you have to write 0 again. It's unclear which of the registers it really resets. It doesn't reset the register it is in.
-\ Page 1498 - The data transmit register is listed as RO. How can a transmit register be RO????
+[ifdef] cl2-a1
+fload ${BP}/cpu/arm/olpc/alc5624.fth \ Realtek ALC5624 CODEC
+[else]
+fload ${BP}/cpu/arm/olpc/alc5631.fth \ Realtek ALC5631Q CODEC
[then]
-: set-sample-rate ( rate -- )
- dup to sample-rate
- dup set-ctlr-sample-rate
- set-codec-sample-rate
-;
-: set-get-sample-rate ( rate -- actual-rate )
- drop d# 48000 ( actual-rate )
- dup set-sample-rate ( actual-rate )
-;
-
-\ This is called from "record" in "mic-test" in "selftest"
-: set-record-gain ( db -- )
- \ translate value from ac97 selftest code into our default value
- dup h# 808 = if ( db )
- drop default-adc-gain ( db' )
- d# 40 set-mic-gain ( db )
- then ( db )
- set-adc-gain
-;
-
-: init-codec ( -- )
- codec-on
- set-default-gains
- d# 48000 set-sample-rate
-;
-: (close)
- audio-clock-off
- adma-base h# 100 " map-out" $call-parent
- sspa-base h# 100 " map-out" $call-parent
- 0 to adma-base 0 to sspa-base
-;
-
-0 value open-count
-: open ( -- flag )
- open-count 0= if
- my-unit h# 400 - h# 100 " map-in" $call-parent to adma-base
- my-unit h# 100 " map-in" $call-parent to sspa-base
- audio-clock-on if (close) false exit then
- " /audio-codec" open-dev to codec-ih
- codec-ih 0= if (close) false exit then
- init-codec
- then
- open-count 1+ to open-count
- true
-;
-: close ( -- )
- open-count 1 = if
- uninstall-playback-alarm codec-off
- codec-ih close-dev
- (close)
- then
- open-count 1- 0 max to open-count
-;
-
-fload ${BP}/forth/lib/isin.fth
-fload ${BP}/forth/lib/tones.fth
-fload ${BP}/dev/geode/ac97/selftest.fth
-
-false value force-internal-mic? \ Can't be implemented on OLPC boards
-2 value #channels
-
-: input-test-settings ( -- ) ;
-: output-test-settings ( -- ) ;
-
-d# -1 constant case-test-volume
-d# -13 constant fixture-test-volume
-d# -22 constant loopback-test-volume
-
-create analysis-parameters
-d# -23 , \ 0 Sample delay
-d# 40 , \ 1 #fixture
-d# 50 , \ 2 fixture-threshold
-d# 60 , \ 3 case-start-left
-d# 83 , \ 4 case-start-right
-d# 400 , \ 5 case-start-quiet
-d# 60 , \ 6 #case-left
-d# 30 , \ 7 #case-right
-d# 25 , \ 8 case-threshold-left
-d# 25 , \ 9 case-threshold-right
-d# 20 , \ 10 #loopback
-d# 70 , \ 11 loopback-threshold
-
-warning @ warning off
-fload ${BP}/dev/hdaudio/test.fth
-warning !
-
-: wro
- wlan-reset-gpio# gpio-dir-in \ So it doesn't fight the cross-wire
-;
-: input-normal ( -- )
- \ Reconnect pin 36 to WLAN_RESET#
- wlan-reset-gpio# af@ 7 invert and wlan-reset-gpio# af!
-
- \ Reconnect pin 26 back to SSPA1 I2S_DATA_IN
- d# 28 af@ 7 invert and 1 or d# 28 af!
-;
-: input-from-lrclk ( -- )
- \ Move pin 26 from SSPA1 I2S_DATA_IN to SSPA2 I2S_DATA_IN
- \ so it doesn't conflict with pin 36.
- d# 28 af@ 7 invert and 3 or d# 28 af!
-
- \ Connect pin 36 to SSPA1 I2S_DATA_IN
- wlan-reset-gpio# af@ 7 invert and 2 or wlan-reset-gpio# af!
-;
-
finish-device
-
device-end
-: (watch-dc) ( bias? -- )
- " /audio" open-dev >r ( bias? r: ihandle )
- " watch-dc" r@ $call-method ( r: ihandle )
- r> close-dev ( )
-;
-: watch-dc-biased ( -- ) true (watch-dc) ;
-: watch-dc-unbiased ( -- ) false (watch-dc) ;
-
+fload ${BP}/cpu/arm/mmp2/sound.fth
0 0 " " " /" begin-package
" audio-complex" device-name
@@ -1097,8 +87,6 @@ device-end
h# 4101 " dai-format" encode-int
end-package
-" /audio/port/endpoint" " /audio-codec/port/endpoint" link-endpoints
-
\ LICENSE_BEGIN
\ Copyright (c) 2011 FirmWorks
\