socsvn commit: r287418 - soc2015/pratiksinghal/cubie-head/sys/arm/allwinner
pratiksinghal at FreeBSD.org
pratiksinghal at FreeBSD.org
Sun Jun 21 07:48:02 UTC 2015
Author: pratiksinghal
Date: Sun Jun 21 07:48:00 2015
New Revision: 287418
URL: http://svnweb.FreeBSD.org/socsvn/?view=rev&rev=287418
Log:
Cleaned up code
Replaced:
soc2015/pratiksinghal/cubie-head/sys/arm/allwinner/a10_mmc.c (contents, props changed)
- copied, changed from r287417, mirror/FreeBSD/head/sys/arm/allwinner/a10_mmc.c
Copied and modified: soc2015/pratiksinghal/cubie-head/sys/arm/allwinner/a10_mmc.c (from r287417, mirror/FreeBSD/head/sys/arm/allwinner/a10_mmc.c)
==============================================================================
--- mirror/FreeBSD/head/sys/arm/allwinner/a10_mmc.c Sun Jun 21 06:57:40 2015 (r287417, copy source)
+++ soc2015/pratiksinghal/cubie-head/sys/arm/allwinner/a10_mmc.c Sun Jun 21 07:48:00 2015 (r287418)
@@ -38,6 +38,7 @@
#include <sys/resource.h>
#include <sys/rman.h>
#include <sys/sysctl.h>
+#include <sys/endian.h>
#include <machine/bus.h>
@@ -48,12 +49,21 @@
#include <dev/mmc/mmcreg.h>
#include <dev/mmc/mmcbrvar.h>
+
#include <arm/allwinner/a10_clk.h>
#include <arm/allwinner/a10_mmc.h>
#define A10_MMC_MEMRES 0
#define A10_MMC_IRQRES 1
#define A10_MMC_RESSZ 2
+#define A10_MMC_NDESC 16
+#define A10_DMA_NSEGS 16
+#define A10_DMA_BUFF_SIZE 0x2000
+#define A10_DMA_MAX_SIZE 0x20000
+#define A10_MMC_DMA_FTRGLEVEL_A20 0x20070008
+#define A10_MMC_DMA_FTRGLEVEL_A10 0x00070208
+#define A10_MMC_DMA_MAXLEN (A10_DMA_MAX_SIZE)
+#define A10_MMC_DMA_MINLEN 512
struct a10_mmc_softc {
bus_space_handle_t a10_bsh;
@@ -69,8 +79,22 @@
struct mtx a10_mtx;
struct resource * a10_res[A10_MMC_RESSZ];
uint32_t a10_intr;
+ uint32_t a10_idst ;
uint32_t a10_intr_wait;
void * a10_intrhand;
+ int a10_use_dma ;
+
+ /* Fields required for DMA access */
+ bus_addr_t a10_dma_cb_arg ;
+ bus_dmamap_t a10_dma_map ;
+ bus_dma_tag_t a10_dma_tag ;
+ void* a10_dma_desc ;
+ bus_dma_tag_t a10_dma_buff_tag ;
+ bus_dmamap_t a10_dma_buff_map ;
+ bus_addr_t a10_dma_buff_addrs[A10_DMA_NSEGS] ;
+ bus_size_t a10_dma_buff_sizes[A10_DMA_NSEGS] ;
+ uint32_t a10_dma_nsegs ;
+
};
static struct resource_spec a10_mmc_res_spec[] = {
@@ -81,11 +105,16 @@
static int a10_mmc_probe(device_t);
static int a10_mmc_attach(device_t);
+static int a10_mmc_setup_dma(struct a10_mmc_softc*, device_t) ;
+static int a10_mmc_prepare_dma(struct a10_mmc_softc*) ;
+static int a10_mmc_can_do_dma(struct mmc_request*) ;
+static void a10_dma_buff_cb(void*, bus_dma_segment_t*, int, int) ;
static int a10_mmc_detach(device_t);
static int a10_mmc_reset(struct a10_mmc_softc *);
static void a10_mmc_intr(void *);
static int a10_mmc_update_clock(struct a10_mmc_softc *);
+static void a10_dma_cb(void*, bus_dma_segment_t*, int, int) ;
static int a10_mmc_update_ios(device_t, device_t);
static int a10_mmc_request(device_t, device_t, struct mmc_request *);
static int a10_mmc_get_ro(device_t, device_t);
@@ -98,6 +127,12 @@
bus_space_read_4((_sc)->a10_bst, (_sc)->a10_bsh, _reg)
#define A10_MMC_WRITE_4(_sc, _reg, _value) \
bus_space_write_4((_sc)->a10_bst, (_sc)->a10_bsh, _reg, _value)
+#define A10_MMC_READ_2(_sc, _reg) \
+ bus_space_read_2((_sc)->a10_bst, (_sc)->a10_bsh, _reg)
+#define A10_MMC_WRITE_2(_sc, _reg, _value) \
+ bus_space_write_2((_sc)->a10_bst, (_sc)->a10_bsh, _reg, _value)
+
+
static int
a10_mmc_probe(device_t dev)
@@ -121,6 +156,7 @@
struct sysctl_oid_list *tree;
sc = device_get_softc(dev);
+ sc->a10_use_dma = 1 ;
sc->a10_dev = dev;
sc->a10_req = NULL;
sc->a10_id = device_get_unit(dev);
@@ -183,6 +219,17 @@
goto fail;
}
+ if (sc->a10_use_dma == 1) {
+ if (a10_mmc_setup_dma(sc,dev) != 0) {
+ device_printf(sc->a10_dev, "Couldn't setup DMA!\n") ;
+ sc->a10_use_dma = 0 ;
+ }
+ }
+ //device_printf(sc->a10_dev, "The address of desc is %p\n",sc->a10_dma_desc) ;
+ sc->a10_dma_nsegs = 0 ;
+#ifdef DEBUG
+ device_printf(sc->a10_dev, "DMA status %d\n", sc->a10_use_dma) ;
+#endif
return (0);
fail:
@@ -195,6 +242,154 @@
}
static int
+a10_mmc_setup_dma(struct a10_mmc_softc* sc, device_t dev)
+{
+ uint32_t a10_dma_size = sizeof(struct a10_mmc_dma_desc)*(A10_MMC_NDESC);
+
+ uint32_t error ;
+ error = bus_dma_tag_create(bus_get_dma_tag(dev),1,
+ a10_dma_size,BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR,
+ NULL,NULL,a10_dma_size,
+ 1,a10_dma_size,0,
+ NULL,NULL,&sc->a10_dma_tag) ;
+ if (error)
+ return (error) ;
+ error = bus_dmamem_alloc(sc->a10_dma_tag,&sc->a10_dma_desc,BUS_DMA_WAITOK|BUS_DMA_ZERO,&sc->a10_dma_map) ;
+ if (error)
+ return (error) ;
+
+ error = bus_dmamap_load(sc->a10_dma_tag, sc->a10_dma_map,sc->a10_dma_desc,a10_dma_size,a10_dma_cb, &sc->a10_dma_cb_arg,0) ;
+
+ if ((error != 0)&&(error != EINPROGRESS))
+ return (error) ;
+ error = bus_dma_tag_create(bus_get_dma_tag(dev),1,
+ 0,BUS_SPACE_MAXADDR_32BIT,BUS_SPACE_MAXADDR,
+ NULL,NULL,A10_DMA_MAX_SIZE,
+ A10_DMA_NSEGS,A10_DMA_BUFF_SIZE,0,
+ NULL,NULL,&sc->a10_dma_buff_tag) ;
+ if (error)
+ return (error) ;
+
+ error = bus_dmamap_create(sc->a10_dma_buff_tag,0,&sc->a10_dma_buff_map) ;
+ if (error)
+ return (error) ;
+
+ return(0) ;
+
+}
+
+static int
+a10_mmc_prepare_dma(struct a10_mmc_softc* sc)
+{
+
+ struct a10_mmc_dma_desc* dma = sc->a10_dma_desc ;
+ struct mmc_command* cmd = sc->a10_req->cmd ;
+ bus_addr_t desc_paddr = sc->a10_dma_cb_arg ;
+ int desc, rem ;
+ uint32_t val;
+ desc = 0 ;
+ rem = min(A10_MMC_DMA_MAXLEN,cmd->data->len) ;
+ uint32_t error = bus_dmamap_load(sc->a10_dma_buff_tag, sc->a10_dma_buff_map,
+ cmd->data->data,rem,a10_dma_buff_cb,
+ sc,0) ;
+ if (error == EINPROGRESS) {
+ for( ; sc->a10_dma_nsegs == 0 ; ) { }
+ }
+ else if (error != 0) {
+ device_printf(sc->a10_dev, "DMA transaction failed due to insufficient resources! error = %u\n",error) ;
+ return EIO ;
+ }
+
+ dma[0].config |= htole32(A10_MMC_DMA_CONFIG_FD) ;
+ while (desc < A10_MMC_NDESC) {
+ dma[desc].buff_size = htole32(sc->a10_dma_buff_sizes[desc]) ;
+ dma[desc].buff_addr = htole32(sc->a10_dma_buff_addrs[desc]) ;
+ dma[desc].config = htole32(A10_MMC_DMA_CONFIG_CH|A10_MMC_DMA_CONFIG_OWN) ;
+ rem -= sc->a10_dma_buff_sizes[desc] ;
+ cmd->data->len -= sc->a10_dma_buff_sizes[desc] ;
+ if (rem > 0) {
+ dma[desc].config |= htole32(A10_MMC_DMA_CONFIG_DIC) ;
+ dma[desc].next = htole32(desc_paddr + ((desc+1)*sizeof(struct a10_mmc_dma_desc))) ;
+ }
+ else {
+ dma[desc].config |= htole32(A10_MMC_DMA_CONFIG_LD | A10_MMC_DMA_CONFIG_ER) ;
+ dma[desc].next = 0 ;
+ break ;
+ }
+ desc++ ;
+ }
+ if (rem > 0) {
+ device_printf(sc->a10_dev, "Couldn't find enough descriptors for DMA transfer!, rem = %d\n", rem);
+ return EIO ;
+ }
+
+ if (sc->a10_req->cmd->data->flags & MMC_DATA_WRITE)
+ bus_dmamap_sync(sc->a10_dma_buff_tag, sc->a10_dma_buff_map, BUS_DMASYNC_PREWRITE) ;
+ else
+ bus_dmamap_sync(sc->a10_dma_buff_tag, sc->a10_dma_buff_map, BUS_DMASYNC_PREREAD) ;
+
+ bus_dmamap_sync(sc->a10_dma_tag, sc->a10_dma_map, BUS_DMASYNC_PREWRITE) ;
+
+ val = A10_MMC_READ_4(sc, A10_MMC_GCTRL) ;
+ val |= A10_MMC_DMA_ENABLE ;
+ val |= A10_MMC_INT_ENABLE ;
+ A10_MMC_WRITE_4(sc, A10_MMC_GCTRL,val) ;
+ val |= A10_MMC_DMA_RESET ;
+ A10_MMC_WRITE_4(sc, A10_MMC_GCTRL,val) ;
+ A10_MMC_WRITE_4(sc, A10_MMC_DMAC,A10_MMC_IDMAC_SOFT_RST) ;
+ A10_MMC_WRITE_4(sc, A10_MMC_DMAC,A10_MMC_IDMAC_IDMA_ON | A10_MMC_IDMAC_FIX_BURST) ;
+ val = A10_MMC_READ_4(sc,A10_MMC_IDIE) ;
+ val &= ~(A10_MMC_IDMAC_RECEIVE_INT | A10_MMC_IDMAC_TRANSMIT_INT) ;
+ A10_MMC_WRITE_4(sc,A10_MMC_IDIE, val) ;
+ if (sc->a10_req->cmd->data->flags & MMC_DATA_WRITE)
+ val |= A10_MMC_IDMAC_TRANSMIT_INT ;
+ else
+ val |= A10_MMC_IDMAC_RECEIVE_INT ;
+ A10_MMC_WRITE_4(sc, A10_MMC_IDIE,val) ;
+ A10_MMC_WRITE_4(sc, A10_MMC_DLBA,desc_paddr) ;
+ A10_MMC_WRITE_4(sc, A10_MMC_FTRGL,A10_MMC_DMA_FTRGLEVEL_A10) ;
+
+ return (0) ;
+}
+
+
+static int
+a10_mmc_can_do_dma(struct mmc_request* req)
+{
+ if (req->cmd->data->len >= A10_MMC_DMA_MAXLEN)
+ //if ((req->cmd->data->len > A10_MMC_DMA_MAXLEN) || (req->cmd->data->len <= A10_MMC_DMA_MINLEN))
+ return (0) ;
+ else
+ return (1) ;
+}
+static void
+a10_dma_cb(void* arg, bus_dma_segment_t* segs, int nsegs, int error)
+{
+ if (error) {
+ printf("a10_mmc: Error in a10_dma_callback function, code = %d\n",error) ;
+ return ;
+ }
+
+ *(bus_addr_t*)arg = segs[0].ds_addr ;
+}
+
+static void
+a10_dma_buff_cb(void* arg, bus_dma_segment_t* segs, int nsegs, int error)
+{
+ if (error) {
+ printf("a10_mmc: Error in a10_dma_buff_callback function, code = %d\n", error) ;
+ return ;
+ }
+ int i ;
+ struct a10_mmc_softc* sc = (struct a10_mmc_softc*) arg ;
+ sc->a10_dma_nsegs = nsegs ;
+ for(i=0; i<nsegs; i++) {
+ sc->a10_dma_buff_addrs[i] = segs[i].ds_addr ;
+ sc->a10_dma_buff_sizes[i] = segs[i].ds_len ;
+ }
+}
+
+static int
a10_mmc_detach(device_t dev)
{
@@ -217,21 +412,18 @@
if (timeout == 0)
return (ETIMEDOUT);
- /* Set the timeout. */
A10_MMC_WRITE_4(sc, A10_MMC_TIMEOUT, 0xffffffff);
-
- /* Clear pending interrupts. */
A10_MMC_WRITE_4(sc, A10_MMC_RINTR, 0xffffffff);
+ A10_MMC_WRITE_4(sc, A10_MMC_IDST, 0xffffffff) ;
/* Unmask interrupts. */
A10_MMC_WRITE_4(sc, A10_MMC_IMASK,
A10_MMC_CMD_DONE | A10_MMC_INT_ERR_BIT |
A10_MMC_DATA_OVER | A10_MMC_AUTOCMD_DONE |
A10_MMC_RX_DATA_REQ | A10_MMC_TX_DATA_REQ);
+ uint32_t temp_val = A10_MMC_READ_4(sc, A10_MMC_GCTRL) | A10_MMC_INT_ENABLE | A10_MMC_ACCESS_BY_AHB ;
+ temp_val = temp_val & (~A10_MMC_DMA_ENABLE) ;
/* Enable interrupts and AHB access. */
- A10_MMC_WRITE_4(sc, A10_MMC_GCTRL,
- A10_MMC_READ_4(sc, A10_MMC_GCTRL) |
- A10_MMC_INT_ENABLE | A10_MMC_ACCESS_BY_AHB);
-
+ A10_MMC_WRITE_4(sc, A10_MMC_GCTRL,temp_val) ;
return (0);
}
@@ -256,7 +448,9 @@
sc->a10_req = NULL;
sc->a10_intr = 0;
sc->a10_resid = 0;
+ sc->a10_idst = 0 ;
sc->a10_intr_wait = 0;
+ sc->a10_dma_nsegs = 0 ;
req->done(req);
}
@@ -295,7 +489,7 @@
a10_mmc_req_done(sc);
}
-static void
+static void
a10_mmc_timeout(void *arg)
{
struct a10_mmc_softc *sc;
@@ -337,48 +531,80 @@
{
struct a10_mmc_softc *sc;
struct mmc_data *data;
- uint32_t imask, rint;
+ uint32_t imask, rint,idst;
sc = (struct a10_mmc_softc *)arg;
A10_MMC_LOCK(sc);
rint = A10_MMC_READ_4(sc, A10_MMC_RINTR);
imask = A10_MMC_READ_4(sc, A10_MMC_IMASK);
- if (imask == 0 && rint == 0) {
+ idst = A10_MMC_READ_4(sc, A10_MMC_IDST) ;
+
+ if (imask == 0 && rint == 0 && idst == 0 ) {
A10_MMC_UNLOCK(sc);
return;
}
-#ifdef DEBUG
- device_printf(sc->a10_dev, "imask: %#x, rint: %#x\n", imask, rint);
-#endif
+
+ A10_MMC_WRITE_4(sc, A10_MMC_RINTR, rint) ;
+ A10_MMC_WRITE_4(sc, A10_MMC_IDST, idst) ;
+ A10_MMC_WRITE_4(sc, A10_MMC_IMASK, imask) ;
+ //device_printf(sc->a10_dev, "imask: %#x, rint: %#x, idst: %#x, gctrl: %#x\n", imask, rint,idst, A10_MMC_READ_4(sc, A10_MMC_GCTRL));
if (sc->a10_req == NULL) {
device_printf(sc->a10_dev,
"Spurious interrupt - no active request, rint: 0x%08X\n",
rint);
- A10_MMC_WRITE_4(sc, A10_MMC_RINTR, rint);
A10_MMC_UNLOCK(sc);
return;
}
+
+ sc->a10_intr |= rint;
if (rint & A10_MMC_INT_ERR_BIT) {
device_printf(sc->a10_dev, "error rint: 0x%08X\n", rint);
- if (rint & A10_MMC_RESP_TIMEOUT)
+ if (rint & A10_MMC_RESP_TIMEOUT) {
sc->a10_req->cmd->error = MMC_ERR_TIMEOUT;
+ }
else
sc->a10_req->cmd->error = MMC_ERR_FAILED;
- A10_MMC_WRITE_4(sc, A10_MMC_RINTR, rint);
a10_mmc_req_done(sc);
A10_MMC_UNLOCK(sc);
return;
}
- sc->a10_intr |= rint;
+ if (idst & A10_MMC_IDMAC_ERROR) {
+ device_printf(sc->a10_dev, "error idst: 0x%08x\n", idst) ;
+ sc->a10_req->cmd->error = MMC_ERR_FAILED ;
+ a10_mmc_req_done(sc) ;
+ A10_MMC_UNLOCK(sc) ;
+ return ;
+ }
+
+ if ((idst & A10_MMC_IDMAC_COMPLETE) && ((sc->a10_intr & sc->a10_intr_wait) == sc->a10_intr_wait)) {
+ if (sc->a10_req->cmd->data->flags & MMC_DATA_WRITE)
+ bus_dmamap_sync(sc->a10_dma_buff_tag, sc->a10_dma_buff_map, BUS_DMASYNC_POSTWRITE) ;
+ else
+ bus_dmamap_sync(sc->a10_dma_buff_tag, sc->a10_dma_buff_map, BUS_DMASYNC_POSTREAD) ;
+ bus_dmamap_sync(sc->a10_dma_tag, sc->a10_dma_map, BUS_DMASYNC_POSTWRITE) ;
+ bus_dmamap_unload(sc->a10_dma_buff_tag, sc->a10_dma_buff_map) ;
+ a10_mmc_req_ok(sc) ;
+ A10_MMC_UNLOCK(sc) ;
+ return ;
+ }
+
+ if ((idst)&&(!(idst & A10_MMC_IDMAC_COMPLETE))) {
+ device_printf(sc->a10_dev, "DMA timeout error!\n") ;
+ sc->a10_req->cmd->error = MMC_ERR_TIMEOUT ;
+ a10_mmc_req_done(sc) ;
+ A10_MMC_UNLOCK(sc) ;
+ return ;
+ }
+
data = sc->a10_req->cmd->data;
+
if (data != NULL && (rint & (A10_MMC_DATA_OVER |
A10_MMC_RX_DATA_REQ | A10_MMC_TX_DATA_REQ)) != 0)
- a10_mmc_pio_transfer(sc, data);
+ a10_mmc_pio_transfer(sc, data);
if ((sc->a10_intr & sc->a10_intr_wait) == sc->a10_intr_wait)
a10_mmc_req_ok(sc);
- A10_MMC_WRITE_4(sc, A10_MMC_RINTR, rint);
A10_MMC_UNLOCK(sc);
}
@@ -388,7 +614,7 @@
int blksz;
struct a10_mmc_softc *sc;
struct mmc_command *cmd;
- uint32_t cmdreg;
+ uint32_t cmdreg ;
sc = device_get_softc(bus);
A10_MMC_LOCK(sc);
@@ -396,6 +622,7 @@
A10_MMC_UNLOCK(sc);
return (EBUSY);
}
+
sc->a10_req = req;
cmd = req->cmd;
cmdreg = A10_MMC_START;
@@ -410,8 +637,10 @@
sc->a10_intr = 0;
sc->a10_resid = 0;
+ sc->a10_idst = 0 ;
sc->a10_intr_wait = A10_MMC_CMD_DONE;
cmd->error = MMC_ERR_NONE;
+
if (cmd->data != NULL) {
sc->a10_intr_wait |= A10_MMC_DATA_OVER;
cmdreg |= A10_MMC_DATA_EXP | A10_MMC_WAIT_PREOVER;
@@ -419,11 +648,38 @@
cmdreg |= A10_MMC_SEND_AUTOSTOP;
sc->a10_intr_wait |= A10_MMC_AUTOCMD_DONE;
}
- if (cmd->data->flags & MMC_DATA_WRITE)
+ if (cmd->data->flags & MMC_DATA_WRITE) {
cmdreg |= A10_MMC_WRITE;
+ }
+
blksz = min(cmd->data->len, MMC_SECTOR_SIZE);
A10_MMC_WRITE_4(sc, A10_MMC_BLKSZ, blksz);
A10_MMC_WRITE_4(sc, A10_MMC_BCNTR, cmd->data->len);
+
+ if ((sc->a10_use_dma == 1)&&(a10_mmc_can_do_dma(req))) {
+ uint32_t error = a10_mmc_prepare_dma(sc) ;
+ if (error == 0) {
+ A10_MMC_WRITE_4(sc, A10_MMC_IMASK, A10_MMC_READ_4(sc, A10_MMC_IMASK) | (A10_MMC_TX_DATA_REQ | A10_MMC_RX_DATA_REQ)) ;
+ }
+ else {
+ uint32_t temp_val = A10_MMC_READ_4(sc, A10_MMC_GCTRL) | A10_MMC_INT_ENABLE | A10_MMC_ACCESS_BY_AHB ;
+ temp_val = temp_val & (~A10_MMC_DMA_ENABLE) ;
+ A10_MMC_WRITE_4(sc, A10_MMC_GCTRL, temp_val) ;
+ }
+ }
+ else
+ {
+ uint32_t temp_val = A10_MMC_READ_4(sc, A10_MMC_GCTRL) | A10_MMC_INT_ENABLE | A10_MMC_ACCESS_BY_AHB ;
+ temp_val = temp_val & (~A10_MMC_DMA_ENABLE) ;
+ A10_MMC_WRITE_4(sc, A10_MMC_GCTRL, temp_val) ;
+ }
+
+ }
+ else
+ {
+ uint32_t temp_val = A10_MMC_READ_4(sc, A10_MMC_GCTRL) | A10_MMC_INT_ENABLE | A10_MMC_ACCESS_BY_AHB ;
+ temp_val = temp_val & (~A10_MMC_DMA_ENABLE) ;
+ A10_MMC_WRITE_4(sc, A10_MMC_GCTRL, temp_val) ;
}
A10_MMC_WRITE_4(sc, A10_MMC_CARG, cmd->arg);
@@ -436,7 +692,7 @@
}
static int
-a10_mmc_read_ivar(device_t bus, device_t child, int which,
+a10_mmc_read_ivar(device_t bus, device_t child, int which,
uintptr_t *result)
{
struct a10_mmc_softc *sc;
More information about the svn-soc-all
mailing list