diff options
Diffstat (limited to 'drivers/mmc')
-rw-r--r-- | drivers/mmc/Kconfig | 11 | ||||
-rw-r--r-- | drivers/mmc/Makefile | 3 | ||||
-rw-r--r-- | drivers/mmc/dw_mmc.c | 33 | ||||
-rw-r--r-- | drivers/mmc/mmc-uclass.c | 146 | ||||
-rw-r--r-- | drivers/mmc/mmc.c | 371 | ||||
-rw-r--r-- | drivers/mmc/mmc_boot.c | 131 | ||||
-rw-r--r-- | drivers/mmc/mmc_legacy.c | 91 | ||||
-rw-r--r-- | drivers/mmc/mmc_private.h | 47 | ||||
-rw-r--r-- | drivers/mmc/msm_sdhci.c | 35 | ||||
-rw-r--r-- | drivers/mmc/rockchip_dw_mmc.c | 73 | ||||
-rw-r--r-- | drivers/mmc/sandbox_mmc.c | 17 | ||||
-rw-r--r-- | drivers/mmc/sdhci.c | 147 |
12 files changed, 689 insertions, 416 deletions
diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig index c80efc3..79cf18f 100644 --- a/drivers/mmc/Kconfig +++ b/drivers/mmc/Kconfig @@ -16,9 +16,18 @@ config DM_MMC appear as block devices in U-Boot and can support filesystems such as EXT4 and FAT. +config DM_MMC_OPS + bool "Support MMC controller operations using Driver Model" + depends on DM_MMC + help + Driver model provides a means of supporting device operations. This + option moves MMC operations under the control of driver model. The + option will be removed as soon as all DM_MMC drivers use it, as it + will the only supported behaviour. + config MSM_SDHCI bool "Qualcomm SDHCI controller" - depends on DM_MMC + depends on DM_MMC && BLK && DM_MMC_OPS help Enables support for SDHCI 2.0 controller present on some Qualcomm Snapdragon devices. This device is compatible with eMMC v4.5 and diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile index 3da4817..b44a12e 100644 --- a/drivers/mmc/Makefile +++ b/drivers/mmc/Makefile @@ -25,6 +25,9 @@ obj-$(CONFIG_FSL_ESDHC) += fsl_esdhc.o obj-$(CONFIG_FTSDC010) += ftsdc010_mci.o obj-$(CONFIG_FTSDC021) += ftsdc021_sdhci.o obj-$(CONFIG_GENERIC_MMC) += mmc.o +ifdef CONFIG_SUPPORT_EMMC_BOOT +obj-$(CONFIG_GENERIC_MMC) += mmc_boot.o +endif obj-$(CONFIG_GENERIC_ATMEL_MCI) += gen_atmel_mci.o obj-$(CONFIG_KONA_SDHCI) += kona_sdhci.o obj-$(CONFIG_MMC_SPI) += mmc_spi.o diff --git a/drivers/mmc/dw_mmc.c b/drivers/mmc/dw_mmc.c index af6e04a..2cf7bae 100644 --- a/drivers/mmc/dw_mmc.c +++ b/drivers/mmc/dw_mmc.c @@ -181,9 +181,16 @@ static int dwmci_set_transfer_mode(struct dwmci_host *host, return mode; } +#ifdef CONFIG_DM_MMC_OPS +int dwmci_send_cmd(struct udevice *dev, struct mmc_cmd *cmd, + struct mmc_data *data) +{ + struct mmc *mmc = mmc_get_mmc_dev(dev); +#else static int dwmci_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data) { +#endif struct dwmci_host *host = mmc->priv; ALLOC_CACHE_ALIGN_BUFFER(struct dwmci_idmac, cur_idmac, data ? DIV_ROUND_UP(data->blocks, 8) : 0); @@ -373,8 +380,14 @@ static int dwmci_setup_bus(struct dwmci_host *host, u32 freq) return 0; } +#ifdef CONFIG_DM_MMC_OPS +int dwmci_set_ios(struct udevice *dev) +{ + struct mmc *mmc = mmc_get_mmc_dev(dev); +#else static void dwmci_set_ios(struct mmc *mmc) { +#endif struct dwmci_host *host = (struct dwmci_host *)mmc->priv; u32 ctype, regs; @@ -405,6 +418,9 @@ static void dwmci_set_ios(struct mmc *mmc) if (host->clksel) host->clksel(host); +#ifdef CONFIG_DM_MMC_OPS + return 0; +#endif } static int dwmci_init(struct mmc *mmc) @@ -448,17 +464,34 @@ static int dwmci_init(struct mmc *mmc) return 0; } +#ifdef CONFIG_DM_MMC_OPS +int dwmci_probe(struct udevice *dev) +{ + struct mmc *mmc = mmc_get_mmc_dev(dev); + + return dwmci_init(mmc); +} + +const struct dm_mmc_ops dm_dwmci_ops = { + .send_cmd = dwmci_send_cmd, + .set_ios = dwmci_set_ios, +}; + +#else static const struct mmc_ops dwmci_ops = { .send_cmd = dwmci_send_cmd, .set_ios = dwmci_set_ios, .init = dwmci_init, }; +#endif void dwmci_setup_cfg(struct mmc_config *cfg, const char *name, int buswidth, uint caps, u32 max_clk, u32 min_clk) { cfg->name = name; +#ifndef CONFIG_DM_MMC_OPS cfg->ops = &dwmci_ops; +#endif cfg->f_min = min_clk; cfg->f_max = max_clk; diff --git a/drivers/mmc/mmc-uclass.c b/drivers/mmc/mmc-uclass.c index 1b967d9..38ced41 100644 --- a/drivers/mmc/mmc-uclass.c +++ b/drivers/mmc/mmc-uclass.c @@ -8,8 +8,76 @@ #include <common.h> #include <mmc.h> #include <dm.h> +#include <dm/device-internal.h> #include <dm/lists.h> #include <dm/root.h> +#include "mmc_private.h" + +#ifdef CONFIG_DM_MMC_OPS +int dm_mmc_send_cmd(struct udevice *dev, struct mmc_cmd *cmd, + struct mmc_data *data) +{ + struct mmc *mmc = mmc_get_mmc_dev(dev); + struct dm_mmc_ops *ops = mmc_get_ops(dev); + int ret; + + mmmc_trace_before_send(mmc, cmd); + if (ops->send_cmd) + ret = ops->send_cmd(dev, cmd, data); + else + ret = -ENOSYS; + mmmc_trace_after_send(mmc, cmd, ret); + + return ret; +} + +int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data) +{ + return dm_mmc_send_cmd(mmc->dev, cmd, data); +} + +int dm_mmc_set_ios(struct udevice *dev) +{ + struct dm_mmc_ops *ops = mmc_get_ops(dev); + + if (!ops->set_ios) + return -ENOSYS; + return ops->set_ios(dev); +} + +int mmc_set_ios(struct mmc *mmc) +{ + return dm_mmc_set_ios(mmc->dev); +} + +int dm_mmc_get_wp(struct udevice *dev) +{ + struct dm_mmc_ops *ops = mmc_get_ops(dev); + + if (!ops->get_wp) + return -ENOSYS; + return ops->get_wp(dev); +} + +int mmc_getwp(struct mmc *mmc) +{ + return dm_mmc_get_wp(mmc->dev); +} + +int dm_mmc_get_cd(struct udevice *dev) +{ + struct dm_mmc_ops *ops = mmc_get_ops(dev); + + if (!ops->get_cd) + return -ENOSYS; + return ops->get_cd(dev); +} + +int mmc_getcd(struct mmc *mmc) +{ + return dm_mmc_get_cd(mmc->dev); +} +#endif struct mmc *mmc_get_mmc_dev(struct udevice *dev) { @@ -125,6 +193,84 @@ void print_mmc_devices(char separator) #else void print_mmc_devices(char separator) { } #endif + +int mmc_bind(struct udevice *dev, struct mmc *mmc, const struct mmc_config *cfg) +{ + struct blk_desc *bdesc; + struct udevice *bdev; + int ret; + + ret = blk_create_devicef(dev, "mmc_blk", "blk", IF_TYPE_MMC, -1, 512, + 0, &bdev); + if (ret) { + debug("Cannot create block device\n"); + return ret; + } + bdesc = dev_get_uclass_platdata(bdev); + mmc->cfg = cfg; + mmc->priv = dev; + + /* the following chunk was from mmc_register() */ + + /* Setup dsr related values */ + mmc->dsr_imp = 0; + mmc->dsr = 0xffffffff; + /* Setup the universal parts of the block interface just once */ + bdesc->removable = 1; + + /* setup initial part type */ + bdesc->part_type = cfg->part_type; + mmc->dev = dev; + + return 0; +} + +int mmc_unbind(struct udevice *dev) +{ + struct udevice *bdev; + + device_find_first_child(dev, &bdev); + if (bdev) { + device_remove(bdev); + device_unbind(bdev); + } + + return 0; +} + +static int mmc_select_hwpart(struct udevice *bdev, int hwpart) +{ + struct udevice *mmc_dev = dev_get_parent(bdev); + struct mmc *mmc = mmc_get_mmc_dev(mmc_dev); + struct blk_desc *desc = dev_get_uclass_platdata(bdev); + int ret; + + if (desc->hwpart == hwpart) + return 0; + + if (mmc->part_config == MMCPART_NOAVAILABLE) + return -EMEDIUMTYPE; + + ret = mmc_switch_part(mmc, hwpart); + if (ret) + return ret; + + return 0; +} + +static const struct blk_ops mmc_blk_ops = { + .read = mmc_bread, +#ifndef CONFIG_SPL_BUILD + .write = mmc_bwrite, +#endif + .select_hwpart = mmc_select_hwpart, +}; + +U_BOOT_DRIVER(mmc_blk) = { + .name = "mmc_blk", + .id = UCLASS_BLK, + .ops = &mmc_blk_ops, +}; #endif /* CONFIG_BLK */ U_BOOT_DRIVER(mmc) = { diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index aabfc71..f8e5f7a 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -21,6 +21,7 @@ #include <div64.h> #include "mmc_private.h" +#ifndef CONFIG_DM_MMC_OPS __weak int board_mmc_getwp(struct mmc *mmc) { return -1; @@ -46,18 +47,20 @@ __weak int board_mmc_getcd(struct mmc *mmc) { return -1; } +#endif -int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data) +#ifdef CONFIG_MMC_TRACE +void mmmc_trace_before_send(struct mmc *mmc, struct mmc_cmd *cmd) { - int ret; + printf("CMD_SEND:%d\n", cmd->cmdidx); + printf("\t\tARG\t\t\t 0x%08X\n", cmd->cmdarg); +} -#ifdef CONFIG_MMC_TRACE +void mmmc_trace_after_send(struct mmc *mmc, struct mmc_cmd *cmd, int ret) +{ int i; u8 *ptr; - printf("CMD_SEND:%d\n", cmd->cmdidx); - printf("\t\tARG\t\t\t 0x%08X\n", cmd->cmdarg); - ret = mmc->cfg->ops->send_cmd(mmc, cmd, data); if (ret) { printf("\t\tRET\t\t\t %d\n", ret); } else { @@ -103,19 +106,34 @@ int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data) break; } } -#else - ret = mmc->cfg->ops->send_cmd(mmc, cmd, data); +} + +void mmc_trace_state(struct mmc *mmc, struct mmc_cmd *cmd) +{ + int status; + + status = (cmd->response[0] & MMC_STATUS_CURR_STATE) >> 9; + printf("CURR STATE:%d\n", status); +} #endif + +#ifndef CONFIG_DM_MMC_OPS +int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data) +{ + int ret; + + mmmc_trace_before_send(mmc, cmd); + ret = mmc->cfg->ops->send_cmd(mmc, cmd, data); + mmmc_trace_after_send(mmc, cmd, ret); + return ret; } +#endif int mmc_send_status(struct mmc *mmc, int timeout) { struct mmc_cmd cmd; int err, retries = 5; -#ifdef CONFIG_MMC_TRACE - int status; -#endif cmd.cmdidx = MMC_CMD_SEND_STATUS; cmd.resp_type = MMC_RSP_R1; @@ -145,10 +163,7 @@ int mmc_send_status(struct mmc *mmc, int timeout) udelay(1000); } -#ifdef CONFIG_MMC_TRACE - status = (cmd.response[0] & MMC_STATUS_CURR_STATE) >> 9; - printf("CURR STATE:%d\n", status); -#endif + mmc_trace_state(mmc, &cmd); if (timeout <= 0) { #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) printf("Timeout waiting card ready\n"); @@ -215,11 +230,10 @@ static int mmc_read_blocks(struct mmc *mmc, void *dst, lbaint_t start, } #ifdef CONFIG_BLK -static ulong mmc_bread(struct udevice *dev, lbaint_t start, lbaint_t blkcnt, - void *dst) +ulong mmc_bread(struct udevice *dev, lbaint_t start, lbaint_t blkcnt, void *dst) #else -static ulong mmc_bread(struct blk_desc *block_dev, lbaint_t start, - lbaint_t blkcnt, void *dst) +ulong mmc_bread(struct blk_desc *block_dev, lbaint_t start, lbaint_t blkcnt, + void *dst) #endif { #ifdef CONFIG_BLK @@ -464,8 +478,7 @@ static int mmc_send_ext_csd(struct mmc *mmc, u8 *ext_csd) return err; } - -static int mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value) +int mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value) { struct mmc_cmd cmd; int timeout = 1000; @@ -566,7 +579,7 @@ static int mmc_set_capacity(struct mmc *mmc, int part_num) return 0; } -static int mmc_switch_part(struct mmc *mmc, unsigned int part_num) +int mmc_switch_part(struct mmc *mmc, unsigned int part_num) { int ret; @@ -586,49 +599,6 @@ static int mmc_switch_part(struct mmc *mmc, unsigned int part_num) return ret; } -#ifdef CONFIG_BLK -static int mmc_select_hwpart(struct udevice *bdev, int hwpart) -{ - struct udevice *mmc_dev = dev_get_parent(bdev); - struct mmc *mmc = mmc_get_mmc_dev(mmc_dev); - struct blk_desc *desc = dev_get_uclass_platdata(bdev); - int ret; - - if (desc->hwpart == hwpart) - return 0; - - if (mmc->part_config == MMCPART_NOAVAILABLE) - return -EMEDIUMTYPE; - - ret = mmc_switch_part(mmc, hwpart); - if (ret) - return ret; - - return 0; -} -#else -static int mmc_select_hwpartp(struct blk_desc *desc, int hwpart) -{ - struct mmc *mmc = find_mmc_device(desc->devnum); - int ret; - - if (!mmc) - return -ENODEV; - - if (mmc->block_dev.hwpart == hwpart) - return 0; - - if (mmc->part_config == MMCPART_NOAVAILABLE) - return -EMEDIUMTYPE; - - ret = mmc_switch_part(mmc, hwpart); - if (ret) - return ret; - - return 0; -} -#endif - int mmc_hwpart_config(struct mmc *mmc, const struct mmc_hwpart_conf *conf, enum mmc_hwpart_conf_mode mode) @@ -823,6 +793,7 @@ int mmc_hwpart_config(struct mmc *mmc, return 0; } +#ifndef CONFIG_DM_MMC_OPS int mmc_getcd(struct mmc *mmc) { int cd; @@ -838,6 +809,7 @@ int mmc_getcd(struct mmc *mmc) return cd; } +#endif static int sd_switch(struct mmc *mmc, int mode, int group, u8 value, u8 *resp) { @@ -1001,11 +973,13 @@ static const u8 multipliers[] = { 80, }; +#ifndef CONFIG_DM_MMC_OPS static void mmc_set_ios(struct mmc *mmc) { if (mmc->cfg->ops->set_ios) mmc->cfg->ops->set_ios(mmc); } +#endif void mmc_set_clock(struct mmc *mmc, uint clock) { @@ -1532,115 +1506,6 @@ static int mmc_send_if_cond(struct mmc *mmc) return 0; } -#ifdef CONFIG_BLK -int mmc_bind(struct udevice *dev, struct mmc *mmc, const struct mmc_config *cfg) -{ - struct blk_desc *bdesc; - struct udevice *bdev; - int ret; - - ret = blk_create_devicef(dev, "mmc_blk", "blk", IF_TYPE_MMC, -1, 512, - 0, &bdev); - if (ret) { - debug("Cannot create block device\n"); - return ret; - } - bdesc = dev_get_uclass_platdata(bdev); - mmc->cfg = cfg; - mmc->priv = dev; - - /* the following chunk was from mmc_register() */ - - /* Setup dsr related values */ - mmc->dsr_imp = 0; - mmc->dsr = 0xffffffff; - /* Setup the universal parts of the block interface just once */ - bdesc->removable = 1; - - /* setup initial part type */ - bdesc->part_type = cfg->part_type; - mmc->dev = dev; - - return 0; -} - -int mmc_unbind(struct udevice *dev) -{ - struct udevice *bdev; - - device_find_first_child(dev, &bdev); - if (bdev) { - device_remove(bdev); - device_unbind(bdev); - } - - return 0; -} - -#else -struct mmc *mmc_create(const struct mmc_config *cfg, void *priv) -{ - struct blk_desc *bdesc; - struct mmc *mmc; - - /* quick validation */ - if (cfg == NULL || cfg->ops == NULL || cfg->ops->send_cmd == NULL || - cfg->f_min == 0 || cfg->f_max == 0 || cfg->b_max == 0) - return NULL; - - mmc = calloc(1, sizeof(*mmc)); - if (mmc == NULL) - return NULL; - - mmc->cfg = cfg; - mmc->priv = priv; - - /* the following chunk was mmc_register() */ - - /* Setup dsr related values */ - mmc->dsr_imp = 0; - mmc->dsr = 0xffffffff; - /* Setup the universal parts of the block interface just once */ - bdesc = mmc_get_blk_desc(mmc); - bdesc->if_type = IF_TYPE_MMC; - bdesc->removable = 1; - bdesc->devnum = mmc_get_next_devnum(); - bdesc->block_read = mmc_bread; - bdesc->block_write = mmc_bwrite; - bdesc->block_erase = mmc_berase; - - /* setup initial part type */ - bdesc->part_type = mmc->cfg->part_type; - mmc_list_add(mmc); - - return mmc; -} - -void mmc_destroy(struct mmc *mmc) -{ - /* only freeing memory for now */ - free(mmc); -} -#endif - -#ifndef CONFIG_BLK -static int mmc_get_dev(int dev, struct blk_desc **descp) -{ - struct mmc *mmc = find_mmc_device(dev); - int ret; - - if (!mmc) - return -ENODEV; - ret = mmc_init(mmc); - if (ret) - return ret; - - *descp = &mmc->block_dev; - - return 0; -} -#endif - /* board-specific MMC power initializations. */ __weak void board_mmc_power_init(void) { @@ -1648,10 +1513,15 @@ __weak void board_mmc_power_init(void) int mmc_start_init(struct mmc *mmc) { + bool no_card; int err; /* we pretend there's no card when init is NULL */ - if (mmc_getcd(mmc) == 0 || mmc->cfg->ops->init == NULL) { + no_card = mmc_getcd(mmc) == 0; +#ifndef CONFIG_DM_MMC_OPS + no_card = no_card || (mmc->cfg->ops->init == NULL); +#endif + if (no_card) { mmc->has_init = 0; #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) printf("MMC: no card present\n"); @@ -1667,12 +1537,14 @@ int mmc_start_init(struct mmc *mmc) #endif board_mmc_power_init(); +#ifdef CONFIG_DM_MMC_OPS + /* The device has already been probed ready for use */ +#else /* made sure it's not NULL earlier */ err = mmc->cfg->ops->init(mmc); - if (err) return err; - +#endif mmc->ddr_mode = 0; mmc_set_bus_width(mmc, 1); mmc_set_clock(mmc, 1); @@ -1839,148 +1711,3 @@ int mmc_initialize(bd_t *bis) mmc_do_preinit(); return 0; } - -#ifdef CONFIG_SUPPORT_EMMC_BOOT -/* - * This function changes the size of boot partition and the size of rpmb - * partition present on EMMC devices. - * - * Input Parameters: - * struct *mmc: pointer for the mmc device strcuture - * bootsize: size of boot partition - * rpmbsize: size of rpmb partition - * - * Returns 0 on success. - */ - -int mmc_boot_partition_size_change(struct mmc *mmc, unsigned long bootsize, - unsigned long rpmbsize) -{ - int err; - struct mmc_cmd cmd; - - /* Only use this command for raw EMMC moviNAND. Enter backdoor mode */ - cmd.cmdidx = MMC_CMD_RES_MAN; - cmd.resp_type = MMC_RSP_R1b; - cmd.cmdarg = MMC_CMD62_ARG1; - - err = mmc_send_cmd(mmc, &cmd, NULL); - if (err) { - debug("mmc_boot_partition_size_change: Error1 = %d\n", err); - return err; - } - - /* Boot partition changing mode */ - cmd.cmdidx = MMC_CMD_RES_MAN; - cmd.resp_type = MMC_RSP_R1b; - cmd.cmdarg = MMC_CMD62_ARG2; - - err = mmc_send_cmd(mmc, &cmd, NULL); - if (err) { - debug("mmc_boot_partition_size_change: Error2 = %d\n", err); - return err; - } - /* boot partition size is multiple of 128KB */ - bootsize = (bootsize * 1024) / 128; - - /* Arg: boot partition size */ - cmd.cmdidx = MMC_CMD_RES_MAN; - cmd.resp_type = MMC_RSP_R1b; - cmd.cmdarg = bootsize; - - err = mmc_send_cmd(mmc, &cmd, NULL); - if (err) { - debug("mmc_boot_partition_size_change: Error3 = %d\n", err); - return err; - } - /* RPMB partition size is multiple of 128KB */ - rpmbsize = (rpmbsize * 1024) / 128; - /* Arg: RPMB partition size */ - cmd.cmdidx = MMC_CMD_RES_MAN; - cmd.resp_type = MMC_RSP_R1b; - cmd.cmdarg = rpmbsize; - - err = mmc_send_cmd(mmc, &cmd, NULL); - if (err) { - debug("mmc_boot_partition_size_change: Error4 = %d\n", err); - return err; - } - return 0; -} - -/* - * Modify EXT_CSD[177] which is BOOT_BUS_WIDTH - * based on the passed in values for BOOT_BUS_WIDTH, RESET_BOOT_BUS_WIDTH - * and BOOT_MODE. - * - * Returns 0 on success. - */ -int mmc_set_boot_bus_width(struct mmc *mmc, u8 width, u8 reset, u8 mode) -{ - int err; - - err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BOOT_BUS_WIDTH, - EXT_CSD_BOOT_BUS_WIDTH_MODE(mode) | - EXT_CSD_BOOT_BUS_WIDTH_RESET(reset) | - EXT_CSD_BOOT_BUS_WIDTH_WIDTH(width)); - - if (err) - return err; - return 0; -} - -/* - * Modify EXT_CSD[179] which is PARTITION_CONFIG (formerly BOOT_CONFIG) - * based on the passed in values for BOOT_ACK, BOOT_PARTITION_ENABLE and - * PARTITION_ACCESS. - * - * Returns 0 on success. - */ -int mmc_set_part_conf(struct mmc *mmc, u8 ack, u8 part_num, u8 access) -{ - int err; - - err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_PART_CONF, - EXT_CSD_BOOT_ACK(ack) | - EXT_CSD_BOOT_PART_NUM(part_num) | - EXT_CSD_PARTITION_ACCESS(access)); - - if (err) - return err; - return 0; -} - -/* - * Modify EXT_CSD[162] which is RST_n_FUNCTION based on the given value - * for enable. Note that this is a write-once field for non-zero values. - * - * Returns 0 on success. - */ -int mmc_set_rst_n_function(struct mmc *mmc, u8 enable) -{ - return mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_RST_N_FUNCTION, - enable); -} -#endif - -#ifdef CONFIG_BLK -static const struct blk_ops mmc_blk_ops = { - .read = mmc_bread, - .write = mmc_bwrite, - .select_hwpart = mmc_select_hwpart, -}; - -U_BOOT_DRIVER(mmc_blk) = { - .name = "mmc_blk", - .id = UCLASS_BLK, - .ops = &mmc_blk_ops, -}; -#else -U_BOOT_LEGACY_BLK(mmc) = { - .if_typename = "mmc", - .if_type = IF_TYPE_MMC, - .max_devs = -1, - .get_dev = mmc_get_dev, - .select_hwpart = mmc_select_hwpartp, -}; -#endif diff --git a/drivers/mmc/mmc_boot.c b/drivers/mmc/mmc_boot.c new file mode 100644 index 0000000..756a982 --- /dev/null +++ b/drivers/mmc/mmc_boot.c @@ -0,0 +1,131 @@ +/* + * Copyright (C) 2016 Google, Inc + * Written by Amar <amarendra.xt@samsung.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <mmc.h> +#include "mmc_private.h" + +/* + * This function changes the size of boot partition and the size of rpmb + * partition present on EMMC devices. + * + * Input Parameters: + * struct *mmc: pointer for the mmc device strcuture + * bootsize: size of boot partition + * rpmbsize: size of rpmb partition + * + * Returns 0 on success. + */ + +int mmc_boot_partition_size_change(struct mmc *mmc, unsigned long bootsize, + unsigned long rpmbsize) +{ + int err; + struct mmc_cmd cmd; + + /* Only use this command for raw EMMC moviNAND. Enter backdoor mode */ + cmd.cmdidx = MMC_CMD_RES_MAN; + cmd.resp_type = MMC_RSP_R1b; + cmd.cmdarg = MMC_CMD62_ARG1; + + err = mmc_send_cmd(mmc, &cmd, NULL); + if (err) { + debug("mmc_boot_partition_size_change: Error1 = %d\n", err); + return err; + } + + /* Boot partition changing mode */ + cmd.cmdidx = MMC_CMD_RES_MAN; + cmd.resp_type = MMC_RSP_R1b; + cmd.cmdarg = MMC_CMD62_ARG2; + + err = mmc_send_cmd(mmc, &cmd, NULL); + if (err) { + debug("mmc_boot_partition_size_change: Error2 = %d\n", err); + return err; + } + /* boot partition size is multiple of 128KB */ + bootsize = (bootsize * 1024) / 128; + + /* Arg: boot partition size */ + cmd.cmdidx = MMC_CMD_RES_MAN; + cmd.resp_type = MMC_RSP_R1b; + cmd.cmdarg = bootsize; + + err = mmc_send_cmd(mmc, &cmd, NULL); + if (err) { + debug("mmc_boot_partition_size_change: Error3 = %d\n", err); + return err; + } + /* RPMB partition size is multiple of 128KB */ + rpmbsize = (rpmbsize * 1024) / 128; + /* Arg: RPMB partition size */ + cmd.cmdidx = MMC_CMD_RES_MAN; + cmd.resp_type = MMC_RSP_R1b; + cmd.cmdarg = rpmbsize; + + err = mmc_send_cmd(mmc, &cmd, NULL); + if (err) { + debug("mmc_boot_partition_size_change: Error4 = %d\n", err); + return err; + } + return 0; +} + +/* + * Modify EXT_CSD[177] which is BOOT_BUS_WIDTH + * based on the passed in values for BOOT_BUS_WIDTH, RESET_BOOT_BUS_WIDTH + * and BOOT_MODE. + * + * Returns 0 on success. + */ +int mmc_set_boot_bus_width(struct mmc *mmc, u8 width, u8 reset, u8 mode) +{ + int err; + + err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BOOT_BUS_WIDTH, + EXT_CSD_BOOT_BUS_WIDTH_MODE(mode) | + EXT_CSD_BOOT_BUS_WIDTH_RESET(reset) | + EXT_CSD_BOOT_BUS_WIDTH_WIDTH(width)); + + if (err) + return err; + return 0; +} + +/* + * Modify EXT_CSD[179] which is PARTITION_CONFIG (formerly BOOT_CONFIG) + * based on the passed in values for BOOT_ACK, BOOT_PARTITION_ENABLE and + * PARTITION_ACCESS. + * + * Returns 0 on success. + */ +int mmc_set_part_conf(struct mmc *mmc, u8 ack, u8 part_num, u8 access) +{ + int err; + + err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_PART_CONF, + EXT_CSD_BOOT_ACK(ack) | + EXT_CSD_BOOT_PART_NUM(part_num) | + EXT_CSD_PARTITION_ACCESS(access)); + + if (err) + return err; + return 0; +} + +/* + * Modify EXT_CSD[162] which is RST_n_FUNCTION based on the given value + * for enable. Note that this is a write-once field for non-zero values. + * + * Returns 0 on success. + */ +int mmc_set_rst_n_function(struct mmc *mmc, u8 enable) +{ + return mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_RST_N_FUNCTION, + enable); +} diff --git a/drivers/mmc/mmc_legacy.c b/drivers/mmc/mmc_legacy.c index 3ec649f..040728b 100644 --- a/drivers/mmc/mmc_legacy.c +++ b/drivers/mmc/mmc_legacy.c @@ -6,7 +6,9 @@ */ #include <common.h> +#include <malloc.h> #include <mmc.h> +#include "mmc_private.h" static struct list_head mmc_devices; static int cur_dev_num = -1; @@ -106,3 +108,92 @@ void print_mmc_devices(char separator) #else void print_mmc_devices(char separator) { } #endif + +struct mmc *mmc_create(const struct mmc_config *cfg, void *priv) +{ + struct blk_desc *bdesc; + struct mmc *mmc; + + /* quick validation */ + if (cfg == NULL || cfg->ops == NULL || cfg->ops->send_cmd == NULL || + cfg->f_min == 0 || cfg->f_max == 0 || cfg->b_max == 0) + return NULL; + + mmc = calloc(1, sizeof(*mmc)); + if (mmc == NULL) + return NULL; + + mmc->cfg = cfg; + mmc->priv = priv; + + /* the following chunk was mmc_register() */ + + /* Setup dsr related values */ + mmc->dsr_imp = 0; + mmc->dsr = 0xffffffff; + /* Setup the universal parts of the block interface just once */ + bdesc = mmc_get_blk_desc(mmc); + bdesc->if_type = IF_TYPE_MMC; + bdesc->removable = 1; + bdesc->devnum = mmc_get_next_devnum(); + bdesc->block_read = mmc_bread; + bdesc->block_write = mmc_bwrite; + bdesc->block_erase = mmc_berase; + + /* setup initial part type */ + bdesc->part_type = mmc->cfg->part_type; + mmc_list_add(mmc); + + return mmc; +} + +void mmc_destroy(struct mmc *mmc) +{ + /* only freeing memory for now */ + free(mmc); +} + +static int mmc_select_hwpartp(struct blk_desc *desc, int hwpart) +{ + struct mmc *mmc = find_mmc_device(desc->devnum); + int ret; + + if (!mmc) + return -ENODEV; + + if (mmc->block_dev.hwpart == hwpart) + return 0; + + if (mmc->part_config == MMCPART_NOAVAILABLE) + return -EMEDIUMTYPE; + + ret = mmc_switch_part(mmc, hwpart); + if (ret) + return ret; + + return 0; +} + +static int mmc_get_dev(int dev, struct blk_desc **descp) +{ + struct mmc *mmc = find_mmc_device(dev); + int ret; + + if (!mmc) + return -ENODEV; + ret = mmc_init(mmc); + if (ret) + return ret; + + *descp = &mmc->block_dev; + + return 0; +} + +U_BOOT_LEGACY_BLK(mmc) = { + .if_typename = "mmc", + .if_type = IF_TYPE_MMC, + .max_devs = -1, + .get_dev = mmc_get_dev, + .select_hwpart = mmc_select_hwpartp, +}; diff --git a/drivers/mmc/mmc_private.h b/drivers/mmc/mmc_private.h index 9f0d5c2..49ec022 100644 --- a/drivers/mmc/mmc_private.h +++ b/drivers/mmc/mmc_private.h @@ -20,6 +20,14 @@ extern int mmc_set_blocklen(struct mmc *mmc, int len); void mmc_adapter_card_type_ident(void); #endif +#ifdef CONFIG_BLK +ulong mmc_bread(struct udevice *dev, lbaint_t start, lbaint_t blkcnt, + void *dst); +#else +ulong mmc_bread(struct blk_desc *block_dev, lbaint_t start, lbaint_t blkcnt, + void *dst); +#endif + #ifndef CONFIG_SPL_BUILD unsigned long mmc_berase(struct blk_desc *block_dev, lbaint_t start, @@ -65,6 +73,25 @@ static inline ulong mmc_bwrite(struct blk_desc *block_dev, lbaint_t start, #endif /* CONFIG_SPL_BUILD */ +#ifdef CONFIG_MMC_TRACE +void mmmc_trace_before_send(struct mmc *mmc, struct mmc_cmd *cmd); +void mmmc_trace_after_send(struct mmc *mmc, struct mmc_cmd *cmd, int ret); +void mmc_trace_state(struct mmc *mmc, struct mmc_cmd *cmd); +#else +static inline void mmmc_trace_before_send(struct mmc *mmc, struct mmc_cmd *cmd) +{ +} + +static inline void mmmc_trace_after_send(struct mmc *mmc, struct mmc_cmd *cmd, + int ret) +{ +} + +static inline void mmc_trace_state(struct mmc *mmc, struct mmc_cmd *cmd) +{ +} +#endif + /** * mmc_get_next_devnum() - Get the next available MMC device number * @@ -89,4 +116,24 @@ void mmc_list_init(void); */ void mmc_list_add(struct mmc *mmc); +/** + * mmc_switch_part() - Switch to a new MMC hardware partition + * + * @mmc: MMC device + * @part_num: Hardware partition number + * @return 0 if OK, -ve on error + */ +int mmc_switch_part(struct mmc *mmc, unsigned int part_num); + +/** + * mmc_switch() - Issue and MMC switch mode command + * + * @mmc: MMC device + * @set: Unused + * @index: Cmdarg index + * @value: Cmdarg value + * @return 0 if OK, -ve on error + */ +int mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value); + #endif /* _MMC_PRIVATE_H_ */ diff --git a/drivers/mmc/msm_sdhci.c b/drivers/mmc/msm_sdhci.c index 96dcdbe..70a8d96 100644 --- a/drivers/mmc/msm_sdhci.c +++ b/drivers/mmc/msm_sdhci.c @@ -36,6 +36,11 @@ /* Non standard (?) SDHCI register */ #define SDHCI_VENDOR_SPEC_CAPABILITIES0 0x11c +struct msm_sdhc_plat { + struct mmc_config cfg; + struct mmc mmc; +}; + struct msm_sdhc { struct sdhci_host host; void *base; @@ -81,9 +86,12 @@ static int msm_sdc_clk_init(struct udevice *dev) static int msm_sdc_probe(struct udevice *dev) { + struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev); + struct msm_sdhc_plat *plat = dev_get_platdata(dev); struct msm_sdhc *prv = dev_get_priv(dev); struct sdhci_host *host = &prv->host; u32 core_version, core_minor, core_major; + u32 caps; int ret; host->quirks = SDHCI_QUIRK_WAIT_SEND_CMD | SDHCI_QUIRK_BROKEN_R1B; @@ -127,7 +135,7 @@ static int msm_sdc_probe(struct udevice *dev) * controller versions and must be explicitly enabled. */ if (core_major >= 1 && core_minor != 0x11 && core_minor != 0x12) { - u32 caps = readl(host->ioaddr + SDHCI_CAPABILITIES); + caps = readl(host->ioaddr + SDHCI_CAPABILITIES); caps |= SDHCI_CAN_VDD_300 | SDHCI_CAN_DO_8BIT; writel(caps, host->ioaddr + SDHCI_VENDOR_SPEC_CAPABILITIES0); } @@ -135,13 +143,17 @@ static int msm_sdc_probe(struct udevice *dev) /* Set host controller version */ host->version = sdhci_readw(host, SDHCI_HOST_VERSION); - /* automatically detect max and min speed */ - ret = add_sdhci(host, 0, 0); + caps = sdhci_readl(host, SDHCI_CAPABILITIES); + ret = sdhci_setup_cfg(&plat->cfg, dev->name, host->bus_width, + caps, 0, 0, host->version, host->quirks, 0); + host->mmc = &plat->mmc; if (ret) return ret; + host->mmc->priv = &prv->host; host->mmc->dev = dev; + upriv->mmc = host->mmc; - return 0; + return sdhci_probe(dev); } static int msm_sdc_remove(struct udevice *dev) @@ -176,6 +188,18 @@ static int msm_ofdata_to_platdata(struct udevice *dev) return 0; } +static int msm_sdc_bind(struct udevice *dev) +{ + struct msm_sdhc_plat *plat = dev_get_platdata(dev); + int ret; + + ret = sdhci_bind(dev, &plat->mmc, &plat->cfg); + if (ret) + return ret; + + return 0; +} + static const struct udevice_id msm_mmc_ids[] = { { .compatible = "qcom,sdhci-msm-v4" }, { } @@ -186,7 +210,10 @@ U_BOOT_DRIVER(msm_sdc_drv) = { .id = UCLASS_MMC, .of_match = msm_mmc_ids, .ofdata_to_platdata = msm_ofdata_to_platdata, + .ops = &sdhci_ops, + .bind = msm_sdc_bind, .probe = msm_sdc_probe, .remove = msm_sdc_remove, .priv_auto_alloc_size = sizeof(struct msm_sdhc), + .platdata_auto_alloc_size = sizeof(struct msm_sdhc_plat), }; diff --git a/drivers/mmc/rockchip_dw_mmc.c b/drivers/mmc/rockchip_dw_mmc.c index d41d60c..020a59b 100644 --- a/drivers/mmc/rockchip_dw_mmc.c +++ b/drivers/mmc/rockchip_dw_mmc.c @@ -7,8 +7,10 @@ #include <common.h> #include <clk.h> #include <dm.h> +#include <dt-structs.h> #include <dwmmc.h> #include <errno.h> +#include <mapmem.h> #include <pwrseq.h> #include <syscon.h> #include <asm/gpio.h> @@ -19,6 +21,9 @@ DECLARE_GLOBAL_DATA_PTR; struct rockchip_mmc_plat { +#if CONFIG_IS_ENABLED(OF_PLATDATA) + struct dtd_rockchip_rk3288_dw_mshc dtplat; +#endif struct mmc_config cfg; struct mmc mmc; }; @@ -26,6 +31,9 @@ struct rockchip_mmc_plat { struct rockchip_dwmmc_priv { struct clk clk; struct dwmci_host host; + int fifo_depth; + bool fifo_mode; + u32 minmax[2]; }; static uint rockchip_dwmmc_get_mmc_clk(struct dwmci_host *host, uint freq) @@ -45,6 +53,7 @@ static uint rockchip_dwmmc_get_mmc_clk(struct dwmci_host *host, uint freq) static int rockchip_dwmmc_ofdata_to_platdata(struct udevice *dev) { +#if !CONFIG_IS_ENABLED(OF_PLATDATA) struct rockchip_dwmmc_priv *priv = dev_get_priv(dev); struct dwmci_host *host = &priv->host; @@ -61,40 +70,54 @@ static int rockchip_dwmmc_ofdata_to_platdata(struct udevice *dev) else host->dev_index = 1; + priv->fifo_depth = fdtdec_get_int(gd->fdt_blob, dev->of_offset, + "fifo-depth", 0); + if (priv->fifo_depth < 0) + return -EINVAL; + priv->fifo_mode = fdtdec_get_bool(gd->fdt_blob, dev->of_offset, + "fifo-mode"); + if (fdtdec_get_int_array(gd->fdt_blob, dev->of_offset, + "clock-freq-min-max", priv->minmax, 2)) + return -EINVAL; +#endif return 0; } static int rockchip_dwmmc_probe(struct udevice *dev) { -#ifdef CONFIG_BLK struct rockchip_mmc_plat *plat = dev_get_platdata(dev); -#endif struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev); struct rockchip_dwmmc_priv *priv = dev_get_priv(dev); struct dwmci_host *host = &priv->host; struct udevice *pwr_dev __maybe_unused; - u32 minmax[2]; int ret; - int fifo_depth; +#if CONFIG_IS_ENABLED(OF_PLATDATA) + struct dtd_rockchip_rk3288_dw_mshc *dtplat = &plat->dtplat; + + host->name = dev->name; + host->ioaddr = map_sysmem(dtplat->reg[0], dtplat->reg[1]); + host->buswidth = dtplat->bus_width; + host->get_mmc_clk = rockchip_dwmmc_get_mmc_clk; + host->priv = dev; + host->dev_index = 0; + priv->fifo_depth = dtplat->fifo_depth; + priv->fifo_mode = 0; + memcpy(priv->minmax, dtplat->clock_freq_min_max, sizeof(priv->minmax)); + + ret = clk_get_by_index_platdata(dev, 0, dtplat->clocks, &priv->clk); + if (ret < 0) + return ret; +#else ret = clk_get_by_index(dev, 0, &priv->clk); if (ret < 0) return ret; - - if (fdtdec_get_int_array(gd->fdt_blob, dev->of_offset, - "clock-freq-min-max", minmax, 2)) - return -EINVAL; - - fifo_depth = fdtdec_get_int(gd->fdt_blob, dev->of_offset, - "fifo-depth", 0); - if (fifo_depth < 0) - return -EINVAL; - +#endif host->fifoth_val = MSIZE(0x2) | - RX_WMARK(fifo_depth / 2 - 1) | TX_WMARK(fifo_depth / 2); + RX_WMARK(priv->fifo_depth / 2 - 1) | + TX_WMARK(priv->fifo_depth / 2); - if (fdtdec_get_bool(gd->fdt_blob, dev->of_offset, "fifo-mode")) - host->fifo_mode = true; + host->fifo_mode = priv->fifo_mode; #ifdef CONFIG_PWRSEQ /* Enable power if needed */ @@ -106,33 +129,24 @@ static int rockchip_dwmmc_probe(struct udevice *dev) return ret; } #endif -#ifdef CONFIG_BLK dwmci_setup_cfg(&plat->cfg, dev->name, host->buswidth, host->caps, - minmax[1], minmax[0]); + priv->minmax[1], priv->minmax[0]); host->mmc = &plat->mmc; -#else - ret = add_dwmci(host, minmax[1], minmax[0]); - if (ret) - return ret; - -#endif host->mmc->priv = &priv->host; host->mmc->dev = dev; upriv->mmc = host->mmc; - return 0; + return dwmci_probe(dev); } static int rockchip_dwmmc_bind(struct udevice *dev) { -#ifdef CONFIG_BLK struct rockchip_mmc_plat *plat = dev_get_platdata(dev); int ret; ret = dwmci_bind(dev, &plat->mmc, &plat->cfg); if (ret) return ret; -#endif return 0; } @@ -143,10 +157,11 @@ static const struct udevice_id rockchip_dwmmc_ids[] = { }; U_BOOT_DRIVER(rockchip_dwmmc_drv) = { - .name = "rockchip_dwmmc", + .name = "rockchip_rk3288_dw_mshc", .id = UCLASS_MMC, .of_match = rockchip_dwmmc_ids, .ofdata_to_platdata = rockchip_dwmmc_ofdata_to_platdata, + .ops = &dm_dwmci_ops, .bind = rockchip_dwmmc_bind, .probe = rockchip_dwmmc_probe, .priv_auto_alloc_size = sizeof(struct rockchip_dwmmc_priv), diff --git a/drivers/mmc/sandbox_mmc.c b/drivers/mmc/sandbox_mmc.c index 7da059c..5f1333b 100644 --- a/drivers/mmc/sandbox_mmc.c +++ b/drivers/mmc/sandbox_mmc.c @@ -25,7 +25,7 @@ struct sandbox_mmc_plat { * This emulate an SD card version 2. Single-block reads result in zero data. * Multiple-block reads return a test string. */ -static int sandbox_mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, +static int sandbox_mmc_send_cmd(struct udevice *dev, struct mmc_cmd *cmd, struct mmc_data *data) { switch (cmd->cmdidx) { @@ -85,25 +85,20 @@ static int sandbox_mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, return 0; } -static void sandbox_mmc_set_ios(struct mmc *mmc) -{ -} - -static int sandbox_mmc_init(struct mmc *mmc) +static int sandbox_mmc_set_ios(struct udevice *dev) { return 0; } -static int sandbox_mmc_getcd(struct mmc *mmc) +static int sandbox_mmc_get_cd(struct udevice *dev) { return 1; } -static const struct mmc_ops sandbox_mmc_ops = { +static const struct dm_mmc_ops sandbox_mmc_ops = { .send_cmd = sandbox_mmc_send_cmd, .set_ios = sandbox_mmc_set_ios, - .init = sandbox_mmc_init, - .getcd = sandbox_mmc_getcd, + .get_cd = sandbox_mmc_get_cd, }; int sandbox_mmc_probe(struct udevice *dev) @@ -120,7 +115,6 @@ int sandbox_mmc_bind(struct udevice *dev) int ret; cfg->name = dev->name; - cfg->ops = &sandbox_mmc_ops; cfg->host_caps = MMC_MODE_HS_52MHz | MMC_MODE_HS | MMC_MODE_8BIT; cfg->voltages = MMC_VDD_165_195 | MMC_VDD_32_33 | MMC_VDD_33_34; cfg->f_min = 1000000; @@ -150,6 +144,7 @@ U_BOOT_DRIVER(mmc_sandbox) = { .name = "mmc_sandbox", .id = UCLASS_MMC, .of_match = sandbox_mmc_ids, + .ops = &sandbox_mmc_ops, .bind = sandbox_mmc_bind, .unbind = sandbox_mmc_unbind, .probe = sandbox_mmc_probe, diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c index 604f18d..de8d8ea 100644 --- a/drivers/mmc/sdhci.c +++ b/drivers/mmc/sdhci.c @@ -9,6 +9,7 @@ */ #include <common.h> +#include <errno.h> #include <malloc.h> #include <mmc.h> #include <sdhci.h> @@ -129,9 +130,17 @@ static int sdhci_transfer_data(struct sdhci_host *host, struct mmc_data *data, #define CONFIG_SDHCI_CMD_DEFAULT_TIMEOUT 100 #define SDHCI_READ_STATUS_TIMEOUT 1000 +#ifdef CONFIG_DM_MMC_OPS +static int sdhci_send_command(struct udevice *dev, struct mmc_cmd *cmd, + struct mmc_data *data) +{ + struct mmc *mmc = mmc_get_mmc_dev(dev); + +#else static int sdhci_send_command(struct mmc *mmc, struct mmc_cmd *cmd, - struct mmc_data *data) + struct mmc_data *data) { +#endif struct sdhci_host *host = mmc->priv; unsigned int stat = 0; int ret = 0; @@ -389,8 +398,14 @@ static void sdhci_set_power(struct sdhci_host *host, unsigned short power) sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL); } +#ifdef CONFIG_DM_MMC_OPS +static int sdhci_set_ios(struct udevice *dev) +{ + struct mmc *mmc = mmc_get_mmc_dev(dev); +#else static void sdhci_set_ios(struct mmc *mmc) { +#endif u32 ctrl; struct sdhci_host *host = mmc->priv; @@ -426,6 +441,9 @@ static void sdhci_set_ios(struct mmc *mmc) ctrl &= ~SDHCI_CTRL_HISPD; sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL); +#ifdef CONFIG_DM_MMC_OPS + return 0; +#endif } static int sdhci_init(struct mmc *mmc) @@ -472,80 +490,110 @@ static int sdhci_init(struct mmc *mmc) return 0; } +#ifdef CONFIG_DM_MMC_OPS +int sdhci_probe(struct udevice *dev) +{ + struct mmc *mmc = mmc_get_mmc_dev(dev); + + return sdhci_init(mmc); +} +const struct dm_mmc_ops sdhci_ops = { + .send_cmd = sdhci_send_command, + .set_ios = sdhci_set_ios, +}; +#else static const struct mmc_ops sdhci_ops = { .send_cmd = sdhci_send_command, .set_ios = sdhci_set_ios, .init = sdhci_init, }; +#endif -int add_sdhci(struct sdhci_host *host, u32 max_clk, u32 min_clk) +int sdhci_setup_cfg(struct mmc_config *cfg, const char *name, int buswidth, + uint caps, u32 max_clk, u32 min_clk, uint version, + uint quirks, uint host_caps) { - unsigned int caps; - - host->cfg.name = host->name; - host->cfg.ops = &sdhci_ops; - - caps = sdhci_readl(host, SDHCI_CAPABILITIES); -#ifdef CONFIG_MMC_SDMA - if (!(caps & SDHCI_CAN_DO_SDMA)) { - printf("%s: Your controller doesn't support SDMA!!\n", - __func__); - return -1; - } + cfg->name = name; +#ifndef CONFIG_DM_MMC_OPS + cfg->ops = &sdhci_ops; #endif - if (max_clk) - host->cfg.f_max = max_clk; + cfg->f_max = max_clk; else { - if (SDHCI_GET_VERSION(host) >= SDHCI_SPEC_300) - host->cfg.f_max = (caps & SDHCI_CLOCK_V3_BASE_MASK) - >> SDHCI_CLOCK_BASE_SHIFT; + if (version >= SDHCI_SPEC_300) + cfg->f_max = (caps & SDHCI_CLOCK_V3_BASE_MASK) >> + SDHCI_CLOCK_BASE_SHIFT; else - host->cfg.f_max = (caps & SDHCI_CLOCK_BASE_MASK) - >> SDHCI_CLOCK_BASE_SHIFT; - host->cfg.f_max *= 1000000; - } - if (host->cfg.f_max == 0) { - printf("%s: Hardware doesn't specify base clock frequency\n", - __func__); - return -1; + cfg->f_max = (caps & SDHCI_CLOCK_BASE_MASK) >> + SDHCI_CLOCK_BASE_SHIFT; + cfg->f_max *= 1000000; } + if (cfg->f_max == 0) + return -EINVAL; if (min_clk) - host->cfg.f_min = min_clk; + cfg->f_min = min_clk; else { - if (SDHCI_GET_VERSION(host) >= SDHCI_SPEC_300) - host->cfg.f_min = host->cfg.f_max / - SDHCI_MAX_DIV_SPEC_300; + if (version >= SDHCI_SPEC_300) + cfg->f_min = cfg->f_max / SDHCI_MAX_DIV_SPEC_300; else - host->cfg.f_min = host->cfg.f_max / - SDHCI_MAX_DIV_SPEC_200; + cfg->f_min = cfg->f_max / SDHCI_MAX_DIV_SPEC_200; } - - host->cfg.voltages = 0; + cfg->voltages = 0; if (caps & SDHCI_CAN_VDD_330) - host->cfg.voltages |= MMC_VDD_32_33 | MMC_VDD_33_34; + cfg->voltages |= MMC_VDD_32_33 | MMC_VDD_33_34; if (caps & SDHCI_CAN_VDD_300) - host->cfg.voltages |= MMC_VDD_29_30 | MMC_VDD_30_31; + cfg->voltages |= MMC_VDD_29_30 | MMC_VDD_30_31; if (caps & SDHCI_CAN_VDD_180) - host->cfg.voltages |= MMC_VDD_165_195; + cfg->voltages |= MMC_VDD_165_195; - if (host->quirks & SDHCI_QUIRK_BROKEN_VOLTAGE) - host->cfg.voltages |= host->voltages; - - host->cfg.host_caps = MMC_MODE_HS | MMC_MODE_HS_52MHz | MMC_MODE_4BIT; - if (SDHCI_GET_VERSION(host) >= SDHCI_SPEC_300) { + cfg->host_caps = MMC_MODE_HS | MMC_MODE_HS_52MHz | MMC_MODE_4BIT; + if (version >= SDHCI_SPEC_300) { if (caps & SDHCI_CAN_DO_8BIT) - host->cfg.host_caps |= MMC_MODE_8BIT; + cfg->host_caps |= MMC_MODE_8BIT; } - if (host->quirks & SDHCI_QUIRK_NO_HISPD_BIT) - host->cfg.host_caps &= ~(MMC_MODE_HS | MMC_MODE_HS_52MHz); + if (quirks & SDHCI_QUIRK_NO_HISPD_BIT) + cfg->host_caps &= ~(MMC_MODE_HS | MMC_MODE_HS_52MHz); - if (host->host_caps) - host->cfg.host_caps |= host->host_caps; + if (host_caps) + cfg->host_caps |= host_caps; - host->cfg.b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT; + + cfg->b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT; + + return 0; +} + +#ifdef CONFIG_BLK +int sdhci_bind(struct udevice *dev, struct mmc *mmc, struct mmc_config *cfg) +{ + return mmc_bind(dev, mmc, cfg); +} +#else +int add_sdhci(struct sdhci_host *host, u32 max_clk, u32 min_clk) +{ + unsigned int caps; + + caps = sdhci_readl(host, SDHCI_CAPABILITIES); +#ifdef CONFIG_MMC_SDMA + if (!(caps & SDHCI_CAN_DO_SDMA)) { + printf("%s: Your controller doesn't support SDMA!!\n", + __func__); + return -1; + } +#endif + + if (sdhci_setup_cfg(&host->cfg, host->name, host->bus_width, caps, + max_clk, min_clk, SDHCI_GET_VERSION(host), + host->quirks, host->host_caps)) { + printf("%s: Hardware doesn't specify base clock frequency\n", + __func__); + return -EINVAL; + } + + if (host->quirks & SDHCI_QUIRK_BROKEN_VOLTAGE) + host->cfg.voltages |= host->voltages; sdhci_reset(host, SDHCI_RESET_ALL); @@ -557,3 +605,4 @@ int add_sdhci(struct sdhci_host *host, u32 max_clk, u32 min_clk) return 0; } +#endif |