diff options
Diffstat (limited to 'drivers')
83 files changed, 3442 insertions, 2078 deletions
diff --git a/drivers/block/mvsata_ide.c b/drivers/block/mvsata_ide.c index 2c6d42410c..7b6a1558d2 100644 --- a/drivers/block/mvsata_ide.c +++ b/drivers/block/mvsata_ide.c @@ -83,7 +83,7 @@ struct mvsata_port_registers { * Status codes to return to client callers. Currently, callers ignore * exact value and only care for zero or nonzero, so no need to make this * public, it is only #define'd for clarity. - * If/when standard negative codes are implemented in U-boot, then these + * If/when standard negative codes are implemented in U-Boot, then these * #defines should be moved to, or replaced by ones from, the common list * of status codes. */ diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig index 9fcde39b71..a98b74bbc0 100644 --- a/drivers/clk/Kconfig +++ b/drivers/clk/Kconfig @@ -20,4 +20,6 @@ config SPL_CLK setting up clocks within SPL, and allows the same drivers to be used as U-Boot proper. +source "drivers/clk/uniphier/Kconfig" + endmenu diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index c9144e3e1d..c51db1562b 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -10,3 +10,4 @@ obj-$(CONFIG_ROCKCHIP_RK3036) += clk_rk3036.o obj-$(CONFIG_ROCKCHIP_RK3288) += clk_rk3288.o obj-$(CONFIG_SANDBOX) += clk_sandbox.o obj-$(CONFIG_MACH_PIC32) += clk_pic32.o +obj-$(CONFIG_CLK_UNIPHIER) += uniphier/ diff --git a/drivers/clk/uniphier/Kconfig b/drivers/clk/uniphier/Kconfig new file mode 100644 index 0000000000..0e90c01a9a --- /dev/null +++ b/drivers/clk/uniphier/Kconfig @@ -0,0 +1,13 @@ +config CLK_UNIPHIER + bool + select CLK + select SPL_CLK + +menu "Clock drivers for UniPhier SoCs" + depends on CLK_UNIPHIER + +config CLK_UNIPHIER_MIO + bool "Clock driver for UniPhier Media I/O block" + default y + +endmenu diff --git a/drivers/clk/uniphier/Makefile b/drivers/clk/uniphier/Makefile new file mode 100644 index 0000000000..a3168f9bc1 --- /dev/null +++ b/drivers/clk/uniphier/Makefile @@ -0,0 +1,3 @@ +obj-y += clk-uniphier-core.o + +obj-$(CONFIG_CLK_UNIPHIER_MIO) += clk-uniphier-mio.o diff --git a/drivers/clk/uniphier/clk-uniphier-core.c b/drivers/clk/uniphier/clk-uniphier-core.c new file mode 100644 index 0000000000..e79e0ff689 --- /dev/null +++ b/drivers/clk/uniphier/clk-uniphier-core.c @@ -0,0 +1,159 @@ +/* + * Copyright (C) 2016 Masahiro Yamada <yamada.masahiro@socionext.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <mapmem.h> +#include <linux/bitops.h> +#include <linux/io.h> +#include <clk.h> +#include <dm/device.h> + +#include "clk-uniphier.h" + +DECLARE_GLOBAL_DATA_PTR; + +static int uniphier_clk_enable(struct udevice *dev, int index) +{ + struct uniphier_clk_priv *priv = dev_get_priv(dev); + struct uniphier_clk_gate_data *gate = priv->socdata->gate; + unsigned int nr_gate = priv->socdata->nr_gate; + void __iomem *reg; + u32 mask, data, tmp; + int i; + + for (i = 0; i < nr_gate; i++) { + if (gate[i].index != index) + continue; + + reg = priv->base + gate[i].reg; + mask = gate[i].mask; + data = gate[i].data & mask; + + tmp = readl(reg); + tmp &= ~mask; + tmp |= data & mask; + debug("%s: %p: %08x\n", __func__, reg, tmp); + writel(tmp, reg); + } + + return 0; +} + +static ulong uniphier_clk_get_rate(struct udevice *dev, int index) +{ + struct uniphier_clk_priv *priv = dev_get_priv(dev); + struct uniphier_clk_rate_data *rdata = priv->socdata->rate; + unsigned int nr_rdata = priv->socdata->nr_rate; + void __iomem *reg; + u32 mask, data; + ulong matched_rate = 0; + int i; + + for (i = 0; i < nr_rdata; i++) { + if (rdata[i].index != index) + continue; + + if (rdata[i].reg == UNIPHIER_CLK_RATE_IS_FIXED) + return rdata[i].rate; + + reg = priv->base + rdata[i].reg; + mask = rdata[i].mask; + data = rdata[i].data & mask; + if ((readl(reg) & mask) == data) { + if (matched_rate && rdata[i].rate != matched_rate) { + printf("failed to get clk rate for insane register values\n"); + return -EINVAL; + } + matched_rate = rdata[i].rate; + } + } + + debug("%s: rate = %lu\n", __func__, matched_rate); + + return matched_rate; +} + +static ulong uniphier_clk_set_rate(struct udevice *dev, int index, ulong rate) +{ + struct uniphier_clk_priv *priv = dev_get_priv(dev); + struct uniphier_clk_rate_data *rdata = priv->socdata->rate; + unsigned int nr_rdata = priv->socdata->nr_rate; + void __iomem *reg; + u32 mask, data, tmp; + ulong best_rate = 0; + int i; + + /* first, decide the best match rate */ + for (i = 0; i < nr_rdata; i++) { + if (rdata[i].index != index) + continue; + + if (rdata[i].reg == UNIPHIER_CLK_RATE_IS_FIXED) + return 0; + + if (rdata[i].rate > best_rate && rdata[i].rate <= rate) + best_rate = rdata[i].rate; + } + + if (!best_rate) + return -ENODEV; + + debug("%s: requested rate = %lu, set rate = %lu\n", __func__, + rate, best_rate); + + /* second, really set registers */ + for (i = 0; i < nr_rdata; i++) { + if (rdata[i].index != index || rdata[i].rate != best_rate) + continue; + + reg = priv->base + rdata[i].reg; + mask = rdata[i].mask; + data = rdata[i].data & mask; + + tmp = readl(reg); + tmp &= ~mask; + tmp |= data; + debug("%s: %p: %08x\n", __func__, reg, tmp); + writel(tmp, reg); + } + + return best_rate; +} + +const struct clk_ops uniphier_clk_ops = { + .enable = uniphier_clk_enable, + .get_periph_rate = uniphier_clk_get_rate, + .set_periph_rate = uniphier_clk_set_rate, +}; + +int uniphier_clk_probe(struct udevice *dev) +{ + struct uniphier_clk_priv *priv = dev_get_priv(dev); + fdt_addr_t addr; + fdt_size_t size; + + addr = fdtdec_get_addr_size(gd->fdt_blob, dev->of_offset, "reg", + &size); + if (addr == FDT_ADDR_T_NONE) + return -EINVAL; + + priv->base = map_sysmem(addr, size); + if (!priv->base) + return -ENOMEM; + + priv->socdata = (void *)dev_get_driver_data(dev); + + return 0; +} + +int uniphier_clk_remove(struct udevice *dev) +{ + struct uniphier_clk_priv *priv = dev_get_priv(dev); + + unmap_sysmem(priv->base); + + return 0; +} diff --git a/drivers/clk/uniphier/clk-uniphier-mio.c b/drivers/clk/uniphier/clk-uniphier-mio.c new file mode 100644 index 0000000000..d91ae34da1 --- /dev/null +++ b/drivers/clk/uniphier/clk-uniphier-mio.c @@ -0,0 +1,178 @@ +/* + * Copyright (C) 2016 Masahiro Yamada <yamada.masahiro@socionext.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <clk.h> +#include <dm/device.h> + +#include "clk-uniphier.h" + +#define UNIPHIER_MIO_CLK_GATE_SD(ch, idx) \ + { \ + .index = (idx), \ + .reg = 0x20 + 0x200 * (ch), \ + .mask = 0x00000100, \ + .data = 0x00000100, \ + }, \ + { \ + .index = (idx), \ + .reg = 0x110 + 0x200 * (ch), \ + .mask = 0x00000001, \ + .data = 0x00000001, \ + } + +#define UNIPHIER_MIO_CLK_RATE_SD(ch, idx) \ + { \ + .index = (idx), \ + .reg = 0x30 + 0x200 * (ch), \ + .mask = 0x00031300, \ + .data = 0x00000000, \ + .rate = 44444444, \ + }, \ + { \ + .index = (idx), \ + .reg = 0x30 + 0x200 * (ch), \ + .mask = 0x00031300, \ + .data = 0x00010000, \ + .rate = 33333333, \ + }, \ + { \ + .index = (idx), \ + .reg = 0x30 + 0x200 * (ch), \ + .mask = 0x00031300, \ + .data = 0x00020000, \ + .rate = 50000000, \ + }, \ + { \ + .index = (idx), \ + .reg = 0x30 + 0x200 * (ch), \ + .mask = 0x00031300, \ + .data = 0x00020000, \ + .rate = 66666666, \ + }, \ + { \ + .index = (idx), \ + .reg = 0x30 + 0x200 * (ch), \ + .mask = 0x00031300, \ + .data = 0x00001000, \ + .rate = 100000000, \ + }, \ + { \ + .index = (idx), \ + .reg = 0x30 + 0x200 * (ch), \ + .mask = 0x00031300, \ + .data = 0x00001100, \ + .rate = 40000000, \ + }, \ + { \ + .index = (idx), \ + .reg = 0x30 + 0x200 * (ch), \ + .mask = 0x00031300, \ + .data = 0x00001200, \ + .rate = 25000000, \ + }, \ + { \ + .index = (idx), \ + .reg = 0x30 + 0x200 * (ch), \ + .mask = 0x00031300, \ + .data = 0x00001300, \ + .rate = 22222222, \ + } + +#define UNIPHIER_MIO_CLK_GATE_USB(ch, idx) \ + { \ + .index = (idx), \ + .reg = 0x20 + 0x200 * (ch), \ + .mask = 0x30000000, \ + .data = 0x30000000, \ + }, \ + { \ + .index = (idx), \ + .reg = 0x110 + 0x200 * (ch), \ + .mask = 0x01000000, \ + .data = 0x01000000, \ + }, \ + { \ + .index = (idx), \ + .reg = 0x114 + 0x200 * (ch), \ + .mask = 0x00000001, \ + .data = 0x00000001, \ + } + +#define UNIPHIER_MIO_CLK_GATE_DMAC(idx) \ + { \ + .index = (idx), \ + .reg = 0x20, \ + .mask = 0x02000000, \ + .data = 0x02000000, \ + }, \ + { \ + .index = (idx), \ + .reg = 0x110, \ + .mask = 0x00020000, \ + .data = 0x00020000, \ + } + +static struct uniphier_clk_gate_data uniphier_mio_clk_gate[] = { + UNIPHIER_MIO_CLK_GATE_SD(0, 0), + UNIPHIER_MIO_CLK_GATE_SD(1, 1), + UNIPHIER_MIO_CLK_GATE_SD(2, 2), /* for PH1-Pro4 only */ + UNIPHIER_MIO_CLK_GATE_USB(0, 3), + UNIPHIER_MIO_CLK_GATE_USB(1, 4), + UNIPHIER_MIO_CLK_GATE_USB(2, 5), + UNIPHIER_MIO_CLK_GATE_DMAC(6), + UNIPHIER_MIO_CLK_GATE_USB(3, 7), /* for PH1-sLD3 only */ +}; + +static struct uniphier_clk_rate_data uniphier_mio_clk_rate[] = { + UNIPHIER_MIO_CLK_RATE_SD(0, 0), + UNIPHIER_MIO_CLK_RATE_SD(1, 1), + UNIPHIER_MIO_CLK_RATE_SD(2, 2), /* for PH1-Pro4 only */ +}; + +static struct uniphier_clk_soc_data uniphier_mio_clk_data = { + .gate = uniphier_mio_clk_gate, + .nr_gate = ARRAY_SIZE(uniphier_mio_clk_gate), + .rate = uniphier_mio_clk_rate, + .nr_rate = ARRAY_SIZE(uniphier_mio_clk_rate), +}; + +static const struct udevice_id uniphier_mio_clk_match[] = { + { + .compatible = "socionext,ph1-sld3-mioctrl", + .data = (ulong)&uniphier_mio_clk_data, + }, + { + .compatible = "socionext,ph1-ld4-mioctrl", + .data = (ulong)&uniphier_mio_clk_data, + }, + { + .compatible = "socionext,ph1-pro4-mioctrl", + .data = (ulong)&uniphier_mio_clk_data, + }, + { + .compatible = "socionext,ph1-sld8-mioctrl", + .data = (ulong)&uniphier_mio_clk_data, + }, + { + .compatible = "socionext,ph1-pro5-mioctrl", + .data = (ulong)&uniphier_mio_clk_data, + }, + { + .compatible = "socionext,proxstream2-mioctrl", + .data = (ulong)&uniphier_mio_clk_data, + }, + { /* sentinel */ } +}; + +U_BOOT_DRIVER(uniphier_mio_clk) = { + .name = "uniphier-mio-clk", + .id = UCLASS_CLK, + .of_match = uniphier_mio_clk_match, + .probe = uniphier_clk_probe, + .remove = uniphier_clk_remove, + .priv_auto_alloc_size = sizeof(struct uniphier_clk_priv), + .ops = &uniphier_clk_ops, +}; diff --git a/drivers/clk/uniphier/clk-uniphier.h b/drivers/clk/uniphier/clk-uniphier.h new file mode 100644 index 0000000000..560b3f8112 --- /dev/null +++ b/drivers/clk/uniphier/clk-uniphier.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2016 Masahiro Yamada <yamada.masahiro@socionext.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef __CLK_UNIPHIER_H__ +#define __CLK_UNIPHIER_H__ + +#include <linux/kernel.h> + +struct uniphier_clk_gate_data { + int index; + unsigned int reg; + u32 mask; + u32 data; +}; + +struct uniphier_clk_rate_data { + int index; + unsigned int reg; +#define UNIPHIER_CLK_RATE_IS_FIXED UINT_MAX + u32 mask; + u32 data; + unsigned long rate; +}; + +struct uniphier_clk_soc_data { + struct uniphier_clk_gate_data *gate; + unsigned int nr_gate; + struct uniphier_clk_rate_data *rate; + unsigned int nr_rate; +}; + +#define UNIPHIER_CLK_FIXED_RATE(i, f) \ + { \ + .index = i, \ + .reg = UNIPHIER_CLK_RATE_IS_FIXED, \ + .rate = f, \ + } + +/** + * struct uniphier_clk_priv - private data for UniPhier clock driver + * + * @base: base address of the clock provider + * @socdata: SoC specific data + */ +struct uniphier_clk_priv { + void __iomem *base; + struct uniphier_clk_soc_data *socdata; +}; + +extern const struct clk_ops uniphier_clk_ops; +int uniphier_clk_probe(struct udevice *dev); +int uniphier_clk_remove(struct udevice *dev); + +#endif /* __CLK_UNIPHIER_H__ */ diff --git a/drivers/ddr/marvell/axp/ddr3_hw_training.c b/drivers/ddr/marvell/axp/ddr3_hw_training.c index a8c5e6a534..c8d7041117 100644 --- a/drivers/ddr/marvell/axp/ddr3_hw_training.c +++ b/drivers/ddr/marvell/axp/ddr3_hw_training.c @@ -450,7 +450,7 @@ int ddr3_hw_training(u32 target_freq, u32 ddr_width, int xor_bypass, ddr3_set_performance_params(&dram_info); if (dram_info.ecc_ena) { - /* Need to SCRUB the DRAM memory area to load U-boot */ + /* Need to SCRUB the DRAM memory area to load U-Boot */ mv_sys_xor_finish(); dram_info.num_cs = 1; dram_info.cs_ena = 1; diff --git a/drivers/fpga/socfpga.c b/drivers/fpga/socfpga.c index 431e159e48..4448250f5c 100644 --- a/drivers/fpga/socfpga.c +++ b/drivers/fpga/socfpga.c @@ -269,7 +269,7 @@ int socfpga_load(Altera_desc *desc, const void *rbf_data, size_t rbf_size) /* Prior programming the FPGA, all bridges need to be shut off */ /* Disable all signals from hps peripheral controller to fpga */ - writel(0, &sysmgr_regs->fpgaintfgrp_gbl); + writel(0, &sysmgr_regs->fpgaintfgrp_module); /* Disable all signals from FPGA to HPS SDRAM */ #define SDR_CTRLGRP_FPGAPORTRST_ADDRESS 0x5080 diff --git a/drivers/gpio/db8500_gpio.c b/drivers/gpio/db8500_gpio.c index d5cb383e85..db32db6845 100644 --- a/drivers/gpio/db8500_gpio.c +++ b/drivers/gpio/db8500_gpio.c @@ -1,14 +1,14 @@ /* * Code ported from Nomadik GPIO driver in ST-Ericsson Linux kernel code. * The purpose is that GPIO config found in kernel should work by simply - * copy-paste it to U-boot. + * copy-paste it to U-Boot. * * Original Linux authors: * Copyright (C) 2008,2009 STMicroelectronics * Copyright (C) 2009 Alessandro Rubini <rubini@unipv.it> * Rewritten based on work by Prafulla WADASKAR <prafulla.wadaskar@st.com> * - * Ported to U-boot by: + * Ported to U-Boot by: * Copyright (C) 2010 Joakim Axelsson <joakim.axelsson AT stericsson.com> * * This program is free software; you can redistribute it and/or modify diff --git a/drivers/gpio/intel_ich6_gpio.c b/drivers/gpio/intel_ich6_gpio.c index 67bf0a2dd3..527ed6d0fa 100644 --- a/drivers/gpio/intel_ich6_gpio.c +++ b/drivers/gpio/intel_ich6_gpio.c @@ -30,6 +30,7 @@ #include <dm.h> #include <errno.h> #include <fdtdec.h> +#include <pch.h> #include <pci.h> #include <asm/gpio.h> #include <asm/io.h> @@ -62,91 +63,6 @@ void ich_gpio_set_gpio_map(const struct pch_gpio_map *map) gd->arch.gpio_map = map; } -static int gpio_ich6_get_base(unsigned long base) -{ - pci_dev_t pci_dev; /* handle for 0:1f:0 */ - u8 tmpbyte; - u16 tmpword; - u32 tmplong; - - /* Where should it be? */ - pci_dev = PCI_BDF(0, 0x1f, 0); - - /* Is the device present? */ - tmpword = x86_pci_read_config16(pci_dev, PCI_VENDOR_ID); - if (tmpword != PCI_VENDOR_ID_INTEL) { - debug("%s: wrong VendorID %x\n", __func__, tmpword); - return -ENODEV; - } - - tmpword = x86_pci_read_config16(pci_dev, PCI_DEVICE_ID); - debug("Found %04x:%04x\n", PCI_VENDOR_ID_INTEL, tmpword); - /* - * We'd like to validate the Device ID too, but pretty much any - * value is either a) correct with slight differences, or b) - * correct but undocumented. We'll have to check a bunch of other - * things instead... - */ - - /* I/O should already be enabled (it's a RO bit). */ - tmpword = x86_pci_read_config16(pci_dev, PCI_COMMAND); - if (!(tmpword & PCI_COMMAND_IO)) { - debug("%s: device IO not enabled\n", __func__); - return -ENODEV; - } - - /* Header Type must be normal (bits 6-0 only; see spec.) */ - tmpbyte = x86_pci_read_config8(pci_dev, PCI_HEADER_TYPE); - if ((tmpbyte & 0x7f) != PCI_HEADER_TYPE_NORMAL) { - debug("%s: invalid Header type\n", __func__); - return -ENODEV; - } - - /* Base Class must be a bridge device */ - tmpbyte = x86_pci_read_config8(pci_dev, PCI_CLASS_CODE); - if (tmpbyte != PCI_CLASS_CODE_BRIDGE) { - debug("%s: invalid class\n", __func__); - return -ENODEV; - } - /* Sub Class must be ISA */ - tmpbyte = x86_pci_read_config8(pci_dev, PCI_CLASS_SUB_CODE); - if (tmpbyte != PCI_CLASS_SUB_CODE_BRIDGE_ISA) { - debug("%s: invalid subclass\n", __func__); - return -ENODEV; - } - - /* Programming Interface must be 0x00 (no others exist) */ - tmpbyte = x86_pci_read_config8(pci_dev, PCI_CLASS_PROG); - if (tmpbyte != 0x00) { - debug("%s: invalid interface type\n", __func__); - return -ENODEV; - } - - /* - * GPIOBASE moved to its current offset with ICH6, but prior to - * that it was unused (or undocumented). Check that it looks - * okay: not all ones or zeros. - * - * Note we don't need check bit0 here, because the Tunnel Creek - * GPIO base address register bit0 is reserved (read returns 0), - * while on the Ivybridge the bit0 is used to indicate it is an - * I/O space. - */ - tmplong = x86_pci_read_config32(pci_dev, base); - if (tmplong == 0x00000000 || tmplong == 0xffffffff) { - debug("%s: unexpected BASE value\n", __func__); - return -ENODEV; - } - - /* - * Okay, I guess we're looking at the right device. The actual - * GPIO registers are in the PCI device's I/O space, starting - * at the offset that we just read. Bit 0 indicates that it's - * an I/O address, not a memory address, so mask that off. - */ - return tmplong & 1 ? tmplong & ~3 : tmplong & ~15; -} - static int _ich6_gpio_set_value(uint16_t base, unsigned offset, int value) { u32 val; @@ -288,20 +204,26 @@ static int _gpio_ich6_pinctrl_cfg_pin(s32 gpiobase, s32 iobase, int pin_node) int gpio_ich6_pinctrl_init(void) { + struct udevice *pch; int pin_node; int node; int ret; - int gpiobase; - int iobase_offset; - int iobase = -1; + u32 gpiobase; + u32 iobase = -1; + + ret = uclass_first_device(UCLASS_PCH, &pch); + if (ret) + return ret; + if (!pch) + return -ENODEV; /* * Get the memory/io base address to configure every pins. * IOBASE is used to configure the mode/pads * GPIOBASE is used to configure the direction and default value */ - gpiobase = gpio_ich6_get_base(PCI_CFG_GPIOBASE); - if (gpiobase < 0) { + ret = pch_get_gpio_base(pch, &gpiobase); + if (ret) { debug("%s: invalid GPIOBASE address (%08x)\n", __func__, gpiobase); return -EINVAL; @@ -319,16 +241,11 @@ int gpio_ich6_pinctrl_init(void) * Get the IOBASE, this is not mandatory as this is not * supported by all the CPU */ - iobase_offset = fdtdec_get_int(gd->fdt_blob, node, "io-base", -1); - if (iobase_offset == -1) { - debug("%s: io-base offset not present\n", __func__); - } else { - iobase = gpio_ich6_get_base(iobase_offset); - if (IS_ERR_VALUE(iobase)) { - debug("%s: invalid IOBASE address (%08x)\n", __func__, - iobase); - return -EINVAL; - } + ret = pch_get_io_base(pch, &iobase); + if (ret && ret != -ENOSYS) { + debug("%s: invalid IOBASE address (%08x)\n", __func__, + iobase); + return -EINVAL; } for (pin_node = fdt_first_subnode(gd->fdt_blob, node); @@ -349,10 +266,14 @@ int gpio_ich6_pinctrl_init(void) static int gpio_ich6_ofdata_to_platdata(struct udevice *dev) { struct ich6_bank_platdata *plat = dev_get_platdata(dev); - u16 gpiobase; + u32 gpiobase; int offset; + int ret; + + ret = pch_get_gpio_base(dev->parent, &gpiobase); + if (ret) + return ret; - gpiobase = gpio_ich6_get_base(PCI_CFG_GPIOBASE); offset = fdtdec_get_int(gd->fdt_blob, dev->of_offset, "reg", -1); if (offset == -1) { debug("%s: Invalid register offset %d\n", __func__, offset); diff --git a/drivers/gpio/tegra_gpio.c b/drivers/gpio/tegra_gpio.c index 8e880e276f..5a031159ca 100644 --- a/drivers/gpio/tegra_gpio.c +++ b/drivers/gpio/tegra_gpio.c @@ -177,7 +177,10 @@ static int tegra_gpio_get_value(struct udevice *dev, unsigned offset) debug("%s: pin = %d (port %d:bit %d)\n", __func__, gpio, GPIO_FULLPORT(gpio), GPIO_BIT(gpio)); - val = readl(&state->bank->gpio_in[GPIO_PORT(gpio)]); + if (get_direction(gpio) == DIRECTION_INPUT) + val = readl(&state->bank->gpio_in[GPIO_PORT(gpio)]); + else + val = readl(&state->bank->gpio_out[GPIO_PORT(gpio)]); return (val >> GPIO_BIT(gpio)) & 1; } diff --git a/drivers/input/tegra-kbc.c b/drivers/input/tegra-kbc.c index 951cbb4481..c77f610769 100644 --- a/drivers/input/tegra-kbc.c +++ b/drivers/input/tegra-kbc.c @@ -312,6 +312,7 @@ static int tegra_kbd_probe(struct udevice *dev) __func__, ret); return ret; } + input_add_tables(input, false); if (priv->matrix.fn_keycode) { ret = input_add_table(input, KEY_FN, -1, priv->matrix.fn_keycode, @@ -326,7 +327,6 @@ static int tegra_kbd_probe(struct udevice *dev) priv->input = input; input->dev = dev; input->read_keys = tegra_kbc_check; - input_add_tables(input, false); strcpy(sdev->name, "tegra-kbc"); ret = input_stdio_register(sdev); if (ret) { diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index e1e3c6b70f..f2b08abf11 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -32,6 +32,7 @@ ifdef CONFIG_DM_I2C obj-$(CONFIG_SANDBOX) += i2c_eeprom_emul.o endif obj-$(CONFIG_SMSC_LPC47M) += smsc_lpc47m.o +obj-$(CONFIG_SMSC_SIO1007) += smsc_sio1007.o obj-$(CONFIG_STATUS_LED) += status_led.o obj-$(CONFIG_SANDBOX) += swap_case.o obj-$(CONFIG_SANDBOX) += syscon_sandbox.o diff --git a/drivers/misc/smsc_sio1007.c b/drivers/misc/smsc_sio1007.c new file mode 100644 index 0000000000..ec53533bde --- /dev/null +++ b/drivers/misc/smsc_sio1007.c @@ -0,0 +1,126 @@ +/* + * Copyright (C) 2016, Bin Meng <bmeng.cn@gmail.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <asm/io.h> +#include <errno.h> +#include <smsc_sio1007.h> + +static inline u8 sio1007_read(int port, int reg) +{ + outb(reg, port); + + return inb(port + 1); +} + +static inline void sio1007_write(int port, int reg, int val) +{ + outb(reg, port); + outb(val, port + 1); +} + +static inline void sio1007_clrsetbits(int port, int reg, u8 clr, u8 set) +{ + sio1007_write(port, reg, (sio1007_read(port, reg) & ~clr) | set); +} + +void sio1007_enable_serial(int port, int num, int iobase, int irq) +{ + if (num < 0 || num > SIO1007_UART_NUM) + return; + + /* enter configuration state */ + outb(0x55, port); + + /* power on serial port and set up its i/o base & irq */ + if (!num) { + sio1007_clrsetbits(port, DEV_POWER_CTRL, 0, UART1_POWER_ON); + sio1007_clrsetbits(port, UART1_IOBASE, 0xfe, iobase >> 2); + sio1007_clrsetbits(port, UART_IRQ, 0xf0, irq << 4); + } else { + sio1007_clrsetbits(port, DEV_POWER_CTRL, 0, UART2_POWER_ON); + sio1007_clrsetbits(port, UART2_IOBASE, 0xfe, iobase >> 2); + sio1007_clrsetbits(port, UART_IRQ, 0x0f, irq); + } + + /* exit configuration state */ + outb(0xaa, port); +} + +void sio1007_enable_runtime(int port, int iobase) +{ + /* enter configuration state */ + outb(0x55, port); + + /* set i/o base for the runtime register block */ + sio1007_clrsetbits(port, RTR_IOBASE_LOW, 0, iobase >> 4); + sio1007_clrsetbits(port, RTR_IOBASE_HIGH, 0, iobase >> 12); + /* turn on address decoding for this block */ + sio1007_clrsetbits(port, DEV_ACTIVATE, 0, RTR_EN); + + /* exit configuration state */ + outb(0xaa, port); +} + +void sio1007_gpio_config(int port, int gpio, int dir, int pol, int type) +{ + int reg = GPIO0_DIR; + + if (gpio < 0 || gpio > SIO1007_GPIO_NUM) + return; + if (gpio >= GPIO_NUM_PER_GROUP) { + reg = GPIO1_DIR; + gpio -= GPIO_NUM_PER_GROUP; + } + + /* enter configuration state */ + outb(0x55, port); + + /* set gpio pin direction, polority and type */ + sio1007_clrsetbits(port, reg, 1 << gpio, dir << gpio); + sio1007_clrsetbits(port, reg + 1, 1 << gpio, pol << gpio); + sio1007_clrsetbits(port, reg + 2, 1 << gpio, type << gpio); + + /* exit configuration state */ + outb(0xaa, port); +} + +int sio1007_gpio_get_value(int port, int gpio) +{ + int reg = GPIO0_DATA; + int val; + + if (gpio < 0 || gpio > SIO1007_GPIO_NUM) + return -EINVAL; + if (gpio >= GPIO_NUM_PER_GROUP) { + reg = GPIO1_DATA; + gpio -= GPIO_NUM_PER_GROUP; + } + + val = inb(port + reg); + if (val & (1 << gpio)) + return 1; + else + return 0; +} + +void sio1007_gpio_set_value(int port, int gpio, int val) +{ + int reg = GPIO0_DATA; + u8 data; + + if (gpio < 0 || gpio > SIO1007_GPIO_NUM) + return; + if (gpio >= GPIO_NUM_PER_GROUP) { + reg = GPIO1_DATA; + gpio -= GPIO_NUM_PER_GROUP; + } + + data = inb(port + reg); + data &= ~(1 << gpio); + data |= (val << gpio); + outb(data, port + reg); +} diff --git a/drivers/mmc/sh_sdhi.c b/drivers/mmc/sh_sdhi.c index cc62c89a25..30e538cc16 100644 --- a/drivers/mmc/sh_sdhi.c +++ b/drivers/mmc/sh_sdhi.c @@ -526,7 +526,7 @@ static int sh_sdhi_start_cmd(struct sh_sdhi_host *host, opc = sh_sdhi_set_cmd(host, data, opc); /* - * U-boot cannot use interrupt. + * U-Boot cannot use interrupt. * So this flag may not be clear by timing */ sh_sdhi_writew(host, SDHI_INFO1, ~INFO1_RESP_END); diff --git a/drivers/mmc/tegra_mmc.c b/drivers/mmc/tegra_mmc.c index 15848658e1..573819a01e 100644 --- a/drivers/mmc/tegra_mmc.c +++ b/drivers/mmc/tegra_mmc.c @@ -674,7 +674,7 @@ void tegra_mmc_init(void) CONFIG_SYS_MMC_MAX_DEVICE); debug("%s: count of Tegra210 sdhci nodes is %d\n", __func__, count); if (process_nodes(blob, node_list, count)) { - printf("%s: Error processing T30 mmc node(s)!\n", __func__); + printf("%s: Error processing T210 mmc node(s)!\n", __func__); return; } @@ -684,7 +684,7 @@ void tegra_mmc_init(void) CONFIG_SYS_MMC_MAX_DEVICE); debug("%s: count of Tegra124 sdhci nodes is %d\n", __func__, count); if (process_nodes(blob, node_list, count)) { - printf("%s: Error processing T30 mmc node(s)!\n", __func__); + printf("%s: Error processing T124 mmc node(s)!\n", __func__); return; } diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig index 9a74064c98..2fc73ef4e5 100644 --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig @@ -71,6 +71,13 @@ config NAND_SUNXI Enable support for NAND. This option allows SPL to read from sunxi NAND using DMA transfers. +config NAND_ARASAN + bool "Configure Arasan Nand" + help + This enables Nand driver support for Arasan nand flash + controller. This uses the hardware ECC for read and + write operations. + comment "Generic NAND options" # Enhance depends when converting drivers to Kconfig which use this config diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile index b4e5376176..6fb37182d5 100644 --- a/drivers/mtd/nand/Makefile +++ b/drivers/mtd/nand/Makefile @@ -42,6 +42,7 @@ ifdef NORMAL_DRIVERS obj-$(CONFIG_NAND_ECC_BCH) += nand_bch.o obj-$(CONFIG_NAND_ATMEL) += atmel_nand.o +obj-$(CONFIG_NAND_ARASAN) += arasan_nfc.o obj-$(CONFIG_DRIVER_NAND_BFIN) += bfin_nand.o obj-$(CONFIG_NAND_DAVINCI) += davinci_nand.o obj-$(CONFIG_NAND_DENALI) += denali.o diff --git a/drivers/mtd/nand/arasan_nfc.c b/drivers/mtd/nand/arasan_nfc.c new file mode 100644 index 0000000000..2d73a05e75 --- /dev/null +++ b/drivers/mtd/nand/arasan_nfc.c @@ -0,0 +1,1154 @@ +/* + * Arasan NAND Flash Controller Driver + * + * Copyright (C) 2014 - 2015 Xilinx, Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <malloc.h> +#include <asm/io.h> +#include <asm/errno.h> +#include <linux/mtd/mtd.h> +#include <linux/mtd/nand.h> +#include <linux/mtd/partitions.h> +#include <linux/mtd/nand_ecc.h> +#include <asm/arch/hardware.h> +#include <asm/arch/sys_proto.h> +#include <nand.h> + +struct arasan_nand_info { + void __iomem *nand_base; + u32 page; +}; + +struct nand_regs { + u32 pkt_reg; + u32 memadr_reg1; + u32 memadr_reg2; + u32 cmd_reg; + u32 pgm_reg; + u32 intsts_enr; + u32 intsig_enr; + u32 intsts_reg; + u32 rdy_busy; + u32 cms_sysadr_reg; + u32 flash_sts_reg; + u32 tmg_reg; + u32 buf_dataport; + u32 ecc_reg; + u32 ecc_errcnt_reg; + u32 ecc_sprcmd_reg; + u32 errcnt_1bitreg; + u32 errcnt_2bitreg; + u32 errcnt_3bitreg; + u32 errcnt_4bitreg; + u32 dma_sysadr0_reg; + u32 dma_bufbdry_reg; + u32 cpu_rls_reg; + u32 errcnt_5bitreg; + u32 errcnt_6bitreg; + u32 errcnt_7bitreg; + u32 errcnt_8bitreg; + u32 data_if_reg; +}; + +#define arasan_nand_base ((struct nand_regs __iomem *)ARASAN_NAND_BASEADDR) + +struct arasan_nand_command_format { + u8 cmd1; + u8 cmd2; + u8 addr_cycles; + u32 pgm; +}; + +#define ONDIE_ECC_FEATURE_ADDR 0x90 + +#define ARASAN_PROG_RD_MASK 0x00000001 +#define ARASAN_PROG_BLK_ERS_MASK 0x00000004 +#define ARASAN_PROG_RD_ID_MASK 0x00000040 +#define ARASAN_PROG_RD_STS_MASK 0x00000008 +#define ARASAN_PROG_PG_PROG_MASK 0x00000010 +#define ARASAN_PROG_RD_PARAM_PG_MASK 0x00000080 +#define ARASAN_PROG_RST_MASK 0x00000100 +#define ARASAN_PROG_GET_FTRS_MASK 0x00000200 +#define ARASAN_PROG_SET_FTRS_MASK 0x00000400 +#define ARASAN_PROG_CHNG_ROWADR_END_MASK 0x00400000 + +#define ARASAN_NAND_CMD_ECC_ON_MASK 0x80000000 +#define ARASAN_NAND_CMD_CMD12_MASK 0xFFFF +#define ARASAN_NAND_CMD_PG_SIZE_MASK 0x3800000 +#define ARASAN_NAND_CMD_PG_SIZE_SHIFT 23 +#define ARASAN_NAND_CMD_CMD2_SHIFT 8 +#define ARASAN_NAND_CMD_ADDR_CYCL_MASK 0x70000000 +#define ARASAN_NAND_CMD_ADDR_CYCL_SHIFT 28 + +#define ARASAN_NAND_MEM_ADDR1_PAGE_MASK 0xFFFF0000 +#define ARASAN_NAND_MEM_ADDR1_COL_MASK 0xFFFF +#define ARASAN_NAND_MEM_ADDR1_PAGE_SHIFT 16 +#define ARASAN_NAND_MEM_ADDR2_PAGE_MASK 0xFF +#define ARASAN_NAND_MEM_ADDR2_CS_MASK 0xC0000000 +#define ARASAN_NAND_MEM_ADDR2_BCH_MASK 0xE000000 +#define ARASAN_NAND_MEM_ADDR2_BCH_SHIFT 25 + +#define ARASAN_NAND_INT_STS_ERR_EN_MASK 0x10 +#define ARASAN_NAND_INT_STS_MUL_BIT_ERR_MASK 0x08 +#define ARASAN_NAND_INT_STS_BUF_RD_RDY_MASK 0x02 +#define ARASAN_NAND_INT_STS_BUF_WR_RDY_MASK 0x01 +#define ARASAN_NAND_INT_STS_XFR_CMPLT_MASK 0x04 + +#define ARASAN_NAND_PKT_REG_PKT_CNT_MASK 0xFFF000 +#define ARASAN_NAND_PKT_REG_PKT_SIZE_MASK 0x7FF +#define ARASAN_NAND_PKT_REG_PKT_CNT_SHFT 12 + +#define ARASAN_NAND_ROW_ADDR_CYCL_MASK 0x0F +#define ARASAN_NAND_COL_ADDR_CYCL_MASK 0xF0 +#define ARASAN_NAND_COL_ADDR_CYCL_SHIFT 4 + +#define ARASAN_NAND_ECC_SIZE_SHIFT 16 +#define ARASAN_NAND_ECC_BCH_SHIFT 27 + +#define ARASAN_NAND_PKTSIZE_1K 1024 +#define ARASAN_NAND_PKTSIZE_512 512 + +#define ARASAN_NAND_POLL_TIMEOUT 1000000 +#define ARASAN_NAND_INVALID_ADDR_CYCL 0xFF + +#define ERR_ADDR_CYCLE -1 +#define READ_BUFF_SIZE 0x4000 + +static struct arasan_nand_command_format *curr_cmd; + +enum addr_cycles { + NAND_ADDR_CYCL_NONE, + NAND_ADDR_CYCL_ONE, + NAND_ADDR_CYCL_ROW, + NAND_ADDR_CYCL_COL, + NAND_ADDR_CYCL_BOTH, +}; + +static struct arasan_nand_command_format arasan_nand_commands[] = { + {NAND_CMD_READ0, NAND_CMD_READSTART, NAND_ADDR_CYCL_BOTH, + ARASAN_PROG_RD_MASK}, + {NAND_CMD_RNDOUT, NAND_CMD_RNDOUTSTART, NAND_ADDR_CYCL_COL, + ARASAN_PROG_RD_MASK}, + {NAND_CMD_READID, NAND_CMD_NONE, NAND_ADDR_CYCL_ONE, + ARASAN_PROG_RD_ID_MASK}, + {NAND_CMD_STATUS, NAND_CMD_NONE, NAND_ADDR_CYCL_NONE, + ARASAN_PROG_RD_STS_MASK}, + {NAND_CMD_SEQIN, NAND_CMD_PAGEPROG, NAND_ADDR_CYCL_BOTH, + ARASAN_PROG_PG_PROG_MASK}, + {NAND_CMD_RNDIN, NAND_CMD_NONE, NAND_ADDR_CYCL_COL, + ARASAN_PROG_CHNG_ROWADR_END_MASK}, + {NAND_CMD_ERASE1, NAND_CMD_ERASE2, NAND_ADDR_CYCL_ROW, + ARASAN_PROG_BLK_ERS_MASK}, + {NAND_CMD_RESET, NAND_CMD_NONE, NAND_ADDR_CYCL_NONE, + ARASAN_PROG_RST_MASK}, + {NAND_CMD_PARAM, NAND_CMD_NONE, NAND_ADDR_CYCL_ONE, + ARASAN_PROG_RD_PARAM_PG_MASK}, + {NAND_CMD_GET_FEATURES, NAND_CMD_NONE, NAND_ADDR_CYCL_ONE, + ARASAN_PROG_GET_FTRS_MASK}, + {NAND_CMD_SET_FEATURES, NAND_CMD_NONE, NAND_ADDR_CYCL_ONE, + ARASAN_PROG_SET_FTRS_MASK}, + {NAND_CMD_NONE, NAND_CMD_NONE, NAND_ADDR_CYCL_NONE, 0}, +}; + +struct arasan_ecc_matrix { + u32 pagesize; + u32 ecc_codeword_size; + u8 eccbits; + u8 bch; + u8 bchval; + u16 eccaddr; + u16 eccsize; +}; + +static const struct arasan_ecc_matrix ecc_matrix[] = { + {512, 512, 1, 0, 0, 0x20D, 0x3}, + {512, 512, 4, 1, 3, 0x209, 0x7}, + {512, 512, 8, 1, 2, 0x203, 0xD}, + /* + * 2K byte page + */ + {2048, 512, 1, 0, 0, 0x834, 0xC}, + {2048, 512, 4, 1, 3, 0x826, 0x1A}, + {2048, 512, 8, 1, 2, 0x80c, 0x34}, + {2048, 512, 12, 1, 1, 0x822, 0x4E}, + {2048, 512, 16, 1, 0, 0x808, 0x68}, + {2048, 1024, 24, 1, 4, 0x81c, 0x54}, + /* + * 4K byte page + */ + {4096, 512, 1, 0, 0, 0x1068, 0x18}, + {4096, 512, 4, 1, 3, 0x104c, 0x34}, + {4096, 512, 8, 1, 2, 0x1018, 0x68}, + {4096, 512, 12, 1, 1, 0x1044, 0x9C}, + {4096, 512, 16, 1, 0, 0x1010, 0xD0}, + {4096, 1024, 24, 1, 4, 0x1038, 0xA8}, + /* + * 8K byte page + */ + {8192, 512, 1, 0, 0, 0x20d0, 0x30}, + {8192, 512, 4, 1, 3, 0x2098, 0x68}, + {8192, 512, 8, 1, 2, 0x2030, 0xD0}, + {8192, 512, 12, 1, 1, 0x2088, 0x138}, + {8192, 512, 16, 1, 0, 0x2020, 0x1A0}, + {8192, 1024, 24, 1, 4, 0x2070, 0x150}, + /* + * 16K byte page + */ + {16384, 512, 1, 0, 0, 0x4460, 0x60}, + {16384, 512, 4, 1, 3, 0x43f0, 0xD0}, + {16384, 512, 8, 1, 2, 0x4320, 0x1A0}, + {16384, 512, 12, 1, 1, 0x4250, 0x270}, + {16384, 512, 16, 1, 0, 0x4180, 0x340}, + {16384, 1024, 24, 1, 4, 0x4220, 0x2A0} +}; + +static u8 buf_data[READ_BUFF_SIZE]; +static u32 buf_index; + +static struct nand_ecclayout nand_oob; + +static struct nand_chip nand_chip[CONFIG_SYS_MAX_NAND_DEVICE]; + +static void arasan_nand_select_chip(struct mtd_info *mtd, int chip) +{ +} + +static void arasan_nand_enable_ecc(void) +{ + u32 reg_val; + + reg_val = readl(&arasan_nand_base->cmd_reg); + reg_val |= ARASAN_NAND_CMD_ECC_ON_MASK; + + writel(reg_val, &arasan_nand_base->cmd_reg); +} + +static u8 arasan_nand_get_addrcycle(struct mtd_info *mtd) +{ + u8 addrcycles; + struct nand_chip *chip = mtd->priv; + + switch (curr_cmd->addr_cycles) { + case NAND_ADDR_CYCL_NONE: + addrcycles = 0; + break; + case NAND_ADDR_CYCL_ONE: + addrcycles = 1; + break; + case NAND_ADDR_CYCL_ROW: + addrcycles = chip->onfi_params.addr_cycles & + ARASAN_NAND_ROW_ADDR_CYCL_MASK; + break; + case NAND_ADDR_CYCL_COL: + addrcycles = (chip->onfi_params.addr_cycles & + ARASAN_NAND_COL_ADDR_CYCL_MASK) >> + ARASAN_NAND_COL_ADDR_CYCL_SHIFT; + break; + case NAND_ADDR_CYCL_BOTH: + addrcycles = chip->onfi_params.addr_cycles & + ARASAN_NAND_ROW_ADDR_CYCL_MASK; + addrcycles += (chip->onfi_params.addr_cycles & + ARASAN_NAND_COL_ADDR_CYCL_MASK) >> + ARASAN_NAND_COL_ADDR_CYCL_SHIFT; + break; + default: + addrcycles = ARASAN_NAND_INVALID_ADDR_CYCL; + break; + } + return addrcycles; +} + +static int arasan_nand_read_page(struct mtd_info *mtd, u8 *buf, u32 size) +{ + struct nand_chip *chip = mtd->priv; + u32 reg_val, i, pktsize, pktnum; + u32 *bufptr = (u32 *)buf; + u32 timeout; + u32 rdcount = 0; + u8 addr_cycles; + + if (chip->ecc_step_ds >= ARASAN_NAND_PKTSIZE_1K) + pktsize = ARASAN_NAND_PKTSIZE_1K; + else + pktsize = ARASAN_NAND_PKTSIZE_512; + + if (size % pktsize) + pktnum = size/pktsize + 1; + else + pktnum = size/pktsize; + + reg_val = readl(&arasan_nand_base->intsts_enr); + reg_val |= ARASAN_NAND_INT_STS_ERR_EN_MASK | + ARASAN_NAND_INT_STS_MUL_BIT_ERR_MASK; + writel(reg_val, &arasan_nand_base->intsts_enr); + + reg_val = readl(&arasan_nand_base->pkt_reg); + reg_val &= ~(ARASAN_NAND_PKT_REG_PKT_CNT_MASK | + ARASAN_NAND_PKT_REG_PKT_SIZE_MASK); + reg_val |= (pktnum << ARASAN_NAND_PKT_REG_PKT_CNT_SHFT) | + pktsize; + writel(reg_val, &arasan_nand_base->pkt_reg); + + arasan_nand_enable_ecc(); + addr_cycles = arasan_nand_get_addrcycle(mtd); + if (addr_cycles == ARASAN_NAND_INVALID_ADDR_CYCL) + return ERR_ADDR_CYCLE; + + writel((NAND_CMD_RNDOUTSTART << ARASAN_NAND_CMD_CMD2_SHIFT) | + NAND_CMD_RNDOUT | (addr_cycles << + ARASAN_NAND_CMD_ADDR_CYCL_SHIFT), + &arasan_nand_base->ecc_sprcmd_reg); + writel(curr_cmd->pgm, &arasan_nand_base->pgm_reg); + + while (rdcount < pktnum) { + timeout = ARASAN_NAND_POLL_TIMEOUT; + while (!(readl(&arasan_nand_base->intsts_reg) & + ARASAN_NAND_INT_STS_BUF_RD_RDY_MASK) && timeout) { + udelay(1); + timeout--; + } + if (!timeout) { + puts("arasan_read_page: timedout:Buff RDY\n"); + return -ETIMEDOUT; + } + + rdcount++; + + if (pktnum == rdcount) { + reg_val = readl(&arasan_nand_base->intsts_enr); + reg_val |= ARASAN_NAND_INT_STS_XFR_CMPLT_MASK; + writel(reg_val, &arasan_nand_base->intsts_enr); + } else { + reg_val = readl(&arasan_nand_base->intsts_enr); + writel(reg_val | ARASAN_NAND_INT_STS_BUF_RD_RDY_MASK, + &arasan_nand_base->intsts_enr); + } + reg_val = readl(&arasan_nand_base->intsts_reg); + writel(reg_val | ARASAN_NAND_INT_STS_BUF_RD_RDY_MASK, + &arasan_nand_base->intsts_reg); + + for (i = 0; i < pktsize/4; i++) + bufptr[i] = readl(&arasan_nand_base->buf_dataport); + + + bufptr += pktsize/4; + + if (rdcount >= pktnum) + break; + + writel(ARASAN_NAND_INT_STS_BUF_RD_RDY_MASK, + &arasan_nand_base->intsts_enr); + } + + timeout = ARASAN_NAND_POLL_TIMEOUT; + + while (!(readl(&arasan_nand_base->intsts_reg) & + ARASAN_NAND_INT_STS_XFR_CMPLT_MASK) && timeout) { + udelay(1); + timeout--; + } + if (!timeout) { + puts("arasan rd_page timedout:Xfer CMPLT\n"); + return -ETIMEDOUT; + } + + reg_val = readl(&arasan_nand_base->intsts_enr); + writel(reg_val | ARASAN_NAND_INT_STS_XFR_CMPLT_MASK, + &arasan_nand_base->intsts_enr); + reg_val = readl(&arasan_nand_base->intsts_reg); + writel(reg_val | ARASAN_NAND_INT_STS_XFR_CMPLT_MASK, + &arasan_nand_base->intsts_reg); + + if (readl(&arasan_nand_base->intsts_reg) & + ARASAN_NAND_INT_STS_MUL_BIT_ERR_MASK) { + printf("arasan rd_page:sbiterror\n"); + return -1; + } + + if (readl(&arasan_nand_base->intsts_reg) & + ARASAN_NAND_INT_STS_ERR_EN_MASK) { + mtd->ecc_stats.failed++; + printf("arasan rd_page:multibiterror\n"); + return -1; + } + + return 0; +} + +static int arasan_nand_read_page_hwecc(struct mtd_info *mtd, + struct nand_chip *chip, u8 *buf, int oob_required, int page) +{ + int status; + + status = arasan_nand_read_page(mtd, buf, (mtd->writesize)); + + if (oob_required) + chip->ecc.read_oob(mtd, chip, page); + + return status; +} + +static void arasan_nand_fill_tx(const u8 *buf, int len) +{ + u32 __iomem *nand = &arasan_nand_base->buf_dataport; + + if (((unsigned long)buf & 0x3) != 0) { + if (((unsigned long)buf & 0x1) != 0) { + if (len) { + writeb(*buf, nand); + buf += 1; + len--; + } + } + + if (((unsigned long)buf & 0x3) != 0) { + if (len >= 2) { + writew(*(u16 *)buf, nand); + buf += 2; + len -= 2; + } + } + } + + while (len >= 4) { + writel(*(u32 *)buf, nand); + buf += 4; + len -= 4; + } + + if (len) { + if (len >= 2) { + writew(*(u16 *)buf, nand); + buf += 2; + len -= 2; + } + + if (len) + writeb(*buf, nand); + } +} + +static int arasan_nand_write_page_hwecc(struct mtd_info *mtd, + struct nand_chip *chip, const u8 *buf, int oob_required) +{ + u32 reg_val, i, pktsize, pktnum; + const u32 *bufptr = (const u32 *)buf; + u32 timeout = ARASAN_NAND_POLL_TIMEOUT; + u32 size = mtd->writesize; + u32 rdcount = 0; + u8 column_addr_cycles; + struct arasan_nand_info *nand = chip->priv; + + if (chip->ecc_step_ds >= ARASAN_NAND_PKTSIZE_1K) + pktsize = ARASAN_NAND_PKTSIZE_1K; + else + pktsize = ARASAN_NAND_PKTSIZE_512; + + if (size % pktsize) + pktnum = size/pktsize + 1; + else + pktnum = size/pktsize; + + reg_val = readl(&arasan_nand_base->pkt_reg); + reg_val &= ~(ARASAN_NAND_PKT_REG_PKT_CNT_MASK | + ARASAN_NAND_PKT_REG_PKT_SIZE_MASK); + reg_val |= (pktnum << ARASAN_NAND_PKT_REG_PKT_CNT_SHFT) | pktsize; + writel(reg_val, &arasan_nand_base->pkt_reg); + + arasan_nand_enable_ecc(); + column_addr_cycles = (chip->onfi_params.addr_cycles & + ARASAN_NAND_COL_ADDR_CYCL_MASK) >> + ARASAN_NAND_COL_ADDR_CYCL_SHIFT; + writel((NAND_CMD_RNDIN | (column_addr_cycles << 28)), + &arasan_nand_base->ecc_sprcmd_reg); + writel(curr_cmd->pgm, &arasan_nand_base->pgm_reg); + + while (rdcount < pktnum) { + timeout = ARASAN_NAND_POLL_TIMEOUT; + while (!(readl(&arasan_nand_base->intsts_reg) & + ARASAN_NAND_INT_STS_BUF_WR_RDY_MASK) && timeout) { + udelay(1); + timeout--; + } + + if (!timeout) { + puts("arasan_write_page: timedout:Buff RDY\n"); + return -ETIMEDOUT; + } + + rdcount++; + + if (pktnum == rdcount) { + reg_val = readl(&arasan_nand_base->intsts_enr); + reg_val |= ARASAN_NAND_INT_STS_XFR_CMPLT_MASK; + writel(reg_val, &arasan_nand_base->intsts_enr); + } else { + reg_val = readl(&arasan_nand_base->intsts_enr); + writel(reg_val | ARASAN_NAND_INT_STS_BUF_WR_RDY_MASK, + &arasan_nand_base->intsts_enr); + } + + reg_val = readl(&arasan_nand_base->intsts_reg); + writel(reg_val | ARASAN_NAND_INT_STS_BUF_WR_RDY_MASK, + &arasan_nand_base->intsts_reg); + + for (i = 0; i < pktsize/4; i++) + writel(bufptr[i], &arasan_nand_base->buf_dataport); + + bufptr += pktsize/4; + + if (rdcount >= pktnum) + break; + + writel(ARASAN_NAND_INT_STS_BUF_WR_RDY_MASK, + &arasan_nand_base->intsts_enr); + } + + timeout = ARASAN_NAND_POLL_TIMEOUT; + + while (!(readl(&arasan_nand_base->intsts_reg) & + ARASAN_NAND_INT_STS_XFR_CMPLT_MASK) && timeout) { + udelay(1); + timeout--; + } + if (!timeout) { + puts("arasan write_page timedout:Xfer CMPLT\n"); + return -ETIMEDOUT; + } + + reg_val = readl(&arasan_nand_base->intsts_enr); + writel(reg_val | ARASAN_NAND_INT_STS_XFR_CMPLT_MASK, + &arasan_nand_base->intsts_enr); + reg_val = readl(&arasan_nand_base->intsts_reg); + writel(reg_val | ARASAN_NAND_INT_STS_XFR_CMPLT_MASK, + &arasan_nand_base->intsts_reg); + + if (oob_required) + chip->ecc.write_oob(mtd, chip, nand->page); + + return 0; +} + +static int arasan_nand_read_oob(struct mtd_info *mtd, struct nand_chip *chip, + int page) +{ + chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page); + chip->read_buf(mtd, chip->oob_poi, (mtd->oobsize)); + + return 0; +} + +static int arasan_nand_write_oob(struct mtd_info *mtd, struct nand_chip *chip, + int page) +{ + int status = 0; + const u8 *buf = chip->oob_poi; + + chip->cmdfunc(mtd, NAND_CMD_SEQIN, mtd->writesize, page); + chip->write_buf(mtd, buf, mtd->oobsize); + + return status; +} + +static int arasan_nand_reset(struct arasan_nand_command_format *curr_cmd) +{ + u32 timeout = ARASAN_NAND_POLL_TIMEOUT; + u32 cmd_reg = 0; + + writel(ARASAN_NAND_INT_STS_XFR_CMPLT_MASK, + &arasan_nand_base->intsts_enr); + cmd_reg = readl(&arasan_nand_base->cmd_reg); + cmd_reg &= ~ARASAN_NAND_CMD_CMD12_MASK; + + cmd_reg |= curr_cmd->cmd1 | + (curr_cmd->cmd2 << ARASAN_NAND_CMD_CMD2_SHIFT); + writel(cmd_reg, &arasan_nand_base->cmd_reg); + writel(curr_cmd->pgm, &arasan_nand_base->pgm_reg); + + while (!(readl(&arasan_nand_base->intsts_reg) & + ARASAN_NAND_INT_STS_XFR_CMPLT_MASK) && timeout) { + udelay(1); + timeout--; + } + if (!timeout) { + printf("ERROR:%s timedout\n", __func__); + return -ETIMEDOUT; + } + + writel(ARASAN_NAND_INT_STS_XFR_CMPLT_MASK, + &arasan_nand_base->intsts_enr); + + writel(ARASAN_NAND_INT_STS_XFR_CMPLT_MASK, + &arasan_nand_base->intsts_reg); + + return 0; +} + +static u8 arasan_nand_page(struct mtd_info *mtd) +{ + u8 page_val = 0; + + switch (mtd->writesize) { + case 512: + page_val = 0; + break; + case 2048: + page_val = 1; + break; + case 4096: + page_val = 2; + break; + case 8192: + page_val = 3; + break; + case 16384: + page_val = 4; + break; + case 1024: + page_val = 5; + break; + default: + printf("%s:Pagesize>16K\n", __func__); + break; + } + + return page_val; +} + +static int arasan_nand_send_wrcmd(struct arasan_nand_command_format *curr_cmd, + int column, int page_addr, struct mtd_info *mtd) +{ + u32 reg_val, page; + u8 page_val, addr_cycles; + + writel(ARASAN_NAND_INT_STS_BUF_WR_RDY_MASK, + &arasan_nand_base->intsts_enr); + reg_val = readl(&arasan_nand_base->cmd_reg); + reg_val &= ~ARASAN_NAND_CMD_CMD12_MASK; + reg_val |= curr_cmd->cmd1 | + (curr_cmd->cmd2 << ARASAN_NAND_CMD_CMD2_SHIFT); + if (curr_cmd->cmd1 == NAND_CMD_SEQIN) { + reg_val &= ~ARASAN_NAND_CMD_PG_SIZE_MASK; + page_val = arasan_nand_page(mtd); + reg_val |= (page_val << ARASAN_NAND_CMD_PG_SIZE_SHIFT); + } + + reg_val &= ~ARASAN_NAND_CMD_ADDR_CYCL_MASK; + addr_cycles = arasan_nand_get_addrcycle(mtd); + + if (addr_cycles == ARASAN_NAND_INVALID_ADDR_CYCL) + return ERR_ADDR_CYCLE; + + reg_val |= (addr_cycles << + ARASAN_NAND_CMD_ADDR_CYCL_SHIFT); + writel(reg_val, &arasan_nand_base->cmd_reg); + + if (page_addr == -1) + page_addr = 0; + + page = (page_addr << ARASAN_NAND_MEM_ADDR1_PAGE_SHIFT) & + ARASAN_NAND_MEM_ADDR1_PAGE_MASK; + column &= ARASAN_NAND_MEM_ADDR1_COL_MASK; + writel(page|column, &arasan_nand_base->memadr_reg1); + + reg_val = readl(&arasan_nand_base->memadr_reg2); + reg_val &= ~ARASAN_NAND_MEM_ADDR2_PAGE_MASK; + reg_val |= (page_addr >> ARASAN_NAND_MEM_ADDR1_PAGE_SHIFT); + writel(reg_val, &arasan_nand_base->memadr_reg2); + reg_val = readl(&arasan_nand_base->memadr_reg2); + reg_val &= ~ARASAN_NAND_MEM_ADDR2_CS_MASK; + writel(reg_val, &arasan_nand_base->memadr_reg2); + + return 0; +} + +static void arasan_nand_write_buf(struct mtd_info *mtd, const u8 *buf, int len) +{ + u32 reg_val; + u32 timeout = ARASAN_NAND_POLL_TIMEOUT; + + reg_val = readl(&arasan_nand_base->pkt_reg); + reg_val &= ~(ARASAN_NAND_PKT_REG_PKT_CNT_MASK | + ARASAN_NAND_PKT_REG_PKT_SIZE_MASK); + + reg_val |= (1 << ARASAN_NAND_PKT_REG_PKT_CNT_SHFT) | len; + writel(reg_val, &arasan_nand_base->pkt_reg); + writel(curr_cmd->pgm, &arasan_nand_base->pgm_reg); + + while (!(readl(&arasan_nand_base->intsts_reg) & + ARASAN_NAND_INT_STS_BUF_WR_RDY_MASK) && timeout) { + udelay(1); + timeout--; + } + + if (!timeout) + puts("ERROR:arasan_nand_write_buf timedout:Buff RDY\n"); + + reg_val = readl(&arasan_nand_base->intsts_enr); + reg_val |= ARASAN_NAND_INT_STS_XFR_CMPLT_MASK; + writel(reg_val, &arasan_nand_base->intsts_enr); + writel(reg_val | ARASAN_NAND_INT_STS_BUF_WR_RDY_MASK, + &arasan_nand_base->intsts_enr); + reg_val = readl(&arasan_nand_base->intsts_reg); + writel(reg_val | ARASAN_NAND_INT_STS_BUF_WR_RDY_MASK, + &arasan_nand_base->intsts_reg); + + arasan_nand_fill_tx(buf, len); + + timeout = ARASAN_NAND_POLL_TIMEOUT; + while (!(readl(&arasan_nand_base->intsts_reg) & + ARASAN_NAND_INT_STS_XFR_CMPLT_MASK) && timeout) { + udelay(1); + timeout--; + } + if (!timeout) + puts("ERROR:arasan_nand_write_buf timedout:Xfer CMPLT\n"); + + writel(readl(&arasan_nand_base->intsts_enr) | + ARASAN_NAND_INT_STS_XFR_CMPLT_MASK, + &arasan_nand_base->intsts_enr); + writel(readl(&arasan_nand_base->intsts_reg) | + ARASAN_NAND_INT_STS_XFR_CMPLT_MASK, + &arasan_nand_base->intsts_reg); +} + +static int arasan_nand_erase(struct arasan_nand_command_format *curr_cmd, + int column, int page_addr, struct mtd_info *mtd) +{ + u32 reg_val, page; + u32 timeout = ARASAN_NAND_POLL_TIMEOUT; + u8 row_addr_cycles; + + writel(ARASAN_NAND_INT_STS_XFR_CMPLT_MASK, + &arasan_nand_base->intsts_enr); + reg_val = readl(&arasan_nand_base->cmd_reg); + reg_val &= ~ARASAN_NAND_CMD_CMD12_MASK; + reg_val |= curr_cmd->cmd1 | + (curr_cmd->cmd2 << ARASAN_NAND_CMD_CMD2_SHIFT); + row_addr_cycles = arasan_nand_get_addrcycle(mtd); + + if (row_addr_cycles == ARASAN_NAND_INVALID_ADDR_CYCL) + return ERR_ADDR_CYCLE; + + reg_val &= ~ARASAN_NAND_CMD_ADDR_CYCL_MASK; + reg_val |= (row_addr_cycles << + ARASAN_NAND_CMD_ADDR_CYCL_SHIFT); + + writel(reg_val, &arasan_nand_base->cmd_reg); + + page = (page_addr << ARASAN_NAND_MEM_ADDR1_PAGE_SHIFT) & + ARASAN_NAND_MEM_ADDR1_PAGE_MASK; + column = page_addr & ARASAN_NAND_MEM_ADDR1_COL_MASK; + writel(page | column, &arasan_nand_base->memadr_reg1); + + reg_val = readl(&arasan_nand_base->memadr_reg2); + reg_val &= ~ARASAN_NAND_MEM_ADDR2_PAGE_MASK; + reg_val |= (page_addr >> ARASAN_NAND_MEM_ADDR1_PAGE_SHIFT); + writel(reg_val, &arasan_nand_base->memadr_reg2); + reg_val = readl(&arasan_nand_base->memadr_reg2); + reg_val &= ~ARASAN_NAND_MEM_ADDR2_CS_MASK; + writel(reg_val, &arasan_nand_base->memadr_reg2); + writel(curr_cmd->pgm, &arasan_nand_base->pgm_reg); + + while (!(readl(&arasan_nand_base->intsts_reg) & + ARASAN_NAND_INT_STS_XFR_CMPLT_MASK) && timeout) { + udelay(1); + timeout--; + } + if (!timeout) { + printf("ERROR:%s timedout:Xfer CMPLT\n", __func__); + return -ETIMEDOUT; + } + + reg_val = readl(&arasan_nand_base->intsts_enr); + writel(reg_val | ARASAN_NAND_INT_STS_XFR_CMPLT_MASK, + &arasan_nand_base->intsts_enr); + reg_val = readl(&arasan_nand_base->intsts_reg); + writel(reg_val | ARASAN_NAND_INT_STS_XFR_CMPLT_MASK, + &arasan_nand_base->intsts_reg); + + return 0; +} + +static int arasan_nand_read_status(struct arasan_nand_command_format *curr_cmd, + int column, int page_addr, struct mtd_info *mtd) +{ + u32 reg_val; + u32 timeout = ARASAN_NAND_POLL_TIMEOUT; + u8 addr_cycles; + + writel(ARASAN_NAND_INT_STS_XFR_CMPLT_MASK, + &arasan_nand_base->intsts_enr); + reg_val = readl(&arasan_nand_base->cmd_reg); + reg_val &= ~ARASAN_NAND_CMD_CMD12_MASK; + reg_val |= curr_cmd->cmd1 | + (curr_cmd->cmd2 << ARASAN_NAND_CMD_CMD2_SHIFT); + addr_cycles = arasan_nand_get_addrcycle(mtd); + + if (addr_cycles == ARASAN_NAND_INVALID_ADDR_CYCL) + return ERR_ADDR_CYCLE; + + reg_val &= ~ARASAN_NAND_CMD_ADDR_CYCL_MASK; + reg_val |= (addr_cycles << + ARASAN_NAND_CMD_ADDR_CYCL_SHIFT); + + writel(reg_val, &arasan_nand_base->cmd_reg); + + reg_val = readl(&arasan_nand_base->pkt_reg); + reg_val &= ~(ARASAN_NAND_PKT_REG_PKT_CNT_MASK | + ARASAN_NAND_PKT_REG_PKT_SIZE_MASK); + reg_val |= (1 << ARASAN_NAND_PKT_REG_PKT_CNT_SHFT) | 1; + writel(reg_val, &arasan_nand_base->pkt_reg); + + reg_val = readl(&arasan_nand_base->memadr_reg2); + reg_val &= ~ARASAN_NAND_MEM_ADDR2_CS_MASK; + writel(reg_val, &arasan_nand_base->memadr_reg2); + + writel(curr_cmd->pgm, &arasan_nand_base->pgm_reg); + while (!(readl(&arasan_nand_base->intsts_reg) & + ARASAN_NAND_INT_STS_XFR_CMPLT_MASK) && timeout) { + udelay(1); + timeout--; + } + + if (!timeout) { + printf("ERROR:%s: timedout:Xfer CMPLT\n", __func__); + return -ETIMEDOUT; + } + + reg_val = readl(&arasan_nand_base->intsts_enr); + writel(reg_val | ARASAN_NAND_INT_STS_XFR_CMPLT_MASK, + &arasan_nand_base->intsts_enr); + reg_val = readl(&arasan_nand_base->intsts_reg); + writel(reg_val | ARASAN_NAND_INT_STS_XFR_CMPLT_MASK, + &arasan_nand_base->intsts_reg); + + return 0; +} + +static int arasan_nand_send_rdcmd(struct arasan_nand_command_format *curr_cmd, + int column, int page_addr, struct mtd_info *mtd) +{ + u32 reg_val, addr_cycles, page; + u8 page_val; + + reg_val = readl(&arasan_nand_base->intsts_enr); + writel(reg_val | ARASAN_NAND_INT_STS_BUF_RD_RDY_MASK, + &arasan_nand_base->intsts_enr); + + reg_val = readl(&arasan_nand_base->cmd_reg); + reg_val &= ~ARASAN_NAND_CMD_CMD12_MASK; + reg_val |= curr_cmd->cmd1 | + (curr_cmd->cmd2 << ARASAN_NAND_CMD_CMD2_SHIFT); + + if (curr_cmd->cmd1 == NAND_CMD_RNDOUT || + curr_cmd->cmd1 == NAND_CMD_READ0) { + reg_val &= ~ARASAN_NAND_CMD_PG_SIZE_MASK; + page_val = arasan_nand_page(mtd); + reg_val |= (page_val << ARASAN_NAND_CMD_PG_SIZE_SHIFT); + } + + reg_val &= ~ARASAN_NAND_CMD_ADDR_CYCL_MASK; + + addr_cycles = arasan_nand_get_addrcycle(mtd); + + if (addr_cycles == ARASAN_NAND_INVALID_ADDR_CYCL) + return ERR_ADDR_CYCLE; + + reg_val |= (addr_cycles << 28); + writel(reg_val, &arasan_nand_base->cmd_reg); + + if (page_addr == -1) + page_addr = 0; + + page = (page_addr << ARASAN_NAND_MEM_ADDR1_PAGE_SHIFT) & + ARASAN_NAND_MEM_ADDR1_PAGE_MASK; + column &= ARASAN_NAND_MEM_ADDR1_COL_MASK; + writel(page | column, &arasan_nand_base->memadr_reg1); + + reg_val = readl(&arasan_nand_base->memadr_reg2); + reg_val &= ~ARASAN_NAND_MEM_ADDR2_PAGE_MASK; + reg_val |= (page_addr >> ARASAN_NAND_MEM_ADDR1_PAGE_SHIFT); + writel(reg_val, &arasan_nand_base->memadr_reg2); + + reg_val = readl(&arasan_nand_base->memadr_reg2); + reg_val &= ~ARASAN_NAND_MEM_ADDR2_CS_MASK; + writel(reg_val, &arasan_nand_base->memadr_reg2); + buf_index = 0; + + return 0; +} + +static void arasan_nand_read_buf(struct mtd_info *mtd, u8 *buf, int size) +{ + u32 reg_val, i; + u32 *bufptr = (u32 *)buf; + u32 timeout = ARASAN_NAND_POLL_TIMEOUT; + + reg_val = readl(&arasan_nand_base->pkt_reg); + reg_val &= ~(ARASAN_NAND_PKT_REG_PKT_CNT_MASK | + ARASAN_NAND_PKT_REG_PKT_SIZE_MASK); + reg_val |= (1 << ARASAN_NAND_PKT_REG_PKT_CNT_SHFT) | size; + writel(reg_val, &arasan_nand_base->pkt_reg); + + writel(curr_cmd->pgm, &arasan_nand_base->pgm_reg); + + while (!(readl(&arasan_nand_base->intsts_reg) & + ARASAN_NAND_INT_STS_BUF_RD_RDY_MASK) && timeout) { + udelay(1); + timeout--; + } + + if (!timeout) + puts("ERROR:arasan_nand_read_buf timedout:Buff RDY\n"); + + reg_val = readl(&arasan_nand_base->intsts_enr); + reg_val |= ARASAN_NAND_INT_STS_XFR_CMPLT_MASK; + writel(reg_val, &arasan_nand_base->intsts_enr); + + writel(reg_val | ARASAN_NAND_INT_STS_BUF_RD_RDY_MASK, + &arasan_nand_base->intsts_enr); + reg_val = readl(&arasan_nand_base->intsts_reg); + writel(reg_val | ARASAN_NAND_INT_STS_BUF_RD_RDY_MASK, + &arasan_nand_base->intsts_reg); + + buf_index = 0; + for (i = 0; i < size / 4; i++) + bufptr[i] = readl(&arasan_nand_base->buf_dataport); + + if (size & 0x03) + bufptr[i] = readl(&arasan_nand_base->buf_dataport); + + timeout = ARASAN_NAND_POLL_TIMEOUT; + + while (!(readl(&arasan_nand_base->intsts_reg) & + ARASAN_NAND_INT_STS_XFR_CMPLT_MASK) && timeout) { + udelay(1); + timeout--; + } + + if (!timeout) + puts("ERROR:arasan_nand_read_buf timedout:Xfer CMPLT\n"); + + reg_val = readl(&arasan_nand_base->intsts_enr); + writel(reg_val | ARASAN_NAND_INT_STS_XFR_CMPLT_MASK, + &arasan_nand_base->intsts_enr); + reg_val = readl(&arasan_nand_base->intsts_reg); + writel(reg_val | ARASAN_NAND_INT_STS_XFR_CMPLT_MASK, + &arasan_nand_base->intsts_reg); +} + +static u8 arasan_nand_read_byte(struct mtd_info *mtd) +{ + struct nand_chip *chip = mtd->priv; + u32 size; + u8 val; + struct nand_onfi_params *p; + + if (buf_index == 0) { + p = &chip->onfi_params; + if (curr_cmd->cmd1 == NAND_CMD_READID) + size = 4; + else if (curr_cmd->cmd1 == NAND_CMD_PARAM) + size = sizeof(struct nand_onfi_params); + else if (curr_cmd->cmd1 == NAND_CMD_RNDOUT) + size = le16_to_cpu(p->ext_param_page_length) * 16; + else if (curr_cmd->cmd1 == NAND_CMD_GET_FEATURES) + size = 4; + else if (curr_cmd->cmd1 == NAND_CMD_STATUS) + return readb(&arasan_nand_base->flash_sts_reg); + else + size = 8; + chip->read_buf(mtd, &buf_data[0], size); + } + + val = *(&buf_data[0] + buf_index); + buf_index++; + + return val; +} + +static void arasan_nand_cmd_function(struct mtd_info *mtd, unsigned int command, + int column, int page_addr) +{ + u32 i, ret = 0; + struct nand_chip *chip = mtd->priv; + struct arasan_nand_info *nand = chip->priv; + + curr_cmd = NULL; + writel(ARASAN_NAND_INT_STS_XFR_CMPLT_MASK, + &arasan_nand_base->intsts_enr); + + if ((command == NAND_CMD_READOOB) && + (mtd->writesize > 512)) { + column += mtd->writesize; + command = NAND_CMD_READ0; + } + + /* Get the command format */ + for (i = 0; (arasan_nand_commands[i].cmd1 != NAND_CMD_NONE || + arasan_nand_commands[i].cmd2 != NAND_CMD_NONE); i++) { + if (command == arasan_nand_commands[i].cmd1) { + curr_cmd = &arasan_nand_commands[i]; + break; + } + } + + if (curr_cmd == NULL) { + printf("Unsupported Command; 0x%x\n", command); + return; + } + + if (curr_cmd->cmd1 == NAND_CMD_RESET) + ret = arasan_nand_reset(curr_cmd); + + if ((curr_cmd->cmd1 == NAND_CMD_READID) || + (curr_cmd->cmd1 == NAND_CMD_PARAM) || + (curr_cmd->cmd1 == NAND_CMD_RNDOUT) || + (curr_cmd->cmd1 == NAND_CMD_GET_FEATURES) || + (curr_cmd->cmd1 == NAND_CMD_READ0)) + ret = arasan_nand_send_rdcmd(curr_cmd, column, page_addr, mtd); + + if ((curr_cmd->cmd1 == NAND_CMD_SET_FEATURES) || + (curr_cmd->cmd1 == NAND_CMD_SEQIN)) { + nand->page = page_addr; + ret = arasan_nand_send_wrcmd(curr_cmd, column, page_addr, mtd); + } + + if (curr_cmd->cmd1 == NAND_CMD_ERASE1) + ret = arasan_nand_erase(curr_cmd, column, page_addr, mtd); + + if (curr_cmd->cmd1 == NAND_CMD_STATUS) + ret = arasan_nand_read_status(curr_cmd, column, page_addr, mtd); + + if (ret != 0) + printf("ERROR:%s:command:0x%x\n", __func__, curr_cmd->cmd1); +} + +static int arasan_nand_ecc_init(struct mtd_info *mtd) +{ + int found = -1; + u32 regval, eccpos_start, i; + struct nand_chip *nand_chip = mtd->priv; + + nand_chip->ecc.mode = NAND_ECC_HW; + nand_chip->ecc.hwctl = NULL; + nand_chip->ecc.read_page = arasan_nand_read_page_hwecc; + nand_chip->ecc.write_page = arasan_nand_write_page_hwecc; + nand_chip->ecc.read_oob = arasan_nand_read_oob; + nand_chip->ecc.write_oob = arasan_nand_write_oob; + + for (i = 0; i < ARRAY_SIZE(ecc_matrix); i++) { + if ((ecc_matrix[i].pagesize == mtd->writesize) && + (ecc_matrix[i].ecc_codeword_size >= + nand_chip->ecc_step_ds)) { + if (ecc_matrix[i].eccbits >= + nand_chip->ecc_strength_ds) { + found = i; + break; + } + found = i; + } + } + + if (found < 0) + return 1; + + regval = ecc_matrix[i].eccaddr | + (ecc_matrix[i].eccsize << ARASAN_NAND_ECC_SIZE_SHIFT) | + (ecc_matrix[i].bch << ARASAN_NAND_ECC_BCH_SHIFT); + writel(regval, &arasan_nand_base->ecc_reg); + + if (ecc_matrix[i].bch) { + regval = readl(&arasan_nand_base->memadr_reg2); + regval &= ~ARASAN_NAND_MEM_ADDR2_BCH_MASK; + regval |= (ecc_matrix[i].bchval << + ARASAN_NAND_MEM_ADDR2_BCH_SHIFT); + writel(regval, &arasan_nand_base->memadr_reg2); + } + + nand_oob.eccbytes = ecc_matrix[i].eccsize; + eccpos_start = mtd->oobsize - nand_oob.eccbytes; + + for (i = 0; i < nand_oob.eccbytes; i++) + nand_oob.eccpos[i] = eccpos_start + i; + + nand_oob.oobfree[0].offset = 2; + nand_oob.oobfree[0].length = eccpos_start - 2; + + nand_chip->ecc.size = ecc_matrix[i].ecc_codeword_size; + nand_chip->ecc.strength = ecc_matrix[i].eccbits; + nand_chip->ecc.bytes = ecc_matrix[i].eccsize; + nand_chip->ecc.layout = &nand_oob; + + return 0; +} + +static int arasan_nand_init(struct nand_chip *nand_chip, int devnum) +{ + struct arasan_nand_info *nand; + struct mtd_info *mtd; + int err = -1; + + nand = calloc(1, sizeof(struct arasan_nand_info)); + if (!nand) { + printf("%s: failed to allocate\n", __func__); + return err; + } + + nand->nand_base = arasan_nand_base; + mtd = &nand_info[0]; + nand_chip->priv = nand; + mtd->priv = nand_chip; + + /* Set the driver entry points for MTD */ + nand_chip->cmdfunc = arasan_nand_cmd_function; + nand_chip->select_chip = arasan_nand_select_chip; + nand_chip->read_byte = arasan_nand_read_byte; + + /* Buffer read/write routines */ + nand_chip->read_buf = arasan_nand_read_buf; + nand_chip->write_buf = arasan_nand_write_buf; + nand_chip->bbt_options = NAND_BBT_USE_FLASH; + + writel(0x0, &arasan_nand_base->cmd_reg); + writel(0x0, &arasan_nand_base->pgm_reg); + + /* first scan to find the device and get the page size */ + if (nand_scan_ident(mtd, 1, NULL)) { + printf("%s: nand_scan_ident failed\n", __func__); + goto fail; + } + + if (arasan_nand_ecc_init(mtd)) { + printf("%s: nand_ecc_init failed\n", __func__); + goto fail; + } + + if (nand_scan_tail(mtd)) { + printf("%s: nand_scan_tail failed\n", __func__); + goto fail; + } + + if (nand_register(devnum)) { + printf("Nand Register Fail\n"); + goto fail; + } + + return 0; +fail: + free(nand); + return err; +} + +void board_nand_init(void) +{ + struct nand_chip *nand = &nand_chip[0]; + + if (arasan_nand_init(nand, 0)) + puts("NAND init failed\n"); +} diff --git a/drivers/mtd/nand/fsl_ifc_spl.c b/drivers/mtd/nand/fsl_ifc_spl.c index fccbfb5129..cbeb74a5bb 100644 --- a/drivers/mtd/nand/fsl_ifc_spl.c +++ b/drivers/mtd/nand/fsl_ifc_spl.c @@ -236,7 +236,7 @@ int nand_spl_load_image(uint32_t offs, unsigned int uboot_size, void *vdst) /* * Main entrypoint for NAND Boot. It's necessary that SDRAM is already - * configured and available since this code loads the main U-boot image + * configured and available since this code loads the main U-Boot image * from NAND into SDRAM and starts from there. */ void nand_boot(void) diff --git a/drivers/mtd/nand/lpc32xx_nand_slc.c b/drivers/mtd/nand/lpc32xx_nand_slc.c index 2e5f139606..4e1be36654 100644 --- a/drivers/mtd/nand/lpc32xx_nand_slc.c +++ b/drivers/mtd/nand/lpc32xx_nand_slc.c @@ -516,7 +516,7 @@ static int lpc32xx_write_page_hwecc(struct mtd_info *mtd, /* * LPC32xx has only one SLC NAND controller, don't utilize * CONFIG_SYS_NAND_SELF_INIT to be able to reuse this function - * both in SPL NAND and U-boot images. + * both in SPL NAND and U-Boot images. */ int board_nand_init(struct nand_chip *lpc32xx_chip) { diff --git a/drivers/mtd/nand/mxc_nand_spl.c b/drivers/mtd/nand/mxc_nand_spl.c index 69b736a848..6ac2c96eeb 100644 --- a/drivers/mtd/nand/mxc_nand_spl.c +++ b/drivers/mtd/nand/mxc_nand_spl.c @@ -337,7 +337,7 @@ void nand_boot(void) if (!nand_spl_load_image(CONFIG_SYS_NAND_U_BOOT_OFFS, CONFIG_SYS_NAND_U_BOOT_SIZE, (uchar *)CONFIG_SYS_NAND_U_BOOT_DST)) { - /* Copy from NAND successful, start U-boot */ + /* Copy from NAND successful, start U-Boot */ uboot = (void *)CONFIG_SYS_NAND_U_BOOT_START; uboot(); } else { diff --git a/drivers/mtd/nand/mxs_nand.c b/drivers/mtd/nand/mxs_nand.c index ba019a0763..b5bbd889ff 100644 --- a/drivers/mtd/nand/mxs_nand.c +++ b/drivers/mtd/nand/mxs_nand.c @@ -1090,24 +1090,29 @@ int mxs_nand_init(struct mxs_nand_info *info) (struct mxs_gpmi_regs *)MXS_GPMI_BASE; struct mxs_bch_regs *bch_regs = (struct mxs_bch_regs *)MXS_BCH_BASE; - int i = 0, j; + int i = 0, j, ret = 0; info->desc = malloc(sizeof(struct mxs_dma_desc *) * MXS_NAND_DMA_DESCRIPTOR_COUNT); - if (!info->desc) + if (!info->desc) { + ret = -ENOMEM; goto err1; + } /* Allocate the DMA descriptors. */ for (i = 0; i < MXS_NAND_DMA_DESCRIPTOR_COUNT; i++) { info->desc[i] = mxs_dma_desc_alloc(); - if (!info->desc[i]) + if (!info->desc[i]) { + ret = -ENOMEM; goto err2; + } } /* Init the DMA controller. */ for (j = MXS_DMA_CHANNEL_AHB_APBH_GPMI0; j <= MXS_DMA_CHANNEL_AHB_APBH_GPMI7; j++) { - if (mxs_dma_init_channel(j)) + ret = mxs_dma_init_channel(j); + if (ret) goto err3; } @@ -1127,15 +1132,16 @@ int mxs_nand_init(struct mxs_nand_info *info) return 0; err3: - for (--j; j >= 0; j--) + for (--j; j >= MXS_DMA_CHANNEL_AHB_APBH_GPMI0; j--) mxs_dma_release(j); err2: - free(info->desc); -err1: for (--i; i >= 0; i--) mxs_dma_desc_free(info->desc[i]); - printf("MXS NAND: Unable to allocate DMA descriptors\n"); - return -ENOMEM; + free(info->desc); +err1: + if (ret == -ENOMEM) + printf("MXS NAND: Unable to allocate DMA descriptors\n"); + return ret; } /*! diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index f65b499beb..939274204e 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c @@ -1486,8 +1486,8 @@ static int alloc_nand_resource(struct pxa3xx_nand_info *info) info->variant = pxa3xx_nand_get_variant(); for (cs = 0; cs < pdata->num_cs; cs++) { mtd = &nand_info[cs]; - chip = (struct nand_chip *)info + - sizeof(struct pxa3xx_nand_host); + chip = (struct nand_chip *) + ((u8 *)&info[1] + sizeof(*host) * cs); host = (struct pxa3xx_nand_host *)chip; info->host[cs] = host; host->mtd = mtd; @@ -1600,19 +1600,12 @@ void board_nand_init(void) struct pxa3xx_nand_host *host; int ret; - info = kzalloc(sizeof(*info) + (sizeof(struct mtd_info) + - sizeof(*host)) * - CONFIG_SYS_MAX_NAND_DEVICE, GFP_KERNEL); + info = kzalloc(sizeof(*info) + + sizeof(*host) * CONFIG_SYS_MAX_NAND_DEVICE, + GFP_KERNEL); if (!info) return; - /* - * If CONFIG_SYS_NAND_SELF_INIT is defined, each driver is responsible - * for instantiating struct nand_chip, while drivers/mtd/nand/nand.c - * still provides a "struct mtd_info nand_info" instance. - */ - info->host[0]->mtd = &nand_info[0]; - ret = pxa3xx_nand_probe(info); if (ret) return; diff --git a/drivers/net/at91_emac.c b/drivers/net/at91_emac.c index 26595929c5..9151600190 100644 --- a/drivers/net/at91_emac.c +++ b/drivers/net/at91_emac.c @@ -12,7 +12,7 @@ #include <asm/io.h> #include <asm/arch/hardware.h> #include <asm/arch/at91_emac.h> -#include <asm/arch/at91_pmc.h> +#include <asm/arch/clk.h> #include <asm/arch/at91_pio.h> #include <net.h> #include <netdev.h> @@ -321,7 +321,6 @@ static int at91emac_init(struct eth_device *netdev, bd_t *bd) emac_device *dev; at91_emac_t *emac; at91_pio_t *pio = (at91_pio_t *) ATMEL_BASE_PIO; - at91_pmc_t *pmc = (at91_pmc_t *) ATMEL_BASE_PMC; emac = (at91_emac_t *) netdev->iobase; dev = (emac_device *) netdev->priv; @@ -347,7 +346,8 @@ static int at91emac_init(struct eth_device *netdev, bd_t *bd) writel(value, &pio->piob.pdr); writel(value, &pio->piob.bsr); - writel(1 << ATMEL_ID_EMAC, &pmc->pcer); + at91_periph_clk_enable(ATMEL_ID_EMAC); + writel(readl(&emac->ctl) | AT91_EMAC_CTL_CSR, &emac->ctl); /* Init Ethernet buffers */ @@ -452,10 +452,10 @@ static int at91emac_recv(struct eth_device *netdev) static int at91emac_write_hwaddr(struct eth_device *netdev) { at91_emac_t *emac; - at91_pmc_t *pmc = (at91_pmc_t *) ATMEL_BASE_PMC; emac = (at91_emac_t *) netdev->iobase; - writel(1 << ATMEL_ID_EMAC, &pmc->pcer); + at91_periph_clk_enable(ATMEL_ID_EMAC); + debug_cond(DEBUG_AT91EMAC, "init MAC-ADDR %02x:%02x:%02x:%02x:%02x:%02x\n", netdev->enetaddr[5], netdev->enetaddr[4], netdev->enetaddr[3], diff --git a/drivers/net/davinci_emac.c b/drivers/net/davinci_emac.c index 92c3dcae3c..b030498402 100644 --- a/drivers/net/davinci_emac.c +++ b/drivers/net/davinci_emac.c @@ -459,11 +459,11 @@ static int davinci_eth_open(struct eth_device *dev, bd_t *bis) /* Set DMA 8 TX / 8 RX Head pointers to 0 */ addr = &adap_emac->TX0HDP; - for(cnt = 0; cnt < 16; cnt++) + for (cnt = 0; cnt < 8; cnt++) writel(0, addr++); addr = &adap_emac->RX0HDP; - for(cnt = 0; cnt < 16; cnt++) + for (cnt = 0; cnt < 8; cnt++) writel(0, addr++); /* Clear Statistics (do this before setting MacControl register) */ @@ -692,8 +692,10 @@ static int davinci_eth_rcv_packet (struct eth_device *dev) davinci_invalidate_rx_descs(); rx_curr_desc = emac_rx_active_head; + if (!rx_curr_desc) + return 0; status = rx_curr_desc->pkt_flag_len; - if ((rx_curr_desc) && ((status & EMAC_CPPI_OWNERSHIP_BIT) == 0)) { + if ((status & EMAC_CPPI_OWNERSHIP_BIT) == 0) { if (status & EMAC_CPPI_RX_ERROR_FRAME) { /* Error in packet - discard it and requeue desc */ printf ("WARN: emac_rcv_pkt: Error in packet\n"); diff --git a/drivers/net/designware.c b/drivers/net/designware.c index 77b98c94c0..ca58f34f13 100644 --- a/drivers/net/designware.c +++ b/drivers/net/designware.c @@ -591,11 +591,9 @@ static int designware_eth_probe(struct udevice *dev) * or via a PCI bridge, fill in platdata before we probe the hardware. */ if (device_is_on_pci_bus(dev)) { - pci_dev_t bdf = dm_pci_get_bdf(dev); - dm_pci_read_config32(dev, PCI_BASE_ADDRESS_0, &iobase); iobase &= PCI_BASE_ADDRESS_MEM_MASK; - iobase = pci_mem_to_phys(bdf, iobase); + iobase = dm_pci_mem_to_phys(dev, iobase); pdata->iobase = iobase; pdata->phy_interface = PHY_INTERFACE_MODE_RMII; diff --git a/drivers/net/e1000.c b/drivers/net/e1000.c index 70fc02ee5c..196989b386 100644 --- a/drivers/net/e1000.c +++ b/drivers/net/e1000.c @@ -38,8 +38,13 @@ tested on both gig copper and gig fiber boards #define TOUT_LOOP 100000 +#ifdef CONFIG_DM_ETH +#define virt_to_bus(devno, v) dm_pci_virt_to_mem(devno, (void *) (v)) +#define bus_to_phys(devno, a) dm_pci_mem_to_phys(devno, a) +#else #define virt_to_bus(devno, v) pci_virt_to_mem(devno, (void *) (v)) #define bus_to_phys(devno, a) pci_mem_to_phys(devno, a) +#endif #define E1000_DEFAULT_PCI_PBA 0x00000030 #define E1000_DEFAULT_PCIE_PBA 0x000a0026 @@ -1395,8 +1400,13 @@ e1000_reset_hw(struct e1000_hw *hw) /* For 82542 (rev 2.0), disable MWI before issuing a device reset */ if (hw->mac_type == e1000_82542_rev2_0) { DEBUGOUT("Disabling MWI on 82542 rev 2.0\n"); +#ifdef CONFIG_DM_ETH + dm_pci_write_config16(hw->pdev, PCI_COMMAND, + hw->pci_cmd_word & ~PCI_COMMAND_INVALIDATE); +#else pci_write_config_word(hw->pdev, PCI_COMMAND, hw->pci_cmd_word & ~PCI_COMMAND_INVALIDATE); +#endif } /* Clear interrupt mask to stop board from generating interrupts */ @@ -1469,7 +1479,11 @@ e1000_reset_hw(struct e1000_hw *hw) /* If MWI was previously enabled, reenable it. */ if (hw->mac_type == e1000_82542_rev2_0) { +#ifdef CONFIG_DM_ETH + dm_pci_write_config16(hw->pdev, PCI_COMMAND, hw->pci_cmd_word); +#else pci_write_config_word(hw->pdev, PCI_COMMAND, hw->pci_cmd_word); +#endif } if (hw->mac_type != e1000_igb) E1000_WRITE_REG(hw, PBA, pba); @@ -1655,9 +1669,15 @@ e1000_init_hw(struct e1000_hw *hw, unsigned char enetaddr[6]) /* For 82542 (rev 2.0), disable MWI and put the receiver into reset */ if (hw->mac_type == e1000_82542_rev2_0) { DEBUGOUT("Disabling MWI on 82542 rev 2.0\n"); +#ifdef CONFIG_DM_ETH + dm_pci_write_config16(hw->pdev, PCI_COMMAND, + hw-> + pci_cmd_word & ~PCI_COMMAND_INVALIDATE); +#else pci_write_config_word(hw->pdev, PCI_COMMAND, hw-> pci_cmd_word & ~PCI_COMMAND_INVALIDATE); +#endif E1000_WRITE_REG(hw, RCTL, E1000_RCTL_RST); E1000_WRITE_FLUSH(hw); mdelay(5); @@ -1673,7 +1693,11 @@ e1000_init_hw(struct e1000_hw *hw, unsigned char enetaddr[6]) E1000_WRITE_REG(hw, RCTL, 0); E1000_WRITE_FLUSH(hw); mdelay(1); +#ifdef CONFIG_DM_ETH + dm_pci_write_config16(hw->pdev, PCI_COMMAND, hw->pci_cmd_word); +#else pci_write_config_word(hw->pdev, PCI_COMMAND, hw->pci_cmd_word); +#endif } /* Zero out the Multicast HASH table */ @@ -1696,10 +1720,17 @@ e1000_init_hw(struct e1000_hw *hw, unsigned char enetaddr[6]) default: /* Workaround for PCI-X problem when BIOS sets MMRBC incorrectly. */ if (hw->bus_type == e1000_bus_type_pcix) { +#ifdef CONFIG_DM_ETH + dm_pci_read_config16(hw->pdev, PCIX_COMMAND_REGISTER, + &pcix_cmd_word); + dm_pci_read_config16(hw->pdev, PCIX_STATUS_REGISTER_HI, + &pcix_stat_hi_word); +#else pci_read_config_word(hw->pdev, PCIX_COMMAND_REGISTER, &pcix_cmd_word); pci_read_config_word(hw->pdev, PCIX_STATUS_REGISTER_HI, &pcix_stat_hi_word); +#endif cmd_mmrbc = (pcix_cmd_word & PCIX_COMMAND_MMRBC_MASK) >> PCIX_COMMAND_MMRBC_SHIFT; @@ -1711,8 +1742,13 @@ e1000_init_hw(struct e1000_hw *hw, unsigned char enetaddr[6]) if (cmd_mmrbc > stat_mmrbc) { pcix_cmd_word &= ~PCIX_COMMAND_MMRBC_MASK; pcix_cmd_word |= stat_mmrbc << PCIX_COMMAND_MMRBC_SHIFT; +#ifdef CONFIG_DM_ETH + dm_pci_write_config16(hw->pdev, PCIX_COMMAND_REGISTER, + pcix_cmd_word); +#else pci_write_config_word(hw->pdev, PCIX_COMMAND_REGISTER, pcix_cmd_word); +#endif } } break; @@ -4809,6 +4845,16 @@ e1000_sw_init(struct e1000_hw *hw) int result; /* PCI config space info */ +#ifdef CONFIG_DM_ETH + dm_pci_read_config16(hw->pdev, PCI_VENDOR_ID, &hw->vendor_id); + dm_pci_read_config16(hw->pdev, PCI_DEVICE_ID, &hw->device_id); + dm_pci_read_config16(hw->pdev, PCI_SUBSYSTEM_VENDOR_ID, + &hw->subsystem_vendor_id); + dm_pci_read_config16(hw->pdev, PCI_SUBSYSTEM_ID, &hw->subsystem_id); + + dm_pci_read_config8(hw->pdev, PCI_REVISION_ID, &hw->revision_id); + dm_pci_read_config16(hw->pdev, PCI_COMMAND, &hw->pci_cmd_word); +#else pci_read_config_word(hw->pdev, PCI_VENDOR_ID, &hw->vendor_id); pci_read_config_word(hw->pdev, PCI_DEVICE_ID, &hw->device_id); pci_read_config_word(hw->pdev, PCI_SUBSYSTEM_VENDOR_ID, @@ -4817,6 +4863,7 @@ e1000_sw_init(struct e1000_hw *hw) pci_read_config_byte(hw->pdev, PCI_REVISION_ID, &hw->revision_id); pci_read_config_word(hw->pdev, PCI_COMMAND, &hw->pci_cmd_word); +#endif /* identify the MAC */ result = e1000_set_mac_type(hw); @@ -5232,25 +5279,46 @@ void e1000_get_bus_type(struct e1000_hw *hw) static LIST_HEAD(e1000_hw_list); #endif +#ifdef CONFIG_DM_ETH +static int e1000_init_one(struct e1000_hw *hw, int cardnum, + struct udevice *devno, unsigned char enetaddr[6]) +#else static int e1000_init_one(struct e1000_hw *hw, int cardnum, pci_dev_t devno, unsigned char enetaddr[6]) +#endif { u32 val; /* Assign the passed-in values */ +#ifdef CONFIG_DM_ETH hw->pdev = devno; +#else + hw->pdev = devno; +#endif hw->cardnum = cardnum; /* Print a debug message with the IO base address */ +#ifdef CONFIG_DM_ETH + dm_pci_read_config32(devno, PCI_BASE_ADDRESS_0, &val); +#else pci_read_config_dword(devno, PCI_BASE_ADDRESS_0, &val); +#endif E1000_DBG(hw, "iobase 0x%08x\n", val & 0xfffffff0); /* Try to enable I/O accesses and bus-mastering */ val = PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER; +#ifdef CONFIG_DM_ETH + dm_pci_write_config32(devno, PCI_COMMAND, val); +#else pci_write_config_dword(devno, PCI_COMMAND, val); +#endif /* Make sure it worked */ +#ifdef CONFIG_DM_ETH + dm_pci_read_config32(devno, PCI_COMMAND, &val); +#else pci_read_config_dword(devno, PCI_COMMAND, &val); +#endif if (!(val & PCI_COMMAND_MEMORY)) { E1000_ERR(hw, "Can't enable I/O memory\n"); return -ENOSPC; @@ -5269,8 +5337,13 @@ static int e1000_init_one(struct e1000_hw *hw, int cardnum, pci_dev_t devno, #ifndef CONFIG_E1000_NO_NVM hw->eeprom_semaphore_present = true; #endif +#ifdef CONFIG_DM_ETH + hw->hw_addr = dm_pci_map_bar(devno, PCI_BASE_ADDRESS_0, + PCI_REGION_MEM); +#else hw->hw_addr = pci_map_bar(devno, PCI_BASE_ADDRESS_0, PCI_REGION_MEM); +#endif hw->mac_type = e1000_undefined; /* MAC and Phy settings */ @@ -5380,7 +5453,7 @@ e1000_initialize(bd_t * bis) for (i = 0; (devno = pci_find_devices(e1000_supported, i)) >= 0; i++) { /* * These will never get freed due to errors, this allows us to - * perform SPI EEPROM programming from U-boot, for example. + * perform SPI EEPROM programming from U-Boot, for example. */ struct eth_device *nic = malloc(sizeof(*nic)); struct e1000_hw *hw = malloc(sizeof(*hw)); @@ -5554,7 +5627,7 @@ static int e1000_eth_probe(struct udevice *dev) hw->name = dev->name; ret = e1000_init_one(hw, trailing_strtol(dev->name), - dm_pci_get_bdf(dev), plat->enetaddr); + dev, plat->enetaddr); if (ret < 0) { printf(pr_fmt("failed to initialize card: %d\n"), ret); return ret; diff --git a/drivers/net/e1000.h b/drivers/net/e1000.h index e46edcd4e1..fcb7df0d83 100644 --- a/drivers/net/e1000.h +++ b/drivers/net/e1000.h @@ -1084,7 +1084,11 @@ struct e1000_hw { #endif unsigned int cardnum; +#ifdef CONFIG_DM_ETH + struct udevice *pdev; +#else pci_dev_t pdev; +#endif uint8_t *hw_addr; e1000_mac_type mac_type; e1000_phy_type phy_type; diff --git a/drivers/net/fsl-mc/mc.c b/drivers/net/fsl-mc/mc.c index fdbd584186..53c4966c33 100644 --- a/drivers/net/fsl-mc/mc.c +++ b/drivers/net/fsl-mc/mc.c @@ -455,7 +455,7 @@ int mc_init(u64 mc_fw_addr, u64 mc_dpc_addr) /* * Management Complex cores should be held at reset out of POR. - * U-boot should be the first software to touch MC. To be safe, + * U-Boot should be the first software to touch MC. To be safe, * we reset all cores again by setting GCR1 to 0. It doesn't do * anything if they are held at reset. After we setup the firmware * we kick off MC by deasserting the reset bit for core 0, and diff --git a/drivers/net/keystone_net.c b/drivers/net/keystone_net.c index 209fae94a7..6b28df0f96 100644 --- a/drivers/net/keystone_net.c +++ b/drivers/net/keystone_net.c @@ -10,6 +10,8 @@ #include <command.h> #include <console.h> +#include <dm.h> + #include <net.h> #include <phy.h> #include <errno.h> @@ -18,10 +20,15 @@ #include <asm/ti-common/keystone_nav.h> #include <asm/ti-common/keystone_net.h> #include <asm/ti-common/keystone_serdes.h> +#include <asm/arch/psc_defs.h> + +DECLARE_GLOBAL_DATA_PTR; +#ifndef CONFIG_DM_ETH unsigned int emac_open; static struct mii_dev *mdio_bus; static unsigned int sys_has_mdio = 1; +#endif #ifdef KEYSTONE2_EMAC_GIG_ENABLE #define emac_gigabit_enable(x) keystone2_eth_gigabit_enable(x) @@ -36,40 +43,74 @@ static unsigned int sys_has_mdio = 1; static u8 rx_buffs[RX_BUFF_NUMS * RX_BUFF_LEN] __aligned(16); +#ifndef CONFIG_DM_ETH struct rx_buff_desc net_rx_buffs = { .buff_ptr = rx_buffs, .num_buffs = RX_BUFF_NUMS, .buff_len = RX_BUFF_LEN, .rx_flow = 22, }; - -#ifndef CONFIG_SOC_K2G -static void keystone2_net_serdes_setup(void); #endif -int keystone2_eth_read_mac_addr(struct eth_device *dev) -{ - struct eth_priv_t *eth_priv; - u32 maca = 0; - u32 macb = 0; +#ifdef CONFIG_DM_ETH - eth_priv = (struct eth_priv_t *)dev->priv; +enum link_type { + LINK_TYPE_MAC_TO_MAC_AUTO = 0, + LINK_TYPE_MAC_TO_PHY_MODE = 1, + LINK_TYPE_MAC_TO_MAC_FORCED_MODE = 2, + LINK_TYPE_MAC_TO_FIBRE_MODE = 3, + LINK_TYPE_MAC_TO_PHY_NO_MDIO_MODE = 4, + LINK_TYPE_10G_MAC_TO_PHY_MODE = 10, + LINK_TYPE_10G_MAC_TO_MAC_FORCED_MODE = 11, +}; - /* Read the e-fuse mac address */ - if (eth_priv->slave_port == 1) { - maca = __raw_readl(MAC_ID_BASE_ADDR); - macb = __raw_readl(MAC_ID_BASE_ADDR + 4); - } +#define mac_hi(mac) (((mac)[0] << 0) | ((mac)[1] << 8) | \ + ((mac)[2] << 16) | ((mac)[3] << 24)) +#define mac_lo(mac) (((mac)[4] << 0) | ((mac)[5] << 8)) - dev->enetaddr[0] = (macb >> 8) & 0xff; - dev->enetaddr[1] = (macb >> 0) & 0xff; - dev->enetaddr[2] = (maca >> 24) & 0xff; - dev->enetaddr[3] = (maca >> 16) & 0xff; - dev->enetaddr[4] = (maca >> 8) & 0xff; - dev->enetaddr[5] = (maca >> 0) & 0xff; +#ifdef CONFIG_KSNET_NETCP_V1_0 - return 0; -} +#define EMAC_EMACSW_BASE_OFS 0x90800 +#define EMAC_EMACSW_PORT_BASE_OFS (EMAC_EMACSW_BASE_OFS + 0x60) + +/* CPSW Switch slave registers */ +#define CPGMACSL_REG_SA_LO 0x10 +#define CPGMACSL_REG_SA_HI 0x14 + +#define DEVICE_EMACSW_BASE(base, x) ((base) + EMAC_EMACSW_PORT_BASE_OFS + \ + (x) * 0x30) + +#elif defined CONFIG_KSNET_NETCP_V1_5 + +#define EMAC_EMACSW_PORT_BASE_OFS 0x222000 + +/* CPSW Switch slave registers */ +#define CPGMACSL_REG_SA_LO 0x308 +#define CPGMACSL_REG_SA_HI 0x30c + +#define DEVICE_EMACSW_BASE(base, x) ((base) + EMAC_EMACSW_PORT_BASE_OFS + \ + (x) * 0x1000) + +#endif + + +struct ks2_eth_priv { + struct udevice *dev; + struct phy_device *phydev; + struct mii_dev *mdio_bus; + int phy_addr; + phy_interface_t phy_if; + int sgmii_link_type; + void *mdio_base; + struct rx_buff_desc net_rx_buffs; + struct pktdma_cfg *netcp_pktdma; + void *hd; + int slave_port; + enum link_type link_type; + bool emac_open; + bool has_mdio; +}; +#endif /* MDIO */ @@ -140,6 +181,7 @@ static int keystone2_mdio_write(struct mii_dev *bus, return 0; } +#ifndef CONFIG_DM_ETH static void __attribute__((unused)) keystone2_eth_gigabit_enable(struct eth_device *dev) { @@ -163,6 +205,31 @@ static void __attribute__((unused)) EMAC_MACCONTROL_GIGFORCE | EMAC_MACCONTROL_GIGABIT_ENABLE, DEVICE_EMACSL_BASE(eth_priv->slave_port - 1) + CPGMACSL_REG_CTL); } +#else +static void __attribute__((unused)) + keystone2_eth_gigabit_enable(struct udevice *dev) +{ + struct ks2_eth_priv *priv = dev_get_priv(dev); + u_int16_t data; + + if (priv->has_mdio) { + data = keystone2_mdio_read(priv->mdio_bus, priv->phy_addr, + MDIO_DEVAD_NONE, 0); + /* speed selection MSB */ + if (!(data & (1 << 6))) + return; + } + + /* + * Check if link detected is giga-bit + * If Gigabit mode detected, enable gigbit in MAC + */ + writel(readl(DEVICE_EMACSL_BASE(priv->slave_port - 1) + + CPGMACSL_REG_CTL) | + EMAC_MACCONTROL_GIGFORCE | EMAC_MACCONTROL_GIGABIT_ENABLE, + DEVICE_EMACSL_BASE(priv->slave_port - 1) + CPGMACSL_REG_CTL); +} +#endif #ifdef CONFIG_SOC_K2G int keystone_rgmii_config(struct phy_device *phy_dev) @@ -401,6 +468,58 @@ int ethss_stop(void) return 0; } +struct ks2_serdes ks2_serdes_sgmii_156p25mhz = { + .clk = SERDES_CLOCK_156P25M, + .rate = SERDES_RATE_5G, + .rate_mode = SERDES_QUARTER_RATE, + .intf = SERDES_PHY_SGMII, + .loopback = 0, +}; + +#ifndef CONFIG_SOC_K2G +static void keystone2_net_serdes_setup(void) +{ + ks2_serdes_init(CONFIG_KSNET_SERDES_SGMII_BASE, + &ks2_serdes_sgmii_156p25mhz, + CONFIG_KSNET_SERDES_LANES_PER_SGMII); + +#if defined(CONFIG_SOC_K2E) || defined(CONFIG_SOC_K2L) + ks2_serdes_init(CONFIG_KSNET_SERDES_SGMII2_BASE, + &ks2_serdes_sgmii_156p25mhz, + CONFIG_KSNET_SERDES_LANES_PER_SGMII); +#endif + + /* wait till setup */ + udelay(5000); +} +#endif + +#ifndef CONFIG_DM_ETH + +int keystone2_eth_read_mac_addr(struct eth_device *dev) +{ + struct eth_priv_t *eth_priv; + u32 maca = 0; + u32 macb = 0; + + eth_priv = (struct eth_priv_t *)dev->priv; + + /* Read the e-fuse mac address */ + if (eth_priv->slave_port == 1) { + maca = __raw_readl(MAC_ID_BASE_ADDR); + macb = __raw_readl(MAC_ID_BASE_ADDR + 4); + } + + dev->enetaddr[0] = (macb >> 8) & 0xff; + dev->enetaddr[1] = (macb >> 0) & 0xff; + dev->enetaddr[2] = (maca >> 24) & 0xff; + dev->enetaddr[3] = (maca >> 16) & 0xff; + dev->enetaddr[4] = (maca >> 8) & 0xff; + dev->enetaddr[5] = (maca >> 0) & 0xff; + + return 0; +} + int32_t cpmac_drv_send(u32 *buffer, int num_bytes, int slave_port_num) { if (num_bytes < EMAC_MIN_ETHERNET_PKT_SIZE) @@ -556,6 +675,7 @@ int keystone2_emac_initialize(struct eth_priv_t *eth_priv) int res; struct eth_device *dev; struct phy_device *phy_dev; + struct mdio_regs *adap_mdio = (struct mdio_regs *)EMAC_MDIO_BASE_ADDR; dev = malloc(sizeof(struct eth_device)); if (dev == NULL) @@ -612,28 +732,301 @@ int keystone2_emac_initialize(struct eth_priv_t *eth_priv) return 0; } -struct ks2_serdes ks2_serdes_sgmii_156p25mhz = { - .clk = SERDES_CLOCK_156P25M, - .rate = SERDES_RATE_5G, - .rate_mode = SERDES_QUARTER_RATE, - .intf = SERDES_PHY_SGMII, - .loopback = 0, -}; +#else -#ifndef CONFIG_SOC_K2G -static void keystone2_net_serdes_setup(void) +static int ks2_eth_start(struct udevice *dev) { - ks2_serdes_init(CONFIG_KSNET_SERDES_SGMII_BASE, - &ks2_serdes_sgmii_156p25mhz, - CONFIG_KSNET_SERDES_LANES_PER_SGMII); + struct ks2_eth_priv *priv = dev_get_priv(dev); -#if defined(CONFIG_SOC_K2E) || defined(CONFIG_SOC_K2L) - ks2_serdes_init(CONFIG_KSNET_SERDES_SGMII2_BASE, - &ks2_serdes_sgmii_156p25mhz, - CONFIG_KSNET_SERDES_LANES_PER_SGMII); +#ifdef CONFIG_SOC_K2G + keystone_rgmii_config(priv->phydev); +#else + keystone_sgmii_config(priv->phydev, priv->slave_port - 1, + priv->sgmii_link_type); #endif - /* wait till setup */ - udelay(5000); + udelay(10000); + + /* On chip switch configuration */ + ethss_config(target_get_switch_ctl(), SWITCH_MAX_PKT_SIZE); + + qm_init(); + + if (ksnav_init(priv->netcp_pktdma, &priv->net_rx_buffs)) { + error("ksnav_init failed\n"); + goto err_knav_init; + } + + /* + * Streaming switch configuration. If not present this + * statement is defined to void in target.h. + * If present this is usually defined to a series of register writes + */ + hw_config_streaming_switch(); + + if (priv->has_mdio) { + phy_startup(priv->phydev); + if (priv->phydev->link == 0) { + error("phy startup failed\n"); + goto err_phy_start; + } + } + + emac_gigabit_enable(dev); + + ethss_start(); + + priv->emac_open = true; + + return 0; + +err_phy_start: + ksnav_close(priv->netcp_pktdma); +err_knav_init: + qm_close(); + + return -EFAULT; +} + +static int ks2_eth_send(struct udevice *dev, void *packet, int length) +{ + struct ks2_eth_priv *priv = dev_get_priv(dev); + + genphy_update_link(priv->phydev); + if (priv->phydev->link == 0) + return -1; + + if (length < EMAC_MIN_ETHERNET_PKT_SIZE) + length = EMAC_MIN_ETHERNET_PKT_SIZE; + + return ksnav_send(priv->netcp_pktdma, (u32 *)packet, + length, (priv->slave_port) << 16); +} + +static int ks2_eth_recv(struct udevice *dev, int flags, uchar **packetp) +{ + struct ks2_eth_priv *priv = dev_get_priv(dev); + int pkt_size; + u32 *pkt = NULL; + + priv->hd = ksnav_recv(priv->netcp_pktdma, &pkt, &pkt_size); + if (priv->hd == NULL) + return -EAGAIN; + + *packetp = (uchar *)pkt; + + return pkt_size; +} + +static int ks2_eth_free_pkt(struct udevice *dev, uchar *packet, + int length) +{ + struct ks2_eth_priv *priv = dev_get_priv(dev); + + ksnav_release_rxhd(priv->netcp_pktdma, priv->hd); + + return 0; +} + +static void ks2_eth_stop(struct udevice *dev) +{ + struct ks2_eth_priv *priv = dev_get_priv(dev); + + if (!priv->emac_open) + return; + ethss_stop(); + + ksnav_close(priv->netcp_pktdma); + qm_close(); + phy_shutdown(priv->phydev); + priv->emac_open = false; +} + +int ks2_eth_read_rom_hwaddr(struct udevice *dev) +{ + struct ks2_eth_priv *priv = dev_get_priv(dev); + struct eth_pdata *pdata = dev_get_platdata(dev); + u32 maca = 0; + u32 macb = 0; + + /* Read the e-fuse mac address */ + if (priv->slave_port == 1) { + maca = __raw_readl(MAC_ID_BASE_ADDR); + macb = __raw_readl(MAC_ID_BASE_ADDR + 4); + } + + pdata->enetaddr[0] = (macb >> 8) & 0xff; + pdata->enetaddr[1] = (macb >> 0) & 0xff; + pdata->enetaddr[2] = (maca >> 24) & 0xff; + pdata->enetaddr[3] = (maca >> 16) & 0xff; + pdata->enetaddr[4] = (maca >> 8) & 0xff; + pdata->enetaddr[5] = (maca >> 0) & 0xff; + + return 0; +} + +int ks2_eth_write_hwaddr(struct udevice *dev) +{ + struct ks2_eth_priv *priv = dev_get_priv(dev); + struct eth_pdata *pdata = dev_get_platdata(dev); + + writel(mac_hi(pdata->enetaddr), + DEVICE_EMACSW_BASE(pdata->iobase, priv->slave_port - 1) + + CPGMACSL_REG_SA_HI); + writel(mac_lo(pdata->enetaddr), + DEVICE_EMACSW_BASE(pdata->iobase, priv->slave_port - 1) + + CPGMACSL_REG_SA_LO); + + return 0; +} + +static int ks2_eth_probe(struct udevice *dev) +{ + struct ks2_eth_priv *priv = dev_get_priv(dev); + struct mii_dev *mdio_bus; + int ret; + + priv->dev = dev; + + /* These clock enables has to be moved to common location */ + if (cpu_is_k2g()) + writel(KS2_ETHERNET_RGMII, KS2_ETHERNET_CFG); + + /* By default, select PA PLL clock as PA clock source */ +#ifndef CONFIG_SOC_K2G + if (psc_enable_module(KS2_LPSC_PA)) + return -EACCES; +#endif + if (psc_enable_module(KS2_LPSC_CPGMAC)) + return -EACCES; + if (psc_enable_module(KS2_LPSC_CRYPTO)) + return -EACCES; + + if (cpu_is_k2e() || cpu_is_k2l()) + pll_pa_clk_sel(); + + + priv->net_rx_buffs.buff_ptr = rx_buffs, + priv->net_rx_buffs.num_buffs = RX_BUFF_NUMS, + priv->net_rx_buffs.buff_len = RX_BUFF_LEN, + + /* Register MDIO bus */ + mdio_bus = mdio_alloc(); + if (!mdio_bus) { + error("MDIO alloc failed\n"); + return -ENOMEM; + } + priv->mdio_bus = mdio_bus; + mdio_bus->read = keystone2_mdio_read; + mdio_bus->write = keystone2_mdio_write; + mdio_bus->reset = keystone2_mdio_reset; + mdio_bus->priv = priv->mdio_base; + sprintf(mdio_bus->name, "ethernet-mdio"); + + ret = mdio_register(mdio_bus); + if (ret) { + error("MDIO bus register failed\n"); + return ret; + } + +#ifndef CONFIG_SOC_K2G + keystone2_net_serdes_setup(); +#endif + + priv->netcp_pktdma = &netcp_pktdma; + + priv->phydev = phy_connect(mdio_bus, priv->phy_addr, dev, priv->phy_if); + phy_config(priv->phydev); + + return 0; } + +int ks2_eth_remove(struct udevice *dev) +{ + struct ks2_eth_priv *priv = dev_get_priv(dev); + + free(priv->phydev); + mdio_unregister(priv->mdio_bus); + mdio_free(priv->mdio_bus); + + return 0; +} + +static const struct eth_ops ks2_eth_ops = { + .start = ks2_eth_start, + .send = ks2_eth_send, + .recv = ks2_eth_recv, + .free_pkt = ks2_eth_free_pkt, + .stop = ks2_eth_stop, + .read_rom_hwaddr = ks2_eth_read_rom_hwaddr, + .write_hwaddr = ks2_eth_write_hwaddr, +}; + + +static int ks2_eth_ofdata_to_platdata(struct udevice *dev) +{ + struct ks2_eth_priv *priv = dev_get_priv(dev); + struct eth_pdata *pdata = dev_get_platdata(dev); + const void *fdt = gd->fdt_blob; + int interfaces; + int interface_0; + int netcp_gbe_0; + int phy; + int mdio; + u32 dma_channel[6]; + + interfaces = fdt_subnode_offset(fdt, dev->of_offset, + "netcp-interfaces"); + interface_0 = fdt_subnode_offset(fdt, interfaces, "interface-0"); + + netcp_gbe_0 = fdtdec_lookup_phandle(fdt, interface_0, "netcp-gbe"); + priv->link_type = fdtdec_get_int(fdt, netcp_gbe_0, + "link-interface", -1); + priv->slave_port = fdtdec_get_int(fdt, netcp_gbe_0, "slave-port", -1); + /* U-Boot slave port number starts with 1 instead of 0 */ + priv->slave_port += 1; + + phy = fdtdec_lookup_phandle(fdt, netcp_gbe_0, "phy-handle"); + priv->phy_addr = fdtdec_get_int(fdt, phy, "reg", -1); + + mdio = fdt_parent_offset(fdt, phy); + if (mdio < 0) { + error("mdio dt not found\n"); + return -ENODEV; + } + priv->mdio_base = (void *)fdtdec_get_addr(fdt, mdio, "reg"); + + if (priv->link_type == LINK_TYPE_MAC_TO_PHY_MODE) { + priv->phy_if = PHY_INTERFACE_MODE_SGMII; + pdata->phy_interface = priv->phy_if; + priv->sgmii_link_type = SGMII_LINK_MAC_PHY; + priv->has_mdio = true; + } + pdata->iobase = dev_get_addr(dev); + + fdtdec_get_int_array(fdt, dev->of_offset, "ti,navigator-dmas", + dma_channel, 6); + priv->net_rx_buffs.rx_flow = dma_channel[1]; + + return 0; +} + +static const struct udevice_id ks2_eth_ids[] = { + { .compatible = "ti,netcp-1.0" }, + { } +}; + + +U_BOOT_DRIVER(eth_ks2) = { + .name = "eth_ks2", + .id = UCLASS_ETH, + .of_match = ks2_eth_ids, + .ofdata_to_platdata = ks2_eth_ofdata_to_platdata, + .probe = ks2_eth_probe, + .remove = ks2_eth_remove, + .ops = &ks2_eth_ops, + .priv_auto_alloc_size = sizeof(struct ks2_eth_priv), + .platdata_auto_alloc_size = sizeof(struct eth_pdata), + .flags = DM_FLAG_ALLOC_PRIV_DMA, +}; #endif diff --git a/drivers/net/lan91c96.c b/drivers/net/lan91c96.c index c4dd01ec2a..3526876d14 100644 --- a/drivers/net/lan91c96.c +++ b/drivers/net/lan91c96.c @@ -1,7 +1,7 @@ /*------------------------------------------------------------------------ * lan91c96.c * This is a driver for SMSC's LAN91C96 single-chip Ethernet device, based - * on the SMC91111 driver from U-boot. + * on the SMC91111 driver from U-Boot. * * (C) Copyright 2002 * Sysgo Real-Time Solutions, GmbH <www.elinos.com> diff --git a/drivers/net/ne2000_base.c b/drivers/net/ne2000_base.c index 887cfd957b..71d133cc8f 100644 --- a/drivers/net/ne2000_base.c +++ b/drivers/net/ne2000_base.c @@ -650,7 +650,7 @@ dp83902a_poll(void) } -/* U-boot specific routines */ +/* U-Boot specific routines */ static u8 *pbuf = NULL; static int pkey = -1; diff --git a/drivers/net/pch_gbe.c b/drivers/net/pch_gbe.c index 56d29d47af..137818b390 100644 --- a/drivers/net/pch_gbe.c +++ b/drivers/net/pch_gbe.c @@ -117,15 +117,15 @@ static void pch_gbe_rx_descs_init(struct udevice *dev) memset(rx_desc, 0, sizeof(struct pch_gbe_rx_desc) * PCH_GBE_DESC_NUM); for (i = 0; i < PCH_GBE_DESC_NUM; i++) - rx_desc->buffer_addr = pci_phys_to_mem(priv->bdf, + rx_desc->buffer_addr = dm_pci_phys_to_mem(priv->dev, (u32)(priv->rx_buff[i])); - writel(pci_phys_to_mem(priv->bdf, (u32)rx_desc), + writel(dm_pci_phys_to_mem(priv->dev, (u32)rx_desc), &mac_regs->rx_dsc_base); writel(sizeof(struct pch_gbe_rx_desc) * (PCH_GBE_DESC_NUM - 1), &mac_regs->rx_dsc_size); - writel(pci_phys_to_mem(priv->bdf, (u32)(rx_desc + 1)), + writel(dm_pci_phys_to_mem(priv->dev, (u32)(rx_desc + 1)), &mac_regs->rx_dsc_sw_p); } @@ -137,11 +137,11 @@ static void pch_gbe_tx_descs_init(struct udevice *dev) memset(tx_desc, 0, sizeof(struct pch_gbe_tx_desc) * PCH_GBE_DESC_NUM); - writel(pci_phys_to_mem(priv->bdf, (u32)tx_desc), + writel(dm_pci_phys_to_mem(priv->dev, (u32)tx_desc), &mac_regs->tx_dsc_base); writel(sizeof(struct pch_gbe_tx_desc) * (PCH_GBE_DESC_NUM - 1), &mac_regs->tx_dsc_size); - writel(pci_phys_to_mem(priv->bdf, (u32)(tx_desc + 1)), + writel(dm_pci_phys_to_mem(priv->dev, (u32)(tx_desc + 1)), &mac_regs->tx_dsc_sw_p); } @@ -251,7 +251,7 @@ static int pch_gbe_send(struct udevice *dev, void *packet, int length) if (length < 64) frame_ctrl |= PCH_GBE_TXD_CTRL_APAD; - tx_desc->buffer_addr = pci_phys_to_mem(priv->bdf, (u32)packet); + tx_desc->buffer_addr = dm_pci_phys_to_mem(priv->dev, (u32)packet); tx_desc->length = length; tx_desc->tx_words_eob = length + 3; tx_desc->tx_frame_ctrl = frame_ctrl; @@ -262,7 +262,7 @@ static int pch_gbe_send(struct udevice *dev, void *packet, int length) if (++priv->tx_idx >= PCH_GBE_DESC_NUM) priv->tx_idx = 0; - writel(pci_phys_to_mem(priv->bdf, (u32)(tx_head + priv->tx_idx)), + writel(dm_pci_phys_to_mem(priv->dev, (u32)(tx_head + priv->tx_idx)), &mac_regs->tx_dsc_sw_p); start = get_timer(0); @@ -294,7 +294,7 @@ static int pch_gbe_recv(struct udevice *dev, int flags, uchar **packetp) if ((u32)rx_desc == hw_desc) return -EAGAIN; - buffer_addr = pci_mem_to_phys(priv->bdf, rx_desc->buffer_addr); + buffer_addr = dm_pci_mem_to_phys(priv->dev, rx_desc->buffer_addr); *packetp = (uchar *)buffer_addr; length = rx_desc->rx_words_eob - 3 - ETH_FCS_LEN; @@ -315,7 +315,7 @@ static int pch_gbe_free_pkt(struct udevice *dev, uchar *packet, int length) if (++rx_swp >= PCH_GBE_DESC_NUM) rx_swp = 0; - writel(pci_phys_to_mem(priv->bdf, (u32)(rx_head + rx_swp)), + writel(dm_pci_phys_to_mem(priv->dev, (u32)(rx_head + rx_swp)), &mac_regs->rx_dsc_sw_p); return 0; @@ -421,11 +421,8 @@ int pch_gbe_probe(struct udevice *dev) { struct pch_gbe_priv *priv; struct eth_pdata *plat = dev_get_platdata(dev); - pci_dev_t devno; u32 iobase; - devno = dm_pci_get_bdf(dev); - /* * The priv structure contains the descriptors and frame buffers which * need a strict buswidth alignment (64 bytes). This is guaranteed by @@ -433,11 +430,11 @@ int pch_gbe_probe(struct udevice *dev) */ priv = dev_get_priv(dev); - priv->bdf = devno; + priv->dev = dev; - pci_read_config_dword(devno, PCI_BASE_ADDRESS_1, &iobase); + dm_pci_read_config32(dev, PCI_BASE_ADDRESS_1, &iobase); iobase &= PCI_BASE_ADDRESS_MEM_MASK; - iobase = pci_mem_to_phys(devno, iobase); + iobase = dm_pci_mem_to_phys(dev, iobase); plat->iobase = iobase; priv->mac_regs = (struct pch_gbe_regs *)iobase; diff --git a/drivers/net/pch_gbe.h b/drivers/net/pch_gbe.h index afcb03dd36..0ea0c73a4f 100644 --- a/drivers/net/pch_gbe.h +++ b/drivers/net/pch_gbe.h @@ -290,7 +290,7 @@ struct pch_gbe_priv { struct phy_device *phydev; struct mii_dev *bus; struct pch_gbe_regs *mac_regs; - pci_dev_t bdf; + struct udevice *dev; int rx_idx; int tx_idx; }; diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c index eab15585c3..b8b1157a0a 100644 --- a/drivers/net/phy/marvell.c +++ b/drivers/net/phy/marvell.c @@ -172,7 +172,6 @@ static int m88e1011s_startup(struct phy_device *phydev) static int m88e1111s_config(struct phy_device *phydev) { int reg; - int timeout; if ((phydev->interface == PHY_INTERFACE_MODE_RGMII) || (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) || @@ -236,16 +235,7 @@ static int m88e1111s_config(struct phy_device *phydev) MIIM_88E1111_PHY_EXT_SR, reg); /* soft reset */ - timeout = 1000; - phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, BMCR_RESET); - udelay(1000); - reg = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMCR); - while ((reg & BMCR_RESET) && --timeout) { - udelay(1000); - reg = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMCR); - } - if (!timeout) - printf("%s: phy soft reset timeout\n", __func__); + phy_reset(phydev); reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_88E1111_PHY_EXT_SR); @@ -258,20 +248,10 @@ static int m88e1111s_config(struct phy_device *phydev) } /* soft reset */ - timeout = 1000; - phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, BMCR_RESET); - udelay(1000); - reg = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMCR); - while ((reg & BMCR_RESET) && --timeout) { - udelay(1000); - reg = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMCR); - } - if (!timeout) - printf("%s: phy soft reset timeout\n", __func__); + phy_reset(phydev); genphy_config_aneg(phydev); - - phy_reset(phydev); + genphy_restart_aneg(phydev); return 0; } diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c index c3da1606dc..8fcf737cb8 100644 --- a/drivers/net/phy/micrel.c +++ b/drivers/net/phy/micrel.c @@ -279,7 +279,8 @@ static int ksz90x1_of_config_group(struct phy_device *phydev, #define CTRL1000_CONFIG_MASTER (1 << 11) #define CTRL1000_MANUAL_CONFIG (1 << 12) -#ifdef CONFIG_DM_ETH +#if defined(CONFIG_DM_ETH) && (defined(CONFIG_PHY_MICREL_KSZ9021) || \ + defined(CONFIG_PHY_MICREL_KSZ9031)) static const struct ksz90x1_reg_field ksz9021_clk_grp[] = { { "txen-skew-ps", 4, 0, 0x7 }, { "txc-skew-ps", 4, 4, 0x7 }, { "rxdv-skew-ps", 4, 8, 0x7 }, { "rxc-skew-ps", 4, 12, 0x7 }, @@ -385,7 +386,8 @@ static struct phy_driver ksz9021_driver = { #define MII_KSZ9031_MMD_ACCES_CTRL 0x0d #define MII_KSZ9031_MMD_REG_DATA 0x0e -#ifdef CONFIG_DM_ETH +#if defined(CONFIG_DM_ETH) && (defined(CONFIG_PHY_MICREL_KSZ9021) || \ + defined(CONFIG_PHY_MICREL_KSZ9031)) static const struct ksz90x1_reg_field ksz9031_ctl_grp[] = { { "txen-skew-ps", 4, 0, 0x7 }, { "rxdv-skew-ps", 4, 4, 0x7 } }; static const struct ksz90x1_reg_field ksz9031_clk_grp[] = diff --git a/drivers/pch/pch-uclass.c b/drivers/pch/pch-uclass.c index 4579ed12f6..7216660a24 100644 --- a/drivers/pch/pch-uclass.c +++ b/drivers/pch/pch-uclass.c @@ -12,35 +12,47 @@ DECLARE_GLOBAL_DATA_PTR; -int pch_get_sbase(struct udevice *dev, ulong *sbasep) +int pch_get_spi_base(struct udevice *dev, ulong *sbasep) { struct pch_ops *ops = pch_get_ops(dev); *sbasep = 0; - if (!ops->get_sbase) + if (!ops->get_spi_base) return -ENOSYS; - return ops->get_sbase(dev, sbasep); + return ops->get_spi_base(dev, sbasep); } -enum pch_version pch_get_version(struct udevice *dev) +int pch_set_spi_protect(struct udevice *dev, bool protect) { struct pch_ops *ops = pch_get_ops(dev); - if (!ops->get_version) + if (!ops->set_spi_protect) return -ENOSYS; - return ops->get_version(dev); + return ops->set_spi_protect(dev, protect); } -int pch_set_spi_protect(struct udevice *dev, bool protect) +int pch_get_gpio_base(struct udevice *dev, u32 *gbasep) { struct pch_ops *ops = pch_get_ops(dev); - if (!ops->set_spi_protect) + *gbasep = 0; + if (!ops->get_gpio_base) return -ENOSYS; - return ops->set_spi_protect(dev, protect); + return ops->get_gpio_base(dev, gbasep); +} + +int pch_get_io_base(struct udevice *dev, u32 *iobasep) +{ + struct pch_ops *ops = pch_get_ops(dev); + + *iobasep = 0; + if (!ops->get_io_base) + return -ENOSYS; + + return ops->get_io_base(dev, iobasep); } static int pch_uclass_post_bind(struct udevice *bus) diff --git a/drivers/pch/pch7.c b/drivers/pch/pch7.c index ef724221c2..302c9299ee 100644 --- a/drivers/pch/pch7.c +++ b/drivers/pch/pch7.c @@ -8,9 +8,10 @@ #include <dm.h> #include <pch.h> +#define GPIO_BASE 0x44 #define BIOS_CTRL 0xd8 -static int pch7_get_sbase(struct udevice *dev, ulong *sbasep) +static int pch7_get_spi_base(struct udevice *dev, ulong *sbasep) { u32 rcba; @@ -22,11 +23,6 @@ static int pch7_get_sbase(struct udevice *dev, ulong *sbasep) return 0; } -static enum pch_version pch7_get_version(struct udevice *dev) -{ - return PCHV_7; -} - static int pch7_set_spi_protect(struct udevice *dev, bool protect) { uint8_t bios_cntl; @@ -42,10 +38,41 @@ static int pch7_set_spi_protect(struct udevice *dev, bool protect) return 0; } +static int pch7_get_gpio_base(struct udevice *dev, u32 *gbasep) +{ + u32 base; + + /* + * GPIO_BASE moved to its current offset with ICH6, but prior to + * that it was unused (or undocumented). Check that it looks + * okay: not all ones or zeros. + * + * Note we don't need check bit0 here, because the Tunnel Creek + * GPIO base address register bit0 is reserved (read returns 0), + * while on the Ivybridge the bit0 is used to indicate it is an + * I/O space. + */ + dm_pci_read_config32(dev, GPIO_BASE, &base); + if (base == 0x00000000 || base == 0xffffffff) { + debug("%s: unexpected BASE value\n", __func__); + return -ENODEV; + } + + /* + * Okay, I guess we're looking at the right device. The actual + * GPIO registers are in the PCI device's I/O space, starting + * at the offset that we just read. Bit 0 indicates that it's + * an I/O address, not a memory address, so mask that off. + */ + *gbasep = base & 1 ? base & ~3 : base & ~15; + + return 0; +} + static const struct pch_ops pch7_ops = { - .get_sbase = pch7_get_sbase, - .get_version = pch7_get_version, + .get_spi_base = pch7_get_spi_base, .set_spi_protect = pch7_set_spi_protect, + .get_gpio_base = pch7_get_gpio_base, }; static const struct udevice_id pch7_ids[] = { diff --git a/drivers/pch/pch9.c b/drivers/pch/pch9.c index 529cb023e2..910eb61f48 100644 --- a/drivers/pch/pch9.c +++ b/drivers/pch/pch9.c @@ -8,9 +8,11 @@ #include <dm.h> #include <pch.h> +#define GPIO_BASE 0x48 +#define IO_BASE 0x4c #define SBASE_ADDR 0x54 -static int pch9_get_sbase(struct udevice *dev, ulong *sbasep) +static int pch9_get_spi_base(struct udevice *dev, ulong *sbasep) { uint32_t sbase_addr; @@ -20,14 +22,56 @@ static int pch9_get_sbase(struct udevice *dev, ulong *sbasep) return 0; } -static enum pch_version pch9_get_version(struct udevice *dev) +static int pch9_get_gpio_base(struct udevice *dev, u32 *gbasep) { - return PCHV_9; + u32 base; + + /* + * GPIO_BASE moved to its current offset with ICH6, but prior to + * that it was unused (or undocumented). Check that it looks + * okay: not all ones or zeros. + * + * Note we don't need check bit0 here, because the Tunnel Creek + * GPIO base address register bit0 is reserved (read returns 0), + * while on the Ivybridge the bit0 is used to indicate it is an + * I/O space. + */ + dm_pci_read_config32(dev, GPIO_BASE, &base); + if (base == 0x00000000 || base == 0xffffffff) { + debug("%s: unexpected BASE value\n", __func__); + return -ENODEV; + } + + /* + * Okay, I guess we're looking at the right device. The actual + * GPIO registers are in the PCI device's I/O space, starting + * at the offset that we just read. Bit 0 indicates that it's + * an I/O address, not a memory address, so mask that off. + */ + *gbasep = base & 1 ? base & ~3 : base & ~15; + + return 0; +} + +static int pch9_get_io_base(struct udevice *dev, u32 *iobasep) +{ + u32 base; + + dm_pci_read_config32(dev, IO_BASE, &base); + if (base == 0x00000000 || base == 0xffffffff) { + debug("%s: unexpected BASE value\n", __func__); + return -ENODEV; + } + + *iobasep = base & 1 ? base & ~3 : base & ~15; + + return 0; } static const struct pch_ops pch9_ops = { - .get_sbase = pch9_get_sbase, - .get_version = pch9_get_version, + .get_spi_base = pch9_get_spi_base, + .get_gpio_base = pch9_get_gpio_base, + .get_io_base = pch9_get_io_base, }; static const struct udevice_id pch9_ids[] = { diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig index cd8f3570f0..6f0d61e7ab 100644 --- a/drivers/pwm/Kconfig +++ b/drivers/pwm/Kconfig @@ -17,3 +17,12 @@ config PWM_ROCKCHIP programmable period and duty cycle. A 32-bit counter is used. Various options provided in the hardware (such as capture mode and continuous/single-shot) are not supported by the driver. + +config PWM_TEGRA + bool "Enable support for the Tegra PWM" + depends on DM_PWM + help + This PWM is found on Tegra 20 and other Nvidia SoCs. It supports + four channels with a programmable period and duty cycle. Only a + 32KHz clock is supported by the driver but the duty cycle is + configurable. diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile index b6d8c16604..fd414b1893 100644 --- a/drivers/pwm/Makefile +++ b/drivers/pwm/Makefile @@ -13,3 +13,6 @@ obj-$(CONFIG_DM_PWM) += pwm-uclass.o obj-$(CONFIG_PWM_ROCKCHIP) += rk_pwm.o obj-$(CONFIG_PWM_IMX) += pwm-imx.o pwm-imx-util.o +ifdef CONFIG_DM_PWM +obj-$(CONFIG_PWM_TEGRA) += tegra_pwm.o +endif diff --git a/drivers/pwm/tegra_pwm.c b/drivers/pwm/tegra_pwm.c new file mode 100644 index 0000000000..10e1fdc9b5 --- /dev/null +++ b/drivers/pwm/tegra_pwm.c @@ -0,0 +1,85 @@ +/* + * Copyright 2016 Google Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <dm.h> +#include <pwm.h> +#include <asm/io.h> +#include <asm/arch/clock.h> +#include <asm/arch/pwm.h> + +DECLARE_GLOBAL_DATA_PTR; + +struct tegra_pwm_priv { + struct pwm_ctlr *regs; +}; + +static int tegra_pwm_set_config(struct udevice *dev, uint channel, + uint period_ns, uint duty_ns) +{ + struct tegra_pwm_priv *priv = dev_get_priv(dev); + struct pwm_ctlr *regs = priv->regs; + uint pulse_width; + u32 reg; + + if (channel >= 4) + return -EINVAL; + debug("%s: Configure '%s' channel %u\n", __func__, dev->name, channel); + /* We ignore the period here and just use 32KHz */ + clock_start_periph_pll(PERIPH_ID_PWM, CLOCK_ID_SFROM32KHZ, 32768); + + pulse_width = duty_ns * 255 / period_ns; + + reg = pulse_width << PWM_WIDTH_SHIFT; + reg |= 1 << PWM_DIVIDER_SHIFT; + writel(reg, ®s[channel].control); + debug("%s: pulse_width=%u\n", __func__, pulse_width); + + return 0; +} + +static int tegra_pwm_set_enable(struct udevice *dev, uint channel, bool enable) +{ + struct tegra_pwm_priv *priv = dev_get_priv(dev); + struct pwm_ctlr *regs = priv->regs; + + if (channel >= 4) + return -EINVAL; + debug("%s: Enable '%s' channel %u\n", __func__, dev->name, channel); + clrsetbits_le32(®s[channel].control, PWM_ENABLE_MASK, + enable ? PWM_ENABLE_MASK : 0); + + return 0; +} + +static int tegra_pwm_ofdata_to_platdata(struct udevice *dev) +{ + struct tegra_pwm_priv *priv = dev_get_priv(dev); + + priv->regs = (struct pwm_ctlr *)dev_get_addr(dev); + + return 0; +} + +static const struct pwm_ops tegra_pwm_ops = { + .set_config = tegra_pwm_set_config, + .set_enable = tegra_pwm_set_enable, +}; + +static const struct udevice_id tegra_pwm_ids[] = { + { .compatible = "nvidia,tegra124-pwm" }, + { .compatible = "nvidia,tegra20-pwm" }, + { } +}; + +U_BOOT_DRIVER(tegra_pwm) = { + .name = "tegra_pwm", + .id = UCLASS_PWM, + .of_match = tegra_pwm_ids, + .ops = &tegra_pwm_ops, + .ofdata_to_platdata = tegra_pwm_ofdata_to_platdata, + .priv_auto_alloc_size = sizeof(struct tegra_pwm_priv), +}; diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile index 57cd38bf6e..c63999ac41 100644 --- a/drivers/serial/Makefile +++ b/drivers/serial/Makefile @@ -22,14 +22,10 @@ obj-$(CONFIG_ATMEL_USART) += atmel_usart.o obj-$(CONFIG_EFI_APP) += serial_efi.o obj-$(CONFIG_LPC32XX_HSUART) += lpc32xx_hsuart.o obj-$(CONFIG_MCFUART) += mcfuart.o -obj-$(CONFIG_OPENCORES_YANU) += opencores_yanu.o obj-$(CONFIG_SYS_NS16550) += ns16550.o obj-$(CONFIG_S5P) += serial_s5p.o -obj-$(CONFIG_IMX_SERIAL) += serial_imx.o -obj-$(CONFIG_MAX3100_SERIAL) += serial_max3100.o obj-$(CONFIG_MXC_UART) += serial_mxc.o obj-$(CONFIG_PXA_SERIAL) += serial_pxa.o -obj-$(CONFIG_SA1100_SERIAL) += serial_sa1100.o obj-$(CONFIG_S3C24X0_SERIAL) += serial_s3c24x0.o obj-$(CONFIG_XILINX_UARTLITE) += serial_xuartlite.o obj-$(CONFIG_SANDBOX_SERIAL) += sandbox.o @@ -37,7 +33,6 @@ obj-$(CONFIG_SCIF_CONSOLE) += serial_sh.o obj-$(CONFIG_ZYNQ_SERIAL) += serial_zynq.o obj-$(CONFIG_BFIN_SERIAL) += serial_bfin.o obj-$(CONFIG_FSL_LPUART) += serial_lpuart.o -obj-$(CONFIG_MXS_AUART) += mxs_auart.o obj-$(CONFIG_ARC_SERIAL) += serial_arc.o obj-$(CONFIG_UNIPHIER_SERIAL) += serial_uniphier.o obj-$(CONFIG_STM32_SERIAL) += serial_stm32.o diff --git a/drivers/serial/mxs_auart.c b/drivers/serial/mxs_auart.c deleted file mode 100644 index fc0fa96a0e..0000000000 --- a/drivers/serial/mxs_auart.c +++ /dev/null @@ -1,151 +0,0 @@ -/* - * Freescale i.MX23/i.MX28 AUART driver - * - * Copyright (C) 2013 Andreas Wass <andreas.wass@dalelven.com> - * - * Based on the MXC serial driver: - * - * (c) 2007 Sascha Hauer <s.hauer@pengutronix.de> - * - * Further based on the Linux mxs-auart.c driver: - * - * Freescale STMP37XX/STMP38X Application UART drkiver - * Copyright 2008-2010 Freescale Semiconductor, Inc. - * - * SPDX-License-Identifier: GPL-2.0+ - */ -#include <common.h> -#include <asm/io.h> -#include <serial.h> -#include <linux/compiler.h> -#include <asm/arch/regs-base.h> -#include <asm/arch/regs-uartapp.h> -#include <asm/arch/sys_proto.h> - -DECLARE_GLOBAL_DATA_PTR; - -#ifndef CONFIG_MXS_AUART_BASE -#error "CONFIG_MXS_AUART_BASE must be set to the base UART to use" -#endif - -/* AUART clock always supplied by XTAL and always 24MHz */ -#define MXS_AUART_CLK 24000000 - -static struct mxs_uartapp_regs *get_uartapp_registers(void) -{ - return (struct mxs_uartapp_regs *)CONFIG_MXS_AUART_BASE; -} - -/** - * Sets the baud rate and settings. - * The settings are: 8 data bits, no parit and 1 stop bit. - */ -static void mxs_auart_setbrg(void) -{ - u32 div; - u32 linectrl = 0; - struct mxs_uartapp_regs *regs = get_uartapp_registers(); - - if (!gd->baudrate) - gd->baudrate = CONFIG_BAUDRATE; - - /* - * From i.MX28 datasheet: - * div is calculated by calculating UARTCLK*32/baudrate, rounded to int - * div must be between 0xEC and 0x003FFFC0 inclusive - * Lowest 6 bits of div goes in BAUD_DIVFRAC part of LINECTRL register - * Next 16 bits goes in BAUD_DIVINT part of LINECTRL register - */ - div = (MXS_AUART_CLK * 32) / gd->baudrate; - if (div < 0xEC || div > 0x003FFFC0) - return; - - linectrl |= ((div & UARTAPP_LINECTRL_EXTRACT_BAUD_DIVFRAC_MASK) << - UARTAPP_LINECTRL_BAUD_DIVFRAC_OFFSET) & - UARTAPP_LINECTRL_BAUD_DIVFRAC_MASK; - linectrl |= ((div >> UARTAPP_LINECTRL_EXTRACT_BAUD_DIVINT_OFFSET) << - UARTAPP_LINECTRL_BAUD_DIVINT_OFFSET) & - UARTAPP_LINECTRL_BAUD_DIVINT_MASK; - - /* Word length: 8 bits */ - linectrl |= UARTAPP_LINECTRL_WLEN_8BITS; - - /* Enable FIFOs. */ - linectrl |= UARTAPP_LINECTRL_FEN_MASK; - - /* Write above settings, no parity, 1 stop bit */ - writel(linectrl, ®s->hw_uartapp_linectrl); -} - -static int mxs_auart_init(void) -{ - struct mxs_uartapp_regs *regs = get_uartapp_registers(); - /* Reset everything */ - mxs_reset_block(®s->hw_uartapp_ctrl0_reg); - /* Disable interrupts */ - writel(0, ®s->hw_uartapp_intr); - /* Set baud rate and settings */ - serial_setbrg(); - /* Disable RTS and CTS, ignore LINECTRL2 register */ - writel(UARTAPP_CTRL2_RTSEN_MASK | - UARTAPP_CTRL2_CTSEN_MASK | - UARTAPP_CTRL2_USE_LCR2_MASK, - ®s->hw_uartapp_ctrl2_clr); - /* Enable receiver, transmitter and UART */ - writel(UARTAPP_CTRL2_RXE_MASK | - UARTAPP_CTRL2_TXE_MASK | - UARTAPP_CTRL2_UARTEN_MASK, - ®s->hw_uartapp_ctrl2_set); - return 0; -} - -static void mxs_auart_putc(const char c) -{ - struct mxs_uartapp_regs *regs = get_uartapp_registers(); - /* Wait in loop while the transmit FIFO is full */ - while (readl(®s->hw_uartapp_stat) & UARTAPP_STAT_TXFF_MASK) - ; - - writel(c, ®s->hw_uartapp_data); - - if (c == '\n') - mxs_auart_putc('\r'); -} - -static int mxs_auart_tstc(void) -{ - struct mxs_uartapp_regs *regs = get_uartapp_registers(); - /* Checks if receive FIFO is empty */ - return !(readl(®s->hw_uartapp_stat) & UARTAPP_STAT_RXFE_MASK); -} - -static int mxs_auart_getc(void) -{ - struct mxs_uartapp_regs *regs = get_uartapp_registers(); - /* Wait until a character is available to read */ - while (!mxs_auart_tstc()) - ; - /* Read the character from the data register */ - return readl(®s->hw_uartapp_data) & 0xFF; -} - -static struct serial_device mxs_auart_drv = { - .name = "mxs_auart_serial", - .start = mxs_auart_init, - .stop = NULL, - .setbrg = mxs_auart_setbrg, - .putc = mxs_auart_putc, - .puts = default_serial_puts, - .getc = mxs_auart_getc, - .tstc = mxs_auart_tstc, -}; - -void mxs_auart_initialize(void) -{ - serial_register(&mxs_auart_drv); -} - -__weak struct serial_device *default_serial_console(void) -{ - return &mxs_auart_drv; -} diff --git a/drivers/serial/opencores_yanu.c b/drivers/serial/opencores_yanu.c deleted file mode 100644 index f68c8d0f04..0000000000 --- a/drivers/serial/opencores_yanu.c +++ /dev/null @@ -1,242 +0,0 @@ -/* - * Altera NiosII YANU serial interface by Imagos - * please see http://www.opencores.org/project,yanu for - * information/downloads - * - * Copyright 2010, Renato Andreola <renato.andreola@imagos.it> - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#include <common.h> -#include <watchdog.h> -#include <asm/io.h> -#include <serial.h> - -DECLARE_GLOBAL_DATA_PTR; - -/*-----------------------------------------------------------------*/ -/* YANU Imagos serial port */ -/*-----------------------------------------------------------------*/ - -#define YANU_MAX_PRESCALER_N ((1 << 4) - 1) /* 15 */ -#define YANU_MAX_PRESCALER_M ((1 << 11) -1) /* 2047 */ -#define YANU_FIFO_SIZE (16) -#define YANU_RXFIFO_SIZE (YANU_FIFO_SIZE) -#define YANU_TXFIFO_SIZE (YANU_FIFO_SIZE) - -#define YANU_RXFIFO_DLY (10*11) -#define YANU_TXFIFO_THR (10) -#define YANU_DATA_CHAR_MASK (0xFF) - -/* data register */ -#define YANU_DATA_OFFSET (0) /* data register offset */ - -#define YANU_CONTROL_OFFSET (4) /* control register offset */ -/* interrupt enable */ -#define YANU_CONTROL_IE_RRDY (1<<0) /* ie on received character ready */ -#define YANU_CONTROL_IE_OE (1<<1) /* ie on rx overrun */ -#define YANU_CONTROL_IE_BRK (1<<2) /* ie on break detect */ -#define YANU_CONTROL_IE_FE (1<<3) /* ie on framing error */ -#define YANU_CONTROL_IE_PE (1<<4) /* ie on parity error */ -#define YANU_CONTROL_IE_TRDY (1<<5) /* ie interrupt on tranmitter ready */ -/* control bits */ -#define YANU_CONTROL_BITS_POS (6) /* bits number pos */ -#define YANU_CONTROL_BITS (1<<YANU_CONTROL_BITS_POS) /* number of rx/tx bits per word. 3 bit unsigned integer */ -#define YANU_CONTROL_BITS_N (3) /* ... its bit filed length */ -#define YANU_CONTROL_PARENA (1<<9) /* enable parity bit transmission/reception */ -#define YANU_CONTROL_PAREVEN (1<<10) /* parity even */ -#define YANU_CONTROL_STOPS (1<<11) /* number of stop bits */ -#define YANU_CONTROL_HHENA (1<<12) /* Harware Handshake enable... */ -#define YANU_CONTROL_FORCEBRK (1<<13) /* if set than txd = active (0) */ -/* tuning part */ -#define YANU_CONTROL_RDYDLY (1<<14) /* delay from "first" before setting rrdy (in bit) */ -#define YANU_CONTROL_RDYDLY_N (8) /* ... its bit filed length */ -#define YANU_CONTROL_TXTHR (1<<22) /* tx interrupt threshold: the trdy set if txfifo_chars<= txthr (chars) */ -#define YANU_CONTROL_TXTHR_N (4) /* ... its bit field length */ - -#define YANU_BAUD_OFFSET (8) /* baud register offset */ -#define YANU_BAUDM (1<<0) /* baud mantissa lsb */ -#define YANU_BAUDM_N (12) /* ...its bit filed length */ -#define YANU_BAUDE (1<<12) /* baud exponent lsb */ -#define YANU_BAUDE_N (4) /* ...its bit field length */ - -#define YANU_ACTION_OFFSET (12) /* action register... write only */ -#define YANU_ACTION_RRRDY (1<<0) /* reset rrdy */ -#define YANU_ACTION_ROE (1<<1) /* reset oe */ -#define YANU_ACTION_RBRK (1<<2) /* reset brk */ -#define YANU_ACTION_RFE (1<<3) /* reset fe */ -#define YANU_ACTION_RPE (1<<4) /* reset pe */ -#define YANU_ACTION_SRRDY (1<<5) /* set rrdy */ -#define YANU_ACTION_SOE (1<<6) /* set oe */ -#define YANU_ACTION_SBRK (1<<7) /* set brk */ -#define YANU_ACTION_SFE (1<<8) /* set fe */ -#define YANU_ACTION_SPE (1<<9) /* set pe */ -#define YANU_ACTION_RFIFO_PULL (1<<10) /* pull a char from rx fifo we MUST do it before taking a char */ -#define YANU_ACTION_RFIFO_CLEAR (1<<11) /* clear rx fifo */ -#define YANU_ACTION_TFIFO_CLEAR (1<<12) /* clear tx fifo */ -#define YANU_ACTION_RTRDY (1<<13) /* clear trdy */ -#define YANU_ACTION_STRDY (1<<14) /* set trdy */ - -#define YANU_STATUS_OFFSET (16) -#define YANU_STATUS_RRDY (1<<0) /* rxrdy flag */ -#define YANU_STATUS_TRDY (1<<1) /* txrdy flag */ -#define YANU_STATUS_OE (1<<2) /* rx overrun error */ -#define YANU_STATUS_BRK (1<<3) /* rx break detect flag */ -#define YANU_STATUS_FE (1<<4) /* rx framing error flag */ -#define YANU_STATUS_PE (1<<5) /* rx parity erro flag */ -#define YANU_RFIFO_CHARS_POS (6) -#define YANU_RFIFO_CHARS (1<<RFIFO_CHAR_POS) /* number of chars into rx fifo */ -#define YANU_RFIFO_CHARS_N (5) /* ...its bit field length: 32 chars */ -#define YANU_TFIFO_CHARS_POS (11) -#define YANU_TFIFO_CHARS (1<<TFIFO_CHAR_POS) /* number of chars into tx fifo */ -#define YANU_TFIFO_CHARS_N (5) /* ...its bit field length: 32 chars */ - -typedef volatile struct { - volatile unsigned data; - volatile unsigned control; /* control register (RW) 32-bit */ - volatile unsigned baud; /* baud/prescaler register (RW) 32-bit */ - volatile unsigned action; /* action register (W) 32-bit */ - volatile unsigned status; /* status register (R) 32-bit */ - volatile unsigned magic; /* magic register (R) 32-bit */ -} yanu_uart_t; - -static yanu_uart_t *uart = (yanu_uart_t *)CONFIG_SYS_NIOS_CONSOLE; - -static void oc_serial_setbrg(void) -{ - int n, k; - const unsigned max_uns = 0xFFFFFFFF; - unsigned best_n, best_m, baud; - unsigned baudrate; - -#if defined(CONFIG_SYS_NIOS_FIXEDBAUD) - /* Everything's already setup for fixed-baud PTF assignment */ - baudrate = CONFIG_BAUDRATE; -#else - baudrate = gd->baudrate; -#endif - /* compute best N and M couple */ - best_n = YANU_MAX_PRESCALER_N; - for (n = YANU_MAX_PRESCALER_N; n >= 0; n--) { - if ((unsigned)CONFIG_SYS_CLK_FREQ / (1 << (n + 4)) >= - baudrate) { - best_n = n; - break; - } - } - for (k = 0;; k++) { - if (baudrate <= (max_uns >> (15+n-k))) - break; - } - best_m = - (baudrate * (1 << (15 + n - k))) / - ((unsigned)CONFIG_SYS_CLK_FREQ >> k); - - baud = best_m + best_n * YANU_BAUDE; - writel(baud, &uart->baud); - - return; -} - -static int oc_serial_init(void) -{ - unsigned action,control; - - /* status register cleanup */ - action = YANU_ACTION_RRRDY | - YANU_ACTION_RTRDY | - YANU_ACTION_ROE | - YANU_ACTION_RBRK | - YANU_ACTION_RFE | - YANU_ACTION_RPE | - YANU_ACTION_RFE | YANU_ACTION_RFIFO_CLEAR | YANU_ACTION_TFIFO_CLEAR; - - writel(action, &uart->action); - - /* - * control register cleanup - * no interrupts enabled - * one stop bit - * hardware flow control disabled - * 8 bits - */ - control = (0x7 << YANU_CONTROL_BITS_POS); - /* enven parity just to be clean */ - control |= YANU_CONTROL_PAREVEN; - /* we set threshold for fifo */ - control |= YANU_CONTROL_RDYDLY * YANU_RXFIFO_DLY; - control |= YANU_CONTROL_TXTHR * YANU_TXFIFO_THR; - - writel(control, &uart->control); - - /* to set baud rate */ - serial_setbrg(); - - return (0); -} - - -/*----------------------------------------------------------------------- - * YANU CONSOLE - *---------------------------------------------------------------------*/ -static void oc_serial_putc(char c) -{ - int tx_chars; - unsigned status; - - if (c == '\n') - serial_putc ('\r'); - - while (1) { - status = readl(&uart->status); - tx_chars = (status>>YANU_TFIFO_CHARS_POS) - & ((1<<YANU_TFIFO_CHARS_N)-1); - if (tx_chars < YANU_TXFIFO_SIZE-1) - break; - WATCHDOG_RESET (); - } - - writel((unsigned char)c, &uart->data); -} - -static int oc_serial_tstc(void) -{ - unsigned status ; - - status = readl(&uart->status); - return (((status >> YANU_RFIFO_CHARS_POS) & - ((1 << YANU_RFIFO_CHARS_N) - 1)) > 0); -} - -static int oc_serial_getc(void) -{ - while (serial_tstc() == 0) - WATCHDOG_RESET (); - - /* first we pull the char */ - writel(YANU_ACTION_RFIFO_PULL, &uart->action); - - return(readl(&uart->data) & YANU_DATA_CHAR_MASK); -} - -static struct serial_device oc_serial_drv = { - .name = "oc_serial", - .start = oc_serial_init, - .stop = NULL, - .setbrg = oc_serial_setbrg, - .putc = oc_serial_putc, - .puts = default_serial_puts, - .getc = oc_serial_getc, - .tstc = oc_serial_tstc, -}; - -void oc_serial_initialize(void) -{ - serial_register(&oc_serial_drv); -} - -__weak struct serial_device *default_serial_console(void) -{ - return &oc_serial_drv; -} diff --git a/drivers/serial/sandbox.c b/drivers/serial/sandbox.c index 45dff98d9d..58f882b22a 100644 --- a/drivers/serial/sandbox.c +++ b/drivers/serial/sandbox.c @@ -25,7 +25,7 @@ DECLARE_GLOBAL_DATA_PTR; /* * * serial_buf: A buffer that holds keyboard characters for the - * Sandbox U-boot. + * Sandbox U-Boot. * * invariants: * serial_buf_write == serial_buf_read -> empty buffer diff --git a/drivers/serial/serial_bfin.c b/drivers/serial/serial_bfin.c index 0443b8427a..1d5be2a7a2 100644 --- a/drivers/serial/serial_bfin.c +++ b/drivers/serial/serial_bfin.c @@ -1,5 +1,5 @@ /* - * U-boot - serial.c Blackfin Serial Driver + * U-Boot - serial.c Blackfin Serial Driver * * Copyright (c) 2005-2008 Analog Devices Inc. * diff --git a/drivers/serial/serial_imx.c b/drivers/serial/serial_imx.c deleted file mode 100644 index d43a5fedcc..0000000000 --- a/drivers/serial/serial_imx.c +++ /dev/null @@ -1,223 +0,0 @@ -/* - * (c) 2004 Sascha Hauer <sascha@saschahauer.de> - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#include <common.h> -#include <asm/arch/imx-regs.h> -#include <serial.h> -#include <linux/compiler.h> - -#if defined CONFIG_IMX_SERIAL1 -#define UART_BASE IMX_UART1_BASE -#elif defined CONFIG_IMX_SERIAL2 -#define UART_BASE IMX_UART2_BASE -#else -#error "define CONFIG_IMX_SERIAL1, CONFIG_IMX_SERIAL2 or CONFIG_IMX_SERIAL_NONE" -#endif - -struct imx_serial { - volatile uint32_t urxd[16]; - volatile uint32_t utxd[16]; - volatile uint32_t ucr1; - volatile uint32_t ucr2; - volatile uint32_t ucr3; - volatile uint32_t ucr4; - volatile uint32_t ufcr; - volatile uint32_t usr1; - volatile uint32_t usr2; - volatile uint32_t uesc; - volatile uint32_t utim; - volatile uint32_t ubir; - volatile uint32_t ubmr; - volatile uint32_t ubrc; - volatile uint32_t bipr[4]; - volatile uint32_t bmpr[4]; - volatile uint32_t uts; -}; - -DECLARE_GLOBAL_DATA_PTR; - -static void imx_serial_setbrg(void) -{ - serial_init(); -} - -extern void imx_gpio_mode(int gpio_mode); - -/* - * Initialise the serial port with the given baudrate. The settings - * are always 8 data bits, no parity, 1 stop bit, no start bits. - * - */ -static int imx_serial_init(void) -{ - volatile struct imx_serial* base = (struct imx_serial *)UART_BASE; - unsigned int ufcr_rfdiv; - unsigned int refclk; - -#ifdef CONFIG_IMX_SERIAL1 - imx_gpio_mode(PC11_PF_UART1_TXD); - imx_gpio_mode(PC12_PF_UART1_RXD); -#else - imx_gpio_mode(PB30_PF_UART2_TXD); - imx_gpio_mode(PB31_PF_UART2_RXD); -#endif - - /* Disable UART */ - base->ucr1 &= ~UCR1_UARTEN; - - /* Set to default POR state */ - - base->ucr1 = 0x00000004; - base->ucr2 = 0x00000000; - base->ucr3 = 0x00000000; - base->ucr4 = 0x00008040; - base->uesc = 0x0000002B; - base->utim = 0x00000000; - base->ubir = 0x00000000; - base->ubmr = 0x00000000; - base->uts = 0x00000000; - /* Set clocks */ - base->ucr4 |= UCR4_REF16; - - /* Configure FIFOs */ - base->ufcr = 0xa81; - - /* set the baud rate. - * - * baud * 16 x - * --------- = - - * refclk y - * - * x - 1 = UBIR - * y - 1 = UBMR - * - * each register is 16 bits wide. refclk max is 96 MHz - * - */ - - ufcr_rfdiv = ((base->ufcr) & UFCR_RFDIV) >> 7; - if (ufcr_rfdiv == 6) - ufcr_rfdiv = 7; - else - ufcr_rfdiv = 6 - ufcr_rfdiv; - - refclk = get_PERCLK1(); - refclk /= ufcr_rfdiv; - - /* Set the numerator value minus one of the BRM ratio */ - base->ubir = (gd->baudrate / 100) - 1; - - /* Set the denominator value minus one of the BRM ratio */ - base->ubmr = (refclk/(16 * 100)) - 1; - - /* Set to 8N1 */ - base->ucr2 &= ~UCR2_PREN; - base->ucr2 |= UCR2_WS; - base->ucr2 &= ~UCR2_STPB; - - /* Ignore RTS */ - base->ucr2 |= UCR2_IRTS; - - /* Enable UART */ - base->ucr1 |= UCR1_UARTEN | UCR1_UARTCLKEN; - - /* Enable FIFOs */ - base->ucr2 |= UCR2_SRST | UCR2_RXEN | UCR2_TXEN; - - /* Clear status flags */ - base->usr2 |= USR2_ADET | - USR2_DTRF | - USR2_IDLE | - USR2_IRINT | - USR2_WAKE | - USR2_RTSF | - USR2_BRCD | - USR2_ORE; - - /* Clear status flags */ - base->usr1 |= USR1_PARITYERR | - USR1_RTSD | - USR1_ESCF | - USR1_FRAMERR | - USR1_AIRINT | - USR1_AWAKE; - return (0); -} - -/* - * Read a single byte from the serial port. Returns 1 on success, 0 - * otherwise. When the function is successful, the character read is - * written into its argument c. - */ -static int imx_serial_getc(void) -{ - volatile struct imx_serial* base = (struct imx_serial *)UART_BASE; - unsigned char ch; - - while(base->uts & UTS_RXEMPTY); - - ch = (char)base->urxd[0]; - - return ch; -} - -#ifdef CONFIG_HWFLOW -static int hwflow = 0; /* turned off by default */ -int hwflow_onoff(int on) -{ -} -#endif - -/* - * Output a single byte to the serial port. - */ -static void imx_serial_putc(const char c) -{ - volatile struct imx_serial* base = (struct imx_serial *)UART_BASE; - - /* Wait for Tx FIFO not full */ - while (base->uts & UTS_TXFULL); - - base->utxd[0] = c; - - /* If \n, also do \r */ - if (c == '\n') - serial_putc ('\r'); -} - -/* - * Test whether a character is in the RX buffer - */ -static int imx_serial_tstc(void) -{ - volatile struct imx_serial* base = (struct imx_serial *)UART_BASE; - - /* If receive fifo is empty, return false */ - if (base->uts & UTS_RXEMPTY) - return 0; - return 1; -} - -static struct serial_device imx_serial_drv = { - .name = "imx_serial", - .start = imx_serial_init, - .stop = NULL, - .setbrg = imx_serial_setbrg, - .putc = imx_serial_putc, - .puts = default_serial_puts, - .getc = imx_serial_getc, - .tstc = imx_serial_tstc, -}; - -void imx_serial_initialize(void) -{ - serial_register(&imx_serial_drv); -} - -__weak struct serial_device *default_serial_console(void) -{ - return &imx_serial_drv; -} diff --git a/drivers/serial/serial_max3100.c b/drivers/serial/serial_max3100.c deleted file mode 100644 index 027d9194a7..0000000000 --- a/drivers/serial/serial_max3100.c +++ /dev/null @@ -1,294 +0,0 @@ -/* - * (C) Copyright 2003 - * - * Pantelis Antoniou <panto@intracom.gr> - * Intracom S.A. - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#include <common.h> -#include <watchdog.h> -#include <serial.h> -#include <linux/compiler.h> - -DECLARE_GLOBAL_DATA_PTR; - -/**************************************************************/ - -/* convienient macros */ -#define MAX3100_SPI_RXD() (MAX3100_SPI_RXD_PORT & MAX3100_SPI_RXD_BIT) - -#define MAX3100_SPI_TXD(x) \ - do { \ - if (x) \ - MAX3100_SPI_TXD_PORT |= MAX3100_SPI_TXD_BIT; \ - else \ - MAX3100_SPI_TXD_PORT &= ~MAX3100_SPI_TXD_BIT; \ - } while(0) - -#define MAX3100_SPI_CLK(x) \ - do { \ - if (x) \ - MAX3100_SPI_CLK_PORT |= MAX3100_SPI_CLK_BIT; \ - else \ - MAX3100_SPI_CLK_PORT &= ~MAX3100_SPI_CLK_BIT; \ - } while(0) - -#define MAX3100_SPI_CLK_TOGGLE() (MAX3100_SPI_CLK_PORT ^= MAX3100_SPI_CLK_BIT) - -#define MAX3100_CS(x) \ - do { \ - if (x) \ - MAX3100_CS_PORT |= MAX3100_CS_BIT; \ - else \ - MAX3100_CS_PORT &= ~MAX3100_CS_BIT; \ - } while(0) - -/**************************************************************/ - -/* MAX3100 definitions */ - -#define MAX3100_WC (3 << 14) /* write configuration */ -#define MAX3100_RC (1 << 14) /* read configuration */ -#define MAX3100_WD (2 << 14) /* write data */ -#define MAX3100_RD (0 << 14) /* read data */ - -/* configuration register bits */ -#define MAX3100_FEN (1 << 13) /* FIFO enable */ -#define MAX3100_SHDN (1 << 12) /* shutdown bit */ -#define MAX3100_TM (1 << 11) /* T bit irq mask */ -#define MAX3100_RM (1 << 10) /* R bit irq mask */ -#define MAX3100_PM (1 << 9) /* P bit irq mask */ -#define MAX3100_RAM (1 << 8) /* mask for RA/FE bit */ -#define MAX3100_IR (1 << 7) /* IRDA timing mode */ -#define MAX3100_ST (1 << 6) /* transmit stop bit */ -#define MAX3100_PE (1 << 5) /* parity enable bit */ -#define MAX3100_L (1 << 4) /* Length bit */ -#define MAX3100_B_MASK (0x000F) /* baud rate bits mask */ -#define MAX3100_B(x) ((x) & 0x000F) /* baud rate select bits */ - -/* data register bits (write) */ -#define MAX3100_TE (1 << 10) /* transmit enable bit (active low) */ -#define MAX3100_RTS (1 << 9) /* request-to-send bit (inverted ~RTS pin) */ - -/* data register bits (read) */ -#define MAX3100_RA (1 << 10) /* receiver activity when in shutdown mode */ -#define MAX3100_FE (1 << 10) /* framing error when in normal mode */ -#define MAX3100_CTS (1 << 9) /* clear-to-send bit (inverted ~CTS pin) */ - -/* data register bits (both directions) */ -#define MAX3100_R (1 << 15) /* receive bit */ -#define MAX3100_T (1 << 14) /* transmit bit */ -#define MAX3100_P (1 << 8) /* parity bit */ -#define MAX3100_D_MASK 0x00FF /* data bits mask */ -#define MAX3100_D(x) ((x) & 0x00FF) /* data bits */ - -/* these definitions are valid only for fOSC = 3.6864MHz */ -#define MAX3100_B_230400 MAX3100_B(0) -#define MAX3100_B_115200 MAX3100_B(1) -#define MAX3100_B_57600 MAX3100_B(2) -#define MAX3100_B_38400 MAX3100_B(9) -#define MAX3100_B_19200 MAX3100_B(10) -#define MAX3100_B_9600 MAX3100_B(11) -#define MAX3100_B_4800 MAX3100_B(12) -#define MAX3100_B_2400 MAX3100_B(13) -#define MAX3100_B_1200 MAX3100_B(14) -#define MAX3100_B_600 MAX3100_B(15) - -/**************************************************************/ - -static inline unsigned int max3100_transfer(unsigned int val) -{ - unsigned int rx; - int b; - - MAX3100_SPI_CLK(0); - MAX3100_CS(0); - - rx = 0; b = 16; - while (--b >= 0) { - MAX3100_SPI_TXD(val & 0x8000); - val <<= 1; - MAX3100_SPI_CLK_TOGGLE(); - udelay(1); - rx <<= 1; - if (MAX3100_SPI_RXD()) - rx |= 1; - MAX3100_SPI_CLK_TOGGLE(); - udelay(1); - } - - MAX3100_SPI_CLK(1); - MAX3100_CS(1); - - return rx; -} - -/**************************************************************/ - -/* must be power of 2 */ -#define RXFIFO_SZ 16 - -static int rxfifo_cnt; -static int rxfifo_in; -static int rxfifo_out; -static unsigned char rxfifo_buf[16]; - -static void max3100_serial_putc_raw(int c) -{ - unsigned int rx; - - while (((rx = max3100_transfer(MAX3100_RC)) & MAX3100_T) == 0) - WATCHDOG_RESET(); - - rx = max3100_transfer(MAX3100_WD | (c & 0xff)); - if ((rx & MAX3100_RD) != 0 && rxfifo_cnt < RXFIFO_SZ) { - rxfifo_cnt++; - rxfifo_buf[rxfifo_in++] = rx & 0xff; - rxfifo_in &= RXFIFO_SZ - 1; - } -} - -static int max3100_serial_getc(void) -{ - int c; - unsigned int rx; - - while (rxfifo_cnt == 0) { - rx = max3100_transfer(MAX3100_RD); - if ((rx & MAX3100_R) != 0) { - do { - rxfifo_cnt++; - rxfifo_buf[rxfifo_in++] = rx & 0xff; - rxfifo_in &= RXFIFO_SZ - 1; - - if (rxfifo_cnt >= RXFIFO_SZ) - break; - } while (((rx = max3100_transfer(MAX3100_RD)) & MAX3100_R) != 0); - } - WATCHDOG_RESET(); - } - - rxfifo_cnt--; - c = rxfifo_buf[rxfifo_out++]; - rxfifo_out &= RXFIFO_SZ - 1; - return c; -} - -static int max3100_serial_tstc(void) -{ - unsigned int rx; - - if (rxfifo_cnt > 0) - return 1; - - rx = max3100_transfer(MAX3100_RD); - if ((rx & MAX3100_R) == 0) - return 0; - - do { - rxfifo_cnt++; - rxfifo_buf[rxfifo_in++] = rx & 0xff; - rxfifo_in &= RXFIFO_SZ - 1; - - if (rxfifo_cnt >= RXFIFO_SZ) - break; - } while (((rx = max3100_transfer(MAX3100_RD)) & MAX3100_R) != 0); - - return 1; -} - -static int max3100_serial_init(void) -{ - unsigned int wconf, rconf; - int i; - - wconf = 0; - - /* Set baud rate */ - switch (gd->baudrate) { - case 1200: - wconf = MAX3100_B_1200; - break; - case 2400: - wconf = MAX3100_B_2400; - break; - case 4800: - wconf = MAX3100_B_4800; - break; - case 9600: - wconf = MAX3100_B_9600; - break; - case 19200: - wconf = MAX3100_B_19200; - break; - case 38400: - wconf = MAX3100_B_38400; - break; - case 57600: - wconf = MAX3100_B_57600; - break; - default: - case 115200: - wconf = MAX3100_B_115200; - break; - case 230400: - wconf = MAX3100_B_230400; - break; - } - - /* try for 10ms, with a 100us gap */ - for (i = 0; i < 10000; i += 100) { - - max3100_transfer(MAX3100_WC | wconf); - rconf = max3100_transfer(MAX3100_RC) & 0x3fff; - - if (rconf == wconf) - break; - udelay(100); - } - - rxfifo_in = rxfifo_out = rxfifo_cnt = 0; - - return (0); -} - -static void max3100_serial_putc(const char c) -{ - if (c == '\n') - max3100_serial_putc_raw('\r'); - - max3100_serial_putc_raw(c); -} - -static void max3100_serial_puts(const char *s) -{ - while (*s) - max3100_serial_putc_raw(*s++); -} - -static void max3100_serial_setbrg(void) -{ -} - -static struct serial_device max3100_serial_drv = { - .name = "max3100_serial", - .start = max3100_serial_init, - .stop = NULL, - .setbrg = max3100_serial_setbrg, - .putc = max3100_serial_putc, - .puts = max3100_serial_puts, - .getc = max3100_serial_getc, - .tstc = max3100_serial_tstc, -}; - -void max3100_serial_initialize(void) -{ - serial_register(&max3100_serial_drv); -} - -__weak struct serial_device *default_serial_console(void) -{ - return &max3100_serial_drv; -} diff --git a/drivers/serial/serial_s3c24x0.c b/drivers/serial/serial_s3c24x0.c index 7afc5044a8..d4e7df27be 100644 --- a/drivers/serial/serial_s3c24x0.c +++ b/drivers/serial/serial_s3c24x0.c @@ -65,10 +65,6 @@ DECLARE_GLOBAL_DATA_PTR; .puts = s3serial##port##_puts, \ } -#ifdef CONFIG_HWFLOW -static int hwflow; -#endif - static void _serial_setbrg(const int dev_index) { struct s3c24x0_uart *uart = s3c24x0_get_base_uart(dev_index); @@ -95,10 +91,6 @@ static int serial_init_dev(const int dev_index) { struct s3c24x0_uart *uart = s3c24x0_get_base_uart(dev_index); -#ifdef CONFIG_HWFLOW - hwflow = 0; /* turned off by default */ -#endif - /* FIFO enable, Tx/Rx FIFO clear */ writel(0x07, &uart->ufcon); writel(0x0, &uart->umcon); @@ -111,16 +103,6 @@ static int serial_init_dev(const int dev_index) */ writel(0x245, &uart->ucon); -#ifdef CONFIG_HWFLOW - writel(0x1, &uart->umcon); /* rts up */ -#endif - - /* FIXME: This is sooooooooooooooooooo ugly */ -#if defined(CONFIG_ARCH_GTA02_v1) || defined(CONFIG_ARCH_GTA02_v2) - /* we need auto hw flow control on the gsm and gps port */ - if (dev_index == 0 || dev_index == 1) - writel(0x10, &uart->umcon); -#endif _serial_setbrg(dev_index); return (0); @@ -146,57 +128,16 @@ static inline int serial_getc_dev(unsigned int dev_index) return _serial_getc(dev_index); } -#ifdef CONFIG_HWFLOW -int hwflow_onoff(int on) -{ - switch (on) { - case 0: - default: - break; /* return current */ - case 1: - hwflow = 1; /* turn on */ - break; - case -1: - hwflow = 0; /* turn off */ - break; - } - return hwflow; -} -#endif - -#ifdef CONFIG_MODEM_SUPPORT -static int be_quiet = 0; -void disable_putc(void) -{ - be_quiet = 1; -} - -void enable_putc(void) -{ - be_quiet = 0; -} -#endif - - /* * Output a single byte to the serial port. */ static void _serial_putc(const char c, const int dev_index) { struct s3c24x0_uart *uart = s3c24x0_get_base_uart(dev_index); -#ifdef CONFIG_MODEM_SUPPORT - if (be_quiet) - return; -#endif while (!(readl(&uart->utrstat) & 0x2)) /* wait for room in the tx FIFO */ ; -#ifdef CONFIG_HWFLOW - while (hwflow && !(readl(&uart->umstat) & 0x1)) - /* Wait for CTS up */ ; -#endif - writeb(c, &uart->utxh); /* If \n, also do \r */ diff --git a/drivers/serial/serial_sa1100.c b/drivers/serial/serial_sa1100.c deleted file mode 100644 index 78f241d850..0000000000 --- a/drivers/serial/serial_sa1100.c +++ /dev/null @@ -1,162 +0,0 @@ -/* - * (C) Copyright 2002 - * Wolfgang Denk, DENX Software Engineering, <wd@denx.de> - * - * (C) Copyright 2002 - * Sysgo Real-Time Solutions, GmbH <www.elinos.com> - * Marius Groeger <mgroeger@sysgo.de> - * - * (C) Copyright 2002 - * Sysgo Real-Time Solutions, GmbH <www.elinos.com> - * Alex Zuepke <azu@sysgo.de> - * - * Copyright (C) 1999 2000 2001 Erik Mouw (J.A.K.Mouw@its.tudelft.nl) - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#include <common.h> -#include <SA-1100.h> -#include <serial.h> -#include <linux/compiler.h> - -DECLARE_GLOBAL_DATA_PTR; - -static void sa1100_serial_setbrg(void) -{ - unsigned int reg = 0; - - if (gd->baudrate == 1200) - reg = 191; - else if (gd->baudrate == 9600) - reg = 23; - else if (gd->baudrate == 19200) - reg = 11; - else if (gd->baudrate == 38400) - reg = 5; - else if (gd->baudrate == 57600) - reg = 3; - else if (gd->baudrate == 115200) - reg = 1; - else - hang (); - -#ifdef CONFIG_SERIAL1 - /* SA1110 uart function */ - Ser1SDCR0 |= SDCR0_SUS; - - /* Wait until port is ready ... */ - while(Ser1UTSR1 & UTSR1_TBY) {} - - /* init serial serial 1 */ - Ser1UTCR3 = 0x00; - Ser1UTSR0 = 0xff; - Ser1UTCR0 = ( UTCR0_1StpBit | UTCR0_8BitData ); - Ser1UTCR1 = 0; - Ser1UTCR2 = (u32)reg; - Ser1UTCR3 = ( UTCR3_RXE | UTCR3_TXE ); -#elif defined(CONFIG_SERIAL3) - /* Wait until port is ready ... */ - while (Ser3UTSR1 & UTSR1_TBY) { - } - - /* init serial serial 3 */ - Ser3UTCR3 = 0x00; - Ser3UTSR0 = 0xff; - Ser3UTCR0 = (UTCR0_1StpBit | UTCR0_8BitData); - Ser3UTCR1 = 0; - Ser3UTCR2 = (u32) reg; - Ser3UTCR3 = (UTCR3_RXE | UTCR3_TXE); -#else -#error "Bad: you didn't configured serial ..." -#endif -} - - -/* - * Initialise the serial port with the given baudrate. The settings - * are always 8 data bits, no parity, 1 stop bit, no start bits. - * - */ -static int sa1100_serial_init(void) -{ - serial_setbrg (); - - return (0); -} - - -/* - * Output a single byte to the serial port. - */ -static void sa1100_serial_putc(const char c) -{ -#ifdef CONFIG_SERIAL1 - /* wait for room in the tx FIFO on SERIAL1 */ - while ((Ser1UTSR0 & UTSR0_TFS) == 0); - - Ser1UTDR = c; -#elif defined(CONFIG_SERIAL3) - /* wait for room in the tx FIFO on SERIAL3 */ - while ((Ser3UTSR0 & UTSR0_TFS) == 0); - - Ser3UTDR = c; -#endif - - /* If \n, also do \r */ - if (c == '\n') - serial_putc ('\r'); -} - -/* - * Read a single byte from the serial port. Returns 1 on success, 0 - * otherwise. When the function is succesfull, the character read is - * written into its argument c. - */ -static int sa1100_serial_tstc(void) -{ -#ifdef CONFIG_SERIAL1 - return Ser1UTSR1 & UTSR1_RNE; -#elif defined(CONFIG_SERIAL3) - return Ser3UTSR1 & UTSR1_RNE; -#endif -} - -/* - * Read a single byte from the serial port. Returns 1 on success, 0 - * otherwise. When the function is succesfull, the character read is - * written into its argument c. - */ -static int sa1100_serial_getc(void) -{ -#ifdef CONFIG_SERIAL1 - while (!(Ser1UTSR1 & UTSR1_RNE)); - - return (char) Ser1UTDR & 0xff; -#elif defined(CONFIG_SERIAL3) - while (!(Ser3UTSR1 & UTSR1_RNE)); - - return (char) Ser3UTDR & 0xff; -#endif -} - -static struct serial_device sa1100_serial_drv = { - .name = "sa1100_serial", - .start = sa1100_serial_init, - .stop = NULL, - .setbrg = sa1100_serial_setbrg, - .putc = sa1100_serial_putc, - .puts = default_serial_puts, - .getc = sa1100_serial_getc, - .tstc = sa1100_serial_tstc, -}; - -void sa1100_serial_initialize(void) -{ - serial_register(&sa1100_serial_drv); -} - -__weak struct serial_device *default_serial_console(void) -{ - return &sa1100_serial_drv; -} diff --git a/drivers/serial/serial_stm32.c b/drivers/serial/serial_stm32.c index 91a5dde577..c793ba6e90 100644 --- a/drivers/serial/serial_stm32.c +++ b/drivers/serial/serial_stm32.c @@ -35,24 +35,6 @@ struct stm32_usart { DECLARE_GLOBAL_DATA_PTR; -#define MAX_SERIAL_PORTS 4 - -/* - * RCC USART specific definitions - */ -#define RCC_ENR_USART1EN (1 << 4) -#define RCC_ENR_USART2EN (1 << 17) -#define RCC_ENR_USART3EN (1 << 18) -#define RCC_ENR_USART6EN (1 << 5) - -/* Array used to figure out which RCC bit needs to be set */ -static const unsigned long usart_port_rcc_pairs[MAX_SERIAL_PORTS][2] = { - { STM32_USART1_BASE, RCC_ENR_USART1EN }, - { STM32_USART2_BASE, RCC_ENR_USART2EN }, - { STM32_USART3_BASE, RCC_ENR_USART3EN }, - { STM32_USART6_BASE, RCC_ENR_USART6EN } -}; - static int stm32_serial_setbrg(struct udevice *dev, int baudrate) { struct stm32_serial_platdata *plat = dev->platdata; @@ -114,28 +96,6 @@ static int stm32_serial_probe(struct udevice *dev) { struct stm32_serial_platdata *plat = dev->platdata; struct stm32_usart *const usart = plat->base; - int usart_port = -1; - int i; - - for (i = 0; i < MAX_SERIAL_PORTS; i++) { - if ((u32)usart == usart_port_rcc_pairs[i][0]) { - usart_port = i; - break; - } - } - - if (usart_port == -1) - return -EINVAL; - - if (((u32)usart & STM32_BUS_MASK) == STM32_APB1PERIPH_BASE) - setbits_le32(&STM32_RCC->apb1enr, - usart_port_rcc_pairs[usart_port][1]); - else if (((u32)usart & STM32_BUS_MASK) == STM32_APB2PERIPH_BASE) - setbits_le32(&STM32_RCC->apb2enr, - usart_port_rcc_pairs[usart_port][1]); - else - return -EINVAL; - setbits_le32(&usart->cr1, USART_CR1_RE | USART_CR1_TE | USART_CR1_UE); return 0; diff --git a/drivers/soc/Makefile b/drivers/soc/Makefile index 99345eb9a0..69f680cc11 100644 --- a/drivers/soc/Makefile +++ b/drivers/soc/Makefile @@ -1,5 +1,5 @@ # -# Makefile for the U-boot SOC specific device drivers. +# Makefile for the U-Boot SOC specific device drivers. # # SPDX-License-Identifier: GPL-2.0+ # diff --git a/drivers/spi/ich.c b/drivers/spi/ich.c index e543b8f0cf..00b2fed7b7 100644 --- a/drivers/spi/ich.c +++ b/drivers/spi/ich.c @@ -5,6 +5,7 @@ * * This file is derived from the flashrom project. */ + #include <common.h> #include <dm.h> #include <errno.h> @@ -17,8 +18,7 @@ #include "ich.h" -#define SPI_OPCODE_WREN 0x06 -#define SPI_OPCODE_FAST_READ 0x0b +DECLARE_GLOBAL_DATA_PTR; #ifdef DEBUG_TRACE #define debug_trace(fmt, args...) debug(fmt, ##args) @@ -26,32 +26,6 @@ #define debug_trace(x, args...) #endif -struct ich_spi_platdata { - enum pch_version ich_version; /* Controller version, 7 or 9 */ -}; - -struct ich_spi_priv { - int ichspi_lock; - int locked; - int opmenu; - int menubytes; - void *base; /* Base of register set */ - int preop; - int optype; - int addr; - int data; - unsigned databytes; - int status; - int control; - int bbar; - int bcr; - uint32_t *pr; /* only for ich9 */ - int speed; /* pointer to speed control */ - ulong max_speed; /* Maximum bus speed in MHz */ - ulong cur_speed; /* Current bus speed */ - struct spi_trans trans; /* current transaction in progress */ -}; - static u8 ich_readb(struct ich_spi_priv *priv, int reg) { u8 value = readb(priv->base + reg); @@ -145,11 +119,11 @@ static int ich_init_controller(struct udevice *dev, void *sbase; /* SBASE is similar */ - pch_get_sbase(dev->parent, &sbase_addr); + pch_get_spi_base(dev->parent, &sbase_addr); sbase = (void *)sbase_addr; debug("%s: sbase=%p\n", __func__, sbase); - if (plat->ich_version == PCHV_7) { + if (plat->ich_version == ICHV_7) { struct ich7_spi_regs *ich7_spi = sbase; ich7_spi = (struct ich7_spi_regs *)sbase; @@ -165,7 +139,7 @@ static int ich_init_controller(struct udevice *dev, ctlr->bbar = offsetof(struct ich7_spi_regs, bbar); ctlr->preop = offsetof(struct ich7_spi_regs, preop); ctlr->base = ich7_spi; - } else if (plat->ich_version == PCHV_9) { + } else if (plat->ich_version == ICHV_9) { struct ich9_spi_regs *ich9_spi = sbase; ctlr->ichspi_lock = readw(&ich9_spi->hsfs) & HSFS_FLOCKDN; @@ -191,7 +165,7 @@ static int ich_init_controller(struct udevice *dev, /* Work out the maximum speed we can support */ ctlr->max_speed = 20000000; - if (plat->ich_version == PCHV_9 && ich9_can_do_33mhz(dev)) + if (plat->ich_version == ICHV_9 && ich9_can_do_33mhz(dev)) ctlr->max_speed = 33000000; debug("ICH SPI: Version ID %d detected at %p, speed %ld\n", plat->ich_version, ctlr->base, ctlr->max_speed); @@ -217,7 +191,7 @@ static void spi_setup_type(struct spi_trans *trans, int data_bytes) { trans->type = 0xFF; - /* Try to guess spi type from read/write sizes. */ + /* Try to guess spi type from read/write sizes */ if (trans->bytesin == 0) { if (trans->bytesout + data_bytes > 4) /* @@ -301,7 +275,7 @@ static int spi_setup_opcode(struct ich_spi_priv *ctlr, struct spi_trans *trans) static int spi_setup_offset(struct spi_trans *trans) { - /* Separate the SPI address and data. */ + /* Separate the SPI address and data */ switch (trans->type) { case SPI_OPCODE_TYPE_READ_NO_ADDRESS: case SPI_OPCODE_TYPE_WRITE_NO_ADDRESS: @@ -410,7 +384,7 @@ static int ich_spi_xfer(struct udevice *dev, unsigned int bitlen, trans->in = din; trans->bytesin = din ? bytes : 0; - /* There has to always at least be an opcode. */ + /* There has to always at least be an opcode */ if (!trans->bytesout) { debug("ICH SPI: No opcode for transfer\n"); return -EPROTO; @@ -420,7 +394,7 @@ static int ich_spi_xfer(struct udevice *dev, unsigned int bitlen, if (ret < 0) return ret; - if (plat->ich_version == PCHV_7) + if (plat->ich_version == ICHV_7) ich_writew(ctlr, SPIS_CDS | SPIS_FCERR, ctlr->status); else ich_writeb(ctlr, SPIS_CDS | SPIS_FCERR, ctlr->status); @@ -541,7 +515,7 @@ static int ich_spi_xfer(struct udevice *dev, unsigned int bitlen, /* write it */ ich_writew(ctlr, control, ctlr->control); - /* Wait for Cycle Done Status or Flash Cycle Error. */ + /* Wait for Cycle Done Status or Flash Cycle Error */ status = ich_status_poll(ctlr, SPIS_CDS | SPIS_FCERR, 1); if (status < 0) return status; @@ -622,9 +596,6 @@ static int ich_spi_probe(struct udevice *dev) uint8_t bios_cntl; int ret; - /* Check the ICH version */ - plat->ich_version = pch_get_version(dev->parent); - ret = ich_init_controller(dev, plat, priv); if (ret) return ret; @@ -678,7 +649,7 @@ static int ich_spi_child_pre_probe(struct udevice *dev) * ICH 7 SPI controller only supports array read command * and byte program command for SST flash */ - if (plat->ich_version == PCHV_7) { + if (plat->ich_version == ICHV_7) { slave->mode_rx = SPI_RX_SLOW; slave->mode = SPI_TX_BYTE; } @@ -686,6 +657,25 @@ static int ich_spi_child_pre_probe(struct udevice *dev) return 0; } +static int ich_spi_ofdata_to_platdata(struct udevice *dev) +{ + struct ich_spi_platdata *plat = dev_get_platdata(dev); + int ret; + + ret = fdt_node_check_compatible(gd->fdt_blob, dev->of_offset, + "intel,ich7-spi"); + if (ret == 0) { + plat->ich_version = ICHV_7; + } else { + ret = fdt_node_check_compatible(gd->fdt_blob, dev->of_offset, + "intel,ich9-spi"); + if (ret == 0) + plat->ich_version = ICHV_9; + } + + return ret; +} + static const struct dm_spi_ops ich_spi_ops = { .xfer = ich_spi_xfer, .set_speed = ich_spi_set_speed, @@ -697,7 +687,8 @@ static const struct dm_spi_ops ich_spi_ops = { }; static const struct udevice_id ich_spi_ids[] = { - { .compatible = "intel,ich-spi" }, + { .compatible = "intel,ich7-spi" }, + { .compatible = "intel,ich9-spi" }, { } }; @@ -706,6 +697,7 @@ U_BOOT_DRIVER(ich_spi) = { .id = UCLASS_SPI, .of_match = ich_spi_ids, .ops = &ich_spi_ops, + .ofdata_to_platdata = ich_spi_ofdata_to_platdata, .platdata_auto_alloc_size = sizeof(struct ich_spi_platdata), .priv_auto_alloc_size = sizeof(struct ich_spi_priv), .child_pre_probe = ich_spi_child_pre_probe, diff --git a/drivers/spi/ich.h b/drivers/spi/ich.h index 1419b23e11..bd0a820809 100644 --- a/drivers/spi/ich.h +++ b/drivers/spi/ich.h @@ -6,6 +6,9 @@ * This file is derived from the flashrom project. */ +#ifndef _ICH_H_ +#define _ICH_H_ + struct ich7_spi_regs { uint16_t spis; uint16_t spic; @@ -19,34 +22,34 @@ struct ich7_spi_regs { } __packed; struct ich9_spi_regs { - uint32_t bfpr; /* 0x00 */ + uint32_t bfpr; /* 0x00 */ uint16_t hsfs; uint16_t hsfc; uint32_t faddr; uint32_t _reserved0; - uint32_t fdata[16]; /* 0x10 */ - uint32_t frap; /* 0x50 */ + uint32_t fdata[16]; /* 0x10 */ + uint32_t frap; /* 0x50 */ uint32_t freg[5]; uint32_t _reserved1[3]; - uint32_t pr[5]; /* 0x74 */ + uint32_t pr[5]; /* 0x74 */ uint32_t _reserved2[2]; - uint8_t ssfs; /* 0x90 */ + uint8_t ssfs; /* 0x90 */ uint8_t ssfc[3]; - uint16_t preop; /* 0x94 */ + uint16_t preop; /* 0x94 */ uint16_t optype; - uint8_t opmenu[8]; /* 0x98 */ + uint8_t opmenu[8]; /* 0x98 */ uint32_t bbar; uint8_t _reserved3[12]; - uint32_t fdoc; /* 0xb0 */ + uint32_t fdoc; /* 0xb0 */ uint32_t fdod; uint8_t _reserved4[8]; - uint32_t afc; /* 0xc0 */ + uint32_t afc; /* 0xc0 */ uint32_t lvscc; uint32_t uvscc; uint8_t _reserved5[4]; - uint32_t fpb; /* 0xd0 */ + uint32_t fpb; /* 0xd0 */ uint8_t _reserved6[28]; - uint32_t srdl; /* 0xf0 */ + uint32_t srdl; /* 0xf0 */ uint32_t srdc; uint32_t scs; uint32_t bcr; @@ -121,8 +124,38 @@ struct spi_trans { uint32_t offset; }; -struct ich_spi_slave { - struct spi_slave slave; +#define SPI_OPCODE_WREN 0x06 +#define SPI_OPCODE_FAST_READ 0x0b + +enum ich_version { + ICHV_7, + ICHV_9, +}; + +struct ich_spi_platdata { + enum ich_version ich_version; /* Controller version, 7 or 9 */ +}; + +struct ich_spi_priv { + int ichspi_lock; + int locked; + int opmenu; + int menubytes; + void *base; /* Base of register set */ + int preop; + int optype; + int addr; + int data; + unsigned databytes; + int status; + int control; + int bbar; + int bcr; + uint32_t *pr; /* only for ich9 */ + int speed; /* pointer to speed control */ + ulong max_speed; /* Maximum bus speed in MHz */ + ulong cur_speed; /* Current bus speed */ struct spi_trans trans; /* current transaction in progress */ - int speed; /* SPI speed in Hz */ }; + +#endif /* _ICH_H_ */ diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c index a13b21d0a0..60f9272ae6 100644 --- a/drivers/usb/gadget/composite.c +++ b/drivers/usb/gadget/composite.c @@ -2,7 +2,7 @@ * composite.c - infrastructure for Composite USB Gadgets * * Copyright (C) 2006-2008 David Brownell - * U-boot porting: Lukasz Majewski <l.majewski@samsung.com> + * U-Boot porting: Lukasz Majewski <l.majewski@samsung.com> * * SPDX-License-Identifier: GPL-2.0+ */ diff --git a/drivers/usb/gadget/config.c b/drivers/usb/gadget/config.c index 014a6791c1..64284b06f8 100644 --- a/drivers/usb/gadget/config.c +++ b/drivers/usb/gadget/config.c @@ -5,7 +5,7 @@ * * SPDX-License-Identifier: GPL-2.0+ * - * Ported to U-boot by: Thomas Smits <ts.smits@gmail.com> and + * Ported to U-Boot by: Thomas Smits <ts.smits@gmail.com> and * Remy Bohmer <linux@bohmer.net> */ diff --git a/drivers/usb/gadget/dwc2_udc_otg.c b/drivers/usb/gadget/dwc2_udc_otg.c index ffe2952f56..cb20b00a56 100644 --- a/drivers/usb/gadget/dwc2_udc_otg.c +++ b/drivers/usb/gadget/dwc2_udc_otg.c @@ -557,8 +557,8 @@ static int dwc2_ep_enable(struct usb_ep *_ep, } /* hardware _could_ do smaller, but driver doesn't */ - if ((desc->bmAttributes == USB_ENDPOINT_XFER_BULK - && le16_to_cpu(get_unaligned(&desc->wMaxPacketSize)) != + if ((desc->bmAttributes == USB_ENDPOINT_XFER_BULK && + le16_to_cpu(get_unaligned(&desc->wMaxPacketSize)) > ep_maxpacket(ep)) || !get_unaligned(&desc->wMaxPacketSize)) { debug("%s: bad %s maxpacket\n", __func__, _ep->name); diff --git a/drivers/usb/gadget/epautoconf.c b/drivers/usb/gadget/epautoconf.c index 6ddbe83deb..a53a6dcda3 100644 --- a/drivers/usb/gadget/epautoconf.c +++ b/drivers/usb/gadget/epautoconf.c @@ -7,7 +7,7 @@ * * SPDX-License-Identifier: GPL-2.0+ * - * Ported to U-boot by: Thomas Smits <ts.smits@gmail.com> and + * Ported to U-Boot by: Thomas Smits <ts.smits@gmail.com> and * Remy Bohmer <linux@bohmer.net> */ diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c index cfe9a24e24..9b06f028d6 100644 --- a/drivers/usb/gadget/ether.c +++ b/drivers/usb/gadget/ether.c @@ -256,7 +256,7 @@ static inline int BITRATE(struct usb_gadget *g) #if defined(CONFIG_USBNET_MANUFACTURER) static char *iManufacturer = CONFIG_USBNET_MANUFACTURER; #else -static char *iManufacturer = "U-boot"; +static char *iManufacturer = "U-Boot"; #endif /* These probably need to be configurable. */ diff --git a/drivers/usb/gadget/gadget_chips.h b/drivers/usb/gadget/gadget_chips.h index e9811c3864..973cd971ad 100644 --- a/drivers/usb/gadget/gadget_chips.h +++ b/drivers/usb/gadget/gadget_chips.h @@ -11,7 +11,7 @@ * Some are available on 2.4 kernels; several are available, but not * yet pushed in the 2.6 mainline tree. * - * Ported to U-boot by: Thomas Smits <ts.smits@gmail.com> and + * Ported to U-Boot by: Thomas Smits <ts.smits@gmail.com> and * Remy Bohmer <linux@bohmer.net> */ #ifdef CONFIG_USB_GADGET_NET2280 diff --git a/drivers/usb/gadget/usbstring.c b/drivers/usb/gadget/usbstring.c index 8c3ff64fe3..3e24fbf80e 100644 --- a/drivers/usb/gadget/usbstring.c +++ b/drivers/usb/gadget/usbstring.c @@ -3,7 +3,7 @@ * * SPDX-License-Identifier: LGPL-2.1+ * - * Ported to U-boot by: Thomas Smits <ts.smits@gmail.com> and + * Ported to U-Boot by: Thomas Smits <ts.smits@gmail.com> and * Remy Bohmer <linux@bohmer.net> */ diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index 39f7185e86..9332374193 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig @@ -74,13 +74,6 @@ config USB_EHCI_MX6 ---help--- Enables support for the on-chip EHCI controller on i.MX6 SoCs. -config USB_EHCI_UNIPHIER - bool "Support for UniPhier on-chip EHCI USB controller" - depends on ARCH_UNIPHIER && OF_CONTROL - default y - ---help--- - Enables support for the on-chip EHCI controller on UniPhier SoCs. - config USB_EHCI_GENERIC bool "Support for generic EHCI USB controller" depends on OF_CONTROL diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile index 6183b80c75..9a87d2bf62 100644 --- a/drivers/usb/host/Makefile +++ b/drivers/usb/host/Makefile @@ -47,7 +47,6 @@ obj-$(CONFIG_USB_EHCI_PCI) += ehci-pci.o obj-$(CONFIG_USB_EHCI_SPEAR) += ehci-spear.o obj-$(CONFIG_USB_EHCI_SUNXI) += ehci-sunxi.o obj-$(CONFIG_USB_EHCI_TEGRA) += ehci-tegra.o -obj-$(CONFIG_USB_EHCI_UNIPHIER) += ehci-uniphier.o obj-$(CONFIG_USB_EHCI_VCT) += ehci-vct.o obj-$(CONFIG_USB_EHCI_VF) += ehci-vf.o obj-$(CONFIG_USB_EHCI_RMOBILE) += ehci-rmobile.o diff --git a/drivers/usb/host/ehci-atmel.c b/drivers/usb/host/ehci-atmel.c index 9a8f004ece..1d7d28048b 100644 --- a/drivers/usb/host/ehci-atmel.c +++ b/drivers/usb/host/ehci-atmel.c @@ -7,44 +7,21 @@ */ #include <common.h> -#include <watchdog.h> #include <usb.h> #include <asm/io.h> -#include <asm/arch/hardware.h> -#include <asm/arch/at91_pmc.h> #include <asm/arch/clk.h> #include "ehci.h" -/* Enable UTMI PLL time out 500us - * 10 times as datasheet specified - */ -#define EN_UPLL_TIMEOUT 500UL - int ehci_hcd_init(int index, enum usb_init_type init, struct ehci_hccr **hccr, struct ehci_hcor **hcor) { - at91_pmc_t *pmc = (at91_pmc_t *)ATMEL_BASE_PMC; - ulong start_time, tmp_time; - - start_time = get_timer(0); /* Enable UTMI PLL */ - writel(AT91_PMC_UPLLEN | AT91_PMC_BIASEN, &pmc->uckr); - while ((readl(&pmc->sr) & AT91_PMC_LOCKU) != AT91_PMC_LOCKU) { - WATCHDOG_RESET(); - tmp_time = get_timer(0); - if ((tmp_time - start_time) > EN_UPLL_TIMEOUT) { - printf("ERROR: failed to enable UPLL\n"); - return -1; - } - } + if (at91_upll_clk_enable()) + return -1; /* Enable USB Host clock */ -#ifdef CPU_HAS_PCR at91_periph_clk_enable(ATMEL_ID_UHPHS); -#else - writel(1 << ATMEL_ID_UHPHS, &pmc->pcer); -#endif *hccr = (struct ehci_hccr *)ATMEL_BASE_EHCI; *hcor = (struct ehci_hcor *)((uint32_t)*hccr + @@ -55,27 +32,12 @@ int ehci_hcd_init(int index, enum usb_init_type init, int ehci_hcd_stop(int index) { - at91_pmc_t *pmc = (at91_pmc_t *)ATMEL_BASE_PMC; - ulong start_time, tmp_time; - /* Disable USB Host Clock */ -#ifdef CPU_HAS_PCR at91_periph_clk_disable(ATMEL_ID_UHPHS); -#else - writel(1 << ATMEL_ID_UHPHS, &pmc->pcdr); -#endif - start_time = get_timer(0); /* Disable UTMI PLL */ - writel(readl(&pmc->uckr) & ~AT91_PMC_UPLLEN, &pmc->uckr); - while ((readl(&pmc->sr) & AT91_PMC_LOCKU) == AT91_PMC_LOCKU) { - WATCHDOG_RESET(); - tmp_time = get_timer(0); - if ((tmp_time - start_time) > EN_UPLL_TIMEOUT) { - printf("ERROR: failed to stop UPLL\n"); - return -1; - } - } + if (at91_upll_clk_disable()) + return -1; return 0; } diff --git a/drivers/usb/host/ehci-uniphier.c b/drivers/usb/host/ehci-uniphier.c deleted file mode 100644 index c3f827ca0a..0000000000 --- a/drivers/usb/host/ehci-uniphier.c +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright (C) 2014-2015 Masahiro Yamada <yamada.masahiro@socionext.com> - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#include <common.h> -#include <linux/err.h> -#include <linux/io.h> -#include <usb.h> -#include <mach/mio-regs.h> -#include <fdtdec.h> -#include "ehci.h" - -DECLARE_GLOBAL_DATA_PTR; - -#define FDT gd->fdt_blob -#define COMPAT "socionext,uniphier-ehci" - -static int get_uniphier_ehci_base(int index, struct ehci_hccr **base) -{ - int offset; - - for (offset = fdt_node_offset_by_compatible(FDT, 0, COMPAT); - offset >= 0; - offset = fdt_node_offset_by_compatible(FDT, offset, COMPAT)) { - if (index == 0) { - *base = (struct ehci_hccr *) - fdtdec_get_addr(FDT, offset, "reg"); - return 0; - } - index--; - } - - return -ENODEV; /* not found */ -} - -static void uniphier_ehci_reset(int index, int on) -{ - u32 tmp; - - tmp = readl(MIO_USB_RSTCTRL(index)); - if (on) - tmp &= ~MIO_USB_RSTCTRL_XRST; - else - tmp |= MIO_USB_RSTCTRL_XRST; - writel(tmp, MIO_USB_RSTCTRL(index)); -} - -int ehci_hcd_init(int index, enum usb_init_type init, struct ehci_hccr **hccr, - struct ehci_hcor **hcor) -{ - int ret; - struct ehci_hccr *cr; - struct ehci_hcor *or; - - uniphier_ehci_reset(index, 0); - - ret = get_uniphier_ehci_base(index, &cr); - if (ret < 0) - return ret; - or = (void *)cr + HC_LENGTH(ehci_readl(&cr->cr_capbase)); - - *hccr = cr; - *hcor = or; - - return 0; -} - -int ehci_hcd_stop(int index) -{ - uniphier_ehci_reset(index, 1); - - return 0; -} diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c index 820e2e56ef..e030a0ab14 100644 --- a/drivers/usb/host/ohci-at91.c +++ b/drivers/usb/host/ohci-at91.c @@ -9,45 +9,29 @@ #if defined(CONFIG_USB_OHCI_NEW) && defined(CONFIG_SYS_USB_OHCI_CPU_INIT) -#include <asm/io.h> -#include <asm/arch/hardware.h> -#include <asm/arch/at91_pmc.h> #include <asm/arch/clk.h> int usb_cpu_init(void) { - at91_pmc_t *pmc = (at91_pmc_t *)ATMEL_BASE_PMC; - #ifdef CONFIG_USB_ATMEL_CLK_SEL_PLLB - /* Enable PLLB */ - writel(get_pllb_init(), &pmc->pllbr); - while ((readl(&pmc->sr) & AT91_PMC_LOCKB) != AT91_PMC_LOCKB) - ; + if (at91_pllb_clk_enable(get_pllb_init())) + return -1; + #ifdef CONFIG_AT91SAM9N12 - writel(AT91_PMC_USBS_USB_PLLB | AT91_PMC_USB_DIV_2, &pmc->usb); + at91_usb_clk_init(AT91_PMC_USBS_USB_PLLB | AT91_PMC_USB_DIV_2); #endif #elif defined(CONFIG_USB_ATMEL_CLK_SEL_UPLL) - /* Enable UPLL */ - writel(readl(&pmc->uckr) | AT91_PMC_UPLLEN | AT91_PMC_BIASEN, - &pmc->uckr); - while ((readl(&pmc->sr) & AT91_PMC_LOCKU) != AT91_PMC_LOCKU) - ; - - /* Select PLLA as input clock of OHCI */ - writel(AT91_PMC_USBS_USB_UPLL | AT91_PMC_USBDIV_10, &pmc->usb); + if (at91_upll_clk_enable()) + return -1; + + at91_usb_clk_init(AT91_PMC_USBS_USB_UPLL | AT91_PMC_USBDIV_10); #endif - /* Enable USB host clock. */ -#ifdef CPU_HAS_PCR at91_periph_clk_enable(ATMEL_ID_UHP); -#else - writel(1 << ATMEL_ID_UHP, &pmc->pcer); -#endif + at91_system_clk_enable(ATMEL_PMC_UHP); #if defined(CONFIG_AT91SAM9261) || defined(CONFIG_AT91SAM9G10) - writel(ATMEL_PMC_UHP | AT91_PMC_HCK0, &pmc->scer); -#else - writel(ATMEL_PMC_UHP, &pmc->scer); + at91_system_clk_enable(AT91_PMC_HCK0); #endif return 0; @@ -55,34 +39,24 @@ int usb_cpu_init(void) int usb_cpu_stop(void) { - at91_pmc_t *pmc = (at91_pmc_t *)ATMEL_BASE_PMC; - - /* Disable USB host clock. */ -#ifdef CPU_HAS_PCR at91_periph_clk_disable(ATMEL_ID_UHP); -#else - writel(1 << ATMEL_ID_UHP, &pmc->pcdr); -#endif + at91_system_clk_disable(ATMEL_PMC_UHP); #if defined(CONFIG_AT91SAM9261) || defined(CONFIG_AT91SAM9G10) - writel(ATMEL_PMC_UHP | AT91_PMC_HCK0, &pmc->scdr); -#else - writel(ATMEL_PMC_UHP, &pmc->scdr); + at91_system_clk_disable(AT91_PMC_HCK0); #endif #ifdef CONFIG_USB_ATMEL_CLK_SEL_PLLB #ifdef CONFIG_AT91SAM9N12 - writel(0, &pmc->usb); + at91_usb_clk_init(0); #endif - /* Disable PLLB */ - writel(0, &pmc->pllbr); - while ((readl(&pmc->sr) & AT91_PMC_LOCKB) != 0) - ; + + if (at91_pllb_clk_disable()) + return -1; + #elif defined(CONFIG_USB_ATMEL_CLK_SEL_UPLL) - /* Disable UPLL */ - writel(readl(&pmc->uckr) & (~AT91_PMC_UPLLEN), &pmc->uckr); - while ((readl(&pmc->sr) & AT91_PMC_LOCKU) == AT91_PMC_LOCKU) - ; + if (at91_upll_clk_disable()) + return -1; #endif return 0; diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index fbc5d7cfe7..ff4179fcd8 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -91,6 +91,16 @@ config CONSOLE_TRUETYPE_SIZE source "drivers/video/fonts/Kconfig" +config VIDCONSOLE_AS_LCD + bool "Use 'vidconsole' when 'lcd' is seen in stdout" + depends on DM_VIDEO + help + This is a work-around for boards which have 'lcd' in their stdout + environment variable, but have moved to use driver model for video. + In this case the console will no-longer work. While it is possible + to update the environment, the breakage may be confusing for users. + This option will be removed around the end of 2016. + config VIDEO_VESA bool "Enable VESA video driver support" default n @@ -371,8 +381,18 @@ config VIDEO_SANDBOX_SDL console device and can display stdout output. Within U-Boot is is a normal bitmap display and can display images as well as text. +config VIDEO_TEGRA20 + bool "Enable LCD support on Tegra20" + depends on OF_CONTROL + help + Tegra20 supports video output to an attached LCD panel as well as + other options such as HDMI. Only the LCD is supported in U-Boot. + This option enables this support which can be used on devices which + have an LCD display connected. + config VIDEO_TEGRA124 bool "Enable video support on Tegra124" + depends on DM_VIDEO help Tegra124 supports many video output options including eDP and HDMI. At present only eDP is supported by U-Boot. This option diff --git a/drivers/video/Makefile b/drivers/video/Makefile index c55e6eda3b..d19a1d9042 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile @@ -57,7 +57,7 @@ obj-$(CONFIG_VIDEO_SED13806) += sed13806.o obj-$(CONFIG_VIDEO_SM501) += sm501.o obj-$(CONFIG_VIDEO_SMI_LYNXEM) += smiLynxEM.o videomodes.o obj-$(CONFIG_VIDEO_SUNXI) += sunxi_display.o videomodes.o -obj-$(CONFIG_VIDEO_TEGRA) += tegra.o +obj-$(CONFIG_VIDEO_TEGRA20) += tegra.o obj-$(CONFIG_VIDEO_VCXK) += bus_vcxk.o obj-$(CONFIG_VIDEO_VESA) += vesa_fb.o obj-$(CONFIG_FORMIKE) += formike.o diff --git a/drivers/video/bcm2835.c b/drivers/video/bcm2835.c index 7867fe3895..bff1fcb9ea 100644 --- a/drivers/video/bcm2835.c +++ b/drivers/video/bcm2835.c @@ -7,6 +7,7 @@ #include <common.h> #include <lcd.h> #include <memalign.h> +#include <phys2bus.h> #include <asm/arch/mbox.h> #include <asm/global_data.h> @@ -103,7 +104,8 @@ void lcd_ctrl_init(void *lcdbase) panel_info.vl_row = h; panel_info.vl_bpix = LCD_COLOR16; - gd->fb_base = msg_setup->allocate_buffer.body.resp.fb_address; + gd->fb_base = bus_to_phys( + msg_setup->allocate_buffer.body.resp.fb_address); } void lcd_enable(void) diff --git a/drivers/video/simple_panel.c b/drivers/video/simple_panel.c index b161517674..c73f24295a 100644 --- a/drivers/video/simple_panel.c +++ b/drivers/video/simple_panel.c @@ -85,6 +85,7 @@ static const struct panel_ops simple_panel_ops = { static const struct udevice_id simple_panel_ids[] = { { .compatible = "simple-panel" }, + { .compatible = "auo,b133xtn01" }, { } }; diff --git a/drivers/video/tegra.c b/drivers/video/tegra.c index 8e8134614e..7fd10e6af3 100644 --- a/drivers/video/tegra.c +++ b/drivers/video/tegra.c @@ -4,11 +4,13 @@ */ #include <common.h> +#include <dm.h> #include <fdtdec.h> -#include <lcd.h> - +#include <pwm.h> +#include <video.h> #include <asm/system.h> #include <asm/gpio.h> +#include <asm/io.h> #include <asm/arch/clock.h> #include <asm/arch/funcmux.h> @@ -30,165 +32,347 @@ enum stage_t { STAGE_DONE, }; -static enum stage_t stage; /* Current stage we are at */ -static unsigned long timer_next; /* Time we can move onto next stage */ +#define FDT_LCD_TIMINGS 4 + +enum { + FDT_LCD_TIMING_REF_TO_SYNC, + FDT_LCD_TIMING_SYNC_WIDTH, + FDT_LCD_TIMING_BACK_PORCH, + FDT_LCD_TIMING_FRONT_PORCH, + + FDT_LCD_TIMING_COUNT, +}; + +enum lcd_cache_t { + FDT_LCD_CACHE_OFF = 0, + FDT_LCD_CACHE_WRITE_THROUGH = 1 << 0, + FDT_LCD_CACHE_WRITE_BACK = 1 << 1, + FDT_LCD_CACHE_FLUSH = 1 << 2, + FDT_LCD_CACHE_WRITE_BACK_FLUSH = FDT_LCD_CACHE_WRITE_BACK | + FDT_LCD_CACHE_FLUSH, +}; + +/* Information about the display controller */ +struct tegra_lcd_priv { + enum stage_t stage; /* Current stage we are at */ + unsigned long timer_next; /* Time we can move onto next stage */ + int width; /* width in pixels */ + int height; /* height in pixels */ -/* Our LCD config, set up in handle_stage() */ -static struct fdt_panel_config config; -struct fdt_disp_config *disp_config; /* Display controller config */ + /* + * log2 of number of bpp, in general, unless it bpp is 24 in which + * case this field holds 24 also! This is a U-Boot thing. + */ + int log2_bpp; + struct disp_ctlr *disp; /* Display controller to use */ + fdt_addr_t frame_buffer; /* Address of frame buffer */ + unsigned pixel_clock; /* Pixel clock in Hz */ + uint horiz_timing[FDT_LCD_TIMING_COUNT]; /* Horizontal timing */ + uint vert_timing[FDT_LCD_TIMING_COUNT]; /* Vertical timing */ + struct udevice *pwm; + int pwm_channel; /* PWM channel to use for backlight */ + enum lcd_cache_t cache_type; + + struct gpio_desc backlight_en; /* GPIO for backlight enable */ + struct gpio_desc lvds_shutdown; /* GPIO for lvds shutdown */ + struct gpio_desc backlight_vdd; /* GPIO for backlight vdd */ + struct gpio_desc panel_vdd; /* GPIO for panel vdd */ + /* + * Panel required timings + * Timing 1: delay between panel_vdd-rise and data-rise + * Timing 2: delay between data-rise and backlight_vdd-rise + * Timing 3: delay between backlight_vdd and pwm-rise + * Timing 4: delay between pwm-rise and backlight_en-rise + */ + uint panel_timings[FDT_LCD_TIMINGS]; +}; enum { /* Maximum LCD size we support */ LCD_MAX_WIDTH = 1366, LCD_MAX_HEIGHT = 768, - LCD_MAX_LOG2_BPP = 4, /* 2^4 = 16 bpp */ + LCD_MAX_LOG2_BPP = VIDEO_BPP16, }; -vidinfo_t panel_info = { - /* Insert a value here so that we don't end up in the BSS */ - .vl_col = -1, -}; +static void update_window(struct dc_ctlr *dc, struct disp_ctl_win *win) +{ + unsigned h_dda, v_dda; + unsigned long val; -#if !CONFIG_IS_ENABLED(OF_CONTROL) -#error "You must enable CONFIG_OF_CONTROL to get Tegra LCD support" -#endif + val = readl(&dc->cmd.disp_win_header); + val |= WINDOW_A_SELECT; + writel(val, &dc->cmd.disp_win_header); -static void update_panel_size(struct fdt_disp_config *config) -{ - panel_info.vl_col = config->width; - panel_info.vl_row = config->height; - panel_info.vl_bpix = config->log2_bpp; + writel(win->fmt, &dc->win.color_depth); + + clrsetbits_le32(&dc->win.byte_swap, BYTE_SWAP_MASK, + BYTE_SWAP_NOSWAP << BYTE_SWAP_SHIFT); + + val = win->out_x << H_POSITION_SHIFT; + val |= win->out_y << V_POSITION_SHIFT; + writel(val, &dc->win.pos); + + val = win->out_w << H_SIZE_SHIFT; + val |= win->out_h << V_SIZE_SHIFT; + writel(val, &dc->win.size); + + val = (win->w * win->bpp / 8) << H_PRESCALED_SIZE_SHIFT; + val |= win->h << V_PRESCALED_SIZE_SHIFT; + writel(val, &dc->win.prescaled_size); + + writel(0, &dc->win.h_initial_dda); + writel(0, &dc->win.v_initial_dda); + + h_dda = (win->w * 0x1000) / max(win->out_w - 1, 1U); + v_dda = (win->h * 0x1000) / max(win->out_h - 1, 1U); + + val = h_dda << H_DDA_INC_SHIFT; + val |= v_dda << V_DDA_INC_SHIFT; + writel(val, &dc->win.dda_increment); + + writel(win->stride, &dc->win.line_stride); + writel(0, &dc->win.buf_stride); + + val = WIN_ENABLE; + if (win->bpp < 24) + val |= COLOR_EXPAND; + writel(val, &dc->win.win_opt); + + writel((unsigned long)win->phys_addr, &dc->winbuf.start_addr); + writel(win->x, &dc->winbuf.addr_h_offset); + writel(win->y, &dc->winbuf.addr_v_offset); + + writel(0xff00, &dc->win.blend_nokey); + writel(0xff00, &dc->win.blend_1win); + + val = GENERAL_ACT_REQ | WIN_A_ACT_REQ; + val |= GENERAL_UPDATE | WIN_A_UPDATE; + writel(val, &dc->cmd.state_ctrl); } -/* - * Main init function called by lcd driver. - * Inits and then prints test pattern if required. - */ +static void write_pair(struct tegra_lcd_priv *priv, int item, u32 *reg) +{ + writel(priv->horiz_timing[item] | + (priv->vert_timing[item] << 16), reg); +} -void lcd_ctrl_init(void *lcdbase) +static int update_display_mode(struct dc_disp_reg *disp, + struct tegra_lcd_priv *priv) { - int type = DCACHE_OFF; - int size; + unsigned long val; + unsigned long rate; + unsigned long div; - assert(disp_config); + writel(0x0, &disp->disp_timing_opt); + write_pair(priv, FDT_LCD_TIMING_REF_TO_SYNC, &disp->ref_to_sync); + write_pair(priv, FDT_LCD_TIMING_SYNC_WIDTH, &disp->sync_width); + write_pair(priv, FDT_LCD_TIMING_BACK_PORCH, &disp->back_porch); + write_pair(priv, FDT_LCD_TIMING_FRONT_PORCH, &disp->front_porch); - /* Make sure that we can acommodate the selected LCD */ - assert(disp_config->width <= LCD_MAX_WIDTH); - assert(disp_config->height <= LCD_MAX_HEIGHT); - assert(disp_config->log2_bpp <= LCD_MAX_LOG2_BPP); - if (disp_config->width <= LCD_MAX_WIDTH - && disp_config->height <= LCD_MAX_HEIGHT - && disp_config->log2_bpp <= LCD_MAX_LOG2_BPP) - update_panel_size(disp_config); - size = lcd_get_size(&lcd_line_length); + writel(priv->width | (priv->height << 16), &disp->disp_active); - /* Set up the LCD caching as requested */ - if (config.cache_type & FDT_LCD_CACHE_WRITE_THROUGH) - type = DCACHE_WRITETHROUGH; - else if (config.cache_type & FDT_LCD_CACHE_WRITE_BACK) - type = DCACHE_WRITEBACK; - mmu_set_region_dcache_behaviour(disp_config->frame_buffer, size, type); + val = DE_SELECT_ACTIVE << DE_SELECT_SHIFT; + val |= DE_CONTROL_NORMAL << DE_CONTROL_SHIFT; + writel(val, &disp->data_enable_opt); - /* Enable flushing after LCD writes if requested */ - lcd_set_flush_dcache(config.cache_type & FDT_LCD_CACHE_FLUSH); + val = DATA_FORMAT_DF1P1C << DATA_FORMAT_SHIFT; + val |= DATA_ALIGNMENT_MSB << DATA_ALIGNMENT_SHIFT; + val |= DATA_ORDER_RED_BLUE << DATA_ORDER_SHIFT; + writel(val, &disp->disp_interface_ctrl); + + /* + * The pixel clock divider is in 7.1 format (where the bottom bit + * represents 0.5). Here we calculate the divider needed to get from + * the display clock (typically 600MHz) to the pixel clock. We round + * up or down as requried. + */ + rate = clock_get_periph_rate(PERIPH_ID_DISP1, CLOCK_ID_CGENERAL); + div = ((rate * 2 + priv->pixel_clock / 2) / priv->pixel_clock) - 2; + debug("Display clock %lu, divider %lu\n", rate, div); + + writel(0x00010001, &disp->shift_clk_opt); - debug("LCD frame buffer at %pa\n", &disp_config->frame_buffer); + val = PIXEL_CLK_DIVIDER_PCD1 << PIXEL_CLK_DIVIDER_SHIFT; + val |= div << SHIFT_CLK_DIVIDER_SHIFT; + writel(val, &disp->disp_clk_ctrl); + + return 0; } -ulong calc_fbsize(void) +/* Start up the display and turn on power to PWMs */ +static void basic_init(struct dc_cmd_reg *cmd) { - return (panel_info.vl_col * panel_info.vl_row * - NBITS(panel_info.vl_bpix)) / 8; + u32 val; + + writel(0x00000100, &cmd->gen_incr_syncpt_ctrl); + writel(0x0000011a, &cmd->cont_syncpt_vsync); + writel(0x00000000, &cmd->int_type); + writel(0x00000000, &cmd->int_polarity); + writel(0x00000000, &cmd->int_mask); + writel(0x00000000, &cmd->int_enb); + + val = PW0_ENABLE | PW1_ENABLE | PW2_ENABLE; + val |= PW3_ENABLE | PW4_ENABLE | PM0_ENABLE; + val |= PM1_ENABLE; + writel(val, &cmd->disp_pow_ctrl); + + val = readl(&cmd->disp_cmd); + val |= CTRL_MODE_C_DISPLAY << CTRL_MODE_SHIFT; + writel(val, &cmd->disp_cmd); } -void lcd_setcolreg(ushort regno, ushort red, ushort green, ushort blue) +static void basic_init_timer(struct dc_disp_reg *disp) { + writel(0x00000020, &disp->mem_high_pri); + writel(0x00000001, &disp->mem_high_pri_timer); } -void tegra_lcd_early_init(const void *blob) +static const u32 rgb_enb_tab[PIN_REG_COUNT] = { + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, +}; + +static const u32 rgb_polarity_tab[PIN_REG_COUNT] = { + 0x00000000, + 0x01000000, + 0x00000000, + 0x00000000, +}; + +static const u32 rgb_data_tab[PIN_REG_COUNT] = { + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, +}; + +static const u32 rgb_sel_tab[PIN_OUTPUT_SEL_COUNT] = { + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00210222, + 0x00002200, + 0x00020000, +}; + +static void rgb_enable(struct dc_com_reg *com) { - /* - * Go with the maximum size for now. We will fix this up after - * relocation. These values are only used for memory alocation. - */ - panel_info.vl_col = LCD_MAX_WIDTH; - panel_info.vl_row = LCD_MAX_HEIGHT; - panel_info.vl_bpix = LCD_MAX_LOG2_BPP; + int i; + + for (i = 0; i < PIN_REG_COUNT; i++) { + writel(rgb_enb_tab[i], &com->pin_output_enb[i]); + writel(rgb_polarity_tab[i], &com->pin_output_polarity[i]); + writel(rgb_data_tab[i], &com->pin_output_data[i]); + } + + for (i = 0; i < PIN_OUTPUT_SEL_COUNT; i++) + writel(rgb_sel_tab[i], &com->pin_output_sel[i]); +} + +static int setup_window(struct disp_ctl_win *win, + struct tegra_lcd_priv *priv) +{ + win->x = 0; + win->y = 0; + win->w = priv->width; + win->h = priv->height; + win->out_x = 0; + win->out_y = 0; + win->out_w = priv->width; + win->out_h = priv->height; + win->phys_addr = priv->frame_buffer; + win->stride = priv->width * (1 << priv->log2_bpp) / 8; + debug("%s: depth = %d\n", __func__, priv->log2_bpp); + switch (priv->log2_bpp) { + case 5: + case 24: + win->fmt = COLOR_DEPTH_R8G8B8A8; + win->bpp = 32; + break; + case 4: + win->fmt = COLOR_DEPTH_B5G6R5; + win->bpp = 16; + break; + + default: + debug("Unsupported LCD bit depth"); + return -1; + } + + return 0; +} + +static void debug_timing(const char *name, unsigned int timing[]) +{ +#ifdef DEBUG + int i; + + debug("%s timing: ", name); + for (i = 0; i < FDT_LCD_TIMING_COUNT; i++) + debug("%d ", timing[i]); + debug("\n"); +#endif } /** - * Decode the panel information from the fdt. + * Register a new display based on device tree configuration. * - * @param blob fdt blob - * @param config structure to store fdt config into - * @return 0 if ok, -ve on error + * The frame buffer can be positioned by U-Boot or overriden by the fdt. + * You should pass in the U-Boot address here, and check the contents of + * struct tegra_lcd_priv to see what was actually chosen. + * + * @param blob Device tree blob + * @param priv Driver's private data + * @param default_lcd_base Default address of LCD frame buffer + * @return 0 if ok, -1 on error (unsupported bits per pixel) */ -static int fdt_decode_lcd(const void *blob, struct fdt_panel_config *config) +static int tegra_display_probe(const void *blob, struct tegra_lcd_priv *priv, + void *default_lcd_base) { - int display_node; + struct disp_ctl_win window; + struct dc_ctlr *dc; - disp_config = tegra_display_get_config(); - if (!disp_config) { - debug("%s: Display controller is not configured\n", __func__); - return -1; - } - display_node = disp_config->panel_node; - if (display_node < 0) { - debug("%s: No panel configuration available\n", __func__); - return -1; - } + priv->frame_buffer = (u32)default_lcd_base; - config->pwm_channel = pwm_request(blob, display_node, "nvidia,pwm"); - if (config->pwm_channel < 0) { - debug("%s: Unable to request PWM channel\n", __func__); - return -1; - } + dc = (struct dc_ctlr *)priv->disp; - config->cache_type = fdtdec_get_int(blob, display_node, - "nvidia,cache-type", - FDT_LCD_CACHE_WRITE_BACK_FLUSH); + /* + * A header file for clock constants was NAKed upstream. + * TODO: Put this into the FDT and fdt_lcd struct when we have clock + * support there + */ + clock_start_periph_pll(PERIPH_ID_HOST1X, CLOCK_ID_PERIPH, + 144 * 1000000); + clock_start_periph_pll(PERIPH_ID_DISP1, CLOCK_ID_CGENERAL, + 600 * 1000000); + basic_init(&dc->cmd); + basic_init_timer(&dc->disp); + rgb_enable(&dc->com); + + if (priv->pixel_clock) + update_display_mode(&dc->disp, priv); + + if (setup_window(&window, priv)) + return -1; - /* These GPIOs are all optional */ - gpio_request_by_name_nodev(blob, display_node, - "nvidia,backlight-enable-gpios", 0, - &config->backlight_en, GPIOD_IS_OUT); - gpio_request_by_name_nodev(blob, display_node, - "nvidia,lvds-shutdown-gpios", 0, - &config->lvds_shutdown, GPIOD_IS_OUT); - gpio_request_by_name_nodev(blob, display_node, - "nvidia,backlight-vdd-gpios", 0, - &config->backlight_vdd, GPIOD_IS_OUT); - gpio_request_by_name_nodev(blob, display_node, - "nvidia,panel-vdd-gpios", 0, - &config->panel_vdd, GPIOD_IS_OUT); + update_window(dc, &window); - return fdtdec_get_int_array(blob, display_node, "nvidia,panel-timings", - config->panel_timings, FDT_LCD_TIMINGS); + return 0; } /** * Handle the next stage of device init */ -static int handle_stage(const void *blob) +static int handle_stage(const void *blob, struct tegra_lcd_priv *priv) { - debug("%s: stage %d\n", __func__, stage); + debug("%s: stage %d\n", __func__, priv->stage); /* do the things for this stage */ - switch (stage) { + switch (priv->stage) { case STAGE_START: - /* Initialize the Tegra display controller */ - if (tegra_display_probe(gd->fdt_blob, (void *)gd->fb_base)) { - printf("%s: Failed to probe display driver\n", - __func__); - return -1; - } - - /* get panel details */ - if (fdt_decode_lcd(blob, &config)) { - printf("No valid LCD information in device tree\n"); - return -1; - } - /* * It is possible that the FDT has requested that the LCD be * disabled. We currently don't support this. It would require @@ -202,52 +386,71 @@ static int handle_stage(const void *blob) funcmux_select(PERIPH_ID_DISP1, FUNCMUX_DEFAULT); break; case STAGE_PANEL_VDD: - if (dm_gpio_is_valid(&config.panel_vdd)) - dm_gpio_set_value(&config.panel_vdd, 1); + if (dm_gpio_is_valid(&priv->panel_vdd)) + dm_gpio_set_value(&priv->panel_vdd, 1); break; case STAGE_LVDS: - if (dm_gpio_is_valid(&config.lvds_shutdown)) - dm_gpio_set_value(&config.lvds_shutdown, 1); + if (dm_gpio_is_valid(&priv->lvds_shutdown)) + dm_gpio_set_value(&priv->lvds_shutdown, 1); break; case STAGE_BACKLIGHT_VDD: - if (dm_gpio_is_valid(&config.backlight_vdd)) - dm_gpio_set_value(&config.backlight_vdd, 1); + if (dm_gpio_is_valid(&priv->backlight_vdd)) + dm_gpio_set_value(&priv->backlight_vdd, 1); break; case STAGE_PWM: /* Enable PWM at 15/16 high, 32768 Hz with divider 1 */ pinmux_set_func(PMUX_PINGRP_GPU, PMUX_FUNC_PWM); pinmux_tristate_disable(PMUX_PINGRP_GPU); - pwm_enable(config.pwm_channel, 32768, 0xdf, 1); + pwm_set_config(priv->pwm, priv->pwm_channel, 0xdf, 0xff); + pwm_set_enable(priv->pwm, priv->pwm_channel, true); break; case STAGE_BACKLIGHT_EN: - if (dm_gpio_is_valid(&config.backlight_en)) - dm_gpio_set_value(&config.backlight_en, 1); + if (dm_gpio_is_valid(&priv->backlight_en)) + dm_gpio_set_value(&priv->backlight_en, 1); break; case STAGE_DONE: break; } /* set up timer for next stage */ - timer_next = timer_get_us(); - if (stage < FDT_LCD_TIMINGS) - timer_next += config.panel_timings[stage] * 1000; + priv->timer_next = timer_get_us(); + if (priv->stage < FDT_LCD_TIMINGS) + priv->timer_next += priv->panel_timings[priv->stage] * 1000; /* move to next stage */ - stage++; + priv->stage++; return 0; } -int tegra_lcd_check_next_stage(const void *blob, int wait) +/** + * Perform the next stage of the LCD init if it is time to do so. + * + * LCD init can be time-consuming because of the number of delays we need + * while waiting for the backlight power supply, etc. This function can + * be called at various times during U-Boot operation to advance the + * initialization of the LCD to the next stage if sufficient time has + * passed since the last stage. It keeps track of what stage it is up to + * and the time that it is permitted to move to the next stage. + * + * The final call should have wait=1 to complete the init. + * + * @param blob fdt blob containing LCD information + * @param wait 1 to wait until all init is complete, and then return + * 0 to return immediately, potentially doing nothing if it is + * not yet time for the next init. + */ +static int tegra_lcd_check_next_stage(const void *blob, + struct tegra_lcd_priv *priv, int wait) { - if (stage == STAGE_DONE) + if (priv->stage == STAGE_DONE) return 0; do { /* wait if we need to */ - debug("%s: stage %d\n", __func__, stage); - if (stage != STAGE_START) { - int delay = timer_next - timer_get_us(); + debug("%s: stage %d\n", __func__, priv->stage); + if (priv->stage != STAGE_START) { + int delay = priv->timer_next - timer_get_us(); if (delay > 0) { if (wait) @@ -257,29 +460,188 @@ int tegra_lcd_check_next_stage(const void *blob, int wait) } } - if (handle_stage(blob)) + if (handle_stage(blob, priv)) return -1; - } while (wait && stage != STAGE_DONE); - if (stage == STAGE_DONE) + } while (wait && priv->stage != STAGE_DONE); + if (priv->stage == STAGE_DONE) debug("%s: LCD init complete\n", __func__); return 0; } -void lcd_enable(void) +static int tegra_lcd_probe(struct udevice *dev) { - /* - * Backlight and power init will be done separately in - * tegra_lcd_check_next_stage(), which should be called in - * board_late_init(). - * - * U-Boot code supports only colour depth, selected at compile time. - * The device tree setting should match this. Otherwise the display - * will not look right, and U-Boot may crash. - */ - if (disp_config->log2_bpp != LCD_BPP) { - printf("%s: Error: LCD depth configured in FDT (%d = %dbpp)" - " must match setting of LCD_BPP (%d)\n", __func__, - disp_config->log2_bpp, disp_config->bpp, LCD_BPP); + struct video_uc_platdata *plat = dev_get_uclass_platdata(dev); + struct video_priv *uc_priv = dev_get_uclass_priv(dev); + struct tegra_lcd_priv *priv = dev_get_priv(dev); + const void *blob = gd->fdt_blob; + int type = DCACHE_OFF; + + /* Initialize the Tegra display controller */ + if (tegra_display_probe(blob, priv, (void *)plat->base)) { + printf("%s: Failed to probe display driver\n", __func__); + return -1; } + + tegra_lcd_check_next_stage(blob, priv, 1); + + /* Set up the LCD caching as requested */ + if (priv->cache_type & FDT_LCD_CACHE_WRITE_THROUGH) + type = DCACHE_WRITETHROUGH; + else if (priv->cache_type & FDT_LCD_CACHE_WRITE_BACK) + type = DCACHE_WRITEBACK; + mmu_set_region_dcache_behaviour(priv->frame_buffer, plat->size, type); + + /* Enable flushing after LCD writes if requested */ + video_set_flush_dcache(dev, priv->cache_type & FDT_LCD_CACHE_FLUSH); + + uc_priv->xsize = priv->width; + uc_priv->ysize = priv->height; + uc_priv->bpix = priv->log2_bpp; + debug("LCD frame buffer at %pa, size %x\n", &priv->frame_buffer, + plat->size); + + return 0; } + +static int tegra_lcd_ofdata_to_platdata(struct udevice *dev) +{ + struct tegra_lcd_priv *priv = dev_get_priv(dev); + struct fdtdec_phandle_args args; + const void *blob = gd->fdt_blob; + int node = dev->of_offset; + int front, back, ref; + int panel_node; + int rgb; + int bpp, bit; + int ret; + + priv->disp = (struct disp_ctlr *)dev_get_addr(dev); + if (!priv->disp) { + debug("%s: No display controller address\n", __func__); + return -EINVAL; + } + + rgb = fdt_subnode_offset(blob, node, "rgb"); + + panel_node = fdtdec_lookup_phandle(blob, rgb, "nvidia,panel"); + if (panel_node < 0) { + debug("%s: Cannot find panel information\n", __func__); + return -EINVAL; + } + + priv->width = fdtdec_get_int(blob, panel_node, "xres", -1); + priv->height = fdtdec_get_int(blob, panel_node, "yres", -1); + priv->pixel_clock = fdtdec_get_int(blob, panel_node, "clock", 0); + if (!priv->pixel_clock || priv->width == -1 || priv->height == -1) { + debug("%s: Pixel parameters missing\n", __func__); + return -EINVAL; + } + + back = fdtdec_get_int(blob, panel_node, "left-margin", -1); + front = fdtdec_get_int(blob, panel_node, "right-margin", -1); + ref = fdtdec_get_int(blob, panel_node, "hsync-len", -1); + if ((back | front | ref) == -1) { + debug("%s: Horizontal parameters missing\n", __func__); + return -EINVAL; + } + + /* Use a ref-to-sync of 1 always, and take this from the front porch */ + priv->horiz_timing[FDT_LCD_TIMING_REF_TO_SYNC] = 1; + priv->horiz_timing[FDT_LCD_TIMING_SYNC_WIDTH] = ref; + priv->horiz_timing[FDT_LCD_TIMING_BACK_PORCH] = back; + priv->horiz_timing[FDT_LCD_TIMING_FRONT_PORCH] = front - + priv->horiz_timing[FDT_LCD_TIMING_REF_TO_SYNC]; + debug_timing("horiz", priv->horiz_timing); + + back = fdtdec_get_int(blob, panel_node, "upper-margin", -1); + front = fdtdec_get_int(blob, panel_node, "lower-margin", -1); + ref = fdtdec_get_int(blob, panel_node, "vsync-len", -1); + if ((back | front | ref) == -1) { + debug("%s: Vertical parameters missing\n", __func__); + return -EINVAL; + } + + priv->vert_timing[FDT_LCD_TIMING_REF_TO_SYNC] = 1; + priv->vert_timing[FDT_LCD_TIMING_SYNC_WIDTH] = ref; + priv->vert_timing[FDT_LCD_TIMING_BACK_PORCH] = back; + priv->vert_timing[FDT_LCD_TIMING_FRONT_PORCH] = front - + priv->vert_timing[FDT_LCD_TIMING_REF_TO_SYNC]; + debug_timing("vert", priv->vert_timing); + + bpp = fdtdec_get_int(blob, panel_node, "nvidia,bits-per-pixel", -1); + bit = ffs(bpp) - 1; + if (bpp == (1 << bit)) + priv->log2_bpp = bit; + else + priv->log2_bpp = bpp; + if (bpp == -1) { + debug("%s: Pixel bpp parameters missing\n", __func__); + return -EINVAL; + } + + if (fdtdec_parse_phandle_with_args(blob, panel_node, "nvidia,pwm", + "#pwm-cells", 0, 0, &args)) { + debug("%s: Unable to decode PWM\n", __func__); + return -EINVAL; + } + + ret = uclass_get_device_by_of_offset(UCLASS_PWM, args.node, &priv->pwm); + if (ret) { + debug("%s: Unable to find PWM\n", __func__); + return -EINVAL; + } + priv->pwm_channel = args.args[0]; + + priv->cache_type = fdtdec_get_int(blob, panel_node, "nvidia,cache-type", + FDT_LCD_CACHE_WRITE_BACK_FLUSH); + + /* These GPIOs are all optional */ + gpio_request_by_name_nodev(blob, panel_node, + "nvidia,backlight-enable-gpios", 0, + &priv->backlight_en, GPIOD_IS_OUT); + gpio_request_by_name_nodev(blob, panel_node, + "nvidia,lvds-shutdown-gpios", 0, + &priv->lvds_shutdown, GPIOD_IS_OUT); + gpio_request_by_name_nodev(blob, panel_node, + "nvidia,backlight-vdd-gpios", 0, + &priv->backlight_vdd, GPIOD_IS_OUT); + gpio_request_by_name_nodev(blob, panel_node, + "nvidia,panel-vdd-gpios", 0, + &priv->panel_vdd, GPIOD_IS_OUT); + + if (fdtdec_get_int_array(blob, panel_node, "nvidia,panel-timings", + priv->panel_timings, FDT_LCD_TIMINGS)) + return -EINVAL; + + return 0; +} + +static int tegra_lcd_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 video_ops tegra_lcd_ops = { +}; + +static const struct udevice_id tegra_lcd_ids[] = { + { .compatible = "nvidia,tegra20-dc" }, + { } +}; + +U_BOOT_DRIVER(tegra_lcd) = { + .name = "tegra_lcd", + .id = UCLASS_VIDEO, + .of_match = tegra_lcd_ids, + .ops = &tegra_lcd_ops, + .bind = tegra_lcd_bind, + .probe = tegra_lcd_probe, + .ofdata_to_platdata = tegra_lcd_ofdata_to_platdata, + .priv_auto_alloc_size = sizeof(struct tegra_lcd_priv), +}; diff --git a/drivers/video/tegra124/Makefile b/drivers/video/tegra124/Makefile index 52eedb0f08..4287b9a25f 100644 --- a/drivers/video/tegra124/Makefile +++ b/drivers/video/tegra124/Makefile @@ -7,4 +7,3 @@ obj-y += display.o obj-y += dp.o obj-y += sor.o -obj-y += tegra124-lcd.o diff --git a/drivers/video/tegra124/display.c b/drivers/video/tegra124/display.c index 610ffa9684..2f1f0df20e 100644 --- a/drivers/video/tegra124/display.c +++ b/drivers/video/tegra124/display.c @@ -14,11 +14,13 @@ #include <edid.h> #include <fdtdec.h> #include <lcd.h> +#include <video.h> #include <asm/gpio.h> #include <asm/io.h> #include <asm/arch/clock.h> #include <asm/arch/pwm.h> #include <asm/arch-tegra/dc.h> +#include <dm/uclass-internal.h> #include "displayport.h" DECLARE_GLOBAL_DATA_PTR; @@ -333,73 +335,46 @@ static int display_update_config_from_edid(struct udevice *dp_dev, return 0; } -/* Somewhat torturous method */ -static int get_backlight_info(const void *blob, struct gpio_desc *vdd, - struct gpio_desc *enable, int *pwmp) -{ - int sor, panel, backlight, power; - const u32 *prop; - int len; - int ret; - - *pwmp = 0; - sor = fdtdec_next_compatible(blob, 0, COMPAT_NVIDIA_TEGRA124_SOR); - if (sor < 0) - return -ENOENT; - panel = fdtdec_lookup_phandle(blob, sor, "nvidia,panel"); - if (panel < 0) - return -ENOENT; - backlight = fdtdec_lookup_phandle(blob, panel, "backlight"); - if (backlight < 0) - return -ENOENT; - ret = gpio_request_by_name_nodev(blob, backlight, "enable-gpios", 0, - enable, GPIOD_IS_OUT); - if (ret) - return ret; - prop = fdt_getprop(blob, backlight, "pwms", &len); - if (!prop || len != 3 * sizeof(u32)) - return -EINVAL; - *pwmp = fdt32_to_cpu(prop[1]); - - power = fdtdec_lookup_phandle(blob, backlight, "power-supply"); - if (power < 0) - return -ENOENT; - ret = gpio_request_by_name_nodev(blob, power, "gpio", 0, vdd, - GPIOD_IS_OUT); - if (ret) - goto err; - - return 0; - -err: - dm_gpio_free(NULL, enable); - return ret; -} - -int display_init(void *lcdbase, int fb_bits_per_pixel, - struct display_timing *timing) +static int display_init(struct udevice *dev, void *lcdbase, + int fb_bits_per_pixel, struct display_timing *timing) { + struct display_plat *disp_uc_plat; struct dc_ctlr *dc_ctlr; const void *blob = gd->fdt_blob; struct udevice *dp_dev; const int href_to_sync = 1, vref_to_sync = 1; int panel_bpp = 18; /* default 18 bits per pixel */ u32 plld_rate; - struct gpio_desc vdd_gpio, enable_gpio; - int pwm; - int node; int ret; + /* + * Before we probe the display device (eDP), tell it that this device + * is are the source of the display data. + */ + ret = uclass_find_first_device(UCLASS_DISPLAY, &dp_dev); + if (ret) { + debug("%s: device '%s' display not found (ret=%d)\n", __func__, + dev->name, ret); + return ret; + } + + disp_uc_plat = dev_get_uclass_platdata(dp_dev); + debug("Found device '%s', disp_uc_priv=%p\n", dp_dev->name, + disp_uc_plat); + disp_uc_plat->src_dev = dev; + ret = uclass_get_device(UCLASS_DISPLAY, 0, &dp_dev); - if (ret) + if (ret) { + debug("%s: Failed to probe eDP, ret=%d\n", __func__, ret); return ret; + } - node = fdtdec_next_compatible(blob, 0, COMPAT_NVIDIA_TEGRA124_DC); - if (node < 0) - return -ENOENT; - dc_ctlr = (struct dc_ctlr *)fdtdec_get_addr(blob, node, "reg"); - if (fdtdec_decode_display_timing(blob, node, 0, timing)) + dc_ctlr = (struct dc_ctlr *)fdtdec_get_addr(blob, dev->of_offset, + "reg"); + if (fdtdec_decode_display_timing(blob, dev->of_offset, 0, timing)) { + debug("%s: Failed to decode display timing\n", __func__); return -EINVAL; + } ret = display_update_config_from_edid(dp_dev, &panel_bpp, timing); if (ret) { @@ -407,12 +382,6 @@ int display_init(void *lcdbase, int fb_bits_per_pixel, dump_config(panel_bpp, timing); } - if (!get_backlight_info(blob, &vdd_gpio, &enable_gpio, &pwm)) { - dm_gpio_set_value(&vdd_gpio, 1); - debug("%s: backlight vdd setting gpio %08x to %d\n", - __func__, gpio_get_number(&vdd_gpio), 1); - } - /* * The plld is programmed with the assumption of the SHIFT_CLK_DIVIDER * and PIXEL_CLK_DIVIDER are zero (divide by 1). See the @@ -443,22 +412,99 @@ int display_init(void *lcdbase, int fb_bits_per_pixel, /* Enable dp */ ret = display_enable(dp_dev, panel_bpp, timing); - if (ret) + if (ret) { + debug("dc: failed to enable display: ret=%d\n", ret); return ret; + } ret = update_window(dc_ctlr, (ulong)lcdbase, fb_bits_per_pixel, timing); + if (ret) { + debug("dc: failed to update window\n"); + return ret; + } + + return 0; +} + +enum { + /* Maximum LCD size we support */ + LCD_MAX_WIDTH = 1920, + LCD_MAX_HEIGHT = 1200, + LCD_MAX_LOG2_BPP = 4, /* 2^4 = 16 bpp */ +}; + +static int tegra124_lcd_init(struct udevice *dev, void *lcdbase, + enum video_log2_bpp l2bpp) +{ + struct video_priv *uc_priv = dev_get_uclass_priv(dev); + struct display_timing timing; + int ret; + + clock_set_up_plldp(); + clock_start_periph_pll(PERIPH_ID_HOST1X, CLOCK_ID_PERIPH, 408000000); + + clock_enable(PERIPH_ID_HOST1X); + clock_enable(PERIPH_ID_DISP1); + clock_enable(PERIPH_ID_PWM); + clock_enable(PERIPH_ID_DPAUX); + clock_enable(PERIPH_ID_SOR0); + udelay(2); + + reset_set_enable(PERIPH_ID_HOST1X, 0); + reset_set_enable(PERIPH_ID_DISP1, 0); + reset_set_enable(PERIPH_ID_PWM, 0); + reset_set_enable(PERIPH_ID_DPAUX, 0); + reset_set_enable(PERIPH_ID_SOR0, 0); + + ret = display_init(dev, lcdbase, 1 << l2bpp, &timing); if (ret) return ret; - /* Set up Tegra PWM to drive the panel backlight */ - pwm_enable(pwm, 0, 220, 0x2e); - udelay(10 * 1000); + uc_priv->xsize = roundup(timing.hactive.typ, 16); + uc_priv->ysize = timing.vactive.typ; + uc_priv->bpix = l2bpp; - if (dm_gpio_is_valid(&enable_gpio)) { - dm_gpio_set_value(&enable_gpio, 1); - debug("%s: backlight enable setting gpio %08x to %d\n", - __func__, gpio_get_number(&enable_gpio), 1); - } + video_set_flush_dcache(dev, 1); + debug("%s: done\n", __func__); return 0; } + +static int tegra124_lcd_probe(struct udevice *dev) +{ + struct video_uc_platdata *plat = dev_get_uclass_platdata(dev); + ulong start; + int ret; + + start = get_timer(0); + ret = tegra124_lcd_init(dev, (void *)plat->base, VIDEO_BPP16); + debug("LCD init took %lu ms\n", get_timer(start)); + if (ret) + printf("%s: Error %d\n", __func__, ret); + + return 0; +} + +static int tegra124_lcd_bind(struct udevice *dev) +{ + struct video_uc_platdata *uc_plat = dev_get_uclass_platdata(dev); + + uc_plat->size = LCD_MAX_WIDTH * LCD_MAX_HEIGHT * + (1 << VIDEO_BPP16) / 8; + debug("%s: Frame buffer size %x\n", __func__, uc_plat->size); + + return 0; +} + +static const struct udevice_id tegra124_lcd_ids[] = { + { .compatible = "nvidia,tegra124-dc" }, + { } +}; + +U_BOOT_DRIVER(tegra124_dc) = { + .name = "tegra124-dc", + .id = UCLASS_VIDEO, + .of_match = tegra124_lcd_ids, + .bind = tegra124_lcd_bind, + .probe = tegra124_lcd_probe, +}; diff --git a/drivers/video/tegra124/dp.c b/drivers/video/tegra124/dp.c index bb1805a248..5bf8524a5e 100644 --- a/drivers/video/tegra124/dp.c +++ b/drivers/video/tegra124/dp.c @@ -11,6 +11,7 @@ #include <div64.h> #include <errno.h> #include <fdtdec.h> +#include <video_bridge.h> #include <asm/io.h> #include <asm/arch-tegra/dc.h> #include "display.h" @@ -26,9 +27,15 @@ struct tegra_dp_plat { ulong base; }; +/** + * struct tegra_dp_priv - private displayport driver info + * + * @dc_dev: Display controller device that is sending the video feed + */ struct tegra_dp_priv { + struct udevice *sor; + struct udevice *dc_dev; struct dpaux_ctlr *regs; - struct tegra_dc_sor_data *sor; u8 revision; int enabled; }; @@ -710,8 +717,8 @@ static int tegra_dc_dp_init_max_link_cfg( return 0; } -static int tegra_dc_dp_set_assr(struct tegra_dp_priv *dp, - struct tegra_dc_sor_data *sor, int ena) +static int tegra_dc_dp_set_assr(struct tegra_dp_priv *priv, + struct udevice *sor, int ena) { int ret; @@ -719,7 +726,7 @@ static int tegra_dc_dp_set_assr(struct tegra_dp_priv *dp, DP_MAIN_LINK_CHANNEL_CODING_SET_ASC_RESET_ENABLE : DP_MAIN_LINK_CHANNEL_CODING_SET_ASC_RESET_DISABLE; - ret = tegra_dc_dp_dpcd_write(dp, DP_EDP_CONFIGURATION_SET, + ret = tegra_dc_dp_dpcd_write(priv, DP_EDP_CONFIGURATION_SET, dpcd_data); if (ret) return ret; @@ -730,7 +737,7 @@ static int tegra_dc_dp_set_assr(struct tegra_dp_priv *dp, } static int tegra_dp_set_link_bandwidth(struct tegra_dp_priv *dp, - struct tegra_dc_sor_data *sor, + struct udevice *sor, u8 link_bw) { tegra_dc_sor_set_link_bandwidth(sor, link_bw); @@ -741,7 +748,7 @@ static int tegra_dp_set_link_bandwidth(struct tegra_dp_priv *dp, static int tegra_dp_set_lane_count(struct tegra_dp_priv *dp, const struct tegra_dp_link_config *link_cfg, - struct tegra_dc_sor_data *sor) + struct udevice *sor) { u8 dpcd_data; int ret; @@ -1002,7 +1009,7 @@ fail: static int tegra_dp_lt_config(struct tegra_dp_priv *dp, u32 pe[4], u32 vs[4], u32 pc[4], const struct tegra_dp_link_config *cfg) { - struct tegra_dc_sor_data *sor = dp->sor; + struct udevice *sor = dp->sor; u32 n_lanes = cfg->lane_count; u8 pc_supported = cfg->tps3_supported; u32 cnt; @@ -1186,7 +1193,7 @@ static int tegra_dc_dp_full_link_training(struct tegra_dp_priv *dp, const struct display_timing *timing, struct tegra_dp_link_config *cfg) { - struct tegra_dc_sor_data *sor = dp->sor; + struct udevice *sor = dp->sor; int err; u32 pe[4], vs[4], pc[4]; @@ -1229,7 +1236,7 @@ fail: */ static int tegra_dc_dp_fast_link_training(struct tegra_dp_priv *dp, const struct tegra_dp_link_config *link_cfg, - struct tegra_dc_sor_data *sor) + struct udevice *sor) { u8 link_bw; u8 lane_count; @@ -1301,7 +1308,7 @@ static int tegra_dc_dp_fast_link_training(struct tegra_dp_priv *dp, static int tegra_dp_do_link_training(struct tegra_dp_priv *dp, struct tegra_dp_link_config *link_cfg, const struct display_timing *timing, - struct tegra_dc_sor_data *sor) + struct udevice *sor) { u8 link_bw; u8 lane_count; @@ -1344,7 +1351,7 @@ static int tegra_dp_do_link_training(struct tegra_dp_priv *dp, static int tegra_dc_dp_explore_link_cfg(struct tegra_dp_priv *dp, struct tegra_dp_link_config *link_cfg, - struct tegra_dc_sor_data *sor, + struct udevice *sor, const struct display_timing *timing) { struct tegra_dp_link_config temp_cfg; @@ -1444,7 +1451,7 @@ static int tegra_dc_dp_check_sink(struct tegra_dp_priv *dp, printf("DP: Out of sync after %d retries\n", max_retry); return -EIO; } - ret = tegra_dc_sor_detach(dp->sor); + ret = tegra_dc_sor_detach(dp->dc_dev, dp->sor); if (ret) return ret; if (tegra_dc_dp_explore_link_cfg(dp, link_cfg, dp->sor, @@ -1454,7 +1461,7 @@ static int tegra_dc_dp_check_sink(struct tegra_dp_priv *dp, } tegra_dc_sor_set_power_state(dp->sor, 1); - tegra_dc_sor_attach(dp->sor, link_cfg, timing); + tegra_dc_sor_attach(dp->dc_dev, dp->sor, link_cfg, timing); /* Increase delay_frame for next try in case the sink is skipping more frames */ @@ -1467,7 +1474,7 @@ int tegra_dp_enable(struct udevice *dev, int panel_bpp, { struct tegra_dp_priv *priv = dev_get_priv(dev); struct tegra_dp_link_config slink_cfg, *link_cfg = &slink_cfg; - struct tegra_dc_sor_data *sor; + struct udevice *sor; int data; int retry; int ret; @@ -1489,9 +1496,11 @@ int tegra_dp_enable(struct udevice *dev, int panel_bpp, return -ENOLINK; } - ret = tegra_dc_sor_init(&sor); - if (ret) + ret = uclass_first_device(UCLASS_VIDEO_BRIDGE, &sor); + if (ret || !sor) { + debug("dp: failed to find SOR device: ret=%d\n", ret); return ret; + } priv->sor = sor; ret = tegra_dc_sor_enable_dp(sor, link_cfg); if (ret) @@ -1531,7 +1540,7 @@ int tegra_dp_enable(struct udevice *dev, int panel_bpp, } tegra_dc_sor_set_power_state(sor, 1); - ret = tegra_dc_sor_attach(sor, link_cfg, timing); + ret = tegra_dc_sor_attach(priv->dc_dev, sor, link_cfg, timing); if (ret && ret != -EEXIST) return ret; @@ -1548,6 +1557,12 @@ int tegra_dp_enable(struct udevice *dev, int panel_bpp, /* Power down the unused lanes to save power - a few hundred mW */ tegra_dc_sor_power_down_unused_lanes(sor, link_cfg); + ret = video_bridge_set_backlight(sor, 80); + if (ret) { + debug("dp: failed to set backlight\n"); + return ret; + } + priv->enabled = true; error_enable: return 0; @@ -1583,10 +1598,14 @@ static int dp_tegra_probe(struct udevice *dev) { struct tegra_dp_plat *plat = dev_get_platdata(dev); struct tegra_dp_priv *priv = dev_get_priv(dev); + struct display_plat *disp_uc_plat = dev_get_uclass_platdata(dev); priv->regs = (struct dpaux_ctlr *)plat->base; priv->enabled = false; + /* Remember the display controller that is sending us video */ + priv->dc_dev = disp_uc_plat->src_dev; + return 0; } diff --git a/drivers/video/tegra124/sor.c b/drivers/video/tegra124/sor.c index aa3d80c4c0..e5cea51d48 100644 --- a/drivers/video/tegra124/sor.c +++ b/drivers/video/tegra124/sor.c @@ -5,9 +5,12 @@ */ #include <common.h> +#include <dm.h> #include <errno.h> #include <fdtdec.h> #include <malloc.h> +#include <panel.h> +#include <video_bridge.h> #include <asm/io.h> #include <asm/arch/clock.h> #include <asm/arch-tegra/dc.h> @@ -37,6 +40,14 @@ DECLARE_GLOBAL_DATA_PTR; #define APBDEV_PMC_IO_DPD2_STATUS_LVDS_OFF (0 << 25) #define APBDEV_PMC_IO_DPD2_STATUS_LVDS_ON (1 << 25) +struct tegra_dc_sor_data { + void *base; + void *pmc_base; + u8 portnum; /* 0 or 1 */ + int power_is_up; + struct udevice *panel; +}; + static inline u32 tegra_sor_readl(struct tegra_dc_sor_data *sor, u32 reg) { return readl((u32 *)sor->base + reg); @@ -57,15 +68,19 @@ static inline void tegra_sor_write_field(struct tegra_dc_sor_data *sor, tegra_sor_writel(sor, reg, reg_val); } -void tegra_dp_disable_tx_pu(struct tegra_dc_sor_data *sor) +void tegra_dp_disable_tx_pu(struct udevice *dev) { + struct tegra_dc_sor_data *sor = dev_get_priv(dev); + tegra_sor_write_field(sor, DP_PADCTL(sor->portnum), DP_PADCTL_TX_PU_MASK, DP_PADCTL_TX_PU_DISABLE); } -void tegra_dp_set_pe_vs_pc(struct tegra_dc_sor_data *sor, u32 mask, u32 pe_reg, +void tegra_dp_set_pe_vs_pc(struct udevice *dev, u32 mask, u32 pe_reg, u32 vs_reg, u32 pc_reg, u8 pc_supported) { + struct tegra_dc_sor_data *sor = dev_get_priv(dev); + tegra_sor_write_field(sor, PR(sor->portnum), mask, pe_reg); tegra_sor_write_field(sor, DC(sor->portnum), mask, vs_reg); if (pc_supported) { @@ -95,8 +110,9 @@ static int tegra_dc_sor_poll_register(struct tegra_dc_sor_data *sor, u32 reg, return -ETIMEDOUT; } -int tegra_dc_sor_set_power_state(struct tegra_dc_sor_data *sor, int pu_pd) +int tegra_dc_sor_set_power_state(struct udevice *dev, int pu_pd) { + struct tegra_dc_sor_data *sor = dev_get_priv(dev); u32 reg_val; u32 orig_val; @@ -123,10 +139,11 @@ int tegra_dc_sor_set_power_state(struct tegra_dc_sor_data *sor, int pu_pd) return 0; } -void tegra_dc_sor_set_dp_linkctl(struct tegra_dc_sor_data *sor, int ena, +void tegra_dc_sor_set_dp_linkctl(struct udevice *dev, int ena, u8 training_pattern, const struct tegra_dp_link_config *link_cfg) { + struct tegra_dc_sor_data *sor = dev_get_priv(dev); u32 reg_val; reg_val = tegra_sor_readl(sor, DP_LINKCTL(sor->portnum)); @@ -194,9 +211,10 @@ static int tegra_dc_sor_enable_lane_sequencer(struct tegra_dc_sor_data *sor, return 0; } -static int tegra_dc_sor_power_dplanes(struct tegra_dc_sor_data *sor, +static int tegra_dc_sor_power_dplanes(struct udevice *dev, u32 lane_count, int pu) { + struct tegra_dc_sor_data *sor = dev_get_priv(dev); u32 reg_val; reg_val = tegra_sor_readl(sor, DP_PADCTL(sor->portnum)); @@ -218,15 +236,15 @@ static int tegra_dc_sor_power_dplanes(struct tegra_dc_sor_data *sor, } tegra_sor_writel(sor, DP_PADCTL(sor->portnum), reg_val); - tegra_dc_sor_set_lane_count(sor, lane_count); + tegra_dc_sor_set_lane_count(dev, lane_count); } return tegra_dc_sor_enable_lane_sequencer(sor, pu, 0); } -void tegra_dc_sor_set_panel_power(struct tegra_dc_sor_data *sor, - int power_up) +void tegra_dc_sor_set_panel_power(struct udevice *dev, int power_up) { + struct tegra_dc_sor_data *sor = dev_get_priv(dev); u32 reg_val; reg_val = tegra_sor_readl(sor, DP_PADCTL(sor->portnum)); @@ -255,14 +273,15 @@ static void tegra_dc_sor_config_pwm(struct tegra_dc_sor_data *sor, u32 pwm_div, } } -static void tegra_dc_sor_set_dp_mode(struct tegra_dc_sor_data *sor, +static void tegra_dc_sor_set_dp_mode(struct udevice *dev, const struct tegra_dp_link_config *link_cfg) { + struct tegra_dc_sor_data *sor = dev_get_priv(dev); u32 reg_val; - tegra_dc_sor_set_link_bandwidth(sor, link_cfg->link_bw); + tegra_dc_sor_set_link_bandwidth(dev, link_cfg->link_bw); - tegra_dc_sor_set_dp_linkctl(sor, 1, training_pattern_none, link_cfg); + tegra_dc_sor_set_dp_linkctl(dev, 1, training_pattern_none, link_cfg); reg_val = tegra_sor_readl(sor, DP_CONFIG(sor->portnum)); reg_val &= ~DP_CONFIG_WATERMARK_MASK; reg_val |= link_cfg->watermark; @@ -351,8 +370,9 @@ static int tegra_dc_sor_io_set_dpd(struct tegra_dc_sor_data *sor, int up) return 0; } -void tegra_dc_sor_set_internal_panel(struct tegra_dc_sor_data *sor, int is_int) +void tegra_dc_sor_set_internal_panel(struct udevice *dev, int is_int) { + struct tegra_dc_sor_data *sor = dev_get_priv(dev); u32 reg_val; reg_val = tegra_sor_readl(sor, DP_SPARE(sor->portnum)); @@ -366,9 +386,10 @@ void tegra_dc_sor_set_internal_panel(struct tegra_dc_sor_data *sor, int is_int) tegra_sor_writel(sor, DP_SPARE(sor->portnum), reg_val); } -void tegra_dc_sor_read_link_config(struct tegra_dc_sor_data *sor, u8 *link_bw, +void tegra_dc_sor_read_link_config(struct udevice *dev, u8 *link_bw, u8 *lane_count) { + struct tegra_dc_sor_data *sor = dev_get_priv(dev); u32 reg_val; reg_val = tegra_sor_readl(sor, CLK_CNTRL); @@ -395,15 +416,18 @@ void tegra_dc_sor_read_link_config(struct tegra_dc_sor_data *sor, u8 *link_bw, } } -void tegra_dc_sor_set_link_bandwidth(struct tegra_dc_sor_data *sor, u8 link_bw) +void tegra_dc_sor_set_link_bandwidth(struct udevice *dev, u8 link_bw) { + struct tegra_dc_sor_data *sor = dev_get_priv(dev); + tegra_sor_write_field(sor, CLK_CNTRL, CLK_CNTRL_DP_LINK_SPEED_MASK, link_bw << CLK_CNTRL_DP_LINK_SPEED_SHIFT); } -void tegra_dc_sor_set_lane_count(struct tegra_dc_sor_data *sor, u8 lane_count) +void tegra_dc_sor_set_lane_count(struct udevice *dev, u8 lane_count) { + struct tegra_dc_sor_data *sor = dev_get_priv(dev); u32 reg_val; reg_val = tegra_sor_readl(sor, DP_LINKCTL(sor->portnum)); @@ -439,15 +463,16 @@ void tegra_dc_sor_set_lane_count(struct tegra_dc_sor_data *sor, u8 lane_count) * 4 1 0 0 0 0 0 1 * 5 0 0 0 0 0 0 1 */ -static int tegra_dc_sor_power_up(struct tegra_dc_sor_data *sor, int is_lvds) +static int tegra_dc_sor_power_up(struct udevice *dev, int is_lvds) { + struct tegra_dc_sor_data *sor = dev_get_priv(dev); int ret; if (sor->power_is_up) return 0; /* Set link bw */ - tegra_dc_sor_set_link_bandwidth(sor, is_lvds ? + tegra_dc_sor_set_link_bandwidth(dev, is_lvds ? CLK_CNTRL_DP_LINK_SPEED_LVDS : CLK_CNTRL_DP_LINK_SPEED_G1_62); @@ -655,9 +680,10 @@ static void tegra_dc_sor_enable_dc(struct dc_ctlr *disp_ctrl) writel(reg_val, &disp_ctrl->cmd.state_access); } -int tegra_dc_sor_enable_dp(struct tegra_dc_sor_data *sor, +int tegra_dc_sor_enable_dp(struct udevice *dev, const struct tegra_dp_link_config *link_cfg) { + struct tegra_dc_sor_data *sor = dev_get_priv(dev); int ret; tegra_sor_write_field(sor, CLK_CNTRL, @@ -701,7 +727,7 @@ int tegra_dc_sor_enable_dp(struct tegra_dc_sor_data *sor, PLL2_AUX2_OVERRIDE_POWERDOWN | PLL2_AUX7_PORT_POWERDOWN_DISABLE); - ret = tegra_dc_sor_power_up(sor, 0); + ret = tegra_dc_sor_power_up(dev, 0); if (ret) { debug("DP failed to power up\n"); return ret; @@ -711,18 +737,19 @@ int tegra_dc_sor_enable_dp(struct tegra_dc_sor_data *sor, clock_sor_enable_edp_clock(); /* Power up lanes */ - tegra_dc_sor_power_dplanes(sor, link_cfg->lane_count, 1); + tegra_dc_sor_power_dplanes(dev, link_cfg->lane_count, 1); - tegra_dc_sor_set_dp_mode(sor, link_cfg); + tegra_dc_sor_set_dp_mode(dev, link_cfg); debug("%s ret\n", __func__); return 0; } -int tegra_dc_sor_attach(struct tegra_dc_sor_data *sor, +int tegra_dc_sor_attach(struct udevice *dc_dev, struct udevice *dev, const struct tegra_dp_link_config *link_cfg, const struct display_timing *timing) { + struct tegra_dc_sor_data *sor = dev_get_priv(dev); const void *blob = gd->fdt_blob; struct dc_ctlr *disp_ctrl; u32 reg_val; @@ -730,9 +757,7 @@ int tegra_dc_sor_attach(struct tegra_dc_sor_data *sor, /* Use the first display controller */ debug("%s\n", __func__); - node = fdtdec_next_compatible(blob, 0, COMPAT_NVIDIA_TEGRA124_DC); - if (node < 0) - return -ENOENT; + node = dc_dev->of_offset; disp_ctrl = (struct dc_ctlr *)fdtdec_get_addr(blob, node, "reg"); tegra_dc_sor_enable_dc(disp_ctrl); @@ -798,9 +823,11 @@ int tegra_dc_sor_attach(struct tegra_dc_sor_data *sor, return 0; } -void tegra_dc_sor_set_lane_parm(struct tegra_dc_sor_data *sor, +void tegra_dc_sor_set_lane_parm(struct udevice *dev, const struct tegra_dp_link_config *link_cfg) { + struct tegra_dc_sor_data *sor = dev_get_priv(dev); + tegra_sor_writel(sor, LANE_DRIVE_CURRENT(sor->portnum), link_cfg->drive_current); tegra_sor_writel(sor, PR(sor->portnum), @@ -809,8 +836,8 @@ void tegra_dc_sor_set_lane_parm(struct tegra_dc_sor_data *sor, link_cfg->postcursor); tegra_sor_writel(sor, LVDS, 0); - tegra_dc_sor_set_link_bandwidth(sor, link_cfg->link_bw); - tegra_dc_sor_set_lane_count(sor, link_cfg->lane_count); + tegra_dc_sor_set_link_bandwidth(dev, link_cfg->link_bw); + tegra_dc_sor_set_lane_count(dev, link_cfg->lane_count); tegra_sor_write_field(sor, DP_PADCTL(sor->portnum), DP_PADCTL_TX_PU_ENABLE | @@ -825,9 +852,10 @@ void tegra_dc_sor_set_lane_parm(struct tegra_dc_sor_data *sor, tegra_sor_write_field(sor, DP_PADCTL(sor->portnum), 0xf0, 0x0); } -int tegra_dc_sor_set_voltage_swing(struct tegra_dc_sor_data *sor, +int tegra_dc_sor_set_voltage_swing(struct udevice *dev, const struct tegra_dp_link_config *link_cfg) { + struct tegra_dc_sor_data *sor = dev_get_priv(dev); u32 drive_current = 0; u32 pre_emphasis = 0; @@ -851,9 +879,10 @@ int tegra_dc_sor_set_voltage_swing(struct tegra_dc_sor_data *sor, return 0; } -void tegra_dc_sor_power_down_unused_lanes(struct tegra_dc_sor_data *sor, +void tegra_dc_sor_power_down_unused_lanes(struct udevice *dev, const struct tegra_dp_link_config *link_cfg) { + struct tegra_dc_sor_data *sor = dev_get_priv(dev); u32 pad_ctrl = 0; int err = 0; @@ -891,9 +920,10 @@ void tegra_dc_sor_power_down_unused_lanes(struct tegra_dc_sor_data *sor, } } -int tegra_sor_precharge_lanes(struct tegra_dc_sor_data *sor, +int tegra_sor_precharge_lanes(struct udevice *dev, const struct tegra_dp_link_config *cfg) { + struct tegra_dc_sor_data *sor = dev_get_priv(dev); u32 val = 0; switch (cfg->lane_count) { @@ -931,8 +961,9 @@ static void tegra_dc_sor_enable_sor(struct dc_ctlr *disp_ctrl, bool enable) writel(reg_val, &disp_ctrl->disp.disp_win_opt); } -int tegra_dc_sor_detach(struct tegra_dc_sor_data *sor) +int tegra_dc_sor_detach(struct udevice *dc_dev, struct udevice *dev) { + struct tegra_dc_sor_data *sor = dev_get_priv(dev); int dc_reg_ctx[DC_REG_SAVE_SPACE]; const void *blob = gd->fdt_blob; struct dc_ctlr *disp_ctrl; @@ -942,11 +973,7 @@ int tegra_dc_sor_detach(struct tegra_dc_sor_data *sor) debug("%s\n", __func__); /* Use the first display controller */ - node = fdtdec_next_compatible(blob, 0, COMPAT_NVIDIA_TEGRA124_DC); - if (node < 0) { - ret = -ENOENT; - goto err; - } + node = dc_dev->of_offset; disp_ctrl = (struct dc_ctlr *)fdtdec_get_addr(blob, node, "reg"); /* Sleep mode */ @@ -997,28 +1024,61 @@ err: return ret; } -int tegra_dc_sor_init(struct tegra_dc_sor_data **sorp) +static int tegra_sor_set_backlight(struct udevice *dev, int percent) { + struct tegra_dc_sor_data *priv = dev_get_priv(dev); + int ret; + + ret = panel_enable_backlight(priv->panel); + if (ret) { + debug("sor: Cannot enable panel backlight\n"); + return ret; + } + + return 0; +} + +static int tegra_sor_ofdata_to_platdata(struct udevice *dev) +{ + struct tegra_dc_sor_data *priv = dev_get_priv(dev); const void *blob = gd->fdt_blob; - struct tegra_dc_sor_data *sor; int node; + int ret; - node = fdtdec_next_compatible(blob, 0, COMPAT_NVIDIA_TEGRA124_SOR); - if (node < 0) - return -ENOENT; - sor = calloc(1, sizeof(*sor)); - if (!sor) - return -ENOMEM; - sor->base = (void *)fdtdec_get_addr(blob, node, "reg"); + priv->base = (void *)fdtdec_get_addr(blob, dev->of_offset, "reg"); node = fdtdec_next_compatible(blob, 0, COMPAT_NVIDIA_TEGRA124_PMC); - if (node < 0) + if (node < 0) { + debug("%s: Cannot find PMC\n", __func__); return -ENOENT; - sor->pmc_base = (void *)fdtdec_get_addr(blob, node, "reg"); + } + priv->pmc_base = (void *)fdtdec_get_addr(blob, node, "reg"); - sor->power_is_up = 0; - sor->portnum = 0; - *sorp = sor; + ret = uclass_get_device_by_phandle(UCLASS_PANEL, dev, "nvidia,panel", + &priv->panel); + if (ret) { + debug("%s: Cannot find panel for '%s' (ret=%d)\n", __func__, + dev->name, ret); + return ret; + } return 0; } + +static const struct video_bridge_ops tegra_sor_ops = { + .set_backlight = tegra_sor_set_backlight, +}; + +static const struct udevice_id tegra_sor_ids[] = { + { .compatible = "nvidia,tegra124-sor" }, + { } +}; + +U_BOOT_DRIVER(sor_tegra) = { + .name = "sor_tegra", + .id = UCLASS_VIDEO_BRIDGE, + .of_match = tegra_sor_ids, + .ofdata_to_platdata = tegra_sor_ofdata_to_platdata, + .ops = &tegra_sor_ops, + .priv_auto_alloc_size = sizeof(struct tegra_dc_sor_data), +}; diff --git a/drivers/video/tegra124/sor.h b/drivers/video/tegra124/sor.h index dc8fd03d80..e854bef17d 100644 --- a/drivers/video/tegra124/sor.h +++ b/drivers/video/tegra124/sor.h @@ -873,44 +873,37 @@ struct tegra_dp_link_config { u8 tps3_supported; }; -struct tegra_dc_sor_data { - void *base; - void *pmc_base; - u8 portnum; /* 0 or 1 */ - int power_is_up; -}; - #define TEGRA_SOR_TIMEOUT_MS 1000 #define TEGRA_SOR_ATTACH_TIMEOUT_MS 1000 -int tegra_dc_sor_enable_dp(struct tegra_dc_sor_data *sor, +int tegra_dc_sor_enable_dp(struct udevice *sor, const struct tegra_dp_link_config *link_cfg); -int tegra_dc_sor_set_power_state(struct tegra_dc_sor_data *sor, int pu_pd); -void tegra_dc_sor_set_dp_linkctl(struct tegra_dc_sor_data *sor, int ena, +int tegra_dc_sor_set_power_state(struct udevice *sor, int pu_pd); +void tegra_dc_sor_set_dp_linkctl(struct udevice *dev, int ena, u8 training_pattern, const struct tegra_dp_link_config *link_cfg); -void tegra_dc_sor_set_link_bandwidth(struct tegra_dc_sor_data *sor, u8 link_bw); -void tegra_dc_sor_set_lane_count(struct tegra_dc_sor_data *sor, u8 lane_count); -void tegra_dc_sor_set_panel_power(struct tegra_dc_sor_data *sor, +void tegra_dc_sor_set_link_bandwidth(struct udevice *dev, u8 link_bw); +void tegra_dc_sor_set_lane_count(struct udevice *dev, u8 lane_count); +void tegra_dc_sor_set_panel_power(struct udevice *sor, int power_up); -void tegra_dc_sor_set_internal_panel(struct tegra_dc_sor_data *sor, int is_int); -void tegra_dc_sor_read_link_config(struct tegra_dc_sor_data *sor, u8 *link_bw, +void tegra_dc_sor_set_internal_panel(struct udevice *dev, int is_int); +void tegra_dc_sor_read_link_config(struct udevice *dev, u8 *link_bw, u8 *lane_count); -void tegra_dc_sor_set_lane_parm(struct tegra_dc_sor_data *sor, - const struct tegra_dp_link_config *link_cfg); -void tegra_dc_sor_power_down_unused_lanes(struct tegra_dc_sor_data *sor, +void tegra_dc_sor_set_lane_parm(struct udevice *dev, + const struct tegra_dp_link_config *link_cfg); +void tegra_dc_sor_power_down_unused_lanes(struct udevice *sor, const struct tegra_dp_link_config *link_cfg); -int tegra_dc_sor_set_voltage_swing(struct tegra_dc_sor_data *sor, +int tegra_dc_sor_set_voltage_swing(struct udevice *sor, const struct tegra_dp_link_config *link_cfg); -int tegra_sor_precharge_lanes(struct tegra_dc_sor_data *sor, +int tegra_sor_precharge_lanes(struct udevice *dev, const struct tegra_dp_link_config *cfg); -void tegra_dp_disable_tx_pu(struct tegra_dc_sor_data *sor); -void tegra_dp_set_pe_vs_pc(struct tegra_dc_sor_data *sor, u32 mask, - u32 pe_reg, u32 vs_reg, u32 pc_reg, u8 pc_supported); +void tegra_dp_disable_tx_pu(struct udevice *sor); +void tegra_dp_set_pe_vs_pc(struct udevice *dev, u32 mask, u32 pe_reg, + u32 vs_reg, u32 pc_reg, u8 pc_supported); -int tegra_dc_sor_attach(struct tegra_dc_sor_data *sor, +int tegra_dc_sor_attach(struct udevice *dc_dev, struct udevice *sor, const struct tegra_dp_link_config *link_cfg, const struct display_timing *timing); -int tegra_dc_sor_detach(struct tegra_dc_sor_data *sor); +int tegra_dc_sor_detach(struct udevice *dc_dev, struct udevice *sor); void tegra_dc_sor_disable_win_short_raster(struct dc_ctlr *disp_ctrl, int *dc_reg_ctx); @@ -918,5 +911,5 @@ int tegra_dc_sor_general_act(struct dc_ctlr *disp_ctrl); void tegra_dc_sor_restore_win_and_raster(struct dc_ctlr *disp_ctrl, int *dc_reg_ctx); -int tegra_dc_sor_init(struct tegra_dc_sor_data **sorp); +int tegra_dc_sor_init(struct udevice **sorp); #endif diff --git a/drivers/video/tegra124/tegra124-lcd.c b/drivers/video/tegra124/tegra124-lcd.c deleted file mode 100644 index cfdc77ffe3..0000000000 --- a/drivers/video/tegra124/tegra124-lcd.c +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright 2014 Google Inc. - * - * SPDX-License-Identifier: GPL-2.0+ - * - */ - -#include <common.h> -#include <errno.h> -#include <fdtdec.h> -#include <lcd.h> -#include <asm/gpio.h> -#include <asm/arch-tegra/clk_rst.h> -#include <asm/arch/clock.h> -#include <asm/arch-tegra/dc.h> -#include <asm/io.h> - -DECLARE_GLOBAL_DATA_PTR; - -enum { - /* Maximum LCD size we support */ - LCD_MAX_WIDTH = 1920, - LCD_MAX_HEIGHT = 1200, - LCD_MAX_LOG2_BPP = 4, /* 2^4 = 16 bpp */ -}; - -vidinfo_t panel_info = { - /* Insert a value here so that we don't end up in the BSS */ - .vl_col = -1, -}; - -int tegra_lcd_check_next_stage(const void *blob, int wait) -{ - return 0; -} - -void tegra_lcd_early_init(const void *blob) -{ - /* - * Go with the maximum size for now. We will fix this up after - * relocation. These values are only used for memory alocation. - */ - panel_info.vl_col = LCD_MAX_WIDTH; - panel_info.vl_row = LCD_MAX_HEIGHT; - panel_info.vl_bpix = LCD_MAX_LOG2_BPP; -} - -static int tegra124_lcd_init(void *lcdbase) -{ - struct display_timing timing; - int ret; - - clock_set_up_plldp(); - clock_start_periph_pll(PERIPH_ID_HOST1X, CLOCK_ID_PERIPH, 408000000); - - clock_enable(PERIPH_ID_HOST1X); - clock_enable(PERIPH_ID_DISP1); - clock_enable(PERIPH_ID_PWM); - clock_enable(PERIPH_ID_DPAUX); - clock_enable(PERIPH_ID_SOR0); - udelay(2); - - reset_set_enable(PERIPH_ID_HOST1X, 0); - reset_set_enable(PERIPH_ID_DISP1, 0); - reset_set_enable(PERIPH_ID_PWM, 0); - reset_set_enable(PERIPH_ID_DPAUX, 0); - reset_set_enable(PERIPH_ID_SOR0, 0); - - ret = display_init(lcdbase, 1 << LCD_BPP, &timing); - if (ret) - return ret; - - panel_info.vl_col = roundup(timing.hactive.typ, 16); - panel_info.vl_row = timing.vactive.typ; - - lcd_set_flush_dcache(1); - - return 0; -} - -void lcd_ctrl_init(void *lcdbase) -{ - ulong start; - int ret; - - start = get_timer(0); - ret = tegra124_lcd_init(lcdbase); - debug("LCD init took %lu ms\n", get_timer(start)); - if (ret) - printf("%s: Error %d\n", __func__, ret); -} - -void lcd_enable(void) -{ -} diff --git a/drivers/video/vidconsole-uclass.c b/drivers/video/vidconsole-uclass.c index f6326b6e07..832e90aea2 100644 --- a/drivers/video/vidconsole-uclass.c +++ b/drivers/video/vidconsole-uclass.c @@ -170,6 +170,7 @@ static void vidconsole_puts(struct stdio_dev *sdev, const char *s) while (*s) vidconsole_put_char(dev, *s++); + video_sync(dev->parent); } /* Set up the number of rows and colours (rotated drivers override this) */ diff --git a/drivers/video/video_bmp.c b/drivers/video/video_bmp.c index c9075d62dd..fb7943e06d 100644 --- a/drivers/video/video_bmp.c +++ b/drivers/video/video_bmp.c @@ -194,7 +194,7 @@ int video_bmp_display(struct udevice *dev, ulong bmp_image, int x, int y, { struct video_priv *priv = dev_get_uclass_priv(dev); ushort *cmap_base = NULL; - ushort i, j; + int i, j; uchar *fb; struct bmp_image *bmp = map_sysmem(bmp_image, 0); uchar *bmap; |