Date: Mon, 18 Aug 2014 15:43:00 GMT From: astarasikov@FreeBSD.org To: svn-soc-all@FreeBSD.org Subject: socsvn commit: r272615 - in soc2014/astarasikov/head/sys: arm/conf arm/goldfish boot/fdt/dts/arm dev/mmc Message-ID: <201408181543.s7IFh0fc029646@socsvn.freebsd.org>
next in thread | raw e-mail | index | archive | help
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@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@xff005000 { compatible = "arm,goldfish-mmc"; reg = <0xff005000 0x1000>; @@ -60,33 +58,14 @@ *** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201408181543.s7IFh0fc029646>