Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a3ae0fc3 authored by Jamie Iles's avatar Jamie Iles Committed by Greg Kroah-Hartman
Browse files

8250: add a UPIO_DWAPB32 for 32 bit accesses



Some platforms contain a Synopsys DesignWare APB UART that is attached
to a 32-bit APB bus where sub-word accesses are not allowed. Add a new
IO type (UPIO_DWAPB32) that performs 32 bit acccesses to the UART.

v2:
	- don't test for 32 bit in the output fast path, provide a
	  separate dwabp32_serial_out() function. Refactor
	  dwabp_serial_out() so that we can reuse the LCR saving
	  code.
v3:
	- rebased on top of "8250: use container_of() instead of
	  casting"

Signed-off-by: default avatarJamie Iles <jamie@jamieiles.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 49d5741b
Loading
Loading
Loading
Loading
+39 −12
Original line number Original line Diff line number Diff line
@@ -454,22 +454,40 @@ static void tsi_serial_out(struct uart_port *p, int offset, int value)
		writeb(value, p->membase + offset);
		writeb(value, p->membase + offset);
}
}


static void dwapb_serial_out(struct uart_port *p, int offset, int value)
/* Save the LCR value so it can be re-written when a Busy Detect IRQ occurs. */
static inline void dwapb_save_out_value(struct uart_port *p, int offset,
					int value)
{
{
	int save_offset = offset;
	offset = map_8250_out_reg(p, offset) << p->regshift;
	/* Save the LCR value so it can be re-written when a
	 * Busy Detect interrupt occurs. */
	if (save_offset == UART_LCR) {
	struct uart_8250_port *up =
	struct uart_8250_port *up =
		container_of(p, struct uart_8250_port, port);
		container_of(p, struct uart_8250_port, port);

	if (offset == UART_LCR)
		up->lcr = value;
		up->lcr = value;
}
}

/* Read the IER to ensure any interrupt is cleared before returning from ISR. */
static inline void dwapb_check_clear_ier(struct uart_port *p, int offset)
{
	if (offset == UART_TX || offset == UART_IER)
		p->serial_in(p, UART_IER);
}

static void dwapb_serial_out(struct uart_port *p, int offset, int value)
{
	int save_offset = offset;
	offset = map_8250_out_reg(p, offset) << p->regshift;
	dwapb_save_out_value(p, save_offset, value);
	writeb(value, p->membase + offset);
	writeb(value, p->membase + offset);
	/* Read the IER to ensure any interrupt is cleared before
	dwapb_check_clear_ier(p, save_offset);
	 * returning from ISR. */
}
	if (save_offset == UART_TX || save_offset == UART_IER)

		value = p->serial_in(p, UART_IER);
static void dwapb32_serial_out(struct uart_port *p, int offset, int value)
{
	int save_offset = offset;
	offset = map_8250_out_reg(p, offset) << p->regshift;
	dwapb_save_out_value(p, save_offset, value);
	writel(value, p->membase + offset);
	dwapb_check_clear_ier(p, save_offset);
}
}


static unsigned int io_serial_in(struct uart_port *p, int offset)
static unsigned int io_serial_in(struct uart_port *p, int offset)
@@ -520,6 +538,11 @@ static void set_io_from_upio(struct uart_port *p)
		p->serial_out = dwapb_serial_out;
		p->serial_out = dwapb_serial_out;
		break;
		break;


	case UPIO_DWAPB32:
		p->serial_in = mem32_serial_in;
		p->serial_out = dwapb32_serial_out;
		break;

	default:
	default:
		p->serial_in = io_serial_in;
		p->serial_in = io_serial_in;
		p->serial_out = io_serial_out;
		p->serial_out = io_serial_out;
@@ -538,6 +561,7 @@ serial_out_sync(struct uart_8250_port *up, int offset, int value)
	case UPIO_MEM32:
	case UPIO_MEM32:
	case UPIO_AU:
	case UPIO_AU:
	case UPIO_DWAPB:
	case UPIO_DWAPB:
	case UPIO_DWAPB32:
		p->serial_out(p, offset, value);
		p->serial_out(p, offset, value);
		p->serial_in(p, UART_LCR);	/* safe, no side-effects */
		p->serial_in(p, UART_LCR);	/* safe, no side-effects */
		break;
		break;
@@ -1587,7 +1611,8 @@ static irqreturn_t serial8250_interrupt(int irq, void *dev_id)
			handled = 1;
			handled = 1;


			end = NULL;
			end = NULL;
		} else if (up->port.iotype == UPIO_DWAPB &&
		} else if ((up->port.iotype == UPIO_DWAPB ||
			    up->port.iotype == UPIO_DWAPB32) &&
			  (iir & UART_IIR_BUSY) == UART_IIR_BUSY) {
			  (iir & UART_IIR_BUSY) == UART_IIR_BUSY) {
			/* The DesignWare APB UART has an Busy Detect (0x07)
			/* The DesignWare APB UART has an Busy Detect (0x07)
			 * interrupt meaning an LCR write attempt occured while the
			 * interrupt meaning an LCR write attempt occured while the
@@ -2492,6 +2517,7 @@ static int serial8250_request_std_resource(struct uart_8250_port *up)
	case UPIO_MEM32:
	case UPIO_MEM32:
	case UPIO_MEM:
	case UPIO_MEM:
	case UPIO_DWAPB:
	case UPIO_DWAPB:
	case UPIO_DWAPB32:
		if (!up->port.mapbase)
		if (!up->port.mapbase)
			break;
			break;


@@ -2529,6 +2555,7 @@ static void serial8250_release_std_resource(struct uart_8250_port *up)
	case UPIO_MEM32:
	case UPIO_MEM32:
	case UPIO_MEM:
	case UPIO_MEM:
	case UPIO_DWAPB:
	case UPIO_DWAPB:
	case UPIO_DWAPB32:
		if (!up->port.mapbase)
		if (!up->port.mapbase)
			break;
			break;


+2 −0
Original line number Original line Diff line number Diff line
@@ -2135,6 +2135,7 @@ uart_report_port(struct uart_driver *drv, struct uart_port *port)
	case UPIO_AU:
	case UPIO_AU:
	case UPIO_TSI:
	case UPIO_TSI:
	case UPIO_DWAPB:
	case UPIO_DWAPB:
	case UPIO_DWAPB32:
		snprintf(address, sizeof(address),
		snprintf(address, sizeof(address),
			 "MMIO 0x%llx", (unsigned long long)port->mapbase);
			 "MMIO 0x%llx", (unsigned long long)port->mapbase);
		break;
		break;
@@ -2555,6 +2556,7 @@ int uart_match_port(struct uart_port *port1, struct uart_port *port2)
	case UPIO_AU:
	case UPIO_AU:
	case UPIO_TSI:
	case UPIO_TSI:
	case UPIO_DWAPB:
	case UPIO_DWAPB:
	case UPIO_DWAPB32:
		return (port1->mapbase == port2->mapbase);
		return (port1->mapbase == port2->mapbase);
	}
	}
	return 0;
	return 0;
+1 −0
Original line number Original line Diff line number Diff line
@@ -314,6 +314,7 @@ struct uart_port {
#define UPIO_TSI		(5)			/* Tsi108/109 type IO */
#define UPIO_TSI		(5)			/* Tsi108/109 type IO */
#define UPIO_DWAPB		(6)			/* DesignWare APB UART */
#define UPIO_DWAPB		(6)			/* DesignWare APB UART */
#define UPIO_RM9000		(7)			/* RM9000 type IO */
#define UPIO_RM9000		(7)			/* RM9000 type IO */
#define UPIO_DWAPB32		(8)			/* DesignWare APB UART (32 bit accesses) */


	unsigned int		read_status_mask;	/* driver specific */
	unsigned int		read_status_mask;	/* driver specific */
	unsigned int		ignore_status_mask;	/* driver specific */
	unsigned int		ignore_status_mask;	/* driver specific */