Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F107156293
D15891.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
15 KB
Referenced Files
None
Subscribers
None
D15891.diff
View Options
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
Details
Attached
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)
Attached To
Mode
D15891: Add MMCCAM support to AllWinner MMC driver
Attached
Detach File
Event Timeline
Log In to Comment