After Nicolas merged Wolfram Sang's imx51 mmc driver, the patches are to add missing bits for getting a bootable Linaro mx51evk kernel.
It's not clear to me if the missing kernel configurations should be addressed in Linaro kernel tree or packaging. I patched mx51_defconfig anyway to show what are missing.
Shawn Guo (3): babbage: esdhc device registration mmc: quirk fix for timeout problem babbage: update mx51_defconfig
arch/arm/configs/mx51_defconfig | 12 +- arch/arm/mach-mx5/Kconfig | 1 + arch/arm/mach-mx5/board-mx51_babbage.c | 20 ++ arch/arm/mach-mx5/clock-mx51.c | 286 +++++++++++++++-------- 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 +- drivers/mmc/host/sdhci-esdhc-imx.c | 3 +- 13 files changed, 371 insertions(+), 124 deletions(-)
This patch are based on Eric Bénard's patches below, and only picks up i.mx51 babbage specific bits.
- cpuimx51: update board support - clock-mx51: factorize clk_set_parent and clk_get_rate - imx-esdhc: update devices registration
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 | 286 +++++++++++++++-------- 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, 360 insertions(+), 120 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 6af69de..769ca05 100644 --- a/arch/arm/mach-mx5/clock-mx51.c +++ b/arch/arm/mach-mx5/clock-mx51.c @@ -41,35 +41,67 @@ static struct clk usboh3_clk;
#define MAX_DPLL_WAIT_TRIES 1000 /* 1000 * udelay(1) = 1ms */
-static int _clk_ccgr_enable(struct clk *clk) -{ - u32 reg; - - reg = __raw_readl(clk->enable_reg); - reg |= MXC_CCM_CCGRx_MOD_ON << clk->enable_shift; - __raw_writel(reg, clk->enable_reg); - - return 0; +/* 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_disable(struct clk *clk) -{ - u32 reg; - reg = __raw_readl(clk->enable_reg); - reg &= ~(MXC_CCM_CCGRx_MOD_OFF << clk->enable_shift); - __raw_writel(reg, clk->enable_reg); +static void _clk_ccgr_setclk(struct clk *clk, unsigned mode) + { + u32 reg = __raw_readl(clk->enable_reg);
+ reg &= ~(MXC_CCM_CCGRx_CG_MASK << clk->enable_shift); + reg |= mode << clk->enable_shift; + + __raw_writel(reg, clk->enable_reg); } - -static void _clk_ccgr_disable_inwait(struct clk *clk) + +static int _clk_ccgr_enable(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_ON); + return 0; + } + + static void _clk_ccgr_disable(struct clk *clk) + { + _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) + { + _clk_ccgr_setclk(clk, MXC_CCM_CCGRx_MOD_IDLE); + }
/* * For the 4-to-1 muxed input clock @@ -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
On Tue, 2010-10-19 at 14:47 +0800, Shawn Guo wrote:
This patch are based on Eric Bénard's patches below, and only picks up i.mx51 babbage specific bits.
- cpuimx51: update board support
- clock-mx51: factorize clk_set_parent and clk_get_rate
- imx-esdhc: update devices registration
Hey Shawn! First of all, thanks so much for your recent work here! Today, with your patches, I finally got my imx51 board booting with the latest linaro image! This has been a long time stumbling block for me, so I'm really glad its finally coming together!
Stuff that still needs to be addressed: --------------------------------------- * mmcinfo needs to be called to avoid mmc hangs. (bug 655461)
* uboot in the hardware pack doesn't seem to utilize the boot.scr by default (likely due to the issue above).
* Latest hardware pack from today doesn't seem to have the kernel changes from git://git.linaro.org/kernel/linux-linaro-2.6.35.git, to enable the sd/mmc device, so I had to build my own kernel.
* /bin/auto-serial-console: tty[A-Z]* --> tty[a-zA-Z]*
* fec ethaddr issue (bug 652426). Can you attach the patch you listed in the bug? I wanted to test it, but trying to pulling it from the comment ends up with too much whitespace damage.
And just a heads up: I while rebasing the imx patches in the linaro tree against Linus' upstream kernel, I noticed this patch has some pretty bad whitespace damage, which will need to be fixed up before pushing to mainline. For example, notice the extra space before the braces in the following:
+static int _clk_ccgr_enable(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_ON);
- return 0;
- }
- static void _clk_ccgr_disable(struct clk *clk)
- {
- _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)
- {
- _clk_ccgr_setclk(clk, MXC_CCM_CCGRx_MOD_IDLE);
- }
thanks again for the great work! -john
Signed-off-by: Shawn Guo shawn.gsc@gmail.com --- drivers/mmc/host/sdhci-esdhc-imx.c | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-)
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,
This patch is to update mx51_defconfig to get a bootable Linaro kernel.
- Support rootfs on mmc
CONFIG_MMC_BLOCK=y CONFIG_MMC_SDHCI=y CONFIG_MMC_SDHCI_PLTFM=y CONFIG_MMC_SDHCI_ESDHC_IMX=y
- Fix https://bugs.launchpad.net/linux-linaro/+bug/659799
CONFIG_TMPFS=y CONFIG_DEVTMPFS=y CONFIG_DEVTMPFS_MOUNT=y
- Fix https://bugs.launchpad.net/linux-linaro/+bug/651195
CONFIG_BLK_DEV_INITRD=y
- Workaround https://bugs.launchpad.net/linux-linaro/+bug/655641
# CONFIG_FIXED_PHY is not set
Signed-off-by: Shawn Guo shawn.gsc@gmail.com --- arch/arm/configs/mx51_defconfig | 12 +++++++++--- 1 files changed, 9 insertions(+), 3 deletions(-)
diff --git a/arch/arm/configs/mx51_defconfig b/arch/arm/configs/mx51_defconfig index a665ecb..9111dc2 100644 --- a/arch/arm/configs/mx51_defconfig +++ b/arch/arm/configs/mx51_defconfig @@ -3,6 +3,7 @@ CONFIG_EXPERIMENTAL=y CONFIG_SYSVIPC=y CONFIG_LOG_BUF_SHIFT=18 CONFIG_RELAY=y +CONFIG_BLK_DEV_INITRD=y CONFIG_EMBEDDED=y # CONFIG_SLUB_DEBUG is not set # CONFIG_COMPAT_BRK is not set @@ -40,6 +41,8 @@ CONFIG_IP_PNP_DHCP=y # CONFIG_INET_LRO is not set # CONFIG_IPV6 is not set # CONFIG_WIRELESS is not set +CONFIG_DEVTMPFS=y +CONFIG_DEVTMPFS_MOUNT=y # CONFIG_STANDALONE is not set CONFIG_CONNECTOR=y CONFIG_BLK_DEV_LOOP=y @@ -69,7 +72,7 @@ CONFIG_REALTEK_PHY=y CONFIG_NATIONAL_PHY=y CONFIG_STE10XP=y CONFIG_LSI_ET1011C_PHY=y -CONFIG_FIXED_PHY=y +# CONFIG_FIXED_PHY is not set CONFIG_MDIO_BITBANG=y CONFIG_MDIO_GPIO=y CONFIG_NET_ETHERNET=y @@ -106,8 +109,10 @@ CONFIG_USB=y CONFIG_USB_EHCI_HCD=y CONFIG_USB_EHCI_MXC=y CONFIG_MMC=y -CONFIG_MMC_BLOCK=m -CONFIG_MMC_SDHCI=m +CONFIG_MMC_BLOCK=y +CONFIG_MMC_SDHCI=y +CONFIG_MMC_SDHCI_PLTFM=y +CONFIG_MMC_SDHCI_ESDHC_IMX=y CONFIG_NEW_LEDS=y CONFIG_LEDS_CLASS=m CONFIG_RTC_CLASS=y @@ -136,6 +141,7 @@ CONFIG_ZISOFS=y CONFIG_UDF_FS=m CONFIG_MSDOS_FS=m CONFIG_VFAT_FS=y +CONFIG_TMPFS=y CONFIG_CONFIGFS_FS=m CONFIG_NFS_FS=y CONFIG_NFS_V3=y
Shawn,
Thanks for the patches. Could you please send patch 1 & 2 to LAKML too for review?
/Amit
On 10 Oct 19, Shawn Guo wrote:
After Nicolas merged Wolfram Sang's imx51 mmc driver, the patches are to add missing bits for getting a bootable Linaro mx51evk kernel.
It's not clear to me if the missing kernel configurations should be addressed in Linaro kernel tree or packaging. I patched mx51_defconfig anyway to show what are missing.
Shawn Guo (3): babbage: esdhc device registration mmc: quirk fix for timeout problem babbage: update mx51_defconfig
arch/arm/configs/mx51_defconfig | 12 +- arch/arm/mach-mx5/Kconfig | 1 + arch/arm/mach-mx5/board-mx51_babbage.c | 20 ++ arch/arm/mach-mx5/clock-mx51.c | 286 +++++++++++++++-------- 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 +- drivers/mmc/host/sdhci-esdhc-imx.c | 3 +- 13 files changed, 371 insertions(+), 124 deletions(-)
linaro-dev mailing list linaro-dev@lists.linaro.org http://lists.linaro.org/mailman/listinfo/linaro-dev
Hi Eric,
If I understand correctly, you meant the tree below.
git://git.pengutronix.de/git/imx/linux-2.6.git
Can you please tell which branch has both your bits and Wolfram's? I can find your bits on branch imx-for-2.6.37, but Wolfram's are not there.
On Tue, Oct 19, 2010 at 8:39 PM, Eric Bénard eric@eukrea.com wrote:
Hi,
Le 19/10/2010 09:20, Amit Kucheria a écrit :
Thanks for the patches. Could you please send patch 1& 2 to LAKML too for review?
you will have to rebase on Sascha's tree as your first patch includes things which are already there.
Eric
Hi Shawn,
Le 19/10/2010 18:28, Shawn Guo a écrit :
If I understand correctly, you meant the tree below.
git://git.pengutronix.de/git/imx/linux-2.6.git
Can you please tell which branch has both your bits and Wolfram's? I can find your bits on branch imx-for-2.6.37, but Wolfram's are not there.
you're right, you have to fetch them from the mmc-next branch of git://git.kernel.org/pub/scm/linux/kernel/git/cjb/mmc.git
Eric