diff options
Diffstat (limited to 'drivers')
31 files changed, 503 insertions, 147 deletions
diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig index 7ebee75c0a..4e95a68a2d 100644 --- a/drivers/ata/Kconfig +++ b/drivers/ata/Kconfig @@ -66,6 +66,14 @@ config DWC_AHSATA Enable this driver to support the DWC AHSATA SATA controller found in i.MX5 and i.MX6 SoCs. +config DWC_AHSATA_AHCI + bool "Enable DWC AHSATA AHCI driver support" + depends on DWC_AHSATA + depends on AHCI + default y + help + Enable this option unless you need your private ahci implementation + config FSL_SATA bool "Enable Freescale SATA controller driver support" select LIBATA @@ -101,6 +109,14 @@ config SATA_SIL3114 help Enable this driver to support the SIL3114 SATA controllers. +config SUNXI_AHCI + bool "Enable Allwinner SATA driver support" + depends on AHCI + default y if ARCH_SUNXI + help + Enable this driver to support the SATA controllers found in the + Allwinner A10, A20 and R40 SoCs. + config AHCI_MVEBU bool "Marvell EBU AHCI SATA support" depends on ARCH_MVEBU diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile index 10bed53bb3..a69edb10f7 100644 --- a/drivers/ata/Makefile +++ b/drivers/ata/Makefile @@ -18,3 +18,4 @@ obj-$(CONFIG_SATA_SIL3114) += sata_sil3114.o obj-$(CONFIG_SATA_SIL) += sata_sil.o obj-$(CONFIG_SANDBOX) += sata_sandbox.o obj-$(CONFIG_AHCI_MVEBU) += ahci_mvebu.o +obj-$(CONFIG_SUNXI_AHCI) += ahci_sunxi.o diff --git a/drivers/ata/ahci_sunxi.c b/drivers/ata/ahci_sunxi.c new file mode 100644 index 0000000000..77b932aa03 --- /dev/null +++ b/drivers/ata/ahci_sunxi.c @@ -0,0 +1,125 @@ +#include <common.h> +#include <ahci.h> +#include <dm.h> +#include <scsi.h> +#include <errno.h> +#include <asm/io.h> +#include <asm/gpio.h> + +#define AHCI_PHYCS0R 0x00c0 +#define AHCI_PHYCS1R 0x00c4 +#define AHCI_PHYCS2R 0x00c8 +#define AHCI_RWCR 0x00fc + +/* This magic PHY initialisation was taken from the Allwinner releases + * and Linux driver, but is completely undocumented. + */ +static int sunxi_ahci_phy_init(u8 *reg_base) +{ + u32 reg_val; + int timeout; + + writel(0, reg_base + AHCI_RWCR); + mdelay(5); + + setbits_le32(reg_base + AHCI_PHYCS1R, 0x1 << 19); + clrsetbits_le32(reg_base + AHCI_PHYCS0R, + (0x7 << 24), + (0x5 << 24) | (0x1 << 23) | (0x1 << 18)); + clrsetbits_le32(reg_base + AHCI_PHYCS1R, + (0x3 << 16) | (0x1f << 8) | (0x3 << 6), + (0x2 << 16) | (0x6 << 8) | (0x2 << 6)); + setbits_le32(reg_base + AHCI_PHYCS1R, (0x1 << 28) | (0x1 << 15)); + clrbits_le32(reg_base + AHCI_PHYCS1R, (0x1 << 19)); + clrsetbits_le32(reg_base + AHCI_PHYCS0R, (0x7 << 20), (0x3 << 20)); + clrsetbits_le32(reg_base + AHCI_PHYCS2R, (0x1f << 5), (0x19 << 5)); + mdelay(5); + + setbits_le32(reg_base + AHCI_PHYCS0R, (0x1 << 19)); + + timeout = 250; /* Power up takes approx 50 us */ + for (;;) { + reg_val = readl(reg_base + AHCI_PHYCS0R) & (0x7 << 28); + if (reg_val == (0x2 << 28)) + break; + if (--timeout == 0) { + printf("AHCI PHY power up failed.\n"); + return -EIO; + } + udelay(1); + }; + + setbits_le32(reg_base + AHCI_PHYCS2R, (0x1 << 24)); + + timeout = 100; /* Calibration takes approx 10 us */ + for (;;) { + reg_val = readl(reg_base + AHCI_PHYCS2R) & (0x1 << 24); + if (reg_val == 0x0) + break; + if (--timeout == 0) { + printf("AHCI PHY calibration failed.\n"); + return -EIO; + } + udelay(1); + } + + mdelay(15); + + writel(0x7, reg_base + AHCI_RWCR); + + return 0; +} + +static int sunxi_sata_probe(struct udevice *dev) +{ + ulong base; + u8 *reg; + int ret; + + base = dev_read_addr(dev); + if (base == FDT_ADDR_T_NONE) { + debug("%s: Failed to find address (err=%d\n)", __func__, ret); + return -EINVAL; + } + reg = (u8 *)base; + ret = sunxi_ahci_phy_init(reg); + if (ret) { + debug("%s: Failed to init phy (err=%d\n)", __func__, ret); + return ret; + } + ret = ahci_probe_scsi(dev, base); + if (ret) { + debug("%s: Failed to probe (err=%d\n)", __func__, ret); + return ret; + } + + return 0; +} + +static int sunxi_sata_bind(struct udevice *dev) +{ + struct udevice *scsi_dev; + int ret; + + ret = ahci_bind_scsi(dev, &scsi_dev); + if (ret) { + debug("%s: Failed to bind (err=%d\n)", __func__, ret); + return ret; + } + + return 0; +} + +static const struct udevice_id sunxi_ahci_ids[] = { + { .compatible = "allwinner,sun4i-a10-ahci" }, + { .compatible = "allwinner,sun8i-r40-ahci" }, + { } +}; + +U_BOOT_DRIVER(ahci_sunxi_drv) = { + .name = "ahci_sunxi", + .id = UCLASS_AHCI, + .of_match = sunxi_ahci_ids, + .bind = sunxi_sata_bind, + .probe = sunxi_sata_probe, +}; diff --git a/drivers/ata/dwc_ahsata.c b/drivers/ata/dwc_ahsata.c index 4c5b98482f..afced8e7e3 100644 --- a/drivers/ata/dwc_ahsata.c +++ b/drivers/ata/dwc_ahsata.c @@ -16,6 +16,7 @@ #include <asm/io.h> #include <asm/arch/clock.h> #include <asm/arch/sys_proto.h> +#include <asm/mach-imx/sata.h> #include <linux/bitops.h> #include <linux/ctype.h> #include <linux/errno.h> @@ -511,15 +512,9 @@ static int ahci_port_start(struct ahci_uc_priv *uc_priv, u8 port) static void dwc_ahsata_print_info(struct blk_desc *pdev) { printf("SATA Device Info:\n\r"); -#ifdef CONFIG_SYS_64BIT_LBA printf("S/N: %s\n\rProduct model number: %s\n\r" - "Firmware version: %s\n\rCapacity: %lld sectors\n\r", + "Firmware version: %s\n\rCapacity: " LBAFU " sectors\n\r", pdev->product, pdev->vendor, pdev->revision, pdev->lba); -#else - printf("S/N: %s\n\rProduct model number: %s\n\r" - "Firmware version: %s\n\rCapacity: %ld sectors\n\r", - pdev->product, pdev->vendor, pdev->revision, pdev->lba); -#endif } static void dwc_ahsata_identify(struct ahci_uc_priv *uc_priv, u16 *id) @@ -754,7 +749,6 @@ static int dwc_ahsata_scan_common(struct ahci_uc_priv *uc_priv, u8 serial[ATA_ID_SERNO_LEN + 1] = { 0 }; u8 firmware[ATA_ID_FW_REV_LEN + 1] = { 0 }; u8 product[ATA_ID_PROD_LEN + 1] = { 0 }; - u64 n_sectors; u8 port = uc_priv->hard_port_no; ALLOC_CACHE_ALIGN_BUFFER(u16, id, ATA_ID_WORDS); @@ -773,9 +767,8 @@ static int dwc_ahsata_scan_common(struct ahci_uc_priv *uc_priv, ata_id_c_string(id, product, ATA_ID_PROD, sizeof(product)); memcpy(pdev->vendor, product, sizeof(product)); - /* Totoal sectors */ - n_sectors = ata_id_n_sectors(id); - pdev->lba = (u32)n_sectors; + /* Total sectors */ + pdev->lba = ata_id_n_sectors(id); pdev->type = DEV_TYPE_HARDDISK; pdev->blksz = ATA_SECT_SIZE; @@ -1028,6 +1021,9 @@ int dwc_ahsata_probe(struct udevice *dev) struct ahci_uc_priv *uc_priv = dev_get_uclass_priv(dev); int ret; +#if defined(CONFIG_MX6) + setup_sata(); +#endif uc_priv->host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA | ATA_FLAG_NO_ATAPI; uc_priv->mmio_base = (void __iomem *)dev_read_addr(dev); @@ -1075,4 +1071,24 @@ U_BOOT_DRIVER(dwc_ahsata_blk) = { .ops = &dwc_ahsata_blk_ops, }; +#if CONFIG_IS_ENABLED(DWC_AHSATA_AHCI) +struct ahci_ops dwc_ahsata_ahci_ops = { + .port_status = dwc_ahsata_port_status, + .reset = dwc_ahsata_bus_reset, + .scan = dwc_ahsata_scan, +}; + +static const struct udevice_id dwc_ahsata_ahci_ids[] = { + { .compatible = "fsl,imx6q-ahci" }, + { } +}; + +U_BOOT_DRIVER(dwc_ahsata_ahci) = { + .name = "dwc_ahsata_ahci", + .id = UCLASS_AHCI, + .of_match = dwc_ahsata_ahci_ids, + .ops = &dwc_ahsata_ahci_ops, + .probe = dwc_ahsata_probe, +}; +#endif #endif diff --git a/drivers/clk/clk_zynq.c b/drivers/clk/clk_zynq.c index 482f0937cb..b09c37db40 100644 --- a/drivers/clk/clk_zynq.c +++ b/drivers/clk/clk_zynq.c @@ -434,6 +434,8 @@ static ulong zynq_clk_get_rate(struct clk *clk) case lqspi_clk ... pcap_clk: case sdio0_clk ... spi1_clk: return zynq_clk_get_peripheral_rate(priv, id, 0); + case i2c0_aper_clk ... i2c1_aper_clk: + return zynq_clk_get_cpu_rate(priv, cpu_1x_clk); default: return -ENXIO; } diff --git a/drivers/clk/sunxi/clk_r40.c b/drivers/clk/sunxi/clk_r40.c index 30beac98bb..44abc4f536 100644 --- a/drivers/clk/sunxi/clk_r40.c +++ b/drivers/clk/sunxi/clk_r40.c @@ -62,7 +62,6 @@ static struct ccu_reset r40_resets[] = { [RST_BUS_MMC1] = RESET(0x2c0, BIT(9)), [RST_BUS_MMC2] = RESET(0x2c0, BIT(10)), [RST_BUS_MMC3] = RESET(0x2c0, BIT(11)), - [RST_BUS_GMAC] = RESET(0x2c0, BIT(17)), [RST_BUS_SPI0] = RESET(0x2c0, BIT(20)), [RST_BUS_SPI1] = RESET(0x2c0, BIT(21)), [RST_BUS_SPI2] = RESET(0x2c0, BIT(22)), @@ -75,6 +74,8 @@ static struct ccu_reset r40_resets[] = { [RST_BUS_OHCI1] = RESET(0x2c0, BIT(30)), [RST_BUS_OHCI2] = RESET(0x2c0, BIT(31)), + [RST_BUS_GMAC] = RESET(0x2c4, BIT(17)), + [RST_BUS_UART0] = RESET(0x2d8, BIT(16)), [RST_BUS_UART1] = RESET(0x2d8, BIT(17)), [RST_BUS_UART2] = RESET(0x2d8, BIT(18)), diff --git a/drivers/fpga/zynqpl.c b/drivers/fpga/zynqpl.c index 499310d0c0..069c63ba45 100644 --- a/drivers/fpga/zynqpl.c +++ b/drivers/fpga/zynqpl.c @@ -408,6 +408,8 @@ static int zynq_load(xilinx_desc *desc, const void *buf, size_t bsize, if (bstype != BIT_PARTIAL) zynq_slcr_devcfg_enable(); + puts("INFO:post config was not run, please run manually if needed\n"); + return FPGA_SUCCESS; } @@ -421,7 +423,8 @@ static int zynq_loadfs(xilinx_desc *desc, const void *buf, size_t bsize, loff_t blocksize, actread; loff_t pos = 0; int fstype; - char *interface, *dev_part, *filename; + char *interface, *dev_part; + const char *filename; blocksize = fsinfo->blocksize; interface = fsinfo->interface; diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index d6e677fba8..0e645f58be 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -128,6 +128,8 @@ config JZ4780_EFUSE config MXC_OCOTP bool "Enable MXC OCOTP Driver" + depends on ARCH_IMX8M || ARCH_MX6 || ARCH_MX7 || ARCH_VF610 + default y help If you say Y here, you will get support for the One Time Programmable memory pages that are stored on the some diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 77d0b3a01f..d0e5426a99 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -190,7 +190,7 @@ config FEC_MXC_MDIO_BASE config FEC_MXC bool "FEC Ethernet controller" - depends on MX5 || MX6 || MX7 || IMX8 + depends on MX5 || MX6 || MX7 || IMX8 || VF610 help This driver supports the 10/100 Fast Ethernet controller for NXP i.MX processors. diff --git a/drivers/net/fec_mxc.c b/drivers/net/fec_mxc.c index 84f010d805..a672250e16 100644 --- a/drivers/net/fec_mxc.c +++ b/drivers/net/fec_mxc.c @@ -1491,6 +1491,7 @@ static const struct udevice_id fecmxc_ids[] = { { .compatible = "fsl,imx6ul-fec" }, { .compatible = "fsl,imx53-fec" }, { .compatible = "fsl,imx7d-fec" }, + { .compatible = "fsl,mvf600-fec" }, { } }; diff --git a/drivers/net/sun8i_emac.c b/drivers/net/sun8i_emac.c index c9798445c7..98bd7a5823 100644 --- a/drivers/net/sun8i_emac.c +++ b/drivers/net/sun8i_emac.c @@ -14,12 +14,14 @@ #include <asm/arch/clock.h> #include <asm/arch/gpio.h> #include <common.h> +#include <clk.h> #include <dm.h> #include <fdt_support.h> #include <linux/err.h> #include <malloc.h> #include <miiphy.h> #include <net.h> +#include <reset.h> #include <dt-bindings/pinctrl/sun4i-a10.h> #ifdef CONFIG_DM_GPIO #include <asm-generic/gpio.h> @@ -135,6 +137,8 @@ struct emac_eth_dev { phys_addr_t sysctl_reg; struct phy_device *phydev; struct mii_dev *bus; + struct clk tx_clk; + struct reset_ctl tx_rst; #ifdef CONFIG_DM_GPIO struct gpio_desc reset_gpio; #endif @@ -285,10 +289,18 @@ static int sun8i_emac_set_syscon(struct sun8i_eth_pdata *pdata, int ret; u32 reg; - reg = readl(priv->sysctl_reg + 0x30); + if (priv->variant == R40_GMAC) { + /* Select RGMII for R40 */ + reg = readl(priv->sysctl_reg + 0x164); + reg |= CCM_GMAC_CTRL_TX_CLK_SRC_INT_RGMII | + CCM_GMAC_CTRL_GPIT_RGMII | + CCM_GMAC_CTRL_TX_CLK_DELAY(CONFIG_GMAC_TX_DELAY); - if (priv->variant == R40_GMAC) + writel(reg, priv->sysctl_reg + 0x164); return 0; + } + + reg = readl(priv->sysctl_reg + 0x30); if (priv->variant == H3_EMAC) { ret = sun8i_emac_set_syscon_ephy(priv, ®); @@ -639,9 +651,24 @@ static int sun8i_eth_write_hwaddr(struct udevice *dev) return _sun8i_write_hwaddr(priv, pdata->enetaddr); } -static void sun8i_emac_board_setup(struct emac_eth_dev *priv) +static int sun8i_emac_board_setup(struct emac_eth_dev *priv) { struct sunxi_ccm_reg *ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE; + int ret; + + ret = clk_enable(&priv->tx_clk); + if (ret) { + dev_err(dev, "failed to enable TX clock\n"); + return ret; + } + + if (reset_valid(&priv->tx_rst)) { + ret = reset_deassert(&priv->tx_rst); + if (ret) { + dev_err(dev, "failed to deassert TX reset\n"); + goto err_tx_clk; + } + } if (priv->variant == H3_EMAC) { /* Only H3/H5 have clock controls for internal EPHY */ @@ -656,26 +683,11 @@ static void sun8i_emac_board_setup(struct emac_eth_dev *priv) } } - if (priv->variant == R40_GMAC) { - /* Set clock gating for emac */ - setbits_le32(&ccm->ahb_reset1_cfg, BIT(AHB_RESET_OFFSET_GMAC)); - - /* De-assert EMAC */ - setbits_le32(&ccm->ahb_gate1, BIT(AHB_GATE_OFFSET_GMAC)); + return 0; - /* Select RGMII for R40 */ - setbits_le32(&ccm->gmac_clk_cfg, - CCM_GMAC_CTRL_TX_CLK_SRC_INT_RGMII | - CCM_GMAC_CTRL_GPIT_RGMII); - setbits_le32(&ccm->gmac_clk_cfg, - CCM_GMAC_CTRL_TX_CLK_DELAY(CONFIG_GMAC_TX_DELAY)); - } else { - /* Set clock gating for emac */ - setbits_le32(&ccm->ahb_gate0, BIT(AHB_GATE_OFFSET_GMAC)); - - /* De-assert EMAC */ - setbits_le32(&ccm->ahb_reset0_cfg, BIT(AHB_RESET_OFFSET_GMAC)); - } +err_tx_clk: + clk_disable(&priv->tx_clk); + return ret; } #if defined(CONFIG_DM_GPIO) @@ -802,10 +814,14 @@ static int sun8i_emac_eth_probe(struct udevice *dev) struct sun8i_eth_pdata *sun8i_pdata = dev_get_platdata(dev); struct eth_pdata *pdata = &sun8i_pdata->eth_pdata; struct emac_eth_dev *priv = dev_get_priv(dev); + int ret; priv->mac_reg = (void *)pdata->iobase; - sun8i_emac_board_setup(priv); + ret = sun8i_emac_board_setup(priv); + if (ret) + return ret; + sun8i_emac_set_syscon(sun8i_pdata, priv); sun8i_mdio_init(dev->name, dev); @@ -834,8 +850,8 @@ static int sun8i_emac_eth_ofdata_to_platdata(struct udevice *dev) int offset = 0; #ifdef CONFIG_DM_GPIO int reset_flags = GPIOD_IS_OUT; - int ret = 0; #endif + int ret; pdata->iobase = devfdt_get_addr(dev); if (pdata->iobase == FDT_ADDR_T_NONE) { @@ -850,25 +866,35 @@ static int sun8i_emac_eth_ofdata_to_platdata(struct udevice *dev) return -EINVAL; } - if (priv->variant != R40_GMAC) { - offset = fdtdec_lookup_phandle(gd->fdt_blob, node, "syscon"); - if (offset < 0) { - debug("%s: cannot find syscon node\n", __func__); - return -EINVAL; - } - reg = fdt_getprop(gd->fdt_blob, offset, "reg", NULL); - if (!reg) { - debug("%s: cannot find reg property in syscon node\n", - __func__); - return -EINVAL; - } - priv->sysctl_reg = fdt_translate_address((void *)gd->fdt_blob, - offset, reg); - if (priv->sysctl_reg == FDT_ADDR_T_NONE) { - debug("%s: Cannot find syscon base address\n", - __func__); - return -EINVAL; - } + ret = clk_get_by_name(dev, "stmmaceth", &priv->tx_clk); + if (ret) { + dev_err(dev, "failed to get TX clock\n"); + return ret; + } + + ret = reset_get_by_name(dev, "stmmaceth", &priv->tx_rst); + if (ret && ret != -ENOENT) { + dev_err(dev, "failed to get TX reset\n"); + return ret; + } + + offset = fdtdec_lookup_phandle(gd->fdt_blob, node, "syscon"); + if (offset < 0) { + debug("%s: cannot find syscon node\n", __func__); + return -EINVAL; + } + + reg = fdt_getprop(gd->fdt_blob, offset, "reg", NULL); + if (!reg) { + debug("%s: cannot find reg property in syscon node\n", + __func__); + return -EINVAL; + } + priv->sysctl_reg = fdt_translate_address((void *)gd->fdt_blob, + offset, reg); + if (priv->sysctl_reg == FDT_ADDR_T_NONE) { + debug("%s: Cannot find syscon base address\n", __func__); + return -EINVAL; } pdata->phy_interface = -1; diff --git a/drivers/net/sunxi_emac.c b/drivers/net/sunxi_emac.c index 8dbd3c50c1..9a5f7fd3c7 100644 --- a/drivers/net/sunxi_emac.c +++ b/drivers/net/sunxi_emac.c @@ -6,6 +6,7 @@ */ #include <common.h> +#include <clk.h> #include <dm.h> #include <linux/err.h> #include <malloc.h> @@ -157,6 +158,7 @@ struct sunxi_sramc_regs { struct emac_eth_dev { struct emac_regs *regs; + struct clk clk; struct mii_dev *bus; struct phy_device *phydev; int link_printed; @@ -500,14 +502,12 @@ static int _sunxi_emac_eth_send(struct emac_eth_dev *priv, void *packet, return 0; } -static void sunxi_emac_board_setup(struct emac_eth_dev *priv) +static int sunxi_emac_board_setup(struct emac_eth_dev *priv) { - struct sunxi_ccm_reg *const ccm = - (struct sunxi_ccm_reg *)SUNXI_CCM_BASE; struct sunxi_sramc_regs *sram = (struct sunxi_sramc_regs *)SUNXI_SRAMC_BASE; struct emac_regs *regs = priv->regs; - int pin; + int pin, ret; /* Map SRAM to EMAC */ setbits_le32(&sram->ctrl1, 0x5 << 2); @@ -517,10 +517,16 @@ static void sunxi_emac_board_setup(struct emac_eth_dev *priv) sunxi_gpio_set_cfgpin(pin, SUNXI_GPA_EMAC); /* Set up clock gating */ - setbits_le32(&ccm->ahb_gate0, 0x1 << AHB_GATE_OFFSET_EMAC); + ret = clk_enable(&priv->clk); + if (ret) { + dev_err(dev, "failed to enable emac clock\n"); + return ret; + } /* Set MII clock */ clrsetbits_le32(®s->mac_mcfg, 0xf << 2, 0xd << 2); + + return 0; } static int sunxi_emac_eth_start(struct udevice *dev) @@ -557,9 +563,19 @@ static int sunxi_emac_eth_probe(struct udevice *dev) { struct eth_pdata *pdata = dev_get_platdata(dev); struct emac_eth_dev *priv = dev_get_priv(dev); + int ret; priv->regs = (struct emac_regs *)pdata->iobase; - sunxi_emac_board_setup(priv); + + ret = clk_get_by_index(dev, 0, &priv->clk); + if (ret) { + dev_err(dev, "failed to get emac clock\n"); + return ret; + } + + ret = sunxi_emac_board_setup(priv); + if (ret) + return ret; return sunxi_emac_init_phy(priv, dev); } diff --git a/drivers/net/zynq_gem.c b/drivers/net/zynq_gem.c index 3bd0093b7a..033efb8195 100644 --- a/drivers/net/zynq_gem.c +++ b/drivers/net/zynq_gem.c @@ -261,45 +261,6 @@ static int phywrite(struct zynq_gem_priv *priv, u32 phy_addr, ZYNQ_GEM_PHYMNTNC_OP_W_MASK, &data); } -static int phy_detection(struct udevice *dev) -{ - int i; - u16 phyreg = 0; - struct zynq_gem_priv *priv = dev->priv; - - if (priv->phyaddr != -1) { - phyread(priv, priv->phyaddr, PHY_DETECT_REG, &phyreg); - if ((phyreg != 0xFFFF) && - ((phyreg & PHY_DETECT_MASK) == PHY_DETECT_MASK)) { - /* Found a valid PHY address */ - debug("Default phy address %d is valid\n", - priv->phyaddr); - return 0; - } else { - debug("PHY address is not setup correctly %d\n", - priv->phyaddr); - priv->phyaddr = -1; - } - } - - debug("detecting phy address\n"); - if (priv->phyaddr == -1) { - /* detect the PHY address */ - for (i = 31; i >= 0; i--) { - phyread(priv, i, PHY_DETECT_REG, &phyreg); - if ((phyreg != 0xFFFF) && - ((phyreg & PHY_DETECT_MASK) == PHY_DETECT_MASK)) { - /* Found a valid PHY address */ - priv->phyaddr = i; - debug("Found valid phy address, %d\n", i); - return 0; - } - } - } - printf("PHY is not detected\n"); - return -1; -} - static int zynq_gem_setup_mac(struct udevice *dev) { u32 i, macaddrlow, macaddrhigh; @@ -345,28 +306,20 @@ static int zynq_phy_init(struct udevice *dev) /* Enable only MDIO bus */ writel(ZYNQ_GEM_NWCTRL_MDEN_MASK, ®s->nwctrl); - if ((priv->interface != PHY_INTERFACE_MODE_SGMII) && - (priv->interface != PHY_INTERFACE_MODE_GMII)) { - ret = phy_detection(dev); - if (ret) { - printf("GEM PHY init failed\n"); - return ret; - } - } - priv->phydev = phy_connect(priv->bus, priv->phyaddr, dev, priv->interface); if (!priv->phydev) return -ENODEV; - priv->phydev->supported &= supported | ADVERTISED_Pause | - ADVERTISED_Asym_Pause; if (priv->max_speed) { ret = phy_set_supported(priv->phydev, priv->max_speed); if (ret) return ret; } + priv->phydev->supported &= supported | ADVERTISED_Pause | + ADVERTISED_Asym_Pause; + priv->phydev->advertising = priv->phydev->supported; priv->phydev->node = priv->phy_of_node; diff --git a/drivers/spi/zynqmp_gqspi.c b/drivers/spi/zynqmp_gqspi.c index da9413c066..04ea42cbcc 100644 --- a/drivers/spi/zynqmp_gqspi.c +++ b/drivers/spi/zynqmp_gqspi.c @@ -267,7 +267,7 @@ void zynqmp_qspi_set_tapdelay(struct udevice *bus, u32 baudrateval) zynqmp_mmio_read(IOU_TAPDLY_BYPASS_OFST, &tapdlybypass); tapdlybypass |= (TAP_DLY_BYPASS_LQSPI_RX_VALUE << TAP_DLY_BYPASS_LQSPI_RX_SHIFT); - } else if (reqhz < GQSPI_FREQ_100MHZ) { + } else if (reqhz <= GQSPI_FREQ_100MHZ) { zynqmp_mmio_read(IOU_TAPDLY_BYPASS_OFST, &tapdlybypass); tapdlybypass |= (TAP_DLY_BYPASS_LQSPI_RX_VALUE << TAP_DLY_BYPASS_LQSPI_RX_SHIFT); @@ -277,7 +277,7 @@ void zynqmp_qspi_set_tapdelay(struct udevice *bus, u32 baudrateval) datadlyadj |= ((GQSPI_USE_DATA_DLY << GQSPI_USE_DATA_DLY_SHIFT) | (GQSPI_DATA_DLY_ADJ_VALUE << GQSPI_DATA_DLY_ADJ_SHIFT)); - } else if (reqhz < GQSPI_FREQ_150MHZ) { + } else if (reqhz <= GQSPI_FREQ_150MHZ) { lpbkdlyadj = readl(®s->lpbkdly); lpbkdlyadj |= ((GQSPI_LPBK_DLY_ADJ_LPBK_MASK) | GQSPI_LPBK_DLY_ADJ_DLY_0); diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index ba1e6bfa43..0fbc115801 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig @@ -154,6 +154,13 @@ config USB_EHCI_OMAP Enables support for the on-chip EHCI controller on OMAP3 and later SoCs. +config USB_EHCI_VF + bool "Support for Vybrid on-chip EHCI USB controller" + depends on ARCH_VF610 + default y + help + Enables support for the on-chip EHCI controller on Vybrid SoCs. + if USB_EHCI_MX7 config MXC_USB_OTG_HACTIVE diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 2eac4b6381..c3781b160d 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -120,7 +120,7 @@ config CONSOLE_TRUETYPE_SIZE config SYS_WHITE_ON_BLACK bool "Display console as white on a black background" - default y if ARCH_AT91 || ARCH_EXYNOS || ARCH_ROCKCHIP || TEGRA || X86 + default y if ARCH_AT91 || ARCH_EXYNOS || ARCH_ROCKCHIP || TEGRA || X86 || ARCH_SUNXI help Normally the display is black on a white background, Enable this option to invert this, i.e. white on a black background. This can be @@ -538,6 +538,8 @@ config VIDEO_TEGRA124 source "drivers/video/bridge/Kconfig" +source "drivers/video/imx/Kconfig" + config VIDEO bool "Enable legacy video support" depends on !DM_VIDEO @@ -547,13 +549,6 @@ config VIDEO model. Video drivers typically provide a colour text console and cursor. -config VIDEO_IPUV3 - bool "i.MX IPUv3 Core video support" - depends on VIDEO && MX6 - help - This enables framebuffer driver for i.MX processors working - on the IPUv3(Image Processing Unit) internal graphic processor. - config CFB_CONSOLE bool "Enable colour frame buffer console" depends on VIDEO diff --git a/drivers/video/Makefile b/drivers/video/Makefile index 671f037c35..349a207035 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile @@ -46,7 +46,7 @@ obj-$(CONFIG_VIDEO_DA8XX) += da8xx-fb.o videomodes.o obj-$(CONFIG_VIDEO_DW_HDMI) += dw_hdmi.o obj-$(CONFIG_VIDEO_EFI) += efi.o obj-$(CONFIG_VIDEO_FSL_DCU_FB) += fsl_dcu_fb.o videomodes.o -obj-$(CONFIG_VIDEO_IPUV3) += mxc_ipuv3_fb.o ipu_common.o ipu_disp.o +obj-$(CONFIG_VIDEO_IPUV3) += imx/ obj-$(CONFIG_VIDEO_IVYBRIDGE_IGD) += ivybridge_igd.o obj-$(CONFIG_VIDEO_LCD_ANX9804) += anx9804.o obj-$(CONFIG_VIDEO_LCD_HITACHI_TX18D42VM) += hitachi_tx18d42vm_lcd.o diff --git a/drivers/video/console_normal.c b/drivers/video/console_normal.c index 2cfa510d5f..7f01ee9424 100644 --- a/drivers/video/console_normal.c +++ b/drivers/video/console_normal.c @@ -84,7 +84,8 @@ static int console_normal_putc_xy(struct udevice *dev, uint x_frac, uint y, return -EAGAIN; for (row = 0; row < VIDEO_FONT_HEIGHT; row++) { - uchar bits = video_fontdata[ch * VIDEO_FONT_HEIGHT + row]; + unsigned int idx = (u8)ch * VIDEO_FONT_HEIGHT + row; + uchar bits = video_fontdata[idx]; switch (vid_priv->bpix) { #ifdef CONFIG_VIDEO_BPP8 diff --git a/drivers/video/console_rotate.c b/drivers/video/console_rotate.c index f076570335..71a5c5efba 100644 --- a/drivers/video/console_rotate.c +++ b/drivers/video/console_rotate.c @@ -90,7 +90,7 @@ static int console_putc_xy_1(struct udevice *dev, uint x_frac, uint y, char ch) int i, col; int mask = 0x80; void *line; - uchar *pfont = video_fontdata + ch * VIDEO_FONT_HEIGHT; + uchar *pfont = video_fontdata + (u8)ch * VIDEO_FONT_HEIGHT; line = vid_priv->fb + (VID_TO_PIXEL(x_frac) + 1) * vid_priv->line_length - (y + 1) * pbytes; @@ -222,7 +222,8 @@ static int console_putc_xy_2(struct udevice *dev, uint x_frac, uint y, char ch) VIDEO_FONT_WIDTH - 1) * VNBYTES(vid_priv->bpix); for (row = 0; row < VIDEO_FONT_HEIGHT; row++) { - uchar bits = video_fontdata[ch * VIDEO_FONT_HEIGHT + row]; + unsigned int idx = (u8)ch * VIDEO_FONT_HEIGHT + row; + uchar bits = video_fontdata[idx]; switch (vid_priv->bpix) { #ifdef CONFIG_VIDEO_BPP8 @@ -348,7 +349,7 @@ static int console_putc_xy_3(struct udevice *dev, uint x_frac, uint y, char ch) void *line = vid_priv->fb + (vid_priv->ysize - VID_TO_PIXEL(x_frac) - 1) * vid_priv->line_length + y * pbytes; - uchar *pfont = video_fontdata + ch * VIDEO_FONT_HEIGHT; + uchar *pfont = video_fontdata + (u8)ch * VIDEO_FONT_HEIGHT; if (x_frac + VID_TO_POS(vc_priv->x_charsize) > vc_priv->xsize_frac) return -EAGAIN; diff --git a/drivers/video/imx/Kconfig b/drivers/video/imx/Kconfig new file mode 100644 index 0000000000..c33620e075 --- /dev/null +++ b/drivers/video/imx/Kconfig @@ -0,0 +1,8 @@ + +config VIDEO_IPUV3 + bool "i.MX IPUv3 Core video support" + depends on (VIDEO || DM_VIDEO) && (MX5 || MX6) + help + This enables framebuffer driver for i.MX processors working + on the IPUv3(Image Processing Unit) internal graphic processor. + diff --git a/drivers/video/imx/Makefile b/drivers/video/imx/Makefile new file mode 100644 index 0000000000..179ea651fe --- /dev/null +++ b/drivers/video/imx/Makefile @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: GPL-2.0+ +# +# (C) Copyright 2000-2007 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. + +obj-y += mxc_ipuv3_fb.o ipu_common.o ipu_disp.o diff --git a/drivers/video/ipu.h b/drivers/video/imx/ipu.h index 1e02c7ab6d..1e02c7ab6d 100644 --- a/drivers/video/ipu.h +++ b/drivers/video/imx/ipu.h diff --git a/drivers/video/ipu_common.c b/drivers/video/imx/ipu_common.c index cbe1984e4f..cbe1984e4f 100644 --- a/drivers/video/ipu_common.c +++ b/drivers/video/imx/ipu_common.c diff --git a/drivers/video/ipu_disp.c b/drivers/video/imx/ipu_disp.c index 5c7722962d..5c7722962d 100644 --- a/drivers/video/ipu_disp.c +++ b/drivers/video/imx/ipu_disp.c diff --git a/drivers/video/ipu_regs.h b/drivers/video/imx/ipu_regs.h index deb44002d7..deb44002d7 100644 --- a/drivers/video/ipu_regs.h +++ b/drivers/video/imx/ipu_regs.h diff --git a/drivers/video/mxc_ipuv3_fb.c b/drivers/video/imx/mxc_ipuv3_fb.c index 23cd55de47..3e38d4bdcc 100644 --- a/drivers/video/mxc_ipuv3_fb.c +++ b/drivers/video/imx/mxc_ipuv3_fb.c @@ -17,13 +17,17 @@ #include <linux/list.h> #include <linux/fb.h> #include <asm/io.h> +#include <asm/mach-imx/video.h> #include <malloc.h> #include <video_fb.h> -#include "videomodes.h" +#include "../videomodes.h" #include "ipu.h" #include "mxcfb.h" #include "ipu_regs.h" +#include <dm.h> +#include <video.h> + DECLARE_GLOBAL_DATA_PTR; static int mxcfb_map_video_memory(struct fb_info *fbi); @@ -401,8 +405,14 @@ static int mxcfb_map_video_memory(struct fb_info *fbi) fbi->fix.line_length; } fbi->fix.smem_len = roundup(fbi->fix.smem_len, ARCH_DMA_MINALIGN); + +#if CONFIG_IS_ENABLED(DM_VIDEO) + fbi->screen_base = (char *)gd->video_bottom; +#else fbi->screen_base = (char *)memalign(ARCH_DMA_MINALIGN, fbi->fix.smem_len); +#endif + fbi->fix.smem_start = (unsigned long)fbi->screen_base; if (fbi->screen_base == 0) { puts("Unable to allocate framebuffer memory\n"); @@ -416,7 +426,9 @@ static int mxcfb_map_video_memory(struct fb_info *fbi) fbi->screen_size = fbi->fix.smem_len; +#if CONFIG_IS_ENABLED(VIDEO) gd->fb_base = fbi->fix.smem_start; +#endif /* Clear the screen */ memset((char *)fbi->screen_base, 0, fbi->fix.smem_len); @@ -611,3 +623,78 @@ int ipuv3_fb_init(struct fb_videomode const *mode, return 0; } + +#if CONFIG_IS_ENABLED(DM_VIDEO) +enum { + /* Maximum display size we support */ + LCD_MAX_WIDTH = 1920, + LCD_MAX_HEIGHT = 1080, + LCD_MAX_LOG2_BPP = VIDEO_BPP16, +}; + +static int ipuv3_video_probe(struct udevice *dev) +{ + struct video_uc_platdata *plat = dev_get_uclass_platdata(dev); + struct video_priv *uc_priv = dev_get_uclass_priv(dev); + u32 fb_start, fb_end; + int ret; + + debug("%s() plat: base 0x%lx, size 0x%x\n", + __func__, plat->base, plat->size); + + ret = ipu_probe(); + if (ret) + return ret; + + ret = ipu_displays_init(); + if (ret < 0) + return ret; + + ret = mxcfb_probe(gpixfmt, gdisp, gmode); + if (ret < 0) + return ret; + + uc_priv->xsize = gmode->xres; + uc_priv->ysize = gmode->yres; + uc_priv->bpix = LCD_MAX_LOG2_BPP; + + /* Enable dcache for the frame buffer */ + fb_start = plat->base & ~(MMU_SECTION_SIZE - 1); + fb_end = plat->base + plat->size; + fb_end = ALIGN(fb_end, 1 << MMU_SECTION_SHIFT); + mmu_set_region_dcache_behaviour(fb_start, fb_end - fb_start, + DCACHE_WRITEBACK); + video_set_flush_dcache(dev, true); + + return 0; +} + +struct ipuv3_video_priv { + ulong regs; +}; + +static int ipuv3_video_bind(struct udevice *dev) +{ + struct video_uc_platdata *plat = dev_get_uclass_platdata(dev); + + plat->size = LCD_MAX_WIDTH * LCD_MAX_HEIGHT * + (1 << LCD_MAX_LOG2_BPP) / 8; + + return 0; +} + +static const struct udevice_id ipuv3_video_ids[] = { + { .compatible = "fsl,imx6q-ipu" }, + { } +}; + +U_BOOT_DRIVER(ipuv3_video) = { + .name = "ipuv3_video", + .id = UCLASS_VIDEO, + .of_match = ipuv3_video_ids, + .bind = ipuv3_video_bind, + .probe = ipuv3_video_probe, + .priv_auto_alloc_size = sizeof(struct ipuv3_video_priv), + .flags = DM_FLAG_PRE_RELOC, +}; +#endif /* CONFIG_DM_VIDEO */ diff --git a/drivers/video/mxcfb.h b/drivers/video/imx/mxcfb.h index 0dc3886193..0dc3886193 100644 --- a/drivers/video/mxcfb.h +++ b/drivers/video/imx/mxcfb.h diff --git a/drivers/video/pwm_backlight.c b/drivers/video/pwm_backlight.c index bd733f5f1c..a587977c22 100644 --- a/drivers/video/pwm_backlight.c +++ b/drivers/video/pwm_backlight.c @@ -39,6 +39,12 @@ struct pwm_backlight_priv { struct udevice *pwm; uint channel; uint period_ns; + /* + * the polarity of one PWM + * 0: normal polarity + * 1: inverted polarity + */ + bool polarity; u32 *levels; int num_levels; uint default_level; @@ -57,7 +63,10 @@ static int set_pwm(struct pwm_backlight_priv *priv) (priv->max_level - priv->min_level + 1); ret = pwm_set_config(priv->pwm, priv->channel, priv->period_ns, duty_cycle); + if (ret) + return log_ret(ret); + ret = pwm_set_invert(priv->pwm, priv->channel, priv->polarity); return log_ret(ret); } @@ -202,6 +211,8 @@ static int pwm_backlight_ofdata_to_platdata(struct udevice *dev) return log_msg_ret("Not enough arguments to pwm\n", -EINVAL); priv->channel = args.args[0]; priv->period_ns = args.args[1]; + if (args.args_count > 2) + priv->polarity = args.args[2]; index = dev_read_u32_default(dev, "default-brightness-level", 255); cell = dev_read_prop(dev, "brightness-levels", &len); diff --git a/drivers/video/vidconsole-uclass.c b/drivers/video/vidconsole-uclass.c index 2ca19d4049..c31303b56e 100644 --- a/drivers/video/vidconsole-uclass.c +++ b/drivers/video/vidconsole-uclass.c @@ -259,6 +259,43 @@ static void vidconsole_escape_char(struct udevice *dev, char ch) priv->escape = 0; switch (ch) { + case 'A': + case 'B': + case 'C': + case 'D': + case 'E': + case 'F': { + int row, col, num; + char *s = priv->escape_buf; + + /* + * Cursor up/down: [%dA, [%dB, [%dE, [%dF + * Cursor left/right: [%dD, [%dC + */ + s++; /* [ */ + s = parsenum(s, &num); + if (num == 0) /* No digit in sequence ... */ + num = 1; /* ... means "move by 1". */ + + get_cursor_position(priv, &row, &col); + if (ch == 'A' || ch == 'F') + row -= num; + if (ch == 'C') + col += num; + if (ch == 'D') + col -= num; + if (ch == 'B' || ch == 'E') + row += num; + if (ch == 'E' || ch == 'F') + col = 0; + if (col < 0) + col = 0; + if (row < 0) + row = 0; + /* Right and bottom overflows are handled in the callee. */ + set_cursor_position(priv, row, col); + break; + } case 'H': case 'f': { int row, col; @@ -309,6 +346,25 @@ static void vidconsole_escape_char(struct udevice *dev, char ch) } break; } + case 'K': { + struct video_priv *vid_priv = dev_get_uclass_priv(dev->parent); + int mode; + + /* + * Clear (parts of) current line + * [0K - clear line to end + * [2K - clear entire line + */ + parsenum(priv->escape_buf + 1, &mode); + + if (mode == 2) { + int row, col; + + get_cursor_position(priv, &row, &col); + vidconsole_set_row(dev, row, vid_priv->colour_bg); + } + break; + } case 'm': { struct video_priv *vid_priv = dev_get_uclass_priv(dev->parent); char *s = priv->escape_buf; @@ -360,6 +416,13 @@ static void vidconsole_escape_char(struct udevice *dev, char ch) vid_priv->colour_fg = vid_console_color( vid_priv, vid_priv->fg_col_idx); break; + case 7: + /* reverse video */ + vid_priv->colour_fg = vid_console_color( + vid_priv, vid_priv->bg_col_idx); + vid_priv->colour_bg = vid_console_color( + vid_priv, vid_priv->fg_col_idx); + break; case 30 ... 37: /* foreground color */ vid_priv->fg_col_idx &= ~7; @@ -368,9 +431,11 @@ static void vidconsole_escape_char(struct udevice *dev, char ch) vid_priv, vid_priv->fg_col_idx); break; case 40 ... 47: - /* background color */ + /* background color, also mask the bold bit */ + vid_priv->bg_col_idx &= ~0xf; + vid_priv->bg_col_idx |= val - 40; vid_priv->colour_bg = vid_console_color( - vid_priv, val - 40); + vid_priv, vid_priv->bg_col_idx); break; default: /* ignore unsupported SGR parameter */ @@ -392,6 +457,32 @@ error: priv->escape = 0; } +/* Put that actual character on the screen (using the CP437 code page). */ +static int vidconsole_output_glyph(struct udevice *dev, char ch) +{ + struct vidconsole_priv *priv = dev_get_uclass_priv(dev); + int ret; + + /* + * Failure of this function normally indicates an unsupported + * colour depth. Check this and return an error to help with + * diagnosis. + */ + ret = vidconsole_putc_xy(dev, priv->xcur_frac, priv->ycur, ch); + if (ret == -EAGAIN) { + vidconsole_newline(dev); + ret = vidconsole_putc_xy(dev, priv->xcur_frac, priv->ycur, ch); + } + if (ret < 0) + return ret; + priv->xcur_frac += ret; + priv->last_ch = ch; + if (priv->xcur_frac >= priv->xsize_frac) + vidconsole_newline(dev); + + return 0; +} + int vidconsole_put_char(struct udevice *dev, char ch) { struct vidconsole_priv *priv = dev_get_uclass_priv(dev); @@ -429,23 +520,9 @@ int vidconsole_put_char(struct udevice *dev, char ch) priv->last_ch = 0; break; default: - /* - * Failure of this function normally indicates an unsupported - * colour depth. Check this and return an error to help with - * diagnosis. - */ - ret = vidconsole_putc_xy(dev, priv->xcur_frac, priv->ycur, ch); - if (ret == -EAGAIN) { - vidconsole_newline(dev); - ret = vidconsole_putc_xy(dev, priv->xcur_frac, - priv->ycur, ch); - } + ret = vidconsole_output_glyph(dev, ch); if (ret < 0) return ret; - priv->xcur_frac += ret; - priv->last_ch = ch; - if (priv->xcur_frac >= priv->xsize_frac) - vidconsole_newline(dev); break; } diff --git a/drivers/video/video-uclass.c b/drivers/video/video-uclass.c index f307cf243b..14aac88d6d 100644 --- a/drivers/video/video-uclass.c +++ b/drivers/video/video-uclass.c @@ -136,6 +136,7 @@ void video_set_default_colors(struct udevice *dev, bool invert) back = temp; } priv->fg_col_idx = fore; + priv->bg_col_idx = back; priv->colour_fg = vid_console_color(priv, fore); priv->colour_bg = vid_console_color(priv, back); } diff --git a/drivers/video/videomodes.c b/drivers/video/videomodes.c index 1cfeaa980f..d7614329ff 100644 --- a/drivers/video/videomodes.c +++ b/drivers/video/videomodes.c @@ -397,7 +397,7 @@ int video_edid_dtd_to_ctfb_res_modes(struct edid_detailed_timing *t, EDID_DETAILED_TIMING_VERTICAL_BLANKING(*t) == 0 || EDID_DETAILED_TIMING_HSYNC_OFFSET(*t) == 0 || EDID_DETAILED_TIMING_VSYNC_OFFSET(*t) == 0 || - /* 3d formats are not supported*/ + /* 3d formats are not supported */ EDID_DETAILED_TIMING_FLAG_STEREO(*t) != 0) return -EINVAL; |