summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorTom Rini <trini@konsulko.com>2015-10-20 21:59:40 -0400
committerTom Rini <trini@konsulko.com>2015-10-20 21:59:40 -0400
commite8d124fae0f3dff87348c989aa65ecf9b6eadc14 (patch)
treeff4f4709e54cde4d97349463c335d00f2d631e42 /drivers
parentfd8133b725198978865ead730ff20d3991e05f20 (diff)
parent5b37212a3d78f546b5ef3f97a75155b3a0fd88cb (diff)
downloadtalos-obmc-uboot-e8d124fae0f3dff87348c989aa65ecf9b6eadc14.tar.gz
talos-obmc-uboot-e8d124fae0f3dff87348c989aa65ecf9b6eadc14.zip
Merge git://git.denx.de/u-boot-marvell
Diffstat (limited to 'drivers')
-rw-r--r--drivers/core/Kconfig30
-rw-r--r--drivers/core/device.c20
-rw-r--r--drivers/mmc/mv_sdhci.c41
-rw-r--r--drivers/usb/host/Kconfig7
-rw-r--r--drivers/usb/host/ehci-marvell.c86
5 files changed, 168 insertions, 16 deletions
diff --git a/drivers/core/Kconfig b/drivers/core/Kconfig
index 41f4e695e8..15681df6d3 100644
--- a/drivers/core/Kconfig
+++ b/drivers/core/Kconfig
@@ -120,4 +120,34 @@ config SPL_SIMPLE_BUS
Supports the 'simple-bus' driver, which is used on some systems
in SPL.
+config OF_TRANSLATE
+ bool "Translate addresses using fdt_translate_address"
+ depends on DM && OF_CONTROL
+ default y
+ help
+ If this option is enabled, the reg property will be translated
+ using the fdt_translate_address() function. This is necessary
+ on some platforms (e.g. MVEBU) using complex "ranges"
+ properties in many nodes. As this translation is not handled
+ correctly in the default simple_bus_translate() function.
+
+ If this option is not enabled, simple_bus_translate() will be
+ used for the address translation. This function is faster and
+ smaller in size than fdt_translate_address().
+
+config SPL_OF_TRANSLATE
+ bool "Translate addresses using fdt_translate_address"
+ depends on SPL_DM && SPL_OF_CONTROL
+ default n
+ help
+ If this option is enabled, the reg property will be translated
+ using the fdt_translate_address() function. This is necessary
+ on some platforms (e.g. MVEBU) using complex "ranges"
+ properties in many nodes. As this translation is not handled
+ correctly in the default simple_bus_translate() function.
+
+ If this option is not enabled, simple_bus_translate() will be
+ used for the address translation. This function is faster and
+ smaller in size than fdt_translate_address().
+
endmenu
diff --git a/drivers/core/device.c b/drivers/core/device.c
index 833a803696..a3dc2ca679 100644
--- a/drivers/core/device.c
+++ b/drivers/core/device.c
@@ -11,6 +11,7 @@
#include <common.h>
#include <fdtdec.h>
+#include <fdt_support.h>
#include <malloc.h>
#include <dm/device.h>
#include <dm/device-internal.h>
@@ -585,6 +586,25 @@ fdt_addr_t dev_get_addr(struct udevice *dev)
#if CONFIG_IS_ENABLED(OF_CONTROL)
fdt_addr_t addr;
+ if (CONFIG_IS_ENABLED(OF_TRANSLATE)) {
+ const fdt32_t *reg;
+
+ reg = fdt_getprop(gd->fdt_blob, dev->of_offset, "reg", NULL);
+ if (!reg)
+ return FDT_ADDR_T_NONE;
+
+ /*
+ * Use the full-fledged translate function for complex
+ * bus setups.
+ */
+ return fdt_translate_address((void *)gd->fdt_blob,
+ dev->of_offset, reg);
+ }
+
+ /*
+ * Use the "simple" translate function for less complex
+ * bus setups.
+ */
addr = fdtdec_get_addr_size_auto_parent(gd->fdt_blob,
dev->parent->of_offset,
dev->of_offset, "reg",
diff --git a/drivers/mmc/mv_sdhci.c b/drivers/mmc/mv_sdhci.c
index 75fa014931..82c695f906 100644
--- a/drivers/mmc/mv_sdhci.c
+++ b/drivers/mmc/mv_sdhci.c
@@ -1,6 +1,41 @@
+/*
+ * Marvell SD Host Controller Interface
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
#include <common.h>
#include <malloc.h>
#include <sdhci.h>
+#include <linux/mbus.h>
+
+#define SDHCI_WINDOW_CTRL(win) (0x4080 + ((win) << 4))
+#define SDHCI_WINDOW_BASE(win) (0x4084 + ((win) << 4))
+
+static void sdhci_mvebu_mbus_config(void __iomem *base)
+{
+ const struct mbus_dram_target_info *dram;
+ int i;
+
+ dram = mvebu_mbus_dram_info();
+
+ for (i = 0; i < 4; i++) {
+ writel(0, base + SDHCI_WINDOW_CTRL(i));
+ writel(0, base + SDHCI_WINDOW_BASE(i));
+ }
+
+ for (i = 0; i < dram->num_cs; i++) {
+ const struct mbus_dram_window *cs = dram->cs + i;
+
+ /* Write size, attributes and target id to control register */
+ writel(((cs->size - 1) & 0xffff0000) | (cs->mbus_attr << 8) |
+ (dram->mbus_dram_target_id << 4) | 1,
+ base + SDHCI_WINDOW_CTRL(i));
+
+ /* Write base address to base register */
+ writel(cs->base, base + SDHCI_WINDOW_BASE(i));
+ }
+}
#ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS
static struct sdhci_ops mv_ops;
@@ -47,6 +82,12 @@ int mv_sdh_init(unsigned long regbase, u32 max_clk, u32 min_clk, u32 quirks)
mv_ops.write_b = mv_sdhci_writeb;
host->ops = &mv_ops;
#endif
+
+ if (CONFIG_IS_ENABLED(ARCH_MVEBU)) {
+ /* Configure SDHCI MBUS mbus bridge windows */
+ sdhci_mvebu_mbus_config((void __iomem *)regbase);
+ }
+
if (quirks & SDHCI_QUIRK_REG32_RW)
host->version = sdhci_readl(host, SDHCI_HOST_VERSION - 2) >> 16;
else
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
index b30b43da3b..2a2bffe06f 100644
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -52,6 +52,13 @@ config USB_EHCI
if USB_EHCI_HCD
+config USB_EHCI_MARVELL
+ bool "Support for MVEBU (AXP / A38x) on-chip EHCI USB controller"
+ depends on ARCH_MVEBU
+ default y
+ ---help---
+ Enables support for the on-chip EHCI controller on MVEBU SoCs.
+
config USB_EHCI_MX6
bool "Support for i.MX6 on-chip EHCI USB controller"
depends on ARCH_MX6
diff --git a/drivers/usb/host/ehci-marvell.c b/drivers/usb/host/ehci-marvell.c
index 50fa01c079..5b0f46aaef 100644
--- a/drivers/usb/host/ehci-marvell.c
+++ b/drivers/usb/host/ehci-marvell.c
@@ -12,6 +12,7 @@
#include "ehci.h"
#include <linux/mbus.h>
#include <asm/arch/cpu.h>
+#include <dm.h>
#if defined(CONFIG_KIRKWOOD)
#include <asm/arch/soc.h>
@@ -28,24 +29,19 @@ DECLARE_GLOBAL_DATA_PTR;
/*
* USB 2.0 Bridge Address Decoding registers setup
*/
-#ifdef CONFIG_ARMADA_XP
+#ifdef CONFIG_DM_USB
-/*
- * Armada XP and Armada 38x have different base addresses for
- * the USB 2.0 EHCI host controller. So we need to provide
- * a mechnism to support both here.
- */
-#define MVUSB0_BASE \
- (mvebu_soc_family() == MVEBU_SOC_A38X ? \
- MVEBU_USB20_BASE : MVEBU_AXP_USB_BASE)
-#define MVUSB_BASE(port) MVUSB0_BASE + ((port) << 12)
+struct ehci_mvebu_priv {
+ struct ehci_ctrl ehci;
+ fdt_addr_t hcd_base;
+};
/*
* Once all the older Marvell SoC's (Orion, Kirkwood) are converted
* to the common mvebu archticture including the mbus setup, this
* will be the only function needed to configure the access windows
*/
-static void usb_brg_adrdec_setup(int index)
+static void usb_brg_adrdec_setup(u32 base)
{
const struct mbus_dram_target_info *dram;
int i;
@@ -53,8 +49,8 @@ static void usb_brg_adrdec_setup(int index)
dram = mvebu_mbus_dram_info();
for (i = 0; i < 4; i++) {
- writel(0, MVUSB_BASE(index) + USB_WINDOW_CTRL(i));
- writel(0, MVUSB_BASE(index) + USB_WINDOW_BASE(i));
+ writel(0, base + USB_WINDOW_CTRL(i));
+ writel(0, base + USB_WINDOW_BASE(i));
}
for (i = 0; i < dram->num_cs; i++) {
@@ -63,12 +59,69 @@ static void usb_brg_adrdec_setup(int index)
/* Write size, attributes and target id to control register */
writel(((cs->size - 1) & 0xffff0000) | (cs->mbus_attr << 8) |
(dram->mbus_dram_target_id << 4) | 1,
- MVUSB_BASE(index) + USB_WINDOW_CTRL(i));
+ base + USB_WINDOW_CTRL(i));
/* Write base address to base register */
- writel(cs->base, MVUSB_BASE(index) + USB_WINDOW_BASE(i));
+ writel(cs->base, base + USB_WINDOW_BASE(i));
}
}
+
+static int ehci_mvebu_probe(struct udevice *dev)
+{
+ struct ehci_mvebu_priv *priv = dev_get_priv(dev);
+ struct ehci_hccr *hccr;
+ struct ehci_hcor *hcor;
+
+ /*
+ * Get the base address for EHCI controller from the device node
+ */
+ priv->hcd_base = dev_get_addr(dev);
+ if (priv->hcd_base == FDT_ADDR_T_NONE) {
+ debug("Can't get the EHCI register base address\n");
+ return -ENXIO;
+ }
+
+ usb_brg_adrdec_setup(priv->hcd_base);
+
+ hccr = (struct ehci_hccr *)(priv->hcd_base + 0x100);
+ hcor = (struct ehci_hcor *)
+ ((u32)hccr + HC_LENGTH(ehci_readl(&hccr->cr_capbase)));
+
+ debug("ehci-marvell: init hccr %x and hcor %x hc_length %d\n",
+ (u32)hccr, (u32)hcor,
+ (u32)HC_LENGTH(ehci_readl(&hccr->cr_capbase)));
+
+ return ehci_register(dev, hccr, hcor, NULL, 0, USB_INIT_HOST);
+}
+
+static int ehci_mvebu_remove(struct udevice *dev)
+{
+ int ret;
+
+ ret = ehci_deregister(dev);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static const struct udevice_id ehci_usb_ids[] = {
+ { .compatible = "marvell,orion-ehci", },
+ { }
+};
+
+U_BOOT_DRIVER(ehci_mvebu) = {
+ .name = "ehci_mvebu",
+ .id = UCLASS_USB,
+ .of_match = ehci_usb_ids,
+ .probe = ehci_mvebu_probe,
+ .remove = ehci_mvebu_remove,
+ .ops = &ehci_usb_ops,
+ .platdata_auto_alloc_size = sizeof(struct usb_platdata),
+ .priv_auto_alloc_size = sizeof(struct ehci_mvebu_priv),
+ .flags = DM_FLAG_ALLOC_PRIV_DMA,
+};
+
#else
#define MVUSB_BASE(port) MVUSB0_BASE
@@ -112,7 +165,6 @@ static void usb_brg_adrdec_setup(int index)
writel(base, MVUSB0_BASE + USB_WINDOW_BASE(i));
}
}
-#endif
/*
* Create the appropriate control structures to manage
@@ -142,3 +194,5 @@ int ehci_hcd_stop(int index)
{
return 0;
}
+
+#endif /* CONFIG_DM_USB */
OpenPOWER on IntegriCloud