[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(&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



More information about the U-Boot mailing list