socsvn commit: r272615 - in soc2014/astarasikov/head/sys: arm/conf arm/goldfish boot/fdt/dts/arm dev/mmc

astarasikov at FreeBSD.org astarasikov at FreeBSD.org
Mon Aug 18 15:43:02 UTC 2014


Author: astarasikov
Date: Mon Aug 18 15:42:59 2014
New Revision: 272615
URL: http://svnweb.FreeBSD.org/socsvn/?view=rev&rev=272615

Log:
  goldfish: working MMC and timer drivers, boots rootfs
  

Modified:
  soc2014/astarasikov/head/sys/arm/conf/GOLDFISH
  soc2014/astarasikov/head/sys/arm/goldfish/goldfish_mmc.c
  soc2014/astarasikov/head/sys/arm/goldfish/goldfish_pdev.c
  soc2014/astarasikov/head/sys/arm/goldfish/goldfish_timer.c
  soc2014/astarasikov/head/sys/boot/fdt/dts/arm/goldfish.dts
  soc2014/astarasikov/head/sys/dev/mmc/mmc.c

Modified: soc2014/astarasikov/head/sys/arm/conf/GOLDFISH
==============================================================================
--- soc2014/astarasikov/head/sys/arm/conf/GOLDFISH	Mon Aug 18 14:47:13 2014	(r272614)
+++ soc2014/astarasikov/head/sys/arm/conf/GOLDFISH	Mon Aug 18 15:42:59 2014	(r272615)
@@ -41,7 +41,6 @@
 makeoptions 	DEBUG=-g		#Build kernel with gdb(1) debug symbols
 options 	HZ=100
 
-options 	SCSI_DELAY=5000		# Delay (in ms) before probing SCSI
 options 	SCHED_4BSD		#4BSD scheduler
 options 	INET			#InterNETworking
 options 	TMPFS			# Efficient memory filesystem
@@ -50,9 +49,12 @@
 options 	UFS_ACL			#Support for access control lists
 options 	UFS_DIRHASH		#Improve performance on big directories
 
+options 	PSEUDOFS		#Pseudo-filesystem framework
+options 	MSDOSFS			#MSDOS Filesystem
+options 	CD9660			#ISO 9660 Filesystem
+options 	PROCFS			#Process filesystem (requires PSEUDOFS)
 options 	GEOM_PART_BSD		# BSD partition scheme
 options 	GEOM_PART_MBR		# MBR partition scheme
-options 	PSEUDOFS		#Pseudo-filesystem framework
 options 	COMPAT_43		#Compatible with BSD 4.3 [KEEP THIS!]
 options 	KTRACE			#ktrace(1) support
 options 	SYSVSHM			#SYSV-style shared memory
@@ -69,8 +71,7 @@
 device 	snp
 
 # NAND for rootfs
-device 	nand
-options 	NANDFS			# NAND file system
+# device 	nand
 
 # Ethernet
 device 	ether
@@ -109,29 +110,22 @@
 #options 	WITNESS
 #options 	WITNESS_SKIPSPIN
 
-device 	md
-device 	random		# Entropy device
+#options 	KTR
+#options 	KTR_VERBOSE=2
+#options 	KTR_ENTRIES=16384
+#options 	KTR_MASK=(KTR_SPARE2)
+#options 	KTR_COMPILE=KTR_ALL
 
-device mmc
-device mmcsd
-options ROOTDEVNAME=\"ufs:/dev/mmcsd0s1a\"
+device 	random		# Entropy device
 
 # Flattened Device Tree
 options 	FDT
 options 	FDT_DTB_STATIC
 makeoptions 	FDT_DTS_FILE=goldfish.dts
 
-#options 	MD_ROOT
-#options 	MD_ROOT_SIZE=5120
-#makeoptions 	MFS_IMAGE=/root/handhelds/myroot.img
-#options 	ROOTDEVNAME=\"/dev/md0\"
-
-#boot from NFS
-#options 	NFSCL
-#options 	NFSCLIENT
-#options 	NFS_ROOT
-#options 	BOOTP_COMPAT
-#options 	BOOTP
-#options 	BOOTP_NFSV3
-#options 	BOOTP_WIRED_TO=smc0
-#options 	ROOTDEVNAME=\"nfs:192.168.1.51:/srv/nfs3/bsd/\"
+device mmc
+device mmcsd
+device sdhci
+options ROOTDEVNAME=\"ufs:/dev/mmcsd0s2a\"
+
+device 	md

Modified: soc2014/astarasikov/head/sys/arm/goldfish/goldfish_mmc.c
==============================================================================
--- soc2014/astarasikov/head/sys/arm/goldfish/goldfish_mmc.c	Mon Aug 18 14:47:13 2014	(r272614)
+++ soc2014/astarasikov/head/sys/arm/goldfish/goldfish_mmc.c	Mon Aug 18 15:42:59 2014	(r272615)
@@ -1,6 +1,4 @@
-/*-
- * Copyright (c) 2014 Alexander Tarasikov <alexander.tarasikov at gmail.com>
- * All rights reserved.
+/*
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -24,111 +22,819 @@
  * SUCH DAMAGE.
  *
  */
-
 #include <sys/cdefs.h>
 __FBSDID("$FreeBSD$");
 
 #include <sys/param.h>
 #include <sys/systm.h>
+#include <sys/bio.h>
 #include <sys/bus.h>
+#include <sys/conf.h>
+#include <sys/endian.h>
 #include <sys/kernel.h>
-#include <sys/module.h>
+#include <sys/kthread.h>
+#include <sys/lock.h>
 #include <sys/malloc.h>
+#include <sys/module.h>
+#include <sys/mutex.h>
+#include <sys/queue.h>
+#include <sys/resource.h>
 #include <sys/rman.h>
+#include <sys/time.h>
 #include <sys/timetc.h>
+#include <sys/watchdog.h>
+
+#include <sys/kdb.h>
+
 #include <machine/bus.h>
+#include <machine/cpu.h>
+#include <machine/cpufunc.h>
+#include <machine/resource.h>
 #include <machine/intr.h>
 
-#include <dev/fdt/fdt_common.h>
-#include <dev/ofw/openfirm.h>
-
 #include <dev/ofw/ofw_bus.h>
 #include <dev/ofw/ofw_bus_subr.h>
 
+#include <dev/mmc/bridge.h>
+#include <dev/mmc/mmcreg.h>
+#include <dev/mmc/mmcbrvar.h>
+
+/* TODO: DMA support instead of memcpy */
+
+enum {
+	/* status register */
+	GOLDFISH_MMC_INT_STATUS	        = 0x00, 
+	/* set this to enable IRQ */
+	GOLDFISH_MMC_INT_ENABLE	        = 0x04,
+	/* set this to specify buffer address */
+	GOLDFISH_MMC_SET_BUFFER          = 0x08,
+	
+	/* MMC command number */
+	GOLDFISH_MMC_CMD	                = 0x0C,	
+
+	/* MMC argument */
+	GOLDFISH_MMC_ARG	                = 0x10,
+	
+	/* MMC response (or R2 bits 0 - 31) */
+	GOLDFISH_MMC_RESP_0		        = 0x14,
+
+	/* MMC R2 response bits 32 - 63 */
+	GOLDFISH_MMC_RESP_1		        = 0x18,
+
+	/* MMC R2 response bits 64 - 95 */
+	GOLDFISH_MMC_RESP_2		        = 0x1C,
+
+	/* MMC R2 response bits 96 - 127 */
+	GOLDFISH_MMC_RESP_3		        = 0x20,
+
+	GOLDFISH_MMC_BLOCK_LENGTH        = 0x24,
+	GOLDFISH_MMC_BLOCK_COUNT         = 0x28,
+
+	/* MMC state flags */
+	GOLDFISH_MMC_STATE               = 0x2C,
+
+	/* MMC_INT_STATUS bits */
+	
+	GOLDFISH_MMC_STAT_END_OF_CMD     = 1U << 0,
+	GOLDFISH_MMC_STAT_END_OF_DATA    = 1U << 1,
+	GOLDFISH_MMC_STAT_STATE_CHANGE   = 1U << 2,
+
+	/* MMC_STATE bits */
+	GOLDFISH_MMC_STATE_INSERTED     = 1U << 0,
+	GOLDFISH_MMC_STATE_READ_ONLY    = 1U << 1,
+};
+
+/* looks like goldfish mmc is modeled after OMAP */
+
+#define OMAP_MMC_CMDTYPE_BC	0
+#define OMAP_MMC_CMDTYPE_BCR	1
+#define OMAP_MMC_CMDTYPE_AC	2
+#define OMAP_MMC_CMDTYPE_ADTC	3
+
+
+#define	GOLDFISH_MMC_BLOCK_SIZE	2048
+
+#if 0
+#ifndef DEBUG
+#define DEBUG
+#endif
+
+#ifdef DEBUG
+#define debugf(fmt, args...) do { printf("%s(): ", __func__);   \
+    printf(fmt,##args); } while (0)
+#else
+#define debugf(fmt, args...)
+#endif
+#else
+#define debugf(fmt, args...)
+#endif
+
+struct goldfish_mmc_dmamap_arg {
+	bus_addr_t		gf_dma_busaddr;
+};
+
 struct goldfish_mmc_softc {
-	struct resource *	li_res;
-	bus_space_tag_t		li_bst;
-	bus_space_handle_t	li_bsh;
-	struct resource*	irq_res;
-	void*			intr_hl;
+	device_t		gf_dev;
+	struct mtx		gf_mtx;
+	struct resource *	gf_mem_res;
+	struct resource *	gf_irq_res;
+	bus_space_tag_t		gf_bst;
+	bus_space_handle_t	gf_bsh;
+	void *			gf_intrhand;
+	struct mmc_host		gf_host;
+	struct mmc_request *	gf_req;
+	struct mmc_data *	gf_data;
+	uint32_t		gf_flags;
+	int			gf_xfer_direction;
+#define	DIRECTION_READ		0
+#define	DIRECTION_WRITE		1
+	int			gf_xfer_done;
+	int			gf_bus_busy;
+	bus_dma_tag_t		gf_dma_tag;
+	bus_dmamap_t		gf_dma_map;
+	bus_addr_t		gf_buffer_phys;
+	void *			gf_buffer;
 };
 
 static int goldfish_mmc_probe(device_t);
 static int goldfish_mmc_attach(device_t);
+static int goldfish_mmc_detach(device_t);
+static void goldfish_mmc_intr(void *);
 
-static struct goldfish_mmc_softc *mmc_softc = NULL;
+const char *
+goldfish_fake_ofw_bus_compat (device_t bus, device_t dev);
 
-#define	mmc_read_4(reg)		\
-    bus_space_read_4(mmc_softc->li_bst, mmc_softc->li_bsh, reg)
-#define	mmc_write_4(reg, val)		\
-    bus_space_write_4(mmc_softc->li_bst, mmc_softc->li_bsh, reg, val)
+static void goldfish_mmc_cmd(struct goldfish_mmc_softc *, struct mmc_command *);
+static void goldfish_mmc_setup_xfer(struct goldfish_mmc_softc *, struct mmc_data *);
+static void goldfish_mmc_xfer_done(struct goldfish_mmc_softc *sc);
+
+static int goldfish_mmc_update_ios(device_t, device_t);
+static int goldfish_mmc_request(device_t, device_t, struct mmc_request *);
+static int goldfish_mmc_get_ro(device_t, device_t);
+static int goldfish_mmc_acquire_host(device_t, device_t);
+static int goldfish_mmc_release_host(device_t, device_t);
+
+#if 0
+static void goldfish_mmc_dma_rxfinish(void *);
+static void goldfish_mmc_dma_rxerror(void *);
+static void goldfish_mmc_dma_txfinish(void *);
+static void goldfish_mmc_dma_txerror(void *);
+#endif
+
+static void goldfish_mmc_dmamap_cb(void *, bus_dma_segment_t *, int, int);
+
+#define	goldfish_mmc_lock(_sc)						\
+    mtx_lock(&_sc->gf_mtx);
+#define	goldfish_mmc_unlock(_sc)						\
+    mtx_unlock(&_sc->gf_mtx);
+#define	goldfish_mmc_read_4(_sc, _reg)					\
+    bus_space_read_4(_sc->gf_bst, _sc->gf_bsh, _reg)
+#define	goldfish_mmc_write_4(_sc, _reg, _value)				\
+    bus_space_write_4(_sc->gf_bst, _sc->gf_bsh, _reg, _value)
 
 static int
 goldfish_mmc_probe(device_t dev)
 {
 
-	if (1 || !ofw_bus_is_compatible(dev, "arm,goldfish-mmc"))
+	#if 0
+	if (!ofw_bus_status_okay(dev))
 		return (ENXIO);
+	#endif
 
-	device_set_desc(dev, "Goldfish MMC");
+	if (!ofw_bus_is_compatible(dev, "arm,goldfish-mmc"))
+		return (ENXIO);
+
+	device_set_desc(dev, "Goldfish MMC controller");
 	return (BUS_PROBE_DEFAULT);
 }
 
 static int
+goldfish_mmc_attach(device_t dev)
+{
+	struct goldfish_mmc_softc *sc = device_get_softc(dev);
+	struct goldfish_mmc_dmamap_arg ctx;
+	device_t child;
+	int rid, err;
+
+	sc->gf_dev = dev;
+	sc->gf_req = NULL;
+
+	mtx_init(&sc->gf_mtx, "goldfish_mmc", "mmc", MTX_DEF);
+
+	rid = 0;
+	sc->gf_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
+	    RF_ACTIVE);
+	if (!sc->gf_mem_res) {
+		device_printf(dev, "cannot allocate memory window\n");
+		return (ENXIO);
+	}
+
+	sc->gf_bst = rman_get_bustag(sc->gf_mem_res);
+	sc->gf_bsh = rman_get_bushandle(sc->gf_mem_res);
+
+	rid = 0;
+	sc->gf_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
+	    RF_ACTIVE);
+	if (!sc->gf_irq_res) {
+		device_printf(dev, "cannot allocate interrupt\n");
+		bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->gf_mem_res);
+		return (ENXIO);
+	}
+
+	if (bus_setup_intr(dev, sc->gf_irq_res, INTR_TYPE_MISC | INTR_MPSAFE,
+	    NULL, goldfish_mmc_intr, sc, &sc->gf_intrhand))
+	{
+		bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->gf_mem_res);
+		bus_release_resource(dev, SYS_RES_IRQ, 0, sc->gf_irq_res);
+		device_printf(dev, "cannot setup interrupt handler\n");
+		return (ENXIO);
+	}
+
+	sc->gf_host.f_min = 400000;
+	sc->gf_host.f_max = 24000000;
+	sc->gf_host.host_ocr = MMC_OCR_320_330 | MMC_OCR_330_340;
+	sc->gf_host.caps = MMC_CAP_4_BIT_DATA;
+
+	/* Alloc DMA memory */
+	err = bus_dma_tag_create(
+	    bus_get_dma_tag(sc->gf_dev),
+	    4, 0,			/* alignment, boundary */
+	    BUS_SPACE_MAXADDR_32BIT,	/* lowaddr */
+	    BUS_SPACE_MAXADDR,		/* highaddr */
+	    NULL, NULL,			/* filter, filterarg */
+	    GOLDFISH_MMC_BLOCK_SIZE, 1,	/* maxsize, nsegments */
+	    GOLDFISH_MMC_BLOCK_SIZE, 0,	/* maxsegsize, flags */
+	    NULL, NULL,			/* lockfunc, lockarg */
+	    &sc->gf_dma_tag);
+
+	err = bus_dmamem_alloc(sc->gf_dma_tag, (void **)&sc->gf_buffer,
+	    0, &sc->gf_dma_map);
+	if (err) {
+		device_printf(dev, "cannot allocate framebuffer\n");
+		goto fail;
+	}
+
+	err = bus_dmamap_load(sc->gf_dma_tag, sc->gf_dma_map, sc->gf_buffer,
+	    GOLDFISH_MMC_BLOCK_SIZE, goldfish_mmc_dmamap_cb, &ctx, BUS_DMA_NOWAIT);
+	if (err) {
+		device_printf(dev, "cannot load DMA map\n");
+		goto fail;
+	}
+
+	sc->gf_buffer_phys = ctx.gf_dma_busaddr;
+	
+	child = device_add_child(dev, "mmc", -1);
+	if (!child) {
+		debugf("attaching MMC bus failed!\n");
+		bus_teardown_intr(dev, sc->gf_irq_res, sc->gf_intrhand);
+		bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->gf_mem_res);
+		bus_release_resource(dev, SYS_RES_IRQ, 0, sc->gf_irq_res);
+		return (ENXIO);
+	}
+	
+	device_set_ivars(dev, &sc->gf_host);
+
+	if (bus_generic_probe(dev)) {
+		goto fail;
+	}
+	
+	if (bus_generic_attach(dev)) {
+		goto fail;
+	}
+	
+	goldfish_mmc_write_4(sc, GOLDFISH_MMC_SET_BUFFER,
+		sc->gf_buffer_phys);
+	goldfish_mmc_write_4(sc, GOLDFISH_MMC_INT_ENABLE,
+		GOLDFISH_MMC_STAT_END_OF_CMD
+		| GOLDFISH_MMC_STAT_END_OF_DATA
+		| GOLDFISH_MMC_STAT_STATE_CHANGE);
+
+	return (0);
+
+fail:
+	if (sc->gf_intrhand)
+		bus_teardown_intr(dev, sc->gf_irq_res, sc->gf_intrhand);
+	if (sc->gf_irq_res)
+		bus_release_resource(dev, SYS_RES_IRQ, 0, sc->gf_irq_res);
+	if (sc->gf_mem_res)
+		bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->gf_mem_res);
+	return (err);
+}
+
+static int
+goldfish_mmc_detach(device_t dev)
+{
+	return (EBUSY);
+}
+
+static void
+goldfish_mmc_cmd_done(struct goldfish_mmc_softc *sc)
+{
+	struct mmc_command *cmd;
+
+	if (!sc || !sc->gf_req || !sc->gf_req->cmd) {
+		debugf("%s: CMD is NULL\n", __func__);
+		return;
+	}
+	
+	cmd = sc->gf_req->cmd;
+	
+	if (cmd->flags & MMC_RSP_136) {
+		cmd->resp[3] = goldfish_mmc_read_4(sc, GOLDFISH_MMC_RESP_0);
+		cmd->resp[2] = goldfish_mmc_read_4(sc, GOLDFISH_MMC_RESP_1);
+		cmd->resp[1] = goldfish_mmc_read_4(sc, GOLDFISH_MMC_RESP_2);
+		cmd->resp[0] = goldfish_mmc_read_4(sc, GOLDFISH_MMC_RESP_3);
+	}
+	else {
+		cmd->resp[0] = goldfish_mmc_read_4(sc, GOLDFISH_MMC_RESP_0);
+	}
+
+	debugf("%s: resp=[%08x %08x %08x %08x]\n",
+		__func__,
+		cmd->resp[0], cmd->resp[1], cmd->resp[2],
+		cmd->resp[3]);
+
+	cmd->error = MMC_ERR_NONE;
+
+	if (cmd->data){
+		goldfish_mmc_setup_xfer(sc, cmd->data);
+		goldfish_mmc_xfer_done(sc);
+	}
+
+	if (sc->gf_req) {	
+		sc->gf_req->done(sc->gf_req);
+		sc->gf_req = NULL;
+	}
+}
+
+static void
+goldfish_mmc_end_of_data(struct goldfish_mmc_softc *sc)
+{
+	if (!sc) {
+		debugf("%s: sc is NULL\n", __func__);
+	}
+	goldfish_mmc_xfer_done(sc);
+	if (sc->gf_req) {
+		sc->gf_req->cmd->error = MMC_ERR_NONE;
+		sc->gf_req->done(sc->gf_req);
+		sc->gf_req = NULL;
+	}
+}
+
+static void
 goldfish_mmc_intr(void *arg)
 {
-	printf("%s: irq\n", __func__);
-	return (FILTER_HANDLED);
+	struct goldfish_mmc_softc *sc = (struct goldfish_mmc_softc *)arg;
+	uint32_t status;
+	int end_command = 0, end_transfer = 0, state_changed = 0;
+
+	goldfish_mmc_lock(sc);
+	
+	while ((status = goldfish_mmc_read_4(sc, GOLDFISH_MMC_INT_STATUS)) != 0)
+	{
+		debugf("interrupt: 0x%08x\n", status);
+		goldfish_mmc_write_4(sc, GOLDFISH_MMC_INT_STATUS, status);
+
+		if (status & GOLDFISH_MMC_STAT_END_OF_CMD) {
+			end_command = 1;
+		}
+		if (status & GOLDFISH_MMC_STAT_END_OF_DATA) {
+			end_transfer = 1;
+		}
+		if (status & GOLDFISH_MMC_STAT_STATE_CHANGE) {
+			state_changed = 1;
+		}
+	}
+
+	if (end_command) {
+		goldfish_mmc_cmd_done(sc);
+	}
+	
+	if (end_transfer) {
+		goldfish_mmc_end_of_data(sc);
+	}
+
+	if (state_changed)
+	{
+		debugf("%s: state changed\n", __func__);
+	}
+
+	goldfish_mmc_unlock(sc);
+
+	debugf("done\n");
 }
 
 static int
-goldfish_mmc_attach(device_t dev)
+goldfish_mmc_request(device_t bus, device_t child, struct mmc_request *req)
 {
-	struct goldfish_mmc_softc *sc = device_get_softc(dev);
-	int li_rid = 0, irq_rid = 0;
+	struct goldfish_mmc_softc *sc = device_get_softc(bus);
+
+	if (!sc) {
+		debugf("%s: sc is NULL\n", __func__);
+		return (EBUSY);
+	}
+
+	if (!req || !req->cmd) {
+		debugf("%s: REQ is NULL\n", __func__);
+	}
+
+	goldfish_mmc_lock(sc);
+	if (sc->gf_req) {
+		debugf("%s: BUSY\n", __func__);
+		return (EBUSY);
+	}
+
+	sc->gf_req = req;
+
+	if (req->cmd->data) {
+		goldfish_mmc_setup_xfer(sc, req->cmd->data);
+		goldfish_mmc_xfer_done(sc);
+	}
+
+	goldfish_mmc_cmd(sc, req->cmd);
+	goldfish_mmc_unlock(sc);
+
+	return (0);
+}
+
+static void
+goldfish_mmc_cmd(struct goldfish_mmc_softc *sc, struct mmc_command *cmd)
+{
+	uint32_t cmdreg = 0;
+	uint32_t cmdtype = 0;
+
+	if (!sc || !cmd) {
+		debugf("%s: CMD is NULL\n", __func__);
+		return;
+	}
 	
-	if (mmc_softc)
-		return (ENXIO);
+	if ((cmd->opcode == 6) && (cmd->arg == 0xffffff)) {
+		//Android Emulator is using 0xfffff1 constant
+		//as a magic value to return the response
+		cmd->arg = 0xfffff1;
+	}
+
+	debugf("cmd: %d arg: 0x%08x\n", cmd->opcode, cmd->arg);
+
+	uint32_t resptype = 0;
+	if (cmd->flags & MMC_RSP_PRESENT) {
+		switch (MMC_RSP(cmd->flags)) {
+		case MMC_RSP_R1:
+		case MMC_RSP_R1B:
+
+		case MMC_RSP_R6:
+			resptype = 1;
+			break;
+		case MMC_RSP_R2:
+			resptype = 2;
+			break;
+		case MMC_RSP_R3:
+			resptype = 3;
+			break;
+		case MMC_RSP_NONE:
+			break;
+		default:
+			debugf("%s: invalid response %lx\n", __func__, MMC_RSP(cmd->flags));
+			break;
+		}
+	}
+
+	if (cmd->flags & MMC_CMD_ADTC) {
+		cmdtype = OMAP_MMC_CMDTYPE_ADTC;
+	}
+	else if (cmd->flags & MMC_CMD_BC) {
+		cmdtype = OMAP_MMC_CMDTYPE_BC;
+	}
+	else if (cmd->flags & MMC_CMD_BCR) {
+		cmdtype = OMAP_MMC_CMDTYPE_BCR;
+	}
+	else {
+		cmdtype = OMAP_MMC_CMDTYPE_AC;
+	}
+
+	cmdreg = cmd->opcode | (resptype << 8) | (cmdtype << 12);
+
+	if (cmd->flags & MMC_RSP_BUSY) {
+		cmdreg |= 1 << 11;
+	}
+
+	if (cmd->data && !(cmd->data->flags & MMC_DATA_WRITE)) {
+		cmdreg |= 1 << 15;
+	}
+
+	goldfish_mmc_write_4(sc, GOLDFISH_MMC_ARG, cmd->arg);
+	goldfish_mmc_write_4(sc, GOLDFISH_MMC_CMD, cmdreg);
+}
+
+static void
+goldfish_mmc_xfer_done(struct goldfish_mmc_softc *sc)
+{
+	int i;
+
+	if (!sc) {
+		debugf("%s: sc is NULL\n", __func__);
+		return;
+	}
+
+	void *resp_ptr = NULL;
+	if (sc->gf_req 
+		&& sc->gf_req
+		&& sc->gf_req->cmd
+		&& sc->gf_req->cmd->data
+		&& sc->gf_req->cmd->data->data) {
+		resp_ptr = sc->gf_req->cmd->data->data;
+	}
+	else {
+		debugf("%s: resp_ptr is NULL\n", __func__);
+		return;
+	}
+
+	enum {
+		WORDS_TO_DUMP = 128,
+	};
+
+	debugf("%s: before GF buffer ", __func__);
+	for (i = 0; i < WORDS_TO_DUMP; i++) {
+		debugf("%08x ", ((uint32_t*)sc->gf_buffer)[i]);
+	}
+	debugf("\n");
+
+	if (resp_ptr) {
+		debugf("%s: before RQ data ", __func__);
+		for (i = 0; i < WORDS_TO_DUMP; i++) {
+			debugf("%08x ", ((uint32_t*)resp_ptr)[i]);
+		}
+	}
+	debugf("\n");
+
+	debugf("%s: gf_data->len=%d cmd->len=%d\n", __func__,
+		sc->gf_data->len, sc->gf_req->cmd->data->len);
+
+	if (sc->gf_xfer_direction == DIRECTION_WRITE) {
+		memcpy(sc->gf_buffer, resp_ptr, sc->gf_req->cmd->data->len);
+	}
+	else {
+		memcpy(resp_ptr, sc->gf_buffer, sc->gf_req->cmd->data->len);
+	}
+
+	debugf("%s: after GF buffer ", __func__);
+	for (i = 0; i < WORDS_TO_DUMP; i++) {
+		debugf("%08x ", ((uint32_t*)sc->gf_buffer)[i]);
+	}
+	debugf("\n");
 	
-	sc->li_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &li_rid, RF_ACTIVE);
-	if (!sc->li_res)
-		goto fail;
+	if (resp_ptr) {
+		debugf("%s: after RQ data ", __func__);
+		for (i = 0; i < WORDS_TO_DUMP; i++) {
+			debugf("%08x ", ((uint32_t*)resp_ptr)[i]);
+		}
+	}
 
-	sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &irq_rid, RF_ACTIVE);
-	if (!sc->irq_res)
-		goto fail;
+	debugf("\n");
+}
 
-	if (bus_setup_intr(dev, sc->irq_res, INTR_TYPE_MISC,
-			goldfish_mmc_intr, NULL, sc, &sc->intr_hl) != 0)
-		goto fail;
+static void
+goldfish_mmc_setup_xfer(struct goldfish_mmc_softc *sc, struct mmc_data *data)
+{
+	if (!sc || !data) {
+		debugf("%s: DATA is NULL\n", __func__);
+		return;
+	}
+
+	sc->gf_data = data;
+	sc->gf_xfer_done = 0;
+	
+	if (data->data == NULL) {
+		debugf("%s: data=NULL\n", __func__);
+		goldfish_mmc_write_4(sc, GOLDFISH_MMC_BLOCK_LENGTH, 0);
+		goldfish_mmc_write_4(sc, GOLDFISH_MMC_BLOCK_COUNT, 0);
+		return;
+	}
+	
+	if (data->flags & MMC_DATA_READ) {
+		sc->gf_xfer_direction = DIRECTION_READ;
+	}
+
+	if (data->flags & MMC_DATA_WRITE) {
+		sc->gf_xfer_direction = DIRECTION_WRITE;
+	}
+	
+	debugf("%s: data length=%d xfer_len=%d\n", __func__, data->len, data->xfer_len);
 
-	sc->li_bst = rman_get_bustag(sc->li_res);
-	sc->li_bsh = rman_get_bushandle(sc->li_res);
-	mmc_softc = sc;
+	goldfish_mmc_write_4(sc, GOLDFISH_MMC_BLOCK_LENGTH, data->len - 1);
+	goldfish_mmc_write_4(sc, GOLDFISH_MMC_BLOCK_COUNT, 0);
+}
+
+static int
+goldfish_mmc_read_ivar(device_t bus, device_t child, int which, 
+    uintptr_t *result)
+{
+	
+	struct goldfish_mmc_softc *sc = device_get_softc(bus);
+
+	switch (which) {
+	case MMCBR_IVAR_BUS_MODE:
+		*(int *)result = sc->gf_host.ios.bus_mode;
+		break;
+	case MMCBR_IVAR_BUS_WIDTH:
+		*(int *)result = sc->gf_host.ios.bus_width;
+		break;
+	case MMCBR_IVAR_CHIP_SELECT:
+		*(int *)result = sc->gf_host.ios.chip_select;
+		break;
+	case MMCBR_IVAR_CLOCK:
+		*(int *)result = sc->gf_host.ios.clock;
+		break;
+	case MMCBR_IVAR_F_MIN:
+		*(int *)result = sc->gf_host.f_min;
+		break;
+	case MMCBR_IVAR_F_MAX:
+		*(int *)result = sc->gf_host.f_max;
+		break;
+	case MMCBR_IVAR_HOST_OCR:
+		*(int *)result = sc->gf_host.host_ocr;
+		break;
+	case MMCBR_IVAR_MODE:
+		*(int *)result = sc->gf_host.mode;
+		break;
+	case MMCBR_IVAR_OCR:
+		*(int *)result = sc->gf_host.ocr;
+		break;
+	case MMCBR_IVAR_POWER_MODE:
+		*(int *)result = sc->gf_host.ios.power_mode;
+		break;
+	case MMCBR_IVAR_VDD:
+		*(int *)result = sc->gf_host.ios.vdd;
+		break;
+	case MMCBR_IVAR_CAPS:
+		*(int *)result = sc->gf_host.caps;
+		break;
+	case MMCBR_IVAR_MAX_DATA:
+		*(int *)result = 1;
+		break;
+	default:
+		return (EINVAL);
+	}
 
 	return (0);
+}
 
-fail:
-	if (sc->irq_res)
-		bus_release_resource(dev, SYS_RES_IRQ, irq_rid, sc->irq_res);
+static int
+goldfish_mmc_write_ivar(device_t bus, device_t child, int which,
+    uintptr_t value)
+{
+	
+	struct goldfish_mmc_softc *sc = device_get_softc(bus);
 
-	if (sc->li_res)
-		bus_release_resource(dev, SYS_RES_MEMORY, li_rid, sc->li_res); 
+	switch (which) {
+	case MMCBR_IVAR_BUS_MODE:
+		sc->gf_host.ios.bus_mode = value;
+		break;
+	case MMCBR_IVAR_BUS_WIDTH:
+		sc->gf_host.ios.bus_width = value;
+		break;
+	case MMCBR_IVAR_CHIP_SELECT:
+		sc->gf_host.ios.chip_select = value;
+		break;
+	case MMCBR_IVAR_CLOCK:
+		sc->gf_host.ios.clock = value;
+		break;
+	case MMCBR_IVAR_MODE:
+		sc->gf_host.mode = value;
+		break;
+	case MMCBR_IVAR_OCR:
+		sc->gf_host.ocr = value;
+		break;
+	case MMCBR_IVAR_POWER_MODE:
+		sc->gf_host.ios.power_mode = value;
+		break;
+	case MMCBR_IVAR_VDD:
+		sc->gf_host.ios.vdd = value;
+		break;
+	/* These are read-only */
+	case MMCBR_IVAR_CAPS:
+	case MMCBR_IVAR_HOST_OCR:
+	case MMCBR_IVAR_F_MIN:
+	case MMCBR_IVAR_F_MAX:
+	case MMCBR_IVAR_MAX_DATA:
+		return (EINVAL);
+	default:
+		return (EINVAL);
+	}
+	return (0);
+}
 
-	return (ENXIO);
+static int
+goldfish_mmc_update_ios(device_t bus, device_t child)
+{
+	return (0);
+}
+
+static int
+goldfish_mmc_get_ro(device_t bus, device_t child)
+{
+	return (0);
+}
+
+static int
+goldfish_mmc_acquire_host(device_t bus, device_t child)
+{
+	struct goldfish_mmc_softc *sc = device_get_softc(bus);
+	int error = 0;
+
+	goldfish_mmc_lock(sc);
+	while (sc->gf_bus_busy)
+		error = mtx_sleep(sc, &sc->gf_mtx, PZERO, "mmcah", 0);
+
+	sc->gf_bus_busy++;
+	goldfish_mmc_unlock(sc);
+	return (error);
+}
+
+static int
+goldfish_mmc_release_host(device_t bus, device_t child)
+{
+	struct goldfish_mmc_softc *sc = device_get_softc(bus);
+
+	goldfish_mmc_lock(sc);
+	sc->gf_bus_busy--;
+	wakeup(sc);
+	goldfish_mmc_unlock(sc);
+	return (0);
+}
+
+#if 0
+static void goldfish_mmc_dma_rxfinish(void *arg)
+{
+}
+
+static void goldfish_mmc_dma_rxerror(void *arg)
+{
+	struct goldfish_mmc_softc *sc = (struct goldfish_mmc_softc *)arg;
+	device_printf(sc->gf_dev, "DMA RX error\n");
+}
+
+static void goldfish_mmc_dma_txfinish(void *arg)
+{
+}
+
+static void goldfish_mmc_dma_txerror(void *arg)
+{
+	struct goldfish_mmc_softc *sc = (struct goldfish_mmc_softc *)arg;
+	
+	device_printf(sc->gf_dev, "DMA TX error\n");
+}
+#endif
+
+static void
+goldfish_mmc_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg, int err)
+{
+	struct goldfish_mmc_dmamap_arg *ctx;
+	
+
+	if (err)
+		return;
+
+	ctx = (struct goldfish_mmc_dmamap_arg *)arg;
+	ctx->gf_dma_busaddr = segs[0].ds_addr;
+}
+
+const char *
+goldfish_fake_ofw_bus_compat (device_t bus, device_t dev)
+{
+	return "mmc";
 }
 
 static device_method_t goldfish_mmc_methods[] = {
+	/* Device interface */
 	DEVMETHOD(device_probe,		goldfish_mmc_probe),
 	DEVMETHOD(device_attach,	goldfish_mmc_attach),
+	DEVMETHOD(device_detach,	goldfish_mmc_detach),
+
+	/* Bus interface */
+	DEVMETHOD(bus_read_ivar,	goldfish_mmc_read_ivar),
+	DEVMETHOD(bus_write_ivar,	goldfish_mmc_write_ivar),
+	//DEVMETHOD(bus_print_child,	bus_generic_print_child),
+
+	/* MMC bridge interface */
+	DEVMETHOD(mmcbr_update_ios,	goldfish_mmc_update_ios),
+	DEVMETHOD(mmcbr_request,	goldfish_mmc_request),
+	DEVMETHOD(mmcbr_get_ro,		goldfish_mmc_get_ro),
+	DEVMETHOD(mmcbr_acquire_host,	goldfish_mmc_acquire_host),
+	DEVMETHOD(mmcbr_release_host,	goldfish_mmc_release_host),
+
+	/* OFW haxx - did not seem to help w/strlcat issue, remove later */
+	DEVMETHOD(ofw_bus_get_compat, goldfish_fake_ofw_bus_compat),
+
 	{ 0, 0 }
 };
 
+static devclass_t goldfish_mmc_devclass;
+
 static driver_t goldfish_mmc_driver = {
-	"mmc",
+	"goldfish_mmc",
 	goldfish_mmc_methods,
 	sizeof(struct goldfish_mmc_softc),
 };
 
-static devclass_t goldfish_mmc_devclass;
-DRIVER_MODULE(mmc, simplebus, goldfish_mmc_driver, goldfish_mmc_devclass, 0, 0);
+DRIVER_MODULE(goldfish_mmc, simplebus, goldfish_mmc_driver, goldfish_mmc_devclass, 0, 0);

Modified: soc2014/astarasikov/head/sys/arm/goldfish/goldfish_pdev.c
==============================================================================
--- soc2014/astarasikov/head/sys/arm/goldfish/goldfish_pdev.c	Mon Aug 18 14:47:13 2014	(r272614)
+++ soc2014/astarasikov/head/sys/arm/goldfish/goldfish_pdev.c	Mon Aug 18 15:42:59 2014	(r272615)
@@ -105,7 +105,7 @@
 	irq_count = pdev_read_4(PDEV_IRQ_COUNT);
 	name_len = pdev_read_4(PDEV_NAME_LEN);
 
-	name = malloc((name_len + 1), M_DEVBUF, M_ZERO);
+	name = malloc((name_len + 1), M_DEVBUF, M_ZERO|M_NOWAIT);
 	if (NULL == name) {
 		name = "NULL";
 	}

Modified: soc2014/astarasikov/head/sys/arm/goldfish/goldfish_timer.c
==============================================================================
--- soc2014/astarasikov/head/sys/arm/goldfish/goldfish_timer.c	Mon Aug 18 14:47:13 2014	(r272614)
+++ soc2014/astarasikov/head/sys/arm/goldfish/goldfish_timer.c	Mon Aug 18 15:42:59 2014	(r272615)
@@ -59,7 +59,7 @@
 	GOLDFISH_TIMER_CLEAR_ALARM = 0x14,
 };
 
-#define CLOCK_TICK_RATE (1000 * 1000 * 1000)
+#define CLOCK_TICK_RATE (1000 * 1000)
 
 struct goldfish_timer_softc {
 	struct resource*	mem_res;

Modified: soc2014/astarasikov/head/sys/boot/fdt/dts/arm/goldfish.dts
==============================================================================
--- soc2014/astarasikov/head/sys/boot/fdt/dts/arm/goldfish.dts	Mon Aug 18 14:47:13 2014	(r272614)
+++ soc2014/astarasikov/head/sys/boot/fdt/dts/arm/goldfish.dts	Mon Aug 18 15:42:59 2014	(r272615)
@@ -25,14 +25,12 @@
 			#interrupt-cells = <1>;
 		};
 
-		/*
 		pdev {
 			compatible = "arm,goldfish-pdev";
 			reg = <0xff001000 0x1000>;
 			interrupts = <1>;
 			interrupt-parent = <&pic>;
 		};
-		*/
 
 		uart0: uart0 {
 			compatible = "arm,goldfish-uart";
@@ -50,7 +48,7 @@
 			interrupts = <3>;
 			interrupt-parent = <&pic>;
 		};
-		
+
 		mmc at xff005000 {
 			compatible = "arm,goldfish-mmc";
 			reg = <0xff005000 0x1000>;
@@ -60,33 +58,14 @@

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***


More information about the svn-soc-all mailing list