Add a serial driver that supports driver model. So far it only works with
the v1 serial port.

Signed-off-by: Simon Glass <[email protected]>
---

 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(&regs->lcr, DLAB);
+       SSYNC();
+
+       /* Program the divisor to get the baud rate we want */
+       bfin_write(&regs->dll, LOB(divisor));
+       bfin_write(&regs->dlh, HIB(divisor));
+       SSYNC();
+
+       /* Clear DLAB in LCR to Access THR RBR IER */
+       bfin_write_and(&regs->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(&regs->gctl, UCEN);
+
+       /* Set LCR to Word Lengh 8-bit word select */
+       bfin_write(&regs->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(&regs->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(&regs->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(&regs->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

_______________________________________________
U-Boot mailing list
[email protected]
http://lists.denx.de/mailman/listinfo/u-boot

Reply via email to