diff options
Diffstat (limited to 'drivers')
38 files changed, 1881 insertions, 307 deletions
diff --git a/drivers/Kconfig b/drivers/Kconfig index 63c92c594a..c02f3231e0 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -46,6 +46,8 @@ source "drivers/power/Kconfig" source "drivers/ram/Kconfig" +source "drivers/remoteproc/Kconfig" + source "drivers/rtc/Kconfig" source "drivers/serial/Kconfig" diff --git a/drivers/Makefile b/drivers/Makefile index 9d0a5959a8..1a30ad1d14 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -59,6 +59,7 @@ obj-y += pwm/ obj-y += input/ # SOC specific infrastructure drivers. obj-y += soc/ +obj-$(CONFIG_REMOTEPROC) += remoteproc/ obj-y += thermal/ endif 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/dfu/dfu_sf.c b/drivers/dfu/dfu_sf.c index c3d3c3bcd8..7646c6b727 100644 --- a/drivers/dfu/dfu_sf.c +++ b/drivers/dfu/dfu_sf.c @@ -23,16 +23,25 @@ static int dfu_read_medium_sf(struct dfu_entity *dfu, u64 offset, void *buf, return spi_flash_read(dfu->data.sf.dev, offset, *len, buf); } +static u64 find_sector(struct dfu_entity *dfu, u64 start, u64 offset) +{ + return (lldiv((start + offset), dfu->data.sf.dev->sector_size)) * + dfu->data.sf.dev->sector_size; +} + static int dfu_write_medium_sf(struct dfu_entity *dfu, u64 offset, void *buf, long *len) { int ret; - ret = spi_flash_erase(dfu->data.sf.dev, offset, *len); + ret = spi_flash_erase(dfu->data.sf.dev, + find_sector(dfu, dfu->data.sf.start, offset), + dfu->data.sf.dev->sector_size); if (ret) return ret; - ret = spi_flash_write(dfu->data.sf.dev, offset, *len, buf); + ret = spi_flash_write(dfu->data.sf.dev, dfu->data.sf.start + offset, + *len, buf); if (ret) return ret; diff --git a/drivers/dma/keystone_nav.c b/drivers/dma/keystone_nav.c index dfca75abdc..5a65b62a39 100644 --- a/drivers/dma/keystone_nav.c +++ b/drivers/dma/keystone_nav.c @@ -54,7 +54,7 @@ int _qm_init(struct qm_config *cfg) qm_cfg = cfg; qm_cfg->mngr_cfg->link_ram_base0 = qm_cfg->i_lram; - qm_cfg->mngr_cfg->link_ram_size0 = HDESC_NUM * 8; + qm_cfg->mngr_cfg->link_ram_size0 = HDESC_NUM * 8 - 1; qm_cfg->mngr_cfg->link_ram_base1 = 0; qm_cfg->mngr_cfg->link_ram_size1 = 0; qm_cfg->mngr_cfg->link_ram_base2 = 0; diff --git a/drivers/gpio/axp_gpio.c b/drivers/gpio/axp_gpio.c index 2e97cc39d6..bd2ac892d0 100644 --- a/drivers/gpio/axp_gpio.c +++ b/drivers/gpio/axp_gpio.c @@ -10,22 +10,13 @@ #include <asm/arch/gpio.h> #include <asm/arch/pmic_bus.h> #include <asm/gpio.h> +#include <axp_pmic.h> #include <dm.h> #include <dm/device-internal.h> #include <dm/lists.h> #include <dm/root.h> #include <errno.h> -#ifdef CONFIG_AXP152_POWER -#include <axp152.h> -#elif defined CONFIG_AXP209_POWER -#include <axp209.h> -#elif defined CONFIG_AXP221_POWER -#include <axp221.h> -#else -#error Unknown AXP model -#endif - static int axp_gpio_set_value(struct udevice *dev, unsigned pin, int val); static u8 axp_get_gpio_ctrl_reg(unsigned pin) diff --git a/drivers/gpio/omap_gpio.c b/drivers/gpio/omap_gpio.c index cd960dc013..93d18e44a5 100644 --- a/drivers/gpio/omap_gpio.c +++ b/drivers/gpio/omap_gpio.c @@ -25,6 +25,7 @@ #include <asm/io.h> #include <asm/errno.h> #include <malloc.h> +#include <dt-bindings/gpio/gpio.h> DECLARE_GLOBAL_DATA_PTR; @@ -276,12 +277,22 @@ static int omap_gpio_get_function(struct udevice *dev, unsigned offset) return GPIOF_INPUT; } +static int omap_gpio_xlate(struct udevice *dev, struct gpio_desc *desc, + struct fdtdec_phandle_args *args) +{ + desc->offset = args->args[0]; + desc->flags = args->args[1] & GPIO_ACTIVE_LOW ? GPIOD_ACTIVE_LOW : 0; + + return 0; +} + static const struct dm_gpio_ops gpio_omap_ops = { .direction_input = omap_gpio_direction_input, .direction_output = omap_gpio_direction_output, .get_value = omap_gpio_get_value, .set_value = omap_gpio_set_value, .get_function = omap_gpio_get_function, + .xlate = omap_gpio_xlate, }; static int omap_gpio_probe(struct udevice *dev) diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig index 6277f92ef5..ceae7bcaec 100644 --- a/drivers/mmc/Kconfig +++ b/drivers/mmc/Kconfig @@ -1,5 +1,11 @@ menu "MMC Host controller Support" +config MMC + bool "Enable MMC support" + depends on ARCH_SUNXI + help + TODO: Move all architectures to use this option + config DM_MMC bool "Enable MMC controllers using Driver Model" depends on DM 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/mmc/omap_hsmmc.c b/drivers/mmc/omap_hsmmc.c index d7b388f3f4..5038a9f55f 100644 --- a/drivers/mmc/omap_hsmmc.c +++ b/drivers/mmc/omap_hsmmc.c @@ -31,10 +31,15 @@ #include <twl4030.h> #include <twl6030.h> #include <palmas.h> -#include <asm/gpio.h> #include <asm/io.h> #include <asm/arch/mmc_host_def.h> +#if !defined(CONFIG_SOC_KEYSTONE) +#include <asm/gpio.h> #include <asm/arch/sys_proto.h> +#endif +#include <dm.h> + +DECLARE_GLOBAL_DATA_PTR; /* simplify defines to OMAP_HSMMC_USE_GPIO */ #if (defined(CONFIG_OMAP_GPIO) && !defined(CONFIG_SPL_BUILD)) || \ @@ -52,9 +57,15 @@ struct omap_hsmmc_data { struct hsmmc *base_addr; struct mmc_config cfg; #ifdef OMAP_HSMMC_USE_GPIO +#ifdef CONFIG_DM_MMC + struct gpio_desc cd_gpio; /* Change Detect GPIO */ + struct gpio_desc wp_gpio; /* Write Protect GPIO */ + bool cd_inverted; +#else int cd_gpio; int wp_gpio; #endif +#endif }; /* If we fail after 1 second wait, something is really bad */ @@ -64,7 +75,7 @@ static int mmc_read_data(struct hsmmc *mmc_base, char *buf, unsigned int size); static int mmc_write_data(struct hsmmc *mmc_base, const char *buf, unsigned int siz); -#ifdef OMAP_HSMMC_USE_GPIO +#if defined(OMAP_HSMMC_USE_GPIO) && !defined(CONFIG_DM_MMC) static int omap_mmc_setup_gpio_in(int gpio, const char *label) { int ret; @@ -600,6 +611,34 @@ static void omap_hsmmc_set_ios(struct mmc *mmc) } #ifdef OMAP_HSMMC_USE_GPIO +#ifdef CONFIG_DM_MMC +static int omap_hsmmc_getcd(struct mmc *mmc) +{ + struct omap_hsmmc_data *priv = mmc->priv; + int value; + + value = dm_gpio_get_value(&priv->cd_gpio); + /* if no CD return as 1 */ + if (value < 0) + return 1; + + if (priv->cd_inverted) + return !value; + return value; +} + +static int omap_hsmmc_getwp(struct mmc *mmc) +{ + struct omap_hsmmc_data *priv = mmc->priv; + int value; + + value = dm_gpio_get_value(&priv->wp_gpio); + /* if no WP return as 0 */ + if (value < 0) + return 0; + return value; +} +#else static int omap_hsmmc_getcd(struct mmc *mmc) { struct omap_hsmmc_data *priv_data = mmc->priv; @@ -628,6 +667,7 @@ static int omap_hsmmc_getwp(struct mmc *mmc) return gpio_get_value(wp_gpio); } #endif +#endif static const struct mmc_ops omap_hsmmc_ops = { .send_cmd = omap_hsmmc_send_cmd, @@ -639,6 +679,7 @@ static const struct mmc_ops omap_hsmmc_ops = { #endif }; +#ifndef CONFIG_DM_MMC int omap_mmc_init(int dev_index, uint host_caps_mask, uint f_max, int cd_gpio, int wp_gpio) { @@ -662,7 +703,8 @@ int omap_mmc_init(int dev_index, uint host_caps_mask, uint f_max, int cd_gpio, priv_data->base_addr = (struct hsmmc *)OMAP_HSMMC2_BASE; #if (defined(CONFIG_OMAP44XX) || defined(CONFIG_OMAP54XX) || \ defined(CONFIG_DRA7XX) || defined(CONFIG_AM57XX) || \ - defined(CONFIG_AM43XX)) && defined(CONFIG_HSMMC2_8BIT) + defined(CONFIG_AM43XX) || defined(CONFIG_SOC_KEYSTONE)) && \ + defined(CONFIG_HSMMC2_8BIT) /* Enable 8-bit interface for eMMC on OMAP4/5 or DRA7XX */ host_caps_val |= MMC_MODE_8BIT; #endif @@ -724,3 +766,79 @@ int omap_mmc_init(int dev_index, uint host_caps_mask, uint f_max, int cd_gpio, return 0; } +#else +static int omap_hsmmc_ofdata_to_platdata(struct udevice *dev) +{ + struct omap_hsmmc_data *priv = dev_get_priv(dev); + const void *fdt = gd->fdt_blob; + int node = dev->of_offset; + struct mmc_config *cfg; + int val; + + priv->base_addr = (struct hsmmc *)dev_get_addr(dev); + cfg = &priv->cfg; + + cfg->host_caps = MMC_MODE_HS_52MHz | MMC_MODE_HS; + val = fdtdec_get_int(fdt, node, "bus-width", -1); + if (val < 0) { + printf("error: bus-width property missing\n"); + return -ENOENT; + } + + switch (val) { + case 0x8: + cfg->host_caps |= MMC_MODE_8BIT; + case 0x4: + cfg->host_caps |= MMC_MODE_4BIT; + break; + default: + printf("error: invalid bus-width property\n"); + return -ENOENT; + } + + cfg->f_min = 400000; + cfg->f_max = fdtdec_get_int(fdt, node, "max-frequency", 52000000); + cfg->voltages = MMC_VDD_32_33 | MMC_VDD_33_34 | MMC_VDD_165_195; + cfg->b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT; + + priv->cd_inverted = fdtdec_get_bool(fdt, node, "cd-inverted"); + + return 0; +} + +static int omap_hsmmc_probe(struct udevice *dev) +{ + struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev); + struct omap_hsmmc_data *priv = dev_get_priv(dev); + struct mmc_config *cfg; + struct mmc *mmc; + + cfg = &priv->cfg; + cfg->name = "OMAP SD/MMC"; + cfg->ops = &omap_hsmmc_ops; + + mmc = mmc_create(cfg, priv); + if (mmc == NULL) + return -1; + + upriv->mmc = mmc; + + return 0; +} + +static const struct udevice_id omap_hsmmc_ids[] = { + { .compatible = "ti,omap3-hsmmc" }, + { .compatible = "ti,omap4-hsmmc" }, + { .compatible = "ti,am33xx-hsmmc" }, + { } +}; + +U_BOOT_DRIVER(omap_hsmmc) = { + .name = "omap_hsmmc", + .id = UCLASS_MMC, + .of_match = omap_hsmmc_ids, + .ofdata_to_platdata = omap_hsmmc_ofdata_to_platdata, + .probe = omap_hsmmc_probe, + .priv_auto_alloc_size = sizeof(struct omap_hsmmc_data), +}; +#endif diff --git a/drivers/mmc/s5p_sdhci.c b/drivers/mmc/s5p_sdhci.c index 4db51d6488..15ecfee961 100644 --- a/drivers/mmc/s5p_sdhci.c +++ b/drivers/mmc/s5p_sdhci.c @@ -84,9 +84,9 @@ static int s5p_sdhci_core_init(struct sdhci_host *host) int s5p_sdhci_init(u32 regbase, int index, int bus_width) { - struct sdhci_host *host = malloc(sizeof(struct sdhci_host)); + struct sdhci_host *host = calloc(1, sizeof(struct sdhci_host)); if (!host) { - printf("sdhci__host malloc fail!\n"); + printf("sdhci__host allocation fail!\n"); return 1; } host->ioaddr = (void *)regbase; @@ -101,29 +101,31 @@ struct sdhci_host sdhci_host[SDHCI_MAX_HOSTS]; static int do_sdhci_init(struct sdhci_host *host) { - int dev_id, flag; - int err = 0; + int dev_id, flag, ret; flag = host->bus_width == 8 ? PINMUX_FLAG_8BIT_MODE : PINMUX_FLAG_NONE; dev_id = host->index + PERIPH_ID_SDMMC0; if (dm_gpio_is_valid(&host->pwr_gpio)) { dm_gpio_set_value(&host->pwr_gpio, 1); - err = exynos_pinmux_config(dev_id, flag); - if (err) { + ret = exynos_pinmux_config(dev_id, flag); + if (ret) { debug("MMC not configured\n"); - return err; + return ret; } } if (dm_gpio_is_valid(&host->cd_gpio)) { - if (dm_gpio_get_value(&host->cd_gpio)) + ret = dm_gpio_get_value(&host->cd_gpio); + if (ret) { + debug("no SD card detected (%d)\n", ret); return -ENODEV; + } - err = exynos_pinmux_config(dev_id, flag); - if (err) { + ret = exynos_pinmux_config(dev_id, flag); + if (ret) { printf("external SD not configured\n"); - return err; + return ret; } } @@ -170,7 +172,8 @@ static int sdhci_get_config(const void *blob, int node, struct sdhci_host *host) static int process_nodes(const void *blob, int node_list[], int count) { struct sdhci_host *host; - int i, node; + int i, node, ret; + int failed = 0; debug("%s: count = %d\n", __func__, count); @@ -182,13 +185,22 @@ static int process_nodes(const void *blob, int node_list[], int count) host = &sdhci_host[i]; - if (sdhci_get_config(blob, node, host)) { - printf("%s: failed to decode dev %d\n", __func__, i); - return -1; + ret = sdhci_get_config(blob, node, host); + if (ret) { + printf("%s: failed to decode dev %d (%d)\n", __func__, i, ret); + failed++; + continue; + } + + ret = do_sdhci_init(host); + if (ret) { + printf("%s: failed to initialize dev %d (%d)\n", __func__, i, ret); + failed++; } - do_sdhci_init(host); } - return 0; + + /* we only consider it an error when all nodes fail */ + return (failed == count ? -1 : 0); } int exynos_mmc_init(const void *blob) @@ -200,8 +212,6 @@ int exynos_mmc_init(const void *blob) COMPAT_SAMSUNG_EXYNOS_MMC, node_list, SDHCI_MAX_HOSTS); - process_nodes(blob, node_list, count); - - return 0; + return process_nodes(blob, node_list, count); } #endif diff --git a/drivers/net/cpsw.c b/drivers/net/cpsw.c index fb4d621a88..3dff9df377 100644 --- a/drivers/net/cpsw.c +++ b/drivers/net/cpsw.c @@ -25,6 +25,9 @@ #include <asm/io.h> #include <phy.h> #include <asm/arch/cpu.h> +#include <dm.h> + +DECLARE_GLOBAL_DATA_PTR; #define BITMASK(bits) (BIT(bits) - 1) #define PHY_REG_MASK 0x1f @@ -37,6 +40,23 @@ #define FULLDUPLEXEN BIT(0) #define MIIEN BIT(15) +/* reg offset */ +#define CPSW_HOST_PORT_OFFSET 0x108 +#define CPSW_SLAVE0_OFFSET 0x208 +#define CPSW_SLAVE1_OFFSET 0x308 +#define CPSW_SLAVE_SIZE 0x100 +#define CPSW_CPDMA_OFFSET 0x800 +#define CPSW_HW_STATS 0x900 +#define CPSW_STATERAM_OFFSET 0xa00 +#define CPSW_CPTS_OFFSET 0xc00 +#define CPSW_ALE_OFFSET 0xd00 +#define CPSW_SLIVER0_OFFSET 0xd80 +#define CPSW_SLIVER1_OFFSET 0xdc0 +#define CPSW_BD_OFFSET 0x2000 +#define CPSW_MDIO_DIV 0xff + +#define AM335X_GMII_SEL_OFFSET 0x630 + /* DMA Registers */ #define CPDMA_TXCONTROL 0x004 #define CPDMA_RXCONTROL 0x014 @@ -218,7 +238,11 @@ struct cpdma_chan { (priv)->data.slaves; slave++) struct cpsw_priv { +#ifdef CONFIG_DM_ETH + struct udevice *dev; +#else struct eth_device *dev; +#endif struct cpsw_platform_data data; int host_port; @@ -522,7 +546,7 @@ static int cpsw_mdio_write(struct mii_dev *bus, int phy_id, int dev_addr, return 0; } -static void cpsw_mdio_init(char *name, u32 mdio_base, u32 div) +static void cpsw_mdio_init(const char *name, u32 mdio_base, u32 div) { struct mii_dev *bus = mdio_alloc(); @@ -563,8 +587,15 @@ static inline void setbit_and_wait_for_clear32(void *addr) static void cpsw_set_slave_mac(struct cpsw_slave *slave, struct cpsw_priv *priv) { +#ifdef CONFIG_DM_ETH + struct eth_pdata *pdata = dev_get_platdata(priv->dev); + + writel(mac_hi(pdata->enetaddr), &slave->regs->sa_hi); + writel(mac_lo(pdata->enetaddr), &slave->regs->sa_lo); +#else __raw_writel(mac_hi(priv->dev->enetaddr), &slave->regs->sa_hi); __raw_writel(mac_lo(priv->dev->enetaddr), &slave->regs->sa_lo); +#endif } static void cpsw_slave_update_link(struct cpsw_slave *slave, @@ -745,9 +776,8 @@ static int cpdma_process(struct cpsw_priv *priv, struct cpdma_chan *chan, return 0; } -static int cpsw_init(struct eth_device *dev, bd_t *bis) +static int _cpsw_init(struct cpsw_priv *priv, u8 *enetaddr) { - struct cpsw_priv *priv = dev->priv; struct cpsw_slave *slave; int i, ret; @@ -772,8 +802,7 @@ static int cpsw_init(struct eth_device *dev, bd_t *bis) cpsw_ale_port_state(priv, priv->host_port, ALE_PORT_STATE_FORWARD); - cpsw_ale_add_ucast(priv, priv->dev->enetaddr, priv->host_port, - ALE_SECURE); + cpsw_ale_add_ucast(priv, enetaddr, priv->host_port, ALE_SECURE); cpsw_ale_add_mcast(priv, net_bcast_ethaddr, 1 << priv->host_port); for_active_slave(slave, priv) @@ -857,10 +886,8 @@ static int cpsw_init(struct eth_device *dev, bd_t *bis) return 0; } -static void cpsw_halt(struct eth_device *dev) +static void _cpsw_halt(struct cpsw_priv *priv) { - struct cpsw_priv *priv = dev->priv; - writel(0, priv->dma_regs + CPDMA_TXCONTROL); writel(0, priv->dma_regs + CPDMA_RXCONTROL); @@ -870,12 +897,10 @@ static void cpsw_halt(struct eth_device *dev) /* clear dma state */ setbit_and_wait_for_clear32(priv->dma_regs + CPDMA_SOFTRESET); - priv->data.control(0); } -static int cpsw_send(struct eth_device *dev, void *packet, int length) +static int _cpsw_send(struct cpsw_priv *priv, void *packet, int length) { - struct cpsw_priv *priv = dev->priv; void *buffer; int len; int timeout = CPDMA_TIMEOUT; @@ -896,20 +921,21 @@ static int cpsw_send(struct eth_device *dev, void *packet, int length) return cpdma_submit(priv, &priv->tx_chan, packet, length); } -static int cpsw_recv(struct eth_device *dev) +static int _cpsw_recv(struct cpsw_priv *priv, uchar **pkt) { - struct cpsw_priv *priv = dev->priv; void *buffer; int len; + int ret = -EAGAIN; - while (cpdma_process(priv, &priv->rx_chan, &buffer, &len) >= 0) { - invalidate_dcache_range((unsigned long)buffer, - (unsigned long)buffer + PKTSIZE_ALIGN); - net_process_received_packet(buffer, len); - cpdma_submit(priv, &priv->rx_chan, buffer, PKTSIZE); - } + ret = cpdma_process(priv, &priv->rx_chan, &buffer, &len); + if (ret < 0) + return ret; - return 0; + invalidate_dcache_range((unsigned long)buffer, + (unsigned long)buffer + PKTSIZE_ALIGN); + *pkt = buffer; + + return len; } static void cpsw_slave_setup(struct cpsw_slave *slave, int slave_num, @@ -923,15 +949,14 @@ static void cpsw_slave_setup(struct cpsw_slave *slave, int slave_num, slave->sliver = regs + data->sliver_reg_ofs; } -static int cpsw_phy_init(struct eth_device *dev, struct cpsw_slave *slave) +static int cpsw_phy_init(struct cpsw_priv *priv, struct cpsw_slave *slave) { - struct cpsw_priv *priv = (struct cpsw_priv *)dev->priv; struct phy_device *phydev; u32 supported = PHY_GBIT_FEATURES; phydev = phy_connect(priv->bus, slave->data->phy_addr, - dev, + priv->dev, slave->data->phy_if); if (!phydev) @@ -946,30 +971,14 @@ static int cpsw_phy_init(struct eth_device *dev, struct cpsw_slave *slave) return 1; } -int cpsw_register(struct cpsw_platform_data *data) +int _cpsw_register(struct cpsw_priv *priv) { - struct cpsw_priv *priv; struct cpsw_slave *slave; + struct cpsw_platform_data *data = &priv->data; void *regs = (void *)data->cpsw_base; - struct eth_device *dev; - - dev = calloc(sizeof(*dev), 1); - if (!dev) - return -ENOMEM; - - priv = calloc(sizeof(*priv), 1); - if (!priv) { - free(dev); - return -ENOMEM; - } - - priv->data = *data; - priv->dev = dev; priv->slaves = malloc(sizeof(struct cpsw_slave) * data->slaves); if (!priv->slaves) { - free(dev); - free(priv); return -ENOMEM; } @@ -987,6 +996,71 @@ int cpsw_register(struct cpsw_platform_data *data) idx = idx + 1; } + cpsw_mdio_init(priv->dev->name, data->mdio_base, data->mdio_div); + priv->bus = miiphy_get_dev_by_name(priv->dev->name); + for_active_slave(slave, priv) + cpsw_phy_init(priv, slave); + + return 0; +} + +#ifndef CONFIG_DM_ETH +static int cpsw_init(struct eth_device *dev, bd_t *bis) +{ + struct cpsw_priv *priv = dev->priv; + + return _cpsw_init(priv, dev->enetaddr); +} + +static void cpsw_halt(struct eth_device *dev) +{ + struct cpsw_priv *priv = dev->priv; + + return _cpsw_halt(priv); +} + +static int cpsw_send(struct eth_device *dev, void *packet, int length) +{ + struct cpsw_priv *priv = dev->priv; + + return _cpsw_send(priv, packet, length); +} + +static int cpsw_recv(struct eth_device *dev) +{ + struct cpsw_priv *priv = dev->priv; + uchar *pkt = NULL; + int len; + + len = _cpsw_recv(priv, &pkt); + + if (len > 0) { + net_process_received_packet(pkt, len); + cpdma_submit(priv, &priv->rx_chan, pkt, PKTSIZE); + } + + return len; +} + +int cpsw_register(struct cpsw_platform_data *data) +{ + struct cpsw_priv *priv; + struct eth_device *dev; + int ret; + + dev = calloc(sizeof(*dev), 1); + if (!dev) + return -ENOMEM; + + priv = calloc(sizeof(*priv), 1); + if (!priv) { + free(dev); + return -ENOMEM; + } + + priv->dev = dev; + priv->data = *data; + strcpy(dev->name, "cpsw"); dev->iobase = 0; dev->init = cpsw_init; @@ -997,10 +1071,224 @@ int cpsw_register(struct cpsw_platform_data *data) eth_register(dev); - cpsw_mdio_init(dev->name, data->mdio_base, data->mdio_div); - priv->bus = miiphy_get_dev_by_name(dev->name); - for_active_slave(slave, priv) - cpsw_phy_init(dev, slave); + ret = _cpsw_register(priv); + if (ret < 0) { + eth_unregister(dev); + free(dev); + free(priv); + return ret; + } return 1; } +#else +static int cpsw_eth_start(struct udevice *dev) +{ + struct eth_pdata *pdata = dev_get_platdata(dev); + struct cpsw_priv *priv = dev_get_priv(dev); + + return _cpsw_init(priv, pdata->enetaddr); +} + +static int cpsw_eth_send(struct udevice *dev, void *packet, int length) +{ + struct cpsw_priv *priv = dev_get_priv(dev); + + return _cpsw_send(priv, packet, length); +} + +static int cpsw_eth_recv(struct udevice *dev, int flags, uchar **packetp) +{ + struct cpsw_priv *priv = dev_get_priv(dev); + + return _cpsw_recv(priv, packetp); +} + +static int cpsw_eth_free_pkt(struct udevice *dev, uchar *packet, + int length) +{ + struct cpsw_priv *priv = dev_get_priv(dev); + + return cpdma_submit(priv, &priv->rx_chan, packet, PKTSIZE); +} + +static void cpsw_eth_stop(struct udevice *dev) +{ + struct cpsw_priv *priv = dev_get_priv(dev); + + return _cpsw_halt(priv); +} + + +static int cpsw_eth_probe(struct udevice *dev) +{ + struct cpsw_priv *priv = dev_get_priv(dev); + + priv->dev = dev; + + return _cpsw_register(priv); +} + +static const struct eth_ops cpsw_eth_ops = { + .start = cpsw_eth_start, + .send = cpsw_eth_send, + .recv = cpsw_eth_recv, + .free_pkt = cpsw_eth_free_pkt, + .stop = cpsw_eth_stop, +}; + +static int cpsw_eth_ofdata_to_platdata(struct udevice *dev) +{ + struct eth_pdata *pdata = dev_get_platdata(dev); + struct cpsw_priv *priv = dev_get_priv(dev); + const char *phy_mode; + const void *fdt = gd->fdt_blob; + int node = dev->of_offset; + int subnode; + int slave_index = 0; + uint32_t mac_hi, mac_lo; + fdt32_t gmii = 0; + int active_slave; + + pdata->iobase = dev_get_addr(dev); + priv->data.version = CPSW_CTRL_VERSION_2; + priv->data.bd_ram_ofs = CPSW_BD_OFFSET; + priv->data.ale_reg_ofs = CPSW_ALE_OFFSET; + priv->data.cpdma_reg_ofs = CPSW_CPDMA_OFFSET; + priv->data.mdio_div = CPSW_MDIO_DIV; + priv->data.host_port_reg_ofs = CPSW_HOST_PORT_OFFSET, + + pdata->phy_interface = -1; + + priv->data.cpsw_base = pdata->iobase; + priv->data.channels = fdtdec_get_int(fdt, node, "cpdma_channels", -1); + if (priv->data.channels <= 0) { + printf("error: cpdma_channels not found in dt\n"); + return -ENOENT; + } + + priv->data.slaves = fdtdec_get_int(fdt, node, "slaves", -1); + if (priv->data.slaves <= 0) { + printf("error: slaves not found in dt\n"); + return -ENOENT; + } + priv->data.slave_data = malloc(sizeof(struct cpsw_slave_data) * + priv->data.slaves); + + priv->data.ale_entries = fdtdec_get_int(fdt, node, "ale_entries", -1); + if (priv->data.ale_entries <= 0) { + printf("error: ale_entries not found in dt\n"); + return -ENOENT; + } + + priv->data.bd_ram_ofs = fdtdec_get_int(fdt, node, "bd_ram_size", -1); + if (priv->data.bd_ram_ofs <= 0) { + printf("error: bd_ram_size not found in dt\n"); + return -ENOENT; + } + + priv->data.mac_control = fdtdec_get_int(fdt, node, "mac_control", -1); + if (priv->data.mac_control <= 0) { + printf("error: ale_entries not found in dt\n"); + return -ENOENT; + } + + active_slave = fdtdec_get_int(fdt, node, "active_slave", 0); + priv->data.active_slave = active_slave; + + fdt_for_each_subnode(fdt, subnode, node) { + int len; + const char *name; + + name = fdt_get_name(fdt, subnode, &len); + if (!strncmp(name, "mdio", 4)) { + priv->data.mdio_base = fdtdec_get_addr(fdt, subnode, + "reg"); + } + + if (!strncmp(name, "slave", 5)) { + u32 phy_id[2]; + + if (slave_index >= priv->data.slaves) { + printf("error: num slaves and slave nodes did not match\n"); + return -EINVAL; + } + phy_mode = fdt_getprop(fdt, subnode, "phy-mode", NULL); + if (phy_mode) + priv->data.slave_data[slave_index].phy_if = + phy_get_interface_by_name(phy_mode); + fdtdec_get_int_array(fdt, subnode, "phy_id", phy_id, 2); + priv->data.slave_data[slave_index].phy_addr = phy_id[1]; + slave_index++; + } + + if (!strncmp(name, "cpsw-phy-sel", 12)) { + priv->data.gmii_sel = fdtdec_get_addr(fdt, subnode, + "reg"); + } + } + + priv->data.slave_data[0].slave_reg_ofs = CPSW_SLAVE0_OFFSET; + priv->data.slave_data[0].sliver_reg_ofs = CPSW_SLIVER0_OFFSET; + + if (priv->data.slaves == 2) { + priv->data.slave_data[1].slave_reg_ofs = CPSW_SLAVE1_OFFSET; + priv->data.slave_data[1].sliver_reg_ofs = CPSW_SLIVER1_OFFSET; + } + + subnode = fdtdec_lookup_phandle(fdt, node, "syscon"); + priv->data.mac_id = fdt_translate_address((void *)fdt, subnode, &gmii); + priv->data.mac_id += AM335X_GMII_SEL_OFFSET; + priv->data.mac_id += active_slave * 8; + + /* try reading mac address from efuse */ + mac_lo = readl(priv->data.mac_id); + mac_hi = readl(priv->data.mac_id + 4); + pdata->enetaddr[0] = mac_hi & 0xFF; + pdata->enetaddr[1] = (mac_hi & 0xFF00) >> 8; + pdata->enetaddr[2] = (mac_hi & 0xFF0000) >> 16; + pdata->enetaddr[3] = (mac_hi & 0xFF000000) >> 24; + pdata->enetaddr[4] = mac_lo & 0xFF; + pdata->enetaddr[5] = (mac_lo & 0xFF00) >> 8; + + pdata->phy_interface = priv->data.slave_data[active_slave].phy_if; + if (pdata->phy_interface == -1) { + debug("%s: Invalid PHY interface '%s'\n", __func__, phy_mode); + return -EINVAL; + } + switch (pdata->phy_interface) { + case PHY_INTERFACE_MODE_MII: + writel(MII_MODE_ENABLE, priv->data.gmii_sel); + break; + case PHY_INTERFACE_MODE_RMII: + writel(RMII_MODE_ENABLE, priv->data.gmii_sel); + break; + case PHY_INTERFACE_MODE_RGMII: + case PHY_INTERFACE_MODE_RGMII_ID: + case PHY_INTERFACE_MODE_RGMII_RXID: + case PHY_INTERFACE_MODE_RGMII_TXID: + writel(RGMII_MODE_ENABLE, priv->data.gmii_sel); + break; + } + return 0; +} + + +static const struct udevice_id cpsw_eth_ids[] = { + { .compatible = "ti,cpsw" }, + { .compatible = "ti,am335x-cpsw" }, + { } +}; + +U_BOOT_DRIVER(eth_cpsw) = { + .name = "eth_cpsw", + .id = UCLASS_ETH, + .of_match = cpsw_eth_ids, + .ofdata_to_platdata = cpsw_eth_ofdata_to_platdata, + .probe = cpsw_eth_probe, + .ops = &cpsw_eth_ops, + .priv_auto_alloc_size = sizeof(struct cpsw_priv), + .platdata_auto_alloc_size = sizeof(struct eth_pdata), + .flags = DM_FLAG_ALLOC_PRIV_DMA, +}; +#endif /* CONFIG_DM_ETH */ diff --git a/drivers/net/keystone_net.c b/drivers/net/keystone_net.c index 67b570279e..5ed29ae917 100644 --- a/drivers/net/keystone_net.c +++ b/drivers/net/keystone_net.c @@ -42,7 +42,9 @@ struct rx_buff_desc net_rx_buffs = { .rx_flow = 22, }; +#ifndef CONFIG_SOC_K2G static void keystone2_net_serdes_setup(void); +#endif int keystone2_eth_read_mac_addr(struct eth_device *dev) { @@ -161,16 +163,37 @@ static void __attribute__((unused)) DEVICE_EMACSL_BASE(eth_priv->slave_port - 1) + CPGMACSL_REG_CTL); } -int keystone_sgmii_link_status(int port) +#ifdef CONFIG_SOC_K2G +int keystone_rgmii_config(struct phy_device *phy_dev) { - u32 status = 0; + unsigned int i, status; - status = __raw_readl(SGMII_STATUS_REG(port)); + i = 0; + do { + if (i > SGMII_ANEG_TIMEOUT) { + puts(" TIMEOUT !\n"); + phy_dev->link = 0; + return 0; + } - return (status & SGMII_REG_STATUS_LOCK) && - (status & SGMII_REG_STATUS_LINK); -} + if (ctrlc()) { + puts("user interrupt!\n"); + phy_dev->link = 0; + return -EINTR; + } + if ((i++ % 500) == 0) + printf("."); + + udelay(1000); /* 1 ms */ + status = readl(RGMII_STATUS_REG); + } while (!(status & RGMII_REG_STATUS_LINK)); + + puts(" done\n"); + + return 0; +} +#else int keystone_sgmii_config(struct phy_device *phy_dev, int port, int interface) { unsigned int i, status, mask; @@ -264,6 +287,7 @@ int keystone_sgmii_config(struct phy_device *phy_dev, int port, int interface) return 0; } +#endif int mac_sl_reset(u32 port) { @@ -315,7 +339,7 @@ int mac_sl_config(u_int16_t port, struct mac_sl_cfg *cfg) writel(cfg->max_rx_len, DEVICE_EMACSL_BASE(port) + CPGMACSL_REG_MAXLEN); writel(cfg->ctl, DEVICE_EMACSL_BASE(port) + CPGMACSL_REG_CTL); -#if defined(CONFIG_SOC_K2E) || defined(CONFIG_SOC_K2L) +#ifndef CONFIG_SOC_K2HK /* Map RX packet flow priority to 0 */ writel(0, DEVICE_EMACSL_BASE(port) + CPGMACSL_REG_RX_PRI_MAP); #endif @@ -401,8 +425,12 @@ static int keystone2_eth_open(struct eth_device *dev, bd_t *bis) if (sys_has_mdio) keystone2_mdio_reset(mdio_bus); +#ifdef CONFIG_SOC_K2G + keystone_rgmii_config(phy_dev); +#else keystone_sgmii_config(phy_dev, eth_priv->slave_port - 1, eth_priv->sgmii_link_type); +#endif udelay(10000); @@ -564,16 +592,18 @@ int keystone2_emac_initialize(struct eth_priv_t *eth_priv) return res; } +#ifndef CONFIG_SOC_K2G keystone2_net_serdes_setup(); +#endif /* Create phy device and bind it with driver */ #ifdef CONFIG_KSNET_MDIO_PHY_CONFIG_ENABLE phy_dev = phy_connect(mdio_bus, eth_priv->phy_addr, - dev, PHY_INTERFACE_MODE_SGMII); + dev, eth_priv->phy_if); phy_config(phy_dev); #else phy_dev = phy_find_by_mask(mdio_bus, 1 << eth_priv->phy_addr, - PHY_INTERFACE_MODE_SGMII); + eth_priv->phy_if); phy_dev->dev = dev; #endif eth_priv->phy_dev = phy_dev; @@ -589,6 +619,7 @@ struct ks2_serdes ks2_serdes_sgmii_156p25mhz = { .loopback = 0, }; +#ifndef CONFIG_SOC_K2G static void keystone2_net_serdes_setup(void) { ks2_serdes_init(CONFIG_KSNET_SERDES_SGMII_BASE, @@ -604,3 +635,4 @@ static void keystone2_net_serdes_setup(void) /* wait till setup */ udelay(5000); } +#endif diff --git a/drivers/pci/pci-uclass.c b/drivers/pci/pci-uclass.c index 0756bbe8f1..1d93194b67 100644 --- a/drivers/pci/pci-uclass.c +++ b/drivers/pci/pci-uclass.c @@ -85,30 +85,7 @@ static int pci_get_bus_max(void) int pci_last_busno(void) { - struct pci_controller *hose; - struct udevice *bus; - struct uclass *uc; - int ret; - - debug("pci_last_busno\n"); - ret = uclass_get(UCLASS_PCI, &uc); - if (ret || list_empty(&uc->dev_head)) - return -1; - - /* Probe the last bus */ - bus = list_entry(uc->dev_head.prev, struct udevice, uclass_node); - debug("bus = %p, %s\n", bus, bus->name); - assert(bus); - ret = device_probe(bus); - if (ret) - return ret; - - /* If that bus has bridges, we may have new buses now. Get the last */ - bus = list_entry(uc->dev_head.prev, struct udevice, uclass_node); - hose = dev_get_uclass_priv(bus); - debug("bus = %s, hose = %p\n", bus->name, hose); - - return hose->last_busno; + return pci_get_bus_max(); } int pci_get_ff(enum pci_size_t size) @@ -387,9 +364,23 @@ int dm_pci_read_config32(struct udevice *dev, int offset, u32 *valuep) return 0; } +static void set_vga_bridge_bits(struct udevice *dev) +{ + struct udevice *parent = dev->parent; + u16 bc; + + while (parent->seq != 0) { + dm_pci_read_config16(parent, PCI_BRIDGE_CONTROL, &bc); + bc |= PCI_BRIDGE_CTL_VGA; + dm_pci_write_config16(parent, PCI_BRIDGE_CONTROL, bc); + parent = parent->parent; + } +} + int pci_auto_config_devices(struct udevice *bus) { struct pci_controller *hose = bus->uclass_priv; + struct pci_child_platdata *pplat; unsigned int sub_bus; struct udevice *dev; int ret; @@ -401,10 +392,18 @@ int pci_auto_config_devices(struct udevice *bus) !ret && dev; ret = device_find_next_child(&dev)) { unsigned int max_bus; + int ret; debug("%s: device %s\n", __func__, dev->name); - max_bus = pciauto_config_device(hose, pci_get_bdf(dev)); + ret = pciauto_config_device(hose, pci_get_bdf(dev)); + if (ret < 0) + return ret; + max_bus = ret; sub_bus = max(sub_bus, max_bus); + + pplat = dev_get_parent_platdata(dev); + if (pplat->class == (PCI_CLASS_DISPLAY_VGA << 8)) + set_vga_bridge_bits(dev); } debug("%s: done\n", __func__); @@ -434,7 +433,7 @@ int dm_pci_hose_probe_bus(struct pci_controller *hose, pci_dev_t bdf) ret = device_probe(bus); if (ret) { - debug("%s: Cannot probe bus bus %s: %d\n", __func__, bus->name, + debug("%s: Cannot probe bus %s: %d\n", __func__, bus->name, ret); return ret; } @@ -474,10 +473,17 @@ static bool pci_match_one_id(const struct pci_device_id *id, * pci_find_and_bind_driver() - Find and bind the right PCI driver * * This only looks at certain fields in the descriptor. + * + * @parent: Parent bus + * @find_id: Specification of the driver to find + * @bdf: Bus/device/function addreess - see PCI_BDF() + * @devp: Returns a pointer to the device created + * @return 0 if OK, -EPERM if the device is not needed before relocation and + * therefore was not created, other -ve value on error */ static int pci_find_and_bind_driver(struct udevice *parent, - struct pci_device_id *find_id, pci_dev_t bdf, - struct udevice **devp) + struct pci_device_id *find_id, + pci_dev_t bdf, struct udevice **devp) { struct pci_driver_entry *start, *entry; const char *drv; @@ -513,7 +519,7 @@ static int pci_find_and_bind_driver(struct udevice *parent, */ if (!(gd->flags & GD_FLG_RELOC) && !(drv->flags & DM_FLAG_PRE_RELOC)) - return 0; + return -EPERM; /* * We could pass the descriptor to the driver as @@ -541,7 +547,7 @@ static int pci_find_and_bind_driver(struct udevice *parent, * limited (ie: using Cache As RAM). */ if (!(gd->flags & GD_FLG_RELOC) && !bridge) - return 0; + return -EPERM; /* Bind a generic driver so that the device can be used */ sprintf(name, "pci_%x:%x.%x", parent->seq, PCI_DEV(bdf), @@ -553,7 +559,7 @@ static int pci_find_and_bind_driver(struct udevice *parent, ret = device_bind_driver(parent, drv, str, devp); if (ret) { - debug("%s: Failed to bind generic driver: %d", __func__, ret); + debug("%s: Failed to bind generic driver: %d\n", __func__, ret); return ret; } debug("%s: No match found: bound generic driver instead\n", __func__); @@ -629,17 +635,17 @@ int pci_bind_bus_devices(struct udevice *bus) ret = pci_find_and_bind_driver(bus, &find_id, bdf, &dev); } - if (ret) + if (ret == -EPERM) + continue; + else if (ret) return ret; /* Update the platform data */ - if (dev) { - pplat = dev_get_parent_platdata(dev); - pplat->devfn = PCI_MASK_BUS(bdf); - pplat->vendor = vendor; - pplat->device = device; - pplat->class = class; - } + pplat = dev_get_parent_platdata(dev); + pplat->devfn = PCI_MASK_BUS(bdf); + pplat->vendor = vendor; + pplat->device = device; + pplat->class = class; } return 0; @@ -777,6 +783,8 @@ static int pci_uclass_post_probe(struct udevice *bus) #ifdef CONFIG_PCI_PNP ret = pci_auto_config_devices(bus); + if (ret < 0) + return ret; #endif #if defined(CONFIG_X86) && defined(CONFIG_HAVE_FSP) @@ -793,11 +801,14 @@ static int pci_uclass_post_probe(struct udevice *bus) * Note we only call this 1) after U-Boot is relocated, and 2) * root bus has finished probing. */ - if ((gd->flags & GD_FLG_RELOC) && (bus->seq == 0)) + if ((gd->flags & GD_FLG_RELOC) && (bus->seq == 0)) { ret = fsp_init_phase_pci(); + if (ret) + return ret; + } #endif - return ret < 0 ? ret : 0; + return 0; } static int pci_uclass_child_post_bind(struct udevice *dev) diff --git a/drivers/pci/pci_auto.c b/drivers/pci/pci_auto.c index 79f27c744b..0412bf3515 100644 --- a/drivers/pci/pci_auto.c +++ b/drivers/pci/pci_auto.c @@ -89,6 +89,7 @@ void pciauto_setup_device(struct pci_controller *hose, struct pci_region *bar_res; int found_mem64 = 0; #endif + u16 class; pci_hose_read_config_word(hose, dev, PCI_COMMAND, &cmdstat); cmdstat = (cmdstat & ~(PCI_COMMAND_IO | PCI_COMMAND_MEMORY)) | PCI_COMMAND_MASTER; @@ -206,6 +207,11 @@ void pciauto_setup_device(struct pci_controller *hose, } #endif + /* PCI_COMMAND_IO must be set for VGA device */ + pci_hose_read_config_word(hose, dev, PCI_CLASS_DEVICE, &class); + if (class == PCI_CLASS_DISPLAY_VGA) + cmdstat |= PCI_COMMAND_IO; + pci_hose_write_config_word(hose, dev, PCI_COMMAND, cmdstat); pci_hose_write_config_byte(hose, dev, PCI_CACHE_LINE_SIZE, CONFIG_SYS_PCI_CACHE_LINE_SIZE); diff --git a/drivers/pci/pcie_imx.c b/drivers/pci/pcie_imx.c index 1568f20c1a..f1e189edd5 100644 --- a/drivers/pci/pcie_imx.c +++ b/drivers/pci/pcie_imx.c @@ -19,6 +19,7 @@ #include <asm/io.h> #include <linux/sizes.h> #include <errno.h> +#include <asm/arch/sys_proto.h> #define PCI_ACCESS_READ 0 #define PCI_ACCESS_WRITE 1 @@ -430,6 +431,10 @@ static int imx_pcie_write_config(struct pci_controller *hose, pci_dev_t d, static int imx6_pcie_assert_core_reset(void) { struct iomuxc *iomuxc_regs = (struct iomuxc *)IOMUXC_BASE_ADDR; + + if (is_mx6dqp()) + setbits_le32(&iomuxc_regs->gpr[1], IOMUXC_GPR1_PCIE_SW_RST); + #if defined(CONFIG_MX6SX) struct gpc *gpc_regs = (struct gpc *)GPC_BASE_ADDR; @@ -536,6 +541,9 @@ static int imx6_pcie_deassert_core_reset(void) enable_pcie_clock(); + if (is_mx6dqp()) + clrbits_le32(&iomuxc_regs->gpr[1], IOMUXC_GPR1_PCIE_SW_RST); + /* * Wait for the clock to settle a bit, when the clock are sourced * from the CPU, we need about 30 ms to settle. diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig index df5e3734b0..809f8f1180 100644 --- a/drivers/power/Kconfig +++ b/drivers/power/Kconfig @@ -4,87 +4,201 @@ source "drivers/power/pmic/Kconfig" source "drivers/power/regulator/Kconfig" +choice + prompt "Select Sunxi PMIC Variant" + depends on ARCH_SUNXI + default AXP209_POWER if MACH_SUN4I || MACH_SUN5I || MACH_SUN7I + default AXP221_POWER if MACH_SUN6I || MACH_SUN8I + +config SUNXI_NO_PMIC + boolean "board without a pmic" + ---help--- + Select this for boards which do not use a PMIC. + +config AXP152_POWER + boolean "axp152 pmic support" + depends on MACH_SUN5I + ---help--- + Select this to enable support for the axp152 pmic found on most + A10s boards. + +config AXP209_POWER + boolean "axp209 pmic support" + depends on MACH_SUN4I || MACH_SUN5I || MACH_SUN7I + ---help--- + Select this to enable support for the axp209 pmic found on most + A10, A13 and A20 boards. + config AXP221_POWER boolean "axp221 / axp223 pmic support" depends on MACH_SUN6I || MACH_SUN8I - default y ---help--- - Say y here to enable support for the axp221 / axp223 pmic found on most - sun6i (A31) / sun8i (A23) boards. + Select this to enable support for the axp221/axp223 pmic found on most + A23 and A31 boards. + +endchoice + +config AXP_DCDC1_VOLT + int "axp pmic dcdc1 voltage" + depends on AXP221_POWER + default 3000 if MACH_SUN6I || MACH_SUN8I + ---help--- + Set the voltage (mV) to program the axp pmic dcdc1 at, set to 0 to + disable dcdc1. On A23 / A31 / A33 (axp221) boards dcdc1 is used for + generic 3.3V IO voltage for external devices like the lcd-panal and + sdcard interfaces, etc. On most boards dcdc1 is undervolted to 3.0V to + safe battery. On A31 devices dcdc1 is also used for VCC-IO. -config AXP221_DCDC1_VOLT - int "axp221 dcdc1 voltage" +config AXP_DCDC2_VOLT + int "axp pmic dcdc2 voltage" + depends on AXP152_POWER || AXP209_POWER || AXP221_POWER + default 1400 if AXP152_POWER || AXP209_POWER + default 1200 if MACH_SUN6I + default 1100 if MACH_SUN8I + ---help--- + Set the voltage (mV) to program the axp pmic dcdc2 at, set to 0 to + disable dcdc2. + On A10(s) / A13 / A20 boards dcdc2 is VDD-CPU and should be 1.4V. + On A31 boards dcdc2 is used for VDD-GPU and should be 1.2V. + On A23/A33 boards dcdc2 is used for VDD-SYS and should be 1.1V. + +config AXP_DCDC3_VOLT + int "axp pmic dcdc3 voltage" + depends on AXP152_POWER || AXP209_POWER || AXP221_POWER + default 1500 if AXP152_POWER + default 1250 if AXP209_POWER + default 1200 if MACH_SUN6I || MACH_SUN8I + ---help--- + Set the voltage (mV) to program the axp pmic dcdc3 at, set to 0 to + disable dcdc3. + On A10(s) / A13 / A20 boards with an axp209 dcdc3 is VDD-INT-DLL and + should be 1.25V. + On A10s boards with an axp152 dcdc3 is VCC-DRAM and should be 1.5V. + On A23 / A31 / A33 boards dcdc3 is VDD-CPU and should be 1.2V. + +config AXP_DCDC4_VOLT + int "axp pmic dcdc4 voltage" + depends on AXP152_POWER || AXP221_POWER + default 1250 if AXP152_POWER + default 1200 if MACH_SUN6I + default 0 if MACH_SUN8I + ---help--- + Set the voltage (mV) to program the axp pmic dcdc4 at, set to 0 to + disable dcdc4. + On A10s boards with an axp152 dcdc4 is VDD-INT-DLL and should be 1.25V. + On A31 boards dcdc4 is used for VDD-SYS and should be 1.2V. + On A23 / A33 boards dcdc4 is unused and should be disabled. + +config AXP_DCDC5_VOLT + int "axp pmic dcdc5 voltage" depends on AXP221_POWER - default 3000 + default 1500 if MACH_SUN6I || MACH_SUN8I ---help--- - Set the voltage (mV) to program the axp221 dcdc1 at, set to 0 to - disable dcdc1. This is typically used as generic 3.3V IO voltage for - things like GPIO-s, sdcard interfaces, etc. On most boards this is - undervolted to 3.0V to safe battery. + Set the voltage (mV) to program the axp pmic dcdc5 at, set to 0 to + disable dcdc5. + On A23 / A31 / A33 boards dcdc5 is VCC-DRAM and should be 1.5V. -config AXP221_DCDC2_VOLT - int "axp221 dcdc2 voltage" +config AXP_ALDO1_VOLT + int "axp pmic (a)ldo1 voltage" depends on AXP221_POWER - default 1200 + default 0 if MACH_SUN6I + default 3000 if MACH_SUN8I ---help--- - Set the voltage (mV) to program the axp221 dcdc2 at, set to 0 to - disable dcdc2. On A31 boards this is typically used for VDD-GPU, - on A23/A33 for VDD-SYS, this should normally be set to 1.2V. + Set the voltage (mV) to program the axp pmic aldo1 at, set to 0 to + disable aldo1. + On A31 boards aldo1 is often used to power the wifi module. + On A23 / A33 boards aldo1 is used for VCC-IO and should be 3.0V. -config AXP221_DLDO1_VOLT - int "axp221 dldo1 voltage" +config AXP_ALDO2_VOLT + int "axp pmic (a)ldo2 voltage" + depends on AXP152_POWER || AXP209_POWER || AXP221_POWER + default 3000 if AXP152_POWER || AXP209_POWER + default 0 if MACH_SUN6I + default 2500 if MACH_SUN8I + ---help--- + Set the voltage (mV) to program the axp pmic aldo2 at, set to 0 to + disable aldo2. + On A10(s) / A13 / A20 boards aldo2 is AVCC and should be 3.0V. + On A31 boards aldo2 is typically unused and should be disabled. + On A31 boards aldo2 may be used for LPDDR2 then it should be 1.8V. + On A23 / A33 boards aldo2 is used for VDD-DLL and should be 2.5V. + +config AXP_ALDO3_VOLT + int "axp pmic (a)ldo3 voltage" + depends on AXP209_POWER || AXP221_POWER + default 0 if AXP209_POWER + default 3000 if MACH_SUN6I || MACH_SUN8I + ---help--- + Set the voltage (mV) to program the axp pmic aldo3 at, set to 0 to + disable aldo3. + On A10(s) / A13 / A20 boards aldo3 should be 2.8V. + On A23 / A31 / A33 boards aldo3 is VCC-PLL and AVCC and should be 3.0V. + +config AXP_ALDO4_VOLT + int "axp pmic (a)ldo4 voltage" + depends on AXP209_POWER + default 0 if AXP209_POWER + ---help--- + Set the voltage (mV) to program the axp pmic aldo4 at, set to 0 to + disable aldo4. + On A10(s) / A13 / A20 boards aldo4 should be 2.8V. + +config AXP_DLDO1_VOLT + int "axp pmic dldo1 voltage" depends on AXP221_POWER default 0 ---help--- - Set the voltage (mV) to program the axp221 dldo1 at, set to 0 to - disable dldo1. On sun6i (A31) boards with ethernet this is often used + Set the voltage (mV) to program the axp pmic dldo1 at, set to 0 to + disable dldo1. On sun6i (A31) boards with ethernet dldo1 is often used to power the ethernet phy. On sun8i (A23) boards this is often used to power the wifi. -config AXP221_DLDO4_VOLT - int "axp221 dldo4 voltage" +config AXP_DLDO2_VOLT + int "axp pmic dldo2 voltage" depends on AXP221_POWER default 0 ---help--- - Set the voltage (mV) to program the axp221 dldo4 at, set to 0 to - disable dldo4. + Set the voltage (mV) to program the axp pmic dldo2 at, set to 0 to + disable dldo2. -config AXP221_ALDO1_VOLT - int "axp221 aldo1 voltage" +config AXP_DLDO3_VOLT + int "axp pmic dldo3 voltage" depends on AXP221_POWER default 0 ---help--- - Set the voltage (mV) to program the axp221 aldo1 at, set to 0 to - disable aldo1. On sun6i (A31) boards which have a wifi module this is - often used to power the wifi module. + Set the voltage (mV) to program the axp pmic dldo3 at, set to 0 to + disable dldo3. -config AXP221_ALDO2_VOLT - int "axp221 aldo2 voltage" +config AXP_DLDO4_VOLT + int "axp pmic dldo4 voltage" depends on AXP221_POWER - default 0 if MACH_SUN6I - default 2500 if MACH_SUN8I + default 0 ---help--- - Set the voltage (mV) to program the axp221 aldo2 at, set to 0 to - disable aldo2. On sun6i (A31) boards this is typically unused and - should be disabled, if it is used for LPDDR2 it should be set to 1.8V. - On sun8i (A23) this is typically connected to VDD-DLL and must be set - to 2.5V. + Set the voltage (mV) to program the axp pmic dldo4 at, set to 0 to + disable dldo4. -config AXP221_ALDO3_VOLT - int "axp221 aldo3 voltage" +config AXP_ELDO1_VOLT + int "axp pmic eldo1 voltage" depends on AXP221_POWER - default 3000 + default 0 + ---help--- + Set the voltage (mV) to program the axp pmic eldo1 at, set to 0 to + disable eldo1. + +config AXP_ELDO2_VOLT + int "axp pmic eldo2 voltage" + depends on AXP221_POWER + default 0 ---help--- - Set the voltage (mV) to program the axp221 aldo3 at, set to 0 to - disable aldo3. This is typically connected to VCC-PLL and AVCC and - must be set to 3V. + Set the voltage (mV) to program the axp pmic eldo2 at, set to 0 to + disable eldo2. -config AXP221_ELDO3_VOLT - int "axp221 eldo3 voltage" +config AXP_ELDO3_VOLT + int "axp pmic eldo3 voltage" depends on AXP221_POWER default 0 ---help--- - Set the voltage (mV) to program the axp221 eldo3 at, set to 0 to + Set the voltage (mV) to program the axp pmic eldo3 at, set to 0 to disable eldo3. On some A31(s) tablets it might be used to supply 1.2V for the SSD2828 chip (converter of parallel LCD interface into MIPI DSI). diff --git a/drivers/power/axp152.c b/drivers/power/axp152.c index 740a3b41cd..297258692d 100644 --- a/drivers/power/axp152.c +++ b/drivers/power/axp152.c @@ -5,18 +5,8 @@ * SPDX-License-Identifier: GPL-2.0+ */ #include <common.h> -#include <i2c.h> -#include <axp152.h> - -static int axp152_write(enum axp152_reg reg, u8 val) -{ - return i2c_write(0x30, reg, 1, &val, 1); -} - -static int axp152_read(enum axp152_reg reg, u8 *val) -{ - return i2c_read(0x30, reg, 1, val, 1); -} +#include <asm/arch/pmic_bus.h> +#include <axp_pmic.h> static u8 axp152_mvolt_to_target(int mvolt, int min, int max, int div) { @@ -28,7 +18,7 @@ static u8 axp152_mvolt_to_target(int mvolt, int min, int max, int div) return (mvolt - min) / div; } -int axp152_set_dcdc2(int mvolt) +int axp_set_dcdc2(unsigned int mvolt) { int rc; u8 current, target; @@ -36,46 +26,50 @@ int axp152_set_dcdc2(int mvolt) target = axp152_mvolt_to_target(mvolt, 700, 2275, 25); /* Do we really need to be this gentle? It has built-in voltage slope */ - while ((rc = axp152_read(AXP152_DCDC2_VOLTAGE, ¤t)) == 0 && + while ((rc = pmic_bus_read(AXP152_DCDC2_VOLTAGE, ¤t)) == 0 && current != target) { if (current < target) current++; else current--; - rc = axp152_write(AXP152_DCDC2_VOLTAGE, current); + rc = pmic_bus_write(AXP152_DCDC2_VOLTAGE, current); if (rc) break; } return rc; } -int axp152_set_dcdc3(int mvolt) +int axp_set_dcdc3(unsigned int mvolt) { u8 target = axp152_mvolt_to_target(mvolt, 700, 3500, 50); - return axp152_write(AXP152_DCDC3_VOLTAGE, target); + return pmic_bus_write(AXP152_DCDC3_VOLTAGE, target); } -int axp152_set_dcdc4(int mvolt) +int axp_set_dcdc4(unsigned int mvolt) { u8 target = axp152_mvolt_to_target(mvolt, 700, 3500, 25); - return axp152_write(AXP152_DCDC4_VOLTAGE, target); + return pmic_bus_write(AXP152_DCDC4_VOLTAGE, target); } -int axp152_set_ldo2(int mvolt) +int axp_set_aldo2(unsigned int mvolt) { u8 target = axp152_mvolt_to_target(mvolt, 700, 3500, 100); - return axp152_write(AXP152_LDO2_VOLTAGE, target); + return pmic_bus_write(AXP152_LDO2_VOLTAGE, target); } -int axp152_init(void) +int axp_init(void) { u8 ver; int rc; - rc = axp152_read(AXP152_CHIP_VERSION, &ver); + rc = pmic_bus_init(); + if (rc) + return rc; + + rc = pmic_bus_read(AXP152_CHIP_VERSION, &ver); if (rc) return rc; diff --git a/drivers/power/axp209.c b/drivers/power/axp209.c index 5161bc1472..71aa000daa 100644 --- a/drivers/power/axp209.c +++ b/drivers/power/axp209.c @@ -6,19 +6,8 @@ */ #include <common.h> -#include <i2c.h> -#include <asm/arch/gpio.h> -#include <axp209.h> - -static int axp209_write(enum axp209_reg reg, u8 val) -{ - return i2c_write(0x34, reg, 1, &val, 1); -} - -static int axp209_read(enum axp209_reg reg, u8 *val) -{ - return i2c_read(0x34, reg, 1, val, 1); -} +#include <asm/arch/pmic_bus.h> +#include <axp_pmic.h> static u8 axp209_mvolt_to_cfg(int mvolt, int min, int max, int div) { @@ -30,22 +19,30 @@ static u8 axp209_mvolt_to_cfg(int mvolt, int min, int max, int div) return (mvolt - min) / div; } -int axp209_set_dcdc2(int mvolt) +int axp_set_dcdc2(unsigned int mvolt) { int rc; u8 cfg, current; + if (mvolt == 0) + return pmic_bus_clrbits(AXP209_OUTPUT_CTRL, + AXP209_OUTPUT_CTRL_DCDC2); + + rc = pmic_bus_setbits(AXP209_OUTPUT_CTRL, AXP209_OUTPUT_CTRL_DCDC2); + if (rc) + return rc; + cfg = axp209_mvolt_to_cfg(mvolt, 700, 2275, 25); /* Do we really need to be this gentle? It has built-in voltage slope */ - while ((rc = axp209_read(AXP209_DCDC2_VOLTAGE, ¤t)) == 0 && + while ((rc = pmic_bus_read(AXP209_DCDC2_VOLTAGE, ¤t)) == 0 && current != cfg) { if (current < cfg) current++; else current--; - rc = axp209_write(AXP209_DCDC2_VOLTAGE, current); + rc = pmic_bus_write(AXP209_DCDC2_VOLTAGE, current); if (rc) break; } @@ -53,68 +50,106 @@ int axp209_set_dcdc2(int mvolt) return rc; } -int axp209_set_dcdc3(int mvolt) +int axp_set_dcdc3(unsigned int mvolt) { u8 cfg = axp209_mvolt_to_cfg(mvolt, 700, 3500, 25); + int rc; - return axp209_write(AXP209_DCDC3_VOLTAGE, cfg); + if (mvolt == 0) + return pmic_bus_clrbits(AXP209_OUTPUT_CTRL, + AXP209_OUTPUT_CTRL_DCDC3); + + rc = pmic_bus_write(AXP209_DCDC3_VOLTAGE, cfg); + if (rc) + return rc; + + return pmic_bus_setbits(AXP209_OUTPUT_CTRL, AXP209_OUTPUT_CTRL_DCDC3); } -int axp209_set_ldo2(int mvolt) +int axp_set_aldo2(unsigned int mvolt) { int rc; u8 cfg, reg; + if (mvolt == 0) + return pmic_bus_clrbits(AXP209_OUTPUT_CTRL, + AXP209_OUTPUT_CTRL_LDO2); + cfg = axp209_mvolt_to_cfg(mvolt, 1800, 3300, 100); - rc = axp209_read(AXP209_LDO24_VOLTAGE, ®); + rc = pmic_bus_read(AXP209_LDO24_VOLTAGE, ®); if (rc) return rc; /* LDO2 configuration is in upper 4 bits */ reg = (reg & 0x0f) | (cfg << 4); - return axp209_write(AXP209_LDO24_VOLTAGE, reg); + rc = pmic_bus_write(AXP209_LDO24_VOLTAGE, reg); + if (rc) + return rc; + + return pmic_bus_setbits(AXP209_OUTPUT_CTRL, AXP209_OUTPUT_CTRL_LDO2); } -int axp209_set_ldo3(int mvolt) +int axp_set_aldo3(unsigned int mvolt) { u8 cfg; + int rc; + + if (mvolt == 0) + return pmic_bus_clrbits(AXP209_OUTPUT_CTRL, + AXP209_OUTPUT_CTRL_LDO3); if (mvolt == -1) cfg = 0x80; /* determined by LDO3IN pin */ else cfg = axp209_mvolt_to_cfg(mvolt, 700, 3500, 25); - return axp209_write(AXP209_LDO3_VOLTAGE, cfg); + rc = pmic_bus_write(AXP209_LDO3_VOLTAGE, cfg); + if (rc) + return rc; + + return pmic_bus_setbits(AXP209_OUTPUT_CTRL, AXP209_OUTPUT_CTRL_LDO3); } -int axp209_set_ldo4(int mvolt) +int axp_set_aldo4(unsigned int mvolt) { int rc; - static const int vindex[] = { + static const unsigned int vindex[] = { 1250, 1300, 1400, 1500, 1600, 1700, 1800, 1900, 2000, 2500, 2700, 2800, 3000, 3100, 3200, 3300 }; u8 cfg, reg; + if (mvolt == 0) + return pmic_bus_clrbits(AXP209_OUTPUT_CTRL, + AXP209_OUTPUT_CTRL_LDO4); + /* Translate mvolt to register cfg value, requested <= selected */ for (cfg = 15; vindex[cfg] > mvolt && cfg > 0; cfg--); - rc = axp209_read(AXP209_LDO24_VOLTAGE, ®); + rc = pmic_bus_read(AXP209_LDO24_VOLTAGE, ®); if (rc) return rc; /* LDO4 configuration is in lower 4 bits */ reg = (reg & 0xf0) | (cfg << 0); - return axp209_write(AXP209_LDO24_VOLTAGE, reg); + rc = pmic_bus_write(AXP209_LDO24_VOLTAGE, reg); + if (rc) + return rc; + + return pmic_bus_setbits(AXP209_OUTPUT_CTRL, AXP209_OUTPUT_CTRL_LDO4); } -int axp209_init(void) +int axp_init(void) { u8 ver; int i, rc; - rc = axp209_read(AXP209_CHIP_VERSION, &ver); + rc = pmic_bus_init(); + if (rc) + return rc; + + rc = pmic_bus_read(AXP209_CHIP_VERSION, &ver); if (rc) return rc; @@ -126,32 +161,10 @@ int axp209_init(void) /* Mask all interrupts */ for (i = AXP209_IRQ_ENABLE1; i <= AXP209_IRQ_ENABLE5; i++) { - rc = axp209_write(i, 0); + rc = pmic_bus_write(i, 0); if (rc) return rc; } return 0; } - -int axp209_poweron_by_dc(void) -{ - u8 v; - - if (axp209_read(AXP209_POWER_STATUS, &v)) - return 0; - - return (v & AXP209_POWER_STATUS_ON_BY_DC); -} - -int axp209_power_button(void) -{ - u8 v; - - if (axp209_read(AXP209_IRQ_STATUS5, &v)) - return 0; - - axp209_write(AXP209_IRQ_STATUS5, AXP209_IRQ5_PEK_DOWN); - - return v & AXP209_IRQ5_PEK_DOWN; -} diff --git a/drivers/power/axp221.c b/drivers/power/axp221.c index 7bbaec87e4..65802e4a71 100644 --- a/drivers/power/axp221.c +++ b/drivers/power/axp221.c @@ -12,9 +12,8 @@ #include <common.h> #include <errno.h> -#include <asm/arch/gpio.h> #include <asm/arch/pmic_bus.h> -#include <axp221.h> +#include <axp_pmic.h> static u8 axp221_mvolt_to_cfg(int mvolt, int min, int max, int div) { @@ -26,7 +25,7 @@ static u8 axp221_mvolt_to_cfg(int mvolt, int min, int max, int div) return (mvolt - min) / div; } -int axp221_set_dcdc1(unsigned int mvolt) +int axp_set_dcdc1(unsigned int mvolt) { int ret; u8 cfg = axp221_mvolt_to_cfg(mvolt, 1600, 3400, 100); @@ -48,7 +47,7 @@ int axp221_set_dcdc1(unsigned int mvolt) AXP221_OUTPUT_CTRL1_DCDC1_EN); } -int axp221_set_dcdc2(unsigned int mvolt) +int axp_set_dcdc2(unsigned int mvolt) { int ret; u8 cfg = axp221_mvolt_to_cfg(mvolt, 600, 1540, 20); @@ -65,7 +64,7 @@ int axp221_set_dcdc2(unsigned int mvolt) AXP221_OUTPUT_CTRL1_DCDC2_EN); } -int axp221_set_dcdc3(unsigned int mvolt) +int axp_set_dcdc3(unsigned int mvolt) { int ret; u8 cfg = axp221_mvolt_to_cfg(mvolt, 600, 1860, 20); @@ -82,7 +81,7 @@ int axp221_set_dcdc3(unsigned int mvolt) AXP221_OUTPUT_CTRL1_DCDC3_EN); } -int axp221_set_dcdc4(unsigned int mvolt) +int axp_set_dcdc4(unsigned int mvolt) { int ret; u8 cfg = axp221_mvolt_to_cfg(mvolt, 600, 1540, 20); @@ -99,7 +98,7 @@ int axp221_set_dcdc4(unsigned int mvolt) AXP221_OUTPUT_CTRL1_DCDC4_EN); } -int axp221_set_dcdc5(unsigned int mvolt) +int axp_set_dcdc5(unsigned int mvolt) { int ret; u8 cfg = axp221_mvolt_to_cfg(mvolt, 1000, 2550, 50); @@ -116,7 +115,7 @@ int axp221_set_dcdc5(unsigned int mvolt) AXP221_OUTPUT_CTRL1_DCDC5_EN); } -int axp221_set_dldo1(unsigned int mvolt) +int axp_set_dldo1(unsigned int mvolt) { int ret; u8 cfg = axp221_mvolt_to_cfg(mvolt, 700, 3300, 100); @@ -133,7 +132,7 @@ int axp221_set_dldo1(unsigned int mvolt) AXP221_OUTPUT_CTRL2_DLDO1_EN); } -int axp221_set_dldo2(unsigned int mvolt) +int axp_set_dldo2(unsigned int mvolt) { int ret; u8 cfg = axp221_mvolt_to_cfg(mvolt, 700, 3300, 100); @@ -150,7 +149,7 @@ int axp221_set_dldo2(unsigned int mvolt) AXP221_OUTPUT_CTRL2_DLDO2_EN); } -int axp221_set_dldo3(unsigned int mvolt) +int axp_set_dldo3(unsigned int mvolt) { int ret; u8 cfg = axp221_mvolt_to_cfg(mvolt, 700, 3300, 100); @@ -167,7 +166,7 @@ int axp221_set_dldo3(unsigned int mvolt) AXP221_OUTPUT_CTRL2_DLDO3_EN); } -int axp221_set_dldo4(unsigned int mvolt) +int axp_set_dldo4(unsigned int mvolt) { int ret; u8 cfg = axp221_mvolt_to_cfg(mvolt, 700, 3300, 100); @@ -184,7 +183,7 @@ int axp221_set_dldo4(unsigned int mvolt) AXP221_OUTPUT_CTRL2_DLDO4_EN); } -int axp221_set_aldo1(unsigned int mvolt) +int axp_set_aldo1(unsigned int mvolt) { int ret; u8 cfg = axp221_mvolt_to_cfg(mvolt, 700, 3300, 100); @@ -201,7 +200,7 @@ int axp221_set_aldo1(unsigned int mvolt) AXP221_OUTPUT_CTRL1_ALDO1_EN); } -int axp221_set_aldo2(unsigned int mvolt) +int axp_set_aldo2(unsigned int mvolt) { int ret; u8 cfg = axp221_mvolt_to_cfg(mvolt, 700, 3300, 100); @@ -218,7 +217,7 @@ int axp221_set_aldo2(unsigned int mvolt) AXP221_OUTPUT_CTRL1_ALDO2_EN); } -int axp221_set_aldo3(unsigned int mvolt) +int axp_set_aldo3(unsigned int mvolt) { int ret; u8 cfg = axp221_mvolt_to_cfg(mvolt, 700, 3300, 100); @@ -235,7 +234,7 @@ int axp221_set_aldo3(unsigned int mvolt) AXP221_OUTPUT_CTRL3_ALDO3_EN); } -int axp221_set_eldo(int eldo_num, unsigned int mvolt) +int axp_set_eldo(int eldo_num, unsigned int mvolt) { int ret; u8 cfg = axp221_mvolt_to_cfg(mvolt, 700, 3300, 100); @@ -268,16 +267,11 @@ int axp221_set_eldo(int eldo_num, unsigned int mvolt) return pmic_bus_setbits(AXP221_OUTPUT_CTRL2, bits); } -int axp221_init(void) +int axp_init(void) { - /* This cannot be 0 because it is used in SPL before BSS is ready */ - static int needs_init = 1; u8 axp_chip_id; int ret; - if (!needs_init) - return 0; - ret = pmic_bus_init(); if (ret) return ret; @@ -289,16 +283,15 @@ int axp221_init(void) if (!(axp_chip_id == 0x6 || axp_chip_id == 0x7 || axp_chip_id == 0x17)) return -ENODEV; - needs_init = 0; return 0; } -int axp221_get_sid(unsigned int *sid) +int axp_get_sid(unsigned int *sid) { u8 *dest = (u8 *)sid; int i, ret; - ret = axp221_init(); + ret = pmic_bus_init(); if (ret) return ret; diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig new file mode 100644 index 0000000000..437224b549 --- /dev/null +++ b/drivers/remoteproc/Kconfig @@ -0,0 +1,24 @@ +# +# (C) Copyright 2015 +# Texas Instruments Incorporated - http://www.ti.com/ +# SPDX-License-Identifier: GPL-2.0+ +# + +menu "Remote Processor drivers" + +# REMOTEPROC gets selected by drivers as needed +# All users should depend on DM +config REMOTEPROC + bool + depends on DM + +# Please keep the configuration alphabetically sorted. +config REMOTEPROC_SANDBOX + bool "Support for Test processor for Sandbox" + select REMOTEPROC + depends on DM + depends on SANDBOX + help + Say 'y' here to add support for test processor which does dummy + operations for sandbox platform. +endmenu diff --git a/drivers/remoteproc/Makefile b/drivers/remoteproc/Makefile new file mode 100644 index 0000000000..720aa6e647 --- /dev/null +++ b/drivers/remoteproc/Makefile @@ -0,0 +1,10 @@ +# +# (C) Copyright 2015 +# Texas Instruments Incorporated - http://www.ti.com/ +# SPDX-License-Identifier: GPL-2.0+ +# + +obj-$(CONFIG_REMOTEPROC) += rproc-uclass.o + +# Remote proc drivers - Please keep this list alphabetically sorted. +obj-$(CONFIG_REMOTEPROC_SANDBOX) += sandbox_testproc.o diff --git a/drivers/remoteproc/rproc-uclass.c b/drivers/remoteproc/rproc-uclass.c new file mode 100644 index 0000000000..a421e12e5d --- /dev/null +++ b/drivers/remoteproc/rproc-uclass.c @@ -0,0 +1,417 @@ +/* + * (C) Copyright 2015 + * Texas Instruments Incorporated - http://www.ti.com/ + * SPDX-License-Identifier: GPL-2.0+ + */ +#define pr_fmt(fmt) "%s: " fmt, __func__ +#include <common.h> +#include <errno.h> +#include <fdtdec.h> +#include <malloc.h> +#include <remoteproc.h> +#include <asm/io.h> +#include <dm/device-internal.h> +#include <dm.h> +#include <dm/uclass.h> +#include <dm/uclass-internal.h> + +DECLARE_GLOBAL_DATA_PTR; + +/** + * for_each_remoteproc_device() - iterate through the list of rproc devices + * @fn: check function to call per match, if this function returns fail, + * iteration is aborted with the resultant error value + * @skip_dev: Device to skip calling the callback about. + * @data: Data to pass to the callback function + * + * Return: 0 if none of the callback returned a non 0 result, else returns the + * result from the callback function + */ +static int for_each_remoteproc_device(int (*fn) (struct udevice *dev, + struct dm_rproc_uclass_pdata *uc_pdata, + const void *data), + struct udevice *skip_dev, + const void *data) +{ + struct udevice *dev; + struct dm_rproc_uclass_pdata *uc_pdata; + int ret; + + for (ret = uclass_find_first_device(UCLASS_REMOTEPROC, &dev); dev; + ret = uclass_find_next_device(&dev)) { + if (ret || dev == skip_dev) + continue; + uc_pdata = dev_get_uclass_platdata(dev); + ret = fn(dev, uc_pdata, data); + if (ret) + return ret; + } + + return 0; +} + +/** + * _rproc_name_is_unique() - iteration helper to check if rproc name is unique + * @dev: device that we are checking name for + * @uc_pdata: uclass platform data + * @data: compare data (this is the name we want to ensure is unique) + * + * Return: 0 is there is no match(is unique); if there is a match(we dont + * have a unique name), return -EINVAL. + */ +static int _rproc_name_is_unique(struct udevice *dev, + struct dm_rproc_uclass_pdata *uc_pdata, + const void *data) +{ + const char *check_name = data; + + /* devices not yet populated with data - so skip them */ + if (!uc_pdata->name && check_name) + return 0; + + /* Return 0 to search further if we dont match */ + if (strlen(uc_pdata->name) != strlen(check_name)) + return 0; + + if (!strcmp(uc_pdata->name, check_name)) + return -EINVAL; + + return 0; +} + +/** + * rproc_name_is_unique() - Check if the rproc name is unique + * @check_dev: Device we are attempting to ensure is unique + * @check_name: Name we are trying to ensure is unique. + * + * Return: true if we have a unique name, false if name is not unique. + */ +static bool rproc_name_is_unique(struct udevice *check_dev, + const char *check_name) +{ + int ret; + + ret = for_each_remoteproc_device(_rproc_name_is_unique, + check_dev, check_name); + return ret ? false : true; +} + +/** + * rproc_pre_probe() - Pre probe accessor for the uclass + * @dev: device for which we are preprobing + * + * Parses and fills up the uclass pdata for use as needed by core and + * remote proc drivers. + * + * Return: 0 if all wernt ok, else appropriate error value. + */ +static int rproc_pre_probe(struct udevice *dev) +{ + struct dm_rproc_uclass_pdata *uc_pdata; + const struct dm_rproc_ops *ops; + + uc_pdata = dev_get_uclass_platdata(dev); + + /* See if we need to populate via fdt */ + + if (!dev->platdata) { +#if CONFIG_IS_ENABLED(OF_CONTROL) + int node = dev->of_offset; + const void *blob = gd->fdt_blob; + bool tmp; + if (!blob) { + debug("'%s' no dt?\n", dev->name); + return -EINVAL; + } + debug("'%s': using fdt\n", dev->name); + uc_pdata->name = fdt_getprop(blob, node, + "remoteproc-name", NULL); + + /* Default is internal memory mapped */ + uc_pdata->mem_type = RPROC_INTERNAL_MEMORY_MAPPED; + tmp = fdtdec_get_bool(blob, node, + "remoteproc-internal-memory-mapped"); + if (tmp) + uc_pdata->mem_type = RPROC_INTERNAL_MEMORY_MAPPED; +#else + /* Nothing much we can do about this, can we? */ + return -EINVAL; +#endif + + } else { + struct dm_rproc_uclass_pdata *pdata = dev->platdata; + + debug("'%s': using legacy data\n", dev->name); + if (pdata->name) + uc_pdata->name = pdata->name; + uc_pdata->mem_type = pdata->mem_type; + uc_pdata->driver_plat_data = pdata->driver_plat_data; + } + + /* Else try using device Name */ + if (!uc_pdata->name) + uc_pdata->name = dev->name; + if (!uc_pdata->name) { + debug("Unnamed device!"); + return -EINVAL; + } + + if (!rproc_name_is_unique(dev, uc_pdata->name)) { + debug("%s duplicate name '%s'\n", dev->name, uc_pdata->name); + return -EINVAL; + } + + ops = rproc_get_ops(dev); + if (!ops) { + debug("%s driver has no ops?\n", dev->name); + return -EINVAL; + } + + if (!ops->load || !ops->start) { + debug("%s driver has missing mandatory ops?\n", dev->name); + return -EINVAL; + } + + return 0; +} + +/** + * rproc_post_probe() - post probe accessor for the uclass + * @dev: deivce we finished probing + * + * initiate init function after the probe is completed. This allows + * the remote processor drivers to split up the initializations between + * probe and init as needed. + * + * Return: if the remote proc driver has a init routine, invokes it and + * hands over the return value. overall, 0 if all went well, else appropriate + * error value. + */ +static int rproc_post_probe(struct udevice *dev) +{ + const struct dm_rproc_ops *ops; + + ops = rproc_get_ops(dev); + if (!ops) { + debug("%s driver has no ops?\n", dev->name); + return -EINVAL; + } + + if (ops->init) + return ops->init(dev); + + return 0; +} + +UCLASS_DRIVER(rproc) = { + .id = UCLASS_REMOTEPROC, + .name = "remoteproc", + .flags = DM_UC_FLAG_SEQ_ALIAS, + .pre_probe = rproc_pre_probe, + .post_probe = rproc_post_probe, + .per_device_platdata_auto_alloc_size = + sizeof(struct dm_rproc_uclass_pdata), +}; + +/* Remoteproc subsystem access functions */ +/** + * _rproc_probe_dev() - iteration helper to probe a rproc device + * @dev: device to probe + * @uc_pdata: uclass data allocated for the device + * @data: unused + * + * Return: 0 if all ok, else appropriate error value. + */ +static int _rproc_probe_dev(struct udevice *dev, + struct dm_rproc_uclass_pdata *uc_pdata, + const void *data) +{ + int ret; + + ret = device_probe(dev); + + if (ret) + debug("%s: Failed to initialize - %d\n", dev->name, ret); + return ret; +} + +/** + * _rproc_dev_is_probed() - check if the device has been probed + * @dev: device to check + * @uc_pdata: unused + * @data: unused + * + * Return: -EAGAIN if not probed else return 0 + */ +static int _rproc_dev_is_probed(struct udevice *dev, + struct dm_rproc_uclass_pdata *uc_pdata, + const void *data) +{ + if (dev->flags & DM_FLAG_ACTIVATED) + return 0; + + return -EAGAIN; +} + +bool rproc_is_initialized(void) +{ + int ret = for_each_remoteproc_device(_rproc_dev_is_probed, NULL, NULL); + return ret ? false : true; +} + +int rproc_init(void) +{ + int ret; + + if (rproc_is_initialized()) { + debug("Already initialized\n"); + return -EINVAL; + } + + ret = for_each_remoteproc_device(_rproc_probe_dev, NULL, NULL); + return ret; +} + +int rproc_load(int id, ulong addr, ulong size) +{ + struct udevice *dev = NULL; + struct dm_rproc_uclass_pdata *uc_pdata; + const struct dm_rproc_ops *ops; + int ret; + + ret = uclass_get_device_by_seq(UCLASS_REMOTEPROC, id, &dev); + if (ret) { + debug("Unknown remote processor id '%d' requested(%d)\n", + id, ret); + return ret; + } + + uc_pdata = dev_get_uclass_platdata(dev); + + ops = rproc_get_ops(dev); + if (!ops) { + debug("%s driver has no ops?\n", dev->name); + return -EINVAL; + } + + debug("Loading to '%s' from address 0x%08lX size of %lu bytes\n", + uc_pdata->name, addr, size); + if (ops->load) + return ops->load(dev, addr, size); + + debug("%s: data corruption?? mandatory function is missing!\n", + dev->name); + + return -EINVAL; +}; + +/* + * Completely internal helper enums.. + * Keeping this isolated helps this code evolve independent of other + * parts.. + */ +enum rproc_ops { + RPROC_START, + RPROC_STOP, + RPROC_RESET, + RPROC_PING, + RPROC_RUNNING, +}; + +/** + * _rproc_ops_wrapper() - wrapper for invoking remote proc driver callback + * @id: id of the remote processor + * @op: one of rproc_ops that indicate what operation to invoke + * + * Most of the checks and verification for remoteproc operations are more + * or less same for almost all operations. This allows us to put a wrapper + * and use the common checks to allow the driver to function appropriately. + * + * Return: 0 if all ok, else appropriate error value. + */ +static int _rproc_ops_wrapper(int id, enum rproc_ops op) +{ + struct udevice *dev = NULL; + struct dm_rproc_uclass_pdata *uc_pdata; + const struct dm_rproc_ops *ops; + int (*fn)(struct udevice *dev); + bool mandatory = false; + char *op_str; + int ret; + + ret = uclass_get_device_by_seq(UCLASS_REMOTEPROC, id, &dev); + if (ret) { + debug("Unknown remote processor id '%d' requested(%d)\n", + id, ret); + return ret; + } + + uc_pdata = dev_get_uclass_platdata(dev); + + ops = rproc_get_ops(dev); + if (!ops) { + debug("%s driver has no ops?\n", dev->name); + return -EINVAL; + } + switch (op) { + case RPROC_START: + fn = ops->start; + mandatory = true; + op_str = "Starting"; + break; + case RPROC_STOP: + fn = ops->stop; + op_str = "Stopping"; + break; + case RPROC_RESET: + fn = ops->reset; + op_str = "Resetting"; + break; + case RPROC_RUNNING: + fn = ops->is_running; + op_str = "Checking if running:"; + break; + case RPROC_PING: + fn = ops->ping; + op_str = "Pinging"; + break; + default: + debug("what is '%d' operation??\n", op); + return -EINVAL; + } + + debug("%s %s...\n", op_str, uc_pdata->name); + if (fn) + return fn(dev); + + if (mandatory) + debug("%s: data corruption?? mandatory function is missing!\n", + dev->name); + + return -ENOSYS; +} + +int rproc_start(int id) +{ + return _rproc_ops_wrapper(id, RPROC_START); +}; + +int rproc_stop(int id) +{ + return _rproc_ops_wrapper(id, RPROC_STOP); +}; + +int rproc_reset(int id) +{ + return _rproc_ops_wrapper(id, RPROC_RESET); +}; + +int rproc_ping(int id) +{ + return _rproc_ops_wrapper(id, RPROC_PING); +}; + +int rproc_is_running(int id) +{ + return _rproc_ops_wrapper(id, RPROC_RUNNING); +}; diff --git a/drivers/remoteproc/sandbox_testproc.c b/drivers/remoteproc/sandbox_testproc.c new file mode 100644 index 0000000000..004c7792d1 --- /dev/null +++ b/drivers/remoteproc/sandbox_testproc.c @@ -0,0 +1,336 @@ +/* + * (C) Copyright 2015 + * Texas Instruments Incorporated - http://www.ti.com/ + * SPDX-License-Identifier: GPL-2.0+ + */ +#define pr_fmt(fmt) "%s: " fmt, __func__ +#include <common.h> +#include <dm.h> +#include <errno.h> +#include <remoteproc.h> + +/** + * enum sandbox_state - different device states + * @sb_booted: Entry condition, just booted + * @sb_init: Initialized (basic environment is ready) + * @sb_reset: Held in reset (accessible, but not running) + * @sb_loaded: Loaded with image (but not running) + * @sb_running: Processor is running + */ +enum sandbox_state { + sb_booted, + sb_init, + sb_reset, + sb_loaded, + sb_running +}; + +/** + * struct sandbox_test_devdata - private data per device + * @current_state: device current state + */ +struct sandbox_test_devdata { + enum sandbox_state current_state; +}; + +/** + * sandbox_dev_move_to_state() - statemachine for our dummy device + * @dev: device to switch state + * @next_state: next proposed state + * + * This tries to follow the following statemachine: + * Entry + * | + * v + * +-------+ + * +---+ init | + * | | | <---------------------+ + * | +-------+ | + * | | + * | | + * | +--------+ | + * Load| | reset | | + * | | | <----------+ | + * | +--------+ | | + * | |Load | | + * | | | | + * | +----v----+ reset | | + * +-> | | (opt) | | + * | Loaded +-----------+ | + * | | | + * +----+----+ | + * | Start | + * +---v-----+ (opt) | + * +->| Running | Stop | + * Ping +- | +--------------------+ + * (opt) +---------+ + * + * (is_running does not change state) + * + * Return: 0 when valid state transition is seen, else returns -EINVAL + */ +static int sandbox_dev_move_to_state(struct udevice *dev, + enum sandbox_state next_state) +{ + struct sandbox_test_devdata *ddata = dev_get_priv(dev); + + /* No state transition is OK */ + if (ddata->current_state == next_state) + return 0; + + debug("current_state=%d, next_state=%d\n", ddata->current_state, + next_state); + switch (ddata->current_state) { + case sb_booted: + if (next_state == sb_init) + goto ok_state; + break; + + case sb_init: + if (next_state == sb_reset || next_state == sb_loaded) + goto ok_state; + break; + + case sb_reset: + if (next_state == sb_loaded || next_state == sb_init) + goto ok_state; + break; + + case sb_loaded: + if (next_state == sb_reset || next_state == sb_init || + next_state == sb_running) + goto ok_state; + break; + + case sb_running: + if (next_state == sb_reset || next_state == sb_init) + goto ok_state; + break; + }; + return -EINVAL; + +ok_state: + ddata->current_state = next_state; + return 0; +} + +/** + * sandbox_testproc_probe() - basic probe function + * @dev: test proc device that is being probed. + * + * Return: 0 if all went ok, else return appropriate error + */ +static int sandbox_testproc_probe(struct udevice *dev) +{ + struct dm_rproc_uclass_pdata *uc_pdata; + struct sandbox_test_devdata *ddata; + int ret; + + uc_pdata = dev_get_uclass_platdata(dev); + ddata = dev_get_priv(dev); + if (!ddata) { + debug("%s: platform private data missing\n", uc_pdata->name); + return -EINVAL; + } + ret = sandbox_dev_move_to_state(dev, sb_booted); + debug("%s: called(%d)\n", uc_pdata->name, ret); + + return ret; +} + +/** + * sandbox_testproc_init() - Simple initialization function + * @dev: device to operate upon + * + * Return: 0 if all went ok, else return appropriate error + */ +static int sandbox_testproc_init(struct udevice *dev) +{ + struct dm_rproc_uclass_pdata *uc_pdata; + int ret; + + uc_pdata = dev_get_uclass_platdata(dev); + + ret = sandbox_dev_move_to_state(dev, sb_init); + + debug("%s: called(%d)\n", uc_pdata->name, ret); + if (ret) + debug("%s init failed\n", uc_pdata->name); + + return ret; +} + +/** + * sandbox_testproc_reset() - Reset the remote processor + * @dev: device to operate upon + * + * Return: 0 if all went ok, else return appropriate error + */ +static int sandbox_testproc_reset(struct udevice *dev) +{ + struct dm_rproc_uclass_pdata *uc_pdata; + int ret; + + uc_pdata = dev_get_uclass_platdata(dev); + + ret = sandbox_dev_move_to_state(dev, sb_reset); + + debug("%s: called(%d)\n", uc_pdata->name, ret); + + if (ret) + debug("%s reset failed\n", uc_pdata->name); + return ret; +} + +/** + * sandbox_testproc_load() - (replace: short desc) + * @dev: device to operate upon + * @addr: Address of the binary image to load + * @size: Size (in bytes) of the binary image to load + * + * Return: 0 if all went ok, else return appropriate error + */ +static int sandbox_testproc_load(struct udevice *dev, ulong addr, ulong size) +{ + struct dm_rproc_uclass_pdata *uc_pdata; + int ret; + + uc_pdata = dev_get_uclass_platdata(dev); + + ret = sandbox_dev_move_to_state(dev, sb_loaded); + + debug("%s: called(%d) Loading to %08lX %lu size\n", + uc_pdata->name, ret, addr, size); + + if (ret) + debug("%s load failed\n", uc_pdata->name); + return ret; +} + +/** + * sandbox_testproc_start() - Start the remote processor + * @dev: device to operate upon + * + * Return: 0 if all went ok, else return appropriate error + */ +static int sandbox_testproc_start(struct udevice *dev) +{ + struct dm_rproc_uclass_pdata *uc_pdata; + int ret; + + uc_pdata = dev_get_uclass_platdata(dev); + + ret = sandbox_dev_move_to_state(dev, sb_running); + + debug("%s: called(%d)\n", uc_pdata->name, ret); + + if (ret) + debug("%s start failed\n", uc_pdata->name); + return ret; +} + +/** + * sandbox_testproc_stop() - Stop the remote processor + * @dev: device to operate upon + * + * Return: 0 if all went ok, else return appropriate error + */ +static int sandbox_testproc_stop(struct udevice *dev) +{ + struct dm_rproc_uclass_pdata *uc_pdata; + int ret; + + uc_pdata = dev_get_uclass_platdata(dev); + + ret = sandbox_dev_move_to_state(dev, sb_init); + + debug("%s: called(%d)\n", uc_pdata->name, ret); + + if (ret) + debug("%s stop failed\n", uc_pdata->name); + return ret; +} + +/** + * sandbox_testproc_is_running() - Check if remote processor is running + * @dev: device to operate upon + * + * Return: 0 if running, 1 if not running + */ +static int sandbox_testproc_is_running(struct udevice *dev) +{ + struct dm_rproc_uclass_pdata *uc_pdata; + struct sandbox_test_devdata *ddata; + int ret = 1; + + uc_pdata = dev_get_uclass_platdata(dev); + ddata = dev_get_priv(dev); + + if (ddata->current_state == sb_running) + ret = 0; + debug("%s: called(%d)\n", uc_pdata->name, ret); + + return ret; +} + +/** + * sandbox_testproc_ping() - Try pinging remote processor + * @dev: device to operate upon + * + * Return: 0 if running, -EINVAL if not running + */ +static int sandbox_testproc_ping(struct udevice *dev) +{ + struct dm_rproc_uclass_pdata *uc_pdata; + struct sandbox_test_devdata *ddata; + int ret; + + uc_pdata = dev_get_uclass_platdata(dev); + ddata = dev_get_priv(dev); + + if (ddata->current_state == sb_running) + ret = 0; + else + ret = -EINVAL; + + debug("%s: called(%d)\n", uc_pdata->name, ret); + if (ret) + debug("%s: No response.(Not started?)\n", uc_pdata->name); + + return ret; +} + +static const struct dm_rproc_ops sandbox_testproc_ops = { + .init = sandbox_testproc_init, + .reset = sandbox_testproc_reset, + .load = sandbox_testproc_load, + .start = sandbox_testproc_start, + .stop = sandbox_testproc_stop, + .is_running = sandbox_testproc_is_running, + .ping = sandbox_testproc_ping, +}; + +static const struct udevice_id sandbox_ids[] = { + {.compatible = "sandbox,test-processor"}, + {} +}; + +U_BOOT_DRIVER(sandbox_testproc) = { + .name = "sandbox_test_proc", + .of_match = sandbox_ids, + .id = UCLASS_REMOTEPROC, + .ops = &sandbox_testproc_ops, + .probe = sandbox_testproc_probe, + .priv_auto_alloc_size = sizeof(struct sandbox_test_devdata), +}; + +/* TODO(nm@ti.com): Remove this along with non-DT support */ +static struct dm_rproc_uclass_pdata proc_3_test = { + .name = "proc_3_legacy", + .mem_type = RPROC_INTERNAL_MEMORY_MAPPED, +}; + +U_BOOT_DEVICE(proc_3_demo) = { + .name = "sandbox_test_proc", + .platdata = &proc_3_test, +}; diff --git a/drivers/rtc/mc146818.c b/drivers/rtc/mc146818.c index 363ade33e3..da804d5459 100644 --- a/drivers/rtc/mc146818.c +++ b/drivers/rtc/mc146818.c @@ -192,7 +192,7 @@ static void mc146818_init(void) /* Clear any pending interrupts */ mc146818_read8(RTC_CONFIG_C); } -#endif +#endif /* CONFIG_CMD_DATE */ #ifdef CONFIG_DM_RTC @@ -225,7 +225,7 @@ static int rtc_mc146818_write8(struct udevice *dev, unsigned int reg, int val) return 0; } -static int rtc_mc146818_bind(struct udevice *dev) +static int rtc_mc146818_probe(struct udevice *dev) { mc146818_init(); @@ -249,7 +249,7 @@ U_BOOT_DRIVER(rtc_mc146818) = { .name = "rtc_mc146818", .id = UCLASS_RTC, .of_match = rtc_mc146818_ids, - .bind = rtc_mc146818_bind, + .probe = rtc_mc146818_probe, .ops = &rtc_mc146818_ops, }; diff --git a/drivers/rtc/rtc-uclass.c b/drivers/rtc/rtc-uclass.c index fe74c69f97..300e9b30ec 100644 --- a/drivers/rtc/rtc-uclass.c +++ b/drivers/rtc/rtc-uclass.c @@ -68,7 +68,7 @@ int rtc_read32(struct udevice *dev, unsigned int reg, u32 *valuep) for (i = 0; i < sizeof(value); i++) { ret = rtc_read8(dev, reg + i); - if (ret) + if (ret < 0) return ret; value |= ret << (i << 3); } diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index ddb725d326..ac5920ad5a 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -109,6 +109,27 @@ config DEBUG_UART_SHIFT value. Use this value to specify the shift to use, where 0=byte registers, 2=32-bit word registers, etc. +config DEBUG_UART_BOARD_INIT + bool "Enable board-specific debug UART init" + depends on DEBUG_UART + help + Some boards need to set things up before the debug UART can be used. + On these boards a call to debug_uart_init() is insufficient. When + this option is enabled, the function board_debug_uart_init() will + be called when debug_uart_init() is called. You can put any code + here that is needed to set up the UART ready for use, such as set + pin multiplexing or enable clocks. + +config DEBUG_UART_ANNOUNCE + bool "Show a message when the debug UART starts up" + depends on DEBUG_UART + help + Enable this option to show a message when the debug UART is ready + for use. You will see a message like "<debug_uart> " as soon as + U-Boot has the UART ready for use (i.e. your code calls + debug_uart_init()). This can be useful just as a check that + everything is working. + config ROCKCHIP_SERIAL bool "Rockchip on-chip UART support" depends on ARCH_ROCKCHIP && DM_SERIAL diff --git a/drivers/serial/ns16550.c b/drivers/serial/ns16550.c index 6275a11a0c..6433844f18 100644 --- a/drivers/serial/ns16550.c +++ b/drivers/serial/ns16550.c @@ -257,7 +257,7 @@ int NS16550_tstc(NS16550_t com_port) (1 << CONFIG_DEBUG_UART_SHIFT), \ CONFIG_DEBUG_UART_SHIFT) -void debug_uart_init(void) +static inline void _debug_uart_init(void) { struct NS16550 *com_port = (struct NS16550 *)CONFIG_DEBUG_UART_BASE; int baud_divisor; diff --git a/drivers/serial/serial_efi.c b/drivers/serial/serial_efi.c index cf57d8977b..ea25c25a68 100644 --- a/drivers/serial/serial_efi.c +++ b/drivers/serial/serial_efi.c @@ -107,7 +107,7 @@ static int serial_efi_pending(struct udevice *dev, bool input) * There is nothing to init here since the EFI console is already running by * the time we enter U-Boot. */ -void debug_uart_init(void) +static inline void _debug_uart_init(void) { } diff --git a/drivers/serial/serial_omap.c b/drivers/serial/serial_omap.c index e8d544f0da..891cd7b7ed 100644 --- a/drivers/serial/serial_omap.c +++ b/drivers/serial/serial_omap.c @@ -12,10 +12,16 @@ DECLARE_GLOBAL_DATA_PTR; +#define DEFAULT_CLK_SPEED 48000000 /* 48Mhz */ + #if CONFIG_IS_ENABLED(OF_CONTROL) static const struct udevice_id omap_serial_ids[] = { + { .compatible = "ti,omap2-uart" }, { .compatible = "ti,omap3-uart" }, { .compatible = "ti,omap4-uart" }, + { .compatible = "ti,am3352-uart" }, + { .compatible = "ti,am4372-uart" }, + { .compatible = "ti,dra742-uart" }, { } }; @@ -28,7 +34,7 @@ static int omap_serial_ofdata_to_platdata(struct udevice *dev) if (ret) return ret; plat->clock = fdtdec_get_int(gd->fdt_blob, dev->of_offset, - "clock-frequency", -1); + "clock-frequency", DEFAULT_CLK_SPEED); plat->reg_shift = 2; return 0; diff --git a/drivers/serial/serial_s5p.c b/drivers/serial/serial_s5p.c index 3f0b588254..feba467d80 100644 --- a/drivers/serial/serial_s5p.c +++ b/drivers/serial/serial_s5p.c @@ -207,7 +207,7 @@ U_BOOT_DRIVER(serial_s5p) = { #include <debug_uart.h> -void debug_uart_init(void) +static inline void _debug_uart_init(void) { struct s5p_uart *uart = (struct s5p_uart *)CONFIG_DEBUG_UART_BASE; diff --git a/drivers/spi/ich.c b/drivers/spi/ich.c index 2e388e7ad9..be4c0a3353 100644 --- a/drivers/spi/ich.c +++ b/drivers/spi/ich.c @@ -133,7 +133,8 @@ static int get_ich_version(uint16_t device_id) (device_id >= PCI_DEVICE_ID_INTEL_PANTHERPOINT_LPC_MIN && device_id <= PCI_DEVICE_ID_INTEL_PANTHERPOINT_LPC_MAX) || device_id == PCI_DEVICE_ID_INTEL_VALLEYVIEW_LPC || - device_id == PCI_DEVICE_ID_INTEL_LYNXPOINT_LPC) + device_id == PCI_DEVICE_ID_INTEL_LYNXPOINT_LPC || + device_id == PCI_DEVICE_ID_INTEL_WILDCATPOINT_LPC) return 9; return 0; diff --git a/drivers/usb/gadget/f_fastboot.c b/drivers/usb/gadget/f_fastboot.c index ca01a018b5..ece48e668c 100644 --- a/drivers/usb/gadget/f_fastboot.c +++ b/drivers/usb/gadget/f_fastboot.c @@ -554,7 +554,7 @@ static void cb_flash(struct usb_ep *ep, struct usb_request *req) static void cb_oem(struct usb_ep *ep, struct usb_request *req) { char *cmd = req->buf; -#ifdef CONFIG_FASTBOOT_FLASH +#ifdef CONFIG_FASTBOOT_FLASH_MMC_DEV if (strncmp("format", cmd + 4, 6) == 0) { char cmdbuf[32]; sprintf(cmdbuf, "gpt write mmc %x $partitions", 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 */ diff --git a/drivers/video/sunxi_display.c b/drivers/video/sunxi_display.c index fc1aea3f06..9fee66a2a4 100644 --- a/drivers/video/sunxi_display.c +++ b/drivers/video/sunxi_display.c @@ -15,7 +15,7 @@ #include <asm/global_data.h> #include <asm/gpio.h> #include <asm/io.h> -#include <axp221.h> +#include <axp_pmic.h> #include <errno.h> #include <fdtdec.h> #include <fdt_support.h> @@ -1217,10 +1217,10 @@ static void sunxi_mode_set(const struct ctfb_res_modes *mode, if (IS_ENABLED(CONFIG_VIDEO_LCD_PANEL_EDP_4_LANE_1620M_VIA_ANX9804)) { /* * The anx9804 needs 1.8V from eldo3, we do this here - * and not via CONFIG_AXP221_ELDO3 from board_init() + * and not via CONFIG_AXP_ELDO3_VOLT from board_init() * to avoid turning this on when using hdmi output. */ - axp221_set_eldo(3, 1800); + axp_set_eldo(3, 1800); anx9804_init(CONFIG_VIDEO_LCD_I2C_BUS, 4, ANX9804_DATA_RATE_1620M, sunxi_display.depth); diff --git a/drivers/video/vesa_fb.c b/drivers/video/vesa_fb.c index 4e6d070a5f..a19651f5f3 100644 --- a/drivers/video/vesa_fb.c +++ b/drivers/video/vesa_fb.c @@ -34,7 +34,7 @@ void *video_hw_init(void) } if (vbe_get_video_info(gdev)) { dev = pci_find_class(PCI_CLASS_DISPLAY_VGA << 8, 0); - if (dev == -1) { + if (dev < 0) { printf("no card detected\n"); return NULL; } |