; ; Copyright (c) 2012, RISC OS Open Ltd ; All rights reserved. ; ; Redistribution and use in source and binary forms, with or without ; modification, are permitted provided that the following conditions are met: ; * Redistributions of source code must retain the above copyright ; notice, this list of conditions and the following disclaimer. ; * Redistributions in binary form must reproduce the above copyright ; notice, this list of conditions and the following disclaimer in the ; documentation and/or other materials provided with the distribution. ; * Neither the name of RISC OS Open Ltd nor the names of its contributors ; may be used to endorse or promote products derived from this software ; without specific prior written permission. ; ; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" ; AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ; IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ; ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE ; LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR ; CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF ; SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ; INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN ; CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ; ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE ; POSSIBILITY OF SUCH DAMAGE. ; EXPORT SDIO_InitDevices IMPORT memcpy IMPORT TPSRead IMPORT TPSWrite IMPORT HAL_CounterDelay ; KEEP ; for debugging GET Hdr:ListOpts GET Hdr:Macros GET Hdr:OSEntries GET hdr.omap3530 GET hdr.GPIO GET hdr.StaticWS sb RN 9 ; Timings ; Maximum time bus power is allowed to take to ramp up or down. ; MMC and SD agree this is 35 ms max ramp up, but nothing is said about ramp down so I'm assuming it's the same. BUS_POWER_RAMP * 35000 ; in us ; Number of reads of SYSSTATUS before we give up waiting for reset to complete RESET_TIMEOUT * 100 ; Number of reads of SYSCTL before we give up waiting for SDCLK to stabilise CLOCKSET_TIMEOUT * 1000 ; Time to leave initialisation procedure to execute INIT_PROCEDURE_TIME * 1000 ; in us ; Frequency of the clock which we divide to produce SDCLK FCLK_FREQ * 96000 ; in kHz ; Physical addresses of pin mux registers L4_PadConf_GPIO23 * L4_Core + 0x25EE L4_PadConf_GPIO26 * L4_Core + 0x25F4 L4_PadConf_GPIO27 * L4_Core + 0x25F6 L4_PadConf_GPIO29 * L4_Core + 0x25FA L4_PadConf_GPIO126 * L4_Core + 0x2150 L4_PadConf_GPIO127 * L4_Core + 0x2152 L4_PadConf_GPIO128 * L4_Core + 0x2154 L4_PadConf_GPIO129 * L4_Core + 0x2156 L4_PadConf_GPIO130 * L4_Core + 0x2158 L4_PadConf_GPIO131 * L4_Core + 0x215A L4_PadConf_GPIO132 * L4_Core + 0x215C L4_PadConf_GPIO133 * L4_Core + 0x215E L4_PadConf_GPIO134 * L4_Core + 0x2160 L4_PadConf_GPIO135 * L4_Core + 0x2162 L4_PadConf_GPIO136 * L4_Core + 0x2164 L4_PadConf_GPIO137 * L4_Core + 0x2166 L4_PadConf_GPIO138 * L4_Core + 0x2168 L4_PadConf_GPIO139 * L4_Core + 0x216A L4_PadConf_GPIO149 * L4_Core + 0x217E L4_PadConf_GPIO150 * L4_Core + 0x2180 L4_PadConf_GPIO163 * L4_Core + 0x219A L4_PadConf_GPIO164 * L4_Core + 0x219C ; Selected bits from PadConf registers (7.6.3 of spruf98b) PADCONF_MASK * &FFFF PADCONF_INPUTENABLE * 1 :SHL: 8 PADCONF_PULLTYPESELECT * 1 :SHL: 4 PADCONF_PULLUDENABLE * 1 :SHL: 3 PADCONF_MUXMODE_GPIO * 4 :SHL: 0 ; Bits within the PBIAS register (7.6.4.102 of spruf98b) PBIASLITESUPPLYHIGH1 * 1 :SHL: 15 PBIASLITEVMODEEROR1 * 1 :SHL: 11 PBIASLITESPEEDCTRL1 * 1 :SHL: 10 PBIASLITEPWRDNZ1 * 1 :SHL: 9 PBIASLITEVMODE1 * 1 :SHL: 8 PBIASLITESUPPLYHIGH0 * 1 :SHL: 7 PBIASLITEVMODEEROR0 * 1 :SHL: 3 PBIASLITESPEEDCTRL0 * 1 :SHL: 2 PBIASLITEPWRDNZ0 * 1 :SHL: 1 PBIASLITEVMODE0 * 1 :SHL: 0 ; Physical addresses of clock setup registers L4_ClockMan_FCLKEN1_CORE * L4_ClockMan + &A00 L4_ClockMan_ICLKEN1_CORE * L4_ClockMan + &A10 ; Bits within clock setup registers EN_MMC1 * 1 :SHL: 24 EN_MMC2 * 1 :SHL: 25 EN_MMC3 * 1 :SHL: 30 ; Physical address of DEVCONF1 register L4_Core_DEVCONF1 * L4_Core + &22D8 ; Bits within DEVCONF1 register MMCSDIO2ADPCLKISEL * 1 :SHL: 6 ; RISC OS device numbers for each controller's IRQ line MMC1_IRQ * 83 MMC2_IRQ * 86 MMC3_IRQ * 94 ; GPIO pin assignments GBLS BBREVC_WP GBLS IGEP_GREEN GBLS IGEP_RED GBLS BBREVB_WP GBLS PANDORA_WP1 GBLS PANDORA_WP2 GBLS PANDORA_LED1 GBLS PANDORA_LED2 GBLS MMC2_CLK GBLS MMC2_CMD GBLS MMC2_DAT0 GBLS MMC2_DAT1 GBLS MMC2_DAT2 GBLS MMC2_DAT3 GBLS MMC2_DIR_DAT0 GBLS MMC2_DIR_DAT1 GBLS MMC2_DIR_CMD GBLS MMC2_CLKIN GBLS BB_USER0 GBLS BB_USER1 GBLS DK_LED2 GBLS DK_LED3 BBREVC_WP SETS "23" IGEP_GREEN SETS "26" IGEP_RED SETS "27" BBREVB_WP SETS "29" ; also WP on DevKit PANDORA_WP1 SETS "126" PANDORA_WP2 SETS "127" PANDORA_LED1 SETS "128" PANDORA_LED2 SETS "129" MMC2_CLK SETS "130" MMC2_CMD SETS "131" MMC2_DAT0 SETS "132" MMC2_DAT1 SETS "133" MMC2_DAT2 SETS "134" MMC2_DAT3 SETS "135" MMC2_DIR_DAT0 SETS "136" MMC2_DIR_DAT1 SETS "137" MMC2_DIR_CMD SETS "138" MMC2_CLKIN SETS "139" BB_USER0 SETS "149" ; right LED BB_USER1 SETS "150" ; left LED DK_LED2 SETS "163" ; second-from-right LED, labelled LED2 (SYSLED3) DK_LED3 SETS "164" ; far right LED, labelled LED3 (SYSLED4) MACRO $name DeclareTPSReg $group, $offset TPSRegGroup_$name * $group TPSRegOffset_$name * $offset MEND GPIODATAIN1 DeclareTPSReg &49, &98 GPIODATADIR1 DeclareTPSReg &49, &9B GPIO_DEBEN1 DeclareTPSReg &49, &A7 GPIOCTRL DeclareTPSReg &49, &AA DCDC_GLOBAL_CFG DeclareTPSReg &4B, &61 VMMC1_DEV_GRP DeclareTPSReg &4B, &82 VMMC1_DEDICATED DeclareTPSReg &4B, &85 VMMC2_DEV_GRP DeclareTPSReg &4B, &86 VMMC2_DEDICATED DeclareTPSReg &4B, &89 VSIM_DEV_GRP DeclareTPSReg &4B, &92 VSIM_DEDICATED DeclareTPSReg &4B, &95 ; Bits in TWL4030/TPS65950 registers GPIO0IN * 1 :SHL: 0 GPIO1IN * 1 :SHL: 1 GPIOCTRL_CD1 * 1 :SHL: 0 GPIOCTRL_CD2 * 1 :SHL: 1 GPIOCTRL_ON * 1 :SHL: 2 DEV_GRP_P3 * 1 :SHL: 7 DEV_GRP_P2 * 1 :SHL: 6 DEV_GRP_P1 * 1 :SHL: 5 DEV_GRP_WARM_CFG * 1 :SHL: 4 DEV_GRP_STATE_MASK * &F :SHL: 0 VMMC1_DEDICATED_TRIEN * 1 :SHL: 6 VMMC1_DEDICATED_TRIM_MASK * 3 :SHL: 4 VMMC1_DEDICATED_VSEL_1_85V * 0 :SHL: 0 VMMC1_DEDICATED_VSEL_2_85V * 1 :SHL: 0 VMMC1_DEDICATED_VSEL_3_00V * 2 :SHL: 0 VMMC1_DEDICATED_VSEL_3_15V * 3 :SHL: 0 VMMC1_DEDICATED_VSEL_MASK * 3 :SHL: 0 VMMC2_DEDICATED_TRIEN * 1 :SHL: 6 VMMC2_DEDICATED_TRIM_MASK * 3 :SHL: 4 VMMC2_DEDICATED_VSEL_1_00V * 0 :SHL: 0 VMMC2_DEDICATED_VSEL_1_20V * 2 :SHL: 0 VMMC2_DEDICATED_VSEL_1_30V * 3 :SHL: 0 VMMC2_DEDICATED_VSEL_1_50V * 4 :SHL: 0 VMMC2_DEDICATED_VSEL_1_80V * 5 :SHL: 0 VMMC2_DEDICATED_VSEL_1_85V * 6 :SHL: 0 VMMC2_DEDICATED_VSEL_2_50V * 7 :SHL: 0 VMMC2_DEDICATED_VSEL_2_60V * 8 :SHL: 0 VMMC2_DEDICATED_VSEL_2_80V * 9 :SHL: 0 VMMC2_DEDICATED_VSEL_2_85V * &A :SHL: 0 VMMC2_DEDICATED_VSEL_3_00V * &B :SHL: 0 VMMC2_DEDICATED_VSEL_3_15V * &C :SHL: 0 VMMC2_DEDICATED_VSEL_MASK * &F :SHL: 0 VSIM_DEDICATED_TRIEN * 1 :SHL: 6 VSIM_DEDICATED_TRIM_MASK * 3 :SHL: 4 VSIM_DEDICATED_VSEL_1_0V * 0 :SHL: 0 VSIM_DEDICATED_VSEL_1_2V * 1 :SHL: 0 VSIM_DEDICATED_VSEL_1_3V * 2 :SHL: 0 VSIM_DEDICATED_VSEL_1_8V * 3 :SHL: 0 VSIM_DEDICATED_VSEL_2_8V * 4 :SHL: 0 VSIM_DEDICATED_VSEL_3_0V * 5 :SHL: 0 VSIM_DEDICATED_VSEL_MASK * 7 :SHL: 0 ; Selected SD controller registers and bits SYSCONFIG * &010 SYSCONFIG_SOFTRESET * 1:SHL:1 SYSSTATUS * &014 SYSSTATUS_RESETDONE * 1:SHL:0 CON * &02C CON_OD * 1 :SHL: 0 CON_INIT * 1 :SHL: 1 CON_DW8 * 1 :SHL: 5 CMD * &10C HCTL * &128 HCTL_DTW * 1 :SHL: 1 HCTL_SDBP * 1 :SHL: 8 HCTL_SDVS_1_8V * 5 :SHL: 9 HCTL_SDVS_3_0V * 6 :SHL: 9 SYSCTL * &12C SYSCTL_ICE * 1 :SHL: 0 SYSCTL_ICS * 1 :SHL: 1 SYSCTL_CEN * 1 :SHL: 2 SYSCTL_CLKD_SHIFT * 6 SYSCTL_CLKD_MASK * &3FF :SHL: SYSCTL_CLKD_SHIFT STAT * &130 STAT_CC * 1 :SHL: 0 CAPA * &140 CAPA_VS33 * 1:SHL:24 CAPA_VS30 * 1:SHL:25 CAPA_VS18 * 1:SHL:26 AREA |Asm$$Code|, CODE, READONLY, PIC MACRO $class HALDeviceField $field, $value LCLS myvalue [ "$value" = "" myvalue SETS "$field" | myvalue SETS "$value" ] ASSERT . - %A0 = HALDevice_$class$field [ ?HALDevice_$class$field = 2 DCW $myvalue ELIF ?HALDevice_$class$field = 4 DCD $myvalue | % ?HALDevice_$class$field ] MEND ; Template for device blocks Template 0 HALDeviceField Type, HALDeviceType_ExpCtl + HALDeviceExpCtl_SDIO HALDeviceField ID, HALDeviceID_SDIO_SDHCI HALDeviceField Location, HALDeviceBus_Interconnect + HALDeviceInterconnectBus_L4 HALDeviceField Version, 0 HALDeviceField Description HALDeviceField Address, 0 ; patched up at initialisation HALDeviceField Reserved1, 0 HALDeviceField Activate, 0 ; patched up at initialisation HALDeviceField Deactivate HALDeviceField Reset HALDeviceField Sleep HALDeviceField Device, MMC1_IRQ ; overridden in some cases HALDeviceField TestIRQ HALDeviceField ClearIRQ, 0 HALDeviceField Reserved2, 0 SDHCI HALDeviceField Flags, HALDeviceSDHCI_Flag_32bit + HALDeviceSDHCI_Flag_R2bug SDHCI HALDeviceField Slots, 1 SDHCI HALDeviceField SlotInfo, 0 ; patched up at initialisation SDHCI HALDeviceField WriteRegister, 0 SDHCI HALDeviceField GetCapabilities, 0 SDHCI HALDeviceField GetVddCapabilities, 0 ; overridden in some cases SDHCI HALDeviceField SetVdd ; overridden in some cases SDHCI HALDeviceField SetBusMode SDHCI HALDeviceField PostPowerOn SDHCI HALDeviceField SetBusWidth SDHCI HALDeviceField GetMaxCurrent ; overridden in some cases SDHCI HALDeviceField SetSDCLK SDHCI HALDeviceField GetTMCLK SDHCI HALDeviceField SetActivity, 0 ; patched up at initialisation SDHCI HALDeviceField GetCardDetect ; overridden in some cases SDHCI HALDeviceField GetWriteProtect, 0 ; patched up at initialisation ASSERT . - %A0 = SDHCISB DCD 0 ; patched up at initialisation ASSERT . - %A0 = SDHCISlotInfo + HALDeviceSDHCI_SlotInfo_Flags DCD 0 ; patched up at initialisation ASSERT . - %A0 = SDHCISlotInfo + HALDeviceSDHCI_SlotInfo_StdRegs DCD 0 ; patched up at initialisation ASSERT . - %A0 = SDHCISize ; Init the SDHCI HAL device(s) ; a1 = GPIOType value ; a2 = GPIORevision value SDIO_InitDevices ROUT Push "a1-a2,lr" MOV a3, #0 ADRL a4, SDIOWS BL InitDevice Pull "a1-a2" TEQ a1, #GPIOType_OMAP3_IGEPv2 ; IGEPv2 has 2 controllers TEQNE a1, #GPIOType_OMAP3_Pandora ; Pandora has 3 Pull "pc", NE Push "a1-a2" MOV a3, #1 ADRL a4, SDIOWS + SDHCISize BL InitDevice Pull "a1-a2" TEQ a1, #GPIOType_OMAP3_Pandora ; only Pandora uses 3 controllers Pull "pc", NE MOV a3, #2 ADRL a4, SDIOWS + 2 * SDHCISize BL InitDevice Pull "pc" ; Init one SDHCI HAL device ; a1 = GPIOType value ; a2 = GPIORevision value ; a3 = device number ; a4 -> workspace for this device InitDevice ROUT Push "a1-a4,lr" MOV a1, a4 ADR a2, Template MOV a3, #SDHCISize BL memcpy Pull "a1-a4" ; Address and SlotInfo_StdRegs LDR ip, L4_Core_Log CMP a3, #1 ADDLO lr, ip, #L4_MemCard1 - L4_Core ADDEQ lr, ip, #L4_MemCard2 - L4_Core ADDHI lr, ip, #L4_MemCard3 - L4_Core STR lr, [a4, #HALDevice_Address] ADD lr, lr, #&100 STR lr, [a4, #SDHCISlotInfo + HALDeviceSDHCI_SlotInfo_StdRegs] ; Device MOVEQ lr, #MMC2_IRQ MOVHI lr, #MMC3_IRQ STRHS lr, [a4, #HALDevice_Device] ; SlotInfo ADD lr, a4, #SDHCISlotInfo STR lr, [a4, #HALDevice_SDHCISlotInfo] ; SDHCISB STR sb, [a4, #SDHCISB] TEQEQ a1, #GPIOType_OMAP3_IGEPv2 TEQNE a3, #2 BEQ %F30 BCS %F20 ; Card slot 1 case ; ---------------- ; Activate ADR lr, Activate_MMC1_BeagleboardxM TEQ a1, #GPIOType_OMAP3_BeagleBoard TEQEQ a2, #GPIORevision_BeagleBoard_AB ADREQ lr, Activate_MMC1_BeagleboardRevB TEQ a2, #GPIORevision_BeagleBoard_C123 TEQNE a2, #GPIORevision_BeagleBoard_C4 TEQEQ a1, #GPIOType_OMAP3_BeagleBoard ADREQ lr, Activate_MMC1_BeagleboardRevC TEQ a1, #GPIOType_OMAP3_IGEPv2 ADREQ lr, Activate_MMC1_IGEPv2 TEQ a1, #GPIOType_OMAP3_DevKit8000 ADREQ lr, Activate_MMC1_DevKit8000 TEQ a1, #GPIOType_OMAP3_Pandora ADREQL lr, Activate_MMC1_Pandora STR lr, [a4, #HALDevice_Activate] ; SetActivity TEQ a1, #GPIOType_OMAP3_BeagleBoard ADREQL lr, SetActivity_Beagleboard ; LEDs are same on original and xM TEQ a1, #GPIOType_OMAP3_IGEPv2 ADREQL lr, SetActivity_IGEPv2 TEQ a1, #GPIOType_OMAP3_DevKit8000 ADREQL lr, SetActivity_DevKit8000 TEQ a1, #GPIOType_OMAP3_Pandora ADREQL lr, SetActivity_Pandora_MMC1 STR lr, [a4, #HALDevice_SDHCISetActivity] ; GetWriteProtect ADRL lr, GetWriteProtect_Unimplemented TEQ a1, #GPIOType_OMAP3_BeagleBoard TEQEQ a2, #GPIORevision_BeagleBoard_AB TEQNE a1, #GPIOType_OMAP3_DevKit8000 ADREQL lr, GetWriteProtect_BeagleboardRevB_DevKit8000 TEQ a2, #GPIORevision_BeagleBoard_C123 TEQNE a2, #GPIORevision_BeagleBoard_C4 TEQEQ a1, #GPIOType_OMAP3_BeagleBoard ADREQL lr, GetWriteProtect_BeagleboardRevC TEQ a1, #GPIOType_OMAP3_Pandora ADREQL lr, GetWriteProtect_Pandora_MMC1 STR lr, [a4, #HALDevice_SDHCIGetWriteProtect] ; SlotInfo_Flags ADRL ip, GetWriteProtect_Unimplemented TEQ lr, ip ; EQ => microSD slot TEQNE a1, #GPIOType_OMAP3_Pandora ; only 4 bits on Pandora even though full size MOVNE lr, #HALDeviceSDHCI_SlotFlag_Bus8Bit MOVEQ lr, #HALDeviceSDHCI_SlotFlag_Bus4Bit STR lr, [a4, #SDHCISlotInfo + HALDeviceSDHCI_SlotInfo_Flags] B %F40 20 ; Card slot 2 case (Pandora only) ; ------------------------------- ; Activate ADRL lr, Activate_MMC2_Pandora STR lr, [a4, #HALDevice_Activate] ; GetVddCapabilities ; Only Pandora uses an external level shifter, and only on MMC2 ADRL lr, GetVddCapabilities_Pandora_MMC2 STR lr, [a4, #HALDevice_SDHCIGetVddCapabilities] ; SetVdd ; Only MMC1 supports variable voltages in the OMAP. Without more details ; of the level shifter on Pandora MMC2 and/or some hardware to test, I'm ; reluctant to implement voltage control for it, so just treat MMC2 as ; fixed voltage in all cases (and assume the bootloader has already ; configured the voltages correctly). We do still need to turn on the ; power internal to the controller, though. ADRL lr, SetVdd_MMC2_LevelShifted STR lr, [a4, #HALDevice_SDHCISetVdd] ; GetMaxCurrent ; Pandora uses the TPS VMMC2 power rail for MMC2. ADRL lr, GetMaxCurrent_MMC2 STR lr, [a4, #HALDevice_SDHCIGetMaxCurrent] ; SetActivity ADRL lr, SetActivity_Pandora_MMC2 STR lr, [a4, #HALDevice_SDHCISetActivity] ; GetCardDetect ADRL lr, GetCardDetect_MMC2 STR lr, [a4, #HALDevice_SDHCIGetCardDetect] ; GetWriteProtect ADRL lr, GetWriteProtect_Pandora_MMC2 STR lr, [a4, #HALDevice_SDHCIGetWriteProtect] ; SlotInfo_Flags MOV lr, #HALDeviceSDHCI_SlotFlag_Bus4Bit STR lr, [a4, #SDHCISlotInfo + HALDeviceSDHCI_SlotInfo_Flags] B %F40 30 ; SDIO WiFi chip (IGEPv2 and Pandora) ; ----------------------------------- ; Activate TEQ a1, #GPIOType_OMAP3_IGEPv2 ADREQL lr, Activate_MMC2_IGEPv2 ADRNEL lr, Activate_MMC3_Pandora STR lr, [a4, #HALDevice_Activate] ; SetVdd ; There is no level shifter between the OMAP and the WiFi chip, and no ; possibility to change the voltage in the OMAP on either MMC2 or MMC3. ; Default SDHCI handler will do in this case. MOV lr, #0 STR lr, [a4, #HALDevice_SDHCISetVdd] ; GetMaxCurrent ; IGEPv2 uses a mixture of 1.8V and 3.3V supplies for its WiFi/Bluetooth ; chip on MMC2. Pandora has a WiFi chip on MMC3, though its details are ; sketchy at the moment; assume it's the same as the IGEPv2. ADRL lr, GetMaxCurrent_LBEE1USJYC STR lr, [a4, #HALDevice_SDHCIGetMaxCurrent] ; SetActivity ADR lr, NOPEntry STR lr, [a4, #HALDevice_SDHCISetActivity] ; GetCardDetect ADRL lr, GetCardDetect_NonRemovable STR lr, [a4, #HALDevice_SDHCIGetCardDetect] ; GetWriteProtect ADRL lr, GetWriteProtect_Unimplemented STR lr, [a4, #HALDevice_SDHCIGetWriteProtect] ; SlotInfo_Flags MOV lr, #HALDeviceSDHCI_SlotFlag_Bus4Bit :OR: HALDeviceSDHCI_SlotFlag_Integrated STR lr, [a4, #SDHCISlotInfo + HALDeviceSDHCI_SlotInfo_Flags] ; drop through... 40 ; The three cases rejoin here MOV a1, #0 ; flags MOV a2, a4 Pull "lr" LDR pc, OSentries+4*OS_AddDevice ; tail call Description DATA = "TI OMAP3 SD host controller", 0 ALIGN NOPEntry ROUT MOV pc, lr MACRO EnableClocks $ctrlr ; 22.6.1.3.1.1 MMCHS Controller Interface and Functional Clocks Enabling ADD a4, a4, #L4_ClockMan_FCLKEN1_CORE - L4_Core LDR a3, [a4] ORR a3, a3, #EN_$ctrlr STR a3, [a4] LDR a3, [a4, #L4_ClockMan_ICLKEN1_CORE - L4_ClockMan_FCLKEN1_CORE] ORR a3, a3, #EN_$ctrlr STR a3, [a4, #L4_ClockMan_ICLKEN1_CORE - L4_ClockMan_FCLKEN1_CORE] SUB a4, a4, #L4_ClockMan_FCLKEN1_CORE - L4_Core MEND MACRO MakeGPIOPin $num, $input LDR a3, [a4, #(L4_PadConf_GPIO$num :AND::NOT: 3) - L4_PadConf] [ L4_PadConf_GPIO$num :AND: 2 = 0 MOVW a2, #PADCONF_MASK BIC a3, a3, a2 [ "$input" = "input" ORR a3, a3, #PADCONF_INPUTENABLE :OR: PADCONF_MUXMODE_GPIO | ORR a3, a3, #PADCONF_MUXMODE_GPIO ] | UXTH a3, a3 [ "$input" = "input" ORR a3, a3, #(PADCONF_INPUTENABLE :OR: PADCONF_MUXMODE_GPIO) :SHL: 16 | ORR a3, a3, #PADCONF_MUXMODE_GPIO :SHL: 16 ] ] STR a3, [a4, #(L4_PadConf_GPIO$num :AND::NOT: 3) - L4_PadConf] GPIO_PrepareC a1, a2, $num [ "$input" = "input" GPIO_SetAsInput a1, a2, a3 | GPIO_SetAsOutput a1, a2, a3 ] MEND MACRO MakeMMCPin $num, $type, $input LDR a3, [a4, #(L4_PadConf_GPIO$num :AND::NOT: 3) - L4_PadConf] [ L4_PadConf_GPIO$num :AND: 2 = 0 MOVW a2, #PADCONF_MASK BIC a3, a3, a2 [ "$input" = "input" ORR a3, a3, #$type :OR: PADCONF_PULLUDENABLE :OR: PADCONF_PULLTYPESELECT :OR: PADCONF_INPUTENABLE | ORR a3, a3, #$type :OR: PADCONF_PULLUDENABLE :OR: PADCONF_PULLTYPESELECT ] | UXTH a3, a3 [ "$input" = "input" ORR a3, a3, #($type :OR: PADCONF_PULLUDENABLE :OR: PADCONF_PULLTYPESELECT) :SHL: 16 ORR a3, a3, #PADCONF_INPUTENABLE :SHL: 16 | ORR a3, a3, #($type :OR: PADCONF_PULLUDENABLE :OR: PADCONF_PULLTYPESELECT) :SHL:16 ] ] STR a3, [a4, #(L4_PadConf_GPIO$num :AND::NOT: 3) - L4_PadConf] MEND MACRO MyTPSWrite $reg, $value LDR lr, =$value STR lr, [sp] MOV a1, #TPSRegGroup_$reg * 2 MOV a4, #TPSRegOffset_$reg BL TPSWrite MEND Activate_MMC1_BeagleboardRevB ROUT Push "sb,lr" LDR sb, [a1, #SDHCISB] LDR a4, L4_Core_Log EnableClocks MMC1 LDR lr, =L4_PadConf - L4_Core ADD a4, a4, lr MakeGPIOPin $BB_USER0, output MakeGPIOPin $BB_USER1, output MakeGPIOPin $BBREVB_WP, input MOV a1, #1 Pull "sb,pc" Activate_MMC1_BeagleboardRevC ROUT Push "sb,lr" LDR sb, [a1, #SDHCISB] LDR a4, L4_Core_Log EnableClocks MMC1 LDR lr, =L4_PadConf - L4_Core ADD a4, a4, lr MakeGPIOPin $BB_USER0, output MakeGPIOPin $BB_USER1, output MakeGPIOPin $BBREVC_WP, input MOV a1, #1 Pull "sb,pc" Activate_MMC1_BeagleboardxM ROUT Push "sb,lr" LDR sb, [a1, #SDHCISB] LDR a4, L4_Core_Log EnableClocks MMC1 LDR lr, =L4_PadConf - L4_Core ADD a4, a4, lr MakeGPIOPin $BB_USER0, output MakeGPIOPin $BB_USER1, output MOV a1, #1 Pull "sb,pc" Activate_MMC1_IGEPv2 ROUT Push "sb,lr" LDR sb, [a1, #SDHCISB] LDR a4, L4_Core_Log EnableClocks MMC1 LDR lr, =L4_PadConf - L4_Core ADD a4, a4, lr MakeGPIOPin $IGEP_GREEN, output MakeGPIOPin $IGEP_RED, output MOV a1, #1 Pull "sb,pc" Activate_MMC1_DevKit8000 ROUT Push "sb,lr" LDR sb, [a1, #SDHCISB] LDR a4, L4_Core_Log EnableClocks MMC1 LDR lr, =L4_PadConf - L4_Core ADD a4, a4, lr MakeGPIOPin $DK_LED2, output MakeGPIOPin $DK_LED3, output MakeGPIOPin $BBREVB_WP, input MOV a1, #1 Pull "sb,pc" Activate_MMC1_Pandora ROUT Push "sb,lr" LDR sb, [a1, #SDHCISB] LDR a4, L4_Core_Log EnableClocks MMC1 LDR lr, =L4_PadConf - L4_Core ADD a4, a4, lr MakeGPIOPin $PANDORA_LED1, output MakeGPIOPin $PANDORA_WP1, input MOV a1, #1 Pull "sb,pc" Activate_MMC2_IGEPv2 ROUT Push "sb,lr" LDR sb, [a1, #SDHCISB] LDR a4, L4_Core_Log EnableClocks MMC2 MOV a1, #1 Pull "sb,pc" Activate_MMC2_Pandora ROUT Push "v1,sb,lr" LDR sb, [a1, #SDHCISB] LDR a4, L4_Core_Log LDR lr, =L4_Core_DEVCONF1 - L4_Core LDR ip, [a4, lr] BIC ip, ip, #MMCSDIO2ADPCLKISEL STR ip, [a4, lr] EnableClocks MMC2 LDR lr, =L4_PadConf - L4_Core ADD a4, a4, lr MakeGPIOPin $PANDORA_LED2, output MakeGPIOPin $PANDORA_WP2, input MakeMMCPin $MMC2_CLK, 0 MakeMMCPin $MMC2_CMD, 0, input MakeMMCPin $MMC2_DAT0, 0, input MakeMMCPin $MMC2_DAT1, 0, input MakeMMCPin $MMC2_DAT2, 0, input MakeMMCPin $MMC2_DAT3, 0, input MakeMMCPin $MMC2_DIR_DAT0, 1 MakeMMCPin $MMC2_DIR_DAT1, 1 MakeMMCPin $MMC2_DIR_CMD, 1 MakeMMCPin $MMC2_CLKIN, 1, input SUB sp, sp, #4 MOV a2, sp MOV a3, #1 LDR v1, OSentries+4*OS_IICOpV MyTPSWrite VMMC2_DEDICATED, VMMC2_DEDICATED_VSEL_3_00V MyTPSWrite VMMC2_DEV_GRP, DEV_GRP_P1 MyTPSWrite GPIOCTRL, GPIOCTRL_ON ADD sp, sp, #4 MOV a1, #1 Pull "v1,sb,pc" Activate_MMC3_Pandora ROUT Push "sb,lr" LDR sb, [a1, #SDHCISB] LDR a4, L4_Core_Log EnableClocks MMC3 MOV a1, #1 Pull "sb,pc" Deactivate * NOPEntry Reset ROUT Push "sb,lr" LDR sb, [a1, #SDHCISB] LDR a4, [a1, #HALDevice_Address] ; 22.6.1.3.1.2 MMCHS Controller Software Reset MOV a2, #SYSCONFIG_SOFTRESET STR a2, [a4, #SYSCONFIG] MOV a3, #RESET_TIMEOUT 00 SUBS a3, a3, #1 Pull "sb,pc", EQ ; timed out LDR a2, [a4, #SYSSTATUS] TST a2, #SYSSTATUS_RESETDONE BEQ %B00 ; 22.6.1.3.1.3 MMCHS Controller Voltage Capabilities Initialization ADRL a2, SDIOWS ; = device for MMC1 TEQ a2, a1 MOVEQ a2, #CAPA_VS18 :OR: CAPA_VS30 MOVNE a2, #CAPA_VS18 STR a2, [a4, #CAPA] Pull "sb,pc" Sleep ROUT ; Could probably turn clock to controller on/off to ; save power, but for now don't support power saving MOV a1, #0 MOV pc, lr TestIRQ ROUT ; Not a shared interrupt, so it must be our fault MOV a1, #1 MOV pc, lr GetVddCapabilities_Pandora_MMC2 ; The TPS can't generate 3.3V, so by deduction this must be 3.0V. MOV a1, #CAPA_VS30 / CAPA_VS33 ; flags start at bit 0 MOV pc, lr SetVdd ROUT ; MMC1 case Push "v1,sb,lr" LDR sb, [a1, #SDHCISB] SUB sp, sp, #4 ; buffer for TPS register contents ; Use separate code branches for each voltage to keep ordering correct TEQ a3, #0 BEQ %F00 LDR a1, =1800 TEQ a3, a1 BEQ %F18 LDR a1, =3000 TEQ a3, a1 BEQ %F30 B %F90 ; shouldn't happen 00 ; Set to 0V ; Set the pads to high impedance to protect the GPIO controller from ramping reference voltages LDR a1, L4_Core_Log LDR a3, =L4_PBiasLite - L4_Core MOV a2, #0 STR a2, [a1, a3] ; Turn off the power in the TWL4030/TPS65950 MOV a2, sp 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 LDR a1, [a1, #HALDevice_Address] MOV a2, #0 STR a2, [a1, #HCTL] ; Wait for the power to ramp before returning MOV r0, #BUS_POWER_RAMP BL HAL_CounterDelay B %F90 18 ; Set to 1.8V ; Turn on the power in the TWL4030/TPS65950 MOV a2, sp MOV a3, #1 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 LDR a1, [a1, #HALDevice_Address] MOV a2, #HCTL_SDVS_1_8V STR a2, [a1, #HCTL] MOV a2, #HCTL_SDVS_1_8V :OR: HCTL_SDBP STR a2, [a1, #HCTL] ; needs to be two separate writes, the SDBP bit won't latch on the first write ; Wait for the power to ramp up MOV r0, #BUS_POWER_RAMP BL HAL_CounterDelay ; Configure the GPIO controller for the new reference voltage LDR a1, L4_Core_Log LDR a3, =L4_PBiasLite - L4_Core MOV a2, #PBIASLITESPEEDCTRL1 :OR: PBIASLITEPWRDNZ1 :OR: PBIASLITESPEEDCTRL0 :OR: PBIASLITEPWRDNZ0 STR a2, [a1, a3] B %F90 30 ; Set to 3.0V ; Turn on the power in the TWL4030/TPS65950 MOV a2, sp MOV a3, #1 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 LDR a1, [a1, #HALDevice_Address] MOV a2, #HCTL_SDVS_3_0V STR a2, [a1, #HCTL] MOV a2, #HCTL_SDVS_3_0V :OR: HCTL_SDBP STR a2, [a1, #HCTL] ; needs to be two separate writes, the SDBP bit won't latch on the first write ; Wait for the power to ramp up MOV r0, #BUS_POWER_RAMP BL HAL_CounterDelay ; Configure the GPIO controller for the new reference voltage LDR a1, L4_Core_Log LDR a3, =L4_PBiasLite - L4_Core MOV a2, #PBIASLITESPEEDCTRL1 :OR: PBIASLITEPWRDNZ1 :OR: PBIASLITEVMODE1 :OR: PBIASLITESPEEDCTRL0 :OR: PBIASLITEPWRDNZ0 :OR: PBIASLITEVMODE0 STR a2, [a1, a3] ; Drop through 90 ADD sp, sp, #4 Pull "v1,sb,pc" SetVdd_MMC2_LevelShifted ROUT Push "sb,lr" LDR sb, [a1, #SDHCISB] LDR a1, [a1, #HALDevice_Address] MOV a2, #HCTL_SDVS_1_8V STR a2, [a1, #HCTL] MOV a2, #HCTL_SDVS_1_8V :OR: HCTL_SDBP STR a2, [a1, #HCTL] ; needs to be two separate writes, the SDBP bit won't latch on the first write ; Wait for the power to ramp up MOV r0, #BUS_POWER_RAMP BL HAL_CounterDelay Pull "sb,pc" SetBusMode ROUT Push "sb,lr" LDR a4, [a1, #HALDevice_Address] LDR ip, [a4, #CON] TEQ a3, #0 ORRNE ip, ip, #CON_OD BICEQ ip, ip, #CON_OD STR ip, [a4, #CON] Pull "sb,pc" PostPowerOn ROUT Push "v1,sb,lr" LDR sb, [a1, #SDHCISB] MOV v1, a1 ; 22.6.1.3.1.5 MMCHS Controller INIT Procedure Start ; We can't set SDCLK as slow as 80 kHz as suggested - and using the the ; 150 kHz set twice doesn't seem to work. Use the procedure described in ; figure 22-27 instead. MOV a3, #150 BL SetSDCLK ; doesn't work without this LDR a4, [v1, #HALDevice_Address] LDR a1, [a4, #CON] ORR a1, a1, #CON_INIT STR a1, [a4, #CON] MOV a1, #0 STR a1, [a4, #CMD] ; dummy command - value doesn't matter because CMD line is held at 1 MOV a1, #INIT_PROCEDURE_TIME BL HAL_CounterDelay LDR a4, [v1, #HALDevice_Address] LDR a1, [a4, #STAT] ORR a1, a1, #STAT_CC STR a1, [a4, #STAT] ; acknowledge command complete interrupt LDR a1, [a4, #CON] BIC a1, a1, #CON_INIT STR a1, [a4, #CON] ; end initialisation sequence MOV a1, #-1 STR a1, [a4, #STAT] ; acknowledge all interrupts Pull "v1,sb,pc" SetBusWidth ROUT LDR a4, [a1, #HALDevice_Address] LDR ip, [a4, #CON] TEQ a3, #8 ORREQ ip, ip, #CON_DW8 BICNE ip, ip, #CON_DW8 STR ip, [a4, #CON] LDR ip, [a4, #HCTL] TEQ a3, #4 ORREQ ip, ip, #HCTL_DTW BICNE ip, ip, #HCTL_DTW STR ip, [a4, #HCTL] MOV pc, lr GetMaxCurrent ROUT ; MMC1 case ; TWL4030/TPS65950 supplies 220 mA on VMMC1 ; VSIM isn't used as a power line so it doesn't matter MOV a1, #220 MOV pc, lr GetMaxCurrent_MMC2 ROUT ; TWL4030/TPS65950 supplies 100 mA on VMMC2 MOV a1, #100 MOV pc, lr GetMaxCurrent_LBEE1USJYC ROUT ; The highest current listed in the LBEE1USJYC datasheet is for when ; it is operating in IEEE802.11b TX mode - a figure of 380 mA. ; I'm assuming the board can supply this? I also can't immediately see ; any reference to whether this is the threshold used in the SDIO ; negotiation - please check this if you are implementing a driver. MOV a1, #380 MOV pc, lr SetSDCLK ROUT LDR a1, [a1, #HALDevice_Address] LDR ip, =FCLK_FREQ ADD a2, ip, a3 SUB a2, a2, #1 ; round divider up so we round frequency down DivRem a4, a2, a3, ip CMP a4, #(SYSCTL_CLKD_MASK :SHR: SYSCTL_CLKD_SHIFT) + 1 MOVHS a4, #SYSCTL_CLKD_MASK :SHR: SYSCTL_CLKD_SHIFT ; a4 = divider LDR a2, [a1, #SYSCTL] BIC a2, a2, #SYSCTL_CEN STR a2, [a1, #SYSCTL] ; stop clock going to card BIC a2, a2, #SYSCTL_ICE STR a2, [a1, #SYSCTL] ; stop clock LDR a3, =SYSCTL_CLKD_MASK BIC a2, a2, a3 ORR a2, a2, a4, LSL #SYSCTL_CLKD_SHIFT STR a2, [a1, #SYSCTL] ; set divider ORR a2, a2, #SYSCTL_ICE STR a2, [a1, #SYSCTL] ; start clock MOV a3, #CLOCKSET_TIMEOUT 00 SUBS a3, a3, #1 MOVEQ pc, lr ; timed out LDR a2, [a1, #SYSCTL] TST a2, #SYSCTL_ICS BEQ %B00 ORR a2, a2, #SYSCTL_CEN STR a2, [a1, #SYSCTL] ; provide clock to card LDR ip, =FCLK_FREQ DivRem a1, ip, a4, a2 MOV pc, lr GetTMCLK ROUT ; Verified experimentally that the OMAP reuses SDCLK for TMCLK LDR a1, [a1, #HALDevice_Address] LDR a2, [a1, #SYSCTL] LDR a3, =SYSCTL_CLKD_MASK AND a2, a2, a3 MOV a2, a2, LSR #SYSCTL_CLKD_SHIFT LDR ip, =FCLK_FREQ DivRem a1, ip, a2, a3 MOV pc, lr SetActivity_Beagleboard ROUT ; including xM Push "sb,lr" LDR sb, [a1, #SDHCISB] GPIO_PrepareC a1, a2, $BB_USER1 TEQ a3, #HALDeviceSDHCI_ActivityOff GPIO_SetOutput0 a1, a2, EQ GPIO_SetOutput1 a1, a2, NE GPIO_PrepareC a1, a2, $BB_USER0 TEQ a3, #HALDeviceSDHCI_ActivityWrite GPIO_SetOutput1 a1, a2, EQ GPIO_SetOutput0 a1, a2, NE Pull "sb,pc" SetActivity_IGEPv2 ROUT Push "sb,lr" LDR sb, [a1, #SDHCISB] GPIO_PrepareC a1, a2, $IGEP_GREEN TEQ a3, #HALDeviceSDHCI_ActivityRead GPIO_SetOutput1 a1, a2, EQ GPIO_SetOutput0 a1, a2, NE GPIO_PrepareC a1, a2, $IGEP_RED TEQ a3, #HALDeviceSDHCI_ActivityWrite GPIO_SetOutput1 a1, a2, EQ GPIO_SetOutput0 a1, a2, NE Pull "sb,pc" SetActivity_DevKit8000 ROUT Push "sb,lr" LDR sb, [a1, #SDHCISB] GPIO_PrepareC a1, a2, $DK_LED2 TEQ a3, #HALDeviceSDHCI_ActivityOff GPIO_SetOutput0 a1, a2, EQ GPIO_SetOutput1 a1, a2, NE GPIO_PrepareC a1, a2, $DK_LED3 TEQ a3, #HALDeviceSDHCI_ActivityWrite GPIO_SetOutput1 a1, a2, EQ GPIO_SetOutput0 a1, a2, NE Pull "sb,pc" SetActivity_Pandora_MMC1 ROUT Push "sb,lr" LDR sb, [a1, #SDHCISB] GPIO_PrepareC a1, a2, $PANDORA_LED1 TEQ a3, #HALDeviceSDHCI_ActivityOff GPIO_SetOutput0 a1, a2, EQ GPIO_SetOutput1 a1, a2, NE Pull "sb,pc" SetActivity_Pandora_MMC2 ROUT Push "sb,lr" LDR sb, [a1, #SDHCISB] GPIO_PrepareC a1, a2, $PANDORA_LED2 TEQ a3, #HALDeviceSDHCI_ActivityOff GPIO_SetOutput0 a1, a2, EQ GPIO_SetOutput1 a1, a2, NE Pull "sb,pc" GetCardDetect ROUT Push "v1,sb,lr" LDR sb, [a1, #SDHCISB] SUB sp, sp, #4 ; buffer for TPS register contents MOV a1, #TPSRegGroup_GPIODATAIN1 * 2 MOV a2, sp MOV a3, #1 MOV a4, #TPSRegOffset_GPIODATAIN1 LDR v1, OSentries+4*OS_IICOpV BL TPSRead Pull "a1" ; value read from register TST a1, #GPIO0IN ; line is active low MOVEQ a1, #1 MOVNE a1, #0 Pull "v1,sb,pc" GetCardDetect_MMC2 ROUT Push "v1,sb,lr" LDR sb, [a1, #SDHCISB] SUB sp, sp, #4 ; buffer for TPS register contents MOV a1, #TPSRegGroup_GPIODATAIN1 * 2 MOV a2, sp MOV a3, #1 MOV a4, #TPSRegOffset_GPIODATAIN1 LDR v1, OSentries+4*OS_IICOpV BL TPSRead Pull "a1" ; value read from register TST a1, #GPIO1IN ; line is active low MOVEQ a1, #1 MOVNE a1, #0 Pull "v1,sb,pc" GetCardDetect_NonRemovable ROUT MOV a1, #1 MOV pc, lr GetWriteProtect_BeagleboardRevB_DevKit8000 ROUT Push "sb,lr" LDR sb, [a1, #SDHCISB] ; When the WP tab is slid back (activated) the switch is open, and the ; external resistor pulls the line high, which is read as a set bit GPIO_PrepareC a1, a2, $BBREVB_WP GPIO_GetInput a1, a1, a2 TEQ a1, #0 MOVNE a1, #1 Pull "sb,pc" GetWriteProtect_BeagleboardRevC ROUT Push "sb,lr" LDR sb, [a1, #SDHCISB] ; When the WP tab is slid back (activated) the switch is open, and the ; external resistor pulls the line high, which is read as a set bit GPIO_PrepareC a1, a2, $BBREVC_WP GPIO_GetInput a1, a1, a2 TEQ a1, #0 MOVNE a1, #1 Pull "sb,pc" GetWriteProtect_Pandora_MMC1 ROUT Push "sb,lr" LDR sb, [a1, #SDHCISB] ; Guess that the polarity is the same as the beagleboard (schematic is vague) GPIO_PrepareC a1, a2, $PANDORA_WP1 GPIO_GetInput a1, a1, a2 TEQ a1, #0 MOVNE a1, #1 Pull "sb,pc" GetWriteProtect_Pandora_MMC2 ROUT Push "sb,lr" LDR sb, [a1, #SDHCISB] ; Guess that the polarity is the same as the beagleboard (schematic is vague) GPIO_PrepareC a1, a2, $PANDORA_WP2 GPIO_GetInput a1, a1, a2 TEQ a1, #0 MOVNE a1, #1 Pull "sb,pc" GetWriteProtect_Unimplemented ROUT ; because it's a microSD slot MOV a1, #0 ; permit writes MOV pc, lr END