diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/core/Kconfig | 30 | ||||
-rw-r--r-- | drivers/core/device.c | 20 | ||||
-rw-r--r-- | drivers/mmc/mv_sdhci.c | 41 | ||||
-rw-r--r-- | drivers/usb/host/Kconfig | 7 | ||||
-rw-r--r-- | drivers/usb/host/ehci-marvell.c | 86 |
5 files changed, 168 insertions, 16 deletions
diff --git a/drivers/core/Kconfig b/drivers/core/Kconfig index 41f4e69..15681df 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 833a803..a3dc2ca 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 75fa014..82c695f 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 b30b43d..2a2bffe 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 50fa01c..5b0f46a 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 */ |