summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/core/device.c11
-rw-r--r--drivers/dfu/dfu_mmc.c11
-rw-r--r--drivers/gpio/mpc85xx_gpio.c37
-rw-r--r--drivers/misc/cros_ec_sandbox.c11
-rw-r--r--drivers/mmc/Kconfig11
-rw-r--r--drivers/mmc/Makefile3
-rw-r--r--drivers/mmc/dw_mmc.c33
-rw-r--r--drivers/mmc/mmc-uclass.c146
-rw-r--r--drivers/mmc/mmc.c371
-rw-r--r--drivers/mmc/mmc_boot.c131
-rw-r--r--drivers/mmc/mmc_legacy.c91
-rw-r--r--drivers/mmc/mmc_private.h47
-rw-r--r--drivers/mmc/msm_sdhci.c35
-rw-r--r--drivers/mmc/rockchip_dw_mmc.c14
-rw-r--r--drivers/mmc/sandbox_mmc.c17
-rw-r--r--drivers/mmc/sdhci.c147
-rw-r--r--drivers/spi/cadence_qspi.c3
-rw-r--r--drivers/spi/cadence_qspi.h2
-rw-r--r--drivers/spi/cadence_qspi_apb.c15
-rw-r--r--drivers/spi/davinci_spi.c329
-rw-r--r--drivers/spi/spi-uclass.c10
21 files changed, 960 insertions, 515 deletions
diff --git a/drivers/core/device.c b/drivers/core/device.c
index eb75b1734f..f7fb0cc0fa 100644
--- a/drivers/core/device.c
+++ b/drivers/core/device.c
@@ -10,6 +10,7 @@
*/
#include <common.h>
+#include <asm/io.h>
#include <fdtdec.h>
#include <fdt_support.h>
#include <malloc.h>
@@ -697,6 +698,16 @@ void *dev_get_addr_ptr(struct udevice *dev)
return (void *)(uintptr_t)dev_get_addr_index(dev, 0);
}
+void *dev_map_physmem(struct udevice *dev, unsigned long size)
+{
+ fdt_addr_t addr = dev_get_addr(dev);
+
+ if (addr == FDT_ADDR_T_NONE)
+ return NULL;
+
+ return map_physmem(addr, size, MAP_NOCACHE);
+}
+
bool device_has_children(struct udevice *dev)
{
return !list_empty(&dev->child_head);
diff --git a/drivers/dfu/dfu_mmc.c b/drivers/dfu/dfu_mmc.c
index 78724e467b..926ccbd2ef 100644
--- a/drivers/dfu/dfu_mmc.c
+++ b/drivers/dfu/dfu_mmc.c
@@ -49,7 +49,7 @@ static int mmc_block_op(enum dfu_op op, struct dfu_entity *dfu,
}
if (dfu->data.mmc.hw_partition >= 0) {
- part_num_bkp = mmc->block_dev.hwpart;
+ part_num_bkp = mmc_get_blk_desc(mmc)->hwpart;
ret = blk_select_hwpart_devnum(IF_TYPE_MMC,
dfu->data.mmc.dev_num,
dfu->data.mmc.hw_partition);
@@ -62,12 +62,11 @@ static int mmc_block_op(enum dfu_op op, struct dfu_entity *dfu,
dfu->data.mmc.dev_num, blk_start, blk_count, buf);
switch (op) {
case DFU_OP_READ:
- n = mmc->block_dev.block_read(&mmc->block_dev, blk_start,
- blk_count, buf);
+ n = blk_dread(mmc_get_blk_desc(mmc), blk_start, blk_count, buf);
break;
case DFU_OP_WRITE:
- n = mmc->block_dev.block_write(&mmc->block_dev, blk_start,
- blk_count, buf);
+ n = blk_dwrite(mmc_get_blk_desc(mmc), blk_start, blk_count,
+ buf);
break;
default:
error("Operation not supported\n");
@@ -356,7 +355,7 @@ int dfu_fill_entity_mmc(struct dfu_entity *dfu, char *devstr, char *s)
} else if (!strcmp(entity_type, "part")) {
disk_partition_t partinfo;
- struct blk_desc *blk_dev = &mmc->block_dev;
+ struct blk_desc *blk_dev = mmc_get_blk_desc(mmc);
int mmcdev = second_arg;
int mmcpart = third_arg;
diff --git a/drivers/gpio/mpc85xx_gpio.c b/drivers/gpio/mpc85xx_gpio.c
index 04773e2b31..3754a8215c 100644
--- a/drivers/gpio/mpc85xx_gpio.c
+++ b/drivers/gpio/mpc85xx_gpio.c
@@ -163,23 +163,41 @@ static int mpc85xx_gpio_get_function(struct udevice *dev, unsigned gpio)
return dir ? GPIOF_OUTPUT : GPIOF_INPUT;
}
+#if CONFIG_IS_ENABLED(OF_CONTROL)
static int mpc85xx_gpio_ofdata_to_platdata(struct udevice *dev) {
- struct mpc85xx_gpio_data *data = dev_get_priv(dev);
+ struct mpc85xx_gpio_plat *plat = dev_get_platdata(dev);
fdt_addr_t addr;
fdt_size_t size;
addr = fdtdec_get_addr_size_auto_noparent(gd->fdt_blob, dev->of_offset,
"reg", 0, &size);
- data->addr = addr;
- data->base = map_sysmem(CONFIG_SYS_IMMR + addr, size);
+ plat->addr = addr;
+ plat->size = size;
+ plat->ngpios = fdtdec_get_int(gd->fdt_blob, dev->of_offset,
+ "ngpios", 32);
- if (!data->base)
+ return 0;
+}
+#endif
+
+static int mpc85xx_gpio_platdata_to_priv(struct udevice *dev)
+{
+ struct mpc85xx_gpio_data *priv = dev_get_priv(dev);
+ struct mpc85xx_gpio_plat *plat = dev_get_platdata(dev);
+ unsigned long size = plat->size;
+
+ if (size == 0)
+ size = 0x100;
+
+ priv->addr = plat->addr;
+ priv->base = map_sysmem(CONFIG_SYS_IMMR + plat->addr, size);
+
+ if (!priv->base)
return -ENOMEM;
- data->gpio_count = fdtdec_get_int(gd->fdt_blob, dev->of_offset,
- "ngpios", 32);
- data->dat_shadow = 0;
+ priv->gpio_count = plat->ngpios;
+ priv->dat_shadow = 0;
return 0;
}
@@ -190,6 +208,8 @@ static int mpc85xx_gpio_probe(struct udevice *dev)
struct mpc85xx_gpio_data *data = dev_get_priv(dev);
char name[32], *str;
+ mpc85xx_gpio_platdata_to_priv(dev);
+
snprintf(name, sizeof(name), "MPC@%lx_", data->addr);
str = strdup(name);
@@ -221,8 +241,11 @@ U_BOOT_DRIVER(gpio_mpc85xx) = {
.name = "gpio_mpc85xx",
.id = UCLASS_GPIO,
.ops = &gpio_mpc85xx_ops,
+#if CONFIG_IS_ENABLED(OF_CONTROL)
.ofdata_to_platdata = mpc85xx_gpio_ofdata_to_platdata,
+ .platdata_auto_alloc_size = sizeof(struct mpc85xx_gpio_plat),
.of_match = mpc85xx_gpio_ids,
+#endif
.probe = mpc85xx_gpio_probe,
.priv_auto_alloc_size = sizeof(struct mpc85xx_gpio_data),
};
diff --git a/drivers/misc/cros_ec_sandbox.c b/drivers/misc/cros_ec_sandbox.c
index 98f19a68bf..c4fbca0d3a 100644
--- a/drivers/misc/cros_ec_sandbox.c
+++ b/drivers/misc/cros_ec_sandbox.c
@@ -517,6 +517,7 @@ int cros_ec_probe(struct udevice *dev)
struct ec_state *ec = dev->priv;
struct cros_ec_dev *cdev = dev->uclass_priv;
const void *blob = gd->fdt_blob;
+ struct udevice *keyb_dev;
int node;
int err;
@@ -525,7 +526,15 @@ int cros_ec_probe(struct udevice *dev)
if (err)
return err;
- node = fdtdec_next_compatible(blob, 0, COMPAT_GOOGLE_CROS_EC_KEYB);
+ node = -1;
+ for (device_find_first_child(dev, &keyb_dev);
+ keyb_dev;
+ device_find_next_child(&keyb_dev)) {
+ if (device_get_uclass_id(keyb_dev) == UCLASS_KEYBOARD) {
+ node = keyb_dev->of_offset;
+ break;
+ }
+ }
if (node < 0) {
debug("%s: No cros_ec keyboard found\n", __func__);
} else if (keyscan_read_fdt_matrix(ec, blob, node)) {
diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig
index c80efc39a7..79cf18f14f 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 3da4817a18..b44a12e606 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 af6e04aa28..2cf7bae792 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 1b967d982b..38ced4102e 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 aabfc711e5..f8e5f7a608 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 0000000000..756a9824e3
--- /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 3ec649f2b8..040728b45d 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 9f0d5c2384..49ec022a9e 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 96dcdbec51..70a8d96eee 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 d41d60ce35..691a51557d 100644
--- a/drivers/mmc/rockchip_dw_mmc.c
+++ b/drivers/mmc/rockchip_dw_mmc.c
@@ -66,9 +66,7 @@ static int rockchip_dwmmc_ofdata_to_platdata(struct udevice *dev)
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;
@@ -106,33 +104,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]);
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;
}
@@ -147,6 +136,7 @@ U_BOOT_DRIVER(rockchip_dwmmc_drv) = {
.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 7da059c43c..5f1333b748 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 604f18dcc9..de8d8ea70c 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
diff --git a/drivers/spi/cadence_qspi.c b/drivers/spi/cadence_qspi.c
index 4f7fd52532..a5244fff4d 100644
--- a/drivers/spi/cadence_qspi.c
+++ b/drivers/spi/cadence_qspi.c
@@ -191,6 +191,7 @@ static int cadence_spi_xfer(struct udevice *dev, unsigned int bitlen,
struct udevice *bus = dev->parent;
struct cadence_spi_platdata *plat = bus->platdata;
struct cadence_spi_priv *priv = dev_get_priv(bus);
+ struct dm_spi_slave_platdata *dm_plat = dev_get_parent_platdata(dev);
void *base = priv->regbase;
u8 *cmd_buf = priv->cmd_buf;
size_t data_bytes;
@@ -250,7 +251,7 @@ static int cadence_spi_xfer(struct udevice *dev, unsigned int bitlen,
break;
case CQSPI_INDIRECT_READ:
err = cadence_qspi_apb_indirect_read_setup(plat,
- priv->cmd_len, cmd_buf);
+ priv->cmd_len, dm_plat->mode_rx, cmd_buf);
if (!err) {
err = cadence_qspi_apb_indirect_read_execute
(plat, data_bytes, din);
diff --git a/drivers/spi/cadence_qspi.h b/drivers/spi/cadence_qspi.h
index 2912e36a53..a849f7b199 100644
--- a/drivers/spi/cadence_qspi.h
+++ b/drivers/spi/cadence_qspi.h
@@ -53,7 +53,7 @@ int cadence_qspi_apb_command_write(void *reg_base_addr,
unsigned int txlen, const u8 *txbuf);
int cadence_qspi_apb_indirect_read_setup(struct cadence_spi_platdata *plat,
- unsigned int cmdlen, const u8 *cmdbuf);
+ unsigned int cmdlen, unsigned int rx_width, const u8 *cmdbuf);
int cadence_qspi_apb_indirect_read_execute(struct cadence_spi_platdata *plat,
unsigned int rxlen, u8 *rxbuf);
int cadence_qspi_apb_indirect_write_setup(struct cadence_spi_platdata *plat,
diff --git a/drivers/spi/cadence_qspi_apb.c b/drivers/spi/cadence_qspi_apb.c
index a71531d309..1a35d558a6 100644
--- a/drivers/spi/cadence_qspi_apb.c
+++ b/drivers/spi/cadence_qspi_apb.c
@@ -29,6 +29,7 @@
#include <asm/io.h>
#include <asm/errno.h>
#include <wait_bit.h>
+#include <spi.h>
#include "cadence_qspi.h"
#define CQSPI_REG_POLL_US (1) /* 1us */
@@ -45,7 +46,6 @@
#define CQSPI_INST_TYPE_QUAD (2)
#define CQSPI_STIG_DATA_LEN_MAX (8)
-#define CQSPI_INDIRECTTRIGGER_ADDR_MASK (0xFFFFF)
#define CQSPI_DUMMY_CLKS_PER_BYTE (8)
#define CQSPI_DUMMY_BYTES_MAX (4)
@@ -549,7 +549,7 @@ int cadence_qspi_apb_command_write(void *reg_base, unsigned int cmdlen,
/* Opcode + Address (3/4 bytes) + dummy bytes (0-4 bytes) */
int cadence_qspi_apb_indirect_read_setup(struct cadence_spi_platdata *plat,
- unsigned int cmdlen, const u8 *cmdbuf)
+ unsigned int cmdlen, unsigned int rx_width, const u8 *cmdbuf)
{
unsigned int reg;
unsigned int rd_reg;
@@ -573,16 +573,15 @@ int cadence_qspi_apb_indirect_read_setup(struct cadence_spi_platdata *plat,
addr_bytes = cmdlen - 1;
/* Setup the indirect trigger address */
- writel(((u32)plat->ahbbase & CQSPI_INDIRECTTRIGGER_ADDR_MASK),
+ writel((u32)plat->ahbbase,
plat->regbase + CQSPI_REG_INDIRECTTRIGGER);
/* Configure the opcode */
rd_reg = cmdbuf[0] << CQSPI_REG_RD_INSTR_OPCODE_LSB;
-#if (CONFIG_SPI_FLASH_QUAD == 1)
- /* Instruction and address at DQ0, data at DQ0-3. */
- rd_reg |= CQSPI_INST_TYPE_QUAD << CQSPI_REG_RD_INSTR_TYPE_DATA_LSB;
-#endif
+ if (rx_width & SPI_RX_QUAD)
+ /* Instruction and address at DQ0, data at DQ0-3. */
+ rd_reg |= CQSPI_INST_TYPE_QUAD << CQSPI_REG_RD_INSTR_TYPE_DATA_LSB;
/* Get address */
addr_value = cadence_qspi_apb_cmd2addr(&cmdbuf[1], addr_bytes);
@@ -714,7 +713,7 @@ int cadence_qspi_apb_indirect_write_setup(struct cadence_spi_platdata *plat,
return -EINVAL;
}
/* Setup the indirect trigger address */
- writel(((u32)plat->ahbbase & CQSPI_INDIRECTTRIGGER_ADDR_MASK),
+ writel((u32)plat->ahbbase,
plat->regbase + CQSPI_REG_INDIRECTTRIGGER);
/* Configure the opcode */
diff --git a/drivers/spi/davinci_spi.c b/drivers/spi/davinci_spi.c
index 0bd4f88926..20aa99a451 100644
--- a/drivers/spi/davinci_spi.c
+++ b/drivers/spi/davinci_spi.c
@@ -14,6 +14,7 @@
#include <malloc.h>
#include <asm/io.h>
#include <asm/arch/hardware.h>
+#include <dm.h>
/* SPIGCR0 */
#define SPIGCR0_SPIENA_MASK 0x1
@@ -51,6 +52,7 @@
/* SPIDEF */
#define SPIDEF_CSDEF0_MASK BIT(0)
+#ifndef CONFIG_DM_SPI
#define SPI0_BUS 0
#define SPI0_BASE CONFIG_SYS_SPI_BASE
/*
@@ -83,6 +85,9 @@
#define SPI2_NUM_CS CONFIG_SYS_SPI2_NUM_CS
#define SPI2_BASE CONFIG_SYS_SPI2_BASE
#endif
+#endif
+
+DECLARE_GLOBAL_DATA_PTR;
/* davinci spi register set */
struct davinci_spi_regs {
@@ -114,16 +119,17 @@ struct davinci_spi_regs {
/* davinci spi slave */
struct davinci_spi_slave {
+#ifndef CONFIG_DM_SPI
struct spi_slave slave;
+#endif
struct davinci_spi_regs *regs;
- unsigned int freq;
+ unsigned int freq; /* current SPI bus frequency */
+ unsigned int mode; /* current SPI mode used */
+ u8 num_cs; /* total no. of CS available */
+ u8 cur_cs; /* CS of current slave */
+ bool half_duplex; /* true, if master is half-duplex only */
};
-static inline struct davinci_spi_slave *to_davinci_spi(struct spi_slave *slave)
-{
- return container_of(slave, struct davinci_spi_slave, slave);
-}
-
/*
* This functions needs to act like a macro to avoid pipeline reloads in the
* loops below. Use always_inline. This gains us about 160KiB/s and the bloat
@@ -144,15 +150,14 @@ static inline u32 davinci_spi_xfer_data(struct davinci_spi_slave *ds, u32 data)
return buf_reg_val;
}
-static int davinci_spi_read(struct spi_slave *slave, unsigned int len,
+static int davinci_spi_read(struct davinci_spi_slave *ds, unsigned int len,
u8 *rxp, unsigned long flags)
{
- struct davinci_spi_slave *ds = to_davinci_spi(slave);
unsigned int data1_reg_val;
/* enable CS hold, CS[n] and clear the data bits */
data1_reg_val = ((1 << SPIDAT1_CSHOLD_SHIFT) |
- (slave->cs << SPIDAT1_CSNR_SHIFT));
+ (ds->cur_cs << SPIDAT1_CSNR_SHIFT));
/* wait till TXFULL is deasserted */
while (readl(&ds->regs->buf) & SPIBUF_TXFULL_MASK)
@@ -175,15 +180,14 @@ static int davinci_spi_read(struct spi_slave *slave, unsigned int len,
return 0;
}
-static int davinci_spi_write(struct spi_slave *slave, unsigned int len,
+static int davinci_spi_write(struct davinci_spi_slave *ds, unsigned int len,
const u8 *txp, unsigned long flags)
{
- struct davinci_spi_slave *ds = to_davinci_spi(slave);
unsigned int data1_reg_val;
/* enable CS hold and clear the data bits */
data1_reg_val = ((1 << SPIDAT1_CSHOLD_SHIFT) |
- (slave->cs << SPIDAT1_CSNR_SHIFT));
+ (ds->cur_cs << SPIDAT1_CSNR_SHIFT));
/* wait till TXFULL is deasserted */
while (readl(&ds->regs->buf) & SPIBUF_TXFULL_MASK)
@@ -209,16 +213,15 @@ static int davinci_spi_write(struct spi_slave *slave, unsigned int len,
return 0;
}
-#ifndef CONFIG_SPI_HALF_DUPLEX
-static int davinci_spi_read_write(struct spi_slave *slave, unsigned int len,
- u8 *rxp, const u8 *txp, unsigned long flags)
+static int davinci_spi_read_write(struct davinci_spi_slave *ds, unsigned
+ int len, u8 *rxp, const u8 *txp,
+ unsigned long flags)
{
- struct davinci_spi_slave *ds = to_davinci_spi(slave);
unsigned int data1_reg_val;
/* enable CS hold and clear the data bits */
data1_reg_val = ((1 << SPIDAT1_CSHOLD_SHIFT) |
- (slave->cs << SPIDAT1_CSNR_SHIFT));
+ (ds->cur_cs << SPIDAT1_CSNR_SHIFT));
/* wait till TXFULL is deasserted */
while (readl(&ds->regs->buf) & SPIBUF_TXFULL_MASK)
@@ -237,7 +240,115 @@ static int davinci_spi_read_write(struct spi_slave *slave, unsigned int len,
return 0;
}
-#endif
+
+
+static int __davinci_spi_claim_bus(struct davinci_spi_slave *ds, int cs)
+{
+ unsigned int mode = 0, scalar;
+
+ /* Enable the SPI hardware */
+ writel(SPIGCR0_SPIRST_MASK, &ds->regs->gcr0);
+ udelay(1000);
+ writel(SPIGCR0_SPIENA_MASK, &ds->regs->gcr0);
+
+ /* Set master mode, powered up and not activated */
+ writel(SPIGCR1_MASTER_MASK | SPIGCR1_CLKMOD_MASK, &ds->regs->gcr1);
+
+ /* CS, CLK, SIMO and SOMI are functional pins */
+ writel(((1 << cs) | SPIPC0_CLKFUN_MASK |
+ SPIPC0_DOFUN_MASK | SPIPC0_DIFUN_MASK), &ds->regs->pc0);
+
+ /* setup format */
+ scalar = ((CONFIG_SYS_SPI_CLK / ds->freq) - 1) & 0xFF;
+
+ /*
+ * Use following format:
+ * character length = 8,
+ * MSB shifted out first
+ */
+ if (ds->mode & SPI_CPOL)
+ mode |= SPI_CPOL;
+ if (!(ds->mode & SPI_CPHA))
+ mode |= SPI_CPHA;
+ writel(8 | (scalar << SPIFMT_PRESCALE_SHIFT) |
+ (mode << SPIFMT_PHASE_SHIFT), &ds->regs->fmt0);
+
+ /*
+ * Including a minor delay. No science here. Should be good even with
+ * no delay
+ */
+ writel((50 << SPI_C2TDELAY_SHIFT) |
+ (50 << SPI_T2CDELAY_SHIFT), &ds->regs->delay);
+
+ /* default chip select register */
+ writel(SPIDEF_CSDEF0_MASK, &ds->regs->def);
+
+ /* no interrupts */
+ writel(0, &ds->regs->int0);
+ writel(0, &ds->regs->lvl);
+
+ /* enable SPI */
+ writel((readl(&ds->regs->gcr1) | SPIGCR1_SPIENA_MASK), &ds->regs->gcr1);
+
+ return 0;
+}
+
+static int __davinci_spi_release_bus(struct davinci_spi_slave *ds)
+{
+ /* Disable the SPI hardware */
+ writel(SPIGCR0_SPIRST_MASK, &ds->regs->gcr0);
+
+ return 0;
+}
+
+static int __davinci_spi_xfer(struct davinci_spi_slave *ds,
+ unsigned int bitlen, const void *dout, void *din,
+ unsigned long flags)
+{
+ unsigned int len;
+
+ if (bitlen == 0)
+ /* Finish any previously submitted transfers */
+ goto out;
+
+ /*
+ * It's not clear how non-8-bit-aligned transfers are supposed to be
+ * represented as a stream of bytes...this is a limitation of
+ * the current SPI interface - here we terminate on receiving such a
+ * transfer request.
+ */
+ if (bitlen % 8) {
+ /* Errors always terminate an ongoing transfer */
+ flags |= SPI_XFER_END;
+ goto out;
+ }
+
+ len = bitlen / 8;
+
+ if (!dout)
+ return davinci_spi_read(ds, len, din, flags);
+ if (!din)
+ return davinci_spi_write(ds, len, dout, flags);
+ if (!ds->half_duplex)
+ return davinci_spi_read_write(ds, len, din, dout, flags);
+
+ printf("SPI full duplex not supported\n");
+ flags |= SPI_XFER_END;
+
+out:
+ if (flags & SPI_XFER_END) {
+ u8 dummy = 0;
+ davinci_spi_write(ds, 1, &dummy, flags);
+ }
+ return 0;
+}
+
+#ifndef CONFIG_DM_SPI
+
+static inline struct davinci_spi_slave *to_davinci_spi(struct spi_slave *slave)
+{
+ return container_of(slave, struct davinci_spi_slave, slave);
+}
int spi_cs_is_valid(unsigned int bus, unsigned int cs)
{
@@ -313,6 +424,7 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
}
ds->freq = max_hz;
+ ds->mode = mode;
return &ds->slave;
}
@@ -324,104 +436,143 @@ void spi_free_slave(struct spi_slave *slave)
free(ds);
}
+int spi_xfer(struct spi_slave *slave, unsigned int bitlen,
+ const void *dout, void *din, unsigned long flags)
+{
+ struct davinci_spi_slave *ds = to_davinci_spi(slave);
+
+ ds->cur_cs = slave->cs;
+
+ return __davinci_spi_xfer(ds, bitlen, dout, din, flags);
+}
+
int spi_claim_bus(struct spi_slave *slave)
{
struct davinci_spi_slave *ds = to_davinci_spi(slave);
- unsigned int scalar;
- /* Enable the SPI hardware */
- writel(SPIGCR0_SPIRST_MASK, &ds->regs->gcr0);
- udelay(1000);
- writel(SPIGCR0_SPIENA_MASK, &ds->regs->gcr0);
+#ifdef CONFIG_SPI_HALF_DUPLEX
+ ds->half_duplex = true;
+#else
+ ds->half_duplex = false;
+#endif
+ return __davinci_spi_claim_bus(ds, ds->slave.cs);
+}
- /* Set master mode, powered up and not activated */
- writel(SPIGCR1_MASTER_MASK | SPIGCR1_CLKMOD_MASK, &ds->regs->gcr1);
+void spi_release_bus(struct spi_slave *slave)
+{
+ struct davinci_spi_slave *ds = to_davinci_spi(slave);
- /* CS, CLK, SIMO and SOMI are functional pins */
- writel(((1 << slave->cs) | SPIPC0_CLKFUN_MASK |
- SPIPC0_DOFUN_MASK | SPIPC0_DIFUN_MASK), &ds->regs->pc0);
+ __davinci_spi_release_bus(ds);
+}
- /* setup format */
- scalar = ((CONFIG_SYS_SPI_CLK / ds->freq) - 1) & 0xFF;
+#else
+static int davinci_spi_set_speed(struct udevice *bus, uint max_hz)
+{
+ struct davinci_spi_slave *ds = dev_get_priv(bus);
- /*
- * Use following format:
- * character length = 8,
- * clock signal delayed by half clk cycle,
- * clock low in idle state - Mode 0,
- * MSB shifted out first
- */
- writel(8 | (scalar << SPIFMT_PRESCALE_SHIFT) |
- (1 << SPIFMT_PHASE_SHIFT), &ds->regs->fmt0);
+ debug("%s speed %u\n", __func__, max_hz);
+ if (max_hz > CONFIG_SYS_SPI_CLK / 2)
+ return -EINVAL;
- /*
- * Including a minor delay. No science here. Should be good even with
- * no delay
- */
- writel((50 << SPI_C2TDELAY_SHIFT) |
- (50 << SPI_T2CDELAY_SHIFT), &ds->regs->delay);
+ ds->freq = max_hz;
- /* default chip select register */
- writel(SPIDEF_CSDEF0_MASK, &ds->regs->def);
+ return 0;
+}
- /* no interrupts */
- writel(0, &ds->regs->int0);
- writel(0, &ds->regs->lvl);
+static int davinci_spi_set_mode(struct udevice *bus, uint mode)
+{
+ struct davinci_spi_slave *ds = dev_get_priv(bus);
- /* enable SPI */
- writel((readl(&ds->regs->gcr1) | SPIGCR1_SPIENA_MASK), &ds->regs->gcr1);
+ debug("%s mode %u\n", __func__, mode);
+ ds->mode = mode;
return 0;
}
-void spi_release_bus(struct spi_slave *slave)
+static int davinci_spi_claim_bus(struct udevice *dev)
{
- struct davinci_spi_slave *ds = to_davinci_spi(slave);
+ struct dm_spi_slave_platdata *slave_plat =
+ dev_get_parent_platdata(dev);
+ struct udevice *bus = dev->parent;
+ struct davinci_spi_slave *ds = dev_get_priv(bus);
+
+ if (slave_plat->cs >= ds->num_cs) {
+ printf("Invalid SPI chipselect\n");
+ return -EINVAL;
+ }
+ ds->half_duplex = slave_plat->mode & SPI_PREAMBLE;
- /* Disable the SPI hardware */
- writel(SPIGCR0_SPIRST_MASK, &ds->regs->gcr0);
+ return __davinci_spi_claim_bus(ds, slave_plat->cs);
}
-int spi_xfer(struct spi_slave *slave, unsigned int bitlen,
- const void *dout, void *din, unsigned long flags)
+static int davinci_spi_release_bus(struct udevice *dev)
{
- unsigned int len;
+ struct davinci_spi_slave *ds = dev_get_priv(dev->parent);
- if (bitlen == 0)
- /* Finish any previously submitted transfers */
- goto out;
+ return __davinci_spi_release_bus(ds);
+}
- /*
- * It's not clear how non-8-bit-aligned transfers are supposed to be
- * represented as a stream of bytes...this is a limitation of
- * the current SPI interface - here we terminate on receiving such a
- * transfer request.
- */
- if (bitlen % 8) {
- /* Errors always terminate an ongoing transfer */
- flags |= SPI_XFER_END;
- goto out;
+static int davinci_spi_xfer(struct udevice *dev, unsigned int bitlen,
+ const void *dout, void *din,
+ unsigned long flags)
+{
+ struct dm_spi_slave_platdata *slave =
+ dev_get_parent_platdata(dev);
+ struct udevice *bus = dev->parent;
+ struct davinci_spi_slave *ds = dev_get_priv(bus);
+
+ if (slave->cs >= ds->num_cs) {
+ printf("Invalid SPI chipselect\n");
+ return -EINVAL;
}
+ ds->cur_cs = slave->cs;
- len = bitlen / 8;
+ return __davinci_spi_xfer(ds, bitlen, dout, din, flags);
+}
- if (!dout)
- return davinci_spi_read(slave, len, din, flags);
- else if (!din)
- return davinci_spi_write(slave, len, dout, flags);
-#ifndef CONFIG_SPI_HALF_DUPLEX
- else
- return davinci_spi_read_write(slave, len, din, dout, flags);
-#else
- printf("SPI full duplex transaction requested with "
- "CONFIG_SPI_HALF_DUPLEX defined.\n");
- flags |= SPI_XFER_END;
-#endif
+static int davinci_spi_probe(struct udevice *bus)
+{
+ /* Nothing to do */
+ return 0;
+}
-out:
- if (flags & SPI_XFER_END) {
- u8 dummy = 0;
- davinci_spi_write(slave, 1, &dummy, flags);
+static int davinci_ofdata_to_platadata(struct udevice *bus)
+{
+ struct davinci_spi_slave *ds = dev_get_priv(bus);
+ const void *blob = gd->fdt_blob;
+ int node = bus->of_offset;
+
+ ds->regs = dev_map_physmem(bus, sizeof(struct davinci_spi_regs));
+ if (!ds->regs) {
+ printf("%s: could not map device address\n", __func__);
+ return -EINVAL;
}
+ ds->num_cs = fdtdec_get_int(blob, node, "num-cs", 4);
+
return 0;
}
+
+static const struct dm_spi_ops davinci_spi_ops = {
+ .claim_bus = davinci_spi_claim_bus,
+ .release_bus = davinci_spi_release_bus,
+ .xfer = davinci_spi_xfer,
+ .set_speed = davinci_spi_set_speed,
+ .set_mode = davinci_spi_set_mode,
+};
+
+static const struct udevice_id davinci_spi_ids[] = {
+ { .compatible = "ti,keystone-spi" },
+ { .compatible = "ti,dm6441-spi" },
+ { }
+};
+
+U_BOOT_DRIVER(davinci_spi) = {
+ .name = "davinci_spi",
+ .id = UCLASS_SPI,
+ .of_match = davinci_spi_ids,
+ .ops = &davinci_spi_ops,
+ .ofdata_to_platdata = davinci_ofdata_to_platadata,
+ .priv_auto_alloc_size = sizeof(struct davinci_spi_slave),
+ .probe = davinci_spi_probe,
+};
+#endif
diff --git a/drivers/spi/spi-uclass.c b/drivers/spi/spi-uclass.c
index 84b6786517..8003f9bfc8 100644
--- a/drivers/spi/spi-uclass.c
+++ b/drivers/spi/spi-uclass.c
@@ -278,6 +278,7 @@ int spi_get_bus_and_cs(int busnum, int cs, int speed, int mode,
struct udevice **busp, struct spi_slave **devp)
{
struct udevice *bus, *dev;
+ struct dm_spi_slave_platdata *plat;
bool created = false;
int ret;
@@ -294,8 +295,6 @@ int spi_get_bus_and_cs(int busnum, int cs, int speed, int mode,
* SPI flash chip - we will bind to the correct driver.
*/
if (ret == -ENODEV && drv_name) {
- struct dm_spi_slave_platdata *plat;
-
debug("%s: Binding new device '%s', busnum=%d, cs=%d, driver=%s\n",
__func__, dev_name, busnum, cs, drv_name);
ret = device_bind_driver(bus, drv_name, dev_name, &dev);
@@ -322,6 +321,11 @@ int spi_get_bus_and_cs(int busnum, int cs, int speed, int mode,
slave->dev = dev;
}
+ plat = dev_get_parent_platdata(dev);
+ if (!speed) {
+ speed = plat->max_hz;
+ mode = plat->mode;
+ }
ret = spi_set_speed_mode(bus, speed, mode);
if (ret)
goto err;
@@ -333,7 +337,7 @@ int spi_get_bus_and_cs(int busnum, int cs, int speed, int mode,
return 0;
err:
- debug("%s: Error path, credted=%d, device '%s'\n", __func__,
+ debug("%s: Error path, created=%d, device '%s'\n", __func__,
created, dev->name);
if (created) {
device_remove(dev);