summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/Kconfig2
-rw-r--r--drivers/Makefile2
-rw-r--r--drivers/block/Kconfig10
-rw-r--r--drivers/block/Makefile1
-rw-r--r--drivers/block/dwc_ahci.c101
-rw-r--r--drivers/clk/Kconfig8
-rw-r--r--drivers/clk/Makefile1
-rw-r--r--drivers/clk/at91/clk-master.c1
-rw-r--r--drivers/clk/at91/clk-peripheral.c29
-rw-r--r--drivers/clk/at91/pmc.c6
-rw-r--r--drivers/clk/clk_bcm6345.c78
-rw-r--r--drivers/clk/rockchip/clk_rk3036.c5
-rw-r--r--drivers/clk/rockchip/clk_rk3188.c12
-rw-r--r--drivers/clk/rockchip/clk_rk3288.c12
-rw-r--r--drivers/clk/rockchip/clk_rk3328.c8
-rw-r--r--drivers/clk/rockchip/clk_rk3399.c131
-rw-r--r--drivers/core/device-remove.c16
-rw-r--r--drivers/cpu/Makefile2
-rw-r--r--drivers/cpu/bmips_cpu.c310
-rw-r--r--drivers/dfu/dfu.c4
-rw-r--r--drivers/gpio/74x164_gpio.c3
-rw-r--r--drivers/gpio/Kconfig14
-rw-r--r--drivers/gpio/Makefile1
-rw-r--r--drivers/gpio/bcm6345_gpio.c125
-rw-r--r--drivers/gpio/gpio-uclass.c2
-rw-r--r--drivers/gpio/intel_ich6_gpio.c30
-rw-r--r--drivers/i2c/davinci_i2c.c277
-rw-r--r--drivers/i2c/fsl_i2c.c9
-rw-r--r--drivers/i2c/fti2c010.c9
-rw-r--r--drivers/i2c/mxc_i2c.c4
-rw-r--r--drivers/i2c/omap24xx_i2c.c7
-rw-r--r--drivers/led/Kconfig19
-rw-r--r--drivers/led/Makefile2
-rw-r--r--drivers/led/led_bcm6328.c262
-rw-r--r--drivers/led/led_bcm6358.c227
-rw-r--r--drivers/misc/i2c_eeprom.c32
-rw-r--r--drivers/mmc/Kconfig5
-rw-r--r--drivers/mmc/Makefile28
-rw-r--r--drivers/mmc/atmel_sdhci.c4
-rw-r--r--drivers/mmc/bcm2835_sdhci.c81
-rw-r--r--drivers/mmc/davinci_mmc.c2
-rw-r--r--drivers/mmc/omap_hsmmc.c95
-rw-r--r--drivers/mmc/pci_mmc.c86
-rw-r--r--drivers/mmc/rockchip_dw_mmc.c24
-rw-r--r--drivers/mmc/sdhci-cadence.c67
-rw-r--r--drivers/mmc/sdhci.c18
-rw-r--r--drivers/mtd/nand/pxa3xx_nand.c62
-rw-r--r--drivers/net/eepro100.c6
-rw-r--r--drivers/net/macb.c52
-rw-r--r--drivers/net/mvpp2.c24
-rw-r--r--drivers/net/phy/mv88e61xx.c4
-rw-r--r--drivers/net/uli526x.c1
-rw-r--r--drivers/pci/pci-uclass.c1
-rw-r--r--drivers/pci/pci_rom.c14
-rw-r--r--drivers/pci/pcie_dw_mvebu.c10
-rw-r--r--drivers/phy/Kconfig62
-rw-r--r--drivers/phy/Makefile10
-rw-r--r--drivers/phy/marvell/comphy.h3
-rw-r--r--drivers/phy/marvell/comphy_core.c16
-rw-r--r--drivers/phy/marvell/comphy_cp110.c449
-rw-r--r--drivers/phy/marvell/comphy_hpipe.h277
-rw-r--r--drivers/phy/marvell/comphy_mux.c7
-rw-r--r--drivers/phy/phy-uclass.c139
-rw-r--r--drivers/phy/sandbox-phy.c108
-rw-r--r--drivers/phy/ti-pipe3-phy.c373
-rw-r--r--drivers/pinctrl/nxp/pinctrl-imx.c4
-rw-r--r--drivers/pinctrl/pinctrl-single.c16
-rw-r--r--drivers/pinctrl/rockchip/pinctrl_rk3399.c61
-rw-r--r--drivers/power/Kconfig8
-rw-r--r--drivers/power/domain/Kconfig7
-rw-r--r--drivers/power/domain/Makefile1
-rw-r--r--drivers/power/domain/bcm6328-power-domain.c83
-rw-r--r--drivers/power/pmic/Kconfig6
-rw-r--r--drivers/power/pmic/Makefile2
-rw-r--r--drivers/power/pmic/rk8xx.c (renamed from drivers/power/pmic/rk808.c)52
-rw-r--r--drivers/power/regulator/Kconfig8
-rw-r--r--drivers/power/regulator/Makefile2
-rw-r--r--drivers/power/regulator/pwm_regulator.c16
-rw-r--r--drivers/power/regulator/rk8xx.c (renamed from drivers/power/regulator/rk808.c)142
-rw-r--r--drivers/power/twl4030.c9
-rw-r--r--drivers/pwm/pwm-uclass.c10
-rw-r--r--drivers/pwm/rk_pwm.c17
-rw-r--r--drivers/pwm/sandbox_pwm.c16
-rw-r--r--drivers/ram/Makefile1
-rw-r--r--drivers/ram/bmips_ram.c122
-rw-r--r--drivers/reset/Kconfig6
-rw-r--r--drivers/reset/Makefile1
-rw-r--r--drivers/reset/reset-bcm6345.c89
-rw-r--r--drivers/serial/Kconfig21
-rw-r--r--drivers/serial/Makefile1
-rw-r--r--drivers/serial/atmel_usart.c84
-rw-r--r--drivers/serial/ns16550.c57
-rw-r--r--drivers/serial/serial-uclass.c2
-rw-r--r--drivers/serial/serial_bcm6345.c300
-rw-r--r--drivers/spi/Kconfig6
-rw-r--r--drivers/spi/ich.c18
-rw-r--r--drivers/spi/ich.h54
-rw-r--r--drivers/spi/omap3_spi.c3
-rw-r--r--drivers/spi/rk_spi.c62
-rw-r--r--drivers/spi/rk_spi.h9
-rw-r--r--drivers/sysreset/Kconfig8
-rw-r--r--drivers/sysreset/Makefile1
-rw-r--r--drivers/sysreset/sysreset_syscon.c78
-rw-r--r--drivers/usb/eth/smsc95xx.c4
-rw-r--r--drivers/usb/gadget/f_fastboot.c12
-rw-r--r--drivers/usb/host/Kconfig19
-rw-r--r--drivers/usb/host/Makefile2
-rw-r--r--drivers/usb/musb-new/linux-compat.h2
-rw-r--r--drivers/usb/musb-new/omap2430.c2
-rw-r--r--drivers/usb/musb/omap3.c6
-rw-r--r--drivers/usb/musb/omap3.h2
-rw-r--r--drivers/video/Kconfig19
-rw-r--r--drivers/video/Makefile1
-rw-r--r--drivers/video/bcm2835.c140
-rw-r--r--drivers/video/dw_hdmi.c31
-rw-r--r--drivers/video/ld9040.c16
-rw-r--r--drivers/video/rockchip/Kconfig51
-rw-r--r--drivers/video/rockchip/Makefile8
-rw-r--r--drivers/video/rockchip/rk_mipi.c491
-rw-r--r--drivers/video/rockchip/rk_vop.c30
-rw-r--r--drivers/video/sunxi/Makefile2
-rw-r--r--drivers/video/sunxi/sunxi_display.c73
-rw-r--r--drivers/video/sunxi/tve.c86
-rw-r--r--drivers/video/video_bmp.c4
-rw-r--r--drivers/watchdog/Kconfig20
-rw-r--r--drivers/watchdog/Makefile1
-rw-r--r--drivers/watchdog/bcm2835_wdt.c35
127 files changed, 5507 insertions, 723 deletions
diff --git a/drivers/Kconfig b/drivers/Kconfig
index a096dad2b22..a5f24d72da7 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -54,6 +54,8 @@ source "drivers/pci/Kconfig"
source "drivers/pcmcia/Kconfig"
+source "drivers/phy/Kconfig"
+
source "drivers/phy/marvell/Kconfig"
source "drivers/pinctrl/Kconfig"
diff --git a/drivers/Makefile b/drivers/Makefile
index 4a4b2377c58..64c39d3a3ef 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -5,6 +5,7 @@
obj-$(CONFIG_$(SPL_TPL_)DM) += core/
obj-$(CONFIG_$(SPL_)CLK) += clk/
obj-$(CONFIG_$(SPL_)LED) += led/
+obj-$(CONFIG_$(SPL_)PHY) += phy/
obj-$(CONFIG_$(SPL_)PINCTRL) += pinctrl/
obj-$(CONFIG_$(SPL_)RAM) += ram/
@@ -75,6 +76,7 @@ obj-y += firmware/
obj-$(CONFIG_FPGA) += fpga/
obj-y += hwmon/
obj-y += misc/
+obj-$(CONFIG_MMC) += mmc/
obj-y += pcmcia/
obj-y += dfu/
obj-$(CONFIG_X86) += pch/
diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig
index 88e66e2377a..6cbe1454b83 100644
--- a/drivers/block/Kconfig
+++ b/drivers/block/Kconfig
@@ -48,4 +48,14 @@ config SATA_CEVA
ZynqMP. Support up to 2 external devices. Complient with SATA 3.1 and
AHCI 1.3 specifications with hot-plug detect feature.
+
+config DWC_AHCI
+ bool "Enable Synopsys DWC AHCI driver support"
+ select SCSI_AHCI
+ select PHY
+ depends on DM_SCSI
+ help
+ Enable this driver to support Sata devices through
+ Synopsys DWC AHCI module.
+
endmenu
diff --git a/drivers/block/Makefile b/drivers/block/Makefile
index f415b3371bb..d89c8b05746 100644
--- a/drivers/block/Makefile
+++ b/drivers/block/Makefile
@@ -11,6 +11,7 @@ ifndef CONFIG_BLK
obj-y += blk_legacy.o
endif
+obj-$(CONFIG_DWC_AHCI) += dwc_ahci.o
obj-$(CONFIG_AHCI) += ahci-uclass.o
obj-$(CONFIG_DM_SCSI) += scsi-uclass.o
obj-$(CONFIG_SCSI_AHCI) += ahci.o
diff --git a/drivers/block/dwc_ahci.c b/drivers/block/dwc_ahci.c
new file mode 100644
index 00000000000..d5bb0b887ae
--- /dev/null
+++ b/drivers/block/dwc_ahci.c
@@ -0,0 +1,101 @@
+/*
+ * DWC SATA platform driver
+ *
+ * (C) Copyright 2016
+ * Texas Instruments Incorporated, <www.ti.com>
+ *
+ * Author: Mugunthan V N <mugunthanvnm@ti.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <ahci.h>
+#include <scsi.h>
+#include <sata.h>
+#include <asm/arch/sata.h>
+#include <asm/io.h>
+#include <generic-phy.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+struct dwc_ahci_priv {
+ void *base;
+ void *wrapper_base;
+};
+
+static int dwc_ahci_ofdata_to_platdata(struct udevice *dev)
+{
+ struct dwc_ahci_priv *priv = dev_get_priv(dev);
+ struct scsi_platdata *plat = dev_get_platdata(dev);
+ fdt_addr_t addr;
+
+ plat->max_id = fdtdec_get_uint(gd->fdt_blob, dev->of_offset, "max-id",
+ CONFIG_SYS_SCSI_MAX_SCSI_ID);
+ plat->max_lun = fdtdec_get_uint(gd->fdt_blob, dev->of_offset,
+ "max-lun", CONFIG_SYS_SCSI_MAX_LUN);
+
+ priv->base = map_physmem(dev_get_addr(dev), sizeof(void *),
+ MAP_NOCACHE);
+
+ addr = dev_get_addr_index(dev, 1);
+ if (addr != FDT_ADDR_T_NONE) {
+ priv->wrapper_base = map_physmem(addr, sizeof(void *),
+ MAP_NOCACHE);
+ } else {
+ priv->wrapper_base = NULL;
+ }
+
+ return 0;
+}
+
+static int dwc_ahci_probe(struct udevice *dev)
+{
+ struct dwc_ahci_priv *priv = dev_get_priv(dev);
+ int ret;
+ struct phy phy;
+
+ ret = generic_phy_get_by_name(dev, "sata-phy", &phy);
+ if (ret) {
+ error("can't get the phy from DT\n");
+ return ret;
+ }
+
+ ret = generic_phy_init(&phy);
+ if (ret) {
+ error("unable to initialize the sata phy\n");
+ return ret;
+ }
+
+ ret = generic_phy_power_on(&phy);
+ if (ret) {
+ error("unable to power on the sata phy\n");
+ return ret;
+ }
+
+ if (priv->wrapper_base) {
+ u32 val = TI_SATA_IDLE_NO | TI_SATA_STANDBY_NO;
+
+ /* Enable SATA module, No Idle, No Standby */
+ writel(val, priv->wrapper_base + TI_SATA_SYSCONFIG);
+ }
+
+ return ahci_init(priv->base);
+}
+
+static const struct udevice_id dwc_ahci_ids[] = {
+ { .compatible = "snps,dwc-ahci" },
+ { }
+};
+
+U_BOOT_DRIVER(dwc_ahci) = {
+ .name = "dwc_ahci",
+ .id = UCLASS_SCSI,
+ .of_match = dwc_ahci_ids,
+ .ofdata_to_platdata = dwc_ahci_ofdata_to_platdata,
+ .probe = dwc_ahci_probe,
+ .priv_auto_alloc_size = sizeof(struct dwc_ahci_priv),
+ .platdata_auto_alloc_size = sizeof(struct scsi_platdata),
+ .flags = DM_FLAG_ALLOC_PRIV_DMA,
+};
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index 5ca958c0075..44da716b267 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -20,6 +20,14 @@ config SPL_CLK
setting up clocks within SPL, and allows the same drivers to be
used as U-Boot proper.
+config CLK_BCM6345
+ bool "Clock controller driver for BCM6345"
+ depends on CLK && ARCH_BMIPS
+ default y
+ help
+ This clock driver adds support for enabling and disabling peripheral
+ clocks on BCM6345 SoCs. HW has no rate changing capabilities.
+
config CLK_BOSTON
def_bool y if TARGET_BOSTON
depends on CLK
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index 01a8cd641e7..2746a8016ab 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -17,6 +17,7 @@ obj-y += tegra/
obj-$(CONFIG_CLK_UNIPHIER) += uniphier/
obj-$(CONFIG_CLK_EXYNOS) += exynos/
obj-$(CONFIG_CLK_AT91) += at91/
+obj-$(CONFIG_CLK_BCM6345) += clk_bcm6345.o
obj-$(CONFIG_CLK_BOSTON) += clk_boston.o
obj-$(CONFIG_ARCH_ASPEED) += aspeed/
obj-$(CONFIG_STM32F7) += clk_stm32f7.o
diff --git a/drivers/clk/at91/clk-master.c b/drivers/clk/at91/clk-master.c
index 284b2482712..72d0a739f11 100644
--- a/drivers/clk/at91/clk-master.c
+++ b/drivers/clk/at91/clk-master.c
@@ -21,6 +21,7 @@ static struct clk_ops at91_master_clk_ops = {
};
static const struct udevice_id at91_master_clk_match[] = {
+ { .compatible = "atmel,at91rm9200-clk-master" },
{ .compatible = "atmel,at91sam9x5-clk-master" },
{}
};
diff --git a/drivers/clk/at91/clk-peripheral.c b/drivers/clk/at91/clk-peripheral.c
index e1ed447133e..62fabe304dc 100644
--- a/drivers/clk/at91/clk-peripheral.c
+++ b/drivers/clk/at91/clk-peripheral.c
@@ -16,6 +16,10 @@
#define PERIPHERAL_ID_MAX 31
#define PERIPHERAL_MASK(id) (1 << ((id) & PERIPHERAL_ID_MAX))
+enum periph_clk_type {
+ CLK_PERIPH_AT91RM9200 = 0,
+ CLK_PERIPH_AT91SAM9X5,
+};
/**
* sam9x5_periph_clk_bind() - for the periph clock driver
* Recursively bind its children as clk devices.
@@ -28,7 +32,14 @@ static int sam9x5_periph_clk_bind(struct udevice *dev)
}
static const struct udevice_id sam9x5_periph_clk_match[] = {
- { .compatible = "atmel,at91sam9x5-clk-peripheral" },
+ {
+ .compatible = "atmel,at91rm9200-clk-peripheral",
+ .data = CLK_PERIPH_AT91RM9200,
+ },
+ {
+ .compatible = "atmel,at91sam9x5-clk-peripheral",
+ .data = CLK_PERIPH_AT91SAM9X5,
+ },
{}
};
@@ -45,12 +56,24 @@ static int periph_clk_enable(struct clk *clk)
{
struct pmc_platdata *plat = dev_get_platdata(clk->dev);
struct at91_pmc *pmc = plat->reg_base;
+ enum periph_clk_type clk_type;
+ void *addr;
if (clk->id < PERIPHERAL_ID_MIN)
return -1;
- writel(clk->id & AT91_PMC_PCR_PID_MASK, &pmc->pcr);
- setbits_le32(&pmc->pcr, AT91_PMC_PCR_CMD_WRITE | AT91_PMC_PCR_EN);
+ clk_type = dev_get_driver_data(dev_get_parent(clk->dev));
+ if (clk_type == CLK_PERIPH_AT91RM9200) {
+ addr = &pmc->pcer;
+ if (clk->id > PERIPHERAL_ID_MAX)
+ addr = &pmc->pcer1;
+
+ setbits_le32(addr, PERIPHERAL_MASK(clk->id));
+ } else {
+ writel(clk->id & AT91_PMC_PCR_PID_MASK, &pmc->pcr);
+ setbits_le32(&pmc->pcr,
+ AT91_PMC_PCR_CMD_WRITE | AT91_PMC_PCR_EN);
+ }
return 0;
}
diff --git a/drivers/clk/at91/pmc.c b/drivers/clk/at91/pmc.c
index fcd693a2f6f..72d52c58188 100644
--- a/drivers/clk/at91/pmc.c
+++ b/drivers/clk/at91/pmc.c
@@ -16,6 +16,12 @@
DECLARE_GLOBAL_DATA_PTR;
static const struct udevice_id at91_pmc_match[] = {
+ { .compatible = "atmel,at91rm9200-pmc" },
+ { .compatible = "atmel,at91sam9260-pmc" },
+ { .compatible = "atmel,at91sam9g45-pmc" },
+ { .compatible = "atmel,at91sam9n12-pmc" },
+ { .compatible = "atmel,at91sam9x5-pmc" },
+ { .compatible = "atmel,sama5d3-pmc" },
{ .compatible = "atmel,sama5d2-pmc" },
{}
};
diff --git a/drivers/clk/clk_bcm6345.c b/drivers/clk/clk_bcm6345.c
new file mode 100644
index 00000000000..4c7a2dfb70b
--- /dev/null
+++ b/drivers/clk/clk_bcm6345.c
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2017 Álvaro Fernández Rojas <noltari@gmail.com>
+ *
+ * Derived from linux/arch/mips/bcm63xx/clk.c:
+ * Copyright (C) 2008 Maxime Bizon <mbizon@freebox.fr>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <clk-uclass.h>
+#include <dm.h>
+#include <errno.h>
+#include <asm/io.h>
+
+#define MAX_CLKS 32
+
+struct bcm6345_clk_priv {
+ void __iomem *regs;
+};
+
+static int bcm6345_clk_enable(struct clk *clk)
+{
+ struct bcm6345_clk_priv *priv = dev_get_priv(clk->dev);
+
+ if (clk->id >= MAX_CLKS)
+ return -EINVAL;
+
+ setbits_be32(priv->regs, BIT(clk->id));
+
+ return 0;
+}
+
+static int bcm6345_clk_disable(struct clk *clk)
+{
+ struct bcm6345_clk_priv *priv = dev_get_priv(clk->dev);
+
+ if (clk->id >= MAX_CLKS)
+ return -EINVAL;
+
+ clrbits_be32(priv->regs, BIT(clk->id));
+
+ return 0;
+}
+
+static struct clk_ops bcm6345_clk_ops = {
+ .disable = bcm6345_clk_disable,
+ .enable = bcm6345_clk_enable,
+};
+
+static const struct udevice_id bcm6345_clk_ids[] = {
+ { .compatible = "brcm,bcm6345-clk" },
+ { /* sentinel */ }
+};
+
+static int bcm63xx_clk_probe(struct udevice *dev)
+{
+ struct bcm6345_clk_priv *priv = dev_get_priv(dev);
+ fdt_addr_t addr;
+ fdt_size_t size;
+
+ addr = dev_get_addr_size_index(dev, 0, &size);
+ if (addr == FDT_ADDR_T_NONE)
+ return -EINVAL;
+
+ priv->regs = ioremap(addr, size);
+
+ return 0;
+}
+
+U_BOOT_DRIVER(clk_bcm6345) = {
+ .name = "clk_bcm6345",
+ .id = UCLASS_CLK,
+ .of_match = bcm6345_clk_ids,
+ .ops = &bcm6345_clk_ops,
+ .probe = bcm63xx_clk_probe,
+ .priv_auto_alloc_size = sizeof(struct bcm6345_clk_priv),
+};
diff --git a/drivers/clk/rockchip/clk_rk3036.c b/drivers/clk/rockchip/clk_rk3036.c
index 7e3bf969440..d866d0bf7a3 100644
--- a/drivers/clk/rockchip/clk_rk3036.c
+++ b/drivers/clk/rockchip/clk_rk3036.c
@@ -228,11 +228,13 @@ static ulong rockchip_mmc_get_clk(struct rk3036_cru *cru, uint clk_general_rate,
switch (periph) {
case HCLK_EMMC:
+ case SCLK_EMMC:
con = readl(&cru->cru_clksel_con[12]);
mux = (con >> EMMC_PLL_SHIFT) & EMMC_PLL_MASK;
div = (con >> EMMC_DIV_SHIFT) & EMMC_DIV_MASK;
break;
case HCLK_SDIO:
+ case SCLK_SDIO:
con = readl(&cru->cru_clksel_con[12]);
mux = (con >> MMC0_PLL_SHIFT) & MMC0_PLL_MASK;
div = (con >> MMC0_DIV_SHIFT) & MMC0_DIV_MASK;
@@ -265,6 +267,7 @@ static ulong rockchip_mmc_set_clk(struct rk3036_cru *cru, uint clk_general_rate,
switch (periph) {
case HCLK_EMMC:
+ case SCLK_EMMC:
rk_clrsetreg(&cru->cru_clksel_con[12],
EMMC_PLL_MASK << EMMC_PLL_SHIFT |
EMMC_DIV_MASK << EMMC_DIV_SHIFT,
@@ -272,6 +275,7 @@ static ulong rockchip_mmc_set_clk(struct rk3036_cru *cru, uint clk_general_rate,
(src_clk_div - 1) << EMMC_DIV_SHIFT);
break;
case HCLK_SDIO:
+ case SCLK_SDIO:
rk_clrsetreg(&cru->cru_clksel_con[11],
MMC0_PLL_MASK << MMC0_PLL_SHIFT |
MMC0_DIV_MASK << MMC0_DIV_SHIFT,
@@ -307,6 +311,7 @@ static ulong rk3036_clk_set_rate(struct clk *clk, ulong rate)
case 0 ... 63:
return 0;
case HCLK_EMMC:
+ case SCLK_EMMC:
new_rate = rockchip_mmc_set_clk(priv->cru, gclk_rate,
clk->id, rate);
break;
diff --git a/drivers/clk/rockchip/clk_rk3188.c b/drivers/clk/rockchip/clk_rk3188.c
index d36cf8f3f27..b32491d3db3 100644
--- a/drivers/clk/rockchip/clk_rk3188.c
+++ b/drivers/clk/rockchip/clk_rk3188.c
@@ -269,14 +269,17 @@ static ulong rockchip_mmc_get_clk(struct rk3188_cru *cru, uint gclk_rate,
switch (periph) {
case HCLK_EMMC:
+ case SCLK_EMMC:
con = readl(&cru->cru_clksel_con[12]);
div = (con >> EMMC_DIV_SHIFT) & EMMC_DIV_MASK;
break;
case HCLK_SDMMC:
+ case SCLK_SDMMC:
con = readl(&cru->cru_clksel_con[11]);
div = (con >> MMC0_DIV_SHIFT) & MMC0_DIV_MASK;
break;
case HCLK_SDIO:
+ case SCLK_SDIO:
con = readl(&cru->cru_clksel_con[12]);
div = (con >> SDIO_DIV_SHIFT) & SDIO_DIV_MASK;
break;
@@ -298,16 +301,19 @@ static ulong rockchip_mmc_set_clk(struct rk3188_cru *cru, uint gclk_rate,
switch (periph) {
case HCLK_EMMC:
+ case SCLK_EMMC:
rk_clrsetreg(&cru->cru_clksel_con[12],
EMMC_DIV_MASK << EMMC_DIV_SHIFT,
src_clk_div << EMMC_DIV_SHIFT);
break;
case HCLK_SDMMC:
+ case SCLK_SDMMC:
rk_clrsetreg(&cru->cru_clksel_con[11],
MMC0_DIV_MASK << MMC0_DIV_SHIFT,
src_clk_div << MMC0_DIV_SHIFT);
break;
case HCLK_SDIO:
+ case SCLK_SDIO:
rk_clrsetreg(&cru->cru_clksel_con[12],
SDIO_DIV_MASK << SDIO_DIV_SHIFT,
src_clk_div << SDIO_DIV_SHIFT);
@@ -466,6 +472,9 @@ static ulong rk3188_clk_get_rate(struct clk *clk)
case HCLK_EMMC:
case HCLK_SDMMC:
case HCLK_SDIO:
+ case SCLK_EMMC:
+ case SCLK_SDMMC:
+ case SCLK_SDIO:
new_rate = rockchip_mmc_get_clk(priv->cru, PERI_HCLK_HZ,
clk->id);
break;
@@ -505,6 +514,9 @@ static ulong rk3188_clk_set_rate(struct clk *clk, ulong rate)
case HCLK_EMMC:
case HCLK_SDMMC:
case HCLK_SDIO:
+ case SCLK_EMMC:
+ case SCLK_SDMMC:
+ case SCLK_SDIO:
new_rate = rockchip_mmc_set_clk(cru, PERI_HCLK_HZ,
clk->id, rate);
break;
diff --git a/drivers/clk/rockchip/clk_rk3288.c b/drivers/clk/rockchip/clk_rk3288.c
index 78356766a78..fc369dde085 100644
--- a/drivers/clk/rockchip/clk_rk3288.c
+++ b/drivers/clk/rockchip/clk_rk3288.c
@@ -513,16 +513,19 @@ static ulong rockchip_mmc_get_clk(struct rk3288_cru *cru, uint gclk_rate,
switch (periph) {
case HCLK_EMMC:
+ case SCLK_EMMC:
con = readl(&cru->cru_clksel_con[12]);
mux = (con >> EMMC_PLL_SHIFT) & EMMC_PLL_MASK;
div = (con >> EMMC_DIV_SHIFT) & EMMC_DIV_MASK;
break;
case HCLK_SDMMC:
+ case SCLK_SDMMC:
con = readl(&cru->cru_clksel_con[11]);
mux = (con >> MMC0_PLL_SHIFT) & MMC0_PLL_MASK;
div = (con >> MMC0_DIV_SHIFT) & MMC0_DIV_MASK;
break;
case HCLK_SDIO0:
+ case SCLK_SDIO0:
con = readl(&cru->cru_clksel_con[12]);
mux = (con >> SDIO0_PLL_SHIFT) & SDIO0_PLL_MASK;
div = (con >> SDIO0_DIV_SHIFT) & SDIO0_DIV_MASK;
@@ -556,6 +559,7 @@ static ulong rockchip_mmc_set_clk(struct rk3288_cru *cru, uint gclk_rate,
}
switch (periph) {
case HCLK_EMMC:
+ case SCLK_EMMC:
rk_clrsetreg(&cru->cru_clksel_con[12],
EMMC_PLL_MASK << EMMC_PLL_SHIFT |
EMMC_DIV_MASK << EMMC_DIV_SHIFT,
@@ -563,6 +567,7 @@ static ulong rockchip_mmc_set_clk(struct rk3288_cru *cru, uint gclk_rate,
(src_clk_div - 1) << EMMC_DIV_SHIFT);
break;
case HCLK_SDMMC:
+ case SCLK_SDMMC:
rk_clrsetreg(&cru->cru_clksel_con[11],
MMC0_PLL_MASK << MMC0_PLL_SHIFT |
MMC0_DIV_MASK << MMC0_DIV_SHIFT,
@@ -570,6 +575,7 @@ static ulong rockchip_mmc_set_clk(struct rk3288_cru *cru, uint gclk_rate,
(src_clk_div - 1) << MMC0_DIV_SHIFT);
break;
case HCLK_SDIO0:
+ case SCLK_SDIO0:
rk_clrsetreg(&cru->cru_clksel_con[12],
SDIO0_PLL_MASK << SDIO0_PLL_SHIFT |
SDIO0_DIV_MASK << SDIO0_DIV_SHIFT,
@@ -662,6 +668,9 @@ static ulong rk3288_clk_get_rate(struct clk *clk)
case HCLK_EMMC:
case HCLK_SDMMC:
case HCLK_SDIO0:
+ case SCLK_EMMC:
+ case SCLK_SDMMC:
+ case SCLK_SDIO0:
new_rate = rockchip_mmc_get_clk(priv->cru, gclk_rate, clk->id);
break;
case SCLK_SPI0:
@@ -706,6 +715,9 @@ static ulong rk3288_clk_set_rate(struct clk *clk, ulong rate)
case HCLK_EMMC:
case HCLK_SDMMC:
case HCLK_SDIO0:
+ case SCLK_EMMC:
+ case SCLK_SDMMC:
+ case SCLK_SDIO0:
new_rate = rockchip_mmc_set_clk(cru, gclk_rate, clk->id, rate);
break;
case SCLK_SPI0:
diff --git a/drivers/clk/rockchip/clk_rk3328.c b/drivers/clk/rockchip/clk_rk3328.c
index 0ff1e30bb59..8ec157416e9 100644
--- a/drivers/clk/rockchip/clk_rk3328.c
+++ b/drivers/clk/rockchip/clk_rk3328.c
@@ -397,9 +397,11 @@ static ulong rk3328_mmc_get_clk(struct rk3328_cru *cru, uint clk_id)
switch (clk_id) {
case HCLK_SDMMC:
+ case SCLK_SDMMC:
con_id = 30;
break;
case HCLK_EMMC:
+ case SCLK_EMMC:
con_id = 32;
break;
default:
@@ -423,9 +425,11 @@ static ulong rk3328_mmc_set_clk(struct rk3328_cru *cru,
switch (clk_id) {
case HCLK_SDMMC:
+ case SCLK_SDMMC:
con_id = 30;
break;
case HCLK_EMMC:
+ case SCLK_EMMC:
con_id = 32;
break;
default:
@@ -483,6 +487,8 @@ static ulong rk3328_clk_get_rate(struct clk *clk)
return 0;
case HCLK_SDMMC:
case HCLK_EMMC:
+ case SCLK_SDMMC:
+ case SCLK_EMMC:
rate = rk3328_mmc_get_clk(priv->cru, clk->id);
break;
case SCLK_I2C0:
@@ -511,6 +517,8 @@ static ulong rk3328_clk_set_rate(struct clk *clk, ulong rate)
return 0;
case HCLK_SDMMC:
case HCLK_EMMC:
+ case SCLK_SDMMC:
+ case SCLK_EMMC:
ret = rk3328_mmc_set_clk(priv->cru, clk->id, rate);
break;
case SCLK_I2C0:
diff --git a/drivers/clk/rockchip/clk_rk3399.c b/drivers/clk/rockchip/clk_rk3399.c
index ff3cc37af33..026ed4dde7b 100644
--- a/drivers/clk/rockchip/clk_rk3399.c
+++ b/drivers/clk/rockchip/clk_rk3399.c
@@ -1,5 +1,6 @@
/*
* (C) Copyright 2015 Google, Inc
+ * (C) 2017 Theobroma Systems Design und Consulting GmbH
*
* SPDX-License-Identifier: GPL-2.0
*/
@@ -207,12 +208,15 @@ enum {
DCLK_VOP_DIV_CON_SHIFT = 0,
/* CLKSEL_CON58 */
- CLK_SPI_PLL_SEL_MASK = 1,
- CLK_SPI_PLL_SEL_CPLL = 0,
- CLK_SPI_PLL_SEL_GPLL = 1,
- CLK_SPI_PLL_DIV_CON_MASK = 0x7f,
- CLK_SPI5_PLL_DIV_CON_SHIFT = 8,
- CLK_SPI5_PLL_SEL_SHIFT = 15,
+ CLK_SPI_PLL_SEL_WIDTH = 1,
+ CLK_SPI_PLL_SEL_MASK = ((1 < CLK_SPI_PLL_SEL_WIDTH) - 1),
+ CLK_SPI_PLL_SEL_CPLL = 0,
+ CLK_SPI_PLL_SEL_GPLL = 1,
+ CLK_SPI_PLL_DIV_CON_WIDTH = 7,
+ CLK_SPI_PLL_DIV_CON_MASK = ((1 << CLK_SPI_PLL_DIV_CON_WIDTH) - 1),
+
+ CLK_SPI5_PLL_DIV_CON_SHIFT = 8,
+ CLK_SPI5_PLL_SEL_SHIFT = 15,
/* CLKSEL_CON59 */
CLK_SPI1_PLL_SEL_SHIFT = 15,
@@ -602,7 +606,96 @@ static ulong rk3399_i2c_set_clk(struct rk3399_cru *cru, ulong clk_id, uint hz)
return -EINVAL;
}
- return DIV_TO_RATE(GPLL_HZ, src_clk_div);
+ return rk3399_i2c_get_clk(cru, clk_id);
+}
+
+/*
+ * RK3399 SPI clocks have a common divider-width (7 bits) and a single bit
+ * to select either CPLL or GPLL as the clock-parent. The location within
+ * the enclosing CLKSEL_CON (i.e. div_shift and sel_shift) are variable.
+ */
+
+struct spi_clkreg {
+ uint8_t reg; /* CLKSEL_CON[reg] register in CRU */
+ uint8_t div_shift;
+ uint8_t sel_shift;
+};
+
+/*
+ * The entries are numbered relative to their offset from SCLK_SPI0.
+ *
+ * Note that SCLK_SPI3 (which is configured via PMUCRU and requires different
+ * logic is not supported).
+ */
+static const struct spi_clkreg spi_clkregs[] = {
+ [0] = { .reg = 59,
+ .div_shift = CLK_SPI0_PLL_DIV_CON_SHIFT,
+ .sel_shift = CLK_SPI0_PLL_SEL_SHIFT, },
+ [1] = { .reg = 59,
+ .div_shift = CLK_SPI1_PLL_DIV_CON_SHIFT,
+ .sel_shift = CLK_SPI1_PLL_SEL_SHIFT, },
+ [2] = { .reg = 60,
+ .div_shift = CLK_SPI2_PLL_DIV_CON_SHIFT,
+ .sel_shift = CLK_SPI2_PLL_SEL_SHIFT, },
+ [3] = { .reg = 60,
+ .div_shift = CLK_SPI4_PLL_DIV_CON_SHIFT,
+ .sel_shift = CLK_SPI4_PLL_SEL_SHIFT, },
+ [4] = { .reg = 58,
+ .div_shift = CLK_SPI5_PLL_DIV_CON_SHIFT,
+ .sel_shift = CLK_SPI5_PLL_SEL_SHIFT, },
+};
+
+static inline u32 extract_bits(u32 val, unsigned width, unsigned shift)
+{
+ return (val >> shift) & ((1 << width) - 1);
+}
+
+static ulong rk3399_spi_get_clk(struct rk3399_cru *cru, ulong clk_id)
+{
+ const struct spi_clkreg *spiclk = NULL;
+ u32 div, val;
+
+ switch (clk_id) {
+ case SCLK_SPI0 ... SCLK_SPI5:
+ spiclk = &spi_clkregs[clk_id - SCLK_SPI0];
+ break;
+
+ default:
+ error("%s: SPI clk-id %ld not supported\n", __func__, clk_id);
+ return -EINVAL;
+ }
+
+ val = readl(&cru->clksel_con[spiclk->reg]);
+ div = extract_bits(val, CLK_SPI_PLL_DIV_CON_WIDTH, spiclk->div_shift);
+
+ return DIV_TO_RATE(GPLL_HZ, div);
+}
+
+static ulong rk3399_spi_set_clk(struct rk3399_cru *cru, ulong clk_id, uint hz)
+{
+ const struct spi_clkreg *spiclk = NULL;
+ int src_clk_div;
+
+ src_clk_div = RATE_TO_DIV(GPLL_HZ, hz);
+ assert(src_clk_div < 127);
+
+ switch (clk_id) {
+ case SCLK_SPI1 ... SCLK_SPI5:
+ spiclk = &spi_clkregs[clk_id - SCLK_SPI0];
+ break;
+
+ default:
+ error("%s: SPI clk-id %ld not supported\n", __func__, clk_id);
+ return -EINVAL;
+ }
+
+ rk_clrsetreg(&cru->clksel_con[spiclk->reg],
+ ((CLK_SPI_PLL_DIV_CON_MASK << spiclk->div_shift) |
+ (CLK_SPI_PLL_SEL_GPLL << spiclk->sel_shift)),
+ ((src_clk_div << spiclk->div_shift) |
+ (CLK_SPI_PLL_SEL_GPLL << spiclk->sel_shift)));
+
+ return rk3399_spi_get_clk(cru, clk_id);
}
static ulong rk3399_vop_set_clk(struct rk3399_cru *cru, ulong clk_id, u32 hz)
@@ -654,6 +747,7 @@ static ulong rk3399_mmc_get_clk(struct rk3399_cru *cru, uint clk_id)
u32 div, con;
switch (clk_id) {
+ case HCLK_SDMMC:
case SCLK_SDMMC:
con = readl(&cru->clksel_con[16]);
break;
@@ -679,6 +773,7 @@ static ulong rk3399_mmc_set_clk(struct rk3399_cru *cru,
int aclk_emmc = 198*MHz;
switch (clk_id) {
+ case HCLK_SDMMC:
case SCLK_SDMMC:
/* Select clk_sdmmc source from GPLL by default */
src_clk_div = GPLL_HZ / set_rate;
@@ -768,6 +863,7 @@ static ulong rk3399_clk_get_rate(struct clk *clk)
switch (clk->id) {
case 0 ... 63:
return 0;
+ case HCLK_SDMMC:
case SCLK_SDMMC:
case SCLK_EMMC:
rate = rk3399_mmc_get_clk(priv->cru, clk->id);
@@ -780,9 +876,20 @@ static ulong rk3399_clk_get_rate(struct clk *clk)
case SCLK_I2C7:
rate = rk3399_i2c_get_clk(priv->cru, clk->id);
break;
+ case SCLK_SPI0...SCLK_SPI5:
+ rate = rk3399_spi_get_clk(priv->cru, clk->id);
+ break;
+ case SCLK_UART0:
+ case SCLK_UART2:
+ return 24000000;
+ break;
+ case PCLK_HDMI_CTRL:
+ break;
case DCLK_VOP0:
case DCLK_VOP1:
break;
+ case PCLK_EFUSE1024NS:
+ break;
default:
return -ENOENT;
}
@@ -798,6 +905,7 @@ static ulong rk3399_clk_set_rate(struct clk *clk, ulong rate)
switch (clk->id) {
case 0 ... 63:
return 0;
+ case HCLK_SDMMC:
case SCLK_SDMMC:
case SCLK_EMMC:
ret = rk3399_mmc_set_clk(priv->cru, clk->id, rate);
@@ -814,6 +922,13 @@ static ulong rk3399_clk_set_rate(struct clk *clk, ulong rate)
case SCLK_I2C7:
ret = rk3399_i2c_set_clk(priv->cru, clk->id, rate);
break;
+ case SCLK_SPI0...SCLK_SPI5:
+ ret = rk3399_spi_set_clk(priv->cru, clk->id, rate);
+ break;
+ case PCLK_HDMI_CTRL:
+ case PCLK_VIO_GRF:
+ /* the PCLK gates for video are enabled by default */
+ break;
case DCLK_VOP0:
case DCLK_VOP1:
ret = rk3399_vop_set_clk(priv->cru, clk->id, rate);
@@ -821,6 +936,8 @@ static ulong rk3399_clk_set_rate(struct clk *clk, ulong rate)
case SCLK_DDRCLK:
ret = rk3399_ddr_set_clk(priv->cru, rate);
break;
+ case PCLK_EFUSE1024NS:
+ break;
default:
return -ENOENT;
}
diff --git a/drivers/core/device-remove.c b/drivers/core/device-remove.c
index cc0043b990b..3c6ab42f7d6 100644
--- a/drivers/core/device-remove.c
+++ b/drivers/core/device-remove.c
@@ -152,6 +152,15 @@ void device_free(struct udevice *dev)
devres_release_probe(dev);
}
+static bool flags_remove(uint flags, uint drv_flags)
+{
+ if ((flags & DM_REMOVE_NORMAL) ||
+ (flags & (drv_flags & (DM_FLAG_ACTIVE_DMA | DM_FLAG_OS_PREPARE))))
+ return true;
+
+ return false;
+}
+
int device_remove(struct udevice *dev, uint flags)
{
const struct driver *drv;
@@ -178,9 +187,7 @@ int device_remove(struct udevice *dev, uint flags)
* Remove the device if called with the "normal" remove flag set,
* or if the remove flag matches any of the drivers remove flags
*/
- if (drv->remove &&
- ((flags & DM_REMOVE_NORMAL) ||
- (flags & (drv->flags & DM_FLAG_ACTIVE_DMA)))) {
+ if (drv->remove && flags_remove(flags, drv->flags)) {
ret = drv->remove(dev);
if (ret)
goto err_remove;
@@ -194,8 +201,7 @@ int device_remove(struct udevice *dev, uint flags)
}
}
- if ((flags & DM_REMOVE_NORMAL) ||
- (flags & (drv->flags & DM_FLAG_ACTIVE_DMA))) {
+ if (flags_remove(flags, drv->flags)) {
device_free(dev);
dev->seq = -1;
diff --git a/drivers/cpu/Makefile b/drivers/cpu/Makefile
index 871016030f8..db515f6f177 100644
--- a/drivers/cpu/Makefile
+++ b/drivers/cpu/Makefile
@@ -5,3 +5,5 @@
# SPDX-License-Identifier: GPL-2.0+
#
obj-$(CONFIG_CPU) += cpu-uclass.o
+
+obj-$(CONFIG_ARCH_BMIPS) += bmips_cpu.o
diff --git a/drivers/cpu/bmips_cpu.c b/drivers/cpu/bmips_cpu.c
new file mode 100644
index 00000000000..379acf2d556
--- /dev/null
+++ b/drivers/cpu/bmips_cpu.c
@@ -0,0 +1,310 @@
+/*
+ * Copyright (C) 2017 Álvaro Fernández Rojas <noltari@gmail.com>
+ *
+ * Derived from linux/arch/mips/bcm63xx/cpu.c:
+ * Copyright (C) 2008 Maxime Bizon <mbizon@freebox.fr>
+ * Copyright (C) 2009 Florian Fainelli <florian@openwrt.org>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <cpu.h>
+#include <dm.h>
+#include <errno.h>
+#include <asm/io.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#define REV_CHIPID_SHIFT 16
+#define REV_CHIPID_MASK (0xffff << REV_CHIPID_SHIFT)
+#define REV_LONG_CHIPID_SHIFT 12
+#define REV_LONG_CHIPID_MASK (0xfffff << REV_LONG_CHIPID_SHIFT)
+#define REV_REVID_SHIFT 0
+#define REV_REVID_MASK (0xff << REV_REVID_SHIFT)
+
+#define REG_BCM6328_OTP 0x62c
+#define BCM6328_TP1_DISABLED BIT(9)
+
+#define REG_BCM6328_MISC_STRAPBUS 0x1a40
+#define STRAPBUS_6328_FCVO_SHIFT 7
+#define STRAPBUS_6328_FCVO_MASK (0x1f << STRAPBUS_6328_FCVO_SHIFT)
+
+#define REG_BCM6358_DDR_DMIPSPLLCFG 0x12b8
+#define DMIPSPLLCFG_6358_M1_SHIFT 0
+#define DMIPSPLLCFG_6358_M1_MASK (0xff << DMIPSPLLCFG_6358_M1_SHIFT)
+#define DMIPSPLLCFG_6358_N1_SHIFT 23
+#define DMIPSPLLCFG_6358_N1_MASK (0x3f << DMIPSPLLCFG_6358_N1_SHIFT)
+#define DMIPSPLLCFG_6358_N2_SHIFT 29
+#define DMIPSPLLCFG_6358_N2_MASK (0x7 << DMIPSPLLCFG_6358_N2_SHIFT)
+
+#define REG_BCM63268_MISC_STRAPBUS 0x1814
+#define STRAPBUS_63268_FCVO_SHIFT 21
+#define STRAPBUS_63268_FCVO_MASK (0xf << STRAPBUS_63268_FCVO_SHIFT)
+
+struct bmips_cpu_priv;
+
+struct bmips_cpu_hw {
+ int (*get_cpu_desc)(struct bmips_cpu_priv *priv, char *buf, int size);
+ ulong (*get_cpu_freq)(struct bmips_cpu_priv *);
+ int (*get_cpu_count)(struct bmips_cpu_priv *);
+};
+
+struct bmips_cpu_priv {
+ void __iomem *regs;
+ const struct bmips_cpu_hw *hw;
+};
+
+/* Specific CPU Ops */
+static int bcm6358_get_cpu_desc(struct bmips_cpu_priv *priv, char *buf,
+ int size)
+{
+ unsigned short cpu_id;
+ unsigned char cpu_rev;
+ u32 val;
+
+ val = readl_be(priv->regs);
+ cpu_id = (val & REV_CHIPID_MASK) >> REV_CHIPID_SHIFT;
+ cpu_rev = (val & REV_REVID_MASK) >> REV_REVID_SHIFT;
+
+ snprintf(buf, size, "BCM%04X%02X", cpu_id, cpu_rev);
+
+ return 0;
+}
+
+static int bcm6328_get_cpu_desc(struct bmips_cpu_priv *priv, char *buf,
+ int size)
+{
+ unsigned int cpu_id;
+ unsigned char cpu_rev;
+ u32 val;
+
+ val = readl_be(priv->regs);
+ cpu_id = (val & REV_LONG_CHIPID_MASK) >> REV_LONG_CHIPID_SHIFT;
+ cpu_rev = (val & REV_REVID_MASK) >> REV_REVID_SHIFT;
+
+ snprintf(buf, size, "BCM%05X%02X", cpu_id, cpu_rev);
+
+ return 0;
+}
+
+static ulong bcm6328_get_cpu_freq(struct bmips_cpu_priv *priv)
+{
+ unsigned int mips_pll_fcvo;
+
+ mips_pll_fcvo = readl_be(priv->regs + REG_BCM6328_MISC_STRAPBUS);
+ mips_pll_fcvo = (mips_pll_fcvo & STRAPBUS_6328_FCVO_MASK)
+ >> STRAPBUS_6328_FCVO_SHIFT;
+
+ switch (mips_pll_fcvo) {
+ case 0x12:
+ case 0x14:
+ case 0x19:
+ return 160000000;
+ case 0x1c:
+ return 192000000;
+ case 0x13:
+ case 0x15:
+ return 200000000;
+ case 0x1a:
+ return 384000000;
+ case 0x16:
+ return 400000000;
+ default:
+ return 320000000;
+ }
+}
+
+static ulong bcm6358_get_cpu_freq(struct bmips_cpu_priv *priv)
+{
+ unsigned int tmp, n1, n2, m1;
+
+ tmp = readl_be(priv->regs + REG_BCM6358_DDR_DMIPSPLLCFG);
+ n1 = (tmp & DMIPSPLLCFG_6358_N1_MASK) >> DMIPSPLLCFG_6358_N1_SHIFT;
+ n2 = (tmp & DMIPSPLLCFG_6358_N2_MASK) >> DMIPSPLLCFG_6358_N2_SHIFT;
+ m1 = (tmp & DMIPSPLLCFG_6358_M1_MASK) >> DMIPSPLLCFG_6358_M1_SHIFT;
+
+ return (16 * 1000000 * n1 * n2) / m1;
+}
+
+static ulong bcm63268_get_cpu_freq(struct bmips_cpu_priv *priv)
+{
+ unsigned int mips_pll_fcvo;
+
+ mips_pll_fcvo = readl_be(priv->regs + REG_BCM63268_MISC_STRAPBUS);
+ mips_pll_fcvo = (mips_pll_fcvo & STRAPBUS_63268_FCVO_MASK)
+ >> STRAPBUS_63268_FCVO_SHIFT;
+
+ switch (mips_pll_fcvo) {
+ case 0x3:
+ case 0xe:
+ return 320000000;
+ case 0xa:
+ return 333000000;
+ case 0x2:
+ case 0xb:
+ case 0xf:
+ return 400000000;
+ default:
+ return 0;
+ }
+}
+
+static int bcm6328_get_cpu_count(struct bmips_cpu_priv *priv)
+{
+ u32 val = readl_be(priv->regs + REG_BCM6328_OTP);
+
+ if (val & BCM6328_TP1_DISABLED)
+ return 1;
+ else
+ return 2;
+}
+
+static int bcm6358_get_cpu_count(struct bmips_cpu_priv *priv)
+{
+ return 2;
+}
+
+static const struct bmips_cpu_hw bmips_cpu_bcm6328 = {
+ .get_cpu_desc = bcm6328_get_cpu_desc,
+ .get_cpu_freq = bcm6328_get_cpu_freq,
+ .get_cpu_count = bcm6328_get_cpu_count,
+};
+
+static const struct bmips_cpu_hw bmips_cpu_bcm6358 = {
+ .get_cpu_desc = bcm6358_get_cpu_desc,
+ .get_cpu_freq = bcm6358_get_cpu_freq,
+ .get_cpu_count = bcm6358_get_cpu_count,
+};
+
+static const struct bmips_cpu_hw bmips_cpu_bcm63268 = {
+ .get_cpu_desc = bcm6328_get_cpu_desc,
+ .get_cpu_freq = bcm63268_get_cpu_freq,
+ .get_cpu_count = bcm6358_get_cpu_count,
+};
+
+/* Generic CPU Ops */
+static int bmips_cpu_get_desc(struct udevice *dev, char *buf, int size)
+{
+ struct bmips_cpu_priv *priv = dev_get_priv(dev);
+ const struct bmips_cpu_hw *hw = priv->hw;
+
+ return hw->get_cpu_desc(priv, buf, size);
+}
+
+static int bmips_cpu_get_info(struct udevice *dev, struct cpu_info *info)
+{
+ struct bmips_cpu_priv *priv = dev_get_priv(dev);
+ const struct bmips_cpu_hw *hw = priv->hw;
+
+ info->cpu_freq = hw->get_cpu_freq(priv);
+ info->features = BIT(CPU_FEAT_L1_CACHE);
+ info->features |= BIT(CPU_FEAT_MMU);
+ info->features |= BIT(CPU_FEAT_DEVICE_ID);
+
+ return 0;
+}
+
+static int bmips_cpu_get_count(struct udevice *dev)
+{
+ struct bmips_cpu_priv *priv = dev_get_priv(dev);
+ const struct bmips_cpu_hw *hw = priv->hw;
+
+ return hw->get_cpu_count(priv);
+}
+
+static int bmips_cpu_get_vendor(struct udevice *dev, char *buf, int size)
+{
+ snprintf(buf, size, "Broadcom");
+
+ return 0;
+}
+
+static const struct cpu_ops bmips_cpu_ops = {
+ .get_desc = bmips_cpu_get_desc,
+ .get_info = bmips_cpu_get_info,
+ .get_count = bmips_cpu_get_count,
+ .get_vendor = bmips_cpu_get_vendor,
+};
+
+/* BMIPS CPU driver */
+int bmips_cpu_bind(struct udevice *dev)
+{
+ struct cpu_platdata *plat = dev_get_parent_platdata(dev);
+
+ plat->cpu_id = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev),
+ "reg", -1);
+ plat->device_id = read_c0_prid();
+
+ return 0;
+}
+
+int bmips_cpu_probe(struct udevice *dev)
+{
+ struct bmips_cpu_priv *priv = dev_get_priv(dev);
+ const struct bmips_cpu_hw *hw =
+ (const struct bmips_cpu_hw *)dev_get_driver_data(dev);
+ fdt_addr_t addr;
+ fdt_size_t size;
+
+ addr = dev_get_addr_size_index(dev_get_parent(dev), 0, &size);
+ if (addr == FDT_ADDR_T_NONE)
+ return -EINVAL;
+
+ priv->regs = ioremap(addr, size);
+ priv->hw = hw;
+
+ return 0;
+}
+
+static const struct udevice_id bmips_cpu_ids[] = {
+ {
+ .compatible = "brcm,bcm6328-cpu",
+ .data = (ulong)&bmips_cpu_bcm6328,
+ }, {
+ .compatible = "brcm,bcm6358-cpu",
+ .data = (ulong)&bmips_cpu_bcm6358,
+ }, {
+ .compatible = "brcm,bcm63268-cpu",
+ .data = (ulong)&bmips_cpu_bcm63268,
+ },
+ { /* sentinel */ }
+};
+
+U_BOOT_DRIVER(bmips_cpu_drv) = {
+ .name = "bmips_cpu",
+ .id = UCLASS_CPU,
+ .of_match = bmips_cpu_ids,
+ .bind = bmips_cpu_bind,
+ .probe = bmips_cpu_probe,
+ .priv_auto_alloc_size = sizeof(struct bmips_cpu_priv),
+ .ops = &bmips_cpu_ops,
+ .flags = DM_FLAG_PRE_RELOC,
+};
+
+#ifdef CONFIG_DISPLAY_CPUINFO
+int print_cpuinfo(void)
+{
+ struct cpu_info cpu;
+ struct udevice *dev;
+ int err;
+ char desc[100];
+
+ err = uclass_get_device(UCLASS_CPU, 0, &dev);
+ if (err)
+ return 0;
+
+ err = cpu_get_info(dev, &cpu);
+ if (err)
+ return 0;
+
+ err = cpu_get_desc(dev, desc, sizeof(desc));
+ if (err)
+ return 0;
+
+ printf("Chip ID: %s, MIPS: ", desc);
+ print_freq(cpu.cpu_freq, "\n");
+
+ return 0;
+}
+#endif
diff --git a/drivers/dfu/dfu.c b/drivers/dfu/dfu.c
index 8dacc1a6d16..ceb33e35eed 100644
--- a/drivers/dfu/dfu.c
+++ b/drivers/dfu/dfu.c
@@ -35,7 +35,11 @@ static struct hash_algo *dfu_hash_algo;
*/
__weak bool dfu_usb_get_reset(void)
{
+#ifdef CONFIG_SPL_DFU_NO_RESET
+ return false;
+#else
return true;
+#endif
}
static int dfu_find_alt_num(const char *s)
diff --git a/drivers/gpio/74x164_gpio.c b/drivers/gpio/74x164_gpio.c
index 750eedfffd0..53a639ae65b 100644
--- a/drivers/gpio/74x164_gpio.c
+++ b/drivers/gpio/74x164_gpio.c
@@ -156,8 +156,7 @@ static int gen_74x164_probe(struct udevice *dev)
ret = gpio_request_by_name(dev, "oe-gpios", 0, &priv->oe,
GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE);
if (ret) {
- dev_err(dev, "No oe-pins property\n");
- goto free_buf;
+ dev_dbg(dev, "No oe-pins property\n");
}
uc_priv->bank_name = str;
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index 99516119ff1..15135e538dc 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -21,6 +21,12 @@ config ALTERA_PIO
Select this to enable PIO for Altera devices. Please find
details on the "Embedded Peripherals IP User Guide" of Altera.
+config BCM6345_GPIO
+ bool "BCM6345 GPIO driver"
+ depends on DM_GPIO && ARCH_BMIPS
+ help
+ This driver supports the GPIO banks on BCM6345 SoCs.
+
config DWAPB_GPIO
bool "DWAPB GPIO driver"
depends on DM && DM_GPIO
@@ -89,6 +95,14 @@ config MSM_GPIO
- APQ8016
- MSM8916
+config OMAP_GPIO
+ bool "TI OMAP GPIO driver"
+ depends on ARCH_OMAP2PLUS
+ default y
+ help
+ Support GPIO controllers on the TI OMAP3/4/5 and related (such as
+ AM335x/AM43xx/AM57xx/DRA7xx/etc) families of SoCs.
+
config PM8916_GPIO
bool "Qualcomm PM8916 PMIC GPIO/keypad driver"
depends on DM_GPIO && PMIC_PM8916
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index 0ca845f54ca..03df558879b 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -16,6 +16,7 @@ obj-$(CONFIG_DM_74X164) += 74x164_gpio.o
obj-$(CONFIG_AT91_GPIO) += at91_gpio.o
obj-$(CONFIG_ATMEL_PIO4) += atmel_pio4.o
+obj-$(CONFIG_BCM6345_GPIO) += bcm6345_gpio.o
obj-$(CONFIG_INTEL_ICH6_GPIO) += intel_ich6_gpio.o
obj-$(CONFIG_INTEL_BROADWELL_GPIO) += intel_broadwell_gpio.o
obj-$(CONFIG_KIRKWOOD_GPIO) += kw_gpio.o
diff --git a/drivers/gpio/bcm6345_gpio.c b/drivers/gpio/bcm6345_gpio.c
new file mode 100644
index 00000000000..1c46020aa4d
--- /dev/null
+++ b/drivers/gpio/bcm6345_gpio.c
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2017 Álvaro Fernández Rojas <noltari@gmail.com>
+ *
+ * Derived from linux/arch/mips/bcm63xx/gpio.c:
+ * Copyright (C) 2008 Maxime Bizon <mbizon@freebox.fr>
+ * Copyright (C) 2008-2011 Florian Fainelli <florian@openwrt.org>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <errno.h>
+#include <asm/gpio.h>
+#include <asm/io.h>
+#include <dm/device.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+struct bcm6345_gpio_priv {
+ void __iomem *reg_dirout;
+ void __iomem *reg_data;
+};
+
+static int bcm6345_gpio_get_value(struct udevice *dev, unsigned offset)
+{
+ struct bcm6345_gpio_priv *priv = dev_get_priv(dev);
+
+ return !!(readl_be(priv->reg_data) & BIT(offset));
+}
+
+static int bcm6345_gpio_set_value(struct udevice *dev, unsigned offset,
+ int value)
+{
+ struct bcm6345_gpio_priv *priv = dev_get_priv(dev);
+
+ if (value)
+ setbits_be32(priv->reg_data, BIT(offset));
+ else
+ clrbits_be32(priv->reg_data, BIT(offset));
+
+ return 0;
+}
+
+static int bcm6345_gpio_set_direction(void __iomem *dirout, unsigned offset,
+ bool input)
+{
+ if (input)
+ clrbits_be32(dirout, BIT(offset));
+ else
+ setbits_be32(dirout, BIT(offset));
+
+ return 0;
+}
+
+static int bcm6345_gpio_direction_input(struct udevice *dev, unsigned offset)
+{
+ struct bcm6345_gpio_priv *priv = dev_get_priv(dev);
+
+ return bcm6345_gpio_set_direction(priv->reg_dirout, offset, 1);
+}
+
+static int bcm6345_gpio_direction_output(struct udevice *dev, unsigned offset,
+ int value)
+{
+ struct bcm6345_gpio_priv *priv = dev_get_priv(dev);
+
+ return bcm6345_gpio_set_direction(priv->reg_dirout, offset, 0);
+}
+
+static int bcm6345_gpio_get_function(struct udevice *dev, unsigned offset)
+{
+ struct bcm6345_gpio_priv *priv = dev_get_priv(dev);
+
+ if (readl_be(priv->reg_dirout) & BIT(offset))
+ return GPIOF_OUTPUT;
+ else
+ return GPIOF_INPUT;
+}
+
+static const struct dm_gpio_ops bcm6345_gpio_ops = {
+ .direction_input = bcm6345_gpio_direction_input,
+ .direction_output = bcm6345_gpio_direction_output,
+ .get_value = bcm6345_gpio_get_value,
+ .set_value = bcm6345_gpio_set_value,
+ .get_function = bcm6345_gpio_get_function,
+};
+
+static int bcm6345_gpio_probe(struct udevice *dev)
+{
+ struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+ struct bcm6345_gpio_priv *priv = dev_get_priv(dev);
+ fdt_addr_t data_addr, dirout_addr;
+ fdt_size_t data_size, dirout_size;
+
+ dirout_addr = dev_get_addr_size_index(dev, 0, &dirout_size);
+ if (dirout_addr == FDT_ADDR_T_NONE)
+ return -EINVAL;
+
+ data_addr = dev_get_addr_size_index(dev, 1, &data_size);
+ if (data_addr == FDT_ADDR_T_NONE)
+ return -EINVAL;
+
+ priv->reg_data = ioremap(data_addr, data_size);
+ priv->reg_dirout = ioremap(dirout_addr, dirout_size);
+
+ uc_priv->gpio_count = fdtdec_get_uint(gd->fdt_blob, dev_of_offset(dev),
+ "ngpios", 32);
+ uc_priv->bank_name = dev->name;
+
+ return 0;
+}
+
+static const struct udevice_id bcm6345_gpio_ids[] = {
+ { .compatible = "brcm,bcm6345-gpio" },
+ { /* sentinel */ }
+};
+
+U_BOOT_DRIVER(bcm6345_gpio) = {
+ .name = "bcm6345-gpio",
+ .id = UCLASS_GPIO,
+ .of_match = bcm6345_gpio_ids,
+ .ops = &bcm6345_gpio_ops,
+ .priv_auto_alloc_size = sizeof(struct bcm6345_gpio_priv),
+ .probe = bcm6345_gpio_probe,
+};
diff --git a/drivers/gpio/gpio-uclass.c b/drivers/gpio/gpio-uclass.c
index 9ab9df4ce7a..ba4804083da 100644
--- a/drivers/gpio/gpio-uclass.c
+++ b/drivers/gpio/gpio-uclass.c
@@ -68,7 +68,7 @@ int dm_gpio_lookup_name(const char *name, struct gpio_desc *desc)
if (numeric != -1) {
offset = numeric - uc_priv->gpio_base;
/* Allow GPIOs to be numbered from 0 */
- if (offset >= 0 && offset < uc_priv->gpio_count)
+ if (offset < uc_priv->gpio_count)
break;
}
diff --git a/drivers/gpio/intel_ich6_gpio.c b/drivers/gpio/intel_ich6_gpio.c
index 8b782260bc3..0a9eb03fd05 100644
--- a/drivers/gpio/intel_ich6_gpio.c
+++ b/drivers/gpio/intel_ich6_gpio.c
@@ -46,22 +46,31 @@ struct ich6_bank_priv {
uint16_t use_sel;
uint16_t io_sel;
uint16_t lvl;
+ u32 lvl_write_cache;
+ bool use_lvl_write_cache;
};
#define GPIO_USESEL_OFFSET(x) (x)
#define GPIO_IOSEL_OFFSET(x) (x + 4)
#define GPIO_LVL_OFFSET(x) (x + 8)
-static int _ich6_gpio_set_value(uint16_t base, unsigned offset, int value)
+static int _ich6_gpio_set_value(struct ich6_bank_priv *bank, unsigned offset,
+ int value)
{
u32 val;
- val = inl(base);
+ if (bank->use_lvl_write_cache)
+ val = bank->lvl_write_cache;
+ else
+ val = inl(bank->lvl);
+
if (value)
val |= (1UL << offset);
else
val &= ~(1UL << offset);
- outl(val, base);
+ outl(val, bank->lvl);
+ if (bank->use_lvl_write_cache)
+ bank->lvl_write_cache = val;
return 0;
}
@@ -112,6 +121,7 @@ static int ich6_gpio_probe(struct udevice *dev)
struct ich6_bank_platdata *plat = dev_get_platdata(dev);
struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
struct ich6_bank_priv *bank = dev_get_priv(dev);
+ const void *prop;
uc_priv->gpio_count = GPIO_PER_BANK;
uc_priv->bank_name = plat->bank_name;
@@ -119,6 +129,14 @@ static int ich6_gpio_probe(struct udevice *dev)
bank->io_sel = plat->base_addr + 4;
bank->lvl = plat->base_addr + 8;
+ prop = fdt_getprop(gd->fdt_blob, dev->of_offset,
+ "use-lvl-write-cache", NULL);
+ if (prop)
+ bank->use_lvl_write_cache = true;
+ else
+ bank->use_lvl_write_cache = false;
+ bank->lvl_write_cache = 0;
+
return 0;
}
@@ -160,7 +178,7 @@ static int ich6_gpio_direction_output(struct udevice *dev, unsigned offset,
if (ret)
return ret;
- return _ich6_gpio_set_value(bank->lvl, offset, value);
+ return _ich6_gpio_set_value(bank, offset, value);
}
static int ich6_gpio_get_value(struct udevice *dev, unsigned offset)
@@ -170,6 +188,8 @@ static int ich6_gpio_get_value(struct udevice *dev, unsigned offset)
int r;
tmplong = inl(bank->lvl);
+ if (bank->use_lvl_write_cache)
+ tmplong |= bank->lvl_write_cache;
r = (tmplong & (1UL << offset)) ? 1 : 0;
return r;
}
@@ -178,7 +198,7 @@ static int ich6_gpio_set_value(struct udevice *dev, unsigned offset,
int value)
{
struct ich6_bank_priv *bank = dev_get_priv(dev);
- return _ich6_gpio_set_value(bank->lvl, offset, value);
+ return _ich6_gpio_set_value(bank, offset, value);
}
static int ich6_gpio_get_function(struct udevice *dev, unsigned offset)
diff --git a/drivers/i2c/davinci_i2c.c b/drivers/i2c/davinci_i2c.c
index c5bd38c67b8..4471193402e 100644
--- a/drivers/i2c/davinci_i2c.c
+++ b/drivers/i2c/davinci_i2c.c
@@ -14,11 +14,21 @@
#include <common.h>
#include <i2c.h>
+#include <dm.h>
#include <asm/arch/hardware.h>
#include <asm/arch/i2c_defs.h>
#include <asm/io.h>
#include "davinci_i2c.h"
+#ifdef CONFIG_DM_I2C
+/* Information about i2c controller */
+struct i2c_bus {
+ int id;
+ uint speed;
+ struct i2c_regs *regs;
+};
+#endif
+
#define CHECK_NACK() \
do {\
if (tmp & (I2C_TIMEOUT | I2C_STAT_NACK)) {\
@@ -27,11 +37,8 @@
} \
} while (0)
-static struct i2c_regs *davinci_get_base(struct i2c_adapter *adap);
-
-static int wait_for_bus(struct i2c_adapter *adap)
+static int _wait_for_bus(struct i2c_regs *i2c_base)
{
- struct i2c_regs *i2c_base = davinci_get_base(adap);
int stat, timeout;
REG(&(i2c_base->i2c_stat)) = 0xffff;
@@ -51,10 +58,8 @@ static int wait_for_bus(struct i2c_adapter *adap)
return 1;
}
-
-static int poll_i2c_irq(struct i2c_adapter *adap, int mask)
+static int _poll_i2c_irq(struct i2c_regs *i2c_base, int mask)
{
- struct i2c_regs *i2c_base = davinci_get_base(adap);
int stat, timeout;
for (timeout = 0; timeout < 10; timeout++) {
@@ -68,10 +73,8 @@ static int poll_i2c_irq(struct i2c_adapter *adap, int mask)
return stat | I2C_TIMEOUT;
}
-static void flush_rx(struct i2c_adapter *adap)
+static void _flush_rx(struct i2c_regs *i2c_base)
{
- struct i2c_regs *i2c_base = davinci_get_base(adap);
-
while (1) {
if (!(REG(&(i2c_base->i2c_stat)) & I2C_STAT_RRDY))
break;
@@ -82,9 +85,9 @@ static void flush_rx(struct i2c_adapter *adap)
}
}
-static uint davinci_i2c_setspeed(struct i2c_adapter *adap, uint speed)
+static uint _davinci_i2c_setspeed(struct i2c_regs *i2c_base,
+ uint speed)
{
- struct i2c_regs *i2c_base = davinci_get_base(adap);
uint32_t div, psc;
psc = 2;
@@ -94,20 +97,18 @@ static uint davinci_i2c_setspeed(struct i2c_adapter *adap, uint speed)
REG(&(i2c_base->i2c_scll)) = (div * 50) / 100; /* 50% Duty */
REG(&(i2c_base->i2c_sclh)) = div - REG(&(i2c_base->i2c_scll));
- adap->speed = speed;
return 0;
}
-static void davinci_i2c_init(struct i2c_adapter *adap, int speed, int slaveadd)
+static void _davinci_i2c_init(struct i2c_regs *i2c_base,
+ uint speed, int slaveadd)
{
- struct i2c_regs *i2c_base = davinci_get_base(adap);
-
if (REG(&(i2c_base->i2c_con)) & I2C_CON_EN) {
REG(&(i2c_base->i2c_con)) = 0;
udelay(50000);
}
- davinci_i2c_setspeed(adap, speed);
+ _davinci_i2c_setspeed(i2c_base, speed);
REG(&(i2c_base->i2c_oa)) = slaveadd;
REG(&(i2c_base->i2c_cnt)) = 0;
@@ -122,47 +123,9 @@ static void davinci_i2c_init(struct i2c_adapter *adap, int speed, int slaveadd)
udelay(1000);
}
-static int davinci_i2c_probe(struct i2c_adapter *adap, uint8_t chip)
+static int _davinci_i2c_read(struct i2c_regs *i2c_base, uint8_t chip,
+ uint32_t addr, int alen, uint8_t *buf, int len)
{
- struct i2c_regs *i2c_base = davinci_get_base(adap);
- int rc = 1;
-
- if (chip == REG(&(i2c_base->i2c_oa)))
- return rc;
-
- REG(&(i2c_base->i2c_con)) = 0;
- if (wait_for_bus(adap))
- return 1;
-
- /* try to read one byte from current (or only) address */
- REG(&(i2c_base->i2c_cnt)) = 1;
- REG(&(i2c_base->i2c_sa)) = chip;
- REG(&(i2c_base->i2c_con)) = (I2C_CON_EN | I2C_CON_MST | I2C_CON_STT |
- I2C_CON_STP);
- udelay(50000);
-
- if (!(REG(&(i2c_base->i2c_stat)) & I2C_STAT_NACK)) {
- rc = 0;
- flush_rx(adap);
- REG(&(i2c_base->i2c_stat)) = 0xffff;
- } else {
- REG(&(i2c_base->i2c_stat)) = 0xffff;
- REG(&(i2c_base->i2c_con)) |= I2C_CON_STP;
- udelay(20000);
- if (wait_for_bus(adap))
- return 1;
- }
-
- flush_rx(adap);
- REG(&(i2c_base->i2c_stat)) = 0xffff;
- REG(&(i2c_base->i2c_cnt)) = 0;
- return rc;
-}
-
-static int davinci_i2c_read(struct i2c_adapter *adap, uint8_t chip,
- uint32_t addr, int alen, uint8_t *buf, int len)
-{
- struct i2c_regs *i2c_base = davinci_get_base(adap);
uint32_t tmp;
int i;
@@ -171,7 +134,7 @@ static int davinci_i2c_read(struct i2c_adapter *adap, uint8_t chip,
return 1;
}
- if (wait_for_bus(adap))
+ if (_wait_for_bus(i2c_base))
return 1;
if (alen != 0) {
@@ -181,7 +144,7 @@ static int davinci_i2c_read(struct i2c_adapter *adap, uint8_t chip,
REG(&(i2c_base->i2c_sa)) = chip;
REG(&(i2c_base->i2c_con)) = tmp;
- tmp = poll_i2c_irq(adap, I2C_STAT_XRDY | I2C_STAT_NACK);
+ tmp = _poll_i2c_irq(i2c_base, I2C_STAT_XRDY | I2C_STAT_NACK);
CHECK_NACK();
@@ -195,7 +158,8 @@ static int davinci_i2c_read(struct i2c_adapter *adap, uint8_t chip,
return 1;
}
- tmp = poll_i2c_irq(adap, I2C_STAT_XRDY | I2C_STAT_NACK);
+ tmp = _poll_i2c_irq(i2c_base,
+ I2C_STAT_XRDY | I2C_STAT_NACK);
CHECK_NACK();
/* No break, fall through */
@@ -208,8 +172,8 @@ static int davinci_i2c_read(struct i2c_adapter *adap, uint8_t chip,
return 1;
}
- tmp = poll_i2c_irq(adap, I2C_STAT_XRDY |
- I2C_STAT_NACK | I2C_STAT_ARDY);
+ tmp = _poll_i2c_irq(i2c_base, I2C_STAT_XRDY |
+ I2C_STAT_NACK | I2C_STAT_ARDY);
CHECK_NACK();
@@ -227,7 +191,7 @@ static int davinci_i2c_read(struct i2c_adapter *adap, uint8_t chip,
REG(&(i2c_base->i2c_con)) = tmp;
for (i = 0; i < len; i++) {
- tmp = poll_i2c_irq(adap, I2C_STAT_RRDY | I2C_STAT_NACK |
+ tmp = _poll_i2c_irq(i2c_base, I2C_STAT_RRDY | I2C_STAT_NACK |
I2C_STAT_ROVR);
CHECK_NACK();
@@ -240,7 +204,7 @@ static int davinci_i2c_read(struct i2c_adapter *adap, uint8_t chip,
}
}
- tmp = poll_i2c_irq(adap, I2C_STAT_SCD | I2C_STAT_NACK);
+ tmp = _poll_i2c_irq(i2c_base, I2C_STAT_SCD | I2C_STAT_NACK);
CHECK_NACK();
@@ -249,7 +213,7 @@ static int davinci_i2c_read(struct i2c_adapter *adap, uint8_t chip,
return 1;
}
- flush_rx(adap);
+ _flush_rx(i2c_base);
REG(&(i2c_base->i2c_stat)) = 0xffff;
REG(&(i2c_base->i2c_cnt)) = 0;
REG(&(i2c_base->i2c_con)) = 0;
@@ -257,10 +221,9 @@ static int davinci_i2c_read(struct i2c_adapter *adap, uint8_t chip,
return 0;
}
-static int davinci_i2c_write(struct i2c_adapter *adap, uint8_t chip,
- uint32_t addr, int alen, uint8_t *buf, int len)
+static int _davinci_i2c_write(struct i2c_regs *i2c_base, uint8_t chip,
+ uint32_t addr, int alen, uint8_t *buf, int len)
{
- struct i2c_regs *i2c_base = davinci_get_base(adap);
uint32_t tmp;
int i;
@@ -273,7 +236,7 @@ static int davinci_i2c_write(struct i2c_adapter *adap, uint8_t chip,
return 1;
}
- if (wait_for_bus(adap))
+ if (_wait_for_bus(i2c_base))
return 1;
/* Start address phase */
@@ -287,7 +250,7 @@ static int davinci_i2c_write(struct i2c_adapter *adap, uint8_t chip,
switch (alen) {
case 2:
/* Send address MSByte */
- tmp = poll_i2c_irq(adap, I2C_STAT_XRDY | I2C_STAT_NACK);
+ tmp = _poll_i2c_irq(i2c_base, I2C_STAT_XRDY | I2C_STAT_NACK);
CHECK_NACK();
@@ -300,7 +263,7 @@ static int davinci_i2c_write(struct i2c_adapter *adap, uint8_t chip,
/* No break, fall through */
case 1:
/* Send address LSByte */
- tmp = poll_i2c_irq(adap, I2C_STAT_XRDY | I2C_STAT_NACK);
+ tmp = _poll_i2c_irq(i2c_base, I2C_STAT_XRDY | I2C_STAT_NACK);
CHECK_NACK();
@@ -313,7 +276,7 @@ static int davinci_i2c_write(struct i2c_adapter *adap, uint8_t chip,
}
for (i = 0; i < len; i++) {
- tmp = poll_i2c_irq(adap, I2C_STAT_XRDY | I2C_STAT_NACK);
+ tmp = _poll_i2c_irq(i2c_base, I2C_STAT_XRDY | I2C_STAT_NACK);
CHECK_NACK();
@@ -323,7 +286,7 @@ static int davinci_i2c_write(struct i2c_adapter *adap, uint8_t chip,
return 1;
}
- tmp = poll_i2c_irq(adap, I2C_STAT_SCD | I2C_STAT_NACK);
+ tmp = _poll_i2c_irq(i2c_base, I2C_STAT_SCD | I2C_STAT_NACK);
CHECK_NACK();
@@ -332,7 +295,7 @@ static int davinci_i2c_write(struct i2c_adapter *adap, uint8_t chip,
return 1;
}
- flush_rx(adap);
+ _flush_rx(i2c_base);
REG(&(i2c_base->i2c_stat)) = 0xffff;
REG(&(i2c_base->i2c_cnt)) = 0;
REG(&(i2c_base->i2c_con)) = 0;
@@ -340,6 +303,43 @@ static int davinci_i2c_write(struct i2c_adapter *adap, uint8_t chip,
return 0;
}
+static int _davinci_i2c_probe_chip(struct i2c_regs *i2c_base, uint8_t chip)
+{
+ int rc = 1;
+
+ if (chip == REG(&(i2c_base->i2c_oa)))
+ return rc;
+
+ REG(&(i2c_base->i2c_con)) = 0;
+ if (_wait_for_bus(i2c_base))
+ return 1;
+
+ /* try to read one byte from current (or only) address */
+ REG(&(i2c_base->i2c_cnt)) = 1;
+ REG(&(i2c_base->i2c_sa)) = chip;
+ REG(&(i2c_base->i2c_con)) = (I2C_CON_EN | I2C_CON_MST | I2C_CON_STT |
+ I2C_CON_STP);
+ udelay(50000);
+
+ if (!(REG(&(i2c_base->i2c_stat)) & I2C_STAT_NACK)) {
+ rc = 0;
+ _flush_rx(i2c_base);
+ REG(&(i2c_base->i2c_stat)) = 0xffff;
+ } else {
+ REG(&(i2c_base->i2c_stat)) = 0xffff;
+ REG(&(i2c_base->i2c_con)) |= I2C_CON_STP;
+ udelay(20000);
+ if (_wait_for_bus(i2c_base))
+ return 1;
+ }
+
+ _flush_rx(i2c_base);
+ REG(&(i2c_base->i2c_stat)) = 0xffff;
+ REG(&(i2c_base->i2c_cnt)) = 0;
+ return rc;
+}
+
+#ifndef CONFIG_DM_I2C
static struct i2c_regs *davinci_get_base(struct i2c_adapter *adap)
{
switch (adap->hwadapnr) {
@@ -361,7 +361,51 @@ static struct i2c_regs *davinci_get_base(struct i2c_adapter *adap)
return NULL;
}
-U_BOOT_I2C_ADAP_COMPLETE(davinci_0, davinci_i2c_init, davinci_i2c_probe,
+static uint davinci_i2c_setspeed(struct i2c_adapter *adap, uint speed)
+{
+ struct i2c_regs *i2c_base = davinci_get_base(adap);
+ uint ret;
+
+ adap->speed = speed;
+ ret = _davinci_i2c_setspeed(i2c_base, speed);
+
+ return ret;
+}
+
+static void davinci_i2c_init(struct i2c_adapter *adap, int speed,
+ int slaveadd)
+{
+ struct i2c_regs *i2c_base = davinci_get_base(adap);
+
+ adap->speed = speed;
+ _davinci_i2c_init(i2c_base, speed, slaveadd);
+
+ return;
+}
+
+static int davinci_i2c_read(struct i2c_adapter *adap, uint8_t chip,
+ uint32_t addr, int alen, uint8_t *buf, int len)
+{
+ struct i2c_regs *i2c_base = davinci_get_base(adap);
+ return _davinci_i2c_read(i2c_base, chip, addr, alen, buf, len);
+}
+
+static int davinci_i2c_write(struct i2c_adapter *adap, uint8_t chip,
+ uint32_t addr, int alen, uint8_t *buf, int len)
+{
+ struct i2c_regs *i2c_base = davinci_get_base(adap);
+
+ return _davinci_i2c_write(i2c_base, chip, addr, alen, buf, len);
+}
+
+static int davinci_i2c_probe_chip(struct i2c_adapter *adap, uint8_t chip)
+{
+ struct i2c_regs *i2c_base = davinci_get_base(adap);
+
+ return _davinci_i2c_probe_chip(i2c_base, chip);
+}
+
+U_BOOT_I2C_ADAP_COMPLETE(davinci_0, davinci_i2c_init, davinci_i2c_probe_chip,
davinci_i2c_read, davinci_i2c_write,
davinci_i2c_setspeed,
CONFIG_SYS_DAVINCI_I2C_SPEED,
@@ -369,7 +413,7 @@ U_BOOT_I2C_ADAP_COMPLETE(davinci_0, davinci_i2c_init, davinci_i2c_probe,
0)
#if I2C_BUS_MAX >= 2
-U_BOOT_I2C_ADAP_COMPLETE(davinci_1, davinci_i2c_init, davinci_i2c_probe,
+U_BOOT_I2C_ADAP_COMPLETE(davinci_1, davinci_i2c_init, davinci_i2c_probe_chip,
davinci_i2c_read, davinci_i2c_write,
davinci_i2c_setspeed,
CONFIG_SYS_DAVINCI_I2C_SPEED1,
@@ -378,10 +422,89 @@ U_BOOT_I2C_ADAP_COMPLETE(davinci_1, davinci_i2c_init, davinci_i2c_probe,
#endif
#if I2C_BUS_MAX >= 3
-U_BOOT_I2C_ADAP_COMPLETE(davinci_2, davinci_i2c_init, davinci_i2c_probe,
+U_BOOT_I2C_ADAP_COMPLETE(davinci_2, davinci_i2c_init, davinci_i2c_probe_chip,
davinci_i2c_read, davinci_i2c_write,
davinci_i2c_setspeed,
CONFIG_SYS_DAVINCI_I2C_SPEED2,
CONFIG_SYS_DAVINCI_I2C_SLAVE2,
2)
#endif
+
+#else /* CONFIG_DM_I2C */
+
+static int davinci_i2c_xfer(struct udevice *bus, struct i2c_msg *msg,
+ int nmsgs)
+{
+ struct i2c_bus *i2c_bus = dev_get_priv(bus);
+ int ret;
+
+ debug("i2c_xfer: %d messages\n", nmsgs);
+ for (; nmsgs > 0; nmsgs--, msg++) {
+ debug("i2c_xfer: chip=0x%x, len=0x%x\n", msg->addr, msg->len);
+ if (msg->flags & I2C_M_RD) {
+ ret = _davinci_i2c_read(i2c_bus->regs, msg->addr,
+ 0, 0, msg->buf, msg->len);
+ } else {
+ ret = _davinci_i2c_write(i2c_bus->regs, msg->addr,
+ 0, 0, msg->buf, msg->len);
+ }
+ if (ret) {
+ debug("i2c_write: error sending\n");
+ return -EREMOTEIO;
+ }
+ }
+
+ return ret;
+}
+
+static int davinci_i2c_set_speed(struct udevice *dev, uint speed)
+{
+ struct i2c_bus *i2c_bus = dev_get_priv(dev);
+
+ i2c_bus->speed = speed;
+ return _davinci_i2c_setspeed(i2c_bus->regs, speed);
+}
+
+static int davinci_i2c_probe(struct udevice *dev)
+{
+ struct i2c_bus *i2c_bus = dev_get_priv(dev);
+
+ i2c_bus->id = dev->seq;
+ i2c_bus->regs = (struct i2c_regs *)dev_get_addr(dev);
+
+ i2c_bus->speed = 100000;
+ _davinci_i2c_init(i2c_bus->regs, i2c_bus->speed, 0);
+
+ return 0;
+}
+
+static int davinci_i2c_probe_chip(struct udevice *bus, uint chip_addr,
+ uint chip_flags)
+{
+ struct i2c_bus *i2c_bus = dev_get_priv(bus);
+
+ return _davinci_i2c_probe_chip(i2c_bus->regs, chip_addr);
+}
+
+static const struct dm_i2c_ops davinci_i2c_ops = {
+ .xfer = davinci_i2c_xfer,
+ .probe_chip = davinci_i2c_probe_chip,
+ .set_bus_speed = davinci_i2c_set_speed,
+};
+
+static const struct udevice_id davinci_i2c_ids[] = {
+ { .compatible = "ti,davinci-i2c"},
+ { .compatible = "ti,keystone-i2c"},
+ { }
+};
+
+U_BOOT_DRIVER(i2c_davinci) = {
+ .name = "i2c_davinci",
+ .id = UCLASS_I2C,
+ .of_match = davinci_i2c_ids,
+ .probe = davinci_i2c_probe,
+ .priv_auto_alloc_size = sizeof(struct i2c_bus),
+ .ops = &davinci_i2c_ops,
+};
+
+#endif /* CONFIG_DM_I2C */
diff --git a/drivers/i2c/fsl_i2c.c b/drivers/i2c/fsl_i2c.c
index a1406baa87b..ff3dc25927a 100644
--- a/drivers/i2c/fsl_i2c.c
+++ b/drivers/i2c/fsl_i2c.c
@@ -284,15 +284,6 @@ static void __i2c_init(const struct fsl_i2c_base *base, int speed, int
break;
}
-
-#ifdef CONFIG_SYS_I2C_BOARD_LATE_INIT
- /* Call board specific i2c bus reset routine AFTER the bus has been
- * initialized. Use either this callpoint or i2c_init_board;
- * which is called before i2c_init operations.
- * For details about this problem see doc/I2C_Edge_Conditions.
- */
- i2c_board_late_init();
-#endif
}
static int
diff --git a/drivers/i2c/fti2c010.c b/drivers/i2c/fti2c010.c
index b35d0d2d9c5..4da959fa537 100644
--- a/drivers/i2c/fti2c010.c
+++ b/drivers/i2c/fti2c010.c
@@ -146,15 +146,6 @@ static void fti2c010_init(struct i2c_adapter *adap, int speed, int slaveaddr)
set_i2c_bus_speed(chip, speed);
/* slave init, don't care */
-
-#ifdef CONFIG_SYS_I2C_BOARD_LATE_INIT
- /* Call board specific i2c bus reset routine AFTER the bus has been
- * initialized. Use either this callpoint or i2c_init_board;
- * which is called before fti2c010_init operations.
- * For details about this problem see doc/I2C_Edge_Conditions.
- */
- i2c_board_late_init();
-#endif
}
/*
diff --git a/drivers/i2c/mxc_i2c.c b/drivers/i2c/mxc_i2c.c
index 13ec0e63b10..b68e82770b5 100644
--- a/drivers/i2c/mxc_i2c.c
+++ b/drivers/i2c/mxc_i2c.c
@@ -69,10 +69,6 @@ DECLARE_GLOBAL_DATA_PTR;
#define I2SR_IIF_CLEAR (0 << 1)
#endif
-#if defined(CONFIG_HARD_I2C) && !defined(CONFIG_SYS_I2C_BASE)
-#error "define CONFIG_SYS_I2C_BASE to use the mxc_i2c driver"
-#endif
-
#ifdef I2C_QUIRK_REG
static u16 i2c_clk_div[60][2] = {
{ 20, 0x00 }, { 22, 0x01 }, { 24, 0x02 }, { 26, 0x03 },
diff --git a/drivers/i2c/omap24xx_i2c.c b/drivers/i2c/omap24xx_i2c.c
index 26996e9db93..4b8397a890d 100644
--- a/drivers/i2c/omap24xx_i2c.c
+++ b/drivers/i2c/omap24xx_i2c.c
@@ -122,7 +122,7 @@ static int wait_for_bb(struct i2c *i2c_base, int waitdelay)
u16 stat;
writew(0xFFFF, &i2c_base->stat); /* clear current interrupts...*/
-#if defined(CONFIG_OMAP243X) || defined(CONFIG_OMAP34XX)
+#if defined(CONFIG_OMAP34XX)
while ((stat = readw(&i2c_base->stat) & I2C_STAT_BB) && timeout--) {
#else
/* Read RAW status */
@@ -153,7 +153,7 @@ static u16 wait_for_event(struct i2c *i2c_base, int waitdelay)
do {
udelay(waitdelay);
-#if defined(CONFIG_OMAP243X) || defined(CONFIG_OMAP34XX)
+#if defined(CONFIG_OMAP34XX)
status = readw(&i2c_base->stat);
#else
/* Read RAW status */
@@ -338,7 +338,7 @@ retry:
/* own address */
writew(slaveadd, &i2c_base->oa);
-#if defined(CONFIG_OMAP243X) || defined(CONFIG_OMAP34XX)
+#if defined(CONFIG_OMAP34XX)
/*
* Have to enable interrupts for OMAP2/3, these IPs don't have
* an 'irqstatus_raw' register and we shall have to poll 'stat'
@@ -910,6 +910,7 @@ static const struct dm_i2c_ops omap_i2c_ops = {
};
static const struct udevice_id omap_i2c_ids[] = {
+ { .compatible = "ti,omap3-i2c" },
{ .compatible = "ti,omap4-i2c" },
{ }
};
diff --git a/drivers/led/Kconfig b/drivers/led/Kconfig
index 309372ab564..5da5c4af392 100644
--- a/drivers/led/Kconfig
+++ b/drivers/led/Kconfig
@@ -9,6 +9,25 @@ config LED
can provide access to board-specific LEDs. Use of the device tree
for configuration is encouraged.
+config LED_BCM6328
+ bool "LED Support for BCM6328"
+ depends on LED && ARCH_BMIPS
+ help
+ This option enables support for LEDs connected to the BCM6328
+ LED HW controller accessed via MMIO registers.
+ HW blinking is supported and up to 24 LEDs can be controlled.
+ All LEDs can blink at the same time but the delay is shared, which
+ means that if one LED is set to blink at 100ms and then a different
+ LED is set to blink at 200ms, both will blink at 200ms.
+
+config LED_BCM6358
+ bool "LED Support for BCM6358"
+ depends on LED && ARCH_BMIPS
+ help
+ This option enables support for LEDs connected to the BCM6358
+ LED HW controller accessed via MMIO registers.
+ HW has no blinking capabilities and up to 32 LEDs can be controlled.
+
config LED_BLINK
bool "Support LED blinking"
depends on LED
diff --git a/drivers/led/Makefile b/drivers/led/Makefile
index 02367fdacbc..9d079f8336e 100644
--- a/drivers/led/Makefile
+++ b/drivers/led/Makefile
@@ -6,4 +6,6 @@
#
obj-y += led-uclass.o
+obj-$(CONFIG_LED_BCM6328) += led_bcm6328.o
+obj-$(CONFIG_LED_BCM6358) += led_bcm6358.o
obj-$(CONFIG_$(SPL_)LED_GPIO) += led_gpio.o
diff --git a/drivers/led/led_bcm6328.c b/drivers/led/led_bcm6328.c
new file mode 100644
index 00000000000..ef8c6a70617
--- /dev/null
+++ b/drivers/led/led_bcm6328.c
@@ -0,0 +1,262 @@
+/*
+ * Copyright (C) 2017 Álvaro Fernández Rojas <noltari@gmail.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <led.h>
+#include <asm/io.h>
+#include <dm/lists.h>
+
+#define LEDS_MAX 24
+
+/* LED Init register */
+#define LED_INIT_REG 0x00
+#define LED_INIT_FASTINTV_MS 20
+#define LED_INIT_FASTINTV_SHIFT 6
+#define LED_INIT_FASTINTV_MASK (0x3f << LED_INIT_FASTINTV_SHIFT)
+#define LED_INIT_SLEDEN_SHIFT 12
+#define LED_INIT_SLEDEN_MASK (1 << LED_INIT_SLEDEN_SHIFT)
+#define LED_INIT_SLEDMUX_SHIFT 13
+#define LED_INIT_SLEDMUX_MASK (1 << LED_INIT_SLEDMUX_SHIFT)
+#define LED_INIT_SLEDCLKNPOL_SHIFT 14
+#define LED_INIT_SLEDCLKNPOL_MASK (1 << LED_INIT_SLEDCLKNPOL_SHIFT)
+#define LED_INIT_SLEDDATAPPOL_SHIFT 15
+#define LED_INIT_SLEDDATANPOL_MASK (1 << LED_INIT_SLEDDATAPPOL_SHIFT)
+#define LED_INIT_SLEDSHIFTDIR_SHIFT 16
+#define LED_INIT_SLEDSHIFTDIR_MASK (1 << LED_INIT_SLEDSHIFTDIR_SHIFT)
+
+/* LED Mode registers */
+#define LED_MODE_REG_HI 0x04
+#define LED_MODE_REG_LO 0x08
+#define LED_MODE_ON 0
+#define LED_MODE_FAST 1
+#define LED_MODE_BLINK 2
+#define LED_MODE_OFF 3
+#define LED_MODE_MASK 0x3
+
+DECLARE_GLOBAL_DATA_PTR;
+
+struct bcm6328_led_priv {
+ void __iomem *regs;
+ void __iomem *mode;
+ uint8_t shift;
+ bool active_low;
+};
+
+static unsigned long bcm6328_led_get_mode(struct bcm6328_led_priv *priv)
+{
+ return ((readl_be(priv->mode) >> priv->shift) & LED_MODE_MASK);
+}
+
+static int bcm6328_led_set_mode(struct bcm6328_led_priv *priv, uint8_t mode)
+{
+ clrsetbits_be32(priv->mode, (LED_MODE_MASK << priv->shift),
+ (mode << priv->shift));
+
+ return 0;
+}
+
+static enum led_state_t bcm6328_led_get_state(struct udevice *dev)
+{
+ struct bcm6328_led_priv *priv = dev_get_priv(dev);
+ enum led_state_t state = LEDST_OFF;
+
+ switch (bcm6328_led_get_mode(priv)) {
+#ifdef CONFIG_LED_BLINK
+ case LED_MODE_BLINK:
+ case LED_MODE_FAST:
+ state = LEDST_BLINK;
+ break;
+#endif
+ case LED_MODE_OFF:
+ state = (priv->active_low ? LEDST_ON : LEDST_OFF);
+ break;
+ case LED_MODE_ON:
+ state = (priv->active_low ? LEDST_OFF : LEDST_ON);
+ break;
+ }
+
+ return state;
+}
+
+static int bcm6328_led_set_state(struct udevice *dev, enum led_state_t state)
+{
+ struct bcm6328_led_priv *priv = dev_get_priv(dev);
+ unsigned long mode;
+
+ switch (state) {
+#ifdef CONFIG_LED_BLINK
+ case LEDST_BLINK:
+ mode = LED_MODE_BLINK;
+ break;
+#endif
+ case LEDST_OFF:
+ mode = (priv->active_low ? LED_MODE_ON : LED_MODE_OFF);
+ break;
+ case LEDST_ON:
+ mode = (priv->active_low ? LED_MODE_OFF : LED_MODE_ON);
+ break;
+ case LEDST_TOGGLE:
+ if (bcm6328_led_get_state(dev) == LEDST_OFF)
+ return bcm6328_led_set_state(dev, LEDST_ON);
+ else
+ return bcm6328_led_set_state(dev, LEDST_OFF);
+ break;
+ default:
+ return -ENOSYS;
+ }
+
+ return bcm6328_led_set_mode(priv, mode);
+}
+
+#ifdef CONFIG_LED_BLINK
+static unsigned long bcm6328_blink_delay(int delay)
+{
+ unsigned long bcm6328_delay = delay;
+
+ bcm6328_delay += (LED_INIT_FASTINTV_MS / 2);
+ bcm6328_delay /= LED_INIT_FASTINTV_MS;
+ bcm6328_delay <<= LED_INIT_FASTINTV_SHIFT;
+
+ if (bcm6328_delay > LED_INIT_FASTINTV_MASK)
+ return LED_INIT_FASTINTV_MASK;
+ else
+ return bcm6328_delay;
+}
+
+static int bcm6328_led_set_period(struct udevice *dev, int period_ms)
+{
+ struct bcm6328_led_priv *priv = dev_get_priv(dev);
+
+ clrsetbits_be32(priv->regs + LED_INIT_REG, LED_INIT_FASTINTV_MASK,
+ bcm6328_blink_delay(period_ms));
+
+ return 0;
+}
+#endif
+
+static const struct led_ops bcm6328_led_ops = {
+ .get_state = bcm6328_led_get_state,
+ .set_state = bcm6328_led_set_state,
+#ifdef CONFIG_LED_BLINK
+ .set_period = bcm6328_led_set_period,
+#endif
+};
+
+static int bcm6328_led_probe(struct udevice *dev)
+{
+ struct led_uc_plat *uc_plat = dev_get_uclass_platdata(dev);
+ fdt_addr_t addr;
+ fdt_size_t size;
+
+ /* Top-level LED node */
+ if (!uc_plat->label) {
+ void __iomem *regs;
+ u32 set_bits = 0;
+
+ addr = dev_get_addr_size_index(dev, 0, &size);
+ if (addr == FDT_ADDR_T_NONE)
+ return -EINVAL;
+
+ regs = ioremap(addr, size);
+
+ if (fdtdec_get_bool(gd->fdt_blob, dev_of_offset(dev),
+ "brcm,serial-leds"))
+ set_bits |= LED_INIT_SLEDEN_MASK;
+ if (fdtdec_get_bool(gd->fdt_blob, dev_of_offset(dev),
+ "brcm,serial-mux"))
+ set_bits |= LED_INIT_SLEDMUX_MASK;
+ if (fdtdec_get_bool(gd->fdt_blob, dev_of_offset(dev),
+ "brcm,serial-clk-low"))
+ set_bits |= LED_INIT_SLEDCLKNPOL_MASK;
+ if (!fdtdec_get_bool(gd->fdt_blob, dev_of_offset(dev),
+ "brcm,serial-dat-low"))
+ set_bits |= LED_INIT_SLEDDATANPOL_MASK;
+ if (!fdtdec_get_bool(gd->fdt_blob, dev_of_offset(dev),
+ "brcm,serial-shift-inv"))
+ set_bits |= LED_INIT_SLEDSHIFTDIR_MASK;
+
+ clrsetbits_be32(regs + LED_INIT_REG, ~0, set_bits);
+ } else {
+ struct bcm6328_led_priv *priv = dev_get_priv(dev);
+ unsigned int pin;
+
+ addr = dev_get_addr_size_index(dev_get_parent(dev), 0, &size);
+ if (addr == FDT_ADDR_T_NONE)
+ return -EINVAL;
+
+ pin = fdtdec_get_uint(gd->fdt_blob, dev_of_offset(dev), "reg",
+ LEDS_MAX);
+ if (pin >= LEDS_MAX)
+ return -EINVAL;
+
+ priv->regs = ioremap(addr, size);
+ if (pin < 8) {
+ /* LEDs 0-7 (bits 47:32) */
+ priv->mode = priv->regs + LED_MODE_REG_HI;
+ priv->shift = (pin << 1);
+ } else {
+ /* LEDs 8-23 (bits 31:0) */
+ priv->mode = priv->regs + LED_MODE_REG_LO;
+ priv->shift = ((pin - 8) << 1);
+ }
+
+ if (fdtdec_get_bool(gd->fdt_blob, dev_of_offset(dev),
+ "active-low"))
+ priv->active_low = true;
+ }
+
+ return 0;
+}
+
+static int bcm6328_led_bind(struct udevice *parent)
+{
+ const void *blob = gd->fdt_blob;
+ int node;
+
+ for (node = fdt_first_subnode(blob, dev_of_offset(parent));
+ node > 0;
+ node = fdt_next_subnode(blob, node)) {
+ struct led_uc_plat *uc_plat;
+ struct udevice *dev;
+ const char *label;
+ int ret;
+
+ label = fdt_getprop(blob, node, "label", NULL);
+ if (!label) {
+ debug("%s: node %s has no label\n", __func__,
+ fdt_get_name(blob, node, NULL));
+ return -EINVAL;
+ }
+
+ ret = device_bind_driver_to_node(parent, "bcm6328-led",
+ fdt_get_name(blob, node, NULL),
+ node, &dev);
+ if (ret)
+ return ret;
+
+ uc_plat = dev_get_uclass_platdata(dev);
+ uc_plat->label = label;
+ }
+
+ return 0;
+}
+
+static const struct udevice_id bcm6328_led_ids[] = {
+ { .compatible = "brcm,bcm6328-leds" },
+ { /* sentinel */ }
+};
+
+U_BOOT_DRIVER(bcm6328_led) = {
+ .name = "bcm6328-led",
+ .id = UCLASS_LED,
+ .of_match = bcm6328_led_ids,
+ .ops = &bcm6328_led_ops,
+ .bind = bcm6328_led_bind,
+ .probe = bcm6328_led_probe,
+ .priv_auto_alloc_size = sizeof(struct bcm6328_led_priv),
+};
diff --git a/drivers/led/led_bcm6358.c b/drivers/led/led_bcm6358.c
new file mode 100644
index 00000000000..11caecdc26b
--- /dev/null
+++ b/drivers/led/led_bcm6358.c
@@ -0,0 +1,227 @@
+/*
+ * Copyright (C) 2017 Álvaro Fernández Rojas <noltari@gmail.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <led.h>
+#include <asm/io.h>
+#include <dm/lists.h>
+
+#define LEDS_MAX 32
+#define LEDS_WAIT 100
+
+/* LED Mode register */
+#define LED_MODE_REG 0x0
+#define LED_MODE_OFF 0
+#define LED_MODE_ON 1
+#define LED_MODE_MASK 1
+
+/* LED Control register */
+#define LED_CTRL_REG 0x4
+#define LED_CTRL_CLK_MASK 0x3
+#define LED_CTRL_CLK_1 0
+#define LED_CTRL_CLK_2 1
+#define LED_CTRL_CLK_4 2
+#define LED_CTRL_CLK_8 3
+#define LED_CTRL_POL_SHIFT 2
+#define LED_CTRL_POL_MASK (1 << LED_CTRL_POL_SHIFT)
+#define LED_CTRL_BUSY_SHIFT 3
+#define LED_CTRL_BUSY_MASK (1 << LED_CTRL_BUSY_SHIFT)
+
+DECLARE_GLOBAL_DATA_PTR;
+
+struct bcm6358_led_priv {
+ void __iomem *regs;
+ uint8_t pin;
+ bool active_low;
+};
+
+static void bcm6358_led_busy(void __iomem *regs)
+{
+ while (readl_be(regs + LED_CTRL_REG) & LED_CTRL_BUSY_MASK)
+ udelay(LEDS_WAIT);
+}
+
+static unsigned long bcm6358_led_get_mode(struct bcm6358_led_priv *priv)
+{
+ bcm6358_led_busy(priv->regs);
+
+ return (readl_be(priv->regs + LED_MODE_REG) >> priv->pin) &
+ LED_MODE_MASK;
+}
+
+static int bcm6358_led_set_mode(struct bcm6358_led_priv *priv, uint8_t mode)
+{
+ bcm6358_led_busy(priv->regs);
+
+ clrsetbits_be32(priv->regs + LED_MODE_REG,
+ (LED_MODE_MASK << priv->pin),
+ (mode << priv->pin));
+
+ return 0;
+}
+
+static enum led_state_t bcm6358_led_get_state(struct udevice *dev)
+{
+ struct bcm6358_led_priv *priv = dev_get_priv(dev);
+ enum led_state_t state = LEDST_OFF;
+
+ switch (bcm6358_led_get_mode(priv)) {
+ case LED_MODE_OFF:
+ state = (priv->active_low ? LEDST_ON : LEDST_OFF);
+ break;
+ case LED_MODE_ON:
+ state = (priv->active_low ? LEDST_OFF : LEDST_ON);
+ break;
+ }
+
+ return state;
+}
+
+static int bcm6358_led_set_state(struct udevice *dev, enum led_state_t state)
+{
+ struct bcm6358_led_priv *priv = dev_get_priv(dev);
+ unsigned long mode;
+
+ switch (state) {
+ case LEDST_OFF:
+ mode = (priv->active_low ? LED_MODE_ON : LED_MODE_OFF);
+ break;
+ case LEDST_ON:
+ mode = (priv->active_low ? LED_MODE_OFF : LED_MODE_ON);
+ break;
+ case LEDST_TOGGLE:
+ if (bcm6358_led_get_state(dev) == LEDST_OFF)
+ return bcm6358_led_set_state(dev, LEDST_ON);
+ else
+ return bcm6358_led_set_state(dev, LEDST_OFF);
+ break;
+ default:
+ return -ENOSYS;
+ }
+
+ return bcm6358_led_set_mode(priv, mode);
+}
+
+static const struct led_ops bcm6358_led_ops = {
+ .get_state = bcm6358_led_get_state,
+ .set_state = bcm6358_led_set_state,
+};
+
+static int bcm6358_led_probe(struct udevice *dev)
+{
+ struct led_uc_plat *uc_plat = dev_get_uclass_platdata(dev);
+ fdt_addr_t addr;
+ fdt_size_t size;
+
+ /* Top-level LED node */
+ if (!uc_plat->label) {
+ void __iomem *regs;
+ unsigned int clk_div;
+ u32 set_bits = 0;
+
+ addr = dev_get_addr_size_index(dev, 0, &size);
+ if (addr == FDT_ADDR_T_NONE)
+ return -EINVAL;
+
+ regs = ioremap(addr, size);
+
+ if (fdtdec_get_bool(gd->fdt_blob, dev_of_offset(dev),
+ "brcm,clk-dat-low"))
+ set_bits |= LED_CTRL_POL_MASK;
+ clk_div = fdtdec_get_uint(gd->fdt_blob, dev_of_offset(dev),
+ "brcm,clk-div", LED_CTRL_CLK_1);
+ switch (clk_div) {
+ case 8:
+ set_bits |= LED_CTRL_CLK_8;
+ break;
+ case 4:
+ set_bits |= LED_CTRL_CLK_4;
+ break;
+ case 2:
+ set_bits |= LED_CTRL_CLK_2;
+ break;
+ default:
+ set_bits |= LED_CTRL_CLK_1;
+ break;
+ }
+
+ bcm6358_led_busy(regs);
+ clrsetbits_be32(regs + LED_CTRL_REG,
+ LED_CTRL_POL_MASK | LED_CTRL_CLK_MASK,
+ set_bits);
+ } else {
+ struct bcm6358_led_priv *priv = dev_get_priv(dev);
+ unsigned int pin;
+
+ addr = dev_get_addr_size_index(dev_get_parent(dev), 0, &size);
+ if (addr == FDT_ADDR_T_NONE)
+ return -EINVAL;
+
+ pin = fdtdec_get_uint(gd->fdt_blob, dev_of_offset(dev), "reg",
+ LEDS_MAX);
+ if (pin >= LEDS_MAX)
+ return -EINVAL;
+
+ priv->regs = ioremap(addr, size);
+ priv->pin = pin;
+
+ if (fdtdec_get_bool(gd->fdt_blob, dev_of_offset(dev),
+ "active-low"))
+ priv->active_low = true;
+ }
+
+ return 0;
+}
+
+static int bcm6358_led_bind(struct udevice *parent)
+{
+ const void *blob = gd->fdt_blob;
+ int node;
+
+ for (node = fdt_first_subnode(blob, dev_of_offset(parent));
+ node > 0;
+ node = fdt_next_subnode(blob, node)) {
+ struct led_uc_plat *uc_plat;
+ struct udevice *dev;
+ const char *label;
+ int ret;
+
+ label = fdt_getprop(blob, node, "label", NULL);
+ if (!label) {
+ debug("%s: node %s has no label\n", __func__,
+ fdt_get_name(blob, node, NULL));
+ return -EINVAL;
+ }
+
+ ret = device_bind_driver_to_node(parent, "bcm6358-led",
+ fdt_get_name(blob, node, NULL),
+ node, &dev);
+ if (ret)
+ return ret;
+
+ uc_plat = dev_get_uclass_platdata(dev);
+ uc_plat->label = label;
+ }
+
+ return 0;
+}
+
+static const struct udevice_id bcm6358_led_ids[] = {
+ { .compatible = "brcm,bcm6358-leds" },
+ { /* sentinel */ }
+};
+
+U_BOOT_DRIVER(bcm6358_led) = {
+ .name = "bcm6358-led",
+ .id = UCLASS_LED,
+ .of_match = bcm6358_led_ids,
+ .bind = bcm6358_led_bind,
+ .probe = bcm6358_led_probe,
+ .priv_auto_alloc_size = sizeof(struct bcm6358_led_priv),
+ .ops = &bcm6358_led_ops,
+};
diff --git a/drivers/misc/i2c_eeprom.c b/drivers/misc/i2c_eeprom.c
index c9f4174bad4..da6e2b05f73 100644
--- a/drivers/misc/i2c_eeprom.c
+++ b/drivers/misc/i2c_eeprom.c
@@ -10,21 +10,41 @@
#include <i2c.h>
#include <i2c_eeprom.h>
-static int i2c_eeprom_read(struct udevice *dev, int offset, uint8_t *buf,
- int size)
+int i2c_eeprom_read(struct udevice *dev, int offset, uint8_t *buf, int size)
+{
+ const struct i2c_eeprom_ops *ops = device_get_ops(dev);
+
+ if (!ops->read)
+ return -ENOSYS;
+
+ return ops->read(dev, offset, buf, size);
+}
+
+int i2c_eeprom_write(struct udevice *dev, int offset, uint8_t *buf, int size)
+{
+ const struct i2c_eeprom_ops *ops = device_get_ops(dev);
+
+ if (!ops->write)
+ return -ENOSYS;
+
+ return ops->write(dev, offset, buf, size);
+}
+
+static int i2c_eeprom_std_read(struct udevice *dev, int offset, uint8_t *buf,
+ int size)
{
return dm_i2c_read(dev, offset, buf, size);
}
-static int i2c_eeprom_write(struct udevice *dev, int offset,
- const uint8_t *buf, int size)
+static int i2c_eeprom_std_write(struct udevice *dev, int offset,
+ const uint8_t *buf, int size)
{
return -ENODEV;
}
struct i2c_eeprom_ops i2c_eeprom_std_ops = {
- .read = i2c_eeprom_read,
- .write = i2c_eeprom_write,
+ .read = i2c_eeprom_std_read,
+ .write = i2c_eeprom_std_write,
};
static int i2c_eeprom_std_ofdata_to_platdata(struct udevice *dev)
diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig
index 6ac26dd137c..0dd44436025 100644
--- a/drivers/mmc/Kconfig
+++ b/drivers/mmc/Kconfig
@@ -10,10 +10,6 @@ config MMC
If you want MMC/SD/SDIO support, you should say Y here and
also to your specific host controller driver.
-config GENERIC_MMC
- bool "Generic MMC driver framework"
- default MMC
-
config DM_MMC
bool "Enable MMC controllers using Driver Model"
depends on DM
@@ -138,6 +134,7 @@ config MMC_PCI
config MMC_OMAP_HS
bool "TI OMAP High Speed Multimedia Card Interface support"
+ select DM_MMC_OPS if DM_MMC
help
This selects the TI OMAP High Speed Multimedia card Interface.
If you have an omap2plus board with a Multimedia Card slot,
diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile
index de91f1423bc..a0786498994 100644
--- a/drivers/mmc/Makefile
+++ b/drivers/mmc/Makefile
@@ -5,17 +5,24 @@
# SPDX-License-Identifier: GPL-2.0+
#
-ifdef CONFIG_DM_MMC
-obj-$(CONFIG_GENERIC_MMC) += mmc-uclass.o
-endif
+obj-y += mmc.o
+obj-$(CONFIG_DM_MMC) += mmc-uclass.o
ifndef CONFIG_BLK
-obj-$(CONFIG_GENERIC_MMC) += mmc_legacy.o
+obj-y += mmc_legacy.o
+endif
+
+obj-$(CONFIG_SUPPORT_EMMC_BOOT) += mmc_boot.o
+
+ifdef CONFIG_SPL_BUILD
+obj-$(CONFIG_SPL_MMC_BOOT) += fsl_esdhc_spl.o
+obj-$(CONFIG_SPL_SAVEENV) += mmc_write.o
+else
+obj-y += mmc_write.o
endif
obj-$(CONFIG_ARM_PL180_MMCI) += arm_pl180_mmci.o
obj-$(CONFIG_MMC_DAVINCI) += davinci_mmc.o
-
obj-$(CONFIG_MMC_DW) += dw_mmc.o
obj-$(CONFIG_MMC_DW_EXYNOS) += exynos_dw_mmc.o
obj-$(CONFIG_MMC_DW_K3) += hi6220_dw_mmc.o
@@ -23,10 +30,6 @@ obj-$(CONFIG_MMC_DW_ROCKCHIP) += rockchip_dw_mmc.o
obj-$(CONFIG_MMC_DW_SOCFPGA) += socfpga_dw_mmc.o
obj-$(CONFIG_FSL_ESDHC) += fsl_esdhc.o
obj-$(CONFIG_FTSDC010) += ftsdc010_mci.o
-obj-$(CONFIG_GENERIC_MMC) += mmc.o
-ifdef CONFIG_SUPPORT_EMMC_BOOT
-obj-$(CONFIG_GENERIC_MMC) += mmc_boot.o
-endif
obj-$(CONFIG_GENERIC_ATMEL_MCI) += gen_atmel_mci.o
obj-$(CONFIG_MMC_MESON_GX) += meson_gx_mmc.o
obj-$(CONFIG_MMC_SPI) += mmc_spi.o
@@ -42,13 +45,6 @@ obj-$(CONFIG_MMC_SANDBOX) += sandbox_mmc.o
obj-$(CONFIG_SH_MMCIF) += sh_mmcif.o
obj-$(CONFIG_SH_SDHI) += sh_sdhi.o
-ifdef CONFIG_SPL_BUILD
-obj-$(CONFIG_SPL_MMC_BOOT) += fsl_esdhc_spl.o
-obj-$(CONFIG_SPL_SAVEENV) += mmc_write.o
-else
-obj-$(CONFIG_GENERIC_MMC) += mmc_write.o
-endif
-
# SDHCI
obj-$(CONFIG_MMC_SDHCI) += sdhci.o
obj-$(CONFIG_MMC_SDHCI_ATMEL) += atmel_sdhci.o
diff --git a/drivers/mmc/atmel_sdhci.c b/drivers/mmc/atmel_sdhci.c
index 852255782f1..86e36a9c286 100644
--- a/drivers/mmc/atmel_sdhci.c
+++ b/drivers/mmc/atmel_sdhci.c
@@ -28,7 +28,7 @@ int atmel_sdhci_init(void *regbase, u32 id)
host->name = "atmel_sdhci";
host->ioaddr = regbase;
- host->quirks = 0;
+ host->quirks = SDHCI_QUIRK_WAIT_SEND_CMD;
max_clk = at91_get_periph_generated_clk(id);
if (!max_clk) {
printf("%s: Failed to get the proper clock\n", __func__);
@@ -74,7 +74,7 @@ static int atmel_sdhci_probe(struct udevice *dev)
host->name = dev->name;
host->ioaddr = (void *)dev_get_addr(dev);
- host->quirks = 0;
+ host->quirks = SDHCI_QUIRK_WAIT_SEND_CMD;
host->bus_width = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev),
"bus-width", 4);
diff --git a/drivers/mmc/bcm2835_sdhci.c b/drivers/mmc/bcm2835_sdhci.c
index 20079bce48b..b6e2fc68972 100644
--- a/drivers/mmc/bcm2835_sdhci.c
+++ b/drivers/mmc/bcm2835_sdhci.c
@@ -37,15 +37,24 @@
*/
#include <common.h>
+#include <dm.h>
#include <malloc.h>
+#include <memalign.h>
#include <sdhci.h>
-#include <mach/timer.h>
+#include <asm/arch/msg.h>
+#include <asm/arch/mbox.h>
#include <mach/sdhci.h>
+#include <mach/timer.h>
/* 400KHz is max freq for card ID etc. Use that as min */
#define MIN_FREQ 400000
#define SDHCI_BUFFER 0x20
+struct bcm2835_sdhci_plat {
+ struct mmc_config cfg;
+ struct mmc mmc;
+};
+
struct bcm2835_sdhci_host {
struct sdhci_host host;
uint twoticks_delay;
@@ -58,7 +67,7 @@ static inline struct bcm2835_sdhci_host *to_bcm(struct sdhci_host *host)
}
static inline void bcm2835_sdhci_raw_writel(struct sdhci_host *host, u32 val,
- int reg)
+ int reg)
{
struct bcm2835_sdhci_host *bcm_host = to_bcm(host);
@@ -153,16 +162,33 @@ static const struct sdhci_ops bcm2835_ops = {
.read_b = bcm2835_sdhci_readb,
};
-int bcm2835_sdhci_init(u32 regbase, u32 emmc_freq)
+static int bcm2835_sdhci_bind(struct udevice *dev)
{
- struct bcm2835_sdhci_host *bcm_host;
- struct sdhci_host *host;
+ struct bcm2835_sdhci_plat *plat = dev_get_platdata(dev);
- bcm_host = calloc(1, sizeof(*bcm_host));
- if (!bcm_host) {
- printf("sdhci_host calloc fail!\n");
- return -ENOMEM;
+ return sdhci_bind(dev, &plat->mmc, &plat->cfg);
+}
+
+static int bcm2835_sdhci_probe(struct udevice *dev)
+{
+ struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
+ struct bcm2835_sdhci_plat *plat = dev_get_platdata(dev);
+ struct bcm2835_sdhci_host *priv = dev_get_priv(dev);
+ struct sdhci_host *host = &priv->host;
+ fdt_addr_t base;
+ int emmc_freq;
+ int ret;
+
+ base = dev_get_addr(dev);
+ if (base == FDT_ADDR_T_NONE)
+ return -EINVAL;
+
+ ret = bcm2835_get_mmc_clock();
+ if (ret < 0) {
+ debug("%s: Failed to set MMC clock (err=%d)\n", __func__, ret);
+ return ret;
}
+ emmc_freq = ret;
/*
* See the comments in bcm2835_sdhci_raw_writel().
@@ -177,19 +203,42 @@ int bcm2835_sdhci_init(u32 regbase, u32 emmc_freq)
* Multiply by 1000000 to get uS per two ticks.
* +1 for hack rounding.
*/
- bcm_host->twoticks_delay = ((2 * 1000000) / MIN_FREQ) + 1;
- bcm_host->last_write = 0;
+ priv->twoticks_delay = ((2 * 1000000) / MIN_FREQ) + 1;
+ priv->last_write = 0;
- host = &bcm_host->host;
- host->name = "bcm2835_sdhci";
- host->ioaddr = (void *)(unsigned long)regbase;
+ host->name = dev->name;
+ host->ioaddr = (void *)base;
host->quirks = SDHCI_QUIRK_BROKEN_VOLTAGE | SDHCI_QUIRK_BROKEN_R1B |
SDHCI_QUIRK_WAIT_SEND_CMD | SDHCI_QUIRK_NO_HISPD_BIT;
host->max_clk = emmc_freq;
host->voltages = MMC_VDD_32_33 | MMC_VDD_33_34 | MMC_VDD_165_195;
host->ops = &bcm2835_ops;
- add_sdhci(host, 0, MIN_FREQ);
+ ret = sdhci_setup_cfg(&plat->cfg, host, emmc_freq, MIN_FREQ);
+ if (ret) {
+ debug("%s: Failed to setup SDHCI (err=%d)\n", __func__, ret);
+ return ret;
+ }
+
+ upriv->mmc = &plat->mmc;
+ host->mmc = &plat->mmc;
+ host->mmc->priv = host;
- return 0;
+ return sdhci_probe(dev);
}
+
+static const struct udevice_id bcm2835_sdhci_match[] = {
+ { .compatible = "brcm,bcm2835-sdhci" },
+ { /* sentinel */ }
+};
+
+U_BOOT_DRIVER(sdhci_cdns) = {
+ .name = "sdhci-bcm2835",
+ .id = UCLASS_MMC,
+ .of_match = bcm2835_sdhci_match,
+ .bind = bcm2835_sdhci_bind,
+ .probe = bcm2835_sdhci_probe,
+ .priv_auto_alloc_size = sizeof(struct bcm2835_sdhci_host),
+ .platdata_auto_alloc_size = sizeof(struct bcm2835_sdhci_plat),
+ .ops = &sdhci_ops,
+};
diff --git a/drivers/mmc/davinci_mmc.c b/drivers/mmc/davinci_mmc.c
index 9edb668e149..dd784290bc6 100644
--- a/drivers/mmc/davinci_mmc.c
+++ b/drivers/mmc/davinci_mmc.c
@@ -347,7 +347,7 @@ static int dmmc_init(struct mmc *mmc)
return 0;
}
-/* Set buswidth or clock as indicated by the GENERIC_MMC framework */
+/* Set buswidth or clock as indicated by the MMC framework */
static int dmmc_set_ios(struct mmc *mmc)
{
struct davinci_mmc *host = mmc->priv;
diff --git a/drivers/mmc/omap_hsmmc.c b/drivers/mmc/omap_hsmmc.c
index 83dda09c1fe..0b21ec6efcf 100644
--- a/drivers/mmc/omap_hsmmc.c
+++ b/drivers/mmc/omap_hsmmc.c
@@ -56,9 +56,8 @@ DECLARE_GLOBAL_DATA_PTR;
#define SYSCTL_SRC (1 << 25)
#define SYSCTL_SRD (1 << 26)
-struct omap_hsmmc_plat {
- struct mmc_config cfg;
- struct mmc mmc;
+struct omap2_mmc_platform_config {
+ u32 reg_offset;
};
struct omap_hsmmc_data {
@@ -327,11 +326,17 @@ static void mmc_reset_controller_fsm(struct hsmmc *mmc_base, u32 bit)
}
}
}
-
+#ifndef CONFIG_DM_MMC
static int omap_hsmmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd,
struct mmc_data *data)
{
struct omap_hsmmc_data *priv = omap_hsmmc_get_data(mmc);
+#else
+static int omap_hsmmc_send_cmd(struct udevice *dev, struct mmc_cmd *cmd,
+ struct mmc_data *data)
+{
+ struct omap_hsmmc_data *priv = dev_get_priv(dev);
+#endif
struct hsmmc *mmc_base;
unsigned int flags, mmc_stat;
ulong start;
@@ -559,9 +564,17 @@ static int mmc_write_data(struct hsmmc *mmc_base, const char *buf,
return 0;
}
+#ifndef CONFIG_DM_MMC
static int omap_hsmmc_set_ios(struct mmc *mmc)
{
struct omap_hsmmc_data *priv = omap_hsmmc_get_data(mmc);
+#else
+static int omap_hsmmc_set_ios(struct udevice *dev)
+{
+ struct omap_hsmmc_data *priv = dev_get_priv(dev);
+ struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
+ struct mmc *mmc = upriv->mmc;
+#endif
struct hsmmc *mmc_base;
unsigned int dsor = 0;
ulong start;
@@ -618,9 +631,9 @@ static int omap_hsmmc_set_ios(struct mmc *mmc)
#ifdef OMAP_HSMMC_USE_GPIO
#ifdef CONFIG_DM_MMC
-static int omap_hsmmc_getcd(struct mmc *mmc)
+static int omap_hsmmc_getcd(struct udevice *dev)
{
- struct omap_hsmmc_data *priv = omap_hsmmc_get_data(mmc);
+ struct omap_hsmmc_data *priv = dev_get_priv(dev);
int value;
value = dm_gpio_get_value(&priv->cd_gpio);
@@ -633,9 +646,9 @@ static int omap_hsmmc_getcd(struct mmc *mmc)
return value;
}
-static int omap_hsmmc_getwp(struct mmc *mmc)
+static int omap_hsmmc_getwp(struct udevice *dev)
{
- struct omap_hsmmc_data *priv = omap_hsmmc_get_data(mmc);
+ struct omap_hsmmc_data *priv = dev_get_priv(dev);
int value;
value = dm_gpio_get_value(&priv->wp_gpio);
@@ -675,6 +688,16 @@ static int omap_hsmmc_getwp(struct mmc *mmc)
#endif
#endif
+#ifdef CONFIG_DM_MMC
+static const struct dm_mmc_ops omap_hsmmc_ops = {
+ .send_cmd = omap_hsmmc_send_cmd,
+ .set_ios = omap_hsmmc_set_ios,
+#ifdef OMAP_HSMMC_USE_GPIO
+ .get_cd = omap_hsmmc_getcd,
+ .get_wp = omap_hsmmc_getwp,
+#endif
+};
+#else
static const struct mmc_ops omap_hsmmc_ops = {
.send_cmd = omap_hsmmc_send_cmd,
.set_ios = omap_hsmmc_set_ios,
@@ -684,6 +707,7 @@ static const struct mmc_ops omap_hsmmc_ops = {
.getwp = omap_hsmmc_getwp,
#endif
};
+#endif
#ifndef CONFIG_DM_MMC
int omap_mmc_init(int dev_index, uint host_caps_mask, uint f_max, int cd_gpio,
@@ -773,17 +797,19 @@ int omap_mmc_init(int dev_index, uint host_caps_mask, uint f_max, int cd_gpio,
return 0;
}
#else
+#if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)
static int omap_hsmmc_ofdata_to_platdata(struct udevice *dev)
{
- struct omap_hsmmc_data *priv = dev_get_priv(dev);
struct omap_hsmmc_plat *plat = dev_get_platdata(dev);
struct mmc_config *cfg = &plat->cfg;
+ struct omap2_mmc_platform_config *data =
+ (struct omap2_mmc_platform_config *)dev_get_driver_data(dev);
const void *fdt = gd->fdt_blob;
int node = dev_of_offset(dev);
int val;
- priv->base_addr = map_physmem(dev_get_addr(dev), sizeof(struct hsmmc *),
- MAP_NOCACHE);
+ plat->base_addr = map_physmem(dev_get_addr(dev), sizeof(struct hsmmc *),
+ MAP_NOCACHE) + data->reg_offset;
cfg->host_caps = MMC_MODE_HS_52MHz | MMC_MODE_HS;
val = fdtdec_get_int(fdt, node, "bus-width", -1);
@@ -809,11 +835,12 @@ static int omap_hsmmc_ofdata_to_platdata(struct udevice *dev)
cfg->b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT;
#ifdef OMAP_HSMMC_USE_GPIO
- priv->cd_inverted = fdtdec_get_bool(fdt, node, "cd-inverted");
+ plat->cd_inverted = fdtdec_get_bool(fdt, node, "cd-inverted");
#endif
return 0;
}
+#endif
#ifdef CONFIG_BLK
@@ -833,7 +860,10 @@ static int omap_hsmmc_probe(struct udevice *dev)
struct mmc *mmc;
cfg->name = "OMAP SD/MMC";
- cfg->ops = &omap_hsmmc_ops;
+ priv->base_addr = plat->base_addr;
+#ifdef OMAP_HSMMC_USE_GPIO
+ priv->cd_inverted = plat->cd_inverted;
+#endif
#ifdef CONFIG_BLK
mmc = &plat->mmc;
@@ -843,7 +873,7 @@ static int omap_hsmmc_probe(struct udevice *dev)
return -1;
#endif
-#ifdef OMAP_HSMMC_USE_GPIO
+#if defined(OMAP_HSMMC_USE_GPIO) && CONFIG_IS_ENABLED(OF_CONTROL)
gpio_request_by_name(dev, "cd-gpios", 0, &priv->cd_gpio, GPIOD_IS_IN);
gpio_request_by_name(dev, "wp-gpios", 0, &priv->wp_gpio, GPIOD_IS_IN);
#endif
@@ -851,26 +881,53 @@ static int omap_hsmmc_probe(struct udevice *dev)
mmc->dev = dev;
upriv->mmc = mmc;
- return 0;
+ return omap_hsmmc_init_setup(mmc);
}
+#if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)
+static const struct omap2_mmc_platform_config omap3_mmc_pdata = {
+ .reg_offset = 0,
+};
+
+static const struct omap2_mmc_platform_config am33xx_mmc_pdata = {
+ .reg_offset = 0x100,
+};
+
+static const struct omap2_mmc_platform_config omap4_mmc_pdata = {
+ .reg_offset = 0x100,
+};
+
static const struct udevice_id omap_hsmmc_ids[] = {
- { .compatible = "ti,omap3-hsmmc" },
- { .compatible = "ti,omap4-hsmmc" },
- { .compatible = "ti,am33xx-hsmmc" },
+ {
+ .compatible = "ti,omap3-hsmmc",
+ .data = (ulong)&omap3_mmc_pdata
+ },
+ {
+ .compatible = "ti,omap4-hsmmc",
+ .data = (ulong)&omap4_mmc_pdata
+ },
+ {
+ .compatible = "ti,am33xx-hsmmc",
+ .data = (ulong)&am33xx_mmc_pdata
+ },
{ }
};
+#endif
U_BOOT_DRIVER(omap_hsmmc) = {
.name = "omap_hsmmc",
.id = UCLASS_MMC,
+#if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)
.of_match = omap_hsmmc_ids,
.ofdata_to_platdata = omap_hsmmc_ofdata_to_platdata,
+ .platdata_auto_alloc_size = sizeof(struct omap_hsmmc_plat),
+#endif
#ifdef CONFIG_BLK
.bind = omap_hsmmc_bind,
#endif
+ .ops = &omap_hsmmc_ops,
.probe = omap_hsmmc_probe,
.priv_auto_alloc_size = sizeof(struct omap_hsmmc_data),
- .platdata_auto_alloc_size = sizeof(struct omap_hsmmc_plat),
+ .flags = DM_FLAG_PRE_RELOC,
};
#endif
diff --git a/drivers/mmc/pci_mmc.c b/drivers/mmc/pci_mmc.c
index e39b476834e..6db89779ba3 100644
--- a/drivers/mmc/pci_mmc.c
+++ b/drivers/mmc/pci_mmc.c
@@ -6,37 +6,71 @@
*/
#include <common.h>
+#include <dm.h>
#include <errno.h>
#include <malloc.h>
+#include <mapmem.h>
#include <sdhci.h>
#include <asm/pci.h>
-int pci_mmc_init(const char *name, struct pci_device_id *mmc_supported)
+struct pci_mmc_plat {
+ struct mmc_config cfg;
+ struct mmc mmc;
+};
+
+struct pci_mmc_priv {
+ struct sdhci_host host;
+ void *base;
+};
+
+static int pci_mmc_probe(struct udevice *dev)
{
- struct sdhci_host *mmc_host;
- u32 iobase;
+ struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
+ struct pci_mmc_plat *plat = dev_get_platdata(dev);
+ struct pci_mmc_priv *priv = dev_get_priv(dev);
+ struct sdhci_host *host = &priv->host;
+ u32 ioaddr;
int ret;
- int i;
-
- for (i = 0; ; i++) {
- struct udevice *dev;
-
- ret = pci_find_device_id(mmc_supported, i, &dev);
- if (ret)
- return ret;
- mmc_host = malloc(sizeof(struct sdhci_host));
- if (!mmc_host)
- return -ENOMEM;
-
- mmc_host->name = name;
- dm_pci_read_config32(dev, PCI_BASE_ADDRESS_0, &iobase);
- mmc_host->ioaddr = (void *)(ulong)iobase;
- mmc_host->quirks = 0;
- mmc_host->max_clk = 0;
- ret = add_sdhci(mmc_host, 0, 0);
- if (ret)
- return ret;
- }
-
- return 0;
+
+ dm_pci_read_config32(dev, PCI_BASE_ADDRESS_0, &ioaddr);
+ host->ioaddr = map_sysmem(ioaddr, 0);
+ host->name = dev->name;
+ ret = sdhci_setup_cfg(&plat->cfg, host, 0, 0);
+ if (ret)
+ return ret;
+ host->mmc = &plat->mmc;
+ host->mmc->priv = &priv->host;
+ host->mmc->dev = dev;
+ upriv->mmc = host->mmc;
+
+ return sdhci_probe(dev);
}
+
+static int pci_mmc_bind(struct udevice *dev)
+{
+ struct pci_mmc_plat *plat = dev_get_platdata(dev);
+
+ return sdhci_bind(dev, &plat->mmc, &plat->cfg);
+}
+
+U_BOOT_DRIVER(pci_mmc) = {
+ .name = "pci_mmc",
+ .id = UCLASS_MMC,
+ .bind = pci_mmc_bind,
+ .probe = pci_mmc_probe,
+ .ops = &sdhci_ops,
+ .priv_auto_alloc_size = sizeof(struct pci_mmc_priv),
+ .platdata_auto_alloc_size = sizeof(struct pci_mmc_plat),
+};
+
+static struct pci_device_id mmc_supported[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BYT_SDIO) },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BYT_SD) },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BYT_EMMC2) },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_QRK_SDIO) },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_TCF_SDIO_0) },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_TCF_SDIO_1) },
+ {},
+};
+
+U_BOOT_PCI_DEVICE(pci_mmc, mmc_supported);
diff --git a/drivers/mmc/rockchip_dw_mmc.c b/drivers/mmc/rockchip_dw_mmc.c
index c36eda05d20..2885ef24970 100644
--- a/drivers/mmc/rockchip_dw_mmc.c
+++ b/drivers/mmc/rockchip_dw_mmc.c
@@ -44,7 +44,7 @@ static uint rockchip_dwmmc_get_mmc_clk(struct dwmci_host *host, uint freq)
ret = clk_set_rate(&priv->clk, freq);
if (ret < 0) {
- debug("%s: err=%d\n", __func__, ret);
+ printf("%s: err=%d\n", __func__, ret);
return ret;
}
@@ -76,9 +76,25 @@ static int rockchip_dwmmc_ofdata_to_platdata(struct udevice *dev)
return -EINVAL;
priv->fifo_mode = fdtdec_get_bool(gd->fdt_blob, dev_of_offset(dev),
"fifo-mode");
+
+ /*
+ * 'clock-freq-min-max' is deprecated
+ * (see https://github.com/torvalds/linux/commit/b023030f10573de738bbe8df63d43acab64c9f7b)
+ */
if (fdtdec_get_int_array(gd->fdt_blob, dev_of_offset(dev),
- "clock-freq-min-max", priv->minmax, 2))
- return -EINVAL;
+ "clock-freq-min-max", priv->minmax, 2)) {
+ int val = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev),
+ "max-frequency", -EINVAL);
+
+ if (val < 0)
+ return val;
+
+ priv->minmax[0] = 400000; /* 400 kHz */
+ priv->minmax[1] = val;
+ } else {
+ debug("%s: 'clock-freq-min-max' property was deprecated.\n",
+ __func__);
+ }
#endif
return 0;
}
@@ -109,7 +125,7 @@ static int rockchip_dwmmc_probe(struct udevice *dev)
if (ret < 0)
return ret;
#else
- ret = clk_get_by_index(dev, 0, &priv->clk);
+ ret = clk_get_by_name(dev, "ciu", &priv->clk);
if (ret < 0)
return ret;
#endif
diff --git a/drivers/mmc/sdhci-cadence.c b/drivers/mmc/sdhci-cadence.c
index 2253bbc5183..dc86d108a69 100644
--- a/drivers/mmc/sdhci-cadence.c
+++ b/drivers/mmc/sdhci-cadence.c
@@ -7,8 +7,10 @@
#include <common.h>
#include <linux/io.h>
+#include <linux/iopoll.h>
#include <linux/sizes.h>
#include <dm/device.h>
+#include <libfdt.h>
#include <mmc.h>
#include <sdhci.h>
@@ -17,7 +19,7 @@
#define SDHCI_CDNS_HRS04_ACK BIT(26)
#define SDHCI_CDNS_HRS04_RD BIT(25)
#define SDHCI_CDNS_HRS04_WR BIT(24)
-#define SDHCI_CDNS_HRS04_RDATA_SHIFT 12
+#define SDHCI_CDNS_HRS04_RDATA_SHIFT 16
#define SDHCI_CDNS_HRS04_WDATA_SHIFT 8
#define SDHCI_CDNS_HRS04_ADDR_SHIFT 0
@@ -34,6 +36,9 @@
#define SDHCI_CDNS_PHY_DLY_EMMC_LEGACY 0x06
#define SDHCI_CDNS_PHY_DLY_EMMC_SDR 0x07
#define SDHCI_CDNS_PHY_DLY_EMMC_DDR 0x08
+#define SDHCI_CDNS_PHY_DLY_SDCLK 0x0b
+#define SDHCI_CDNS_PHY_DLY_HSMMC 0x0c
+#define SDHCI_CDNS_PHY_DLY_STROBE 0x0d
struct sdhci_cdns_plat {
struct mmc_config cfg;
@@ -41,11 +46,31 @@ struct sdhci_cdns_plat {
void __iomem *hrs_addr;
};
-static void sdhci_cdns_write_phy_reg(struct sdhci_cdns_plat *plat,
- u8 addr, u8 data)
+struct sdhci_cdns_phy_cfg {
+ const char *property;
+ u8 addr;
+};
+
+static const struct sdhci_cdns_phy_cfg sdhci_cdns_phy_cfgs[] = {
+ { "cdns,phy-input-delay-sd-highspeed", SDHCI_CDNS_PHY_DLY_SD_HS, },
+ { "cdns,phy-input-delay-legacy", SDHCI_CDNS_PHY_DLY_SD_DEFAULT, },
+ { "cdns,phy-input-delay-sd-uhs-sdr12", SDHCI_CDNS_PHY_DLY_UHS_SDR12, },
+ { "cdns,phy-input-delay-sd-uhs-sdr25", SDHCI_CDNS_PHY_DLY_UHS_SDR25, },
+ { "cdns,phy-input-delay-sd-uhs-sdr50", SDHCI_CDNS_PHY_DLY_UHS_SDR50, },
+ { "cdns,phy-input-delay-sd-uhs-ddr50", SDHCI_CDNS_PHY_DLY_UHS_DDR50, },
+ { "cdns,phy-input-delay-mmc-highspeed", SDHCI_CDNS_PHY_DLY_EMMC_SDR, },
+ { "cdns,phy-input-delay-mmc-ddr", SDHCI_CDNS_PHY_DLY_EMMC_DDR, },
+ { "cdns,phy-dll-delay-sdclk", SDHCI_CDNS_PHY_DLY_SDCLK, },
+ { "cdns,phy-dll-delay-sdclk-hsmmc", SDHCI_CDNS_PHY_DLY_HSMMC, },
+ { "cdns,phy-dll-delay-strobe", SDHCI_CDNS_PHY_DLY_STROBE, },
+};
+
+static int sdhci_cdns_write_phy_reg(struct sdhci_cdns_plat *plat,
+ u8 addr, u8 data)
{
void __iomem *reg = plat->hrs_addr + SDHCI_CDNS_HRS04;
u32 tmp;
+ int ret;
tmp = (data << SDHCI_CDNS_HRS04_WDATA_SHIFT) |
(addr << SDHCI_CDNS_HRS04_ADDR_SHIFT);
@@ -54,17 +79,36 @@ static void sdhci_cdns_write_phy_reg(struct sdhci_cdns_plat *plat,
tmp |= SDHCI_CDNS_HRS04_WR;
writel(tmp, reg);
+ ret = readl_poll_timeout(reg, tmp, tmp & SDHCI_CDNS_HRS04_ACK, 10);
+ if (ret)
+ return ret;
+
tmp &= ~SDHCI_CDNS_HRS04_WR;
writel(tmp, reg);
+
+ return 0;
}
-static void sdhci_cdns_phy_init(struct sdhci_cdns_plat *plat)
+static int sdhci_cdns_phy_init(struct sdhci_cdns_plat *plat,
+ const void *fdt, int nodeoffset)
{
- sdhci_cdns_write_phy_reg(plat, SDHCI_CDNS_PHY_DLY_SD_HS, 4);
- sdhci_cdns_write_phy_reg(plat, SDHCI_CDNS_PHY_DLY_SD_DEFAULT, 4);
- sdhci_cdns_write_phy_reg(plat, SDHCI_CDNS_PHY_DLY_EMMC_LEGACY, 9);
- sdhci_cdns_write_phy_reg(plat, SDHCI_CDNS_PHY_DLY_EMMC_SDR, 2);
- sdhci_cdns_write_phy_reg(plat, SDHCI_CDNS_PHY_DLY_EMMC_DDR, 3);
+ const u32 *prop;
+ int ret, i;
+
+ for (i = 0; i < ARRAY_SIZE(sdhci_cdns_phy_cfgs); i++) {
+ prop = fdt_getprop(fdt, nodeoffset,
+ sdhci_cdns_phy_cfgs[i].property, NULL);
+ if (!prop)
+ continue;
+
+ ret = sdhci_cdns_write_phy_reg(plat,
+ sdhci_cdns_phy_cfgs[i].addr,
+ fdt32_to_cpu(*prop));
+ if (ret)
+ return ret;
+ }
+
+ return 0;
}
static int sdhci_cdns_bind(struct udevice *dev)
@@ -76,6 +120,7 @@ static int sdhci_cdns_bind(struct udevice *dev)
static int sdhci_cdns_probe(struct udevice *dev)
{
+ DECLARE_GLOBAL_DATA_PTR;
struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
struct sdhci_cdns_plat *plat = dev_get_platdata(dev);
struct sdhci_host *host = dev_get_priv(dev);
@@ -94,7 +139,9 @@ static int sdhci_cdns_probe(struct udevice *dev)
host->ioaddr = plat->hrs_addr + SDHCI_CDNS_SRS_BASE;
host->quirks |= SDHCI_QUIRK_WAIT_SEND_CMD;
- sdhci_cdns_phy_init(plat);
+ ret = sdhci_cdns_phy_init(plat, gd->fdt_blob, dev->of_offset);
+ if (ret)
+ return ret;
ret = sdhci_setup_cfg(&plat->cfg, host, 0, 0);
if (ret)
diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c
index b745977b3fb..161a6b1399c 100644
--- a/drivers/mmc/sdhci.c
+++ b/drivers/mmc/sdhci.c
@@ -332,8 +332,7 @@ static int sdhci_set_clock(struct mmc *mmc, unsigned int clock)
*/
if (host->clk_mul) {
for (div = 1; div <= 1024; div++) {
- if ((host->max_clk * host->clk_mul / div)
- <= clock)
+ if ((host->max_clk / div) <= clock)
break;
}
@@ -547,6 +546,14 @@ int sdhci_setup_cfg(struct mmc_config *cfg, struct sdhci_host *host,
#ifndef CONFIG_DM_MMC_OPS
cfg->ops = &sdhci_ops;
#endif
+
+ /* Check whether the clock multiplier is supported or not */
+ if (SDHCI_GET_VERSION(host) >= SDHCI_SPEC_300) {
+ caps_1 = sdhci_readl(host, SDHCI_CAPABILITIES_1);
+ host->clk_mul = (caps_1 & SDHCI_CLOCK_MUL_MASK) >>
+ SDHCI_CLOCK_MUL_SHIFT;
+ }
+
if (host->max_clk == 0) {
if (SDHCI_GET_VERSION(host) >= SDHCI_SPEC_300)
host->max_clk = (caps & SDHCI_CLOCK_V3_BASE_MASK) >>
@@ -555,6 +562,8 @@ int sdhci_setup_cfg(struct mmc_config *cfg, struct sdhci_host *host,
host->max_clk = (caps & SDHCI_CLOCK_BASE_MASK) >>
SDHCI_CLOCK_BASE_SHIFT;
host->max_clk *= 1000000;
+ if (host->clk_mul)
+ host->max_clk *= host->clk_mul;
}
if (host->max_clk == 0) {
printf("%s: Hardware doesn't specify base clock frequency\n",
@@ -590,11 +599,6 @@ int sdhci_setup_cfg(struct mmc_config *cfg, struct sdhci_host *host,
if (SDHCI_GET_VERSION(host) >= SDHCI_SPEC_300) {
if (!(caps & SDHCI_CAN_DO_8BIT))
cfg->host_caps &= ~MMC_MODE_8BIT;
-
- /* Find out whether clock multiplier is supported */
- caps_1 = sdhci_readl(host, SDHCI_CAPABILITIES_1);
- host->clk_mul = (caps_1 & SDHCI_CLOCK_MUL_MASK) >>
- SDHCI_CLOCK_MUL_SHIFT;
}
if (host->host_caps)
diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c
index dfe8966b56b..0042a7ba11d 100644
--- a/drivers/mtd/nand/pxa3xx_nand.c
+++ b/drivers/mtd/nand/pxa3xx_nand.c
@@ -9,6 +9,7 @@
#include <common.h>
#include <malloc.h>
+#include <fdtdec.h>
#include <nand.h>
#include <linux/errno.h>
#include <asm/io.h>
@@ -19,6 +20,8 @@
#include "pxa3xx_nand.h"
+DECLARE_GLOBAL_DATA_PTR;
+
#define TIMEOUT_DRAIN_FIFO 5 /* in ms */
#define CHIP_DELAY_TIMEOUT 200
#define NAND_STOP_DELAY 40
@@ -1510,8 +1513,6 @@ static int alloc_nand_resource(struct pxa3xx_nand_info *info)
chip->cmdfunc = nand_cmdfunc;
}
- info->mmio_base = (void __iomem *)MVEBU_NAND_BASE;
-
/* Allocate a buffer to allow flash detection */
info->buf_size = INIT_BUFFER_SIZE;
info->data_buff = kmalloc(info->buf_size, GFP_KERNEL);
@@ -1533,17 +1534,62 @@ fail_disable_clk:
static int pxa3xx_nand_probe_dt(struct pxa3xx_nand_info *info)
{
struct pxa3xx_nand_platform_data *pdata;
+ const void *blob = gd->fdt_blob;
+ int node = -1;
pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
if (!pdata)
return -ENOMEM;
- pdata->enable_arbiter = 1;
- pdata->num_cs = 1;
+ /* Get address decoding nodes from the FDT blob */
+ do {
+ node = fdt_node_offset_by_compatible(blob, node,
+ "marvell,mvebu-pxa3xx-nand");
+ if (node < 0)
+ break;
+
+ /* Bypass disabeld nodes */
+ if (!fdtdec_get_is_enabled(blob, node))
+ continue;
- info->pdata = pdata;
+ /* Get the first enabled NAND controler base address */
+ info->mmio_base =
+ (void __iomem *)fdtdec_get_addr_size_auto_noparent(
+ blob, node, "reg", 0, NULL, true);
- return 0;
+ pdata->num_cs = fdtdec_get_int(blob, node, "num-cs", 1);
+ if (pdata->num_cs != 1) {
+ error("pxa3xx driver supports single CS only\n");
+ break;
+ }
+
+ if (fdtdec_get_bool(blob, node, "nand-enable-arbiter"))
+ pdata->enable_arbiter = 1;
+
+ if (fdtdec_get_bool(blob, node, "nand-keep-config"))
+ pdata->keep_config = 1;
+
+ /*
+ * ECC parameters.
+ * If these are not set, they will be selected according
+ * to the detected flash type.
+ */
+ /* ECC strength */
+ pdata->ecc_strength = fdtdec_get_int(blob, node,
+ "nand-ecc-strength", 0);
+
+ /* ECC step size */
+ pdata->ecc_step_size = fdtdec_get_int(blob, node,
+ "nand-ecc-step-size", 0);
+
+ info->pdata = pdata;
+
+ /* Currently support only a single NAND controller */
+ return 0;
+
+ } while (node >= 0);
+
+ return -EINVAL;
}
static int pxa3xx_nand_probe(struct pxa3xx_nand_info *info)
@@ -1603,8 +1649,8 @@ void board_nand_init(void)
int ret;
info = kzalloc(sizeof(*info) +
- sizeof(*host) * CONFIG_SYS_MAX_NAND_DEVICE,
- GFP_KERNEL);
+ sizeof(*host) * CONFIG_SYS_MAX_NAND_DEVICE,
+ GFP_KERNEL);
if (!info)
return;
diff --git a/drivers/net/eepro100.c b/drivers/net/eepro100.c
index 0f350cba53e..33d9fd6a57f 100644
--- a/drivers/net/eepro100.c
+++ b/drivers/net/eepro100.c
@@ -207,12 +207,6 @@ static int tx_threshold;
* There are so many options that it would be difficult to document
* each bit. We mostly use the default or recommended settings.
*/
-static const char i82557_config_cmd[] = {
- 22, 0x08, 0, 0, 0, 0, 0x32, 0x03, 1, /* 1=Use MII 0=Use AUI */
- 0, 0x2E, 0, 0x60, 0,
- 0xf2, 0x48, 0, 0x40, 0xf2, 0x80, /* 0x40=Force full-duplex */
- 0x3f, 0x05,
-};
static const char i82558_config_cmd[] = {
22, 0x08, 0, 1, 0, 0, 0x22, 0x03, 1, /* 1=Use MII 0=Use AUI */
0, 0x2E, 0, 0x60, 0x08, 0x88,
diff --git a/drivers/net/macb.c b/drivers/net/macb.c
index 402e8668174..21a620c244c 100644
--- a/drivers/net/macb.c
+++ b/drivers/net/macb.c
@@ -111,6 +111,9 @@ struct macb_device {
#endif
unsigned short phy_addr;
struct mii_dev *bus;
+#ifdef CONFIG_PHYLIB
+ struct phy_device *phydev;
+#endif
#ifdef CONFIG_DM_ETH
#ifdef CONFIG_CLK
@@ -479,9 +482,6 @@ static int macb_phy_init(struct macb_device *macb, const char *name)
#ifdef CONFIG_DM_ETH
struct macb_device *macb = dev_get_priv(dev);
#endif
-#ifdef CONFIG_PHYLIB
- struct phy_device *phydev;
-#endif
u32 ncfgr;
u16 phy_id, status, adv, lpa;
int media, speed, duplex;
@@ -503,19 +503,19 @@ static int macb_phy_init(struct macb_device *macb, const char *name)
#ifdef CONFIG_PHYLIB
#ifdef CONFIG_DM_ETH
- phydev = phy_connect(macb->bus, macb->phy_addr, dev,
+ macb->phydev = phy_connect(macb->bus, macb->phy_addr, dev,
macb->phy_interface);
#else
/* need to consider other phy interface mode */
- phydev = phy_connect(macb->bus, macb->phy_addr, &macb->netdev,
+ macb->phydev = phy_connect(macb->bus, macb->phy_addr, &macb->netdev,
PHY_INTERFACE_MODE_RGMII);
#endif
- if (!phydev) {
+ if (!macb->phydev) {
printf("phy_connect failed\n");
return -ENODEV;
}
- phy_config(phydev);
+ phy_config(macb->phydev);
#endif
status = macb_mdio_read(macb, MII_BMSR);
@@ -1035,6 +1035,7 @@ static int macb_eth_probe(struct udevice *dev)
struct eth_pdata *pdata = dev_get_platdata(dev);
struct macb_device *macb = dev_get_priv(dev);
const char *phy_mode;
+ __maybe_unused int ret;
phy_mode = fdt_getprop(gd->fdt_blob, dev_of_offset(dev), "phy-mode",
NULL);
@@ -1048,7 +1049,7 @@ static int macb_eth_probe(struct udevice *dev)
macb->regs = (void *)pdata->iobase;
#ifdef CONFIG_CLK
- int ret = macb_enable_clk(dev);
+ ret = macb_enable_clk(dev);
if (ret)
return ret;
#endif
@@ -1056,23 +1057,35 @@ static int macb_eth_probe(struct udevice *dev)
_macb_eth_initialize(macb);
#if defined(CONFIG_CMD_MII) || defined(CONFIG_PHYLIB)
- int retval;
- struct mii_dev *mdiodev = mdio_alloc();
- if (!mdiodev)
+ macb->bus = mdio_alloc();
+ if (!macb->bus)
return -ENOMEM;
- strncpy(mdiodev->name, dev->name, MDIO_NAME_LEN);
- mdiodev->read = macb_miiphy_read;
- mdiodev->write = macb_miiphy_write;
+ strncpy(macb->bus->name, dev->name, MDIO_NAME_LEN);
+ macb->bus->read = macb_miiphy_read;
+ macb->bus->write = macb_miiphy_write;
- retval = mdio_register(mdiodev);
- if (retval < 0)
- return retval;
+ ret = mdio_register(macb->bus);
+ if (ret < 0)
+ return ret;
macb->bus = miiphy_get_dev_by_name(dev->name);
#endif
return 0;
}
+static int macb_eth_remove(struct udevice *dev)
+{
+ struct macb_device *macb = dev_get_priv(dev);
+
+#ifdef CONFIG_PHYLIB
+ free(macb->phydev);
+#endif
+ mdio_unregister(macb->bus);
+ mdio_free(macb->bus);
+
+ return 0;
+}
+
static int macb_eth_ofdata_to_platdata(struct udevice *dev)
{
struct eth_pdata *pdata = dev_get_platdata(dev);
@@ -1083,6 +1096,10 @@ static int macb_eth_ofdata_to_platdata(struct udevice *dev)
static const struct udevice_id macb_eth_ids[] = {
{ .compatible = "cdns,macb" },
+ { .compatible = "cdns,at91sam9260-macb" },
+ { .compatible = "atmel,sama5d2-gem" },
+ { .compatible = "atmel,sama5d3-gem" },
+ { .compatible = "atmel,sama5d4-gem" },
{ }
};
@@ -1092,6 +1109,7 @@ U_BOOT_DRIVER(eth_macb) = {
.of_match = macb_eth_ids,
.ofdata_to_platdata = macb_eth_ofdata_to_platdata,
.probe = macb_eth_probe,
+ .remove = macb_eth_remove,
.ops = &macb_eth_ops,
.priv_auto_alloc_size = sizeof(struct macb_device),
.platdata_auto_alloc_size = sizeof(struct eth_pdata),
diff --git a/drivers/net/mvpp2.c b/drivers/net/mvpp2.c
index 8ffe6c84d43..08adb68aa53 100644
--- a/drivers/net/mvpp2.c
+++ b/drivers/net/mvpp2.c
@@ -2618,6 +2618,13 @@ static void mvpp2_bm_pool_bufsize_set(struct mvpp2 *priv,
static void mvpp2_bm_bufs_free(struct udevice *dev, struct mvpp2 *priv,
struct mvpp2_bm_pool *bm_pool)
{
+ int i;
+
+ for (i = 0; i < bm_pool->buf_num; i++) {
+ /* Allocate buffer back from the buffer manager */
+ mvpp2_read(priv, MVPP2_BM_PHY_ALLOC_REG(bm_pool->id));
+ }
+
bm_pool->buf_num = 0;
}
@@ -5501,6 +5508,21 @@ static int mvpp2_probe(struct udevice *dev)
return 0;
}
+/*
+ * Empty BM pool and stop its activity before the OS is started
+ */
+static int mvpp2_remove(struct udevice *dev)
+{
+ struct mvpp2_port *port = dev_get_priv(dev);
+ struct mvpp2 *priv = port->priv;
+ int i;
+
+ for (i = 0; i < MVPP2_BM_POOLS_NUM; i++)
+ mvpp2_bm_pool_destroy(dev, priv, &priv->bm_pools[i]);
+
+ return 0;
+}
+
static const struct eth_ops mvpp2_ops = {
.start = mvpp2_start,
.send = mvpp2_send,
@@ -5512,9 +5534,11 @@ static struct driver mvpp2_driver = {
.name = "mvpp2",
.id = UCLASS_ETH,
.probe = mvpp2_probe,
+ .remove = mvpp2_remove,
.ops = &mvpp2_ops,
.priv_auto_alloc_size = sizeof(struct mvpp2_port),
.platdata_auto_alloc_size = sizeof(struct eth_pdata),
+ .flags = DM_FLAG_ACTIVE_DMA,
};
/*
diff --git a/drivers/net/phy/mv88e61xx.c b/drivers/net/phy/mv88e61xx.c
index a2fd1686fc3..3d2f6b98ad0 100644
--- a/drivers/net/phy/mv88e61xx.c
+++ b/drivers/net/phy/mv88e61xx.c
@@ -655,8 +655,10 @@ static int mv88e61xx_read_port_config(struct phy_device *phydev, u8 port)
do {
val = mv88e61xx_port_read(phydev, port,
PORT_REG_STATUS);
- if (val < 0)
+ if (val < 0) {
+ res = -EIO;
goto unforce;
+ }
if (val & PORT_REG_STATUS_LINK)
break;
} while (--timeout);
diff --git a/drivers/net/uli526x.c b/drivers/net/uli526x.c
index 47cdb858c77..d05ae9ea0cf 100644
--- a/drivers/net/uli526x.c
+++ b/drivers/net/uli526x.c
@@ -166,7 +166,6 @@ static int mode = 8;
/* function declaration -- */
static int uli526x_start_xmit(struct eth_device *dev, void *packet, int length);
-static const struct ethtool_ops netdev_ethtool_ops;
static u16 read_srom_word(long, int);
static void uli526x_descriptor_init(struct uli526x_board_info *, unsigned long);
static void allocate_rx_buffer(struct uli526x_board_info *);
diff --git a/drivers/pci/pci-uclass.c b/drivers/pci/pci-uclass.c
index 40f59c0c4c4..504d7e3bb13 100644
--- a/drivers/pci/pci-uclass.c
+++ b/drivers/pci/pci-uclass.c
@@ -660,6 +660,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\n", __func__, ret);
+ free(str);
return ret;
}
debug("%s: No match found: bound generic driver instead\n", __func__);
diff --git a/drivers/pci/pci_rom.c b/drivers/pci/pci_rom.c
index 57204c4f3f1..75fb0933371 100644
--- a/drivers/pci/pci_rom.c
+++ b/drivers/pci/pci_rom.c
@@ -35,8 +35,22 @@
#include <video_fb.h>
#include <linux/screen_info.h>
+#ifdef CONFIG_X86
+#include <asm/acpi_s3.h>
+DECLARE_GLOBAL_DATA_PTR;
+#endif
+
__weak bool board_should_run_oprom(struct udevice *dev)
{
+#if defined(CONFIG_X86) && defined(CONFIG_HAVE_ACPI_RESUME)
+ if (gd->arch.prev_sleep_state == ACPI_S3) {
+ if (IS_ENABLED(CONFIG_S3_VGA_ROM_RUN))
+ return true;
+ else
+ return false;
+ }
+#endif
+
return true;
}
diff --git a/drivers/pci/pcie_dw_mvebu.c b/drivers/pci/pcie_dw_mvebu.c
index d4776a9c81e..05a06604e68 100644
--- a/drivers/pci/pcie_dw_mvebu.c
+++ b/drivers/pci/pcie_dw_mvebu.c
@@ -487,13 +487,13 @@ static int pcie_dw_mvebu_probe(struct udevice *dev)
/* Don't register host if link is down */
if (!pcie_dw_mvebu_pcie_link_up(pcie->ctrl_base, LINK_SPEED_GEN_3)) {
printf("PCIE-%d: Link down\n", dev->seq);
- return -ENODEV;
+ } else {
+ printf("PCIE-%d: Link up (Gen%d-x%d, Bus%d)\n", dev->seq,
+ pcie_dw_get_link_speed(pcie->ctrl_base),
+ pcie_dw_get_link_width(pcie->ctrl_base),
+ hose->first_busno);
}
- printf("PCIE-%d: Link up (Gen%d-x%d, Bus%d)\n", dev->seq,
- pcie_dw_get_link_speed(pcie->ctrl_base),
- pcie_dw_get_link_width(pcie->ctrl_base), hose->first_busno);
-
pcie_dw_regions_setup(pcie);
/* Set the CLASS_REV of RC CFG header to PCI_CLASS_BRIDGE_PCI */
diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
new file mode 100644
index 00000000000..a91a6946b89
--- /dev/null
+++ b/drivers/phy/Kconfig
@@ -0,0 +1,62 @@
+
+menu "PHY Subsystem"
+
+config PHY
+ bool "PHY Core"
+ depends on DM
+ help
+ PHY support.
+
+ This framework is designed to provide a generic interface for PHY
+ devices. PHY devices are dedicated hardware that handle the physical
+ layer of the protocols in the OSI model.
+ PHYs are commonly used for high speed interfaces such as Serial-ATA
+ or PCI express.
+ The API provides functions to initialize/deinitialize the
+ PHY, power on/off the PHY, and reset the PHY. It's meant to be as
+ compatible as possible with the equivalent framework found in the
+ linux kernel.
+
+config SPL_PHY
+ bool "PHY Core in SPL"
+ depends on DM
+ help
+ PHY support in SPL.
+
+ This framework is designed to provide a generic interface for PHY
+ devices. PHY devices are dedicated hardware that handle the physical
+ layer of the protocols (https://en.wikipedia.org/wiki/OSI_model).
+ PHYs are commonly used for high speed interfaces such as Serial-ATA
+ or PCI express.
+ The API provides functions to initialize/deinitialize the
+ PHY, power on/off the PHY, and reset the PHY. It's meant to be as
+ compatible as possible with the equivalent framework found in the
+ linux kernel.
+
+config PHY_SANDBOX
+ bool "Sandbox PHY support"
+ depends on SANDBOX
+ depends on PHY
+ help
+ This select a dummy sandbox PHY driver. It used only to implement
+ the unit tests for the phy framework
+
+config PIPE3_PHY
+ bool "Support omap's PIPE3 PHY"
+ depends on PHY && ARCH_OMAP2
+ help
+ Support for the omap PIPE3 phy for sata
+
+ This PHY is found on omap devices supporting SATA such as dra7, am57x
+ and omap5
+
+config SPL_PIPE3_PHY
+ bool "Support omap's PIPE3 PHY in SPL"
+ depends on SPL_PHY && ARCH_OMAP2
+ help
+ Support for the omap PIPE3 phy for sata in SPL
+
+ This PHY is found on omap devices supporting SATA such as dra7, am57x
+ and omap5
+
+endmenu
diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
new file mode 100644
index 00000000000..6ce96d2cccb
--- /dev/null
+++ b/drivers/phy/Makefile
@@ -0,0 +1,10 @@
+#
+# Copyright (C) 2017 Texas Instruments Incorporated - http://www.ti.com/
+# Written by Jean-Jacques Hiblot <jjhiblot@ti.com>
+#
+# SPDX-License-Identifier: GPL-2.0+
+#
+
+obj-$(CONFIG_$(SPL_)PHY) += phy-uclass.o
+obj-$(CONFIG_PHY_SANDBOX) += sandbox-phy.o
+obj-$(CONFIG_$(SPL_)PIPE3_PHY) += ti-pipe3-phy.o
diff --git a/drivers/phy/marvell/comphy.h b/drivers/phy/marvell/comphy.h
index 0a156925794..c9b94a4c5e3 100644
--- a/drivers/phy/marvell/comphy.h
+++ b/drivers/phy/marvell/comphy.h
@@ -86,6 +86,7 @@ struct comphy_map {
u32 speed;
u32 invert;
bool clk_src;
+ bool end_point;
};
struct chip_serdes_phy_config {
@@ -96,7 +97,7 @@ struct chip_serdes_phy_config {
void __iomem *hpipe3_base_addr;
u32 comphy_lanes_count;
u32 comphy_mux_bitcount;
- u32 comphy_index;
+ u32 cp_index;
};
/* Register helper functions */
diff --git a/drivers/phy/marvell/comphy_core.c b/drivers/phy/marvell/comphy_core.c
index caa1928f07d..596921b6c33 100644
--- a/drivers/phy/marvell/comphy_core.c
+++ b/drivers/phy/marvell/comphy_core.c
@@ -37,7 +37,7 @@ static char *get_type_string(u32 type)
"SGMII1", "SGMII2", "SGMII3", "QSGMII",
"USB3_HOST0", "USB3_HOST1", "USB3_DEVICE",
"XAUI0", "XAUI1", "XAUI2", "XAUI3",
- "RXAUI0", "RXAUI1", "KR"};
+ "RXAUI0", "RXAUI1", "SFI", "IGNORE"};
if (type < 0 || type > PHY_TYPE_MAX)
return "invalid";
@@ -90,9 +90,6 @@ void comphy_print(struct chip_serdes_phy_config *chip_cfg,
for (lane = 0; lane < chip_cfg->comphy_lanes_count;
lane++, comphy_map_data++) {
- if (comphy_map_data->type == PHY_TYPE_UNCONNECTED)
- continue;
-
if (comphy_map_data->speed == PHY_SPEED_INVALID) {
printf("Comphy-%d: %-13s\n", lane,
get_type_string(comphy_map_data->type));
@@ -113,6 +110,7 @@ static int comphy_probe(struct udevice *dev)
int subnode;
int lane;
int last_idx = 0;
+ static int current_idx;
/* Save base addresses for later use */
chip_cfg->comphy_base_addr = (void *)dev_get_addr_index(dev, 0);
@@ -166,6 +164,8 @@ static int comphy_probe(struct udevice *dev)
blob, subnode, "phy-invert", PHY_POLARITY_NO_INVERT);
comphy_map_data[lane].clk_src = fdtdec_get_bool(blob, subnode,
"clk-src");
+ comphy_map_data[lane].end_point = fdtdec_get_bool(blob, subnode,
+ "end_point");
if (comphy_map_data[lane].type == PHY_TYPE_INVALID) {
printf("no phy type for lane %d, setting lane as unconnected\n",
lane + 1);
@@ -174,13 +174,13 @@ static int comphy_probe(struct udevice *dev)
lane++;
}
- /* Save comphy index for MultiCP devices (A8K) */
- chip_cfg->comphy_index = dev->seq;
+ /* Save CP index for MultiCP devices (A8K) */
+ chip_cfg->cp_index = current_idx++;
/* PHY power UP sequence */
chip_cfg->ptr_comphy_chip_init(chip_cfg, comphy_map_data);
/* PHY print SerDes status */
if (of_machine_is_compatible("marvell,armada8040"))
- printf("Comphy chip #%d:\n", chip_cfg->comphy_index);
+ printf("Comphy chip #%d:\n", chip_cfg->cp_index);
comphy_print(chip_cfg, comphy_map_data);
/*
@@ -189,7 +189,7 @@ static int comphy_probe(struct udevice *dev)
if (of_machine_is_compatible("marvell,armada8040"))
last_idx = 1;
- if (chip_cfg->comphy_index == last_idx) {
+ if (chip_cfg->cp_index == last_idx) {
/* Initialize dedicated PHYs (not muxed SerDes lanes) */
comphy_dedicated_phys_init();
}
diff --git a/drivers/phy/marvell/comphy_cp110.c b/drivers/phy/marvell/comphy_cp110.c
index 25c067d23fa..3ac405a9be6 100644
--- a/drivers/phy/marvell/comphy_cp110.c
+++ b/drivers/phy/marvell/comphy_cp110.c
@@ -34,26 +34,23 @@ struct utmi_phy_data {
* PIPE selector include USB and PCIe options.
* PHY selector include the Ethernet and SATA options, every Ethernet
* option has different options, for example: serdes lane2 had option
- * Eth_port_0 that include (SGMII0, XAUI0, RXAUI0, KR)
+ * Eth_port_0 that include (SGMII0, RXAUI0, SFI)
*/
struct comphy_mux_data cp110_comphy_phy_mux_data[] = {
- {4, {{PHY_TYPE_UNCONNECTED, 0x0}, {PHY_TYPE_SGMII2, 0x1}, /* Lane 0 */
- {PHY_TYPE_XAUI2, 0x1}, {PHY_TYPE_SATA1, 0x4} } },
- {4, {{PHY_TYPE_UNCONNECTED, 0x0}, {PHY_TYPE_SGMII3, 0x1}, /* Lane 1 */
- {PHY_TYPE_XAUI3, 0x1}, {PHY_TYPE_SATA0, 0x4} } },
+ {4, {{PHY_TYPE_UNCONNECTED, 0x0}, {PHY_TYPE_SGMII1, 0x1}, /* Lane 0 */
+ {PHY_TYPE_SATA1, 0x4} } },
+ {4, {{PHY_TYPE_UNCONNECTED, 0x0}, {PHY_TYPE_SGMII2, 0x1}, /* Lane 1 */
+ {PHY_TYPE_SATA0, 0x4} } },
{6, {{PHY_TYPE_UNCONNECTED, 0x0}, {PHY_TYPE_SGMII0, 0x1}, /* Lane 2 */
- {PHY_TYPE_XAUI0, 0x1}, {PHY_TYPE_RXAUI0, 0x1},
- {PHY_TYPE_KR, 0x1}, {PHY_TYPE_SATA0, 0x4} } },
- {8, {{PHY_TYPE_UNCONNECTED, 0x0}, {PHY_TYPE_SGMII0, 0x1}, /* Lane 3 */
- {PHY_TYPE_XAUI0, 0x1}, {PHY_TYPE_RXAUI0, 0x1},
- {PHY_TYPE_KR, 0x1}, {PHY_TYPE_XAUI1, 0x1},
- {PHY_TYPE_RXAUI1, 0x1}, {PHY_TYPE_SATA1, 0x4} } },
+ {PHY_TYPE_RXAUI0, 0x1}, {PHY_TYPE_SFI, 0x1},
+ {PHY_TYPE_SATA0, 0x4} } },
+ {8, {{PHY_TYPE_UNCONNECTED, 0x0}, {PHY_TYPE_RXAUI1, 0x1}, /* Lane 3 */
+ {PHY_TYPE_SGMII1, 0x2}, {PHY_TYPE_SATA1, 0x4} } },
{7, {{PHY_TYPE_UNCONNECTED, 0x0}, {PHY_TYPE_SGMII0, 0x2}, /* Lane 4 */
- {PHY_TYPE_XAUI0, 0x1}, {PHY_TYPE_RXAUI0, 0x1}, {PHY_TYPE_KR, 0x1},
- {PHY_TYPE_SGMII2, 0x1}, {PHY_TYPE_XAUI2, 0x1} } },
- {6, {{PHY_TYPE_UNCONNECTED, 0x0}, {PHY_TYPE_XAUI1, 0x1}, /* Lane 5 */
- {PHY_TYPE_RXAUI1, 0x1}, {PHY_TYPE_SGMII3, 0x1},
- {PHY_TYPE_XAUI3, 0x1}, {PHY_TYPE_SATA1, 0x4} } },
+ {PHY_TYPE_RXAUI0, 0x2}, {PHY_TYPE_SFI, 0x2},
+ {PHY_TYPE_SGMII1, 0x1} } },
+ {6, {{PHY_TYPE_UNCONNECTED, 0x0}, {PHY_TYPE_SGMII2, 0x1}, /* Lane 5 */
+ {PHY_TYPE_RXAUI1, 0x2}, {PHY_TYPE_SATA1, 0x4} } },
};
struct comphy_mux_data cp110_comphy_pipe_mux_data[] = {
@@ -87,8 +84,8 @@ static u32 polling_with_timeout(void __iomem *addr, u32 val,
return 0;
}
-static int comphy_pcie_power_up(u32 lane, u32 pcie_width,
- bool clk_src, void __iomem *hpipe_base,
+static int comphy_pcie_power_up(u32 lane, u32 pcie_width, bool clk_src,
+ bool is_end_point, void __iomem *hpipe_base,
void __iomem *comphy_base)
{
u32 mask, data, ret = 1;
@@ -109,6 +106,7 @@ static int comphy_pcie_power_up(u32 lane, u32 pcie_width,
* and SerDes Lane 0 got PCIe ref-clock #0
*/
debug("PCIe clock = %x\n", pcie_clk);
+ debug("PCIe RC = %d\n", !is_end_point);
debug("PCIe width = %d\n", pcie_width);
/* enable PCIe by4 and by2 */
@@ -234,6 +232,8 @@ static int comphy_pcie_power_up(u32 lane, u32 pcie_width,
mask |= HPIPE_MISC_REFCLK_SEL_MASK;
data |= 0x1 << HPIPE_MISC_REFCLK_SEL_OFFSET;
}
+ mask |= HPIPE_MISC_ICP_FORCE_MASK;
+ data |= 0x1 << HPIPE_MISC_ICP_FORCE_OFFSET;
reg_set(hpipe_addr + HPIPE_MISC_REG, data, mask);
if (pcie_clk) { /* output */
/* Set reference frequcency select - 0x2 for 25MHz*/
@@ -269,6 +269,9 @@ static int comphy_pcie_power_up(u32 lane, u32 pcie_width,
/* Set Maximal PHY Generation Setting(8Gbps) */
mask = HPIPE_INTERFACE_GEN_MAX_MASK;
data = 0x2 << HPIPE_INTERFACE_GEN_MAX_OFFSET;
+ /* Bypass frame detection and sync detection for RX DATA */
+ mask = HPIPE_INTERFACE_DET_BYPASS_MASK;
+ data = 0x1 << HPIPE_INTERFACE_DET_BYPASS_OFFSET;
/* Set Link Train Mode (Tx training control pins are used) */
mask |= HPIPE_INTERFACE_LINK_TRAIN_MASK;
data |= 0x1 << HPIPE_INTERFACE_LINK_TRAIN_OFFSET;
@@ -353,21 +356,21 @@ static int comphy_pcie_power_up(u32 lane, u32 pcie_width,
data = 0x3 << HPIPE_G3_DFE_RES_OFFSET;
reg_set(hpipe_addr + HPIPE_G3_SETTING_4_REG, data, mask);
- /* Force DFE resolution (use GEN table value) */
+ /* Use TX/RX training result for DFE */
mask = HPIPE_DFE_RES_FORCE_MASK;
- data = 0x1 << HPIPE_DFE_RES_FORCE_OFFSET;
+ data = 0x0 << HPIPE_DFE_RES_FORCE_OFFSET;
reg_set(hpipe_addr + HPIPE_DFE_REG0, data, mask);
/* Configure initial and final coefficient value for receiver */
- mask = HPIPE_G3_RX_SELMUPI_MASK;
- data = 0x1 << HPIPE_G3_RX_SELMUPI_OFFSET;
+ mask = HPIPE_G3_SET_1_G3_RX_SELMUPI_MASK;
+ data = 0x1 << HPIPE_G3_SET_1_G3_RX_SELMUPI_OFFSET;
- mask |= HPIPE_G3_RX_SELMUPF_MASK;
- data |= 0x1 << HPIPE_G3_RX_SELMUPF_OFFSET;
+ mask |= HPIPE_G3_SET_1_G3_RX_SELMUPF_MASK;
+ data |= 0x1 << HPIPE_G3_SET_1_G3_RX_SELMUPF_OFFSET;
- mask |= HPIPE_G3_SETTING_BIT_MASK;
- data |= 0x0 << HPIPE_G3_SETTING_BIT_OFFSET;
- reg_set(hpipe_addr + HPIPE_G3_SETTINGS_1_REG, data, mask);
+ mask |= HPIPE_G3_SET_1_G3_SAMPLER_INPAIRX2_EN_MASK;
+ data |= 0x0 << HPIPE_G3_SET_1_G3_SAMPLER_INPAIRX2_EN_OFFSET;
+ reg_set(hpipe_addr + HPIPE_G3_SET_1_REG, data, mask);
/* Trigger sampler enable pulse */
mask = HPIPE_SMAPLER_MASK;
@@ -381,13 +384,70 @@ static int comphy_pcie_power_up(u32 lane, u32 pcie_width,
data = 0x1 << HPIPE_G3_FFE_DEG_RES_LEVEL_OFFSET;
mask |= HPIPE_G3_FFE_LOAD_RES_LEVEL_MASK;
- data |= 0x1 << HPIPE_G3_FFE_LOAD_RES_LEVEL_OFFSET;
+ data |= 0x3 << HPIPE_G3_FFE_LOAD_RES_LEVEL_OFFSET;
reg_set(hpipe_addr + HPIPE_G3_SETTING_3_REG, data, mask);
- /* Set phy in root complex mode */
- mask = HPIPE_CFG_PHY_RC_EP_MASK;
- data = 0x1 << HPIPE_CFG_PHY_RC_EP_OFFSET;
- reg_set(hpipe_addr + HPIPE_LANE_EQU_CONFIG_0_REG, data, mask);
+ /* Pattern lock lost timeout disable */
+ mask = HPIPE_PATTERN_LOCK_LOST_TIMEOUT_EN_MASK;
+ data = 0x0 << HPIPE_PATTERN_LOCK_LOST_TIMEOUT_EN_OFFSET;
+ reg_set(hpipe_addr + HPIPE_FRAME_DETECT_CTRL_3_REG, data, mask);
+
+ /* Configure DFE adaptations */
+ mask = HPIPE_CDR_MAX_DFE_ADAPT_1_MASK;
+ data = 0x1 << HPIPE_CDR_MAX_DFE_ADAPT_1_OFFSET;
+ mask |= HPIPE_CDR_MAX_DFE_ADAPT_0_MASK;
+ data |= 0x0 << HPIPE_CDR_MAX_DFE_ADAPT_0_OFFSET;
+ mask |= HPIPE_CDR_RX_MAX_DFE_ADAPT_1_MASK;
+ data |= 0x0 << HPIPE_CDR_RX_MAX_DFE_ADAPT_1_OFFSET;
+ reg_set(hpipe_addr + HPIPE_CDR_CONTROL_REG, data, mask);
+ mask = HPIPE_DFE_TX_MAX_DFE_ADAPT_MASK;
+ data = 0x0 << HPIPE_DFE_TX_MAX_DFE_ADAPT_OFFSET;
+ reg_set(hpipe_addr + HPIPE_DFE_CONTROL_REG, data, mask);
+
+ /* Genration 2 setting 1*/
+ mask = HPIPE_G2_SET_1_G2_RX_SELMUPI_MASK;
+ data = 0x0 << HPIPE_G2_SET_1_G2_RX_SELMUPI_OFFSET;
+ mask |= HPIPE_G2_SET_1_G2_RX_SELMUPP_MASK;
+ data |= 0x1 << HPIPE_G2_SET_1_G2_RX_SELMUPP_OFFSET;
+ mask |= HPIPE_G2_SET_1_G2_RX_SELMUFI_MASK;
+ data |= 0x0 << HPIPE_G2_SET_1_G2_RX_SELMUFI_OFFSET;
+ reg_set(hpipe_addr + HPIPE_G2_SET_1_REG, data, mask);
+
+ /* DFE enable */
+ mask = HPIPE_G2_DFE_RES_MASK;
+ data = 0x3 << HPIPE_G2_DFE_RES_OFFSET;
+ reg_set(hpipe_addr + HPIPE_G2_SETTINGS_4_REG, data, mask);
+
+ /* Configure DFE Resolution */
+ mask = HPIPE_LANE_CFG4_DFE_EN_SEL_MASK;
+ data = 0x1 << HPIPE_LANE_CFG4_DFE_EN_SEL_OFFSET;
+ reg_set(hpipe_addr + HPIPE_LANE_CFG4_REG, data, mask);
+
+ /* VDD calibration control */
+ mask = HPIPE_EXT_SELLV_RXSAMPL_MASK;
+ data = 0x16 << HPIPE_EXT_SELLV_RXSAMPL_OFFSET;
+ reg_set(hpipe_addr + HPIPE_VDD_CAL_CTRL_REG, data, mask);
+
+ /* Set PLL Charge-pump Current Control */
+ mask = HPIPE_G3_SETTING_5_G3_ICP_MASK;
+ data = 0x4 << HPIPE_G3_SETTING_5_G3_ICP_OFFSET;
+ reg_set(hpipe_addr + HPIPE_G3_SETTING_5_REG, data, mask);
+
+ /* Set lane rqualization remote setting */
+ mask = HPIPE_LANE_CFG_FOM_DIRN_OVERRIDE_MASK;
+ data = 0x1 << HPIPE_LANE_CFG_FOM_DIRN_OVERRIDE_OFFSET;
+ mask |= HPIPE_LANE_CFG_FOM_ONLY_MODE_MASK;
+ data |= 0x1 << HPIPE_LANE_CFG_FOM_ONLY_MODE_OFFFSET;
+ mask |= HPIPE_LANE_CFG_FOM_PRESET_VECTOR_MASK;
+ data |= 0x2 << HPIPE_LANE_CFG_FOM_PRESET_VECTOR_OFFSET;
+ reg_set(hpipe_addr + HPIPE_LANE_EQ_REMOTE_SETTING_REG, data, mask);
+
+ if (!is_end_point) {
+ /* Set phy in root complex mode */
+ mask = HPIPE_CFG_PHY_RC_EP_MASK;
+ data = 0x1 << HPIPE_CFG_PHY_RC_EP_OFFSET;
+ reg_set(hpipe_addr + HPIPE_LANE_EQU_CONFIG_0_REG, data, mask);
+ }
debug("stage: Comphy power up\n");
@@ -582,7 +642,7 @@ static int comphy_usb3_power_up(u32 lane, void __iomem *hpipe_base,
}
static int comphy_sata_power_up(u32 lane, void __iomem *hpipe_base,
- void __iomem *comphy_base, int comphy_index)
+ void __iomem *comphy_base, int cp_index)
{
u32 mask, data, i, ret = 1;
void __iomem *hpipe_addr = HPIPE_ADDR(hpipe_base, lane);
@@ -601,7 +661,7 @@ static int comphy_sata_power_up(u32 lane, void __iomem *hpipe_base,
* In order to parse each CPs SATA node, fdt_node_offset_by_compatible
* must be called again (according to the CP id)
*/
- for (i = 0; i < (comphy_index + 1); i++)
+ for (i = 0; i < (cp_index + 1); i++)
sata_node = fdt_node_offset_by_compatible(
gd->fdt_blob, sata_node, "marvell,armada-8k-ahci");
@@ -690,10 +750,176 @@ static int comphy_sata_power_up(u32 lane, void __iomem *hpipe_base,
0x2 << HPIPE_LOOPBACK_SEL_OFFSET, HPIPE_LOOPBACK_SEL_MASK);
debug("stage: Analog paramters from ETP(HW)\n");
- /*
- * TODO: Set analog paramters from ETP(HW) - for now use the
- * default datas
- */
+ /* Set analog parameters from ETP(HW) */
+ /* G1 settings */
+ mask = HPIPE_G1_SET_1_G1_RX_SELMUPI_MASK;
+ data = 0x0 << HPIPE_G1_SET_1_G1_RX_SELMUPI_OFFSET;
+ mask |= HPIPE_G1_SET_1_G1_RX_SELMUPP_MASK;
+ data |= 0x1 << HPIPE_G1_SET_1_G1_RX_SELMUPP_OFFSET;
+ mask |= HPIPE_G1_SET_1_G1_RX_SELMUFI_MASK;
+ data |= 0x0 << HPIPE_G1_SET_1_G1_RX_SELMUFI_OFFSET;
+ mask |= HPIPE_G1_SET_1_G1_RX_SELMUFF_MASK;
+ data |= 0x3 << HPIPE_G1_SET_1_G1_RX_SELMUFF_OFFSET;
+ mask |= HPIPE_G1_SET_1_G1_RX_DIGCK_DIV_MASK;
+ data |= 0x1 << HPIPE_G1_SET_1_G1_RX_DIGCK_DIV_OFFSET;
+ reg_set(hpipe_addr + HPIPE_G1_SET_1_REG, data, mask);
+
+ mask = HPIPE_G1_SETTINGS_3_G1_FFE_CAP_SEL_MASK;
+ data = 0xf << HPIPE_G1_SETTINGS_3_G1_FFE_CAP_SEL_OFFSET;
+ mask |= HPIPE_G1_SETTINGS_3_G1_FFE_RES_SEL_MASK;
+ data |= 0x2 << HPIPE_G1_SETTINGS_3_G1_FFE_RES_SEL_OFFSET;
+ mask |= HPIPE_G1_SETTINGS_3_G1_FFE_SETTING_FORCE_MASK;
+ data |= 0x1 << HPIPE_G1_SETTINGS_3_G1_FFE_SETTING_FORCE_OFFSET;
+ mask |= HPIPE_G1_SETTINGS_3_G1_FFE_DEG_RES_LEVEL_MASK;
+ data |= 0x1 << HPIPE_G1_SETTINGS_3_G1_FFE_DEG_RES_LEVEL_OFFSET;
+ mask |= HPIPE_G1_SETTINGS_3_G1_FFE_LOAD_RES_LEVEL_MASK;
+ data |= 0x1 << HPIPE_G1_SETTINGS_3_G1_FFE_LOAD_RES_LEVEL_OFFSET;
+ reg_set(hpipe_addr + HPIPE_G1_SETTINGS_3_REG, data, mask);
+
+ /* G2 settings */
+ mask = HPIPE_G2_SET_1_G2_RX_SELMUPI_MASK;
+ data = 0x0 << HPIPE_G2_SET_1_G2_RX_SELMUPI_OFFSET;
+ mask |= HPIPE_G2_SET_1_G2_RX_SELMUPP_MASK;
+ data |= 0x1 << HPIPE_G2_SET_1_G2_RX_SELMUPP_OFFSET;
+ mask |= HPIPE_G2_SET_1_G2_RX_SELMUFI_MASK;
+ data |= 0x0 << HPIPE_G2_SET_1_G2_RX_SELMUFI_OFFSET;
+ mask |= HPIPE_G2_SET_1_G2_RX_SELMUFF_MASK;
+ data |= 0x3 << HPIPE_G2_SET_1_G2_RX_SELMUFF_OFFSET;
+ mask |= HPIPE_G2_SET_1_G2_RX_DIGCK_DIV_MASK;
+ data |= 0x1 << HPIPE_G2_SET_1_G2_RX_DIGCK_DIV_OFFSET;
+ reg_set(hpipe_addr + HPIPE_G2_SET_1_REG, data, mask);
+
+ /* G3 settings */
+ mask = HPIPE_G3_SET_1_G3_RX_SELMUPI_MASK;
+ data = 0x2 << HPIPE_G3_SET_1_G3_RX_SELMUPI_OFFSET;
+ mask |= HPIPE_G3_SET_1_G3_RX_SELMUPF_MASK;
+ data |= 0x2 << HPIPE_G3_SET_1_G3_RX_SELMUPF_OFFSET;
+ mask |= HPIPE_G3_SET_1_G3_RX_SELMUFI_MASK;
+ data |= 0x3 << HPIPE_G3_SET_1_G3_RX_SELMUFI_OFFSET;
+ mask |= HPIPE_G3_SET_1_G3_RX_SELMUFF_MASK;
+ data |= 0x3 << HPIPE_G3_SET_1_G3_RX_SELMUFF_OFFSET;
+ mask |= HPIPE_G3_SET_1_G3_RX_DFE_EN_MASK;
+ data |= 0x1 << HPIPE_G3_SET_1_G3_RX_DFE_EN_OFFSET;
+ mask |= HPIPE_G3_SET_1_G3_RX_DIGCK_DIV_MASK;
+ data |= 0x2 << HPIPE_G3_SET_1_G3_RX_DIGCK_DIV_OFFSET;
+ mask |= HPIPE_G3_SET_1_G3_SAMPLER_INPAIRX2_EN_MASK;
+ data |= 0x0 << HPIPE_G3_SET_1_G3_SAMPLER_INPAIRX2_EN_OFFSET;
+ reg_set(hpipe_addr + HPIPE_G3_SET_1_REG, data, mask);
+
+ /* DTL Control */
+ mask = HPIPE_PWR_CTR_DTL_SQ_DET_EN_MASK;
+ data = 0x1 << HPIPE_PWR_CTR_DTL_SQ_DET_EN_OFFSET;
+ mask |= HPIPE_PWR_CTR_DTL_SQ_PLOOP_EN_MASK;
+ data |= 0x1 << HPIPE_PWR_CTR_DTL_SQ_PLOOP_EN_OFFSET;
+ mask |= HPIPE_PWR_CTR_DTL_FLOOP_EN_MASK;
+ data |= 0x1 << HPIPE_PWR_CTR_DTL_FLOOP_EN_OFFSET;
+ mask |= HPIPE_PWR_CTR_DTL_CLAMPING_SEL_MASK;
+ data |= 0x1 << HPIPE_PWR_CTR_DTL_CLAMPING_SEL_OFFSET;
+ mask |= HPIPE_PWR_CTR_DTL_INTPCLK_DIV_FORCE_MASK;
+ data |= 0x1 << HPIPE_PWR_CTR_DTL_INTPCLK_DIV_FORCE_OFFSET;
+ mask |= HPIPE_PWR_CTR_DTL_CLK_MODE_MASK;
+ data |= 0x1 << HPIPE_PWR_CTR_DTL_CLK_MODE_OFFSET;
+ mask |= HPIPE_PWR_CTR_DTL_CLK_MODE_FORCE_MASK;
+ data |= 0x1 << HPIPE_PWR_CTR_DTL_CLK_MODE_FORCE_OFFSET;
+ reg_set(hpipe_addr + HPIPE_PWR_CTR_DTL_REG, data, mask);
+
+ /* Trigger sampler enable pulse (by toggleing the bit) */
+ mask = HPIPE_SMAPLER_MASK;
+ data = 0x1 << HPIPE_SMAPLER_OFFSET;
+ reg_set(hpipe_addr + HPIPE_SAMPLER_N_PROC_CALIB_CTRL_REG, data, mask);
+ mask = HPIPE_SMAPLER_MASK;
+ data = 0x0 << HPIPE_SMAPLER_OFFSET;
+ reg_set(hpipe_addr + HPIPE_SAMPLER_N_PROC_CALIB_CTRL_REG, data, mask);
+
+ /* VDD Calibration Control 3 */
+ mask = HPIPE_EXT_SELLV_RXSAMPL_MASK;
+ data = 0x10 << HPIPE_EXT_SELLV_RXSAMPL_OFFSET;
+ reg_set(hpipe_addr + HPIPE_VDD_CAL_CTRL_REG, data, mask);
+
+ /* DFE Resolution Control */
+ mask = HPIPE_DFE_RES_FORCE_MASK;
+ data = 0x1 << HPIPE_DFE_RES_FORCE_OFFSET;
+ reg_set(hpipe_addr + HPIPE_DFE_REG0, data, mask);
+
+ /* DFE F3-F5 Coefficient Control */
+ mask = HPIPE_DFE_F3_F5_DFE_EN_MASK;
+ data = 0x0 << HPIPE_DFE_F3_F5_DFE_EN_OFFSET;
+ mask |= HPIPE_DFE_F3_F5_DFE_CTRL_MASK;
+ data = 0x0 << HPIPE_DFE_F3_F5_DFE_CTRL_OFFSET;
+ reg_set(hpipe_addr + HPIPE_DFE_F3_F5_REG, data, mask);
+
+ /* G3 Setting 3 */
+ mask = HPIPE_G3_FFE_CAP_SEL_MASK;
+ data = 0xf << HPIPE_G3_FFE_CAP_SEL_OFFSET;
+ mask |= HPIPE_G3_FFE_RES_SEL_MASK;
+ data |= 0x4 << HPIPE_G3_FFE_RES_SEL_OFFSET;
+ mask |= HPIPE_G3_FFE_SETTING_FORCE_MASK;
+ data |= 0x1 << HPIPE_G3_FFE_SETTING_FORCE_OFFSET;
+ mask |= HPIPE_G3_FFE_DEG_RES_LEVEL_MASK;
+ data |= 0x1 << HPIPE_G3_FFE_DEG_RES_LEVEL_OFFSET;
+ mask |= HPIPE_G3_FFE_LOAD_RES_LEVEL_MASK;
+ data |= 0x3 << HPIPE_G3_FFE_LOAD_RES_LEVEL_OFFSET;
+ reg_set(hpipe_addr + HPIPE_G3_SETTING_3_REG, data, mask);
+
+ /* G3 Setting 4 */
+ mask = HPIPE_G3_DFE_RES_MASK;
+ data = 0x2 << HPIPE_G3_DFE_RES_OFFSET;
+ reg_set(hpipe_addr + HPIPE_G3_SETTING_4_REG, data, mask);
+
+ /* Offset Phase Control */
+ mask = HPIPE_OS_PH_OFFSET_MASK;
+ data = 0x5c << HPIPE_OS_PH_OFFSET_OFFSET;
+ mask |= HPIPE_OS_PH_OFFSET_FORCE_MASK;
+ data |= 0x1 << HPIPE_OS_PH_OFFSET_FORCE_OFFSET;
+ reg_set(hpipe_addr + HPIPE_PHASE_CONTROL_REG, data, mask);
+ mask = HPIPE_OS_PH_VALID_MASK;
+ data = 0x1 << HPIPE_OS_PH_VALID_OFFSET;
+ reg_set(hpipe_addr + HPIPE_PHASE_CONTROL_REG, data, mask);
+ mask = HPIPE_OS_PH_VALID_MASK;
+ data = 0x0 << HPIPE_OS_PH_VALID_OFFSET;
+ reg_set(hpipe_addr + HPIPE_PHASE_CONTROL_REG, data, mask);
+
+ /* Set G1 TX amplitude and TX post emphasis value */
+ mask = HPIPE_G1_SET_0_G1_TX_AMP_MASK;
+ data = 0x8 << HPIPE_G1_SET_0_G1_TX_AMP_OFFSET;
+ mask |= HPIPE_G1_SET_0_G1_TX_AMP_ADJ_MASK;
+ data |= 0x1 << HPIPE_G1_SET_0_G1_TX_AMP_ADJ_OFFSET;
+ mask |= HPIPE_G1_SET_0_G1_TX_EMPH1_MASK;
+ data |= 0x1 << HPIPE_G1_SET_0_G1_TX_EMPH1_OFFSET;
+ mask |= HPIPE_G1_SET_0_G1_TX_EMPH1_EN_MASK;
+ data |= 0x1 << HPIPE_G1_SET_0_G1_TX_EMPH1_EN_OFFSET;
+ reg_set(hpipe_addr + HPIPE_G1_SET_0_REG, data, mask);
+
+ /* Set G2 TX amplitude and TX post emphasis value */
+ mask = HPIPE_G2_SET_0_G2_TX_AMP_MASK;
+ data = 0xa << HPIPE_G2_SET_0_G2_TX_AMP_OFFSET;
+ mask |= HPIPE_G2_SET_0_G2_TX_AMP_ADJ_MASK;
+ data |= 0x1 << HPIPE_G2_SET_0_G2_TX_AMP_ADJ_OFFSET;
+ mask |= HPIPE_G2_SET_0_G2_TX_EMPH1_MASK;
+ data |= 0x2 << HPIPE_G2_SET_0_G2_TX_EMPH1_OFFSET;
+ mask |= HPIPE_G2_SET_0_G2_TX_EMPH1_EN_MASK;
+ data |= 0x1 << HPIPE_G2_SET_0_G2_TX_EMPH1_EN_OFFSET;
+ reg_set(hpipe_addr + HPIPE_G2_SET_0_REG, data, mask);
+
+ /* Set G3 TX amplitude and TX post emphasis value */
+ mask = HPIPE_G3_SET_0_G3_TX_AMP_MASK;
+ data = 0xe << HPIPE_G3_SET_0_G3_TX_AMP_OFFSET;
+ mask |= HPIPE_G3_SET_0_G3_TX_AMP_ADJ_MASK;
+ data |= 0x1 << HPIPE_G3_SET_0_G3_TX_AMP_ADJ_OFFSET;
+ mask |= HPIPE_G3_SET_0_G3_TX_EMPH1_MASK;
+ data |= 0x6 << HPIPE_G3_SET_0_G3_TX_EMPH1_OFFSET;
+ mask |= HPIPE_G3_SET_0_G3_TX_EMPH1_EN_MASK;
+ data |= 0x1 << HPIPE_G3_SET_0_G3_TX_EMPH1_EN_OFFSET;
+ mask |= HPIPE_G3_SET_0_G3_TX_SLEW_RATE_SEL_MASK;
+ data |= 0x4 << HPIPE_G3_SET_0_G3_TX_SLEW_RATE_SEL_OFFSET;
+ mask |= HPIPE_G3_SET_0_G3_TX_SLEW_CTRL_EN_MASK;
+ data |= 0x0 << HPIPE_G3_SET_0_G3_TX_SLEW_CTRL_EN_OFFSET;
+ reg_set(hpipe_addr + HPIPE_G3_SET_0_REG, data, mask);
+
+ /* SERDES External Configuration 2 register */
+ mask = SD_EXTERNAL_CONFIG2_SSC_ENABLE_MASK;
+ data = 0x1 << SD_EXTERNAL_CONFIG2_SSC_ENABLE_OFFSET;
+ reg_set(sd_ip_addr + SD_EXTERNAL_CONFIG2_REG, data, mask);
/* DFE reset sequence */
reg_set(hpipe_addr + HPIPE_PWR_CTR_REG,
@@ -907,8 +1133,8 @@ static int comphy_sgmii_power_up(u32 lane, u32 sgmii_speed,
return ret;
}
-static int comphy_kr_power_up(u32 lane, void __iomem *hpipe_base,
- void __iomem *comphy_base)
+static int comphy_sfi_power_up(u32 lane, void __iomem *hpipe_base,
+ void __iomem *comphy_base, u32 speed)
{
u32 mask, data, ret = 1;
void __iomem *hpipe_addr = HPIPE_ADDR(hpipe_base, lane);
@@ -963,7 +1189,9 @@ static int comphy_kr_power_up(u32 lane, void __iomem *hpipe_base,
debug("stage: Comphy configuration\n");
/* set reference clock */
mask = HPIPE_MISC_ICP_FORCE_MASK;
- data = 0x1 << HPIPE_MISC_ICP_FORCE_OFFSET;
+ data = (speed == PHY_SPEED_5_15625G) ?
+ (0x0 << HPIPE_MISC_ICP_FORCE_OFFSET) :
+ (0x1 << HPIPE_MISC_ICP_FORCE_OFFSET);
mask |= HPIPE_MISC_REFCLK_SEL_MASK;
data |= 0x0 << HPIPE_MISC_REFCLK_SEL_OFFSET;
reg_set(hpipe_addr + HPIPE_MISC_REG, data, mask);
@@ -988,6 +1216,22 @@ static int comphy_kr_power_up(u32 lane, void __iomem *hpipe_base,
data = 0x1 << HPIPE_PWR_CTR_DTL_FLOOP_EN_OFFSET;
reg_set(hpipe_addr + HPIPE_PWR_CTR_DTL_REG, data, mask);
+ /* Transmitter/Receiver Speed Divider Force */
+ if (speed == PHY_SPEED_5_15625G) {
+ mask = HPIPE_SPD_DIV_FORCE_RX_SPD_DIV_MASK;
+ data = 1 << HPIPE_SPD_DIV_FORCE_RX_SPD_DIV_OFFSET;
+ mask |= HPIPE_SPD_DIV_FORCE_RX_SPD_DIV_FORCE_MASK;
+ data |= 1 << HPIPE_SPD_DIV_FORCE_RX_SPD_DIV_FORCE_OFFSET;
+ mask |= HPIPE_SPD_DIV_FORCE_TX_SPD_DIV_MASK;
+ data |= 1 << HPIPE_SPD_DIV_FORCE_TX_SPD_DIV_OFFSET;
+ mask |= HPIPE_SPD_DIV_FORCE_TX_SPD_DIV_FORCE_MASK;
+ data |= 1 << HPIPE_SPD_DIV_FORCE_TX_SPD_DIV_FORCE_OFFSET;
+ } else {
+ mask = HPIPE_TXDIGCK_DIV_FORCE_MASK;
+ data = 0x1 << HPIPE_TXDIGCK_DIV_FORCE_OFFSET;
+ }
+ reg_set(hpipe_addr + HPIPE_SPD_DIV_FORCE_REG, data, mask);
+
/* Set analog paramters from ETP(HW) */
debug("stage: Analog paramters from ETP(HW)\n");
/* SERDES External Configuration 2 */
@@ -999,10 +1243,15 @@ static int comphy_kr_power_up(u32 lane, void __iomem *hpipe_base,
data = 0x1 << HPIPE_DFE_RES_FORCE_OFFSET;
reg_set(hpipe_addr + HPIPE_DFE_REG0, data, mask);
/* 0xd-G1_Setting_0 */
- mask = HPIPE_G1_SET_0_G1_TX_AMP_MASK;
- data = 0x1c << HPIPE_G1_SET_0_G1_TX_AMP_OFFSET;
- mask |= HPIPE_G1_SET_0_G1_TX_EMPH1_MASK;
- data |= 0xe << HPIPE_G1_SET_0_G1_TX_EMPH1_OFFSET;
+ if (speed == PHY_SPEED_5_15625G) {
+ mask = HPIPE_G1_SET_0_G1_TX_EMPH1_MASK;
+ data = 0x6 << HPIPE_G1_SET_0_G1_TX_EMPH1_OFFSET;
+ } else {
+ mask = HPIPE_G1_SET_0_G1_TX_AMP_MASK;
+ data = 0x1c << HPIPE_G1_SET_0_G1_TX_AMP_OFFSET;
+ mask |= HPIPE_G1_SET_0_G1_TX_EMPH1_MASK;
+ data |= 0xe << HPIPE_G1_SET_0_G1_TX_EMPH1_OFFSET;
+ }
reg_set(hpipe_addr + HPIPE_G1_SET_0_REG, data, mask);
/* Genration 1 setting 2 (G1_Setting_2) */
mask = HPIPE_G1_SET_2_G1_TX_EMPH0_MASK;
@@ -1027,13 +1276,27 @@ static int comphy_kr_power_up(u32 lane, void __iomem *hpipe_base,
data = 0 << HPIPE_CAL_REG_1_EXT_TXIMP_OFFSET;
reg_set(hpipe_addr + HPIPE_G1_SETTING_5_REG, data, mask);
/* 0xE-G1_Setting_1 */
- mask = HPIPE_G1_SET_1_G1_RX_SELMUPI_MASK;
- data = 0x1 << HPIPE_G1_SET_1_G1_RX_SELMUPI_OFFSET;
- mask |= HPIPE_G1_SET_1_G1_RX_SELMUPP_MASK;
- data |= 0x1 << HPIPE_G1_SET_1_G1_RX_SELMUPP_OFFSET;
- mask |= HPIPE_G1_SET_1_G1_RX_DFE_EN_MASK;
- data |= 0x1 << HPIPE_G1_SET_1_G1_RX_DFE_EN_OFFSET;
+ mask = HPIPE_G1_SET_1_G1_RX_DFE_EN_MASK;
+ data = 0x1 << HPIPE_G1_SET_1_G1_RX_DFE_EN_OFFSET;
+ if (speed == PHY_SPEED_5_15625G) {
+ mask |= HPIPE_G1_SET_1_G1_RX_SELMUPI_MASK;
+ data |= 0x1 << HPIPE_G1_SET_1_G1_RX_SELMUPI_OFFSET;
+ mask |= HPIPE_G1_SET_1_G1_RX_SELMUPP_MASK;
+ data |= 0x1 << HPIPE_G1_SET_1_G1_RX_SELMUPP_OFFSET;
+ } else {
+ mask |= HPIPE_G1_SET_1_G1_RX_SELMUPI_MASK;
+ data |= 0x2 << HPIPE_G1_SET_1_G1_RX_SELMUPI_OFFSET;
+ mask |= HPIPE_G1_SET_1_G1_RX_SELMUPP_MASK;
+ data |= 0x2 << HPIPE_G1_SET_1_G1_RX_SELMUPP_OFFSET;
+ mask |= HPIPE_G1_SET_1_G1_RX_SELMUFI_MASK;
+ data |= 0x0 << HPIPE_G1_SET_1_G1_RX_SELMUFI_OFFSET;
+ mask |= HPIPE_G1_SET_1_G1_RX_SELMUFF_MASK;
+ data |= 0x1 << HPIPE_G1_SET_1_G1_RX_SELMUFF_OFFSET;
+ mask |= HPIPE_G1_SET_1_G1_RX_DIGCK_DIV_MASK;
+ data |= 0x3 << HPIPE_G1_SET_1_G1_RX_DIGCK_DIV_OFFSET;
+ }
reg_set(hpipe_addr + HPIPE_G1_SET_1_REG, data, mask);
+
/* 0xA-DFE_Reg3 */
mask = HPIPE_DFE_F3_F5_DFE_EN_MASK;
data = 0x0 << HPIPE_DFE_F3_F5_DFE_EN_OFFSET;
@@ -1048,8 +1311,74 @@ static int comphy_kr_power_up(u32 lane, void __iomem *hpipe_base,
/* Genration 1 setting 3 (G1_Setting_3) */
mask = HPIPE_G1_SETTINGS_3_G1_FBCK_SEL_MASK;
data = 0x1 << HPIPE_G1_SETTINGS_3_G1_FBCK_SEL_OFFSET;
+ if (speed == PHY_SPEED_5_15625G) {
+ /* Force FFE (Feed Forward Equalization) to 5G */
+ mask |= HPIPE_G1_SETTINGS_3_G1_FFE_CAP_SEL_MASK;
+ data |= 0xf << HPIPE_G1_SETTINGS_3_G1_FFE_CAP_SEL_OFFSET;
+ mask |= HPIPE_G1_SETTINGS_3_G1_FFE_RES_SEL_MASK;
+ data |= 0x4 << HPIPE_G1_SETTINGS_3_G1_FFE_RES_SEL_OFFSET;
+ mask |= HPIPE_G1_SETTINGS_3_G1_FFE_SETTING_FORCE_MASK;
+ data |= 0x1 << HPIPE_G1_SETTINGS_3_G1_FFE_SETTING_FORCE_OFFSET;
+ }
reg_set(hpipe_addr + HPIPE_G1_SETTINGS_3_REG, data, mask);
+ /* Connfigure RX training timer */
+ mask = HPIPE_RX_TRAIN_TIMER_MASK;
+ data = 0x13 << HPIPE_RX_TRAIN_TIMER_OFFSET;
+ reg_set(hpipe_addr + HPIPE_TX_TRAIN_CTRL_5_REG, data, mask);
+
+ /* Enable TX train peak to peak hold */
+ mask = HPIPE_TX_TRAIN_P2P_HOLD_MASK;
+ data = 0x1 << HPIPE_TX_TRAIN_P2P_HOLD_OFFSET;
+ reg_set(hpipe_addr + HPIPE_TX_TRAIN_CTRL_0_REG, data, mask);
+
+ /* Configure TX preset index */
+ mask = HPIPE_TX_PRESET_INDEX_MASK;
+ data = 0x2 << HPIPE_TX_PRESET_INDEX_OFFSET;
+ reg_set(hpipe_addr + HPIPE_TX_PRESET_INDEX_REG, data, mask);
+
+ /* Disable pattern lock lost timeout */
+ mask = HPIPE_PATTERN_LOCK_LOST_TIMEOUT_EN_MASK;
+ data = 0x0 << HPIPE_PATTERN_LOCK_LOST_TIMEOUT_EN_OFFSET;
+ reg_set(hpipe_addr + HPIPE_FRAME_DETECT_CTRL_3_REG, data, mask);
+
+ /* Configure TX training pattern and TX training 16bit auto */
+ mask = HPIPE_TX_TRAIN_16BIT_AUTO_EN_MASK;
+ data = 0x1 << HPIPE_TX_TRAIN_16BIT_AUTO_EN_OFFSET;
+ mask |= HPIPE_TX_TRAIN_PAT_SEL_MASK;
+ data |= 0x1 << HPIPE_TX_TRAIN_PAT_SEL_OFFSET;
+ reg_set(hpipe_addr + HPIPE_TX_TRAIN_REG, data, mask);
+
+ /* Configure Training patten number */
+ mask = HPIPE_TRAIN_PAT_NUM_MASK;
+ data = 0x88 << HPIPE_TRAIN_PAT_NUM_OFFSET;
+ reg_set(hpipe_addr + HPIPE_FRAME_DETECT_CTRL_0_REG, data, mask);
+
+ /* Configure differencial manchester encoter to ethernet mode */
+ mask = HPIPE_DME_ETHERNET_MODE_MASK;
+ data = 0x1 << HPIPE_DME_ETHERNET_MODE_OFFSET;
+ reg_set(hpipe_addr + HPIPE_DME_REG, data, mask);
+
+ /* Configure VDD Continuous Calibration */
+ mask = HPIPE_CAL_VDD_CONT_MODE_MASK;
+ data = 0x1 << HPIPE_CAL_VDD_CONT_MODE_OFFSET;
+ reg_set(hpipe_addr + HPIPE_VDD_CAL_0_REG, data, mask);
+
+ /* Trigger sampler enable pulse (by toggleing the bit) */
+ mask = HPIPE_RX_SAMPLER_OS_GAIN_MASK;
+ data = 0x3 << HPIPE_RX_SAMPLER_OS_GAIN_OFFSET;
+ mask |= HPIPE_SMAPLER_MASK;
+ data |= 0x1 << HPIPE_SMAPLER_OFFSET;
+ reg_set(hpipe_addr + HPIPE_SAMPLER_N_PROC_CALIB_CTRL_REG, data, mask);
+ mask = HPIPE_SMAPLER_MASK;
+ data = 0x0 << HPIPE_SMAPLER_OFFSET;
+ reg_set(hpipe_addr + HPIPE_SAMPLER_N_PROC_CALIB_CTRL_REG, data, mask);
+
+ /* Set External RX Regulator Control */
+ mask = HPIPE_EXT_SELLV_RXSAMPL_MASK;
+ data = 0x1A << HPIPE_EXT_SELLV_RXSAMPL_OFFSET;
+ reg_set(hpipe_addr + HPIPE_VDD_CAL_CTRL_REG, data, mask);
+
debug("stage: RFU configurations- Power Up PLL,Tx,Rx\n");
/* SERDES External Configuration */
mask = SD_EXTERNAL_CONFIG0_SD_PU_PLL_MASK;
@@ -1301,7 +1630,7 @@ static void comphy_utmi_power_down(u32 utmi_index, void __iomem *utmi_base_addr,
* If UTMI connected to USB Device, configure mux prior to PHY init
* (Device can be connected to UTMI0 or to UTMI1)
*/
- if (utmi_phy_port == UTMI_PHY_TO_USB_DEVICE0) {
+ if (utmi_phy_port == UTMI_PHY_TO_USB3_DEVICE0) {
debug("stage: UTMI %d - Enable Device mode and configure UTMI mux\n",
utmi_index);
/* USB3 Device UTMI enable */
@@ -1493,7 +1822,8 @@ static void comphy_utmi_phy_init(u32 utmi_phy_count,
continue;
}
printf("UTMI PHY %d initialized to ", i);
- if (cp110_utmi_data[i].utmi_phy_port == UTMI_PHY_TO_USB_DEVICE0)
+ if (cp110_utmi_data[i].utmi_phy_port ==
+ UTMI_PHY_TO_USB3_DEVICE0)
printf("USB Device\n");
else
printf("USB Host%d\n",
@@ -1659,6 +1989,7 @@ int comphy_cp110_init(struct chip_serdes_phy_config *ptr_chip_cfg,
}
switch (ptr_comphy_map->type) {
case PHY_TYPE_UNCONNECTED:
+ case PHY_TYPE_IGNORE:
continue;
break;
case PHY_TYPE_PEX0:
@@ -1667,6 +1998,7 @@ int comphy_cp110_init(struct chip_serdes_phy_config *ptr_chip_cfg,
case PHY_TYPE_PEX3:
ret = comphy_pcie_power_up(
lane, pcie_width, ptr_comphy_map->clk_src,
+ serdes_map->end_point,
hpipe_base_addr, comphy_base_addr);
break;
case PHY_TYPE_SATA0:
@@ -1675,7 +2007,7 @@ int comphy_cp110_init(struct chip_serdes_phy_config *ptr_chip_cfg,
case PHY_TYPE_SATA3:
ret = comphy_sata_power_up(
lane, hpipe_base_addr, comphy_base_addr,
- ptr_chip_cfg->comphy_index);
+ ptr_chip_cfg->cp_index);
break;
case PHY_TYPE_USB3_HOST0:
case PHY_TYPE_USB3_HOST1:
@@ -1696,9 +2028,10 @@ int comphy_cp110_init(struct chip_serdes_phy_config *ptr_chip_cfg,
lane, ptr_comphy_map->speed, hpipe_base_addr,
comphy_base_addr);
break;
- case PHY_TYPE_KR:
- ret = comphy_kr_power_up(lane, hpipe_base_addr,
- comphy_base_addr);
+ case PHY_TYPE_SFI:
+ ret = comphy_sfi_power_up(lane, hpipe_base_addr,
+ comphy_base_addr,
+ ptr_comphy_map->speed);
break;
case PHY_TYPE_RXAUI0:
case PHY_TYPE_RXAUI1:
@@ -1712,7 +2045,7 @@ int comphy_cp110_init(struct chip_serdes_phy_config *ptr_chip_cfg,
}
if (ret == 0) {
/*
- * If interface wans't initialiuzed, set the lane to
+ * If interface wans't initialized, set the lane to
* PHY_TYPE_UNCONNECTED state.
*/
ptr_comphy_map->type = PHY_TYPE_UNCONNECTED;
diff --git a/drivers/phy/marvell/comphy_hpipe.h b/drivers/phy/marvell/comphy_hpipe.h
index 179e910a0c8..fbceb2a403d 100644
--- a/drivers/phy/marvell/comphy_hpipe.h
+++ b/drivers/phy/marvell/comphy_hpipe.h
@@ -49,6 +49,9 @@
#define SD_EXTERNAL_CONFIG2_PIN_DFE_EN_OFFSET 4
#define SD_EXTERNAL_CONFIG2_PIN_DFE_EN_MASK \
(0x1 << SD_EXTERNAL_CONFIG2_PIN_DFE_EN_OFFSET)
+#define SD_EXTERNAL_CONFIG2_SSC_ENABLE_OFFSET 7
+#define SD_EXTERNAL_CONFIG2_SSC_ENABLE_MASK \
+ (0x1 << SD_EXTERNAL_CONFIG2_SSC_ENABLE_OFFSET)
#define SD_EXTERNAL_STATUS0_REG 0x18
#define SD_EXTERNAL_STATUS0_PLL_TX_OFFSET 2
@@ -105,9 +108,15 @@
#define HPIPE_G1_SET_0_G1_TX_AMP_OFFSET 1
#define HPIPE_G1_SET_0_G1_TX_AMP_MASK \
(0x1f << HPIPE_G1_SET_0_G1_TX_AMP_OFFSET)
+#define HPIPE_G1_SET_0_G1_TX_AMP_ADJ_OFFSET 6
+#define HPIPE_G1_SET_0_G1_TX_AMP_ADJ_MASK \
+ (0x1 << HPIPE_G1_SET_0_G1_TX_AMP_ADJ_OFFSET)
#define HPIPE_G1_SET_0_G1_TX_EMPH1_OFFSET 7
#define HPIPE_G1_SET_0_G1_TX_EMPH1_MASK \
(0xf << HPIPE_G1_SET_0_G1_TX_EMPH1_OFFSET)
+#define HPIPE_G1_SET_0_G1_TX_EMPH1_EN_OFFSET 11
+#define HPIPE_G1_SET_0_G1_TX_EMPH1_EN_MASK \
+ (0x1 << HPIPE_G1_SET_0_G1_TX_EMPH1_EN_OFFSET)
#define HPIPE_G1_SET_1_REG 0x038
#define HPIPE_G1_SET_1_G1_RX_SELMUPI_OFFSET 0
@@ -116,22 +125,96 @@
#define HPIPE_G1_SET_1_G1_RX_SELMUPP_OFFSET 3
#define HPIPE_G1_SET_1_G1_RX_SELMUPP_MASK \
(0x7 << HPIPE_G1_SET_1_G1_RX_SELMUPP_OFFSET)
+#define HPIPE_G1_SET_1_G1_RX_SELMUFI_OFFSET 6
+#define HPIPE_G1_SET_1_G1_RX_SELMUFI_MASK \
+ (0x3 << HPIPE_G1_SET_1_G1_RX_SELMUFI_OFFSET)
+#define HPIPE_G1_SET_1_G1_RX_SELMUFF_OFFSET 8
+#define HPIPE_G1_SET_1_G1_RX_SELMUFF_MASK \
+ (0x3 << HPIPE_G1_SET_1_G1_RX_SELMUFF_OFFSET)
#define HPIPE_G1_SET_1_G1_RX_DFE_EN_OFFSET 10
#define HPIPE_G1_SET_1_G1_RX_DFE_EN_MASK \
(0x1 << HPIPE_G1_SET_1_G1_RX_DFE_EN_OFFSET)
-#define HPIPE_G2_SETTINGS_1_REG 0x040
-
-#define HPIPE_G3_SETTINGS_1_REG 0x048
-#define HPIPE_G3_RX_SELMUPI_OFFSET 0
-#define HPIPE_G3_RX_SELMUPI_MASK \
- (0x7 << HPIPE_G3_RX_SELMUPI_OFFSET)
-#define HPIPE_G3_RX_SELMUPF_OFFSET 3
-#define HPIPE_G3_RX_SELMUPF_MASK \
- (0x7 << HPIPE_G3_RX_SELMUPF_OFFSET)
-#define HPIPE_G3_SETTING_BIT_OFFSET 13
-#define HPIPE_G3_SETTING_BIT_MASK \
- (0x1 << HPIPE_G3_SETTING_BIT_OFFSET)
+#define HPIPE_G1_SET_1_G1_RX_DIGCK_DIV_OFFSET 11
+#define HPIPE_G1_SET_1_G1_RX_DIGCK_DIV_MASK \
+ (0x3 << HPIPE_G1_SET_1_G1_RX_DIGCK_DIV_OFFSET)
+
+#define HPIPE_G2_SET_0_REG 0x3c
+#define HPIPE_G2_SET_0_G2_TX_AMP_OFFSET 1
+#define HPIPE_G2_SET_0_G2_TX_AMP_MASK \
+ (0x1f << HPIPE_G2_SET_0_G2_TX_AMP_OFFSET)
+#define HPIPE_G2_SET_0_G2_TX_AMP_ADJ_OFFSET 6
+#define HPIPE_G2_SET_0_G2_TX_AMP_ADJ_MASK \
+ (0x1 << HPIPE_G2_SET_0_G2_TX_AMP_ADJ_OFFSET)
+#define HPIPE_G2_SET_0_G2_TX_EMPH1_OFFSET 7
+#define HPIPE_G2_SET_0_G2_TX_EMPH1_MASK \
+ (0xf << HPIPE_G2_SET_0_G2_TX_EMPH1_OFFSET)
+#define HPIPE_G2_SET_0_G2_TX_EMPH1_EN_OFFSET 11
+#define HPIPE_G2_SET_0_G2_TX_EMPH1_EN_MASK \
+ (0x1 << HPIPE_G2_SET_0_G2_TX_EMPH1_EN_OFFSET)
+
+#define HPIPE_G2_SET_1_REG 0x040
+#define HPIPE_G2_SET_1_G2_RX_SELMUPI_OFFSET 0
+#define HPIPE_G2_SET_1_G2_RX_SELMUPI_MASK \
+ (0x7 << HPIPE_G2_SET_1_G2_RX_SELMUPI_OFFSET)
+#define HPIPE_G2_SET_1_G2_RX_SELMUPP_OFFSET 3
+#define HPIPE_G2_SET_1_G2_RX_SELMUPP_MASK \
+ (0x7 << HPIPE_G2_SET_1_G2_RX_SELMUPP_OFFSET)
+#define HPIPE_G2_SET_1_G2_RX_SELMUFI_OFFSET 6
+#define HPIPE_G2_SET_1_G2_RX_SELMUFI_MASK \
+ (0x3 << HPIPE_G2_SET_1_G2_RX_SELMUFI_OFFSET)
+#define HPIPE_G2_SET_1_G2_RX_SELMUFF_OFFSET 8
+#define HPIPE_G2_SET_1_G2_RX_SELMUFF_MASK \
+ (0x3 << HPIPE_G2_SET_1_G2_RX_SELMUFF_OFFSET)
+#define HPIPE_G2_SET_1_G2_RX_DFE_EN_OFFSET 10
+#define HPIPE_G2_SET_1_G2_RX_DFE_EN_MASK \
+ (0x1 << HPIPE_G2_SET_1_G2_RX_DFE_EN_OFFSET)
+#define HPIPE_G2_SET_1_G2_RX_DIGCK_DIV_OFFSET 11
+#define HPIPE_G2_SET_1_G2_RX_DIGCK_DIV_MASK \
+ (0x3 << HPIPE_G2_SET_1_G2_RX_DIGCK_DIV_OFFSET)
+
+#define HPIPE_G3_SET_0_REG 0x44
+#define HPIPE_G3_SET_0_G3_TX_AMP_OFFSET 1
+#define HPIPE_G3_SET_0_G3_TX_AMP_MASK \
+ (0x1f << HPIPE_G3_SET_0_G3_TX_AMP_OFFSET)
+#define HPIPE_G3_SET_0_G3_TX_AMP_ADJ_OFFSET 6
+#define HPIPE_G3_SET_0_G3_TX_AMP_ADJ_MASK \
+ (0x1 << HPIPE_G3_SET_0_G3_TX_AMP_ADJ_OFFSET)
+#define HPIPE_G3_SET_0_G3_TX_EMPH1_OFFSET 7
+#define HPIPE_G3_SET_0_G3_TX_EMPH1_MASK \
+ (0xf << HPIPE_G3_SET_0_G3_TX_EMPH1_OFFSET)
+#define HPIPE_G3_SET_0_G3_TX_EMPH1_EN_OFFSET 11
+#define HPIPE_G3_SET_0_G3_TX_EMPH1_EN_MASK \
+ (0x1 << HPIPE_G3_SET_0_G3_TX_EMPH1_EN_OFFSET)
+#define HPIPE_G3_SET_0_G3_TX_SLEW_RATE_SEL_OFFSET 12
+#define HPIPE_G3_SET_0_G3_TX_SLEW_RATE_SEL_MASK \
+ (0x7 << HPIPE_G3_SET_0_G3_TX_SLEW_RATE_SEL_OFFSET)
+#define HPIPE_G3_SET_0_G3_TX_SLEW_CTRL_EN_OFFSET 15
+#define HPIPE_G3_SET_0_G3_TX_SLEW_CTRL_EN_MASK \
+ (0x1 << HPIPE_G3_SET_0_G3_TX_SLEW_CTRL_EN_OFFSET)
+
+#define HPIPE_G3_SET_1_REG 0x048
+#define HPIPE_G3_SET_1_G3_RX_SELMUPI_OFFSET 0
+#define HPIPE_G3_SET_1_G3_RX_SELMUPI_MASK \
+ (0x7 << HPIPE_G3_SET_1_G3_RX_SELMUPI_OFFSET)
+#define HPIPE_G3_SET_1_G3_RX_SELMUPF_OFFSET 3
+#define HPIPE_G3_SET_1_G3_RX_SELMUPF_MASK \
+ (0x7 << HPIPE_G3_SET_1_G3_RX_SELMUPF_OFFSET)
+#define HPIPE_G3_SET_1_G3_RX_SELMUFI_OFFSET 6
+#define HPIPE_G3_SET_1_G3_RX_SELMUFI_MASK \
+ (0x3 << HPIPE_G3_SET_1_G3_RX_SELMUFI_OFFSET)
+#define HPIPE_G3_SET_1_G3_RX_SELMUFF_OFFSET 8
+#define HPIPE_G3_SET_1_G3_RX_SELMUFF_MASK \
+ (0x3 << HPIPE_G3_SET_1_G3_RX_SELMUFF_OFFSET)
+#define HPIPE_G3_SET_1_G3_RX_DFE_EN_OFFSET 10
+#define HPIPE_G3_SET_1_G3_RX_DFE_EN_MASK \
+ (0x1 << HPIPE_G3_SET_1_G3_RX_DFE_EN_OFFSET)
+#define HPIPE_G3_SET_1_G3_RX_DIGCK_DIV_OFFSET 11
+#define HPIPE_G3_SET_1_G3_RX_DIGCK_DIV_MASK \
+ (0x3 << HPIPE_G3_SET_1_G3_RX_DIGCK_DIV_OFFSET)
+#define HPIPE_G3_SET_1_G3_SAMPLER_INPAIRX2_EN_OFFSET 13
+#define HPIPE_G3_SET_1_G3_SAMPLER_INPAIRX2_EN_MASK \
+ (0x1 << HPIPE_G3_SET_1_G3_SAMPLER_INPAIRX2_EN_OFFSET)
#define HPIPE_LOOPBACK_REG 0x08c
#define HPIPE_LOOPBACK_SEL_OFFSET 1
@@ -144,6 +227,9 @@
#define HPIPE_INTERFACE_GEN_MAX_OFFSET 10
#define HPIPE_INTERFACE_GEN_MAX_MASK \
(0x3 << HPIPE_INTERFACE_GEN_MAX_OFFSET)
+#define HPIPE_INTERFACE_DET_BYPASS_OFFSET 12
+#define HPIPE_INTERFACE_DET_BYPASS_MASK \
+ (0x1 << HPIPE_INTERFACE_DET_BYPASS_OFFSET)
#define HPIPE_INTERFACE_LINK_TRAIN_OFFSET 14
#define HPIPE_INTERFACE_LINK_TRAIN_MASK \
(0x1 << HPIPE_INTERFACE_LINK_TRAIN_OFFSET)
@@ -166,6 +252,16 @@
#define HPIPE_VTHIMPCAL_CTRL_REG 0x104
+#define HPIPE_VDD_CAL_CTRL_REG 0x114
+#define HPIPE_EXT_SELLV_RXSAMPL_OFFSET 5
+#define HPIPE_EXT_SELLV_RXSAMPL_MASK \
+ (0x1f << HPIPE_EXT_SELLV_RXSAMPL_OFFSET)
+
+#define HPIPE_VDD_CAL_0_REG 0x108
+#define HPIPE_CAL_VDD_CONT_MODE_OFFSET 15
+#define HPIPE_CAL_VDD_CONT_MODE_MASK \
+ (0x1 << HPIPE_CAL_VDD_CONT_MODE_OFFSET)
+
#define HPIPE_PCIE_REG0 0x120
#define HPIPE_PCIE_IDLE_SYNC_OFFSET 12
#define HPIPE_PCIE_IDLE_SYNC_MASK \
@@ -212,9 +308,29 @@
#define HPIPE_PWR_CTR_SFT_RST_MASK \
(0x1 << HPIPE_PWR_CTR_SFT_RST_OFFSET)
+#define HPIPE_SPD_DIV_FORCE_REG 0x154
+#define HPIPE_TXDIGCK_DIV_FORCE_OFFSET 7
+#define HPIPE_TXDIGCK_DIV_FORCE_MASK \
+ (0x1 << HPIPE_TXDIGCK_DIV_FORCE_OFFSET)
+#define HPIPE_SPD_DIV_FORCE_RX_SPD_DIV_OFFSET 8
+#define HPIPE_SPD_DIV_FORCE_RX_SPD_DIV_MASK \
+ (0x3 << HPIPE_SPD_DIV_FORCE_RX_SPD_DIV_OFFSET)
+#define HPIPE_SPD_DIV_FORCE_RX_SPD_DIV_FORCE_OFFSET 10
+#define HPIPE_SPD_DIV_FORCE_RX_SPD_DIV_FORCE_MASK \
+ (0x1 << HPIPE_SPD_DIV_FORCE_RX_SPD_DIV_FORCE_OFFSET)
+#define HPIPE_SPD_DIV_FORCE_TX_SPD_DIV_OFFSET 13
+#define HPIPE_SPD_DIV_FORCE_TX_SPD_DIV_MASK \
+ (0x3 << HPIPE_SPD_DIV_FORCE_TX_SPD_DIV_OFFSET)
+#define HPIPE_SPD_DIV_FORCE_TX_SPD_DIV_FORCE_OFFSET 15
+#define HPIPE_SPD_DIV_FORCE_TX_SPD_DIV_FORCE_MASK \
+ (0x1 << HPIPE_SPD_DIV_FORCE_TX_SPD_DIV_FORCE_OFFSET)
+
#define HPIPE_PLLINTP_REG1 0x150
#define HPIPE_SAMPLER_N_PROC_CALIB_CTRL_REG 0x16C
+#define HPIPE_RX_SAMPLER_OS_GAIN_OFFSET 6
+#define HPIPE_RX_SAMPLER_OS_GAIN_MASK \
+ (0x3 << HPIPE_RX_SAMPLER_OS_GAIN_OFFSET)
#define HPIPE_SMAPLER_OFFSET 12
#define HPIPE_SMAPLER_MASK \
(0x1 << HPIPE_SMAPLER_OFFSET)
@@ -227,12 +343,54 @@
#define HPIPE_TX_REG1_SLC_EN_MASK \
(0x3f << HPIPE_TX_REG1_SLC_EN_OFFSET)
-#define HPIPE_PWR_CTR_DTL_REG 0x184
-#define HPIPE_PWR_CTR_DTL_FLOOP_EN_OFFSET 2
-#define HPIPE_PWR_CTR_DTL_FLOOP_EN_MASK \
+#define HPIPE_PWR_CTR_DTL_REG 0x184
+#define HPIPE_PWR_CTR_DTL_SQ_DET_EN_OFFSET 0
+#define HPIPE_PWR_CTR_DTL_SQ_DET_EN_MASK \
+ (0x1 << HPIPE_PWR_CTR_DTL_SQ_DET_EN_OFFSET)
+#define HPIPE_PWR_CTR_DTL_SQ_PLOOP_EN_OFFSET 1
+#define HPIPE_PWR_CTR_DTL_SQ_PLOOP_EN_MASK \
+ (0x1 << HPIPE_PWR_CTR_DTL_SQ_PLOOP_EN_OFFSET)
+#define HPIPE_PWR_CTR_DTL_FLOOP_EN_OFFSET 2
+#define HPIPE_PWR_CTR_DTL_FLOOP_EN_MASK \
(0x1 << HPIPE_PWR_CTR_DTL_FLOOP_EN_OFFSET)
-
-#define HPIPE_RX_REG3 0x188
+#define HPIPE_PWR_CTR_DTL_CLAMPING_SEL_OFFSET 4
+#define HPIPE_PWR_CTR_DTL_CLAMPING_SEL_MASK \
+ (0x7 << HPIPE_PWR_CTR_DTL_CLAMPING_SEL_OFFSET)
+#define HPIPE_PWR_CTR_DTL_INTPCLK_DIV_FORCE_OFFSET 10
+#define HPIPE_PWR_CTR_DTL_INTPCLK_DIV_FORCE_MASK \
+ (0x1 << HPIPE_PWR_CTR_DTL_INTPCLK_DIV_FORCE_OFFSET)
+#define HPIPE_PWR_CTR_DTL_CLK_MODE_OFFSET 12
+#define HPIPE_PWR_CTR_DTL_CLK_MODE_MASK \
+ (0x3 << HPIPE_PWR_CTR_DTL_CLK_MODE_OFFSET)
+#define HPIPE_PWR_CTR_DTL_CLK_MODE_FORCE_OFFSET 14
+#define HPIPE_PWR_CTR_DTL_CLK_MODE_FORCE_MASK \
+ (1 << HPIPE_PWR_CTR_DTL_CLK_MODE_FORCE_OFFSET)
+
+#define HPIPE_PHASE_CONTROL_REG 0x188
+#define HPIPE_OS_PH_OFFSET_OFFSET 0
+#define HPIPE_OS_PH_OFFSET_MASK \
+ (0x7f << HPIPE_OS_PH_OFFSET_OFFSET)
+#define HPIPE_OS_PH_OFFSET_FORCE_OFFSET 7
+#define HPIPE_OS_PH_OFFSET_FORCE_MASK \
+ (0x1 << HPIPE_OS_PH_OFFSET_FORCE_OFFSET)
+#define HPIPE_OS_PH_VALID_OFFSET 8
+#define HPIPE_OS_PH_VALID_MASK \
+ (0x1 << HPIPE_OS_PH_VALID_OFFSET)
+
+#define HPIPE_FRAME_DETECT_CTRL_0_REG 0x214
+#define HPIPE_TRAIN_PAT_NUM_OFFSET 0x7
+#define HPIPE_TRAIN_PAT_NUM_MASK \
+ (0x1FF << HPIPE_TRAIN_PAT_NUM_OFFSET)
+
+#define HPIPE_FRAME_DETECT_CTRL_3_REG 0x220
+#define HPIPE_PATTERN_LOCK_LOST_TIMEOUT_EN_OFFSET 12
+#define HPIPE_PATTERN_LOCK_LOST_TIMEOUT_EN_MASK \
+ (0x1 << HPIPE_PATTERN_LOCK_LOST_TIMEOUT_EN_OFFSET)
+
+#define HPIPE_DME_REG 0x228
+#define HPIPE_DME_ETHERNET_MODE_OFFSET 7
+#define HPIPE_DME_ETHERNET_MODE_MASK \
+ (0x1 << HPIPE_DME_ETHERNET_MODE_OFFSET)
#define HPIPE_TX_TRAIN_CTRL_0_REG 0x268
#define HPIPE_TX_TRAIN_P2P_HOLD_OFFSET 15
@@ -259,6 +417,9 @@
#define HPIPE_PCIE_REG3 0x290
#define HPIPE_TX_TRAIN_CTRL_5_REG 0x2A4
+#define HPIPE_RX_TRAIN_TIMER_OFFSET 0
+#define HPIPE_RX_TRAIN_TIMER_MASK \
+ (0x3ff << HPIPE_RX_TRAIN_TIMER_OFFSET)
#define HPIPE_TX_TRAIN_START_SQ_EN_OFFSET 11
#define HPIPE_TX_TRAIN_START_SQ_EN_MASK \
(0x1 << HPIPE_TX_TRAIN_START_SQ_EN_OFFSET)
@@ -279,6 +440,23 @@
#define HPIPE_TX_TRAIN_COE_FM_PIN_PCIE3_OFFSET 7
#define HPIPE_TX_TRAIN_COE_FM_PIN_PCIE3_MASK \
(0x1 << HPIPE_TX_TRAIN_COE_FM_PIN_PCIE3_OFFSET)
+#define HPIPE_TX_TRAIN_16BIT_AUTO_EN_OFFSET 8
+#define HPIPE_TX_TRAIN_16BIT_AUTO_EN_MASK \
+ (0x1 << HPIPE_TX_TRAIN_16BIT_AUTO_EN_OFFSET)
+#define HPIPE_TX_TRAIN_PAT_SEL_OFFSET 9
+#define HPIPE_TX_TRAIN_PAT_SEL_MASK \
+ (0x1 << HPIPE_TX_TRAIN_PAT_SEL_OFFSET)
+
+#define HPIPE_CDR_CONTROL_REG 0x418
+#define HPIPE_CDR_RX_MAX_DFE_ADAPT_1_OFFSET 12
+#define HPIPE_CDR_RX_MAX_DFE_ADAPT_1_MASK \
+ (0x3 << HPIPE_CDR_RX_MAX_DFE_ADAPT_1_OFFSET)
+#define HPIPE_CDR_MAX_DFE_ADAPT_0_OFFSET 9
+#define HPIPE_CDR_MAX_DFE_ADAPT_0_MASK \
+ (0x7 << HPIPE_CDR_MAX_DFE_ADAPT_0_OFFSET)
+#define HPIPE_CDR_MAX_DFE_ADAPT_1_OFFSET 6
+#define HPIPE_CDR_MAX_DFE_ADAPT_1_MASK \
+ (0x7 << HPIPE_CDR_MAX_DFE_ADAPT_1_OFFSET)
#define HPIPE_TX_TRAIN_CTRL_11_REG 0x438
#define HPIPE_TX_STATUS_CHECK_MODE_OFFSET 6
@@ -291,10 +469,25 @@
#define HPIPE_TX_SWEEP_PRESET_EN_MASK \
(0x1 << HPIPE_TX_SWEEP_PRESET_EN_OFFSET)
-#define HPIPE_G1_SETTINGS_3_REG 0x440
-#define HPIPE_G1_SETTINGS_3_G1_FBCK_SEL_OFFSET 9
-#define HPIPE_G1_SETTINGS_3_G1_FBCK_SEL_MASK \
+#define HPIPE_G1_SETTINGS_3_REG 0x440
+#define HPIPE_G1_SETTINGS_3_G1_FFE_CAP_SEL_OFFSET 0
+#define HPIPE_G1_SETTINGS_3_G1_FFE_CAP_SEL_MASK \
+ (0xf << HPIPE_G1_SETTINGS_3_G1_FFE_CAP_SEL_OFFSET)
+#define HPIPE_G1_SETTINGS_3_G1_FFE_RES_SEL_OFFSET 4
+#define HPIPE_G1_SETTINGS_3_G1_FFE_RES_SEL_MASK \
+ (0x7 << HPIPE_G1_SETTINGS_3_G1_FFE_RES_SEL_OFFSET)
+#define HPIPE_G1_SETTINGS_3_G1_FFE_SETTING_FORCE_OFFSET 7
+#define HPIPE_G1_SETTINGS_3_G1_FFE_SETTING_FORCE_MASK \
+ (0x1 << HPIPE_G1_SETTINGS_3_G1_FFE_SETTING_FORCE_OFFSET)
+#define HPIPE_G1_SETTINGS_3_G1_FBCK_SEL_OFFSET 9
+#define HPIPE_G1_SETTINGS_3_G1_FBCK_SEL_MASK \
(0x1 << HPIPE_G1_SETTINGS_3_G1_FBCK_SEL_OFFSET)
+#define HPIPE_G1_SETTINGS_3_G1_FFE_DEG_RES_LEVEL_OFFSET 12
+#define HPIPE_G1_SETTINGS_3_G1_FFE_DEG_RES_LEVEL_MASK \
+ (0x3 << HPIPE_G1_SETTINGS_3_G1_FFE_DEG_RES_LEVEL_OFFSET)
+#define HPIPE_G1_SETTINGS_3_G1_FFE_LOAD_RES_LEVEL_OFFSET 14
+#define HPIPE_G1_SETTINGS_3_G1_FFE_LOAD_RES_LEVEL_MASK \
+ (0x3 << HPIPE_G1_SETTINGS_3_G1_FFE_LOAD_RES_LEVEL_OFFSET)
#define HPIPE_G1_SETTINGS_4_REG 0x444
#define HPIPE_G1_SETTINGS_4_G1_DFE_RES_OFFSET 8
@@ -302,9 +495,22 @@
(0x3 << HPIPE_G1_SETTINGS_4_G1_DFE_RES_OFFSET)
#define HPIPE_G2_SETTINGS_3_REG 0x448
-#define HPIPE_G2_SETTINGS_4_REG 0x44C
+
+#define HPIPE_G2_SETTINGS_4_REG 0x44c
+#define HPIPE_G2_DFE_RES_OFFSET 8
+#define HPIPE_G2_DFE_RES_MASK \
+ (0x3 << HPIPE_G2_DFE_RES_OFFSET)
#define HPIPE_G3_SETTING_3_REG 0x450
+#define HPIPE_G3_FFE_CAP_SEL_OFFSET 0
+#define HPIPE_G3_FFE_CAP_SEL_MASK \
+ (0xf << HPIPE_G3_FFE_CAP_SEL_OFFSET)
+#define HPIPE_G3_FFE_RES_SEL_OFFSET 4
+#define HPIPE_G3_FFE_RES_SEL_MASK \
+ (0x7 << HPIPE_G3_FFE_RES_SEL_OFFSET)
+#define HPIPE_G3_FFE_SETTING_FORCE_OFFSET 7
+#define HPIPE_G3_FFE_SETTING_FORCE_MASK \
+ (0x1 << HPIPE_G3_FFE_SETTING_FORCE_OFFSET)
#define HPIPE_G3_FFE_DEG_RES_LEVEL_OFFSET 12
#define HPIPE_G3_FFE_DEG_RES_LEVEL_MASK \
(0x3 << HPIPE_G3_FFE_DEG_RES_LEVEL_OFFSET)
@@ -317,6 +523,16 @@
#define HPIPE_G3_DFE_RES_MASK \
(0x3 << HPIPE_G3_DFE_RES_OFFSET)
+#define HPIPE_TX_PRESET_INDEX_REG 0x468
+#define HPIPE_TX_PRESET_INDEX_OFFSET 0
+#define HPIPE_TX_PRESET_INDEX_MASK \
+ (0xf << HPIPE_TX_PRESET_INDEX_OFFSET)
+
+#define HPIPE_DFE_CONTROL_REG 0x470
+#define HPIPE_DFE_TX_MAX_DFE_ADAPT_OFFSET 14
+#define HPIPE_DFE_TX_MAX_DFE_ADAPT_MASK \
+ (0x3 << HPIPE_DFE_TX_MAX_DFE_ADAPT_OFFSET)
+
#define HPIPE_DFE_CTRL_28_REG 0x49C
#define HPIPE_DFE_CTRL_28_PIPE4_OFFSET 7
#define HPIPE_DFE_CTRL_28_PIPE4_MASK \
@@ -327,6 +543,11 @@
#define HPIPE_G1_SETTING_5_G1_ICP_MASK \
(0xf << HPIPE_G1_SETTING_5_G1_ICP_OFFSET)
+#define HPIPE_G3_SETTING_5_REG 0x548
+#define HPIPE_G3_SETTING_5_G3_ICP_OFFSET 0
+#define HPIPE_G3_SETTING_5_G3_ICP_MASK \
+ (0xf << HPIPE_G3_SETTING_5_G3_ICP_OFFSET)
+
#define HPIPE_LANE_CONFIG0_REG 0x600
#define HPIPE_LANE_CONFIG0_TXDEEMPH0_OFFSET 0
#define HPIPE_LANE_CONFIG0_TXDEEMPH0_MASK \
@@ -349,6 +570,9 @@
#define HPIPE_LANE_CFG4_DFE_CTRL_OFFSET 0
#define HPIPE_LANE_CFG4_DFE_CTRL_MASK \
(0x7 << HPIPE_LANE_CFG4_DFE_CTRL_OFFSET)
+#define HPIPE_LANE_CFG4_DFE_EN_SEL_OFFSET 3
+#define HPIPE_LANE_CFG4_DFE_EN_SEL_MASK \
+ (0x1 << HPIPE_LANE_CFG4_DFE_EN_SEL_OFFSET)
#define HPIPE_LANE_CFG4_DFE_OVER_OFFSET 6
#define HPIPE_LANE_CFG4_DFE_OVER_MASK \
(0x1 << HPIPE_LANE_CFG4_DFE_OVER_OFFSET)
@@ -366,6 +590,17 @@
#define HPIPE_CFG_UPDATE_POLARITY_MASK \
(0x1 << HPIPE_CFG_UPDATE_POLARITY_OFFSET)
+#define HPIPE_LANE_EQ_REMOTE_SETTING_REG 0x6f8
+#define HPIPE_LANE_CFG_FOM_DIRN_OVERRIDE_OFFSET 0
+#define HPIPE_LANE_CFG_FOM_DIRN_OVERRIDE_MASK \
+ (0x1 << HPIPE_LANE_CFG_FOM_DIRN_OVERRIDE_OFFSET)
+#define HPIPE_LANE_CFG_FOM_ONLY_MODE_OFFFSET 1
+#define HPIPE_LANE_CFG_FOM_ONLY_MODE_MASK \
+ (0x1 << HPIPE_LANE_CFG_FOM_ONLY_MODE_OFFFSET)
+#define HPIPE_LANE_CFG_FOM_PRESET_VECTOR_OFFSET 2
+#define HPIPE_LANE_CFG_FOM_PRESET_VECTOR_MASK \
+ (0xf << HPIPE_LANE_CFG_FOM_PRESET_VECTOR_OFFSET)
+
#define HPIPE_RST_CLK_CTRL_REG 0x704
#define HPIPE_RST_CLK_CTRL_PIPE_RST_OFFSET 0
#define HPIPE_RST_CLK_CTRL_PIPE_RST_MASK \
diff --git a/drivers/phy/marvell/comphy_mux.c b/drivers/phy/marvell/comphy_mux.c
index 1dc7426b638..b036fb13b9c 100644
--- a/drivers/phy/marvell/comphy_mux.c
+++ b/drivers/phy/marvell/comphy_mux.c
@@ -27,6 +27,10 @@ static void comphy_mux_check_config(struct comphy_mux_data *mux_data,
for (lane = 0; lane < comphy_max_lanes;
lane++, comphy_map_data++, mux_data++) {
+ /* Don't check ignored COMPHYs */
+ if (comphy_map_data->type == PHY_TYPE_IGNORE)
+ continue;
+
mux_opt = mux_data->mux_values;
for (opt = 0, valid = 0; opt < mux_data->max_lane_values;
opt++, mux_opt++) {
@@ -83,6 +87,9 @@ static void comphy_mux_reg_write(struct comphy_mux_data *mux_data,
for (lane = 0; lane < comphy_max_lanes;
lane++, comphy_map_data++, mux_data++) {
+ if (comphy_map_data->type == PHY_TYPE_IGNORE)
+ continue;
+
offset = lane * bitcount;
mask = (((1 << bitcount) - 1) << offset);
value = (comphy_mux_get_mux_value(mux_data,
diff --git a/drivers/phy/phy-uclass.c b/drivers/phy/phy-uclass.c
new file mode 100644
index 00000000000..0d8bef76dbd
--- /dev/null
+++ b/drivers/phy/phy-uclass.c
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2017 Texas Instruments Incorporated - http://www.ti.com/
+ * Written by Jean-Jacques Hiblot <jjhiblot@ti.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <generic-phy.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static inline struct phy_ops *phy_dev_ops(struct udevice *dev)
+{
+ return (struct phy_ops *)dev->driver->ops;
+}
+
+static int generic_phy_xlate_offs_flags(struct phy *phy,
+ struct fdtdec_phandle_args *args)
+{
+ debug("%s(phy=%p)\n", __func__, phy);
+
+ if (args->args_count > 1) {
+ debug("Invaild args_count: %d\n", args->args_count);
+ return -EINVAL;
+ }
+
+ if (args->args_count)
+ phy->id = args->args[0];
+ else
+ phy->id = 0;
+
+
+ return 0;
+}
+
+int generic_phy_get_by_index(struct udevice *dev, int index,
+ struct phy *phy)
+{
+ struct fdtdec_phandle_args args;
+ struct phy_ops *ops;
+ int ret;
+ struct udevice *phydev;
+
+ debug("%s(dev=%p, index=%d, phy=%p)\n", __func__, dev, index, phy);
+
+ assert(phy);
+ ret = fdtdec_parse_phandle_with_args(gd->fdt_blob, dev_of_offset(dev),
+ "phys", "#phy-cells", 0, index,
+ &args);
+ if (ret) {
+ debug("%s: fdtdec_parse_phandle_with_args failed: err=%d\n",
+ __func__, ret);
+ return ret;
+ }
+
+ ret = uclass_get_device_by_of_offset(UCLASS_PHY, args.node, &phydev);
+ if (ret) {
+ debug("%s: uclass_get_device_by_of_offset failed: err=%d\n",
+ __func__, ret);
+ return ret;
+ }
+
+ phy->dev = phydev;
+
+ ops = phy_dev_ops(phydev);
+
+ if (ops->of_xlate)
+ ret = ops->of_xlate(phy, &args);
+ else
+ ret = generic_phy_xlate_offs_flags(phy, &args);
+ if (ret) {
+ debug("of_xlate() failed: %d\n", ret);
+ goto err;
+ }
+
+ return 0;
+
+err:
+ return ret;
+}
+
+int generic_phy_get_by_name(struct udevice *dev, const char *phy_name,
+ struct phy *phy)
+{
+ int index;
+
+ debug("%s(dev=%p, name=%s, phy=%p)\n", __func__, dev, phy_name, phy);
+
+ index = fdt_stringlist_search(gd->fdt_blob, dev_of_offset(dev),
+ "phy-names", phy_name);
+ if (index < 0) {
+ debug("fdt_stringlist_search() failed: %d\n", index);
+ return index;
+ }
+
+ return generic_phy_get_by_index(dev, index, phy);
+}
+
+int generic_phy_init(struct phy *phy)
+{
+ struct phy_ops const *ops = phy_dev_ops(phy->dev);
+
+ return ops->init ? ops->init(phy) : 0;
+}
+
+int generic_phy_reset(struct phy *phy)
+{
+ struct phy_ops const *ops = phy_dev_ops(phy->dev);
+
+ return ops->reset ? ops->reset(phy) : 0;
+}
+
+int generic_phy_exit(struct phy *phy)
+{
+ struct phy_ops const *ops = phy_dev_ops(phy->dev);
+
+ return ops->exit ? ops->exit(phy) : 0;
+}
+
+int generic_phy_power_on(struct phy *phy)
+{
+ struct phy_ops const *ops = phy_dev_ops(phy->dev);
+
+ return ops->power_on ? ops->power_on(phy) : 0;
+}
+
+int generic_phy_power_off(struct phy *phy)
+{
+ struct phy_ops const *ops = phy_dev_ops(phy->dev);
+
+ return ops->power_off ? ops->power_off(phy) : 0;
+}
+
+UCLASS_DRIVER(phy) = {
+ .id = UCLASS_PHY,
+ .name = "phy",
+};
diff --git a/drivers/phy/sandbox-phy.c b/drivers/phy/sandbox-phy.c
new file mode 100644
index 00000000000..9ad820c24c9
--- /dev/null
+++ b/drivers/phy/sandbox-phy.c
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2017 Texas Instruments Incorporated - http://www.ti.com/
+ * Written by Jean-Jacques Hiblot <jjhiblot@ti.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <generic-phy.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+struct sandbox_phy_priv {
+ bool initialized;
+ bool on;
+ bool broken;
+};
+
+static int sandbox_phy_power_on(struct phy *phy)
+{
+ struct sandbox_phy_priv *priv = dev_get_priv(phy->dev);
+
+ if (!priv->initialized)
+ return -EIO;
+
+ if (priv->broken)
+ return -EIO;
+
+ priv->on = true;
+
+ return 0;
+}
+
+static int sandbox_phy_power_off(struct phy *phy)
+{
+ struct sandbox_phy_priv *priv = dev_get_priv(phy->dev);
+
+ if (!priv->initialized)
+ return -EIO;
+
+ if (priv->broken)
+ return -EIO;
+
+ /*
+ * for validation purpose, let's says that power off
+ * works only for PHY 0
+ */
+ if (phy->id)
+ return -EIO;
+
+ priv->on = false;
+
+ return 0;
+}
+
+static int sandbox_phy_init(struct phy *phy)
+{
+ struct sandbox_phy_priv *priv = dev_get_priv(phy->dev);
+
+ priv->initialized = true;
+ priv->on = true;
+
+ return 0;
+}
+
+static int sandbox_phy_exit(struct phy *phy)
+{
+ struct sandbox_phy_priv *priv = dev_get_priv(phy->dev);
+
+ priv->initialized = false;
+ priv->on = false;
+
+ return 0;
+}
+
+static int sandbox_phy_probe(struct udevice *dev)
+{
+ struct sandbox_phy_priv *priv = dev_get_priv(dev);
+
+ priv->initialized = false;
+ priv->on = false;
+ priv->broken = fdtdec_get_bool(gd->fdt_blob, dev_of_offset(dev),
+ "broken");
+
+ return 0;
+}
+
+static struct phy_ops sandbox_phy_ops = {
+ .power_on = sandbox_phy_power_on,
+ .power_off = sandbox_phy_power_off,
+ .init = sandbox_phy_init,
+ .exit = sandbox_phy_exit,
+};
+
+static const struct udevice_id sandbox_phy_ids[] = {
+ { .compatible = "sandbox,phy" },
+ { }
+};
+
+U_BOOT_DRIVER(phy_sandbox) = {
+ .name = "phy_sandbox",
+ .id = UCLASS_PHY,
+ .of_match = sandbox_phy_ids,
+ .ops = &sandbox_phy_ops,
+ .probe = sandbox_phy_probe,
+ .priv_auto_alloc_size = sizeof(struct sandbox_phy_priv),
+};
diff --git a/drivers/phy/ti-pipe3-phy.c b/drivers/phy/ti-pipe3-phy.c
new file mode 100644
index 00000000000..ed80f0ff0b1
--- /dev/null
+++ b/drivers/phy/ti-pipe3-phy.c
@@ -0,0 +1,373 @@
+/*
+ * Copyright (C) 2017 Texas Instruments Incorporated - http://www.ti.com/
+ * Written by Jean-Jacques Hiblot <jjhiblot@ti.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <dm/device.h>
+#include <generic-phy.h>
+#include <asm/io.h>
+#include <asm/arch/sys_proto.h>
+#include <syscon.h>
+#include <regmap.h>
+
+/* PLLCTRL Registers */
+#define PLL_STATUS 0x00000004
+#define PLL_GO 0x00000008
+#define PLL_CONFIGURATION1 0x0000000C
+#define PLL_CONFIGURATION2 0x00000010
+#define PLL_CONFIGURATION3 0x00000014
+#define PLL_CONFIGURATION4 0x00000020
+
+#define PLL_REGM_MASK 0x001FFE00
+#define PLL_REGM_SHIFT 9
+#define PLL_REGM_F_MASK 0x0003FFFF
+#define PLL_REGM_F_SHIFT 0
+#define PLL_REGN_MASK 0x000001FE
+#define PLL_REGN_SHIFT 1
+#define PLL_SELFREQDCO_MASK 0x0000000E
+#define PLL_SELFREQDCO_SHIFT 1
+#define PLL_SD_MASK 0x0003FC00
+#define PLL_SD_SHIFT 10
+#define SET_PLL_GO 0x1
+#define PLL_TICOPWDN BIT(16)
+#define PLL_LDOPWDN BIT(15)
+#define PLL_LOCK 0x2
+#define PLL_IDLE 0x1
+
+/* Software rest for the SATA PLL (in CTRL_CORE_SMA_SW_0 register)*/
+#define SATA_PLL_SOFT_RESET (1<<18)
+
+/* PHY POWER CONTROL Register */
+#define OMAP_CTRL_PIPE3_PHY_PWRCTL_CLK_CMD_MASK 0x003FC000
+#define OMAP_CTRL_PIPE3_PHY_PWRCTL_CLK_CMD_SHIFT 0xE
+
+#define OMAP_CTRL_PIPE3_PHY_PWRCTL_CLK_FREQ_MASK 0xFFC00000
+#define OMAP_CTRL_PIPE3_PHY_PWRCTL_CLK_FREQ_SHIFT 0x16
+
+#define OMAP_CTRL_PIPE3_PHY_TX_RX_POWERON 0x3
+#define OMAP_CTRL_PIPE3_PHY_TX_RX_POWEROFF 0x0
+
+
+#define PLL_IDLE_TIME 100 /* in milliseconds */
+#define PLL_LOCK_TIME 100 /* in milliseconds */
+
+struct omap_pipe3 {
+ void __iomem *pll_ctrl_base;
+ void __iomem *power_reg;
+ void __iomem *pll_reset_reg;
+ struct pipe3_dpll_map *dpll_map;
+};
+
+
+struct pipe3_dpll_params {
+ u16 m;
+ u8 n;
+ u8 freq:3;
+ u8 sd;
+ u32 mf;
+};
+
+struct pipe3_dpll_map {
+ unsigned long rate;
+ struct pipe3_dpll_params params;
+};
+
+static inline u32 omap_pipe3_readl(void __iomem *addr, unsigned offset)
+{
+ return readl(addr + offset);
+}
+
+static inline void omap_pipe3_writel(void __iomem *addr, unsigned offset,
+ u32 data)
+{
+ writel(data, addr + offset);
+}
+
+static struct pipe3_dpll_params *omap_pipe3_get_dpll_params(struct omap_pipe3
+ *pipe3)
+{
+ u32 rate;
+ struct pipe3_dpll_map *dpll_map = pipe3->dpll_map;
+
+ rate = get_sys_clk_freq();
+
+ for (; dpll_map->rate; dpll_map++) {
+ if (rate == dpll_map->rate)
+ return &dpll_map->params;
+ }
+
+ printf("%s: No DPLL configuration for %u Hz SYS CLK\n",
+ __func__, rate);
+ return NULL;
+}
+
+static int omap_pipe3_wait_lock(struct omap_pipe3 *pipe3)
+{
+ u32 val;
+ int timeout = PLL_LOCK_TIME;
+
+ do {
+ mdelay(1);
+ val = omap_pipe3_readl(pipe3->pll_ctrl_base, PLL_STATUS);
+ if (val & PLL_LOCK)
+ break;
+ } while (--timeout);
+
+ if (!(val & PLL_LOCK)) {
+ printf("%s: DPLL failed to lock\n", __func__);
+ return -EBUSY;
+ }
+
+ return 0;
+}
+
+static int omap_pipe3_dpll_program(struct omap_pipe3 *pipe3)
+{
+ u32 val;
+ struct pipe3_dpll_params *dpll_params;
+
+ dpll_params = omap_pipe3_get_dpll_params(pipe3);
+ if (!dpll_params) {
+ printf("%s: Invalid DPLL parameters\n", __func__);
+ return -EINVAL;
+ }
+
+ val = omap_pipe3_readl(pipe3->pll_ctrl_base, PLL_CONFIGURATION1);
+ val &= ~PLL_REGN_MASK;
+ val |= dpll_params->n << PLL_REGN_SHIFT;
+ omap_pipe3_writel(pipe3->pll_ctrl_base, PLL_CONFIGURATION1, val);
+
+ val = omap_pipe3_readl(pipe3->pll_ctrl_base, PLL_CONFIGURATION2);
+ val &= ~PLL_SELFREQDCO_MASK;
+ val |= dpll_params->freq << PLL_SELFREQDCO_SHIFT;
+ omap_pipe3_writel(pipe3->pll_ctrl_base, PLL_CONFIGURATION2, val);
+
+ val = omap_pipe3_readl(pipe3->pll_ctrl_base, PLL_CONFIGURATION1);
+ val &= ~PLL_REGM_MASK;
+ val |= dpll_params->m << PLL_REGM_SHIFT;
+ omap_pipe3_writel(pipe3->pll_ctrl_base, PLL_CONFIGURATION1, val);
+
+ val = omap_pipe3_readl(pipe3->pll_ctrl_base, PLL_CONFIGURATION4);
+ val &= ~PLL_REGM_F_MASK;
+ val |= dpll_params->mf << PLL_REGM_F_SHIFT;
+ omap_pipe3_writel(pipe3->pll_ctrl_base, PLL_CONFIGURATION4, val);
+
+ val = omap_pipe3_readl(pipe3->pll_ctrl_base, PLL_CONFIGURATION3);
+ val &= ~PLL_SD_MASK;
+ val |= dpll_params->sd << PLL_SD_SHIFT;
+ omap_pipe3_writel(pipe3->pll_ctrl_base, PLL_CONFIGURATION3, val);
+
+ omap_pipe3_writel(pipe3->pll_ctrl_base, PLL_GO, SET_PLL_GO);
+
+ return omap_pipe3_wait_lock(pipe3);
+}
+
+static void omap_control_pipe3_power(struct omap_pipe3 *pipe3, int on)
+{
+ u32 val, rate;
+
+ val = readl(pipe3->power_reg);
+
+ rate = get_sys_clk_freq();
+ rate = rate/1000000;
+
+ if (on) {
+ val &= ~(OMAP_CTRL_PIPE3_PHY_PWRCTL_CLK_CMD_MASK |
+ OMAP_CTRL_PIPE3_PHY_PWRCTL_CLK_FREQ_MASK);
+ val |= OMAP_CTRL_PIPE3_PHY_TX_RX_POWERON <<
+ OMAP_CTRL_PIPE3_PHY_PWRCTL_CLK_CMD_SHIFT;
+ val |= rate <<
+ OMAP_CTRL_PIPE3_PHY_PWRCTL_CLK_FREQ_SHIFT;
+ } else {
+ val &= ~OMAP_CTRL_PIPE3_PHY_PWRCTL_CLK_CMD_MASK;
+ val |= OMAP_CTRL_PIPE3_PHY_TX_RX_POWEROFF <<
+ OMAP_CTRL_PIPE3_PHY_PWRCTL_CLK_CMD_SHIFT;
+ }
+
+ writel(val, pipe3->power_reg);
+}
+
+static int pipe3_init(struct phy *phy)
+{
+ int ret;
+ u32 val;
+ struct omap_pipe3 *pipe3 = dev_get_priv(phy->dev);
+
+ /* Program the DPLL only if not locked */
+ val = omap_pipe3_readl(pipe3->pll_ctrl_base, PLL_STATUS);
+ if (!(val & PLL_LOCK)) {
+ ret = omap_pipe3_dpll_program(pipe3);
+ if (ret)
+ return ret;
+ } else {
+ /* else just bring it out of IDLE mode */
+ val = omap_pipe3_readl(pipe3->pll_ctrl_base,
+ PLL_CONFIGURATION2);
+ if (val & PLL_IDLE) {
+ val &= ~PLL_IDLE;
+ omap_pipe3_writel(pipe3->pll_ctrl_base,
+ PLL_CONFIGURATION2, val);
+ ret = omap_pipe3_wait_lock(pipe3);
+ if (ret)
+ return ret;
+ }
+ }
+ return 0;
+}
+
+static int pipe3_power_on(struct phy *phy)
+{
+ struct omap_pipe3 *pipe3 = dev_get_priv(phy->dev);
+
+ /* Power up the PHY */
+ omap_control_pipe3_power(pipe3, 1);
+
+ return 0;
+}
+
+static int pipe3_power_off(struct phy *phy)
+{
+ struct omap_pipe3 *pipe3 = dev_get_priv(phy->dev);
+
+ /* Power down the PHY */
+ omap_control_pipe3_power(pipe3, 0);
+
+ return 0;
+}
+
+static int pipe3_exit(struct phy *phy)
+{
+ u32 val;
+ int timeout = PLL_IDLE_TIME;
+ struct omap_pipe3 *pipe3 = dev_get_priv(phy->dev);
+
+ pipe3_power_off(phy);
+
+ /* Put DPLL in IDLE mode */
+ val = omap_pipe3_readl(pipe3->pll_ctrl_base, PLL_CONFIGURATION2);
+ val |= PLL_IDLE;
+ omap_pipe3_writel(pipe3->pll_ctrl_base, PLL_CONFIGURATION2, val);
+
+ /* wait for LDO and Oscillator to power down */
+ do {
+ mdelay(1);
+ val = omap_pipe3_readl(pipe3->pll_ctrl_base, PLL_STATUS);
+ if ((val & PLL_TICOPWDN) && (val & PLL_LDOPWDN))
+ break;
+ } while (--timeout);
+
+ if (!(val & PLL_TICOPWDN) || !(val & PLL_LDOPWDN)) {
+ error("%s: Failed to power down DPLL: PLL_STATUS 0x%x\n",
+ __func__, val);
+ return -EBUSY;
+ }
+
+ val = readl(pipe3->pll_reset_reg);
+ writel(val | SATA_PLL_SOFT_RESET, pipe3->pll_reset_reg);
+ mdelay(1);
+ writel(val & ~SATA_PLL_SOFT_RESET, pipe3->pll_reset_reg);
+ return 0;
+}
+
+static void *get_reg(struct udevice *dev, const char *name)
+{
+ struct udevice *syscon;
+ struct regmap *regmap;
+ const fdt32_t *cell;
+ int len, err;
+ void *base;
+
+ err = uclass_get_device_by_phandle(UCLASS_SYSCON, dev,
+ name, &syscon);
+ if (err) {
+ error("unable to find syscon device for %s (%d)\n",
+ name, err);
+ return NULL;
+ }
+
+ regmap = syscon_get_regmap(syscon);
+ if (IS_ERR(regmap)) {
+ error("unable to find regmap for %s (%ld)\n",
+ name, PTR_ERR(regmap));
+ return NULL;
+ }
+
+ cell = fdt_getprop(gd->fdt_blob, dev->of_offset, name,
+ &len);
+ if (len < 2*sizeof(fdt32_t)) {
+ error("offset not available for %s\n", name);
+ return NULL;
+ }
+
+ base = regmap_get_range(regmap, 0);
+ if (!base)
+ return NULL;
+
+ return fdtdec_get_number(cell + 1, 1) + base;
+}
+
+static int pipe3_phy_probe(struct udevice *dev)
+{
+ fdt_addr_t addr;
+ fdt_size_t sz;
+ struct omap_pipe3 *pipe3 = dev_get_priv(dev);
+
+ addr = dev_get_addr_size_index(dev, 2, &sz);
+ if (addr == FDT_ADDR_T_NONE) {
+ error("missing pll ctrl address\n");
+ return -EINVAL;
+ }
+
+ pipe3->pll_ctrl_base = map_physmem(addr, sz, MAP_NOCACHE);
+ if (!pipe3->pll_ctrl_base) {
+ error("unable to remap pll ctrl\n");
+ return -EINVAL;
+ }
+
+ pipe3->power_reg = get_reg(dev, "syscon-phy-power");
+ if (!pipe3->power_reg)
+ return -EINVAL;
+
+ pipe3->pll_reset_reg = get_reg(dev, "syscon-pllreset");
+ if (!pipe3->pll_reset_reg)
+ return -EINVAL;
+
+ pipe3->dpll_map = (struct pipe3_dpll_map *)dev_get_driver_data(dev);
+
+ return 0;
+}
+
+static struct pipe3_dpll_map dpll_map_sata[] = {
+ {12000000, {1000, 7, 4, 6, 0} }, /* 12 MHz */
+ {16800000, {714, 7, 4, 6, 0} }, /* 16.8 MHz */
+ {19200000, {625, 7, 4, 6, 0} }, /* 19.2 MHz */
+ {20000000, {600, 7, 4, 6, 0} }, /* 20 MHz */
+ {26000000, {461, 7, 4, 6, 0} }, /* 26 MHz */
+ {38400000, {312, 7, 4, 6, 0} }, /* 38.4 MHz */
+ { }, /* Terminator */
+};
+
+static const struct udevice_id pipe3_phy_ids[] = {
+ { .compatible = "ti,phy-pipe3-sata", .data = (ulong)&dpll_map_sata },
+ { }
+};
+
+static struct phy_ops pipe3_phy_ops = {
+ .init = pipe3_init,
+ .power_on = pipe3_power_on,
+ .power_off = pipe3_power_off,
+ .exit = pipe3_exit,
+};
+
+U_BOOT_DRIVER(pipe3_phy) = {
+ .name = "pipe3_phy",
+ .id = UCLASS_PHY,
+ .of_match = pipe3_phy_ids,
+ .ops = &pipe3_phy_ops,
+ .probe = pipe3_phy_probe,
+ .priv_auto_alloc_size = sizeof(struct omap_pipe3),
+};
diff --git a/drivers/pinctrl/nxp/pinctrl-imx.c b/drivers/pinctrl/nxp/pinctrl-imx.c
index f0321c40576..ebc14a31f1e 100644
--- a/drivers/pinctrl/nxp/pinctrl-imx.c
+++ b/drivers/pinctrl/nxp/pinctrl-imx.c
@@ -53,6 +53,7 @@ static int imx_pinctrl_set_state(struct udevice *dev, struct udevice *config)
if (fdtdec_get_int_array(gd->fdt_blob, node, "fsl,pins",
pin_data, size >> 2)) {
dev_err(dev, "Error reading pin data.\n");
+ devm_kfree(dev, pin_data);
return -EINVAL;
}
@@ -78,6 +79,7 @@ static int imx_pinctrl_set_state(struct udevice *dev, struct udevice *config)
if ((mux_reg == -1) || (conf_reg == -1)) {
dev_err(dev, "Error mux_reg or conf_reg\n");
+ devm_kfree(dev, pin_data);
return -EINVAL;
}
@@ -166,6 +168,8 @@ static int imx_pinctrl_set_state(struct udevice *dev, struct udevice *config)
}
}
+ devm_kfree(dev, pin_data);
+
return 0;
}
diff --git a/drivers/pinctrl/pinctrl-single.c b/drivers/pinctrl/pinctrl-single.c
index d2dcec0d135..f19f7791f07 100644
--- a/drivers/pinctrl/pinctrl-single.c
+++ b/drivers/pinctrl/pinctrl-single.c
@@ -47,27 +47,27 @@ static int single_configure_pins(struct udevice *dev,
int n, reg;
u32 val;
- for (n = 0; n < count; n++) {
+ for (n = 0; n < count; n++, pins++) {
reg = fdt32_to_cpu(pins->reg);
if ((reg < 0) || (reg > pdata->offset)) {
dev_dbg(dev, " invalid register offset 0x%08x\n", reg);
- pins++;
continue;
}
reg += pdata->base;
+ val = fdt32_to_cpu(pins->val) & pdata->mask;
switch (pdata->width) {
+ case 16:
+ writew((readw(reg) & ~pdata->mask) | val, reg);
+ break;
case 32:
- val = readl(reg) & ~pdata->mask;
- val |= fdt32_to_cpu(pins->val) & pdata->mask;
- writel(val, reg);
- dev_dbg(dev, " reg/val 0x%08x/0x%08x\n",
- reg, val);
+ writel((readl(reg) & ~pdata->mask) | val, reg);
break;
default:
dev_warn(dev, "unsupported register width %i\n",
pdata->width);
+ continue;
}
- pins++;
+ dev_dbg(dev, " reg/val 0x%08x/0x%08x\n",reg, val);
}
return 0;
}
diff --git a/drivers/pinctrl/rockchip/pinctrl_rk3399.c b/drivers/pinctrl/rockchip/pinctrl_rk3399.c
index 507bec4a969..d93b90310b0 100644
--- a/drivers/pinctrl/rockchip/pinctrl_rk3399.c
+++ b/drivers/pinctrl/rockchip/pinctrl_rk3399.c
@@ -145,7 +145,19 @@ static int pinctrl_rk3399_spi_config(struct rk3399_grf_regs *grf,
| GRF_SPI2TPM_CLK << GRF_GPIO2B3_SEL_SHIFT
| GRF_SPI2TPM_CSN0 << GRF_GPIO2B4_SEL_SHIFT);
break;
+ case PERIPH_ID_SPI5:
+ if (cs != 0)
+ goto err;
+ rk_clrsetreg(&grf->gpio2c_iomux,
+ GRF_GPIO2C4_SEL_MASK | GRF_GPIO2C5_SEL_MASK
+ | GRF_GPIO2C6_SEL_MASK | GRF_GPIO2C7_SEL_MASK,
+ GRF_SPI5EXPPLUS_RXD << GRF_GPIO2C4_SEL_SHIFT
+ | GRF_SPI5EXPPLUS_TXD << GRF_GPIO2C5_SEL_SHIFT
+ | GRF_SPI5EXPPLUS_CLK << GRF_GPIO2C6_SEL_SHIFT
+ | GRF_SPI5EXPPLUS_CSN0 << GRF_GPIO2C7_SEL_SHIFT);
+ break;
default:
+ printf("%s: spi_id %d is not supported.\n", __func__, spi_id);
goto err;
}
@@ -232,6 +244,41 @@ static void pinctrl_rk3399_gmac_config(struct rk3399_grf_regs *grf, int mmc_id)
rk_clrsetreg(&grf->gpio3c_iomux,
GRF_GPIO3C1_SEL_MASK,
GRF_MAC_TXCLK << GRF_GPIO3C1_SEL_SHIFT);
+
+ /* Set drive strength for GMAC tx io, value 3 means 13mA */
+ rk_clrsetreg(&grf->gpio3_e[0],
+ GRF_GPIO3A0_E_MASK | GRF_GPIO3A1_E_MASK |
+ GRF_GPIO3A4_E_MASK | GRF_GPIO3A5_E0_MASK,
+ 3 << GRF_GPIO3A0_E_SHIFT |
+ 3 << GRF_GPIO3A1_E_SHIFT |
+ 3 << GRF_GPIO3A4_E_SHIFT |
+ 1 << GRF_GPIO3A5_E0_SHIFT);
+ rk_clrsetreg(&grf->gpio3_e[1],
+ GRF_GPIO3A5_E12_MASK,
+ 1 << GRF_GPIO3A5_E12_SHIFT);
+ rk_clrsetreg(&grf->gpio3_e[2],
+ GRF_GPIO3B4_E_MASK,
+ 3 << GRF_GPIO3B4_E_SHIFT);
+ rk_clrsetreg(&grf->gpio3_e[4],
+ GRF_GPIO3C1_E_MASK,
+ 3 << GRF_GPIO3C1_E_SHIFT);
+}
+#endif
+
+#if !defined(CONFIG_SPL_BUILD)
+static void pinctrl_rk3399_hdmi_config(struct rk3399_grf_regs *grf, int hdmi_id)
+{
+ switch (hdmi_id) {
+ case PERIPH_ID_HDMI:
+ rk_clrsetreg(&grf->gpio4c_iomux,
+ GRF_GPIO4C0_SEL_MASK | GRF_GPIO4C1_SEL_MASK,
+ (GRF_HDMII2C_SCL << GRF_GPIO4C0_SEL_SHIFT) |
+ (GRF_HDMII2C_SDA << GRF_GPIO4C1_SEL_SHIFT));
+ break;
+ default:
+ debug("%s: hdmi_id = %d unsupported\n", __func__, hdmi_id);
+ break;
+ }
}
#endif
@@ -259,6 +306,9 @@ static int rk3399_pinctrl_request(struct udevice *dev, int func, int flags)
case PERIPH_ID_SPI0:
case PERIPH_ID_SPI1:
case PERIPH_ID_SPI2:
+ case PERIPH_ID_SPI3:
+ case PERIPH_ID_SPI4:
+ case PERIPH_ID_SPI5:
pinctrl_rk3399_spi_config(priv->grf, priv->pmugrf, func, flags);
break;
case PERIPH_ID_UART0:
@@ -281,6 +331,11 @@ static int rk3399_pinctrl_request(struct udevice *dev, int func, int flags)
pinctrl_rk3399_gmac_config(priv->grf, func);
break;
#endif
+#if !defined(CONFIG_SPL_BUILD)
+ case PERIPH_ID_HDMI:
+ pinctrl_rk3399_hdmi_config(priv->grf, func);
+ break;
+#endif
default:
return -EINVAL;
}
@@ -307,6 +362,8 @@ static int rk3399_pinctrl_get_periph_id(struct udevice *dev,
return PERIPH_ID_SPI1;
case 52:
return PERIPH_ID_SPI2;
+ case 132:
+ return PERIPH_ID_SPI5;
case 57:
return PERIPH_ID_I2C0;
case 59: /* Note strange order */
@@ -325,6 +382,10 @@ static int rk3399_pinctrl_get_periph_id(struct udevice *dev,
case 12:
return PERIPH_ID_GMAC;
#endif
+#if !defined(CONFIG_SPL_BUILD)
+ case 23:
+ return PERIPH_ID_HDMI;
+#endif
}
#endif
return -ENOENT;
diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig
index 911ecb1144a..d8c107e2069 100644
--- a/drivers/power/Kconfig
+++ b/drivers/power/Kconfig
@@ -308,4 +308,12 @@ config SY8106A_VOUT1_VOLT
is typically used to power the VDD-CPU and should be 1200mV.
Values can range from 680mV till 1950mV.
+config TWL4030_POWER
+ depends on OMAP34XX
+ bool "Enable driver for TI TWL4030 power management chip"
+ imply CMD_POWEROFF
+ ---help---
+ The TWL4030 in a combination audio CODEC/power management with
+ GPIO and it is commonly used with the OMAP3 family of processors
+
endmenu
diff --git a/drivers/power/domain/Kconfig b/drivers/power/domain/Kconfig
index 132e33250e8..7cfa7614987 100644
--- a/drivers/power/domain/Kconfig
+++ b/drivers/power/domain/Kconfig
@@ -9,6 +9,13 @@ config POWER_DOMAIN
domains). This may be used to save power. This API provides the
means to control such power management hardware.
+config BCM6328_POWER_DOMAIN
+ bool "Enable the BCM6328 power domain driver"
+ depends on POWER_DOMAIN && ARCH_BMIPS
+ help
+ Enable support for manipulating BCM6345 power domains via MMIO
+ mapped registers.
+
config SANDBOX_POWER_DOMAIN
bool "Enable the sandbox power domain test driver"
depends on POWER_DOMAIN && SANDBOX
diff --git a/drivers/power/domain/Makefile b/drivers/power/domain/Makefile
index 2c3d92638fb..c7d76444020 100644
--- a/drivers/power/domain/Makefile
+++ b/drivers/power/domain/Makefile
@@ -3,6 +3,7 @@
# SPDX-License-Identifier: GPL-2.0
obj-$(CONFIG_POWER_DOMAIN) += power-domain-uclass.o
+obj-$(CONFIG_BCM6328_POWER_DOMAIN) += bcm6328-power-domain.o
obj-$(CONFIG_SANDBOX_POWER_DOMAIN) += sandbox-power-domain.o
obj-$(CONFIG_SANDBOX_POWER_DOMAIN) += sandbox-power-domain-test.o
obj-$(CONFIG_TEGRA186_POWER_DOMAIN) += tegra186-power-domain.o
diff --git a/drivers/power/domain/bcm6328-power-domain.c b/drivers/power/domain/bcm6328-power-domain.c
new file mode 100644
index 00000000000..15638bf3bad
--- /dev/null
+++ b/drivers/power/domain/bcm6328-power-domain.c
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2017 Álvaro Fernández Rojas <noltari@gmail.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <power-domain-uclass.h>
+#include <asm/io.h>
+
+#define MAX_DOMAINS 32
+
+struct bcm6328_power_domain {
+ void __iomem *regs;
+};
+
+static int bcm6328_power_domain_request(struct power_domain *power_domain)
+{
+ if (power_domain->id >= MAX_DOMAINS)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int bcm6328_power_domain_free(struct power_domain *power_domain)
+{
+ return 0;
+}
+
+static int bcm6328_power_domain_on(struct power_domain *power_domain)
+{
+ struct bcm6328_power_domain *priv = dev_get_priv(power_domain->dev);
+
+ clrbits_be32(priv->regs, BIT(power_domain->id));
+
+ return 0;
+}
+
+static int bcm6328_power_domain_off(struct power_domain *power_domain)
+{
+ struct bcm6328_power_domain *priv = dev_get_priv(power_domain->dev);
+
+ setbits_be32(priv->regs, BIT(power_domain->id));
+
+ return 0;
+}
+
+static int bcm6328_power_domain_probe(struct udevice *dev)
+{
+ struct bcm6328_power_domain *priv = dev_get_priv(dev);
+ fdt_addr_t addr;
+ fdt_size_t size;
+
+ addr = dev_get_addr_size_index(dev, 0, &size);
+ if (addr == FDT_ADDR_T_NONE)
+ return -EINVAL;
+
+ priv->regs = ioremap(addr, size);
+
+ return 0;
+}
+
+static const struct udevice_id bcm6328_power_domain_ids[] = {
+ { .compatible = "brcm,bcm6328-power-domain" },
+ { /* sentinel */ }
+};
+
+struct power_domain_ops bcm6328_power_domain_ops = {
+ .free = bcm6328_power_domain_free,
+ .off = bcm6328_power_domain_off,
+ .on = bcm6328_power_domain_on,
+ .request = bcm6328_power_domain_request,
+};
+
+U_BOOT_DRIVER(bcm6328_power_domain) = {
+ .name = "bcm6328_power_domain",
+ .id = UCLASS_POWER_DOMAIN,
+ .of_match = bcm6328_power_domain_ids,
+ .ops = &bcm6328_power_domain_ops,
+ .priv_auto_alloc_size = sizeof(struct bcm6328_power_domain),
+ .probe = bcm6328_power_domain_probe,
+};
diff --git a/drivers/power/pmic/Kconfig b/drivers/power/pmic/Kconfig
index 4891b1704e8..3f50c121571 100644
--- a/drivers/power/pmic/Kconfig
+++ b/drivers/power/pmic/Kconfig
@@ -28,7 +28,7 @@ config SPL_PMIC_CHILDREN
This allows PMICs to support child devices (such as regulators) in
SPL. This adds quite a bit of code so if you are not using this
feature you can turn it off. In this case you may need a 'back door'
- to call your regulator code (e.g. see rk808.c for direct functions
+ to call your regulator code (e.g. see rk8xx.c for direct functions
for use in SPL).
config PMIC_ACT8846
@@ -100,8 +100,8 @@ config PMIC_PM8916
Driver binding info: doc/device-tree-bindings/pmic/pm8916.txt
-config PMIC_RK808
- bool "Enable support for Rockchip PMIC RK808"
+config PMIC_RK8XX
+ bool "Enable support for Rockchip PMIC RK8XX"
depends on DM_PMIC
---help---
The Rockchip RK808 PMIC provides four buck DC-DC convertors, 8 LDOs,
diff --git a/drivers/power/pmic/Makefile b/drivers/power/pmic/Makefile
index 5f1bef33cdd..f409e3a0b36 100644
--- a/drivers/power/pmic/Makefile
+++ b/drivers/power/pmic/Makefile
@@ -15,7 +15,7 @@ obj-$(CONFIG_PMIC_ACT8846) += act8846.o
obj-$(CONFIG_PMIC_AS3722) += as3722.o
obj-$(CONFIG_PMIC_MAX8997) += max8997.o
obj-$(CONFIG_PMIC_PM8916) += pm8916.o
-obj-$(CONFIG_PMIC_RK808) += rk808.o
+obj-$(CONFIG_PMIC_RK8XX) += rk8xx.o
obj-$(CONFIG_PMIC_RN5T567) += rn5t567.o
obj-$(CONFIG_PMIC_TPS65090) += tps65090.o
obj-$(CONFIG_PMIC_S5M8767) += s5m8767.o
diff --git a/drivers/power/pmic/rk808.c b/drivers/power/pmic/rk8xx.c
index 3f5f316b56f..394e2ff9db3 100644
--- a/drivers/power/pmic/rk808.c
+++ b/drivers/power/pmic/rk8xx.c
@@ -10,24 +10,24 @@
#include <errno.h>
#include <fdtdec.h>
#include <libfdt.h>
-#include <power/rk808_pmic.h>
+#include <power/rk8xx_pmic.h>
#include <power/pmic.h>
DECLARE_GLOBAL_DATA_PTR;
static const struct pmic_child_info pmic_children_info[] = {
- { .prefix = "DCDC_REG", .driver = "rk808_buck"},
- { .prefix = "LDO_REG", .driver = "rk808_ldo"},
- { .prefix = "SWITCH_REG", .driver = "rk808_switch"},
+ { .prefix = "DCDC_REG", .driver = "rk8xx_buck"},
+ { .prefix = "LDO_REG", .driver = "rk8xx_ldo"},
+ { .prefix = "SWITCH_REG", .driver = "rk8xx_switch"},
{ },
};
-static int rk808_reg_count(struct udevice *dev)
+static int rk8xx_reg_count(struct udevice *dev)
{
return RK808_NUM_OF_REGS;
}
-static int rk808_write(struct udevice *dev, uint reg, const uint8_t *buff,
+static int rk8xx_write(struct udevice *dev, uint reg, const uint8_t *buff,
int len)
{
int ret;
@@ -41,7 +41,7 @@ static int rk808_write(struct udevice *dev, uint reg, const uint8_t *buff,
return 0;
}
-static int rk808_read(struct udevice *dev, uint reg, uint8_t *buff, int len)
+static int rk8xx_read(struct udevice *dev, uint reg, uint8_t *buff, int len)
{
int ret;
@@ -55,7 +55,7 @@ static int rk808_read(struct udevice *dev, uint reg, uint8_t *buff, int len)
}
#if CONFIG_IS_ENABLED(PMIC_CHILDREN)
-static int rk808_bind(struct udevice *dev)
+static int rk8xx_bind(struct udevice *dev)
{
const void *blob = gd->fdt_blob;
int regulators_node;
@@ -80,23 +80,39 @@ static int rk808_bind(struct udevice *dev)
}
#endif
-static struct dm_pmic_ops rk808_ops = {
- .reg_count = rk808_reg_count,
- .read = rk808_read,
- .write = rk808_write,
+static int rk8xx_probe(struct udevice *dev)
+{
+ struct rk8xx_priv *priv = dev_get_priv(dev);
+ uint8_t msb, lsb;
+
+ /* read Chip variant */
+ rk8xx_read(dev, ID_MSB, &msb, 1);
+ rk8xx_read(dev, ID_LSB, &lsb, 1);
+
+ priv->variant = ((msb << 8) | lsb) & RK8XX_ID_MSK;
+
+ return 0;
+}
+
+static struct dm_pmic_ops rk8xx_ops = {
+ .reg_count = rk8xx_reg_count,
+ .read = rk8xx_read,
+ .write = rk8xx_write,
};
-static const struct udevice_id rk808_ids[] = {
+static const struct udevice_id rk8xx_ids[] = {
{ .compatible = "rockchip,rk808" },
+ { .compatible = "rockchip,rk818" },
{ }
};
-U_BOOT_DRIVER(pmic_rk808) = {
- .name = "rk808 pmic",
+U_BOOT_DRIVER(pmic_rk8xx) = {
+ .name = "rk8xx pmic",
.id = UCLASS_PMIC,
- .of_match = rk808_ids,
+ .of_match = rk8xx_ids,
#if CONFIG_IS_ENABLED(PMIC_CHILDREN)
- .bind = rk808_bind,
+ .bind = rk8xx_bind,
#endif
- .ops = &rk808_ops,
+ .probe = rk8xx_probe,
+ .ops = &rk8xx_ops,
};
diff --git a/drivers/power/regulator/Kconfig b/drivers/power/regulator/Kconfig
index f870e8bcc9f..ef057e0e2fb 100644
--- a/drivers/power/regulator/Kconfig
+++ b/drivers/power/regulator/Kconfig
@@ -76,11 +76,11 @@ config DM_REGULATOR_GPIO
features for gpio regulators. The driver implements get/set for
voltage value.
-config REGULATOR_RK808
- bool "Enable driver for RK808 regulators"
- depends on DM_REGULATOR && PMIC_RK808
+config REGULATOR_RK8XX
+ bool "Enable driver for RK8XX regulators"
+ depends on DM_REGULATOR && PMIC_RK8XX
---help---
- Enable support for the regulator functions of the RK808 PMIC. The
+ Enable support for the regulator functions of the RK8XX PMIC. The
driver implements get/set api for the various BUCKS and LDOs supported
by the PMIC device. This driver is controlled by a device tree node
which includes voltage limits.
diff --git a/drivers/power/regulator/Makefile b/drivers/power/regulator/Makefile
index 6002c88a6c1..3e01021b76a 100644
--- a/drivers/power/regulator/Makefile
+++ b/drivers/power/regulator/Makefile
@@ -12,7 +12,7 @@ obj-$(CONFIG_DM_REGULATOR_PFUZE100) += pfuze100.o
obj-$(CONFIG_REGULATOR_PWM) += pwm_regulator.o
obj-$(CONFIG_$(SPL_)DM_REGULATOR_FIXED) += fixed.o
obj-$(CONFIG_$(SPL_)DM_REGULATOR_GPIO) += gpio-regulator.o
-obj-$(CONFIG_REGULATOR_RK808) += rk808.o
+obj-$(CONFIG_REGULATOR_RK8XX) += rk8xx.o
obj-$(CONFIG_REGULATOR_S5M8767) += s5m8767.o
obj-$(CONFIG_DM_REGULATOR_SANDBOX) += sandbox.o
obj-$(CONFIG_REGULATOR_TPS65090) += tps65090_regulator.o
diff --git a/drivers/power/regulator/pwm_regulator.c b/drivers/power/regulator/pwm_regulator.c
index 4875238e43d..a6c9fccd68e 100644
--- a/drivers/power/regulator/pwm_regulator.c
+++ b/drivers/power/regulator/pwm_regulator.c
@@ -24,6 +24,12 @@ struct pwm_regulator_info {
int pwm_id;
/* the period of one PWM cycle */
int period_ns;
+ /*
+ * the polarity of one PWM
+ * 0: normal polarity
+ * 1: inverted polarity
+ */
+ bool polarity;
struct udevice *pwm;
/* initialize voltage of regulator */
unsigned int init_voltage;
@@ -49,7 +55,7 @@ static int pwm_voltage_to_duty_cycle_percentage(struct udevice *dev, int req_uV)
int max_uV = priv->max_voltage;
int diff = max_uV - min_uV;
- return 100 - (((req_uV * 100) - (min_uV * 100)) / diff);
+ return ((req_uV * 100) - (min_uV * 100)) / diff;
}
static int pwm_regulator_get_voltage(struct udevice *dev)
@@ -67,6 +73,12 @@ static int pwm_regulator_set_voltage(struct udevice *dev, int uvolt)
duty_cycle = pwm_voltage_to_duty_cycle_percentage(dev, uvolt);
+ ret = pwm_set_invert(priv->pwm, priv->pwm_id, priv->polarity);
+ if (ret) {
+ dev_err(dev, "Failed to init PWM\n");
+ return ret;
+ }
+
ret = pwm_set_config(priv->pwm, priv->pwm_id,
(priv->period_ns / 100) * duty_cycle, priv->period_ns);
if (ret) {
@@ -97,9 +109,9 @@ static int pwm_regulator_ofdata_to_platdata(struct udevice *dev)
debug("%s: Cannot get PWM phandle: ret=%d\n", __func__, ret);
return ret;
}
- /* TODO: pwm_id here from device tree if needed */
priv->period_ns = args.args[1];
+ priv->polarity = args.args[2];
priv->init_voltage = fdtdec_get_int(blob, node,
"regulator-init-microvolt", -1);
diff --git a/drivers/power/regulator/rk808.c b/drivers/power/regulator/rk8xx.c
index adef8f57f27..e655c2d91f5 100644
--- a/drivers/power/regulator/rk808.c
+++ b/drivers/power/regulator/rk8xx.c
@@ -12,7 +12,7 @@
#include <common.h>
#include <dm.h>
#include <errno.h>
-#include <power/rk808_pmic.h>
+#include <power/rk8xx_pmic.h>
#include <power/pmic.h>
#include <power/regulator.h>
@@ -20,36 +20,88 @@
#define ENABLE_DRIVER
#endif
-struct rk808_reg_info {
+/* Field Definitions */
+#define RK808_BUCK_VSEL_MASK 0x3f
+#define RK808_BUCK4_VSEL_MASK 0xf
+#define RK808_LDO_VSEL_MASK 0x1f
+
+#define RK818_BUCK_VSEL_MASK 0x3f
+#define RK818_BUCK4_VSEL_MASK 0x1f
+#define RK818_LDO_VSEL_MASK 0x1f
+#define RK818_LDO3_ON_VSEL_MASK 0xf
+#define RK818_BOOST_ON_VSEL_MASK 0xe0
+
+struct rk8xx_reg_info {
uint min_uv;
uint step_uv;
s8 vsel_reg;
- u8 vsel_bits;
+ u8 vsel_mask;
+};
+
+static const struct rk8xx_reg_info rk808_buck[] = {
+ { 712500, 12500, REG_BUCK1_ON_VSEL, RK808_BUCK_VSEL_MASK, },
+ { 712500, 12500, REG_BUCK2_ON_VSEL, RK808_BUCK_VSEL_MASK, },
+ { 712500, 12500, -1, RK808_BUCK_VSEL_MASK, },
+ { 1800000, 100000, REG_BUCK4_ON_VSEL, RK808_BUCK4_VSEL_MASK, },
};
-static const struct rk808_reg_info rk808_buck[] = {
- { 712500, 12500, REG_BUCK1_ON_VSEL, 6, },
- { 712500, 12500, REG_BUCK2_ON_VSEL, 6, },
- { 712500, 12500, -1, 6, },
- { 1800000, 100000, REG_BUCK4_ON_VSEL, 4, },
+static const struct rk8xx_reg_info rk808_ldo[] = {
+ { 1800000, 100000, REG_LDO1_ON_VSEL, RK808_LDO_VSEL_MASK, },
+ { 1800000, 100000, REG_LDO2_ON_VSEL, RK808_LDO_VSEL_MASK, },
+ { 800000, 100000, REG_LDO3_ON_VSEL, RK808_BUCK4_VSEL_MASK, },
+ { 1800000, 100000, REG_LDO4_ON_VSEL, RK808_LDO_VSEL_MASK, },
+ { 1800000, 100000, REG_LDO5_ON_VSEL, RK808_LDO_VSEL_MASK, },
+ { 800000, 100000, REG_LDO6_ON_VSEL, RK808_LDO_VSEL_MASK, },
+ { 800000, 100000, REG_LDO7_ON_VSEL, RK808_LDO_VSEL_MASK, },
+ { 1800000, 100000, REG_LDO8_ON_VSEL, RK808_LDO_VSEL_MASK, },
};
-static const struct rk808_reg_info rk808_ldo[] = {
- { 1800000, 100000, LDO1_ON_VSEL, 5, },
- { 1800000, 100000, LDO2_ON_VSEL, 5, },
- { 800000, 100000, LDO3_ON_VSEL, 4, },
- { 1800000, 100000, LDO4_ON_VSEL, 5, },
- { 1800000, 100000, LDO5_ON_VSEL, 5, },
- { 800000, 100000, LDO6_ON_VSEL, 5, },
- { 800000, 100000, LDO7_ON_VSEL, 5, },
- { 1800000, 100000, LDO8_ON_VSEL, 5, },
+static const struct rk8xx_reg_info rk818_buck[] = {
+ { 712500, 12500, REG_BUCK1_ON_VSEL, RK818_BUCK_VSEL_MASK, },
+ { 712500, 12500, REG_BUCK2_ON_VSEL, RK818_BUCK_VSEL_MASK, },
+ { 712500, 12500, -1, RK818_BUCK_VSEL_MASK, },
+ { 1800000, 100000, REG_BUCK4_ON_VSEL, RK818_BUCK4_VSEL_MASK, },
};
+static const struct rk8xx_reg_info rk818_ldo[] = {
+ { 1800000, 100000, REG_LDO1_ON_VSEL, RK818_LDO_VSEL_MASK, },
+ { 1800000, 100000, REG_LDO2_ON_VSEL, RK818_LDO_VSEL_MASK, },
+ { 800000, 100000, REG_LDO3_ON_VSEL, RK818_LDO3_ON_VSEL_MASK, },
+ { 1800000, 100000, REG_LDO4_ON_VSEL, RK818_LDO_VSEL_MASK, },
+ { 1800000, 100000, REG_LDO5_ON_VSEL, RK818_LDO_VSEL_MASK, },
+ { 800000, 100000, REG_LDO6_ON_VSEL, RK818_LDO_VSEL_MASK, },
+ { 800000, 100000, REG_LDO7_ON_VSEL, RK818_LDO_VSEL_MASK, },
+ { 1800000, 100000, REG_LDO8_ON_VSEL, RK818_LDO_VSEL_MASK, },
+};
+
+static const struct rk8xx_reg_info *get_buck_reg(struct udevice *pmic,
+ int num)
+{
+ struct rk8xx_priv *priv = dev_get_priv(pmic);
+ switch (priv->variant) {
+ case RK818_ID:
+ return &rk818_buck[num];
+ default:
+ return &rk808_buck[num];
+ }
+}
+
+static const struct rk8xx_reg_info *get_ldo_reg(struct udevice *pmic,
+ int num)
+{
+ struct rk8xx_priv *priv = dev_get_priv(pmic);
+ switch (priv->variant) {
+ case RK818_ID:
+ return &rk818_ldo[num - 1];
+ default:
+ return &rk808_ldo[num - 1];
+ }
+}
static int _buck_set_value(struct udevice *pmic, int buck, int uvolt)
{
- const struct rk808_reg_info *info = &rk808_buck[buck - 1];
- int mask = (1 << info->vsel_bits) - 1;
+ const struct rk8xx_reg_info *info = get_buck_reg(pmic, buck - 1);
+ int mask = info->vsel_mask;
int val;
if (info->vsel_reg == -1)
@@ -69,7 +121,7 @@ static int _buck_set_enable(struct udevice *pmic, int buck, bool enable)
buck--;
mask = 1 << buck;
if (enable) {
- ret = pmic_clrsetbits(pmic, DCDC_ILMAX, 0, 3 << (buck * 2));
+ ret = pmic_clrsetbits(pmic, REG_DCDC_ILMAX, 0, 3 << (buck * 2));
if (ret)
return ret;
ret = pmic_clrsetbits(pmic, REG_DCDC_UV_ACT, 1 << buck, 0);
@@ -84,8 +136,8 @@ static int _buck_set_enable(struct udevice *pmic, int buck, bool enable)
static int buck_get_value(struct udevice *dev)
{
int buck = dev->driver_data - 1;
- const struct rk808_reg_info *info = &rk808_buck[buck];
- int mask = (1 << info->vsel_bits) - 1;
+ const struct rk8xx_reg_info *info = get_buck_reg(dev->parent, buck);
+ int mask = info->vsel_mask;
int ret, val;
if (info->vsel_reg == -1)
@@ -130,8 +182,8 @@ static bool buck_get_enable(struct udevice *dev)
static int ldo_get_value(struct udevice *dev)
{
int ldo = dev->driver_data - 1;
- const struct rk808_reg_info *info = &rk808_ldo[ldo];
- int mask = (1 << info->vsel_bits) - 1;
+ const struct rk8xx_reg_info *info = get_ldo_reg(dev->parent, ldo);
+ int mask = info->vsel_mask;
int ret, val;
if (info->vsel_reg == -1)
@@ -147,8 +199,8 @@ static int ldo_get_value(struct udevice *dev)
static int ldo_set_value(struct udevice *dev, int uvolt)
{
int ldo = dev->driver_data - 1;
- const struct rk808_reg_info *info = &rk808_ldo[ldo];
- int mask = (1 << info->vsel_bits) - 1;
+ const struct rk8xx_reg_info *info = get_ldo_reg(dev->parent, ldo);
+ int mask = info->vsel_mask;
int val;
if (info->vsel_reg == -1)
@@ -212,7 +264,7 @@ static bool switch_get_enable(struct udevice *dev)
return ret & mask ? true : false;
}
-static int rk808_buck_probe(struct udevice *dev)
+static int rk8xx_buck_probe(struct udevice *dev)
{
struct dm_regulator_uclass_platdata *uc_pdata;
@@ -224,7 +276,7 @@ static int rk808_buck_probe(struct udevice *dev)
return 0;
}
-static int rk808_ldo_probe(struct udevice *dev)
+static int rk8xx_ldo_probe(struct udevice *dev)
{
struct dm_regulator_uclass_platdata *uc_pdata;
@@ -236,7 +288,7 @@ static int rk808_ldo_probe(struct udevice *dev)
return 0;
}
-static int rk808_switch_probe(struct udevice *dev)
+static int rk8xx_switch_probe(struct udevice *dev)
{
struct dm_regulator_uclass_platdata *uc_pdata;
@@ -248,48 +300,48 @@ static int rk808_switch_probe(struct udevice *dev)
return 0;
}
-static const struct dm_regulator_ops rk808_buck_ops = {
+static const struct dm_regulator_ops rk8xx_buck_ops = {
.get_value = buck_get_value,
.set_value = buck_set_value,
.get_enable = buck_get_enable,
.set_enable = buck_set_enable,
};
-static const struct dm_regulator_ops rk808_ldo_ops = {
+static const struct dm_regulator_ops rk8xx_ldo_ops = {
.get_value = ldo_get_value,
.set_value = ldo_set_value,
.get_enable = ldo_get_enable,
.set_enable = ldo_set_enable,
};
-static const struct dm_regulator_ops rk808_switch_ops = {
+static const struct dm_regulator_ops rk8xx_switch_ops = {
.get_enable = switch_get_enable,
.set_enable = switch_set_enable,
};
-U_BOOT_DRIVER(rk808_buck) = {
- .name = "rk808_buck",
+U_BOOT_DRIVER(rk8xx_buck) = {
+ .name = "rk8xx_buck",
.id = UCLASS_REGULATOR,
- .ops = &rk808_buck_ops,
- .probe = rk808_buck_probe,
+ .ops = &rk8xx_buck_ops,
+ .probe = rk8xx_buck_probe,
};
-U_BOOT_DRIVER(rk808_ldo) = {
- .name = "rk808_ldo",
+U_BOOT_DRIVER(rk8xx_ldo) = {
+ .name = "rk8xx_ldo",
.id = UCLASS_REGULATOR,
- .ops = &rk808_ldo_ops,
- .probe = rk808_ldo_probe,
+ .ops = &rk8xx_ldo_ops,
+ .probe = rk8xx_ldo_probe,
};
-U_BOOT_DRIVER(rk808_switch) = {
- .name = "rk808_switch",
+U_BOOT_DRIVER(rk8xx_switch) = {
+ .name = "rk8xx_switch",
.id = UCLASS_REGULATOR,
- .ops = &rk808_switch_ops,
- .probe = rk808_switch_probe,
+ .ops = &rk8xx_switch_ops,
+ .probe = rk8xx_switch_probe,
};
#endif
-int rk808_spl_configure_buck(struct udevice *pmic, int buck, int uvolt)
+int rk8xx_spl_configure_buck(struct udevice *pmic, int buck, int uvolt)
{
int ret;
diff --git a/drivers/power/twl4030.c b/drivers/power/twl4030.c
index 8866bf1b19e..ab98d68dfb7 100644
--- a/drivers/power/twl4030.c
+++ b/drivers/power/twl4030.c
@@ -171,3 +171,12 @@ void twl4030_power_mmc_init(int dev_index)
mdelay(100); /* ramp-up delay from Linux code */
}
}
+
+#ifdef CONFIG_CMD_POWEROFF
+int do_poweroff(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ twl4030_power_off();
+
+ return 0;
+}
+#endif
diff --git a/drivers/pwm/pwm-uclass.c b/drivers/pwm/pwm-uclass.c
index c2200af8a55..69051fe1b56 100644
--- a/drivers/pwm/pwm-uclass.c
+++ b/drivers/pwm/pwm-uclass.c
@@ -9,6 +9,16 @@
#include <dm.h>
#include <pwm.h>
+int pwm_set_invert(struct udevice *dev, uint channel, bool polarity)
+{
+ struct pwm_ops *ops = pwm_get_ops(dev);
+
+ if (!ops->set_invert)
+ return -ENOSYS;
+
+ return ops->set_invert(dev, channel, polarity);
+}
+
int pwm_set_config(struct udevice *dev, uint channel, uint period_ns,
uint duty_ns)
{
diff --git a/drivers/pwm/rk_pwm.c b/drivers/pwm/rk_pwm.c
index 9254f5bc397..f3b2f7615d2 100644
--- a/drivers/pwm/rk_pwm.c
+++ b/drivers/pwm/rk_pwm.c
@@ -21,8 +21,22 @@ DECLARE_GLOBAL_DATA_PTR;
struct rk_pwm_priv {
struct rk3288_pwm *regs;
ulong freq;
+ uint enable_conf;
};
+static int rk_pwm_set_invert(struct udevice *dev, uint channel, bool polarity)
+{
+ struct rk_pwm_priv *priv = dev_get_priv(dev);
+
+ debug("%s: polarity=%u\n", __func__, polarity);
+ if (polarity)
+ priv->enable_conf |= PWM_DUTY_NEGATIVE | PWM_INACTIVE_POSTIVE;
+ else
+ priv->enable_conf |= PWM_DUTY_POSTIVE | PWM_INACTIVE_NEGATIVE;
+
+ return 0;
+}
+
static int rk_pwm_set_config(struct udevice *dev, uint channel, uint period_ns,
uint duty_ns)
{
@@ -32,7 +46,7 @@ static int rk_pwm_set_config(struct udevice *dev, uint channel, uint period_ns,
debug("%s: period_ns=%u, duty_ns=%u\n", __func__, period_ns, duty_ns);
writel(PWM_SEL_SRC_CLK | PWM_OUTPUT_LEFT | PWM_LP_DISABLE |
- PWM_CONTINUOUS | PWM_DUTY_POSTIVE | PWM_INACTIVE_POSTIVE |
+ PWM_CONTINUOUS | priv->enable_conf |
RK_PWM_DISABLE,
&regs->ctrl);
@@ -83,6 +97,7 @@ static int rk_pwm_probe(struct udevice *dev)
}
static const struct pwm_ops rk_pwm_ops = {
+ .set_invert = rk_pwm_set_invert,
.set_config = rk_pwm_set_config,
.set_enable = rk_pwm_set_enable,
};
diff --git a/drivers/pwm/sandbox_pwm.c b/drivers/pwm/sandbox_pwm.c
index c2ce974ddea..fcb10845515 100644
--- a/drivers/pwm/sandbox_pwm.c
+++ b/drivers/pwm/sandbox_pwm.c
@@ -21,6 +21,7 @@ struct sandbox_pwm_chan {
uint period_ns;
uint duty_ns;
bool enable;
+ bool polarity;
};
struct sandbox_pwm_priv {
@@ -56,9 +57,24 @@ static int sandbox_pwm_set_enable(struct udevice *dev, uint channel,
return 0;
}
+static int sandbox_pwm_set_invert(struct udevice *dev, uint channel,
+ bool polarity)
+{
+ struct sandbox_pwm_priv *priv = dev_get_priv(dev);
+ struct sandbox_pwm_chan *chan;
+
+ if (channel >= NUM_CHANNELS)
+ return -ENOSPC;
+ chan = &priv->chan[channel];
+ chan->polarity = polarity;
+
+ return 0;
+}
+
static const struct pwm_ops sandbox_pwm_ops = {
.set_config = sandbox_pwm_set_config,
.set_enable = sandbox_pwm_set_enable,
+ .set_invert = sandbox_pwm_set_invert,
};
static const struct udevice_id sandbox_pwm_ids[] = {
diff --git a/drivers/ram/Makefile b/drivers/ram/Makefile
index ecb036dfbab..c409c480fc7 100644
--- a/drivers/ram/Makefile
+++ b/drivers/ram/Makefile
@@ -7,3 +7,4 @@
obj-$(CONFIG_RAM) += ram-uclass.o
obj-$(CONFIG_SANDBOX) += sandbox_ram.o
obj-$(CONFIG_STM32_SDRAM) += stm32_sdram.o
+obj-$(CONFIG_ARCH_BMIPS) += bmips_ram.o
diff --git a/drivers/ram/bmips_ram.c b/drivers/ram/bmips_ram.c
new file mode 100644
index 00000000000..d0f7cd73768
--- /dev/null
+++ b/drivers/ram/bmips_ram.c
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2017 Álvaro Fernández Rojas <noltari@gmail.com>
+ *
+ * Derived from linux/arch/mips/bcm63xx/cpu.c:
+ * Copyright (C) 2008 Maxime Bizon <mbizon@freebox.fr>
+ * Copyright (C) 2009 Florian Fainelli <florian@openwrt.org>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <errno.h>
+#include <ram.h>
+#include <asm/io.h>
+#include <dm/device.h>
+
+#define MEMC_CFG_REG 0x4
+#define MEMC_CFG_32B_SHIFT 1
+#define MEMC_CFG_32B_MASK (1 << MEMC_CFG_32B_SHIFT)
+#define MEMC_CFG_COL_SHIFT 3
+#define MEMC_CFG_COL_MASK (0x3 << MEMC_CFG_COL_SHIFT)
+#define MEMC_CFG_ROW_SHIFT 6
+#define MEMC_CFG_ROW_MASK (0x3 << MEMC_CFG_ROW_SHIFT)
+
+#define DDR_CSEND_REG 0x8
+
+struct bmips_ram_priv;
+
+struct bmips_ram_hw {
+ ulong (*get_ram_size)(struct bmips_ram_priv *);
+};
+
+struct bmips_ram_priv {
+ void __iomem *regs;
+ const struct bmips_ram_hw *hw;
+};
+
+static ulong bcm6328_get_ram_size(struct bmips_ram_priv *priv)
+{
+ return readl_be(priv->regs + DDR_CSEND_REG) << 24;
+}
+
+static ulong bcm6358_get_ram_size(struct bmips_ram_priv *priv)
+{
+ unsigned int cols = 0, rows = 0, is_32bits = 0, banks = 0;
+ u32 val;
+
+ val = readl_be(priv->regs + MEMC_CFG_REG);
+ rows = (val & MEMC_CFG_ROW_MASK) >> MEMC_CFG_ROW_SHIFT;
+ cols = (val & MEMC_CFG_COL_MASK) >> MEMC_CFG_COL_SHIFT;
+ is_32bits = (val & MEMC_CFG_32B_MASK) ? 0 : 1;
+ banks = 2;
+
+ /* 0 => 11 address bits ... 2 => 13 address bits */
+ rows += 11;
+
+ /* 0 => 8 address bits ... 2 => 10 address bits */
+ cols += 8;
+
+ return 1 << (cols + rows + (is_32bits + 1) + banks);
+}
+
+static int bmips_ram_get_info(struct udevice *dev, struct ram_info *info)
+{
+ struct bmips_ram_priv *priv = dev_get_priv(dev);
+ const struct bmips_ram_hw *hw = priv->hw;
+
+ info->base = 0x80000000;
+ info->size = hw->get_ram_size(priv);
+
+ return 0;
+}
+
+static const struct ram_ops bmips_ram_ops = {
+ .get_info = bmips_ram_get_info,
+};
+
+static const struct bmips_ram_hw bmips_ram_bcm6328 = {
+ .get_ram_size = bcm6328_get_ram_size,
+};
+
+static const struct bmips_ram_hw bmips_ram_bcm6358 = {
+ .get_ram_size = bcm6358_get_ram_size,
+};
+
+static const struct udevice_id bmips_ram_ids[] = {
+ {
+ .compatible = "brcm,bcm6328-mc",
+ .data = (ulong)&bmips_ram_bcm6328,
+ }, {
+ .compatible = "brcm,bcm6358-mc",
+ .data = (ulong)&bmips_ram_bcm6358,
+ }, { /* sentinel */ }
+};
+
+static int bmips_ram_probe(struct udevice *dev)
+{
+ struct bmips_ram_priv *priv = dev_get_priv(dev);
+ const struct bmips_ram_hw *hw =
+ (const struct bmips_ram_hw *)dev_get_driver_data(dev);
+ fdt_addr_t addr;
+ fdt_size_t size;
+
+ addr = dev_get_addr_size_index(dev, 0, &size);
+ if (addr == FDT_ADDR_T_NONE)
+ return -EINVAL;
+
+ priv->regs = ioremap(addr, size);
+ priv->hw = hw;
+
+ return 0;
+}
+
+U_BOOT_DRIVER(bmips_ram) = {
+ .name = "bmips-mc",
+ .id = UCLASS_RAM,
+ .of_match = bmips_ram_ids,
+ .probe = bmips_ram_probe,
+ .priv_auto_alloc_size = sizeof(struct bmips_ram_priv),
+ .ops = &bmips_ram_ops,
+ .flags = DM_FLAG_PRE_RELOC,
+};
diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig
index 80f4646a79c..e6af7da8fe5 100644
--- a/drivers/reset/Kconfig
+++ b/drivers/reset/Kconfig
@@ -42,6 +42,12 @@ config TEGRA186_RESET
Enable support for manipulating Tegra's on-SoC reset signals via IPC
requests to the BPMP (Boot and Power Management Processor).
+config RESET_BCM6345
+ bool "Reset controller driver for BCM6345"
+ depends on DM_RESET && ARCH_BMIPS
+ help
+ Support reset controller on BCM6345.
+
config RESET_UNIPHIER
bool "Reset controller driver for UniPhier SoCs"
depends on ARCH_UNIPHIER
diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile
index 630b4b4e541..d5e06c2241d 100644
--- a/drivers/reset/Makefile
+++ b/drivers/reset/Makefile
@@ -8,5 +8,6 @@ obj-$(CONFIG_SANDBOX_MBOX) += sandbox-reset-test.o
obj-$(CONFIG_STI_RESET) += sti-reset.o
obj-$(CONFIG_TEGRA_CAR_RESET) += tegra-car-reset.o
obj-$(CONFIG_TEGRA186_RESET) += tegra186-reset.o
+obj-$(CONFIG_RESET_BCM6345) += reset-bcm6345.o
obj-$(CONFIG_RESET_UNIPHIER) += reset-uniphier.o
obj-$(CONFIG_AST2500_RESET) += ast2500-reset.o
diff --git a/drivers/reset/reset-bcm6345.c b/drivers/reset/reset-bcm6345.c
new file mode 100644
index 00000000000..774c2a7538d
--- /dev/null
+++ b/drivers/reset/reset-bcm6345.c
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2017 Álvaro Fernández Rojas <noltari@gmail.com>
+ *
+ * Derived from linux/arch/mips/bcm63xx/reset.c:
+ * Copyright (C) 2012 Jonas Gorski <jonas.gorski@gmail.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <reset-uclass.h>
+#include <asm/io.h>
+
+#define MAX_RESETS 32
+
+struct bcm6345_reset_priv {
+ void __iomem *regs;
+};
+
+static int bcm6345_reset_assert(struct reset_ctl *rst)
+{
+ struct bcm6345_reset_priv *priv = dev_get_priv(rst->dev);
+
+ clrbits_be32(priv->regs, BIT(rst->id));
+ mdelay(20);
+
+ return 0;
+}
+
+static int bcm6345_reset_deassert(struct reset_ctl *rst)
+{
+ struct bcm6345_reset_priv *priv = dev_get_priv(rst->dev);
+
+ setbits_be32(priv->regs, BIT(rst->id));
+ mdelay(20);
+
+ return 0;
+}
+
+static int bcm6345_reset_free(struct reset_ctl *rst)
+{
+ return 0;
+}
+
+static int bcm6345_reset_request(struct reset_ctl *rst)
+{
+ if (rst->id >= MAX_RESETS)
+ return -EINVAL;
+
+ return bcm6345_reset_assert(rst);
+}
+
+struct reset_ops bcm6345_reset_reset_ops = {
+ .free = bcm6345_reset_free,
+ .request = bcm6345_reset_request,
+ .rst_assert = bcm6345_reset_assert,
+ .rst_deassert = bcm6345_reset_deassert,
+};
+
+static const struct udevice_id bcm6345_reset_ids[] = {
+ { .compatible = "brcm,bcm6345-reset" },
+ { /* sentinel */ }
+};
+
+static int bcm6345_reset_probe(struct udevice *dev)
+{
+ struct bcm6345_reset_priv *priv = dev_get_priv(dev);
+ fdt_addr_t addr;
+ fdt_size_t size;
+
+ addr = dev_get_addr_size_index(dev, 0, &size);
+ if (addr == FDT_ADDR_T_NONE)
+ return -EINVAL;
+
+ priv->regs = ioremap(addr, size);
+
+ return 0;
+}
+
+U_BOOT_DRIVER(bcm6345_reset) = {
+ .name = "bcm6345-reset",
+ .id = UCLASS_RESET,
+ .of_match = bcm6345_reset_ids,
+ .ops = &bcm6345_reset_reset_ops,
+ .probe = bcm6345_reset_probe,
+ .priv_auto_alloc_size = sizeof(struct bcm6345_reset_priv),
+};
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
index 58320666b7d..58fc7cd2e66 100644
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -145,6 +145,14 @@ config DEBUG_UART_ATMEL
will need to provide parameters to make this work. The driver will
be available until the real driver-model serial is running.
+config DEBUG_UART_BCM6345
+ bool "BCM6345 UART"
+ depends on BCM6345_SERIAL
+ help
+ Select this to enable a debug UART on BCM6345 SoCs. You
+ will need to provide parameters to make this work. The driver will
+ be available until the real driver model serial is running.
+
config DEBUG_UART_NS16550
bool "ns16550"
help
@@ -249,6 +257,13 @@ config DEBUG_UART_UNIPHIER
driver will be available until the real driver-model serial is
running.
+config DEBUG_UART_OMAP
+ bool "OMAP uart"
+ help
+ Select this to enable a debug UART using the omap ns16550 driver.
+ You will need to provide parameters to make this work. The driver
+ will be available until the real driver model serial is running.
+
endchoice
config DEBUG_UART_BASE
@@ -350,6 +365,12 @@ config ATMEL_USART
configured in the device tree, and input clock frequency can
be got from the clk node.
+config BCM6345_SERIAL
+ bool "Support for BCM6345 UART"
+ depends on DM_SERIAL && ARCH_BMIPS
+ help
+ Select this to enable UART on BCM6345 SoCs.
+
config FSL_LPUART
bool "Freescale LPUART support"
help
diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile
index 4382cf93297..dca31b295c1 100644
--- a/drivers/serial/Makefile
+++ b/drivers/serial/Makefile
@@ -20,6 +20,7 @@ obj-$(CONFIG_ALTERA_JTAG_UART) += altera_jtag_uart.o
obj-$(CONFIG_AR933X_UART) += serial_ar933x.o
obj-$(CONFIG_ARM_DCC) += arm_dcc.o
obj-$(CONFIG_ATMEL_USART) += atmel_usart.o
+obj-$(CONFIG_BCM6345_SERIAL) += serial_bcm6345.o
obj-$(CONFIG_EFI_APP) += serial_efi.o
obj-$(CONFIG_LPC32XX_HSUART) += lpc32xx_hsuart.o
obj-$(CONFIG_MCFUART) += mcfuart.o
diff --git a/drivers/serial/atmel_usart.c b/drivers/serial/atmel_usart.c
index 7674f97e8dd..453f8eb4518 100644
--- a/drivers/serial/atmel_usart.c
+++ b/drivers/serial/atmel_usart.c
@@ -7,6 +7,7 @@
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
+#include <clk.h>
#include <dm.h>
#include <errno.h>
#include <watchdog.h>
@@ -25,6 +26,7 @@
DECLARE_GLOBAL_DATA_PTR;
+#ifndef CONFIG_DM_SERIAL
static void atmel_serial_setbrg_internal(atmel_usart3_t *usart, int id,
int baudrate)
{
@@ -66,7 +68,6 @@ static void atmel_serial_activate(atmel_usart3_t *usart)
__udelay(100);
}
-#ifndef CONFIG_DM_SERIAL
static void atmel_serial_setbrg(void)
{
atmel_serial_setbrg_internal((atmel_usart3_t *)CONFIG_USART_BASE,
@@ -133,17 +134,47 @@ __weak struct serial_device *default_serial_console(void)
#endif
#ifdef CONFIG_DM_SERIAL
+enum serial_clk_type {
+ CLK_TYPE_NORMAL = 0,
+ CLK_TYPE_DBGU,
+};
struct atmel_serial_priv {
atmel_usart3_t *usart;
+ ulong usart_clk_rate;
};
+static void _atmel_serial_set_brg(atmel_usart3_t *usart,
+ ulong usart_clk_rate, int baudrate)
+{
+ unsigned long divisor;
+
+ divisor = (usart_clk_rate / 16 + baudrate / 2) / baudrate;
+ writel(USART3_BF(CD, divisor), &usart->brgr);
+}
+
+void _atmel_serial_init(atmel_usart3_t *usart,
+ ulong usart_clk_rate, int baudrate)
+{
+ writel(USART3_BIT(RXDIS) | USART3_BIT(TXDIS), &usart->cr);
+
+ writel((USART3_BF(USART_MODE, USART3_USART_MODE_NORMAL) |
+ USART3_BF(USCLKS, USART3_USCLKS_MCK) |
+ USART3_BF(CHRL, USART3_CHRL_8) |
+ USART3_BF(PAR, USART3_PAR_NONE) |
+ USART3_BF(NBSTOP, USART3_NBSTOP_1)), &usart->mr);
+
+ _atmel_serial_set_brg(usart, usart_clk_rate, baudrate);
+
+ writel(USART3_BIT(RSTRX) | USART3_BIT(RSTTX), &usart->cr);
+ writel(USART3_BIT(RXEN) | USART3_BIT(TXEN), &usart->cr);
+}
+
int atmel_serial_setbrg(struct udevice *dev, int baudrate)
{
struct atmel_serial_priv *priv = dev_get_priv(dev);
- atmel_serial_setbrg_internal(priv->usart, 0 /* ignored */, baudrate);
- atmel_serial_activate(priv->usart);
+ _atmel_serial_set_brg(priv->usart, priv->usart_clk_rate, baudrate);
return 0;
}
@@ -188,10 +219,39 @@ static const struct dm_serial_ops atmel_serial_ops = {
.setbrg = atmel_serial_setbrg,
};
+static int atmel_serial_enable_clk(struct udevice *dev)
+{
+ struct atmel_serial_priv *priv = dev_get_priv(dev);
+ struct clk clk;
+ ulong clk_rate;
+ int ret;
+
+ ret = clk_get_by_index(dev, 0, &clk);
+ if (ret)
+ return -EINVAL;
+
+ if (dev_get_driver_data(dev) == CLK_TYPE_NORMAL) {
+ ret = clk_enable(&clk);
+ if (ret)
+ return ret;
+ }
+
+ clk_rate = clk_get_rate(&clk);
+ if (!clk_rate)
+ return -EINVAL;
+
+ priv->usart_clk_rate = clk_rate;
+
+ clk_free(&clk);
+
+ return 0;
+}
+
static int atmel_serial_probe(struct udevice *dev)
{
struct atmel_serial_platdata *plat = dev->platdata;
struct atmel_serial_priv *priv = dev_get_priv(dev);
+ int ret;
#if CONFIG_IS_ENABLED(OF_CONTROL)
fdt_addr_t addr_base;
@@ -202,14 +262,26 @@ static int atmel_serial_probe(struct udevice *dev)
plat->base_addr = (uint32_t)addr_base;
#endif
priv->usart = (atmel_usart3_t *)plat->base_addr;
- atmel_serial_init_internal(priv->usart);
+
+ ret = atmel_serial_enable_clk(dev);
+ if (ret)
+ return ret;
+
+ _atmel_serial_init(priv->usart, priv->usart_clk_rate, gd->baudrate);
return 0;
}
#if CONFIG_IS_ENABLED(OF_CONTROL)
static const struct udevice_id atmel_serial_ids[] = {
- { .compatible = "atmel,at91sam9260-usart" },
+ {
+ .compatible = "atmel,at91sam9260-dbgu",
+ .data = CLK_TYPE_DBGU,
+ },
+ {
+ .compatible = "atmel,at91sam9260-usart",
+ .data = CLK_TYPE_NORMAL,
+ },
{ }
};
#endif
@@ -233,7 +305,7 @@ static inline void _debug_uart_init(void)
{
atmel_usart3_t *usart = (atmel_usart3_t *)CONFIG_DEBUG_UART_BASE;
- atmel_serial_setbrg_internal(usart, 0, CONFIG_BAUDRATE);
+ _atmel_serial_init(usart, CONFIG_DEBUG_UART_CLOCK, CONFIG_BAUDRATE);
}
static inline void _debug_uart_putc(int ch)
diff --git a/drivers/serial/ns16550.c b/drivers/serial/ns16550.c
index 4f86780cb12..0eb7c025618 100644
--- a/drivers/serial/ns16550.c
+++ b/drivers/serial/ns16550.c
@@ -175,21 +175,17 @@ void NS16550_init(NS16550_t com_port, int baud_divisor)
;
serial_out(CONFIG_SYS_NS16550_IER, &com_port->ier);
-#if defined(CONFIG_OMAP) || defined(CONFIG_AM33XX) || \
- defined(CONFIG_TI81XX) || defined(CONFIG_AM43XX)
+#if defined(CONFIG_ARCH_OMAP2PLUS)
serial_out(0x7, &com_port->mdr1); /* mode select reset TL16C750*/
#endif
serial_out(UART_MCRVAL, &com_port->mcr);
serial_out(ns16550_getfcr(com_port), &com_port->fcr);
if (baud_divisor != -1)
NS16550_setbrg(com_port, baud_divisor);
-#if defined(CONFIG_OMAP) || \
- defined(CONFIG_AM33XX) || defined(CONFIG_SOC_DA8XX) || \
- defined(CONFIG_TI81XX) || defined(CONFIG_AM43XX)
-
+#if defined(CONFIG_ARCH_OMAP2PLUS) || defined(CONFIG_SOC_DA8XX)
/* /16 is proper to hit 115200 with 48MHz */
serial_out(0, &com_port->mdr1);
-#endif /* CONFIG_OMAP */
+#endif
#if defined(CONFIG_SOC_KEYSTONE)
serial_out(UART_REG_VAL_PWREMU_MGMT_UART_ENABLE, &com_port->regC);
#endif
@@ -246,17 +242,6 @@ int NS16550_tstc(NS16550_t com_port)
#include <debug_uart.h>
-#define serial_dout(reg, value) \
- serial_out_shift((char *)com_port + \
- ((char *)reg - (char *)com_port) * \
- (1 << CONFIG_DEBUG_UART_SHIFT), \
- CONFIG_DEBUG_UART_SHIFT, value)
-#define serial_din(reg) \
- serial_in_shift((char *)com_port + \
- ((char *)reg - (char *)com_port) * \
- (1 << CONFIG_DEBUG_UART_SHIFT), \
- CONFIG_DEBUG_UART_SHIFT)
-
static inline void _debug_uart_init(void)
{
struct NS16550 *com_port = (struct NS16550 *)CONFIG_DEBUG_UART_BASE;
@@ -293,6 +278,42 @@ DEBUG_UART_FUNCS
#endif
+#ifdef CONFIG_DEBUG_UART_OMAP
+
+#include <debug_uart.h>
+
+static inline void _debug_uart_init(void)
+{
+ struct NS16550 *com_port = (struct NS16550 *)CONFIG_DEBUG_UART_BASE;
+ int baud_divisor;
+
+ baud_divisor = ns16550_calc_divisor(com_port, CONFIG_DEBUG_UART_CLOCK,
+ CONFIG_BAUDRATE);
+ serial_dout(&com_port->ier, CONFIG_SYS_NS16550_IER);
+ serial_dout(&com_port->mdr1, 0x7);
+ serial_dout(&com_port->mcr, UART_MCRVAL);
+ serial_dout(&com_port->fcr, UART_FCR_DEFVAL);
+
+ serial_dout(&com_port->lcr, UART_LCR_BKSE | UART_LCRVAL);
+ serial_dout(&com_port->dll, baud_divisor & 0xff);
+ serial_dout(&com_port->dlm, (baud_divisor >> 8) & 0xff);
+ serial_dout(&com_port->lcr, UART_LCRVAL);
+ serial_dout(&com_port->mdr1, 0x0);
+}
+
+static inline void _debug_uart_putc(int ch)
+{
+ struct NS16550 *com_port = (struct NS16550 *)CONFIG_DEBUG_UART_BASE;
+
+ while (!(serial_din(&com_port->lsr) & UART_LSR_THRE))
+ ;
+ serial_dout(&com_port->thr, ch);
+}
+
+DEBUG_UART_FUNCS
+
+#endif
+
#ifdef CONFIG_DM_SERIAL
static int ns16550_serial_putc(struct udevice *dev, const char ch)
{
diff --git a/drivers/serial/serial-uclass.c b/drivers/serial/serial-uclass.c
index 43c028ebe63..c2b9c5f12f5 100644
--- a/drivers/serial/serial-uclass.c
+++ b/drivers/serial/serial-uclass.c
@@ -349,7 +349,7 @@ static int serial_pre_remove(struct udevice *dev)
#if CONFIG_IS_ENABLED(SYS_STDIO_DEREGISTER)
struct serial_dev_priv *upriv = dev_get_uclass_priv(dev);
- if (stdio_deregister_dev(upriv->sdev, 0))
+ if (stdio_deregister_dev(upriv->sdev, true))
return -EPERM;
#endif
diff --git a/drivers/serial/serial_bcm6345.c b/drivers/serial/serial_bcm6345.c
new file mode 100644
index 00000000000..db270e3b21b
--- /dev/null
+++ b/drivers/serial/serial_bcm6345.c
@@ -0,0 +1,300 @@
+/*
+ * Copyright (C) 2017 Álvaro Fernández Rojas <noltari@gmail.com>
+ *
+ * Derived from linux/drivers/tty/serial/bcm63xx_uart.c:
+ * Copyright (C) 2008 Maxime Bizon <mbizon@freebox.fr>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <clk.h>
+#include <debug_uart.h>
+#include <errno.h>
+#include <serial.h>
+#include <asm/io.h>
+#include <asm/types.h>
+#include <dm/device.h>
+
+/* UART Control register */
+#define UART_CTL_REG 0x0
+#define UART_CTL_RXTIMEOUT_MASK 0x1f
+#define UART_CTL_RXTIMEOUT_5 0x5
+#define UART_CTL_RSTRXFIFO_SHIFT 6
+#define UART_CTL_RSTRXFIFO_MASK (1 << UART_CTL_RSTRXFIFO_SHIFT)
+#define UART_CTL_RSTTXFIFO_SHIFT 7
+#define UART_CTL_RSTTXFIFO_MASK (1 << UART_CTL_RSTTXFIFO_SHIFT)
+#define UART_CTL_STOPBITS_SHIFT 8
+#define UART_CTL_STOPBITS_MASK (0xf << UART_CTL_STOPBITS_SHIFT)
+#define UART_CTL_STOPBITS_1 (0x7 << UART_CTL_STOPBITS_SHIFT)
+#define UART_CTL_BITSPERSYM_SHIFT 12
+#define UART_CTL_BITSPERSYM_MASK (0x3 << UART_CTL_BITSPERSYM_SHIFT)
+#define UART_CTL_BITSPERSYM_8 (0x3 << UART_CTL_BITSPERSYM_SHIFT)
+#define UART_CTL_XMITBRK_SHIFT 14
+#define UART_CTL_XMITBRK_MASK (1 << UART_CTL_XMITBRK_SHIFT)
+#define UART_CTL_RSVD_SHIFT 15
+#define UART_CTL_RSVD_MASK (1 << UART_CTL_RSVD_SHIFT)
+#define UART_CTL_RXPAREVEN_SHIFT 16
+#define UART_CTL_RXPAREVEN_MASK (1 << UART_CTL_RXPAREVEN_SHIFT)
+#define UART_CTL_RXPAREN_SHIFT 17
+#define UART_CTL_RXPAREN_MASK (1 << UART_CTL_RXPAREN_SHIFT)
+#define UART_CTL_TXPAREVEN_SHIFT 18
+#define UART_CTL_TXPAREVEN_MASK (1 << UART_CTL_TXPAREVEN_SHIFT)
+#define UART_CTL_TXPAREN_SHIFT 19
+#define UART_CTL_TXPAREN_MASK (1 << UART_CTL_TXPAREN_SHIFT)
+#define UART_CTL_LOOPBACK_SHIFT 20
+#define UART_CTL_LOOPBACK_MASK (1 << UART_CTL_LOOPBACK_SHIFT)
+#define UART_CTL_RXEN_SHIFT 21
+#define UART_CTL_RXEN_MASK (1 << UART_CTL_RXEN_SHIFT)
+#define UART_CTL_TXEN_SHIFT 22
+#define UART_CTL_TXEN_MASK (1 << UART_CTL_TXEN_SHIFT)
+#define UART_CTL_BRGEN_SHIFT 23
+#define UART_CTL_BRGEN_MASK (1 << UART_CTL_BRGEN_SHIFT)
+
+/* UART Baudword register */
+#define UART_BAUD_REG 0x4
+
+/* UART FIFO Config register */
+#define UART_FIFO_CFG_REG 0x8
+#define UART_FIFO_CFG_RX_SHIFT 8
+#define UART_FIFO_CFG_RX_MASK (0xf << UART_FIFO_CFG_RX_SHIFT)
+#define UART_FIFO_CFG_RX_4 (0x4 << UART_FIFO_CFG_RX_SHIFT)
+#define UART_FIFO_CFG_TX_SHIFT 12
+#define UART_FIFO_CFG_TX_MASK (0xf << UART_FIFO_CFG_TX_SHIFT)
+#define UART_FIFO_CFG_TX_4 (0x4 << UART_FIFO_CFG_TX_SHIFT)
+
+/* UART Interrupt register */
+#define UART_IR_REG 0x10
+#define UART_IR_STAT(x) (1 << (x))
+#define UART_IR_TXEMPTY 5
+#define UART_IR_RXOVER 7
+#define UART_IR_RXNOTEMPTY 11
+
+/* UART FIFO register */
+#define UART_FIFO_REG 0x14
+#define UART_FIFO_VALID_MASK 0xff
+#define UART_FIFO_FRAMEERR_SHIFT 8
+#define UART_FIFO_FRAMEERR_MASK (1 << UART_FIFO_FRAMEERR_SHIFT)
+#define UART_FIFO_PARERR_SHIFT 9
+#define UART_FIFO_PARERR_MASK (1 << UART_FIFO_PARERR_SHIFT)
+#define UART_FIFO_BRKDET_SHIFT 10
+#define UART_FIFO_BRKDET_MASK (1 << UART_FIFO_BRKDET_SHIFT)
+#define UART_FIFO_ANYERR_MASK (UART_FIFO_FRAMEERR_MASK | \
+ UART_FIFO_PARERR_MASK | \
+ UART_FIFO_BRKDET_MASK)
+
+struct bcm6345_serial_priv {
+ void __iomem *base;
+ ulong uartclk;
+};
+
+/* enable rx & tx operation on uart */
+static void bcm6345_serial_enable(void __iomem *base)
+{
+ setbits_be32(base + UART_CTL_REG, UART_CTL_BRGEN_MASK |
+ UART_CTL_TXEN_MASK | UART_CTL_RXEN_MASK);
+}
+
+/* disable rx & tx operation on uart */
+static void bcm6345_serial_disable(void __iomem *base)
+{
+ clrbits_be32(base + UART_CTL_REG, UART_CTL_BRGEN_MASK |
+ UART_CTL_TXEN_MASK | UART_CTL_RXEN_MASK);
+}
+
+/* clear all unread data in rx fifo and unsent data in tx fifo */
+static void bcm6345_serial_flush(void __iomem *base)
+{
+ /* empty rx and tx fifo */
+ setbits_be32(base + UART_CTL_REG, UART_CTL_RSTRXFIFO_MASK |
+ UART_CTL_RSTTXFIFO_MASK);
+
+ /* read any pending char to make sure all irq status are cleared */
+ readl_be(base + UART_FIFO_REG);
+}
+
+static int bcm6345_serial_init(void __iomem *base, ulong clk, u32 baudrate)
+{
+ u32 val;
+
+ /* mask all irq and flush port */
+ bcm6345_serial_disable(base);
+ bcm6345_serial_flush(base);
+
+ /* set uart control config */
+ clrsetbits_be32(base + UART_CTL_REG,
+ /* clear rx timeout */
+ UART_CTL_RXTIMEOUT_MASK |
+ /* clear stop bits */
+ UART_CTL_STOPBITS_MASK |
+ /* clear bits per symbol */
+ UART_CTL_BITSPERSYM_MASK |
+ /* clear xmit break */
+ UART_CTL_XMITBRK_MASK |
+ /* clear reserved bit */
+ UART_CTL_RSVD_MASK |
+ /* disable parity */
+ UART_CTL_RXPAREN_MASK |
+ UART_CTL_TXPAREN_MASK |
+ /* disable loopback */
+ UART_CTL_LOOPBACK_MASK,
+ /* set timeout to 5 */
+ UART_CTL_RXTIMEOUT_5 |
+ /* set 8 bits/symbol */
+ UART_CTL_BITSPERSYM_8 |
+ /* set parity to even */
+ UART_CTL_RXPAREVEN_MASK |
+ UART_CTL_TXPAREVEN_MASK);
+
+ /* set uart fifo config */
+ clrsetbits_be32(base + UART_FIFO_CFG_REG,
+ /* clear fifo config */
+ UART_FIFO_CFG_RX_MASK |
+ UART_FIFO_CFG_TX_MASK,
+ /* set fifo config to 4 */
+ UART_FIFO_CFG_RX_4 |
+ UART_FIFO_CFG_TX_4);
+
+ /* set baud rate */
+ val = (clk / baudrate) / 16;
+ if (val & 0x1)
+ val = val;
+ else
+ val = val / 2 - 1;
+ writel_be(val, base + UART_BAUD_REG);
+
+ /* clear interrupts */
+ writel_be(0, base + UART_IR_REG);
+
+ /* enable uart */
+ bcm6345_serial_enable(base);
+
+ return 0;
+}
+
+static int bcm6345_serial_pending(struct udevice *dev, bool input)
+{
+ struct bcm6345_serial_priv *priv = dev_get_priv(dev);
+ u32 val = readl_be(priv->base + UART_IR_REG);
+
+ if (input)
+ return !!(val & UART_IR_STAT(UART_IR_RXNOTEMPTY));
+ else
+ return !(val & UART_IR_STAT(UART_IR_TXEMPTY));
+}
+
+static int bcm6345_serial_setbrg(struct udevice *dev, int baudrate)
+{
+ struct bcm6345_serial_priv *priv = dev_get_priv(dev);
+
+ return bcm6345_serial_init(priv->base, priv->uartclk, baudrate);
+}
+
+static int bcm6345_serial_putc(struct udevice *dev, const char ch)
+{
+ struct bcm6345_serial_priv *priv = dev_get_priv(dev);
+ u32 val;
+
+ val = readl_be(priv->base + UART_IR_REG);
+ if (!(val & UART_IR_STAT(UART_IR_TXEMPTY)))
+ return -EAGAIN;
+
+ writel_be(ch, priv->base + UART_FIFO_REG);
+
+ return 0;
+}
+
+static int bcm6345_serial_getc(struct udevice *dev)
+{
+ struct bcm6345_serial_priv *priv = dev_get_priv(dev);
+ u32 val;
+
+ val = readl_be(priv->base + UART_IR_REG);
+ if (val & UART_IR_STAT(UART_IR_RXOVER))
+ setbits_be32(priv->base + UART_CTL_REG,
+ UART_CTL_RSTRXFIFO_MASK);
+ if (!(val & UART_IR_STAT(UART_IR_RXNOTEMPTY)))
+ return -EAGAIN;
+
+ val = readl_be(priv->base + UART_FIFO_REG);
+ if (val & UART_FIFO_ANYERR_MASK)
+ return -EAGAIN;
+
+ return val & UART_FIFO_VALID_MASK;
+}
+
+static int bcm6345_serial_probe(struct udevice *dev)
+{
+ struct bcm6345_serial_priv *priv = dev_get_priv(dev);
+ struct clk clk;
+ fdt_addr_t addr;
+ fdt_size_t size;
+ int ret;
+
+ /* get address */
+ addr = dev_get_addr_size_index(dev, 0, &size);
+ if (addr == FDT_ADDR_T_NONE)
+ return -EINVAL;
+
+ priv->base = ioremap(addr, size);
+
+ /* get clock rate */
+ ret = clk_get_by_index(dev, 0, &clk);
+ if (ret < 0)
+ return ret;
+ priv->uartclk = clk_get_rate(&clk) / 2;
+ clk_free(&clk);
+
+ /* initialize serial */
+ return bcm6345_serial_init(priv->base, priv->uartclk, CONFIG_BAUDRATE);
+}
+
+static const struct dm_serial_ops bcm6345_serial_ops = {
+ .putc = bcm6345_serial_putc,
+ .pending = bcm6345_serial_pending,
+ .getc = bcm6345_serial_getc,
+ .setbrg = bcm6345_serial_setbrg,
+};
+
+static const struct udevice_id bcm6345_serial_ids[] = {
+ { .compatible = "brcm,bcm6345-uart" },
+ { /* sentinel */ }
+};
+
+U_BOOT_DRIVER(bcm6345_serial) = {
+ .name = "bcm6345-uart",
+ .id = UCLASS_SERIAL,
+ .of_match = bcm6345_serial_ids,
+ .probe = bcm6345_serial_probe,
+ .priv_auto_alloc_size = sizeof(struct bcm6345_serial_priv),
+ .ops = &bcm6345_serial_ops,
+ .flags = DM_FLAG_PRE_RELOC,
+};
+
+#ifdef CONFIG_DEBUG_UART_BCM6345
+static inline void _debug_uart_init(void)
+{
+ void __iomem *base = (void __iomem *)CONFIG_DEBUG_UART_BASE;
+
+ bcm6345_serial_init(base, CONFIG_DEBUG_UART_CLOCK, CONFIG_BAUDRATE);
+}
+
+static inline void wait_xfered(void __iomem *base)
+{
+ do {
+ u32 val = readl_be(base + UART_IR_REG);
+ if (val & UART_IR_STAT(UART_IR_TXEMPTY))
+ break;
+ } while (1);
+}
+
+static inline void _debug_uart_putc(int ch)
+{
+ void __iomem *base = (void __iomem *)CONFIG_DEBUG_UART_BASE;
+
+ wait_xfered(base);
+ writel_be(ch, base + UART_FIFO_REG);
+ wait_xfered(base);
+}
+
+DEBUG_UART_FUNCS
+#endif
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index f3f7dbe0897..bef864f46e5 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -197,6 +197,12 @@ config OMAP3_SPI
endif # if DM_SPI
+config SOFT_SPI
+ bool "Soft SPI driver"
+ help
+ Enable Soft SPI driver. This driver is to use GPIO simulate
+ the SPI protocol.
+
config FSL_ESPI
bool "Freescale eSPI driver"
help
diff --git a/drivers/spi/ich.c b/drivers/spi/ich.c
index 893fe33b66f..bf2e99b5ccb 100644
--- a/drivers/spi/ich.c
+++ b/drivers/spi/ich.c
@@ -617,6 +617,22 @@ static int ich_spi_probe(struct udevice *dev)
return 0;
}
+static int ich_spi_remove(struct udevice *bus)
+{
+ struct ich_spi_priv *ctlr = dev_get_priv(bus);
+
+ /*
+ * Configure SPI controller so that the Linux MTD driver can fully
+ * access the SPI NOR chip
+ */
+ ich_writew(ctlr, SPI_OPPREFIX, ctlr->preop);
+ ich_writew(ctlr, SPI_OPTYPE, ctlr->optype);
+ ich_writel(ctlr, SPI_OPMENU_LOWER, ctlr->opmenu);
+ ich_writel(ctlr, SPI_OPMENU_UPPER, ctlr->opmenu + sizeof(u32));
+
+ return 0;
+}
+
static int ich_spi_set_speed(struct udevice *bus, uint speed)
{
struct ich_spi_priv *priv = dev_get_priv(bus);
@@ -700,4 +716,6 @@ U_BOOT_DRIVER(ich_spi) = {
.priv_auto_alloc_size = sizeof(struct ich_spi_priv),
.child_pre_probe = ich_spi_child_pre_probe,
.probe = ich_spi_probe,
+ .remove = ich_spi_remove,
+ .flags = DM_FLAG_OS_PREPARE,
};
diff --git a/drivers/spi/ich.h b/drivers/spi/ich.h
index bd0a8208096..dcb8a9048f8 100644
--- a/drivers/spi/ich.h
+++ b/drivers/spi/ich.h
@@ -102,13 +102,6 @@ enum {
};
enum {
- SPI_OPCODE_TYPE_READ_NO_ADDRESS = 0,
- SPI_OPCODE_TYPE_WRITE_NO_ADDRESS = 1,
- SPI_OPCODE_TYPE_READ_WITH_ADDRESS = 2,
- SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS = 3
-};
-
-enum {
ICH_MAX_CMD_LEN = 5,
};
@@ -124,8 +117,55 @@ struct spi_trans {
uint32_t offset;
};
+#define SPI_OPCODE_WRSR 0x01
+#define SPI_OPCODE_PAGE_PROGRAM 0x02
+#define SPI_OPCODE_READ 0x03
+#define SPI_OPCODE_WRDIS 0x04
+#define SPI_OPCODE_RDSR 0x05
#define SPI_OPCODE_WREN 0x06
#define SPI_OPCODE_FAST_READ 0x0b
+#define SPI_OPCODE_ERASE_SECT 0x20
+#define SPI_OPCODE_READ_ID 0x9f
+#define SPI_OPCODE_ERASE_BLOCK 0xd8
+
+#define SPI_OPCODE_TYPE_READ_NO_ADDRESS 0
+#define SPI_OPCODE_TYPE_WRITE_NO_ADDRESS 1
+#define SPI_OPCODE_TYPE_READ_WITH_ADDRESS 2
+#define SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS 3
+
+#define SPI_OPMENU_0 SPI_OPCODE_WRSR
+#define SPI_OPTYPE_0 SPI_OPCODE_TYPE_WRITE_NO_ADDRESS
+
+#define SPI_OPMENU_1 SPI_OPCODE_PAGE_PROGRAM
+#define SPI_OPTYPE_1 SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS
+
+#define SPI_OPMENU_2 SPI_OPCODE_READ
+#define SPI_OPTYPE_2 SPI_OPCODE_TYPE_READ_WITH_ADDRESS
+
+#define SPI_OPMENU_3 SPI_OPCODE_RDSR
+#define SPI_OPTYPE_3 SPI_OPCODE_TYPE_READ_NO_ADDRESS
+
+#define SPI_OPMENU_4 SPI_OPCODE_ERASE_SECT
+#define SPI_OPTYPE_4 SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS
+
+#define SPI_OPMENU_5 SPI_OPCODE_READ_ID
+#define SPI_OPTYPE_5 SPI_OPCODE_TYPE_READ_NO_ADDRESS
+
+#define SPI_OPMENU_6 SPI_OPCODE_ERASE_BLOCK
+#define SPI_OPTYPE_6 SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS
+
+#define SPI_OPMENU_7 SPI_OPCODE_FAST_READ
+#define SPI_OPTYPE_7 SPI_OPCODE_TYPE_READ_WITH_ADDRESS
+
+#define SPI_OPPREFIX ((SPI_OPCODE_WREN << 8) | SPI_OPCODE_WREN)
+#define SPI_OPTYPE ((SPI_OPTYPE_7 << 14) | (SPI_OPTYPE_6 << 12) | \
+ (SPI_OPTYPE_5 << 10) | (SPI_OPTYPE_4 << 8) | \
+ (SPI_OPTYPE_3 << 6) | (SPI_OPTYPE_2 << 4) | \
+ (SPI_OPTYPE_1 << 2) | (SPI_OPTYPE_0 << 0))
+#define SPI_OPMENU_UPPER ((SPI_OPMENU_7 << 24) | (SPI_OPMENU_6 << 16) | \
+ (SPI_OPMENU_5 << 8) | (SPI_OPMENU_4 << 0))
+#define SPI_OPMENU_LOWER ((SPI_OPMENU_3 << 24) | (SPI_OPMENU_2 << 16) | \
+ (SPI_OPMENU_1 << 8) | (SPI_OPMENU_0 << 0))
enum ich_version {
ICHV_7,
diff --git a/drivers/spi/omap3_spi.c b/drivers/spi/omap3_spi.c
index 76d376ac445..3caea151c54 100644
--- a/drivers/spi/omap3_spi.c
+++ b/drivers/spi/omap3_spi.c
@@ -568,7 +568,8 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
priv->freq = max_hz;
priv->mode = mode;
priv->wordlen = priv->slave.wordlen;
-#ifdef CONFIG_OMAP3_SPI_D0_D1_SWAPPED
+#if 0
+ /* Please migrate to DM_SPI support for this feature. */
priv->pin_dir = MCSPI_PINDIR_D0_OUT_D1_IN;
#endif
diff --git a/drivers/spi/rk_spi.c b/drivers/spi/rk_spi.c
index 3e44f1795e3..ea209801a73 100644
--- a/drivers/spi/rk_spi.c
+++ b/drivers/spi/rk_spi.c
@@ -79,12 +79,31 @@ static void rkspi_enable_chip(struct rockchip_spi *regs, bool enable)
static void rkspi_set_clk(struct rockchip_spi_priv *priv, uint speed)
{
- uint clk_div;
+ /*
+ * We should try not to exceed the speed requested by the caller:
+ * when selecting a divider, we need to make sure we round up.
+ */
+ uint clk_div = DIV_ROUND_UP(priv->input_rate, speed);
+
+ /* The baudrate register (BAUDR) is defined as a 32bit register where
+ * the upper 16bit are reserved and having 'Fsclk_out' in the lower
+ * 16bits with 'Fsclk_out' defined as follows:
+ *
+ * Fsclk_out = Fspi_clk/ SCKDV
+ * Where SCKDV is any even value between 2 and 65534.
+ */
+ if (clk_div > 0xfffe) {
+ clk_div = 0xfffe;
+ debug("%s: can't divide down to %d hz (actual will be %d hz)\n",
+ __func__, speed, priv->input_rate / clk_div);
+ }
+
+ /* Round up to the next even 16bit number */
+ clk_div = (clk_div + 1) & 0xfffe;
- clk_div = clk_get_divisor(priv->input_rate, speed);
debug("spi speed %u, div %u\n", speed, clk_div);
- writel(clk_div, &priv->regs->baudr);
+ clrsetbits_le32(&priv->regs->baudr, 0xffff, clk_div);
priv->last_speed_hz = speed;
}
@@ -190,6 +209,26 @@ static int rockchip_spi_ofdata_to_platdata(struct udevice *bus)
return 0;
}
+static int rockchip_spi_calc_modclk(ulong max_freq)
+{
+ unsigned div;
+ const unsigned long gpll_hz = 594000000UL;
+
+ /*
+ * We need to find an input clock that provides at least twice
+ * the maximum frequency and can be generated from the assumed
+ * speed of GPLL (594MHz) using an integer divider.
+ *
+ * To give us more achievable bitrates at higher speeds (these
+ * are generated by dividing by an even 16-bit integer from
+ * this frequency), we try to have an input frequency of at
+ * least 4x our max_freq.
+ */
+
+ div = DIV_ROUND_UP(gpll_hz, max_freq * 4);
+ return gpll_hz / div;
+}
+
static int rockchip_spi_probe(struct udevice *bus)
{
struct rockchip_spi_platdata *plat = dev_get_platdata(bus);
@@ -207,11 +246,13 @@ static int rockchip_spi_probe(struct udevice *bus)
priv->last_transaction_us = timer_get_us();
priv->max_freq = plat->frequency;
- /*
- * Use 99 MHz as our clock since it divides nicely into 594 MHz which
- * is the assumed speed for CLK_GENERAL.
- */
- ret = clk_set_rate(&priv->clk, 99000000);
+ /* Clamp the value from the DTS against any hardware limits */
+ if (priv->max_freq > ROCKCHIP_SPI_MAX_RATE)
+ priv->max_freq = ROCKCHIP_SPI_MAX_RATE;
+
+ /* Find a module-input clock that fits with the max_freq setting */
+ ret = clk_set_rate(&priv->clk,
+ rockchip_spi_calc_modclk(priv->max_freq));
if (ret < 0) {
debug("%s: Failed to set clock: %d\n", __func__, ret);
return ret;
@@ -371,10 +412,10 @@ static int rockchip_spi_set_speed(struct udevice *bus, uint speed)
{
struct rockchip_spi_priv *priv = dev_get_priv(bus);
- if (speed > ROCKCHIP_SPI_MAX_RATE)
- return -EINVAL;
+ /* Clamp to the maximum frequency specified in the DTS */
if (speed > priv->max_freq)
speed = priv->max_freq;
+
priv->speed_hz = speed;
return 0;
@@ -403,6 +444,7 @@ static const struct dm_spi_ops rockchip_spi_ops = {
static const struct udevice_id rockchip_spi_ids[] = {
{ .compatible = "rockchip,rk3288-spi" },
+ { .compatible = "rockchip,rk3399-spi" },
{ }
};
diff --git a/drivers/spi/rk_spi.h b/drivers/spi/rk_spi.h
index f1ac81203fa..02aa9d04368 100644
--- a/drivers/spi/rk_spi.h
+++ b/drivers/spi/rk_spi.h
@@ -119,6 +119,13 @@ enum {
};
#define ROCKCHIP_SPI_TIMEOUT_MS 1000
-#define ROCKCHIP_SPI_MAX_RATE 48000000
+
+/*
+ * We limit the maximum bitrate to 50MBit/s (50MHz) due to an assumed
+ * hardware limitation... the Linux kernel source has the following
+ * comment:
+ * "sclk_out: spi master internal logic in rk3x can support 50Mhz"
+ */
+#define ROCKCHIP_SPI_MAX_RATE 50000000
#endif /* __RK_SPI_H */
diff --git a/drivers/sysreset/Kconfig b/drivers/sysreset/Kconfig
index 966463036f1..b2f746494d2 100644
--- a/drivers/sysreset/Kconfig
+++ b/drivers/sysreset/Kconfig
@@ -23,4 +23,12 @@ config SYSRESET_PSCI
must be running on your system.
endif
+
+config SYSRESET_SYSCON
+ bool "Enable support for mfd syscon reboot driver"
+ select REGMAP
+ select SYSCON
+ help
+ Reboot support for generic SYSCON mapped register reset.
+
endmenu
diff --git a/drivers/sysreset/Makefile b/drivers/sysreset/Makefile
index 7bb840649ff..bd352e75415 100644
--- a/drivers/sysreset/Makefile
+++ b/drivers/sysreset/Makefile
@@ -6,6 +6,7 @@
obj-$(CONFIG_SYSRESET) += sysreset-uclass.o
obj-$(CONFIG_SYSRESET_PSCI) += sysreset_psci.o
+obj-$(CONFIG_SYSRESET_SYSCON) += sysreset_syscon.o
ifndef CONFIG_SPL_BUILD
obj-$(CONFIG_ROCKCHIP_RK3036) += sysreset_rk3036.o
diff --git a/drivers/sysreset/sysreset_syscon.c b/drivers/sysreset/sysreset_syscon.c
new file mode 100644
index 00000000000..3818faeb462
--- /dev/null
+++ b/drivers/sysreset/sysreset_syscon.c
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2017 Álvaro Fernández Rojas <noltari@gmail.com>
+ *
+ * Derived from linux/drivers/power/reset/syscon-reboot.c:
+ * Copyright (C) 2013, Applied Micro Circuits Corporation
+ * Author: Feng Kan <fkan@apm.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <regmap.h>
+#include <sysreset.h>
+#include <syscon.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+struct syscon_reboot_priv {
+ struct regmap *regmap;
+ unsigned int offset;
+ unsigned int mask;
+};
+
+static int syscon_reboot_request(struct udevice *dev, enum sysreset_t type)
+{
+ struct syscon_reboot_priv *priv = dev_get_priv(dev);
+
+ regmap_write(priv->regmap, priv->offset, priv->mask);
+
+ return -EINPROGRESS;
+}
+
+static struct sysreset_ops syscon_reboot_ops = {
+ .request = syscon_reboot_request,
+};
+
+int syscon_reboot_probe(struct udevice *dev)
+{
+ struct udevice *syscon;
+ struct syscon_reboot_priv *priv = dev_get_priv(dev);
+ int err;
+
+ err = uclass_get_device_by_phandle(UCLASS_SYSCON, dev,
+ "regmap", &syscon);
+ if (err) {
+ error("unable to find syscon device\n");
+ return err;
+ }
+
+ priv->regmap = syscon_get_regmap(syscon);
+ if (!priv->regmap) {
+ error("unable to find regmap\n");
+ return -ENODEV;
+ }
+
+ priv->offset = fdtdec_get_uint(gd->fdt_blob, dev_of_offset(dev),
+ "offset", 0);
+ priv->mask = fdtdec_get_uint(gd->fdt_blob, dev_of_offset(dev),
+ "mask", 0);
+
+ return 0;
+}
+
+static const struct udevice_id syscon_reboot_ids[] = {
+ { .compatible = "syscon-reboot" },
+ { /* sentinel */ }
+};
+
+U_BOOT_DRIVER(syscon_reboot) = {
+ .name = "syscon_reboot",
+ .id = UCLASS_SYSRESET,
+ .of_match = syscon_reboot_ids,
+ .probe = syscon_reboot_probe,
+ .priv_auto_alloc_size = sizeof(struct syscon_reboot_priv),
+ .ops = &syscon_reboot_ops,
+};
diff --git a/drivers/usb/eth/smsc95xx.c b/drivers/usb/eth/smsc95xx.c
index d4c8ea4a98a..26000a5a45b 100644
--- a/drivers/usb/eth/smsc95xx.c
+++ b/drivers/usb/eth/smsc95xx.c
@@ -998,7 +998,7 @@ int smsc95xx_eth_recv(struct udevice *dev, int flags, uchar **packetp)
}
*packetp = ptr + sizeof(packet_len);
- return packet_len;
+ return packet_len - 4;
err:
usb_ether_advance_rxbuf(ueth, -1);
@@ -1009,7 +1009,7 @@ static int smsc95xx_free_pkt(struct udevice *dev, uchar *packet, int packet_len)
{
struct smsc95xx_private *priv = dev_get_priv(dev);
- packet_len = ALIGN(packet_len, 4);
+ packet_len = ALIGN(packet_len + sizeof(u32), 4);
usb_ether_advance_rxbuf(&priv->ueth, sizeof(u32) + packet_len);
return 0;
diff --git a/drivers/usb/gadget/f_fastboot.c b/drivers/usb/gadget/f_fastboot.c
index 2160b1ccdc3..7cd6d24bf50 100644
--- a/drivers/usb/gadget/f_fastboot.c
+++ b/drivers/usb/gadget/f_fastboot.c
@@ -432,9 +432,15 @@ static void cb_getvar(struct usb_ep *ep, struct usb_request *req)
else
strcpy(response, "FAILValue not set");
} else {
- char envstr[32];
+ char *envstr;
- snprintf(envstr, sizeof(envstr) - 1, "fastboot.%s", cmd);
+ envstr = malloc(strlen("fastboot.") + strlen(cmd) + 1);
+ if (!envstr) {
+ fastboot_tx_write_str("FAILmalloc error");
+ return;
+ }
+
+ sprintf(envstr, "fastboot.%s", cmd);
s = getenv(envstr);
if (s) {
strncat(response, s, chars_left);
@@ -442,6 +448,8 @@ static void cb_getvar(struct usb_ep *ep, struct usb_request *req)
printf("WARNING: unknown variable: %s\n", cmd);
strcpy(response, "FAILVariable not implemented");
}
+
+ free(envstr);
}
fastboot_tx_write_str(response);
}
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
index fb5aa6f8891..9a67e43c2d9 100644
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -57,6 +57,7 @@ endif # USB_XHCI_HCD
config USB_EHCI_HCD
bool "EHCI HCD (USB 2.0) support"
+ default y if ARCH_MX5 || ARCH_MX6
select USB_HOST
---help---
The Enhanced Host Controller Interface (EHCI) is standard for USB 2.0
@@ -74,12 +75,6 @@ config USB_EHCI_HCD
You may want to read <file:Documentation/usb/ehci.txt>.
-config USB_EHCI
- bool
- default USB_EHCI_HCD
- ---help---
- TODO: rename after most boards switch to Kconfig
-
if USB_EHCI_HCD
config USB_EHCI_ATMEL
@@ -90,8 +85,8 @@ config USB_EHCI_ATMEL
Enables support for the on-chip EHCI controller on Atmel chips.
config USB_EHCI_MARVELL
- bool "Support for MVEBU (AXP / A38x) on-chip EHCI USB controller"
- depends on ARCH_MVEBU
+ bool "Support for Marvell on-chip EHCI USB controller"
+ depends on ARCH_MVEBU || KIRKWOOD || ORION5X
default y
---help---
Enables support for the on-chip EHCI controller on MVEBU SoCs.
@@ -110,6 +105,14 @@ config USB_EHCI_MX7
---help---
Enables support for the on-chip EHCI controller on i.MX7 SoCs.
+config USB_EHCI_OMAP
+ bool "Support for OMAP3+ on-chip EHCI USB controller"
+ depends on ARCH_OMAP2PLUS
+ default y
+ ---help---
+ Enables support for the on-chip EHCI controller on OMAP3 and later
+ SoCs.
+
if USB_EHCI_MX7
config MXC_USB_OTG_HACTIVE
diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile
index 58c0cf54c21..bf354fe8d52 100644
--- a/drivers/usb/host/Makefile
+++ b/drivers/usb/host/Makefile
@@ -24,7 +24,7 @@ obj-$(CONFIG_USB_OHCI_LPC32XX) += ohci-lpc32xx.o
obj-$(CONFIG_USB_OHCI_GENERIC) += ohci-generic.o
# echi
-obj-$(CONFIG_USB_EHCI) += ehci-hcd.o
+obj-$(CONFIG_USB_EHCI_HCD) += ehci-hcd.o
obj-$(CONFIG_USB_EHCI_ARMADA100) += ehci-armada100.o utmi-armada100.o
obj-$(CONFIG_USB_EHCI_ATMEL) += ehci-atmel.o
ifdef CONFIG_MPC512X
diff --git a/drivers/usb/musb-new/linux-compat.h b/drivers/usb/musb-new/linux-compat.h
index 92449775799..4dae83ed685 100644
--- a/drivers/usb/musb-new/linux-compat.h
+++ b/drivers/usb/musb-new/linux-compat.h
@@ -30,7 +30,7 @@
#define CONFIG_SOC_OMAP3430
#endif
-#ifdef CONFIG_OMAP4430
+#ifdef CONFIG_OMAP44XX
#define CONFIG_ARCH_OMAP4
#endif
diff --git a/drivers/usb/musb-new/omap2430.c b/drivers/usb/musb-new/omap2430.c
index 684ad9539af..ba22dfe6cb0 100644
--- a/drivers/usb/musb-new/omap2430.c
+++ b/drivers/usb/musb-new/omap2430.c
@@ -441,7 +441,7 @@ static int omap2430_musb_enable(struct musb *musb)
twl6030_usb_device_settings();
#endif
-#ifdef CONFIG_OMAP4430
+#ifdef CONFIG_OMAP44XX
u32 *usbotghs_control = (u32 *)((*ctrl)->control_usbotghs_ctrl);
*usbotghs_control = USBOTGHS_CONTROL_AVALID |
USBOTGHS_CONTROL_VBUSVALID | USBOTGHS_CONTROL_IDDIG;
diff --git a/drivers/usb/musb/omap3.c b/drivers/usb/musb/omap3.c
index 97da529b44e..57889ef0e7d 100644
--- a/drivers/usb/musb/omap3.c
+++ b/drivers/usb/musb/omap3.c
@@ -55,7 +55,7 @@ static struct omap3_otg_regs *otg;
#define OMAP3_OTG_SYSSTATUS_RESETDONE 0x0001
/* OMAP4430 has an internal PHY, use it */
-#ifdef CONFIG_OMAP4430
+#ifdef CONFIG_OMAP44XX
#define OMAP3_OTG_INTERFSEL_OMAP 0x0000
#else
#define OMAP3_OTG_INTERFSEL_OMAP 0x0001
@@ -118,11 +118,11 @@ int musb_platform_init(void)
stdby &= ~OMAP3_OTG_FORCESTDBY_STANDBY;
writel(stdby, &otg->forcestdby);
-#ifdef CONFIG_OMAP3_EVM
+#ifdef CONFIG_TARGET_OMAP3_EVM
musb_cfg.extvbus = omap3_evm_need_extvbus();
#endif
-#ifdef CONFIG_OMAP4430
+#ifdef CONFIG_OMAP44XX
u32 *usbotghs_control =
(u32 *)((*ctrl)->control_usbotghs_ctrl);
*usbotghs_control = 0x15;
diff --git a/drivers/usb/musb/omap3.h b/drivers/usb/musb/omap3.h
index ae645c72de7..d91ad0a85b3 100644
--- a/drivers/usb/musb/omap3.h
+++ b/drivers/usb/musb/omap3.h
@@ -32,7 +32,7 @@
int musb_platform_init(void);
-#ifdef CONFIG_OMAP3_EVM
+#ifdef CONFIG_TARGET_OMAP3_EVM
extern u8 omap3_evm_need_extvbus(void);
#endif
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index e29c3fcfc6d..61dfed8c063 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -425,15 +425,7 @@ config VIDEO_FSL_DCU_MAX_FB_SIZE_MB
Set maximum framebuffer size to be used for Freescale Display
Controller Unit (DCU4).
-config VIDEO_ROCKCHIP
- bool "Enable Rockchip video support"
- depends on DM_VIDEO
- help
- Rockchip SoCs provide video output capabilities for High-Definition
- Multimedia Interface (HDMI), Low-voltage Differential Signalling
- (LVDS), embedded DisplayPort (eDP) and Display Serial Interface
- (DSI). This driver supports the on-chip video output device, and
- targets the Rockchip RK3288.
+source "drivers/video/rockchip/Kconfig"
config VIDEO_SANDBOX_SDL
bool "Enable sandbox video console using SDL"
@@ -627,4 +619,13 @@ config LCD
CONFIG option. See the README for details. Drives which have been
converted to driver model will instead used CONFIG_DM_VIDEO.
+config VIDEO_DW_HDMI
+ bool
+ help
+ Enables the common driver code for the Designware HDMI TX
+ block found in SoCs from various vendors.
+ As this does not provide any functionality by itself (but
+ rather requires a SoC-specific glue driver to call it), it
+ can not be enabled from the configuration menu.
+
endmenu
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index a80af3104d1..58f5de52001 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -57,6 +57,7 @@ obj-$(CONFIG_VIDEO_VESA) += vesa.o
obj-$(CONFIG_FORMIKE) += formike.o
obj-$(CONFIG_LG4573) += lg4573.o
obj-$(CONFIG_AM335X_LCD) += am335x-fb.o
+obj-$(CONFIG_VIDEO_DW_HDMI) += dw_hdmi.o
obj-${CONFIG_VIDEO_TEGRA124} += tegra124/
obj-${CONFIG_EXYNOS_FB} += exynos/
diff --git a/drivers/video/bcm2835.c b/drivers/video/bcm2835.c
index cc6454f10d4..952ef596611 100644
--- a/drivers/video/bcm2835.c
+++ b/drivers/video/bcm2835.c
@@ -5,124 +5,56 @@
*/
#include <common.h>
-#include <lcd.h>
-#include <memalign.h>
-#include <phys2bus.h>
+#include <dm.h>
+#include <video.h>
#include <asm/arch/mbox.h>
-#include <asm/global_data.h>
+#include <asm/arch/msg.h>
-DECLARE_GLOBAL_DATA_PTR;
-
-/* Global variables that lcd.c expects to exist */
-vidinfo_t panel_info;
-
-static u32 bcm2835_pitch;
-
-struct msg_query {
- struct bcm2835_mbox_hdr hdr;
- struct bcm2835_mbox_tag_physical_w_h physical_w_h;
- u32 end_tag;
-};
-
-struct msg_setup {
- struct bcm2835_mbox_hdr hdr;
- struct bcm2835_mbox_tag_physical_w_h physical_w_h;
- struct bcm2835_mbox_tag_virtual_w_h virtual_w_h;
- struct bcm2835_mbox_tag_depth depth;
- struct bcm2835_mbox_tag_pixel_order pixel_order;
- struct bcm2835_mbox_tag_alpha_mode alpha_mode;
- struct bcm2835_mbox_tag_virtual_offset virtual_offset;
- struct bcm2835_mbox_tag_overscan overscan;
- struct bcm2835_mbox_tag_allocate_buffer allocate_buffer;
- struct bcm2835_mbox_tag_pitch pitch;
- u32 end_tag;
-};
-
-void lcd_ctrl_init(void *lcdbase)
+static int bcm2835_video_probe(struct udevice *dev)
{
- ALLOC_CACHE_ALIGN_BUFFER(struct msg_query, msg_query, 1);
- ALLOC_CACHE_ALIGN_BUFFER(struct msg_setup, msg_setup, 1);
+ struct video_uc_platdata *plat = dev_get_uclass_platdata(dev);
+ struct video_priv *uc_priv = dev_get_uclass_priv(dev);
int ret;
- u32 w, h;
- u32 fb_start, fb_end;
+ int w, h, pitch;
+ ulong fb_base, fb_size, fb_start, fb_end;
debug("bcm2835: Query resolution...\n");
-
- BCM2835_MBOX_INIT_HDR(msg_query);
- BCM2835_MBOX_INIT_TAG_NO_REQ(&msg_query->physical_w_h,
- GET_PHYSICAL_W_H);
- ret = bcm2835_mbox_call_prop(BCM2835_MBOX_PROP_CHAN, &msg_query->hdr);
- if (ret) {
- printf("bcm2835: Could not query display resolution\n");
- /* FIXME: How to disable the LCD to prevent errors? hang()? */
- return;
- }
-
- w = msg_query->physical_w_h.body.resp.width;
- h = msg_query->physical_w_h.body.resp.height;
+ ret = bcm2835_get_video_size(&w, &h);
+ if (ret)
+ return -EIO;
debug("bcm2835: Setting up display for %d x %d\n", w, h);
-
- BCM2835_MBOX_INIT_HDR(msg_setup);
- BCM2835_MBOX_INIT_TAG(&msg_setup->physical_w_h, SET_PHYSICAL_W_H);
- msg_setup->physical_w_h.body.req.width = w;
- msg_setup->physical_w_h.body.req.height = h;
- BCM2835_MBOX_INIT_TAG(&msg_setup->virtual_w_h, SET_VIRTUAL_W_H);
- msg_setup->virtual_w_h.body.req.width = w;
- msg_setup->virtual_w_h.body.req.height = h;
- BCM2835_MBOX_INIT_TAG(&msg_setup->depth, SET_DEPTH);
- msg_setup->depth.body.req.bpp = 32;
- BCM2835_MBOX_INIT_TAG(&msg_setup->pixel_order, SET_PIXEL_ORDER);
- msg_setup->pixel_order.body.req.order = BCM2835_MBOX_PIXEL_ORDER_RGB;
- BCM2835_MBOX_INIT_TAG(&msg_setup->alpha_mode, SET_ALPHA_MODE);
- msg_setup->alpha_mode.body.req.alpha = BCM2835_MBOX_ALPHA_MODE_IGNORED;
- BCM2835_MBOX_INIT_TAG(&msg_setup->virtual_offset, SET_VIRTUAL_OFFSET);
- msg_setup->virtual_offset.body.req.x = 0;
- msg_setup->virtual_offset.body.req.y = 0;
- BCM2835_MBOX_INIT_TAG(&msg_setup->overscan, SET_OVERSCAN);
- msg_setup->overscan.body.req.top = 0;
- msg_setup->overscan.body.req.bottom = 0;
- msg_setup->overscan.body.req.left = 0;
- msg_setup->overscan.body.req.right = 0;
- BCM2835_MBOX_INIT_TAG(&msg_setup->allocate_buffer, ALLOCATE_BUFFER);
- msg_setup->allocate_buffer.body.req.alignment = 0x100;
- BCM2835_MBOX_INIT_TAG_NO_REQ(&msg_setup->pitch, GET_PITCH);
-
- ret = bcm2835_mbox_call_prop(BCM2835_MBOX_PROP_CHAN, &msg_setup->hdr);
- if (ret) {
- printf("bcm2835: Could not configure display\n");
- /* FIXME: How to disable the LCD to prevent errors? hang()? */
- return;
- }
-
- w = msg_setup->physical_w_h.body.resp.width;
- h = msg_setup->physical_w_h.body.resp.height;
- bcm2835_pitch = msg_setup->pitch.body.resp.pitch;
+ ret = bcm2835_set_video_params(&w, &h, 32, BCM2835_MBOX_PIXEL_ORDER_RGB,
+ BCM2835_MBOX_ALPHA_MODE_IGNORED,
+ &fb_base, &fb_size, &pitch);
debug("bcm2835: Final resolution is %d x %d\n", w, h);
- panel_info.vl_col = w;
- panel_info.vl_row = h;
- panel_info.vl_bpix = LCD_COLOR32;
-
- gd->fb_base = bus_to_phys(
- msg_setup->allocate_buffer.body.resp.fb_address);
-
/* Enable dcache for the frame buffer */
- fb_start = gd->fb_base & ~(MMU_SECTION_SIZE - 1);
- fb_end = gd->fb_base + msg_setup->allocate_buffer.body.resp.fb_size;
+ fb_start = fb_base & ~(MMU_SECTION_SIZE - 1);
+ fb_end = fb_base + fb_size;
fb_end = ALIGN(fb_end, 1 << MMU_SECTION_SHIFT);
mmu_set_region_dcache_behaviour(fb_start, fb_end - fb_start,
- DCACHE_WRITEBACK);
- lcd_set_flush_dcache(1);
-}
+ DCACHE_WRITEBACK);
+ video_set_flush_dcache(dev, true);
-void lcd_enable(void)
-{
-}
+ uc_priv->xsize = w;
+ uc_priv->ysize = h;
+ uc_priv->bpix = VIDEO_BPP32;
+ plat->base = fb_base;
+ plat->size = fb_size;
-int lcd_get_size(int *line_length)
-{
- *line_length = bcm2835_pitch;
- return *line_length * panel_info.vl_row;
+ return 0;
}
+
+static const struct udevice_id bcm2835_video_ids[] = {
+ { .compatible = "brcm,bcm2835-hdmi" },
+ { }
+};
+
+U_BOOT_DRIVER(bcm2835_video) = {
+ .name = "bcm2835_video",
+ .id = UCLASS_VIDEO,
+ .of_match = bcm2835_video_ids,
+ .probe = bcm2835_video_probe,
+};
diff --git a/drivers/video/dw_hdmi.c b/drivers/video/dw_hdmi.c
index 8a531098237..6039d676c5b 100644
--- a/drivers/video/dw_hdmi.c
+++ b/drivers/video/dw_hdmi.c
@@ -414,13 +414,9 @@ static void hdmi_av_composer(struct dw_hdmi *hdmi,
HDMI_FC_INVIDCONF_DE_IN_POLARITY_ACTIVE_HIGH :
HDMI_FC_INVIDCONF_DE_IN_POLARITY_ACTIVE_LOW);
- /*
- * TODO(sjg@chromium.org>: Need to check for HDMI / DVI
- * inv_val |= (edid->hdmi_monitor_detected ?
- * HDMI_FC_INVIDCONF_DVI_MODEZ_HDMI_MODE :
- * HDMI_FC_INVIDCONF_DVI_MODEZ_DVI_MODE);
- */
- inv_val |= HDMI_FC_INVIDCONF_DVI_MODEZ_HDMI_MODE;
+ inv_val |= (edid->hdmi_monitor ?
+ HDMI_FC_INVIDCONF_DVI_MODEZ_HDMI_MODE :
+ HDMI_FC_INVIDCONF_DVI_MODEZ_DVI_MODE);
inv_val |= HDMI_FC_INVIDCONF_R_V_BLANK_IN_OSC_ACTIVE_LOW;
@@ -459,7 +455,7 @@ static void hdmi_av_composer(struct dw_hdmi *hdmi,
}
/* hdmi initialization step b.4 */
-static void hdmi_enable_video_path(struct dw_hdmi *hdmi)
+static void hdmi_enable_video_path(struct dw_hdmi *hdmi, bool audio)
{
uint clkdis;
@@ -484,8 +480,10 @@ static void hdmi_enable_video_path(struct dw_hdmi *hdmi)
clkdis &= ~HDMI_MC_CLKDIS_TMDSCLK_DISABLE;
hdmi_write(hdmi, clkdis, HDMI_MC_CLKDIS);
- clkdis &= ~HDMI_MC_CLKDIS_AUDCLK_DISABLE;
- hdmi_write(hdmi, clkdis, HDMI_MC_CLKDIS);
+ if (audio) {
+ clkdis &= ~HDMI_MC_CLKDIS_AUDCLK_DISABLE;
+ hdmi_write(hdmi, clkdis, HDMI_MC_CLKDIS);
+ }
}
/* workaround to clear the overflow condition */
@@ -716,7 +714,8 @@ int dw_hdmi_enable(struct dw_hdmi *hdmi, const struct display_timing *edid)
{
int ret;
- debug("hdmi, mode info : clock %d hdis %d vdis %d\n",
+ debug("%s, mode info : clock %d hdis %d vdis %d\n",
+ edid->hdmi_monitor ? "hdmi" : "dvi",
edid->pixelclock.typ, edid->hactive.typ, edid->vactive.typ);
hdmi_av_composer(hdmi, edid);
@@ -725,11 +724,13 @@ int dw_hdmi_enable(struct dw_hdmi *hdmi, const struct display_timing *edid)
if (ret)
return ret;
- hdmi_enable_video_path(hdmi);
+ hdmi_enable_video_path(hdmi, edid->hdmi_monitor);
- hdmi_audio_fifo_reset(hdmi);
- hdmi_audio_set_format(hdmi);
- hdmi_audio_set_samplerate(hdmi, edid->pixelclock.typ);
+ if (edid->hdmi_monitor) {
+ hdmi_audio_fifo_reset(hdmi);
+ hdmi_audio_set_format(hdmi);
+ hdmi_audio_set_samplerate(hdmi, edid->pixelclock.typ);
+ }
hdmi_video_packetize(hdmi);
hdmi_video_sample(hdmi);
diff --git a/drivers/video/ld9040.c b/drivers/video/ld9040.c
index 23fe783c884..8a90c25797e 100644
--- a/drivers/video/ld9040.c
+++ b/drivers/video/ld9040.c
@@ -10,10 +10,6 @@
#include <common.h>
#include <spi.h>
-static const unsigned char SEQ_SWRESET[] = {
- 0x01,
-};
-
static const unsigned char SEQ_USER_SETTING[] = {
0xF0, 0x5A, 0x5A
};
@@ -22,10 +18,6 @@ static const unsigned char SEQ_ELVSS_ON[] = {
0xB1, 0x0D, 0x00, 0x16,
};
-static const unsigned char SEQ_TEMP_SWIRE[] = {
- 0xB2, 0x06, 0x06, 0x06, 0x06,
-};
-
static const unsigned char SEQ_GTCON[] = {
0xF7, 0x09, 0x00, 0x00,
};
@@ -46,10 +38,6 @@ static const unsigned char SEQ_GAMMA_CTRL[] = {
0xFB, 0x02, 0x5A,
};
-static const unsigned char SEQ_APON[] = {
- 0xF3, 0x00, 0x00, 0x00, 0x0A, 0x02,
-};
-
static const unsigned char SEQ_DISPCTL[] = {
0xF2, 0x02, 0x08, 0x08, 0x10, 0x10,
};
@@ -66,10 +54,6 @@ static const unsigned char SEQ_SLPOUT[] = {
0x11,
};
-static const unsigned char SEQ_SLPIN[] = {
- 0x10,
-};
-
static const unsigned char SEQ_DISPON[] = {
0x29,
};
diff --git a/drivers/video/rockchip/Kconfig b/drivers/video/rockchip/Kconfig
new file mode 100644
index 00000000000..80e399f7d7d
--- /dev/null
+++ b/drivers/video/rockchip/Kconfig
@@ -0,0 +1,51 @@
+#
+# Video drivers selection for rockchip soc. These configs only impact the
+# compile process. You can surely check all the options. In this case, all the
+# display driver will be compiled, but which drivers finally will be used is
+# decided by device tree configuration. What's more, enable needed power for
+# display by configure the device tree, and the vop driver will do the rest.
+#
+# Author: Eric Gao <eric.gao@rock-chips.com>
+#
+
+menuconfig VIDEO_ROCKCHIP
+ bool "Enable Rockchip Video Support"
+ depends on DM_VIDEO
+ help
+ Rockchip SoCs provide video output capabilities for High-Definition
+ Multimedia Interface (HDMI), Low-voltage Differential Signalling
+ (LVDS), embedded DisplayPort (eDP) and Display Serial Interface
+ (DSI). This driver supports the on-chip video output device, and
+ targets the Rockchip RK3288 and RK3399.
+
+if VIDEO_ROCKCHIP
+
+config DISPLAY_ROCKCHIP_EDP
+ bool "EDP Port"
+ depends on VIDEO_ROCKCHIP
+ help
+ This enables Embedded DisplayPort(EDP) display support.
+
+config DISPLAY_ROCKCHIP_LVDS
+ bool "LVDS Port"
+ depends on VIDEO_ROCKCHIP
+ help
+ This enables Low-voltage Differential Signaling(LVDS) display
+ support.
+
+config DISPLAY_ROCKCHIP_HDMI
+ bool "HDMI port"
+ select VIDEO_DW_HDMI
+ depends on VIDEO_ROCKCHIP
+ help
+ This enables High-Definition Multimedia Interface display support.
+
+config DISPLAY_ROCKCHIP_MIPI
+ bool "MIPI Port"
+ depends on VIDEO_ROCKCHIP
+ help
+ This enables Mobile Industry Processor Interface(MIPI) display
+ support. The mipi controller and dphy on rk3288& rk3399 support
+ 16,18, 24 bits per pixel with upto 2k resolution ratio.
+
+endif
diff --git a/drivers/video/rockchip/Makefile b/drivers/video/rockchip/Makefile
index 755350b9341..cd54b12a4e4 100644
--- a/drivers/video/rockchip/Makefile
+++ b/drivers/video/rockchip/Makefile
@@ -5,4 +5,10 @@
# SPDX-License-Identifier: GPL-2.0+
#
-obj-y += rk_edp.o rk_hdmi.o rk_vop.o rk_lvds.o ../dw_hdmi.o
+ifdef CONFIG_VIDEO_ROCKCHIP
+obj-y += rk_vop.o
+obj-$(CONFIG_DISPLAY_ROCKCHIP_EDP) += rk_edp.o
+obj-$(CONFIG_DISPLAY_ROCKCHIP_LVDS) += rk_lvds.o
+obj-$(CONFIG_DISPLAY_ROCKCHIP_HDMI) += rk_hdmi.o
+obj-$(CONFIG_DISPLAY_ROCKCHIP_MIPI) += rk_mipi.o
+endif
diff --git a/drivers/video/rockchip/rk_mipi.c b/drivers/video/rockchip/rk_mipi.c
new file mode 100644
index 00000000000..4d9d12e1d75
--- /dev/null
+++ b/drivers/video/rockchip/rk_mipi.c
@@ -0,0 +1,491 @@
+/*
+ * Copyright (c) 2017, Fuzhou Rockchip Electronics Co., Ltd
+ * Author: Eric Gao <eric.gao@rock-chips.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <clk.h>
+#include <display.h>
+#include <dm.h>
+#include <fdtdec.h>
+#include <panel.h>
+#include <regmap.h>
+#include <syscon.h>
+#include <asm/gpio.h>
+#include <asm/hardware.h>
+#include <asm/io.h>
+#include <dm/uclass-internal.h>
+#include <linux/kernel.h>
+#include <asm/arch/clock.h>
+#include <asm/arch/cru_rk3399.h>
+#include <asm/arch/grf_rk3399.h>
+#include <asm/arch/rockchip_mipi_dsi.h>
+#include <dt-bindings/clock/rk3288-cru.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/*
+ * Private information for rk mipi
+ *
+ * @regs: mipi controller address
+ * @grf: GRF register
+ * @panel: panel assined by device tree
+ * @ref_clk: reference clock for mipi dsi pll
+ * @sysclk: config clock for mipi dsi register
+ * @pix_clk: pixel clock for vop->dsi data transmission
+ * @phy_clk: mipi dphy output clock
+ * @txbyte_clk: clock for dsi->dphy high speed data transmission
+ * @txesc_clk: clock for tx esc mode
+ */
+struct rk_mipi_priv {
+ void __iomem *regs;
+ struct rk3399_grf_regs *grf;
+ struct udevice *panel;
+ struct mipi_dsi *dsi;
+ u32 ref_clk;
+ u32 sys_clk;
+ u32 pix_clk;
+ u32 phy_clk;
+ u32 txbyte_clk;
+ u32 txesc_clk;
+};
+
+static int rk_mipi_read_timing(struct udevice *dev,
+ struct display_timing *timing)
+{
+ int ret;
+
+ ret = fdtdec_decode_display_timing(gd->fdt_blob, dev_of_offset(dev),
+ 0, timing);
+ if (ret) {
+ debug("%s: Failed to decode display timing (ret=%d)\n",
+ __func__, ret);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/*
+ * Register write function used only for mipi dsi controller.
+ * Parameter:
+ * @regs: mipi controller address
+ * @reg: combination of regaddr(16bit)|bitswidth(8bit)|offset(8bit) you can
+ * use define in rk_mipi.h directly for this parameter
+ * @val: value that will be write to specified bits of register
+ */
+static void rk_mipi_dsi_write(u32 regs, u32 reg, u32 val)
+{
+ u32 dat;
+ u32 mask;
+ u32 offset = (reg >> OFFSET_SHIFT) & 0xff;
+ u32 bits = (reg >> BITS_SHIFT) & 0xff;
+ u64 addr = (reg >> ADDR_SHIFT) + regs;
+
+ /* Mask for specifiled bits,the corresponding bits will be clear */
+ mask = ~((0xffffffff << offset) & (0xffffffff >> (32 - offset - bits)));
+
+ /* Make sure val in the available range */
+ val &= ~(0xffffffff << bits);
+
+ /* Get register's original val */
+ dat = readl(addr);
+
+ /* Clear specified bits */
+ dat &= mask;
+
+ /* Fill specified bits */
+ dat |= val << offset;
+
+ writel(dat, addr);
+}
+
+static int rk_mipi_dsi_enable(struct udevice *dev,
+ const struct display_timing *timing)
+{
+ int node, timing_node;
+ int val;
+ struct rk_mipi_priv *priv = dev_get_priv(dev);
+ u64 regs = (u64)priv->regs;
+ struct display_plat *disp_uc_plat = dev_get_uclass_platdata(dev);
+ u32 txbyte_clk = priv->txbyte_clk;
+ u32 txesc_clk = priv->txesc_clk;
+
+ txesc_clk = txbyte_clk/(txbyte_clk/txesc_clk + 1);
+
+ /* Select the video source */
+ switch (disp_uc_plat->source_id) {
+ case VOP_B:
+ rk_clrsetreg(&priv->grf->soc_con20, GRF_DSI0_VOP_SEL_MASK,
+ GRF_DSI0_VOP_SEL_B << GRF_DSI0_VOP_SEL_SHIFT);
+ break;
+ case VOP_L:
+ rk_clrsetreg(&priv->grf->soc_con20, GRF_DSI0_VOP_SEL_MASK,
+ GRF_DSI0_VOP_SEL_L << GRF_DSI0_VOP_SEL_SHIFT);
+ break;
+ default:
+ debug("%s: Invalid VOP id\n", __func__);
+ return -EINVAL;
+ }
+
+ /* Set Controller as TX mode */
+ val = GRF_DPHY_TX0_RXMODE_DIS << GRF_DPHY_TX0_RXMODE_SHIFT;
+ rk_clrsetreg(&priv->grf->soc_con22, GRF_DPHY_TX0_RXMODE_MASK, val);
+
+ /* Exit tx stop mode */
+ val |= GRF_DPHY_TX0_TXSTOPMODE_DIS << GRF_DPHY_TX0_TXSTOPMODE_SHIFT;
+ rk_clrsetreg(&priv->grf->soc_con22, GRF_DPHY_TX0_TXSTOPMODE_MASK, val);
+
+ /* Disable turnequest */
+ val |= GRF_DPHY_TX0_TURNREQUEST_DIS << GRF_DPHY_TX0_TURNREQUEST_SHIFT;
+ rk_clrsetreg(&priv->grf->soc_con22, GRF_DPHY_TX0_TURNREQUEST_MASK, val);
+
+ /* Set Display timing parameter */
+ rk_mipi_dsi_write(regs, VID_HSA_TIME, timing->hsync_len.typ);
+ rk_mipi_dsi_write(regs, VID_HBP_TIME, timing->hback_porch.typ);
+ rk_mipi_dsi_write(regs, VID_HLINE_TIME, (timing->hsync_len.typ
+ + timing->hback_porch.typ + timing->hactive.typ
+ + timing->hfront_porch.typ));
+ rk_mipi_dsi_write(regs, VID_VSA_LINES, timing->vsync_len.typ);
+ rk_mipi_dsi_write(regs, VID_VBP_LINES, timing->vback_porch.typ);
+ rk_mipi_dsi_write(regs, VID_VFP_LINES, timing->vfront_porch.typ);
+ rk_mipi_dsi_write(regs, VID_ACTIVE_LINES, timing->vactive.typ);
+
+ /* Set Signal Polarity */
+ val = (timing->flags & DISPLAY_FLAGS_HSYNC_LOW) ? 1 : 0;
+ rk_mipi_dsi_write(regs, HSYNC_ACTIVE_LOW, val);
+
+ val = (timing->flags & DISPLAY_FLAGS_VSYNC_LOW) ? 1 : 0;
+ rk_mipi_dsi_write(regs, VSYNC_ACTIVE_LOW, val);
+
+ val = (timing->flags & DISPLAY_FLAGS_DE_LOW) ? 1 : 0;
+ rk_mipi_dsi_write(regs, DISPLAY_FLAGS_DE_LOW, val);
+
+ val = (timing->flags & DISPLAY_FLAGS_PIXDATA_NEGEDGE) ? 1 : 0;
+ rk_mipi_dsi_write(regs, COLORM_ACTIVE_LOW, val);
+
+ /* Set video mode */
+ rk_mipi_dsi_write(regs, CMD_VIDEO_MODE, VIDEO_MODE);
+
+ /* Set video mode transmission type as burst mode */
+ rk_mipi_dsi_write(regs, VID_MODE_TYPE, BURST_MODE);
+
+ /* Set pix num in a video package */
+ rk_mipi_dsi_write(regs, VID_PKT_SIZE, 0x4b0);
+
+ /* Set dpi color coding depth 24 bit */
+ timing_node = fdt_subnode_offset(gd->fdt_blob, dev_of_offset(dev),
+ "display-timings");
+ node = fdt_first_subnode(gd->fdt_blob, timing_node);
+ val = fdtdec_get_int(gd->fdt_blob, node, "bits-per-pixel", -1);
+ switch (val) {
+ case 16:
+ rk_mipi_dsi_write(regs, DPI_COLOR_CODING, DPI_16BIT_CFG_1);
+ break;
+ case 24:
+ rk_mipi_dsi_write(regs, DPI_COLOR_CODING, DPI_24BIT);
+ break;
+ case 30:
+ rk_mipi_dsi_write(regs, DPI_COLOR_CODING, DPI_30BIT);
+ break;
+ default:
+ rk_mipi_dsi_write(regs, DPI_COLOR_CODING, DPI_24BIT);
+ }
+ /* Enable low power mode */
+ rk_mipi_dsi_write(regs, LP_CMD_EN, 1);
+ rk_mipi_dsi_write(regs, LP_HFP_EN, 1);
+ rk_mipi_dsi_write(regs, LP_VACT_EN, 1);
+ rk_mipi_dsi_write(regs, LP_VFP_EN, 1);
+ rk_mipi_dsi_write(regs, LP_VBP_EN, 1);
+ rk_mipi_dsi_write(regs, LP_VSA_EN, 1);
+
+ /* Division for timeout counter clk */
+ rk_mipi_dsi_write(regs, TO_CLK_DIVISION, 0x0a);
+
+ /* Tx esc clk division from txbyte clk */
+ rk_mipi_dsi_write(regs, TX_ESC_CLK_DIVISION, txbyte_clk/txesc_clk);
+
+ /* Timeout count for hs<->lp transation between Line period */
+ rk_mipi_dsi_write(regs, HSTX_TO_CNT, 0x3e8);
+
+ /* Phy State transfer timing */
+ rk_mipi_dsi_write(regs, PHY_STOP_WAIT_TIME, 32);
+ rk_mipi_dsi_write(regs, PHY_TXREQUESTCLKHS, 1);
+ rk_mipi_dsi_write(regs, PHY_HS2LP_TIME, 0x14);
+ rk_mipi_dsi_write(regs, PHY_LP2HS_TIME, 0x10);
+ rk_mipi_dsi_write(regs, MAX_RD_TIME, 0x2710);
+
+ /* Power on */
+ rk_mipi_dsi_write(regs, SHUTDOWNZ, 1);
+
+ return 0;
+}
+
+/* rk mipi dphy write function. It is used to write test data to dphy */
+static void rk_mipi_phy_write(u32 regs, unsigned char test_code,
+ unsigned char *test_data, unsigned char size)
+{
+ int i = 0;
+
+ /* Write Test code */
+ rk_mipi_dsi_write(regs, PHY_TESTCLK, 1);
+ rk_mipi_dsi_write(regs, PHY_TESTDIN, test_code);
+ rk_mipi_dsi_write(regs, PHY_TESTEN, 1);
+ rk_mipi_dsi_write(regs, PHY_TESTCLK, 0);
+ rk_mipi_dsi_write(regs, PHY_TESTEN, 0);
+
+ /* Write Test data */
+ for (i = 0; i < size; i++) {
+ rk_mipi_dsi_write(regs, PHY_TESTCLK, 0);
+ rk_mipi_dsi_write(regs, PHY_TESTDIN, test_data[i]);
+ rk_mipi_dsi_write(regs, PHY_TESTCLK, 1);
+ }
+}
+
+/*
+ * Mipi dphy config function. Calculate the suitable prediv, feedback div,
+ * fsfreqrang value ,cap ,lpf and so on according to the given pix clk rate,
+ * and then enable phy.
+ */
+static int rk_mipi_phy_enable(struct udevice *dev)
+{
+ int i;
+ struct rk_mipi_priv *priv = dev_get_priv(dev);
+ u64 regs = (u64)priv->regs;
+ u64 fbdiv;
+ u64 prediv = 1;
+ u32 max_fbdiv = 512;
+ u32 max_prediv, min_prediv;
+ u64 ddr_clk = priv->phy_clk;
+ u32 refclk = priv->ref_clk;
+ u32 remain = refclk;
+ unsigned char test_data[2] = {0};
+
+ int freq_rang[][2] = {
+ {90, 0x01}, {100, 0x10}, {110, 0x20}, {130, 0x01},
+ {140, 0x11}, {150, 0x21}, {170, 0x02}, {180, 0x12},
+ {200, 0x22}, {220, 0x03}, {240, 0x13}, {250, 0x23},
+ {270, 0x04}, {300, 0x14}, {330, 0x05}, {360, 0x15},
+ {400, 0x25}, {450, 0x06}, {500, 0x16}, {550, 0x07},
+ {600, 0x17}, {650, 0x08}, {700, 0x18}, {750, 0x09},
+ {800, 0x19}, {850, 0x29}, {900, 0x39}, {950, 0x0a},
+ {1000, 0x1a}, {1050, 0x2a}, {1100, 0x3a}, {1150, 0x0b},
+ {1200, 0x1b}, {1250, 0x2b}, {1300, 0x3b}, {1350, 0x0c},
+ {1400, 0x1c}, {1450, 0x2c}, {1500, 0x3c}
+ };
+
+ /* Shutdown mode */
+ rk_mipi_dsi_write(regs, PHY_SHUTDOWNZ, 0);
+ rk_mipi_dsi_write(regs, PHY_RSTZ, 0);
+ rk_mipi_dsi_write(regs, PHY_TESTCLR, 1);
+
+ /* Pll locking */
+ rk_mipi_dsi_write(regs, PHY_TESTCLR, 0);
+
+ /* config cp and lfp */
+ test_data[0] = 0x80 | (ddr_clk / (200 * MHz)) << 3 | 0x3;
+ rk_mipi_phy_write(regs, CODE_PLL_VCORANGE_VCOCAP, test_data, 1);
+
+ test_data[0] = 0x8;
+ rk_mipi_phy_write(regs, CODE_PLL_CPCTRL, test_data, 1);
+
+ test_data[0] = 0x80 | 0x40;
+ rk_mipi_phy_write(regs, CODE_PLL_LPF_CP, test_data, 1);
+
+ /* select the suitable value for fsfreqrang reg */
+ for (i = 0; i < ARRAY_SIZE(freq_rang); i++) {
+ if (ddr_clk / (MHz) >= freq_rang[i][0])
+ break;
+ }
+ if (i == ARRAY_SIZE(freq_rang)) {
+ debug("%s: Dphy freq out of range!\n", __func__);
+ return -EINVAL;
+ }
+ test_data[0] = freq_rang[i][1] << 1;
+ rk_mipi_phy_write(regs, CODE_HS_RX_LANE0, test_data, 1);
+
+ /*
+ * Calculate the best ddrclk and it's corresponding div value. If the
+ * given pixelclock is great than 250M, ddrclk will be fix 1500M.
+ * Otherwise,
+ * it's equal to ddr_clk= pixclk * 6. 40MHz >= refclk / prediv >= 5MHz
+ * according to spec.
+ */
+ max_prediv = (refclk / (5 * MHz));
+ min_prediv = ((refclk / (40 * MHz)) ? (refclk / (40 * MHz) + 1) : 1);
+
+ debug("%s: DEBUG: max_prediv=%u, min_prediv=%u\n", __func__, max_prediv,
+ min_prediv);
+
+ if (max_prediv < min_prediv) {
+ debug("%s: Invalid refclk value\n", __func__);
+ return -EINVAL;
+ }
+
+ /* Calculate the best refclk and feedback division value for dphy pll */
+ for (i = min_prediv; i < max_prediv; i++) {
+ if ((ddr_clk * i % refclk < remain) &&
+ (ddr_clk * i / refclk) < max_fbdiv) {
+ prediv = i;
+ remain = ddr_clk * i % refclk;
+ }
+ }
+ fbdiv = ddr_clk * prediv / refclk;
+ ddr_clk = refclk * fbdiv / prediv;
+ priv->phy_clk = ddr_clk;
+
+ debug("%s: DEBUG: refclk=%u, refclk=%llu, fbdiv=%llu, phyclk=%llu\n",
+ __func__, refclk, prediv, fbdiv, ddr_clk);
+
+ /* config prediv and feedback reg */
+ test_data[0] = prediv - 1;
+ rk_mipi_phy_write(regs, CODE_PLL_INPUT_DIV_RAT, test_data, 1);
+ test_data[0] = (fbdiv - 1) & 0x1f;
+ rk_mipi_phy_write(regs, CODE_PLL_LOOP_DIV_RAT, test_data, 1);
+ test_data[0] = (fbdiv - 1) >> 5 | 0x80;
+ rk_mipi_phy_write(regs, CODE_PLL_LOOP_DIV_RAT, test_data, 1);
+ test_data[0] = 0x30;
+ rk_mipi_phy_write(regs, CODE_PLL_INPUT_LOOP_DIV_RAT, test_data, 1);
+
+ /* rest config */
+ test_data[0] = 0x4d;
+ rk_mipi_phy_write(regs, CODE_BANDGAP_BIAS_CTRL, test_data, 1);
+
+ test_data[0] = 0x3d;
+ rk_mipi_phy_write(regs, CODE_TERMINATION_CTRL, test_data, 1);
+
+ test_data[0] = 0xdf;
+ rk_mipi_phy_write(regs, CODE_TERMINATION_CTRL, test_data, 1);
+
+ test_data[0] = 0x7;
+ rk_mipi_phy_write(regs, CODE_AFE_BIAS_BANDGAP_ANOLOG, test_data, 1);
+
+ test_data[0] = 0x80 | 0x7;
+ rk_mipi_phy_write(regs, CODE_AFE_BIAS_BANDGAP_ANOLOG, test_data, 1);
+
+ test_data[0] = 0x80 | 15;
+ rk_mipi_phy_write(regs, CODE_HSTXDATALANEREQUSETSTATETIME,
+ test_data, 1);
+ test_data[0] = 0x80 | 85;
+ rk_mipi_phy_write(regs, CODE_HSTXDATALANEPREPARESTATETIME,
+ test_data, 1);
+ test_data[0] = 0x40 | 10;
+ rk_mipi_phy_write(regs, CODE_HSTXDATALANEHSZEROSTATETIME,
+ test_data, 1);
+
+ /* enter into stop mode */
+ rk_mipi_dsi_write(regs, N_LANES, 0x03);
+ rk_mipi_dsi_write(regs, PHY_ENABLECLK, 1);
+ rk_mipi_dsi_write(regs, PHY_FORCEPLL, 1);
+ rk_mipi_dsi_write(regs, PHY_SHUTDOWNZ, 1);
+ rk_mipi_dsi_write(regs, PHY_RSTZ, 1);
+
+ return 0;
+}
+
+/*
+ * This function is called by rk_display_init() using rk_mipi_dsi_enable() and
+ * rk_mipi_phy_enable() to initialize mipi controller and dphy. If success,
+ * enable backlight.
+ */
+static int rk_display_enable(struct udevice *dev, int panel_bpp,
+ const struct display_timing *timing)
+{
+ int ret;
+ struct rk_mipi_priv *priv = dev_get_priv(dev);
+
+ /* Fill the mipi controller parameter */
+ priv->ref_clk = 24 * MHz;
+ priv->sys_clk = priv->ref_clk;
+ priv->pix_clk = timing->pixelclock.typ;
+ priv->phy_clk = priv->pix_clk * 6;
+ priv->txbyte_clk = priv->phy_clk / 8;
+ priv->txesc_clk = 20 * MHz;
+
+ /* Config and enable mipi dsi according to timing */
+ ret = rk_mipi_dsi_enable(dev, timing);
+ if (ret) {
+ debug("%s: rk_mipi_dsi_enable() failed (err=%d)\n",
+ __func__, ret);
+ return ret;
+ }
+
+ /* Config and enable mipi phy */
+ ret = rk_mipi_phy_enable(dev);
+ if (ret) {
+ debug("%s: rk_mipi_phy_enable() failed (err=%d)\n",
+ __func__, ret);
+ return ret;
+ }
+
+ /* Enable backlight */
+ ret = panel_enable_backlight(priv->panel);
+ if (ret) {
+ debug("%s: panel_enable_backlight() failed (err=%d)\n",
+ __func__, ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int rk_mipi_ofdata_to_platdata(struct udevice *dev)
+{
+ struct rk_mipi_priv *priv = dev_get_priv(dev);
+
+ priv->grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF);
+ if (priv->grf <= 0) {
+ debug("%s: Get syscon grf failed (ret=%llu)\n",
+ __func__, (u64)priv->grf);
+ return -ENXIO;
+ }
+ priv->regs = (void *)dev_get_addr(dev);
+ if (priv->regs <= 0) {
+ debug("%s: Get MIPI dsi address failed (ret=%llu)\n", __func__,
+ (u64)priv->regs);
+ return -ENXIO;
+ }
+
+ return 0;
+}
+
+/*
+ * Probe function: check panel existence and readingit's timing. Then config
+ * mipi dsi controller and enable it according to the timing parameter.
+ */
+static int rk_mipi_probe(struct udevice *dev)
+{
+ int ret;
+ struct rk_mipi_priv *priv = dev_get_priv(dev);
+
+ ret = uclass_get_device_by_phandle(UCLASS_PANEL, dev, "rockchip,panel",
+ &priv->panel);
+ if (ret) {
+ debug("%s: Can not find panel (err=%d)\n", __func__, ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static const struct dm_display_ops rk_mipi_dsi_ops = {
+ .read_timing = rk_mipi_read_timing,
+ .enable = rk_display_enable,
+};
+
+static const struct udevice_id rk_mipi_dsi_ids[] = {
+ { .compatible = "rockchip,rk3399_mipi_dsi" },
+ { }
+};
+
+U_BOOT_DRIVER(rk_mipi_dsi) = {
+ .name = "rk_mipi_dsi",
+ .id = UCLASS_DISPLAY,
+ .of_match = rk_mipi_dsi_ids,
+ .ofdata_to_platdata = rk_mipi_ofdata_to_platdata,
+ .probe = rk_mipi_probe,
+ .ops = &rk_mipi_dsi_ops,
+ .priv_auto_alloc_size = sizeof(struct rk_mipi_priv),
+};
diff --git a/drivers/video/rockchip/rk_vop.c b/drivers/video/rockchip/rk_vop.c
index bc02f800dc4..aa6ca8c8595 100644
--- a/drivers/video/rockchip/rk_vop.c
+++ b/drivers/video/rockchip/rk_vop.c
@@ -117,6 +117,10 @@ void rkvop_mode_set(struct rk3288_vop *regs,
clrsetbits_le32(&regs->sys_ctrl, M_ALL_OUT_EN,
V_RGB_OUT_EN(1));
break;
+ case VOP_MODE_MIPI:
+ clrsetbits_le32(&regs->sys_ctrl, M_ALL_OUT_EN,
+ V_MIPI_OUT_EN(1));
+ break;
}
if (mode == VOP_MODE_HDMI || mode == VOP_MODE_EDP)
@@ -177,13 +181,11 @@ void rkvop_mode_set(struct rk3288_vop *regs,
*
* @dev: VOP device that we want to connect to the display
* @fbbase: Frame buffer address
- * @l2bpp Log2 of bits-per-pixels for the display
* @ep_node: Device tree node to process - this is the offset of an endpoint
* node within the VOP's 'port' list.
* @return 0 if OK, -ve if something went wrong
*/
-int rk_display_init(struct udevice *dev, ulong fbbase,
- enum video_log2_bpp l2bpp, int ep_node)
+int rk_display_init(struct udevice *dev, ulong fbbase, int ep_node)
{
struct video_priv *uc_priv = dev_get_uclass_priv(dev);
const void *blob = gd->fdt_blob;
@@ -195,6 +197,7 @@ int rk_display_init(struct udevice *dev, ulong fbbase,
int ret, remote, i, offset;
struct display_plat *disp_uc_plat;
struct clk clk;
+ enum video_log2_bpp l2bpp;
vop_id = fdtdec_get_int(blob, ep_node, "reg", -1);
debug("vop_id=%d\n", vop_id);
@@ -244,11 +247,24 @@ int rk_display_init(struct udevice *dev, ulong fbbase,
ret = clk_get_by_index(dev, 1, &clk);
if (!ret)
ret = clk_set_rate(&clk, timing.pixelclock.typ);
- if (ret) {
+ if (IS_ERR_VALUE(ret)) {
debug("%s: Failed to set pixel clock: ret=%d\n", __func__, ret);
return ret;
}
+ /* Set bitwidth for vop display according to vop mode */
+ switch (vop_id) {
+ case VOP_MODE_EDP:
+ case VOP_MODE_HDMI:
+ case VOP_MODE_LVDS:
+ l2bpp = VIDEO_BPP16;
+ break;
+ case VOP_MODE_MIPI:
+ l2bpp = VIDEO_BPP32;
+ break;
+ default:
+ l2bpp = VIDEO_BPP16;
+ }
rkvop_mode_set(regs, &timing, vop_id);
rkvop_enable(regs, fbbase, 1 << l2bpp, &timing);
@@ -326,7 +342,7 @@ static int rk_vop_probe(struct udevice *dev)
for (node = fdt_first_subnode(blob, port);
node > 0;
node = fdt_next_subnode(blob, node)) {
- ret = rk_display_init(dev, plat->base, VIDEO_BPP16, node);
+ ret = rk_display_init(dev, plat->base, node);
if (ret)
debug("Device failed: ret=%d\n", ret);
if (!ret)
@@ -341,7 +357,7 @@ static int rk_vop_bind(struct udevice *dev)
{
struct video_uc_platdata *plat = dev_get_uclass_platdata(dev);
- plat->size = 1920 * 1080 * 2;
+ plat->size = 1920 * 1200 * 4;
return 0;
}
@@ -350,6 +366,8 @@ static const struct video_ops rk_vop_ops = {
};
static const struct udevice_id rk_vop_ids[] = {
+ { .compatible = "rockchip,rk3399-vop-big" },
+ { .compatible = "rockchip,rk3399-vop-lit" },
{ .compatible = "rockchip,rk3288-vop" },
{ }
};
diff --git a/drivers/video/sunxi/Makefile b/drivers/video/sunxi/Makefile
index b8afd892ad7..dbaab61b59c 100644
--- a/drivers/video/sunxi/Makefile
+++ b/drivers/video/sunxi/Makefile
@@ -5,5 +5,5 @@
# SPDX-License-Identifier: GPL-2.0+
#
-obj-$(CONFIG_VIDEO_SUNXI) += sunxi_display.o lcdc.o ../videomodes.o
+obj-$(CONFIG_VIDEO_SUNXI) += sunxi_display.o lcdc.o tve.o ../videomodes.o
obj-$(CONFIG_VIDEO_DE2) += sunxi_de2.o sunxi_dw_hdmi.o lcdc.o ../dw_hdmi.o
diff --git a/drivers/video/sunxi/sunxi_display.c b/drivers/video/sunxi/sunxi_display.c
index 92c9d06054f..de768ba94a3 100644
--- a/drivers/video/sunxi/sunxi_display.c
+++ b/drivers/video/sunxi/sunxi_display.c
@@ -14,6 +14,7 @@
#include <asm/arch/gpio.h>
#include <asm/arch/lcdc.h>
#include <asm/arch/pwm.h>
+#include <asm/arch/tve.h>
#include <asm/global_data.h>
#include <asm/gpio.h>
#include <asm/io.h>
@@ -929,63 +930,19 @@ static void sunxi_tvencoder_mode_set(void)
switch (sunxi_display.monitor) {
case sunxi_monitor_vga:
- writel(SUNXI_TVE_GCTRL_DAC_INPUT(0, 1) |
- SUNXI_TVE_GCTRL_DAC_INPUT(1, 2) |
- SUNXI_TVE_GCTRL_DAC_INPUT(2, 3), &tve->gctrl);
- writel(SUNXI_TVE_CFG0_VGA, &tve->cfg0);
- writel(SUNXI_TVE_DAC_CFG0_VGA, &tve->dac_cfg0);
- writel(SUNXI_TVE_UNKNOWN1_VGA, &tve->unknown1);
+ tvencoder_mode_set(tve, tve_mode_vga);
break;
case sunxi_monitor_composite_pal_nc:
- writel(SUNXI_TVE_CHROMA_FREQ_PAL_NC, &tve->chroma_freq);
- /* Fall through */
+ tvencoder_mode_set(tve, tve_mode_composite_pal_nc);
+ break;
case sunxi_monitor_composite_pal:
- writel(SUNXI_TVE_GCTRL_DAC_INPUT(0, 1) |
- SUNXI_TVE_GCTRL_DAC_INPUT(1, 2) |
- SUNXI_TVE_GCTRL_DAC_INPUT(2, 3) |
- SUNXI_TVE_GCTRL_DAC_INPUT(3, 4), &tve->gctrl);
- writel(SUNXI_TVE_CFG0_PAL, &tve->cfg0);
- writel(SUNXI_TVE_DAC_CFG0_COMPOSITE, &tve->dac_cfg0);
- writel(SUNXI_TVE_FILTER_COMPOSITE, &tve->filter);
- writel(SUNXI_TVE_PORCH_NUM_PAL, &tve->porch_num);
- writel(SUNXI_TVE_LINE_NUM_PAL, &tve->line_num);
- writel(SUNXI_TVE_BLANK_BLACK_LEVEL_PAL, &tve->blank_black_level);
- writel(SUNXI_TVE_UNKNOWN1_COMPOSITE, &tve->unknown1);
- writel(SUNXI_TVE_CBR_LEVEL_PAL, &tve->cbr_level);
- writel(SUNXI_TVE_BURST_WIDTH_COMPOSITE, &tve->burst_width);
- writel(SUNXI_TVE_UNKNOWN2_PAL, &tve->unknown2);
- writel(SUNXI_TVE_ACTIVE_NUM_COMPOSITE, &tve->active_num);
- writel(SUNXI_TVE_CHROMA_BW_GAIN_COMP, &tve->chroma_bw_gain);
- writel(SUNXI_TVE_NOTCH_WIDTH_COMPOSITE, &tve->notch_width);
- writel(SUNXI_TVE_RESYNC_NUM_PAL, &tve->resync_num);
- writel(SUNXI_TVE_SLAVE_PARA_COMPOSITE, &tve->slave_para);
+ tvencoder_mode_set(tve, tve_mode_composite_pal);
break;
case sunxi_monitor_composite_pal_m:
- writel(SUNXI_TVE_CHROMA_FREQ_PAL_M, &tve->chroma_freq);
- writel(SUNXI_TVE_COLOR_BURST_PAL_M, &tve->color_burst);
- /* Fall through */
+ tvencoder_mode_set(tve, tve_mode_composite_pal_m);
+ break;
case sunxi_monitor_composite_ntsc:
- writel(SUNXI_TVE_GCTRL_DAC_INPUT(0, 1) |
- SUNXI_TVE_GCTRL_DAC_INPUT(1, 2) |
- SUNXI_TVE_GCTRL_DAC_INPUT(2, 3) |
- SUNXI_TVE_GCTRL_DAC_INPUT(3, 4), &tve->gctrl);
- writel(SUNXI_TVE_CFG0_NTSC, &tve->cfg0);
- writel(SUNXI_TVE_DAC_CFG0_COMPOSITE, &tve->dac_cfg0);
- writel(SUNXI_TVE_FILTER_COMPOSITE, &tve->filter);
- writel(SUNXI_TVE_PORCH_NUM_NTSC, &tve->porch_num);
- writel(SUNXI_TVE_LINE_NUM_NTSC, &tve->line_num);
- writel(SUNXI_TVE_BLANK_BLACK_LEVEL_NTSC, &tve->blank_black_level);
- writel(SUNXI_TVE_UNKNOWN1_COMPOSITE, &tve->unknown1);
- writel(SUNXI_TVE_CBR_LEVEL_NTSC, &tve->cbr_level);
- writel(SUNXI_TVE_BURST_PHASE_NTSC, &tve->burst_phase);
- writel(SUNXI_TVE_BURST_WIDTH_COMPOSITE, &tve->burst_width);
- writel(SUNXI_TVE_UNKNOWN2_NTSC, &tve->unknown2);
- writel(SUNXI_TVE_SYNC_VBI_LEVEL_NTSC, &tve->sync_vbi_level);
- writel(SUNXI_TVE_ACTIVE_NUM_COMPOSITE, &tve->active_num);
- writel(SUNXI_TVE_CHROMA_BW_GAIN_COMP, &tve->chroma_bw_gain);
- writel(SUNXI_TVE_NOTCH_WIDTH_COMPOSITE, &tve->notch_width);
- writel(SUNXI_TVE_RESYNC_NUM_NTSC, &tve->resync_num);
- writel(SUNXI_TVE_SLAVE_PARA_COMPOSITE, &tve->slave_para);
+ tvencoder_mode_set(tve, tve_mode_composite_ntsc);
break;
case sunxi_monitor_none:
case sunxi_monitor_dvi:
@@ -995,14 +952,6 @@ static void sunxi_tvencoder_mode_set(void)
}
}
-static void sunxi_tvencoder_enable(void)
-{
- struct sunxi_tve_reg * const tve =
- (struct sunxi_tve_reg *)SUNXI_TVE0_BASE;
-
- setbits_le32(&tve->gctrl, SUNXI_TVE_GCTRL_ENABLE);
-}
-
#endif /* CONFIG_VIDEO_VGA || defined CONFIG_VIDEO_COMPOSITE */
static void sunxi_drc_init(void)
@@ -1080,6 +1029,8 @@ static void sunxi_mode_set(const struct ctfb_res_modes *mode,
int __maybe_unused clk_div, clk_double;
struct sunxi_lcdc_reg * const lcdc =
(struct sunxi_lcdc_reg *)SUNXI_LCD0_BASE;
+ struct sunxi_tve_reg * __maybe_unused const tve =
+ (struct sunxi_tve_reg *)SUNXI_TVE0_BASE;
switch (sunxi_display.monitor) {
case sunxi_monitor_none:
@@ -1134,7 +1085,7 @@ static void sunxi_mode_set(const struct ctfb_res_modes *mode,
sunxi_tvencoder_mode_set();
sunxi_composer_enable();
lcdc_enable(lcdc, sunxi_display.depth);
- sunxi_tvencoder_enable();
+ tvencoder_enable(tve);
#elif defined CONFIG_VIDEO_VGA_VIA_LCD
sunxi_composer_mode_set(mode, address);
sunxi_lcdc_tcon0_mode_set(mode, true);
@@ -1153,7 +1104,7 @@ static void sunxi_mode_set(const struct ctfb_res_modes *mode,
sunxi_tvencoder_mode_set();
sunxi_composer_enable();
lcdc_enable(lcdc, sunxi_display.depth);
- sunxi_tvencoder_enable();
+ tvencoder_enable(tve);
#endif
break;
}
diff --git a/drivers/video/sunxi/tve.c b/drivers/video/sunxi/tve.c
new file mode 100644
index 00000000000..adea78a69aa
--- /dev/null
+++ b/drivers/video/sunxi/tve.c
@@ -0,0 +1,86 @@
+/*
+ * TV encoder driver for Allwinner SoCs.
+ *
+ * (C) Copyright 2013-2014 Luc Verhaegen <libv@skynet.be>
+ * (C) Copyright 2014-2015 Hans de Goede <hdegoede@redhat.com>
+ * (C) Copyright 2017 Jernej Skrabec <jernej.skrabec@siol.net>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+
+#include <asm/arch/tve.h>
+#include <asm/io.h>
+
+void tvencoder_mode_set(struct sunxi_tve_reg * const tve, enum tve_mode mode)
+{
+ switch (mode) {
+ case tve_mode_vga:
+ writel(SUNXI_TVE_GCTRL_DAC_INPUT(0, 1) |
+ SUNXI_TVE_GCTRL_DAC_INPUT(1, 2) |
+ SUNXI_TVE_GCTRL_DAC_INPUT(2, 3), &tve->gctrl);
+ writel(SUNXI_TVE_CFG0_VGA, &tve->cfg0);
+ writel(SUNXI_TVE_DAC_CFG0_VGA, &tve->dac_cfg0);
+ writel(SUNXI_TVE_UNKNOWN1_VGA, &tve->unknown1);
+ break;
+ case tve_mode_composite_pal_nc:
+ writel(SUNXI_TVE_CHROMA_FREQ_PAL_NC, &tve->chroma_freq);
+ /* Fall through */
+ case tve_mode_composite_pal:
+ writel(SUNXI_TVE_GCTRL_DAC_INPUT(0, 1) |
+ SUNXI_TVE_GCTRL_DAC_INPUT(1, 2) |
+ SUNXI_TVE_GCTRL_DAC_INPUT(2, 3) |
+ SUNXI_TVE_GCTRL_DAC_INPUT(3, 4), &tve->gctrl);
+ writel(SUNXI_TVE_CFG0_PAL, &tve->cfg0);
+ writel(SUNXI_TVE_DAC_CFG0_COMPOSITE, &tve->dac_cfg0);
+ writel(SUNXI_TVE_FILTER_COMPOSITE, &tve->filter);
+ writel(SUNXI_TVE_PORCH_NUM_PAL, &tve->porch_num);
+ writel(SUNXI_TVE_LINE_NUM_PAL, &tve->line_num);
+ writel(SUNXI_TVE_BLANK_BLACK_LEVEL_PAL,
+ &tve->blank_black_level);
+ writel(SUNXI_TVE_UNKNOWN1_COMPOSITE, &tve->unknown1);
+ writel(SUNXI_TVE_CBR_LEVEL_PAL, &tve->cbr_level);
+ writel(SUNXI_TVE_BURST_WIDTH_COMPOSITE, &tve->burst_width);
+ writel(SUNXI_TVE_UNKNOWN2_PAL, &tve->unknown2);
+ writel(SUNXI_TVE_ACTIVE_NUM_COMPOSITE, &tve->active_num);
+ writel(SUNXI_TVE_CHROMA_BW_GAIN_COMP, &tve->chroma_bw_gain);
+ writel(SUNXI_TVE_NOTCH_WIDTH_COMPOSITE, &tve->notch_width);
+ writel(SUNXI_TVE_RESYNC_NUM_PAL, &tve->resync_num);
+ writel(SUNXI_TVE_SLAVE_PARA_COMPOSITE, &tve->slave_para);
+ break;
+ case tve_mode_composite_pal_m:
+ writel(SUNXI_TVE_CHROMA_FREQ_PAL_M, &tve->chroma_freq);
+ writel(SUNXI_TVE_COLOR_BURST_PAL_M, &tve->color_burst);
+ /* Fall through */
+ case tve_mode_composite_ntsc:
+ writel(SUNXI_TVE_GCTRL_DAC_INPUT(0, 1) |
+ SUNXI_TVE_GCTRL_DAC_INPUT(1, 2) |
+ SUNXI_TVE_GCTRL_DAC_INPUT(2, 3) |
+ SUNXI_TVE_GCTRL_DAC_INPUT(3, 4), &tve->gctrl);
+ writel(SUNXI_TVE_CFG0_NTSC, &tve->cfg0);
+ writel(SUNXI_TVE_DAC_CFG0_COMPOSITE, &tve->dac_cfg0);
+ writel(SUNXI_TVE_FILTER_COMPOSITE, &tve->filter);
+ writel(SUNXI_TVE_PORCH_NUM_NTSC, &tve->porch_num);
+ writel(SUNXI_TVE_LINE_NUM_NTSC, &tve->line_num);
+ writel(SUNXI_TVE_BLANK_BLACK_LEVEL_NTSC,
+ &tve->blank_black_level);
+ writel(SUNXI_TVE_UNKNOWN1_COMPOSITE, &tve->unknown1);
+ writel(SUNXI_TVE_CBR_LEVEL_NTSC, &tve->cbr_level);
+ writel(SUNXI_TVE_BURST_PHASE_NTSC, &tve->burst_phase);
+ writel(SUNXI_TVE_BURST_WIDTH_COMPOSITE, &tve->burst_width);
+ writel(SUNXI_TVE_UNKNOWN2_NTSC, &tve->unknown2);
+ writel(SUNXI_TVE_SYNC_VBI_LEVEL_NTSC, &tve->sync_vbi_level);
+ writel(SUNXI_TVE_ACTIVE_NUM_COMPOSITE, &tve->active_num);
+ writel(SUNXI_TVE_CHROMA_BW_GAIN_COMP, &tve->chroma_bw_gain);
+ writel(SUNXI_TVE_NOTCH_WIDTH_COMPOSITE, &tve->notch_width);
+ writel(SUNXI_TVE_RESYNC_NUM_NTSC, &tve->resync_num);
+ writel(SUNXI_TVE_SLAVE_PARA_COMPOSITE, &tve->slave_para);
+ break;
+ }
+}
+
+void tvencoder_enable(struct sunxi_tve_reg * const tve)
+{
+ setbits_le32(&tve->gctrl, SUNXI_TVE_GCTRL_ENABLE);
+}
diff --git a/drivers/video/video_bmp.c b/drivers/video/video_bmp.c
index 32a4e7f8a90..f803067da31 100644
--- a/drivers/video/video_bmp.c
+++ b/drivers/video/video_bmp.c
@@ -316,7 +316,7 @@ int video_bmp_display(struct udevice *dev, ulong bmp_image, int x, int y,
}
break;
#endif /* CONFIG_BMP_16BPP */
-#if defined(CONFIG_BMP_24BMP)
+#if defined(CONFIG_BMP_24BPP)
case 24:
for (i = 0; i < height; ++i) {
for (j = 0; j < width; j++) {
@@ -328,7 +328,7 @@ int video_bmp_display(struct udevice *dev, ulong bmp_image, int x, int y,
fb -= priv->line_length + width * (bpix / 8);
}
break;
-#endif /* CONFIG_BMP_24BMP */
+#endif /* CONFIG_BMP_24BPP */
#if defined(CONFIG_BMP_32BPP)
case 32:
for (i = 0; i < height; ++i) {
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index 2034e3c620f..22a7c4f8018 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -1,5 +1,25 @@
menu "Watchdog Timer Support"
+config HW_WATCHDOG
+ bool
+
+config BCM2835_WDT
+ bool "Enable BCM2835/2836 watchdog driver"
+ select HW_WATCHDOG
+ help
+ Say Y here to enable the BCM2835/2836 watchdog
+
+ This provides basic infrastructure to support BCM2835/2836 watchdog
+ hardware, with a max timeout of ~15secs.
+
+config OMAP_WATCHDOG
+ bool "TI OMAP watchdog driver"
+ depends on ARCH_OMAP2PLUS
+ select HW_WATCHDOG
+ default y if AM33XX
+ help
+ Say Y here to enable the OMAP3+ watchdog driver.
+
config ULP_WATCHDOG
bool "i.MX7ULP watchdog"
help
diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
index dfc7fbda4ab..8378601b331 100644
--- a/drivers/watchdog/Makefile
+++ b/drivers/watchdog/Makefile
@@ -18,3 +18,4 @@ obj-$(CONFIG_ULP_WATCHDOG) += ulp_wdog.o
obj-$(CONFIG_WDT) += wdt-uclass.o
obj-$(CONFIG_WDT_SANDBOX) += sandbox_wdt.o
obj-$(CONFIG_WDT_ASPEED) += ast_wdt.o
+obj-$(CONFIG_BCM2835_WDT) += bcm2835_wdt.o
diff --git a/drivers/watchdog/bcm2835_wdt.c b/drivers/watchdog/bcm2835_wdt.c
new file mode 100644
index 00000000000..6f753ae8ae4
--- /dev/null
+++ b/drivers/watchdog/bcm2835_wdt.c
@@ -0,0 +1,35 @@
+/*
+ * Watchdog driver for Broadcom BCM2835
+ *
+ * Copyright (C) 2017 Paolo Pisati <p.pisati@gmail.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#include <common.h>
+#include <efi_loader.h>
+#include <asm/io.h>
+#include <asm/arch/wdog.h>
+
+#define SECS_TO_WDOG_TICKS(x) ((x) << 16)
+#define MAX_TIMEOUT 0xf /* ~15s */
+
+static __efi_runtime_data bool enabled = true;
+
+extern void reset_cpu(ulong ticks);
+
+void hw_watchdog_reset(void)
+{
+ if (enabled)
+ reset_cpu(SECS_TO_WDOG_TICKS(MAX_TIMEOUT));
+}
+
+void hw_watchdog_init(void)
+{
+ hw_watchdog_reset();
+}
+
+void __efi_runtime hw_watchdog_disable(void)
+{
+ enabled = false;
+}