From 94bc9177cabdedd30795d236699b5df1c5c1d4a5 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Tue, 15 Aug 2017 22:38:27 -0700 Subject: x86: ich-spi: Remove spi_write_protect_region() This routine is not called anywhere. Signed-off-by: Bin Meng Reviewed-by: Stefan Roese --- drivers/spi/ich.c | 50 -------------------------------------------------- 1 file changed, 50 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/ich.c b/drivers/spi/ich.c index bf2e99b5ccb..46dd9a873c7 100644 --- a/drivers/spi/ich.c +++ b/drivers/spi/ich.c @@ -539,56 +539,6 @@ static int ich_spi_xfer(struct udevice *dev, unsigned int bitlen, return 0; } -/* - * This uses the SPI controller from the Intel Cougar Point and Panther Point - * PCH to write-protect portions of the SPI flash until reboot. The changes - * don't actually take effect until the HSFS[FLOCKDN] bit is set, but that's - * done elsewhere. - */ -int spi_write_protect_region(struct udevice *dev, uint32_t lower_limit, - uint32_t length, int hint) -{ - struct udevice *bus = dev->parent; - struct ich_spi_priv *ctlr = dev_get_priv(bus); - uint32_t tmplong; - uint32_t upper_limit; - - if (!ctlr->pr) { - printf("%s: operation not supported on this chipset\n", - __func__); - return -ENOSYS; - } - - if (length == 0 || - lower_limit > (0xFFFFFFFFUL - length) + 1 || - hint < 0 || hint > 4) { - printf("%s(0x%x, 0x%x, %d): invalid args\n", __func__, - lower_limit, length, hint); - return -EPERM; - } - - upper_limit = lower_limit + length - 1; - - /* - * Determine bits to write, as follows: - * 31 Write-protection enable (includes erase operation) - * 30:29 reserved - * 28:16 Upper Limit (FLA address bits 24:12, with 11:0 == 0xfff) - * 15 Read-protection enable - * 14:13 reserved - * 12:0 Lower Limit (FLA address bits 24:12, with 11:0 == 0x000) - */ - tmplong = 0x80000000 | - ((upper_limit & 0x01fff000) << 4) | - ((lower_limit & 0x01fff000) >> 12); - - printf("%s: writing 0x%08x to %p\n", __func__, tmplong, - &ctlr->pr[hint]); - ctlr->pr[hint] = tmplong; - - return 0; -} - static int ich_spi_probe(struct udevice *dev) { struct ich_spi_platdata *plat = dev_get_platdata(dev); -- cgit v1.3.1 From 7d8297892715563a7d9ff6ff90876fd7cbeddd30 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Tue, 15 Aug 2017 22:38:28 -0700 Subject: x86: ich-spi: Remove unnecessary assignment in ich_init_controller() There is no need to do another assignment to ich7_spi. Signed-off-by: Bin Meng Reviewed-by: Stefan Roese --- drivers/spi/ich.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/spi/ich.c b/drivers/spi/ich.c index 46dd9a873c7..909eefc0429 100644 --- a/drivers/spi/ich.c +++ b/drivers/spi/ich.c @@ -126,7 +126,6 @@ static int ich_init_controller(struct udevice *dev, if (plat->ich_version == ICHV_7) { struct ich7_spi_regs *ich7_spi = sbase; - ich7_spi = (struct ich7_spi_regs *)sbase; ctlr->ichspi_lock = readw(&ich7_spi->spis) & SPIS_LOCK; ctlr->opmenu = offsetof(struct ich7_spi_regs, opmenu); ctlr->menubytes = sizeof(ich7_spi->opmenu); -- cgit v1.3.1 From 3e7914168413f7aa05a68a53ca16e84b14d6851b Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Tue, 15 Aug 2017 22:38:29 -0700 Subject: x86: ich-spi: Don't read cached lock status At present the ICH SPI controller driver reads the controller lock status from its register in the probe routine and saves the lock status to a member of priv. Later the driver uses the cached status from priv to judge whether the controller setting is locked and do different setup. But such logic is only valid when there is only the SPI controller driver that touches the SPI hardware. In fact the lock status change can be trigged outside the driver, eg: during the fsp_notify() call when Intel FSP is used. This changes the driver to read the lock status every time when an SPI transfer is initiated instead of reading the cached one. Signed-off-by: Bin Meng Reviewed-by: Stefan Roese --- drivers/spi/ich.c | 29 +++++++++++++++++++++++------ drivers/spi/ich.h | 2 -- 2 files changed, 23 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/ich.c b/drivers/spi/ich.c index 909eefc0429..d4888f5fa48 100644 --- a/drivers/spi/ich.c +++ b/drivers/spi/ich.c @@ -126,7 +126,6 @@ static int ich_init_controller(struct udevice *dev, if (plat->ich_version == ICHV_7) { struct ich7_spi_regs *ich7_spi = sbase; - ctlr->ichspi_lock = readw(&ich7_spi->spis) & SPIS_LOCK; ctlr->opmenu = offsetof(struct ich7_spi_regs, opmenu); ctlr->menubytes = sizeof(ich7_spi->opmenu); ctlr->optype = offsetof(struct ich7_spi_regs, optype); @@ -141,7 +140,6 @@ static int ich_init_controller(struct udevice *dev, } else if (plat->ich_version == ICHV_9) { struct ich9_spi_regs *ich9_spi = sbase; - ctlr->ichspi_lock = readw(&ich9_spi->hsfs) & HSFS_FLOCKDN; ctlr->opmenu = offsetof(struct ich9_spi_regs, opmenu); ctlr->menubytes = sizeof(ich9_spi->opmenu); ctlr->optype = offsetof(struct ich9_spi_regs, optype); @@ -186,6 +184,23 @@ static inline void spi_use_in(struct spi_trans *trans, unsigned bytes) trans->bytesin -= bytes; } +static bool spi_lock_status(struct ich_spi_platdata *plat, void *sbase) +{ + int lock = 0; + + if (plat->ich_version == ICHV_7) { + struct ich7_spi_regs *ich7_spi = sbase; + + lock = readw(&ich7_spi->spis) & SPIS_LOCK; + } else if (plat->ich_version == ICHV_9) { + struct ich9_spi_regs *ich9_spi = sbase; + + lock = readw(&ich9_spi->hsfs) & HSFS_FLOCKDN; + } + + return lock != 0; +} + static void spi_setup_type(struct spi_trans *trans, int data_bytes) { trans->type = 0xFF; @@ -219,14 +234,15 @@ static void spi_setup_type(struct spi_trans *trans, int data_bytes) } } -static int spi_setup_opcode(struct ich_spi_priv *ctlr, struct spi_trans *trans) +static int spi_setup_opcode(struct ich_spi_priv *ctlr, struct spi_trans *trans, + bool lock) { uint16_t optypes; uint8_t opmenu[ctlr->menubytes]; trans->opcode = trans->out[0]; spi_use_out(trans, 1); - if (!ctlr->ichspi_lock) { + if (!lock) { /* The lock is off, so just use index 0. */ ich_writeb(ctlr, trans->opcode, ctlr->opmenu); optypes = ich_readw(ctlr, ctlr->optype); @@ -336,6 +352,7 @@ static int ich_spi_xfer(struct udevice *dev, unsigned int bitlen, struct spi_trans *trans = &ctlr->trans; unsigned type = flags & (SPI_XFER_BEGIN | SPI_XFER_END); int using_cmd = 0; + bool lock = spi_lock_status(plat, ctlr->base); int ret; /* We don't support writing partial bytes */ @@ -399,7 +416,7 @@ static int ich_spi_xfer(struct udevice *dev, unsigned int bitlen, ich_writeb(ctlr, SPIS_CDS | SPIS_FCERR, ctlr->status); spi_setup_type(trans, using_cmd ? bytes : 0); - opcode_index = spi_setup_opcode(ctlr, trans); + opcode_index = spi_setup_opcode(ctlr, trans, lock); if (opcode_index < 0) return -EINVAL; with_address = spi_setup_offset(trans); @@ -412,7 +429,7 @@ static int ich_spi_xfer(struct udevice *dev, unsigned int bitlen, * in order to prevent the Management Engine from * issuing a transaction between WREN and DATA. */ - if (!ctlr->ichspi_lock) + if (!lock) ich_writew(ctlr, trans->opcode, ctlr->preop); return 0; } diff --git a/drivers/spi/ich.h b/drivers/spi/ich.h index dcb8a9048f8..c867c57be9f 100644 --- a/drivers/spi/ich.h +++ b/drivers/spi/ich.h @@ -177,8 +177,6 @@ struct ich_spi_platdata { }; struct ich_spi_priv { - int ichspi_lock; - int locked; int opmenu; int menubytes; void *base; /* Base of register set */ -- cgit v1.3.1 From b42711f90c66d683b808cd78d9748ab38407413f Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Tue, 15 Aug 2017 22:38:30 -0700 Subject: x86: ich-spi: Move opcode registers configuration to another routine At present the ICH SPI opcode registers configuration is done in the ich_spi_remove() routine, a little bit weird but that's how current. Linux MTD driver works. This changes to move the opcode registers configuration to a separate routine ich_spi_config_opcode() which might be called by U-Boot itself as well. Signed-off-by: Bin Meng Reviewed-by: Stefan Roese --- drivers/spi/ich.c | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/ich.c b/drivers/spi/ich.c index d4888f5fa48..373bc2683b0 100644 --- a/drivers/spi/ich.c +++ b/drivers/spi/ich.c @@ -338,6 +338,21 @@ static int ich_status_poll(struct ich_spi_priv *ctlr, u16 bitmask, return -ETIMEDOUT; } +void ich_spi_config_opcode(struct udevice *dev) +{ + struct ich_spi_priv *ctlr = dev_get_priv(dev); + + /* + * PREOP, OPTYPE, OPMENU1/OPMENU2 registers can be locked down + * to prevent accidental or intentional writes. Before they get + * locked down, these registers should be initialized properly. + */ + ich_writew(ctlr, SPI_OPPREFIX, ctlr->preop); + ich_writew(ctlr, SPI_OPTYPE, ctlr->optype); + ich_writel(ctlr, SPI_OPMENU_LOWER, ctlr->opmenu); + ich_writel(ctlr, SPI_OPMENU_UPPER, ctlr->opmenu + sizeof(u32)); +} + static int ich_spi_xfer(struct udevice *dev, unsigned int bitlen, const void *dout, void *din, unsigned long flags) { @@ -585,16 +600,11 @@ static int ich_spi_probe(struct udevice *dev) static int ich_spi_remove(struct udevice *bus) { - struct ich_spi_priv *ctlr = dev_get_priv(bus); - /* * Configure SPI controller so that the Linux MTD driver can fully * access the SPI NOR chip */ - ich_writew(ctlr, SPI_OPPREFIX, ctlr->preop); - ich_writew(ctlr, SPI_OPTYPE, ctlr->optype); - ich_writel(ctlr, SPI_OPMENU_LOWER, ctlr->opmenu); - ich_writel(ctlr, SPI_OPMENU_UPPER, ctlr->opmenu + sizeof(u32)); + ich_spi_config_opcode(bus); return 0; } -- cgit v1.3.1 From 76e726502ec0230070640e3c4cd3dd930e5bb9e8 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Wed, 16 Aug 2017 07:35:36 -0700 Subject: vbe: Drop vbe_get_video_info() With DM video, this is not used any more. Drop it. Signed-off-by: Bin Meng --- drivers/pci/pci_rom.c | 41 ----------------------------------------- include/vbe.h | 2 -- 2 files changed, 43 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/pci_rom.c b/drivers/pci/pci_rom.c index 75fb0933371..46fe5e62471 100644 --- a/drivers/pci/pci_rom.c +++ b/drivers/pci/pci_rom.c @@ -202,47 +202,6 @@ static int pci_rom_load(struct pci_rom_header *rom_header, struct vbe_mode_info mode_info; -int vbe_get_video_info(struct graphic_device *gdev) -{ -#ifdef CONFIG_FRAMEBUFFER_SET_VESA_MODE - struct vesa_mode_info *vesa = &mode_info.vesa; - - gdev->winSizeX = vesa->x_resolution; - gdev->winSizeY = vesa->y_resolution; - - gdev->plnSizeX = vesa->x_resolution; - gdev->plnSizeY = vesa->y_resolution; - - gdev->gdfBytesPP = vesa->bits_per_pixel / 8; - - switch (vesa->bits_per_pixel) { - case 32: - case 24: - gdev->gdfIndex = GDF_32BIT_X888RGB; - break; - case 16: - gdev->gdfIndex = GDF_16BIT_565RGB; - break; - default: - gdev->gdfIndex = GDF__8BIT_INDEX; - break; - } - - gdev->isaBase = CONFIG_SYS_ISA_IO_BASE_ADDRESS; - gdev->pciBase = vesa->phys_base_ptr; - - gdev->frameAdrs = vesa->phys_base_ptr; - gdev->memSize = vesa->bytes_per_scanline * vesa->y_resolution; - - gdev->vprBase = vesa->phys_base_ptr; - gdev->cprBase = vesa->phys_base_ptr; - - return gdev->winSizeX ? 0 : -ENOSYS; -#else - return -ENOSYS; -#endif -} - void setup_video(struct screen_info *screen_info) { struct vesa_mode_info *vesa = &mode_info.vesa; diff --git a/include/vbe.h b/include/vbe.h index 16bb0962367..d6980d953fb 100644 --- a/include/vbe.h +++ b/include/vbe.h @@ -104,8 +104,6 @@ struct vbe_ddc_info { extern struct vbe_mode_info mode_info; -struct graphic_device; -int vbe_get_video_info(struct graphic_device *gdev); struct video_priv; struct video_uc_platdata; int vbe_setup_video_priv(struct vesa_mode_info *vesa, -- cgit v1.3.1 From 7fded0ce0ff68551ceb631f98d60db162e49f80c Mon Sep 17 00:00:00 2001 From: Stefan Roese Date: Wed, 16 Aug 2017 17:37:15 +0200 Subject: Revert "serial: ns16550: Add RX interrupt buffer support" This reverts commit 6822cf3ec7c8768b8727573b8f4b2cb3d870b881. As Bin Meng has tested and pointed out, we don't need the RX interrupt for the RX buffer support at all. Just reading all available characters into a buffer is sufficient to solve the problem with the dropped characters upon long lines pasted into the U-Boot prompt. Since this RX buffer support can be implemented in a generic way, without any device specifica (e.g. for the ns16550), I'll post a new patch with a new serial RX buffer support for DM, which all DM based serial drivers can use. Signed-off-by: Stefan Roese Cc: Simon Glass Cc: Bin Meng Cc: Tom Rini Reviewed-by: Bin Meng --- drivers/serial/Kconfig | 10 ---- drivers/serial/ns16550.c | 123 ++--------------------------------------------- include/ns16550.h | 10 ---- 3 files changed, 5 insertions(+), 138 deletions(-) (limited to 'drivers') diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index a8e997834ad..1c2c5d66e1d 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -64,16 +64,6 @@ config DM_SERIAL implements serial_putc() etc. The uclass interface is defined in include/serial.h. -config SERIAL_IRQ_BUFFER - bool "Enable RX interrupt buffer for serial input" - depends on DM_SERIAL - default n - help - Enable RX interrupt 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 SPL_DM_SERIAL bool "Enable Driver Model for serial drivers in SPL" depends on DM_SERIAL diff --git a/drivers/serial/ns16550.c b/drivers/serial/ns16550.c index 607a1b8c1de..c702304e79b 100644 --- a/drivers/serial/ns16550.c +++ b/drivers/serial/ns16550.c @@ -314,80 +314,6 @@ DEBUG_UART_FUNCS #endif #ifdef CONFIG_DM_SERIAL - -#if CONFIG_IS_ENABLED(SERIAL_IRQ_BUFFER) - -#define BUF_COUNT 256 - -static void rx_fifo_to_buf(struct udevice *dev) -{ - struct NS16550 *const com_port = dev_get_priv(dev); - struct ns16550_platdata *plat = dev->platdata; - - /* Read all available chars into buffer */ - while ((serial_in(&com_port->lsr) & UART_LSR_DR)) { - plat->buf[plat->wr_ptr++] = serial_in(&com_port->rbr); - plat->wr_ptr %= BUF_COUNT; - } -} - -static int rx_pending(struct udevice *dev) -{ - struct ns16550_platdata *plat = dev->platdata; - - /* - * At startup it may happen, that some already received chars are - * "stuck" in the RX FIFO, even with the interrupt enabled. This - * RX FIFO flushing makes sure, that these chars are read out and - * the RX interrupts works as expected. - */ - rx_fifo_to_buf(dev); - - return plat->rd_ptr != plat->wr_ptr ? 1 : 0; -} - -static int rx_get(struct udevice *dev) -{ - struct ns16550_platdata *plat = dev->platdata; - char val; - - val = plat->buf[plat->rd_ptr++]; - plat->rd_ptr %= BUF_COUNT; - - return val; -} - -void ns16550_handle_irq(void *data) -{ - struct udevice *dev = (struct udevice *)data; - struct NS16550 *const com_port = dev_get_priv(dev); - - /* Check if interrupt is pending */ - if (serial_in(&com_port->iir) & UART_IIR_NO_INT) - return; - - /* Flush all available characters from the RX FIFO into the RX buffer */ - rx_fifo_to_buf(dev); -} - -#else /* CONFIG_SERIAL_IRQ_BUFFER */ - -static int rx_pending(struct udevice *dev) -{ - struct NS16550 *const com_port = dev_get_priv(dev); - - return serial_in(&com_port->lsr) & UART_LSR_DR ? 1 : 0; -} - -static int rx_get(struct udevice *dev) -{ - struct NS16550 *const com_port = dev_get_priv(dev); - - return serial_in(&com_port->rbr); -} - -#endif /* CONFIG_SERIAL_IRQ_BUFFER */ - static int ns16550_serial_putc(struct udevice *dev, const char ch) { struct NS16550 *const com_port = dev_get_priv(dev); @@ -413,17 +339,19 @@ static int ns16550_serial_pending(struct udevice *dev, bool input) struct NS16550 *const com_port = dev_get_priv(dev); if (input) - return rx_pending(dev); + 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) { - if (!ns16550_serial_pending(dev, true)) + struct NS16550 *const com_port = dev_get_priv(dev); + + if (!(serial_in(&com_port->lsr) & UART_LSR_DR)) return -EAGAIN; - return rx_get(dev); + return serial_in(&com_port->rbr); } static int ns16550_serial_setbrg(struct udevice *dev, int baudrate) @@ -446,39 +374,8 @@ int ns16550_serial_probe(struct udevice *dev) com_port->plat = dev_get_platdata(dev); NS16550_init(com_port, -1); -#if CONFIG_IS_ENABLED(SERIAL_IRQ_BUFFER) - if (gd->flags & GD_FLG_RELOC) { - struct ns16550_platdata *plat = dev->platdata; - - /* Allocate the RX buffer */ - plat->buf = malloc(BUF_COUNT); - - /* Install the interrupt handler */ - irq_install_handler(plat->irq, ns16550_handle_irq, dev); - - /* Enable RX interrupts */ - serial_out(UART_IER_RDI, &com_port->ier); - } -#endif - - return 0; -} - -#if CONFIG_IS_ENABLED(SERIAL_PRESENT) && \ - (!defined(CONFIG_TPL_BUILD) || defined(CONFIG_TPL_DM_SERIAL)) -static int ns16550_serial_remove(struct udevice *dev) -{ -#if CONFIG_IS_ENABLED(SERIAL_IRQ_BUFFER) - if (gd->flags & GD_FLG_RELOC) { - struct ns16550_platdata *plat = dev->platdata; - - irq_free_handler(plat->irq); - } -#endif - return 0; } -#endif #if CONFIG_IS_ENABLED(OF_CONTROL) enum { @@ -561,15 +458,6 @@ int ns16550_serial_ofdata_to_platdata(struct udevice *dev) if (port_type == PORT_JZ4780) plat->fcr |= UART_FCR_UME; -#if CONFIG_IS_ENABLED(SERIAL_IRQ_BUFFER) - plat->irq = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev), - "interrupts", 0); - if (!plat->irq) { - debug("ns16550 interrupt not provided\n"); - return -EINVAL; - } -#endif - return 0; } #endif @@ -617,7 +505,6 @@ U_BOOT_DRIVER(ns16550_serial) = { #endif .priv_auto_alloc_size = sizeof(struct NS16550), .probe = ns16550_serial_probe, - .remove = ns16550_serial_remove, .ops = &ns16550_serial_ops, .flags = DM_FLAG_PRE_RELOC, }; diff --git a/include/ns16550.h b/include/ns16550.h index 7e9944d0d92..5fcbcd2e74e 100644 --- a/include/ns16550.h +++ b/include/ns16550.h @@ -51,10 +51,6 @@ * @base: Base register address * @reg_shift: Shift size of registers (0=byte, 1=16bit, 2=32bit...) * @clock: UART base clock speed in Hz - * - * @buf: Pointer to the RX interrupt buffer - * @rd_ptr: Read pointer in the RX interrupt buffer - * @wr_ptr: Write pointer in the RX interrupt buffer */ struct ns16550_platdata { unsigned long base; @@ -62,12 +58,6 @@ struct ns16550_platdata { int clock; int reg_offset; u32 fcr; - - int irq; - - char *buf; - int rd_ptr; - int wr_ptr; }; struct udevice; -- cgit v1.3.1 From 3ca7a06afb7cbc867b7861a8b9aada74e5bbb559 Mon Sep 17 00:00:00 2001 From: Stefan Roese Date: Wed, 16 Aug 2017 17:37:16 +0200 Subject: serial: serial-uclass: Add generic serial RX buffer support Pasting longer lines into the U-Boot console prompt sometimes leads to characters missing. One problem here is the small 16-byte FIFO of the legacy NS16550 UART, e.g. on x86 platforms. This patch now introduces a Kconfig option to enable RX buffer support for all DM based serial drivers. With this option enabled, I was able paste really long lines into the U-Boot console, without any characters missing. Signed-off-by: Stefan Roese Cc: Simon Glass Cc: Bin Meng Cc: Tom Rini Reviewed-by: Bin Meng Tested-by: Bin Meng --- drivers/serial/Kconfig | 15 +++++++++++++ drivers/serial/serial-uclass.c | 48 ++++++++++++++++++++++++++++++++++++++++-- include/serial.h | 10 ++++++++- 3 files changed, 70 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index 1c2c5d66e1d..aeed538fa4e 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -64,6 +64,21 @@ config DM_SERIAL 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 SPL_DM_SERIAL bool "Enable Driver Model for serial drivers in SPL" depends on DM_SERIAL diff --git a/drivers/serial/serial-uclass.c b/drivers/serial/serial-uclass.c index 998d372da6b..2e5116f7cee 100644 --- a/drivers/serial/serial-uclass.c +++ b/drivers/serial/serial-uclass.c @@ -160,7 +160,7 @@ static void _serial_puts(struct udevice *dev, const char *str) _serial_putc(dev, *str++); } -static int _serial_getc(struct udevice *dev) +static int __serial_getc(struct udevice *dev) { struct dm_serial_ops *ops = serial_get_ops(dev); int err; @@ -174,7 +174,7 @@ static int _serial_getc(struct udevice *dev) return err >= 0 ? err : 0; } -static int _serial_tstc(struct udevice *dev) +static int __serial_tstc(struct udevice *dev) { struct dm_serial_ops *ops = serial_get_ops(dev); @@ -184,6 +184,44 @@ static int _serial_tstc(struct udevice *dev) 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; + + 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) @@ -359,6 +397,12 @@ static int serial_post_probe(struct udevice *dev) 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; diff --git a/include/serial.h b/include/serial.h index f4171964ae6..d87f01082a0 100644 --- a/include/serial.h +++ b/include/serial.h @@ -148,10 +148,18 @@ struct dm_serial_ops { /** * struct serial_dev_priv - information about a device used by the uclass * - * @sdev: stdio device attached to this uart + * @sdev: stdio device attached to this uart + * + * @buf: Pointer to the RX buffer + * @rd_ptr: Read pointer in the RX buffer + * @wr_ptr: Write pointer in the RX buffer */ struct serial_dev_priv { struct stdio_dev *sdev; + + char *buf; + int rd_ptr; + int wr_ptr; }; /* Access the serial operations for a device */ -- cgit v1.3.1