| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * Copyright (c) 2012 Samsung Electronics Co., Ltd. |
|---|
| 3 | 4 | * http://www.samsung.com |
|---|
| 4 | 5 | * |
|---|
| 5 | 6 | * Copyright (C) 2010 Samsung Electronics Co. Ltd. |
|---|
| 6 | 7 | * Jaswinder Singh <jassi.brar@samsung.com> |
|---|
| 7 | | - * |
|---|
| 8 | | - * This program is free software; you can redistribute it and/or modify |
|---|
| 9 | | - * it under the terms of the GNU General Public License as published by |
|---|
| 10 | | - * the Free Software Foundation; either version 2 of the License, or |
|---|
| 11 | | - * (at your option) any later version. |
|---|
| 12 | 8 | */ |
|---|
| 13 | 9 | |
|---|
| 10 | +#include <linux/debugfs.h> |
|---|
| 14 | 11 | #include <linux/kernel.h> |
|---|
| 15 | 12 | #include <linux/io.h> |
|---|
| 16 | 13 | #include <linux/init.h> |
|---|
| .. | .. |
|---|
| 28 | 25 | #include <linux/err.h> |
|---|
| 29 | 26 | #include <linux/pm_runtime.h> |
|---|
| 30 | 27 | #include <linux/bug.h> |
|---|
| 28 | +#include <linux/reset.h> |
|---|
| 31 | 29 | |
|---|
| 32 | 30 | #include "dmaengine.h" |
|---|
| 33 | 31 | #define PL330_MAX_CHAN 8 |
|---|
| .. | .. |
|---|
| 37 | 35 | |
|---|
| 38 | 36 | #define PL330_QUIRK_BROKEN_NO_FLUSHP BIT(0) |
|---|
| 39 | 37 | #define PL330_QUIRK_PERIPH_BURST BIT(1) |
|---|
| 40 | | - |
|---|
| 41 | | -#ifdef CONFIG_CPU_RV1126 |
|---|
| 42 | | -#undef writel |
|---|
| 43 | | -#define writel(v, c) \ |
|---|
| 44 | | - do { \ |
|---|
| 45 | | - readl_relaxed(c); \ |
|---|
| 46 | | - __iowmb(); \ |
|---|
| 47 | | - writel_relaxed(v, c); \ |
|---|
| 48 | | - } while (0) |
|---|
| 49 | | -#endif |
|---|
| 50 | 38 | |
|---|
| 51 | 39 | enum pl330_cachectrl { |
|---|
| 52 | 40 | CCTRL0, /* Noncacheable and nonbufferable */ |
|---|
| .. | .. |
|---|
| 268 | 256 | static unsigned cmd_line; |
|---|
| 269 | 257 | #define PL330_DBGCMD_DUMP(off, x...) do { \ |
|---|
| 270 | 258 | printk("%x:", cmd_line); \ |
|---|
| 271 | | - printk(x); \ |
|---|
| 259 | + printk(KERN_CONT x); \ |
|---|
| 272 | 260 | cmd_line += off; \ |
|---|
| 273 | 261 | } while (0) |
|---|
| 274 | 262 | #define PL330_DBGMC_START(addr) (cmd_line = addr) |
|---|
| .. | .. |
|---|
| 298 | 286 | u32 irq_ns; |
|---|
| 299 | 287 | }; |
|---|
| 300 | 288 | |
|---|
| 301 | | -/** |
|---|
| 289 | +/* |
|---|
| 302 | 290 | * Request Configuration. |
|---|
| 303 | 291 | * The PL330 core does not modify this and uses the last |
|---|
| 304 | 292 | * working configuration if the request doesn't provide any. |
|---|
| .. | .. |
|---|
| 460 | 448 | /* DMA-mapped view of the FIFO; may differ if an IOMMU is present */ |
|---|
| 461 | 449 | dma_addr_t fifo_dma; |
|---|
| 462 | 450 | enum dma_data_direction dir; |
|---|
| 463 | | - unsigned int src_interlace_size; |
|---|
| 464 | | - unsigned int dst_interlace_size; |
|---|
| 451 | + struct dma_slave_config slave_config; |
|---|
| 465 | 452 | |
|---|
| 466 | 453 | /* for runtime pm tracking */ |
|---|
| 467 | 454 | bool active; |
|---|
| .. | .. |
|---|
| 470 | 457 | struct pl330_dmac { |
|---|
| 471 | 458 | /* DMA-Engine Device */ |
|---|
| 472 | 459 | struct dma_device ddma; |
|---|
| 473 | | - |
|---|
| 474 | | - /* Holds info about sg limitations */ |
|---|
| 475 | | - struct device_dma_parameters dma_parms; |
|---|
| 476 | 460 | |
|---|
| 477 | 461 | /* Pool of descriptors available for the DMAC's channels */ |
|---|
| 478 | 462 | struct list_head desc_pool; |
|---|
| .. | .. |
|---|
| 509 | 493 | unsigned int num_peripherals; |
|---|
| 510 | 494 | struct dma_pl330_chan *peripherals; /* keep at end */ |
|---|
| 511 | 495 | int quirks; |
|---|
| 496 | + |
|---|
| 497 | + struct reset_control *rstc; |
|---|
| 498 | + struct reset_control *rstc_ocp; |
|---|
| 512 | 499 | }; |
|---|
| 513 | 500 | |
|---|
| 514 | 501 | static struct pl330_of_quirks { |
|---|
| .. | .. |
|---|
| 554 | 541 | /* For cyclic capability */ |
|---|
| 555 | 542 | bool cyclic; |
|---|
| 556 | 543 | size_t num_periods; |
|---|
| 544 | +#ifdef CONFIG_NO_GKI |
|---|
| 557 | 545 | /* interlace size */ |
|---|
| 558 | 546 | unsigned int src_interlace_size; |
|---|
| 559 | 547 | unsigned int dst_interlace_size; |
|---|
| 548 | +#endif |
|---|
| 560 | 549 | }; |
|---|
| 561 | 550 | |
|---|
| 562 | 551 | struct _xfer_spec { |
|---|
| 563 | 552 | u32 ccr; |
|---|
| 564 | 553 | struct dma_pl330_desc *desc; |
|---|
| 565 | 554 | }; |
|---|
| 555 | + |
|---|
| 556 | +static int pl330_config_write(struct dma_chan *chan, |
|---|
| 557 | + struct dma_slave_config *slave_config, |
|---|
| 558 | + enum dma_transfer_direction direction); |
|---|
| 566 | 559 | |
|---|
| 567 | 560 | static inline bool _queue_full(struct pl330_thread *thrd) |
|---|
| 568 | 561 | { |
|---|
| .. | .. |
|---|
| 1088 | 1081 | |
|---|
| 1089 | 1082 | if (_state(thrd) == PL330_STATE_KILLING) |
|---|
| 1090 | 1083 | UNTIL(thrd, PL330_STATE_STOPPED) |
|---|
| 1091 | | - /* fall through */ |
|---|
| 1084 | + fallthrough; |
|---|
| 1092 | 1085 | |
|---|
| 1093 | 1086 | case PL330_STATE_FAULTING: |
|---|
| 1094 | 1087 | _stop(thrd); |
|---|
| 1095 | | - /* fall through */ |
|---|
| 1088 | + fallthrough; |
|---|
| 1096 | 1089 | |
|---|
| 1097 | 1090 | case PL330_STATE_KILLING: |
|---|
| 1098 | 1091 | case PL330_STATE_COMPLETING: |
|---|
| 1099 | 1092 | UNTIL(thrd, PL330_STATE_STOPPED) |
|---|
| 1100 | | - /* fall through */ |
|---|
| 1093 | + fallthrough; |
|---|
| 1101 | 1094 | |
|---|
| 1102 | 1095 | case PL330_STATE_STOPPED: |
|---|
| 1103 | 1096 | return _trigger(thrd); |
|---|
| .. | .. |
|---|
| 1148 | 1141 | |
|---|
| 1149 | 1142 | switch (direction) { |
|---|
| 1150 | 1143 | case DMA_MEM_TO_MEM: |
|---|
| 1151 | | - /* fall through */ |
|---|
| 1152 | 1144 | case DMA_MEM_TO_DEV: |
|---|
| 1153 | 1145 | off += _emit_LD(dry_run, &buf[off], cond); |
|---|
| 1154 | 1146 | break; |
|---|
| .. | .. |
|---|
| 1182 | 1174 | |
|---|
| 1183 | 1175 | switch (direction) { |
|---|
| 1184 | 1176 | case DMA_MEM_TO_MEM: |
|---|
| 1185 | | - /* fall through */ |
|---|
| 1186 | 1177 | case DMA_DEV_TO_MEM: |
|---|
| 1187 | 1178 | off += _emit_ST(dry_run, &buf[off], cond); |
|---|
| 1188 | 1179 | break; |
|---|
| .. | .. |
|---|
| 1227 | 1218 | pxs->desc->peri); |
|---|
| 1228 | 1219 | off += _emit_store(dry_run, &buf[off], cond, pxs->desc->rqtype, |
|---|
| 1229 | 1220 | pxs->desc->peri); |
|---|
| 1221 | +#ifdef CONFIG_NO_GKI |
|---|
| 1230 | 1222 | switch (pxs->desc->rqtype) { |
|---|
| 1231 | 1223 | case DMA_DEV_TO_MEM: |
|---|
| 1224 | + |
|---|
| 1232 | 1225 | if (pxs->desc->dst_interlace_size) |
|---|
| 1233 | 1226 | off += _emit_ADDH(dry_run, &buf[off], DST, |
|---|
| 1234 | 1227 | pxs->desc->dst_interlace_size); |
|---|
| .. | .. |
|---|
| 1242 | 1235 | WARN_ON(1); |
|---|
| 1243 | 1236 | break; |
|---|
| 1244 | 1237 | } |
|---|
| 1238 | +#endif |
|---|
| 1245 | 1239 | } |
|---|
| 1246 | 1240 | |
|---|
| 1247 | 1241 | return off; |
|---|
| .. | .. |
|---|
| 1258 | 1252 | |
|---|
| 1259 | 1253 | switch (pxs->desc->rqtype) { |
|---|
| 1260 | 1254 | case DMA_MEM_TO_DEV: |
|---|
| 1261 | | - /* fall through */ |
|---|
| 1262 | 1255 | case DMA_DEV_TO_MEM: |
|---|
| 1263 | 1256 | off += _ldst_peripheral(pl330, dry_run, &buf[off], pxs, cyc, |
|---|
| 1264 | 1257 | cond); |
|---|
| .. | .. |
|---|
| 1293 | 1286 | |
|---|
| 1294 | 1287 | switch (pxs->desc->rqtype) { |
|---|
| 1295 | 1288 | case DMA_MEM_TO_DEV: |
|---|
| 1296 | | - /* fall through */ |
|---|
| 1289 | + fallthrough; |
|---|
| 1297 | 1290 | case DMA_DEV_TO_MEM: |
|---|
| 1298 | 1291 | /* |
|---|
| 1299 | 1292 | * dregs_len = (total bytes - BURST_TO_BYTE(bursts, ccr)) / |
|---|
| .. | .. |
|---|
| 1457 | 1450 | off += _emit_LPEND(dry_run, &buf[off], &lpend); |
|---|
| 1458 | 1451 | } |
|---|
| 1459 | 1452 | |
|---|
| 1453 | +#ifdef CONFIG_NO_GKI |
|---|
| 1460 | 1454 | if (!pxs->desc->src_interlace_size && |
|---|
| 1461 | 1455 | !pxs->desc->dst_interlace_size) { |
|---|
| 1462 | 1456 | num_dregs = BYTE_MOD_BURST_LEN(x->bytes, pxs->ccr); |
|---|
| .. | .. |
|---|
| 1466 | 1460 | off += _emit_MOV(dry_run, &buf[off], CCR, pxs->ccr); |
|---|
| 1467 | 1461 | } |
|---|
| 1468 | 1462 | } |
|---|
| 1463 | +#else |
|---|
| 1464 | + num_dregs = BYTE_MOD_BURST_LEN(x->bytes, pxs->ccr); |
|---|
| 1465 | + |
|---|
| 1466 | + if (num_dregs) { |
|---|
| 1467 | + off += _dregs(pl330, dry_run, &buf[off], pxs, num_dregs); |
|---|
| 1468 | + off += _emit_MOV(dry_run, &buf[off], CCR, pxs->ccr); |
|---|
| 1469 | + } |
|---|
| 1470 | +#endif |
|---|
| 1469 | 1471 | |
|---|
| 1470 | 1472 | off += _emit_SEV(dry_run, &buf[off], ev); |
|---|
| 1471 | 1473 | |
|---|
| .. | .. |
|---|
| 1533 | 1535 | BRST_SIZE(ccr); |
|---|
| 1534 | 1536 | int off = 0; |
|---|
| 1535 | 1537 | |
|---|
| 1538 | +#ifdef CONFIG_NO_GKI |
|---|
| 1536 | 1539 | if (pxs->desc->rqtype == DMA_DEV_TO_MEM) |
|---|
| 1537 | 1540 | bursts = x->bytes / (BRST_SIZE(ccr) * BRST_LEN(ccr) + |
|---|
| 1538 | 1541 | pxs->desc->dst_interlace_size); |
|---|
| 1539 | 1542 | else if (pxs->desc->rqtype == DMA_MEM_TO_DEV) |
|---|
| 1540 | 1543 | bursts = x->bytes / (BRST_SIZE(ccr) * BRST_LEN(ccr) + |
|---|
| 1541 | 1544 | pxs->desc->src_interlace_size); |
|---|
| 1545 | +#endif |
|---|
| 1542 | 1546 | while (bursts) { |
|---|
| 1543 | 1547 | c = bursts; |
|---|
| 1544 | 1548 | off += _loop(pl330, dry_run, &buf[off], &c, pxs); |
|---|
| 1545 | 1549 | bursts -= c; |
|---|
| 1546 | 1550 | } |
|---|
| 1551 | +#ifdef CONFIG_NO_GKI |
|---|
| 1547 | 1552 | if (!pxs->desc->src_interlace_size && |
|---|
| 1548 | 1553 | !pxs->desc->dst_interlace_size) |
|---|
| 1549 | 1554 | off += _dregs(pl330, dry_run, &buf[off], pxs, num_dregs); |
|---|
| 1550 | | - |
|---|
| 1555 | +#else |
|---|
| 1556 | + off += _dregs(pl330, dry_run, &buf[off], pxs, num_dregs); |
|---|
| 1557 | +#endif |
|---|
| 1551 | 1558 | return off; |
|---|
| 1552 | 1559 | } |
|---|
| 1553 | 1560 | |
|---|
| .. | .. |
|---|
| 1578 | 1585 | unsigned long bursts = BYTE_TO_BURST(x->bytes, ccr); |
|---|
| 1579 | 1586 | int off = 0; |
|---|
| 1580 | 1587 | |
|---|
| 1588 | +#ifdef CONFIG_NO_GKI |
|---|
| 1581 | 1589 | if (pxs->desc->rqtype == DMA_DEV_TO_MEM) |
|---|
| 1582 | 1590 | bursts = x->bytes / (BRST_SIZE(ccr) * BRST_LEN(ccr) |
|---|
| 1583 | 1591 | + pxs->desc->dst_interlace_size); |
|---|
| 1584 | 1592 | else if (pxs->desc->rqtype == DMA_MEM_TO_DEV) |
|---|
| 1585 | 1593 | bursts = x->bytes / (BRST_SIZE(ccr) * BRST_LEN(ccr) |
|---|
| 1586 | 1594 | + pxs->desc->src_interlace_size); |
|---|
| 1595 | +#endif |
|---|
| 1587 | 1596 | /* Setup Loop(s) */ |
|---|
| 1588 | 1597 | off += _loop_cyclic(pl330, dry_run, &buf[off], bursts, pxs, ev); |
|---|
| 1589 | 1598 | |
|---|
| .. | .. |
|---|
| 1767 | 1776 | tasklet_schedule(&pch->task); |
|---|
| 1768 | 1777 | } |
|---|
| 1769 | 1778 | |
|---|
| 1770 | | -static void pl330_dotask(unsigned long data) |
|---|
| 1779 | +static void pl330_dotask(struct tasklet_struct *t) |
|---|
| 1771 | 1780 | { |
|---|
| 1772 | | - struct pl330_dmac *pl330 = (struct pl330_dmac *) data; |
|---|
| 1781 | + struct pl330_dmac *pl330 = from_tasklet(pl330, t, tasks); |
|---|
| 1773 | 1782 | unsigned long flags; |
|---|
| 1774 | 1783 | int i; |
|---|
| 1775 | 1784 | |
|---|
| .. | .. |
|---|
| 2126 | 2135 | if (ret) { |
|---|
| 2127 | 2136 | dev_err(pl330->ddma.dev, "%s:%d Can't to create channels for DMAC!\n", |
|---|
| 2128 | 2137 | __func__, __LINE__); |
|---|
| 2129 | | - dma_free_coherent(pl330->ddma.dev, |
|---|
| 2138 | + dma_free_attrs(pl330->ddma.dev, |
|---|
| 2130 | 2139 | chans * pl330->mcbufsz, |
|---|
| 2131 | | - pl330->mcode_cpu, pl330->mcode_bus); |
|---|
| 2140 | + pl330->mcode_cpu, pl330->mcode_bus, |
|---|
| 2141 | + DMA_ATTR_PRIVILEGED); |
|---|
| 2132 | 2142 | return ret; |
|---|
| 2133 | 2143 | } |
|---|
| 2134 | 2144 | |
|---|
| .. | .. |
|---|
| 2174 | 2184 | return ret; |
|---|
| 2175 | 2185 | } |
|---|
| 2176 | 2186 | |
|---|
| 2177 | | - tasklet_init(&pl330->tasks, pl330_dotask, (unsigned long) pl330); |
|---|
| 2187 | + tasklet_setup(&pl330->tasks, pl330_dotask); |
|---|
| 2178 | 2188 | |
|---|
| 2179 | 2189 | pl330->state = INIT; |
|---|
| 2180 | 2190 | |
|---|
| .. | .. |
|---|
| 2207 | 2217 | /* Free DMAC resources */ |
|---|
| 2208 | 2218 | dmac_free_threads(pl330); |
|---|
| 2209 | 2219 | |
|---|
| 2210 | | - dma_free_coherent(pl330->ddma.dev, |
|---|
| 2220 | + dma_free_attrs(pl330->ddma.dev, |
|---|
| 2211 | 2221 | pl330->pcfg.num_chan * pl330->mcbufsz, pl330->mcode_cpu, |
|---|
| 2212 | | - pl330->mcode_bus); |
|---|
| 2222 | + pl330->mcode_bus, DMA_ATTR_PRIVILEGED); |
|---|
| 2213 | 2223 | } |
|---|
| 2214 | 2224 | |
|---|
| 2215 | 2225 | /* forward declaration */ |
|---|
| .. | .. |
|---|
| 2257 | 2267 | } |
|---|
| 2258 | 2268 | } |
|---|
| 2259 | 2269 | |
|---|
| 2260 | | -static void pl330_tasklet(unsigned long data) |
|---|
| 2270 | +static void pl330_tasklet(struct tasklet_struct *t) |
|---|
| 2261 | 2271 | { |
|---|
| 2262 | | - struct dma_pl330_chan *pch = (struct dma_pl330_chan *)data; |
|---|
| 2272 | + struct dma_pl330_chan *pch = from_tasklet(pch, t, task); |
|---|
| 2263 | 2273 | struct dma_pl330_desc *desc, *_dt; |
|---|
| 2264 | 2274 | unsigned long flags; |
|---|
| 2265 | 2275 | bool power_down = false; |
|---|
| .. | .. |
|---|
| 2367 | 2377 | return -ENOMEM; |
|---|
| 2368 | 2378 | } |
|---|
| 2369 | 2379 | |
|---|
| 2370 | | - tasklet_init(&pch->task, pl330_tasklet, (unsigned long) pch); |
|---|
| 2380 | + tasklet_setup(&pch->task, pl330_tasklet); |
|---|
| 2371 | 2381 | |
|---|
| 2372 | 2382 | spin_unlock_irqrestore(&pl330->lock, flags); |
|---|
| 2373 | 2383 | |
|---|
| .. | .. |
|---|
| 2432 | 2442 | return max_burst_len; |
|---|
| 2433 | 2443 | } |
|---|
| 2434 | 2444 | |
|---|
| 2445 | +static int pl330_config_write(struct dma_chan *chan, |
|---|
| 2446 | + struct dma_slave_config *slave_config, |
|---|
| 2447 | + enum dma_transfer_direction direction) |
|---|
| 2448 | +{ |
|---|
| 2449 | + struct dma_pl330_chan *pch = to_pchan(chan); |
|---|
| 2450 | + |
|---|
| 2451 | + pl330_unprep_slave_fifo(pch); |
|---|
| 2452 | + if (direction == DMA_MEM_TO_DEV) { |
|---|
| 2453 | + if (slave_config->dst_addr) |
|---|
| 2454 | + pch->fifo_addr = slave_config->dst_addr; |
|---|
| 2455 | + if (slave_config->dst_addr_width) |
|---|
| 2456 | + pch->burst_sz = __ffs(slave_config->dst_addr_width); |
|---|
| 2457 | +#ifdef CONFIG_NO_GKI |
|---|
| 2458 | + if (slave_config->src_interlace_size) |
|---|
| 2459 | + pch->slave_config.src_interlace_size = slave_config->src_interlace_size; |
|---|
| 2460 | +#endif |
|---|
| 2461 | + pch->burst_len = fixup_burst_len(slave_config->dst_maxburst, |
|---|
| 2462 | + pch->dmac->quirks); |
|---|
| 2463 | + } else if (direction == DMA_DEV_TO_MEM) { |
|---|
| 2464 | + if (slave_config->src_addr) |
|---|
| 2465 | + pch->fifo_addr = slave_config->src_addr; |
|---|
| 2466 | + if (slave_config->src_addr_width) |
|---|
| 2467 | + pch->burst_sz = __ffs(slave_config->src_addr_width); |
|---|
| 2468 | +#ifdef CONFIG_NO_GKI |
|---|
| 2469 | + if (slave_config->dst_interlace_size) |
|---|
| 2470 | + pch->slave_config.dst_interlace_size = slave_config->dst_interlace_size; |
|---|
| 2471 | +#endif |
|---|
| 2472 | + pch->burst_len = fixup_burst_len(slave_config->src_maxburst, |
|---|
| 2473 | + pch->dmac->quirks); |
|---|
| 2474 | + } |
|---|
| 2475 | + |
|---|
| 2476 | + return 0; |
|---|
| 2477 | +} |
|---|
| 2478 | + |
|---|
| 2435 | 2479 | static int pl330_config(struct dma_chan *chan, |
|---|
| 2436 | 2480 | struct dma_slave_config *slave_config) |
|---|
| 2437 | 2481 | { |
|---|
| 2438 | 2482 | struct dma_pl330_chan *pch = to_pchan(chan); |
|---|
| 2439 | 2483 | |
|---|
| 2440 | | - pl330_unprep_slave_fifo(pch); |
|---|
| 2441 | | - if (slave_config->direction == DMA_MEM_TO_DEV) { |
|---|
| 2442 | | - if (slave_config->dst_addr) |
|---|
| 2443 | | - pch->fifo_addr = slave_config->dst_addr; |
|---|
| 2444 | | - if (slave_config->dst_addr_width) |
|---|
| 2445 | | - pch->burst_sz = __ffs(slave_config->dst_addr_width); |
|---|
| 2446 | | - if (slave_config->src_interlace_size) |
|---|
| 2447 | | - pch->src_interlace_size = slave_config->src_interlace_size; |
|---|
| 2448 | | - pch->burst_len = fixup_burst_len(slave_config->dst_maxburst, |
|---|
| 2449 | | - pch->dmac->quirks); |
|---|
| 2450 | | - } else if (slave_config->direction == DMA_DEV_TO_MEM) { |
|---|
| 2451 | | - if (slave_config->src_addr) |
|---|
| 2452 | | - pch->fifo_addr = slave_config->src_addr; |
|---|
| 2453 | | - if (slave_config->src_addr_width) |
|---|
| 2454 | | - pch->burst_sz = __ffs(slave_config->src_addr_width); |
|---|
| 2455 | | - if (slave_config->dst_interlace_size) |
|---|
| 2456 | | - pch->dst_interlace_size = slave_config->dst_interlace_size; |
|---|
| 2457 | | - pch->burst_len = fixup_burst_len(slave_config->src_maxburst, |
|---|
| 2458 | | - pch->dmac->quirks); |
|---|
| 2459 | | - } |
|---|
| 2484 | + memcpy(&pch->slave_config, slave_config, sizeof(*slave_config)); |
|---|
| 2460 | 2485 | |
|---|
| 2461 | 2486 | return 0; |
|---|
| 2462 | 2487 | } |
|---|
| .. | .. |
|---|
| 2467 | 2492 | struct dma_pl330_desc *desc; |
|---|
| 2468 | 2493 | unsigned long flags; |
|---|
| 2469 | 2494 | struct pl330_dmac *pl330 = pch->dmac; |
|---|
| 2470 | | - LIST_HEAD(list); |
|---|
| 2471 | 2495 | bool power_down = false; |
|---|
| 2472 | 2496 | |
|---|
| 2473 | 2497 | pm_runtime_get_sync(pl330->ddma.dev); |
|---|
| .. | .. |
|---|
| 2672 | 2696 | list_splice_tail_init(&pch->submitted_list, &pch->work_list); |
|---|
| 2673 | 2697 | spin_unlock_irqrestore(&pch->lock, flags); |
|---|
| 2674 | 2698 | |
|---|
| 2675 | | - pl330_tasklet((unsigned long)pch); |
|---|
| 2699 | + pl330_tasklet(&pch->task); |
|---|
| 2676 | 2700 | } |
|---|
| 2677 | 2701 | |
|---|
| 2678 | 2702 | /* |
|---|
| .. | .. |
|---|
| 2776 | 2800 | |
|---|
| 2777 | 2801 | /* If the DMAC pool is empty, alloc new */ |
|---|
| 2778 | 2802 | if (!desc) { |
|---|
| 2779 | | - DEFINE_SPINLOCK(lock); |
|---|
| 2803 | + static DEFINE_SPINLOCK(lock); |
|---|
| 2780 | 2804 | LIST_HEAD(pool); |
|---|
| 2781 | 2805 | |
|---|
| 2782 | 2806 | if (!add_desc(&pool, &lock, GFP_ATOMIC, 1)) |
|---|
| .. | .. |
|---|
| 2862 | 2886 | { |
|---|
| 2863 | 2887 | struct dma_pl330_desc *desc = NULL; |
|---|
| 2864 | 2888 | struct dma_pl330_chan *pch = to_pchan(chan); |
|---|
| 2865 | | - dma_addr_t dst; |
|---|
| 2866 | | - dma_addr_t src; |
|---|
| 2889 | + dma_addr_t dst = 0; |
|---|
| 2890 | + dma_addr_t src = 0; |
|---|
| 2867 | 2891 | |
|---|
| 2868 | 2892 | if (len % period_len != 0) |
|---|
| 2869 | 2893 | return NULL; |
|---|
| .. | .. |
|---|
| 2873 | 2897 | __func__, __LINE__); |
|---|
| 2874 | 2898 | return NULL; |
|---|
| 2875 | 2899 | } |
|---|
| 2900 | + |
|---|
| 2901 | + pl330_config_write(chan, &pch->slave_config, direction); |
|---|
| 2876 | 2902 | |
|---|
| 2877 | 2903 | if (!pl330_prep_slave_fifo(pch, direction)) |
|---|
| 2878 | 2904 | return NULL; |
|---|
| .. | .. |
|---|
| 2910 | 2936 | desc->cyclic = true; |
|---|
| 2911 | 2937 | desc->num_periods = len / period_len; |
|---|
| 2912 | 2938 | desc->txd.flags = flags; |
|---|
| 2913 | | - |
|---|
| 2914 | | - desc->src_interlace_size = pch->src_interlace_size; |
|---|
| 2915 | | - desc->dst_interlace_size = pch->dst_interlace_size; |
|---|
| 2916 | | - |
|---|
| 2939 | +#ifdef CONFIG_NO_GKI |
|---|
| 2940 | + desc->src_interlace_size = pch->slave_config.src_interlace_size; |
|---|
| 2941 | + desc->dst_interlace_size = pch->slave_config.dst_interlace_size; |
|---|
| 2942 | +#endif |
|---|
| 2917 | 2943 | return &desc->txd; |
|---|
| 2918 | 2944 | } |
|---|
| 2919 | 2945 | |
|---|
| .. | .. |
|---|
| 3004 | 3030 | if (unlikely(!pch || !sgl || !sg_len)) |
|---|
| 3005 | 3031 | return NULL; |
|---|
| 3006 | 3032 | |
|---|
| 3033 | + pl330_config_write(chan, &pch->slave_config, direction); |
|---|
| 3034 | + |
|---|
| 3007 | 3035 | if (!pl330_prep_slave_fifo(pch, direction)) |
|---|
| 3008 | 3036 | return NULL; |
|---|
| 3009 | 3037 | |
|---|
| .. | .. |
|---|
| 3044 | 3072 | desc->rqcfg.brst_len = pch->burst_len; |
|---|
| 3045 | 3073 | desc->rqtype = direction; |
|---|
| 3046 | 3074 | desc->bytes_requested = sg_dma_len(sg); |
|---|
| 3047 | | - desc->src_interlace_size = pch->src_interlace_size; |
|---|
| 3048 | | - desc->dst_interlace_size = pch->dst_interlace_size; |
|---|
| 3075 | +#ifdef CONFIG_NO_GKI |
|---|
| 3076 | + desc->src_interlace_size = pch->slave_config.src_interlace_size; |
|---|
| 3077 | + desc->dst_interlace_size = pch->slave_config.dst_interlace_size; |
|---|
| 3078 | +#endif |
|---|
| 3049 | 3079 | } |
|---|
| 3050 | 3080 | |
|---|
| 3051 | 3081 | /* Return the last desc in the chain */ |
|---|
| .. | .. |
|---|
| 3068 | 3098 | BIT(DMA_SLAVE_BUSWIDTH_4_BYTES) | \ |
|---|
| 3069 | 3099 | BIT(DMA_SLAVE_BUSWIDTH_8_BYTES) |
|---|
| 3070 | 3100 | |
|---|
| 3101 | +#ifdef CONFIG_DEBUG_FS |
|---|
| 3102 | +static int pl330_debugfs_show(struct seq_file *s, void *data) |
|---|
| 3103 | +{ |
|---|
| 3104 | + struct pl330_dmac *pl330 = s->private; |
|---|
| 3105 | + int chans, pchs, ch, pr; |
|---|
| 3106 | + |
|---|
| 3107 | + chans = pl330->pcfg.num_chan; |
|---|
| 3108 | + pchs = pl330->num_peripherals; |
|---|
| 3109 | + |
|---|
| 3110 | + seq_puts(s, "PL330 physical channels:\n"); |
|---|
| 3111 | + seq_puts(s, "THREAD:\t\tCHANNEL:\n"); |
|---|
| 3112 | + seq_puts(s, "--------\t-----\n"); |
|---|
| 3113 | + for (ch = 0; ch < chans; ch++) { |
|---|
| 3114 | + struct pl330_thread *thrd = &pl330->channels[ch]; |
|---|
| 3115 | + int found = -1; |
|---|
| 3116 | + |
|---|
| 3117 | + for (pr = 0; pr < pchs; pr++) { |
|---|
| 3118 | + struct dma_pl330_chan *pch = &pl330->peripherals[pr]; |
|---|
| 3119 | + |
|---|
| 3120 | + if (!pch->thread || thrd->id != pch->thread->id) |
|---|
| 3121 | + continue; |
|---|
| 3122 | + |
|---|
| 3123 | + found = pr; |
|---|
| 3124 | + } |
|---|
| 3125 | + |
|---|
| 3126 | + seq_printf(s, "%d\t\t", thrd->id); |
|---|
| 3127 | + if (found == -1) |
|---|
| 3128 | + seq_puts(s, "--\n"); |
|---|
| 3129 | + else |
|---|
| 3130 | + seq_printf(s, "%d\n", found); |
|---|
| 3131 | + } |
|---|
| 3132 | + |
|---|
| 3133 | + return 0; |
|---|
| 3134 | +} |
|---|
| 3135 | + |
|---|
| 3136 | +DEFINE_SHOW_ATTRIBUTE(pl330_debugfs); |
|---|
| 3137 | + |
|---|
| 3138 | +static inline void init_pl330_debugfs(struct pl330_dmac *pl330) |
|---|
| 3139 | +{ |
|---|
| 3140 | + debugfs_create_file(dev_name(pl330->ddma.dev), |
|---|
| 3141 | + S_IFREG | 0444, NULL, pl330, |
|---|
| 3142 | + &pl330_debugfs_fops); |
|---|
| 3143 | +} |
|---|
| 3144 | +#else |
|---|
| 3145 | +static inline void init_pl330_debugfs(struct pl330_dmac *pl330) |
|---|
| 3146 | +{ |
|---|
| 3147 | +} |
|---|
| 3148 | +#endif |
|---|
| 3149 | + |
|---|
| 3071 | 3150 | /* |
|---|
| 3072 | 3151 | * Runtime PM callbacks are provided by amba/bus.c driver. |
|---|
| 3073 | 3152 | * |
|---|
| .. | .. |
|---|
| 3078 | 3157 | { |
|---|
| 3079 | 3158 | struct amba_device *pcdev = to_amba_device(dev); |
|---|
| 3080 | 3159 | |
|---|
| 3081 | | - pm_runtime_disable(dev); |
|---|
| 3082 | | - |
|---|
| 3083 | | - if (!pm_runtime_status_suspended(dev)) { |
|---|
| 3084 | | - /* amba did not disable the clock */ |
|---|
| 3085 | | - amba_pclk_disable(pcdev); |
|---|
| 3086 | | - } |
|---|
| 3160 | + pm_runtime_force_suspend(dev); |
|---|
| 3087 | 3161 | amba_pclk_unprepare(pcdev); |
|---|
| 3088 | 3162 | |
|---|
| 3089 | 3163 | return 0; |
|---|
| .. | .. |
|---|
| 3098 | 3172 | if (ret) |
|---|
| 3099 | 3173 | return ret; |
|---|
| 3100 | 3174 | |
|---|
| 3101 | | - if (!pm_runtime_status_suspended(dev)) |
|---|
| 3102 | | - ret = amba_pclk_enable(pcdev); |
|---|
| 3103 | | - |
|---|
| 3104 | | - pm_runtime_enable(dev); |
|---|
| 3175 | + pm_runtime_force_resume(dev); |
|---|
| 3105 | 3176 | |
|---|
| 3106 | 3177 | return ret; |
|---|
| 3107 | 3178 | } |
|---|
| 3108 | 3179 | |
|---|
| 3109 | | -static SIMPLE_DEV_PM_OPS(pl330_pm, pl330_suspend, pl330_resume); |
|---|
| 3180 | +static const struct dev_pm_ops pl330_pm = { |
|---|
| 3181 | + SET_LATE_SYSTEM_SLEEP_PM_OPS(pl330_suspend, pl330_resume) |
|---|
| 3182 | +}; |
|---|
| 3110 | 3183 | |
|---|
| 3111 | 3184 | static int |
|---|
| 3112 | 3185 | pl330_probe(struct amba_device *adev, const struct amba_id *id) |
|---|
| .. | .. |
|---|
| 3145 | 3218 | return PTR_ERR(pl330->base); |
|---|
| 3146 | 3219 | |
|---|
| 3147 | 3220 | amba_set_drvdata(adev, pl330); |
|---|
| 3221 | + |
|---|
| 3222 | + pl330->rstc = devm_reset_control_get_optional(&adev->dev, "dma"); |
|---|
| 3223 | + if (IS_ERR(pl330->rstc)) { |
|---|
| 3224 | + return dev_err_probe(&adev->dev, PTR_ERR(pl330->rstc), "Failed to get reset!\n"); |
|---|
| 3225 | + } else { |
|---|
| 3226 | + ret = reset_control_deassert(pl330->rstc); |
|---|
| 3227 | + if (ret) { |
|---|
| 3228 | + dev_err(&adev->dev, "Couldn't deassert the device from reset!\n"); |
|---|
| 3229 | + return ret; |
|---|
| 3230 | + } |
|---|
| 3231 | + } |
|---|
| 3232 | + |
|---|
| 3233 | + pl330->rstc_ocp = devm_reset_control_get_optional(&adev->dev, "dma-ocp"); |
|---|
| 3234 | + if (IS_ERR(pl330->rstc_ocp)) { |
|---|
| 3235 | + return dev_err_probe(&adev->dev, PTR_ERR(pl330->rstc_ocp), |
|---|
| 3236 | + "Failed to get OCP reset!\n"); |
|---|
| 3237 | + } else { |
|---|
| 3238 | + ret = reset_control_deassert(pl330->rstc_ocp); |
|---|
| 3239 | + if (ret) { |
|---|
| 3240 | + dev_err(&adev->dev, "Couldn't deassert the device from OCP reset!\n"); |
|---|
| 3241 | + return ret; |
|---|
| 3242 | + } |
|---|
| 3243 | + } |
|---|
| 3148 | 3244 | |
|---|
| 3149 | 3245 | for (i = 0; i < AMBA_NR_IRQS; i++) { |
|---|
| 3150 | 3246 | irq = adev->irq[i]; |
|---|
| .. | .. |
|---|
| 3242 | 3338 | } |
|---|
| 3243 | 3339 | } |
|---|
| 3244 | 3340 | |
|---|
| 3245 | | - adev->dev.dma_parms = &pl330->dma_parms; |
|---|
| 3246 | | - |
|---|
| 3247 | 3341 | /* |
|---|
| 3248 | 3342 | * This is the limit for transfers with a buswidth of 1, larger |
|---|
| 3249 | 3343 | * buswidths will have larger limits. |
|---|
| .. | .. |
|---|
| 3253 | 3347 | dev_err(&adev->dev, "unable to set the seg size\n"); |
|---|
| 3254 | 3348 | |
|---|
| 3255 | 3349 | |
|---|
| 3350 | + init_pl330_debugfs(pl330); |
|---|
| 3256 | 3351 | dev_info(&adev->dev, |
|---|
| 3257 | 3352 | "Loaded driver for PL330 DMAC-%x\n", adev->periphid); |
|---|
| 3258 | 3353 | dev_info(&adev->dev, |
|---|
| .. | .. |
|---|
| 3284 | 3379 | probe_err2: |
|---|
| 3285 | 3380 | pl330_del(pl330); |
|---|
| 3286 | 3381 | |
|---|
| 3382 | + if (pl330->rstc_ocp) |
|---|
| 3383 | + reset_control_assert(pl330->rstc_ocp); |
|---|
| 3384 | + |
|---|
| 3385 | + if (pl330->rstc) |
|---|
| 3386 | + reset_control_assert(pl330->rstc); |
|---|
| 3287 | 3387 | return ret; |
|---|
| 3288 | 3388 | } |
|---|
| 3289 | 3389 | |
|---|
| 3290 | | -static int pl330_remove(struct amba_device *adev) |
|---|
| 3390 | +static void pl330_remove(struct amba_device *adev) |
|---|
| 3291 | 3391 | { |
|---|
| 3292 | 3392 | struct pl330_dmac *pl330 = amba_get_drvdata(adev); |
|---|
| 3293 | 3393 | struct dma_pl330_chan *pch, *_p; |
|---|
| .. | .. |
|---|
| 3322 | 3422 | |
|---|
| 3323 | 3423 | pl330_del(pl330); |
|---|
| 3324 | 3424 | |
|---|
| 3325 | | - return 0; |
|---|
| 3425 | + if (pl330->rstc_ocp) |
|---|
| 3426 | + reset_control_assert(pl330->rstc_ocp); |
|---|
| 3427 | + |
|---|
| 3428 | + if (pl330->rstc) |
|---|
| 3429 | + reset_control_assert(pl330->rstc); |
|---|
| 3326 | 3430 | } |
|---|
| 3327 | 3431 | |
|---|
| 3328 | 3432 | static const struct amba_id pl330_ids[] = { |
|---|