[prev in list] [next in list] [prev in thread] [next in thread] 

List:       openbsd-arm
Subject:    Re: miniroot-am335x-55.fs installing to BeagleBone Black: no sd1
From:       Sylvestre Gallon <ccna.syl () gmail ! com>
Date:       2014-11-03 9:49:07
Message-ID: 20141103094906.GA830 () gmail ! com
[Download RAW message or body]

On Sun, Nov 02, 2014 at 09:31:26PM +1100, Jonathan Gray wrote:
> On Mon, Oct 20, 2014 at 02:40:13AM -0400, Andrew Hills wrote:
> > On 10/19/14, 11:15 AM, Gerke M. Preussner wrote:
> > > I haven't had any time yet to look into this. Were you able to make any
> > > progress on your end?
> > 
> > I'm not sure I'd call it progress; I'm not familiar with the MMC
> > protocol, so I'm spending most of my time learning rather than debugging.
> > 
> > During the initialization, I see sys/dev/sdmmc roughly follow this order:
> > 
> > sdmmc_card_attach()
> > . sdmmc_enable()
> > .. sdmmc_mem_enable()
> > ... sdmmc_mem_send_op_cond() reads memory OCR
> > ... sdmmc_mem_send_op_cond() attempts to send memory OCR
> > .... sdmmc_mmc_command() doesn't fail, but doesn't succeed
> > (MMC_OCR_MEM_READY is not set)
> > .... command times out after 100 attempts (sdmmc_mem.c:519-538)
> > 
> > What I haven't been able to figure out is why the command doesn't have
> > the intended effect. Unfortunately, I enabled debug statements in
> > sys/arch/armv7/omap/ommmc.c without thinking, so the system is unusable
> > until I get the old bsd.umg back. Hopefully more to come soon.
> > 
> 
> I tracked the problem down, it seems u-boot only sets up CAPA for emmc.

ok syl@.

> 
> With the diff below I can access the sd card on my bbb rev C (sd0) in
> addition to the emmc (sd1).  Both are still quite slow though, with
> reads to the raw device around 780 KB/s on sd and 800 KB/s on emmc.
> 
> Besides DMA, it sounds like opting into a higher bus width
> (4 bit on sd, 8 bit on emmc) and clock speeds might help there?
> Then there is also the HSPE/High Speed Enable bit in HCTL.

If you want I already tried to do something for the DMA. The diff below
works 95% of the time, but the 5 other pourcent it broke your
filesystem... 

I think the problem has something to do with arm cache, perhaps in 
bus_dmamap_sync ? I've already shared this diff with rapha@ 
but we haven't find how to fix this. I broke my BBB few weeks ago
so I haven't test this diff with the fix for l1 pte...

If you want to try the dma code (at your own fs risk :)) you will 
need to remove my fist goto without_dma;

Cheers,


Index: am335x.c
===================================================================
RCS file: /cvs/src/sys/arch/armv7/omap/am335x.c,v
retrieving revision 1.4
diff -u -p -u -p -r1.4 am335x.c
--- am335x.c	18 Oct 2013 15:23:58 -0000	1.4
+++ am335x.c	22 Oct 2013 14:00:41 -0000
@@ -72,6 +72,10 @@
 #define EDMACOMP_IRQ	12
 #define EDMAMPERR_IRQ	13
 #define EDMAERR_IRQ	14
+#define SDQTXEVT1	2
+#define SDQRXEVT1	3
+#define SDQTXEVT0	24
+#define SDQRXEVT0	25
 
 #define UARTx_SIZE	0x90
 #define UART0_ADDR	0x44E09000
@@ -177,13 +181,15 @@ struct omap_dev am335x_devs[] = {
 	{ .name = "ommmc",
 	  .unit = 0,
 	  .mem = { { HSMMC0_ADDR, HSMMCx_SIZE } },
-	  .irq = { HSMMC0_IRQ }
+	  .irq = { HSMMC0_IRQ },
+	  .dma = { SDQRXEVT0, SDQTXEVT0 }
 	},
 
 	{ .name = "ommmc",
 	  .unit = 1,
 	  .mem = { { HSMMC1_ADDR, HSMMCx_SIZE } },
-	  .irq = { HSMMC1_IRQ }
+	  .irq = { HSMMC1_IRQ },
+	  .dma = { SDQRXEVT1, SDQTXEVT1 }
 	},
 
 	/* cpsw Ethernet */
Index: ommmc.c
===================================================================
RCS file: /cvs/src/sys/arch/armv7/omap/ommmc.c,v
retrieving revision 1.7
diff -u -p -u -p -r1.7 ommmc.c
--- ommmc.c	18 Oct 2013 15:23:58 -0000	1.7
+++ ommmc.c	22 Oct 2013 14:00:46 -0000
@@ -33,6 +33,7 @@
 
 #include <armv7/omap/omapvar.h>
 #include <armv7/omap/prcmvar.h>
+#include <armv7/omap/edmavar.h>
 
 /*
  * NOTE: on OMAP4430/AM335x these registers skew by 0x100
@@ -178,23 +179,35 @@
 #define SDHC_BUFFER_TIMEOUT	hz
 #define SDHC_TRANSFER_TIMEOUT	hz
 
+#define OMMMC_DMA_BUFSIZE	MAXPHYS
+#define OMMMC_DMA_SEGSIZE	OMMMC_DMA_BUFSIZE
+
 void ommmc_attach(struct device *parent, struct device *self, void *args);
 
 struct ommmc_softc {
 	struct device sc_dev;
 	bus_space_tag_t		sc_iot;
 	bus_space_handle_t	sc_ioh;
-	void			*sc_ih; /* Interrupt handler */
-	uint32_t		sc_flags;
+	void			*sc_ih;		/* Interrupt handler */
 
-	struct device *sdmmc;		/* generic SD/MMC device */
-	int clockbit;			/* clock control bit */
-	uint32_t clkbase;		/* base clock frequency in KHz */
-	int maxblklen;			/* maximum block length */
-	int flags;			/* flags for this host */
-	uint32_t ocr;			/* OCR value from capabilities */
-	uint32_t intr_status;		/* soft interrupt status */
-	uint32_t intr_error_status;	/*  */
+	/* DMA */
+	bus_dma_tag_t		sc_bdt;
+	bus_dmamap_t		sc_dmap;
+	uint32_t		sc_dma_tx_ch;
+	uint32_t		sc_dma_rx_ch;
+	uint32_t		sc_hwfifo_addr;
+	bus_dma_segment_t	sc_segs;
+	caddr_t			sc_datakvap;
+	int			sc_rsegs;
+
+	struct device		*sdmmc;		/* generic SD/MMC device */
+	int			clockbit;	/* clock control bit */
+	uint32_t		clkbase;	/* base clock frequency in KHz */
+	int			maxblklen;	/* maximum block length */
+	int			flags;		/* flags for this host */
+	uint32_t		ocr;		/* OCR value from capabilities */
+	uint32_t		intr_status;	/* soft interrupt status */
+	uint32_t		intr_error_status;	/*  */
 };
 
 
@@ -236,6 +249,8 @@ int	ommmc_wait_state(struct ommmc_softc 
 int	ommmc_soft_reset(struct ommmc_softc *, int);
 int	ommmc_wait_intr(struct ommmc_softc *, int, int);
 void	ommmc_transfer_data(struct ommmc_softc *, struct sdmmc_command *);
+int	ommmc_dma_xfer_init(struct ommmc_softc *, struct sdmmc_command *);
+int	ommmc_dma_xfer_finish(struct ommmc_softc *, struct sdmmc_command *);
 void	ommmc_read_data(struct ommmc_softc *, uint8_t *, int);
 void	ommmc_write_data(struct ommmc_softc *, uint8_t *, int);
 
@@ -274,15 +289,24 @@ struct cfattach ommmc_ca = {
 	sizeof(struct ommmc_softc), NULL, ommmc_attach
 };
 
+static void
+edma_it(void *sc)
+{
+	wakeup(sc);
+}
+
 void
 ommmc_attach(struct device *parent, struct device *self, void *args)
 {
 	struct ommmc_softc		*sc = (struct ommmc_softc *) self;
	struct armv7_attach_args	*aa = args;
 	struct sdmmcbus_attach_args	 saa;
 	uint32_t			 caps;
 
 	sc->sc_iot = aa->aa_iot;
+	sc->sc_bdt = aa->aa_dmat;
+	sc->sc_hwfifo_addr = aa->aa_dev->mem[0].addr + MMCHS_DATA;
+
 	if (bus_space_map(sc->sc_iot, aa->aa_dev->mem[0].addr,
 	    aa->aa_dev->mem[0].size, 0, &sc->sc_ioh))
 		panic("%s: bus_space_map failed!", __func__);
@@ -311,12 +334,26 @@ ommmc_attach(struct device *parent, stru
 	/* Determine host capabilities. */
 	caps = HREAD4(sc, MMCHS_CAPA);
 
-#if 0
-	/* we want this !! */
-	/* Use DMA if the host system and the controller support it. */
-	if (usedma && ISSET(caps, SDHC_DMA_SUPPORT))
+	if (ISSET(caps, MMCHS_CAPA_DS)) {
+		goto without_dma;
+		if (board_id != BOARD_ID_AM335X_BEAGLEBONE)
+			goto without_dma;
+
+		/* Get DMA channels */
+		sc->sc_dma_rx_ch = aa->aa_dev->dma[0];
+		sc->sc_dma_tx_ch = aa->aa_dev->dma[1];
+
+		if (edma_intr_dma_en(sc->sc_dma_rx_ch, edma_it, sc) ||
+		    edma_intr_dma_en(sc->sc_dma_tx_ch, edma_it, sc))
+			goto without_dma;
+
+		if (bus_dmamap_create(sc->sc_bdt, OMMMC_DMA_BUFSIZE, 1,
+		    OMMMC_DMA_SEGSIZE, 0 , BUS_DMA_WAITOK, &sc->sc_dmap) != 0)
+			goto without_dma;
+
 		SET(sc->flags, SHF_USE_DMA);
-#endif
+	}
+without_dma:
 
 	/*
 	 * Determine the base clock frequency. (2.2.24)
@@ -798,8 +837,13 @@ ommmc_exec_command(sdmmc_chipset_handle_
 	 * If the command has data to transfer in any direction,
 	 * execute the transfer now.
 	 */
-	if (cmd->c_error == 0 && cmd->c_data != NULL)
-		ommmc_transfer_data(sc, cmd);
+
+	if (cmd->c_error == 0 && cmd->c_data != NULL) {
+		if (!ISSET(sc->flags, SHF_USE_DMA))
+			ommmc_transfer_data(sc, cmd);
+		else
+			ommmc_dma_xfer_finish(sc, cmd);
+	}
 
 #if 0
 	/* Turn off the LED. */
@@ -860,16 +904,15 @@ ommmc_start_command(struct ommmc_softc *
 			command |= MMCHS_CMD_ACEN;
 		}
 	}
-#ifdef notyet
+
 	if (ISSET(sc->flags, SHF_USE_DMA))
 		command |= MMCHS_CMD_DE;
-#endif
 
 	/*
 	 * Prepare command register value. (2.2.6)
 	 */
 	command |= (cmd->c_opcode << MMCHS_CMD_INDX_SHIFT) &
-	   MMCHS_CMD_INDX_SHIFT_MASK;
+	    MMCHS_CMD_INDX_SHIFT_MASK;
 
 	if (ISSET(cmd->c_flags, SCF_RSP_CRC))
 		command |= MMCHS_CMD_CCCE;
@@ -890,6 +933,9 @@ ommmc_start_command(struct ommmc_softc *
 	/* Wait until command and data inhibit bits are clear. (1.5) */
 	if ((error = ommmc_wait_state(sc, MMCHS_PSTATE_CMDI, 0)) != 0)
 		return (error);
+	/* Wait until command and data inhibit bits are clear. (1.5) */
+	if ((error = ommmc_wait_state(sc, MMCHS_PSTATE_DATI, 0)) != 0)
+		return (error);
 
 	s = splsdmmc();
 
@@ -898,11 +944,15 @@ ommmc_start_command(struct ommmc_softc *
 	HSET1(sc, SDHC_HOST_CTL, SDHC_LED_ON);
 #endif
 
-	/* XXX: Set DMA start address if SHF_USE_DMA is set. */
-
 	DPRINTF(1,("%s: cmd=%#x blksize=%d blkcount=%d\n",
 	    DEVNAME(sc), command, blksize, blkcount));
 
+	if (cmd->c_datalen > 0 && ISSET(sc->flags, SHF_USE_DMA)) {
+		error = ommmc_dma_xfer_init(sc, cmd);
+		if (error)
+			return (error);
+	}
+
 	/*
 	 * Start a CPU data transfer.  Writing to the high order byte
 	 * of the SDHC_COMMAND register triggers the SD command. (1.5)
@@ -914,6 +964,141 @@ ommmc_start_command(struct ommmc_softc *
 
 	splx(s);
 	return (0);
+}
+
+int
+ommmc_dma_xfer_init(struct ommmc_softc *sc, struct sdmmc_command *cmd)
+{
+	struct edma_param params;
+	uint32_t blksize = 0;
+	uint32_t blkcount = 0;
+	int error;
+	uint32_t ch;
+	int read;
+
+	blksize = MIN(cmd->c_datalen, cmd->c_blklen);
+	blkcount = cmd->c_datalen / blksize;
+	read = ISSET(cmd->c_flags, SCF_CMD_READ);
+
+
+	/* Allocate and map DMA memory for data xfer */
+	error = bus_dmamem_alloc(sc->sc_bdt, cmd->c_datalen, 0, 0,
+	    &sc->sc_segs, 1, &sc->sc_rsegs, BUS_DMA_WAITOK | BUS_DMA_ZERO);
+	if (error) {
+		printf("%s: could not allocate %d bytes\n",
+		    DEVNAME(sc), cmd->c_datalen);
+		    goto ret;
+	}
+
+	error = bus_dmamem_map(sc->sc_bdt, &sc->sc_segs, sc->sc_rsegs,
+	    cmd->c_datalen, &sc->sc_datakvap, BUS_DMA_WAITOK |
+	    BUS_DMA_COHERENT);
+	if (error) {
+		printf("%s: could not map data buffer\n", DEVNAME(sc));
+		goto free_databuf;
+	}
+
+	/* If it is a write, copy data from sdmmmc-provided buffer. */
+	if (!read)
+		memcpy(sc->sc_datakvap, cmd->c_data, cmd->c_datalen);
+
+	/* Load the data buffer and sync it */
+	error = bus_dmamap_load(sc->sc_bdt, sc->sc_dmap, sc->sc_datakvap,
+	    cmd->c_datalen, NULL, ((read) ? BUS_DMA_READ : BUS_DMA_WRITE)
+	    | BUS_DMA_WAITOK);
+	if (error) {
+		printf("%s: could not load DMA map\n", DEVNAME(sc));
+		goto unmap_databuf;
+	}
+
+	bus_dmamap_sync(sc->sc_bdt, sc->sc_dmap, 0, cmd->c_datalen,
+	    BUS_DMASYNC_PREREAD);
+	bus_dmamap_sync(sc->sc_bdt, sc->sc_dmap, 0, cmd->c_datalen,
+	    BUS_DMASYNC_PREWRITE);
+
+	/* set edma params and enable dma xfer trigged by device */
+	bzero(&params, sizeof(params));
+	if (read) {
+		ch = sc->sc_dma_rx_ch;
+		params.src = sc->sc_hwfifo_addr;
+		params.dst = sc->sc_dmap->dm_segs[0].ds_addr;
+		params.dstbidx = 64;
+		params.dstcidx = blksize;
+		params.opt = 1; /* enable sam */
+	} else {
+		ch = sc->sc_dma_tx_ch;
+		params.src = sc->sc_dmap->dm_segs[0].ds_addr;
+		params.dst = sc->sc_hwfifo_addr;
+		params.srcbidx = 64;
+		params.srccidx = blksize;
+		params.opt = (1 << 1); /* enable dam */
+	}
+	params.acnt = 64;
+	params.bcnt = blksize / 64;
+	params.ccnt = blkcount;
+	params.link = 0xffff;
+	params.opt |= (1<<20) | (ch << 12) | (2 << 8) | (1 << 2);
+
+	edma_param_write(ch, &params);
+	edma_trig_xfer_by_dev(ch);
+
+	return (0);
+
+unmap_databuf:
+	bus_dmamem_unmap(sc->sc_bdt, sc->sc_datakvap, cmd->c_datalen);
+free_databuf:
+	bus_dmamem_free(sc->sc_bdt, &sc->sc_segs, sc->sc_rsegs);
+ret:
+	printf("%s: xfer error=%d\n", DEVNAME(sc), error);
+
+	return (error);
+}
+
+int
+ommmc_dma_xfer_finish(struct ommmc_softc *sc, struct sdmmc_command *cmd)
+{
+	int error = 0;
+	int read;
+
+	read = ISSET(cmd->c_flags, SCF_CMD_READ);
+
+	/* wait for completion */
+	if (!ommmc_wait_intr(sc, MMCHS_STAT_TC, SDHC_TRANSFER_TIMEOUT))
+		error = ETIMEDOUT;
+	/* Wait until command and data inhibit bits are clear. (1.5) */
+	if (!error)
+		error = ommmc_wait_state(sc, MMCHS_PSTATE_DATI, 0);
+
+	if (error != 0)
+		cmd->c_error = error;
+	SET(cmd->c_flags, SCF_ITSDONE);
+
+	DPRINTF(1,("%s: data transfer done (error=%d)\n", DEVNAME(sc),
+	    cmd->c_error));
+
+	if (error)
+		goto unload_databuf;
+
+	bus_dmamap_sync(sc->sc_bdt, sc->sc_dmap, 0, cmd->c_datalen,
+	    BUS_DMASYNC_POSTREAD);
+	bus_dmamap_sync(sc->sc_bdt, sc->sc_dmap, 0, cmd->c_datalen,
+	    BUS_DMASYNC_POSTWRITE);
+
+unload_databuf:
+	bus_dmamap_unload(sc->sc_bdt, sc->sc_dmap);
+
+	/* If this is a read, copy data into sdmmc-provided buffer. */
+	if (error == 0 && read)
+		memcpy(cmd->c_data, sc->sc_datakvap, cmd->c_datalen);
+
+	/* Free DMA data buffer */
+
+	bus_dmamem_unmap(sc->sc_bdt, sc->sc_datakvap, cmd->c_datalen);
+	bus_dmamem_free(sc->sc_bdt, &sc->sc_segs, sc->sc_rsegs);
+
+	if (error)
+		printf("%s: xfer done, error=%d\n", DEVNAME(sc), error);
+	return (error);
 }
 
 void

[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic