diff options
Diffstat (limited to 'roms/u-boot/drivers/serial')
55 files changed, 14745 insertions, 0 deletions
diff --git a/roms/u-boot/drivers/serial/Kconfig b/roms/u-boot/drivers/serial/Kconfig new file mode 100644 index 000000000..6d1c4530d --- /dev/null +++ b/roms/u-boot/drivers/serial/Kconfig @@ -0,0 +1,947 @@ +# +# 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 + select SYS_MALLOC_F + 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 SERIAL_PROBE_ALL + bool "Probe all available serial devices" + depends on DM_SERIAL + default n + help + The serial subsystem only probes for a single serial device, + but does not probe for other remaining serial devices. + With this option set, we make probing and searching for + all available devices optional. + Normally, U-Boot talks to one serial port at a time, but SBSA + compliant UART devices like PL011 require initialization + by firmware and to let the kernel use serial port for sending + and receiving the characters. + + If unsure, say N. + +config SPL_DM_SERIAL + bool "Enable Driver Model for serial drivers in SPL" + depends on DM_SERIAL && SPL_DM + select SYS_SPL_MALLOC_F + 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 + select SYS_TPL_MALLOC_F + 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" + depends on 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" + depends on 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" + depends on 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" + depends on SYS_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" + depends on ARCH_EXYNOS || ARCH_S5PC1XX + 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" + depends on 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" + depends on 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" + depends on MVEBU_A3700_UART + 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" + depends on ZYNQ_SERIAL + 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" + depends on PL01X_SERIAL + 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" + depends on PL011_SERIAL + 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" + depends on SIFIVE_SERIAL + 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" + depends on OMAP_SERIAL + 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. + +config DEBUG_UART_MT7620 + bool "UART driver for MediaTek MT7620 and earlier SoCs" + depends on MT7620_SERIAL + help + Select this to enable a debug UART using the UART driver for + MediaTek MT7620 and earlier SoCs. + 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 ARM_DCC + bool "ARM Debug Communication Channel (DCC) as UART support" + depends on ARM + help + Select this to enable using the ARM DCC as a form of UART. + +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 COREBOOT_SERIAL + bool "Coreboot UART support" + depends on DM_SERIAL + default y if SYS_COREBOOT + select SYS_NS16550 + help + Select this to enable a ns16550-style UART where the platform data + comes from the coreboot 'sysinfo' tables. This allows U-Boot to have + a serial console on any platform without needing to change the + device tree, etc. + +config CORTINA_UART + bool "Cortina UART support" + depends on DM_SERIAL + help + Select this to enable UART support for Cortina-Access UART devices + found on CAxxxx 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 ARCH_MX25 || ARCH_MX31 || TARGET_FLEA3 \ + || 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 NS16550_DYNAMIC + bool "Allow NS16550 to be configured at runtime" + default y if SYS_COREBOOT || SYS_SLIMBOOTLOADER + help + Enable this option to allow device-tree control of the driver. + + Normally this driver is controlled by the following options: + + CONFIG_SYS_NS16550_PORT_MAPPED - indicates that port I/O is used for + access. If not enabled, then the UART is memory-mapped. + CONFIG_SYS_NS16550_MEM32 - if memory-mapped, indicates that 32-bit + access should be used (instead of 8-bit) + CONFIG_SYS_NS16550_REG_SIZE - indicates register width and also + endianness. If positive, big-endian access is used. If negative, + little-endian is used. + + It is not a good practice for a driver to be statically configured, + since it prevents the same driver being used for different types of + UARTs in a system. This option avoids this problem at the cost of a + slightly increased code size. + +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 S5P_SERIAL + bool "Support for Samsung S5P UART" + depends on ARCH_EXYNOS || ARCH_S5PC1XX + default y + help + Select this to enable Samsung S5P UART support. + +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 + 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 OCTEON_SERIAL_BOOTCMD + bool "MIPS Octeon PCI remote bootcmd input" + depends on ARCH_OCTEON + depends on DM_SERIAL + select SYS_IS_IN_ENV + select CONSOLE_MUX + help + This driver supports remote input over the PCIe bus from a host + to U-Boot for entering commands. It is utilized by the host + commands 'oct-remote-load' and 'oct-remote-bootcmd'. + +config OCTEON_SERIAL_PCIE_CONSOLE + bool "MIPS Octeon PCIe remote console" + depends on ARCH_OCTEON + depends on (DM_SERIAL && DM_STDIO) + select SYS_STDIO_DEREGISTER + select SYS_CONSOLE_IS_IN_ENV + select CONSOLE_MUX + help + This driver supports remote console over the PCIe bus when the + Octeon is running in PCIe target mode. The host program + 'oct-remote-console' can be used to connect to this console. + The console number will likely be 0 or 1. + +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 + 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 MT7620_SERIAL + bool "UART driver for MediaTek MT7620 and earlier SoCs" + depends on DM_SERIAL + help + Select this to enable UART support for MediaTek MT7620 and earlier + SoCs. This driver uses driver model and requires a device tree + binding to operate. + The UART driver for MediaTek MT7620 and earlier SoCs is *NOT* + compatible with the ns16550a UART. + +config MPC8XX_CONS + bool "Console driver for MPC8XX" + depends on MPC8xx + default y + +config XEN_SERIAL + bool "XEN serial support" + depends on XEN + help + If built without DM support, then requires Xen + to be built with CONFIG_VERBOSE_DEBUG. + +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 diff --git a/roms/u-boot/drivers/serial/Makefile b/roms/u-boot/drivers/serial/Makefile new file mode 100644 index 000000000..6c0fdca58 --- /dev/null +++ b/roms/u-boot/drivers/serial/Makefile @@ -0,0 +1,80 @@ +# 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_COREBOOT_SERIAL) += serial_coreboot.o +obj-$(CONFIG_CORTINA_UART) += serial_cortina.o +obj-$(CONFIG_EFI_APP) += serial_efi.o +obj-$(CONFIG_LPC32XX_HSUART) += lpc32xx_hsuart.o +obj-$(CONFIG_MCFUART) += serial_mcf.o +obj-$(CONFIG_SYS_NS16550) += ns16550.o +obj-$(CONFIG_S5P_SERIAL) += 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_OCTEON_SERIAL_BOOTCMD) += serial_octeon_bootcmd.o +obj-$(CONFIG_OCTEON_SERIAL_PCIE_CONSOLE) += serial_octeon_pcie_console.o +obj-$(CONFIG_OWL_SERIAL) += serial_owl.o +obj-$(CONFIG_OMAP_SERIAL) += serial_omap.o +obj-$(CONFIG_MTK_SERIAL) += serial_mtk.o +obj-$(CONFIG_MT7620_SERIAL) += serial_mt7620.o +obj-$(CONFIG_SIFIVE_SERIAL) += serial_sifive.o +obj-$(CONFIG_XEN_SERIAL) += serial_xen.o + +ifndef CONFIG_SPL_BUILD +obj-$(CONFIG_USB_TTY) += usbtty.o +endif diff --git a/roms/u-boot/drivers/serial/altera_jtag_uart.c b/roms/u-boot/drivers/serial/altera_jtag_uart.c new file mode 100644 index 000000000..4435fcf56 --- /dev/null +++ b/roms/u-boot/drivers/serial/altera_jtag_uart.c @@ -0,0 +1,151 @@ +// 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> +#include <linux/bitops.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_plat { + 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_plat *plat = dev_get_plat(dev); + 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_plat *plat = dev_get_plat(dev); + 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_plat *plat = dev_get_plat(dev); + 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_plat *plat = dev_get_plat(dev); + struct altera_jtaguart_regs *const regs = plat->regs; + + writel(ALTERA_JTAG_AC, ®s->control); /* clear AC flag */ +#endif + return 0; +} + +static int altera_jtaguart_of_to_plat(struct udevice *dev) +{ + struct altera_jtaguart_plat *plat = dev_get_plat(dev); + + plat->regs = map_physmem(dev_read_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, + .of_to_plat = altera_jtaguart_of_to_plat, + .plat_auto = sizeof(struct altera_jtaguart_plat), + .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 diff --git a/roms/u-boot/drivers/serial/altera_uart.c b/roms/u-boot/drivers/serial/altera_uart.c new file mode 100644 index 000000000..b18be6e24 --- /dev/null +++ b/roms/u-boot/drivers/serial/altera_uart.c @@ -0,0 +1,149 @@ +// 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> +#include <linux/bitops.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_plat { + struct altera_uart_regs *regs; + unsigned int uartclk; +}; + +static int altera_uart_setbrg(struct udevice *dev, int baudrate) +{ + struct altera_uart_plat *plat = dev_get_plat(dev); + 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_plat *plat = dev_get_plat(dev); + 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_plat *plat = dev_get_plat(dev); + 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_plat *plat = dev_get_plat(dev); + 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_of_to_plat(struct udevice *dev) +{ + struct altera_uart_plat *plat = dev_get_plat(dev); + + plat->regs = map_physmem(dev_read_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, + .of_to_plat = altera_uart_of_to_plat, + .plat_auto = sizeof(struct altera_uart_plat), + .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 diff --git a/roms/u-boot/drivers/serial/arm_dcc.c b/roms/u-boot/drivers/serial/arm_dcc.c new file mode 100644 index 000000000..dfcb6fd69 --- /dev/null +++ b/roms/u-boot/drivers/serial/arm_dcc.c @@ -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 diff --git a/roms/u-boot/drivers/serial/atmel_usart.c b/roms/u-boot/drivers/serial/atmel_usart.c new file mode 100644 index 000000000..bd14f3e78 --- /dev/null +++ b/roms/u-boot/drivers/serial/atmel_usart.c @@ -0,0 +1,338 @@ +// 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 <malloc.h> +#include <watchdog.h> +#include <serial.h> +#include <debug_uart.h> +#include <asm/global_data.h> +#include <linux/compiler.h> +#include <linux/delay.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_plat *plat = dev_get_plat(dev); + struct atmel_serial_priv *priv = dev_get_priv(dev); + int ret; +#if CONFIG_IS_ENABLED(OF_CONTROL) + fdt_addr_t addr_base; + + addr_base = dev_read_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, + .plat_auto = sizeof(struct atmel_serial_plat), +#endif + .probe = atmel_serial_probe, + .ops = &atmel_serial_ops, +#if !CONFIG_IS_ENABLED(OF_CONTROL) + .flags = DM_FLAG_PRE_RELOC, +#endif + .priv_auto = 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 diff --git a/roms/u-boot/drivers/serial/atmel_usart.h b/roms/u-boot/drivers/serial/atmel_usart.h new file mode 100644 index 000000000..8f2748815 --- /dev/null +++ b/roms/u-boot/drivers/serial/atmel_usart.h @@ -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__ */ diff --git a/roms/u-boot/drivers/serial/lpc32xx_hsuart.c b/roms/u-boot/drivers/serial/lpc32xx_hsuart.c new file mode 100644 index 000000000..d39a3c049 --- /dev/null +++ b/roms/u-boot/drivers/serial/lpc32xx_hsuart.c @@ -0,0 +1,112 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2011-2015 Vladimir Zapolskiy <vz@mleia.com> + */ + +#include <common.h> +#include <clock_legacy.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_plat *plat = dev_get_plat(dev); + struct lpc32xx_hsuart_priv *priv = dev_get_priv(dev); + + priv->hsuart = (struct hsuart_regs *)plat->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 = sizeof(struct lpc32xx_hsuart_priv), + .flags = DM_FLAG_PRE_RELOC, +}; diff --git a/roms/u-boot/drivers/serial/ns16550.c b/roms/u-boot/drivers/serial/ns16550.c new file mode 100644 index 000000000..cc121eee2 --- /dev/null +++ b/roms/u-boot/drivers/serial/ns16550.c @@ -0,0 +1,633 @@ +/* + * COM1 NS16550 support + * originally from linux source (arch/powerpc/boot/ns16550.c) + * modified to use CONFIG_SYS_ISA_MEM and new defines + */ + +#include <clock_legacy.h> +#include <common.h> +#include <clk.h> +#include <dm.h> +#include <errno.h> +#include <log.h> +#include <ns16550.h> +#include <reset.h> +#include <serial.h> +#include <watchdog.h> +#include <asm/global_data.h> +#include <linux/err.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 + +/* + * Use this #ifdef for now since many platforms don't define in(), out(), + * out_le32(), etc. but we don't have #defines to indicate this. + * + * TODO(sjg@chromium.org): Add CONFIG options to indicate what I/O is available + * on a platform + */ +#ifdef CONFIG_NS16550_DYNAMIC +static void serial_out_dynamic(struct ns16550_plat *plat, u8 *addr, + int value) +{ + if (plat->flags & NS16550_FLAG_IO) { + outb(value, addr); + } else if (plat->reg_width == 4) { + if (plat->flags & NS16550_FLAG_ENDIAN) { + if (plat->flags & NS16550_FLAG_BE) + out_be32(addr, value); + else + out_le32(addr, value); + } else { + writel(value, addr); + } + } else if (plat->flags & NS16550_FLAG_BE) { + writeb(value, addr + (1 << plat->reg_shift) - 1); + } else { + writeb(value, addr); + } +} + +static int serial_in_dynamic(struct ns16550_plat *plat, u8 *addr) +{ + if (plat->flags & NS16550_FLAG_IO) { + return inb(addr); + } else if (plat->reg_width == 4) { + if (plat->flags & NS16550_FLAG_ENDIAN) { + if (plat->flags & NS16550_FLAG_BE) + return in_be32(addr); + else + return in_le32(addr); + } else { + return readl(addr); + } + } else if (plat->flags & NS16550_FLAG_BE) { + return readb(addr + (1 << plat->reg_shift) - 1); + } else { + return readb(addr); + } +} +#else +static inline void serial_out_dynamic(struct ns16550_plat *plat, u8 *addr, + int value) +{ +} + +static inline int serial_in_dynamic(struct ns16550_plat *plat, u8 *addr) +{ + return 0; +} + +#endif /* CONFIG_NS16550_DYNAMIC */ + +static void ns16550_writeb(struct ns16550 *port, int offset, int value) +{ + struct ns16550_plat *plat = port->plat; + unsigned char *addr; + + offset *= 1 << plat->reg_shift; + addr = (unsigned char *)plat->base + offset + plat->reg_offset; + + if (IS_ENABLED(CONFIG_NS16550_DYNAMIC)) + serial_out_dynamic(plat, addr, value); + else + serial_out_shift(addr, plat->reg_shift, value); +} + +static int ns16550_readb(struct ns16550 *port, int offset) +{ + struct ns16550_plat *plat = port->plat; + unsigned char *addr; + + offset *= 1 << plat->reg_shift; + addr = (unsigned char *)plat->base + offset + plat->reg_offset; + + if (IS_ENABLED(CONFIG_NS16550_DYNAMIC)) + return serial_in_dynamic(plat, addr); + else + return serial_in_shift(addr, plat->reg_shift); +} + +static u32 ns16550_getfcr(struct ns16550 *port) +{ + struct ns16550_plat *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(struct ns16550 *port) +{ + return UART_FCR_DEFVAL; +} +#endif + +int ns16550_calc_divisor(struct ns16550 *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(struct ns16550 *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(struct ns16550 *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); + else { + // Re-use old baud rate divisor to flush transmit reg. + const int dll = serial_in(&com_port->dll); + const int dlm = serial_in(&com_port->dlm); + const int divisor = dll | (dlm << 8); + ns16550_setbrg(com_port, 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(struct ns16550 *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(struct ns16550 *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(struct ns16550 *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(struct ns16550 *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_plat *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_plat *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; + info->clock = plat->clock; + + return 0; +} + +static int ns16550_serial_assign_base(struct ns16550_plat *plat, fdt_addr_t base) +{ + if (base == FDT_ADDR_T_NONE) + return -EINVAL; + +#ifdef CONFIG_SYS_NS16550_PORT_MAPPED + plat->base = base; +#else + plat->base = (unsigned long)map_physmem(base, 0, MAP_NOCACHE); +#endif + + return 0; +} + +int ns16550_serial_probe(struct udevice *dev) +{ + struct ns16550_plat *plat = dev_get_plat(dev); + struct ns16550 *const com_port = dev_get_priv(dev); + struct reset_ctl_bulk reset_bulk; + fdt_addr_t addr; + int ret; + + /* + * If we are on PCI bus, either directly attached to a PCI root port, + * or via a PCI bridge, assign plat->base before probing hardware. + */ + if (device_is_on_pci_bus(dev)) { + addr = devfdt_get_addr_pci(dev); + ret = ns16550_serial_assign_base(plat, addr); + if (ret) + return ret; + } + + ret = reset_get_bulk(dev, &reset_bulk); + if (!ret) + reset_deassert_bulk(&reset_bulk); + + com_port->plat = dev_get_plat(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_of_to_plat(struct udevice *dev) +{ + struct ns16550_plat *plat = dev_get_plat(dev); + const u32 port_type = dev_get_driver_data(dev); + fdt_addr_t addr; + struct clk clk; + int err; + + addr = dev_read_addr(dev); + err = ns16550_serial_assign_base(plat, addr); + if (err && !device_is_on_pci_bus(dev)) + return err; + + 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) + plat->clock = 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, + .of_to_plat = ns16550_serial_of_to_plat, + .plat_auto = sizeof(struct ns16550_plat), +#endif + .priv_auto = sizeof(struct ns16550), + .probe = ns16550_serial_probe, + .ops = &ns16550_serial_ops, +#if !CONFIG_IS_ENABLED(OF_CONTROL) + .flags = DM_FLAG_PRE_RELOC, +#endif +}; + +DM_DRIVER_ALIAS(ns16550_serial, rockchip_rk3328_uart) +DM_DRIVER_ALIAS(ns16550_serial, rockchip_rk3368_uart) +DM_DRIVER_ALIAS(ns16550_serial, ti_da830_uart) +#endif +#endif /* SERIAL_PRESENT */ + +#endif /* CONFIG_DM_SERIAL */ diff --git a/roms/u-boot/drivers/serial/sandbox.c b/roms/u-boot/drivers/serial/sandbox.c new file mode 100644 index 000000000..5243c955f --- /dev/null +++ b/roms/u-boot/drivers/serial/sandbox.c @@ -0,0 +1,249 @@ +// 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 <lcd.h> +#include <os.h> +#include <serial.h> +#include <video.h> +#include <asm/global_data.h> +#include <linux/compiler.h> +#include <asm/serial.h> +#include <asm/state.h> + +DECLARE_GLOBAL_DATA_PTR; + +/** + * 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); + membuff_init(&priv->buf, priv->serial_buf, sizeof(priv->serial_buf)); + + return 0; +} + +static int sandbox_serial_remove(struct udevice *dev) +{ + struct sandbox_serial_plat *plat = dev_get_plat(dev); + + 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_plat *plat = dev_get_plat(dev); + + /* With of-platdata we don't real the colour correctly, so disable it */ + if (!CONFIG_IS_ENABLED(OF_PLATDATA) && 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 int sandbox_serial_pending(struct udevice *dev, bool input) +{ + struct sandbox_serial_priv *priv = dev_get_priv(dev); + ssize_t count; + char *data; + int avail; + + if (!input) + return 0; + + os_usleep(100); + if (!IS_ENABLED(CONFIG_SPL_BUILD)) + video_sync_all(); + avail = membuff_putraw(&priv->buf, 100, false, &data); + if (!avail) + return 1; /* buffer full */ + + count = os_read(0, data, avail); + if (count > 0) + membuff_putraw(&priv->buf, count, true, &data); + + return membuff_avail(&priv->buf); +} + +static int sandbox_serial_getc(struct udevice *dev) +{ + struct sandbox_serial_priv *priv = dev_get_priv(dev); + + if (!sandbox_serial_pending(dev, true)) + return -EAGAIN; /* buffer empty */ + + return membuff_getbyte(&priv->buf); +} + +#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, + .clock = SERIAL_DEFAULT_CLOCK, + }; + + if (!serial_info) + return -EINVAL; + + *serial_info = info; + + return 0; +} + +static const char * const ansi_colour[] = { + "black", "red", "green", "yellow", "blue", "megenta", "cyan", + "white", +}; + +static int sandbox_serial_of_to_plat(struct udevice *dev) +{ + struct sandbox_serial_plat *plat = dev_get_plat(dev); + const char *colour; + int i; + + if (CONFIG_IS_ENABLED(OF_PLATDATA)) + return 0; + plat->colour = -1; + colour = dev_read_string(dev, "sandbox,text-colour"); + 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(sandbox_serial) = { + .name = "sandbox_serial", + .id = UCLASS_SERIAL, + .of_match = sandbox_serial_ids, + .of_to_plat = sandbox_serial_of_to_plat, + .plat_auto = sizeof(struct sandbox_serial_plat), + .priv_auto = sizeof(struct sandbox_serial_priv), + .probe = sandbox_serial_probe, + .remove = sandbox_serial_remove, + .ops = &sandbox_serial_ops, + .flags = DM_FLAG_PRE_RELOC, +}; + +#if !CONFIG_IS_ENABLED(OF_PLATDATA) +static const struct sandbox_serial_plat platdata_non_fdt = { + .colour = -1, +}; + +U_BOOT_DRVINFO(serial_sandbox_non_fdt) = { + .name = "sandbox_serial", + .plat = &platdata_non_fdt, +}; +#endif diff --git a/roms/u-boot/drivers/serial/serial-uclass.c b/roms/u-boot/drivers/serial/serial-uclass.c new file mode 100644 index 000000000..8a87eed68 --- /dev/null +++ b/roms/u-boot/drivers/serial/serial-uclass.c @@ -0,0 +1,522 @@ +// 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 <malloc.h> +#include <os.h> +#include <serial.h> +#include <stdio_dev.h> +#include <watchdog.h> +#include <asm/global_data.h> +#include <dm/lists.h> +#include <dm/device-internal.h> +#include <dm/of_access.h> +#include <linux/delay.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_get_flags(dev) & 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; + serial_setbrg(); +#endif + + return 0; +} + +/* Called after relocation */ +int serial_initialize(void) +{ + /* Scanning uclass to probe devices */ + if (IS_ENABLED(CONFIG_SERIAL_PROBE_ALL)) { + int ret; + + ret = uclass_probe_all(UCLASS_SERIAL); + if (ret) + return ret; + } + + return 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 (getchar() == '\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 = sizeof(struct serial_dev_priv), +}; +#endif diff --git a/roms/u-boot/drivers/serial/serial.c b/roms/u-boot/drivers/serial/serial.c new file mode 100644 index 000000000..dea25a049 --- /dev/null +++ b/roms/u-boot/drivers/serial/serial.c @@ -0,0 +1,555 @@ +// 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 <hang.h> +#include <serial.h> +#include <stdio_dev.h> +#include <post.h> +#include <asm/global_data.h> +#include <linux/compiler.h> +#include <errno.h> +#include <linux/delay.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 (getchar() == '\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. + */ +int 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); + + return 0; +} + +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) +{ + 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 diff --git a/roms/u-boot/drivers/serial/serial_ar933x.c b/roms/u-boot/drivers/serial/serial_ar933x.c new file mode 100644 index 000000000..da06bef97 --- /dev/null +++ b/roms/u-boot/drivers/serial/serial_ar933x.c @@ -0,0 +1,243 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2015-2016 Wills Wang <wills.wang@live.com> + */ + +#include <common.h> +#include <clock_legacy.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 <linux/bitops.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 = dev_read_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 = 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 diff --git a/roms/u-boot/drivers/serial/serial_arc.c b/roms/u-boot/drivers/serial/serial_arc.c new file mode 100644 index 000000000..8f3e4dd44 --- /dev/null +++ b/roms/u-boot/drivers/serial/serial_arc.c @@ -0,0 +1,159 @@ +/* + * 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> +#include <asm/global_data.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_plat { + 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_plat *plat = dev_get_plat(dev); + 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_plat *plat = dev_get_plat(dev); + 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_plat *plat = dev_get_plat(dev); + 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_plat *plat = dev_get_plat(dev); + 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_of_to_plat(struct udevice *dev) +{ + struct arc_serial_plat *plat = dev_get_plat(dev); + DECLARE_GLOBAL_DATA_PTR; + + plat->reg = dev_read_addr_ptr(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, + .of_to_plat = arc_serial_of_to_plat, + .plat_auto = sizeof(struct arc_serial_plat), + .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 diff --git a/roms/u-boot/drivers/serial/serial_bcm283x_mu.c b/roms/u-boot/drivers/serial/serial_bcm283x_mu.c new file mode 100644 index 000000000..58fa722b4 --- /dev/null +++ b/roms/u-boot/drivers/serial/serial_bcm283x_mu.c @@ -0,0 +1,204 @@ +// 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/bitops.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_plat *plat = dev_get_plat(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_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_probe(struct udevice *dev) +{ + struct bcm283x_mu_serial_plat *plat = dev_get_plat(dev); + struct bcm283x_mu_priv *priv = dev_get_priv(dev); + fdt_addr_t addr; + + /* Don't spawn the device if it's not muxed */ + if (!bcm283x_is_serial_muxed()) + return -ENODEV; + + /* + * Read the ofdata here rather than in an of_to_plat() method + * since we need the soc simple-bus to be probed so that the 'ranges' + * property is used. + */ + addr = dev_read_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; + + priv->regs = (struct bcm283x_mu_regs *)plat->base; + + 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), + .plat_auto = sizeof(struct bcm283x_mu_serial_plat), + .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 = sizeof(struct bcm283x_mu_priv), +}; diff --git a/roms/u-boot/drivers/serial/serial_bcm283x_pl011.c b/roms/u-boot/drivers/serial/serial_bcm283x_pl011.c new file mode 100644 index 000000000..2d2e97031 --- /dev/null +++ b/roms/u-boot/drivers/serial/serial_bcm283x_pl011.c @@ -0,0 +1,101 @@ +// 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_probe(struct udevice *dev) +{ + struct pl01x_serial_plat *plat = dev_get_plat(dev); + int ret; + + /* Don't spawn the device if it's not muxed */ + if (!bcm283x_is_serial_muxed()) + return -ENODEV; + + /* + * Read the ofdata here rather than in an of_to_plat() method + * since we need the soc simple-bus to be probed so that the 'ranges' + * property is used. + */ + ret = pl01x_serial_of_to_plat(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 pl01x_serial_probe(dev); +} + +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), + .probe = bcm283x_pl011_serial_probe, + .plat_auto = sizeof(struct pl01x_serial_plat), + .ops = &bcm283x_pl011_serial_ops, +#if !CONFIG_IS_ENABLED(OF_CONTROL) || CONFIG_IS_ENABLED(OF_BOARD) + .flags = DM_FLAG_PRE_RELOC, +#endif + .priv_auto = sizeof(struct pl01x_priv), +}; diff --git a/roms/u-boot/drivers/serial/serial_bcm6345.c b/roms/u-boot/drivers/serial/serial_bcm6345.c new file mode 100644 index 000000000..f08e91ff3 --- /dev/null +++ b/roms/u-boot/drivers/serial/serial_bcm6345.c @@ -0,0 +1,296 @@ +// 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 <malloc.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 = 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 diff --git a/roms/u-boot/drivers/serial/serial_coreboot.c b/roms/u-boot/drivers/serial/serial_coreboot.c new file mode 100644 index 000000000..de09c8681 --- /dev/null +++ b/roms/u-boot/drivers/serial/serial_coreboot.c @@ -0,0 +1,46 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * UART support for U-Boot when launched from Coreboot + * + * Copyright 2019 Google LLC + */ + +#include <common.h> +#include <dm.h> +#include <ns16550.h> +#include <serial.h> +#include <asm/cb_sysinfo.h> + +static int coreboot_of_to_plat(struct udevice *dev) +{ + struct ns16550_plat *plat = dev_get_plat(dev); + struct cb_serial *cb_info = lib_sysinfo.serial; + + plat->base = cb_info->baseaddr; + plat->reg_shift = cb_info->regwidth == 4 ? 2 : 0; + plat->reg_width = cb_info->regwidth; + plat->clock = cb_info->input_hertz; + plat->fcr = UART_FCR_DEFVAL; + plat->flags = 0; + if (cb_info->type == CB_SERIAL_TYPE_IO_MAPPED) + plat->flags |= NS16550_FLAG_IO; + + return 0; +} + +static const struct udevice_id coreboot_serial_ids[] = { + { .compatible = "coreboot-serial" }, + { }, +}; + +U_BOOT_DRIVER(coreboot_uart) = { + .name = "coreboot_uart", + .id = UCLASS_SERIAL, + .of_match = coreboot_serial_ids, + .priv_auto = sizeof(struct ns16550), + .plat_auto = sizeof(struct ns16550_plat), + .of_to_plat = coreboot_of_to_plat, + .probe = ns16550_serial_probe, + .ops = &ns16550_serial_ops, + .flags = DM_FLAG_PRE_RELOC, +}; diff --git a/roms/u-boot/drivers/serial/serial_cortina.c b/roms/u-boot/drivers/serial/serial_cortina.c new file mode 100644 index 000000000..6dc81a775 --- /dev/null +++ b/roms/u-boot/drivers/serial/serial_cortina.c @@ -0,0 +1,165 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (C) Copyright 2020 Cortina-Access Ltd. + * Common UART Driver for Cortina Access CAxxxx line of SoCs + * + */ + +#include <common.h> +#include <dm.h> +#include <errno.h> +#include <watchdog.h> +#include <asm/io.h> +#include <serial.h> +#include <linux/bitops.h> +#include <linux/compiler.h> + +/* Register definitions */ +#define UCFG 0x00 /* UART config register */ +#define UFC 0x04 /* Flow Control */ +#define URX_SAMPLE 0x08 /* UART RX Sample register */ +#define URT_TUNE 0x0C /* Fine tune of UART clk */ +#define UTX_DATA 0x10 /* UART TX Character data */ +#define URX_DATA 0x14 /* UART RX Character data */ +#define UINFO 0x18 /* UART Info */ +#define UINT_EN0 0x1C /* UART Interrupt enable 0 */ +#define UINT_EN1 0x20 /* UART Interrupt enable 1 */ +#define UINT0 0x24 /* UART Interrupt 0 setting/clearing */ +#define UINT1 0x28 /* UART Interrupt 1 setting/clearing */ +#define UINT_STAT 0x2C /* UART Interrupt Status */ + +/* UART Control Register Bit Fields */ +#define UCFG_BAUD_COUNT_MASK 0xFFFFFF00 +#define UCFG_BAUD_COUNT(x) ((x << 8) & UCFG_BAUD_COUNT_MASK) +#define UCFG_EN BIT(7) +#define UCFG_RX_EN BIT(6) +#define UCFG_TX_EN BIT(5) +#define UCFG_PARITY_EN BIT(4) +#define UCFG_PARITY_SEL BIT(3) +#define UCFG_2STOP_BIT BIT(2) +#define UCFG_CNT1 BIT(1) +#define UCFG_CNT0 BIT(0) +#define UCFG_CHAR_5 0 +#define UCFG_CHAR_6 1 +#define UCFG_CHAR_7 2 +#define UCFG_CHAR_8 3 + +#define UINFO_TX_FIFO_EMPTY BIT(3) +#define UINFO_TX_FIFO_FULL BIT(2) +#define UINFO_RX_FIFO_EMPTY BIT(1) +#define UINFO_RX_FIFO_FULL BIT(0) + +#define UINT_RX_NON_EMPTY BIT(6) +#define UINT_TX_EMPTY BIT(5) +#define UINT_RX_UNDERRUN BIT(4) +#define UINT_RX_OVERRUN BIT(3) +#define UINT_RX_PARITY_ERR BIT(2) +#define UINT_RX_STOP_ERR BIT(1) +#define UINT_TX_OVERRUN BIT(0) +#define UINT_MASK_ALL 0x7F + +struct ca_uart_priv { + void __iomem *base; +}; + +int ca_serial_setbrg(struct udevice *dev, int baudrate) +{ + struct ca_uart_priv *priv = dev_get_priv(dev); + unsigned int uart_ctrl, baud, sample; + + baud = CORTINA_UART_CLOCK / baudrate; + + uart_ctrl = readl(priv->base + UCFG); + uart_ctrl &= ~UCFG_BAUD_COUNT_MASK; + uart_ctrl |= UCFG_BAUD_COUNT(baud); + writel(uart_ctrl, priv->base + UCFG); + + sample = baud / 2; + sample = (sample < 7) ? 7 : sample; + writel(sample, priv->base + URX_SAMPLE); + + return 0; +} + +static int ca_serial_getc(struct udevice *dev) +{ + struct ca_uart_priv *priv = dev_get_priv(dev); + int ch; + + ch = readl(priv->base + URX_DATA) & 0xFF; + + return (int)ch; +} + +static int ca_serial_putc(struct udevice *dev, const char ch) +{ + struct ca_uart_priv *priv = dev_get_priv(dev); + unsigned int status; + + /* Retry if TX FIFO full */ + status = readl(priv->base + UINFO); + if (status & UINFO_TX_FIFO_FULL) + return -EAGAIN; + + writel(ch, priv->base + UTX_DATA); + + return 0; +} + +static int ca_serial_pending(struct udevice *dev, bool input) +{ + struct ca_uart_priv *priv = dev_get_priv(dev); + unsigned int status; + + status = readl(priv->base + UINFO); + + if (input) + return (status & UINFO_RX_FIFO_EMPTY) ? 0 : 1; + else + return (status & UINFO_TX_FIFO_FULL) ? 1 : 0; +} + +static int ca_serial_probe(struct udevice *dev) +{ + struct ca_uart_priv *priv = dev_get_priv(dev); + u32 uart_ctrl; + + /* Set data, parity and stop bits */ + uart_ctrl = UCFG_EN | UCFG_TX_EN | UCFG_RX_EN | UCFG_CHAR_8; + writel(uart_ctrl, priv->base + UCFG); + + return 0; +} + +static int ca_serial_of_to_plat(struct udevice *dev) +{ + struct ca_uart_priv *priv = dev_get_priv(dev); + + priv->base = dev_remap_addr_index(dev, 0); + if (!priv->base) + return -ENOENT; + + return 0; +} + +static const struct dm_serial_ops ca_serial_ops = { + .putc = ca_serial_putc, + .pending = ca_serial_pending, + .getc = ca_serial_getc, + .setbrg = ca_serial_setbrg, +}; + +static const struct udevice_id ca_serial_ids[] = { + {.compatible = "cortina,ca-uart"}, + {} +}; + +U_BOOT_DRIVER(serial_cortina) = { + .name = "serial_cortina", + .id = UCLASS_SERIAL, + .of_match = ca_serial_ids, + .of_to_plat = ca_serial_of_to_plat, + .priv_auto = sizeof(struct ca_uart_priv), + .probe = ca_serial_probe, + .ops = &ca_serial_ops +}; diff --git a/roms/u-boot/drivers/serial/serial_efi.c b/roms/u-boot/drivers/serial/serial_efi.c new file mode 100644 index 000000000..33ddbd608 --- /dev/null +++ b/roms/u-boot/drivers/serial/serial_efi.c @@ -0,0 +1,156 @@ +// 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 <log.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 = sizeof(struct serial_efi_priv), + .probe = serial_efi_probe, + .ops = &serial_efi_ops, +}; diff --git a/roms/u-boot/drivers/serial/serial_intel_mid.c b/roms/u-boot/drivers/serial/serial_intel_mid.c new file mode 100644 index 000000000..bbf19057c --- /dev/null +++ b/roms/u-boot/drivers/serial/serial_intel_mid.c @@ -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_plat *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_plat *plat = dev_get_plat(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, + .of_to_plat = ns16550_serial_of_to_plat, + .plat_auto = sizeof(struct ns16550_plat), + .priv_auto = sizeof(struct ns16550), + .probe = mid_serial_probe, + .ops = &ns16550_serial_ops, +}; diff --git a/roms/u-boot/drivers/serial/serial_linflexuart.c b/roms/u-boot/drivers/serial/serial_linflexuart.c new file mode 100644 index 000000000..876a4baa9 --- /dev/null +++ b/roms/u-boot/drivers/serial/serial_linflexuart.c @@ -0,0 +1,219 @@ +// 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/global_data.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_plat { + 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_plat *plat = dev_get_plat(dev); + 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 = 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 */ diff --git a/roms/u-boot/drivers/serial/serial_lpuart.c b/roms/u-boot/drivers/serial/serial_lpuart.c new file mode 100644 index 000000000..2b473d70f --- /dev/null +++ b/roms/u-boot/drivers/serial/serial_lpuart.c @@ -0,0 +1,574 @@ +// 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 <log.h> +#include <watchdog.h> +#include <asm/global_data.h> +#include <asm/io.h> +#include <serial.h> +#include <dm/device_compat.h> +#include <linux/bitops.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 +#if defined(CONFIG_ARCH_IMX8) || defined(CONFIG_ARCH_IMXRT) +#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, + DEV_IMXRT, +}; + +struct lpuart_serial_plat { + 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_plat *plat = dev_get_plat(dev); + + return plat->flags & LPUART_FLAG_REGMAP_32BIT_REG; +} + +static void _lpuart_serial_setbrg(struct udevice *dev, + int baudrate) +{ + struct lpuart_serial_plat *plat = dev_get_plat(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_plat *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_plat *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_plat *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_plat *plat = dev_get_plat(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_plat *plat = dev_get_plat(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_plat *plat = dev_get_plat(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_plat *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_plat *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_plat *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_plat *plat = dev_get_plat(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 || + plat->devtype == DEV_IMXRT) { + _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_plat *plat = dev_get_plat(dev); + + if (is_lpuart32(dev)) { + if (plat->devtype == DEV_MX7ULP || plat->devtype == DEV_IMX8 || + plat->devtype == DEV_IMXRT) + _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_plat *plat = dev_get_plat(dev); + + 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_plat *plat = dev_get_plat(dev); + + 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_plat *plat = dev_get_plat(dev); + 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 CONFIG_IS_ENABLED(CLK) + struct clk per_clk; + int ret; + + ret = clk_get_by_name(dev, "per", &per_clk); + if (!ret) { + ret = clk_enable(&per_clk); + if (ret) { + dev_err(dev, "Failed to get per clk: %d\n", ret); + return ret; + } + } else { + debug("%s: Failed to get per clk: %d\n", __func__, ret); + } +#endif + + if (is_lpuart32(dev)) + return _lpuart32_serial_init(dev); + else + return _lpuart_serial_init(dev); +} + +static int lpuart_serial_of_to_plat(struct udevice *dev) +{ + struct lpuart_serial_plat *plat = dev_get_plat(dev); + const void *blob = gd->fdt_blob; + int node = dev_of_offset(dev); + fdt_addr_t addr; + + addr = dev_read_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; + else if (!fdt_node_check_compatible(blob, node, "fsl,imxrt-lpuart")) + plat->devtype = DEV_IMXRT; + + 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 }, + { .compatible = "fsl,imxrt-lpuart", + .data = LPUART_FLAG_REGMAP_32BIT_REG }, + { } +}; + +U_BOOT_DRIVER(serial_lpuart) = { + .name = "serial_lpuart", + .id = UCLASS_SERIAL, + .of_match = lpuart_serial_ids, + .of_to_plat = lpuart_serial_of_to_plat, + .plat_auto = sizeof(struct lpuart_serial_plat), + .probe = lpuart_serial_probe, + .ops = &lpuart_serial_ops, +}; diff --git a/roms/u-boot/drivers/serial/serial_mcf.c b/roms/u-boot/drivers/serial/serial_mcf.c new file mode 100644 index 000000000..bb2afd0d8 --- /dev/null +++ b/roms/u-boot/drivers/serial/serial_mcf.c @@ -0,0 +1,180 @@ +// 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 <asm/global_data.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_plat *plat = dev_get_plat(dev); + + plat->port = dev_seq(dev); + + 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_plat *plat = dev_get_plat(dev); + 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_plat *plat = dev_get_plat(dev); + 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_plat *plat = dev_get_plat(dev); + 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_plat *plat = dev_get_plat(dev); + 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_of_to_plat(struct udevice *dev) +{ + struct coldfire_serial_plat *plat = dev_get_plat(dev); + fdt_addr_t addr_base; + + addr_base = dev_read_addr(dev); + if (addr_base == FDT_ADDR_T_NONE) + return -ENODEV; + + plat->base = (uint32_t)addr_base; + 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, + .of_to_plat = coldfire_of_to_plat, + .plat_auto = sizeof(struct coldfire_serial_plat), + .probe = coldfire_serial_probe, + .ops = &coldfire_serial_ops, + .flags = DM_FLAG_PRE_RELOC, +}; diff --git a/roms/u-boot/drivers/serial/serial_meson.c b/roms/u-boot/drivers/serial/serial_meson.c new file mode 100644 index 000000000..d69ec221e --- /dev/null +++ b/roms/u-boot/drivers/serial/serial_meson.c @@ -0,0 +1,195 @@ +// 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/bitops.h> +#include <linux/compiler.h> +#include <serial.h> + +struct meson_uart { + u32 wfifo; + u32 rfifo; + u32 control; + u32 status; + u32 misc; +}; + +struct meson_serial_plat { + 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_plat *plat = dev_get_plat(dev); + struct meson_uart *const uart = plat->reg; + + meson_serial_init(uart); + + return 0; +} + +static void meson_serial_rx_error(struct udevice *dev) +{ + struct meson_serial_plat *plat = dev_get_plat(dev); + struct meson_uart *const uart = plat->reg; + u32 val = readl(&uart->control); + + /* Clear error */ + val |= AML_UART_CLR_ERR; + writel(val, &uart->control); + val &= ~AML_UART_CLR_ERR; + writel(val, &uart->control); + + /* Remove spurious byte from fifo */ + readl(&uart->rfifo); +} + +static int meson_serial_getc(struct udevice *dev) +{ + struct meson_serial_plat *plat = dev_get_plat(dev); + struct meson_uart *const uart = plat->reg; + uint32_t status = readl(&uart->status); + + if (status & AML_UART_RX_EMPTY) + return -EAGAIN; + + if (status & AML_UART_ERR) { + meson_serial_rx_error(dev); + return -EIO; + } + + return readl(&uart->rfifo) & 0xff; +} + +static int meson_serial_putc(struct udevice *dev, const char ch) +{ + struct meson_serial_plat *plat = dev_get_plat(dev); + 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_plat *plat = dev_get_plat(dev); + struct meson_uart *const uart = plat->reg; + uint32_t status = readl(&uart->status); + + if (input) { + if (status & AML_UART_RX_EMPTY) + return false; + + /* + * Handle and drop any RX error here to avoid + * returning true here when an error byte is in the FIFO + */ + if (status & AML_UART_ERR) { + meson_serial_rx_error(dev); + return false; + } + + return true; + } else { + return !(status & AML_UART_TX_FULL); + } +} + +static int meson_serial_of_to_plat(struct udevice *dev) +{ + struct meson_serial_plat *plat = dev_get_plat(dev); + fdt_addr_t addr; + + addr = dev_read_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, + .of_to_plat = meson_serial_of_to_plat, + .plat_auto = sizeof(struct meson_serial_plat), +}; + +#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 diff --git a/roms/u-boot/drivers/serial/serial_mpc8xx.c b/roms/u-boot/drivers/serial/serial_mpc8xx.c new file mode 100644 index 000000000..0978930dc --- /dev/null +++ b/roms/u-boot/drivers/serial/serial_mpc8xx.c @@ -0,0 +1,258 @@ +// 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 <asm/global_data.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, +}; diff --git a/roms/u-boot/drivers/serial/serial_msm.c b/roms/u-boot/drivers/serial/serial_msm.c new file mode 100644 index 000000000..d8c6c2f6b --- /dev/null +++ b/roms/u-boot/drivers/serial/serial_msm.c @@ -0,0 +1,247 @@ +// 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 <malloc.h> +#include <serial.h> +#include <watchdog.h> +#include <asm/global_data.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 */ + uint32_t clk_bit_rate; /* data mover mode bit rate register value */ +}; + +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(priv->clk_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_of_to_plat(struct udevice *dev) +{ + struct msm_serial_data *priv = dev_get_priv(dev); + + priv->base = dev_read_addr(dev); + if (priv->base == FDT_ADDR_T_NONE) + return -EINVAL; + + priv->clk_bit_rate = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev), + "bit-rate", UART_DM_CLK_RX_TX_BIT_RATE); + + 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, + .of_to_plat = msm_serial_of_to_plat, + .priv_auto = sizeof(struct msm_serial_data), + .probe = msm_serial_probe, + .ops = &msm_serial_ops, +}; diff --git a/roms/u-boot/drivers/serial/serial_mt7620.c b/roms/u-boot/drivers/serial/serial_mt7620.c new file mode 100644 index 000000000..826a14b49 --- /dev/null +++ b/roms/u-boot/drivers/serial/serial_mt7620.c @@ -0,0 +1,246 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * UART driver for MediaTek MT7620 and earlier SoCs + * + * Copyright (C) 2020 MediaTek Inc. + * Author: Weijie Gao <weijie.gao@mediatek.com> + */ + +#include <clk.h> +#include <div64.h> +#include <dm.h> +#include <errno.h> +#include <log.h> +#include <reset.h> +#include <serial.h> +#include <watchdog.h> +#include <asm/io.h> +#include <asm/types.h> +#include <asm/addrspace.h> +#include <dm/device_compat.h> +#include <linux/err.h> + +#if CONFIG_IS_ENABLED(OF_PLATDATA) +#include <dt-structs.h> +#endif + +struct mt7620_serial_regs { + u32 rbr; + u32 thr; + u32 ier; + u32 iir; + u32 fcr; + u32 lcr; + u32 mcr; + u32 lsr; + u32 msr; + u32 scratch; + u32 dl; + u32 dll; + u32 dlm; + u32 ifctl; +}; + +#define UART_LCR_WLS_8 0x03 /* 8 bit character length */ + +#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) + +struct mt7620_serial_plat { +#if CONFIG_IS_ENABLED(OF_PLATDATA) + struct dtd_serial_mt7620 dtplat; +#endif + + struct mt7620_serial_regs __iomem *regs; + u32 clock; +}; + +static void _mt7620_serial_setbrg(struct mt7620_serial_plat *plat, int baud) +{ + u32 quot; + + /* set divisor */ + quot = DIV_ROUND_CLOSEST(plat->clock, 16 * baud); + writel(quot, &plat->regs->dl); + + /* set character length and stop bits */ + writel(UART_LCR_WLS_8, &plat->regs->lcr); +} + +static int mt7620_serial_setbrg(struct udevice *dev, int baudrate) +{ + struct mt7620_serial_plat *plat = dev_get_plat(dev); + + _mt7620_serial_setbrg(plat, baudrate); + + return 0; +} + +static int mt7620_serial_putc(struct udevice *dev, const char ch) +{ + struct mt7620_serial_plat *plat = dev_get_plat(dev); + + if (!(readl(&plat->regs->lsr) & UART_LSR_THRE)) + return -EAGAIN; + + writel(ch, &plat->regs->thr); + + if (ch == '\n') + WATCHDOG_RESET(); + + return 0; +} + +static int mt7620_serial_getc(struct udevice *dev) +{ + struct mt7620_serial_plat *plat = dev_get_plat(dev); + + if (!(readl(&plat->regs->lsr) & UART_LSR_DR)) + return -EAGAIN; + + return readl(&plat->regs->rbr); +} + +static int mt7620_serial_pending(struct udevice *dev, bool input) +{ + struct mt7620_serial_plat *plat = dev_get_plat(dev); + + if (input) + return (readl(&plat->regs->lsr) & UART_LSR_DR) ? 1 : 0; + + return (readl(&plat->regs->lsr) & UART_LSR_THRE) ? 0 : 1; +} + +static int mt7620_serial_probe(struct udevice *dev) +{ + struct mt7620_serial_plat *plat = dev_get_plat(dev); + +#if CONFIG_IS_ENABLED(OF_PLATDATA) + plat->regs = (void __iomem *)KSEG1ADDR(plat->dtplat.reg[0]); + plat->clock = plat->dtplat.clock_frequency; +#endif + + /* Disable interrupt */ + writel(0, &plat->regs->ier); + + writel(UART_MCRVAL, &plat->regs->mcr); + writel(UART_FCRVAL, &plat->regs->fcr); + + return 0; +} + +#if !CONFIG_IS_ENABLED(OF_PLATDATA) +static int mt7620_serial_of_to_plat(struct udevice *dev) +{ + struct mt7620_serial_plat *plat = dev_get_plat(dev); + struct reset_ctl reset_uart; + struct clk clk; + int err; + + err = reset_get_by_index(dev, 0, &reset_uart); + if (!err) + reset_deassert(&reset_uart); + + plat->regs = dev_remap_addr_index(dev, 0); + if (!plat->regs) { + dev_err(dev, "mt7620_serial: unable to map UART registers\n"); + return -EINVAL; + } + + 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) { + dev_err(dev, "mt7620_serial: failed to get clock\n"); + return err; + } + + if (!plat->clock) + plat->clock = dev_read_u32_default(dev, "clock-frequency", 0); + + if (!plat->clock) { + dev_err(dev, "mt7620_serial: clock not defined\n"); + return -EINVAL; + } + + return 0; +} + +static const struct udevice_id mt7620_serial_ids[] = { + { .compatible = "mediatek,mt7620-uart" }, + { } +}; +#endif + +static const struct dm_serial_ops mt7620_serial_ops = { + .putc = mt7620_serial_putc, + .pending = mt7620_serial_pending, + .getc = mt7620_serial_getc, + .setbrg = mt7620_serial_setbrg, +}; + +U_BOOT_DRIVER(serial_mt7620) = { + .name = "serial_mt7620", + .id = UCLASS_SERIAL, +#if !CONFIG_IS_ENABLED(OF_PLATDATA) + .of_match = mt7620_serial_ids, + .of_to_plat = mt7620_serial_of_to_plat, +#endif + .plat_auto = sizeof(struct mt7620_serial_plat), + .probe = mt7620_serial_probe, + .ops = &mt7620_serial_ops, + .flags = DM_FLAG_PRE_RELOC, +}; + +DM_DRIVER_ALIAS(serial_mt7620, mediatek_mt7620_uart); + +#ifdef CONFIG_DEBUG_UART_MT7620 + +#include <debug_uart.h> + +static inline void _debug_uart_init(void) +{ + struct mt7620_serial_plat plat; + + plat.regs = (void *)CONFIG_DEBUG_UART_BASE; + plat.clock = CONFIG_DEBUG_UART_CLOCK; + + writel(0, &plat.regs->ier); + writel(UART_MCRVAL, &plat.regs->mcr); + writel(UART_FCRVAL, &plat.regs->fcr); + + _mt7620_serial_setbrg(&plat, CONFIG_BAUDRATE); +} + +static inline void _debug_uart_putc(int ch) +{ + struct mt7620_serial_regs __iomem *regs = + (void *)CONFIG_DEBUG_UART_BASE; + + while (!(readl(®s->lsr) & UART_LSR_THRE)) + ; + + writel(ch, ®s->thr); +} + +DEBUG_UART_FUNCS + +#endif diff --git a/roms/u-boot/drivers/serial/serial_mtk.c b/roms/u-boot/drivers/serial/serial_mtk.c new file mode 100644 index 000000000..4145d9fdb --- /dev/null +++ b/roms/u-boot/drivers/serial/serial_mtk.c @@ -0,0 +1,452 @@ +// 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 <log.h> +#include <serial.h> +#include <watchdog.h> +#include <asm/global_data.h> +#include <asm/io.h> +#include <asm/types.h> +#include <linux/err.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; + bool force_highspeed; +}; + +static void _mtk_serial_setbrg(struct mtk_serial_priv *priv, int baud) +{ + u32 quot, realbaud, samplecount = 1; + + /* Special case for low baud clock */ + if (baud <= 115200 && priv->clock <= 12000000) { + 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); + + 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); + } + + goto set_baud; + } + + if (priv->force_highspeed) + goto use_hs3; + + if (baud <= 115200) { + writel(0, &priv->regs->highspeed); + quot = DIV_ROUND_CLOSEST(priv->clock, 16 * baud); + } 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 { +use_hs3: + writel(3, &priv->regs->highspeed); + + quot = DIV_ROUND_UP(priv->clock, 256 * baud); + samplecount = DIV_ROUND_CLOSEST(priv->clock, quot * baud); + } + +set_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); + + /* set highspeed mode sample count & point */ + 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_of_to_plat(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; + } + + priv->force_highspeed = dev_read_bool(dev, "mediatek,force-highspeed"); + + 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, + .of_to_plat = mtk_serial_of_to_plat, + .priv_auto = 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 diff --git a/roms/u-boot/drivers/serial/serial_mvebu_a3700.c b/roms/u-boot/drivers/serial/serial_mvebu_a3700.c new file mode 100644 index 000000000..8f404879a --- /dev/null +++ b/roms/u-boot/drivers/serial/serial_mvebu_a3700.c @@ -0,0 +1,179 @@ +// 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_plat { + 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_TX_EMPTY 0x40 +#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_plat *plat = dev_get_plat(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_plat *plat = dev_get_plat(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_plat *plat = dev_get_plat(dev); + void __iomem *base = plat->base; + + if (input) { + if (readl(base + UART_STATUS_REG) & UART_STATUS_RX_RDY) + return 1; + } else { + if (!(readl(base + UART_STATUS_REG) & UART_STATUS_TX_EMPTY)) + return 1; + } + + return 0; +} + +static int mvebu_serial_setbrg(struct udevice *dev, int baudrate) +{ + struct mvebu_plat *plat = dev_get_plat(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_plat *plat = dev_get_plat(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_of_to_plat(struct udevice *dev) +{ + struct mvebu_plat *plat = dev_get_plat(dev); + + plat->base = dev_read_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, + .of_to_plat = mvebu_serial_of_to_plat, + .plat_auto = sizeof(struct mvebu_plat), + .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 diff --git a/roms/u-boot/drivers/serial/serial_mxc.c b/roms/u-boot/drivers/serial/serial_mxc.c new file mode 100644 index 000000000..e4970a169 --- /dev/null +++ b/roms/u-boot/drivers/serial/serial_mxc.c @@ -0,0 +1,394 @@ +// 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 <asm/global_data.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_plat *plat = dev_get_plat(dev); + 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_plat *plat = dev_get_plat(dev); + + _mxc_serial_init(plat->reg, plat->use_dte); + + return 0; +} + +static int mxc_serial_getc(struct udevice *dev) +{ + struct mxc_serial_plat *plat = dev_get_plat(dev); + 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_plat *plat = dev_get_plat(dev); + 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_plat *plat = dev_get_plat(dev); + 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_of_to_plat(struct udevice *dev) +{ + struct mxc_serial_plat *plat = dev_get_plat(dev); + fdt_addr_t addr; + + addr = dev_read_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, + .of_to_plat = mxc_serial_of_to_plat, + .plat_auto = sizeof(struct mxc_serial_plat), +#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 diff --git a/roms/u-boot/drivers/serial/serial_ns16550.c b/roms/u-boot/drivers/serial/serial_ns16550.c new file mode 100644 index 000000000..97b6a4ff4 --- /dev/null +++ b/roms/u-boot/drivers/serial/serial_ns16550.c @@ -0,0 +1,254 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (C) Copyright 2000 + * Rob Taylor, Flying Pig Systems. robt@flyingpig.com. + */ + +#include <common.h> +#include <clock_legacy.h> +#include <ns16550.h> +#include <serial.h> +#include <asm/global_data.h> +#include <linux/compiler.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 struct ns16550 *serial_ports[6] = { +#ifdef CONFIG_SYS_NS16550_COM1 + (struct ns16550 *)CONFIG_SYS_NS16550_COM1, +#else + NULL, +#endif +#ifdef CONFIG_SYS_NS16550_COM2 + (struct ns16550 *)CONFIG_SYS_NS16550_COM2, +#else + NULL, +#endif +#ifdef CONFIG_SYS_NS16550_COM3 + (struct ns16550 *)CONFIG_SYS_NS16550_COM3, +#else + NULL, +#endif +#ifdef CONFIG_SYS_NS16550_COM4 + (struct ns16550 *)CONFIG_SYS_NS16550_COM4, +#else + NULL, +#endif +#ifdef CONFIG_SYS_NS16550_COM5 + (struct ns16550 *)CONFIG_SYS_NS16550_COM5, +#else + NULL, +#endif +#ifdef CONFIG_SYS_NS16550_COM6 + (struct ns16550 *)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 */ diff --git a/roms/u-boot/drivers/serial/serial_nulldev.c b/roms/u-boot/drivers/serial/serial_nulldev.c new file mode 100644 index 000000000..efae14dd6 --- /dev/null +++ b/roms/u-boot/drivers/serial/serial_nulldev.c @@ -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, +}; diff --git a/roms/u-boot/drivers/serial/serial_octeon_bootcmd.c b/roms/u-boot/drivers/serial/serial_octeon_bootcmd.c new file mode 100644 index 000000000..4bcff77eb --- /dev/null +++ b/roms/u-boot/drivers/serial/serial_octeon_bootcmd.c @@ -0,0 +1,182 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2019 Marvell International Ltd. + * Copyright (C) 2021 Stefan Roese <sr@denx.de> + */ + +#include <dm.h> +#include <dm/uclass.h> +#include <errno.h> +#include <input.h> +#include <iomux.h> +#include <log.h> +#include <serial.h> +#include <stdio_dev.h> +#include <string.h> +#include <watchdog.h> +#include <linux/delay.h> +#include <asm/addrspace.h> +#include <asm/io.h> +#include <mach/cvmx-regs.h> +#include <mach/cvmx-bootmem.h> + +#define DRIVER_NAME "pci-bootcmd" + +/* + * Important: + * This address cannot be changed as the PCI console tool relies on exactly + * this value! + */ +#define BOOTLOADER_PCI_READ_BUFFER_BASE 0x6c000 +#define BOOTLOADER_PCI_READ_BUFFER_SIZE 256 +#define BOOTLOADER_PCI_WRITE_BUFFER_SIZE 256 + +#define BOOTLOADER_PCI_READ_BUFFER_STR_LEN \ + (BOOTLOADER_PCI_READ_BUFFER_SIZE - 8) +#define BOOTLOADER_PCI_WRITE_BUFFER_STR_LEN \ + (BOOTLOADER_PCI_WRITE_BUFFER_SIZE - 8) + +#define BOOTLOADER_PCI_READ_BUFFER_OWNER_ADDR \ + (BOOTLOADER_PCI_READ_BUFFER_BASE + 0) +#define BOOTLOADER_PCI_READ_BUFFER_LEN_ADDR \ + (BOOTLOADER_PCI_READ_BUFFER_BASE + 4) +#define BOOTLOADER_PCI_READ_BUFFER_DATA_ADDR \ + (BOOTLOADER_PCI_READ_BUFFER_BASE + 8) + +enum octeon_pci_io_buf_owner { + /* Must be zero, set when memory cleared */ + OCTEON_PCI_IO_BUF_OWNER_INVALID = 0, + OCTEON_PCI_IO_BUF_OWNER_OCTEON = 1, + OCTEON_PCI_IO_BUF_OWNER_HOST = 2, +}; + +/* Structure for bootloader PCI IO buffers */ +struct octeon_pci_io_buf { + u32 owner; + u32 len; + char data[0]; +}; + +struct octeon_bootcmd_priv { + bool started; + int copy_offset; + bool eol; + bool unlocked; + struct octeon_pci_io_buf *buf; +}; + +static int octeon_bootcmd_pending(struct udevice *dev, bool input) +{ + struct octeon_bootcmd_priv *priv = dev_get_priv(dev); + + if (!input) + return 0; + + if (priv->eol) + return 1; + + CVMX_SYNC; + if (priv->buf->owner != OCTEON_PCI_IO_BUF_OWNER_OCTEON) + return 0; + + if (priv->buf->len > priv->copy_offset && + (priv->buf->data[priv->copy_offset] != '\0')) + return 1; + + return 0; +} + +static int octeon_bootcmd_getc(struct udevice *dev) +{ + struct octeon_bootcmd_priv *priv = dev_get_priv(dev); + char c; + + /* There's no EOL for boot commands so we fake it. */ + if (priv->eol) { + priv->eol = false; + return '\n'; + } + + while (!octeon_bootcmd_pending(dev, true)) { + WATCHDOG_RESET(); + /* + * ToDo: + * The original code calls octeon_board_poll() here. We may + * need to implement something similar here. + */ + udelay(100); + } + + c = priv->buf->data[priv->copy_offset]; + priv->buf->data[priv->copy_offset++] = '\0'; + + if (priv->copy_offset >= min_t(int, CONFIG_SYS_CBSIZE - 1, + BOOTLOADER_PCI_READ_BUFFER_STR_LEN - 1) || + (priv->buf->data[priv->copy_offset] == '\0')) { + priv->copy_offset = 0; + priv->buf->len = 0; + priv->buf->owner = OCTEON_PCI_IO_BUF_OWNER_HOST; + priv->eol = true; + CVMX_SYNC; + } + + return c; +} + +static const struct dm_serial_ops octeon_bootcmd_ops = { + .getc = octeon_bootcmd_getc, + .pending = octeon_bootcmd_pending, +}; + +static int octeon_bootcmd_probe(struct udevice *dev) +{ + struct octeon_bootcmd_priv *priv = dev_get_priv(dev); + + priv->buf = (void *)CKSEG0ADDR(BOOTLOADER_PCI_READ_BUFFER_BASE); + memset(priv->buf, 0, BOOTLOADER_PCI_READ_BUFFER_SIZE); + priv->eol = false; + + /* + * When the bootcmd console is first started it is started as locked to + * block any calls sending a command until U-Boot is ready to accept + * commands. Just before the main loop starts to accept commands the + * bootcmd console is unlocked. + */ + if (priv->unlocked) + priv->buf->owner = OCTEON_PCI_IO_BUF_OWNER_HOST; + else + priv->buf->owner = OCTEON_PCI_IO_BUF_OWNER_OCTEON; + + debug("%s called, buffer ptr: 0x%p, owner: %s\n", __func__, + priv->buf, + priv->buf->owner == OCTEON_PCI_IO_BUF_OWNER_HOST ? + "host" : "octeon"); + debug("&priv->copy_offset: 0x%p\n", &priv->copy_offset); + CVMX_SYNC; + + /* + * Perhaps reinvestige this: In the original code, "unlocked" etc + * is set in the octeon_pci_bootcmd_unlock() function called very + * late. + */ + priv->buf->owner = OCTEON_PCI_IO_BUF_OWNER_HOST; + priv->unlocked = true; + priv->started = true; + CVMX_SYNC; + + return 0; +} + +static const struct udevice_id octeon_bootcmd_serial_id[] = { + { .compatible = "marvell,pci-bootcmd", }, + { }, +}; + +U_BOOT_DRIVER(octeon_bootcmd) = { + .name = DRIVER_NAME, + .id = UCLASS_SERIAL, + .ops = &octeon_bootcmd_ops, + .of_match = of_match_ptr(octeon_bootcmd_serial_id), + .probe = octeon_bootcmd_probe, + .priv_auto = sizeof(struct octeon_bootcmd_priv), +}; diff --git a/roms/u-boot/drivers/serial/serial_octeon_pcie_console.c b/roms/u-boot/drivers/serial/serial_octeon_pcie_console.c new file mode 100644 index 000000000..c76e787d0 --- /dev/null +++ b/roms/u-boot/drivers/serial/serial_octeon_pcie_console.c @@ -0,0 +1,365 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2019 Marvell International Ltd. + * Copyright (C) 2021 Stefan Roese <sr@denx.de> + */ + +#include <dm.h> +#include <dm/uclass.h> +#include <errno.h> +#include <input.h> +#include <iomux.h> +#include <log.h> +#include <serial.h> +#include <stdio_dev.h> +#include <string.h> +#include <watchdog.h> +#include <linux/delay.h> +#include <asm/io.h> +#include <mach/cvmx-regs.h> +#include <mach/cvmx-bootmem.h> + +#define DRIVER_NAME "pci-console" +#define OCTEONTX_PCIE_CONSOLE_NAME_LEN 16 + +/* Current versions */ +#define OCTEON_PCIE_CONSOLE_MAJOR_VERSION 1 +#define OCTEON_PCIE_CONSOLE_MINOR_VERSION 0 + +#define OCTEON_PCIE_CONSOLE_BLOCK_NAME "__pci_console" + +/* + * Structure that defines a single console. + * Note: when read_index == write_index, the buffer is empty. + * The actual usable size of each console is console_buf_size -1; + */ +struct octeon_pcie_console { + u64 input_base_addr; + u32 input_read_index; + u32 input_write_index; + u64 output_base_addr; + u32 output_read_index; + u32 output_write_index; + u32 lock; + u32 buf_size; +}; + +/* + * This is the main container structure that contains all the information + * about all PCI consoles. The address of this structure is passed to various + * routines that operation on PCI consoles. + */ +struct octeon_pcie_console_desc { + u32 major_version; + u32 minor_version; + u32 lock; + u32 flags; + u32 num_consoles; + u32 pad; + /* must be 64 bit aligned here... */ + /* Array of addresses of octeon_pcie_console_t structures */ + u64 console_addr_array[0]; + /* Implicit storage for console_addr_array */ +}; + +struct octeon_pcie_console_priv { + struct octeon_pcie_console *console; + int console_num; + bool console_active; +}; + +/* Flag definitions for read/write functions */ +enum { + /* + * If set, read/write functions won't block waiting for space or data. + * For reads, 0 bytes may be read, and for writes not all of the + * supplied data may be written. + */ + OCT_PCI_CON_FLAG_NONBLOCK = 1 << 0, +}; + +static int buffer_free_bytes(u32 buffer_size, u32 wr_idx, u32 rd_idx) +{ + if (rd_idx >= buffer_size || wr_idx >= buffer_size) + return -1; + + return ((buffer_size - 1) - (wr_idx - rd_idx)) % buffer_size; +} + +static int buffer_avail_bytes(u32 buffer_size, u32 wr_idx, u32 rd_idx) +{ + if (rd_idx >= buffer_size || wr_idx >= buffer_size) + return -1; + + return buffer_size - 1 - buffer_free_bytes(buffer_size, wr_idx, rd_idx); +} + +static int buffer_read_avail(struct udevice *dev, unsigned int console_num) +{ + struct octeon_pcie_console_priv *priv = dev_get_priv(dev); + struct octeon_pcie_console *cons_ptr = priv->console; + int avail; + + avail = buffer_avail_bytes(cons_ptr->buf_size, + cons_ptr->input_write_index, + cons_ptr->input_read_index); + if (avail >= 0) + return avail; + + return 0; +} + +static int octeon_pcie_console_read(struct udevice *dev, + unsigned int console_num, char *buffer, + int buffer_size, u32 flags) +{ + struct octeon_pcie_console_priv *priv = dev_get_priv(dev); + struct octeon_pcie_console *cons_ptr = priv->console; + int avail; + char *buf_ptr; + int bytes_read; + int read_size; + + buf_ptr = (char *)cvmx_phys_to_ptr(cons_ptr->input_base_addr); + + avail = buffer_avail_bytes(cons_ptr->buf_size, + cons_ptr->input_write_index, + cons_ptr->input_read_index); + if (avail < 0) + return avail; + + if (!(flags & OCT_PCI_CON_FLAG_NONBLOCK)) { + /* Wait for some data to be available */ + while (0 == (avail = buffer_avail_bytes(cons_ptr->buf_size, + cons_ptr->input_write_index, + cons_ptr->input_read_index))) { + mdelay(10); + WATCHDOG_RESET(); + } + } + + bytes_read = 0; + + /* Don't overflow the buffer passed to us */ + read_size = min_t(int, avail, buffer_size); + + /* Limit ourselves to what we can input in a contiguous block */ + if (cons_ptr->input_read_index + read_size >= cons_ptr->buf_size) + read_size = cons_ptr->buf_size - cons_ptr->input_read_index; + + memcpy(buffer, buf_ptr + cons_ptr->input_read_index, read_size); + cons_ptr->input_read_index = + (cons_ptr->input_read_index + read_size) % cons_ptr->buf_size; + bytes_read += read_size; + + /* Mark the PCIe console to be active from now on */ + if (bytes_read) + priv->console_active = true; + + return bytes_read; +} + +static int octeon_pcie_console_write(struct udevice *dev, + unsigned int console_num, + const char *buffer, + int bytes_to_write, u32 flags) +{ + struct octeon_pcie_console_priv *priv = dev_get_priv(dev); + struct octeon_pcie_console *cons_ptr = priv->console; + int avail; + char *buf_ptr; + int bytes_written; + + buf_ptr = (char *)cvmx_phys_to_ptr(cons_ptr->output_base_addr); + bytes_written = 0; + while (bytes_to_write > 0) { + avail = buffer_free_bytes(cons_ptr->buf_size, + cons_ptr->output_write_index, + cons_ptr->output_read_index); + + if (avail > 0) { + int write_size = min_t(int, avail, bytes_to_write); + + /* + * Limit ourselves to what we can output in a contiguous + * block + */ + if (cons_ptr->output_write_index + write_size >= + cons_ptr->buf_size) { + write_size = cons_ptr->buf_size - + cons_ptr->output_write_index; + } + + memcpy(buf_ptr + cons_ptr->output_write_index, + buffer + bytes_written, write_size); + /* + * Make sure data is visible before changing write + * index + */ + CVMX_SYNCW; + cons_ptr->output_write_index = + (cons_ptr->output_write_index + write_size) % + cons_ptr->buf_size; + bytes_to_write -= write_size; + bytes_written += write_size; + } else if (avail == 0) { + /* + * Check to see if we should wait for room, or return + * after a partial write + */ + if (flags & OCT_PCI_CON_FLAG_NONBLOCK) + goto done; + + WATCHDOG_RESET(); + mdelay(10); /* Delay if we are spinning */ + } else { + bytes_written = -1; + goto done; + } + } + +done: + return bytes_written; +} + +static struct octeon_pcie_console_desc *octeon_pcie_console_init(int num_consoles, + int buffer_size) +{ + struct octeon_pcie_console_desc *cons_desc_ptr; + struct octeon_pcie_console *cons_ptr; + s64 addr; + u64 avail_addr; + int alloc_size; + int i; + + /* Compute size required for pci console structure */ + alloc_size = num_consoles * + (buffer_size * 2 + sizeof(struct octeon_pcie_console) + + sizeof(u64)) + sizeof(struct octeon_pcie_console_desc); + + /* + * Allocate memory for the consoles. This must be in the range + * addresssible by the bootloader. + * Try to do so in a manner which minimizes fragmentation. We try to + * put it at the top of DDR0 or bottom of DDR2 first, and only do + * generic allocation if those fail + */ + addr = cvmx_bootmem_phy_named_block_alloc(alloc_size, + OCTEON_DDR0_SIZE - alloc_size - 128, + OCTEON_DDR0_SIZE, 128, + OCTEON_PCIE_CONSOLE_BLOCK_NAME, + CVMX_BOOTMEM_FLAG_END_ALLOC); + if (addr < 0) { + addr = cvmx_bootmem_phy_named_block_alloc(alloc_size, 0, + 0x1fffffff, 128, + OCTEON_PCIE_CONSOLE_BLOCK_NAME, + CVMX_BOOTMEM_FLAG_END_ALLOC); + } + if (addr < 0) + return 0; + + cons_desc_ptr = cvmx_phys_to_ptr(addr); + + /* Clear entire alloc'ed memory */ + memset(cons_desc_ptr, 0, alloc_size); + + /* Initialize as locked until we are done */ + cons_desc_ptr->lock = 1; + CVMX_SYNCW; + cons_desc_ptr->num_consoles = num_consoles; + cons_desc_ptr->flags = 0; + cons_desc_ptr->major_version = OCTEON_PCIE_CONSOLE_MAJOR_VERSION; + cons_desc_ptr->minor_version = OCTEON_PCIE_CONSOLE_MINOR_VERSION; + + avail_addr = addr + sizeof(struct octeon_pcie_console_desc) + + num_consoles * sizeof(u64); + + for (i = 0; i < num_consoles; i++) { + cons_desc_ptr->console_addr_array[i] = avail_addr; + cons_ptr = (void *)cons_desc_ptr->console_addr_array[i]; + avail_addr += sizeof(struct octeon_pcie_console); + cons_ptr->input_base_addr = avail_addr; + avail_addr += buffer_size; + cons_ptr->output_base_addr = avail_addr; + avail_addr += buffer_size; + cons_ptr->buf_size = buffer_size; + } + CVMX_SYNCW; + cons_desc_ptr->lock = 0; + + return cvmx_phys_to_ptr(addr); +} + +static int octeon_pcie_console_getc(struct udevice *dev) +{ + char c; + + octeon_pcie_console_read(dev, 0, &c, 1, 0); + return c; +} + +static int octeon_pcie_console_putc(struct udevice *dev, const char c) +{ + struct octeon_pcie_console_priv *priv = dev_get_priv(dev); + + if (priv->console_active) + octeon_pcie_console_write(dev, 0, (char *)&c, 1, 0); + + return 0; +} + +static int octeon_pcie_console_pending(struct udevice *dev, bool input) +{ + if (input) { + udelay(100); + return buffer_read_avail(dev, 0) > 0; + } + + return 0; +} + +static const struct dm_serial_ops octeon_pcie_console_ops = { + .getc = octeon_pcie_console_getc, + .putc = octeon_pcie_console_putc, + .pending = octeon_pcie_console_pending, +}; + +static int octeon_pcie_console_probe(struct udevice *dev) +{ + struct octeon_pcie_console_priv *priv = dev_get_priv(dev); + struct octeon_pcie_console_desc *cons_desc; + int console_count; + int console_size; + int console_num; + + /* + * Currently only 1 console is supported. Perhaps we need to add + * a console nexus if more than one needs to be supported. + */ + console_count = 1; + console_size = 1024; + console_num = 0; + + cons_desc = octeon_pcie_console_init(console_count, console_size); + priv->console = + cvmx_phys_to_ptr(cons_desc->console_addr_array[console_num]); + + debug("PCI console init succeeded, %d consoles, %d bytes each\n", + console_count, console_size); + + return 0; +} + +static const struct udevice_id octeon_pcie_console_serial_id[] = { + { .compatible = "marvell,pci-console", }, + { }, +}; + +U_BOOT_DRIVER(octeon_pcie_console) = { + .name = DRIVER_NAME, + .id = UCLASS_SERIAL, + .ops = &octeon_pcie_console_ops, + .of_match = of_match_ptr(octeon_pcie_console_serial_id), + .probe = octeon_pcie_console_probe, + .priv_auto = sizeof(struct octeon_pcie_console_priv), +}; diff --git a/roms/u-boot/drivers/serial/serial_omap.c b/roms/u-boot/drivers/serial/serial_omap.c new file mode 100644 index 000000000..2b23ece44 --- /dev/null +++ b/roms/u-boot/drivers/serial/serial_omap.c @@ -0,0 +1,171 @@ +// 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 <log.h> +#include <ns16550.h> +#include <serial.h> +#include <clk.h> +#include <linux/err.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_of_to_plat(struct udevice *dev) +{ + struct ns16550_plat *plat = dev_get_plat(dev); + 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, + .of_to_plat = omap_serial_of_to_plat, + .plat_auto = sizeof(struct ns16550_plat), +#endif + .priv_auto = 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 */ diff --git a/roms/u-boot/drivers/serial/serial_owl.c b/roms/u-boot/drivers/serial/serial_owl.c new file mode 100644 index 000000000..3b795785f --- /dev/null +++ b/roms/u-boot/drivers/serial/serial_owl.c @@ -0,0 +1,136 @@ +// 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> +#include <linux/bitops.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_of_to_plat(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,owl-uart" }, + { } +}; + +U_BOOT_DRIVER(serial_owl) = { + .name = "serial_owl", + .id = UCLASS_SERIAL, + .of_match = owl_serial_ids, + .of_to_plat = owl_serial_of_to_plat, + .priv_auto = sizeof(struct owl_serial_priv), + .probe = owl_serial_probe, + .ops = &owl_serial_ops, +}; diff --git a/roms/u-boot/drivers/serial/serial_pic32.c b/roms/u-boot/drivers/serial/serial_pic32.c new file mode 100644 index 000000000..ccdda9f03 --- /dev/null +++ b/roms/u-boot/drivers/serial/serial_pic32.c @@ -0,0 +1,201 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (c) 2015 Paul Thacker <paul.thacker@microchip.com> + * + */ +#include <common.h> +#include <clk.h> +#include <dm.h> +#include <malloc.h> +#include <serial.h> +#include <wait_bit.h> +#include <asm/global_data.h> +#include <linux/bitops.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 = 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 diff --git a/roms/u-boot/drivers/serial/serial_pl01x.c b/roms/u-boot/drivers/serial/serial_pl01x.c new file mode 100644 index 000000000..5283d5ed1 --- /dev/null +++ b/roms/u-boot/drivers/serial/serial_pl01x.c @@ -0,0 +1,427 @@ +// 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 <asm/global_data.h> +/* For get_bus_freq() */ +#include <clock_legacy.h> +#include <dm.h> +#include <clk.h> +#include <errno.h> +#include <watchdog.h> +#include <asm/io.h> +#include <serial.h> +#include <dm/device_compat.h> +#include <dm/platform_data/serial_pl01x.h> +#include <linux/compiler.h> +#include "serial_pl01x_internal.h" + +DECLARE_GLOBAL_DATA_PTR; + +#ifndef CONFIG_DM_SERIAL + +static volatile unsigned char *const port[] = CONFIG_PL01x_PORTS; +static enum pl01x_type pl01x_type __section(".data"); +static struct pl01x_regs *base_regs __section(".data"); +#define NUM_PORTS (sizeof(port)/sizeof(port[0])) + +#endif + +static int pl01x_putc(struct pl01x_regs *regs, char c) +{ + /* 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) +{ + 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; + + /* Without a valid clock rate we cannot set up the baudrate. */ + if (clock) { + /* + * 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 */ + +#ifdef CONFIG_DM_SERIAL + +int pl01x_serial_setbrg(struct udevice *dev, int baudrate) +{ + struct pl01x_serial_plat *plat = dev_get_plat(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_plat *plat = dev_get_plat(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}, + {} +}; + +#ifndef CONFIG_PL011_CLOCK +#define CONFIG_PL011_CLOCK 0 +#endif + +int pl01x_serial_of_to_plat(struct udevice *dev) +{ + struct pl01x_serial_plat *plat = dev_get_plat(dev); + struct clk clk; + fdt_addr_t addr; + int ret; + + addr = dev_read_addr(dev); + if (addr == FDT_ADDR_T_NONE) + return -EINVAL; + + plat->base = addr; + plat->clock = dev_read_u32_default(dev, "clock", CONFIG_PL011_CLOCK); + ret = clk_get_by_index(dev, 0, &clk); + if (!ret) { + ret = clk_enable(&clk); + if (ret && ret != -ENOSYS) { + dev_err(dev, "failed to enable clock\n"); + return ret; + } + + plat->clock = clk_get_rate(&clk); + if (IS_ERR_VALUE(plat->clock)) { + dev_err(dev, "failed to get rate\n"); + return plat->clock; + } + debug("%s: CLK %d\n", __func__, plat->clock); + } + 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), + .of_to_plat = of_match_ptr(pl01x_serial_of_to_plat), + .plat_auto = sizeof(struct pl01x_serial_plat), + .probe = pl01x_serial_probe, + .ops = &pl01x_serial_ops, + .flags = DM_FLAG_PRE_RELOC, + .priv_auto = 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 diff --git a/roms/u-boot/drivers/serial/serial_pl01x_internal.h b/roms/u-boot/drivers/serial/serial_pl01x_internal.h new file mode 100644 index 000000000..dfd95a0b7 --- /dev/null +++ b/roms/u-boot/drivers/serial/serial_pl01x_internal.h @@ -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_of_to_plat(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) diff --git a/roms/u-boot/drivers/serial/serial_pxa.c b/roms/u-boot/drivers/serial/serial_pxa.c new file mode 100644 index 000000000..330fc127e --- /dev/null +++ b/roms/u-boot/drivers/serial/serial_pxa.c @@ -0,0 +1,343 @@ +// 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 <hang.h> +#include <asm/arch/pxa-regs.h> +#include <asm/arch/regs-uart.h> +#include <asm/global_data.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_plat *plat = dev_get_plat(dev); + + 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_plat *plat = dev_get_plat(dev); + 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_plat *plat = dev_get_plat(dev); + 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_plat *plat = dev_get_plat(dev); + 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_plat *plat = dev_get_plat(dev); + 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 */ diff --git a/roms/u-boot/drivers/serial/serial_rockchip.c b/roms/u-boot/drivers/serial/serial_rockchip.c new file mode 100644 index 000000000..97d40869a --- /dev/null +++ b/roms/u-boot/drivers/serial/serial_rockchip.c @@ -0,0 +1,61 @@ +// 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> +#include <dm/device-internal.h> + +#if defined(CONFIG_ROCKCHIP_RK3188) +struct rockchip_uart_plat { + struct dtd_rockchip_rk3188_uart dtplat; + struct ns16550_plat plat; +}; +struct dtd_rockchip_rk3188_uart *dtplat, s_dtplat; +#elif defined(CONFIG_ROCKCHIP_RK3288) +struct rockchip_uart_plat { + struct dtd_rockchip_rk3288_uart dtplat; + struct ns16550_plat plat; +}; +struct dtd_rockchip_rk3288_uart *dtplat, s_dtplat; +#endif + +static int rockchip_serial_probe(struct udevice *dev) +{ + struct rockchip_uart_plat *plat = dev_get_plat(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_set_plat(dev, &plat->plat); + + return ns16550_serial_probe(dev); +} + +U_BOOT_DRIVER(rockchip_rk3188_uart) = { + .name = "rockchip_rk3188_uart", + .id = UCLASS_SERIAL, + .priv_auto = sizeof(struct ns16550), + .plat_auto = sizeof(struct rockchip_uart_plat), + .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 = sizeof(struct ns16550), + .plat_auto = sizeof(struct rockchip_uart_plat), + .probe = rockchip_serial_probe, + .ops = &ns16550_serial_ops, + .flags = DM_FLAG_PRE_RELOC, +}; diff --git a/roms/u-boot/drivers/serial/serial_s5p.c b/roms/u-boot/drivers/serial/serial_s5p.c new file mode 100644 index 000000000..6d09952a5 --- /dev/null +++ b/roms/u-boot/drivers/serial/serial_s5p.c @@ -0,0 +1,241 @@ +// 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 <asm/global_data.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_plat { + 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_plat *plat = dev_get_plat(dev); + 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_plat *plat = dev_get_plat(dev); + 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_plat *plat = dev_get_plat(dev); + 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_plat *plat = dev_get_plat(dev); + 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_plat *plat = dev_get_plat(dev); + 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_of_to_plat(struct udevice *dev) +{ + struct s5p_serial_plat *plat = dev_get_plat(dev); + fdt_addr_t addr; + + addr = dev_read_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(dev)); + 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, + .of_to_plat = s5p_serial_of_to_plat, + .plat_auto = sizeof(struct s5p_serial_plat), + .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 diff --git a/roms/u-boot/drivers/serial/serial_sh.c b/roms/u-boot/drivers/serial/serial_sh.c new file mode 100644 index 000000000..e6c23cedf --- /dev/null +++ b/roms/u-boot/drivers/serial/serial_sh.c @@ -0,0 +1,369 @@ +// 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/global_data.h> +#include <asm/io.h> +#include <asm/processor.h> +#include <serial.h> +#include <linux/compiler.h> +#include <dm/platform_data/serial_sh.h> +#include <linux/delay.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); + status &= (SCIF_DR | SCxSR_RDxF(port)); + if (status) + return status; + return scif_rxfill(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_plat *plat = dev_get_plat(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_plat *plat = dev_get_plat(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_of_to_plat(struct udevice *dev) +{ + struct sh_serial_plat *plat = dev_get_plat(dev); + struct clk sh_serial_clk; + fdt_addr_t addr; + int ret; + + addr = dev_read_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), + .of_to_plat = of_match_ptr(sh_serial_of_to_plat), + .plat_auto = sizeof(struct sh_serial_plat), + .probe = sh_serial_probe, + .ops = &sh_serial_ops, +#if !CONFIG_IS_ENABLED(OF_CONTROL) + .flags = DM_FLAG_PRE_RELOC, +#endif + .priv_auto = 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 */ diff --git a/roms/u-boot/drivers/serial/serial_sh.h b/roms/u-boot/drivers/serial/serial_sh.h new file mode 100644 index 000000000..11deaa951 --- /dev/null +++ b/roms/u-boot/drivers/serial/serial_sh.h @@ -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 diff --git a/roms/u-boot/drivers/serial/serial_sifive.c b/roms/u-boot/drivers/serial/serial_sifive.c new file mode 100644 index 000000000..794f9c924 --- /dev/null +++ b/roms/u-boot/drivers/serial/serial_sifive.c @@ -0,0 +1,233 @@ +// 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 <log.h> +#include <watchdog.h> +#include <asm/global_data.h> +#include <asm/io.h> +#include <linux/compiler.h> +#include <serial.h> +#include <linux/err.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_plat { + 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_plat *plat = dev_get_plat(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; + } + } + plat->clock = clock; + _sifive_serial_setbrg(plat->regs, plat->clock, baudrate); + + return 0; +} + +static int sifive_serial_probe(struct udevice *dev) +{ + struct sifive_uart_plat *plat = dev_get_plat(dev); + + /* No need to reinitialize the UART after relocation */ + if (gd->flags & GD_FLG_RELOC) + return 0; + + _sifive_serial_init(plat->regs); + + return 0; +} + +static int sifive_serial_getc(struct udevice *dev) +{ + int c; + struct sifive_uart_plat *plat = dev_get_plat(dev); + struct uart_sifive *regs = plat->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_plat *plat = dev_get_plat(dev); + + while ((rc = _sifive_serial_putc(plat->regs, ch)) == -EAGAIN) ; + + return rc; +} + +static int sifive_serial_pending(struct udevice *dev, bool input) +{ + struct sifive_uart_plat *plat = dev_get_plat(dev); + struct uart_sifive *regs = plat->regs; + + if (input) + return (readl(®s->ip) & UART_IP_RXWM); + else + return !!(readl(®s->txfifo) & UART_TXFIFO_FULL); +} + +static int sifive_serial_of_to_plat(struct udevice *dev) +{ + struct sifive_uart_plat *plat = dev_get_plat(dev); + + plat->regs = (struct uart_sifive *)(uintptr_t)dev_read_addr(dev); + if (IS_ERR(plat->regs)) + return PTR_ERR(plat->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, + .of_to_plat = sifive_serial_of_to_plat, + .plat_auto = sizeof(struct sifive_uart_plat), + .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 diff --git a/roms/u-boot/drivers/serial/serial_sti_asc.c b/roms/u-boot/drivers/serial/serial_sti_asc.c new file mode 100644 index 000000000..2cada4efb --- /dev/null +++ b/roms/u-boot/drivers/serial/serial_sti_asc.c @@ -0,0 +1,212 @@ +// 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@foss.st.com> for STMicroelectronics. + */ + +#include <common.h> +#include <dm.h> +#include <log.h> +#include <serial.h> +#include <asm/global_data.h> +#include <asm/io.h> +#include <linux/bitops.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 = dev_read_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 = sizeof(struct sti_asc_serial), +}; + diff --git a/roms/u-boot/drivers/serial/serial_stm32.c b/roms/u-boot/drivers/serial/serial_stm32.c new file mode 100644 index 000000000..f6cb708c3 --- /dev/null +++ b/roms/u-boot/drivers/serial/serial_stm32.c @@ -0,0 +1,292 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2016, STMicroelectronics - All Rights Reserved + * Author(s): Vikas Manocha, <vikas.manocha@st.com> for STMicroelectronics. + */ + +#define LOG_CATEGORY UCLASS_SERIAL + +#include <common.h> +#include <clk.h> +#include <dm.h> +#include <log.h> +#include <reset.h> +#include <serial.h> +#include <watchdog.h> +#include <asm/io.h> +#include <asm/arch/stm32.h> +#include <dm/device_compat.h> +#include <linux/bitops.h> +#include <linux/delay.h> +#include "serial_stm32.h" +#include <dm/device_compat.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_plat *plat = dev_get_plat(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_plat *plat = dev_get_plat(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_plat *plat = dev_get_plat(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_plat *plat = dev_get_plat(dev); + + return _stm32_serial_putc(plat->base, plat->uart_info, c); +} + +static int stm32_serial_pending(struct udevice *dev, bool input) +{ + struct stm32x7_serial_plat *plat = dev_get_plat(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_plat *plat = dev_get_plat(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_of_to_plat(struct udevice *dev) +{ + struct stm32x7_serial_plat *plat = dev_get_plat(dev); + + plat->base = dev_read_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), + .of_to_plat = of_match_ptr(stm32_serial_of_to_plat), + .plat_auto = sizeof(struct stm32x7_serial_plat), + .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 diff --git a/roms/u-boot/drivers/serial/serial_stm32.h b/roms/u-boot/drivers/serial/serial_stm32.h new file mode 100644 index 000000000..5bee68fa9 --- /dev/null +++ b/roms/u-boot/drivers/serial/serial_stm32.h @@ -0,0 +1,82 @@ +/* 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_ + +#include <linux/bitops.h> +#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_plat { + 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 diff --git a/roms/u-boot/drivers/serial/serial_uniphier.c b/roms/u-boot/drivers/serial/serial_uniphier.c new file mode 100644 index 000000000..27e4b92c3 --- /dev/null +++ b/roms/u-boot/drivers/serial/serial_uniphier.c @@ -0,0 +1,177 @@ +// 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/bitfield.h> +#include <linux/bitops.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> + +#define UNIPHIER_UART_REGSHIFT 2 + +#define UNIPHIER_UART_RX (0 << (UNIPHIER_UART_REGSHIFT)) +#define UNIPHIER_UART_TX UNIPHIER_UART_RX +/* bit[15:8] = CHAR, bit[7:0] = FCR */ +#define UNIPHIER_UART_CHAR_FCR (3 << (UNIPHIER_UART_REGSHIFT)) +#define UNIPHIER_UART_FCR_MASK GENMASK(7, 0) +/* bit[15:8] = LCR, bit[7:0] = MCR */ +#define UNIPHIER_UART_LCR_MCR (4 << (UNIPHIER_UART_REGSHIFT)) +#define UNIPHIER_UART_LCR_MASK GENMASK(15, 8) +#define UNIPHIER_UART_LSR (5 << (UNIPHIER_UART_REGSHIFT)) +/* Divisor Latch Register */ +#define UNIPHIER_UART_DLR (9 << (UNIPHIER_UART_REGSHIFT)) + +struct uniphier_serial_priv { + void __iomem *membase; + unsigned int uartclk; +}; + +static int uniphier_serial_setbrg(struct udevice *dev, int baudrate) +{ + struct uniphier_serial_priv *priv = dev_get_priv(dev); + static const unsigned int mode_x_div = 16; + unsigned int divisor; + + divisor = DIV_ROUND_CLOSEST(priv->uartclk, mode_x_div * baudrate); + + /* flush the trasmitter before changing hw setting */ + while (!(readl(priv->membase + UNIPHIER_UART_LSR) & UART_LSR_TEMT)) + ; + + writel(divisor, priv->membase + UNIPHIER_UART_DLR); + + return 0; +} + +static int uniphier_serial_getc(struct udevice *dev) +{ + struct uniphier_serial_priv *priv = dev_get_priv(dev); + + if (!(readl(priv->membase + UNIPHIER_UART_LSR) & UART_LSR_DR)) + return -EAGAIN; + + return readl(priv->membase + UNIPHIER_UART_RX); +} + +static int uniphier_serial_putc(struct udevice *dev, const char c) +{ + struct uniphier_serial_priv *priv = dev_get_priv(dev); + + if (!(readl(priv->membase + UNIPHIER_UART_LSR) & UART_LSR_THRE)) + return -EAGAIN; + + writel(c, priv->membase + UNIPHIER_UART_TX); + + return 0; +} + +static int uniphier_serial_pending(struct udevice *dev, bool input) +{ + struct uniphier_serial_priv *priv = dev_get_priv(dev); + + if (input) + return readl(priv->membase + UNIPHIER_UART_LSR) & UART_LSR_DR; + else + return !(readl(priv->membase + UNIPHIER_UART_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); + const struct uniphier_serial_clk_data *clk_data; + ofnode root_node; + fdt_addr_t base; + u32 tmp; + + base = dev_read_addr(dev); + if (base == FDT_ADDR_T_NONE) + return -EINVAL; + + priv->membase = devm_ioremap(dev, base, SZ_64); + if (!priv->membase) + return -ENOMEM; + + 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; + + /* flush the trasmitter before changing hw setting */ + while (!(readl(priv->membase + UNIPHIER_UART_LSR) & UART_LSR_TEMT)) + ; + + /* enable FIFO */ + tmp = readl(priv->membase + UNIPHIER_UART_CHAR_FCR); + tmp &= ~UNIPHIER_UART_FCR_MASK; + tmp |= FIELD_PREP(UNIPHIER_UART_FCR_MASK, UART_FCR_ENABLE_FIFO); + writel(tmp, priv->membase + UNIPHIER_UART_CHAR_FCR); + + tmp = readl(priv->membase + UNIPHIER_UART_LCR_MCR); + tmp &= ~UNIPHIER_UART_LCR_MASK; + tmp |= FIELD_PREP(UNIPHIER_UART_LCR_MASK, UART_LCR_WLEN8); + writel(tmp, priv->membase + UNIPHIER_UART_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 = sizeof(struct uniphier_serial_priv), + .ops = &uniphier_serial_ops, +}; diff --git a/roms/u-boot/drivers/serial/serial_xen.c b/roms/u-boot/drivers/serial/serial_xen.c new file mode 100644 index 000000000..e1d5b229b --- /dev/null +++ b/roms/u-boot/drivers/serial/serial_xen.c @@ -0,0 +1,183 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * (C) 2018 NXP + * (C) 2020 EPAM Systems Inc. + */ +#include <common.h> +#include <cpu_func.h> +#include <dm.h> +#include <serial.h> +#include <watchdog.h> +#include <asm/global_data.h> + +#include <linux/bug.h> + +#include <xen/hvm.h> +#include <xen/events.h> + +#include <xen/interface/sched.h> +#include <xen/interface/hvm/hvm_op.h> +#include <xen/interface/hvm/params.h> +#include <xen/interface/io/console.h> +#include <xen/interface/io/ring.h> + +DECLARE_GLOBAL_DATA_PTR; + +u32 console_evtchn; + +/* + * struct xen_uart_priv - Structure representing a Xen UART info + * @intf: Console I/O interface for Xen guest OSes + * @evtchn: Console event channel + */ +struct xen_uart_priv { + struct xencons_interface *intf; + u32 evtchn; +}; + +int xen_serial_setbrg(struct udevice *dev, int baudrate) +{ + return 0; +} + +static int xen_serial_probe(struct udevice *dev) +{ + struct xen_uart_priv *priv = dev_get_priv(dev); + u64 val = 0; + unsigned long gfn; + int ret; + + ret = hvm_get_parameter(HVM_PARAM_CONSOLE_EVTCHN, &val); + if (ret < 0 || val == 0) + return ret; + + priv->evtchn = val; + console_evtchn = val; + + ret = hvm_get_parameter(HVM_PARAM_CONSOLE_PFN, &val); + if (ret < 0) + return ret; + + if (!val) + return -EINVAL; + + gfn = val; + priv->intf = (struct xencons_interface *)(gfn << XEN_PAGE_SHIFT); + + return 0; +} + +static int xen_serial_pending(struct udevice *dev, bool input) +{ + struct xen_uart_priv *priv = dev_get_priv(dev); + struct xencons_interface *intf = priv->intf; + + if (!input || intf->in_cons == intf->in_prod) + return 0; + + return 1; +} + +static int xen_serial_getc(struct udevice *dev) +{ + struct xen_uart_priv *priv = dev_get_priv(dev); + struct xencons_interface *intf = priv->intf; + XENCONS_RING_IDX cons; + char c; + + while (intf->in_cons == intf->in_prod) + mb(); /* wait */ + + cons = intf->in_cons; + mb(); /* get pointers before reading ring */ + + c = intf->in[MASK_XENCONS_IDX(cons++, intf->in)]; + + mb(); /* read ring before consuming */ + intf->in_cons = cons; + + notify_remote_via_evtchn(priv->evtchn); + + return c; +} + +static int __write_console(struct udevice *dev, const char *data, int len) +{ + struct xen_uart_priv *priv = dev_get_priv(dev); + struct xencons_interface *intf = priv->intf; + XENCONS_RING_IDX cons, prod; + int sent = 0; + + cons = intf->out_cons; + prod = intf->out_prod; + mb(); /* Update pointer */ + + WARN_ON((prod - cons) > sizeof(intf->out)); + + while ((sent < len) && ((prod - cons) < sizeof(intf->out))) + intf->out[MASK_XENCONS_IDX(prod++, intf->out)] = data[sent++]; + + mb(); /* Update data before pointer */ + intf->out_prod = prod; + + if (sent) + notify_remote_via_evtchn(priv->evtchn); + + return sent; +} + +static int write_console(struct udevice *dev, const char *data, int len) +{ + /* + * Make sure the whole buffer is emitted, polling if + * necessary. We don't ever want to rely on the hvc daemon + * because the most interesting console output is when the + * kernel is crippled. + */ + while (len) { + int sent = __write_console(dev, data, len); + + data += sent; + len -= sent; + + if (unlikely(len)) + HYPERVISOR_sched_op(SCHEDOP_yield, NULL); + } + + return 0; +} + +static int xen_serial_putc(struct udevice *dev, const char ch) +{ + write_console(dev, &ch, 1); + + return 0; +} + +static const struct dm_serial_ops xen_serial_ops = { + .putc = xen_serial_putc, + .getc = xen_serial_getc, + .pending = xen_serial_pending, +}; + +#if CONFIG_IS_ENABLED(OF_CONTROL) +static const struct udevice_id xen_serial_ids[] = { + { .compatible = "xen,xen" }, + { } +}; +#endif + +U_BOOT_DRIVER(serial_xen) = { + .name = "serial_xen", + .id = UCLASS_SERIAL, +#if CONFIG_IS_ENABLED(OF_CONTROL) + .of_match = xen_serial_ids, +#endif + .priv_auto = sizeof(struct xen_uart_priv), + .probe = xen_serial_probe, + .ops = &xen_serial_ops, +#if !CONFIG_IS_ENABLED(OF_CONTROL) + .flags = DM_FLAG_PRE_RELOC, +#endif +}; + diff --git a/roms/u-boot/drivers/serial/serial_xuartlite.c b/roms/u-boot/drivers/serial/serial_xuartlite.c new file mode 100644 index 000000000..9780a44d0 --- /dev/null +++ b/roms/u-boot/drivers/serial/serial_xuartlite.c @@ -0,0 +1,171 @@ +// 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/bitops.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 + +static bool little_endian; + +struct uartlite { + unsigned int rx_fifo; + unsigned int tx_fifo; + unsigned int status; + unsigned int control; +}; + +struct uartlite_plat { + struct uartlite *regs; +}; + +static u32 uart_in32(void __iomem *addr) +{ + if (little_endian) + return in_le32(addr); + else + return in_be32(addr); +} + +static void uart_out32(void __iomem *addr, u32 val) +{ + if (little_endian) + out_le32(addr, val); + else + out_be32(addr, val); +} + +static int uartlite_serial_putc(struct udevice *dev, const char ch) +{ + struct uartlite_plat *plat = dev_get_plat(dev); + struct uartlite *regs = plat->regs; + + if (uart_in32(®s->status) & SR_TX_FIFO_FULL) + return -EAGAIN; + + uart_out32(®s->tx_fifo, ch & 0xff); + + return 0; +} + +static int uartlite_serial_getc(struct udevice *dev) +{ + struct uartlite_plat *plat = dev_get_plat(dev); + struct uartlite *regs = plat->regs; + + if (!(uart_in32(®s->status) & SR_RX_FIFO_VALID_DATA)) + return -EAGAIN; + + return uart_in32(®s->rx_fifo) & 0xff; +} + +static int uartlite_serial_pending(struct udevice *dev, bool input) +{ + struct uartlite_plat *plat = dev_get_plat(dev); + struct uartlite *regs = plat->regs; + + if (input) + return uart_in32(®s->status) & SR_RX_FIFO_VALID_DATA; + + return !(uart_in32(®s->status) & SR_TX_FIFO_EMPTY); +} + +static int uartlite_serial_probe(struct udevice *dev) +{ + struct uartlite_plat *plat = dev_get_plat(dev); + struct uartlite *regs = plat->regs; + int ret; + + uart_out32(®s->control, 0); + uart_out32(®s->control, ULITE_CONTROL_RST_RX | ULITE_CONTROL_RST_TX); + ret = uart_in32(®s->status); + /* Endianness detection */ + if ((ret & SR_TX_FIFO_EMPTY) != SR_TX_FIFO_EMPTY) { + little_endian = true; + uart_out32(®s->control, ULITE_CONTROL_RST_RX | + ULITE_CONTROL_RST_TX); + } + + return 0; +} + +static int uartlite_serial_of_to_plat(struct udevice *dev) +{ + struct uartlite_plat *plat = dev_get_plat(dev); + + plat->regs = dev_read_addr_ptr(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, + .of_to_plat = uartlite_serial_of_to_plat, + .plat_auto = sizeof(struct uartlite_plat), + .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; + int ret; + + uart_out32(®s->control, 0); + uart_out32(®s->control, ULITE_CONTROL_RST_RX | ULITE_CONTROL_RST_TX); + ret = uart_in32(®s->status); + /* Endianness detection */ + if ((ret & SR_TX_FIFO_EMPTY) != SR_TX_FIFO_EMPTY) { + little_endian = true; + uart_out32(®s->control, ULITE_CONTROL_RST_RX | + ULITE_CONTROL_RST_TX); + } +} + +static inline void _debug_uart_putc(int ch) +{ + struct uartlite *regs = (struct uartlite *)CONFIG_DEBUG_UART_BASE; + + while (uart_in32(®s->status) & SR_TX_FIFO_FULL) + ; + + uart_out32(®s->tx_fifo, ch & 0xff); +} + +DEBUG_UART_FUNCS +#endif diff --git a/roms/u-boot/drivers/serial/serial_zynq.c b/roms/u-boot/drivers/serial/serial_zynq.c new file mode 100644 index 000000000..799d52404 --- /dev/null +++ b/roms/u-boot/drivers/serial/serial_zynq.c @@ -0,0 +1,240 @@ +// 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 <log.h> +#include <watchdog.h> +#include <asm/io.h> +#include <dm/device_compat.h> +#include <linux/bitops.h> +#include <linux/compiler.h> +#include <serial.h> +#include <linux/err.h> + +#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_plat { + struct uart_zynq *regs; +}; + +/* Set up the baud rate */ +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_plat *plat = dev_get_plat(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) { + dev_err(dev, "failed to enable clock\n"); + return ret; + } + + _uart_zynq_serial_setbrg(plat->regs, clock, baudrate); + + return 0; +} + +static int zynq_serial_probe(struct udevice *dev) +{ + struct zynq_uart_plat *plat = dev_get_plat(dev); + struct uart_zynq *regs = plat->regs; + u32 val; + + /* No need to reinitialize the UART if TX already enabled */ + val = readl(®s->control); + if (val & ZYNQ_UART_CR_TX_EN) + return 0; + + _uart_zynq_serial_init(plat->regs); + + return 0; +} + +static int zynq_serial_getc(struct udevice *dev) +{ + struct zynq_uart_plat *plat = dev_get_plat(dev); + struct uart_zynq *regs = plat->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_plat *plat = dev_get_plat(dev); + + return _uart_zynq_serial_putc(plat->regs, ch); +} + +static int zynq_serial_pending(struct udevice *dev, bool input) +{ + struct zynq_uart_plat *plat = dev_get_plat(dev); + struct uart_zynq *regs = plat->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_of_to_plat(struct udevice *dev) +{ + struct zynq_uart_plat *plat = dev_get_plat(dev); + + plat->regs = (struct uart_zynq *)dev_read_addr(dev); + if (IS_ERR(plat->regs)) + return PTR_ERR(plat->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, + .of_to_plat = zynq_serial_of_to_plat, + .plat_auto = sizeof(struct zynq_uart_plat), + .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 diff --git a/roms/u-boot/drivers/serial/usbtty.c b/roms/u-boot/drivers/serial/usbtty.c new file mode 100644 index 000000000..4f4eb02de --- /dev/null +++ b/roms/u-boot/drivers/serial/usbtty.c @@ -0,0 +1,1042 @@ +// 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 + */ + +#include <common.h> +#include <config.h> +#include <circbuf.h> +#include <env.h> +#include <serial.h> +#include <stdio_dev.h> +#include <asm/unaligned.h> +#include "usbtty.h" +#include "usb_cdc_acm.h" +#include "usbdescriptors.h" + +#ifdef DEBUG +#define TTYDBG(fmt,args...)\ + serial_printf("[%s] %s %d: "fmt, __FILE__,__FUNCTION__,__LINE__,##args) +#else +#define TTYDBG(fmt,args...) do{}while(0) +#endif + +#if 1 +#define TTYERR(fmt,args...)\ + serial_printf("ERROR![%s] %s %d: "fmt, __FILE__,__FUNCTION__,\ + __LINE__,##args) +#else +#define TTYERR(fmt,args...) do{}while(0) +#endif + +/* + * Defines + */ +#define NUM_CONFIGS 1 +#define MAX_INTERFACES 2 +#define NUM_ENDPOINTS 3 +#define ACM_TX_ENDPOINT 3 +#define ACM_RX_ENDPOINT 2 +#define GSERIAL_TX_ENDPOINT 2 +#define GSERIAL_RX_ENDPOINT 1 +#define NUM_ACM_INTERFACES 2 +#define NUM_GSERIAL_INTERFACES 1 +#define CONFIG_USBD_DATA_INTERFACE_STR "Bulk Data Interface" +#define CONFIG_USBD_CTRL_INTERFACE_STR "Control Interface" + +/* + * Buffers to hold input and output data + */ +#define USBTTY_BUFFER_SIZE 2048 +static circbuf_t usbtty_input; +static circbuf_t usbtty_output; + + +/* + * Instance variables + */ +static struct stdio_dev usbttydev; +static struct usb_device_instance device_instance[1]; +static struct usb_bus_instance bus_instance[1]; +static struct usb_configuration_instance config_instance[NUM_CONFIGS]; +static struct usb_interface_instance interface_instance[MAX_INTERFACES]; +static struct usb_alternate_instance alternate_instance[MAX_INTERFACES]; +/* one extra for control endpoint */ +static struct usb_endpoint_instance endpoint_instance[NUM_ENDPOINTS+1]; + +/* + * Global flag + */ +int usbtty_configured_flag = 0; + +/* + * Serial number + */ +static char serial_number[16]; + + +/* + * Descriptors, Strings, Local variables. + */ + +/* defined and used by gadget/ep0.c */ +extern struct usb_string_descriptor **usb_strings; + +/* Indicies, References */ +static unsigned short rx_endpoint = 0; +static unsigned short tx_endpoint = 0; +static unsigned short interface_count = 0; +static struct usb_string_descriptor *usbtty_string_table[STR_COUNT]; + +/* USB Descriptor Strings */ +static u8 wstrLang[4] = {4,USB_DT_STRING,0x9,0x4}; +static u8 wstrManufacturer[2 + 2*(sizeof(CONFIG_USBD_MANUFACTURER)-1)]; +static u8 wstrProduct[2 + 2*(sizeof(CONFIG_USBD_PRODUCT_NAME)-1)]; +static u8 wstrSerial[2 + 2*(sizeof(serial_number) - 1)]; +static u8 wstrConfiguration[2 + 2*(sizeof(CONFIG_USBD_CONFIGURATION_STR)-1)]; +static u8 wstrDataInterface[2 + 2*(sizeof(CONFIG_USBD_DATA_INTERFACE_STR)-1)]; +static u8 wstrCtrlInterface[2 + 2*(sizeof(CONFIG_USBD_DATA_INTERFACE_STR)-1)]; + +/* Standard USB Data Structures */ +static struct usb_interface_descriptor interface_descriptors[MAX_INTERFACES]; +static struct usb_endpoint_descriptor *ep_descriptor_ptrs[NUM_ENDPOINTS]; +static struct usb_configuration_descriptor *configuration_descriptor = 0; +static struct usb_device_descriptor device_descriptor = { + .bLength = sizeof(struct usb_device_descriptor), + .bDescriptorType = USB_DT_DEVICE, + .bcdUSB = cpu_to_le16(USB_BCD_VERSION), + .bDeviceSubClass = 0x00, + .bDeviceProtocol = 0x00, + .bMaxPacketSize0 = EP0_MAX_PACKET_SIZE, + .idVendor = cpu_to_le16(CONFIG_USBD_VENDORID), + .bcdDevice = cpu_to_le16(USBTTY_BCD_DEVICE), + .iManufacturer = STR_MANUFACTURER, + .iProduct = STR_PRODUCT, + .iSerialNumber = STR_SERIAL, + .bNumConfigurations = NUM_CONFIGS +}; + + +#if defined(CONFIG_USBD_HS) +static struct usb_qualifier_descriptor qualifier_descriptor = { + .bLength = sizeof(struct usb_qualifier_descriptor), + .bDescriptorType = USB_DT_QUAL, + .bcdUSB = cpu_to_le16(USB_BCD_VERSION), + .bDeviceClass = COMMUNICATIONS_DEVICE_CLASS, + .bDeviceSubClass = 0x00, + .bDeviceProtocol = 0x00, + .bMaxPacketSize0 = EP0_MAX_PACKET_SIZE, + .bNumConfigurations = NUM_CONFIGS +}; +#endif + +/* + * Static CDC ACM specific descriptors + */ + +struct acm_config_desc { + struct usb_configuration_descriptor configuration_desc; + + /* Master Interface */ + struct usb_interface_descriptor interface_desc; + + struct usb_class_header_function_descriptor usb_class_header; + struct usb_class_call_management_descriptor usb_class_call_mgt; + struct usb_class_abstract_control_descriptor usb_class_acm; + struct usb_class_union_function_descriptor usb_class_union; + struct usb_endpoint_descriptor notification_endpoint; + + /* Slave Interface */ + struct usb_interface_descriptor data_class_interface; + struct usb_endpoint_descriptor data_endpoints[NUM_ENDPOINTS-1]; +} __attribute__((packed)); + +static struct acm_config_desc acm_configuration_descriptors[NUM_CONFIGS] = { + { + .configuration_desc ={ + .bLength = + sizeof(struct usb_configuration_descriptor), + .bDescriptorType = USB_DT_CONFIG, + .wTotalLength = + cpu_to_le16(sizeof(struct acm_config_desc)), + .bNumInterfaces = NUM_ACM_INTERFACES, + .bConfigurationValue = 1, + .iConfiguration = STR_CONFIG, + .bmAttributes = + BMATTRIBUTE_SELF_POWERED|BMATTRIBUTE_RESERVED, + .bMaxPower = USBTTY_MAXPOWER + }, + /* Interface 1 */ + .interface_desc = { + .bLength = sizeof(struct usb_interface_descriptor), + .bDescriptorType = USB_DT_INTERFACE, + .bInterfaceNumber = 0, + .bAlternateSetting = 0, + .bNumEndpoints = 0x01, + .bInterfaceClass = + COMMUNICATIONS_INTERFACE_CLASS_CONTROL, + .bInterfaceSubClass = COMMUNICATIONS_ACM_SUBCLASS, + .bInterfaceProtocol = COMMUNICATIONS_V25TER_PROTOCOL, + .iInterface = STR_CTRL_INTERFACE, + }, + .usb_class_header = { + .bFunctionLength = + sizeof(struct usb_class_header_function_descriptor), + .bDescriptorType = CS_INTERFACE, + .bDescriptorSubtype = USB_ST_HEADER, + .bcdCDC = cpu_to_le16(110), + }, + .usb_class_call_mgt = { + .bFunctionLength = + sizeof(struct usb_class_call_management_descriptor), + .bDescriptorType = CS_INTERFACE, + .bDescriptorSubtype = USB_ST_CMF, + .bmCapabilities = 0x00, + .bDataInterface = 0x01, + }, + .usb_class_acm = { + .bFunctionLength = + sizeof(struct usb_class_abstract_control_descriptor), + .bDescriptorType = CS_INTERFACE, + .bDescriptorSubtype = USB_ST_ACMF, + .bmCapabilities = 0x00, + }, + .usb_class_union = { + .bFunctionLength = + sizeof(struct usb_class_union_function_descriptor), + .bDescriptorType = CS_INTERFACE, + .bDescriptorSubtype = USB_ST_UF, + .bMasterInterface = 0x00, + .bSlaveInterface0 = 0x01, + }, + .notification_endpoint = { + .bLength = + sizeof(struct usb_endpoint_descriptor), + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = UDC_INT_ENDPOINT | USB_DIR_IN, + .bmAttributes = USB_ENDPOINT_XFER_INT, + .wMaxPacketSize + = cpu_to_le16(CONFIG_USBD_SERIAL_INT_PKTSIZE), + .bInterval = 0xFF, + }, + + /* Interface 2 */ + .data_class_interface = { + .bLength = + sizeof(struct usb_interface_descriptor), + .bDescriptorType = USB_DT_INTERFACE, + .bInterfaceNumber = 0x01, + .bAlternateSetting = 0x00, + .bNumEndpoints = 0x02, + .bInterfaceClass = + COMMUNICATIONS_INTERFACE_CLASS_DATA, + .bInterfaceSubClass = DATA_INTERFACE_SUBCLASS_NONE, + .bInterfaceProtocol = DATA_INTERFACE_PROTOCOL_NONE, + .iInterface = STR_DATA_INTERFACE, + }, + .data_endpoints = { + { + .bLength = + sizeof(struct usb_endpoint_descriptor), + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = UDC_OUT_ENDPOINT | USB_DIR_OUT, + .bmAttributes = + USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = + cpu_to_le16(CONFIG_USBD_SERIAL_BULK_PKTSIZE), + .bInterval = 0xFF, + }, + { + .bLength = + sizeof(struct usb_endpoint_descriptor), + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = UDC_IN_ENDPOINT | USB_DIR_IN, + .bmAttributes = + USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = + cpu_to_le16(CONFIG_USBD_SERIAL_BULK_PKTSIZE), + .bInterval = 0xFF, + }, + }, + }, +}; + +static struct rs232_emu rs232_desc={ + .dter = 115200, + .stop_bits = 0x00, + .parity = 0x00, + .data_bits = 0x08 +}; + + +/* + * Static Generic Serial specific data + */ + + +struct gserial_config_desc { + + struct usb_configuration_descriptor configuration_desc; + struct usb_interface_descriptor interface_desc[NUM_GSERIAL_INTERFACES]; + struct usb_endpoint_descriptor data_endpoints[NUM_ENDPOINTS]; + +} __attribute__((packed)); + +static struct gserial_config_desc +gserial_configuration_descriptors[NUM_CONFIGS] ={ + { + .configuration_desc ={ + .bLength = sizeof(struct usb_configuration_descriptor), + .bDescriptorType = USB_DT_CONFIG, + .wTotalLength = + cpu_to_le16(sizeof(struct gserial_config_desc)), + .bNumInterfaces = NUM_GSERIAL_INTERFACES, + .bConfigurationValue = 1, + .iConfiguration = STR_CONFIG, + .bmAttributes = + BMATTRIBUTE_SELF_POWERED|BMATTRIBUTE_RESERVED, + .bMaxPower = USBTTY_MAXPOWER + }, + .interface_desc = { + { + .bLength = + sizeof(struct usb_interface_descriptor), + .bDescriptorType = USB_DT_INTERFACE, + .bInterfaceNumber = 0, + .bAlternateSetting = 0, + .bNumEndpoints = NUM_ENDPOINTS, + .bInterfaceClass = + COMMUNICATIONS_INTERFACE_CLASS_VENDOR, + .bInterfaceSubClass = + COMMUNICATIONS_NO_SUBCLASS, + .bInterfaceProtocol = + COMMUNICATIONS_NO_PROTOCOL, + .iInterface = STR_DATA_INTERFACE + }, + }, + .data_endpoints = { + { + .bLength = + sizeof(struct usb_endpoint_descriptor), + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = UDC_OUT_ENDPOINT | USB_DIR_OUT, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = + cpu_to_le16(CONFIG_USBD_SERIAL_OUT_PKTSIZE), + .bInterval= 0xFF, + }, + { + .bLength = + sizeof(struct usb_endpoint_descriptor), + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = UDC_IN_ENDPOINT | USB_DIR_IN, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = + cpu_to_le16(CONFIG_USBD_SERIAL_IN_PKTSIZE), + .bInterval = 0xFF, + }, + { + .bLength = + sizeof(struct usb_endpoint_descriptor), + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = UDC_INT_ENDPOINT | USB_DIR_IN, + .bmAttributes = USB_ENDPOINT_XFER_INT, + .wMaxPacketSize = + cpu_to_le16(CONFIG_USBD_SERIAL_INT_PKTSIZE), + .bInterval = 0xFF, + }, + }, + }, +}; + +/* + * Static Function Prototypes + */ + +static void usbtty_init_strings (void); +static void usbtty_init_instances (void); +static void usbtty_init_endpoints (void); +static void usbtty_init_terminal_type(short type); +static void usbtty_event_handler (struct usb_device_instance *device, + usb_device_event_t event, int data); +static int usbtty_cdc_setup(struct usb_device_request *request, + struct urb *urb); +static int usbtty_configured (void); +static int write_buffer (circbuf_t * buf); +static int fill_buffer (circbuf_t * buf); + +void usbtty_poll (void); + +/* utility function for converting char* to wide string used by USB */ +static void str2wide (char *str, u16 * wide) +{ + int i; + for (i = 0; i < strlen (str) && str[i]; i++){ + #if defined(__LITTLE_ENDIAN) + wide[i] = (u16) str[i]; + #elif defined(__BIG_ENDIAN) + wide[i] = ((u16)(str[i])<<8); + #else + #error "__LITTLE_ENDIAN or __BIG_ENDIAN undefined" + #endif + } +} + +/* + * Test whether a character is in the RX buffer + */ + +int usbtty_tstc(struct stdio_dev *dev) +{ + struct usb_endpoint_instance *endpoint = + &endpoint_instance[rx_endpoint]; + + /* If no input data exists, allow more RX to be accepted */ + if(usbtty_input.size <= 0){ + udc_unset_nak(endpoint->endpoint_address&0x03); + } + + usbtty_poll (); + return (usbtty_input.size > 0); +} + +/* + * Read a single byte from the usb client port. Returns 1 on success, 0 + * otherwise. When the function is succesfull, the character read is + * written into its argument c. + */ + +int usbtty_getc(struct stdio_dev *dev) +{ + char c; + struct usb_endpoint_instance *endpoint = + &endpoint_instance[rx_endpoint]; + + while (usbtty_input.size <= 0) { + udc_unset_nak(endpoint->endpoint_address&0x03); + usbtty_poll (); + } + + buf_pop (&usbtty_input, &c, 1); + udc_set_nak(endpoint->endpoint_address&0x03); + + return c; +} + +/* + * Output a single byte to the usb client port. + */ +void usbtty_putc(struct stdio_dev *dev, const char c) +{ + if (!usbtty_configured ()) + return; + + /* If \n, also do \r */ + if (c == '\n') + buf_push (&usbtty_output, "\r", 1); + + buf_push(&usbtty_output, &c, 1); + + /* Poll at end to handle new data... */ + if ((usbtty_output.size + 2) >= usbtty_output.totalsize) { + usbtty_poll (); + } +} + +/* usbtty_puts() helper function for finding the next '\n' in a string */ +static int next_nl_pos (const char *s) +{ + int i; + + for (i = 0; s[i] != '\0'; i++) { + if (s[i] == '\n') + return i; + } + return i; +} + +/* + * Output a string to the usb client port - implementing flow control + */ + +static void __usbtty_puts (const char *str, int len) +{ + int maxlen = usbtty_output.totalsize; + int space, n; + + /* break str into chunks < buffer size, if needed */ + while (len > 0) { + usbtty_poll (); + + space = maxlen - usbtty_output.size; + /* Empty buffer here, if needed, to ensure space... */ + if (space) { + write_buffer (&usbtty_output); + + n = min(space, min(len, maxlen)); + buf_push (&usbtty_output, str, n); + + str += n; + len -= n; + } + } +} + +void usbtty_puts(struct stdio_dev *dev, const char *str) +{ + int n; + int len; + + if (!usbtty_configured ()) + return; + + len = strlen (str); + /* add '\r' for each '\n' */ + while (len > 0) { + n = next_nl_pos (str); + + if (str[n] == '\n') { + __usbtty_puts(str, n); + __usbtty_puts("\r\n", 2); + str += (n + 1); + len -= (n + 1); + } else { + /* No \n found. All done. */ + __usbtty_puts (str, n); + break; + } + } + + /* Poll at end to handle new data... */ + usbtty_poll (); +} + +/* + * Initialize the usb client port. + * + */ +int drv_usbtty_init (void) +{ + int rc; + char * sn; + char * tt; + int snlen; + + /* Get serial number */ + sn = env_get("serial#"); + if (!sn) + sn = "000000000000"; + snlen = strlen(sn); + if (snlen > sizeof(serial_number) - 1) { + printf ("Warning: serial number %s is too long (%d > %lu)\n", + sn, snlen, (ulong)(sizeof(serial_number) - 1)); + snlen = sizeof(serial_number) - 1; + } + memcpy (serial_number, sn, snlen); + serial_number[snlen] = '\0'; + + /* Decide on which type of UDC device to be. + */ + tt = env_get("usbtty"); + if (!tt) + tt = "generic"; + usbtty_init_terminal_type(strcmp(tt,"cdc_acm")); + + /* prepare buffers... */ + buf_init (&usbtty_input, USBTTY_BUFFER_SIZE); + buf_init (&usbtty_output, USBTTY_BUFFER_SIZE); + + /* Now, set up USB controller and infrastructure */ + udc_init (); /* Basic USB initialization */ + + usbtty_init_strings (); + usbtty_init_instances (); + + usbtty_init_endpoints (); + + udc_startup_events (device_instance);/* Enable dev, init udc pointers */ + udc_connect (); /* Enable pullup for host detection */ + + /* Device initialization */ + memset (&usbttydev, 0, sizeof (usbttydev)); + + strcpy (usbttydev.name, "usbtty"); + usbttydev.ext = 0; /* No extensions */ + usbttydev.flags = DEV_FLAGS_INPUT | DEV_FLAGS_OUTPUT; + usbttydev.tstc = usbtty_tstc; /* 'tstc' function */ + usbttydev.getc = usbtty_getc; /* 'getc' function */ + usbttydev.putc = usbtty_putc; /* 'putc' function */ + usbttydev.puts = usbtty_puts; /* 'puts' function */ + + rc = stdio_register (&usbttydev); + + return (rc == 0) ? 1 : rc; +} + +static void usbtty_init_strings (void) +{ + struct usb_string_descriptor *string; + + usbtty_string_table[STR_LANG] = + (struct usb_string_descriptor*)wstrLang; + + string = (struct usb_string_descriptor *) wstrManufacturer; + string->bLength = sizeof(wstrManufacturer); + string->bDescriptorType = USB_DT_STRING; + str2wide (CONFIG_USBD_MANUFACTURER, string->wData); + usbtty_string_table[STR_MANUFACTURER]=string; + + + string = (struct usb_string_descriptor *) wstrProduct; + string->bLength = sizeof(wstrProduct); + string->bDescriptorType = USB_DT_STRING; + str2wide (CONFIG_USBD_PRODUCT_NAME, string->wData); + usbtty_string_table[STR_PRODUCT]=string; + + + string = (struct usb_string_descriptor *) wstrSerial; + string->bLength = sizeof(serial_number); + string->bDescriptorType = USB_DT_STRING; + str2wide (serial_number, string->wData); + usbtty_string_table[STR_SERIAL]=string; + + + string = (struct usb_string_descriptor *) wstrConfiguration; + string->bLength = sizeof(wstrConfiguration); + string->bDescriptorType = USB_DT_STRING; + str2wide (CONFIG_USBD_CONFIGURATION_STR, string->wData); + usbtty_string_table[STR_CONFIG]=string; + + + string = (struct usb_string_descriptor *) wstrDataInterface; + string->bLength = sizeof(wstrDataInterface); + string->bDescriptorType = USB_DT_STRING; + str2wide (CONFIG_USBD_DATA_INTERFACE_STR, string->wData); + usbtty_string_table[STR_DATA_INTERFACE]=string; + + string = (struct usb_string_descriptor *) wstrCtrlInterface; + string->bLength = sizeof(wstrCtrlInterface); + string->bDescriptorType = USB_DT_STRING; + str2wide (CONFIG_USBD_CTRL_INTERFACE_STR, string->wData); + usbtty_string_table[STR_CTRL_INTERFACE]=string; + + /* Now, initialize the string table for ep0 handling */ + usb_strings = usbtty_string_table; +} + +#define init_wMaxPacketSize(x) le16_to_cpu(get_unaligned(\ + &ep_descriptor_ptrs[(x) - 1]->wMaxPacketSize)); + +static void usbtty_init_instances (void) +{ + int i; + + /* initialize device instance */ + memset (device_instance, 0, sizeof (struct usb_device_instance)); + device_instance->device_state = STATE_INIT; + device_instance->device_descriptor = &device_descriptor; +#if defined(CONFIG_USBD_HS) + device_instance->qualifier_descriptor = &qualifier_descriptor; +#endif + device_instance->event = usbtty_event_handler; + device_instance->cdc_recv_setup = usbtty_cdc_setup; + device_instance->bus = bus_instance; + device_instance->configurations = NUM_CONFIGS; + device_instance->configuration_instance_array = config_instance; + + /* initialize bus instance */ + memset (bus_instance, 0, sizeof (struct usb_bus_instance)); + bus_instance->device = device_instance; + bus_instance->endpoint_array = endpoint_instance; + bus_instance->max_endpoints = 1; + bus_instance->maxpacketsize = 64; + bus_instance->serial_number_str = serial_number; + + /* configuration instance */ + memset (config_instance, 0, + sizeof (struct usb_configuration_instance)); + config_instance->interfaces = interface_count; + config_instance->configuration_descriptor = configuration_descriptor; + config_instance->interface_instance_array = interface_instance; + + /* interface instance */ + memset (interface_instance, 0, + sizeof (struct usb_interface_instance)); + interface_instance->alternates = 1; + interface_instance->alternates_instance_array = alternate_instance; + + /* alternates instance */ + memset (alternate_instance, 0, + sizeof (struct usb_alternate_instance)); + alternate_instance->interface_descriptor = interface_descriptors; + alternate_instance->endpoints = NUM_ENDPOINTS; + alternate_instance->endpoints_descriptor_array = ep_descriptor_ptrs; + + /* endpoint instances */ + memset (&endpoint_instance[0], 0, + sizeof (struct usb_endpoint_instance)); + endpoint_instance[0].endpoint_address = 0; + endpoint_instance[0].rcv_packetSize = EP0_MAX_PACKET_SIZE; + endpoint_instance[0].rcv_attributes = USB_ENDPOINT_XFER_CONTROL; + endpoint_instance[0].tx_packetSize = EP0_MAX_PACKET_SIZE; + endpoint_instance[0].tx_attributes = USB_ENDPOINT_XFER_CONTROL; + udc_setup_ep (device_instance, 0, &endpoint_instance[0]); + + for (i = 1; i <= NUM_ENDPOINTS; i++) { + memset (&endpoint_instance[i], 0, + sizeof (struct usb_endpoint_instance)); + + endpoint_instance[i].endpoint_address = + ep_descriptor_ptrs[i - 1]->bEndpointAddress; + + endpoint_instance[i].rcv_attributes = + ep_descriptor_ptrs[i - 1]->bmAttributes; + + endpoint_instance[i].rcv_packetSize = init_wMaxPacketSize(i); + + endpoint_instance[i].tx_attributes = + ep_descriptor_ptrs[i - 1]->bmAttributes; + + endpoint_instance[i].tx_packetSize = init_wMaxPacketSize(i); + + endpoint_instance[i].tx_attributes = + ep_descriptor_ptrs[i - 1]->bmAttributes; + + urb_link_init (&endpoint_instance[i].rcv); + urb_link_init (&endpoint_instance[i].rdy); + urb_link_init (&endpoint_instance[i].tx); + urb_link_init (&endpoint_instance[i].done); + + if (endpoint_instance[i].endpoint_address & USB_DIR_IN) + endpoint_instance[i].tx_urb = + usbd_alloc_urb (device_instance, + &endpoint_instance[i]); + else + endpoint_instance[i].rcv_urb = + usbd_alloc_urb (device_instance, + &endpoint_instance[i]); + } +} + +static void usbtty_init_endpoints (void) +{ + int i; + + bus_instance->max_endpoints = NUM_ENDPOINTS + 1; + for (i = 1; i <= NUM_ENDPOINTS; i++) { + udc_setup_ep (device_instance, i, &endpoint_instance[i]); + } +} + +/* usbtty_init_terminal_type + * + * Do some late binding for our device type. + */ +static void usbtty_init_terminal_type(short type) +{ + switch(type){ + /* CDC ACM */ + case 0: + /* Assign endpoint descriptors */ + ep_descriptor_ptrs[0] = + &acm_configuration_descriptors[0].notification_endpoint; + ep_descriptor_ptrs[1] = + &acm_configuration_descriptors[0].data_endpoints[0]; + ep_descriptor_ptrs[2] = + &acm_configuration_descriptors[0].data_endpoints[1]; + + /* Enumerate Device Descriptor */ + device_descriptor.bDeviceClass = + COMMUNICATIONS_DEVICE_CLASS; + device_descriptor.idProduct = + cpu_to_le16(CONFIG_USBD_PRODUCTID_CDCACM); + +#if defined(CONFIG_USBD_HS) + qualifier_descriptor.bDeviceClass = + COMMUNICATIONS_DEVICE_CLASS; +#endif + /* Assign endpoint indices */ + tx_endpoint = ACM_TX_ENDPOINT; + rx_endpoint = ACM_RX_ENDPOINT; + + /* Configuration Descriptor */ + configuration_descriptor = + (struct usb_configuration_descriptor*) + &acm_configuration_descriptors; + + /* Interface count */ + interface_count = NUM_ACM_INTERFACES; + break; + + /* BULK IN/OUT & Default */ + case 1: + default: + /* Assign endpoint descriptors */ + ep_descriptor_ptrs[0] = + &gserial_configuration_descriptors[0].data_endpoints[0]; + ep_descriptor_ptrs[1] = + &gserial_configuration_descriptors[0].data_endpoints[1]; + ep_descriptor_ptrs[2] = + &gserial_configuration_descriptors[0].data_endpoints[2]; + + /* Enumerate Device Descriptor */ + device_descriptor.bDeviceClass = 0xFF; + device_descriptor.idProduct = + cpu_to_le16(CONFIG_USBD_PRODUCTID_GSERIAL); +#if defined(CONFIG_USBD_HS) + qualifier_descriptor.bDeviceClass = 0xFF; +#endif + /* Assign endpoint indices */ + tx_endpoint = GSERIAL_TX_ENDPOINT; + rx_endpoint = GSERIAL_RX_ENDPOINT; + + /* Configuration Descriptor */ + configuration_descriptor = + (struct usb_configuration_descriptor*) + &gserial_configuration_descriptors; + + /* Interface count */ + interface_count = NUM_GSERIAL_INTERFACES; + break; + } +} + +/******************************************************************************/ + +static struct urb *next_urb (struct usb_device_instance *device, + struct usb_endpoint_instance *endpoint) +{ + struct urb *current_urb = NULL; + int space; + + /* If there's a queue, then we should add to the last urb */ + if (!endpoint->tx_queue) { + current_urb = endpoint->tx_urb; + } else { + /* Last urb from tx chain */ + current_urb = + p2surround (struct urb, link, endpoint->tx.prev); + } + + /* Make sure this one has enough room */ + space = current_urb->buffer_length - current_urb->actual_length; + if (space > 0) { + return current_urb; + } else { /* No space here */ + /* First look at done list */ + current_urb = first_urb_detached (&endpoint->done); + if (!current_urb) { + current_urb = usbd_alloc_urb (device, endpoint); + } + + urb_append (&endpoint->tx, current_urb); + endpoint->tx_queue++; + } + return current_urb; +} + +static int write_buffer (circbuf_t * buf) +{ + if (!usbtty_configured ()) { + return 0; + } + + struct usb_endpoint_instance *endpoint = + &endpoint_instance[tx_endpoint]; + struct urb *current_urb = NULL; + + /* TX data still exists - send it now + */ + if(endpoint->sent < endpoint->tx_urb->actual_length){ + if(udc_endpoint_write (endpoint)){ + /* Write pre-empted by RX */ + return -1; + } + } + + if (buf->size) { + char *dest; + + int space_avail; + int popnum, popped; + int total = 0; + + /* Break buffer into urb sized pieces, + * and link each to the endpoint + */ + while (buf->size > 0) { + + current_urb = next_urb (device_instance, endpoint); + + dest = (char*)current_urb->buffer + + current_urb->actual_length; + + space_avail = + current_urb->buffer_length - + current_urb->actual_length; + popnum = min(space_avail, (int)buf->size); + if (popnum == 0) + break; + + popped = buf_pop (buf, dest, popnum); + if (popped == 0) + break; + current_urb->actual_length += popped; + total += popped; + + /* If endpoint->last == 0, then transfers have + * not started on this endpoint + */ + if (endpoint->last == 0) { + if(udc_endpoint_write (endpoint)){ + /* Write pre-empted by RX */ + return -1; + } + } + + }/* end while */ + return total; + } + + return 0; +} + +static int fill_buffer (circbuf_t * buf) +{ + struct usb_endpoint_instance *endpoint = + &endpoint_instance[rx_endpoint]; + + if (endpoint->rcv_urb && endpoint->rcv_urb->actual_length) { + unsigned int nb = 0; + char *src = (char *) endpoint->rcv_urb->buffer; + unsigned int rx_avail = buf->totalsize - buf->size; + + if(rx_avail >= endpoint->rcv_urb->actual_length){ + + nb = endpoint->rcv_urb->actual_length; + buf_push (buf, src, nb); + endpoint->rcv_urb->actual_length = 0; + + } + return nb; + } + return 0; +} + +static int usbtty_configured (void) +{ + return usbtty_configured_flag; +} + +/******************************************************************************/ + +static void usbtty_event_handler (struct usb_device_instance *device, + usb_device_event_t event, int data) +{ +#if defined(CONFIG_USBD_HS) + int i; +#endif + switch (event) { + case DEVICE_RESET: + case DEVICE_BUS_INACTIVE: + usbtty_configured_flag = 0; + break; + case DEVICE_CONFIGURED: + usbtty_configured_flag = 1; + break; + + case DEVICE_ADDRESS_ASSIGNED: +#if defined(CONFIG_USBD_HS) + /* + * is_usbd_high_speed routine needs to be defined by + * specific gadget driver + * It returns true if device enumerates at High speed + * Retuns false otherwise + */ + for (i = 0; i < NUM_ENDPOINTS; i++) { + if (((ep_descriptor_ptrs[i]->bmAttributes & + USB_ENDPOINT_XFERTYPE_MASK) == + USB_ENDPOINT_XFER_BULK) + && is_usbd_high_speed()) { + + ep_descriptor_ptrs[i]->wMaxPacketSize = + CONFIG_USBD_SERIAL_BULK_HS_PKTSIZE; + } + + endpoint_instance[i + 1].tx_packetSize = + ep_descriptor_ptrs[i]->wMaxPacketSize; + endpoint_instance[i + 1].rcv_packetSize = + ep_descriptor_ptrs[i]->wMaxPacketSize; + } +#endif + usbtty_init_endpoints (); + + default: + break; + } +} + +/******************************************************************************/ + +int usbtty_cdc_setup(struct usb_device_request *request, struct urb *urb) +{ + switch (request->bRequest){ + + case ACM_SET_CONTROL_LINE_STATE: /* Implies DTE ready */ + break; + case ACM_SEND_ENCAPSULATED_COMMAND : /* Required */ + break; + case ACM_SET_LINE_ENCODING : /* DTE stop/parity bits + * per character */ + break; + case ACM_GET_ENCAPSULATED_RESPONSE : /* request response */ + break; + case ACM_GET_LINE_ENCODING : /* request DTE rate, + * stop/parity bits */ + memcpy (urb->buffer , &rs232_desc, sizeof(rs232_desc)); + urb->actual_length = sizeof(rs232_desc); + + break; + default: + return 1; + } + return 0; +} + +/******************************************************************************/ + +/* + * Since interrupt handling has not yet been implemented, we use this function + * to handle polling. This is called by the tstc,getc,putc,puts routines to + * update the USB state. + */ +void usbtty_poll (void) +{ + /* New interrupts? */ + udc_irq(); + + /* Write any output data to host buffer + * (do this before checking interrupts to avoid missing one) + */ + if (usbtty_configured ()) { + write_buffer (&usbtty_output); + } + + /* New interrupts? */ + udc_irq(); + + /* Check for new data from host.. + * (do this after checking interrupts to get latest data) + */ + if (usbtty_configured ()) { + fill_buffer (&usbtty_input); + } + + /* New interrupts? */ + udc_irq(); + +} diff --git a/roms/u-boot/drivers/serial/usbtty.h b/roms/u-boot/drivers/serial/usbtty.h new file mode 100644 index 000000000..05b3c01e5 --- /dev/null +++ b/roms/u-boot/drivers/serial/usbtty.h @@ -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 |