diff options
author | Heikki Krogerus <heikki.krogerus@linux.intel.com> | 2013-01-10 04:25:12 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2013-01-16 02:03:00 -0500 |
commit | 7277b2a1c687b728a4ec0511d2ae076aed6ed5b4 (patch) | |
tree | e7274f6523a7cb4989cbabd338d32f4d2131b739 /drivers/tty/serial/8250/8250_dw.c | |
parent | 9ee4b83e51f741a645c43e61b9f3f8075ca0fdf4 (diff) |
serial: 8250_dw: Enable DMA support with ACPI
With ACPI 5.0 we can use the FixedDMA Resource Descriptor to
extract the needed information for DMA support.
Signed-off-by: Heikki Krogerus <heikki.krogerus@linux.intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/tty/serial/8250/8250_dw.c')
-rw-r--r-- | drivers/tty/serial/8250/8250_dw.c | 65 |
1 files changed, 65 insertions, 0 deletions
diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c index f6eeff02dced..ceacf5e36f2e 100644 --- a/drivers/tty/serial/8250/8250_dw.c +++ b/drivers/tty/serial/8250/8250_dw.c | |||
@@ -27,6 +27,8 @@ | |||
27 | #include <linux/slab.h> | 27 | #include <linux/slab.h> |
28 | #include <linux/acpi.h> | 28 | #include <linux/acpi.h> |
29 | 29 | ||
30 | #include "8250.h" | ||
31 | |||
30 | /* Offsets for the DesignWare specific registers */ | 32 | /* Offsets for the DesignWare specific registers */ |
31 | #define DW_UART_USR 0x1f /* UART Status Register */ | 33 | #define DW_UART_USR 0x1f /* UART Status Register */ |
32 | #define DW_UART_CPR 0xf4 /* Component Parameter Register */ | 34 | #define DW_UART_CPR 0xf4 /* Component Parameter Register */ |
@@ -143,9 +145,64 @@ static int dw8250_probe_of(struct uart_port *p) | |||
143 | return 0; | 145 | return 0; |
144 | } | 146 | } |
145 | 147 | ||
148 | static bool dw8250_acpi_dma_filter(struct dma_chan *chan, void *parm) | ||
149 | { | ||
150 | return chan->chan_id == *(int *)parm; | ||
151 | } | ||
152 | |||
153 | static acpi_status | ||
154 | dw8250_acpi_walk_resource(struct acpi_resource *res, void *data) | ||
155 | { | ||
156 | struct uart_port *p = data; | ||
157 | struct uart_8250_port *port; | ||
158 | struct uart_8250_dma *dma; | ||
159 | struct acpi_resource_fixed_dma *fixed_dma; | ||
160 | struct dma_slave_config *slave; | ||
161 | |||
162 | port = container_of(p, struct uart_8250_port, port); | ||
163 | |||
164 | switch (res->type) { | ||
165 | case ACPI_RESOURCE_TYPE_FIXED_DMA: | ||
166 | fixed_dma = &res->data.fixed_dma; | ||
167 | |||
168 | /* TX comes first */ | ||
169 | if (!port->dma) { | ||
170 | dma = devm_kzalloc(p->dev, sizeof(*dma), GFP_KERNEL); | ||
171 | if (!dma) | ||
172 | return AE_NO_MEMORY; | ||
173 | |||
174 | port->dma = dma; | ||
175 | slave = &dma->txconf; | ||
176 | |||
177 | slave->direction = DMA_MEM_TO_DEV; | ||
178 | slave->dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; | ||
179 | slave->slave_id = fixed_dma->request_lines; | ||
180 | |||
181 | dma->tx_chan_id = fixed_dma->channels; | ||
182 | dma->tx_param = &dma->tx_chan_id; | ||
183 | dma->fn = dw8250_acpi_dma_filter; | ||
184 | } else { | ||
185 | dma = port->dma; | ||
186 | slave = &dma->rxconf; | ||
187 | |||
188 | slave->direction = DMA_DEV_TO_MEM; | ||
189 | slave->src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; | ||
190 | slave->slave_id = fixed_dma->request_lines; | ||
191 | |||
192 | dma->rx_chan_id = fixed_dma->channels; | ||
193 | dma->rx_param = &dma->rx_chan_id; | ||
194 | } | ||
195 | |||
196 | break; | ||
197 | } | ||
198 | |||
199 | return AE_OK; | ||
200 | } | ||
201 | |||
146 | static int dw8250_probe_acpi(struct uart_port *p) | 202 | static int dw8250_probe_acpi(struct uart_port *p) |
147 | { | 203 | { |
148 | const struct acpi_device_id *id; | 204 | const struct acpi_device_id *id; |
205 | acpi_status status; | ||
149 | u32 reg; | 206 | u32 reg; |
150 | 207 | ||
151 | id = acpi_match_device(p->dev->driver->acpi_match_table, p->dev); | 208 | id = acpi_match_device(p->dev->driver->acpi_match_table, p->dev); |
@@ -158,6 +215,14 @@ static int dw8250_probe_acpi(struct uart_port *p) | |||
158 | p->regshift = 2; | 215 | p->regshift = 2; |
159 | p->uartclk = (unsigned int)id->driver_data; | 216 | p->uartclk = (unsigned int)id->driver_data; |
160 | 217 | ||
218 | status = acpi_walk_resources(ACPI_HANDLE(p->dev), METHOD_NAME__CRS, | ||
219 | dw8250_acpi_walk_resource, p); | ||
220 | if (ACPI_FAILURE(status)) { | ||
221 | dev_err_ratelimited(p->dev, "%s failed \"%s\"\n", __func__, | ||
222 | acpi_format_exception(status)); | ||
223 | return -ENODEV; | ||
224 | } | ||
225 | |||
161 | /* Fix Haswell issue where the clocks do not get enabled */ | 226 | /* Fix Haswell issue where the clocks do not get enabled */ |
162 | if (!strcmp(id->id, "INT33C4") || !strcmp(id->id, "INT33C5")) { | 227 | if (!strcmp(id->id, "INT33C4") || !strcmp(id->id, "INT33C5")) { |
163 | reg = readl(p->membase + LPSS_PRV_CLOCK_PARAMS); | 228 | reg = readl(p->membase + LPSS_PRV_CLOCK_PARAMS); |