diff options
Diffstat (limited to 'drivers/tty/serial/8250/8250_dw.c')
-rw-r--r-- | drivers/tty/serial/8250/8250_dw.c | 257 |
1 files changed, 220 insertions, 37 deletions
diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c index 096d2ef48b32..db0e66f6dd0e 100644 --- a/drivers/tty/serial/8250/8250_dw.c +++ b/drivers/tty/serial/8250/8250_dw.c | |||
@@ -2,6 +2,7 @@ | |||
2 | * Synopsys DesignWare 8250 driver. | 2 | * Synopsys DesignWare 8250 driver. |
3 | * | 3 | * |
4 | * Copyright 2011 Picochip, Jamie Iles. | 4 | * Copyright 2011 Picochip, Jamie Iles. |
5 | * Copyright 2013 Intel Corporation | ||
5 | * | 6 | * |
6 | * This program is free software; you can redistribute it and/or modify | 7 | * This program is free software; you can redistribute it and/or modify |
7 | * it under the terms of the GNU General Public License as published by | 8 | * it under the terms of the GNU General Public License as published by |
@@ -24,6 +25,34 @@ | |||
24 | #include <linux/of_platform.h> | 25 | #include <linux/of_platform.h> |
25 | #include <linux/platform_device.h> | 26 | #include <linux/platform_device.h> |
26 | #include <linux/slab.h> | 27 | #include <linux/slab.h> |
28 | #include <linux/acpi.h> | ||
29 | |||
30 | #include "8250.h" | ||
31 | |||
32 | /* Offsets for the DesignWare specific registers */ | ||
33 | #define DW_UART_USR 0x1f /* UART Status Register */ | ||
34 | #define DW_UART_CPR 0xf4 /* Component Parameter Register */ | ||
35 | #define DW_UART_UCV 0xf8 /* UART Component Version */ | ||
36 | |||
37 | /* Intel Low Power Subsystem specific */ | ||
38 | #define LPSS_PRV_CLOCK_PARAMS 0x800 | ||
39 | |||
40 | /* Component Parameter Register bits */ | ||
41 | #define DW_UART_CPR_ABP_DATA_WIDTH (3 << 0) | ||
42 | #define DW_UART_CPR_AFCE_MODE (1 << 4) | ||
43 | #define DW_UART_CPR_THRE_MODE (1 << 5) | ||
44 | #define DW_UART_CPR_SIR_MODE (1 << 6) | ||
45 | #define DW_UART_CPR_SIR_LP_MODE (1 << 7) | ||
46 | #define DW_UART_CPR_ADDITIONAL_FEATURES (1 << 8) | ||
47 | #define DW_UART_CPR_FIFO_ACCESS (1 << 9) | ||
48 | #define DW_UART_CPR_FIFO_STAT (1 << 10) | ||
49 | #define DW_UART_CPR_SHADOW (1 << 11) | ||
50 | #define DW_UART_CPR_ENCODED_PARMS (1 << 12) | ||
51 | #define DW_UART_CPR_DMA_EXTRA (1 << 13) | ||
52 | #define DW_UART_CPR_FIFO_MODE (0xff << 16) | ||
53 | /* Helper for fifo size calculation */ | ||
54 | #define DW_UART_CPR_FIFO_SIZE(a) (((a >> 16) & 0xff) * 16) | ||
55 | |||
27 | 56 | ||
28 | struct dw8250_data { | 57 | struct dw8250_data { |
29 | int last_lcr; | 58 | int last_lcr; |
@@ -66,9 +95,6 @@ static unsigned int dw8250_serial_in32(struct uart_port *p, int offset) | |||
66 | return readl(p->membase + offset); | 95 | return readl(p->membase + offset); |
67 | } | 96 | } |
68 | 97 | ||
69 | /* Offset for the DesignWare's UART Status Register. */ | ||
70 | #define UART_USR 0x1f | ||
71 | |||
72 | static int dw8250_handle_irq(struct uart_port *p) | 98 | static int dw8250_handle_irq(struct uart_port *p) |
73 | { | 99 | { |
74 | struct dw8250_data *d = p->private_data; | 100 | struct dw8250_data *d = p->private_data; |
@@ -78,7 +104,7 @@ static int dw8250_handle_irq(struct uart_port *p) | |||
78 | return 1; | 104 | return 1; |
79 | } else if ((iir & UART_IIR_BUSY) == UART_IIR_BUSY) { | 105 | } else if ((iir & UART_IIR_BUSY) == UART_IIR_BUSY) { |
80 | /* Clear the USR and write the LCR again. */ | 106 | /* Clear the USR and write the LCR again. */ |
81 | (void)p->serial_in(p, UART_USR); | 107 | (void)p->serial_in(p, DW_UART_USR); |
82 | p->serial_out(p, UART_LCR, d->last_lcr); | 108 | p->serial_out(p, UART_LCR, d->last_lcr); |
83 | 109 | ||
84 | return 1; | 110 | return 1; |
@@ -87,61 +113,210 @@ static int dw8250_handle_irq(struct uart_port *p) | |||
87 | return 0; | 113 | return 0; |
88 | } | 114 | } |
89 | 115 | ||
116 | static int dw8250_probe_of(struct uart_port *p) | ||
117 | { | ||
118 | struct device_node *np = p->dev->of_node; | ||
119 | u32 val; | ||
120 | |||
121 | if (!of_property_read_u32(np, "reg-io-width", &val)) { | ||
122 | switch (val) { | ||
123 | case 1: | ||
124 | break; | ||
125 | case 4: | ||
126 | p->iotype = UPIO_MEM32; | ||
127 | p->serial_in = dw8250_serial_in32; | ||
128 | p->serial_out = dw8250_serial_out32; | ||
129 | break; | ||
130 | default: | ||
131 | dev_err(p->dev, "unsupported reg-io-width (%u)\n", val); | ||
132 | return -EINVAL; | ||
133 | } | ||
134 | } | ||
135 | |||
136 | if (!of_property_read_u32(np, "reg-shift", &val)) | ||
137 | p->regshift = val; | ||
138 | |||
139 | if (of_property_read_u32(np, "clock-frequency", &val)) { | ||
140 | dev_err(p->dev, "no clock-frequency property set\n"); | ||
141 | return -EINVAL; | ||
142 | } | ||
143 | p->uartclk = val; | ||
144 | |||
145 | return 0; | ||
146 | } | ||
147 | |||
148 | #ifdef CONFIG_ACPI | ||
149 | static bool dw8250_acpi_dma_filter(struct dma_chan *chan, void *parm) | ||
150 | { | ||
151 | return chan->chan_id == *(int *)parm; | ||
152 | } | ||
153 | |||
154 | static acpi_status | ||
155 | dw8250_acpi_walk_resource(struct acpi_resource *res, void *data) | ||
156 | { | ||
157 | struct uart_port *p = data; | ||
158 | struct uart_8250_port *port; | ||
159 | struct uart_8250_dma *dma; | ||
160 | struct acpi_resource_fixed_dma *fixed_dma; | ||
161 | struct dma_slave_config *slave; | ||
162 | |||
163 | port = container_of(p, struct uart_8250_port, port); | ||
164 | |||
165 | switch (res->type) { | ||
166 | case ACPI_RESOURCE_TYPE_FIXED_DMA: | ||
167 | fixed_dma = &res->data.fixed_dma; | ||
168 | |||
169 | /* TX comes first */ | ||
170 | if (!port->dma) { | ||
171 | dma = devm_kzalloc(p->dev, sizeof(*dma), GFP_KERNEL); | ||
172 | if (!dma) | ||
173 | return AE_NO_MEMORY; | ||
174 | |||
175 | port->dma = dma; | ||
176 | slave = &dma->txconf; | ||
177 | |||
178 | slave->direction = DMA_MEM_TO_DEV; | ||
179 | slave->dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; | ||
180 | slave->slave_id = fixed_dma->request_lines; | ||
181 | slave->dst_maxburst = port->tx_loadsz / 4; | ||
182 | |||
183 | dma->tx_chan_id = fixed_dma->channels; | ||
184 | dma->tx_param = &dma->tx_chan_id; | ||
185 | dma->fn = dw8250_acpi_dma_filter; | ||
186 | } else { | ||
187 | dma = port->dma; | ||
188 | slave = &dma->rxconf; | ||
189 | |||
190 | slave->direction = DMA_DEV_TO_MEM; | ||
191 | slave->src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; | ||
192 | slave->slave_id = fixed_dma->request_lines; | ||
193 | slave->src_maxburst = p->fifosize / 4; | ||
194 | |||
195 | dma->rx_chan_id = fixed_dma->channels; | ||
196 | dma->rx_param = &dma->rx_chan_id; | ||
197 | } | ||
198 | |||
199 | break; | ||
200 | } | ||
201 | |||
202 | return AE_OK; | ||
203 | } | ||
204 | |||
205 | static int dw8250_probe_acpi(struct uart_port *p) | ||
206 | { | ||
207 | const struct acpi_device_id *id; | ||
208 | acpi_status status; | ||
209 | u32 reg; | ||
210 | |||
211 | id = acpi_match_device(p->dev->driver->acpi_match_table, p->dev); | ||
212 | if (!id) | ||
213 | return -ENODEV; | ||
214 | |||
215 | p->iotype = UPIO_MEM32; | ||
216 | p->serial_in = dw8250_serial_in32; | ||
217 | p->serial_out = dw8250_serial_out32; | ||
218 | p->regshift = 2; | ||
219 | p->uartclk = (unsigned int)id->driver_data; | ||
220 | |||
221 | status = acpi_walk_resources(ACPI_HANDLE(p->dev), METHOD_NAME__CRS, | ||
222 | dw8250_acpi_walk_resource, p); | ||
223 | if (ACPI_FAILURE(status)) { | ||
224 | dev_err_ratelimited(p->dev, "%s failed \"%s\"\n", __func__, | ||
225 | acpi_format_exception(status)); | ||
226 | return -ENODEV; | ||
227 | } | ||
228 | |||
229 | /* Fix Haswell issue where the clocks do not get enabled */ | ||
230 | if (!strcmp(id->id, "INT33C4") || !strcmp(id->id, "INT33C5")) { | ||
231 | reg = readl(p->membase + LPSS_PRV_CLOCK_PARAMS); | ||
232 | writel(reg | 1, p->membase + LPSS_PRV_CLOCK_PARAMS); | ||
233 | } | ||
234 | |||
235 | return 0; | ||
236 | } | ||
237 | #else | ||
238 | static inline int dw8250_probe_acpi(struct uart_port *p) | ||
239 | { | ||
240 | return -ENODEV; | ||
241 | } | ||
242 | #endif /* CONFIG_ACPI */ | ||
243 | |||
244 | static void dw8250_setup_port(struct uart_8250_port *up) | ||
245 | { | ||
246 | struct uart_port *p = &up->port; | ||
247 | u32 reg = readl(p->membase + DW_UART_UCV); | ||
248 | |||
249 | /* | ||
250 | * If the Component Version Register returns zero, we know that | ||
251 | * ADDITIONAL_FEATURES are not enabled. No need to go any further. | ||
252 | */ | ||
253 | if (!reg) | ||
254 | return; | ||
255 | |||
256 | dev_dbg_ratelimited(p->dev, "Designware UART version %c.%c%c\n", | ||
257 | (reg >> 24) & 0xff, (reg >> 16) & 0xff, (reg >> 8) & 0xff); | ||
258 | |||
259 | reg = readl(p->membase + DW_UART_CPR); | ||
260 | if (!reg) | ||
261 | return; | ||
262 | |||
263 | /* Select the type based on fifo */ | ||
264 | if (reg & DW_UART_CPR_FIFO_MODE) { | ||
265 | p->type = PORT_16550A; | ||
266 | p->flags |= UPF_FIXED_TYPE; | ||
267 | p->fifosize = DW_UART_CPR_FIFO_SIZE(reg); | ||
268 | up->tx_loadsz = p->fifosize; | ||
269 | } | ||
270 | } | ||
271 | |||
90 | static int dw8250_probe(struct platform_device *pdev) | 272 | static int dw8250_probe(struct platform_device *pdev) |
91 | { | 273 | { |
92 | struct uart_8250_port uart = {}; | 274 | struct uart_8250_port uart = {}; |
93 | struct resource *regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 275 | struct resource *regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
94 | struct resource *irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); | 276 | struct resource *irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); |
95 | struct device_node *np = pdev->dev.of_node; | ||
96 | u32 val; | ||
97 | struct dw8250_data *data; | 277 | struct dw8250_data *data; |
278 | int err; | ||
98 | 279 | ||
99 | if (!regs || !irq) { | 280 | if (!regs || !irq) { |
100 | dev_err(&pdev->dev, "no registers/irq defined\n"); | 281 | dev_err(&pdev->dev, "no registers/irq defined\n"); |
101 | return -EINVAL; | 282 | return -EINVAL; |
102 | } | 283 | } |
103 | 284 | ||
104 | data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); | ||
105 | if (!data) | ||
106 | return -ENOMEM; | ||
107 | uart.port.private_data = data; | ||
108 | |||
109 | spin_lock_init(&uart.port.lock); | 285 | spin_lock_init(&uart.port.lock); |
110 | uart.port.mapbase = regs->start; | 286 | uart.port.mapbase = regs->start; |
111 | uart.port.irq = irq->start; | 287 | uart.port.irq = irq->start; |
112 | uart.port.handle_irq = dw8250_handle_irq; | 288 | uart.port.handle_irq = dw8250_handle_irq; |
113 | uart.port.type = PORT_8250; | 289 | uart.port.type = PORT_8250; |
114 | uart.port.flags = UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF | UPF_IOREMAP | | 290 | uart.port.flags = UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF | UPF_FIXED_PORT; |
115 | UPF_FIXED_PORT | UPF_FIXED_TYPE; | ||
116 | uart.port.dev = &pdev->dev; | 291 | uart.port.dev = &pdev->dev; |
117 | 292 | ||
293 | uart.port.membase = ioremap(regs->start, resource_size(regs)); | ||
294 | if (!uart.port.membase) | ||
295 | return -ENOMEM; | ||
296 | |||
118 | uart.port.iotype = UPIO_MEM; | 297 | uart.port.iotype = UPIO_MEM; |
119 | uart.port.serial_in = dw8250_serial_in; | 298 | uart.port.serial_in = dw8250_serial_in; |
120 | uart.port.serial_out = dw8250_serial_out; | 299 | uart.port.serial_out = dw8250_serial_out; |
121 | if (!of_property_read_u32(np, "reg-io-width", &val)) { | 300 | |
122 | switch (val) { | 301 | dw8250_setup_port(&uart); |
123 | case 1: | 302 | |
124 | break; | 303 | if (pdev->dev.of_node) { |
125 | case 4: | 304 | err = dw8250_probe_of(&uart.port); |
126 | uart.port.iotype = UPIO_MEM32; | 305 | if (err) |
127 | uart.port.serial_in = dw8250_serial_in32; | 306 | return err; |
128 | uart.port.serial_out = dw8250_serial_out32; | 307 | } else if (ACPI_HANDLE(&pdev->dev)) { |
129 | break; | 308 | err = dw8250_probe_acpi(&uart.port); |
130 | default: | 309 | if (err) |
131 | dev_err(&pdev->dev, "unsupported reg-io-width (%u)\n", | 310 | return err; |
132 | val); | 311 | } else { |
133 | return -EINVAL; | 312 | return -ENODEV; |
134 | } | ||
135 | } | 313 | } |
136 | 314 | ||
137 | if (!of_property_read_u32(np, "reg-shift", &val)) | 315 | data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); |
138 | uart.port.regshift = val; | 316 | if (!data) |
317 | return -ENOMEM; | ||
139 | 318 | ||
140 | if (of_property_read_u32(np, "clock-frequency", &val)) { | 319 | uart.port.private_data = data; |
141 | dev_err(&pdev->dev, "no clock-frequency property set\n"); | ||
142 | return -EINVAL; | ||
143 | } | ||
144 | uart.port.uartclk = val; | ||
145 | 320 | ||
146 | data->line = serial8250_register_8250_port(&uart); | 321 | data->line = serial8250_register_8250_port(&uart); |
147 | if (data->line < 0) | 322 | if (data->line < 0) |
@@ -184,17 +359,25 @@ static int dw8250_resume(struct platform_device *pdev) | |||
184 | #define dw8250_resume NULL | 359 | #define dw8250_resume NULL |
185 | #endif /* CONFIG_PM */ | 360 | #endif /* CONFIG_PM */ |
186 | 361 | ||
187 | static const struct of_device_id dw8250_match[] = { | 362 | static const struct of_device_id dw8250_of_match[] = { |
188 | { .compatible = "snps,dw-apb-uart" }, | 363 | { .compatible = "snps,dw-apb-uart" }, |
189 | { /* Sentinel */ } | 364 | { /* Sentinel */ } |
190 | }; | 365 | }; |
191 | MODULE_DEVICE_TABLE(of, dw8250_match); | 366 | MODULE_DEVICE_TABLE(of, dw8250_of_match); |
367 | |||
368 | static const struct acpi_device_id dw8250_acpi_match[] = { | ||
369 | { "INT33C4", 100000000 }, | ||
370 | { "INT33C5", 100000000 }, | ||
371 | { }, | ||
372 | }; | ||
373 | MODULE_DEVICE_TABLE(acpi, dw8250_acpi_match); | ||
192 | 374 | ||
193 | static struct platform_driver dw8250_platform_driver = { | 375 | static struct platform_driver dw8250_platform_driver = { |
194 | .driver = { | 376 | .driver = { |
195 | .name = "dw-apb-uart", | 377 | .name = "dw-apb-uart", |
196 | .owner = THIS_MODULE, | 378 | .owner = THIS_MODULE, |
197 | .of_match_table = dw8250_match, | 379 | .of_match_table = dw8250_of_match, |
380 | .acpi_match_table = ACPI_PTR(dw8250_acpi_match), | ||
198 | }, | 381 | }, |
199 | .probe = dw8250_probe, | 382 | .probe = dw8250_probe, |
200 | .remove = dw8250_remove, | 383 | .remove = dw8250_remove, |