Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

dmaengine: qcom: Add ADM driver

Add the DMA engine driver for the QCOM Application Data Mover (ADM) DMA
controller found in the MSM8x60 and IPQ/APQ8064 platforms.

The ADM supports both memory to memory transactions and memory
to/from peripheral device transactions. The controller also provides
flow control capabilities for transactions to/from peripheral devices.

The initial release of this driver supports slave transfers to/from
peripherals and also incorporates CRCI (client rate control interface)
flow control.

The hardware only supports a 32 bit physical address, so specifying
!PHYS_ADDR_T_64BIT gives maximum COMPILE_TEST coverage without having to
spend effort on kludging things in the code that will never actually be
needed on real hardware.

Signed-off-by: Andy Gross <agross@codeaurora.org>
Signed-off-by: Thomas Pedersen <twp@codeaurora.org>
Signed-off-by: Jonathan McDowell <noodles@earth.li>
Link: https://lore.kernel.org/r/20201114140233.GM32650@earth.li
Signed-off-by: Vinod Koul <vkoul@kernel.org>

authored by

Jonathan McDowell and committed by
Vinod Koul
5c9f8c2d f74faa0c

+915
+11
drivers/dma/qcom/Kconfig
··· 1 1 # SPDX-License-Identifier: GPL-2.0-only 2 + config QCOM_ADM 3 + tristate "Qualcomm ADM support" 4 + depends on (ARCH_QCOM || COMPILE_TEST) && !PHYS_ADDR_T_64BIT 5 + select DMA_ENGINE 6 + select DMA_VIRTUAL_CHANNELS 7 + help 8 + Enable support for the Qualcomm Application Data Mover (ADM) DMA 9 + controller, as present on MSM8x60, APQ8064, and IPQ8064 devices. 10 + This controller provides DMA capabilities for both general purpose 11 + and on-chip peripheral devices. 12 + 2 13 config QCOM_BAM_DMA 3 14 tristate "QCOM BAM DMA support" 4 15 depends on ARCH_QCOM || (COMPILE_TEST && OF && ARM)
+1
drivers/dma/qcom/Makefile
··· 1 1 # SPDX-License-Identifier: GPL-2.0 2 + obj-$(CONFIG_QCOM_ADM) += qcom_adm.o 2 3 obj-$(CONFIG_QCOM_BAM_DMA) += bam_dma.o 3 4 obj-$(CONFIG_QCOM_HIDMA_MGMT) += hdma_mgmt.o 4 5 hdma_mgmt-objs := hidma_mgmt.o hidma_mgmt_sys.o
+903
drivers/dma/qcom/qcom_adm.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + /* 3 + * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved. 4 + */ 5 + 6 + #include <linux/clk.h> 7 + #include <linux/delay.h> 8 + #include <linux/device.h> 9 + #include <linux/dmaengine.h> 10 + #include <linux/dma-mapping.h> 11 + #include <linux/init.h> 12 + #include <linux/interrupt.h> 13 + #include <linux/io.h> 14 + #include <linux/kernel.h> 15 + #include <linux/module.h> 16 + #include <linux/of.h> 17 + #include <linux/of_address.h> 18 + #include <linux/of_irq.h> 19 + #include <linux/of_dma.h> 20 + #include <linux/platform_device.h> 21 + #include <linux/reset.h> 22 + #include <linux/scatterlist.h> 23 + #include <linux/slab.h> 24 + 25 + #include "../dmaengine.h" 26 + #include "../virt-dma.h" 27 + 28 + /* ADM registers - calculated from channel number and security domain */ 29 + #define ADM_CHAN_MULTI 0x4 30 + #define ADM_CI_MULTI 0x4 31 + #define ADM_CRCI_MULTI 0x4 32 + #define ADM_EE_MULTI 0x800 33 + #define ADM_CHAN_OFFS(chan) (ADM_CHAN_MULTI * (chan)) 34 + #define ADM_EE_OFFS(ee) (ADM_EE_MULTI * (ee)) 35 + #define ADM_CHAN_EE_OFFS(chan, ee) (ADM_CHAN_OFFS(chan) + ADM_EE_OFFS(ee)) 36 + #define ADM_CHAN_OFFS(chan) (ADM_CHAN_MULTI * (chan)) 37 + #define ADM_CI_OFFS(ci) (ADM_CHAN_OFF(ci)) 38 + #define ADM_CH_CMD_PTR(chan, ee) (ADM_CHAN_EE_OFFS(chan, ee)) 39 + #define ADM_CH_RSLT(chan, ee) (0x40 + ADM_CHAN_EE_OFFS(chan, ee)) 40 + #define ADM_CH_FLUSH_STATE0(chan, ee) (0x80 + ADM_CHAN_EE_OFFS(chan, ee)) 41 + #define ADM_CH_STATUS_SD(chan, ee) (0x200 + ADM_CHAN_EE_OFFS(chan, ee)) 42 + #define ADM_CH_CONF(chan) (0x240 + ADM_CHAN_OFFS(chan)) 43 + #define ADM_CH_RSLT_CONF(chan, ee) (0x300 + ADM_CHAN_EE_OFFS(chan, ee)) 44 + #define ADM_SEC_DOMAIN_IRQ_STATUS(ee) (0x380 + ADM_EE_OFFS(ee)) 45 + #define ADM_CI_CONF(ci) (0x390 + (ci) * ADM_CI_MULTI) 46 + #define ADM_GP_CTL 0x3d8 47 + #define ADM_CRCI_CTL(crci, ee) (0x400 + (crci) * ADM_CRCI_MULTI + \ 48 + ADM_EE_OFFS(ee)) 49 + 50 + /* channel status */ 51 + #define ADM_CH_STATUS_VALID BIT(1) 52 + 53 + /* channel result */ 54 + #define ADM_CH_RSLT_VALID BIT(31) 55 + #define ADM_CH_RSLT_ERR BIT(3) 56 + #define ADM_CH_RSLT_FLUSH BIT(2) 57 + #define ADM_CH_RSLT_TPD BIT(1) 58 + 59 + /* channel conf */ 60 + #define ADM_CH_CONF_SHADOW_EN BIT(12) 61 + #define ADM_CH_CONF_MPU_DISABLE BIT(11) 62 + #define ADM_CH_CONF_PERM_MPU_CONF BIT(9) 63 + #define ADM_CH_CONF_FORCE_RSLT_EN BIT(7) 64 + #define ADM_CH_CONF_SEC_DOMAIN(ee) ((((ee) & 0x3) << 4) | (((ee) & 0x4) << 11)) 65 + 66 + /* channel result conf */ 67 + #define ADM_CH_RSLT_CONF_FLUSH_EN BIT(1) 68 + #define ADM_CH_RSLT_CONF_IRQ_EN BIT(0) 69 + 70 + /* CRCI CTL */ 71 + #define ADM_CRCI_CTL_MUX_SEL BIT(18) 72 + #define ADM_CRCI_CTL_RST BIT(17) 73 + 74 + /* CI configuration */ 75 + #define ADM_CI_RANGE_END(x) ((x) << 24) 76 + #define ADM_CI_RANGE_START(x) ((x) << 16) 77 + #define ADM_CI_BURST_4_WORDS BIT(2) 78 + #define ADM_CI_BURST_8_WORDS BIT(3) 79 + 80 + /* GP CTL */ 81 + #define ADM_GP_CTL_LP_EN BIT(12) 82 + #define ADM_GP_CTL_LP_CNT(x) ((x) << 8) 83 + 84 + /* Command pointer list entry */ 85 + #define ADM_CPLE_LP BIT(31) 86 + #define ADM_CPLE_CMD_PTR_LIST BIT(29) 87 + 88 + /* Command list entry */ 89 + #define ADM_CMD_LC BIT(31) 90 + #define ADM_CMD_DST_CRCI(n) (((n) & 0xf) << 7) 91 + #define ADM_CMD_SRC_CRCI(n) (((n) & 0xf) << 3) 92 + 93 + #define ADM_CMD_TYPE_SINGLE 0x0 94 + #define ADM_CMD_TYPE_BOX 0x3 95 + 96 + #define ADM_CRCI_MUX_SEL BIT(4) 97 + #define ADM_DESC_ALIGN 8 98 + #define ADM_MAX_XFER (SZ_64K - 1) 99 + #define ADM_MAX_ROWS (SZ_64K - 1) 100 + #define ADM_MAX_CHANNELS 16 101 + 102 + struct adm_desc_hw_box { 103 + u32 cmd; 104 + u32 src_addr; 105 + u32 dst_addr; 106 + u32 row_len; 107 + u32 num_rows; 108 + u32 row_offset; 109 + }; 110 + 111 + struct adm_desc_hw_single { 112 + u32 cmd; 113 + u32 src_addr; 114 + u32 dst_addr; 115 + u32 len; 116 + }; 117 + 118 + struct adm_async_desc { 119 + struct virt_dma_desc vd; 120 + struct adm_device *adev; 121 + 122 + size_t length; 123 + enum dma_transfer_direction dir; 124 + dma_addr_t dma_addr; 125 + size_t dma_len; 126 + 127 + void *cpl; 128 + dma_addr_t cp_addr; 129 + u32 crci; 130 + u32 mux; 131 + u32 blk_size; 132 + }; 133 + 134 + struct adm_chan { 135 + struct virt_dma_chan vc; 136 + struct adm_device *adev; 137 + 138 + /* parsed from DT */ 139 + u32 id; /* channel id */ 140 + 141 + struct adm_async_desc *curr_txd; 142 + struct dma_slave_config slave; 143 + struct list_head node; 144 + 145 + int error; 146 + int initialized; 147 + }; 148 + 149 + static inline struct adm_chan *to_adm_chan(struct dma_chan *common) 150 + { 151 + return container_of(common, struct adm_chan, vc.chan); 152 + } 153 + 154 + struct adm_device { 155 + void __iomem *regs; 156 + struct device *dev; 157 + struct dma_device common; 158 + struct device_dma_parameters dma_parms; 159 + struct adm_chan *channels; 160 + 161 + u32 ee; 162 + 163 + struct clk *core_clk; 164 + struct clk *iface_clk; 165 + 166 + struct reset_control *clk_reset; 167 + struct reset_control *c0_reset; 168 + struct reset_control *c1_reset; 169 + struct reset_control *c2_reset; 170 + int irq; 171 + }; 172 + 173 + /** 174 + * adm_free_chan - Frees dma resources associated with the specific channel 175 + * 176 + * Free all allocated descriptors associated with this channel 177 + * 178 + */ 179 + static void adm_free_chan(struct dma_chan *chan) 180 + { 181 + /* free all queued descriptors */ 182 + vchan_free_chan_resources(to_virt_chan(chan)); 183 + } 184 + 185 + /** 186 + * adm_get_blksize - Get block size from burst value 187 + * 188 + */ 189 + static int adm_get_blksize(unsigned int burst) 190 + { 191 + int ret; 192 + 193 + switch (burst) { 194 + case 16: 195 + case 32: 196 + case 64: 197 + case 128: 198 + ret = ffs(burst >> 4) - 1; 199 + break; 200 + case 192: 201 + ret = 4; 202 + break; 203 + case 256: 204 + ret = 5; 205 + break; 206 + default: 207 + ret = -EINVAL; 208 + break; 209 + } 210 + 211 + return ret; 212 + } 213 + 214 + /** 215 + * adm_process_fc_descriptors - Process descriptors for flow controlled xfers 216 + * 217 + * @achan: ADM channel 218 + * @desc: Descriptor memory pointer 219 + * @sg: Scatterlist entry 220 + * @crci: CRCI value 221 + * @burst: Burst size of transaction 222 + * @direction: DMA transfer direction 223 + */ 224 + static void *adm_process_fc_descriptors(struct adm_chan *achan, void *desc, 225 + struct scatterlist *sg, u32 crci, 226 + u32 burst, 227 + enum dma_transfer_direction direction) 228 + { 229 + struct adm_desc_hw_box *box_desc = NULL; 230 + struct adm_desc_hw_single *single_desc; 231 + u32 remainder = sg_dma_len(sg); 232 + u32 rows, row_offset, crci_cmd; 233 + u32 mem_addr = sg_dma_address(sg); 234 + u32 *incr_addr = &mem_addr; 235 + u32 *src, *dst; 236 + 237 + if (direction == DMA_DEV_TO_MEM) { 238 + crci_cmd = ADM_CMD_SRC_CRCI(crci); 239 + row_offset = burst; 240 + src = &achan->slave.src_addr; 241 + dst = &mem_addr; 242 + } else { 243 + crci_cmd = ADM_CMD_DST_CRCI(crci); 244 + row_offset = burst << 16; 245 + src = &mem_addr; 246 + dst = &achan->slave.dst_addr; 247 + } 248 + 249 + while (remainder >= burst) { 250 + box_desc = desc; 251 + box_desc->cmd = ADM_CMD_TYPE_BOX | crci_cmd; 252 + box_desc->row_offset = row_offset; 253 + box_desc->src_addr = *src; 254 + box_desc->dst_addr = *dst; 255 + 256 + rows = remainder / burst; 257 + rows = min_t(u32, rows, ADM_MAX_ROWS); 258 + box_desc->num_rows = rows << 16 | rows; 259 + box_desc->row_len = burst << 16 | burst; 260 + 261 + *incr_addr += burst * rows; 262 + remainder -= burst * rows; 263 + desc += sizeof(*box_desc); 264 + } 265 + 266 + /* if leftover bytes, do one single descriptor */ 267 + if (remainder) { 268 + single_desc = desc; 269 + single_desc->cmd = ADM_CMD_TYPE_SINGLE | crci_cmd; 270 + single_desc->len = remainder; 271 + single_desc->src_addr = *src; 272 + single_desc->dst_addr = *dst; 273 + desc += sizeof(*single_desc); 274 + 275 + if (sg_is_last(sg)) 276 + single_desc->cmd |= ADM_CMD_LC; 277 + } else { 278 + if (box_desc && sg_is_last(sg)) 279 + box_desc->cmd |= ADM_CMD_LC; 280 + } 281 + 282 + return desc; 283 + } 284 + 285 + /** 286 + * adm_process_non_fc_descriptors - Process descriptors for non-fc xfers 287 + * 288 + * @achan: ADM channel 289 + * @desc: Descriptor memory pointer 290 + * @sg: Scatterlist entry 291 + * @direction: DMA transfer direction 292 + */ 293 + static void *adm_process_non_fc_descriptors(struct adm_chan *achan, void *desc, 294 + struct scatterlist *sg, 295 + enum dma_transfer_direction direction) 296 + { 297 + struct adm_desc_hw_single *single_desc; 298 + u32 remainder = sg_dma_len(sg); 299 + u32 mem_addr = sg_dma_address(sg); 300 + u32 *incr_addr = &mem_addr; 301 + u32 *src, *dst; 302 + 303 + if (direction == DMA_DEV_TO_MEM) { 304 + src = &achan->slave.src_addr; 305 + dst = &mem_addr; 306 + } else { 307 + src = &mem_addr; 308 + dst = &achan->slave.dst_addr; 309 + } 310 + 311 + do { 312 + single_desc = desc; 313 + single_desc->cmd = ADM_CMD_TYPE_SINGLE; 314 + single_desc->src_addr = *src; 315 + single_desc->dst_addr = *dst; 316 + single_desc->len = (remainder > ADM_MAX_XFER) ? 317 + ADM_MAX_XFER : remainder; 318 + 319 + remainder -= single_desc->len; 320 + *incr_addr += single_desc->len; 321 + desc += sizeof(*single_desc); 322 + } while (remainder); 323 + 324 + /* set last command if this is the end of the whole transaction */ 325 + if (sg_is_last(sg)) 326 + single_desc->cmd |= ADM_CMD_LC; 327 + 328 + return desc; 329 + } 330 + 331 + /** 332 + * adm_prep_slave_sg - Prep slave sg transaction 333 + * 334 + * @chan: dma channel 335 + * @sgl: scatter gather list 336 + * @sg_len: length of sg 337 + * @direction: DMA transfer direction 338 + * @flags: DMA flags 339 + * @context: transfer context (unused) 340 + */ 341 + static struct dma_async_tx_descriptor *adm_prep_slave_sg(struct dma_chan *chan, 342 + struct scatterlist *sgl, 343 + unsigned int sg_len, 344 + enum dma_transfer_direction direction, 345 + unsigned long flags, 346 + void *context) 347 + { 348 + struct adm_chan *achan = to_adm_chan(chan); 349 + struct adm_device *adev = achan->adev; 350 + struct adm_async_desc *async_desc; 351 + struct scatterlist *sg; 352 + dma_addr_t cple_addr; 353 + u32 i, burst; 354 + u32 single_count = 0, box_count = 0, crci = 0; 355 + void *desc; 356 + u32 *cple; 357 + int blk_size = 0; 358 + 359 + if (!is_slave_direction(direction)) { 360 + dev_err(adev->dev, "invalid dma direction\n"); 361 + return NULL; 362 + } 363 + 364 + /* 365 + * get burst value from slave configuration 366 + */ 367 + burst = (direction == DMA_MEM_TO_DEV) ? 368 + achan->slave.dst_maxburst : 369 + achan->slave.src_maxburst; 370 + 371 + /* if using flow control, validate burst and crci values */ 372 + if (achan->slave.device_fc) { 373 + blk_size = adm_get_blksize(burst); 374 + if (blk_size < 0) { 375 + dev_err(adev->dev, "invalid burst value: %d\n", 376 + burst); 377 + return ERR_PTR(-EINVAL); 378 + } 379 + 380 + crci = achan->slave.slave_id & 0xf; 381 + if (!crci || achan->slave.slave_id > 0x1f) { 382 + dev_err(adev->dev, "invalid crci value\n"); 383 + return ERR_PTR(-EINVAL); 384 + } 385 + } 386 + 387 + /* iterate through sgs and compute allocation size of structures */ 388 + for_each_sg(sgl, sg, sg_len, i) { 389 + if (achan->slave.device_fc) { 390 + box_count += DIV_ROUND_UP(sg_dma_len(sg) / burst, 391 + ADM_MAX_ROWS); 392 + if (sg_dma_len(sg) % burst) 393 + single_count++; 394 + } else { 395 + single_count += DIV_ROUND_UP(sg_dma_len(sg), 396 + ADM_MAX_XFER); 397 + } 398 + } 399 + 400 + async_desc = kzalloc(sizeof(*async_desc), GFP_NOWAIT); 401 + if (!async_desc) 402 + return ERR_PTR(-ENOMEM); 403 + 404 + if (crci) 405 + async_desc->mux = achan->slave.slave_id & ADM_CRCI_MUX_SEL ? 406 + ADM_CRCI_CTL_MUX_SEL : 0; 407 + async_desc->crci = crci; 408 + async_desc->blk_size = blk_size; 409 + async_desc->dma_len = single_count * sizeof(struct adm_desc_hw_single) + 410 + box_count * sizeof(struct adm_desc_hw_box) + 411 + sizeof(*cple) + 2 * ADM_DESC_ALIGN; 412 + 413 + async_desc->cpl = kzalloc(async_desc->dma_len, GFP_NOWAIT); 414 + if (!async_desc->cpl) 415 + goto free; 416 + 417 + async_desc->adev = adev; 418 + 419 + /* both command list entry and descriptors must be 8 byte aligned */ 420 + cple = PTR_ALIGN(async_desc->cpl, ADM_DESC_ALIGN); 421 + desc = PTR_ALIGN(cple + 1, ADM_DESC_ALIGN); 422 + 423 + for_each_sg(sgl, sg, sg_len, i) { 424 + async_desc->length += sg_dma_len(sg); 425 + 426 + if (achan->slave.device_fc) 427 + desc = adm_process_fc_descriptors(achan, desc, sg, crci, 428 + burst, direction); 429 + else 430 + desc = adm_process_non_fc_descriptors(achan, desc, sg, 431 + direction); 432 + } 433 + 434 + async_desc->dma_addr = dma_map_single(adev->dev, async_desc->cpl, 435 + async_desc->dma_len, 436 + DMA_TO_DEVICE); 437 + if (dma_mapping_error(adev->dev, async_desc->dma_addr)) 438 + goto free; 439 + 440 + cple_addr = async_desc->dma_addr + ((void *)cple - async_desc->cpl); 441 + 442 + /* init cmd list */ 443 + dma_sync_single_for_cpu(adev->dev, cple_addr, sizeof(*cple), 444 + DMA_TO_DEVICE); 445 + *cple = ADM_CPLE_LP; 446 + *cple |= (async_desc->dma_addr + ADM_DESC_ALIGN) >> 3; 447 + dma_sync_single_for_device(adev->dev, cple_addr, sizeof(*cple), 448 + DMA_TO_DEVICE); 449 + 450 + return vchan_tx_prep(&achan->vc, &async_desc->vd, flags); 451 + 452 + free: 453 + kfree(async_desc); 454 + return ERR_PTR(-ENOMEM); 455 + } 456 + 457 + /** 458 + * adm_terminate_all - terminate all transactions on a channel 459 + * @achan: adm dma channel 460 + * 461 + * Dequeues and frees all transactions, aborts current transaction 462 + * No callbacks are done 463 + * 464 + */ 465 + static int adm_terminate_all(struct dma_chan *chan) 466 + { 467 + struct adm_chan *achan = to_adm_chan(chan); 468 + struct adm_device *adev = achan->adev; 469 + unsigned long flags; 470 + LIST_HEAD(head); 471 + 472 + spin_lock_irqsave(&achan->vc.lock, flags); 473 + vchan_get_all_descriptors(&achan->vc, &head); 474 + 475 + /* send flush command to terminate current transaction */ 476 + writel_relaxed(0x0, 477 + adev->regs + ADM_CH_FLUSH_STATE0(achan->id, adev->ee)); 478 + 479 + spin_unlock_irqrestore(&achan->vc.lock, flags); 480 + 481 + vchan_dma_desc_free_list(&achan->vc, &head); 482 + 483 + return 0; 484 + } 485 + 486 + static int adm_slave_config(struct dma_chan *chan, struct dma_slave_config *cfg) 487 + { 488 + struct adm_chan *achan = to_adm_chan(chan); 489 + unsigned long flag; 490 + 491 + spin_lock_irqsave(&achan->vc.lock, flag); 492 + memcpy(&achan->slave, cfg, sizeof(struct dma_slave_config)); 493 + spin_unlock_irqrestore(&achan->vc.lock, flag); 494 + 495 + return 0; 496 + } 497 + 498 + /** 499 + * adm_start_dma - start next transaction 500 + * @achan - ADM dma channel 501 + */ 502 + static void adm_start_dma(struct adm_chan *achan) 503 + { 504 + struct virt_dma_desc *vd = vchan_next_desc(&achan->vc); 505 + struct adm_device *adev = achan->adev; 506 + struct adm_async_desc *async_desc; 507 + 508 + lockdep_assert_held(&achan->vc.lock); 509 + 510 + if (!vd) 511 + return; 512 + 513 + list_del(&vd->node); 514 + 515 + /* write next command list out to the CMD FIFO */ 516 + async_desc = container_of(vd, struct adm_async_desc, vd); 517 + achan->curr_txd = async_desc; 518 + 519 + /* reset channel error */ 520 + achan->error = 0; 521 + 522 + if (!achan->initialized) { 523 + /* enable interrupts */ 524 + writel(ADM_CH_CONF_SHADOW_EN | 525 + ADM_CH_CONF_PERM_MPU_CONF | 526 + ADM_CH_CONF_MPU_DISABLE | 527 + ADM_CH_CONF_SEC_DOMAIN(adev->ee), 528 + adev->regs + ADM_CH_CONF(achan->id)); 529 + 530 + writel(ADM_CH_RSLT_CONF_IRQ_EN | ADM_CH_RSLT_CONF_FLUSH_EN, 531 + adev->regs + ADM_CH_RSLT_CONF(achan->id, adev->ee)); 532 + 533 + achan->initialized = 1; 534 + } 535 + 536 + /* set the crci block size if this transaction requires CRCI */ 537 + if (async_desc->crci) { 538 + writel(async_desc->mux | async_desc->blk_size, 539 + adev->regs + ADM_CRCI_CTL(async_desc->crci, adev->ee)); 540 + } 541 + 542 + /* make sure IRQ enable doesn't get reordered */ 543 + wmb(); 544 + 545 + /* write next command list out to the CMD FIFO */ 546 + writel(ALIGN(async_desc->dma_addr, ADM_DESC_ALIGN) >> 3, 547 + adev->regs + ADM_CH_CMD_PTR(achan->id, adev->ee)); 548 + } 549 + 550 + /** 551 + * adm_dma_irq - irq handler for ADM controller 552 + * @irq: IRQ of interrupt 553 + * @data: callback data 554 + * 555 + * IRQ handler for the bam controller 556 + */ 557 + static irqreturn_t adm_dma_irq(int irq, void *data) 558 + { 559 + struct adm_device *adev = data; 560 + u32 srcs, i; 561 + struct adm_async_desc *async_desc; 562 + unsigned long flags; 563 + 564 + srcs = readl_relaxed(adev->regs + 565 + ADM_SEC_DOMAIN_IRQ_STATUS(adev->ee)); 566 + 567 + for (i = 0; i < ADM_MAX_CHANNELS; i++) { 568 + struct adm_chan *achan = &adev->channels[i]; 569 + u32 status, result; 570 + 571 + if (srcs & BIT(i)) { 572 + status = readl_relaxed(adev->regs + 573 + ADM_CH_STATUS_SD(i, adev->ee)); 574 + 575 + /* if no result present, skip */ 576 + if (!(status & ADM_CH_STATUS_VALID)) 577 + continue; 578 + 579 + result = readl_relaxed(adev->regs + 580 + ADM_CH_RSLT(i, adev->ee)); 581 + 582 + /* no valid results, skip */ 583 + if (!(result & ADM_CH_RSLT_VALID)) 584 + continue; 585 + 586 + /* flag error if transaction was flushed or failed */ 587 + if (result & (ADM_CH_RSLT_ERR | ADM_CH_RSLT_FLUSH)) 588 + achan->error = 1; 589 + 590 + spin_lock_irqsave(&achan->vc.lock, flags); 591 + async_desc = achan->curr_txd; 592 + 593 + achan->curr_txd = NULL; 594 + 595 + if (async_desc) { 596 + vchan_cookie_complete(&async_desc->vd); 597 + 598 + /* kick off next DMA */ 599 + adm_start_dma(achan); 600 + } 601 + 602 + spin_unlock_irqrestore(&achan->vc.lock, flags); 603 + } 604 + } 605 + 606 + return IRQ_HANDLED; 607 + } 608 + 609 + /** 610 + * adm_tx_status - returns status of transaction 611 + * @chan: dma channel 612 + * @cookie: transaction cookie 613 + * @txstate: DMA transaction state 614 + * 615 + * Return status of dma transaction 616 + */ 617 + static enum dma_status adm_tx_status(struct dma_chan *chan, dma_cookie_t cookie, 618 + struct dma_tx_state *txstate) 619 + { 620 + struct adm_chan *achan = to_adm_chan(chan); 621 + struct virt_dma_desc *vd; 622 + enum dma_status ret; 623 + unsigned long flags; 624 + size_t residue = 0; 625 + 626 + ret = dma_cookie_status(chan, cookie, txstate); 627 + if (ret == DMA_COMPLETE || !txstate) 628 + return ret; 629 + 630 + spin_lock_irqsave(&achan->vc.lock, flags); 631 + 632 + vd = vchan_find_desc(&achan->vc, cookie); 633 + if (vd) 634 + residue = container_of(vd, struct adm_async_desc, vd)->length; 635 + 636 + spin_unlock_irqrestore(&achan->vc.lock, flags); 637 + 638 + /* 639 + * residue is either the full length if it is in the issued list, or 0 640 + * if it is in progress. We have no reliable way of determining 641 + * anything inbetween 642 + */ 643 + dma_set_residue(txstate, residue); 644 + 645 + if (achan->error) 646 + return DMA_ERROR; 647 + 648 + return ret; 649 + } 650 + 651 + /** 652 + * adm_issue_pending - starts pending transactions 653 + * @chan: dma channel 654 + * 655 + * Issues all pending transactions and starts DMA 656 + */ 657 + static void adm_issue_pending(struct dma_chan *chan) 658 + { 659 + struct adm_chan *achan = to_adm_chan(chan); 660 + unsigned long flags; 661 + 662 + spin_lock_irqsave(&achan->vc.lock, flags); 663 + 664 + if (vchan_issue_pending(&achan->vc) && !achan->curr_txd) 665 + adm_start_dma(achan); 666 + spin_unlock_irqrestore(&achan->vc.lock, flags); 667 + } 668 + 669 + /** 670 + * adm_dma_free_desc - free descriptor memory 671 + * @vd: virtual descriptor 672 + * 673 + */ 674 + static void adm_dma_free_desc(struct virt_dma_desc *vd) 675 + { 676 + struct adm_async_desc *async_desc = container_of(vd, 677 + struct adm_async_desc, vd); 678 + 679 + dma_unmap_single(async_desc->adev->dev, async_desc->dma_addr, 680 + async_desc->dma_len, DMA_TO_DEVICE); 681 + kfree(async_desc->cpl); 682 + kfree(async_desc); 683 + } 684 + 685 + static void adm_channel_init(struct adm_device *adev, struct adm_chan *achan, 686 + u32 index) 687 + { 688 + achan->id = index; 689 + achan->adev = adev; 690 + 691 + vchan_init(&achan->vc, &adev->common); 692 + achan->vc.desc_free = adm_dma_free_desc; 693 + } 694 + 695 + static int adm_dma_probe(struct platform_device *pdev) 696 + { 697 + struct adm_device *adev; 698 + int ret; 699 + u32 i; 700 + 701 + adev = devm_kzalloc(&pdev->dev, sizeof(*adev), GFP_KERNEL); 702 + if (!adev) 703 + return -ENOMEM; 704 + 705 + adev->dev = &pdev->dev; 706 + 707 + adev->regs = devm_platform_ioremap_resource(pdev, 0); 708 + if (IS_ERR(adev->regs)) 709 + return PTR_ERR(adev->regs); 710 + 711 + adev->irq = platform_get_irq(pdev, 0); 712 + if (adev->irq < 0) 713 + return adev->irq; 714 + 715 + ret = of_property_read_u32(pdev->dev.of_node, "qcom,ee", &adev->ee); 716 + if (ret) { 717 + dev_err(adev->dev, "Execution environment unspecified\n"); 718 + return ret; 719 + } 720 + 721 + adev->core_clk = devm_clk_get(adev->dev, "core"); 722 + if (IS_ERR(adev->core_clk)) 723 + return PTR_ERR(adev->core_clk); 724 + 725 + adev->iface_clk = devm_clk_get(adev->dev, "iface"); 726 + if (IS_ERR(adev->iface_clk)) 727 + return PTR_ERR(adev->iface_clk); 728 + 729 + adev->clk_reset = devm_reset_control_get_exclusive(&pdev->dev, "clk"); 730 + if (IS_ERR(adev->clk_reset)) { 731 + dev_err(adev->dev, "failed to get ADM0 reset\n"); 732 + return PTR_ERR(adev->clk_reset); 733 + } 734 + 735 + adev->c0_reset = devm_reset_control_get_exclusive(&pdev->dev, "c0"); 736 + if (IS_ERR(adev->c0_reset)) { 737 + dev_err(adev->dev, "failed to get ADM0 C0 reset\n"); 738 + return PTR_ERR(adev->c0_reset); 739 + } 740 + 741 + adev->c1_reset = devm_reset_control_get_exclusive(&pdev->dev, "c1"); 742 + if (IS_ERR(adev->c1_reset)) { 743 + dev_err(adev->dev, "failed to get ADM0 C1 reset\n"); 744 + return PTR_ERR(adev->c1_reset); 745 + } 746 + 747 + adev->c2_reset = devm_reset_control_get_exclusive(&pdev->dev, "c2"); 748 + if (IS_ERR(adev->c2_reset)) { 749 + dev_err(adev->dev, "failed to get ADM0 C2 reset\n"); 750 + return PTR_ERR(adev->c2_reset); 751 + } 752 + 753 + ret = clk_prepare_enable(adev->core_clk); 754 + if (ret) { 755 + dev_err(adev->dev, "failed to prepare/enable core clock\n"); 756 + return ret; 757 + } 758 + 759 + ret = clk_prepare_enable(adev->iface_clk); 760 + if (ret) { 761 + dev_err(adev->dev, "failed to prepare/enable iface clock\n"); 762 + goto err_disable_core_clk; 763 + } 764 + 765 + reset_control_assert(adev->clk_reset); 766 + reset_control_assert(adev->c0_reset); 767 + reset_control_assert(adev->c1_reset); 768 + reset_control_assert(adev->c2_reset); 769 + 770 + udelay(2); 771 + 772 + reset_control_deassert(adev->clk_reset); 773 + reset_control_deassert(adev->c0_reset); 774 + reset_control_deassert(adev->c1_reset); 775 + reset_control_deassert(adev->c2_reset); 776 + 777 + adev->channels = devm_kcalloc(adev->dev, ADM_MAX_CHANNELS, 778 + sizeof(*adev->channels), GFP_KERNEL); 779 + 780 + if (!adev->channels) { 781 + ret = -ENOMEM; 782 + goto err_disable_clks; 783 + } 784 + 785 + /* allocate and initialize channels */ 786 + INIT_LIST_HEAD(&adev->common.channels); 787 + 788 + for (i = 0; i < ADM_MAX_CHANNELS; i++) 789 + adm_channel_init(adev, &adev->channels[i], i); 790 + 791 + /* reset CRCIs */ 792 + for (i = 0; i < 16; i++) 793 + writel(ADM_CRCI_CTL_RST, adev->regs + 794 + ADM_CRCI_CTL(i, adev->ee)); 795 + 796 + /* configure client interfaces */ 797 + writel(ADM_CI_RANGE_START(0x40) | ADM_CI_RANGE_END(0xb0) | 798 + ADM_CI_BURST_8_WORDS, adev->regs + ADM_CI_CONF(0)); 799 + writel(ADM_CI_RANGE_START(0x2a) | ADM_CI_RANGE_END(0x2c) | 800 + ADM_CI_BURST_8_WORDS, adev->regs + ADM_CI_CONF(1)); 801 + writel(ADM_CI_RANGE_START(0x12) | ADM_CI_RANGE_END(0x28) | 802 + ADM_CI_BURST_8_WORDS, adev->regs + ADM_CI_CONF(2)); 803 + writel(ADM_GP_CTL_LP_EN | ADM_GP_CTL_LP_CNT(0xf), 804 + adev->regs + ADM_GP_CTL); 805 + 806 + ret = devm_request_irq(adev->dev, adev->irq, adm_dma_irq, 807 + 0, "adm_dma", adev); 808 + if (ret) 809 + goto err_disable_clks; 810 + 811 + platform_set_drvdata(pdev, adev); 812 + 813 + adev->common.dev = adev->dev; 814 + adev->common.dev->dma_parms = &adev->dma_parms; 815 + 816 + /* set capabilities */ 817 + dma_cap_zero(adev->common.cap_mask); 818 + dma_cap_set(DMA_SLAVE, adev->common.cap_mask); 819 + dma_cap_set(DMA_PRIVATE, adev->common.cap_mask); 820 + 821 + /* initialize dmaengine apis */ 822 + adev->common.directions = BIT(DMA_DEV_TO_MEM | DMA_MEM_TO_DEV); 823 + adev->common.residue_granularity = DMA_RESIDUE_GRANULARITY_DESCRIPTOR; 824 + adev->common.src_addr_widths = DMA_SLAVE_BUSWIDTH_4_BYTES; 825 + adev->common.dst_addr_widths = DMA_SLAVE_BUSWIDTH_4_BYTES; 826 + adev->common.device_free_chan_resources = adm_free_chan; 827 + adev->common.device_prep_slave_sg = adm_prep_slave_sg; 828 + adev->common.device_issue_pending = adm_issue_pending; 829 + adev->common.device_tx_status = adm_tx_status; 830 + adev->common.device_terminate_all = adm_terminate_all; 831 + adev->common.device_config = adm_slave_config; 832 + 833 + ret = dma_async_device_register(&adev->common); 834 + if (ret) { 835 + dev_err(adev->dev, "failed to register dma async device\n"); 836 + goto err_disable_clks; 837 + } 838 + 839 + ret = of_dma_controller_register(pdev->dev.of_node, 840 + of_dma_xlate_by_chan_id, 841 + &adev->common); 842 + if (ret) 843 + goto err_unregister_dma; 844 + 845 + return 0; 846 + 847 + err_unregister_dma: 848 + dma_async_device_unregister(&adev->common); 849 + err_disable_clks: 850 + clk_disable_unprepare(adev->iface_clk); 851 + err_disable_core_clk: 852 + clk_disable_unprepare(adev->core_clk); 853 + 854 + return ret; 855 + } 856 + 857 + static int adm_dma_remove(struct platform_device *pdev) 858 + { 859 + struct adm_device *adev = platform_get_drvdata(pdev); 860 + struct adm_chan *achan; 861 + u32 i; 862 + 863 + of_dma_controller_free(pdev->dev.of_node); 864 + dma_async_device_unregister(&adev->common); 865 + 866 + for (i = 0; i < ADM_MAX_CHANNELS; i++) { 867 + achan = &adev->channels[i]; 868 + 869 + /* mask IRQs for this channel/EE pair */ 870 + writel(0, adev->regs + ADM_CH_RSLT_CONF(achan->id, adev->ee)); 871 + 872 + tasklet_kill(&adev->channels[i].vc.task); 873 + adm_terminate_all(&adev->channels[i].vc.chan); 874 + } 875 + 876 + devm_free_irq(adev->dev, adev->irq, adev); 877 + 878 + clk_disable_unprepare(adev->core_clk); 879 + clk_disable_unprepare(adev->iface_clk); 880 + 881 + return 0; 882 + } 883 + 884 + static const struct of_device_id adm_of_match[] = { 885 + { .compatible = "qcom,adm", }, 886 + {} 887 + }; 888 + MODULE_DEVICE_TABLE(of, adm_of_match); 889 + 890 + static struct platform_driver adm_dma_driver = { 891 + .probe = adm_dma_probe, 892 + .remove = adm_dma_remove, 893 + .driver = { 894 + .name = "adm-dma-engine", 895 + .of_match_table = adm_of_match, 896 + }, 897 + }; 898 + 899 + module_platform_driver(adm_dma_driver); 900 + 901 + MODULE_AUTHOR("Andy Gross <agross@codeaurora.org>"); 902 + MODULE_DESCRIPTION("QCOM ADM DMA engine driver"); 903 + MODULE_LICENSE("GPL v2");