riscv32: riscv-privilege: Microsemi Mi-V support
This commit adds support for Microsemi Mi-V RISC-V softcore CPU running on the M2GL025 IGLOO2 FPGA development board. signed-off-by: Karol Gugala <kgugala@antmicro.com>
This commit is contained in:
parent
23a5b5d171
commit
1765d75ff4
19 changed files with 733 additions and 2 deletions
1
arch/riscv32/soc/riscv-privilege/miv/CMakeLists.txt
Normal file
1
arch/riscv32/soc/riscv-privilege/miv/CMakeLists.txt
Normal file
|
@ -0,0 +1 @@
|
|||
zephyr_sources()
|
|
@ -0,0 +1,47 @@
|
|||
if SOC_SERIES_RISCV32_MIV
|
||||
|
||||
config SOC_SERIES
|
||||
string
|
||||
default "miv"
|
||||
|
||||
config SYS_CLOCK_HW_CYCLES_PER_SEC
|
||||
int
|
||||
default 660000
|
||||
|
||||
config RISCV_SOC_INTERRUPT_INIT
|
||||
bool
|
||||
default y
|
||||
|
||||
config RISCV_HAS_CPU_IDLE
|
||||
bool
|
||||
default y
|
||||
|
||||
config RISCV_HAS_PLIC
|
||||
bool
|
||||
default y
|
||||
|
||||
config NUM_IRQS
|
||||
int
|
||||
default 42
|
||||
|
||||
config XIP
|
||||
bool
|
||||
default y
|
||||
|
||||
config RISCV_ROM_BASE_ADDR
|
||||
hex
|
||||
default 0x80000000
|
||||
|
||||
config RISCV_ROM_SIZE
|
||||
hex
|
||||
default 0x40000
|
||||
|
||||
config RISCV_RAM_BASE_ADDR
|
||||
hex
|
||||
default 0x80040000
|
||||
|
||||
config RISCV_RAM_SIZE
|
||||
hex
|
||||
default 0x40000
|
||||
|
||||
endif # SOC_SERIES_RISCV32_MIV
|
11
arch/riscv32/soc/riscv-privilege/miv/Kconfig.series
Normal file
11
arch/riscv32/soc/riscv-privilege/miv/Kconfig.series
Normal file
|
@ -0,0 +1,11 @@
|
|||
# Kconfig - RISCV32_MIV implementation
|
||||
#
|
||||
# Copyright (c) 2018 Antmicro <www.antmicro.com>
|
||||
#
|
||||
|
||||
config SOC_SERIES_RISCV32_MIV
|
||||
bool "Microsemi Mi-V implementation"
|
||||
depends on RISCV32
|
||||
select SOC_FAMILY_RISCV_PRIVILEGE
|
||||
help
|
||||
Enable support for Microsemi Mi-V
|
14
arch/riscv32/soc/riscv-privilege/miv/Kconfig.soc
Normal file
14
arch/riscv32/soc/riscv-privilege/miv/Kconfig.soc
Normal file
|
@ -0,0 +1,14 @@
|
|||
# Kconfig - RISCV32_MIV configuration options
|
||||
#
|
||||
# Copyright (c) 2018 Antmicro <www.antmicro.com>
|
||||
#
|
||||
|
||||
choice
|
||||
prompt "Microsemi Mi-V system implementation"
|
||||
depends on SOC_SERIES_RISCV32_MIV
|
||||
|
||||
config SOC_RISCV32_MIV
|
||||
bool "Microsemi Mi-V system implementation"
|
||||
select ATOMIC_OPERATIONS_C
|
||||
|
||||
endchoice
|
7
arch/riscv32/soc/riscv-privilege/miv/linker.ld
Normal file
7
arch/riscv32/soc/riscv-privilege/miv/linker.ld
Normal file
|
@ -0,0 +1,7 @@
|
|||
/*
|
||||
* Copyright (c) 2018 Antmicro <www.antmicro.com>
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <arch/riscv32/common/linker.ld>
|
66
arch/riscv32/soc/riscv-privilege/miv/soc.h
Normal file
66
arch/riscv32/soc/riscv-privilege/miv/soc.h
Normal file
|
@ -0,0 +1,66 @@
|
|||
#ifndef __RISCV32_MIV_SOC_H_
|
||||
#define __RISCV32_MIV_SOC_H_
|
||||
|
||||
#include <soc_common.h>
|
||||
|
||||
/* GPIO Interrupts */
|
||||
#define MIV_GPIO_0_IRQ (RISCV_MAX_GENERIC_IRQ + 0)
|
||||
#define MIV_GPIO_1_IRQ (RISCV_MAX_GENERIC_IRQ + 1)
|
||||
#define MIV_GPIO_2_IRQ (RISCV_MAX_GENERIC_IRQ + 2)
|
||||
#define MIV_GPIO_3_IRQ (RISCV_MAX_GENERIC_IRQ + 3)
|
||||
#define MIV_GPIO_4_IRQ (RISCV_MAX_GENERIC_IRQ + 4)
|
||||
#define MIV_GPIO_5_IRQ (RISCV_MAX_GENERIC_IRQ + 5)
|
||||
#define MIV_GPIO_6_IRQ (RISCV_MAX_GENERIC_IRQ + 6)
|
||||
#define MIV_GPIO_7_IRQ (RISCV_MAX_GENERIC_IRQ + 7)
|
||||
#define MIV_GPIO_8_IRQ (RISCV_MAX_GENERIC_IRQ + 8)
|
||||
#define MIV_GPIO_9_IRQ (RISCV_MAX_GENERIC_IRQ + 9)
|
||||
#define MIV_GPIO_10_IRQ (RISCV_MAX_GENERIC_IRQ + 10)
|
||||
#define MIV_GPIO_11_IRQ (RISCV_MAX_GENERIC_IRQ + 11)
|
||||
#define MIV_GPIO_12_IRQ (RISCV_MAX_GENERIC_IRQ + 12)
|
||||
#define MIV_GPIO_13_IRQ (RISCV_MAX_GENERIC_IRQ + 13)
|
||||
#define MIV_GPIO_14_IRQ (RISCV_MAX_GENERIC_IRQ + 14)
|
||||
#define MIV_GPIO_15_IRQ (RISCV_MAX_GENERIC_IRQ + 15)
|
||||
#define MIV_GPIO_16_IRQ (RISCV_MAX_GENERIC_IRQ + 16)
|
||||
#define MIV_GPIO_17_IRQ (RISCV_MAX_GENERIC_IRQ + 17)
|
||||
#define MIV_GPIO_18_IRQ (RISCV_MAX_GENERIC_IRQ + 18)
|
||||
#define MIV_GPIO_19_IRQ (RISCV_MAX_GENERIC_IRQ + 19)
|
||||
#define MIV_GPIO_20_IRQ (RISCV_MAX_GENERIC_IRQ + 20)
|
||||
#define MIV_GPIO_21_IRQ (RISCV_MAX_GENERIC_IRQ + 21)
|
||||
#define MIV_GPIO_22_IRQ (RISCV_MAX_GENERIC_IRQ + 22)
|
||||
#define MIV_GPIO_23_IRQ (RISCV_MAX_GENERIC_IRQ + 23)
|
||||
#define MIV_GPIO_24_IRQ (RISCV_MAX_GENERIC_IRQ + 24)
|
||||
#define MIV_GPIO_25_IRQ (RISCV_MAX_GENERIC_IRQ + 25)
|
||||
#define MIV_GPIO_26_IRQ (RISCV_MAX_GENERIC_IRQ + 26)
|
||||
#define MIV_GPIO_27_IRQ (RISCV_MAX_GENERIC_IRQ + 27)
|
||||
#define MIV_GPIO_28_IRQ (RISCV_MAX_GENERIC_IRQ + 28)
|
||||
#define MIV_GPIO_29_IRQ (RISCV_MAX_GENERIC_IRQ + 29)
|
||||
#define MIV_GPIO_30_IRQ (RISCV_MAX_GENERIC_IRQ + 30)
|
||||
#define MIV_GPIO_31_IRQ (RISCV_MAX_GENERIC_IRQ + 31)
|
||||
|
||||
/* UART Configuration */
|
||||
#define MIV_UART_0_BASE_ADDR 0x70001000
|
||||
#define MIV_UART_0_LINECFG 0x1
|
||||
|
||||
/* GPIO Configuration */
|
||||
#define MIV_GPIO_0_BASE_ADDR 0x70002000
|
||||
|
||||
/* Platform Level Interrupt Controller Configuration */
|
||||
#define MIV_PLIC_BASE_ADDR 0x40000000
|
||||
#define MIV_PLIC_PRIO_BASE_ADDR MIV_PLIC_BASE_ADDR
|
||||
#define MIV_PLIC_IRQ_EN_BASE_ADDR (MIV_PLIC_BASE_ADDR + 0x2000)
|
||||
#define MIV_PLIC_REG_BASE_ADDR (MIV_PLIC_BASE_ADDR + 0x200000)
|
||||
|
||||
#define MIV_PLIC_MAX_PRIORITY 7
|
||||
|
||||
/* Clock controller. */
|
||||
#define PRCI_BASE_ADDR 0x44000000
|
||||
|
||||
/* Timer configuration */
|
||||
#define RISCV_MTIME_BASE 0x4400bff8
|
||||
#define RISCV_MTIMECMP_BASE 0x44004000
|
||||
|
||||
/* lib-c hooks required RAM defined variables */
|
||||
#define RISCV_RAM_BASE CONFIG_RISCV_RAM_BASE_ADDR
|
||||
#define RISCV_RAM_SIZE CONFIG_RISCV_RAM_SIZE
|
||||
|
||||
#endif /* __RISCV32_MIV_SOC_H_ */
|
1
boards/riscv32/m2gl025_miv/CMakeLists.txt
Normal file
1
boards/riscv32/m2gl025_miv/CMakeLists.txt
Normal file
|
@ -0,0 +1 @@
|
|||
zephyr_library_include_directories(${PROJECT_SOURCE_DIR}/drivers)
|
3
boards/riscv32/m2gl025_miv/Kconfig.board
Normal file
3
boards/riscv32/m2gl025_miv/Kconfig.board
Normal file
|
@ -0,0 +1,3 @@
|
|||
config BOARD_M2GL025_MIV
|
||||
bool "Microsemi M2GL025 IGLOO2 dev board with Mi-V CPU"
|
||||
depends on SOC_RISCV32_MIV
|
6
boards/riscv32/m2gl025_miv/Kconfig.defconfig
Normal file
6
boards/riscv32/m2gl025_miv/Kconfig.defconfig
Normal file
|
@ -0,0 +1,6 @@
|
|||
if BOARD_M2GL025_MIV
|
||||
|
||||
config BOARD
|
||||
default "m2gl025_miv"
|
||||
|
||||
endif
|
14
boards/riscv32/m2gl025_miv/board.h
Normal file
14
boards/riscv32/m2gl025_miv/board.h
Normal file
|
@ -0,0 +1,14 @@
|
|||
/*
|
||||
* Copyright (c) 2018 Antmicro <www.antmicro.com>
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef __INC_BOARD_H
|
||||
#define __INC_BOARD_H
|
||||
|
||||
#include <soc.h>
|
||||
|
||||
#define uart_miv_port_0_clk_freq 66000000
|
||||
|
||||
#endif /* __INC_BOARD_H */
|
69
boards/riscv32/m2gl025_miv/doc/m2g1025_miv.rst
Normal file
69
boards/riscv32/m2gl025_miv/doc/m2g1025_miv.rst
Normal file
|
@ -0,0 +1,69 @@
|
|||
.. _m2gl025-miv:
|
||||
|
||||
Microsemi M2GL025 Mi-V
|
||||
######################
|
||||
|
||||
Overview
|
||||
********
|
||||
|
||||
The Microsemi M2GL025 board is an IGLOO2 FPGA based development board.
|
||||
The Mi-V RISC-V soft CPU can be deployed on the MGL025 board.
|
||||
More information can be found on
|
||||
`Microsemi's website <https://www.microsemi.com/product-directory/embedded-processing/4406-cpus>`_.
|
||||
|
||||
Programming and debugging
|
||||
*************************
|
||||
|
||||
Building
|
||||
========
|
||||
|
||||
Applications for the ``m2gl025_miv`` board configuration can be built as usual
|
||||
(see :ref:`build_an_application`).
|
||||
In order to build the application for ``m2gl025_miv``, set the ``BOARD`` variable
|
||||
to ``m2gl025_miv``.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
export BOARD="m2gl025_miv"
|
||||
|
||||
Flashing
|
||||
========
|
||||
|
||||
In order to upload the application to the device, you'll need OpenOCD and GDB
|
||||
with RISC-V support.
|
||||
You can get them as a part of SoftConsole SDK.
|
||||
Download and installation instructions can be found on
|
||||
`Microsemi's SoftConsole website
|
||||
<https://www.microsemi.com/product-directory/design-tools/4879-softconsole>`_.
|
||||
|
||||
With the necessary tools installed, you can connect to the board using OpenOCD.
|
||||
To establish an OpenOCD connection run:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
sudo LD_LIBRARY_PATH=<softconsole_path>/openocd/bin \
|
||||
<softconsole_path>/openocd/bin/openocd --file \
|
||||
<softconsole_path>/openocd/share/openocd/scripts/board/microsemi-riscv.cfg
|
||||
|
||||
|
||||
Leave it running, and in a different terminal, use GDB to upload the binary to
|
||||
the board. You can use the RISC-V GDB from a toolchain delivered with
|
||||
SoftConsole SDK.
|
||||
|
||||
Here is the GDB terminal command to connect to the device
|
||||
and load the binary:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
<softconsole_path>/riscv-unknown-elf-gcc/bin/riscv64-unknown-elf-gdb \
|
||||
-ex "target extended-remote localhost:3333" \
|
||||
-ex "set mem inaccessible-by-default off" \
|
||||
-ex "set arch riscv:rv32" \
|
||||
-ex "set riscv use_compressed_breakpoints no" \
|
||||
-ex "load" <path_to_executable>
|
||||
|
||||
Debugging
|
||||
=========
|
||||
|
||||
Refer to the detailed overview of :ref:`application_debugging`.
|
||||
|
11
boards/riscv32/m2gl025_miv/m2gl025_miv.yaml
Normal file
11
boards/riscv32/m2gl025_miv/m2gl025_miv.yaml
Normal file
|
@ -0,0 +1,11 @@
|
|||
identifier: m2gl025_miv
|
||||
name: Microsemi M2GL025 with MiV target
|
||||
type: mcu
|
||||
arch: riscv32
|
||||
toolchain:
|
||||
- zephyr
|
||||
ram: 64
|
||||
testing:
|
||||
ignore_tags:
|
||||
- net
|
||||
- bluetooth
|
16
boards/riscv32/m2gl025_miv/m2gl025_miv_defconfig
Normal file
16
boards/riscv32/m2gl025_miv/m2gl025_miv_defconfig
Normal file
|
@ -0,0 +1,16 @@
|
|||
CONFIG_RISCV32=y
|
||||
CONFIG_SOC_SERIES_RISCV32_MIV=y
|
||||
CONFIG_SOC_RISCV32_MIV=y
|
||||
CONFIG_BOARD_M2GL025_MIV=y
|
||||
CONFIG_CONSOLE=y
|
||||
CONFIG_SERIAL=y
|
||||
CONFIG_UART_MIV=y
|
||||
CONFIG_UART_MIV_PORT_0=y
|
||||
CONFIG_UART_MIV_PORT_0_BAUD_RATE=115200
|
||||
CONFIG_UART_MIV_PORT_0_NAME="uart0"
|
||||
CONFIG_UART_CONSOLE=y
|
||||
CONFIG_UART_CONSOLE_ON_DEV_NAME="uart0"
|
||||
CONFIG_PLIC=y
|
||||
CONFIG_RISCV_MACHINE_TIMER=y
|
||||
CONFIG_GPIO=n
|
||||
CONFIG_XIP=y
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
/**
|
||||
* @brief Platform Level Interrupt Controller (PLIC) driver
|
||||
* for the RISC-V processors
|
||||
* for RISC-V processors
|
||||
*/
|
||||
|
||||
#include <kernel.h>
|
||||
|
|
|
@ -18,6 +18,12 @@
|
|||
#define PLIC_IRQ_EN_BASE_ADDR FE310_PLIC_IRQ_EN_BASE_ADDR
|
||||
#define PLIC_PRIO_BASE_ADDR FE310_PLIC_PRIO_BASE_ADDR
|
||||
#define PLIC_MAX_PRIORITY FE310_PLIC_MAX_PRIORITY
|
||||
/* Mi-V definitons for the PLIC */
|
||||
#elif defined(CONFIG_SOC_SERIES_RISCV32_MIV)
|
||||
#define PLIC_REG_BASE_ADDR MIV_PLIC_REG_BASE_ADDR
|
||||
#define PLIC_IRQ_EN_BASE_ADDR MIV_PLIC_IRQ_EN_BASE_ADDR
|
||||
#define PLIC_PRIO_BASE_ADDR MIV_PLIC_PRIO_BASE_ADDR
|
||||
#define PLIC_MAX_PRIORITY MIV_PLIC_MAX_PRIORITY
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
zephyr_library()
|
||||
|
||||
zephyr_library_sources_ifdef(CONFIG_UART_ALTERA_JTAG uart_altera_jtag_hal.c)
|
||||
zephyr_library_sources_if_kconfig(uart_imx.c)
|
||||
zephyr_library_sources_if_kconfig(uart_cc32xx.c)
|
||||
|
@ -10,6 +9,7 @@ zephyr_library_sources_if_kconfig(uart_gecko.c)
|
|||
zephyr_library_sources_if_kconfig(uart_mcux.c)
|
||||
zephyr_library_sources_if_kconfig(uart_mcux_lpuart.c)
|
||||
zephyr_library_sources_if_kconfig(uart_mcux_lpsci.c)
|
||||
zephyr_library_sources_if_kconfig(uart_miv.c)
|
||||
zephyr_library_sources_if_kconfig(uart_msp432p4xx.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_NRF_UART_PERIPHERAL uart_nrfx_uart.c)
|
||||
zephyr_library_sources_if_kconfig(uart_ns16550.c)
|
||||
|
|
|
@ -73,6 +73,8 @@ source "drivers/serial/Kconfig.mcux_lpsci"
|
|||
|
||||
source "drivers/serial/Kconfig.mcux_lpuart"
|
||||
|
||||
source "drivers/serial/Kconfig.miv"
|
||||
|
||||
source "drivers/serial/Kconfig.imx"
|
||||
|
||||
source "drivers/serial/Kconfig.stellaris"
|
||||
|
|
42
drivers/serial/Kconfig.miv
Normal file
42
drivers/serial/Kconfig.miv
Normal file
|
@ -0,0 +1,42 @@
|
|||
# Kconfig.miv - Mi-V UART configuration option
|
||||
#
|
||||
# Copyright (c) 2018 Antmicro <www.antmicro.com>
|
||||
#
|
||||
|
||||
menuconfig UART_MIV
|
||||
bool "Mi-V serial driver"
|
||||
depends on SOC_RISCV32_MIV
|
||||
default n
|
||||
select SERIAL_HAS_DRIVER
|
||||
help
|
||||
This option enables the Mi-V serial driver.
|
||||
|
||||
menuconfig UART_MIV_PORT_0
|
||||
bool "Enable Mi-V Port 0"
|
||||
default n
|
||||
depends on UART_MIV
|
||||
help
|
||||
This tells the driver to configure the UART port at boot, depending on
|
||||
the additional configuration options below.
|
||||
|
||||
config UART_MIV_PORT_0_NAME
|
||||
string "Port 0 Device Name"
|
||||
default "uart0"
|
||||
depends on UART_MIV_PORT_0
|
||||
help
|
||||
This is the device name for UART, and is included in the device
|
||||
struct.
|
||||
|
||||
config UART_MIV_PORT_0_BAUD_RATE
|
||||
int "Port 0 Baud Rate"
|
||||
default 0
|
||||
depends on UART_MIV_PORT_0
|
||||
help
|
||||
The baud rate for UART port to be set to at boot.
|
||||
|
||||
config UART_MIV_PORT_0_IRQ_PRIORITY
|
||||
int "Port 0 Interrupt Priority"
|
||||
default 1
|
||||
depends on UART_MIV_PORT_0
|
||||
help
|
||||
Port 0 Interrupt Priority
|
415
drivers/serial/uart_miv.c
Normal file
415
drivers/serial/uart_miv.c
Normal file
|
@ -0,0 +1,415 @@
|
|||
/*
|
||||
* Copyright (c) 2018 Antmicro <www.antmicro.com>
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <kernel.h>
|
||||
#include <arch/cpu.h>
|
||||
#include <uart.h>
|
||||
#include <board.h>
|
||||
|
||||
|
||||
/* UART REGISTERS DEFINITIONS */
|
||||
|
||||
/* TX register */
|
||||
#define TXDATA_REG_OFFSET 0x0
|
||||
|
||||
#define TXDATA_OFFSET 0x0
|
||||
#define TXDATA_MASK 0xFF
|
||||
#define TXDATA_SHIFT 0
|
||||
|
||||
/* RX register */
|
||||
#define RXDATA_REG_OFFSET 0x4
|
||||
|
||||
#define RXDATA_OFFSET 0x4
|
||||
#define RXDATA_MASK 0xFF
|
||||
#define RXDATA_SHIFT 0
|
||||
|
||||
/* Control1 register */
|
||||
#define CTRL1_REG_OFFSET 0x8
|
||||
|
||||
/* Baud value lower 8 bits */
|
||||
#define CTRL1_BAUDVALUE_OFFSET 0x8
|
||||
#define CTRL1_BAUDVALUE_MASK 0xFF
|
||||
#define CTRL1_BAUDVALUE_SHIFT 0
|
||||
|
||||
/* Control2 register */
|
||||
#define CTRL2_REG_OFFSET 0xC
|
||||
|
||||
/* Bit length */
|
||||
#define CTRL2_BIT_LENGTH_OFFSET 0xC
|
||||
#define CTRL2_BIT_LENGTH_MASK 0x01
|
||||
#define CTRL2_BIT_LENGTH_SHIFT 0
|
||||
|
||||
/* Parity enable */
|
||||
#define CTRL2_PARITY_EN_OFFSET 0xC
|
||||
#define CTRL2_PARITY_EN_MASK 0x02
|
||||
#define CTRL2_PARITY_EN_SHIFT 1
|
||||
|
||||
/* Odd/even parity configuration */
|
||||
#define CTRL2_ODD_EVEN_OFFSET 0xC
|
||||
#define CTRL2_ODD_EVEN_MASK 0x04
|
||||
#define CTRL2_ODD_EVEN_SHIFT 2
|
||||
|
||||
/* Baud value higher 5 bits */
|
||||
#define CTRL2_BAUDVALUE_OFFSET 0xC
|
||||
#define CTRL2_BAUDVALUE_MASK 0xF8
|
||||
#define CTRL2_BAUDVALUE_SHIFT 3
|
||||
|
||||
/* Status register */
|
||||
#define StatusReg_REG_OFFSET 0x10
|
||||
|
||||
#define STATUS_REG_OFFSET 0x10
|
||||
|
||||
/* TX ready */
|
||||
#define STATUS_TXRDY_OFFSET 0x10
|
||||
#define STATUS_TXRDY_MASK 0x01
|
||||
#define STATUS_TXRDY_SHIFT 0
|
||||
|
||||
/* Receive full - raised even when 1 char arrived */
|
||||
#define STATUS_RXFULL_OFFSET 0x10
|
||||
#define STATUS_RXFULL_MASK 0x02
|
||||
#define STATUS_RXFULL_SHIFT 1
|
||||
|
||||
/* Parity error */
|
||||
#define STATUS_PARITYERR_OFFSET 0x10
|
||||
#define STATUS_PARITYERR_MASK 0x04
|
||||
#define STATUS_PARITYERR_SHIFT 2
|
||||
|
||||
/* Overflow */
|
||||
#define STATUS_OVERFLOW_OFFSET 0x10
|
||||
#define STATUS_OVERFLOW_MASK 0x08
|
||||
#define STATUS_OVERFLOW_SHIFT 3
|
||||
|
||||
/* Frame error */
|
||||
#define STATUS_FRAMERR_OFFSET 0x10
|
||||
#define STATUS_FRAMERR_MASK 0x10
|
||||
#define STATUS_FRAMERR_SHIFT 4
|
||||
|
||||
/* Data bits length defines */
|
||||
#define DATA_7_BITS 0x00
|
||||
#define DATA_8_BITS 0x01
|
||||
|
||||
/* Parity defines */
|
||||
#define NO_PARITY 0x00
|
||||
#define EVEN_PARITY 0x02
|
||||
#define ODD_PARITY 0x06
|
||||
|
||||
/* Error Status definitions */
|
||||
#define UART_PARITY_ERROR 0x01
|
||||
#define UART_OVERFLOW_ERROR 0x02
|
||||
#define UART_FRAMING_ERROR 0x04
|
||||
|
||||
#define BAUDVALUE_LSB ((u16_t)(0x00FF))
|
||||
#define BAUDVALUE_MSB ((u16_t)(0xFF00))
|
||||
#define BAUDVALUE_SHIFT ((u8_t)(5))
|
||||
|
||||
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
|
||||
static struct k_thread rx_thread;
|
||||
static K_THREAD_STACK_DEFINE(rx_stack, 512);
|
||||
#endif
|
||||
|
||||
struct uart_miv_regs_t {
|
||||
u8_t tx;
|
||||
u8_t reserved0[3];
|
||||
u8_t rx;
|
||||
u8_t reserved1[3];
|
||||
u8_t ctrlreg1;
|
||||
u8_t reserved2[3];
|
||||
u8_t ctrlreg2;
|
||||
u8_t reserved3[3];
|
||||
u8_t status;
|
||||
};
|
||||
|
||||
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
|
||||
typedef void (*irq_cfg_func_t)(struct device *dev);
|
||||
#endif
|
||||
|
||||
struct uart_miv_device_config {
|
||||
u32_t uart_addr;
|
||||
u32_t sys_clk_freq;
|
||||
u32_t line_config;
|
||||
u32_t baud_rate;
|
||||
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
|
||||
irq_cfg_func_t cfg_func;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct uart_miv_data {
|
||||
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
|
||||
uart_irq_callback_t callback;
|
||||
#endif
|
||||
};
|
||||
|
||||
#define DEV_CFG(dev) \
|
||||
((const struct uart_miv_device_config * const) \
|
||||
(dev)->config->config_info)
|
||||
#define DEV_UART(dev) \
|
||||
((struct uart_miv_regs_t *)(DEV_CFG(dev))->uart_addr)
|
||||
#define DEV_DATA(dev) \
|
||||
((struct uart_miv_data * const)(dev)->driver_data)
|
||||
|
||||
static unsigned char uart_miv_poll_out(struct device *dev,
|
||||
unsigned char c)
|
||||
{
|
||||
volatile struct uart_miv_regs_t *uart = DEV_UART(dev);
|
||||
|
||||
while (!(uart->status & STATUS_TXRDY_MASK))
|
||||
;
|
||||
|
||||
uart->tx = c;
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
static int uart_miv_poll_in(struct device *dev, unsigned char *c)
|
||||
{
|
||||
volatile struct uart_miv_regs_t *uart = DEV_UART(dev);
|
||||
|
||||
if (uart->status & STATUS_RXFULL_MASK) {
|
||||
*c = (unsigned char)(uart->rx & RXDATA_MASK);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int uart_miv_err_check(struct device *dev)
|
||||
{
|
||||
volatile struct uart_miv_regs_t *uart = DEV_UART(dev);
|
||||
u32_t flags = uart->status;
|
||||
int err = 0;
|
||||
|
||||
if (flags & STATUS_PARITYERR_MASK) {
|
||||
err |= UART_PARITY_ERROR;
|
||||
}
|
||||
|
||||
if (flags & STATUS_OVERFLOW_MASK) {
|
||||
err |= UART_OVERFLOW_ERROR;
|
||||
}
|
||||
|
||||
if (flags & STATUS_FRAMERR_MASK) {
|
||||
err |= UART_FRAMING_ERROR;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
|
||||
|
||||
static int uart_miv_fifo_fill(struct device *dev,
|
||||
const u8_t *tx_data,
|
||||
int size)
|
||||
{
|
||||
volatile struct uart_miv_regs_t *uart = DEV_UART(dev);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < size && (uart->status & STATUS_TXRDY_MASK); i++) {
|
||||
uart->tx = tx_data[i];
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
static int uart_miv_fifo_read(struct device *dev,
|
||||
u8_t *rx_data,
|
||||
const int size)
|
||||
{
|
||||
volatile struct uart_miv_regs_t *uart = DEV_UART(dev);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < size; i++) {
|
||||
if (uart->status & STATUS_RXFULL_MASK) {
|
||||
rx_data[i] = (unsigned char)(uart->rx & RXDATA_MASK);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
static void uart_miv_irq_tx_enable(struct device *dev)
|
||||
{
|
||||
ARG_UNUSED(dev);
|
||||
}
|
||||
|
||||
static void uart_miv_irq_tx_disable(struct device *dev)
|
||||
{
|
||||
ARG_UNUSED(dev);
|
||||
}
|
||||
|
||||
static int uart_miv_irq_tx_ready(struct device *dev)
|
||||
{
|
||||
volatile struct uart_miv_regs_t *uart = DEV_UART(dev);
|
||||
|
||||
return !(uart->status & STATUS_TXRDY_MASK);
|
||||
}
|
||||
|
||||
static int uart_miv_irq_tx_complete(struct device *dev)
|
||||
{
|
||||
ARG_UNUSED(dev);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void uart_miv_irq_rx_enable(struct device *dev)
|
||||
{
|
||||
ARG_UNUSED(dev);
|
||||
}
|
||||
|
||||
static void uart_miv_irq_rx_disable(struct device *dev)
|
||||
{
|
||||
ARG_UNUSED(dev);
|
||||
}
|
||||
|
||||
static int uart_miv_irq_rx_ready(struct device *dev)
|
||||
{
|
||||
volatile struct uart_miv_regs_t *uart = DEV_UART(dev);
|
||||
|
||||
return !!(uart->status & STATUS_RXFULL_MASK);
|
||||
}
|
||||
|
||||
static void uart_miv_irq_err_enable(struct device *dev)
|
||||
{
|
||||
ARG_UNUSED(dev);
|
||||
}
|
||||
|
||||
static void uart_miv_irq_err_disable(struct device *dev)
|
||||
{
|
||||
ARG_UNUSED(dev);
|
||||
}
|
||||
|
||||
static int uart_miv_irq_is_pending(struct device *dev)
|
||||
{
|
||||
volatile struct uart_miv_regs_t *uart = DEV_UART(dev);
|
||||
|
||||
return !!(uart->status & STATUS_RXFULL_MASK);
|
||||
}
|
||||
|
||||
static int uart_miv_irq_update(struct device *dev)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void uart_miv_irq_handler(void *arg)
|
||||
{
|
||||
struct device *dev = (struct device *)arg;
|
||||
struct uart_miv_data *data = DEV_DATA(dev);
|
||||
|
||||
if (data->callback) {
|
||||
data->callback(dev);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This thread is a workaround for IRQs that are not connected in Mi-V.
|
||||
* Since we cannot rely on IRQs, the rx_thread is working instead and
|
||||
* polling for data. The thread calls the registered callback when data
|
||||
* arrives.
|
||||
*/
|
||||
void uart_miv_rx_thread(void *arg1, void *arg2, void *arg3)
|
||||
{
|
||||
struct device *dev = (struct device *)arg1;
|
||||
volatile struct uart_miv_regs_t *uart = DEV_UART(dev);
|
||||
const struct uart_miv_device_config *const cfg = DEV_CFG(dev);
|
||||
/* Make it go to sleep for a period no longer than
|
||||
* time to receive next character.
|
||||
*/
|
||||
u32_t delay = 1000000 / cfg->baud_rate;
|
||||
|
||||
while (1) {
|
||||
if (uart->status & STATUS_RXFULL_MASK) {
|
||||
uart_miv_irq_handler(dev);
|
||||
}
|
||||
k_sleep(delay);
|
||||
}
|
||||
}
|
||||
|
||||
static void uart_miv_irq_callback_set(struct device *dev,
|
||||
uart_irq_callback_t cb)
|
||||
{
|
||||
struct uart_miv_data *data = DEV_DATA(dev);
|
||||
|
||||
data->callback = cb;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_UART_INTERRUPT_DRIVEN */
|
||||
|
||||
static int uart_miv_init(struct device *dev)
|
||||
{
|
||||
const struct uart_miv_device_config *const cfg = DEV_CFG(dev);
|
||||
volatile struct uart_miv_regs_t *uart = DEV_UART(dev);
|
||||
/* Calculate divider value to set baudrate */
|
||||
u16_t baud_value = (cfg->sys_clk_freq / (16 * cfg->baud_rate)) - 1;
|
||||
|
||||
/* Set baud rate */
|
||||
uart->ctrlreg1 = (u8_t)(baud_value & BAUDVALUE_LSB);
|
||||
uart->ctrlreg2 = (u8_t)(cfg->line_config) |
|
||||
(u8_t)((baud_value & BAUDVALUE_MSB) >> BAUDVALUE_SHIFT);
|
||||
|
||||
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
|
||||
/* Setup thread polling for data */
|
||||
cfg->cfg_func(dev);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct uart_driver_api uart_miv_driver_api = {
|
||||
.poll_in = uart_miv_poll_in,
|
||||
.poll_out = uart_miv_poll_out,
|
||||
.err_check = uart_miv_err_check,
|
||||
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
|
||||
.fifo_fill = uart_miv_fifo_fill,
|
||||
.fifo_read = uart_miv_fifo_read,
|
||||
.irq_tx_enable = uart_miv_irq_tx_enable,
|
||||
.irq_tx_disable = uart_miv_irq_tx_disable,
|
||||
.irq_tx_ready = uart_miv_irq_tx_ready,
|
||||
.irq_tx_complete = uart_miv_irq_tx_complete,
|
||||
.irq_rx_enable = uart_miv_irq_rx_enable,
|
||||
.irq_rx_disable = uart_miv_irq_rx_disable,
|
||||
.irq_rx_ready = uart_miv_irq_rx_ready,
|
||||
.irq_err_enable = uart_miv_irq_err_enable,
|
||||
.irq_err_disable = uart_miv_irq_err_disable,
|
||||
.irq_is_pending = uart_miv_irq_is_pending,
|
||||
.irq_update = uart_miv_irq_update,
|
||||
.irq_callback_set = uart_miv_irq_callback_set,
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifdef CONFIG_UART_MIV_PORT_0
|
||||
|
||||
static struct uart_miv_data uart_miv_data_0;
|
||||
|
||||
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
|
||||
static void uart_miv_irq_cfg_func_0(struct device *dev);
|
||||
#endif
|
||||
|
||||
static const struct uart_miv_device_config uart_miv_dev_cfg_0 = {
|
||||
.uart_addr = MIV_UART_0_BASE_ADDR,
|
||||
.sys_clk_freq = uart_miv_port_0_clk_freq,
|
||||
.line_config = MIV_UART_0_LINECFG,
|
||||
.baud_rate = CONFIG_UART_MIV_PORT_0_BAUD_RATE,
|
||||
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
|
||||
.cfg_func = uart_miv_irq_cfg_func_0,
|
||||
#endif
|
||||
};
|
||||
|
||||
DEVICE_AND_API_INIT(uart_miv_0, CONFIG_UART_MIV_PORT_0_NAME,
|
||||
uart_miv_init, &uart_miv_data_0, &uart_miv_dev_cfg_0,
|
||||
PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEVICE,
|
||||
(void *)&uart_miv_driver_api);
|
||||
|
||||
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
|
||||
static void uart_miv_irq_cfg_func_0(struct device *dev)
|
||||
{
|
||||
/* Create a thread which will poll for data - replacement for IRQ */
|
||||
k_thread_create(&rx_thread, rx_stack, 500,
|
||||
uart_miv_rx_thread, dev, NULL, NULL, K_PRIO_COOP(2),
|
||||
0, K_NO_WAIT);
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* CONFIG_MIV_UART_0 */
|
Loading…
Add table
Add a link
Reference in a new issue