All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v10 0/8] Cavium MMC driver
@ 2016-12-19 12:15 Jan Glauber
  2016-12-19 12:15 ` [PATCH v10 1/8] mmc: cavium: Add core MMC driver for Cavium SOCs Jan Glauber
                   ` (8 more replies)
  0 siblings, 9 replies; 20+ messages in thread
From: Jan Glauber @ 2016-12-19 12:15 UTC (permalink / raw)
  To: Ulf Hansson
  Cc: linux-mmc, linux-kernel, David Daney, Steven J . Hill, Jan Glauber

While this patch series seems to be somehow overdue, in the meantime the
same MMC unit was re-used on Cavium's ThunderX SOC so our interest in making
progress upstreaming this driver has doubled now...

Glancing over the history of the series I think most of the high-level
comments should be adressed by now (like DTS representation of the
multiple slots). I've added some new features for the ARM64 port
and in the process re-wrote parts of the driver and split it into smaller,
hopefully easier to review parts.

In porting the driver to arm64 I run into some issues.

1. mmc_parse_of is not capable of supporting multiple slots behind one
   controller. On arm64 the host controller is presented as one PCI device.
   There are no devices per slot as with the platform variant, so I
   needed to create dummy devices to make mmc_parse_of work.
   IMHO it would be cleaner if mmc_parse_of could be extended to cover
   the multiple slots case.

2. Without setting MMC_CAP_1_8V_DDR DDR mode is not usable for eMMC.
   I would prefer to introduce a new cap flag, MMC_CAP_3_3V_DDR,
   if possible. Currently I need to add "mmc-ddr-1_8v" to DTS,
   which seems odd for a 3.3v only host controller.

3. Because the slots share the host controller using the
   "full-pwr-cycle" attribute turned out to not work well.
   I'm not 100% sure just ignoring the attribute is correct.

For the driver to work GPIO support is required, the GPIO driver is
not yet available upstream. Therefore, for the time being I removed
the GPIO dependency from Kconfig.

Feedback welcome!

Changes to v9:
- Split into several patches for easier review
- Re-factor code into smaller functions
- Introduce callback functions for platform specific code
- Remove some dead code
- Remove lots of type casts
- Use NSEC_PER_SEC
- Invert if's to reduce code indentation
- Remove host->linear_buf for now, maybe we can use MMC bounce buffers feature instead
- Use dma_[un]map_sg and length/address accessors instead of direct access
- Set DMA mask
- Add scatter-gather support
- Check for switch errors
- Wait until switch is done
- Enable DDR support for eMMC
- Post CMD23 capability
- Add pr_debug logs
- Split lock acquire from switch_to
- Sort include headers
- Fix code indentation and some checkpatch errors
- Fix includes for octeon specific file
- Fixed modular build on Octeon
- Fail fast on CRC errors (Steven)
- Document devicetree bindings

Cheers,
Jan

--------------------

Jan Glauber (8):
  mmc: cavium: Add core MMC driver for Cavium SOCs
  mmc: octeon: Add MMC platform driver for Octeon SOCs
  mmc: octeon: Work-around hardware bug on cn6xxx and cnf7xxx
  mmc: octeon: Add support for Octeon cn7890
  mmc: thunderx: Add MMC PCI driver for ThunderX SOCs
  mmc: thunderx: Add scatter-gather DMA support
  mmc: thunderx: Support DDR mode for eMMC devices
  dt-bindings: mmc: Add Cavium SOCs MMC bindings

 .../devicetree/bindings/mmc/octeon-mmc.txt         |   59 +
 arch/mips/cavium-octeon/Makefile                   |    1 +
 arch/mips/cavium-octeon/octeon-mmc.c               |   98 ++
 drivers/mmc/host/Kconfig                           |   19 +
 drivers/mmc/host/Makefile                          |    4 +
 drivers/mmc/host/cavium_core_mmc.c                 | 1137 ++++++++++++++++++++
 drivers/mmc/host/cavium_mmc.h                      |  425 ++++++++
 drivers/mmc/host/octeon_platdrv_mmc.c              |  260 +++++
 drivers/mmc/host/thunderx_pcidrv_mmc.c             |  217 ++++
 9 files changed, 2220 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/mmc/octeon-mmc.txt
 create mode 100644 arch/mips/cavium-octeon/octeon-mmc.c
 create mode 100644 drivers/mmc/host/cavium_core_mmc.c
 create mode 100644 drivers/mmc/host/cavium_mmc.h
 create mode 100644 drivers/mmc/host/octeon_platdrv_mmc.c
 create mode 100644 drivers/mmc/host/thunderx_pcidrv_mmc.c

-- 
2.9.0.rc0.21.g7777322

^ permalink raw reply	[flat|nested] 20+ messages in thread

* [PATCH v10 1/8] mmc: cavium: Add core MMC driver for Cavium SOCs
  2016-12-19 12:15 [PATCH v10 0/8] Cavium MMC driver Jan Glauber
@ 2016-12-19 12:15 ` Jan Glauber
  2016-12-19 12:15 ` [PATCH v10 2/8] mmc: octeon: Add MMC platform driver for Octeon SOCs Jan Glauber
                   ` (7 subsequent siblings)
  8 siblings, 0 replies; 20+ messages in thread
From: Jan Glauber @ 2016-12-19 12:15 UTC (permalink / raw)
  To: Ulf Hansson
  Cc: linux-mmc, linux-kernel, David Daney, Steven J . Hill, Jan Glauber

This core driver will be used by a MIPS platform driver
or by an ARM64 PCI driver. The core driver implements the
mmc_host_ops and slot probe & remove functions.
Callbacks are provided to allow platform specific interrupt
enable and bus locking.

The host controller supports:
- up to 4 slots that can contain sd-cards or eMMC chips
- 1, 4 and 8 bit bus width
- SDR and DDR
- transfers up to 52 Mhz (might be less when multiple slots are used)
- DMA read/write
- multi-block read/write (but not stream mode)

Voltage is limited to 3.3v and shared for all slots.

A global lock for all MMC devices is required because the host
controller is shared.

Signed-off-by: Jan Glauber <jglauber@cavium.com>
---
 drivers/mmc/host/cavium_core_mmc.c | 1008 ++++++++++++++++++++++++++++++++++++
 drivers/mmc/host/cavium_mmc.h      |  303 +++++++++++
 2 files changed, 1311 insertions(+)
 create mode 100644 drivers/mmc/host/cavium_core_mmc.c
 create mode 100644 drivers/mmc/host/cavium_mmc.h

diff --git a/drivers/mmc/host/cavium_core_mmc.c b/drivers/mmc/host/cavium_core_mmc.c
new file mode 100644
index 0000000..89d23d3
--- /dev/null
+++ b/drivers/mmc/host/cavium_core_mmc.c
@@ -0,0 +1,1008 @@
+/*
+ * Shared part of driver for MMC/SDHC controller on Cavium OCTEON and
+ * ThunderX SOCs.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2012-2016 Cavium Inc.
+ * Authors:
+ *   David Daney <david.daney@cavium.com>
+ *   Peter Swain <pswain@cavium.com>
+ *   Steven J. Hill <steven.hill@cavium.com>
+ *   Jan Glauber <jglauber@cavium.com>
+ */
+#include <linux/delay.h>
+#include <linux/dma-direction.h>
+#include <linux/dma-mapping.h>
+#include <linux/gpio/consumer.h>
+#include <linux/interrupt.h>
+#include <linux/mmc/mmc.h>
+#include <linux/mmc/slot-gpio.h>
+#include <linux/module.h>
+#include <linux/scatterlist.h>
+#include <linux/time.h>
+
+#include "cavium_mmc.h"
+
+/*
+ * The Cavium MMC host hardware assumes that all commands have fixed
+ * command and response types.  These are correct if MMC devices are
+ * being used.  However, non-MMC devices like SD use command and
+ * response types that are unexpected by the host hardware.
+ *
+ * The command and response types can be overridden by supplying an
+ * XOR value that is applied to the type.  We calculate the XOR value
+ * from the values in this table and the flags passed from the MMC
+ * core.
+ */
+static struct cvm_mmc_cr_type cvm_mmc_cr_types[] = {
+	{0, 0},		/* CMD0 */
+	{0, 3},		/* CMD1 */
+	{0, 2},		/* CMD2 */
+	{0, 1},		/* CMD3 */
+	{0, 0},		/* CMD4 */
+	{0, 1},		/* CMD5 */
+	{0, 1},		/* CMD6 */
+	{0, 1},		/* CMD7 */
+	{1, 1},		/* CMD8 */
+	{0, 2},		/* CMD9 */
+	{0, 2},		/* CMD10 */
+	{1, 1},		/* CMD11 */
+	{0, 1},		/* CMD12 */
+	{0, 1},		/* CMD13 */
+	{1, 1},		/* CMD14 */
+	{0, 0},		/* CMD15 */
+	{0, 1},		/* CMD16 */
+	{1, 1},		/* CMD17 */
+	{1, 1},		/* CMD18 */
+	{3, 1},		/* CMD19 */
+	{2, 1},		/* CMD20 */
+	{0, 0},		/* CMD21 */
+	{0, 0},		/* CMD22 */
+	{0, 1},		/* CMD23 */
+	{2, 1},		/* CMD24 */
+	{2, 1},		/* CMD25 */
+	{2, 1},		/* CMD26 */
+	{2, 1},		/* CMD27 */
+	{0, 1},		/* CMD28 */
+	{0, 1},		/* CMD29 */
+	{1, 1},		/* CMD30 */
+	{1, 1},		/* CMD31 */
+	{0, 0},		/* CMD32 */
+	{0, 0},		/* CMD33 */
+	{0, 0},		/* CMD34 */
+	{0, 1},		/* CMD35 */
+	{0, 1},		/* CMD36 */
+	{0, 0},		/* CMD37 */
+	{0, 1},		/* CMD38 */
+	{0, 4},		/* CMD39 */
+	{0, 5},		/* CMD40 */
+	{0, 0},		/* CMD41 */
+	{2, 1},		/* CMD42 */
+	{0, 0},		/* CMD43 */
+	{0, 0},		/* CMD44 */
+	{0, 0},		/* CMD45 */
+	{0, 0},		/* CMD46 */
+	{0, 0},		/* CMD47 */
+	{0, 0},		/* CMD48 */
+	{0, 0},		/* CMD49 */
+	{0, 0},		/* CMD50 */
+	{0, 0},		/* CMD51 */
+	{0, 0},		/* CMD52 */
+	{0, 0},		/* CMD53 */
+	{0, 0},		/* CMD54 */
+	{0, 1},		/* CMD55 */
+	{0xff, 0xff},	/* CMD56 */
+	{0, 0},		/* CMD57 */
+	{0, 0},		/* CMD58 */
+	{0, 0},		/* CMD59 */
+	{0, 0},		/* CMD60 */
+	{0, 0},		/* CMD61 */
+	{0, 0},		/* CMD62 */
+	{0, 0}		/* CMD63 */
+};
+
+static struct cvm_mmc_cr_mods cvm_mmc_get_cr_mods(struct mmc_command *cmd)
+{
+	struct cvm_mmc_cr_type *cr;
+	u8 hardware_ctype, hardware_rtype;
+	u8 desired_ctype = 0, desired_rtype = 0;
+	struct cvm_mmc_cr_mods r;
+
+	cr = cvm_mmc_cr_types + (cmd->opcode & 0x3f);
+	hardware_ctype = cr->ctype;
+	hardware_rtype = cr->rtype;
+	if (cmd->opcode == MMC_GEN_CMD)
+		hardware_ctype = (cmd->arg & 1) ? 1 : 2;
+
+	switch (mmc_cmd_type(cmd)) {
+	case MMC_CMD_ADTC:
+		desired_ctype = (cmd->data->flags & MMC_DATA_WRITE) ? 2 : 1;
+		break;
+	case MMC_CMD_AC:
+	case MMC_CMD_BC:
+	case MMC_CMD_BCR:
+		desired_ctype = 0;
+		break;
+	}
+
+	switch (mmc_resp_type(cmd)) {
+	case MMC_RSP_NONE:
+		desired_rtype = 0;
+		break;
+	case MMC_RSP_R1:/* MMC_RSP_R5, MMC_RSP_R6, MMC_RSP_R7 */
+	case MMC_RSP_R1B:
+		desired_rtype = 1;
+		break;
+	case MMC_RSP_R2:
+		desired_rtype = 2;
+		break;
+	case MMC_RSP_R3: /* MMC_RSP_R4 */
+		desired_rtype = 3;
+		break;
+	}
+	r.ctype_xor = desired_ctype ^ hardware_ctype;
+	r.rtype_xor = desired_rtype ^ hardware_rtype;
+	return r;
+}
+
+static void check_switch_errors(struct cvm_mmc_host *host)
+{
+	union mio_emm_switch emm_switch;
+
+	emm_switch.val = readq(host->base + MIO_EMM_SWITCH);
+	if (emm_switch.s.switch_err0)
+		dev_err(host->dev, "Switch power class error\n");
+	if (emm_switch.s.switch_err1)
+		dev_err(host->dev, "Switch hs timing error\n");
+	if (emm_switch.s.switch_err2)
+		dev_err(host->dev, "Switch bus width error\n");
+}
+
+/*
+ * We never set the switch_exe bit since that would interfere
+ * with the commands send by the MMC core.
+ */
+static void do_switch(struct cvm_mmc_host *host, u64 val)
+{
+	union mio_emm_rsp_sts rsp_sts;
+	union mio_emm_switch emm_switch;
+	int retries = 100;
+	int bus_id;
+
+	emm_switch.val = val;
+
+	/*
+	 * Modes setting only taken from slot 0. Work around that hardware
+	 * issue by first switching to slot 0.
+	 */
+	bus_id = emm_switch.s.bus_id;
+	emm_switch.s.bus_id = 0;
+	writeq(emm_switch.val, host->base + MIO_EMM_SWITCH);
+
+	emm_switch.s.bus_id = bus_id;
+	writeq(emm_switch.val, host->base + MIO_EMM_SWITCH);
+
+	/* wait for the switch to finish */
+	do {
+		rsp_sts.val = readq(host->base + MIO_EMM_RSP_STS);
+		if (!rsp_sts.s.switch_val)
+			break;
+		udelay(10);
+	} while (--retries);
+
+	check_switch_errors(host);
+}
+
+static bool switch_val_changed(struct cvm_mmc_slot *slot, u64 new_val)
+{
+	/* Match BUS_ID, HS_TIMING, BUS_WIDTH, POWER_CLASS, CLK_HI, CLK_LO */
+	u64 match = 0x3001070fffffffffull;
+
+	return (slot->cached_switch & match) != (new_val & match);
+}
+
+static void set_wdog(struct cvm_mmc_slot *slot, unsigned int ns)
+{
+	u64 timeout;
+
+	WARN_ON_ONCE(!slot->clock);
+	if (ns)
+		timeout = (slot->clock * ns) / NSEC_PER_SEC;
+	else
+		timeout = (slot->clock * 850ull) / 1000ull;
+	writeq(timeout, slot->host->base + MIO_EMM_WDOG);
+}
+
+static void cvm_mmc_reset_bus(struct cvm_mmc_slot *slot)
+{
+	union mio_emm_switch emm_switch;
+	u64 wdog = 0;
+
+	emm_switch.val = readq(slot->host->base + MIO_EMM_SWITCH);
+	wdog = readq(slot->host->base + MIO_EMM_WDOG);
+
+	emm_switch.s.switch_exe = 0;
+	emm_switch.s.switch_err0 = 0;
+	emm_switch.s.switch_err1 = 0;
+	emm_switch.s.switch_err2 = 0;
+	emm_switch.s.bus_id = slot->bus_id;
+	do_switch(slot->host, emm_switch.val);
+
+	slot->cached_switch = emm_switch.val;
+
+	msleep(20);
+
+	writeq(wdog, slot->host->base + MIO_EMM_WDOG);
+}
+
+/* Switch to another slot if needed */
+static void cvm_mmc_switch_to(struct cvm_mmc_slot *slot)
+{
+	struct cvm_mmc_host *host = slot->host;
+	struct cvm_mmc_slot *old_slot;
+	union mio_emm_switch emm_switch;
+	union mio_emm_sample emm_sample;
+
+	if (slot->bus_id == host->last_slot)
+		return;
+
+	if (host->last_slot >= 0 && host->slot[host->last_slot]) {
+		old_slot = host->slot[host->last_slot];
+		old_slot->cached_switch = readq(host->base + MIO_EMM_SWITCH);
+		old_slot->cached_rca = readq(host->base + MIO_EMM_RCA);
+	}
+
+	writeq(slot->cached_rca, host->base + MIO_EMM_RCA);
+	emm_switch.val = slot->cached_switch;
+	emm_switch.s.bus_id = slot->bus_id;
+	do_switch(host, emm_switch.val);
+
+	emm_sample.val = 0;
+	emm_sample.s.cmd_cnt = slot->cmd_cnt;
+	emm_sample.s.dat_cnt = slot->dat_cnt;
+	writeq(emm_sample.val, host->base + MIO_EMM_SAMPLE);
+
+	host->last_slot = slot->bus_id;
+}
+
+static void do_read(struct cvm_mmc_host *host, struct mmc_request *req,
+		    u64 dbuf)
+{
+	struct sg_mapping_iter *smi = &host->smi;
+	int data_len = req->data->blocks * req->data->blksz;
+	int bytes_xfered, shift = -1;
+	u64 dat = 0;
+
+	/* Auto inc from offset zero */
+	writeq((0x10000 | (dbuf << 6)), host->base + MIO_EMM_BUF_IDX);
+
+	for (bytes_xfered = 0; bytes_xfered < data_len;) {
+		if (smi->consumed >= smi->length) {
+			if (!sg_miter_next(smi))
+				break;
+			smi->consumed = 0;
+		}
+
+		if (shift < 0) {
+			dat = readq(host->base + MIO_EMM_BUF_DAT);
+			shift = 56;
+		}
+
+		while (smi->consumed < smi->length && shift >= 0) {
+			((u8 *)smi->addr)[smi->consumed] = (dat >> shift) & 0xff;
+			bytes_xfered++;
+			smi->consumed++;
+			shift -= 8;
+		}
+	}
+
+	sg_miter_stop(smi);
+	req->data->bytes_xfered = bytes_xfered;
+	req->data->error = 0;
+}
+
+static void do_write(struct mmc_request *req)
+{
+	req->data->bytes_xfered = req->data->blocks * req->data->blksz;
+	req->data->error = 0;
+}
+
+static void set_cmd_response(struct cvm_mmc_host *host, struct mmc_request *req,
+			     union mio_emm_rsp_sts *rsp_sts)
+{
+	u64 rsp_hi, rsp_lo;
+
+	if (!rsp_sts->s.rsp_val)
+		return;
+
+	rsp_lo = readq(host->base + MIO_EMM_RSP_LO);
+
+	switch (rsp_sts->s.rsp_type) {
+	case 1:
+	case 3:
+		req->cmd->resp[0] = (rsp_lo >> 8) & 0xffffffff;
+		req->cmd->resp[1] = 0;
+		req->cmd->resp[2] = 0;
+		req->cmd->resp[3] = 0;
+		break;
+	case 2:
+		req->cmd->resp[3] = rsp_lo & 0xffffffff;
+		req->cmd->resp[2] = (rsp_lo >> 32) & 0xffffffff;
+		rsp_hi = readq(host->base + MIO_EMM_RSP_HI);
+		req->cmd->resp[1] = rsp_hi & 0xffffffff;
+		req->cmd->resp[0] = (rsp_hi >> 32) & 0xffffffff;
+		break;
+	}
+}
+
+static int get_dma_dir(struct mmc_data *data)
+{
+	return (data->flags & MMC_DATA_WRITE) ? DMA_TO_DEVICE : DMA_FROM_DEVICE;
+}
+
+static int finish_dma_single(struct cvm_mmc_host *host, struct mmc_data *data)
+{
+	data->bytes_xfered = data->blocks * data->blksz;
+	data->error = 0;
+	return 1;
+}
+
+static int finish_dma(struct cvm_mmc_host *host, struct mmc_data *data)
+{
+	return finish_dma_single(host, data);
+}
+
+static bool bad_status(union mio_emm_rsp_sts *rsp_sts)
+{
+	if (rsp_sts->s.rsp_bad_sts || rsp_sts->s.rsp_crc_err ||
+	    rsp_sts->s.rsp_timeout || rsp_sts->s.blk_crc_err ||
+	    rsp_sts->s.blk_timeout || rsp_sts->s.dbuf_err)
+		return true;
+
+	return false;
+}
+
+/* Try to clean up failed DMA. */
+static void cleanup_dma(struct cvm_mmc_host *host,
+			union mio_emm_rsp_sts *rsp_sts)
+{
+	union mio_emm_dma emm_dma;
+
+	emm_dma.val = readq(host->base + MIO_EMM_DMA);
+	emm_dma.s.dma_val = 1;
+	emm_dma.s.dat_null = 1;
+	emm_dma.s.bus_id = rsp_sts->s.bus_id;
+	writeq(emm_dma.val, host->base + MIO_EMM_DMA);
+}
+
+irqreturn_t cvm_mmc_interrupt(int irq, void *dev_id)
+{
+	struct cvm_mmc_host *host = dev_id;
+	union mio_emm_rsp_sts rsp_sts;
+	union mio_emm_int emm_int;
+	struct mmc_request *req;
+	bool host_done;
+
+	/* Clear interrupt bits (write 1 clears ). */
+	emm_int.val = readq(host->base + MIO_EMM_INT);
+	writeq(emm_int.val, host->base + MIO_EMM_INT);
+
+	if (emm_int.s.switch_err)
+		check_switch_errors(host);
+
+	req = host->current_req;
+	if (!req)
+		goto out;
+
+	rsp_sts.val = readq(host->base + MIO_EMM_RSP_STS);
+	/*
+	 * dma_val set means DMA is still in progress. Don't touch
+	 * the request and wait for the interrupt indicating that
+	 * the DMA is finished.
+	 */
+	if (rsp_sts.s.dma_val && host->dma_active)
+		goto out;
+
+	if (!host->dma_active && emm_int.s.buf_done && req->data) {
+		unsigned int type = (rsp_sts.val >> 7) & 3;
+
+		if (type == 1)
+			do_read(host, req, rsp_sts.s.dbuf);
+		else if (type == 2)
+			do_write(req);
+	}
+
+	host_done = emm_int.s.cmd_done || emm_int.s.dma_done ||
+		    emm_int.s.cmd_err || emm_int.s.dma_err;
+
+	if (!(host_done && req->done))
+		goto no_req_done;
+
+	if (bad_status(&rsp_sts))
+		req->cmd->error = -EILSEQ;
+	else
+		req->cmd->error = 0;
+
+	if (host->dma_active && req->data)
+		if (!finish_dma(host, req->data))
+			goto no_req_done;
+
+	set_cmd_response(host, req, &rsp_sts);
+	if (emm_int.s.dma_err && rsp_sts.s.dma_pend)
+		cleanup_dma(host, &rsp_sts);
+
+	host->current_req = NULL;
+	req->done(req);
+
+no_req_done:
+	if (host_done)
+		host->release_bus(host);
+out:
+	return IRQ_RETVAL(emm_int.val != 0);
+}
+
+/*
+ * Program DMA_CFG and if needed DMA_ADR.
+ * Returns 0 on error, DMA address otherwise.
+ */
+static u64 prepare_dma_single(struct cvm_mmc_host *host, struct mmc_data *data)
+{
+	union mio_emm_dma_cfg dma_cfg;
+	int count;
+	u64 addr;
+
+	count = dma_map_sg(host->dev, data->sg, data->sg_len,
+			   get_dma_dir(data));
+	if (!count)
+		return 0;
+
+	dma_cfg.val = 0;
+	dma_cfg.s.en = 1;
+	dma_cfg.s.rw = (data->flags & MMC_DATA_WRITE) ? 1 : 0;
+#ifdef __LITTLE_ENDIAN
+	dma_cfg.s.endian = 1;
+#endif
+	dma_cfg.s.size = (sg_dma_len(&data->sg[0]) / 8) - 1;
+
+	addr = sg_dma_address(&data->sg[0]);
+	dma_cfg.s.adr = addr;
+	writeq(dma_cfg.val, host->dma_base + MIO_EMM_DMA_CFG);
+
+	pr_debug("[%s] sg_dma_len: %u  total sg_elem: %d\n",
+		 (dma_cfg.s.rw) ? "W" : "R", sg_dma_len(&data->sg[0]), count);
+	return addr;
+}
+
+static u64 prepare_dma(struct cvm_mmc_host *host, struct mmc_data *data)
+{
+	return prepare_dma_single(host, data);
+}
+
+static void prepare_ext_dma(struct mmc_host *mmc, struct mmc_request *mrq,
+			    union mio_emm_dma *emm_dma)
+{
+	struct cvm_mmc_slot *slot = mmc_priv(mmc);
+
+	/*
+	 * Our MMC host hardware does not issue single commands,
+	 * because that would require the driver and the MMC core
+	 * to do work to determine the proper sequence of commands.
+	 * Instead, our hardware is superior to most other MMC bus
+	 * hosts. The sequence of MMC commands required to execute
+	 * a transfer are issued automatically by the bus hardware.
+	 *
+	 * - David Daney <ddaney@cavium.com>
+	 */
+	emm_dma->val = 0;
+	emm_dma->s.bus_id = slot->bus_id;
+	emm_dma->s.dma_val = 1;
+	emm_dma->s.sector = mmc_card_blockaddr(mmc->card) ? 1 : 0;
+	emm_dma->s.rw = (mrq->data->flags & MMC_DATA_WRITE) ? 1 : 0;
+	emm_dma->s.block_cnt = mrq->data->blocks;
+	emm_dma->s.card_addr = mrq->cmd->arg;
+	if (mmc_card_mmc(mmc->card) || (mmc_card_sd(mmc->card) &&
+	    (mmc->card->scr.cmds & SD_SCR_CMD23_SUPPORT)))
+		emm_dma->s.multi = 1;
+
+	pr_debug("[%s] blocks: %u  multi: %d\n", (emm_dma->s.rw) ? "W" : "R",
+		 mrq->data->blocks, emm_dma->s.multi);
+}
+
+static void prepare_emm_int(union mio_emm_int *emm_int)
+{
+	emm_int->val = 0;
+	emm_int->s.cmd_err = 1;
+	emm_int->s.dma_done = 1;
+	emm_int->s.dma_err = 1;
+}
+
+static void cvm_mmc_dma_request(struct mmc_host *mmc,
+				struct mmc_request *mrq)
+{
+	struct cvm_mmc_slot *slot = mmc_priv(mmc);
+	struct cvm_mmc_host *host = slot->host;
+	union mio_emm_dma emm_dma;
+	union mio_emm_int emm_int;
+	struct mmc_data *data;
+	u64 addr;
+
+	if (!mrq->data || !mrq->data->sg || !mrq->data->sg_len ||
+	    !mrq->stop || mrq->stop->opcode != MMC_STOP_TRANSMISSION) {
+		dev_err(&mmc->card->dev,
+			"Error: cmv_mmc_dma_request no data\n");
+		goto error;
+	}
+
+	cvm_mmc_switch_to(slot);
+
+	data = mrq->data;
+	pr_debug("DMA request  blocks: %d  block_size: %d  total_size: %d\n",
+		 data->blocks, data->blksz, data->blocks * data->blksz);
+	if (data->timeout_ns)
+		set_wdog(slot, data->timeout_ns);
+
+	WARN_ON(host->current_req);
+	host->current_req = mrq;
+
+	prepare_ext_dma(mmc, mrq, &emm_dma);
+	addr = prepare_dma(host, data);
+	if (!addr) {
+		dev_err(host->dev, "prepare_dma failed\n");
+		goto error;
+	}
+	prepare_emm_int(&emm_int);
+
+	host->dma_active = true;
+	host->int_enable(host, emm_int.val);
+
+	/*
+	 * If we have a valid SD card in the slot, we set the response
+	 * bit mask to check for CRC errors and timeouts only.
+	 * Otherwise, use the default power reset value.
+	 */
+	if (mmc->card && mmc_card_sd(mmc->card))
+		writeq(0x00b00000ull, host->base + MIO_EMM_STS_MASK);
+	else
+		writeq(0xe4390080ull, host->base + MIO_EMM_STS_MASK);
+	writeq(emm_dma.val, host->base + MIO_EMM_DMA);
+	return;
+
+error:
+	mrq->cmd->error = -EINVAL;
+	if (mrq->done)
+		mrq->done(mrq);
+	host->release_bus(host);
+}
+
+static void do_read_request(struct cvm_mmc_host *host, struct mmc_request *mrq)
+{
+	sg_miter_start(&host->smi, mrq->data->sg, mrq->data->sg_len,
+		       SG_MITER_ATOMIC | SG_MITER_TO_SG);
+}
+
+static void do_write_request(struct cvm_mmc_host *host, struct mmc_request *mrq)
+{
+	unsigned int data_len = mrq->data->blocks * mrq->data->blksz;
+	struct sg_mapping_iter *smi = &host->smi;
+	unsigned int bytes_xfered;
+	int shift = 56;
+	u64 dat = 0;
+
+	/* Copy data to the xmit buffer before issuing the command. */
+	sg_miter_start(smi, mrq->data->sg, mrq->data->sg_len, SG_MITER_FROM_SG);
+
+	/* Auto inc from offset zero, dbuf zero */
+	writeq(0x10000ull, host->base + MIO_EMM_BUF_IDX);
+
+	for (bytes_xfered = 0; bytes_xfered < data_len;) {
+		if (smi->consumed >= smi->length) {
+			if (!sg_miter_next(smi))
+				break;
+			smi->consumed = 0;
+		}
+
+		while (smi->consumed < smi->length && shift >= 0) {
+			dat |= ((u8 *)smi->addr)[smi->consumed] << shift;
+			bytes_xfered++;
+			smi->consumed++;
+			shift -= 8;
+		}
+
+		if (shift < 0) {
+			writeq(dat, host->base + MIO_EMM_BUF_DAT);
+			shift = 56;
+			dat = 0;
+		}
+	}
+	sg_miter_stop(smi);
+}
+
+static void cvm_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq)
+{
+	struct cvm_mmc_slot *slot = mmc_priv(mmc);
+	struct cvm_mmc_host *host = slot->host;
+	struct mmc_command *cmd = mrq->cmd;
+	union mio_emm_int emm_int;
+	union mio_emm_cmd emm_cmd;
+	struct cvm_mmc_cr_mods mods;
+	union mio_emm_rsp_sts rsp_sts;
+	int retries = 100;
+
+	/*
+	 * Note about locking:
+	 * All MMC devices share the same bus and controller. Allow only a
+	 * single user of the bootbus/MMC bus at a time. The lock is acquired
+	 * on all entry points from the MMC layer.
+	 *
+	 * For requests the lock is only released after the completion
+	 * interrupt!
+	 */
+	host->acquire_bus(host);
+
+	if (cmd->opcode == MMC_READ_MULTIPLE_BLOCK ||
+	    cmd->opcode == MMC_WRITE_MULTIPLE_BLOCK)
+		return cvm_mmc_dma_request(mmc, mrq);
+
+	cvm_mmc_switch_to(slot);
+
+	mods = cvm_mmc_get_cr_mods(cmd);
+
+	WARN_ON(host->current_req);
+	host->current_req = mrq;
+
+	emm_int.val = 0;
+	emm_int.s.cmd_done = 1;
+	emm_int.s.cmd_err = 1;
+
+	if (cmd->data) {
+		if (cmd->data->flags & MMC_DATA_READ)
+			do_read_request(host, mrq);
+		else
+			do_write_request(host, mrq);
+
+		if (cmd->data->timeout_ns)
+			set_wdog(slot, cmd->data->timeout_ns);
+	} else
+		set_wdog(slot, 0);
+
+	host->dma_active = false;
+	host->int_enable(host, emm_int.val);
+
+	emm_cmd.val = 0;
+	emm_cmd.s.cmd_val = 1;
+	emm_cmd.s.ctype_xor = mods.ctype_xor;
+	emm_cmd.s.rtype_xor = mods.rtype_xor;
+	if (mmc_cmd_type(cmd) == MMC_CMD_ADTC)
+		emm_cmd.s.offset = 64 - ((cmd->data->blocks * cmd->data->blksz) / 8);
+	emm_cmd.s.bus_id = slot->bus_id;
+	emm_cmd.s.cmd_idx = cmd->opcode;
+	emm_cmd.s.arg = cmd->arg;
+
+	writeq(0, host->base + MIO_EMM_STS_MASK);
+
+retry:
+	rsp_sts.val = readq(host->base + MIO_EMM_RSP_STS);
+	if (rsp_sts.s.dma_val || rsp_sts.s.cmd_val ||
+	    rsp_sts.s.switch_val || rsp_sts.s.dma_pend) {
+		udelay(10);
+		if (--retries)
+			goto retry;
+	}
+	if (!retries)
+		dev_err(host->dev, "Bad status: %Lx before command write\n", rsp_sts.val);
+	writeq(emm_cmd.val, host->base + MIO_EMM_CMD);
+}
+
+static void cvm_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
+{
+	struct cvm_mmc_slot *slot = mmc_priv(mmc);
+	struct cvm_mmc_host *host = slot->host;
+	int clk_period, power_class = 10, bus_width = 0;
+	union mio_emm_switch emm_switch;
+	u64 clock;
+
+	host->acquire_bus(host);
+	cvm_mmc_switch_to(slot);
+
+	/* Reset the chip on each POWER_OFF. */
+	if (ios->power_mode == MMC_POWER_OFF) {
+		cvm_mmc_reset_bus(slot);
+		gpiod_set_value_cansleep(host->global_pwr_gpiod, 0);
+	} else
+		gpiod_set_value_cansleep(host->global_pwr_gpiod, 1);
+
+	switch (ios->bus_width) {
+	case MMC_BUS_WIDTH_8:
+		bus_width = 2;
+		break;
+	case MMC_BUS_WIDTH_4:
+		bus_width = 1;
+		break;
+	case MMC_BUS_WIDTH_1:
+		bus_width = 0;
+		break;
+	}
+
+	slot->bus_width = bus_width;
+
+	if (!ios->clock)
+		goto out;
+
+	/* Change the clock frequency. */
+	clock = ios->clock;
+	if (clock > 52000000)
+		clock = 52000000;
+	slot->clock = clock;
+	clk_period = (host->sys_freq + clock - 1) / (2 * clock);
+
+	emm_switch.val = 0;
+	emm_switch.s.hs_timing = (ios->timing == MMC_TIMING_MMC_HS);
+	emm_switch.s.bus_width = bus_width;
+	emm_switch.s.power_class = power_class;
+	emm_switch.s.clk_hi = clk_period;
+	emm_switch.s.clk_lo = clk_period;
+	emm_switch.s.bus_id = slot->bus_id;
+
+	if (!switch_val_changed(slot, emm_switch.val))
+		goto out;
+
+	set_wdog(slot, 0);
+	do_switch(host, emm_switch.val);
+	slot->cached_switch = emm_switch.val;
+out:
+	host->release_bus(host);
+}
+
+const struct mmc_host_ops cvm_mmc_ops = {
+	.request        = cvm_mmc_request,
+	.set_ios        = cvm_mmc_set_ios,
+	.get_ro		= mmc_gpio_get_ro,
+	.get_cd		= mmc_gpio_get_cd,
+};
+
+static void cvm_mmc_set_clock(struct cvm_mmc_slot *slot, unsigned int clock)
+{
+	struct mmc_host *mmc = slot->mmc;
+
+	clock = min(clock, mmc->f_max);
+	clock = max(clock, mmc->f_min);
+	slot->clock = clock;
+}
+
+static int cvm_mmc_init_lowlevel(struct cvm_mmc_slot *slot)
+{
+	struct cvm_mmc_host *host = slot->host;
+	union mio_emm_switch emm_switch;
+
+	/* Enable this bus slot. */
+	host->emm_cfg |= (1ull << slot->bus_id);
+	writeq(host->emm_cfg, slot->host->base + MIO_EMM_CFG);
+	udelay(10);
+
+	/* Program initial clock speed and power. */
+	cvm_mmc_set_clock(slot, slot->mmc->f_min);
+	emm_switch.val = 0;
+	emm_switch.s.power_class = 10;
+	emm_switch.s.clk_hi = (slot->sclock / slot->clock) / 2;
+	emm_switch.s.clk_lo = (slot->sclock / slot->clock) / 2;
+
+	/* Make the changes take effect on this bus slot. */
+	emm_switch.s.bus_id = slot->bus_id;
+	do_switch(host, emm_switch.val);
+
+	slot->cached_switch = emm_switch.val;
+
+	/*
+	 * Set watchdog timeout value and default reset value
+	 * for the mask register. Finally, set the CARD_RCA
+	 * bit so that we can get the card address relative
+	 * to the CMD register for CMD7 transactions.
+	 */
+	set_wdog(slot, 0);
+	writeq(0xe4390080ull, host->base + MIO_EMM_STS_MASK);
+	writeq(1, host->base + MIO_EMM_RCA);
+	return 0;
+}
+
+static int set_bus_width(struct device *dev, struct cvm_mmc_slot *slot, u32 id)
+{
+	u32 bus_width;
+	int ret;
+
+	/*
+	 * The "cavium,bus-max-width" property is DEPRECATED and should
+	 * not be used. We handle it here to support older firmware.
+	 * Going forward, the standard "bus-width" property is used
+	 * instead of the Cavium-specific property.
+	 */
+	if (!(slot->mmc->caps & (MMC_CAP_8_BIT_DATA | MMC_CAP_4_BIT_DATA))) {
+		/* Try legacy "cavium,bus-max-width" property. */
+		ret = of_property_read_u32(dev->of_node, "cavium,bus-max-width",
+					   &bus_width);
+		if (ret) {
+			/* No bus width specified, use default. */
+			bus_width = 8;
+			dev_info(dev, "Default width 8 used for slot %u\n", id);
+		}
+	} else {
+		/* Hosts capable of 8-bit transfers can also do 4 bits */
+		bus_width = (slot->mmc->caps & MMC_CAP_8_BIT_DATA) ? 8 : 4;
+	}
+
+	switch (bus_width) {
+	case 8:
+		slot->bus_width = (MMC_BUS_WIDTH_8 - 1);
+		slot->mmc->caps = MMC_CAP_8_BIT_DATA | MMC_CAP_4_BIT_DATA;
+		break;
+	case 4:
+		slot->bus_width = (MMC_BUS_WIDTH_4 - 1);
+		slot->mmc->caps = MMC_CAP_4_BIT_DATA;
+		break;
+	case 1:
+		slot->bus_width = MMC_BUS_WIDTH_1;
+		break;
+	default:
+		dev_err(dev, "Invalid bus width for slot %u\n", id);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static void set_frequency(struct device *dev, struct mmc_host *mmc, u32 id)
+{
+	int ret;
+
+	/*
+	 * The "spi-max-frequency" property is DEPRECATED and should
+	 * not be used. We handle it here to support older firmware.
+	 * Going forward, the standard "max-frequency" property is
+	 * used instead of the Cavium-specific property.
+	 */
+	if (mmc->f_max == 0) {
+		/* Try legacy "spi-max-frequency" property. */
+		ret = of_property_read_u32(dev->of_node, "spi-max-frequency",
+					   &mmc->f_max);
+		if (ret) {
+			/* No frequency properties found, use default. */
+			mmc->f_max = 52000000;
+			dev_info(dev, "Default %u frequency used for slot %u\n",
+				 mmc->f_max, id);
+		}
+	} else if (mmc->f_max > 52000000)
+		mmc->f_max = 52000000;
+
+	/* Set minimum frequency */
+	mmc->f_min = 400000;
+}
+
+int cvm_mmc_slot_probe(struct device *dev, struct cvm_mmc_host *host)
+{
+	struct device_node *node = dev->of_node;
+	u32 id, cmd_skew, dat_skew;
+	struct cvm_mmc_slot *slot;
+	struct mmc_host *mmc;
+	u64 clock_period;
+	int ret;
+
+	ret = of_property_read_u32(node, "reg", &id);
+	if (ret) {
+		dev_err(dev, "Missing or invalid reg property on %s\n",
+			of_node_full_name(node));
+		return ret;
+	}
+
+	if (id >= CAVIUM_MAX_MMC || host->slot[id]) {
+		dev_err(dev, "Invalid reg property on %s\n",
+			of_node_full_name(node));
+		return -EINVAL;
+	}
+
+	mmc = mmc_alloc_host(sizeof(struct cvm_mmc_slot), dev);
+	if (!mmc)
+		return -ENOMEM;
+
+	slot = mmc_priv(mmc);
+	slot->mmc = mmc;
+	slot->host = host;
+
+	ret = mmc_of_parse(mmc);
+	if (ret)
+		goto err;
+
+	ret = set_bus_width(dev, slot, id);
+	if (ret)
+		goto err;
+
+	set_frequency(dev, mmc, id);
+
+	/* Octeon-specific DT properties. */
+	ret = of_property_read_u32(node, "cavium,cmd-clk-skew", &cmd_skew);
+	if (ret)
+		cmd_skew = 0;
+	ret = of_property_read_u32(node, "cavium,dat-clk-skew", &dat_skew);
+	if (ret)
+		dat_skew = 0;
+
+	/*
+	 * We only have a 3.3v supply, so we are calling this mostly
+	 * to get a sane OCR mask for other parts of the MMC subsytem.
+	 */
+	ret = mmc_of_parse_voltage(node, &mmc->ocr_avail);
+	if (ret == -EINVAL)
+		goto err;
+
+	/*
+	 * We do not have a voltage regulator, just a single
+	 * GPIO line to control power to all of the slots. It
+	 * is registered in the platform code. We can, however,
+	 * still set the POWER_OFF capability as long as the
+	 * GPIO was registered correctly.
+	 */
+	if (!IS_ERR(host->global_pwr_gpiod)) {
+		mmc->caps |= MMC_CAP_POWER_OFF_CARD;
+		dev_info(dev, "Got global power GPIO\n");
+	} else
+		dev_info(dev, "Did not get global power GPIO\n");
+
+	/* Set up host parameters */
+	mmc->ops = &cvm_mmc_ops;
+
+	mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED |
+		     MMC_CAP_ERASE | MMC_CAP_CMD23;
+
+	mmc->max_segs = 1;
+
+	/* DMA size field can address up to 8 MB */
+	mmc->max_seg_size = 8 * 1024 * 1024;
+	mmc->max_req_size = mmc->max_seg_size;
+	/* External DMA is in 512 byte blocks */
+	mmc->max_blk_size = 512;
+	/* DMA block count field is 15 bits */
+	mmc->max_blk_count = 32767;
+
+	slot->clock = mmc->f_min;
+	slot->sclock = host->sys_freq;
+
+	/* Period in picoseconds. */
+	clock_period = 1000000000000ull / slot->sclock;
+	slot->cmd_cnt = (cmd_skew + clock_period / 2) / clock_period;
+	slot->dat_cnt = (dat_skew + clock_period / 2) / clock_period;
+
+	slot->bus_id = id;
+	slot->cached_rca = 1;
+
+	host->acquire_bus(host);
+	host->slot[id] = slot;
+	cvm_mmc_switch_to(slot);
+	cvm_mmc_init_lowlevel(slot);
+	host->release_bus(host);
+
+	ret = mmc_add_host(mmc);
+	if (ret) {
+		dev_err(dev, "mmc_add_host() returned %d\n", ret);
+		goto err;
+	}
+
+	return 0;
+
+err:
+	slot->host->slot[id] = NULL;
+
+	gpiod_set_value_cansleep(host->global_pwr_gpiod, 0);
+
+	mmc_free_host(slot->mmc);
+	return ret;
+}
+
+int cvm_mmc_slot_remove(struct cvm_mmc_slot *slot)
+{
+	mmc_remove_host(slot->mmc);
+	slot->host->slot[slot->bus_id] = NULL;
+	gpiod_set_value_cansleep(slot->host->global_pwr_gpiod, 0);
+	mmc_free_host(slot->mmc);
+
+	return 0;
+}
diff --git a/drivers/mmc/host/cavium_mmc.h b/drivers/mmc/host/cavium_mmc.h
new file mode 100644
index 0000000..27fb02b
--- /dev/null
+++ b/drivers/mmc/host/cavium_mmc.h
@@ -0,0 +1,303 @@
+/*
+ * Driver for MMC and SSD cards for Cavium OCTEON and ThunderX SOCs.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2012-2016 Cavium Inc.
+ */
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/mmc/host.h>
+#include <linux/of.h>
+#include <linux/scatterlist.h>
+#include <linux/semaphore.h>
+
+#define CAVIUM_MAX_MMC		4
+
+struct cvm_mmc_host {
+	struct device *dev;
+	void __iomem *base;
+	void __iomem *dma_base;
+	u64 emm_cfg;
+	int last_slot;
+	struct clk *clk;
+	int sys_freq;
+
+	struct mmc_request *current_req;
+	struct sg_mapping_iter smi;
+	bool dma_active;
+
+	struct gpio_desc *global_pwr_gpiod;
+
+	struct cvm_mmc_slot *slot[CAVIUM_MAX_MMC];
+
+	void (*acquire_bus)(struct cvm_mmc_host *);
+	void (*release_bus)(struct cvm_mmc_host *);
+	void (*int_enable)(struct cvm_mmc_host *, u64);
+};
+
+struct cvm_mmc_slot {
+	struct mmc_host *mmc;		/* slot-level mmc_core object */
+	struct cvm_mmc_host *host;	/* common hw for all slots */
+
+	u64 clock;
+	unsigned int sclock;
+
+	u64 cached_switch;
+	u64 cached_rca;
+
+	unsigned int cmd_cnt;		/* sample delay */
+	unsigned int dat_cnt;		/* sample delay */
+
+	int bus_width;
+	int bus_id;
+};
+
+struct cvm_mmc_cr_type {
+	u8 ctype;
+	u8 rtype;
+};
+
+struct cvm_mmc_cr_mods {
+	u8 ctype_xor;
+	u8 rtype_xor;
+};
+
+/* Bitfield definitions */
+
+union mio_emm_cmd {
+	u64 val;
+	struct mio_emm_cmd_s {
+#ifdef __BIG_ENDIAN_BITFIELD
+		u64 :2;
+		u64 bus_id:2;
+		u64 cmd_val:1;
+		u64 :3;
+		u64 dbuf:1;
+		u64 offset:6;
+		u64 :6;
+		u64 ctype_xor:2;
+		u64 rtype_xor:3;
+		u64 cmd_idx:6;
+		u64 arg:32;
+#else
+		u64 arg:32;
+		u64 cmd_idx:6;
+		u64 rtype_xor:3;
+		u64 ctype_xor:2;
+		u64 :6;
+		u64 offset:6;
+		u64 dbuf:1;
+		u64 :3;
+		u64 cmd_val:1;
+		u64 bus_id:2;
+		u64 :2;
+#endif
+	} s;
+};
+
+union mio_emm_dma {
+	u64 val;
+	struct mio_emm_dma_s {
+#ifdef __BIG_ENDIAN_BITFIELD
+		u64 :2;
+		u64 bus_id:2;
+		u64 dma_val:1;
+		u64 sector:1;
+		u64 dat_null:1;
+		u64 thres:6;
+		u64 rel_wr:1;
+		u64 rw:1;
+		u64 multi:1;
+		u64 block_cnt:16;
+		u64 card_addr:32;
+#else
+		u64 card_addr:32;
+		u64 block_cnt:16;
+		u64 multi:1;
+		u64 rw:1;
+		u64 rel_wr:1;
+		u64 thres:6;
+		u64 dat_null:1;
+		u64 sector:1;
+		u64 dma_val:1;
+		u64 bus_id:2;
+		u64 :2;
+#endif
+	} s;
+};
+
+union mio_emm_dma_cfg {
+	u64 val;
+	struct mio_emm_dma_cfg_s {
+#ifdef __BIG_ENDIAN_BITFIELD
+		u64 en:1;
+		u64 rw:1;
+		u64 clr:1;
+		u64 :1;
+		u64 swap32:1;
+		u64 swap16:1;
+		u64 swap8:1;
+		u64 endian:1;
+		u64 size:20;
+		u64 adr:36;
+#else
+		u64 adr:36;
+		u64 size:20;
+		u64 endian:1;
+		u64 swap8:1;
+		u64 swap16:1;
+		u64 swap32:1;
+		u64 :1;
+		u64 clr:1;
+		u64 rw:1;
+		u64 en:1;
+#endif
+	} s;
+};
+
+union mio_emm_int {
+	u64 val;
+	struct mio_emm_int_s {
+#ifdef __BIG_ENDIAN_BITFIELD
+		u64 :57;
+		u64 switch_err:1;
+		u64 switch_done:1;
+		u64 dma_err:1;
+		u64 cmd_err:1;
+		u64 dma_done:1;
+		u64 cmd_done:1;
+		u64 buf_done:1;
+#else
+		u64 buf_done:1;
+		u64 cmd_done:1;
+		u64 dma_done:1;
+		u64 cmd_err:1;
+		u64 dma_err:1;
+		u64 switch_done:1;
+		u64 switch_err:1;
+		u64 :57;
+#endif
+	} s;
+};
+
+union mio_emm_rsp_sts {
+	u64 val;
+	struct mio_emm_rsp_sts_s {
+#ifdef __BIG_ENDIAN_BITFIELD
+		u64 :2;
+		u64 bus_id:2;
+		u64 cmd_val:1;
+		u64 switch_val:1;
+		u64 dma_val:1;
+		u64 dma_pend:1;
+		u64 :27;
+		u64 dbuf_err:1;
+		u64 :4;
+		u64 dbuf:1;
+		u64 blk_timeout:1;
+		u64 blk_crc_err:1;
+		u64 rsp_busybit:1;
+		u64 stp_timeout:1;
+		u64 stp_crc_err:1;
+		u64 stp_bad_sts:1;
+		u64 stp_val:1;
+		u64 rsp_timeout:1;
+		u64 rsp_crc_err:1;
+		u64 rsp_bad_sts:1;
+		u64 rsp_val:1;
+		u64 rsp_type:3;
+		u64 cmd_type:2;
+		u64 cmd_idx:6;
+		u64 cmd_done:1;
+#else
+		u64 cmd_done:1;
+		u64 cmd_idx:6;
+		u64 cmd_type:2;
+		u64 rsp_type:3;
+		u64 rsp_val:1;
+		u64 rsp_bad_sts:1;
+		u64 rsp_crc_err:1;
+		u64 rsp_timeout:1;
+		u64 stp_val:1;
+		u64 stp_bad_sts:1;
+		u64 stp_crc_err:1;
+		u64 stp_timeout:1;
+		u64 rsp_busybit:1;
+		u64 blk_crc_err:1;
+		u64 blk_timeout:1;
+		u64 dbuf:1;
+		u64 :4;
+		u64 dbuf_err:1;
+		u64 :27;
+		u64 dma_pend:1;
+		u64 dma_val:1;
+		u64 switch_val:1;
+		u64 cmd_val:1;
+		u64 bus_id:2;
+		u64 :2;
+#endif
+	} s;
+};
+
+union mio_emm_sample {
+	u64 val;
+	struct mio_emm_sample_s {
+#ifdef __BIG_ENDIAN_BITFIELD
+		u64 :38;
+		u64 cmd_cnt:10;
+		u64 :6;
+		u64 dat_cnt:10;
+#else
+		u64 dat_cnt:10;
+		u64 :6;
+		u64 cmd_cnt:10;
+		u64 :38;
+#endif
+	} s;
+};
+
+union mio_emm_switch {
+	u64 val;
+	struct mio_emm_switch_s {
+#ifdef __BIG_ENDIAN_BITFIELD
+		u64 :2;
+		u64 bus_id:2;
+		u64 switch_exe:1;
+		u64 switch_err0:1;
+		u64 switch_err1:1;
+		u64 switch_err2:1;
+		u64 :7;
+		u64 hs_timing:1;
+		u64 :5;
+		u64 bus_width:3;
+		u64 :4;
+		u64 power_class:4;
+		u64 clk_hi:16;
+		u64 clk_lo:16;
+#else
+		u64 clk_lo:16;
+		u64 clk_hi:16;
+		u64 power_class:4;
+		u64 :4;
+		u64 bus_width:3;
+		u64 :5;
+		u64 hs_timing:1;
+		u64 :7;
+		u64 switch_err2:1;
+		u64 switch_err1:1;
+		u64 switch_err0:1;
+		u64 switch_exe:1;
+		u64 bus_id:2;
+		u64 :2;
+#endif
+	} s;
+};
+
+/* Protoypes */
+irqreturn_t cvm_mmc_interrupt(int irq, void *dev_id);
+int cvm_mmc_slot_probe(struct device *dev, struct cvm_mmc_host *host);
+int cvm_mmc_slot_remove(struct cvm_mmc_slot *slot);
+extern const struct mmc_host_ops cvm_mmc_ops;
-- 
2.9.0.rc0.21.g7777322

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH v10 2/8] mmc: octeon: Add MMC platform driver for Octeon SOCs
  2016-12-19 12:15 [PATCH v10 0/8] Cavium MMC driver Jan Glauber
  2016-12-19 12:15 ` [PATCH v10 1/8] mmc: cavium: Add core MMC driver for Cavium SOCs Jan Glauber
@ 2016-12-19 12:15 ` Jan Glauber
  2016-12-19 12:15 ` [PATCH v10 3/8] mmc: octeon: Work-around hardware bug on cn6xxx and cnf7xxx Jan Glauber
                   ` (6 subsequent siblings)
  8 siblings, 0 replies; 20+ messages in thread
From: Jan Glauber @ 2016-12-19 12:15 UTC (permalink / raw)
  To: Ulf Hansson
  Cc: linux-mmc, linux-kernel, David Daney, Steven J . Hill, Jan Glauber

Add a platform driver for Octeon MIPS SOCs.

Signed-off-by: Jan Glauber <jglauber@cavium.com>
---
 drivers/mmc/host/Kconfig              |  10 ++
 drivers/mmc/host/Makefile             |   2 +
 drivers/mmc/host/cavium_mmc.h         |  19 ++++
 drivers/mmc/host/octeon_platdrv_mmc.c | 183 ++++++++++++++++++++++++++++++++++
 4 files changed, 214 insertions(+)
 create mode 100644 drivers/mmc/host/octeon_platdrv_mmc.c

diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index 5274f50..6f22e16 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -343,6 +343,16 @@ config MMC_SDHCI_ST
 	  If you have a controller with this interface, say Y or M here.
 	  If unsure, say N.
 
+config MMC_OCTEON
+	tristate "Cavium OCTEON SD/MMC Card Interface support"
+	depends on CAVIUM_OCTEON_SOC
+	help
+	  This selects Cavium OCTEON SD/MMC card Interface.
+	  If you have an OCTEON board with a Multimedia Card slot,
+	  say Y or M here.
+
+	  If unsure, say N.
+
 config MMC_OMAP
 	tristate "TI OMAP Multimedia Card Interface support"
 	depends on ARCH_OMAP
diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile
index e2bdaaf..6e57e11 100644
--- a/drivers/mmc/host/Makefile
+++ b/drivers/mmc/host/Makefile
@@ -21,6 +21,8 @@ obj-$(CONFIG_MMC_SDHCI_SPEAR)	+= sdhci-spear.o
 obj-$(CONFIG_MMC_WBSD)		+= wbsd.o
 obj-$(CONFIG_MMC_AU1X)		+= au1xmmc.o
 obj-$(CONFIG_MMC_MTK)		+= mtk-sd.o
+octeon_mmc-objs := cavium_core_mmc.o octeon_platdrv_mmc.o
+obj-$(CONFIG_MMC_OCTEON)	+= octeon_mmc.o
 obj-$(CONFIG_MMC_OMAP)		+= omap.o
 obj-$(CONFIG_MMC_OMAP_HS)	+= omap_hsmmc.o
 obj-$(CONFIG_MMC_ATMELMCI)	+= atmel-mci.o
diff --git a/drivers/mmc/host/cavium_mmc.h b/drivers/mmc/host/cavium_mmc.h
index 27fb02b..e900dd1 100644
--- a/drivers/mmc/host/cavium_mmc.h
+++ b/drivers/mmc/host/cavium_mmc.h
@@ -16,6 +16,25 @@
 
 #define CAVIUM_MAX_MMC		4
 
+#define MIO_EMM_DMA_CFG		0x00
+#define MIO_EMM_DMA_ADR		0x08
+
+#define MIO_EMM_CFG		0x00
+#define MIO_EMM_SWITCH		0x48
+#define MIO_EMM_DMA		0x50
+#define MIO_EMM_CMD		0x58
+#define MIO_EMM_RSP_STS		0x60
+#define MIO_EMM_RSP_LO		0x68
+#define MIO_EMM_RSP_HI		0x70
+#define MIO_EMM_INT		0x78
+#define MIO_EMM_INT_EN		0x80
+#define MIO_EMM_WDOG		0x88
+#define MIO_EMM_SAMPLE		0x90
+#define MIO_EMM_STS_MASK	0x98
+#define MIO_EMM_RCA		0xa0
+#define MIO_EMM_BUF_IDX		0xe0
+#define MIO_EMM_BUF_DAT		0xe8
+
 struct cvm_mmc_host {
 	struct device *dev;
 	void __iomem *base;
diff --git a/drivers/mmc/host/octeon_platdrv_mmc.c b/drivers/mmc/host/octeon_platdrv_mmc.c
new file mode 100644
index 0000000..f3f6581
--- /dev/null
+++ b/drivers/mmc/host/octeon_platdrv_mmc.c
@@ -0,0 +1,183 @@
+/*
+ * Driver for MMC and SSD cards for Cavium OCTEON SOCs.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2012-2016 Cavium Inc.
+ */
+#include <linux/gpio/consumer.h>
+#include <linux/interrupt.h>
+#include <linux/mmc/mmc.h>
+#include <linux/mmc/slot-gpio.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <asm/octeon/octeon.h>
+#include "cavium_mmc.h"
+
+#define DRV_NAME "octeon_mmc"
+
+#define CVMX_MIO_BOOT_CTL CVMX_ADD_IO_SEG(0x00011800000000D0ull)
+
+static void octeon_mmc_acquire_bus(struct cvm_mmc_host *host)
+{
+	/* Switch the MMC controller onto the bus. */
+	down(&octeon_bootbus_sem);
+	writeq(0, (void __iomem *)CVMX_MIO_BOOT_CTL);
+}
+
+static void octeon_mmc_release_bus(struct cvm_mmc_host *host)
+{
+	up(&octeon_bootbus_sem);
+}
+
+static void octeon_mmc_int_enable(struct cvm_mmc_host *host, u64 val)
+{
+	writeq(val, host->base + MIO_EMM_INT);
+	writeq(val, host->base + MIO_EMM_INT_EN);
+}
+
+static int octeon_mmc_probe(struct platform_device *pdev)
+{
+	struct device_node *cn, *node = pdev->dev.of_node;
+	struct cvm_mmc_host *host;
+	struct resource	*res;
+	void __iomem *base;
+	int mmc_irq[9];
+	int i, ret = 0;
+	u64 val;
+
+	host = devm_kzalloc(&pdev->dev, sizeof(*host), GFP_KERNEL);
+	if (!host)
+		return -ENOMEM;
+
+	host->dev = &pdev->dev;
+	host->acquire_bus = octeon_mmc_acquire_bus;
+	host->release_bus = octeon_mmc_release_bus;
+	host->int_enable = octeon_mmc_int_enable;
+
+	host->sys_freq = octeon_get_io_clock_rate();
+
+	/* First one is EMM second DMA */
+	for (i = 0; i < 2; i++) {
+		mmc_irq[i] = platform_get_irq(pdev, i);
+		if (mmc_irq[i] < 0)
+			return mmc_irq[i];
+	}
+	host->last_slot = -1;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		dev_err(&pdev->dev, "Platform resource[0] is missing\n");
+		return -ENXIO;
+	}
+	base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(base))
+		return PTR_ERR(base);
+	host->base = (void __iomem *)base;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	if (!res) {
+		dev_err(&pdev->dev, "Platform resource[1] is missing\n");
+		return -EINVAL;
+	}
+	base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(base))
+		return PTR_ERR(base);
+	host->dma_base = (void __iomem *)base;
+
+	/*
+	 * Clear out any pending interrupts that may be left over from
+	 * bootloader.
+	 */
+	val = readq(host->base + MIO_EMM_INT);
+	writeq(val, host->base + MIO_EMM_INT);
+
+	ret = devm_request_irq(&pdev->dev, mmc_irq[0],
+			       cvm_mmc_interrupt, 0, DRV_NAME, host);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "Error: devm_request_irq %d\n",
+			mmc_irq[0]);
+		return ret;
+	}
+
+	host->global_pwr_gpiod = devm_gpiod_get_optional(&pdev->dev, "power",
+							 GPIOD_OUT_HIGH);
+	if (IS_ERR(host->global_pwr_gpiod)) {
+		dev_err(&pdev->dev, "Invalid power GPIO\n");
+		return PTR_ERR(host->global_pwr_gpiod);
+	}
+
+	platform_set_drvdata(pdev, host);
+
+	for_each_child_of_node(node, cn) {
+		struct platform_device *slot_pdev;
+
+		slot_pdev = of_platform_device_create(cn, NULL, &pdev->dev);
+		ret = cvm_mmc_slot_probe(&slot_pdev->dev, host);
+		if (ret) {
+			dev_err(&pdev->dev, "Error populating slots\n");
+			gpiod_set_value_cansleep(host->global_pwr_gpiod, 0);
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static int octeon_mmc_remove(struct platform_device *pdev)
+{
+	union mio_emm_dma_cfg dma_cfg;
+	struct cvm_mmc_host *host = platform_get_drvdata(pdev);
+	int i;
+
+	for (i = 0; i < CAVIUM_MAX_MMC; i++)
+		if (host->slot[i])
+			cvm_mmc_slot_remove(host->slot[i]);
+
+	dma_cfg.val = readq(host->dma_base + MIO_EMM_DMA_CFG);
+	dma_cfg.s.en = 0;
+	writeq(dma_cfg.val, host->dma_base + MIO_EMM_DMA_CFG);
+
+	gpiod_set_value_cansleep(host->global_pwr_gpiod, 0);
+
+	return 0;
+}
+
+static const struct of_device_id octeon_mmc_match[] = {
+	{
+		.compatible = "cavium,octeon-6130-mmc",
+	},
+	{
+		.compatible = "cavium,octeon-7890-mmc",
+	},
+	{},
+};
+MODULE_DEVICE_TABLE(of, octeon_mmc_match);
+
+static struct platform_driver octeon_mmc_driver = {
+	.probe		= octeon_mmc_probe,
+	.remove		= octeon_mmc_remove,
+	.driver		= {
+		.name	= DRV_NAME,
+		.of_match_table = octeon_mmc_match,
+	},
+};
+
+static int __init octeon_mmc_init(void)
+{
+	return platform_driver_register(&octeon_mmc_driver);
+}
+
+static void __exit octeon_mmc_cleanup(void)
+{
+	platform_driver_unregister(&octeon_mmc_driver);
+}
+
+module_init(octeon_mmc_init);
+module_exit(octeon_mmc_cleanup);
+
+MODULE_AUTHOR("Cavium Inc. <support@cavium.com>");
+MODULE_DESCRIPTION("Low-level driver for Cavium OCTEON MMC/SSD card");
+MODULE_LICENSE("GPL");
-- 
2.9.0.rc0.21.g7777322

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH v10 3/8] mmc: octeon: Work-around hardware bug on cn6xxx and cnf7xxx
  2016-12-19 12:15 [PATCH v10 0/8] Cavium MMC driver Jan Glauber
  2016-12-19 12:15 ` [PATCH v10 1/8] mmc: cavium: Add core MMC driver for Cavium SOCs Jan Glauber
  2016-12-19 12:15 ` [PATCH v10 2/8] mmc: octeon: Add MMC platform driver for Octeon SOCs Jan Glauber
@ 2016-12-19 12:15 ` Jan Glauber
  2016-12-19 12:15 ` [PATCH v10 4/8] mmc: octeon: Add support for Octeon cn7890 Jan Glauber
                   ` (5 subsequent siblings)
  8 siblings, 0 replies; 20+ messages in thread
From: Jan Glauber @ 2016-12-19 12:15 UTC (permalink / raw)
  To: Ulf Hansson
  Cc: linux-mmc, linux-kernel, David Daney, Steven J . Hill, Jan Glauber

Prevent data corruption on cn6xxx and cnf7xxx.
Due to an imperfection in the design of the MMC bus hardware,
the 2nd to last cache block of a DMA read must be locked into the L2
cache.

Signed-off-by: Jan Glauber <jglauber@cavium.com>
---
 arch/mips/cavium-octeon/Makefile      |  1 +
 arch/mips/cavium-octeon/octeon-mmc.c  | 98 +++++++++++++++++++++++++++++++++++
 drivers/mmc/host/cavium_core_mmc.c    |  5 ++
 drivers/mmc/host/cavium_mmc.h         |  5 ++
 drivers/mmc/host/octeon_platdrv_mmc.c | 30 +++++++++++
 5 files changed, 139 insertions(+)
 create mode 100644 arch/mips/cavium-octeon/octeon-mmc.c

diff --git a/arch/mips/cavium-octeon/Makefile b/arch/mips/cavium-octeon/Makefile
index 2a59265..5f09d26 100644
--- a/arch/mips/cavium-octeon/Makefile
+++ b/arch/mips/cavium-octeon/Makefile
@@ -18,3 +18,4 @@ obj-y += crypto/
 obj-$(CONFIG_MTD)		      += flash_setup.o
 obj-$(CONFIG_SMP)		      += smp.o
 obj-$(CONFIG_OCTEON_ILM)	      += oct_ilm.o
+obj-$(CONFIG_MMC_OCTEON)	      += octeon-mmc.o
diff --git a/arch/mips/cavium-octeon/octeon-mmc.c b/arch/mips/cavium-octeon/octeon-mmc.c
new file mode 100644
index 0000000..6aaaf73
--- /dev/null
+++ b/arch/mips/cavium-octeon/octeon-mmc.c
@@ -0,0 +1,98 @@
+/*
+ * Driver for MMC and SSD cards for Cavium OCTEON SOCs.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2012-2016 Cavium Inc.
+ */
+#include <linux/export.h>
+#include <asm/octeon/octeon.h>
+
+/*
+ * The functions below are used for the EMMC-17978 workaround.
+ *
+ * Due to an imperfection in the design of the MMC bus hardware,
+ * the 2nd to last cache block of a DMA read must be locked into the L2 Cache.
+ * Otherwise, data corruption may occur.
+ */
+
+static inline void *phys_to_ptr(u64 address)
+{
+	return (void *)(address | (1ull << 63)); /* XKPHYS */
+}
+
+/**
+ * Lock a single line into L2. The line is zeroed before locking
+ * to make sure no dram accesses are made.
+ *
+ * @addr   Physical address to lock
+ */
+static void l2c_lock_line(u64 addr)
+{
+	char *addr_ptr = phys_to_ptr(addr);
+
+	asm volatile (
+		"cache 31, %[line]"	/* Unlock the line */
+		:: [line] "m" (*addr_ptr));
+}
+
+/**
+ * Unlock a single line in the L2 cache.
+ *
+ * @addr	Physical address to unlock
+ *
+ * Return Zero on success
+ */
+static void l2c_unlock_line(u64 addr)
+{
+	char *addr_ptr = phys_to_ptr(addr);
+
+	asm volatile (
+		"cache 23, %[line]"	/* Unlock the line */
+		:: [line] "m" (*addr_ptr));
+}
+
+/**
+ * Locks a memory region in the L2 cache
+ *
+ * @start - start address to begin locking
+ * @len - length in bytes to lock
+ */
+void l2c_lock_mem_region(u64 start, u64 len)
+{
+	u64 end;
+
+	/* Round start/end to cache line boundaries */
+	end = ALIGN(start + len - 1, CVMX_CACHE_LINE_SIZE);
+	start = ALIGN(start, CVMX_CACHE_LINE_SIZE);
+
+	while (start <= end) {
+		l2c_lock_line(start);
+		start += CVMX_CACHE_LINE_SIZE;
+	}
+	asm volatile("sync");
+}
+EXPORT_SYMBOL_GPL(l2c_lock_mem_region);
+
+/**
+ * Unlock a memory region in the L2 cache
+ *
+ * @start - start address to unlock
+ * @len - length to unlock in bytes
+ */
+void l2c_unlock_mem_region(u64 start, u64 len)
+{
+	u64 end;
+
+	/* Round start/end to cache line boundaries */
+	end = ALIGN(start + len - 1, CVMX_CACHE_LINE_SIZE);
+	start = ALIGN(start, CVMX_CACHE_LINE_SIZE);
+
+	while (start <= end) {
+		l2c_unlock_line(start);
+		start += CVMX_CACHE_LINE_SIZE;
+	}
+}
+EXPORT_SYMBOL_GPL(l2c_unlock_mem_region);
diff --git a/drivers/mmc/host/cavium_core_mmc.c b/drivers/mmc/host/cavium_core_mmc.c
index 89d23d3..1bdba06 100644
--- a/drivers/mmc/host/cavium_core_mmc.c
+++ b/drivers/mmc/host/cavium_core_mmc.c
@@ -438,6 +438,8 @@ irqreturn_t cvm_mmc_interrupt(int irq, void *dev_id)
 	req->done(req);
 
 no_req_done:
+	if (host->dmar_fixup_done)
+		host->dmar_fixup_done(host);
 	if (host_done)
 		host->release_bus(host);
 out:
@@ -558,6 +560,9 @@ static void cvm_mmc_dma_request(struct mmc_host *mmc,
 	host->dma_active = true;
 	host->int_enable(host, emm_int.val);
 
+	if (host->dmar_fixup)
+		host->dmar_fixup(host, mrq->cmd, data, addr);
+
 	/*
 	 * If we have a valid SD card in the slot, we set the response
 	 * bit mask to check for CRC errors and timeouts only.
diff --git a/drivers/mmc/host/cavium_mmc.h b/drivers/mmc/host/cavium_mmc.h
index e900dd1..f350212 100644
--- a/drivers/mmc/host/cavium_mmc.h
+++ b/drivers/mmc/host/cavium_mmc.h
@@ -40,6 +40,7 @@ struct cvm_mmc_host {
 	void __iomem *base;
 	void __iomem *dma_base;
 	u64 emm_cfg;
+	u64 n_minus_one;	/* OCTEON II workaround location */
 	int last_slot;
 	struct clk *clk;
 	int sys_freq;
@@ -55,6 +56,10 @@ struct cvm_mmc_host {
 	void (*acquire_bus)(struct cvm_mmc_host *);
 	void (*release_bus)(struct cvm_mmc_host *);
 	void (*int_enable)(struct cvm_mmc_host *, u64);
+	/* required on some MIPS models */
+	void (*dmar_fixup)(struct cvm_mmc_host *, struct mmc_command *,
+			   struct mmc_data *, u64);
+	void (*dmar_fixup_done)(struct cvm_mmc_host *);
 };
 
 struct cvm_mmc_slot {
diff --git a/drivers/mmc/host/octeon_platdrv_mmc.c b/drivers/mmc/host/octeon_platdrv_mmc.c
index f3f6581..59b73fb 100644
--- a/drivers/mmc/host/octeon_platdrv_mmc.c
+++ b/drivers/mmc/host/octeon_platdrv_mmc.c
@@ -20,6 +20,9 @@
 
 #define CVMX_MIO_BOOT_CTL CVMX_ADD_IO_SEG(0x00011800000000D0ull)
 
+extern void l2c_lock_mem_region(u64 start, u64 len);
+extern void l2c_unlock_mem_region(u64 start, u64 len);
+
 static void octeon_mmc_acquire_bus(struct cvm_mmc_host *host)
 {
 	/* Switch the MMC controller onto the bus. */
@@ -38,6 +41,28 @@ static void octeon_mmc_int_enable(struct cvm_mmc_host *host, u64 val)
 	writeq(val, host->base + MIO_EMM_INT_EN);
 }
 
+static void octeon_mmc_dmar_fixup(struct cvm_mmc_host *host,
+				  struct mmc_command *cmd,
+				  struct mmc_data *data,
+				  u64 addr)
+{
+	if (cmd->opcode != MMC_WRITE_MULTIPLE_BLOCK)
+		return;
+	if (data->blksz * data->blocks <= 1024)
+		return;
+
+	host->n_minus_one = addr + (data->blksz * data->blocks) - 1024;
+	l2c_lock_mem_region(host->n_minus_one, 512);
+}
+
+static void octeon_mmc_dmar_fixup_done(struct cvm_mmc_host *host)
+{
+	if (!host->n_minus_one)
+		return;
+	l2c_unlock_mem_region(host->n_minus_one, 512);
+	host->n_minus_one = 0;
+}
+
 static int octeon_mmc_probe(struct platform_device *pdev)
 {
 	struct device_node *cn, *node = pdev->dev.of_node;
@@ -56,6 +81,11 @@ static int octeon_mmc_probe(struct platform_device *pdev)
 	host->acquire_bus = octeon_mmc_acquire_bus;
 	host->release_bus = octeon_mmc_release_bus;
 	host->int_enable = octeon_mmc_int_enable;
+	if (OCTEON_IS_MODEL(OCTEON_CN6XXX) ||
+	    OCTEON_IS_MODEL(OCTEON_CNF7XXX)) {
+		host->dmar_fixup = octeon_mmc_dmar_fixup;
+		host->dmar_fixup_done = octeon_mmc_dmar_fixup_done;
+	}
 
 	host->sys_freq = octeon_get_io_clock_rate();
 
-- 
2.9.0.rc0.21.g7777322

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH v10 4/8] mmc: octeon: Add support for Octeon cn7890
  2016-12-19 12:15 [PATCH v10 0/8] Cavium MMC driver Jan Glauber
                   ` (2 preceding siblings ...)
  2016-12-19 12:15 ` [PATCH v10 3/8] mmc: octeon: Work-around hardware bug on cn6xxx and cnf7xxx Jan Glauber
@ 2016-12-19 12:15 ` Jan Glauber
  2016-12-19 12:15 ` [PATCH v10 5/8] mmc: thunderx: Add MMC PCI driver for ThunderX SOCs Jan Glauber
                   ` (4 subsequent siblings)
  8 siblings, 0 replies; 20+ messages in thread
From: Jan Glauber @ 2016-12-19 12:15 UTC (permalink / raw)
  To: Ulf Hansson
  Cc: linux-mmc, linux-kernel, David Daney, Steven J . Hill, Jan Glauber

The MMC unit on Octeon cn7890 differs in that it has multiple
interrupts. Requires a lock for the interrupt handler. DMA addresses
have a dedicated 64 bit register now, so use that when available.

Signed-off-by: Jan Glauber <jglauber@cavium.com>
---
 drivers/mmc/host/cavium_core_mmc.c    | 16 ++++++-
 drivers/mmc/host/cavium_mmc.h         |  6 +++
 drivers/mmc/host/octeon_platdrv_mmc.c | 79 ++++++++++++++++++++++++++++-------
 3 files changed, 84 insertions(+), 17 deletions(-)

diff --git a/drivers/mmc/host/cavium_core_mmc.c b/drivers/mmc/host/cavium_core_mmc.c
index 1bdba06..596505a 100644
--- a/drivers/mmc/host/cavium_core_mmc.c
+++ b/drivers/mmc/host/cavium_core_mmc.c
@@ -384,8 +384,14 @@ irqreturn_t cvm_mmc_interrupt(int irq, void *dev_id)
 	union mio_emm_rsp_sts rsp_sts;
 	union mio_emm_int emm_int;
 	struct mmc_request *req;
+	unsigned long flags = 0;
 	bool host_done;
 
+	if (host->need_irq_handler_lock)
+		spin_lock_irqsave(&host->irq_handler_lock, flags);
+	else
+		__acquire(&host->irq_handler_lock);
+
 	/* Clear interrupt bits (write 1 clears ). */
 	emm_int.val = readq(host->base + MIO_EMM_INT);
 	writeq(emm_int.val, host->base + MIO_EMM_INT);
@@ -443,6 +449,10 @@ irqreturn_t cvm_mmc_interrupt(int irq, void *dev_id)
 	if (host_done)
 		host->release_bus(host);
 out:
+	if (host->need_irq_handler_lock)
+		spin_unlock_irqrestore(&host->irq_handler_lock, flags);
+	else
+		__release(&host->irq_handler_lock);
 	return IRQ_RETVAL(emm_int.val != 0);
 }
 
@@ -470,11 +480,15 @@ static u64 prepare_dma_single(struct cvm_mmc_host *host, struct mmc_data *data)
 	dma_cfg.s.size = (sg_dma_len(&data->sg[0]) / 8) - 1;
 
 	addr = sg_dma_address(&data->sg[0]);
-	dma_cfg.s.adr = addr;
+	if (!host->big_dma_addr)
+		dma_cfg.s.adr = addr;
 	writeq(dma_cfg.val, host->dma_base + MIO_EMM_DMA_CFG);
 
 	pr_debug("[%s] sg_dma_len: %u  total sg_elem: %d\n",
 		 (dma_cfg.s.rw) ? "W" : "R", sg_dma_len(&data->sg[0]), count);
+
+	if (host->big_dma_addr)
+		writeq(addr, host->dma_base + MIO_EMM_DMA_ADR);
 	return addr;
 }
 
diff --git a/drivers/mmc/host/cavium_mmc.h b/drivers/mmc/host/cavium_mmc.h
index f350212..5f41be9 100644
--- a/drivers/mmc/host/cavium_mmc.h
+++ b/drivers/mmc/host/cavium_mmc.h
@@ -49,6 +49,12 @@ struct cvm_mmc_host {
 	struct sg_mapping_iter smi;
 	bool dma_active;
 
+	bool has_ciu3;
+	bool big_dma_addr;
+	bool need_irq_handler_lock;
+	spinlock_t irq_handler_lock;
+	struct semaphore mmc_serializer;
+
 	struct gpio_desc *global_pwr_gpiod;
 
 	struct cvm_mmc_slot *slot[CAVIUM_MAX_MMC];
diff --git a/drivers/mmc/host/octeon_platdrv_mmc.c b/drivers/mmc/host/octeon_platdrv_mmc.c
index 59b73fb..c5dba81 100644
--- a/drivers/mmc/host/octeon_platdrv_mmc.c
+++ b/drivers/mmc/host/octeon_platdrv_mmc.c
@@ -25,20 +25,28 @@ extern void l2c_unlock_mem_region(u64 start, u64 len);
 
 static void octeon_mmc_acquire_bus(struct cvm_mmc_host *host)
 {
-	/* Switch the MMC controller onto the bus. */
-	down(&octeon_bootbus_sem);
-	writeq(0, (void __iomem *)CVMX_MIO_BOOT_CTL);
+	if (!host->has_ciu3) {
+		/* Switch the MMC controller onto the bus. */
+		down(&octeon_bootbus_sem);
+		writeq(0, (void __iomem *)CVMX_MIO_BOOT_CTL);
+	} else {
+		down(&host->mmc_serializer);
+	}
 }
 
 static void octeon_mmc_release_bus(struct cvm_mmc_host *host)
 {
-	up(&octeon_bootbus_sem);
+	if (!host->has_ciu3)
+		up(&octeon_bootbus_sem);
+	else
+		up(&host->mmc_serializer);
 }
 
 static void octeon_mmc_int_enable(struct cvm_mmc_host *host, u64 val)
 {
 	writeq(val, host->base + MIO_EMM_INT);
-	writeq(val, host->base + MIO_EMM_INT_EN);
+	if (!host->dma_active || (host->dma_active && !host->has_ciu3))
+		writeq(val, host->base + MIO_EMM_INT_EN);
 }
 
 static void octeon_mmc_dmar_fixup(struct cvm_mmc_host *host,
@@ -77,6 +85,9 @@ static int octeon_mmc_probe(struct platform_device *pdev)
 	if (!host)
 		return -ENOMEM;
 
+	spin_lock_init(&host->irq_handler_lock);
+	sema_init(&host->mmc_serializer, 1);
+
 	host->dev = &pdev->dev;
 	host->acquire_bus = octeon_mmc_acquire_bus;
 	host->release_bus = octeon_mmc_release_bus;
@@ -89,12 +100,34 @@ static int octeon_mmc_probe(struct platform_device *pdev)
 
 	host->sys_freq = octeon_get_io_clock_rate();
 
-	/* First one is EMM second DMA */
-	for (i = 0; i < 2; i++) {
-		mmc_irq[i] = platform_get_irq(pdev, i);
-		if (mmc_irq[i] < 0)
-			return mmc_irq[i];
+	if (of_device_is_compatible(node, "cavium,octeon-7890-mmc")) {
+		host->big_dma_addr = true;
+		host->need_irq_handler_lock = true;
+		host->has_ciu3 = true;
+		/*
+		 * First seven are the EMM_INT bits 0..6, then two for
+		 * the EMM_DMA_INT bits
+		 */
+		for (i = 0; i < 9; i++) {
+			mmc_irq[i] = platform_get_irq(pdev, i);
+			if (mmc_irq[i] < 0)
+				return mmc_irq[i];
+
+			/* work around legacy u-boot device trees */
+			irq_set_irq_type(mmc_irq[i], IRQ_TYPE_EDGE_RISING);
+		}
+	} else {
+		host->big_dma_addr = false;
+		host->need_irq_handler_lock = false;
+		host->has_ciu3 = false;
+		/* First one is EMM second DMA */
+		for (i = 0; i < 2; i++) {
+			mmc_irq[i] = platform_get_irq(pdev, i);
+			if (mmc_irq[i] < 0)
+				return mmc_irq[i];
+		}
 	}
+
 	host->last_slot = -1;
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -124,12 +157,26 @@ static int octeon_mmc_probe(struct platform_device *pdev)
 	val = readq(host->base + MIO_EMM_INT);
 	writeq(val, host->base + MIO_EMM_INT);
 
-	ret = devm_request_irq(&pdev->dev, mmc_irq[0],
-			       cvm_mmc_interrupt, 0, DRV_NAME, host);
-	if (ret < 0) {
-		dev_err(&pdev->dev, "Error: devm_request_irq %d\n",
-			mmc_irq[0]);
-		return ret;
+	if (host->has_ciu3) {
+		/* Only CMD_DONE, DMA_DONE, CMD_ERR, DMA_ERR */
+		for (i = 1; i <= 4; i++) {
+			ret = devm_request_irq(&pdev->dev, mmc_irq[i],
+					       cvm_mmc_interrupt,
+					       0, DRV_NAME, host);
+			if (ret < 0) {
+				dev_err(&pdev->dev, "Error: devm_request_irq %d\n",
+					mmc_irq[i]);
+				return ret;
+			}
+		}
+	} else {
+		ret = devm_request_irq(&pdev->dev, mmc_irq[0],
+				       cvm_mmc_interrupt, 0, DRV_NAME, host);
+		if (ret < 0) {
+			dev_err(&pdev->dev, "Error: devm_request_irq %d\n",
+				mmc_irq[0]);
+			return ret;
+		}
 	}
 
 	host->global_pwr_gpiod = devm_gpiod_get_optional(&pdev->dev, "power",
-- 
2.9.0.rc0.21.g7777322

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH v10 5/8] mmc: thunderx: Add MMC PCI driver for ThunderX SOCs
  2016-12-19 12:15 [PATCH v10 0/8] Cavium MMC driver Jan Glauber
                   ` (3 preceding siblings ...)
  2016-12-19 12:15 ` [PATCH v10 4/8] mmc: octeon: Add support for Octeon cn7890 Jan Glauber
@ 2016-12-19 12:15 ` Jan Glauber
  2016-12-19 12:15 ` [PATCH v10 6/8] mmc: thunderx: Add scatter-gather DMA support Jan Glauber
                   ` (3 subsequent siblings)
  8 siblings, 0 replies; 20+ messages in thread
From: Jan Glauber @ 2016-12-19 12:15 UTC (permalink / raw)
  To: Ulf Hansson
  Cc: linux-mmc, linux-kernel, David Daney, Steven J . Hill, Jan Glauber

Add a platform driver for ThunderX ARM SOCs.

Signed-off-by: Jan Glauber <jglauber@cavium.com>
---
 drivers/mmc/host/Kconfig               |   9 ++
 drivers/mmc/host/Makefile              |   2 +
 drivers/mmc/host/cavium_mmc.h          |  38 ++++++
 drivers/mmc/host/thunderx_pcidrv_mmc.c | 214 +++++++++++++++++++++++++++++++++
 4 files changed, 263 insertions(+)
 create mode 100644 drivers/mmc/host/thunderx_pcidrv_mmc.c

diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index 6f22e16..38d7403 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -353,6 +353,15 @@ config MMC_OCTEON
 
 	  If unsure, say N.
 
+config MMC_THUNDERX
+	tristate "Cavium ThunderX SD/MMC Card Interface support"
+	depends on PCI && 64BIT && (ARM64 || COMPILE_TEST)
+	help
+	  This selects Cavium ThunderX SD/MMC Card Interface.
+	  If you have an Cavium ARM64 board with a Multimedia Card slot
+	  or builtin eMMC chip say Y or M here. If built as a module
+	  the module will be called thunderx_mmc.ko.
+
 config MMC_OMAP
 	tristate "TI OMAP Multimedia Card Interface support"
 	depends on ARCH_OMAP
diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile
index 6e57e11..488351f 100644
--- a/drivers/mmc/host/Makefile
+++ b/drivers/mmc/host/Makefile
@@ -23,6 +23,8 @@ obj-$(CONFIG_MMC_AU1X)		+= au1xmmc.o
 obj-$(CONFIG_MMC_MTK)		+= mtk-sd.o
 octeon_mmc-objs := cavium_core_mmc.o octeon_platdrv_mmc.o
 obj-$(CONFIG_MMC_OCTEON)	+= octeon_mmc.o
+thunderx_mmc-objs := cavium_core_mmc.o thunderx_pcidrv_mmc.o
+obj-$(CONFIG_MMC_THUNDERX)	+= thunderx_mmc.o
 obj-$(CONFIG_MMC_OMAP)		+= omap.o
 obj-$(CONFIG_MMC_OMAP_HS)	+= omap_hsmmc.o
 obj-$(CONFIG_MMC_ATMELMCI)	+= atmel-mci.o
diff --git a/drivers/mmc/host/cavium_mmc.h b/drivers/mmc/host/cavium_mmc.h
index 5f41be9..09fe6d9 100644
--- a/drivers/mmc/host/cavium_mmc.h
+++ b/drivers/mmc/host/cavium_mmc.h
@@ -11,11 +11,14 @@
 #include <linux/io.h>
 #include <linux/mmc/host.h>
 #include <linux/of.h>
+#include <linux/pci.h>
 #include <linux/scatterlist.h>
 #include <linux/semaphore.h>
 
 #define CAVIUM_MAX_MMC		4
 
+#if IS_ENABLED(CONFIG_OCTEON_MMC)
+
 #define MIO_EMM_DMA_CFG		0x00
 #define MIO_EMM_DMA_ADR		0x08
 
@@ -35,6 +38,36 @@
 #define MIO_EMM_BUF_IDX		0xe0
 #define MIO_EMM_BUF_DAT		0xe8
 
+#else /* CONFIG_THUNDERX_MMC */
+
+#define MIO_EMM_DMA_CFG		0x180
+#define MIO_EMM_DMA_ADR		0x188
+#define MIO_EMM_DMA_INT		0x190
+#define MIO_EMM_DMA_INT_W1S	0x198
+#define MIO_EMM_DMA_INT_ENA_W1S	0x1a0
+#define MIO_EMM_DMA_INT_ENA_W1C	0x1a8
+
+#define MIO_EMM_CFG		0x2000
+#define MIO_EMM_SWITCH		0x2048
+#define MIO_EMM_DMA		0x2050
+#define MIO_EMM_CMD		0x2058
+#define MIO_EMM_RSP_STS		0x2060
+#define MIO_EMM_RSP_LO		0x2068
+#define MIO_EMM_RSP_HI		0x2070
+#define MIO_EMM_INT		0x2078
+#define MIO_EMM_INT_EN		0x2080
+#define MIO_EMM_WDOG		0x2088
+#define MIO_EMM_SAMPLE		0x2090
+#define MIO_EMM_STS_MASK	0x2098
+#define MIO_EMM_RCA		0x20a0
+#define MIO_EMM_BUF_IDX		0x20e0
+#define MIO_EMM_BUF_DAT		0x20e8
+
+#define MIO_EMM_INT_EN_SET	0x20b0
+#define MIO_EMM_INT_EN_CLR	0x20b8
+
+#endif
+
 struct cvm_mmc_host {
 	struct device *dev;
 	void __iomem *base;
@@ -66,6 +99,11 @@ struct cvm_mmc_host {
 	void (*dmar_fixup)(struct cvm_mmc_host *, struct mmc_command *,
 			   struct mmc_data *, u64);
 	void (*dmar_fixup_done)(struct cvm_mmc_host *);
+
+#if IS_ENABLED(CONFIG_MMC_THUNDERX)
+	struct msix_entry	*mmc_msix;
+	unsigned int		msix_count;
+#endif
 };
 
 struct cvm_mmc_slot {
diff --git a/drivers/mmc/host/thunderx_pcidrv_mmc.c b/drivers/mmc/host/thunderx_pcidrv_mmc.c
new file mode 100644
index 0000000..04d03bf
--- /dev/null
+++ b/drivers/mmc/host/thunderx_pcidrv_mmc.c
@@ -0,0 +1,214 @@
+/*
+ * Driver for MMC and SSD cards for Cavium ThunderX SOCs.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2016 Cavium Inc.
+ */
+#include <linux/dma-mapping.h>
+#include <linux/gpio/consumer.h>
+#include <linux/interrupt.h>
+#include <linux/mmc/mmc.h>
+#include <linux/mmc/slot-gpio.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include "cavium_mmc.h"
+
+#define DRV_NAME "thunderx_mmc"
+
+static void thunder_mmc_acquire_bus(struct cvm_mmc_host *host)
+{
+	down(&host->mmc_serializer);
+}
+
+static void thunder_mmc_release_bus(struct cvm_mmc_host *host)
+{
+	up(&host->mmc_serializer);
+}
+
+static void thunder_mmc_int_enable(struct cvm_mmc_host *host, u64 val)
+{
+	writeq(val, host->base + MIO_EMM_INT);
+	writeq(val, host->base + MIO_EMM_INT_EN_SET);
+}
+
+static int thunder_mmc_register_interrupts(struct cvm_mmc_host *host,
+					   struct pci_dev *pdev)
+{
+	int ret, i;
+
+	host->msix_count = pci_msix_vec_count(pdev);
+	host->mmc_msix = devm_kzalloc(&pdev->dev,
+		(sizeof(struct msix_entry)) * host->msix_count, GFP_KERNEL);
+	if (!host->mmc_msix)
+		return -ENOMEM;
+
+	for (i = 0; i < host->msix_count; i++)
+		host->mmc_msix[i].entry = i;
+
+	ret = pci_enable_msix(pdev, host->mmc_msix, host->msix_count);
+	if (ret)
+		return ret;
+
+	/* register interrupts */
+	for (i = 0; i < host->msix_count; i++) {
+		ret = devm_request_irq(&pdev->dev, host->mmc_msix[i].vector,
+				       cvm_mmc_interrupt,
+				       0, DRV_NAME, host);
+		if (ret)
+			return ret;
+	}
+	return 0;
+}
+
+static int thunder_mmc_probe(struct pci_dev *pdev,
+			     const struct pci_device_id *id)
+{
+	struct device_node *node = pdev->dev.of_node;
+	struct device *dev = &pdev->dev;
+	struct device_node *child_node;
+	struct cvm_mmc_host *host;
+	int ret;
+
+	host = devm_kzalloc(dev, sizeof(*host), GFP_KERNEL);
+	if (!host)
+		return -ENOMEM;
+
+	pci_set_drvdata(pdev, host);
+	ret = pcim_enable_device(pdev);
+	if (ret)
+		return ret;
+
+	ret = pci_request_regions(pdev, DRV_NAME);
+	if (ret)
+		return ret;
+
+	host->base = pcim_iomap(pdev, 0, pci_resource_len(pdev, 0));
+	if (!host->base)
+		return -EINVAL;
+
+	/* On ThunderX these are identical */
+	host->dma_base = host->base;
+
+	host->clk = devm_clk_get(dev, NULL);
+	if (IS_ERR(host->clk))
+		return PTR_ERR(host->clk);
+
+	ret = clk_prepare_enable(host->clk);
+	if (ret)
+		return ret;
+	host->sys_freq = clk_get_rate(host->clk);
+
+	spin_lock_init(&host->irq_handler_lock);
+	sema_init(&host->mmc_serializer, 1);
+
+	host->dev = dev;
+	host->acquire_bus = thunder_mmc_acquire_bus;
+	host->release_bus = thunder_mmc_release_bus;
+	host->int_enable = thunder_mmc_int_enable;
+
+	host->big_dma_addr = true;
+	host->need_irq_handler_lock = true;
+	host->last_slot = -1;
+
+	ret = dma_set_mask(dev, DMA_BIT_MASK(48));
+	if (ret)
+		goto error;
+
+	/*
+	 * Clear out any pending interrupts that may be left over from
+	 * bootloader. Writing 1 to the bits clears them.
+	 */
+	writeq(127, host->base + MIO_EMM_INT_EN);
+	writeq(3, host->base + MIO_EMM_DMA_INT_ENA_W1C);
+
+	ret = thunder_mmc_register_interrupts(host, pdev);
+	if (ret)
+		goto error;
+
+	host->global_pwr_gpiod = devm_gpiod_get_optional(&pdev->dev, "power",
+							 GPIOD_OUT_LOW);
+	if (IS_ERR(host->global_pwr_gpiod)) {
+		ret = PTR_ERR(host->global_pwr_gpiod);
+		goto error;
+	}
+
+	for_each_child_of_node(node, child_node) {
+		/*
+		 * XXX hack: mmc_of_parse looks only at the current device's
+		 * DT node. That means we require one device per slot with
+		 * it's node pointing to the slot. The easiest way to get this
+		 * is using of_platform_device_create. Not sure what a proper
+		 * solution is, maybe extend mmc_of_parse to handle multiple
+		 * slots? --jang
+		 */
+		struct platform_device *slot_pdev;
+
+		slot_pdev = of_platform_device_create(child_node, NULL,
+						      &pdev->dev);
+		if (!slot_pdev)
+			continue;
+		ret = cvm_mmc_slot_probe(&slot_pdev->dev, host);
+		if (ret) {
+			gpiod_set_value_cansleep(host->global_pwr_gpiod, 0);
+			goto error;
+		}
+	}
+	dev_info(dev, "probed\n");
+	return 0;
+
+error:
+	clk_disable_unprepare(host->clk);
+	return ret;
+}
+
+static void thunder_mmc_remove(struct pci_dev *pdev)
+{
+	struct cvm_mmc_host *host = pci_get_drvdata(pdev);
+	union mio_emm_dma_cfg dma_cfg;
+	int i;
+
+	for (i = 0; i < CAVIUM_MAX_MMC; i++)
+		if (host->slot[i])
+			cvm_mmc_slot_remove(host->slot[i]);
+
+	dma_cfg.val = readq(host->dma_base + MIO_EMM_DMA_CFG);
+	dma_cfg.s.en = 0;
+	writeq(dma_cfg.val, host->dma_base + MIO_EMM_DMA_CFG);
+
+	gpiod_set_value_cansleep(host->global_pwr_gpiod, 0);
+	clk_disable_unprepare(host->clk);
+}
+
+static const struct pci_device_id thunder_mmc_id_table[] = {
+	{ PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, 0xa010) },
+	{ 0, }  /* end of table */
+};
+
+static struct pci_driver thunder_mmc_driver = {
+	.name = DRV_NAME,
+	.id_table = thunder_mmc_id_table,
+	.probe = thunder_mmc_probe,
+	.remove = thunder_mmc_remove,
+};
+
+static int __init thunder_mmc_init_module(void)
+{
+	return pci_register_driver(&thunder_mmc_driver);
+}
+
+static void __exit thunder_mmc_exit_module(void)
+{
+	pci_unregister_driver(&thunder_mmc_driver);
+}
+
+module_init(thunder_mmc_init_module);
+module_exit(thunder_mmc_exit_module);
+
+MODULE_AUTHOR("Cavium Inc.");
+MODULE_DESCRIPTION("Cavium ThunderX eMMC Driver");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, thunder_mmc_id_table);
+
-- 
2.9.0.rc0.21.g7777322

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH v10 6/8] mmc: thunderx: Add scatter-gather DMA support
  2016-12-19 12:15 [PATCH v10 0/8] Cavium MMC driver Jan Glauber
                   ` (4 preceding siblings ...)
  2016-12-19 12:15 ` [PATCH v10 5/8] mmc: thunderx: Add MMC PCI driver for ThunderX SOCs Jan Glauber
@ 2016-12-19 12:15 ` Jan Glauber
  2016-12-19 12:15 ` [PATCH v10 7/8] mmc: thunderx: Support DDR mode for eMMC devices Jan Glauber
                   ` (2 subsequent siblings)
  8 siblings, 0 replies; 20+ messages in thread
From: Jan Glauber @ 2016-12-19 12:15 UTC (permalink / raw)
  To: Ulf Hansson
  Cc: linux-mmc, linux-kernel, David Daney, Steven J . Hill, Jan Glauber

Add Support for the scatter-gather DMA available in the
ThunderX MMC units. Up to 16 DMA requests can be processed
together.

Signed-off-by: Jan Glauber <jglauber@cavium.com>
---
 drivers/mmc/host/cavium_core_mmc.c     | 105 ++++++++++++++++++++++++++++++++-
 drivers/mmc/host/cavium_mmc.h          |  54 +++++++++++++++++
 drivers/mmc/host/thunderx_pcidrv_mmc.c |   3 +
 3 files changed, 159 insertions(+), 3 deletions(-)

diff --git a/drivers/mmc/host/cavium_core_mmc.c b/drivers/mmc/host/cavium_core_mmc.c
index 596505a..3cd4849 100644
--- a/drivers/mmc/host/cavium_core_mmc.c
+++ b/drivers/mmc/host/cavium_core_mmc.c
@@ -350,9 +350,31 @@ static int finish_dma_single(struct cvm_mmc_host *host, struct mmc_data *data)
 	return 1;
 }
 
+static int finish_dma_sg(struct cvm_mmc_host *host, struct mmc_data *data)
+{
+	union mio_emm_dma_fifo_cfg fifo_cfg;
+
+	/* Check if there are any pending requests left */
+	fifo_cfg.val = readq(host->dma_base + MIO_EMM_DMA_FIFO_CFG);
+	if (fifo_cfg.s.count)
+		dev_err(host->dev, "%u requests still pending\n",
+			fifo_cfg.s.count);
+
+	data->bytes_xfered = data->blocks * data->blksz;
+	data->error = 0;
+
+	/* Clear and disable FIFO */
+	writeq(BIT_ULL(16), host->dma_base + MIO_EMM_DMA_FIFO_CFG);
+	dma_unmap_sg(host->dev, data->sg, data->sg_len, get_dma_dir(data));
+	return 1;
+}
+
 static int finish_dma(struct cvm_mmc_host *host, struct mmc_data *data)
 {
-	return finish_dma_single(host, data);
+	if (host->use_sg && data->sg_len > 1)
+		return finish_dma_sg(host, data);
+	else
+		return finish_dma_single(host, data);
 }
 
 static bool bad_status(union mio_emm_rsp_sts *rsp_sts)
@@ -492,9 +514,83 @@ static u64 prepare_dma_single(struct cvm_mmc_host *host, struct mmc_data *data)
 	return addr;
 }
 
+/*
+ * Queue complete sg list into the FIFO.
+ * Returns 0 on error, 1 otherwise.
+ */
+static u64 prepare_dma_sg(struct cvm_mmc_host *host, struct mmc_data *data)
+{
+	union mio_emm_dma_fifo_cmd fifo_cmd;
+	struct scatterlist *sg;
+	int count, i;
+	u64 addr;
+
+	count = dma_map_sg(host->dev, data->sg, data->sg_len,
+			   get_dma_dir(data));
+	if (!count)
+		return 0;
+	if (count > 16)
+		goto error;
+
+	/* Enable FIFO by removing CLR bit */
+	writeq(0, host->dma_base + MIO_EMM_DMA_FIFO_CFG);
+
+	for_each_sg(data->sg, sg, count, i) {
+		/* Program DMA address */
+		addr = sg_dma_address(sg);
+		if (addr & 7)
+			goto error;
+		writeq(addr, host->dma_base + MIO_EMM_DMA_FIFO_ADR);
+
+		/*
+		 * If we have scatter-gather support we also have an extra
+		 * register for the DMA addr, so no need to check
+		 * host->big_dma_addr here.
+		 */
+		fifo_cmd.val = 0;
+		fifo_cmd.s.rw = (data->flags & MMC_DATA_WRITE) ? 1 : 0;
+
+		/* enable interrupts on the last element */
+		if (i + 1 == count)
+			fifo_cmd.s.intdis = 0;
+		else
+			fifo_cmd.s.intdis = 1;
+
+#ifdef __LITTLE_ENDIAN
+		fifo_cmd.s.endian = 1;
+#endif
+		fifo_cmd.s.size = sg_dma_len(sg) / 8 - 1;
+		/*
+		 * The write copies the address and the command to the FIFO
+		 * and increments the FIFO's COUNT field.
+		 */
+		writeq(fifo_cmd.val, host->dma_base + MIO_EMM_DMA_FIFO_CMD);
+		pr_debug("[%s] sg_dma_len: %u  sg_elem: %d/%d\n",
+			 (fifo_cmd.s.rw) ? "W" : "R", sg_dma_len(sg), i, count);
+	}
+
+	/*
+	 * In difference to prepare_dma_single we don't return the
+	 * address here, as it would not make sense for scatter-gather.
+	 * The dma fixup is only required on models that don't support
+	 * scatter-gather, so that is not a problem.
+	 */
+	return 1;
+
+error:
+	WARN_ON_ONCE(1);
+	dma_unmap_sg(host->dev, data->sg, data->sg_len, get_dma_dir(data));
+	/* Disable FIFO */
+	writeq(BIT_ULL(16), host->dma_base + MIO_EMM_DMA_FIFO_CFG);
+	return 0;
+}
+
 static u64 prepare_dma(struct cvm_mmc_host *host, struct mmc_data *data)
 {
-	return prepare_dma_single(host, data);
+	if (host->use_sg && data->sg_len > 1)
+		return prepare_dma_sg(host, data);
+	else
+		return prepare_dma_single(host, data);
 }
 
 static void prepare_ext_dma(struct mmc_host *mmc, struct mmc_request *mrq,
@@ -972,7 +1068,10 @@ int cvm_mmc_slot_probe(struct device *dev, struct cvm_mmc_host *host)
 	mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED |
 		     MMC_CAP_ERASE | MMC_CAP_CMD23;
 
-	mmc->max_segs = 1;
+	if (host->use_sg)
+		mmc->max_segs = 16;
+	else
+		mmc->max_segs = 1;
 
 	/* DMA size field can address up to 8 MB */
 	mmc->max_seg_size = 8 * 1024 * 1024;
diff --git a/drivers/mmc/host/cavium_mmc.h b/drivers/mmc/host/cavium_mmc.h
index 09fe6d9..9fab637 100644
--- a/drivers/mmc/host/cavium_mmc.h
+++ b/drivers/mmc/host/cavium_mmc.h
@@ -40,6 +40,9 @@
 
 #else /* CONFIG_THUNDERX_MMC */
 
+#define MIO_EMM_DMA_FIFO_CFG	0x160
+#define MIO_EMM_DMA_FIFO_ADR	0x170
+#define MIO_EMM_DMA_FIFO_CMD	0x178
 #define MIO_EMM_DMA_CFG		0x180
 #define MIO_EMM_DMA_ADR		0x188
 #define MIO_EMM_DMA_INT		0x190
@@ -81,6 +84,7 @@ struct cvm_mmc_host {
 	struct mmc_request *current_req;
 	struct sg_mapping_iter smi;
 	bool dma_active;
+	bool use_sg;
 
 	bool has_ciu3;
 	bool big_dma_addr;
@@ -135,6 +139,56 @@ struct cvm_mmc_cr_mods {
 
 /* Bitfield definitions */
 
+union mio_emm_dma_fifo_cfg {
+	u64 val;
+	struct mio_emm_dma_fifo_cfg_s {
+#ifdef __BIG_ENDIAN_BITFIELD
+		u64 :48;
+		u64 clr:1;
+		u64 :3;
+		u64 int_lvl:4;
+		u64 :3;
+		u64 count:5;
+#else
+		u64 count:5;
+		u64 :3;
+		u64 int_lvl:4;
+		u64 :3;
+		u64 clr:1;
+		u64 :48;
+#endif
+	} s;
+};
+
+union mio_emm_dma_fifo_cmd {
+	u64 val;
+	struct mio_emm_dma_fifo_cmd_s {
+#ifdef __BIG_ENDIAN_BITFIELD
+		u64 :1;
+		u64 rw:1;
+		u64 :1;
+		u64 intdis:1;
+		u64 swap32:1;
+		u64 swap16:1;
+		u64 swap8:1;
+		u64 endian:1;
+		u64 size:20;
+		u64 :36;
+#else
+		u64 :36;
+		u64 size:20;
+		u64 endian:1;
+		u64 swap8:1;
+		u64 swap16:1;
+		u64 swap32:1;
+		u64 intdis:1;
+		u64 :1;
+		u64 rw:1;
+		u64 :1;
+#endif
+	} s;
+};
+
 union mio_emm_cmd {
 	u64 val;
 	struct mio_emm_cmd_s {
diff --git a/drivers/mmc/host/thunderx_pcidrv_mmc.c b/drivers/mmc/host/thunderx_pcidrv_mmc.c
index 04d03bf..d5b38ba 100644
--- a/drivers/mmc/host/thunderx_pcidrv_mmc.c
+++ b/drivers/mmc/host/thunderx_pcidrv_mmc.c
@@ -109,6 +109,7 @@ static int thunder_mmc_probe(struct pci_dev *pdev,
 	host->release_bus = thunder_mmc_release_bus;
 	host->int_enable = thunder_mmc_int_enable;
 
+	host->use_sg = true;
 	host->big_dma_addr = true;
 	host->need_irq_handler_lock = true;
 	host->last_slot = -1;
@@ -123,6 +124,8 @@ static int thunder_mmc_probe(struct pci_dev *pdev,
 	 */
 	writeq(127, host->base + MIO_EMM_INT_EN);
 	writeq(3, host->base + MIO_EMM_DMA_INT_ENA_W1C);
+	/* Clear DMA FIFO */
+	writeq(BIT_ULL(16), host->base + MIO_EMM_DMA_FIFO_CFG);
 
 	ret = thunder_mmc_register_interrupts(host, pdev);
 	if (ret)
-- 
2.9.0.rc0.21.g7777322

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH v10 7/8] mmc: thunderx: Support DDR mode for eMMC devices
  2016-12-19 12:15 [PATCH v10 0/8] Cavium MMC driver Jan Glauber
                   ` (5 preceding siblings ...)
  2016-12-19 12:15 ` [PATCH v10 6/8] mmc: thunderx: Add scatter-gather DMA support Jan Glauber
@ 2016-12-19 12:15 ` Jan Glauber
  2016-12-19 12:15 ` [PATCH v10 8/8] dt-bindings: mmc: Add Cavium SOCs MMC bindings Jan Glauber
  2016-12-20 12:10 ` [PATCH v10 0/8] Cavium MMC driver Ulf Hansson
  8 siblings, 0 replies; 20+ messages in thread
From: Jan Glauber @ 2016-12-19 12:15 UTC (permalink / raw)
  To: Ulf Hansson
  Cc: linux-mmc, linux-kernel, David Daney, Steven J . Hill, Jan Glauber

Add support for switching to DDR mode for eMMC devices.
Although the host controller only supports 3.3 Volt
and DDR52 uses 1.8 Volt according to the specification
it is possible to use DDR also with 3.3 Volt for eMMC chips.

To switch to DDR mode MMC_CAP_1_8V_DDR is required.

Signed-off-by: Jan Glauber <jglauber@cavium.com>
---
 drivers/mmc/host/cavium_core_mmc.c | 13 ++++++++++++-
 1 file changed, 12 insertions(+), 1 deletion(-)

diff --git a/drivers/mmc/host/cavium_core_mmc.c b/drivers/mmc/host/cavium_core_mmc.c
index 3cd4849..ca0748c 100644
--- a/drivers/mmc/host/cavium_core_mmc.c
+++ b/drivers/mmc/host/cavium_core_mmc.c
@@ -841,6 +841,10 @@ static void cvm_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
 		break;
 	}
 
+	/* DDR is available for 4/8 bit bus width */
+	if (ios->bus_width && ios->timing == MMC_TIMING_MMC_DDR52)
+		bus_width |= 4;
+
 	slot->bus_width = bus_width;
 
 	if (!ios->clock)
@@ -1065,8 +1069,15 @@ int cvm_mmc_slot_probe(struct device *dev, struct cvm_mmc_host *host)
 	/* Set up host parameters */
 	mmc->ops = &cvm_mmc_ops;
 
+	/*
+	 * We only have a 3.3v supply, we cannot support any
+	 * of the UHS modes. We do support the high speed DDR
+	 * modes up to 52MHz. And we need to lie about 1.8v support,
+	 * otherwise the MMC layer will not switch to DDR.
+	 */
 	mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED |
-		     MMC_CAP_ERASE | MMC_CAP_CMD23;
+		     MMC_CAP_ERASE | MMC_CAP_CMD23 |
+		     MMC_CAP_1_8V_DDR;
 
 	if (host->use_sg)
 		mmc->max_segs = 16;
-- 
2.9.0.rc0.21.g7777322

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH v10 8/8] dt-bindings: mmc: Add Cavium SOCs MMC bindings
  2016-12-19 12:15 [PATCH v10 0/8] Cavium MMC driver Jan Glauber
                   ` (6 preceding siblings ...)
  2016-12-19 12:15 ` [PATCH v10 7/8] mmc: thunderx: Support DDR mode for eMMC devices Jan Glauber
@ 2016-12-19 12:15 ` Jan Glauber
  2016-12-22 20:32     ` Rob Herring
  2016-12-20 12:10 ` [PATCH v10 0/8] Cavium MMC driver Ulf Hansson
  8 siblings, 1 reply; 20+ messages in thread
From: Jan Glauber @ 2016-12-19 12:15 UTC (permalink / raw)
  To: Ulf Hansson
  Cc: linux-mmc, linux-kernel, David Daney, Steven J . Hill,
	Jan Glauber, Rob Herring, Mark Rutland, devicetree

Add description of Cavium Octeon and ThunderX SOC device tree bindings.

CC: Ulf Hansson <ulf.hansson@linaro.org>
CC: Rob Herring <robh+dt@kernel.org>
CC: Mark Rutland <mark.rutland@arm.com>
CC: devicetree@vger.kernel.org

Signed-off-by: Jan Glauber <jglauber@cavium.com>
---
 .../devicetree/bindings/mmc/octeon-mmc.txt         | 59 ++++++++++++++++++++++
 1 file changed, 59 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/mmc/octeon-mmc.txt

diff --git a/Documentation/devicetree/bindings/mmc/octeon-mmc.txt b/Documentation/devicetree/bindings/mmc/octeon-mmc.txt
new file mode 100644
index 0000000..aad02eb
--- /dev/null
+++ b/Documentation/devicetree/bindings/mmc/octeon-mmc.txt
@@ -0,0 +1,59 @@
+* Cavium Octeon & ThunderX MMC controller
+
+The highspeed MMC host controller on Caviums SoCs provides an interface
+for MMC and SD types of memory cards.
+
+Supported maximum speeds are the ones of the eMMC standard 4.41 as well
+as the speed of SD standard 4.0. Only 3.3 Volt is supported.
+
+Required properties:
+ - compatible : should be one of:
+   * "cavium,octeon-6130-mmc"
+   * "cavium,octeon-6130-mmc-slot"
+   * "cavium,octeon-7890-mmc"
+   * "cavium,octeon-7890-mmc-slot"
+   * "cavium,thunder-8190-mmc"
+   * "cavium,thunder-8190-mmc-slot"
+   * "cavium,thunder-8390-mmc"
+   * "cavium,thunder-8390-mmc-slot"
+ - reg : mmc controller base registers
+ - clocks : phandle
+
+Optional properties:
+ - for cd, bus-width and additional generic mmc parameters
+   please refer to mmc.txt within this directory
+ - "cavium,cmd-clk-skew" : number of coprocessor clocks before sampling command
+ - "cavium,dat-clk-skew" : number of coprocessor clocks before sampling data
+
+Deprecated properties:
+- spi-max-frequency : use max-frequency instead
+- "cavium,bus-max-width" : use bus-width instead
+
+Examples:
+	- Within .dtsi:
+	mmc_1_4: mmc@1,4 {
+		compatible = "cavium,thunder-8390-mmc";
+		reg = <0x0c00 0 0 0 0>;	/* DEVFN = 0x0c (1:4) */
+		#address-cells = <1>;
+		#size-cells = <0>;
+		clocks = <&sclk>;
+	};
+
+	- Within dts:
+	mmc-slot@0 {
+		compatible = "cavium,thunder-8390-mmc-slot";
+		reg = <0>;
+		voltage-ranges = <3300 3300>;
+		max-frequency = <42000000>;
+		bus-width = <4>;
+		cap-sd-highspeed;
+	};
+	mmc-slot@1 {
+		compatible = "cavium,thunder-8390-mmc-slot";
+		reg = <1>;
+		voltage-ranges = <3300 3300>;
+		max-frequency = <42000000>;
+		bus-width = <8>;
+		cap-mmc-highspeed;
+		non-removable;
+	};
-- 
2.9.0.rc0.21.g7777322

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* Re: [PATCH v10 0/8] Cavium MMC driver
  2016-12-19 12:15 [PATCH v10 0/8] Cavium MMC driver Jan Glauber
                   ` (7 preceding siblings ...)
  2016-12-19 12:15 ` [PATCH v10 8/8] dt-bindings: mmc: Add Cavium SOCs MMC bindings Jan Glauber
@ 2016-12-20 12:10 ` Ulf Hansson
  2016-12-20 12:24   ` Jan Glauber
  2017-01-19 14:50   ` Jan Glauber
  8 siblings, 2 replies; 20+ messages in thread
From: Ulf Hansson @ 2016-12-20 12:10 UTC (permalink / raw)
  To: Jan Glauber; +Cc: linux-mmc, linux-kernel, David Daney, Steven J . Hill

Hi Jan,

On 19 December 2016 at 13:15, Jan Glauber <jglauber@cavium.com> wrote:
> While this patch series seems to be somehow overdue, in the meantime the
> same MMC unit was re-used on Cavium's ThunderX SOC so our interest in making
> progress upstreaming this driver has doubled now...
>
> Glancing over the history of the series I think most of the high-level
> comments should be adressed by now (like DTS representation of the
> multiple slots). I've added some new features for the ARM64 port
> and in the process re-wrote parts of the driver and split it into smaller,
> hopefully easier to review parts.

I only had a quick review, but the overall impression is that it's
getting far better. Here follows my summary.

1) I intend to especially look at DTS representation for the slot
nodes, to make sure we have a good solution. Allow me to get back on
this.

2) I don't like how you have named files, as it doesn't express the
obvious relationship between the core library and the drivers. I would
rather see something similar to dw_mmc or sdhci.

3) Related to 2), I would also like to have a prefix of the commit
messages which express the relationships. Again follow dw_mmc/sdhci.

4) GPIO powers should be modelled as GPIO regulators. I believe we
have discussed this earlier as well (I don't really recall in detail
about the last things). It gives us the opportunity to via the
regulator framework to find out the supported voltage levels. This is
the generic method which is used by mmc drivers, you need to adopt to
this as well.

5) Please reorder the series so the DT bindings doc change comes
first. I need an ack from the DT maintainer for it.

6) The most important feedback:
This driver has been posted in many versions by now. Perhaps I could
have been more responsive throughout the attempts, I apologize for
that. On the other hand, you seems to have a round robin schedule for
whom that sends a new version. :-) That makes me wonder about your
support in the maintenance phase. I hope my concern is wrong, but how
about that you point out a responsible maintainer? Especially since
this seems to become a family of Cavium variants, it would help me if
I could rely on someone providing acks for future changes. Would you
be able to accept that role?

>
> In porting the driver to arm64 I run into some issues.
>
> 1. mmc_parse_of is not capable of supporting multiple slots behind one
>    controller. On arm64 the host controller is presented as one PCI device.
>    There are no devices per slot as with the platform variant, so I
>    needed to create dummy devices to make mmc_parse_of work.
>    IMHO it would be cleaner if mmc_parse_of could be extended to cover
>    the multiple slots case.

Yes. I agree that this make sense!
Seems like we could try to make use of the struct device_node instead
of the struct device.

I will try to come up with an idea, I keep you posted.

>
> 2. Without setting MMC_CAP_1_8V_DDR DDR mode is not usable for eMMC.
>    I would prefer to introduce a new cap flag, MMC_CAP_3_3V_DDR,
>    if possible. Currently I need to add "mmc-ddr-1_8v" to DTS,
>    which seems odd for a 3.3v only host controller.

This keep coming back. Both DT bindings and changing to the mmc core
has been posted.

Allow me to help out and re-post a new series. You can build on top of
them - I will keep you on cc.

>
> 3. Because the slots share the host controller using the
>    "full-pwr-cycle" attribute turned out to not work well.
>    I'm not 100% sure just ignoring the attribute is correct.

The full-pwr-cycle shall be set whether you are able to power cycle
the *card*. So this binding should be a part of each slot/child node -
if the host supports it.

>
> For the driver to work GPIO support is required, the GPIO driver is
> not yet available upstream. Therefore, for the time being I removed
> the GPIO dependency from Kconfig.

Is this is about the GPIO powers or also GPIO card detect?

Anyway, I am fine with not depending on GPIO Kconfig.

[...]

Kind regards
Uffe

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH v10 0/8] Cavium MMC driver
  2016-12-20 12:10 ` [PATCH v10 0/8] Cavium MMC driver Ulf Hansson
@ 2016-12-20 12:24   ` Jan Glauber
  2016-12-20 12:38     ` Ulf Hansson
  2017-01-19 14:50   ` Jan Glauber
  1 sibling, 1 reply; 20+ messages in thread
From: Jan Glauber @ 2016-12-20 12:24 UTC (permalink / raw)
  To: Ulf Hansson; +Cc: linux-mmc, linux-kernel, David Daney, Steven J . Hill

On Tue, Dec 20, 2016 at 01:10:56PM +0100, Ulf Hansson wrote:
> Hi Jan,
> 
> On 19 December 2016 at 13:15, Jan Glauber <jglauber@cavium.com> wrote:
> > While this patch series seems to be somehow overdue, in the meantime the
> > same MMC unit was re-used on Cavium's ThunderX SOC so our interest in making
> > progress upstreaming this driver has doubled now...
> >
> > Glancing over the history of the series I think most of the high-level
> > comments should be adressed by now (like DTS representation of the
> > multiple slots). I've added some new features for the ARM64 port
> > and in the process re-wrote parts of the driver and split it into smaller,
> > hopefully easier to review parts.
> 
> I only had a quick review, but the overall impression is that it's
> getting far better. Here follows my summary.
> 
> 1) I intend to especially look at DTS representation for the slot
> nodes, to make sure we have a good solution. Allow me to get back on
> this.
> 
> 2) I don't like how you have named files, as it doesn't express the
> obvious relationship between the core library and the drivers. I would
> rather see something similar to dw_mmc or sdhci.
> 
> 3) Related to 2), I would also like to have a prefix of the commit
> messages which express the relationships. Again follow dw_mmc/sdhci.
> 
> 4) GPIO powers should be modelled as GPIO regulators. I believe we
> have discussed this earlier as well (I don't really recall in detail
> about the last things). It gives us the opportunity to via the
> regulator framework to find out the supported voltage levels. This is
> the generic method which is used by mmc drivers, you need to adopt to
> this as well.
> 
> 5) Please reorder the series so the DT bindings doc change comes
> first. I need an ack from the DT maintainer for it.
> 
> 6) The most important feedback:
> This driver has been posted in many versions by now. Perhaps I could
> have been more responsive throughout the attempts, I apologize for
> that. On the other hand, you seems to have a round robin schedule for
> whom that sends a new version. :-) That makes me wonder about your
> support in the maintenance phase. I hope my concern is wrong, but how
> about that you point out a responsible maintainer? Especially since
> this seems to become a family of Cavium variants, it would help me if
> I could rely on someone providing acks for future changes. Would you
> be able to accept that role?

Hi Uffe,

thanks for your feedback! To answer only point 6 for now, I was not to
keen on being the next poster of this series ;- Nevertheless, I'm
comitted to keep working on this driver to bring it finally upstream and
also to maintain it in the future. To make this clear I'll add myself
and possibly also David or Steven to MAINTAINERS.

Cheers,
Jan

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH v10 0/8] Cavium MMC driver
  2016-12-20 12:24   ` Jan Glauber
@ 2016-12-20 12:38     ` Ulf Hansson
  0 siblings, 0 replies; 20+ messages in thread
From: Ulf Hansson @ 2016-12-20 12:38 UTC (permalink / raw)
  To: Jan Glauber; +Cc: linux-mmc, linux-kernel, David Daney, Steven J . Hill

>
> Hi Uffe,
>
> thanks for your feedback! To answer only point 6 for now, I was not to
> keen on being the next poster of this series ;- Nevertheless, I'm
> comitted to keep working on this driver to bring it finally upstream and
> also to maintain it in the future. To make this clear I'll add myself
> and possibly also David or Steven to MAINTAINERS.

Thanks! That shows your commitment.

Kind regards
Uffe

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH v10 8/8] dt-bindings: mmc: Add Cavium SOCs MMC bindings
@ 2016-12-22 20:32     ` Rob Herring
  0 siblings, 0 replies; 20+ messages in thread
From: Rob Herring @ 2016-12-22 20:32 UTC (permalink / raw)
  To: Jan Glauber
  Cc: Ulf Hansson, linux-mmc, linux-kernel, David Daney,
	Steven J . Hill, Mark Rutland, devicetree

On Mon, Dec 19, 2016 at 01:15:52PM +0100, Jan Glauber wrote:
> Add description of Cavium Octeon and ThunderX SOC device tree bindings.
> 
> CC: Ulf Hansson <ulf.hansson@linaro.org>
> CC: Rob Herring <robh+dt@kernel.org>
> CC: Mark Rutland <mark.rutland@arm.com>
> CC: devicetree@vger.kernel.org
> 
> Signed-off-by: Jan Glauber <jglauber@cavium.com>
> ---
>  .../devicetree/bindings/mmc/octeon-mmc.txt         | 59 ++++++++++++++++++++++

Perhaps cavium-mmc.txt would be more appropriate now.

>  1 file changed, 59 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/mmc/octeon-mmc.txt
> 
> diff --git a/Documentation/devicetree/bindings/mmc/octeon-mmc.txt b/Documentation/devicetree/bindings/mmc/octeon-mmc.txt
> new file mode 100644
> index 0000000..aad02eb
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/mmc/octeon-mmc.txt
> @@ -0,0 +1,59 @@
> +* Cavium Octeon & ThunderX MMC controller
> +
> +The highspeed MMC host controller on Caviums SoCs provides an interface
> +for MMC and SD types of memory cards.
> +
> +Supported maximum speeds are the ones of the eMMC standard 4.41 as well
> +as the speed of SD standard 4.0. Only 3.3 Volt is supported.
> +
> +Required properties:
> + - compatible : should be one of:
> +   * "cavium,octeon-6130-mmc"
> +   * "cavium,octeon-6130-mmc-slot"
> +   * "cavium,octeon-7890-mmc"
> +   * "cavium,octeon-7890-mmc-slot"
> +   * "cavium,thunder-8190-mmc"
> +   * "cavium,thunder-8190-mmc-slot"
> +   * "cavium,thunder-8390-mmc"
> +   * "cavium,thunder-8390-mmc-slot"
> + - reg : mmc controller base registers

Following PCI addressing?

> + - clocks : phandle
> +
> +Optional properties:
> + - for cd, bus-width and additional generic mmc parameters
> +   please refer to mmc.txt within this directory
> + - "cavium,cmd-clk-skew" : number of coprocessor clocks before sampling command
> + - "cavium,dat-clk-skew" : number of coprocessor clocks before sampling data
> +
> +Deprecated properties:
> +- spi-max-frequency : use max-frequency instead
> +- "cavium,bus-max-width" : use bus-width instead

Drop the quotes.

> +
> +Examples:
> +	- Within .dtsi:

Don't show the division between files in the example.

> +	mmc_1_4: mmc@1,4 {
> +		compatible = "cavium,thunder-8390-mmc";
> +		reg = <0x0c00 0 0 0 0>;	/* DEVFN = 0x0c (1:4) */
> +		#address-cells = <1>;
> +		#size-cells = <0>;
> +		clocks = <&sclk>;
> +	};
> +
> +	- Within dts:
> +	mmc-slot@0 {

Need to show this is a child node.

> +		compatible = "cavium,thunder-8390-mmc-slot";
> +		reg = <0>;
> +		voltage-ranges = <3300 3300>;
> +		max-frequency = <42000000>;
> +		bus-width = <4>;
> +		cap-sd-highspeed;
> +	};
> +	mmc-slot@1 {
> +		compatible = "cavium,thunder-8390-mmc-slot";
> +		reg = <1>;
> +		voltage-ranges = <3300 3300>;
> +		max-frequency = <42000000>;
> +		bus-width = <8>;
> +		cap-mmc-highspeed;
> +		non-removable;
> +	};
> -- 
> 2.9.0.rc0.21.g7777322
> 

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH v10 8/8] dt-bindings: mmc: Add Cavium SOCs MMC bindings
@ 2016-12-22 20:32     ` Rob Herring
  0 siblings, 0 replies; 20+ messages in thread
From: Rob Herring @ 2016-12-22 20:32 UTC (permalink / raw)
  To: Jan Glauber
  Cc: Ulf Hansson, linux-mmc-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA, David Daney,
	Steven J . Hill, Mark Rutland, devicetree-u79uwXL29TY76Z2rM5mHXA

On Mon, Dec 19, 2016 at 01:15:52PM +0100, Jan Glauber wrote:
> Add description of Cavium Octeon and ThunderX SOC device tree bindings.
> 
> CC: Ulf Hansson <ulf.hansson-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
> CC: Rob Herring <robh+dt-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
> CC: Mark Rutland <mark.rutland-5wv7dgnIgG8@public.gmane.org>
> CC: devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
> 
> Signed-off-by: Jan Glauber <jglauber-YGCgFSpz5w/QT0dZR+AlfA@public.gmane.org>
> ---
>  .../devicetree/bindings/mmc/octeon-mmc.txt         | 59 ++++++++++++++++++++++

Perhaps cavium-mmc.txt would be more appropriate now.

>  1 file changed, 59 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/mmc/octeon-mmc.txt
> 
> diff --git a/Documentation/devicetree/bindings/mmc/octeon-mmc.txt b/Documentation/devicetree/bindings/mmc/octeon-mmc.txt
> new file mode 100644
> index 0000000..aad02eb
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/mmc/octeon-mmc.txt
> @@ -0,0 +1,59 @@
> +* Cavium Octeon & ThunderX MMC controller
> +
> +The highspeed MMC host controller on Caviums SoCs provides an interface
> +for MMC and SD types of memory cards.
> +
> +Supported maximum speeds are the ones of the eMMC standard 4.41 as well
> +as the speed of SD standard 4.0. Only 3.3 Volt is supported.
> +
> +Required properties:
> + - compatible : should be one of:
> +   * "cavium,octeon-6130-mmc"
> +   * "cavium,octeon-6130-mmc-slot"
> +   * "cavium,octeon-7890-mmc"
> +   * "cavium,octeon-7890-mmc-slot"
> +   * "cavium,thunder-8190-mmc"
> +   * "cavium,thunder-8190-mmc-slot"
> +   * "cavium,thunder-8390-mmc"
> +   * "cavium,thunder-8390-mmc-slot"
> + - reg : mmc controller base registers

Following PCI addressing?

> + - clocks : phandle
> +
> +Optional properties:
> + - for cd, bus-width and additional generic mmc parameters
> +   please refer to mmc.txt within this directory
> + - "cavium,cmd-clk-skew" : number of coprocessor clocks before sampling command
> + - "cavium,dat-clk-skew" : number of coprocessor clocks before sampling data
> +
> +Deprecated properties:
> +- spi-max-frequency : use max-frequency instead
> +- "cavium,bus-max-width" : use bus-width instead

Drop the quotes.

> +
> +Examples:
> +	- Within .dtsi:

Don't show the division between files in the example.

> +	mmc_1_4: mmc@1,4 {
> +		compatible = "cavium,thunder-8390-mmc";
> +		reg = <0x0c00 0 0 0 0>;	/* DEVFN = 0x0c (1:4) */
> +		#address-cells = <1>;
> +		#size-cells = <0>;
> +		clocks = <&sclk>;
> +	};
> +
> +	- Within dts:
> +	mmc-slot@0 {

Need to show this is a child node.

> +		compatible = "cavium,thunder-8390-mmc-slot";
> +		reg = <0>;
> +		voltage-ranges = <3300 3300>;
> +		max-frequency = <42000000>;
> +		bus-width = <4>;
> +		cap-sd-highspeed;
> +	};
> +	mmc-slot@1 {
> +		compatible = "cavium,thunder-8390-mmc-slot";
> +		reg = <1>;
> +		voltage-ranges = <3300 3300>;
> +		max-frequency = <42000000>;
> +		bus-width = <8>;
> +		cap-mmc-highspeed;
> +		non-removable;
> +	};
> -- 
> 2.9.0.rc0.21.g7777322
> 
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH v10 8/8] dt-bindings: mmc: Add Cavium SOCs MMC bindings
  2016-12-22 20:32     ` Rob Herring
@ 2017-01-09 15:05       ` Jan Glauber
  -1 siblings, 0 replies; 20+ messages in thread
From: Jan Glauber @ 2017-01-09 15:05 UTC (permalink / raw)
  To: Rob Herring
  Cc: Ulf Hansson, linux-mmc, linux-kernel, David Daney,
	Steven J . Hill, Mark Rutland, devicetree

On Thu, Dec 22, 2016 at 02:32:42PM -0600, Rob Herring wrote:
> On Mon, Dec 19, 2016 at 01:15:52PM +0100, Jan Glauber wrote:
> > Add description of Cavium Octeon and ThunderX SOC device tree bindings.
> > 
> > CC: Ulf Hansson <ulf.hansson@linaro.org>
> > CC: Rob Herring <robh+dt@kernel.org>
> > CC: Mark Rutland <mark.rutland@arm.com>
> > CC: devicetree@vger.kernel.org
> > 
> > Signed-off-by: Jan Glauber <jglauber@cavium.com>
> > ---
> >  .../devicetree/bindings/mmc/octeon-mmc.txt         | 59 ++++++++++++++++++++++
> 
> Perhaps cavium-mmc.txt would be more appropriate now.

Yes, forgot to rename it.

> >  1 file changed, 59 insertions(+)
> >  create mode 100644 Documentation/devicetree/bindings/mmc/octeon-mmc.txt
> > 
> > diff --git a/Documentation/devicetree/bindings/mmc/octeon-mmc.txt b/Documentation/devicetree/bindings/mmc/octeon-mmc.txt
> > new file mode 100644
> > index 0000000..aad02eb
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/mmc/octeon-mmc.txt
> > @@ -0,0 +1,59 @@
> > +* Cavium Octeon & ThunderX MMC controller
> > +
> > +The highspeed MMC host controller on Caviums SoCs provides an interface
> > +for MMC and SD types of memory cards.
> > +
> > +Supported maximum speeds are the ones of the eMMC standard 4.41 as well
> > +as the speed of SD standard 4.0. Only 3.3 Volt is supported.
> > +
> > +Required properties:
> > + - compatible : should be one of:
> > +   * "cavium,octeon-6130-mmc"
> > +   * "cavium,octeon-6130-mmc-slot"
> > +   * "cavium,octeon-7890-mmc"
> > +   * "cavium,octeon-7890-mmc-slot"
> > +   * "cavium,thunder-8190-mmc"
> > +   * "cavium,thunder-8190-mmc-slot"
> > +   * "cavium,thunder-8390-mmc"
> > +   * "cavium,thunder-8390-mmc-slot"
> > + - reg : mmc controller base registers
> 
> Following PCI addressing?

Yes for the host controller, for the child nodes we use reg as the
physical slot number. Maybe I should describe the child node properties
separately?

> > + - clocks : phandle
> > +
> > +Optional properties:
> > + - for cd, bus-width and additional generic mmc parameters
> > +   please refer to mmc.txt within this directory
> > + - "cavium,cmd-clk-skew" : number of coprocessor clocks before sampling command
> > + - "cavium,dat-clk-skew" : number of coprocessor clocks before sampling data
> > +
> > +Deprecated properties:
> > +- spi-max-frequency : use max-frequency instead
> > +- "cavium,bus-max-width" : use bus-width instead
> 
> Drop the quotes.

OK, droped them also above.

> > +
> > +Examples:
> > +	- Within .dtsi:
> 
> Don't show the division between files in the example.

OK.

> > +	mmc_1_4: mmc@1,4 {
> > +		compatible = "cavium,thunder-8390-mmc";
> > +		reg = <0x0c00 0 0 0 0>;	/* DEVFN = 0x0c (1:4) */
> > +		#address-cells = <1>;
> > +		#size-cells = <0>;
> > +		clocks = <&sclk>;
> > +	};
> > +
> > +	- Within dts:
> > +	mmc-slot@0 {
> 
> Need to show this is a child node.

OK.

> > +		compatible = "cavium,thunder-8390-mmc-slot";
> > +		reg = <0>;
> > +		voltage-ranges = <3300 3300>;
> > +		max-frequency = <42000000>;
> > +		bus-width = <4>;
> > +		cap-sd-highspeed;
> > +	};
> > +	mmc-slot@1 {
> > +		compatible = "cavium,thunder-8390-mmc-slot";
> > +		reg = <1>;
> > +		voltage-ranges = <3300 3300>;
> > +		max-frequency = <42000000>;
> > +		bus-width = <8>;
> > +		cap-mmc-highspeed;
> > +		non-removable;
> > +	};
> > -- 
> > 2.9.0.rc0.21.g7777322
> > 

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH v10 8/8] dt-bindings: mmc: Add Cavium SOCs MMC bindings
@ 2017-01-09 15:05       ` Jan Glauber
  0 siblings, 0 replies; 20+ messages in thread
From: Jan Glauber @ 2017-01-09 15:05 UTC (permalink / raw)
  To: Rob Herring
  Cc: Ulf Hansson, linux-mmc-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA, David Daney,
	Steven J . Hill, Mark Rutland, devicetree-u79uwXL29TY76Z2rM5mHXA

On Thu, Dec 22, 2016 at 02:32:42PM -0600, Rob Herring wrote:
> On Mon, Dec 19, 2016 at 01:15:52PM +0100, Jan Glauber wrote:
> > Add description of Cavium Octeon and ThunderX SOC device tree bindings.
> > 
> > CC: Ulf Hansson <ulf.hansson-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
> > CC: Rob Herring <robh+dt-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
> > CC: Mark Rutland <mark.rutland-5wv7dgnIgG8@public.gmane.org>
> > CC: devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
> > 
> > Signed-off-by: Jan Glauber <jglauber-YGCgFSpz5w/QT0dZR+AlfA@public.gmane.org>
> > ---
> >  .../devicetree/bindings/mmc/octeon-mmc.txt         | 59 ++++++++++++++++++++++
> 
> Perhaps cavium-mmc.txt would be more appropriate now.

Yes, forgot to rename it.

> >  1 file changed, 59 insertions(+)
> >  create mode 100644 Documentation/devicetree/bindings/mmc/octeon-mmc.txt
> > 
> > diff --git a/Documentation/devicetree/bindings/mmc/octeon-mmc.txt b/Documentation/devicetree/bindings/mmc/octeon-mmc.txt
> > new file mode 100644
> > index 0000000..aad02eb
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/mmc/octeon-mmc.txt
> > @@ -0,0 +1,59 @@
> > +* Cavium Octeon & ThunderX MMC controller
> > +
> > +The highspeed MMC host controller on Caviums SoCs provides an interface
> > +for MMC and SD types of memory cards.
> > +
> > +Supported maximum speeds are the ones of the eMMC standard 4.41 as well
> > +as the speed of SD standard 4.0. Only 3.3 Volt is supported.
> > +
> > +Required properties:
> > + - compatible : should be one of:
> > +   * "cavium,octeon-6130-mmc"
> > +   * "cavium,octeon-6130-mmc-slot"
> > +   * "cavium,octeon-7890-mmc"
> > +   * "cavium,octeon-7890-mmc-slot"
> > +   * "cavium,thunder-8190-mmc"
> > +   * "cavium,thunder-8190-mmc-slot"
> > +   * "cavium,thunder-8390-mmc"
> > +   * "cavium,thunder-8390-mmc-slot"
> > + - reg : mmc controller base registers
> 
> Following PCI addressing?

Yes for the host controller, for the child nodes we use reg as the
physical slot number. Maybe I should describe the child node properties
separately?

> > + - clocks : phandle
> > +
> > +Optional properties:
> > + - for cd, bus-width and additional generic mmc parameters
> > +   please refer to mmc.txt within this directory
> > + - "cavium,cmd-clk-skew" : number of coprocessor clocks before sampling command
> > + - "cavium,dat-clk-skew" : number of coprocessor clocks before sampling data
> > +
> > +Deprecated properties:
> > +- spi-max-frequency : use max-frequency instead
> > +- "cavium,bus-max-width" : use bus-width instead
> 
> Drop the quotes.

OK, droped them also above.

> > +
> > +Examples:
> > +	- Within .dtsi:
> 
> Don't show the division between files in the example.

OK.

> > +	mmc_1_4: mmc@1,4 {
> > +		compatible = "cavium,thunder-8390-mmc";
> > +		reg = <0x0c00 0 0 0 0>;	/* DEVFN = 0x0c (1:4) */
> > +		#address-cells = <1>;
> > +		#size-cells = <0>;
> > +		clocks = <&sclk>;
> > +	};
> > +
> > +	- Within dts:
> > +	mmc-slot@0 {
> 
> Need to show this is a child node.

OK.

> > +		compatible = "cavium,thunder-8390-mmc-slot";
> > +		reg = <0>;
> > +		voltage-ranges = <3300 3300>;
> > +		max-frequency = <42000000>;
> > +		bus-width = <4>;
> > +		cap-sd-highspeed;
> > +	};
> > +	mmc-slot@1 {
> > +		compatible = "cavium,thunder-8390-mmc-slot";
> > +		reg = <1>;
> > +		voltage-ranges = <3300 3300>;
> > +		max-frequency = <42000000>;
> > +		bus-width = <8>;
> > +		cap-mmc-highspeed;
> > +		non-removable;
> > +	};
> > -- 
> > 2.9.0.rc0.21.g7777322
> > 
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH v10 0/8] Cavium MMC driver
  2016-12-20 12:10 ` [PATCH v10 0/8] Cavium MMC driver Ulf Hansson
  2016-12-20 12:24   ` Jan Glauber
@ 2017-01-19 14:50   ` Jan Glauber
  2017-01-19 17:47     ` David Daney
  2017-01-19 21:38     ` Ulf Hansson
  1 sibling, 2 replies; 20+ messages in thread
From: Jan Glauber @ 2017-01-19 14:50 UTC (permalink / raw)
  To: Ulf Hansson; +Cc: linux-mmc, linux-kernel, David Daney, Steven J . Hill

On Tue, Dec 20, 2016 at 01:10:56PM +0100, Ulf Hansson wrote:
> Hi Jan,
> 
> On 19 December 2016 at 13:15, Jan Glauber <jglauber@cavium.com> wrote:
> > While this patch series seems to be somehow overdue, in the meantime the
> > same MMC unit was re-used on Cavium's ThunderX SOC so our interest in making
> > progress upstreaming this driver has doubled now...
> >
> > Glancing over the history of the series I think most of the high-level
> > comments should be adressed by now (like DTS representation of the
> > multiple slots). I've added some new features for the ARM64 port
> > and in the process re-wrote parts of the driver and split it into smaller,
> > hopefully easier to review parts.
> 
> I only had a quick review, but the overall impression is that it's
> getting far better. Here follows my summary.
> 
> 1) I intend to especially look at DTS representation for the slot
> nodes, to make sure we have a good solution. Allow me to get back on
> this.
> 
> 2) I don't like how you have named files, as it doesn't express the
> obvious relationship between the core library and the drivers. I would
> rather see something similar to dw_mmc or sdhci.

I've prefixed all files with "cavium" and adjusted names, incl. Kconfig
names.

> 3) Related to 2), I would also like to have a prefix of the commit
> messages which express the relationships. Again follow dw_mmc/sdhci.

OK.

> 4) GPIO powers should be modelled as GPIO regulators. I believe we
> have discussed this earlier as well (I don't really recall in detail
> about the last things). It gives us the opportunity to via the
> regulator framework to find out the supported voltage levels. This is
> the generic method which is used by mmc drivers, you need to adopt to
> this as well.

I've added a fixed regulator to DT:

        vcc_3v3: regulator-vcc_3v3 {
                compatible = "regulator-fixed";
                regulator-name = "VCC_3V3";
                regulator-min-microvolt = <3300000>;
                regulator-max-microvolt = <3300000>;

                gpio = <&gpio_6_0 8 0>;
                /* enable-gpio = <&gpio_6_0 8 0>; */
                enable-active-high;
        };

This seems to enable the gpio. Is this sufficient or do I need the
gpio-regulator?

> 5) Please reorder the series so the DT bindings doc change comes
> first. I need an ack from the DT maintainer for it.

OK.

> 6) The most important feedback:
> This driver has been posted in many versions by now. Perhaps I could
> have been more responsive throughout the attempts, I apologize for
> that. On the other hand, you seems to have a round robin schedule for
> whom that sends a new version. :-) That makes me wonder about your
> support in the maintenance phase. I hope my concern is wrong, but how
> about that you point out a responsible maintainer? Especially since
> this seems to become a family of Cavium variants, it would help me if
> I could rely on someone providing acks for future changes. Would you
> be able to accept that role?
> 
> >
> > In porting the driver to arm64 I run into some issues.
> >
> > 1. mmc_parse_of is not capable of supporting multiple slots behind one
> >    controller. On arm64 the host controller is presented as one PCI device.
> >    There are no devices per slot as with the platform variant, so I
> >    needed to create dummy devices to make mmc_parse_of work.
> >    IMHO it would be cleaner if mmc_parse_of could be extended to cover
> >    the multiple slots case.
> 
> Yes. I agree that this make sense!
> Seems like we could try to make use of the struct device_node instead
> of the struct device.
> 
> I will try to come up with an idea, I keep you posted.
> 
> >
> > 2. Without setting MMC_CAP_1_8V_DDR DDR mode is not usable for eMMC.
> >    I would prefer to introduce a new cap flag, MMC_CAP_3_3V_DDR,
> >    if possible. Currently I need to add "mmc-ddr-1_8v" to DTS,
> >    which seems odd for a 3.3v only host controller.
> 
> This keep coming back. Both DT bindings and changing to the mmc core
> has been posted.
> 
> Allow me to help out and re-post a new series. You can build on top of
> them - I will keep you on cc.

Any news here? Can you give me a pointer?

> >
> > 3. Because the slots share the host controller using the
> >    "full-pwr-cycle" attribute turned out to not work well.
> >    I'm not 100% sure just ignoring the attribute is correct.
> 
> The full-pwr-cycle shall be set whether you are able to power cycle
> the *card*. So this binding should be a part of each slot/child node -
> if the host supports it.
> 
> >
> > For the driver to work GPIO support is required, the GPIO driver is
> > not yet available upstream. Therefore, for the time being I removed
> > the GPIO dependency from Kconfig.
> 
> Is this is about the GPIO powers or also GPIO card detect?
> 
> Anyway, I am fine with not depending on GPIO Kconfig.
> 

Meanwhile the GPIO driver was posted here:
https://lkml.org/lkml/2017/1/6/985

> [...]
> 
> Kind regards
> Uffe

Thanks for the review,
Jan

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH v10 0/8] Cavium MMC driver
  2017-01-19 14:50   ` Jan Glauber
@ 2017-01-19 17:47     ` David Daney
  2017-01-20 10:37       ` Jan Glauber
  2017-01-19 21:38     ` Ulf Hansson
  1 sibling, 1 reply; 20+ messages in thread
From: David Daney @ 2017-01-19 17:47 UTC (permalink / raw)
  To: Jan Glauber, Ulf Hansson; +Cc: linux-mmc, linux-kernel, Steven J . Hill

On 01/19/2017 06:50 AM, Jan Glauber wrote:
[...]
>
>> 4) GPIO powers should be modelled as GPIO regulators. I believe we
>> have discussed this earlier as well (I don't really recall in detail
>> about the last things). It gives us the opportunity to via the
>> regulator framework to find out the supported voltage levels. This is
>> the generic method which is used by mmc drivers, you need to adopt to
>> this as well.
>
> I've added a fixed regulator to DT:
>
>         vcc_3v3: regulator-vcc_3v3 {
>                 compatible = "regulator-fixed";
>                 regulator-name = "VCC_3V3";


Very minor point not really directly related to the MMC driver: 
"VCC_3V3" implies a general purpose supply for many things on the board. 
  This is not the case for these boards.  The "regulator" controls power 
only to eMMC and SD devices, so a name that conveys that function should 
be invented.

Actually on some boards GPIO 8 doesn't even control a regulator, but 
instead only activates a bus isolator on the control and data signals to 
the eMMC and SD devices.  In this case we would be using the regulator 
framework only because the code is already there and it happens to work, 
not because we actually have a regulator.

>                 regulator-min-microvolt = <3300000>;
>                 regulator-max-microvolt = <3300000>;
>
>                 gpio = <&gpio_6_0 8 0>;
>                 /* enable-gpio = <&gpio_6_0 8 0>; */
>                 enable-active-high;
>         };
>
> This seems to enable the gpio. Is this sufficient or do I need the
> gpio-regulator?
>

Does the "regulator-fixed" allow us to properly turn it on and off?

If not, we may have to switch to "gpio-regulator".  Which ever is 
simplest should be used.

[...]

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH v10 0/8] Cavium MMC driver
  2017-01-19 14:50   ` Jan Glauber
  2017-01-19 17:47     ` David Daney
@ 2017-01-19 21:38     ` Ulf Hansson
  1 sibling, 0 replies; 20+ messages in thread
From: Ulf Hansson @ 2017-01-19 21:38 UTC (permalink / raw)
  To: Jan Glauber; +Cc: linux-mmc, linux-kernel, David Daney, Steven J . Hill

[...]

> I've added a fixed regulator to DT:
>
>         vcc_3v3: regulator-vcc_3v3 {
>                 compatible = "regulator-fixed";
>                 regulator-name = "VCC_3V3";
>                 regulator-min-microvolt = <3300000>;
>                 regulator-max-microvolt = <3300000>;
>
>                 gpio = <&gpio_6_0 8 0>;
>                 /* enable-gpio = <&gpio_6_0 8 0>; */
>                 enable-active-high;
>         };
>
> This seems to enable the gpio. Is this sufficient or do I need the
> gpio-regulator?

Looks good to me.

[...]

>> > In porting the driver to arm64 I run into some issues.
>> >
>> > 1. mmc_parse_of is not capable of supporting multiple slots behind one
>> >    controller. On arm64 the host controller is presented as one PCI device.
>> >    There are no devices per slot as with the platform variant, so I
>> >    needed to create dummy devices to make mmc_parse_of work.
>> >    IMHO it would be cleaner if mmc_parse_of could be extended to cover
>> >    the multiple slots case.
>>
>> Yes. I agree that this make sense!
>> Seems like we could try to make use of the struct device_node instead
>> of the struct device.
>>
>> I will try to come up with an idea, I keep you posted.
>>
>> >
>> > 2. Without setting MMC_CAP_1_8V_DDR DDR mode is not usable for eMMC.
>> >    I would prefer to introduce a new cap flag, MMC_CAP_3_3V_DDR,
>> >    if possible. Currently I need to add "mmc-ddr-1_8v" to DTS,
>> >    which seems odd for a 3.3v only host controller.
>>
>> This keep coming back. Both DT bindings and changing to the mmc core
>> has been posted.
>>
>> Allow me to help out and re-post a new series. You can build on top of
>> them - I will keep you on cc.
>
> Any news here? Can you give me a pointer?

For 1), I need some more time. Feel free to try it out your self.

For 2), I am working on it. Likely in the beginning of next week I
will post something.

[...]

Kind regards
Uffe

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH v10 0/8] Cavium MMC driver
  2017-01-19 17:47     ` David Daney
@ 2017-01-20 10:37       ` Jan Glauber
  0 siblings, 0 replies; 20+ messages in thread
From: Jan Glauber @ 2017-01-20 10:37 UTC (permalink / raw)
  To: David Daney; +Cc: Ulf Hansson, linux-mmc, linux-kernel, Steven J . Hill

On Thu, Jan 19, 2017 at 09:47:33AM -0800, David Daney wrote:
> On 01/19/2017 06:50 AM, Jan Glauber wrote:
> [...]
> >
> >>4) GPIO powers should be modelled as GPIO regulators. I believe we
> >>have discussed this earlier as well (I don't really recall in detail
> >>about the last things). It gives us the opportunity to via the
> >>regulator framework to find out the supported voltage levels. This is
> >>the generic method which is used by mmc drivers, you need to adopt to
> >>this as well.
> >
> >I've added a fixed regulator to DT:
> >
> >        vcc_3v3: regulator-vcc_3v3 {
> >                compatible = "regulator-fixed";
> >                regulator-name = "VCC_3V3";
> 
> 
> Very minor point not really directly related to the MMC driver:
> "VCC_3V3" implies a general purpose supply for many things on the
> board.  This is not the case for these boards.  The "regulator"
> controls power only to eMMC and SD devices, so a name that conveys
> that function should be invented.

OK, I'll rename it to:

	mmc_supply_3v3: mmc_supply_3v3 {
        	compatible = "regulator-fixed";
		regulator-name = "mmc_supply_3v3";
		[...]


> Actually on some boards GPIO 8 doesn't even control a regulator, but
> instead only activates a bus isolator on the control and data
> signals to the eMMC and SD devices.  In this case we would be using
> the regulator framework only because the code is already there and
> it happens to work, not because we actually have a regulator.
> 
> >                regulator-min-microvolt = <3300000>;
> >                regulator-max-microvolt = <3300000>;
> >
> >                gpio = <&gpio_6_0 8 0>;
> >                /* enable-gpio = <&gpio_6_0 8 0>; */
> >                enable-active-high;
> >        };
> >
> >This seems to enable the gpio. Is this sufficient or do I need the
> >gpio-regulator?
> >
> 
> Does the "regulator-fixed" allow us to properly turn it on and off?

Yes, I've disabled all gpio calls from our mmc driver, with only the gpio 
settings in the regulator entry I get:

root@sff:~# cat /sys/kernel/debug/gpio 
gpiochip0: GPIOs 464-511, parent: pci/0000:00:06.0, gpio_thunderx:
 gpio-472 (                    |mmc_supply_3v3      ) out hi 

So the regulator driver enables GPIO 8 as it should.

> If not, we may have to switch to "gpio-regulator".  Which ever is
> simplest should be used.

"regulator-fixed" seems sufficient to me as we don't need the additional
power states that "gpio-regulator" supports.

> [...]

^ permalink raw reply	[flat|nested] 20+ messages in thread

end of thread, other threads:[~2017-01-20 10:38 UTC | newest]

Thread overview: 20+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-12-19 12:15 [PATCH v10 0/8] Cavium MMC driver Jan Glauber
2016-12-19 12:15 ` [PATCH v10 1/8] mmc: cavium: Add core MMC driver for Cavium SOCs Jan Glauber
2016-12-19 12:15 ` [PATCH v10 2/8] mmc: octeon: Add MMC platform driver for Octeon SOCs Jan Glauber
2016-12-19 12:15 ` [PATCH v10 3/8] mmc: octeon: Work-around hardware bug on cn6xxx and cnf7xxx Jan Glauber
2016-12-19 12:15 ` [PATCH v10 4/8] mmc: octeon: Add support for Octeon cn7890 Jan Glauber
2016-12-19 12:15 ` [PATCH v10 5/8] mmc: thunderx: Add MMC PCI driver for ThunderX SOCs Jan Glauber
2016-12-19 12:15 ` [PATCH v10 6/8] mmc: thunderx: Add scatter-gather DMA support Jan Glauber
2016-12-19 12:15 ` [PATCH v10 7/8] mmc: thunderx: Support DDR mode for eMMC devices Jan Glauber
2016-12-19 12:15 ` [PATCH v10 8/8] dt-bindings: mmc: Add Cavium SOCs MMC bindings Jan Glauber
2016-12-22 20:32   ` Rob Herring
2016-12-22 20:32     ` Rob Herring
2017-01-09 15:05     ` Jan Glauber
2017-01-09 15:05       ` Jan Glauber
2016-12-20 12:10 ` [PATCH v10 0/8] Cavium MMC driver Ulf Hansson
2016-12-20 12:24   ` Jan Glauber
2016-12-20 12:38     ` Ulf Hansson
2017-01-19 14:50   ` Jan Glauber
2017-01-19 17:47     ` David Daney
2017-01-20 10:37       ` Jan Glauber
2017-01-19 21:38     ` Ulf Hansson

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.