linux-arm-kernel.lists.infradead.org archive mirror
 help / color / mirror / Atom feed
* [RFC v2 0/2] Add support for Meson MX "SDIO" MMC controller
@ 2017-09-24 19:05 Martin Blumenstingl
  2017-09-24 19:05 ` [RFC v2 1/2] dt-bindings: mmc: Document the Amlogic Meson8 and Meson8b SDIO bindings Martin Blumenstingl
                   ` (2 more replies)
  0 siblings, 3 replies; 10+ messages in thread
From: Martin Blumenstingl @ 2017-09-24 19:05 UTC (permalink / raw)
  To: linux-arm-kernel

This is the successor to Carlo Caione's "Add support for Amlogic Meson
MMC driver" series (v5) from [0].
This new driver is for the "SDIO" controller found in Amlogic Meson6,
Meson8 and Meson8b SoCs and supports an internal mux to allow connecting
three cards to it.


changes since RFC v1 at [1]:
- added COMMON_CLK dependency as reported by the kbuild test robot
- use of_platform_device_{create,destroy} instead of open-coding it's
  logic
- moved struct device (which was an array) from meson_mx_mmc_host to
  the corresponding meson_mx_mmc_slot
- use struct mmc_command's busy_timeout instead of hard-coding the
  timeout values in meson_mx_mmc_start_cmd()
- don't use arrays with only one element for the clock parents in
  meson_mx_mmc_register_clks()
- removed the wrapper functions meson_mx_mmc_readl() meson_mx_mmc_writel()
- allow setting the MMC clock to 0 for UHS speed mode (the actual
  hardware clock cannot be gated as far as I know, so instead the
  lowest supported rate is chosen)
- remove unused #include <linux/init.h>
- add MMC_CAP_ERASE
- removed multiple slot support after discussing this with Ulf
  (this is a feature that needs to be part of the MMC core before drivers
  can use it)
- removed SDIO interrupt support (as I currently don't have a way to
  test it)
- merge meson_mx_mmc_apply_ios into meson_mx_mmc_set_ios (as that's
  the only place where it's needed after removing multiple slot support)
- updated the commit message of the driver patch to indicate the
  difference between the meson-mx-sdio.c and meson-gx.c (and the "still
  missing SDHC") driver
- NOTE: I did not add Rob's ACK on the dt-bindings patch because I
  introduced the "mmc-slot" compatible for the child nodes as suggested
  by Ulf (and I want confirmation from the DT maintainers that I did this
  correctly)


(notable) changes since Carlo's latest from [0] version are:
- renamed the driver to meson-mx-sdio (Amlogic's reference kernel calls
  the driver "aml_sdio" as there is a second MMC controller in these SoCs
  which they call the "SDHC controller"). do the same with our driver to
  avoid confusion once we add support for the second controller (which uses
  a completely different register layout)
- add support for the internal "mux" in this MMC controller (which allows
  connecting up to three devices to the the controller - at the cost of
  performance though since the controller can only process one request at
  a time). The driver registers a new device for each sub-node, which is
  then fed into the MMC framework to allow per-slot configuration using
  devicetree (see the example in the documentation)
- use the common clock framework internally for managing the MMC clock
  (there is a fixed-factor clock in the controller which takes clk81 as
   input and divides it's clock by two and a divider clock which takes
   the result from the fixed-factor clock as input)
- support the regulators provided by the MMC framework
- support for GPIO-based card-detection and read-only-detection through
  the MMC framework
- use of the <linux/bitfield.h> FIELD_PREP and FIELD_GET macros where it
  make sense (and thus the code easier to read)
- re-worked locking (based on the locking in dw_mmc as that also provides
  multiple "MMC slots")


tests done so far (use-cases which involve two cards were done only with
RFC v1):
- reading an OLD 256MiB SD card (which uses only a 1-bit bus) works fine
  (sha1sum of the whole device matches with what I get on my PC's
  card-reader)
- reading a somewhat more modern class 10 SD card and putting Arch Linux
  ARM on it (and using that as root file system)
- it successfully detects the RTL8723BS SDIO wifi chip in my device (even
  if the SD card is also enabled)
- reading a 128MiB file from the SD card while scanning wifi networks on
  the RTL8723BS card does not seem to result in any corruption (sha1sum
  of the read file seems to match)
- read speed of my class 10 SD card: ~15MiB/s
- (unfortunately I could NOT test downloading a file over wifi to the SD
  card because the RTL8723BS driver refuses to see any wifi networks, but
  that might be a problem on the RTL8723BS driver side since I don't get
  any error and the driver has just landed a few weeks ago in staging)


[0] http://lists.infradead.org/pipermail/linux-arm-kernel/2016-February/412136.html
[1] http://lists.infradead.org/pipermail/linux-amlogic/2017-May/003466.html


Carlo Caione (2):
  dt-bindings: mmc: Document the Amlogic Meson8 and Meson8b SDIO
    bindings
  mmc: meson-mx-sdio: Add a driver for the Amlogic Meson8 and Meson8b
    SoCs

 .../bindings/mmc/amlogic,meson-mx-sdio.txt         |  52 ++
 drivers/mmc/host/Kconfig                           |  13 +
 drivers/mmc/host/Makefile                          |   1 +
 drivers/mmc/host/meson-mx-sdio.c                   | 795 +++++++++++++++++++++
 4 files changed, 861 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/mmc/amlogic,meson-mx-sdio.txt
 create mode 100644 drivers/mmc/host/meson-mx-sdio.c

-- 
2.14.1

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

* [RFC v2 1/2] dt-bindings: mmc: Document the Amlogic Meson8 and Meson8b SDIO bindings
  2017-09-24 19:05 [RFC v2 0/2] Add support for Meson MX "SDIO" MMC controller Martin Blumenstingl
@ 2017-09-24 19:05 ` Martin Blumenstingl
  2017-09-27 19:37   ` Rob Herring
  2017-10-02  7:55   ` Ulf Hansson
  2017-09-24 19:05 ` [RFC v2 2/2] mmc: meson-mx-sdio: Add a driver for the Amlogic Meson8 and Meson8b SoCs Martin Blumenstingl
  2017-09-27 19:36 ` [RFC v2 0/2] Add support for Meson MX "SDIO" MMC controller Rob Herring
  2 siblings, 2 replies; 10+ messages in thread
From: Martin Blumenstingl @ 2017-09-24 19:05 UTC (permalink / raw)
  To: linux-arm-kernel

From: Carlo Caione <carlo@endlessm.com>

This documents the devicetree bindings for the SDIO/MMC host found in
Amlogic Meson8 and Meson8b SoCs. It supports the SD specification v2.0
and the eMMC specification v4.41.
It has an internal "mux" which allows connecting up to three MMC devices
to it. The maximum supported bus-width is 4-bits.

Amlogic's GPL kernel sources call it "SDIO" to differentiate it from the
other MMC controller in (at least the Meson8 and Meson8b) the SoCs (they
call the other one "SDHC", which supports a bus-width of up to 8-bits).

Signed-off-by: Carlo Caione <carlo@endlessm.com>
Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
---
 .../bindings/mmc/amlogic,meson-mx-sdio.txt         | 52 ++++++++++++++++++++++
 1 file changed, 52 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/mmc/amlogic,meson-mx-sdio.txt

diff --git a/Documentation/devicetree/bindings/mmc/amlogic,meson-mx-sdio.txt b/Documentation/devicetree/bindings/mmc/amlogic,meson-mx-sdio.txt
new file mode 100644
index 000000000000..124ea362eec9
--- /dev/null
+++ b/Documentation/devicetree/bindings/mmc/amlogic,meson-mx-sdio.txt
@@ -0,0 +1,52 @@
+* Amlogic Meson6, Meson8 and Meson8b SDIO/MMC controller
+
+The highspeed MMC host controller on Amlogic SoCs provides an interface
+for MMC, SD, SDIO and SDHC types of memory cards.
+
+Supported maximum speeds are the ones of the eMMC standard 4.41 as well
+as the speed of SD standard 2.0.
+
+The hardware provides an internal "mux" which allows up to three slots
+to be controlled. Only one slot can be accessed at a time.
+
+Required properties:
+ - compatible : must be one of
+	- "amlogic,meson8-sdio"
+	- "amlogic,meson8b-sdio"
+	along with the generic "amlogic,meson-mx-sdio"
+ - reg : mmc controller base registers
+ - interrupts : mmc controller interrupt
+ - #address-cells : must be 1
+ - size-cells : must be 0
+ - clocks : phandle to clock providers
+ - clock-names : must contain "core" and "clkin"
+
+Required child nodes:
+A node for each slot provided by the MMC controller is required.
+
+Required properties on each child node (= slot):
+ - compatible : must be "mmc-slot" (see mmc.txt within this directory)
+ - reg : the slot (or "port") ID
+
+Optional properties on each child node (= slot):
+ - bus-width : must be 1 or 4 (8-bit bus is not supported)
+ - for cd and all other additional generic mmc parameters
+   please refer to mmc.txt within this directory
+
+Examples:
+	mmc at c1108c20 {
+		compatible = "amlogic,meson8-sdio", "amlogic,meson-mx-sdio";
+		reg = <0xc1108c20 0x20>;
+		interrupts = <0 28 1>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		clocks = <&clkc CLKID_SDIO>, <&clkc CLKID_CLK81>;
+		clock-names = "core", "clkin";
+
+		slot at 1 {
+			compatible = "mmc-slot";
+			reg = <1>;
+
+			bus-width = <4>;
+		};
+	};
-- 
2.14.1

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

* [RFC v2 2/2] mmc: meson-mx-sdio: Add a driver for the Amlogic Meson8 and Meson8b SoCs
  2017-09-24 19:05 [RFC v2 0/2] Add support for Meson MX "SDIO" MMC controller Martin Blumenstingl
  2017-09-24 19:05 ` [RFC v2 1/2] dt-bindings: mmc: Document the Amlogic Meson8 and Meson8b SDIO bindings Martin Blumenstingl
@ 2017-09-24 19:05 ` Martin Blumenstingl
  2017-10-02  8:08   ` Ulf Hansson
  2017-09-27 19:36 ` [RFC v2 0/2] Add support for Meson MX "SDIO" MMC controller Rob Herring
  2 siblings, 1 reply; 10+ messages in thread
From: Martin Blumenstingl @ 2017-09-24 19:05 UTC (permalink / raw)
  To: linux-arm-kernel

From: Carlo Caione <carlo@endlessm.com>

Add a driver for the SDIO/MMC host found on the Amlogic Meson SoCs. This
is an MMC controller which provides an interface between the application
processor and various memory cards. It supports the SD specification
v2.0 and the eMMC specification v4.41.

The controller provides an internal "mux" which allows connecting up to
three MMC devices to it. Only one device can be used at a time though
since the registers are shared across all devices. The driver takes care
of synchronizing access (similar to the dw_mmc driver).
The maximum supported bus-width is 4-bits.

Amlogic's GPL kernel sources call the corresponding driver "aml_sdio" to
differentiate it from the other MMC controller in (at least the Meson8
and Meson8b) the SoCs (they call the other drivers aml_sdhc and
aml_sdhc_m8, which seem to support a bus-width of up to 8-bits). This
means that there are three different MMC host controller IP blocks from
Amlogic (each of them with completely own register layout and features):
- "SDIO": 1 and 4 bit bus width, support for high-speed modes up to
  UHS-I SDR50, part of Meson6, Meson8 and Meson8b (the driver from this
  patch targets this controller)
- "SDHC": 1, 4 and 8 bit bus width, compatible with standard iNAND
  interface, support for speeds up to HS200 and MMC spec up to version
  4.5x, part of Meson8 and Meson8b SoCs (there is no mainline driver
  for this controller yet)
- "SDEMMC": 1, 4 and 8 bit bus width, support for speeds up to HS400
  and MMC spec up to version 5.0, part of the Meson GX (64-bit) SoCs
  (supported by the meson-gx MMC host driver)

Signed-off-by: Carlo Caione <carlo@endlessm.com>
Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
---
 drivers/mmc/host/Kconfig         |  13 +
 drivers/mmc/host/Makefile        |   1 +
 drivers/mmc/host/meson-mx-sdio.c | 795 +++++++++++++++++++++++++++++++++++++++
 3 files changed, 809 insertions(+)
 create mode 100644 drivers/mmc/host/meson-mx-sdio.c

diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index 8c15637178ff..a27b99c77661 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -352,6 +352,19 @@ config MMC_MESON_GX
 
 	  If you have a controller with this interface, say Y here.
 
+config MMC_MESON_MX_SDIO
+	tristate "Amlogic Meson6/Meson8/Meson8b SD/MMC Host Controller support"
+	depends on ARCH_MESON || COMPILE_TEST
+	depends on COMMON_CLK
+	depends on HAS_DMA
+	depends on OF
+	help
+	  This selects support for the SD/MMC Host Controller on
+	  Amlogic Meson6, Meson8 and Meson8b SoCs.
+
+	  If you have a controller with this interface, say Y or M here.
+	  If unsure, say N.
+
 config MMC_MOXART
 	tristate "MOXART SD/MMC Host Controller support"
 	depends on ARCH_MOXART && MMC
diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile
index 303f5cd46cd9..0de72a531240 100644
--- a/drivers/mmc/host/Makefile
+++ b/drivers/mmc/host/Makefile
@@ -64,6 +64,7 @@ obj-$(CONFIG_MMC_VUB300)	+= vub300.o
 obj-$(CONFIG_MMC_USHC)		+= ushc.o
 obj-$(CONFIG_MMC_WMT)		+= wmt-sdmmc.o
 obj-$(CONFIG_MMC_MESON_GX)	+= meson-gx-mmc.o
+obj-$(CONFIG_MMC_MESON_MX_SDIO)	+= meson-mx-sdio.o
 obj-$(CONFIG_MMC_MOXART)	+= moxart-mmc.o
 obj-$(CONFIG_MMC_SUNXI)		+= sunxi-mmc.o
 obj-$(CONFIG_MMC_USDHI6ROL0)	+= usdhi6rol0.o
diff --git a/drivers/mmc/host/meson-mx-sdio.c b/drivers/mmc/host/meson-mx-sdio.c
new file mode 100644
index 000000000000..aa5d35ee7359
--- /dev/null
+++ b/drivers/mmc/host/meson-mx-sdio.c
@@ -0,0 +1,795 @@
+/*
+ * meson-mx-sdio.c - Meson6, Meson8 and Meson8b SDIO/MMC Host Controller
+ *
+ * Copyright (C) 2015 Endless Mobile, Inc.
+ * Author: Carlo Caione <carlo@endlessm.com>
+ * Copyright (C) 2017 Martin Blumenstingl <martin.blumenstingl@googlemail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ */
+
+#include <linux/bitfield.h>
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/platform_device.h>
+#include <linux/of_platform.h>
+#include <linux/timer.h>
+#include <linux/types.h>
+
+#include <linux/mmc/host.h>
+#include <linux/mmc/mmc.h>
+#include <linux/mmc/sdio.h>
+#include <linux/mmc/slot-gpio.h>
+
+#define MESON_MX_SDIO_ARGU					0x00
+
+#define MESON_MX_SDIO_SEND					0x04
+	#define MESON_MX_SDIO_SEND_COMMAND_INDEX_MASK		GENMASK(7, 0)
+	#define MESON_MX_SDIO_SEND_CMD_RESP_BITS_MASK		GENMASK(15, 8)
+	#define MESON_MX_SDIO_SEND_RESP_WITHOUT_CRC7		BIT(16)
+	#define MESON_MX_SDIO_SEND_RESP_HAS_DATA		BIT(17)
+	#define MESON_MX_SDIO_SEND_RESP_CRC7_FROM_8		BIT(18)
+	#define MESON_MX_SDIO_SEND_CHECK_DAT0_BUSY		BIT(19)
+	#define MESON_MX_SDIO_SEND_DATA				BIT(20)
+	#define MESON_MX_SDIO_SEND_USE_INT_WINDOW		BIT(21)
+	#define MESON_MX_SDIO_SEND_REPEAT_PACKAGE_TIMES_MASK	GENMASK(31, 24)
+
+#define MESON_MX_SDIO_CONF					0x08
+	#define MESON_MX_SDIO_CONF_CMD_CLK_DIV_SHIFT		0
+	#define MESON_MX_SDIO_CONF_CMD_CLK_DIV_WIDTH		10
+	#define MESON_MX_SDIO_CONF_CMD_DISABLE_CRC		BIT(10)
+	#define MESON_MX_SDIO_CONF_CMD_OUT_AT_POSITIVE_EDGE	BIT(11)
+	#define MESON_MX_SDIO_CONF_CMD_ARGUMENT_BITS_MASK	GENMASK(17, 12)
+	#define MESON_MX_SDIO_CONF_RESP_LATCH_AT_NEGATIVE_EDGE	BIT(18)
+	#define MESON_MX_SDIO_CONF_DATA_LATCH_AT_NEGATIVE_EDGE	BIT(19)
+	#define MESON_MX_SDIO_CONF_BUS_WIDTH			BIT(20)
+	#define MESON_MX_SDIO_CONF_M_ENDIAN_MASK		GENMASK(22, 21)
+	#define MESON_MX_SDIO_CONF_WRITE_NWR_MASK		GENMASK(28, 23)
+	#define MESON_MX_SDIO_CONF_WRITE_CRC_OK_STATUS_MASK	GENMASK(31, 29)
+
+#define MESON_MX_SDIO_IRQS					0x0c
+	#define MESON_MX_SDIO_IRQS_STATUS_STATE_MACHINE_MASK	GENMASK(3, 0)
+	#define MESON_MX_SDIO_IRQS_CMD_BUSY			BIT(4)
+	#define MESON_MX_SDIO_IRQS_RESP_CRC7_OK			BIT(5)
+	#define MESON_MX_SDIO_IRQS_DATA_READ_CRC16_OK		BIT(6)
+	#define MESON_MX_SDIO_IRQS_DATA_WRITE_CRC16_OK		BIT(7)
+	#define MESON_MX_SDIO_IRQS_IF_INT			BIT(8)
+	#define MESON_MX_SDIO_IRQS_CMD_INT			BIT(9)
+	#define MESON_MX_SDIO_IRQS_STATUS_INFO_MASK		GENMASK(15, 12)
+	#define MESON_MX_SDIO_IRQS_TIMING_OUT_INT		BIT(16)
+	#define MESON_MX_SDIO_IRQS_AMRISC_TIMING_OUT_INT_EN	BIT(17)
+	#define MESON_MX_SDIO_IRQS_ARC_TIMING_OUT_INT_EN	BIT(18)
+	#define MESON_MX_SDIO_IRQS_TIMING_OUT_COUNT_MASK	GENMASK(31, 19)
+
+#define MESON_MX_SDIO_IRQC					0x10
+	#define MESON_MX_SDIO_IRQC_ARC_IF_INT_EN		BIT(3)
+	#define MESON_MX_SDIO_IRQC_ARC_CMD_INT_EN		BIT(4)
+	#define MESON_MX_SDIO_IRQC_IF_CONFIG_MASK		GENMASK(7, 6)
+	#define MESON_MX_SDIO_IRQC_FORCE_DATA_CLK		BIT(8)
+	#define MESON_MX_SDIO_IRQC_FORCE_DATA_CMD		BIT(9)
+	#define MESON_MX_SDIO_IRQC_FORCE_DATA_DAT_MASK		GENMASK(10, 13)
+	#define MESON_MX_SDIO_IRQC_SOFT_RESET			BIT(15)
+	#define MESON_MX_SDIO_IRQC_FORCE_HALT			BIT(30)
+	#define MESON_MX_SDIO_IRQC_HALT_HOLE			BIT(31)
+
+#define MESON_MX_SDIO_MULT					0x14
+	#define MESON_MX_SDIO_MULT_PORT_SEL_MASK		GENMASK(1, 0)
+	#define MESON_MX_SDIO_MULT_MEMORY_STICK_ENABLE		BIT(2)
+	#define MESON_MX_SDIO_MULT_MEMORY_STICK_SCLK_ALWAYS	BIT(3)
+	#define MESON_MX_SDIO_MULT_STREAM_ENABLE		BIT(4)
+	#define MESON_MX_SDIO_MULT_STREAM_8BITS_MODE		BIT(5)
+	#define MESON_MX_SDIO_MULT_WR_RD_OUT_INDEX		BIT(8)
+	#define MESON_MX_SDIO_MULT_DAT0_DAT1_SWAPPED		BIT(10)
+	#define MESON_MX_SDIO_MULT_DAT1_DAT0_SWAPPED		BIT(11)
+	#define MESON_MX_SDIO_MULT_RESP_READ_INDEX_MASK		GENMASK(15, 12)
+
+#define MESON_MX_SDIO_ADDR					0x18
+
+#define MESON_MX_SDIO_EXT					0x1c
+	#define MESON_MX_SDIO_EXT_DATA_RW_NUMBER_MASK		GENMASK(29, 16)
+
+#define MESON_MX_SDIO_BOUNCE_REQ_SIZE				(128 * 1024)
+#define MESON_MX_SDIO_RESPONSE_CRC16_BITS			(16 - 1)
+#define MESON_MX_SDIO_MAX_SLOTS					3
+
+struct meson_mx_mmc_slot {
+	struct device			*dev;
+	struct mmc_host			*mmc;
+	struct meson_mx_mmc_host	*host;
+
+	struct mmc_request		*mrq;
+	struct mmc_command		*cmd;
+	int				error;
+
+	unsigned int			id;
+};
+
+struct meson_mx_mmc_host {
+	struct device			*dev;
+
+	struct clk			*parent_clk;
+	struct clk			*core_clk;
+	struct clk_divider		cfg_div;
+	struct clk			*cfg_div_clk;
+	struct clk_fixed_factor		fixed_factor;
+	struct clk			*fixed_factor_clk;
+
+	void __iomem			*base;
+	int				irq;
+	spinlock_t			irq_lock;
+
+	struct timer_list		cmd_timeout;
+
+	struct meson_mx_mmc_slot	*slot;
+};
+
+static void meson_mx_mmc_mask_bits(struct mmc_host *mmc, char reg, u32 mask,
+				   u32 val)
+{
+	struct meson_mx_mmc_slot *slot = mmc_priv(mmc);
+	u32 regval;
+
+	regval = readl(slot->host->base + reg);
+	regval &= ~mask;
+	regval |= (val & mask);
+
+	writel(regval, slot->host->base + reg);
+}
+
+static void meson_mx_mmc_soft_reset(struct meson_mx_mmc_host *host)
+{
+	writel(MESON_MX_SDIO_IRQC_SOFT_RESET, host->base + MESON_MX_SDIO_IRQC);
+	udelay(2);
+}
+
+static struct mmc_command *meson_mx_mmc_get_next_cmd(struct mmc_command *cmd)
+{
+	if (cmd->opcode == MMC_SET_BLOCK_COUNT && !cmd->error)
+		return cmd->mrq->cmd;
+	else if (mmc_op_multi(cmd->opcode) &&
+		 (!cmd->mrq->sbc || cmd->error || cmd->data->error))
+		return cmd->mrq->stop;
+	else
+		return NULL;
+}
+
+static void meson_mx_mmc_start_cmd(struct mmc_host *mmc,
+				   struct mmc_command *cmd)
+{
+	struct meson_mx_mmc_slot *slot = mmc_priv(mmc);
+	unsigned int pack_size;
+	unsigned long irqflags, timeout;
+	u32 mult, send = 0, ext = 0;
+
+	slot->cmd = cmd;
+
+	if (cmd->busy_timeout)
+		timeout = msecs_to_jiffies(cmd->busy_timeout);
+	else
+		timeout = msecs_to_jiffies(1000);
+
+	switch (mmc_resp_type(cmd)) {
+	case MMC_RSP_R1:
+	case MMC_RSP_R1B:
+	case MMC_RSP_R3:
+		/* 7 (CMD) + 32 (response) + 7 (CRC) -1 */
+		send |= FIELD_PREP(MESON_MX_SDIO_SEND_CMD_RESP_BITS_MASK, 45);
+		break;
+	case MMC_RSP_R2:
+		/* 7 (CMD) + 120 (response) + 7 (CRC) -1 */
+		send |= FIELD_PREP(MESON_MX_SDIO_SEND_CMD_RESP_BITS_MASK, 133);
+		send |= MESON_MX_SDIO_SEND_RESP_CRC7_FROM_8;
+		break;
+	default:
+		break;
+	}
+
+	if (!(cmd->flags & MMC_RSP_CRC))
+		send |= MESON_MX_SDIO_SEND_RESP_WITHOUT_CRC7;
+
+	if (cmd->flags & MMC_RSP_BUSY)
+		send |= MESON_MX_SDIO_SEND_CHECK_DAT0_BUSY;
+
+	if (cmd->data) {
+		send |= FIELD_PREP(MESON_MX_SDIO_SEND_REPEAT_PACKAGE_TIMES_MASK,
+				   (cmd->data->blocks - 1));
+
+		pack_size = cmd->data->blksz * BITS_PER_BYTE;
+		if (mmc->ios.bus_width == MMC_BUS_WIDTH_4)
+			pack_size += MESON_MX_SDIO_RESPONSE_CRC16_BITS * 4;
+		else
+			pack_size += MESON_MX_SDIO_RESPONSE_CRC16_BITS * 1;
+
+		ext |= FIELD_PREP(MESON_MX_SDIO_EXT_DATA_RW_NUMBER_MASK,
+				  pack_size);
+
+		if (cmd->data->flags & MMC_DATA_WRITE)
+			send |= MESON_MX_SDIO_SEND_DATA;
+		else
+			send |= MESON_MX_SDIO_SEND_RESP_HAS_DATA;
+
+		cmd->data->bytes_xfered = 0;
+	}
+
+	send |= FIELD_PREP(MESON_MX_SDIO_SEND_COMMAND_INDEX_MASK,
+			   (0x40 | cmd->opcode));
+
+	spin_lock_irqsave(&slot->host->irq_lock, irqflags);
+
+	mult = readl(slot->host->base + MESON_MX_SDIO_MULT);
+	mult &= ~MESON_MX_SDIO_MULT_PORT_SEL_MASK;
+	mult |= FIELD_PREP(MESON_MX_SDIO_MULT_PORT_SEL_MASK, slot->id);
+	mult |= BIT(31);
+	writel(mult, slot->host->base + MESON_MX_SDIO_MULT);
+
+	/* enable the CMD done interrupt */
+	meson_mx_mmc_mask_bits(mmc, MESON_MX_SDIO_IRQC,
+			       MESON_MX_SDIO_IRQC_ARC_CMD_INT_EN,
+			       MESON_MX_SDIO_IRQC_ARC_CMD_INT_EN);
+
+	/* clear pending interrupts */
+	meson_mx_mmc_mask_bits(mmc, MESON_MX_SDIO_IRQS,
+			       MESON_MX_SDIO_IRQS_CMD_INT,
+			       MESON_MX_SDIO_IRQS_CMD_INT);
+
+	writel(cmd->arg, slot->host->base + MESON_MX_SDIO_ARGU);
+	writel(ext, slot->host->base + MESON_MX_SDIO_EXT);
+	writel(send, slot->host->base + MESON_MX_SDIO_SEND);
+
+	spin_unlock_irqrestore(&slot->host->irq_lock, irqflags);
+
+	mod_timer(&slot->host->cmd_timeout, jiffies + timeout);
+}
+
+static void meson_mx_mmc_request_done(struct meson_mx_mmc_slot *slot)
+{
+	struct mmc_request *mrq;
+
+	mrq = slot->mrq;
+
+	slot->mrq = NULL;
+	slot->cmd = NULL;
+
+	mmc_request_done(slot->mmc, mrq);
+}
+
+static void meson_mx_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
+{
+	struct meson_mx_mmc_slot *slot = mmc_priv(mmc);
+	unsigned short vdd = ios->vdd;
+	unsigned long clk_rate = ios->clock;
+
+	switch (ios->bus_width) {
+	case MMC_BUS_WIDTH_1:
+		meson_mx_mmc_mask_bits(mmc, MESON_MX_SDIO_CONF,
+				       MESON_MX_SDIO_CONF_BUS_WIDTH, 0);
+		break;
+
+	case MMC_BUS_WIDTH_4:
+		meson_mx_mmc_mask_bits(mmc, MESON_MX_SDIO_CONF,
+				       MESON_MX_SDIO_CONF_BUS_WIDTH,
+				       MESON_MX_SDIO_CONF_BUS_WIDTH);
+		break;
+
+	case MMC_BUS_WIDTH_8:
+	default:
+		dev_err(mmc_dev(mmc), "unsupported bus width: %d\n",
+			ios->bus_width);
+		slot->error = -EINVAL;
+		return;
+	}
+
+	slot->error = clk_set_rate(slot->host->cfg_div_clk, ios->clock);
+	if (slot->error) {
+		dev_warn(mmc_dev(mmc),
+				"failed to set MMC clock to %lu: %d\n",
+				clk_rate, slot->error);
+		return;
+	}
+
+	mmc->actual_clock = clk_get_rate(slot->host->cfg_div_clk);
+
+	switch (ios->power_mode) {
+	case MMC_POWER_OFF:
+		vdd = 0;
+		/* fall-through: */
+	case MMC_POWER_UP:
+		if (!IS_ERR(mmc->supply.vmmc)) {
+			slot->error = mmc_regulator_set_ocr(mmc,
+							    mmc->supply.vmmc,
+							    vdd);
+			if (slot->error)
+				return;
+		}
+		break;
+	}
+}
+
+static int meson_mx_mmc_map_dma(struct mmc_host *mmc, struct mmc_request *mrq)
+{
+	struct mmc_data *data = mrq->data;
+	int dma_len;
+	struct scatterlist *sg;
+
+	if (!data)
+		return 0;
+
+	sg = data->sg;
+	if (sg->offset & 3 || sg->length & 3) {
+		dev_err(mmc_dev(mmc),
+			"unaligned scatterlist: offset %x length %d\n",
+			sg->offset, sg->length);
+		return -EINVAL;
+	}
+
+	dma_len = dma_map_sg(mmc_dev(mmc), data->sg, data->sg_len,
+			     mmc_get_dma_dir(data));
+	if (dma_len <= 0) {
+		dev_err(mmc_dev(mmc), "dma_map_sg failed\n");
+		return -ENOMEM;
+	}
+
+	return 0;
+}
+
+static void meson_mx_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq)
+{
+	struct meson_mx_mmc_slot *slot = mmc_priv(mmc);
+	struct meson_mx_mmc_host *host = slot->host;
+	struct mmc_command *cmd = mrq->cmd;
+
+	if (!slot->error)
+		slot->error = meson_mx_mmc_map_dma(mmc, mrq);
+
+	if (slot->error) {
+		cmd->error = slot->error;
+		mmc_request_done(mmc, mrq);
+		return;
+	}
+
+	slot->mrq = mrq;
+
+	if (mrq->data)
+		writel(sg_dma_address(mrq->data->sg),
+		       host->base + MESON_MX_SDIO_ADDR);
+
+	if (mrq->sbc)
+		meson_mx_mmc_start_cmd(mmc, mrq->sbc);
+	else
+		meson_mx_mmc_start_cmd(mmc, mrq->cmd);
+}
+
+static int meson_mx_mmc_card_busy(struct mmc_host *mmc)
+{
+	struct meson_mx_mmc_slot *slot = mmc_priv(mmc);
+	u32 irqc = readl(slot->host->base + MESON_MX_SDIO_IRQC);
+
+	return !!(irqc & MESON_MX_SDIO_IRQC_FORCE_DATA_DAT_MASK);
+}
+
+static void meson_mx_mmc_read_response(struct mmc_host *mmc,
+				       struct mmc_command *cmd)
+{
+	struct meson_mx_mmc_slot *slot = mmc_priv(mmc);
+	struct meson_mx_mmc_host *host = slot->host;
+	u32 mult;
+	int i, resp[4];
+
+	mult = readl(host->base + MESON_MX_SDIO_MULT);
+	mult |= MESON_MX_SDIO_MULT_WR_RD_OUT_INDEX;
+	mult &= ~MESON_MX_SDIO_MULT_RESP_READ_INDEX_MASK;
+	mult |= FIELD_PREP(MESON_MX_SDIO_MULT_RESP_READ_INDEX_MASK, 0);
+	writel(mult, host->base + MESON_MX_SDIO_MULT);
+
+	if (cmd->flags & MMC_RSP_136) {
+		for (i = 0; i <= 3; i++)
+			resp[3 - i] = readl(host->base + MESON_MX_SDIO_ARGU);
+		cmd->resp[0] = (resp[0] << 8) | ((resp[1] >> 24) & 0xff);
+		cmd->resp[1] = (resp[1] << 8) | ((resp[2] >> 24) & 0xff);
+		cmd->resp[2] = (resp[2] << 8) | ((resp[3] >> 24) & 0xff);
+		cmd->resp[3] = (resp[3] << 8);
+	} else if (cmd->flags & MMC_RSP_PRESENT) {
+		cmd->resp[0] = readl(host->base + MESON_MX_SDIO_ARGU);
+	}
+}
+
+static irqreturn_t meson_mx_mmc_process_cmd_irq(struct meson_mx_mmc_slot *slot,
+						u32 irqs, u32 send)
+{
+	struct mmc_command *cmd = slot->cmd;
+
+	/*
+	 * NOTE: even though it shouldn't happen we sometimes get command
+	 * interrupts twice (at least this is what it looks like). Ideally
+	 * we find out why this happens and warn here as soon as it occurs.
+	 */
+	if (!cmd)
+		return IRQ_HANDLED;
+
+	cmd->error = 0;
+	meson_mx_mmc_read_response(slot->mmc, cmd);
+
+	if (cmd->data) {
+		if (!((irqs & MESON_MX_SDIO_IRQS_DATA_READ_CRC16_OK) ||
+		      (irqs & MESON_MX_SDIO_IRQS_DATA_WRITE_CRC16_OK)))
+			cmd->error = -EILSEQ;
+	} else {
+		if (!((irqs & MESON_MX_SDIO_IRQS_RESP_CRC7_OK) ||
+		      (send & MESON_MX_SDIO_SEND_RESP_WITHOUT_CRC7)))
+			cmd->error = -EILSEQ;
+	}
+
+	return IRQ_WAKE_THREAD;
+}
+
+static irqreturn_t meson_mx_mmc_irq(int irq, void *data)
+{
+	struct meson_mx_mmc_host *host = (void *) data;
+	u32 irqs, send;
+	unsigned long irqflags;
+	irqreturn_t ret;
+
+	spin_lock_irqsave(&host->irq_lock, irqflags);
+
+	irqs = readl(host->base + MESON_MX_SDIO_IRQS);
+	send = readl(host->base + MESON_MX_SDIO_SEND);
+
+	if (irqs & MESON_MX_SDIO_IRQS_CMD_INT)
+		ret = meson_mx_mmc_process_cmd_irq(host->slot, irqs, send);
+	else
+		ret = IRQ_HANDLED;
+
+	/* finally ACK all pending interrupts */
+	writel(irqs, host->base + MESON_MX_SDIO_IRQS);
+
+	spin_unlock_irqrestore(&host->irq_lock, irqflags);
+
+	return ret;
+}
+
+static irqreturn_t meson_mx_mmc_irq_thread(int irq, void *irq_data)
+{
+	struct meson_mx_mmc_host *host = (void *) irq_data;
+	struct meson_mx_mmc_slot *slot = host->slot;
+	struct mmc_command *cmd = slot->cmd, *next_cmd;
+
+	if (WARN_ON(!cmd))
+		return IRQ_HANDLED;
+
+	del_timer_sync(&host->cmd_timeout);
+
+	if (cmd->data) {
+		dma_unmap_sg(mmc_dev(slot->mmc), cmd->data->sg,
+				cmd->data->sg_len,
+				mmc_get_dma_dir(cmd->data));
+
+		cmd->data->bytes_xfered = cmd->data->blksz * cmd->data->blocks;
+	}
+
+	next_cmd = meson_mx_mmc_get_next_cmd(cmd);
+	if (next_cmd)
+		meson_mx_mmc_start_cmd(slot->mmc, next_cmd);
+	else
+		meson_mx_mmc_request_done(slot);
+
+	return IRQ_HANDLED;
+}
+
+static void meson_mx_mmc_timeout(unsigned long arg)
+{
+	struct meson_mx_mmc_host *host = (void *) arg;
+	struct meson_mx_mmc_slot *slot;
+	unsigned long irqflags;
+	u32 irqc;
+
+	spin_lock_irqsave(&host->irq_lock, irqflags);
+
+	/* disable the CMD interrupt */
+	irqc = readl(host->base + MESON_MX_SDIO_IRQC);
+	irqc &= ~MESON_MX_SDIO_IRQC_ARC_CMD_INT_EN;
+	writel(irqc, host->base + MESON_MX_SDIO_IRQC);
+
+	spin_unlock_irqrestore(&host->irq_lock, irqflags);
+
+	/*
+	 * skip the timeout handling if the interrupt handler already processed
+	 * the command.
+	 */
+	if (!host->slot->cmd)
+		return;
+
+	dev_dbg(mmc_dev(host->slot->mmc),
+		"Timeout on CMD%u (IRQS = 0x%08x, ARGU = 0x%08x)\n",
+		slot->cmd->opcode, readl(host->base + MESON_MX_SDIO_IRQS),
+		readl(host->base + MESON_MX_SDIO_ARGU));
+
+	host->slot->cmd->error = -ETIMEDOUT;
+
+	meson_mx_mmc_request_done(host->slot);
+}
+
+static struct mmc_host_ops meson_mx_mmc_ops = {
+	.request		= meson_mx_mmc_request,
+	.set_ios		= meson_mx_mmc_set_ios,
+	.card_busy		= meson_mx_mmc_card_busy,
+	.get_cd			= mmc_gpio_get_cd,
+	.get_ro			= mmc_gpio_get_ro,
+};
+
+static int meson_mx_mmc_slot_probe(struct device *slot_dev,
+				   struct meson_mx_mmc_host *host)
+{
+	struct meson_mx_mmc_slot *slot;
+	struct mmc_host *mmc;
+	unsigned int id;
+	int ret;
+
+	if (of_property_read_u32(slot_dev->of_node, "reg", &id)) {
+		dev_err(slot_dev, "missing 'reg' property\n");
+		return -EINVAL;
+	}
+
+	if (id >= MESON_MX_SDIO_MAX_SLOTS) {
+		dev_err(slot_dev, "invalid 'reg' property value %d\n", id);
+		return -EINVAL;
+	}
+
+	mmc = mmc_alloc_host(sizeof(*slot), slot_dev);
+	if (!mmc)
+		return -ENOMEM;
+
+	slot = mmc_priv(mmc);
+	slot->dev = slot_dev;
+	slot->mmc = mmc;
+	slot->id = id;
+	slot->host = host;
+
+	host->slot = slot;
+
+	/* Get regulators and the supported OCR mask */
+	ret = mmc_regulator_get_supply(mmc);
+	if (ret == -EPROBE_DEFER)
+		goto error_free_host;
+
+	mmc->max_req_size = MESON_MX_SDIO_BOUNCE_REQ_SIZE;
+	mmc->max_seg_size = mmc->max_req_size;
+	mmc->max_blk_count =
+		FIELD_GET(MESON_MX_SDIO_SEND_REPEAT_PACKAGE_TIMES_MASK,
+			  0xffffffff);
+	mmc->max_blk_size = FIELD_GET(MESON_MX_SDIO_EXT_DATA_RW_NUMBER_MASK,
+				      0xffffffff);
+	mmc->max_blk_size -= (4 * MESON_MX_SDIO_RESPONSE_CRC16_BITS);
+	mmc->max_blk_size /= BITS_PER_BYTE;
+
+	/* Get the min and max supported clock rates */
+	mmc->f_min = clk_round_rate(host->cfg_div_clk, 1);
+	mmc->f_max = clk_round_rate(host->cfg_div_clk,
+				    clk_get_rate(host->parent_clk));
+
+	mmc->caps |= MMC_CAP_ERASE | MMC_CAP_CMD23;
+	mmc->ops = &meson_mx_mmc_ops;
+
+	ret = mmc_of_parse(mmc);
+	if (ret)
+		goto error_free_host;
+
+	ret = mmc_add_host(mmc);
+	if (ret)
+		goto error_free_host;
+
+	return 0;
+
+error_free_host:
+	mmc_free_host(mmc);
+	return ret;
+}
+
+static int meson_mx_mmc_probe_slots(struct meson_mx_mmc_host *host)
+{
+	struct device_node *slot_node;
+	struct platform_device *slot_pdev;
+	int ret;
+
+	for_each_child_of_node(host->dev->of_node, slot_node) {
+		if (!of_device_is_compatible(slot_node, "mmc-slot"))
+			continue;
+
+		/*
+		 * TODO: the MMC core framework currently does not support
+		 * controllers with multiple slots properly.
+		 */
+		if (host->slot) {
+			dev_warn(host->dev,
+				 "skipping slot other than the first\n");
+			continue;
+		}
+
+		slot_pdev = of_platform_device_create(slot_node, NULL,
+						      host->dev);
+		if (!slot_pdev)
+			continue;
+
+		ret = meson_mx_mmc_slot_probe(&slot_pdev->dev, host);
+		if (ret) {
+			of_platform_device_destroy(&slot_pdev->dev, NULL);
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static int meson_mx_mmc_register_clks(struct meson_mx_mmc_host *host)
+{
+	struct clk_init_data init;
+	const char *clk_div_parent, *clk_fixed_factor_parent;
+
+	clk_fixed_factor_parent = __clk_get_name(host->parent_clk);
+	init.name = devm_kasprintf(host->dev, GFP_KERNEL, "%s#fixed_factor",
+				   dev_name(host->dev));
+	init.ops = &clk_fixed_factor_ops;
+	init.flags = 0;
+	init.parent_names = &clk_fixed_factor_parent;
+	init.num_parents = 1;
+	host->fixed_factor.div = 2;
+	host->fixed_factor.mult = 1;
+	host->fixed_factor.hw.init = &init;
+
+	host->fixed_factor_clk = devm_clk_register(host->dev,
+						 &host->fixed_factor.hw);
+	if (WARN_ON(PTR_ERR_OR_ZERO(host->fixed_factor_clk)))
+		return PTR_ERR(host->fixed_factor_clk);
+
+	clk_div_parent = __clk_get_name(host->fixed_factor_clk);
+	init.name = devm_kasprintf(host->dev, GFP_KERNEL, "%s#div",
+				   dev_name(host->dev));
+	init.ops = &clk_divider_ops;
+	init.flags = CLK_SET_RATE_PARENT;
+	init.parent_names = &clk_div_parent;
+	init.num_parents = 1;
+	host->cfg_div.reg = host->base + MESON_MX_SDIO_CONF;
+	host->cfg_div.shift = MESON_MX_SDIO_CONF_CMD_CLK_DIV_SHIFT;
+	host->cfg_div.width = MESON_MX_SDIO_CONF_CMD_CLK_DIV_WIDTH;
+	host->cfg_div.hw.init = &init;
+	host->cfg_div.flags = CLK_DIVIDER_ALLOW_ZERO;
+
+	host->cfg_div_clk = devm_clk_register(host->dev, &host->cfg_div.hw);
+	if (WARN_ON(PTR_ERR_OR_ZERO(host->cfg_div_clk)))
+		return PTR_ERR(host->fixed_factor_clk);
+
+	return 0;
+}
+
+static int meson_mx_mmc_probe(struct platform_device *pdev)
+{
+	struct meson_mx_mmc_host *host;
+	struct resource *res;
+	int ret, irq;
+	u32 conf;
+
+	host = devm_kzalloc(&pdev->dev, sizeof(*host), GFP_KERNEL);
+	if (!host)
+		return -ENOMEM;
+
+	spin_lock_init(&host->irq_lock);
+	setup_timer(&host->cmd_timeout, meson_mx_mmc_timeout,
+		    (unsigned long)host);
+	host->dev = &pdev->dev;
+
+	platform_set_drvdata(pdev, host);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	host->base = devm_ioremap_resource(host->dev, res);
+	if (IS_ERR(host->base)) {
+		ret = PTR_ERR(host->base);
+		goto error_out;
+	}
+
+	irq = platform_get_irq(pdev, 0);
+	ret = devm_request_threaded_irq(host->dev, irq, meson_mx_mmc_irq,
+					meson_mx_mmc_irq_thread, IRQF_ONESHOT,
+					NULL, host);
+	if (ret)
+		goto error_out;
+
+	host->core_clk = devm_clk_get(host->dev, "core");
+	if (IS_ERR(host->core_clk)) {
+		ret = PTR_ERR(host->core_clk);
+		goto error_out;
+	}
+
+	host->parent_clk = devm_clk_get(host->dev, "clkin");
+	if (IS_ERR(host->parent_clk)) {
+		ret = PTR_ERR(host->parent_clk);
+		goto error_out;
+	}
+
+	ret = meson_mx_mmc_register_clks(host);
+	if (ret)
+		goto error_out;
+
+	ret = clk_prepare_enable(host->core_clk);
+	if (ret) {
+		dev_err(host->dev, "Failed to enable core clock\n");
+		goto error_out;
+	}
+
+	ret = clk_prepare_enable(host->cfg_div_clk);
+	if (ret) {
+		dev_err(host->dev, "Failed to enable MMC clock\n");
+		goto error_disable_core_clk;
+	}
+
+	conf = 0;
+	conf |= FIELD_PREP(MESON_MX_SDIO_CONF_CMD_ARGUMENT_BITS_MASK, 39);
+	conf |= FIELD_PREP(MESON_MX_SDIO_CONF_M_ENDIAN_MASK, 0x3);
+	conf |= FIELD_PREP(MESON_MX_SDIO_CONF_WRITE_NWR_MASK, 0x2);
+	conf |= FIELD_PREP(MESON_MX_SDIO_CONF_WRITE_CRC_OK_STATUS_MASK, 0x2);
+	writel(conf, host->base + MESON_MX_SDIO_CONF);
+
+	meson_mx_mmc_soft_reset(host);
+
+	ret = meson_mx_mmc_probe_slots(host);
+	if (ret)
+		goto error_disable_clks;
+
+	return 0;
+
+error_disable_clks:
+	clk_disable_unprepare(host->cfg_div_clk);
+error_disable_core_clk:
+	clk_disable_unprepare(host->core_clk);
+error_out:
+	return ret;
+}
+
+static int meson_mx_mmc_remove(struct platform_device *pdev)
+{
+	struct meson_mx_mmc_host *host = platform_get_drvdata(pdev);
+	struct meson_mx_mmc_slot *slot = host->slot;
+
+	del_timer_sync(&host->cmd_timeout);
+
+	if (slot) {
+		mmc_remove_host(slot->mmc);
+		mmc_free_host(slot->mmc);
+		of_platform_device_destroy(slot->dev, NULL);
+	}
+
+	clk_disable_unprepare(host->cfg_div_clk);
+	clk_disable_unprepare(host->core_clk);
+
+	return 0;
+}
+
+static const struct of_device_id meson_mx_mmc_of_match[] = {
+	{ .compatible = "amlogic,meson8-sdio", },
+	{ .compatible = "amlogic,meson8b-sdio", },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, meson_mx_mmc_of_match);
+
+static struct platform_driver meson_mx_mmc_driver = {
+	.probe   = meson_mx_mmc_probe,
+	.remove  = meson_mx_mmc_remove,
+	.driver  = {
+		.name = "meson-mx-sdio",
+		.of_match_table = of_match_ptr(meson_mx_mmc_of_match),
+	},
+};
+
+module_platform_driver(meson_mx_mmc_driver);
+
+MODULE_DESCRIPTION("Meson6, Meson8 and Meson8b SDIO/MMC Host Driver");
+MODULE_AUTHOR("Carlo Caione <carlo@endlessm.com>");
+MODULE_AUTHOR("Martin Blumenstingl <martin.blumenstingl@googlemail.com>");
+MODULE_LICENSE("GPL v2");
-- 
2.14.1

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

* [RFC v2 0/2] Add support for Meson MX "SDIO" MMC controller
  2017-09-24 19:05 [RFC v2 0/2] Add support for Meson MX "SDIO" MMC controller Martin Blumenstingl
  2017-09-24 19:05 ` [RFC v2 1/2] dt-bindings: mmc: Document the Amlogic Meson8 and Meson8b SDIO bindings Martin Blumenstingl
  2017-09-24 19:05 ` [RFC v2 2/2] mmc: meson-mx-sdio: Add a driver for the Amlogic Meson8 and Meson8b SoCs Martin Blumenstingl
@ 2017-09-27 19:36 ` Rob Herring
  2017-10-03 11:19   ` Martin Blumenstingl
  2 siblings, 1 reply; 10+ messages in thread
From: Rob Herring @ 2017-09-27 19:36 UTC (permalink / raw)
  To: linux-arm-kernel

On Sun, Sep 24, 2017 at 09:05:26PM +0200, Martin Blumenstingl wrote:
> This is the successor to Carlo Caione's "Add support for Amlogic Meson
> MMC driver" series (v5) from [0].
> This new driver is for the "SDIO" controller found in Amlogic Meson6,
> Meson8 and Meson8b SoCs and supports an internal mux to allow connecting
> three cards to it.
> 
> 
> changes since RFC v1 at [1]:
> - added COMMON_CLK dependency as reported by the kbuild test robot
> - use of_platform_device_{create,destroy} instead of open-coding it's
>   logic
> - moved struct device (which was an array) from meson_mx_mmc_host to
>   the corresponding meson_mx_mmc_slot
> - use struct mmc_command's busy_timeout instead of hard-coding the
>   timeout values in meson_mx_mmc_start_cmd()
> - don't use arrays with only one element for the clock parents in
>   meson_mx_mmc_register_clks()
> - removed the wrapper functions meson_mx_mmc_readl() meson_mx_mmc_writel()
> - allow setting the MMC clock to 0 for UHS speed mode (the actual
>   hardware clock cannot be gated as far as I know, so instead the
>   lowest supported rate is chosen)
> - remove unused #include <linux/init.h>
> - add MMC_CAP_ERASE
> - removed multiple slot support after discussing this with Ulf
>   (this is a feature that needs to be part of the MMC core before drivers
>   can use it)
> - removed SDIO interrupt support (as I currently don't have a way to
>   test it)
> - merge meson_mx_mmc_apply_ios into meson_mx_mmc_set_ios (as that's
>   the only place where it's needed after removing multiple slot support)
> - updated the commit message of the driver patch to indicate the
>   difference between the meson-mx-sdio.c and meson-gx.c (and the "still
>   missing SDHC") driver
> - NOTE: I did not add Rob's ACK on the dt-bindings patch because I
>   introduced the "mmc-slot" compatible for the child nodes as suggested
>   by Ulf (and I want confirmation from the DT maintainers that I did this
>   correctly)

Didn't slot support get removed as no h/w really uses that feature?

Rob

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

* [RFC v2 1/2] dt-bindings: mmc: Document the Amlogic Meson8 and Meson8b SDIO bindings
  2017-09-24 19:05 ` [RFC v2 1/2] dt-bindings: mmc: Document the Amlogic Meson8 and Meson8b SDIO bindings Martin Blumenstingl
@ 2017-09-27 19:37   ` Rob Herring
  2017-10-02  7:55   ` Ulf Hansson
  1 sibling, 0 replies; 10+ messages in thread
From: Rob Herring @ 2017-09-27 19:37 UTC (permalink / raw)
  To: linux-arm-kernel

On Sun, Sep 24, 2017 at 09:05:27PM +0200, Martin Blumenstingl wrote:
> From: Carlo Caione <carlo@endlessm.com>
> 
> This documents the devicetree bindings for the SDIO/MMC host found in
> Amlogic Meson8 and Meson8b SoCs. It supports the SD specification v2.0
> and the eMMC specification v4.41.
> It has an internal "mux" which allows connecting up to three MMC devices
> to it. The maximum supported bus-width is 4-bits.
> 
> Amlogic's GPL kernel sources call it "SDIO" to differentiate it from the
> other MMC controller in (at least the Meson8 and Meson8b) the SoCs (they
> call the other one "SDHC", which supports a bus-width of up to 8-bits).
> 
> Signed-off-by: Carlo Caione <carlo@endlessm.com>
> Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
> ---
>  .../bindings/mmc/amlogic,meson-mx-sdio.txt         | 52 ++++++++++++++++++++++
>  1 file changed, 52 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/mmc/amlogic,meson-mx-sdio.txt

Acked-by: Rob Herring <robh@kernel.org>

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

* [RFC v2 1/2] dt-bindings: mmc: Document the Amlogic Meson8 and Meson8b SDIO bindings
  2017-09-24 19:05 ` [RFC v2 1/2] dt-bindings: mmc: Document the Amlogic Meson8 and Meson8b SDIO bindings Martin Blumenstingl
  2017-09-27 19:37   ` Rob Herring
@ 2017-10-02  7:55   ` Ulf Hansson
  2017-10-02 18:47     ` Martin Blumenstingl
  1 sibling, 1 reply; 10+ messages in thread
From: Ulf Hansson @ 2017-10-02  7:55 UTC (permalink / raw)
  To: linux-arm-kernel

On 24 September 2017 at 21:05, Martin Blumenstingl
<martin.blumenstingl@googlemail.com> wrote:
> From: Carlo Caione <carlo@endlessm.com>
>
> This documents the devicetree bindings for the SDIO/MMC host found in
> Amlogic Meson8 and Meson8b SoCs. It supports the SD specification v2.0
> and the eMMC specification v4.41.
> It has an internal "mux" which allows connecting up to three MMC devices
> to it. The maximum supported bus-width is 4-bits.
>
> Amlogic's GPL kernel sources call it "SDIO" to differentiate it from the
> other MMC controller in (at least the Meson8 and Meson8b) the SoCs (they
> call the other one "SDHC", which supports a bus-width of up to 8-bits).
>
> Signed-off-by: Carlo Caione <carlo@endlessm.com>
> Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
> ---
>  .../bindings/mmc/amlogic,meson-mx-sdio.txt         | 52 ++++++++++++++++++++++
>  1 file changed, 52 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/mmc/amlogic,meson-mx-sdio.txt
>
> diff --git a/Documentation/devicetree/bindings/mmc/amlogic,meson-mx-sdio.txt b/Documentation/devicetree/bindings/mmc/amlogic,meson-mx-sdio.txt
> new file mode 100644
> index 000000000000..124ea362eec9
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/mmc/amlogic,meson-mx-sdio.txt
> @@ -0,0 +1,52 @@
> +* Amlogic Meson6, Meson8 and Meson8b SDIO/MMC controller
> +
> +The highspeed MMC host controller on Amlogic SoCs provides an interface
> +for MMC, SD, SDIO and SDHC types of memory cards.
> +
> +Supported maximum speeds are the ones of the eMMC standard 4.41 as well
> +as the speed of SD standard 2.0.
> +
> +The hardware provides an internal "mux" which allows up to three slots
> +to be controlled. Only one slot can be accessed at a time.

This is good information, however as the driver won't support multiple
slots, at least short term, I think we need to mention that. Otherwise
people may think that three slots is actually supported, while in fact
it isn't.

> +
> +Required properties:
> + - compatible : must be one of
> +       - "amlogic,meson8-sdio"
> +       - "amlogic,meson8b-sdio"
> +       along with the generic "amlogic,meson-mx-sdio"
> + - reg : mmc controller base registers
> + - interrupts : mmc controller interrupt
> + - #address-cells : must be 1
> + - size-cells : must be 0
> + - clocks : phandle to clock providers
> + - clock-names : must contain "core" and "clkin"
> +
> +Required child nodes:
> +A node for each slot provided by the MMC controller is required.
> +
> +Required properties on each child node (= slot):
> + - compatible : must be "mmc-slot" (see mmc.txt within this directory)
> + - reg : the slot (or "port") ID
> +
> +Optional properties on each child node (= slot):
> + - bus-width : must be 1 or 4 (8-bit bus is not supported)
> + - for cd and all other additional generic mmc parameters
> +   please refer to mmc.txt within this directory
> +
> +Examples:
> +       mmc at c1108c20 {
> +               compatible = "amlogic,meson8-sdio", "amlogic,meson-mx-sdio";
> +               reg = <0xc1108c20 0x20>;
> +               interrupts = <0 28 1>;
> +               #address-cells = <1>;
> +               #size-cells = <0>;
> +               clocks = <&clkc CLKID_SDIO>, <&clkc CLKID_CLK81>;
> +               clock-names = "core", "clkin";
> +
> +               slot at 1 {
> +                       compatible = "mmc-slot";
> +                       reg = <1>;
> +
> +                       bus-width = <4>;
> +               };
> +       };
> --
> 2.14.1
>

Kind regards
Uffe

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

* [RFC v2 2/2] mmc: meson-mx-sdio: Add a driver for the Amlogic Meson8 and Meson8b SoCs
  2017-09-24 19:05 ` [RFC v2 2/2] mmc: meson-mx-sdio: Add a driver for the Amlogic Meson8 and Meson8b SoCs Martin Blumenstingl
@ 2017-10-02  8:08   ` Ulf Hansson
  2017-10-02 18:45     ` Martin Blumenstingl
  0 siblings, 1 reply; 10+ messages in thread
From: Ulf Hansson @ 2017-10-02  8:08 UTC (permalink / raw)
  To: linux-arm-kernel

[...]

> +#define MESON_MX_SDIO_MAX_SLOTS                                        3
> +
> +struct meson_mx_mmc_slot {
> +       struct device                   *dev;
> +       struct mmc_host                 *mmc;
> +       struct meson_mx_mmc_host        *host;
> +
> +       struct mmc_request              *mrq;
> +       struct mmc_command              *cmd;
> +       int                             error;
> +
> +       unsigned int                    id;
> +};

If I recall correctly, we agreed on postponing the multiple slot
support for now as to start simple.
Therefore, can you please remove all that code, and instead only use
the struct meson_mx_mmc_host for the data needed.

Just to be clear, I am fine having using the mmc slot bindings, as we
agreed. However as only one slot is supported in this stage, we don't
need a separate struct for that.

> +
> +struct meson_mx_mmc_host {
> +       struct device                   *dev;
> +
> +       struct clk                      *parent_clk;
> +       struct clk                      *core_clk;
> +       struct clk_divider              cfg_div;
> +       struct clk                      *cfg_div_clk;
> +       struct clk_fixed_factor         fixed_factor;
> +       struct clk                      *fixed_factor_clk;
> +
> +       void __iomem                    *base;
> +       int                             irq;
> +       spinlock_t                      irq_lock;
> +
> +       struct timer_list               cmd_timeout;
> +
> +       struct meson_mx_mmc_slot        *slot;
> +};
> +

[...]

> +static int meson_mx_mmc_slot_probe(struct device *slot_dev,
> +                                  struct meson_mx_mmc_host *host)
> +{
> +       struct meson_mx_mmc_slot *slot;
> +       struct mmc_host *mmc;
> +       unsigned int id;
> +       int ret;
> +
> +       if (of_property_read_u32(slot_dev->of_node, "reg", &id)) {
> +               dev_err(slot_dev, "missing 'reg' property\n");
> +               return -EINVAL;
> +       }
> +
> +       if (id >= MESON_MX_SDIO_MAX_SLOTS) {
> +               dev_err(slot_dev, "invalid 'reg' property value %d\n", id);
> +               return -EINVAL;
> +       }
> +
> +       mmc = mmc_alloc_host(sizeof(*slot), slot_dev);
> +       if (!mmc)
> +               return -ENOMEM;
> +
> +       slot = mmc_priv(mmc);
> +       slot->dev = slot_dev;
> +       slot->mmc = mmc;
> +       slot->id = id;
> +       slot->host = host;
> +
> +       host->slot = slot;
> +
> +       /* Get regulators and the supported OCR mask */
> +       ret = mmc_regulator_get_supply(mmc);
> +       if (ret == -EPROBE_DEFER)
> +               goto error_free_host;
> +
> +       mmc->max_req_size = MESON_MX_SDIO_BOUNCE_REQ_SIZE;
> +       mmc->max_seg_size = mmc->max_req_size;
> +       mmc->max_blk_count =
> +               FIELD_GET(MESON_MX_SDIO_SEND_REPEAT_PACKAGE_TIMES_MASK,
> +                         0xffffffff);
> +       mmc->max_blk_size = FIELD_GET(MESON_MX_SDIO_EXT_DATA_RW_NUMBER_MASK,
> +                                     0xffffffff);
> +       mmc->max_blk_size -= (4 * MESON_MX_SDIO_RESPONSE_CRC16_BITS);
> +       mmc->max_blk_size /= BITS_PER_BYTE;
> +
> +       /* Get the min and max supported clock rates */
> +       mmc->f_min = clk_round_rate(host->cfg_div_clk, 1);
> +       mmc->f_max = clk_round_rate(host->cfg_div_clk,
> +                                   clk_get_rate(host->parent_clk));
> +
> +       mmc->caps |= MMC_CAP_ERASE | MMC_CAP_CMD23;
> +       mmc->ops = &meson_mx_mmc_ops;
> +
> +       ret = mmc_of_parse(mmc);
> +       if (ret)
> +               goto error_free_host;
> +
> +       ret = mmc_add_host(mmc);
> +       if (ret)
> +               goto error_free_host;
> +
> +       return 0;
> +
> +error_free_host:
> +       mmc_free_host(mmc);
> +       return ret;
> +}
> +
> +static int meson_mx_mmc_probe_slots(struct meson_mx_mmc_host *host)
> +{
> +       struct device_node *slot_node;
> +       struct platform_device *slot_pdev;
> +       int ret;
> +
> +       for_each_child_of_node(host->dev->of_node, slot_node) {
> +               if (!of_device_is_compatible(slot_node, "mmc-slot"))
> +                       continue;
> +
> +               /*
> +                * TODO: the MMC core framework currently does not support
> +                * controllers with multiple slots properly.
> +                */
> +               if (host->slot) {
> +                       dev_warn(host->dev,
> +                                "skipping slot other than the first\n");
> +                       continue;
> +               }
> +
> +               slot_pdev = of_platform_device_create(slot_node, NULL,
> +                                                     host->dev);
> +               if (!slot_pdev)
> +                       continue;
> +
> +               ret = meson_mx_mmc_slot_probe(&slot_pdev->dev, host);
> +               if (ret) {
> +                       of_platform_device_destroy(&slot_pdev->dev, NULL);
> +                       return ret;
> +               }
> +       }
> +
> +       return 0;
> +}

For the above two functions, please simplify the code by limiting them
to deal with only one valid mmc-slot.

[...]

Besides the comments on the multiple slot support, this looks good to me.

Kind regards
Uffe

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

* [RFC v2 2/2] mmc: meson-mx-sdio: Add a driver for the Amlogic Meson8 and Meson8b SoCs
  2017-10-02  8:08   ` Ulf Hansson
@ 2017-10-02 18:45     ` Martin Blumenstingl
  0 siblings, 0 replies; 10+ messages in thread
From: Martin Blumenstingl @ 2017-10-02 18:45 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Ulf,

On Mon, Oct 2, 2017 at 10:08 AM, Ulf Hansson <ulf.hansson@linaro.org> wrote:
> [...]
>
>> +#define MESON_MX_SDIO_MAX_SLOTS                                        3
>> +
>> +struct meson_mx_mmc_slot {
>> +       struct device                   *dev;
>> +       struct mmc_host                 *mmc;
>> +       struct meson_mx_mmc_host        *host;
>> +
>> +       struct mmc_request              *mrq;
>> +       struct mmc_command              *cmd;
>> +       int                             error;
>> +
>> +       unsigned int                    id;
>> +};
>
> If I recall correctly, we agreed on postponing the multiple slot
> support for now as to start simple.
yes, indeed

> Therefore, can you please remove all that code, and instead only use
> the struct meson_mx_mmc_host for the data needed.
I initially wanted to keep these structs separated to make it easier
to spot which part of the logic might have to be changed to support
multiple slots
looking back at it: currently meson_mx_mmc_slot only contains very
generic stuff, so it'll (hopefully) be easy to spot the relevant parts
anyways
I'll remove it, which will even fix a warning found by the "kbuild
test robot" (where I didn't initialize but use the "slot" variable in
meson_mx_mmc_timeout)

> Just to be clear, I am fine having using the mmc slot bindings, as we
> agreed. However as only one slot is supported in this stage, we don't
> need a separate struct for that.
ACK

>> +
>> +struct meson_mx_mmc_host {
>> +       struct device                   *dev;
>> +
>> +       struct clk                      *parent_clk;
>> +       struct clk                      *core_clk;
>> +       struct clk_divider              cfg_div;
>> +       struct clk                      *cfg_div_clk;
>> +       struct clk_fixed_factor         fixed_factor;
>> +       struct clk                      *fixed_factor_clk;
>> +
>> +       void __iomem                    *base;
>> +       int                             irq;
>> +       spinlock_t                      irq_lock;
>> +
>> +       struct timer_list               cmd_timeout;
>> +
>> +       struct meson_mx_mmc_slot        *slot;
>> +};
>> +
>
> [...]
>
>> +static int meson_mx_mmc_slot_probe(struct device *slot_dev,
>> +                                  struct meson_mx_mmc_host *host)
>> +{
>> +       struct meson_mx_mmc_slot *slot;
>> +       struct mmc_host *mmc;
>> +       unsigned int id;
>> +       int ret;
>> +
>> +       if (of_property_read_u32(slot_dev->of_node, "reg", &id)) {
>> +               dev_err(slot_dev, "missing 'reg' property\n");
>> +               return -EINVAL;
>> +       }
>> +
>> +       if (id >= MESON_MX_SDIO_MAX_SLOTS) {
>> +               dev_err(slot_dev, "invalid 'reg' property value %d\n", id);
>> +               return -EINVAL;
>> +       }
>> +
>> +       mmc = mmc_alloc_host(sizeof(*slot), slot_dev);
>> +       if (!mmc)
>> +               return -ENOMEM;
>> +
>> +       slot = mmc_priv(mmc);
>> +       slot->dev = slot_dev;
>> +       slot->mmc = mmc;
>> +       slot->id = id;
>> +       slot->host = host;
>> +
>> +       host->slot = slot;
>> +
>> +       /* Get regulators and the supported OCR mask */
>> +       ret = mmc_regulator_get_supply(mmc);
>> +       if (ret == -EPROBE_DEFER)
>> +               goto error_free_host;
>> +
>> +       mmc->max_req_size = MESON_MX_SDIO_BOUNCE_REQ_SIZE;
>> +       mmc->max_seg_size = mmc->max_req_size;
>> +       mmc->max_blk_count =
>> +               FIELD_GET(MESON_MX_SDIO_SEND_REPEAT_PACKAGE_TIMES_MASK,
>> +                         0xffffffff);
>> +       mmc->max_blk_size = FIELD_GET(MESON_MX_SDIO_EXT_DATA_RW_NUMBER_MASK,
>> +                                     0xffffffff);
>> +       mmc->max_blk_size -= (4 * MESON_MX_SDIO_RESPONSE_CRC16_BITS);
>> +       mmc->max_blk_size /= BITS_PER_BYTE;
>> +
>> +       /* Get the min and max supported clock rates */
>> +       mmc->f_min = clk_round_rate(host->cfg_div_clk, 1);
>> +       mmc->f_max = clk_round_rate(host->cfg_div_clk,
>> +                                   clk_get_rate(host->parent_clk));
>> +
>> +       mmc->caps |= MMC_CAP_ERASE | MMC_CAP_CMD23;
>> +       mmc->ops = &meson_mx_mmc_ops;
>> +
>> +       ret = mmc_of_parse(mmc);
>> +       if (ret)
>> +               goto error_free_host;
>> +
>> +       ret = mmc_add_host(mmc);
>> +       if (ret)
>> +               goto error_free_host;
>> +
>> +       return 0;
>> +
>> +error_free_host:
>> +       mmc_free_host(mmc);
>> +       return ret;
>> +}
>> +
>> +static int meson_mx_mmc_probe_slots(struct meson_mx_mmc_host *host)
>> +{
>> +       struct device_node *slot_node;
>> +       struct platform_device *slot_pdev;
>> +       int ret;
>> +
>> +       for_each_child_of_node(host->dev->of_node, slot_node) {
>> +               if (!of_device_is_compatible(slot_node, "mmc-slot"))
>> +                       continue;
>> +
>> +               /*
>> +                * TODO: the MMC core framework currently does not support
>> +                * controllers with multiple slots properly.
>> +                */
>> +               if (host->slot) {
>> +                       dev_warn(host->dev,
>> +                                "skipping slot other than the first\n");
>> +                       continue;
>> +               }
>> +
>> +               slot_pdev = of_platform_device_create(slot_node, NULL,
>> +                                                     host->dev);
>> +               if (!slot_pdev)
>> +                       continue;
>> +
>> +               ret = meson_mx_mmc_slot_probe(&slot_pdev->dev, host);
>> +               if (ret) {
>> +                       of_platform_device_destroy(&slot_pdev->dev, NULL);
>> +                       return ret;
>> +               }
>> +       }
>> +
>> +       return 0;
>> +}
>
> For the above two functions, please simplify the code by limiting them
> to deal with only one valid mmc-slot.
OK, I'll do that - however I'll leave that TODO comment in the code so
people know that this is on purpose

> [...]
>
> Besides the comments on the multiple slot support, this looks good to me.
awesome, thanks for reviewing!
I'll send an updated version as soon as I have time


Regards,
Martin

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

* [RFC v2 1/2] dt-bindings: mmc: Document the Amlogic Meson8 and Meson8b SDIO bindings
  2017-10-02  7:55   ` Ulf Hansson
@ 2017-10-02 18:47     ` Martin Blumenstingl
  0 siblings, 0 replies; 10+ messages in thread
From: Martin Blumenstingl @ 2017-10-02 18:47 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Oct 2, 2017 at 9:55 AM, Ulf Hansson <ulf.hansson@linaro.org> wrote:
> On 24 September 2017 at 21:05, Martin Blumenstingl
> <martin.blumenstingl@googlemail.com> wrote:
>> From: Carlo Caione <carlo@endlessm.com>
>>
>> This documents the devicetree bindings for the SDIO/MMC host found in
>> Amlogic Meson8 and Meson8b SoCs. It supports the SD specification v2.0
>> and the eMMC specification v4.41.
>> It has an internal "mux" which allows connecting up to three MMC devices
>> to it. The maximum supported bus-width is 4-bits.
>>
>> Amlogic's GPL kernel sources call it "SDIO" to differentiate it from the
>> other MMC controller in (at least the Meson8 and Meson8b) the SoCs (they
>> call the other one "SDHC", which supports a bus-width of up to 8-bits).
>>
>> Signed-off-by: Carlo Caione <carlo@endlessm.com>
>> Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
>> ---
>>  .../bindings/mmc/amlogic,meson-mx-sdio.txt         | 52 ++++++++++++++++++++++
>>  1 file changed, 52 insertions(+)
>>  create mode 100644 Documentation/devicetree/bindings/mmc/amlogic,meson-mx-sdio.txt
>>
>> diff --git a/Documentation/devicetree/bindings/mmc/amlogic,meson-mx-sdio.txt b/Documentation/devicetree/bindings/mmc/amlogic,meson-mx-sdio.txt
>> new file mode 100644
>> index 000000000000..124ea362eec9
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/mmc/amlogic,meson-mx-sdio.txt
>> @@ -0,0 +1,52 @@
>> +* Amlogic Meson6, Meson8 and Meson8b SDIO/MMC controller
>> +
>> +The highspeed MMC host controller on Amlogic SoCs provides an interface
>> +for MMC, SD, SDIO and SDHC types of memory cards.
>> +
>> +Supported maximum speeds are the ones of the eMMC standard 4.41 as well
>> +as the speed of SD standard 2.0.
>> +
>> +The hardware provides an internal "mux" which allows up to three slots
>> +to be controlled. Only one slot can be accessed at a time.
>
> This is good information, however as the driver won't support multiple
> slots, at least short term, I think we need to mention that. Otherwise
> people may think that three slots is actually supported, while in fact
> it isn't.
OK, I'll add a note when I re-spin this series

>> +
>> +Required properties:
>> + - compatible : must be one of
>> +       - "amlogic,meson8-sdio"
>> +       - "amlogic,meson8b-sdio"
>> +       along with the generic "amlogic,meson-mx-sdio"
>> + - reg : mmc controller base registers
>> + - interrupts : mmc controller interrupt
>> + - #address-cells : must be 1
>> + - size-cells : must be 0
>> + - clocks : phandle to clock providers
>> + - clock-names : must contain "core" and "clkin"
>> +
>> +Required child nodes:
>> +A node for each slot provided by the MMC controller is required.
>> +
>> +Required properties on each child node (= slot):
>> + - compatible : must be "mmc-slot" (see mmc.txt within this directory)
>> + - reg : the slot (or "port") ID
>> +
>> +Optional properties on each child node (= slot):
>> + - bus-width : must be 1 or 4 (8-bit bus is not supported)
>> + - for cd and all other additional generic mmc parameters
>> +   please refer to mmc.txt within this directory
>> +
>> +Examples:
>> +       mmc at c1108c20 {
>> +               compatible = "amlogic,meson8-sdio", "amlogic,meson-mx-sdio";
>> +               reg = <0xc1108c20 0x20>;
>> +               interrupts = <0 28 1>;
>> +               #address-cells = <1>;
>> +               #size-cells = <0>;
>> +               clocks = <&clkc CLKID_SDIO>, <&clkc CLKID_CLK81>;
>> +               clock-names = "core", "clkin";
>> +
>> +               slot at 1 {
>> +                       compatible = "mmc-slot";
>> +                       reg = <1>;
>> +
>> +                       bus-width = <4>;
>> +               };
>> +       };
>> --
>> 2.14.1
>>
>
> Kind regards
> Uffe


Regards,
Martin

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

* [RFC v2 0/2] Add support for Meson MX "SDIO" MMC controller
  2017-09-27 19:36 ` [RFC v2 0/2] Add support for Meson MX "SDIO" MMC controller Rob Herring
@ 2017-10-03 11:19   ` Martin Blumenstingl
  0 siblings, 0 replies; 10+ messages in thread
From: Martin Blumenstingl @ 2017-10-03 11:19 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Rob,

On Wed, Sep 27, 2017 at 9:36 PM, Rob Herring <robh@kernel.org> wrote:
> On Sun, Sep 24, 2017 at 09:05:26PM +0200, Martin Blumenstingl wrote:
>> This is the successor to Carlo Caione's "Add support for Amlogic Meson
>> MMC driver" series (v5) from [0].
>> This new driver is for the "SDIO" controller found in Amlogic Meson6,
>> Meson8 and Meson8b SoCs and supports an internal mux to allow connecting
>> three cards to it.
>>
>>
>> changes since RFC v1 at [1]:
>> - added COMMON_CLK dependency as reported by the kbuild test robot
>> - use of_platform_device_{create,destroy} instead of open-coding it's
>>   logic
>> - moved struct device (which was an array) from meson_mx_mmc_host to
>>   the corresponding meson_mx_mmc_slot
>> - use struct mmc_command's busy_timeout instead of hard-coding the
>>   timeout values in meson_mx_mmc_start_cmd()
>> - don't use arrays with only one element for the clock parents in
>>   meson_mx_mmc_register_clks()
>> - removed the wrapper functions meson_mx_mmc_readl() meson_mx_mmc_writel()
>> - allow setting the MMC clock to 0 for UHS speed mode (the actual
>>   hardware clock cannot be gated as far as I know, so instead the
>>   lowest supported rate is chosen)
>> - remove unused #include <linux/init.h>
>> - add MMC_CAP_ERASE
>> - removed multiple slot support after discussing this with Ulf
>>   (this is a feature that needs to be part of the MMC core before drivers
>>   can use it)
>> - removed SDIO interrupt support (as I currently don't have a way to
>>   test it)
>> - merge meson_mx_mmc_apply_ios into meson_mx_mmc_set_ios (as that's
>>   the only place where it's needed after removing multiple slot support)
>> - updated the commit message of the driver patch to indicate the
>>   difference between the meson-mx-sdio.c and meson-gx.c (and the "still
>>   missing SDHC") driver
>> - NOTE: I did not add Rob's ACK on the dt-bindings patch because I
>>   introduced the "mmc-slot" compatible for the child nodes as suggested
>>   by Ulf (and I want confirmation from the DT maintainers that I did this
>>   correctly)
>
> Didn't slot support get removed as no h/w really uses that feature?
I have at least one boards which uses it: Endless Mini (EC-100)
the SoC itself has two MMC controllers, but that board has:
- an eMMC module (connected to a yet unsupported MMC controller)
- an internal SD card (connected to the SDIO controller from this patch)
- a RTL8723BS wifi SDIO card (also connected to the SDIO controller
from this patch)

so it's pretty rare - but such hardware exists.


Regards,
Martin

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

end of thread, other threads:[~2017-10-03 11:19 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2017-09-24 19:05 [RFC v2 0/2] Add support for Meson MX "SDIO" MMC controller Martin Blumenstingl
2017-09-24 19:05 ` [RFC v2 1/2] dt-bindings: mmc: Document the Amlogic Meson8 and Meson8b SDIO bindings Martin Blumenstingl
2017-09-27 19:37   ` Rob Herring
2017-10-02  7:55   ` Ulf Hansson
2017-10-02 18:47     ` Martin Blumenstingl
2017-09-24 19:05 ` [RFC v2 2/2] mmc: meson-mx-sdio: Add a driver for the Amlogic Meson8 and Meson8b SoCs Martin Blumenstingl
2017-10-02  8:08   ` Ulf Hansson
2017-10-02 18:45     ` Martin Blumenstingl
2017-09-27 19:36 ` [RFC v2 0/2] Add support for Meson MX "SDIO" MMC controller Rob Herring
2017-10-03 11:19   ` Martin Blumenstingl

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).