Skip to content

Commit

Permalink
serial: 8250_dw: Use 64-bit access for OCTEON.
Browse files Browse the repository at this point in the history
Although the existing code appears to work on most hardware, the
hardware designers tell us that 8-bit access to the registers is not
guaranteed to be reliable.  Also the OCTEON simulation environments
prohibit 8-bit accesses.

For these reasons, we use __raw_readq/__raw_writeq for OCTEON.  This
code is protected with #ifdef CONFIG_64BIT so it still builds under
configurations lacking readq/writeq.

We can get rid of the #ifdef __BIG_ENDIAN, as under 64-bit accesses,
OCTEON is byte order invariant.

Signed-off-by: David Daney <david.daney@cavium.com>
Signed-off-by: Aleksey Makarov <aleksey.makarov@auriga.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
  • Loading branch information
David Daney authored and Greg Kroah-Hartman committed Nov 26, 2014
1 parent 93d94b3 commit bca2092
Showing 1 changed file with 41 additions and 14 deletions.
55 changes: 41 additions & 14 deletions drivers/tty/serial/8250/8250_dw.c
Original file line number Diff line number Diff line change
Expand Up @@ -122,13 +122,44 @@ static unsigned int dw8250_serial_in(struct uart_port *p, int offset)
return dw8250_modify_msr(p, offset, value);
}

/* Read Back (rb) version to ensure register access ording. */
static void dw8250_serial_out_rb(struct uart_port *p, int offset, int value)
#ifdef CONFIG_64BIT
static unsigned int dw8250_serial_inq(struct uart_port *p, int offset)
{
dw8250_serial_out(p, offset, value);
dw8250_serial_in(p, UART_LCR);
unsigned int value;

value = (u8)__raw_readq(p->membase + (offset << p->regshift));

return dw8250_modify_msr(p, offset, value);
}

static void dw8250_serial_outq(struct uart_port *p, int offset, int value)
{
struct dw8250_data *d = p->private_data;

if (offset == UART_MCR)
d->last_mcr = value;

value &= 0xff;
__raw_writeq(value, p->membase + (offset << p->regshift));
/* Read back to ensure register write ordering. */
__raw_readq(p->membase + (UART_LCR << p->regshift));

/* Make sure LCR write wasn't ignored */
if (offset == UART_LCR) {
int tries = 1000;
while (tries--) {
unsigned int lcr = p->serial_in(p, UART_LCR);
if ((value & ~UART_LCR_SPAR) == (lcr & ~UART_LCR_SPAR))
return;
dw8250_force_idle(p);
__raw_writeq(value & 0xff,
p->membase + (UART_LCR << p->regshift));
}
dev_err(p->dev, "Couldn't set LCR to %d\n", value);
}
}
#endif /* CONFIG_64BIT */

static void dw8250_serial_out32(struct uart_port *p, int offset, int value)
{
struct dw8250_data *d = p->private_data;
Expand Down Expand Up @@ -260,21 +291,17 @@ static int dw8250_probe_of(struct uart_port *p,
bool has_ucv = true;
int id;

#ifdef CONFIG_64BIT
if (of_device_is_compatible(np, "cavium,octeon-3860-uart")) {
#ifdef __BIG_ENDIAN
/*
* Low order bits of these 64-bit registers, when
* accessed as a byte, are 7 bytes further down in the
* address space in big endian mode.
*/
p->membase += 7;
#endif
p->serial_out = dw8250_serial_out_rb;
p->serial_in = dw8250_serial_inq;
p->serial_out = dw8250_serial_outq;
p->flags = UPF_SKIP_TEST | UPF_SHARE_IRQ | UPF_FIXED_TYPE;
p->type = PORT_OCTEON;
data->usr_reg = 0x27;
has_ucv = false;
} else if (!of_property_read_u32(np, "reg-io-width", &val)) {
} else
#endif
if (!of_property_read_u32(np, "reg-io-width", &val)) {
switch (val) {
case 1:
break;
Expand Down

0 comments on commit bca2092

Please sign in to comment.