-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Signed-off-by: Brian Swetland <swetland@google.com>
- Loading branch information
Arve Hjønnevåg
authored and
Russell King
committed
Jan 26, 2008
1 parent
9e73c84
commit bfe645a
Showing
3 changed files
with
365 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,214 @@ | ||
/* linux/arch/arm/mach-msm/dma.c | ||
* | ||
* Copyright (C) 2007 Google, Inc. | ||
* | ||
* This software is licensed under the terms of the GNU General Public | ||
* License version 2, as published by the Free Software Foundation, and | ||
* may be copied, distributed, and modified under those terms. | ||
* | ||
* This program is distributed in the hope that it will be useful, | ||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
* GNU General Public License for more details. | ||
* | ||
*/ | ||
|
||
#include <asm/io.h> | ||
#include <linux/interrupt.h> | ||
#include <asm/arch/dma.h> | ||
|
||
#define MSM_DMOV_CHANNEL_COUNT 16 | ||
|
||
enum { | ||
MSM_DMOV_PRINT_ERRORS = 1, | ||
MSM_DMOV_PRINT_IO = 2, | ||
MSM_DMOV_PRINT_FLOW = 4 | ||
}; | ||
|
||
static DEFINE_SPINLOCK(msm_dmov_lock); | ||
static struct msm_dmov_cmd active_command; | ||
static struct list_head ready_commands[MSM_DMOV_CHANNEL_COUNT]; | ||
static struct list_head active_commands[MSM_DMOV_CHANNEL_COUNT]; | ||
unsigned int msm_dmov_print_mask = MSM_DMOV_PRINT_ERRORS; | ||
|
||
#define MSM_DMOV_DPRINTF(mask, format, args...) \ | ||
do { \ | ||
if ((mask) & msm_dmov_print_mask) \ | ||
printk(KERN_ERR format, args); \ | ||
} while (0) | ||
#define PRINT_ERROR(format, args...) \ | ||
MSM_DMOV_DPRINTF(MSM_DMOV_PRINT_ERRORS, format, args); | ||
#define PRINT_IO(format, args...) \ | ||
MSM_DMOV_DPRINTF(MSM_DMOV_PRINT_IO, format, args); | ||
#define PRINT_FLOW(format, args...) \ | ||
MSM_DMOV_DPRINTF(MSM_DMOV_PRINT_FLOW, format, args); | ||
|
||
void msm_dmov_enqueue_cmd(unsigned id, struct msm_dmov_cmd *cmd) | ||
{ | ||
unsigned long irq_flags; | ||
unsigned int status; | ||
|
||
spin_lock_irqsave(&msm_dmov_lock, irq_flags); | ||
status = readl(DMOV_STATUS(id)); | ||
if (list_empty(&ready_commands[id]) && | ||
(status & DMOV_STATUS_CMD_PTR_RDY)) { | ||
#if 0 | ||
if (list_empty(&active_commands[id])) { | ||
PRINT_FLOW("msm_dmov_enqueue_cmd(%d), enable interrupt\n", id); | ||
writel(DMOV_CONFIG_IRQ_EN, DMOV_CONFIG(id)); | ||
} | ||
#endif | ||
PRINT_IO("msm_dmov_enqueue_cmd(%d), start command, status %x\n", id, status); | ||
list_add_tail(&cmd->list, &active_commands[id]); | ||
writel(cmd->cmdptr, DMOV_CMD_PTR(id)); | ||
} else { | ||
if (list_empty(&active_commands[id])) | ||
PRINT_ERROR("msm_dmov_enqueue_cmd(%d), error datamover stalled, status %x\n", id, status); | ||
|
||
PRINT_IO("msm_dmov_enqueue_cmd(%d), enqueue command, status %x\n", id, status); | ||
list_add_tail(&cmd->list, &ready_commands[id]); | ||
} | ||
spin_unlock_irqrestore(&msm_dmov_lock, irq_flags); | ||
} | ||
|
||
struct msm_dmov_exec_cmdptr_cmd { | ||
struct msm_dmov_cmd dmov_cmd; | ||
struct completion complete; | ||
unsigned id; | ||
unsigned int result; | ||
unsigned int flush[6]; | ||
}; | ||
|
||
static void dmov_exec_cmdptr_complete_func(struct msm_dmov_cmd *_cmd, unsigned int result) | ||
{ | ||
struct msm_dmov_exec_cmdptr_cmd *cmd = container_of(_cmd, struct msm_dmov_exec_cmdptr_cmd, dmov_cmd); | ||
cmd->result = result; | ||
if (result != 0x80000002) { | ||
cmd->flush[0] = readl(DMOV_FLUSH0(cmd->id)); | ||
cmd->flush[1] = readl(DMOV_FLUSH1(cmd->id)); | ||
cmd->flush[2] = readl(DMOV_FLUSH2(cmd->id)); | ||
cmd->flush[3] = readl(DMOV_FLUSH3(cmd->id)); | ||
cmd->flush[4] = readl(DMOV_FLUSH4(cmd->id)); | ||
cmd->flush[5] = readl(DMOV_FLUSH5(cmd->id)); | ||
} | ||
complete(&cmd->complete); | ||
} | ||
|
||
int msm_dmov_exec_cmd(unsigned id, unsigned int cmdptr) | ||
{ | ||
struct msm_dmov_exec_cmdptr_cmd cmd; | ||
|
||
PRINT_FLOW("dmov_exec_cmdptr(%d, %x)\n", id, cmdptr); | ||
|
||
cmd.dmov_cmd.cmdptr = cmdptr; | ||
cmd.dmov_cmd.complete_func = dmov_exec_cmdptr_complete_func; | ||
cmd.id = id; | ||
init_completion(&cmd.complete); | ||
|
||
msm_dmov_enqueue_cmd(id, &cmd.dmov_cmd); | ||
wait_for_completion(&cmd.complete); | ||
|
||
if (cmd.result != 0x80000002) { | ||
PRINT_ERROR("dmov_exec_cmdptr(%d): ERROR, result: %x\n", id, cmd.result); | ||
PRINT_ERROR("dmov_exec_cmdptr(%d): flush: %x %x %x %x\n", | ||
id, cmd.flush[0], cmd.flush[1], cmd.flush[2], cmd.flush[3]); | ||
return -EIO; | ||
} | ||
PRINT_FLOW("dmov_exec_cmdptr(%d, %x) done\n", id, cmdptr); | ||
return 0; | ||
} | ||
|
||
|
||
static irqreturn_t msm_datamover_irq_handler(int irq, void *dev_id) | ||
{ | ||
unsigned int int_status, mask, id; | ||
unsigned long irq_flags; | ||
unsigned int ch_status; | ||
unsigned int ch_result; | ||
struct msm_dmov_cmd *cmd; | ||
|
||
spin_lock_irqsave(&msm_dmov_lock, irq_flags); | ||
|
||
int_status = readl(DMOV_ISR); /* read and clear interrupt */ | ||
PRINT_FLOW("msm_datamover_irq_handler: DMOV_ISR %x\n", int_status); | ||
|
||
while (int_status) { | ||
mask = int_status & -int_status; | ||
id = fls(mask) - 1; | ||
PRINT_FLOW("msm_datamover_irq_handler %08x %08x id %d\n", int_status, mask, id); | ||
int_status &= ~mask; | ||
ch_status = readl(DMOV_STATUS(id)); | ||
if (!(ch_status & DMOV_STATUS_RSLT_VALID)) { | ||
PRINT_FLOW("msm_datamover_irq_handler id %d, result not valid %x\n", id, ch_status); | ||
continue; | ||
} | ||
do { | ||
ch_result = readl(DMOV_RSLT(id)); | ||
if (list_empty(&active_commands[id])) { | ||
PRINT_ERROR("msm_datamover_irq_handler id %d, got result " | ||
"with no active command, status %x, result %x\n", | ||
id, ch_status, ch_result); | ||
cmd = NULL; | ||
} else | ||
cmd = list_entry(active_commands[id].next, typeof(*cmd), list); | ||
PRINT_FLOW("msm_datamover_irq_handler id %d, status %x, result %x\n", id, ch_status, ch_result); | ||
if (ch_result & DMOV_RSLT_DONE) { | ||
PRINT_FLOW("msm_datamover_irq_handler id %d, status %x\n", | ||
id, ch_status); | ||
PRINT_IO("msm_datamover_irq_handler id %d, got result " | ||
"for %p, result %x\n", id, cmd, ch_result); | ||
if (cmd) { | ||
list_del(&cmd->list); | ||
cmd->complete_func(cmd, ch_result); | ||
} | ||
} | ||
if (ch_result & DMOV_RSLT_FLUSH) { | ||
unsigned int flush0 = readl(DMOV_FLUSH0(id)); | ||
PRINT_FLOW("msm_datamover_irq_handler id %d, status %x\n", id, ch_status); | ||
PRINT_FLOW("msm_datamover_irq_handler id %d, flush, result %x, flush0 %x\n", id, ch_result, flush0); | ||
if (cmd) { | ||
list_del(&cmd->list); | ||
cmd->complete_func(cmd, ch_result); | ||
} | ||
} | ||
if (ch_result & DMOV_RSLT_ERROR) { | ||
unsigned int flush0 = readl(DMOV_FLUSH0(id)); | ||
PRINT_ERROR("msm_datamover_irq_handler id %d, status %x\n", id, ch_status); | ||
PRINT_ERROR("msm_datamover_irq_handler id %d, error, result %x, flush0 %x\n", id, ch_result, flush0); | ||
if (cmd) { | ||
list_del(&cmd->list); | ||
cmd->complete_func(cmd, ch_result); | ||
} | ||
/* this does not seem to work, once we get an error */ | ||
/* the datamover will no longer accept commands */ | ||
writel(0, DMOV_FLUSH0(id)); | ||
} | ||
ch_status = readl(DMOV_STATUS(id)); | ||
PRINT_FLOW("msm_datamover_irq_handler id %d, status %x\n", id, ch_status); | ||
if ((ch_status & DMOV_STATUS_CMD_PTR_RDY) && !list_empty(&ready_commands[id])) { | ||
cmd = list_entry(ready_commands[id].next, typeof(*cmd), list); | ||
list_del(&cmd->list); | ||
list_add_tail(&cmd->list, &active_commands[id]); | ||
PRINT_FLOW("msm_datamover_irq_handler id %d, start command\n", id); | ||
writel(cmd->cmdptr, DMOV_CMD_PTR(id)); | ||
} | ||
} while (ch_status & DMOV_STATUS_RSLT_VALID); | ||
PRINT_FLOW("msm_datamover_irq_handler id %d, status %x\n", id, ch_status); | ||
} | ||
spin_unlock_irqrestore(&msm_dmov_lock, irq_flags); | ||
return IRQ_HANDLED; | ||
} | ||
|
||
static int __init msm_init_datamover(void) | ||
{ | ||
int i; | ||
for (i = 0; i < MSM_DMOV_CHANNEL_COUNT; i++) { | ||
INIT_LIST_HEAD(&ready_commands[i]); | ||
INIT_LIST_HEAD(&active_commands[i]); | ||
writel(DMOV_CONFIG_IRQ_EN | DMOV_CONFIG_FORCE_TOP_PTR_RSLT | DMOV_CONFIG_FORCE_FLUSH_RSLT, DMOV_CONFIG(i)); | ||
} | ||
return request_irq(INT_ADM_AARM, msm_datamover_irq_handler, 0, "msmdatamover", NULL); | ||
} | ||
|
||
arch_initcall(msm_init_datamover); | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,151 @@ | ||
/* linux/include/asm-arm/arch-msm/dma.h | ||
* | ||
* Copyright (C) 2007 Google, Inc. | ||
* | ||
* This software is licensed under the terms of the GNU General Public | ||
* License version 2, as published by the Free Software Foundation, and | ||
* may be copied, distributed, and modified under those terms. | ||
* | ||
* This program is distributed in the hope that it will be useful, | ||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
* GNU General Public License for more details. | ||
* | ||
*/ | ||
|
||
#ifndef __ASM_ARCH_MSM_DMA_H | ||
|
||
#include <linux/list.h> | ||
#include <asm/arch/msm_iomap.h> | ||
|
||
struct msm_dmov_cmd { | ||
struct list_head list; | ||
unsigned int cmdptr; | ||
void (*complete_func)(struct msm_dmov_cmd *cmd, unsigned int result); | ||
/* void (*user_result_func)(struct msm_dmov_cmd *cmd); */ | ||
}; | ||
|
||
void msm_dmov_enqueue_cmd(unsigned id, struct msm_dmov_cmd *cmd); | ||
void msm_dmov_stop_cmd(unsigned id, struct msm_dmov_cmd *cmd); | ||
int msm_dmov_exec_cmd(unsigned id, unsigned int cmdptr); | ||
/* int msm_dmov_exec_cmd_etc(unsigned id, unsigned int cmdptr, int timeout, int interruptible); */ | ||
|
||
|
||
|
||
#define DMOV_SD0(off, ch) (MSM_DMOV_BASE + 0x0000 + (off) + ((ch) << 2)) | ||
#define DMOV_SD1(off, ch) (MSM_DMOV_BASE + 0x0400 + (off) + ((ch) << 2)) | ||
#define DMOV_SD2(off, ch) (MSM_DMOV_BASE + 0x0800 + (off) + ((ch) << 2)) | ||
#define DMOV_SD3(off, ch) (MSM_DMOV_BASE + 0x0C00 + (off) + ((ch) << 2)) | ||
|
||
/* only security domain 3 is available to the ARM11 | ||
* SD0 -> mARM trusted, SD1 -> mARM nontrusted, SD2 -> aDSP, SD3 -> aARM | ||
*/ | ||
|
||
#define DMOV_CMD_PTR(ch) DMOV_SD3(0x000, ch) | ||
#define DMOV_CMD_LIST (0 << 29) /* does not work */ | ||
#define DMOV_CMD_PTR_LIST (1 << 29) /* works */ | ||
#define DMOV_CMD_INPUT_CFG (2 << 29) /* untested */ | ||
#define DMOV_CMD_OUTPUT_CFG (3 << 29) /* untested */ | ||
#define DMOV_CMD_ADDR(addr) ((addr) >> 3) | ||
|
||
#define DMOV_RSLT(ch) DMOV_SD3(0x040, ch) | ||
#define DMOV_RSLT_VALID (1 << 31) /* 0 == host has empties result fifo */ | ||
#define DMOV_RSLT_ERROR (1 << 3) | ||
#define DMOV_RSLT_FLUSH (1 << 2) | ||
#define DMOV_RSLT_DONE (1 << 1) /* top pointer done */ | ||
#define DMOV_RSLT_USER (1 << 0) /* command with FR force result */ | ||
|
||
#define DMOV_FLUSH0(ch) DMOV_SD3(0x080, ch) | ||
#define DMOV_FLUSH1(ch) DMOV_SD3(0x0C0, ch) | ||
#define DMOV_FLUSH2(ch) DMOV_SD3(0x100, ch) | ||
#define DMOV_FLUSH3(ch) DMOV_SD3(0x140, ch) | ||
#define DMOV_FLUSH4(ch) DMOV_SD3(0x180, ch) | ||
#define DMOV_FLUSH5(ch) DMOV_SD3(0x1C0, ch) | ||
|
||
#define DMOV_STATUS(ch) DMOV_SD3(0x200, ch) | ||
#define DMOV_STATUS_RSLT_COUNT(n) (((n) >> 29)) | ||
#define DMOV_STATUS_CMD_COUNT(n) (((n) >> 27) & 3) | ||
#define DMOV_STATUS_RSLT_VALID (1 << 1) | ||
#define DMOV_STATUS_CMD_PTR_RDY (1 << 0) | ||
|
||
#define DMOV_ISR DMOV_SD3(0x380, 0) | ||
|
||
#define DMOV_CONFIG(ch) DMOV_SD3(0x300, ch) | ||
#define DMOV_CONFIG_FORCE_TOP_PTR_RSLT (1 << 2) | ||
#define DMOV_CONFIG_FORCE_FLUSH_RSLT (1 << 1) | ||
#define DMOV_CONFIG_IRQ_EN (1 << 0) | ||
|
||
/* channel assignments */ | ||
|
||
#define DMOV_NAND_CHAN 7 | ||
#define DMOV_NAND_CRCI_CMD 5 | ||
#define DMOV_NAND_CRCI_DATA 4 | ||
|
||
#define DMOV_SDC1_CHAN 8 | ||
#define DMOV_SDC1_CRCI 6 | ||
|
||
#define DMOV_SDC2_CHAN 8 | ||
#define DMOV_SDC2_CRCI 7 | ||
|
||
#define DMOV_TSIF_CHAN 10 | ||
#define DMOV_TSIF_CRCI 10 | ||
|
||
#define DMOV_USB_CHAN 11 | ||
|
||
/* no client rate control ifc (eg, ram) */ | ||
#define DMOV_NONE_CRCI 0 | ||
|
||
|
||
/* If the CMD_PTR register has CMD_PTR_LIST selected, the data mover | ||
* is going to walk a list of 32bit pointers as described below. Each | ||
* pointer points to a *array* of dmov_s, etc structs. The last pointer | ||
* in the list is marked with CMD_PTR_LP. The last struct in each array | ||
* is marked with CMD_LC (see below). | ||
*/ | ||
#define CMD_PTR_ADDR(addr) ((addr) >> 3) | ||
#define CMD_PTR_LP (1 << 31) /* last pointer */ | ||
#define CMD_PTR_PT (3 << 29) /* ? */ | ||
|
||
/* Single Item Mode */ | ||
typedef struct { | ||
unsigned cmd; | ||
unsigned src; | ||
unsigned dst; | ||
unsigned len; | ||
} dmov_s; | ||
|
||
/* Scatter/Gather Mode */ | ||
typedef struct { | ||
unsigned cmd; | ||
unsigned src_dscr; | ||
unsigned dst_dscr; | ||
unsigned _reserved; | ||
} dmov_sg; | ||
|
||
/* bits for the cmd field of the above structures */ | ||
|
||
#define CMD_LC (1 << 31) /* last command */ | ||
#define CMD_FR (1 << 22) /* force result -- does not work? */ | ||
#define CMD_OCU (1 << 21) /* other channel unblock */ | ||
#define CMD_OCB (1 << 20) /* other channel block */ | ||
#define CMD_TCB (1 << 19) /* ? */ | ||
#define CMD_DAH (1 << 18) /* destination address hold -- does not work?*/ | ||
#define CMD_SAH (1 << 17) /* source address hold -- does not work? */ | ||
|
||
#define CMD_MODE_SINGLE (0 << 0) /* dmov_s structure used */ | ||
#define CMD_MODE_SG (1 << 0) /* untested */ | ||
#define CMD_MODE_IND_SG (2 << 0) /* untested */ | ||
#define CMD_MODE_BOX (3 << 0) /* untested */ | ||
|
||
#define CMD_DST_SWAP_BYTES (1 << 14) /* exchange each byte n with byte n+1 */ | ||
#define CMD_DST_SWAP_SHORTS (1 << 15) /* exchange each short n with short n+1 */ | ||
#define CMD_DST_SWAP_WORDS (1 << 16) /* exchange each word n with word n+1 */ | ||
|
||
#define CMD_SRC_SWAP_BYTES (1 << 11) /* exchange each byte n with byte n+1 */ | ||
#define CMD_SRC_SWAP_SHORTS (1 << 12) /* exchange each short n with short n+1 */ | ||
#define CMD_SRC_SWAP_WORDS (1 << 13) /* exchange each word n with word n+1 */ | ||
|
||
#define CMD_DST_CRCI(n) (((n) & 15) << 7) | ||
#define CMD_SRC_CRCI(n) (((n) & 15) << 3) | ||
|
||
#endif |