Commit b5d4e1d0 authored by Jeffrey Lee's avatar Jeffrey Lee

Implement HAL UART API. Tidy up debug output.

Detail:
  hdr/BCM2835, hdr/StaticWS, s/Debug, s/Top, s/Video - Fix up the two serial debug switches to work correctly. Disable debug by default.
  s/UART, hdr/UART - Implement HAL UART API, for the PL011 UART.
Admin:
  Tested on Raspberry Pi 1 B
  Requires DualSerial 0.25 to work correctly


Version 0.59. Tagged as 'BCM2835-0_59'
parent 2b6c0909
/* (0.58)
/* (0.59)
*
* This file is automatically maintained by srccommit, do not edit manually.
* Last processed by srccommit version: 1.1.
*
*/
#define Module_MajorVersion_CMHG 0.58
#define Module_MajorVersion_CMHG 0.59
#define Module_MinorVersion_CMHG
#define Module_Date_CMHG 10 May 2016
#define Module_Date_CMHG 09 Oct 2016
#define Module_MajorVersion "0.58"
#define Module_Version 58
#define Module_MajorVersion "0.59"
#define Module_Version 59
#define Module_MinorVersion ""
#define Module_Date "10 May 2016"
#define Module_Date "09 Oct 2016"
#define Module_ApplicationDate "10-May-16"
#define Module_ApplicationDate "09-Oct-16"
#define Module_ComponentName "BCM2835"
#define Module_ComponentPath "mixed/RiscOS/Sources/HAL/BCM2835"
#define Module_FullVersion "0.58"
#define Module_HelpVersion "0.58 (10 May 2016)"
#define Module_LibraryVersionInfo "0:58"
#define Module_FullVersion "0.59"
#define Module_HelpVersion "0.59 (09 Oct 2016)"
#define Module_LibraryVersionInfo "0:59"
......@@ -34,12 +34,13 @@
[ :LNOT :DEF: BCM2835_Hdr
GBLL BCM2835_Hdr
GBLL HALDebug
HALDebug SETL {TRUE}
; Debugging in the serial port (HAL_DebugTX, HAL_DebugRX)
GBLL Debug
Debug SETL {TRUE}
Debug SETL {FALSE}
; Debug messages from the HAL itself
GBLL HALDebug
HALDebug SETL {FALSE} :LAND: Debug
; RPi ARM11 registers
......
......@@ -89,7 +89,7 @@ PeriBase # 4
IRQ_Base_Address # 4
ARM_Counter_IO_Address # 4
ARM_Timer_IO_Address # 4
UARTFCRSoftCopy # 4
UARTOldModemStatus # 4
MMUOffBaseAddr # 4 ; original address kernel was loaded from
MachineID # 8 ; derived from MAC address if there
......@@ -127,7 +127,6 @@ VirtGPIOBuf # 4
; align to 16 byte boundary NB this isnt aligned once hal initialised
# (((:INDEX:@)+15):AND::NOT:15)-(:INDEX:@)
! 0,"tagbuffer at ":CC::STR:(&fc001000+:INDEX:@),0
tagbuffer # 300 ; platform query buffer
NCNBAddr # 4 ;NCNB workspace
......@@ -136,9 +135,6 @@ NCNBPhysAddr # 4 ;VC physical address of NCNB workspace
OSheader # 4
OSentries # 4*(HighestOSEntry+1)
! 0,"SDHCI at ":CC::STR:(&FC0001D8+:INDEX:@),0
SDHCIWriteInterval # 4 ; minimum counter ticks between writes
SDHCILastWriteCount # 4 ; counter value at last write
SDHCIInputClock # 4 ; estimated speed of input clock to SDHCI block
......
......@@ -30,15 +30,56 @@
; its Linux drivers, thus making this port possible.
;
; not used any longer .. JB 20/2/12
UART011_DR * 0
UART011_RSR * 4
UART011_ECR * 4
UART011_CR * &30
UART011_FR * &18
UART011_FBRD * &28
UART011_IBRD * &24
UART011_LCRH * &2C
; UART clock
UARTCLK * 3000000
; UARTCR bits
CR_CTSEN * 1:SHL:16 ; Hardware CTS
CR_RTSEN * 1:SHL:15 ; Hardware RTS
CR_RTS * 1:SHL:11 ; RTS
CR_RXE * 1:SHL:9 ; RX enable
CR_TXE * 1:SHL:8 ; TX enable
CR_LBE * 1:SHL:7 ; Loopback
CR_UARTEN * 1:SHL:0 ; UART enable
; UARTLCRH bits
LCRH_SPS * 1:SHL:7 ; Sticky parity
LCRH_WLEN * 3:SHL:5 ; Word length
LCRH_WLEN_shift * 5
LCRH_FEN * 1:SHL:4 ; FIFO enable
LCRH_STP2 * 1:SHL:3 ; 2 stop bits
LCRH_EPS * 1:SHL:2 ; Even parity
LCRH_PEN * 1:SHL:1 ; Parity enable
LCRH_BRK * 1:SHL:0 ; Break enable
; UARTFLAG bit assignments
FLAG_TXFE * 7 ; TX FIFO empty
FLAG_RXFF * 6 ; RX FIFO full
FLAG_TXFF * 5 ; TX FIFO full
FLAG_RXFE * 4 ; RX FIFO empty
FLAG_BUSY * 3 ; UART busy transmitting
FLAG_CTS * 0
; UARTDR bit assignments
DR_OE * 11 ; Overrun error
DR_BE * 10 ; Break error
DR_PE * 9 ; Parity error
DR_FE * 8 ; Framing error
; UARTRSRECR bit assignments
RSR_OE * 3 ; Overrun error
RSR_BE * 2 ; Break error
RSR_PE * 1 ; Parity error
RSR_FE * 0 ; Framing error
; UARTIMSC, UARTRIS, UARTMIS, UARTICR bit assignments
UI_OE * 10 ; Overrun error
UI_BE * 9 ; Break error
UI_PE * 8 ; Parity error
UI_FE * 7 ; Framing error
UI_RT * 6 ; RX timeout
UI_TX * 5 ; TX FIFO empty threshold crossed
UI_RX * 4 ; RX FIFO full threshold crossed
UI_CTS * 1 ; CTS
END
......@@ -32,6 +32,9 @@
AREA |ARM$$code|, CODE, READONLY, PIC
GET hdr.BCM2835
[ Debug
IMPORT HAL_UARTLineStatus
IMPORT HAL_UARTTransmitByte
IMPORT HAL_UARTReceiveByte
......@@ -59,5 +62,6 @@ HAL_DebugRX stmfd sp!, {a2,lr}
tst a2, #1
mvneq a1, #0 ; -1 exit if no character
ldmfd sp!, {a2,pc}
]
END
......@@ -110,9 +110,12 @@
IMPORT HAL_UARTModemControl
IMPORT HAL_UARTModemStatus
IMPORT HAL_UARTDevice
IMPORT HAL_UARTDefault
[ Debug
IMPORT HAL_DebugRX
IMPORT HAL_DebugTX
]
IMPORT HAL_PlatformName
......@@ -438,12 +441,6 @@ clear_lp1
; OS_Start doesn't return....invokes HAL_Init after MMU activation
[ HALDebug
sign_on = "BCM2835 Raspberry Pi",13,10,0
start_os = "Starting OS",13,10,0
ALIGN
]
holding_pattern
; Auxilliary cores arrive here
; First, work out who we are
......@@ -591,8 +588,13 @@ HAL_EntryTable DATA
HALEntry HAL_Reset
[ Debug
HALEntry HAL_DebugRX
HALEntry HAL_DebugTX
|
NullEntry ; HAL_DebugRX
NullEntry ; HAL_DebugTX
]
NullEntry ; HAL_PCIFeatures
NullEntry ; HAL_PCIReadConfigByte
......@@ -637,7 +639,7 @@ HAL_EntryTable DATA
NullEntry ; HALEntry HAL_VideoFramestoreAddress
NullEntry ; HALEntry HAL_UARTDefault
HALEntry HAL_UARTDefault
NullEntry ; HALEntry HAL_VideoStartupMode
......@@ -663,11 +665,14 @@ HAL_Init
CallOS OS_MapInIO
STR a1, PeriBase
[ Debug
MOV a1,#0 ; start the uart ..we use it for debug
BL HAL_UARTStartUp ; restart to capture logical io address
[ HALDebug
bl HAL_DebugTXStrInline
DCB "HalStart from OS",10,0
]
]
ALIGN
......@@ -702,10 +707,12 @@ HAL_Init
LDR a2, VC_Base
LDR a3, VC_Size
[ HALDebug
mov r0,a2
bl HAL_DebugHexTX4
mov r0,a3
bl HAL_DebugHexTX4
]
; Get the physical address of NCNB workspace
; R8 -> start of NCNB workspace
......@@ -972,26 +979,6 @@ jbdtxh stmfd r13!,{r0-r3,lr} ; print byte as hex
addgt a1,a4,#&37
bl HAL_DebugTX
ldmfd r13!,{r0-r3,pc}
|
HAL_DebugTX
HAL_DebugS
HAL_DebugHexTX
HAL_DebugHexTX2
HAL_DebugHexTX4
MOV pc, lr
HAL_DebugTXStrInline
stmfd r13!, {r0-r3} ; lr points to prinstring, immediately
; following call, null terminated
sub r3,lr,#1
1 ldrb r0,[r3,#1]! ; pop next char, auto incr
teq r0,#0 ; terminating null
biceq lr,r3,#3 ; round down address
ldmeqfd r13!,{r0-r3}
addeq pc,lr,#4 ; return to next word
b %bt1 ; loop
]
END
......@@ -28,10 +28,6 @@
;
; With many thanks to Broadcom Europe Ltd for releasing the source code to
; its Linux drivers, thus making this port possible.
;
; NB. This is currently just a minimal implementation for driving the
; BCM2835's "mini UART" at 115k2 baud for keyboard/mouse input.
;
AREA |Asm$$Code|, CODE, READONLY, PIC
......@@ -46,6 +42,7 @@
GET hdr.BCM2835
GET hdr.StaticWS
GET hdr.UART
EXPORT HAL_UARTPorts
EXPORT HAL_UARTStartUp
......@@ -66,29 +63,61 @@
EXPORT HAL_UARTModemControl
EXPORT HAL_UARTModemStatus
EXPORT HAL_UARTDevice
EXPORT HAL_UARTDefault
; Control support for RTS/CTS. These aren't exported on the model B
; rev 1 PCB, and on future PCBs they're in awkward positions, so I
; doubt anyone makes any serious use of them. Also, this code is
; untested!
GBLL ModemControl
ModemControl SETL {FALSE}
; Put base address into the indicated register, given port number in a1
MACRO
BaseAddr $reg
LCLS r
[ "$reg" <> ""
r SETS "$reg"
|
r SETS "a1"
]
LDR $r, PeriBase
ADD $r, $r, #UART_Base :AND: :NOT: &FFFF
ADD $r, $r, #UART_Base :AND: &FFFF
MEND
; Stop the UART and wait for it to become idle
; Required before modifying UARTIBRD, UARTFBRD, UARTLCRH
MACRO
StopUART $temp
LDR $temp, [a1,#UARTCR]
BIC $temp, $temp, #CR_UARTEN
STR $temp, [a1,#UARTCR]
; Wait for transmission of current character to finish
10
LDR $temp, [a1,#UARTFLAG]
TST $temp, #1:SHL:FLAG_BUSY
BNE %BT10
MEND
; Put base address into the a1, given port number in a1
MACRO
$label BaseAddr
LDR a1, PeriBase
ADD a1, a1, #UART_Base :AND: :NOT: &FFFF
ADD a1, a1, #UART_Base :AND: &FFFF
StartUART $temp
LDR $temp, [a1,#UARTCR]
ORR $temp, $temp, #CR_UARTEN
STR $temp, [a1,#UARTCR]
MEND
; int HAL_UARTPorts(void)
;
; Return array of UART port physical addresses.
; Return number of UART ports
;
HAL_UARTPorts
; HALStub "HAL_UARTPorts"
MOV a1, #1
MOV a1, #1 ; Currently we only support the main UART (PL011-compatible)
MOV pc, lr
; void StartUp(int port)
;
HAL_UARTStartUp
ADD a3, sb, a1
DataSyncBarrier a2 ; resync before writing peripheral
LDR a2, PeriBase ; first turn on the serial pins
ADD a3, a2, #GPIO_Base ; (for setting pins up)
......@@ -96,10 +125,9 @@ HAL_UARTStartUp
BIC a2, a2, #8_00770000 ;
ORR a2, a2, #8_00440000 ; set GPIO 14 + 15 to alt0 (100)
STR a2, [a3, #GPFSel1] ;
BaseAddr
DataSyncBarrier a2 ; resync before writing peripheral
MOV a2, #0 ;(macro above zeroes the a2)
STR a2, [a1,#UARTCR]
BaseAddr
StopUART a2
MOV a2, #&68
AND a3, a2,#&3F
STR a3, [a1,#UARTFBRD]
......@@ -108,16 +136,23 @@ HAL_UARTStartUp
MOV a2, #3<<5
ORR a2, a2,#&10
STR a2, [a1,#UARTLCRH]
MOV a2, #&300
ORR a2, a2,#1
MOV a2, #(2:SHL:3)+2 ; Set default FIFO threshold of 1/2
STR a2, [a1,#UARTIFLS]
LDR a2, =CR_RXE+CR_TXE+CR_UARTEN
STR a2, [a1,#UARTCR]
DataSyncBarrier a2
MOV pc, lr
; void HAL_UARTShutdown(int port)
;
HAL_UARTShutdown
HAL_UARTShutdown ROUT
BaseAddr
MOV a2, #0
DataSyncBarrier a3
StopUART a2
; Flush FIFO
MOV a3, #0
STR a3, [a1,#UARTLCRH]
DataSyncBarrier a3
MOV pc, lr
; int HAL_UARTFeatures(int port)
......@@ -125,9 +160,15 @@ HAL_UARTShutdown
; Bit 0: FIFOs available
; Bit 1: DMA available
; Bit 2: Modem lines available
; Bit 3: Hardware RTS/CTS available
; Bit 4: Transmitter empty IRQ is actually "TX FIFO under threshold" IRQ
;
HAL_UARTFeatures
MOV a1, #2_101
[ ModemControl
MOV a1, #2_11101
|
MOV a1, #2_10001
]
MOV pc, lr
; int HAL_UARTReceiveByte(int port, int *status)
......@@ -137,28 +178,54 @@ HAL_UARTFeatures
; read (see LineStatus). The return value is only meaningful if a
; received byte is available (bit 0 of *status will be set).
;
HAL_UARTReceiveByte
STR lr, [sp, #-4]!
HAL_UARTReceiveByte ROUT
Entry
BaseAddr
DataSyncBarrier a3 ; resync after reading peripheral
LDR a3, [a1, #UARTFLAG]
MOV a4, #1
BICS a3, a4, a3, LSR #4
LDRNE ip, [a1, #UARTDR]
TSTNE ip, #&F00
STRNE a2, [a1, #UARTRSRECR] ;clear error condition
BNE rx_error
ANDS a4, a3, #1:SHL:FLAG_RXFE
MOVNE ip, #0
LDREQ ip, [a1, #UARTDR]
DataSyncBarrier lr ; resync after reading peripheral
TEQ a2, #0
STRNE a3, [a2]
DataSyncBarrier a3 ; resync after reading peripheral
AND a1, ip, #&FF
LDR pc, [sp], #4
rx_error
TEQ a2,#0
STRNE a2,[a2]
MOV a1,#0
LDR pc,[sp],#4
BEQ %FT90
; Status wanted, so clear error bits from UARTLineStatus
TST ip, #&F00
STRNE ip, [a1, #UARTRSRECR]
BL calcstatus
STR a1, [a2]
90
AND a1, ip, #255
EXIT
; In:
; a3 = UARTFLAG
; a4 = a3 AND 1:SHL:FLAG_RXFE
; ip = UARTDR
; Out:
; a1 = status flags
; a3, a4 corrupt
calcstatus
MOV a1, #1 ; Bit 0 needs inverting
TST a3, #1:SHL:FLAG_BUSY
EOR a1, a1, a4, LSR #FLAG_RXFE ; -> RDR
AND a4, a3, #1:SHL:FLAG_TXFE
ORREQ a1, a1, a4, LSR #FLAG_TXFE-6 ; -> Transmitter+FIFO empty
ORR a1, a1, a4, LSR #FLAG_TXFE-5 ; -> TX FIFO empty
AND a4, a3, #1:SHL:FLAG_TXFF
ORR a1, a1, a4, LSL #8-FLAG_TXFF ; TX FIFO full
AND a4, ip, #1:SHL:DR_OE
AND a3, ip, #1:SHL:DR_BE
ORR a1, a1, a4, LSR #DR_OE-1
AND a4, ip, #1:SHL:DR_PE
ORR a1, a1, a3, LSR #DR_BE-4
AND a3, ip, #1:SHL:DR_FE
ORR a1, a1, a4, LSR #DR_PE-2
TST ip, #(1:SHL:DR_PE)+(1:SHL:DR_FE)+(1:SHL:DR_BE)
ORR a1, a1, a3, LSR #DR_FE-3
ORRNE a1, a1, #128 ; "FIFO contains PE, FE, BE" - we can only report this for the current byte
MOV pc, lr
; void HAL_UARTTransmitByte(int port, int byte)
;
......@@ -175,9 +242,10 @@ HAL_UARTTransmitByte
; 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 5: Transmitter FIFO Empty
; Bit 6: Transmitter FIFO + hold register empty
; Bit 7: FIFO contains a Parity, Framing or Break error
; Bit 8: TX FIFO full
;
; Parity, Framing and Break errors are associated with each byte received.
; Whether the values reported here are associated with the last byte
......@@ -190,15 +258,12 @@ HAL_UARTTransmitByte
;
HAL_UARTLineStatus
BaseAddr
LDR a2, [a1, #UARTFLAG]
MOV a1, #0
TST a2, #&80
ORRNE a1, a1, #&20
EORNE a2, a2, #8
TSTNE a2, #8
ORRNE a1, a1, #&40
DataSyncBarrier a2 ; resync after reading peripheral
MOV pc, lr
LDR a3, [a1, #UARTFLAG]
LDR ip, [a1, #UARTRSRECR]
DataSyncBarrier a2 ; resync after reading/before write
MOVS ip, ip, LSL #DR_FE-RSR_FE ; Convert RSRECR to fake DR
STRNE ip, [a1, #UARTRSRECR] ; Clear any errors
B calcstatus ; Exit via calcstatus
; int HAL_UARTInterruptEnable(int port, int eor, int mask)
;
......@@ -213,6 +278,40 @@ HAL_UARTLineStatus
;
HAL_UARTInterruptEnable
BaseAddr
LDR a4, [a1, #UARTIMSC]
DataSyncBarrier ip ; resync after reading/before write
; Remap IMSC to match the API
[ ModemControl
AND ip, a4, #1:SHL:UI_CTS
MOV ip, ip, LSL #3-UI_CTS
|
MOV ip, #0
]
TST a4, #(1:SHL:UI_OE)+(1:SHL:UI_BE)+(1:SHL:UI_PE)+(1:SHL:UI_FE)
ORRNE ip, ip, #1:SHL:2
TST a4, #1:SHL:UI_TX
ORRNE ip, ip, #1:SHL:1
TST a4, #(1:SHL:UI_RT)+(1:SHL:UI_RX)
ORRNE ip, ip, #1:SHL:0
; Modify
AND a3, ip, a3
EOR a3, a3, a2
; Map back
MOV a2, #0
TST a3, #1:SHL:0
ORRNE a2, a2, #(1:SHL:UI_RT)+(1:SHL:UI_RX)
TST a3, #1:SHL:1
ORRNE a2, a2, #1:SHL:UI_TX
TST a3, #1:SHL:2
ORRNE a2, a2, #(1:SHL:UI_OE)+(1:SHL:UI_BE)+(1:SHL:UI_PE)+(1:SHL:UI_FE)
[ ModemControl
TST a3, #1:SHL:3
ORRNE a2, a2, #1:SHL:UI_CTS
]
TEQ a2, a4
STRNE a2, [a1, #UARTIMSC]
DataSyncBarrier a2
MOV a1, ip
MOV pc, lr
......@@ -221,9 +320,35 @@ HAL_UARTInterruptEnable
; Sets the rate, in units of 1/16 of a baud. Returns the previous rate.
; Use -1 to read.
;
HAL_UARTRate
HAL_UARTRate ROUT
Entry
BaseAddr
MOV pc,lr
DataSyncBarrier a3
; Get current baud
LDR a3, [a1, #UARTIBRD]
LDR a4, [a1, #UARTFBRD]
ORR a3, a4, a3, LSL #6
LDR a4, =UARTCLK*64
DivRem ip, a4, a3, lr
; Set new baud
CMP a2, #-1
BEQ %FT90
StopUART a3
LDR a3, =UARTCLK*64
ADD a3, a3, a2, LSR #1 ; Add 0.5 to round to nearest
DivRem a4, a3, a2, lr ; a4 = new divisor
AND a3, a4, #63
MOV a4, a4, LSR #6
STR a3, [a1, #UARTFBRD]
STR a4, [a1, #UARTIBRD]
; Perform a dummy write to LCRH to latch the new divisor values
LDR a3, [a1, #UARTLCRH]
STR a3, [a1, #UARTLCRH]
StartUART a3
90
DataSyncBarrier a3
MOV a1, ip
EXIT
; int HAL_UARTFormat(int port, int format)
;
......@@ -238,24 +363,56 @@ HAL_UARTRate
; Returns previous format. -1 to read.
;
HAL_UARTFormat
HAL_UARTFormat ROUT
BaseAddr
DataSyncBarrier a3
; Get current settings
LDR a3, [a1, #UARTLCRH]
AND a4, a3, #LCRH_WLEN
MOV a4, a4, LSR #LCRH_WLEN_shift
TST a3, #LCRH_STP2
ORRNE a4, a4, #1:SHL:2
TST a3, #LCRH_PEN
ORRNE a4, a4, #1:SHL:3
TST a3, #LCRH_EPS
ORRNE a4, a4, #1:SHL:4
TST a3, #LCRH_SPS
ORRNE a4, a4, #1:SHL:5
; Apply new settings
CMP a2, #-1
BEQ %FT90
StopUART ip
BIC a3, a3, #LCRH_SPS+LCRH_WLEN+LCRH_STP2+LCRH_EPS+LCRH_PEN
TST a2, #1:SHL:5
ORRNE a3, a3, #LCRH_SPS
TST a2, #1:SHL:4
ORRNE a3, a3, #LCRH_EPS
TST a2, #1:SHL:3
ORRNE a3, a3, #LCRH_PEN
TST a2, #1:SHL:2
ORRNE a3, a3, #LCRH_STP2
AND a2, a2, #3
ORR a3, a3, a2, LSL #LCRH_WLEN_shift
STR a3, [a1, #UARTLCRH]
StartUART a3
90
DataSyncBarrier a3
MOV a1, a4
MOV pc, lr
; void HAL_UARTFIFOSize(int port, int *rx, int *tx)
;
; Returns the size of the RX and TX FIFOs. Either parameter may be NULL.