From owner-svn-soc-all@FreeBSD.ORG Sun Jun 21 07:48:01 2015 Return-Path: Delivered-To: svn-soc-all@hub.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [8.8.178.115]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTPS id E9099F73 for ; Sun, 21 Jun 2015 07:48:01 +0000 (UTC) (envelope-from pratiksinghal@FreeBSD.org) Received: from socsvn.freebsd.org (socsvn.freebsd.org [IPv6:2001:1900:2254:206a::50:2]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id D55723BF for ; Sun, 21 Jun 2015 07:48:01 +0000 (UTC) (envelope-from pratiksinghal@FreeBSD.org) Received: from socsvn.freebsd.org ([127.0.1.124]) by socsvn.freebsd.org (8.14.9/8.14.9) with ESMTP id t5L7m1nv047285 for ; Sun, 21 Jun 2015 07:48:01 GMT (envelope-from pratiksinghal@FreeBSD.org) Received: (from www@localhost) by socsvn.freebsd.org (8.14.9/8.14.9/Submit) id t5L7m1VS047282 for svn-soc-all@FreeBSD.org; Sun, 21 Jun 2015 07:48:01 GMT (envelope-from pratiksinghal@FreeBSD.org) Date: Sun, 21 Jun 2015 07:48:01 GMT Message-Id: <201506210748.t5L7m1VS047282@socsvn.freebsd.org> X-Authentication-Warning: socsvn.freebsd.org: www set sender to pratiksinghal@FreeBSD.org using -f From: pratiksinghal@FreeBSD.org To: svn-soc-all@FreeBSD.org Subject: socsvn commit: r287418 - soc2015/pratiksinghal/cubie-head/sys/arm/allwinner MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-soc-all@freebsd.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: SVN commit messages for the entire Summer of Code repository List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 21 Jun 2015 07:48:02 -0000 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 #include #include +#include #include @@ -48,12 +49,21 @@ #include #include + #include #include #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; ia10_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;