; Copyright 2010 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:Proc AREA |Asm$$Code|, CODE, READONLY, PIC EXPORT TPSRead EXPORT TPSWrite EXPORT TPS_Init IMPORT IIC_DoOp_Poll ; A couple of utility functions for reading/writing registers from the TWL4030/TPS65950 IC ; (although the protocol is probably generic enough to work with many other IIC devices) ; For the majority of uses, v1 simply needs to be initialised as follows: ; LDR v1, OSentries+4*OS_IICOpV ; i.e. the IIC transfer will be performed on IIC bus 0, via RISCOS_IICOpV, ; returning an IICStatus. ; When using OS_IICOpV, v2 can be left uninitialised. ; TODO - Tidy this up - TPSRead/TPSWrite can simply choose for themselves whether to use OS_IICOpV or IIC_DoOp_Poll TPSRead ; a1 = IIC address(*2) ; a2 = buffer ; a3 = count ; a4 = start register ; v1 = IIC func ; v2 = IIC param ; out: ; a1 = return code ; ip corrupted ; buffer updated ORR a1, a1, #1 ; read Push "a1-a4,lr" ; Push regs and second iic_transfer block EOR a1, a1, #1+(1:SHL:29) ; write with retry ADD a2, sp, #12 MOV a3, #1 Push "a1-a3" ; push first iic_transfer block MOV a1, sp MOV a2, #2 MOV a3, v2 BLX v1 ADD sp, sp, #16 Pull "a2-a4,pc" TPSWrite ; a1 = IIC address(*2) ; a2 = buffer ; a3 = count ; a4 = start register ; v1 = IIC func ; v2 = IIC param ; out: ; a1 = return code ; ip corrupted ORR a1, a1, #1:SHL:31 ; Write (no start bit) Push "a1-a4,lr" ; Push regs and second iic_transfer block EOR a1, a1, #(1:SHL:29)+(1:SHL:31) ; Write (retries) ADD a2, sp, #12 MOV a3, #1 Push "a1-a3" ; push first iic_transfer block MOV a1, sp MOV a2, #2 MOV a3, v2 BLX v1 ADD sp, sp, #16 Pull "a2-a4,pc" ; TPS power scripts ; These scripts control how the chip subresources respond to on/off/reset events ; At the moment we only set up a script for reset, which is required to make sure VDD1/VDD2 are reset to safe levels (problems seen on some BB-xM boards when SmartReflex is in use, but code is probably needed for non-SmartReflex voltage control as well) ; Resource groups RES_GRP_RES * &0 RES_GRP_PP * &1 RES_GRP_RC * &2 RES_GRP_PP_RC * &3 RES_GRP_PR * &4 RES_GRP_PP_PR * &5 RES_GRP_RC_PR * &6 RES_GRP_ALL * &7 ; Types RES_TYPE_ALL * &7 ; States RES_STATE_WRST * &F RES_STATE_ACTIVE * &E RES_STATE_SLEEP * &8 RES_STATE_OFF * &0 ; Resources RES_VAUX1 * 1 RES_VAUX2 * 2 RES_VAUX3 * 3 RES_VAUX4 * 4 RES_VMMC1 * 5 RES_VMMC2 * 6 RES_VPLL1 * 7 RES_VPLL2 * 8 RES_VSIM * 9 RES_VDAC * 10 RES_VINTANA1 * 11 RES_VINTANA2 * 12 RES_VINTDIG * 13 RES_VIO * 14 RES_VDD1 * 15 RES_VDD2 * 16 RES_VUSB_1V5 * 17 RES_VUSB_1V8 * 18 RES_VUSB_3V1 * 19 RES_VUSBCP * 20 RES_REGEN * 21 RES_NRES_PWRON * 22 RES_CLKEN * 23 RES_SYSEN * 24 RES_HFCLKOUT * 25 RES_32KCLKOUT * 26 RES_RESET * 27 RES_MAIN_REF * 28 ; IIC addresses PROTECT_KEY * &44 P1_SW_EVENTS * &46 P2_SW_EVENTS * &47 P3_SW_EVENTS * &48 PB_CFG * &4A PB_WORD_MSB * &4B PB_WORD_LSB * &4C SEQ_ADD_WARM * &58 MEMORY_ADDRESS * &59 MEMORY_DATA * &5A VAUX1_DEV_GRP * &72 VAUX2_DEV_GRP * &76 VAUX3_DEV_GRP * &7A VAUX4_DEV_GRP * &7E VMMC1_DEV_GRP * &82 VMMC2_DEV_GRP * &86 VPLL1_DEV_GRP * &8A VPLL2_DEV_GRP * &8E VSIM_DEV_GRP * &92 VDAC_DEV_GRP * &96 VINTANA1_DEV_GRP * &9A VINTANA2_DEV_GRP * &9E VINTDIG_DEV_GRP * &A2 VIO_DEV_GRP * &A6 VDD1_DEV_GRP * &B0 VDD2_DEV_GRP * &BE VUSB1V5_DEV_GRP * &CC VUSB1V3_DEV_GRP * &D2 REGEN_DEV_GRP * &DA NRESPWRON_DEV_GRP * &DD CLKEN_DEV_GRP * &E0 SYSEN_DEV_GRP * &E3 HFCLKOUT_DEV_GRP * &E6 _32KCLKOUT_DEV_GRP * &E9 TRITON_RESET_DEV_GRP * &EC MAINREF_DEV_GRP * &EF ; Macros for constructing a power bus message/script entry: ; first byte is high word of message ; second byte is low word ; third byte is optional delay value (encoded) ; $p123 somewhat useless for script entries - it seems to get stripped out when written to script memory? MACRO PwrMsgSingle $p123, $res, $state, $delay DCB ($p123 :SHL: 5) + ($res :SHR: 4) DCB (($res :SHL: 4) + ($state)) :AND: 255 [ "$delay" <> "" DCB $delay ] MEND MACRO PwrMsgBroadcast $p123, $grp, $type, $type2, $state, $delay DCB ($p123 :SHL: 5) + &10 + ($grp :SHL: 1) + ($type2 :SHR: 1) DCB (($type2 :SHL: 7) + ($type :SHL: 4) + ($state)) :AND: 255 [ "$delay" <> "" DCB $delay ] MEND ; Macros for setting up resource properties ; First byte is IIC address to start at ; Then three bytes for configuration (DEV_GRP, TYPE, REMAP) MACRO PwrResCfg $res, $p123, $type, $type2, $off, $sleep DCB $res._DEV_GRP DCB $p123 :SHL: 5 DCB $type + ($type2 :SHL: 3) DCB $sleep + ($off :SHL: 4) MEND ; Power resource configuration as per http://omapedia.org/wiki/TWL4030_power_scripts ; This is required for the warmreset script to work ; Note that we're ignoring the erratum 27 workaround (not needed for TWL4030/TPS65950?), and only modifying the resources that need changing from default (to avoid messing up any P1/P2/P3 assignments that have been made to aux LDOs that are used for video, USB, etc.) powerconfig_start PwrResCfg VPLL1, 2_001, 3, 1, RES_STATE_OFF, RES_STATE_OFF PwrResCfg VINTANA1, 2_111, 1, 2, RES_STATE_OFF, RES_STATE_SLEEP PwrResCfg VINTANA2, 2_111, 0, 2, RES_STATE_OFF, RES_STATE_SLEEP PwrResCfg VINTDIG, 2_111, 1, 2, RES_STATE_OFF, RES_STATE_SLEEP PwrResCfg VIO, 2_111, 2, 2, RES_STATE_OFF, RES_STATE_SLEEP PwrResCfg VDD1, 2_001, 4, 1, RES_STATE_OFF, RES_STATE_OFF PwrResCfg VDD2, 2_001, 3, 1, RES_STATE_OFF, RES_STATE_OFF PwrResCfg REGEN, 2_111, 2, 1, RES_STATE_OFF, RES_STATE_SLEEP PwrResCfg NRESPWRON, 2_111, 0, 1, RES_STATE_OFF, RES_STATE_SLEEP PwrResCfg CLKEN, 2_111, 3, 2, RES_STATE_OFF, RES_STATE_SLEEP PwrResCfg SYSEN, 2_111, 6, 1, RES_STATE_OFF, RES_STATE_SLEEP PwrResCfg HFCLKOUT, 2_001, 0, 2, RES_STATE_OFF, RES_STATE_SLEEP DCB 0 ; Terminator ; TI's recommended generic warm reset script ; From http://permalink.gmane.org/gmane.linux.ports.arm.omap/56193 warmreset_script PwrMsgSingle 2_000, RES_NRES_PWRON, RES_STATE_OFF, 2 PwrMsgSingle 2_000, RES_RESET, RES_STATE_OFF, 2 PwrMsgSingle 2_000, RES_MAIN_REF, RES_STATE_WRST, 2 PwrMsgBroadcast 2_000, RES_GRP_ALL, 0, 2, RES_STATE_WRST, 2 PwrMsgSingle 2_000, RES_VUSB_3V1, RES_STATE_WRST, 2 PwrMsgBroadcast 2_000, RES_GRP_ALL, 0, 1, RES_STATE_WRST, 2 PwrMsgBroadcast 2_000, RES_GRP_RC, RES_TYPE_ALL, 0, RES_STATE_WRST, 2 PwrMsgSingle 2_000, RES_RESET, RES_STATE_ACTIVE, 2 PwrMsgSingle 2_000, RES_NRES_PWRON, RES_STATE_ACTIVE, 2 warmreset_script_end ; Post-warmreset power bus message, as per per swcu050g p240 ; I'm not entirely sure why this has to be done manually instead of as part of the warmreset script. ASSERT PB_WORD_MSB = PB_CFG + 1 ASSERT PB_WORD_LSB = PB_WORD_MSB + 1 post_warmreset_command DCB 2 ; PB_CFG: Allow IIC access to power bus PwrMsgBroadcast 2_111, RES_GRP_ALL, RES_TYPE_ALL, 0, RES_STATE_ACTIVE ; &FE, &7E from TRM ALIGN TPS_Init ROUT Entry "v1-v3", 4 ; Issue the post-warmreset power bus message MOV a1, #&4b*2 ADR a2, post_warmreset_command MOV a3, #3 MOV a4, #PB_CFG ADRL v1, IIC_DoOp_Poll BL TPSWrite ; Poll PB_CFG until command completes MOV a2, sp MOV a3, #1 05 MOV a1, #&4b*2 BL TPSRead CMP a1, #0 BNE %BT05 LDRB a1, [a2] TST a1, #1 BNE %BT05 ; Set up resource properties ADR a2, powerconfig_start MOV a3, #3 10 LDRB a4, [a2], #1 CMP a4, #0 BEQ %FT20 MOV a1, #&4b*2 BL TPSWrite ADD a2, a2, #3 B %BT10 20 ; Now load the warmreset script ; Must unlock registers via PROTECT_KEY MOV a1, #&4b*2 MOV a2, sp MOV ip, #&c0 STRB ip, [a2] MOV a3, #1 MOV a4, #PROTECT_KEY BL TPSWrite MOV ip, #&0c STRB ip, [a2] MOV a1, #&4b*2 BL TPSWrite ; Load script ; TODO - Make sure we're not overwriting any other scripts ADR a2, warmreset_script ADR v2, warmreset_script_end MOV v3, #&2b BL loadscript ; Set script start address MOV a1, #&4b*2 MOV a2, sp STRB v3, [sp] MOV a3, #1 MOV a4, #SEQ_ADD_WARM BL TPSWrite ; Enable warmreset for P1, P2, P3 ASSERT P2_SW_EVENTS = P1_SW_EVENTS + 1 ASSERT P3_SW_EVENTS = P2_SW_EVENTS + 1 MOV a1, #&4b*2 MOV a3, #3 MOV a4, #P1_SW_EVENTS BL TPSRead LDR ip, [a2] LDR a1, =&101010 ORR ip, ip, a1 STR ip, [a2] MOV a1, #&4b*2 BL TPSWrite ; Lock registers MOV a1, #0 STRB a1, [a2] MOV a1, #&4b*2 MOV a3, #1 MOV a4, #PROTECT_KEY BL TPSWrite ; Done EXIT loadscript ROUT ; a2 = script start ; v1 = IIC func ptr ; v2 = script end ; v3 = address to load to Entry "a2,v3-v4", 4 ; Set MEMORY_ADDRESS to the address to start at, SHL 2 MOV a1, #&4b*2 MOV ip, v3, LSL #2 MOV a2, sp STRB ip, [a2] MOV a3, #1 MOV a4, #MEMORY_ADDRESS BL TPSWrite ; Load script LDR a2, [sp, #4] MOV a4, #MEMORY_DATA 10 ; Three data bytes MOV v4, #3 20 MOV a1, #&4b*2 BL TPSWrite ADD a2, a2, #1 SUBS v4, v4, #1 BNE %BT20 ; Next address byte Push "a2" ADD v3, v3, #1 CMP a2, v2 MOVEQ v3, #&3f ADD a2, sp, #4 STRB v3, [a2] MOV a1, #&4b*2 BL TPSWrite Pull "a2" CMP v3, #&3f BNE %BT10 EXIT END