svn commit: r363489 - head/sys/dev/mmc/host

Emmanuel Vadot manu at FreeBSD.org
Fri Jul 24 19:52:53 UTC 2020


Author: manu
Date: Fri Jul 24 19:52:52 2020
New Revision: 363489
URL: https://svnweb.freebsd.org/changeset/base/363489

Log:
  dwmmc: Add MMCCAM part
  
  Add support for MMCCAM for dwmmc
  
  Submitted by:	kibab
  Tested On:	Rock64, RockPro64

Modified:
  head/sys/dev/mmc/host/dwmmc.c
  head/sys/dev/mmc/host/dwmmc_var.h

Modified: head/sys/dev/mmc/host/dwmmc.c
==============================================================================
--- head/sys/dev/mmc/host/dwmmc.c	Fri Jul 24 18:44:50 2020	(r363488)
+++ head/sys/dev/mmc/host/dwmmc.c	Fri Jul 24 19:52:52 2020	(r363489)
@@ -68,9 +68,23 @@ __FBSDID("$FreeBSD$");
 #include <dev/mmc/host/dwmmc_reg.h>
 #include <dev/mmc/host/dwmmc_var.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
+
 #include "mmcbr_if.h"
 
+#ifdef DEBUG
+#define dprintf(fmt, args...) printf(fmt, ##args)
+#else
 #define dprintf(x, arg...)
+#endif
 
 #define	READ4(_sc, _reg) \
 	bus_read_4((_sc)->res[0], _reg)
@@ -129,6 +143,14 @@ static int dma_stop(struct dwmmc_softc *);
 static void pio_read(struct dwmmc_softc *, struct mmc_command *);
 static void pio_write(struct dwmmc_softc *, struct mmc_command *);
 static void dwmmc_handle_card_present(struct dwmmc_softc *sc, bool is_present);
+static int dwmmc_switch_vccq(device_t, device_t);
+#ifdef MMCCAM
+static void dwmmc_cam_action(struct cam_sim *, union ccb *);
+static void dwmmc_cam_poll(struct cam_sim *);
+static int dwmmc_cam_settran_settings(struct dwmmc_softc *, union ccb *);
+static int dwmmc_cam_request(struct dwmmc_softc *, union ccb *);
+static void dwmmc_cam_handle_mmcio(struct cam_sim *, union ccb *);
+#endif
 
 static struct resource_spec dwmmc_spec[] = {
 	{ SYS_RES_MEMORY,	0,	RF_ACTIVE },
@@ -286,8 +308,18 @@ static void
 dwmmc_cmd_done(struct dwmmc_softc *sc)
 {
 	struct mmc_command *cmd;
+#ifdef MMCCAM
+	union ccb *ccb;
+#endif
 
+#ifdef MMCCAM
+	ccb = sc->ccb;
+	if (ccb == NULL)
+		return;
+	cmd = &ccb->mmcio.cmd;
+#else
 	cmd = sc->curcmd;
+#endif
 	if (cmd == NULL)
 		return;
 
@@ -432,6 +464,9 @@ dwmmc_card_task(void *arg, int pending __unused)
 {
 	struct dwmmc_softc *sc = arg;
 
+#ifdef MMCCAM
+	mmccam_start_discovery(sc->sim);
+#else
 	DWMMC_LOCK(sc);
 
 	if (READ4(sc, SDMMC_CDETECT) == 0) {
@@ -459,6 +494,7 @@ dwmmc_card_task(void *arg, int pending __unused)
 		} else
 			DWMMC_UNLOCK(sc);
 	}
+#endif /* MMCCAM */
 }
 
 static int
@@ -721,12 +757,40 @@ dwmmc_attach(device_t dev)
 	TIMEOUT_TASK_INIT(taskqueue_swi_giant, &sc->card_delayed_task, 0,
 		dwmmc_card_task, sc);
 
+#ifdef MMCCAM
+	sc->ccb = NULL;
+	if ((sc->devq = cam_simq_alloc(1)) == NULL) {
+		goto fail;
+	}
+
+	mtx_init(&sc->sim_mtx, "dwmmcsim", NULL, MTX_DEF);
+	sc->sim = cam_sim_alloc_dev(dwmmc_cam_action, dwmmc_cam_poll,
+	    "dw_mmc_sim", sc, 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->dev, 0) != 0) {
+                device_printf(sc->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;
+        }
+
+fail:
+        mtx_unlock(&sc->sim_mtx);
+#endif
 	/* 
 	 * Schedule a card detection as we won't get an interrupt
 	 * if the card is inserted when we attach
 	 */
 	dwmmc_card_task(sc, 0);
-
 	return (0);
 }
 
@@ -1041,15 +1105,17 @@ dwmmc_start_cmd(struct dwmmc_softc *sc, struct mmc_com
 	uint32_t blksz;
 	uint32_t cmdr;
 
+	dprintf("%s\n", __func__);
 	sc->curcmd = cmd;
 	data = cmd->data;
 
 	if ((sc->hwtype & HWTYPE_MASK) == HWTYPE_ROCKCHIP)
 		dwmmc_setup_bus(sc, sc->host.ios.clock);
 
+#ifndef MMCCAM
 	/* XXX Upper layers don't always set this */
 	cmd->mrq = sc->req;
-
+#endif
 	/* Begin setting up command register. */
 
 	cmdr = cmd->opcode;
@@ -1119,11 +1185,23 @@ dwmmc_start_cmd(struct dwmmc_softc *sc, struct mmc_com
 static void
 dwmmc_next_operation(struct dwmmc_softc *sc)
 {
+	struct mmc_command *cmd;
+	dprintf("%s\n", __func__);
+#ifdef MMCCAM
+	union ccb *ccb;
+
+	ccb = sc->ccb;
+	if (ccb == NULL)
+		return;
+	cmd = &ccb->mmcio.cmd;
+#else
 	struct mmc_request *req;
 
 	req = sc->req;
 	if (req == NULL)
 		return;
+	cmd = req->cmd;
+#endif
 
 	sc->acd_rcvd = 0;
 	sc->dto_rcvd = 0;
@@ -1140,17 +1218,26 @@ dwmmc_next_operation(struct dwmmc_softc *sc)
 
 	if (sc->flags & PENDING_CMD) {
 		sc->flags &= ~PENDING_CMD;
-		dwmmc_start_cmd(sc, req->cmd);
+		dwmmc_start_cmd(sc, cmd);
 		return;
 	} else if (sc->flags & PENDING_STOP && !sc->use_auto_stop) {
 		sc->flags &= ~PENDING_STOP;
-		dwmmc_start_cmd(sc, req->stop);
+		/// XXX: What to do with this?
+		//dwmmc_start_cmd(sc, req->stop);
 		return;
 	}
 
+#ifdef MMCCAM
+	sc->ccb = NULL;
+	sc->curcmd = NULL;
+	ccb->ccb_h.status =
+		(ccb->mmcio.cmd.error == 0 ? CAM_REQ_CMP : CAM_REQ_CMP_ERR);
+	xpt_done(ccb);
+#else
 	sc->req = NULL;
 	sc->curcmd = NULL;
 	req->done(req);
+#endif
 }
 
 static int
@@ -1164,6 +1251,9 @@ dwmmc_request(device_t brdev, device_t reqdev, struct 
 
 	DWMMC_LOCK(sc);
 
+#ifdef MMCCAM
+	sc->flags |= PENDING_CMD;
+#else
 	if (sc->req != NULL) {
 		DWMMC_UNLOCK(sc);
 		return (EBUSY);
@@ -1173,6 +1263,7 @@ dwmmc_request(device_t brdev, device_t reqdev, struct 
 	sc->flags |= PENDING_CMD;
 	if (sc->req->stop)
 		sc->flags |= PENDING_STOP;
+#endif
 	dwmmc_next_operation(sc);
 
 	DWMMC_UNLOCK(sc);
@@ -1326,6 +1417,230 @@ dwmmc_write_ivar(device_t bus, device_t child, int whi
 	}
 	return (0);
 }
+
+/* Note: this function likely belongs to the specific driver impl */
+static int
+dwmmc_switch_vccq(device_t dev, device_t child)
+{
+	device_printf(dev, "This is a default impl of switch_vccq() that always fails\n");
+	return EINVAL;
+}
+
+#ifdef MMCCAM
+static void
+dwmmc_cam_handle_mmcio(struct cam_sim *sim, union ccb *ccb)
+{
+	struct dwmmc_softc *sc;
+
+	sc = cam_sim_softc(sim);
+
+	dwmmc_cam_request(sc, ccb);
+}
+
+static void
+dwmmc_cam_action(struct cam_sim *sim, union ccb *ccb)
+{
+	struct dwmmc_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:
+		/* XXX: correctly calculate maxio here */
+		mmc_path_inq(&ccb->cpi, "Deglitch Networks", sim, MMC_SECTOR_SIZE);
+		break;
+
+	case XPT_GET_TRAN_SETTINGS:
+	{
+		struct ccb_trans_settings *cts = &ccb->cts;
+
+		if (bootverbose)
+			device_printf(sc->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->host.host_ocr;
+		cts->proto_specific.mmc.host_f_min = sc->host.f_min;
+		cts->proto_specific.mmc.host_f_max = sc->host.f_max;
+		cts->proto_specific.mmc.host_caps = sc->host.caps;
+		/* XXX: correctly calculate host_max_data */
+		cts->proto_specific.mmc.host_max_data = 1;
+		memcpy(&cts->proto_specific.mmc.ios, &sc->host.ios, sizeof(struct mmc_ios));
+		ccb->ccb_h.status = CAM_REQ_CMP;
+		break;
+	}
+	case XPT_SET_TRAN_SETTINGS:
+	{
+		if (bootverbose)
+			device_printf(sc->dev, "Got XPT_SET_TRAN_SETTINGS\n");
+		dwmmc_cam_settran_settings(sc, ccb);
+		ccb->ccb_h.status = CAM_REQ_CMP;
+		break;
+	}
+	case XPT_RESET_BUS: {
+		struct ccb_trans_settings_mmc *cts;
+
+		cts = &ccb->cts.proto_specific.mmc;
+		cts->ios_valid = MMC_PM;
+		cts->ios.power_mode = power_off;
+		/* Power off the MMC bus */
+		if (dwmmc_cam_settran_settings(sc, ccb) != 0) {
+			device_printf(sc->dev,"cannot power down the MMC bus\n");
+			ccb->ccb_h.status = CAM_REQ_CMP_ERR;
+			break;
+		}
+
+		/* Soft Reset controller and run initialization again */
+		if (dwmmc_ctrl_reset(sc, (SDMMC_CTRL_RESET |
+				  SDMMC_CTRL_FIFO_RESET |
+				  SDMMC_CTRL_DMA_RESET)) != 0) {
+			device_printf(sc->dev, "cannot reset the controller\n");
+			ccb->ccb_h.status = CAM_REQ_CMP_ERR;
+			break;
+		}
+
+		cts->ios_valid = MMC_PM;
+		cts->ios.power_mode = power_on;
+		/* Power off the MMC bus */
+		if (dwmmc_cam_settran_settings(sc, ccb) != 0) {
+			device_printf(sc->dev, "cannot power on the MMC bus\n");
+			ccb->ccb_h.status = CAM_REQ_CMP_ERR;
+			break;
+		}
+
+		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;
+
+		dwmmc_cam_handle_mmcio(sim, ccb);
+		return;
+		/* NOTREACHED */
+		break;
+	default:
+		ccb->ccb_h.status = CAM_REQ_INVALID;
+		break;
+	}
+	xpt_done(ccb);
+	return;
+}
+
+static void
+dwmmc_cam_poll(struct cam_sim *sim)
+{
+	return;
+}
+
+static int
+dwmmc_cam_settran_settings(struct dwmmc_softc *sc, union ccb *ccb)
+{
+	struct mmc_ios *ios;
+	struct mmc_ios *new_ios;
+	struct ccb_trans_settings_mmc *cts;
+	int res;
+
+	ios = &sc->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;
+		if (bootverbose)
+			device_printf(sc->dev, "Clock => %d\n", ios->clock);
+	}
+	if (cts->ios_valid & MMC_VDD) {
+		ios->vdd = new_ios->vdd;
+		if (bootverbose)
+			device_printf(sc->dev, "VDD => %d\n", ios->vdd);
+	}
+	if (cts->ios_valid & MMC_CS) {
+		ios->chip_select = new_ios->chip_select;
+		if (bootverbose)
+			device_printf(sc->dev, "CS => %d\n", ios->chip_select);
+	}
+	if (cts->ios_valid & MMC_BW) {
+		ios->bus_width = new_ios->bus_width;
+		if (bootverbose)
+			device_printf(sc->dev, "Bus width => %d\n", ios->bus_width);
+	}
+	if (cts->ios_valid & MMC_PM) {
+		ios->power_mode = new_ios->power_mode;
+		if (bootverbose)
+			device_printf(sc->dev, "Power mode => %d\n", ios->power_mode);
+	}
+	if (cts->ios_valid & MMC_BT) {
+		ios->timing = new_ios->timing;
+		if (bootverbose)
+			device_printf(sc->dev, "Timing => %d\n", ios->timing);
+	}
+	if (cts->ios_valid & MMC_BM) {
+		ios->bus_mode = new_ios->bus_mode;
+		if (bootverbose)
+			device_printf(sc->dev, "Bus mode => %d\n", ios->bus_mode);
+	}
+	if (cts->ios_valid & MMC_VCCQ) {
+		ios->vccq = new_ios->vccq;
+		if (bootverbose)
+			device_printf(sc->dev, "VCCQ => %d\n", ios->vccq);
+		res = dwmmc_switch_vccq(sc->dev, NULL);
+		device_printf(sc->dev, "VCCQ switch result: %d\n", res);
+	}
+
+	return (dwmmc_update_ios(sc->dev, NULL));
+}
+
+static int
+dwmmc_cam_request(struct dwmmc_softc *sc, union ccb *ccb)
+{
+	struct ccb_mmcio *mmcio;
+
+	mmcio = &ccb->mmcio;
+
+	DWMMC_LOCK(sc);
+
+#ifdef DEBUG
+	if (__predict_false(bootverbose)) {
+		device_printf(sc->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->dev, "Controller still has an active command\n");
+		return (EBUSY);
+	}
+	sc->ccb = ccb;
+	DWMMC_UNLOCK(sc);
+	dwmmc_request(sc->dev, NULL, NULL);
+
+	return (0);
+}
+#endif
 
 static device_method_t dwmmc_methods[] = {
 	/* Bus interface */

Modified: head/sys/dev/mmc/host/dwmmc_var.h
==============================================================================
--- head/sys/dev/mmc/host/dwmmc_var.h	Fri Jul 24 18:44:50 2020	(r363488)
+++ head/sys/dev/mmc/host/dwmmc_var.h	Fri Jul 24 19:52:52 2020	(r363489)
@@ -39,6 +39,8 @@
 #include <dev/extres/regulator/regulator.h>
 #endif
 
+#include "opt_mmccam.h"
+
 enum {
 	HWTYPE_NONE,
 	HWTYPE_ALTERA,
@@ -54,7 +56,14 @@ struct dwmmc_softc {
 	struct mmc_host		host;
 	struct mmc_fdt_helper	mmc_helper;
 	struct mtx		sc_mtx;
+#ifdef MMCCAM
+	union ccb *		ccb;
+	struct cam_devq *	devq;
+	struct cam_sim * 	sim;
+	struct mtx		sim_mtx;
+#else
 	struct mmc_request	*req;
+#endif
 	struct mmc_command	*curcmd;
 	uint32_t		flags;
 	uint32_t		hwtype;


More information about the svn-src-head mailing list