diff options
| -rw-r--r-- | drivers/tty/serial/8250/8250_dw.c | 108 |
1 files changed, 69 insertions, 39 deletions
diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c index d07b6af3a937..76a8daadff47 100644 --- a/drivers/tty/serial/8250/8250_dw.c +++ b/drivers/tty/serial/8250/8250_dw.c | |||
| @@ -29,6 +29,8 @@ | |||
| 29 | #include <linux/clk.h> | 29 | #include <linux/clk.h> |
| 30 | #include <linux/pm_runtime.h> | 30 | #include <linux/pm_runtime.h> |
| 31 | 31 | ||
| 32 | #include <asm/byteorder.h> | ||
| 33 | |||
| 32 | #include "8250.h" | 34 | #include "8250.h" |
| 33 | 35 | ||
| 34 | /* Offsets for the DesignWare specific registers */ | 36 | /* Offsets for the DesignWare specific registers */ |
| @@ -57,6 +59,7 @@ struct dw8250_data { | |||
| 57 | int last_lcr; | 59 | int last_lcr; |
| 58 | int line; | 60 | int line; |
| 59 | struct clk *clk; | 61 | struct clk *clk; |
| 62 | u8 usr_reg; | ||
| 60 | }; | 63 | }; |
| 61 | 64 | ||
| 62 | static void dw8250_serial_out(struct uart_port *p, int offset, int value) | 65 | static void dw8250_serial_out(struct uart_port *p, int offset, int value) |
| @@ -77,6 +80,13 @@ static unsigned int dw8250_serial_in(struct uart_port *p, int offset) | |||
| 77 | return readb(p->membase + offset); | 80 | return readb(p->membase + offset); |
| 78 | } | 81 | } |
| 79 | 82 | ||
| 83 | /* Read Back (rb) version to ensure register access ording. */ | ||
| 84 | static void dw8250_serial_out_rb(struct uart_port *p, int offset, int value) | ||
| 85 | { | ||
| 86 | dw8250_serial_out(p, offset, value); | ||
| 87 | dw8250_serial_in(p, UART_LCR); | ||
| 88 | } | ||
| 89 | |||
| 80 | static void dw8250_serial_out32(struct uart_port *p, int offset, int value) | 90 | static void dw8250_serial_out32(struct uart_port *p, int offset, int value) |
| 81 | { | 91 | { |
| 82 | struct dw8250_data *d = p->private_data; | 92 | struct dw8250_data *d = p->private_data; |
| @@ -104,7 +114,7 @@ static int dw8250_handle_irq(struct uart_port *p) | |||
| 104 | return 1; | 114 | return 1; |
| 105 | } else if ((iir & UART_IIR_BUSY) == UART_IIR_BUSY) { | 115 | } else if ((iir & UART_IIR_BUSY) == UART_IIR_BUSY) { |
| 106 | /* Clear the USR and write the LCR again. */ | 116 | /* Clear the USR and write the LCR again. */ |
| 107 | (void)p->serial_in(p, DW_UART_USR); | 117 | (void)p->serial_in(p, d->usr_reg); |
| 108 | p->serial_out(p, UART_LCR, d->last_lcr); | 118 | p->serial_out(p, UART_LCR, d->last_lcr); |
| 109 | 119 | ||
| 110 | return 1; | 120 | return 1; |
| @@ -125,12 +135,60 @@ dw8250_do_pm(struct uart_port *port, unsigned int state, unsigned int old) | |||
| 125 | pm_runtime_put_sync_suspend(port->dev); | 135 | pm_runtime_put_sync_suspend(port->dev); |
| 126 | } | 136 | } |
| 127 | 137 | ||
| 128 | static int dw8250_probe_of(struct uart_port *p) | 138 | static void dw8250_setup_port(struct uart_8250_port *up) |
| 139 | { | ||
| 140 | struct uart_port *p = &up->port; | ||
| 141 | u32 reg = readl(p->membase + DW_UART_UCV); | ||
| 142 | |||
| 143 | /* | ||
| 144 | * If the Component Version Register returns zero, we know that | ||
| 145 | * ADDITIONAL_FEATURES are not enabled. No need to go any further. | ||
| 146 | */ | ||
| 147 | if (!reg) | ||
| 148 | return; | ||
| 149 | |||
| 150 | dev_dbg_ratelimited(p->dev, "Designware UART version %c.%c%c\n", | ||
| 151 | (reg >> 24) & 0xff, (reg >> 16) & 0xff, (reg >> 8) & 0xff); | ||
| 152 | |||
| 153 | reg = readl(p->membase + DW_UART_CPR); | ||
| 154 | if (!reg) | ||
| 155 | return; | ||
| 156 | |||
| 157 | /* Select the type based on fifo */ | ||
| 158 | if (reg & DW_UART_CPR_FIFO_MODE) { | ||
| 159 | p->type = PORT_16550A; | ||
| 160 | p->flags |= UPF_FIXED_TYPE; | ||
| 161 | p->fifosize = DW_UART_CPR_FIFO_SIZE(reg); | ||
| 162 | up->tx_loadsz = p->fifosize; | ||
| 163 | up->capabilities = UART_CAP_FIFO; | ||
| 164 | } | ||
| 165 | |||
| 166 | if (reg & DW_UART_CPR_AFCE_MODE) | ||
| 167 | up->capabilities |= UART_CAP_AFE; | ||
| 168 | } | ||
| 169 | |||
| 170 | static int dw8250_probe_of(struct uart_port *p, | ||
| 171 | struct dw8250_data *data) | ||
| 129 | { | 172 | { |
| 130 | struct device_node *np = p->dev->of_node; | 173 | struct device_node *np = p->dev->of_node; |
| 131 | u32 val; | 174 | u32 val; |
| 132 | 175 | bool has_ucv = true; | |
| 133 | if (!of_property_read_u32(np, "reg-io-width", &val)) { | 176 | |
| 177 | if (of_device_is_compatible(np, "cavium,octeon-3860-uart")) { | ||
| 178 | #ifdef __BIG_ENDIAN | ||
| 179 | /* | ||
| 180 | * Low order bits of these 64-bit registers, when | ||
| 181 | * accessed as a byte, are 7 bytes further down in the | ||
| 182 | * address space in big endian mode. | ||
| 183 | */ | ||
| 184 | p->membase += 7; | ||
| 185 | #endif | ||
| 186 | p->serial_out = dw8250_serial_out_rb; | ||
| 187 | p->flags = ASYNC_SKIP_TEST | UPF_SHARE_IRQ | UPF_FIXED_TYPE; | ||
| 188 | p->type = PORT_OCTEON; | ||
| 189 | data->usr_reg = 0x27; | ||
| 190 | has_ucv = false; | ||
| 191 | } else if (!of_property_read_u32(np, "reg-io-width", &val)) { | ||
| 134 | switch (val) { | 192 | switch (val) { |
| 135 | case 1: | 193 | case 1: |
| 136 | break; | 194 | break; |
| @@ -144,6 +202,8 @@ static int dw8250_probe_of(struct uart_port *p) | |||
| 144 | return -EINVAL; | 202 | return -EINVAL; |
| 145 | } | 203 | } |
| 146 | } | 204 | } |
| 205 | if (has_ucv) | ||
| 206 | dw8250_setup_port(container_of(p, struct uart_8250_port, port)); | ||
| 147 | 207 | ||
| 148 | if (!of_property_read_u32(np, "reg-shift", &val)) | 208 | if (!of_property_read_u32(np, "reg-shift", &val)) |
| 149 | p->regshift = val; | 209 | p->regshift = val; |
| @@ -168,6 +228,8 @@ static int dw8250_probe_acpi(struct uart_8250_port *up) | |||
| 168 | const struct acpi_device_id *id; | 228 | const struct acpi_device_id *id; |
| 169 | struct uart_port *p = &up->port; | 229 | struct uart_port *p = &up->port; |
| 170 | 230 | ||
| 231 | dw8250_setup_port(up); | ||
| 232 | |||
| 171 | id = acpi_match_device(p->dev->driver->acpi_match_table, p->dev); | 233 | id = acpi_match_device(p->dev->driver->acpi_match_table, p->dev); |
| 172 | if (!id) | 234 | if (!id) |
| 173 | return -ENODEV; | 235 | return -ENODEV; |
| @@ -196,38 +258,6 @@ static inline int dw8250_probe_acpi(struct uart_8250_port *up) | |||
| 196 | } | 258 | } |
| 197 | #endif /* CONFIG_ACPI */ | 259 | #endif /* CONFIG_ACPI */ |
| 198 | 260 | ||
| 199 | static void dw8250_setup_port(struct uart_8250_port *up) | ||
| 200 | { | ||
| 201 | struct uart_port *p = &up->port; | ||
| 202 | u32 reg = readl(p->membase + DW_UART_UCV); | ||
| 203 | |||
| 204 | /* | ||
| 205 | * If the Component Version Register returns zero, we know that | ||
| 206 | * ADDITIONAL_FEATURES are not enabled. No need to go any further. | ||
| 207 | */ | ||
| 208 | if (!reg) | ||
| 209 | return; | ||
| 210 | |||
| 211 | dev_dbg_ratelimited(p->dev, "Designware UART version %c.%c%c\n", | ||
| 212 | (reg >> 24) & 0xff, (reg >> 16) & 0xff, (reg >> 8) & 0xff); | ||
| 213 | |||
| 214 | reg = readl(p->membase + DW_UART_CPR); | ||
| 215 | if (!reg) | ||
| 216 | return; | ||
| 217 | |||
| 218 | /* Select the type based on fifo */ | ||
| 219 | if (reg & DW_UART_CPR_FIFO_MODE) { | ||
| 220 | p->type = PORT_16550A; | ||
| 221 | p->flags |= UPF_FIXED_TYPE; | ||
| 222 | p->fifosize = DW_UART_CPR_FIFO_SIZE(reg); | ||
| 223 | up->tx_loadsz = p->fifosize; | ||
| 224 | up->capabilities = UART_CAP_FIFO; | ||
| 225 | } | ||
| 226 | |||
| 227 | if (reg & DW_UART_CPR_AFCE_MODE) | ||
| 228 | up->capabilities |= UART_CAP_AFE; | ||
| 229 | } | ||
| 230 | |||
| 231 | static int dw8250_probe(struct platform_device *pdev) | 261 | static int dw8250_probe(struct platform_device *pdev) |
| 232 | { | 262 | { |
| 233 | struct uart_8250_port uart = {}; | 263 | struct uart_8250_port uart = {}; |
| @@ -259,6 +289,7 @@ static int dw8250_probe(struct platform_device *pdev) | |||
| 259 | if (!data) | 289 | if (!data) |
| 260 | return -ENOMEM; | 290 | return -ENOMEM; |
| 261 | 291 | ||
| 292 | data->usr_reg = DW_UART_USR; | ||
| 262 | data->clk = devm_clk_get(&pdev->dev, NULL); | 293 | data->clk = devm_clk_get(&pdev->dev, NULL); |
| 263 | if (!IS_ERR(data->clk)) { | 294 | if (!IS_ERR(data->clk)) { |
| 264 | clk_prepare_enable(data->clk); | 295 | clk_prepare_enable(data->clk); |
| @@ -270,10 +301,8 @@ static int dw8250_probe(struct platform_device *pdev) | |||
| 270 | |||
