GK SDK 源码库: XMIPCLinuxV100R005C00SPC030 (kernel/tools/open_source excluded)
This commit is contained in:
@@ -0,0 +1,811 @@
|
||||
#
|
||||
# Serial device configuration
|
||||
#
|
||||
|
||||
menu "Serial drivers"
|
||||
|
||||
config BAUDRATE
|
||||
int "Default baudrate"
|
||||
default 115200
|
||||
help
|
||||
Select a default baudrate, where "default" has a driver-specific
|
||||
meaning of either setting the baudrate for the early debug UART
|
||||
in the SPL stage (most drivers) or for choosing a default baudrate
|
||||
in the absence of an environment setting (serial_mxc.c).
|
||||
|
||||
config REQUIRE_SERIAL_CONSOLE
|
||||
bool "Require a serial port for console"
|
||||
# Running without a serial console is not supported by the
|
||||
# non-dm serial code
|
||||
depends on DM_SERIAL
|
||||
default y
|
||||
help
|
||||
Require a serial port for the console, and panic if none is found
|
||||
during serial port initialization (default y). Set this to n on
|
||||
boards which have no debug serial port whatsoever.
|
||||
|
||||
config SPECIFY_CONSOLE_INDEX
|
||||
bool "Specify the port number used for console"
|
||||
default y if !DM_SERIAL || (SPL && !SPL_DM_SERIAL) || \
|
||||
(TPL && !TPL_DM_SERIAL)
|
||||
help
|
||||
In various cases, we need to specify which of the UART devices that
|
||||
a board or SoC has available are to be used for the console device
|
||||
in U-Boot.
|
||||
|
||||
config SERIAL_PRESENT
|
||||
bool "Provide a serial driver"
|
||||
depends on DM_SERIAL
|
||||
default y
|
||||
help
|
||||
In very space-constrained devices even the full UART driver is too
|
||||
large. In this case the debug UART can still be used in some cases.
|
||||
This option enables the full UART in U-Boot, so if is it disabled,
|
||||
the full UART driver will be omitted, thus saving space.
|
||||
|
||||
config SPL_SERIAL_PRESENT
|
||||
bool "Provide a serial driver in SPL"
|
||||
depends on DM_SERIAL && SPL
|
||||
default y
|
||||
help
|
||||
In very space-constrained devices even the full UART driver is too
|
||||
large. In this case the debug UART can still be used in some cases.
|
||||
This option enables the full UART in SPL, so if is it disabled,
|
||||
the full UART driver will be omitted, thus saving space.
|
||||
|
||||
config TPL_SERIAL_PRESENT
|
||||
bool "Provide a serial driver in TPL"
|
||||
depends on DM_SERIAL && TPL
|
||||
default y
|
||||
help
|
||||
In very space-constrained devices even the full UART driver is too
|
||||
large. In this case the debug UART can still be used in some cases.
|
||||
This option enables the full UART in TPL, so if is it disabled,
|
||||
the full UART driver will be omitted, thus saving space.
|
||||
|
||||
# Logic to allow us to use the imply keyword to set what the default port
|
||||
# should be. The default is otherwise 1.
|
||||
config CONS_INDEX_0
|
||||
bool
|
||||
|
||||
config CONS_INDEX_2
|
||||
bool
|
||||
|
||||
config CONS_INDEX_3
|
||||
bool
|
||||
|
||||
config CONS_INDEX_4
|
||||
bool
|
||||
|
||||
config CONS_INDEX_5
|
||||
bool
|
||||
|
||||
config CONS_INDEX_6
|
||||
bool
|
||||
|
||||
config CONS_INDEX
|
||||
int "UART used for console"
|
||||
depends on SPECIFY_CONSOLE_INDEX
|
||||
range 0 6
|
||||
default 0 if CONS_INDEX_0
|
||||
default 2 if CONS_INDEX_2
|
||||
default 3 if CONS_INDEX_3
|
||||
default 4 if CONS_INDEX_4
|
||||
default 5 if CONS_INDEX_5
|
||||
default 6 if CONS_INDEX_6
|
||||
default 1
|
||||
help
|
||||
Set this to match the UART number of the serial console.
|
||||
|
||||
config DM_SERIAL
|
||||
bool "Enable Driver Model for serial drivers"
|
||||
depends on DM
|
||||
help
|
||||
Enable driver model for serial. This replaces
|
||||
drivers/serial/serial.c with the serial uclass, which
|
||||
implements serial_putc() etc. The uclass interface is
|
||||
defined in include/serial.h.
|
||||
|
||||
config SERIAL_RX_BUFFER
|
||||
bool "Enable RX buffer for serial input"
|
||||
depends on DM_SERIAL
|
||||
help
|
||||
Enable RX buffer support for the serial driver. This enables
|
||||
pasting longer strings, even when the RX FIFO of the UART is
|
||||
not big enough (e.g. 16 bytes on the normal NS16550).
|
||||
|
||||
config SERIAL_RX_BUFFER_SIZE
|
||||
int "RX buffer size"
|
||||
depends on SERIAL_RX_BUFFER
|
||||
default 256
|
||||
help
|
||||
The size of the RX buffer (needs to be power of 2)
|
||||
|
||||
config SERIAL_SEARCH_ALL
|
||||
bool "Search for serial devices after default one failed"
|
||||
depends on DM_SERIAL
|
||||
help
|
||||
The serial subsystem only searches for a single serial device
|
||||
that was instantiated, but does not check whether it was probed
|
||||
correctly. With this option set, we make successful probing
|
||||
mandatory and search for fallback serial devices if the default
|
||||
device does not work.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
config SPL_DM_SERIAL
|
||||
bool "Enable Driver Model for serial drivers in SPL"
|
||||
depends on DM_SERIAL && SPL_DM
|
||||
default y
|
||||
help
|
||||
Enable driver model for serial in SPL. This replaces
|
||||
drivers/serial/serial.c with the serial uclass, which
|
||||
implements serial_putc() etc. The uclass interface is
|
||||
defined in include/serial.h.
|
||||
|
||||
config TPL_DM_SERIAL
|
||||
bool "Enable Driver Model for serial drivers in TPL"
|
||||
depends on DM_SERIAL && TPL_DM
|
||||
default y if TPL && DM_SERIAL
|
||||
help
|
||||
Enable driver model for serial in TPL. This replaces
|
||||
drivers/serial/serial.c with the serial uclass, which
|
||||
implements serial_putc() etc. The uclass interface is
|
||||
defined in include/serial.h.
|
||||
|
||||
config DEBUG_UART
|
||||
bool "Enable an early debug UART for debugging"
|
||||
help
|
||||
The debug UART is intended for use very early in U-Boot to debug
|
||||
problems when an ICE or other debug mechanism is not available.
|
||||
|
||||
To use it you should:
|
||||
- Make sure your UART supports this interface
|
||||
- Enable CONFIG_DEBUG_UART
|
||||
- Enable the CONFIG for your UART to tell it to provide this interface
|
||||
(e.g. CONFIG_DEBUG_UART_NS16550)
|
||||
- Define the required settings as needed (see below)
|
||||
- Call debug_uart_init() before use
|
||||
- Call debug_uart_putc() to output a character
|
||||
|
||||
Depending on your platform it may be possible to use this UART before
|
||||
a stack is available.
|
||||
|
||||
If your UART does not support this interface you can probably add
|
||||
support quite easily. Remember that you cannot use driver model and
|
||||
it is preferred to use no stack.
|
||||
|
||||
You must not use this UART once driver model is working and the
|
||||
serial drivers are up and running (done in serial_init()). Otherwise
|
||||
the drivers may conflict and you will get strange output.
|
||||
|
||||
choice
|
||||
prompt "Select which UART will provide the debug UART"
|
||||
depends on DEBUG_UART
|
||||
default DEBUG_UART_NS16550
|
||||
|
||||
config DEBUG_UART_ALTERA_JTAGUART
|
||||
bool "Altera JTAG UART"
|
||||
help
|
||||
Select this to enable a debug UART using the altera_jtag_uart driver.
|
||||
You will need to provide parameters to make this work. The driver will
|
||||
be available until the real driver model serial is running.
|
||||
|
||||
config DEBUG_UART_ALTERA_UART
|
||||
bool "Altera UART"
|
||||
help
|
||||
Select this to enable a debug UART using the altera_uart driver.
|
||||
You will need to provide parameters to make this work. The driver will
|
||||
be available until the real driver model serial is running.
|
||||
|
||||
config DEBUG_UART_AR933X
|
||||
bool "QCA/Atheros ar933x"
|
||||
depends on AR933X_UART
|
||||
help
|
||||
Select this to enable a debug UART using the ar933x uart driver.
|
||||
You will need to provide parameters to make this work. The
|
||||
driver will be available until the real driver model serial is
|
||||
running.
|
||||
|
||||
config DEBUG_ARC_SERIAL
|
||||
bool "ARC UART"
|
||||
depends on ARC_SERIAL
|
||||
help
|
||||
Select this to enable a debug UART using the ARC UART driver.
|
||||
You will need to provide parameters to make this work. The
|
||||
driver will be available until the real driver model serial is
|
||||
running.
|
||||
|
||||
config DEBUG_UART_ATMEL
|
||||
bool "Atmel USART"
|
||||
help
|
||||
Select this to enable a debug UART using the atmel usart driver. You
|
||||
will need to provide parameters to make this work. The driver will
|
||||
be available until the real driver-model serial is running.
|
||||
|
||||
config DEBUG_UART_BCM6345
|
||||
bool "BCM6345 UART"
|
||||
depends on BCM6345_SERIAL
|
||||
help
|
||||
Select this to enable a debug UART on BCM6345 SoCs. You
|
||||
will need to provide parameters to make this work. The driver will
|
||||
be available until the real driver model serial is running.
|
||||
|
||||
config DEBUG_UART_NS16550
|
||||
bool "ns16550"
|
||||
help
|
||||
Select this to enable a debug UART using the ns16550 driver. You
|
||||
will need to provide parameters to make this work. The driver will
|
||||
be available until the real driver model serial is running.
|
||||
|
||||
config DEBUG_EFI_CONSOLE
|
||||
bool "EFI"
|
||||
depends on EFI_APP
|
||||
help
|
||||
Select this to enable a debug console which calls back to EFI to
|
||||
output to the console. This can be useful for early debugging of
|
||||
U-Boot when running on top of EFI (Extensive Firmware Interface).
|
||||
This is a type of BIOS used by PCs.
|
||||
|
||||
config DEBUG_UART_S5P
|
||||
bool "Samsung S5P"
|
||||
help
|
||||
Select this to enable a debug UART using the serial_s5p driver. You
|
||||
will need to provide parameters to make this work. The driver will
|
||||
be available until the real driver-model serial is running.
|
||||
|
||||
config DEBUG_UART_MESON
|
||||
bool "Amlogic Meson"
|
||||
depends on MESON_SERIAL
|
||||
help
|
||||
Select this to enable a debug UART using the serial_meson driver. You
|
||||
will need to provide parameters to make this work. The driver will
|
||||
be available until the real driver-model serial is running.
|
||||
|
||||
config DEBUG_UART_UARTLITE
|
||||
bool "Xilinx Uartlite"
|
||||
help
|
||||
Select this to enable a debug UART using the serial_uartlite driver.
|
||||
You will need to provide parameters to make this work. The driver will
|
||||
be available until the real driver-model serial is running.
|
||||
|
||||
config DEBUG_UART_ARM_DCC
|
||||
bool "ARM DCC"
|
||||
help
|
||||
Select this to enable a debug UART using the ARM JTAG DCC port.
|
||||
The DCC port can be used for very early debugging and doesn't require
|
||||
any additional setting like address/baudrate/clock. On systems without
|
||||
any serial interface this is the easiest way how to get console.
|
||||
Every ARM core has own DCC port which is the part of debug interface.
|
||||
This port is available at least on ARMv6, ARMv7, ARMv8 and XScale
|
||||
architectures.
|
||||
|
||||
config DEBUG_MVEBU_A3700_UART
|
||||
bool "Marvell Armada 3700"
|
||||
help
|
||||
Select this to enable a debug UART using the serial_mvebu driver. You
|
||||
will need to provide parameters to make this work. The driver will
|
||||
be available until the real driver-model serial is running.
|
||||
|
||||
config DEBUG_UART_ZYNQ
|
||||
bool "Xilinx Zynq"
|
||||
help
|
||||
Select this to enable a debug UART using the serial_zynq driver. You
|
||||
will need to provide parameters to make this work. The driver will
|
||||
be available until the real driver-model serial is running.
|
||||
|
||||
config DEBUG_UART_APBUART
|
||||
depends on LEON3
|
||||
bool "Gaisler APBUART"
|
||||
help
|
||||
Select this to enable a debug UART using the serial_leon3 driver. You
|
||||
will need to provide parameters to make this work. The driver will
|
||||
be available until the real driver model serial is running.
|
||||
|
||||
config DEBUG_UART_PL010
|
||||
bool "pl010"
|
||||
help
|
||||
Select this to enable a debug UART using the pl01x driver with the
|
||||
PL010 UART type. You will need to provide parameters to make this
|
||||
work. The driver will be available until the real driver model
|
||||
serial is running.
|
||||
|
||||
config DEBUG_UART_PL011
|
||||
bool "pl011"
|
||||
help
|
||||
Select this to enable a debug UART using the pl01x driver with the
|
||||
PL011 UART type. You will need to provide parameters to make this
|
||||
work. The driver will be available until the real driver model
|
||||
serial is running.
|
||||
|
||||
config DEBUG_UART_PIC32
|
||||
bool "Microchip PIC32"
|
||||
depends on PIC32_SERIAL
|
||||
help
|
||||
Select this to enable a debug UART using the serial_pic32 driver. You
|
||||
will need to provide parameters to make this work. The driver will
|
||||
be available until the real driver model serial is running.
|
||||
|
||||
config DEBUG_UART_MXC
|
||||
bool "IMX Serial port"
|
||||
depends on MXC_UART
|
||||
help
|
||||
Select this to enable a debug UART using the serial_mxc driver. You
|
||||
will need to provide parameters to make this work. The driver will
|
||||
be available until the real driver model serial is running.
|
||||
|
||||
config DEBUG_UART_SANDBOX
|
||||
bool "sandbox"
|
||||
depends on SANDBOX_SERIAL
|
||||
help
|
||||
Select this to enable the debug UART using the sandbox driver. This
|
||||
provides basic serial output from the console without needing to
|
||||
start up driver model. The driver will be available until the real
|
||||
driver model serial is running.
|
||||
|
||||
config DEBUG_UART_SIFIVE
|
||||
bool "SiFive UART"
|
||||
help
|
||||
Select this to enable a debug UART using the serial_sifive driver. You
|
||||
will need to provide parameters to make this work. The driver will
|
||||
be available until the real driver-model serial is running.
|
||||
|
||||
config DEBUG_UART_STM32
|
||||
bool "STMicroelectronics STM32"
|
||||
depends on STM32_SERIAL
|
||||
help
|
||||
Select this to enable a debug UART using the serial_stm32 driver
|
||||
You will need to provide parameters to make this work.
|
||||
The driver will be available until the real driver model
|
||||
serial is running.
|
||||
|
||||
config DEBUG_UART_UNIPHIER
|
||||
bool "UniPhier on-chip UART"
|
||||
depends on ARCH_UNIPHIER
|
||||
help
|
||||
Select this to enable a debug UART using the UniPhier on-chip UART.
|
||||
You will need to provide DEBUG_UART_BASE to make this work. The
|
||||
driver will be available until the real driver-model serial is
|
||||
running.
|
||||
|
||||
config DEBUG_UART_OMAP
|
||||
bool "OMAP uart"
|
||||
help
|
||||
Select this to enable a debug UART using the omap ns16550 driver.
|
||||
You will need to provide parameters to make this work. The driver
|
||||
will be available until the real driver model serial is running.
|
||||
|
||||
config DEBUG_UART_MTK
|
||||
bool "MediaTek High-speed UART"
|
||||
depends on MTK_SERIAL
|
||||
help
|
||||
Select this to enable a debug UART using the MediaTek High-speed
|
||||
UART driver.
|
||||
You will need to provide parameters to make this work. The
|
||||
driver will be available until the real driver model serial is
|
||||
running.
|
||||
|
||||
endchoice
|
||||
|
||||
config DEBUG_UART_BASE
|
||||
hex "Base address of UART"
|
||||
depends on DEBUG_UART
|
||||
default 0 if DEBUG_UART_SANDBOX
|
||||
help
|
||||
This is the base address of your UART for memory-mapped UARTs.
|
||||
|
||||
A default should be provided by your board, but if not you will need
|
||||
to use the correct value here.
|
||||
|
||||
config DEBUG_UART_CLOCK
|
||||
int "UART input clock"
|
||||
depends on DEBUG_UART
|
||||
default 0 if DEBUG_UART_SANDBOX
|
||||
help
|
||||
The UART input clock determines the speed of the internal UART
|
||||
circuitry. The baud rate is derived from this by dividing the input
|
||||
clock down.
|
||||
|
||||
A default should be provided by your board, but if not you will need
|
||||
to use the correct value here.
|
||||
|
||||
config DEBUG_UART_SHIFT
|
||||
int "UART register shift"
|
||||
depends on DEBUG_UART
|
||||
default 0 if DEBUG_UART
|
||||
help
|
||||
Some UARTs (notably ns16550) support different register layouts
|
||||
where the registers are spaced either as bytes, words or some other
|
||||
value. Use this value to specify the shift to use, where 0=byte
|
||||
registers, 2=32-bit word registers, etc.
|
||||
|
||||
config DEBUG_UART_BOARD_INIT
|
||||
bool "Enable board-specific debug UART init"
|
||||
depends on DEBUG_UART
|
||||
help
|
||||
Some boards need to set things up before the debug UART can be used.
|
||||
On these boards a call to debug_uart_init() is insufficient. When
|
||||
this option is enabled, the function board_debug_uart_init() will
|
||||
be called when debug_uart_init() is called. You can put any code
|
||||
here that is needed to set up the UART ready for use, such as set
|
||||
pin multiplexing or enable clocks.
|
||||
|
||||
config DEBUG_UART_ANNOUNCE
|
||||
bool "Show a message when the debug UART starts up"
|
||||
depends on DEBUG_UART
|
||||
help
|
||||
Enable this option to show a message when the debug UART is ready
|
||||
for use. You will see a message like "<debug_uart> " as soon as
|
||||
U-Boot has the UART ready for use (i.e. your code calls
|
||||
debug_uart_init()). This can be useful just as a check that
|
||||
everything is working.
|
||||
|
||||
config DEBUG_UART_SKIP_INIT
|
||||
bool "Skip UART initialization"
|
||||
depends on DEBUG_UART
|
||||
help
|
||||
Select this if the UART you want to use for debug output is already
|
||||
initialized by the time U-Boot starts its execution.
|
||||
|
||||
config DEBUG_UART_NS16550_CHECK_ENABLED
|
||||
bool "Check if UART is enabled on output"
|
||||
depends on DEBUG_UART
|
||||
depends on DEBUG_UART_NS16550
|
||||
help
|
||||
Select this if puts()/putc() might be called before the debug UART
|
||||
has been initialized. If this is disabled, putc() might sit in a
|
||||
tight loop if it is called before debug_uart_init() has been called.
|
||||
|
||||
Note that this does not work for every ns16550-compatible UART and
|
||||
so has to be enabled carefully or you might notice lost characters.
|
||||
|
||||
config ALTERA_JTAG_UART
|
||||
bool "Altera JTAG UART support"
|
||||
depends on DM_SERIAL
|
||||
help
|
||||
Select this to enable an JTAG UART for Altera devices.The JTAG UART
|
||||
core implements a method to communicate serial character streams
|
||||
between a host PC and a Qsys system on an Altera FPGA. Please find
|
||||
details on the "Embedded Peripherals IP User Guide" of Altera.
|
||||
|
||||
config ALTERA_JTAG_UART_BYPASS
|
||||
bool "Bypass output when no connection"
|
||||
depends on ALTERA_JTAG_UART
|
||||
help
|
||||
Bypass console output and keep going even if there is no JTAG
|
||||
terminal connection with the host. The console output will resume
|
||||
once the JTAG terminal is connected. Without the bypass, the console
|
||||
output will wait forever until a JTAG terminal is connected. If you
|
||||
not are sure, say Y.
|
||||
|
||||
config ALTERA_UART
|
||||
bool "Altera UART support"
|
||||
depends on DM_SERIAL
|
||||
help
|
||||
Select this to enable an UART for Altera devices. Please find
|
||||
details on the "Embedded Peripherals IP User Guide" of Altera.
|
||||
|
||||
config AR933X_UART
|
||||
bool "QCA/Atheros ar933x UART support"
|
||||
depends on DM_SERIAL && SOC_AR933X
|
||||
help
|
||||
Select this to enable UART support for QCA/Atheros ar933x
|
||||
devices. This driver uses driver model and requires a device
|
||||
tree binding to operate, please refer to the document at
|
||||
doc/device-tree-bindings/serial/qca,ar9330-uart.txt.
|
||||
|
||||
config ARC_SERIAL
|
||||
bool "ARC UART support"
|
||||
depends on DM_SERIAL
|
||||
help
|
||||
Select this to enable support for ARC UART now typically
|
||||
only used in Synopsys DesignWare ARC simulators like nSIM.
|
||||
|
||||
config ATMEL_USART
|
||||
bool "Atmel USART support"
|
||||
help
|
||||
Select this to enable USART support for Atmel SoCs. It can be
|
||||
configured in the device tree, and input clock frequency can
|
||||
be got from the clk node.
|
||||
|
||||
config SPL_UART_CLOCK
|
||||
int "SPL fixed UART input clock"
|
||||
depends on ATMEL_USART && SPL && !SPL_CLK
|
||||
default 132096000 if ARCH_AT91
|
||||
help
|
||||
Provide a fixed clock value as input to the UART controller. This
|
||||
might be needed on platforms which can't enable CONFIG_SPL_CLK
|
||||
because of SPL image size restrictions.
|
||||
|
||||
config BCM283X_MU_SERIAL
|
||||
bool "Support for BCM283x Mini-UART"
|
||||
depends on DM_SERIAL && ARCH_BCM283X
|
||||
default y
|
||||
help
|
||||
Select this to enable Mini-UART support on BCM283X family of SoCs.
|
||||
|
||||
config BCM283X_PL011_SERIAL
|
||||
bool "Support for BCM283x PL011 UART"
|
||||
depends on PL01X_SERIAL && ARCH_BCM283X
|
||||
default y
|
||||
help
|
||||
Select this to enable an overriding PL011 driver for BCM283X SoCs
|
||||
that supports automatic disable, so that it only gets used when
|
||||
the UART is actually muxed.
|
||||
|
||||
config BCM6345_SERIAL
|
||||
bool "Support for BCM6345 UART"
|
||||
depends on DM_SERIAL
|
||||
help
|
||||
Select this to enable UART on BCM6345 SoCs.
|
||||
|
||||
config FSL_LINFLEXUART
|
||||
bool "Freescale Linflex UART support"
|
||||
depends on DM_SERIAL
|
||||
help
|
||||
Select this to enable the Linflex serial module found on some
|
||||
NXP SoCs like S32V234.
|
||||
|
||||
config FSL_LPUART
|
||||
bool "Freescale LPUART support"
|
||||
help
|
||||
Select this to enable a Low Power UART for Freescale VF610 and
|
||||
QorIQ Layerscape devices.
|
||||
|
||||
config MVEBU_A3700_UART
|
||||
bool "UART support for Armada 3700"
|
||||
default n
|
||||
help
|
||||
Choose this option to add support for UART driver on the Marvell
|
||||
Armada 3700 SoC. The base address is configured via DT.
|
||||
|
||||
config MCFUART
|
||||
bool "Freescale ColdFire UART support"
|
||||
help
|
||||
Choose this option to add support for UART driver on the ColdFire
|
||||
SoC's family. The serial communication channel provides a full-duplex
|
||||
asynchronous/synchronous receiver and transmitter deriving an
|
||||
operating frequency from the internal bus clock or an external clock.
|
||||
|
||||
config MXC_UART
|
||||
bool "IMX serial port support"
|
||||
depends on MX5 || MX6 || MX7 || IMX8M
|
||||
help
|
||||
If you have a machine based on a Motorola IMX CPU you
|
||||
can enable its onboard serial port by enabling this option.
|
||||
|
||||
config NULLDEV_SERIAL
|
||||
bool "Null serial device"
|
||||
help
|
||||
Select this to enable null serial device support. A null serial
|
||||
device merely acts as a placeholder for a serial device and does
|
||||
nothing for all it's operation.
|
||||
|
||||
config PIC32_SERIAL
|
||||
bool "Support for Microchip PIC32 on-chip UART"
|
||||
depends on DM_SERIAL && MACH_PIC32
|
||||
default y
|
||||
help
|
||||
Support for the UART found on Microchip PIC32 SoC's.
|
||||
|
||||
config SYS_NS16550
|
||||
bool "NS16550 UART or compatible"
|
||||
help
|
||||
Support NS16550 UART or compatible. This can be enabled in the
|
||||
device tree with the correct input clock frequency. If the input
|
||||
clock frequency is not defined in the device tree, the macro
|
||||
CONFIG_SYS_NS16550_CLK defined in a legacy board header file will
|
||||
be used. It can be a constant or a function to get clock, eg,
|
||||
get_serial_clock().
|
||||
|
||||
config INTEL_MID_SERIAL
|
||||
bool "Intel MID platform UART support"
|
||||
depends on DM_SERIAL && OF_CONTROL
|
||||
depends on INTEL_MID
|
||||
select SYS_NS16550
|
||||
help
|
||||
Select this to enable a UART for Intel MID platforms.
|
||||
This uses the ns16550 driver as a library.
|
||||
|
||||
config PL010_SERIAL
|
||||
bool "ARM PL010 driver"
|
||||
depends on !DM_SERIAL
|
||||
help
|
||||
Select this to enable a UART for platforms using PL010.
|
||||
|
||||
config PL011_SERIAL
|
||||
bool "ARM PL011 driver"
|
||||
depends on !DM_SERIAL
|
||||
help
|
||||
Select this to enable a UART for platforms using PL011.
|
||||
|
||||
config PL01X_SERIAL
|
||||
bool "ARM PL010 and PL011 driver"
|
||||
depends on DM_SERIAL
|
||||
help
|
||||
Select this to enable a UART for platforms using PL010 or PL011.
|
||||
|
||||
config ROCKCHIP_SERIAL
|
||||
bool "Rockchip on-chip UART support"
|
||||
depends on DM_SERIAL && SPL_OF_PLATDATA
|
||||
help
|
||||
Select this to enable a debug UART for Rockchip devices when using
|
||||
CONFIG_SPL_OF_PLATDATA (i.e. a compiled-in device tree replacemenmt).
|
||||
This uses the ns16550 driver, converting the platdata from of-platdata
|
||||
to the ns16550 format.
|
||||
|
||||
config SANDBOX_SERIAL
|
||||
bool "Sandbox UART support"
|
||||
depends on SANDBOX
|
||||
help
|
||||
Select this to enable a seral UART for sandbox. This is required to
|
||||
operate correctly, otherwise you will see no serial output from
|
||||
sandbox. The emulated UART will display to the console and console
|
||||
input will be fed into the UART. This allows you to interact with
|
||||
U-Boot.
|
||||
|
||||
The operation of the console is controlled by the -t command-line
|
||||
flag. In raw mode, U-Boot sees all characters from the terminal
|
||||
before they are processed, including Ctrl-C. In cooked mode, Ctrl-C
|
||||
is processed by the terminal, and terminates U-Boot. Valid options
|
||||
are:
|
||||
|
||||
-t raw-with-sigs Raw mode, Ctrl-C will terminate U-Boot
|
||||
-t raw Raw mode, Ctrl-C is processed by U-Boot
|
||||
-t cooked Cooked mode, Ctrl-C terminates
|
||||
|
||||
config SCIF_CONSOLE
|
||||
bool "Renesas SCIF UART support"
|
||||
depends on SH || ARCH_RMOBILE
|
||||
help
|
||||
Select this to enable Renesas SCIF UART. To operate serial ports
|
||||
on systems with RCar or SH SoCs, say Y to this option. If unsure,
|
||||
say N.
|
||||
|
||||
config UNIPHIER_SERIAL
|
||||
bool "Support for UniPhier on-chip UART"
|
||||
depends on ARCH_UNIPHIER
|
||||
default y
|
||||
help
|
||||
If you have a UniPhier based board and want to use the on-chip
|
||||
serial ports, say Y to this option. If unsure, say N.
|
||||
|
||||
config XILINX_UARTLITE
|
||||
bool "Xilinx Uarlite support"
|
||||
depends on DM_SERIAL && (MICROBLAZE || ARCH_ZYNQ || ARCH_ZYNQMP || 4xx)
|
||||
help
|
||||
If you have a Xilinx based board and want to use the uartlite
|
||||
serial ports, say Y to this option. If unsure, say N.
|
||||
|
||||
config MESON_SERIAL
|
||||
bool "Support for Amlogic Meson UART"
|
||||
depends on DM_SERIAL && ARCH_MESON
|
||||
help
|
||||
If you have an Amlogic Meson based board and want to use the on-chip
|
||||
serial ports, say Y to this option. If unsure, say N.
|
||||
|
||||
config MSM_SERIAL
|
||||
bool "Qualcomm on-chip UART"
|
||||
depends on DM_SERIAL
|
||||
help
|
||||
Support Data Mover UART used on Qualcomm Snapdragon SoCs.
|
||||
It should support all Qualcomm devices with UARTDM version 1.4,
|
||||
for example APQ8016 and MSM8916.
|
||||
Single baudrate is supported in current implementation (115200).
|
||||
|
||||
config OMAP_SERIAL
|
||||
bool "Support for OMAP specific UART"
|
||||
depends on DM_SERIAL
|
||||
default y if (ARCH_OMAP2PLUS || ARCH_K3)
|
||||
select SYS_NS16550
|
||||
help
|
||||
If you have an TI based SoC and want to use the on-chip serial
|
||||
port, say Y to this option. If unsure say N.
|
||||
|
||||
config OWL_SERIAL
|
||||
bool "Actions Semi OWL UART"
|
||||
depends on DM_SERIAL && ARCH_OWL
|
||||
help
|
||||
If you have a Actions Semi OWL based board and want to use the on-chip
|
||||
serial port, say Y to this option. If unsure, say N.
|
||||
Single baudrate is supported in current implementation (115200).
|
||||
|
||||
config PXA_SERIAL
|
||||
bool "PXA serial port support"
|
||||
help
|
||||
If you have a machine based on a Marvell XScale PXA2xx CPU you
|
||||
can enable its onboard serial ports by enabling this option.
|
||||
|
||||
config SIFIVE_SERIAL
|
||||
bool "SiFive UART support"
|
||||
depends on DM_SERIAL
|
||||
help
|
||||
This driver supports the SiFive UART. If unsure say N.
|
||||
|
||||
config STI_ASC_SERIAL
|
||||
bool "STMicroelectronics on-chip UART"
|
||||
depends on DM_SERIAL && ARCH_STI
|
||||
help
|
||||
Select this to enable Asynchronous Serial Controller available
|
||||
on STiH410 SoC. This is a basic implementation, it supports
|
||||
following baudrate 9600, 19200, 38400, 57600 and 115200.
|
||||
|
||||
config STM32_SERIAL
|
||||
bool "STMicroelectronics STM32 SoCs on-chip UART"
|
||||
depends on DM_SERIAL && (STM32F4 || STM32F7 || STM32H7 || ARCH_STM32MP)
|
||||
help
|
||||
If you have a machine based on a STM32 F4, F7, H7 or MP1 SOC
|
||||
you can enable its onboard serial ports, say Y to this option.
|
||||
If unsure, say N.
|
||||
|
||||
config ZYNQ_SERIAL
|
||||
bool "Cadence (Xilinx Zynq) UART support"
|
||||
depends on DM_SERIAL && (MICROBLAZE || ARCH_ZYNQ || ARCH_ZYNQMP || ARCH_ZYNQMP_R5)
|
||||
help
|
||||
This driver supports the Cadence UART. It is found e.g. in Xilinx
|
||||
Zynq/ZynqMP.
|
||||
|
||||
config MTK_SERIAL
|
||||
bool "MediaTek High-speed UART support"
|
||||
depends on DM_SERIAL
|
||||
help
|
||||
Select this to enable UART support for MediaTek High-speed UART
|
||||
devices. This driver uses driver model and requires a device
|
||||
tree binding to operate.
|
||||
The High-speed UART is compatible with the ns16550a UART and have
|
||||
its own high-speed registers.
|
||||
|
||||
config MPC8XX_CONS
|
||||
bool "Console driver for MPC8XX"
|
||||
depends on MPC8xx
|
||||
default y
|
||||
|
||||
choice
|
||||
prompt "Console port"
|
||||
default 8xx_CONS_SMC1
|
||||
depends on MPC8XX_CONS
|
||||
help
|
||||
Depending on board, select one serial port
|
||||
(CONFIG_8xx_CONS_SMC1 or CONFIG_8xx_CONS_SMC2)
|
||||
|
||||
config 8xx_CONS_SMC1
|
||||
bool "SMC1"
|
||||
|
||||
config 8xx_CONS_SMC2
|
||||
bool "SMC2"
|
||||
|
||||
endchoice
|
||||
|
||||
config SYS_SMC_RXBUFLEN
|
||||
int "Console Rx buffer length"
|
||||
depends on MPC8XX_CONS
|
||||
default 1
|
||||
help
|
||||
With CONFIG_SYS_SMC_RXBUFLEN it is possible to define
|
||||
the maximum receive buffer length for the SMC.
|
||||
This option is actual only for 8xx possible.
|
||||
If using CONFIG_SYS_SMC_RXBUFLEN also CONFIG_SYS_MAXIDLE
|
||||
must be defined, to setup the maximum idle timeout for
|
||||
the SMC.
|
||||
|
||||
config SYS_MAXIDLE
|
||||
int "maximum idle timeout"
|
||||
depends on MPC8XX_CONS
|
||||
default 0
|
||||
|
||||
config SYS_BRGCLK_PRESCALE
|
||||
int "BRG Clock Prescale"
|
||||
depends on MPC8XX_CONS
|
||||
default 1
|
||||
|
||||
config SYS_SDSR
|
||||
hex "SDSR Value"
|
||||
depends on MPC8XX_CONS
|
||||
default 0x83
|
||||
|
||||
config SYS_SDMR
|
||||
hex "SDMR Value"
|
||||
depends on MPC8XX_CONS
|
||||
default 0
|
||||
|
||||
endmenu
|
||||
@@ -0,0 +1,74 @@
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
#
|
||||
# (C) Copyright 2006-2009
|
||||
# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
|
||||
|
||||
ifdef CONFIG_SPL_BUILD
|
||||
|
||||
ifeq ($(CONFIG_$(SPL_TPL_)BUILD)$(CONFIG_$(SPL_TPL_)DM_SERIAL),yy)
|
||||
obj-y += serial-uclass.o
|
||||
else
|
||||
obj-y += serial.o
|
||||
endif
|
||||
|
||||
else
|
||||
|
||||
ifdef CONFIG_DM_SERIAL
|
||||
obj-y += serial-uclass.o
|
||||
else
|
||||
obj-y += serial.o
|
||||
endif
|
||||
|
||||
endif
|
||||
|
||||
ifdef CONFIG_DM_SERIAL
|
||||
obj-$(CONFIG_PL01X_SERIAL) += serial_pl01x.o
|
||||
else
|
||||
obj-$(CONFIG_PL010_SERIAL) += serial_pl01x.o
|
||||
obj-$(CONFIG_PL011_SERIAL) += serial_pl01x.o
|
||||
obj-$(CONFIG_SYS_NS16550_SERIAL) += serial_ns16550.o
|
||||
endif
|
||||
|
||||
obj-$(CONFIG_ALTERA_UART) += altera_uart.o
|
||||
obj-$(CONFIG_ALTERA_JTAG_UART) += altera_jtag_uart.o
|
||||
obj-$(CONFIG_AR933X_UART) += serial_ar933x.o
|
||||
obj-$(CONFIG_ARM_DCC) += arm_dcc.o
|
||||
obj-$(CONFIG_ATMEL_USART) += atmel_usart.o
|
||||
obj-$(CONFIG_BCM6345_SERIAL) += serial_bcm6345.o
|
||||
obj-$(CONFIG_EFI_APP) += serial_efi.o
|
||||
obj-$(CONFIG_LPC32XX_HSUART) += lpc32xx_hsuart.o
|
||||
obj-$(CONFIG_MCFUART) += mcfuart.o
|
||||
obj-$(CONFIG_SYS_NS16550) += ns16550.o
|
||||
obj-$(CONFIG_S5P) += serial_s5p.o
|
||||
obj-$(CONFIG_MXC_UART) += serial_mxc.o
|
||||
obj-$(CONFIG_PXA_SERIAL) += serial_pxa.o
|
||||
obj-$(CONFIG_MESON_SERIAL) += serial_meson.o
|
||||
obj-$(CONFIG_INTEL_MID_SERIAL) += serial_intel_mid.o
|
||||
ifdef CONFIG_SPL_BUILD
|
||||
obj-$(CONFIG_ROCKCHIP_SERIAL) += serial_rockchip.o
|
||||
endif
|
||||
obj-$(CONFIG_XILINX_UARTLITE) += serial_xuartlite.o
|
||||
obj-$(CONFIG_SANDBOX_SERIAL) += sandbox.o
|
||||
obj-$(CONFIG_SCIF_CONSOLE) += serial_sh.o
|
||||
obj-$(CONFIG_ZYNQ_SERIAL) += serial_zynq.o
|
||||
obj-$(CONFIG_FSL_LPUART) += serial_lpuart.o
|
||||
obj-$(CONFIG_FSL_LINFLEXUART) += serial_linflexuart.o
|
||||
obj-$(CONFIG_ARC_SERIAL) += serial_arc.o
|
||||
obj-$(CONFIG_UNIPHIER_SERIAL) += serial_uniphier.o
|
||||
obj-$(CONFIG_STM32_SERIAL) += serial_stm32.o
|
||||
obj-$(CONFIG_STI_ASC_SERIAL) += serial_sti_asc.o
|
||||
obj-$(CONFIG_PIC32_SERIAL) += serial_pic32.o
|
||||
obj-$(CONFIG_BCM283X_MU_SERIAL) += serial_bcm283x_mu.o
|
||||
obj-$(CONFIG_BCM283X_PL011_SERIAL) += serial_bcm283x_pl011.o
|
||||
obj-$(CONFIG_MSM_SERIAL) += serial_msm.o
|
||||
obj-$(CONFIG_MVEBU_A3700_UART) += serial_mvebu_a3700.o
|
||||
obj-$(CONFIG_MPC8XX_CONS) += serial_mpc8xx.o
|
||||
obj-$(CONFIG_NULLDEV_SERIAL) += serial_nulldev.o
|
||||
obj-$(CONFIG_OWL_SERIAL) += serial_owl.o
|
||||
obj-$(CONFIG_OMAP_SERIAL) += serial_omap.o
|
||||
obj-$(CONFIG_MTK_SERIAL) += serial_mtk.o
|
||||
obj-$(CONFIG_SIFIVE_SERIAL) += serial_sifive.o
|
||||
|
||||
ifndef CONFIG_SPL_BUILD
|
||||
obj-$(CONFIG_USB_TTY) += usbtty.o
|
||||
endif
|
||||
@@ -0,0 +1,150 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* (C) Copyright 2004, Psyent Corporation <www.psyent.com>
|
||||
* Scott McNutt <smcnutt@psyent.com>
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <dm.h>
|
||||
#include <errno.h>
|
||||
#include <serial.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
/* data register */
|
||||
#define ALTERA_JTAG_RVALID BIT(15) /* Read valid */
|
||||
|
||||
/* control register */
|
||||
#define ALTERA_JTAG_AC BIT(10) /* activity indicator */
|
||||
#define ALTERA_JTAG_RRDY BIT(12) /* read available */
|
||||
#define ALTERA_JTAG_WSPACE(d) ((d) >> 16) /* Write space avail */
|
||||
/* Write fifo size. FIXME: this should be extracted with sopc2dts */
|
||||
#define ALTERA_JTAG_WRITE_DEPTH 64
|
||||
|
||||
struct altera_jtaguart_regs {
|
||||
u32 data; /* Data register */
|
||||
u32 control; /* Control register */
|
||||
};
|
||||
|
||||
struct altera_jtaguart_platdata {
|
||||
struct altera_jtaguart_regs *regs;
|
||||
};
|
||||
|
||||
static int altera_jtaguart_setbrg(struct udevice *dev, int baudrate)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int altera_jtaguart_putc(struct udevice *dev, const char ch)
|
||||
{
|
||||
struct altera_jtaguart_platdata *plat = dev->platdata;
|
||||
struct altera_jtaguart_regs *const regs = plat->regs;
|
||||
u32 st = readl(®s->control);
|
||||
|
||||
#ifdef CONFIG_ALTERA_JTAG_UART_BYPASS
|
||||
if (!(st & ALTERA_JTAG_AC)) /* no connection yet */
|
||||
return -ENETUNREACH;
|
||||
#endif
|
||||
|
||||
if (ALTERA_JTAG_WSPACE(st) == 0)
|
||||
return -EAGAIN;
|
||||
|
||||
writel(ch, ®s->data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int altera_jtaguart_pending(struct udevice *dev, bool input)
|
||||
{
|
||||
struct altera_jtaguart_platdata *plat = dev->platdata;
|
||||
struct altera_jtaguart_regs *const regs = plat->regs;
|
||||
u32 st = readl(®s->control);
|
||||
|
||||
if (input)
|
||||
return st & ALTERA_JTAG_RRDY ? 1 : 0;
|
||||
else
|
||||
return !(ALTERA_JTAG_WSPACE(st) == ALTERA_JTAG_WRITE_DEPTH);
|
||||
}
|
||||
|
||||
static int altera_jtaguart_getc(struct udevice *dev)
|
||||
{
|
||||
struct altera_jtaguart_platdata *plat = dev->platdata;
|
||||
struct altera_jtaguart_regs *const regs = plat->regs;
|
||||
u32 val;
|
||||
|
||||
val = readl(®s->data);
|
||||
|
||||
if (!(val & ALTERA_JTAG_RVALID))
|
||||
return -EAGAIN;
|
||||
|
||||
return val & 0xff;
|
||||
}
|
||||
|
||||
static int altera_jtaguart_probe(struct udevice *dev)
|
||||
{
|
||||
#ifdef CONFIG_ALTERA_JTAG_UART_BYPASS
|
||||
struct altera_jtaguart_platdata *plat = dev->platdata;
|
||||
struct altera_jtaguart_regs *const regs = plat->regs;
|
||||
|
||||
writel(ALTERA_JTAG_AC, ®s->control); /* clear AC flag */
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int altera_jtaguart_ofdata_to_platdata(struct udevice *dev)
|
||||
{
|
||||
struct altera_jtaguart_platdata *plat = dev_get_platdata(dev);
|
||||
|
||||
plat->regs = map_physmem(devfdt_get_addr(dev),
|
||||
sizeof(struct altera_jtaguart_regs),
|
||||
MAP_NOCACHE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dm_serial_ops altera_jtaguart_ops = {
|
||||
.putc = altera_jtaguart_putc,
|
||||
.pending = altera_jtaguart_pending,
|
||||
.getc = altera_jtaguart_getc,
|
||||
.setbrg = altera_jtaguart_setbrg,
|
||||
};
|
||||
|
||||
static const struct udevice_id altera_jtaguart_ids[] = {
|
||||
{ .compatible = "altr,juart-1.0" },
|
||||
{}
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(altera_jtaguart) = {
|
||||
.name = "altera_jtaguart",
|
||||
.id = UCLASS_SERIAL,
|
||||
.of_match = altera_jtaguart_ids,
|
||||
.ofdata_to_platdata = altera_jtaguart_ofdata_to_platdata,
|
||||
.platdata_auto_alloc_size = sizeof(struct altera_jtaguart_platdata),
|
||||
.probe = altera_jtaguart_probe,
|
||||
.ops = &altera_jtaguart_ops,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_DEBUG_UART_ALTERA_JTAGUART
|
||||
|
||||
#include <debug_uart.h>
|
||||
|
||||
static inline void _debug_uart_init(void)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void _debug_uart_putc(int ch)
|
||||
{
|
||||
struct altera_jtaguart_regs *regs = (void *)CONFIG_DEBUG_UART_BASE;
|
||||
|
||||
while (1) {
|
||||
u32 st = readl(®s->control);
|
||||
|
||||
if (ALTERA_JTAG_WSPACE(st))
|
||||
break;
|
||||
}
|
||||
|
||||
writel(ch, ®s->data);
|
||||
}
|
||||
|
||||
DEBUG_UART_FUNCS
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,148 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* (C) Copyright 2004, Psyent Corporation <www.psyent.com>
|
||||
* Scott McNutt <smcnutt@psyent.com>
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <dm.h>
|
||||
#include <errno.h>
|
||||
#include <serial.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
/* status register */
|
||||
#define ALTERA_UART_TMT BIT(5) /* tx empty */
|
||||
#define ALTERA_UART_TRDY BIT(6) /* tx ready */
|
||||
#define ALTERA_UART_RRDY BIT(7) /* rx ready */
|
||||
|
||||
struct altera_uart_regs {
|
||||
u32 rxdata; /* Rx data reg */
|
||||
u32 txdata; /* Tx data reg */
|
||||
u32 status; /* Status reg */
|
||||
u32 control; /* Control reg */
|
||||
u32 divisor; /* Baud rate divisor reg */
|
||||
u32 endofpacket; /* End-of-packet reg */
|
||||
};
|
||||
|
||||
struct altera_uart_platdata {
|
||||
struct altera_uart_regs *regs;
|
||||
unsigned int uartclk;
|
||||
};
|
||||
|
||||
static int altera_uart_setbrg(struct udevice *dev, int baudrate)
|
||||
{
|
||||
struct altera_uart_platdata *plat = dev->platdata;
|
||||
struct altera_uart_regs *const regs = plat->regs;
|
||||
u32 div;
|
||||
|
||||
div = (plat->uartclk / baudrate) - 1;
|
||||
writel(div, ®s->divisor);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int altera_uart_putc(struct udevice *dev, const char ch)
|
||||
{
|
||||
struct altera_uart_platdata *plat = dev->platdata;
|
||||
struct altera_uart_regs *const regs = plat->regs;
|
||||
|
||||
if (!(readl(®s->status) & ALTERA_UART_TRDY))
|
||||
return -EAGAIN;
|
||||
|
||||
writel(ch, ®s->txdata);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int altera_uart_pending(struct udevice *dev, bool input)
|
||||
{
|
||||
struct altera_uart_platdata *plat = dev->platdata;
|
||||
struct altera_uart_regs *const regs = plat->regs;
|
||||
u32 st = readl(®s->status);
|
||||
|
||||
if (input)
|
||||
return st & ALTERA_UART_RRDY ? 1 : 0;
|
||||
else
|
||||
return !(st & ALTERA_UART_TMT);
|
||||
}
|
||||
|
||||
static int altera_uart_getc(struct udevice *dev)
|
||||
{
|
||||
struct altera_uart_platdata *plat = dev->platdata;
|
||||
struct altera_uart_regs *const regs = plat->regs;
|
||||
|
||||
if (!(readl(®s->status) & ALTERA_UART_RRDY))
|
||||
return -EAGAIN;
|
||||
|
||||
return readl(®s->rxdata) & 0xff;
|
||||
}
|
||||
|
||||
static int altera_uart_probe(struct udevice *dev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int altera_uart_ofdata_to_platdata(struct udevice *dev)
|
||||
{
|
||||
struct altera_uart_platdata *plat = dev_get_platdata(dev);
|
||||
|
||||
plat->regs = map_physmem(devfdt_get_addr(dev),
|
||||
sizeof(struct altera_uart_regs),
|
||||
MAP_NOCACHE);
|
||||
plat->uartclk = dev_read_u32_default(dev, "clock-frequency", 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dm_serial_ops altera_uart_ops = {
|
||||
.putc = altera_uart_putc,
|
||||
.pending = altera_uart_pending,
|
||||
.getc = altera_uart_getc,
|
||||
.setbrg = altera_uart_setbrg,
|
||||
};
|
||||
|
||||
static const struct udevice_id altera_uart_ids[] = {
|
||||
{ .compatible = "altr,uart-1.0" },
|
||||
{}
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(altera_uart) = {
|
||||
.name = "altera_uart",
|
||||
.id = UCLASS_SERIAL,
|
||||
.of_match = altera_uart_ids,
|
||||
.ofdata_to_platdata = altera_uart_ofdata_to_platdata,
|
||||
.platdata_auto_alloc_size = sizeof(struct altera_uart_platdata),
|
||||
.probe = altera_uart_probe,
|
||||
.ops = &altera_uart_ops,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_DEBUG_UART_ALTERA_UART
|
||||
|
||||
#include <debug_uart.h>
|
||||
|
||||
static inline void _debug_uart_init(void)
|
||||
{
|
||||
struct altera_uart_regs *regs = (void *)CONFIG_DEBUG_UART_BASE;
|
||||
u32 div;
|
||||
|
||||
div = (CONFIG_DEBUG_UART_CLOCK / CONFIG_BAUDRATE) - 1;
|
||||
writel(div, ®s->divisor);
|
||||
}
|
||||
|
||||
static inline void _debug_uart_putc(int ch)
|
||||
{
|
||||
struct altera_uart_regs *regs = (void *)CONFIG_DEBUG_UART_BASE;
|
||||
|
||||
while (1) {
|
||||
u32 st = readl(®s->status);
|
||||
|
||||
if (st & ALTERA_UART_TRDY)
|
||||
break;
|
||||
}
|
||||
|
||||
writel(ch, ®s->txdata);
|
||||
}
|
||||
|
||||
DEBUG_UART_FUNCS
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,174 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (C) 2004-2007 ARM Limited.
|
||||
* Copyright (C) 2008 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
|
||||
* Copyright (C) 2015 - 2016 Xilinx, Inc, Michal Simek
|
||||
*
|
||||
* As a special exception, if other files instantiate templates or use macros
|
||||
* or inline functions from this file, or you compile this file and link it
|
||||
* with other works to produce a work based on this file, this file does not
|
||||
* by itself cause the resulting work to be covered by the GNU General Public
|
||||
* License. However the source code for this file must still be made available
|
||||
* in accordance with section (3) of the GNU General Public License.
|
||||
|
||||
* This exception does not invalidate any other reasons why a work based on
|
||||
* this file might be covered by the GNU General Public License.
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <dm.h>
|
||||
#include <serial.h>
|
||||
|
||||
#if defined(CONFIG_CPU_V6) || defined(CONFIG_CPU_V7A) || defined(CONFIG_CPU_V7R)
|
||||
/*
|
||||
* ARMV6 & ARMV7
|
||||
*/
|
||||
#define DCC_RBIT (1 << 30)
|
||||
#define DCC_WBIT (1 << 29)
|
||||
|
||||
#define write_dcc(x) \
|
||||
__asm__ volatile ("mcr p14, 0, %0, c0, c5, 0\n" : : "r" (x))
|
||||
|
||||
#define read_dcc(x) \
|
||||
__asm__ volatile ("mrc p14, 0, %0, c0, c5, 0\n" : "=r" (x))
|
||||
|
||||
#define status_dcc(x) \
|
||||
__asm__ volatile ("mrc p14, 0, %0, c0, c1, 0\n" : "=r" (x))
|
||||
|
||||
#elif defined(CONFIG_CPU_XSCALE)
|
||||
/*
|
||||
* XSCALE
|
||||
*/
|
||||
#define DCC_RBIT (1 << 31)
|
||||
#define DCC_WBIT (1 << 28)
|
||||
|
||||
#define write_dcc(x) \
|
||||
__asm__ volatile ("mcr p14, 0, %0, c8, c0, 0\n" : : "r" (x))
|
||||
|
||||
#define read_dcc(x) \
|
||||
__asm__ volatile ("mrc p14, 0, %0, c9, c0, 0\n" : "=r" (x))
|
||||
|
||||
#define status_dcc(x) \
|
||||
__asm__ volatile ("mrc p14, 0, %0, c14, c0, 0\n" : "=r" (x))
|
||||
|
||||
#elif defined(CONFIG_CPU_ARMV8)
|
||||
/*
|
||||
* ARMV8
|
||||
*/
|
||||
#define DCC_RBIT (1 << 30)
|
||||
#define DCC_WBIT (1 << 29)
|
||||
|
||||
#define write_dcc(x) \
|
||||
__asm__ volatile ("msr dbgdtrtx_el0, %0\n" : : "r" (x))
|
||||
|
||||
#define read_dcc(x) \
|
||||
__asm__ volatile ("mrs %0, dbgdtrrx_el0\n" : "=r" (x))
|
||||
|
||||
#define status_dcc(x) \
|
||||
__asm__ volatile ("mrs %0, mdccsr_el0\n" : "=r" (x))
|
||||
|
||||
#else
|
||||
#define DCC_RBIT (1 << 0)
|
||||
#define DCC_WBIT (1 << 1)
|
||||
|
||||
#define write_dcc(x) \
|
||||
__asm__ volatile ("mcr p14, 0, %0, c1, c0, 0\n" : : "r" (x))
|
||||
|
||||
#define read_dcc(x) \
|
||||
__asm__ volatile ("mrc p14, 0, %0, c1, c0, 0\n" : "=r" (x))
|
||||
|
||||
#define status_dcc(x) \
|
||||
__asm__ volatile ("mrc p14, 0, %0, c0, c0, 0\n" : "=r" (x))
|
||||
|
||||
#endif
|
||||
|
||||
#define can_read_dcc(x) do { \
|
||||
status_dcc(x); \
|
||||
x &= DCC_RBIT; \
|
||||
} while (0);
|
||||
|
||||
#define can_write_dcc(x) do { \
|
||||
status_dcc(x); \
|
||||
x &= DCC_WBIT; \
|
||||
x = (x == 0); \
|
||||
} while (0);
|
||||
|
||||
#define TIMEOUT_COUNT 0x4000000
|
||||
|
||||
static int arm_dcc_getc(struct udevice *dev)
|
||||
{
|
||||
int ch;
|
||||
register unsigned int reg;
|
||||
|
||||
do {
|
||||
can_read_dcc(reg);
|
||||
} while (!reg);
|
||||
read_dcc(ch);
|
||||
|
||||
return ch;
|
||||
}
|
||||
|
||||
static int arm_dcc_putc(struct udevice *dev, char ch)
|
||||
{
|
||||
register unsigned int reg;
|
||||
unsigned int timeout_count = TIMEOUT_COUNT;
|
||||
|
||||
while (--timeout_count) {
|
||||
can_write_dcc(reg);
|
||||
if (reg)
|
||||
break;
|
||||
}
|
||||
if (timeout_count == 0)
|
||||
return -EAGAIN;
|
||||
else
|
||||
write_dcc(ch);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int arm_dcc_pending(struct udevice *dev, bool input)
|
||||
{
|
||||
register unsigned int reg;
|
||||
|
||||
if (input) {
|
||||
can_read_dcc(reg);
|
||||
} else {
|
||||
can_write_dcc(reg);
|
||||
}
|
||||
|
||||
return reg;
|
||||
}
|
||||
|
||||
static const struct dm_serial_ops arm_dcc_ops = {
|
||||
.putc = arm_dcc_putc,
|
||||
.pending = arm_dcc_pending,
|
||||
.getc = arm_dcc_getc,
|
||||
};
|
||||
|
||||
static const struct udevice_id arm_dcc_ids[] = {
|
||||
{ .compatible = "arm,dcc", },
|
||||
{ }
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(serial_dcc) = {
|
||||
.name = "arm_dcc",
|
||||
.id = UCLASS_SERIAL,
|
||||
.of_match = arm_dcc_ids,
|
||||
.ops = &arm_dcc_ops,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_DEBUG_UART_ARM_DCC
|
||||
|
||||
#include <debug_uart.h>
|
||||
|
||||
static inline void _debug_uart_init(void)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void _debug_uart_putc(int ch)
|
||||
{
|
||||
arm_dcc_putc(NULL, ch);
|
||||
}
|
||||
|
||||
DEBUG_UART_FUNCS
|
||||
#endif
|
||||
@@ -0,0 +1,335 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright (C) 2004-2006 Atmel Corporation
|
||||
*
|
||||
* Modified to support C structur SoC access by
|
||||
* Andreas Bießmann <biessmann@corscience.de>
|
||||
*/
|
||||
#include <common.h>
|
||||
#include <clk.h>
|
||||
#include <dm.h>
|
||||
#include <errno.h>
|
||||
#include <watchdog.h>
|
||||
#include <serial.h>
|
||||
#include <debug_uart.h>
|
||||
#include <linux/compiler.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
#ifdef CONFIG_DM_SERIAL
|
||||
#include <asm/arch/atmel_serial.h>
|
||||
#endif
|
||||
#include <asm/arch/clk.h>
|
||||
#include <asm/arch/hardware.h>
|
||||
|
||||
#include "atmel_usart.h"
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
#ifndef CONFIG_DM_SERIAL
|
||||
static void atmel_serial_setbrg_internal(atmel_usart3_t *usart, int id,
|
||||
int baudrate)
|
||||
{
|
||||
unsigned long divisor;
|
||||
unsigned long usart_hz;
|
||||
|
||||
/*
|
||||
* Master Clock
|
||||
* Baud Rate = --------------
|
||||
* 16 * CD
|
||||
*/
|
||||
usart_hz = get_usart_clk_rate(id);
|
||||
divisor = (usart_hz / 16 + baudrate / 2) / baudrate;
|
||||
writel(USART3_BF(CD, divisor), &usart->brgr);
|
||||
}
|
||||
|
||||
static void atmel_serial_init_internal(atmel_usart3_t *usart)
|
||||
{
|
||||
/*
|
||||
* Just in case: drain transmitter register
|
||||
* 1000us is enough for baudrate >= 9600
|
||||
*/
|
||||
if (!(readl(&usart->csr) & USART3_BIT(TXEMPTY)))
|
||||
__udelay(1000);
|
||||
|
||||
writel(USART3_BIT(RSTRX) | USART3_BIT(RSTTX), &usart->cr);
|
||||
}
|
||||
|
||||
static void atmel_serial_activate(atmel_usart3_t *usart)
|
||||
{
|
||||
writel((USART3_BF(USART_MODE, USART3_USART_MODE_NORMAL)
|
||||
| USART3_BF(USCLKS, USART3_USCLKS_MCK)
|
||||
| USART3_BF(CHRL, USART3_CHRL_8)
|
||||
| USART3_BF(PAR, USART3_PAR_NONE)
|
||||
| USART3_BF(NBSTOP, USART3_NBSTOP_1)),
|
||||
&usart->mr);
|
||||
writel(USART3_BIT(RXEN) | USART3_BIT(TXEN), &usart->cr);
|
||||
/* 100us is enough for the new settings to be settled */
|
||||
__udelay(100);
|
||||
}
|
||||
|
||||
static void atmel_serial_setbrg(void)
|
||||
{
|
||||
atmel_serial_setbrg_internal((atmel_usart3_t *)CONFIG_USART_BASE,
|
||||
CONFIG_USART_ID, gd->baudrate);
|
||||
}
|
||||
|
||||
static int atmel_serial_init(void)
|
||||
{
|
||||
atmel_usart3_t *usart = (atmel_usart3_t *)CONFIG_USART_BASE;
|
||||
|
||||
atmel_serial_init_internal(usart);
|
||||
serial_setbrg();
|
||||
atmel_serial_activate(usart);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void atmel_serial_putc(char c)
|
||||
{
|
||||
atmel_usart3_t *usart = (atmel_usart3_t *)CONFIG_USART_BASE;
|
||||
|
||||
if (c == '\n')
|
||||
serial_putc('\r');
|
||||
|
||||
while (!(readl(&usart->csr) & USART3_BIT(TXRDY)));
|
||||
writel(c, &usart->thr);
|
||||
}
|
||||
|
||||
static int atmel_serial_getc(void)
|
||||
{
|
||||
atmel_usart3_t *usart = (atmel_usart3_t *)CONFIG_USART_BASE;
|
||||
|
||||
while (!(readl(&usart->csr) & USART3_BIT(RXRDY)))
|
||||
WATCHDOG_RESET();
|
||||
return readl(&usart->rhr);
|
||||
}
|
||||
|
||||
static int atmel_serial_tstc(void)
|
||||
{
|
||||
atmel_usart3_t *usart = (atmel_usart3_t *)CONFIG_USART_BASE;
|
||||
return (readl(&usart->csr) & USART3_BIT(RXRDY)) != 0;
|
||||
}
|
||||
|
||||
static struct serial_device atmel_serial_drv = {
|
||||
.name = "atmel_serial",
|
||||
.start = atmel_serial_init,
|
||||
.stop = NULL,
|
||||
.setbrg = atmel_serial_setbrg,
|
||||
.putc = atmel_serial_putc,
|
||||
.puts = default_serial_puts,
|
||||
.getc = atmel_serial_getc,
|
||||
.tstc = atmel_serial_tstc,
|
||||
};
|
||||
|
||||
void atmel_serial_initialize(void)
|
||||
{
|
||||
serial_register(&atmel_serial_drv);
|
||||
}
|
||||
|
||||
__weak struct serial_device *default_serial_console(void)
|
||||
{
|
||||
return &atmel_serial_drv;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_DM_SERIAL
|
||||
enum serial_clk_type {
|
||||
CLK_TYPE_NORMAL = 0,
|
||||
CLK_TYPE_DBGU,
|
||||
};
|
||||
|
||||
struct atmel_serial_priv {
|
||||
atmel_usart3_t *usart;
|
||||
ulong usart_clk_rate;
|
||||
};
|
||||
|
||||
static void _atmel_serial_set_brg(atmel_usart3_t *usart,
|
||||
ulong usart_clk_rate, int baudrate)
|
||||
{
|
||||
unsigned long divisor;
|
||||
|
||||
divisor = (usart_clk_rate / 16 + baudrate / 2) / baudrate;
|
||||
writel(USART3_BF(CD, divisor), &usart->brgr);
|
||||
}
|
||||
|
||||
void _atmel_serial_init(atmel_usart3_t *usart,
|
||||
ulong usart_clk_rate, int baudrate)
|
||||
{
|
||||
writel(USART3_BIT(RXDIS) | USART3_BIT(TXDIS), &usart->cr);
|
||||
|
||||
writel((USART3_BF(USART_MODE, USART3_USART_MODE_NORMAL) |
|
||||
USART3_BF(USCLKS, USART3_USCLKS_MCK) |
|
||||
USART3_BF(CHRL, USART3_CHRL_8) |
|
||||
USART3_BF(PAR, USART3_PAR_NONE) |
|
||||
USART3_BF(NBSTOP, USART3_NBSTOP_1)), &usart->mr);
|
||||
|
||||
_atmel_serial_set_brg(usart, usart_clk_rate, baudrate);
|
||||
|
||||
writel(USART3_BIT(RSTRX) | USART3_BIT(RSTTX), &usart->cr);
|
||||
writel(USART3_BIT(RXEN) | USART3_BIT(TXEN), &usart->cr);
|
||||
}
|
||||
|
||||
int atmel_serial_setbrg(struct udevice *dev, int baudrate)
|
||||
{
|
||||
struct atmel_serial_priv *priv = dev_get_priv(dev);
|
||||
|
||||
_atmel_serial_set_brg(priv->usart, priv->usart_clk_rate, baudrate);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int atmel_serial_getc(struct udevice *dev)
|
||||
{
|
||||
struct atmel_serial_priv *priv = dev_get_priv(dev);
|
||||
|
||||
if (!(readl(&priv->usart->csr) & USART3_BIT(RXRDY)))
|
||||
return -EAGAIN;
|
||||
|
||||
return readl(&priv->usart->rhr);
|
||||
}
|
||||
|
||||
static int atmel_serial_putc(struct udevice *dev, const char ch)
|
||||
{
|
||||
struct atmel_serial_priv *priv = dev_get_priv(dev);
|
||||
|
||||
if (!(readl(&priv->usart->csr) & USART3_BIT(TXRDY)))
|
||||
return -EAGAIN;
|
||||
|
||||
writel(ch, &priv->usart->thr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int atmel_serial_pending(struct udevice *dev, bool input)
|
||||
{
|
||||
struct atmel_serial_priv *priv = dev_get_priv(dev);
|
||||
uint32_t csr = readl(&priv->usart->csr);
|
||||
|
||||
if (input)
|
||||
return csr & USART3_BIT(RXRDY) ? 1 : 0;
|
||||
else
|
||||
return csr & USART3_BIT(TXEMPTY) ? 0 : 1;
|
||||
}
|
||||
|
||||
static const struct dm_serial_ops atmel_serial_ops = {
|
||||
.putc = atmel_serial_putc,
|
||||
.pending = atmel_serial_pending,
|
||||
.getc = atmel_serial_getc,
|
||||
.setbrg = atmel_serial_setbrg,
|
||||
};
|
||||
|
||||
#if defined(CONFIG_SPL_BUILD) && !defined(CONFIG_SPL_CLK)
|
||||
static int atmel_serial_enable_clk(struct udevice *dev)
|
||||
{
|
||||
struct atmel_serial_priv *priv = dev_get_priv(dev);
|
||||
|
||||
/* Use fixed clock value in SPL */
|
||||
priv->usart_clk_rate = CONFIG_SPL_UART_CLOCK;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
static int atmel_serial_enable_clk(struct udevice *dev)
|
||||
{
|
||||
struct atmel_serial_priv *priv = dev_get_priv(dev);
|
||||
struct clk clk;
|
||||
ulong clk_rate;
|
||||
int ret;
|
||||
|
||||
ret = clk_get_by_index(dev, 0, &clk);
|
||||
if (ret)
|
||||
return -EINVAL;
|
||||
|
||||
if (dev_get_driver_data(dev) == CLK_TYPE_NORMAL) {
|
||||
ret = clk_enable(&clk);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
clk_rate = clk_get_rate(&clk);
|
||||
if (!clk_rate)
|
||||
return -EINVAL;
|
||||
|
||||
priv->usart_clk_rate = clk_rate;
|
||||
|
||||
clk_free(&clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int atmel_serial_probe(struct udevice *dev)
|
||||
{
|
||||
struct atmel_serial_platdata *plat = dev->platdata;
|
||||
struct atmel_serial_priv *priv = dev_get_priv(dev);
|
||||
int ret;
|
||||
#if CONFIG_IS_ENABLED(OF_CONTROL)
|
||||
fdt_addr_t addr_base;
|
||||
|
||||
addr_base = devfdt_get_addr(dev);
|
||||
if (addr_base == FDT_ADDR_T_NONE)
|
||||
return -ENODEV;
|
||||
|
||||
plat->base_addr = (uint32_t)addr_base;
|
||||
#endif
|
||||
priv->usart = (atmel_usart3_t *)plat->base_addr;
|
||||
|
||||
ret = atmel_serial_enable_clk(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
_atmel_serial_init(priv->usart, priv->usart_clk_rate, gd->baudrate);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if CONFIG_IS_ENABLED(OF_CONTROL)
|
||||
static const struct udevice_id atmel_serial_ids[] = {
|
||||
{
|
||||
.compatible = "atmel,at91sam9260-dbgu",
|
||||
.data = CLK_TYPE_DBGU,
|
||||
},
|
||||
{
|
||||
.compatible = "atmel,at91sam9260-usart",
|
||||
.data = CLK_TYPE_NORMAL,
|
||||
},
|
||||
{ }
|
||||
};
|
||||
#endif
|
||||
|
||||
U_BOOT_DRIVER(serial_atmel) = {
|
||||
.name = "serial_atmel",
|
||||
.id = UCLASS_SERIAL,
|
||||
#if CONFIG_IS_ENABLED(OF_CONTROL)
|
||||
.of_match = atmel_serial_ids,
|
||||
.platdata_auto_alloc_size = sizeof(struct atmel_serial_platdata),
|
||||
#endif
|
||||
.probe = atmel_serial_probe,
|
||||
.ops = &atmel_serial_ops,
|
||||
#if !CONFIG_IS_ENABLED(OF_CONTROL)
|
||||
.flags = DM_FLAG_PRE_RELOC,
|
||||
#endif
|
||||
.priv_auto_alloc_size = sizeof(struct atmel_serial_priv),
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_DEBUG_UART_ATMEL
|
||||
static inline void _debug_uart_init(void)
|
||||
{
|
||||
atmel_usart3_t *usart = (atmel_usart3_t *)CONFIG_DEBUG_UART_BASE;
|
||||
|
||||
_atmel_serial_init(usart, CONFIG_DEBUG_UART_CLOCK, CONFIG_BAUDRATE);
|
||||
}
|
||||
|
||||
static inline void _debug_uart_putc(int ch)
|
||||
{
|
||||
atmel_usart3_t *usart = (atmel_usart3_t *)CONFIG_DEBUG_UART_BASE;
|
||||
|
||||
while (!(readl(&usart->csr) & USART3_BIT(TXRDY)))
|
||||
;
|
||||
|
||||
writel(ch, &usart->thr);
|
||||
}
|
||||
|
||||
DEBUG_UART_FUNCS
|
||||
#endif
|
||||
@@ -0,0 +1,293 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/*
|
||||
* Register definitions for the Atmel USART3 module.
|
||||
*
|
||||
* Copyright (C) 2005-2006 Atmel Corporation
|
||||
*
|
||||
* Modified to support C structure SoC access by
|
||||
* Andreas Bießmann <biessmann@corscience.de>
|
||||
*/
|
||||
#ifndef __DRIVERS_ATMEL_USART_H__
|
||||
#define __DRIVERS_ATMEL_USART_H__
|
||||
|
||||
/* USART3 register footprint */
|
||||
typedef struct atmel_usart3 {
|
||||
u32 cr;
|
||||
u32 mr;
|
||||
u32 ier;
|
||||
u32 idr;
|
||||
u32 imr;
|
||||
u32 csr;
|
||||
u32 rhr;
|
||||
u32 thr;
|
||||
u32 brgr;
|
||||
u32 rtor;
|
||||
u32 ttgr;
|
||||
u32 reserved0[5];
|
||||
u32 fidi;
|
||||
u32 ner;
|
||||
u32 reserved1;
|
||||
u32 ifr;
|
||||
u32 man;
|
||||
u32 reserved2[54]; /* version and PDC not needed */
|
||||
} atmel_usart3_t;
|
||||
|
||||
/* Bitfields in CR */
|
||||
#define USART3_RSTRX_OFFSET 2
|
||||
#define USART3_RSTRX_SIZE 1
|
||||
#define USART3_RSTTX_OFFSET 3
|
||||
#define USART3_RSTTX_SIZE 1
|
||||
#define USART3_RXEN_OFFSET 4
|
||||
#define USART3_RXEN_SIZE 1
|
||||
#define USART3_RXDIS_OFFSET 5
|
||||
#define USART3_RXDIS_SIZE 1
|
||||
#define USART3_TXEN_OFFSET 6
|
||||
#define USART3_TXEN_SIZE 1
|
||||
#define USART3_TXDIS_OFFSET 7
|
||||
#define USART3_TXDIS_SIZE 1
|
||||
#define USART3_RSTSTA_OFFSET 8
|
||||
#define USART3_RSTSTA_SIZE 1
|
||||
#define USART3_STTBRK_OFFSET 9
|
||||
#define USART3_STTBRK_SIZE 1
|
||||
#define USART3_STPBRK_OFFSET 10
|
||||
#define USART3_STPBRK_SIZE 1
|
||||
#define USART3_STTTO_OFFSET 11
|
||||
#define USART3_STTTO_SIZE 1
|
||||
#define USART3_SENDA_OFFSET 12
|
||||
#define USART3_SENDA_SIZE 1
|
||||
#define USART3_RSTIT_OFFSET 13
|
||||
#define USART3_RSTIT_SIZE 1
|
||||
#define USART3_RSTNACK_OFFSET 14
|
||||
#define USART3_RSTNACK_SIZE 1
|
||||
#define USART3_RETTO_OFFSET 15
|
||||
#define USART3_RETTO_SIZE 1
|
||||
#define USART3_DTREN_OFFSET 16
|
||||
#define USART3_DTREN_SIZE 1
|
||||
#define USART3_DTRDIS_OFFSET 17
|
||||
#define USART3_DTRDIS_SIZE 1
|
||||
#define USART3_RTSEN_OFFSET 18
|
||||
#define USART3_RTSEN_SIZE 1
|
||||
#define USART3_RTSDIS_OFFSET 19
|
||||
#define USART3_RTSDIS_SIZE 1
|
||||
#define USART3_COMM_TX_OFFSET 30
|
||||
#define USART3_COMM_TX_SIZE 1
|
||||
#define USART3_COMM_RX_OFFSET 31
|
||||
#define USART3_COMM_RX_SIZE 1
|
||||
|
||||
/* Bitfields in MR */
|
||||
#define USART3_USART_MODE_OFFSET 0
|
||||
#define USART3_USART_MODE_SIZE 4
|
||||
#define USART3_USCLKS_OFFSET 4
|
||||
#define USART3_USCLKS_SIZE 2
|
||||
#define USART3_CHRL_OFFSET 6
|
||||
#define USART3_CHRL_SIZE 2
|
||||
#define USART3_SYNC_OFFSET 8
|
||||
#define USART3_SYNC_SIZE 1
|
||||
#define USART3_PAR_OFFSET 9
|
||||
#define USART3_PAR_SIZE 3
|
||||
#define USART3_NBSTOP_OFFSET 12
|
||||
#define USART3_NBSTOP_SIZE 2
|
||||
#define USART3_CHMODE_OFFSET 14
|
||||
#define USART3_CHMODE_SIZE 2
|
||||
#define USART3_MSBF_OFFSET 16
|
||||
#define USART3_MSBF_SIZE 1
|
||||
#define USART3_MODE9_OFFSET 17
|
||||
#define USART3_MODE9_SIZE 1
|
||||
#define USART3_CLKO_OFFSET 18
|
||||
#define USART3_CLKO_SIZE 1
|
||||
#define USART3_OVER_OFFSET 19
|
||||
#define USART3_OVER_SIZE 1
|
||||
#define USART3_INACK_OFFSET 20
|
||||
#define USART3_INACK_SIZE 1
|
||||
#define USART3_DSNACK_OFFSET 21
|
||||
#define USART3_DSNACK_SIZE 1
|
||||
#define USART3_MAX_ITERATION_OFFSET 24
|
||||
#define USART3_MAX_ITERATION_SIZE 3
|
||||
#define USART3_FILTER_OFFSET 28
|
||||
#define USART3_FILTER_SIZE 1
|
||||
|
||||
/* Bitfields in CSR */
|
||||
#define USART3_RXRDY_OFFSET 0
|
||||
#define USART3_RXRDY_SIZE 1
|
||||
#define USART3_TXRDY_OFFSET 1
|
||||
#define USART3_TXRDY_SIZE 1
|
||||
#define USART3_RXBRK_OFFSET 2
|
||||
#define USART3_RXBRK_SIZE 1
|
||||
#define USART3_ENDRX_OFFSET 3
|
||||
#define USART3_ENDRX_SIZE 1
|
||||
#define USART3_ENDTX_OFFSET 4
|
||||
#define USART3_ENDTX_SIZE 1
|
||||
#define USART3_OVRE_OFFSET 5
|
||||
#define USART3_OVRE_SIZE 1
|
||||
#define USART3_FRAME_OFFSET 6
|
||||
#define USART3_FRAME_SIZE 1
|
||||
#define USART3_PARE_OFFSET 7
|
||||
#define USART3_PARE_SIZE 1
|
||||
#define USART3_TIMEOUT_OFFSET 8
|
||||
#define USART3_TIMEOUT_SIZE 1
|
||||
#define USART3_TXEMPTY_OFFSET 9
|
||||
#define USART3_TXEMPTY_SIZE 1
|
||||
#define USART3_ITERATION_OFFSET 10
|
||||
#define USART3_ITERATION_SIZE 1
|
||||
#define USART3_TXBUFE_OFFSET 11
|
||||
#define USART3_TXBUFE_SIZE 1
|
||||
#define USART3_RXBUFF_OFFSET 12
|
||||
#define USART3_RXBUFF_SIZE 1
|
||||
#define USART3_NACK_OFFSET 13
|
||||
#define USART3_NACK_SIZE 1
|
||||
#define USART3_RIIC_OFFSET 16
|
||||
#define USART3_RIIC_SIZE 1
|
||||
#define USART3_DSRIC_OFFSET 17
|
||||
#define USART3_DSRIC_SIZE 1
|
||||
#define USART3_DCDIC_OFFSET 18
|
||||
#define USART3_DCDIC_SIZE 1
|
||||
#define USART3_CTSIC_OFFSET 19
|
||||
#define USART3_CTSIC_SIZE 1
|
||||
#define USART3_RI_OFFSET 20
|
||||
#define USART3_RI_SIZE 1
|
||||
#define USART3_DSR_OFFSET 21
|
||||
#define USART3_DSR_SIZE 1
|
||||
#define USART3_DCD_OFFSET 22
|
||||
#define USART3_DCD_SIZE 1
|
||||
#define USART3_CTS_OFFSET 23
|
||||
#define USART3_CTS_SIZE 1
|
||||
|
||||
/* Bitfields in RHR */
|
||||
#define USART3_RXCHR_OFFSET 0
|
||||
#define USART3_RXCHR_SIZE 9
|
||||
|
||||
/* Bitfields in THR */
|
||||
#define USART3_TXCHR_OFFSET 0
|
||||
#define USART3_TXCHR_SIZE 9
|
||||
|
||||
/* Bitfields in BRGR */
|
||||
#define USART3_CD_OFFSET 0
|
||||
#define USART3_CD_SIZE 16
|
||||
|
||||
/* Bitfields in RTOR */
|
||||
#define USART3_TO_OFFSET 0
|
||||
#define USART3_TO_SIZE 16
|
||||
|
||||
/* Bitfields in TTGR */
|
||||
#define USART3_TG_OFFSET 0
|
||||
#define USART3_TG_SIZE 8
|
||||
|
||||
/* Bitfields in FIDI */
|
||||
#define USART3_FI_DI_RATIO_OFFSET 0
|
||||
#define USART3_FI_DI_RATIO_SIZE 11
|
||||
|
||||
/* Bitfields in NER */
|
||||
#define USART3_NB_ERRORS_OFFSET 0
|
||||
#define USART3_NB_ERRORS_SIZE 8
|
||||
|
||||
/* Bitfields in XXR */
|
||||
#define USART3_XOFF_OFFSET 0
|
||||
#define USART3_XOFF_SIZE 8
|
||||
#define USART3_XON_OFFSET 8
|
||||
#define USART3_XON_SIZE 8
|
||||
|
||||
/* Bitfields in IFR */
|
||||
#define USART3_IRDA_FILTER_OFFSET 0
|
||||
#define USART3_IRDA_FILTER_SIZE 8
|
||||
|
||||
/* Bitfields in RCR */
|
||||
#define USART3_RXCTR_OFFSET 0
|
||||
#define USART3_RXCTR_SIZE 16
|
||||
|
||||
/* Bitfields in TCR */
|
||||
#define USART3_TXCTR_OFFSET 0
|
||||
#define USART3_TXCTR_SIZE 16
|
||||
|
||||
/* Bitfields in RNCR */
|
||||
#define USART3_RXNCR_OFFSET 0
|
||||
#define USART3_RXNCR_SIZE 16
|
||||
|
||||
/* Bitfields in TNCR */
|
||||
#define USART3_TXNCR_OFFSET 0
|
||||
#define USART3_TXNCR_SIZE 16
|
||||
|
||||
/* Bitfields in PTCR */
|
||||
#define USART3_RXTEN_OFFSET 0
|
||||
#define USART3_RXTEN_SIZE 1
|
||||
#define USART3_RXTDIS_OFFSET 1
|
||||
#define USART3_RXTDIS_SIZE 1
|
||||
#define USART3_TXTEN_OFFSET 8
|
||||
#define USART3_TXTEN_SIZE 1
|
||||
#define USART3_TXTDIS_OFFSET 9
|
||||
#define USART3_TXTDIS_SIZE 1
|
||||
|
||||
/* Constants for USART_MODE */
|
||||
#define USART3_USART_MODE_NORMAL 0
|
||||
#define USART3_USART_MODE_RS485 1
|
||||
#define USART3_USART_MODE_HARDWARE 2
|
||||
#define USART3_USART_MODE_MODEM 3
|
||||
#define USART3_USART_MODE_ISO7816_T0 4
|
||||
#define USART3_USART_MODE_ISO7816_T1 6
|
||||
#define USART3_USART_MODE_IRDA 8
|
||||
|
||||
/* Constants for USCLKS */
|
||||
#define USART3_USCLKS_MCK 0
|
||||
#define USART3_USCLKS_MCK_DIV 1
|
||||
#define USART3_USCLKS_SCK 3
|
||||
|
||||
/* Constants for CHRL */
|
||||
#define USART3_CHRL_5 0
|
||||
#define USART3_CHRL_6 1
|
||||
#define USART3_CHRL_7 2
|
||||
#define USART3_CHRL_8 3
|
||||
|
||||
/* Constants for PAR */
|
||||
#define USART3_PAR_EVEN 0
|
||||
#define USART3_PAR_ODD 1
|
||||
#define USART3_PAR_SPACE 2
|
||||
#define USART3_PAR_MARK 3
|
||||
#define USART3_PAR_NONE 4
|
||||
#define USART3_PAR_MULTI 6
|
||||
|
||||
/* Constants for NBSTOP */
|
||||
#define USART3_NBSTOP_1 0
|
||||
#define USART3_NBSTOP_1_5 1
|
||||
#define USART3_NBSTOP_2 2
|
||||
|
||||
/* Constants for CHMODE */
|
||||
#define USART3_CHMODE_NORMAL 0
|
||||
#define USART3_CHMODE_ECHO 1
|
||||
#define USART3_CHMODE_LOCAL_LOOP 2
|
||||
#define USART3_CHMODE_REMOTE_LOOP 3
|
||||
|
||||
/* Constants for MSBF */
|
||||
#define USART3_MSBF_LSBF 0
|
||||
#define USART3_MSBF_MSBF 1
|
||||
|
||||
/* Constants for OVER */
|
||||
#define USART3_OVER_X16 0
|
||||
#define USART3_OVER_X8 1
|
||||
|
||||
/* Constants for CD */
|
||||
#define USART3_CD_DISABLE 0
|
||||
#define USART3_CD_BYPASS 1
|
||||
|
||||
/* Constants for TO */
|
||||
#define USART3_TO_DISABLE 0
|
||||
|
||||
/* Constants for TG */
|
||||
#define USART3_TG_DISABLE 0
|
||||
|
||||
/* Constants for FI_DI_RATIO */
|
||||
#define USART3_FI_DI_RATIO_DISABLE 0
|
||||
|
||||
/* Bit manipulation macros */
|
||||
#define USART3_BIT(name) \
|
||||
(1 << USART3_##name##_OFFSET)
|
||||
#define USART3_BF(name,value) \
|
||||
(((value) & ((1 << USART3_##name##_SIZE) - 1)) \
|
||||
<< USART3_##name##_OFFSET)
|
||||
#define USART3_BFEXT(name,value) \
|
||||
(((value) >> USART3_##name##_OFFSET) \
|
||||
& ((1 << USART3_##name##_SIZE) - 1))
|
||||
#define USART3_BFINS(name,value,old) \
|
||||
(((old) & ~(((1 << USART3_##name##_SIZE) - 1) \
|
||||
<< USART3_##name##_OFFSET)) \
|
||||
| USART3_BF(name,value))
|
||||
|
||||
#endif /* __DRIVERS_ATMEL_USART_H__ */
|
||||
@@ -0,0 +1,111 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright (C) 2011-2015 Vladimir Zapolskiy <vz@mleia.com>
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <dm.h>
|
||||
#include <serial.h>
|
||||
#include <dm/platform_data/lpc32xx_hsuart.h>
|
||||
|
||||
#include <asm/arch/uart.h>
|
||||
#include <linux/compiler.h>
|
||||
|
||||
struct lpc32xx_hsuart_priv {
|
||||
struct hsuart_regs *hsuart;
|
||||
};
|
||||
|
||||
static int lpc32xx_serial_setbrg(struct udevice *dev, int baudrate)
|
||||
{
|
||||
struct lpc32xx_hsuart_priv *priv = dev_get_priv(dev);
|
||||
struct hsuart_regs *hsuart = priv->hsuart;
|
||||
u32 div;
|
||||
|
||||
/* UART rate = PERIPH_CLK / ((HSU_RATE + 1) x 14) */
|
||||
div = (get_serial_clock() / 14 + baudrate / 2) / baudrate - 1;
|
||||
if (div > 255)
|
||||
div = 255;
|
||||
|
||||
writel(div, &hsuart->rate);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lpc32xx_serial_getc(struct udevice *dev)
|
||||
{
|
||||
struct lpc32xx_hsuart_priv *priv = dev_get_priv(dev);
|
||||
struct hsuart_regs *hsuart = priv->hsuart;
|
||||
|
||||
if (!(readl(&hsuart->level) & HSUART_LEVEL_RX))
|
||||
return -EAGAIN;
|
||||
|
||||
return readl(&hsuart->rx) & HSUART_RX_DATA;
|
||||
}
|
||||
|
||||
static int lpc32xx_serial_putc(struct udevice *dev, const char c)
|
||||
{
|
||||
struct lpc32xx_hsuart_priv *priv = dev_get_priv(dev);
|
||||
struct hsuart_regs *hsuart = priv->hsuart;
|
||||
|
||||
/* Wait for empty FIFO */
|
||||
if (readl(&hsuart->level) & HSUART_LEVEL_TX)
|
||||
return -EAGAIN;
|
||||
|
||||
writel(c, &hsuart->tx);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lpc32xx_serial_pending(struct udevice *dev, bool input)
|
||||
{
|
||||
struct lpc32xx_hsuart_priv *priv = dev_get_priv(dev);
|
||||
struct hsuart_regs *hsuart = priv->hsuart;
|
||||
|
||||
if (input) {
|
||||
if (readl(&hsuart->level) & HSUART_LEVEL_RX)
|
||||
return 1;
|
||||
} else {
|
||||
if (readl(&hsuart->level) & HSUART_LEVEL_TX)
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lpc32xx_serial_init(struct hsuart_regs *hsuart)
|
||||
{
|
||||
/* Disable hardware RTS and CTS flow control, set up RX and TX FIFO */
|
||||
writel(HSUART_CTRL_TMO_16 | HSUART_CTRL_HSU_OFFSET(20) |
|
||||
HSUART_CTRL_HSU_RX_TRIG_32 | HSUART_CTRL_HSU_TX_TRIG_0,
|
||||
&hsuart->ctrl);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lpc32xx_hsuart_probe(struct udevice *dev)
|
||||
{
|
||||
struct lpc32xx_hsuart_platdata *platdata = dev_get_platdata(dev);
|
||||
struct lpc32xx_hsuart_priv *priv = dev_get_priv(dev);
|
||||
|
||||
priv->hsuart = (struct hsuart_regs *)platdata->base;
|
||||
|
||||
lpc32xx_serial_init(priv->hsuart);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dm_serial_ops lpc32xx_hsuart_ops = {
|
||||
.setbrg = lpc32xx_serial_setbrg,
|
||||
.getc = lpc32xx_serial_getc,
|
||||
.putc = lpc32xx_serial_putc,
|
||||
.pending = lpc32xx_serial_pending,
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(lpc32xx_hsuart) = {
|
||||
.name = "lpc32xx_hsuart",
|
||||
.id = UCLASS_SERIAL,
|
||||
.probe = lpc32xx_hsuart_probe,
|
||||
.ops = &lpc32xx_hsuart_ops,
|
||||
.priv_auto_alloc_size = sizeof(struct lpc32xx_hsuart_priv),
|
||||
.flags = DM_FLAG_PRE_RELOC,
|
||||
};
|
||||
@@ -0,0 +1,179 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* (C) Copyright 2004-2007 Freescale Semiconductor, Inc.
|
||||
* TsiChung Liew, Tsi-Chung.Liew@freescale.com.
|
||||
*
|
||||
* Modified to add device model (DM) support
|
||||
* (C) Copyright 2015 Angelo Dureghello <angelo@sysam.it>
|
||||
*
|
||||
* Modified to add DM and fdt support, removed non DM code
|
||||
* (C) Copyright 2018 Angelo Dureghello <angelo@sysam.it>
|
||||
*/
|
||||
|
||||
/*
|
||||
* Minimal serial functions needed to use one of the uart ports
|
||||
* as serial console interface.
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <dm.h>
|
||||
#include <dm/platform_data/serial_coldfire.h>
|
||||
#include <serial.h>
|
||||
#include <linux/compiler.h>
|
||||
#include <asm/immap.h>
|
||||
#include <asm/uart.h>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
extern void uart_port_conf(int port);
|
||||
|
||||
static int mcf_serial_init_common(uart_t *uart, int port_idx, int baudrate)
|
||||
{
|
||||
u32 counter;
|
||||
|
||||
uart_port_conf(port_idx);
|
||||
|
||||
/* write to SICR: SIM2 = uart mode,dcd does not affect rx */
|
||||
writeb(UART_UCR_RESET_RX, &uart->ucr);
|
||||
writeb(UART_UCR_RESET_TX, &uart->ucr);
|
||||
writeb(UART_UCR_RESET_ERROR, &uart->ucr);
|
||||
writeb(UART_UCR_RESET_MR, &uart->ucr);
|
||||
__asm__("nop");
|
||||
|
||||
writeb(0, &uart->uimr);
|
||||
|
||||
/* write to CSR: RX/TX baud rate from timers */
|
||||
writeb(UART_UCSR_RCS_SYS_CLK | UART_UCSR_TCS_SYS_CLK, &uart->ucsr);
|
||||
|
||||
writeb(UART_UMR_BC_8 | UART_UMR_PM_NONE, &uart->umr);
|
||||
writeb(UART_UMR_SB_STOP_BITS_1, &uart->umr);
|
||||
|
||||
/* Setting up BaudRate */
|
||||
counter = (u32) ((gd->bus_clk / 32) + (baudrate / 2));
|
||||
counter = counter / baudrate;
|
||||
|
||||
/* write to CTUR: divide counter upper byte */
|
||||
writeb((u8)((counter & 0xff00) >> 8), &uart->ubg1);
|
||||
/* write to CTLR: divide counter lower byte */
|
||||
writeb((u8)(counter & 0x00ff), &uart->ubg2);
|
||||
|
||||
writeb(UART_UCR_RX_ENABLED | UART_UCR_TX_ENABLED, &uart->ucr);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void mcf_serial_setbrg_common(uart_t *uart, int baudrate)
|
||||
{
|
||||
u32 counter;
|
||||
|
||||
/* Setting up BaudRate */
|
||||
counter = (u32) ((gd->bus_clk / 32) + (baudrate / 2));
|
||||
counter = counter / baudrate;
|
||||
|
||||
/* write to CTUR: divide counter upper byte */
|
||||
writeb(((counter & 0xff00) >> 8), &uart->ubg1);
|
||||
/* write to CTLR: divide counter lower byte */
|
||||
writeb((counter & 0x00ff), &uart->ubg2);
|
||||
|
||||
writeb(UART_UCR_RESET_RX, &uart->ucr);
|
||||
writeb(UART_UCR_RESET_TX, &uart->ucr);
|
||||
|
||||
writeb(UART_UCR_RX_ENABLED | UART_UCR_TX_ENABLED, &uart->ucr);
|
||||
}
|
||||
|
||||
static int coldfire_serial_probe(struct udevice *dev)
|
||||
{
|
||||
struct coldfire_serial_platdata *plat = dev->platdata;
|
||||
|
||||
return mcf_serial_init_common((uart_t *)plat->base,
|
||||
plat->port, plat->baudrate);
|
||||
}
|
||||
|
||||
static int coldfire_serial_putc(struct udevice *dev, const char ch)
|
||||
{
|
||||
struct coldfire_serial_platdata *plat = dev->platdata;
|
||||
uart_t *uart = (uart_t *)plat->base;
|
||||
|
||||
/* Wait for last character to go. */
|
||||
if (!(readb(&uart->usr) & UART_USR_TXRDY))
|
||||
return -EAGAIN;
|
||||
|
||||
writeb(ch, &uart->utb);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int coldfire_serial_getc(struct udevice *dev)
|
||||
{
|
||||
struct coldfire_serial_platdata *plat = dev->platdata;
|
||||
uart_t *uart = (uart_t *)(plat->base);
|
||||
|
||||
/* Wait for a character to arrive. */
|
||||
if (!(readb(&uart->usr) & UART_USR_RXRDY))
|
||||
return -EAGAIN;
|
||||
|
||||
return readb(&uart->urb);
|
||||
}
|
||||
|
||||
int coldfire_serial_setbrg(struct udevice *dev, int baudrate)
|
||||
{
|
||||
struct coldfire_serial_platdata *plat = dev->platdata;
|
||||
uart_t *uart = (uart_t *)(plat->base);
|
||||
|
||||
mcf_serial_setbrg_common(uart, baudrate);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int coldfire_serial_pending(struct udevice *dev, bool input)
|
||||
{
|
||||
struct coldfire_serial_platdata *plat = dev->platdata;
|
||||
uart_t *uart = (uart_t *)(plat->base);
|
||||
|
||||
if (input)
|
||||
return readb(&uart->usr) & UART_USR_RXRDY ? 1 : 0;
|
||||
else
|
||||
return readb(&uart->usr) & UART_USR_TXRDY ? 0 : 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int coldfire_ofdata_to_platdata(struct udevice *dev)
|
||||
{
|
||||
struct coldfire_serial_platdata *plat = dev_get_platdata(dev);
|
||||
fdt_addr_t addr_base;
|
||||
|
||||
addr_base = devfdt_get_addr(dev);
|
||||
if (addr_base == FDT_ADDR_T_NONE)
|
||||
return -ENODEV;
|
||||
|
||||
plat->base = (uint32_t)addr_base;
|
||||
|
||||
plat->port = dev->seq;
|
||||
plat->baudrate = gd->baudrate;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dm_serial_ops coldfire_serial_ops = {
|
||||
.putc = coldfire_serial_putc,
|
||||
.pending = coldfire_serial_pending,
|
||||
.getc = coldfire_serial_getc,
|
||||
.setbrg = coldfire_serial_setbrg,
|
||||
};
|
||||
|
||||
static const struct udevice_id coldfire_serial_ids[] = {
|
||||
{ .compatible = "fsl,mcf-uart" },
|
||||
{ }
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(serial_coldfire) = {
|
||||
.name = "serial_coldfire",
|
||||
.id = UCLASS_SERIAL,
|
||||
.of_match = coldfire_serial_ids,
|
||||
.ofdata_to_platdata = coldfire_ofdata_to_platdata,
|
||||
.platdata_auto_alloc_size = sizeof(struct coldfire_serial_platdata),
|
||||
.probe = coldfire_serial_probe,
|
||||
.ops = &coldfire_serial_ops,
|
||||
.flags = DM_FLAG_PRE_RELOC,
|
||||
};
|
||||
@@ -0,0 +1,530 @@
|
||||
/*
|
||||
* COM1 NS16550 support
|
||||
* originally from linux source (arch/powerpc/boot/ns16550.c)
|
||||
* modified to use CONFIG_SYS_ISA_MEM and new defines
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <clk.h>
|
||||
#include <dm.h>
|
||||
#include <errno.h>
|
||||
#include <ns16550.h>
|
||||
#include <reset.h>
|
||||
#include <serial.h>
|
||||
#include <watchdog.h>
|
||||
#include <linux/types.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
#define UART_LCRVAL UART_LCR_8N1 /* 8 data, 1 stop, no parity */
|
||||
#define UART_MCRVAL (UART_MCR_DTR | \
|
||||
UART_MCR_RTS) /* RTS/DTR */
|
||||
|
||||
#if !CONFIG_IS_ENABLED(DM_SERIAL)
|
||||
#ifdef CONFIG_SYS_NS16550_PORT_MAPPED
|
||||
#define serial_out(x, y) outb(x, (ulong)y)
|
||||
#define serial_in(y) inb((ulong)y)
|
||||
#elif defined(CONFIG_SYS_NS16550_MEM32) && (CONFIG_SYS_NS16550_REG_SIZE > 0)
|
||||
#define serial_out(x, y) out_be32(y, x)
|
||||
#define serial_in(y) in_be32(y)
|
||||
#elif defined(CONFIG_SYS_NS16550_MEM32) && (CONFIG_SYS_NS16550_REG_SIZE < 0)
|
||||
#define serial_out(x, y) out_le32(y, x)
|
||||
#define serial_in(y) in_le32(y)
|
||||
#else
|
||||
#define serial_out(x, y) writeb(x, y)
|
||||
#define serial_in(y) readb(y)
|
||||
#endif
|
||||
#endif /* !CONFIG_DM_SERIAL */
|
||||
|
||||
#if defined(CONFIG_SOC_KEYSTONE)
|
||||
#define UART_REG_VAL_PWREMU_MGMT_UART_DISABLE 0
|
||||
#define UART_REG_VAL_PWREMU_MGMT_UART_ENABLE ((1 << 14) | (1 << 13) | (1 << 0))
|
||||
#undef UART_MCRVAL
|
||||
#ifdef CONFIG_SERIAL_HW_FLOW_CONTROL
|
||||
#define UART_MCRVAL (UART_MCR_RTS | UART_MCR_AFE)
|
||||
#else
|
||||
#define UART_MCRVAL (UART_MCR_RTS)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_SYS_NS16550_IER
|
||||
#define CONFIG_SYS_NS16550_IER 0x00
|
||||
#endif /* CONFIG_SYS_NS16550_IER */
|
||||
|
||||
static inline void serial_out_shift(void *addr, int shift, int value)
|
||||
{
|
||||
#ifdef CONFIG_SYS_NS16550_PORT_MAPPED
|
||||
outb(value, (ulong)addr);
|
||||
#elif defined(CONFIG_SYS_NS16550_MEM32) && defined(CONFIG_SYS_LITTLE_ENDIAN)
|
||||
out_le32(addr, value);
|
||||
#elif defined(CONFIG_SYS_NS16550_MEM32) && defined(CONFIG_SYS_BIG_ENDIAN)
|
||||
out_be32(addr, value);
|
||||
#elif defined(CONFIG_SYS_NS16550_MEM32)
|
||||
writel(value, addr);
|
||||
#elif defined(CONFIG_SYS_BIG_ENDIAN)
|
||||
writeb(value, addr + (1 << shift) - 1);
|
||||
#else
|
||||
writeb(value, addr);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline int serial_in_shift(void *addr, int shift)
|
||||
{
|
||||
#ifdef CONFIG_SYS_NS16550_PORT_MAPPED
|
||||
return inb((ulong)addr);
|
||||
#elif defined(CONFIG_SYS_NS16550_MEM32) && defined(CONFIG_SYS_LITTLE_ENDIAN)
|
||||
return in_le32(addr);
|
||||
#elif defined(CONFIG_SYS_NS16550_MEM32) && defined(CONFIG_SYS_BIG_ENDIAN)
|
||||
return in_be32(addr);
|
||||
#elif defined(CONFIG_SYS_NS16550_MEM32)
|
||||
return readl(addr);
|
||||
#elif defined(CONFIG_SYS_BIG_ENDIAN)
|
||||
return readb(addr + (1 << shift) - 1);
|
||||
#else
|
||||
return readb(addr);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if CONFIG_IS_ENABLED(DM_SERIAL)
|
||||
|
||||
#ifndef CONFIG_SYS_NS16550_CLK
|
||||
#define CONFIG_SYS_NS16550_CLK 0
|
||||
#endif
|
||||
|
||||
static void ns16550_writeb(NS16550_t port, int offset, int value)
|
||||
{
|
||||
struct ns16550_platdata *plat = port->plat;
|
||||
unsigned char *addr;
|
||||
|
||||
offset *= 1 << plat->reg_shift;
|
||||
addr = (unsigned char *)plat->base + offset;
|
||||
|
||||
/*
|
||||
* As far as we know it doesn't make sense to support selection of
|
||||
* these options at run-time, so use the existing CONFIG options.
|
||||
*/
|
||||
serial_out_shift(addr + plat->reg_offset, plat->reg_shift, value);
|
||||
}
|
||||
|
||||
static int ns16550_readb(NS16550_t port, int offset)
|
||||
{
|
||||
struct ns16550_platdata *plat = port->plat;
|
||||
unsigned char *addr;
|
||||
|
||||
offset *= 1 << plat->reg_shift;
|
||||
addr = (unsigned char *)plat->base + offset;
|
||||
|
||||
return serial_in_shift(addr + plat->reg_offset, plat->reg_shift);
|
||||
}
|
||||
|
||||
static u32 ns16550_getfcr(NS16550_t port)
|
||||
{
|
||||
struct ns16550_platdata *plat = port->plat;
|
||||
|
||||
return plat->fcr;
|
||||
}
|
||||
|
||||
/* We can clean these up once everything is moved to driver model */
|
||||
#define serial_out(value, addr) \
|
||||
ns16550_writeb(com_port, \
|
||||
(unsigned char *)addr - (unsigned char *)com_port, value)
|
||||
#define serial_in(addr) \
|
||||
ns16550_readb(com_port, \
|
||||
(unsigned char *)addr - (unsigned char *)com_port)
|
||||
#else
|
||||
static u32 ns16550_getfcr(NS16550_t port)
|
||||
{
|
||||
return UART_FCR_DEFVAL;
|
||||
}
|
||||
#endif
|
||||
|
||||
int ns16550_calc_divisor(NS16550_t port, int clock, int baudrate)
|
||||
{
|
||||
const unsigned int mode_x_div = 16;
|
||||
|
||||
return DIV_ROUND_CLOSEST(clock, mode_x_div * baudrate);
|
||||
}
|
||||
|
||||
static void NS16550_setbrg(NS16550_t com_port, int baud_divisor)
|
||||
{
|
||||
/* to keep serial format, read lcr before writing BKSE */
|
||||
int lcr_val = serial_in(&com_port->lcr) & ~UART_LCR_BKSE;
|
||||
|
||||
serial_out(UART_LCR_BKSE | lcr_val, &com_port->lcr);
|
||||
serial_out(baud_divisor & 0xff, &com_port->dll);
|
||||
serial_out((baud_divisor >> 8) & 0xff, &com_port->dlm);
|
||||
serial_out(lcr_val, &com_port->lcr);
|
||||
}
|
||||
|
||||
void NS16550_init(NS16550_t com_port, int baud_divisor)
|
||||
{
|
||||
#if (defined(CONFIG_SPL_BUILD) && \
|
||||
(defined(CONFIG_OMAP34XX) || defined(CONFIG_OMAP44XX)))
|
||||
/*
|
||||
* On some OMAP3/OMAP4 devices when UART3 is configured for boot mode
|
||||
* before SPL starts only THRE bit is set. We have to empty the
|
||||
* transmitter before initialization starts.
|
||||
*/
|
||||
if ((serial_in(&com_port->lsr) & (UART_LSR_TEMT | UART_LSR_THRE))
|
||||
== UART_LSR_THRE) {
|
||||
if (baud_divisor != -1)
|
||||
NS16550_setbrg(com_port, baud_divisor);
|
||||
serial_out(0, &com_port->mdr1);
|
||||
}
|
||||
#endif
|
||||
|
||||
while (!(serial_in(&com_port->lsr) & UART_LSR_TEMT))
|
||||
;
|
||||
|
||||
serial_out(CONFIG_SYS_NS16550_IER, &com_port->ier);
|
||||
#if defined(CONFIG_ARCH_OMAP2PLUS) || defined(CONFIG_OMAP_SERIAL)
|
||||
serial_out(0x7, &com_port->mdr1); /* mode select reset TL16C750*/
|
||||
#endif
|
||||
|
||||
serial_out(UART_MCRVAL, &com_port->mcr);
|
||||
serial_out(ns16550_getfcr(com_port), &com_port->fcr);
|
||||
/* initialize serial config to 8N1 before writing baudrate */
|
||||
serial_out(UART_LCRVAL, &com_port->lcr);
|
||||
if (baud_divisor != -1)
|
||||
NS16550_setbrg(com_port, baud_divisor);
|
||||
#if defined(CONFIG_ARCH_OMAP2PLUS) || defined(CONFIG_SOC_DA8XX) || \
|
||||
defined(CONFIG_OMAP_SERIAL)
|
||||
/* /16 is proper to hit 115200 with 48MHz */
|
||||
serial_out(0, &com_port->mdr1);
|
||||
#endif
|
||||
#if defined(CONFIG_SOC_KEYSTONE)
|
||||
serial_out(UART_REG_VAL_PWREMU_MGMT_UART_ENABLE, &com_port->regC);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef CONFIG_NS16550_MIN_FUNCTIONS
|
||||
void NS16550_reinit(NS16550_t com_port, int baud_divisor)
|
||||
{
|
||||
serial_out(CONFIG_SYS_NS16550_IER, &com_port->ier);
|
||||
NS16550_setbrg(com_port, 0);
|
||||
serial_out(UART_MCRVAL, &com_port->mcr);
|
||||
serial_out(ns16550_getfcr(com_port), &com_port->fcr);
|
||||
NS16550_setbrg(com_port, baud_divisor);
|
||||
}
|
||||
#endif /* CONFIG_NS16550_MIN_FUNCTIONS */
|
||||
|
||||
void NS16550_putc(NS16550_t com_port, char c)
|
||||
{
|
||||
while ((serial_in(&com_port->lsr) & UART_LSR_THRE) == 0)
|
||||
;
|
||||
serial_out(c, &com_port->thr);
|
||||
|
||||
/*
|
||||
* Call watchdog_reset() upon newline. This is done here in putc
|
||||
* since the environment code uses a single puts() to print the complete
|
||||
* environment upon "printenv". So we can't put this watchdog call
|
||||
* in puts().
|
||||
*/
|
||||
if (c == '\n')
|
||||
WATCHDOG_RESET();
|
||||
}
|
||||
|
||||
#ifndef CONFIG_NS16550_MIN_FUNCTIONS
|
||||
char NS16550_getc(NS16550_t com_port)
|
||||
{
|
||||
while ((serial_in(&com_port->lsr) & UART_LSR_DR) == 0) {
|
||||
#if !defined(CONFIG_SPL_BUILD) && defined(CONFIG_USB_TTY)
|
||||
extern void usbtty_poll(void);
|
||||
usbtty_poll();
|
||||
#endif
|
||||
WATCHDOG_RESET();
|
||||
}
|
||||
return serial_in(&com_port->rbr);
|
||||
}
|
||||
|
||||
int NS16550_tstc(NS16550_t com_port)
|
||||
{
|
||||
return (serial_in(&com_port->lsr) & UART_LSR_DR) != 0;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_NS16550_MIN_FUNCTIONS */
|
||||
|
||||
#ifdef CONFIG_DEBUG_UART_NS16550
|
||||
|
||||
#include <debug_uart.h>
|
||||
|
||||
static inline void _debug_uart_init(void)
|
||||
{
|
||||
struct NS16550 *com_port = (struct NS16550 *)CONFIG_DEBUG_UART_BASE;
|
||||
int baud_divisor;
|
||||
|
||||
/*
|
||||
* We copy the code from above because it is already horribly messy.
|
||||
* Trying to refactor to nicely remove the duplication doesn't seem
|
||||
* feasible. The better fix is to move all users of this driver to
|
||||
* driver model.
|
||||
*/
|
||||
baud_divisor = ns16550_calc_divisor(com_port, CONFIG_DEBUG_UART_CLOCK,
|
||||
CONFIG_BAUDRATE);
|
||||
serial_dout(&com_port->ier, CONFIG_SYS_NS16550_IER);
|
||||
serial_dout(&com_port->mcr, UART_MCRVAL);
|
||||
serial_dout(&com_port->fcr, UART_FCR_DEFVAL);
|
||||
|
||||
serial_dout(&com_port->lcr, UART_LCR_BKSE | UART_LCRVAL);
|
||||
serial_dout(&com_port->dll, baud_divisor & 0xff);
|
||||
serial_dout(&com_port->dlm, (baud_divisor >> 8) & 0xff);
|
||||
serial_dout(&com_port->lcr, UART_LCRVAL);
|
||||
}
|
||||
|
||||
static inline int NS16550_read_baud_divisor(struct NS16550 *com_port)
|
||||
{
|
||||
int ret;
|
||||
|
||||
serial_dout(&com_port->lcr, UART_LCR_BKSE | UART_LCRVAL);
|
||||
ret = serial_din(&com_port->dll) & 0xff;
|
||||
ret |= (serial_din(&com_port->dlm) & 0xff) << 8;
|
||||
serial_dout(&com_port->lcr, UART_LCRVAL);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline void _debug_uart_putc(int ch)
|
||||
{
|
||||
struct NS16550 *com_port = (struct NS16550 *)CONFIG_DEBUG_UART_BASE;
|
||||
|
||||
while (!(serial_din(&com_port->lsr) & UART_LSR_THRE)) {
|
||||
#ifdef CONFIG_DEBUG_UART_NS16550_CHECK_ENABLED
|
||||
if (!NS16550_read_baud_divisor(com_port))
|
||||
return;
|
||||
#endif
|
||||
}
|
||||
serial_dout(&com_port->thr, ch);
|
||||
}
|
||||
|
||||
DEBUG_UART_FUNCS
|
||||
|
||||
#endif
|
||||
|
||||
#if CONFIG_IS_ENABLED(DM_SERIAL)
|
||||
static int ns16550_serial_putc(struct udevice *dev, const char ch)
|
||||
{
|
||||
struct NS16550 *const com_port = dev_get_priv(dev);
|
||||
|
||||
if (!(serial_in(&com_port->lsr) & UART_LSR_THRE))
|
||||
return -EAGAIN;
|
||||
serial_out(ch, &com_port->thr);
|
||||
|
||||
/*
|
||||
* Call watchdog_reset() upon newline. This is done here in putc
|
||||
* since the environment code uses a single puts() to print the complete
|
||||
* environment upon "printenv". So we can't put this watchdog call
|
||||
* in puts().
|
||||
*/
|
||||
if (ch == '\n')
|
||||
WATCHDOG_RESET();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ns16550_serial_pending(struct udevice *dev, bool input)
|
||||
{
|
||||
struct NS16550 *const com_port = dev_get_priv(dev);
|
||||
|
||||
if (input)
|
||||
return (serial_in(&com_port->lsr) & UART_LSR_DR) ? 1 : 0;
|
||||
else
|
||||
return (serial_in(&com_port->lsr) & UART_LSR_THRE) ? 0 : 1;
|
||||
}
|
||||
|
||||
static int ns16550_serial_getc(struct udevice *dev)
|
||||
{
|
||||
struct NS16550 *const com_port = dev_get_priv(dev);
|
||||
|
||||
if (!(serial_in(&com_port->lsr) & UART_LSR_DR))
|
||||
return -EAGAIN;
|
||||
|
||||
return serial_in(&com_port->rbr);
|
||||
}
|
||||
|
||||
static int ns16550_serial_setbrg(struct udevice *dev, int baudrate)
|
||||
{
|
||||
struct NS16550 *const com_port = dev_get_priv(dev);
|
||||
struct ns16550_platdata *plat = com_port->plat;
|
||||
int clock_divisor;
|
||||
|
||||
clock_divisor = ns16550_calc_divisor(com_port, plat->clock, baudrate);
|
||||
|
||||
NS16550_setbrg(com_port, clock_divisor);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ns16550_serial_setconfig(struct udevice *dev, uint serial_config)
|
||||
{
|
||||
struct NS16550 *const com_port = dev_get_priv(dev);
|
||||
int lcr_val = UART_LCR_WLS_8;
|
||||
uint parity = SERIAL_GET_PARITY(serial_config);
|
||||
uint bits = SERIAL_GET_BITS(serial_config);
|
||||
uint stop = SERIAL_GET_STOP(serial_config);
|
||||
|
||||
/*
|
||||
* only parity config is implemented, check if other serial settings
|
||||
* are the default one.
|
||||
*/
|
||||
if (bits != SERIAL_8_BITS || stop != SERIAL_ONE_STOP)
|
||||
return -ENOTSUPP; /* not supported in driver*/
|
||||
|
||||
switch (parity) {
|
||||
case SERIAL_PAR_NONE:
|
||||
/* no bits to add */
|
||||
break;
|
||||
case SERIAL_PAR_ODD:
|
||||
lcr_val |= UART_LCR_PEN;
|
||||
break;
|
||||
case SERIAL_PAR_EVEN:
|
||||
lcr_val |= UART_LCR_PEN | UART_LCR_EPS;
|
||||
break;
|
||||
default:
|
||||
return -ENOTSUPP; /* not supported in driver*/
|
||||
}
|
||||
|
||||
serial_out(lcr_val, &com_port->lcr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ns16550_serial_getinfo(struct udevice *dev,
|
||||
struct serial_device_info *info)
|
||||
{
|
||||
struct NS16550 *const com_port = dev_get_priv(dev);
|
||||
struct ns16550_platdata *plat = com_port->plat;
|
||||
|
||||
info->type = SERIAL_CHIP_16550_COMPATIBLE;
|
||||
#ifdef CONFIG_SYS_NS16550_PORT_MAPPED
|
||||
info->addr_space = SERIAL_ADDRESS_SPACE_IO;
|
||||
#else
|
||||
info->addr_space = SERIAL_ADDRESS_SPACE_MEMORY;
|
||||
#endif
|
||||
info->addr = plat->base;
|
||||
info->reg_width = plat->reg_width;
|
||||
info->reg_shift = plat->reg_shift;
|
||||
info->reg_offset = plat->reg_offset;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ns16550_serial_probe(struct udevice *dev)
|
||||
{
|
||||
struct NS16550 *const com_port = dev_get_priv(dev);
|
||||
struct reset_ctl_bulk reset_bulk;
|
||||
int ret;
|
||||
|
||||
ret = reset_get_bulk(dev, &reset_bulk);
|
||||
if (!ret)
|
||||
reset_deassert_bulk(&reset_bulk);
|
||||
|
||||
com_port->plat = dev_get_platdata(dev);
|
||||
NS16550_init(com_port, -1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if CONFIG_IS_ENABLED(OF_CONTROL)
|
||||
enum {
|
||||
PORT_NS16550 = 0,
|
||||
PORT_JZ4780,
|
||||
};
|
||||
#endif
|
||||
|
||||
#if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)
|
||||
int ns16550_serial_ofdata_to_platdata(struct udevice *dev)
|
||||
{
|
||||
struct ns16550_platdata *plat = dev->platdata;
|
||||
const u32 port_type = dev_get_driver_data(dev);
|
||||
fdt_addr_t addr;
|
||||
struct clk clk;
|
||||
int err;
|
||||
|
||||
/* try Processor Local Bus device first */
|
||||
addr = dev_read_addr_pci(dev);
|
||||
if (addr == FDT_ADDR_T_NONE)
|
||||
return -EINVAL;
|
||||
|
||||
#ifdef CONFIG_SYS_NS16550_PORT_MAPPED
|
||||
plat->base = addr;
|
||||
#else
|
||||
plat->base = (unsigned long)map_physmem(addr, 0, MAP_NOCACHE);
|
||||
#endif
|
||||
|
||||
plat->reg_offset = dev_read_u32_default(dev, "reg-offset", 0);
|
||||
plat->reg_shift = dev_read_u32_default(dev, "reg-shift", 0);
|
||||
plat->reg_width = dev_read_u32_default(dev, "reg-io-width", 1);
|
||||
|
||||
err = clk_get_by_index(dev, 0, &clk);
|
||||
if (!err) {
|
||||
err = clk_get_rate(&clk);
|
||||
if (!IS_ERR_VALUE(err))
|
||||
plat->clock = err;
|
||||
} else if (err != -ENOENT && err != -ENODEV && err != -ENOSYS) {
|
||||
debug("ns16550 failed to get clock\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
if (!plat->clock)
|
||||
plat->clock = dev_read_u32_default(dev, "clock-frequency",
|
||||
CONFIG_SYS_NS16550_CLK);
|
||||
if (!plat->clock) {
|
||||
debug("ns16550 clock not defined\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
plat->fcr = UART_FCR_DEFVAL;
|
||||
if (port_type == PORT_JZ4780)
|
||||
plat->fcr |= UART_FCR_UME;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
const struct dm_serial_ops ns16550_serial_ops = {
|
||||
.putc = ns16550_serial_putc,
|
||||
.pending = ns16550_serial_pending,
|
||||
.getc = ns16550_serial_getc,
|
||||
.setbrg = ns16550_serial_setbrg,
|
||||
.setconfig = ns16550_serial_setconfig,
|
||||
.getinfo = ns16550_serial_getinfo,
|
||||
};
|
||||
|
||||
#if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)
|
||||
/*
|
||||
* Please consider existing compatible strings before adding a new
|
||||
* one to keep this table compact. Or you may add a generic "ns16550"
|
||||
* compatible string to your dts.
|
||||
*/
|
||||
static const struct udevice_id ns16550_serial_ids[] = {
|
||||
{ .compatible = "ns16550", .data = PORT_NS16550 },
|
||||
{ .compatible = "ns16550a", .data = PORT_NS16550 },
|
||||
{ .compatible = "ingenic,jz4780-uart", .data = PORT_JZ4780 },
|
||||
{ .compatible = "nvidia,tegra20-uart", .data = PORT_NS16550 },
|
||||
{ .compatible = "snps,dw-apb-uart", .data = PORT_NS16550 },
|
||||
{}
|
||||
};
|
||||
#endif /* OF_CONTROL && !OF_PLATDATA */
|
||||
|
||||
#if CONFIG_IS_ENABLED(SERIAL_PRESENT)
|
||||
|
||||
/* TODO(sjg@chromium.org): Integrate this into a macro like CONFIG_IS_ENABLED */
|
||||
#if !defined(CONFIG_TPL_BUILD) || defined(CONFIG_TPL_DM_SERIAL)
|
||||
U_BOOT_DRIVER(ns16550_serial) = {
|
||||
.name = "ns16550_serial",
|
||||
.id = UCLASS_SERIAL,
|
||||
#if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)
|
||||
.of_match = ns16550_serial_ids,
|
||||
.ofdata_to_platdata = ns16550_serial_ofdata_to_platdata,
|
||||
.platdata_auto_alloc_size = sizeof(struct ns16550_platdata),
|
||||
#endif
|
||||
.priv_auto_alloc_size = sizeof(struct NS16550),
|
||||
.probe = ns16550_serial_probe,
|
||||
.ops = &ns16550_serial_ops,
|
||||
#if !CONFIG_IS_ENABLED(OF_CONTROL)
|
||||
.flags = DM_FLAG_PRE_RELOC,
|
||||
#endif
|
||||
};
|
||||
#endif
|
||||
#endif /* SERIAL_PRESENT */
|
||||
|
||||
#endif /* CONFIG_DM_SERIAL */
|
||||
@@ -0,0 +1,275 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright (c) 2011 The Chromium OS Authors.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This provide a test serial port. It provides an emulated serial port where
|
||||
* a test program and read out the serial output and inject serial input for
|
||||
* U-Boot.
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <console.h>
|
||||
#include <dm.h>
|
||||
#include <fdtdec.h>
|
||||
#include <lcd.h>
|
||||
#include <os.h>
|
||||
#include <serial.h>
|
||||
#include <video.h>
|
||||
#include <linux/compiler.h>
|
||||
#include <asm/state.h>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
#if CONFIG_IS_ENABLED(OF_CONTROL)
|
||||
|
||||
/*
|
||||
*
|
||||
* serial_buf: A buffer that holds keyboard characters for the
|
||||
* Sandbox U-Boot.
|
||||
*
|
||||
* invariants:
|
||||
* serial_buf_write == serial_buf_read -> empty buffer
|
||||
* (serial_buf_write + 1) % 16 == serial_buf_read -> full buffer
|
||||
*/
|
||||
static char serial_buf[16];
|
||||
static unsigned int serial_buf_write;
|
||||
static unsigned int serial_buf_read;
|
||||
|
||||
struct sandbox_serial_platdata {
|
||||
int colour; /* Text colour to use for output, -1 for none */
|
||||
};
|
||||
|
||||
struct sandbox_serial_priv {
|
||||
bool start_of_line;
|
||||
};
|
||||
|
||||
/**
|
||||
* output_ansi_colour() - Output an ANSI colour code
|
||||
*
|
||||
* @colour: Colour to output (0-7)
|
||||
*/
|
||||
static void output_ansi_colour(int colour)
|
||||
{
|
||||
char ansi_code[] = "\x1b[1;3Xm";
|
||||
|
||||
ansi_code[5] = '0' + colour;
|
||||
os_write(1, ansi_code, sizeof(ansi_code) - 1);
|
||||
}
|
||||
|
||||
static void output_ansi_reset(void)
|
||||
{
|
||||
os_write(1, "\x1b[0m", 4);
|
||||
}
|
||||
|
||||
static int sandbox_serial_probe(struct udevice *dev)
|
||||
{
|
||||
struct sandbox_state *state = state_get_current();
|
||||
struct sandbox_serial_priv *priv = dev_get_priv(dev);
|
||||
|
||||
if (state->term_raw != STATE_TERM_COOKED)
|
||||
os_tty_raw(0, state->term_raw == STATE_TERM_RAW_WITH_SIGS);
|
||||
priv->start_of_line = 0;
|
||||
|
||||
if (state->term_raw != STATE_TERM_RAW)
|
||||
disable_ctrlc(1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sandbox_serial_remove(struct udevice *dev)
|
||||
{
|
||||
struct sandbox_serial_platdata *plat = dev->platdata;
|
||||
|
||||
if (plat->colour != -1)
|
||||
output_ansi_reset();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sandbox_serial_putc(struct udevice *dev, const char ch)
|
||||
{
|
||||
struct sandbox_serial_priv *priv = dev_get_priv(dev);
|
||||
struct sandbox_serial_platdata *plat = dev->platdata;
|
||||
|
||||
if (priv->start_of_line && plat->colour != -1) {
|
||||
priv->start_of_line = false;
|
||||
output_ansi_colour(plat->colour);
|
||||
}
|
||||
|
||||
os_write(1, &ch, 1);
|
||||
if (ch == '\n')
|
||||
priv->start_of_line = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned int increment_buffer_index(unsigned int index)
|
||||
{
|
||||
return (index + 1) % ARRAY_SIZE(serial_buf);
|
||||
}
|
||||
|
||||
static int sandbox_serial_pending(struct udevice *dev, bool input)
|
||||
{
|
||||
const unsigned int next_index =
|
||||
increment_buffer_index(serial_buf_write);
|
||||
ssize_t count;
|
||||
|
||||
if (!input)
|
||||
return 0;
|
||||
|
||||
os_usleep(100);
|
||||
#ifndef CONFIG_SPL_BUILD
|
||||
video_sync_all();
|
||||
#endif
|
||||
if (next_index == serial_buf_read)
|
||||
return 1; /* buffer full */
|
||||
|
||||
count = os_read(0, &serial_buf[serial_buf_write], 1);
|
||||
if (count == 1)
|
||||
serial_buf_write = next_index;
|
||||
|
||||
return serial_buf_write != serial_buf_read;
|
||||
}
|
||||
|
||||
static int sandbox_serial_getc(struct udevice *dev)
|
||||
{
|
||||
int result;
|
||||
|
||||
if (!sandbox_serial_pending(dev, true))
|
||||
return -EAGAIN; /* buffer empty */
|
||||
|
||||
result = serial_buf[serial_buf_read];
|
||||
serial_buf_read = increment_buffer_index(serial_buf_read);
|
||||
return result;
|
||||
}
|
||||
#endif /* CONFIG_IS_ENABLED(OF_CONTROL) */
|
||||
|
||||
#ifdef CONFIG_DEBUG_UART_SANDBOX
|
||||
|
||||
#include <debug_uart.h>
|
||||
|
||||
static inline void _debug_uart_init(void)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void _debug_uart_putc(int ch)
|
||||
{
|
||||
os_putc(ch);
|
||||
}
|
||||
|
||||
DEBUG_UART_FUNCS
|
||||
|
||||
#endif /* CONFIG_DEBUG_UART_SANDBOX */
|
||||
|
||||
static int sandbox_serial_getconfig(struct udevice *dev, uint *serial_config)
|
||||
{
|
||||
uint config = SERIAL_DEFAULT_CONFIG;
|
||||
|
||||
if (!serial_config)
|
||||
return -EINVAL;
|
||||
|
||||
*serial_config = config;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sandbox_serial_setconfig(struct udevice *dev, uint serial_config)
|
||||
{
|
||||
u8 parity = SERIAL_GET_PARITY(serial_config);
|
||||
u8 bits = SERIAL_GET_BITS(serial_config);
|
||||
u8 stop = SERIAL_GET_STOP(serial_config);
|
||||
|
||||
if (bits != SERIAL_8_BITS || stop != SERIAL_ONE_STOP ||
|
||||
parity != SERIAL_PAR_NONE)
|
||||
return -ENOTSUPP; /* not supported in driver*/
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sandbox_serial_getinfo(struct udevice *dev,
|
||||
struct serial_device_info *serial_info)
|
||||
{
|
||||
struct serial_device_info info = {
|
||||
.type = SERIAL_CHIP_UNKNOWN,
|
||||
.addr_space = SERIAL_ADDRESS_SPACE_IO,
|
||||
.addr = SERIAL_DEFAULT_ADDRESS,
|
||||
.reg_width = 1,
|
||||
.reg_offset = 0,
|
||||
.reg_shift = 0,
|
||||
};
|
||||
|
||||
if (!serial_info)
|
||||
return -EINVAL;
|
||||
|
||||
*serial_info = info;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if CONFIG_IS_ENABLED(OF_CONTROL)
|
||||
static const char * const ansi_colour[] = {
|
||||
"black", "red", "green", "yellow", "blue", "megenta", "cyan",
|
||||
"white",
|
||||
};
|
||||
|
||||
static int sandbox_serial_ofdata_to_platdata(struct udevice *dev)
|
||||
{
|
||||
struct sandbox_serial_platdata *plat = dev->platdata;
|
||||
const char *colour;
|
||||
int i;
|
||||
|
||||
if (CONFIG_IS_ENABLED(OF_PLATDATA))
|
||||
return 0;
|
||||
plat->colour = -1;
|
||||
colour = fdt_getprop(gd->fdt_blob, dev_of_offset(dev),
|
||||
"sandbox,text-colour", NULL);
|
||||
if (colour) {
|
||||
for (i = 0; i < ARRAY_SIZE(ansi_colour); i++) {
|
||||
if (!strcmp(colour, ansi_colour[i])) {
|
||||
plat->colour = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dm_serial_ops sandbox_serial_ops = {
|
||||
.putc = sandbox_serial_putc,
|
||||
.pending = sandbox_serial_pending,
|
||||
.getc = sandbox_serial_getc,
|
||||
.getconfig = sandbox_serial_getconfig,
|
||||
.setconfig = sandbox_serial_setconfig,
|
||||
.getinfo = sandbox_serial_getinfo,
|
||||
};
|
||||
|
||||
static const struct udevice_id sandbox_serial_ids[] = {
|
||||
{ .compatible = "sandbox,serial" },
|
||||
{ }
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(serial_sandbox) = {
|
||||
.name = "serial_sandbox",
|
||||
.id = UCLASS_SERIAL,
|
||||
.of_match = sandbox_serial_ids,
|
||||
.ofdata_to_platdata = sandbox_serial_ofdata_to_platdata,
|
||||
.platdata_auto_alloc_size = sizeof(struct sandbox_serial_platdata),
|
||||
.priv_auto_alloc_size = sizeof(struct sandbox_serial_priv),
|
||||
.probe = sandbox_serial_probe,
|
||||
.remove = sandbox_serial_remove,
|
||||
.ops = &sandbox_serial_ops,
|
||||
.flags = DM_FLAG_PRE_RELOC,
|
||||
};
|
||||
|
||||
static const struct sandbox_serial_platdata platdata_non_fdt = {
|
||||
.colour = -1,
|
||||
};
|
||||
|
||||
U_BOOT_DEVICE(serial_sandbox_non_fdt) = {
|
||||
.name = "serial_sandbox",
|
||||
.platdata = &platdata_non_fdt,
|
||||
};
|
||||
#endif /* CONFIG_IS_ENABLED(OF_CONTROL) */
|
||||
@@ -0,0 +1,509 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright (c) 2014 The Chromium OS Authors.
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <dm.h>
|
||||
#include <env_internal.h>
|
||||
#include <errno.h>
|
||||
#include <os.h>
|
||||
#include <serial.h>
|
||||
#include <stdio_dev.h>
|
||||
#include <watchdog.h>
|
||||
#include <dm/lists.h>
|
||||
#include <dm/device-internal.h>
|
||||
#include <dm/of_access.h>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
/*
|
||||
* Table with supported baudrates (defined in config_xyz.h)
|
||||
*/
|
||||
static const unsigned long baudrate_table[] = CONFIG_SYS_BAUDRATE_TABLE;
|
||||
|
||||
#if !CONFIG_VAL(SYS_MALLOC_F_LEN)
|
||||
#error "Serial is required before relocation - define CONFIG_$(SPL_)SYS_MALLOC_F_LEN to make this work"
|
||||
#endif
|
||||
|
||||
#if CONFIG_IS_ENABLED(SERIAL_PRESENT)
|
||||
static int serial_check_stdout(const void *blob, struct udevice **devp)
|
||||
{
|
||||
int node = -1;
|
||||
const char *str, *p, *name;
|
||||
int namelen;
|
||||
|
||||
/* Check for a chosen console */
|
||||
str = fdtdec_get_chosen_prop(blob, "stdout-path");
|
||||
if (str) {
|
||||
p = strchr(str, ':');
|
||||
namelen = p ? p - str : strlen(str);
|
||||
node = fdt_path_offset_namelen(blob, str, namelen);
|
||||
|
||||
if (node < 0) {
|
||||
/*
|
||||
* Deal with things like
|
||||
* stdout-path = "serial0:115200n8";
|
||||
*
|
||||
* We need to look up the alias and then follow it to
|
||||
* the correct node.
|
||||
*/
|
||||
name = fdt_get_alias_namelen(blob, str, namelen);
|
||||
if (name)
|
||||
node = fdt_path_offset(blob, name);
|
||||
}
|
||||
}
|
||||
|
||||
if (node < 0)
|
||||
node = fdt_path_offset(blob, "console");
|
||||
if (!uclass_get_device_by_of_offset(UCLASS_SERIAL, node, devp))
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* If the console is not marked to be bound before relocation, bind it
|
||||
* anyway.
|
||||
*/
|
||||
if (node > 0 && !lists_bind_fdt(gd->dm_root, offset_to_ofnode(node),
|
||||
devp, false)) {
|
||||
if (!device_probe(*devp))
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
static void serial_find_console_or_panic(void)
|
||||
{
|
||||
const void *blob = gd->fdt_blob;
|
||||
struct udevice *dev;
|
||||
#ifdef CONFIG_SERIAL_SEARCH_ALL
|
||||
int ret;
|
||||
#endif
|
||||
|
||||
if (CONFIG_IS_ENABLED(OF_PLATDATA)) {
|
||||
uclass_first_device(UCLASS_SERIAL, &dev);
|
||||
if (dev) {
|
||||
gd->cur_serial_dev = dev;
|
||||
return;
|
||||
}
|
||||
} else if (CONFIG_IS_ENABLED(OF_CONTROL) && blob) {
|
||||
/* Live tree has support for stdout */
|
||||
if (of_live_active()) {
|
||||
struct device_node *np = of_get_stdout();
|
||||
|
||||
if (np && !uclass_get_device_by_ofnode(UCLASS_SERIAL,
|
||||
np_to_ofnode(np), &dev)) {
|
||||
gd->cur_serial_dev = dev;
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if (!serial_check_stdout(blob, &dev)) {
|
||||
gd->cur_serial_dev = dev;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!SPL_BUILD || !CONFIG_IS_ENABLED(OF_CONTROL) || !blob) {
|
||||
/*
|
||||
* Try to use CONFIG_CONS_INDEX if available (it is numbered
|
||||
* from 1!).
|
||||
*
|
||||
* Failing that, get the device with sequence number 0, or in
|
||||
* extremis just the first working serial device we can find.
|
||||
* But we insist on having a console (even if it is silent).
|
||||
*/
|
||||
#ifdef CONFIG_CONS_INDEX
|
||||
#define INDEX (CONFIG_CONS_INDEX - 1)
|
||||
#else
|
||||
#define INDEX 0
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SERIAL_SEARCH_ALL
|
||||
if (!uclass_get_device_by_seq(UCLASS_SERIAL, INDEX, &dev) ||
|
||||
!uclass_get_device(UCLASS_SERIAL, INDEX, &dev)) {
|
||||
if (dev->flags & DM_FLAG_ACTIVATED) {
|
||||
gd->cur_serial_dev = dev;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Search for any working device */
|
||||
for (ret = uclass_first_device_check(UCLASS_SERIAL, &dev);
|
||||
dev;
|
||||
ret = uclass_next_device_check(&dev)) {
|
||||
if (!ret) {
|
||||
/* Device did succeed probing */
|
||||
gd->cur_serial_dev = dev;
|
||||
return;
|
||||
}
|
||||
}
|
||||
#else
|
||||
if (!uclass_get_device_by_seq(UCLASS_SERIAL, INDEX, &dev) ||
|
||||
!uclass_get_device(UCLASS_SERIAL, INDEX, &dev) ||
|
||||
(!uclass_first_device(UCLASS_SERIAL, &dev) && dev)) {
|
||||
gd->cur_serial_dev = dev;
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
#undef INDEX
|
||||
}
|
||||
|
||||
#ifdef CONFIG_REQUIRE_SERIAL_CONSOLE
|
||||
panic_str("No serial driver found");
|
||||
#endif
|
||||
}
|
||||
#endif /* CONFIG_SERIAL_PRESENT */
|
||||
|
||||
/* Called prior to relocation */
|
||||
int serial_init(void)
|
||||
{
|
||||
#if CONFIG_IS_ENABLED(SERIAL_PRESENT)
|
||||
serial_find_console_or_panic();
|
||||
gd->flags |= GD_FLG_SERIAL_READY;
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Called after relocation */
|
||||
void serial_initialize(void)
|
||||
{
|
||||
serial_init();
|
||||
}
|
||||
|
||||
static void _serial_putc(struct udevice *dev, char ch)
|
||||
{
|
||||
struct dm_serial_ops *ops = serial_get_ops(dev);
|
||||
int err;
|
||||
|
||||
if (ch == '\n')
|
||||
_serial_putc(dev, '\r');
|
||||
|
||||
do {
|
||||
err = ops->putc(dev, ch);
|
||||
} while (err == -EAGAIN);
|
||||
}
|
||||
|
||||
static void _serial_puts(struct udevice *dev, const char *str)
|
||||
{
|
||||
while (*str)
|
||||
_serial_putc(dev, *str++);
|
||||
}
|
||||
|
||||
static int __serial_getc(struct udevice *dev)
|
||||
{
|
||||
struct dm_serial_ops *ops = serial_get_ops(dev);
|
||||
int err;
|
||||
|
||||
do {
|
||||
err = ops->getc(dev);
|
||||
if (err == -EAGAIN)
|
||||
WATCHDOG_RESET();
|
||||
} while (err == -EAGAIN);
|
||||
|
||||
return err >= 0 ? err : 0;
|
||||
}
|
||||
|
||||
static int __serial_tstc(struct udevice *dev)
|
||||
{
|
||||
struct dm_serial_ops *ops = serial_get_ops(dev);
|
||||
|
||||
if (ops->pending)
|
||||
return ops->pending(dev, true);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
#if CONFIG_IS_ENABLED(SERIAL_RX_BUFFER)
|
||||
static int _serial_tstc(struct udevice *dev)
|
||||
{
|
||||
struct serial_dev_priv *upriv = dev_get_uclass_priv(dev);
|
||||
|
||||
/* Read all available chars into the RX buffer */
|
||||
while (__serial_tstc(dev)) {
|
||||
upriv->buf[upriv->wr_ptr++] = __serial_getc(dev);
|
||||
upriv->wr_ptr %= CONFIG_SERIAL_RX_BUFFER_SIZE;
|
||||
}
|
||||
|
||||
return upriv->rd_ptr != upriv->wr_ptr ? 1 : 0;
|
||||
}
|
||||
|
||||
static int _serial_getc(struct udevice *dev)
|
||||
{
|
||||
struct serial_dev_priv *upriv = dev_get_uclass_priv(dev);
|
||||
char val;
|
||||
|
||||
if (upriv->rd_ptr == upriv->wr_ptr)
|
||||
return __serial_getc(dev);
|
||||
|
||||
val = upriv->buf[upriv->rd_ptr++];
|
||||
upriv->rd_ptr %= CONFIG_SERIAL_RX_BUFFER_SIZE;
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
#else /* CONFIG_IS_ENABLED(SERIAL_RX_BUFFER) */
|
||||
|
||||
static int _serial_getc(struct udevice *dev)
|
||||
{
|
||||
return __serial_getc(dev);
|
||||
}
|
||||
|
||||
static int _serial_tstc(struct udevice *dev)
|
||||
{
|
||||
return __serial_tstc(dev);
|
||||
}
|
||||
#endif /* CONFIG_IS_ENABLED(SERIAL_RX_BUFFER) */
|
||||
|
||||
void serial_putc(char ch)
|
||||
{
|
||||
if (gd->cur_serial_dev)
|
||||
_serial_putc(gd->cur_serial_dev, ch);
|
||||
}
|
||||
|
||||
void serial_puts(const char *str)
|
||||
{
|
||||
if (gd->cur_serial_dev)
|
||||
_serial_puts(gd->cur_serial_dev, str);
|
||||
}
|
||||
|
||||
int serial_getc(void)
|
||||
{
|
||||
if (!gd->cur_serial_dev)
|
||||
return 0;
|
||||
|
||||
return _serial_getc(gd->cur_serial_dev);
|
||||
}
|
||||
|
||||
int serial_tstc(void)
|
||||
{
|
||||
if (!gd->cur_serial_dev)
|
||||
return 0;
|
||||
|
||||
return _serial_tstc(gd->cur_serial_dev);
|
||||
}
|
||||
|
||||
void serial_setbrg(void)
|
||||
{
|
||||
struct dm_serial_ops *ops;
|
||||
|
||||
if (!gd->cur_serial_dev)
|
||||
return;
|
||||
|
||||
ops = serial_get_ops(gd->cur_serial_dev);
|
||||
if (ops->setbrg)
|
||||
ops->setbrg(gd->cur_serial_dev, gd->baudrate);
|
||||
}
|
||||
|
||||
int serial_getconfig(struct udevice *dev, uint *config)
|
||||
{
|
||||
struct dm_serial_ops *ops;
|
||||
|
||||
ops = serial_get_ops(dev);
|
||||
if (ops->getconfig)
|
||||
return ops->getconfig(dev, config);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int serial_setconfig(struct udevice *dev, uint config)
|
||||
{
|
||||
struct dm_serial_ops *ops;
|
||||
|
||||
ops = serial_get_ops(dev);
|
||||
if (ops->setconfig)
|
||||
return ops->setconfig(dev, config);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int serial_getinfo(struct udevice *dev, struct serial_device_info *info)
|
||||
{
|
||||
struct dm_serial_ops *ops;
|
||||
|
||||
if (!info)
|
||||
return -EINVAL;
|
||||
|
||||
info->baudrate = gd->baudrate;
|
||||
|
||||
ops = serial_get_ops(dev);
|
||||
if (ops->getinfo)
|
||||
return ops->getinfo(dev, info);
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
void serial_stdio_init(void)
|
||||
{
|
||||
}
|
||||
|
||||
#if defined(CONFIG_DM_STDIO)
|
||||
|
||||
#if CONFIG_IS_ENABLED(SERIAL_PRESENT)
|
||||
static void serial_stub_putc(struct stdio_dev *sdev, const char ch)
|
||||
{
|
||||
_serial_putc(sdev->priv, ch);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void serial_stub_puts(struct stdio_dev *sdev, const char *str)
|
||||
{
|
||||
_serial_puts(sdev->priv, str);
|
||||
}
|
||||
|
||||
static int serial_stub_getc(struct stdio_dev *sdev)
|
||||
{
|
||||
return _serial_getc(sdev->priv);
|
||||
}
|
||||
|
||||
static int serial_stub_tstc(struct stdio_dev *sdev)
|
||||
{
|
||||
return _serial_tstc(sdev->priv);
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* on_baudrate() - Update the actual baudrate when the env var changes
|
||||
*
|
||||
* This will check for a valid baudrate and only apply it if valid.
|
||||
*/
|
||||
static int on_baudrate(const char *name, const char *value, enum env_op op,
|
||||
int flags)
|
||||
{
|
||||
int i;
|
||||
int baudrate;
|
||||
|
||||
switch (op) {
|
||||
case env_op_create:
|
||||
case env_op_overwrite:
|
||||
/*
|
||||
* Switch to new baudrate if new baudrate is supported
|
||||
*/
|
||||
baudrate = simple_strtoul(value, NULL, 10);
|
||||
|
||||
/* Not actually changing */
|
||||
if (gd->baudrate == baudrate)
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(baudrate_table); ++i) {
|
||||
if (baudrate == baudrate_table[i])
|
||||
break;
|
||||
}
|
||||
if (i == ARRAY_SIZE(baudrate_table)) {
|
||||
if ((flags & H_FORCE) == 0)
|
||||
printf("## Baudrate %d bps not supported\n",
|
||||
baudrate);
|
||||
return 1;
|
||||
}
|
||||
if ((flags & H_INTERACTIVE) != 0) {
|
||||
printf("## Switch baudrate to %d bps and press ENTER ...\n",
|
||||
baudrate);
|
||||
udelay(50000);
|
||||
}
|
||||
|
||||
gd->baudrate = baudrate;
|
||||
|
||||
serial_setbrg();
|
||||
|
||||
udelay(50000);
|
||||
|
||||
if ((flags & H_INTERACTIVE) != 0)
|
||||
while (1) {
|
||||
if (getc() == '\r')
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
case env_op_delete:
|
||||
printf("## Baudrate may not be deleted\n");
|
||||
return 1;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
U_BOOT_ENV_CALLBACK(baudrate, on_baudrate);
|
||||
|
||||
#if CONFIG_IS_ENABLED(SERIAL_PRESENT)
|
||||
static int serial_post_probe(struct udevice *dev)
|
||||
{
|
||||
struct dm_serial_ops *ops = serial_get_ops(dev);
|
||||
#ifdef CONFIG_DM_STDIO
|
||||
struct serial_dev_priv *upriv = dev_get_uclass_priv(dev);
|
||||
struct stdio_dev sdev;
|
||||
#endif
|
||||
int ret;
|
||||
|
||||
#if defined(CONFIG_NEEDS_MANUAL_RELOC)
|
||||
if (ops->setbrg)
|
||||
ops->setbrg += gd->reloc_off;
|
||||
if (ops->getc)
|
||||
ops->getc += gd->reloc_off;
|
||||
if (ops->putc)
|
||||
ops->putc += gd->reloc_off;
|
||||
if (ops->pending)
|
||||
ops->pending += gd->reloc_off;
|
||||
if (ops->clear)
|
||||
ops->clear += gd->reloc_off;
|
||||
if (ops->getconfig)
|
||||
ops->getconfig += gd->reloc_off;
|
||||
if (ops->setconfig)
|
||||
ops->setconfig += gd->reloc_off;
|
||||
#if CONFIG_POST & CONFIG_SYS_POST_UART
|
||||
if (ops->loop)
|
||||
ops->loop += gd->reloc_off;
|
||||
#endif
|
||||
if (ops->getinfo)
|
||||
ops->getinfo += gd->reloc_off;
|
||||
#endif
|
||||
/* Set the baud rate */
|
||||
if (ops->setbrg) {
|
||||
ret = ops->setbrg(dev, gd->baudrate);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_DM_STDIO
|
||||
if (!(gd->flags & GD_FLG_RELOC))
|
||||
return 0;
|
||||
memset(&sdev, '\0', sizeof(sdev));
|
||||
|
||||
strncpy(sdev.name, dev->name, sizeof(sdev.name));
|
||||
sdev.flags = DEV_FLAGS_OUTPUT | DEV_FLAGS_INPUT | DEV_FLAGS_DM;
|
||||
sdev.priv = dev;
|
||||
sdev.putc = serial_stub_putc;
|
||||
sdev.puts = serial_stub_puts;
|
||||
sdev.getc = serial_stub_getc;
|
||||
sdev.tstc = serial_stub_tstc;
|
||||
|
||||
#if CONFIG_IS_ENABLED(SERIAL_RX_BUFFER)
|
||||
/* Allocate the RX buffer */
|
||||
upriv->buf = malloc(CONFIG_SERIAL_RX_BUFFER_SIZE);
|
||||
#endif
|
||||
|
||||
stdio_register_dev(&sdev, &upriv->sdev);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int serial_pre_remove(struct udevice *dev)
|
||||
{
|
||||
#if CONFIG_IS_ENABLED(SYS_STDIO_DEREGISTER)
|
||||
struct serial_dev_priv *upriv = dev_get_uclass_priv(dev);
|
||||
|
||||
if (stdio_deregister_dev(upriv->sdev, true))
|
||||
return -EPERM;
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
UCLASS_DRIVER(serial) = {
|
||||
.id = UCLASS_SERIAL,
|
||||
.name = "serial",
|
||||
.flags = DM_UC_FLAG_SEQ_ALIAS,
|
||||
.post_probe = serial_post_probe,
|
||||
.pre_remove = serial_pre_remove,
|
||||
.per_device_auto_alloc_size = sizeof(struct serial_dev_priv),
|
||||
};
|
||||
#endif
|
||||
@@ -0,0 +1,554 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* (C) Copyright 2004
|
||||
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <env_internal.h>
|
||||
#include <serial.h>
|
||||
#include <stdio_dev.h>
|
||||
#include <post.h>
|
||||
#include <linux/compiler.h>
|
||||
#include <errno.h>
|
||||
#include <linux/lotus/usb.h>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
static struct serial_device *serial_devices;
|
||||
static struct serial_device *serial_current;
|
||||
/*
|
||||
* Table with supported baudrates (defined in config_xyz.h)
|
||||
*/
|
||||
static const unsigned long baudrate_table[] = CONFIG_SYS_BAUDRATE_TABLE;
|
||||
|
||||
/**
|
||||
* serial_null() - Void registration routine of a serial driver
|
||||
*
|
||||
* This routine implements a void registration routine of a serial
|
||||
* driver. The registration routine of a particular driver is aliased
|
||||
* to this empty function in case the driver is not compiled into
|
||||
* U-Boot.
|
||||
*/
|
||||
static void serial_null(void)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* on_baudrate() - Update the actual baudrate when the env var changes
|
||||
*
|
||||
* @name: changed environment variable
|
||||
* @value: new value of the environment variable
|
||||
* @op: operation (create, overwrite, or delete)
|
||||
* @flags: attributes of environment variable change,
|
||||
* see flags H_* in include/search.h
|
||||
*
|
||||
* This will check for a valid baudrate and only apply it if valid.
|
||||
*
|
||||
* Return: 0 on success, 1 on error
|
||||
*/
|
||||
static int on_baudrate(const char *name, const char *value, enum env_op op,
|
||||
int flags)
|
||||
{
|
||||
int i;
|
||||
int baudrate;
|
||||
|
||||
switch (op) {
|
||||
case env_op_create:
|
||||
case env_op_overwrite:
|
||||
/*
|
||||
* Switch to new baudrate if new baudrate is supported
|
||||
*/
|
||||
baudrate = simple_strtoul(value, NULL, 10);
|
||||
|
||||
/* Not actually changing */
|
||||
if (gd->baudrate == baudrate)
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(baudrate_table); ++i) {
|
||||
if (baudrate == baudrate_table[i])
|
||||
break;
|
||||
}
|
||||
if (i == ARRAY_SIZE(baudrate_table)) {
|
||||
if ((flags & H_FORCE) == 0)
|
||||
printf("## Baudrate %d bps not supported\n",
|
||||
baudrate);
|
||||
return 1;
|
||||
}
|
||||
if ((flags & H_INTERACTIVE) != 0) {
|
||||
printf("## Switch baudrate to %d"
|
||||
" bps and press ENTER ...\n", baudrate);
|
||||
udelay(50000);
|
||||
}
|
||||
|
||||
gd->baudrate = baudrate;
|
||||
|
||||
serial_setbrg();
|
||||
|
||||
udelay(50000);
|
||||
|
||||
if ((flags & H_INTERACTIVE) != 0)
|
||||
while (1) {
|
||||
if (getc() == '\r')
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
case env_op_delete:
|
||||
printf("## Baudrate may not be deleted\n");
|
||||
return 1;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
U_BOOT_ENV_CALLBACK(baudrate, on_baudrate);
|
||||
|
||||
/**
|
||||
* serial_initfunc() - Forward declare of driver registration routine
|
||||
* @name: Name of the real driver registration routine.
|
||||
*
|
||||
* This macro expands onto forward declaration of a driver registration
|
||||
* routine, which is then used below in serial_initialize() function.
|
||||
* The declaration is made weak and aliases to serial_null() so in case
|
||||
* the driver is not compiled in, the function is still declared and can
|
||||
* be used, but aliases to serial_null() and thus is optimized away.
|
||||
*/
|
||||
#define serial_initfunc(name) \
|
||||
void name(void) \
|
||||
__attribute__((weak, alias("serial_null")));
|
||||
|
||||
serial_initfunc(atmel_serial_initialize);
|
||||
serial_initfunc(mcf_serial_initialize);
|
||||
serial_initfunc(mpc85xx_serial_initialize);
|
||||
serial_initfunc(mxc_serial_initialize);
|
||||
serial_initfunc(ns16550_serial_initialize);
|
||||
serial_initfunc(pl01x_serial_initialize);
|
||||
serial_initfunc(pxa_serial_initialize);
|
||||
serial_initfunc(sh_serial_initialize);
|
||||
serial_initfunc(mtk_serial_initialize);
|
||||
|
||||
/**
|
||||
* serial_register() - Register serial driver with serial driver core
|
||||
* @dev: Pointer to the serial driver structure
|
||||
*
|
||||
* This function registers the serial driver supplied via @dev with
|
||||
* serial driver core, thus making U-Boot aware of it and making it
|
||||
* available for U-Boot to use. On platforms that still require manual
|
||||
* relocation of constant variables, relocation of the supplied structure
|
||||
* is performed.
|
||||
*/
|
||||
void serial_register(struct serial_device *dev)
|
||||
{
|
||||
#ifdef CONFIG_NEEDS_MANUAL_RELOC
|
||||
if (dev->start)
|
||||
dev->start += gd->reloc_off;
|
||||
if (dev->stop)
|
||||
dev->stop += gd->reloc_off;
|
||||
if (dev->setbrg)
|
||||
dev->setbrg += gd->reloc_off;
|
||||
if (dev->getc)
|
||||
dev->getc += gd->reloc_off;
|
||||
if (dev->tstc)
|
||||
dev->tstc += gd->reloc_off;
|
||||
if (dev->putc)
|
||||
dev->putc += gd->reloc_off;
|
||||
if (dev->puts)
|
||||
dev->puts += gd->reloc_off;
|
||||
#endif
|
||||
|
||||
dev->next = serial_devices;
|
||||
serial_devices = dev;
|
||||
}
|
||||
|
||||
/**
|
||||
* serial_initialize() - Register all compiled-in serial port drivers
|
||||
*
|
||||
* This function registers all serial port drivers that are compiled
|
||||
* into the U-Boot binary with the serial core, thus making them
|
||||
* available to U-Boot to use. Lastly, this function assigns a default
|
||||
* serial port to the serial core. That serial port is then used as a
|
||||
* default output.
|
||||
*/
|
||||
void serial_initialize(void)
|
||||
{
|
||||
atmel_serial_initialize();
|
||||
mcf_serial_initialize();
|
||||
mpc85xx_serial_initialize();
|
||||
mxc_serial_initialize();
|
||||
ns16550_serial_initialize();
|
||||
pl01x_serial_initialize();
|
||||
pxa_serial_initialize();
|
||||
sh_serial_initialize();
|
||||
mtk_serial_initialize();
|
||||
|
||||
serial_assign(default_serial_console()->name);
|
||||
}
|
||||
|
||||
static int serial_stub_start(struct stdio_dev *sdev)
|
||||
{
|
||||
struct serial_device *dev = sdev->priv;
|
||||
|
||||
return dev->start();
|
||||
}
|
||||
|
||||
static int serial_stub_stop(struct stdio_dev *sdev)
|
||||
{
|
||||
struct serial_device *dev = sdev->priv;
|
||||
|
||||
return dev->stop();
|
||||
}
|
||||
|
||||
static void serial_stub_putc(struct stdio_dev *sdev, const char ch)
|
||||
{
|
||||
struct serial_device *dev = sdev->priv;
|
||||
|
||||
dev->putc(ch);
|
||||
}
|
||||
|
||||
static void serial_stub_puts(struct stdio_dev *sdev, const char *str)
|
||||
{
|
||||
struct serial_device *dev = sdev->priv;
|
||||
|
||||
dev->puts(str);
|
||||
}
|
||||
|
||||
static int serial_stub_getc(struct stdio_dev *sdev)
|
||||
{
|
||||
struct serial_device *dev = sdev->priv;
|
||||
|
||||
return dev->getc();
|
||||
}
|
||||
|
||||
static int serial_stub_tstc(struct stdio_dev *sdev)
|
||||
{
|
||||
struct serial_device *dev = sdev->priv;
|
||||
|
||||
return dev->tstc();
|
||||
}
|
||||
|
||||
/**
|
||||
* serial_stdio_init() - Register serial ports with STDIO core
|
||||
*
|
||||
* This function generates a proxy driver for each serial port driver.
|
||||
* These proxy drivers then register with the STDIO core, making the
|
||||
* serial drivers available as STDIO devices.
|
||||
*/
|
||||
void serial_stdio_init(void)
|
||||
{
|
||||
struct stdio_dev dev;
|
||||
struct serial_device *s = serial_devices;
|
||||
|
||||
while (s) {
|
||||
memset(&dev, 0, sizeof(dev));
|
||||
|
||||
strcpy(dev.name, s->name);
|
||||
dev.flags = DEV_FLAGS_OUTPUT | DEV_FLAGS_INPUT;
|
||||
|
||||
dev.start = serial_stub_start;
|
||||
dev.stop = serial_stub_stop;
|
||||
dev.putc = serial_stub_putc;
|
||||
dev.puts = serial_stub_puts;
|
||||
dev.getc = serial_stub_getc;
|
||||
dev.tstc = serial_stub_tstc;
|
||||
dev.priv = s;
|
||||
|
||||
stdio_register(&dev);
|
||||
|
||||
s = s->next;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* serial_assign() - Select the serial output device by name
|
||||
* @name: Name of the serial driver to be used as default output
|
||||
*
|
||||
* This function configures the serial output multiplexing by
|
||||
* selecting which serial device will be used as default. In case
|
||||
* the STDIO "serial" device is selected as stdin/stdout/stderr,
|
||||
* the serial device previously configured by this function will be
|
||||
* used for the particular operation.
|
||||
*
|
||||
* Returns 0 on success, negative on error.
|
||||
*/
|
||||
int serial_assign(const char *name)
|
||||
{
|
||||
struct serial_device *s;
|
||||
|
||||
for (s = serial_devices; s; s = s->next) {
|
||||
if (strcmp(s->name, name))
|
||||
continue;
|
||||
serial_current = s;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/**
|
||||
* serial_reinit_all() - Reinitialize all compiled-in serial ports
|
||||
*
|
||||
* This function reinitializes all serial ports that are compiled
|
||||
* into U-Boot by calling their serial_start() functions.
|
||||
*/
|
||||
void serial_reinit_all(void)
|
||||
{
|
||||
struct serial_device *s;
|
||||
|
||||
for (s = serial_devices; s; s = s->next)
|
||||
s->start();
|
||||
}
|
||||
|
||||
/**
|
||||
* get_current() - Return pointer to currently selected serial port
|
||||
*
|
||||
* This function returns a pointer to currently selected serial port.
|
||||
* The currently selected serial port is altered by serial_assign()
|
||||
* function.
|
||||
*
|
||||
* In case this function is called before relocation or before any serial
|
||||
* port is configured, this function calls default_serial_console() to
|
||||
* determine the serial port. Otherwise, the configured serial port is
|
||||
* returned.
|
||||
*
|
||||
* Returns pointer to the currently selected serial port on success,
|
||||
* NULL on error.
|
||||
*/
|
||||
static struct serial_device *get_current(void)
|
||||
{
|
||||
struct serial_device *dev;
|
||||
|
||||
if (!(gd->flags & GD_FLG_RELOC))
|
||||
dev = default_serial_console();
|
||||
else if (!serial_current)
|
||||
dev = default_serial_console();
|
||||
else
|
||||
dev = serial_current;
|
||||
|
||||
/* We must have a console device */
|
||||
if (!dev) {
|
||||
#ifdef CONFIG_SPL_BUILD
|
||||
puts("Cannot find console\n");
|
||||
hang();
|
||||
#else
|
||||
panic("Cannot find console\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
return dev;
|
||||
}
|
||||
|
||||
/**
|
||||
* serial_init() - Initialize currently selected serial port
|
||||
*
|
||||
* This function initializes the currently selected serial port. This
|
||||
* usually involves setting up the registers of that particular port,
|
||||
* enabling clock and such. This function uses the get_current() call
|
||||
* to determine which port is selected.
|
||||
*
|
||||
* Returns 0 on success, negative on error.
|
||||
*/
|
||||
int serial_init(void)
|
||||
{
|
||||
gd->flags |= GD_FLG_SERIAL_READY;
|
||||
return get_current()->start();
|
||||
}
|
||||
|
||||
/**
|
||||
* serial_setbrg() - Configure baud-rate of currently selected serial port
|
||||
*
|
||||
* This function configures the baud-rate of the currently selected
|
||||
* serial port. The baud-rate is retrieved from global data within
|
||||
* the serial port driver. This function uses the get_current() call
|
||||
* to determine which port is selected.
|
||||
*
|
||||
* Returns 0 on success, negative on error.
|
||||
*/
|
||||
void serial_setbrg(void)
|
||||
{
|
||||
get_current()->setbrg();
|
||||
}
|
||||
|
||||
/**
|
||||
* serial_getc() - Read character from currently selected serial port
|
||||
*
|
||||
* This function retrieves a character from currently selected serial
|
||||
* port. In case there is no character waiting on the serial port,
|
||||
* this function will block and wait for the character to appear. This
|
||||
* function uses the get_current() call to determine which port is
|
||||
* selected.
|
||||
*
|
||||
* Returns the character on success, negative on error.
|
||||
*/
|
||||
int serial_getc(void)
|
||||
{
|
||||
return get_current()->getc();
|
||||
}
|
||||
|
||||
/**
|
||||
* serial_tstc() - Test if data is available on currently selected serial port
|
||||
*
|
||||
* This function tests if one or more characters are available on
|
||||
* currently selected serial port. This function never blocks. This
|
||||
* function uses the get_current() call to determine which port is
|
||||
* selected.
|
||||
*
|
||||
* Returns positive if character is available, zero otherwise.
|
||||
*/
|
||||
int serial_tstc(void)
|
||||
{
|
||||
return get_current()->tstc();
|
||||
}
|
||||
|
||||
/**
|
||||
* serial_putc() - Output character via currently selected serial port
|
||||
* @c: Single character to be output from the serial port.
|
||||
*
|
||||
* This function outputs a character via currently selected serial
|
||||
* port. This character is passed to the serial port driver responsible
|
||||
* for controlling the hardware. The hardware may still be in process
|
||||
* of transmitting another character, therefore this function may block
|
||||
* for a short amount of time. This function uses the get_current()
|
||||
* call to determine which port is selected.
|
||||
*/
|
||||
void serial_putc(const char c)
|
||||
{
|
||||
get_current()->putc(c);
|
||||
}
|
||||
|
||||
/**
|
||||
* serial_puts() - Output string via currently selected serial port
|
||||
* @s: Zero-terminated string to be output from the serial port.
|
||||
*
|
||||
* This function outputs a zero-terminated string via currently
|
||||
* selected serial port. This function behaves as an accelerator
|
||||
* in case the hardware can queue multiple characters for transfer.
|
||||
* The whole string that is to be output is available to the function
|
||||
* implementing the hardware manipulation. Transmitting the whole
|
||||
* string may take some time, thus this function may block for some
|
||||
* amount of time. This function uses the get_current() call to
|
||||
* determine which port is selected.
|
||||
*/
|
||||
void serial_puts(const char *s)
|
||||
{
|
||||
get_current()->puts(s);
|
||||
}
|
||||
|
||||
/**
|
||||
* default_serial_puts() - Output string by calling serial_putc() in loop
|
||||
* @s: Zero-terminated string to be output from the serial port.
|
||||
*
|
||||
* This function outputs a zero-terminated string by calling serial_putc()
|
||||
* in a loop. Most drivers do not support queueing more than one byte for
|
||||
* transfer, thus this function precisely implements their serial_puts().
|
||||
*
|
||||
* To optimize the number of get_current() calls, this function only
|
||||
* calls get_current() once and then directly accesses the putc() call
|
||||
* of the &struct serial_device .
|
||||
*/
|
||||
void default_serial_puts(const char *s)
|
||||
{
|
||||
#ifdef CONFIG_USB_GADGET
|
||||
udc_puts(s);
|
||||
#endif
|
||||
struct serial_device *dev = get_current();
|
||||
while (*s)
|
||||
dev->putc(*s++);
|
||||
}
|
||||
|
||||
#if CONFIG_POST & CONFIG_SYS_POST_UART
|
||||
static const int bauds[] = CONFIG_SYS_BAUDRATE_TABLE;
|
||||
|
||||
/**
|
||||
* uart_post_test() - Test the currently selected serial port using POST
|
||||
* @flags: POST framework flags
|
||||
*
|
||||
* Do a loopback test of the currently selected serial port. This
|
||||
* function is only useful in the context of the POST testing framwork.
|
||||
* The serial port is first configured into loopback mode and then
|
||||
* characters are sent through it.
|
||||
*
|
||||
* Returns 0 on success, value otherwise.
|
||||
*/
|
||||
/* Mark weak until post/cpu/.../uart.c migrate over */
|
||||
__weak
|
||||
int uart_post_test(int flags)
|
||||
{
|
||||
unsigned char c;
|
||||
int ret, saved_baud, b;
|
||||
struct serial_device *saved_dev, *s;
|
||||
|
||||
/* Save current serial state */
|
||||
ret = 0;
|
||||
saved_dev = serial_current;
|
||||
saved_baud = gd->baudrate;
|
||||
|
||||
for (s = serial_devices; s; s = s->next) {
|
||||
/* If this driver doesn't support loop back, skip it */
|
||||
if (!s->loop)
|
||||
continue;
|
||||
|
||||
/* Test the next device */
|
||||
serial_current = s;
|
||||
|
||||
ret = serial_init();
|
||||
if (ret)
|
||||
goto done;
|
||||
|
||||
/* Consume anything that happens to be queued */
|
||||
while (serial_tstc())
|
||||
serial_getc();
|
||||
|
||||
/* Enable loop back */
|
||||
s->loop(1);
|
||||
|
||||
/* Test every available baud rate */
|
||||
for (b = 0; b < ARRAY_SIZE(bauds); ++b) {
|
||||
gd->baudrate = bauds[b];
|
||||
serial_setbrg();
|
||||
|
||||
/*
|
||||
* Stick to printable chars to avoid issues:
|
||||
* - terminal corruption
|
||||
* - serial program reacting to sequences and sending
|
||||
* back random extra data
|
||||
* - most serial drivers add in extra chars (like \r\n)
|
||||
*/
|
||||
for (c = 0x20; c < 0x7f; ++c) {
|
||||
/* Send it out */
|
||||
serial_putc(c);
|
||||
|
||||
/* Make sure it's the same one */
|
||||
ret = (c != serial_getc());
|
||||
if (ret) {
|
||||
s->loop(0);
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Clean up the output in case it was sent */
|
||||
serial_putc('\b');
|
||||
ret = ('\b' != serial_getc());
|
||||
if (ret) {
|
||||
s->loop(0);
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Disable loop back */
|
||||
s->loop(0);
|
||||
|
||||
/* XXX: There is no serial_stop() !? */
|
||||
if (s->stop)
|
||||
s->stop();
|
||||
}
|
||||
|
||||
done:
|
||||
/* Restore previous serial state */
|
||||
serial_current = saved_dev;
|
||||
gd->baudrate = saved_baud;
|
||||
serial_reinit_all();
|
||||
serial_setbrg();
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,241 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright (C) 2015-2016 Wills Wang <wills.wang@live.com>
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <dm.h>
|
||||
#include <div64.h>
|
||||
#include <errno.h>
|
||||
#include <serial.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/addrspace.h>
|
||||
#include <asm/types.h>
|
||||
#include <dm/pinctrl.h>
|
||||
#include <mach/ar71xx_regs.h>
|
||||
|
||||
#define AR933X_UART_DATA_REG 0x00
|
||||
#define AR933X_UART_CS_REG 0x04
|
||||
#define AR933X_UART_CLK_REG 0x08
|
||||
|
||||
#define AR933X_UART_DATA_TX_RX_MASK 0xff
|
||||
#define AR933X_UART_DATA_RX_CSR BIT(8)
|
||||
#define AR933X_UART_DATA_TX_CSR BIT(9)
|
||||
#define AR933X_UART_CS_IF_MODE_S 2
|
||||
#define AR933X_UART_CS_IF_MODE_M 0x3
|
||||
#define AR933X_UART_CS_IF_MODE_DTE 1
|
||||
#define AR933X_UART_CS_IF_MODE_DCE 2
|
||||
#define AR933X_UART_CS_TX_RDY_ORIDE BIT(7)
|
||||
#define AR933X_UART_CS_RX_RDY_ORIDE BIT(8)
|
||||
#define AR933X_UART_CLK_STEP_M 0xffff
|
||||
#define AR933X_UART_CLK_SCALE_M 0xfff
|
||||
#define AR933X_UART_CLK_SCALE_S 16
|
||||
#define AR933X_UART_CLK_STEP_S 0
|
||||
|
||||
struct ar933x_serial_priv {
|
||||
void __iomem *regs;
|
||||
};
|
||||
|
||||
/*
|
||||
* Baudrate algorithm come from Linux/drivers/tty/serial/ar933x_uart.c
|
||||
* baudrate = (clk / (scale + 1)) * (step * (1 / 2^17))
|
||||
*/
|
||||
static u32 ar933x_serial_get_baud(u32 clk, u32 scale, u32 step)
|
||||
{
|
||||
u64 t;
|
||||
u32 div;
|
||||
|
||||
div = (2 << 16) * (scale + 1);
|
||||
t = clk;
|
||||
t *= step;
|
||||
t += (div / 2);
|
||||
do_div(t, div);
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
static void ar933x_serial_get_scale_step(u32 clk, u32 baud,
|
||||
u32 *scale, u32 *step)
|
||||
{
|
||||
u32 tscale, baudrate;
|
||||
long min_diff;
|
||||
|
||||
*scale = 0;
|
||||
*step = 0;
|
||||
|
||||
min_diff = baud;
|
||||
for (tscale = 0; tscale < AR933X_UART_CLK_SCALE_M; tscale++) {
|
||||
u64 tstep;
|
||||
int diff;
|
||||
|
||||
tstep = baud * (tscale + 1);
|
||||
tstep *= (2 << 16);
|
||||
do_div(tstep, clk);
|
||||
|
||||
if (tstep > AR933X_UART_CLK_STEP_M)
|
||||
break;
|
||||
|
||||
baudrate = ar933x_serial_get_baud(clk, tscale, tstep);
|
||||
diff = abs(baudrate - baud);
|
||||
if (diff < min_diff) {
|
||||
min_diff = diff;
|
||||
*scale = tscale;
|
||||
*step = tstep;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int ar933x_serial_setbrg(struct udevice *dev, int baudrate)
|
||||
{
|
||||
struct ar933x_serial_priv *priv = dev_get_priv(dev);
|
||||
u32 val, scale, step;
|
||||
|
||||
val = get_serial_clock();
|
||||
ar933x_serial_get_scale_step(val, baudrate, &scale, &step);
|
||||
|
||||
val = (scale & AR933X_UART_CLK_SCALE_M)
|
||||
<< AR933X_UART_CLK_SCALE_S;
|
||||
val |= (step & AR933X_UART_CLK_STEP_M)
|
||||
<< AR933X_UART_CLK_STEP_S;
|
||||
writel(val, priv->regs + AR933X_UART_CLK_REG);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ar933x_serial_putc(struct udevice *dev, const char c)
|
||||
{
|
||||
struct ar933x_serial_priv *priv = dev_get_priv(dev);
|
||||
u32 data;
|
||||
|
||||
data = readl(priv->regs + AR933X_UART_DATA_REG);
|
||||
if (!(data & AR933X_UART_DATA_TX_CSR))
|
||||
return -EAGAIN;
|
||||
|
||||
data = (u32)c | AR933X_UART_DATA_TX_CSR;
|
||||
writel(data, priv->regs + AR933X_UART_DATA_REG);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ar933x_serial_getc(struct udevice *dev)
|
||||
{
|
||||
struct ar933x_serial_priv *priv = dev_get_priv(dev);
|
||||
u32 data;
|
||||
|
||||
data = readl(priv->regs + AR933X_UART_DATA_REG);
|
||||
if (!(data & AR933X_UART_DATA_RX_CSR))
|
||||
return -EAGAIN;
|
||||
|
||||
writel(AR933X_UART_DATA_RX_CSR, priv->regs + AR933X_UART_DATA_REG);
|
||||
return data & AR933X_UART_DATA_TX_RX_MASK;
|
||||
}
|
||||
|
||||
static int ar933x_serial_pending(struct udevice *dev, bool input)
|
||||
{
|
||||
struct ar933x_serial_priv *priv = dev_get_priv(dev);
|
||||
u32 data;
|
||||
|
||||
data = readl(priv->regs + AR933X_UART_DATA_REG);
|
||||
if (input)
|
||||
return (data & AR933X_UART_DATA_RX_CSR) ? 1 : 0;
|
||||
else
|
||||
return (data & AR933X_UART_DATA_TX_CSR) ? 0 : 1;
|
||||
}
|
||||
|
||||
static int ar933x_serial_probe(struct udevice *dev)
|
||||
{
|
||||
struct ar933x_serial_priv *priv = dev_get_priv(dev);
|
||||
fdt_addr_t addr;
|
||||
u32 val;
|
||||
|
||||
addr = devfdt_get_addr(dev);
|
||||
if (addr == FDT_ADDR_T_NONE)
|
||||
return -EINVAL;
|
||||
|
||||
priv->regs = map_physmem(addr, AR933X_UART_SIZE,
|
||||
MAP_NOCACHE);
|
||||
|
||||
/*
|
||||
* UART controller configuration:
|
||||
* - no DMA
|
||||
* - no interrupt
|
||||
* - DCE mode
|
||||
* - no flow control
|
||||
* - set RX ready oride
|
||||
* - set TX ready oride
|
||||
*/
|
||||
val = (AR933X_UART_CS_IF_MODE_DCE << AR933X_UART_CS_IF_MODE_S) |
|
||||
AR933X_UART_CS_TX_RDY_ORIDE | AR933X_UART_CS_RX_RDY_ORIDE;
|
||||
writel(val, priv->regs + AR933X_UART_CS_REG);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dm_serial_ops ar933x_serial_ops = {
|
||||
.putc = ar933x_serial_putc,
|
||||
.pending = ar933x_serial_pending,
|
||||
.getc = ar933x_serial_getc,
|
||||
.setbrg = ar933x_serial_setbrg,
|
||||
};
|
||||
|
||||
static const struct udevice_id ar933x_serial_ids[] = {
|
||||
{ .compatible = "qca,ar9330-uart" },
|
||||
{ }
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(serial_ar933x) = {
|
||||
.name = "serial_ar933x",
|
||||
.id = UCLASS_SERIAL,
|
||||
.of_match = ar933x_serial_ids,
|
||||
.priv_auto_alloc_size = sizeof(struct ar933x_serial_priv),
|
||||
.probe = ar933x_serial_probe,
|
||||
.ops = &ar933x_serial_ops,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_DEBUG_UART_AR933X
|
||||
|
||||
#include <debug_uart.h>
|
||||
|
||||
static inline void _debug_uart_init(void)
|
||||
{
|
||||
void __iomem *regs = (void *)CONFIG_DEBUG_UART_BASE;
|
||||
u32 val, scale, step;
|
||||
|
||||
/*
|
||||
* UART controller configuration:
|
||||
* - no DMA
|
||||
* - no interrupt
|
||||
* - DCE mode
|
||||
* - no flow control
|
||||
* - set RX ready oride
|
||||
* - set TX ready oride
|
||||
*/
|
||||
val = (AR933X_UART_CS_IF_MODE_DCE << AR933X_UART_CS_IF_MODE_S) |
|
||||
AR933X_UART_CS_TX_RDY_ORIDE | AR933X_UART_CS_RX_RDY_ORIDE;
|
||||
writel(val, regs + AR933X_UART_CS_REG);
|
||||
|
||||
ar933x_serial_get_scale_step(CONFIG_DEBUG_UART_CLOCK,
|
||||
CONFIG_BAUDRATE, &scale, &step);
|
||||
|
||||
val = (scale & AR933X_UART_CLK_SCALE_M)
|
||||
<< AR933X_UART_CLK_SCALE_S;
|
||||
val |= (step & AR933X_UART_CLK_STEP_M)
|
||||
<< AR933X_UART_CLK_STEP_S;
|
||||
writel(val, regs + AR933X_UART_CLK_REG);
|
||||
}
|
||||
|
||||
static inline void _debug_uart_putc(int c)
|
||||
{
|
||||
void __iomem *regs = (void *)CONFIG_DEBUG_UART_BASE;
|
||||
u32 data;
|
||||
|
||||
do {
|
||||
data = readl(regs + AR933X_UART_DATA_REG);
|
||||
} while (!(data & AR933X_UART_DATA_TX_CSR));
|
||||
|
||||
data = (u32)c | AR933X_UART_DATA_TX_CSR;
|
||||
writel(data, regs + AR933X_UART_DATA_REG);
|
||||
}
|
||||
|
||||
DEBUG_UART_FUNCS
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,158 @@
|
||||
/*
|
||||
* Copyright (C) 2013 Synopsys, Inc. (www.synopsys.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <dm.h>
|
||||
#include <serial.h>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
struct arc_serial_regs {
|
||||
unsigned int id0;
|
||||
unsigned int id1;
|
||||
unsigned int id2;
|
||||
unsigned int id3;
|
||||
unsigned int data;
|
||||
unsigned int status;
|
||||
unsigned int baudl;
|
||||
unsigned int baudh;
|
||||
};
|
||||
|
||||
|
||||
struct arc_serial_platdata {
|
||||
struct arc_serial_regs *reg;
|
||||
unsigned int uartclk;
|
||||
};
|
||||
|
||||
/* Bit definitions of STATUS register */
|
||||
#define UART_RXEMPTY (1 << 5)
|
||||
#define UART_OVERFLOW_ERR (1 << 1)
|
||||
#define UART_TXEMPTY (1 << 7)
|
||||
|
||||
static int arc_serial_setbrg(struct udevice *dev, int baudrate)
|
||||
{
|
||||
struct arc_serial_platdata *plat = dev->platdata;
|
||||
struct arc_serial_regs *const regs = plat->reg;
|
||||
int arc_console_baud = gd->cpu_clk / (baudrate * 4) - 1;
|
||||
|
||||
writeb(arc_console_baud & 0xff, ®s->baudl);
|
||||
writeb((arc_console_baud & 0xff00) >> 8, ®s->baudh);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int arc_serial_putc(struct udevice *dev, const char c)
|
||||
{
|
||||
struct arc_serial_platdata *plat = dev->platdata;
|
||||
struct arc_serial_regs *const regs = plat->reg;
|
||||
|
||||
while (!(readb(®s->status) & UART_TXEMPTY))
|
||||
;
|
||||
|
||||
writeb(c, ®s->data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int arc_serial_tstc(struct arc_serial_regs *const regs)
|
||||
{
|
||||
return !(readb(®s->status) & UART_RXEMPTY);
|
||||
}
|
||||
|
||||
static int arc_serial_pending(struct udevice *dev, bool input)
|
||||
{
|
||||
struct arc_serial_platdata *plat = dev->platdata;
|
||||
struct arc_serial_regs *const regs = plat->reg;
|
||||
uint32_t status = readb(®s->status);
|
||||
|
||||
if (input)
|
||||
return status & UART_RXEMPTY ? 0 : 1;
|
||||
else
|
||||
return status & UART_TXEMPTY ? 0 : 1;
|
||||
}
|
||||
|
||||
static int arc_serial_getc(struct udevice *dev)
|
||||
{
|
||||
struct arc_serial_platdata *plat = dev->platdata;
|
||||
struct arc_serial_regs *const regs = plat->reg;
|
||||
|
||||
while (!arc_serial_tstc(regs))
|
||||
;
|
||||
|
||||
/* Check for overflow errors */
|
||||
if (readb(®s->status) & UART_OVERFLOW_ERR)
|
||||
return 0;
|
||||
|
||||
return readb(®s->data) & 0xFF;
|
||||
}
|
||||
|
||||
static int arc_serial_probe(struct udevice *dev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dm_serial_ops arc_serial_ops = {
|
||||
.putc = arc_serial_putc,
|
||||
.pending = arc_serial_pending,
|
||||
.getc = arc_serial_getc,
|
||||
.setbrg = arc_serial_setbrg,
|
||||
};
|
||||
|
||||
static const struct udevice_id arc_serial_ids[] = {
|
||||
{ .compatible = "snps,arc-uart" },
|
||||
{ }
|
||||
};
|
||||
|
||||
static int arc_serial_ofdata_to_platdata(struct udevice *dev)
|
||||
{
|
||||
struct arc_serial_platdata *plat = dev_get_platdata(dev);
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
plat->reg = (struct arc_serial_regs *)devfdt_get_addr(dev);
|
||||
plat->uartclk = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev),
|
||||
"clock-frequency", 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
U_BOOT_DRIVER(serial_arc) = {
|
||||
.name = "serial_arc",
|
||||
.id = UCLASS_SERIAL,
|
||||
.of_match = arc_serial_ids,
|
||||
.ofdata_to_platdata = arc_serial_ofdata_to_platdata,
|
||||
.platdata_auto_alloc_size = sizeof(struct arc_serial_platdata),
|
||||
.probe = arc_serial_probe,
|
||||
.ops = &arc_serial_ops,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_DEBUG_ARC_SERIAL
|
||||
#include <debug_uart.h>
|
||||
|
||||
static inline void _debug_uart_init(void)
|
||||
{
|
||||
struct arc_serial_regs *regs = (struct arc_serial_regs *)CONFIG_DEBUG_UART_BASE;
|
||||
int arc_console_baud = CONFIG_DEBUG_UART_CLOCK / (CONFIG_BAUDRATE * 4) - 1;
|
||||
|
||||
writeb(arc_console_baud & 0xff, ®s->baudl);
|
||||
writeb((arc_console_baud & 0xff00) >> 8, ®s->baudh);
|
||||
}
|
||||
|
||||
static inline void _debug_uart_putc(int c)
|
||||
{
|
||||
struct arc_serial_regs *regs = (struct arc_serial_regs *)CONFIG_DEBUG_UART_BASE;
|
||||
|
||||
while (!(readb(®s->status) & UART_TXEMPTY))
|
||||
;
|
||||
|
||||
writeb(c, ®s->data);
|
||||
}
|
||||
|
||||
DEBUG_UART_FUNCS
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,206 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* (C) Copyright 2016 Stephen Warren <swarren@wwwdotorg.org>
|
||||
*
|
||||
* Derived from pl01x code:
|
||||
*
|
||||
* (C) Copyright 2000
|
||||
* Rob Taylor, Flying Pig Systems. robt@flyingpig.com.
|
||||
*
|
||||
* (C) Copyright 2004
|
||||
* ARM Ltd.
|
||||
* Philippe Robin, <philippe.robin@arm.com>
|
||||
*/
|
||||
|
||||
/* Simple U-Boot driver for the BCM283x mini UART */
|
||||
|
||||
#include <common.h>
|
||||
#include <dm.h>
|
||||
#include <errno.h>
|
||||
#include <watchdog.h>
|
||||
#include <asm/gpio.h>
|
||||
#include <asm/io.h>
|
||||
#include <serial.h>
|
||||
#include <dm/platform_data/serial_bcm283x_mu.h>
|
||||
#include <dm/pinctrl.h>
|
||||
#include <linux/compiler.h>
|
||||
|
||||
struct bcm283x_mu_regs {
|
||||
u32 io;
|
||||
u32 iir;
|
||||
u32 ier;
|
||||
u32 lcr;
|
||||
u32 mcr;
|
||||
u32 lsr;
|
||||
u32 msr;
|
||||
u32 scratch;
|
||||
u32 cntl;
|
||||
u32 stat;
|
||||
u32 baud;
|
||||
};
|
||||
|
||||
#define BCM283X_MU_LCR_DATA_SIZE_8 3
|
||||
|
||||
#define BCM283X_MU_LSR_TX_IDLE BIT(6)
|
||||
/* This actually means not full, but is named not empty in the docs */
|
||||
#define BCM283X_MU_LSR_TX_EMPTY BIT(5)
|
||||
#define BCM283X_MU_LSR_RX_READY BIT(0)
|
||||
|
||||
struct bcm283x_mu_priv {
|
||||
struct bcm283x_mu_regs *regs;
|
||||
};
|
||||
|
||||
static int bcm283x_mu_serial_getc(struct udevice *dev);
|
||||
|
||||
static int bcm283x_mu_serial_setbrg(struct udevice *dev, int baudrate)
|
||||
{
|
||||
struct bcm283x_mu_serial_platdata *plat = dev_get_platdata(dev);
|
||||
struct bcm283x_mu_priv *priv = dev_get_priv(dev);
|
||||
struct bcm283x_mu_regs *regs = priv->regs;
|
||||
u32 divider;
|
||||
|
||||
if (plat->skip_init)
|
||||
goto out;
|
||||
|
||||
divider = plat->clock / (baudrate * 8);
|
||||
|
||||
writel(BCM283X_MU_LCR_DATA_SIZE_8, ®s->lcr);
|
||||
writel(divider - 1, ®s->baud);
|
||||
|
||||
out:
|
||||
/* Flush the RX queue - all data in there is bogus */
|
||||
while (bcm283x_mu_serial_getc(dev) != -EAGAIN) ;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bcm283x_mu_serial_probe(struct udevice *dev)
|
||||
{
|
||||
struct bcm283x_mu_serial_platdata *plat = dev_get_platdata(dev);
|
||||
struct bcm283x_mu_priv *priv = dev_get_priv(dev);
|
||||
|
||||
priv->regs = (struct bcm283x_mu_regs *)plat->base;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bcm283x_mu_serial_getc(struct udevice *dev)
|
||||
{
|
||||
struct bcm283x_mu_priv *priv = dev_get_priv(dev);
|
||||
struct bcm283x_mu_regs *regs = priv->regs;
|
||||
u32 data;
|
||||
|
||||
/* Wait until there is data in the FIFO */
|
||||
if (!(readl(®s->lsr) & BCM283X_MU_LSR_RX_READY))
|
||||
return -EAGAIN;
|
||||
|
||||
data = readl(®s->io);
|
||||
|
||||
return (int)data;
|
||||
}
|
||||
|
||||
static int bcm283x_mu_serial_putc(struct udevice *dev, const char data)
|
||||
{
|
||||
struct bcm283x_mu_priv *priv = dev_get_priv(dev);
|
||||
struct bcm283x_mu_regs *regs = priv->regs;
|
||||
|
||||
/* Wait until there is space in the FIFO */
|
||||
if (!(readl(®s->lsr) & BCM283X_MU_LSR_TX_EMPTY))
|
||||
return -EAGAIN;
|
||||
|
||||
/* Send the character */
|
||||
writel(data, ®s->io);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bcm283x_mu_serial_pending(struct udevice *dev, bool input)
|
||||
{
|
||||
struct bcm283x_mu_priv *priv = dev_get_priv(dev);
|
||||
struct bcm283x_mu_regs *regs = priv->regs;
|
||||
unsigned int lsr;
|
||||
|
||||
lsr = readl(®s->lsr);
|
||||
|
||||
if (input) {
|
||||
WATCHDOG_RESET();
|
||||
return (lsr & BCM283X_MU_LSR_RX_READY) ? 1 : 0;
|
||||
} else {
|
||||
return (lsr & BCM283X_MU_LSR_TX_IDLE) ? 0 : 1;
|
||||
}
|
||||
}
|
||||
|
||||
static const struct dm_serial_ops bcm283x_mu_serial_ops = {
|
||||
.putc = bcm283x_mu_serial_putc,
|
||||
.pending = bcm283x_mu_serial_pending,
|
||||
.getc = bcm283x_mu_serial_getc,
|
||||
.setbrg = bcm283x_mu_serial_setbrg,
|
||||
};
|
||||
|
||||
#if CONFIG_IS_ENABLED(OF_CONTROL)
|
||||
static const struct udevice_id bcm283x_mu_serial_id[] = {
|
||||
{.compatible = "brcm,bcm2835-aux-uart"},
|
||||
{}
|
||||
};
|
||||
|
||||
/*
|
||||
* Check if this serial device is muxed
|
||||
*
|
||||
* The serial device will only work properly if it has been muxed to the serial
|
||||
* pins by firmware. Check whether that happened here.
|
||||
*
|
||||
* @return true if serial device is muxed, false if not
|
||||
*/
|
||||
static bool bcm283x_is_serial_muxed(void)
|
||||
{
|
||||
int serial_gpio = 15;
|
||||
struct udevice *dev;
|
||||
|
||||
if (uclass_first_device(UCLASS_PINCTRL, &dev) || !dev)
|
||||
return false;
|
||||
|
||||
if (pinctrl_get_gpio_mux(dev, 0, serial_gpio) != BCM2835_GPIO_ALT5)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static int bcm283x_mu_serial_ofdata_to_platdata(struct udevice *dev)
|
||||
{
|
||||
struct bcm283x_mu_serial_platdata *plat = dev_get_platdata(dev);
|
||||
fdt_addr_t addr;
|
||||
|
||||
/* Don't spawn the device if it's not muxed */
|
||||
if (!bcm283x_is_serial_muxed())
|
||||
return -ENODEV;
|
||||
|
||||
addr = devfdt_get_addr(dev);
|
||||
if (addr == FDT_ADDR_T_NONE)
|
||||
return -EINVAL;
|
||||
|
||||
plat->base = addr;
|
||||
plat->clock = dev_read_u32_default(dev, "clock", 1);
|
||||
|
||||
/*
|
||||
* TODO: Reinitialization doesn't always work for now, just skip
|
||||
* init always - we know we're already initialized
|
||||
*/
|
||||
plat->skip_init = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
U_BOOT_DRIVER(serial_bcm283x_mu) = {
|
||||
.name = "serial_bcm283x_mu",
|
||||
.id = UCLASS_SERIAL,
|
||||
.of_match = of_match_ptr(bcm283x_mu_serial_id),
|
||||
.ofdata_to_platdata = of_match_ptr(bcm283x_mu_serial_ofdata_to_platdata),
|
||||
.platdata_auto_alloc_size = sizeof(struct bcm283x_mu_serial_platdata),
|
||||
.probe = bcm283x_mu_serial_probe,
|
||||
.ops = &bcm283x_mu_serial_ops,
|
||||
#if !CONFIG_IS_ENABLED(OF_CONTROL) || CONFIG_IS_ENABLED(OF_BOARD)
|
||||
.flags = DM_FLAG_PRE_RELOC,
|
||||
#endif
|
||||
.priv_auto_alloc_size = sizeof(struct bcm283x_mu_priv),
|
||||
};
|
||||
@@ -0,0 +1,97 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright (c) 2018 Alexander Graf <agraf@suse.de>
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <dm.h>
|
||||
#include <asm/gpio.h>
|
||||
#include <dm/pinctrl.h>
|
||||
#include <dm/platform_data/serial_pl01x.h>
|
||||
#include <serial.h>
|
||||
#include "serial_pl01x_internal.h"
|
||||
|
||||
/*
|
||||
* Check if this serial device is muxed
|
||||
*
|
||||
* The serial device will only work properly if it has been muxed to the serial
|
||||
* pins by firmware. Check whether that happened here.
|
||||
*
|
||||
* @return true if serial device is muxed, false if not
|
||||
*/
|
||||
static bool bcm283x_is_serial_muxed(void)
|
||||
{
|
||||
int serial_gpio = 15;
|
||||
struct udevice *dev;
|
||||
|
||||
if (uclass_first_device(UCLASS_PINCTRL, &dev) || !dev)
|
||||
return false;
|
||||
|
||||
if (pinctrl_get_gpio_mux(dev, 0, serial_gpio) != BCM2835_GPIO_ALT0)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static int bcm283x_pl011_serial_ofdata_to_platdata(struct udevice *dev)
|
||||
{
|
||||
struct pl01x_serial_platdata *plat = dev_get_platdata(dev);
|
||||
int ret;
|
||||
|
||||
/* Don't spawn the device if it's not muxed */
|
||||
if (!bcm283x_is_serial_muxed())
|
||||
return -ENODEV;
|
||||
|
||||
ret = pl01x_serial_ofdata_to_platdata(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* TODO: Reinitialization doesn't always work for now, just skip
|
||||
* init always - we know we're already initialized
|
||||
*/
|
||||
plat->skip_init = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bcm283x_pl011_serial_setbrg(struct udevice *dev, int baudrate)
|
||||
{
|
||||
int r;
|
||||
|
||||
r = pl01x_serial_setbrg(dev, baudrate);
|
||||
|
||||
/*
|
||||
* We may have been muxed to a bogus line before. Drain the RX
|
||||
* queue so we start at a clean slate.
|
||||
*/
|
||||
while (pl01x_serial_getc(dev) != -EAGAIN) ;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static const struct dm_serial_ops bcm283x_pl011_serial_ops = {
|
||||
.putc = pl01x_serial_putc,
|
||||
.pending = pl01x_serial_pending,
|
||||
.getc = pl01x_serial_getc,
|
||||
.setbrg = bcm283x_pl011_serial_setbrg,
|
||||
};
|
||||
|
||||
static const struct udevice_id bcm283x_pl011_serial_id[] = {
|
||||
{.compatible = "brcm,bcm2835-pl011", .data = TYPE_PL011},
|
||||
{}
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(bcm283x_pl011_uart) = {
|
||||
.name = "bcm283x_pl011",
|
||||
.id = UCLASS_SERIAL,
|
||||
.of_match = of_match_ptr(bcm283x_pl011_serial_id),
|
||||
.ofdata_to_platdata = of_match_ptr(bcm283x_pl011_serial_ofdata_to_platdata),
|
||||
.platdata_auto_alloc_size = sizeof(struct pl01x_serial_platdata),
|
||||
.probe = pl01x_serial_probe,
|
||||
.ops = &bcm283x_pl011_serial_ops,
|
||||
#if !CONFIG_IS_ENABLED(OF_CONTROL) || CONFIG_IS_ENABLED(OF_BOARD)
|
||||
.flags = DM_FLAG_PRE_RELOC,
|
||||
#endif
|
||||
.priv_auto_alloc_size = sizeof(struct pl01x_priv),
|
||||
};
|
||||
@@ -0,0 +1,295 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright (C) 2017 Álvaro Fernández Rojas <noltari@gmail.com>
|
||||
*
|
||||
* Derived from linux/drivers/tty/serial/bcm63xx_uart.c:
|
||||
* Copyright (C) 2008 Maxime Bizon <mbizon@freebox.fr>
|
||||
*/
|
||||
|
||||
#include <clk.h>
|
||||
#include <dm.h>
|
||||
#include <debug_uart.h>
|
||||
#include <errno.h>
|
||||
#include <serial.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/types.h>
|
||||
|
||||
/* UART Control register */
|
||||
#define UART_CTL_REG 0x0
|
||||
#define UART_CTL_RXTIMEOUT_MASK 0x1f
|
||||
#define UART_CTL_RXTIMEOUT_5 0x5
|
||||
#define UART_CTL_RSTRXFIFO_SHIFT 6
|
||||
#define UART_CTL_RSTRXFIFO_MASK (1 << UART_CTL_RSTRXFIFO_SHIFT)
|
||||
#define UART_CTL_RSTTXFIFO_SHIFT 7
|
||||
#define UART_CTL_RSTTXFIFO_MASK (1 << UART_CTL_RSTTXFIFO_SHIFT)
|
||||
#define UART_CTL_STOPBITS_SHIFT 8
|
||||
#define UART_CTL_STOPBITS_MASK (0xf << UART_CTL_STOPBITS_SHIFT)
|
||||
#define UART_CTL_STOPBITS_1 (0x7 << UART_CTL_STOPBITS_SHIFT)
|
||||
#define UART_CTL_BITSPERSYM_SHIFT 12
|
||||
#define UART_CTL_BITSPERSYM_MASK (0x3 << UART_CTL_BITSPERSYM_SHIFT)
|
||||
#define UART_CTL_BITSPERSYM_8 (0x3 << UART_CTL_BITSPERSYM_SHIFT)
|
||||
#define UART_CTL_XMITBRK_SHIFT 14
|
||||
#define UART_CTL_XMITBRK_MASK (1 << UART_CTL_XMITBRK_SHIFT)
|
||||
#define UART_CTL_RSVD_SHIFT 15
|
||||
#define UART_CTL_RSVD_MASK (1 << UART_CTL_RSVD_SHIFT)
|
||||
#define UART_CTL_RXPAREVEN_SHIFT 16
|
||||
#define UART_CTL_RXPAREVEN_MASK (1 << UART_CTL_RXPAREVEN_SHIFT)
|
||||
#define UART_CTL_RXPAREN_SHIFT 17
|
||||
#define UART_CTL_RXPAREN_MASK (1 << UART_CTL_RXPAREN_SHIFT)
|
||||
#define UART_CTL_TXPAREVEN_SHIFT 18
|
||||
#define UART_CTL_TXPAREVEN_MASK (1 << UART_CTL_TXPAREVEN_SHIFT)
|
||||
#define UART_CTL_TXPAREN_SHIFT 19
|
||||
#define UART_CTL_TXPAREN_MASK (1 << UART_CTL_TXPAREN_SHIFT)
|
||||
#define UART_CTL_LOOPBACK_SHIFT 20
|
||||
#define UART_CTL_LOOPBACK_MASK (1 << UART_CTL_LOOPBACK_SHIFT)
|
||||
#define UART_CTL_RXEN_SHIFT 21
|
||||
#define UART_CTL_RXEN_MASK (1 << UART_CTL_RXEN_SHIFT)
|
||||
#define UART_CTL_TXEN_SHIFT 22
|
||||
#define UART_CTL_TXEN_MASK (1 << UART_CTL_TXEN_SHIFT)
|
||||
#define UART_CTL_BRGEN_SHIFT 23
|
||||
#define UART_CTL_BRGEN_MASK (1 << UART_CTL_BRGEN_SHIFT)
|
||||
|
||||
/* UART Baudword register */
|
||||
#define UART_BAUD_REG 0x4
|
||||
|
||||
/* UART FIFO Config register */
|
||||
#define UART_FIFO_CFG_REG 0x8
|
||||
#define UART_FIFO_CFG_RX_SHIFT 8
|
||||
#define UART_FIFO_CFG_RX_MASK (0xf << UART_FIFO_CFG_RX_SHIFT)
|
||||
#define UART_FIFO_CFG_RX_4 (0x4 << UART_FIFO_CFG_RX_SHIFT)
|
||||
#define UART_FIFO_CFG_TX_SHIFT 12
|
||||
#define UART_FIFO_CFG_TX_MASK (0xf << UART_FIFO_CFG_TX_SHIFT)
|
||||
#define UART_FIFO_CFG_TX_4 (0x4 << UART_FIFO_CFG_TX_SHIFT)
|
||||
|
||||
/* UART Interrupt register */
|
||||
#define UART_IR_REG 0x10
|
||||
#define UART_IR_STAT(x) (1 << (x))
|
||||
#define UART_IR_TXEMPTY 5
|
||||
#define UART_IR_RXOVER 7
|
||||
#define UART_IR_RXNOTEMPTY 11
|
||||
|
||||
/* UART FIFO register */
|
||||
#define UART_FIFO_REG 0x14
|
||||
#define UART_FIFO_VALID_MASK 0xff
|
||||
#define UART_FIFO_FRAMEERR_SHIFT 8
|
||||
#define UART_FIFO_FRAMEERR_MASK (1 << UART_FIFO_FRAMEERR_SHIFT)
|
||||
#define UART_FIFO_PARERR_SHIFT 9
|
||||
#define UART_FIFO_PARERR_MASK (1 << UART_FIFO_PARERR_SHIFT)
|
||||
#define UART_FIFO_BRKDET_SHIFT 10
|
||||
#define UART_FIFO_BRKDET_MASK (1 << UART_FIFO_BRKDET_SHIFT)
|
||||
#define UART_FIFO_ANYERR_MASK (UART_FIFO_FRAMEERR_MASK | \
|
||||
UART_FIFO_PARERR_MASK | \
|
||||
UART_FIFO_BRKDET_MASK)
|
||||
|
||||
struct bcm6345_serial_priv {
|
||||
void __iomem *base;
|
||||
ulong uartclk;
|
||||
};
|
||||
|
||||
/* enable rx & tx operation on uart */
|
||||
static void bcm6345_serial_enable(void __iomem *base)
|
||||
{
|
||||
setbits_32(base + UART_CTL_REG, UART_CTL_BRGEN_MASK |
|
||||
UART_CTL_TXEN_MASK | UART_CTL_RXEN_MASK);
|
||||
}
|
||||
|
||||
/* disable rx & tx operation on uart */
|
||||
static void bcm6345_serial_disable(void __iomem *base)
|
||||
{
|
||||
clrbits_32(base + UART_CTL_REG, UART_CTL_BRGEN_MASK |
|
||||
UART_CTL_TXEN_MASK | UART_CTL_RXEN_MASK);
|
||||
}
|
||||
|
||||
/* clear all unread data in rx fifo and unsent data in tx fifo */
|
||||
static void bcm6345_serial_flush(void __iomem *base)
|
||||
{
|
||||
/* empty rx and tx fifo */
|
||||
setbits_32(base + UART_CTL_REG, UART_CTL_RSTRXFIFO_MASK |
|
||||
UART_CTL_RSTTXFIFO_MASK);
|
||||
|
||||
/* read any pending char to make sure all irq status are cleared */
|
||||
readl(base + UART_FIFO_REG);
|
||||
}
|
||||
|
||||
static int bcm6345_serial_init(void __iomem *base, ulong clk, u32 baudrate)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
/* mask all irq and flush port */
|
||||
bcm6345_serial_disable(base);
|
||||
bcm6345_serial_flush(base);
|
||||
|
||||
/* set uart control config */
|
||||
clrsetbits_32(base + UART_CTL_REG,
|
||||
/* clear rx timeout */
|
||||
UART_CTL_RXTIMEOUT_MASK |
|
||||
/* clear stop bits */
|
||||
UART_CTL_STOPBITS_MASK |
|
||||
/* clear bits per symbol */
|
||||
UART_CTL_BITSPERSYM_MASK |
|
||||
/* clear xmit break */
|
||||
UART_CTL_XMITBRK_MASK |
|
||||
/* clear reserved bit */
|
||||
UART_CTL_RSVD_MASK |
|
||||
/* disable parity */
|
||||
UART_CTL_RXPAREN_MASK |
|
||||
UART_CTL_TXPAREN_MASK |
|
||||
/* disable loopback */
|
||||
UART_CTL_LOOPBACK_MASK,
|
||||
/* set timeout to 5 */
|
||||
UART_CTL_RXTIMEOUT_5 |
|
||||
/* set 8 bits/symbol */
|
||||
UART_CTL_BITSPERSYM_8 |
|
||||
/* set 1 stop bit */
|
||||
UART_CTL_STOPBITS_1 |
|
||||
/* set parity to even */
|
||||
UART_CTL_RXPAREVEN_MASK |
|
||||
UART_CTL_TXPAREVEN_MASK);
|
||||
|
||||
/* set uart fifo config */
|
||||
clrsetbits_32(base + UART_FIFO_CFG_REG,
|
||||
/* clear fifo config */
|
||||
UART_FIFO_CFG_RX_MASK |
|
||||
UART_FIFO_CFG_TX_MASK,
|
||||
/* set fifo config to 4 */
|
||||
UART_FIFO_CFG_RX_4 |
|
||||
UART_FIFO_CFG_TX_4);
|
||||
|
||||
/* set baud rate */
|
||||
val = ((clk / baudrate) >> 4);
|
||||
if (val & 0x1)
|
||||
val = (val >> 1);
|
||||
else
|
||||
val = (val >> 1) - 1;
|
||||
writel(val, base + UART_BAUD_REG);
|
||||
|
||||
/* clear interrupts */
|
||||
writel(0, base + UART_IR_REG);
|
||||
|
||||
/* enable uart */
|
||||
bcm6345_serial_enable(base);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bcm6345_serial_pending(struct udevice *dev, bool input)
|
||||
{
|
||||
struct bcm6345_serial_priv *priv = dev_get_priv(dev);
|
||||
u32 val = readl(priv->base + UART_IR_REG);
|
||||
|
||||
if (input)
|
||||
return !!(val & UART_IR_STAT(UART_IR_RXNOTEMPTY));
|
||||
else
|
||||
return !(val & UART_IR_STAT(UART_IR_TXEMPTY));
|
||||
}
|
||||
|
||||
static int bcm6345_serial_setbrg(struct udevice *dev, int baudrate)
|
||||
{
|
||||
struct bcm6345_serial_priv *priv = dev_get_priv(dev);
|
||||
|
||||
return bcm6345_serial_init(priv->base, priv->uartclk, baudrate);
|
||||
}
|
||||
|
||||
static int bcm6345_serial_putc(struct udevice *dev, const char ch)
|
||||
{
|
||||
struct bcm6345_serial_priv *priv = dev_get_priv(dev);
|
||||
u32 val;
|
||||
|
||||
val = readl(priv->base + UART_IR_REG);
|
||||
if (!(val & UART_IR_STAT(UART_IR_TXEMPTY)))
|
||||
return -EAGAIN;
|
||||
|
||||
writel(ch, priv->base + UART_FIFO_REG);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bcm6345_serial_getc(struct udevice *dev)
|
||||
{
|
||||
struct bcm6345_serial_priv *priv = dev_get_priv(dev);
|
||||
u32 val;
|
||||
|
||||
val = readl(priv->base + UART_IR_REG);
|
||||
if (val & UART_IR_STAT(UART_IR_RXOVER))
|
||||
setbits_32(priv->base + UART_CTL_REG, UART_CTL_RSTRXFIFO_MASK);
|
||||
if (!(val & UART_IR_STAT(UART_IR_RXNOTEMPTY)))
|
||||
return -EAGAIN;
|
||||
|
||||
val = readl(priv->base + UART_FIFO_REG);
|
||||
if (val & UART_FIFO_ANYERR_MASK)
|
||||
return -EAGAIN;
|
||||
|
||||
return val & UART_FIFO_VALID_MASK;
|
||||
}
|
||||
|
||||
static int bcm6345_serial_probe(struct udevice *dev)
|
||||
{
|
||||
struct bcm6345_serial_priv *priv = dev_get_priv(dev);
|
||||
struct clk clk;
|
||||
int ret;
|
||||
|
||||
/* get address */
|
||||
priv->base = dev_remap_addr(dev);
|
||||
if (!priv->base)
|
||||
return -EINVAL;
|
||||
|
||||
/* get clock rate */
|
||||
ret = clk_get_by_index(dev, 0, &clk);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
priv->uartclk = clk_get_rate(&clk);
|
||||
clk_free(&clk);
|
||||
|
||||
/* initialize serial */
|
||||
return bcm6345_serial_init(priv->base, priv->uartclk, CONFIG_BAUDRATE);
|
||||
}
|
||||
|
||||
static const struct dm_serial_ops bcm6345_serial_ops = {
|
||||
.putc = bcm6345_serial_putc,
|
||||
.pending = bcm6345_serial_pending,
|
||||
.getc = bcm6345_serial_getc,
|
||||
.setbrg = bcm6345_serial_setbrg,
|
||||
};
|
||||
|
||||
static const struct udevice_id bcm6345_serial_ids[] = {
|
||||
{ .compatible = "brcm,bcm6345-uart" },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(bcm6345_serial) = {
|
||||
.name = "bcm6345-uart",
|
||||
.id = UCLASS_SERIAL,
|
||||
.of_match = bcm6345_serial_ids,
|
||||
.probe = bcm6345_serial_probe,
|
||||
.priv_auto_alloc_size = sizeof(struct bcm6345_serial_priv),
|
||||
.ops = &bcm6345_serial_ops,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_DEBUG_UART_BCM6345
|
||||
static inline void _debug_uart_init(void)
|
||||
{
|
||||
void __iomem *base = (void __iomem *)CONFIG_DEBUG_UART_BASE;
|
||||
|
||||
bcm6345_serial_init(base, CONFIG_DEBUG_UART_CLOCK, CONFIG_BAUDRATE);
|
||||
}
|
||||
|
||||
static inline void wait_xfered(void __iomem *base)
|
||||
{
|
||||
do {
|
||||
u32 val = readl(base + UART_IR_REG);
|
||||
if (val & UART_IR_STAT(UART_IR_TXEMPTY))
|
||||
break;
|
||||
} while (1);
|
||||
}
|
||||
|
||||
static inline void _debug_uart_putc(int ch)
|
||||
{
|
||||
void __iomem *base = (void __iomem *)CONFIG_DEBUG_UART_BASE;
|
||||
|
||||
wait_xfered(base);
|
||||
writel(ch, base + UART_FIFO_REG);
|
||||
wait_xfered(base);
|
||||
}
|
||||
|
||||
DEBUG_UART_FUNCS
|
||||
#endif
|
||||
@@ -0,0 +1,155 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright (c) 2015 Google, Inc
|
||||
* Written by Simon Glass <sjg@chromium.org>
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <debug_uart.h>
|
||||
#include <dm.h>
|
||||
#include <efi.h>
|
||||
#include <efi_api.h>
|
||||
#include <errno.h>
|
||||
#include <fdtdec.h>
|
||||
#include <linux/compiler.h>
|
||||
#include <asm/io.h>
|
||||
#include <serial.h>
|
||||
|
||||
/* Information about the efi console */
|
||||
struct serial_efi_priv {
|
||||
struct efi_simple_text_input_protocol *con_in;
|
||||
struct efi_simple_text_output_protocol *con_out;
|
||||
struct efi_input_key key;
|
||||
bool have_key;
|
||||
};
|
||||
|
||||
int serial_efi_setbrg(struct udevice *dev, int baudrate)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int serial_efi_get_key(struct serial_efi_priv *priv)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (priv->have_key)
|
||||
return 0;
|
||||
ret = priv->con_in->read_key_stroke(priv->con_in, &priv->key);
|
||||
if (ret == EFI_NOT_READY)
|
||||
return -EAGAIN;
|
||||
else if (ret != EFI_SUCCESS)
|
||||
return -EIO;
|
||||
|
||||
priv->have_key = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int serial_efi_getc(struct udevice *dev)
|
||||
{
|
||||
struct serial_efi_priv *priv = dev_get_priv(dev);
|
||||
int ret, ch;
|
||||
|
||||
ret = serial_efi_get_key(priv);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
priv->have_key = false;
|
||||
ch = priv->key.unicode_char;
|
||||
|
||||
/*
|
||||
* Unicode char 8 (for backspace) is never returned. Instead we get a
|
||||
* key scan code of 8. Handle this so that backspace works correctly
|
||||
* in the U-Boot command line.
|
||||
*/
|
||||
if (!ch && priv->key.scan_code == 8)
|
||||
ch = 8;
|
||||
debug(" [%x %x %x] ", ch, priv->key.unicode_char, priv->key.scan_code);
|
||||
|
||||
return ch;
|
||||
}
|
||||
|
||||
static int serial_efi_putc(struct udevice *dev, const char ch)
|
||||
{
|
||||
struct serial_efi_priv *priv = dev_get_priv(dev);
|
||||
uint16_t ucode[2];
|
||||
int ret;
|
||||
|
||||
ucode[0] = ch;
|
||||
ucode[1] = '\0';
|
||||
ret = priv->con_out->output_string(priv->con_out, ucode);
|
||||
if (ret)
|
||||
return -EIO;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int serial_efi_pending(struct udevice *dev, bool input)
|
||||
{
|
||||
struct serial_efi_priv *priv = dev_get_priv(dev);
|
||||
int ret;
|
||||
|
||||
/* We assume that EFI will stall if its output buffer fills up */
|
||||
if (!input)
|
||||
return 0;
|
||||
|
||||
ret = serial_efi_get_key(priv);
|
||||
if (ret == -EAGAIN)
|
||||
return 0;
|
||||
else if (ret)
|
||||
return ret;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* There is nothing to init here since the EFI console is already running by
|
||||
* the time we enter U-Boot.
|
||||
*/
|
||||
static inline void _debug_uart_init(void)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void _debug_uart_putc(int ch)
|
||||
{
|
||||
struct efi_system_table *sys_table = efi_get_sys_table();
|
||||
uint16_t ucode[2];
|
||||
|
||||
ucode[0] = ch;
|
||||
ucode[1] = '\0';
|
||||
sys_table->con_out->output_string(sys_table->con_out, ucode);
|
||||
}
|
||||
|
||||
DEBUG_UART_FUNCS
|
||||
|
||||
static int serial_efi_probe(struct udevice *dev)
|
||||
{
|
||||
struct efi_system_table *table = efi_get_sys_table();
|
||||
struct serial_efi_priv *priv = dev_get_priv(dev);
|
||||
|
||||
priv->con_in = table->con_in;
|
||||
priv->con_out = table->con_out;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dm_serial_ops serial_efi_ops = {
|
||||
.putc = serial_efi_putc,
|
||||
.getc = serial_efi_getc,
|
||||
.pending = serial_efi_pending,
|
||||
.setbrg = serial_efi_setbrg,
|
||||
};
|
||||
|
||||
static const struct udevice_id serial_efi_ids[] = {
|
||||
{ .compatible = "efi,uart" },
|
||||
{ }
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(serial_efi) = {
|
||||
.name = "serial_efi",
|
||||
.id = UCLASS_SERIAL,
|
||||
.of_match = serial_efi_ids,
|
||||
.priv_auto_alloc_size = sizeof(struct serial_efi_priv),
|
||||
.probe = serial_efi_probe,
|
||||
.ops = &serial_efi_ops,
|
||||
};
|
||||
@@ -0,0 +1,67 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright (c) 2017 Intel Corporation
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <dm.h>
|
||||
#include <ns16550.h>
|
||||
#include <serial.h>
|
||||
|
||||
/*
|
||||
* The UART clock is calculated as
|
||||
*
|
||||
* UART clock = XTAL * UART_MUL / UART_DIV
|
||||
*
|
||||
* The baudrate is calculated as
|
||||
*
|
||||
* baud rate = UART clock / UART_PS / DLAB
|
||||
*/
|
||||
#define UART_PS 0x30
|
||||
#define UART_MUL 0x34
|
||||
#define UART_DIV 0x38
|
||||
|
||||
static void mid_writel(struct ns16550_platdata *plat, int offset, int value)
|
||||
{
|
||||
unsigned char *addr;
|
||||
|
||||
offset *= 1 << plat->reg_shift;
|
||||
addr = (unsigned char *)plat->base + offset;
|
||||
|
||||
writel(value, addr + plat->reg_offset);
|
||||
}
|
||||
|
||||
static int mid_serial_probe(struct udevice *dev)
|
||||
{
|
||||
struct ns16550_platdata *plat = dev_get_platdata(dev);
|
||||
|
||||
/*
|
||||
* Initialize fractional divider correctly for Intel Edison
|
||||
* platform.
|
||||
*
|
||||
* For backward compatibility we have to set initial DLAB value
|
||||
* to 16 and speed to 115200 baud, where initial frequency is
|
||||
* 29491200Hz, and XTAL frequency is 38.4MHz.
|
||||
*/
|
||||
mid_writel(plat, UART_MUL, 96);
|
||||
mid_writel(plat, UART_DIV, 125);
|
||||
mid_writel(plat, UART_PS, 16);
|
||||
|
||||
return ns16550_serial_probe(dev);
|
||||
}
|
||||
|
||||
static const struct udevice_id mid_serial_ids[] = {
|
||||
{ .compatible = "intel,mid-uart" },
|
||||
{}
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(serial_intel_mid) = {
|
||||
.name = "serial_intel_mid",
|
||||
.id = UCLASS_SERIAL,
|
||||
.of_match = mid_serial_ids,
|
||||
.ofdata_to_platdata = ns16550_serial_ofdata_to_platdata,
|
||||
.platdata_auto_alloc_size = sizeof(struct ns16550_platdata),
|
||||
.priv_auto_alloc_size = sizeof(struct NS16550),
|
||||
.probe = mid_serial_probe,
|
||||
.ops = &ns16550_serial_ops,
|
||||
};
|
||||
@@ -0,0 +1,218 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* (C) Copyright 2013-2016 Freescale Semiconductor, Inc.
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <dm.h>
|
||||
#include <errno.h>
|
||||
#include <watchdog.h>
|
||||
#include <asm/io.h>
|
||||
#include <serial.h>
|
||||
#include <linux/compiler.h>
|
||||
#include <asm/arch/imx-regs.h>
|
||||
#include <asm/arch/clock.h>
|
||||
|
||||
#define US1_TDRE (1 << 7)
|
||||
#define US1_RDRF (1 << 5)
|
||||
#define UC2_TE (1 << 3)
|
||||
#define LINCR1_INIT (1 << 0)
|
||||
#define LINCR1_MME (1 << 4)
|
||||
#define LINCR1_BF (1 << 7)
|
||||
#define LINSR_LINS_INITMODE (0x00001000)
|
||||
#define LINSR_LINS_MASK (0x0000F000)
|
||||
#define UARTCR_UART (1 << 0)
|
||||
#define UARTCR_WL0 (1 << 1)
|
||||
#define UARTCR_PCE (1 << 2)
|
||||
#define UARTCR_PC0 (1 << 3)
|
||||
#define UARTCR_TXEN (1 << 4)
|
||||
#define UARTCR_RXEN (1 << 5)
|
||||
#define UARTCR_PC1 (1 << 6)
|
||||
#define UARTSR_DTF (1 << 1)
|
||||
#define UARTSR_DRF (1 << 2)
|
||||
#define UARTSR_RMB (1 << 9)
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
static void _linflex_serial_setbrg(struct linflex_fsl *base, int baudrate)
|
||||
{
|
||||
u32 clk = mxc_get_clock(MXC_UART_CLK);
|
||||
u32 ibr, fbr;
|
||||
|
||||
if (!baudrate)
|
||||
baudrate = CONFIG_BAUDRATE;
|
||||
|
||||
ibr = (u32) (clk / (16 * gd->baudrate));
|
||||
fbr = (u32) (clk % (16 * gd->baudrate)) * 16;
|
||||
|
||||
__raw_writel(ibr, &base->linibrr);
|
||||
__raw_writel(fbr, &base->linfbrr);
|
||||
}
|
||||
|
||||
static int _linflex_serial_getc(struct linflex_fsl *base)
|
||||
{
|
||||
char c;
|
||||
|
||||
if (!(__raw_readb(&base->uartsr) & UARTSR_DRF))
|
||||
return -EAGAIN;
|
||||
|
||||
if (!(__raw_readl(&base->uartsr) & UARTSR_RMB))
|
||||
return -EAGAIN;
|
||||
|
||||
c = __raw_readl(&base->bdrm);
|
||||
__raw_writeb((__raw_readb(&base->uartsr) | (UARTSR_DRF | UARTSR_RMB)),
|
||||
&base->uartsr);
|
||||
return c;
|
||||
}
|
||||
|
||||
static int _linflex_serial_putc(struct linflex_fsl *base, const char c)
|
||||
{
|
||||
__raw_writeb(c, &base->bdrl);
|
||||
|
||||
|
||||
if (!(__raw_readb(&base->uartsr) & UARTSR_DTF))
|
||||
return -EAGAIN;
|
||||
|
||||
__raw_writeb((__raw_readb(&base->uartsr) | UARTSR_DTF), &base->uartsr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialise the serial port with the given baudrate. The settings
|
||||
* are always 8 data bits, no parity, 1 stop bit, no start bits.
|
||||
*/
|
||||
static int _linflex_serial_init(struct linflex_fsl *base)
|
||||
{
|
||||
volatile u32 ctrl;
|
||||
|
||||
/* set the Linflex in master mode amd activate by-pass filter */
|
||||
ctrl = LINCR1_BF | LINCR1_MME;
|
||||
__raw_writel(ctrl, &base->lincr1);
|
||||
|
||||
/* init mode */
|
||||
ctrl |= LINCR1_INIT;
|
||||
__raw_writel(ctrl, &base->lincr1);
|
||||
|
||||
/* waiting for init mode entry - TODO: add a timeout */
|
||||
while ((__raw_readl(&base->linsr) & LINSR_LINS_MASK) !=
|
||||
LINSR_LINS_INITMODE);
|
||||
|
||||
/* set UART bit to allow writing other bits */
|
||||
__raw_writel(UARTCR_UART, &base->uartcr);
|
||||
|
||||
/* provide data bits, parity, stop bit, etc */
|
||||
serial_setbrg();
|
||||
|
||||
/* 8 bit data, no parity, Tx and Rx enabled, UART mode */
|
||||
__raw_writel(UARTCR_PC1 | UARTCR_RXEN | UARTCR_TXEN | UARTCR_PC0
|
||||
| UARTCR_WL0 | UARTCR_UART, &base->uartcr);
|
||||
|
||||
ctrl = __raw_readl(&base->lincr1);
|
||||
ctrl &= ~LINCR1_INIT;
|
||||
__raw_writel(ctrl, &base->lincr1); /* end init mode */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct linflex_serial_platdata {
|
||||
struct linflex_fsl *base_addr;
|
||||
u8 port_id; /* do we need this? */
|
||||
};
|
||||
|
||||
struct linflex_serial_priv {
|
||||
struct linflex_fsl *lfuart;
|
||||
};
|
||||
|
||||
int linflex_serial_setbrg(struct udevice *dev, int baudrate)
|
||||
{
|
||||
struct linflex_serial_priv *priv = dev_get_priv(dev);
|
||||
|
||||
_linflex_serial_setbrg(priv->lfuart, baudrate);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int linflex_serial_getc(struct udevice *dev)
|
||||
{
|
||||
struct linflex_serial_priv *priv = dev_get_priv(dev);
|
||||
|
||||
return _linflex_serial_getc(priv->lfuart);
|
||||
}
|
||||
|
||||
static int linflex_serial_putc(struct udevice *dev, const char ch)
|
||||
{
|
||||
|
||||
struct linflex_serial_priv *priv = dev_get_priv(dev);
|
||||
|
||||
return _linflex_serial_putc(priv->lfuart, ch);
|
||||
}
|
||||
|
||||
static int linflex_serial_pending(struct udevice *dev, bool input)
|
||||
{
|
||||
struct linflex_serial_priv *priv = dev_get_priv(dev);
|
||||
uint32_t uartsr = __raw_readl(&priv->lfuart->uartsr);
|
||||
|
||||
if (input)
|
||||
return ((uartsr & UARTSR_DRF) && (uartsr & UARTSR_RMB)) ? 1 : 0;
|
||||
else
|
||||
return uartsr & UARTSR_DTF ? 0 : 1;
|
||||
}
|
||||
|
||||
static void linflex_serial_init_internal(struct linflex_fsl *lfuart)
|
||||
{
|
||||
_linflex_serial_init(lfuart);
|
||||
_linflex_serial_setbrg(lfuart, CONFIG_BAUDRATE);
|
||||
return;
|
||||
}
|
||||
|
||||
static int linflex_serial_probe(struct udevice *dev)
|
||||
{
|
||||
struct linflex_serial_platdata *plat = dev->platdata;
|
||||
struct linflex_serial_priv *priv = dev_get_priv(dev);
|
||||
|
||||
priv->lfuart = (struct linflex_fsl *)plat->base_addr;
|
||||
linflex_serial_init_internal(priv->lfuart);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dm_serial_ops linflex_serial_ops = {
|
||||
.putc = linflex_serial_putc,
|
||||
.pending = linflex_serial_pending,
|
||||
.getc = linflex_serial_getc,
|
||||
.setbrg = linflex_serial_setbrg,
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(serial_linflex) = {
|
||||
.name = "serial_linflex",
|
||||
.id = UCLASS_SERIAL,
|
||||
.probe = linflex_serial_probe,
|
||||
.ops = &linflex_serial_ops,
|
||||
.flags = DM_FLAG_PRE_RELOC,
|
||||
.priv_auto_alloc_size = sizeof(struct linflex_serial_priv),
|
||||
};
|
||||
|
||||
#ifdef CONFIG_DEBUG_UART_LINFLEXUART
|
||||
|
||||
#include <debug_uart.h>
|
||||
|
||||
|
||||
static inline void _debug_uart_init(void)
|
||||
{
|
||||
struct linflex_fsl *base = (struct linflex_fsl *)CONFIG_DEBUG_UART_BASE;
|
||||
|
||||
linflex_serial_init_internal(base);
|
||||
}
|
||||
|
||||
static inline void _debug_uart_putc(int ch)
|
||||
{
|
||||
struct linflex_fsl *base = (struct linflex_fsl *)CONFIG_DEBUG_UART_BASE;
|
||||
|
||||
/* XXX: Is this OK? Should this use the non-DM version? */
|
||||
_linflex_serial_putc(base, ch);
|
||||
}
|
||||
|
||||
DEBUG_UART_FUNCS
|
||||
|
||||
#endif /* CONFIG_DEBUG_UART_LINFLEXUART */
|
||||
@@ -0,0 +1,547 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright 2019 NXP
|
||||
* Copyright 2013 Freescale Semiconductor, Inc.
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <clk.h>
|
||||
#include <dm.h>
|
||||
#include <fsl_lpuart.h>
|
||||
#include <watchdog.h>
|
||||
#include <asm/io.h>
|
||||
#include <serial.h>
|
||||
#include <linux/compiler.h>
|
||||
#include <asm/arch/imx-regs.h>
|
||||
#include <asm/arch/clock.h>
|
||||
|
||||
#define US1_TDRE (1 << 7)
|
||||
#define US1_RDRF (1 << 5)
|
||||
#define US1_OR (1 << 3)
|
||||
#define UC2_TE (1 << 3)
|
||||
#define UC2_RE (1 << 2)
|
||||
#define CFIFO_TXFLUSH (1 << 7)
|
||||
#define CFIFO_RXFLUSH (1 << 6)
|
||||
#define SFIFO_RXOF (1 << 2)
|
||||
#define SFIFO_RXUF (1 << 0)
|
||||
|
||||
#define STAT_LBKDIF (1 << 31)
|
||||
#define STAT_RXEDGIF (1 << 30)
|
||||
#define STAT_TDRE (1 << 23)
|
||||
#define STAT_RDRF (1 << 21)
|
||||
#define STAT_IDLE (1 << 20)
|
||||
#define STAT_OR (1 << 19)
|
||||
#define STAT_NF (1 << 18)
|
||||
#define STAT_FE (1 << 17)
|
||||
#define STAT_PF (1 << 16)
|
||||
#define STAT_MA1F (1 << 15)
|
||||
#define STAT_MA2F (1 << 14)
|
||||
#define STAT_FLAGS (STAT_LBKDIF | STAT_RXEDGIF | STAT_IDLE | STAT_OR | \
|
||||
STAT_NF | STAT_FE | STAT_PF | STAT_MA1F | STAT_MA2F)
|
||||
|
||||
#define CTRL_TE (1 << 19)
|
||||
#define CTRL_RE (1 << 18)
|
||||
|
||||
#define FIFO_RXFLUSH BIT(14)
|
||||
#define FIFO_TXFLUSH BIT(15)
|
||||
#define FIFO_TXSIZE_MASK 0x70
|
||||
#define FIFO_TXSIZE_OFF 4
|
||||
#define FIFO_RXSIZE_MASK 0x7
|
||||
#define FIFO_RXSIZE_OFF 0
|
||||
#define FIFO_TXFE 0x80
|
||||
#ifdef CONFIG_ARCH_IMX8
|
||||
#define FIFO_RXFE 0x08
|
||||
#else
|
||||
#define FIFO_RXFE 0x40
|
||||
#endif
|
||||
|
||||
#define WATER_TXWATER_OFF 0
|
||||
#define WATER_RXWATER_OFF 16
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
#define LPUART_FLAG_REGMAP_32BIT_REG BIT(0)
|
||||
#define LPUART_FLAG_REGMAP_ENDIAN_BIG BIT(1)
|
||||
|
||||
enum lpuart_devtype {
|
||||
DEV_VF610 = 1,
|
||||
DEV_LS1021A,
|
||||
DEV_MX7ULP,
|
||||
DEV_IMX8
|
||||
};
|
||||
|
||||
struct lpuart_serial_platdata {
|
||||
void *reg;
|
||||
enum lpuart_devtype devtype;
|
||||
ulong flags;
|
||||
};
|
||||
|
||||
static void lpuart_read32(u32 flags, u32 *addr, u32 *val)
|
||||
{
|
||||
if (flags & LPUART_FLAG_REGMAP_32BIT_REG) {
|
||||
if (flags & LPUART_FLAG_REGMAP_ENDIAN_BIG)
|
||||
*(u32 *)val = in_be32(addr);
|
||||
else
|
||||
*(u32 *)val = in_le32(addr);
|
||||
}
|
||||
}
|
||||
|
||||
static void lpuart_write32(u32 flags, u32 *addr, u32 val)
|
||||
{
|
||||
if (flags & LPUART_FLAG_REGMAP_32BIT_REG) {
|
||||
if (flags & LPUART_FLAG_REGMAP_ENDIAN_BIG)
|
||||
out_be32(addr, val);
|
||||
else
|
||||
out_le32(addr, val);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#ifndef CONFIG_SYS_CLK_FREQ
|
||||
#define CONFIG_SYS_CLK_FREQ 0
|
||||
#endif
|
||||
|
||||
u32 __weak get_lpuart_clk(void)
|
||||
{
|
||||
return CONFIG_SYS_CLK_FREQ;
|
||||
}
|
||||
|
||||
#if CONFIG_IS_ENABLED(CLK)
|
||||
static int get_lpuart_clk_rate(struct udevice *dev, u32 *clk)
|
||||
{
|
||||
struct clk per_clk;
|
||||
ulong rate;
|
||||
int ret;
|
||||
|
||||
ret = clk_get_by_name(dev, "per", &per_clk);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to get per clk: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
rate = clk_get_rate(&per_clk);
|
||||
if ((long)rate <= 0) {
|
||||
dev_err(dev, "Failed to get per clk rate: %ld\n", (long)rate);
|
||||
return ret;
|
||||
}
|
||||
*clk = rate;
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
static inline int get_lpuart_clk_rate(struct udevice *dev, u32 *clk)
|
||||
{ return -ENOSYS; }
|
||||
#endif
|
||||
|
||||
static bool is_lpuart32(struct udevice *dev)
|
||||
{
|
||||
struct lpuart_serial_platdata *plat = dev->platdata;
|
||||
|
||||
return plat->flags & LPUART_FLAG_REGMAP_32BIT_REG;
|
||||
}
|
||||
|
||||
static void _lpuart_serial_setbrg(struct udevice *dev,
|
||||
int baudrate)
|
||||
{
|
||||
struct lpuart_serial_platdata *plat = dev_get_platdata(dev);
|
||||
struct lpuart_fsl *base = plat->reg;
|
||||
u32 clk;
|
||||
u16 sbr;
|
||||
int ret;
|
||||
|
||||
if (CONFIG_IS_ENABLED(CLK)) {
|
||||
ret = get_lpuart_clk_rate(dev, &clk);
|
||||
if (ret)
|
||||
return;
|
||||
} else {
|
||||
clk = get_lpuart_clk();
|
||||
}
|
||||
|
||||
sbr = (u16)(clk / (16 * baudrate));
|
||||
|
||||
/* place adjustment later - n/32 BRFA */
|
||||
__raw_writeb(sbr >> 8, &base->ubdh);
|
||||
__raw_writeb(sbr & 0xff, &base->ubdl);
|
||||
}
|
||||
|
||||
static int _lpuart_serial_getc(struct lpuart_serial_platdata *plat)
|
||||
{
|
||||
struct lpuart_fsl *base = plat->reg;
|
||||
while (!(__raw_readb(&base->us1) & (US1_RDRF | US1_OR)))
|
||||
WATCHDOG_RESET();
|
||||
|
||||
barrier();
|
||||
|
||||
return __raw_readb(&base->ud);
|
||||
}
|
||||
|
||||
static void _lpuart_serial_putc(struct lpuart_serial_platdata *plat,
|
||||
const char c)
|
||||
{
|
||||
struct lpuart_fsl *base = plat->reg;
|
||||
|
||||
while (!(__raw_readb(&base->us1) & US1_TDRE))
|
||||
WATCHDOG_RESET();
|
||||
|
||||
__raw_writeb(c, &base->ud);
|
||||
}
|
||||
|
||||
/* Test whether a character is in the RX buffer */
|
||||
static int _lpuart_serial_tstc(struct lpuart_serial_platdata *plat)
|
||||
{
|
||||
struct lpuart_fsl *base = plat->reg;
|
||||
|
||||
if (__raw_readb(&base->urcfifo) == 0)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialise the serial port with the given baudrate. The settings
|
||||
* are always 8 data bits, no parity, 1 stop bit, no start bits.
|
||||
*/
|
||||
static int _lpuart_serial_init(struct udevice *dev)
|
||||
{
|
||||
struct lpuart_serial_platdata *plat = dev_get_platdata(dev);
|
||||
struct lpuart_fsl *base = (struct lpuart_fsl *)plat->reg;
|
||||
u8 ctrl;
|
||||
|
||||
ctrl = __raw_readb(&base->uc2);
|
||||
ctrl &= ~UC2_RE;
|
||||
ctrl &= ~UC2_TE;
|
||||
__raw_writeb(ctrl, &base->uc2);
|
||||
|
||||
__raw_writeb(0, &base->umodem);
|
||||
__raw_writeb(0, &base->uc1);
|
||||
|
||||
/* Disable FIFO and flush buffer */
|
||||
__raw_writeb(0x0, &base->upfifo);
|
||||
__raw_writeb(0x0, &base->utwfifo);
|
||||
__raw_writeb(0x1, &base->urwfifo);
|
||||
__raw_writeb(CFIFO_TXFLUSH | CFIFO_RXFLUSH, &base->ucfifo);
|
||||
|
||||
/* provide data bits, parity, stop bit, etc */
|
||||
_lpuart_serial_setbrg(dev, gd->baudrate);
|
||||
|
||||
__raw_writeb(UC2_RE | UC2_TE, &base->uc2);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void _lpuart32_serial_setbrg_7ulp(struct udevice *dev,
|
||||
int baudrate)
|
||||
{
|
||||
struct lpuart_serial_platdata *plat = dev_get_platdata(dev);
|
||||
struct lpuart_fsl_reg32 *base = plat->reg;
|
||||
u32 sbr, osr, baud_diff, tmp_osr, tmp_sbr, tmp_diff, tmp;
|
||||
u32 clk;
|
||||
int ret;
|
||||
|
||||
if (CONFIG_IS_ENABLED(CLK)) {
|
||||
ret = get_lpuart_clk_rate(dev, &clk);
|
||||
if (ret)
|
||||
return;
|
||||
} else {
|
||||
clk = get_lpuart_clk();
|
||||
}
|
||||
|
||||
baud_diff = baudrate;
|
||||
osr = 0;
|
||||
sbr = 0;
|
||||
|
||||
for (tmp_osr = 4; tmp_osr <= 32; tmp_osr++) {
|
||||
tmp_sbr = (clk / (baudrate * tmp_osr));
|
||||
|
||||
if (tmp_sbr == 0)
|
||||
tmp_sbr = 1;
|
||||
|
||||
/*calculate difference in actual buad w/ current values */
|
||||
tmp_diff = (clk / (tmp_osr * tmp_sbr));
|
||||
tmp_diff = tmp_diff - baudrate;
|
||||
|
||||
/* select best values between sbr and sbr+1 */
|
||||
if (tmp_diff > (baudrate - (clk / (tmp_osr * (tmp_sbr + 1))))) {
|
||||
tmp_diff = baudrate - (clk / (tmp_osr * (tmp_sbr + 1)));
|
||||
tmp_sbr++;
|
||||
}
|
||||
|
||||
if (tmp_diff <= baud_diff) {
|
||||
baud_diff = tmp_diff;
|
||||
osr = tmp_osr;
|
||||
sbr = tmp_sbr;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO: handle buadrate outside acceptable rate
|
||||
* if (baudDiff > ((config->baudRate_Bps / 100) * 3))
|
||||
* {
|
||||
* Unacceptable baud rate difference of more than 3%
|
||||
* return kStatus_LPUART_BaudrateNotSupport;
|
||||
* }
|
||||
*/
|
||||
tmp = in_le32(&base->baud);
|
||||
|
||||
if ((osr > 3) && (osr < 8))
|
||||
tmp |= LPUART_BAUD_BOTHEDGE_MASK;
|
||||
|
||||
tmp &= ~LPUART_BAUD_OSR_MASK;
|
||||
tmp |= LPUART_BAUD_OSR(osr-1);
|
||||
|
||||
tmp &= ~LPUART_BAUD_SBR_MASK;
|
||||
tmp |= LPUART_BAUD_SBR(sbr);
|
||||
|
||||
/* explicitly disable 10 bit mode & set 1 stop bit */
|
||||
tmp &= ~(LPUART_BAUD_M10_MASK | LPUART_BAUD_SBNS_MASK);
|
||||
|
||||
out_le32(&base->baud, tmp);
|
||||
}
|
||||
|
||||
static void _lpuart32_serial_setbrg(struct udevice *dev,
|
||||
int baudrate)
|
||||
{
|
||||
struct lpuart_serial_platdata *plat = dev_get_platdata(dev);
|
||||
struct lpuart_fsl_reg32 *base = plat->reg;
|
||||
u32 clk;
|
||||
u32 sbr;
|
||||
int ret;
|
||||
|
||||
if (CONFIG_IS_ENABLED(CLK)) {
|
||||
ret = get_lpuart_clk_rate(dev, &clk);
|
||||
if (ret)
|
||||
return;
|
||||
} else {
|
||||
clk = get_lpuart_clk();
|
||||
}
|
||||
|
||||
sbr = (clk / (16 * baudrate));
|
||||
|
||||
/* place adjustment later - n/32 BRFA */
|
||||
lpuart_write32(plat->flags, &base->baud, sbr);
|
||||
}
|
||||
|
||||
static int _lpuart32_serial_getc(struct lpuart_serial_platdata *plat)
|
||||
{
|
||||
struct lpuart_fsl_reg32 *base = plat->reg;
|
||||
u32 stat, val;
|
||||
|
||||
lpuart_read32(plat->flags, &base->stat, &stat);
|
||||
while ((stat & STAT_RDRF) == 0) {
|
||||
lpuart_write32(plat->flags, &base->stat, STAT_FLAGS);
|
||||
WATCHDOG_RESET();
|
||||
lpuart_read32(plat->flags, &base->stat, &stat);
|
||||
}
|
||||
|
||||
lpuart_read32(plat->flags, &base->data, &val);
|
||||
|
||||
lpuart_read32(plat->flags, &base->stat, &stat);
|
||||
if (stat & STAT_OR)
|
||||
lpuart_write32(plat->flags, &base->stat, STAT_OR);
|
||||
|
||||
return val & 0x3ff;
|
||||
}
|
||||
|
||||
static void _lpuart32_serial_putc(struct lpuart_serial_platdata *plat,
|
||||
const char c)
|
||||
{
|
||||
struct lpuart_fsl_reg32 *base = plat->reg;
|
||||
u32 stat;
|
||||
|
||||
if (c == '\n')
|
||||
serial_putc('\r');
|
||||
|
||||
while (true) {
|
||||
lpuart_read32(plat->flags, &base->stat, &stat);
|
||||
|
||||
if ((stat & STAT_TDRE))
|
||||
break;
|
||||
|
||||
WATCHDOG_RESET();
|
||||
}
|
||||
|
||||
lpuart_write32(plat->flags, &base->data, c);
|
||||
}
|
||||
|
||||
/* Test whether a character is in the RX buffer */
|
||||
static int _lpuart32_serial_tstc(struct lpuart_serial_platdata *plat)
|
||||
{
|
||||
struct lpuart_fsl_reg32 *base = plat->reg;
|
||||
u32 water;
|
||||
|
||||
lpuart_read32(plat->flags, &base->water, &water);
|
||||
|
||||
if ((water >> 24) == 0)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialise the serial port with the given baudrate. The settings
|
||||
* are always 8 data bits, no parity, 1 stop bit, no start bits.
|
||||
*/
|
||||
static int _lpuart32_serial_init(struct udevice *dev)
|
||||
{
|
||||
struct lpuart_serial_platdata *plat = dev_get_platdata(dev);
|
||||
struct lpuart_fsl_reg32 *base = (struct lpuart_fsl_reg32 *)plat->reg;
|
||||
u32 val, tx_fifo_size;
|
||||
|
||||
lpuart_read32(plat->flags, &base->ctrl, &val);
|
||||
val &= ~CTRL_RE;
|
||||
val &= ~CTRL_TE;
|
||||
lpuart_write32(plat->flags, &base->ctrl, val);
|
||||
|
||||
lpuart_write32(plat->flags, &base->modir, 0);
|
||||
|
||||
lpuart_read32(plat->flags, &base->fifo, &val);
|
||||
tx_fifo_size = (val & FIFO_TXSIZE_MASK) >> FIFO_TXSIZE_OFF;
|
||||
/* Set the TX water to half of FIFO size */
|
||||
if (tx_fifo_size > 1)
|
||||
tx_fifo_size = tx_fifo_size >> 1;
|
||||
|
||||
/* Set RX water to 0, to be triggered by any receive data */
|
||||
lpuart_write32(plat->flags, &base->water,
|
||||
(tx_fifo_size << WATER_TXWATER_OFF));
|
||||
|
||||
/* Enable TX and RX FIFO */
|
||||
val |= (FIFO_TXFE | FIFO_RXFE | FIFO_TXFLUSH | FIFO_RXFLUSH);
|
||||
lpuart_write32(plat->flags, &base->fifo, val);
|
||||
|
||||
lpuart_write32(plat->flags, &base->match, 0);
|
||||
|
||||
if (plat->devtype == DEV_MX7ULP || plat->devtype == DEV_IMX8) {
|
||||
_lpuart32_serial_setbrg_7ulp(dev, gd->baudrate);
|
||||
} else {
|
||||
/* provide data bits, parity, stop bit, etc */
|
||||
_lpuart32_serial_setbrg(dev, gd->baudrate);
|
||||
}
|
||||
|
||||
lpuart_write32(plat->flags, &base->ctrl, CTRL_RE | CTRL_TE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lpuart_serial_setbrg(struct udevice *dev, int baudrate)
|
||||
{
|
||||
struct lpuart_serial_platdata *plat = dev_get_platdata(dev);
|
||||
|
||||
if (is_lpuart32(dev)) {
|
||||
if (plat->devtype == DEV_MX7ULP || plat->devtype == DEV_IMX8)
|
||||
_lpuart32_serial_setbrg_7ulp(dev, baudrate);
|
||||
else
|
||||
_lpuart32_serial_setbrg(dev, baudrate);
|
||||
} else {
|
||||
_lpuart_serial_setbrg(dev, baudrate);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lpuart_serial_getc(struct udevice *dev)
|
||||
{
|
||||
struct lpuart_serial_platdata *plat = dev->platdata;
|
||||
|
||||
if (is_lpuart32(dev))
|
||||
return _lpuart32_serial_getc(plat);
|
||||
|
||||
return _lpuart_serial_getc(plat);
|
||||
}
|
||||
|
||||
static int lpuart_serial_putc(struct udevice *dev, const char c)
|
||||
{
|
||||
struct lpuart_serial_platdata *plat = dev->platdata;
|
||||
|
||||
if (is_lpuart32(dev))
|
||||
_lpuart32_serial_putc(plat, c);
|
||||
else
|
||||
_lpuart_serial_putc(plat, c);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lpuart_serial_pending(struct udevice *dev, bool input)
|
||||
{
|
||||
struct lpuart_serial_platdata *plat = dev->platdata;
|
||||
struct lpuart_fsl *reg = plat->reg;
|
||||
struct lpuart_fsl_reg32 *reg32 = plat->reg;
|
||||
u32 stat;
|
||||
|
||||
if (is_lpuart32(dev)) {
|
||||
if (input) {
|
||||
return _lpuart32_serial_tstc(plat);
|
||||
} else {
|
||||
lpuart_read32(plat->flags, ®32->stat, &stat);
|
||||
return stat & STAT_TDRE ? 0 : 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (input)
|
||||
return _lpuart_serial_tstc(plat);
|
||||
else
|
||||
return __raw_readb(®->us1) & US1_TDRE ? 0 : 1;
|
||||
}
|
||||
|
||||
static int lpuart_serial_probe(struct udevice *dev)
|
||||
{
|
||||
if (is_lpuart32(dev))
|
||||
return _lpuart32_serial_init(dev);
|
||||
else
|
||||
return _lpuart_serial_init(dev);
|
||||
}
|
||||
|
||||
static int lpuart_serial_ofdata_to_platdata(struct udevice *dev)
|
||||
{
|
||||
struct lpuart_serial_platdata *plat = dev->platdata;
|
||||
const void *blob = gd->fdt_blob;
|
||||
int node = dev_of_offset(dev);
|
||||
fdt_addr_t addr;
|
||||
|
||||
addr = devfdt_get_addr(dev);
|
||||
if (addr == FDT_ADDR_T_NONE)
|
||||
return -EINVAL;
|
||||
|
||||
plat->reg = (void *)addr;
|
||||
plat->flags = dev_get_driver_data(dev);
|
||||
|
||||
if (fdtdec_get_bool(blob, node, "little-endian"))
|
||||
plat->flags &= ~LPUART_FLAG_REGMAP_ENDIAN_BIG;
|
||||
|
||||
if (!fdt_node_check_compatible(blob, node, "fsl,ls1021a-lpuart"))
|
||||
plat->devtype = DEV_LS1021A;
|
||||
else if (!fdt_node_check_compatible(blob, node, "fsl,imx7ulp-lpuart"))
|
||||
plat->devtype = DEV_MX7ULP;
|
||||
else if (!fdt_node_check_compatible(blob, node, "fsl,vf610-lpuart"))
|
||||
plat->devtype = DEV_VF610;
|
||||
else if (!fdt_node_check_compatible(blob, node, "fsl,imx8qm-lpuart"))
|
||||
plat->devtype = DEV_IMX8;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dm_serial_ops lpuart_serial_ops = {
|
||||
.putc = lpuart_serial_putc,
|
||||
.pending = lpuart_serial_pending,
|
||||
.getc = lpuart_serial_getc,
|
||||
.setbrg = lpuart_serial_setbrg,
|
||||
};
|
||||
|
||||
static const struct udevice_id lpuart_serial_ids[] = {
|
||||
{ .compatible = "fsl,ls1021a-lpuart", .data =
|
||||
LPUART_FLAG_REGMAP_32BIT_REG | LPUART_FLAG_REGMAP_ENDIAN_BIG },
|
||||
{ .compatible = "fsl,imx7ulp-lpuart",
|
||||
.data = LPUART_FLAG_REGMAP_32BIT_REG },
|
||||
{ .compatible = "fsl,vf610-lpuart"},
|
||||
{ .compatible = "fsl,imx8qm-lpuart",
|
||||
.data = LPUART_FLAG_REGMAP_32BIT_REG },
|
||||
{ }
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(serial_lpuart) = {
|
||||
.name = "serial_lpuart",
|
||||
.id = UCLASS_SERIAL,
|
||||
.of_match = lpuart_serial_ids,
|
||||
.ofdata_to_platdata = lpuart_serial_ofdata_to_platdata,
|
||||
.platdata_auto_alloc_size = sizeof(struct lpuart_serial_platdata),
|
||||
.probe = lpuart_serial_probe,
|
||||
.ops = &lpuart_serial_ops,
|
||||
};
|
||||
@@ -0,0 +1,159 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* (C) Copyright 2016 Beniamino Galvani <b.galvani@gmail.com>
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <dm.h>
|
||||
#include <errno.h>
|
||||
#include <fdtdec.h>
|
||||
#include <linux/compiler.h>
|
||||
#include <serial.h>
|
||||
|
||||
struct meson_uart {
|
||||
u32 wfifo;
|
||||
u32 rfifo;
|
||||
u32 control;
|
||||
u32 status;
|
||||
u32 misc;
|
||||
};
|
||||
|
||||
struct meson_serial_platdata {
|
||||
struct meson_uart *reg;
|
||||
};
|
||||
|
||||
/* AML_UART_STATUS bits */
|
||||
#define AML_UART_PARITY_ERR BIT(16)
|
||||
#define AML_UART_FRAME_ERR BIT(17)
|
||||
#define AML_UART_TX_FIFO_WERR BIT(18)
|
||||
#define AML_UART_RX_EMPTY BIT(20)
|
||||
#define AML_UART_TX_FULL BIT(21)
|
||||
#define AML_UART_TX_EMPTY BIT(22)
|
||||
#define AML_UART_XMIT_BUSY BIT(25)
|
||||
#define AML_UART_ERR (AML_UART_PARITY_ERR | \
|
||||
AML_UART_FRAME_ERR | \
|
||||
AML_UART_TX_FIFO_WERR)
|
||||
|
||||
/* AML_UART_CONTROL bits */
|
||||
#define AML_UART_TX_EN BIT(12)
|
||||
#define AML_UART_RX_EN BIT(13)
|
||||
#define AML_UART_TX_RST BIT(22)
|
||||
#define AML_UART_RX_RST BIT(23)
|
||||
#define AML_UART_CLR_ERR BIT(24)
|
||||
|
||||
static void meson_serial_init(struct meson_uart *uart)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
val = readl(&uart->control);
|
||||
val |= (AML_UART_RX_RST | AML_UART_TX_RST | AML_UART_CLR_ERR);
|
||||
writel(val, &uart->control);
|
||||
val &= ~(AML_UART_RX_RST | AML_UART_TX_RST | AML_UART_CLR_ERR);
|
||||
writel(val, &uart->control);
|
||||
val |= (AML_UART_RX_EN | AML_UART_TX_EN);
|
||||
writel(val, &uart->control);
|
||||
}
|
||||
|
||||
static int meson_serial_probe(struct udevice *dev)
|
||||
{
|
||||
struct meson_serial_platdata *plat = dev->platdata;
|
||||
struct meson_uart *const uart = plat->reg;
|
||||
|
||||
meson_serial_init(uart);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int meson_serial_getc(struct udevice *dev)
|
||||
{
|
||||
struct meson_serial_platdata *plat = dev->platdata;
|
||||
struct meson_uart *const uart = plat->reg;
|
||||
|
||||
if (readl(&uart->status) & AML_UART_RX_EMPTY)
|
||||
return -EAGAIN;
|
||||
|
||||
return readl(&uart->rfifo) & 0xff;
|
||||
}
|
||||
|
||||
static int meson_serial_putc(struct udevice *dev, const char ch)
|
||||
{
|
||||
struct meson_serial_platdata *plat = dev->platdata;
|
||||
struct meson_uart *const uart = plat->reg;
|
||||
|
||||
if (readl(&uart->status) & AML_UART_TX_FULL)
|
||||
return -EAGAIN;
|
||||
|
||||
writel(ch, &uart->wfifo);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int meson_serial_pending(struct udevice *dev, bool input)
|
||||
{
|
||||
struct meson_serial_platdata *plat = dev->platdata;
|
||||
struct meson_uart *const uart = plat->reg;
|
||||
uint32_t status = readl(&uart->status);
|
||||
|
||||
if (input)
|
||||
return !(status & AML_UART_RX_EMPTY);
|
||||
else
|
||||
return !(status & AML_UART_TX_FULL);
|
||||
}
|
||||
|
||||
static int meson_serial_ofdata_to_platdata(struct udevice *dev)
|
||||
{
|
||||
struct meson_serial_platdata *plat = dev->platdata;
|
||||
fdt_addr_t addr;
|
||||
|
||||
addr = devfdt_get_addr(dev);
|
||||
if (addr == FDT_ADDR_T_NONE)
|
||||
return -EINVAL;
|
||||
|
||||
plat->reg = (struct meson_uart *)addr;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dm_serial_ops meson_serial_ops = {
|
||||
.putc = meson_serial_putc,
|
||||
.pending = meson_serial_pending,
|
||||
.getc = meson_serial_getc,
|
||||
};
|
||||
|
||||
static const struct udevice_id meson_serial_ids[] = {
|
||||
{ .compatible = "amlogic,meson-uart" },
|
||||
{ .compatible = "amlogic,meson-gx-uart" },
|
||||
{ }
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(serial_meson) = {
|
||||
.name = "serial_meson",
|
||||
.id = UCLASS_SERIAL,
|
||||
.of_match = meson_serial_ids,
|
||||
.probe = meson_serial_probe,
|
||||
.ops = &meson_serial_ops,
|
||||
.ofdata_to_platdata = meson_serial_ofdata_to_platdata,
|
||||
.platdata_auto_alloc_size = sizeof(struct meson_serial_platdata),
|
||||
};
|
||||
|
||||
#ifdef CONFIG_DEBUG_UART_MESON
|
||||
|
||||
#include <debug_uart.h>
|
||||
|
||||
static inline void _debug_uart_init(void)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void _debug_uart_putc(int ch)
|
||||
{
|
||||
struct meson_uart *regs = (struct meson_uart *)CONFIG_DEBUG_UART_BASE;
|
||||
|
||||
while (readl(®s->status) & AML_UART_TX_FULL)
|
||||
;
|
||||
|
||||
writel(ch, ®s->wfifo);
|
||||
}
|
||||
|
||||
DEBUG_UART_FUNCS
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,257 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* (C) Copyright 2000
|
||||
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <command.h>
|
||||
#include <dm.h>
|
||||
#include <serial.h>
|
||||
#include <watchdog.h>
|
||||
#include <asm/cpm_8xx.h>
|
||||
#include <linux/compiler.h>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
#if defined(CONFIG_8xx_CONS_SMC1) /* Console on SMC1 */
|
||||
#define SMC_INDEX 0
|
||||
#define PROFF_SMC PROFF_SMC1
|
||||
#define CPM_CR_CH_SMC CPM_CR_CH_SMC1
|
||||
#define IOPINS 0xc0
|
||||
|
||||
#elif defined(CONFIG_8xx_CONS_SMC2) /* Console on SMC2 */
|
||||
#define SMC_INDEX 1
|
||||
#define PROFF_SMC PROFF_SMC2
|
||||
#define CPM_CR_CH_SMC CPM_CR_CH_SMC2
|
||||
#define IOPINS 0xc00
|
||||
|
||||
#endif /* CONFIG_8xx_CONS_SMCx */
|
||||
|
||||
struct serialbuffer {
|
||||
cbd_t rxbd; /* Rx BD */
|
||||
cbd_t txbd; /* Tx BD */
|
||||
uint rxindex; /* index for next character to read */
|
||||
uchar rxbuf[CONFIG_SYS_SMC_RXBUFLEN];/* rx buffers */
|
||||
uchar txbuf; /* tx buffers */
|
||||
};
|
||||
|
||||
static void serial_setdivisor(cpm8xx_t __iomem *cp, int baudrate)
|
||||
{
|
||||
int divisor = (gd->cpu_clk + 8 * baudrate) / 16 / baudrate;
|
||||
|
||||
if (divisor / 16 > 0x1000) {
|
||||
/* bad divisor, assume 50MHz clock and 9600 baud */
|
||||
divisor = (50 * 1000 * 1000 + 8 * 9600) / 16 / 9600;
|
||||
}
|
||||
|
||||
divisor /= CONFIG_SYS_BRGCLK_PRESCALE;
|
||||
|
||||
if (divisor <= 0x1000)
|
||||
out_be32(&cp->cp_brgc1, ((divisor - 1) << 1) | CPM_BRG_EN);
|
||||
else
|
||||
out_be32(&cp->cp_brgc1, ((divisor / 16 - 1) << 1) | CPM_BRG_EN |
|
||||
CPM_BRG_DIV16);
|
||||
}
|
||||
|
||||
/*
|
||||
* Minimal serial functions needed to use one of the SMC ports
|
||||
* as serial console interface.
|
||||
*/
|
||||
|
||||
static int serial_mpc8xx_setbrg(struct udevice *dev, int baudrate)
|
||||
{
|
||||
immap_t __iomem *im = (immap_t __iomem *)CONFIG_SYS_IMMR;
|
||||
cpm8xx_t __iomem *cp = &(im->im_cpm);
|
||||
|
||||
/* Set up the baud rate generator.
|
||||
* See 8xx_io/commproc.c for details.
|
||||
*
|
||||
* Wire BRG1 to SMCx
|
||||
*/
|
||||
|
||||
out_be32(&cp->cp_simode, 0);
|
||||
|
||||
serial_setdivisor(cp, baudrate);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int serial_mpc8xx_probe(struct udevice *dev)
|
||||
{
|
||||
immap_t __iomem *im = (immap_t __iomem *)CONFIG_SYS_IMMR;
|
||||
smc_t __iomem *sp;
|
||||
smc_uart_t __iomem *up;
|
||||
cpm8xx_t __iomem *cp = &(im->im_cpm);
|
||||
struct serialbuffer __iomem *rtx;
|
||||
|
||||
/* initialize pointers to SMC */
|
||||
|
||||
sp = cp->cp_smc + SMC_INDEX;
|
||||
up = (smc_uart_t __iomem *)&cp->cp_dparam[PROFF_SMC];
|
||||
/* Disable relocation */
|
||||
out_be16(&up->smc_rpbase, 0);
|
||||
|
||||
/* Disable transmitter/receiver. */
|
||||
clrbits_be16(&sp->smc_smcmr, SMCMR_REN | SMCMR_TEN);
|
||||
|
||||
/* Enable SDMA. */
|
||||
out_be32(&im->im_siu_conf.sc_sdcr, 1);
|
||||
|
||||
/* clear error conditions */
|
||||
out_8(&im->im_sdma.sdma_sdsr, CONFIG_SYS_SDSR);
|
||||
|
||||
/* clear SDMA interrupt mask */
|
||||
out_8(&im->im_sdma.sdma_sdmr, CONFIG_SYS_SDMR);
|
||||
|
||||
/* Use Port B for SMCx instead of other functions. */
|
||||
setbits_be32(&cp->cp_pbpar, IOPINS);
|
||||
clrbits_be32(&cp->cp_pbdir, IOPINS);
|
||||
clrbits_be16(&cp->cp_pbodr, IOPINS);
|
||||
|
||||
/* Set the physical address of the host memory buffers in
|
||||
* the buffer descriptors.
|
||||
*/
|
||||
rtx = (struct serialbuffer __iomem *)&cp->cp_dpmem[CPM_SERIAL_BASE];
|
||||
/* Allocate space for two buffer descriptors in the DP ram.
|
||||
* For now, this address seems OK, but it may have to
|
||||
* change with newer versions of the firmware.
|
||||
* damm: allocating space after the two buffers for rx/tx data
|
||||
*/
|
||||
|
||||
out_be32(&rtx->rxbd.cbd_bufaddr, (__force uint)&rtx->rxbuf);
|
||||
out_be16(&rtx->rxbd.cbd_sc, 0);
|
||||
|
||||
out_be32(&rtx->txbd.cbd_bufaddr, (__force uint)&rtx->txbuf);
|
||||
out_be16(&rtx->txbd.cbd_sc, 0);
|
||||
|
||||
/* Set up the uart parameters in the parameter ram. */
|
||||
out_be16(&up->smc_rbase, CPM_SERIAL_BASE);
|
||||
out_be16(&up->smc_tbase, CPM_SERIAL_BASE + sizeof(cbd_t));
|
||||
out_8(&up->smc_rfcr, SMC_EB);
|
||||
out_8(&up->smc_tfcr, SMC_EB);
|
||||
|
||||
/* Set UART mode, 8 bit, no parity, one stop.
|
||||
* Enable receive and transmit.
|
||||
*/
|
||||
out_be16(&sp->smc_smcmr, smcr_mk_clen(9) | SMCMR_SM_UART);
|
||||
|
||||
/* Mask all interrupts and remove anything pending.
|
||||
*/
|
||||
out_8(&sp->smc_smcm, 0);
|
||||
out_8(&sp->smc_smce, 0xff);
|
||||
|
||||
/* Set up the baud rate generator */
|
||||
serial_mpc8xx_setbrg(dev, gd->baudrate);
|
||||
|
||||
/* Make the first buffer the only buffer. */
|
||||
setbits_be16(&rtx->txbd.cbd_sc, BD_SC_WRAP);
|
||||
setbits_be16(&rtx->rxbd.cbd_sc, BD_SC_EMPTY | BD_SC_WRAP);
|
||||
|
||||
/* single/multi character receive. */
|
||||
out_be16(&up->smc_mrblr, CONFIG_SYS_SMC_RXBUFLEN);
|
||||
out_be16(&up->smc_maxidl, CONFIG_SYS_MAXIDLE);
|
||||
out_be32(&rtx->rxindex, 0);
|
||||
|
||||
/* Initialize Tx/Rx parameters. */
|
||||
while (in_be16(&cp->cp_cpcr) & CPM_CR_FLG) /* wait if cp is busy */
|
||||
;
|
||||
|
||||
out_be16(&cp->cp_cpcr,
|
||||
mk_cr_cmd(CPM_CR_CH_SMC, CPM_CR_INIT_TRX) | CPM_CR_FLG);
|
||||
|
||||
while (in_be16(&cp->cp_cpcr) & CPM_CR_FLG) /* wait if cp is busy */
|
||||
;
|
||||
|
||||
/* Enable transmitter/receiver. */
|
||||
setbits_be16(&sp->smc_smcmr, SMCMR_REN | SMCMR_TEN);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int serial_mpc8xx_putc(struct udevice *dev, const char c)
|
||||
{
|
||||
immap_t __iomem *im = (immap_t __iomem *)CONFIG_SYS_IMMR;
|
||||
cpm8xx_t __iomem *cpmp = &(im->im_cpm);
|
||||
struct serialbuffer __iomem *rtx;
|
||||
|
||||
if (c == '\n')
|
||||
serial_mpc8xx_putc(dev, '\r');
|
||||
|
||||
rtx = (struct serialbuffer __iomem *)&cpmp->cp_dpmem[CPM_SERIAL_BASE];
|
||||
|
||||
/* Wait for last character to go. */
|
||||
out_8(&rtx->txbuf, c);
|
||||
out_be16(&rtx->txbd.cbd_datlen, 1);
|
||||
setbits_be16(&rtx->txbd.cbd_sc, BD_SC_READY);
|
||||
|
||||
while (in_be16(&rtx->txbd.cbd_sc) & BD_SC_READY)
|
||||
WATCHDOG_RESET();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int serial_mpc8xx_getc(struct udevice *dev)
|
||||
{
|
||||
immap_t __iomem *im = (immap_t __iomem *)CONFIG_SYS_IMMR;
|
||||
cpm8xx_t __iomem *cpmp = &(im->im_cpm);
|
||||
struct serialbuffer __iomem *rtx;
|
||||
unsigned char c;
|
||||
uint rxindex;
|
||||
|
||||
rtx = (struct serialbuffer __iomem *)&cpmp->cp_dpmem[CPM_SERIAL_BASE];
|
||||
|
||||
/* Wait for character to show up. */
|
||||
while (in_be16(&rtx->rxbd.cbd_sc) & BD_SC_EMPTY)
|
||||
WATCHDOG_RESET();
|
||||
|
||||
/* the characters are read one by one,
|
||||
* use the rxindex to know the next char to deliver
|
||||
*/
|
||||
rxindex = in_be32(&rtx->rxindex);
|
||||
c = in_8(rtx->rxbuf + rxindex);
|
||||
rxindex++;
|
||||
|
||||
/* check if all char are readout, then make prepare for next receive */
|
||||
if (rxindex >= in_be16(&rtx->rxbd.cbd_datlen)) {
|
||||
rxindex = 0;
|
||||
setbits_be16(&rtx->rxbd.cbd_sc, BD_SC_EMPTY);
|
||||
}
|
||||
out_be32(&rtx->rxindex, rxindex);
|
||||
return c;
|
||||
}
|
||||
|
||||
static int serial_mpc8xx_pending(struct udevice *dev, bool input)
|
||||
{
|
||||
immap_t __iomem *im = (immap_t __iomem *)CONFIG_SYS_IMMR;
|
||||
cpm8xx_t __iomem *cpmp = &(im->im_cpm);
|
||||
struct serialbuffer __iomem *rtx;
|
||||
|
||||
if (!input)
|
||||
return 0;
|
||||
|
||||
rtx = (struct serialbuffer __iomem *)&cpmp->cp_dpmem[CPM_SERIAL_BASE];
|
||||
|
||||
return !(in_be16(&rtx->rxbd.cbd_sc) & BD_SC_EMPTY);
|
||||
}
|
||||
|
||||
static const struct dm_serial_ops serial_mpc8xx_ops = {
|
||||
.putc = serial_mpc8xx_putc,
|
||||
.pending = serial_mpc8xx_pending,
|
||||
.getc = serial_mpc8xx_getc,
|
||||
.setbrg = serial_mpc8xx_setbrg,
|
||||
};
|
||||
|
||||
static const struct udevice_id serial_mpc8xx_ids[] = {
|
||||
{ .compatible = "fsl,pq1-smc" },
|
||||
{ }
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(serial_mpc8xx) = {
|
||||
.name = "serial_mpc8xx",
|
||||
.id = UCLASS_SERIAL,
|
||||
.of_match = serial_mpc8xx_ids,
|
||||
.probe = serial_mpc8xx_probe,
|
||||
.ops = &serial_mpc8xx_ops,
|
||||
.flags = DM_FLAG_PRE_RELOC,
|
||||
};
|
||||
@@ -0,0 +1,241 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Qualcomm UART driver
|
||||
*
|
||||
* (C) Copyright 2015 Mateusz Kulikowski <mateusz.kulikowski@gmail.com>
|
||||
*
|
||||
* UART will work in Data Mover mode.
|
||||
* Based on Linux driver.
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <clk.h>
|
||||
#include <dm.h>
|
||||
#include <errno.h>
|
||||
#include <serial.h>
|
||||
#include <watchdog.h>
|
||||
#include <asm/io.h>
|
||||
#include <linux/compiler.h>
|
||||
#include <dm/pinctrl.h>
|
||||
|
||||
/* Serial registers - this driver works in uartdm mode*/
|
||||
|
||||
#define UARTDM_DMRX 0x34 /* Max RX transfer length */
|
||||
#define UARTDM_NCF_TX 0x40 /* Number of chars to TX */
|
||||
|
||||
#define UARTDM_RXFS 0x50 /* RX channel status register */
|
||||
#define UARTDM_RXFS_BUF_SHIFT 0x7 /* Number of bytes in the packing buffer */
|
||||
#define UARTDM_RXFS_BUF_MASK 0x7
|
||||
#define UARTDM_MR1 0x00
|
||||
#define UARTDM_MR2 0x04
|
||||
#define UARTDM_CSR 0xA0
|
||||
|
||||
#define UARTDM_SR 0xA4 /* Status register */
|
||||
#define UARTDM_SR_RX_READY (1 << 0) /* Word is the receiver FIFO */
|
||||
#define UARTDM_SR_TX_EMPTY (1 << 3) /* Transmitter underrun */
|
||||
#define UARTDM_SR_UART_OVERRUN (1 << 4) /* Receive overrun */
|
||||
|
||||
#define UARTDM_CR 0xA8 /* Command register */
|
||||
#define UARTDM_CR_CMD_RESET_ERR (3 << 4) /* Clear overrun error */
|
||||
#define UARTDM_CR_CMD_RESET_STALE_INT (8 << 4) /* Clears stale irq */
|
||||
#define UARTDM_CR_CMD_RESET_TX_READY (3 << 8) /* Clears TX Ready irq*/
|
||||
#define UARTDM_CR_CMD_FORCE_STALE (4 << 8) /* Causes stale event */
|
||||
#define UARTDM_CR_CMD_STALE_EVENT_DISABLE (6 << 8) /* Disable stale event */
|
||||
|
||||
#define UARTDM_IMR 0xB0 /* Interrupt mask register */
|
||||
#define UARTDM_ISR 0xB4 /* Interrupt status register */
|
||||
#define UARTDM_ISR_TX_READY 0x80 /* TX FIFO empty */
|
||||
|
||||
#define UARTDM_TF 0x100 /* UART Transmit FIFO register */
|
||||
#define UARTDM_RF 0x140 /* UART Receive FIFO register */
|
||||
|
||||
#define UART_DM_CLK_RX_TX_BIT_RATE 0xCC
|
||||
#define MSM_BOOT_UART_DM_8_N_1_MODE 0x34
|
||||
#define MSM_BOOT_UART_DM_CMD_RESET_RX 0x10
|
||||
#define MSM_BOOT_UART_DM_CMD_RESET_TX 0x20
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
struct msm_serial_data {
|
||||
phys_addr_t base;
|
||||
unsigned chars_cnt; /* number of buffered chars */
|
||||
uint32_t chars_buf; /* buffered chars */
|
||||
};
|
||||
|
||||
static int msm_serial_fetch(struct udevice *dev)
|
||||
{
|
||||
struct msm_serial_data *priv = dev_get_priv(dev);
|
||||
unsigned sr;
|
||||
|
||||
if (priv->chars_cnt)
|
||||
return priv->chars_cnt;
|
||||
|
||||
/* Clear error in case of buffer overrun */
|
||||
if (readl(priv->base + UARTDM_SR) & UARTDM_SR_UART_OVERRUN)
|
||||
writel(UARTDM_CR_CMD_RESET_ERR, priv->base + UARTDM_CR);
|
||||
|
||||
/* We need to fetch new character */
|
||||
sr = readl(priv->base + UARTDM_SR);
|
||||
|
||||
if (sr & UARTDM_SR_RX_READY) {
|
||||
/* There are at least 4 bytes in fifo */
|
||||
priv->chars_buf = readl(priv->base + UARTDM_RF);
|
||||
priv->chars_cnt = 4;
|
||||
} else {
|
||||
/* Check if there is anything in fifo */
|
||||
priv->chars_cnt = readl(priv->base + UARTDM_RXFS);
|
||||
/* Extract number of characters in UART packing buffer*/
|
||||
priv->chars_cnt = (priv->chars_cnt >>
|
||||
UARTDM_RXFS_BUF_SHIFT) &
|
||||
UARTDM_RXFS_BUF_MASK;
|
||||
if (!priv->chars_cnt)
|
||||
return 0;
|
||||
|
||||
/* There is at least one charcter, move it to fifo */
|
||||
writel(UARTDM_CR_CMD_FORCE_STALE,
|
||||
priv->base + UARTDM_CR);
|
||||
|
||||
priv->chars_buf = readl(priv->base + UARTDM_RF);
|
||||
writel(UARTDM_CR_CMD_RESET_STALE_INT,
|
||||
priv->base + UARTDM_CR);
|
||||
writel(0x7, priv->base + UARTDM_DMRX);
|
||||
}
|
||||
|
||||
return priv->chars_cnt;
|
||||
}
|
||||
|
||||
static int msm_serial_getc(struct udevice *dev)
|
||||
{
|
||||
struct msm_serial_data *priv = dev_get_priv(dev);
|
||||
char c;
|
||||
|
||||
if (!msm_serial_fetch(dev))
|
||||
return -EAGAIN;
|
||||
|
||||
c = priv->chars_buf & 0xFF;
|
||||
priv->chars_buf >>= 8;
|
||||
priv->chars_cnt--;
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
static int msm_serial_putc(struct udevice *dev, const char ch)
|
||||
{
|
||||
struct msm_serial_data *priv = dev_get_priv(dev);
|
||||
|
||||
if (!(readl(priv->base + UARTDM_SR) & UARTDM_SR_TX_EMPTY) &&
|
||||
!(readl(priv->base + UARTDM_ISR) & UARTDM_ISR_TX_READY))
|
||||
return -EAGAIN;
|
||||
|
||||
writel(UARTDM_CR_CMD_RESET_TX_READY, priv->base + UARTDM_CR);
|
||||
|
||||
writel(1, priv->base + UARTDM_NCF_TX);
|
||||
writel(ch, priv->base + UARTDM_TF);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int msm_serial_pending(struct udevice *dev, bool input)
|
||||
{
|
||||
if (input) {
|
||||
if (msm_serial_fetch(dev))
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dm_serial_ops msm_serial_ops = {
|
||||
.putc = msm_serial_putc,
|
||||
.pending = msm_serial_pending,
|
||||
.getc = msm_serial_getc,
|
||||
};
|
||||
|
||||
static int msm_uart_clk_init(struct udevice *dev)
|
||||
{
|
||||
uint clk_rate = fdtdec_get_uint(gd->fdt_blob, dev_of_offset(dev),
|
||||
"clock-frequency", 115200);
|
||||
uint clkd[2]; /* clk_id and clk_no */
|
||||
int clk_offset;
|
||||
struct udevice *clk_dev;
|
||||
struct clk clk;
|
||||
int ret;
|
||||
|
||||
ret = fdtdec_get_int_array(gd->fdt_blob, dev_of_offset(dev), "clock",
|
||||
clkd, 2);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
clk_offset = fdt_node_offset_by_phandle(gd->fdt_blob, clkd[0]);
|
||||
if (clk_offset < 0)
|
||||
return clk_offset;
|
||||
|
||||
ret = uclass_get_device_by_of_offset(UCLASS_CLK, clk_offset, &clk_dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
clk.id = clkd[1];
|
||||
ret = clk_request(clk_dev, &clk);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = clk_set_rate(&clk, clk_rate);
|
||||
clk_free(&clk);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void uart_dm_init(struct msm_serial_data *priv)
|
||||
{
|
||||
writel(UART_DM_CLK_RX_TX_BIT_RATE, priv->base + UARTDM_CSR);
|
||||
writel(0x0, priv->base + UARTDM_MR1);
|
||||
writel(MSM_BOOT_UART_DM_8_N_1_MODE, priv->base + UARTDM_MR2);
|
||||
writel(MSM_BOOT_UART_DM_CMD_RESET_RX, priv->base + UARTDM_CR);
|
||||
writel(MSM_BOOT_UART_DM_CMD_RESET_TX, priv->base + UARTDM_CR);
|
||||
}
|
||||
static int msm_serial_probe(struct udevice *dev)
|
||||
{
|
||||
int ret;
|
||||
struct msm_serial_data *priv = dev_get_priv(dev);
|
||||
|
||||
/* No need to reinitialize the UART after relocation */
|
||||
if (gd->flags & GD_FLG_RELOC)
|
||||
return 0;
|
||||
|
||||
ret = msm_uart_clk_init(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
pinctrl_select_state(dev, "uart");
|
||||
uart_dm_init(priv);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int msm_serial_ofdata_to_platdata(struct udevice *dev)
|
||||
{
|
||||
struct msm_serial_data *priv = dev_get_priv(dev);
|
||||
|
||||
priv->base = devfdt_get_addr(dev);
|
||||
if (priv->base == FDT_ADDR_T_NONE)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct udevice_id msm_serial_ids[] = {
|
||||
{ .compatible = "qcom,msm-uartdm-v1.4" },
|
||||
{ }
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(serial_msm) = {
|
||||
.name = "serial_msm",
|
||||
.id = UCLASS_SERIAL,
|
||||
.of_match = msm_serial_ids,
|
||||
.ofdata_to_platdata = msm_serial_ofdata_to_platdata,
|
||||
.priv_auto_alloc_size = sizeof(struct msm_serial_data),
|
||||
.probe = msm_serial_probe,
|
||||
.ops = &msm_serial_ops,
|
||||
};
|
||||
@@ -0,0 +1,457 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* MediaTek High-speed UART driver
|
||||
*
|
||||
* Copyright (C) 2018 MediaTek Inc.
|
||||
* Author: Weijie Gao <weijie.gao@mediatek.com>
|
||||
*/
|
||||
|
||||
#include <clk.h>
|
||||
#include <common.h>
|
||||
#include <div64.h>
|
||||
#include <dm.h>
|
||||
#include <errno.h>
|
||||
#include <serial.h>
|
||||
#include <watchdog.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/types.h>
|
||||
|
||||
struct mtk_serial_regs {
|
||||
u32 rbr;
|
||||
u32 ier;
|
||||
u32 fcr;
|
||||
u32 lcr;
|
||||
u32 mcr;
|
||||
u32 lsr;
|
||||
u32 msr;
|
||||
u32 spr;
|
||||
u32 mdr1;
|
||||
u32 highspeed;
|
||||
u32 sample_count;
|
||||
u32 sample_point;
|
||||
u32 fracdiv_l;
|
||||
u32 fracdiv_m;
|
||||
u32 escape_en;
|
||||
u32 guard;
|
||||
u32 rx_sel;
|
||||
};
|
||||
|
||||
#define thr rbr
|
||||
#define iir fcr
|
||||
#define dll rbr
|
||||
#define dlm ier
|
||||
|
||||
#define UART_LCR_WLS_8 0x03 /* 8 bit character length */
|
||||
#define UART_LCR_DLAB 0x80 /* Divisor latch access bit */
|
||||
|
||||
#define UART_LSR_DR 0x01 /* Data ready */
|
||||
#define UART_LSR_THRE 0x20 /* Xmit holding register empty */
|
||||
#define UART_LSR_TEMT 0x40 /* Xmitter empty */
|
||||
|
||||
#define UART_MCR_DTR 0x01 /* DTR */
|
||||
#define UART_MCR_RTS 0x02 /* RTS */
|
||||
|
||||
#define UART_FCR_FIFO_EN 0x01 /* Fifo enable */
|
||||
#define UART_FCR_RXSR 0x02 /* Receiver soft reset */
|
||||
#define UART_FCR_TXSR 0x04 /* Transmitter soft reset */
|
||||
|
||||
#define UART_MCRVAL (UART_MCR_DTR | \
|
||||
UART_MCR_RTS)
|
||||
|
||||
/* Clear & enable FIFOs */
|
||||
#define UART_FCRVAL (UART_FCR_FIFO_EN | \
|
||||
UART_FCR_RXSR | \
|
||||
UART_FCR_TXSR)
|
||||
|
||||
/* the data is correct if the real baud is within 3%. */
|
||||
#define BAUD_ALLOW_MAX(baud) ((baud) + (baud) * 3 / 100)
|
||||
#define BAUD_ALLOW_MIX(baud) ((baud) - (baud) * 3 / 100)
|
||||
|
||||
struct mtk_serial_priv {
|
||||
struct mtk_serial_regs __iomem *regs;
|
||||
u32 clock;
|
||||
};
|
||||
|
||||
static void _mtk_serial_setbrg(struct mtk_serial_priv *priv, int baud)
|
||||
{
|
||||
bool support_clk12m_baud115200;
|
||||
u32 quot, samplecount, realbaud;
|
||||
|
||||
if ((baud <= 115200) && (priv->clock == 12000000))
|
||||
support_clk12m_baud115200 = true;
|
||||
else
|
||||
support_clk12m_baud115200 = false;
|
||||
|
||||
if (baud <= 115200) {
|
||||
writel(0, &priv->regs->highspeed);
|
||||
quot = DIV_ROUND_CLOSEST(priv->clock, 16 * baud);
|
||||
|
||||
if (support_clk12m_baud115200) {
|
||||
writel(3, &priv->regs->highspeed);
|
||||
quot = DIV_ROUND_CLOSEST(priv->clock, 256 * baud);
|
||||
if (quot == 0)
|
||||
quot = 1;
|
||||
|
||||
samplecount = DIV_ROUND_CLOSEST(priv->clock,
|
||||
quot * baud);
|
||||
if (samplecount != 0) {
|
||||
realbaud = priv->clock / samplecount / quot;
|
||||
if ((realbaud > BAUD_ALLOW_MAX(baud)) ||
|
||||
(realbaud < BAUD_ALLOW_MIX(baud))) {
|
||||
pr_info("baud %d can't be handled\n",
|
||||
baud);
|
||||
}
|
||||
} else {
|
||||
pr_info("samplecount is 0\n");
|
||||
}
|
||||
}
|
||||
} else if (baud <= 576000) {
|
||||
writel(2, &priv->regs->highspeed);
|
||||
|
||||
/* Set to next lower baudrate supported */
|
||||
if ((baud == 500000) || (baud == 576000))
|
||||
baud = 460800;
|
||||
quot = DIV_ROUND_UP(priv->clock, 4 * baud);
|
||||
} else {
|
||||
writel(3, &priv->regs->highspeed);
|
||||
quot = DIV_ROUND_UP(priv->clock, 256 * baud);
|
||||
}
|
||||
|
||||
/* set divisor */
|
||||
writel(UART_LCR_WLS_8 | UART_LCR_DLAB, &priv->regs->lcr);
|
||||
writel(quot & 0xff, &priv->regs->dll);
|
||||
writel((quot >> 8) & 0xff, &priv->regs->dlm);
|
||||
writel(UART_LCR_WLS_8, &priv->regs->lcr);
|
||||
|
||||
if (baud > 460800) {
|
||||
u32 tmp;
|
||||
|
||||
tmp = DIV_ROUND_CLOSEST(priv->clock, quot * baud);
|
||||
writel(tmp - 1, &priv->regs->sample_count);
|
||||
writel((tmp - 2) >> 1, &priv->regs->sample_point);
|
||||
} else {
|
||||
writel(0, &priv->regs->sample_count);
|
||||
writel(0xff, &priv->regs->sample_point);
|
||||
}
|
||||
|
||||
if (support_clk12m_baud115200) {
|
||||
writel(samplecount - 1, &priv->regs->sample_count);
|
||||
writel((samplecount - 2) >> 1, &priv->regs->sample_point);
|
||||
}
|
||||
}
|
||||
|
||||
static int _mtk_serial_putc(struct mtk_serial_priv *priv, const char ch)
|
||||
{
|
||||
if (!(readl(&priv->regs->lsr) & UART_LSR_THRE))
|
||||
return -EAGAIN;
|
||||
|
||||
writel(ch, &priv->regs->thr);
|
||||
|
||||
if (ch == '\n')
|
||||
WATCHDOG_RESET();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _mtk_serial_getc(struct mtk_serial_priv *priv)
|
||||
{
|
||||
if (!(readl(&priv->regs->lsr) & UART_LSR_DR))
|
||||
return -EAGAIN;
|
||||
|
||||
return readl(&priv->regs->rbr);
|
||||
}
|
||||
|
||||
static int _mtk_serial_pending(struct mtk_serial_priv *priv, bool input)
|
||||
{
|
||||
if (input)
|
||||
return (readl(&priv->regs->lsr) & UART_LSR_DR) ? 1 : 0;
|
||||
else
|
||||
return (readl(&priv->regs->lsr) & UART_LSR_THRE) ? 0 : 1;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_DM_SERIAL) && \
|
||||
(!defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_DM))
|
||||
static int mtk_serial_setbrg(struct udevice *dev, int baudrate)
|
||||
{
|
||||
struct mtk_serial_priv *priv = dev_get_priv(dev);
|
||||
|
||||
_mtk_serial_setbrg(priv, baudrate);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mtk_serial_putc(struct udevice *dev, const char ch)
|
||||
{
|
||||
struct mtk_serial_priv *priv = dev_get_priv(dev);
|
||||
|
||||
return _mtk_serial_putc(priv, ch);
|
||||
}
|
||||
|
||||
static int mtk_serial_getc(struct udevice *dev)
|
||||
{
|
||||
struct mtk_serial_priv *priv = dev_get_priv(dev);
|
||||
|
||||
return _mtk_serial_getc(priv);
|
||||
}
|
||||
|
||||
static int mtk_serial_pending(struct udevice *dev, bool input)
|
||||
{
|
||||
struct mtk_serial_priv *priv = dev_get_priv(dev);
|
||||
|
||||
return _mtk_serial_pending(priv, input);
|
||||
}
|
||||
|
||||
static int mtk_serial_probe(struct udevice *dev)
|
||||
{
|
||||
struct mtk_serial_priv *priv = dev_get_priv(dev);
|
||||
|
||||
/* Disable interrupt */
|
||||
writel(0, &priv->regs->ier);
|
||||
|
||||
writel(UART_MCRVAL, &priv->regs->mcr);
|
||||
writel(UART_FCRVAL, &priv->regs->fcr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mtk_serial_ofdata_to_platdata(struct udevice *dev)
|
||||
{
|
||||
struct mtk_serial_priv *priv = dev_get_priv(dev);
|
||||
fdt_addr_t addr;
|
||||
struct clk clk;
|
||||
int err;
|
||||
|
||||
addr = dev_read_addr(dev);
|
||||
if (addr == FDT_ADDR_T_NONE)
|
||||
return -EINVAL;
|
||||
|
||||
priv->regs = map_physmem(addr, 0, MAP_NOCACHE);
|
||||
|
||||
err = clk_get_by_index(dev, 0, &clk);
|
||||
if (!err) {
|
||||
err = clk_get_rate(&clk);
|
||||
if (!IS_ERR_VALUE(err))
|
||||
priv->clock = err;
|
||||
} else if (err != -ENOENT && err != -ENODEV && err != -ENOSYS) {
|
||||
debug("mtk_serial: failed to get clock\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
if (!priv->clock)
|
||||
priv->clock = dev_read_u32_default(dev, "clock-frequency", 0);
|
||||
|
||||
if (!priv->clock) {
|
||||
debug("mtk_serial: clock not defined\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dm_serial_ops mtk_serial_ops = {
|
||||
.putc = mtk_serial_putc,
|
||||
.pending = mtk_serial_pending,
|
||||
.getc = mtk_serial_getc,
|
||||
.setbrg = mtk_serial_setbrg,
|
||||
};
|
||||
|
||||
static const struct udevice_id mtk_serial_ids[] = {
|
||||
{ .compatible = "mediatek,hsuart" },
|
||||
{ .compatible = "mediatek,mt6577-uart" },
|
||||
{ }
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(serial_mtk) = {
|
||||
.name = "serial_mtk",
|
||||
.id = UCLASS_SERIAL,
|
||||
.of_match = mtk_serial_ids,
|
||||
.ofdata_to_platdata = mtk_serial_ofdata_to_platdata,
|
||||
.priv_auto_alloc_size = sizeof(struct mtk_serial_priv),
|
||||
.probe = mtk_serial_probe,
|
||||
.ops = &mtk_serial_ops,
|
||||
.flags = DM_FLAG_PRE_RELOC,
|
||||
};
|
||||
#else
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
#define DECLARE_HSUART_PRIV(port) \
|
||||
static struct mtk_serial_priv mtk_hsuart##port = { \
|
||||
.regs = (struct mtk_serial_regs *)CONFIG_SYS_NS16550_COM##port, \
|
||||
.clock = CONFIG_SYS_NS16550_CLK \
|
||||
};
|
||||
|
||||
#define DECLARE_HSUART_FUNCTIONS(port) \
|
||||
static int mtk_serial##port##_init(void) \
|
||||
{ \
|
||||
writel(0, &mtk_hsuart##port.regs->ier); \
|
||||
writel(UART_MCRVAL, &mtk_hsuart##port.regs->mcr); \
|
||||
writel(UART_FCRVAL, &mtk_hsuart##port.regs->fcr); \
|
||||
_mtk_serial_setbrg(&mtk_hsuart##port, gd->baudrate); \
|
||||
return 0 ; \
|
||||
} \
|
||||
static void mtk_serial##port##_setbrg(void) \
|
||||
{ \
|
||||
_mtk_serial_setbrg(&mtk_hsuart##port, gd->baudrate); \
|
||||
} \
|
||||
static int mtk_serial##port##_getc(void) \
|
||||
{ \
|
||||
int err; \
|
||||
do { \
|
||||
err = _mtk_serial_getc(&mtk_hsuart##port); \
|
||||
if (err == -EAGAIN) \
|
||||
WATCHDOG_RESET(); \
|
||||
} while (err == -EAGAIN); \
|
||||
return err >= 0 ? err : 0; \
|
||||
} \
|
||||
static int mtk_serial##port##_tstc(void) \
|
||||
{ \
|
||||
return _mtk_serial_pending(&mtk_hsuart##port, true); \
|
||||
} \
|
||||
static void mtk_serial##port##_putc(const char c) \
|
||||
{ \
|
||||
int err; \
|
||||
if (c == '\n') \
|
||||
mtk_serial##port##_putc('\r'); \
|
||||
do { \
|
||||
err = _mtk_serial_putc(&mtk_hsuart##port, c); \
|
||||
} while (err == -EAGAIN); \
|
||||
} \
|
||||
static void mtk_serial##port##_puts(const char *s) \
|
||||
{ \
|
||||
while (*s) { \
|
||||
mtk_serial##port##_putc(*s++); \
|
||||
} \
|
||||
}
|
||||
|
||||
/* Serial device descriptor */
|
||||
#define INIT_HSUART_STRUCTURE(port, __name) { \
|
||||
.name = __name, \
|
||||
.start = mtk_serial##port##_init, \
|
||||
.stop = NULL, \
|
||||
.setbrg = mtk_serial##port##_setbrg, \
|
||||
.getc = mtk_serial##port##_getc, \
|
||||
.tstc = mtk_serial##port##_tstc, \
|
||||
.putc = mtk_serial##port##_putc, \
|
||||
.puts = mtk_serial##port##_puts, \
|
||||
}
|
||||
|
||||
#define DECLARE_HSUART(port, __name) \
|
||||
DECLARE_HSUART_PRIV(port); \
|
||||
DECLARE_HSUART_FUNCTIONS(port); \
|
||||
struct serial_device mtk_hsuart##port##_device = \
|
||||
INIT_HSUART_STRUCTURE(port, __name);
|
||||
|
||||
#if !defined(CONFIG_CONS_INDEX)
|
||||
#elif (CONFIG_CONS_INDEX < 1) || (CONFIG_CONS_INDEX > 6)
|
||||
#error "Invalid console index value."
|
||||
#endif
|
||||
|
||||
#if CONFIG_CONS_INDEX == 1 && !defined(CONFIG_SYS_NS16550_COM1)
|
||||
#error "Console port 1 defined but not configured."
|
||||
#elif CONFIG_CONS_INDEX == 2 && !defined(CONFIG_SYS_NS16550_COM2)
|
||||
#error "Console port 2 defined but not configured."
|
||||
#elif CONFIG_CONS_INDEX == 3 && !defined(CONFIG_SYS_NS16550_COM3)
|
||||
#error "Console port 3 defined but not configured."
|
||||
#elif CONFIG_CONS_INDEX == 4 && !defined(CONFIG_SYS_NS16550_COM4)
|
||||
#error "Console port 4 defined but not configured."
|
||||
#elif CONFIG_CONS_INDEX == 5 && !defined(CONFIG_SYS_NS16550_COM5)
|
||||
#error "Console port 5 defined but not configured."
|
||||
#elif CONFIG_CONS_INDEX == 6 && !defined(CONFIG_SYS_NS16550_COM6)
|
||||
#error "Console port 6 defined but not configured."
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SYS_NS16550_COM1)
|
||||
DECLARE_HSUART(1, "mtk-hsuart0");
|
||||
#endif
|
||||
#if defined(CONFIG_SYS_NS16550_COM2)
|
||||
DECLARE_HSUART(2, "mtk-hsuart1");
|
||||
#endif
|
||||
#if defined(CONFIG_SYS_NS16550_COM3)
|
||||
DECLARE_HSUART(3, "mtk-hsuart2");
|
||||
#endif
|
||||
#if defined(CONFIG_SYS_NS16550_COM4)
|
||||
DECLARE_HSUART(4, "mtk-hsuart3");
|
||||
#endif
|
||||
#if defined(CONFIG_SYS_NS16550_COM5)
|
||||
DECLARE_HSUART(5, "mtk-hsuart4");
|
||||
#endif
|
||||
#if defined(CONFIG_SYS_NS16550_COM6)
|
||||
DECLARE_HSUART(6, "mtk-hsuart5");
|
||||
#endif
|
||||
|
||||
__weak struct serial_device *default_serial_console(void)
|
||||
{
|
||||
#if CONFIG_CONS_INDEX == 1
|
||||
return &mtk_hsuart1_device;
|
||||
#elif CONFIG_CONS_INDEX == 2
|
||||
return &mtk_hsuart2_device;
|
||||
#elif CONFIG_CONS_INDEX == 3
|
||||
return &mtk_hsuart3_device;
|
||||
#elif CONFIG_CONS_INDEX == 4
|
||||
return &mtk_hsuart4_device;
|
||||
#elif CONFIG_CONS_INDEX == 5
|
||||
return &mtk_hsuart5_device;
|
||||
#elif CONFIG_CONS_INDEX == 6
|
||||
return &mtk_hsuart6_device;
|
||||
#else
|
||||
#error "Bad CONFIG_CONS_INDEX."
|
||||
#endif
|
||||
}
|
||||
|
||||
void mtk_serial_initialize(void)
|
||||
{
|
||||
#if defined(CONFIG_SYS_NS16550_COM1)
|
||||
serial_register(&mtk_hsuart1_device);
|
||||
#endif
|
||||
#if defined(CONFIG_SYS_NS16550_COM2)
|
||||
serial_register(&mtk_hsuart2_device);
|
||||
#endif
|
||||
#if defined(CONFIG_SYS_NS16550_COM3)
|
||||
serial_register(&mtk_hsuart3_device);
|
||||
#endif
|
||||
#if defined(CONFIG_SYS_NS16550_COM4)
|
||||
serial_register(&mtk_hsuart4_device);
|
||||
#endif
|
||||
#if defined(CONFIG_SYS_NS16550_COM5)
|
||||
serial_register(&mtk_hsuart5_device);
|
||||
#endif
|
||||
#if defined(CONFIG_SYS_NS16550_COM6)
|
||||
serial_register(&mtk_hsuart6_device);
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_DEBUG_UART_MTK
|
||||
|
||||
#include <debug_uart.h>
|
||||
|
||||
static inline void _debug_uart_init(void)
|
||||
{
|
||||
struct mtk_serial_priv priv;
|
||||
|
||||
priv.regs = (void *) CONFIG_DEBUG_UART_BASE;
|
||||
priv.clock = CONFIG_DEBUG_UART_CLOCK;
|
||||
|
||||
writel(0, &priv.regs->ier);
|
||||
writel(UART_MCRVAL, &priv.regs->mcr);
|
||||
writel(UART_FCRVAL, &priv.regs->fcr);
|
||||
|
||||
_mtk_serial_setbrg(&priv, CONFIG_BAUDRATE);
|
||||
}
|
||||
|
||||
static inline void _debug_uart_putc(int ch)
|
||||
{
|
||||
struct mtk_serial_regs __iomem *regs =
|
||||
(void *) CONFIG_DEBUG_UART_BASE;
|
||||
|
||||
while (!(readl(®s->lsr) & UART_LSR_THRE))
|
||||
;
|
||||
|
||||
writel(ch, ®s->thr);
|
||||
}
|
||||
|
||||
DEBUG_UART_FUNCS
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,173 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright (C) 2016 Stefan Roese <sr@denx.de>
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <dm.h>
|
||||
#include <serial.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
struct mvebu_platdata {
|
||||
void __iomem *base;
|
||||
};
|
||||
|
||||
/*
|
||||
* Register offset
|
||||
*/
|
||||
#define UART_RX_REG 0x00
|
||||
#define UART_TX_REG 0x04
|
||||
#define UART_CTRL_REG 0x08
|
||||
#define UART_STATUS_REG 0x0c
|
||||
#define UART_BAUD_REG 0x10
|
||||
#define UART_POSSR_REG 0x14
|
||||
|
||||
#define UART_STATUS_RX_RDY 0x10
|
||||
#define UART_STATUS_TXFIFO_FULL 0x800
|
||||
|
||||
#define UART_CTRL_RXFIFO_RESET 0x4000
|
||||
#define UART_CTRL_TXFIFO_RESET 0x8000
|
||||
|
||||
#define CONFIG_UART_BASE_CLOCK 25804800
|
||||
|
||||
static int mvebu_serial_putc(struct udevice *dev, const char ch)
|
||||
{
|
||||
struct mvebu_platdata *plat = dev_get_platdata(dev);
|
||||
void __iomem *base = plat->base;
|
||||
|
||||
while (readl(base + UART_STATUS_REG) & UART_STATUS_TXFIFO_FULL)
|
||||
;
|
||||
|
||||
writel(ch, base + UART_TX_REG);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mvebu_serial_getc(struct udevice *dev)
|
||||
{
|
||||
struct mvebu_platdata *plat = dev_get_platdata(dev);
|
||||
void __iomem *base = plat->base;
|
||||
|
||||
while (!(readl(base + UART_STATUS_REG) & UART_STATUS_RX_RDY))
|
||||
;
|
||||
|
||||
return readl(base + UART_RX_REG) & 0xff;
|
||||
}
|
||||
|
||||
static int mvebu_serial_pending(struct udevice *dev, bool input)
|
||||
{
|
||||
struct mvebu_platdata *plat = dev_get_platdata(dev);
|
||||
void __iomem *base = plat->base;
|
||||
|
||||
if (readl(base + UART_STATUS_REG) & UART_STATUS_RX_RDY)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mvebu_serial_setbrg(struct udevice *dev, int baudrate)
|
||||
{
|
||||
struct mvebu_platdata *plat = dev_get_platdata(dev);
|
||||
void __iomem *base = plat->base;
|
||||
|
||||
/*
|
||||
* Calculate divider
|
||||
* baudrate = clock / 16 / divider
|
||||
*/
|
||||
writel(CONFIG_UART_BASE_CLOCK / baudrate / 16, base + UART_BAUD_REG);
|
||||
|
||||
/*
|
||||
* Set Programmable Oversampling Stack to 0,
|
||||
* UART defaults to 16x scheme
|
||||
*/
|
||||
writel(0, base + UART_POSSR_REG);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mvebu_serial_probe(struct udevice *dev)
|
||||
{
|
||||
struct mvebu_platdata *plat = dev_get_platdata(dev);
|
||||
void __iomem *base = plat->base;
|
||||
|
||||
/* reset FIFOs */
|
||||
writel(UART_CTRL_RXFIFO_RESET | UART_CTRL_TXFIFO_RESET,
|
||||
base + UART_CTRL_REG);
|
||||
|
||||
/* No Parity, 1 Stop */
|
||||
writel(0, base + UART_CTRL_REG);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mvebu_serial_ofdata_to_platdata(struct udevice *dev)
|
||||
{
|
||||
struct mvebu_platdata *plat = dev_get_platdata(dev);
|
||||
|
||||
plat->base = devfdt_get_addr_ptr(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dm_serial_ops mvebu_serial_ops = {
|
||||
.putc = mvebu_serial_putc,
|
||||
.pending = mvebu_serial_pending,
|
||||
.getc = mvebu_serial_getc,
|
||||
.setbrg = mvebu_serial_setbrg,
|
||||
};
|
||||
|
||||
static const struct udevice_id mvebu_serial_ids[] = {
|
||||
{ .compatible = "marvell,armada-3700-uart" },
|
||||
{ }
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(serial_mvebu) = {
|
||||
.name = "serial_mvebu",
|
||||
.id = UCLASS_SERIAL,
|
||||
.of_match = mvebu_serial_ids,
|
||||
.ofdata_to_platdata = mvebu_serial_ofdata_to_platdata,
|
||||
.platdata_auto_alloc_size = sizeof(struct mvebu_platdata),
|
||||
.probe = mvebu_serial_probe,
|
||||
.ops = &mvebu_serial_ops,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_DEBUG_MVEBU_A3700_UART
|
||||
|
||||
#include <debug_uart.h>
|
||||
|
||||
static inline void _debug_uart_init(void)
|
||||
{
|
||||
void __iomem *base = (void __iomem *)CONFIG_DEBUG_UART_BASE;
|
||||
|
||||
/* reset FIFOs */
|
||||
writel(UART_CTRL_RXFIFO_RESET | UART_CTRL_TXFIFO_RESET,
|
||||
base + UART_CTRL_REG);
|
||||
|
||||
/* No Parity, 1 Stop */
|
||||
writel(0, base + UART_CTRL_REG);
|
||||
|
||||
/*
|
||||
* Calculate divider
|
||||
* baudrate = clock / 16 / divider
|
||||
*/
|
||||
writel(CONFIG_UART_BASE_CLOCK / 115200 / 16, base + UART_BAUD_REG);
|
||||
|
||||
/*
|
||||
* Set Programmable Oversampling Stack to 0,
|
||||
* UART defaults to 16x scheme
|
||||
*/
|
||||
writel(0, base + UART_POSSR_REG);
|
||||
}
|
||||
|
||||
static inline void _debug_uart_putc(int ch)
|
||||
{
|
||||
void __iomem *base = (void __iomem *)CONFIG_DEBUG_UART_BASE;
|
||||
|
||||
while (readl(base + UART_STATUS_REG) & UART_STATUS_TXFIFO_FULL)
|
||||
;
|
||||
|
||||
writel(ch, base + UART_TX_REG);
|
||||
}
|
||||
|
||||
DEBUG_UART_FUNCS
|
||||
#endif
|
||||
@@ -0,0 +1,393 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* (c) 2007 Sascha Hauer <s.hauer@pengutronix.de>
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <dm.h>
|
||||
#include <errno.h>
|
||||
#include <watchdog.h>
|
||||
#include <asm/arch/imx-regs.h>
|
||||
#include <asm/arch/clock.h>
|
||||
#include <dm/platform_data/serial_mxc.h>
|
||||
#include <serial.h>
|
||||
#include <linux/compiler.h>
|
||||
|
||||
/* UART Control Register Bit Fields.*/
|
||||
#define URXD_CHARRDY (1<<15)
|
||||
#define URXD_ERR (1<<14)
|
||||
#define URXD_OVRRUN (1<<13)
|
||||
#define URXD_FRMERR (1<<12)
|
||||
#define URXD_BRK (1<<11)
|
||||
#define URXD_PRERR (1<<10)
|
||||
#define URXD_RX_DATA (0xFF)
|
||||
#define UCR1_ADEN (1<<15) /* Auto dectect interrupt */
|
||||
#define UCR1_ADBR (1<<14) /* Auto detect baud rate */
|
||||
#define UCR1_TRDYEN (1<<13) /* Transmitter ready interrupt enable */
|
||||
#define UCR1_IDEN (1<<12) /* Idle condition interrupt */
|
||||
#define UCR1_RRDYEN (1<<9) /* Recv ready interrupt enable */
|
||||
#define UCR1_RDMAEN (1<<8) /* Recv ready DMA enable */
|
||||
#define UCR1_IREN (1<<7) /* Infrared interface enable */
|
||||
#define UCR1_TXMPTYEN (1<<6) /* Transimitter empty interrupt enable */
|
||||
#define UCR1_RTSDEN (1<<5) /* RTS delta interrupt enable */
|
||||
#define UCR1_SNDBRK (1<<4) /* Send break */
|
||||
#define UCR1_TDMAEN (1<<3) /* Transmitter ready DMA enable */
|
||||
#define UCR1_UARTCLKEN (1<<2) /* UART clock enabled */
|
||||
#define UCR1_DOZE (1<<1) /* Doze */
|
||||
#define UCR1_UARTEN (1<<0) /* UART enabled */
|
||||
#define UCR2_ESCI (1<<15) /* Escape seq interrupt enable */
|
||||
#define UCR2_IRTS (1<<14) /* Ignore RTS pin */
|
||||
#define UCR2_CTSC (1<<13) /* CTS pin control */
|
||||
#define UCR2_CTS (1<<12) /* Clear to send */
|
||||
#define UCR2_ESCEN (1<<11) /* Escape enable */
|
||||
#define UCR2_PREN (1<<8) /* Parity enable */
|
||||
#define UCR2_PROE (1<<7) /* Parity odd/even */
|
||||
#define UCR2_STPB (1<<6) /* Stop */
|
||||
#define UCR2_WS (1<<5) /* Word size */
|
||||
#define UCR2_RTSEN (1<<4) /* Request to send interrupt enable */
|
||||
#define UCR2_TXEN (1<<2) /* Transmitter enabled */
|
||||
#define UCR2_RXEN (1<<1) /* Receiver enabled */
|
||||
#define UCR2_SRST (1<<0) /* SW reset */
|
||||
#define UCR3_DTREN (1<<13) /* DTR interrupt enable */
|
||||
#define UCR3_PARERREN (1<<12) /* Parity enable */
|
||||
#define UCR3_FRAERREN (1<<11) /* Frame error interrupt enable */
|
||||
#define UCR3_DSR (1<<10) /* Data set ready */
|
||||
#define UCR3_DCD (1<<9) /* Data carrier detect */
|
||||
#define UCR3_RI (1<<8) /* Ring indicator */
|
||||
#define UCR3_ADNIMP (1<<7) /* Autobaud Detection Not Improved */
|
||||
#define UCR3_RXDSEN (1<<6) /* Receive status interrupt enable */
|
||||
#define UCR3_AIRINTEN (1<<5) /* Async IR wake interrupt enable */
|
||||
#define UCR3_AWAKEN (1<<4) /* Async wake interrupt enable */
|
||||
#define UCR3_REF25 (1<<3) /* Ref freq 25 MHz */
|
||||
#define UCR3_REF30 (1<<2) /* Ref Freq 30 MHz */
|
||||
#define UCR3_INVT (1<<1) /* Inverted Infrared transmission */
|
||||
#define UCR3_BPEN (1<<0) /* Preset registers enable */
|
||||
#define UCR4_CTSTL_32 (32<<10) /* CTS trigger level (32 chars) */
|
||||
#define UCR4_INVR (1<<9) /* Inverted infrared reception */
|
||||
#define UCR4_ENIRI (1<<8) /* Serial infrared interrupt enable */
|
||||
#define UCR4_WKEN (1<<7) /* Wake interrupt enable */
|
||||
#define UCR4_REF16 (1<<6) /* Ref freq 16 MHz */
|
||||
#define UCR4_IRSC (1<<5) /* IR special case */
|
||||
#define UCR4_TCEN (1<<3) /* Transmit complete interrupt enable */
|
||||
#define UCR4_BKEN (1<<2) /* Break condition interrupt enable */
|
||||
#define UCR4_OREN (1<<1) /* Receiver overrun interrupt enable */
|
||||
#define UCR4_DREN (1<<0) /* Recv data ready interrupt enable */
|
||||
#define UFCR_RXTL_SHF 0 /* Receiver trigger level shift */
|
||||
#define UFCR_RFDIV (7<<7) /* Reference freq divider mask */
|
||||
#define UFCR_RFDIV_SHF 7 /* Reference freq divider shift */
|
||||
#define RFDIV 4 /* divide input clock by 2 */
|
||||
#define UFCR_DCEDTE (1<<6) /* DTE mode select */
|
||||
#define UFCR_TXTL_SHF 10 /* Transmitter trigger level shift */
|
||||
#define USR1_PARITYERR (1<<15) /* Parity error interrupt flag */
|
||||
#define USR1_RTSS (1<<14) /* RTS pin status */
|
||||
#define USR1_TRDY (1<<13) /* Transmitter ready interrupt/dma flag */
|
||||
#define USR1_RTSD (1<<12) /* RTS delta */
|
||||
#define USR1_ESCF (1<<11) /* Escape seq interrupt flag */
|
||||
#define USR1_FRAMERR (1<<10) /* Frame error interrupt flag */
|
||||
#define USR1_RRDY (1<<9) /* Receiver ready interrupt/dma flag */
|
||||
#define USR1_TIMEOUT (1<<7) /* Receive timeout interrupt status */
|
||||
#define USR1_RXDS (1<<6) /* Receiver idle interrupt flag */
|
||||
#define USR1_AIRINT (1<<5) /* Async IR wake interrupt flag */
|
||||
#define USR1_AWAKE (1<<4) /* Aysnc wake interrupt flag */
|
||||
#define USR2_ADET (1<<15) /* Auto baud rate detect complete */
|
||||
#define USR2_TXFE (1<<14) /* Transmit buffer FIFO empty */
|
||||
#define USR2_DTRF (1<<13) /* DTR edge interrupt flag */
|
||||
#define USR2_IDLE (1<<12) /* Idle condition */
|
||||
#define USR2_IRINT (1<<8) /* Serial infrared interrupt flag */
|
||||
#define USR2_WAKE (1<<7) /* Wake */
|
||||
#define USR2_RTSF (1<<4) /* RTS edge interrupt flag */
|
||||
#define USR2_TXDC (1<<3) /* Transmitter complete */
|
||||
#define USR2_BRCD (1<<2) /* Break condition */
|
||||
#define USR2_ORE (1<<1) /* Overrun error */
|
||||
#define USR2_RDR (1<<0) /* Recv data ready */
|
||||
#define UTS_FRCPERR (1<<13) /* Force parity error */
|
||||
#define UTS_LOOP (1<<12) /* Loop tx and rx */
|
||||
#define UTS_TXEMPTY (1<<6) /* TxFIFO empty */
|
||||
#define UTS_RXEMPTY (1<<5) /* RxFIFO empty */
|
||||
#define UTS_TXFULL (1<<4) /* TxFIFO full */
|
||||
#define UTS_RXFULL (1<<3) /* RxFIFO full */
|
||||
#define UTS_SOFTRS (1<<0) /* Software reset */
|
||||
#define TXTL 2 /* reset default */
|
||||
#define RXTL 1 /* reset default */
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
struct mxc_uart {
|
||||
u32 rxd;
|
||||
u32 spare0[15];
|
||||
|
||||
u32 txd;
|
||||
u32 spare1[15];
|
||||
|
||||
u32 cr1;
|
||||
u32 cr2;
|
||||
u32 cr3;
|
||||
u32 cr4;
|
||||
|
||||
u32 fcr;
|
||||
u32 sr1;
|
||||
u32 sr2;
|
||||
u32 esc;
|
||||
|
||||
u32 tim;
|
||||
u32 bir;
|
||||
u32 bmr;
|
||||
u32 brc;
|
||||
|
||||
u32 onems;
|
||||
u32 ts;
|
||||
};
|
||||
|
||||
static void _mxc_serial_init(struct mxc_uart *base, int use_dte)
|
||||
{
|
||||
writel(0, &base->cr1);
|
||||
writel(0, &base->cr2);
|
||||
|
||||
while (!(readl(&base->cr2) & UCR2_SRST));
|
||||
|
||||
if (use_dte)
|
||||
writel(0x404 | UCR3_ADNIMP, &base->cr3);
|
||||
else
|
||||
writel(0x704 | UCR3_ADNIMP, &base->cr3);
|
||||
|
||||
writel(0x704 | UCR3_ADNIMP, &base->cr3);
|
||||
writel(0x8000, &base->cr4);
|
||||
writel(0x2b, &base->esc);
|
||||
writel(0, &base->tim);
|
||||
|
||||
writel(0, &base->ts);
|
||||
}
|
||||
|
||||
static void _mxc_serial_setbrg(struct mxc_uart *base, unsigned long clk,
|
||||
unsigned long baudrate, bool use_dte)
|
||||
{
|
||||
u32 tmp;
|
||||
|
||||
tmp = RFDIV << UFCR_RFDIV_SHF;
|
||||
if (use_dte)
|
||||
tmp |= UFCR_DCEDTE;
|
||||
else
|
||||
tmp |= (TXTL << UFCR_TXTL_SHF) | (RXTL << UFCR_RXTL_SHF);
|
||||
writel(tmp, &base->fcr);
|
||||
|
||||
writel(0xf, &base->bir);
|
||||
writel(clk / (2 * baudrate), &base->bmr);
|
||||
|
||||
writel(UCR2_WS | UCR2_IRTS | UCR2_RXEN | UCR2_TXEN | UCR2_SRST,
|
||||
&base->cr2);
|
||||
writel(UCR1_UARTEN, &base->cr1);
|
||||
}
|
||||
|
||||
#if !CONFIG_IS_ENABLED(DM_SERIAL)
|
||||
|
||||
#ifndef CONFIG_MXC_UART_BASE
|
||||
#error "define CONFIG_MXC_UART_BASE to use the MXC UART driver"
|
||||
#endif
|
||||
|
||||
#define mxc_base ((struct mxc_uart *)CONFIG_MXC_UART_BASE)
|
||||
|
||||
static void mxc_serial_setbrg(void)
|
||||
{
|
||||
u32 clk = imx_get_uartclk();
|
||||
|
||||
if (!gd->baudrate)
|
||||
gd->baudrate = CONFIG_BAUDRATE;
|
||||
|
||||
_mxc_serial_setbrg(mxc_base, clk, gd->baudrate, false);
|
||||
}
|
||||
|
||||
static int mxc_serial_getc(void)
|
||||
{
|
||||
while (readl(&mxc_base->ts) & UTS_RXEMPTY)
|
||||
WATCHDOG_RESET();
|
||||
return (readl(&mxc_base->rxd) & URXD_RX_DATA); /* mask out status from upper word */
|
||||
}
|
||||
|
||||
static void mxc_serial_putc(const char c)
|
||||
{
|
||||
/* If \n, also do \r */
|
||||
if (c == '\n')
|
||||
serial_putc('\r');
|
||||
|
||||
writel(c, &mxc_base->txd);
|
||||
|
||||
/* wait for transmitter to be ready */
|
||||
while (!(readl(&mxc_base->ts) & UTS_TXEMPTY))
|
||||
WATCHDOG_RESET();
|
||||
}
|
||||
|
||||
/* Test whether a character is in the RX buffer */
|
||||
static int mxc_serial_tstc(void)
|
||||
{
|
||||
/* If receive fifo is empty, return false */
|
||||
if (readl(&mxc_base->ts) & UTS_RXEMPTY)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialise the serial port with the given baudrate. The settings
|
||||
* are always 8 data bits, no parity, 1 stop bit, no start bits.
|
||||
*/
|
||||
static int mxc_serial_init(void)
|
||||
{
|
||||
_mxc_serial_init(mxc_base, false);
|
||||
|
||||
serial_setbrg();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct serial_device mxc_serial_drv = {
|
||||
.name = "mxc_serial",
|
||||
.start = mxc_serial_init,
|
||||
.stop = NULL,
|
||||
.setbrg = mxc_serial_setbrg,
|
||||
.putc = mxc_serial_putc,
|
||||
.puts = default_serial_puts,
|
||||
.getc = mxc_serial_getc,
|
||||
.tstc = mxc_serial_tstc,
|
||||
};
|
||||
|
||||
void mxc_serial_initialize(void)
|
||||
{
|
||||
serial_register(&mxc_serial_drv);
|
||||
}
|
||||
|
||||
__weak struct serial_device *default_serial_console(void)
|
||||
{
|
||||
return &mxc_serial_drv;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if CONFIG_IS_ENABLED(DM_SERIAL)
|
||||
|
||||
int mxc_serial_setbrg(struct udevice *dev, int baudrate)
|
||||
{
|
||||
struct mxc_serial_platdata *plat = dev->platdata;
|
||||
u32 clk = imx_get_uartclk();
|
||||
|
||||
_mxc_serial_setbrg(plat->reg, clk, baudrate, plat->use_dte);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mxc_serial_probe(struct udevice *dev)
|
||||
{
|
||||
struct mxc_serial_platdata *plat = dev->platdata;
|
||||
|
||||
_mxc_serial_init(plat->reg, plat->use_dte);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mxc_serial_getc(struct udevice *dev)
|
||||
{
|
||||
struct mxc_serial_platdata *plat = dev->platdata;
|
||||
struct mxc_uart *const uart = plat->reg;
|
||||
|
||||
if (readl(&uart->ts) & UTS_RXEMPTY)
|
||||
return -EAGAIN;
|
||||
|
||||
return readl(&uart->rxd) & URXD_RX_DATA;
|
||||
}
|
||||
|
||||
static int mxc_serial_putc(struct udevice *dev, const char ch)
|
||||
{
|
||||
struct mxc_serial_platdata *plat = dev->platdata;
|
||||
struct mxc_uart *const uart = plat->reg;
|
||||
|
||||
if (!(readl(&uart->ts) & UTS_TXEMPTY))
|
||||
return -EAGAIN;
|
||||
|
||||
writel(ch, &uart->txd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mxc_serial_pending(struct udevice *dev, bool input)
|
||||
{
|
||||
struct mxc_serial_platdata *plat = dev->platdata;
|
||||
struct mxc_uart *const uart = plat->reg;
|
||||
uint32_t sr2 = readl(&uart->sr2);
|
||||
|
||||
if (input)
|
||||
return sr2 & USR2_RDR ? 1 : 0;
|
||||
else
|
||||
return sr2 & USR2_TXDC ? 0 : 1;
|
||||
}
|
||||
|
||||
static const struct dm_serial_ops mxc_serial_ops = {
|
||||
.putc = mxc_serial_putc,
|
||||
.pending = mxc_serial_pending,
|
||||
.getc = mxc_serial_getc,
|
||||
.setbrg = mxc_serial_setbrg,
|
||||
};
|
||||
|
||||
#if CONFIG_IS_ENABLED(OF_CONTROL)
|
||||
static int mxc_serial_ofdata_to_platdata(struct udevice *dev)
|
||||
{
|
||||
struct mxc_serial_platdata *plat = dev->platdata;
|
||||
fdt_addr_t addr;
|
||||
|
||||
addr = devfdt_get_addr(dev);
|
||||
if (addr == FDT_ADDR_T_NONE)
|
||||
return -EINVAL;
|
||||
|
||||
plat->reg = (struct mxc_uart *)addr;
|
||||
|
||||
plat->use_dte = fdtdec_get_bool(gd->fdt_blob, dev_of_offset(dev),
|
||||
"fsl,dte-mode");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct udevice_id mxc_serial_ids[] = {
|
||||
{ .compatible = "fsl,imx21-uart" },
|
||||
{ .compatible = "fsl,imx53-uart" },
|
||||
{ .compatible = "fsl,imx6sx-uart" },
|
||||
{ .compatible = "fsl,imx6ul-uart" },
|
||||
{ .compatible = "fsl,imx7d-uart" },
|
||||
{ .compatible = "fsl,imx6q-uart" },
|
||||
{ }
|
||||
};
|
||||
#endif
|
||||
|
||||
U_BOOT_DRIVER(serial_mxc) = {
|
||||
.name = "serial_mxc",
|
||||
.id = UCLASS_SERIAL,
|
||||
#if CONFIG_IS_ENABLED(OF_CONTROL)
|
||||
.of_match = mxc_serial_ids,
|
||||
.ofdata_to_platdata = mxc_serial_ofdata_to_platdata,
|
||||
.platdata_auto_alloc_size = sizeof(struct mxc_serial_platdata),
|
||||
#endif
|
||||
.probe = mxc_serial_probe,
|
||||
.ops = &mxc_serial_ops,
|
||||
.flags = DM_FLAG_PRE_RELOC,
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_DEBUG_UART_MXC
|
||||
#include <debug_uart.h>
|
||||
|
||||
static inline void _debug_uart_init(void)
|
||||
{
|
||||
struct mxc_uart *base = (struct mxc_uart *)CONFIG_DEBUG_UART_BASE;
|
||||
|
||||
_mxc_serial_init(base, false);
|
||||
_mxc_serial_setbrg(base, CONFIG_DEBUG_UART_CLOCK,
|
||||
CONFIG_BAUDRATE, false);
|
||||
}
|
||||
|
||||
static inline void _debug_uart_putc(int ch)
|
||||
{
|
||||
struct mxc_uart *base = (struct mxc_uart *)CONFIG_DEBUG_UART_BASE;
|
||||
|
||||
while (!(readl(&base->ts) & UTS_TXEMPTY))
|
||||
WATCHDOG_RESET();
|
||||
|
||||
writel(ch, &base->txd);
|
||||
}
|
||||
|
||||
DEBUG_UART_FUNCS
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,257 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* (C) Copyright 2000
|
||||
* Rob Taylor, Flying Pig Systems. robt@flyingpig.com.
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <linux/compiler.h>
|
||||
|
||||
#include <ns16550.h>
|
||||
#ifdef CONFIG_NS87308
|
||||
#include <ns87308.h>
|
||||
#endif
|
||||
|
||||
#include <serial.h>
|
||||
|
||||
#ifndef CONFIG_NS16550_MIN_FUNCTIONS
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
#if !defined(CONFIG_CONS_INDEX)
|
||||
#elif (CONFIG_CONS_INDEX < 1) || (CONFIG_CONS_INDEX > 6)
|
||||
#error "Invalid console index value."
|
||||
#endif
|
||||
|
||||
#if CONFIG_CONS_INDEX == 1 && !defined(CONFIG_SYS_NS16550_COM1)
|
||||
#error "Console port 1 defined but not configured."
|
||||
#elif CONFIG_CONS_INDEX == 2 && !defined(CONFIG_SYS_NS16550_COM2)
|
||||
#error "Console port 2 defined but not configured."
|
||||
#elif CONFIG_CONS_INDEX == 3 && !defined(CONFIG_SYS_NS16550_COM3)
|
||||
#error "Console port 3 defined but not configured."
|
||||
#elif CONFIG_CONS_INDEX == 4 && !defined(CONFIG_SYS_NS16550_COM4)
|
||||
#error "Console port 4 defined but not configured."
|
||||
#elif CONFIG_CONS_INDEX == 5 && !defined(CONFIG_SYS_NS16550_COM5)
|
||||
#error "Console port 5 defined but not configured."
|
||||
#elif CONFIG_CONS_INDEX == 6 && !defined(CONFIG_SYS_NS16550_COM6)
|
||||
#error "Console port 6 defined but not configured."
|
||||
#endif
|
||||
|
||||
/* Note: The port number specified in the functions is 1 based.
|
||||
* the array is 0 based.
|
||||
*/
|
||||
static NS16550_t serial_ports[6] = {
|
||||
#ifdef CONFIG_SYS_NS16550_COM1
|
||||
(NS16550_t)CONFIG_SYS_NS16550_COM1,
|
||||
#else
|
||||
NULL,
|
||||
#endif
|
||||
#ifdef CONFIG_SYS_NS16550_COM2
|
||||
(NS16550_t)CONFIG_SYS_NS16550_COM2,
|
||||
#else
|
||||
NULL,
|
||||
#endif
|
||||
#ifdef CONFIG_SYS_NS16550_COM3
|
||||
(NS16550_t)CONFIG_SYS_NS16550_COM3,
|
||||
#else
|
||||
NULL,
|
||||
#endif
|
||||
#ifdef CONFIG_SYS_NS16550_COM4
|
||||
(NS16550_t)CONFIG_SYS_NS16550_COM4,
|
||||
#else
|
||||
NULL,
|
||||
#endif
|
||||
#ifdef CONFIG_SYS_NS16550_COM5
|
||||
(NS16550_t)CONFIG_SYS_NS16550_COM5,
|
||||
#else
|
||||
NULL,
|
||||
#endif
|
||||
#ifdef CONFIG_SYS_NS16550_COM6
|
||||
(NS16550_t)CONFIG_SYS_NS16550_COM6
|
||||
#else
|
||||
NULL
|
||||
#endif
|
||||
};
|
||||
|
||||
#define PORT serial_ports[port-1]
|
||||
|
||||
/* Multi serial device functions */
|
||||
#define DECLARE_ESERIAL_FUNCTIONS(port) \
|
||||
static int eserial##port##_init(void) \
|
||||
{ \
|
||||
int clock_divisor; \
|
||||
clock_divisor = ns16550_calc_divisor(serial_ports[port-1], \
|
||||
CONFIG_SYS_NS16550_CLK, gd->baudrate); \
|
||||
NS16550_init(serial_ports[port-1], clock_divisor); \
|
||||
return 0 ; \
|
||||
} \
|
||||
static void eserial##port##_setbrg(void) \
|
||||
{ \
|
||||
serial_setbrg_dev(port); \
|
||||
} \
|
||||
static int eserial##port##_getc(void) \
|
||||
{ \
|
||||
return serial_getc_dev(port); \
|
||||
} \
|
||||
static int eserial##port##_tstc(void) \
|
||||
{ \
|
||||
return serial_tstc_dev(port); \
|
||||
} \
|
||||
static void eserial##port##_putc(const char c) \
|
||||
{ \
|
||||
serial_putc_dev(port, c); \
|
||||
} \
|
||||
static void eserial##port##_puts(const char *s) \
|
||||
{ \
|
||||
serial_puts_dev(port, s); \
|
||||
}
|
||||
|
||||
/* Serial device descriptor */
|
||||
#define INIT_ESERIAL_STRUCTURE(port, __name) { \
|
||||
.name = __name, \
|
||||
.start = eserial##port##_init, \
|
||||
.stop = NULL, \
|
||||
.setbrg = eserial##port##_setbrg, \
|
||||
.getc = eserial##port##_getc, \
|
||||
.tstc = eserial##port##_tstc, \
|
||||
.putc = eserial##port##_putc, \
|
||||
.puts = eserial##port##_puts, \
|
||||
}
|
||||
|
||||
static void _serial_putc(const char c, const int port)
|
||||
{
|
||||
if (c == '\n')
|
||||
NS16550_putc(PORT, '\r');
|
||||
|
||||
NS16550_putc(PORT, c);
|
||||
}
|
||||
|
||||
static void _serial_puts(const char *s, const int port)
|
||||
{
|
||||
while (*s) {
|
||||
_serial_putc(*s++, port);
|
||||
}
|
||||
}
|
||||
|
||||
static int _serial_getc(const int port)
|
||||
{
|
||||
return NS16550_getc(PORT);
|
||||
}
|
||||
|
||||
static int _serial_tstc(const int port)
|
||||
{
|
||||
return NS16550_tstc(PORT);
|
||||
}
|
||||
|
||||
static void _serial_setbrg(const int port)
|
||||
{
|
||||
int clock_divisor;
|
||||
|
||||
clock_divisor = ns16550_calc_divisor(PORT, CONFIG_SYS_NS16550_CLK,
|
||||
gd->baudrate);
|
||||
NS16550_reinit(PORT, clock_divisor);
|
||||
}
|
||||
|
||||
static inline void
|
||||
serial_putc_dev(unsigned int dev_index,const char c)
|
||||
{
|
||||
_serial_putc(c,dev_index);
|
||||
}
|
||||
|
||||
static inline void
|
||||
serial_puts_dev(unsigned int dev_index,const char *s)
|
||||
{
|
||||
_serial_puts(s,dev_index);
|
||||
}
|
||||
|
||||
static inline int
|
||||
serial_getc_dev(unsigned int dev_index)
|
||||
{
|
||||
return _serial_getc(dev_index);
|
||||
}
|
||||
|
||||
static inline int
|
||||
serial_tstc_dev(unsigned int dev_index)
|
||||
{
|
||||
return _serial_tstc(dev_index);
|
||||
}
|
||||
|
||||
static inline void
|
||||
serial_setbrg_dev(unsigned int dev_index)
|
||||
{
|
||||
_serial_setbrg(dev_index);
|
||||
}
|
||||
|
||||
#if defined(CONFIG_SYS_NS16550_COM1)
|
||||
DECLARE_ESERIAL_FUNCTIONS(1);
|
||||
struct serial_device eserial1_device =
|
||||
INIT_ESERIAL_STRUCTURE(1, "eserial0");
|
||||
#endif
|
||||
#if defined(CONFIG_SYS_NS16550_COM2)
|
||||
DECLARE_ESERIAL_FUNCTIONS(2);
|
||||
struct serial_device eserial2_device =
|
||||
INIT_ESERIAL_STRUCTURE(2, "eserial1");
|
||||
#endif
|
||||
#if defined(CONFIG_SYS_NS16550_COM3)
|
||||
DECLARE_ESERIAL_FUNCTIONS(3);
|
||||
struct serial_device eserial3_device =
|
||||
INIT_ESERIAL_STRUCTURE(3, "eserial2");
|
||||
#endif
|
||||
#if defined(CONFIG_SYS_NS16550_COM4)
|
||||
DECLARE_ESERIAL_FUNCTIONS(4);
|
||||
struct serial_device eserial4_device =
|
||||
INIT_ESERIAL_STRUCTURE(4, "eserial3");
|
||||
#endif
|
||||
#if defined(CONFIG_SYS_NS16550_COM5)
|
||||
DECLARE_ESERIAL_FUNCTIONS(5);
|
||||
struct serial_device eserial5_device =
|
||||
INIT_ESERIAL_STRUCTURE(5, "eserial4");
|
||||
#endif
|
||||
#if defined(CONFIG_SYS_NS16550_COM6)
|
||||
DECLARE_ESERIAL_FUNCTIONS(6);
|
||||
struct serial_device eserial6_device =
|
||||
INIT_ESERIAL_STRUCTURE(6, "eserial5");
|
||||
#endif
|
||||
|
||||
__weak struct serial_device *default_serial_console(void)
|
||||
{
|
||||
#if CONFIG_CONS_INDEX == 1
|
||||
return &eserial1_device;
|
||||
#elif CONFIG_CONS_INDEX == 2
|
||||
return &eserial2_device;
|
||||
#elif CONFIG_CONS_INDEX == 3
|
||||
return &eserial3_device;
|
||||
#elif CONFIG_CONS_INDEX == 4
|
||||
return &eserial4_device;
|
||||
#elif CONFIG_CONS_INDEX == 5
|
||||
return &eserial5_device;
|
||||
#elif CONFIG_CONS_INDEX == 6
|
||||
return &eserial6_device;
|
||||
#else
|
||||
#error "Bad CONFIG_CONS_INDEX."
|
||||
#endif
|
||||
}
|
||||
|
||||
void ns16550_serial_initialize(void)
|
||||
{
|
||||
#if defined(CONFIG_SYS_NS16550_COM1)
|
||||
serial_register(&eserial1_device);
|
||||
#endif
|
||||
#if defined(CONFIG_SYS_NS16550_COM2)
|
||||
serial_register(&eserial2_device);
|
||||
#endif
|
||||
#if defined(CONFIG_SYS_NS16550_COM3)
|
||||
serial_register(&eserial3_device);
|
||||
#endif
|
||||
#if defined(CONFIG_SYS_NS16550_COM4)
|
||||
serial_register(&eserial4_device);
|
||||
#endif
|
||||
#if defined(CONFIG_SYS_NS16550_COM5)
|
||||
serial_register(&eserial5_device);
|
||||
#endif
|
||||
#if defined(CONFIG_SYS_NS16550_COM6)
|
||||
serial_register(&eserial6_device);
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif /* !CONFIG_NS16550_MIN_FUNCTIONS */
|
||||
@@ -0,0 +1,53 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright (c) 2015 National Instruments
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <dm.h>
|
||||
#include <serial.h>
|
||||
|
||||
static int nulldev_serial_setbrg(struct udevice *dev, int baudrate)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int nulldev_serial_getc(struct udevice *dev)
|
||||
{
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
static int nulldev_serial_pending(struct udevice *dev, bool input)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int nulldev_serial_input(struct udevice *dev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int nulldev_serial_putc(struct udevice *dev, const char ch)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct udevice_id nulldev_serial_ids[] = {
|
||||
{ .compatible = "nulldev-serial" },
|
||||
{ }
|
||||
};
|
||||
|
||||
|
||||
const struct dm_serial_ops nulldev_serial_ops = {
|
||||
.putc = nulldev_serial_putc,
|
||||
.pending = nulldev_serial_pending,
|
||||
.getc = nulldev_serial_getc,
|
||||
.setbrg = nulldev_serial_setbrg,
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(serial_nulldev) = {
|
||||
.name = "serial_nulldev",
|
||||
.id = UCLASS_SERIAL,
|
||||
.of_match = nulldev_serial_ids,
|
||||
.ops = &nulldev_serial_ops,
|
||||
};
|
||||
@@ -0,0 +1,169 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Texas Instruments' OMAP serial driver
|
||||
*
|
||||
* Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/
|
||||
* Lokesh Vutla <lokeshvutla@ti.com>
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <dm.h>
|
||||
#include <dt-structs.h>
|
||||
#include <ns16550.h>
|
||||
#include <serial.h>
|
||||
#include <clk.h>
|
||||
|
||||
#ifndef CONFIG_SYS_NS16550_CLK
|
||||
#define CONFIG_SYS_NS16550_CLK 0
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_DEBUG_UART_OMAP
|
||||
|
||||
#ifndef CONFIG_SYS_NS16550_IER
|
||||
#define CONFIG_SYS_NS16550_IER 0x00
|
||||
#endif
|
||||
|
||||
#define UART_MCRVAL 0x00
|
||||
#define UART_LCRVAL UART_LCR_8N1
|
||||
|
||||
static inline void serial_out_shift(void *addr, int shift, int value)
|
||||
{
|
||||
#ifdef CONFIG_SYS_NS16550_PORT_MAPPED
|
||||
outb(value, (ulong)addr);
|
||||
#elif defined(CONFIG_SYS_NS16550_MEM32) && defined(CONFIG_SYS_LITTLE_ENDIAN)
|
||||
out_le32(addr, value);
|
||||
#elif defined(CONFIG_SYS_NS16550_MEM32) && defined(CONFIG_SYS_BIG_ENDIAN)
|
||||
out_be32(addr, value);
|
||||
#elif defined(CONFIG_SYS_NS16550_MEM32)
|
||||
writel(value, addr);
|
||||
#elif defined(CONFIG_SYS_BIG_ENDIAN)
|
||||
writeb(value, addr + (1 << shift) - 1);
|
||||
#else
|
||||
writeb(value, addr);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline int serial_in_shift(void *addr, int shift)
|
||||
{
|
||||
#ifdef CONFIG_SYS_NS16550_PORT_MAPPED
|
||||
return inb((ulong)addr);
|
||||
#elif defined(CONFIG_SYS_NS16550_MEM32) && defined(CONFIG_SYS_LITTLE_ENDIAN)
|
||||
return in_le32(addr);
|
||||
#elif defined(CONFIG_SYS_NS16550_MEM32) && defined(CONFIG_SYS_BIG_ENDIAN)
|
||||
return in_be32(addr);
|
||||
#elif defined(CONFIG_SYS_NS16550_MEM32)
|
||||
return readl(addr);
|
||||
#elif defined(CONFIG_SYS_BIG_ENDIAN)
|
||||
return readb(addr + (1 << shift) - 1);
|
||||
#else
|
||||
return readb(addr);
|
||||
#endif
|
||||
}
|
||||
|
||||
#include <debug_uart.h>
|
||||
|
||||
static inline void _debug_uart_init(void)
|
||||
{
|
||||
struct NS16550 *com_port = (struct NS16550 *)CONFIG_DEBUG_UART_BASE;
|
||||
int baud_divisor;
|
||||
|
||||
baud_divisor = ns16550_calc_divisor(com_port, CONFIG_DEBUG_UART_CLOCK,
|
||||
CONFIG_BAUDRATE);
|
||||
serial_dout(&com_port->ier, CONFIG_SYS_NS16550_IER);
|
||||
serial_dout(&com_port->mdr1, 0x7);
|
||||
serial_dout(&com_port->mcr, UART_MCRVAL);
|
||||
serial_dout(&com_port->fcr, UART_FCR_DEFVAL);
|
||||
|
||||
serial_dout(&com_port->lcr, UART_LCR_BKSE | UART_LCRVAL);
|
||||
serial_dout(&com_port->dll, baud_divisor & 0xff);
|
||||
serial_dout(&com_port->dlm, (baud_divisor >> 8) & 0xff);
|
||||
serial_dout(&com_port->lcr, UART_LCRVAL);
|
||||
serial_dout(&com_port->mdr1, 0x0);
|
||||
}
|
||||
|
||||
static inline void _debug_uart_putc(int ch)
|
||||
{
|
||||
struct NS16550 *com_port = (struct NS16550 *)CONFIG_DEBUG_UART_BASE;
|
||||
|
||||
while (!(serial_din(&com_port->lsr) & UART_LSR_THRE))
|
||||
;
|
||||
serial_dout(&com_port->thr, ch);
|
||||
}
|
||||
|
||||
DEBUG_UART_FUNCS
|
||||
|
||||
#endif
|
||||
|
||||
#if CONFIG_IS_ENABLED(DM_SERIAL)
|
||||
|
||||
#if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)
|
||||
static int omap_serial_ofdata_to_platdata(struct udevice *dev)
|
||||
{
|
||||
struct ns16550_platdata *plat = dev->platdata;
|
||||
fdt_addr_t addr;
|
||||
struct clk clk;
|
||||
int err;
|
||||
|
||||
/* try Processor Local Bus device first */
|
||||
addr = dev_read_addr(dev);
|
||||
if (addr == FDT_ADDR_T_NONE)
|
||||
return -EINVAL;
|
||||
|
||||
plat->base = (unsigned long)map_physmem(addr, 0, MAP_NOCACHE);
|
||||
|
||||
plat->reg_offset = dev_read_u32_default(dev, "reg-offset", 0);
|
||||
plat->reg_shift = 2;
|
||||
|
||||
err = clk_get_by_index(dev, 0, &clk);
|
||||
if (!err) {
|
||||
err = clk_get_rate(&clk);
|
||||
if (!IS_ERR_VALUE(err))
|
||||
plat->clock = err;
|
||||
} else if (err != -ENOENT && err != -ENODEV && err != -ENOSYS) {
|
||||
debug("omap serial failed to get clock\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
if (!plat->clock)
|
||||
plat->clock = dev_read_u32_default(dev, "clock-frequency",
|
||||
CONFIG_SYS_NS16550_CLK);
|
||||
if (!plat->clock) {
|
||||
debug("omap serial clock not defined\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
plat->fcr = UART_FCR_DEFVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct udevice_id omap_serial_ids[] = {
|
||||
{ .compatible = "ti,omap2-uart", },
|
||||
{ .compatible = "ti,omap3-uart", },
|
||||
{ .compatible = "ti,omap4-uart", },
|
||||
{ .compatible = "ti,am3352-uart", },
|
||||
{ .compatible = "ti,am4372-uart", },
|
||||
{ .compatible = "ti,dra742-uart", },
|
||||
{ .compatible = "ti,am654-uart", },
|
||||
{}
|
||||
};
|
||||
#endif /* OF_CONTROL && !OF_PLATDATA */
|
||||
|
||||
#if CONFIG_IS_ENABLED(SERIAL_PRESENT)
|
||||
U_BOOT_DRIVER(omap_serial) = {
|
||||
.name = "omap_serial",
|
||||
.id = UCLASS_SERIAL,
|
||||
#if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)
|
||||
.of_match = omap_serial_ids,
|
||||
.ofdata_to_platdata = omap_serial_ofdata_to_platdata,
|
||||
.platdata_auto_alloc_size = sizeof(struct ns16550_platdata),
|
||||
#endif
|
||||
.priv_auto_alloc_size = sizeof(struct NS16550),
|
||||
.probe = ns16550_serial_probe,
|
||||
.ops = &ns16550_serial_ops,
|
||||
#if !CONFIG_IS_ENABLED(OF_CONTROL)
|
||||
.flags = DM_FLAG_PRE_RELOC,
|
||||
#endif
|
||||
};
|
||||
#endif
|
||||
#endif /* DM_SERIAL */
|
||||
@@ -0,0 +1,135 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Actions Semi OWL SoCs UART driver
|
||||
*
|
||||
* Copyright (C) 2015 Actions Semi Co., Ltd.
|
||||
* Copyright (C) 2018 Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <clk.h>
|
||||
#include <dm.h>
|
||||
#include <errno.h>
|
||||
#include <fdtdec.h>
|
||||
#include <serial.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/types.h>
|
||||
|
||||
/* UART Registers */
|
||||
#define OWL_UART_CTL (0x0000)
|
||||
#define OWL_UART_RXDAT (0x0004)
|
||||
#define OWL_UART_TXDAT (0x0008)
|
||||
#define OWL_UART_STAT (0x000C)
|
||||
|
||||
/* UART_CTL Register Definitions */
|
||||
#define OWL_UART_CTL_PRS_NONE GENMASK(6, 4)
|
||||
#define OWL_UART_CTL_STPS BIT(2)
|
||||
#define OWL_UART_CTL_DWLS 3
|
||||
|
||||
/* UART_STAT Register Definitions */
|
||||
#define OWL_UART_STAT_TFES BIT(10) /* TX FIFO Empty Status */
|
||||
#define OWL_UART_STAT_RFFS BIT(9) /* RX FIFO full Status */
|
||||
#define OWL_UART_STAT_TFFU BIT(6) /* TX FIFO full Status */
|
||||
#define OWL_UART_STAT_RFEM BIT(5) /* RX FIFO Empty Status */
|
||||
|
||||
struct owl_serial_priv {
|
||||
phys_addr_t base;
|
||||
};
|
||||
|
||||
int owl_serial_setbrg(struct udevice *dev, int baudrate)
|
||||
{
|
||||
/* Driver supports only fixed baudrate */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int owl_serial_getc(struct udevice *dev)
|
||||
{
|
||||
struct owl_serial_priv *priv = dev_get_priv(dev);
|
||||
|
||||
if (readl(priv->base + OWL_UART_STAT) & OWL_UART_STAT_RFEM)
|
||||
return -EAGAIN;
|
||||
|
||||
return (int)(readl(priv->base + OWL_UART_RXDAT));
|
||||
}
|
||||
|
||||
static int owl_serial_putc(struct udevice *dev, const char ch)
|
||||
{
|
||||
struct owl_serial_priv *priv = dev_get_priv(dev);
|
||||
|
||||
if (readl(priv->base + OWL_UART_STAT) & OWL_UART_STAT_TFFU)
|
||||
return -EAGAIN;
|
||||
|
||||
writel(ch, priv->base + OWL_UART_TXDAT);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int owl_serial_pending(struct udevice *dev, bool input)
|
||||
{
|
||||
struct owl_serial_priv *priv = dev_get_priv(dev);
|
||||
unsigned int stat = readl(priv->base + OWL_UART_STAT);
|
||||
|
||||
if (input)
|
||||
return !(stat & OWL_UART_STAT_RFEM);
|
||||
else
|
||||
return !(stat & OWL_UART_STAT_TFES);
|
||||
}
|
||||
|
||||
static int owl_serial_probe(struct udevice *dev)
|
||||
{
|
||||
struct owl_serial_priv *priv = dev_get_priv(dev);
|
||||
struct clk clk;
|
||||
u32 uart_ctl;
|
||||
int ret;
|
||||
|
||||
/* Set data, parity and stop bits */
|
||||
uart_ctl = readl(priv->base + OWL_UART_CTL);
|
||||
uart_ctl &= ~(OWL_UART_CTL_PRS_NONE);
|
||||
uart_ctl &= ~(OWL_UART_CTL_STPS);
|
||||
uart_ctl |= OWL_UART_CTL_DWLS;
|
||||
writel(uart_ctl, priv->base + OWL_UART_CTL);
|
||||
|
||||
/* Enable UART clock */
|
||||
ret = clk_get_by_index(dev, 0, &clk);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = clk_enable(&clk);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int owl_serial_ofdata_to_platdata(struct udevice *dev)
|
||||
{
|
||||
struct owl_serial_priv *priv = dev_get_priv(dev);
|
||||
|
||||
priv->base = dev_read_addr(dev);
|
||||
if (priv->base == FDT_ADDR_T_NONE)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dm_serial_ops owl_serial_ops = {
|
||||
.putc = owl_serial_putc,
|
||||
.pending = owl_serial_pending,
|
||||
.getc = owl_serial_getc,
|
||||
.setbrg = owl_serial_setbrg,
|
||||
};
|
||||
|
||||
static const struct udevice_id owl_serial_ids[] = {
|
||||
{ .compatible = "actions,s900-serial" },
|
||||
{ }
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(serial_owl) = {
|
||||
.name = "serial_owl",
|
||||
.id = UCLASS_SERIAL,
|
||||
.of_match = owl_serial_ids,
|
||||
.ofdata_to_platdata = owl_serial_ofdata_to_platdata,
|
||||
.priv_auto_alloc_size = sizeof(struct owl_serial_priv),
|
||||
.probe = owl_serial_probe,
|
||||
.ops = &owl_serial_ops,
|
||||
};
|
||||
@@ -0,0 +1,198 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* (c) 2015 Paul Thacker <paul.thacker@microchip.com>
|
||||
*
|
||||
*/
|
||||
#include <common.h>
|
||||
#include <clk.h>
|
||||
#include <dm.h>
|
||||
#include <serial.h>
|
||||
#include <wait_bit.h>
|
||||
#include <mach/pic32.h>
|
||||
#include <dt-bindings/clock/microchip,clock.h>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
/* UART Control Registers */
|
||||
#define U_MOD 0x00
|
||||
#define U_MODCLR (U_MOD + _CLR_OFFSET)
|
||||
#define U_MODSET (U_MOD + _SET_OFFSET)
|
||||
#define U_STA 0x10
|
||||
#define U_STACLR (U_STA + _CLR_OFFSET)
|
||||
#define U_STASET (U_STA + _SET_OFFSET)
|
||||
#define U_TXR 0x20
|
||||
#define U_RXR 0x30
|
||||
#define U_BRG 0x40
|
||||
|
||||
/* U_MOD bits */
|
||||
#define UART_ENABLE BIT(15)
|
||||
|
||||
/* U_STA bits */
|
||||
#define UART_RX_ENABLE BIT(12)
|
||||
#define UART_TX_BRK BIT(11)
|
||||
#define UART_TX_ENABLE BIT(10)
|
||||
#define UART_TX_FULL BIT(9)
|
||||
#define UART_TX_EMPTY BIT(8)
|
||||
#define UART_RX_OVER BIT(1)
|
||||
#define UART_RX_DATA_AVAIL BIT(0)
|
||||
|
||||
struct pic32_uart_priv {
|
||||
void __iomem *base;
|
||||
ulong uartclk;
|
||||
};
|
||||
|
||||
/*
|
||||
* Initialize the serial port with the given baudrate.
|
||||
* The settings are always 8 data bits, no parity, 1 stop bit, no start bits.
|
||||
*/
|
||||
static int pic32_serial_init(void __iomem *base, ulong clk, u32 baudrate)
|
||||
{
|
||||
u32 div = DIV_ROUND_CLOSEST(clk, baudrate * 16);
|
||||
|
||||
/* wait for TX FIFO to empty */
|
||||
wait_for_bit_le32(base + U_STA, UART_TX_EMPTY,
|
||||
true, CONFIG_SYS_HZ, false);
|
||||
|
||||
/* send break */
|
||||
writel(UART_TX_BRK, base + U_STASET);
|
||||
|
||||
/* disable and clear mode */
|
||||
writel(0, base + U_MOD);
|
||||
writel(0, base + U_STA);
|
||||
|
||||
/* set baud rate generator */
|
||||
writel(div - 1, base + U_BRG);
|
||||
|
||||
/* enable the UART for TX and RX */
|
||||
writel(UART_TX_ENABLE | UART_RX_ENABLE, base + U_STASET);
|
||||
|
||||
/* enable the UART */
|
||||
writel(UART_ENABLE, base + U_MODSET);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Check whether any char pending in RX fifo */
|
||||
static int pic32_uart_pending_input(void __iomem *base)
|
||||
{
|
||||
/* check if rx buffer overrun error has occurred */
|
||||
if (readl(base + U_STA) & UART_RX_OVER) {
|
||||
readl(base + U_RXR);
|
||||
|
||||
/* clear overrun error to keep receiving */
|
||||
writel(UART_RX_OVER, base + U_STACLR);
|
||||
}
|
||||
|
||||
/* In PIC32 there is no way to know number of outstanding
|
||||
* chars in rx-fifo. Only it can be known whether there is any.
|
||||
*/
|
||||
return readl(base + U_STA) & UART_RX_DATA_AVAIL;
|
||||
}
|
||||
|
||||
static int pic32_uart_pending(struct udevice *dev, bool input)
|
||||
{
|
||||
struct pic32_uart_priv *priv = dev_get_priv(dev);
|
||||
|
||||
if (input)
|
||||
return pic32_uart_pending_input(priv->base);
|
||||
|
||||
return !(readl(priv->base + U_STA) & UART_TX_EMPTY);
|
||||
}
|
||||
|
||||
static int pic32_uart_setbrg(struct udevice *dev, int baudrate)
|
||||
{
|
||||
struct pic32_uart_priv *priv = dev_get_priv(dev);
|
||||
|
||||
return pic32_serial_init(priv->base, priv->uartclk, baudrate);
|
||||
}
|
||||
|
||||
static int pic32_uart_putc(struct udevice *dev, const char ch)
|
||||
{
|
||||
struct pic32_uart_priv *priv = dev_get_priv(dev);
|
||||
|
||||
/* Check if Tx FIFO is full */
|
||||
if (readl(priv->base + U_STA) & UART_TX_FULL)
|
||||
return -EAGAIN;
|
||||
|
||||
/* pump the char to tx buffer */
|
||||
writel(ch, priv->base + U_TXR);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pic32_uart_getc(struct udevice *dev)
|
||||
{
|
||||
struct pic32_uart_priv *priv = dev_get_priv(dev);
|
||||
|
||||
/* return error if RX fifo is empty */
|
||||
if (!pic32_uart_pending_input(priv->base))
|
||||
return -EAGAIN;
|
||||
|
||||
/* read the character from rx buffer */
|
||||
return readl(priv->base + U_RXR) & 0xff;
|
||||
}
|
||||
|
||||
static int pic32_uart_probe(struct udevice *dev)
|
||||
{
|
||||
struct pic32_uart_priv *priv = dev_get_priv(dev);
|
||||
struct clk clk;
|
||||
fdt_addr_t addr;
|
||||
fdt_size_t size;
|
||||
int ret;
|
||||
|
||||
/* get address */
|
||||
addr = fdtdec_get_addr_size(gd->fdt_blob, dev_of_offset(dev), "reg",
|
||||
&size);
|
||||
if (addr == FDT_ADDR_T_NONE)
|
||||
return -EINVAL;
|
||||
|
||||
priv->base = ioremap(addr, size);
|
||||
|
||||
/* get clock rate */
|
||||
ret = clk_get_by_index(dev, 0, &clk);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
priv->uartclk = clk_get_rate(&clk);
|
||||
clk_free(&clk);
|
||||
|
||||
/* initialize serial */
|
||||
return pic32_serial_init(priv->base, priv->uartclk, CONFIG_BAUDRATE);
|
||||
}
|
||||
|
||||
static const struct dm_serial_ops pic32_uart_ops = {
|
||||
.putc = pic32_uart_putc,
|
||||
.pending = pic32_uart_pending,
|
||||
.getc = pic32_uart_getc,
|
||||
.setbrg = pic32_uart_setbrg,
|
||||
};
|
||||
|
||||
static const struct udevice_id pic32_uart_ids[] = {
|
||||
{ .compatible = "microchip,pic32mzda-uart" },
|
||||
{}
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(pic32_serial) = {
|
||||
.name = "pic32-uart",
|
||||
.id = UCLASS_SERIAL,
|
||||
.of_match = pic32_uart_ids,
|
||||
.probe = pic32_uart_probe,
|
||||
.ops = &pic32_uart_ops,
|
||||
.priv_auto_alloc_size = sizeof(struct pic32_uart_priv),
|
||||
};
|
||||
|
||||
#ifdef CONFIG_DEBUG_UART_PIC32
|
||||
#include <debug_uart.h>
|
||||
|
||||
static inline void _debug_uart_init(void)
|
||||
{
|
||||
void __iomem *base = (void __iomem *)CONFIG_DEBUG_UART_BASE;
|
||||
|
||||
pic32_serial_init(base, CONFIG_DEBUG_UART_CLOCK, CONFIG_BAUDRATE);
|
||||
}
|
||||
|
||||
static inline void _debug_uart_putc(int ch)
|
||||
{
|
||||
writel(ch, CONFIG_DEBUG_UART_BASE + U_TXR);
|
||||
}
|
||||
|
||||
DEBUG_UART_FUNCS
|
||||
#endif
|
||||
@@ -0,0 +1,432 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* (C) Copyright 2000
|
||||
* Rob Taylor, Flying Pig Systems. robt@flyingpig.com.
|
||||
*
|
||||
* (C) Copyright 2004
|
||||
* ARM Ltd.
|
||||
* Philippe Robin, <philippe.robin@arm.com>
|
||||
*/
|
||||
|
||||
/* Simple U-Boot driver for the PrimeCell PL010/PL011 UARTs */
|
||||
|
||||
#include <common.h>
|
||||
#include <dm.h>
|
||||
#include <errno.h>
|
||||
#include <watchdog.h>
|
||||
#include <asm/io.h>
|
||||
#include <serial.h>
|
||||
#include <dm/platform_data/serial_pl01x.h>
|
||||
#include <linux/compiler.h>
|
||||
#include "serial_pl01x_internal.h"
|
||||
|
||||
#include <linux/lotus/usb.h>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
#ifndef CONFIG_DM_SERIAL
|
||||
|
||||
static volatile unsigned char *const port[] = CONFIG_PL01x_PORTS;
|
||||
static enum pl01x_type pl01x_type __attribute__ ((section(".data")));
|
||||
static struct pl01x_regs *base_regs __attribute__ ((section(".data")));
|
||||
#define NUM_PORTS (sizeof(port)/sizeof(port[0]))
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_LOTUS_DISABLE_CONSOLE
|
||||
static bool g_uart_fputc_en = false;
|
||||
#else
|
||||
static bool g_uart_fputc_en = true;
|
||||
#endif
|
||||
|
||||
static int pl01x_putc(struct pl01x_regs *regs, char c)
|
||||
{
|
||||
#ifdef CONFIG_LOTUS_DISABLE_CONSOLE
|
||||
return 0;
|
||||
#endif
|
||||
if (g_uart_fputc_en == false) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Wait until there is space in the FIFO */
|
||||
if (readl(®s->fr) & UART_PL01x_FR_TXFF)
|
||||
return -EAGAIN;
|
||||
|
||||
/* Send the character */
|
||||
writel(c, ®s->dr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pl01x_getc(struct pl01x_regs *regs)
|
||||
{
|
||||
unsigned int data;
|
||||
|
||||
/* Wait until there is data in the FIFO */
|
||||
if (readl(®s->fr) & UART_PL01x_FR_RXFE)
|
||||
return -EAGAIN;
|
||||
|
||||
data = readl(®s->dr);
|
||||
|
||||
/* Check for an error flag */
|
||||
if (data & 0xFFFFFF00) {
|
||||
/* Clear the error */
|
||||
writel(0xFFFFFFFF, ®s->ecr);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return (int) data;
|
||||
}
|
||||
|
||||
static int pl01x_tstc(struct pl01x_regs *regs)
|
||||
{
|
||||
#ifdef CONFIG_LOTUS_DISABLE_CONSOLE
|
||||
return 0;
|
||||
#endif
|
||||
WATCHDOG_RESET();
|
||||
return !(readl(®s->fr) & UART_PL01x_FR_RXFE);
|
||||
}
|
||||
|
||||
static int pl01x_generic_serial_init(struct pl01x_regs *regs,
|
||||
enum pl01x_type type)
|
||||
{
|
||||
switch (type) {
|
||||
case TYPE_PL010:
|
||||
/* disable everything */
|
||||
writel(0, ®s->pl010_cr);
|
||||
break;
|
||||
case TYPE_PL011:
|
||||
/* disable everything */
|
||||
writel(0, ®s->pl011_cr);
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pl011_set_line_control(struct pl01x_regs *regs)
|
||||
{
|
||||
unsigned int lcr;
|
||||
/*
|
||||
* Internal update of baud rate register require line
|
||||
* control register write
|
||||
*/
|
||||
lcr = UART_PL011_LCRH_WLEN_8 | UART_PL011_LCRH_FEN;
|
||||
writel(lcr, ®s->pl011_lcrh);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pl01x_generic_setbrg(struct pl01x_regs *regs, enum pl01x_type type,
|
||||
int clock, int baudrate)
|
||||
{
|
||||
switch (type) {
|
||||
case TYPE_PL010: {
|
||||
unsigned int divisor;
|
||||
|
||||
/* disable everything */
|
||||
writel(0, ®s->pl010_cr);
|
||||
|
||||
switch (baudrate) {
|
||||
case 9600:
|
||||
divisor = UART_PL010_BAUD_9600;
|
||||
break;
|
||||
case 19200:
|
||||
divisor = UART_PL010_BAUD_19200;
|
||||
break;
|
||||
case 38400:
|
||||
divisor = UART_PL010_BAUD_38400;
|
||||
break;
|
||||
case 57600:
|
||||
divisor = UART_PL010_BAUD_57600;
|
||||
break;
|
||||
case 115200:
|
||||
divisor = UART_PL010_BAUD_115200;
|
||||
break;
|
||||
default:
|
||||
divisor = UART_PL010_BAUD_38400;
|
||||
}
|
||||
|
||||
writel((divisor & 0xf00) >> 8, ®s->pl010_lcrm);
|
||||
writel(divisor & 0xff, ®s->pl010_lcrl);
|
||||
|
||||
/*
|
||||
* Set line control for the PL010 to be 8 bits, 1 stop bit,
|
||||
* no parity, fifo enabled
|
||||
*/
|
||||
writel(UART_PL010_LCRH_WLEN_8 | UART_PL010_LCRH_FEN,
|
||||
®s->pl010_lcrh);
|
||||
/* Finally, enable the UART */
|
||||
writel(UART_PL010_CR_UARTEN, ®s->pl010_cr);
|
||||
break;
|
||||
}
|
||||
case TYPE_PL011: {
|
||||
unsigned int temp;
|
||||
unsigned int divider;
|
||||
unsigned int remainder;
|
||||
unsigned int fraction;
|
||||
|
||||
/*
|
||||
* Set baud rate
|
||||
*
|
||||
* IBRD = UART_CLK / (16 * BAUD_RATE)
|
||||
* FBRD = RND((64 * MOD(UART_CLK,(16 * BAUD_RATE)))
|
||||
* / (16 * BAUD_RATE))
|
||||
*/
|
||||
temp = 16 * baudrate;
|
||||
divider = clock / temp;
|
||||
remainder = clock % temp;
|
||||
temp = (8 * remainder) / baudrate;
|
||||
fraction = (temp >> 1) + (temp & 1);
|
||||
|
||||
writel(divider, ®s->pl011_ibrd);
|
||||
writel(fraction, ®s->pl011_fbrd);
|
||||
|
||||
pl011_set_line_control(regs);
|
||||
/* Finally, enable the UART */
|
||||
writel(UART_PL011_CR_UARTEN | UART_PL011_CR_TXE |
|
||||
UART_PL011_CR_RXE | UART_PL011_CR_RTS, ®s->pl011_cr);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifndef CONFIG_DM_SERIAL
|
||||
static void pl01x_serial_init_baud(int baudrate)
|
||||
{
|
||||
int clock = 0;
|
||||
|
||||
#if defined(CONFIG_PL010_SERIAL)
|
||||
pl01x_type = TYPE_PL010;
|
||||
#elif defined(CONFIG_PL011_SERIAL)
|
||||
pl01x_type = TYPE_PL011;
|
||||
clock = CONFIG_PL011_CLOCK;
|
||||
#endif
|
||||
base_regs = (struct pl01x_regs *)port[CONFIG_CONS_INDEX];
|
||||
|
||||
pl01x_generic_serial_init(base_regs, pl01x_type);
|
||||
pl01x_generic_setbrg(base_regs, pl01x_type, clock, baudrate);
|
||||
}
|
||||
|
||||
/*
|
||||
* Integrator AP has two UARTs, we use the first one, at 38400-8-N-1
|
||||
* Integrator CP has two UARTs, use the first one, at 38400-8-N-1
|
||||
* Versatile PB has four UARTs.
|
||||
*/
|
||||
int pl01x_serial_init(void)
|
||||
{
|
||||
pl01x_serial_init_baud(CONFIG_BAUDRATE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void pl01x_serial_putc(const char c)
|
||||
{
|
||||
if (c == '\n')
|
||||
while (pl01x_putc(base_regs, '\r') == -EAGAIN);
|
||||
|
||||
while (pl01x_putc(base_regs, c) == -EAGAIN);
|
||||
}
|
||||
|
||||
static int pl01x_serial_getc(void)
|
||||
{
|
||||
while (1) {
|
||||
int ch = pl01x_getc(base_regs);
|
||||
|
||||
if (ch == -EAGAIN) {
|
||||
WATCHDOG_RESET();
|
||||
continue;
|
||||
}
|
||||
|
||||
return ch;
|
||||
}
|
||||
}
|
||||
|
||||
static int pl01x_serial_tstc(void)
|
||||
{
|
||||
return pl01x_tstc(base_regs);
|
||||
}
|
||||
|
||||
static void pl01x_serial_setbrg(void)
|
||||
{
|
||||
/*
|
||||
* Flush FIFO and wait for non-busy before changing baudrate to avoid
|
||||
* crap in console
|
||||
*/
|
||||
while (!(readl(&base_regs->fr) & UART_PL01x_FR_TXFE))
|
||||
WATCHDOG_RESET();
|
||||
while (readl(&base_regs->fr) & UART_PL01x_FR_BUSY)
|
||||
WATCHDOG_RESET();
|
||||
pl01x_serial_init_baud(gd->baudrate);
|
||||
}
|
||||
|
||||
static struct serial_device pl01x_serial_drv = {
|
||||
.name = "pl01x_serial",
|
||||
.start = pl01x_serial_init,
|
||||
.stop = NULL,
|
||||
.setbrg = pl01x_serial_setbrg,
|
||||
.putc = pl01x_serial_putc,
|
||||
.puts = default_serial_puts,
|
||||
.getc = pl01x_serial_getc,
|
||||
.tstc = pl01x_serial_tstc,
|
||||
};
|
||||
|
||||
void pl01x_serial_initialize(void)
|
||||
{
|
||||
serial_register(&pl01x_serial_drv);
|
||||
}
|
||||
|
||||
__weak struct serial_device *default_serial_console(void)
|
||||
{
|
||||
return &pl01x_serial_drv;
|
||||
}
|
||||
|
||||
#endif /* nCONFIG_DM_SERIAL */
|
||||
|
||||
void serial_puts_to_tool(const char *s)
|
||||
{
|
||||
#ifdef CONFIG_USB_GADGET
|
||||
udc_puts(s);
|
||||
#endif
|
||||
while (*s) {
|
||||
while (pl01x_putc(base_regs, *s) == -EAGAIN);
|
||||
s++;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_DM_SERIAL
|
||||
|
||||
int pl01x_serial_setbrg(struct udevice *dev, int baudrate)
|
||||
{
|
||||
struct pl01x_serial_platdata *plat = dev_get_platdata(dev);
|
||||
struct pl01x_priv *priv = dev_get_priv(dev);
|
||||
|
||||
if (!plat->skip_init) {
|
||||
pl01x_generic_setbrg(priv->regs, priv->type, plat->clock,
|
||||
baudrate);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pl01x_serial_probe(struct udevice *dev)
|
||||
{
|
||||
struct pl01x_serial_platdata *plat = dev_get_platdata(dev);
|
||||
struct pl01x_priv *priv = dev_get_priv(dev);
|
||||
|
||||
priv->regs = (struct pl01x_regs *)plat->base;
|
||||
priv->type = plat->type;
|
||||
if (!plat->skip_init)
|
||||
return pl01x_generic_serial_init(priv->regs, priv->type);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pl01x_serial_getc(struct udevice *dev)
|
||||
{
|
||||
struct pl01x_priv *priv = dev_get_priv(dev);
|
||||
|
||||
return pl01x_getc(priv->regs);
|
||||
}
|
||||
|
||||
int pl01x_serial_putc(struct udevice *dev, const char ch)
|
||||
{
|
||||
struct pl01x_priv *priv = dev_get_priv(dev);
|
||||
|
||||
return pl01x_putc(priv->regs, ch);
|
||||
}
|
||||
|
||||
int pl01x_serial_pending(struct udevice *dev, bool input)
|
||||
{
|
||||
struct pl01x_priv *priv = dev_get_priv(dev);
|
||||
unsigned int fr = readl(&priv->regs->fr);
|
||||
|
||||
if (input)
|
||||
return pl01x_tstc(priv->regs);
|
||||
else
|
||||
return fr & UART_PL01x_FR_TXFF ? 0 : 1;
|
||||
}
|
||||
|
||||
static const struct dm_serial_ops pl01x_serial_ops = {
|
||||
.putc = pl01x_serial_putc,
|
||||
.pending = pl01x_serial_pending,
|
||||
.getc = pl01x_serial_getc,
|
||||
.setbrg = pl01x_serial_setbrg,
|
||||
};
|
||||
|
||||
#if CONFIG_IS_ENABLED(OF_CONTROL)
|
||||
static const struct udevice_id pl01x_serial_id[] ={
|
||||
{.compatible = "arm,pl011", .data = TYPE_PL011},
|
||||
{.compatible = "arm,pl010", .data = TYPE_PL010},
|
||||
{}
|
||||
};
|
||||
|
||||
int pl01x_serial_ofdata_to_platdata(struct udevice *dev)
|
||||
{
|
||||
struct pl01x_serial_platdata *plat = dev_get_platdata(dev);
|
||||
fdt_addr_t addr;
|
||||
|
||||
addr = devfdt_get_addr(dev);
|
||||
if (addr == FDT_ADDR_T_NONE)
|
||||
return -EINVAL;
|
||||
|
||||
plat->base = addr;
|
||||
plat->clock = dev_read_u32_default(dev, "clock", 1);
|
||||
plat->type = dev_get_driver_data(dev);
|
||||
plat->skip_init = dev_read_bool(dev, "skip-init");
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
U_BOOT_DRIVER(serial_pl01x) = {
|
||||
.name = "serial_pl01x",
|
||||
.id = UCLASS_SERIAL,
|
||||
.of_match = of_match_ptr(pl01x_serial_id),
|
||||
.ofdata_to_platdata = of_match_ptr(pl01x_serial_ofdata_to_platdata),
|
||||
.platdata_auto_alloc_size = sizeof(struct pl01x_serial_platdata),
|
||||
.probe = pl01x_serial_probe,
|
||||
.ops = &pl01x_serial_ops,
|
||||
.flags = DM_FLAG_PRE_RELOC,
|
||||
.priv_auto_alloc_size = sizeof(struct pl01x_priv),
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_DEBUG_UART_PL010) || defined(CONFIG_DEBUG_UART_PL011)
|
||||
|
||||
#include <debug_uart.h>
|
||||
|
||||
static void _debug_uart_init(void)
|
||||
{
|
||||
#ifndef CONFIG_DEBUG_UART_SKIP_INIT
|
||||
struct pl01x_regs *regs = (struct pl01x_regs *)CONFIG_DEBUG_UART_BASE;
|
||||
enum pl01x_type type = CONFIG_IS_ENABLED(DEBUG_UART_PL011) ?
|
||||
TYPE_PL011 : TYPE_PL010;
|
||||
|
||||
pl01x_generic_serial_init(regs, type);
|
||||
pl01x_generic_setbrg(regs, type,
|
||||
CONFIG_DEBUG_UART_CLOCK, CONFIG_BAUDRATE);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void _debug_uart_putc(int ch)
|
||||
{
|
||||
struct pl01x_regs *regs = (struct pl01x_regs *)CONFIG_DEBUG_UART_BASE;
|
||||
|
||||
pl01x_putc(regs, ch);
|
||||
}
|
||||
|
||||
DEBUG_UART_FUNCS
|
||||
|
||||
#endif
|
||||
|
||||
void serial_enable_output(bool is_enable)
|
||||
{
|
||||
g_uart_fputc_en = is_enable;
|
||||
}
|
||||
@@ -0,0 +1,145 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/*
|
||||
* (C) Copyright 2003, 2004
|
||||
* ARM Ltd.
|
||||
* Philippe Robin, <philippe.robin@arm.com>
|
||||
*/
|
||||
|
||||
/*
|
||||
* ARM PrimeCell UART's (PL010 & PL011)
|
||||
* ------------------------------------
|
||||
*
|
||||
* Definitions common to both PL010 & PL011
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
/*
|
||||
* We can use a combined structure for PL010 and PL011, because they overlap
|
||||
* only in common registers.
|
||||
*/
|
||||
struct pl01x_regs {
|
||||
u32 dr; /* 0x00 Data register */
|
||||
u32 ecr; /* 0x04 Error clear register (Write) */
|
||||
u32 pl010_lcrh; /* 0x08 Line control register, high byte */
|
||||
u32 pl010_lcrm; /* 0x0C Line control register, middle byte */
|
||||
u32 pl010_lcrl; /* 0x10 Line control register, low byte */
|
||||
u32 pl010_cr; /* 0x14 Control register */
|
||||
u32 fr; /* 0x18 Flag register (Read only) */
|
||||
#ifdef CONFIG_PL011_SERIAL_RLCR
|
||||
u32 pl011_rlcr; /* 0x1c Receive line control register */
|
||||
#else
|
||||
u32 reserved;
|
||||
#endif
|
||||
u32 ilpr; /* 0x20 IrDA low-power counter register */
|
||||
u32 pl011_ibrd; /* 0x24 Integer baud rate register */
|
||||
u32 pl011_fbrd; /* 0x28 Fractional baud rate register */
|
||||
u32 pl011_lcrh; /* 0x2C Line control register */
|
||||
u32 pl011_cr; /* 0x30 Control register */
|
||||
};
|
||||
|
||||
#ifdef CONFIG_DM_SERIAL
|
||||
|
||||
int pl01x_serial_ofdata_to_platdata(struct udevice *dev);
|
||||
int pl01x_serial_probe(struct udevice *dev);
|
||||
|
||||
/* Needed for external pl01x_serial_ops drivers */
|
||||
int pl01x_serial_putc(struct udevice *dev, const char ch);
|
||||
int pl01x_serial_pending(struct udevice *dev, bool input);
|
||||
int pl01x_serial_getc(struct udevice *dev);
|
||||
int pl01x_serial_setbrg(struct udevice *dev, int baudrate);
|
||||
|
||||
struct pl01x_priv {
|
||||
struct pl01x_regs *regs;
|
||||
enum pl01x_type type;
|
||||
};
|
||||
|
||||
#endif /* CONFIG_DM_SERIAL */
|
||||
#endif /* !__ASSEMBLY__ */
|
||||
|
||||
#define UART_PL01x_RSR_OE 0x08
|
||||
#define UART_PL01x_RSR_BE 0x04
|
||||
#define UART_PL01x_RSR_PE 0x02
|
||||
#define UART_PL01x_RSR_FE 0x01
|
||||
|
||||
#define UART_PL01x_FR_TXFE 0x80
|
||||
#define UART_PL01x_FR_RXFF 0x40
|
||||
#define UART_PL01x_FR_TXFF 0x20
|
||||
#define UART_PL01x_FR_RXFE 0x10
|
||||
#define UART_PL01x_FR_BUSY 0x08
|
||||
#define UART_PL01x_FR_TMSK (UART_PL01x_FR_TXFF + UART_PL01x_FR_BUSY)
|
||||
|
||||
/*
|
||||
* PL010 definitions
|
||||
*
|
||||
*/
|
||||
#define UART_PL010_CR_LPE (1 << 7)
|
||||
#define UART_PL010_CR_RTIE (1 << 6)
|
||||
#define UART_PL010_CR_TIE (1 << 5)
|
||||
#define UART_PL010_CR_RIE (1 << 4)
|
||||
#define UART_PL010_CR_MSIE (1 << 3)
|
||||
#define UART_PL010_CR_IIRLP (1 << 2)
|
||||
#define UART_PL010_CR_SIREN (1 << 1)
|
||||
#define UART_PL010_CR_UARTEN (1 << 0)
|
||||
|
||||
#define UART_PL010_LCRH_WLEN_8 (3 << 5)
|
||||
#define UART_PL010_LCRH_WLEN_7 (2 << 5)
|
||||
#define UART_PL010_LCRH_WLEN_6 (1 << 5)
|
||||
#define UART_PL010_LCRH_WLEN_5 (0 << 5)
|
||||
#define UART_PL010_LCRH_FEN (1 << 4)
|
||||
#define UART_PL010_LCRH_STP2 (1 << 3)
|
||||
#define UART_PL010_LCRH_EPS (1 << 2)
|
||||
#define UART_PL010_LCRH_PEN (1 << 1)
|
||||
#define UART_PL010_LCRH_BRK (1 << 0)
|
||||
|
||||
|
||||
#define UART_PL010_BAUD_460800 1
|
||||
#define UART_PL010_BAUD_230400 3
|
||||
#define UART_PL010_BAUD_115200 7
|
||||
#define UART_PL010_BAUD_57600 15
|
||||
#define UART_PL010_BAUD_38400 23
|
||||
#define UART_PL010_BAUD_19200 47
|
||||
#define UART_PL010_BAUD_14400 63
|
||||
#define UART_PL010_BAUD_9600 95
|
||||
#define UART_PL010_BAUD_4800 191
|
||||
#define UART_PL010_BAUD_2400 383
|
||||
#define UART_PL010_BAUD_1200 767
|
||||
/*
|
||||
* PL011 definitions
|
||||
*
|
||||
*/
|
||||
#define UART_PL011_LCRH_SPS (1 << 7)
|
||||
#define UART_PL011_LCRH_WLEN_8 (3 << 5)
|
||||
#define UART_PL011_LCRH_WLEN_7 (2 << 5)
|
||||
#define UART_PL011_LCRH_WLEN_6 (1 << 5)
|
||||
#define UART_PL011_LCRH_WLEN_5 (0 << 5)
|
||||
#define UART_PL011_LCRH_FEN (1 << 4)
|
||||
#define UART_PL011_LCRH_STP2 (1 << 3)
|
||||
#define UART_PL011_LCRH_EPS (1 << 2)
|
||||
#define UART_PL011_LCRH_PEN (1 << 1)
|
||||
#define UART_PL011_LCRH_BRK (1 << 0)
|
||||
|
||||
#define UART_PL011_CR_CTSEN (1 << 15)
|
||||
#define UART_PL011_CR_RTSEN (1 << 14)
|
||||
#define UART_PL011_CR_OUT2 (1 << 13)
|
||||
#define UART_PL011_CR_OUT1 (1 << 12)
|
||||
#define UART_PL011_CR_RTS (1 << 11)
|
||||
#define UART_PL011_CR_DTR (1 << 10)
|
||||
#define UART_PL011_CR_RXE (1 << 9)
|
||||
#define UART_PL011_CR_TXE (1 << 8)
|
||||
#define UART_PL011_CR_LPE (1 << 7)
|
||||
#define UART_PL011_CR_IIRLP (1 << 2)
|
||||
#define UART_PL011_CR_SIREN (1 << 1)
|
||||
#define UART_PL011_CR_UARTEN (1 << 0)
|
||||
|
||||
#define UART_PL011_IMSC_OEIM (1 << 10)
|
||||
#define UART_PL011_IMSC_BEIM (1 << 9)
|
||||
#define UART_PL011_IMSC_PEIM (1 << 8)
|
||||
#define UART_PL011_IMSC_FEIM (1 << 7)
|
||||
#define UART_PL011_IMSC_RTIM (1 << 6)
|
||||
#define UART_PL011_IMSC_TXIM (1 << 5)
|
||||
#define UART_PL011_IMSC_RXIM (1 << 4)
|
||||
#define UART_PL011_IMSC_DSRMIM (1 << 3)
|
||||
#define UART_PL011_IMSC_DCDMIM (1 << 2)
|
||||
#define UART_PL011_IMSC_CTSMIM (1 << 1)
|
||||
#define UART_PL011_IMSC_RIMIM (1 << 0)
|
||||
@@ -0,0 +1,341 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright (C) 2011 Marek Vasut <marek.vasut@gmail.com>
|
||||
*
|
||||
* (C) Copyright 2002
|
||||
* Wolfgang Denk, DENX Software Engineering, <wd@denx.de>
|
||||
*
|
||||
* (C) Copyright 2002
|
||||
* Sysgo Real-Time Solutions, GmbH <www.elinos.com>
|
||||
* Marius Groeger <mgroeger@sysgo.de>
|
||||
*
|
||||
* (C) Copyright 2002
|
||||
* Sysgo Real-Time Solutions, GmbH <www.elinos.com>
|
||||
* Alex Zuepke <azu@sysgo.de>
|
||||
*
|
||||
* Copyright (C) 1999 2000 2001 Erik Mouw (J.A.K.Mouw@its.tudelft.nl)
|
||||
*
|
||||
* Modified to add driver model (DM) support
|
||||
* (C) Copyright 2016 Marcel Ziswiler <marcel.ziswiler@toradex.com>
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <asm/arch/pxa-regs.h>
|
||||
#include <asm/arch/regs-uart.h>
|
||||
#include <asm/io.h>
|
||||
#include <dm.h>
|
||||
#include <dm/platform_data/serial_pxa.h>
|
||||
#include <linux/compiler.h>
|
||||
#include <serial.h>
|
||||
#include <watchdog.h>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
static uint32_t pxa_uart_get_baud_divider(int baudrate)
|
||||
{
|
||||
return 921600 / baudrate;
|
||||
}
|
||||
|
||||
static void pxa_uart_toggle_clock(uint32_t uart_index, int enable)
|
||||
{
|
||||
uint32_t clk_reg, clk_offset, reg;
|
||||
|
||||
clk_reg = UART_CLK_REG;
|
||||
clk_offset = UART_CLK_BASE << uart_index;
|
||||
|
||||
reg = readl(clk_reg);
|
||||
|
||||
if (enable)
|
||||
reg |= clk_offset;
|
||||
else
|
||||
reg &= ~clk_offset;
|
||||
|
||||
writel(reg, clk_reg);
|
||||
}
|
||||
|
||||
/*
|
||||
* Enable clock and set baud rate, parity etc.
|
||||
*/
|
||||
void pxa_setbrg_common(struct pxa_uart_regs *uart_regs, int port, int baudrate)
|
||||
{
|
||||
uint32_t divider = pxa_uart_get_baud_divider(baudrate);
|
||||
if (!divider)
|
||||
hang();
|
||||
|
||||
|
||||
pxa_uart_toggle_clock(port, 1);
|
||||
|
||||
/* Disable interrupts and FIFOs */
|
||||
writel(0, &uart_regs->ier);
|
||||
writel(0, &uart_regs->fcr);
|
||||
|
||||
/* Set baud rate */
|
||||
writel(LCR_WLS0 | LCR_WLS1 | LCR_DLAB, &uart_regs->lcr);
|
||||
writel(divider & 0xff, &uart_regs->dll);
|
||||
writel(divider >> 8, &uart_regs->dlh);
|
||||
writel(LCR_WLS0 | LCR_WLS1, &uart_regs->lcr);
|
||||
|
||||
/* Enable UART */
|
||||
writel(IER_UUE, &uart_regs->ier);
|
||||
}
|
||||
|
||||
#ifndef CONFIG_DM_SERIAL
|
||||
static struct pxa_uart_regs *pxa_uart_index_to_regs(uint32_t uart_index)
|
||||
{
|
||||
switch (uart_index) {
|
||||
case FFUART_INDEX: return (struct pxa_uart_regs *)FFUART_BASE;
|
||||
case BTUART_INDEX: return (struct pxa_uart_regs *)BTUART_BASE;
|
||||
case STUART_INDEX: return (struct pxa_uart_regs *)STUART_BASE;
|
||||
case HWUART_INDEX: return (struct pxa_uart_regs *)HWUART_BASE;
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Enable clock and set baud rate, parity etc.
|
||||
*/
|
||||
void pxa_setbrg_dev(uint32_t uart_index)
|
||||
{
|
||||
struct pxa_uart_regs *uart_regs = pxa_uart_index_to_regs(uart_index);
|
||||
if (!uart_regs)
|
||||
panic("Failed getting UART registers\n");
|
||||
|
||||
pxa_setbrg_common(uart_regs, uart_index, gd->baudrate);
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialise the serial port with the given baudrate. The settings
|
||||
* are always 8 data bits, no parity, 1 stop bit, no start bits.
|
||||
*/
|
||||
int pxa_init_dev(unsigned int uart_index)
|
||||
{
|
||||
pxa_setbrg_dev(uart_index);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Output a single byte to the serial port.
|
||||
*/
|
||||
void pxa_putc_dev(unsigned int uart_index, const char c)
|
||||
{
|
||||
struct pxa_uart_regs *uart_regs;
|
||||
|
||||
/* If \n, also do \r */
|
||||
if (c == '\n')
|
||||
pxa_putc_dev(uart_index, '\r');
|
||||
|
||||
uart_regs = pxa_uart_index_to_regs(uart_index);
|
||||
if (!uart_regs)
|
||||
hang();
|
||||
|
||||
while (!(readl(&uart_regs->lsr) & LSR_TEMT))
|
||||
WATCHDOG_RESET();
|
||||
writel(c, &uart_regs->thr);
|
||||
}
|
||||
|
||||
/*
|
||||
* Read a single byte from the serial port. Returns 1 on success, 0
|
||||
* otherwise. When the function is succesfull, the character read is
|
||||
* written into its argument c.
|
||||
*/
|
||||
int pxa_tstc_dev(unsigned int uart_index)
|
||||
{
|
||||
struct pxa_uart_regs *uart_regs;
|
||||
|
||||
uart_regs = pxa_uart_index_to_regs(uart_index);
|
||||
if (!uart_regs)
|
||||
return -1;
|
||||
|
||||
return readl(&uart_regs->lsr) & LSR_DR;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read a single byte from the serial port. Returns 1 on success, 0
|
||||
* otherwise. When the function is succesfull, the character read is
|
||||
* written into its argument c.
|
||||
*/
|
||||
int pxa_getc_dev(unsigned int uart_index)
|
||||
{
|
||||
struct pxa_uart_regs *uart_regs;
|
||||
|
||||
uart_regs = pxa_uart_index_to_regs(uart_index);
|
||||
if (!uart_regs)
|
||||
return -1;
|
||||
|
||||
while (!(readl(&uart_regs->lsr) & LSR_DR))
|
||||
WATCHDOG_RESET();
|
||||
return readl(&uart_regs->rbr) & 0xff;
|
||||
}
|
||||
|
||||
void pxa_puts_dev(unsigned int uart_index, const char *s)
|
||||
{
|
||||
while (*s)
|
||||
pxa_putc_dev(uart_index, *s++);
|
||||
}
|
||||
|
||||
#define pxa_uart(uart, UART) \
|
||||
int uart##_init(void) \
|
||||
{ \
|
||||
return pxa_init_dev(UART##_INDEX); \
|
||||
} \
|
||||
\
|
||||
void uart##_setbrg(void) \
|
||||
{ \
|
||||
return pxa_setbrg_dev(UART##_INDEX); \
|
||||
} \
|
||||
\
|
||||
void uart##_putc(const char c) \
|
||||
{ \
|
||||
return pxa_putc_dev(UART##_INDEX, c); \
|
||||
} \
|
||||
\
|
||||
void uart##_puts(const char *s) \
|
||||
{ \
|
||||
return pxa_puts_dev(UART##_INDEX, s); \
|
||||
} \
|
||||
\
|
||||
int uart##_getc(void) \
|
||||
{ \
|
||||
return pxa_getc_dev(UART##_INDEX); \
|
||||
} \
|
||||
\
|
||||
int uart##_tstc(void) \
|
||||
{ \
|
||||
return pxa_tstc_dev(UART##_INDEX); \
|
||||
} \
|
||||
|
||||
#define pxa_uart_desc(uart) \
|
||||
struct serial_device serial_##uart##_device = \
|
||||
{ \
|
||||
.name = "serial_"#uart, \
|
||||
.start = uart##_init, \
|
||||
.stop = NULL, \
|
||||
.setbrg = uart##_setbrg, \
|
||||
.getc = uart##_getc, \
|
||||
.tstc = uart##_tstc, \
|
||||
.putc = uart##_putc, \
|
||||
.puts = uart##_puts, \
|
||||
};
|
||||
|
||||
#define pxa_uart_multi(uart, UART) \
|
||||
pxa_uart(uart, UART) \
|
||||
pxa_uart_desc(uart)
|
||||
|
||||
#if defined(CONFIG_HWUART)
|
||||
pxa_uart_multi(hwuart, HWUART)
|
||||
#endif
|
||||
#if defined(CONFIG_STUART)
|
||||
pxa_uart_multi(stuart, STUART)
|
||||
#endif
|
||||
#if defined(CONFIG_FFUART)
|
||||
pxa_uart_multi(ffuart, FFUART)
|
||||
#endif
|
||||
#if defined(CONFIG_BTUART)
|
||||
pxa_uart_multi(btuart, BTUART)
|
||||
#endif
|
||||
|
||||
__weak struct serial_device *default_serial_console(void)
|
||||
{
|
||||
#if CONFIG_CONS_INDEX == 1
|
||||
return &serial_hwuart_device;
|
||||
#elif CONFIG_CONS_INDEX == 2
|
||||
return &serial_stuart_device;
|
||||
#elif CONFIG_CONS_INDEX == 3
|
||||
return &serial_ffuart_device;
|
||||
#elif CONFIG_CONS_INDEX == 4
|
||||
return &serial_btuart_device;
|
||||
#else
|
||||
#error "Bad CONFIG_CONS_INDEX."
|
||||
#endif
|
||||
}
|
||||
|
||||
void pxa_serial_initialize(void)
|
||||
{
|
||||
#if defined(CONFIG_FFUART)
|
||||
serial_register(&serial_ffuart_device);
|
||||
#endif
|
||||
#if defined(CONFIG_BTUART)
|
||||
serial_register(&serial_btuart_device);
|
||||
#endif
|
||||
#if defined(CONFIG_STUART)
|
||||
serial_register(&serial_stuart_device);
|
||||
#endif
|
||||
}
|
||||
#endif /* CONFIG_DM_SERIAL */
|
||||
|
||||
#ifdef CONFIG_DM_SERIAL
|
||||
static int pxa_serial_probe(struct udevice *dev)
|
||||
{
|
||||
struct pxa_serial_platdata *plat = dev->platdata;
|
||||
|
||||
pxa_setbrg_common((struct pxa_uart_regs *)plat->base, plat->port,
|
||||
plat->baudrate);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pxa_serial_putc(struct udevice *dev, const char ch)
|
||||
{
|
||||
struct pxa_serial_platdata *plat = dev->platdata;
|
||||
struct pxa_uart_regs *uart_regs = (struct pxa_uart_regs *)plat->base;
|
||||
|
||||
/* Wait for last character to go. */
|
||||
if (!(readl(&uart_regs->lsr) & LSR_TEMT))
|
||||
return -EAGAIN;
|
||||
|
||||
writel(ch, &uart_regs->thr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pxa_serial_getc(struct udevice *dev)
|
||||
{
|
||||
struct pxa_serial_platdata *plat = dev->platdata;
|
||||
struct pxa_uart_regs *uart_regs = (struct pxa_uart_regs *)plat->base;
|
||||
|
||||
/* Wait for a character to arrive. */
|
||||
if (!(readl(&uart_regs->lsr) & LSR_DR))
|
||||
return -EAGAIN;
|
||||
|
||||
return readl(&uart_regs->rbr) & 0xff;
|
||||
}
|
||||
|
||||
int pxa_serial_setbrg(struct udevice *dev, int baudrate)
|
||||
{
|
||||
struct pxa_serial_platdata *plat = dev->platdata;
|
||||
struct pxa_uart_regs *uart_regs = (struct pxa_uart_regs *)plat->base;
|
||||
int port = plat->port;
|
||||
|
||||
pxa_setbrg_common(uart_regs, port, baudrate);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pxa_serial_pending(struct udevice *dev, bool input)
|
||||
{
|
||||
struct pxa_serial_platdata *plat = dev->platdata;
|
||||
struct pxa_uart_regs *uart_regs = (struct pxa_uart_regs *)plat->base;
|
||||
|
||||
if (input)
|
||||
return readl(&uart_regs->lsr) & LSR_DR ? 1 : 0;
|
||||
else
|
||||
return readl(&uart_regs->lsr) & LSR_TEMT ? 0 : 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dm_serial_ops pxa_serial_ops = {
|
||||
.putc = pxa_serial_putc,
|
||||
.pending = pxa_serial_pending,
|
||||
.getc = pxa_serial_getc,
|
||||
.setbrg = pxa_serial_setbrg,
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(serial_pxa) = {
|
||||
.name = "serial_pxa",
|
||||
.id = UCLASS_SERIAL,
|
||||
.probe = pxa_serial_probe,
|
||||
.ops = &pxa_serial_ops,
|
||||
.flags = DM_FLAG_PRE_RELOC,
|
||||
};
|
||||
#endif /* CONFIG_DM_SERIAL */
|
||||
@@ -0,0 +1,60 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright (c) 2015 Google, Inc
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <debug_uart.h>
|
||||
#include <dm.h>
|
||||
#include <dt-structs.h>
|
||||
#include <ns16550.h>
|
||||
#include <serial.h>
|
||||
#include <asm/arch-rockchip/clock.h>
|
||||
|
||||
#if defined(CONFIG_ROCKCHIP_RK3188)
|
||||
struct rockchip_uart_platdata {
|
||||
struct dtd_rockchip_rk3188_uart dtplat;
|
||||
struct ns16550_platdata plat;
|
||||
};
|
||||
struct dtd_rockchip_rk3188_uart *dtplat, s_dtplat;
|
||||
#elif defined(CONFIG_ROCKCHIP_RK3288)
|
||||
struct rockchip_uart_platdata {
|
||||
struct dtd_rockchip_rk3288_uart dtplat;
|
||||
struct ns16550_platdata plat;
|
||||
};
|
||||
struct dtd_rockchip_rk3288_uart *dtplat, s_dtplat;
|
||||
#endif
|
||||
|
||||
static int rockchip_serial_probe(struct udevice *dev)
|
||||
{
|
||||
struct rockchip_uart_platdata *plat = dev_get_platdata(dev);
|
||||
|
||||
/* Create some new platform data for the standard driver */
|
||||
plat->plat.base = plat->dtplat.reg[0];
|
||||
plat->plat.reg_shift = plat->dtplat.reg_shift;
|
||||
plat->plat.clock = plat->dtplat.clock_frequency;
|
||||
plat->plat.fcr = UART_FCR_DEFVAL;
|
||||
dev->platdata = &plat->plat;
|
||||
|
||||
return ns16550_serial_probe(dev);
|
||||
}
|
||||
|
||||
U_BOOT_DRIVER(rockchip_rk3188_uart) = {
|
||||
.name = "rockchip_rk3188_uart",
|
||||
.id = UCLASS_SERIAL,
|
||||
.priv_auto_alloc_size = sizeof(struct NS16550),
|
||||
.platdata_auto_alloc_size = sizeof(struct rockchip_uart_platdata),
|
||||
.probe = rockchip_serial_probe,
|
||||
.ops = &ns16550_serial_ops,
|
||||
.flags = DM_FLAG_PRE_RELOC,
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(rockchip_rk3288_uart) = {
|
||||
.name = "rockchip_rk3288_uart",
|
||||
.id = UCLASS_SERIAL,
|
||||
.priv_auto_alloc_size = sizeof(struct NS16550),
|
||||
.platdata_auto_alloc_size = sizeof(struct rockchip_uart_platdata),
|
||||
.probe = rockchip_serial_probe,
|
||||
.ops = &ns16550_serial_ops,
|
||||
.flags = DM_FLAG_PRE_RELOC,
|
||||
};
|
||||
@@ -0,0 +1,240 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* (C) Copyright 2009 SAMSUNG Electronics
|
||||
* Minkyu Kang <mk7.kang@samsung.com>
|
||||
* Heungjun Kim <riverful.kim@samsung.com>
|
||||
*
|
||||
* based on drivers/serial/s3c64xx.c
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <dm.h>
|
||||
#include <errno.h>
|
||||
#include <fdtdec.h>
|
||||
#include <linux/compiler.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/arch/clk.h>
|
||||
#include <asm/arch/uart.h>
|
||||
#include <serial.h>
|
||||
#include <clk.h>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
#define RX_FIFO_COUNT_SHIFT 0
|
||||
#define RX_FIFO_COUNT_MASK (0xff << RX_FIFO_COUNT_SHIFT)
|
||||
#define RX_FIFO_FULL (1 << 8)
|
||||
#define TX_FIFO_COUNT_SHIFT 16
|
||||
#define TX_FIFO_COUNT_MASK (0xff << TX_FIFO_COUNT_SHIFT)
|
||||
#define TX_FIFO_FULL (1 << 24)
|
||||
|
||||
/* Information about a serial port */
|
||||
struct s5p_serial_platdata {
|
||||
struct s5p_uart *reg; /* address of registers in physical memory */
|
||||
u8 port_id; /* uart port number */
|
||||
};
|
||||
|
||||
/*
|
||||
* The coefficient, used to calculate the baudrate on S5P UARTs is
|
||||
* calculated as
|
||||
* C = UBRDIV * 16 + number_of_set_bits_in_UDIVSLOT
|
||||
* however, section 31.6.11 of the datasheet doesn't recomment using 1 for 1,
|
||||
* 3 for 2, ... (2^n - 1) for n, instead, they suggest using these constants:
|
||||
*/
|
||||
static const int udivslot[] = {
|
||||
0,
|
||||
0x0080,
|
||||
0x0808,
|
||||
0x0888,
|
||||
0x2222,
|
||||
0x4924,
|
||||
0x4a52,
|
||||
0x54aa,
|
||||
0x5555,
|
||||
0xd555,
|
||||
0xd5d5,
|
||||
0xddd5,
|
||||
0xdddd,
|
||||
0xdfdd,
|
||||
0xdfdf,
|
||||
0xffdf,
|
||||
};
|
||||
|
||||
static void __maybe_unused s5p_serial_init(struct s5p_uart *uart)
|
||||
{
|
||||
/* enable FIFOs, auto clear Rx FIFO */
|
||||
writel(0x3, &uart->ufcon);
|
||||
writel(0, &uart->umcon);
|
||||
/* 8N1 */
|
||||
writel(0x3, &uart->ulcon);
|
||||
/* No interrupts, no DMA, pure polling */
|
||||
writel(0x245, &uart->ucon);
|
||||
}
|
||||
|
||||
static void __maybe_unused s5p_serial_baud(struct s5p_uart *uart, uint uclk,
|
||||
int baudrate)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
val = uclk / baudrate;
|
||||
|
||||
writel(val / 16 - 1, &uart->ubrdiv);
|
||||
|
||||
if (s5p_uart_divslot())
|
||||
writew(udivslot[val % 16], &uart->rest.slot);
|
||||
else
|
||||
writeb(val % 16, &uart->rest.value);
|
||||
}
|
||||
|
||||
#ifndef CONFIG_SPL_BUILD
|
||||
int s5p_serial_setbrg(struct udevice *dev, int baudrate)
|
||||
{
|
||||
struct s5p_serial_platdata *plat = dev->platdata;
|
||||
struct s5p_uart *const uart = plat->reg;
|
||||
u32 uclk;
|
||||
|
||||
#ifdef CONFIG_CLK_EXYNOS
|
||||
struct clk clk;
|
||||
u32 ret;
|
||||
|
||||
ret = clk_get_by_index(dev, 1, &clk);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
uclk = clk_get_rate(&clk);
|
||||
#else
|
||||
uclk = get_uart_clk(plat->port_id);
|
||||
#endif
|
||||
|
||||
s5p_serial_baud(uart, uclk, baudrate);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int s5p_serial_probe(struct udevice *dev)
|
||||
{
|
||||
struct s5p_serial_platdata *plat = dev->platdata;
|
||||
struct s5p_uart *const uart = plat->reg;
|
||||
|
||||
s5p_serial_init(uart);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int serial_err_check(const struct s5p_uart *const uart, int op)
|
||||
{
|
||||
unsigned int mask;
|
||||
|
||||
/*
|
||||
* UERSTAT
|
||||
* Break Detect [3]
|
||||
* Frame Err [2] : receive operation
|
||||
* Parity Err [1] : receive operation
|
||||
* Overrun Err [0] : receive operation
|
||||
*/
|
||||
if (op)
|
||||
mask = 0x8;
|
||||
else
|
||||
mask = 0xf;
|
||||
|
||||
return readl(&uart->uerstat) & mask;
|
||||
}
|
||||
|
||||
static int s5p_serial_getc(struct udevice *dev)
|
||||
{
|
||||
struct s5p_serial_platdata *plat = dev->platdata;
|
||||
struct s5p_uart *const uart = plat->reg;
|
||||
|
||||
if (!(readl(&uart->ufstat) & RX_FIFO_COUNT_MASK))
|
||||
return -EAGAIN;
|
||||
|
||||
serial_err_check(uart, 0);
|
||||
return (int)(readb(&uart->urxh) & 0xff);
|
||||
}
|
||||
|
||||
static int s5p_serial_putc(struct udevice *dev, const char ch)
|
||||
{
|
||||
struct s5p_serial_platdata *plat = dev->platdata;
|
||||
struct s5p_uart *const uart = plat->reg;
|
||||
|
||||
if (readl(&uart->ufstat) & TX_FIFO_FULL)
|
||||
return -EAGAIN;
|
||||
|
||||
writeb(ch, &uart->utxh);
|
||||
serial_err_check(uart, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int s5p_serial_pending(struct udevice *dev, bool input)
|
||||
{
|
||||
struct s5p_serial_platdata *plat = dev->platdata;
|
||||
struct s5p_uart *const uart = plat->reg;
|
||||
uint32_t ufstat = readl(&uart->ufstat);
|
||||
|
||||
if (input)
|
||||
return (ufstat & RX_FIFO_COUNT_MASK) >> RX_FIFO_COUNT_SHIFT;
|
||||
else
|
||||
return (ufstat & TX_FIFO_COUNT_MASK) >> TX_FIFO_COUNT_SHIFT;
|
||||
}
|
||||
|
||||
static int s5p_serial_ofdata_to_platdata(struct udevice *dev)
|
||||
{
|
||||
struct s5p_serial_platdata *plat = dev->platdata;
|
||||
fdt_addr_t addr;
|
||||
|
||||
addr = devfdt_get_addr(dev);
|
||||
if (addr == FDT_ADDR_T_NONE)
|
||||
return -EINVAL;
|
||||
|
||||
plat->reg = (struct s5p_uart *)addr;
|
||||
plat->port_id = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev),
|
||||
"id", dev->seq);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dm_serial_ops s5p_serial_ops = {
|
||||
.putc = s5p_serial_putc,
|
||||
.pending = s5p_serial_pending,
|
||||
.getc = s5p_serial_getc,
|
||||
.setbrg = s5p_serial_setbrg,
|
||||
};
|
||||
|
||||
static const struct udevice_id s5p_serial_ids[] = {
|
||||
{ .compatible = "samsung,exynos4210-uart" },
|
||||
{ }
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(serial_s5p) = {
|
||||
.name = "serial_s5p",
|
||||
.id = UCLASS_SERIAL,
|
||||
.of_match = s5p_serial_ids,
|
||||
.ofdata_to_platdata = s5p_serial_ofdata_to_platdata,
|
||||
.platdata_auto_alloc_size = sizeof(struct s5p_serial_platdata),
|
||||
.probe = s5p_serial_probe,
|
||||
.ops = &s5p_serial_ops,
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_DEBUG_UART_S5P
|
||||
|
||||
#include <debug_uart.h>
|
||||
|
||||
static inline void _debug_uart_init(void)
|
||||
{
|
||||
struct s5p_uart *uart = (struct s5p_uart *)CONFIG_DEBUG_UART_BASE;
|
||||
|
||||
s5p_serial_init(uart);
|
||||
s5p_serial_baud(uart, CONFIG_DEBUG_UART_CLOCK, CONFIG_BAUDRATE);
|
||||
}
|
||||
|
||||
static inline void _debug_uart_putc(int ch)
|
||||
{
|
||||
struct s5p_uart *uart = (struct s5p_uart *)CONFIG_DEBUG_UART_BASE;
|
||||
|
||||
while (readl(&uart->ufstat) & TX_FIFO_FULL);
|
||||
|
||||
writeb(ch, &uart->utxh);
|
||||
}
|
||||
|
||||
DEBUG_UART_FUNCS
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,364 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* SuperH SCIF device driver.
|
||||
* Copyright (C) 2013 Renesas Electronics Corporation
|
||||
* Copyright (C) 2007,2008,2010, 2014 Nobuhiro Iwamatsu
|
||||
* Copyright (C) 2002 - 2008 Paul Mundt
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <errno.h>
|
||||
#include <clk.h>
|
||||
#include <dm.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/processor.h>
|
||||
#include <serial.h>
|
||||
#include <linux/compiler.h>
|
||||
#include <dm/platform_data/serial_sh.h>
|
||||
#include "serial_sh.h"
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
#if defined(CONFIG_CPU_SH7780)
|
||||
static int scif_rxfill(struct uart_port *port)
|
||||
{
|
||||
return sci_in(port, SCRFDR) & 0xff;
|
||||
}
|
||||
#elif defined(CONFIG_CPU_SH7763)
|
||||
static int scif_rxfill(struct uart_port *port)
|
||||
{
|
||||
if ((port->mapbase == 0xffe00000) ||
|
||||
(port->mapbase == 0xffe08000)) {
|
||||
/* SCIF0/1*/
|
||||
return sci_in(port, SCRFDR) & 0xff;
|
||||
} else {
|
||||
/* SCIF2 */
|
||||
return sci_in(port, SCFDR) & SCIF2_RFDC_MASK;
|
||||
}
|
||||
}
|
||||
#else
|
||||
static int scif_rxfill(struct uart_port *port)
|
||||
{
|
||||
return sci_in(port, SCFDR) & SCIF_RFDC_MASK;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void sh_serial_init_generic(struct uart_port *port)
|
||||
{
|
||||
sci_out(port, SCSCR , SCSCR_INIT(port));
|
||||
sci_out(port, SCSCR , SCSCR_INIT(port));
|
||||
sci_out(port, SCSMR, 0);
|
||||
sci_out(port, SCSMR, 0);
|
||||
sci_out(port, SCFCR, SCFCR_RFRST|SCFCR_TFRST);
|
||||
sci_in(port, SCFCR);
|
||||
sci_out(port, SCFCR, 0);
|
||||
#if defined(CONFIG_RZA1)
|
||||
sci_out(port, SCSPTR, 0x0003);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
sh_serial_setbrg_generic(struct uart_port *port, int clk, int baudrate)
|
||||
{
|
||||
if (port->clk_mode == EXT_CLK) {
|
||||
unsigned short dl = DL_VALUE(baudrate, clk);
|
||||
sci_out(port, DL, dl);
|
||||
/* Need wait: Clock * 1/dl * 1/16 */
|
||||
udelay((1000000 * dl * 16 / clk) * 1000 + 1);
|
||||
} else {
|
||||
sci_out(port, SCBRR, SCBRR_VALUE(baudrate, clk));
|
||||
}
|
||||
}
|
||||
|
||||
static void handle_error(struct uart_port *port)
|
||||
{
|
||||
sci_in(port, SCxSR);
|
||||
sci_out(port, SCxSR, SCxSR_ERROR_CLEAR(port));
|
||||
sci_in(port, SCLSR);
|
||||
sci_out(port, SCLSR, 0x00);
|
||||
}
|
||||
|
||||
static int serial_raw_putc(struct uart_port *port, const char c)
|
||||
{
|
||||
/* Tx fifo is empty */
|
||||
if (!(sci_in(port, SCxSR) & SCxSR_TEND(port)))
|
||||
return -EAGAIN;
|
||||
|
||||
sci_out(port, SCxTDR, c);
|
||||
sci_out(port, SCxSR, sci_in(port, SCxSR) & ~SCxSR_TEND(port));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int serial_rx_fifo_level(struct uart_port *port)
|
||||
{
|
||||
return scif_rxfill(port);
|
||||
}
|
||||
|
||||
static int sh_serial_tstc_generic(struct uart_port *port)
|
||||
{
|
||||
if (sci_in(port, SCxSR) & SCIF_ERRORS) {
|
||||
handle_error(port);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return serial_rx_fifo_level(port) ? 1 : 0;
|
||||
}
|
||||
|
||||
static int serial_getc_check(struct uart_port *port)
|
||||
{
|
||||
unsigned short status;
|
||||
|
||||
status = sci_in(port, SCxSR);
|
||||
|
||||
if (status & SCIF_ERRORS)
|
||||
handle_error(port);
|
||||
if (sci_in(port, SCLSR) & SCxSR_ORER(port))
|
||||
handle_error(port);
|
||||
return status & (SCIF_DR | SCxSR_RDxF(port));
|
||||
}
|
||||
|
||||
static int sh_serial_getc_generic(struct uart_port *port)
|
||||
{
|
||||
unsigned short status;
|
||||
char ch;
|
||||
|
||||
if (!serial_getc_check(port))
|
||||
return -EAGAIN;
|
||||
|
||||
ch = sci_in(port, SCxRDR);
|
||||
status = sci_in(port, SCxSR);
|
||||
|
||||
sci_out(port, SCxSR, SCxSR_RDxF_CLEAR(port));
|
||||
|
||||
if (status & SCIF_ERRORS)
|
||||
handle_error(port);
|
||||
|
||||
if (sci_in(port, SCLSR) & SCxSR_ORER(port))
|
||||
handle_error(port);
|
||||
|
||||
return ch;
|
||||
}
|
||||
|
||||
#if CONFIG_IS_ENABLED(DM_SERIAL)
|
||||
|
||||
static int sh_serial_pending(struct udevice *dev, bool input)
|
||||
{
|
||||
struct uart_port *priv = dev_get_priv(dev);
|
||||
|
||||
return sh_serial_tstc_generic(priv);
|
||||
}
|
||||
|
||||
static int sh_serial_putc(struct udevice *dev, const char ch)
|
||||
{
|
||||
struct uart_port *priv = dev_get_priv(dev);
|
||||
|
||||
return serial_raw_putc(priv, ch);
|
||||
}
|
||||
|
||||
static int sh_serial_getc(struct udevice *dev)
|
||||
{
|
||||
struct uart_port *priv = dev_get_priv(dev);
|
||||
|
||||
return sh_serial_getc_generic(priv);
|
||||
}
|
||||
|
||||
static int sh_serial_setbrg(struct udevice *dev, int baudrate)
|
||||
{
|
||||
struct sh_serial_platdata *plat = dev_get_platdata(dev);
|
||||
struct uart_port *priv = dev_get_priv(dev);
|
||||
|
||||
sh_serial_setbrg_generic(priv, plat->clk, baudrate);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sh_serial_probe(struct udevice *dev)
|
||||
{
|
||||
struct sh_serial_platdata *plat = dev_get_platdata(dev);
|
||||
struct uart_port *priv = dev_get_priv(dev);
|
||||
|
||||
priv->membase = (unsigned char *)plat->base;
|
||||
priv->mapbase = plat->base;
|
||||
priv->type = plat->type;
|
||||
priv->clk_mode = plat->clk_mode;
|
||||
|
||||
sh_serial_init_generic(priv);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dm_serial_ops sh_serial_ops = {
|
||||
.putc = sh_serial_putc,
|
||||
.pending = sh_serial_pending,
|
||||
.getc = sh_serial_getc,
|
||||
.setbrg = sh_serial_setbrg,
|
||||
};
|
||||
|
||||
#if CONFIG_IS_ENABLED(OF_CONTROL)
|
||||
static const struct udevice_id sh_serial_id[] ={
|
||||
{.compatible = "renesas,sci", .data = PORT_SCI},
|
||||
{.compatible = "renesas,scif", .data = PORT_SCIF},
|
||||
{.compatible = "renesas,scifa", .data = PORT_SCIFA},
|
||||
{}
|
||||
};
|
||||
|
||||
static int sh_serial_ofdata_to_platdata(struct udevice *dev)
|
||||
{
|
||||
struct sh_serial_platdata *plat = dev_get_platdata(dev);
|
||||
struct clk sh_serial_clk;
|
||||
fdt_addr_t addr;
|
||||
int ret;
|
||||
|
||||
addr = devfdt_get_addr(dev);
|
||||
if (!addr)
|
||||
return -EINVAL;
|
||||
|
||||
plat->base = addr;
|
||||
|
||||
ret = clk_get_by_name(dev, "fck", &sh_serial_clk);
|
||||
if (!ret) {
|
||||
ret = clk_enable(&sh_serial_clk);
|
||||
if (!ret)
|
||||
plat->clk = clk_get_rate(&sh_serial_clk);
|
||||
} else {
|
||||
plat->clk = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev),
|
||||
"clock", 1);
|
||||
}
|
||||
|
||||
plat->type = dev_get_driver_data(dev);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
U_BOOT_DRIVER(serial_sh) = {
|
||||
.name = "serial_sh",
|
||||
.id = UCLASS_SERIAL,
|
||||
.of_match = of_match_ptr(sh_serial_id),
|
||||
.ofdata_to_platdata = of_match_ptr(sh_serial_ofdata_to_platdata),
|
||||
.platdata_auto_alloc_size = sizeof(struct sh_serial_platdata),
|
||||
.probe = sh_serial_probe,
|
||||
.ops = &sh_serial_ops,
|
||||
#if !CONFIG_IS_ENABLED(OF_CONTROL)
|
||||
.flags = DM_FLAG_PRE_RELOC,
|
||||
#endif
|
||||
.priv_auto_alloc_size = sizeof(struct uart_port),
|
||||
};
|
||||
|
||||
#else /* CONFIG_DM_SERIAL */
|
||||
|
||||
#if defined(CONFIG_CONS_SCIF0)
|
||||
# define SCIF_BASE SCIF0_BASE
|
||||
#elif defined(CONFIG_CONS_SCIF1)
|
||||
# define SCIF_BASE SCIF1_BASE
|
||||
#elif defined(CONFIG_CONS_SCIF2)
|
||||
# define SCIF_BASE SCIF2_BASE
|
||||
#elif defined(CONFIG_CONS_SCIF3)
|
||||
# define SCIF_BASE SCIF3_BASE
|
||||
#elif defined(CONFIG_CONS_SCIF4)
|
||||
# define SCIF_BASE SCIF4_BASE
|
||||
#elif defined(CONFIG_CONS_SCIF5)
|
||||
# define SCIF_BASE SCIF5_BASE
|
||||
#elif defined(CONFIG_CONS_SCIF6)
|
||||
# define SCIF_BASE SCIF6_BASE
|
||||
#elif defined(CONFIG_CONS_SCIF7)
|
||||
# define SCIF_BASE SCIF7_BASE
|
||||
#elif defined(CONFIG_CONS_SCIFA0)
|
||||
# define SCIF_BASE SCIFA0_BASE
|
||||
#else
|
||||
# error "Default SCIF doesn't set....."
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SCIF_A)
|
||||
#define SCIF_BASE_PORT PORT_SCIFA
|
||||
#elif defined(CONFIG_SCI)
|
||||
#define SCIF_BASE_PORT PORT_SCI
|
||||
#else
|
||||
#define SCIF_BASE_PORT PORT_SCIF
|
||||
#endif
|
||||
|
||||
static struct uart_port sh_sci = {
|
||||
.membase = (unsigned char *)SCIF_BASE,
|
||||
.mapbase = SCIF_BASE,
|
||||
.type = SCIF_BASE_PORT,
|
||||
#ifdef CONFIG_SCIF_USE_EXT_CLK
|
||||
.clk_mode = EXT_CLK,
|
||||
#endif
|
||||
};
|
||||
|
||||
static void sh_serial_setbrg(void)
|
||||
{
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
struct uart_port *port = &sh_sci;
|
||||
|
||||
sh_serial_setbrg_generic(port, CONFIG_SH_SCIF_CLK_FREQ, gd->baudrate);
|
||||
}
|
||||
|
||||
static int sh_serial_init(void)
|
||||
{
|
||||
struct uart_port *port = &sh_sci;
|
||||
|
||||
sh_serial_init_generic(port);
|
||||
serial_setbrg();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void sh_serial_putc(const char c)
|
||||
{
|
||||
struct uart_port *port = &sh_sci;
|
||||
|
||||
if (c == '\n') {
|
||||
while (1) {
|
||||
if (serial_raw_putc(port, '\r') != -EAGAIN)
|
||||
break;
|
||||
}
|
||||
}
|
||||
while (1) {
|
||||
if (serial_raw_putc(port, c) != -EAGAIN)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int sh_serial_tstc(void)
|
||||
{
|
||||
struct uart_port *port = &sh_sci;
|
||||
|
||||
return sh_serial_tstc_generic(port);
|
||||
}
|
||||
|
||||
static int sh_serial_getc(void)
|
||||
{
|
||||
struct uart_port *port = &sh_sci;
|
||||
int ch;
|
||||
|
||||
while (1) {
|
||||
ch = sh_serial_getc_generic(port);
|
||||
if (ch != -EAGAIN)
|
||||
break;
|
||||
}
|
||||
|
||||
return ch;
|
||||
}
|
||||
|
||||
static struct serial_device sh_serial_drv = {
|
||||
.name = "sh_serial",
|
||||
.start = sh_serial_init,
|
||||
.stop = NULL,
|
||||
.setbrg = sh_serial_setbrg,
|
||||
.putc = sh_serial_putc,
|
||||
.puts = default_serial_puts,
|
||||
.getc = sh_serial_getc,
|
||||
.tstc = sh_serial_tstc,
|
||||
};
|
||||
|
||||
void sh_serial_initialize(void)
|
||||
{
|
||||
serial_register(&sh_serial_drv);
|
||||
}
|
||||
|
||||
__weak struct serial_device *default_serial_console(void)
|
||||
{
|
||||
return &sh_serial_drv;
|
||||
}
|
||||
#endif /* CONFIG_DM_SERIAL */
|
||||
@@ -0,0 +1,505 @@
|
||||
/*
|
||||
* Copy and modify from linux/drivers/serial/sh-sci.h
|
||||
*/
|
||||
|
||||
#include <dm/platform_data/serial_sh.h>
|
||||
|
||||
struct uart_port {
|
||||
unsigned long iobase; /* in/out[bwl] */
|
||||
unsigned char *membase; /* read/write[bwl] */
|
||||
unsigned long mapbase; /* for ioremap */
|
||||
enum sh_serial_type type; /* port type */
|
||||
enum sh_clk_mode clk_mode; /* clock mode */
|
||||
};
|
||||
|
||||
#if defined(CONFIG_CPU_SH7721) || \
|
||||
defined(CONFIG_SH73A0) || \
|
||||
defined(CONFIG_R8A7740)
|
||||
# define SCSCR_INIT(port) 0x0030 /* TIE=0,RIE=0,TE=1,RE=1 */
|
||||
# define PORT_PTCR 0xA405011EUL
|
||||
# define PORT_PVCR 0xA4050122UL
|
||||
# define SCIF_ORER 0x0200 /* overrun error bit */
|
||||
#elif defined(CONFIG_CPU_SH7750) || \
|
||||
defined(CONFIG_CPU_SH7750R) || \
|
||||
defined(CONFIG_CPU_SH7750S) || \
|
||||
defined(CONFIG_CPU_SH7751) || \
|
||||
defined(CONFIG_CPU_SH7751R)
|
||||
# define SCSPTR1 0xffe0001c /* 8 bit SCI */
|
||||
# define SCSPTR2 0xFFE80020 /* 16 bit SCIF */
|
||||
# define SCIF_ORER 0x0001 /* overrun error bit */
|
||||
# define SCSCR_INIT(port) (((port)->type == PORT_SCI) ? \
|
||||
0x30 /* TIE=0,RIE=0,TE=1,RE=1 */ : \
|
||||
0x38 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */)
|
||||
#elif defined(CONFIG_CPU_SH7722)
|
||||
# define PADR 0xA4050120
|
||||
# undef PSDR
|
||||
# define PSDR 0xA405013e
|
||||
# define PWDR 0xA4050166
|
||||
# define PSCR 0xA405011E
|
||||
# define SCIF_ORER 0x0001 /* overrun error bit */
|
||||
# define SCSCR_INIT(port) 0x0038 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */
|
||||
#elif defined(CONFIG_CPU_SH7723)
|
||||
# define SCSPTR0 0xa4050160
|
||||
# define SCSPTR1 0xa405013e
|
||||
# define SCSPTR2 0xa4050160
|
||||
# define SCSPTR3 0xa405013e
|
||||
# define SCSPTR4 0xa4050128
|
||||
# define SCSPTR5 0xa4050128
|
||||
# define SCIF_ORER 0x0001 /* overrun error bit */
|
||||
# define SCSCR_INIT(port) 0x0038 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */
|
||||
#elif defined(CONFIG_CPU_SH7734)
|
||||
# define SCSPTR0 0xFFE40020
|
||||
# define SCSPTR1 0xFFE41020
|
||||
# define SCSPTR2 0xFFE42020
|
||||
# define SCSPTR3 0xFFE43020
|
||||
# define SCSPTR4 0xFFE44020
|
||||
# define SCSPTR5 0xFFE45020
|
||||
# define SCIF_ORER 0x0001 /* overrun error bit */
|
||||
# define SCSCR_INIT(port) 0x0038 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */
|
||||
#elif defined(CONFIG_CPU_SH7757) || \
|
||||
defined(CONFIG_CPU_SH7752) || \
|
||||
defined(CONFIG_CPU_SH7753)
|
||||
# define SCSPTR0 0xfe4b0020
|
||||
# define SCSPTR1 0xfe4b0020
|
||||
# define SCSPTR2 0xfe4b0020
|
||||
# define SCIF_ORER 0x0001
|
||||
# define SCSCR_INIT(port) 0x38
|
||||
# define SCIF_ONLY
|
||||
#elif defined(CONFIG_CPU_SH7763)
|
||||
# define SCSPTR0 0xffe00024 /* 16 bit SCIF */
|
||||
# define SCSPTR1 0xffe08024 /* 16 bit SCIF */
|
||||
# define SCSPTR2 0xffe10020 /* 16 bit SCIF/IRDA */
|
||||
# define SCIF_ORER 0x0001 /* overrun error bit */
|
||||
# define SCSCR_INIT(port) 0x38 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */
|
||||
#elif defined(CONFIG_CPU_SH7780)
|
||||
# define SCSPTR0 0xffe00024 /* 16 bit SCIF */
|
||||
# define SCSPTR1 0xffe10024 /* 16 bit SCIF */
|
||||
# define SCIF_ORER 0x0001 /* Overrun error bit */
|
||||
|
||||
/* TIE=0,RIE=0,TE=1,RE=1,REIE=1,CKE1=1 */
|
||||
# define SCSCR_INIT(port) 0x3a
|
||||
|
||||
#elif defined(CONFIG_RZA1)
|
||||
# define SCSPTR0 0xe8007020 /* 16 bit SCIF */
|
||||
# define SCSPTR1 0xe8007820 /* 16 bit SCIF */
|
||||
# define SCSPTR2 0xe8008020 /* 16 bit SCIF */
|
||||
# define SCSPTR3 0xe8008820 /* 16 bit SCIF */
|
||||
# define SCSPTR4 0xe8009020 /* 16 bit SCIF */
|
||||
# define SCSPTR5 0xe8009820 /* 16 bit SCIF */
|
||||
# define SCSPTR6 0xe800a020 /* 16 bit SCIF */
|
||||
# define SCSPTR7 0xe800a820 /* 16 bit SCIF */
|
||||
# define SCSCR_INIT(port) 0x38 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */
|
||||
# define SCIF_ORER 0x0001 /* overrun error bit */
|
||||
#elif defined(CONFIG_RCAR_GEN2) || defined(CONFIG_RCAR_GEN3) || \
|
||||
defined(CONFIG_R7S72100)
|
||||
# if defined(CONFIG_SCIF_A)
|
||||
# define SCIF_ORER 0x0200
|
||||
# else
|
||||
# define SCIF_ORER 0x0001
|
||||
# endif
|
||||
# define SCSCR_INIT(port) (port->clk_mode == EXT_CLK ? 0x32 : 0x30)
|
||||
/* TIE=0,RIE=0,TE=1,RE=1,REIE=0, */
|
||||
#else
|
||||
# error CPU subtype not defined
|
||||
#endif
|
||||
|
||||
/* SCSCR */
|
||||
#define SCI_CTRL_FLAGS_TIE 0x80 /* all */
|
||||
#define SCI_CTRL_FLAGS_RIE 0x40 /* all */
|
||||
#define SCI_CTRL_FLAGS_TE 0x20 /* all */
|
||||
#define SCI_CTRL_FLAGS_RE 0x10 /* all */
|
||||
#if defined(CONFIG_CPU_SH7750) || \
|
||||
defined(CONFIG_CPU_SH7750R) || \
|
||||
defined(CONFIG_CPU_SH7722) || \
|
||||
defined(CONFIG_CPU_SH7734) || \
|
||||
defined(CONFIG_CPU_SH7750S) || \
|
||||
defined(CONFIG_CPU_SH7751) || \
|
||||
defined(CONFIG_CPU_SH7751R) || \
|
||||
defined(CONFIG_CPU_SH7763) || \
|
||||
defined(CONFIG_CPU_SH7780)
|
||||
#define SCI_CTRL_FLAGS_REIE 0x08 /* 7750 SCIF */
|
||||
#else
|
||||
#define SCI_CTRL_FLAGS_REIE 0
|
||||
#endif
|
||||
/* SCI_CTRL_FLAGS_MPIE 0x08 * 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */
|
||||
/* SCI_CTRL_FLAGS_TEIE 0x04 * 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */
|
||||
/* SCI_CTRL_FLAGS_CKE1 0x02 * all */
|
||||
/* SCI_CTRL_FLAGS_CKE0 0x01 * 7707 SCI/SCIF, 7708 SCI, 7709 SCI/SCIF, 7750 SCI */
|
||||
|
||||
/* SCxSR SCI */
|
||||
#define SCI_TDRE 0x80 /* 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */
|
||||
#define SCI_RDRF 0x40 /* 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */
|
||||
#define SCI_ORER 0x20 /* 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */
|
||||
#define SCI_FER 0x10 /* 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */
|
||||
#define SCI_PER 0x08 /* 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */
|
||||
#define SCI_TEND 0x04 /* 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */
|
||||
/* SCI_MPB 0x02 * 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */
|
||||
/* SCI_MPBT 0x01 * 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */
|
||||
|
||||
#define SCI_ERRORS ( SCI_PER | SCI_FER | SCI_ORER)
|
||||
|
||||
/* SCxSR SCIF */
|
||||
#define SCIF_ER 0x0080 /* 7705 SCIF, 7707 SCIF, 7709 SCIF, 7750 SCIF */
|
||||
#define SCIF_TEND 0x0040 /* 7705 SCIF, 7707 SCIF, 7709 SCIF, 7750 SCIF */
|
||||
#define SCIF_TDFE 0x0020 /* 7705 SCIF, 7707 SCIF, 7709 SCIF, 7750 SCIF */
|
||||
#define SCIF_BRK 0x0010 /* 7705 SCIF, 7707 SCIF, 7709 SCIF, 7750 SCIF */
|
||||
#define SCIF_FER 0x0008 /* 7705 SCIF, 7707 SCIF, 7709 SCIF, 7750 SCIF */
|
||||
#define SCIF_PER 0x0004 /* 7705 SCIF, 7707 SCIF, 7709 SCIF, 7750 SCIF */
|
||||
#define SCIF_RDF 0x0002 /* 7705 SCIF, 7707 SCIF, 7709 SCIF, 7750 SCIF */
|
||||
#define SCIF_DR 0x0001 /* 7705 SCIF, 7707 SCIF, 7709 SCIF, 7750 SCIF */
|
||||
|
||||
#if defined(CONFIG_CPU_SH7721) || \
|
||||
defined(CONFIG_SH73A0) || \
|
||||
defined(CONFIG_R8A7740)
|
||||
# define SCIF_ORER 0x0200
|
||||
# define SCIF_ERRORS (SCIF_PER | SCIF_FER | SCIF_ER | SCIF_BRK | SCIF_ORER)
|
||||
# define SCIF_RFDC_MASK 0x007f
|
||||
# define SCIF_TXROOM_MAX 64
|
||||
#elif defined(CONFIG_CPU_SH7763)
|
||||
# define SCIF_ERRORS (SCIF_PER | SCIF_FER | SCIF_ER | SCIF_BRK)
|
||||
# define SCIF_RFDC_MASK 0x007f
|
||||
# define SCIF_TXROOM_MAX 64
|
||||
/* SH7763 SCIF2 support */
|
||||
# define SCIF2_RFDC_MASK 0x001f
|
||||
# define SCIF2_TXROOM_MAX 16
|
||||
#elif defined(CONFIG_RCAR_GEN2)
|
||||
# define SCIF_ERRORS (SCIF_PER | SCIF_FER | SCIF_ER | SCIF_BRK)
|
||||
# if defined(CONFIG_SCIF_A)
|
||||
# define SCIF_RFDC_MASK 0x007f
|
||||
# else
|
||||
# define SCIF_RFDC_MASK 0x001f
|
||||
# endif
|
||||
#else
|
||||
# define SCIF_ERRORS (SCIF_PER | SCIF_FER | SCIF_ER | SCIF_BRK)
|
||||
# define SCIF_RFDC_MASK 0x001f
|
||||
# define SCIF_TXROOM_MAX 16
|
||||
#endif
|
||||
|
||||
#ifndef SCIF_ORER
|
||||
#define SCIF_ORER 0x0000
|
||||
#endif
|
||||
|
||||
#define SCxSR_TEND(port)\
|
||||
(((port)->type == PORT_SCI) ? SCI_TEND : SCIF_TEND)
|
||||
#define SCxSR_ERRORS(port)\
|
||||
(((port)->type == PORT_SCI) ? SCI_ERRORS : SCIF_ERRORS)
|
||||
#define SCxSR_RDxF(port)\
|
||||
(((port)->type == PORT_SCI) ? SCI_RDRF : SCIF_RDF)
|
||||
#define SCxSR_TDxE(port)\
|
||||
(((port)->type == PORT_SCI) ? SCI_TDRE : SCIF_TDFE)
|
||||
#define SCxSR_FER(port)\
|
||||
(((port)->type == PORT_SCI) ? SCI_FER : SCIF_FER)
|
||||
#define SCxSR_PER(port)\
|
||||
(((port)->type == PORT_SCI) ? SCI_PER : SCIF_PER)
|
||||
#define SCxSR_BRK(port)\
|
||||
((port)->type == PORT_SCI) ? 0x00 : SCIF_BRK)
|
||||
#define SCxSR_ORER(port)\
|
||||
(((port)->type == PORT_SCI) ? SCI_ORER : SCIF_ORER)
|
||||
|
||||
#if defined(CONFIG_CPU_SH7721) || \
|
||||
defined(CONFIG_SH73A0) || \
|
||||
defined(CONFIG_R8A7740)
|
||||
# define SCxSR_RDxF_CLEAR(port) (sci_in(port, SCxSR) & 0xfffc)
|
||||
# define SCxSR_ERROR_CLEAR(port) (sci_in(port, SCxSR) & 0xfd73)
|
||||
# define SCxSR_TDxE_CLEAR(port) (sci_in(port, SCxSR) & 0xffdf)
|
||||
# define SCxSR_BREAK_CLEAR(port) (sci_in(port, SCxSR) & 0xffe3)
|
||||
#else
|
||||
# define SCxSR_RDxF_CLEAR(port) (((port)->type == PORT_SCI) ? 0xbc : 0x00fc)
|
||||
# define SCxSR_ERROR_CLEAR(port) (((port)->type == PORT_SCI) ? 0xc4 : 0x0073)
|
||||
# define SCxSR_TDxE_CLEAR(port) (((port)->type == PORT_SCI) ? 0x78 : 0x00df)
|
||||
# define SCxSR_BREAK_CLEAR(port) (((port)->type == PORT_SCI) ? 0xc4 : 0x00e3)
|
||||
#endif
|
||||
|
||||
/* SCFCR */
|
||||
#define SCFCR_RFRST 0x0002
|
||||
#define SCFCR_TFRST 0x0004
|
||||
#define SCFCR_TCRST 0x4000
|
||||
#define SCFCR_MCE 0x0008
|
||||
|
||||
#define SCI_MAJOR 204
|
||||
#define SCI_MINOR_START 8
|
||||
|
||||
/* Generic serial flags */
|
||||
#define SCI_RX_THROTTLE 0x0000001
|
||||
|
||||
#define SCI_MAGIC 0xbabeface
|
||||
|
||||
/*
|
||||
* Events are used to schedule things to happen at timer-interrupt
|
||||
* time, instead of at rs interrupt time.
|
||||
*/
|
||||
#define SCI_EVENT_WRITE_WAKEUP 0
|
||||
|
||||
#define SCI_IN(size, offset)\
|
||||
if ((size) == 8) {\
|
||||
return readb(port->membase + (offset));\
|
||||
} else {\
|
||||
return readw(port->membase + (offset));\
|
||||
}
|
||||
#define SCI_OUT(size, offset, value)\
|
||||
if ((size) == 8) {\
|
||||
writeb(value, port->membase + (offset));\
|
||||
} else if ((size) == 16) {\
|
||||
writew(value, port->membase + (offset));\
|
||||
}
|
||||
|
||||
#define CPU_SCIx_FNS(name, sci_offset, sci_size, scif_offset, scif_size)\
|
||||
static inline unsigned int sci_##name##_in(struct uart_port *port) {\
|
||||
if (port->type == PORT_SCIF || port->type == PORT_SCIFB) {\
|
||||
SCI_IN(scif_size, scif_offset)\
|
||||
} else { /* PORT_SCI or PORT_SCIFA */\
|
||||
SCI_IN(sci_size, sci_offset);\
|
||||
}\
|
||||
}\
|
||||
static inline void sci_##name##_out(struct uart_port *port,\
|
||||
unsigned int value) {\
|
||||
if (port->type == PORT_SCIF || port->type == PORT_SCIFB) {\
|
||||
SCI_OUT(scif_size, scif_offset, value)\
|
||||
} else { /* PORT_SCI or PORT_SCIFA */\
|
||||
SCI_OUT(sci_size, sci_offset, value);\
|
||||
}\
|
||||
}
|
||||
|
||||
#define CPU_SCIF_FNS(name, scif_offset, scif_size) \
|
||||
static inline unsigned int sci_##name##_in(struct uart_port *port) {\
|
||||
SCI_IN(scif_size, scif_offset);\
|
||||
}\
|
||||
static inline void sci_##name##_out(struct uart_port *port,\
|
||||
unsigned int value) {\
|
||||
SCI_OUT(scif_size, scif_offset, value);\
|
||||
}
|
||||
|
||||
#define CPU_SCI_FNS(name, sci_offset, sci_size)\
|
||||
static inline unsigned int sci_##name##_in(struct uart_port *port) {\
|
||||
SCI_IN(sci_size, sci_offset);\
|
||||
}\
|
||||
static inline void sci_##name##_out(struct uart_port *port,\
|
||||
unsigned int value) {\
|
||||
SCI_OUT(sci_size, sci_offset, value);\
|
||||
}
|
||||
|
||||
#if defined(CONFIG_SH73A0) || \
|
||||
defined(CONFIG_R8A7740)
|
||||
#if defined(CONFIG_CPU_SH7721) || \
|
||||
defined(CONFIG_SH73A0)
|
||||
#define SCIF_FNS(name, scif_offset, scif_size) \
|
||||
CPU_SCIF_FNS(name, scif_offset, scif_size)
|
||||
#elif defined(CONFIG_R8A7740)
|
||||
#define SCIx_FNS(name, sh4_scifa_offset, sh4_scifa_size,\
|
||||
sh4_scifb_offset, sh4_scifb_size) \
|
||||
CPU_SCIx_FNS(name, sh4_scifa_offset, sh4_scifa_size,\
|
||||
sh4_scifb_offset, sh4_scifb_size)
|
||||
#define SCIF_FNS(name, scif_offset, scif_size) \
|
||||
CPU_SCIF_FNS(name, scif_offset, scif_size)
|
||||
#else
|
||||
#define SCIx_FNS(name, sh3_sci_offset, sh3_sci_size,\
|
||||
sh4_sci_offset, sh4_sci_size, \
|
||||
sh3_scif_offset, sh3_scif_size,\
|
||||
sh4_scif_offset, sh4_scif_size, \
|
||||
h8_sci_offset, h8_sci_size) \
|
||||
CPU_SCIx_FNS(name, sh3_sci_offset, sh3_sci_size,\
|
||||
sh3_scif_offset, sh3_scif_size)
|
||||
#define SCIF_FNS(name, sh3_scif_offset, sh3_scif_size,\
|
||||
sh4_scif_offset, sh4_scif_size) \
|
||||
CPU_SCIF_FNS(name, sh3_scif_offset, sh3_scif_size)
|
||||
#endif
|
||||
#elif defined(CONFIG_CPU_SH7723)
|
||||
#define SCIx_FNS(name, sh4_scifa_offset, sh4_scifa_size,\
|
||||
sh4_scif_offset, sh4_scif_size) \
|
||||
CPU_SCIx_FNS(name, sh4_scifa_offset, sh4_scifa_size,\
|
||||
sh4_scif_offset, sh4_scif_size)
|
||||
#define SCIF_FNS(name, sh4_scif_offset, sh4_scif_size) \
|
||||
CPU_SCIF_FNS(name, sh4_scif_offset, sh4_scif_size)
|
||||
#else
|
||||
#define SCIx_FNS(name, sh3_sci_offset, sh3_sci_size,\
|
||||
sh4_sci_offset, sh4_sci_size, \
|
||||
sh3_scif_offset, sh3_scif_size,\
|
||||
sh4_scif_offset, sh4_scif_size, \
|
||||
h8_sci_offset, h8_sci_size) \
|
||||
CPU_SCIx_FNS(name, sh4_sci_offset, sh4_sci_size,\
|
||||
sh4_scif_offset, sh4_scif_size)
|
||||
#define SCIF_FNS(name, sh3_scif_offset, sh3_scif_size, \
|
||||
sh4_scif_offset, sh4_scif_size) \
|
||||
CPU_SCIF_FNS(name, sh4_scif_offset, sh4_scif_size)
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_CPU_SH7721) || \
|
||||
defined(CONFIG_SH73A0)
|
||||
|
||||
SCIF_FNS(SCSMR, 0x00, 16)
|
||||
SCIF_FNS(SCBRR, 0x04, 8)
|
||||
SCIF_FNS(SCSCR, 0x08, 16)
|
||||
SCIF_FNS(SCTDSR, 0x0c, 8)
|
||||
SCIF_FNS(SCFER, 0x10, 16)
|
||||
SCIF_FNS(SCxSR, 0x14, 16)
|
||||
SCIF_FNS(SCFCR, 0x18, 16)
|
||||
SCIF_FNS(SCFDR, 0x1c, 16)
|
||||
SCIF_FNS(SCxTDR, 0x20, 8)
|
||||
SCIF_FNS(SCxRDR, 0x24, 8)
|
||||
SCIF_FNS(SCLSR, 0x00, 0)
|
||||
SCIF_FNS(DL, 0x00, 0) /* dummy */
|
||||
#elif defined(CONFIG_R8A7740)
|
||||
SCIF_FNS(SCSMR, 0x00, 16)
|
||||
SCIF_FNS(SCBRR, 0x04, 8)
|
||||
SCIF_FNS(SCSCR, 0x08, 16)
|
||||
SCIF_FNS(SCTDSR, 0x0c, 16)
|
||||
SCIF_FNS(SCFER, 0x10, 16)
|
||||
SCIF_FNS(SCxSR, 0x14, 16)
|
||||
SCIF_FNS(SCFCR, 0x18, 16)
|
||||
SCIF_FNS(SCFDR, 0x1c, 16)
|
||||
SCIF_FNS(SCTFDR, 0x38, 16)
|
||||
SCIF_FNS(SCRFDR, 0x3c, 16)
|
||||
SCIx_FNS(SCxTDR, 0x20, 8, 0x40, 8)
|
||||
SCIx_FNS(SCxRDR, 0x24, 8, 0x60, 8)
|
||||
SCIF_FNS(SCLSR, 0x00, 0)
|
||||
SCIF_FNS(DL, 0x00, 0) /* dummy */
|
||||
#elif defined(CONFIG_CPU_SH7723)
|
||||
SCIx_FNS(SCSMR, 0x00, 16, 0x00, 16)
|
||||
SCIx_FNS(SCBRR, 0x04, 8, 0x04, 8)
|
||||
SCIx_FNS(SCSCR, 0x08, 16, 0x08, 16)
|
||||
SCIx_FNS(SCxTDR, 0x20, 8, 0x0c, 8)
|
||||
SCIx_FNS(SCxSR, 0x14, 16, 0x10, 16)
|
||||
SCIx_FNS(SCxRDR, 0x24, 8, 0x14, 8)
|
||||
SCIx_FNS(SCSPTR, 0, 0, 0, 0)
|
||||
SCIF_FNS(SCTDSR, 0x0c, 8)
|
||||
SCIF_FNS(SCFER, 0x10, 16)
|
||||
SCIF_FNS(SCFCR, 0x18, 16)
|
||||
SCIF_FNS(SCFDR, 0x1c, 16)
|
||||
SCIF_FNS(SCLSR, 0x24, 16)
|
||||
SCIF_FNS(DL, 0x00, 0) /* dummy */
|
||||
#elif defined(CONFIG_RCAR_GEN2)
|
||||
/* SCIFA and SCIF register offsets and size */
|
||||
SCIx_FNS(SCSMR, 0, 0, 0x00, 16, 0, 0, 0x00, 16, 0, 0)
|
||||
SCIx_FNS(SCBRR, 0, 0, 0x04, 8, 0, 0, 0x04, 8, 0, 0)
|
||||
SCIx_FNS(SCSCR, 0, 0, 0x08, 16, 0, 0, 0x08, 16, 0, 0)
|
||||
SCIx_FNS(SCxTDR, 0, 0, 0x20, 8, 0, 0, 0x0C, 8, 0, 0)
|
||||
SCIx_FNS(SCxSR, 0, 0, 0x14, 16, 0, 0, 0x10, 16, 0, 0)
|
||||
SCIx_FNS(SCxRDR, 0, 0, 0x24, 8, 0, 0, 0x14, 8, 0, 0)
|
||||
SCIF_FNS(SCFCR, 0, 0, 0x18, 16)
|
||||
SCIF_FNS(SCFDR, 0, 0, 0x1C, 16)
|
||||
SCIF_FNS(SCSPTR, 0, 0, 0x20, 16)
|
||||
SCIF_FNS(DL, 0, 0, 0x30, 16)
|
||||
SCIF_FNS(CKS, 0, 0, 0x34, 16)
|
||||
#if defined(CONFIG_SCIF_A)
|
||||
SCIF_FNS(SCLSR, 0, 0, 0x14, 16)
|
||||
#else
|
||||
SCIF_FNS(SCLSR, 0, 0, 0x24, 16)
|
||||
#endif
|
||||
#else
|
||||
/* reg SCI/SH3 SCI/SH4 SCIF/SH3 SCIF/SH4 SCI/H8*/
|
||||
/* name off sz off sz off sz off sz off sz*/
|
||||
SCIx_FNS(SCSMR, 0x00, 8, 0x00, 8, 0x00, 8, 0x00, 16, 0x00, 8)
|
||||
SCIx_FNS(SCBRR, 0x02, 8, 0x04, 8, 0x02, 8, 0x04, 8, 0x01, 8)
|
||||
SCIx_FNS(SCSCR, 0x04, 8, 0x08, 8, 0x04, 8, 0x08, 16, 0x02, 8)
|
||||
SCIx_FNS(SCxTDR, 0x06, 8, 0x0c, 8, 0x06, 8, 0x0C, 8, 0x03, 8)
|
||||
SCIx_FNS(SCxSR, 0x08, 8, 0x10, 8, 0x08, 16, 0x10, 16, 0x04, 8)
|
||||
SCIx_FNS(SCxRDR, 0x0a, 8, 0x14, 8, 0x0A, 8, 0x14, 8, 0x05, 8)
|
||||
SCIF_FNS(SCFCR, 0x0c, 8, 0x18, 16)
|
||||
#if defined(CONFIG_CPU_SH7780)
|
||||
SCIF_FNS(SCFDR, 0x0e, 16, 0x1C, 16)
|
||||
SCIF_FNS(SCTFDR, 0x0e, 16, 0x1C, 16)
|
||||
SCIF_FNS(SCRFDR, 0x0e, 16, 0x20, 16)
|
||||
SCIF_FNS(SCSPTR, 0, 0, 0x24, 16)
|
||||
SCIF_FNS(SCLSR, 0, 0, 0x28, 16)
|
||||
#elif defined(CONFIG_CPU_SH7763)
|
||||
SCIF_FNS(SCFDR, 0, 0, 0x1C, 16)
|
||||
SCIF_FNS(SCSPTR2, 0, 0, 0x20, 16)
|
||||
SCIF_FNS(SCLSR2, 0, 0, 0x24, 16)
|
||||
SCIF_FNS(SCTFDR, 0x0e, 16, 0x1C, 16)
|
||||
SCIF_FNS(SCRFDR, 0x0e, 16, 0x20, 16)
|
||||
SCIF_FNS(SCSPTR, 0, 0, 0x24, 16)
|
||||
SCIF_FNS(SCLSR, 0, 0, 0x28, 16)
|
||||
#else
|
||||
|
||||
SCIF_FNS(SCFDR, 0x0e, 16, 0x1C, 16)
|
||||
#if defined(CONFIG_CPU_SH7722)
|
||||
SCIF_FNS(SCSPTR, 0, 0, 0, 0)
|
||||
#else
|
||||
SCIF_FNS(SCSPTR, 0, 0, 0x20, 16)
|
||||
#endif
|
||||
SCIF_FNS(SCLSR, 0, 0, 0x24, 16)
|
||||
#endif
|
||||
SCIF_FNS(DL, 0, 0, 0x0, 0) /* dummy */
|
||||
#endif
|
||||
#define sci_in(port, reg) sci_##reg##_in(port)
|
||||
#define sci_out(port, reg, value) sci_##reg##_out(port, value)
|
||||
|
||||
#if defined(CONFIG_CPU_SH7750) || \
|
||||
defined(CONFIG_CPU_SH7751) || \
|
||||
defined(CONFIG_CPU_SH7751R) || \
|
||||
defined(CONFIG_CPU_SH7750R) || \
|
||||
defined(CONFIG_CPU_SH7750S)
|
||||
static inline int sci_rxd_in(struct uart_port *port)
|
||||
{
|
||||
if (port->mapbase == 0xffe00000)
|
||||
return __raw_readb(SCSPTR1)&0x01 ? 1 : 0; /* SCI */
|
||||
return 1;
|
||||
}
|
||||
#else /* default case for non-SCI processors */
|
||||
static inline int sci_rxd_in(struct uart_port *port)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Values for the BitRate Register (SCBRR)
|
||||
*
|
||||
* The values are actually divisors for a frequency which can
|
||||
* be internal to the SH3 (14.7456MHz) or derived from an external
|
||||
* clock source. This driver assumes the internal clock is used;
|
||||
* to support using an external clock source, config options or
|
||||
* possibly command-line options would need to be added.
|
||||
*
|
||||
* Also, to support speeds below 2400 (why?) the lower 2 bits of
|
||||
* the SCSMR register would also need to be set to non-zero values.
|
||||
*
|
||||
* -- Greg Banks 27Feb2000
|
||||
*
|
||||
* Answer: The SCBRR register is only eight bits, and the value in
|
||||
* it gets larger with lower baud rates. At around 2400 (depending on
|
||||
* the peripherial module clock) you run out of bits. However the
|
||||
* lower two bits of SCSMR allow the module clock to be divided down,
|
||||
* scaling the value which is needed in SCBRR.
|
||||
*
|
||||
* -- Stuart Menefy - 23 May 2000
|
||||
*
|
||||
* I meant, why would anyone bother with bitrates below 2400.
|
||||
*
|
||||
* -- Greg Banks - 7Jul2000
|
||||
*
|
||||
* You "speedist"! How will I use my 110bps ASR-33 teletype with paper
|
||||
* tape reader as a console!
|
||||
*
|
||||
* -- Mitch Davis - 15 Jul 2000
|
||||
*/
|
||||
|
||||
#if defined(CONFIG_CPU_SH7780)
|
||||
#define SCBRR_VALUE(bps, clk) ((clk+16*bps)/(16*bps)-1)
|
||||
#elif defined(CONFIG_CPU_SH7721) || \
|
||||
defined(CONFIG_SH73A0) || \
|
||||
defined(CONFIG_R8A7740)
|
||||
#define SCBRR_VALUE(bps, clk) (((clk*2)+16*bps)/(32*bps)-1)
|
||||
#elif defined(CONFIG_CPU_SH7723)
|
||||
static inline int scbrr_calc(struct uart_port *port, int bps, int clk)
|
||||
{
|
||||
if (port->type == PORT_SCIF)
|
||||
return (clk+16*bps)/(32*bps)-1;
|
||||
else
|
||||
return ((clk*2)+16*bps)/(16*bps)-1;
|
||||
}
|
||||
#define SCBRR_VALUE(bps, clk) scbrr_calc(port, bps, clk)
|
||||
#elif defined(CONFIG_RCAR_GEN2)
|
||||
#define DL_VALUE(bps, clk) (clk / bps / 16) /* External Clock */
|
||||
#if defined(CONFIG_SCIF_A)
|
||||
#define SCBRR_VALUE(bps, clk) (clk / bps / 16 - 1) /* Internal Clock */
|
||||
#else
|
||||
#define SCBRR_VALUE(bps, clk) (clk / bps / 32 - 1) /* Internal Clock */
|
||||
#endif
|
||||
#else /* Generic SH */
|
||||
#define SCBRR_VALUE(bps, clk) ((clk+16*bps)/(32*bps)-1)
|
||||
#endif
|
||||
|
||||
#ifndef DL_VALUE
|
||||
#define DL_VALUE(bps, clk) 0
|
||||
#endif
|
||||
@@ -0,0 +1,230 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright (C) 2018 Anup Patel <anup@brainfault.org>
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <clk.h>
|
||||
#include <debug_uart.h>
|
||||
#include <dm.h>
|
||||
#include <errno.h>
|
||||
#include <fdtdec.h>
|
||||
#include <watchdog.h>
|
||||
#include <asm/io.h>
|
||||
#include <linux/compiler.h>
|
||||
#include <serial.h>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
#define UART_TXFIFO_FULL 0x80000000
|
||||
#define UART_RXFIFO_EMPTY 0x80000000
|
||||
#define UART_RXFIFO_DATA 0x000000ff
|
||||
#define UART_TXCTRL_TXEN 0x1
|
||||
#define UART_RXCTRL_RXEN 0x1
|
||||
|
||||
/* IP register */
|
||||
#define UART_IP_RXWM 0x2
|
||||
|
||||
struct uart_sifive {
|
||||
u32 txfifo;
|
||||
u32 rxfifo;
|
||||
u32 txctrl;
|
||||
u32 rxctrl;
|
||||
u32 ie;
|
||||
u32 ip;
|
||||
u32 div;
|
||||
};
|
||||
|
||||
struct sifive_uart_platdata {
|
||||
unsigned long clock;
|
||||
struct uart_sifive *regs;
|
||||
};
|
||||
|
||||
/**
|
||||
* Find minimum divisor divides in_freq to max_target_hz;
|
||||
* Based on uart driver n SiFive FSBL.
|
||||
*
|
||||
* f_baud = f_in / (div + 1) => div = (f_in / f_baud) - 1
|
||||
* The nearest integer solution requires rounding up as to not exceed
|
||||
* max_target_hz.
|
||||
* div = ceil(f_in / f_baud) - 1
|
||||
* = floor((f_in - 1 + f_baud) / f_baud) - 1
|
||||
* This should not overflow as long as (f_in - 1 + f_baud) does not exceed
|
||||
* 2^32 - 1, which is unlikely since we represent frequencies in kHz.
|
||||
*/
|
||||
static inline unsigned int uart_min_clk_divisor(unsigned long in_freq,
|
||||
unsigned long max_target_hz)
|
||||
{
|
||||
unsigned long quotient =
|
||||
(in_freq + max_target_hz - 1) / (max_target_hz);
|
||||
/* Avoid underflow */
|
||||
if (quotient == 0)
|
||||
return 0;
|
||||
else
|
||||
return quotient - 1;
|
||||
}
|
||||
|
||||
/* Set up the baud rate in gd struct */
|
||||
static void _sifive_serial_setbrg(struct uart_sifive *regs,
|
||||
unsigned long clock, unsigned long baud)
|
||||
{
|
||||
writel((uart_min_clk_divisor(clock, baud)), ®s->div);
|
||||
}
|
||||
|
||||
static void _sifive_serial_init(struct uart_sifive *regs)
|
||||
{
|
||||
writel(UART_TXCTRL_TXEN, ®s->txctrl);
|
||||
writel(UART_RXCTRL_RXEN, ®s->rxctrl);
|
||||
writel(0, ®s->ie);
|
||||
}
|
||||
|
||||
static int _sifive_serial_putc(struct uart_sifive *regs, const char c)
|
||||
{
|
||||
if (readl(®s->txfifo) & UART_TXFIFO_FULL)
|
||||
return -EAGAIN;
|
||||
|
||||
writel(c, ®s->txfifo);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _sifive_serial_getc(struct uart_sifive *regs)
|
||||
{
|
||||
int ch = readl(®s->rxfifo);
|
||||
|
||||
if (ch & UART_RXFIFO_EMPTY)
|
||||
return -EAGAIN;
|
||||
ch &= UART_RXFIFO_DATA;
|
||||
|
||||
return ch;
|
||||
}
|
||||
|
||||
static int sifive_serial_setbrg(struct udevice *dev, int baudrate)
|
||||
{
|
||||
int ret;
|
||||
struct clk clk;
|
||||
struct sifive_uart_platdata *platdata = dev_get_platdata(dev);
|
||||
u32 clock = 0;
|
||||
|
||||
ret = clk_get_by_index(dev, 0, &clk);
|
||||
if (IS_ERR_VALUE(ret)) {
|
||||
debug("SiFive UART failed to get clock\n");
|
||||
ret = dev_read_u32(dev, "clock-frequency", &clock);
|
||||
if (IS_ERR_VALUE(ret)) {
|
||||
debug("SiFive UART clock not defined\n");
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
clock = clk_get_rate(&clk);
|
||||
if (IS_ERR_VALUE(clock)) {
|
||||
debug("SiFive UART clock get rate failed\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
platdata->clock = clock;
|
||||
_sifive_serial_setbrg(platdata->regs, platdata->clock, baudrate);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sifive_serial_probe(struct udevice *dev)
|
||||
{
|
||||
struct sifive_uart_platdata *platdata = dev_get_platdata(dev);
|
||||
|
||||
/* No need to reinitialize the UART after relocation */
|
||||
if (gd->flags & GD_FLG_RELOC)
|
||||
return 0;
|
||||
|
||||
_sifive_serial_init(platdata->regs);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sifive_serial_getc(struct udevice *dev)
|
||||
{
|
||||
int c;
|
||||
struct sifive_uart_platdata *platdata = dev_get_platdata(dev);
|
||||
struct uart_sifive *regs = platdata->regs;
|
||||
|
||||
while ((c = _sifive_serial_getc(regs)) == -EAGAIN) ;
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
static int sifive_serial_putc(struct udevice *dev, const char ch)
|
||||
{
|
||||
int rc;
|
||||
struct sifive_uart_platdata *platdata = dev_get_platdata(dev);
|
||||
|
||||
while ((rc = _sifive_serial_putc(platdata->regs, ch)) == -EAGAIN) ;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int sifive_serial_pending(struct udevice *dev, bool input)
|
||||
{
|
||||
struct sifive_uart_platdata *platdata = dev_get_platdata(dev);
|
||||
struct uart_sifive *regs = platdata->regs;
|
||||
|
||||
if (input)
|
||||
return (readl(®s->ip) & UART_IP_RXWM);
|
||||
else
|
||||
return !!(readl(®s->txfifo) & UART_TXFIFO_FULL);
|
||||
}
|
||||
|
||||
static int sifive_serial_ofdata_to_platdata(struct udevice *dev)
|
||||
{
|
||||
struct sifive_uart_platdata *platdata = dev_get_platdata(dev);
|
||||
|
||||
platdata->regs = (struct uart_sifive *)dev_read_addr(dev);
|
||||
if (IS_ERR(platdata->regs))
|
||||
return PTR_ERR(platdata->regs);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dm_serial_ops sifive_serial_ops = {
|
||||
.putc = sifive_serial_putc,
|
||||
.getc = sifive_serial_getc,
|
||||
.pending = sifive_serial_pending,
|
||||
.setbrg = sifive_serial_setbrg,
|
||||
};
|
||||
|
||||
static const struct udevice_id sifive_serial_ids[] = {
|
||||
{ .compatible = "sifive,uart0" },
|
||||
{ }
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(serial_sifive) = {
|
||||
.name = "serial_sifive",
|
||||
.id = UCLASS_SERIAL,
|
||||
.of_match = sifive_serial_ids,
|
||||
.ofdata_to_platdata = sifive_serial_ofdata_to_platdata,
|
||||
.platdata_auto_alloc_size = sizeof(struct sifive_uart_platdata),
|
||||
.probe = sifive_serial_probe,
|
||||
.ops = &sifive_serial_ops,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_DEBUG_UART_SIFIVE
|
||||
static inline void _debug_uart_init(void)
|
||||
{
|
||||
struct uart_sifive *regs =
|
||||
(struct uart_sifive *)CONFIG_DEBUG_UART_BASE;
|
||||
|
||||
_sifive_serial_setbrg(regs, CONFIG_DEBUG_UART_CLOCK,
|
||||
CONFIG_BAUDRATE);
|
||||
_sifive_serial_init(regs);
|
||||
}
|
||||
|
||||
static inline void _debug_uart_putc(int ch)
|
||||
{
|
||||
struct uart_sifive *regs =
|
||||
(struct uart_sifive *)CONFIG_DEBUG_UART_BASE;
|
||||
|
||||
while (_sifive_serial_putc(regs, ch) == -EAGAIN)
|
||||
WATCHDOG_RESET();
|
||||
}
|
||||
|
||||
DEBUG_UART_FUNCS
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,209 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Support for Serial I/O using STMicroelectronics' on-chip ASC.
|
||||
*
|
||||
* Copyright (C) 2017, STMicroelectronics - All Rights Reserved
|
||||
* Author(s): Patrice Chotard, <patrice.chotard@st.com> for STMicroelectronics.
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <dm.h>
|
||||
#include <serial.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
#define BAUDMODE 0x00001000
|
||||
#define RXENABLE 0x00000100
|
||||
#define RUN 0x00000080
|
||||
#define MODE 0x00000001
|
||||
#define MODE_8BIT 0x0001
|
||||
#define STOP_1BIT 0x0008
|
||||
#define PARITYODD 0x0020
|
||||
|
||||
#define STA_TF BIT(9)
|
||||
#define STA_RBF BIT(0)
|
||||
|
||||
struct sti_asc_uart {
|
||||
u32 baudrate;
|
||||
u32 txbuf;
|
||||
u32 rxbuf;
|
||||
u32 control;
|
||||
u32 inten;
|
||||
u32 status;
|
||||
u32 guardtime;
|
||||
u32 timeout;
|
||||
u32 txreset;
|
||||
u32 rxreset;
|
||||
};
|
||||
|
||||
struct sti_asc_serial {
|
||||
/* address of registers in physical memory */
|
||||
struct sti_asc_uart *regs;
|
||||
};
|
||||
|
||||
/* Values for the BAUDRATE Register */
|
||||
#define PCLK (200ul * 1000000ul)
|
||||
#define BAUDRATE_VAL_M0(bps) (PCLK / (16 * (bps)))
|
||||
#define BAUDRATE_VAL_M1(bps) ((bps * (1 << 14)) + (1<<13)) / (PCLK/(1 << 6))
|
||||
|
||||
/*
|
||||
* MODE 0
|
||||
* ICCLK
|
||||
* ASCBaudRate = ----------------
|
||||
* baudrate * 16
|
||||
*
|
||||
* MODE 1
|
||||
* baudrate * 16 * 2^16
|
||||
* ASCBaudRate = ------------------------
|
||||
* ICCLK
|
||||
*
|
||||
* NOTE:
|
||||
* Mode 1 should be used for baudrates of 19200, and above, as it
|
||||
* has a lower deviation error than Mode 0 for higher frequencies.
|
||||
* Mode 0 should be used for all baudrates below 19200.
|
||||
*/
|
||||
|
||||
static int sti_asc_pending(struct udevice *dev, bool input)
|
||||
{
|
||||
struct sti_asc_serial *priv = dev_get_priv(dev);
|
||||
struct sti_asc_uart *const uart = priv->regs;
|
||||
unsigned long status;
|
||||
|
||||
status = readl(&uart->status);
|
||||
if (input)
|
||||
return status & STA_RBF;
|
||||
else
|
||||
return status & STA_TF;
|
||||
}
|
||||
|
||||
static int _sti_asc_serial_setbrg(struct sti_asc_uart *uart, int baudrate)
|
||||
{
|
||||
unsigned long val;
|
||||
int t, mode = 1;
|
||||
|
||||
switch (baudrate) {
|
||||
case 9600:
|
||||
t = BAUDRATE_VAL_M0(9600);
|
||||
mode = 0;
|
||||
break;
|
||||
case 19200:
|
||||
t = BAUDRATE_VAL_M1(19200);
|
||||
break;
|
||||
case 38400:
|
||||
t = BAUDRATE_VAL_M1(38400);
|
||||
break;
|
||||
case 57600:
|
||||
t = BAUDRATE_VAL_M1(57600);
|
||||
break;
|
||||
default:
|
||||
debug("ASC: unsupported baud rate: %d, using 115200 instead.\n",
|
||||
baudrate);
|
||||
case 115200:
|
||||
t = BAUDRATE_VAL_M1(115200);
|
||||
break;
|
||||
}
|
||||
|
||||
/* disable the baudrate generator */
|
||||
val = readl(&uart->control);
|
||||
writel(val & ~RUN, &uart->control);
|
||||
|
||||
/* set baud generator reload value */
|
||||
writel(t, &uart->baudrate);
|
||||
/* reset the RX & TX buffers */
|
||||
writel(1, &uart->txreset);
|
||||
writel(1, &uart->rxreset);
|
||||
|
||||
/* set baud generator mode */
|
||||
if (mode)
|
||||
val |= BAUDMODE;
|
||||
|
||||
/* finally, write value and enable ASC */
|
||||
writel(val, &uart->control);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* called to adjust baud-rate */
|
||||
static int sti_asc_serial_setbrg(struct udevice *dev, int baudrate)
|
||||
{
|
||||
struct sti_asc_serial *priv = dev_get_priv(dev);
|
||||
struct sti_asc_uart *const uart = priv->regs;
|
||||
|
||||
return _sti_asc_serial_setbrg(uart, baudrate);
|
||||
}
|
||||
|
||||
/* blocking function, that returns next char */
|
||||
static int sti_asc_serial_getc(struct udevice *dev)
|
||||
{
|
||||
struct sti_asc_serial *priv = dev_get_priv(dev);
|
||||
struct sti_asc_uart *const uart = priv->regs;
|
||||
|
||||
/* polling wait: for a char to be read */
|
||||
if (!sti_asc_pending(dev, true))
|
||||
return -EAGAIN;
|
||||
|
||||
return readl(&uart->rxbuf);
|
||||
}
|
||||
|
||||
/* write write out a single char */
|
||||
static int sti_asc_serial_putc(struct udevice *dev, const char c)
|
||||
{
|
||||
struct sti_asc_serial *priv = dev_get_priv(dev);
|
||||
struct sti_asc_uart *const uart = priv->regs;
|
||||
|
||||
/* wait till safe to write next char */
|
||||
if (sti_asc_pending(dev, false))
|
||||
return -EAGAIN;
|
||||
|
||||
/* finally, write next char */
|
||||
writel(c, &uart->txbuf);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* initialize the ASC */
|
||||
static int sti_asc_serial_probe(struct udevice *dev)
|
||||
{
|
||||
struct sti_asc_serial *priv = dev_get_priv(dev);
|
||||
unsigned long val;
|
||||
fdt_addr_t base;
|
||||
|
||||
base = devfdt_get_addr(dev);
|
||||
if (base == FDT_ADDR_T_NONE)
|
||||
return -EINVAL;
|
||||
|
||||
priv->regs = (struct sti_asc_uart *)base;
|
||||
sti_asc_serial_setbrg(dev, gd->baudrate);
|
||||
|
||||
/*
|
||||
* build up the value to be written to CONTROL
|
||||
* set character length, bit stop number, odd parity
|
||||
*/
|
||||
val = RXENABLE | RUN | MODE_8BIT | STOP_1BIT | PARITYODD;
|
||||
writel(val, &priv->regs->control);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dm_serial_ops sti_asc_serial_ops = {
|
||||
.putc = sti_asc_serial_putc,
|
||||
.pending = sti_asc_pending,
|
||||
.getc = sti_asc_serial_getc,
|
||||
.setbrg = sti_asc_serial_setbrg,
|
||||
};
|
||||
|
||||
static const struct udevice_id sti_serial_of_match[] = {
|
||||
{ .compatible = "st,asc" },
|
||||
{ }
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(serial_sti_asc) = {
|
||||
.name = "serial_sti_asc",
|
||||
.id = UCLASS_SERIAL,
|
||||
.of_match = sti_serial_of_match,
|
||||
.ops = &sti_asc_serial_ops,
|
||||
.probe = sti_asc_serial_probe,
|
||||
.priv_auto_alloc_size = sizeof(struct sti_asc_serial),
|
||||
};
|
||||
|
||||
@@ -0,0 +1,285 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright (C) 2016, STMicroelectronics - All Rights Reserved
|
||||
* Author(s): Vikas Manocha, <vikas.manocha@st.com> for STMicroelectronics.
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <clk.h>
|
||||
#include <dm.h>
|
||||
#include <reset.h>
|
||||
#include <serial.h>
|
||||
#include <watchdog.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/arch/stm32.h>
|
||||
#include "serial_stm32.h"
|
||||
|
||||
static void _stm32_serial_setbrg(fdt_addr_t base,
|
||||
struct stm32_uart_info *uart_info,
|
||||
u32 clock_rate,
|
||||
int baudrate)
|
||||
{
|
||||
bool stm32f4 = uart_info->stm32f4;
|
||||
u32 int_div, mantissa, fraction, oversampling;
|
||||
|
||||
int_div = DIV_ROUND_CLOSEST(clock_rate, baudrate);
|
||||
|
||||
if (int_div < 16) {
|
||||
oversampling = 8;
|
||||
setbits_le32(base + CR1_OFFSET(stm32f4), USART_CR1_OVER8);
|
||||
} else {
|
||||
oversampling = 16;
|
||||
clrbits_le32(base + CR1_OFFSET(stm32f4), USART_CR1_OVER8);
|
||||
}
|
||||
|
||||
mantissa = (int_div / oversampling) << USART_BRR_M_SHIFT;
|
||||
fraction = int_div % oversampling;
|
||||
|
||||
writel(mantissa | fraction, base + BRR_OFFSET(stm32f4));
|
||||
}
|
||||
|
||||
static int stm32_serial_setbrg(struct udevice *dev, int baudrate)
|
||||
{
|
||||
struct stm32x7_serial_platdata *plat = dev_get_platdata(dev);
|
||||
|
||||
_stm32_serial_setbrg(plat->base, plat->uart_info,
|
||||
plat->clock_rate, baudrate);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int stm32_serial_setconfig(struct udevice *dev, uint serial_config)
|
||||
{
|
||||
struct stm32x7_serial_platdata *plat = dev_get_platdata(dev);
|
||||
bool stm32f4 = plat->uart_info->stm32f4;
|
||||
u8 uart_enable_bit = plat->uart_info->uart_enable_bit;
|
||||
u32 cr1 = plat->base + CR1_OFFSET(stm32f4);
|
||||
u32 config = 0;
|
||||
uint parity = SERIAL_GET_PARITY(serial_config);
|
||||
uint bits = SERIAL_GET_BITS(serial_config);
|
||||
uint stop = SERIAL_GET_STOP(serial_config);
|
||||
|
||||
/*
|
||||
* only parity config is implemented, check if other serial settings
|
||||
* are the default one.
|
||||
* (STM32F4 serial IP didn't support parity setting)
|
||||
*/
|
||||
if (bits != SERIAL_8_BITS || stop != SERIAL_ONE_STOP || stm32f4)
|
||||
return -ENOTSUPP; /* not supported in driver*/
|
||||
|
||||
clrbits_le32(cr1, USART_CR1_RE | USART_CR1_TE | BIT(uart_enable_bit));
|
||||
/* update usart configuration (uart need to be disable)
|
||||
* PCE: parity check enable
|
||||
* PS : '0' : Even / '1' : Odd
|
||||
* M[1:0] = '00' : 8 Data bits
|
||||
* M[1:0] = '01' : 9 Data bits with parity
|
||||
*/
|
||||
switch (parity) {
|
||||
default:
|
||||
case SERIAL_PAR_NONE:
|
||||
config = 0;
|
||||
break;
|
||||
case SERIAL_PAR_ODD:
|
||||
config = USART_CR1_PCE | USART_CR1_PS | USART_CR1_M0;
|
||||
break;
|
||||
case SERIAL_PAR_EVEN:
|
||||
config = USART_CR1_PCE | USART_CR1_M0;
|
||||
break;
|
||||
}
|
||||
|
||||
clrsetbits_le32(cr1,
|
||||
USART_CR1_PCE | USART_CR1_PS | USART_CR1_M1 |
|
||||
USART_CR1_M0,
|
||||
config);
|
||||
setbits_le32(cr1, USART_CR1_RE | USART_CR1_TE | BIT(uart_enable_bit));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int stm32_serial_getc(struct udevice *dev)
|
||||
{
|
||||
struct stm32x7_serial_platdata *plat = dev_get_platdata(dev);
|
||||
bool stm32f4 = plat->uart_info->stm32f4;
|
||||
fdt_addr_t base = plat->base;
|
||||
u32 isr = readl(base + ISR_OFFSET(stm32f4));
|
||||
|
||||
if ((isr & USART_ISR_RXNE) == 0)
|
||||
return -EAGAIN;
|
||||
|
||||
if (isr & (USART_ISR_PE | USART_ISR_ORE | USART_ISR_FE)) {
|
||||
if (!stm32f4)
|
||||
setbits_le32(base + ICR_OFFSET,
|
||||
USART_ICR_PCECF | USART_ICR_ORECF |
|
||||
USART_ICR_FECF);
|
||||
else
|
||||
readl(base + RDR_OFFSET(stm32f4));
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return readl(base + RDR_OFFSET(stm32f4));
|
||||
}
|
||||
|
||||
static int _stm32_serial_putc(fdt_addr_t base,
|
||||
struct stm32_uart_info *uart_info,
|
||||
const char c)
|
||||
{
|
||||
bool stm32f4 = uart_info->stm32f4;
|
||||
|
||||
if ((readl(base + ISR_OFFSET(stm32f4)) & USART_ISR_TXE) == 0)
|
||||
return -EAGAIN;
|
||||
|
||||
writel(c, base + TDR_OFFSET(stm32f4));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int stm32_serial_putc(struct udevice *dev, const char c)
|
||||
{
|
||||
struct stm32x7_serial_platdata *plat = dev_get_platdata(dev);
|
||||
|
||||
return _stm32_serial_putc(plat->base, plat->uart_info, c);
|
||||
}
|
||||
|
||||
static int stm32_serial_pending(struct udevice *dev, bool input)
|
||||
{
|
||||
struct stm32x7_serial_platdata *plat = dev_get_platdata(dev);
|
||||
bool stm32f4 = plat->uart_info->stm32f4;
|
||||
fdt_addr_t base = plat->base;
|
||||
|
||||
if (input)
|
||||
return readl(base + ISR_OFFSET(stm32f4)) &
|
||||
USART_ISR_RXNE ? 1 : 0;
|
||||
else
|
||||
return readl(base + ISR_OFFSET(stm32f4)) &
|
||||
USART_ISR_TXE ? 0 : 1;
|
||||
}
|
||||
|
||||
static void _stm32_serial_init(fdt_addr_t base,
|
||||
struct stm32_uart_info *uart_info)
|
||||
{
|
||||
bool stm32f4 = uart_info->stm32f4;
|
||||
u8 uart_enable_bit = uart_info->uart_enable_bit;
|
||||
|
||||
/* Disable uart-> enable fifo -> enable uart */
|
||||
clrbits_le32(base + CR1_OFFSET(stm32f4), USART_CR1_RE | USART_CR1_TE |
|
||||
BIT(uart_enable_bit));
|
||||
if (uart_info->has_fifo)
|
||||
setbits_le32(base + CR1_OFFSET(stm32f4), USART_CR1_FIFOEN);
|
||||
setbits_le32(base + CR1_OFFSET(stm32f4), USART_CR1_RE | USART_CR1_TE |
|
||||
BIT(uart_enable_bit));
|
||||
}
|
||||
|
||||
static int stm32_serial_probe(struct udevice *dev)
|
||||
{
|
||||
struct stm32x7_serial_platdata *plat = dev_get_platdata(dev);
|
||||
struct clk clk;
|
||||
struct reset_ctl reset;
|
||||
int ret;
|
||||
|
||||
plat->uart_info = (struct stm32_uart_info *)dev_get_driver_data(dev);
|
||||
|
||||
ret = clk_get_by_index(dev, 0, &clk);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = clk_enable(&clk);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to enable clock\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = reset_get_by_index(dev, 0, &reset);
|
||||
if (!ret) {
|
||||
reset_assert(&reset);
|
||||
udelay(2);
|
||||
reset_deassert(&reset);
|
||||
}
|
||||
|
||||
plat->clock_rate = clk_get_rate(&clk);
|
||||
if (!plat->clock_rate) {
|
||||
clk_disable(&clk);
|
||||
return -EINVAL;
|
||||
};
|
||||
|
||||
_stm32_serial_init(plat->base, plat->uart_info);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct udevice_id stm32_serial_id[] = {
|
||||
{ .compatible = "st,stm32-uart", .data = (ulong)&stm32f4_info},
|
||||
{ .compatible = "st,stm32f7-uart", .data = (ulong)&stm32f7_info},
|
||||
{ .compatible = "st,stm32h7-uart", .data = (ulong)&stm32h7_info},
|
||||
{}
|
||||
};
|
||||
|
||||
static int stm32_serial_ofdata_to_platdata(struct udevice *dev)
|
||||
{
|
||||
struct stm32x7_serial_platdata *plat = dev_get_platdata(dev);
|
||||
|
||||
plat->base = devfdt_get_addr(dev);
|
||||
if (plat->base == FDT_ADDR_T_NONE)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dm_serial_ops stm32_serial_ops = {
|
||||
.putc = stm32_serial_putc,
|
||||
.pending = stm32_serial_pending,
|
||||
.getc = stm32_serial_getc,
|
||||
.setbrg = stm32_serial_setbrg,
|
||||
.setconfig = stm32_serial_setconfig
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(serial_stm32) = {
|
||||
.name = "serial_stm32",
|
||||
.id = UCLASS_SERIAL,
|
||||
.of_match = of_match_ptr(stm32_serial_id),
|
||||
.ofdata_to_platdata = of_match_ptr(stm32_serial_ofdata_to_platdata),
|
||||
.platdata_auto_alloc_size = sizeof(struct stm32x7_serial_platdata),
|
||||
.ops = &stm32_serial_ops,
|
||||
.probe = stm32_serial_probe,
|
||||
#if !CONFIG_IS_ENABLED(OF_CONTROL)
|
||||
.flags = DM_FLAG_PRE_RELOC,
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifdef CONFIG_DEBUG_UART_STM32
|
||||
#include <debug_uart.h>
|
||||
static inline struct stm32_uart_info *_debug_uart_info(void)
|
||||
{
|
||||
struct stm32_uart_info *uart_info;
|
||||
|
||||
#if defined(CONFIG_STM32F4)
|
||||
uart_info = &stm32f4_info;
|
||||
#elif defined(CONFIG_STM32F7)
|
||||
uart_info = &stm32f7_info;
|
||||
#else
|
||||
uart_info = &stm32h7_info;
|
||||
#endif
|
||||
return uart_info;
|
||||
}
|
||||
|
||||
static inline void _debug_uart_init(void)
|
||||
{
|
||||
fdt_addr_t base = CONFIG_DEBUG_UART_BASE;
|
||||
struct stm32_uart_info *uart_info = _debug_uart_info();
|
||||
|
||||
_stm32_serial_init(base, uart_info);
|
||||
_stm32_serial_setbrg(base, uart_info,
|
||||
CONFIG_DEBUG_UART_CLOCK,
|
||||
CONFIG_BAUDRATE);
|
||||
}
|
||||
|
||||
static inline void _debug_uart_putc(int c)
|
||||
{
|
||||
fdt_addr_t base = CONFIG_DEBUG_UART_BASE;
|
||||
struct stm32_uart_info *uart_info = _debug_uart_info();
|
||||
|
||||
while (_stm32_serial_putc(base, uart_info, c) == -EAGAIN)
|
||||
;
|
||||
}
|
||||
|
||||
DEBUG_UART_FUNCS
|
||||
#endif
|
||||
@@ -0,0 +1,81 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/*
|
||||
* Copyright (C) 2016, STMicroelectronics - All Rights Reserved
|
||||
* Author(s): Vikas Manocha, <vikas.manocha@st.com> for STMicroelectronics.
|
||||
*/
|
||||
|
||||
#ifndef _SERIAL_STM32_
|
||||
#define _SERIAL_STM32_
|
||||
|
||||
#define CR1_OFFSET(x) (x ? 0x0c : 0x00)
|
||||
#define CR3_OFFSET(x) (x ? 0x14 : 0x08)
|
||||
#define BRR_OFFSET(x) (x ? 0x08 : 0x0c)
|
||||
#define ISR_OFFSET(x) (x ? 0x00 : 0x1c)
|
||||
|
||||
#define ICR_OFFSET 0x20
|
||||
|
||||
/*
|
||||
* STM32F4 has one Data Register (DR) for received or transmitted
|
||||
* data, so map Receive Data Register (RDR) and Transmit Data
|
||||
* Register (TDR) at the same offset
|
||||
*/
|
||||
#define RDR_OFFSET(x) (x ? 0x04 : 0x24)
|
||||
#define TDR_OFFSET(x) (x ? 0x04 : 0x28)
|
||||
|
||||
struct stm32_uart_info {
|
||||
u8 uart_enable_bit; /* UART_CR1_UE */
|
||||
bool stm32f4; /* true for STM32F4, false otherwise */
|
||||
bool has_fifo;
|
||||
};
|
||||
|
||||
struct stm32_uart_info stm32f4_info = {
|
||||
.stm32f4 = true,
|
||||
.uart_enable_bit = 13,
|
||||
.has_fifo = false,
|
||||
};
|
||||
|
||||
struct stm32_uart_info stm32f7_info = {
|
||||
.uart_enable_bit = 0,
|
||||
.stm32f4 = false,
|
||||
.has_fifo = true,
|
||||
};
|
||||
|
||||
struct stm32_uart_info stm32h7_info = {
|
||||
.uart_enable_bit = 0,
|
||||
.stm32f4 = false,
|
||||
.has_fifo = true,
|
||||
};
|
||||
|
||||
/* Information about a serial port */
|
||||
struct stm32x7_serial_platdata {
|
||||
fdt_addr_t base; /* address of registers in physical memory */
|
||||
struct stm32_uart_info *uart_info;
|
||||
unsigned long int clock_rate;
|
||||
};
|
||||
|
||||
#define USART_CR1_FIFOEN BIT(29)
|
||||
#define USART_CR1_M1 BIT(28)
|
||||
#define USART_CR1_OVER8 BIT(15)
|
||||
#define USART_CR1_M0 BIT(12)
|
||||
#define USART_CR1_PCE BIT(10)
|
||||
#define USART_CR1_PS BIT(9)
|
||||
#define USART_CR1_TE BIT(3)
|
||||
#define USART_CR1_RE BIT(2)
|
||||
|
||||
#define USART_CR3_OVRDIS BIT(12)
|
||||
|
||||
#define USART_ISR_TXE BIT(7)
|
||||
#define USART_ISR_RXNE BIT(5)
|
||||
#define USART_ISR_ORE BIT(3)
|
||||
#define USART_ISR_FE BIT(1)
|
||||
#define USART_ISR_PE BIT(0)
|
||||
|
||||
#define USART_BRR_F_MASK GENMASK(7, 0)
|
||||
#define USART_BRR_M_SHIFT 4
|
||||
#define USART_BRR_M_MASK GENMASK(15, 4)
|
||||
|
||||
#define USART_ICR_ORECF BIT(3)
|
||||
#define USART_ICR_FECF BIT(1)
|
||||
#define USART_ICR_PCECF BIT(0)
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,173 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright (C) 2012-2015 Panasonic Corporation
|
||||
* Copyright (C) 2015-2016 Socionext Inc.
|
||||
* Author: Masahiro Yamada <yamada.masahiro@socionext.com>
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <dm.h>
|
||||
#include <linux/bug.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/serial_reg.h>
|
||||
#include <linux/sizes.h>
|
||||
#include <linux/errno.h>
|
||||
#include <serial.h>
|
||||
#include <fdtdec.h>
|
||||
|
||||
/*
|
||||
* Note: Register map is slightly different from that of 16550.
|
||||
*/
|
||||
struct uniphier_serial {
|
||||
u32 rx; /* In: Receive buffer */
|
||||
#define tx rx /* Out: Transmit buffer */
|
||||
u32 ier; /* Interrupt Enable Register */
|
||||
u32 iir; /* In: Interrupt ID Register */
|
||||
u32 char_fcr; /* Charactor / FIFO Control Register */
|
||||
u32 lcr_mcr; /* Line/Modem Control Register */
|
||||
#define LCR_SHIFT 8
|
||||
#define LCR_MASK (0xff << (LCR_SHIFT))
|
||||
u32 lsr; /* In: Line Status Register */
|
||||
u32 msr; /* In: Modem Status Register */
|
||||
u32 __rsv0;
|
||||
u32 __rsv1;
|
||||
u32 dlr; /* Divisor Latch Register */
|
||||
};
|
||||
|
||||
struct uniphier_serial_priv {
|
||||
struct uniphier_serial __iomem *membase;
|
||||
unsigned int uartclk;
|
||||
};
|
||||
|
||||
#define uniphier_serial_port(dev) \
|
||||
((struct uniphier_serial_priv *)dev_get_priv(dev))->membase
|
||||
|
||||
static int uniphier_serial_setbrg(struct udevice *dev, int baudrate)
|
||||
{
|
||||
struct uniphier_serial_priv *priv = dev_get_priv(dev);
|
||||
struct uniphier_serial __iomem *port = uniphier_serial_port(dev);
|
||||
const unsigned int mode_x_div = 16;
|
||||
unsigned int divisor;
|
||||
|
||||
divisor = DIV_ROUND_CLOSEST(priv->uartclk, mode_x_div * baudrate);
|
||||
|
||||
writel(divisor, &port->dlr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int uniphier_serial_getc(struct udevice *dev)
|
||||
{
|
||||
struct uniphier_serial __iomem *port = uniphier_serial_port(dev);
|
||||
|
||||
if (!(readl(&port->lsr) & UART_LSR_DR))
|
||||
return -EAGAIN;
|
||||
|
||||
return readl(&port->rx);
|
||||
}
|
||||
|
||||
static int uniphier_serial_putc(struct udevice *dev, const char c)
|
||||
{
|
||||
struct uniphier_serial __iomem *port = uniphier_serial_port(dev);
|
||||
|
||||
if (!(readl(&port->lsr) & UART_LSR_THRE))
|
||||
return -EAGAIN;
|
||||
|
||||
writel(c, &port->tx);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int uniphier_serial_pending(struct udevice *dev, bool input)
|
||||
{
|
||||
struct uniphier_serial __iomem *port = uniphier_serial_port(dev);
|
||||
|
||||
if (input)
|
||||
return readl(&port->lsr) & UART_LSR_DR;
|
||||
else
|
||||
return !(readl(&port->lsr) & UART_LSR_THRE);
|
||||
}
|
||||
|
||||
/*
|
||||
* SPL does not have enough memory footprint for the clock driver.
|
||||
* Hardcode clock frequency for each SoC.
|
||||
*/
|
||||
struct uniphier_serial_clk_data {
|
||||
const char *compatible;
|
||||
unsigned int clk_rate;
|
||||
};
|
||||
|
||||
static const struct uniphier_serial_clk_data uniphier_serial_clk_data[] = {
|
||||
{ .compatible = "socionext,uniphier-ld4", .clk_rate = 36864000 },
|
||||
{ .compatible = "socionext,uniphier-pro4", .clk_rate = 73728000 },
|
||||
{ .compatible = "socionext,uniphier-sld8", .clk_rate = 80000000 },
|
||||
{ .compatible = "socionext,uniphier-pro5", .clk_rate = 73728000 },
|
||||
{ .compatible = "socionext,uniphier-pxs2", .clk_rate = 88888888 },
|
||||
{ .compatible = "socionext,uniphier-ld6b", .clk_rate = 88888888 },
|
||||
{ .compatible = "socionext,uniphier-ld11", .clk_rate = 58823529 },
|
||||
{ .compatible = "socionext,uniphier-ld20", .clk_rate = 58823529 },
|
||||
{ .compatible = "socionext,uniphier-pxs3", .clk_rate = 58823529 },
|
||||
{ /* sentinel */ },
|
||||
};
|
||||
|
||||
static int uniphier_serial_probe(struct udevice *dev)
|
||||
{
|
||||
struct uniphier_serial_priv *priv = dev_get_priv(dev);
|
||||
struct uniphier_serial __iomem *port;
|
||||
const struct uniphier_serial_clk_data *clk_data;
|
||||
ofnode root_node;
|
||||
fdt_addr_t base;
|
||||
u32 tmp;
|
||||
|
||||
base = devfdt_get_addr(dev);
|
||||
if (base == FDT_ADDR_T_NONE)
|
||||
return -EINVAL;
|
||||
|
||||
port = devm_ioremap(dev, base, SZ_64);
|
||||
if (!port)
|
||||
return -ENOMEM;
|
||||
|
||||
priv->membase = port;
|
||||
|
||||
root_node = ofnode_path("/");
|
||||
clk_data = uniphier_serial_clk_data;
|
||||
while (clk_data->compatible) {
|
||||
if (ofnode_device_is_compatible(root_node,
|
||||
clk_data->compatible))
|
||||
break;
|
||||
clk_data++;
|
||||
}
|
||||
|
||||
if (WARN_ON(!clk_data->compatible))
|
||||
return -ENOTSUPP;
|
||||
|
||||
priv->uartclk = clk_data->clk_rate;
|
||||
|
||||
tmp = readl(&port->lcr_mcr);
|
||||
tmp &= ~LCR_MASK;
|
||||
tmp |= UART_LCR_WLEN8 << LCR_SHIFT;
|
||||
writel(tmp, &port->lcr_mcr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct udevice_id uniphier_uart_of_match[] = {
|
||||
{ .compatible = "socionext,uniphier-uart" },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
static const struct dm_serial_ops uniphier_serial_ops = {
|
||||
.setbrg = uniphier_serial_setbrg,
|
||||
.getc = uniphier_serial_getc,
|
||||
.putc = uniphier_serial_putc,
|
||||
.pending = uniphier_serial_pending,
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(uniphier_serial) = {
|
||||
.name = "uniphier-uart",
|
||||
.id = UCLASS_SERIAL,
|
||||
.of_match = uniphier_uart_of_match,
|
||||
.probe = uniphier_serial_probe,
|
||||
.priv_auto_alloc_size = sizeof(struct uniphier_serial_priv),
|
||||
.ops = &uniphier_serial_ops,
|
||||
};
|
||||
@@ -0,0 +1,138 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* (C) Copyright 2008 - 2015 Michal Simek <monstr@monstr.eu>
|
||||
* Clean driver and add xilinx constant from header file
|
||||
*
|
||||
* (C) Copyright 2004 Atmark Techno, Inc.
|
||||
* Yasushi SHOJI <yashi@atmark-techno.com>
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <common.h>
|
||||
#include <dm.h>
|
||||
#include <asm/io.h>
|
||||
#include <linux/compiler.h>
|
||||
#include <serial.h>
|
||||
|
||||
#define SR_TX_FIFO_FULL BIT(3) /* transmit FIFO full */
|
||||
#define SR_TX_FIFO_EMPTY BIT(2) /* transmit FIFO empty */
|
||||
#define SR_RX_FIFO_VALID_DATA BIT(0) /* data in receive FIFO */
|
||||
#define SR_RX_FIFO_FULL BIT(1) /* receive FIFO full */
|
||||
|
||||
#define ULITE_CONTROL_RST_TX 0x01
|
||||
#define ULITE_CONTROL_RST_RX 0x02
|
||||
|
||||
struct uartlite {
|
||||
unsigned int rx_fifo;
|
||||
unsigned int tx_fifo;
|
||||
unsigned int status;
|
||||
unsigned int control;
|
||||
};
|
||||
|
||||
struct uartlite_platdata {
|
||||
struct uartlite *regs;
|
||||
};
|
||||
|
||||
static int uartlite_serial_putc(struct udevice *dev, const char ch)
|
||||
{
|
||||
struct uartlite_platdata *plat = dev_get_platdata(dev);
|
||||
struct uartlite *regs = plat->regs;
|
||||
|
||||
if (in_be32(®s->status) & SR_TX_FIFO_FULL)
|
||||
return -EAGAIN;
|
||||
|
||||
out_be32(®s->tx_fifo, ch & 0xff);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int uartlite_serial_getc(struct udevice *dev)
|
||||
{
|
||||
struct uartlite_platdata *plat = dev_get_platdata(dev);
|
||||
struct uartlite *regs = plat->regs;
|
||||
|
||||
if (!(in_be32(®s->status) & SR_RX_FIFO_VALID_DATA))
|
||||
return -EAGAIN;
|
||||
|
||||
return in_be32(®s->rx_fifo) & 0xff;
|
||||
}
|
||||
|
||||
static int uartlite_serial_pending(struct udevice *dev, bool input)
|
||||
{
|
||||
struct uartlite_platdata *plat = dev_get_platdata(dev);
|
||||
struct uartlite *regs = plat->regs;
|
||||
|
||||
if (input)
|
||||
return in_be32(®s->status) & SR_RX_FIFO_VALID_DATA;
|
||||
|
||||
return !(in_be32(®s->status) & SR_TX_FIFO_EMPTY);
|
||||
}
|
||||
|
||||
static int uartlite_serial_probe(struct udevice *dev)
|
||||
{
|
||||
struct uartlite_platdata *plat = dev_get_platdata(dev);
|
||||
struct uartlite *regs = plat->regs;
|
||||
|
||||
out_be32(®s->control, 0);
|
||||
out_be32(®s->control, ULITE_CONTROL_RST_RX | ULITE_CONTROL_RST_TX);
|
||||
in_be32(®s->control);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int uartlite_serial_ofdata_to_platdata(struct udevice *dev)
|
||||
{
|
||||
struct uartlite_platdata *plat = dev_get_platdata(dev);
|
||||
|
||||
plat->regs = (struct uartlite *)devfdt_get_addr(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dm_serial_ops uartlite_serial_ops = {
|
||||
.putc = uartlite_serial_putc,
|
||||
.pending = uartlite_serial_pending,
|
||||
.getc = uartlite_serial_getc,
|
||||
};
|
||||
|
||||
static const struct udevice_id uartlite_serial_ids[] = {
|
||||
{ .compatible = "xlnx,opb-uartlite-1.00.b", },
|
||||
{ .compatible = "xlnx,xps-uartlite-1.00.a" },
|
||||
{ }
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(serial_uartlite) = {
|
||||
.name = "serial_uartlite",
|
||||
.id = UCLASS_SERIAL,
|
||||
.of_match = uartlite_serial_ids,
|
||||
.ofdata_to_platdata = uartlite_serial_ofdata_to_platdata,
|
||||
.platdata_auto_alloc_size = sizeof(struct uartlite_platdata),
|
||||
.probe = uartlite_serial_probe,
|
||||
.ops = &uartlite_serial_ops,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_DEBUG_UART_UARTLITE
|
||||
|
||||
#include <debug_uart.h>
|
||||
|
||||
static inline void _debug_uart_init(void)
|
||||
{
|
||||
struct uartlite *regs = (struct uartlite *)CONFIG_DEBUG_UART_BASE;
|
||||
|
||||
out_be32(®s->control, 0);
|
||||
out_be32(®s->control, ULITE_CONTROL_RST_RX | ULITE_CONTROL_RST_TX);
|
||||
in_be32(®s->control);
|
||||
}
|
||||
|
||||
static inline void _debug_uart_putc(int ch)
|
||||
{
|
||||
struct uartlite *regs = (struct uartlite *)CONFIG_DEBUG_UART_BASE;
|
||||
|
||||
while (in_be32(®s->status) & SR_TX_FIFO_FULL)
|
||||
;
|
||||
|
||||
out_be32(®s->tx_fifo, ch & 0xff);
|
||||
}
|
||||
|
||||
DEBUG_UART_FUNCS
|
||||
#endif
|
||||
@@ -0,0 +1,235 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright (C) 2012 Michal Simek <monstr@monstr.eu>
|
||||
* Copyright (C) 2011-2012 Xilinx, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <clk.h>
|
||||
#include <common.h>
|
||||
#include <debug_uart.h>
|
||||
#include <dm.h>
|
||||
#include <errno.h>
|
||||
#include <fdtdec.h>
|
||||
#include <watchdog.h>
|
||||
#include <asm/io.h>
|
||||
#include <linux/compiler.h>
|
||||
#include <serial.h>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
#define ZYNQ_UART_SR_TXACTIVE BIT(11) /* TX active */
|
||||
#define ZYNQ_UART_SR_TXFULL BIT(4) /* TX FIFO full */
|
||||
#define ZYNQ_UART_SR_RXEMPTY BIT(1) /* RX FIFO empty */
|
||||
|
||||
#define ZYNQ_UART_CR_TX_EN BIT(4) /* TX enabled */
|
||||
#define ZYNQ_UART_CR_RX_EN BIT(2) /* RX enabled */
|
||||
#define ZYNQ_UART_CR_TXRST BIT(1) /* TX logic reset */
|
||||
#define ZYNQ_UART_CR_RXRST BIT(0) /* RX logic reset */
|
||||
|
||||
#define ZYNQ_UART_MR_PARITY_NONE 0x00000020 /* No parity mode */
|
||||
|
||||
struct uart_zynq {
|
||||
u32 control; /* 0x0 - Control Register [8:0] */
|
||||
u32 mode; /* 0x4 - Mode Register [10:0] */
|
||||
u32 reserved1[4];
|
||||
u32 baud_rate_gen; /* 0x18 - Baud Rate Generator [15:0] */
|
||||
u32 reserved2[4];
|
||||
u32 channel_sts; /* 0x2c - Channel Status [11:0] */
|
||||
u32 tx_rx_fifo; /* 0x30 - FIFO [15:0] or [7:0] */
|
||||
u32 baud_rate_divider; /* 0x34 - Baud Rate Divider [7:0] */
|
||||
};
|
||||
|
||||
struct zynq_uart_platdata {
|
||||
struct uart_zynq *regs;
|
||||
};
|
||||
|
||||
/* Set up the baud rate in gd struct */
|
||||
static void _uart_zynq_serial_setbrg(struct uart_zynq *regs,
|
||||
unsigned long clock, unsigned long baud)
|
||||
{
|
||||
/* Calculation results. */
|
||||
unsigned int calc_bauderror, bdiv, bgen;
|
||||
unsigned long calc_baud = 0;
|
||||
|
||||
/* Covering case where input clock is so slow */
|
||||
if (clock < 1000000 && baud > 4800)
|
||||
baud = 4800;
|
||||
|
||||
/* master clock
|
||||
* Baud rate = ------------------
|
||||
* bgen * (bdiv + 1)
|
||||
*
|
||||
* Find acceptable values for baud generation.
|
||||
*/
|
||||
for (bdiv = 4; bdiv < 255; bdiv++) {
|
||||
bgen = clock / (baud * (bdiv + 1));
|
||||
if (bgen < 2 || bgen > 65535)
|
||||
continue;
|
||||
|
||||
calc_baud = clock / (bgen * (bdiv + 1));
|
||||
|
||||
/*
|
||||
* Use first calculated baudrate with
|
||||
* an acceptable (<3%) error
|
||||
*/
|
||||
if (baud > calc_baud)
|
||||
calc_bauderror = baud - calc_baud;
|
||||
else
|
||||
calc_bauderror = calc_baud - baud;
|
||||
if (((calc_bauderror * 100) / baud) < 3)
|
||||
break;
|
||||
}
|
||||
|
||||
writel(bdiv, ®s->baud_rate_divider);
|
||||
writel(bgen, ®s->baud_rate_gen);
|
||||
}
|
||||
|
||||
/* Initialize the UART, with...some settings. */
|
||||
static void _uart_zynq_serial_init(struct uart_zynq *regs)
|
||||
{
|
||||
/* RX/TX enabled & reset */
|
||||
writel(ZYNQ_UART_CR_TX_EN | ZYNQ_UART_CR_RX_EN | ZYNQ_UART_CR_TXRST | \
|
||||
ZYNQ_UART_CR_RXRST, ®s->control);
|
||||
writel(ZYNQ_UART_MR_PARITY_NONE, ®s->mode); /* 8 bit, no parity */
|
||||
}
|
||||
|
||||
static int _uart_zynq_serial_putc(struct uart_zynq *regs, const char c)
|
||||
{
|
||||
if (readl(®s->channel_sts) & ZYNQ_UART_SR_TXFULL)
|
||||
return -EAGAIN;
|
||||
|
||||
writel(c, ®s->tx_rx_fifo);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int zynq_serial_setbrg(struct udevice *dev, int baudrate)
|
||||
{
|
||||
struct zynq_uart_platdata *platdata = dev_get_platdata(dev);
|
||||
unsigned long clock;
|
||||
|
||||
int ret;
|
||||
struct clk clk;
|
||||
|
||||
ret = clk_get_by_index(dev, 0, &clk);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "failed to get clock\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
clock = clk_get_rate(&clk);
|
||||
if (IS_ERR_VALUE(clock)) {
|
||||
dev_err(dev, "failed to get rate\n");
|
||||
return clock;
|
||||
}
|
||||
debug("%s: CLK %ld\n", __func__, clock);
|
||||
|
||||
ret = clk_enable(&clk);
|
||||
if (ret && ret != -ENOSYS) {
|
||||
dev_err(dev, "failed to enable clock\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
_uart_zynq_serial_setbrg(platdata->regs, clock, baudrate);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int zynq_serial_probe(struct udevice *dev)
|
||||
{
|
||||
struct zynq_uart_platdata *platdata = dev_get_platdata(dev);
|
||||
|
||||
/* No need to reinitialize the UART after relocation */
|
||||
if (gd->flags & GD_FLG_RELOC)
|
||||
return 0;
|
||||
|
||||
_uart_zynq_serial_init(platdata->regs);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int zynq_serial_getc(struct udevice *dev)
|
||||
{
|
||||
struct zynq_uart_platdata *platdata = dev_get_platdata(dev);
|
||||
struct uart_zynq *regs = platdata->regs;
|
||||
|
||||
if (readl(®s->channel_sts) & ZYNQ_UART_SR_RXEMPTY)
|
||||
return -EAGAIN;
|
||||
|
||||
return readl(®s->tx_rx_fifo);
|
||||
}
|
||||
|
||||
static int zynq_serial_putc(struct udevice *dev, const char ch)
|
||||
{
|
||||
struct zynq_uart_platdata *platdata = dev_get_platdata(dev);
|
||||
|
||||
return _uart_zynq_serial_putc(platdata->regs, ch);
|
||||
}
|
||||
|
||||
static int zynq_serial_pending(struct udevice *dev, bool input)
|
||||
{
|
||||
struct zynq_uart_platdata *platdata = dev_get_platdata(dev);
|
||||
struct uart_zynq *regs = platdata->regs;
|
||||
|
||||
if (input)
|
||||
return !(readl(®s->channel_sts) & ZYNQ_UART_SR_RXEMPTY);
|
||||
else
|
||||
return !!(readl(®s->channel_sts) & ZYNQ_UART_SR_TXACTIVE);
|
||||
}
|
||||
|
||||
static int zynq_serial_ofdata_to_platdata(struct udevice *dev)
|
||||
{
|
||||
struct zynq_uart_platdata *platdata = dev_get_platdata(dev);
|
||||
|
||||
platdata->regs = (struct uart_zynq *)dev_read_addr(dev);
|
||||
if (IS_ERR(platdata->regs))
|
||||
return PTR_ERR(platdata->regs);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dm_serial_ops zynq_serial_ops = {
|
||||
.putc = zynq_serial_putc,
|
||||
.pending = zynq_serial_pending,
|
||||
.getc = zynq_serial_getc,
|
||||
.setbrg = zynq_serial_setbrg,
|
||||
};
|
||||
|
||||
static const struct udevice_id zynq_serial_ids[] = {
|
||||
{ .compatible = "xlnx,xuartps" },
|
||||
{ .compatible = "cdns,uart-r1p8" },
|
||||
{ .compatible = "cdns,uart-r1p12" },
|
||||
{ }
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(serial_zynq) = {
|
||||
.name = "serial_zynq",
|
||||
.id = UCLASS_SERIAL,
|
||||
.of_match = zynq_serial_ids,
|
||||
.ofdata_to_platdata = zynq_serial_ofdata_to_platdata,
|
||||
.platdata_auto_alloc_size = sizeof(struct zynq_uart_platdata),
|
||||
.probe = zynq_serial_probe,
|
||||
.ops = &zynq_serial_ops,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_DEBUG_UART_ZYNQ
|
||||
static inline void _debug_uart_init(void)
|
||||
{
|
||||
struct uart_zynq *regs = (struct uart_zynq *)CONFIG_DEBUG_UART_BASE;
|
||||
|
||||
_uart_zynq_serial_init(regs);
|
||||
_uart_zynq_serial_setbrg(regs, CONFIG_DEBUG_UART_CLOCK,
|
||||
CONFIG_BAUDRATE);
|
||||
}
|
||||
|
||||
static inline void _debug_uart_putc(int ch)
|
||||
{
|
||||
struct uart_zynq *regs = (struct uart_zynq *)CONFIG_DEBUG_UART_BASE;
|
||||
|
||||
while (_uart_zynq_serial_putc(regs, ch) == -EAGAIN)
|
||||
WATCHDOG_RESET();
|
||||
}
|
||||
|
||||
DEBUG_UART_FUNCS
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,76 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/*
|
||||
* (C) Copyright 2003
|
||||
* Gerry Hamel, geh@ti.com, Texas Instruments
|
||||
*
|
||||
* (C) Copyright 2006
|
||||
* Bryan O'Donoghue, bodonoghue@codehermit.ie, CodeHermit
|
||||
*/
|
||||
|
||||
#ifndef __USB_TTY_H__
|
||||
#define __USB_TTY_H__
|
||||
|
||||
#include <usbdevice.h>
|
||||
#if defined(CONFIG_PPC)
|
||||
#include <usb/mpc8xx_udc.h>
|
||||
#elif defined(CONFIG_CPU_PXA27X)
|
||||
#include <usb/pxa27x_udc.h>
|
||||
#elif defined(CONFIG_DW_UDC)
|
||||
#include <usb/designware_udc.h>
|
||||
#elif defined(CONFIG_CI_UDC)
|
||||
#include <usb/ci_udc.h>
|
||||
#endif
|
||||
|
||||
#include <usb/udc.h>
|
||||
#include <version.h>
|
||||
|
||||
/* If no VendorID/ProductID is defined in config.h, pretend to be Linux
|
||||
* DO NOT Reuse this Vendor/Product setup with protocol incompatible devices */
|
||||
|
||||
#ifndef CONFIG_USBD_VENDORID
|
||||
#define CONFIG_USBD_VENDORID 0x0525 /* Linux/NetChip */
|
||||
#endif
|
||||
#ifndef CONFIG_USBD_PRODUCTID_GSERIAL
|
||||
#define CONFIG_USBD_PRODUCTID_GSERIAL 0xa4a6 /* gserial */
|
||||
#endif
|
||||
#ifndef CONFIG_USBD_PRODUCTID_CDCACM
|
||||
#define CONFIG_USBD_PRODUCTID_CDCACM 0xa4a7 /* CDC ACM */
|
||||
#endif
|
||||
#ifndef CONFIG_USBD_MANUFACTURER
|
||||
#define CONFIG_USBD_MANUFACTURER "Das U-Boot"
|
||||
#endif
|
||||
#ifndef CONFIG_USBD_PRODUCT_NAME
|
||||
#define CONFIG_USBD_PRODUCT_NAME U_BOOT_VERSION
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_USBD_CONFIGURATION_STR
|
||||
#define CONFIG_USBD_CONFIGURATION_STR "TTY via USB"
|
||||
#endif
|
||||
|
||||
#define CONFIG_USBD_SERIAL_OUT_ENDPOINT UDC_OUT_ENDPOINT
|
||||
#define CONFIG_USBD_SERIAL_OUT_PKTSIZE UDC_OUT_PACKET_SIZE
|
||||
#define CONFIG_USBD_SERIAL_IN_ENDPOINT UDC_IN_ENDPOINT
|
||||
#define CONFIG_USBD_SERIAL_IN_PKTSIZE UDC_IN_PACKET_SIZE
|
||||
#define CONFIG_USBD_SERIAL_INT_ENDPOINT UDC_INT_ENDPOINT
|
||||
#define CONFIG_USBD_SERIAL_INT_PKTSIZE UDC_INT_PACKET_SIZE
|
||||
#define CONFIG_USBD_SERIAL_BULK_PKTSIZE UDC_BULK_PACKET_SIZE
|
||||
|
||||
#if defined(CONFIG_USBD_HS)
|
||||
#define CONFIG_USBD_SERIAL_BULK_HS_PKTSIZE UDC_BULK_HS_PACKET_SIZE
|
||||
#endif
|
||||
|
||||
#define USBTTY_DEVICE_CLASS COMMUNICATIONS_DEVICE_CLASS
|
||||
|
||||
#define USBTTY_BCD_DEVICE 0x00
|
||||
#define USBTTY_MAXPOWER 0x00
|
||||
|
||||
#define STR_LANG 0x00
|
||||
#define STR_MANUFACTURER 0x01
|
||||
#define STR_PRODUCT 0x02
|
||||
#define STR_SERIAL 0x03
|
||||
#define STR_CONFIG 0x04
|
||||
#define STR_DATA_INTERFACE 0x05
|
||||
#define STR_CTRL_INTERFACE 0x06
|
||||
#define STR_COUNT 0x07
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user