github.com/usbarmory/tamago@v0.0.0-20240508072735-8612bbe1e454/soc/sifive/uart/uart.go (about)

     1  // SiFive UART driver
     2  // https://github.com/usbarmory/tamago
     3  //
     4  // Copyright (c) WithSecure Corporation
     5  // https://foundry.withsecure.com
     6  //
     7  // Use of this source code is governed by the license
     8  // that can be found in the LICENSE file.
     9  
    10  // Package uart implements a driver for SiFive UART controllers adopting the
    11  // following reference specifications:
    12  //   - FU540C00RM - SiFive FU540-C000 Manual - v1p4 2021/03/25
    13  //
    14  // This package is only meant to be used with `GOOS=tamago GOARCH=riscv64` as
    15  // supported by the TamaGo framework for bare metal Go on RISC-V SoCs, see
    16  // https://github.com/usbarmory/tamago.
    17  package uart
    18  
    19  import (
    20  	"github.com/usbarmory/tamago/bits"
    21  	"github.com/usbarmory/tamago/internal/reg"
    22  )
    23  
    24  // UART registers
    25  const (
    26  	UART_DEFAULT_BAUDRATE = 115200
    27  
    28  	// p94, Chapter 13 UART, FU540C00RM
    29  
    30  	UARTx_TXDATA = 0x0000
    31  	TXDATA_FULL  = 31
    32  	TXDATA_DATA  = 0
    33  
    34  	UARTx_RXDATA = 0x0004
    35  	RXDATA_EMPTY = 31
    36  	RXDATA_DATA  = 0
    37  
    38  	UARTx_TXCTRL = 0x0008
    39  	UARTx_RXCTRL = 0x000c
    40  )
    41  
    42  // UART represents a serial port instance.
    43  type UART struct {
    44  	// Controller index
    45  	Index int
    46  	// Base register
    47  	Base uint32
    48  
    49  	// control registers
    50  	txdata uint32
    51  	rxdata uint32
    52  	txctrl uint32
    53  	rxctrl uint32
    54  }
    55  
    56  // Init initializes and enables the UART for RS-232 mode,
    57  // p3605, 55.13.1 Programming the UART in RS-232 mode, IMX6ULLRM.
    58  func (hw *UART) Init() {
    59  	if hw.Base == 0 {
    60  		panic("invalid UART controller instance")
    61  	}
    62  
    63  	hw.txdata = hw.Base + UARTx_TXDATA
    64  	hw.rxdata = hw.Base + UARTx_RXDATA
    65  	hw.txctrl = hw.Base + UARTx_TXCTRL
    66  	hw.rxctrl = hw.Base + UARTx_RXCTRL
    67  }
    68  
    69  func (hw *UART) txFull() bool {
    70  	return reg.Get(hw.txdata, TXDATA_FULL, 1) == 1
    71  }
    72  
    73  // Tx transmits a single character to the serial port.
    74  func (hw *UART) Tx(c byte) {
    75  	for hw.txFull() {
    76  		// wait for TX FIFO to have room for a character
    77  	}
    78  	reg.Write(hw.txdata, uint32(c))
    79  }
    80  
    81  // Rx receives a single character from the serial port.
    82  func (hw *UART) Rx() (c byte, valid bool) {
    83  	rxdata := reg.Read(hw.rxdata)
    84  
    85  	if bits.Get(&rxdata, RXDATA_EMPTY, 1) == 1 {
    86  		return
    87  	}
    88  
    89  	return byte(bits.Get(&rxdata, RXDATA_DATA, 0xff)), true
    90  }
    91  
    92  // Write data from buffer to serial port.
    93  func (hw *UART) Write(buf []byte) (n int, _ error) {
    94  	for n = 0; n < len(buf); n++ {
    95  		hw.Tx(buf[n])
    96  	}
    97  
    98  	return
    99  }
   100  
   101  // Read available data to buffer from serial port.
   102  func (hw *UART) Read(buf []byte) (n int, _ error) {
   103  	var valid bool
   104  
   105  	for n = 0; n < len(buf); n++ {
   106  		buf[n], valid = hw.Rx()
   107  
   108  		if !valid {
   109  			break
   110  		}
   111  	}
   112  
   113  	return
   114  }