|
@@ -65,14 +65,36 @@ static int meson_serial_probe(struct udevice *dev)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+static void meson_serial_rx_error(struct udevice *dev)
|
|
|
+{
|
|
|
+ struct meson_serial_platdata *plat = dev->platdata;
|
|
|
+ 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_platdata *plat = dev->platdata;
|
|
|
struct meson_uart *const uart = plat->reg;
|
|
|
+ uint32_t status = readl(&uart->status);
|
|
|
|
|
|
- if (readl(&uart->status) & AML_UART_RX_EMPTY)
|
|
|
+ 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;
|
|
|
}
|
|
|
|
|
@@ -95,10 +117,23 @@ static int meson_serial_pending(struct udevice *dev, bool input)
|
|
|
struct meson_uart *const uart = plat->reg;
|
|
|
uint32_t status = readl(&uart->status);
|
|
|
|
|
|
- if (input)
|
|
|
- return !(status & AML_UART_RX_EMPTY);
|
|
|
- else
|
|
|
+ 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_ofdata_to_platdata(struct udevice *dev)
|