RISC-V/SiFive: Add uart0 driver

This commit is contained in:
Fabien Chouteau
2019-09-05 14:49:38 +02:00
committed by Fabien Chouteau
parent a8a60898a6
commit a61be055b9
10 changed files with 612 additions and 0 deletions

View File

@@ -0,0 +1,273 @@
------------------------------------------------------------------------------
-- --
-- Copyright (C) 2017-2019, AdaCore --
-- --
-- Redistribution and use in source and binary forms, with or without --
-- modification, are permitted provided that the following conditions are --
-- met: --
-- 1. Redistributions of source code must retain the above copyright --
-- notice, this list of conditions and the following disclaimer. --
-- 2. Redistributions in binary form must reproduce the above copyright --
-- notice, this list of conditions and the following disclaimer in --
-- the documentation and/or other materials provided with the --
-- distribution. --
-- 3. Neither the name of the copyright holder nor the names of its --
-- contributors may be used to endorse or promote products derived --
-- from this software without specific prior written permission. --
-- --
-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS --
-- "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT --
-- LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR --
-- A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT --
-- HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, --
-- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT --
-- LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, --
-- DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY --
-- THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT --
-- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE --
-- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. --
-- --
------------------------------------------------------------------------------
package body SiFive.UART is
-------------------
-- Set_Stop_Bits --
-------------------
procedure Set_Stop_Bits (This : in out UART_Device; To : Stop_Bits) is
Periph : aliased UART_Peripheral
with Import, Address => System'To_Address (This.Base_Address);
begin
Periph.TXCTRL.NSTOP := (case To is
when Stopbits_1 => False,
when Stopbits_2 => True);
end Set_Stop_Bits;
-------------------
-- Set_Baud_Rate --
-------------------
procedure Set_Baud_Rate (This : in out UART_Device;
CPU_Frequency : UInt32;
To : Baud_Rates)
is
Periph : aliased UART_Peripheral
with Import, Address => System'To_Address (This.Base_Address);
begin
Periph.DIV.DIV := UInt16 (CPU_Frequency / (To - 1));
end Set_Baud_Rate;
---------------
-- Enable_RX --
---------------
procedure Enable_RX (This : in out UART_Device) is
Periph : aliased UART_Peripheral
with Import, Address => System'To_Address (This.Base_Address);
begin
Periph.RXCTRL.ENABLE := True;
end Enable_RX;
---------------
-- Enable_TX --
---------------
procedure Enable_TX (This : in out UART_Device) is
Periph : aliased UART_Peripheral
with Import, Address => System'To_Address (This.Base_Address);
begin
Periph.TXCTRL.ENABLE := True;
end Enable_TX;
----------------
-- Disable_RX --
----------------
procedure Disable_RX (This : in out UART_Device) is
Periph : aliased UART_Peripheral
with Import, Address => System'To_Address (This.Base_Address);
begin
Periph.RXCTRL.ENABLE := False;
end Disable_RX;
----------------
-- Disable_TX --
----------------
procedure Disable_TX (This : in out UART_Device) is
Periph : aliased UART_Peripheral
with Import, Address => System'To_Address (This.Base_Address);
begin
Periph.TXCTRL.ENABLE := False;
end Disable_TX;
--------------------------
-- RX_Interrupt_Pending --
--------------------------
function RX_Interrupt_Pending (This : UART_Device) return Boolean
is
Periph : aliased UART_Peripheral
with Import, Address => System'To_Address (This.Base_Address);
begin
return Periph.IP.RXWM;
end RX_Interrupt_Pending;
--------------------------
-- TX_Interrupt_Pending --
--------------------------
function TX_Interrupt_Pending (This : UART_Device) return Boolean
is
Periph : aliased UART_Peripheral
with Import, Address => System'To_Address (This.Base_Address);
begin
return Periph.IP.TXWM;
end TX_Interrupt_Pending;
-------------------------
-- Enable_RX_Interrupt --
-------------------------
procedure Enable_RX_Interrupt (This : in out UART_Device) is
Periph : aliased UART_Peripheral
with Import, Address => System'To_Address (This.Base_Address);
begin
Periph.IE.RXWM := True;
end Enable_RX_Interrupt;
-------------------------
-- Enable_TX_Interrupt --
-------------------------
procedure Enable_TX_Interrupt (This : in out UART_Device) is
Periph : aliased UART_Peripheral
with Import, Address => System'To_Address (This.Base_Address);
begin
Periph.IE.TXWM := True;
end Enable_TX_Interrupt;
--------------------------
-- Disable_RX_Interrupt --
--------------------------
procedure Disable_RX_Interrupt (This : in out UART_Device) is
Periph : aliased UART_Peripheral
with Import, Address => System'To_Address (This.Base_Address);
begin
Periph.IE.RXWM := False;
end Disable_RX_Interrupt;
--------------------------
-- Disable_TX_Interrupt --
--------------------------
procedure Disable_TX_Interrupt (This : in out UART_Device) is
Periph : aliased UART_Peripheral
with Import, Address => System'To_Address (This.Base_Address);
begin
Periph.IE.TXWM := False;
end Disable_TX_Interrupt;
------------------------------
-- Set_Interrupt_Thresholds --
------------------------------
procedure Set_Interrupt_Thresholds (This : in out UART_Device;
RX, TX : UInt3)
is
Periph : aliased UART_Peripheral
with Import, Address => System'To_Address (This.Base_Address);
begin
Periph.TXCTRL.TXCNT := TX;
Periph.RXCTRL.RXCNT := RX;
end Set_Interrupt_Thresholds;
--------------
-- Transmit --
--------------
overriding
procedure Transmit
(This : in out UART_Device;
Data : UART_Data_8b;
Status : out UART_Status;
Timeout : Natural := 1000)
is
pragma Unreferenced (Timeout);
Periph : aliased UART_Peripheral
with Import, Address => System'To_Address (This.Base_Address);
begin
for Elt of Data loop
while Periph.TXDATA.FULL loop
null;
end loop;
Periph.TXDATA.DATA := Elt;
end loop;
Status := Ok;
end Transmit;
--------------
-- Transmit --
--------------
overriding
procedure Transmit
(This : in out UART_Device;
Data : UART_Data_9b;
Status : out UART_Status;
Timeout : Natural := 1000)
is
begin
raise Program_Error with "FE310 UART only support 8bit mode";
end Transmit;
-------------
-- Receive --
-------------
overriding
procedure Receive
(This : in out UART_Device;
Data : out UART_Data_8b;
Status : out UART_Status;
Timeout : Natural := 1000)
is
pragma Unreferenced (Timeout);
Periph : aliased UART_Peripheral
with Import, Address => System'To_Address (This.Base_Address);
Data_Reg : RXDATA_Register;
begin
for Elt of Data loop
loop
Data_Reg := Periph.RXDATA;
exit when not Data_Reg.EMPTY;
end loop;
Elt := Data_Reg.DATA;
end loop;
Status := Ok;
end Receive;
-------------
-- Receive --
-------------
overriding
procedure Receive
(This : in out UART_Device;
Data : out UART_Data_9b;
Status : out UART_Status;
Timeout : Natural := 1000)
is
begin
raise Program_Error with "FE310 UART only support 8bit mode";
end Receive;
end SiFive.UART;

View File

@@ -0,0 +1,289 @@
------------------------------------------------------------------------------
-- --
-- Copyright (C) 2017-2019, AdaCore --
-- --
-- Redistribution and use in source and binary forms, with or without --
-- modification, are permitted provided that the following conditions are --
-- met: --
-- 1. Redistributions of source code must retain the above copyright --
-- notice, this list of conditions and the following disclaimer. --
-- 2. Redistributions in binary form must reproduce the above copyright --
-- notice, this list of conditions and the following disclaimer in --
-- the documentation and/or other materials provided with the --
-- distribution. --
-- 3. Neither the name of the copyright holder nor the names of its --
-- contributors may be used to endorse or promote products derived --
-- from this software without specific prior written permission. --
-- --
-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS --
-- "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT --
-- LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR --
-- A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT --
-- HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, --
-- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT --
-- LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, --
-- DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY --
-- THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT --
-- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE --
-- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. --
-- --
------------------------------------------------------------------------------
with System.Storage_Elements;
with HAL; use HAL;
with HAL.UART; use HAL.UART;
private with System;
package SiFive.UART is
type UART_Device
(Base_Address : System.Storage_Elements.Integer_Address)
is
limited new HAL.UART.UART_Port with private;
type Stop_Bits is (Stopbits_1, Stopbits_2);
procedure Set_Stop_Bits (This : in out UART_Device; To : Stop_Bits);
subtype Baud_Rates is UInt32;
procedure Set_Baud_Rate (This : in out UART_Device;
CPU_Frequency : UInt32;
To : Baud_Rates);
procedure Enable_RX (This : in out UART_Device);
procedure Enable_TX (This : in out UART_Device);
procedure Disable_RX (This : in out UART_Device);
procedure Disable_TX (This : in out UART_Device);
function RX_Interrupt_Pending (This : UART_Device) return Boolean;
-- The interrupt flag is set when the RX fifo is strictly greater than the
-- threshold (default to 0).
--
-- The flag is cleared by the hardware when enough data have been dequeued.
function TX_Interrupt_Pending (This : UART_Device) return Boolean;
-- The interrupt flag is set when the TX fifo is strictly less than the
-- threshold (default to 0).
--
-- The flag is cleared by the hardware when enough data have been enqueued.
procedure Enable_RX_Interrupt (This : in out UART_Device);
procedure Enable_TX_Interrupt (This : in out UART_Device);
procedure Disable_RX_Interrupt (This : in out UART_Device);
procedure Disable_TX_Interrupt (This : in out UART_Device);
procedure Set_Interrupt_Thresholds (This : in out UART_Device;
RX, TX : UInt3);
---------------
-- HAL.GPIO --
---------------
overriding
function Data_Size (Port : UART_Device) return UART_Data_Size
is (Data_Size_8b);
-- FE310 UARTs are 8bits only
overriding
procedure Transmit
(This : in out UART_Device;
Data : UART_Data_8b;
Status : out UART_Status;
Timeout : Natural := 1000);
overriding
procedure Transmit
(This : in out UART_Device;
Data : UART_Data_9b;
Status : out UART_Status;
Timeout : Natural := 1000);
overriding
procedure Receive
(This : in out UART_Device;
Data : out UART_Data_8b;
Status : out UART_Status;
Timeout : Natural := 1000);
overriding
procedure Receive
(This : in out UART_Device;
Data : out UART_Data_9b;
Status : out UART_Status;
Timeout : Natural := 1000);
private
---------------
-- Registers --
---------------
subtype TXDATA_DATA_Field is HAL.UInt8;
-- Transmit Data Register.
type TXDATA_Register is record
DATA : TXDATA_DATA_Field := 16#0#;
-- unspecified
Reserved_8_30 : HAL.UInt23 := 16#0#;
FULL : Boolean := False;
end record
with Volatile_Full_Access, Size => 32,
Bit_Order => System.Low_Order_First;
for TXDATA_Register use record
DATA at 0 range 0 .. 7;
Reserved_8_30 at 0 range 8 .. 30;
FULL at 0 range 31 .. 31;
end record;
subtype RXDATA_DATA_Field is HAL.UInt8;
-- Receive Data Register.
type RXDATA_Register is record
DATA : RXDATA_DATA_Field := 16#0#;
-- unspecified
Reserved_8_30 : HAL.UInt23 := 16#0#;
EMPTY : Boolean := False;
end record
with Volatile_Full_Access, Size => 32,
Bit_Order => System.Low_Order_First;
for RXDATA_Register use record
DATA at 0 range 0 .. 7;
Reserved_8_30 at 0 range 8 .. 30;
EMPTY at 0 range 31 .. 31;
end record;
subtype TXCTRL_TXCNT_Field is HAL.UInt3;
-- Transmit Control Register.
type TXCTRL_Register is record
ENABLE : Boolean := False;
NSTOP : Boolean := False;
-- unspecified
Reserved_2_15 : HAL.UInt14 := 16#0#;
TXCNT : TXCTRL_TXCNT_Field := 16#0#;
-- unspecified
Reserved_19_31 : HAL.UInt13 := 16#0#;
end record
with Volatile_Full_Access, Size => 32,
Bit_Order => System.Low_Order_First;
for TXCTRL_Register use record
ENABLE at 0 range 0 .. 0;
NSTOP at 0 range 1 .. 1;
Reserved_2_15 at 0 range 2 .. 15;
TXCNT at 0 range 16 .. 18;
Reserved_19_31 at 0 range 19 .. 31;
end record;
subtype RXCTRL_RXCNT_Field is HAL.UInt3;
-- Receive Control Register.
type RXCTRL_Register is record
ENABLE : Boolean := False;
-- unspecified
Reserved_1_15 : HAL.UInt15 := 16#0#;
RXCNT : RXCTRL_RXCNT_Field := 16#0#;
-- unspecified
Reserved_19_31 : HAL.UInt13 := 16#0#;
end record
with Volatile_Full_Access, Size => 32,
Bit_Order => System.Low_Order_First;
for RXCTRL_Register use record
ENABLE at 0 range 0 .. 0;
Reserved_1_15 at 0 range 1 .. 15;
RXCNT at 0 range 16 .. 18;
Reserved_19_31 at 0 range 19 .. 31;
end record;
-- Interrupt Pending Register.
type IP_Register is record
TXWM : Boolean := False;
RXWM : Boolean := False;
-- unspecified
Reserved_2_31 : HAL.UInt30 := 16#0#;
end record
with Volatile_Full_Access, Size => 32,
Bit_Order => System.Low_Order_First;
for IP_Register use record
TXWM at 0 range 0 .. 0;
RXWM at 0 range 1 .. 1;
Reserved_2_31 at 0 range 2 .. 31;
end record;
-- Interrupt Enable Register.
type IE_Register is record
TXWM : Boolean := False;
RXWM : Boolean := False;
-- unspecified
Reserved_2_31 : HAL.UInt30 := 16#0#;
end record
with Volatile_Full_Access, Size => 32,
Bit_Order => System.Low_Order_First;
for IE_Register use record
TXWM at 0 range 0 .. 0;
RXWM at 0 range 1 .. 1;
Reserved_2_31 at 0 range 2 .. 31;
end record;
subtype DIV_DIV_Field is HAL.UInt16;
-- Baud Rate Divisor Register (BAUD = Fin / (DIV + 1)).
type DIV_Register is record
DIV : DIV_DIV_Field := 16#0#;
-- unspecified
Reserved_16_31 : HAL.UInt16 := 16#0#;
end record
with Volatile_Full_Access, Size => 32,
Bit_Order => System.Low_Order_First;
for DIV_Register use record
DIV at 0 range 0 .. 15;
Reserved_16_31 at 0 range 16 .. 31;
end record;
-----------------
-- Peripherals --
-----------------
-- Universal Asynchronous Receiver/Transmitter.
type UART_Peripheral is record
-- Transmit Data Register.
TXDATA : aliased TXDATA_Register;
-- Receive Data Register.
RXDATA : aliased RXDATA_Register;
-- Transmit Control Register.
TXCTRL : aliased TXCTRL_Register;
-- Receive Control Register.
RXCTRL : aliased RXCTRL_Register;
-- Interrupt Pending Register.
IP : aliased IP_Register;
-- Interrupt Enable Register.
IE : aliased IE_Register;
-- Baud Rate Divisor Register (BAUD = Fin / (DIV + 1)).
DIV : aliased DIV_Register;
end record
with Volatile;
for UART_Peripheral use record
TXDATA at 16#0# range 0 .. 31;
RXDATA at 16#4# range 0 .. 31;
TXCTRL at 16#8# range 0 .. 31;
RXCTRL at 16#C# range 0 .. 31;
IP at 16#10# range 0 .. 31;
IE at 16#14# range 0 .. 31;
DIV at 16#18# range 0 .. 31;
end record;
type UART_Device
(Base_Address : System.Storage_Elements.Integer_Address)
is
limited new HAL.UART.UART_Port with null record;
end SiFive.UART;

View File

@@ -2,6 +2,7 @@ with SiFive.GPIO; use SiFive.GPIO;
with SiFive.SPI; use SiFive.SPI;
with SiFive.PWM; use SiFive.PWM;
with System; use System;
with SiFive.UART; use SiFive.UART;
package SiFive.Device is
@@ -50,4 +51,12 @@ package SiFive.Device is
with Import, Address => System'To_Address (268570624);
PWM1 : aliased SiFive.PWM.PWM_Device (PWM1_Internal'Access);
-- UART0 --
UART0 : aliased SiFive.UART.UART_Device (268500992);
-- UART1 --
UART1 : aliased SiFive.UART.UART_Device (268505088);
end SiFive.Device;

View File

@@ -2,6 +2,7 @@ with SiFive.GPIO; use SiFive.GPIO;
with SiFive.SPI; use SiFive.SPI;
with SiFive.PWM; use SiFive.PWM;
with System; use System;
with SiFive.UART; use SiFive.UART;
package SiFive.Device is
@@ -50,4 +51,12 @@ package SiFive.Device is
with Import, Address => System'To_Address (268570624);
PWM1 : aliased SiFive.PWM.PWM_Device (PWM1_Internal'Access);
-- UART0 --
UART0 : aliased SiFive.UART.UART_Device (268500992);
-- UART1 --
UART1 : aliased SiFive.UART.UART_Device (268505088);
end SiFive.Device;

View File

@@ -2,6 +2,7 @@ with SiFive.GPIO; use SiFive.GPIO;
with SiFive.SPI; use SiFive.SPI;
with SiFive.PWM; use SiFive.PWM;
with System; use System;
with SiFive.UART; use SiFive.UART;
package SiFive.Device is
@@ -50,4 +51,12 @@ package SiFive.Device is
with Import, Address => System'To_Address (268570624);
PWM1 : aliased SiFive.PWM.PWM_Device (PWM1_Internal'Access);
-- UART0 --
UART0 : aliased SiFive.UART.UART_Device (268500992);
-- UART1 --
UART1 : aliased SiFive.UART.UART_Device (268505088);
end SiFive.Device;

View File

@@ -96,6 +96,7 @@ library project Unleashed_Full is
Src_Dirs_Root & "/arch/RISC-V/SiFive/", -- From MCU definition
Src_Dirs_Root & "/arch/RISC-V/SiFive/drivers/spi0", -- From MCU definition
Src_Dirs_Root & "/arch/RISC-V/SiFive/drivers/pwm0", -- From MCU definition
Src_Dirs_Root & "/arch/RISC-V/SiFive/drivers/uart0", -- From MCU definition
Src_Dirs_Root & "/middleware/src/filesystem", -- From middleware config
Src_Dirs_Root & "/middleware/src/BLE", -- From middleware config
Src_Dirs_Root & "/middleware/src/utils", -- From middleware config

View File

@@ -96,6 +96,7 @@ library project Unleashed_SFP is
Src_Dirs_Root & "/arch/RISC-V/SiFive/", -- From MCU definition
Src_Dirs_Root & "/arch/RISC-V/SiFive/drivers/spi0", -- From MCU definition
Src_Dirs_Root & "/arch/RISC-V/SiFive/drivers/pwm0", -- From MCU definition
Src_Dirs_Root & "/arch/RISC-V/SiFive/drivers/uart0", -- From MCU definition
Src_Dirs_Root & "/middleware/src/filesystem", -- From middleware config
Src_Dirs_Root & "/middleware/src/BLE", -- From middleware config
Src_Dirs_Root & "/middleware/src/utils", -- From middleware config

View File

@@ -96,6 +96,7 @@ library project Unleashed_ZFP is
Src_Dirs_Root & "/arch/RISC-V/SiFive/", -- From MCU definition
Src_Dirs_Root & "/arch/RISC-V/SiFive/drivers/spi0", -- From MCU definition
Src_Dirs_Root & "/arch/RISC-V/SiFive/drivers/pwm0", -- From MCU definition
Src_Dirs_Root & "/arch/RISC-V/SiFive/drivers/uart0", -- From MCU definition
Src_Dirs_Root & "/middleware/src/filesystem", -- From middleware config
Src_Dirs_Root & "/middleware/src/BLE", -- From middleware config
Src_Dirs_Root & "/middleware/src/utils", -- From middleware config

View File

@@ -16,6 +16,8 @@ class U540(SOC):
self.add(SiFivePWM_0(0x10020000, 0x1000, '0'))
self.add(SiFivePWM_0(0x10021000, 0x1000, '1'))
self.add(SiFiveUART_0(0x10010000, 0x1000, '0'))
self.add(SiFiveUART_0(0x10011000, 0x1000, '1'))
def list_of_devices(config):

View File

@@ -132,3 +132,21 @@ class SiFivePWM_0(SiFive):
out += " PWM%s : aliased SiFive.PWM.PWM_Device (PWM%s_Internal'Access);\n"\
% (self._port_id, self._port_id)
return out + "\n"
class SiFiveUART_0(SiFive):
def __init__(self, base_addr, size, port_id):
super(SiFiveUART_0, self).__init__()
self._port_id = port_id
self.set_reg(base_addr, size);
self.add_source_dir('arch/RISC-V/SiFive/drivers/uart0');
self.add_dependency("SiFive.UART")
self.add_dependency("System")
def generate_device_spec(self):
out = " -- UART%s --\n\n" % self._port_id
out += " UART%s : aliased SiFive.UART.UART_Device (%d);\n" \
% (self._port_id, self._base_addr)
return out + "\n"