|
@@ -25,6 +25,28 @@
|
|
|
#include <linux/platform_device.h>
|
|
|
#include <linux/slab.h>
|
|
|
|
|
|
+/* Offsets for the DesignWare specific registers */
|
|
|
+#define DW_UART_USR 0x1f /* UART Status Register */
|
|
|
+#define DW_UART_CPR 0xf4 /* Component Parameter Register */
|
|
|
+#define DW_UART_UCV 0xf8 /* UART Component Version */
|
|
|
+
|
|
|
+/* Component Parameter Register bits */
|
|
|
+#define DW_UART_CPR_ABP_DATA_WIDTH (3 << 0)
|
|
|
+#define DW_UART_CPR_AFCE_MODE (1 << 4)
|
|
|
+#define DW_UART_CPR_THRE_MODE (1 << 5)
|
|
|
+#define DW_UART_CPR_SIR_MODE (1 << 6)
|
|
|
+#define DW_UART_CPR_SIR_LP_MODE (1 << 7)
|
|
|
+#define DW_UART_CPR_ADDITIONAL_FEATURES (1 << 8)
|
|
|
+#define DW_UART_CPR_FIFO_ACCESS (1 << 9)
|
|
|
+#define DW_UART_CPR_FIFO_STAT (1 << 10)
|
|
|
+#define DW_UART_CPR_SHADOW (1 << 11)
|
|
|
+#define DW_UART_CPR_ENCODED_PARMS (1 << 12)
|
|
|
+#define DW_UART_CPR_DMA_EXTRA (1 << 13)
|
|
|
+#define DW_UART_CPR_FIFO_MODE (0xff << 16)
|
|
|
+/* Helper for fifo size calculation */
|
|
|
+#define DW_UART_CPR_FIFO_SIZE(a) (((a >> 16) & 0xff) * 16)
|
|
|
+
|
|
|
+
|
|
|
struct dw8250_data {
|
|
|
int last_lcr;
|
|
|
int line;
|
|
@@ -66,9 +88,6 @@ static unsigned int dw8250_serial_in32(struct uart_port *p, int offset)
|
|
|
return readl(p->membase + offset);
|
|
|
}
|
|
|
|
|
|
-/* Offset for the DesignWare's UART Status Register. */
|
|
|
-#define UART_USR 0x1f
|
|
|
-
|
|
|
static int dw8250_handle_irq(struct uart_port *p)
|
|
|
{
|
|
|
struct dw8250_data *d = p->private_data;
|
|
@@ -78,7 +97,7 @@ static int dw8250_handle_irq(struct uart_port *p)
|
|
|
return 1;
|
|
|
} else if ((iir & UART_IIR_BUSY) == UART_IIR_BUSY) {
|
|
|
/* Clear the USR and write the LCR again. */
|
|
|
- (void)p->serial_in(p, UART_USR);
|
|
|
+ (void)p->serial_in(p, DW_UART_USR);
|
|
|
p->serial_out(p, d->last_lcr, UART_LCR);
|
|
|
|
|
|
return 1;
|
|
@@ -119,6 +138,34 @@ static int dw8250_probe_of(struct uart_port *p)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+static void dw8250_setup_port(struct uart_8250_port *up)
|
|
|
+{
|
|
|
+ struct uart_port *p = &up->port;
|
|
|
+ u32 reg = readl(p->membase + DW_UART_UCV);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * If the Component Version Register returns zero, we know that
|
|
|
+ * ADDITIONAL_FEATURES are not enabled. No need to go any further.
|
|
|
+ */
|
|
|
+ if (!reg)
|
|
|
+ return;
|
|
|
+
|
|
|
+ dev_dbg_ratelimited(p->dev, "Designware UART version %c.%c%c\n",
|
|
|
+ (reg >> 24) & 0xff, (reg >> 16) & 0xff, (reg >> 8) & 0xff);
|
|
|
+
|
|
|
+ reg = readl(p->membase + DW_UART_CPR);
|
|
|
+ if (!reg)
|
|
|
+ return;
|
|
|
+
|
|
|
+ /* Select the type based on fifo */
|
|
|
+ if (reg & DW_UART_CPR_FIFO_MODE) {
|
|
|
+ p->type = PORT_16550A;
|
|
|
+ p->flags |= UPF_FIXED_TYPE;
|
|
|
+ p->fifosize = DW_UART_CPR_FIFO_SIZE(reg);
|
|
|
+ up->tx_loadsz = p->fifosize;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
static int dw8250_probe(struct platform_device *pdev)
|
|
|
{
|
|
|
struct uart_8250_port uart = {};
|
|
@@ -156,6 +203,8 @@ static int dw8250_probe(struct platform_device *pdev)
|
|
|
return -ENODEV;
|
|
|
}
|
|
|
|
|
|
+ dw8250_setup_port(&uart);
|
|
|
+
|
|
|
data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
|
|
|
if (!data)
|
|
|
return -ENOMEM;
|