Add support for Amlogic Meson MMC controller
Subsystems (3)
cover Add support for Amlogic Meson MMC controller
From: Carlo Caione <[email protected]>
This patchset is a port / rewrite of the Amlogic driver shipped in the SDK for the Meson GXBB (S905) platform. It has been tested on the Hardkernel Odroid-C2 board.
The driver is enabled using U_BOOT_DEVICE in the board file because there is no MMC driver yet in the linux kernel.
This patchset depends on the basic support for Amlogic S905 SoCs written by Beniamino[1]
[1] https://www.mail-archive.com/u-boot at lists.denx.de/msg212188.html
Carlo Caione (2):
mmc: Add Amlogic Meson driver
arm: amlogic: Enable MMC driver on Odroid-C2
arch/arm/include/asm/arch-meson/sd_emmc.h | 109 +++++++++++ board/hardkernel/odroid-c2/odroid-c2.c | 42 ++++ configs/odroid-c2_defconfig | 5 + drivers/mmc/Makefile | 1 + drivers/mmc/meson_mmc.c | 305 ++++++++++++++++++++++++++++++ include/configs/odroid-c2.h | 7 + 6 files changed, 469 insertions(+) create mode 100644 arch/arm/include/asm/arch-meson/sd_emmc.h create mode 100644 drivers/mmc/meson_mmc.c
Signature · 1 line
2.7.4
PATCH 1/2 mmc: Add Amlogic Meson driver
From: Carlo Caione <[email protected]>
This is a port / rewrite of the Amlogic driver shipped whithin the Amlogic SDK for the Meson GXBaby (S905) SoC.
--- arch/arm/include/asm/arch-meson/sd_emmc.h | 109 +++++++++++ drivers/mmc/Makefile | 1 + drivers/mmc/meson_mmc.c | 305 ++++++++++++++++++++++++++++++ 3 files changed, 415 insertions(+) create mode 100644 arch/arm/include/asm/arch-meson/sd_emmc.h create mode 100644 drivers/mmc/meson_mmc.c
arch/arm/include/asm/arch-meson/sd_emmc.h new file +109 -0
@@ -0,0 +1,109 @@ +/* +* (C) Copyright 2016 Carlo Caione <[email protected]> +* +* SPDX-License-Identifier: GPL-2.0+ +*/ + +#ifndef __SD_EMMC_H__ +#define __SD_EMMC_H__ + +#include <mmc.h> + +#define SDIO_PORT_A 0 +#define SDIO_PORT_B 1 +#define SDIO_PORT_C 2 + +#define SD_EMMC_BASE_A 0xd0070000 +#define SD_EMMC_BASE_B 0xd0072000 +#define SD_EMMC_BASE_C 0xd0074000 + +#define SD_IRQ_ALL 0x3fff + +#define SD_EMMC_CLKSRC_24M 24000000 +#define SD_EMMC_CLKSRC_DIV2 1000000000 + +#define CLK_DIV 0 +#define CLK_SRC 6 +#define CLK_CO_PHASE 8 +#define CLK_ALWAYS_ON 24 + +#define ADDR_USE_PING_BUF BIT(1) + +#define SD_EMMC_RXD_ERROR BIT(0) +#define SD_EMMC_TXD_ERROR BIT(1) +#define SD_EMMC_DESC_ERROR BIT(2) +#define SD_EMMC_RESP_CRC_ERROR BIT(3) +#define SD_EMMC_RESP_TIMEOUT_ERROR BIT(4) +#define SD_EMMC_DESC_TIMEOUT_ERROR BIT(5) + +#define CFG_BUS_WIDTH 0 +#define CFG_BUS_WIDTH_MASK (0x3 << 0) +#define CFG_BL_LEN 4 +#define CFG_BL_LEN_MASK (0xf << 4) +#define CFG_RESP_TIMEOUT 8 +#define CFG_RESP_TIMEOUT_MASK (0xf << 8) +#define CFG_RC_CC 12 +#define CFG_RC_CC_MASK (0xf << 12) + +#define STATUS_RXD_ERR_MASK 0xff +#define STATUS_TXD_ERR BIT(8) +#define STATUS_DESC_ERR BIT(9) +#define STATUS_RESP_ERR BIT(10) +#define STATUS_RESP_TIMEOUT BIT(11) +#define STATUS_DESC_TIMEOUT BIT(12) +#define STATUS_END_OF_CHAIN BIT(13) + +#define CMD_CFG_LENGTH_MASK 0x1ff +#define CMD_CFG_CMD_INDEX 24 +#define CMD_CFG_BLOCK_MODE BIT(9) +#define CMD_CFG_R1B BIT(10) +#define CMD_CFG_END_OF_CHAIN BIT(11) +#define CMD_CFG_NO_RESP BIT(16) +#define CMD_CFG_DATA_IO BIT(18) +#define CMD_CFG_DATA_WR BIT(19) +#define CMD_CFG_RESP_NOCRC BIT(20) +#define CMD_CFG_RESP_128 BIT(21) +#define CMD_CFG_OWNER BIT(31) + +struct meson_mmc_regs { +uint32_t gclock; +uint32_t gdelay; +uint32_t gadjust; +uint32_t reserved_0c; +uint32_t gcalout; +uint32_t reserved_14[11 ]; +uint32_t gstart; +uint32_t gcfg; +uint32_t gstatus; +uint32_t girq_en; +uint32_t gcmd_cfg; +uint32_t gcmd_arg; +uint32_t gcmd_dat; +uint32_t gcmd_rsp0; +uint32_t gcmd_rsp1; +uint32_t gcmd_rsp2; +uint32_t gcmd_rsp3; +uint32_t reserved_6c; +uint32_t gcurr_cfg; +uint32_t gcurr_arg; +uint32_t gcurr_dat; +uint32_t gcurr_rsp; +uint32_t gnext_cfg; +uint32_t gnext_arg; +uint32_t gnext_dat; +uint32_t gnext_rsp; +uint32_t grxd; +uint32_t gtxd; +uint32_t reserved_98[90 ]; +uint32_t gdesc[128 ]; +uint32_t gping[128 ]; +uint32_t gpong[128 ]; +}; + +struct meson_mmc_platdata { +struct mmc_config cfg; +struct meson_mmc_regs *sd_emmc_reg; +char *w_buf; +}; + +#endif
drivers/mmc/Makefile +1 -0
@@ -21,6 +21,7 @@ obj-$(CONFIG_FTSDC021) += ftsdc021_sdhci.o obj-$(CONFIG_GENERIC_MMC) += mmc.o obj-$(CONFIG_GENERIC_ATMEL_MCI) += gen_atmel_mci.o obj-$(CONFIG_KONA_SDHCI) += kona_sdhci.o +obj-$(CONFIG_MMC_MESON) += meson_mmc.o obj-$(CONFIG_MMC_SPI) += mmc_spi.o obj-$(CONFIG_MMC_SUNXI) += sunxi_mmc.o obj-$(CONFIG_MV_SDHCI) += mv_sdhci.o
drivers/mmc/meson_mmc.c new file +305 -0
305 lines not on this page · raw message
Signature · 1 line
2.7.4
Kevin Hilman
maintainerPATCH 1/2 mmc: Add Amlogic Meson driver
Quoted 6 lines · Carlo Caione
From: Carlo Caione <[email protected]>
This is a port / rewrite of the Amlogic driver shipped whithin the Amlogic SDK for the Meson GXBaby (S905) SoC.
Signed-off-by Carlo Caione <[email protected]>
[...]
drivers/mmc/meson_mmc.c line 295
Quoted 3 lines
drivers/mmc/meson_mmc.c new file +3
-0+static const struct udevice_id meson_mmc_match[] = { + { .compatible ="amlogic,meson-mmc" }, + {/* sentinel */ }
IIUC, this controller is different between meson8* and gxbb. If that's the case, this compatible should probably be more specific.
Kevin
PATCH 1/2 mmc: Add Amlogic Meson driver
Quoted 9 lines · Kevin Hilman
Quoted 6 lines · Carlo Caione
From: Carlo Caione <[email protected]>
This is a port / rewrite of the Amlogic driver shipped whithin the Amlogic SDK for the Meson GXBaby (S905) SoC.
Signed-off-by Carlo Caione <[email protected]>
Quoted 8 lines
[...]
drivers/mmc/meson_mmc.c line 295
Quoted 3 lines
drivers/mmc/meson_mmc.c new file +3
-0+static const struct udevice_id meson_mmc_match[] = { + { .compatible ="amlogic,meson-mmc" }, + {/* sentinel */ }IIUC, this controller is different between meson8* and gxbb. If that's the case, this compatible should probably be more specific.
Yes, this is a point I raised also on lkml when I submitted the MMC driver for the Meson8b.
Since the registers mapping is different I assume that this is the case. Just to be sure, given that you are the only one with a datasheet for the GXBB, can you confirm that?
Actually for the same reason I was in doubt if CONFIG_MMC_MESON was a right naming choice here, but since it is really unlikely that we will ever see a U-Boot port for the Meson8b I stuck with that.
Cheers,
Signature · 1 line
Carlo Caione
Kevin Hilman
maintainerPATCH 1/2 mmc: Add Amlogic Meson driver
Quoted 16 lines · Carlo Caione
Quoted 15 lines · Kevin Hilman
Quoted 6 lines · Carlo Caione
From: Carlo Caione <[email protected]>
This is a port / rewrite of the Amlogic driver shipped whithin the Amlogic SDK for the Meson GXBaby (S905) SoC.
Signed-off-by Carlo Caione <[email protected]>[...]
Quoted 3 lines
drivers/mmc/meson_mmc.c new file +3
-0+static const struct udevice_id meson_mmc_match[] = { + { .compatible ="amlogic,meson-mmc" }, + {/* sentinel */ }
Quoted 8 lines
Quoted 2 lines
IIUC, this controller is different between meson8* and gxbb. If that's the case, this compatible should probably be more specific.
Yes, this is a point I raised also on lkml when I submitted the MMC driver for the Meson8b.
Since the registers mapping is different I assume that this is the case. Just to be sure, given that you are the only one with a datasheet for the GXBB, can you confirm that?
I took a quick look and just compared the register layouts between s805 and s905 and indeed they are quite different.
Kevin
PATCH 1/2 mmc: Add Amlogic Meson driver
In reply to Carlo CaioneAm 13.05.2016 um 15:53 schrieb Carlo Caione:
Quoted 2 lines
[...] but since it is really unlikely that we will ever see a U-Boot port for the Meson8b I stuck with that.
Why do you consider that so unlikely? Please don't make such assumptions for design decisions.
Regards,
Andreas
Signature · 3 lines
SUSE Linux GmbH, Maxfeldstr. 5, 90409 N?rnberg, Germany GF: Felix Imend?rffer, Jane Smithard, Graham Norton HRB 21284 (AG N?rnberg)
PATCH 1/2 mmc: Add Amlogic Meson driver
In reply to Carlo CaioneHi Carlo
Quoted 4 lines · Carlo Caione
From: Carlo Caione <[email protected]>
This is a port / rewrite of the Amlogic driver shipped whithin the Amlogic SDK for the Meson GXBaby (S905) SoC.
s/whithin/within
And If you want to apply this patch, could you resend the patch on lates u-boot?
Quoted 29 lines
Signed-off-by Carlo Caione <[email protected]>--- arch/arm/include/asm/arch-meson/sd_emmc.h | 109 +++++++++++ drivers/mmc/Makefile | 1 + drivers/mmc/meson_mmc.c | 305 ++++++++++++++++++++++++++++++ 3 files changed, 415 insertions(+) create mode 100644 arch/arm/include/asm/arch-meson/sd_emmc.h create mode 100644 drivers/mmc/meson_mmc.carch/arm/include/asm/arch-meson/sd_emmc.h new file +13
-0@@ -0,0 +1,109 @@ +/* +* (C) Copyright 2016 Carlo Caione <[email protected]> +* +* SPDX-License-Identifier: GPL-2.0+ +*/ + +#ifndef __SD_EMMC_H__ +#define __SD_EMMC_H__ + +#include <mmc.h> + +#define SDIO_PORT_A 0 +#define SDIO_PORT_B 1
arch/arm/include/asm/arch-meson/sd_emmc.h line 23
Quoted 10 lines
arch/arm/include/asm/arch-meson/sd_emmc.h new file +10
-0+#define SDIO_PORT_C 2 + +#define SD_EMMC_BASE_A 0xd0070000 +#define SD_EMMC_BASE_B 0xd0072000 +#define SD_EMMC_BASE_C 0xd0074000 + +#define SD_IRQ_ALL 0x3fff + +#define SD_EMMC_CLKSRC_24M 24000000 +#define SD_EMMC_CLKSRC_DIV2 1000000000
Is it right? 1GHz?
arch/arm/include/asm/arch-meson/sd_emmc.h line 28
Quoted 5 lines
arch/arm/include/asm/arch-meson/sd_emmc.h new file +5
-0+ +#define CLK_DIV 0 +#define CLK_SRC 6 +#define CLK_CO_PHASE 8 +#define CLK_ALWAYS_ON 24
Are these for shifting?
Quoted 28 lines
arch/arm/include/asm/arch-meson/sd_emmc.h new file +28
-0+ +#define ADDR_USE_PING_BUF BIT(1) + +#define SD_EMMC_RXD_ERROR BIT(0) +#define SD_EMMC_TXD_ERROR BIT(1) +#define SD_EMMC_DESC_ERROR BIT(2) +#define SD_EMMC_RESP_CRC_ERROR BIT(3) +#define SD_EMMC_RESP_TIMEOUT_ERROR BIT(4) +#define SD_EMMC_DESC_TIMEOUT_ERROR BIT(5) + +#define CFG_BUS_WIDTH 0 +#define CFG_BUS_WIDTH_MASK (0x3 << 0) +#define CFG_BL_LEN 4 +#define CFG_BL_LEN_MASK (0xf << 4) +#define CFG_RESP_TIMEOUT 8 +#define CFG_RESP_TIMEOUT_MASK (0xf << 8) +#define CFG_RC_CC 12 +#define CFG_RC_CC_MASK (0xf << 12) + +#define STATUS_RXD_ERR_MASK 0xff +#define STATUS_TXD_ERR BIT(8) +#define STATUS_DESC_ERR BIT(9) +#define STATUS_RESP_ERR BIT(10) +#define STATUS_RESP_TIMEOUT BIT(11) +#define STATUS_DESC_TIMEOUT BIT(12) +#define STATUS_END_OF_CHAIN BIT(13) + +#define CMD_CFG_LENGTH_MASK 0x1ff
arch/arm/include/asm/arch-meson/sd_emmc.h line 66
Quoted 10 lines
arch/arm/include/asm/arch-meson/sd_emmc.h new file +10
-0+#define CMD_CFG_CMD_INDEX 24 +#define CMD_CFG_BLOCK_MODE BIT(9) +#define CMD_CFG_R1B BIT(10) +#define CMD_CFG_END_OF_CHAIN BIT(11) +#define CMD_CFG_NO_RESP BIT(16) +#define CMD_CFG_DATA_IO BIT(18) +#define CMD_CFG_DATA_WR BIT(19) +#define CMD_CFG_RESP_NOCRC BIT(20) +#define CMD_CFG_RESP_128 BIT(21) +#define CMD_CFG_OWNER BIT(31)
Add the description for which register.
e,g
/* GCLOCK register */
#define ...
Quoted 25 lines
arch/arm/include/asm/arch-meson/sd_emmc.h new file +25
-0+ +struct meson_mmc_regs { +uint32_t gclock; +uint32_t gdelay; +uint32_t gadjust; +uint32_t reserved_0c; +uint32_t gcalout; +uint32_t reserved_14[11 ]; +uint32_t gstart; +uint32_t gcfg; +uint32_t gstatus; +uint32_t girq_en; +uint32_t gcmd_cfg; +uint32_t gcmd_arg; +uint32_t gcmd_dat; +uint32_t gcmd_rsp0; +uint32_t gcmd_rsp1; +uint32_t gcmd_rsp2; +uint32_t gcmd_rsp3; +uint32_t reserved_6c; +uint32_t gcurr_cfg; +uint32_t gcurr_arg; +uint32_t gcurr_dat; +uint32_t gcurr_rsp; +uint32_t gnext_cfg;
arch/arm/include/asm/arch-meson/sd_emmc.h line 101
Quoted 10 lines
arch/arm/include/asm/arch-meson/sd_emmc.h new file +10
-0+uint32_t gnext_arg; +uint32_t gnext_dat; +uint32_t gnext_rsp; +uint32_t grxd; +uint32_t gtxd; +uint32_t reserved_98[90 ]; +uint32_t gdesc[128 ]; +uint32_t gping[128 ]; +uint32_t gpong[128 ]; +};
Don't use this style..Use the define.
It's difficult to debug..devloper don't know which offset is used before calculating. And add the descriptions..
Quoted 49 lines
arch/arm/include/asm/arch-meson/sd_emmc.h new file +8
-0+ +struct meson_mmc_platdata { +struct mmc_config cfg; +struct meson_mmc_regs *sd_emmc_reg; +char *w_buf; +}; + +#endif drivers/mmc/Makefile +1
-0@@ -21,6 +21,7 @@ obj-$(CONFIG_FTSDC021) += ftsdc021_sdhci.o obj-$(CONFIG_GENERIC_MMC) += mmc.o obj-$(CONFIG_GENERIC_ATMEL_MCI) += gen_atmel_mci.o obj-$(CONFIG_KONA_SDHCI) += kona_sdhci.o +obj-$(CONFIG_MMC_MESON) += meson_mmc.o obj-$(CONFIG_MMC_SPI) += mmc_spi.o obj-$(CONFIG_MMC_SUNXI) += sunxi_mmc.o obj-$(CONFIG_MV_SDHCI) += mv_sdhci.odrivers/mmc/meson_mmc.c new file +23
-0@@ -0,0 +1,305 @@ +/* +* (C) Copyright 2016 Carlo Caione <[email protected]> +* +* SPDX-License-Identifier: GPL-2.0+ +*/ + +#include <common.h> +#include <fdtdec.h> +#include <malloc.h> +#include <mmc.h> +#include <asm/io.h> +#include <asm/arch/sd_emmc.h> +#include <dm/device.h> + +static void meson_mmc_config_clock (struct mmc *mmc, +struct meson_mmc_regs *meson_mmc_reg) +{ +uint32_t meson_mmc_clk =0 ; +unsigned int clk, clk_src, clk_div; + +if (mmc->clock >12000000 ) { + clk =SD_EMMC_CLKSRC_DIV2 ; + clk_src =1 ;
drivers/mmc/meson_mmc.c line 33
Quoted 10 lines
drivers/mmc/meson_mmc.c new file +10
-0+ }else { + clk =SD_EMMC_CLKSRC_24M ; + clk_src =0 ; + } + clk_div = clk / mmc->clock; + +if (mmc->clock < mmc->cfg->f_min) + mmc->clock = mmc->cfg->f_min; +if (mmc->clock > mmc->cfg->f_max) + mmc->clock = mmc->cfg->f_max;
In mmc_set_clock(), mmc->clock is already assigned.. Doesn't need this.
drivers/mmc/meson_mmc.c line 39
Quoted 6 lines
drivers/mmc/meson_mmc.c new file +6
-0+ +/* Keep the clock always on */ + meson_mmc_clk |= (1 <<CLK_ALWAYS_ON ); + +/* 180 phase */ + meson_mmc_clk |= (2 <<CLK_CO_PHASE );
Don't use the magic number, what do 1 and 2 mean?
drivers/mmc/meson_mmc.c line 43
Quoted 4 lines
drivers/mmc/meson_mmc.c new file +4
-0+ +/* clock settings */ + meson_mmc_clk |= (clk_src <<CLK_SRC ); + meson_mmc_clk |= (clk_div <<CLK_DIV );
How many bits do use for clk_div? bit[0:11]?
Quoted 28 lines
drivers/mmc/meson_mmc.c new file +28
-0+ +writel (meson_mmc_clk, &meson_mmc_reg->gclock); +} + +static void meson_mmc_set_ios (struct mmc *mmc) +{ +struct meson_mmc_platdata *pdata; +struct meson_mmc_regs *meson_mmc_reg; +unsigned int bus_width; +uint32_t meson_mmc_cfg =0 ; + + pdata = mmc->priv; + meson_mmc_reg = pdata->sd_emmc_reg; + +meson_mmc_config_clock (mmc, meson_mmc_reg); + + meson_mmc_cfg =readl (&meson_mmc_reg->gcfg); + +if (mmc->bus_width ==1 ) + bus_width =0 ; +else + bus_width = mmc->bus_width /4 ; + +/* 1-bit mode */ + meson_mmc_cfg &= ~CFG_BUS_WIDTH_MASK ; + meson_mmc_cfg |= (bus_width <<CFG_BUS_WIDTH ); + +/* 512 bytes block lenght */
drivers/mmc/meson_mmc.c line 81
Quoted 10 lines
drivers/mmc/meson_mmc.c new file +10
-0+ meson_mmc_cfg &= ~CFG_BL_LEN_MASK ; + meson_mmc_cfg |= (9 <<CFG_BL_LEN ); + +/* Response timeout 256 clk */ + meson_mmc_cfg &= ~CFG_RESP_TIMEOUT_MASK ; + meson_mmc_cfg |= (7 <<CFG_RESP_TIMEOUT ); + +/* Command-command gap 1024 clk */ + meson_mmc_cfg &= ~CFG_RC_CC_MASK ; + meson_mmc_cfg |= (4 <<CFG_RC_CC );
Ditto...what are 9, 7, 4?
Don't use the magic number in entire your codes.
drivers/mmc/meson_mmc.c line 85
Quoted 4 lines
drivers/mmc/meson_mmc.c new file +4
-0+ +writel (meson_mmc_cfg, &meson_mmc_reg->gcfg); + +return ;
not needs "return"
Quoted 13 lines
drivers/mmc/meson_mmc.c new file +13
-0+} + +static int meson_mmc_init (struct mmc *mmc) +{ +mmc_set_clock (mmc,400000 ); + +return 0 ; +} + +static void meson_mmc_setup_cmd (struct mmc *mmc,struct mmc_data *data, +struct mmc_cmd *cmd, +struct meson_mmc_regs *meson_mmc_reg) +{
drivers/mmc/meson_mmc.c line 108
Quoted 10 lines
drivers/mmc/meson_mmc.c new file +10
-0+uint32_t meson_mmc_cmd =0 ; + + meson_mmc_cmd = ((0x80 | cmd->cmdidx) <<CMD_CFG_CMD_INDEX ); + +if (cmd->resp_type &MMC_RSP_PRESENT ) { +if (cmd->resp_type &MMC_RSP_136 ) + meson_mmc_cmd |=CMD_CFG_RESP_128 ; + +if (cmd->resp_type &MMC_RSP_BUSY ) + meson_mmc_cmd |=CMD_CFG_R1B ;
There is no case with MMC_RSP_136 and MMC_RSP_BUSY together.
Quoted 43 lines
drivers/mmc/meson_mmc.c new file +43
-0+ +if (!(cmd->resp_type &MMC_RSP_CRC )) + meson_mmc_cmd |=CMD_CFG_RESP_NOCRC ; + }else { + meson_mmc_cmd |=CMD_CFG_NO_RESP ; + } + +if (data) { + meson_mmc_cmd |=CMD_CFG_DATA_IO ; + +if (data->flags ==MMC_DATA_WRITE ) + meson_mmc_cmd |=CMD_CFG_DATA_WR ; + +if (data->blocks >1 ) { + meson_mmc_cmd |=CMD_CFG_BLOCK_MODE ; + meson_mmc_cmd |= data->blocks; + }else { + meson_mmc_cmd |= (data->blocksize &CMD_CFG_LENGTH_MASK ); + } + } + + meson_mmc_cmd |=CMD_CFG_OWNER ; + meson_mmc_cmd |=CMD_CFG_END_OF_CHAIN ; + +writel (meson_mmc_cmd, &meson_mmc_reg->gcmd_cfg); + +return ; +} + +static void meson_mmc_setup_addr (struct mmc *mmc,struct mmc_data *data, +struct meson_mmc_regs *meson_mmc_reg) +{ +struct meson_mmc_platdata *pdata; +unsigned int data_size =0 ; +uint32_t meson_mmc_data_addr =0 ; + + pdata = mmc->priv; + +if (data) { + data_size = data->blocks * data->blocksize; + +if (data->flags ==MMC_DATA_READ ) { +if (data_size <0x200 ) {
drivers/mmc/meson_mmc.c line 161
Quoted 10 lines
drivers/mmc/meson_mmc.c new file +10
-0+ meson_mmc_data_addr = (ulong ) meson_mmc_reg->gping; + meson_mmc_data_addr |=ADDR_USE_PING_BUF ; + }else { +invalidate_dcache_range ((ulong ) data->dest, + (ulong) (data->dest + data_size)); + meson_mmc_data_addr = (ulong ) data->dest; + } + } + +if (data->flags ==MMC_DATA_WRITE ) {
data->flags is only two..MMC_DATA_WRITE ..otherwise MMC_DATA_READ.
Quoted 47 lines
drivers/mmc/meson_mmc.c new file +47
-0+ pdata->w_buf =calloc (data_size,sizeof (char )); +memcpy (pdata->w_buf, data->src, data_size); +flush_dcache_range ((ulong ) pdata->w_buf, + (ulong) (pdata->w_buf + data_size)); + meson_mmc_data_addr = (ulong ) pdata->w_buf; + } + } + +writel (meson_mmc_data_addr, &meson_mmc_reg->gcmd_dat); + +return ; +} + +static void meson_mmc_read_response (struct mmc *mmc,struct mmc_data *data, +struct mmc_cmd *cmd, +struct meson_mmc_regs *meson_mmc_reg) +{ +unsigned int data_size =0 ; + +if (data) { + data_size = data->blocks * data->blocksize; +if ((data_size <0x200 ) && (data->flags ==MMC_DATA_READ )) +memcpy (data->dest, (const void *)meson_mmc_reg->gping, data_size); + } + +if (cmd->resp_type &MMC_RSP_136 ) { + cmd->response[0 ] =readl (&meson_mmc_reg->gcmd_rsp3); + cmd->response[1 ] =readl (&meson_mmc_reg->gcmd_rsp2); + cmd->response[2 ] =readl (&meson_mmc_reg->gcmd_rsp1); + cmd->response[3 ] =readl (&meson_mmc_reg->gcmd_rsp0); + }else { + cmd->response[0 ] =readl (&meson_mmc_reg->gcmd_rsp0); + } +} + +static int meson_mmc_send_cmd (struct mmc *mmc,struct mmc_cmd *cmd, +struct mmc_data *data) +{ +struct meson_mmc_platdata *pdata; +struct meson_mmc_regs *meson_mmc_reg; +uint32_t meson_mmc_irq =0 ; +int ret =0 ; + + pdata = mmc->priv; + meson_mmc_reg = pdata->sd_emmc_reg; + +meson_mmc_setup_cmd (mmc, data, cmd, meson_mmc_reg);
drivers/mmc/meson_mmc.c line 218
Quoted 10 lines
drivers/mmc/meson_mmc.c new file +10
-0+meson_mmc_setup_addr (mmc, data, meson_mmc_reg); + +writel (SD_IRQ_ALL , &meson_mmc_reg->gstatus); +writel (cmd->cmdarg, &meson_mmc_reg->gcmd_arg); + +while (1 ) { + meson_mmc_irq =readl (&meson_mmc_reg->gstatus); +if (meson_mmc_irq &STATUS_END_OF_CHAIN ) +break ; + }
I don't like this style...potential infinte loop.
drivers/mmc/meson_mmc.c line 231
Quoted 13 lines
drivers/mmc/meson_mmc.c new file +13
-0+ +if (meson_mmc_irq &STATUS_RXD_ERR_MASK ) + ret |=SD_EMMC_RXD_ERROR ; +if (meson_mmc_irq &STATUS_TXD_ERR ) + ret |=SD_EMMC_TXD_ERROR ; +if (meson_mmc_irq &STATUS_DESC_ERR ) + ret |=SD_EMMC_DESC_ERROR ; +if (meson_mmc_irq &STATUS_RESP_ERR ) + ret |=SD_EMMC_RESP_CRC_ERROR ; +if (meson_mmc_irq &STATUS_RESP_TIMEOUT ) + ret |=SD_EMMC_RESP_TIMEOUT_ERROR ; +if (meson_mmc_irq &STATUS_DESC_TIMEOUT ) + ret |=SD_EMMC_DESC_TIMEOUT_ERROR ;
What are these ret values? Do you use the your specific error values?
drivers/mmc/meson_mmc.c line 240
Quoted 9 lines
drivers/mmc/meson_mmc.c new file +9
-0+ +meson_mmc_read_response (mmc, data, cmd, meson_mmc_reg); + +if (data && data->flags ==MMC_DATA_WRITE ) +free (pdata->w_buf); + +if (ret) { +if (meson_mmc_irq &STATUS_RESP_TIMEOUT ) +return TIMEOUT ;
Strange this..why return at here...not above?
Best Regards,
Jaehoon Chung
Quoted 66 lines
drivers/mmc/meson_mmc.c new file +65
-0+return ret; + } + +return 0 ; +} + +static const struct mmc_ops meson_mmc_ops = { + .send_cmd = meson_mmc_send_cmd, + .set_ios = meson_mmc_set_ios, + .init = meson_mmc_init, +}; + +static int meson_mmc_ofdata_to_platdata (struct udevice *dev) +{ +struct meson_mmc_platdata *pdata = dev->platdata; +fdt_addr_t addr; + + addr =dev_get_addr (dev); +if (addr ==FDT_ADDR_T_NONE ) +return -EINVAL ; + + pdata->sd_emmc_reg = (struct meson_mmc_regs *)addr; + +return 0 ; +} + +static int meson_mmc_probe (struct udevice *dev) +{ +struct meson_mmc_platdata *pdata = dev->platdata; +struct mmc_uclass_priv *upriv =dev_get_uclass_priv (dev); +struct mmc *mmc; +struct mmc_config *cfg; + + cfg = &pdata->cfg; + cfg->ops = &meson_mmc_ops; + + cfg->voltages =MMC_VDD_33_34 |MMC_VDD_32_33 | +MMC_VDD_31_32 |MMC_VDD_165_195 ; + cfg->host_caps =MMC_MODE_8BIT |MMC_MODE_4BIT | + MMC_MODE_HS_52MHz |MMC_MODE_HS ; + cfg->f_min =400000 ; + cfg->f_max =50000000 ; + cfg->b_max =256 ; + + mmc =mmc_create (cfg, pdata); +if (!mmc) +return -ENOMEM ; + + upriv->mmc = mmc; +return 0 ; +} + +static const struct udevice_id meson_mmc_match[] = { + { .compatible ="amlogic,meson-mmc" }, + {/* sentinel */ } +}; + +U_BOOT_DRIVER (meson_mmc) = { + .name ="meson_mmc" , + .id =UCLASS_MMC , + .of_match = meson_mmc_match, + .probe = meson_mmc_probe, + .ofdata_to_platdata = meson_mmc_ofdata_to_platdata, + .platdata_auto_alloc_size =sizeof (struct meson_mmc_platdata ), +};
PATCH 2/2 arm: amlogic: Enable MMC driver on Odroid-C2
In reply to Carlo CaioneFrom: Carlo Caione <[email protected]>
Add support for the MMC on the Hardkernel Odroid-C2 board.
--- board/hardkernel/odroid-c2/odroid-c2.c | 42 ++++++++++++++++++++++++++++++++++ configs/odroid-c2_defconfig | 5 ++++ include/configs/odroid-c2.h | 7 ++++++ 3 files changed, 54 insertions(+)
board/hardkernel/odroid-c2/odroid-c2.c +42 -0
@@ -8,6 +8,7 @@#include <asm/io.h> #include <asm/arch/gxbb.h> #include <asm/arch/sm.h> +#include <asm/arch/sd_emmc.h> #include <dm/platdata.h> #include <phy.h>
@@ -65,3 +66,44 @@ int misc_init_r(void)return 0 ; } + +#ifdef CONFIG_GENERIC_MMC + +static const struct meson_mmc_platdata gxbb_sd_platdata[] = { + { .sd_emmc_reg = (struct meson_mmc_regs *)SD_EMMC_BASE_A }, + { .sd_emmc_reg = (struct meson_mmc_regs *)SD_EMMC_BASE_B }, + { .sd_emmc_reg = (struct meson_mmc_regs *)SD_EMMC_BASE_C }, +}; + +U_BOOT_DEVICE (meson_mmc) = { + .name ="meson_mmc" , + .platdata = &gxbb_sd_platdata[CONFIG_MMC_MESON_SD_PORT ], +}; + +static void meson_mmc_pinmux_setup (unsigned int port) +{ +switch (port) { +case SDIO_PORT_A : +setbits_le32 (GXBB_PINMUX (8 ),0x3f ); +break ; +case SDIO_PORT_B : +setbits_le32 (GXBB_PINMUX (2 ),0x3f <<10 ); +break ; +case SDIO_PORT_C : +clrbits_le32 (GXBB_PINMUX (2 ),0x1f <<22 ); +setbits_le32 (GXBB_PINMUX (4 ), (0x3 <<18 ) | (3 <<30 )); +break ; +default : +printf ("meson: invalid MMC port %d for pinmux setup\n" , port); +break ; + } +} + +int board_mmc_init (bd_t *bis) +{ +meson_mmc_pinmux_setup (CONFIG_MMC_MESON_SD_PORT ); + +return 0 ; +} + +#endif
configs/odroid-c2_defconfig +5 -0
@@ -7,11 +7,16 @@ CONFIG_DEFAULT_DEVICE_TREE="meson-gxbb-odroidc2" # CONFIG_CMD_IMI is not set # CONFIG_CMD_IMLS is not set # CONFIG_CMD_LOADS is not set +CONFIG_CMD_MMC=y # CONFIG_CMD_FPGA is not set # CONFIG_CMD_SOURCE is not set # CONFIG_CMD_SETEXPR is not set +CONFIG_CMD_EXT4=y +CONFIG_CMD_FAT=y +CONFIG_CMD_FS_GENERIC=y CONFIG_OF_CONTROL=y CONFIG_NET_RANDOM_ETHADDR=y +CONFIG_DM_MMC=y CONFIG_DM_ETH=y CONFIG_ETH_DESIGNWARE=y CONFIG_DEBUG_UART=y
include/configs/odroid-c2.h +7 -0
@@ -46,6 +46,13 @@#define CONFIG_SYS_LONGHELP #define CONFIG_CMDLINE_EDITING +#ifdef CONFIG_DM_MMC +#define CONFIG_MMC +#define CONFIG_GENERIC_MMC +#define CONFIG_MMC_MESON +#define CONFIG_MMC_MESON_SD_PORT 1 +#endif +#include <config_distro_defaults.h> #endif /* __CONFIG_H */
Signature · 1 line
2.7.4
cover Add support for Amlogic Meson MMC controller
In reply to Carlo CaioneApplied this on my Odroid C2, and it worked OK when installed on the SDcard, but failed when installed on the eMMC module:
=> version
U-Boot 2016.05-rc3 (May 14 2016 - 21:06:28 -0700) odroid-c2 aarch64-linux-gnu-gcc (GCC) 5.3.1 20160212 (Red Hat Cross 5.3.1-2) GNU ld version 2.26.20160125
=> mmc info
Card did not respond to voltage select!
Robert Gadsdon.
cover Add support for Amlogic Meson MMC controller
Quoted 10 lines · Robert Gadsdon
Applied this on my Odroid C2, and it worked OK when installed on the SDcard, but failed when installed on the eMMC module:
=> version
U-Boot 2016.05-rc3 (May 14 2016 - 21:06:28 -0700) odroid-c2 aarch64-linux-gnu-gcc (GCC) 5.3.1 20160212 (Red Hat Cross 5.3.1-2) GNU ld version 2.26.20160125=> mmc info
Card did not respond to voltage select!
Yes, this is expected since the muxing in the board file is only enabling the SDcard. Could you try to set the correct muxing also for the eMMC and check again?
Unfortunately I don't have an eMMC for the Odroid-C2 to check this out. I'll try to prepare a board file also for the P20x so I can test this better.
Thank you for testing this BTW.
Cheers,
Signature · 1 line
Carlo Caione
cover Add support for Amlogic Meson MMC controller
Quoted 3 lines · Carlo Caione
Quoted 2 lines · Robert Gadsdon
Applied this on my Odroid C2, and it worked OK when installed on the SDcard, but failed when installed on the eMMC module:
Oh, reading this again you meant that you put u-boot directly on the eMMC? Ok then, something is wrong when using the driver with the eMMC.
I'll try to boot it on the P20x and check what's wrong with it.
Thanks,
Signature · 1 line
Carlo Caione
cover Add support for Amlogic Meson MMC controller
Quoted 8 lines · Carlo Caione
Quoted 3 lines · Carlo Caione
Quoted 2 lines · Robert Gadsdon
Applied this on my Odroid C2, and it worked OK when installed on the SDcard, but failed when installed on the eMMC module:
Oh, reading this again you meant that you put u-boot directly on the eMMC? Ok then, something is wrong when using the driver with the eMMC.
Yes, I installed it directly on the eMMC, using the micro-sd adapter, and following the same instructions as for the SDcard..
Robert Gadsdon.
cover Add support for Amlogic Meson MMC controller
Quoted 6 lines · Robert Gadsdon
Quoted 5 lines · Carlo Caione
Quoted 3 lines · Carlo Caione
Quoted 2 lines · Robert Gadsdon
Applied this on my Odroid C2, and it worked OK when installed on the SDcard, but failed when installed on the eMMC module:
Quoted 6 lines
Quoted 3 lines
Oh, reading this again you meant that you put u-boot directly on the eMMC? Ok then, something is wrong when using the driver with the eMMC.
Yes, I installed it directly on the eMMC, using the micro-sd adapter, and following the same instructions as for the SDcard..
Could you try with this patch?
(quoted diff) +0 -0
b/board/hardkernel/odroid-c2/odroid-c2.c
index 34b9a95..ab78328 100644
board/hardkernel/odroid-c2/odroid-c2.c +0 -0
@@ -80,6 +80,11 @@ U_BOOT_DEVICE(meson_mmc) = { .platdata = &gxbb_sd_platdata[CONFIG_MMC_MESON_SD_PORT],
};
+U_BOOT_DEVICE(meson_emmc) = {
+ .name = "meson_mmc",
+ .platdata = &gxbb_sd_platdata[2],
+};
+
static void meson_mmc_pinmux_setup(unsigned int port)
{
switch (port) {Thanks,
Signature · 1 line
Carlo Caione
cover Add support for Amlogic Meson MMC controller
Quoted 31 lines · Carlo Caione
Quoted 10 lines · Robert Gadsdon
Quoted 9 lines · Carlo Caione
Quoted 3 lines · Carlo Caione
Quoted 2 lines · Robert Gadsdon
Applied this on my Odroid C2, and it worked OK when installed on the SDcard, but failed when installed on the eMMC module:
Oh, reading this again you meant that you put u-boot directly on the eMMC? Ok then, something is wrong when using the driver with the eMMC.
Yes, I installed it directly on the eMMC, using the micro-sd adapter, and following the same instructions as for the SDcard..
Could you try with this patch?
board/hardkernel/odroid-c2/odroid-c2.c +0
-0@@ -80,6 +80,11 @@ U_BOOT_DEVICE(meson_mmc) = { .platdata = &gxbb_sd_platdata[CONFIG_MMC_MESON_SD_PORT], }; +U_BOOT_DEVICE(meson_emmc) = { + .name = "meson_mmc", + .platdata = &gxbb_sd_platdata[2],+}; + static void meson_mmc_pinmux_setup(unsigned int port) { switch (port) {
Quoted 1 line
Thanks,
Patch applied, and now the eMMC is detected OK:
=> mmc info
Device: <NULL>
Manufacturer ID: 15
OEM: 100
Name: BGND3
Tran Speed: 52000000
Rd Block Len: 512
MMC version 5.0
High Capacity: Yes
Capacity: 29.1 GiB
Bus Width: 8-bit
Erase Group Size: 512 KiB
HC WP Group Size: 8 MiB
User Capacity: 29.1 GiB WRREL
Boot Capacity: 4 MiB ENH
RPMB Capacity: 4 MiB ENH
... And I can load/boot the Kernel (as far as the /dev/mmc... prompt..)
Thanks!
Robert Gadsdon.