diff mbox

[1/2] mmc: core: Support all MMC capabilities when booting from Device Tree

Message ID 1350306959-5843-1-git-send-email-lee.jones@linaro.org (mailing list archive)
State New, archived
Headers show

Commit Message

Lee Jones Oct. 15, 2012, 1:15 p.m. UTC
Capabilities are an important part of the MMC subsystem. Much
supported functionality would be lost if we didn't provide the
same level of support when booting Device Tree as we currently
do when the subsystem is passed capabilities via platform data.
This patch supplies this support with one simple call to a
DT parsing function.

Cc: Chris Ball <cjb@laptop.org>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: linux-mmc@vger.kernel.org
Acked-by: Linus Walleij <linus.walleij@linaro.org>
Acked-by: Ulf Hansson <ulf.hansson@linaro.org>
Signed-off-by: Lee Jones <lee.jones@linaro.org>
---
 drivers/mmc/core/host.c  |   93 ++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/mmc/host.h |    3 +-
 2 files changed, 95 insertions(+), 1 deletion(-)

Comments

Arnd Bergmann Oct. 15, 2012, 2:20 p.m. UTC | #1
On Monday 15 October 2012, Lee Jones wrote:
> Capabilities are an important part of the MMC subsystem. Much
> supported functionality would be lost if we didn't provide the
> same level of support when booting Device Tree as we currently
> do when the subsystem is passed capabilities via platform data.
> This patch supplies this support with one simple call to a
> DT parsing function.

We already document all the commonly used properties
in Documentation/devicetree/bindings/mmc/mmc.txt

Please don't add any duplicates or those that are not used
so far.

> +	if(of_property_read_bool(np, "mmc-cap-4-bit-data"))
> +		*caps |= MMC_CAP_4_BIT_DATA;

see "bus-width" property.

> +	if(of_property_read_bool(np, "mmc-cap-mmc-highspeed"))
> +		*caps |= MMC_CAP_MMC_HIGHSPEED;
> +	if(of_property_read_bool(np, "mmc-cap-sd-highspeed"))
> +		*caps |= MMC_CAP_SD_HIGHSPEED;

implied by "max-frequency" property.

> +	if(of_property_read_bool(np, "mmc-cap-sdio-irq"))
> +		*caps |= MMC_CAP_SDIO_IRQ;

implied by presence of SDIO irq property.

> +	if(of_property_read_bool(np, "mmc-cap-spi"))
> +		*caps |= MMC_CAP_SPI;

Only used by the mmc_spi driver, can be hardcoded there.

> +	if(of_property_read_bool(np, "mmc-cap-needs-poll"))
> +		*caps |= MMC_CAP_NEEDS_POLL;

implied by absence of irqs property.

> +	if(of_property_read_bool(np, "mmc-cap-8-bit-data"))
> +		*caps |= MMC_CAP_8_BIT_DATA;

see "bus-width" property.

> +	if(of_property_read_bool(np, "mmc-cap-nonremovable"))
> +		*caps |= MMC_CAP_NONREMOVABLE;

see "non-removable property.

> +	if(of_property_read_bool(np, "mmc-cap-wait-while-busy"))
> +		*caps |= MMC_CAP_WAIT_WHILE_BUSY;

This seems to be a linux device driver specific quirk that doesn't
belong into a hardware description.

> +	if(of_property_read_bool(np, "mmc-cap-erase"))
> +		*caps |= MMC_CAP_ERASE;

driver specific.

> ...

and so on. What are you actually missing in the properties that
are already there?

	Arnd
Lee Jones Oct. 15, 2012, 4:07 p.m. UTC | #2
> On Monday 15 October 2012, Lee Jones wrote:
> > Capabilities are an important part of the MMC subsystem. Much
> > supported functionality would be lost if we didn't provide the
> > same level of support when booting Device Tree as we currently
> > do when the subsystem is passed capabilities via platform data.
> > This patch supplies this support with one simple call to a
> > DT parsing function.
> 
> We already document all the commonly used properties
> in Documentation/devicetree/bindings/mmc/mmc.txt

<snip>

> and so on. What are you actually missing in the properties that
> are already there?

MMC_CAP_ERASE
MMC_CAP_UHS_SDR12
MMC_CAP_UHS_SDR25
MMC_CAP_UHS_DDR50
MMC_CAP_1_8V_DDR

MMC_CAP2_DETECT_ON_ERR
MMC_CAP2_NO_SLEEP_CMD
Arnd Bergmann Oct. 17, 2012, 1:38 p.m. UTC | #3
On Monday 15 October 2012, Lee Jones wrote:
> > and so on. What are you actually missing in the properties that
> > are already there?
> 
> MMC_CAP_ERASE

This one seems to be set unconditionally on some controllers but
not on others. Why would it need to be configurable?

> MMC_CAP_UHS_SDR12
> MMC_CAP_UHS_SDR25
> MMC_CAP_UHS_DDR50

Could this be derived from max-frequency?

> MMC_CAP_1_8V_DDR

Right, I suppose we need this. Should we have a minimum and maximum
voltage added to the common properties for this?

> MMC_CAP2_DETECT_ON_ERR
> MMC_CAP2_NO_SLEEP_CMD

I don't see these ones being set anywhere, but they were both
added by Ulf. Maybe he can comment on if or why they are needed
in devicetree, rather than being set by the driver unconditionally
or for specific versions of the host controller.

	Arnd
Ulf Hansson Oct. 17, 2012, 6:53 p.m. UTC | #4
On 17 October 2012 15:38, Arnd Bergmann <arnd@arndb.de> wrote:
> On Monday 15 October 2012, Lee Jones wrote:
>> > and so on. What are you actually missing in the properties that
>> > are already there?
>>
>> MMC_CAP_ERASE
>
> This one seems to be set unconditionally on some controllers but
> not on others. Why would it need to be configurable?
>
>> MMC_CAP_UHS_SDR12
>> MMC_CAP_UHS_SDR25
>> MMC_CAP_UHS_DDR50
>
> Could this be derived from max-frequency?

No, this is likely depending on what the hw controller supports. Not
connected to the freq.
UHS also means 1.8 V I/O voltage.

>
>> MMC_CAP_1_8V_DDR
>
> Right, I suppose we need this. Should we have a minimum and maximum
> voltage added to the common properties for this?
>
>> MMC_CAP2_DETECT_ON_ERR
>> MMC_CAP2_NO_SLEEP_CMD
>
> I don't see these ones being set anywhere, but they were both
> added by Ulf. Maybe he can comment on if or why they are needed
> in devicetree, rather than being set by the driver unconditionally
> or for specific versions of the host controller.

From ux500 perspective there are patches not been up-streamed yet
which are using these host caps, for whatever it is worth for you to
know and consider.

Actually, I think quite a few of the host caps in mmc could be debated
whether those should exist at all.
Some are directly mapped to what the host controller hw support, some
are purely what the host driver (sw) support, but then there are
others kind of "mmc/sd/sdio software support configuration" which are
kind of strange host caps to me. For example MMC_CAP2_DETECT_ON_ERR
which I invented. :-). I think it especially these "software support
configuration" caps that might be causing this dt issues.

Would be very interesting to hear if someone is sharing my thoughts
around the host caps. Or if I am totally wrong here.

Kind regards
Ulf Hansson
Philip Rakity Oct. 17, 2012, 7:56 p.m. UTC | #5
On 17 Oct 2012, at 14:38, Arnd Bergmann <arnd@arndb.de> wrote:

> On Monday 15 October 2012, Lee Jones wrote:
>>> and so on. What are you actually missing in the properties that
>>> are already there?
>> 
>> MMC_CAP_ERASE
> 
> This one seems to be set unconditionally on some controllers but
> not on others. Why would it need to be configurable?
> 
>> MMC_CAP_UHS_SDR12
>> MMC_CAP_UHS_SDR25
>> MMC_CAP_UHS_DDR50
> 
> Could this be derived from max-frequency?

The problem is the controller may signal it supports DDR but the host cannot.  For example no voltage at correct level.
Same issue with 8 bit support.  Controller could say supports it but board has only 4 "wires"
> 
>> MMC_CAP_1_8V_DDR
> 
> Right, I suppose we need this. Should we have a minimum and maximum
> voltage added to the common properties for this?
> 
>> MMC_CAP2_DETECT_ON_ERR
>> MMC_CAP2_NO_SLEEP_CMD
> 
> I don't see these ones being set anywhere, but they were both
> added by Ulf. Maybe he can comment on if or why they are needed
> in devicetree, rather than being set by the driver unconditionally
> or for specific versions of the host controller.
> 
> 	Arnd
> --
> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c
index ee2e16b..61a02db 100644
--- a/drivers/mmc/core/host.c
+++ b/drivers/mmc/core/host.c
@@ -20,6 +20,7 @@ 
 #include <linux/leds.h>
 #include <linux/slab.h>
 #include <linux/suspend.h>
+#include <linux/of.h>
 
 #include <linux/mmc/host.h>
 #include <linux/mmc/card.h>
@@ -436,3 +437,95 @@  void mmc_free_host(struct mmc_host *host)
 }
 
 EXPORT_SYMBOL(mmc_free_host);
+
+/**
+ *	mmc_of_populate_caps - support all MMC capabilities from Device Tree
+ *	@np: MMC OF device node
+ *	@caps: Host capabilities - as per linux/mmc/host.h
+ *	@caps2: More host cabibilies - as per linux/mmc/host.h
+ *
+ *	Read capability string from the device node provided and populate
+ *	the capability container accordingly.
+ */
+void mmc_of_populate_caps(struct device_node *np,
+			  unsigned long *caps,
+			  unsigned int *caps2)
+{
+	if(of_property_read_bool(np, "mmc-cap-4-bit-data"))
+		*caps |= MMC_CAP_4_BIT_DATA;
+	if(of_property_read_bool(np, "mmc-cap-mmc-highspeed"))
+		*caps |= MMC_CAP_MMC_HIGHSPEED;
+	if(of_property_read_bool(np, "mmc-cap-sd-highspeed"))
+		*caps |= MMC_CAP_SD_HIGHSPEED;
+	if(of_property_read_bool(np, "mmc-cap-sdio-irq"))
+		*caps |= MMC_CAP_SDIO_IRQ;
+	if(of_property_read_bool(np, "mmc-cap-spi"))
+		*caps |= MMC_CAP_SPI;
+	if(of_property_read_bool(np, "mmc-cap-needs-poll"))
+		*caps |= MMC_CAP_NEEDS_POLL;
+	if(of_property_read_bool(np, "mmc-cap-8-bit-data"))
+		*caps |= MMC_CAP_8_BIT_DATA;
+	if(of_property_read_bool(np, "mmc-cap-nonremovable"))
+		*caps |= MMC_CAP_NONREMOVABLE;
+	if(of_property_read_bool(np, "mmc-cap-wait-while-busy"))
+		*caps |= MMC_CAP_WAIT_WHILE_BUSY;
+	if(of_property_read_bool(np, "mmc-cap-erase"))
+		*caps |= MMC_CAP_ERASE;
+	if(of_property_read_bool(np, "mmc-cap-1-8v-ddr"))
+		*caps |= MMC_CAP_1_8V_DDR;
+	if(of_property_read_bool(np, "mmc-cap-1-2v-ddr"))
+		*caps |= MMC_CAP_1_2V_DDR;
+	if(of_property_read_bool(np, "mmc-cap-power-off-card"))
+		*caps |= MMC_CAP_POWER_OFF_CARD;
+	if(of_property_read_bool(np, "mmc-cap-bus-width-test"))
+		*caps |= MMC_CAP_BUS_WIDTH_TEST;
+	if(of_property_read_bool(np, "mmc-cap-uhs-sdr12"))
+		*caps |= MMC_CAP_UHS_SDR12;
+	if(of_property_read_bool(np, "mmc-cap-uhs-sdr25"))
+		*caps |= MMC_CAP_UHS_SDR25;
+	if(of_property_read_bool(np, "mmc-cap-uhs-sdr50"))
+		*caps |= MMC_CAP_UHS_SDR50;
+	if(of_property_read_bool(np, "mmc-cap-uhs-sdr104"))
+		*caps |= MMC_CAP_UHS_SDR104;
+	if(of_property_read_bool(np, "mmc-cap-uhs-ddr50"))
+		*caps |= MMC_CAP_UHS_DDR50;
+	if(of_property_read_bool(np, "mmc-cap-driver-type-a"))
+		*caps |= MMC_CAP_DRIVER_TYPE_A;
+	if(of_property_read_bool(np, "mmc-cap-driver-type-c"))
+		*caps |= MMC_CAP_DRIVER_TYPE_C;
+	if(of_property_read_bool(np, "mmc-cap-driver-type-d"))
+		*caps |= MMC_CAP_DRIVER_TYPE_D;
+	if(of_property_read_bool(np, "mmc-cap-cmd23"))
+		*caps |= MMC_CAP_CMD23;
+	if(of_property_read_bool(np, "mmc-cap-hw-reset"))
+		*caps |= MMC_CAP_HW_RESET;
+
+	if(of_property_read_bool(np, "mmc-cap2-bootpart-noacc"))
+		*caps2 |= MMC_CAP2_BOOTPART_NOACC;
+	if(of_property_read_bool(np, "mmc-cap2-cache-ctrl"))
+		*caps2 |= MMC_CAP2_CACHE_CTRL;
+	if(of_property_read_bool(np, "mmc-cap2-poweroff-notify"))
+		*caps2 |= MMC_CAP2_POWEROFF_NOTIFY;
+	if(of_property_read_bool(np, "mmc-cap2-no-multi-read"))
+		*caps2 |= MMC_CAP2_NO_MULTI_READ;
+	if(of_property_read_bool(np, "mmc-cap2-no-sleep-cmd"))
+		*caps2 |= MMC_CAP2_NO_SLEEP_CMD;
+	if(of_property_read_bool(np, "mmc-cap2-hs200-1-8v-sdr"))
+		*caps2 |= MMC_CAP2_HS200_1_8V_SDR;
+	if(of_property_read_bool(np, "mmc-cap2-hs200-1-2v-sdr"))
+		*caps2 |= MMC_CAP2_HS200_1_2V_SDR;
+	if(of_property_read_bool(np, "mmc-cap2-hs200"))
+		*caps2 |= MMC_CAP2_HS200;
+	if(of_property_read_bool(np, "mmc-cap2-broken-voltage"))
+		*caps2 |= MMC_CAP2_BROKEN_VOLTAGE;
+	if(of_property_read_bool(np, "mmc-cap2-detect-on-err"))
+		*caps2 |= MMC_CAP2_DETECT_ON_ERR;
+	if(of_property_read_bool(np, "mmc-cap2-hc-erase-sz"))
+		*caps2 |= MMC_CAP2_HC_ERASE_SZ;
+	if(of_property_read_bool(np, "mmc-cap2-cd-active-high"))
+		*caps2 |= MMC_CAP2_CD_ACTIVE_HIGH;
+	if(of_property_read_bool(np, "mmc-cap2-ro-active-high"))
+		*caps2 |= MMC_CAP2_RO_ACTIVE_HIGH;
+}
+
+EXPORT_SYMBOL(mmc_of_populate_caps);
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index 7abb0e1..612cf0e 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -344,7 +344,8 @@  extern struct mmc_host *mmc_alloc_host(int extra, struct device *);
 extern int mmc_add_host(struct mmc_host *);
 extern void mmc_remove_host(struct mmc_host *);
 extern void mmc_free_host(struct mmc_host *);
-
+extern void mmc_of_populate_caps(struct device_node *,
+				 unsigned long *, unsigned int *);
 static inline void *mmc_priv(struct mmc_host *host)
 {
 	return (void *)host->private;