From 6e835fc21e8b0f933e0ad8bda6063b2fdbc7cff6 Mon Sep 17 00:00:00 2001
From: Jeffrey Lee <jlee@gitlab.riscosopen.org>
Date: Sun, 30 Sep 2012 16:36:44 +0000
Subject: [PATCH] Implement Pandora keyboard scan & audio support

Detail:
  s/PAudio, Makefile - Added Pandora audio driver. The Pandora uses a different audio setup to all the other OMAP boards, so to keep things simple the implementation is kept in its own file seperate from the main one.
  s/KbdMatrix, hdr/StaticWS - Implemented Pandora boot-time keyboard scan. This uses the keyboard matrix & GPIO keys instead of the USB libraries.
  s/Boot - Moved call to Audio_Init into the per-board HAL_InitDevices code so that Pandora can call PandoraAudio_Init instead.
  s/SDIO - For MMC1, avoid touching VSIM if the bus width is only 4 bits (i.e. on Pandora). On Pandora VSIM is used for the audio DAC instead.
Admin:
  Tested on Pandora


Version 0.81. Tagged as 'OMAP3-0_81'
---
 Makefile     |   2 +-
 VersionASM   |  12 +-
 VersionNum   |  20 +-
 hdr/StaticWS |   2 +
 s/Boot       |   7 +-
 s/KbdMatrix  | 152 +++++++++++++-
 s/PAudio     | 569 +++++++++++++++++++++++++++++++++++++++++++++++++++
 s/SDIO       |  18 ++
 8 files changed, 759 insertions(+), 23 deletions(-)
 create mode 100644 s/PAudio

diff --git a/Makefile b/Makefile
index c3e8d92..1866814 100644
--- a/Makefile
+++ b/Makefile
@@ -17,7 +17,7 @@
 
 COMPONENT = OMAP-3 HAL
 TARGET = OMAP3
-OBJS = Top Boot Interrupts Timers CLib CLibAsm Stubs UART Debug PRCM Video USB I2C RTC SDMA TPS Audio GPIO GPMC NIC NVMemory CPUClk KbdScan SR37x SDIO KbdMatrix
+OBJS = Top Boot Interrupts Timers CLib CLibAsm Stubs UART Debug PRCM Video USB I2C RTC SDMA TPS Audio GPIO GPMC NIC NVMemory CPUClk KbdScan SR37x SDIO KbdMatrix PAudio
 USBDIR = <Lib$Dir>.USB
 
 HDRS =
diff --git a/VersionASM b/VersionASM
index 0fdbed6..8a8d072 100644
--- a/VersionASM
+++ b/VersionASM
@@ -11,13 +11,13 @@
                         GBLS    Module_HelpVersion
                         GBLS    Module_ComponentName
                         GBLS    Module_ComponentPath
-Module_MajorVersion     SETS    "0.80"
-Module_Version          SETA    80
+Module_MajorVersion     SETS    "0.81"
+Module_Version          SETA    81
 Module_MinorVersion     SETS    ""
-Module_Date             SETS    "23 Sep 2012"
-Module_ApplicationDate  SETS    "23-Sep-12"
+Module_Date             SETS    "30 Sep 2012"
+Module_ApplicationDate  SETS    "30-Sep-12"
 Module_ComponentName    SETS    "OMAP3"
 Module_ComponentPath    SETS    "castle/RiscOS/Sources/HAL/OMAP3"
-Module_FullVersion      SETS    "0.80"
-Module_HelpVersion      SETS    "0.80 (23 Sep 2012)"
+Module_FullVersion      SETS    "0.81"
+Module_HelpVersion      SETS    "0.81 (30 Sep 2012)"
                         END
diff --git a/VersionNum b/VersionNum
index 2cf90f5..552873f 100644
--- a/VersionNum
+++ b/VersionNum
@@ -1,23 +1,23 @@
-/* (0.80)
+/* (0.81)
  *
  * This file is automatically maintained by srccommit, do not edit manually.
  * Last processed by srccommit version: 1.1.
  *
  */
-#define Module_MajorVersion_CMHG        0.80
+#define Module_MajorVersion_CMHG        0.81
 #define Module_MinorVersion_CMHG        
-#define Module_Date_CMHG                23 Sep 2012
+#define Module_Date_CMHG                30 Sep 2012
 
-#define Module_MajorVersion             "0.80"
-#define Module_Version                  80
+#define Module_MajorVersion             "0.81"
+#define Module_Version                  81
 #define Module_MinorVersion             ""
-#define Module_Date                     "23 Sep 2012"
+#define Module_Date                     "30 Sep 2012"
 
-#define Module_ApplicationDate          "23-Sep-12"
+#define Module_ApplicationDate          "30-Sep-12"
 
 #define Module_ComponentName            "OMAP3"
 #define Module_ComponentPath            "castle/RiscOS/Sources/HAL/OMAP3"
 
-#define Module_FullVersion              "0.80"
-#define Module_HelpVersion              "0.80 (23 Sep 2012)"
-#define Module_LibraryVersionInfo       "0:80"
+#define Module_FullVersion              "0.81"
+#define Module_HelpVersion              "0.81 (30 Sep 2012)"
+#define Module_LibraryVersionInfo       "0:81"
diff --git a/hdr/StaticWS b/hdr/StaticWS
index 804862d..96827e3 100644
--- a/hdr/StaticWS
+++ b/hdr/StaticWS
@@ -87,6 +87,8 @@ NCNBWorkspace   #       4 ; Base of ncnb workspace
 NCNBAllocNext   #       4 ; next free address in ncnb workspace
 
 DMAPktSz_Audio  #       4 ; DMA packet size to use for audio transfers (McBSP2 TX)
+KbdMatrixScan   #       4 ; Scan results for boot-time keyboard matrix scanning
+KbdMatrixTime   #       4 ; Start time of boot-time keyboard matrix scanning
 
 USBHAL_WS       #       USBHAL_WS_Size ; USB workspace for keyboard scan
 
diff --git a/s/Boot b/s/Boot
index c7cb243..e763db4 100644
--- a/s/Boot
+++ b/s/Boot
@@ -163,6 +163,7 @@ HALdescriptor   DATA
         IMPORT   SDMA_Init
         IMPORT   VideoDevice_Init
         IMPORT   Audio_Init
+        IMPORT   PandoraAudio_Init
         IMPORT   GPMC_Init
         IMPORT   NIC_Init
         IMPORT   NIC_GPMC_Config_IGEP
@@ -1026,15 +1027,16 @@ HAL_InitDevices
         BL      RTC_Init
         BL      SDMA_Init
         BL      VideoDevice_Init
-        BL      Audio_Init
         ; Board-specific HAL devices
         LDR     pc, [sb, #BoardConfig_InitDevices]
         ; EVM & touchbook don't have any extra devices
 Board_InitDevices_OMAP35xEVM
 Board_InitDevices_TouchBook
+        BL      Audio_Init
         EXIT
 
 Board_InitDevices_Pandora
+        BL      PandoraAudio_Init
         MOV     a1, #GPIOType_OMAP3_Pandora
         MOV     a2, #0 ; no boards variants for Pandora (yet?)
         BL      SDIO_InitDevices
@@ -1043,6 +1045,7 @@ Board_InitDevices_Pandora
         EXIT
 
 Board_InitDevices_IGEPv2
+        BL      Audio_Init
         ; SMSC NIC on GPMC CS 5, GPIO IRQ 176
         MOV     a1, #5
         ADRL    a2, NIC_GPMC_Config_IGEP
@@ -1080,6 +1083,7 @@ Board_InitDevices_IGEPv2
         EXIT
 
 Board_InitDevices_DevKit8000
+        BL      Audio_Init
         ; DM9000 on GPMC 6, GPIO IRQ 25
         MOV     a1, #6
         ADRL    a2, NIC_GPMC_Config_DevKit
@@ -1098,6 +1102,7 @@ Board_InitDevices_DevKit8000
         EXIT
 
 Board_InitDevices_BeagleBoard
+        BL      Audio_Init
         ; Determine board revision for GPIO device
         ; HAL_Init will have set everything up already, so we can just read the pins
         LDR     v1, L4_GPIO_Table+4*(171>>5)
diff --git a/s/KbdMatrix b/s/KbdMatrix
index 7c17da3..984eb13 100644
--- a/s/KbdMatrix
+++ b/s/KbdMatrix
@@ -27,6 +27,8 @@
         GET     hdr.omap3530
         GET     hdr.StaticWS
         GET     hdr.UART
+        GET     hdr.GPIO
+        GET     hdr.PRCM
 
         AREA    |Asm$$Code|, CODE, READONLY, PIC
 
@@ -35,12 +37,152 @@
         EXPORT  Pandora_KbdScanFinish
         EXPORT  Pandora_KbdScanInterrupt
         EXPORT  PandoraKB_Init
+        IMPORT  TPSRead
+        IMPORT  TPSWrite
 
-; TODO - Pandora keyboard scan code
-; For now just skip the scan
-Pandora_KbdScan
-        MOV     a1, #KbdFlag_Done
-Pandora_KbdScanSetup
+KEYPAD_IIC * &4A*2
+
+; IIC registers, just the interesting ones
+KEYP_CTRL_REG   * &D2
+KEY_DEB_REG     * &D3
+LK_PTV_REG      * &D5
+TIME_OUT_REG1   * &D6
+TIME_OUT_REG2   * &D7
+FULL_CODE       * &DB ; 8 registers
+KEYP_EDR        * &E8
+KEYP_SIH_CTRL   * &E9
+
+; Register bits
+KEYP_CTRL_REG_SOFT_NRST       * &01
+KEYP_CTRL_REG_SOFTMODEN       * &02
+KEYP_CTRL_REG_LK_EN           * &04
+KEYP_CTRL_REG_TOE_EN          * &08
+KEYP_CTRL_REG_TOLE_EN         * &10
+KEYP_CTRL_REG_RP_EN           * &20
+KEYP_CTRL_REG_KBD_ON          * &40
+
+KEYP_EDR_ITKPFALLING          * &01
+KEYP_EDR_ITKPRISING           * &02
+KEYP_EDR_ITLKFALLING          * &04
+KEYP_EDR_ITLKRISING           * &08
+KEYP_EDR_ITTOFALLING          * &10
+KEYP_EDR_ITTORISING           * &20
+KEYP_EDR_ITMISFALLING         * &40
+KEYP_EDR_ITMISRISING          * &80
+
+KEYP_SIH_CTRL_EXCLEN          * &01
+KEYP_SIH_CTRL_PENDDIS         * &02
+KEYP_SIH_CTRL_COR             * &04
+
+Pandora_GPIO_Ctrl * 104
+Pandora_GPIO_Copy * 111 ; B button on gamepad; default mapping is for A/B/X/Y to be home/end/page down/page up
+
+; Pandora keyboard scan code
+Pandora_KbdScanSetup ROUT
+        Entry   "v1,v2"
+        ; Set required GPIOs as input
+        GPIO_PrepareC a1,a2,Pandora_GPIO_Ctrl
+        GPIO_SetAsInput a1,a2,a3
+        GPIO_PrepareC a1,a2,Pandora_GPIO_Copy
+        GPIO_SetAsInput a1,a2,a3
+        ; Set up keyboard matrix controller
+        ADR     a2, init_data
+        MOV     a3, #1
+        LDR     v1, OSentries + 4*OS_IICOpV
+10
+        LDRB    a4, [a2], #1
+        CMP     a4, #0
+        EXIT    EQ
+        MOV     a1, #KEYPAD_IIC
+        BL      TPSWrite
+        ADD     a2, a2, #1
+        B       %BT10
+init_data
+        DCB     KEYP_CTRL_REG
+        DCB     KEYP_CTRL_REG_SOFT_NRST + KEYP_CTRL_REG_SOFTMODEN + KEYP_CTRL_REG_TOE_EN + KEYP_CTRL_REG_KBD_ON
+        DCB     KEYP_EDR
+        DCB     KEYP_EDR_ITKPFALLING + KEYP_EDR_ITKPRISING + KEYP_EDR_ITTORISING
+        DCB     LK_PTV_REG
+        DCB     4<<5
+        DCB     KEY_DEB_REG
+        DCB     20
+        DCB     TIME_OUT_REG1
+        DCB     100
+        DCB     TIME_OUT_REG2
+        DCB     0
+        DCB     KEYP_SIH_CTRL
+        DCB     KEYP_SIH_CTRL_PENDDIS + KEYP_SIH_CTRL_COR
+        ; Terminator
+        DCB     0
+
+; Keys needed for keyboard scanning
+        MACRO
+        MatrixKey $row,$col,$key
+        DCB     $row
+        DCB     1<<$col
+        DCB     KbdFlag_$key
+        MEND
+
+PandoraKeys
+;        MatrixKey ,,Ctrl - Not on keyboard, GPIO 104
+        MatrixKey 7,3,Shift
+        MatrixKey 4,2,R
+        MatrixKey 3,2,T
+        MatrixKey 2,0,Delete
+;        MatrixKey ,,Copy - No copy/end key, but default gamepad mapping is for B (GPIO 111) to act as end
+        DCB     255
+        ALIGN
+
+Pandora_KbdScan ROUT
+        Entry   "v1-v2",8
+        ; Update scan results
+        LDR     v2, KbdMatrixScan
+        ORR     v2, v2, #KbdFlag_Present
+        GPIO_PrepareC a1,a2,Pandora_GPIO_Ctrl
+        GPIO_GetInput a1,a1,a2
+        TEQ     a1, #0 ; Most gamepad controls are active low
+        ORREQ   v2, v2, #KbdFlag_Ctrl
+        GPIO_PrepareC a1,a2,Pandora_GPIO_Copy
+        GPIO_GetInput a1,a1,a2
+        TEQ     a1, #0 ; Most gamepad controls are active low
+        ORREQ   v2, v2, #KbdFlag_Copy
+        ; Check keyboard matrix
+        MOV     a1, #KEYPAD_IIC
+        MOV     a2, sp
+        MOV     a3, #8
+        MOV     a4, #FULL_CODE
+        LDR     v1, OSentries + 4*OS_IICOpV
+        BL      TPSRead
+        CMP     a1, #0
+        BNE     %FT20
+        ADR     a1, PandoraKeys
+10
+        LDRB    a2, [a1], #1
+        CMP     a2, #255
+        BEQ     %FT20
+        LDRB    a3, [a1], #1
+        LDRB    a4, [a1], #1
+        LDRB    a2, [sp, a2]
+        TST     a2, a3
+        ORRNE   v2, v2, a4
+        B       %BT10
+20
+        ; We know the keyboard is present, so only do a 1 second scan instead of a full 5 second one (or however long RISC OS decides to run it for)
+        ; We'll use the 32K timer as our time source since it's easy to get hold of
+        LDR     a1, L4_32KTIMER_Log
+        LDR     a1, [a1, #REG_32KSYNCNT_CR]
+        LDR     a2, KbdMatrixTime
+        ; Timing starts from the first call to KbdScan
+        CMP     a2, #0
+        ADDEQ   a2, a1, #32768
+        STREQ   a2, KbdMatrixTime
+        SUBS    a1, a1, a2
+        ORRGE   v2, v2, #KbdFlag_Done
+        STR     v2, KbdMatrixScan
+        MOV     a1, v2
+        EXIT
+
+        ; Nothing to do for these two
 Pandora_KbdScanInterrupt
 Pandora_KbdScanFinish
         MOV     pc, lr
diff --git a/s/PAudio b/s/PAudio
new file mode 100644
index 0000000..9be5135
--- /dev/null
+++ b/s/PAudio
@@ -0,0 +1,569 @@
+; Copyright 2012 Castle Technology Ltd
+;
+; Licensed under the Apache License, Version 2.0 (the "License");
+; you may not use this file except in compliance with the License.
+; You may obtain a copy of the License at
+;
+;     http://www.apache.org/licenses/LICENSE-2.0
+;
+; Unless required by applicable law or agreed to in writing, software
+; distributed under the License is distributed on an "AS IS" BASIS,
+; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+; See the License for the specific language governing permissions and
+; limitations under the License.
+;
+
+        GET     Hdr:ListOpts
+        GET     Hdr:Macros
+        GET     Hdr:System
+        GET     Hdr:Machine.<Machine>
+        GET     Hdr:ImageSize.<ImageSize>
+        $GetIO
+
+        GET     Hdr:OSEntries
+        GET     Hdr:HALEntries
+        GET     Hdr:HALDevice
+        GET     Hdr:AudioDevice
+        GET     Hdr:MixerDevice
+        GET     Hdr:Proc
+
+        GET     hdr.omap3530
+        GET     hdr.StaticWS
+        GET     hdr.PRCM
+        GET     hdr.GPIO
+
+        AREA    |Asm$$Code|, CODE, READONLY, PIC
+
+        EXPORT  PandoraAudio_Init
+
+        IMPORT  TPSRead
+        IMPORT  TPSWrite
+
+        IMPORT  memcpy
+        IMPORT  DebugHALPrint
+        IMPORT  DebugHALPrintReg
+        IMPORT  HAL_IRQClear
+        IMPORT  HAL_CounterDelay
+
+        MACRO
+        CallOS  $entry
+        ASSERT  $entry <= HighestOSEntry
+        MOV     lr, pc
+        LDR     pc, OSentries + 4*$entry
+        MEND
+
+; Pandora audio driver
+;
+; The Pandora is different to the other OMAP boards. Instead of having the TPS connected to McBSP2 and using it for both input and output, things are set up as follows:
+; * McBSP2 is used for audio output and is connected to a PCM1773
+; * McBSP4 is used for audio input and is connected to the TPS
+; * McBSP2 produces the bit clock that's sent to the PCM1773
+; * The TPS produces the Fs*256 clock that's sent to the PCM1773
+; * The Fs*256 clock is also sent to the McBSP2, and is used for the source of the bit clock
+; The PCM1773 is a fairly dumb DAC, unlike its bigger brother the PCM1772. This means we don't have any hardware mixing controls available for audio output.
+; Since audio input on RISC OS is still a work-in-progress, this means that we can ignore McBSP4 and skip creating a mixer device. We only need minimal TPS code to set up the correct Fs*256 clock, and the code necessary for driving McBSP2 as a clock master instead of slave.
+
+PCM1773_POWER_GPIO * 118
+AMP_POWER_GPIO * 14
+
+; Flag to enable gobs of debug output
+            GBLL    AudioDebug
+AudioDebug  SETL    {FALSE}
+
+PandoraAudio_Init
+        Push    "v1-v4,lr"
+ [ AudioDebug
+        DebugTX "Audio_Init"
+ ]
+        ADRL    v1, AudioWS
+        MOV     a1, v1
+        ADR     a2, AudioTemplate
+        MOV     a3, #Audio_DeviceSize
+        BL      memcpy
+        STR     sb, [v1, #:INDEX:AudioWorkspace]
+        ; Make sure PCM1773 + amplifier are off
+        GPIO_PrepareC a1, a2, AMP_POWER_GPIO
+        GPIO_SetAsOutput a1, a2, a3
+        GPIO_SetOutput0 a1, a2
+        MOV     a1, #1000
+        BL      HAL_CounterDelay
+        GPIO_PrepareC a1, a2, PCM1773_POWER_GPIO
+        GPIO_SetAsOutput a1, a2, a3
+        GPIO_SetOutput0 a1, a2
+        ; Get McBSP2 logical address
+        LDR     v2, L4_Per_Log
+        ADD     v2, v2, #L4_McBSP2-L4_Per
+        STR     v2, [v1, #:INDEX:AudioRegs]
+ [ AudioDebug
+        DebugReg v2, "McBSP2 @ "
+ ]
+
+        ; Before we go any further, turn on the power to McBSP2 & make sure it's in a reset state
+        ; TODO - This should probably go in AudioActivate!
+        LDR     a1, L4_ClockMan_Log
+        ADD     a1, a1, #CM_FCLKEN_PER
+        LDR     a2, [a1]
+        ORR     a2, a2, #1 ; McBSP2 clock enable
+        STR     a2, [a1]
+        LDR     a2, [a1, #CM_ICLKEN_PER-CM_FCLKEN_PER]!
+        ORR     a2, a2, #1
+        STR     a2, [a1]
+        ; CONTROL_DEVCONF0: McBSP2 gets its clock from McBSP_CLKS
+        LDR     a1, L4_Core_Log
+        ADD     a1, a1, #&2200
+        LDR     a2, [a1, #&74]
+        ORR     a2, a2, #1<<6
+        STR     a2, [a1, #&74]
+        ; Set McBSP2 to reset state
+        MOV     a1, #0
+        STR     a1, [v2, #MCBSPLP_SPCR1]
+        MOV     a1, #&200
+        STR     a1, [v2, #MCBSPLP_SPCR2]
+        ; Perform full reset, in fact
+        MOV     a1, #2
+        STR     a1, [v2, #MCBSPLP_SYSCONFIG]
+10
+        LDR     a1, [v2, #MCBSPLP_SYSCONFIG]
+        TST     a1, #2
+        BNE     %BT10
+        ; Set smart idle mode. No auto-idle available! :(
+        MOV     a1, #2<<3
+        STR     a1, [v2, #MCBSPLP_SYSCONFIG]
+        ; One-time setup of transmitter registers
+        LDR     a1, =&0F0F ; Active-low RX/TX frame sync, RX on rising, TX on falling, clocks in master mode
+        STR     a1, [v2, #MCBSPLP_PCR]
+        MOV     a1, #&40 ; 16bit words, 1 word per frame
+        STR     a1, [v2, #MCBSPLP_XCR1]
+        LDR     a1, =&8041 ; dual-phase frame, (16 bit, 1 word), MSB first, 1-bit delay
+        STR     a1, [v2, #MCBSPLP_XCR2]
+        ; Program sample rate generator registers
+        LDR     a1, =&f07 ; 16 bit frame width-1, CLKGDV=7. Fs*256/(CLKGDV+1) = 2*16 bits per Fs
+        STR     a1, [v2, #MCBSPLP_SRGR1]
+        LDR     a1, =&101f ; FPER=2*16 bit-1, SRG drives TX frame sync
+        STR     a1, [v2, #MCBSPLP_SRGR2]
+
+        ; Register audio device
+        MOV     a2, v1
+        MOV     a1, #0
+        CallOS  OS_AddDevice
+
+        ; Set TPS audio registers to default values
+        MOV     a1, #TPSAUDIO_IIC*2
+        ADR     a2, TPSDefaults
+        MOV     a3, #1 ; Program CODEC_MODE first to make sure the power is off, then program everything else in one go
+        MOV     a4, #CODEC_MODE
+        LDR     v1, OSentries+4*OS_IICOpV
+        BL      TPSWrite
+ [ AudioDebug
+        CMP     a1, #0
+        BEQ     %FT10
+        DebugTX "Audio_Init: TPS CODEC_MODE reset failed!"
+10
+ ]
+        MOV     a1, #TPSAUDIO_IIC*2
+        ADD     a2, a2, #1
+        MOV     a3, #(MISC_SET_2+1)-OPTION
+        ADD     a4, a4, #1
+        BL      TPSWrite
+ [ AudioDebug
+        CMP     a1, #0
+        BEQ     %FT10
+        DebugTX "Audio_Init: TPS audio reset failed!"
+10
+ ]
+        ; Write APLL_CTL with the right value
+        MOV     a1, #TPSAUDIO_IIC*2
+        ADD     a2, sb, #BoardConfig_APLL_CTL
+        MOV     a3, #1
+        MOV     a4, #APLL_CTL
+        BL      TPSWrite
+ [ AudioDebug
+        CMP     a1, #0
+        BEQ     %FT10
+        DebugTX "Audio_Init: APLL_CTL write failed!"
+10
+ ]
+
+ [ AudioDebug
+        DebugTX "Audio_Init done"
+ ]
+        Pull    "v1-v4,pc"
+
+TPSDefaults ; List of default settings for TPS registers
+        ; These are based around the standard settings from s.Audio, then tweaked for the Pandora
+        DCB &00 ; CODEC_MODE
+        DCB &C3 ; OPTION - RX path 2 & TX path 1 enabled
+        DCB &00 ; (unused)
+        DCB &00 ; MCBIAS_CTL
+        DCB &00 ; ANAMICL - linux has 01
+        DCB &00 ; ANAMICR
+        DCB &00 ; AVADC_CTL
+        DCB &00 ; ADCMICSEL
+        DCB &00 ; DIGMIXING
+        DCB &00 ; ATXL1PGA
+        DCB &00 ; ATXR1PGA
+        DCB &00 ; ATXL2PGA
+        DCB &00 ; AVTXR2PGA
+        DCB &82 ; AUDIO_IF - slave mode with Fs*256 output
+        DCB &00 ; VOICE_IF
+        DCB &00 ; ARXR1PGA mute
+        DCB &00 ; ARXL1PGA mute
+        DCB &00 ; ARXR2PGA mute
+        DCB &00 ; ARXL2PGA mute
+        DCB &00 ; VRXPGA
+        DCB &00 ; VSTPGA
+        DCB &00 ; VRX2ARXPGA
+        DCB &00 ; AVDAC_CTL
+        DCB &00 ; ARX2VTXPGA
+        DCB &30 ; ARXL1_APGA_CTL mute
+        DCB &30 ; ARXR1_APGA_CTL mute
+        DCB &30 ; ARXL2_APGA_CTL mute
+        DCB &30 ; ARXR2_APGA_CTL mute
+        DCB &00 ; ATX2ARXPGA
+        DCB &00 ; BT_IF
+        DCB &00 ; BTPGA
+        DCB &00 ; BTSTPGA
+        DCB &00 ; EAR_CTL
+        DCB &00 ; HS_SEL
+        DCB &00 ; HS_GAIN_SET
+        DCB &00 ; HS_POPN_SET
+        DCB &00 ; PREDL_CTL
+        DCB &00 ; PREDR_CTL
+        DCB &00 ; PRECKL_CTL
+        DCB &00 ; PRECKR_CTL
+        DCB &00 ; HFL_CTL
+        DCB &00 ; HFR_CTL
+        DCB &05 ; ALC_CTL
+        DCB &00 ; ALC_SET1
+        DCB &00 ; ALC_SET2
+        DCB &00 ; BOOST_CTL
+        DCB &00 ; SOFTVOL_CTL
+        DCB &13 ; DTMF_FREQSEL
+        DCB &00 ; DTMF_TONEXT1H
+        DCB &00 ; DTMF_TONEXT1L
+        DCB &00 ; DTMF_TONEXT2H
+        DCB &00 ; DTMF_TONEXT2L
+        DCB &79 ; DTMF_TONOFF
+        DCB &11 ; DTMF_WANONOFF
+        DCB &00 ; CODEC_RX_SCRAMBLE_H
+        DCB &00 ; CODEC_RX_SCRAMBLE_M
+        DCB &00 ; CODEC_RX_SCRAMBLE_L
+        DCB &00 ; APLL_CTL - gets filled in properly afterwards
+        DCB &00 ; DTMF_CTL
+        DCB &00 ; DTMF_PGA_CTL2
+        DCB &00 ; DTMF_PGA_CTL1
+        DCB &02 ; MISC_SET_1
+        DCB &00 ; PCMBTMUX
+        DCB &00 ; (unused)
+        DCB &00 ; (unused)
+        DCB &00 ; (unused)
+        DCB &00 ; RX_PATH_SEL
+        DCB &00 ; VDL_APGA_CTL
+        DCB &00 ; VIBRA_CTL
+        DCB &00 ; VIBRA_SET
+        DCB &00 ; (unused)
+        DCB &00 ; ANAMIC_GAIN
+        DCB &00 ; MISC_SET_2
+
+        ASSERT (. - TPSDefaults) = (MISC_SET_2+1)-CODEC_MODE
+
+        ALIGN
+
+; Sample rate table
+; The first 'reserved' byte is used to store the value that needs programming into the TPS CODEC_MODE register
+
+        GBLA    numrate
+numrate SETA    0
+
+        MACRO
+$lab    cdf     $freq, $per, $mode      ; CD-derived rate ($freq in Hz, since all integral)
+$lab    DCD     $freq*1024              ; frequency value as reported by Sound_SampleRate
+        DCB     $per                    ; period as reported via Sound_Configure
+        DCB     $mode                   ; CODEC_MODE setting
+        DCW     0                       ; padding to 8 bytes
+numrate SETA    numrate+1
+        MEND
+
+        ASSERT  HALDevice_AudioRateTableSize = 8
+
+ratetab cdf     8000, 125, &00          ;  8kHz     (125usec)  AC97/6
+        cdf     11025, 91, &10          ; 11.025kHz (~91 usec) CD/4
+        cdf     12000, 83, &20          ; 12kHz     (~83 usec) AC97/4
+        cdf     16000, 63, &40          ; 16kHz     (~63 usec) AC97/3
+        cdf     22050, 45, &50          ; 22.05kHz  (~45 usec) CD/2
+        cdf     24000, 42, &60          ; 24kHz     (~42 usec) AC97/2
+        cdf     32000, 31, &80          ; 32kHz     (~31 usec) AC97*2/3
+        cdf     44100, 23, &90          ; 44.1kHz   (~23 usec) CD/1
+        cdf     48000, 21, &a0          ; 48kHz     (~21 usec) AC97/1
+
+; Audio controller HAL device
+
+AudioTemplate
+        DCW     HALDeviceType_Audio + HALDeviceAudio_AudC
+        DCW     HALDeviceID_AudC_Pandora
+        DCD     HALDeviceBus_Ser + HALDeviceSerBus_IIC
+        DCD     1:SHL:16        ; API version
+        DCD     AudioDesc
+        DCD     0               ; Address - N/A
+        %       12              ; Reserved
+        DCD     AudioActivate
+        DCD     AudioDeactivate
+        DCD     AudioReset
+        DCD     AudioSleep
+        DCD     McBSP2_IRQ      ; Device
+        DCD     0               ; TestIRQ cannot be called
+        %       8
+        DCD     0               ; No mixer device
+        DCD     1               ; Output channels (supported so far)
+        DCD     0               ; Input channels (supported so far)
+        ASSERT  (.-AudioTemplate) = HALDevice_Audio_Size
+        ; DMA channel parameters
+        DCD     0 ; flags
+        DCD     McBSP2_DMA_TX + 1 ; logical channel
+        DCD     0 ; 'cycle speed'
+        DCD     2 ; transfer unit size
+        DCD     L4_McBSP2+MCBSPLP_DXR ; *physical* address to send data to
+        ; Enable/disable/IRQ routines
+        DCD     PreEnable
+        DCD     PostEnable
+        DCD     PreDisable
+        DCD     PostDisable
+        DCD     IRQHandle
+        DCD     numrate         ; Number of sample rates
+        DCD     ratetab         ; Sample rate table
+        DCD     AudioSetRate    ; SetRate function
+        ASSERT  (.-AudioTemplate) = HALDevice_Audio_Size_1
+        DCD     0               ; Filled in during init
+        DCD     0               ; Filled in during init
+        DCD     0
+        ALIGN
+
+        ASSERT  (.-AudioTemplate) = Audio_DeviceSize
+
+AudioDesc
+        =       "Pandora audio controller", 0
+        ALIGN
+
+AudioActivate
+        MOV     a1, #1
+        MOV     pc, lr
+
+AudioDeactivate
+        MOV     pc, lr
+
+AudioReset
+        MOV     pc, lr
+
+AudioSleep
+        MOV     a1, #0
+        MOV     pc, lr
+
+SetCodecMode
+        ; Reprogram CODEC_MODE from softcopy
+        ; Assumes a1=audio device ptr, sb=HAL workspace
+        Entry   "a1-a4,v1"
+        ADR     a2, AudioMode
+        MOV     a1, #TPSAUDIO_IIC*2
+        MOV     a3, #1
+        MOV     a4, #CODEC_MODE
+        LDR     v1, OSentries+4*OS_IICOpV
+        BL      TPSWrite
+ [ AudioDebug
+        CMP     a1, #0
+        EXIT EQ
+        DebugTX "SetCodecMode: TPS write failed!"
+ ]
+        EXIT
+
+PreEnable
+        ; a2 = DMA buffer length
+        ; Use the buffer length to calculate a DMA packet size that fits in the FIFO.
+        LDR     a3, AudioWorkspace
+        MOV     a4, #1
+10
+        MOV     a2, a2, LSR #1 ; Number of DMA elements/FIFO entries
+        CMP     a2, #&200 ; FIFO size is &500. To try and avoid underflow, try to make sure there's no more than &200 free entries.
+        STRLE   a2, [a3, #:INDEX:DMAPktSz_Audio]
+        MOVLE   pc, lr
+        ; Divide size by two until we reach our goal
+        TST     a2, #1
+        MOVEQ   a4, a4, LSL #1
+        BEQ     %BT10
+        ; If we're here, it means we can't divide any more, and we're still stuck with a large transfer size.
+        ; For RISC OS, the largest non-fittable size is 4K-4, which will result in a2=&3FF and a4=2
+        ; Since &3FF is smaller than the FIFO size we'll make an exception to our above rule and allow it to be used
+        ; But to future-proof ourselves against buffers larger than 4K we'll fall back to using a4 if needed. Transferring only two elements at a time will hurt the memory bus a bit, but at least it'll work!
+        CMP     a2, #&400
+        STRLE   a2, [a3, #:INDEX:DMAPktSz_Audio]
+        STRGT   a4, [a3, #:INDEX:DMAPktSz_Audio]
+        MOV     pc, lr
+
+PostEnable
+        ; a2 = DMA buffer length
+        ; This function is a mix of two things - the TPS programming steps from section 14.5.3 of the manual (swcu050d.pdf, page 715/716), and the McBSP programming steps
+        ; The steps for both have been stripped down to the bare minimum that are required for (re)initialisation.
+        ; The McBSP instance is initialised first, to allow the DMA to prefill the TX FIFO. The TWL/TPS is then initialised afterwards.
+        Entry   "v1-v3,sb"
+        LDR     sb, AudioWorkspace
+ [ AudioDebug
+        DebugTX "PostEnable"
+ ]
+        Push    "a1"
+        LDR     v1, AudioRegs
+        ; Set McBSP instance to reset state (although it should be reset already)
+        MOV     a1, #0
+        STR     a1, [v1, #MCBSPLP_SPCR1]
+        MOV     a1, #&200
+        STR     a1, [v1, #MCBSPLP_SPCR2]
+        ; Reset IRQ state, and enable underflow/overflow IRQ
+        MVN     a1, #0
+        STR     a1, [v1, #MCBSPLP_IRQSTATUS]
+        MOV     a1, #&1800
+        STR     a1, [v1, #MCBSPLP_IRQENABLE]
+        ; Program FIFO threshold value, using our precomputed packet size
+        LDR     a2, DMAPktSz_Audio
+ [ AudioDebug
+        DebugReg a2, "Packet size="
+ ]
+        SUB     a2, a2, #1
+        STR     a2, [v1, #MCBSPLP_THRSH2] ; Threshold = number of 16bit samples that SDMA sends, minus one. Any other value is wrong and will cause audio corruption.
+        ; Wait 2 SRG clock cycles
+        ; For now, just wait for a msec or so
+        MOV     a1, #1024
+        BL      HAL_CounterDelay
+        ; Bring sample rate generator out of reset (required even with external clocks)
+        MOV     v2, #&240
+        STR     v2, [v1, #MCBSPLP_SPCR2]
+        ; Bring transmitter out of reset
+        ORR     v2, v2, #1
+        STR     v2, [v1, #MCBSPLP_SPCR2]
+        ; Wait some more, according to linux
+        MOV     a1, #1024
+        BL      HAL_CounterDelay
+        Pull    "a1"
+        ; Now start frame sync
+        ORR     v2, v2, #&80
+        STR     v2, [v1, #MCBSPLP_SPCR2]
+        ; Wait for FIFO to fill by DMA
+        LDR     v3, DMAPktSz_Audio
+        ; Use the 32K timer to provide a clock reference for a timeout (in
+        ; case DMA isn't running for some reason, e.g. DMAManager being
+        ; naughty and sneakily resetting it during Service_PreReset)
+        LDR     v2, L4_32KTIMER_Log
+        LDR     a3, [v2, #REG_32KSYNCNT_CR]
+10
+        LDR     a2, [v1, #MCBSPLP_XBUFFSTAT]
+        CMP     a2, v3
+        BLE     %FT20
+        LDR     ip, [v2, #REG_32KSYNCNT_CR]
+        SUB     ip, ip, a3
+        CMP     ip, #16384 ; Half a second should be more than enough
+        BLO     %BT10
+ [ AudioDebug
+        DebugTX "FIFO fill timeout!"
+ ]
+        ; Since timeouts shouldn't happen, I don't think anyone will mind if
+        ; we just bug out and don't start the audio codec
+        EXIT
+20
+ [ AudioDebug
+        DebugReg a2, "Post-prime XBUFFSTAT="
+ ]
+
+        ; TPS Step 18 - turn codec power on
+        LDR     v1, AudioMode
+        ORR     v1, v1, #2
+        STR     v1, AudioMode
+        BL      SetCodecMode
+        ; Bring PCM1773 + amplifier out of reset
+        GPIO_PrepareC a1, a2, PCM1773_POWER_GPIO
+        GPIO_SetOutput1 a1, a2
+        GPIO_PrepareC a1, a2, AMP_POWER_GPIO
+        GPIO_SetOutput1 a1, a2
+        EXIT
+
+PreDisable
+        ; Disable the DAC + AMP, TWL/TPS, and then McBSP
+        ; This should avoid unwanted underflow IRQs
+        Entry   "v1,sb"
+        LDR     sb, AudioWorkspace
+ [ AudioDebug
+        DebugTX "PreDisable"
+ ]
+        ; Disable IRQs
+        LDR     a2, AudioRegs
+        MOV     a3, #0
+        STR     a3, [a2, #MCBSPLP_IRQENABLE]
+        ; Turn PCM1773 + AMP power off
+        Push    "a1"
+        GPIO_PrepareC a1, a2, AMP_POWER_GPIO
+        GPIO_SetOutput0 a1, a2
+        MOV     a1, #1000
+        BL      HAL_CounterDelay
+        GPIO_PrepareC a1, a2, PCM1773_POWER_GPIO
+        GPIO_SetOutput0 a1, a2
+        Pull    "a1"
+        ; Turn codec power off
+        LDR     a2, AudioMode
+        BIC     a2, a2, #2
+        STR     a2, AudioMode
+        BL      SetCodecMode
+        ; Disable McBSP
+        LDR     v1, AudioRegs
+        MOV     a1, #0
+        STR     a1, [v1, #MCBSPLP_SPCR1]
+        MOV     a1, #&200
+        STR     a1, [v1, #MCBSPLP_SPCR2]
+        EXIT
+
+PostDisable
+        MOV     pc, lr
+
+IRQHandle
+ [ AudioDebug
+        Push    "sb,lr"
+        LDR     sb, AudioWorkspace
+        LDR     a2, AudioRegs
+        LDR     a2, [a2, #MCBSPLP_IRQSTATUS]
+        DebugReg a2,"IRQHandle: IRQSTATUS="
+        Pull    "sb,lr"
+ ]
+        ; Just clear the IRQ and ask for an audio reset
+        LDR     a3, AudioRegs
+        MOV     a2, #0
+        STR     a2, [a3, #MCBSPLP_IRQENABLE] ; Make sure we don't get bothered about this again - we can't guarantee when the OS will get round to resetting the audio, and could potentially get stuck in a loop if we allow the IRQ to keep firing
+        MVN     a2, #0
+        STR     a2, [a3, #MCBSPLP_IRQSTATUS]
+        MOV     a1, #1
+        MOV     pc, lr
+
+AudioSetRate
+        ; a2 = sample rate index (0-based)
+        Entry   "sb"
+        LDR     sb, AudioWorkspace
+ [ AudioDebug
+        DebugReg a2, "AudioSetRate: "
+ ]
+        ; Reload CODEC_MODE with the required value
+        ; The manual states APLL_RATE can only be changed if the codec is off!
+        ADRL    a3, ratetab
+        ASSERT  HALDevice_AudioRateTableSize = 8
+        ADD     a3, a3, a2, LSL #3
+        LDRB    a3, [a3, #5]
+        LDR     a2, AudioMode
+        CMP     a2, a3
+        EXIT EQ ; Redundant update, ignore
+        TST     a2, #2
+ [ AudioDebug
+        BEQ     %FT10
+        DebugTX "AudioSetRate: Failed, codec is active!"
+        EXIT
+10
+ |
+        EXIT NE
+ ]
+        STR     a3, AudioMode
+        BL      SetCodecMode
+        EXIT
+
+        END
diff --git a/s/SDIO b/s/SDIO
index 65085f0..2bda529 100644
--- a/s/SDIO
+++ b/s/SDIO
@@ -817,7 +817,13 @@ SetVdd ROUT ; MMC1 case
         MOV     a3, #1
         LDR     v1, OSentries+4*OS_IICOpV
         MyTPSWrite VMMC1_DEV_GRP, 0
+        ; VSIM only used with 8bit interfaces
+        LDR     ip, =:INDEX:SDIOWS+SDHCISlotInfo+HALDeviceSDHCI_SlotInfo_Flags
+        LDR     ip, [sb, ip]
+        TST     ip, #HALDeviceSDHCI_SlotFlag_Bus8Bit
+        BEQ     %FT05
         MyTPSWrite VSIM_DEV_GRP, 0
+05
 
         ; Turn off the power internal to the SD controller
         ADRL    a1, SDIOWS
@@ -839,8 +845,14 @@ SetVdd ROUT ; MMC1 case
         LDR     v1, OSentries+4*OS_IICOpV
         MyTPSWrite VMMC1_DEDICATED, VMMC1_DEDICATED_VSEL_1_85V
         MyTPSWrite VMMC1_DEV_GRP, DEV_GRP_P1
+        ; VSIM only used with 8bit interfaces
+        LDR     ip, =:INDEX:SDIOWS+SDHCISlotInfo+HALDeviceSDHCI_SlotInfo_Flags
+        LDR     ip, [sb, ip]
+        TST     ip, #HALDeviceSDHCI_SlotFlag_Bus8Bit
+        BEQ     %FT20
         MyTPSWrite VSIM_DEDICATED, VSIM_DEDICATED_VSEL_1_8V
         MyTPSWrite VSIM_DEV_GRP, DEV_GRP_P1
+20
 
         ; Turn on the power internal to the SD controller
         ADRL    a1, SDIOWS
@@ -870,8 +882,14 @@ SetVdd ROUT ; MMC1 case
         LDR     v1, OSentries+4*OS_IICOpV
         MyTPSWrite VMMC1_DEDICATED, VMMC1_DEDICATED_VSEL_3_00V
         MyTPSWrite VMMC1_DEV_GRP, DEV_GRP_P1
+        ; VSIM only used with 8bit interfaces
+        LDR     ip, =:INDEX:SDIOWS+SDHCISlotInfo+HALDeviceSDHCI_SlotInfo_Flags
+        LDR     ip, [sb, ip]
+        TST     ip, #HALDeviceSDHCI_SlotFlag_Bus8Bit
+        BEQ     %FT35
         MyTPSWrite VSIM_DEDICATED, VSIM_DEDICATED_VSEL_3_0V
         MyTPSWrite VSIM_DEV_GRP, DEV_GRP_P1
+35
 
         ; Turn on the power internal to the SD controller
         ADRL    a1, SDIOWS
-- 
GitLab