diff options
author | David Daney <david.daney@cavium.com> | 2014-11-14 09:26:19 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2014-11-25 20:06:39 -0500 |
commit | bca2092d78970df3959462d2aae1941e6b24ebdf (patch) | |
tree | 488f13b304dae0359039fdc88ff8890085aeeff5 /drivers/tty | |
parent | 93d94b37fd044674e4e495bed82a45c38bde865a (diff) |
serial: 8250_dw: Use 64-bit access for OCTEON.
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>
Diffstat (limited to 'drivers/tty')
-rw-r--r-- | drivers/tty/serial/8250/8250_dw.c | 55 |
1 files changed, 41 insertions, 14 deletions
diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c index 18ff53298d2f..f4fd362f6da2 100644 --- a/drivers/tty/serial/8250/8250_dw.c +++ b/drivers/tty/serial/8250/8250_dw.c | |||
@@ -122,13 +122,44 @@ static unsigned int dw8250_serial_in(struct uart_port *p, int offset) | |||
122 | return dw8250_modify_msr(p, offset, value); | 122 | return dw8250_modify_msr(p, offset, value); |
123 | } | 123 | } |
124 | 124 | ||
125 | /* Read Back (rb) version to ensure register access ording. */ | 125 | #ifdef CONFIG_64BIT |
126 | static void dw8250_serial_out_rb(struct uart_port *p, int offset, int value) | 126 | static unsigned int dw8250_serial_inq(struct uart_port *p, int offset) |
127 | { | 127 | { |
128 | dw8250_serial_out(p, offset, value); | 128 | unsigned int value; |
129 | dw8250_serial_in(p, UART_LCR); | 129 | |
130 | value = (u8)__raw_readq(p->membase + (offset << p->regshift)); | ||
131 | |||
132 | return dw8250_modify_msr(p, offset, value); | ||
130 | } | 133 | } |
131 | 134 | ||
135 | static void dw8250_serial_outq(struct uart_port *p, int offset, int value) | ||
136 | { | ||
137 | struct dw8250_data *d = p->private_data; | ||
138 | |||
139 | if (offset == UART_MCR) | ||
140 | d->last_mcr = value; | ||
141 | |||
142 | value &= 0xff; | ||
143 | __raw_writeq(value, p->membase + (offset << p->regshift)); | ||
144 | /* Read back to ensure register write ordering. */ | ||
145 | __raw_readq(p->membase + (UART_LCR << p->regshift)); | ||
146 | |||
147 | /* Make sure LCR write wasn't ignored */ | ||
148 | if (offset == UART_LCR) { | ||
149 | int tries = 1000; | ||
150 | while (tries--) { | ||
151 | unsigned int lcr = p->serial_in(p, UART_LCR); | ||
152 | if ((value & ~UART_LCR_SPAR) == (lcr & ~UART_LCR_SPAR)) | ||
153 | return; | ||
154 | dw8250_force_idle(p); | ||
155 | __raw_writeq(value & 0xff, | ||
156 | p->membase + (UART_LCR << p->regshift)); | ||
157 | } | ||
158 | dev_err(p->dev, "Couldn't set LCR to %d\n", value); | ||
159 | } | ||
160 | } | ||
161 | #endif /* CONFIG_64BIT */ | ||
162 | |||
132 | static void dw8250_serial_out32(struct uart_port *p, int offset, int value) | 163 | static void dw8250_serial_out32(struct uart_port *p, int offset, int value) |
133 | { | 164 | { |
134 | struct dw8250_data *d = p->private_data; | 165 | struct dw8250_data *d = p->private_data; |
@@ -260,21 +291,17 @@ static int dw8250_probe_of(struct uart_port *p, | |||
260 | bool has_ucv = true; | 291 | bool has_ucv = true; |
261 | int id; | 292 | int id; |
262 | 293 | ||
294 | #ifdef CONFIG_64BIT | ||
263 | if (of_device_is_compatible(np, "cavium,octeon-3860-uart")) { | 295 | if (of_device_is_compatible(np, "cavium,octeon-3860-uart")) { |
264 | #ifdef __BIG_ENDIAN | 296 | p->serial_in = dw8250_serial_inq; |
265 | /* | 297 | p->serial_out = dw8250_serial_outq; |
266 | * Low order bits of these 64-bit registers, when | ||
267 | * accessed as a byte, are 7 bytes further down in the | ||
268 | * address space in big endian mode. | ||
269 | */ | ||
270 | p->membase += 7; | ||
271 | #endif | ||
272 | p->serial_out = dw8250_serial_out_rb; | ||
273 | p->flags = UPF_SKIP_TEST | UPF_SHARE_IRQ | UPF_FIXED_TYPE; | 298 | p->flags = UPF_SKIP_TEST | UPF_SHARE_IRQ | UPF_FIXED_TYPE; |
274 | p->type = PORT_OCTEON; | 299 | p->type = PORT_OCTEON; |
275 | data->usr_reg = 0x27; | 300 | data->usr_reg = 0x27; |
276 | has_ucv = false; | 301 | has_ucv = false; |
277 | } else if (!of_property_read_u32(np, "reg-io-width", &val)) { | 302 | } else |
303 | #endif | ||
304 | if (!of_property_read_u32(np, "reg-io-width", &val)) { | ||
278 | switch (val) { | 305 | switch (val) { |
279 | case 1: | 306 | case 1: |
280 | break; | 307 | break; |