; Copyright 2011 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:Proc GET hdr.omap3530 GET hdr.StaticWS GET hdr.PRCM AREA |Asm$$Code|, CODE, READONLY, PIC EXPORT CPUClk_PreInit EXPORT CPUClk_Init EXPORT CPUClk_AdjustDPLL EXPORT CPUClk_PreReset IMPORT TPSRead IMPORT TPSWrite IMPORT memcpy IMPORT __rt_udiv IMPORT IIC_DoOp_Poll GBLL DebugCPUClk DebugCPUClk SETL {FALSE} [ DebugCPUClk IMPORT DebugHALPrint IMPORT DebugHALPrintReg IMPORT DebugHALPrintByte ] CPUClk_PreInit ROUT ; Identify the OMAP type, set up the HAL device descriptor, then put the CPU speed to max to help cut down our boot time Entry "v1-v4" [ {TRUE} ; Try smartreflex IMPORT SR37x_PreInit BL SR37x_PreInit CMP a1, #0 EXIT EQ ] ; First identify the OMAP type LDR a1, L4_Wakeup_Log LDR a2, =L4_CONTROL_IDCODE-L4_Wakeup LDR a1, [a2, a1]! UBFX a1, a1, #12, #16 ADR a3, CPUList 10 LDMIA a3!,{a4,v1,v2} CMP a4,#0 EXIT EQ ; Unrecognised CPU! CMP a1, a4 BNE %BT10 ; Extra logic for detecting 720MHz OMAP3's MOV v4, #0 LDR a3, =HAWKEYE_OMAP35x_ES10 CMP a3, a1 LDRNE a3, =HAWKEYE_OMAP35x CMPNE a3, a1 LDREQ a2, [a2, #L4_PRODID-L4_CONTROL_IDCODE] ANDEQ v4, a2, #&F ; 0x0 for 600MHz, 0x8 for 720MHz [ DebugCPUClk DebugReg a4, "CPU=" DebugReg v1, "OPPTbl size=" DebugReg v2, "OPPTbl ptr=" DebugReg v4, "720MHz=" ] ; v1 = OPPTbl size ; v2 = OPPTbl ptr ; Init the HAL device descriptor ADRL v3, CPUClkWS MOV a1, v3 ADR a2, CPUClkDevTemplate MOV a3, #HALDevice_CPUClk_Size BL memcpy ADR a1, CPUClk_Shutdown STR a1, [v3, #:INDEX: CPUClkShutdown] STR sb, [v3, #:INDEX: CPUClkWorkspace] STR v1, [v3, #:INDEX: CPUClkOPPTblSize] ADD a1, v3, #:INDEX: CPUClkOPPTbl MOV a2, v2 ASSERT OPPTbl_Size = 4 LDR a3, [v2, v1, LSL #2] ; Get shutdown setting STR a3, [v3, #:INDEX: CPUClkOPPDefault] MOV a3, v1, LSL #2 BL memcpy ; Poke the last entry in the table if this was a 720MHz model CMP v4, #8 MOVEQ v4, #720 STREQH v4, [v3, #:INDEX: CPUClkOPPTbl + End_OPPTbl_OMAP35x-OPPTbl_OMAP35x - OPPTbl_Size + OPPTbl_MHz] SUB sp, sp, #4 MOV a2, sp MOV a3, #1 ADRL v1, IIC_DoOp_Poll ; Make sure VDD1_VMODE_CFG is set correctly ; We want READ_REG set, ENABLE_VMODE clear MOV a1, #TPSPM_IIC*2 MOV a4, #VDD1_VMODE_CFG BL TPSRead CMP a1, #0 BNE %FT20 LDRB ip, [a2] [ DebugCPUClk DebugReg ip, "VDD1_VMODE_CFG=" ] BIC lr, ip, #1 ORR lr, lr, #2 CMP lr, ip BEQ %FT10 STRB lr, [a2] MOV a1, #TPSPM_IIC*2 BL TPSWrite CMP a1, #0 BNE %FT20 10 ; Ensure smartreflex is disabled in the TPS MOV a1, #TPSPM_IIC*2 MOV a4, #DCDC_GLOBAL_CFG BL TPSRead CMP a1, #0 BNE %FT20 LDRB ip, [a2] TST ip, #1<<3 BEQ %FT20 BIC ip, ip, #1<<3 STRB ip, [a2] MOV a1, #TPSPM_IIC*2 BL TPSWrite 20 CMP a1, #0 ADD sp, sp, #4 EXIT NE ; TODO - Extra setup steps: ; - Ensure DSP is off ; - Ensure VMODE is off (CPU side) ; - Ensure smartreflex is off (CPU side) ; Go to max speed MOV a1, v3 MVN a2, #0 STR a2, CPUClkNewSpeed LDR a2, CPUClkOPPTblSize BL CPUClk_Set [ DebugCPUClk DebugTX "CPUClk_PreInit done" ] EXIT CPUClk_Init ROUT ; Register device with OS ; Note if smartreflex is in use, this will be the smartreflex device which we're registering ADRL a2, CPUClkWS LDR a3, [a2] MOV a1, #0 CMP a3, #0 ; Don't register if we didn't set up the device (e.g. unknown OMAP type) MOVEQ pc, lr CallOS OS_AddDevice,tailcall CPUClk_PreReset ; Call the appropriate shutdown function ADRL a1, CPUClkWS LDR a2, CPUClkShutdown TEQ a2, #0 MOVNE pc, a2 MOV pc, lr MACRO OPPTblEntry $mhz,$vdd1,$clkout_m2 ; VDD1 specified in mV DCW $mhz DCB ((($vdd1-600)*10)+124)/125 ; VDD1_VSEL = ((V-0.6)+0.0124)/0.0125 DCB $clkout_m2 MEND OPPTbl_OMAP35x OPPTblEntry 125, 0985, 1 ; OPP1 OPPTblEntry 250, 1060, 1 ; OPP2 OPPTblEntry 500, 1200, 1 ; OPP3 OPPTblEntry 550, 1270, 1 ; OPP4 OPPTblEntry 600, 1350, 1 ; OPP5 End_OPPTbl_OMAP35x OPPTblEntry 500, 1200, 1 ; Shutdown setting: OPP3 @ 1.2V OPPTbl_AMDM37x OPPTblEntry 300, 0970, 2 ; OPP50 OPPTblEntry 600, 1140, 1 ; OPP100 OPPTblEntry 800, 1270, 1 ; OPP130 End_OPPTbl_AMDM37x OPPTblEntry 600, 1200, 1 ; Shutdown setting: OPP100 @ 1.2V MACRO CPUListEntry $hawkeye, $list DCD $hawkeye ASSERT (End_$list-$list)/OPPTbl_Size <= OPPTbl_Max DCD (End_$list-$list)/OPPTbl_Size DCD $list MEND CPUList CPUListEntry HAWKEYE_OMAP35x_ES10, OPPTbl_OMAP35x CPUListEntry HAWKEYE_OMAP35x, OPPTbl_OMAP35x CPUListEntry HAWKEYE_AMDM37x, OPPTbl_AMDM37x DCD 0 CPUClkDevTemplate DCW HALDeviceType_SysPeri + HALDeviceSysPeri_CPUClk DCW HALDeviceID_CPUClk_OMAP3 DCD HALDeviceBus_Peri + HALDevicePeriBus_Sonics3220 DCD 0 ; API version DCD CPUClk_Desc ; Description DCD 0 ; Address - unused % 12 ; Unused DCD CPUClk_Activate DCD CPUClk_Deactivate DCD CPUClk_Reset DCD CPUClk_Sleep DCD -1 ; Device - unused DCD 0 ; TestIRQ DCD 0 ; ClearIRQ % 4 ASSERT (.-CPUClkDevTemplate) = HALDeviceSize DCD CPUClk_NumSpeeds DCD CPUClk_Info DCD CPUClk_Get DCD CPUClk_Set DCD CPUClk_Override ASSERT (.-CPUClkDevTemplate) = HALDevice_CPUClk_Size CPUClk_Desc = "OMAP3 CPU clock generator",0 ALIGN CPUClk_Activate ; Do nothing MOV a1, #1 CPUClk_Deactivate CPUClk_Reset MOV pc, lr CPUClk_Sleep MOV a1, #0 MOV pc, lr CPUClk_NumSpeeds ; Out: a1 = num entries in table LDR a1, CPUClkOPPTblSize MOV pc, lr CPUClk_Info ; In: a2 = table index ; Out: a1 = MHz ADR a3, CPUClkOPPTbl ASSERT OPPTbl_Size = 4 ASSERT OPPTbl_MHz = 0 ADD a3, a3, a2, LSL #2 LDRH a1, [a3] MOV pc, lr CPUClk_Get ; Return current table index EntryS "sb" CPSID i ; Prevent speed changing while we're reading it LDR a2, CPUClkNewSpeed LDR sb, CPUClkWorkspace CMP a2, #-1 ; Are we changing speed? BLNE CPUClk_Set ; Yes, complete the change so that the returned value is accurate ADRL a2, CPUClkWS LDR a1, CPUClkCurSpeed EXITS CPUClk_Set ROUT ; a2 = new table index ; Return 0 on success, -1 on failure EntryS "v1-v5,sb", 4 ; Turn IRQs off so that we only have to worry about being re-entered during IIC ops ; Keeping IRQs off will also help reduce the time spent with the DPLL unlocked CPSID i ; Clamp a2, get table entry LDR sb, CPUClkWorkspace CMP a2, #0 LDR v3, CPUClkOPPTblSize MOVLT a2, #0 ADR v2, CPUClkOPPTbl CMP a2, v3 SUBGE a2, v3, #1 ASSERT OPPTbl_Size = 4 ASSERT OPPTbl_MHz = 0 ADD v2, v2, a2, LSL #2 10 LDRH v3, [v2, #OPPTbl_MHz] ; a2 = new idx ; v2 = OPP table entry ptr ; v3 = new clock rate [ DebugCPUClk DebugReg a2,"CPUClk_Set: Idx=" DebugReg v2,"OPPTbl ptr=" DebugReg v3,"New rate=" LDR a3, CPUClkNewSpeed DebugReg a3,"Re-entrancy flag=" ] ; Set the re-entrancy flag STR a2, CPUClkNewSpeed ; Get current VDD1 LDR v1, HALInitialised MOV a1, #TPSPM_IIC*2 MOV a2, sp MOV a3, #1 CMP v1, #0 MOV a4, #VDD1_VSEL ADREQL v1, IIC_DoOp_Poll LDRNE v1, OSentries+4*OS_IICOpV BL TPSRead CMP a1, #0 BNE %FT80 ; Check if this change has been completed/cancelled by us being re-entered ADRL a1, CPUClkWS LDR a1, CPUClkNewSpeed CMP a1, #-1 EXITS EQ,c LDRB a1, [a2] LDRB ip, [v2, #OPPTbl_VDD1] [ DebugCPUClk DebugReg a1,"VDD1 currently " DebugReg ip,"VDD1 needed " ] CMP a1, ip BHS %FT30 ; Pre-increment VDD1 [ DebugCPUClk DebugReg ip,"Increasing VDD1 to " ] STRB ip, [a2] MOV a1, #TPSPM_IIC*2 BL TPSWrite CMP a1, #0 BNE %FT80 ; Check if this change has been completed/cancelled by us being re-entered ADRL a1, CPUClkWS LDR a1, CPUClkNewSpeed CMP a1, #-1 EXITS EQ,c 30 ; Adjust DPLL registers LDRB a1, [v2, #OPPTbl_CLKOUT_M2] BL CPUClk_AdjustDPLL ; v3-v5, ip corrupt ; Now check if we need to reduce VDD1 ; a2-v1 still valid from earlier LDRB a1, [a2] LDRB ip, [v2, #OPPTbl_VDD1] CMP a1, ip BEQ %FT70 [ DebugCPUClk DebugReg ip,"Decreasing VDD1 to " ] STRB ip, [a2] MOV a1, #TPSPM_IIC*2 BL TPSWrite CMP a1, #0 BNE %FT80 70 [ DebugCPUClk DebugTX "CPUClk_Set done" ] ; All done ; However it's still possible we were re-entered; only set CPUClkSpeed if CPUClkNewSpeed != -1 ADRL a1, CPUClkWS LDR a2, CPUClkNewSpeed CMP a2, #-1 STRNE a2, CPUClkCurSpeed MVN a3, #0 STR a3, CPUClkNewSpeed MOV a1, #0 EXITS ,c 80 ; Something bad happened! [ DebugCPUClk DebugReg a1,"IIC error! " ] ; Best we can really do is give up ADRL a2, CPUClkWS MVN a1, #0 STR a1, [a2, #:INDEX:CPUClkNewSpeed] 90 EXITS ,c CPUClk_Shutdown ALTENTRY ; Reset to default speed & voltage prior to reset/power off ; This avoids Pandora Linux often hanging on boot after RISC OS has been run CPSID i ADR v2, CPUClkOPPDefault B %BT10 CPUClk_Override ROUT EntryS CPSID i ; a2 = table ptr ; a3 = num entries ; a4 = format no. CMP a4, #OPPTbl_Format BNE %FT20 CMP a3, #OPPTbl_Max BGT %FT20 ; Check we aren't in the middle of setting the speed LDR ip, CPUClkNewSpeed CMP ip, #-1 MVNNE a1, #0 ; -1 for try again later EXITS NE,c ; Update table ASSERT OPPTbl_Size = 4 STR a3, CPUClkOPPTblSize ADR ip, CPUClkOPPTbl 10 LDR a4, [a2], #4 SUBS a3, a3, #1 STR a4, [ip], #4 BNE %BT10 20 MOV a1, #OPPTbl_Format ; Return expected table format EXITS ,c CPUClk_AdjustDPLL ROUT ; Common routine shared with SmartReflex driver ; In: ; a1 = new CLKOUT_M2 setting ; v3 = new MHz value ; sb = HAL workspace ; IRQs disabled ; Out: ; v3-v5, ip corrupt Entry MUL v3, a1, v3 LDR ip, L4_ClockMan_Log LDR lr, [ip, #CM_CLKSEL1_PLL_MPU] MOV v4, lr BFI v4, v3, #8, #11 ; Update MPU_DPLL_MULT LDR v5, [ip, #CM_CLKSEL2_PLL_MPU] LDR v3, [ip, #CM_CLKEN_PLL_MPU] ; v4 = new CM_CLKSEL1_PLL_MPU ; a1 = new CM_CLKSEL2_PLL_MPU ; lr = old CM_CLKSEL1_PLL_MPU ; v5 = old CM_CLKSEL2_PLL_MPU [ DebugCPUClk Push "lr" DebugReg v4, "New CM_CLKSEL1_PLL_MPU=" DebugReg a1, "New CM_CLKSEL2_PLL_MPU=" LDR lr,[sp] DebugReg lr, "Old CM_CLKSEL1_PLL_MPU=" DebugReg v5, "Old CM_CLKSEL2_PLL_MPU=" Pull "lr" ] CMP v4, lr CMPEQ a1, v5 ANDEQ lr, v3, #7 CMPEQ lr, #7 BEQ %FT60 ; No parameters need updating, skip the update [ DebugCPUClk DebugTX "Going to bypass mode" ] ; Go to bypass mode MOV lr, #5 BFI v3, lr, #0, #3 STR v3, [ip, #CM_CLKEN_PLL_MPU] ; Wait for completion 40 LDR lr, [ip, #CM_IDLEST_PLL_MPU] TST lr, #1 BNE %BT40 [ DebugCPUClk DebugTX "Setting new clock rate" ] ; Set new frequency STR v4, [ip, #CM_CLKSEL1_PLL_MPU] STR a1, [ip, #CM_CLKSEL2_PLL_MPU] [ DebugCPUClk DebugTX "Requesting lock" ] ; Request lock ORR v3, v3, #7 STR v3, [ip, #CM_CLKEN_PLL_MPU] ; Wait for completion 50 LDR lr, [ip, #CM_IDLEST_PLL_MPU] TST lr, #1 BEQ %BT50 [ DebugCPUClk DebugTX "Lock complete" ] 60 EXIT END