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