summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/bios_emulator/x86emu/sys.c2
-rw-r--r--drivers/clk/clk-uclass.c22
-rw-r--r--drivers/clk/clk_fixed_rate.c2
-rw-r--r--drivers/clk/clk_rk3288.c33
-rw-r--r--drivers/core/device-remove.c2
-rw-r--r--drivers/core/device.c58
-rw-r--r--drivers/core/lists.c2
-rw-r--r--drivers/core/regmap.c57
-rw-r--r--drivers/core/root.c4
-rw-r--r--drivers/core/syscon-uclass.c13
-rw-r--r--drivers/crypto/fsl/desc.h2
-rw-r--r--drivers/ddr/fsl/ctrl_regs.c2
-rw-r--r--drivers/dfu/dfu_mmc.c11
-rw-r--r--drivers/fpga/fpga.c2
-rw-r--r--drivers/gpio/mpc85xx_gpio.c37
-rw-r--r--drivers/misc/Makefile7
-rw-r--r--drivers/misc/cros_ec_sandbox.c11
-rw-r--r--drivers/misc/spltest_sandbox.c53
-rw-r--r--drivers/mmc/Kconfig13
-rw-r--r--drivers/mmc/Makefile3
-rw-r--r--drivers/mmc/dw_mmc.c33
-rw-r--r--drivers/mmc/exynos_dw_mmc.c148
-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.c73
-rw-r--r--drivers/mmc/sandbox_mmc.c17
-rw-r--r--drivers/mmc/sdhci.c147
-rw-r--r--drivers/mmc/sunxi_mmc.c27
-rw-r--r--drivers/mtd/cfi_flash.c2
-rw-r--r--drivers/mtd/nand/mxs_nand.c2
-rw-r--r--drivers/mtd/nand/tegra_nand.c2
-rw-r--r--drivers/mtd/spi/Kconfig12
-rw-r--r--drivers/mtd/spi/Makefile1
-rw-r--r--drivers/mtd/spi/sunxi_spi_spl.c283
-rw-r--r--drivers/net/Kconfig9
-rw-r--r--drivers/net/Makefile1
-rw-r--r--drivers/net/sun8i_emac.c789
-rw-r--r--drivers/pci/pci_rom.c11
-rw-r--r--drivers/pinctrl/rockchip/pinctrl_rk3288.c8
-rw-r--r--drivers/rtc/date.c71
-rw-r--r--drivers/serial/Kconfig9
-rw-r--r--drivers/serial/Makefile3
-rw-r--r--drivers/serial/ns16550.c4
-rw-r--r--drivers/serial/sandbox.c2
-rw-r--r--drivers/serial/serial-uclass.c8
-rw-r--r--drivers/serial/serial_rockchip.c43
-rw-r--r--drivers/serial/serial_stm32x7.c16
-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
-rw-r--r--drivers/usb/musb-new/musb_dsps.c2
-rw-r--r--drivers/video/tegra.c2
58 files changed, 2529 insertions, 712 deletions
diff --git a/drivers/bios_emulator/x86emu/sys.c b/drivers/bios_emulator/x86emu/sys.c
index 0ba9c0c105..c2db1213fe 100644
--- a/drivers/bios_emulator/x86emu/sys.c
+++ b/drivers/bios_emulator/x86emu/sys.c
@@ -35,7 +35,7 @@
* Description: This file includes subroutines which are related to
* programmed I/O and memory access. Included in this module
* are default functions that do nothing. For real uses these
-* functions will have to be overriden by the user library.
+* functions will have to be overridden by the user library.
*
****************************************************************************/
diff --git a/drivers/clk/clk-uclass.c b/drivers/clk/clk-uclass.c
index 6e4d67220a..e0f85677e3 100644
--- a/drivers/clk/clk-uclass.c
+++ b/drivers/clk/clk-uclass.c
@@ -10,6 +10,7 @@
#include <clk.h>
#include <clk-uclass.h>
#include <dm.h>
+#include <dt-structs.h>
#include <errno.h>
DECLARE_GLOBAL_DATA_PTR;
@@ -21,6 +22,22 @@ static inline struct clk_ops *clk_dev_ops(struct udevice *dev)
#if CONFIG_IS_ENABLED(OF_CONTROL)
#ifdef CONFIG_SPL_BUILD
+# if CONFIG_IS_ENABLED(OF_PLATDATA)
+int clk_get_by_index_platdata(struct udevice *dev, int index,
+ struct phandle_2_cell *cells, struct clk *clk)
+{
+ int ret;
+
+ if (index != 0)
+ return -ENOSYS;
+ ret = uclass_get_device(UCLASS_CLK, 0, &clk->dev);
+ if (ret)
+ return ret;
+ clk->id = cells[0].id;
+
+ return 0;
+}
+# else
int clk_get_by_index(struct udevice *dev, int index, struct clk *clk)
{
int ret;
@@ -39,6 +56,7 @@ int clk_get_by_index(struct udevice *dev, int index, struct clk *clk)
clk->id = cell[1];
return 0;
}
+# endif /* OF_PLATDATA */
int clk_get_by_name(struct udevice *dev, const char *name, struct clk *clk)
{
@@ -117,8 +135,8 @@ int clk_get_by_name(struct udevice *dev, const char *name, struct clk *clk)
return clk_get_by_index(dev, index, clk);
}
-#endif
-#endif
+#endif /* CONFIG_SPL_BUILD */
+#endif /* OF_CONTROL */
int clk_request(struct udevice *dev, struct clk *clk)
{
diff --git a/drivers/clk/clk_fixed_rate.c b/drivers/clk/clk_fixed_rate.c
index 797e537907..9c4d2b322f 100644
--- a/drivers/clk/clk_fixed_rate.c
+++ b/drivers/clk/clk_fixed_rate.c
@@ -30,9 +30,11 @@ const struct clk_ops clk_fixed_rate_ops = {
static int clk_fixed_rate_ofdata_to_platdata(struct udevice *dev)
{
+#if !CONFIG_IS_ENABLED(OF_PLATDATA)
to_clk_fixed_rate(dev)->fixed_rate =
fdtdec_get_int(gd->fdt_blob, dev->of_offset,
"clock-frequency", 0);
+#endif
return 0;
}
diff --git a/drivers/clk/clk_rk3288.c b/drivers/clk/clk_rk3288.c
index 2285453e8d..679f010bb7 100644
--- a/drivers/clk/clk_rk3288.c
+++ b/drivers/clk/clk_rk3288.c
@@ -7,7 +7,9 @@
#include <common.h>
#include <clk-uclass.h>
#include <dm.h>
+#include <dt-structs.h>
#include <errno.h>
+#include <mapmem.h>
#include <syscon.h>
#include <asm/io.h>
#include <asm/arch/clock.h>
@@ -21,6 +23,12 @@
DECLARE_GLOBAL_DATA_PTR;
+struct rk3288_clk_plat {
+#if CONFIG_IS_ENABLED(OF_PLATDATA)
+ struct dtd_rockchip_rk3288_cru dtd;
+#endif
+};
+
struct rk3288_clk_priv {
struct rk3288_grf *grf;
struct rk3288_cru *cru;
@@ -783,13 +791,30 @@ static struct clk_ops rk3288_clk_ops = {
.set_rate = rk3288_clk_set_rate,
};
-static int rk3288_clk_probe(struct udevice *dev)
+static int rk3288_clk_ofdata_to_platdata(struct udevice *dev)
{
+#if !CONFIG_IS_ENABLED(OF_PLATDATA)
struct rk3288_clk_priv *priv = dev_get_priv(dev);
priv->cru = (struct rk3288_cru *)dev_get_addr(dev);
+#endif
+
+ return 0;
+}
+
+static int rk3288_clk_probe(struct udevice *dev)
+{
+ struct rk3288_clk_priv *priv = dev_get_priv(dev);
+
priv->grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF);
+ if (IS_ERR(priv->grf))
+ return PTR_ERR(priv->grf);
#ifdef CONFIG_SPL_BUILD
+#if CONFIG_IS_ENABLED(OF_PLATDATA)
+ struct rk3288_clk_plat *plat = dev_get_platdata(dev);
+
+ priv->cru = map_sysmem(plat->dtd.reg[0], plat->dtd.reg[1]);
+#endif
rkclk_init(priv->cru, priv->grf);
#endif
@@ -813,12 +838,14 @@ static const struct udevice_id rk3288_clk_ids[] = {
{ }
};
-U_BOOT_DRIVER(clk_rk3288) = {
- .name = "clk_rk3288",
+U_BOOT_DRIVER(rockchip_rk3288_cru) = {
+ .name = "rockchip_rk3288_cru",
.id = UCLASS_CLK,
.of_match = rk3288_clk_ids,
.priv_auto_alloc_size = sizeof(struct rk3288_clk_priv),
+ .platdata_auto_alloc_size = sizeof(struct rk3288_clk_plat),
.ops = &rk3288_clk_ops,
.bind = rk3288_clk_bind,
+ .ofdata_to_platdata = rk3288_clk_ofdata_to_platdata,
.probe = rk3288_clk_probe,
};
diff --git a/drivers/core/device-remove.c b/drivers/core/device-remove.c
index 0e56b23fbb..a7f77b4a21 100644
--- a/drivers/core/device-remove.c
+++ b/drivers/core/device-remove.c
@@ -112,7 +112,7 @@ int device_unbind(struct udevice *dev)
devres_release_all(dev);
- if (dev->flags & DM_NAME_ALLOCED)
+ if (dev->flags & DM_FLAG_NAME_ALLOCED)
free((char *)dev->name);
free(dev);
diff --git a/drivers/core/device.c b/drivers/core/device.c
index eb75b1734f..5bb1d7793d 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>
@@ -29,7 +30,7 @@ DECLARE_GLOBAL_DATA_PTR;
static int device_bind_common(struct udevice *parent, const struct driver *drv,
const char *name, void *platdata,
ulong driver_data, int of_offset,
- struct udevice **devp)
+ uint of_platdata_size, struct udevice **devp)
{
struct udevice *dev;
struct uclass *uc;
@@ -83,12 +84,29 @@ static int device_bind_common(struct udevice *parent, const struct driver *drv,
}
}
- if (!dev->platdata && drv->platdata_auto_alloc_size) {
- dev->flags |= DM_FLAG_ALLOC_PDATA;
- dev->platdata = calloc(1, drv->platdata_auto_alloc_size);
- if (!dev->platdata) {
- ret = -ENOMEM;
- goto fail_alloc1;
+ if (drv->platdata_auto_alloc_size) {
+ bool alloc = !platdata;
+
+ if (CONFIG_IS_ENABLED(OF_PLATDATA)) {
+ if (of_platdata_size) {
+ dev->flags |= DM_FLAG_OF_PLATDATA;
+ if (of_platdata_size <
+ drv->platdata_auto_alloc_size)
+ alloc = true;
+ }
+ }
+ if (alloc) {
+ dev->flags |= DM_FLAG_ALLOC_PDATA;
+ dev->platdata = calloc(1,
+ drv->platdata_auto_alloc_size);
+ if (!dev->platdata) {
+ ret = -ENOMEM;
+ goto fail_alloc1;
+ }
+ if (CONFIG_IS_ENABLED(OF_PLATDATA) && platdata) {
+ memcpy(dev->platdata, platdata,
+ of_platdata_size);
+ }
}
}
@@ -201,14 +219,14 @@ int device_bind_with_driver_data(struct udevice *parent,
struct udevice **devp)
{
return device_bind_common(parent, drv, name, NULL, driver_data,
- of_offset, devp);
+ of_offset, 0, devp);
}
int device_bind(struct udevice *parent, const struct driver *drv,
const char *name, void *platdata, int of_offset,
struct udevice **devp)
{
- return device_bind_common(parent, drv, name, platdata, 0, of_offset,
+ return device_bind_common(parent, drv, name, platdata, 0, of_offset, 0,
devp);
}
@@ -216,6 +234,7 @@ int device_bind_by_name(struct udevice *parent, bool pre_reloc_only,
const struct driver_info *info, struct udevice **devp)
{
struct driver *drv;
+ uint platdata_size = 0;
drv = lists_driver_lookup_name(info->name);
if (!drv)
@@ -223,8 +242,11 @@ int device_bind_by_name(struct udevice *parent, bool pre_reloc_only,
if (pre_reloc_only && !(drv->flags & DM_FLAG_PRE_RELOC))
return -EPERM;
- return device_bind(parent, drv, info->name, (void *)info->platdata,
- -1, devp);
+#if CONFIG_IS_ENABLED(OF_PLATDATA)
+ platdata_size = info->platdata_size;
+#endif
+ return device_bind_common(parent, drv, info->name,
+ (void *)info->platdata, 0, -1, platdata_size, devp);
}
static void *alloc_priv(int size, uint flags)
@@ -607,7 +629,7 @@ const char *dev_get_uclass_name(struct udevice *dev)
fdt_addr_t dev_get_addr_index(struct udevice *dev, int index)
{
-#if CONFIG_IS_ENABLED(OF_CONTROL)
+#if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)
fdt_addr_t addr;
if (CONFIG_IS_ENABLED(OF_TRANSLATE)) {
@@ -697,6 +719,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);
@@ -727,7 +759,7 @@ bool device_is_last_sibling(struct udevice *dev)
void device_set_name_alloced(struct udevice *dev)
{
- dev->flags |= DM_NAME_ALLOCED;
+ dev->flags |= DM_FLAG_NAME_ALLOCED;
}
int device_set_name(struct udevice *dev, const char *name)
diff --git a/drivers/core/lists.c b/drivers/core/lists.c
index 0c27717790..6a634e6951 100644
--- a/drivers/core/lists.c
+++ b/drivers/core/lists.c
@@ -99,7 +99,7 @@ int device_bind_driver_to_node(struct udevice *parent, const char *drv_name,
return 0;
}
-#if CONFIG_IS_ENABLED(OF_CONTROL)
+#if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)
/**
* driver_check_compatible() - Check if a driver is compatible with this node
*
diff --git a/drivers/core/regmap.c b/drivers/core/regmap.c
index 519832f173..0299ff0879 100644
--- a/drivers/core/regmap.c
+++ b/drivers/core/regmap.c
@@ -15,6 +15,49 @@
DECLARE_GLOBAL_DATA_PTR;
+static struct regmap *regmap_alloc_count(int count)
+{
+ struct regmap *map;
+
+ map = malloc(sizeof(struct regmap));
+ if (!map)
+ return NULL;
+ if (count <= 1) {
+ map->range = &map->base_range;
+ } else {
+ map->range = malloc(count * sizeof(struct regmap_range));
+ if (!map->range) {
+ free(map);
+ return NULL;
+ }
+ }
+ map->range_count = count;
+
+ return map;
+}
+
+#if CONFIG_IS_ENABLED(OF_PLATDATA)
+int regmap_init_mem_platdata(struct udevice *dev, u32 *reg, int count,
+ struct regmap **mapp)
+{
+ struct regmap_range *range;
+ struct regmap *map;
+
+ map = regmap_alloc_count(count);
+ if (!map)
+ return -ENOMEM;
+
+ map->base = *reg;
+ for (range = map->range; count > 0; reg += 2, range++, count--) {
+ range->start = *reg;
+ range->size = reg[1];
+ }
+
+ *mapp = map;
+
+ return 0;
+}
+#else
int regmap_init_mem(struct udevice *dev, struct regmap **mapp)
{
const void *blob = gd->fdt_blob;
@@ -37,22 +80,11 @@ int regmap_init_mem(struct udevice *dev, struct regmap **mapp)
if (!cell || !count)
return -EINVAL;
- map = malloc(sizeof(struct regmap));
+ map = regmap_alloc_count(count);
if (!map)
return -ENOMEM;
- if (count <= 1) {
- map->range = &map->base_range;
- } else {
- map->range = malloc(count * sizeof(struct regmap_range));
- if (!map->range) {
- free(map);
- return -ENOMEM;
- }
- }
-
map->base = fdtdec_get_number(cell, addr_len);
- map->range_count = count;
for (range = map->range; count > 0;
count--, cell += both_len, range++) {
@@ -64,6 +96,7 @@ int regmap_init_mem(struct udevice *dev, struct regmap **mapp)
return 0;
}
+#endif
void *regmap_get_range(struct regmap *map, unsigned int range_num)
{
diff --git a/drivers/core/root.c b/drivers/core/root.c
index 95886add23..158702406e 100644
--- a/drivers/core/root.c
+++ b/drivers/core/root.c
@@ -188,7 +188,7 @@ int dm_scan_platdata(bool pre_reloc_only)
return ret;
}
-#if CONFIG_IS_ENABLED(OF_CONTROL)
+#if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)
int dm_scan_fdt_node(struct udevice *parent, const void *blob, int offset,
bool pre_reloc_only)
{
@@ -244,7 +244,7 @@ int dm_init_and_scan(bool pre_reloc_only)
return ret;
}
- if (CONFIG_IS_ENABLED(OF_CONTROL)) {
+ if (CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)) {
ret = dm_scan_fdt(gd->fdt_blob, pre_reloc_only);
if (ret) {
debug("dm_scan_fdt() failed: %d\n", ret);
diff --git a/drivers/core/syscon-uclass.c b/drivers/core/syscon-uclass.c
index e03f46af57..01bd9683a7 100644
--- a/drivers/core/syscon-uclass.c
+++ b/drivers/core/syscon-uclass.c
@@ -29,7 +29,20 @@ static int syscon_pre_probe(struct udevice *dev)
{
struct syscon_uc_info *priv = dev_get_uclass_priv(dev);
+ /*
+ * With OF_PLATDATA we really have no way of knowing the format of
+ * the device-specific platform data. So we assume that it starts with
+ * a 'reg' member, and this holds a single address and size. Drivers
+ * using OF_PLATDATA will need to ensure that this is true.
+ */
+#if CONFIG_IS_ENABLED(OF_PLATDATA)
+ struct syscon_base_platdata *plat = dev_get_platdata(dev);
+
+ return regmap_init_mem_platdata(dev, plat->reg, ARRAY_SIZE(plat->reg),
+ &priv->regmap);
+#else
return regmap_init_mem(dev, &priv->regmap);
+#endif
}
int syscon_get_by_driver_data(ulong driver_data, struct udevice **devp)
diff --git a/drivers/crypto/fsl/desc.h b/drivers/crypto/fsl/desc.h
index 1ac3a09dff..081bce53cf 100644
--- a/drivers/crypto/fsl/desc.h
+++ b/drivers/crypto/fsl/desc.h
@@ -107,7 +107,7 @@
*/
#define HDR_REVERSE 0x00000800
-/* Propogate DNR property to SharedDesc */
+/* Propagate DNR property to SharedDesc */
#define HDR_PROP_DNR 0x00000800
/* JobDesc/SharedDesc share property */
diff --git a/drivers/ddr/fsl/ctrl_regs.c b/drivers/ddr/fsl/ctrl_regs.c
index 1d5cec662c..abd576b935 100644
--- a/drivers/ddr/fsl/ctrl_regs.c
+++ b/drivers/ddr/fsl/ctrl_regs.c
@@ -2212,7 +2212,7 @@ static void set_ddr_wrlvl_cntl(fsl_ddr_cfg_regs_t *ddr, unsigned int wrlvl_en,
* Write leveling start time
* The value use for the DQS_ADJUST for the first sample
* when write leveling is enabled. It probably needs to be
- * overriden per platform.
+ * overridden per platform.
*/
wrlvl_start = 0x8;
/*
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/fpga/fpga.c b/drivers/fpga/fpga.c
index 7e2f3e17a7..e0fb1b4e78 100644
--- a/drivers/fpga/fpga.c
+++ b/drivers/fpga/fpga.c
@@ -31,7 +31,7 @@ static void fpga_no_sup(char *fn, char *msg)
else if (msg)
printf("No support for %s.\n", msg);
else
- printf("No FPGA suport!\n");
+ printf("No FPGA support!\n");
}
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/Makefile b/drivers/misc/Makefile
index 066639ba1f..fff6f0cdf9 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -29,12 +29,19 @@ obj-$(CONFIG_PDSP188x) += pdsp188x.o
obj-$(CONFIG_$(SPL_)PWRSEQ) += pwrseq-uclass.o
obj-$(CONFIG_SANDBOX) += sysreset_sandbox.o
ifdef CONFIG_DM_I2C
+ifndef CONFIG_SPL_BUILD
obj-$(CONFIG_SANDBOX) += i2c_eeprom_emul.o
endif
+endif
obj-$(CONFIG_SMSC_LPC47M) += smsc_lpc47m.o
obj-$(CONFIG_SMSC_SIO1007) += smsc_sio1007.o
obj-$(CONFIG_STATUS_LED) += status_led.o
obj-$(CONFIG_SANDBOX) += swap_case.o
+ifdef CONFIG_SPL_OF_PLATDATA
+ifdef CONFIG_SPL_BUILD
+obj-$(CONFIG_SANDBOX) += spltest_sandbox.o
+endif
+endif
obj-$(CONFIG_SANDBOX) += syscon_sandbox.o
obj-$(CONFIG_TWL4030_LED) += twl4030_led.o
obj-$(CONFIG_FSL_IFC) += fsl_ifc.o
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/misc/spltest_sandbox.c b/drivers/misc/spltest_sandbox.c
new file mode 100644
index 0000000000..1fef8252ab
--- /dev/null
+++ b/drivers/misc/spltest_sandbox.c
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2016 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <dt-structs.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static int sandbox_spl_probe(struct udevice *dev)
+{
+ struct dtd_sandbox_spl_test *plat = dev_get_platdata(dev);
+ int i;
+
+ printf("of-platdata probe:\n");
+ printf("bool %d\n", plat->boolval);
+
+ printf("byte %02x\n", plat->byteval);
+ printf("bytearray");
+ for (i = 0; i < sizeof(plat->bytearray); i++)
+ printf(" %02x", plat->bytearray[i]);
+ printf("\n");
+
+ printf("int %d\n", plat->intval);
+ printf("intarray");
+ for (i = 0; i < ARRAY_SIZE(plat->intarray); i++)
+ printf(" %d", plat->intarray[i]);
+ printf("\n");
+
+ printf("longbytearray");
+ for (i = 0; i < sizeof(plat->longbytearray); i++)
+ printf(" %02x", plat->longbytearray[i]);
+ printf("\n");
+
+ printf("string %s\n", plat->stringval);
+ printf("stringarray");
+ for (i = 0; i < ARRAY_SIZE(plat->stringarray); i++)
+ printf(" \"%s\"", plat->stringarray[i]);
+ printf("\n");
+
+ return 0;
+}
+
+U_BOOT_DRIVER(sandbox_spl_test) = {
+ .name = "sandbox_spl_test",
+ .id = UCLASS_MISC,
+ .flags = DM_FLAG_PRE_RELOC,
+ .probe = sandbox_spl_probe,
+};
diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig
index c80efc39a7..e0adb9b1a3 100644
--- a/drivers/mmc/Kconfig
+++ b/drivers/mmc/Kconfig
@@ -10,15 +10,24 @@ config DM_MMC
bool "Enable MMC controllers using Driver Model"
depends on DM
help
- This enables the MultiMediaCard (MMC) uclass which suports MMC and
+ This enables the MultiMediaCard (MMC) uclass which supports MMC and
Secure Digital I/O (SDIO) cards. Both removable (SD, micro-SD, etc.)
and non-removable (e.g. eMMC chip) devices are supported. These
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/exynos_dw_mmc.c b/drivers/mmc/exynos_dw_mmc.c
index 863bbb3f64..283befccfb 100644
--- a/drivers/mmc/exynos_dw_mmc.c
+++ b/drivers/mmc/exynos_dw_mmc.c
@@ -23,8 +23,21 @@
#define DWMMC_MMC0_SDR_TIMING_VAL 0x03030001
#define DWMMC_MMC2_SDR_TIMING_VAL 0x03020001
+#ifdef CONFIG_DM_MMC
+#include <dm.h>
+DECLARE_GLOBAL_DATA_PTR;
+
+struct exynos_mmc_plat {
+ struct mmc_config cfg;
+ struct mmc mmc;
+};
+#endif
+
/* Exynos implmentation specific drver private data */
struct dwmci_exynos_priv_data {
+#ifdef CONFIG_DM_MMC
+ struct dwmci_host host;
+#endif
u32 sdr_timing;
};
@@ -80,11 +93,10 @@ static void exynos_dwmci_board_init(struct dwmci_host *host)
exynos_dwmci_clksel(host);
}
-static int exynos_dwmci_core_init(struct dwmci_host *host, int index)
+static int exynos_dwmci_core_init(struct dwmci_host *host)
{
unsigned int div;
unsigned long freq, sclk;
- struct dwmci_exynos_priv_data *priv = host->priv;
if (host->bus_hz)
freq = host->bus_hz;
@@ -92,10 +104,10 @@ static int exynos_dwmci_core_init(struct dwmci_host *host, int index)
freq = DWMMC_MAX_FREQ;
/* request mmc clock vlaue of 52MHz. */
- sclk = get_mmc_clk(index);
+ sclk = get_mmc_clk(host->dev_index);
div = DIV_ROUND_UP(sclk, freq);
/* set the clock divisor for mmc */
- set_mmc_clk(index, div);
+ set_mmc_clk(host->dev_index, div);
host->name = "EXYNOS DWMMC";
#ifdef CONFIG_EXYNOS5420
@@ -103,78 +115,35 @@ static int exynos_dwmci_core_init(struct dwmci_host *host, int index)
#endif
host->board_init = exynos_dwmci_board_init;
- if (!priv->sdr_timing) {
- if (index == 0)
- priv->sdr_timing = DWMMC_MMC0_SDR_TIMING_VAL;
- else if (index == 2)
- priv->sdr_timing = DWMMC_MMC2_SDR_TIMING_VAL;
- }
-
host->caps = MMC_MODE_DDR_52MHz;
host->clksel = exynos_dwmci_clksel;
- host->dev_index = index;
host->get_mmc_clk = exynos_dwmci_get_clk;
+
+#ifndef CONFIG_DM_MMC
/* Add the mmc channel to be registered with mmc core */
if (add_dwmci(host, DWMMC_MAX_FREQ, DWMMC_MIN_FREQ)) {
- printf("DWMMC%d registration failed\n", index);
+ printf("DWMMC%d registration failed\n", host->dev_index);
return -1;
}
- return 0;
-}
-
-/*
- * This function adds the mmc channel to be registered with mmc core.
- * index - mmc channel number.
- * regbase - register base address of mmc channel specified in 'index'.
- * bus_width - operating bus width of mmc channel specified in 'index'.
- * clksel - value to be written into CLKSEL register in case of FDT.
- * NULL in case od non-FDT.
- */
-int exynos_dwmci_add_port(int index, u32 regbase, int bus_width, u32 clksel)
-{
- struct dwmci_host *host = NULL;
- struct dwmci_exynos_priv_data *priv;
-
- host = malloc(sizeof(struct dwmci_host));
- if (!host) {
- error("dwmci_host malloc fail!\n");
- return -ENOMEM;
- }
-
- priv = malloc(sizeof(struct dwmci_exynos_priv_data));
- if (!priv) {
- error("dwmci_exynos_priv_data malloc fail!\n");
- return -ENOMEM;
- }
-
- host->ioaddr = (void *)regbase;
- host->buswidth = bus_width;
-
- if (clksel)
- priv->sdr_timing = clksel;
-
- host->priv = priv;
+#endif
- return exynos_dwmci_core_init(host, index);
+ return 0;
}
-#if CONFIG_IS_ENABLED(OF_CONTROL)
static struct dwmci_host dwmci_host[DWMMC_MAX_CH_NUM];
static int do_dwmci_init(struct dwmci_host *host)
{
- int index, flag, err;
-
- index = host->dev_index;
+ int flag, err;
flag = host->buswidth == 8 ? PINMUX_FLAG_8BIT_MODE : PINMUX_FLAG_NONE;
err = exynos_pinmux_config(host->dev_id, flag);
if (err) {
- printf("DWMMC%d not configure\n", index);
+ printf("DWMMC%d not configure\n", host->dev_index);
return err;
}
- return exynos_dwmci_core_init(host, index);
+ return exynos_dwmci_core_init(host);
}
static int exynos_dwmci_get_config(const void *blob, int node,
@@ -197,13 +166,14 @@ static int exynos_dwmci_get_config(const void *blob, int node,
if (host->dev_index == host->dev_id)
host->dev_index = host->dev_id - PERIPH_ID_SDMMC0;
- /* Get the bus width from the device node */
- host->buswidth = fdtdec_get_int(blob, node, "samsung,bus-width", 0);
- if (host->buswidth <= 0) {
- printf("DWMMC%d: Can't get bus-width\n", host->dev_index);
+ if (host->dev_index > 4) {
+ printf("DWMMC%d: Can't get the dev index\n", host->dev_index);
return -EINVAL;
}
+ /* Get the bus width from the device node (Default is 4bit buswidth) */
+ host->buswidth = fdtdec_get_int(blob, node, "samsung,bus-width", 4);
+
/* Set the base address from the device node */
base = fdtdec_get_addr(blob, node, "reg");
if (!base) {
@@ -265,15 +235,13 @@ static int exynos_dwmci_process_node(const void *blob,
int exynos_dwmmc_init(const void *blob)
{
- int compat_id;
int node_list[DWMMC_MAX_CH_NUM];
int boot_dev_node;
int err = 0, count;
- compat_id = COMPAT_SAMSUNG_EXYNOS_DWMMC;
-
count = fdtdec_find_aliases_for_id(blob, "mmc",
- compat_id, node_list, DWMMC_MAX_CH_NUM);
+ COMPAT_SAMSUNG_EXYNOS_DWMMC, node_list,
+ DWMMC_MAX_CH_NUM);
/* For DWMMC always set boot device as mmc 0 */
if (count >= 3 && get_boot_mode() == BOOT_MODE_SD) {
@@ -286,4 +254,58 @@ int exynos_dwmmc_init(const void *blob)
return err;
}
+
+#ifdef CONFIG_DM_MMC
+static int exynos_dwmmc_probe(struct udevice *dev)
+{
+ struct exynos_mmc_plat *plat = dev_get_platdata(dev);
+ struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
+ struct dwmci_exynos_priv_data *priv = dev_get_priv(dev);
+ struct dwmci_host *host = &priv->host;
+ int err;
+
+ err = exynos_dwmci_get_config(gd->fdt_blob, dev->of_offset, host);
+ if (err)
+ return err;
+ err = do_dwmci_init(host);
+ if (err)
+ return err;
+
+ dwmci_setup_cfg(&plat->cfg, host->name, host->buswidth, host->caps,
+ DWMMC_MAX_FREQ, DWMMC_MIN_FREQ);
+ host->mmc = &plat->mmc;
+ host->mmc->priv = &priv->host;
+ host->priv = dev;
+ upriv->mmc = host->mmc;
+
+ return dwmci_probe(dev);
+}
+
+static int exynos_dwmmc_bind(struct udevice *dev)
+{
+ struct exynos_mmc_plat *plat = dev_get_platdata(dev);
+ int ret;
+
+ ret = dwmci_bind(dev, &plat->mmc, &plat->cfg);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static const struct udevice_id exynos_dwmmc_ids[] = {
+ { .compatible = "samsung,exynos4412-dw-mshc" },
+ { }
+};
+
+U_BOOT_DRIVER(exynos_dwmmc_drv) = {
+ .name = "exynos_dwmmc",
+ .id = UCLASS_MMC,
+ .of_match = exynos_dwmmc_ids,
+ .bind = exynos_dwmmc_bind,
+ .ops = &dm_dwmci_ops,
+ .probe = exynos_dwmmc_probe,
+ .priv_auto_alloc_size = sizeof(struct dwmci_exynos_priv_data),
+ .platdata_auto_alloc_size = sizeof(struct exynos_mmc_plat),
+};
#endif
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..020a59b921 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 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/mmc/sunxi_mmc.c b/drivers/mmc/sunxi_mmc.c
index ce2dc4ae41..5d8abdc897 100644
--- a/drivers/mmc/sunxi_mmc.c
+++ b/drivers/mmc/sunxi_mmc.c
@@ -269,18 +269,18 @@ static int mmc_trans_data_by_cpu(struct mmc *mmc, struct mmc_data *data)
unsigned i;
unsigned *buff = (unsigned int *)(reading ? data->dest : data->src);
unsigned byte_cnt = data->blocksize * data->blocks;
- unsigned timeout_msecs = byte_cnt >> 8;
- if (timeout_msecs < 2000)
- timeout_msecs = 2000;
+ unsigned timeout_usecs = (byte_cnt >> 8) * 1000;
+ if (timeout_usecs < 2000000)
+ timeout_usecs = 2000000;
/* Always read / write data through the CPU */
setbits_le32(&mmchost->reg->gctrl, SUNXI_MMC_GCTRL_ACCESS_BY_AHB);
for (i = 0; i < (byte_cnt >> 2); i++) {
while (readl(&mmchost->reg->status) & status_bit) {
- if (!timeout_msecs--)
+ if (!timeout_usecs--)
return -1;
- udelay(1000);
+ udelay(1);
}
if (reading)
@@ -445,23 +445,6 @@ static int sunxi_mmc_getcd(struct mmc *mmc)
return !gpio_get_value(cd_pin);
}
-int sunxi_mmc_has_egon_boot_signature(struct mmc *mmc)
-{
- char *buf = malloc(512);
- int valid_signature = 0;
-
- if (buf == NULL)
- panic("Failed to allocate memory\n");
-
- if (mmc_getcd(mmc) && mmc_init(mmc) == 0 &&
- mmc->block_dev.block_read(&mmc->block_dev, 16, 1, buf) == 1 &&
- strncmp(&buf[4], "eGON.BT0", 8) == 0)
- valid_signature = 1;
-
- free(buf);
- return valid_signature;
-}
-
static const struct mmc_ops sunxi_mmc_ops = {
.send_cmd = sunxi_mmc_send_cmd,
.set_ios = sunxi_mmc_set_ios,
diff --git a/drivers/mtd/cfi_flash.c b/drivers/mtd/cfi_flash.c
index 8ccaff0e63..33c4a9342f 100644
--- a/drivers/mtd/cfi_flash.c
+++ b/drivers/mtd/cfi_flash.c
@@ -608,7 +608,7 @@ static int flash_full_status_check (flash_info_t * info, flash_sect_t sector,
case CFI_CMDSET_INTEL_EXTENDED:
case CFI_CMDSET_INTEL_STANDARD:
if ((retcode == ERR_OK)
- && !flash_isequal (info, sector, 0, FLASH_STATUS_DONE)) {
+ && !flash_isset(info, sector, 0, FLASH_STATUS_DONE)) {
retcode = ERR_INVAL;
printf ("Flash %s error at address %lx\n", prompt,
info->start[sector]);
diff --git a/drivers/mtd/nand/mxs_nand.c b/drivers/mtd/nand/mxs_nand.c
index c90a3a7bd2..94fc5c18a0 100644
--- a/drivers/mtd/nand/mxs_nand.c
+++ b/drivers/mtd/nand/mxs_nand.c
@@ -976,7 +976,7 @@ static int mxs_nand_block_bad(struct mtd_info *mtd, loff_t ofs)
* counted, so we know the physical geometry. This enables us to make some
* important configuration decisions.
*
- * The return value of this function propogates directly back to this driver's
+ * The return value of this function propagates directly back to this driver's
* call to nand_scan(). Anything other than zero will cause this driver to
* tear everything down and declare failure.
*/
diff --git a/drivers/mtd/nand/tegra_nand.c b/drivers/mtd/nand/tegra_nand.c
index 2032f65812..38bd7a5578 100644
--- a/drivers/mtd/nand/tegra_nand.c
+++ b/drivers/mtd/nand/tegra_nand.c
@@ -884,7 +884,7 @@ static void setup_timing(unsigned timing[FDT_NAND_TIMING_COUNT],
* Decode NAND parameters from the device tree
*
* @param blob Device tree blob
- * @param node Node containing "nand-flash" compatble node
+ * @param node Node containing "nand-flash" compatible node
* @return 0 if ok, -ve on error (FDT_ERR_...)
*/
static int fdt_decode_nand(const void *blob, int node, struct fdt_nand *config)
diff --git a/drivers/mtd/spi/Kconfig b/drivers/mtd/spi/Kconfig
index 3f7433cbc2..1f23c8e34e 100644
--- a/drivers/mtd/spi/Kconfig
+++ b/drivers/mtd/spi/Kconfig
@@ -128,4 +128,16 @@ config SPI_FLASH_MTD
If unsure, say N
+if SPL
+
+config SPL_SPI_SUNXI
+ bool "Support for SPI Flash on Allwinner SoCs in SPL"
+ depends on MACH_SUN4I || MACH_SUN5I || MACH_SUN7I || MACH_SUN8I_H3 || MACH_SUN50I
+ ---help---
+ Enable support for SPI Flash. This option allows SPL to read from
+ sunxi SPI Flash. It uses the same method as the boot ROM, so does
+ not need any extra configuration.
+
+endif
+
endmenu # menu "SPI Flash Support"
diff --git a/drivers/mtd/spi/Makefile b/drivers/mtd/spi/Makefile
index c665836f95..6f47a66f40 100644
--- a/drivers/mtd/spi/Makefile
+++ b/drivers/mtd/spi/Makefile
@@ -10,6 +10,7 @@ obj-$(CONFIG_DM_SPI_FLASH) += sf-uclass.o
ifdef CONFIG_SPL_BUILD
obj-$(CONFIG_SPL_SPI_LOAD) += spi_spl_load.o
obj-$(CONFIG_SPL_SPI_BOOT) += fsl_espi_spl.o
+obj-$(CONFIG_SPL_SPI_SUNXI) += sunxi_spi_spl.o
endif
obj-$(CONFIG_SPI_FLASH) += sf_probe.o spi_flash.o sf_params.o sf.o
diff --git a/drivers/mtd/spi/sunxi_spi_spl.c b/drivers/mtd/spi/sunxi_spi_spl.c
new file mode 100644
index 0000000000..e3ded5b4e8
--- /dev/null
+++ b/drivers/mtd/spi/sunxi_spi_spl.c
@@ -0,0 +1,283 @@
+/*
+ * Copyright (C) 2016 Siarhei Siamashka <siarhei.siamashka@gmail.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <spl.h>
+#include <asm/gpio.h>
+#include <asm/io.h>
+
+#ifdef CONFIG_SPL_OS_BOOT
+#error CONFIG_SPL_OS_BOOT is not supported yet
+#endif
+
+/*
+ * This is a very simple U-Boot image loading implementation, trying to
+ * replicate what the boot ROM is doing when loading the SPL. Because we
+ * know the exact pins where the SPI Flash is connected and also know
+ * that the Read Data Bytes (03h) command is supported, the hardware
+ * configuration is very simple and we don't need the extra flexibility
+ * of the SPI framework. Moreover, we rely on the default settings of
+ * the SPI controler hardware registers and only adjust what needs to
+ * be changed. This is good for the code size and this implementation
+ * adds less than 400 bytes to the SPL.
+ *
+ * There are two variants of the SPI controller in Allwinner SoCs:
+ * A10/A13/A20 (sun4i variant) and everything else (sun6i variant).
+ * Both of them are supported.
+ *
+ * The pin mixing part is SoC specific and only A10/A13/A20/H3/A64 are
+ * supported at the moment.
+ */
+
+/*****************************************************************************/
+/* SUN4I variant of the SPI controller */
+/*****************************************************************************/
+
+#define SUN4I_SPI0_CCTL (0x01C05000 + 0x1C)
+#define SUN4I_SPI0_CTL (0x01C05000 + 0x08)
+#define SUN4I_SPI0_RX (0x01C05000 + 0x00)
+#define SUN4I_SPI0_TX (0x01C05000 + 0x04)
+#define SUN4I_SPI0_FIFO_STA (0x01C05000 + 0x28)
+#define SUN4I_SPI0_BC (0x01C05000 + 0x20)
+#define SUN4I_SPI0_TC (0x01C05000 + 0x24)
+
+#define SUN4I_CTL_ENABLE BIT(0)
+#define SUN4I_CTL_MASTER BIT(1)
+#define SUN4I_CTL_TF_RST BIT(8)
+#define SUN4I_CTL_RF_RST BIT(9)
+#define SUN4I_CTL_XCH BIT(10)
+
+/*****************************************************************************/
+/* SUN6I variant of the SPI controller */
+/*****************************************************************************/
+
+#define SUN6I_SPI0_CCTL (0x01C68000 + 0x24)
+#define SUN6I_SPI0_GCR (0x01C68000 + 0x04)
+#define SUN6I_SPI0_TCR (0x01C68000 + 0x08)
+#define SUN6I_SPI0_FIFO_STA (0x01C68000 + 0x1C)
+#define SUN6I_SPI0_MBC (0x01C68000 + 0x30)
+#define SUN6I_SPI0_MTC (0x01C68000 + 0x34)
+#define SUN6I_SPI0_BCC (0x01C68000 + 0x38)
+#define SUN6I_SPI0_TXD (0x01C68000 + 0x200)
+#define SUN6I_SPI0_RXD (0x01C68000 + 0x300)
+
+#define SUN6I_CTL_ENABLE BIT(0)
+#define SUN6I_CTL_MASTER BIT(1)
+#define SUN6I_CTL_SRST BIT(31)
+#define SUN6I_TCR_XCH BIT(31)
+
+/*****************************************************************************/
+
+#define CCM_AHB_GATING0 (0x01C20000 + 0x60)
+#define CCM_SPI0_CLK (0x01C20000 + 0xA0)
+#define SUN6I_BUS_SOFT_RST_REG0 (0x01C20000 + 0x2C0)
+
+#define AHB_RESET_SPI0_SHIFT 20
+#define AHB_GATE_OFFSET_SPI0 20
+
+#define SPI0_CLK_DIV_BY_2 0x1000
+#define SPI0_CLK_DIV_BY_4 0x1001
+
+/*****************************************************************************/
+
+/*
+ * Allwinner A10/A20 SoCs were using pins PC0,PC1,PC2,PC23 for booting
+ * from SPI Flash, everything else is using pins PC0,PC1,PC2,PC3.
+ */
+static void spi0_pinmux_setup(unsigned int pin_function)
+{
+ unsigned int pin;
+
+ for (pin = SUNXI_GPC(0); pin <= SUNXI_GPC(2); pin++)
+ sunxi_gpio_set_cfgpin(pin, pin_function);
+
+ if (IS_ENABLED(CONFIG_MACH_SUN4I) || IS_ENABLED(CONFIG_MACH_SUN7I))
+ sunxi_gpio_set_cfgpin(SUNXI_GPC(23), pin_function);
+ else
+ sunxi_gpio_set_cfgpin(SUNXI_GPC(3), pin_function);
+}
+
+/*
+ * Setup 6 MHz from OSC24M (because the BROM is doing the same).
+ */
+static void spi0_enable_clock(void)
+{
+ /* Deassert SPI0 reset on SUN6I */
+ if (IS_ENABLED(CONFIG_SUNXI_GEN_SUN6I))
+ setbits_le32(SUN6I_BUS_SOFT_RST_REG0,
+ (1 << AHB_RESET_SPI0_SHIFT));
+
+ /* Open the SPI0 gate */
+ setbits_le32(CCM_AHB_GATING0, (1 << AHB_GATE_OFFSET_SPI0));
+
+ /* Divide by 4 */
+ writel(SPI0_CLK_DIV_BY_4, IS_ENABLED(CONFIG_SUNXI_GEN_SUN6I) ?
+ SUN6I_SPI0_CCTL : SUN4I_SPI0_CCTL);
+ /* 24MHz from OSC24M */
+ writel((1 << 31), CCM_SPI0_CLK);
+
+ if (IS_ENABLED(CONFIG_SUNXI_GEN_SUN6I)) {
+ /* Enable SPI in the master mode and do a soft reset */
+ setbits_le32(SUN6I_SPI0_GCR, SUN6I_CTL_MASTER |
+ SUN6I_CTL_ENABLE |
+ SUN6I_CTL_SRST);
+ /* Wait for completion */
+ while (readl(SUN6I_SPI0_GCR) & SUN6I_CTL_SRST)
+ ;
+ } else {
+ /* Enable SPI in the master mode and reset FIFO */
+ setbits_le32(SUN4I_SPI0_CTL, SUN4I_CTL_MASTER |
+ SUN4I_CTL_ENABLE |
+ SUN4I_CTL_TF_RST |
+ SUN4I_CTL_RF_RST);
+ }
+}
+
+static void spi0_disable_clock(void)
+{
+ /* Disable the SPI0 controller */
+ if (IS_ENABLED(CONFIG_SUNXI_GEN_SUN6I))
+ clrbits_le32(SUN6I_SPI0_GCR, SUN6I_CTL_MASTER |
+ SUN6I_CTL_ENABLE);
+ else
+ clrbits_le32(SUN4I_SPI0_CTL, SUN4I_CTL_MASTER |
+ SUN4I_CTL_ENABLE);
+
+ /* Disable the SPI0 clock */
+ writel(0, CCM_SPI0_CLK);
+
+ /* Close the SPI0 gate */
+ clrbits_le32(CCM_AHB_GATING0, (1 << AHB_GATE_OFFSET_SPI0));
+
+ /* Assert SPI0 reset on SUN6I */
+ if (IS_ENABLED(CONFIG_SUNXI_GEN_SUN6I))
+ clrbits_le32(SUN6I_BUS_SOFT_RST_REG0,
+ (1 << AHB_RESET_SPI0_SHIFT));
+}
+
+static int spi0_init(void)
+{
+ unsigned int pin_function = SUNXI_GPC_SPI0;
+ if (IS_ENABLED(CONFIG_MACH_SUN50I))
+ pin_function = SUN50I_GPC_SPI0;
+
+ spi0_pinmux_setup(pin_function);
+ spi0_enable_clock();
+}
+
+static void spi0_deinit(void)
+{
+ /* New SoCs can disable pins, older could only set them as input */
+ unsigned int pin_function = SUNXI_GPIO_INPUT;
+ if (IS_ENABLED(CONFIG_SUNXI_GEN_SUN6I))
+ pin_function = SUNXI_GPIO_DISABLE;
+
+ spi0_disable_clock();
+ spi0_pinmux_setup(pin_function);
+}
+
+/*****************************************************************************/
+
+#define SPI_READ_MAX_SIZE 60 /* FIFO size, minus 4 bytes of the header */
+
+static void sunxi_spi0_read_data(u8 *buf, u32 addr, u32 bufsize,
+ u32 spi_ctl_reg,
+ u32 spi_ctl_xch_bitmask,
+ u32 spi_fifo_reg,
+ u32 spi_tx_reg,
+ u32 spi_rx_reg,
+ u32 spi_bc_reg,
+ u32 spi_tc_reg,
+ u32 spi_bcc_reg)
+{
+ writel(4 + bufsize, spi_bc_reg); /* Burst counter (total bytes) */
+ writel(4, spi_tc_reg); /* Transfer counter (bytes to send) */
+ if (spi_bcc_reg)
+ writel(4, spi_bcc_reg); /* SUN6I also needs this */
+
+ /* Send the Read Data Bytes (03h) command header */
+ writeb(0x03, spi_tx_reg);
+ writeb((u8)(addr >> 16), spi_tx_reg);
+ writeb((u8)(addr >> 8), spi_tx_reg);
+ writeb((u8)(addr), spi_tx_reg);
+
+ /* Start the data transfer */
+ setbits_le32(spi_ctl_reg, spi_ctl_xch_bitmask);
+
+ /* Wait until everything is received in the RX FIFO */
+ while ((readl(spi_fifo_reg) & 0x7F) < 4 + bufsize)
+ ;
+
+ /* Skip 4 bytes */
+ readl(spi_rx_reg);
+
+ /* Read the data */
+ while (bufsize-- > 0)
+ *buf++ = readb(spi_rx_reg);
+
+ /* tSHSL time is up to 100 ns in various SPI flash datasheets */
+ udelay(1);
+}
+
+static void spi0_read_data(void *buf, u32 addr, u32 len)
+{
+ u8 *buf8 = buf;
+ u32 chunk_len;
+
+ while (len > 0) {
+ chunk_len = len;
+ if (chunk_len > SPI_READ_MAX_SIZE)
+ chunk_len = SPI_READ_MAX_SIZE;
+
+ if (IS_ENABLED(CONFIG_SUNXI_GEN_SUN6I)) {
+ sunxi_spi0_read_data(buf8, addr, chunk_len,
+ SUN6I_SPI0_TCR,
+ SUN6I_TCR_XCH,
+ SUN6I_SPI0_FIFO_STA,
+ SUN6I_SPI0_TXD,
+ SUN6I_SPI0_RXD,
+ SUN6I_SPI0_MBC,
+ SUN6I_SPI0_MTC,
+ SUN6I_SPI0_BCC);
+ } else {
+ sunxi_spi0_read_data(buf8, addr, chunk_len,
+ SUN4I_SPI0_CTL,
+ SUN4I_CTL_XCH,
+ SUN4I_SPI0_FIFO_STA,
+ SUN4I_SPI0_TX,
+ SUN4I_SPI0_RX,
+ SUN4I_SPI0_BC,
+ SUN4I_SPI0_TC,
+ 0);
+ }
+
+ len -= chunk_len;
+ buf8 += chunk_len;
+ addr += chunk_len;
+ }
+}
+
+/*****************************************************************************/
+
+int spl_spi_load_image(void)
+{
+ int err;
+ struct image_header *header;
+ header = (struct image_header *)(CONFIG_SYS_TEXT_BASE);
+
+ spi0_init();
+
+ spi0_read_data((void *)header, CONFIG_SYS_SPI_U_BOOT_OFFS, 0x40);
+ err = spl_parse_image_header(header);
+ if (err)
+ return err;
+
+ spi0_read_data((void *)spl_image.load_addr, CONFIG_SYS_SPI_U_BOOT_OFFS,
+ spl_image.size);
+
+ spi0_deinit();
+ return 0;
+}
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index c1cb689ccf..88d8e83906 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -152,6 +152,15 @@ config RTL8169
This driver supports Realtek 8169 series gigabit ethernet family of
PCI/PCIe chipsets/adapters.
+config SUN8I_EMAC
+ bool "Allwinner Sun8i Ethernet MAC support"
+ depends on DM_ETH
+ select PHYLIB
+ help
+ This driver supports the Allwinner based SUN8I/SUN50I Ethernet MAC.
+ It can be found in H3/A64/A83T based SoCs and compatible with both
+ External and Internal PHY's.
+
config XILINX_AXIEMAC
depends on DM_ETH && (MICROBLAZE || ARCH_ZYNQ || ARCH_ZYNQMP)
select PHYLIB
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 5702592169..a4485266d4 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -24,6 +24,7 @@ obj-$(CONFIG_E1000) += e1000.o
obj-$(CONFIG_E1000_SPI) += e1000_spi.o
obj-$(CONFIG_EEPRO100) += eepro100.o
obj-$(CONFIG_SUNXI_EMAC) += sunxi_emac.o
+obj-$(CONFIG_SUN8I_EMAC) += sun8i_emac.o
obj-$(CONFIG_ENC28J60) += enc28j60.o
obj-$(CONFIG_EP93XX) += ep93xx_eth.o
obj-$(CONFIG_ETHOC) += ethoc.o
diff --git a/drivers/net/sun8i_emac.c b/drivers/net/sun8i_emac.c
new file mode 100644
index 0000000000..4bed50d668
--- /dev/null
+++ b/drivers/net/sun8i_emac.c
@@ -0,0 +1,789 @@
+/*
+ * (C) Copyright 2016
+ * Author: Amit Singh Tomar, amittomer25@gmail.com
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ *
+ * Ethernet driver for H3/A64/A83T based SoC's
+ *
+ * It is derived from the work done by
+ * LABBE Corentin & Chen-Yu Tsai for Linux, THANKS!
+ *
+*/
+
+#include <asm/io.h>
+#include <asm/arch/clock.h>
+#include <asm/arch/gpio.h>
+#include <common.h>
+#include <dm.h>
+#include <fdt_support.h>
+#include <linux/err.h>
+#include <malloc.h>
+#include <miiphy.h>
+#include <net.h>
+
+#define SCTL_EMAC_TX_CLK_SRC_MII BIT(0)
+#define SCTL_EMAC_EPIT_MII BIT(2)
+#define SCTL_EMAC_CLK_SEL BIT(18) /* 25 Mhz */
+
+#define MDIO_CMD_MII_BUSY BIT(0)
+#define MDIO_CMD_MII_WRITE BIT(1)
+
+#define MDIO_CMD_MII_PHY_REG_ADDR_MASK 0x000001f0
+#define MDIO_CMD_MII_PHY_REG_ADDR_SHIFT 4
+#define MDIO_CMD_MII_PHY_ADDR_MASK 0x0001f000
+#define MDIO_CMD_MII_PHY_ADDR_SHIFT 12
+
+#define CONFIG_TX_DESCR_NUM 32
+#define CONFIG_RX_DESCR_NUM 32
+#define CONFIG_ETH_BUFSIZE 2024
+
+#define TX_TOTAL_BUFSIZE (CONFIG_ETH_BUFSIZE * CONFIG_TX_DESCR_NUM)
+#define RX_TOTAL_BUFSIZE (CONFIG_ETH_BUFSIZE * CONFIG_RX_DESCR_NUM)
+
+#define H3_EPHY_DEFAULT_VALUE 0x58000
+#define H3_EPHY_DEFAULT_MASK GENMASK(31, 15)
+#define H3_EPHY_ADDR_SHIFT 20
+#define REG_PHY_ADDR_MASK GENMASK(4, 0)
+#define H3_EPHY_LED_POL BIT(17) /* 1: active low, 0: active high */
+#define H3_EPHY_SHUTDOWN BIT(16) /* 1: shutdown, 0: power up */
+#define H3_EPHY_SELECT BIT(15) /* 1: internal PHY, 0: external PHY */
+
+#define SC_RMII_EN BIT(13)
+#define SC_EPIT BIT(2) /* 1: RGMII, 0: MII */
+#define SC_ETCS_MASK GENMASK(1, 0)
+#define SC_ETCS_EXT_GMII 0x1
+#define SC_ETCS_INT_GMII 0x2
+
+#define CONFIG_MDIO_TIMEOUT (3 * CONFIG_SYS_HZ)
+
+#define AHB_GATE_OFFSET_EPHY 0
+
+#if defined(CONFIG_MACH_SUN8I_H3)
+#define SUN8I_GPD8_GMAC 2
+#else
+#define SUN8I_GPD8_GMAC 4
+#endif
+
+/* H3/A64 EMAC Register's offset */
+#define EMAC_CTL0 0x00
+#define EMAC_CTL1 0x04
+#define EMAC_INT_STA 0x08
+#define EMAC_INT_EN 0x0c
+#define EMAC_TX_CTL0 0x10
+#define EMAC_TX_CTL1 0x14
+#define EMAC_TX_FLOW_CTL 0x1c
+#define EMAC_TX_DMA_DESC 0x20
+#define EMAC_RX_CTL0 0x24
+#define EMAC_RX_CTL1 0x28
+#define EMAC_RX_DMA_DESC 0x34
+#define EMAC_MII_CMD 0x48
+#define EMAC_MII_DATA 0x4c
+#define EMAC_ADDR0_HIGH 0x50
+#define EMAC_ADDR0_LOW 0x54
+#define EMAC_TX_DMA_STA 0xb0
+#define EMAC_TX_CUR_DESC 0xb4
+#define EMAC_TX_CUR_BUF 0xb8
+#define EMAC_RX_DMA_STA 0xc0
+#define EMAC_RX_CUR_DESC 0xc4
+
+DECLARE_GLOBAL_DATA_PTR;
+
+enum emac_variant {
+ A83T_EMAC = 1,
+ H3_EMAC,
+ A64_EMAC,
+};
+
+struct emac_dma_desc {
+ u32 status;
+ u32 st;
+ u32 buf_addr;
+ u32 next;
+} __aligned(ARCH_DMA_MINALIGN);
+
+struct emac_eth_dev {
+ struct emac_dma_desc rx_chain[CONFIG_TX_DESCR_NUM];
+ struct emac_dma_desc tx_chain[CONFIG_RX_DESCR_NUM];
+ char rxbuffer[RX_TOTAL_BUFSIZE] __aligned(ARCH_DMA_MINALIGN);
+ char txbuffer[TX_TOTAL_BUFSIZE] __aligned(ARCH_DMA_MINALIGN);
+
+ u32 interface;
+ u32 phyaddr;
+ u32 link;
+ u32 speed;
+ u32 duplex;
+ u32 phy_configured;
+ u32 tx_currdescnum;
+ u32 rx_currdescnum;
+ u32 addr;
+ u32 tx_slot;
+ bool use_internal_phy;
+
+ enum emac_variant variant;
+ void *mac_reg;
+ phys_addr_t sysctl_reg;
+ struct phy_device *phydev;
+ struct mii_dev *bus;
+};
+
+static int sun8i_mdio_read(struct mii_dev *bus, int addr, int devad, int reg)
+{
+ struct emac_eth_dev *priv = bus->priv;
+ ulong start;
+ u32 miiaddr = 0;
+ int timeout = CONFIG_MDIO_TIMEOUT;
+
+ miiaddr &= ~MDIO_CMD_MII_WRITE;
+ miiaddr &= ~MDIO_CMD_MII_PHY_REG_ADDR_MASK;
+ miiaddr |= (reg << MDIO_CMD_MII_PHY_REG_ADDR_SHIFT) &
+ MDIO_CMD_MII_PHY_REG_ADDR_MASK;
+
+ miiaddr &= ~MDIO_CMD_MII_PHY_ADDR_MASK;
+
+ miiaddr |= (addr << MDIO_CMD_MII_PHY_ADDR_SHIFT) &
+ MDIO_CMD_MII_PHY_ADDR_MASK;
+
+ miiaddr |= MDIO_CMD_MII_BUSY;
+
+ writel(miiaddr, priv->mac_reg + EMAC_MII_CMD);
+
+ start = get_timer(0);
+ while (get_timer(start) < timeout) {
+ if (!(readl(priv->mac_reg + EMAC_MII_CMD) & MDIO_CMD_MII_BUSY))
+ return readl(priv->mac_reg + EMAC_MII_DATA);
+ udelay(10);
+ };
+
+ return -1;
+}
+
+static int sun8i_mdio_write(struct mii_dev *bus, int addr, int devad, int reg,
+ u16 val)
+{
+ struct emac_eth_dev *priv = bus->priv;
+ ulong start;
+ u32 miiaddr = 0;
+ int ret = -1, timeout = CONFIG_MDIO_TIMEOUT;
+
+ miiaddr &= ~MDIO_CMD_MII_PHY_REG_ADDR_MASK;
+ miiaddr |= (reg << MDIO_CMD_MII_PHY_REG_ADDR_SHIFT) &
+ MDIO_CMD_MII_PHY_REG_ADDR_MASK;
+
+ miiaddr &= ~MDIO_CMD_MII_PHY_ADDR_MASK;
+ miiaddr |= (addr << MDIO_CMD_MII_PHY_ADDR_SHIFT) &
+ MDIO_CMD_MII_PHY_ADDR_MASK;
+
+ miiaddr |= MDIO_CMD_MII_WRITE;
+ miiaddr |= MDIO_CMD_MII_BUSY;
+
+ writel(miiaddr, priv->mac_reg + EMAC_MII_CMD);
+ writel(val, priv->mac_reg + EMAC_MII_DATA);
+
+ start = get_timer(0);
+ while (get_timer(start) < timeout) {
+ if (!(readl(priv->mac_reg + EMAC_MII_CMD) &
+ MDIO_CMD_MII_BUSY)) {
+ ret = 0;
+ break;
+ }
+ udelay(10);
+ };
+
+ return ret;
+}
+
+static int _sun8i_write_hwaddr(struct emac_eth_dev *priv, u8 *mac_id)
+{
+ u32 macid_lo, macid_hi;
+
+ macid_lo = mac_id[0] + (mac_id[1] << 8) + (mac_id[2] << 16) +
+ (mac_id[3] << 24);
+ macid_hi = mac_id[4] + (mac_id[5] << 8);
+
+ writel(macid_hi, priv->mac_reg + EMAC_ADDR0_HIGH);
+ writel(macid_lo, priv->mac_reg + EMAC_ADDR0_LOW);
+
+ return 0;
+}
+
+static void sun8i_adjust_link(struct emac_eth_dev *priv,
+ struct phy_device *phydev)
+{
+ u32 v;
+
+ v = readl(priv->mac_reg + EMAC_CTL0);
+
+ if (phydev->duplex)
+ v |= BIT(0);
+ else
+ v &= ~BIT(0);
+
+ v &= ~0x0C;
+
+ switch (phydev->speed) {
+ case 1000:
+ break;
+ case 100:
+ v |= BIT(2);
+ v |= BIT(3);
+ break;
+ case 10:
+ v |= BIT(3);
+ break;
+ }
+ writel(v, priv->mac_reg + EMAC_CTL0);
+}
+
+static int sun8i_emac_set_syscon_ephy(struct emac_eth_dev *priv, u32 *reg)
+{
+ if (priv->use_internal_phy) {
+ /* H3 based SoC's that has an Internal 100MBit PHY
+ * needs to be configured and powered up before use
+ */
+ *reg &= ~H3_EPHY_DEFAULT_MASK;
+ *reg |= H3_EPHY_DEFAULT_VALUE;
+ *reg |= priv->phyaddr << H3_EPHY_ADDR_SHIFT;
+ *reg &= ~H3_EPHY_SHUTDOWN;
+ *reg |= H3_EPHY_SELECT;
+ } else
+ /* This is to select External Gigabit PHY on
+ * the boards with H3 SoC.
+ */
+ *reg &= ~H3_EPHY_SELECT;
+
+ return 0;
+}
+
+static int sun8i_emac_set_syscon(struct emac_eth_dev *priv)
+{
+ int ret;
+ u32 reg;
+
+ reg = readl(priv->sysctl_reg);
+
+ if (priv->variant == H3_EMAC) {
+ ret = sun8i_emac_set_syscon_ephy(priv, &reg);
+ if (ret)
+ return ret;
+ }
+
+ reg &= ~(SC_ETCS_MASK | SC_EPIT);
+ if (priv->variant == H3_EMAC || priv->variant == A64_EMAC)
+ reg &= ~SC_RMII_EN;
+
+ switch (priv->interface) {
+ case PHY_INTERFACE_MODE_MII:
+ /* default */
+ break;
+ case PHY_INTERFACE_MODE_RGMII:
+ reg |= SC_EPIT | SC_ETCS_INT_GMII;
+ break;
+ case PHY_INTERFACE_MODE_RMII:
+ if (priv->variant == H3_EMAC ||
+ priv->variant == A64_EMAC) {
+ reg |= SC_RMII_EN | SC_ETCS_EXT_GMII;
+ break;
+ }
+ /* RMII not supported on A83T */
+ default:
+ debug("%s: Invalid PHY interface\n", __func__);
+ return -EINVAL;
+ }
+
+ writel(reg, priv->sysctl_reg);
+
+ return 0;
+}
+
+static int sun8i_phy_init(struct emac_eth_dev *priv, void *dev)
+{
+ struct phy_device *phydev;
+
+ phydev = phy_connect(priv->bus, priv->phyaddr, dev, priv->interface);
+ if (!phydev)
+ return -ENODEV;
+
+ phy_connect_dev(phydev, dev);
+
+ priv->phydev = phydev;
+ phy_config(priv->phydev);
+
+ return 0;
+}
+
+static void rx_descs_init(struct emac_eth_dev *priv)
+{
+ struct emac_dma_desc *desc_table_p = &priv->rx_chain[0];
+ char *rxbuffs = &priv->rxbuffer[0];
+ struct emac_dma_desc *desc_p;
+ u32 idx;
+
+ /* flush Rx buffers */
+ flush_dcache_range((uintptr_t)rxbuffs, (ulong)rxbuffs +
+ RX_TOTAL_BUFSIZE);
+
+ for (idx = 0; idx < CONFIG_RX_DESCR_NUM; idx++) {
+ desc_p = &desc_table_p[idx];
+ desc_p->buf_addr = (uintptr_t)&rxbuffs[idx * CONFIG_ETH_BUFSIZE]
+ ;
+ desc_p->next = (uintptr_t)&desc_table_p[idx + 1];
+ desc_p->st |= CONFIG_ETH_BUFSIZE;
+ desc_p->status = BIT(31);
+ }
+
+ /* Correcting the last pointer of the chain */
+ desc_p->next = (uintptr_t)&desc_table_p[0];
+
+ flush_dcache_range((uintptr_t)priv->rx_chain,
+ (uintptr_t)priv->rx_chain +
+ sizeof(priv->rx_chain));
+
+ writel((uintptr_t)&desc_table_p[0], (priv->mac_reg + EMAC_RX_DMA_DESC));
+ priv->rx_currdescnum = 0;
+}
+
+static void tx_descs_init(struct emac_eth_dev *priv)
+{
+ struct emac_dma_desc *desc_table_p = &priv->tx_chain[0];
+ char *txbuffs = &priv->txbuffer[0];
+ struct emac_dma_desc *desc_p;
+ u32 idx;
+
+ for (idx = 0; idx < CONFIG_TX_DESCR_NUM; idx++) {
+ desc_p = &desc_table_p[idx];
+ desc_p->buf_addr = (uintptr_t)&txbuffs[idx * CONFIG_ETH_BUFSIZE]
+ ;
+ desc_p->next = (uintptr_t)&desc_table_p[idx + 1];
+ desc_p->status = (1 << 31);
+ desc_p->st = 0;
+ }
+
+ /* Correcting the last pointer of the chain */
+ desc_p->next = (uintptr_t)&desc_table_p[0];
+
+ /* Flush all Tx buffer descriptors */
+ flush_dcache_range((uintptr_t)priv->tx_chain,
+ (uintptr_t)priv->tx_chain +
+ sizeof(priv->tx_chain));
+
+ writel((uintptr_t)&desc_table_p[0], priv->mac_reg + EMAC_TX_DMA_DESC);
+ priv->tx_currdescnum = 0;
+}
+
+static int _sun8i_emac_eth_init(struct emac_eth_dev *priv, u8 *enetaddr)
+{
+ u32 reg, v;
+ int timeout = 100;
+
+ reg = readl((priv->mac_reg + EMAC_CTL1));
+
+ if (!(reg & 0x1)) {
+ /* Soft reset MAC */
+ setbits_le32((priv->mac_reg + EMAC_CTL1), 0x1);
+ do {
+ reg = readl(priv->mac_reg + EMAC_CTL1);
+ } while ((reg & 0x01) != 0 && (--timeout));
+ if (!timeout) {
+ printf("%s: Timeout\n", __func__);
+ return -1;
+ }
+ }
+
+ /* Rewrite mac address after reset */
+ _sun8i_write_hwaddr(priv, enetaddr);
+
+ v = readl(priv->mac_reg + EMAC_TX_CTL1);
+ /* TX_MD Transmission starts after a full frame located in TX DMA FIFO*/
+ v |= BIT(1);
+ writel(v, priv->mac_reg + EMAC_TX_CTL1);
+
+ v = readl(priv->mac_reg + EMAC_RX_CTL1);
+ /* RX_MD RX DMA reads data from RX DMA FIFO to host memory after a
+ * complete frame has been written to RX DMA FIFO
+ */
+ v |= BIT(1);
+ writel(v, priv->mac_reg + EMAC_RX_CTL1);
+
+ /* DMA */
+ writel(8 << 24, priv->mac_reg + EMAC_CTL1);
+
+ /* Initialize rx/tx descriptors */
+ rx_descs_init(priv);
+ tx_descs_init(priv);
+
+ /* PHY Start Up */
+ genphy_parse_link(priv->phydev);
+
+ sun8i_adjust_link(priv, priv->phydev);
+
+ /* Start RX DMA */
+ v = readl(priv->mac_reg + EMAC_RX_CTL1);
+ v |= BIT(30);
+ writel(v, priv->mac_reg + EMAC_RX_CTL1);
+ /* Start TX DMA */
+ v = readl(priv->mac_reg + EMAC_TX_CTL1);
+ v |= BIT(30);
+ writel(v, priv->mac_reg + EMAC_TX_CTL1);
+
+ /* Enable RX/TX */
+ setbits_le32(priv->mac_reg + EMAC_RX_CTL0, BIT(31));
+ setbits_le32(priv->mac_reg + EMAC_TX_CTL0, BIT(31));
+
+ return 0;
+}
+
+static int parse_phy_pins(struct udevice *dev)
+{
+ int offset;
+ const char *pin_name;
+ int drive, pull, i;
+
+ offset = fdtdec_lookup_phandle(gd->fdt_blob, dev->of_offset,
+ "pinctrl-0");
+ if (offset < 0) {
+ printf("WARNING: emac: cannot find pinctrl-0 node\n");
+ return offset;
+ }
+
+ drive = fdt_getprop_u32_default_node(gd->fdt_blob, offset, 0,
+ "allwinner,drive", 4);
+ pull = fdt_getprop_u32_default_node(gd->fdt_blob, offset, 0,
+ "allwinner,pull", 0);
+ for (i = 0; ; i++) {
+ int pin;
+
+ if (fdt_get_string_index(gd->fdt_blob, offset,
+ "allwinner,pins", i, &pin_name))
+ break;
+ if (pin_name[0] != 'P')
+ continue;
+ pin = (pin_name[1] - 'A') << 5;
+ if (pin >= 26 << 5)
+ continue;
+ pin += simple_strtol(&pin_name[2], NULL, 10);
+
+ sunxi_gpio_set_cfgpin(pin, SUN8I_GPD8_GMAC);
+ sunxi_gpio_set_drv(pin, drive);
+ sunxi_gpio_set_pull(pin, pull);
+ }
+
+ if (!i) {
+ printf("WARNING: emac: cannot find allwinner,pins property\n");
+ return -2;
+ }
+
+ return 0;
+}
+
+static int _sun8i_eth_recv(struct emac_eth_dev *priv, uchar **packetp)
+{
+ u32 status, desc_num = priv->rx_currdescnum;
+ struct emac_dma_desc *desc_p = &priv->rx_chain[desc_num];
+ int length = -EAGAIN;
+ int good_packet = 1;
+ uintptr_t desc_start = (uintptr_t)desc_p;
+ uintptr_t desc_end = desc_start +
+ roundup(sizeof(*desc_p), ARCH_DMA_MINALIGN);
+
+ ulong data_start = (uintptr_t)desc_p->buf_addr;
+ ulong data_end;
+
+ /* Invalidate entire buffer descriptor */
+ invalidate_dcache_range(desc_start, desc_end);
+
+ status = desc_p->status;
+
+ /* Check for DMA own bit */
+ if (!(status & BIT(31))) {
+ length = (desc_p->status >> 16) & 0x3FFF;
+
+ if (length < 0x40) {
+ good_packet = 0;
+ debug("RX: Bad Packet (runt)\n");
+ }
+
+ data_end = data_start + length;
+ /* Invalidate received data */
+ invalidate_dcache_range(rounddown(data_start,
+ ARCH_DMA_MINALIGN),
+ roundup(data_end,
+ ARCH_DMA_MINALIGN));
+ if (good_packet) {
+ if (length > CONFIG_ETH_BUFSIZE) {
+ printf("Received packet is too big (len=%d)\n",
+ length);
+ return -EMSGSIZE;
+ }
+ *packetp = (uchar *)(ulong)desc_p->buf_addr;
+ return length;
+ }
+ }
+
+ return length;
+}
+
+static int _sun8i_emac_eth_send(struct emac_eth_dev *priv, void *packet,
+ int len)
+{
+ u32 v, desc_num = priv->tx_currdescnum;
+ struct emac_dma_desc *desc_p = &priv->tx_chain[desc_num];
+ uintptr_t desc_start = (uintptr_t)desc_p;
+ uintptr_t desc_end = desc_start +
+ roundup(sizeof(*desc_p), ARCH_DMA_MINALIGN);
+
+ uintptr_t data_start = (uintptr_t)desc_p->buf_addr;
+ uintptr_t data_end = data_start +
+ roundup(len, ARCH_DMA_MINALIGN);
+
+ /* Invalidate entire buffer descriptor */
+ invalidate_dcache_range(desc_start, desc_end);
+
+ desc_p->st = len;
+ /* Mandatory undocumented bit */
+ desc_p->st |= BIT(24);
+
+ memcpy((void *)data_start, packet, len);
+
+ /* Flush data to be sent */
+ flush_dcache_range(data_start, data_end);
+
+ /* frame end */
+ desc_p->st |= BIT(30);
+ desc_p->st |= BIT(31);
+
+ /*frame begin */
+ desc_p->st |= BIT(29);
+ desc_p->status = BIT(31);
+
+ /*Descriptors st and status field has changed, so FLUSH it */
+ flush_dcache_range(desc_start, desc_end);
+
+ /* Move to next Descriptor and wrap around */
+ if (++desc_num >= CONFIG_TX_DESCR_NUM)
+ desc_num = 0;
+ priv->tx_currdescnum = desc_num;
+
+ /* Start the DMA */
+ v = readl(priv->mac_reg + EMAC_TX_CTL1);
+ v |= BIT(31);/* mandatory */
+ v |= BIT(30);/* mandatory */
+ writel(v, priv->mac_reg + EMAC_TX_CTL1);
+
+ return 0;
+}
+
+static int sun8i_eth_write_hwaddr(struct udevice *dev)
+{
+ struct eth_pdata *pdata = dev_get_platdata(dev);
+ struct emac_eth_dev *priv = dev_get_priv(dev);
+
+ return _sun8i_write_hwaddr(priv, pdata->enetaddr);
+}
+
+static void sun8i_emac_board_setup(struct emac_eth_dev *priv)
+{
+ struct sunxi_ccm_reg *ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
+
+ if (priv->use_internal_phy) {
+ /* Set clock gating for ephy */
+ setbits_le32(&ccm->bus_gate4, BIT(AHB_GATE_OFFSET_EPHY));
+
+ /* Set Tx clock source as MII with rate 25 MZ */
+ setbits_le32(priv->sysctl_reg, SCTL_EMAC_TX_CLK_SRC_MII |
+ SCTL_EMAC_EPIT_MII | SCTL_EMAC_CLK_SEL);
+ /* Deassert EPHY */
+ setbits_le32(&ccm->ahb_reset2_cfg, BIT(AHB_RESET_OFFSET_EPHY));
+ }
+
+ /* Set clock gating for emac */
+ setbits_le32(&ccm->ahb_gate0, BIT(AHB_GATE_OFFSET_GMAC));
+
+ /* Set EMAC clock */
+ setbits_le32(&ccm->axi_gate, (BIT(1) | BIT(0)));
+
+ /* De-assert EMAC */
+ setbits_le32(&ccm->ahb_reset0_cfg, BIT(AHB_RESET_OFFSET_GMAC));
+}
+
+static int sun8i_mdio_init(const char *name, struct emac_eth_dev *priv)
+{
+ struct mii_dev *bus = mdio_alloc();
+
+ if (!bus) {
+ debug("Failed to allocate MDIO bus\n");
+ return -ENOMEM;
+ }
+
+ bus->read = sun8i_mdio_read;
+ bus->write = sun8i_mdio_write;
+ snprintf(bus->name, sizeof(bus->name), name);
+ bus->priv = (void *)priv;
+
+ return mdio_register(bus);
+}
+
+static int sun8i_emac_eth_start(struct udevice *dev)
+{
+ struct eth_pdata *pdata = dev_get_platdata(dev);
+
+ return _sun8i_emac_eth_init(dev->priv, pdata->enetaddr);
+}
+
+static int sun8i_emac_eth_send(struct udevice *dev, void *packet, int length)
+{
+ struct emac_eth_dev *priv = dev_get_priv(dev);
+
+ return _sun8i_emac_eth_send(priv, packet, length);
+}
+
+static int sun8i_emac_eth_recv(struct udevice *dev, int flags, uchar **packetp)
+{
+ struct emac_eth_dev *priv = dev_get_priv(dev);
+
+ return _sun8i_eth_recv(priv, packetp);
+}
+
+static int _sun8i_free_pkt(struct emac_eth_dev *priv)
+{
+ u32 desc_num = priv->rx_currdescnum;
+ struct emac_dma_desc *desc_p = &priv->rx_chain[desc_num];
+ uintptr_t desc_start = (uintptr_t)desc_p;
+ uintptr_t desc_end = desc_start +
+ roundup(sizeof(u32), ARCH_DMA_MINALIGN);
+
+ /* Make the current descriptor valid again */
+ desc_p->status |= BIT(31);
+
+ /* Flush Status field of descriptor */
+ flush_dcache_range(desc_start, desc_end);
+
+ /* Move to next desc and wrap-around condition. */
+ if (++desc_num >= CONFIG_RX_DESCR_NUM)
+ desc_num = 0;
+ priv->rx_currdescnum = desc_num;
+
+ return 0;
+}
+
+static int sun8i_eth_free_pkt(struct udevice *dev, uchar *packet,
+ int length)
+{
+ struct emac_eth_dev *priv = dev_get_priv(dev);
+
+ return _sun8i_free_pkt(priv);
+}
+
+static void sun8i_emac_eth_stop(struct udevice *dev)
+{
+ struct emac_eth_dev *priv = dev_get_priv(dev);
+
+ /* Stop Rx/Tx transmitter */
+ clrbits_le32(priv->mac_reg + EMAC_RX_CTL0, BIT(31));
+ clrbits_le32(priv->mac_reg + EMAC_TX_CTL0, BIT(31));
+
+ /* Stop TX DMA */
+ clrbits_le32(priv->mac_reg + EMAC_TX_CTL1, BIT(30));
+
+ phy_shutdown(priv->phydev);
+}
+
+static int sun8i_emac_eth_probe(struct udevice *dev)
+{
+ struct eth_pdata *pdata = dev_get_platdata(dev);
+ struct emac_eth_dev *priv = dev_get_priv(dev);
+
+ priv->mac_reg = (void *)pdata->iobase;
+
+ sun8i_emac_board_setup(priv);
+
+ sun8i_mdio_init(dev->name, priv);
+ priv->bus = miiphy_get_dev_by_name(dev->name);
+
+ sun8i_emac_set_syscon(priv);
+
+ return sun8i_phy_init(priv, dev);
+}
+
+static const struct eth_ops sun8i_emac_eth_ops = {
+ .start = sun8i_emac_eth_start,
+ .write_hwaddr = sun8i_eth_write_hwaddr,
+ .send = sun8i_emac_eth_send,
+ .recv = sun8i_emac_eth_recv,
+ .free_pkt = sun8i_eth_free_pkt,
+ .stop = sun8i_emac_eth_stop,
+};
+
+static int sun8i_emac_eth_ofdata_to_platdata(struct udevice *dev)
+{
+ struct eth_pdata *pdata = dev_get_platdata(dev);
+ struct emac_eth_dev *priv = dev_get_priv(dev);
+ const char *phy_mode;
+ int offset = 0;
+
+ pdata->iobase = dev_get_addr_name(dev, "emac");
+ priv->sysctl_reg = dev_get_addr_name(dev, "syscon");
+
+ pdata->phy_interface = -1;
+ priv->phyaddr = -1;
+ priv->use_internal_phy = false;
+
+ offset = fdtdec_lookup_phandle(gd->fdt_blob, dev->of_offset,
+ "phy");
+ if (offset > 0)
+ priv->phyaddr = fdtdec_get_int(gd->fdt_blob, offset, "reg",
+ -1);
+
+ phy_mode = fdt_getprop(gd->fdt_blob, dev->of_offset, "phy-mode", NULL);
+
+ if (phy_mode)
+ pdata->phy_interface = phy_get_interface_by_name(phy_mode);
+ printf("phy interface%d\n", pdata->phy_interface);
+
+ if (pdata->phy_interface == -1) {
+ debug("%s: Invalid PHY interface '%s'\n", __func__, phy_mode);
+ return -EINVAL;
+ }
+
+ priv->variant = dev_get_driver_data(dev);
+
+ if (!priv->variant) {
+ printf("%s: Missing variant '%s'\n", __func__,
+ (char *)priv->variant);
+ return -EINVAL;
+ }
+
+ if (priv->variant == H3_EMAC) {
+ if (fdt_getprop(gd->fdt_blob, dev->of_offset,
+ "allwinner,use-internal-phy", NULL))
+ priv->use_internal_phy = true;
+ }
+
+ priv->interface = pdata->phy_interface;
+
+ if (!priv->use_internal_phy)
+ parse_phy_pins(dev);
+
+ return 0;
+}
+
+static const struct udevice_id sun8i_emac_eth_ids[] = {
+ {.compatible = "allwinner,sun8i-h3-emac", .data = (uintptr_t)H3_EMAC },
+ {.compatible = "allwinner,sun50i-a64-emac",
+ .data = (uintptr_t)A64_EMAC },
+ {.compatible = "allwinner,sun8i-a83t-emac",
+ .data = (uintptr_t)A83T_EMAC },
+ { }
+};
+
+U_BOOT_DRIVER(eth_sun8i_emac) = {
+ .name = "eth_sun8i_emac",
+ .id = UCLASS_ETH,
+ .of_match = sun8i_emac_eth_ids,
+ .ofdata_to_platdata = sun8i_emac_eth_ofdata_to_platdata,
+ .probe = sun8i_emac_eth_probe,
+ .ops = &sun8i_emac_eth_ops,
+ .priv_auto_alloc_size = sizeof(struct emac_eth_dev),
+ .platdata_auto_alloc_size = sizeof(struct eth_pdata),
+ .flags = DM_FLAG_ALLOC_PRIV_DMA,
+};
diff --git a/drivers/pci/pci_rom.c b/drivers/pci/pci_rom.c
index 9eb605be74..399055b078 100644
--- a/drivers/pci/pci_rom.c
+++ b/drivers/pci/pci_rom.c
@@ -39,14 +39,9 @@ __weak bool board_should_run_oprom(struct udevice *dev)
return true;
}
-static bool should_load_oprom(struct udevice *dev)
+__weak bool board_should_load_oprom(struct udevice *dev)
{
- if (IS_ENABLED(CONFIG_ALWAYS_LOAD_OPROM))
- return 1;
- if (board_should_run_oprom(dev))
- return 1;
-
- return 0;
+ return true;
}
__weak uint32_t board_map_oprom_vendev(uint32_t vendev)
@@ -278,7 +273,7 @@ int dm_pci_run_vga_bios(struct udevice *dev, int (*int15_handler)(void),
return -ENODEV;
}
- if (!should_load_oprom(dev))
+ if (!board_should_load_oprom(dev))
return -ENXIO;
ret = pci_rom_probe(dev, &rom);
diff --git a/drivers/pinctrl/rockchip/pinctrl_rk3288.c b/drivers/pinctrl/rockchip/pinctrl_rk3288.c
index 1fa1daa939..8cb3b8228e 100644
--- a/drivers/pinctrl/rockchip/pinctrl_rk3288.c
+++ b/drivers/pinctrl/rockchip/pinctrl_rk3288.c
@@ -476,6 +476,7 @@ static int rk3288_pinctrl_request(struct udevice *dev, int func, int flags)
static int rk3288_pinctrl_get_periph_id(struct udevice *dev,
struct udevice *periph)
{
+#if !CONFIG_IS_ENABLED(OF_PLATDATA)
u32 cell[3];
int ret;
@@ -506,6 +507,7 @@ static int rk3288_pinctrl_get_periph_id(struct udevice *dev,
case 103:
return PERIPH_ID_HDMI;
}
+#endif
return -ENOENT;
}
@@ -664,8 +666,12 @@ static struct pinctrl_ops rk3288_pinctrl_ops = {
static int rk3288_pinctrl_bind(struct udevice *dev)
{
+#if CONFIG_IS_ENABLED(OF_PLATDATA)
+ return 0;
+#else
/* scan child GPIO banks */
return dm_scan_fdt_node(dev, gd->fdt_blob, dev->of_offset, false);
+#endif
}
#ifndef CONFIG_SPL_BUILD
@@ -719,7 +725,7 @@ static const struct udevice_id rk3288_pinctrl_ids[] = {
};
U_BOOT_DRIVER(pinctrl_rk3288) = {
- .name = "pinctrl_rk3288",
+ .name = "rockchip_rk3288_pinctrl",
.id = UCLASS_PINCTRL,
.of_match = rk3288_pinctrl_ids,
.priv_auto_alloc_size = sizeof(struct rk3288_pinctrl_priv),
diff --git a/drivers/rtc/date.c b/drivers/rtc/date.c
index 8c643a0b46..bfa2e1378e 100644
--- a/drivers/rtc/date.c
+++ b/drivers/rtc/date.c
@@ -5,10 +5,6 @@
* SPDX-License-Identifier: GPL-2.0+
*/
-/*
- * Date & Time support for Philips PCF8563 RTC
- */
-
#include <common.h>
#include <command.h>
#include <errno.h>
@@ -28,53 +24,52 @@ static int month_days[12] = {
31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
};
+static int month_offset[] = {
+ 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334
+};
+
/*
* This only works for the Gregorian calendar - i.e. after 1752 (in the UK)
*/
int rtc_calc_weekday(struct rtc_time *tm)
{
- int leapsToDate;
- int lastYear;
+ int leaps_to_date;
+ int last_year;
int day;
- int MonthOffset[] = { 0,31,59,90,120,151,181,212,243,273,304,334 };
if (tm->tm_year < 1753)
- return -EINVAL;
- lastYear=tm->tm_year-1;
+ return -1;
+ last_year = tm->tm_year - 1;
- /*
- * Number of leap corrections to apply up to end of last year
- */
- leapsToDate = lastYear/4 - lastYear/100 + lastYear/400;
+ /* Number of leap corrections to apply up to end of last year */
+ leaps_to_date = last_year / 4 - last_year / 100 + last_year / 400;
/*
* This year is a leap year if it is divisible by 4 except when it is
* divisible by 100 unless it is divisible by 400
*
- * e.g. 1904 was a leap year, 1900 was not, 1996 is, and 2000 will be
+ * e.g. 1904 was a leap year, 1900 was not, 1996 is, and 2000 is.
*/
- if((tm->tm_year%4==0) &&
- ((tm->tm_year%100!=0) || (tm->tm_year%400==0)) &&
- (tm->tm_mon>2)) {
- /*
- * We are past Feb. 29 in a leap year
- */
- day=1;
+ if (tm->tm_year % 4 == 0 &&
+ ((tm->tm_year % 100 != 0) || (tm->tm_year % 400 == 0)) &&
+ tm->tm_mon > 2) {
+ /* We are past Feb. 29 in a leap year */
+ day = 1;
} else {
- day=0;
+ day = 0;
}
- day += lastYear*365 + leapsToDate + MonthOffset[tm->tm_mon-1] + tm->tm_mday;
-
- tm->tm_wday=day%7;
+ day += last_year * 365 + leaps_to_date + month_offset[tm->tm_mon - 1] +
+ tm->tm_mday;
+ tm->tm_wday = day % 7;
return 0;
}
int rtc_to_tm(int tim, struct rtc_time *tm)
{
- register int i;
- register long hms, day;
+ register int i;
+ register long hms, day;
day = tim / SECDAY;
hms = tim % SECDAY;
@@ -85,22 +80,19 @@ int rtc_to_tm(int tim, struct rtc_time *tm)
tm->tm_sec = (hms % 3600) % 60;
/* Number of years in days */
- for (i = STARTOFTIME; day >= days_in_year(i); i++) {
+ for (i = STARTOFTIME; day >= days_in_year(i); i++)
day -= days_in_year(i);
- }
tm->tm_year = i;
/* Number of months in days left */
- if (leapyear(tm->tm_year)) {
+ if (leapyear(tm->tm_year))
days_in_month(FEBRUARY) = 29;
- }
- for (i = 1; day >= days_in_month(i); i++) {
+ for (i = 1; day >= days_in_month(i); i++)
day -= days_in_month(i);
- }
days_in_month(FEBRUARY) = 28;
tm->tm_mon = i;
- /* Days are what is left over (+1) from all that. */
+ /* Days are what is left over (+1) from all that */
tm->tm_mday = day + 1;
/* Zero unused fields */
@@ -113,19 +105,20 @@ int rtc_to_tm(int tim, struct rtc_time *tm)
return rtc_calc_weekday(tm);
}
-/* Converts Gregorian date to seconds since 1970-01-01 00:00:00.
+/*
+ * Converts Gregorian date to seconds since 1970-01-01 00:00:00.
* Assumes input in normal date format, i.e. 1980-12-31 23:59:59
* => year=1980, mon=12, day=31, hour=23, min=59, sec=59.
*
* [For the Julian calendar (which was used in Russia before 1917,
* Britain & colonies before 1752, anywhere else before 1582,
* and is still in use by some communities) leave out the
- * -year/100+year/400 terms, and add 10.]
+ * -year / 100 + year / 400 terms, and add 10.]
*
* This algorithm was first published by Gauss (I think).
*
* WARNING: this function will overflow on 2106-02-07 06:28:16 on
- * machines were long is 32-bit! (However, as time_t is signed, we
+ * machines where long is 32-bit! (However, as time_t is signed, we
* will already get problems at other places on 2038-01-19 03:14:08)
*/
unsigned long rtc_mktime(const struct rtc_time *tm)
@@ -135,8 +128,8 @@ unsigned long rtc_mktime(const struct rtc_time *tm)
int days, hours;
mon -= 2;
- if (0 >= (int)mon) { /* 1..12 -> 11,12,1..10 */
- mon += 12; /* Puts Feb last since it has leap day */
+ if (0 >= (int)mon) { /* 1..12 -> 11, 12, 1..10 */
+ mon += 12; /* Puts Feb last since it has leap day */
year -= 1;
}
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
index 0e3890391b..9ff7234d61 100644
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -312,6 +312,15 @@ config SYS_NS16550
be used. It can be a constant or a function to get clock, eg,
get_serial_clock().
+config ROCKCHIP_SERIAL
+ bool "Rockchip on-chip UART support"
+ depends on DM_SERIAL && SPL_OF_PLATDATA
+ help
+ Select this to enable a debug UART for Rockchip devices when using
+ CONFIG_OF_PLATDATA (i.e. a compiled-in device tree replacemenmt).
+ This uses the ns16550 driver, converting the platdata from of-platdata
+ to the ns16550 format.
+
config SANDBOX_SERIAL
bool "Sandbox UART support"
depends on SANDBOX
diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile
index 92cbea5913..6986d659ab 100644
--- a/drivers/serial/Makefile
+++ b/drivers/serial/Makefile
@@ -28,6 +28,9 @@ obj-$(CONFIG_S5P) += serial_s5p.o
obj-$(CONFIG_MXC_UART) += serial_mxc.o
obj-$(CONFIG_PXA_SERIAL) += serial_pxa.o
obj-$(CONFIG_MESON_SERIAL) += serial_meson.o
+ifdef CONFIG_SPL_BUILD
+obj-$(CONFIG_ROCKCHIP_SERIAL) += serial_rockchip.o
+endif
obj-$(CONFIG_S3C24X0_SERIAL) += serial_s3c24x0.o
obj-$(CONFIG_XILINX_UARTLITE) += serial_xuartlite.o
obj-$(CONFIG_SANDBOX_SERIAL) += sandbox.o
diff --git a/drivers/serial/ns16550.c b/drivers/serial/ns16550.c
index c6cb3eb500..88fca15357 100644
--- a/drivers/serial/ns16550.c
+++ b/drivers/serial/ns16550.c
@@ -347,7 +347,7 @@ int ns16550_serial_probe(struct udevice *dev)
return 0;
}
-#if CONFIG_IS_ENABLED(OF_CONTROL)
+#if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)
int ns16550_serial_ofdata_to_platdata(struct udevice *dev)
{
struct ns16550_platdata *plat = dev->platdata;
@@ -416,6 +416,7 @@ const struct dm_serial_ops ns16550_serial_ops = {
.setbrg = ns16550_serial_setbrg,
};
+#if !CONFIG_IS_ENABLED(OF_PLATDATA)
#if CONFIG_IS_ENABLED(OF_CONTROL)
/*
* Please consider existing compatible strings before adding a new
@@ -452,4 +453,5 @@ U_BOOT_DRIVER(ns16550_serial) = {
.flags = DM_FLAG_PRE_RELOC,
};
#endif
+#endif /* !OF_PLATDATA */
#endif /* CONFIG_DM_SERIAL */
diff --git a/drivers/serial/sandbox.c b/drivers/serial/sandbox.c
index 58f882b22a..bcc3465312 100644
--- a/drivers/serial/sandbox.c
+++ b/drivers/serial/sandbox.c
@@ -115,7 +115,9 @@ static int sandbox_serial_pending(struct udevice *dev, bool input)
return 0;
os_usleep(100);
+#ifndef CONFIG_SPL_BUILD
video_sync_all();
+#endif
if (next_index == serial_buf_read)
return 1; /* buffer full */
diff --git a/drivers/serial/serial-uclass.c b/drivers/serial/serial-uclass.c
index 0ce5c44f33..19f38e162e 100644
--- a/drivers/serial/serial-uclass.c
+++ b/drivers/serial/serial-uclass.c
@@ -33,7 +33,13 @@ static void serial_find_console_or_panic(void)
struct udevice *dev;
int node;
- if (CONFIG_IS_ENABLED(OF_CONTROL) && blob) {
+ if (CONFIG_IS_ENABLED(OF_PLATDATA)) {
+ uclass_first_device(UCLASS_SERIAL, &dev);
+ if (dev) {
+ gd->cur_serial_dev = dev;
+ return;
+ }
+ } else if (CONFIG_IS_ENABLED(OF_CONTROL) && blob) {
/* Check for a chosen console */
node = fdtdec_get_chosen_node(blob, "stdout-path");
if (node < 0) {
diff --git a/drivers/serial/serial_rockchip.c b/drivers/serial/serial_rockchip.c
new file mode 100644
index 0000000000..6bac95a414
--- /dev/null
+++ b/drivers/serial/serial_rockchip.c
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2015 Google, Inc
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <debug_uart.h>
+#include <dm.h>
+#include <dt-structs.h>
+#include <ns16550.h>
+#include <serial.h>
+#include <asm/arch/clock.h>
+
+struct rockchip_uart_platdata {
+ struct dtd_rockchip_rk3288_uart dtplat;
+ struct ns16550_platdata plat;
+};
+
+struct dtd_rockchip_rk3288_uart *dtplat, s_dtplat;
+
+static int rockchip_serial_probe(struct udevice *dev)
+{
+ struct rockchip_uart_platdata *plat = dev_get_platdata(dev);
+
+ /* Create some new platform data for the standard driver */
+ plat->plat.base = plat->dtplat.reg[0];
+ plat->plat.reg_shift = plat->dtplat.reg_shift;
+ plat->plat.clock = plat->dtplat.clock_frequency;
+ dev->platdata = &plat->plat;
+
+ return ns16550_serial_probe(dev);
+}
+
+U_BOOT_DRIVER(rockchip_rk3288_uart) = {
+ .name = "rockchip_rk3288_uart",
+ .id = UCLASS_SERIAL,
+ .priv_auto_alloc_size = sizeof(struct NS16550),
+ .platdata_auto_alloc_size = sizeof(struct rockchip_uart_platdata),
+ .probe = rockchip_serial_probe,
+ .ops = &ns16550_serial_ops,
+ .flags = DM_FLAG_PRE_RELOC,
+};
diff --git a/drivers/serial/serial_stm32x7.c b/drivers/serial/serial_stm32x7.c
index cfbfab7e41..592c0bde36 100644
--- a/drivers/serial/serial_stm32x7.c
+++ b/drivers/serial/serial_stm32x7.c
@@ -9,6 +9,7 @@
#include <dm.h>
#include <asm/io.h>
#include <serial.h>
+#include <asm/arch/stm32.h>
#include <dm/platform_data/serial_stm32x7.h>
#include "serial_stm32x7.h"
@@ -18,7 +19,20 @@ static int stm32_serial_setbrg(struct udevice *dev, int baudrate)
{
struct stm32x7_serial_platdata *plat = dev->platdata;
struct stm32_usart *const usart = plat->base;
- writel(plat->clock/baudrate, &usart->brr);
+ u32 clock, int_div, frac_div, tmp;
+
+ if (((u32)usart & STM32_BUS_MASK) == APB1_PERIPH_BASE)
+ clock = clock_get(CLOCK_APB1);
+ else if (((u32)usart & STM32_BUS_MASK) == APB2_PERIPH_BASE)
+ clock = clock_get(CLOCK_APB2);
+ else
+ return -EINVAL;
+
+ int_div = (25 * clock) / (4 * baudrate);
+ tmp = ((int_div / 100) << USART_BRR_M_SHIFT) & USART_BRR_M_MASK;
+ frac_div = int_div - (100 * (tmp >> USART_BRR_M_SHIFT));
+ tmp |= (((frac_div * 16) + 50) / 100) & USART_BRR_F_MASK;
+ writel(tmp, &usart->brr);
return 0;
}
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);
diff --git a/drivers/usb/musb-new/musb_dsps.c b/drivers/usb/musb-new/musb_dsps.c
index bb7c952292..a71db76d7c 100644
--- a/drivers/usb/musb-new/musb_dsps.c
+++ b/drivers/usb/musb-new/musb_dsps.c
@@ -627,7 +627,7 @@ static int __devinit dsps_probe(struct platform_device *pdev)
/* get memory resource */
iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!iomem) {
- dev_err(&pdev->dev, "failed to get usbss mem resourse\n");
+ dev_err(&pdev->dev, "failed to get usbss mem resource\n");
ret = -ENODEV;
goto err1;
}
diff --git a/drivers/video/tegra.c b/drivers/video/tegra.c
index 217f05f9e2..92214d61b2 100644
--- a/drivers/video/tegra.c
+++ b/drivers/video/tegra.c
@@ -251,7 +251,7 @@ static int setup_window(struct disp_ctl_win *win,
/**
* Register a new display based on device tree configuration.
*
- * The frame buffer can be positioned by U-Boot or overriden by the fdt.
+ * The frame buffer can be positioned by U-Boot or overridden by the fdt.
* You should pass in the U-Boot address here, and check the contents of
* struct tegra_lcd_priv to see what was actually chosen.
*