RTC 8.48 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
; Copyright 2009 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:RTCDevice

        GET     hdr.omap3530
        GET     hdr.StaticWS
        GET     hdr.Timers
        GET     hdr.PRCM

        AREA    |Asm$$Code|, CODE, READONLY, PIC

        EXPORT  RTC_Init
35 36
        IMPORT  TPSRead
        IMPORT  TPSWrite
37 38 39 40 41 42 43

;       Note - debug stuff won't work since we don't get passed a HAL workspace pointer!
;        IMPORT  DebugHALPrint
;        IMPORT  DebugHALPrintReg
;        IMPORT  DebugMemDump
;        IMPORT  DebugHALPrintByte

44 45 46 47 48 49 50 51 52
; TWL/TPS RTC IIC address
TPSRTC_IIC     * &4b

; Some RTC registers
SECONDS_REG       * &1C
RTC_CTRL_REG      * &29
RTC_STATUS_REG    * &2a


53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87
        MACRO
        CallOS  $entry, $tailcall
        ASSERT  $entry <= HighestOSEntry
 [ "$tailcall"=""
        MOV     lr, pc
 |
   [ "$tailcall"<>"tailcall"
        ! 0, "Unrecognised parameter to CallOS"
   ]
 ]
        LDR     pc, OSentries + 4*$entry
        MEND

RTC_Init
        ; Just register our HAL Device with the OS
        MOV     a1, #0
        ADR     a2, RTCDevice
        CallOS  OS_AddDevice, tailcall

RTCDevice
        DCW     HALDeviceType_SysPeri + HALDeviceSysPeri_RTC
        DCW     HALDeviceID_RTC_TPS65950
        DCD     HALDeviceBus_Ser + HALDeviceSerBus_IIC
        DCD     0               ; API version
        DCD     RTCDesc
        DCD     0               ; Address - N/A
        %       12              ; Reserved
        DCD     RTCActivate
        DCD     RTCDeactivate
        DCD     RTCReset
        DCD     RTCSleep
        DCD     -1              ; Interrupt N/A
        DCD     0
        %       8
        DCB     RTCTimeFormat_BCD
88
        DCB     RTCFormatFlags_BCD_1BasedDay+RTCFormatFlags_BCD_1BasedMonth+RTCFormatFlags_BCD_YearLOIsGood ; todo - add RTCFormatFlags_BCD_NeedsYearHelp once NVRAM is implemented
89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125
        %       2
        DCD     RTCReadTime
        DCD     RTCWriteTime

RTCDesc
        DCB "TPS65950-compatible real-time clock",0

        ALIGN

RTCActivate
        MOV     a1, #1
RTCDeactivate
RTCReset
        MOV     pc, lr

RTCSleep
        MOV     a1, #0 ; Previously at full power
        MOV     pc, lr

RTCReadTime
        ; In:
        ; a1 = HALDevice ptr
        ; a2 = RTCTimeStruct ptr
        ; a3 = IICOp func ptr
        ; a4 = kernel workspace ptr
        ; Out:
        ; a1 = return code
        ; RTCTimeStruct updated
        Push    "v1-v3,lr"
        MOV     v1, a3
        MOV     v2, a4
        MOV     v3, a2
        ; Reading the time safely involves several transfers:
        ; 1. Read RTC_STATUS_REG. If bit 1 is clear, the RTC is stopped and we can just assume its contents are invalid.
        ; 2. Set RTC_CTRL_REG=&41 (RTC running, GET_TIME set, 24hr mode). GET_TIME will read the time from the RTC circuitry and latch it into the time registers (the regular time registers, NOT the alarm ones as stated by the manual!)
        ; 3. Read the time regs to read latched time.
        ; There's no need to clear GET_TIME either, as it is cleared automatically by the HW.
126
        MOV     a1, #TPSRTC_IIC*2
127 128
        SUB     sp, sp, #4 ; temp small buffer on stack
        MOV     a3, #1
129
        MOV     a4, #RTC_STATUS_REG
130 131 132 133 134 135 136 137 138 139 140 141
        MOV     a2, sp
        BL      TPSRead
        CMP     a1, #ECOMPLETED
        LDRB    ip, [a2]
        MOV     a1, #RTCRetCode_InvalidTime
        MOVNE   a1, #RTCRetCode_Error
        EOR     ip, ip, #2
        TSTEQ   ip, #2
        ADDNE   sp, sp, #4
        Pull    "v1-v3,pc", NE
        MOV     ip, #&41
        STR     ip, [a2]
142 143
        MOV     a1, #TPSRTC_IIC*2
        MOV     a4, #RTC_CTRL_REG
144 145 146 147 148
        BL      TPSWrite
        CMP     a1, #ECOMPLETED
        MOVNE   a1, #RTCRetCode_Error
        ADD     sp, sp, #4
        Pull    "v1-v3,pc", NE
149
        MOV     a1, #TPSRTC_IIC*2
150 151 152 153 154 155 156 157
        ; We can read the time directly into the RTCTimeStruct buffer
        ASSERT RTCTimeStruct_BCD_Minutes=RTCTimeStruct_BCD_Seconds+1
        ASSERT RTCTimeStruct_BCD_Hours=RTCTimeStruct_BCD_Seconds+2
        ASSERT RTCTimeStruct_BCD_DayOfMonth=RTCTimeStruct_BCD_Seconds+3
        ASSERT RTCTimeStruct_BCD_Month=RTCTimeStruct_BCD_Seconds+4
        ASSERT RTCTimeStruct_BCD_YearLO=RTCTimeStruct_BCD_Seconds+5
        ADD     a2, v3, #RTCTimeStruct_BCD_Seconds
        MOV     a3, #6
158
        MOV     a4, #SECONDS_REG
159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191
        BL      TPSRead
        CMP     a1, #ECOMPLETED
        MOVNE   a1, #RTCRetCode_Error
        Pull    "v1-v3,pc", NE
        ASSERT  ECOMPLETED = 0
        STRB    a1, [v3, #RTCTimeStruct_BCD_Centiseconds] ; No centisecond time
        ; Construct a fakey YearHI by looking at YearLO
        ; Anything 70 or above is considered 1970+, else 2000+
        ; This should work OK, since RISC OS clamps the time to 1970 for unix compatability (or it does on boot, at least)
        LDRB    a2, [v3, #RTCTimeStruct_BCD_YearLO]
        CMP     a2, #&70
        MOVGE   a3, #&19
        MOVLT   a3, #&20
        STRB    a3, [v3, #RTCTimeStruct_BCD_YearHI]
        ASSERT  RTCRetCode_OK = 0
        Pull    "v1-v3,pc"

RTCWriteTime
        ; In:
        ; a1 = HALDevice ptr
        ; a2 = RTCTimeStruct ptr
        ; a3 = IICOp func ptr
        ; a4 = kernel workspace ptr
        ; Out:
        ; a1 = return code
        Push    "v1-v3,lr"
        MOV     v1, a3
        MOV     v2, a4
        MOV     v3, a2
        ; Writing the time safely involves several transfers:
        ; 1. Write 0 to RTC_CTRL_REG to stop the clock (just in case there are any issues with the clock updating while it's being written to)
        ; 2. Write the new time values
        ; 3. Write 1 to RTC_CTRL_REG to start the clock
192
        MOV     a1, #TPSRTC_IIC*2
193 194 195
        MOV     ip, #0
        STR     ip, [sp,#-4]! ; temp small buffer on stack
        MOV     a3, #1
196
        MOV     a4, #RTC_CTRL_REG
197 198 199 200 201 202
        MOV     a2, sp
        BL      TPSWrite
        CMP     a1, #ECOMPLETED
        MOVNE   a1, #RTCRetCode_Error
        ADDNE   sp, sp, #4
        Pull    "v1-v3,pc", NE
203
        MOV     a1, #TPSRTC_IIC*2
204 205 206 207 208 209 210 211
        ; We can write the time directly from the RTCTimeStruct buffer
        ASSERT RTCTimeStruct_BCD_Minutes=RTCTimeStruct_BCD_Seconds+1
        ASSERT RTCTimeStruct_BCD_Hours=RTCTimeStruct_BCD_Seconds+2
        ASSERT RTCTimeStruct_BCD_DayOfMonth=RTCTimeStruct_BCD_Seconds+3
        ASSERT RTCTimeStruct_BCD_Month=RTCTimeStruct_BCD_Seconds+4
        ASSERT RTCTimeStruct_BCD_YearLO=RTCTimeStruct_BCD_Seconds+5
        ADD     a2, v3, #RTCTimeStruct_BCD_Seconds
        MOV     a3, #6
212
        MOV     a4, #SECONDS_REG
213 214 215 216 217 218 219 220 221 222 223
        ; Sometimes we don't write the time, so skip those bytes if necessary
        LDRB    ip, [a2]
        CMP     ip, #255
        ADDEQ   a2, a2, #3
        SUBEQ   a3, a3, #3
        ADDEQ   a4, a4, #3
        ; Sometimes we don't write the date either
        LDRB    ip, [v3, #RTCTimeStruct_BCD_DayOfMonth]
        CMP     ip, #255
        SUBEQS  a3, a3, #3
        BEQ     %FT01 ; Nothing left to write!
224 225 226 227 228
        BL      TPSWrite
        CMP     a1, #ECOMPLETED
        MOVNE   a1, #RTCRetCode_Error
        ADDNE   sp, sp, #4
        Pull    "v1-v3,pc", NE
229
01
230 231 232
        MOV     a3, #1
        STR     a3, [sp]
        MOV     a2, sp
233 234
        MOV     a4, #RTC_CTRL_REG
        MOV     a1, #TPSRTC_IIC*2
235 236 237 238 239 240 241
        BL      TPSWrite
        CMP     a1, #ECOMPLETED
        ASSERT  RTCRetCode_OK = ECOMPLETED
        MOVNE   a1, #RTCRetCode_Error
        ADD     sp, sp, #4
        Pull    "v1-v3,pc"

Jeffrey Lee's avatar
Jeffrey Lee committed
242 243 244 245 246 247 248 249 250 251 252 253 254 255
        EXPORT  ReadTimeForNVRAM
        IMPORT  IIC_DoOp_Poll

; int ReadTimeForNVRAM (struct rtctime*)
; Reads BCD time into given rtctime struct
; Returns zero on success, non-zero on failure
ReadTimeForNVRAM
        MOV     a2, a1
        ADRL    a1, RTCDevice
        LDR     a3, HALInitialised
        CMP     a3, #0
        ADREQL  a3, IIC_DoOp_Poll
        LDRNE   a3, OSentries + 4 * OS_IICOpV
        B       RTCReadTime
256 257

        END