Add PL330 Dma

This commit is contained in:
fang
2010-10-26 15:24:14 +08:00
parent e937295366
commit 431193bde0
11 changed files with 3741 additions and 2 deletions

View File

@@ -15,6 +15,9 @@ config ARM_VIC_NR
config ICST525
bool
config PL330
bool
config ICST307
bool

View File

@@ -5,6 +5,7 @@
obj-$(CONFIG_ARM_GIC) += gic.o
obj-$(CONFIG_ARM_VIC) += vic.o
obj-$(CONFIG_ICST525) += icst525.o
obj-$(CONFIG_PL330) += pl330.o
obj-$(CONFIG_ICST307) += icst307.o
obj-$(CONFIG_SA1111) += sa1111.o
obj-$(CONFIG_PCI_HOST_VIA82C505) += via82c505.o

1966
arch/arm/common/pl330.c Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,217 @@
/* linux/include/asm/hardware/pl330.h
*
* Copyright (C) 2010 Samsung Electronics Co. Ltd.
* Jaswinder Singh <jassi.brar@samsung.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* 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.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef __PL330_CORE_H
#define __PL330_CORE_H
#define PL330_MAX_CHAN 8
#define PL330_MAX_IRQS 32
#define PL330_MAX_PERI 32
enum pl330_srccachectrl {
SCCTRL0 = 0, /* Noncacheable and nonbufferable */
SCCTRL1, /* Bufferable only */
SCCTRL2, /* Cacheable, but do not allocate */
SCCTRL3, /* Cacheable and bufferable, but do not allocate */
SINVALID1,
SINVALID2,
SCCTRL6, /* Cacheable write-through, allocate on reads only */
SCCTRL7, /* Cacheable write-back, allocate on reads only */
};
enum pl330_dstcachectrl {
DCCTRL0 = 0, /* Noncacheable and nonbufferable */
DCCTRL1, /* Bufferable only */
DCCTRL2, /* Cacheable, but do not allocate */
DCCTRL3, /* Cacheable and bufferable, but do not allocate */
DINVALID1 = 8,
DINVALID2,
DCCTRL6, /* Cacheable write-through, allocate on writes only */
DCCTRL7, /* Cacheable write-back, allocate on writes only */
};
/* Populated by the PL330 core driver for DMA API driver's info */
struct pl330_config {
u32 periph_id;
u32 pcell_id;
#define DMAC_MODE_NS (1 << 0)
unsigned int mode;
unsigned int data_bus_width:10; /* In number of bits */
unsigned int data_buf_dep:10;
unsigned int num_chan:4;
unsigned int num_peri:6;
u32 peri_ns;
unsigned int num_events:6;
u32 irq_ns;
};
/* Handle to the DMAC provided to the PL330 core */
struct pl330_info {
/* Owning device */
struct device *dev;
/* Size of MicroCode buffers for each channel. */
unsigned mcbufsz;
/* ioremap'ed address of PL330 registers. */
void __iomem *base;
/* Client can freely use it. */
void *client_data;
/* PL330 core data, Client must not touch it. */
void *pl330_data;
/* Populated by the PL330 core driver during pl330_add */
struct pl330_config pcfg;
/*
* If the DMAC has some reset mechanism, then the
* client may want to provide pointer to the method.
*/
void (*dmac_reset)(struct pl330_info *pi);
};
enum pl330_byteswap {
SWAP_NO = 0,
SWAP_2,
SWAP_4,
SWAP_8,
SWAP_16,
};
/**
* Request Configuration.
* The PL330 core does not modify this and uses the last
* working configuration if the request doesn't provide any.
*
* The Client may want to provide this info only for the
* first request and a request with new settings.
*/
struct pl330_reqcfg {
/* Address Incrementing */
unsigned dst_inc:1;
unsigned src_inc:1;
/*
* For now, the SRC & DST protection levels
* and burst size/length are assumed same.
*/
bool nonsecure;
bool privileged;
bool insnaccess;
unsigned brst_len:5;
unsigned brst_size:3; /* in power of 2 */
enum pl330_dstcachectrl dcctl;
enum pl330_srccachectrl scctl;
enum pl330_byteswap swap;
};
/*
* One cycle of DMAC operation.
* There may be more than one xfer in a request.
*/
struct pl330_xfer {
u32 src_addr;
u32 dst_addr;
/* Size to xfer */
u32 bytes;
/*
* Pointer to next xfer in the list.
* The last xfer in the req must point to NULL.
*/
struct pl330_xfer *next;
};
/* The xfer callbacks are made with one of these arguments. */
enum pl330_op_err {
/* The all xfers in the request were success. */
PL330_ERR_NONE,
/* If req aborted due to global error. */
PL330_ERR_ABORT,
/* If req failed due to problem with Channel. */
PL330_ERR_FAIL,
};
enum pl330_reqtype {
MEMTOMEM,
MEMTODEV,
DEVTOMEM,
DEVTODEV,
};
/* A request defining Scatter-Gather List ending with NULL xfer. */
struct pl330_req {
enum pl330_reqtype rqtype;
/* Index of peripheral for the xfer. */
unsigned peri:5;
/* Unique token for this xfer, set by the client. */
void *token;
/* Callback to be called after xfer. */
void (*xfer_cb)(void *token, enum pl330_op_err err);
/* If NULL, req will be done at last set parameters. */
struct pl330_reqcfg *cfg;
/* Pointer to first xfer in the request. */
struct pl330_xfer *x;
};
/*
* To know the status of the channel and DMAC, the client
* provides a pointer to this structure. The PL330 core
* fills it with current information.
*/
struct pl330_chanstatus {
/*
* If the DMAC engine halted due to some error,
* the client should remove-add DMAC.
*/
bool dmac_halted;
/*
* If channel is halted due to some error,
* the client should ABORT/FLUSH and START the channel.
*/
bool faulting;
/* Location of last load */
u32 src_addr;
/* Location of last store */
u32 dst_addr;
/*
* Pointer to the currently active req, NULL if channel is
* inactive, even though the requests may be present.
*/
struct pl330_req *top_req;
/* Pointer to req waiting second in the queue if any. */
struct pl330_req *wait_req;
};
enum pl330_chan_op {
/* Start the channel */
PL330_OP_START,
/* Abort the active xfer */
PL330_OP_ABORT,
/* Stop xfer and flush queue */
PL330_OP_FLUSH,
};
extern int pl330_add(struct pl330_info *);
extern void pl330_del(struct pl330_info *pi);
extern int pl330_update(const struct pl330_info *pi);
extern void pl330_release_channel(void *ch_id);
extern void *pl330_request_channel(const struct pl330_info *pi);
extern int pl330_chan_status(void *ch_id, struct pl330_chanstatus *pstatus);
extern int pl330_chan_ctrl(void *ch_id, enum pl330_chan_op op);
extern int pl330_submit_req(void *ch_id, struct pl330_req *r);
#endif /* __PL330_CORE_H */

View File

@@ -2,5 +2,6 @@ config MACH_RK29SDK
depends on ARCH_RK29
default y
bool "ROCKCHIP Board Rk29 For Sdk"
help
select PL330
help
Support for the ROCKCHIP Board For Rk29 Sdk.

View File

@@ -1,2 +1,2 @@
obj-y += timer.o io.o devices.o iomux.o clock.o
obj-y += timer.o io.o devices.o iomux.o clock.o rk29-pl330.o dma.o
obj-$(CONFIG_MACH_RK29SDK) += board-rk29sdk.o

114
arch/arm/mach-rk29/dma.c Normal file
View File

@@ -0,0 +1,114 @@
#include <linux/platform_device.h>
#include <linux/dma-mapping.h>
#include <mach/rk29_iomap.h>
#include <mach/irqs.h>
#include <mach/rk29-dma-pl330.h>
static u64 dma_dmamask = DMA_BIT_MASK(16);
static struct resource rk29_dmac0_resource[] = {
[0] = {
.start = RK29_DMAC0_PHYS,
.end = RK29_DMAC0_PHYS + RK29_DMAC0_SIZE,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = IRQ_DMAC0_0,
.end = IRQ_DMAC0_0,
.flags = IORESOURCE_IRQ,
},
};
static struct rk29_pl330_platdata rk29_dmac0_pdata = {
.peri = {
[0] = DMACH_UART0_TX,
[1] = DMACH_UART0_RX,
[2] = DMACH_I2S_8CH_TX,
[3] = DMACH_I2S_8CH_RX,
[4] = DMACH_I2S_2CH_TX,
[5] = DMACH_I2S_2CH_RX,
[6] = DMACH_SPDIF,
[7] = DMACH_MAX,
[8] = DMACH_MAX,
[9] = DMACH_MAX,
[10] = DMACH_MAX,
[11] = DMACH_MAX,
[12] = DMACH_MAX,
[13] = DMACH_MAX,
[14] = DMACH_MAX,
[15] = DMACH_MAX,
},
};
static struct platform_device rk29_device_dmac0 = {
.name = "rk29-pl330",
.id = 1,
.num_resources = ARRAY_SIZE(rk29_dmac0_resource),
.resource = rk29_dmac0_resource,
.dev = {
.dma_mask = &dma_dmamask,
.coherent_dma_mask = DMA_BIT_MASK(16),
.platform_data = &rk29_dmac0_pdata,
},
};
static struct resource rk29_dmac2_resource[] = {
[0] = {
.start = RK29_DMA2_PHYS,
.end = RK29_DMA2_PHYS + RK29_DMA2_SIZE,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = IRQ_DMAC2_0,
.end = IRQ_DMAC2_0,
.flags = IORESOURCE_IRQ,
},
};
static struct rk29_pl330_platdata rk29_dmac2_pdata = {
.peri = {
[0] = DMACH_HSADC,
[1] = DMACH_SDMMC,
[2] = DMACH_SDIO,
[3] = DMACH_EMMC,
[4] = DMACH_UART1_TX,
[5] = DMACH_UART1_RX,
[6] = DMACH_UART2_TX,
[7] = DMACH_UART2_RX,
[8] = DMACH_UART3_TX,
[9] = DMACH_UART3_RX,
[10] = DMACH_SPI0_TX,
[11] = DMACH_SPI0_RX,
[12] = DMACH_SPI1_TX,
[13] = DMACH_SPI1_RX,
[14] = DMACH_PID_FILTER,
[15] = DMACH_MAX,
},
};
static struct platform_device rk29_device_dmac2 = {
.name = "rk29-pl330",
.id = 2,
.num_resources = ARRAY_SIZE(rk29_dmac2_resource),
.resource = rk29_dmac2_resource,
.dev = {
.dma_mask = &dma_dmamask,
.coherent_dma_mask = DMA_BIT_MASK(16),
.platform_data = &rk29_dmac2_pdata,
},
};
static struct platform_device *rk29_dmacs[] __initdata = {
&rk29_device_dmac0,
&rk29_device_dmac2,
};
static int __init rk29_dma_init(void)
{
platform_add_devices(rk29_dmacs, ARRAY_SIZE(rk29_dmacs));
return 0;
}
arch_initcall(rk29_dma_init);

View File

@@ -0,0 +1,127 @@
/* arch/arm/plat-samsung/include/plat/dma.h
*
* Copyright (C) 2003-2006 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk>
*
* Samsung rk29 DMA support
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
enum rk29_dma_buffresult {
RK29_RES_OK,
RK29_RES_ERR,
RK29_RES_ABORT
};
enum rk29_dmasrc {
RK29_DMASRC_HW, /* source is memory */
RK29_DMASRC_MEM /* source is hardware */
};
/* enum rk29_chan_op
*
* operation codes passed to the DMA code by the user, and also used
* to inform the current channel owner of any changes to the system state
*/
enum rk29_chan_op {
RK29_DMAOP_START,
RK29_DMAOP_STOP,
RK29_DMAOP_PAUSE,
RK29_DMAOP_RESUME,
RK29_DMAOP_FLUSH,
RK29_DMAOP_TIMEOUT, /* internal signal to handler */
RK29_DMAOP_STARTED, /* indicate channel started */
};
struct rk29_dma_client {
char *name;
};
struct rk29_dma_chan;
/* rk29_dma_cbfn_t
*
* buffer callback routine type
*/
typedef void (*rk29_dma_cbfn_t)(struct rk29_dma_chan *,
void *buf, int size,
enum rk29_dma_buffresult result);
typedef int (*rk29_dma_opfn_t)(struct rk29_dma_chan *,
enum rk29_chan_op );
/* rk29_dma_request
*
* request a dma channel exclusivley
*/
extern int rk29_dma_request(unsigned int channel,
struct rk29_dma_client *, void *dev);
/* rk29_dma_ctrl
*
* change the state of the dma channel
*/
extern int rk29_dma_ctrl(unsigned int channel, enum rk29_chan_op op);
/* rk29_dma_setflags
*
* set the channel's flags to a given state
*/
extern int rk29_dma_setflags(unsigned int channel,
unsigned int flags);
/* rk29_dma_free
*
* free the dma channel (will also abort any outstanding operations)
*/
extern int rk29_dma_free(unsigned int channel, struct rk29_dma_client *);
/* rk29_dma_enqueue
*
* place the given buffer onto the queue of operations for the channel.
* The buffer must be allocated from dma coherent memory, or the Dcache/WB
* drained before the buffer is given to the DMA system.
*/
extern int rk29_dma_enqueue(unsigned int channel, void *id,
dma_addr_t data, int size);
/* rk29_dma_config
*
* configure the dma channel
*/
extern int rk29_dma_config(unsigned int channel, int xferunit);
/* rk29_dma_devconfig
*
* configure the device we're talking to
*/
extern int rk29_dma_devconfig(unsigned int channel,
enum rk29_dmasrc source, unsigned long devaddr);
/* rk29_dma_getposition
*
* get the position that the dma transfer is currently at
*/
extern int rk29_dma_getposition(unsigned int channel,
dma_addr_t *src, dma_addr_t *dest);
extern int rk29_dma_set_opfn(unsigned int, rk29_dma_opfn_t rtn);
extern int rk29_dma_set_buffdone_fn(unsigned int, rk29_dma_cbfn_t rtn);

View File

@@ -19,6 +19,17 @@
#define RK29XX_IRQ(x) (x+32)
#define IRQ_DMAC0_0 RK29XX_IRQ(0)
#define IRQ_DMAC0_1 RK29XX_IRQ(1)
#define IRQ_DMAC0_2 RK29XX_IRQ(2)
#define IRQ_DMAC0_3 RK29XX_IRQ(3)
#define IRQ_DMAC2_0 RK29XX_IRQ(4)
#define IRQ_DMAC2_1 RK29XX_IRQ(5)
#define IRQ_DMAC2_2 RK29XX_IRQ(6)
#define IRQ_DMAC2_3 RK29XX_IRQ(7)
#define IRQ_DMAC2_4 RK29XX_IRQ(8)
#define IRQ_GPU RK29XX_IRQ(9)
#define IRQ_VEPU RK29XX_IRQ(10)
#define IRQ_VDPU RK29XX_IRQ(11)

View File

@@ -0,0 +1,75 @@
/*
* Copyright (C) 2010 RockChip Electronics Co. Ltd.
* ZhenFu Fang <fzf@rock-chips.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
#ifndef __RK29_DMA_PL330_H_
#define __RK29_DMA_PL330_H_
#define RK29_DMAF_AUTOSTART (1 << 0)
#define RK29_DMAF_CIRCULAR (1 << 1)
/*
* PL330 can assign any channel to communicate with
* any of the peripherals attched to the DMAC.
* For the sake of consistency across client drivers,
* We keep the channel names unchanged and only add
* missing peripherals are added.
* Order is not important since rk29 PL330 API driver
* use these just as IDs.
*/
enum dma_ch {
DMACH_UART0_TX,
DMACH_UART0_RX,
DMACH_I2S_8CH_TX,
DMACH_I2S_8CH_RX,
DMACH_I2S_2CH_TX,
DMACH_I2S_2CH_RX,
DMACH_SPDIF,
DMACH_HSADC,
DMACH_SDMMC,
DMACH_SDIO,
DMACH_EMMC,
DMACH_UART1_TX,
DMACH_UART1_RX,
DMACH_UART2_TX,
DMACH_UART2_RX,
DMACH_UART3_TX,
DMACH_UART3_RX,
DMACH_SPI0_TX,
DMACH_SPI0_RX,
DMACH_SPI1_TX,
DMACH_SPI1_RX,
DMACH_PID_FILTER,
/* END Marker, also used to denote a reserved channel */
DMACH_MAX,
};
static inline bool rk29_dma_has_circular(void)
{
return true;
}
/*
* Every PL330 DMAC has max 32 peripheral interfaces,
* of which some may be not be really used in your
* DMAC's configuration.
* Populate this array of 32 peri i/fs with relevant
* channel IDs for used peri i/f and DMACH_MAX for
* those unused.
*
* The platforms just need to provide this info
* to the rk29 DMA API driver for PL330.
*/
struct rk29_pl330_platdata {
enum dma_ch peri[16];
};
#include <mach/dma.h>
#endif /* __RK29_DMA_PL330_H_ */

File diff suppressed because it is too large Load Diff