From: Domenico Andreoli <[email-masked]>

Very easy implementation of the AMBA PL010 driver.

That drv->devdata masked by macro pl010_decomp_base() is exactly the Nth
element of the array of "things" in the console data. In this case the
"things" in that array are bare base addresses.

This is how the console data definition in the board file may look:

static const unsigned long decomp_console[] __decomp_archdata = {
	0xa0000,
	0xb0000,
	0xc0000,
	0xd0000,
};

DECOMP_CONSOLE_MACH(SOMEMACH, "amba-pl011", decomp_console);

Signed-off-by: Domenico Andreoli <[email-masked]>

---
 drivers/tty/serial/amba-pl010.c |   51 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 51 insertions(+)

Index: b/drivers/tty/serial/amba-pl010.c
===================================================================
--- a/drivers/tty/serial/amba-pl010.c
+++ b/drivers/tty/serial/amba-pl010.c
@@ -42,6 +42,7 @@
 #include <linux/tty_flip.h>
 #include <linux/serial_core.h>
 #include <linux/serial.h>
+#include <linux/decompress/console.h>
 #include <linux/amba/bus.h>
 #include <linux/amba/serial.h>
 #include <linux/clk.h>
@@ -832,6 +833,56 @@ static void __exit pl010_exit(void)
 module_init(pl010_init);
 module_exit(pl010_exit);
 
+#define pl010_decomp_base(_drv)    (*(unsigned long *) (_drv)->devdata)
+
+static int __decomp_arch pl010_decomp_probe(struct decomp_console_drv *drv)
+{
+	unsigned long base = pl010_decomp_base(drv);
+	volatile uint32_t *cr;
+
+	/* this driver doesn't support probing of the base address */
+	if (!base)
+		return -EINVAL;
+
+	cr = (volatile uint32_t *) (base + UART010_CR);
+	return (*cr & UART01x_CR_UARTEN) ? 0 : -1;
+}
+
+static void __decomp_arch pl010_decomp_putc(struct decomp_console_drv *drv, int ch)
+{
+	unsigned long base = pl010_decomp_base(drv);
+	volatile uint32_t *fr, *dr;
+
+	fr = (volatile uint32_t *) (base + UART01x_FR);
+	while (*fr & UART01x_FR_TXFF)
+		barrier();
+
+	dr = (volatile uint32_t *) (base + UART01x_DR);
+	*dr = ch;
+}
+
+static void __decomp_arch pl010_decomp_flush(struct decomp_console_drv *drv)
+{
+	unsigned long base = pl010_decomp_base(drv);
+	volatile uint32_t *fr;
+
+	fr = (volatile uint32_t *) (base + UART01x_FR);
+	while (*fr & UART01x_FR_BUSY)
+		barrier();
+}
+
+static const char pl010_dt_compat[][16] __decomp_archdata = {
+	"amba-pl010",
+	"",
+};
+
+DECOMP_CONSOLE_START("ttyAM")
+	.probe = pl010_decomp_probe,
+	.putc = pl010_decomp_putc,
+	.flush = pl010_decomp_flush,
+	.dt_compat = pl010_dt_compat,
+DECOMP_CONSOLE_END
+
 MODULE_AUTHOR("ARM Ltd/Deep Blue Solutions Ltd");
 MODULE_DESCRIPTION("ARM AMBA serial port driver");
 MODULE_LICENSE("GPL");