[U-Boot] [PATCH 27/29] dm: blackfin: Add a driver-model serial driver
Simon Glass
sjg at chromium.org
Thu Dec 15 04:27:58 CET 2016
Add a serial driver that supports driver model. So far it only works with
the v1 serial port.
Signed-off-by: Simon Glass <sjg at chromium.org>
---
arch/blackfin/include/asm/serial1.h | 2 +
drivers/serial/Kconfig | 8 ++
drivers/serial/serial_bfin.c | 192 ++++++++++++++++++++++++++++++++++++
3 files changed, 202 insertions(+)
diff --git a/arch/blackfin/include/asm/serial1.h b/arch/blackfin/include/asm/serial1.h
index 467d381..be5a7a9 100644
--- a/arch/blackfin/include/asm/serial1.h
+++ b/arch/blackfin/include/asm/serial1.h
@@ -231,6 +231,7 @@ static inline void serial_early_do_portmux(void)
SSYNC();
}
+#ifndef CONFIG_DM_SERIAL
__attribute__((always_inline))
static inline int uart_init(uint32_t uart_base)
{
@@ -262,6 +263,7 @@ static inline int serial_early_uninit(uint32_t uart_base)
return 0;
}
+#endif /* !CONFIG_DM_SERIAL */
__attribute__((always_inline))
static inline void serial_set_divisor(uint32_t uart_base, uint16_t divisor)
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
index 620dd82..3b16c40 100644
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -161,6 +161,14 @@ config DEBUG_MVEBU_A3700_UART
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_BLACKFIN
+ bool "Blackfin"
+ help
+ Select this to enable a debug UART using the serial_bfin driver. You
+ will need to provide parameters to make this work. The driver will
+ be available until the real driver-model serial is running. This
+ only supports the v1 UART at present.
+
config DEBUG_UART_ZYNQ
bool "Xilinx Zynq"
help
diff --git a/drivers/serial/serial_bfin.c b/drivers/serial/serial_bfin.c
index 1d5be2a..8d80b05 100644
--- a/drivers/serial/serial_bfin.c
+++ b/drivers/serial/serial_bfin.c
@@ -38,6 +38,8 @@
*/
#include <common.h>
+#include <debug_uart.h>
+#include <dm.h>
#include <post.h>
#include <watchdog.h>
#include <serial.h>
@@ -47,6 +49,8 @@
DECLARE_GLOBAL_DATA_PTR;
+#ifndef CONFIG_DM_SERIAL
+
#ifdef CONFIG_UART_CONSOLE
#ifdef CONFIG_DEBUG_SERIAL
@@ -409,3 +413,191 @@ void bfin_serial_initialize(void)
serial_register(&bfin_serial_mem_device);
}
#endif /* CONFIG_UART_MEM */
+
+#endif /* CONFIG_DM_SERIAL */
+
+
+#ifdef CONFIG_DM_SERIAL
+struct bfin_serial_priv {
+ struct bfin_mmr_serial *regs;
+};
+
+static void dm_serial_set_divisor(struct bfin_mmr_serial *regs,
+ uint16_t divisor)
+{
+ /* Set DLAB in LCR to Access DLL and DLH */
+ bfin_write_or(®s->lcr, DLAB);
+ SSYNC();
+
+ /* Program the divisor to get the baud rate we want */
+ bfin_write(®s->dll, LOB(divisor));
+ bfin_write(®s->dlh, HIB(divisor));
+ SSYNC();
+
+ /* Clear DLAB in LCR to Access THR RBR IER */
+ bfin_write_and(®s->lcr, ~DLAB);
+ SSYNC();
+}
+
+static void __serial_set_baud(struct bfin_mmr_serial *regs, unsigned baud)
+{
+ uint16_t divisor = (get_uart_clk() + (baud * 8)) / (baud * 16)
+ - ANOMALY_05000230;
+
+ dm_serial_set_divisor(regs, divisor);
+}
+
+static inline int uart_init(struct bfin_mmr_serial *regs)
+{
+ /* always enable UART -- avoids anomalies 05000309 and 05000350 */
+ bfin_write(®s->gctl, UCEN);
+
+ /* Set LCR to Word Lengh 8-bit word select */
+ bfin_write(®s->lcr, WLS_8);
+
+ SSYNC();
+
+ return 0;
+}
+
+static int uart_tstc(struct bfin_mmr_serial *regs)
+{
+ WATCHDOG_RESET();
+ return (_lsr_read(regs) & DR) ? 1 : 0;
+}
+
+#if defined(CONFIG_DEBUG_UART_BLACKFIN)
+
+#include <debug_uart.h>
+
+static inline int serial_early_init(struct bfin_mmr_serial *regs)
+{
+ /* handle portmux crap on different Blackfins */
+ serial_early_do_portmux();
+
+ uart_init(regs);
+ serial_early_set_baud((ulong)regs, CONFIG_BAUDRATE);
+
+ return 0;
+}
+
+static void _debug_uart_init(void)
+{
+ struct bfin_mmr_serial *regs =
+ (struct bfin_mmr_serial *)CONFIG_DEBUG_UART_BASE;
+
+ serial_early_init(regs);
+}
+
+static inline void _debug_uart_putc(int ch)
+{
+ struct bfin_mmr_serial *regs =
+ (struct bfin_mmr_serial *)CONFIG_DEBUG_UART_BASE;
+
+ /* wait for the hardware fifo to clear up */
+ while (!(_lsr_read(regs) & THRE))
+ continue;
+
+ /* queue the character for transmission */
+ bfin_write(®s->thr, ch);
+ SSYNC();
+}
+
+DEBUG_UART_FUNCS
+
+#endif /* CONFIG_DEBUG_UART_BLACKFIN */
+
+static int bfin_serial_probe(struct udevice *dev)
+{
+ struct bfin_serial_priv *priv = dev_get_priv(dev);
+ const unsigned short pins[] = { _P_UART(0, RX), _P_UART(0, TX), 0, };
+ struct bfin_mmr_serial *regs;
+
+ peripheral_request_list(pins, "bfin-uart");
+ regs = (struct bfin_mmr_serial *)MMR_UART(0);
+ priv->regs = regs;
+
+ return 0;
+}
+
+static int bfin_serial_putc(struct udevice *dev, const char ch)
+{
+ struct bfin_serial_priv *priv = dev_get_priv(dev);
+ struct bfin_mmr_serial *regs = priv->regs;
+
+ /* wait for the hardware fifo to clear up */
+ if (!(_lsr_read(regs) & THRE))
+ return -EAGAIN;
+
+ /* queue the character for transmission */
+ bfin_write(®s->thr, ch);
+ SSYNC();
+
+ return 0;
+}
+
+static int bfin_serial_getc(struct udevice *dev)
+{
+ struct bfin_serial_priv *priv = dev_get_priv(dev);
+ struct bfin_mmr_serial *regs = priv->regs;
+ uint16_t uart_rbr_val;
+
+ /* wait for data ! */
+ if (!uart_tstc(regs))
+ return -EAGAIN;
+
+ /* grab the new byte */
+ uart_rbr_val = bfin_read(®s->rbr);
+ _lsr_write(regs, -1);
+
+ return uart_rbr_val;
+}
+
+int bfin_serial_setbrg(struct udevice *dev, int baudrate)
+{
+ struct bfin_serial_priv *priv = dev_get_priv(dev);
+ struct bfin_mmr_serial *regs = priv->regs;
+
+ uart_init(regs);
+ __serial_set_baud(regs, baudrate);
+ _lsr_write(regs, -1);
+
+ return 0;
+}
+
+static int bfin_serial_pending(struct udevice *dev, bool input)
+{
+ struct bfin_serial_priv *priv = dev_get_priv(dev);
+ struct bfin_mmr_serial *regs = priv->regs;
+
+ if (input)
+ return (_lsr_read(regs) & DR) ? 1 : 0;
+ else
+ return (_lsr_read(regs) & TEMT) ? 0 : 1;
+
+ return 0;
+}
+
+static const struct udevice_id bfin_uart_of_match[] = {
+ { .compatible = "adi,uart-v1" },
+ { /* sentinel */ }
+};
+
+static const struct dm_serial_ops bfin_serial_ops = {
+ .putc = bfin_serial_putc,
+ .pending = bfin_serial_pending,
+ .getc = bfin_serial_getc,
+ .setbrg = bfin_serial_setbrg,
+};
+
+U_BOOT_DRIVER(serial_bfin) = {
+ .name = "serial_bfin",
+ .id = UCLASS_SERIAL,
+ .of_match = bfin_uart_of_match,
+ .probe = bfin_serial_probe,
+ .ops = &bfin_serial_ops,
+ .priv_auto_alloc_size = sizeof(struct bfin_serial_priv),
+ .flags = DM_FLAG_PRE_RELOC,
+};
+
+#endif /* !CONFIG_DM_SERIAL */
--
2.8.0.rc3.226.g39d4020
More information about the U-Boot
mailing list