139aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus/* 239aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus * drivers/media/video/omap24xxcam-dma.c 339aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus * 439aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus * Copyright (C) 2004 MontaVista Software, Inc. 539aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus * Copyright (C) 2004 Texas Instruments. 639aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus * Copyright (C) 2007 Nokia Corporation. 739aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus * 839aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus * Contact: Sakari Ailus <sakari.ailus@nokia.com> 939aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus * 1039aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus * Based on code from Andy Lowe <source@mvista.com> and 1139aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus * David Cohen <david.cohen@indt.org.br>. 1239aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus * 1339aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus * This program is free software; you can redistribute it and/or 1439aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus * modify it under the terms of the GNU General Public License 1539aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus * version 2 as published by the Free Software Foundation. 1639aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus * 1739aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus * This program is distributed in the hope that it will be useful, but 1839aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus * WITHOUT ANY WARRANTY; without even the implied warranty of 1939aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 2039aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus * General Public License for more details. 2139aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus * 2239aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus * You should have received a copy of the GNU General Public License 2339aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus * along with this program; if not, write to the Free Software 2439aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 2539aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus * 02110-1301 USA 2639aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus */ 2739aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus 2839aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus#include <linux/kernel.h> 2939aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus#include <linux/io.h> 3039aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus#include <linux/scatterlist.h> 3139aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus 3239aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus#include "omap24xxcam.h" 3339aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus 3439aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus/* 3539aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus * 3639aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus * DMA hardware. 3739aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus * 3839aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus */ 3939aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus 4039aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus/* Ack all interrupt on CSR and IRQSTATUS_L0 */ 4139aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailusstatic void omap24xxcam_dmahw_ack_all(unsigned long base) 4239aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus{ 4339aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus u32 csr; 4439aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus int i; 4539aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus 4639aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus for (i = 0; i < NUM_CAMDMA_CHANNELS; ++i) { 4739aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus csr = omap24xxcam_reg_in(base, CAMDMA_CSR(i)); 4839aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus /* ack interrupt in CSR */ 4939aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus omap24xxcam_reg_out(base, CAMDMA_CSR(i), csr); 5039aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus } 5139aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus omap24xxcam_reg_out(base, CAMDMA_IRQSTATUS_L0, 0xf); 5239aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus} 5339aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus 5439aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus/* Ack dmach on CSR and IRQSTATUS_L0 */ 5539aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailusstatic u32 omap24xxcam_dmahw_ack_ch(unsigned long base, int dmach) 5639aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus{ 5739aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus u32 csr; 5839aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus 5939aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus csr = omap24xxcam_reg_in(base, CAMDMA_CSR(dmach)); 6039aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus /* ack interrupt in CSR */ 6139aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus omap24xxcam_reg_out(base, CAMDMA_CSR(dmach), csr); 6239aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus /* ack interrupt in IRQSTATUS */ 6339aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus omap24xxcam_reg_out(base, CAMDMA_IRQSTATUS_L0, (1 << dmach)); 6439aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus 6539aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus return csr; 6639aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus} 6739aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus 6839aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailusstatic int omap24xxcam_dmahw_running(unsigned long base, int dmach) 6939aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus{ 7039aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus return omap24xxcam_reg_in(base, CAMDMA_CCR(dmach)) & CAMDMA_CCR_ENABLE; 7139aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus} 7239aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus 7339aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailusstatic void omap24xxcam_dmahw_transfer_setup(unsigned long base, int dmach, 7439aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus dma_addr_t start, u32 len) 7539aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus{ 7639aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus omap24xxcam_reg_out(base, CAMDMA_CCR(dmach), 7739aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus CAMDMA_CCR_SEL_SRC_DST_SYNC 7839aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus | CAMDMA_CCR_BS 7939aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus | CAMDMA_CCR_DST_AMODE_POST_INC 8039aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus | CAMDMA_CCR_SRC_AMODE_POST_INC 8139aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus | CAMDMA_CCR_FS 8239aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus | CAMDMA_CCR_WR_ACTIVE 8339aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus | CAMDMA_CCR_RD_ACTIVE 8439aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus | CAMDMA_CCR_SYNCHRO_CAMERA); 8539aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus omap24xxcam_reg_out(base, CAMDMA_CLNK_CTRL(dmach), 0); 8639aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus omap24xxcam_reg_out(base, CAMDMA_CEN(dmach), len); 8739aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus omap24xxcam_reg_out(base, CAMDMA_CFN(dmach), 1); 8839aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus omap24xxcam_reg_out(base, CAMDMA_CSDP(dmach), 8939aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus CAMDMA_CSDP_WRITE_MODE_POSTED 9039aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus | CAMDMA_CSDP_DST_BURST_EN_32 9139aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus | CAMDMA_CSDP_DST_PACKED 9239aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus | CAMDMA_CSDP_SRC_BURST_EN_32 9339aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus | CAMDMA_CSDP_SRC_PACKED 9439aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus | CAMDMA_CSDP_DATA_TYPE_8BITS); 9539aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus omap24xxcam_reg_out(base, CAMDMA_CSSA(dmach), 0); 9639aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus omap24xxcam_reg_out(base, CAMDMA_CDSA(dmach), start); 9739aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus omap24xxcam_reg_out(base, CAMDMA_CSEI(dmach), 0); 9839aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus omap24xxcam_reg_out(base, CAMDMA_CSFI(dmach), DMA_THRESHOLD); 9939aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus omap24xxcam_reg_out(base, CAMDMA_CDEI(dmach), 0); 10039aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus omap24xxcam_reg_out(base, CAMDMA_CDFI(dmach), 0); 10139aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus omap24xxcam_reg_out(base, CAMDMA_CSR(dmach), 10239aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus CAMDMA_CSR_MISALIGNED_ERR 10339aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus | CAMDMA_CSR_SECURE_ERR 10439aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus | CAMDMA_CSR_TRANS_ERR 10539aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus | CAMDMA_CSR_BLOCK 10639aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus | CAMDMA_CSR_DROP); 10739aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus omap24xxcam_reg_out(base, CAMDMA_CICR(dmach), 10839aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus CAMDMA_CICR_MISALIGNED_ERR_IE 10939aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus | CAMDMA_CICR_SECURE_ERR_IE 11039aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus | CAMDMA_CICR_TRANS_ERR_IE 11139aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus | CAMDMA_CICR_BLOCK_IE 11239aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus | CAMDMA_CICR_DROP_IE); 11339aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus} 11439aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus 11539aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailusstatic void omap24xxcam_dmahw_transfer_start(unsigned long base, int dmach) 11639aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus{ 11739aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus omap24xxcam_reg_out(base, CAMDMA_CCR(dmach), 11839aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus CAMDMA_CCR_SEL_SRC_DST_SYNC 11939aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus | CAMDMA_CCR_BS 12039aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus | CAMDMA_CCR_DST_AMODE_POST_INC 12139aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus | CAMDMA_CCR_SRC_AMODE_POST_INC 12239aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus | CAMDMA_CCR_ENABLE 12339aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus | CAMDMA_CCR_FS 12439aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus | CAMDMA_CCR_SYNCHRO_CAMERA); 12539aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus} 12639aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus 12739aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailusstatic void omap24xxcam_dmahw_transfer_chain(unsigned long base, int dmach, 12839aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus int free_dmach) 12939aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus{ 13039aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus int prev_dmach, ch; 13139aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus 13239aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus if (dmach == 0) 13339aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus prev_dmach = NUM_CAMDMA_CHANNELS - 1; 13439aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus else 13539aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus prev_dmach = dmach - 1; 13639aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus omap24xxcam_reg_out(base, CAMDMA_CLNK_CTRL(prev_dmach), 13739aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus CAMDMA_CLNK_CTRL_ENABLE_LNK | dmach); 13839aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus /* Did we chain the DMA transfer before the previous one 13939aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus * finished? 14039aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus */ 14139aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus ch = (dmach + free_dmach) % NUM_CAMDMA_CHANNELS; 14239aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus while (!(omap24xxcam_reg_in(base, CAMDMA_CCR(ch)) 14339aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus & CAMDMA_CCR_ENABLE)) { 14439aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus if (ch == dmach) { 14539aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus /* The previous transfer has ended and this one 14639aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus * hasn't started, so we must not have chained 14739aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus * to the previous one in time. We'll have to 14839aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus * start it now. 14939aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus */ 15039aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus omap24xxcam_dmahw_transfer_start(base, dmach); 15139aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus break; 15239aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus } else 15339aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus ch = (ch + 1) % NUM_CAMDMA_CHANNELS; 15439aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus } 15539aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus} 15639aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus 15739aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus/* Abort all chained DMA transfers. After all transfers have been 15839aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus * aborted and the DMA controller is idle, the completion routines for 15939aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus * any aborted transfers will be called in sequence. The DMA 16039aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus * controller may not be idle after this routine completes, because 16139aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus * the completion routines might start new transfers. 16239aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus */ 16339aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailusstatic void omap24xxcam_dmahw_abort_ch(unsigned long base, int dmach) 16439aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus{ 16539aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus /* mask all interrupts from this channel */ 16639aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus omap24xxcam_reg_out(base, CAMDMA_CICR(dmach), 0); 16739aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus /* unlink this channel */ 16839aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus omap24xxcam_reg_merge(base, CAMDMA_CLNK_CTRL(dmach), 0, 16939aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus CAMDMA_CLNK_CTRL_ENABLE_LNK); 17039aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus /* disable this channel */ 17139aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus omap24xxcam_reg_merge(base, CAMDMA_CCR(dmach), 0, CAMDMA_CCR_ENABLE); 17239aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus} 17339aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus 17439aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailusstatic void omap24xxcam_dmahw_init(unsigned long base) 17539aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus{ 17639aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus omap24xxcam_reg_out(base, CAMDMA_OCP_SYSCONFIG, 17739aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus CAMDMA_OCP_SYSCONFIG_MIDLEMODE_FSTANDBY 17839aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus | CAMDMA_OCP_SYSCONFIG_SIDLEMODE_FIDLE 17939aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus | CAMDMA_OCP_SYSCONFIG_AUTOIDLE); 18039aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus 18139aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus omap24xxcam_reg_merge(base, CAMDMA_GCR, 0x10, 18239aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus CAMDMA_GCR_MAX_CHANNEL_FIFO_DEPTH); 18339aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus 18439aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus omap24xxcam_reg_out(base, CAMDMA_IRQENABLE_L0, 0xf); 18539aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus} 18639aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus 18739aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus/* 18839aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus * 18939aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus * Individual DMA channel handling. 19039aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus * 19139aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus */ 19239aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus 19339aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus/* Start a DMA transfer from the camera to memory. 19439aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus * Returns zero if the transfer was successfully started, or non-zero if all 19539aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus * DMA channels are already in use or starting is currently inhibited. 19639aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus */ 19739aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailusstatic int omap24xxcam_dma_start(struct omap24xxcam_dma *dma, dma_addr_t start, 19839aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus u32 len, dma_callback_t callback, void *arg) 19939aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus{ 20039aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus unsigned long flags; 20139aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus int dmach; 20239aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus 20339aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus spin_lock_irqsave(&dma->lock, flags); 20439aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus 20539aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus if (!dma->free_dmach || atomic_read(&dma->dma_stop)) { 20639aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus spin_unlock_irqrestore(&dma->lock, flags); 20739aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus return -EBUSY; 20839aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus } 20939aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus 21039aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus dmach = dma->next_dmach; 21139aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus 21239aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus dma->ch_state[dmach].callback = callback; 21339aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus dma->ch_state[dmach].arg = arg; 21439aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus 21539aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus omap24xxcam_dmahw_transfer_setup(dma->base, dmach, start, len); 21639aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus 21739aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus /* We're ready to start the DMA transfer. */ 21839aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus 21939aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus if (dma->free_dmach < NUM_CAMDMA_CHANNELS) { 22039aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus /* A transfer is already in progress, so try to chain to it. */ 22139aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus omap24xxcam_dmahw_transfer_chain(dma->base, dmach, 22239aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus dma->free_dmach); 22339aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus } else { 22439aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus /* No transfer is in progress, so we'll just start this one 22539aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus * now. 22639aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus */ 22739aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus omap24xxcam_dmahw_transfer_start(dma->base, dmach); 22839aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus } 22939aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus 23039aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus dma->next_dmach = (dma->next_dmach + 1) % NUM_CAMDMA_CHANNELS; 23139aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus dma->free_dmach--; 23239aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus 23339aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus spin_unlock_irqrestore(&dma->lock, flags); 23439aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus 23539aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus return 0; 23639aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus} 23739aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus 23839aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus/* Abort all chained DMA transfers. After all transfers have been 23939aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus * aborted and the DMA controller is idle, the completion routines for 24039aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus * any aborted transfers will be called in sequence. The DMA 24139aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus * controller may not be idle after this routine completes, because 24239aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus * the completion routines might start new transfers. 24339aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus */ 24439aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailusstatic void omap24xxcam_dma_abort(struct omap24xxcam_dma *dma, u32 csr) 24539aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus{ 24639aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus unsigned long flags; 24739aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus int dmach, i, free_dmach; 24839aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus dma_callback_t callback; 24939aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus void *arg; 25039aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus 25139aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus spin_lock_irqsave(&dma->lock, flags); 25239aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus 25339aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus /* stop any DMA transfers in progress */ 25439aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus dmach = (dma->next_dmach + dma->free_dmach) % NUM_CAMDMA_CHANNELS; 25539aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus for (i = 0; i < NUM_CAMDMA_CHANNELS; i++) { 25639aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus omap24xxcam_dmahw_abort_ch(dma->base, dmach); 25739aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus dmach = (dmach + 1) % NUM_CAMDMA_CHANNELS; 25839aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus } 25939aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus 26039aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus /* We have to be careful here because the callback routine 26139aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus * might start a new DMA transfer, and we only want to abort 26239aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus * transfers that were started before this routine was called. 26339aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus */ 26439aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus free_dmach = dma->free_dmach; 26539aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus while ((dma->free_dmach < NUM_CAMDMA_CHANNELS) && 26639aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus (free_dmach < NUM_CAMDMA_CHANNELS)) { 26739aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus dmach = (dma->next_dmach + dma->free_dmach) 26839aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus % NUM_CAMDMA_CHANNELS; 26939aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus callback = dma->ch_state[dmach].callback; 27039aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus arg = dma->ch_state[dmach].arg; 27139aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus dma->free_dmach++; 27239aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus free_dmach++; 27339aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus if (callback) { 27439aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus /* leave interrupts disabled during callback */ 27539aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus spin_unlock(&dma->lock); 27639aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus (*callback) (dma, csr, arg); 27739aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus spin_lock(&dma->lock); 27839aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus } 27939aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus } 28039aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus 28139aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus spin_unlock_irqrestore(&dma->lock, flags); 28239aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus} 28339aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus 28439aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus/* Abort all chained DMA transfers. After all transfers have been 28539aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus * aborted and the DMA controller is idle, the completion routines for 28639aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus * any aborted transfers will be called in sequence. If the completion 28739aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus * routines attempt to start a new DMA transfer it will fail, so the 28839aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus * DMA controller will be idle after this routine completes. 28939aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus */ 29039aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailusstatic void omap24xxcam_dma_stop(struct omap24xxcam_dma *dma, u32 csr) 29139aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus{ 29239aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus atomic_inc(&dma->dma_stop); 29339aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus omap24xxcam_dma_abort(dma, csr); 29439aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus atomic_dec(&dma->dma_stop); 29539aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus} 29639aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus 29739aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus/* Camera DMA interrupt service routine. */ 29839aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailusvoid omap24xxcam_dma_isr(struct omap24xxcam_dma *dma) 29939aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus{ 30039aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus int dmach; 30139aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus dma_callback_t callback; 30239aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus void *arg; 30339aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus u32 csr; 30439aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus const u32 csr_error = CAMDMA_CSR_MISALIGNED_ERR 30539aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus | CAMDMA_CSR_SUPERVISOR_ERR | CAMDMA_CSR_SECURE_ERR 30639aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus | CAMDMA_CSR_TRANS_ERR | CAMDMA_CSR_DROP; 30739aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus 30839aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus spin_lock(&dma->lock); 30939aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus 31039aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus if (dma->free_dmach == NUM_CAMDMA_CHANNELS) { 31139aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus /* A camera DMA interrupt occurred while all channels 31239aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus * are idle, so we'll acknowledge the interrupt in the 31339aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus * IRQSTATUS register and exit. 31439aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus */ 31539aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus omap24xxcam_dmahw_ack_all(dma->base); 31639aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus spin_unlock(&dma->lock); 31739aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus return; 31839aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus } 31939aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus 32039aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus while (dma->free_dmach < NUM_CAMDMA_CHANNELS) { 32139aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus dmach = (dma->next_dmach + dma->free_dmach) 32239aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus % NUM_CAMDMA_CHANNELS; 32339aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus if (omap24xxcam_dmahw_running(dma->base, dmach)) { 32439aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus /* This buffer hasn't finished yet, so we're done. */ 32539aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus break; 32639aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus } 32739aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus csr = omap24xxcam_dmahw_ack_ch(dma->base, dmach); 32839aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus if (csr & csr_error) { 32939aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus /* A DMA error occurred, so stop all DMA 33039aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus * transfers in progress. 33139aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus */ 33239aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus spin_unlock(&dma->lock); 33339aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus omap24xxcam_dma_stop(dma, csr); 33439aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus return; 33539aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus } else { 33639aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus callback = dma->ch_state[dmach].callback; 33739aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus arg = dma->ch_state[dmach].arg; 33839aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus dma->free_dmach++; 33939aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus if (callback) { 34039aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus spin_unlock(&dma->lock); 34139aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus (*callback) (dma, csr, arg); 34239aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus spin_lock(&dma->lock); 34339aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus } 34439aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus } 34539aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus } 34639aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus 34739aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus spin_unlock(&dma->lock); 34839aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus 34939aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus omap24xxcam_sgdma_process( 35039aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus container_of(dma, struct omap24xxcam_sgdma, dma)); 35139aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus} 35239aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus 35339aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailusvoid omap24xxcam_dma_hwinit(struct omap24xxcam_dma *dma) 35439aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus{ 35539aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus unsigned long flags; 35639aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus 35739aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus spin_lock_irqsave(&dma->lock, flags); 35839aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus 35939aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus omap24xxcam_dmahw_init(dma->base); 36039aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus 36139aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus spin_unlock_irqrestore(&dma->lock, flags); 36239aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus} 36339aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus 36439aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailusstatic void omap24xxcam_dma_init(struct omap24xxcam_dma *dma, 36539aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus unsigned long base) 36639aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus{ 36739aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus int ch; 36839aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus 36939aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus /* group all channels on DMA IRQ0 and unmask irq */ 37039aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus spin_lock_init(&dma->lock); 37139aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus dma->base = base; 37239aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus dma->free_dmach = NUM_CAMDMA_CHANNELS; 37339aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus dma->next_dmach = 0; 37439aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus for (ch = 0; ch < NUM_CAMDMA_CHANNELS; ch++) { 37539aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus dma->ch_state[ch].callback = NULL; 37639aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus dma->ch_state[ch].arg = NULL; 37739aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus } 37839aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus} 37939aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus 38039aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus/* 38139aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus * 38239aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus * Scatter-gather DMA. 38339aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus * 38439aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus * High-level DMA construct for transferring whole picture frames to 38539aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus * memory that is discontinuous. 38639aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus * 38739aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus */ 38839aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus 38939aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus/* DMA completion routine for the scatter-gather DMA fragments. */ 39039aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailusstatic void omap24xxcam_sgdma_callback(struct omap24xxcam_dma *dma, u32 csr, 39139aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus void *arg) 39239aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus{ 39339aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus struct omap24xxcam_sgdma *sgdma = 39439aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus container_of(dma, struct omap24xxcam_sgdma, dma); 39539aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus int sgslot = (int)arg; 39639aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus struct sgdma_state *sg_state; 39739aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus const u32 csr_error = CAMDMA_CSR_MISALIGNED_ERR 39839aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus | CAMDMA_CSR_SUPERVISOR_ERR | CAMDMA_CSR_SECURE_ERR 39939aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus | CAMDMA_CSR_TRANS_ERR | CAMDMA_CSR_DROP; 40039aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus 40139aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus spin_lock(&sgdma->lock); 40239aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus 40339aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus /* We got an interrupt, we can remove the timer */ 40439aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus del_timer(&sgdma->reset_timer); 40539aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus 40639aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus sg_state = sgdma->sg_state + sgslot; 40739aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus if (!sg_state->queued_sglist) { 40839aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus spin_unlock(&sgdma->lock); 40939aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus printk(KERN_ERR "%s: sgdma completed when none queued!\n", 41039aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus __func__); 41139aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus return; 41239aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus } 41339aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus 41439aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus sg_state->csr |= csr; 41539aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus if (!--sg_state->queued_sglist) { 41639aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus /* Queue for this sglist is empty, so check to see if we're 41739aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus * done. 41839aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus */ 41939aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus if ((sg_state->next_sglist == sg_state->sglen) 42039aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus || (sg_state->csr & csr_error)) { 42139aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus sgdma_callback_t callback = sg_state->callback; 42239aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus void *arg = sg_state->arg; 42339aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus u32 sg_csr = sg_state->csr; 42439aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus /* All done with this sglist */ 42539aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus sgdma->free_sgdma++; 42639aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus if (callback) { 42739aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus spin_unlock(&sgdma->lock); 42839aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus (*callback) (sgdma, sg_csr, arg); 42939aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus return; 43039aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus } 43139aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus } 43239aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus } 43339aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus 43439aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus spin_unlock(&sgdma->lock); 43539aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus} 43639aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus 43739aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus/* Start queued scatter-gather DMA transfers. */ 43839aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailusvoid omap24xxcam_sgdma_process(struct omap24xxcam_sgdma *sgdma) 43939aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus{ 44039aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus unsigned long flags; 44139aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus int queued_sgdma, sgslot; 44239aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus struct sgdma_state *sg_state; 44339aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus const u32 csr_error = CAMDMA_CSR_MISALIGNED_ERR 44439aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus | CAMDMA_CSR_SUPERVISOR_ERR | CAMDMA_CSR_SECURE_ERR 44539aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus | CAMDMA_CSR_TRANS_ERR | CAMDMA_CSR_DROP; 44639aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus 44739aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus spin_lock_irqsave(&sgdma->lock, flags); 44839aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus 44939aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus queued_sgdma = NUM_SG_DMA - sgdma->free_sgdma; 45039aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus sgslot = (sgdma->next_sgdma + sgdma->free_sgdma) % NUM_SG_DMA; 45139aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus while (queued_sgdma > 0) { 45239aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus sg_state = sgdma->sg_state + sgslot; 45339aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus while ((sg_state->next_sglist < sg_state->sglen) && 45439aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus !(sg_state->csr & csr_error)) { 45539aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus const struct scatterlist *sglist; 45639aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus unsigned int len; 45739aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus 45839aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus sglist = sg_state->sglist + sg_state->next_sglist; 45939aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus /* try to start the next DMA transfer */ 46039aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus if (sg_state->next_sglist + 1 == sg_state->sglen) { 46139aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus /* 46239aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus * On the last sg, we handle the case where 46339aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus * cam->img.pix.sizeimage % PAGE_ALIGN != 0 46439aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus */ 46539aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus len = sg_state->len - sg_state->bytes_read; 46639aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus } else { 46739aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus len = sg_dma_len(sglist); 46839aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus } 46939aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus 47039aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus if (omap24xxcam_dma_start(&sgdma->dma, 47139aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus sg_dma_address(sglist), 47239aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus len, 47339aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus omap24xxcam_sgdma_callback, 47439aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus (void *)sgslot)) { 47539aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus /* DMA start failed */ 47639aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus spin_unlock_irqrestore(&sgdma->lock, flags); 47739aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus return; 47839aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus } else { 47939aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus unsigned long expires; 48039aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus /* DMA start was successful */ 48139aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus sg_state->next_sglist++; 48239aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus sg_state->bytes_read += len; 48339aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus sg_state->queued_sglist++; 48439aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus 48539aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus /* We start the reset timer */ 48639aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus expires = jiffies + HZ; 48739aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus mod_timer(&sgdma->reset_timer, expires); 48839aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus } 48939aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus } 49039aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus queued_sgdma--; 49139aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus sgslot = (sgslot + 1) % NUM_SG_DMA; 49239aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus } 49339aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus 49439aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus spin_unlock_irqrestore(&sgdma->lock, flags); 49539aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus} 49639aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus 49739aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus/* 49839aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus * Queue a scatter-gather DMA transfer from the camera to memory. 49939aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus * Returns zero if the transfer was successfully queued, or non-zero 50039aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus * if all of the scatter-gather slots are already in use. 50139aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus */ 50239aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailusint omap24xxcam_sgdma_queue(struct omap24xxcam_sgdma *sgdma, 50339aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus const struct scatterlist *sglist, int sglen, 50439aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus int len, sgdma_callback_t callback, void *arg) 50539aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus{ 50639aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus unsigned long flags; 50739aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus struct sgdma_state *sg_state; 50839aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus 5099aa7705c966c750dda3d5c8d8a20f8e46668911cJoe Perches if ((sglen < 0) || ((sglen > 0) && !sglist)) 51039aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus return -EINVAL; 51139aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus 51239aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus spin_lock_irqsave(&sgdma->lock, flags); 51339aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus 51439aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus if (!sgdma->free_sgdma) { 51539aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus spin_unlock_irqrestore(&sgdma->lock, flags); 51639aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus return -EBUSY; 51739aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus } 51839aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus 51939aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus sg_state = sgdma->sg_state + sgdma->next_sgdma; 52039aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus 52139aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus sg_state->sglist = sglist; 52239aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus sg_state->sglen = sglen; 52339aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus sg_state->next_sglist = 0; 52439aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus sg_state->bytes_read = 0; 52539aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus sg_state->len = len; 52639aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus sg_state->queued_sglist = 0; 52739aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus sg_state->csr = 0; 52839aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus sg_state->callback = callback; 52939aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus sg_state->arg = arg; 53039aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus 53139aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus sgdma->next_sgdma = (sgdma->next_sgdma + 1) % NUM_SG_DMA; 53239aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus sgdma->free_sgdma--; 53339aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus 53439aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus spin_unlock_irqrestore(&sgdma->lock, flags); 53539aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus 53639aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus omap24xxcam_sgdma_process(sgdma); 53739aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus 53839aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus return 0; 53939aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus} 54039aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus 54139aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus/* Sync scatter-gather DMA by aborting any DMA transfers currently in progress. 54239aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus * Any queued scatter-gather DMA transactions that have not yet been started 54339aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus * will remain queued. The DMA controller will be idle after this routine 54439aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus * completes. When the scatter-gather queue is restarted, the next 54539aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus * scatter-gather DMA transfer will begin at the start of a new transaction. 54639aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus */ 54739aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailusvoid omap24xxcam_sgdma_sync(struct omap24xxcam_sgdma *sgdma) 54839aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus{ 54939aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus unsigned long flags; 55039aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus int sgslot; 55139aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus struct sgdma_state *sg_state; 55239aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus u32 csr = CAMDMA_CSR_TRANS_ERR; 55339aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus 55439aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus /* stop any DMA transfers in progress */ 55539aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus omap24xxcam_dma_stop(&sgdma->dma, csr); 55639aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus 55739aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus spin_lock_irqsave(&sgdma->lock, flags); 55839aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus 55939aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus if (sgdma->free_sgdma < NUM_SG_DMA) { 56039aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus sgslot = (sgdma->next_sgdma + sgdma->free_sgdma) % NUM_SG_DMA; 56139aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus sg_state = sgdma->sg_state + sgslot; 56239aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus if (sg_state->next_sglist != 0) { 56339aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus /* This DMA transfer was in progress, so abort it. */ 56439aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus sgdma_callback_t callback = sg_state->callback; 56539aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus void *arg = sg_state->arg; 56639aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus sgdma->free_sgdma++; 56739aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus if (callback) { 56839aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus /* leave interrupts masked */ 56939aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus spin_unlock(&sgdma->lock); 57039aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus (*callback) (sgdma, csr, arg); 57139aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus spin_lock(&sgdma->lock); 57239aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus } 57339aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus } 57439aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus } 57539aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus 57639aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus spin_unlock_irqrestore(&sgdma->lock, flags); 57739aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus} 57839aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus 57939aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailusvoid omap24xxcam_sgdma_init(struct omap24xxcam_sgdma *sgdma, 58039aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus unsigned long base, 58139aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus void (*reset_callback)(unsigned long data), 58239aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus unsigned long reset_callback_data) 58339aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus{ 58439aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus int sg; 58539aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus 58639aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus spin_lock_init(&sgdma->lock); 58739aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus sgdma->free_sgdma = NUM_SG_DMA; 58839aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus sgdma->next_sgdma = 0; 58939aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus for (sg = 0; sg < NUM_SG_DMA; sg++) { 59039aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus sgdma->sg_state[sg].sglen = 0; 59139aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus sgdma->sg_state[sg].next_sglist = 0; 59239aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus sgdma->sg_state[sg].bytes_read = 0; 59339aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus sgdma->sg_state[sg].queued_sglist = 0; 59439aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus sgdma->sg_state[sg].csr = 0; 59539aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus sgdma->sg_state[sg].callback = NULL; 59639aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus sgdma->sg_state[sg].arg = NULL; 59739aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus } 59839aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus 59939aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus omap24xxcam_dma_init(&sgdma->dma, base); 60039aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus setup_timer(&sgdma->reset_timer, reset_callback, reset_callback_data); 60139aee69a166b775a38ed0053596cdb8e717ae315Sakari Ailus} 602