Page MenuHomeFreeBSD

D15891.diff
No OneTemporary

D15891.diff

Index: head/sys/arm/allwinner/aw_mmc.c
===================================================================
--- head/sys/arm/allwinner/aw_mmc.c
+++ head/sys/arm/allwinner/aw_mmc.c
@@ -55,6 +55,16 @@
#include <dev/extres/hwreset/hwreset.h>
#include <dev/extres/regulator/regulator.h>
+#include "opt_mmccam.h"
+
+#ifdef MMCCAM
+#include <cam/cam.h>
+#include <cam/cam_ccb.h>
+#include <cam/cam_debug.h>
+#include <cam/cam_sim.h>
+#include <cam/cam_xpt_sim.h>
+#endif
+
#define AW_MMC_MEMRES 0
#define AW_MMC_IRQRES 1
#define AW_MMC_RESSZ 2
@@ -112,7 +122,14 @@
int aw_timeout;
struct callout aw_timeoutc;
struct mmc_host aw_host;
+#ifdef MMCCAM
+ union ccb * ccb;
+ struct cam_devq * devq;
+ struct cam_sim * sim;
+ struct mtx sim_mtx;
+#else
struct mmc_request * aw_req;
+#endif
struct mtx aw_mtx;
struct resource * aw_res[AW_MMC_RESSZ];
struct aw_mmc_conf * aw_mmc_conf;
@@ -148,11 +165,19 @@
static void aw_mmc_intr(void *);
static int aw_mmc_update_clock(struct aw_mmc_softc *, uint32_t);
+static void aw_mmc_print_error(uint32_t);
static int aw_mmc_update_ios(device_t, device_t);
static int aw_mmc_request(device_t, device_t, struct mmc_request *);
static int aw_mmc_get_ro(device_t, device_t);
static int aw_mmc_acquire_host(device_t, device_t);
static int aw_mmc_release_host(device_t, device_t);
+#ifdef MMCCAM
+static void aw_mmc_cam_action(struct cam_sim *, union ccb *);
+static void aw_mmc_cam_poll(struct cam_sim *);
+static int aw_mmc_cam_settran_settings(struct aw_mmc_softc *, union ccb *);
+static int aw_mmc_cam_request(struct aw_mmc_softc *, union ccb *);
+static void aw_mmc_cam_handle_mmcio(struct cam_sim *, union ccb *);
+#endif
#define AW_MMC_LOCK(_sc) mtx_lock(&(_sc)->aw_mtx)
#define AW_MMC_UNLOCK(_sc) mtx_unlock(&(_sc)->aw_mtx)
@@ -161,7 +186,201 @@
#define AW_MMC_WRITE_4(_sc, _reg, _value) \
bus_write_4((_sc)->aw_res[AW_MMC_MEMRES], _reg, _value)
+#ifdef MMCCAM
+static void
+aw_mmc_cam_handle_mmcio(struct cam_sim *sim, union ccb *ccb)
+{
+ struct aw_mmc_softc *sc;
+
+ sc = cam_sim_softc(sim);
+
+ aw_mmc_cam_request(sc, ccb);
+}
+
+static void
+aw_mmc_cam_action(struct cam_sim *sim, union ccb *ccb)
+{
+ struct aw_mmc_softc *sc;
+
+ sc = cam_sim_softc(sim);
+ if (sc == NULL) {
+ ccb->ccb_h.status = CAM_SEL_TIMEOUT;
+ xpt_done(ccb);
+ return;
+ }
+
+ mtx_assert(&sc->sim_mtx, MA_OWNED);
+
+ switch (ccb->ccb_h.func_code) {
+ case XPT_PATH_INQ:
+ {
+ struct ccb_pathinq *cpi;
+
+ cpi = &ccb->cpi;
+ cpi->version_num = 1;
+ cpi->hba_inquiry = 0;
+ cpi->target_sprt = 0;
+ cpi->hba_misc = PIM_NOBUSRESET | PIM_SEQSCAN;
+ cpi->hba_eng_cnt = 0;
+ cpi->max_target = 0;
+ cpi->max_lun = 0;
+ cpi->initiator_id = 1;
+ cpi->maxio = (sc->aw_mmc_conf->dma_xferlen *
+ AW_MMC_DMA_SEGS) / MMC_SECTOR_SIZE;
+ strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
+ strncpy(cpi->hba_vid, "Deglitch Networks", HBA_IDLEN);
+ strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN);
+ cpi->unit_number = cam_sim_unit(sim);
+ cpi->bus_id = cam_sim_bus(sim);
+ cpi->protocol = PROTO_MMCSD;
+ cpi->protocol_version = SCSI_REV_0;
+ cpi->transport = XPORT_MMCSD;
+ cpi->transport_version = 1;
+
+ cpi->ccb_h.status = CAM_REQ_CMP;
+ break;
+ }
+ case XPT_GET_TRAN_SETTINGS:
+ {
+ struct ccb_trans_settings *cts = &ccb->cts;
+
+ if (bootverbose)
+ device_printf(sc->aw_dev, "Got XPT_GET_TRAN_SETTINGS\n");
+
+ cts->protocol = PROTO_MMCSD;
+ cts->protocol_version = 1;
+ cts->transport = XPORT_MMCSD;
+ cts->transport_version = 1;
+ cts->xport_specific.valid = 0;
+ cts->proto_specific.mmc.host_ocr = sc->aw_host.host_ocr;
+ cts->proto_specific.mmc.host_f_min = sc->aw_host.f_min;
+ cts->proto_specific.mmc.host_f_max = sc->aw_host.f_max;
+ cts->proto_specific.mmc.host_caps = sc->aw_host.caps;
+ memcpy(&cts->proto_specific.mmc.ios, &sc->aw_host.ios, sizeof(struct mmc_ios));
+ ccb->ccb_h.status = CAM_REQ_CMP;
+ break;
+ }
+ case XPT_SET_TRAN_SETTINGS:
+ {
+ if (bootverbose)
+ device_printf(sc->aw_dev, "Got XPT_SET_TRAN_SETTINGS\n");
+ aw_mmc_cam_settran_settings(sc, ccb);
+ ccb->ccb_h.status = CAM_REQ_CMP;
+ break;
+ }
+ case XPT_RESET_BUS:
+ if (bootverbose)
+ device_printf(sc->aw_dev, "Got XPT_RESET_BUS, ACK it...\n");
+ ccb->ccb_h.status = CAM_REQ_CMP;
+ break;
+ case XPT_MMC_IO:
+ /*
+ * Here is the HW-dependent part of
+ * sending the command to the underlying h/w
+ * At some point in the future an interrupt comes.
+ * Then the request will be marked as completed.
+ */
+ ccb->ccb_h.status = CAM_REQ_INPROG;
+
+ aw_mmc_cam_handle_mmcio(sim, ccb);
+ return;
+ /* NOTREACHED */
+ break;
+ default:
+ ccb->ccb_h.status = CAM_REQ_INVALID;
+ break;
+ }
+ xpt_done(ccb);
+ return;
+}
+
+static void
+aw_mmc_cam_poll(struct cam_sim *sim)
+{
+ return;
+}
+
static int
+aw_mmc_cam_settran_settings(struct aw_mmc_softc *sc, union ccb *ccb)
+{
+ struct mmc_ios *ios;
+ struct mmc_ios *new_ios;
+ struct ccb_trans_settings_mmc *cts;
+
+ ios = &sc->aw_host.ios;
+
+ cts = &ccb->cts.proto_specific.mmc;
+ new_ios = &cts->ios;
+
+ /* Update only requested fields */
+ if (cts->ios_valid & MMC_CLK) {
+ ios->clock = new_ios->clock;
+ device_printf(sc->aw_dev, "Clock => %d\n", ios->clock);
+ }
+ if (cts->ios_valid & MMC_VDD) {
+ ios->vdd = new_ios->vdd;
+ device_printf(sc->aw_dev, "VDD => %d\n", ios->vdd);
+ }
+ if (cts->ios_valid & MMC_CS) {
+ ios->chip_select = new_ios->chip_select;
+ device_printf(sc->aw_dev, "CS => %d\n", ios->chip_select);
+ }
+ if (cts->ios_valid & MMC_BW) {
+ ios->bus_width = new_ios->bus_width;
+ device_printf(sc->aw_dev, "Bus width => %d\n", ios->bus_width);
+ }
+ if (cts->ios_valid & MMC_PM) {
+ ios->power_mode = new_ios->power_mode;
+ device_printf(sc->aw_dev, "Power mode => %d\n", ios->power_mode);
+ }
+ if (cts->ios_valid & MMC_BT) {
+ ios->timing = new_ios->timing;
+ device_printf(sc->aw_dev, "Timing => %d\n", ios->timing);
+ }
+ if (cts->ios_valid & MMC_BM) {
+ ios->bus_mode = new_ios->bus_mode;
+ device_printf(sc->aw_dev, "Bus mode => %d\n", ios->bus_mode);
+ }
+
+ return (aw_mmc_update_ios(sc->aw_dev, NULL));
+}
+
+static int
+aw_mmc_cam_request(struct aw_mmc_softc *sc, union ccb *ccb)
+{
+ struct ccb_mmcio *mmcio;
+
+ mmcio = &ccb->mmcio;
+
+ AW_MMC_LOCK(sc);
+
+#ifdef DEBUG
+ if (__predict_false(bootverbose)) {
+ device_printf(sc->aw_dev, "CMD%u arg %#x flags %#x dlen %u dflags %#x\n",
+ mmcio->cmd.opcode, mmcio->cmd.arg, mmcio->cmd.flags,
+ mmcio->cmd.data != NULL ? (unsigned int) mmcio->cmd.data->len : 0,
+ mmcio->cmd.data != NULL ? mmcio->cmd.data->flags: 0);
+ }
+#endif
+ if (mmcio->cmd.data != NULL) {
+ if (mmcio->cmd.data->len == 0 || mmcio->cmd.data->flags == 0)
+ panic("data->len = %d, data->flags = %d -- something is b0rked",
+ (int)mmcio->cmd.data->len, mmcio->cmd.data->flags);
+ }
+ if (sc->ccb != NULL) {
+ device_printf(sc->aw_dev, "Controller still has an active command\n");
+ return (EBUSY);
+ }
+ sc->ccb = ccb;
+ /* aw_mmc_request locks again */
+ AW_MMC_UNLOCK(sc);
+ aw_mmc_request(sc->aw_dev, NULL, NULL);
+
+ return (0);
+}
+#endif /* MMCCAM */
+
+static int
aw_mmc_probe(device_t dev)
{
@@ -192,7 +411,9 @@
sc->aw_mmc_conf = (struct aw_mmc_conf *)ofw_bus_search_compatible(dev, compat_data)->ocd_data;
+#ifndef MMCCAM
sc->aw_req = NULL;
+#endif
if (bus_alloc_resources(dev, aw_mmc_res_spec, sc->aw_res) != 0) {
device_printf(dev, "cannot allocate device resources\n");
return (ENXIO);
@@ -295,6 +516,35 @@
if (bus_width >= 8)
sc->aw_host.caps |= MMC_CAP_8_BIT_DATA;
+#ifdef MMCCAM
+ child = NULL; /* Not used by MMCCAM, need to silence compiler warnings */
+ sc->ccb = NULL;
+ if ((sc->devq = cam_simq_alloc(1)) == NULL) {
+ goto fail;
+ }
+
+ mtx_init(&sc->sim_mtx, "awmmcsim", NULL, MTX_DEF);
+ sc->sim = cam_sim_alloc(aw_mmc_cam_action, aw_mmc_cam_poll,
+ "aw_mmc_sim", sc, device_get_unit(dev),
+ &sc->sim_mtx, 1, 1, sc->devq);
+
+ if (sc->sim == NULL) {
+ cam_simq_free(sc->devq);
+ device_printf(dev, "cannot allocate CAM SIM\n");
+ goto fail;
+ }
+
+ mtx_lock(&sc->sim_mtx);
+ if (xpt_bus_register(sc->sim, sc->aw_dev, 0) != 0) {
+ device_printf(dev, "cannot register SCSI pass-through bus\n");
+ cam_sim_free(sc->sim, FALSE);
+ cam_simq_free(sc->devq);
+ mtx_unlock(&sc->sim_mtx);
+ goto fail;
+ }
+
+ mtx_unlock(&sc->sim_mtx);
+#else /* !MMCCAM */
child = device_add_child(dev, "mmc", -1);
if (child == NULL) {
device_printf(dev, "attaching MMC bus failed!\n");
@@ -305,7 +555,7 @@
device_delete_child(dev, child);
goto fail;
}
-
+#endif /* MMCCAM */
return (0);
fail:
@@ -314,6 +564,17 @@
bus_teardown_intr(dev, sc->aw_res[AW_MMC_IRQRES], sc->aw_intrhand);
bus_release_resources(dev, aw_mmc_res_spec, sc->aw_res);
+#ifdef MMCCAM
+ if (sc->sim != NULL) {
+ mtx_lock(&sc->sim_mtx);
+ xpt_bus_deregister(cam_sim_path(sc->sim));
+ cam_sim_free(sc->sim, FALSE);
+ mtx_unlock(&sc->sim_mtx);
+ }
+
+ if (sc->devq != NULL)
+ cam_simq_free(sc->devq);
+#endif
return (ENXIO);
}
@@ -437,7 +698,11 @@
struct mmc_command *cmd;
uint32_t val;
+#ifdef MMCCAM
+ cmd = &sc->ccb->mmcio.cmd;
+#else
cmd = sc->aw_req->cmd;
+#endif
if (cmd->data->len > (sc->aw_mmc_conf->dma_xferlen * AW_MMC_DMA_SEGS))
return (EFBIG);
error = bus_dmamap_load(sc->aw_dma_buf_tag, sc->aw_dma_buf_map,
@@ -549,11 +814,25 @@
aw_mmc_req_done(struct aw_mmc_softc *sc)
{
struct mmc_command *cmd;
+#ifdef MMCCAM
+ union ccb *ccb;
+#else
struct mmc_request *req;
+#endif
uint32_t val, mask;
int retry;
+#ifdef MMCCAM
+ ccb = sc->ccb;
+ cmd = &ccb->mmcio.cmd;
+#else
cmd = sc->aw_req->cmd;
+#endif
+#ifdef DEBUG
+ if (bootverbose) {
+ device_printf(sc->aw_dev, "%s: cmd %d err %d\n", __func__, cmd->opcode, cmd->error);
+ }
+#endif
if (cmd->error != MMC_ERR_NONE) {
/* Reset the FIFO and DMA engines. */
mask = AW_MMC_GCTL_FIFO_RST | AW_MMC_GCTL_DMA_RST;
@@ -573,14 +852,21 @@
aw_mmc_update_clock(sc, 1);
}
- req = sc->aw_req;
callout_stop(&sc->aw_timeoutc);
- sc->aw_req = NULL;
sc->aw_intr = 0;
sc->aw_resid = 0;
sc->aw_dma_map_err = 0;
sc->aw_intr_wait = 0;
+#ifdef MMCCAM
+ sc->ccb = NULL;
+ ccb->ccb_h.status =
+ (ccb->mmcio.cmd.error == 0 ? CAM_REQ_CMP : CAM_REQ_CMP_ERR);
+ xpt_done(ccb);
+#else
+ req = sc->aw_req;
+ sc->aw_req = NULL;
req->done(req);
+#endif
}
static void
@@ -597,7 +883,11 @@
break;
DELAY(1000);
}
+#ifdef MMCCAM
+ cmd = &sc->ccb->mmcio.cmd;
+#else
cmd = sc->aw_req->cmd;
+#endif
if (timeout == 0) {
cmd->error = MMC_ERR_FAILED;
aw_mmc_req_done(sc);
@@ -618,15 +908,30 @@
aw_mmc_req_done(sc);
}
+
+static inline void
+set_mmc_error(struct aw_mmc_softc *sc, int error_code)
+{
+#ifdef MMCCAM
+ sc->ccb->mmcio.cmd.error = error_code;
+#else
+ sc->aw_req->cmd->error = error_code;
+#endif
+}
+
static void
aw_mmc_timeout(void *arg)
{
struct aw_mmc_softc *sc;
sc = (struct aw_mmc_softc *)arg;
+#ifdef MMCCAM
+ if (sc->ccb != NULL) {
+#else
if (sc->aw_req != NULL) {
+#endif
device_printf(sc->aw_dev, "controller timeout\n");
- sc->aw_req->cmd->error = MMC_ERR_TIMEOUT;
+ set_mmc_error(sc, MMC_ERR_TIMEOUT);
aw_mmc_req_done(sc);
} else
device_printf(sc->aw_dev,
@@ -634,6 +939,28 @@
}
static void
+aw_mmc_print_error(uint32_t err)
+{
+ if(err & AW_MMC_INT_RESP_ERR)
+ printf("AW_MMC_INT_RESP_ERR ");
+ if (err & AW_MMC_INT_RESP_CRC_ERR)
+ printf("AW_MMC_INT_RESP_CRC_ERR ");
+ if (err & AW_MMC_INT_DATA_CRC_ERR)
+ printf("AW_MMC_INT_DATA_CRC_ERR ");
+ if (err & AW_MMC_INT_RESP_TIMEOUT)
+ printf("AW_MMC_INT_RESP_TIMEOUT ");
+ if (err & AW_MMC_INT_FIFO_RUN_ERR)
+ printf("AW_MMC_INT_FIFO_RUN_ERR ");
+ if (err & AW_MMC_INT_CMD_BUSY)
+ printf("AW_MMC_INT_CMD_BUSY ");
+ if (err & AW_MMC_INT_DATA_START_ERR)
+ printf("AW_MMC_INT_DATA_START_ERR ");
+ if (err & AW_MMC_INT_DATA_END_BIT_ERR)
+ printf("AW_MMC_INT_DATA_END_BIT_ERR");
+ printf("\n");
+}
+
+static void
aw_mmc_intr(void *arg)
{
bus_dmasync_op_t sync_op;
@@ -654,31 +981,41 @@
device_printf(sc->aw_dev, "idst: %#x, imask: %#x, rint: %#x\n",
idst, imask, rint);
#endif
+#ifdef MMCCAM
+ if (sc->ccb == NULL) {
+#else
if (sc->aw_req == NULL) {
+#endif
device_printf(sc->aw_dev,
"Spurious interrupt - no active request, rint: 0x%08X\n",
rint);
+ aw_mmc_print_error(rint);
goto end;
}
if (rint & AW_MMC_INT_ERR_BIT) {
if (bootverbose)
device_printf(sc->aw_dev, "error rint: 0x%08X\n", rint);
+ aw_mmc_print_error(rint);
if (rint & AW_MMC_INT_RESP_TIMEOUT)
- sc->aw_req->cmd->error = MMC_ERR_TIMEOUT;
+ set_mmc_error(sc, MMC_ERR_TIMEOUT);
else
- sc->aw_req->cmd->error = MMC_ERR_FAILED;
+ set_mmc_error(sc, MMC_ERR_FAILED);
aw_mmc_req_done(sc);
goto end;
}
if (idst & AW_MMC_IDST_ERROR) {
device_printf(sc->aw_dev, "error idst: 0x%08x\n", idst);
- sc->aw_req->cmd->error = MMC_ERR_FAILED;
+ set_mmc_error(sc, MMC_ERR_FAILED);
aw_mmc_req_done(sc);
goto end;
}
sc->aw_intr |= rint;
+#ifdef MMCCAM
+ data = sc->ccb->mmcio.cmd.data;
+#else
data = sc->aw_req->cmd->data;
+#endif
if (data != NULL && (idst & AW_MMC_IDST_COMPLETE) != 0) {
if (data->flags & MMC_DATA_WRITE)
sync_op = BUS_DMASYNC_POSTWRITE;
@@ -712,13 +1049,29 @@
sc = device_get_softc(bus);
AW_MMC_LOCK(sc);
+#ifdef MMCCAM
+ KASSERT(req == NULL, ("req should be NULL in MMCCAM case!"));
+ /*
+ * For MMCCAM, sc->ccb has been NULL-checked and populated
+ * by aw_mmc_cam_request() already.
+ */
+ cmd = &sc->ccb->mmcio.cmd;
+#else
if (sc->aw_req) {
AW_MMC_UNLOCK(sc);
return (EBUSY);
}
-
sc->aw_req = req;
cmd = req->cmd;
+
+#ifdef DEBUG
+ if (bootverbose)
+ device_printf(sc->aw_dev, "CMD%u arg %#x flags %#x dlen %u dflags %#x\n",
+ cmd->opcode, cmd->arg, cmd->flags,
+ cmd->data != NULL ? (unsigned int)cmd->data->len : 0,
+ cmd->data != NULL ? cmd->data->flags: 0);
+#endif
+#endif
cmdreg = AW_MMC_CMDR_LOAD;
imask = AW_MMC_INT_ERR_BIT;
sc->aw_intr_wait = 0;
@@ -1163,4 +1516,6 @@
DRIVER_MODULE(aw_mmc, simplebus, aw_mmc_driver, aw_mmc_devclass, NULL,
NULL);
+#ifndef MMCCAM
MMC_DECLARE_BRIDGE(aw_mmc);
+#endif
Index: head/sys/arm/allwinner/files.allwinner
===================================================================
--- head/sys/arm/allwinner/files.allwinner
+++ head/sys/arm/allwinner/files.allwinner
@@ -10,7 +10,7 @@
arm/allwinner/aw_gpio.c optional gpio
arm/allwinner/aw_if_dwc.c optional dwc
arm/allwinner/aw_machdep.c standard
-arm/allwinner/aw_mmc.c optional mmc
+arm/allwinner/aw_mmc.c optional mmc | mmccam
arm/allwinner/aw_mp.c optional smp
arm/allwinner/aw_nmi.c optional intrng
arm/allwinner/aw_rsb.c optional rsb | p2wi
Index: head/sys/conf/files.arm64
===================================================================
--- head/sys/conf/files.arm64
+++ head/sys/conf/files.arm64
@@ -27,7 +27,7 @@
# Allwinner common files
arm/allwinner/a10_ehci.c optional ehci aw_ehci fdt
arm/allwinner/aw_gpio.c optional gpio aw_gpio fdt
-arm/allwinner/aw_mmc.c optional mmc aw_mmc fdt
+arm/allwinner/aw_mmc.c optional mmc aw_mmc fdt | mmccam aw_mmc fdt
arm/allwinner/aw_nmi.c optional aw_nmi fdt \
compile-with "${NORMAL_C} -I$S/gnu/dts/include"
arm/allwinner/aw_rsb.c optional aw_rsb fdt

File Metadata

Mime Type
text/plain
Expires
Sat, Jan 11, 11:50 PM (20 h, 42 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
15759000
Default Alt Text
D15891.diff (15 KB)

Event Timeline