Can we merge the SD/MMC patches for i.MX MMC support into the linaro kernel? They have been reviewed extensively and look very likely to go into the next merge window.
Merging them and enabling SD support for i.MX51 will allow us to make a more functional hwpack for the babbage boards.
Please search for "SD/MMC driver for MX25/35/51" from Wolfram Sang on lakml for the patchset.
Regards, Amit
This sounds ok to me.
Nico, let me know when this is in your stable tree.
Thanks, John
On Mon, Oct 11, 2010 at 8:37 AM, Amit Kucheria amit.kucheria@linaro.org wrote:
Can we merge the SD/MMC patches for i.MX MMC support into the linaro kernel? They have been reviewed extensively and look very likely to go into the next merge window.
Merging them and enabling SD support for i.MX51 will allow us to make a more functional hwpack for the babbage boards.
Please search for "SD/MMC driver for MX25/35/51" from Wolfram Sang on lakml for the patchset.
Regards, Amit
linaro-dev mailing list linaro-dev@lists.linaro.org http://lists.linaro.org/mailman/listinfo/linaro-dev
Looks like discussion is still happening on the mmc mailing list wrt those patches. How pressing is it to have them merged? I'd like to pick up the final patch versions if possible.
Also I'd much prefer if someone could test those patches when applied to the linaro stable tree before actually merging them officially. Did someone test them already?
On Mon, 11 Oct 2010, John Rigby wrote:
This sounds ok to me.
Nico, let me know when this is in your stable tree.
Thanks, John
On Mon, Oct 11, 2010 at 8:37 AM, Amit Kucheria amit.kucheria@linaro.org wrote:
Can we merge the SD/MMC patches for i.MX MMC support into the linaro kernel? They have been reviewed extensively and look very likely to go into the next merge window.
Merging them and enabling SD support for i.MX51 will allow us to make a more functional hwpack for the babbage boards.
Please search for "SD/MMC driver for MX25/35/51" from Wolfram Sang on lakml for the patchset.
Regards, Amit
linaro-dev mailing list linaro-dev@lists.linaro.org http://lists.linaro.org/mailman/listinfo/linaro-dev
I applied the patches on linux-linaro-2.6.35, and can mount the rootfs on mmc.
On Tue, Oct 12, 2010 at 11:48 AM, Nicolas Pitre nicolas.pitre@linaro.org wrote:
Looks like discussion is still happening on the mmc mailing list wrt those patches. How pressing is it to have them merged? I'd like to pick up the final patch versions if possible.
Also I'd much prefer if someone could test those patches when applied to the linaro stable tree before actually merging them officially. Did someone test them already?
On Mon, 11 Oct 2010, John Rigby wrote:
This sounds ok to me.
Nico, let me know when this is in your stable tree.
Thanks, John
On Mon, Oct 11, 2010 at 8:37 AM, Amit Kucheria amit.kucheria@linaro.org wrote:
Can we merge the SD/MMC patches for i.MX MMC support into the linaro kernel? They have been reviewed extensively and look very likely to go into the next merge window.
Merging them and enabling SD support for i.MX51 will allow us to make a more functional hwpack for the babbage boards.
Please search for "SD/MMC driver for MX25/35/51" from Wolfram Sang on lakml for the patchset.
Regards, Amit
linaro-dev mailing list linaro-dev@lists.linaro.org http://lists.linaro.org/mailman/listinfo/linaro-dev
linaro-dev mailing list linaro-dev@lists.linaro.org http://lists.linaro.org/mailman/listinfo/linaro-dev
On Tue, Oct 12, 2010 at 11:59 AM, Shawn Guo shawn.gsc@gmail.com wrote:
I applied the patches on linux-linaro-2.6.35, and can mount the rootfs on mmc.
I'm sorry. This is a mis-communication. To clarify it, I tested Zhu Richard's bits other than Wolfram's at that time. As you have seen, I'm running into some problem with Wolfram's mmc driver plus my registration bits.
On Tue, Oct 12, 2010 at 11:48 AM, Nicolas Pitre nicolas.pitre@linaro.org wrote:
Looks like discussion is still happening on the mmc mailing list wrt those patches. How pressing is it to have them merged? I'd like to pick up the final patch versions if possible.
Also I'd much prefer if someone could test those patches when applied to the linaro stable tree before actually merging them officially. Did someone test them already?
On Mon, 11 Oct 2010, John Rigby wrote:
This sounds ok to me.
Nico, let me know when this is in your stable tree.
Thanks, John
On Mon, Oct 11, 2010 at 8:37 AM, Amit Kucheria amit.kucheria@linaro.org wrote:
Can we merge the SD/MMC patches for i.MX MMC support into the linaro kernel? They have been reviewed extensively and look very likely to go into the next merge window.
Merging them and enabling SD support for i.MX51 will allow us to make a more functional hwpack for the babbage boards.
Please search for "SD/MMC driver for MX25/35/51" from Wolfram Sang on lakml for the patchset.
Regards, Amit
Nico,
Yes it has been reviewed several times now. So I'm hopeful it'll go in for the next merge window.
Without it, linaro-media-create can't work since we don't support anything except SD boot for now.
/Amit
On Tue, Oct 12, 2010 at 6:48 AM, Nicolas Pitre nicolas.pitre@linaro.org wrote:
Looks like discussion is still happening on the mmc mailing list wrt those patches. How pressing is it to have them merged? I'd like to pick up the final patch versions if possible.
Also I'd much prefer if someone could test those patches when applied to the linaro stable tree before actually merging them officially. Did someone test them already?
On Mon, 11 Oct 2010, John Rigby wrote:
This sounds ok to me.
Nico, let me know when this is in your stable tree.
Thanks, John
On Tue, 12 Oct 2010, Amit Kucheria wrote:
Nico,
Yes it has been reviewed several times now. So I'm hopeful it'll go in for the next merge window.
It will. They're merged in cjb's tree now. And I've picked them up, plus a few others.
Compile tested only as I don't have the hardware.
Nicolas
Hi Nicolas,
Thanks for the merging. But the bits for babbage mmc resources and driver registration are missing. I'm trying to add them for getting a bootable mmc linaro image, but running into some problem right now. Will continue digging tomorrow.
On Sat, Oct 16, 2010 at 10:35 AM, Nicolas Pitre nicolas.pitre@linaro.org wrote:
On Tue, 12 Oct 2010, Amit Kucheria wrote:
Nico,
Yes it has been reviewed several times now. So I'm hopeful it'll go in for the next merge window.
It will. They're merged in cjb's tree now. And I've picked them up, plus a few others.
Compile tested only as I don't have the hardware.
Nicolas
linaro-dev mailing list linaro-dev@lists.linaro.org http://lists.linaro.org/mailman/listinfo/linaro-dev
On Sun, 17 Oct 2010, Shawn Guo wrote:
Hi Nicolas,
Thanks for the merging. But the bits for babbage mmc resources and driver registration are missing. I'm trying to add them for getting a bootable mmc linaro image, but running into some problem right now. Will continue digging tomorrow.
OK thanks. I'm definitely interested in your progress.
Nicolas
Hi Shawn,
Le 17/10/2010 17:27, Shawn Guo a écrit :
Thanks for the merging. But the bits for babbage mmc resources and driver registration are missing. I'm trying to add them for getting a bootable mmc linaro image, but running into some problem right now. Will continue digging tomorrow.
you can find a working example here : http://lists.infradead.org/pipermail/linux-arm-kernel/2010-October/028846.ht...
before, you will need this patch serie : http://lists.infradead.org/pipermail/linux-arm-kernel/2010-October/028826.ht... and this patch : http://lists.infradead.org/pipermail/linux-arm-kernel/2010-October/028855.ht...
Eric
Hi Eric,
Thanks for the links. I was following the patches to add the babbage registration specific bits (see patch below). I can see following mmc related boot log showing the card is initialized and recognized.
sdhci: Copyright(c) Pierre Ossman mmc0: SDHCI controller on platform [sdhci-esdhc-imx.0] using DMA mmc1: SDHCI controller on platform [sdhci-esdhc-imx.1] using DMA ...... Waiting for root device /dev/mmcblk0p3... mmc0: new high speed SD card at address fb74 blk_queue_max_hw_sectors: set to minimum 8 mmcblk0: mmc0:fb74 SD02G 1.83 GiB mmcblk0: p1 p2 p3 ......
But when I try to login console, it gives a bunch of error messages like below.
mmcblk0: error -110 transferring data, sector 1737392, nr 2, card status 0xe00 end_request: I/O error, dev mmcblk0, sector 1737392 mmcblk0: error -84 transferring data, sector 1737394, nr 8, card status 0x900 end_request: I/O error, dev mmcblk0, sector 1737394 mmcblk0: error -84 transferring data, sector 1737402, nr 8, card status 0x900 end_request: I/O error, dev mmcblk0, sector 1737402 ......
As you have tested Wolfram's bits on i.MX51 (eukrea?), probably my babbage registration bit is causing problem. Could you please help have a review to see if anything incorrect?
On Mon, Oct 18, 2010 at 1:04 AM, Eric Bénard eric@eukrea.com wrote:
Hi Shawn,
Le 17/10/2010 17:27, Shawn Guo a écrit :
Thanks for the merging. But the bits for babbage mmc resources and driver registration are missing. I'm trying to add them for getting a bootable mmc linaro image, but running into some problem right now. Will continue digging tomorrow.
you can find a working example here : http://lists.infradead.org/pipermail/linux-arm-kernel/2010-October/028846.ht...
before, you will need this patch serie : http://lists.infradead.org/pipermail/linux-arm-kernel/2010-October/028826.ht... and this patch : http://lists.infradead.org/pipermail/linux-arm-kernel/2010-October/028855.ht...
Eric
From 511b5ec7aaeb8c15b6613b9ff68e967998e6c37a Mon Sep 17 00:00:00 2001
From: Shawn Guo shawn.gsc@gmail.com Date: Sun, 17 Oct 2010 22:31:34 +0800 Subject: [PATCH] Add resource and registeration for wsa mmc driver
Signed-off-by: Shawn Guo shawn.gsc@gmail.com --- arch/arm/mach-mx5/Kconfig | 1 + arch/arm/mach-mx5/board-mx51_babbage.c | 20 ++ arch/arm/mach-mx5/clock-mx51.c | 268 +++++++++++++++-------- arch/arm/mach-mx5/devices-imx51.h | 17 ++ arch/arm/plat-mxc/devices/Kconfig | 3 + arch/arm/plat-mxc/devices/Makefile | 1 + arch/arm/plat-mxc/devices/platform-esdhc.c | 71 ++++++ arch/arm/plat-mxc/include/mach/devices-common.h | 10 + arch/arm/plat-mxc/include/mach/esdhc.h | 16 ++ arch/arm/plat-mxc/include/mach/iomux-mx51.h | 39 +++- arch/arm/plat-mxc/include/mach/mx51.h | 16 +- 11 files changed, 351 insertions(+), 111 deletions(-) create mode 100644 arch/arm/mach-mx5/devices-imx51.h create mode 100644 arch/arm/plat-mxc/devices/platform-esdhc.c create mode 100644 arch/arm/plat-mxc/include/mach/esdhc.h
diff --git a/arch/arm/mach-mx5/Kconfig b/arch/arm/mach-mx5/Kconfig index 0848db5..a263666 100644 --- a/arch/arm/mach-mx5/Kconfig +++ b/arch/arm/mach-mx5/Kconfig @@ -10,6 +10,7 @@ comment "MX5 platforms:"
config MACH_MX51_BABBAGE bool "Support MX51 BABBAGE platforms" + select IMX_HAVE_PLATFORM_ESDHC help Include support for MX51 Babbage platform, also known as MX51EVK in u-boot. This includes specific configurations for the board and its diff --git a/arch/arm/mach-mx5/board-mx51_babbage.c b/arch/arm/mach-mx5/board-mx51_babbage.c index 6e384d9..476bfe4 100644 --- a/arch/arm/mach-mx5/board-mx51_babbage.c +++ b/arch/arm/mach-mx5/board-mx51_babbage.c @@ -31,6 +31,7 @@ #include <asm/mach/arch.h> #include <asm/mach/time.h>
+#include "devices-imx51.h" #include "devices.h"
#define BABBAGE_USB_HUB_RESET (0*32 + 7) /* GPIO_1_7 */ @@ -93,6 +94,22 @@ static struct pad_desc mx51babbage_pads[] = {
/* USB HUB reset line*/ MX51_PAD_GPIO_1_7__GPIO_1_7, + + /* SD 1 */ + MX51_PAD_SD1_CMD__SD1_CMD, + MX51_PAD_SD1_CLK__SD1_CLK, + MX51_PAD_SD1_DATA0__SD1_DATA0, + MX51_PAD_SD1_DATA1__SD1_DATA1, + MX51_PAD_SD1_DATA2__SD1_DATA2, + MX51_PAD_SD1_DATA3__SD1_DATA3, + + /* SD 2 */ + MX51_PAD_SD2_CMD__SD2_CMD, + MX51_PAD_SD2_CLK__SD2_CLK, + MX51_PAD_SD2_DATA0__SD2_DATA0, + MX51_PAD_SD2_DATA1__SD2_DATA1, + MX51_PAD_SD2_DATA2__SD2_DATA2, + MX51_PAD_SD2_DATA3__SD2_DATA3, };
/* Serial ports */ @@ -268,6 +285,9 @@ static void __init mxc_board_init(void) /* setback USBH1_STP to be function */ mxc_iomux_v3_setup_pad(&usbh1stp); babbage_usbhub_reset(); + + imx51_add_esdhc(0, NULL); + imx51_add_esdhc(1, NULL); }
static void __init mx51_babbage_timer_init(void) diff --git a/arch/arm/mach-mx5/clock-mx51.c b/arch/arm/mach-mx5/clock-mx51.c index 57c10a9..c879a91 100644 --- a/arch/arm/mach-mx5/clock-mx51.c +++ b/arch/arm/mach-mx5/clock-mx51.c @@ -41,34 +41,66 @@ static struct clk usboh3_clk;
#define MAX_DPLL_WAIT_TRIES 1000 /* 1000 * udelay(1) = 1ms */
-static int _clk_ccgr_enable(struct clk *clk) +/* calculate best pre and post dividers to get the required divider */ +static void __calc_pre_post_dividers(u32 div, u32 *pre, u32 *post, + u32 max_pre, u32 max_post) +{ + if (div >= max_pre * max_post) { + *pre = max_pre; + *post = max_post; + } else if (div >= max_pre) { + u32 min_pre, temp_pre, old_err, err; + min_pre = DIV_ROUND_UP(div, max_post); + old_err = max_pre; + for (temp_pre = max_pre; temp_pre >= min_pre; temp_pre--) { + err = div % temp_pre; + if (err == 0) { + *pre = temp_pre; + break; + } + err = temp_pre - err; + if (err < old_err) { + old_err = err; + *pre = temp_pre; + } + } + *post = DIV_ROUND_UP(div, *pre); + } else { + *pre = div; + *post = 1; + } +} + +static void _clk_ccgr_setclk(struct clk *clk, unsigned mode) { - u32 reg; + u32 reg = __raw_readl(clk->enable_reg); + + reg &= ~(MXC_CCM_CCGRx_CG_MASK << clk->enable_shift); + reg |= mode << clk->enable_shift;
- reg = __raw_readl(clk->enable_reg); - reg |= MXC_CCM_CCGRx_MOD_ON << clk->enable_shift; __raw_writel(reg, clk->enable_reg); +}
+static int _clk_ccgr_enable(struct clk *clk) +{ + _clk_ccgr_setclk(clk, MXC_CCM_CCGRx_MOD_ON); return 0; }
static void _clk_ccgr_disable(struct clk *clk) { - u32 reg; - reg = __raw_readl(clk->enable_reg); - reg &= ~(MXC_CCM_CCGRx_CG_MASK << clk->enable_shift); - __raw_writel(reg, clk->enable_reg); + _clk_ccgr_setclk(clk, MXC_CCM_CCGRx_MOD_OFF); +}
+static int _clk_ccgr_enable_inrun(struct clk *clk) +{ + _clk_ccgr_setclk(clk, MXC_CCM_CCGRx_MOD_IDLE); + return 0; }
static void _clk_ccgr_disable_inwait(struct clk *clk) { - u32 reg; - - reg = __raw_readl(clk->enable_reg); - reg &= ~(MXC_CCM_CCGRx_CG_MASK << clk->enable_shift); - reg |= MXC_CCM_CCGRx_MOD_IDLE << clk->enable_shift; - __raw_writel(reg, clk->enable_reg); + _clk_ccgr_setclk(clk, MXC_CCM_CCGRx_MOD_IDLE); }
/* @@ -542,64 +574,6 @@ static int _clk_ipg_per_set_parent(struct clk *clk, struct clk *parent) return 0; }
-static unsigned long clk_uart_get_rate(struct clk *clk) -{ - u32 reg, prediv, podf; - unsigned long parent_rate; - - parent_rate = clk_get_rate(clk->parent); - - reg = __raw_readl(MXC_CCM_CSCDR1); - prediv = ((reg & MXC_CCM_CSCDR1_UART_CLK_PRED_MASK) >> - MXC_CCM_CSCDR1_UART_CLK_PRED_OFFSET) + 1; - podf = ((reg & MXC_CCM_CSCDR1_UART_CLK_PODF_MASK) >> - MXC_CCM_CSCDR1_UART_CLK_PODF_OFFSET) + 1; - - return parent_rate / (prediv * podf); -} - -static int _clk_uart_set_parent(struct clk *clk, struct clk *parent) -{ - u32 reg, mux; - - mux = _get_mux(parent, &pll1_sw_clk, &pll2_sw_clk, &pll3_sw_clk, - &lp_apm_clk); - reg = __raw_readl(MXC_CCM_CSCMR1) & ~MXC_CCM_CSCMR1_UART_CLK_SEL_MASK; - reg |= mux << MXC_CCM_CSCMR1_UART_CLK_SEL_OFFSET; - __raw_writel(reg, MXC_CCM_CSCMR1); - - return 0; -} - -static unsigned long clk_usboh3_get_rate(struct clk *clk) -{ - u32 reg, prediv, podf; - unsigned long parent_rate; - - parent_rate = clk_get_rate(clk->parent); - - reg = __raw_readl(MXC_CCM_CSCDR1); - prediv = ((reg & MXC_CCM_CSCDR1_USBOH3_CLK_PRED_MASK) >> - MXC_CCM_CSCDR1_USBOH3_CLK_PRED_OFFSET) + 1; - podf = ((reg & MXC_CCM_CSCDR1_USBOH3_CLK_PODF_MASK) >> - MXC_CCM_CSCDR1_USBOH3_CLK_PODF_OFFSET) + 1; - - return parent_rate / (prediv * podf); -} - -static int _clk_usboh3_set_parent(struct clk *clk, struct clk *parent) -{ - u32 reg, mux; - - mux = _get_mux(parent, &pll1_sw_clk, &pll2_sw_clk, &pll3_sw_clk, - &lp_apm_clk); - reg = __raw_readl(MXC_CCM_CSCMR1) & ~MXC_CCM_CSCMR1_USBOH3_CLK_SEL_MASK; - reg |= mux << MXC_CCM_CSCMR1_USBOH3_CLK_SEL_OFFSET; - __raw_writel(reg, MXC_CCM_CSCMR1); - - return 0; -} - static unsigned long get_high_reference_clock_rate(struct clk *clk) { return external_high_reference; @@ -715,18 +689,6 @@ static struct clk ipg_perclk = { .set_parent = _clk_ipg_per_set_parent, };
-static struct clk uart_root_clk = { - .parent = &pll2_sw_clk, - .get_rate = clk_uart_get_rate, - .set_parent = _clk_uart_set_parent, -}; - -static struct clk usboh3_clk = { - .parent = &pll2_sw_clk, - .get_rate = clk_usboh3_get_rate, - .set_parent = _clk_usboh3_set_parent, -}; - static struct clk ahb_max_clk = { .parent = &ahb_clk, .enable_reg = MXC_CCM_CCGR0, @@ -762,21 +724,125 @@ static struct clk kpp_clk = { .id = 0, };
-#define DEFINE_CLOCK(name, i, er, es, gr, sr, p, s) \ +#define DEFINE_CLOCK_MAX(name, i, er, es, pfx, p, s) \ static struct clk name = { \ .id = i, \ .enable_reg = er, \ .enable_shift = es, \ - .get_rate = gr, \ - .set_rate = sr, \ - .enable = _clk_ccgr_enable, \ - .disable = _clk_ccgr_disable, \ + .get_rate = pfx##_get_rate, \ + .set_rate = pfx##_set_rate, \ + .set_parent = pfx##_set_parent, \ + .enable = _clk_max_enable, \ + .disable = _clk_max_disable, \ .parent = p, \ .secondary = s, \ }
-/* DEFINE_CLOCK(name, id, enable_reg, enable_shift, - get_rate, set_rate, parent, secondary); */ +#define CLK_GET_RATE(name, nr, bitsname) \ +static unsigned long clk_##name##_get_rate(struct clk *clk) \ +{ \ + u32 reg, pred, podf; \ + \ + reg = __raw_readl(MXC_CCM_CSCDR##nr); \ + pred = (reg & MXC_CCM_CSCDR##nr##_##bitsname##_CLK_PRED_MASK) \ + >> MXC_CCM_CSCDR##nr##_##bitsname##_CLK_PRED_OFFSET; \ + podf = (reg & MXC_CCM_CSCDR##nr##_##bitsname##_CLK_PODF_MASK) \ + >> MXC_CCM_CSCDR##nr##_##bitsname##_CLK_PODF_OFFSET; \ + \ + return DIV_ROUND_CLOSEST(clk_get_rate(clk->parent), \ + (pred + 1) * (podf + 1)); \ +} + +#define CLK_SET_PARENT(name, nr, bitsname) \ +static int clk_##name##_set_parent(struct clk *clk, struct clk *parent) \ +{ \ + u32 reg, mux; \ + \ + mux = _get_mux(parent, &pll1_sw_clk, &pll2_sw_clk, \ + &pll3_sw_clk, &lp_apm_clk); \ + reg = __raw_readl(MXC_CCM_CSCMR##nr) & \ + ~MXC_CCM_CSCMR##nr##_##bitsname##_CLK_SEL_MASK; \ + reg |= mux << MXC_CCM_CSCMR##nr##_##bitsname##_CLK_SEL_OFFSET; \ + __raw_writel(reg, MXC_CCM_CSCMR##nr); \ + \ + return 0; \ +} + +#define CLK_SET_RATE(name, nr, bitsname) \ +static int clk_##name##_set_rate(struct clk *clk, unsigned long rate) \ +{ \ + u32 reg, div, parent_rate; \ + u32 pre = 0, post = 0; \ + \ + parent_rate = clk_get_rate(clk->parent); \ + div = parent_rate / rate; \ + \ + if ((parent_rate / div) != rate) \ + return -EINVAL; \ + \ + __calc_pre_post_dividers(div, &pre, &post, \ + (MXC_CCM_CSCDR##nr##_##bitsname##_CLK_PRED_MASK >> \ + MXC_CCM_CSCDR##nr##_##bitsname##_CLK_PRED_OFFSET) + 1, \ + (MXC_CCM_CSCDR##nr##_##bitsname##_CLK_PODF_MASK >> \ + MXC_CCM_CSCDR##nr##_##bitsname##_CLK_PODF_OFFSET) + 1);\ + \ + /* Set sdhc1 clock divider */ \ + reg = __raw_readl(MXC_CCM_CSCDR##nr) & \ + ~(MXC_CCM_CSCDR##nr##_##bitsname##_CLK_PRED_MASK \ + | MXC_CCM_CSCDR##nr##_##bitsname##_CLK_PODF_MASK); \ + reg |= (post - 1) << \ + MXC_CCM_CSCDR##nr##_##bitsname##_CLK_PODF_OFFSET; \ + reg |= (pre - 1) << \ + MXC_CCM_CSCDR##nr##_##bitsname##_CLK_PRED_OFFSET; \ + __raw_writel(reg, MXC_CCM_CSCDR##nr); \ + \ + return 0; \ +} + +/* UART */ +CLK_GET_RATE(uart, 1, UART) +CLK_SET_PARENT(uart, 1, UART) + +static struct clk uart_root_clk = { + .parent = &pll2_sw_clk, + .get_rate = clk_uart_get_rate, + .set_parent = clk_uart_set_parent, +}; + +/* USBOH3 */ +CLK_GET_RATE(usboh3, 1, USBOH3) +CLK_SET_PARENT(usboh3, 1, USBOH3) + +static struct clk usboh3_clk = { + .parent = &pll2_sw_clk, + .get_rate = clk_usboh3_get_rate, + .set_parent = clk_usboh3_set_parent, +}; + +/* eSDHC */ +CLK_GET_RATE(esdhc1, 1, ESDHC1_MSHC1) +CLK_SET_PARENT(esdhc1, 1, ESDHC1_MSHC1) +CLK_SET_RATE(esdhc1, 1, ESDHC1_MSHC1) + +CLK_GET_RATE(esdhc2, 1, ESDHC2_MSHC2) +CLK_SET_PARENT(esdhc2, 1, ESDHC2_MSHC2) +CLK_SET_RATE(esdhc2, 1, ESDHC2_MSHC2) + +#define DEFINE_CLOCK_FULL(name, i, er, es, gr, sr, e, d, p, s) \ + static struct clk name = { \ + .id = i, \ + .enable_reg = er, \ + .enable_shift = es, \ + .get_rate = gr, \ + .set_rate = sr, \ + .enable = e, \ + .disable = d, \ + .parent = p, \ + .secondary = s, \ + } + +#define DEFINE_CLOCK(name, i, er, es, gr, sr, p, s) \ + DEFINE_CLOCK_FULL(name, i, er, es, gr, sr, _clk_ccgr_enable, _clk_ccgr_disable, p, s)
/* Shared peripheral bus arbiter */ DEFINE_CLOCK(spba_clk, 0, MXC_CCM_CCGR5, MXC_CCM_CCGRx_CG0_OFFSET, @@ -814,6 +880,16 @@ DEFINE_CLOCK(hsi2c_clk, 0, MXC_CCM_CCGR1, MXC_CCM_CCGRx_CG11_OFFSET, DEFINE_CLOCK(fec_clk, 0, MXC_CCM_CCGR2, MXC_CCM_CCGRx_CG12_OFFSET, NULL, NULL, &ipg_clk, NULL);
+/* eSDHC */ +DEFINE_CLOCK_FULL(esdhc1_ipg_clk, 0, MXC_CCM_CCGR3, MXC_CCM_CCGRx_CG0_OFFSET, + NULL, NULL, _clk_max_enable, _clk_max_disable, &ipg_clk, NULL); +DEFINE_CLOCK_MAX(esdhc1_clk, 0, MXC_CCM_CCGR3, MXC_CCM_CCGRx_CG1_OFFSET, + clk_esdhc1, &pll2_sw_clk, &esdhc1_ipg_clk); +DEFINE_CLOCK_FULL(esdhc2_ipg_clk, 1, MXC_CCM_CCGR3, MXC_CCM_CCGRx_CG2_OFFSET, + NULL, NULL, _clk_max_enable, _clk_max_disable, &ipg_clk, NULL); +DEFINE_CLOCK_MAX(esdhc2_clk, 1, MXC_CCM_CCGR3, MXC_CCM_CCGRx_CG3_OFFSET, + clk_esdhc2, &pll2_sw_clk, &esdhc2_ipg_clk); + #define _REGISTER_CLOCK(d, n, c) \ { \ .dev_id = d, \ @@ -837,6 +913,8 @@ static struct clk_lookup lookups[] = { _REGISTER_CLOCK("fsl-usb2-udc", "usb", usboh3_clk) _REGISTER_CLOCK("fsl-usb2-udc", "usb_ahb", ahb_clk) _REGISTER_CLOCK("imx-keypad.0", NULL, kpp_clk) + _REGISTER_CLOCK("sdhci-esdhc-imx.0", NULL, esdhc1_clk) + _REGISTER_CLOCK("sdhci-esdhc-imx.1", NULL, esdhc2_clk) };
static void clk_tree_init(void) @@ -880,6 +958,14 @@ int __init mx51_clocks_init(unsigned long ckil, unsigned long osc, /* set the usboh3_clk parent to pll2_sw_clk */ clk_set_parent(&usboh3_clk, &pll2_sw_clk);
+ /* Set SDHC parents to be PLL2 */ + clk_set_parent(&esdhc1_clk, &pll2_sw_clk); + clk_set_parent(&esdhc2_clk, &pll2_sw_clk); + + /* set SDHC root clock as 166.25MHZ*/ + clk_set_rate(&esdhc1_clk, 166250000); + clk_set_rate(&esdhc2_clk, 166250000); + /* System timer */ mxc_timer_init(&gpt_clk, MX51_IO_ADDRESS(MX51_GPT1_BASE_ADDR), MX51_MXC_INT_GPT); diff --git a/arch/arm/mach-mx5/devices-imx51.h b/arch/arm/mach-mx5/devices-imx51.h new file mode 100644 index 0000000..1c43940 --- /dev/null +++ b/arch/arm/mach-mx5/devices-imx51.h @@ -0,0 +1,17 @@ +/*
+ * Copyright (C) 2010 Jason Wang <jason77.wang at gmail.com>
+ *
+ * based on mach-mx3/devices-imx35.h which is
+ * Copyright (C) 2010 Pengutronix
+ * Uwe Kleine-Koenig <u.kleine-koenig at pengutronix.de>
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License version 2 as published by the
+ * Free Software Foundation.
+ */
+#include <mach/mx51.h>
+#include <mach/devices-common.h>
+
+extern const struct imx_esdhc_imx_data imx51_esdhc_data[] __initconst;
+#define imx51_add_esdhc(id, pdata) \
+ imx_add_esdhc(&imx51_esdhc_data[id], pdata)
diff --git a/arch/arm/plat-mxc/devices/Kconfig b/arch/arm/plat-mxc/devices/Kconfig index 9ab784b..4730d2c 100644 --- a/arch/arm/plat-mxc/devices/Kconfig +++ b/arch/arm/plat-mxc/devices/Kconfig @@ -13,3 +13,6 @@ config IMX_HAVE_PLATFORM_MXC_NAND
config IMX_HAVE_PLATFORM_SPI_IMX bool + +config IMX_HAVE_PLATFORM_ESDHC + bool diff --git a/arch/arm/plat-mxc/devices/Makefile b/arch/arm/plat-mxc/devices/Makefile index 347da51..81aa17e 100644 --- a/arch/arm/plat-mxc/devices/Makefile +++ b/arch/arm/plat-mxc/devices/Makefile @@ -6,3 +6,4 @@ obj-$(CONFIG_IMX_HAVE_PLATFORM_IMX_I2C) += platform-imx-i2c.o obj-$(CONFIG_IMX_HAVE_PLATFORM_IMX_UART) += platform-imx-uart.o obj-$(CONFIG_IMX_HAVE_PLATFORM_MXC_NAND) += platform-mxc_nand.o obj-$(CONFIG_IMX_HAVE_PLATFORM_SPI_IMX) += platform-spi_imx.o +obj-$(CONFIG_IMX_HAVE_PLATFORM_ESDHC) += platform-esdhc.o diff --git a/arch/arm/plat-mxc/devices/platform-esdhc.c b/arch/arm/plat-mxc/devices/platform-esdhc.c new file mode 100644 index 0000000..668050b --- /dev/null +++ b/arch/arm/plat-mxc/devices/platform-esdhc.c @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2010 Pengutronix, Wolfram Sang <w.sang at pengutronix.de> + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License version 2 as published by the + * Free Software Foundation. + */ + +#include <mach/hardware.h> +#include <mach/devices-common.h> +#include <mach/esdhc.h> + +#define imx_esdhc_imx_data_entry_single(soc, _id, hwid) \ + { \ + .id = _id, \ + .iobase = soc ## _ESDHC ## hwid ## _BASE_ADDR, \ + .irq = soc ## _INT_ESDHC ## hwid, \ + } + +#define imx_esdhc_imx_data_entry(soc, id, hwid) \ + [id] = imx_esdhc_imx_data_entry_single(soc, id, hwid) + +#ifdef CONFIG_ARCH_MX25 +const struct imx_esdhc_imx_data imx25_esdhc_data[] __initconst = { +#define imx25_esdhc_data_entry(_id, _hwid) \ + imx_esdhc_imx_data_entry(MX25, _id, _hwid) + imx25_esdhc_data_entry(0, 1), + imx25_esdhc_data_entry(1, 2), +}; +#endif /* ifdef CONFIG_ARCH_MX25 */ + +#ifdef CONFIG_ARCH_MX35 +const struct imx_esdhc_imx_data imx35_esdhc_data[] __initconst = { +#define imx35_esdhc_data_entry(_id, _hwid) \ + imx_esdhc_imx_data_entry(MX35, _id, _hwid) + imx35_esdhc_data_entry(0, 1), + imx35_esdhc_data_entry(1, 2), + imx35_esdhc_data_entry(2, 3), +}; +#endif /* ifdef CONFIG_ARCH_MX35 */ + +#ifdef CONFIG_ARCH_MX51 +const struct imx_esdhc_imx_data imx51_esdhc_data[] __initconst = { +#define imx51_esdhc_data_entry(_id, _hwid) \ + imx_esdhc_imx_data_entry(MX51, _id, _hwid) + imx51_esdhc_data_entry(0, 1), + imx51_esdhc_data_entry(1, 2), + imx51_esdhc_data_entry(2, 3), + imx51_esdhc_data_entry(3, 4), +}; +#endif /* ifdef CONFIG_ARCH_MX51 */ + +struct platform_device *__init imx_add_esdhc( + const struct imx_esdhc_imx_data *data, + const struct esdhc_platform_data *pdata) +{ + struct resource res[] = { + { + .start = data->iobase, + .end = data->iobase + SZ_16K - 1, + .flags = IORESOURCE_MEM, + }, { + .start = data->irq, + .end = data->irq, + .flags = IORESOURCE_IRQ, + }, + }; + + return imx_add_platform_device("sdhci-esdhc-imx", data->id, res, + ARRAY_SIZE(res), pdata, sizeof(*pdata)); +} diff --git a/arch/arm/plat-mxc/include/mach/devices-common.h b/arch/arm/plat-mxc/include/mach/devices-common.h index c5f68c5..af7a232 100644 --- a/arch/arm/plat-mxc/include/mach/devices-common.h +++ b/arch/arm/plat-mxc/include/mach/devices-common.h @@ -58,3 +58,13 @@ struct platform_device *__init imx_add_mxc_nand_v21(resource_size_t iobase, struct platform_device *__init imx_add_spi_imx(int id, resource_size_t iobase, resource_size_t iosize, int irq, const struct spi_imx_master *pdata); + +#include <mach/esdhc.h> +struct imx_esdhc_imx_data { + int id; + resource_size_t iobase; + resource_size_t irq; +}; +struct platform_device *__init imx_add_esdhc( + const struct imx_esdhc_imx_data *data, + const struct esdhc_platform_data *pdata); diff --git a/arch/arm/plat-mxc/include/mach/esdhc.h b/arch/arm/plat-mxc/include/mach/esdhc.h new file mode 100644 index 0000000..0724bcd --- /dev/null +++ b/arch/arm/plat-mxc/include/mach/esdhc.h @@ -0,0 +1,16 @@ +/* + * Copyright 2010 Wolfram Sang <w.sang at pengutronix.de> + * + * 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; version 2 + * of the License. + */ + +#ifndef __ASM_ARCH_IMX_ESDHC_H +#define __ASM_ARCH_IMX_ESDHC_H + +struct esdhc_platform_data { + unsigned int wp_gpio; /* write protect pin */ +}; +#endif /* __ASM_ARCH_IMX_ESDHC_H */ diff --git a/arch/arm/plat-mxc/include/mach/iomux-mx51.h b/arch/arm/plat-mxc/include/mach/iomux-mx51.h index 21bfa46..935f790 100644 --- a/arch/arm/plat-mxc/include/mach/iomux-mx51.h +++ b/arch/arm/plat-mxc/include/mach/iomux-mx51.h @@ -45,6 +45,9 @@ typedef enum iomux_config { PAD_CTL_PKE | PAD_CTL_HYS) #define MX51_GPIO_PAD_CTRL (PAD_CTL_DSE_HIGH | PAD_CTL_PKE | \ PAD_CTL_SRE_FAST) +#define MX51_SDHCI_PAD_CTRL (PAD_CTL_DSE_HIGH | PAD_CTL_PUS_47K_UP | \ + PAD_CTL_PKE | PAD_CTL_PUE | PAD_CTL_SRE_FAST | \ + PAD_CTL_DVS)
/* * The naming convention for the pad modes is MX51_PAD_<padname>__<padmode> @@ -294,20 +297,32 @@ typedef enum iomux_config { #define MX51_PAD_DISP2_DAT13__DISP2_DAT13 IOMUX_PAD(0x790, 0x388, 0, 0x0, 0, NO_PAD_CTRL) #define MX51_PAD_DISP2_DAT14__DISP2_DAT14 IOMUX_PAD(0x794, 0x38C, 0, 0x0, 0, NO_PAD_CTRL) #define MX51_PAD_DISP2_DAT15__DISP2_DAT15 IOMUX_PAD(0x798, 0x390, 0, 0x0, 0, NO_PAD_CTRL) -#define MX51_PAD_SD1_CMD__SD1_CMD IOMUX_PAD(0x79C, 0x394, 0, 0x0, 0, NO_PAD_CTRL) -#define MX51_PAD_SD1_CLK__SD1_CLK IOMUX_PAD(0x7A0, 0x398, 0, 0x0, 0, NO_PAD_CTRL) -#define MX51_PAD_SD1_DATA0__SD1_DATA0 IOMUX_PAD(0x7A4, 0x39C, 0, 0x0, 0, NO_PAD_CTRL) -#define MX51_PAD_SD1_DATA1__SD1_DATA1 IOMUX_PAD(0x7A8, 0x3A0, 0, 0x0, 0, NO_PAD_CTRL) -#define MX51_PAD_SD1_DATA2__SD1_DATA2 IOMUX_PAD(0x7AC, 0x3A4, 0, 0x0, 0, NO_PAD_CTRL) -#define MX51_PAD_SD1_DATA3__SD1_DATA3 IOMUX_PAD(0x7B0, 0x3A8, 0, 0x0, 0, NO_PAD_CTRL) +#define MX51_PAD_SD1_CMD__SD1_CMD IOMUX_PAD(0x79C, 0x394, IOMUX_CONFIG_SION, 0x0, 0, \ + MX51_SDHCI_PAD_CTRL) +#define MX51_PAD_SD1_CLK__SD1_CLK IOMUX_PAD(0x7A0, 0x398, IOMUX_CONFIG_SION, 0x0, 0, \ + MX51_SDHCI_PAD_CTRL | PAD_CTL_HYS) +#define MX51_PAD_SD1_DATA0__SD1_DATA0 IOMUX_PAD(0x7A4, 0x39C, IOMUX_CONFIG_SION, 0x0, 0, \ + MX51_SDHCI_PAD_CTRL) +#define MX51_PAD_SD1_DATA1__SD1_DATA1 IOMUX_PAD(0x7A8, 0x3A0, IOMUX_CONFIG_SION, 0x0, 0, \ + MX51_SDHCI_PAD_CTRL) +#define MX51_PAD_SD1_DATA2__SD1_DATA2 IOMUX_PAD(0x7AC, 0x3A4, IOMUX_CONFIG_SION, 0x0, 0, \ + MX51_SDHCI_PAD_CTRL) +#define MX51_PAD_SD1_DATA3__SD1_DATA3 IOMUX_PAD(0x7B0, 0x3A8, IOMUX_CONFIG_SION, 0x0, 0, \ + MX51_SDHCI_PAD_CTRL) #define MX51_PAD_GPIO_1_0__GPIO_1_0 IOMUX_PAD(0x7B4, 0x3AC, 1, 0x0, 0, NO_PAD_CTRL) #define MX51_PAD_GPIO_1_1__GPIO_1_1 IOMUX_PAD(0x7B8, 0x3B0, 1, 0x0, 0, NO_PAD_CTRL) -#define MX51_PAD_SD2_CMD__SD2_CMD IOMUX_PAD(0x7BC, 0x3B4, 0, 0x0, 0, NO_PAD_CTRL) -#define MX51_PAD_SD2_CLK__SD2_CLK IOMUX_PAD(0x7C0, 0x3B8, 0, 0x0, 0, NO_PAD_CTRL) -#define MX51_PAD_SD2_DATA0__SD2_DATA0 IOMUX_PAD(0x7C4, 0x3BC, 0, 0x0, 0, NO_PAD_CTRL) -#define MX51_PAD_SD2_DATA1__SD2_DATA1 IOMUX_PAD(0x7C8, 0x3C0, 0, 0x0, 0, NO_PAD_CTRL) -#define MX51_PAD_SD2_DATA2__SD2_DATA2 IOMUX_PAD(0x7CC, 0x3C4, 0, 0x0, 0, NO_PAD_CTRL) -#define MX51_PAD_SD2_DATA3__SD2_DATA3 IOMUX_PAD(0x7D0, 0x3C8, 0, 0x0, 0, NO_PAD_CTRL) +#define MX51_PAD_SD2_CMD__SD2_CMD IOMUX_PAD(0x7BC, 0x3B4, IOMUX_CONFIG_SION, 0x0, 1, \ + MX51_SDHCI_PAD_CTRL) +#define MX51_PAD_SD2_CLK__SD2_CLK IOMUX_PAD(0x7C0, 0x3B8, IOMUX_CONFIG_SION, 0x0, 0, \ + MX51_SDHCI_PAD_CTRL | PAD_CTL_HYS) +#define MX51_PAD_SD2_DATA0__SD2_DATA0 IOMUX_PAD(0x7C4, 0x3BC, IOMUX_CONFIG_SION, 0x0, 0, \ + MX51_SDHCI_PAD_CTRL) +#define MX51_PAD_SD2_DATA1__SD2_DATA1 IOMUX_PAD(0x7C8, 0x3C0, IOMUX_CONFIG_SION, 0x0, 0, \ + MX51_SDHCI_PAD_CTRL) +#define MX51_PAD_SD2_DATA2__SD2_DATA2 IOMUX_PAD(0x7CC, 0x3C4, IOMUX_CONFIG_SION, 0x0, 0, \ + MX51_SDHCI_PAD_CTRL) +#define MX51_PAD_SD2_DATA3__SD2_DATA3 IOMUX_PAD(0x7D0, 0x3C8, IOMUX_CONFIG_SION, 0x0, 0, \ + MX51_SDHCI_PAD_CTRL) #define MX51_PAD_GPIO_1_2__GPIO_1_2 IOMUX_PAD(0x7D4, 0x3CC, 0, 0x0, 0, NO_PAD_CTRL) #define MX51_PAD_GPIO_1_2__I2C2_SCL IOMUX_PAD(0x7D4, 0x3CC, (2 | IOMUX_CONFIG_SION), \ 0x9b8, 3, MX51_I2C_PAD_CTRL) diff --git a/arch/arm/plat-mxc/include/mach/mx51.h b/arch/arm/plat-mxc/include/mach/mx51.h index 5aad344..5be17ae 100644 --- a/arch/arm/plat-mxc/include/mach/mx51.h +++ b/arch/arm/plat-mxc/include/mach/mx51.h @@ -76,13 +76,13 @@ #define MX51_SPBA0_BASE_ADDR_VIRT 0xFB100000 #define MX51_SPBA0_SIZE SZ_1M
-#define MX51_MMC_SDHC1_BASE_ADDR (MX51_SPBA0_BASE_ADDR + 0x00004000) -#define MX51_MMC_SDHC2_BASE_ADDR (MX51_SPBA0_BASE_ADDR + 0x00008000) +#define MX51_ESDHC1_BASE_ADDR (MX51_SPBA0_BASE_ADDR + 0x00004000) +#define MX51_ESDHC2_BASE_ADDR (MX51_SPBA0_BASE_ADDR + 0x00008000) #define MX51_UART3_BASE_ADDR (MX51_SPBA0_BASE_ADDR + 0x0000C000) #define MX51_CSPI1_BASE_ADDR (MX51_SPBA0_BASE_ADDR + 0x00010000) #define MX51_SSI2_BASE_ADDR (MX51_SPBA0_BASE_ADDR + 0x00014000) -#define MX51_MMC_SDHC3_BASE_ADDR (MX51_SPBA0_BASE_ADDR + 0x00020000) -#define MX51_MMC_SDHC4_BASE_ADDR (MX51_SPBA0_BASE_ADDR + 0x00024000) +#define MX51_ESDHC3_BASE_ADDR (MX51_SPBA0_BASE_ADDR + 0x00020000) +#define MX51_ESDHC4_BASE_ADDR (MX51_SPBA0_BASE_ADDR + 0x00024000) #define MX51_SPDIF_BASE_ADDR (MX51_SPBA0_BASE_ADDR + 0x00028000) #define MX51_ATA_DMA_BASE_ADDR (MX51_SPBA0_BASE_ADDR + 0x00030000) #define MX51_SLIM_DMA_BASE_ADDR (MX51_SPBA0_BASE_ADDR + 0x00034000) @@ -319,10 +319,10 @@ */ #define MX51_MXC_INT_BASE 0 #define MX51_MXC_INT_RESV0 0 -#define MX51_MXC_INT_MMC_SDHC1 1 -#define MX51_MXC_INT_MMC_SDHC2 2 -#define MX51_MXC_INT_MMC_SDHC3 3 -#define MX51_MXC_INT_MMC_SDHC4 4 +#define MX51_INT_ESDHC1 1 +#define MX51_INT_ESDHC2 2 +#define MX51_INT_ESDHC3 3 +#define MX51_INT_ESDHC4 4 #define MX51_MXC_INT_RESV5 5 #define MX51_MXC_INT_SDMA 6 #define MX51_MXC_INT_IOMUX 7
Correct Richard address ...
On Mon, Oct 18, 2010 at 4:10 PM, Shawn Guo shawn.gsc@gmail.com wrote:
Hi Eric,
Thanks for the links. I was following the patches to add the babbage registration specific bits (see patch below). I can see following mmc related boot log showing the card is initialized and recognized.
sdhci: Copyright(c) Pierre Ossman mmc0: SDHCI controller on platform [sdhci-esdhc-imx.0] using DMA mmc1: SDHCI controller on platform [sdhci-esdhc-imx.1] using DMA ...... Waiting for root device /dev/mmcblk0p3... mmc0: new high speed SD card at address fb74 blk_queue_max_hw_sectors: set to minimum 8 mmcblk0: mmc0:fb74 SD02G 1.83 GiB mmcblk0: p1 p2 p3 ......
But when I try to login console, it gives a bunch of error messages like below.
mmcblk0: error -110 transferring data, sector 1737392, nr 2, card status 0xe00 end_request: I/O error, dev mmcblk0, sector 1737392 mmcblk0: error -84 transferring data, sector 1737394, nr 8, card status 0x900 end_request: I/O error, dev mmcblk0, sector 1737394 mmcblk0: error -84 transferring data, sector 1737402, nr 8, card status 0x900 end_request: I/O error, dev mmcblk0, sector 1737402 ......
As you have tested Wolfram's bits on i.MX51 (eukrea?), probably my babbage registration bit is causing problem. Could you please help have a review to see if anything incorrect?
On Mon, Oct 18, 2010 at 1:04 AM, Eric Bénard eric@eukrea.com wrote:
Hi Shawn,
Le 17/10/2010 17:27, Shawn Guo a écrit :
Thanks for the merging. But the bits for babbage mmc resources and driver registration are missing. I'm trying to add them for getting a bootable mmc linaro image, but running into some problem right now. Will continue digging tomorrow.
you can find a working example here : http://lists.infradead.org/pipermail/linux-arm-kernel/2010-October/028846.ht...
before, you will need this patch serie : http://lists.infradead.org/pipermail/linux-arm-kernel/2010-October/028826.ht... and this patch : http://lists.infradead.org/pipermail/linux-arm-kernel/2010-October/028855.ht...
Eric
From 511b5ec7aaeb8c15b6613b9ff68e967998e6c37a Mon Sep 17 00:00:00 2001 From: Shawn Guo shawn.gsc@gmail.com Date: Sun, 17 Oct 2010 22:31:34 +0800 Subject: [PATCH] Add resource and registeration for wsa mmc driver
Signed-off-by: Shawn Guo shawn.gsc@gmail.com
arch/arm/mach-mx5/Kconfig | 1 + arch/arm/mach-mx5/board-mx51_babbage.c | 20 ++ arch/arm/mach-mx5/clock-mx51.c | 268 +++++++++++++++-------- arch/arm/mach-mx5/devices-imx51.h | 17 ++ arch/arm/plat-mxc/devices/Kconfig | 3 + arch/arm/plat-mxc/devices/Makefile | 1 + arch/arm/plat-mxc/devices/platform-esdhc.c | 71 ++++++ arch/arm/plat-mxc/include/mach/devices-common.h | 10 + arch/arm/plat-mxc/include/mach/esdhc.h | 16 ++ arch/arm/plat-mxc/include/mach/iomux-mx51.h | 39 +++- arch/arm/plat-mxc/include/mach/mx51.h | 16 +- 11 files changed, 351 insertions(+), 111 deletions(-) create mode 100644 arch/arm/mach-mx5/devices-imx51.h create mode 100644 arch/arm/plat-mxc/devices/platform-esdhc.c create mode 100644 arch/arm/plat-mxc/include/mach/esdhc.h
diff --git a/arch/arm/mach-mx5/Kconfig b/arch/arm/mach-mx5/Kconfig index 0848db5..a263666 100644 --- a/arch/arm/mach-mx5/Kconfig +++ b/arch/arm/mach-mx5/Kconfig @@ -10,6 +10,7 @@ comment "MX5 platforms:"
config MACH_MX51_BABBAGE bool "Support MX51 BABBAGE platforms"
- select IMX_HAVE_PLATFORM_ESDHC
help Include support for MX51 Babbage platform, also known as MX51EVK in u-boot. This includes specific configurations for the board and its diff --git a/arch/arm/mach-mx5/board-mx51_babbage.c b/arch/arm/mach-mx5/board-mx51_babbage.c index 6e384d9..476bfe4 100644 --- a/arch/arm/mach-mx5/board-mx51_babbage.c +++ b/arch/arm/mach-mx5/board-mx51_babbage.c @@ -31,6 +31,7 @@ #include <asm/mach/arch.h> #include <asm/mach/time.h>
+#include "devices-imx51.h" #include "devices.h"
#define BABBAGE_USB_HUB_RESET (0*32 + 7) /* GPIO_1_7 */ @@ -93,6 +94,22 @@ static struct pad_desc mx51babbage_pads[] = {
/* USB HUB reset line*/ MX51_PAD_GPIO_1_7__GPIO_1_7,
- /* SD 1 */
- MX51_PAD_SD1_CMD__SD1_CMD,
- MX51_PAD_SD1_CLK__SD1_CLK,
- MX51_PAD_SD1_DATA0__SD1_DATA0,
- MX51_PAD_SD1_DATA1__SD1_DATA1,
- MX51_PAD_SD1_DATA2__SD1_DATA2,
- MX51_PAD_SD1_DATA3__SD1_DATA3,
- /* SD 2 */
- MX51_PAD_SD2_CMD__SD2_CMD,
- MX51_PAD_SD2_CLK__SD2_CLK,
- MX51_PAD_SD2_DATA0__SD2_DATA0,
- MX51_PAD_SD2_DATA1__SD2_DATA1,
- MX51_PAD_SD2_DATA2__SD2_DATA2,
- MX51_PAD_SD2_DATA3__SD2_DATA3,
};
/* Serial ports */ @@ -268,6 +285,9 @@ static void __init mxc_board_init(void) /* setback USBH1_STP to be function */ mxc_iomux_v3_setup_pad(&usbh1stp); babbage_usbhub_reset();
- imx51_add_esdhc(0, NULL);
- imx51_add_esdhc(1, NULL);
}
static void __init mx51_babbage_timer_init(void) diff --git a/arch/arm/mach-mx5/clock-mx51.c b/arch/arm/mach-mx5/clock-mx51.c index 57c10a9..c879a91 100644 --- a/arch/arm/mach-mx5/clock-mx51.c +++ b/arch/arm/mach-mx5/clock-mx51.c @@ -41,34 +41,66 @@ static struct clk usboh3_clk;
#define MAX_DPLL_WAIT_TRIES 1000 /* 1000 * udelay(1) = 1ms */
-static int _clk_ccgr_enable(struct clk *clk) +/* calculate best pre and post dividers to get the required divider */ +static void __calc_pre_post_dividers(u32 div, u32 *pre, u32 *post,
- u32 max_pre, u32 max_post)
+{
- if (div >= max_pre * max_post) {
- *pre = max_pre;
- *post = max_post;
- } else if (div >= max_pre) {
- u32 min_pre, temp_pre, old_err, err;
- min_pre = DIV_ROUND_UP(div, max_post);
- old_err = max_pre;
- for (temp_pre = max_pre; temp_pre >= min_pre; temp_pre--) {
- err = div % temp_pre;
- if (err == 0) {
- *pre = temp_pre;
- break;
- }
- err = temp_pre - err;
- if (err < old_err) {
- old_err = err;
- *pre = temp_pre;
- }
- }
- *post = DIV_ROUND_UP(div, *pre);
- } else {
- *pre = div;
- *post = 1;
- }
+}
+static void _clk_ccgr_setclk(struct clk *clk, unsigned mode) {
- u32 reg;
- u32 reg = __raw_readl(clk->enable_reg);
- reg &= ~(MXC_CCM_CCGRx_CG_MASK << clk->enable_shift);
- reg |= mode << clk->enable_shift;
- reg = __raw_readl(clk->enable_reg);
- reg |= MXC_CCM_CCGRx_MOD_ON << clk->enable_shift;
__raw_writel(reg, clk->enable_reg); +}
+static int _clk_ccgr_enable(struct clk *clk) +{
- _clk_ccgr_setclk(clk, MXC_CCM_CCGRx_MOD_ON);
return 0; }
static void _clk_ccgr_disable(struct clk *clk) {
- u32 reg;
- reg = __raw_readl(clk->enable_reg);
- reg &= ~(MXC_CCM_CCGRx_CG_MASK << clk->enable_shift);
- __raw_writel(reg, clk->enable_reg);
- _clk_ccgr_setclk(clk, MXC_CCM_CCGRx_MOD_OFF);
+}
+static int _clk_ccgr_enable_inrun(struct clk *clk) +{
- _clk_ccgr_setclk(clk, MXC_CCM_CCGRx_MOD_IDLE);
- return 0;
}
static void _clk_ccgr_disable_inwait(struct clk *clk) {
- u32 reg;
- reg = __raw_readl(clk->enable_reg);
- reg &= ~(MXC_CCM_CCGRx_CG_MASK << clk->enable_shift);
- reg |= MXC_CCM_CCGRx_MOD_IDLE << clk->enable_shift;
- __raw_writel(reg, clk->enable_reg);
- _clk_ccgr_setclk(clk, MXC_CCM_CCGRx_MOD_IDLE);
}
/* @@ -542,64 +574,6 @@ static int _clk_ipg_per_set_parent(struct clk *clk, struct clk *parent) return 0; }
-static unsigned long clk_uart_get_rate(struct clk *clk) -{
- u32 reg, prediv, podf;
- unsigned long parent_rate;
- parent_rate = clk_get_rate(clk->parent);
- reg = __raw_readl(MXC_CCM_CSCDR1);
- prediv = ((reg & MXC_CCM_CSCDR1_UART_CLK_PRED_MASK) >>
- MXC_CCM_CSCDR1_UART_CLK_PRED_OFFSET) + 1;
- podf = ((reg & MXC_CCM_CSCDR1_UART_CLK_PODF_MASK) >>
- MXC_CCM_CSCDR1_UART_CLK_PODF_OFFSET) + 1;
- return parent_rate / (prediv * podf);
-}
-static int _clk_uart_set_parent(struct clk *clk, struct clk *parent) -{
- u32 reg, mux;
- mux = _get_mux(parent, &pll1_sw_clk, &pll2_sw_clk, &pll3_sw_clk,
- &lp_apm_clk);
- reg = __raw_readl(MXC_CCM_CSCMR1) & ~MXC_CCM_CSCMR1_UART_CLK_SEL_MASK;
- reg |= mux << MXC_CCM_CSCMR1_UART_CLK_SEL_OFFSET;
- __raw_writel(reg, MXC_CCM_CSCMR1);
- return 0;
-}
-static unsigned long clk_usboh3_get_rate(struct clk *clk) -{
- u32 reg, prediv, podf;
- unsigned long parent_rate;
- parent_rate = clk_get_rate(clk->parent);
- reg = __raw_readl(MXC_CCM_CSCDR1);
- prediv = ((reg & MXC_CCM_CSCDR1_USBOH3_CLK_PRED_MASK) >>
- MXC_CCM_CSCDR1_USBOH3_CLK_PRED_OFFSET) + 1;
- podf = ((reg & MXC_CCM_CSCDR1_USBOH3_CLK_PODF_MASK) >>
- MXC_CCM_CSCDR1_USBOH3_CLK_PODF_OFFSET) + 1;
- return parent_rate / (prediv * podf);
-}
-static int _clk_usboh3_set_parent(struct clk *clk, struct clk *parent) -{
- u32 reg, mux;
- mux = _get_mux(parent, &pll1_sw_clk, &pll2_sw_clk, &pll3_sw_clk,
- &lp_apm_clk);
- reg = __raw_readl(MXC_CCM_CSCMR1) & ~MXC_CCM_CSCMR1_USBOH3_CLK_SEL_MASK;
- reg |= mux << MXC_CCM_CSCMR1_USBOH3_CLK_SEL_OFFSET;
- __raw_writel(reg, MXC_CCM_CSCMR1);
- return 0;
-}
static unsigned long get_high_reference_clock_rate(struct clk *clk) { return external_high_reference; @@ -715,18 +689,6 @@ static struct clk ipg_perclk = { .set_parent = _clk_ipg_per_set_parent, };
-static struct clk uart_root_clk = {
- .parent = &pll2_sw_clk,
- .get_rate = clk_uart_get_rate,
- .set_parent = _clk_uart_set_parent,
-};
-static struct clk usboh3_clk = {
- .parent = &pll2_sw_clk,
- .get_rate = clk_usboh3_get_rate,
- .set_parent = _clk_usboh3_set_parent,
-};
static struct clk ahb_max_clk = { .parent = &ahb_clk, .enable_reg = MXC_CCM_CCGR0, @@ -762,21 +724,125 @@ static struct clk kpp_clk = { .id = 0, };
-#define DEFINE_CLOCK(name, i, er, es, gr, sr, p, s) \ +#define DEFINE_CLOCK_MAX(name, i, er, es, pfx, p, s) \ static struct clk name = { \ .id = i, \ .enable_reg = er, \ .enable_shift = es, \
- .get_rate = gr, \
- .set_rate = sr, \
- .enable = _clk_ccgr_enable, \
- .disable = _clk_ccgr_disable, \
- .get_rate = pfx##_get_rate, \
- .set_rate = pfx##_set_rate, \
- .set_parent = pfx##_set_parent, \
- .enable = _clk_max_enable, \
- .disable = _clk_max_disable, \
.parent = p, \ .secondary = s, \ }
-/* DEFINE_CLOCK(name, id, enable_reg, enable_shift,
- get_rate, set_rate, parent, secondary); */
+#define CLK_GET_RATE(name, nr, bitsname) \ +static unsigned long clk_##name##_get_rate(struct clk *clk) \ +{ \
- u32 reg, pred, podf; \
- \
- reg = __raw_readl(MXC_CCM_CSCDR##nr); \
- pred = (reg & MXC_CCM_CSCDR##nr##_##bitsname##_CLK_PRED_MASK) \
- >> MXC_CCM_CSCDR##nr##_##bitsname##_CLK_PRED_OFFSET; \
- podf = (reg & MXC_CCM_CSCDR##nr##_##bitsname##_CLK_PODF_MASK) \
- >> MXC_CCM_CSCDR##nr##_##bitsname##_CLK_PODF_OFFSET; \
- \
- return DIV_ROUND_CLOSEST(clk_get_rate(clk->parent), \
- (pred + 1) * (podf + 1)); \
+}
+#define CLK_SET_PARENT(name, nr, bitsname) \ +static int clk_##name##_set_parent(struct clk *clk, struct clk *parent) \ +{ \
- u32 reg, mux; \
- \
- mux = _get_mux(parent, &pll1_sw_clk, &pll2_sw_clk, \
- &pll3_sw_clk, &lp_apm_clk); \
- reg = __raw_readl(MXC_CCM_CSCMR##nr) & \
- ~MXC_CCM_CSCMR##nr##_##bitsname##_CLK_SEL_MASK; \
- reg |= mux << MXC_CCM_CSCMR##nr##_##bitsname##_CLK_SEL_OFFSET; \
- __raw_writel(reg, MXC_CCM_CSCMR##nr); \
- \
- return 0; \
+}
+#define CLK_SET_RATE(name, nr, bitsname) \ +static int clk_##name##_set_rate(struct clk *clk, unsigned long rate) \ +{ \
- u32 reg, div, parent_rate; \
- u32 pre = 0, post = 0; \
- \
- parent_rate = clk_get_rate(clk->parent); \
- div = parent_rate / rate; \
- \
- if ((parent_rate / div) != rate) \
- return -EINVAL; \
- \
- __calc_pre_post_dividers(div, &pre, &post, \
- (MXC_CCM_CSCDR##nr##_##bitsname##_CLK_PRED_MASK >> \
- MXC_CCM_CSCDR##nr##_##bitsname##_CLK_PRED_OFFSET) + 1, \
- (MXC_CCM_CSCDR##nr##_##bitsname##_CLK_PODF_MASK >> \
- MXC_CCM_CSCDR##nr##_##bitsname##_CLK_PODF_OFFSET) + 1);\
- \
- /* Set sdhc1 clock divider */ \
- reg = __raw_readl(MXC_CCM_CSCDR##nr) & \
- ~(MXC_CCM_CSCDR##nr##_##bitsname##_CLK_PRED_MASK \
- | MXC_CCM_CSCDR##nr##_##bitsname##_CLK_PODF_MASK); \
- reg |= (post - 1) << \
- MXC_CCM_CSCDR##nr##_##bitsname##_CLK_PODF_OFFSET; \
- reg |= (pre - 1) << \
- MXC_CCM_CSCDR##nr##_##bitsname##_CLK_PRED_OFFSET; \
- __raw_writel(reg, MXC_CCM_CSCDR##nr); \
- \
- return 0; \
+}
+/* UART */ +CLK_GET_RATE(uart, 1, UART) +CLK_SET_PARENT(uart, 1, UART)
+static struct clk uart_root_clk = {
- .parent = &pll2_sw_clk,
- .get_rate = clk_uart_get_rate,
- .set_parent = clk_uart_set_parent,
+};
+/* USBOH3 */ +CLK_GET_RATE(usboh3, 1, USBOH3) +CLK_SET_PARENT(usboh3, 1, USBOH3)
+static struct clk usboh3_clk = {
- .parent = &pll2_sw_clk,
- .get_rate = clk_usboh3_get_rate,
- .set_parent = clk_usboh3_set_parent,
+};
+/* eSDHC */ +CLK_GET_RATE(esdhc1, 1, ESDHC1_MSHC1) +CLK_SET_PARENT(esdhc1, 1, ESDHC1_MSHC1) +CLK_SET_RATE(esdhc1, 1, ESDHC1_MSHC1)
+CLK_GET_RATE(esdhc2, 1, ESDHC2_MSHC2) +CLK_SET_PARENT(esdhc2, 1, ESDHC2_MSHC2) +CLK_SET_RATE(esdhc2, 1, ESDHC2_MSHC2)
+#define DEFINE_CLOCK_FULL(name, i, er, es, gr, sr, e, d, p, s) \
- static struct clk name = { \
- .id = i, \
- .enable_reg = er, \
- .enable_shift = es, \
- .get_rate = gr, \
- .set_rate = sr, \
- .enable = e, \
- .disable = d, \
- .parent = p, \
- .secondary = s, \
- }
+#define DEFINE_CLOCK(name, i, er, es, gr, sr, p, s) \
- DEFINE_CLOCK_FULL(name, i, er, es, gr, sr, _clk_ccgr_enable,
_clk_ccgr_disable, p, s)
/* Shared peripheral bus arbiter */ DEFINE_CLOCK(spba_clk, 0, MXC_CCM_CCGR5, MXC_CCM_CCGRx_CG0_OFFSET, @@ -814,6 +880,16 @@ DEFINE_CLOCK(hsi2c_clk, 0, MXC_CCM_CCGR1, MXC_CCM_CCGRx_CG11_OFFSET, DEFINE_CLOCK(fec_clk, 0, MXC_CCM_CCGR2, MXC_CCM_CCGRx_CG12_OFFSET, NULL, NULL, &ipg_clk, NULL);
+/* eSDHC */ +DEFINE_CLOCK_FULL(esdhc1_ipg_clk, 0, MXC_CCM_CCGR3, MXC_CCM_CCGRx_CG0_OFFSET,
- NULL, NULL, _clk_max_enable, _clk_max_disable, &ipg_clk, NULL);
+DEFINE_CLOCK_MAX(esdhc1_clk, 0, MXC_CCM_CCGR3, MXC_CCM_CCGRx_CG1_OFFSET,
- clk_esdhc1, &pll2_sw_clk, &esdhc1_ipg_clk);
+DEFINE_CLOCK_FULL(esdhc2_ipg_clk, 1, MXC_CCM_CCGR3, MXC_CCM_CCGRx_CG2_OFFSET,
- NULL, NULL, _clk_max_enable, _clk_max_disable, &ipg_clk, NULL);
+DEFINE_CLOCK_MAX(esdhc2_clk, 1, MXC_CCM_CCGR3, MXC_CCM_CCGRx_CG3_OFFSET,
- clk_esdhc2, &pll2_sw_clk, &esdhc2_ipg_clk);
#define _REGISTER_CLOCK(d, n, c) \ { \ .dev_id = d, \ @@ -837,6 +913,8 @@ static struct clk_lookup lookups[] = { _REGISTER_CLOCK("fsl-usb2-udc", "usb", usboh3_clk) _REGISTER_CLOCK("fsl-usb2-udc", "usb_ahb", ahb_clk) _REGISTER_CLOCK("imx-keypad.0", NULL, kpp_clk)
- _REGISTER_CLOCK("sdhci-esdhc-imx.0", NULL, esdhc1_clk)
- _REGISTER_CLOCK("sdhci-esdhc-imx.1", NULL, esdhc2_clk)
};
static void clk_tree_init(void) @@ -880,6 +958,14 @@ int __init mx51_clocks_init(unsigned long ckil, unsigned long osc, /* set the usboh3_clk parent to pll2_sw_clk */ clk_set_parent(&usboh3_clk, &pll2_sw_clk);
- /* Set SDHC parents to be PLL2 */
- clk_set_parent(&esdhc1_clk, &pll2_sw_clk);
- clk_set_parent(&esdhc2_clk, &pll2_sw_clk);
- /* set SDHC root clock as 166.25MHZ*/
- clk_set_rate(&esdhc1_clk, 166250000);
- clk_set_rate(&esdhc2_clk, 166250000);
/* System timer */ mxc_timer_init(&gpt_clk, MX51_IO_ADDRESS(MX51_GPT1_BASE_ADDR), MX51_MXC_INT_GPT); diff --git a/arch/arm/mach-mx5/devices-imx51.h b/arch/arm/mach-mx5/devices-imx51.h new file mode 100644 index 0000000..1c43940 --- /dev/null +++ b/arch/arm/mach-mx5/devices-imx51.h @@ -0,0 +1,17 @@ +/*
- Copyright (C) 2010 Jason Wang <jason77.wang at gmail.com>
- based on mach-mx3/devices-imx35.h which is
- Copyright (C) 2010 Pengutronix
- Uwe Kleine-Koenig <u.kleine-koenig at pengutronix.de>
- This program is free software; you can redistribute it and/or
modify it under
- the terms of the GNU General Public License version 2 as published by the
- Free Software Foundation.
*/
+#include <mach/mx51.h>
+#include <mach/devices-common.h>
+extern const struct imx_esdhc_imx_data imx51_esdhc_data[] __initconst;
+#define imx51_add_esdhc(id, pdata) \
- imx_add_esdhc(&imx51_esdhc_data[id], pdata)
diff --git a/arch/arm/plat-mxc/devices/Kconfig b/arch/arm/plat-mxc/devices/Kconfig index 9ab784b..4730d2c 100644 --- a/arch/arm/plat-mxc/devices/Kconfig +++ b/arch/arm/plat-mxc/devices/Kconfig @@ -13,3 +13,6 @@ config IMX_HAVE_PLATFORM_MXC_NAND
config IMX_HAVE_PLATFORM_SPI_IMX bool
+config IMX_HAVE_PLATFORM_ESDHC
- bool
diff --git a/arch/arm/plat-mxc/devices/Makefile b/arch/arm/plat-mxc/devices/Makefile index 347da51..81aa17e 100644 --- a/arch/arm/plat-mxc/devices/Makefile +++ b/arch/arm/plat-mxc/devices/Makefile @@ -6,3 +6,4 @@ obj-$(CONFIG_IMX_HAVE_PLATFORM_IMX_I2C) += platform-imx-i2c.o obj-$(CONFIG_IMX_HAVE_PLATFORM_IMX_UART) += platform-imx-uart.o obj-$(CONFIG_IMX_HAVE_PLATFORM_MXC_NAND) += platform-mxc_nand.o obj-$(CONFIG_IMX_HAVE_PLATFORM_SPI_IMX) += platform-spi_imx.o +obj-$(CONFIG_IMX_HAVE_PLATFORM_ESDHC) += platform-esdhc.o diff --git a/arch/arm/plat-mxc/devices/platform-esdhc.c b/arch/arm/plat-mxc/devices/platform-esdhc.c new file mode 100644 index 0000000..668050b --- /dev/null +++ b/arch/arm/plat-mxc/devices/platform-esdhc.c @@ -0,0 +1,71 @@ +/*
- Copyright (C) 2010 Pengutronix, Wolfram Sang <w.sang at pengutronix.de>
- This program is free software; you can redistribute it and/or
modify it under
- the terms of the GNU General Public License version 2 as published by the
- Free Software Foundation.
- */
+#include <mach/hardware.h> +#include <mach/devices-common.h> +#include <mach/esdhc.h>
+#define imx_esdhc_imx_data_entry_single(soc, _id, hwid) \
- { \
- .id = _id, \
- .iobase = soc ## _ESDHC ## hwid ## _BASE_ADDR, \
- .irq = soc ## _INT_ESDHC ## hwid, \
- }
+#define imx_esdhc_imx_data_entry(soc, id, hwid) \
- [id] = imx_esdhc_imx_data_entry_single(soc, id, hwid)
+#ifdef CONFIG_ARCH_MX25 +const struct imx_esdhc_imx_data imx25_esdhc_data[] __initconst = { +#define imx25_esdhc_data_entry(_id, _hwid) \
- imx_esdhc_imx_data_entry(MX25, _id, _hwid)
- imx25_esdhc_data_entry(0, 1),
- imx25_esdhc_data_entry(1, 2),
+}; +#endif /* ifdef CONFIG_ARCH_MX25 */
+#ifdef CONFIG_ARCH_MX35 +const struct imx_esdhc_imx_data imx35_esdhc_data[] __initconst = { +#define imx35_esdhc_data_entry(_id, _hwid) \
- imx_esdhc_imx_data_entry(MX35, _id, _hwid)
- imx35_esdhc_data_entry(0, 1),
- imx35_esdhc_data_entry(1, 2),
- imx35_esdhc_data_entry(2, 3),
+}; +#endif /* ifdef CONFIG_ARCH_MX35 */
+#ifdef CONFIG_ARCH_MX51 +const struct imx_esdhc_imx_data imx51_esdhc_data[] __initconst = { +#define imx51_esdhc_data_entry(_id, _hwid) \
- imx_esdhc_imx_data_entry(MX51, _id, _hwid)
- imx51_esdhc_data_entry(0, 1),
- imx51_esdhc_data_entry(1, 2),
- imx51_esdhc_data_entry(2, 3),
- imx51_esdhc_data_entry(3, 4),
+}; +#endif /* ifdef CONFIG_ARCH_MX51 */
+struct platform_device *__init imx_add_esdhc(
- const struct imx_esdhc_imx_data *data,
- const struct esdhc_platform_data *pdata)
+{
- struct resource res[] = {
- {
- .start = data->iobase,
- .end = data->iobase + SZ_16K - 1,
- .flags = IORESOURCE_MEM,
- }, {
- .start = data->irq,
- .end = data->irq,
- .flags = IORESOURCE_IRQ,
- },
- };
- return imx_add_platform_device("sdhci-esdhc-imx", data->id, res,
- ARRAY_SIZE(res), pdata, sizeof(*pdata));
+} diff --git a/arch/arm/plat-mxc/include/mach/devices-common.h b/arch/arm/plat-mxc/include/mach/devices-common.h index c5f68c5..af7a232 100644 --- a/arch/arm/plat-mxc/include/mach/devices-common.h +++ b/arch/arm/plat-mxc/include/mach/devices-common.h @@ -58,3 +58,13 @@ struct platform_device *__init imx_add_mxc_nand_v21(resource_size_t iobase, struct platform_device *__init imx_add_spi_imx(int id, resource_size_t iobase, resource_size_t iosize, int irq, const struct spi_imx_master *pdata);
+#include <mach/esdhc.h> +struct imx_esdhc_imx_data {
- int id;
- resource_size_t iobase;
- resource_size_t irq;
+}; +struct platform_device *__init imx_add_esdhc(
- const struct imx_esdhc_imx_data *data,
- const struct esdhc_platform_data *pdata);
diff --git a/arch/arm/plat-mxc/include/mach/esdhc.h b/arch/arm/plat-mxc/include/mach/esdhc.h new file mode 100644 index 0000000..0724bcd --- /dev/null +++ b/arch/arm/plat-mxc/include/mach/esdhc.h @@ -0,0 +1,16 @@ +/*
- Copyright 2010 Wolfram Sang <w.sang at pengutronix.de>
- 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; version 2
- of the License.
- */
+#ifndef __ASM_ARCH_IMX_ESDHC_H +#define __ASM_ARCH_IMX_ESDHC_H
+struct esdhc_platform_data {
- unsigned int wp_gpio; /* write protect pin */
+}; +#endif /* __ASM_ARCH_IMX_ESDHC_H */ diff --git a/arch/arm/plat-mxc/include/mach/iomux-mx51.h b/arch/arm/plat-mxc/include/mach/iomux-mx51.h index 21bfa46..935f790 100644 --- a/arch/arm/plat-mxc/include/mach/iomux-mx51.h +++ b/arch/arm/plat-mxc/include/mach/iomux-mx51.h @@ -45,6 +45,9 @@ typedef enum iomux_config { PAD_CTL_PKE | PAD_CTL_HYS) #define MX51_GPIO_PAD_CTRL (PAD_CTL_DSE_HIGH | PAD_CTL_PKE | \ PAD_CTL_SRE_FAST) +#define MX51_SDHCI_PAD_CTRL (PAD_CTL_DSE_HIGH | PAD_CTL_PUS_47K_UP | \
- PAD_CTL_PKE | PAD_CTL_PUE | PAD_CTL_SRE_FAST | \
- PAD_CTL_DVS)
/* * The naming convention for the pad modes is MX51_PAD_<padname>__<padmode> @@ -294,20 +297,32 @@ typedef enum iomux_config { #define MX51_PAD_DISP2_DAT13__DISP2_DAT13 IOMUX_PAD(0x790, 0x388, 0, 0x0, 0, NO_PAD_CTRL) #define MX51_PAD_DISP2_DAT14__DISP2_DAT14 IOMUX_PAD(0x794, 0x38C, 0, 0x0, 0, NO_PAD_CTRL) #define MX51_PAD_DISP2_DAT15__DISP2_DAT15 IOMUX_PAD(0x798, 0x390, 0, 0x0, 0, NO_PAD_CTRL) -#define MX51_PAD_SD1_CMD__SD1_CMD IOMUX_PAD(0x79C, 0x394, 0, 0x0, 0, NO_PAD_CTRL) -#define MX51_PAD_SD1_CLK__SD1_CLK IOMUX_PAD(0x7A0, 0x398, 0, 0x0, 0, NO_PAD_CTRL) -#define MX51_PAD_SD1_DATA0__SD1_DATA0 IOMUX_PAD(0x7A4, 0x39C, 0, 0x0, 0, NO_PAD_CTRL) -#define MX51_PAD_SD1_DATA1__SD1_DATA1 IOMUX_PAD(0x7A8, 0x3A0, 0, 0x0, 0, NO_PAD_CTRL) -#define MX51_PAD_SD1_DATA2__SD1_DATA2 IOMUX_PAD(0x7AC, 0x3A4, 0, 0x0, 0, NO_PAD_CTRL) -#define MX51_PAD_SD1_DATA3__SD1_DATA3 IOMUX_PAD(0x7B0, 0x3A8, 0, 0x0, 0, NO_PAD_CTRL) +#define MX51_PAD_SD1_CMD__SD1_CMD IOMUX_PAD(0x79C, 0x394, IOMUX_CONFIG_SION, 0x0, 0, \
- MX51_SDHCI_PAD_CTRL)
+#define MX51_PAD_SD1_CLK__SD1_CLK IOMUX_PAD(0x7A0, 0x398, IOMUX_CONFIG_SION, 0x0, 0, \
- MX51_SDHCI_PAD_CTRL | PAD_CTL_HYS)
+#define MX51_PAD_SD1_DATA0__SD1_DATA0 IOMUX_PAD(0x7A4, 0x39C, IOMUX_CONFIG_SION, 0x0, 0, \
- MX51_SDHCI_PAD_CTRL)
+#define MX51_PAD_SD1_DATA1__SD1_DATA1 IOMUX_PAD(0x7A8, 0x3A0, IOMUX_CONFIG_SION, 0x0, 0, \
- MX51_SDHCI_PAD_CTRL)
+#define MX51_PAD_SD1_DATA2__SD1_DATA2 IOMUX_PAD(0x7AC, 0x3A4, IOMUX_CONFIG_SION, 0x0, 0, \
- MX51_SDHCI_PAD_CTRL)
+#define MX51_PAD_SD1_DATA3__SD1_DATA3 IOMUX_PAD(0x7B0, 0x3A8, IOMUX_CONFIG_SION, 0x0, 0, \
- MX51_SDHCI_PAD_CTRL)
#define MX51_PAD_GPIO_1_0__GPIO_1_0 IOMUX_PAD(0x7B4, 0x3AC, 1, 0x0, 0, NO_PAD_CTRL) #define MX51_PAD_GPIO_1_1__GPIO_1_1 IOMUX_PAD(0x7B8, 0x3B0, 1, 0x0, 0, NO_PAD_CTRL) -#define MX51_PAD_SD2_CMD__SD2_CMD IOMUX_PAD(0x7BC, 0x3B4, 0, 0x0, 0, NO_PAD_CTRL) -#define MX51_PAD_SD2_CLK__SD2_CLK IOMUX_PAD(0x7C0, 0x3B8, 0, 0x0, 0, NO_PAD_CTRL) -#define MX51_PAD_SD2_DATA0__SD2_DATA0 IOMUX_PAD(0x7C4, 0x3BC, 0, 0x0, 0, NO_PAD_CTRL) -#define MX51_PAD_SD2_DATA1__SD2_DATA1 IOMUX_PAD(0x7C8, 0x3C0, 0, 0x0, 0, NO_PAD_CTRL) -#define MX51_PAD_SD2_DATA2__SD2_DATA2 IOMUX_PAD(0x7CC, 0x3C4, 0, 0x0, 0, NO_PAD_CTRL) -#define MX51_PAD_SD2_DATA3__SD2_DATA3 IOMUX_PAD(0x7D0, 0x3C8, 0, 0x0, 0, NO_PAD_CTRL) +#define MX51_PAD_SD2_CMD__SD2_CMD IOMUX_PAD(0x7BC, 0x3B4, IOMUX_CONFIG_SION, 0x0, 1, \
- MX51_SDHCI_PAD_CTRL)
+#define MX51_PAD_SD2_CLK__SD2_CLK IOMUX_PAD(0x7C0, 0x3B8, IOMUX_CONFIG_SION, 0x0, 0, \
- MX51_SDHCI_PAD_CTRL | PAD_CTL_HYS)
+#define MX51_PAD_SD2_DATA0__SD2_DATA0 IOMUX_PAD(0x7C4, 0x3BC, IOMUX_CONFIG_SION, 0x0, 0, \
- MX51_SDHCI_PAD_CTRL)
+#define MX51_PAD_SD2_DATA1__SD2_DATA1 IOMUX_PAD(0x7C8, 0x3C0, IOMUX_CONFIG_SION, 0x0, 0, \
- MX51_SDHCI_PAD_CTRL)
+#define MX51_PAD_SD2_DATA2__SD2_DATA2 IOMUX_PAD(0x7CC, 0x3C4, IOMUX_CONFIG_SION, 0x0, 0, \
- MX51_SDHCI_PAD_CTRL)
+#define MX51_PAD_SD2_DATA3__SD2_DATA3 IOMUX_PAD(0x7D0, 0x3C8, IOMUX_CONFIG_SION, 0x0, 0, \
- MX51_SDHCI_PAD_CTRL)
#define MX51_PAD_GPIO_1_2__GPIO_1_2 IOMUX_PAD(0x7D4, 0x3CC, 0, 0x0, 0, NO_PAD_CTRL) #define MX51_PAD_GPIO_1_2__I2C2_SCL IOMUX_PAD(0x7D4, 0x3CC, (2 | IOMUX_CONFIG_SION), \ 0x9b8, 3, MX51_I2C_PAD_CTRL) diff --git a/arch/arm/plat-mxc/include/mach/mx51.h b/arch/arm/plat-mxc/include/mach/mx51.h index 5aad344..5be17ae 100644 --- a/arch/arm/plat-mxc/include/mach/mx51.h +++ b/arch/arm/plat-mxc/include/mach/mx51.h @@ -76,13 +76,13 @@ #define MX51_SPBA0_BASE_ADDR_VIRT 0xFB100000 #define MX51_SPBA0_SIZE SZ_1M
-#define MX51_MMC_SDHC1_BASE_ADDR (MX51_SPBA0_BASE_ADDR + 0x00004000) -#define MX51_MMC_SDHC2_BASE_ADDR (MX51_SPBA0_BASE_ADDR + 0x00008000) +#define MX51_ESDHC1_BASE_ADDR (MX51_SPBA0_BASE_ADDR + 0x00004000) +#define MX51_ESDHC2_BASE_ADDR (MX51_SPBA0_BASE_ADDR + 0x00008000) #define MX51_UART3_BASE_ADDR (MX51_SPBA0_BASE_ADDR + 0x0000C000) #define MX51_CSPI1_BASE_ADDR (MX51_SPBA0_BASE_ADDR + 0x00010000) #define MX51_SSI2_BASE_ADDR (MX51_SPBA0_BASE_ADDR + 0x00014000) -#define MX51_MMC_SDHC3_BASE_ADDR (MX51_SPBA0_BASE_ADDR + 0x00020000) -#define MX51_MMC_SDHC4_BASE_ADDR (MX51_SPBA0_BASE_ADDR + 0x00024000) +#define MX51_ESDHC3_BASE_ADDR (MX51_SPBA0_BASE_ADDR + 0x00020000) +#define MX51_ESDHC4_BASE_ADDR (MX51_SPBA0_BASE_ADDR + 0x00024000) #define MX51_SPDIF_BASE_ADDR (MX51_SPBA0_BASE_ADDR + 0x00028000) #define MX51_ATA_DMA_BASE_ADDR (MX51_SPBA0_BASE_ADDR + 0x00030000) #define MX51_SLIM_DMA_BASE_ADDR (MX51_SPBA0_BASE_ADDR + 0x00034000) @@ -319,10 +319,10 @@ */ #define MX51_MXC_INT_BASE 0 #define MX51_MXC_INT_RESV0 0 -#define MX51_MXC_INT_MMC_SDHC1 1 -#define MX51_MXC_INT_MMC_SDHC2 2 -#define MX51_MXC_INT_MMC_SDHC3 3 -#define MX51_MXC_INT_MMC_SDHC4 4 +#define MX51_INT_ESDHC1 1 +#define MX51_INT_ESDHC2 2 +#define MX51_INT_ESDHC3 3 +#define MX51_INT_ESDHC4 4 #define MX51_MXC_INT_RESV5 5 #define MX51_MXC_INT_SDMA 6 #define MX51_MXC_INT_IOMUX 7 -- 1.7.1
-- Regards, Shawn
Hi Shawn,
Le 18/10/2010 10:10, Shawn Guo a écrit :
But when I try to login console, it gives a bunch of error messages like below.
mmcblk0: error -110 transferring data, sector 1737392, nr 2, card status 0xe00 end_request: I/O error, dev mmcblk0, sector 1737392 mmcblk0: error -84 transferring data, sector 1737394, nr 8, card status 0x900 end_request: I/O error, dev mmcblk0, sector 1737394 mmcblk0: error -84 transferring data, sector 1737402, nr 8, card status 0x900 end_request: I/O error, dev mmcblk0, sector 1737402 ......
As you have tested Wolfram's bits on i.MX51 (eukrea?), probably my babbage registration bit is causing problem. Could you please help have a review to see if anything incorrect?
I just tested a linaro rootfs on SDCard (we have a nand flash so until now we had our rootfs on it) and got the same errors as you. As suggested by Richard, SDHCI_QUIRK_BROKEN_TIMEOUT_VAL seems to fix the problem, so can you try the following patch ?
BTW, concerning Linaro's rootfs, I didn't managed to get a login prompt on the serial port because of udev problems certainly because I'm missing options in the kernel configuration, but at least I don't have anymore mmc error messages.
Eric
diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c index 2e9cca1..e8f7048 100644 --- a/drivers/mmc/host/sdhci-esdhc-imx.c +++ b/drivers/mmc/host/sdhci-esdhc-imx.c @@ -134,7 +134,8 @@ static struct sdhci_ops sdhci_esdhc_ops = {
struct sdhci_pltfm_data sdhci_esdhc_imx_pdata = { .quirks = ESDHC_DEFAULT_QUIRKS | SDHCI_QUIRK_NO_MULTIBLOCK - | SDHCI_QUIRK_BROKEN_ADMA, + | SDHCI_QUIRK_BROKEN_ADMA + | SDHCI_QUIRK_BROKEN_TIMEOUT_VAL, /* ADMA has issues. Might be fixable */ /* NO_MULTIBLOCK might be MX35 only (Errata: ENGcm07207) */ .ops = &sdhci_esdhc_ops,
On Mon, Oct 18, 2010 at 5:34 PM, Eric Bénard eric@eukrea.com wrote:
I just tested a linaro rootfs on SDCard (we have a nand flash so until now we had our rootfs on it) and got the same errors as you. As suggested by Richard, SDHCI_QUIRK_BROKEN_TIMEOUT_VAL seems to fix the problem, so can you try the following patch ?
diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c index 2e9cca1..e8f7048 100644 --- a/drivers/mmc/host/sdhci-esdhc-imx.c +++ b/drivers/mmc/host/sdhci-esdhc-imx.c @@ -134,7 +134,8 @@ static struct sdhci_ops sdhci_esdhc_ops = {
struct sdhci_pltfm_data sdhci_esdhc_imx_pdata = { .quirks = ESDHC_DEFAULT_QUIRKS | SDHCI_QUIRK_NO_MULTIBLOCK
- | SDHCI_QUIRK_BROKEN_ADMA,
- | SDHCI_QUIRK_BROKEN_ADMA
- | SDHCI_QUIRK_BROKEN_TIMEOUT_VAL,
/* ADMA has issues. Might be fixable */ /* NO_MULTIBLOCK might be MX35 only (Errata: ENGcm07207) */ .ops = &sdhci_esdhc_ops,
Yes, it's working. And I can get into Linaro console now. So we need the following bits to get it work.
- Wolfram's esdhc driver (merged) - SDHCI_QUIRK_BROKEN_TIMEOUT_VAL patch - Babbage registration patch (based on Eric's bits) - Related kernel configurations
Hi Shawn,
Le 18/10/2010 11:46, Shawn Guo a écrit :
Yes, it's working. And I can get into Linaro console now. So we need the following bits to get it work.
- Wolfram's esdhc driver (merged)
- SDHCI_QUIRK_BROKEN_TIMEOUT_VAL patch
- Babbage registration patch (based on Eric's bits)
- Related kernel configurations
may you please send me your .config and the link to the git tree your are using for your kernel ? I don't manage to boot the Linaro headless rootfs on my board (ureadahead crash then nothing more on the console) and now I've started to play with that I so want to get the login :-D and I think I may be missing a kernel option but which one ?
Kernel : 2.6.37-rc7 + i.MX patches Command line : console=ttymxc0,115200 root=/dev/mmcblk0p3 rootfstype=ext3 ip=off rootwait rw
Thanks, Eric
Here you go. I'm using Linaro tree below.
git://git.linaro.org/kernel/linux-linaro-2.6.35.git
Also make sure you have the change below for /bin/auto-serial-console.
line #15 of auto-serial-console: tty[A-Z]* ) --> tty[a-zA-Z]* )
On Mon, Oct 18, 2010 at 6:42 PM, Eric Bénard eric@eukrea.com wrote:
Hi Shawn,
Le 18/10/2010 11:46, Shawn Guo a écrit :
Yes, it's working. And I can get into Linaro console now. So we need the following bits to get it work.
- Wolfram's esdhc driver (merged)
- SDHCI_QUIRK_BROKEN_TIMEOUT_VAL patch
- Babbage registration patch (based on Eric's bits)
- Related kernel configurations
may you please send me your .config and the link to the git tree your are using for your kernel ? I don't manage to boot the Linaro headless rootfs on my board (ureadahead crash then nothing more on the console) and now I've started to play with that I so want to get the login :-D and I think I may be missing a kernel option but which one ?
Kernel : 2.6.37-rc7 + i.MX patches Command line : console=ttymxc0,115200 root=/dev/mmcblk0p3 rootfstype=ext3 ip=off rootwait rw
Thanks, Eric
Le 18/10/2010 12:58, Shawn Guo a écrit :
Here you go. I'm using Linaro tree below.
git://git.linaro.org/kernel/linux-linaro-2.6.35.git
Also make sure you have the change below for /bin/auto-serial-console.
line #15 of auto-serial-console: tty[A-Z]* ) --> tty[a-zA-Z]* )
Thanks. Now it's booting fine on my board (using 2.6.36-rc7 + mmc & imx patches). The error was that I wasn't using the uInitrd which seems to be absolutely necessary to prepare the rootfs to boot.
Eric
Shawn,
So does git://git.linaro.org/kernel/linux-linaro-2.6.35.git have everything you want in the linaro packaged kernel? Can you tell me what CONFIGs need to be turned on?
Thanks, John
On Mon, Oct 18, 2010 at 4:58 AM, Shawn Guo shawn.gsc@gmail.com wrote:
Here you go. I'm using Linaro tree below.
git://git.linaro.org/kernel/linux-linaro-2.6.35.git
Also make sure you have the change below for /bin/auto-serial-console.
line #15 of auto-serial-console: tty[A-Z]* ) --> tty[a-zA-Z]* )
On Mon, Oct 18, 2010 at 6:42 PM, Eric Bénard eric@eukrea.com wrote:
Hi Shawn,
Le 18/10/2010 11:46, Shawn Guo a écrit :
Yes, it's working. And I can get into Linaro console now. So we need the following bits to get it work.
- Wolfram's esdhc driver (merged)
- SDHCI_QUIRK_BROKEN_TIMEOUT_VAL patch
- Babbage registration patch (based on Eric's bits)
- Related kernel configurations
may you please send me your .config and the link to the git tree your are using for your kernel ? I don't manage to boot the Linaro headless rootfs on my board (ureadahead crash then nothing more on the console) and now I've started to play with that I so want to get the login :-D and I think I may be missing a kernel option but which one ?
Kernel : 2.6.37-rc7 + i.MX patches Command line : console=ttymxc0,115200 root=/dev/mmcblk0p3 rootfstype=ext3 ip=off rootwait rw
Thanks, Eric
-- Regards, Shawn
linaro-dev mailing list linaro-dev@lists.linaro.org http://lists.linaro.org/mailman/listinfo/linaro-dev
On Mon, 18 Oct 2010, John Rigby wrote:
Shawn,
So does git://git.linaro.org/kernel/linux-linaro-2.6.35.git have everything you want in the linaro packaged kernel?
I don't think so. Seems that the device registration for Babbage is missing, as well as a quirk for the timeout problem. However I'd prefer if someone has a set of only those missing and _tested_ patches somewhere that I could apply instead of me second guessing what's needed without being able to test the result myself.
Nicolas
Nicolas,
Thanks for the info. I'll wait to see more patches/testing from Shawn before pulling.
John
On Mon, Oct 18, 2010 at 8:50 AM, Nicolas Pitre nicolas.pitre@linaro.org wrote:
On Mon, 18 Oct 2010, John Rigby wrote:
Shawn,
So does git://git.linaro.org/kernel/linux-linaro-2.6.35.git have everything you want in the linaro packaged kernel?
I don't think so. Seems that the device registration for Babbage is missing, as well as a quirk for the timeout problem. However I'd prefer if someone has a set of only those missing and _tested_ patches somewhere that I could apply instead of me second guessing what's needed without being able to test the result myself.
Nicolas
On Mon, 2010-10-18 at 18:58 +0800, Shawn Guo wrote:
Here you go. I'm using Linaro tree below.
git://git.linaro.org/kernel/linux-linaro-2.6.35.git
I've tried using this tree, (as well as the pengutronix.de tree and linus' upstream) with an older 9.04 disk image, but none of the booting kernels could find the sd card (no mmcblk devices located in the boot log)
So sort of to echo what Nicolas said, it seems pretty difficult to follow which set of patches (as well as what .config settings) are needed to get upstream booting.
Also, after trying to create a imx51 sd image with the lastest linaro-media-create tools & nightly images, the board didn't seem to be able to find uboot on the resulting sd card (wouldn't stay on when i pushed the power button). Are there still issues with the uboot integration? Or am I just doing something wrong?
thanks -john
On Mon, Oct 18, 2010 at 06:47:19PM -0700, john stultz wrote:
I've tried using this tree, (as well as the pengutronix.de tree and linus' upstream) with an older 9.04 disk image, but none of the booting kernels could find the sd card (no mmcblk devices located in the boot log)
I didn't follow this thread very closely (actually I'm on holiday :)), but have you disabled CONFIG_SYSFS_DEPRECATED? This causes issues with newer udevs if activated. One of them is that mmcblk devices are not created when initally booting.
On Tue, 2010-10-19 at 03:59 +0200, Wolfram Sang wrote:
On Mon, Oct 18, 2010 at 06:47:19PM -0700, john stultz wrote:
I've tried using this tree, (as well as the pengutronix.de tree and linus' upstream) with an older 9.04 disk image, but none of the booting kernels could find the sd card (no mmcblk devices located in the boot log)
I didn't follow this thread very closely (actually I'm on holiday :)), but have you disabled CONFIG_SYSFS_DEPRECATED? This causes issues with newer udevs if activated. One of them is that mmcblk devices are not created when initally booting.
Hrm. Unfortunately that's already off in my .config, so it must be something else. But thanks so much for the suggestion!
Now get back to enjoying your holiday! :) -john
Hi John,
On Tue, Oct 19, 2010 at 9:47 AM, john stultz johnstul@us.ibm.com wrote:
So sort of to echo what Nicolas said, it seems pretty difficult to follow which set of patches (as well as what .config settings) are needed to get upstream booting.
I just sent out the patch (to linaro-dev) which is working on Linaro kernel tree per my test.
Also, after trying to create a imx51 sd image with the lastest linaro-media-create tools & nightly images, the board didn't seem to be able to find uboot on the resulting sd card (wouldn't stay on when i pushed the power button). Are there still issues with the uboot integration? Or am I just doing something wrong?
There is a bug which can be fixed by https://bugs.launchpad.net/linux-linaro/+bug/656962/comments/2.
Loic, Alexander,
Could the fix be merged soon? This is really a show-stopper bug.
On Tue, Oct 19, 2010, Shawn Guo wrote:
I merged this; would be awesome if you could send further code changes as bzr merge request (push your topic branch to launchpad and bzr lp-propose-merge)!
Thanks
Hi Loic,
I like the merge request way, but I'm behind a firewall. I was told that it's tough to get bzr push through firewall. Any suggestion to break the firewall through?
On Tue, Oct 19, 2010 at 6:05 PM, Loïc Minier loic.minier@linaro.org wrote:
On Tue, Oct 19, 2010, Shawn Guo wrote:
I merged this; would be awesome if you could send further code changes as bzr merge request (push your topic branch to launchpad and bzr lp-propose-merge)!
Thanks
Loďc Minier
On Tue, Oct 19, 2010, Shawn Guo wrote:
I like the merge request way, but I'm behind a firewall. I was told that it's tough to get bzr push through firewall. Any suggestion to break the firewall through?
You don't have outbound SSH access? That's problematic indeed; is this something you could get fixed?
Another way to send bzr changes is via a bzr bundle, which you can attach to an email, but it's a bit more cumbersome IMHO
Hi,
Le 19/10/2010 03:47, john stultz a écrit :
On Mon, 2010-10-18 at 18:58 +0800, Shawn Guo wrote:
Here you go. I'm using Linaro tree below.
git://git.linaro.org/kernel/linux-linaro-2.6.35.git
I've tried using this tree, (as well as the pengutronix.de tree and linus' upstream) with an older 9.04 disk image, but none of the booting kernels could find the sd card (no mmcblk devices located in the boot log)
So sort of to echo what Nicolas said, it seems pretty difficult to follow which set of patches (as well as what .config settings) are needed to get upstream booting.
on babbage you should need on top of Linaro's tree : Shawn's patch http://lists.linaro.org/pipermail/linaro-dev/2010-October/001307.html and this fix : http://lists.linaro.org/pipermail/linaro-dev/2010-October/001316.html
To remove the anoying sdhci probe log, add : http://git.kernel.org/?p=linux/kernel/git/cjb/mmc.git%3Ba=commit%3Bh=0ca6d53...
Eric