; 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.
;
; This is currently set up to provide only 1 serial port - UART3

        EXPORT  HAL_UARTPorts
        EXPORT  HAL_UARTStartUp
        EXPORT  HAL_UARTShutdown
        EXPORT  HAL_UARTFeatures
        EXPORT  HAL_UARTReceiveByte
        EXPORT  HAL_UARTTransmitByte
        EXPORT  HAL_UARTLineStatus
        EXPORT  HAL_UARTInterruptEnable
        EXPORT  HAL_UARTRate
        EXPORT  HAL_UARTFormat
        EXPORT  HAL_UARTFIFOSize
        EXPORT  HAL_UARTFIFOClear
        EXPORT  HAL_UARTFIFOEnable
        EXPORT  HAL_UARTFIFOThreshold
        EXPORT  HAL_UARTInterruptID
        EXPORT  HAL_UARTBreak
        EXPORT  HAL_UARTModemControl
        EXPORT  HAL_UARTModemStatus
        EXPORT  HAL_UARTDevice

        GET     Hdr:ListOpts
        GET     Hdr:Macros
        GET     Hdr:System
        GET     Hdr:Machine.<Machine>
        GET     Hdr:ImageSize.<ImageSize>

        GET     Hdr:Proc
        GET     Hdr:OSEntries

        GET     hdr.omap3530
        GET     hdr.StaticWS
        GET     hdr.UART

; Put base address into the a1, given port number in a1
        MACRO
$label  BaseAddr
        LDR     a1, L4_UART3_Log
        MEND

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

; int Ports(void)
;
;   Return array of UART port physical addresses.
;
HAL_UARTPorts
        MOV     a1, #1
        MOV     pc, lr

; void StartUp(int port)
;
HAL_UARTStartUp
        BaseAddr
        MOV     a2, #0
        STRB    a2, [a1, #UART_IER]
        STRB    a2, [a1, #UART_FCR]
        STRB    a2, UARTFCRSoftCopy
        MOV     a2, #OUT2
        STRB    a2, [a1, #UART_MCR]
        MOV     a2, #WLS_8
        STRB    a2, [a1, #UART_LCR]
        MOV     pc, lr

; void Shutdown(int port)
;
HAL_UARTShutdown
        BaseAddr
        MOV     a2, #0
        STRB    a2, [a1, #UART_IER]
        STRB    a2, [a1, #UART_FCR]
        STRB    a2, [a1, #UART_MCR]
        MOV     pc, lr

; int Features(int port)
;
;      Bit 0:  FIFOs available
;      Bit 1:  DMA available
;      Bit 2:  Modem lines available
;
HAL_UARTFeatures
        MOV     a1, #2_101
        MOV     pc, lr

; int ReceiveByte(int port, int *status)
;
;   Returns the next byte from the FIFO (if enabled) or the holding register.
;   If status is non-NULL, the line status associated with the byte is
;   read (see LineStatus). The return value is only meaningful if a
;   received byte is available (bit 0 of *status will be set).
;
HAL_UARTReceiveByte
        BaseAddr
        TEQ     a2, #0
        LDRNEB  a3, [a1, #UART_LSR]     ; Read int state if returning status
        LDRB    a1, [a1, #UART_RBR]
        STRNE   a3, [a2]
        MOV     pc, lr

; void TransmitByte(int port, int byte)
;
HAL_UARTTransmitByte
        BaseAddr
        STRB    a2, [a1, #UART_THR]
        MOV     pc, lr

; int LineStatus(int port)
;
;      Bit 0: Receiver Data Ready
;      Bit 1: Overrun Error
;      Bit 2: Parity Error
;      Bit 3: Framing Error
;      Bit 4: Break Error
;      Bit 5: Transmitter Holding Register Empty
;      Bit 6: Transmitter Empty (including FIFO)
;      Bit 7: FIFO contains a Parity, Framing or Break error
;
;   Parity, Framing and Break errors are associated with each byte received.
;   Whether the values reported here are associated with the last byte
;   read using ReceiveByte or with the next byte to be read is undefined.
;   You should request the status using ReceiveByte to ensure accurate
;   identification of bytes with errors.
;
;   Error bits are cleared whenever status is read, using either LineStatus
;   or ReceiveByte with status non-NULL.
;
HAL_UARTLineStatus
        BaseAddr
        LDRB    a1, [a1, #UART_LSR]
        MOV     pc, lr

; int InterruptEnable(int port, int eor, int mask)
;
;   Enables interrupts. Bits are:
;
;      Bit 0: Received Data Available (and Character Timeout)
;      Bit 1: Transmitter Holding Register Empty
;      Bit 2: Received Line Status
;      Bit 3: Modem Status
;
;   Returns previous state.
;
HAL_UARTInterruptEnable
        BaseAddr
        PHPSEI  ip, a4
        LDRB    a4, [a1, #UART_IER]
        AND     a3, a4, a3
        EOR     a3, a2, a3
        STRB    a3, [a1, #UART_IER]
        PLP     ip
        MOV     a1, a4
        MOV     pc, lr


; int Rate(int port, int baud16)
;
;   Sets the rate, in units of 1/16 of a baud. Returns the previous rate.
;   Use -1 to read.
;
HAL_UARTRate
        Entry   "v1,v3"
        BaseAddr
        PHPSEI  ip, a4
        LDRB    v3, [a1, #UART_LCR]
        ORR     a4, v3, #DLAB           ; Access divisor latch registers
        STRB    a4, [a1, #UART_LCR]

        LDRB    a3, [a1, #UART_DLL]     ; Read the current baud rate
        LDRB    a4, [a1, #UART_DLM]
        LDR     v1, =UARTCLK
        ADD     a4, a3, a4, LSL#8
        DivRem  a3, v1, a4, lr          ; a3 now contains baud rate * 16
        CMP     v1, a4, LSR#1           ; If the remainder is greater than 1/2
        ADDGE   a3, a3, #1              ; the divisor, round up
        CMN     a2, #1                  ; Don't write if we're reading!
        BEQ     %FT10

; We need to program 48MHz / (16 * baud rate)

        LDR     v1, =UARTCLK            ; This was corrupted by the above DIVREM
        DivRem  a4, v1, a2, lr
        CMP     v1, a2, LSR#1           ; If the remainder is greater than 1/2
        ADDGE   a4, a4, #1              ; the divisor, round up

        STRB    a4, [a1, #UART_DLL]
        MOV     a4, a4, LSR#8
        STRB    a4, [a1, #UART_DLM]

10      STRB    v3, [a1, #UART_LCR]     ; Turn off divisor latch access
        MOV     a1, a3                  ; Return previous state
        PLP     ip
        EXIT

; int Format(int port, int format)
;
;   Bits 0-1: Bits per word  0=>5, 1=>6, 2=>7, 3=>8
;   Bit 2:    Stop length 0=>1, 1=>2 (1.5 if 5 bits)
;   Bit 3:    Parity enabled
;   Bits 4-5: Parity:  0 => Odd (or disabled)
;                      1 => Even
;                      2 => Mark (parity bit = 1)
;                      3 => Space (parity bit = 0)
;
;   Returns previous format. -1 to read.
;

HAL_UARTFormatMask    *  SPA+EPS+PEN+STP+WLS

HAL_UARTFormat
        BaseAddr
        PHPSEI  ip, a3
        LDRB    a3, [a1, #UART_LCR]
        CMP     a2, #-1
        AND     a4, a3, #HAL_UARTFormatMask     ; a4 = relevant bits of current LCR
        BIC     a3, a3, #HAL_UARTFormatMask     ; a3 = other bits of current LCR
        ANDNE   a2, a2, #HAL_UARTFormatMask     ; a2 = relevant bits on entry
        ORRNE   a2, a2, a3
        STRNEB  a2, [a1, #UART_LCR]
        PLP     ip
        MOV     a1, a4
        MOV     pc, lr

; void FIFOSize(int port, int *rx, int *tx)
;
;   Returns the size of the RX and TX FIFOs. Either parameter may be NULL.
;   Note that the size of the TX FIFO is the total amount of data that can
;   be sent immediately when the Transmitter Holding Register Empty
;   status holds. (So an unusual UART that had a transmit threshold
;   should return total FIFO size minus threshold).
;
HAL_UARTFIFOSize
        BaseAddr
        MOV     a1, #64
        TEQ     a2, #0
        STRNE   a1, [a2]
        TEQ     a3, #0
        STRNE   a1, [a3]
        MOV     pc, lr

; void FIFOClear(int port, int flags)
;
;   Clears the input FIFO (if bit 0 set) and the output FIFO (if bit 1 set).
;
HAL_UARTFIFOClear
        BaseAddr
        AND     a2, a2, #2_11
        PHPSEI  ip, a3
        LDRB    a3, UARTFCRSoftCopy
        ORR     a3, a3, a2, LSL #1
        STRB    a3, [a1, #UART_FCR]
        PLP     ip
        MOV     pc, lr

; int FIFOEnable(int port, int enable)
;
;   Enables or disables the RX and TX FIFOs: 0 => disable, 1 => enable
;   -1 => read status. Returns previous status.
;
HAL_UARTFIFOEnable
        BaseAddr
        PHPSEI  ip, a3
        LDRB    a3, UARTFCRSoftCopy
        ASSERT  FIFOEN=1
        AND     a4, a3, #FIFOEN
        CMP     a2, #-1
        BEQ     %FT10
        CMP     a2, #0
        BICEQ   a3, a3, #FIFOEN
        ORRNE   a3, a3, #FIFOEN
        STRB    a3, [a1, #UART_FCR]
        STRB    a3, UARTFCRSoftCopy
10      MOV     a1, a4
        PLP     ip
        MOV     pc, lr

; int FIFOThreshold(int port, int threshold)
;
;   Sets the receive threshold level for the FIFO RX interrupt. For OMAP3530
;   this is 8, 16, 56 or 60 bytes. Returns previous value. -1 to read.
;
HAL_UARTFIFOThreshold
        BaseAddr
        PHPSEI  ip, a3
        LDRB    a3, UARTFCRSoftCopy
        ANDS    a4, a3, #FIFOTHR
        BIC     a3, a3, #FIFOTHR
        ASSERT  FIFOTHR_8 = 0
        MOVEQ   a4, #8
        BEQ     %FT10
        CMP     a4, #FIFOTHR_56
        MOVLO   a4, #16
        MOVEQ   a4, #56
        MOVHI   a4, #60
10      CMP     a2, #-1
        BEQ     %FT20
        CMP     a2, #16
        ADDGE   a3, a3, #FIFOTHR_16
        CMP     a2, #56
        ADDGE   a3, a3, #FIFOTHR_56-FIFOTHR_16
        CMP     a2, #60
        ADDGE   a3, a3, #FIFOTHR_60-FIFOTHR_56
        STRB    a3, [a1, #UART_FCR]
        STRB    a3, UARTFCRSoftCopy
20      MOV     a1, a4
        PLP     ip
        MOV     pc, lr

; int InterruptID(int port)
;
;   Returns the highest priority interrupt currently asserted. In order
;   of priority:
;
;   3 => Receiver Line Status (Cleared by ReceiveByte)
;   2 => Received Data Available (Cleared by reading enough data)
;   6 => Character Timeout (received data waiting)
;   1 => Transmitter Holding Register Empty (Cleared by this call)
;   0 => Modem Status (Cleared by ModemStatus)
;   -1 => No Interrupt
;
;   The Modem Status interrupt occurs when the CTS, DSR or DCD inputs
;   change, or when RI goes from high to low (ie bits 0 to 3 of ModemStatus
;   are set).
;
HAL_UARTInterruptID
        BaseAddr
        LDRB    a4, [a1, #UART_IIR]
        TST     a4, #1
        MOVEQ   a1, a4, LSR #1
        ANDEQ   a1, a1, #7
        MOVNE   a1, #-1
        MOV     pc, lr

; int Break(int port, int enable)
;
;   Activates (1) or deactivates (0) a break condition. -1 to read,
;   returns previous state.
;
HAL_UARTBreak
        BaseAddr
        PHPSEI  ip, a3
        LDRB    a3, [a1, #UART_LCR]
        ANDS    a4, a3, #BCR
        MOVNE   a4, #1
        CMP     a2, #-1
        BEQ     %FT10
        CMP     a2, #0
        BICEQ   a3, a3, #BCR
        ORRNE   a3, a3, #BCR
        STRB    a3, [a1, #UART_LCR]
10      MOV     a1, a4
        PLP     ip
        MOV     pc, lr

; int ModemControl(int port, int eor, int mask)
;
;   Modifies the modem control outputs.
;
;   Bit 0: DTR
;   Bit 1: RTS
;
;   Note that these are logical outputs, although the physical pins may be
;   inverted.  So 1 indicates a request to send.  Returns previous state.
;   Needs to clear the modem interrupt status.
;

HAL_UARTModemControl
        BaseAddr
        PHPSEI  ip, a3
        LDRB    a3, [a1, #UART_MCR]
        CMP     a2, #-1
        AND     a4, a3, #DTR+RTS                ; a4 = relevant bits of current MCR
        BIC     a3, a3, #DTR+RTS                ; a3 = other bits of current MCR
        ANDNE   a2, a2, #DTR+RTS                ; a2 = relevant bits on entry
        ORRNE   a2, a2, a3
        STRNEB  a2, [a1, #UART_MCR]
        PLP     ip
        MOV     a1, a4
        MOV     pc, lr


; int ModemStatus(int port)
;
;   Reads the modem status inputs.
;
;   Bit 0: CTS changed since last call
;   Bit 1: DSR changed since last call
;   Bit 2: RI changed from high to low since last call
;   Bit 3: DCD changed since last call
;   Bit 4: CTS
;   Bit 5: DSR
;   Bit 6: RI
;   Bit 7: DCD
;
;   Note that these are logical inputs, although the physical pins may be
;   inverted.  So 1 indicates a Clear To Send condition.  This must also clear
;   the modem interrupt status.
;
HAL_UARTModemStatus
        BaseAddr
        LDRB    a1, [a1, #UART_MSR]
        MOV     pc, lr

; int Device(int port)
;
;   Return the device number allocated to the UART port
;
HAL_UARTDevice
        MOV     a1, #74
        MOV     pc, lr

        END