omap-dma.c revision b9e97822da374f52aaf99cb502f531ff2184b8f5
17bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King/* 27bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King * OMAP DMAengine support 37bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King * 47bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King * This program is free software; you can redistribute it and/or modify 57bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King * it under the terms of the GNU General Public License version 2 as 67bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King * published by the Free Software Foundation. 77bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King */ 87bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King#include <linux/dmaengine.h> 97bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King#include <linux/dma-mapping.h> 107bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King#include <linux/err.h> 117bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King#include <linux/init.h> 127bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King#include <linux/interrupt.h> 137bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King#include <linux/list.h> 147bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King#include <linux/module.h> 157bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King#include <linux/omap-dma.h> 167bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King#include <linux/platform_device.h> 177bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King#include <linux/slab.h> 187bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King#include <linux/spinlock.h> 198d30662aac256eb61bc2f1d9cf1191825ef96328Jon Hunter#include <linux/of_dma.h> 208d30662aac256eb61bc2f1d9cf1191825ef96328Jon Hunter#include <linux/of_device.h> 217bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King 227bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King#include "virt-dma.h" 237d7e1eba7e92c2f9c76db80adc24836e7a114bfbTony Lindgren 247bedaa5537604f34d1d63c5ec7891e559d2a61edRussell Kingstruct omap_dmadev { 257bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King struct dma_device ddev; 267bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King spinlock_t lock; 277bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King struct tasklet_struct task; 287bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King struct list_head pending; 291b416c4b41351c3eb8fc42dbb4cd8eba463c0813Russell King struct omap_system_dma_plat_info *plat; 307bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King}; 317bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King 327bedaa5537604f34d1d63c5ec7891e559d2a61edRussell Kingstruct omap_chan { 337bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King struct virt_dma_chan vc; 347bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King struct list_head node; 351b416c4b41351c3eb8fc42dbb4cd8eba463c0813Russell King struct omap_system_dma_plat_info *plat; 367bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King 377bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King struct dma_slave_config cfg; 387bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King unsigned dma_sig; 393a774ea91a5d05e7af58db6ae1ba298263c4a3d3Russell King bool cyclic; 402dcdf570936168d488acf90be9b04a3d32dafce7Peter Ujfalusi bool paused; 417bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King 427bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King int dma_ch; 437bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King struct omap_desc *desc; 447bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King unsigned sgidx; 457bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King}; 467bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King 477bedaa5537604f34d1d63c5ec7891e559d2a61edRussell Kingstruct omap_sg { 487bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King dma_addr_t addr; 497bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King uint32_t en; /* number of elements (24-bit) */ 507bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King uint32_t fn; /* number of frames (16-bit) */ 517bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King}; 527bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King 537bedaa5537604f34d1d63c5ec7891e559d2a61edRussell Kingstruct omap_desc { 547bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King struct virt_dma_desc vd; 557bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King enum dma_transfer_direction dir; 567bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King dma_addr_t dev_addr; 577bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King 587c836bc7f9f71d62a8dc50712db122a69b405486Russell King int16_t fi; /* for OMAP_DMA_SYNC_PACKET */ 597bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King uint8_t es; /* OMAP_DMA_DATA_TYPE_xxx */ 607bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King uint8_t sync_mode; /* OMAP_DMA_SYNC_xxx */ 617bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King uint8_t sync_type; /* OMAP_DMA_xxx_SYNC* */ 627bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King uint8_t periph_port; /* Peripheral port */ 637bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King 647bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King unsigned sglen; 657bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King struct omap_sg sg[0]; 667bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King}; 677bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King 687bedaa5537604f34d1d63c5ec7891e559d2a61edRussell Kingstatic const unsigned es_bytes[] = { 697bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King [OMAP_DMA_DATA_TYPE_S8] = 1, 707bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King [OMAP_DMA_DATA_TYPE_S16] = 2, 717bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King [OMAP_DMA_DATA_TYPE_S32] = 4, 727bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King}; 737bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King 748d30662aac256eb61bc2f1d9cf1191825ef96328Jon Hunterstatic struct of_dma_filter_info omap_dma_info = { 758d30662aac256eb61bc2f1d9cf1191825ef96328Jon Hunter .filter_fn = omap_dma_filter_fn, 768d30662aac256eb61bc2f1d9cf1191825ef96328Jon Hunter}; 778d30662aac256eb61bc2f1d9cf1191825ef96328Jon Hunter 787bedaa5537604f34d1d63c5ec7891e559d2a61edRussell Kingstatic inline struct omap_dmadev *to_omap_dma_dev(struct dma_device *d) 797bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King{ 807bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King return container_of(d, struct omap_dmadev, ddev); 817bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King} 827bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King 837bedaa5537604f34d1d63c5ec7891e559d2a61edRussell Kingstatic inline struct omap_chan *to_omap_dma_chan(struct dma_chan *c) 847bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King{ 857bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King return container_of(c, struct omap_chan, vc.chan); 867bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King} 877bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King 887bedaa5537604f34d1d63c5ec7891e559d2a61edRussell Kingstatic inline struct omap_desc *to_omap_dma_desc(struct dma_async_tx_descriptor *t) 897bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King{ 907bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King return container_of(t, struct omap_desc, vd.tx); 917bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King} 927bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King 937bedaa5537604f34d1d63c5ec7891e559d2a61edRussell Kingstatic void omap_dma_desc_free(struct virt_dma_desc *vd) 947bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King{ 957bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King kfree(container_of(vd, struct omap_desc, vd)); 967bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King} 977bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King 987bedaa5537604f34d1d63c5ec7891e559d2a61edRussell Kingstatic void omap_dma_start_sg(struct omap_chan *c, struct omap_desc *d, 997bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King unsigned idx) 1007bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King{ 1017bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King struct omap_sg *sg = d->sg + idx; 102b9e97822da374f52aaf99cb502f531ff2184b8f5Russell King uint32_t val; 103b9e97822da374f52aaf99cb502f531ff2184b8f5Russell King 104b9e97822da374f52aaf99cb502f531ff2184b8f5Russell King if (d->dir == DMA_DEV_TO_MEM) { 105b9e97822da374f52aaf99cb502f531ff2184b8f5Russell King if (dma_omap1()) { 106b9e97822da374f52aaf99cb502f531ff2184b8f5Russell King val = c->plat->dma_read(CSDP, c->dma_ch); 107b9e97822da374f52aaf99cb502f531ff2184b8f5Russell King val &= ~(0x1f << 9); 108b9e97822da374f52aaf99cb502f531ff2184b8f5Russell King val |= OMAP_DMA_PORT_EMIFF << 9; 109b9e97822da374f52aaf99cb502f531ff2184b8f5Russell King c->plat->dma_write(val, CSDP, c->dma_ch); 110b9e97822da374f52aaf99cb502f531ff2184b8f5Russell King } 1117bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King 112b9e97822da374f52aaf99cb502f531ff2184b8f5Russell King val = c->plat->dma_read(CCR, c->dma_ch); 113b9e97822da374f52aaf99cb502f531ff2184b8f5Russell King val &= ~(0x03 << 14); 114b9e97822da374f52aaf99cb502f531ff2184b8f5Russell King val |= OMAP_DMA_AMODE_POST_INC << 14; 115b9e97822da374f52aaf99cb502f531ff2184b8f5Russell King c->plat->dma_write(val, CCR, c->dma_ch); 116b9e97822da374f52aaf99cb502f531ff2184b8f5Russell King 117b9e97822da374f52aaf99cb502f531ff2184b8f5Russell King c->plat->dma_write(sg->addr, CDSA, c->dma_ch); 118b9e97822da374f52aaf99cb502f531ff2184b8f5Russell King c->plat->dma_write(0, CDEI, c->dma_ch); 119b9e97822da374f52aaf99cb502f531ff2184b8f5Russell King c->plat->dma_write(0, CDFI, c->dma_ch); 120b9e97822da374f52aaf99cb502f531ff2184b8f5Russell King } else { 121b9e97822da374f52aaf99cb502f531ff2184b8f5Russell King if (dma_omap1()) { 122b9e97822da374f52aaf99cb502f531ff2184b8f5Russell King val = c->plat->dma_read(CSDP, c->dma_ch); 123b9e97822da374f52aaf99cb502f531ff2184b8f5Russell King val &= ~(0x1f << 2); 124b9e97822da374f52aaf99cb502f531ff2184b8f5Russell King val |= OMAP_DMA_PORT_EMIFF << 2; 125b9e97822da374f52aaf99cb502f531ff2184b8f5Russell King c->plat->dma_write(val, CSDP, c->dma_ch); 126b9e97822da374f52aaf99cb502f531ff2184b8f5Russell King } 127b9e97822da374f52aaf99cb502f531ff2184b8f5Russell King 128b9e97822da374f52aaf99cb502f531ff2184b8f5Russell King val = c->plat->dma_read(CCR, c->dma_ch); 129b9e97822da374f52aaf99cb502f531ff2184b8f5Russell King val &= ~(0x03 << 12); 130b9e97822da374f52aaf99cb502f531ff2184b8f5Russell King val |= OMAP_DMA_AMODE_POST_INC << 12; 131b9e97822da374f52aaf99cb502f531ff2184b8f5Russell King c->plat->dma_write(val, CCR, c->dma_ch); 132b9e97822da374f52aaf99cb502f531ff2184b8f5Russell King 133b9e97822da374f52aaf99cb502f531ff2184b8f5Russell King c->plat->dma_write(sg->addr, CSSA, c->dma_ch); 134b9e97822da374f52aaf99cb502f531ff2184b8f5Russell King c->plat->dma_write(0, CSEI, c->dma_ch); 135b9e97822da374f52aaf99cb502f531ff2184b8f5Russell King c->plat->dma_write(0, CSFI, c->dma_ch); 136b9e97822da374f52aaf99cb502f531ff2184b8f5Russell King } 137b9e97822da374f52aaf99cb502f531ff2184b8f5Russell King 138b9e97822da374f52aaf99cb502f531ff2184b8f5Russell King val = c->plat->dma_read(CSDP, c->dma_ch); 139b9e97822da374f52aaf99cb502f531ff2184b8f5Russell King val &= ~0x03; 140b9e97822da374f52aaf99cb502f531ff2184b8f5Russell King val |= d->es; 141b9e97822da374f52aaf99cb502f531ff2184b8f5Russell King c->plat->dma_write(val, CSDP, c->dma_ch); 142b9e97822da374f52aaf99cb502f531ff2184b8f5Russell King 143b9e97822da374f52aaf99cb502f531ff2184b8f5Russell King if (dma_omap1()) { 144b9e97822da374f52aaf99cb502f531ff2184b8f5Russell King val = c->plat->dma_read(CCR, c->dma_ch); 145b9e97822da374f52aaf99cb502f531ff2184b8f5Russell King val &= ~(1 << 5); 146b9e97822da374f52aaf99cb502f531ff2184b8f5Russell King if (d->sync_mode == OMAP_DMA_SYNC_FRAME) 147b9e97822da374f52aaf99cb502f531ff2184b8f5Russell King val |= 1 << 5; 148b9e97822da374f52aaf99cb502f531ff2184b8f5Russell King c->plat->dma_write(val, CCR, c->dma_ch); 149b9e97822da374f52aaf99cb502f531ff2184b8f5Russell King 150b9e97822da374f52aaf99cb502f531ff2184b8f5Russell King val = c->plat->dma_read(CCR2, c->dma_ch); 151b9e97822da374f52aaf99cb502f531ff2184b8f5Russell King val &= ~(1 << 2); 152b9e97822da374f52aaf99cb502f531ff2184b8f5Russell King if (d->sync_mode == OMAP_DMA_SYNC_BLOCK) 153b9e97822da374f52aaf99cb502f531ff2184b8f5Russell King val |= 1 << 2; 154b9e97822da374f52aaf99cb502f531ff2184b8f5Russell King c->plat->dma_write(val, CCR2, c->dma_ch); 155b9e97822da374f52aaf99cb502f531ff2184b8f5Russell King } else if (c->dma_sig) { 156b9e97822da374f52aaf99cb502f531ff2184b8f5Russell King val = c->plat->dma_read(CCR, c->dma_ch); 157b9e97822da374f52aaf99cb502f531ff2184b8f5Russell King 158b9e97822da374f52aaf99cb502f531ff2184b8f5Russell King /* DMA_SYNCHRO_CONTROL_UPPER depends on the channel number */ 159b9e97822da374f52aaf99cb502f531ff2184b8f5Russell King val &= ~((1 << 23) | (3 << 19) | 0x1f); 160b9e97822da374f52aaf99cb502f531ff2184b8f5Russell King val |= (c->dma_sig & ~0x1f) << 14; 161b9e97822da374f52aaf99cb502f531ff2184b8f5Russell King val |= c->dma_sig & 0x1f; 162b9e97822da374f52aaf99cb502f531ff2184b8f5Russell King 163b9e97822da374f52aaf99cb502f531ff2184b8f5Russell King if (d->sync_mode & OMAP_DMA_SYNC_FRAME) 164b9e97822da374f52aaf99cb502f531ff2184b8f5Russell King val |= 1 << 5; 165b9e97822da374f52aaf99cb502f531ff2184b8f5Russell King else 166b9e97822da374f52aaf99cb502f531ff2184b8f5Russell King val &= ~(1 << 5); 167b9e97822da374f52aaf99cb502f531ff2184b8f5Russell King 168b9e97822da374f52aaf99cb502f531ff2184b8f5Russell King if (d->sync_mode & OMAP_DMA_SYNC_BLOCK) 169b9e97822da374f52aaf99cb502f531ff2184b8f5Russell King val |= 1 << 18; 170b9e97822da374f52aaf99cb502f531ff2184b8f5Russell King else 171b9e97822da374f52aaf99cb502f531ff2184b8f5Russell King val &= ~(1 << 18); 172b9e97822da374f52aaf99cb502f531ff2184b8f5Russell King 173b9e97822da374f52aaf99cb502f531ff2184b8f5Russell King switch (d->sync_type) { 174b9e97822da374f52aaf99cb502f531ff2184b8f5Russell King case OMAP_DMA_DST_SYNC_PREFETCH: 175b9e97822da374f52aaf99cb502f531ff2184b8f5Russell King val &= ~(1 << 24); /* dest synch */ 176b9e97822da374f52aaf99cb502f531ff2184b8f5Russell King val |= 1 << 23; /* Prefetch */ 177b9e97822da374f52aaf99cb502f531ff2184b8f5Russell King break; 178b9e97822da374f52aaf99cb502f531ff2184b8f5Russell King case 0: 179b9e97822da374f52aaf99cb502f531ff2184b8f5Russell King val &= ~(1 << 24); /* dest synch */ 180b9e97822da374f52aaf99cb502f531ff2184b8f5Russell King break; 181b9e97822da374f52aaf99cb502f531ff2184b8f5Russell King default: 182b9e97822da374f52aaf99cb502f531ff2184b8f5Russell King val |= 1 << 24; /* source synch */ 183b9e97822da374f52aaf99cb502f531ff2184b8f5Russell King break; 184b9e97822da374f52aaf99cb502f531ff2184b8f5Russell King } 185b9e97822da374f52aaf99cb502f531ff2184b8f5Russell King c->plat->dma_write(val, CCR, c->dma_ch); 186b9e97822da374f52aaf99cb502f531ff2184b8f5Russell King } 1877bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King 188b9e97822da374f52aaf99cb502f531ff2184b8f5Russell King c->plat->dma_write(sg->en, CEN, c->dma_ch); 189b9e97822da374f52aaf99cb502f531ff2184b8f5Russell King c->plat->dma_write(sg->fn, CFN, c->dma_ch); 1907bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King 1917bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King omap_start_dma(c->dma_ch); 1927bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King} 1937bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King 1947bedaa5537604f34d1d63c5ec7891e559d2a61edRussell Kingstatic void omap_dma_start_desc(struct omap_chan *c) 1957bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King{ 1967bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King struct virt_dma_desc *vd = vchan_next_desc(&c->vc); 1977bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King struct omap_desc *d; 198b9e97822da374f52aaf99cb502f531ff2184b8f5Russell King uint32_t val; 1997bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King 2007bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King if (!vd) { 2017bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King c->desc = NULL; 2027bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King return; 2037bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King } 2047bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King 2057bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King list_del(&vd->node); 2067bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King 2077bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King c->desc = d = to_omap_dma_desc(&vd->tx); 2087bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King c->sgidx = 0; 2097bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King 210b9e97822da374f52aaf99cb502f531ff2184b8f5Russell King if (d->dir == DMA_DEV_TO_MEM) { 211b9e97822da374f52aaf99cb502f531ff2184b8f5Russell King if (dma_omap1()) { 212b9e97822da374f52aaf99cb502f531ff2184b8f5Russell King val = c->plat->dma_read(CSDP, c->dma_ch); 213b9e97822da374f52aaf99cb502f531ff2184b8f5Russell King val &= ~(0x1f << 2); 214b9e97822da374f52aaf99cb502f531ff2184b8f5Russell King val |= d->periph_port << 2; 215b9e97822da374f52aaf99cb502f531ff2184b8f5Russell King c->plat->dma_write(val, CSDP, c->dma_ch); 216b9e97822da374f52aaf99cb502f531ff2184b8f5Russell King } 217b9e97822da374f52aaf99cb502f531ff2184b8f5Russell King 218b9e97822da374f52aaf99cb502f531ff2184b8f5Russell King val = c->plat->dma_read(CCR, c->dma_ch); 219b9e97822da374f52aaf99cb502f531ff2184b8f5Russell King val &= ~(0x03 << 12); 220b9e97822da374f52aaf99cb502f531ff2184b8f5Russell King val |= OMAP_DMA_AMODE_CONSTANT << 12; 221b9e97822da374f52aaf99cb502f531ff2184b8f5Russell King c->plat->dma_write(val, CCR, c->dma_ch); 222b9e97822da374f52aaf99cb502f531ff2184b8f5Russell King 223b9e97822da374f52aaf99cb502f531ff2184b8f5Russell King c->plat->dma_write(d->dev_addr, CSSA, c->dma_ch); 224b9e97822da374f52aaf99cb502f531ff2184b8f5Russell King c->plat->dma_write(0, CSEI, c->dma_ch); 225b9e97822da374f52aaf99cb502f531ff2184b8f5Russell King c->plat->dma_write(d->fi, CSFI, c->dma_ch); 226b9e97822da374f52aaf99cb502f531ff2184b8f5Russell King } else { 227b9e97822da374f52aaf99cb502f531ff2184b8f5Russell King if (dma_omap1()) { 228b9e97822da374f52aaf99cb502f531ff2184b8f5Russell King val = c->plat->dma_read(CSDP, c->dma_ch); 229b9e97822da374f52aaf99cb502f531ff2184b8f5Russell King val &= ~(0x1f << 9); 230b9e97822da374f52aaf99cb502f531ff2184b8f5Russell King val |= d->periph_port << 9; 231b9e97822da374f52aaf99cb502f531ff2184b8f5Russell King c->plat->dma_write(val, CSDP, c->dma_ch); 232b9e97822da374f52aaf99cb502f531ff2184b8f5Russell King } 233b9e97822da374f52aaf99cb502f531ff2184b8f5Russell King 234b9e97822da374f52aaf99cb502f531ff2184b8f5Russell King val = c->plat->dma_read(CCR, c->dma_ch); 235b9e97822da374f52aaf99cb502f531ff2184b8f5Russell King val &= ~(0x03 << 14); 236b9e97822da374f52aaf99cb502f531ff2184b8f5Russell King val |= OMAP_DMA_AMODE_CONSTANT << 14; 237b9e97822da374f52aaf99cb502f531ff2184b8f5Russell King c->plat->dma_write(val, CCR, c->dma_ch); 238b9e97822da374f52aaf99cb502f531ff2184b8f5Russell King 239b9e97822da374f52aaf99cb502f531ff2184b8f5Russell King c->plat->dma_write(d->dev_addr, CDSA, c->dma_ch); 240b9e97822da374f52aaf99cb502f531ff2184b8f5Russell King c->plat->dma_write(0, CDEI, c->dma_ch); 241b9e97822da374f52aaf99cb502f531ff2184b8f5Russell King c->plat->dma_write(d->fi, CDFI, c->dma_ch); 242b9e97822da374f52aaf99cb502f531ff2184b8f5Russell King } 2437bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King 2447bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King omap_dma_start_sg(c, d, 0); 2457bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King} 2467bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King 2477bedaa5537604f34d1d63c5ec7891e559d2a61edRussell Kingstatic void omap_dma_callback(int ch, u16 status, void *data) 2487bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King{ 2497bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King struct omap_chan *c = data; 2507bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King struct omap_desc *d; 2517bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King unsigned long flags; 2527bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King 2537bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King spin_lock_irqsave(&c->vc.lock, flags); 2547bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King d = c->desc; 2557bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King if (d) { 2563a774ea91a5d05e7af58db6ae1ba298263c4a3d3Russell King if (!c->cyclic) { 2573a774ea91a5d05e7af58db6ae1ba298263c4a3d3Russell King if (++c->sgidx < d->sglen) { 2583a774ea91a5d05e7af58db6ae1ba298263c4a3d3Russell King omap_dma_start_sg(c, d, c->sgidx); 2593a774ea91a5d05e7af58db6ae1ba298263c4a3d3Russell King } else { 2603a774ea91a5d05e7af58db6ae1ba298263c4a3d3Russell King omap_dma_start_desc(c); 2613a774ea91a5d05e7af58db6ae1ba298263c4a3d3Russell King vchan_cookie_complete(&d->vd); 2623a774ea91a5d05e7af58db6ae1ba298263c4a3d3Russell King } 2637bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King } else { 2643a774ea91a5d05e7af58db6ae1ba298263c4a3d3Russell King vchan_cyclic_callback(&d->vd); 2657bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King } 2667bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King } 2677bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King spin_unlock_irqrestore(&c->vc.lock, flags); 2687bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King} 2697bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King 2707bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King/* 2717bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King * This callback schedules all pending channels. We could be more 2727bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King * clever here by postponing allocation of the real DMA channels to 2737bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King * this point, and freeing them when our virtual channel becomes idle. 2747bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King * 2757bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King * We would then need to deal with 'all channels in-use' 2767bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King */ 2777bedaa5537604f34d1d63c5ec7891e559d2a61edRussell Kingstatic void omap_dma_sched(unsigned long data) 2787bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King{ 2797bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King struct omap_dmadev *d = (struct omap_dmadev *)data; 2807bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King LIST_HEAD(head); 2817bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King 2827bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King spin_lock_irq(&d->lock); 2837bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King list_splice_tail_init(&d->pending, &head); 2847bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King spin_unlock_irq(&d->lock); 2857bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King 2867bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King while (!list_empty(&head)) { 2877bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King struct omap_chan *c = list_first_entry(&head, 2887bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King struct omap_chan, node); 2897bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King 2907bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King spin_lock_irq(&c->vc.lock); 2917bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King list_del_init(&c->node); 2927bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King omap_dma_start_desc(c); 2937bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King spin_unlock_irq(&c->vc.lock); 2947bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King } 2957bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King} 2967bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King 2977bedaa5537604f34d1d63c5ec7891e559d2a61edRussell Kingstatic int omap_dma_alloc_chan_resources(struct dma_chan *chan) 2987bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King{ 2997bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King struct omap_chan *c = to_omap_dma_chan(chan); 3007bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King 3019e2f7d827912609a71a53d625ee27d29dfbf87e0Ezequiel Garcia dev_dbg(c->vc.chan.device->dev, "allocating channel for %u\n", c->dma_sig); 3027bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King 3037bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King return omap_request_dma(c->dma_sig, "DMA engine", 3047bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King omap_dma_callback, c, &c->dma_ch); 3057bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King} 3067bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King 3077bedaa5537604f34d1d63c5ec7891e559d2a61edRussell Kingstatic void omap_dma_free_chan_resources(struct dma_chan *chan) 3087bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King{ 3097bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King struct omap_chan *c = to_omap_dma_chan(chan); 3107bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King 3117bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King vchan_free_chan_resources(&c->vc); 3127bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King omap_free_dma(c->dma_ch); 3137bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King 3149e2f7d827912609a71a53d625ee27d29dfbf87e0Ezequiel Garcia dev_dbg(c->vc.chan.device->dev, "freeing channel for %u\n", c->dma_sig); 3157bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King} 3167bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King 3173850e22f5146d2ff5b66f1b7460d4720d5f1b6c7Russell Kingstatic size_t omap_dma_sg_size(struct omap_sg *sg) 3183850e22f5146d2ff5b66f1b7460d4720d5f1b6c7Russell King{ 3193850e22f5146d2ff5b66f1b7460d4720d5f1b6c7Russell King return sg->en * sg->fn; 3203850e22f5146d2ff5b66f1b7460d4720d5f1b6c7Russell King} 3213850e22f5146d2ff5b66f1b7460d4720d5f1b6c7Russell King 3223850e22f5146d2ff5b66f1b7460d4720d5f1b6c7Russell Kingstatic size_t omap_dma_desc_size(struct omap_desc *d) 3233850e22f5146d2ff5b66f1b7460d4720d5f1b6c7Russell King{ 3243850e22f5146d2ff5b66f1b7460d4720d5f1b6c7Russell King unsigned i; 3253850e22f5146d2ff5b66f1b7460d4720d5f1b6c7Russell King size_t size; 3263850e22f5146d2ff5b66f1b7460d4720d5f1b6c7Russell King 3273850e22f5146d2ff5b66f1b7460d4720d5f1b6c7Russell King for (size = i = 0; i < d->sglen; i++) 3283850e22f5146d2ff5b66f1b7460d4720d5f1b6c7Russell King size += omap_dma_sg_size(&d->sg[i]); 3293850e22f5146d2ff5b66f1b7460d4720d5f1b6c7Russell King 3303850e22f5146d2ff5b66f1b7460d4720d5f1b6c7Russell King return size * es_bytes[d->es]; 3313850e22f5146d2ff5b66f1b7460d4720d5f1b6c7Russell King} 3323850e22f5146d2ff5b66f1b7460d4720d5f1b6c7Russell King 3333850e22f5146d2ff5b66f1b7460d4720d5f1b6c7Russell Kingstatic size_t omap_dma_desc_size_pos(struct omap_desc *d, dma_addr_t addr) 3343850e22f5146d2ff5b66f1b7460d4720d5f1b6c7Russell King{ 3353850e22f5146d2ff5b66f1b7460d4720d5f1b6c7Russell King unsigned i; 3363850e22f5146d2ff5b66f1b7460d4720d5f1b6c7Russell King size_t size, es_size = es_bytes[d->es]; 3373850e22f5146d2ff5b66f1b7460d4720d5f1b6c7Russell King 3383850e22f5146d2ff5b66f1b7460d4720d5f1b6c7Russell King for (size = i = 0; i < d->sglen; i++) { 3393850e22f5146d2ff5b66f1b7460d4720d5f1b6c7Russell King size_t this_size = omap_dma_sg_size(&d->sg[i]) * es_size; 3403850e22f5146d2ff5b66f1b7460d4720d5f1b6c7Russell King 3413850e22f5146d2ff5b66f1b7460d4720d5f1b6c7Russell King if (size) 3423850e22f5146d2ff5b66f1b7460d4720d5f1b6c7Russell King size += this_size; 3433850e22f5146d2ff5b66f1b7460d4720d5f1b6c7Russell King else if (addr >= d->sg[i].addr && 3443850e22f5146d2ff5b66f1b7460d4720d5f1b6c7Russell King addr < d->sg[i].addr + this_size) 3453850e22f5146d2ff5b66f1b7460d4720d5f1b6c7Russell King size += d->sg[i].addr + this_size - addr; 3463850e22f5146d2ff5b66f1b7460d4720d5f1b6c7Russell King } 3473850e22f5146d2ff5b66f1b7460d4720d5f1b6c7Russell King return size; 3483850e22f5146d2ff5b66f1b7460d4720d5f1b6c7Russell King} 3493850e22f5146d2ff5b66f1b7460d4720d5f1b6c7Russell King 3507bedaa5537604f34d1d63c5ec7891e559d2a61edRussell Kingstatic enum dma_status omap_dma_tx_status(struct dma_chan *chan, 3517bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King dma_cookie_t cookie, struct dma_tx_state *txstate) 3527bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King{ 3533850e22f5146d2ff5b66f1b7460d4720d5f1b6c7Russell King struct omap_chan *c = to_omap_dma_chan(chan); 3543850e22f5146d2ff5b66f1b7460d4720d5f1b6c7Russell King struct virt_dma_desc *vd; 3553850e22f5146d2ff5b66f1b7460d4720d5f1b6c7Russell King enum dma_status ret; 3563850e22f5146d2ff5b66f1b7460d4720d5f1b6c7Russell King unsigned long flags; 3573850e22f5146d2ff5b66f1b7460d4720d5f1b6c7Russell King 3583850e22f5146d2ff5b66f1b7460d4720d5f1b6c7Russell King ret = dma_cookie_status(chan, cookie, txstate); 3597cce5083b738e3e693abe082d9958686bcb88d32Vinod Koul if (ret == DMA_COMPLETE || !txstate) 3603850e22f5146d2ff5b66f1b7460d4720d5f1b6c7Russell King return ret; 3613850e22f5146d2ff5b66f1b7460d4720d5f1b6c7Russell King 3623850e22f5146d2ff5b66f1b7460d4720d5f1b6c7Russell King spin_lock_irqsave(&c->vc.lock, flags); 3633850e22f5146d2ff5b66f1b7460d4720d5f1b6c7Russell King vd = vchan_find_desc(&c->vc, cookie); 3643850e22f5146d2ff5b66f1b7460d4720d5f1b6c7Russell King if (vd) { 3653850e22f5146d2ff5b66f1b7460d4720d5f1b6c7Russell King txstate->residue = omap_dma_desc_size(to_omap_dma_desc(&vd->tx)); 3663850e22f5146d2ff5b66f1b7460d4720d5f1b6c7Russell King } else if (c->desc && c->desc->vd.tx.cookie == cookie) { 3673850e22f5146d2ff5b66f1b7460d4720d5f1b6c7Russell King struct omap_desc *d = c->desc; 3683850e22f5146d2ff5b66f1b7460d4720d5f1b6c7Russell King dma_addr_t pos; 3693850e22f5146d2ff5b66f1b7460d4720d5f1b6c7Russell King 3703850e22f5146d2ff5b66f1b7460d4720d5f1b6c7Russell King if (d->dir == DMA_MEM_TO_DEV) 3713850e22f5146d2ff5b66f1b7460d4720d5f1b6c7Russell King pos = omap_get_dma_src_pos(c->dma_ch); 3723850e22f5146d2ff5b66f1b7460d4720d5f1b6c7Russell King else if (d->dir == DMA_DEV_TO_MEM) 3733850e22f5146d2ff5b66f1b7460d4720d5f1b6c7Russell King pos = omap_get_dma_dst_pos(c->dma_ch); 3743850e22f5146d2ff5b66f1b7460d4720d5f1b6c7Russell King else 3753850e22f5146d2ff5b66f1b7460d4720d5f1b6c7Russell King pos = 0; 3763850e22f5146d2ff5b66f1b7460d4720d5f1b6c7Russell King 3773850e22f5146d2ff5b66f1b7460d4720d5f1b6c7Russell King txstate->residue = omap_dma_desc_size_pos(d, pos); 3783850e22f5146d2ff5b66f1b7460d4720d5f1b6c7Russell King } else { 3793850e22f5146d2ff5b66f1b7460d4720d5f1b6c7Russell King txstate->residue = 0; 3803850e22f5146d2ff5b66f1b7460d4720d5f1b6c7Russell King } 3813850e22f5146d2ff5b66f1b7460d4720d5f1b6c7Russell King spin_unlock_irqrestore(&c->vc.lock, flags); 3823850e22f5146d2ff5b66f1b7460d4720d5f1b6c7Russell King 3833850e22f5146d2ff5b66f1b7460d4720d5f1b6c7Russell King return ret; 3847bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King} 3857bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King 3867bedaa5537604f34d1d63c5ec7891e559d2a61edRussell Kingstatic void omap_dma_issue_pending(struct dma_chan *chan) 3877bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King{ 3887bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King struct omap_chan *c = to_omap_dma_chan(chan); 3897bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King unsigned long flags; 3907bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King 3917bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King spin_lock_irqsave(&c->vc.lock, flags); 3927bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King if (vchan_issue_pending(&c->vc) && !c->desc) { 393765024697807ad1e1cac332aa891253ca4a339daPeter Ujfalusi /* 394765024697807ad1e1cac332aa891253ca4a339daPeter Ujfalusi * c->cyclic is used only by audio and in this case the DMA need 395765024697807ad1e1cac332aa891253ca4a339daPeter Ujfalusi * to be started without delay. 396765024697807ad1e1cac332aa891253ca4a339daPeter Ujfalusi */ 397765024697807ad1e1cac332aa891253ca4a339daPeter Ujfalusi if (!c->cyclic) { 398765024697807ad1e1cac332aa891253ca4a339daPeter Ujfalusi struct omap_dmadev *d = to_omap_dma_dev(chan->device); 399765024697807ad1e1cac332aa891253ca4a339daPeter Ujfalusi spin_lock(&d->lock); 400765024697807ad1e1cac332aa891253ca4a339daPeter Ujfalusi if (list_empty(&c->node)) 401765024697807ad1e1cac332aa891253ca4a339daPeter Ujfalusi list_add_tail(&c->node, &d->pending); 402765024697807ad1e1cac332aa891253ca4a339daPeter Ujfalusi spin_unlock(&d->lock); 403765024697807ad1e1cac332aa891253ca4a339daPeter Ujfalusi tasklet_schedule(&d->task); 404765024697807ad1e1cac332aa891253ca4a339daPeter Ujfalusi } else { 405765024697807ad1e1cac332aa891253ca4a339daPeter Ujfalusi omap_dma_start_desc(c); 406765024697807ad1e1cac332aa891253ca4a339daPeter Ujfalusi } 4077bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King } 4087bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King spin_unlock_irqrestore(&c->vc.lock, flags); 4097bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King} 4107bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King 4117bedaa5537604f34d1d63c5ec7891e559d2a61edRussell Kingstatic struct dma_async_tx_descriptor *omap_dma_prep_slave_sg( 4127bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King struct dma_chan *chan, struct scatterlist *sgl, unsigned sglen, 4137bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King enum dma_transfer_direction dir, unsigned long tx_flags, void *context) 4147bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King{ 4157bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King struct omap_chan *c = to_omap_dma_chan(chan); 4167bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King enum dma_slave_buswidth dev_width; 4177bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King struct scatterlist *sgent; 4187bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King struct omap_desc *d; 4197bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King dma_addr_t dev_addr; 4207bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King unsigned i, j = 0, es, en, frame_bytes, sync_type; 4217bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King u32 burst; 4227bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King 4237bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King if (dir == DMA_DEV_TO_MEM) { 4247bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King dev_addr = c->cfg.src_addr; 4257bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King dev_width = c->cfg.src_addr_width; 4267bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King burst = c->cfg.src_maxburst; 4277bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King sync_type = OMAP_DMA_SRC_SYNC; 4287bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King } else if (dir == DMA_MEM_TO_DEV) { 4297bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King dev_addr = c->cfg.dst_addr; 4307bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King dev_width = c->cfg.dst_addr_width; 4317bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King burst = c->cfg.dst_maxburst; 4327bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King sync_type = OMAP_DMA_DST_SYNC; 4337bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King } else { 4347bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King dev_err(chan->device->dev, "%s: bad direction?\n", __func__); 4357bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King return NULL; 4367bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King } 4377bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King 4387bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King /* Bus width translates to the element size (ES) */ 4397bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King switch (dev_width) { 4407bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King case DMA_SLAVE_BUSWIDTH_1_BYTE: 4417bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King es = OMAP_DMA_DATA_TYPE_S8; 4427bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King break; 4437bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King case DMA_SLAVE_BUSWIDTH_2_BYTES: 4447bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King es = OMAP_DMA_DATA_TYPE_S16; 4457bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King break; 4467bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King case DMA_SLAVE_BUSWIDTH_4_BYTES: 4477bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King es = OMAP_DMA_DATA_TYPE_S32; 4487bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King break; 4497bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King default: /* not reached */ 4507bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King return NULL; 4517bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King } 4527bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King 4537bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King /* Now allocate and setup the descriptor. */ 4547bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King d = kzalloc(sizeof(*d) + sglen * sizeof(d->sg[0]), GFP_ATOMIC); 4557bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King if (!d) 4567bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King return NULL; 4577bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King 4587bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King d->dir = dir; 4597bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King d->dev_addr = dev_addr; 4607bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King d->es = es; 4617bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King d->sync_mode = OMAP_DMA_SYNC_FRAME; 4627bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King d->sync_type = sync_type; 4637bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King d->periph_port = OMAP_DMA_PORT_TIPB; 4647bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King 4657bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King /* 4667bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King * Build our scatterlist entries: each contains the address, 4677bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King * the number of elements (EN) in each frame, and the number of 4687bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King * frames (FN). Number of bytes for this entry = ES * EN * FN. 4697bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King * 4707bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King * Burst size translates to number of elements with frame sync. 4717bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King * Note: DMA engine defines burst to be the number of dev-width 4727bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King * transfers. 4737bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King */ 4747bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King en = burst; 4757bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King frame_bytes = es_bytes[es] * en; 4767bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King for_each_sg(sgl, sgent, sglen, i) { 4777bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King d->sg[j].addr = sg_dma_address(sgent); 4787bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King d->sg[j].en = en; 4797bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King d->sg[j].fn = sg_dma_len(sgent) / frame_bytes; 4807bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King j++; 4817bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King } 4827bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King 4837bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King d->sglen = j; 4847bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King 4857bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King return vchan_tx_prep(&c->vc, &d->vd, tx_flags); 4867bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King} 4877bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King 4883a774ea91a5d05e7af58db6ae1ba298263c4a3d3Russell Kingstatic struct dma_async_tx_descriptor *omap_dma_prep_dma_cyclic( 4893a774ea91a5d05e7af58db6ae1ba298263c4a3d3Russell King struct dma_chan *chan, dma_addr_t buf_addr, size_t buf_len, 490ec8b5e48c03790a68cb875fe5064007a9cbdfdd0Peter Ujfalusi size_t period_len, enum dma_transfer_direction dir, unsigned long flags, 491ec8b5e48c03790a68cb875fe5064007a9cbdfdd0Peter Ujfalusi void *context) 4923a774ea91a5d05e7af58db6ae1ba298263c4a3d3Russell King{ 4933a774ea91a5d05e7af58db6ae1ba298263c4a3d3Russell King struct omap_chan *c = to_omap_dma_chan(chan); 4943a774ea91a5d05e7af58db6ae1ba298263c4a3d3Russell King enum dma_slave_buswidth dev_width; 4953a774ea91a5d05e7af58db6ae1ba298263c4a3d3Russell King struct omap_desc *d; 4963a774ea91a5d05e7af58db6ae1ba298263c4a3d3Russell King dma_addr_t dev_addr; 4973a774ea91a5d05e7af58db6ae1ba298263c4a3d3Russell King unsigned es, sync_type; 4983a774ea91a5d05e7af58db6ae1ba298263c4a3d3Russell King u32 burst; 4993a774ea91a5d05e7af58db6ae1ba298263c4a3d3Russell King 5003a774ea91a5d05e7af58db6ae1ba298263c4a3d3Russell King if (dir == DMA_DEV_TO_MEM) { 5013a774ea91a5d05e7af58db6ae1ba298263c4a3d3Russell King dev_addr = c->cfg.src_addr; 5023a774ea91a5d05e7af58db6ae1ba298263c4a3d3Russell King dev_width = c->cfg.src_addr_width; 5033a774ea91a5d05e7af58db6ae1ba298263c4a3d3Russell King burst = c->cfg.src_maxburst; 5043a774ea91a5d05e7af58db6ae1ba298263c4a3d3Russell King sync_type = OMAP_DMA_SRC_SYNC; 5053a774ea91a5d05e7af58db6ae1ba298263c4a3d3Russell King } else if (dir == DMA_MEM_TO_DEV) { 5063a774ea91a5d05e7af58db6ae1ba298263c4a3d3Russell King dev_addr = c->cfg.dst_addr; 5073a774ea91a5d05e7af58db6ae1ba298263c4a3d3Russell King dev_width = c->cfg.dst_addr_width; 5083a774ea91a5d05e7af58db6ae1ba298263c4a3d3Russell King burst = c->cfg.dst_maxburst; 5093a774ea91a5d05e7af58db6ae1ba298263c4a3d3Russell King sync_type = OMAP_DMA_DST_SYNC; 5103a774ea91a5d05e7af58db6ae1ba298263c4a3d3Russell King } else { 5113a774ea91a5d05e7af58db6ae1ba298263c4a3d3Russell King dev_err(chan->device->dev, "%s: bad direction?\n", __func__); 5123a774ea91a5d05e7af58db6ae1ba298263c4a3d3Russell King return NULL; 5133a774ea91a5d05e7af58db6ae1ba298263c4a3d3Russell King } 5143a774ea91a5d05e7af58db6ae1ba298263c4a3d3Russell King 5153a774ea91a5d05e7af58db6ae1ba298263c4a3d3Russell King /* Bus width translates to the element size (ES) */ 5163a774ea91a5d05e7af58db6ae1ba298263c4a3d3Russell King switch (dev_width) { 5173a774ea91a5d05e7af58db6ae1ba298263c4a3d3Russell King case DMA_SLAVE_BUSWIDTH_1_BYTE: 5183a774ea91a5d05e7af58db6ae1ba298263c4a3d3Russell King es = OMAP_DMA_DATA_TYPE_S8; 5193a774ea91a5d05e7af58db6ae1ba298263c4a3d3Russell King break; 5203a774ea91a5d05e7af58db6ae1ba298263c4a3d3Russell King case DMA_SLAVE_BUSWIDTH_2_BYTES: 5213a774ea91a5d05e7af58db6ae1ba298263c4a3d3Russell King es = OMAP_DMA_DATA_TYPE_S16; 5223a774ea91a5d05e7af58db6ae1ba298263c4a3d3Russell King break; 5233a774ea91a5d05e7af58db6ae1ba298263c4a3d3Russell King case DMA_SLAVE_BUSWIDTH_4_BYTES: 5243a774ea91a5d05e7af58db6ae1ba298263c4a3d3Russell King es = OMAP_DMA_DATA_TYPE_S32; 5253a774ea91a5d05e7af58db6ae1ba298263c4a3d3Russell King break; 5263a774ea91a5d05e7af58db6ae1ba298263c4a3d3Russell King default: /* not reached */ 5273a774ea91a5d05e7af58db6ae1ba298263c4a3d3Russell King return NULL; 5283a774ea91a5d05e7af58db6ae1ba298263c4a3d3Russell King } 5293a774ea91a5d05e7af58db6ae1ba298263c4a3d3Russell King 5303a774ea91a5d05e7af58db6ae1ba298263c4a3d3Russell King /* Now allocate and setup the descriptor. */ 5313a774ea91a5d05e7af58db6ae1ba298263c4a3d3Russell King d = kzalloc(sizeof(*d) + sizeof(d->sg[0]), GFP_ATOMIC); 5323a774ea91a5d05e7af58db6ae1ba298263c4a3d3Russell King if (!d) 5333a774ea91a5d05e7af58db6ae1ba298263c4a3d3Russell King return NULL; 5343a774ea91a5d05e7af58db6ae1ba298263c4a3d3Russell King 5353a774ea91a5d05e7af58db6ae1ba298263c4a3d3Russell King d->dir = dir; 5363a774ea91a5d05e7af58db6ae1ba298263c4a3d3Russell King d->dev_addr = dev_addr; 5373a774ea91a5d05e7af58db6ae1ba298263c4a3d3Russell King d->fi = burst; 5383a774ea91a5d05e7af58db6ae1ba298263c4a3d3Russell King d->es = es; 539ccffa3870a7ec2b59cf051b745220c56f423d182Peter Ujfalusi if (burst) 540ccffa3870a7ec2b59cf051b745220c56f423d182Peter Ujfalusi d->sync_mode = OMAP_DMA_SYNC_PACKET; 541ccffa3870a7ec2b59cf051b745220c56f423d182Peter Ujfalusi else 542ccffa3870a7ec2b59cf051b745220c56f423d182Peter Ujfalusi d->sync_mode = OMAP_DMA_SYNC_ELEMENT; 5433a774ea91a5d05e7af58db6ae1ba298263c4a3d3Russell King d->sync_type = sync_type; 5443a774ea91a5d05e7af58db6ae1ba298263c4a3d3Russell King d->periph_port = OMAP_DMA_PORT_MPUI; 5453a774ea91a5d05e7af58db6ae1ba298263c4a3d3Russell King d->sg[0].addr = buf_addr; 5463a774ea91a5d05e7af58db6ae1ba298263c4a3d3Russell King d->sg[0].en = period_len / es_bytes[es]; 5473a774ea91a5d05e7af58db6ae1ba298263c4a3d3Russell King d->sg[0].fn = buf_len / period_len; 5483a774ea91a5d05e7af58db6ae1ba298263c4a3d3Russell King d->sglen = 1; 5493a774ea91a5d05e7af58db6ae1ba298263c4a3d3Russell King 5503a774ea91a5d05e7af58db6ae1ba298263c4a3d3Russell King if (!c->cyclic) { 5513a774ea91a5d05e7af58db6ae1ba298263c4a3d3Russell King c->cyclic = true; 5523a774ea91a5d05e7af58db6ae1ba298263c4a3d3Russell King omap_dma_link_lch(c->dma_ch, c->dma_ch); 5532dde5b909e117cc95a5e31604f9bfd043e78ad9dPeter Ujfalusi 5542dde5b909e117cc95a5e31604f9bfd043e78ad9dPeter Ujfalusi if (flags & DMA_PREP_INTERRUPT) 5552dde5b909e117cc95a5e31604f9bfd043e78ad9dPeter Ujfalusi omap_enable_dma_irq(c->dma_ch, OMAP_DMA_FRAME_IRQ); 5562dde5b909e117cc95a5e31604f9bfd043e78ad9dPeter Ujfalusi 5573a774ea91a5d05e7af58db6ae1ba298263c4a3d3Russell King omap_disable_dma_irq(c->dma_ch, OMAP_DMA_BLOCK_IRQ); 5583a774ea91a5d05e7af58db6ae1ba298263c4a3d3Russell King } 5593a774ea91a5d05e7af58db6ae1ba298263c4a3d3Russell King 56027615a97b2dc7e98b925973b78d1cdc3ee288ab0Tony Lindgren if (dma_omap2plus()) { 561b9e97822da374f52aaf99cb502f531ff2184b8f5Russell King uint32_t val; 562b9e97822da374f52aaf99cb502f531ff2184b8f5Russell King 563b9e97822da374f52aaf99cb502f531ff2184b8f5Russell King val = c->plat->dma_read(CSDP, c->dma_ch); 564b9e97822da374f52aaf99cb502f531ff2184b8f5Russell King val |= 0x03 << 7; /* src burst mode 16 */ 565b9e97822da374f52aaf99cb502f531ff2184b8f5Russell King val |= 0x03 << 14; /* dst burst mode 16 */ 566b9e97822da374f52aaf99cb502f531ff2184b8f5Russell King c->plat->dma_write(val, CSDP, c->dma_ch); 5673a774ea91a5d05e7af58db6ae1ba298263c4a3d3Russell King } 5683a774ea91a5d05e7af58db6ae1ba298263c4a3d3Russell King 5692dde5b909e117cc95a5e31604f9bfd043e78ad9dPeter Ujfalusi return vchan_tx_prep(&c->vc, &d->vd, flags); 5703a774ea91a5d05e7af58db6ae1ba298263c4a3d3Russell King} 5713a774ea91a5d05e7af58db6ae1ba298263c4a3d3Russell King 5727bedaa5537604f34d1d63c5ec7891e559d2a61edRussell Kingstatic int omap_dma_slave_config(struct omap_chan *c, struct dma_slave_config *cfg) 5737bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King{ 5747bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King if (cfg->src_addr_width == DMA_SLAVE_BUSWIDTH_8_BYTES || 5757bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King cfg->dst_addr_width == DMA_SLAVE_BUSWIDTH_8_BYTES) 5767bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King return -EINVAL; 5777bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King 5787bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King memcpy(&c->cfg, cfg, sizeof(c->cfg)); 5797bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King 5807bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King return 0; 5817bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King} 5827bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King 5837bedaa5537604f34d1d63c5ec7891e559d2a61edRussell Kingstatic int omap_dma_terminate_all(struct omap_chan *c) 5847bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King{ 5857bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King struct omap_dmadev *d = to_omap_dma_dev(c->vc.chan.device); 5867bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King unsigned long flags; 5877bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King LIST_HEAD(head); 5887bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King 5897bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King spin_lock_irqsave(&c->vc.lock, flags); 5907bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King 5917bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King /* Prevent this channel being scheduled */ 5927bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King spin_lock(&d->lock); 5937bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King list_del_init(&c->node); 5947bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King spin_unlock(&d->lock); 5957bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King 5967bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King /* 5977bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King * Stop DMA activity: we assume the callback will not be called 5987bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King * after omap_stop_dma() returns (even if it does, it will see 5997bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King * c->desc is NULL and exit.) 6007bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King */ 6017bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King if (c->desc) { 6027bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King c->desc = NULL; 6032dcdf570936168d488acf90be9b04a3d32dafce7Peter Ujfalusi /* Avoid stopping the dma twice */ 6042dcdf570936168d488acf90be9b04a3d32dafce7Peter Ujfalusi if (!c->paused) 6052dcdf570936168d488acf90be9b04a3d32dafce7Peter Ujfalusi omap_stop_dma(c->dma_ch); 6067bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King } 6077bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King 6083a774ea91a5d05e7af58db6ae1ba298263c4a3d3Russell King if (c->cyclic) { 6093a774ea91a5d05e7af58db6ae1ba298263c4a3d3Russell King c->cyclic = false; 6102dcdf570936168d488acf90be9b04a3d32dafce7Peter Ujfalusi c->paused = false; 6113a774ea91a5d05e7af58db6ae1ba298263c4a3d3Russell King omap_dma_unlink_lch(c->dma_ch, c->dma_ch); 6123a774ea91a5d05e7af58db6ae1ba298263c4a3d3Russell King } 6133a774ea91a5d05e7af58db6ae1ba298263c4a3d3Russell King 6147bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King vchan_get_all_descriptors(&c->vc, &head); 6157bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King spin_unlock_irqrestore(&c->vc.lock, flags); 6167bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King vchan_dma_desc_free_list(&c->vc, &head); 6177bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King 6187bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King return 0; 6197bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King} 6207bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King 6217bedaa5537604f34d1d63c5ec7891e559d2a61edRussell Kingstatic int omap_dma_pause(struct omap_chan *c) 6227bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King{ 6232dcdf570936168d488acf90be9b04a3d32dafce7Peter Ujfalusi /* Pause/Resume only allowed with cyclic mode */ 6242dcdf570936168d488acf90be9b04a3d32dafce7Peter Ujfalusi if (!c->cyclic) 6252dcdf570936168d488acf90be9b04a3d32dafce7Peter Ujfalusi return -EINVAL; 6262dcdf570936168d488acf90be9b04a3d32dafce7Peter Ujfalusi 6272dcdf570936168d488acf90be9b04a3d32dafce7Peter Ujfalusi if (!c->paused) { 6282dcdf570936168d488acf90be9b04a3d32dafce7Peter Ujfalusi omap_stop_dma(c->dma_ch); 6292dcdf570936168d488acf90be9b04a3d32dafce7Peter Ujfalusi c->paused = true; 6302dcdf570936168d488acf90be9b04a3d32dafce7Peter Ujfalusi } 6312dcdf570936168d488acf90be9b04a3d32dafce7Peter Ujfalusi 6322dcdf570936168d488acf90be9b04a3d32dafce7Peter Ujfalusi return 0; 6337bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King} 6347bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King 6357bedaa5537604f34d1d63c5ec7891e559d2a61edRussell Kingstatic int omap_dma_resume(struct omap_chan *c) 6367bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King{ 6372dcdf570936168d488acf90be9b04a3d32dafce7Peter Ujfalusi /* Pause/Resume only allowed with cyclic mode */ 6382dcdf570936168d488acf90be9b04a3d32dafce7Peter Ujfalusi if (!c->cyclic) 6392dcdf570936168d488acf90be9b04a3d32dafce7Peter Ujfalusi return -EINVAL; 6402dcdf570936168d488acf90be9b04a3d32dafce7Peter Ujfalusi 6412dcdf570936168d488acf90be9b04a3d32dafce7Peter Ujfalusi if (c->paused) { 6422dcdf570936168d488acf90be9b04a3d32dafce7Peter Ujfalusi omap_start_dma(c->dma_ch); 6432dcdf570936168d488acf90be9b04a3d32dafce7Peter Ujfalusi c->paused = false; 6442dcdf570936168d488acf90be9b04a3d32dafce7Peter Ujfalusi } 6452dcdf570936168d488acf90be9b04a3d32dafce7Peter Ujfalusi 6462dcdf570936168d488acf90be9b04a3d32dafce7Peter Ujfalusi return 0; 6477bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King} 6487bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King 6497bedaa5537604f34d1d63c5ec7891e559d2a61edRussell Kingstatic int omap_dma_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, 6507bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King unsigned long arg) 6517bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King{ 6527bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King struct omap_chan *c = to_omap_dma_chan(chan); 6537bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King int ret; 6547bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King 6557bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King switch (cmd) { 6567bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King case DMA_SLAVE_CONFIG: 6577bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King ret = omap_dma_slave_config(c, (struct dma_slave_config *)arg); 6587bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King break; 6597bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King 6607bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King case DMA_TERMINATE_ALL: 6617bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King ret = omap_dma_terminate_all(c); 6627bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King break; 6637bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King 6647bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King case DMA_PAUSE: 6657bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King ret = omap_dma_pause(c); 6667bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King break; 6677bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King 6687bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King case DMA_RESUME: 6697bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King ret = omap_dma_resume(c); 6707bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King break; 6717bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King 6727bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King default: 6737bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King ret = -ENXIO; 6747bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King break; 6757bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King } 6767bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King 6777bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King return ret; 6787bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King} 6797bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King 6807bedaa5537604f34d1d63c5ec7891e559d2a61edRussell Kingstatic int omap_dma_chan_init(struct omap_dmadev *od, int dma_sig) 6817bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King{ 6827bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King struct omap_chan *c; 6837bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King 6847bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King c = kzalloc(sizeof(*c), GFP_KERNEL); 6857bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King if (!c) 6867bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King return -ENOMEM; 6877bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King 6881b416c4b41351c3eb8fc42dbb4cd8eba463c0813Russell King c->plat = od->plat; 6897bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King c->dma_sig = dma_sig; 6907bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King c->vc.desc_free = omap_dma_desc_free; 6917bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King vchan_init(&c->vc, &od->ddev); 6927bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King INIT_LIST_HEAD(&c->node); 6937bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King 6947bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King od->ddev.chancnt++; 6957bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King 6967bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King return 0; 6977bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King} 6987bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King 6997bedaa5537604f34d1d63c5ec7891e559d2a61edRussell Kingstatic void omap_dma_free(struct omap_dmadev *od) 7007bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King{ 7017bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King tasklet_kill(&od->task); 7027bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King while (!list_empty(&od->ddev.channels)) { 7037bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King struct omap_chan *c = list_first_entry(&od->ddev.channels, 7047bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King struct omap_chan, vc.chan.device_node); 7057bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King 7067bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King list_del(&c->vc.chan.device_node); 7077bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King tasklet_kill(&c->vc.task); 7087bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King kfree(c); 7097bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King } 7107bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King} 7117bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King 7127bedaa5537604f34d1d63c5ec7891e559d2a61edRussell Kingstatic int omap_dma_probe(struct platform_device *pdev) 7137bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King{ 7147bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King struct omap_dmadev *od; 7157bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King int rc, i; 7167bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King 717104fce73fdbd174eb08a493eeb2920fd59e6d3f4Russell King od = devm_kzalloc(&pdev->dev, sizeof(*od), GFP_KERNEL); 7187bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King if (!od) 7197bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King return -ENOMEM; 7207bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King 7211b416c4b41351c3eb8fc42dbb4cd8eba463c0813Russell King od->plat = omap_get_plat_info(); 7221b416c4b41351c3eb8fc42dbb4cd8eba463c0813Russell King if (!od->plat) 7231b416c4b41351c3eb8fc42dbb4cd8eba463c0813Russell King return -EPROBE_DEFER; 7241b416c4b41351c3eb8fc42dbb4cd8eba463c0813Russell King 7257bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King dma_cap_set(DMA_SLAVE, od->ddev.cap_mask); 7263a774ea91a5d05e7af58db6ae1ba298263c4a3d3Russell King dma_cap_set(DMA_CYCLIC, od->ddev.cap_mask); 7277bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King od->ddev.device_alloc_chan_resources = omap_dma_alloc_chan_resources; 7287bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King od->ddev.device_free_chan_resources = omap_dma_free_chan_resources; 7297bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King od->ddev.device_tx_status = omap_dma_tx_status; 7307bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King od->ddev.device_issue_pending = omap_dma_issue_pending; 7317bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King od->ddev.device_prep_slave_sg = omap_dma_prep_slave_sg; 7323a774ea91a5d05e7af58db6ae1ba298263c4a3d3Russell King od->ddev.device_prep_dma_cyclic = omap_dma_prep_dma_cyclic; 7337bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King od->ddev.device_control = omap_dma_control; 7347bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King od->ddev.dev = &pdev->dev; 7357bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King INIT_LIST_HEAD(&od->ddev.channels); 7367bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King INIT_LIST_HEAD(&od->pending); 7377bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King spin_lock_init(&od->lock); 7387bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King 7397bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King tasklet_init(&od->task, omap_dma_sched, (unsigned long)od); 7407bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King 7417bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King for (i = 0; i < 127; i++) { 7427bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King rc = omap_dma_chan_init(od, i); 7437bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King if (rc) { 7447bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King omap_dma_free(od); 7457bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King return rc; 7467bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King } 7477bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King } 7487bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King 7497bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King rc = dma_async_device_register(&od->ddev); 7507bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King if (rc) { 7517bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King pr_warn("OMAP-DMA: failed to register slave DMA engine device: %d\n", 7527bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King rc); 7537bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King omap_dma_free(od); 7548d30662aac256eb61bc2f1d9cf1191825ef96328Jon Hunter return rc; 7558d30662aac256eb61bc2f1d9cf1191825ef96328Jon Hunter } 7568d30662aac256eb61bc2f1d9cf1191825ef96328Jon Hunter 7578d30662aac256eb61bc2f1d9cf1191825ef96328Jon Hunter platform_set_drvdata(pdev, od); 7588d30662aac256eb61bc2f1d9cf1191825ef96328Jon Hunter 7598d30662aac256eb61bc2f1d9cf1191825ef96328Jon Hunter if (pdev->dev.of_node) { 7608d30662aac256eb61bc2f1d9cf1191825ef96328Jon Hunter omap_dma_info.dma_cap = od->ddev.cap_mask; 7618d30662aac256eb61bc2f1d9cf1191825ef96328Jon Hunter 7628d30662aac256eb61bc2f1d9cf1191825ef96328Jon Hunter /* Device-tree DMA controller registration */ 7638d30662aac256eb61bc2f1d9cf1191825ef96328Jon Hunter rc = of_dma_controller_register(pdev->dev.of_node, 7648d30662aac256eb61bc2f1d9cf1191825ef96328Jon Hunter of_dma_simple_xlate, &omap_dma_info); 7658d30662aac256eb61bc2f1d9cf1191825ef96328Jon Hunter if (rc) { 7668d30662aac256eb61bc2f1d9cf1191825ef96328Jon Hunter pr_warn("OMAP-DMA: failed to register DMA controller\n"); 7678d30662aac256eb61bc2f1d9cf1191825ef96328Jon Hunter dma_async_device_unregister(&od->ddev); 7688d30662aac256eb61bc2f1d9cf1191825ef96328Jon Hunter omap_dma_free(od); 7698d30662aac256eb61bc2f1d9cf1191825ef96328Jon Hunter } 7707bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King } 7717bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King 7727bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King dev_info(&pdev->dev, "OMAP DMA engine driver\n"); 7737bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King 7747bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King return rc; 7757bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King} 7767bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King 7777bedaa5537604f34d1d63c5ec7891e559d2a61edRussell Kingstatic int omap_dma_remove(struct platform_device *pdev) 7787bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King{ 7797bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King struct omap_dmadev *od = platform_get_drvdata(pdev); 7807bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King 7818d30662aac256eb61bc2f1d9cf1191825ef96328Jon Hunter if (pdev->dev.of_node) 7828d30662aac256eb61bc2f1d9cf1191825ef96328Jon Hunter of_dma_controller_free(pdev->dev.of_node); 7838d30662aac256eb61bc2f1d9cf1191825ef96328Jon Hunter 7847bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King dma_async_device_unregister(&od->ddev); 7857bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King omap_dma_free(od); 7867bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King 7877bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King return 0; 7887bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King} 7897bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King 7908d30662aac256eb61bc2f1d9cf1191825ef96328Jon Hunterstatic const struct of_device_id omap_dma_match[] = { 7918d30662aac256eb61bc2f1d9cf1191825ef96328Jon Hunter { .compatible = "ti,omap2420-sdma", }, 7928d30662aac256eb61bc2f1d9cf1191825ef96328Jon Hunter { .compatible = "ti,omap2430-sdma", }, 7938d30662aac256eb61bc2f1d9cf1191825ef96328Jon Hunter { .compatible = "ti,omap3430-sdma", }, 7948d30662aac256eb61bc2f1d9cf1191825ef96328Jon Hunter { .compatible = "ti,omap3630-sdma", }, 7958d30662aac256eb61bc2f1d9cf1191825ef96328Jon Hunter { .compatible = "ti,omap4430-sdma", }, 7968d30662aac256eb61bc2f1d9cf1191825ef96328Jon Hunter {}, 7978d30662aac256eb61bc2f1d9cf1191825ef96328Jon Hunter}; 7988d30662aac256eb61bc2f1d9cf1191825ef96328Jon HunterMODULE_DEVICE_TABLE(of, omap_dma_match); 7998d30662aac256eb61bc2f1d9cf1191825ef96328Jon Hunter 8007bedaa5537604f34d1d63c5ec7891e559d2a61edRussell Kingstatic struct platform_driver omap_dma_driver = { 8017bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King .probe = omap_dma_probe, 8027bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King .remove = omap_dma_remove, 8037bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King .driver = { 8047bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King .name = "omap-dma-engine", 8057bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King .owner = THIS_MODULE, 8068d30662aac256eb61bc2f1d9cf1191825ef96328Jon Hunter .of_match_table = of_match_ptr(omap_dma_match), 8077bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King }, 8087bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King}; 8097bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King 8107bedaa5537604f34d1d63c5ec7891e559d2a61edRussell Kingbool omap_dma_filter_fn(struct dma_chan *chan, void *param) 8117bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King{ 8127bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King if (chan->device->dev->driver == &omap_dma_driver.driver) { 8137bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King struct omap_chan *c = to_omap_dma_chan(chan); 8147bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King unsigned req = *(unsigned *)param; 8157bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King 8167bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King return req == c->dma_sig; 8177bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King } 8187bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King return false; 8197bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King} 8207bedaa5537604f34d1d63c5ec7891e559d2a61edRussell KingEXPORT_SYMBOL_GPL(omap_dma_filter_fn); 8217bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King 8227bedaa5537604f34d1d63c5ec7891e559d2a61edRussell Kingstatic int omap_dma_init(void) 8237bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King{ 824be1f94812c2cc0aaf696d39fe23104763ea52b5bTony Lindgren return platform_driver_register(&omap_dma_driver); 8257bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King} 8267bedaa5537604f34d1d63c5ec7891e559d2a61edRussell Kingsubsys_initcall(omap_dma_init); 8277bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King 8287bedaa5537604f34d1d63c5ec7891e559d2a61edRussell Kingstatic void __exit omap_dma_exit(void) 8297bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King{ 8307bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King platform_driver_unregister(&omap_dma_driver); 8317bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King} 8327bedaa5537604f34d1d63c5ec7891e559d2a61edRussell Kingmodule_exit(omap_dma_exit); 8337bedaa5537604f34d1d63c5ec7891e559d2a61edRussell King 8347bedaa5537604f34d1d63c5ec7891e559d2a61edRussell KingMODULE_AUTHOR("Russell King"); 8357bedaa5537604f34d1d63c5ec7891e559d2a61edRussell KingMODULE_LICENSE("GPL"); 836