diff options
Diffstat (limited to 'drivers')
321 files changed, 16081 insertions, 1278 deletions
diff --git a/drivers/Kconfig b/drivers/Kconfig index 7a839fa1aa..119e412849 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -16,6 +16,8 @@ source "drivers/block/Kconfig" source "drivers/bootcount/Kconfig" +source "drivers/button/Kconfig" + source "drivers/cache/Kconfig" source "drivers/clk/Kconfig" diff --git a/drivers/Makefile b/drivers/Makefile index afd159e903..2178871bfb 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -1,5 +1,6 @@ # SPDX-License-Identifier: GPL-2.0+ +obj-$(CONFIG_$(SPL_TPL_)BUTTON) += button/ obj-$(CONFIG_$(SPL_TPL_)CACHE) += cache/ obj-$(CONFIG_$(SPL_TPL_)CLK) += clk/ obj-$(CONFIG_$(SPL_TPL_)DM) += core/ diff --git a/drivers/adc/exynos-adc.c b/drivers/adc/exynos-adc.c index 12c49fc8ce..b459b57050 100644 --- a/drivers/adc/exynos-adc.c +++ b/drivers/adc/exynos-adc.c @@ -106,7 +106,7 @@ int exynos_adc_ofdata_to_platdata(struct udevice *dev) struct adc_uclass_platdata *uc_pdata = dev_get_uclass_platdata(dev); struct exynos_adc_priv *priv = dev_get_priv(dev); - priv->regs = (struct exynos_adc_v2 *)devfdt_get_addr(dev); + priv->regs = dev_read_addr_ptr(dev); if (priv->regs == (struct exynos_adc_v2 *)FDT_ADDR_T_NONE) { pr_err("Dev: %s - can't get address!", dev->name); return -ENODATA; diff --git a/drivers/adc/stm32-adc-core.c b/drivers/adc/stm32-adc-core.c index 31bbb6f9d6..f20c46fb36 100644 --- a/drivers/adc/stm32-adc-core.c +++ b/drivers/adc/stm32-adc-core.c @@ -7,6 +7,7 @@ */ #include <common.h> +#include <dm.h> #include <asm/io.h> #include <dm/device_compat.h> #include <linux/bitops.h> diff --git a/drivers/adc/stm32-adc-core.h b/drivers/adc/stm32-adc-core.h index ba0e10e6cc..05968dbcc8 100644 --- a/drivers/adc/stm32-adc-core.h +++ b/drivers/adc/stm32-adc-core.h @@ -26,9 +26,9 @@ #define STM32_ADC_MAX_ADCS 3 #define STM32_ADCX_COMN_OFFSET 0x300 -#include <common.h> #include <clk.h> -#include <dm.h> + +struct udevice; /** * struct stm32_adc_common - stm32 ADC driver common data (for all instances) diff --git a/drivers/adc/stm32-adc.c b/drivers/adc/stm32-adc.c index b12f894a9b..3f0ed48846 100644 --- a/drivers/adc/stm32-adc.c +++ b/drivers/adc/stm32-adc.c @@ -8,6 +8,7 @@ #include <common.h> #include <adc.h> +#include <dm.h> #include <asm/io.h> #include <dm/device_compat.h> #include <linux/bitops.h> diff --git a/drivers/ata/dwc_ahci.c b/drivers/ata/dwc_ahci.c index 017650ae46..825fe57f85 100644 --- a/drivers/ata/dwc_ahci.c +++ b/drivers/ata/dwc_ahci.c @@ -34,7 +34,7 @@ static int dwc_ahci_ofdata_to_platdata(struct udevice *dev) struct dwc_ahci_priv *priv = dev_get_priv(dev); fdt_addr_t addr; - priv->base = map_physmem(devfdt_get_addr(dev), sizeof(void *), + priv->base = map_physmem(dev_read_addr(dev), sizeof(void *), MAP_NOCACHE); addr = devfdt_get_addr_index(dev, 1); diff --git a/drivers/button/Kconfig b/drivers/button/Kconfig new file mode 100644 index 0000000000..6b3ec7e55d --- /dev/null +++ b/drivers/button/Kconfig @@ -0,0 +1,21 @@ +menu "Button Support" + +config BUTTON + bool "Enable button support" + depends on DM + help + Many boards have buttons which can be used to change behaviour (reset, ...). + U-Boot provides a uclass API to implement this feature. Button drivers + can provide access to board-specific buttons. Use of the device tree + for configuration is encouraged. + +config BUTTON_GPIO + bool "Button gpio" + depends on BUTTON + help + Enable support for buttons which are connected to GPIO lines. These + GPIOs may be on the SoC or some other device which provides GPIOs. + The GPIO driver must used driver model. Buttons are configured using + the device tree. + +endmenu diff --git a/drivers/button/Makefile b/drivers/button/Makefile new file mode 100644 index 0000000000..fcc10ebe8d --- /dev/null +++ b/drivers/button/Makefile @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: GPL-2.0+ +# +# Copyright (C) 2020 Philippe Reynes <philippe.reynes@softathome.com> + +obj-$(CONFIG_BUTTON) += button-uclass.o +obj-$(CONFIG_BUTTON_GPIO) += button-gpio.o diff --git a/drivers/button/button-gpio.c b/drivers/button/button-gpio.c new file mode 100644 index 0000000000..985ae7f5a7 --- /dev/null +++ b/drivers/button/button-gpio.c @@ -0,0 +1,112 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2020 Philippe Reynes <philippe.reynes@softathome.com> + */ + +#include <common.h> +#include <button.h> +#include <dm.h> +#include <dm/lists.h> +#include <dm/uclass-internal.h> +#include <log.h> +#include <asm/gpio.h> + +struct button_gpio_priv { + struct gpio_desc gpio; +}; + +static enum button_state_t button_gpio_get_state(struct udevice *dev) +{ + struct button_gpio_priv *priv = dev_get_priv(dev); + int ret; + + if (!dm_gpio_is_valid(&priv->gpio)) + return -EREMOTEIO; + ret = dm_gpio_get_value(&priv->gpio); + if (ret < 0) + return ret; + + return ret ? BUTTON_ON : BUTTON_OFF; +} + +static int button_gpio_probe(struct udevice *dev) +{ + struct button_uc_plat *uc_plat = dev_get_uclass_platdata(dev); + struct button_gpio_priv *priv = dev_get_priv(dev); + int ret; + + /* Ignore the top-level button node */ + if (!uc_plat->label) + return 0; + + ret = gpio_request_by_name(dev, "gpios", 0, &priv->gpio, GPIOD_IS_IN); + if (ret) + return ret; + + return 0; +} + +static int button_gpio_remove(struct udevice *dev) +{ + /* + * The GPIO driver may have already been removed. We will need to + * address this more generally. + */ + if (!IS_ENABLED(CONFIG_SANDBOX)) { + struct button_gpio_priv *priv = dev_get_priv(dev); + + if (dm_gpio_is_valid(&priv->gpio)) + dm_gpio_free(dev, &priv->gpio); + } + + return 0; +} + +static int button_gpio_bind(struct udevice *parent) +{ + struct udevice *dev; + ofnode node; + int ret; + + dev_for_each_subnode(node, parent) { + struct button_uc_plat *uc_plat; + const char *label; + + label = ofnode_read_string(node, "label"); + if (!label) { + debug("%s: node %s has no label\n", __func__, + ofnode_get_name(node)); + return -EINVAL; + } + ret = device_bind_driver_to_node(parent, "button_gpio", + ofnode_get_name(node), + node, &dev); + if (ret) + return ret; + uc_plat = dev_get_uclass_platdata(dev); + uc_plat->label = label; + } + + return 0; +} + +static const struct button_ops button_gpio_ops = { + .get_state = button_gpio_get_state, +}; + +static const struct udevice_id button_gpio_ids[] = { + { .compatible = "gpio-keys" }, + { .compatible = "gpio-keys-polled" }, + { } +}; + +U_BOOT_DRIVER(button_gpio) = { + .name = "button_gpio", + .id = UCLASS_BUTTON, + .of_match = button_gpio_ids, + .ops = &button_gpio_ops, + .priv_auto_alloc_size = sizeof(struct button_gpio_priv), + .bind = button_gpio_bind, + .probe = button_gpio_probe, + .remove = button_gpio_remove, +}; diff --git a/drivers/button/button-uclass.c b/drivers/button/button-uclass.c new file mode 100644 index 0000000000..1c742c265c --- /dev/null +++ b/drivers/button/button-uclass.c @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2020 Philippe Reynes <philippe.reynes@softathome.com> + * + * Based on led-uclass.c + */ + +#include <common.h> +#include <button.h> +#include <dm.h> +#include <dm/uclass-internal.h> + +int button_get_by_label(const char *label, struct udevice **devp) +{ + struct udevice *dev; + struct uclass *uc; + + uclass_id_foreach_dev(UCLASS_BUTTON, dev, uc) { + struct button_uc_plat *uc_plat = dev_get_uclass_platdata(dev); + + /* Ignore the top-level button node */ + if (uc_plat->label && !strcmp(label, uc_plat->label)) + return uclass_get_device_tail(dev, 0, devp); + } + + return -ENODEV; +} + +enum button_state_t button_get_state(struct udevice *dev) +{ + struct button_ops *ops = button_get_ops(dev); + + if (!ops->get_state) + return -ENOSYS; + + return ops->get_state(dev); +} + +UCLASS_DRIVER(button) = { + .id = UCLASS_BUTTON, + .name = "button", + .per_device_platdata_auto_alloc_size = sizeof(struct button_uc_plat), +}; diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig index 82cb1874e1..6003e140b5 100644 --- a/drivers/clk/Kconfig +++ b/drivers/clk/Kconfig @@ -83,6 +83,13 @@ config CLK_INTEL set up by U-Boot itself but only statically. Thus the driver does not support changing clock rates, only querying them. +config CLK_OCTEON + bool "Clock controller driver for Marvell MIPS Octeon" + depends on CLK && ARCH_OCTEON + default y + help + Enable this to support the clocks on Octeon MIPS platforms. + config CLK_STM32F bool "Enable clock driver support for STM32F family" depends on CLK && (STM32F7 || STM32F4) diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index d911954581..cda4b4b605 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -29,6 +29,7 @@ obj-$(CONFIG_$(SPL_TPL_)CLK_INTEL) += intel/ obj-$(CONFIG_CLK_HSDK) += clk-hsdk-cgu.o obj-$(CONFIG_CLK_K210) += kendryte/ obj-$(CONFIG_CLK_MPC83XX) += mpc83xx_clk.o +obj-$(CONFIG_CLK_OCTEON) += clk_octeon.o obj-$(CONFIG_CLK_OWL) += owl/ obj-$(CONFIG_CLK_RENESAS) += renesas/ obj-$(CONFIG_CLK_SIFIVE) += sifive/ diff --git a/drivers/clk/altera/clk-agilex.c b/drivers/clk/altera/clk-agilex.c index 0042958f4c..9927ada201 100644 --- a/drivers/clk/altera/clk-agilex.c +++ b/drivers/clk/altera/clk-agilex.c @@ -553,7 +553,7 @@ static int socfpga_clk_ofdata_to_platdata(struct udevice *dev) struct socfpga_clk_platdata *plat = dev_get_platdata(dev); fdt_addr_t addr; - addr = devfdt_get_addr(dev); + addr = dev_read_addr(dev); if (addr == FDT_ADDR_T_NONE) return -EINVAL; plat->regs = (void __iomem *)addr; diff --git a/drivers/clk/altera/clk-arria10.c b/drivers/clk/altera/clk-arria10.c index ede0be299d..732ed4d79b 100644 --- a/drivers/clk/altera/clk-arria10.c +++ b/drivers/clk/altera/clk-arria10.c @@ -285,7 +285,7 @@ static int socfpga_a10_clk_probe(struct udevice *dev) socfpga_a10_handoff_workaround(dev); if (!fdt_node_check_compatible(fdt, offset, "altr,clk-mgr")) { - plat->regs = devfdt_get_addr(dev); + plat->regs = dev_read_addr(dev); } else { pdev = dev_get_parent(dev); if (!pdev) diff --git a/drivers/clk/clk-uclass.c b/drivers/clk/clk-uclass.c index 15656f5973..934cd5787a 100644 --- a/drivers/clk/clk-uclass.c +++ b/drivers/clk/clk-uclass.c @@ -25,6 +25,11 @@ static inline const struct clk_ops *clk_dev_ops(struct udevice *dev) return (const struct clk_ops *)dev->driver->ops; } +struct clk *dev_get_clk_ptr(struct udevice *dev) +{ + return (struct clk *)dev_get_uclass_priv(dev); +} + #if CONFIG_IS_ENABLED(OF_CONTROL) # if CONFIG_IS_ENABLED(OF_PLATDATA) int clk_get_by_driver_info(struct udevice *dev, struct phandle_1_arg *cells, diff --git a/drivers/clk/clk_octeon.c b/drivers/clk/clk_octeon.c new file mode 100644 index 0000000000..fd559e05fc --- /dev/null +++ b/drivers/clk/clk_octeon.c @@ -0,0 +1,72 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2020 Stefan Roese <sr@denx.de> + */ + +#include <clk-uclass.h> +#include <dm.h> +#include <dt-bindings/clock/octeon-clock.h> + +DECLARE_GLOBAL_DATA_PTR; + +struct octeon_clk_priv { + u64 core_clk; + u64 io_clk; +}; + +static int octeon_clk_enable(struct clk *clk) +{ + /* Nothing to do on Octeon */ + return 0; +} + +static ulong octeon_clk_get_rate(struct clk *clk) +{ + struct octeon_clk_priv *priv = dev_get_priv(clk->dev); + + switch (clk->id) { + case OCTEON_CLK_CORE: + return priv->core_clk; + + case OCTEON_CLK_IO: + return priv->io_clk; + + default: + return 0; + } + + return 0; +} + +static struct clk_ops octeon_clk_ops = { + .enable = octeon_clk_enable, + .get_rate = octeon_clk_get_rate, +}; + +static const struct udevice_id octeon_clk_ids[] = { + { .compatible = "mrvl,octeon-clk" }, + { /* sentinel */ } +}; + +static int octeon_clk_probe(struct udevice *dev) +{ + struct octeon_clk_priv *priv = dev_get_priv(dev); + + /* + * The clock values are already read into GD, lets just store them + * in priv data + */ + priv->core_clk = gd->cpu_clk; + priv->io_clk = gd->bus_clk; + + return 0; +} + +U_BOOT_DRIVER(clk_octeon) = { + .name = "clk_octeon", + .id = UCLASS_CLK, + .of_match = octeon_clk_ids, + .ops = &octeon_clk_ops, + .probe = octeon_clk_probe, + .priv_auto_alloc_size = sizeof(struct octeon_clk_priv), +}; diff --git a/drivers/clk/exynos/clk-exynos7420.c b/drivers/clk/exynos/clk-exynos7420.c index aa86c7ca44..4a023ea736 100644 --- a/drivers/clk/exynos/clk-exynos7420.c +++ b/drivers/clk/exynos/clk-exynos7420.c @@ -95,7 +95,7 @@ static int exynos7420_clk_topc_probe(struct udevice *dev) fdt_addr_t base; int ret; - base = devfdt_get_addr(dev); + base = dev_read_addr(dev); if (base == FDT_ADDR_T_NONE) return -EINVAL; @@ -149,7 +149,7 @@ static int exynos7420_clk_top0_probe(struct udevice *dev) if (!priv) return -EINVAL; - base = devfdt_get_addr(dev); + base = dev_read_addr(dev); if (base == FDT_ADDR_T_NONE) return -EINVAL; diff --git a/drivers/clk/kendryte/bypass.c b/drivers/clk/kendryte/bypass.c index d1fd28175b..5f1986f2cb 100644 --- a/drivers/clk/kendryte/bypass.c +++ b/drivers/clk/kendryte/bypass.c @@ -4,12 +4,15 @@ */ #define LOG_CATEGORY UCLASS_CLK -#include <kendryte/bypass.h> +#include <common.h> +#include <clk.h> #include <clk-uclass.h> +#include <dm.h> +#include <log.h> +#include <kendryte/bypass.h> #include <linux/clk-provider.h> #include <linux/err.h> -#include <log.h> #define CLK_K210_BYPASS "k210_clk_bypass" diff --git a/drivers/clk/kendryte/pll.c b/drivers/clk/kendryte/pll.c index 19e358856a..ab6d75d585 100644 --- a/drivers/clk/kendryte/pll.c +++ b/drivers/clk/kendryte/pll.c @@ -3,18 +3,20 @@ * Copyright (C) 2019-20 Sean Anderson <seanga2@gmail.com> */ #define LOG_CATEGORY UCLASS_CLK -#include <kendryte/pll.h> -#include <asm/io.h> +#include <common.h> +#include <dm.h> /* For DIV_ROUND_DOWN_ULL, defined in linux/kernel.h */ #include <div64.h> +#include <log.h> +#include <serial.h> +#include <asm/io.h> #include <dt-bindings/clock/k210-sysctl.h> +#include <kendryte/pll.h> #include <linux/bitfield.h> #include <linux/clk-provider.h> #include <linux/delay.h> #include <linux/err.h> -#include <log.h> -#include <serial.h> #define CLK_K210_PLL "k210_clk_pll" diff --git a/drivers/clk/renesas/Kconfig b/drivers/clk/renesas/Kconfig index e78817829b..284e2138b3 100644 --- a/drivers/clk/renesas/Kconfig +++ b/drivers/clk/renesas/Kconfig @@ -48,6 +48,13 @@ config CLK_RCAR_GEN3 help Enable this to support the clocks on Renesas RCar Gen3 SoC. +config CLK_R8A774A1 + bool "Renesas R8A774A1 clock driver" + def_bool y if R8A774A1 + depends on CLK_RCAR_GEN3 + help + Enable this to support the clocks on Renesas R8A774A1 SoC. + config CLK_R8A7795 bool "Renesas R8A7795 clock driver" depends on CLK_RCAR_GEN3 diff --git a/drivers/clk/renesas/Makefile b/drivers/clk/renesas/Makefile index 88339e9d7e..dd599b757e 100644 --- a/drivers/clk/renesas/Makefile +++ b/drivers/clk/renesas/Makefile @@ -1,5 +1,6 @@ obj-$(CONFIG_CLK_RENESAS) += renesas-cpg-mssr.o obj-$(CONFIG_CLK_RCAR_GEN2) += clk-rcar-gen2.o +obj-$(CONFIG_CLK_R8A774A1) += r8a774a1-cpg-mssr.o obj-$(CONFIG_CLK_R8A7790) += r8a7790-cpg-mssr.o obj-$(CONFIG_CLK_R8A7791) += r8a7791-cpg-mssr.o obj-$(CONFIG_CLK_R8A7792) += r8a7792-cpg-mssr.o diff --git a/drivers/clk/renesas/clk-rcar-gen2.c b/drivers/clk/renesas/clk-rcar-gen2.c index 3ed0aa92cb..16da10c8dd 100644 --- a/drivers/clk/renesas/clk-rcar-gen2.c +++ b/drivers/clk/renesas/clk-rcar-gen2.c @@ -283,7 +283,7 @@ int gen2_clk_probe(struct udevice *dev) u32 cpg_mode; int ret; - priv->base = (struct gen2_base *)devfdt_get_addr(dev); + priv->base = dev_read_addr_ptr(dev); if (!priv->base) return -EINVAL; diff --git a/drivers/clk/renesas/clk-rcar-gen3.c b/drivers/clk/renesas/clk-rcar-gen3.c index 15e3833756..30a101fe86 100644 --- a/drivers/clk/renesas/clk-rcar-gen3.c +++ b/drivers/clk/renesas/clk-rcar-gen3.c @@ -359,7 +359,7 @@ int gen3_clk_probe(struct udevice *dev) u32 cpg_mode; int ret; - priv->base = (struct gen3_base *)devfdt_get_addr(dev); + priv->base = dev_read_addr_ptr(dev); if (!priv->base) return -EINVAL; diff --git a/drivers/clk/renesas/r8a774a1-cpg-mssr.c b/drivers/clk/renesas/r8a774a1-cpg-mssr.c new file mode 100644 index 0000000000..8935667736 --- /dev/null +++ b/drivers/clk/renesas/r8a774a1-cpg-mssr.c @@ -0,0 +1,339 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Renesas R8A774A1 CPG MSSR driver + * + * Copyright (C) 2017-2019 Marek Vasut <marek.vasut@gmail.com> + * + * Based on the following driver from Linux kernel: + * r8a7796 Clock Pulse Generator / Module Standby and Software Reset + * + * Copyright (C) 2016 Glider bvba + */ + +#include <common.h> +#include <clk-uclass.h> +#include <dm.h> + +#include <dt-bindings/clock/r8a774a1-cpg-mssr.h> + +#include "renesas-cpg-mssr.h" +#include "rcar-gen3-cpg.h" + +enum clk_ids { + /* Core Clock Outputs exported to DT */ + LAST_DT_CORE_CLK = R8A774A1_CLK_CANFD, + + /* External Input Clocks */ + CLK_EXTAL, + CLK_EXTALR, + + /* Internal Core Clocks */ + CLK_MAIN, + CLK_PLL0, + CLK_PLL1, + CLK_PLL2, + CLK_PLL3, + CLK_PLL4, + CLK_PLL1_DIV2, + CLK_PLL1_DIV4, + CLK_S0, + CLK_S1, + CLK_S2, + CLK_S3, + CLK_SDSRC, + CLK_RINT, + + /* Module Clocks */ + MOD_CLK_BASE +}; + +static const struct cpg_core_clk r8a774a1_core_clks[] = { + /* External Clock Inputs */ + DEF_INPUT("extal", CLK_EXTAL), + DEF_INPUT("extalr", CLK_EXTALR), + + /* Internal Core Clocks */ + DEF_BASE(".main", CLK_MAIN, CLK_TYPE_GEN3_MAIN, CLK_EXTAL), + DEF_BASE(".pll0", CLK_PLL0, CLK_TYPE_GEN3_PLL0, CLK_MAIN), + DEF_BASE(".pll1", CLK_PLL1, CLK_TYPE_GEN3_PLL1, CLK_MAIN), + DEF_BASE(".pll2", CLK_PLL2, CLK_TYPE_GEN3_PLL2, CLK_MAIN), + DEF_BASE(".pll3", CLK_PLL3, CLK_TYPE_GEN3_PLL3, CLK_MAIN), + DEF_BASE(".pll4", CLK_PLL4, CLK_TYPE_GEN3_PLL4, CLK_MAIN), + + DEF_FIXED(".pll1_div2", CLK_PLL1_DIV2, CLK_PLL1, 2, 1), + DEF_FIXED(".pll1_div4", CLK_PLL1_DIV4, CLK_PLL1_DIV2, 2, 1), + DEF_FIXED(".s0", CLK_S0, CLK_PLL1_DIV2, 2, 1), + DEF_FIXED(".s1", CLK_S1, CLK_PLL1_DIV2, 3, 1), + DEF_FIXED(".s2", CLK_S2, CLK_PLL1_DIV2, 4, 1), + DEF_FIXED(".s3", CLK_S3, CLK_PLL1_DIV2, 6, 1), + DEF_FIXED(".sdsrc", CLK_SDSRC, CLK_PLL1_DIV2, 2, 1), + + DEF_GEN3_OSC(".r", CLK_RINT, CLK_EXTAL, 32), + + /* Core Clock Outputs */ + DEF_GEN3_Z("z", R8A774A1_CLK_Z, CLK_TYPE_GEN3_Z, CLK_PLL0, 2, 8), + DEF_GEN3_Z("z2", R8A774A1_CLK_Z2, CLK_TYPE_GEN3_Z, CLK_PLL2, 2, 0), + DEF_FIXED("ztr", R8A774A1_CLK_ZTR, CLK_PLL1_DIV2, 6, 1), + DEF_FIXED("ztrd2", R8A774A1_CLK_ZTRD2, CLK_PLL1_DIV2, 12, 1), + DEF_FIXED("zt", R8A774A1_CLK_ZT, CLK_PLL1_DIV2, 4, 1), + DEF_FIXED("zx", R8A774A1_CLK_ZX, CLK_PLL1_DIV2, 2, 1), + DEF_FIXED("s0d1", R8A774A1_CLK_S0D1, CLK_S0, 1, 1), + DEF_FIXED("s0d2", R8A774A1_CLK_S0D2, CLK_S0, 2, 1), + DEF_FIXED("s0d3", R8A774A1_CLK_S0D3, CLK_S0, 3, 1), + DEF_FIXED("s0d4", R8A774A1_CLK_S0D4, CLK_S0, 4, 1), + DEF_FIXED("s0d6", R8A774A1_CLK_S0D6, CLK_S0, 6, 1), + DEF_FIXED("s0d8", R8A774A1_CLK_S0D8, CLK_S0, 8, 1), + DEF_FIXED("s0d12", R8A774A1_CLK_S0D12, CLK_S0, 12, 1), + DEF_FIXED("s1d2", R8A774A1_CLK_S1D2, CLK_S1, 2, 1), + DEF_FIXED("s1d4", R8A774A1_CLK_S1D4, CLK_S1, 4, 1), + DEF_FIXED("s2d1", R8A774A1_CLK_S2D1, CLK_S2, 1, 1), + DEF_FIXED("s2d2", R8A774A1_CLK_S2D2, CLK_S2, 2, 1), + DEF_FIXED("s2d4", R8A774A1_CLK_S2D4, CLK_S2, 4, 1), + DEF_FIXED("s3d1", R8A774A1_CLK_S3D1, CLK_S3, 1, 1), + DEF_FIXED("s3d2", R8A774A1_CLK_S3D2, CLK_S3, 2, 1), + DEF_FIXED("s3d4", R8A774A1_CLK_S3D4, CLK_S3, 4, 1), + + DEF_GEN3_SD("sd0", R8A774A1_CLK_SD0, CLK_SDSRC, 0x074), + DEF_GEN3_SD("sd1", R8A774A1_CLK_SD1, CLK_SDSRC, 0x078), + DEF_GEN3_SD("sd2", R8A774A1_CLK_SD2, CLK_SDSRC, 0x268), + DEF_GEN3_SD("sd3", R8A774A1_CLK_SD3, CLK_SDSRC, 0x26c), + + DEF_FIXED("cl", R8A774A1_CLK_CL, CLK_PLL1_DIV2, 48, 1), + DEF_FIXED("cp", R8A774A1_CLK_CP, CLK_EXTAL, 2, 1), + DEF_FIXED("cpex", R8A774A1_CLK_CPEX, CLK_EXTAL, 2, 1), + + DEF_DIV6P1("canfd", R8A774A1_CLK_CANFD, CLK_PLL1_DIV4, 0x244), + DEF_DIV6P1("csi0", R8A774A1_CLK_CSI0, CLK_PLL1_DIV4, 0x00c), + DEF_DIV6P1("mso", R8A774A1_CLK_MSO, CLK_PLL1_DIV4, 0x014), + DEF_DIV6P1("hdmi", R8A774A1_CLK_HDMI, CLK_PLL1_DIV4, 0x250), + + DEF_GEN3_OSC("osc", R8A774A1_CLK_OSC, CLK_EXTAL, 8), + + DEF_BASE("r", R8A774A1_CLK_R, CLK_TYPE_GEN3_R, CLK_RINT), +}; + +static const struct mssr_mod_clk r8a774a1_mod_clks[] = { + DEF_MOD("tmu4", 121, R8A774A1_CLK_S0D6), + DEF_MOD("tmu3", 122, R8A774A1_CLK_S3D2), + DEF_MOD("tmu2", 123, R8A774A1_CLK_S3D2), + DEF_MOD("tmu1", 124, R8A774A1_CLK_S3D2), + DEF_MOD("tmu0", 125, R8A774A1_CLK_CP), + DEF_MOD("fdp1-0", 119, R8A774A1_CLK_S0D1), + DEF_MOD("scif5", 202, R8A774A1_CLK_S3D4), + DEF_MOD("scif4", 203, R8A774A1_CLK_S3D4), + DEF_MOD("scif3", 204, R8A774A1_CLK_S3D4), + DEF_MOD("scif1", 206, R8A774A1_CLK_S3D4), + DEF_MOD("scif0", 207, R8A774A1_CLK_S3D4), + DEF_MOD("msiof3", 208, R8A774A1_CLK_MSO), + DEF_MOD("msiof2", 209, R8A774A1_CLK_MSO), + DEF_MOD("msiof1", 210, R8A774A1_CLK_MSO), + DEF_MOD("msiof0", 211, R8A774A1_CLK_MSO), + DEF_MOD("sys-dmac2", 217, R8A774A1_CLK_S3D1), + DEF_MOD("sys-dmac1", 218, R8A774A1_CLK_S3D1), + DEF_MOD("sys-dmac0", 219, R8A774A1_CLK_S0D3), + DEF_MOD("cmt3", 300, R8A774A1_CLK_R), + DEF_MOD("cmt2", 301, R8A774A1_CLK_R), + DEF_MOD("cmt1", 302, R8A774A1_CLK_R), + DEF_MOD("cmt0", 303, R8A774A1_CLK_R), + DEF_MOD("scif2", 310, R8A774A1_CLK_S3D4), + DEF_MOD("sdif3", 311, R8A774A1_CLK_SD3), + DEF_MOD("sdif2", 312, R8A774A1_CLK_SD2), + DEF_MOD("sdif1", 313, R8A774A1_CLK_SD1), + DEF_MOD("sdif0", 314, R8A774A1_CLK_SD0), + DEF_MOD("pcie1", 318, R8A774A1_CLK_S3D1), + DEF_MOD("pcie0", 319, R8A774A1_CLK_S3D1), + DEF_MOD("usb3-if0", 328, R8A774A1_CLK_S3D1), + DEF_MOD("usb-dmac0", 330, R8A774A1_CLK_S3D1), + DEF_MOD("usb-dmac1", 331, R8A774A1_CLK_S3D1), + DEF_MOD("rwdt", 402, R8A774A1_CLK_R), + DEF_MOD("intc-ex", 407, R8A774A1_CLK_CP), + DEF_MOD("intc-ap", 408, R8A774A1_CLK_S0D3), + DEF_MOD("audmac1", 501, R8A774A1_CLK_S1D2), + DEF_MOD("audmac0", 502, R8A774A1_CLK_S1D2), + DEF_MOD("hscif4", 516, R8A774A1_CLK_S3D1), + DEF_MOD("hscif3", 517, R8A774A1_CLK_S3D1), + DEF_MOD("hscif2", 518, R8A774A1_CLK_S3D1), + DEF_MOD("hscif1", 519, R8A774A1_CLK_S3D1), + DEF_MOD("hscif0", 520, R8A774A1_CLK_S3D1), + DEF_MOD("thermal", 522, R8A774A1_CLK_CP), + DEF_MOD("pwm", 523, R8A774A1_CLK_S0D12), + DEF_MOD("fcpvd2", 601, R8A774A1_CLK_S0D2), + DEF_MOD("fcpvd1", 602, R8A774A1_CLK_S0D2), + DEF_MOD("fcpvd0", 603, R8A774A1_CLK_S0D2), + DEF_MOD("fcpvb0", 607, R8A774A1_CLK_S0D1), + DEF_MOD("fcpvi0", 611, R8A774A1_CLK_S0D1), + DEF_MOD("fcpf0", 615, R8A774A1_CLK_S0D1), + DEF_MOD("fcpci0", 617, R8A774A1_CLK_S0D2), + DEF_MOD("fcpcs", 619, R8A774A1_CLK_S0D2), + DEF_MOD("vspd2", 621, R8A774A1_CLK_S0D2), + DEF_MOD("vspd1", 622, R8A774A1_CLK_S0D2), + DEF_MOD("vspd0", 623, R8A774A1_CLK_S0D2), + DEF_MOD("vspb", 626, R8A774A1_CLK_S0D1), + DEF_MOD("vspi0", 631, R8A774A1_CLK_S0D1), + DEF_MOD("ehci1", 702, R8A774A1_CLK_S3D2), + DEF_MOD("ehci0", 703, R8A774A1_CLK_S3D2), + DEF_MOD("hsusb", 704, R8A774A1_CLK_S3D2), + DEF_MOD("csi20", 714, R8A774A1_CLK_CSI0), + DEF_MOD("csi40", 716, R8A774A1_CLK_CSI0), + DEF_MOD("du2", 722, R8A774A1_CLK_S2D1), + DEF_MOD("du1", 723, R8A774A1_CLK_S2D1), + DEF_MOD("du0", 724, R8A774A1_CLK_S2D1), + DEF_MOD("lvds", 727, R8A774A1_CLK_S2D1), + DEF_MOD("hdmi0", 729, R8A774A1_CLK_HDMI), + DEF_MOD("vin7", 804, R8A774A1_CLK_S0D2), + DEF_MOD("vin6", 805, R8A774A1_CLK_S0D2), + DEF_MOD("vin5", 806, R8A774A1_CLK_S0D2), + DEF_MOD("vin4", 807, R8A774A1_CLK_S0D2), + DEF_MOD("vin3", 808, R8A774A1_CLK_S0D2), + DEF_MOD("vin2", 809, R8A774A1_CLK_S0D2), + DEF_MOD("vin1", 810, R8A774A1_CLK_S0D2), + DEF_MOD("vin0", 811, R8A774A1_CLK_S0D2), + DEF_MOD("etheravb", 812, R8A774A1_CLK_S0D6), + DEF_MOD("gpio7", 905, R8A774A1_CLK_S3D4), + DEF_MOD("gpio6", 906, R8A774A1_CLK_S3D4), + DEF_MOD("gpio5", 907, R8A774A1_CLK_S3D4), + DEF_MOD("gpio4", 908, R8A774A1_CLK_S3D4), + DEF_MOD("gpio3", 909, R8A774A1_CLK_S3D4), + DEF_MOD("gpio2", 910, R8A774A1_CLK_S3D4), + DEF_MOD("gpio1", 911, R8A774A1_CLK_S3D4), + DEF_MOD("gpio0", 912, R8A774A1_CLK_S3D4), + DEF_MOD("can-fd", 914, R8A774A1_CLK_S3D2), + DEF_MOD("can-if1", 915, R8A774A1_CLK_S3D4), + DEF_MOD("can-if0", 916, R8A774A1_CLK_S3D4), + DEF_MOD("i2c6", 918, R8A774A1_CLK_S0D6), + DEF_MOD("i2c5", 919, R8A774A1_CLK_S0D6), + DEF_MOD("i2c-dvfs", 926, R8A774A1_CLK_CP), + DEF_MOD("i2c4", 927, R8A774A1_CLK_S0D6), + DEF_MOD("i2c3", 928, R8A774A1_CLK_S0D6), + DEF_MOD("i2c2", 929, R8A774A1_CLK_S3D2), + DEF_MOD("i2c1", 930, R8A774A1_CLK_S3D2), + DEF_MOD("i2c0", 931, R8A774A1_CLK_S3D2), + DEF_MOD("ssi-all", 1005, R8A774A1_CLK_S3D4), + DEF_MOD("ssi9", 1006, MOD_CLK_ID(1005)), + DEF_MOD("ssi8", 1007, MOD_CLK_ID(1005)), + DEF_MOD("ssi7", 1008, MOD_CLK_ID(1005)), + DEF_MOD("ssi6", 1009, MOD_CLK_ID(1005)), + DEF_MOD("ssi5", 1010, MOD_CLK_ID(1005)), + DEF_MOD("ssi4", 1011, MOD_CLK_ID(1005)), + DEF_MOD("ssi3", 1012, MOD_CLK_ID(1005)), + DEF_MOD("ssi2", 1013, MOD_CLK_ID(1005)), + DEF_MOD("ssi1", 1014, MOD_CLK_ID(1005)), + DEF_MOD("ssi0", 1015, MOD_CLK_ID(1005)), + DEF_MOD("scu-all", 1017, R8A774A1_CLK_S3D4), + DEF_MOD("scu-dvc1", 1018, MOD_CLK_ID(1017)), + DEF_MOD("scu-dvc0", 1019, MOD_CLK_ID(1017)), + DEF_MOD("scu-ctu1-mix1", 1020, MOD_CLK_ID(1017)), + DEF_MOD("scu-ctu0-mix0", 1021, MOD_CLK_ID(1017)), + DEF_MOD("scu-src9", 1022, MOD_CLK_ID(1017)), + DEF_MOD("scu-src8", 1023, MOD_CLK_ID(1017)), + DEF_MOD("scu-src7", 1024, MOD_CLK_ID(1017)), + DEF_MOD("scu-src6", 1025, MOD_CLK_ID(1017)), + DEF_MOD("scu-src5", 1026, MOD_CLK_ID(1017)), + DEF_MOD("scu-src4", 1027, MOD_CLK_ID(1017)), + DEF_MOD("scu-src3", 1028, MOD_CLK_ID(1017)), + DEF_MOD("scu-src2", 1029, MOD_CLK_ID(1017)), + DEF_MOD("scu-src1", 1030, MOD_CLK_ID(1017)), + DEF_MOD("scu-src0", 1031, MOD_CLK_ID(1017)), +}; + +/* + * CPG Clock Data + */ + +/* + * MD EXTAL PLL0 PLL1 PLL2 PLL3 PLL4 OSC + * 14 13 19 17 (MHz) + *------------------------------------------------------------------------- + * 0 0 0 0 16.66 x 1 x180 x192 x144 x192 x144 /16 + * 0 0 0 1 16.66 x 1 x180 x192 x144 x128 x144 /16 + * 0 0 1 0 Prohibited setting + * 0 0 1 1 16.66 x 1 x180 x192 x144 x192 x144 /16 + * 0 1 0 0 20 x 1 x150 x160 x120 x160 x120 /19 + * 0 1 0 1 20 x 1 x150 x160 x120 x106 x120 /19 + * 0 1 1 0 Prohibited setting + * 0 1 1 1 20 x 1 x150 x160 x120 x160 x120 /19 + * 1 0 0 0 25 x 1 x120 x128 x96 x128 x96 /24 + * 1 0 0 1 25 x 1 x120 x128 x96 x84 x96 /24 + * 1 0 1 0 Prohibited setting + * 1 0 1 1 25 x 1 x120 x128 x96 x128 x96 /24 + * 1 1 0 0 33.33 / 2 x180 x192 x144 x192 x144 /32 + * 1 1 0 1 33.33 / 2 x180 x192 x144 x128 x144 /32 + * 1 1 1 0 Prohibited setting + * 1 1 1 1 33.33 / 2 x180 x192 x144 x192 x144 /32 + */ +#define CPG_PLL_CONFIG_INDEX(md) ((((md) & BIT(14)) >> 11) | \ + (((md) & BIT(13)) >> 11) | \ + (((md) & BIT(19)) >> 18) | \ + (((md) & BIT(17)) >> 17)) + +static const struct rcar_gen3_cpg_pll_config cpg_pll_configs[16] = { + /* EXTAL div PLL1 mult/div PLL3 mult/div OSC prediv */ + { 1, 192, 1, 192, 1, 16, }, + { 1, 192, 1, 128, 1, 16, }, + { 0, /* Prohibited setting */ }, + { 1, 192, 1, 192, 1, 16, }, + { 1, 160, 1, 160, 1, 19, }, + { 1, 160, 1, 106, 1, 19, }, + { 0, /* Prohibited setting */ }, + { 1, 160, 1, 160, 1, 19, }, + { 1, 128, 1, 128, 1, 24, }, + { 1, 128, 1, 84, 1, 24, }, + { 0, /* Prohibited setting */ }, + { 1, 128, 1, 128, 1, 24, }, + { 2, 192, 1, 192, 1, 32, }, + { 2, 192, 1, 128, 1, 32, }, + { 0, /* Prohibited setting */ }, + { 2, 192, 1, 192, 1, 32, }, +}; + +static const struct mstp_stop_table r8a774a1_mstp_table[] = { + { 0x00000000, 0, 0x00000000, 0 }, + { 0xc3e81000, 0, 0xc3e81000, 0 }, + { 0x000E0FDC, 0, 0x000E0FDC, 0 }, + { 0xD00C7C1F, 0, 0xD00C7C1F, 0 }, + { 0x80000004, 0, 0x80000004, 0 }, + { 0x00DF0006, 0, 0x00DF0006, 0 }, + { 0XC5EACCCE, 0, 0XC5EACCCE, 0 }, + { 0x29E1401C, 0, 0x29E1401C, 0 }, + { 0x00009FF1, 0, 0x00009FF1, 0 }, + { 0xFC4FDFE0, 0, 0xFC4FDFE0, 0 }, + { 0xFFFEFFE8, 0, 0xFFFEFFE8, 0 }, +}; + +static const void *r8a774a1_get_pll_config(const u32 cpg_mode) +{ + return &cpg_pll_configs[CPG_PLL_CONFIG_INDEX(cpg_mode)]; +} + +static const struct cpg_mssr_info r8a774a1_cpg_mssr_info = { + .core_clk = r8a774a1_core_clks, + .core_clk_size = ARRAY_SIZE(r8a774a1_core_clks), + .mod_clk = r8a774a1_mod_clks, + .mod_clk_size = ARRAY_SIZE(r8a774a1_mod_clks), + .mstp_table = r8a774a1_mstp_table, + .mstp_table_size = ARRAY_SIZE(r8a774a1_mstp_table), + .reset_node = "renesas,r8a774a1-rst", + .extalr_node = "extalr", + .mod_clk_base = MOD_CLK_BASE, + .clk_extal_id = CLK_EXTAL, + .clk_extalr_id = CLK_EXTALR, + .get_pll_config = r8a774a1_get_pll_config, +}; + +static const struct udevice_id r8a774a1_clk_ids[] = { + { + .compatible = "renesas,r8a774a1-cpg-mssr", + .data = (ulong)&r8a774a1_cpg_mssr_info, + }, + { } +}; + +U_BOOT_DRIVER(clk_r8a774a1) = { + .name = "clk_r8a774a1", + .id = UCLASS_CLK, + .of_match = r8a774a1_clk_ids, + .priv_auto_alloc_size = sizeof(struct gen3_clk_priv), + .ops = &gen3_clk_ops, + .probe = gen3_clk_probe, + .remove = gen3_clk_remove, +}; diff --git a/drivers/clk/renesas/rcar-gen3-cpg.h b/drivers/clk/renesas/rcar-gen3-cpg.h index 7b1b242215..3beae7d825 100644 --- a/drivers/clk/renesas/rcar-gen3-cpg.h +++ b/drivers/clk/renesas/rcar-gen3-cpg.h @@ -56,6 +56,8 @@ enum rcar_gen3_clk_types { DEF_BASE(_name, _id, CLK_TYPE_GEN3_RCKSEL, \ (_parent0) << 16 | (_parent1), .div = (_div0) << 16 | (_div1)) +#define DEF_GEN3_Z(_name, _id, _type, _parent, _div, _offset) \ + DEF_BASE(_name, _id, _type, _parent, .div = _div, .offset = _offset) struct rcar_gen3_cpg_pll_config { u8 extal_div; diff --git a/drivers/clk/sifive/fu540-prci.c b/drivers/clk/sifive/fu540-prci.c index fe6e0d4073..c5148e9a37 100644 --- a/drivers/clk/sifive/fu540-prci.c +++ b/drivers/clk/sifive/fu540-prci.c @@ -30,17 +30,22 @@ #include <common.h> #include <asm/io.h> +#include <asm/arch/reset.h> #include <clk-uclass.h> #include <clk.h> #include <div64.h> #include <dm.h> #include <errno.h> +#include <reset-uclass.h> +#include <dm/device.h> +#include <dm/uclass.h> #include <linux/delay.h> #include <linux/err.h> #include <linux/math64.h> #include <linux/clk/analogbits-wrpll-cln28hpc.h> #include <dt-bindings/clock/sifive-fu540-prci.h> +#include <dt-bindings/reset/sifive-fu540-prci.h> /* * EXPECTED_CLK_PARENT_COUNT: how many parent clocks this driver expects: @@ -131,21 +136,18 @@ /* DEVICESRESETREG */ #define PRCI_DEVICESRESETREG_OFFSET 0x28 -#define PRCI_DEVICESRESETREG_DDR_CTRL_RST_N_SHIFT 0 +#define PRCI_DEVICERESETCNT 5 + #define PRCI_DEVICESRESETREG_DDR_CTRL_RST_N_MASK \ - (0x1 << PRCI_DEVICESRESETREG_DDR_CTRL_RST_N_SHIFT) -#define PRCI_DEVICESRESETREG_DDR_AXI_RST_N_SHIFT 1 + (0x1 << PRCI_RST_DDR_CTRL_N) #define PRCI_DEVICESRESETREG_DDR_AXI_RST_N_MASK \ - (0x1 << PRCI_DEVICESRESETREG_DDR_AXI_RST_N_SHIFT) -#define PRCI_DEVICESRESETREG_DDR_AHB_RST_N_SHIFT 2 + (0x1 << PRCI_RST_DDR_AXI_N) #define PRCI_DEVICESRESETREG_DDR_AHB_RST_N_MASK \ - (0x1 << PRCI_DEVICESRESETREG_DDR_AHB_RST_N_SHIFT) -#define PRCI_DEVICESRESETREG_DDR_PHY_RST_N_SHIFT 3 + (0x1 << PRCI_RST_DDR_AHB_N) #define PRCI_DEVICESRESETREG_DDR_PHY_RST_N_MASK \ - (0x1 << PRCI_DEVICESRESETREG_DDR_PHY_RST_N_SHIFT) -#define PRCI_DEVICESRESETREG_GEMGXL_RST_N_SHIFT 5 + (0x1 << PRCI_RST_DDR_PHY_N) #define PRCI_DEVICESRESETREG_GEMGXL_RST_N_MASK \ - (0x1 << PRCI_DEVICESRESETREG_GEMGXL_RST_N_SHIFT) + (0x1 << PRCI_RST_GEMGXL_N) /* CLKMUXSTATUSREG */ #define PRCI_CLKMUXSTATUSREG_OFFSET 0x2c @@ -528,6 +530,41 @@ static const struct __prci_clock_ops sifive_fu540_prci_tlclksel_clk_ops = { .recalc_rate = sifive_fu540_prci_tlclksel_recalc_rate, }; +static int __prci_consumer_reset(const char *rst_name, bool trigger) +{ + struct udevice *dev; + struct reset_ctl rst_sig; + int ret; + + ret = uclass_get_device_by_driver(UCLASS_RESET, + DM_GET_DRIVER(sifive_reset), + &dev); + if (ret) { + dev_err(dev, "Reset driver not found: %d\n", ret); + return ret; + } + + ret = reset_get_by_name(dev, rst_name, &rst_sig); + if (ret) { + dev_err(dev, "failed to get %s reset\n", rst_name); + return ret; + } + + if (reset_valid(&rst_sig)) { + if (trigger) + ret = reset_deassert(&rst_sig); + else + ret = reset_assert(&rst_sig); + if (ret) { + dev_err(dev, "failed to trigger reset id = %ld\n", + rst_sig.id); + return ret; + } + } + + return ret; +} + /** * __prci_ddr_release_reset() - Release DDR reset * @pd: struct __prci_data * for the PRCI containing the DDRCLK mux reg @@ -535,19 +572,20 @@ static const struct __prci_clock_ops sifive_fu540_prci_tlclksel_clk_ops = { */ static void __prci_ddr_release_reset(struct __prci_data *pd) { - u32 v; - - v = __prci_readl(pd, PRCI_DEVICESRESETREG_OFFSET); - v |= PRCI_DEVICESRESETREG_DDR_CTRL_RST_N_MASK; - __prci_writel(v, PRCI_DEVICESRESETREG_OFFSET, pd); + /* Release DDR ctrl reset */ + __prci_consumer_reset("ddr_ctrl", true); /* HACK to get the '1 full controller clock cycle'. */ asm volatile ("fence"); - v = __prci_readl(pd, PRCI_DEVICESRESETREG_OFFSET); - v |= (PRCI_DEVICESRESETREG_DDR_AXI_RST_N_MASK | - PRCI_DEVICESRESETREG_DDR_AHB_RST_N_MASK | - PRCI_DEVICESRESETREG_DDR_PHY_RST_N_MASK); - __prci_writel(v, PRCI_DEVICESRESETREG_OFFSET, pd); + + /* Release DDR AXI reset */ + __prci_consumer_reset("ddr_axi", true); + + /* Release DDR AHB reset */ + __prci_consumer_reset("ddr_ahb", true); + + /* Release DDR PHY reset */ + __prci_consumer_reset("ddr_phy", true); /* HACK to get the '1 full controller clock cycle'. */ asm volatile ("fence"); @@ -567,12 +605,8 @@ static void __prci_ddr_release_reset(struct __prci_data *pd) */ static void __prci_ethernet_release_reset(struct __prci_data *pd) { - u32 v; - /* Release GEMGXL reset */ - v = __prci_readl(pd, PRCI_DEVICESRESETREG_OFFSET); - v |= PRCI_DEVICESRESETREG_GEMGXL_RST_N_MASK; - __prci_writel(v, PRCI_DEVICESRESETREG_OFFSET, pd); + __prci_consumer_reset("gemgxl_reset", true); /* Procmon => core clock */ __prci_writel(PRCI_PROCMONCFG_CORE_CLOCK_MASK, PRCI_PROCMONCFG_OFFSET, @@ -757,6 +791,11 @@ static struct clk_ops sifive_fu540_prci_ops = { .disable = sifive_fu540_prci_disable, }; +static int sifive_fu540_clk_bind(struct udevice *dev) +{ + return sifive_reset_bind(dev, PRCI_DEVICERESETCNT); +} + static const struct udevice_id sifive_fu540_prci_ids[] = { { .compatible = "sifive,fu540-c000-prci" }, { } @@ -769,4 +808,5 @@ U_BOOT_DRIVER(sifive_fu540_prci) = { .probe = sifive_fu540_prci_probe, .ops = &sifive_fu540_prci_ops, .priv_auto_alloc_size = sizeof(struct __prci_data), + .bind = sifive_fu540_clk_bind, }; diff --git a/drivers/clk/uniphier/clk-uniphier-core.c b/drivers/clk/uniphier/clk-uniphier-core.c index c9ec523080..4e25db354e 100644 --- a/drivers/clk/uniphier/clk-uniphier-core.c +++ b/drivers/clk/uniphier/clk-uniphier-core.c @@ -253,7 +253,7 @@ static int uniphier_clk_probe(struct udevice *dev) struct uniphier_clk_priv *priv = dev_get_priv(dev); fdt_addr_t addr; - addr = devfdt_get_addr(dev->parent); + addr = dev_read_addr(dev->parent); if (addr == FDT_ADDR_T_NONE) return -EINVAL; diff --git a/drivers/core/device.c b/drivers/core/device.c index 476133f172..355dbd147a 100644 --- a/drivers/core/device.c +++ b/drivers/core/device.c @@ -82,7 +82,8 @@ static int device_bind_common(struct udevice *parent, const struct driver *drv, * This is just a 'requested' sequence, and will be * resolved (and ->seq updated) when the device is probed. */ - if (CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)) { + if (CONFIG_IS_ENABLED(OF_CONTROL) && + !CONFIG_IS_ENABLED(OF_PLATDATA)) { if (uc->uc_drv->name && ofnode_valid(node)) dev_read_alias_seq(dev, &dev->req_seq); #if CONFIG_IS_ENABLED(OF_PRIOR_STAGE) diff --git a/drivers/cpu/bmips_cpu.c b/drivers/cpu/bmips_cpu.c index 2649c5c6e9..421cc7a9a4 100644 --- a/drivers/cpu/bmips_cpu.c +++ b/drivers/cpu/bmips_cpu.c @@ -379,7 +379,7 @@ static const struct bmips_cpu_hw bmips_cpu_bcm6838 = { }; /* Generic CPU Ops */ -static int bmips_cpu_get_desc(struct udevice *dev, char *buf, int size) +static int bmips_cpu_get_desc(const struct udevice *dev, char *buf, int size) { struct bmips_cpu_priv *priv = dev_get_priv(dev); const struct bmips_cpu_hw *hw = priv->hw; @@ -387,7 +387,7 @@ static int bmips_cpu_get_desc(struct udevice *dev, char *buf, int size) return hw->get_cpu_desc(priv, buf, size); } -static int bmips_cpu_get_info(struct udevice *dev, struct cpu_info *info) +static int bmips_cpu_get_info(const struct udevice *dev, struct cpu_info *info) { struct bmips_cpu_priv *priv = dev_get_priv(dev); const struct bmips_cpu_hw *hw = priv->hw; @@ -400,7 +400,7 @@ static int bmips_cpu_get_info(struct udevice *dev, struct cpu_info *info) return 0; } -static int bmips_cpu_get_count(struct udevice *dev) +static int bmips_cpu_get_count(const struct udevice *dev) { struct bmips_cpu_priv *priv = dev_get_priv(dev); const struct bmips_cpu_hw *hw = priv->hw; @@ -408,7 +408,7 @@ static int bmips_cpu_get_count(struct udevice *dev) return hw->get_cpu_count(priv); } -static int bmips_cpu_get_vendor(struct udevice *dev, char *buf, int size) +static int bmips_cpu_get_vendor(const struct udevice *dev, char *buf, int size) { snprintf(buf, size, "Broadcom"); diff --git a/drivers/cpu/cpu-uclass.c b/drivers/cpu/cpu-uclass.c index cbb4419ec0..37e3cf2d8f 100644 --- a/drivers/cpu/cpu-uclass.c +++ b/drivers/cpu/cpu-uclass.c @@ -69,7 +69,7 @@ struct udevice *cpu_get_current_dev(void) return cpu; } -int cpu_get_desc(struct udevice *dev, char *buf, int size) +int cpu_get_desc(const struct udevice *dev, char *buf, int size) { struct cpu_ops *ops = cpu_get_ops(dev); @@ -79,7 +79,7 @@ int cpu_get_desc(struct udevice *dev, char *buf, int size) return ops->get_desc(dev, buf, size); } -int cpu_get_info(struct udevice *dev, struct cpu_info *info) +int cpu_get_info(const struct udevice *dev, struct cpu_info *info) { struct cpu_ops *ops = cpu_get_ops(dev); @@ -92,7 +92,7 @@ int cpu_get_info(struct udevice *dev, struct cpu_info *info) return ops->get_info(dev, info); } -int cpu_get_count(struct udevice *dev) +int cpu_get_count(const struct udevice *dev) { struct cpu_ops *ops = cpu_get_ops(dev); @@ -102,7 +102,7 @@ int cpu_get_count(struct udevice *dev) return ops->get_count(dev); } -int cpu_get_vendor(struct udevice *dev, char *buf, int size) +int cpu_get_vendor(const struct udevice *dev, char *buf, int size) { struct cpu_ops *ops = cpu_get_ops(dev); diff --git a/drivers/cpu/cpu_sandbox.c b/drivers/cpu/cpu_sandbox.c index 30a12e5a53..caa26e50f2 100644 --- a/drivers/cpu/cpu_sandbox.c +++ b/drivers/cpu/cpu_sandbox.c @@ -8,14 +8,14 @@ #include <dm.h> #include <cpu.h> -int cpu_sandbox_get_desc(struct udevice *dev, char *buf, int size) +int cpu_sandbox_get_desc(const struct udevice *dev, char *buf, int size) { snprintf(buf, size, "LEG Inc. SuperMegaUltraTurbo CPU No. 1"); return 0; } -int cpu_sandbox_get_info(struct udevice *dev, struct cpu_info *info) +int cpu_sandbox_get_info(const struct udevice *dev, struct cpu_info *info) { info->cpu_freq = 42 * 42 * 42 * 42 * 42; info->features = 0x42424242; @@ -24,12 +24,12 @@ int cpu_sandbox_get_info(struct udevice *dev, struct cpu_info *info) return 0; } -int cpu_sandbox_get_count(struct udevice *dev) +int cpu_sandbox_get_count(const struct udevice *dev) { return 42; } -int cpu_sandbox_get_vendor(struct udevice *dev, char *buf, int size) +int cpu_sandbox_get_vendor(const struct udevice *dev, char *buf, int size) { snprintf(buf, size, "Languid Example Garbage Inc."); diff --git a/drivers/cpu/imx8_cpu.c b/drivers/cpu/imx8_cpu.c index 6345cd0815..502c8ebb43 100644 --- a/drivers/cpu/imx8_cpu.c +++ b/drivers/cpu/imx8_cpu.c @@ -100,7 +100,7 @@ static int cpu_imx_get_temp(struct cpu_imx_platdata *plat) } #endif -int cpu_imx_get_desc(struct udevice *dev, char *buf, int size) +int cpu_imx_get_desc(const struct udevice *dev, char *buf, int size) { struct cpu_imx_platdata *plat = dev_get_platdata(dev); int ret, temp; @@ -126,7 +126,7 @@ int cpu_imx_get_desc(struct udevice *dev, char *buf, int size) return 0; } -static int cpu_imx_get_info(struct udevice *dev, struct cpu_info *info) +static int cpu_imx_get_info(const struct udevice *dev, struct cpu_info *info) { struct cpu_imx_platdata *plat = dev_get_platdata(dev); @@ -135,7 +135,7 @@ static int cpu_imx_get_info(struct udevice *dev, struct cpu_info *info) return 0; } -static int cpu_imx_get_count(struct udevice *dev) +static int cpu_imx_get_count(const struct udevice *dev) { ofnode node; int num = 0; @@ -157,7 +157,7 @@ static int cpu_imx_get_count(struct udevice *dev) return num; } -static int cpu_imx_get_vendor(struct udevice *dev, char *buf, int size) +static int cpu_imx_get_vendor(const struct udevice *dev, char *buf, int size) { snprintf(buf, size, "NXP"); return 0; diff --git a/drivers/cpu/mpc83xx_cpu.c b/drivers/cpu/mpc83xx_cpu.c index f8a84bae9d..5f1592f9ad 100644 --- a/drivers/cpu/mpc83xx_cpu.c +++ b/drivers/cpu/mpc83xx_cpu.c @@ -60,7 +60,7 @@ static inline u32 get_spridr(void) * determine_type() - Determine CPU family of MPC83xx device * @dev: CPU device from which to read CPU family from */ -static inline void determine_family(struct udevice *dev) +static inline void determine_family(const struct udevice *dev) { struct mpc83xx_cpu_priv *priv = dev_get_priv(dev); /* Upper 12 bits of PARTID field (bits 0-23 in SPRIDR) */ @@ -95,7 +95,7 @@ static inline void determine_family(struct udevice *dev) * determine_type() - Determine CPU type of MPC83xx device * @dev: CPU device from which to read CPU type from */ -static inline void determine_type(struct udevice *dev) +static inline void determine_type(const struct udevice *dev) { struct mpc83xx_cpu_priv *priv = dev_get_priv(dev); /* Upper 16 bits of PVR (Processor Version Register) */ @@ -169,7 +169,7 @@ static inline void determine_type(struct udevice *dev) * determine_e300_type() - Determine e300 core type of MPC83xx device * @dev: CPU device from which to read e300 core type from */ -static inline void determine_e300_type(struct udevice *dev) +static inline void determine_e300_type(const struct udevice *dev) { struct mpc83xx_cpu_priv *priv = dev_get_priv(dev); /* Upper 16 bits of PVR (Processor Version Register) */ @@ -198,7 +198,7 @@ static inline void determine_e300_type(struct udevice *dev) * determine_revid() - Determine revision ID of CPU device * @dev: CPU device from which to read revision ID */ -static inline void determine_revid(struct udevice *dev) +static inline void determine_revid(const struct udevice *dev) { struct mpc83xx_cpu_priv *priv = dev_get_priv(dev); u32 REVID_MAJOR_MASK; @@ -221,7 +221,7 @@ static inline void determine_revid(struct udevice *dev) * determine_cpu_data() - Determine CPU information from hardware * @dev: CPU device from which to read information */ -static void determine_cpu_data(struct udevice *dev) +static void determine_cpu_data(const struct udevice *dev) { struct mpc83xx_cpu_priv *priv = dev_get_priv(dev); const u32 E_FLAG_MASK = 0x00010000; @@ -239,7 +239,7 @@ static void determine_cpu_data(struct udevice *dev) priv->is_e_processor = !bitfield_extract_by_mask(spridr, E_FLAG_MASK); } -static int mpc83xx_cpu_get_desc(struct udevice *dev, char *buf, int size) +static int mpc83xx_cpu_get_desc(const struct udevice *dev, char *buf, int size) { struct mpc83xx_cpu_priv *priv = dev_get_priv(dev); struct clk core_clk; @@ -248,14 +248,14 @@ static int mpc83xx_cpu_get_desc(struct udevice *dev, char *buf, int size) char csb_freq[32]; int ret; - ret = clk_get_by_index(dev, 0, &core_clk); + ret = clk_get_by_index((struct udevice *)dev, 0, &core_clk); if (ret) { debug("%s: Failed to get core clock (err = %d)\n", dev->name, ret); return ret; } - ret = clk_get_by_index(dev, 1, &csb_clk); + ret = clk_get_by_index((struct udevice *)dev, 1, &csb_clk); if (ret) { debug("%s: Failed to get CSB clock (err = %d)\n", dev->name, ret); @@ -278,13 +278,14 @@ static int mpc83xx_cpu_get_desc(struct udevice *dev, char *buf, int size) return 0; } -static int mpc83xx_cpu_get_info(struct udevice *dev, struct cpu_info *info) +static int mpc83xx_cpu_get_info(const struct udevice *dev, + struct cpu_info *info) { struct clk clock; int ret; ulong freq; - ret = clk_get_by_index(dev, 0, &clock); + ret = clk_get_by_index((struct udevice *)dev, 0, &clock); if (ret) { debug("%s: Failed to get core clock (err = %d)\n", dev->name, ret); @@ -303,13 +304,14 @@ static int mpc83xx_cpu_get_info(struct udevice *dev, struct cpu_info *info) return 0; } -static int mpc83xx_cpu_get_count(struct udevice *dev) +static int mpc83xx_cpu_get_count(const struct udevice *dev) { /* We have one e300cX core */ return 1; } -static int mpc83xx_cpu_get_vendor(struct udevice *dev, char *buf, int size) +static int mpc83xx_cpu_get_vendor(const struct udevice *dev, char *buf, + int size) { snprintf(buf, size, "NXP"); diff --git a/drivers/cpu/riscv_cpu.c b/drivers/cpu/riscv_cpu.c index 100fe5542e..93ce708f65 100644 --- a/drivers/cpu/riscv_cpu.c +++ b/drivers/cpu/riscv_cpu.c @@ -17,7 +17,7 @@ DECLARE_GLOBAL_DATA_PTR; -static int riscv_cpu_get_desc(struct udevice *dev, char *buf, int size) +static int riscv_cpu_get_desc(const struct udevice *dev, char *buf, int size) { const char *isa; @@ -30,7 +30,7 @@ static int riscv_cpu_get_desc(struct udevice *dev, char *buf, int size) return 0; } -static int riscv_cpu_get_info(struct udevice *dev, struct cpu_info *info) +static int riscv_cpu_get_info(const struct udevice *dev, struct cpu_info *info) { int ret; struct clk clk; @@ -39,7 +39,7 @@ static int riscv_cpu_get_info(struct udevice *dev, struct cpu_info *info) u32 d_cache_size; /* First try getting the frequency from the assigned clock */ - ret = clk_get_by_index(dev, 0, &clk); + ret = clk_get_by_index((struct udevice *)dev, 0, &clk); if (!ret) { ret = clk_get_rate(&clk); if (!IS_ERR_VALUE(ret)) @@ -67,7 +67,7 @@ static int riscv_cpu_get_info(struct udevice *dev, struct cpu_info *info) return 0; } -static int riscv_cpu_get_count(struct udevice *dev) +static int riscv_cpu_get_count(const struct udevice *dev) { ofnode node; int num = 0; diff --git a/drivers/crypto/fsl/Kconfig b/drivers/crypto/fsl/Kconfig index 181a1e5e99..5ed6140da3 100644 --- a/drivers/crypto/fsl/Kconfig +++ b/drivers/crypto/fsl/Kconfig @@ -45,3 +45,17 @@ config SYS_FSL_SEC_COMPAT config SYS_FSL_SEC_LE bool "Little-endian access to Freescale Secure Boot" + +if FSL_CAAM + +config FSL_CAAM_RNG + bool "Enable Random Number Generator support" + depends on DM_RNG + default y + help + Enable support for the hardware based random number generator + module of the CAAM. The random data is fetched from the DRGB + using the prediction resistance flag which means the DRGB is + reseeded from the TRNG every time random data is generated. + +endif diff --git a/drivers/crypto/fsl/Makefile b/drivers/crypto/fsl/Makefile index cfb36f3bb9..a5e8d38e38 100644 --- a/drivers/crypto/fsl/Makefile +++ b/drivers/crypto/fsl/Makefile @@ -7,3 +7,4 @@ obj-$(CONFIG_FSL_CAAM) += jr.o fsl_hash.o jobdesc.o error.o obj-$(CONFIG_CMD_BLOB) += fsl_blob.o obj-$(CONFIG_CMD_DEKBLOB) += fsl_blob.o obj-$(CONFIG_RSA_FREESCALE_EXP) += fsl_rsa.o +obj-$(CONFIG_FSL_CAAM_RNG) += rng.o diff --git a/drivers/crypto/fsl/desc.h b/drivers/crypto/fsl/desc.h index 11ad506829..3589e6ea02 100644 --- a/drivers/crypto/fsl/desc.h +++ b/drivers/crypto/fsl/desc.h @@ -520,6 +520,8 @@ #define OP_ALG_ICV_OFF (0 << OP_ALG_ICV_SHIFT) #define OP_ALG_ICV_ON (1 << OP_ALG_ICV_SHIFT) +#define OP_ALG_PR_ON 0x02 + #define OP_ALG_DIR_SHIFT 0 #define OP_ALG_DIR_MASK 1 #define OP_ALG_DECRYPT 0 diff --git a/drivers/crypto/fsl/desc_constr.h b/drivers/crypto/fsl/desc_constr.h index cb112283ac..b82ba83e73 100644 --- a/drivers/crypto/fsl/desc_constr.h +++ b/drivers/crypto/fsl/desc_constr.h @@ -36,19 +36,16 @@ (LDOFF_ENABLE_AUTO_NFIFO << LDST_OFFSET_SHIFT)) #ifdef CONFIG_PHYS_64BIT -union ptr_addr_t { - u64 m_whole; - struct { +struct ptr_addr_t { #ifdef CONFIG_SYS_FSL_SEC_LE - u32 low; - u32 high; + u32 low; + u32 high; #elif defined(CONFIG_SYS_FSL_SEC_BE) - u32 high; - u32 low; + u32 high; + u32 low; #else #error Neither CONFIG_SYS_FSL_SEC_LE nor CONFIG_SYS_FSL_SEC_BE is defined #endif - } m_halfs; }; #endif @@ -57,9 +54,10 @@ static inline void pdb_add_ptr(dma_addr_t *offset, dma_addr_t ptr) #ifdef CONFIG_PHYS_64BIT /* The Position of low and high part of 64 bit address * will depend on the endianness of CAAM Block */ - union ptr_addr_t *ptr_addr = (union ptr_addr_t *)offset; - ptr_addr->m_halfs.high = (u32)(ptr >> 32); - ptr_addr->m_halfs.low = (u32)ptr; + struct ptr_addr_t *ptr_addr = (struct ptr_addr_t *)offset; + + ptr_addr->high = (u32)(ptr >> 32); + ptr_addr->low = (u32)ptr; #else *offset = ptr; #endif @@ -111,9 +109,10 @@ static inline void append_ptr(u32 *desc, dma_addr_t ptr) #ifdef CONFIG_PHYS_64BIT /* The Position of low and high part of 64 bit address * will depend on the endianness of CAAM Block */ - union ptr_addr_t *ptr_addr = (union ptr_addr_t *)offset; - ptr_addr->m_halfs.high = (u32)(ptr >> 32); - ptr_addr->m_halfs.low = (u32)ptr; + struct ptr_addr_t *ptr_addr = (struct ptr_addr_t *)offset; + + ptr_addr->high = (u32)(ptr >> 32); + ptr_addr->low = (u32)ptr; #else *offset = ptr; #endif diff --git a/drivers/crypto/fsl/fsl_hash.c b/drivers/crypto/fsl/fsl_hash.c index 953deec9ff..61f953e8a6 100644 --- a/drivers/crypto/fsl/fsl_hash.c +++ b/drivers/crypto/fsl/fsl_hash.c @@ -86,7 +86,7 @@ static int caam_hash_update(void *hash_ctx, const void *buf, unsigned int size, int is_last, enum caam_hash_algos caam_algo) { - uint32_t final = 0; + uint32_t final; phys_addr_t addr = virt_to_phys((void *)buf); struct sha_ctx *ctx = hash_ctx; diff --git a/drivers/crypto/fsl/jobdesc.c b/drivers/crypto/fsl/jobdesc.c index 2f35e0c90b..fbc1aeddee 100644 --- a/drivers/crypto/fsl/jobdesc.c +++ b/drivers/crypto/fsl/jobdesc.c @@ -102,8 +102,8 @@ int caam_page_alloc(uint8_t page_num, uint8_t partition_num) /* if the page is not owned => problem */ if ((temp_reg & SMCSJR_PO) != PAGE_OWNED) { - printf("Allocation of page %d in partition %d failed 0x%X\n", - temp_reg, page_num, partition_num); + printf("Allocation of page %u in partition %u failed 0x%X\n", + page_num, partition_num, temp_reg); return ERROR_IN_PAGE_ALLOC; } @@ -258,7 +258,7 @@ void inline_cnstr_jobdesc_blob_decap(uint32_t *desc, uint8_t *key_idnfr, * Descriptor to instantiate RNG State Handle 0 in normal mode and * load the JDKEK, TDKEK and TDSK registers */ -void inline_cnstr_jobdesc_rng_instantiation(uint32_t *desc, int handle) +void inline_cnstr_jobdesc_rng_instantiation(u32 *desc, int handle, int do_sk) { u32 *jump_cmd; @@ -266,10 +266,11 @@ void inline_cnstr_jobdesc_rng_instantiation(uint32_t *desc, int handle) /* INIT RNG in non-test mode */ append_operation(desc, OP_TYPE_CLASS1_ALG | OP_ALG_ALGSEL_RNG | - (handle << OP_ALG_AAI_SHIFT) | OP_ALG_AS_INIT); + (handle << OP_ALG_AAI_SHIFT) | OP_ALG_AS_INIT | + OP_ALG_PR_ON); /* For SH0, Secure Keys must be generated as well */ - if (handle == 0) { + if (!handle && do_sk) { /* wait for done */ jump_cmd = append_jump(desc, JUMP_CLASS_CLASS1); set_jump_tgt_here(desc, jump_cmd); @@ -286,6 +287,25 @@ void inline_cnstr_jobdesc_rng_instantiation(uint32_t *desc, int handle) } } +/* Descriptor for deinstantiation of the RNG block. */ +void inline_cnstr_jobdesc_rng_deinstantiation(u32 *desc, int handle) +{ + init_job_desc(desc, 0); + + append_operation(desc, OP_TYPE_CLASS1_ALG | OP_ALG_ALGSEL_RNG | + (handle << OP_ALG_AAI_SHIFT) | OP_ALG_AS_INITFINAL); +} + +void inline_cnstr_jobdesc_rng(u32 *desc, void *data_out, u32 size) +{ + dma_addr_t dma_data_out = virt_to_phys(data_out); + + init_job_desc(desc, 0); + append_operation(desc, OP_ALG_ALGSEL_RNG | OP_TYPE_CLASS1_ALG | + OP_ALG_PR_ON); + append_fifo_store(desc, dma_data_out, size, FIFOST_TYPE_RNGSTORE); +} + /* Change key size to bytes form bits in calling function*/ void inline_cnstr_jobdesc_pkha_rsaexp(uint32_t *desc, struct pk_in_params *pkin, uint8_t *out, diff --git a/drivers/crypto/fsl/jobdesc.h b/drivers/crypto/fsl/jobdesc.h index d782c46b9d..c4501abd26 100644 --- a/drivers/crypto/fsl/jobdesc.h +++ b/drivers/crypto/fsl/jobdesc.h @@ -39,9 +39,14 @@ void inline_cnstr_jobdesc_blob_decap(uint32_t *desc, uint8_t *key_idnfr, uint8_t *enc_blob, uint8_t *plain_txt, uint32_t out_sz); -void inline_cnstr_jobdesc_rng_instantiation(uint32_t *desc, int handle); +void inline_cnstr_jobdesc_rng_instantiation(u32 *desc, int handle, int do_sk); + +void inline_cnstr_jobdesc_rng_deinstantiation(u32 *desc, int handle); + +void inline_cnstr_jobdesc_rng(u32 *desc, void *data_out, u32 size); void inline_cnstr_jobdesc_pkha_rsaexp(uint32_t *desc, struct pk_in_params *pkin, uint8_t *out, uint32_t out_siz); + #endif diff --git a/drivers/crypto/fsl/jr.c b/drivers/crypto/fsl/jr.c index e2d9216cfc..44273c345f 100644 --- a/drivers/crypto/fsl/jr.c +++ b/drivers/crypto/fsl/jr.c @@ -7,6 +7,7 @@ #include <common.h> #include <cpu_func.h> +#include <linux/kernel.h> #include <log.h> #include <malloc.h> #include "fsl_sec.h" @@ -19,6 +20,7 @@ #include <asm/cache.h> #include <asm/fsl_pamu.h> #endif +#include <dm/lists.h> #define CIRC_CNT(head, tail, size) (((head) - (tail)) & (size - 1)) #define CIRC_SPACE(head, tail, size) CIRC_CNT((tail), (head) + 1, (size)) @@ -446,7 +448,52 @@ int sec_reset(void) return sec_reset_idx(0); } #ifndef CONFIG_SPL_BUILD -static int instantiate_rng(uint8_t sec_idx) +static int deinstantiate_rng(u8 sec_idx, int state_handle_mask) +{ + u32 *desc; + int sh_idx, ret = 0; + int desc_size = ALIGN(sizeof(u32) * 2, ARCH_DMA_MINALIGN); + + desc = memalign(ARCH_DMA_MINALIGN, desc_size); + if (!desc) { + debug("cannot allocate RNG init descriptor memory\n"); + return -ENOMEM; + } + + for (sh_idx = 0; sh_idx < RNG4_MAX_HANDLES; sh_idx++) { + /* + * If the corresponding bit is set, then it means the state + * handle was initialized by us, and thus it needs to be + * deinitialized as well + */ + + if (state_handle_mask & RDSTA_IF(sh_idx)) { + /* + * Create the descriptor for deinstantating this state + * handle. + */ + inline_cnstr_jobdesc_rng_deinstantiation(desc, sh_idx); + flush_dcache_range((unsigned long)desc, + (unsigned long)desc + desc_size); + + ret = run_descriptor_jr_idx(desc, sec_idx); + if (ret) { + printf("SEC%u: RNG4 SH%d deinstantiation failed with error 0x%x\n", + sec_idx, sh_idx, ret); + ret = -EIO; + break; + } + + printf("SEC%u: Deinstantiated RNG4 SH%d\n", + sec_idx, sh_idx); + } + } + + free(desc); + return ret; +} + +static int instantiate_rng(u8 sec_idx, int gen_sk) { u32 *desc; u32 rdsta_val; @@ -466,11 +513,20 @@ static int instantiate_rng(uint8_t sec_idx) * If the corresponding bit is set, this state handle * was initialized by somebody else, so it's left alone. */ - rdsta_val = sec_in32(&rng->rdsta) & RNG_STATE_HANDLE_MASK; - if (rdsta_val & (1 << sh_idx)) - continue; + rdsta_val = sec_in32(&rng->rdsta); + if (rdsta_val & (RDSTA_IF(sh_idx))) { + if (rdsta_val & RDSTA_PR(sh_idx)) + continue; + + printf("SEC%u: RNG4 SH%d was instantiated w/o prediction resistance. Tearing it down\n", + sec_idx, sh_idx); - inline_cnstr_jobdesc_rng_instantiation(desc, sh_idx); + ret = deinstantiate_rng(sec_idx, RDSTA_IF(sh_idx)); + if (ret) + break; + } + + inline_cnstr_jobdesc_rng_instantiation(desc, sh_idx, gen_sk); size = roundup(sizeof(uint32_t) * 6, ARCH_DMA_MINALIGN); flush_dcache_range((unsigned long)desc, (unsigned long)desc + size); @@ -478,11 +534,11 @@ static int instantiate_rng(uint8_t sec_idx) ret = run_descriptor_jr_idx(desc, sec_idx); if (ret) - printf("RNG: Instantiation failed with error 0x%x\n", - ret); + printf("SEC%u: RNG4 SH%d instantiation failed with error 0x%x\n", + sec_idx, sh_idx, ret); - rdsta_val = sec_in32(&rng->rdsta) & RNG_STATE_HANDLE_MASK; - if (!(rdsta_val & (1 << sh_idx))) { + rdsta_val = sec_in32(&rng->rdsta); + if (!(rdsta_val & RDSTA_IF(sh_idx))) { free(desc); return -1; } @@ -498,9 +554,17 @@ static int instantiate_rng(uint8_t sec_idx) static u8 get_rng_vid(uint8_t sec_idx) { ccsr_sec_t *sec = (void *)SEC_ADDR(sec_idx); - u32 cha_vid = sec_in32(&sec->chavid_ls); + u8 vid; + + if (caam_get_era() < 10) { + vid = (sec_in32(&sec->chavid_ls) & SEC_CHAVID_RNG_LS_MASK) + >> SEC_CHAVID_LS_RNG_SHIFT; + } else { + vid = (sec_in32(&sec->vreg.rng) & CHA_VER_VID_MASK) + >> CHA_VER_VID_SHIFT; + } - return (cha_vid & SEC_CHAVID_RNG_LS_MASK) >> SEC_CHAVID_LS_RNG_SHIFT; + return vid; } /* @@ -538,14 +602,15 @@ static void kick_trng(int ent_delay, uint8_t sec_idx) static int rng_init(uint8_t sec_idx) { - int ret, ent_delay = RTSDCTL_ENT_DLY_MIN; + int ret, gen_sk, ent_delay = RTSDCTL_ENT_DLY_MIN; ccsr_sec_t __iomem *sec = (ccsr_sec_t __iomem *)SEC_ADDR(sec_idx); struct rng4tst __iomem *rng = (struct rng4tst __iomem *)&sec->rng; u32 inst_handles; + gen_sk = !(sec_in32(&rng->rdsta) & RDSTA_SKVN); do { - inst_handles = sec_in32(&rng->rdsta) & RNG_STATE_HANDLE_MASK; + inst_handles = sec_in32(&rng->rdsta) & RDSTA_MASK; /* * If either of the SH's were instantiated by somebody else @@ -566,10 +631,10 @@ static int rng_init(uint8_t sec_idx) * interval, leading to a sucessful initialization of * the RNG. */ - ret = instantiate_rng(sec_idx); + ret = instantiate_rng(sec_idx, gen_sk); } while ((ret == -1) && (ent_delay < RTSDCTL_ENT_DLY_MAX)); if (ret) { - printf("RNG: Failed to instantiate RNG\n"); + printf("SEC%u: Failed to instantiate RNG\n", sec_idx); return ret; } @@ -592,7 +657,7 @@ int sec_init_idx(uint8_t sec_idx) #endif if (!(sec_idx < CONFIG_SYS_FSL_MAX_NUM_OF_SEC)) { - printf("SEC initialization failed\n"); + printf("SEC%u: initialization failed\n", sec_idx); return -1; } @@ -640,7 +705,7 @@ int sec_init_idx(uint8_t sec_idx) ret = jr_init(sec_idx); if (ret < 0) { - printf("SEC initialization failed\n"); + printf("SEC%u: initialization failed\n", sec_idx); return -1; } @@ -654,10 +719,18 @@ int sec_init_idx(uint8_t sec_idx) #ifndef CONFIG_SPL_BUILD if (get_rng_vid(sec_idx) >= 4) { if (rng_init(sec_idx) < 0) { - printf("SEC%u: RNG instantiation failed\n", sec_idx); + printf("SEC%u: RNG instantiation failed\n", sec_idx); return -1; } - printf("SEC%u: RNG instantiated\n", sec_idx); + + if (IS_ENABLED(CONFIG_DM_RNG)) { + ret = device_bind_driver(NULL, "caam-rng", "caam-rng", + NULL); + if (ret) + printf("Couldn't bind rng driver (%d)\n", ret); + } + + printf("SEC%u: RNG instantiated\n", sec_idx); } #endif return ret; diff --git a/drivers/crypto/fsl/rng.c b/drivers/crypto/fsl/rng.c new file mode 100644 index 0000000000..3c0c2b067f --- /dev/null +++ b/drivers/crypto/fsl/rng.c @@ -0,0 +1,88 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2020 Michael Walle <michael@walle.cc> + * + * Driver for Freescale Cryptographic Accelerator and Assurance + * Module (CAAM) hardware random number generator. + */ + +#include <asm/cache.h> +#include <common.h> +#include <cpu_func.h> +#include <dm.h> +#include <rng.h> +#include <linux/kernel.h> +#include "desc_constr.h" +#include "jobdesc.h" +#include "jr.h" + +#define CAAM_RNG_MAX_FIFO_STORE_SIZE 16 +#define CAAM_RNG_DESC_LEN (3 * CAAM_CMD_SZ + CAAM_PTR_SZ) + +struct caam_rng_priv { + u32 desc[CAAM_RNG_DESC_LEN / 4]; + u8 data[CAAM_RNG_MAX_FIFO_STORE_SIZE] __aligned(ARCH_DMA_MINALIGN); +}; + +static int caam_rng_read_one(struct caam_rng_priv *priv) +{ + int size = ALIGN(CAAM_RNG_MAX_FIFO_STORE_SIZE, ARCH_DMA_MINALIGN); + int ret; + + ret = run_descriptor_jr(priv->desc); + if (ret < 0) + return -EIO; + + invalidate_dcache_range((unsigned long)priv->data, + (unsigned long)priv->data + size); + + return 0; +} + +static int caam_rng_read(struct udevice *dev, void *data, size_t len) +{ + struct caam_rng_priv *priv = dev_get_priv(dev); + u8 *buffer = data; + size_t size; + int ret; + + while (len) { + ret = caam_rng_read_one(priv); + if (ret) + return ret; + + size = min(len, (size_t)CAAM_RNG_MAX_FIFO_STORE_SIZE); + + memcpy(buffer, priv->data, size); + buffer += size; + len -= size; + } + + return 0; +} + +static int caam_rng_probe(struct udevice *dev) +{ + struct caam_rng_priv *priv = dev_get_priv(dev); + ulong size = ALIGN(CAAM_RNG_DESC_LEN, ARCH_DMA_MINALIGN); + + inline_cnstr_jobdesc_rng(priv->desc, priv->data, + CAAM_RNG_MAX_FIFO_STORE_SIZE); + flush_dcache_range((unsigned long)priv->desc, + (unsigned long)priv->desc + size); + + return 0; +} + +static const struct dm_rng_ops caam_rng_ops = { + .read = caam_rng_read, +}; + +U_BOOT_DRIVER(caam_rng) = { + .name = "caam-rng", + .id = UCLASS_RNG, + .ops = &caam_rng_ops, + .probe = caam_rng_probe, + .priv_auto_alloc_size = sizeof(struct caam_rng_priv), + .flags = DM_FLAG_ALLOC_PRIV_DMA, +}; diff --git a/drivers/crypto/fsl/sec.c b/drivers/crypto/fsl/sec.c index a2c0bfaf44..f0a4a63d88 100644 --- a/drivers/crypto/fsl/sec.c +++ b/drivers/crypto/fsl/sec.c @@ -98,7 +98,15 @@ void fdt_fixup_crypto_node(void *blob, int sec_rev) fdt_strerror(err)); } #elif CONFIG_SYS_FSL_SEC_COMPAT >= 4 /* SEC4 */ -static u8 caam_get_era(void) +/** + * caam_get_era() - fetch the CAAM's era + * + * The SEC module povides an "Era" which can be used to differentiate + * between different revisions. + * + * Return: era of the SEC. + */ +u8 caam_get_era(void) { static const struct { u16 ip_id; diff --git a/drivers/dma/ti-edma3.c b/drivers/dma/ti-edma3.c index 77c4ba9530..13ab967089 100644 --- a/drivers/dma/ti-edma3.c +++ b/drivers/dma/ti-edma3.c @@ -546,7 +546,7 @@ static int ti_edma3_ofdata_to_platdata(struct udevice *dev) { struct ti_edma3_priv *priv = dev_get_priv(dev); - priv->base = devfdt_get_addr(dev); + priv->base = dev_read_addr(dev); return 0; } diff --git a/drivers/fpga/socfpga_arria10.c b/drivers/fpga/socfpga_arria10.c index dfd3cbb461..44e1ac54c3 100644 --- a/drivers/fpga/socfpga_arria10.c +++ b/drivers/fpga/socfpga_arria10.c @@ -13,6 +13,7 @@ #include <altera.h> #include <asm/arch/pinmux.h> #include <common.h> +#include <dm.h> #include <dm/ofnode.h> #include <errno.h> #include <fs_loader.h> diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 0e8ad9530d..11e9a17f97 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -154,6 +154,17 @@ config IMX_RGPIO2P help This driver supports i.MX7ULP Rapid GPIO2P controller. +config IPROC_GPIO + bool "Broadcom iProc GPIO driver(without pinconf)" + default n + help + The Broadcom iProc based SoCs- Cygnus, NS2, NS3, NSP and Stingray, + use the same GPIO Controller IP hence this driver could be used + for all. + + The Broadcom iProc based SoCs have multiple GPIO controllers and only + the always-ON GPIO controller (CRMU/AON) is supported by this driver. + config HSDK_CREG_GPIO bool "HSDK CREG GPIO griver" depends on DM_GPIO @@ -335,6 +346,16 @@ config PIC32_GPIO help Say yes here to support Microchip PIC32 GPIOs. +config OCTEON_GPIO + bool "Octeon II/III/TX/TX2 GPIO driver" + depends on DM_GPIO && DM_PCI && (ARCH_OCTEON || ARCH_OCTEONTX || ARCH_OCTEONTX2) + default y + help + Add support for the Marvell Octeon GPIO driver. This is used with + various Octeon parts such as Octeon II/III and OcteonTX/TX2. + Octeon II/III has 32 GPIOs (count defined via DT) and OcteonTX/TX2 + has 64 GPIOs (count defined via internal register). + config STM32_GPIO bool "ST STM32 GPIO driver" depends on DM_GPIO && (ARCH_STM32 || ARCH_STM32MP) @@ -457,4 +478,13 @@ config MT7621_GPIO help Say yes here to support MediaTek MT7621 compatible GPIOs. +config NX_GPIO + bool "Nexell GPIO driver" + depends on DM_GPIO + help + Support GPIO access on Nexell SoCs. The GPIOs are arranged into + a number of banks (different for each SoC type) each with 32 GPIOs. + The GPIOs for a device are defined in the device tree with one node + for each bank. + endmenu diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 7638259007..d3d0d3cacf 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -19,6 +19,7 @@ obj-$(CONFIG_CORTINA_GPIO) += cortina_gpio.o obj-$(CONFIG_INTEL_GPIO) += intel_gpio.o obj-$(CONFIG_INTEL_ICH6_GPIO) += intel_ich6_gpio.o obj-$(CONFIG_INTEL_BROADWELL_GPIO) += intel_broadwell_gpio.o +obj-$(CONFIG_IPROC_GPIO) += iproc_gpio.o obj-$(CONFIG_KIRKWOOD_GPIO) += kw_gpio.o obj-$(CONFIG_KONA_GPIO) += kona_gpio.o obj-$(CONFIG_MARVELL_GPIO) += mvgpio.o @@ -58,10 +59,12 @@ obj-$(CONFIG_HIKEY_GPIO) += hi6220_gpio.o obj-$(CONFIG_HSDK_CREG_GPIO) += hsdk-creg-gpio.o obj-$(CONFIG_IMX_RGPIO2P) += imx_rgpio2p.o obj-$(CONFIG_PIC32_GPIO) += pic32_gpio.o +obj-$(CONFIG_OCTEON_GPIO) += octeon_gpio.o obj-$(CONFIG_MVEBU_GPIO) += mvebu_gpio.o obj-$(CONFIG_MSM_GPIO) += msm_gpio.o obj-$(CONFIG_$(SPL_)PCF8575_GPIO) += pcf8575_gpio.o obj-$(CONFIG_PM8916_GPIO) += pm8916_gpio.o obj-$(CONFIG_MT7621_GPIO) += mt7621_gpio.o obj-$(CONFIG_MSCC_SGPIO) += mscc_sgpio.o +obj-$(CONFIG_NX_GPIO) += nx_gpio.o obj-$(CONFIG_SIFIVE_GPIO) += sifive-gpio.o diff --git a/drivers/gpio/altera_pio.c b/drivers/gpio/altera_pio.c index 324f9c29a8..75800d9f31 100644 --- a/drivers/gpio/altera_pio.c +++ b/drivers/gpio/altera_pio.c @@ -88,7 +88,7 @@ static int altera_pio_ofdata_to_platdata(struct udevice *dev) { struct altera_pio_platdata *plat = dev_get_platdata(dev); - plat->regs = map_physmem(devfdt_get_addr(dev), + plat->regs = map_physmem(dev_read_addr(dev), sizeof(struct altera_pio_regs), MAP_NOCACHE); plat->gpio_count = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev), diff --git a/drivers/gpio/atmel_pio4.c b/drivers/gpio/atmel_pio4.c index 455944d547..18f365fa41 100644 --- a/drivers/gpio/atmel_pio4.c +++ b/drivers/gpio/atmel_pio4.c @@ -299,7 +299,7 @@ static int atmel_pio4_probe(struct udevice *dev) clk_free(&clk); - addr_base = devfdt_get_addr(dev); + addr_base = dev_read_addr(dev); if (addr_base == FDT_ADDR_T_NONE) return -EINVAL; diff --git a/drivers/gpio/bcm2835_gpio.c b/drivers/gpio/bcm2835_gpio.c index f4b67f1cf0..0dff9ac711 100644 --- a/drivers/gpio/bcm2835_gpio.c +++ b/drivers/gpio/bcm2835_gpio.c @@ -121,7 +121,7 @@ static int bcm2835_gpio_ofdata_to_platdata(struct udevice *dev) struct bcm2835_gpio_platdata *plat = dev_get_platdata(dev); fdt_addr_t addr; - addr = devfdt_get_addr(dev); + addr = dev_read_addr(dev); if (addr == FDT_ADDR_T_NONE) return -EINVAL; diff --git a/drivers/gpio/da8xx_gpio.c b/drivers/gpio/da8xx_gpio.c index ab0a5cfd33..f875888510 100644 --- a/drivers/gpio/da8xx_gpio.c +++ b/drivers/gpio/da8xx_gpio.c @@ -545,7 +545,7 @@ static int davinci_gpio_ofdata_to_platdata(struct udevice *dev) struct davinci_gpio_platdata *plat = dev_get_platdata(dev); fdt_addr_t addr; - addr = devfdt_get_addr(dev); + addr = dev_read_addr(dev); if (addr == FDT_ADDR_T_NONE) return -EINVAL; diff --git a/drivers/gpio/gpio-rcar.c b/drivers/gpio/gpio-rcar.c index c49a041059..a993fd4d70 100644 --- a/drivers/gpio/gpio-rcar.c +++ b/drivers/gpio/gpio-rcar.c @@ -148,7 +148,7 @@ static int rcar_gpio_probe(struct udevice *dev) int node = dev_of_offset(dev); int ret; - priv->regs = (void __iomem *)devfdt_get_addr(dev); + priv->regs = dev_read_addr_ptr(dev); uc_priv->bank_name = dev->name; ret = fdtdec_parse_phandle_with_args(gd->fdt_blob, node, "gpio-ranges", diff --git a/drivers/gpio/gpio-rza1.c b/drivers/gpio/gpio-rza1.c index 21a87d645c..86804ac2f5 100644 --- a/drivers/gpio/gpio-rza1.c +++ b/drivers/gpio/gpio-rza1.c @@ -112,7 +112,7 @@ static int r7s72100_gpio_probe(struct udevice *dev) uc_priv->bank_name = dev->name; dev = dev_get_parent(dev); - addr_base = devfdt_get_addr(dev); + addr_base = dev_read_addr(dev); if (addr_base == FDT_ADDR_T_NONE) return -EINVAL; diff --git a/drivers/gpio/gpio-uniphier.c b/drivers/gpio/gpio-uniphier.c index 30392bccaa..54a38da0f1 100644 --- a/drivers/gpio/gpio-uniphier.c +++ b/drivers/gpio/gpio-uniphier.c @@ -142,7 +142,7 @@ static int uniphier_gpio_probe(struct udevice *dev) struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev); fdt_addr_t addr; - addr = devfdt_get_addr(dev); + addr = dev_read_addr(dev); if (addr == FDT_ADDR_T_NONE) return -EINVAL; diff --git a/drivers/gpio/iproc_gpio.c b/drivers/gpio/iproc_gpio.c new file mode 100644 index 0000000000..cc26a1306b --- /dev/null +++ b/drivers/gpio/iproc_gpio.c @@ -0,0 +1,290 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2020 Broadcom + */ + +#include <common.h> +#include <errno.h> +#include <asm/gpio.h> +#include <asm/io.h> +#include <dm.h> +#include <dm/device_compat.h> +#include <dm/devres.h> +#include <dm/pinctrl.h> + +/* + * There are five GPIO bank register. Each bank can configure max of 32 gpios. + * BANK0 - gpios 0 to 31 + * BANK1 - gpios 32 to 63 + * BANK2 - gpios 64 to 95 + * BANK3 - gpios 96 to 127 + * BANK4 - gpios 128 to 150 + * + * Offset difference between consecutive bank register is 0x200 + */ +#define NGPIO_PER_BANK 32 +#define GPIO_BANK_SIZE 0x200 +#define GPIO_BANK(pin) ((pin) / NGPIO_PER_BANK) +#define GPIO_SHIFT(pin) ((pin) % NGPIO_PER_BANK) +#define GPIO_REG(pin, reg) (GPIO_BANK_SIZE * GPIO_BANK(pin) + (reg)) + +/* device register offset */ +#define DATA_IN_OFFSET 0x00 +#define DATA_OUT_OFFSET 0x04 +#define OUT_EN_OFFSET 0x08 + +/** + * struct iproc_gpio_pctrl_map - gpio and pinctrl mapping + * @gpio_pin: start of gpio number in gpio-ranges + * @pctrl_pin: start of pinctrl number in gpio-ranges + * @npins: total number of pins in gpio-ranges + * @node: list node + */ +struct iproc_gpio_pctrl_map { + u32 gpio_pin; + u32 pctrl_pin; + u32 npins; + struct list_head node; +}; + +/** + * struct iproc_gpio_pctrl_map - gpio device instance + * @pinctrl_dev:pointer to pinctrl device + * @gpiomap: list node having mapping between gpio and pinctrl + * @base: I/O register base address of gpio device + * @name: gpio device name, ex GPIO0, GPIO1 + * @ngpios: total number of gpios + */ +struct iproc_gpio_platdata { + struct udevice *pinctrl_dev; + struct list_head gpiomap; + void __iomem *base; + char *name; + u32 ngpios; +}; + +/** + * iproc_gpio_set_bit - set or clear one bit in an iproc GPIO register. + * + * The bit relates to a GPIO pin. + * + * @plat: iproc GPIO device + * @reg: register offset + * @gpio: GPIO pin + * @set: set or clear + */ +static inline void iproc_gpio_set_bit(struct iproc_gpio_platdata *plat, + u32 reg, u32 gpio, bool set) +{ + u32 offset = GPIO_REG(gpio, reg); + u32 shift = GPIO_SHIFT(gpio); + + clrsetbits_le32(plat->base + offset, BIT(shift), + (set ? BIT(shift) : 0)); +} + +static inline bool iproc_gpio_get_bit(struct iproc_gpio_platdata *plat, + u32 reg, u32 gpio) +{ + u32 offset = GPIO_REG(gpio, reg); + u32 shift = GPIO_SHIFT(gpio); + + return readl(plat->base + offset) & BIT(shift); +} + +/** + * iproc_get_gpio_pctrl_mapping() - get associated pinctrl pin from gpio pin + * + * @plat: iproc GPIO device + * @gpio: GPIO pin + */ +static u32 iproc_get_pctrl_from_gpio(struct iproc_gpio_platdata *plat, u32 gpio) +{ + struct iproc_gpio_pctrl_map *range = NULL; + struct list_head *pos, *tmp; + u32 ret = 0; + + list_for_each_safe(pos, tmp, &plat->gpiomap) { + range = list_entry(pos, struct iproc_gpio_pctrl_map, node); + if (gpio == range->gpio_pin || + gpio < (range->gpio_pin + range->npins)) { + ret = range->pctrl_pin + (gpio - range->gpio_pin); + break; + } + } + + return ret; +} + +/** + * iproc_get_gpio_pctrl_mapping() - get mapping between gpio and pinctrl + * + * Read dt node "gpio-ranges" to get gpio and pinctrl mapping and store + * in private data structure to use it later while enabling gpio. + * + * @dev: pointer to GPIO device + * @return 0 on success and -ENOMEM on failure + */ +static int iproc_get_gpio_pctrl_mapping(struct udevice *dev) +{ + struct iproc_gpio_platdata *plat = dev_get_platdata(dev); + struct iproc_gpio_pctrl_map *range = NULL; + struct ofnode_phandle_args args; + int index = 0, ret; + + for (;; index++) { + ret = dev_read_phandle_with_args(dev, "gpio-ranges", + NULL, 3, index, &args); + if (ret) + break; + + range = devm_kzalloc(dev, sizeof(*range), GFP_KERNEL); + if (!range) + return -ENOMEM; + + range->gpio_pin = args.args[0]; + range->pctrl_pin = args.args[1]; + range->npins = args.args[2]; + list_add_tail(&range->node, &plat->gpiomap); + } + + return 0; +} + +static int iproc_gpio_request(struct udevice *dev, u32 gpio, const char *label) +{ + struct iproc_gpio_platdata *plat = dev_get_platdata(dev); + u32 pctrl; + + /* nothing to do if there is no corresponding pinctrl device */ + if (!plat->pinctrl_dev) + return 0; + + pctrl = iproc_get_pctrl_from_gpio(plat, gpio); + + return pinctrl_request(plat->pinctrl_dev, pctrl, 0); +} + +static int iproc_gpio_direction_input(struct udevice *dev, u32 gpio) +{ + struct iproc_gpio_platdata *plat = dev_get_platdata(dev); + + iproc_gpio_set_bit(plat, OUT_EN_OFFSET, gpio, false); + dev_dbg(dev, "gpio:%u set input\n", gpio); + + return 0; +} + +static int iproc_gpio_direction_output(struct udevice *dev, u32 gpio, int value) +{ + struct iproc_gpio_platdata *plat = dev_get_platdata(dev); + + iproc_gpio_set_bit(plat, OUT_EN_OFFSET, gpio, true); + iproc_gpio_set_bit(plat, DATA_OUT_OFFSET, gpio, value); + dev_dbg(dev, "gpio:%u set output, value:%d\n", gpio, value); + + return 0; +} + +static int iproc_gpio_get_value(struct udevice *dev, u32 gpio) +{ + struct iproc_gpio_platdata *plat = dev_get_platdata(dev); + int value; + + value = iproc_gpio_get_bit(plat, DATA_IN_OFFSET, gpio); + dev_dbg(dev, "gpio:%u get, value:%d\n", gpio, value); + + return value; +} + +static int iproc_gpio_set_value(struct udevice *dev, u32 gpio, int value) +{ + struct iproc_gpio_platdata *plat = dev_get_platdata(dev); + + if (iproc_gpio_get_bit(plat, OUT_EN_OFFSET, gpio)) + iproc_gpio_set_bit(plat, DATA_OUT_OFFSET, gpio, value); + + dev_dbg(dev, "gpio:%u set, value:%d\n", gpio, value); + return 0; +} + +static int iproc_gpio_get_function(struct udevice *dev, u32 gpio) +{ + struct iproc_gpio_platdata *plat = dev_get_platdata(dev); + + if (iproc_gpio_get_bit(plat, OUT_EN_OFFSET, gpio)) + return GPIOF_OUTPUT; + else + return GPIOF_INPUT; +} + +static int iproc_gpio_ofdata_to_platdata(struct udevice *dev) +{ + struct iproc_gpio_platdata *plat = dev_get_platdata(dev); + struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev); + int ret; + char name[10]; + + plat->base = dev_read_addr_ptr(dev); + if (!plat->base) { + debug("%s: Failed to get base address\n", __func__); + return -EINVAL; + } + + ret = dev_read_u32(dev, "ngpios", &plat->ngpios); + if (ret < 0) { + dev_err(dev, "%s: Failed to get ngpios\n", __func__); + return ret; + } + + uclass_get_device_by_phandle(UCLASS_PINCTRL, dev, "gpio-ranges", + &plat->pinctrl_dev); + if (ret < 0) { + dev_err(dev, "%s: Failed to get pinctrl phandle\n", __func__); + return ret; + } + + INIT_LIST_HEAD(&plat->gpiomap); + ret = iproc_get_gpio_pctrl_mapping(dev); + if (ret < 0) { + dev_err(dev, "%s: Failed to get gpio to pctrl map ret(%d)\n", + __func__, ret); + return ret; + } + + snprintf(name, sizeof(name), "GPIO%d", dev->req_seq); + plat->name = strdup(name); + if (!plat->name) + return -ENOMEM; + + uc_priv->gpio_count = plat->ngpios; + uc_priv->bank_name = plat->name; + + dev_info(dev, ":bank name(%s) base %p, #gpios %d\n", + plat->name, plat->base, plat->ngpios); + + return 0; +} + +static const struct dm_gpio_ops iproc_gpio_ops = { + .request = iproc_gpio_request, + .direction_input = iproc_gpio_direction_input, + .direction_output = iproc_gpio_direction_output, + .get_value = iproc_gpio_get_value, + .set_value = iproc_gpio_set_value, + .get_function = iproc_gpio_get_function, +}; + +static const struct udevice_id iproc_gpio_ids[] = { + { .compatible = "brcm,iproc-gpio" }, + { } +}; + +U_BOOT_DRIVER(iproc_gpio) = { + .name = "iproc_gpio", + .id = UCLASS_GPIO, + .of_match = iproc_gpio_ids, + .ops = &iproc_gpio_ops, + .ofdata_to_platdata = iproc_gpio_ofdata_to_platdata, + .platdata_auto_alloc_size = sizeof(struct iproc_gpio_platdata), +}; diff --git a/drivers/gpio/msm_gpio.c b/drivers/gpio/msm_gpio.c index ac5d20c1b9..416fb56a98 100644 --- a/drivers/gpio/msm_gpio.c +++ b/drivers/gpio/msm_gpio.c @@ -96,7 +96,7 @@ static int msm_gpio_probe(struct udevice *dev) { struct msm_gpio_bank *priv = dev_get_priv(dev); - priv->base = devfdt_get_addr(dev); + priv->base = dev_read_addr(dev); return priv->base == FDT_ADDR_T_NONE ? -EINVAL : 0; } @@ -118,6 +118,7 @@ static int msm_gpio_ofdata_to_platdata(struct udevice *dev) static const struct udevice_id msm_gpio_ids[] = { { .compatible = "qcom,msm8916-pinctrl" }, { .compatible = "qcom,apq8016-pinctrl" }, + { .compatible = "qcom,ipq4019-pinctrl" }, { } }; diff --git a/drivers/gpio/mvebu_gpio.c b/drivers/gpio/mvebu_gpio.c index 770cbf6b60..65eaa71c20 100644 --- a/drivers/gpio/mvebu_gpio.c +++ b/drivers/gpio/mvebu_gpio.c @@ -90,7 +90,7 @@ static int mvebu_gpio_probe(struct udevice *dev) struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev); struct mvebu_gpio_priv *priv = dev_get_priv(dev); - priv->regs = (struct mvebu_gpio_regs *)devfdt_get_addr(dev); + priv->regs = dev_read_addr_ptr(dev); uc_priv->gpio_count = MVEBU_GPIOS_PER_BANK; priv->name[0] = 'A' + dev->req_seq; uc_priv->bank_name = priv->name; diff --git a/drivers/gpio/mxc_gpio.c b/drivers/gpio/mxc_gpio.c index fc7d296a2c..88b920a074 100644 --- a/drivers/gpio/mxc_gpio.c +++ b/drivers/gpio/mxc_gpio.c @@ -312,7 +312,7 @@ static int mxc_gpio_ofdata_to_platdata(struct udevice *dev) struct mxc_gpio_plat *plat = dev_get_platdata(dev); if (!CONFIG_IS_ENABLED(OF_PLATDATA)) { fdt_addr_t addr; - addr = devfdt_get_addr(dev); + addr = dev_read_addr(dev); if (addr == FDT_ADDR_T_NONE) return -EINVAL; diff --git a/drivers/gpio/mxs_gpio.c b/drivers/gpio/mxs_gpio.c index cb797261b7..aaabb0216b 100644 --- a/drivers/gpio/mxs_gpio.c +++ b/drivers/gpio/mxs_gpio.c @@ -138,12 +138,6 @@ int name_to_gpio(const char *name) #include <asm/arch/gpio.h> #define MXS_MAX_GPIO_PER_BANK 32 -#ifdef CONFIG_MX28 -#define dtd_fsl_imx_gpio dtd_fsl_imx28_gpio -#else /* CONFIG_MX23 */ -#define dtd_fsl_imx_gpio dtd_fsl_imx23_gpio -#endif - DECLARE_GLOBAL_DATA_PTR; /* * According to i.MX28 Reference Manual: @@ -158,7 +152,7 @@ DECLARE_GLOBAL_DATA_PTR; struct mxs_gpio_platdata { #if CONFIG_IS_ENABLED(OF_PLATDATA) - struct dtd_fsl_imx_gpio dtplat; + struct dtd_fsl_imx23_gpio dtplat; #endif unsigned int bank; int gpio_ranges; @@ -247,7 +241,7 @@ static int mxs_gpio_probe(struct udevice *dev) char name[16], *str; #if CONFIG_IS_ENABLED(OF_PLATDATA) - struct dtd_fsl_imx_gpio *dtplat = &plat->dtplat; + struct dtd_fsl_imx23_gpio *dtplat = &plat->dtplat; priv->bank = (unsigned int)dtplat->reg[0]; uc_priv->gpio_count = dtplat->gpio_ranges[3]; #else @@ -275,7 +269,7 @@ static int mxs_ofdata_to_platdata(struct udevice *dev) int node = dev_of_offset(dev); int ret; - plat->bank = devfdt_get_addr(dev); + plat->bank = dev_read_addr(dev); if (plat->bank == FDT_ADDR_T_NONE) { printf("%s: No 'reg' property defined!\n", __func__); return -EINVAL; diff --git a/drivers/gpio/nx_gpio.c b/drivers/gpio/nx_gpio.c new file mode 100644 index 0000000000..5ec73c4359 --- /dev/null +++ b/drivers/gpio/nx_gpio.c @@ -0,0 +1,250 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (C) Copyright 2016 Nexell + * DeokJin, Lee <truevirtue@nexell.co.kr> + */ + +#include <common.h> +#include <dm.h> +#include <errno.h> +#include <malloc.h> +#include <asm/io.h> +#include <asm/gpio.h> + +DECLARE_GLOBAL_DATA_PTR; + +struct nx_gpio_regs { + u32 data; /* Data register */ + u32 outputenb; /* Output Enable register */ + u32 detmode[2]; /* Detect Mode Register */ + u32 intenb; /* Interrupt Enable Register */ + u32 det; /* Event Detect Register */ + u32 pad; /* Pad Status Register */ +}; + +struct nx_alive_gpio_regs { + u32 pwrgate; /* Power Gating Register */ + u32 reserved0[28]; /* Reserved0 */ + u32 outputenb_reset;/* Alive GPIO Output Enable Reset Register */ + u32 outputenb; /* Alive GPIO Output Enable Register */ + u32 outputenb_read; /* Alive GPIO Output Read Register */ + u32 reserved1[3]; /* Reserved1 */ + u32 pad_reset; /* Alive GPIO Output Reset Register */ + u32 data; /* Alive GPIO Output Register */ + u32 pad_read; /* Alive GPIO Pad Read Register */ + u32 reserved2[33]; /* Reserved2 */ + u32 pad; /* Alive GPIO Input Value Register */ +}; + +struct nx_gpio_platdata { + void *regs; + int gpio_count; + const char *bank_name; +}; + +static int nx_alive_gpio_is_check(struct udevice *dev) +{ + struct nx_gpio_platdata *plat = dev_get_platdata(dev); + const char *bank_name = plat->bank_name; + + if (!strcmp(bank_name, "gpio_alv")) + return 1; + + return 0; +} + +static int nx_alive_gpio_direction_input(struct udevice *dev, unsigned int pin) +{ + struct nx_gpio_platdata *plat = dev_get_platdata(dev); + struct nx_alive_gpio_regs *const regs = plat->regs; + + setbits_le32(®s->outputenb_reset, 1 << pin); + + return 0; +} + +static int nx_alive_gpio_direction_output(struct udevice *dev, unsigned int pin, + int val) +{ + struct nx_gpio_platdata *plat = dev_get_platdata(dev); + struct nx_alive_gpio_regs *const regs = plat->regs; + + if (val) + setbits_le32(®s->data, 1 << pin); + else + setbits_le32(®s->pad_reset, 1 << pin); + + setbits_le32(®s->outputenb, 1 << pin); + + return 0; +} + +static int nx_alive_gpio_get_value(struct udevice *dev, unsigned int pin) +{ + struct nx_gpio_platdata *plat = dev_get_platdata(dev); + struct nx_alive_gpio_regs *const regs = plat->regs; + unsigned int mask = 1UL << pin; + unsigned int value; + + value = (readl(®s->pad_read) & mask) >> pin; + + return value; +} + +static int nx_alive_gpio_set_value(struct udevice *dev, unsigned int pin, + int val) +{ + struct nx_gpio_platdata *plat = dev_get_platdata(dev); + struct nx_alive_gpio_regs *const regs = plat->regs; + + if (val) + setbits_le32(®s->data, 1 << pin); + else + clrbits_le32(®s->pad_reset, 1 << pin); + + return 0; +} + +static int nx_alive_gpio_get_function(struct udevice *dev, unsigned int pin) +{ + struct nx_gpio_platdata *plat = dev_get_platdata(dev); + struct nx_alive_gpio_regs *const regs = plat->regs; + unsigned int mask = (1UL << pin); + unsigned int output; + + output = readl(®s->outputenb_read) & mask; + + if (output) + return GPIOF_OUTPUT; + else + return GPIOF_INPUT; +} + +static int nx_gpio_direction_input(struct udevice *dev, unsigned int pin) +{ + struct nx_gpio_platdata *plat = dev_get_platdata(dev); + struct nx_gpio_regs *const regs = plat->regs; + + if (nx_alive_gpio_is_check(dev)) + return nx_alive_gpio_direction_input(dev, pin); + + clrbits_le32(®s->outputenb, 1 << pin); + + return 0; +} + +static int nx_gpio_direction_output(struct udevice *dev, unsigned int pin, + int val) +{ + struct nx_gpio_platdata *plat = dev_get_platdata(dev); + struct nx_gpio_regs *const regs = plat->regs; + + if (nx_alive_gpio_is_check(dev)) + return nx_alive_gpio_direction_output(dev, pin, val); + + if (val) + setbits_le32(®s->data, 1 << pin); + else + clrbits_le32(®s->data, 1 << pin); + + setbits_le32(®s->outputenb, 1 << pin); + + return 0; +} + +static int nx_gpio_get_value(struct udevice *dev, unsigned int pin) +{ + struct nx_gpio_platdata *plat = dev_get_platdata(dev); + struct nx_gpio_regs *const regs = plat->regs; + unsigned int mask = 1UL << pin; + unsigned int value; + + if (nx_alive_gpio_is_check(dev)) + return nx_alive_gpio_get_value(dev, pin); + + value = (readl(®s->pad) & mask) >> pin; + + return value; +} + +static int nx_gpio_set_value(struct udevice *dev, unsigned int pin, int val) +{ + struct nx_gpio_platdata *plat = dev_get_platdata(dev); + struct nx_gpio_regs *const regs = plat->regs; + + if (nx_alive_gpio_is_check(dev)) + return nx_alive_gpio_set_value(dev, pin, val); + + if (val) + setbits_le32(®s->data, 1 << pin); + else + clrbits_le32(®s->data, 1 << pin); + + return 0; +} + +static int nx_gpio_get_function(struct udevice *dev, unsigned int pin) +{ + struct nx_gpio_platdata *plat = dev_get_platdata(dev); + struct nx_gpio_regs *const regs = plat->regs; + unsigned int mask = (1UL << pin); + unsigned int output; + + if (nx_alive_gpio_is_check(dev)) + return nx_alive_gpio_get_function(dev, pin); + + output = readl(®s->outputenb) & mask; + + if (output) + return GPIOF_OUTPUT; + else + return GPIOF_INPUT; +} + +static int nx_gpio_probe(struct udevice *dev) +{ + struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev); + struct nx_gpio_platdata *plat = dev_get_platdata(dev); + + uc_priv->gpio_count = plat->gpio_count; + uc_priv->bank_name = plat->bank_name; + + return 0; +} + +static int nx_gpio_ofdata_to_platdata(struct udevice *dev) +{ + struct nx_gpio_platdata *plat = dev_get_platdata(dev); + + plat->regs = map_physmem(devfdt_get_addr(dev), + sizeof(struct nx_gpio_regs), + MAP_NOCACHE); + plat->gpio_count = dev_read_s32_default(dev, "nexell,gpio-bank-width", + 32); + plat->bank_name = dev_read_string(dev, "gpio-bank-name"); + + return 0; +} + +static const struct dm_gpio_ops nx_gpio_ops = { + .direction_input = nx_gpio_direction_input, + .direction_output = nx_gpio_direction_output, + .get_value = nx_gpio_get_value, + .set_value = nx_gpio_set_value, + .get_function = nx_gpio_get_function, +}; + +static const struct udevice_id nx_gpio_ids[] = { + { .compatible = "nexell,nexell-gpio" }, + { } +}; + +U_BOOT_DRIVER(nx_gpio) = { + .name = "nx_gpio", + .id = UCLASS_GPIO, + .of_match = nx_gpio_ids, + .ops = &nx_gpio_ops, + .ofdata_to_platdata = nx_gpio_ofdata_to_platdata, + .platdata_auto_alloc_size = sizeof(struct nx_gpio_platdata), + .probe = nx_gpio_probe, +}; diff --git a/drivers/gpio/octeon_gpio.c b/drivers/gpio/octeon_gpio.c new file mode 100644 index 0000000000..45acaadcdb --- /dev/null +++ b/drivers/gpio/octeon_gpio.c @@ -0,0 +1,242 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2018 Marvell International Ltd. + * + * (C) Copyright 2011 + * eInfochips Ltd. <www.einfochips.com> + * Written-by: Ajay Bhargav <ajay.bhargav@einfochips.com> + * + * (C) Copyright 2010 + * Marvell Semiconductor <www.marvell.com> + */ + +#include <dm.h> +#include <pci.h> +#include <pci_ids.h> +#include <asm/gpio.h> +#include <asm/io.h> +#include <linux/bitfield.h> +#include <linux/compat.h> +#include <dt-bindings/gpio/gpio.h> + +/* Returns the bit value to write or read based on the offset */ +#define GPIO_BIT(x) BIT_ULL((x) & 0x3f) + +#define GPIO_RX_DAT 0x00 +#define GPIO_TX_SET 0x08 +#define GPIO_TX_CLR 0x10 +#define GPIO_CONST 0x90 /* OcteonTX only */ + +/* Offset to register-set for 2nd GPIOs (> 63), OcteonTX only */ +#define GPIO1_OFFSET 0x1400 + +/* GPIO_CONST register bits */ +#define GPIO_CONST_GPIOS_MASK GENMASK_ULL(7, 0) + +/* GPIO_BIT_CFG register bits */ +#define GPIO_BIT_CFG_TX_OE BIT_ULL(0) +#define GPIO_BIT_CFG_PIN_XOR BIT_ULL(1) +#define GPIO_BIT_CFG_INT_EN BIT_ULL(2) +#define GPIO_BIT_CFG_PIN_SEL_MASK GENMASK_ULL(26, 16) + +enum { + PROBE_PCI = 0, /* PCI based probing */ + PROBE_DT, /* DT based probing */ +}; + +struct octeon_gpio_data { + int probe; + u32 reg_offs; + u32 gpio_bit_cfg_offs; +}; + +struct octeon_gpio { + void __iomem *base; + const struct octeon_gpio_data *data; +}; + +/* Returns the offset to the output register based on the offset and value */ +static u32 gpio_tx_reg(int offset, int value) +{ + u32 ret; + + ret = value ? GPIO_TX_SET : GPIO_TX_CLR; + if (offset > 63) + ret += GPIO1_OFFSET; + + return ret; +} + +/* Returns the offset to the input data register based on the offset */ +static u32 gpio_rx_dat_reg(int offset) +{ + u32 ret; + + ret = GPIO_RX_DAT; + if (offset > 63) + ret += GPIO1_OFFSET; + + return ret; +} + +static int octeon_gpio_dir_input(struct udevice *dev, unsigned int offset) +{ + struct octeon_gpio *gpio = dev_get_priv(dev); + + debug("%s(%s, %u)\n", __func__, dev->name, offset); + clrbits_64(gpio->base + gpio->data->gpio_bit_cfg_offs + 8 * offset, + GPIO_BIT_CFG_TX_OE | GPIO_BIT_CFG_PIN_XOR | + GPIO_BIT_CFG_INT_EN | GPIO_BIT_CFG_PIN_SEL_MASK); + + return 0; +} + +static int octeon_gpio_dir_output(struct udevice *dev, unsigned int offset, + int value) +{ + struct octeon_gpio *gpio = dev_get_priv(dev); + + debug("%s(%s, %u, %d)\n", __func__, dev->name, offset, value); + writeq(GPIO_BIT(offset), gpio->base + gpio->data->reg_offs + + gpio_tx_reg(offset, value)); + + clrsetbits_64(gpio->base + gpio->data->gpio_bit_cfg_offs + 8 * offset, + GPIO_BIT_CFG_PIN_SEL_MASK | GPIO_BIT_CFG_INT_EN, + GPIO_BIT_CFG_TX_OE); + + return 0; +} + +static int octeon_gpio_get_value(struct udevice *dev, unsigned int offset) +{ + struct octeon_gpio *gpio = dev_get_priv(dev); + u64 reg = readq(gpio->base + gpio->data->reg_offs + + gpio_rx_dat_reg(offset)); + + debug("%s(%s, %u): value: %d\n", __func__, dev->name, offset, + !!(reg & GPIO_BIT(offset))); + + return !!(reg & GPIO_BIT(offset)); +} + +static int octeon_gpio_set_value(struct udevice *dev, + unsigned int offset, int value) +{ + struct octeon_gpio *gpio = dev_get_priv(dev); + + debug("%s(%s, %u, %d)\n", __func__, dev->name, offset, value); + writeq(GPIO_BIT(offset), gpio->base + gpio->data->reg_offs + + gpio_tx_reg(offset, value)); + + return 0; +} + +static int octeon_gpio_get_function(struct udevice *dev, unsigned int offset) +{ + struct octeon_gpio *gpio = dev_get_priv(dev); + u64 val = readq(gpio->base + gpio->data->gpio_bit_cfg_offs + + 8 * offset); + int pin_sel; + + debug("%s(%s, %u): GPIO_BIT_CFG: 0x%llx\n", __func__, dev->name, + offset, val); + pin_sel = FIELD_GET(GPIO_BIT_CFG_PIN_SEL_MASK, val); + if (pin_sel) + return GPIOF_FUNC; + else if (val & GPIO_BIT_CFG_TX_OE) + return GPIOF_OUTPUT; + else + return GPIOF_INPUT; +} + +static int octeon_gpio_xlate(struct udevice *dev, struct gpio_desc *desc, + struct ofnode_phandle_args *args) +{ + if (args->args_count < 1) + return -EINVAL; + + desc->offset = args->args[0]; + desc->flags = 0; + if (args->args_count > 1) { + if (args->args[1] & GPIO_ACTIVE_LOW) + desc->flags |= GPIOD_ACTIVE_LOW; + /* In the future add tri-state flag support */ + } + return 0; +} + +static const struct dm_gpio_ops octeon_gpio_ops = { + .direction_input = octeon_gpio_dir_input, + .direction_output = octeon_gpio_dir_output, + .get_value = octeon_gpio_get_value, + .set_value = octeon_gpio_set_value, + .get_function = octeon_gpio_get_function, + .xlate = octeon_gpio_xlate, +}; + +static int octeon_gpio_probe(struct udevice *dev) +{ + struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev); + struct octeon_gpio *priv = dev_get_priv(dev); + char *end; + + priv->data = (const struct octeon_gpio_data *)dev_get_driver_data(dev); + + if (priv->data->probe == PROBE_PCI) { + priv->base = dm_pci_map_bar(dev, PCI_BASE_ADDRESS_0, + PCI_REGION_MEM); + uc_priv->gpio_count = readq(priv->base + + priv->data->reg_offs + GPIO_CONST) & + GPIO_CONST_GPIOS_MASK; + } else { + priv->base = dev_remap_addr(dev); + uc_priv->gpio_count = ofnode_read_u32_default(dev->node, + "nr-gpios", 32); + } + + if (!priv->base) { + debug("%s(%s): Could not get base address\n", + __func__, dev->name); + return -ENODEV; + } + + uc_priv->bank_name = strdup(dev->name); + end = strchr(uc_priv->bank_name, '@'); + end[0] = 'A' + dev->seq; + end[1] = '\0'; + + debug("%s(%s): base address: %p, pin count: %d\n", + __func__, dev->name, priv->base, uc_priv->gpio_count); + + return 0; +} + +static const struct octeon_gpio_data gpio_octeon_data = { + .probe = PROBE_DT, + .reg_offs = 0x80, + .gpio_bit_cfg_offs = 0x100, +}; + +static const struct octeon_gpio_data gpio_octeontx_data = { + .probe = PROBE_PCI, + .reg_offs = 0x00, + .gpio_bit_cfg_offs = 0x400, +}; + +static const struct udevice_id octeon_gpio_ids[] = { + { .compatible = "cavium,thunder-8890-gpio", + .data = (ulong)&gpio_octeontx_data }, + { .compatible = "cavium,octeon-7890-gpio", + .data = (ulong)&gpio_octeon_data }, + { } +}; + +U_BOOT_DRIVER(octeon_gpio) = { + .name = "octeon_gpio", + .id = UCLASS_GPIO, + .of_match = of_match_ptr(octeon_gpio_ids), + .probe = octeon_gpio_probe, + .priv_auto_alloc_size = sizeof(struct octeon_gpio), + .ops = &octeon_gpio_ops, + .flags = DM_FLAG_PRE_RELOC, +}; diff --git a/drivers/gpio/omap_gpio.c b/drivers/gpio/omap_gpio.c index c986ef0380..6eaa0a08a2 100644 --- a/drivers/gpio/omap_gpio.c +++ b/drivers/gpio/omap_gpio.c @@ -308,7 +308,7 @@ static int omap_gpio_bind(struct udevice *dev) if (plat) return 0; - base_addr = devfdt_get_addr(dev); + base_addr = dev_read_addr(dev); if (base_addr == FDT_ADDR_T_NONE) return -EINVAL; @@ -347,7 +347,7 @@ static int omap_gpio_ofdata_to_platdata(struct udevice *dev) struct omap_gpio_platdata *plat = dev_get_platdata(dev); fdt_addr_t addr; - addr = devfdt_get_addr(dev); + addr = dev_read_addr(dev); if (addr == FDT_ADDR_T_NONE) return -EINVAL; diff --git a/drivers/gpio/pm8916_gpio.c b/drivers/gpio/pm8916_gpio.c index 51df5367ea..58f044678b 100644 --- a/drivers/gpio/pm8916_gpio.c +++ b/drivers/gpio/pm8916_gpio.c @@ -256,7 +256,7 @@ static int pm8941_pwrkey_probe(struct udevice *dev) struct pm8916_gpio_bank *priv = dev_get_priv(dev); int reg; - priv->pid = devfdt_get_addr(dev); + priv->pid = dev_read_addr(dev); if (priv->pid == FDT_ADDR_T_NONE) return log_msg_ret("bad address", -EINVAL); diff --git a/drivers/gpio/s5p_gpio.c b/drivers/gpio/s5p_gpio.c index 258f13395d..c78227f4da 100644 --- a/drivers/gpio/s5p_gpio.c +++ b/drivers/gpio/s5p_gpio.c @@ -316,7 +316,7 @@ static int gpio_exynos_bind(struct udevice *parent) if (plat) return 0; - base = (struct s5p_gpio_bank *)devfdt_get_addr(parent); + base = dev_read_addr_ptr(parent); for (node = fdt_first_subnode(blob, dev_of_offset(parent)), bank = base; node > 0; node = fdt_next_subnode(blob, node), bank++) { @@ -339,7 +339,7 @@ static int gpio_exynos_bind(struct udevice *parent) dev_set_of_offset(dev, node); - reg = devfdt_get_addr(dev); + reg = dev_read_addr(dev); if (reg != FDT_ADDR_T_NONE) bank = (struct s5p_gpio_bank *)((ulong)base + reg); diff --git a/drivers/gpio/sifive-gpio.c b/drivers/gpio/sifive-gpio.c index 24da3b3c23..bf3537b76b 100644 --- a/drivers/gpio/sifive-gpio.c +++ b/drivers/gpio/sifive-gpio.c @@ -159,7 +159,7 @@ static int sifive_gpio_ofdata_to_platdata(struct udevice *dev) struct sifive_gpio_platdata *plat = dev_get_platdata(dev); fdt_addr_t addr; - addr = devfdt_get_addr(dev); + addr = dev_read_addr(dev); if (addr == FDT_ADDR_T_NONE) return -EINVAL; diff --git a/drivers/gpio/sunxi_gpio.c b/drivers/gpio/sunxi_gpio.c index 9c3a4428e1..3efccf496f 100644 --- a/drivers/gpio/sunxi_gpio.c +++ b/drivers/gpio/sunxi_gpio.c @@ -293,7 +293,7 @@ static int gpio_sunxi_bind(struct udevice *parent) if (plat) return 0; - ctlr = (struct sunxi_gpio_reg *)devfdt_get_addr(parent); + ctlr = dev_read_addr_ptr(parent); for (bank = 0; bank < soc_data->no_banks; bank++) { struct sunxi_gpio_platdata *plat; struct udevice *dev; diff --git a/drivers/gpio/vybrid_gpio.c b/drivers/gpio/vybrid_gpio.c index d2c1d7d859..4efff5c364 100644 --- a/drivers/gpio/vybrid_gpio.c +++ b/drivers/gpio/vybrid_gpio.c @@ -109,7 +109,7 @@ static int vybrid_gpio_odata_to_platdata(struct udevice *dev) struct vybrid_gpio_platdata *plat = dev_get_platdata(dev); fdt_addr_t base_addr; - base_addr = devfdt_get_addr(dev); + base_addr = dev_read_addr(dev); if (base_addr == FDT_ADDR_T_NONE) return -EINVAL; diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig index 87d11b663c..dec6dc9dfa 100644 --- a/drivers/i2c/Kconfig +++ b/drivers/i2c/Kconfig @@ -333,6 +333,15 @@ config SYS_MXC_I2C8_SLAVE MXC I2C8 Slave endif +config SYS_I2C_NEXELL + bool "Nexell I2C driver" + depends on DM_I2C + help + Add support for the Nexell I2C driver. This is used with various + Nexell parts such as S5Pxx18 series SoCs. All chips + have several I2C ports and all are provided, controlled by the + device tree. + config SYS_I2C_OMAP24XX bool "TI OMAP2+ I2C driver" depends on ARCH_OMAP2PLUS || ARCH_K3 diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile index 174081e252..e851ec462e 100644 --- a/drivers/i2c/Makefile +++ b/drivers/i2c/Makefile @@ -28,6 +28,7 @@ obj-$(CONFIG_SYS_I2C_LPC32XX) += lpc32xx_i2c.o obj-$(CONFIG_SYS_I2C_MESON) += meson_i2c.o obj-$(CONFIG_SYS_I2C_MVTWSI) += mvtwsi.o obj-$(CONFIG_SYS_I2C_MXC) += mxc_i2c.o +obj-$(CONFIG_SYS_I2C_NEXELL) += nx_i2c.o obj-$(CONFIG_SYS_I2C_OCTEON) += octeon_i2c.o obj-$(CONFIG_SYS_I2C_OMAP24XX) += omap24xx_i2c.o obj-$(CONFIG_SYS_I2C_RCAR_I2C) += rcar_i2c.o diff --git a/drivers/i2c/at91_i2c.c b/drivers/i2c/at91_i2c.c index c817ed6bf9..9d6c6d80e2 100644 --- a/drivers/i2c/at91_i2c.c +++ b/drivers/i2c/at91_i2c.c @@ -225,7 +225,7 @@ static int at91_i2c_ofdata_to_platdata(struct udevice *dev) struct at91_i2c_bus *bus = dev_get_priv(dev); int node = dev_of_offset(dev); - bus->regs = (struct at91_i2c_regs *)devfdt_get_addr(dev); + bus->regs = dev_read_addr_ptr(dev); bus->pdata = (struct at91_i2c_pdata *)dev_get_driver_data(dev); bus->clock_frequency = fdtdec_get_int(blob, node, "clock-frequency", 100000); diff --git a/drivers/i2c/davinci_i2c.c b/drivers/i2c/davinci_i2c.c index f8e9d003e6..a54f2151fd 100644 --- a/drivers/i2c/davinci_i2c.c +++ b/drivers/i2c/davinci_i2c.c @@ -471,7 +471,7 @@ static int davinci_i2c_probe(struct udevice *dev) struct i2c_bus *i2c_bus = dev_get_priv(dev); i2c_bus->id = dev->seq; - i2c_bus->regs = (struct i2c_regs *)devfdt_get_addr(dev); + i2c_bus->regs = dev_read_addr_ptr(dev); i2c_bus->speed = 100000; _davinci_i2c_init(i2c_bus->regs, i2c_bus->speed, 0); diff --git a/drivers/i2c/exynos_hs_i2c.c b/drivers/i2c/exynos_hs_i2c.c index 4fc9d90580..5785adedb6 100644 --- a/drivers/i2c/exynos_hs_i2c.c +++ b/drivers/i2c/exynos_hs_i2c.c @@ -525,7 +525,7 @@ static int s3c_i2c_ofdata_to_platdata(struct udevice *dev) node = dev_of_offset(dev); - i2c_bus->hsregs = (struct exynos5_hsi2c *)devfdt_get_addr(dev); + i2c_bus->hsregs = dev_read_addr_ptr(dev); i2c_bus->id = pinmux_decode_periph_id(blob, node); diff --git a/drivers/i2c/i2c-uniphier-f.c b/drivers/i2c/i2c-uniphier-f.c index d8b4a683bc..a110fe9e8d 100644 --- a/drivers/i2c/i2c-uniphier-f.c +++ b/drivers/i2c/i2c-uniphier-f.c @@ -94,7 +94,7 @@ static int uniphier_fi2c_probe(struct udevice *dev) fdt_addr_t addr; struct uniphier_fi2c_priv *priv = dev_get_priv(dev); - addr = devfdt_get_addr(dev); + addr = dev_read_addr(dev); if (addr == FDT_ADDR_T_NONE) return -EINVAL; diff --git a/drivers/i2c/i2c-uniphier.c b/drivers/i2c/i2c-uniphier.c index f06523ab99..e7f44e14e9 100644 --- a/drivers/i2c/i2c-uniphier.c +++ b/drivers/i2c/i2c-uniphier.c @@ -50,7 +50,7 @@ static int uniphier_i2c_probe(struct udevice *dev) fdt_addr_t addr; struct uniphier_i2c_priv *priv = dev_get_priv(dev); - addr = devfdt_get_addr(dev); + addr = dev_read_addr(dev); if (addr == FDT_ADDR_T_NONE) return -EINVAL; diff --git a/drivers/i2c/imx_lpi2c.c b/drivers/i2c/imx_lpi2c.c index b7b2aafc7f..feeed1e9a2 100644 --- a/drivers/i2c/imx_lpi2c.c +++ b/drivers/i2c/imx_lpi2c.c @@ -447,7 +447,7 @@ static int imx_lpi2c_probe(struct udevice *bus) i2c_bus->driver_data = dev_get_driver_data(bus); - addr = devfdt_get_addr(bus); + addr = dev_read_addr(bus); if (addr == FDT_ADDR_T_NONE) return -EINVAL; diff --git a/drivers/i2c/iproc_i2c.c b/drivers/i2c/iproc_i2c.c index a846e0a1fe..b7e9ced898 100644 --- a/drivers/i2c/iproc_i2c.c +++ b/drivers/i2c/iproc_i2c.c @@ -678,7 +678,7 @@ static int iproc_i2c_ofdata_to_platdata(struct udevice *bus) int node = dev_of_offset(bus); const void *blob = gd->fdt_blob; - bus_prvdata->base = map_physmem(devfdt_get_addr(bus), + bus_prvdata->base = map_physmem(dev_read_addr(bus), sizeof(void *), MAP_NOCACHE); diff --git a/drivers/i2c/mxc_i2c.c b/drivers/i2c/mxc_i2c.c index 3b0d27e6cd..e3d980a9df 100644 --- a/drivers/i2c/mxc_i2c.c +++ b/drivers/i2c/mxc_i2c.c @@ -4,6 +4,7 @@ * * (c) 2007 Pengutronix, Sascha Hauer <s.hauer@pengutronix.de> * (c) 2011 Marek Vasut <marek.vasut@gmail.com> + * Copyright 2020 NXP * * Based on i2c-imx.c from linux kernel: * Copyright (C) 2005 Torsten Koschorrek <koschorrek at synertronixx.de> @@ -341,6 +342,57 @@ static int i2c_init_transfer_(struct mxc_i2c_bus *i2c_bus, u8 chip, return 0; } +#if !defined(I2C2_BASE_ADDR) +#define I2C2_BASE_ADDR 0 +#endif + +#if !defined(I2C3_BASE_ADDR) +#define I2C3_BASE_ADDR 0 +#endif + +#if !defined(I2C4_BASE_ADDR) +#define I2C4_BASE_ADDR 0 +#endif + +#if !defined(I2C5_BASE_ADDR) +#define I2C5_BASE_ADDR 0 +#endif + +#if !defined(I2C6_BASE_ADDR) +#define I2C6_BASE_ADDR 0 +#endif + +#if !defined(I2C7_BASE_ADDR) +#define I2C7_BASE_ADDR 0 +#endif + +#if !defined(I2C8_BASE_ADDR) +#define I2C8_BASE_ADDR 0 +#endif + +static struct mxc_i2c_bus mxc_i2c_buses[] = { +#if defined(CONFIG_ARCH_LS1021A) || defined(CONFIG_VF610) || \ + defined(CONFIG_FSL_LAYERSCAPE) + { 0, I2C1_BASE_ADDR, I2C_QUIRK_FLAG }, + { 1, I2C2_BASE_ADDR, I2C_QUIRK_FLAG }, + { 2, I2C3_BASE_ADDR, I2C_QUIRK_FLAG }, + { 3, I2C4_BASE_ADDR, I2C_QUIRK_FLAG }, + { 4, I2C5_BASE_ADDR, I2C_QUIRK_FLAG }, + { 5, I2C6_BASE_ADDR, I2C_QUIRK_FLAG }, + { 6, I2C7_BASE_ADDR, I2C_QUIRK_FLAG }, + { 7, I2C8_BASE_ADDR, I2C_QUIRK_FLAG }, +#else + { 0, I2C1_BASE_ADDR, 0 }, + { 1, I2C2_BASE_ADDR, 0 }, + { 2, I2C3_BASE_ADDR, 0 }, + { 3, I2C4_BASE_ADDR, 0 }, + { 4, I2C5_BASE_ADDR, 0 }, + { 5, I2C6_BASE_ADDR, 0 }, + { 6, I2C7_BASE_ADDR, 0 }, + { 7, I2C8_BASE_ADDR, 0 }, +#endif +}; + #ifndef CONFIG_DM_I2C int i2c_idle_bus(struct mxc_i2c_bus *i2c_bus) { @@ -434,6 +486,24 @@ exit: return ret; } #endif +/* + * Early init I2C for prepare read the clk through I2C. + */ +void i2c_early_init_f(void) +{ + ulong base = mxc_i2c_buses[I2C_EARLY_INIT_INDEX].base; + bool quirk = mxc_i2c_buses[I2C_EARLY_INIT_INDEX].driver_data + & I2C_QUIRK_FLAG ? true : false; + int reg_shift = quirk ? VF610_I2C_REGSHIFT : IMX_I2C_REGSHIFT; + + /* Set I2C divider value */ + writeb(I2C_IFDR_DIV_CONSERVATIVE, base + (IFDR << reg_shift)); + /* Reset module */ + writeb(I2CR_IDIS, base + (I2CR << reg_shift)); + writeb(0, base + (I2SR << reg_shift)); + /* Enable I2C */ + writeb(I2CR_IEN, base + (I2CR << reg_shift)); +} static int i2c_init_transfer(struct mxc_i2c_bus *i2c_bus, u8 chip, u32 addr, int alen) @@ -662,57 +732,6 @@ static int bus_i2c_write(struct mxc_i2c_bus *i2c_bus, u8 chip, u32 addr, return ret; } -#if !defined(I2C2_BASE_ADDR) -#define I2C2_BASE_ADDR 0 -#endif - -#if !defined(I2C3_BASE_ADDR) -#define I2C3_BASE_ADDR 0 -#endif - -#if !defined(I2C4_BASE_ADDR) -#define I2C4_BASE_ADDR 0 -#endif - -#if !defined(I2C5_BASE_ADDR) -#define I2C5_BASE_ADDR 0 -#endif - -#if !defined(I2C6_BASE_ADDR) -#define I2C6_BASE_ADDR 0 -#endif - -#if !defined(I2C7_BASE_ADDR) -#define I2C7_BASE_ADDR 0 -#endif - -#if !defined(I2C8_BASE_ADDR) -#define I2C8_BASE_ADDR 0 -#endif - -static struct mxc_i2c_bus mxc_i2c_buses[] = { -#if defined(CONFIG_ARCH_LS1021A) || defined(CONFIG_VF610) || \ - defined(CONFIG_FSL_LAYERSCAPE) - { 0, I2C1_BASE_ADDR, I2C_QUIRK_FLAG }, - { 1, I2C2_BASE_ADDR, I2C_QUIRK_FLAG }, - { 2, I2C3_BASE_ADDR, I2C_QUIRK_FLAG }, - { 3, I2C4_BASE_ADDR, I2C_QUIRK_FLAG }, - { 4, I2C5_BASE_ADDR, I2C_QUIRK_FLAG }, - { 5, I2C6_BASE_ADDR, I2C_QUIRK_FLAG }, - { 6, I2C7_BASE_ADDR, I2C_QUIRK_FLAG }, - { 7, I2C8_BASE_ADDR, I2C_QUIRK_FLAG }, -#else - { 0, I2C1_BASE_ADDR, 0 }, - { 1, I2C2_BASE_ADDR, 0 }, - { 2, I2C3_BASE_ADDR, 0 }, - { 3, I2C4_BASE_ADDR, 0 }, - { 4, I2C5_BASE_ADDR, 0 }, - { 5, I2C6_BASE_ADDR, 0 }, - { 6, I2C7_BASE_ADDR, 0 }, - { 7, I2C8_BASE_ADDR, 0 }, -#endif -}; - struct mxc_i2c_bus *i2c_get_base(struct i2c_adapter *adap) { return &mxc_i2c_buses[adap->hwadapnr]; @@ -778,24 +797,7 @@ void bus_i2c_init(int index, int speed, int unused, bus_i2c_set_bus_speed(&mxc_i2c_buses[index], speed); } -/* - * Early init I2C for prepare read the clk through I2C. - */ -void i2c_early_init_f(void) -{ - ulong base = mxc_i2c_buses[I2C_EARLY_INIT_INDEX].base; - bool quirk = mxc_i2c_buses[I2C_EARLY_INIT_INDEX].driver_data - & I2C_QUIRK_FLAG ? true : false; - int reg_shift = quirk ? VF610_I2C_REGSHIFT : IMX_I2C_REGSHIFT; - /* Set I2C divider value */ - writeb(I2C_IFDR_DIV_CONSERVATIVE, base + (IFDR << reg_shift)); - /* Reset module */ - writeb(I2CR_IDIS, base + (I2CR << reg_shift)); - writeb(0, base + (I2SR << reg_shift)); - /* Enable I2C */ - writeb(I2CR_IEN, base + (I2CR << reg_shift)); -} /* * Init I2C Bus @@ -899,7 +901,7 @@ static int mxc_i2c_probe(struct udevice *bus) i2c_bus->driver_data = dev_get_driver_data(bus); - addr = devfdt_get_addr(bus); + addr = dev_read_addr(bus); if (addr == FDT_ADDR_T_NONE) return -EINVAL; diff --git a/drivers/i2c/nx_i2c.c b/drivers/i2c/nx_i2c.c new file mode 100644 index 0000000000..ca14a0ecac --- /dev/null +++ b/drivers/i2c/nx_i2c.c @@ -0,0 +1,626 @@ +#include <common.h> +#include <errno.h> +#include <dm.h> +#include <i2c.h> +#include <log.h> +#include <asm/arch/nexell.h> +#include <asm/arch/reset.h> +#include <asm/arch/clk.h> +#include <asm/arch/nx_gpio.h> +#include <linux/delay.h> + +#define I2C_WRITE 0 +#define I2C_READ 1 + +#define I2CSTAT_MTM 0xC0 /* Master Transmit Mode */ +#define I2CSTAT_MRM 0x80 /* Master Receive Mode */ +#define I2CSTAT_BSY 0x20 /* Read: Bus Busy */ +#define I2CSTAT_SS 0x20 /* Write: START (1) / STOP (0) */ +#define I2CSTAT_RXTXEN 0x10 /* Rx/Tx enable */ +#define I2CSTAT_ABT 0x08 /* Arbitration bit */ +#define I2CSTAT_NACK 0x01 /* Nack bit */ +#define I2CCON_IRCLR 0x100 /* Interrupt Clear bit */ +#define I2CCON_ACKGEN 0x80 /* Acknowledge generation */ +#define I2CCON_TCP256 0x40 /* Tx-clock prescaler: 16 (0) / 256 (1) */ +#define I2CCON_IRENB 0x20 /* Interrupt Enable bit */ +#define I2CCON_IRPND 0x10 /* Interrupt pending bit */ +#define I2CCON_TCDMSK 0x0F /* I2C-bus transmit clock divider bit mask */ + +#ifdef CONFIG_ARCH_S5P6818 +#define SDADLY_CLKSTEP 5 /* SDA delay: Reg. val. is multiple of 5 clks */ +#define SDADLY_MAX 3 /* SDA delay: Max. reg. value is 3 */ +#define I2CLC_FILTER 0x04 /* SDA filter on */ +#else +#define STOPCON_CLR 0x01 /* Clock Line Release */ +#define STOPCON_DLR 0x02 /* Data Line Release */ +#define STOPCON_NAG 0x04 /* not-ackn. generation and data shift cont. */ +#endif + +#define I2C_TIMEOUT_MS 10 /* 10 ms */ + +#define I2C_M_NOSTOP 0x100 + +#define MAX_I2C_NUM 3 + +#define DEFAULT_SPEED 100000 /* default I2C speed [Hz] */ + +DECLARE_GLOBAL_DATA_PTR; + +struct nx_i2c_regs { + uint iiccon; + uint iicstat; + uint iicadd; + uint iicds; +#ifdef CONFIG_ARCH_S5P6818 + /* S5P6818: Offset 0x10 is Line Control Register (SDA-delay, Filter) */ + uint iiclc; +#else + /* S5P4418: Offset 0x10 is Stop Control Register */ + uint iicstopcon; +#endif +}; + +struct nx_i2c_bus { + uint bus_num; + struct nx_i2c_regs *regs; + uint speed; + uint target_speed; +#ifdef CONFIG_ARCH_S5P6818 + uint sda_delay; +#else + /* setup time for Stop condition [us] */ + uint tsu_stop; +#endif +}; + +/* s5pxx18 i2c must be reset before enabled */ +static void i2c_reset(int ch) +{ + int rst_id = RESET_ID_I2C0 + ch; + + nx_rstcon_setrst(rst_id, 0); + nx_rstcon_setrst(rst_id, 1); +} + +static uint i2c_get_clkrate(struct nx_i2c_bus *bus) +{ + struct clk *clk; + int index = bus->bus_num; + char name[50] = {0, }; + + sprintf(name, "%s.%d", DEV_NAME_I2C, index); + clk = clk_get((const char *)name); + if (!clk) + return -1; + + return clk_get_rate(clk); +} + +static uint i2c_set_clk(struct nx_i2c_bus *bus, uint enb) +{ + struct clk *clk; + char name[50]; + + sprintf(name, "%s.%d", DEV_NAME_I2C, bus->bus_num); + clk = clk_get((const char *)name); + if (!clk) { + debug("%s(): clk_get(%s) error!\n", + __func__, (const char *)name); + return -EINVAL; + } + + clk_disable(clk); + if (enb) + clk_enable(clk); + + return 0; +} + +#ifdef CONFIG_ARCH_S5P6818 +/* Set SDA line delay, not available at S5P4418 */ +static int nx_i2c_set_sda_delay(struct nx_i2c_bus *bus) +{ + struct nx_i2c_regs *i2c = bus->regs; + uint pclk = 0; + uint t_pclk = 0; + uint delay = 0; + + /* get input clock of the I2C-controller */ + pclk = i2c_get_clkrate(bus); + + if (bus->sda_delay) { + /* t_pclk = period time of one pclk [ns] */ + t_pclk = DIV_ROUND_UP(1000, pclk / 1000000); + /* delay = number of pclks required for sda_delay [ns] */ + delay = DIV_ROUND_UP(bus->sda_delay, t_pclk); + /* delay = register value (step of 5 clocks) */ + delay = DIV_ROUND_UP(delay, SDADLY_CLKSTEP); + /* max. possible register value = 3 */ + if (delay > SDADLY_MAX) { + delay = SDADLY_MAX; + debug("%s(): sda-delay des.: %dns, sat. to max.: %dns (granularity: %dns)\n", + __func__, bus->sda_delay, t_pclk * delay * SDADLY_CLKSTEP, + t_pclk * SDADLY_CLKSTEP); + } else { + debug("%s(): sda-delay des.: %dns, act.: %dns (granularity: %dns)\n", + __func__, bus->sda_delay, t_pclk * delay * SDADLY_CLKSTEP, + t_pclk * SDADLY_CLKSTEP); + } + + delay |= I2CLC_FILTER; + } else { + delay = 0; + debug("%s(): sda-delay = 0\n", __func__); + } + + delay &= 0x7; + writel(delay, &i2c->iiclc); + + return 0; +} +#endif + +static int nx_i2c_set_bus_speed(struct udevice *dev, uint speed) +{ + struct nx_i2c_bus *bus = dev_get_priv(dev); + struct nx_i2c_regs *i2c = bus->regs; + unsigned long pclk, pres = 16, div; + + if (i2c_set_clk(bus, 1)) + return -EINVAL; + + /* get input clock of the I2C-controller */ + pclk = i2c_get_clkrate(bus); + + /* calculate prescaler and divisor values */ + if ((pclk / pres / (16 + 1)) > speed) + /* prescaler value 16 is too less --> set to 256 */ + pres = 256; + + div = 0; + /* actual divider = div + 1 */ + while ((pclk / pres / (div + 1)) > speed) + div++; + + if (div > 0xF) { + debug("%s(): pres==%ld, div==0x%lx is saturated to 0xF !)\n", + __func__, pres, div); + div = 0xF; + } else { + debug("%s(): pres==%ld, div==0x%lx)\n", __func__, pres, div); + } + + /* set Tx-clock divisor and prescaler values */ + writel((div & I2CCON_TCDMSK) | ((pres == 256) ? I2CCON_TCP256 : 0), + &i2c->iiccon); + + /* init to SLAVE REVEIVE and set slaveaddr */ + writel(0, &i2c->iicstat); + writel(0x00, &i2c->iicadd); + + /* program Master Transmit (and implicit STOP) */ + writel(I2CSTAT_MTM | I2CSTAT_RXTXEN, &i2c->iicstat); + + /* calculate actual I2C speed [Hz] */ + bus->speed = pclk / ((div + 1) * pres); + debug("%s(): speed des.: %dHz, act.: %dHz\n", + __func__, speed, bus->speed); + +#ifdef CONFIG_ARCH_S5P6818 + nx_i2c_set_sda_delay(bus); +#else + /* setup time for Stop condition [us], min. 4us @ 100kHz I2C-clock */ + bus->tsu_stop = DIV_ROUND_UP(400, bus->speed / 1000); +#endif + + if (i2c_set_clk(bus, 0)) + return -EINVAL; + return 0; +} + +static void i2c_process_node(struct udevice *dev) +{ + struct nx_i2c_bus *bus = dev_get_priv(dev); + + bus->target_speed = dev_read_s32_default(dev, "clock-frequency", + DEFAULT_SPEED); +#ifdef CONFIG_ARCH_S5P6818 + bus->sda_delay = dev_read_s32_default(dev, "i2c-sda-delay-ns", 0); +#endif +} + +static int nx_i2c_probe(struct udevice *dev) +{ + struct nx_i2c_bus *bus = dev_get_priv(dev); + fdt_addr_t addr; + + /* get regs = i2c base address */ + addr = devfdt_get_addr(dev); + if (addr == FDT_ADDR_T_NONE) + return -EINVAL; + bus->regs = (struct nx_i2c_regs *)addr; + + bus->bus_num = dev->seq; + + /* i2c node parsing */ + i2c_process_node(dev); + if (!bus->target_speed) + return -ENODEV; + + /* reset */ + i2c_reset(bus->bus_num); + + return 0; +} + +/* i2c bus busy check */ +static int i2c_is_busy(struct nx_i2c_regs *i2c) +{ + ulong start_time; + + start_time = get_timer(0); + while (readl(&i2c->iicstat) & I2CSTAT_BSY) { + if (get_timer(start_time) > I2C_TIMEOUT_MS) { + debug("Timeout\n"); + return -EBUSY; + } + } + return 0; +} + +/* irq enable/disable functions */ +static void i2c_enable_irq(struct nx_i2c_regs *i2c) +{ + unsigned int reg; + + reg = readl(&i2c->iiccon); + reg |= I2CCON_IRENB; + writel(reg, &i2c->iiccon); +} + +/* irq clear function */ +static void i2c_clear_irq(struct nx_i2c_regs *i2c) +{ + unsigned int reg; + + reg = readl(&i2c->iiccon); + /* reset interrupt pending flag */ + reg &= ~(I2CCON_IRPND); + /* + * Interrupt must also be cleared! + * Otherwise linux boot may hang after: + * [ 0.436000] NetLabel: unlabeled traffic allowed by default + * Next would be: + * [ 0.442000] clocksource: Switched to clocksource source timer + */ + reg |= I2CCON_IRCLR; + writel(reg, &i2c->iiccon); +} + +/* ack enable functions */ +static void i2c_enable_ack(struct nx_i2c_regs *i2c) +{ + unsigned int reg; + + reg = readl(&i2c->iiccon); + reg |= I2CCON_ACKGEN; + writel(reg, &i2c->iiccon); +} + +static void i2c_send_stop(struct nx_i2c_bus *bus) +{ + struct nx_i2c_regs *i2c = bus->regs; + + if (IS_ENABLED(CONFIG_ARCH_S5P6818)) { + unsigned int reg; + + reg = readl(&i2c->iicstat); + reg |= I2CSTAT_MRM | I2CSTAT_RXTXEN; + reg &= (~I2CSTAT_SS); + + writel(reg, &i2c->iicstat); + i2c_clear_irq(i2c); + } else { /* S5P4418 */ + writel(STOPCON_NAG, &i2c->iicstopcon); + + i2c_clear_irq(i2c); + + /* + * Clock Line Release --> SDC changes from Low to High and + * SDA from High to Low + */ + writel(STOPCON_CLR, &i2c->iicstopcon); + + /* Hold SDA Low (Setup Time for Stop condition) */ + udelay(bus->tsu_stop); + + i2c_clear_irq(i2c); + + /* Master Receive Mode Stop --> SDA becomes High */ + writel(I2CSTAT_MRM, &i2c->iicstat); + } +} + +static int wait_for_xfer(struct nx_i2c_regs *i2c) +{ + unsigned long start_time = get_timer(0); + + do { + if (readl(&i2c->iiccon) & I2CCON_IRPND) + /* return -EREMOTEIO if not Acknowledged, otherwise 0 */ + return (readl(&i2c->iicstat) & I2CSTAT_NACK) ? + -EREMOTEIO : 0; + } while (get_timer(start_time) < I2C_TIMEOUT_MS); + + return -ETIMEDOUT; +} + +static int i2c_transfer(struct nx_i2c_regs *i2c, + uchar cmd_type, + uchar chip_addr, + uchar addr[], + uchar addr_len, + uchar data[], + unsigned short data_len, + uint seq) +{ + uint status; + int i = 0, result; + + /* Note: data_len = 0 is supported for "probe_chip" */ + + i2c_enable_irq(i2c); + i2c_enable_ack(i2c); + + /* Get the slave chip address going */ + /* Enable Rx/Tx */ + writel(I2CSTAT_RXTXEN, &i2c->iicstat); + + writel(chip_addr, &i2c->iicds); + status = I2CSTAT_RXTXEN | I2CSTAT_SS; + if (cmd_type == I2C_WRITE || (addr && addr_len)) + status |= I2CSTAT_MTM; + else + status |= I2CSTAT_MRM; + + writel(status, &i2c->iicstat); + if (seq) + i2c_clear_irq(i2c); + + /* Wait for chip address to transmit. */ + result = wait_for_xfer(i2c); + if (result) { + debug("%s: transmitting chip address failed\n", __func__); + goto bailout; + } + + /* If register address needs to be transmitted - do it now. */ + if (addr && addr_len) { /* register addr */ + while ((i < addr_len) && !result) { + writel(addr[i++], &i2c->iicds); + i2c_clear_irq(i2c); + result = wait_for_xfer(i2c); + } + + i = 0; + if (result) { + debug("%s: transmitting register address failed\n", + __func__); + goto bailout; + } + } + + switch (cmd_type) { + case I2C_WRITE: + while ((i < data_len) && !result) { + writel(data[i++], &i2c->iicds); + i2c_clear_irq(i2c); + result = wait_for_xfer(i2c); + } + break; + case I2C_READ: + if (addr && addr_len) { + /* + * Register address has been sent, now send slave chip + * address again to start the actual read transaction. + */ + writel(chip_addr, &i2c->iicds); + + /* Generate a re-START. */ + writel(I2CSTAT_MRM | I2CSTAT_RXTXEN | + I2CSTAT_SS, &i2c->iicstat); + i2c_clear_irq(i2c); + result = wait_for_xfer(i2c); + if (result) { + debug("%s: I2C_READ: sending chip addr. failed\n", + __func__); + goto bailout; + } + } + + while ((i < data_len) && !result) { + /* disable ACK for final READ */ + if (i == data_len - 1) + clrbits_le32(&i2c->iiccon, I2CCON_ACKGEN); + + i2c_clear_irq(i2c); + result = wait_for_xfer(i2c); + data[i++] = readb(&i2c->iicds); + } + + if (result == -EREMOTEIO) + /* Not Acknowledged --> normal terminated read. */ + result = 0; + else if (result == -ETIMEDOUT) + debug("%s: I2C_READ: time out\n", __func__); + else + debug("%s: I2C_READ: read not terminated with NACK\n", + __func__); + break; + + default: + debug("%s: bad call\n", __func__); + result = -EINVAL; + break; + } + +bailout: + return result; +} + +static int nx_i2c_read(struct udevice *dev, uchar chip_addr, uint addr, + uint alen, uchar *buffer, uint len, uint seq) +{ + struct nx_i2c_bus *i2c; + uchar xaddr[4]; + int ret; + + i2c = dev_get_priv(dev); + if (!i2c) + return -EFAULT; + + if (alen > 4) { + debug("I2C read: addr len %d not supported\n", alen); + return -EADDRNOTAVAIL; + } + + if (alen > 0) + xaddr[0] = (addr >> 24) & 0xFF; + + if (alen > 0) { + xaddr[0] = (addr >> 24) & 0xFF; + xaddr[1] = (addr >> 16) & 0xFF; + xaddr[2] = (addr >> 8) & 0xFF; + xaddr[3] = addr & 0xFF; + } + + ret = i2c_transfer(i2c->regs, I2C_READ, chip_addr << 1, + &xaddr[4 - alen], alen, buffer, len, seq); + + if (ret) { + debug("I2C read failed %d\n", ret); + return -EIO; + } + + return 0; +} + +static int nx_i2c_write(struct udevice *dev, uchar chip_addr, uint addr, + uint alen, uchar *buffer, uint len, uint seq) +{ + struct nx_i2c_bus *i2c; + uchar xaddr[4]; + int ret; + + i2c = dev_get_priv(dev); + if (!i2c) + return -EFAULT; + + if (alen > 4) { + debug("I2C write: addr len %d not supported\n", alen); + return -EINVAL; + } + + if (alen > 0) { + xaddr[0] = (addr >> 24) & 0xFF; + xaddr[1] = (addr >> 16) & 0xFF; + xaddr[2] = (addr >> 8) & 0xFF; + xaddr[3] = addr & 0xFF; + } + + ret = i2c_transfer(i2c->regs, I2C_WRITE, chip_addr << 1, + &xaddr[4 - alen], alen, buffer, len, seq); + if (ret) { + debug("I2C write failed %d\n", ret); + return -EIO; + } + + return 0; +} + +static int nx_i2c_xfer(struct udevice *dev, struct i2c_msg *msg, int nmsgs) +{ + struct nx_i2c_bus *bus = dev_get_priv(dev); + struct nx_i2c_regs *i2c = bus->regs; + int ret; + int i; + + /* The power loss by the clock, only during on/off. */ + ret = i2c_set_clk(bus, 1); + + if (!ret) + /* Bus State(Busy) check */ + ret = i2c_is_busy(i2c); + if (!ret) { + for (i = 0; i < nmsgs; msg++, i++) { + if (msg->flags & I2C_M_RD) { + ret = nx_i2c_read(dev, msg->addr, 0, 0, + msg->buf, msg->len, i); + } else { + ret = nx_i2c_write(dev, msg->addr, 0, 0, + msg->buf, msg->len, i); + } + + if (ret) { + debug("i2c_xfer: error sending\n"); + ret = -EREMOTEIO; + } + } + + i2c_send_stop(bus); + if (i2c_set_clk(bus, 0)) + ret = -EINVAL; + } + + return ret; +}; + +static int nx_i2c_probe_chip(struct udevice *dev, u32 chip_addr, + u32 chip_flags) +{ + int ret; + struct nx_i2c_bus *bus = dev_get_priv(dev); + + ret = i2c_set_clk(bus, 1); + + if (!ret) { + /* + * Send Chip Address only + * --> I2C transfer with data length and address length = 0. + * If there is a Slave, i2c_transfer() returns 0 (acknowledge + * transfer). + * I2C_WRITE must be used in order Master Transmit Mode is + * selected. Otherwise (in Master Receive Mode, I2C_READ) + * sending the stop condition below is not working (SDA does + * not transit to High). + */ + ret = i2c_transfer(bus->regs, I2C_WRITE, (uchar)chip_addr << 1, + NULL, 0, NULL, 0, 0); + + i2c_send_stop(bus); + if (i2c_set_clk(bus, 0)) + ret = -EINVAL; + } + + return ret; +} + +static const struct dm_i2c_ops nx_i2c_ops = { + .xfer = nx_i2c_xfer, + .probe_chip = nx_i2c_probe_chip, + .set_bus_speed = nx_i2c_set_bus_speed, +}; + +static const struct udevice_id nx_i2c_ids[] = { + { .compatible = "nexell,s5pxx18-i2c" }, + { } +}; + +U_BOOT_DRIVER(i2c_nexell) = { + .name = "i2c_nexell", + .id = UCLASS_I2C, + .of_match = nx_i2c_ids, + .probe = nx_i2c_probe, + .priv_auto_alloc_size = sizeof(struct nx_i2c_bus), + .ops = &nx_i2c_ops, +}; diff --git a/drivers/i2c/omap24xx_i2c.c b/drivers/i2c/omap24xx_i2c.c index 8592a819c4..0af4e333c4 100644 --- a/drivers/i2c/omap24xx_i2c.c +++ b/drivers/i2c/omap24xx_i2c.c @@ -1067,7 +1067,7 @@ static int omap_i2c_ofdata_to_platdata(struct udevice *bus) { struct omap_i2c_platdata *plat = dev_get_platdata(bus); - plat->base = devfdt_get_addr(bus); + plat->base = dev_read_addr(bus); plat->speed = dev_read_u32_default(bus, "clock-frequency", I2C_SPEED_STANDARD_RATE); plat->ip_rev = dev_get_driver_data(bus); diff --git a/drivers/i2c/s3c24x0_i2c.c b/drivers/i2c/s3c24x0_i2c.c index 5907217981..cb45d3c100 100644 --- a/drivers/i2c/s3c24x0_i2c.c +++ b/drivers/i2c/s3c24x0_i2c.c @@ -310,7 +310,7 @@ static int s3c_i2c_ofdata_to_platdata(struct udevice *dev) node = dev_of_offset(dev); - i2c_bus->regs = (struct s3c24x0_i2c *)devfdt_get_addr(dev); + i2c_bus->regs = dev_read_addr_ptr(dev); i2c_bus->id = pinmux_decode_periph_id(blob, node); diff --git a/drivers/input/tegra-kbc.c b/drivers/input/tegra-kbc.c index 3409bb61d5..f07a51dc30 100644 --- a/drivers/input/tegra-kbc.c +++ b/drivers/input/tegra-kbc.c @@ -291,7 +291,7 @@ static int tegra_kbd_probe(struct udevice *dev) struct input_config *input = &uc_priv->input; int ret; - priv->kbc = (struct kbc_tegra *)devfdt_get_addr(dev); + priv->kbc = dev_read_addr_ptr(dev); if ((fdt_addr_t)priv->kbc == FDT_ADDR_T_NONE) { debug("%s: No keyboard register found\n", __func__); return -EINVAL; diff --git a/drivers/mailbox/tegra-hsp.c b/drivers/mailbox/tegra-hsp.c index f82e6d3d16..e91dac201d 100644 --- a/drivers/mailbox/tegra-hsp.c +++ b/drivers/mailbox/tegra-hsp.c @@ -153,7 +153,7 @@ static int tegra_hsp_probe(struct udevice *dev) debug("%s(dev=%p)\n", __func__, dev); - thsp->regs = devfdt_get_addr(dev); + thsp->regs = dev_read_addr(dev); if (thsp->regs == FDT_ADDR_T_NONE) return -ENODEV; diff --git a/drivers/misc/altera_sysid.c b/drivers/misc/altera_sysid.c index 387c70b070..c6502650b7 100644 --- a/drivers/misc/altera_sysid.c +++ b/drivers/misc/altera_sysid.c @@ -73,7 +73,7 @@ static int altera_sysid_ofdata_to_platdata(struct udevice *dev) { struct altera_sysid_platdata *plat = dev_get_platdata(dev); - plat->regs = map_physmem(devfdt_get_addr(dev), + plat->regs = map_physmem(dev_read_addr(dev), sizeof(struct altera_sysid_regs), MAP_NOCACHE); diff --git a/drivers/misc/imx8/scu.c b/drivers/misc/imx8/scu.c index ee635eb947..223aac8518 100644 --- a/drivers/misc/imx8/scu.c +++ b/drivers/misc/imx8/scu.c @@ -187,7 +187,7 @@ static int imx8_scu_probe(struct udevice *dev) debug("%s(dev=%p) (plat=%p)\n", __func__, dev, plat); - addr = devfdt_get_addr(dev); + addr = dev_read_addr(dev); if (addr == FDT_ADDR_T_NONE) return -EINVAL; diff --git a/drivers/misc/microchip_flexcom.c b/drivers/misc/microchip_flexcom.c index 44a8b180a4..64cc4ae7b6 100644 --- a/drivers/misc/microchip_flexcom.c +++ b/drivers/misc/microchip_flexcom.c @@ -26,7 +26,7 @@ static int microchip_flexcom_ofdata_to_platdata(struct udevice *dev) struct microchip_flexcom_platdata *plat = dev_get_platdata(dev); int ret; - plat->regs = map_physmem(devfdt_get_addr(dev), + plat->regs = map_physmem(dev_read_addr(dev), sizeof(struct microchip_flexcom_regs), MAP_NOCACHE); diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig index ad86c232c4..556b3ac489 100644 --- a/drivers/mmc/Kconfig +++ b/drivers/mmc/Kconfig @@ -263,6 +263,14 @@ config MMC_DW_SNPS This selects support for Synopsys DesignWare Memory Card Interface driver extensions used in various Synopsys ARC devboards. +config NEXELL_DWMMC + bool "Nexell SD/MMC controller support" + depends on ARCH_NEXELL + depends on MMC_DW + depends on DM_MMC + depends on PINCTRL_NEXELL + default y + config MMC_MESON_GX bool "Meson GX EMMC controller support" depends on DM_MMC && BLK && ARCH_MESON diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile index e84c792999..d375669a7b 100644 --- a/drivers/mmc/Makefile +++ b/drivers/mmc/Makefile @@ -44,6 +44,7 @@ obj-$(CONFIG_SH_MMCIF) += sh_mmcif.o obj-$(CONFIG_SH_SDHI) += sh_sdhi.o obj-$(CONFIG_STM32_SDMMC2) += stm32_sdmmc2.o obj-$(CONFIG_JZ47XX_MMC) += jz_mmc.o +obj-$(CONFIG_NEXELL_DWMMC) += nexell_dw_mmc.o # SDHCI obj-$(CONFIG_MMC_SDHCI) += sdhci.o diff --git a/drivers/mmc/aspeed_sdhci.c b/drivers/mmc/aspeed_sdhci.c index 8929e603f3..543c65a8e3 100644 --- a/drivers/mmc/aspeed_sdhci.c +++ b/drivers/mmc/aspeed_sdhci.c @@ -34,7 +34,7 @@ static int aspeed_sdhci_probe(struct udevice *dev) goto free; host->name = dev->name; - host->ioaddr = (void *)devfdt_get_addr(dev); + host->ioaddr = dev_read_addr_ptr(dev); max_clk = clk_get_rate(&clk); if (IS_ERR_VALUE(max_clk)) { diff --git a/drivers/mmc/atmel_sdhci.c b/drivers/mmc/atmel_sdhci.c index 2b797c9bd4..0c53caf448 100644 --- a/drivers/mmc/atmel_sdhci.c +++ b/drivers/mmc/atmel_sdhci.c @@ -69,7 +69,7 @@ static int atmel_sdhci_probe(struct udevice *dev) return ret; host->name = dev->name; - host->ioaddr = (void *)devfdt_get_addr(dev); + host->ioaddr = dev_read_addr_ptr(dev); host->quirks = SDHCI_QUIRK_WAIT_SEND_CMD; host->bus_width = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev), diff --git a/drivers/mmc/bcm2835_sdhci.c b/drivers/mmc/bcm2835_sdhci.c index 5cdf3c506f..7a410d1dd3 100644 --- a/drivers/mmc/bcm2835_sdhci.c +++ b/drivers/mmc/bcm2835_sdhci.c @@ -182,7 +182,7 @@ static int bcm2835_sdhci_probe(struct udevice *dev) int ret; int clock_id = (int)dev_get_driver_data(dev); - base = devfdt_get_addr(dev); + base = dev_read_addr(dev); if (base == FDT_ADDR_T_NONE) return -EINVAL; diff --git a/drivers/mmc/bcm2835_sdhost.c b/drivers/mmc/bcm2835_sdhost.c index c4876e81f8..b793028ab5 100644 --- a/drivers/mmc/bcm2835_sdhost.c +++ b/drivers/mmc/bcm2835_sdhost.c @@ -766,7 +766,7 @@ static int bcm2835_probe(struct udevice *dev) upriv->mmc = &plat->mmc; plat->cfg.name = dev->name; - host->phys_addr = devfdt_get_addr(dev); + host->phys_addr = dev_read_addr(dev); if (host->phys_addr == FDT_ADDR_T_NONE) return -EINVAL; diff --git a/drivers/mmc/bcmstb_sdhci.c b/drivers/mmc/bcmstb_sdhci.c index c14f8289e6..5269aa77ce 100644 --- a/drivers/mmc/bcmstb_sdhci.c +++ b/drivers/mmc/bcmstb_sdhci.c @@ -62,7 +62,7 @@ static int sdhci_bcmstb_probe(struct udevice *dev) fdt_addr_t base; int ret; - base = devfdt_get_addr(dev); + base = dev_read_addr(dev); if (base == FDT_ADDR_T_NONE) return -EINVAL; diff --git a/drivers/mmc/fsl_esdhc.c b/drivers/mmc/fsl_esdhc.c index f6e0d43057..de9fe01bc5 100644 --- a/drivers/mmc/fsl_esdhc.c +++ b/drivers/mmc/fsl_esdhc.c @@ -671,45 +671,6 @@ static void fsl_esdhc_get_cfg_common(struct fsl_esdhc_priv *priv, cfg->b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT; } -#ifdef CONFIG_FSL_ESDHC_ADAPTER_IDENT -void mmc_adapter_card_type_ident(void) -{ - u8 card_id; - u8 value; - - card_id = QIXIS_READ(present) & QIXIS_SDID_MASK; - gd->arch.sdhc_adapter = card_id; - - switch (card_id) { - case QIXIS_ESDHC_ADAPTER_TYPE_EMMC45: - value = QIXIS_READ(brdcfg[5]); - value |= (QIXIS_DAT4 | QIXIS_DAT5_6_7); - QIXIS_WRITE(brdcfg[5], value); - break; - case QIXIS_ESDHC_ADAPTER_TYPE_SDMMC_LEGACY: - value = QIXIS_READ(pwr_ctl[1]); - value |= QIXIS_EVDD_BY_SDHC_VS; - QIXIS_WRITE(pwr_ctl[1], value); - break; - case QIXIS_ESDHC_ADAPTER_TYPE_EMMC44: - value = QIXIS_READ(brdcfg[5]); - value |= (QIXIS_SDCLKIN | QIXIS_SDCLKOUT); - QIXIS_WRITE(brdcfg[5], value); - break; - case QIXIS_ESDHC_ADAPTER_TYPE_RSV: - break; - case QIXIS_ESDHC_ADAPTER_TYPE_MMC: - break; - case QIXIS_ESDHC_ADAPTER_TYPE_SD: - break; - case QIXIS_ESDHC_NO_ADAPTER: - break; - default: - break; - } -} -#endif - #ifdef CONFIG_OF_LIBFDT __weak int esdhc_status_fixup(void *blob, const char *compat) { diff --git a/drivers/mmc/ftsdc010_mci.c b/drivers/mmc/ftsdc010_mci.c index fb28f0166f..bc0d5ffed5 100644 --- a/drivers/mmc/ftsdc010_mci.c +++ b/drivers/mmc/ftsdc010_mci.c @@ -395,7 +395,7 @@ static int ftsdc010_mmc_ofdata_to_platdata(struct udevice *dev) struct ftsdc_priv *priv = dev_get_priv(dev); struct ftsdc010_chip *chip = &priv->chip; chip->name = dev->name; - chip->ioaddr = (void *)devfdt_get_addr(dev); + chip->ioaddr = dev_read_addr_ptr(dev); chip->buswidth = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev), "bus-width", 4); chip->priv = dev; diff --git a/drivers/mmc/hi6220_dw_mmc.c b/drivers/mmc/hi6220_dw_mmc.c index 6de7924383..67d6a05b3b 100644 --- a/drivers/mmc/hi6220_dw_mmc.c +++ b/drivers/mmc/hi6220_dw_mmc.c @@ -33,7 +33,7 @@ static int hi6220_dwmmc_ofdata_to_platdata(struct udevice *dev) struct dwmci_host *host = &priv->host; host->name = dev->name; - host->ioaddr = (void *)devfdt_get_addr(dev); + host->ioaddr = dev_read_addr_ptr(dev); host->buswidth = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev), "bus-width", 4); diff --git a/drivers/mmc/iproc_sdhci.c b/drivers/mmc/iproc_sdhci.c index 91e2e3f0b8..9f530638e3 100644 --- a/drivers/mmc/iproc_sdhci.c +++ b/drivers/mmc/iproc_sdhci.c @@ -188,7 +188,7 @@ static int iproc_sdhci_probe(struct udevice *dev) iproc_host->shadow_blk = 0; host->name = dev->name; - host->ioaddr = (void *)devfdt_get_addr(dev); + host->ioaddr = dev_read_addr_ptr(dev); host->voltages = MMC_VDD_165_195 | MMC_VDD_32_33 | MMC_VDD_33_34; host->quirks = SDHCI_QUIRK_BROKEN_VOLTAGE | SDHCI_QUIRK_BROKEN_R1B; diff --git a/drivers/mmc/jz_mmc.c b/drivers/mmc/jz_mmc.c index d3f1eddf45..b33f085073 100644 --- a/drivers/mmc/jz_mmc.c +++ b/drivers/mmc/jz_mmc.c @@ -450,7 +450,7 @@ static int jz_mmc_ofdata_to_platdata(struct udevice *dev) struct mmc_config *cfg; int ret; - priv->regs = map_physmem(devfdt_get_addr(dev), 0x100, MAP_NOCACHE); + priv->regs = map_physmem(dev_read_addr(dev), 0x100, MAP_NOCACHE); cfg = &plat->cfg; cfg->name = "MSC"; diff --git a/drivers/mmc/meson_gx_mmc.c b/drivers/mmc/meson_gx_mmc.c index b7f793cd04..719dd1e5e5 100644 --- a/drivers/mmc/meson_gx_mmc.c +++ b/drivers/mmc/meson_gx_mmc.c @@ -228,7 +228,7 @@ static int meson_mmc_ofdata_to_platdata(struct udevice *dev) struct meson_mmc_platdata *pdata = dev_get_platdata(dev); fdt_addr_t addr; - addr = devfdt_get_addr(dev); + addr = dev_read_addr(dev); if (addr == FDT_ADDR_T_NONE) return -EINVAL; diff --git a/drivers/mmc/mmc-uclass.c b/drivers/mmc/mmc-uclass.c index c5b7872900..90690c8d1e 100644 --- a/drivers/mmc/mmc-uclass.c +++ b/drivers/mmc/mmc-uclass.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0+ /* * Copyright (C) 2015 Google, Inc + * Copyright 2020 NXP * Written by Simon Glass <sjg@chromium.org> */ @@ -309,9 +310,6 @@ void mmc_do_preinit(void) if (!m) continue; -#ifdef CONFIG_FSL_ESDHC_ADAPTER_IDENT - mmc_set_preinit(m, 1); -#endif if (m->preinit) mmc_start_init(m); } diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index f36d11ddc8..d79cdef62e 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0+ /* * Copyright 2008, Freescale Semiconductor, Inc + * Copyright 2020 NXP * Andy Fleming * * Based vaguely on the Linux code @@ -2789,9 +2790,6 @@ int mmc_get_op_cond(struct mmc *mmc) if (mmc->has_init) return 0; -#ifdef CONFIG_FSL_ESDHC_ADAPTER_IDENT - mmc_adapter_card_type_ident(); -#endif err = mmc_power_init(mmc); if (err) return err; @@ -3073,9 +3071,6 @@ int mmc_init_device(int num) m = mmc_get_mmc_dev(dev); if (!m) return 0; -#ifdef CONFIG_FSL_ESDHC_ADAPTER_IDENT - mmc_set_preinit(m, 1); -#endif if (m->preinit) mmc_start_init(m); diff --git a/drivers/mmc/mmc_legacy.c b/drivers/mmc/mmc_legacy.c index 2bb12ceeaf..a05da6c2e8 100644 --- a/drivers/mmc/mmc_legacy.c +++ b/drivers/mmc/mmc_legacy.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0+ /* * Copyright (C) 2016 Google, Inc + * Copyright 2020 NXP * Written by Simon Glass <sjg@chromium.org> */ @@ -23,9 +24,6 @@ struct mmc *find_mmc_device(int dev_num) void mmc_do_preinit(void) { struct mmc *m = &mmc_static; -#ifdef CONFIG_FSL_ESDHC_ADAPTER_IDENT - mmc_set_preinit(m, 1); -#endif if (m->preinit) mmc_start_init(m); } @@ -77,9 +75,6 @@ void mmc_do_preinit(void) list_for_each(entry, &mmc_devices) { m = list_entry(entry, struct mmc, link); -#ifdef CONFIG_FSL_ESDHC_ADAPTER_IDENT - mmc_set_preinit(m, 1); -#endif if (m->preinit) mmc_start_init(m); } diff --git a/drivers/mmc/mmc_private.h b/drivers/mmc/mmc_private.h index 35170d03ab..a0900e8cad 100644 --- a/drivers/mmc/mmc_private.h +++ b/drivers/mmc/mmc_private.h @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0+ */ /* * Copyright 2008,2010 Freescale Semiconductor, Inc + * Copyright 2020 NXP * Andy Fleming * * Based (loosely) on the Linux code @@ -16,9 +17,6 @@ int mmc_send_status(struct mmc *mmc, unsigned int *status); int mmc_poll_for_busy(struct mmc *mmc, int timeout); int mmc_set_blocklen(struct mmc *mmc, int len); -#ifdef CONFIG_FSL_ESDHC_ADAPTER_IDENT -void mmc_adapter_card_type_ident(void); -#endif #if CONFIG_IS_ENABLED(BLK) ulong mmc_bread(struct udevice *dev, lbaint_t start, lbaint_t blkcnt, diff --git a/drivers/mmc/msm_sdhci.c b/drivers/mmc/msm_sdhci.c index da3ae2ec35..56c3e35c9e 100644 --- a/drivers/mmc/msm_sdhci.c +++ b/drivers/mmc/msm_sdhci.c @@ -171,7 +171,7 @@ static int msm_ofdata_to_platdata(struct udevice *dev) int node = dev_of_offset(dev); host->name = strdup(dev->name); - host->ioaddr = (void *)devfdt_get_addr(dev); + host->ioaddr = dev_read_addr_ptr(dev); host->bus_width = fdtdec_get_int(gd->fdt_blob, node, "bus-width", 4); host->index = fdtdec_get_uint(gd->fdt_blob, node, "index", 0); priv->base = (void *)fdtdec_get_addr_size_auto_parent(gd->fdt_blob, diff --git a/drivers/mmc/mv_sdhci.c b/drivers/mmc/mv_sdhci.c index f5f3e43247..9b3dfa13e6 100644 --- a/drivers/mmc/mv_sdhci.c +++ b/drivers/mmc/mv_sdhci.c @@ -112,7 +112,7 @@ static int mv_sdhci_probe(struct udevice *dev) int ret; host->name = MVSDH_NAME; - host->ioaddr = (void *)devfdt_get_addr(dev); + host->ioaddr = dev_read_addr_ptr(dev); host->quirks = SDHCI_QUIRK_32BIT_DMA_ADDR | SDHCI_QUIRK_WAIT_SEND_CMD; host->mmc = &plat->mmc; host->mmc->dev = dev; diff --git a/drivers/mmc/mxsmmc.c b/drivers/mmc/mxsmmc.c index d48050ba8a..2b3a3a992c 100644 --- a/drivers/mmc/mxsmmc.c +++ b/drivers/mmc/mxsmmc.c @@ -52,15 +52,9 @@ struct mxsmmc_priv { #include <dm/read.h> #include <dt-structs.h> -#ifdef CONFIG_MX28 -#define dtd_fsl_imx_mmc dtd_fsl_imx28_mmc -#else /* CONFIG_MX23 */ -#define dtd_fsl_imx_mmc dtd_fsl_imx23_mmc -#endif - struct mxsmmc_platdata { #if CONFIG_IS_ENABLED(OF_PLATDATA) - struct dtd_fsl_imx_mmc dtplat; + struct dtd_fsl_imx23_mmc dtplat; #endif struct mmc_config cfg; struct mmc mmc; @@ -582,7 +576,7 @@ static int mxsmmc_probe(struct udevice *dev) debug("%s: probe\n", __func__); #if CONFIG_IS_ENABLED(OF_PLATDATA) - struct dtd_fsl_imx_mmc *dtplat = &plat->dtplat; + struct dtd_fsl_imx23_mmc *dtplat = &plat->dtplat; struct phandle_1_arg *p1a = &dtplat->clocks[0]; priv->buswidth = dtplat->bus_width; diff --git a/drivers/mmc/nexell_dw_mmc.c b/drivers/mmc/nexell_dw_mmc.c new file mode 100644 index 0000000000..0462759444 --- /dev/null +++ b/drivers/mmc/nexell_dw_mmc.c @@ -0,0 +1,237 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (C) Copyright 2016 Nexell + * Youngbok, Park <park@nexell.co.kr> + * + * (C) Copyright 2019 Stefan Bosch <stefan_b@posteo.net> + */ + +#include <common.h> +#include <dm.h> +#include <dt-structs.h> +#include <dwmmc.h> +#include <log.h> +#include <syscon.h> +#include <asm/arch/reset.h> +#include <asm/arch/clk.h> + +#define DWMCI_CLKSEL 0x09C +#define DWMCI_SHIFT_0 0x0 +#define DWMCI_SHIFT_1 0x1 +#define DWMCI_SHIFT_2 0x2 +#define DWMCI_SHIFT_3 0x3 +#define DWMCI_SET_SAMPLE_CLK(x) (x) +#define DWMCI_SET_DRV_CLK(x) ((x) << 16) +#define DWMCI_SET_DIV_RATIO(x) ((x) << 24) +#define DWMCI_CLKCTRL 0x114 +#define NX_MMC_CLK_DELAY(x, y, a, b) ((((x) & 0xFF) << 0) |\ + (((y) & 0x03) << 16) |\ + (((a) & 0xFF) << 8) |\ + (((b) & 0x03) << 24)) + +struct nexell_mmc_plat { + struct mmc_config cfg; + struct mmc mmc; +}; + +struct nexell_dwmmc_priv { + struct clk *clk; + struct dwmci_host host; + int fifo_size; + bool fifo_mode; + int frequency; + u32 min_freq; + u32 max_freq; + int d_delay; + int d_shift; + int s_delay; + int s_shift; + bool mmcboost; +}; + +struct clk *clk_get(const char *id); + +static void nx_dw_mmc_clksel(struct dwmci_host *host) +{ + /* host->priv is pointer to "struct udevice" */ + struct nexell_dwmmc_priv *priv = dev_get_priv(host->priv); + u32 val; + + if (priv->mmcboost) + val = DWMCI_SET_SAMPLE_CLK(DWMCI_SHIFT_0) | + DWMCI_SET_DRV_CLK(DWMCI_SHIFT_0) | DWMCI_SET_DIV_RATIO(1); + else + val = DWMCI_SET_SAMPLE_CLK(DWMCI_SHIFT_0) | + DWMCI_SET_DRV_CLK(DWMCI_SHIFT_0) | DWMCI_SET_DIV_RATIO(3); + + dwmci_writel(host, DWMCI_CLKSEL, val); +} + +static void nx_dw_mmc_reset(int ch) +{ + int rst_id = RESET_ID_SDMMC0 + ch; + + nx_rstcon_setrst(rst_id, 0); + nx_rstcon_setrst(rst_id, 1); +} + +static void nx_dw_mmc_clk_delay(struct udevice *dev) +{ + unsigned int delay; + struct nexell_dwmmc_priv *priv = dev_get_priv(dev); + struct dwmci_host *host = &priv->host; + + delay = NX_MMC_CLK_DELAY(priv->d_delay, + priv->d_shift, priv->s_delay, priv->s_shift); + + writel(delay, (host->ioaddr + DWMCI_CLKCTRL)); + debug("%s: Values set: d_delay==%d, d_shift==%d, s_delay==%d, " + "s_shift==%d\n", __func__, priv->d_delay, priv->d_shift, + priv->s_delay, priv->s_shift); +} + +static unsigned int nx_dw_mmc_get_clk(struct dwmci_host *host, uint freq) +{ + struct clk *clk; + struct udevice *dev = host->priv; + struct nexell_dwmmc_priv *priv = dev_get_priv(dev); + + int index = host->dev_index; + char name[50] = { 0, }; + + clk = priv->clk; + if (!clk) { + sprintf(name, "%s.%d", DEV_NAME_SDHC, index); + clk = clk_get((const char *)name); + if (!clk) + return 0; + priv->clk = clk; + } + + return clk_get_rate(clk) / 2; +} + +static unsigned long nx_dw_mmc_set_clk(struct dwmci_host *host, + unsigned int rate) +{ + struct clk *clk; + char name[50] = { 0, }; + struct udevice *dev = host->priv; + struct nexell_dwmmc_priv *priv = dev_get_priv(dev); + + int index = host->dev_index; + + clk = priv->clk; + if (!clk) { + sprintf(name, "%s.%d", DEV_NAME_SDHC, index); + clk = clk_get((const char *)name); + if (!clk) { + debug("%s: clk_get(\"%s\") failed!\n", __func__, name); + return 0; + } + priv->clk = clk; + } + + clk_disable(clk); + rate = clk_set_rate(clk, rate); + clk_enable(clk); + + return rate; +} + +static int nexell_dwmmc_ofdata_to_platdata(struct udevice *dev) +{ + struct nexell_dwmmc_priv *priv = dev_get_priv(dev); + struct dwmci_host *host = &priv->host; + int val = -1; + + debug("%s\n", __func__); + + host->name = dev->name; + host->ioaddr = dev_read_addr_ptr(dev); + host->buswidth = dev_read_u32_default(dev, "bus-width", 4); + host->get_mmc_clk = nx_dw_mmc_get_clk; + host->clksel = nx_dw_mmc_clksel; + host->priv = dev; + + val = dev_read_u32_default(dev, "index", -1); + if (val < 0 || val > 2) { + debug(" 'index' missing/invalid!\n"); + return -EINVAL; + } + host->dev_index = val; + + priv->fifo_size = dev_read_u32_default(dev, "fifo-size", 0x20); + priv->fifo_mode = dev_read_bool(dev, "fifo-mode"); + priv->frequency = dev_read_u32_default(dev, "frequency", 50000000); + priv->max_freq = dev_read_u32_default(dev, "max-frequency", 50000000); + priv->min_freq = 400000; /* 400 kHz */ + priv->d_delay = dev_read_u32_default(dev, "drive_dly", 0); + priv->d_shift = dev_read_u32_default(dev, "drive_shift", 3); + priv->s_delay = dev_read_u32_default(dev, "sample_dly", 0); + priv->s_shift = dev_read_u32_default(dev, "sample_shift", 2); + priv->mmcboost = dev_read_u32_default(dev, "mmcboost", 0); + + debug(" index==%d, name==%s, ioaddr==0x%08x\n", + host->dev_index, host->name, (u32)host->ioaddr); + return 0; +} + +static int nexell_dwmmc_probe(struct udevice *dev) +{ + struct nexell_mmc_plat *plat = dev_get_platdata(dev); + struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev); + struct nexell_dwmmc_priv *priv = dev_get_priv(dev); + struct dwmci_host *host = &priv->host; + struct udevice *pwr_dev __maybe_unused; + + host->fifoth_val = MSIZE(0x2) | + RX_WMARK(priv->fifo_size / 2 - 1) | + TX_WMARK(priv->fifo_size / 2); + + host->fifo_mode = priv->fifo_mode; + + dwmci_setup_cfg(&plat->cfg, host, priv->max_freq, priv->min_freq); + host->mmc = &plat->mmc; + host->mmc->priv = &priv->host; + host->mmc->dev = dev; + upriv->mmc = host->mmc; + + if (nx_dw_mmc_set_clk(host, priv->frequency * 4) != + priv->frequency * 4) { + debug("%s: nx_dw_mmc_set_clk(host, %d) failed!\n", + __func__, priv->frequency * 4); + return -EIO; + } + debug("%s: nx_dw_mmc_set_clk(host, %d) OK\n", + __func__, priv->frequency * 4); + + nx_dw_mmc_reset(host->dev_index); + nx_dw_mmc_clk_delay(dev); + + return dwmci_probe(dev); +} + +static int nexell_dwmmc_bind(struct udevice *dev) +{ + struct nexell_mmc_plat *plat = dev_get_platdata(dev); + + return dwmci_bind(dev, &plat->mmc, &plat->cfg); +} + +static const struct udevice_id nexell_dwmmc_ids[] = { + { .compatible = "nexell,nexell-dwmmc" }, + { } +}; + +U_BOOT_DRIVER(nexell_dwmmc_drv) = { + .name = "nexell_dwmmc", + .id = UCLASS_MMC, + .of_match = nexell_dwmmc_ids, + .ofdata_to_platdata = nexell_dwmmc_ofdata_to_platdata, + .ops = &dm_dwmci_ops, + .bind = nexell_dwmmc_bind, + .probe = nexell_dwmmc_probe, + .priv_auto_alloc_size = sizeof(struct nexell_dwmmc_priv), + .platdata_auto_alloc_size = sizeof(struct nexell_mmc_plat), +}; diff --git a/drivers/mmc/omap_hsmmc.c b/drivers/mmc/omap_hsmmc.c index db1f85125f..715eee0e3e 100644 --- a/drivers/mmc/omap_hsmmc.c +++ b/drivers/mmc/omap_hsmmc.c @@ -1911,7 +1911,7 @@ static int omap_hsmmc_ofdata_to_platdata(struct udevice *dev) int node = dev_of_offset(dev); int ret; - plat->base_addr = map_physmem(devfdt_get_addr(dev), + plat->base_addr = map_physmem(dev_read_addr(dev), sizeof(struct hsmmc *), MAP_NOCACHE); @@ -1933,7 +1933,7 @@ static int omap_hsmmc_ofdata_to_platdata(struct udevice *dev) plat->controller_flags |= of_data->controller_flags; #ifdef CONFIG_OMAP54XX - fixups = platform_fixups_mmc(devfdt_get_addr(dev)); + fixups = platform_fixups_mmc(dev_read_addr(dev)); if (fixups) { plat->hw_rev = fixups->hw_rev; cfg->host_caps &= ~fixups->unsupported_caps; diff --git a/drivers/mmc/renesas-sdhi.c b/drivers/mmc/renesas-sdhi.c index d6ea99d2ce..d80b3fc28f 100644 --- a/drivers/mmc/renesas-sdhi.c +++ b/drivers/mmc/renesas-sdhi.c @@ -20,7 +20,6 @@ #include <linux/sizes.h> #include <power/regulator.h> #include <asm/unaligned.h> - #include "tmio-common.h" #if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) || \ @@ -843,6 +842,7 @@ static const struct udevice_id renesas_sdhi_match[] = { { .compatible = "renesas,sdhi-r8a7794", .data = RENESAS_GEN2_QUIRKS }, { .compatible = "renesas,sdhi-r8a7795", .data = RENESAS_GEN3_QUIRKS }, { .compatible = "renesas,sdhi-r8a7796", .data = RENESAS_GEN3_QUIRKS }, + { .compatible = "renesas,rcar-gen3-sdhi", .data = RENESAS_GEN3_QUIRKS }, { .compatible = "renesas,sdhi-r8a77965", .data = RENESAS_GEN3_QUIRKS }, { .compatible = "renesas,sdhi-r8a77970", .data = RENESAS_GEN3_QUIRKS }, { .compatible = "renesas,sdhi-r8a77990", .data = RENESAS_GEN3_QUIRKS }, diff --git a/drivers/mmc/sdhci-cadence.c b/drivers/mmc/sdhci-cadence.c index 7b5010b655..cc99bebc30 100644 --- a/drivers/mmc/sdhci-cadence.c +++ b/drivers/mmc/sdhci-cadence.c @@ -260,7 +260,7 @@ static int sdhci_cdns_probe(struct udevice *dev) fdt_addr_t base; int ret; - base = devfdt_get_addr(dev); + base = dev_read_addr(dev); if (base == FDT_ADDR_T_NONE) return -EINVAL; diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c index f4eb655f6e..ff871f8252 100644 --- a/drivers/mmc/sdhci.c +++ b/drivers/mmc/sdhci.c @@ -15,7 +15,6 @@ #include <malloc.h> #include <mmc.h> #include <sdhci.h> -#include <dm.h> #include <asm/cache.h> #include <linux/bitops.h> #include <linux/delay.h> diff --git a/drivers/mmc/sh_mmcif.c b/drivers/mmc/sh_mmcif.c index 2e994d0178..ad386909e9 100644 --- a/drivers/mmc/sh_mmcif.c +++ b/drivers/mmc/sh_mmcif.c @@ -680,7 +680,7 @@ static int sh_mmcif_dm_probe(struct udevice *dev) fdt_addr_t base; int ret; - base = devfdt_get_addr(dev); + base = dev_read_addr(dev); if (base == FDT_ADDR_T_NONE) return -EINVAL; diff --git a/drivers/mmc/sh_sdhi.c b/drivers/mmc/sh_sdhi.c index 772fe943e4..315f95cce8 100644 --- a/drivers/mmc/sh_sdhi.c +++ b/drivers/mmc/sh_sdhi.c @@ -834,7 +834,7 @@ static int sh_sdhi_dm_probe(struct udevice *dev) fdt_addr_t base; int ret; - base = devfdt_get_addr(dev); + base = dev_read_addr(dev); if (base == FDT_ADDR_T_NONE) return -EINVAL; diff --git a/drivers/mmc/socfpga_dw_mmc.c b/drivers/mmc/socfpga_dw_mmc.c index 892222d27d..0022f943bd 100644 --- a/drivers/mmc/socfpga_dw_mmc.c +++ b/drivers/mmc/socfpga_dw_mmc.c @@ -109,7 +109,7 @@ static int socfpga_dwmmc_ofdata_to_platdata(struct udevice *dev) } host->name = dev->name; - host->ioaddr = (void *)devfdt_get_addr(dev); + host->ioaddr = dev_read_addr_ptr(dev); host->buswidth = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev), "bus-width", 4); host->clksel = socfpga_dwmci_clksel; diff --git a/drivers/mmc/sti_sdhci.c b/drivers/mmc/sti_sdhci.c index 9bcd8ce5f6..5578feebef 100644 --- a/drivers/mmc/sti_sdhci.c +++ b/drivers/mmc/sti_sdhci.c @@ -116,7 +116,7 @@ static int sti_sdhci_ofdata_to_platdata(struct udevice *dev) struct sdhci_host *host = dev_get_priv(dev); host->name = strdup(dev->name); - host->ioaddr = (void *)devfdt_get_addr(dev); + host->ioaddr = dev_read_addr_ptr(dev); host->bus_width = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev), "bus-width", 4); diff --git a/drivers/mmc/tangier_sdhci.c b/drivers/mmc/tangier_sdhci.c index 0d6e5d6246..879e2c98a2 100644 --- a/drivers/mmc/tangier_sdhci.c +++ b/drivers/mmc/tangier_sdhci.c @@ -35,7 +35,7 @@ static int sdhci_tangier_probe(struct udevice *dev) fdt_addr_t base; int ret; - base = devfdt_get_addr(dev); + base = dev_read_addr(dev); if (base == FDT_ADDR_T_NONE) return -EINVAL; diff --git a/drivers/mmc/tmio-common.c b/drivers/mmc/tmio-common.c index 20cd237ef0..c653973676 100644 --- a/drivers/mmc/tmio-common.c +++ b/drivers/mmc/tmio-common.c @@ -722,7 +722,7 @@ int tmio_sd_probe(struct udevice *dev, u32 quirks) ulong mclk; int ret; - base = devfdt_get_addr(dev); + base = dev_read_addr(dev); if (base == FDT_ADDR_T_NONE) return -EINVAL; diff --git a/drivers/mmc/xenon_sdhci.c b/drivers/mmc/xenon_sdhci.c index e765dd384a..356dd9846d 100644 --- a/drivers/mmc/xenon_sdhci.c +++ b/drivers/mmc/xenon_sdhci.c @@ -455,7 +455,7 @@ static int xenon_sdhci_ofdata_to_platdata(struct udevice *dev) const char *name; host->name = dev->name; - host->ioaddr = (void *)devfdt_get_addr(dev); + host->ioaddr = dev_read_addr_ptr(dev); if (device_is_compatible(dev, "marvell,armada-3700-sdhci")) priv->pad_ctrl_reg = (void *)devfdt_get_addr_index(dev, 1); diff --git a/drivers/mtd/nand/raw/brcmnand/brcmnand_compat.c b/drivers/mtd/nand/raw/brcmnand/brcmnand_compat.c index c58679834e..a6acf556bc 100644 --- a/drivers/mtd/nand/raw/brcmnand/brcmnand_compat.c +++ b/drivers/mtd/nand/raw/brcmnand/brcmnand_compat.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0+ #include <common.h> +#include <dm.h> #include <malloc.h> #include <dm/devres.h> #include "brcmnand_compat.h" diff --git a/drivers/mtd/nand/raw/brcmnand/brcmnand_compat.h b/drivers/mtd/nand/raw/brcmnand/brcmnand_compat.h index 6f9bec7085..52711d4978 100644 --- a/drivers/mtd/nand/raw/brcmnand/brcmnand_compat.h +++ b/drivers/mtd/nand/raw/brcmnand/brcmnand_compat.h @@ -3,8 +3,8 @@ #ifndef __BRCMNAND_COMPAT_H #define __BRCMNAND_COMPAT_H -#include <clk.h> -#include <dm.h> +struct clk; +struct udevice; char *devm_kasprintf(struct udevice *dev, gfp_t gfp, const char *fmt, ...); diff --git a/drivers/mtd/spi/Makefile b/drivers/mtd/spi/Makefile index 952fd1e45a..99cc418552 100644 --- a/drivers/mtd/spi/Makefile +++ b/drivers/mtd/spi/Makefile @@ -8,7 +8,7 @@ spi-nor-y := sf_probe.o spi-nor-ids.o ifdef CONFIG_SPL_BUILD obj-$(CONFIG_SPL_SPI_BOOT) += fsl_espi_spl.o -ifeq ($(CONFIG_SPL_SPI_FLASH_TINY),y) +ifeq ($(CONFIG_$(SPL_TPL_)SPI_FLASH_TINY),y) spi-nor-y += spi-nor-tiny.o else spi-nor-y += spi-nor-core.o diff --git a/drivers/mtd/spi/sf_probe.c b/drivers/mtd/spi/sf_probe.c index 475f6c31db..b959e3453a 100644 --- a/drivers/mtd/spi/sf_probe.c +++ b/drivers/mtd/spi/sf_probe.c @@ -119,7 +119,7 @@ static int spi_flash_std_erase(struct udevice *dev, u32 offset, size_t len) struct erase_info instr; if (offset % mtd->erasesize || len % mtd->erasesize) { - printf("SF: Erase offset/length not multiple of erase size\n"); + debug("SF: Erase offset/length not multiple of erase size\n"); return -EINVAL; } diff --git a/drivers/mtd/spi/spi-nor-core.c b/drivers/mtd/spi/spi-nor-core.c index fdcd830ce4..0113e70037 100644 --- a/drivers/mtd/spi/spi-nor-core.c +++ b/drivers/mtd/spi/spi-nor-core.c @@ -2470,7 +2470,7 @@ static int spi_nor_init(struct spi_nor *nor) * designer) that this is bad. */ if (nor->flags & SNOR_F_BROKEN_RESET) - printf("enabling reset hack; may not recover from unexpected reboots\n"); + debug("enabling reset hack; may not recover from unexpected reboots\n"); set_4byte(nor, nor->info, 1); } diff --git a/drivers/mtd/spi/spi-nor-tiny.c b/drivers/mtd/spi/spi-nor-tiny.c index 9f676c649d..fa26ea33c8 100644 --- a/drivers/mtd/spi/spi-nor-tiny.c +++ b/drivers/mtd/spi/spi-nor-tiny.c @@ -377,7 +377,7 @@ static const struct flash_info *spi_nor_read_id(struct spi_nor *nor) } dev_dbg(nor->dev, "unrecognized JEDEC id bytes: %02x, %02x, %02x\n", id[0], id[1], id[2]); - return ERR_PTR(-ENODEV); + return ERR_PTR(-EMEDIUMTYPE); } static int spi_nor_read(struct mtd_info *mtd, loff_t from, size_t len, @@ -733,7 +733,7 @@ int spi_nor_scan(struct spi_nor *nor) info = spi_nor_read_id(nor); if (IS_ERR_OR_NULL(info)) - return -ENOENT; + return PTR_ERR(info); /* Parse the Serial Flash Discoverable Parameters table. */ ret = spi_nor_init_params(nor, info, ¶ms); if (ret) diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index ec3fb49832..15030b8165 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -491,6 +491,12 @@ config SH_ETHER source "drivers/net/ti/Kconfig" +config TULIP + bool "DEC Tulip DC2114x Ethernet support" + depends on (DM_ETH && DM_PCI) || !DM_ETH + help + This driver supports DEC DC2114x Fast ethernet chips. + config XILINX_AXIEMAC depends on DM_ETH && (MICROBLAZE || ARCH_ZYNQ || ARCH_ZYNQMP) select PHYLIB diff --git a/drivers/net/ag7xxx.c b/drivers/net/ag7xxx.c index 3b5d11f956..ccba3947ac 100644 --- a/drivers/net/ag7xxx.c +++ b/drivers/net/ag7xxx.c @@ -1256,7 +1256,7 @@ static int ag7xxx_eth_ofdata_to_platdata(struct udevice *dev) const char *phy_mode; int ret; - pdata->iobase = devfdt_get_addr(dev); + pdata->iobase = dev_read_addr(dev); pdata->phy_interface = -1; /* Decoding of convoluted PHY wiring on Atheros MIPS. */ diff --git a/drivers/net/dc2114x.c b/drivers/net/dc2114x.c index 0cb54e3214..9f8c6c58d9 100644 --- a/drivers/net/dc2114x.c +++ b/drivers/net/dc2114x.c @@ -1,7 +1,8 @@ // SPDX-License-Identifier: GPL-2.0+ #include <common.h> -#include <env.h> +#include <asm/io.h> +#include <dm.h> #include <malloc.h> #include <net.h> #include <netdev.h> @@ -11,8 +12,6 @@ #define SROM_DLEVEL 0 -#undef UPDATE_SROM - /* PCI Registers. */ #define PCI_CFDA_PSM 0x43 @@ -74,10 +73,12 @@ #define POLL_DEMAND 1 -#if defined(CONFIG_E500) -#define phys_to_bus(a) (a) +#if defined(CONFIG_DM_ETH) +#define phys_to_bus(dev, a) dm_pci_phys_to_mem((dev), (a)) +#elif defined(CONFIG_E500) +#define phys_to_bus(dev, a) (a) #else -#define phys_to_bus(a) pci_phys_to_mem((pci_dev_t)dev->priv, a) +#define phys_to_bus(dev, a) pci_phys_to_mem((dev), (a)) #endif #define NUM_RX_DESC PKTBUFSRX @@ -95,87 +96,97 @@ struct de4x5_desc { u32 next; }; -/* RX and TX descriptor ring */ -static struct de4x5_desc rx_ring[NUM_RX_DESC] __aligned(32); -static struct de4x5_desc tx_ring[NUM_TX_DESC] __aligned(32); -static int rx_new; /* RX descriptor ring pointer */ -static int tx_new; /* TX descriptor ring pointer */ - -static char rx_ring_size; -static char tx_ring_size; +struct dc2114x_priv { + struct de4x5_desc rx_ring[NUM_RX_DESC] __aligned(32); + struct de4x5_desc tx_ring[NUM_TX_DESC] __aligned(32); + int rx_new; /* RX descriptor ring pointer */ + int tx_new; /* TX descriptor ring pointer */ + char rx_ring_size; + char tx_ring_size; +#ifdef CONFIG_DM_ETH + struct udevice *devno; +#else + struct eth_device dev; + pci_dev_t devno; +#endif + char *name; + void __iomem *iobase; + u8 *enetaddr; +}; -static u32 dc2114x_inl(struct eth_device *dev, u32 addr) +/* RX and TX descriptor ring */ +static u32 dc2114x_inl(struct dc2114x_priv *priv, u32 addr) { - return le32_to_cpu(*(volatile u32 *)(addr + dev->iobase)); + return le32_to_cpu(readl(priv->iobase + addr)); } -static void dc2114x_outl(struct eth_device *dev, u32 command, u32 addr) +static void dc2114x_outl(struct dc2114x_priv *priv, u32 command, u32 addr) { - *(volatile u32 *)(addr + dev->iobase) = cpu_to_le32(command); + writel(cpu_to_le32(command), priv->iobase + addr); } -static void reset_de4x5(struct eth_device *dev) +static void reset_de4x5(struct dc2114x_priv *priv) { u32 i; - i = dc2114x_inl(dev, DE4X5_BMR); + i = dc2114x_inl(priv, DE4X5_BMR); mdelay(1); - dc2114x_outl(dev, i | BMR_SWR, DE4X5_BMR); + dc2114x_outl(priv, i | BMR_SWR, DE4X5_BMR); mdelay(1); - dc2114x_outl(dev, i, DE4X5_BMR); + dc2114x_outl(priv, i, DE4X5_BMR); mdelay(1); for (i = 0; i < 5; i++) { - dc2114x_inl(dev, DE4X5_BMR); + dc2114x_inl(priv, DE4X5_BMR); mdelay(10); } mdelay(1); } -static void start_de4x5(struct eth_device *dev) +static void start_de4x5(struct dc2114x_priv *priv) { u32 omr; - omr = dc2114x_inl(dev, DE4X5_OMR); + omr = dc2114x_inl(priv, DE4X5_OMR); omr |= OMR_ST | OMR_SR; - dc2114x_outl(dev, omr, DE4X5_OMR); /* Enable the TX and/or RX */ + dc2114x_outl(priv, omr, DE4X5_OMR); /* Enable the TX and/or RX */ } -static void stop_de4x5(struct eth_device *dev) +static void stop_de4x5(struct dc2114x_priv *priv) { u32 omr; - omr = dc2114x_inl(dev, DE4X5_OMR); + omr = dc2114x_inl(priv, DE4X5_OMR); omr &= ~(OMR_ST | OMR_SR); - dc2114x_outl(dev, omr, DE4X5_OMR); /* Disable the TX and/or RX */ + dc2114x_outl(priv, omr, DE4X5_OMR); /* Disable the TX and/or RX */ } /* SROM Read and write routines. */ -static void sendto_srom(struct eth_device *dev, u_int command, u_long addr) +static void sendto_srom(struct dc2114x_priv *priv, u_int command, u_long addr) { - dc2114x_outl(dev, command, addr); + dc2114x_outl(priv, command, addr); udelay(1); } -static int getfrom_srom(struct eth_device *dev, u_long addr) +static int getfrom_srom(struct dc2114x_priv *priv, u_long addr) { - u32 tmp = dc2114x_inl(dev, addr); + u32 tmp = dc2114x_inl(priv, addr); udelay(1); return tmp; } /* Note: this routine returns extra data bits for size detection. */ -static int do_read_eeprom(struct eth_device *dev, u_long ioaddr, int location, +static int do_read_eeprom(struct dc2114x_priv *priv, u_long ioaddr, int location, int addr_len) { int read_cmd = location | (SROM_READ_CMD << addr_len); unsigned int retval = 0; int i; - sendto_srom(dev, SROM_RD | SROM_SR, ioaddr); - sendto_srom(dev, SROM_RD | SROM_SR | DT_CS, ioaddr); + sendto_srom(priv, SROM_RD | SROM_SR, ioaddr); + sendto_srom(priv, SROM_RD | SROM_SR | DT_CS, ioaddr); debug_cond(SROM_DLEVEL >= 1, " EEPROM read at %d ", location); @@ -183,35 +194,35 @@ static int do_read_eeprom(struct eth_device *dev, u_long ioaddr, int location, for (i = 4 + addr_len; i >= 0; i--) { short dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0; - sendto_srom(dev, SROM_RD | SROM_SR | DT_CS | dataval, + sendto_srom(priv, SROM_RD | SROM_SR | DT_CS | dataval, ioaddr); udelay(10); - sendto_srom(dev, SROM_RD | SROM_SR | DT_CS | dataval | DT_CLK, + sendto_srom(priv, SROM_RD | SROM_SR | DT_CS | dataval | DT_CLK, ioaddr); udelay(10); debug_cond(SROM_DLEVEL >= 2, "%X", - getfrom_srom(dev, ioaddr) & 15); + getfrom_srom(priv, ioaddr) & 15); retval = (retval << 1) | - !!(getfrom_srom(dev, ioaddr) & EE_DATA_READ); + !!(getfrom_srom(priv, ioaddr) & EE_DATA_READ); } - sendto_srom(dev, SROM_RD | SROM_SR | DT_CS, ioaddr); + sendto_srom(priv, SROM_RD | SROM_SR | DT_CS, ioaddr); - debug_cond(SROM_DLEVEL >= 2, " :%X:", getfrom_srom(dev, ioaddr) & 15); + debug_cond(SROM_DLEVEL >= 2, " :%X:", getfrom_srom(priv, ioaddr) & 15); for (i = 16; i > 0; i--) { - sendto_srom(dev, SROM_RD | SROM_SR | DT_CS | DT_CLK, ioaddr); + sendto_srom(priv, SROM_RD | SROM_SR | DT_CS | DT_CLK, ioaddr); udelay(10); debug_cond(SROM_DLEVEL >= 2, "%X", - getfrom_srom(dev, ioaddr) & 15); + getfrom_srom(priv, ioaddr) & 15); retval = (retval << 1) | - !!(getfrom_srom(dev, ioaddr) & EE_DATA_READ); - sendto_srom(dev, SROM_RD | SROM_SR | DT_CS, ioaddr); + !!(getfrom_srom(priv, ioaddr) & EE_DATA_READ); + sendto_srom(priv, SROM_RD | SROM_SR | DT_CS, ioaddr); udelay(10); } /* Terminate the EEPROM access. */ - sendto_srom(dev, SROM_RD | SROM_SR, ioaddr); + sendto_srom(priv, SROM_RD | SROM_SR, ioaddr); debug_cond(SROM_DLEVEL >= 2, " EEPROM value at %d is %5.5x.\n", location, retval); @@ -224,139 +235,53 @@ static int do_read_eeprom(struct eth_device *dev, u_long ioaddr, int location, * enable. It returns the data output from the EEPROM, and thus may * also be used for reads. */ -static int do_eeprom_cmd(struct eth_device *dev, u_long ioaddr, int cmd, +static int do_eeprom_cmd(struct dc2114x_priv *priv, u_long ioaddr, int cmd, int cmd_len) { unsigned int retval = 0; debug_cond(SROM_DLEVEL >= 1, " EEPROM op 0x%x: ", cmd); - sendto_srom(dev, SROM_RD | SROM_SR | DT_CS | DT_CLK, ioaddr); + sendto_srom(priv, SROM_RD | SROM_SR | DT_CS | DT_CLK, ioaddr); /* Shift the command bits out. */ do { short dataval = (cmd & BIT(cmd_len)) ? EE_WRITE_1 : EE_WRITE_0; - sendto_srom(dev, dataval, ioaddr); + sendto_srom(priv, dataval, ioaddr); udelay(10); debug_cond(SROM_DLEVEL >= 2, "%X", - getfrom_srom(dev, ioaddr) & 15); + getfrom_srom(priv, ioaddr) & 15); - sendto_srom(dev, dataval | DT_CLK, ioaddr); + sendto_srom(priv, dataval | DT_CLK, ioaddr); udelay(10); retval = (retval << 1) | - !!(getfrom_srom(dev, ioaddr) & EE_DATA_READ); + !!(getfrom_srom(priv, ioaddr) & EE_DATA_READ); } while (--cmd_len >= 0); - sendto_srom(dev, SROM_RD | SROM_SR | DT_CS, ioaddr); + sendto_srom(priv, SROM_RD | SROM_SR | DT_CS, ioaddr); /* Terminate the EEPROM access. */ - sendto_srom(dev, SROM_RD | SROM_SR, ioaddr); + sendto_srom(priv, SROM_RD | SROM_SR, ioaddr); debug_cond(SROM_DLEVEL >= 1, " EEPROM result is 0x%5.5x.\n", retval); return retval; } -static int read_srom(struct eth_device *dev, u_long ioaddr, int index) +static int read_srom(struct dc2114x_priv *priv, u_long ioaddr, int index) { int ee_addr_size; - ee_addr_size = (do_read_eeprom(dev, ioaddr, 0xff, 8) & BIT(18)) ? 8 : 6; + ee_addr_size = (do_read_eeprom(priv, ioaddr, 0xff, 8) & BIT(18)) ? 8 : 6; - return do_eeprom_cmd(dev, ioaddr, 0xffff | + return do_eeprom_cmd(priv, ioaddr, 0xffff | (((SROM_READ_CMD << ee_addr_size) | index) << 16), 3 + ee_addr_size + 16); } -#ifdef UPDATE_SROM -static int write_srom(struct eth_device *dev, u_long ioaddr, int index, - int new_value) -{ - unsigned short newval; - int ee_addr_size; - int i; - - ee_addr_size = (do_read_eeprom(dev, ioaddr, 0xff, 8) & BIT(18)) ? 8 : 6; - - udelay(10 * 1000); /* test-only */ - - debug_cond(SROM_DLEVEL >= 1, "ee_addr_size=%d.\n", ee_addr_size); - debug_cond(SROM_DLEVEL >= 1, - "Writing new entry 0x%4.4x to offset %d.\n", - new_value, index); - - /* Enable programming modes. */ - do_eeprom_cmd(dev, ioaddr, 0x4f << (ee_addr_size - 4), - 3 + ee_addr_size); - - /* Do the actual write. */ - do_eeprom_cmd(dev, ioaddr, new_value | - (((SROM_WRITE_CMD << ee_addr_size) | index) << 16), - 3 + ee_addr_size + 16); - - /* Poll for write finished. */ - sendto_srom(dev, SROM_RD | SROM_SR | DT_CS, ioaddr); - for (i = 0; i < 10000; i++) { /* Typical 2000 ticks */ - if (getfrom_srom(dev, ioaddr) & EE_DATA_READ) - break; - } - - debug_cond(SROM_DLEVEL >= 1, " Write finished after %d ticks.\n", i); - - /* Disable programming. */ - do_eeprom_cmd(dev, ioaddr, (0x40 << (ee_addr_size - 4)), - 3 + ee_addr_size); - - /* And read the result. */ - newval = do_eeprom_cmd(dev, ioaddr, - (((SROM_READ_CMD << ee_addr_size) | index) << 16) - | 0xffff, 3 + ee_addr_size + 16); - - debug_cond(SROM_DLEVEL >= 1, " New value at offset %d is %4.4x.\n", - index, newval); - - return 1; -} - -static void update_srom(struct eth_device *dev, struct bd_info *bis) -{ - static unsigned short eeprom[0x40] = { - 0x140b, 0x6610, 0x0000, 0x0000, /* 00 */ - 0x0000, 0x0000, 0x0000, 0x0000, /* 04 */ - 0x00a3, 0x0103, 0x0000, 0x0000, /* 08 */ - 0x0000, 0x1f00, 0x0000, 0x0000, /* 0c */ - 0x0108, 0x038d, 0x0000, 0x0000, /* 10 */ - 0xe078, 0x0001, 0x0040, 0x0018, /* 14 */ - 0x0000, 0x0000, 0x0000, 0x0000, /* 18 */ - 0x0000, 0x0000, 0x0000, 0x0000, /* 1c */ - 0x0000, 0x0000, 0x0000, 0x0000, /* 20 */ - 0x0000, 0x0000, 0x0000, 0x0000, /* 24 */ - 0x0000, 0x0000, 0x0000, 0x0000, /* 28 */ - 0x0000, 0x0000, 0x0000, 0x0000, /* 2c */ - 0x0000, 0x0000, 0x0000, 0x0000, /* 30 */ - 0x0000, 0x0000, 0x0000, 0x0000, /* 34 */ - 0x0000, 0x0000, 0x0000, 0x0000, /* 38 */ - 0x0000, 0x0000, 0x0000, 0x4e07, /* 3c */ - }; - uchar enetaddr[6]; - int i; - - /* Ethernet Addr... */ - if (!eth_env_get_enetaddr("ethaddr", enetaddr)) - return; - - eeprom[0x0a] = (enetaddr[1] << 8) | enetaddr[0]; - eeprom[0x0b] = (enetaddr[3] << 8) | enetaddr[2]; - eeprom[0x0c] = (enetaddr[5] << 8) | enetaddr[4]; - - for (i = 0; i < 0x40; i++) - write_srom(dev, DE4X5_APROM, i, eeprom[i]); -} -#endif /* UPDATE_SROM */ - -static void send_setup_frame(struct eth_device *dev, struct bd_info *bis) +static void send_setup_frame(struct dc2114x_priv *priv) { char setup_frame[SETUP_FRAME_LEN]; char *pa = &setup_frame[0]; @@ -365,223 +290,267 @@ static void send_setup_frame(struct eth_device *dev, struct bd_info *bis) memset(pa, 0xff, SETUP_FRAME_LEN); for (i = 0; i < ETH_ALEN; i++) { - *(pa + (i & 1)) = dev->enetaddr[i]; + *(pa + (i & 1)) = priv->enetaddr[i]; if (i & 0x01) pa += 4; } - for (i = 0; tx_ring[tx_new].status & cpu_to_le32(T_OWN); i++) { + for (i = 0; priv->tx_ring[priv->tx_new].status & cpu_to_le32(T_OWN); i++) { if (i < TOUT_LOOP) continue; - printf("%s: tx error buffer not ready\n", dev->name); + printf("%s: tx error buffer not ready\n", priv->name); return; } - tx_ring[tx_new].buf = cpu_to_le32(phys_to_bus((u32)&setup_frame[0])); - tx_ring[tx_new].des1 = cpu_to_le32(TD_TER | TD_SET | SETUP_FRAME_LEN); - tx_ring[tx_new].status = cpu_to_le32(T_OWN); + priv->tx_ring[priv->tx_new].buf = cpu_to_le32(phys_to_bus(priv->devno, + (u32)&setup_frame[0])); + priv->tx_ring[priv->tx_new].des1 = cpu_to_le32(TD_TER | TD_SET | SETUP_FRAME_LEN); + priv->tx_ring[priv->tx_new].status = cpu_to_le32(T_OWN); - dc2114x_outl(dev, POLL_DEMAND, DE4X5_TPD); + dc2114x_outl(priv, POLL_DEMAND, DE4X5_TPD); - for (i = 0; tx_ring[tx_new].status & cpu_to_le32(T_OWN); i++) { + for (i = 0; priv->tx_ring[priv->tx_new].status & cpu_to_le32(T_OWN); i++) { if (i < TOUT_LOOP) continue; - printf("%s: tx buffer not ready\n", dev->name); + printf("%s: tx buffer not ready\n", priv->name); return; } - if (le32_to_cpu(tx_ring[tx_new].status) != 0x7FFFFFFF) { + if (le32_to_cpu(priv->tx_ring[priv->tx_new].status) != 0x7FFFFFFF) { printf("TX error status2 = 0x%08X\n", - le32_to_cpu(tx_ring[tx_new].status)); + le32_to_cpu(priv->tx_ring[priv->tx_new].status)); } - tx_new = (tx_new + 1) % NUM_TX_DESC; + priv->tx_new = (priv->tx_new + 1) % NUM_TX_DESC; } -static int dc21x4x_send(struct eth_device *dev, void *packet, int length) +static int dc21x4x_send_common(struct dc2114x_priv *priv, void *packet, int length) { int status = -1; int i; if (length <= 0) { - printf("%s: bad packet size: %d\n", dev->name, length); + printf("%s: bad packet size: %d\n", priv->name, length); goto done; } - for (i = 0; tx_ring[tx_new].status & cpu_to_le32(T_OWN); i++) { + for (i = 0; priv->tx_ring[priv->tx_new].status & cpu_to_le32(T_OWN); i++) { if (i < TOUT_LOOP) continue; - printf("%s: tx error buffer not ready\n", dev->name); + printf("%s: tx error buffer not ready\n", priv->name); goto done; } - tx_ring[tx_new].buf = cpu_to_le32(phys_to_bus((u32)packet)); - tx_ring[tx_new].des1 = cpu_to_le32(TD_TER | TD_LS | TD_FS | length); - tx_ring[tx_new].status = cpu_to_le32(T_OWN); + priv->tx_ring[priv->tx_new].buf = cpu_to_le32(phys_to_bus(priv->devno, + (u32)packet)); + priv->tx_ring[priv->tx_new].des1 = cpu_to_le32(TD_TER | TD_LS | TD_FS | length); + priv->tx_ring[priv->tx_new].status = cpu_to_le32(T_OWN); - dc2114x_outl(dev, POLL_DEMAND, DE4X5_TPD); + dc2114x_outl(priv, POLL_DEMAND, DE4X5_TPD); - for (i = 0; tx_ring[tx_new].status & cpu_to_le32(T_OWN); i++) { + for (i = 0; priv->tx_ring[priv->tx_new].status & cpu_to_le32(T_OWN); i++) { if (i < TOUT_LOOP) continue; - printf(".%s: tx buffer not ready\n", dev->name); + printf(".%s: tx buffer not ready\n", priv->name); goto done; } - if (le32_to_cpu(tx_ring[tx_new].status) & TD_ES) { - tx_ring[tx_new].status = 0x0; + if (le32_to_cpu(priv->tx_ring[priv->tx_new].status) & TD_ES) { + priv->tx_ring[priv->tx_new].status = 0x0; goto done; } status = length; done: - tx_new = (tx_new + 1) % NUM_TX_DESC; + priv->tx_new = (priv->tx_new + 1) % NUM_TX_DESC; return status; } -static int dc21x4x_recv(struct eth_device *dev) +static int dc21x4x_recv_check(struct dc2114x_priv *priv) { int length = 0; u32 status; - while (true) { - status = le32_to_cpu(rx_ring[rx_new].status); + status = le32_to_cpu(priv->rx_ring[priv->rx_new].status); - if (status & R_OWN) - break; + if (status & R_OWN) + return 0; - if (status & RD_LS) { - /* Valid frame status. */ - if (status & RD_ES) { - /* There was an error. */ - printf("RX error status = 0x%08X\n", status); - } else { - /* A valid frame received. */ - length = (le32_to_cpu(rx_ring[rx_new].status) - >> 16); - - /* Pass the packet up to the protocol layers */ - net_process_received_packet - (net_rx_packets[rx_new], length - 4); - } - - /* - * Change buffer ownership for this frame, - * back to the adapter. - */ - rx_ring[rx_new].status = cpu_to_le32(R_OWN); - } + if (status & RD_LS) { + /* Valid frame status. */ + if (status & RD_ES) { + /* There was an error. */ + printf("RX error status = 0x%08X\n", status); + return -EINVAL; + } else { + /* A valid frame received. */ + length = (le32_to_cpu(priv->rx_ring[priv->rx_new].status) + >> 16); - /* Update entry information. */ - rx_new = (rx_new + 1) % rx_ring_size; + return length; + } } - return length; + return -EAGAIN; } -static int dc21x4x_init(struct eth_device *dev, struct bd_info *bis) +static int dc21x4x_init_common(struct dc2114x_priv *priv) { int i; - int devbusfn = (int)dev->priv; - - /* Ensure we're not sleeping. */ - pci_write_config_byte(devbusfn, PCI_CFDA_PSM, WAKEUP); - reset_de4x5(dev); + reset_de4x5(priv); - if (dc2114x_inl(dev, DE4X5_STS) & (STS_TS | STS_RS)) { + if (dc2114x_inl(priv, DE4X5_STS) & (STS_TS | STS_RS)) { printf("Error: Cannot reset ethernet controller.\n"); return -1; } - dc2114x_outl(dev, OMR_SDP | OMR_PS | OMR_PM, DE4X5_OMR); + dc2114x_outl(priv, OMR_SDP | OMR_PS | OMR_PM, DE4X5_OMR); for (i = 0; i < NUM_RX_DESC; i++) { - rx_ring[i].status = cpu_to_le32(R_OWN); - rx_ring[i].des1 = cpu_to_le32(RX_BUFF_SZ); - rx_ring[i].buf = - cpu_to_le32(phys_to_bus((u32)net_rx_packets[i])); - rx_ring[i].next = 0; + priv->rx_ring[i].status = cpu_to_le32(R_OWN); + priv->rx_ring[i].des1 = cpu_to_le32(RX_BUFF_SZ); + priv->rx_ring[i].buf = cpu_to_le32(phys_to_bus(priv->devno, + (u32)net_rx_packets[i])); + priv->rx_ring[i].next = 0; } for (i = 0; i < NUM_TX_DESC; i++) { - tx_ring[i].status = 0; - tx_ring[i].des1 = 0; - tx_ring[i].buf = 0; - tx_ring[i].next = 0; + priv->tx_ring[i].status = 0; + priv->tx_ring[i].des1 = 0; + priv->tx_ring[i].buf = 0; + priv->tx_ring[i].next = 0; } - rx_ring_size = NUM_RX_DESC; - tx_ring_size = NUM_TX_DESC; + priv->rx_ring_size = NUM_RX_DESC; + priv->tx_ring_size = NUM_TX_DESC; /* Write the end of list marker to the descriptor lists. */ - rx_ring[rx_ring_size - 1].des1 |= cpu_to_le32(RD_RER); - tx_ring[tx_ring_size - 1].des1 |= cpu_to_le32(TD_TER); + priv->rx_ring[priv->rx_ring_size - 1].des1 |= cpu_to_le32(RD_RER); + priv->tx_ring[priv->tx_ring_size - 1].des1 |= cpu_to_le32(TD_TER); /* Tell the adapter where the TX/RX rings are located. */ - dc2114x_outl(dev, phys_to_bus((u32)&rx_ring), DE4X5_RRBA); - dc2114x_outl(dev, phys_to_bus((u32)&tx_ring), DE4X5_TRBA); + dc2114x_outl(priv, phys_to_bus(priv->devno, (u32)&priv->rx_ring), + DE4X5_RRBA); + dc2114x_outl(priv, phys_to_bus(priv->devno, (u32)&priv->tx_ring), + DE4X5_TRBA); - start_de4x5(dev); + start_de4x5(priv); - tx_new = 0; - rx_new = 0; + priv->tx_new = 0; + priv->rx_new = 0; - send_setup_frame(dev, bis); + send_setup_frame(priv); return 0; } -static void dc21x4x_halt(struct eth_device *dev) +static void dc21x4x_halt_common(struct dc2114x_priv *priv) { - int devbusfn = (int)dev->priv; - - stop_de4x5(dev); - dc2114x_outl(dev, 0, DE4X5_SICR); - - pci_write_config_byte(devbusfn, PCI_CFDA_PSM, SLEEP); + stop_de4x5(priv); + dc2114x_outl(priv, 0, DE4X5_SICR); } -static void read_hw_addr(struct eth_device *dev, struct bd_info *bis) +static void read_hw_addr(struct dc2114x_priv *priv) { - u_short tmp, *p = (u_short *)(&dev->enetaddr[0]); + u_short tmp, *p = (u_short *)(&priv->enetaddr[0]); int i, j = 0; for (i = 0; i < (ETH_ALEN >> 1); i++) { - tmp = read_srom(dev, DE4X5_APROM, (SROM_HWADD >> 1) + i); + tmp = read_srom(priv, DE4X5_APROM, (SROM_HWADD >> 1) + i); *p = le16_to_cpu(tmp); j += *p++; } if (!j || j == 0x2fffd) { - memset(dev->enetaddr, 0, ETH_ALEN); + memset(priv->enetaddr, 0, ETH_ALEN); debug("Warning: can't read HW address from SROM.\n"); -#ifdef UPDATE_SROM - update_srom(dev, bis); -#endif } } static struct pci_device_id supported[] = { - { PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TULIP_FAST }, - { PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_21142 }, + { PCI_DEVICE(PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TULIP_FAST) }, + { PCI_DEVICE(PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_21142) }, { } }; +#ifndef CONFIG_DM_ETH +static int dc21x4x_init(struct eth_device *dev, struct bd_info *bis) +{ + struct dc2114x_priv *priv = + container_of(dev, struct dc2114x_priv, dev); + + /* Ensure we're not sleeping. */ + pci_write_config_byte(priv->devno, PCI_CFDA_PSM, WAKEUP); + + return dc21x4x_init_common(priv); +} + +static void dc21x4x_halt(struct eth_device *dev) +{ + struct dc2114x_priv *priv = + container_of(dev, struct dc2114x_priv, dev); + + dc21x4x_halt_common(priv); + + pci_write_config_byte(priv->devno, PCI_CFDA_PSM, SLEEP); +} + +static int dc21x4x_send(struct eth_device *dev, void *packet, int length) +{ + struct dc2114x_priv *priv = + container_of(dev, struct dc2114x_priv, dev); + + return dc21x4x_send_common(priv, packet, length); +} + +static int dc21x4x_recv(struct eth_device *dev) +{ + struct dc2114x_priv *priv = + container_of(dev, struct dc2114x_priv, dev); + int length = 0; + int ret; + + while (true) { + ret = dc21x4x_recv_check(priv); + if (!ret) + break; + + if (ret > 0) { + length = ret; + /* Pass the packet up to the protocol layers */ + net_process_received_packet + (net_rx_packets[priv->rx_new], length - 4); + } + + /* + * Change buffer ownership for this frame, + * back to the adapter. + */ + if (ret != -EAGAIN) + priv->rx_ring[priv->rx_new].status = cpu_to_le32(R_OWN); + + /* Update entry information. */ + priv->rx_new = (priv->rx_new + 1) % priv->rx_ring_size; + } + + return length; +} + int dc21x4x_initialize(struct bd_info *bis) { + struct dc2114x_priv *priv; struct eth_device *dev; unsigned short status; unsigned char timer; unsigned int iobase; int card_number = 0; pci_dev_t devbusfn; - unsigned int cfrv; int idx = 0; while (1) { @@ -589,14 +558,6 @@ int dc21x4x_initialize(struct bd_info *bis) if (devbusfn == -1) break; - /* Get the chip configuration revision register. */ - pci_read_config_dword(devbusfn, PCI_REVISION_ID, &cfrv); - - if ((cfrv & CFRV_RN) < DC2114x_BRK) { - printf("Error: The chip is not DC21143.\n"); - continue; - } - pci_read_config_word(devbusfn, PCI_COMMAND, &status); status |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER; pci_write_config_word(devbusfn, PCI_COMMAND, status); @@ -625,15 +586,19 @@ int dc21x4x_initialize(struct bd_info *bis) iobase &= PCI_BASE_ADDRESS_MEM_MASK; debug("dc21x4x: DEC 21142 PCI Device @0x%x\n", iobase); - dev = (struct eth_device *)malloc(sizeof(*dev)); - if (!dev) { + priv = memalign(32, sizeof(*priv)); + if (!priv) { printf("Can not allocalte memory of dc21x4x\n"); break; } + memset(priv, 0, sizeof(*priv)); - memset(dev, 0, sizeof(*dev)); + dev = &priv->dev; sprintf(dev->name, "dc21x4x#%d", card_number); + priv->devno = devbusfn; + priv->name = dev->name; + priv->enetaddr = dev->enetaddr; dev->iobase = pci_mem_to_phys(devbusfn, iobase); dev->priv = (void *)devbusfn; @@ -647,7 +612,7 @@ int dc21x4x_initialize(struct bd_info *bis) udelay(10 * 1000); - read_hw_addr(dev, bis); + read_hw_addr(priv); eth_register(dev); @@ -656,3 +621,139 @@ int dc21x4x_initialize(struct bd_info *bis) return card_number; } + +#else /* DM_ETH */ +static int dc2114x_start(struct udevice *dev) +{ + struct eth_pdata *plat = dev_get_platdata(dev); + struct dc2114x_priv *priv = dev_get_priv(dev); + + memcpy(priv->enetaddr, plat->enetaddr, sizeof(plat->enetaddr)); + + /* Ensure we're not sleeping. */ + dm_pci_write_config8(dev, PCI_CFDA_PSM, WAKEUP); + + return dc21x4x_init_common(priv); +} + +static void dc2114x_stop(struct udevice *dev) +{ + struct dc2114x_priv *priv = dev_get_priv(dev); + + dc21x4x_halt_common(priv); + + dm_pci_write_config8(dev, PCI_CFDA_PSM, SLEEP); +} + +static int dc2114x_send(struct udevice *dev, void *packet, int length) +{ + struct dc2114x_priv *priv = dev_get_priv(dev); + int ret; + + ret = dc21x4x_send_common(priv, packet, length); + + return ret ? 0 : -ETIMEDOUT; +} + +static int dc2114x_recv(struct udevice *dev, int flags, uchar **packetp) +{ + struct dc2114x_priv *priv = dev_get_priv(dev); + int ret; + + ret = dc21x4x_recv_check(priv); + + if (ret < 0) { + /* Update entry information. */ + priv->rx_new = (priv->rx_new + 1) % priv->rx_ring_size; + ret = 0; + } + + if (!ret) + return 0; + + *packetp = net_rx_packets[priv->rx_new]; + + return ret - 4; +} + +static int dc2114x_free_pkt(struct udevice *dev, uchar *packet, int length) +{ + struct dc2114x_priv *priv = dev_get_priv(dev); + + priv->rx_ring[priv->rx_new].status = cpu_to_le32(R_OWN); + + /* Update entry information. */ + priv->rx_new = (priv->rx_new + 1) % priv->rx_ring_size; + + return 0; +} + +static int dc2114x_read_rom_hwaddr(struct udevice *dev) +{ + struct dc2114x_priv *priv = dev_get_priv(dev); + + read_hw_addr(priv); + + return 0; +} + +static int dc2114x_bind(struct udevice *dev) +{ + static int card_number; + char name[16]; + + sprintf(name, "dc2114x#%u", card_number++); + + return device_set_name(dev, name); +} + +static int dc2114x_probe(struct udevice *dev) +{ + struct eth_pdata *plat = dev_get_platdata(dev); + struct dc2114x_priv *priv = dev_get_priv(dev); + u16 command, status; + u32 iobase; + + dm_pci_read_config32(dev, PCI_BASE_ADDRESS_1, &iobase); + iobase &= ~0xf; + + debug("dc2114x: DEC 2114x PCI Device @0x%x\n", iobase); + + priv->devno = dev; + priv->enetaddr = plat->enetaddr; + priv->iobase = (void __iomem *)dm_pci_mem_to_phys(dev, iobase); + + command = PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER; + dm_pci_write_config16(dev, PCI_COMMAND, command); + dm_pci_read_config16(dev, PCI_COMMAND, &status); + if ((status & command) != command) { + printf("dc2114x: Couldn't enable IO access or Bus Mastering\n"); + return -EINVAL; + } + + dm_pci_write_config8(dev, PCI_LATENCY_TIMER, 0x60); + + return 0; +} + +static const struct eth_ops dc2114x_ops = { + .start = dc2114x_start, + .send = dc2114x_send, + .recv = dc2114x_recv, + .stop = dc2114x_stop, + .free_pkt = dc2114x_free_pkt, + .read_rom_hwaddr = dc2114x_read_rom_hwaddr, +}; + +U_BOOT_DRIVER(eth_dc2114x) = { + .name = "eth_dc2114x", + .id = UCLASS_ETH, + .bind = dc2114x_bind, + .probe = dc2114x_probe, + .ops = &dc2114x_ops, + .priv_auto_alloc_size = sizeof(struct dc2114x_priv), + .platdata_auto_alloc_size = sizeof(struct eth_pdata), +}; + +U_BOOT_PCI_DEVICE(eth_dc2114x, supported); +#endif diff --git a/drivers/net/dwc_eth_qos.c b/drivers/net/dwc_eth_qos.c index 62941bb175..1d9eefbb3e 100644 --- a/drivers/net/dwc_eth_qos.c +++ b/drivers/net/dwc_eth_qos.c @@ -1995,9 +1995,9 @@ static int eqos_probe(struct udevice *dev) eqos->dev = dev; eqos->config = (void *)dev_get_driver_data(dev); - eqos->regs = devfdt_get_addr(dev); + eqos->regs = dev_read_addr(dev); if (eqos->regs == FDT_ADDR_T_NONE) { - pr_err("devfdt_get_addr() failed"); + pr_err("dev_read_addr() failed"); return -ENODEV; } eqos->mac_regs = (void *)(eqos->regs + EQOS_MAC_REGS_BASE); diff --git a/drivers/net/ethoc.c b/drivers/net/ethoc.c index fd589a0764..b9d80a5b08 100644 --- a/drivers/net/ethoc.c +++ b/drivers/net/ethoc.c @@ -690,7 +690,7 @@ static int ethoc_ofdata_to_platdata(struct udevice *dev) struct ethoc_eth_pdata *pdata = dev_get_platdata(dev); fdt_addr_t addr; - pdata->eth_pdata.iobase = devfdt_get_addr(dev); + pdata->eth_pdata.iobase = dev_read_addr(dev); addr = devfdt_get_addr_index(dev, 1); if (addr != FDT_ADDR_T_NONE) pdata->packet_base = addr; diff --git a/drivers/net/fec_mxc.c b/drivers/net/fec_mxc.c index b3d4acb106..bb55be9a26 100644 --- a/drivers/net/fec_mxc.c +++ b/drivers/net/fec_mxc.c @@ -1534,7 +1534,7 @@ static int fecmxc_ofdata_to_platdata(struct udevice *dev) struct fec_priv *priv = dev_get_priv(dev); const char *phy_mode; - pdata->iobase = (phys_addr_t)devfdt_get_addr(dev); + pdata->iobase = dev_read_addr(dev); priv->eth = (struct ethernet_regs *)pdata->iobase; pdata->phy_interface = -1; diff --git a/drivers/net/fsl_mcdmafec.c b/drivers/net/fsl_mcdmafec.c index f33529cb67..e27f7e5321 100644 --- a/drivers/net/fsl_mcdmafec.c +++ b/drivers/net/fsl_mcdmafec.c @@ -570,7 +570,7 @@ static int mcdmafec_ofdata_to_platdata(struct udevice *dev) struct eth_pdata *pdata = dev_get_platdata(dev); const u32 *val; - pdata->iobase = (phys_addr_t)devfdt_get_addr(dev); + pdata->iobase = dev_read_addr(dev); /* Default to 10Mbit/s */ pdata->max_speed = 10; diff --git a/drivers/net/ftgmac100.c b/drivers/net/ftgmac100.c index e4d08f2ba0..5676a5b3ba 100644 --- a/drivers/net/ftgmac100.c +++ b/drivers/net/ftgmac100.c @@ -517,7 +517,7 @@ static int ftgmac100_ofdata_to_platdata(struct udevice *dev) struct ftgmac100_data *priv = dev_get_priv(dev); const char *phy_mode; - pdata->iobase = devfdt_get_addr(dev); + pdata->iobase = dev_read_addr(dev); pdata->phy_interface = -1; phy_mode = dev_read_string(dev, "phy-mode"); if (phy_mode) diff --git a/drivers/net/ftmac100.c b/drivers/net/ftmac100.c index 79c64ec89a..292690de96 100644 --- a/drivers/net/ftmac100.c +++ b/drivers/net/ftmac100.c @@ -398,7 +398,7 @@ static int ftmac100_ofdata_to_platdata(struct udevice *dev) struct ftmac100_data *priv = dev_get_priv(dev); struct eth_pdata *pdata = dev_get_platdata(dev); const char *mac; - pdata->iobase = devfdt_get_addr(dev); + pdata->iobase = dev_read_addr(dev); priv->iobase = pdata->iobase; mac = dtbmacaddr(0); if (mac) diff --git a/drivers/net/ks8851_mll.c b/drivers/net/ks8851_mll.c index 1773c7671f..d22668446d 100644 --- a/drivers/net/ks8851_mll.c +++ b/drivers/net/ks8851_mll.c @@ -642,7 +642,7 @@ static int ks8851_ofdata_to_platdata(struct udevice *dev) struct ks_net *ks = dev_get_priv(dev); struct eth_pdata *pdata = dev_get_platdata(dev); - pdata->iobase = devfdt_get_addr(dev); + pdata->iobase = dev_read_addr(dev); ks->iobase = pdata->iobase; return 0; diff --git a/drivers/net/mcffec.c b/drivers/net/mcffec.c index 1a8351be1c..f94a2d8123 100644 --- a/drivers/net/mcffec.c +++ b/drivers/net/mcffec.c @@ -589,7 +589,7 @@ static int mcffec_ofdata_to_platdata(struct udevice *dev) struct eth_pdata *pdata = dev_get_platdata(dev); const u32 *val; - pdata->iobase = (phys_addr_t)devfdt_get_addr(dev); + pdata->iobase = dev_read_addr(dev); /* Default to 10Mbit/s */ pdata->max_speed = 10; diff --git a/drivers/net/mtk_eth.c b/drivers/net/mtk_eth.c index 86f1360ae3..5183c08e14 100644 --- a/drivers/net/mtk_eth.c +++ b/drivers/net/mtk_eth.c @@ -1094,7 +1094,8 @@ static int mtk_phy_probe(struct udevice *dev) static void mtk_sgmii_init(struct mtk_eth_priv *priv) { /* Set SGMII GEN2 speed(2.5G) */ - clrsetbits_le32(priv->sgmii_base + SGMSYS_GEN2_SPEED, + clrsetbits_le32(priv->sgmii_base + ((priv->soc == SOC_MT7622) ? + SGMSYS_GEN2_SPEED : SGMSYS_GEN2_SPEED_V2), SGMSYS_SPEED_2500, SGMSYS_SPEED_2500); /* Disable SGMII AN */ @@ -1418,7 +1419,7 @@ static int mtk_eth_ofdata_to_platdata(struct udevice *dev) priv->soc = dev_get_driver_data(dev); - pdata->iobase = devfdt_get_addr(dev); + pdata->iobase = dev_read_addr(dev); /* get corresponding ethsys phandle */ ret = dev_read_phandle_with_args(dev, "mediatek,ethsys", NULL, 0, 0, diff --git a/drivers/net/mtk_eth.h b/drivers/net/mtk_eth.h index be74ac27ea..057ecfaabf 100644 --- a/drivers/net/mtk_eth.h +++ b/drivers/net/mtk_eth.h @@ -46,6 +46,7 @@ #define SGMII_PHYA_PWD BIT(4) #define SGMSYS_GEN2_SPEED 0x2028 +#define SGMSYS_GEN2_SPEED_V2 0x128 #define SGMSYS_SPEED_2500 BIT(2) /* Frame Engine Registers */ diff --git a/drivers/net/mvgbe.c b/drivers/net/mvgbe.c index 86b1b8cee5..2f9464b961 100644 --- a/drivers/net/mvgbe.c +++ b/drivers/net/mvgbe.c @@ -997,7 +997,7 @@ static int mvgbe_ofdata_to_platdata(struct udevice *dev) int pnode; unsigned long addr; - pdata->iobase = devfdt_get_addr(dev); + pdata->iobase = dev_read_addr(dev); pdata->phy_interface = -1; pnode = fdt_node_offset_by_compatible(blob, node, diff --git a/drivers/net/mvneta.c b/drivers/net/mvneta.c index 092f619bd5..4c7d06ca40 100644 --- a/drivers/net/mvneta.c +++ b/drivers/net/mvneta.c @@ -1796,7 +1796,7 @@ static int mvneta_ofdata_to_platdata(struct udevice *dev) struct eth_pdata *pdata = dev_get_platdata(dev); const char *phy_mode; - pdata->iobase = devfdt_get_addr(dev); + pdata->iobase = dev_read_addr(dev); /* Get phy-mode / phy_interface from DT */ pdata->phy_interface = -1; diff --git a/drivers/net/pcnet.c b/drivers/net/pcnet.c index 559560860b..ad5ac6618f 100644 --- a/drivers/net/pcnet.c +++ b/drivers/net/pcnet.c @@ -10,7 +10,6 @@ #include <cpu_func.h> #include <dm.h> #include <log.h> -#include <dm.h> #include <malloc.h> #include <memalign.h> #include <net.h> diff --git a/drivers/net/pfe_eth/pfe_eth.c b/drivers/net/pfe_eth/pfe_eth.c index 718e24f14d..e49bf4a6f3 100644 --- a/drivers/net/pfe_eth/pfe_eth.c +++ b/drivers/net/pfe_eth/pfe_eth.c @@ -33,7 +33,7 @@ struct gemac_s gem_info[] = { /* phy iface */ .phy_address = CONFIG_PFE_EMAC2_PHY_ADDR, - .phy_mode = PHY_INTERFACE_MODE_RGMII_TXID, + .phy_mode = PHY_INTERFACE_MODE_RGMII_ID, }, }; diff --git a/drivers/net/pfe_eth/pfe_firmware.c b/drivers/net/pfe_eth/pfe_firmware.c index 0493cfe872..55e661c0e1 100644 --- a/drivers/net/pfe_eth/pfe_firmware.c +++ b/drivers/net/pfe_eth/pfe_firmware.c @@ -16,13 +16,14 @@ #include <linux/bitops.h> #include <net/pfe_eth/pfe_eth.h> #include <net/pfe_eth/pfe_firmware.h> +#include <spi_flash.h> #ifdef CONFIG_CHAIN_OF_TRUST #include <fsl_validate.h> #endif #define PFE_FIRMWARE_FIT_CNF_NAME "config@1" -static const void *pfe_fit_addr = (void *)CONFIG_SYS_LS_PFE_FW_ADDR; +static const void *pfe_fit_addr; /* * PFE elf firmware loader. @@ -163,6 +164,44 @@ static int pfe_fit_check(void) return ret; } +int pfe_spi_flash_init(void) +{ + struct spi_flash *pfe_flash; + int ret = 0; + void *addr = malloc(CONFIG_SYS_QE_FMAN_FW_LENGTH); + +#ifdef CONFIG_DM_SPI_FLASH + struct udevice *new; + + /* speed and mode will be read from DT */ + ret = spi_flash_probe_bus_cs(CONFIG_ENV_SPI_BUS, + CONFIG_ENV_SPI_CS, 0, 0, &new); + + pfe_flash = dev_get_uclass_priv(new); +#else + pfe_flash = spi_flash_probe(CONFIG_ENV_SPI_BUS, + CONFIG_ENV_SPI_CS, + CONFIG_ENV_SPI_MAX_HZ, + CONFIG_ENV_SPI_MODE); +#endif + if (!pfe_flash) { + printf("SF: probe for pfe failed\n"); + return -ENODEV; + } + + ret = spi_flash_read(pfe_flash, + CONFIG_SYS_LS_PFE_FW_ADDR, + CONFIG_SYS_QE_FMAN_FW_LENGTH, + addr); + if (ret) + printf("SF: read for pfe failed\n"); + + pfe_fit_addr = addr; + spi_flash_free(pfe_flash); + + return ret; +} + /* * PFE firmware initialization. * Loads different firmware files from FIT image. @@ -187,6 +226,10 @@ int pfe_firmware_init(void) int ret = 0; int fw_count; + ret = pfe_spi_flash_init(); + if (ret) + goto err; + ret = pfe_fit_check(); if (ret) goto err; diff --git a/drivers/net/ravb.c b/drivers/net/ravb.c index 393ee9bb81..886f53ee82 100644 --- a/drivers/net/ravb.c +++ b/drivers/net/ravb.c @@ -651,7 +651,7 @@ int ravb_ofdata_to_platdata(struct udevice *dev) const fdt32_t *cell; int ret = 0; - pdata->iobase = devfdt_get_addr(dev); + pdata->iobase = dev_read_addr(dev); pdata->phy_interface = -1; phy_mode = fdt_getprop(gd->fdt_blob, dev_of_offset(dev), "phy-mode", NULL); diff --git a/drivers/net/sh_eth.c b/drivers/net/sh_eth.c index 8823769edd..4cbffb14c5 100644 --- a/drivers/net/sh_eth.c +++ b/drivers/net/sh_eth.c @@ -918,7 +918,7 @@ int sh_ether_ofdata_to_platdata(struct udevice *dev) const fdt32_t *cell; int ret = 0; - pdata->iobase = devfdt_get_addr(dev); + pdata->iobase = dev_read_addr(dev); pdata->phy_interface = -1; phy_mode = fdt_getprop(gd->fdt_blob, dev_of_offset(dev), "phy-mode", NULL); diff --git a/drivers/net/smc911x.c b/drivers/net/smc911x.c index 9c5dc46483..09372d7f6b 100644 --- a/drivers/net/smc911x.c +++ b/drivers/net/smc911x.c @@ -612,7 +612,7 @@ static int smc911x_ofdata_to_platdata(struct udevice *dev) struct smc911x_priv *priv = dev_get_priv(dev); struct eth_pdata *pdata = dev_get_platdata(dev); - pdata->iobase = devfdt_get_addr(dev); + pdata->iobase = dev_read_addr(dev); priv->iobase = pdata->iobase; return 0; diff --git a/drivers/net/sni_ave.c b/drivers/net/sni_ave.c index 0784635689..0f7ada8c3e 100644 --- a/drivers/net/sni_ave.c +++ b/drivers/net/sni_ave.c @@ -746,7 +746,7 @@ static int ave_ofdata_to_platdata(struct udevice *dev) if (!priv->data) return -EINVAL; - pdata->iobase = devfdt_get_addr(dev); + pdata->iobase = dev_read_addr(dev); pdata->phy_interface = -1; phy_mode = fdt_getprop(gd->fdt_blob, dev_of_offset(dev), "phy-mode", NULL); diff --git a/drivers/net/sun8i_emac.c b/drivers/net/sun8i_emac.c index e2b05ace8f..546cc6ccb6 100644 --- a/drivers/net/sun8i_emac.c +++ b/drivers/net/sun8i_emac.c @@ -919,7 +919,7 @@ static int sun8i_emac_eth_ofdata_to_platdata(struct udevice *dev) #endif int ret; - pdata->iobase = devfdt_get_addr(dev); + pdata->iobase = dev_read_addr(dev); if (pdata->iobase == FDT_ADDR_T_NONE) { debug("%s: Cannot find MAC base address\n", __func__); return -EINVAL; diff --git a/drivers/net/sunxi_emac.c b/drivers/net/sunxi_emac.c index 6364beb9f2..df18ecc064 100644 --- a/drivers/net/sunxi_emac.c +++ b/drivers/net/sunxi_emac.c @@ -594,7 +594,7 @@ static int sunxi_emac_eth_ofdata_to_platdata(struct udevice *dev) { struct eth_pdata *pdata = dev_get_platdata(dev); - pdata->iobase = devfdt_get_addr(dev); + pdata->iobase = dev_read_addr(dev); return 0; } diff --git a/drivers/net/ti/Kconfig b/drivers/net/ti/Kconfig index ecf642de10..f2dbbd0128 100644 --- a/drivers/net/ti/Kconfig +++ b/drivers/net/ti/Kconfig @@ -14,6 +14,12 @@ config DRIVER_TI_EMAC help Support for davinci emac +config DRIVER_TI_EMAC_USE_RMII + depends on DRIVER_TI_EMAC + bool "Use RMII" + help + Configure the TI EMAC driver to use RMII + config DRIVER_TI_KEYSTONE_NET bool "TI Keystone 2 Ethernet" help diff --git a/drivers/net/ti/keystone_net.c b/drivers/net/ti/keystone_net.c index e3ac40ca0d..50f0d33a83 100644 --- a/drivers/net/ti/keystone_net.c +++ b/drivers/net/ti/keystone_net.c @@ -787,7 +787,7 @@ static int ks2_eth_ofdata_to_platdata(struct udevice *dev) ks2_eth_parse_slave_interface(dev_of_offset(dev), gbe_0, priv, pdata); - pdata->iobase = devfdt_get_addr(dev); + pdata->iobase = dev_read_addr(dev); return 0; } diff --git a/drivers/net/xilinx_axi_emac.c b/drivers/net/xilinx_axi_emac.c index 2cd5596768..99d4d85c52 100644 --- a/drivers/net/xilinx_axi_emac.c +++ b/drivers/net/xilinx_axi_emac.c @@ -722,7 +722,7 @@ static int axi_emac_ofdata_to_platdata(struct udevice *dev) int offset = 0; const char *phy_mode; - pdata->iobase = (phys_addr_t)devfdt_get_addr(dev); + pdata->iobase = dev_read_addr(dev); priv->iobase = (struct axi_regs *)pdata->iobase; offset = fdtdec_lookup_phandle(gd->fdt_blob, node, diff --git a/drivers/net/xilinx_emaclite.c b/drivers/net/xilinx_emaclite.c index 9bdb6798b6..64c18bae74 100644 --- a/drivers/net/xilinx_emaclite.c +++ b/drivers/net/xilinx_emaclite.c @@ -599,7 +599,7 @@ static int emaclite_ofdata_to_platdata(struct udevice *dev) struct xemaclite *emaclite = dev_get_priv(dev); int offset = 0; - pdata->iobase = (phys_addr_t)devfdt_get_addr(dev); + pdata->iobase = dev_read_addr(dev); emaclite->regs = (struct emaclite_regs *)ioremap_nocache(pdata->iobase, 0x10000); diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig index ff974e5d74..91065e67f1 100644 --- a/drivers/pci/Kconfig +++ b/drivers/pci/Kconfig @@ -128,12 +128,29 @@ config PCI_XILINX which can be used on some generations of Xilinx FPGAs. config PCIE_LAYERSCAPE - bool "Layerscape PCIe support" + bool + default n + +config PCIE_LAYERSCAPE_RC + bool "Layerscape PCIe Root Complex mode support" + depends on DM_PCI + select PCIE_LAYERSCAPE + help + Enable Layerscape PCIe Root Complex mode driver support. The Layerscape + SoC may have one or several PCIe controllers. Each controller can be + configured to Root Complex mode by clearing the corresponding bit of + RCW[HOST_AGT_PEX]. + +config PCIE_LAYERSCAPE_EP + bool "Layerscape PCIe Endpoint mode support" depends on DM_PCI + select PCIE_LAYERSCAPE + select PCI_ENDPOINT help - Support Layerscape PCIe. The Layerscape SoC may have one or several - PCIe controllers. The PCIe may works in RC or EP mode according to - RCW[HOST_AGT_PEX] setting. + Enable Layerscape PCIe Endpoint mode driver support. The Layerscape + SoC may have one or several PCIe controllers. Each controller can be + configured to Endpoint mode by setting the corresponding bit of + RCW[HOST_AGT_PEX]. config PCIE_LAYERSCAPE_GEN4 bool "Layerscape Gen4 PCIe support" @@ -145,7 +162,7 @@ config PCIE_LAYERSCAPE_GEN4 config FSL_PCIE_COMPAT string "PCIe compatible of Kernel DT" - depends on PCIE_LAYERSCAPE || PCIE_LAYERSCAPE_GEN4 + depends on PCIE_LAYERSCAPE_RC || PCIE_LAYERSCAPE_GEN4 default "fsl,ls1012a-pcie" if ARCH_LS1012A default "fsl,ls1028a-pcie" if ARCH_LS1028A default "fsl,ls1043a-pcie" if ARCH_LS1043A @@ -160,7 +177,7 @@ config FSL_PCIE_COMPAT config FSL_PCIE_EP_COMPAT string "PCIe EP compatible of Kernel DT" - depends on PCIE_LAYERSCAPE || PCIE_LAYERSCAPE_GEN4 + depends on PCIE_LAYERSCAPE_RC || PCIE_LAYERSCAPE_GEN4 default "fsl,lx2160a-pcie-ep" if ARCH_LX2160A default "fsl,ls-pcie-ep" help diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile index 6378821aaf..9faebffa48 100644 --- a/drivers/pci/Makefile +++ b/drivers/pci/Makefile @@ -34,7 +34,10 @@ obj-$(CONFIG_PCI_AARDVARK) += pci-aardvark.o obj-$(CONFIG_PCIE_DW_MVEBU) += pcie_dw_mvebu.o obj-$(CONFIG_PCIE_FSL) += pcie_fsl.o pcie_fsl_fixup.o obj-$(CONFIG_PCIE_LAYERSCAPE) += pcie_layerscape.o -obj-$(CONFIG_PCIE_LAYERSCAPE) += pcie_layerscape_fixup.o pcie_layerscape_fixup_common.o +obj-$(CONFIG_PCIE_LAYERSCAPE_RC) += pcie_layerscape_rc.o \ + pcie_layerscape_fixup.o \ + pcie_layerscape_fixup_common.o +obj-$(CONFIG_PCIE_LAYERSCAPE_EP) += pcie_layerscape_ep.o obj-$(CONFIG_PCIE_LAYERSCAPE_GEN4) += pcie_layerscape_gen4.o \ pcie_layerscape_gen4_fixup.o \ pcie_layerscape_fixup_common.o diff --git a/drivers/pci/pcie_layerscape.c b/drivers/pci/pcie_layerscape.c index 39b6d40802..25b5272d4e 100644 --- a/drivers/pci/pcie_layerscape.c +++ b/drivers/pci/pcie_layerscape.c @@ -1,18 +1,15 @@ // SPDX-License-Identifier: GPL-2.0+ /* - * Copyright 2017-2019 NXP + * Copyright 2017-2020 NXP * Copyright 2014-2015 Freescale Semiconductor, Inc. * Layerscape PCIe driver */ #include <common.h> #include <log.h> -#include <asm/arch/fsl_serdes.h> -#include <pci.h> #include <asm/io.h> #include <errno.h> #include <malloc.h> -#include <dm.h> #if defined(CONFIG_FSL_LSCH2) || defined(CONFIG_FSL_LSCH3) || \ defined(CONFIG_ARM) #include <asm/arch/clock.h> @@ -23,18 +20,17 @@ DECLARE_GLOBAL_DATA_PTR; LIST_HEAD(ls_pcie_list); -static unsigned int dbi_readl(struct ls_pcie *pcie, unsigned int offset) +unsigned int dbi_readl(struct ls_pcie *pcie, unsigned int offset) { return in_le32(pcie->dbi + offset); } -static void dbi_writel(struct ls_pcie *pcie, unsigned int value, - unsigned int offset) +void dbi_writel(struct ls_pcie *pcie, unsigned int value, unsigned int offset) { out_le32(pcie->dbi + offset, value); } -static unsigned int ctrl_readl(struct ls_pcie *pcie, unsigned int offset) +unsigned int ctrl_readl(struct ls_pcie *pcie, unsigned int offset) { if (pcie->big_endian) return in_be32(pcie->ctrl + offset); @@ -42,8 +38,8 @@ static unsigned int ctrl_readl(struct ls_pcie *pcie, unsigned int offset) return in_le32(pcie->ctrl + offset); } -static void ctrl_writel(struct ls_pcie *pcie, unsigned int value, - unsigned int offset) +void ctrl_writel(struct ls_pcie *pcie, unsigned int value, + unsigned int offset) { if (pcie->big_endian) out_be32(pcie->ctrl + offset, value); @@ -51,6 +47,26 @@ static void ctrl_writel(struct ls_pcie *pcie, unsigned int value, out_le32(pcie->ctrl + offset, value); } +void ls_pcie_dbi_ro_wr_en(struct ls_pcie *pcie) +{ + u32 reg, val; + + reg = PCIE_MISC_CONTROL_1_OFF; + val = dbi_readl(pcie, reg); + val |= PCIE_DBI_RO_WR_EN; + dbi_writel(pcie, val, reg); +} + +void ls_pcie_dbi_ro_wr_dis(struct ls_pcie *pcie) +{ + u32 reg, val; + + reg = PCIE_MISC_CONTROL_1_OFF; + val = dbi_readl(pcie, reg); + val &= ~PCIE_DBI_RO_WR_EN; + dbi_writel(pcie, val, reg); +} + static int ls_pcie_ltssm(struct ls_pcie *pcie) { u32 state; @@ -67,7 +83,7 @@ static int ls_pcie_ltssm(struct ls_pcie *pcie) return state; } -static int ls_pcie_link_up(struct ls_pcie *pcie) +int ls_pcie_link_up(struct ls_pcie *pcie) { int ltssm; @@ -78,22 +94,8 @@ static int ls_pcie_link_up(struct ls_pcie *pcie) return 1; } -static void ls_pcie_cfg0_set_busdev(struct ls_pcie *pcie, u32 busdev) -{ - dbi_writel(pcie, PCIE_ATU_REGION_OUTBOUND | PCIE_ATU_REGION_INDEX0, - PCIE_ATU_VIEWPORT); - dbi_writel(pcie, busdev, PCIE_ATU_LOWER_TARGET); -} - -static void ls_pcie_cfg1_set_busdev(struct ls_pcie *pcie, u32 busdev) -{ - dbi_writel(pcie, PCIE_ATU_REGION_OUTBOUND | PCIE_ATU_REGION_INDEX1, - PCIE_ATU_VIEWPORT); - dbi_writel(pcie, busdev, PCIE_ATU_LOWER_TARGET); -} - -static void ls_pcie_atu_outbound_set(struct ls_pcie *pcie, int idx, int type, - u64 phys, u64 bus_addr, pci_size_t size) +void ls_pcie_atu_outbound_set(struct ls_pcie *pcie, int idx, int type, + u64 phys, u64 bus_addr, u64 size) { dbi_writel(pcie, PCIE_ATU_REGION_OUTBOUND | idx, PCIE_ATU_VIEWPORT); dbi_writel(pcie, (u32)phys, PCIE_ATU_LOWER_BASE); @@ -106,459 +108,41 @@ static void ls_pcie_atu_outbound_set(struct ls_pcie *pcie, int idx, int type, } /* Use bar match mode and MEM type as default */ -static void ls_pcie_atu_inbound_set(struct ls_pcie *pcie, int idx, - int bar, u64 phys) +void ls_pcie_atu_inbound_set(struct ls_pcie *pcie, u32 pf, u32 vf_flag, + int type, int idx, int bar, u64 phys) { dbi_writel(pcie, PCIE_ATU_REGION_INBOUND | idx, PCIE_ATU_VIEWPORT); dbi_writel(pcie, (u32)phys, PCIE_ATU_LOWER_TARGET); dbi_writel(pcie, phys >> 32, PCIE_ATU_UPPER_TARGET); - dbi_writel(pcie, PCIE_ATU_TYPE_MEM, PCIE_ATU_CR1); + dbi_writel(pcie, type | PCIE_ATU_FUNC_NUM(pf), PCIE_ATU_CR1); dbi_writel(pcie, PCIE_ATU_ENABLE | PCIE_ATU_BAR_MODE_ENABLE | + (vf_flag ? PCIE_ATU_FUNC_NUM_MATCH_EN : 0) | + (vf_flag ? PCIE_ATU_VFBAR_MATCH_MODE_EN : 0) | PCIE_ATU_BAR_NUM(bar), PCIE_ATU_CR2); } -static void ls_pcie_dump_atu(struct ls_pcie *pcie) +void ls_pcie_dump_atu(struct ls_pcie *pcie, u32 win_num, u32 type) { - int i; + int win_idx; - for (i = 0; i < PCIE_ATU_REGION_NUM; i++) { - dbi_writel(pcie, PCIE_ATU_REGION_OUTBOUND | i, - PCIE_ATU_VIEWPORT); - debug("iATU%d:\n", i); + for (win_idx = 0; win_idx < win_num; win_idx++) { + dbi_writel(pcie, type | win_idx, PCIE_ATU_VIEWPORT); + debug("iATU%d:\n", win_idx); debug("\tLOWER PHYS 0x%08x\n", dbi_readl(pcie, PCIE_ATU_LOWER_BASE)); debug("\tUPPER PHYS 0x%08x\n", dbi_readl(pcie, PCIE_ATU_UPPER_BASE)); - debug("\tLOWER BUS 0x%08x\n", - dbi_readl(pcie, PCIE_ATU_LOWER_TARGET)); - debug("\tUPPER BUS 0x%08x\n", - dbi_readl(pcie, PCIE_ATU_UPPER_TARGET)); - debug("\tLIMIT 0x%08x\n", - readl(pcie->dbi + PCIE_ATU_LIMIT)); + if (type == PCIE_ATU_REGION_OUTBOUND) { + debug("\tLOWER BUS 0x%08x\n", + dbi_readl(pcie, PCIE_ATU_LOWER_TARGET)); + debug("\tUPPER BUS 0x%08x\n", + dbi_readl(pcie, PCIE_ATU_UPPER_TARGET)); + debug("\tLIMIT 0x%08x\n", + dbi_readl(pcie, PCIE_ATU_LIMIT)); + } debug("\tCR1 0x%08x\n", dbi_readl(pcie, PCIE_ATU_CR1)); debug("\tCR2 0x%08x\n", dbi_readl(pcie, PCIE_ATU_CR2)); } } - -static void ls_pcie_setup_atu(struct ls_pcie *pcie) -{ - struct pci_region *io, *mem, *pref; - unsigned long long offset = 0; - int idx = 0; - uint svr; - - svr = get_svr(); - if (((svr >> SVR_VAR_PER_SHIFT) & SVR_LS102XA_MASK) == SVR_LS102XA) { - offset = LS1021_PCIE_SPACE_OFFSET + - LS1021_PCIE_SPACE_SIZE * pcie->idx; - } - - /* ATU 0 : OUTBOUND : CFG0 */ - ls_pcie_atu_outbound_set(pcie, PCIE_ATU_REGION_INDEX0, - PCIE_ATU_TYPE_CFG0, - pcie->cfg_res.start + offset, - 0, - fdt_resource_size(&pcie->cfg_res) / 2); - /* ATU 1 : OUTBOUND : CFG1 */ - ls_pcie_atu_outbound_set(pcie, PCIE_ATU_REGION_INDEX1, - PCIE_ATU_TYPE_CFG1, - pcie->cfg_res.start + offset + - fdt_resource_size(&pcie->cfg_res) / 2, - 0, - fdt_resource_size(&pcie->cfg_res) / 2); - - pci_get_regions(pcie->bus, &io, &mem, &pref); - idx = PCIE_ATU_REGION_INDEX1 + 1; - - /* Fix the pcie memory map for LS2088A series SoCs */ - svr = (svr >> SVR_VAR_PER_SHIFT) & 0xFFFFFE; - if (svr == SVR_LS2088A || svr == SVR_LS2084A || - svr == SVR_LS2048A || svr == SVR_LS2044A || - svr == SVR_LS2081A || svr == SVR_LS2041A) { - if (io) - io->phys_start = (io->phys_start & - (PCIE_PHYS_SIZE - 1)) + - LS2088A_PCIE1_PHYS_ADDR + - LS2088A_PCIE_PHYS_SIZE * pcie->idx; - if (mem) - mem->phys_start = (mem->phys_start & - (PCIE_PHYS_SIZE - 1)) + - LS2088A_PCIE1_PHYS_ADDR + - LS2088A_PCIE_PHYS_SIZE * pcie->idx; - if (pref) - pref->phys_start = (pref->phys_start & - (PCIE_PHYS_SIZE - 1)) + - LS2088A_PCIE1_PHYS_ADDR + - LS2088A_PCIE_PHYS_SIZE * pcie->idx; - } - - if (io) - /* ATU : OUTBOUND : IO */ - ls_pcie_atu_outbound_set(pcie, idx++, - PCIE_ATU_TYPE_IO, - io->phys_start + offset, - io->bus_start, - io->size); - - if (mem) - /* ATU : OUTBOUND : MEM */ - ls_pcie_atu_outbound_set(pcie, idx++, - PCIE_ATU_TYPE_MEM, - mem->phys_start + offset, - mem->bus_start, - mem->size); - - if (pref) - /* ATU : OUTBOUND : pref */ - ls_pcie_atu_outbound_set(pcie, idx++, - PCIE_ATU_TYPE_MEM, - pref->phys_start + offset, - pref->bus_start, - pref->size); - - ls_pcie_dump_atu(pcie); -} - -/* Return 0 if the address is valid, -errno if not valid */ -static int ls_pcie_addr_valid(struct ls_pcie *pcie, pci_dev_t bdf) -{ - struct udevice *bus = pcie->bus; - - if (pcie->mode == PCI_HEADER_TYPE_NORMAL) - return -ENODEV; - - if (!pcie->enabled) - return -ENXIO; - - if (PCI_BUS(bdf) < bus->seq) - return -EINVAL; - - if ((PCI_BUS(bdf) > bus->seq) && (!ls_pcie_link_up(pcie))) - return -EINVAL; - - if (PCI_BUS(bdf) <= (bus->seq + 1) && (PCI_DEV(bdf) > 0)) - return -EINVAL; - - return 0; -} - -int ls_pcie_conf_address(const struct udevice *bus, pci_dev_t bdf, - uint offset, void **paddress) -{ - struct ls_pcie *pcie = dev_get_priv(bus); - u32 busdev; - - if (ls_pcie_addr_valid(pcie, bdf)) - return -EINVAL; - - if (PCI_BUS(bdf) == bus->seq) { - *paddress = pcie->dbi + offset; - return 0; - } - - busdev = PCIE_ATU_BUS(PCI_BUS(bdf) - bus->seq) | - PCIE_ATU_DEV(PCI_DEV(bdf)) | - PCIE_ATU_FUNC(PCI_FUNC(bdf)); - - if (PCI_BUS(bdf) == bus->seq + 1) { - ls_pcie_cfg0_set_busdev(pcie, busdev); - *paddress = pcie->cfg0 + offset; - } else { - ls_pcie_cfg1_set_busdev(pcie, busdev); - *paddress = pcie->cfg1 + offset; - } - return 0; -} - -static int ls_pcie_read_config(const struct udevice *bus, pci_dev_t bdf, - uint offset, ulong *valuep, - enum pci_size_t size) -{ - return pci_generic_mmap_read_config(bus, ls_pcie_conf_address, - bdf, offset, valuep, size); -} - -static int ls_pcie_write_config(struct udevice *bus, pci_dev_t bdf, - uint offset, ulong value, - enum pci_size_t size) -{ - return pci_generic_mmap_write_config(bus, ls_pcie_conf_address, - bdf, offset, value, size); -} - -/* Clear multi-function bit */ -static void ls_pcie_clear_multifunction(struct ls_pcie *pcie) -{ - writeb(PCI_HEADER_TYPE_BRIDGE, pcie->dbi + PCI_HEADER_TYPE); -} - -/* Fix class value */ -static void ls_pcie_fix_class(struct ls_pcie *pcie) -{ - writew(PCI_CLASS_BRIDGE_PCI, pcie->dbi + PCI_CLASS_DEVICE); -} - -/* Drop MSG TLP except for Vendor MSG */ -static void ls_pcie_drop_msg_tlp(struct ls_pcie *pcie) -{ - u32 val; - - val = dbi_readl(pcie, PCIE_STRFMR1); - val &= 0xDFFFFFFF; - dbi_writel(pcie, val, PCIE_STRFMR1); -} - -/* Disable all bars in RC mode */ -static void ls_pcie_disable_bars(struct ls_pcie *pcie) -{ - dbi_writel(pcie, 0, PCIE_CS2_OFFSET + PCI_BASE_ADDRESS_0); - dbi_writel(pcie, 0, PCIE_CS2_OFFSET + PCI_BASE_ADDRESS_1); - dbi_writel(pcie, 0xfffffffe, PCIE_CS2_OFFSET + PCI_ROM_ADDRESS1); -} - -static void ls_pcie_setup_ctrl(struct ls_pcie *pcie) -{ - ls_pcie_setup_atu(pcie); - - dbi_writel(pcie, 1, PCIE_DBI_RO_WR_EN); - ls_pcie_fix_class(pcie); - ls_pcie_clear_multifunction(pcie); - ls_pcie_drop_msg_tlp(pcie); - dbi_writel(pcie, 0, PCIE_DBI_RO_WR_EN); - - ls_pcie_disable_bars(pcie); - pcie->stream_id_cur = 0; -} - -static void ls_pcie_ep_setup_atu(struct ls_pcie *pcie) -{ - u64 phys = CONFIG_SYS_PCI_EP_MEMORY_BASE; - - /* ATU 0 : INBOUND : map BAR0 */ - ls_pcie_atu_inbound_set(pcie, 0, 0, phys); - /* ATU 1 : INBOUND : map BAR1 */ - phys += PCIE_BAR1_SIZE; - ls_pcie_atu_inbound_set(pcie, 1, 1, phys); - /* ATU 2 : INBOUND : map BAR2 */ - phys += PCIE_BAR2_SIZE; - ls_pcie_atu_inbound_set(pcie, 2, 2, phys); - /* ATU 3 : INBOUND : map BAR4 */ - phys = CONFIG_SYS_PCI_EP_MEMORY_BASE + PCIE_BAR4_SIZE; - ls_pcie_atu_inbound_set(pcie, 3, 4, phys); - - /* ATU 0 : OUTBOUND : map MEM */ - ls_pcie_atu_outbound_set(pcie, 0, - PCIE_ATU_TYPE_MEM, - pcie->cfg_res.start, - 0, - CONFIG_SYS_PCI_MEMORY_SIZE); -} - -/* BAR0 and BAR1 are 32bit BAR2 and BAR4 are 64bit */ -static void ls_pcie_ep_setup_bar(void *bar_base, int bar, u32 size) -{ - /* The least inbound window is 4KiB */ - if (size < 4 * 1024) - return; - - switch (bar) { - case 0: - writel(size - 1, bar_base + PCI_BASE_ADDRESS_0); - break; - case 1: - writel(size - 1, bar_base + PCI_BASE_ADDRESS_1); - break; - case 2: - writel(size - 1, bar_base + PCI_BASE_ADDRESS_2); - writel(0, bar_base + PCI_BASE_ADDRESS_3); - break; - case 4: - writel(size - 1, bar_base + PCI_BASE_ADDRESS_4); - writel(0, bar_base + PCI_BASE_ADDRESS_5); - break; - default: - break; - } -} - -static void ls_pcie_ep_setup_bars(void *bar_base) -{ - /* BAR0 - 32bit - 4K configuration */ - ls_pcie_ep_setup_bar(bar_base, 0, PCIE_BAR0_SIZE); - /* BAR1 - 32bit - 8K MSIX*/ - ls_pcie_ep_setup_bar(bar_base, 1, PCIE_BAR1_SIZE); - /* BAR2 - 64bit - 4K MEM desciptor */ - ls_pcie_ep_setup_bar(bar_base, 2, PCIE_BAR2_SIZE); - /* BAR4 - 64bit - 1M MEM*/ - ls_pcie_ep_setup_bar(bar_base, 4, PCIE_BAR4_SIZE); -} - -static void ls_pcie_ep_enable_cfg(struct ls_pcie *pcie) -{ - u32 config; - - config = ctrl_readl(pcie, PCIE_PF_CONFIG); - config |= PCIE_CONFIG_READY; - ctrl_writel(pcie, config, PCIE_PF_CONFIG); -} - -static void ls_pcie_setup_ep(struct ls_pcie *pcie) -{ - u32 sriov; - - sriov = readl(pcie->dbi + PCIE_SRIOV); - if (PCI_EXT_CAP_ID(sriov) == PCI_EXT_CAP_ID_SRIOV) { - int pf, vf; - - for (pf = 0; pf < PCIE_PF_NUM; pf++) { - for (vf = 0; vf <= PCIE_VF_NUM; vf++) { - ctrl_writel(pcie, PCIE_LCTRL0_VAL(pf, vf), - PCIE_PF_VF_CTRL); - - ls_pcie_ep_setup_bars(pcie->dbi); - ls_pcie_ep_setup_atu(pcie); - } - } - /* Disable CFG2 */ - ctrl_writel(pcie, 0, PCIE_PF_VF_CTRL); - } else { - ls_pcie_ep_setup_bars(pcie->dbi + PCIE_NO_SRIOV_BAR_BASE); - ls_pcie_ep_setup_atu(pcie); - } - - ls_pcie_ep_enable_cfg(pcie); -} - -static int ls_pcie_probe(struct udevice *dev) -{ - struct ls_pcie *pcie = dev_get_priv(dev); - const void *fdt = gd->fdt_blob; - int node = dev_of_offset(dev); - u16 link_sta; - uint svr; - int ret; - fdt_size_t cfg_size; - - pcie->bus = dev; - - ret = fdt_get_named_resource(fdt, node, "reg", "reg-names", - "dbi", &pcie->dbi_res); - if (ret) { - printf("ls-pcie: resource \"dbi\" not found\n"); - return ret; - } - - pcie->idx = (pcie->dbi_res.start - PCIE_SYS_BASE_ADDR) / PCIE_CCSR_SIZE; - - list_add(&pcie->list, &ls_pcie_list); - - pcie->enabled = is_serdes_configured(PCIE_SRDS_PRTCL(pcie->idx)); - if (!pcie->enabled) { - printf("PCIe%d: %s disabled\n", pcie->idx, dev->name); - return 0; - } - - pcie->dbi = map_physmem(pcie->dbi_res.start, - fdt_resource_size(&pcie->dbi_res), - MAP_NOCACHE); - - ret = fdt_get_named_resource(fdt, node, "reg", "reg-names", - "lut", &pcie->lut_res); - if (!ret) - pcie->lut = map_physmem(pcie->lut_res.start, - fdt_resource_size(&pcie->lut_res), - MAP_NOCACHE); - - ret = fdt_get_named_resource(fdt, node, "reg", "reg-names", - "ctrl", &pcie->ctrl_res); - if (!ret) - pcie->ctrl = map_physmem(pcie->ctrl_res.start, - fdt_resource_size(&pcie->ctrl_res), - MAP_NOCACHE); - if (!pcie->ctrl) - pcie->ctrl = pcie->lut; - - if (!pcie->ctrl) { - printf("%s: NOT find CTRL\n", dev->name); - return -1; - } - - ret = fdt_get_named_resource(fdt, node, "reg", "reg-names", - "config", &pcie->cfg_res); - if (ret) { - printf("%s: resource \"config\" not found\n", dev->name); - return ret; - } - - /* - * Fix the pcie memory map address and PF control registers address - * for LS2088A series SoCs - */ - svr = get_svr(); - svr = (svr >> SVR_VAR_PER_SHIFT) & 0xFFFFFE; - if (svr == SVR_LS2088A || svr == SVR_LS2084A || - svr == SVR_LS2048A || svr == SVR_LS2044A || - svr == SVR_LS2081A || svr == SVR_LS2041A) { - cfg_size = fdt_resource_size(&pcie->cfg_res); - pcie->cfg_res.start = LS2088A_PCIE1_PHYS_ADDR + - LS2088A_PCIE_PHYS_SIZE * pcie->idx; - pcie->cfg_res.end = pcie->cfg_res.start + cfg_size; - pcie->ctrl = pcie->lut + 0x40000; - } - - pcie->cfg0 = map_physmem(pcie->cfg_res.start, - fdt_resource_size(&pcie->cfg_res), - MAP_NOCACHE); - pcie->cfg1 = pcie->cfg0 + fdt_resource_size(&pcie->cfg_res) / 2; - - pcie->big_endian = fdtdec_get_bool(fdt, node, "big-endian"); - - debug("%s dbi:%lx lut:%lx ctrl:0x%lx cfg0:0x%lx, big-endian:%d\n", - dev->name, (unsigned long)pcie->dbi, (unsigned long)pcie->lut, - (unsigned long)pcie->ctrl, (unsigned long)pcie->cfg0, - pcie->big_endian); - - pcie->mode = readb(pcie->dbi + PCI_HEADER_TYPE) & 0x7f; - - if (pcie->mode == PCI_HEADER_TYPE_NORMAL) { - printf("PCIe%u: %s %s", pcie->idx, dev->name, "Endpoint"); - ls_pcie_setup_ep(pcie); - } else { - printf("PCIe%u: %s %s", pcie->idx, dev->name, "Root Complex"); - ls_pcie_setup_ctrl(pcie); - } - - if (!ls_pcie_link_up(pcie)) { - /* Let the user know there's no PCIe link */ - printf(": no link\n"); - return 0; - } - - /* Print the negotiated PCIe link width */ - link_sta = readw(pcie->dbi + PCIE_LINK_STA); - printf(": x%d gen%d\n", (link_sta & PCIE_LINK_WIDTH_MASK) >> 4, - link_sta & PCIE_LINK_SPEED_MASK); - - return 0; -} - -static const struct dm_pci_ops ls_pcie_ops = { - .read_config = ls_pcie_read_config, - .write_config = ls_pcie_write_config, -}; - -static const struct udevice_id ls_pcie_ids[] = { - { .compatible = "fsl,ls-pcie" }, - { } -}; - -U_BOOT_DRIVER(pci_layerscape) = { - .name = "pci_layerscape", - .id = UCLASS_PCI, - .of_match = ls_pcie_ids, - .ops = &ls_pcie_ops, - .probe = ls_pcie_probe, - .priv_auto_alloc_size = sizeof(struct ls_pcie), -}; diff --git a/drivers/pci/pcie_layerscape.h b/drivers/pci/pcie_layerscape.h index 95454bc188..0124e8e051 100644 --- a/drivers/pci/pcie_layerscape.h +++ b/drivers/pci/pcie_layerscape.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0+ */ /* - * Copyright 2017-2019 NXP + * Copyright 2017-2020 NXP * Copyright 2014-2015 Freescale Semiconductor, Inc. * Layerscape PCIe driver */ @@ -8,7 +8,8 @@ #ifndef _PCIE_LAYERSCAPE_H_ #define _PCIE_LAYERSCAPE_H_ #include <pci.h> -#include <dm.h> + +#include <linux/sizes.h> #ifndef CONFIG_SYS_PCI_MEMORY_BUS #define CONFIG_SYS_PCI_MEMORY_BUS CONFIG_SYS_SDRAM_BASE @@ -19,7 +20,7 @@ #endif #ifndef CONFIG_SYS_PCI_MEMORY_SIZE -#define CONFIG_SYS_PCI_MEMORY_SIZE (2 * 1024 * 1024 * 1024UL) /* 2G */ +#define CONFIG_SYS_PCI_MEMORY_SIZE SZ_4G #endif #ifndef CONFIG_SYS_PCI_EP_MEMORY_BASE @@ -39,14 +40,18 @@ #define PCIE_ATU_REGION_INDEX2 (0x2 << 0) #define PCIE_ATU_REGION_INDEX3 (0x3 << 0) #define PCIE_ATU_REGION_NUM 6 +#define PCIE_ATU_REGION_NUM_SRIOV 24 #define PCIE_ATU_CR1 0x904 #define PCIE_ATU_TYPE_MEM (0x0 << 0) #define PCIE_ATU_TYPE_IO (0x2 << 0) #define PCIE_ATU_TYPE_CFG0 (0x4 << 0) #define PCIE_ATU_TYPE_CFG1 (0x5 << 0) +#define PCIE_ATU_FUNC_NUM(pf) ((pf) << 20) #define PCIE_ATU_CR2 0x908 #define PCIE_ATU_ENABLE (0x1 << 31) #define PCIE_ATU_BAR_MODE_ENABLE (0x1 << 30) +#define PCIE_ATU_FUNC_NUM_MATCH_EN BIT(19) +#define PCIE_ATU_VFBAR_MATCH_MODE_EN BIT(26) #define PCIE_ATU_BAR_NUM(bar) ((bar) << 8) #define PCIE_ATU_LOWER_BASE 0x90C #define PCIE_ATU_UPPER_BASE 0x910 @@ -60,7 +65,8 @@ /* DBI registers */ #define PCIE_SRIOV 0x178 #define PCIE_STRFMR1 0x71c /* Symbol Timer & Filter Mask Register1 */ -#define PCIE_DBI_RO_WR_EN 0x8bc +#define PCIE_DBI_RO_WR_EN BIT(0) +#define PCIE_MISC_CONTROL_1_OFF 0x8BC #define PCIE_LINK_CAP 0x7c #define PCIE_LINK_SPEED_MASK 0xf @@ -82,14 +88,19 @@ PCIE_LCTRL0_CFG2_ENABLE) #define PCIE_NO_SRIOV_BAR_BASE 0x1000 - +#define FSL_PCIE_EP_MIN_APERTURE 4096 /* 4 Kbytes */ #define PCIE_PF_NUM 2 #define PCIE_VF_NUM 64 +#define BAR_NUM 8 + +#define PCIE_BAR0_SIZE SZ_4K +#define PCIE_BAR1_SIZE SZ_8K +#define PCIE_BAR2_SIZE SZ_4K +#define PCIE_BAR4_SIZE SZ_1M -#define PCIE_BAR0_SIZE (4 * 1024) /* 4K */ -#define PCIE_BAR1_SIZE (8 * 1024) /* 8K for MSIX */ -#define PCIE_BAR2_SIZE (4 * 1024) /* 4K */ -#define PCIE_BAR4_SIZE (1 * 1024 * 1024) /* 1M */ +#define PCIE_SRIOV_VFBAR0 0x19C + +#define PCIE_MASK_OFFSET(flag, pf, off) ((flag) ? 0 : (0x1000 + (off) * (pf))) /* LUT registers */ #define PCIE_LUT_UDR(n) (0x800 + (n) * 8) @@ -128,26 +139,62 @@ #define LS1021_PEXMSCPORTSR(pex_idx) (0x94 + (pex_idx) * 4) #define LS1021_LTSSM_STATE_SHIFT 20 +/* LX2160a PF1 offset */ +#define LX2160_PCIE_PF1_OFFSET 0x8000 + +/* layerscape PF1 offset */ +#define LS_PCIE_PF1_OFFSET 0x20000 + struct ls_pcie { + void __iomem *dbi; + void __iomem *lut; + void __iomem *ctrl; int idx; + bool big_endian; + int mode; +}; + +struct ls_pcie_rc { + struct ls_pcie *pcie; struct list_head list; struct udevice *bus; struct fdt_resource dbi_res; struct fdt_resource lut_res; struct fdt_resource ctrl_res; struct fdt_resource cfg_res; - void __iomem *dbi; - void __iomem *lut; - void __iomem *ctrl; void __iomem *cfg0; void __iomem *cfg1; - bool big_endian; bool enabled; int next_lut_index; int stream_id_cur; - int mode; +}; + +struct ls_pcie_ep { + struct fdt_resource addr_res; + struct ls_pcie *pcie; + struct udevice *bus; + void __iomem *addr; + u32 cfg2_flag; + u32 sriov_flag; + u32 pf1_offset; + u32 num_ib_wins; + u32 num_ob_wins; + u8 max_functions; }; extern struct list_head ls_pcie_list; +unsigned int dbi_readl(struct ls_pcie *pcie, unsigned int offset); +void dbi_writel(struct ls_pcie *pcie, unsigned int value, unsigned int offset); +unsigned int ctrl_readl(struct ls_pcie *pcie, unsigned int offset); +void ctrl_writel(struct ls_pcie *pcie, unsigned int value, unsigned int offset); +void ls_pcie_atu_outbound_set(struct ls_pcie *pcie, int idx, int type, + u64 phys, u64 bus_addr, u64 size); +void ls_pcie_atu_inbound_set(struct ls_pcie *pcie, u32 pf, u32 vf_flag, + int type, int idx, int bar, u64 phys); +void ls_pcie_dump_atu(struct ls_pcie *pcie, u32 win_num, u32 type); +int ls_pcie_link_up(struct ls_pcie *pcie); +void ls_pcie_dbi_ro_wr_en(struct ls_pcie *pcie); +void ls_pcie_dbi_ro_wr_dis(struct ls_pcie *pcie); + #endif /* _PCIE_LAYERSCAPE_H_ */ diff --git a/drivers/pci/pcie_layerscape_ep.c b/drivers/pci/pcie_layerscape_ep.c new file mode 100644 index 0000000000..eba230e3a5 --- /dev/null +++ b/drivers/pci/pcie_layerscape_ep.c @@ -0,0 +1,332 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2020 NXP + * Layerscape PCIe EP driver + */ + +#include <common.h> +#include <dm.h> +#include <dm/devres.h> +#include <errno.h> +#include <pci_ep.h> +#include <asm/io.h> +#include <linux/sizes.h> +#include <linux/log2.h> +#include "pcie_layerscape.h" + +DECLARE_GLOBAL_DATA_PTR; + +static void ls_pcie_ep_enable_cfg(struct ls_pcie_ep *pcie_ep) +{ + struct ls_pcie *pcie = pcie_ep->pcie; + u32 config; + + config = ctrl_readl(pcie, PCIE_PF_CONFIG); + config |= PCIE_CONFIG_READY; + ctrl_writel(pcie, config, PCIE_PF_CONFIG); +} + +static int ls_ep_set_bar(struct udevice *dev, uint fn, struct pci_bar *ep_bar) +{ + struct ls_pcie_ep *pcie_ep = dev_get_priv(dev); + struct ls_pcie *pcie = pcie_ep->pcie; + dma_addr_t bar_phys = ep_bar->phys_addr; + enum pci_barno bar = ep_bar->barno; + u32 reg = PCI_BASE_ADDRESS_0 + (4 * bar); + int flags = ep_bar->flags; + int type, idx; + u64 size; + + idx = bar; + /* BAR size is 2^(aperture + 11) */ + size = max_t(size_t, ep_bar->size, FSL_PCIE_EP_MIN_APERTURE); + + if (!(flags & PCI_BASE_ADDRESS_SPACE)) + type = PCIE_ATU_TYPE_MEM; + else + type = PCIE_ATU_TYPE_IO; + + ls_pcie_atu_inbound_set(pcie, fn, 0, type, idx, bar, bar_phys); + + dbi_writel(pcie, lower_32_bits(size - 1), reg + PCIE_NO_SRIOV_BAR_BASE); + dbi_writel(pcie, flags, reg); + + if (flags & PCI_BASE_ADDRESS_MEM_TYPE_64) { + dbi_writel(pcie, upper_32_bits(size - 1), + reg + 4 + PCIE_NO_SRIOV_BAR_BASE); + dbi_writel(pcie, 0, reg + 4); + } + + return 0; +} + +static struct pci_ep_ops ls_pcie_ep_ops = { + .set_bar = ls_ep_set_bar, +}; + +static void ls_pcie_ep_setup_atu(struct ls_pcie_ep *pcie_ep, u32 pf) +{ + struct ls_pcie *pcie = pcie_ep->pcie; + u32 vf_flag = 0; + u64 phys = 0; + + phys = CONFIG_SYS_PCI_EP_MEMORY_BASE + pf * SZ_64M; + + phys = ALIGN(phys, PCIE_BAR0_SIZE); + /* ATU 0 : INBOUND : map BAR0 */ + ls_pcie_atu_inbound_set(pcie, pf, vf_flag, PCIE_ATU_TYPE_MEM, + 0 + pf * BAR_NUM, 0, phys); + /* ATU 1 : INBOUND : map BAR1 */ + phys = ALIGN(phys + PCIE_BAR0_SIZE, PCIE_BAR1_SIZE); + ls_pcie_atu_inbound_set(pcie, pf, vf_flag, PCIE_ATU_TYPE_MEM, + 1 + pf * BAR_NUM, 1, phys); + /* ATU 2 : INBOUND : map BAR2 */ + phys = ALIGN(phys + PCIE_BAR1_SIZE, PCIE_BAR2_SIZE); + ls_pcie_atu_inbound_set(pcie, pf, vf_flag, PCIE_ATU_TYPE_MEM, + 2 + pf * BAR_NUM, 2, phys); + /* ATU 3 : INBOUND : map BAR2 */ + phys = ALIGN(phys + PCIE_BAR2_SIZE, PCIE_BAR4_SIZE); + ls_pcie_atu_inbound_set(pcie, pf, vf_flag, PCIE_ATU_TYPE_MEM, + 3 + pf * BAR_NUM, 4, phys); + + if (pcie_ep->sriov_flag) { + vf_flag = 1; + /* ATU 4 : INBOUND : map BAR0 */ + phys = ALIGN(phys + PCIE_BAR4_SIZE, PCIE_BAR0_SIZE); + ls_pcie_atu_inbound_set(pcie, pf, vf_flag, PCIE_ATU_TYPE_MEM, + 4 + pf * BAR_NUM, 0, phys); + /* ATU 5 : INBOUND : map BAR1 */ + phys = ALIGN(phys + PCIE_BAR0_SIZE * PCIE_VF_NUM, + PCIE_BAR1_SIZE); + ls_pcie_atu_inbound_set(pcie, pf, vf_flag, PCIE_ATU_TYPE_MEM, + 5 + pf * BAR_NUM, 1, phys); + /* ATU 6 : INBOUND : map BAR2 */ + phys = ALIGN(phys + PCIE_BAR1_SIZE * PCIE_VF_NUM, + PCIE_BAR2_SIZE); + ls_pcie_atu_inbound_set(pcie, pf, vf_flag, PCIE_ATU_TYPE_MEM, + 6 + pf * BAR_NUM, 2, phys); + /* ATU 7 : INBOUND : map BAR4 */ + phys = ALIGN(phys + PCIE_BAR2_SIZE * PCIE_VF_NUM, + PCIE_BAR4_SIZE); + ls_pcie_atu_inbound_set(pcie, pf, vf_flag, PCIE_ATU_TYPE_MEM, + 7 + pf * BAR_NUM, 4, phys); + } + + /* ATU: OUTBOUND : map MEM */ + ls_pcie_atu_outbound_set(pcie, pf, PCIE_ATU_TYPE_MEM, + (u64)pcie_ep->addr_res.start + + pf * CONFIG_SYS_PCI_MEMORY_SIZE, + 0, CONFIG_SYS_PCI_MEMORY_SIZE); +} + +/* BAR0 and BAR1 are 32bit BAR2 and BAR4 are 64bit */ +static void ls_pcie_ep_setup_bar(void *bar_base, int bar, u32 size) +{ + u32 mask; + + /* The least inbound window is 4KiB */ + if (size < SZ_4K) + mask = 0; + else + mask = size - 1; + + switch (bar) { + case 0: + writel(mask, bar_base + PCI_BASE_ADDRESS_0); + break; + case 1: + writel(mask, bar_base + PCI_BASE_ADDRESS_1); + break; + case 2: + writel(mask, bar_base + PCI_BASE_ADDRESS_2); + writel(0, bar_base + PCI_BASE_ADDRESS_3); + break; + case 4: + writel(mask, bar_base + PCI_BASE_ADDRESS_4); + writel(0, bar_base + PCI_BASE_ADDRESS_5); + break; + default: + break; + } +} + +static void ls_pcie_ep_setup_bars(void *bar_base) +{ + /* BAR0 - 32bit - MEM */ + ls_pcie_ep_setup_bar(bar_base, 0, PCIE_BAR0_SIZE); + /* BAR1 - 32bit - MEM*/ + ls_pcie_ep_setup_bar(bar_base, 1, PCIE_BAR1_SIZE); + /* BAR2 - 64bit - MEM */ + ls_pcie_ep_setup_bar(bar_base, 2, PCIE_BAR2_SIZE); + /* BAR4 - 64bit - MEM */ + ls_pcie_ep_setup_bar(bar_base, 4, PCIE_BAR4_SIZE); +} + +static void ls_pcie_ep_setup_vf_bars(void *bar_base) +{ + /* VF BAR0 MASK register at offset 0x19c*/ + bar_base += PCIE_SRIOV_VFBAR0 - PCI_BASE_ADDRESS_0; + + /* VF-BAR0 - 32bit - MEM */ + ls_pcie_ep_setup_bar(bar_base, 0, PCIE_BAR0_SIZE); + /* VF-BAR1 - 32bit - MEM*/ + ls_pcie_ep_setup_bar(bar_base, 1, PCIE_BAR1_SIZE); + /* VF-BAR2 - 64bit - MEM */ + ls_pcie_ep_setup_bar(bar_base, 2, PCIE_BAR2_SIZE); + /* VF-BAR4 - 64bit - MEM */ + ls_pcie_ep_setup_bar(bar_base, 4, PCIE_BAR4_SIZE); +} + +static void ls_pcie_setup_ep(struct ls_pcie_ep *pcie_ep) +{ + u32 sriov; + u32 pf, vf; + void *bar_base = NULL; + struct ls_pcie *pcie = pcie_ep->pcie; + + sriov = readl(pcie->dbi + PCIE_SRIOV); + if (PCI_EXT_CAP_ID(sriov) == PCI_EXT_CAP_ID_SRIOV) { + pcie_ep->sriov_flag = 1; + for (pf = 0; pf < PCIE_PF_NUM; pf++) { + /* + * The VF_BARn_REG register's Prefetchable and Type bit + * fields are overwritten by a write to VF's BAR Mask + * register. Before writing to the VF_BARn_MASK_REG + * register, write 0b to the PCIE_MISC_CONTROL_1_OFF + * register. + */ + writel(0, pcie->dbi + PCIE_MISC_CONTROL_1_OFF); + + bar_base = pcie->dbi + + PCIE_MASK_OFFSET(pcie_ep->cfg2_flag, pf, + pcie_ep->pf1_offset); + + if (pcie_ep->cfg2_flag) { + ctrl_writel(pcie, + PCIE_LCTRL0_VAL(pf, 0), + PCIE_PF_VF_CTRL); + ls_pcie_ep_setup_bars(bar_base); + + for (vf = 1; vf <= PCIE_VF_NUM; vf++) { + ctrl_writel(pcie, + PCIE_LCTRL0_VAL(pf, vf), + PCIE_PF_VF_CTRL); + ls_pcie_ep_setup_vf_bars(bar_base); + } + } else { + ls_pcie_ep_setup_bars(bar_base); + ls_pcie_ep_setup_vf_bars(bar_base); + } + + ls_pcie_ep_setup_atu(pcie_ep, pf); + } + + if (pcie_ep->cfg2_flag) /* Disable CFG2 */ + ctrl_writel(pcie, 0, PCIE_PF_VF_CTRL); + } else { + ls_pcie_ep_setup_bars(pcie->dbi + PCIE_NO_SRIOV_BAR_BASE); + ls_pcie_ep_setup_atu(pcie_ep, 0); + } + + ls_pcie_dump_atu(pcie, PCIE_ATU_REGION_NUM_SRIOV, + PCIE_ATU_REGION_INBOUND); + + ls_pcie_ep_enable_cfg(pcie_ep); +} + +static int ls_pcie_ep_probe(struct udevice *dev) +{ + struct ls_pcie_ep *pcie_ep = dev_get_priv(dev); + struct ls_pcie *pcie; + u16 link_sta; + int ret; + u32 svr; + + pcie = devm_kmalloc(dev, sizeof(*pcie), GFP_KERNEL); + if (!pcie) + return -ENOMEM; + + pcie_ep->pcie = pcie; + + pcie->dbi = (void __iomem *)devfdt_get_addr_index(dev, 0); + if (!pcie->dbi) + return -ENOMEM; + + pcie->ctrl = (void __iomem *)devfdt_get_addr_index(dev, 1); + if (!pcie->ctrl) + return -ENOMEM; + + ret = fdt_get_named_resource(gd->fdt_blob, dev_of_offset(dev), + "reg", "reg-names", + "addr_space", &pcie_ep->addr_res); + if (ret) { + printf("%s: resource \"addr_space\" not found\n", dev->name); + return ret; + } + + pcie->idx = ((unsigned long)pcie->dbi - PCIE_SYS_BASE_ADDR) / + PCIE_CCSR_SIZE; + + pcie->big_endian = fdtdec_get_bool(gd->fdt_blob, dev_of_offset(dev), + "big-endian"); + + svr = SVR_SOC_VER(get_svr()); + + if (svr == SVR_LX2160A) + pcie_ep->pf1_offset = LX2160_PCIE_PF1_OFFSET; + else + pcie_ep->pf1_offset = LS_PCIE_PF1_OFFSET; + + if (svr == SVR_LS2080A || svr == SVR_LS2085A) + pcie_ep->cfg2_flag = 1; + else + pcie_ep->cfg2_flag = 0; + + pcie->mode = readb(pcie->dbi + PCI_HEADER_TYPE) & 0x7f; + if (pcie->mode != PCI_HEADER_TYPE_NORMAL) + return 0; + + pcie_ep->max_functions = fdtdec_get_int(gd->fdt_blob, + dev_of_offset(dev), + "max-functions", 1); + pcie_ep->num_ib_wins = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev), + "num-ib-windows", 8); + pcie_ep->num_ob_wins = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev), + "num-ob-windows", 8); + + printf("PCIe%u: %s %s", pcie->idx, dev->name, "Endpoint"); + ls_pcie_setup_ep(pcie_ep); + + if (!ls_pcie_link_up(pcie)) { + /* Let the user know there's no PCIe link */ + printf(": no link\n"); + return 0; + } + + /* Print the negotiated PCIe link width */ + link_sta = readw(pcie->dbi + PCIE_LINK_STA); + printf(": x%d gen%d\n", (link_sta & PCIE_LINK_WIDTH_MASK) >> 4, + link_sta & PCIE_LINK_SPEED_MASK); + + return 0; +} + +static int ls_pcie_ep_remove(struct udevice *dev) +{ + return 0; +} + +const struct udevice_id ls_pcie_ep_ids[] = { + { .compatible = "fsl,ls-pcie-ep" }, + { } +}; + +U_BOOT_DRIVER(pci_layerscape_ep) = { + .name = "pci_layerscape_ep", + .id = UCLASS_PCI_EP, + .of_match = ls_pcie_ep_ids, + .ops = &ls_pcie_ep_ops, + .probe = ls_pcie_ep_probe, + .remove = ls_pcie_ep_remove, + .priv_auto_alloc_size = sizeof(struct ls_pcie_ep), +}; diff --git a/drivers/pci/pcie_layerscape_fixup.c b/drivers/pci/pcie_layerscape_fixup.c index 76e680481a..8315b0b590 100644 --- a/drivers/pci/pcie_layerscape_fixup.c +++ b/drivers/pci/pcie_layerscape_fixup.c @@ -6,6 +6,7 @@ */ #include <common.h> +#include <dm.h> #include <init.h> #include <log.h> #include <pci.h> @@ -25,17 +26,19 @@ /* * Return next available LUT index. */ -static int ls_pcie_next_lut_index(struct ls_pcie *pcie) +static int ls_pcie_next_lut_index(struct ls_pcie_rc *pcie_rc) { - if (pcie->next_lut_index < PCIE_LUT_ENTRY_COUNT) - return pcie->next_lut_index++; + if (pcie_rc->next_lut_index < PCIE_LUT_ENTRY_COUNT) + return pcie_rc->next_lut_index++; else return -ENOSPC; /* LUT is full */ } -static void lut_writel(struct ls_pcie *pcie, unsigned int value, +static void lut_writel(struct ls_pcie_rc *pcie_rc, unsigned int value, unsigned int offset) { + struct ls_pcie *pcie = pcie_rc->pcie; + if (pcie->big_endian) out_be32(pcie->lut + offset, value); else @@ -45,12 +48,12 @@ static void lut_writel(struct ls_pcie *pcie, unsigned int value, /* * Program a single LUT entry */ -static void ls_pcie_lut_set_mapping(struct ls_pcie *pcie, int index, u32 devid, - u32 streamid) +static void ls_pcie_lut_set_mapping(struct ls_pcie_rc *pcie_rc, int index, + u32 devid, u32 streamid) { /* leave mask as all zeroes, want to match all bits */ - lut_writel(pcie, devid << 16, PCIE_LUT_UDR(index)); - lut_writel(pcie, streamid | PCIE_LUT_ENABLE, PCIE_LUT_LDR(index)); + lut_writel(pcie_rc, devid << 16, PCIE_LUT_UDR(index)); + lut_writel(pcie_rc, streamid | PCIE_LUT_ENABLE, PCIE_LUT_LDR(index)); } /* @@ -61,7 +64,8 @@ static void ls_pcie_lut_set_mapping(struct ls_pcie *pcie, int index, u32 devid, * msi-map = <[devid] [phandle-to-msi-ctrl] [stream-id] [count] * [devid] [phandle-to-msi-ctrl] [stream-id] [count]>; */ -static void fdt_pcie_set_msi_map_entry_ls(void *blob, struct ls_pcie *pcie, +static void fdt_pcie_set_msi_map_entry_ls(void *blob, + struct ls_pcie_rc *pcie_rc, u32 devid, u32 streamid) { u32 *prop; @@ -69,10 +73,11 @@ static void fdt_pcie_set_msi_map_entry_ls(void *blob, struct ls_pcie *pcie, int nodeoffset; uint svr; char *compat = NULL; + struct ls_pcie *pcie = pcie_rc->pcie; /* find pci controller node */ nodeoffset = fdt_node_offset_by_compat_reg(blob, "fsl,ls-pcie", - pcie->dbi_res.start); + pcie_rc->dbi_res.start); if (nodeoffset < 0) { #ifdef CONFIG_FSL_PCIE_COMPAT /* Compatible with older version of dts node */ svr = (get_svr() >> SVR_VAR_PER_SHIFT) & 0xFFFFFE; @@ -84,7 +89,7 @@ static void fdt_pcie_set_msi_map_entry_ls(void *blob, struct ls_pcie *pcie, compat = CONFIG_FSL_PCIE_COMPAT; if (compat) nodeoffset = fdt_node_offset_by_compat_reg(blob, - compat, pcie->dbi_res.start); + compat, pcie_rc->dbi_res.start); #endif if (nodeoffset < 0) return; @@ -114,7 +119,8 @@ static void fdt_pcie_set_msi_map_entry_ls(void *blob, struct ls_pcie *pcie, * iommu-map = <[devid] [phandle-to-iommu-ctrl] [stream-id] [count] * [devid] [phandle-to-iommu-ctrl] [stream-id] [count]>; */ -static void fdt_pcie_set_iommu_map_entry_ls(void *blob, struct ls_pcie *pcie, +static void fdt_pcie_set_iommu_map_entry_ls(void *blob, + struct ls_pcie_rc *pcie_rc, u32 devid, u32 streamid) { u32 *prop; @@ -123,10 +129,11 @@ static void fdt_pcie_set_iommu_map_entry_ls(void *blob, struct ls_pcie *pcie, int lenp; uint svr; char *compat = NULL; + struct ls_pcie *pcie = pcie_rc->pcie; /* find pci controller node */ nodeoffset = fdt_node_offset_by_compat_reg(blob, "fsl,ls-pcie", - pcie->dbi_res.start); + pcie_rc->dbi_res.start); if (nodeoffset < 0) { #ifdef CONFIG_FSL_PCIE_COMPAT /* Compatible with older version of dts node */ svr = (get_svr() >> SVR_VAR_PER_SHIFT) & 0xFFFFFE; @@ -139,7 +146,7 @@ static void fdt_pcie_set_iommu_map_entry_ls(void *blob, struct ls_pcie *pcie, if (compat) nodeoffset = fdt_node_offset_by_compat_reg(blob, - compat, pcie->dbi_res.start); + compat, pcie_rc->dbi_res.start); #endif if (nodeoffset < 0) return; @@ -170,7 +177,7 @@ static void fdt_pcie_set_iommu_map_entry_ls(void *blob, struct ls_pcie *pcie, static void fdt_fixup_pcie_ls(void *blob) { struct udevice *dev, *bus; - struct ls_pcie *pcie; + struct ls_pcie_rc *pcie_rc; int streamid; int index; pci_dev_t bdf; @@ -181,17 +188,18 @@ static void fdt_fixup_pcie_ls(void *blob) pci_find_next_device(&dev)) { for (bus = dev; device_is_on_pci_bus(bus);) bus = bus->parent; - pcie = dev_get_priv(bus); + pcie_rc = dev_get_priv(bus); - streamid = pcie_next_streamid(pcie->stream_id_cur, pcie->idx); + streamid = pcie_next_streamid(pcie_rc->stream_id_cur, + pcie_rc->pcie->idx); if (streamid < 0) { debug("ERROR: no stream ids free\n"); continue; } else { - pcie->stream_id_cur++; + pcie_rc->stream_id_cur++; } - index = ls_pcie_next_lut_index(pcie); + index = ls_pcie_next_lut_index(pcie_rc); if (index < 0) { debug("ERROR: no LUT indexes free\n"); continue; @@ -200,27 +208,28 @@ static void fdt_fixup_pcie_ls(void *blob) /* the DT fixup must be relative to the hose first_busno */ bdf = dm_pci_get_bdf(dev) - PCI_BDF(bus->seq, 0, 0); /* map PCI b.d.f to streamID in LUT */ - ls_pcie_lut_set_mapping(pcie, index, bdf >> 8, + ls_pcie_lut_set_mapping(pcie_rc, index, bdf >> 8, streamid); /* update msi-map in device tree */ - fdt_pcie_set_msi_map_entry_ls(blob, pcie, bdf >> 8, + fdt_pcie_set_msi_map_entry_ls(blob, pcie_rc, bdf >> 8, streamid); /* update iommu-map in device tree */ - fdt_pcie_set_iommu_map_entry_ls(blob, pcie, bdf >> 8, + fdt_pcie_set_iommu_map_entry_ls(blob, pcie_rc, bdf >> 8, streamid); } pcie_board_fix_fdt(blob); } #endif -static void ft_pcie_rc_fix(void *blob, struct ls_pcie *pcie) +static void ft_pcie_rc_fix(void *blob, struct ls_pcie_rc *pcie_rc) { int off; uint svr; char *compat = NULL; + struct ls_pcie *pcie = pcie_rc->pcie; off = fdt_node_offset_by_compat_reg(blob, "fsl,ls-pcie", - pcie->dbi_res.start); + pcie_rc->dbi_res.start); if (off < 0) { #ifdef CONFIG_FSL_PCIE_COMPAT /* Compatible with older version of dts node */ svr = (get_svr() >> SVR_VAR_PER_SHIFT) & 0xFFFFFE; @@ -232,46 +241,47 @@ static void ft_pcie_rc_fix(void *blob, struct ls_pcie *pcie) compat = CONFIG_FSL_PCIE_COMPAT; if (compat) off = fdt_node_offset_by_compat_reg(blob, - compat, pcie->dbi_res.start); + compat, pcie_rc->dbi_res.start); #endif if (off < 0) return; } - if (pcie->enabled && pcie->mode == PCI_HEADER_TYPE_BRIDGE) + if (pcie_rc->enabled && pcie->mode == PCI_HEADER_TYPE_BRIDGE) fdt_set_node_status(blob, off, FDT_STATUS_OKAY, 0); else fdt_set_node_status(blob, off, FDT_STATUS_DISABLED, 0); } -static void ft_pcie_ep_fix(void *blob, struct ls_pcie *pcie) +static void ft_pcie_ep_fix(void *blob, struct ls_pcie_rc *pcie_rc) { int off; + struct ls_pcie *pcie = pcie_rc->pcie; off = fdt_node_offset_by_compat_reg(blob, CONFIG_FSL_PCIE_EP_COMPAT, - pcie->dbi_res.start); + pcie_rc->dbi_res.start); if (off < 0) return; - if (pcie->enabled && pcie->mode == PCI_HEADER_TYPE_NORMAL) + if (pcie_rc->enabled && pcie->mode == PCI_HEADER_TYPE_NORMAL) fdt_set_node_status(blob, off, FDT_STATUS_OKAY, 0); else fdt_set_node_status(blob, off, FDT_STATUS_DISABLED, 0); } -static void ft_pcie_ls_setup(void *blob, struct ls_pcie *pcie) +static void ft_pcie_ls_setup(void *blob, struct ls_pcie_rc *pcie_rc) { - ft_pcie_ep_fix(blob, pcie); - ft_pcie_rc_fix(blob, pcie); + ft_pcie_ep_fix(blob, pcie_rc); + ft_pcie_rc_fix(blob, pcie_rc); } /* Fixup Kernel DT for PCIe */ void ft_pci_setup_ls(void *blob, struct bd_info *bd) { - struct ls_pcie *pcie; + struct ls_pcie_rc *pcie_rc; - list_for_each_entry(pcie, &ls_pcie_list, list) - ft_pcie_ls_setup(blob, pcie); + list_for_each_entry(pcie_rc, &ls_pcie_list, list) + ft_pcie_ls_setup(blob, pcie_rc); #if defined(CONFIG_FSL_LSCH3) || defined(CONFIG_FSL_LSCH2) fdt_fixup_pcie_ls(blob); diff --git a/drivers/pci/pcie_layerscape_gen4.h b/drivers/pci/pcie_layerscape_gen4.h index d298a2b810..483eb538b5 100644 --- a/drivers/pci/pcie_layerscape_gen4.h +++ b/drivers/pci/pcie_layerscape_gen4.h @@ -9,7 +9,6 @@ #ifndef _PCIE_LAYERSCAPE_GEN4_H_ #define _PCIE_LAYERSCAPE_GEN4_H_ #include <pci.h> -#include <dm.h> #include <linux/bitops.h> #ifndef CONFIG_SYS_PCI_MEMORY_SIZE diff --git a/drivers/pci/pcie_layerscape_gen4_fixup.c b/drivers/pci/pcie_layerscape_gen4_fixup.c index 375ce45839..148b5d17ed 100644 --- a/drivers/pci/pcie_layerscape_gen4_fixup.c +++ b/drivers/pci/pcie_layerscape_gen4_fixup.c @@ -8,6 +8,7 @@ */ #include <common.h> +#include <dm.h> #include <log.h> #include <pci.h> #include <asm/arch/fsl_serdes.h> diff --git a/drivers/pci/pcie_layerscape_rc.c b/drivers/pci/pcie_layerscape_rc.c new file mode 100644 index 0000000000..25c6ddebce --- /dev/null +++ b/drivers/pci/pcie_layerscape_rc.c @@ -0,0 +1,379 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2020 NXP + * Layerscape PCIe driver + */ + +#include <common.h> +#include <asm/arch/fsl_serdes.h> +#include <pci.h> +#include <asm/io.h> +#include <errno.h> +#include <malloc.h> +#include <dm.h> +#include <dm/devres.h> +#if defined(CONFIG_FSL_LSCH2) || defined(CONFIG_FSL_LSCH3) || \ + defined(CONFIG_ARM) +#include <asm/arch/clock.h> +#endif +#include "pcie_layerscape.h" + +DECLARE_GLOBAL_DATA_PTR; + +static void ls_pcie_cfg0_set_busdev(struct ls_pcie_rc *pcie_rc, u32 busdev) +{ + struct ls_pcie *pcie = pcie_rc->pcie; + + dbi_writel(pcie, PCIE_ATU_REGION_OUTBOUND | PCIE_ATU_REGION_INDEX0, + PCIE_ATU_VIEWPORT); + dbi_writel(pcie, busdev, PCIE_ATU_LOWER_TARGET); +} + +static void ls_pcie_cfg1_set_busdev(struct ls_pcie_rc *pcie_rc, u32 busdev) +{ + struct ls_pcie *pcie = pcie_rc->pcie; + + dbi_writel(pcie, PCIE_ATU_REGION_OUTBOUND | PCIE_ATU_REGION_INDEX1, + PCIE_ATU_VIEWPORT); + dbi_writel(pcie, busdev, PCIE_ATU_LOWER_TARGET); +} + +static void ls_pcie_setup_atu(struct ls_pcie_rc *pcie_rc) +{ + struct pci_region *io, *mem, *pref; + unsigned long long offset = 0; + struct ls_pcie *pcie = pcie_rc->pcie; + int idx = 0; + uint svr; + + svr = get_svr(); + if (((svr >> SVR_VAR_PER_SHIFT) & SVR_LS102XA_MASK) == SVR_LS102XA) { + offset = LS1021_PCIE_SPACE_OFFSET + + LS1021_PCIE_SPACE_SIZE * pcie->idx; + } + + /* ATU 0 : OUTBOUND : CFG0 */ + ls_pcie_atu_outbound_set(pcie, PCIE_ATU_REGION_INDEX0, + PCIE_ATU_TYPE_CFG0, + pcie_rc->cfg_res.start + offset, + 0, + fdt_resource_size(&pcie_rc->cfg_res) / 2); + /* ATU 1 : OUTBOUND : CFG1 */ + ls_pcie_atu_outbound_set(pcie, PCIE_ATU_REGION_INDEX1, + PCIE_ATU_TYPE_CFG1, + pcie_rc->cfg_res.start + offset + + fdt_resource_size(&pcie_rc->cfg_res) / 2, + 0, + fdt_resource_size(&pcie_rc->cfg_res) / 2); + + pci_get_regions(pcie_rc->bus, &io, &mem, &pref); + idx = PCIE_ATU_REGION_INDEX1 + 1; + + /* Fix the pcie memory map for LS2088A series SoCs */ + svr = (svr >> SVR_VAR_PER_SHIFT) & 0xFFFFFE; + if (svr == SVR_LS2088A || svr == SVR_LS2084A || + svr == SVR_LS2048A || svr == SVR_LS2044A || + svr == SVR_LS2081A || svr == SVR_LS2041A) { + if (io) + io->phys_start = (io->phys_start & + (PCIE_PHYS_SIZE - 1)) + + LS2088A_PCIE1_PHYS_ADDR + + LS2088A_PCIE_PHYS_SIZE * pcie->idx; + if (mem) + mem->phys_start = (mem->phys_start & + (PCIE_PHYS_SIZE - 1)) + + LS2088A_PCIE1_PHYS_ADDR + + LS2088A_PCIE_PHYS_SIZE * pcie->idx; + if (pref) + pref->phys_start = (pref->phys_start & + (PCIE_PHYS_SIZE - 1)) + + LS2088A_PCIE1_PHYS_ADDR + + LS2088A_PCIE_PHYS_SIZE * pcie->idx; + } + + if (io) + /* ATU : OUTBOUND : IO */ + ls_pcie_atu_outbound_set(pcie, idx++, + PCIE_ATU_TYPE_IO, + io->phys_start + offset, + io->bus_start, + io->size); + + if (mem) + /* ATU : OUTBOUND : MEM */ + ls_pcie_atu_outbound_set(pcie, idx++, + PCIE_ATU_TYPE_MEM, + mem->phys_start + offset, + mem->bus_start, + mem->size); + + if (pref) + /* ATU : OUTBOUND : pref */ + ls_pcie_atu_outbound_set(pcie, idx++, + PCIE_ATU_TYPE_MEM, + pref->phys_start + offset, + pref->bus_start, + pref->size); + + ls_pcie_dump_atu(pcie, PCIE_ATU_REGION_NUM, PCIE_ATU_REGION_OUTBOUND); +} + +/* Return 0 if the address is valid, -errno if not valid */ +static int ls_pcie_addr_valid(struct ls_pcie_rc *pcie_rc, pci_dev_t bdf) +{ + struct udevice *bus = pcie_rc->bus; + struct ls_pcie *pcie = pcie_rc->pcie; + + if (pcie->mode == PCI_HEADER_TYPE_NORMAL) + return -ENODEV; + + if (!pcie_rc->enabled) + return -ENXIO; + + if (PCI_BUS(bdf) < bus->seq) + return -EINVAL; + + if ((PCI_BUS(bdf) > bus->seq) && (!ls_pcie_link_up(pcie))) + return -EINVAL; + + if (PCI_BUS(bdf) <= (bus->seq + 1) && (PCI_DEV(bdf) > 0)) + return -EINVAL; + + return 0; +} + +int ls_pcie_conf_address(const struct udevice *bus, pci_dev_t bdf, + uint offset, void **paddress) +{ + struct ls_pcie_rc *pcie_rc = dev_get_priv(bus); + struct ls_pcie *pcie = pcie_rc->pcie; + u32 busdev; + + if (ls_pcie_addr_valid(pcie_rc, bdf)) + return -EINVAL; + + if (PCI_BUS(bdf) == bus->seq) { + *paddress = pcie->dbi + offset; + return 0; + } + + busdev = PCIE_ATU_BUS(PCI_BUS(bdf) - bus->seq) | + PCIE_ATU_DEV(PCI_DEV(bdf)) | + PCIE_ATU_FUNC(PCI_FUNC(bdf)); + + if (PCI_BUS(bdf) == bus->seq + 1) { + ls_pcie_cfg0_set_busdev(pcie_rc, busdev); + *paddress = pcie_rc->cfg0 + offset; + } else { + ls_pcie_cfg1_set_busdev(pcie_rc, busdev); + *paddress = pcie_rc->cfg1 + offset; + } + return 0; +} + +static int ls_pcie_read_config(const struct udevice *bus, pci_dev_t bdf, + uint offset, ulong *valuep, + enum pci_size_t size) +{ + return pci_generic_mmap_read_config(bus, ls_pcie_conf_address, + bdf, offset, valuep, size); +} + +static int ls_pcie_write_config(struct udevice *bus, pci_dev_t bdf, + uint offset, ulong value, + enum pci_size_t size) +{ + return pci_generic_mmap_write_config(bus, ls_pcie_conf_address, + bdf, offset, value, size); +} + +/* Clear multi-function bit */ +static void ls_pcie_clear_multifunction(struct ls_pcie_rc *pcie_rc) +{ + struct ls_pcie *pcie = pcie_rc->pcie; + + writeb(PCI_HEADER_TYPE_BRIDGE, pcie->dbi + PCI_HEADER_TYPE); +} + +/* Fix class value */ +static void ls_pcie_fix_class(struct ls_pcie_rc *pcie_rc) +{ + struct ls_pcie *pcie = pcie_rc->pcie; + + writew(PCI_CLASS_BRIDGE_PCI, pcie->dbi + PCI_CLASS_DEVICE); +} + +/* Drop MSG TLP except for Vendor MSG */ +static void ls_pcie_drop_msg_tlp(struct ls_pcie_rc *pcie_rc) +{ + struct ls_pcie *pcie = pcie_rc->pcie; + u32 val; + + val = dbi_readl(pcie, PCIE_STRFMR1); + val &= 0xDFFFFFFF; + dbi_writel(pcie, val, PCIE_STRFMR1); +} + +/* Disable all bars in RC mode */ +static void ls_pcie_disable_bars(struct ls_pcie_rc *pcie_rc) +{ + struct ls_pcie *pcie = pcie_rc->pcie; + + dbi_writel(pcie, 0, PCIE_CS2_OFFSET + PCI_BASE_ADDRESS_0); + dbi_writel(pcie, 0, PCIE_CS2_OFFSET + PCI_BASE_ADDRESS_1); + dbi_writel(pcie, 0xfffffffe, PCIE_CS2_OFFSET + PCI_ROM_ADDRESS1); +} + +static void ls_pcie_setup_ctrl(struct ls_pcie_rc *pcie_rc) +{ + struct ls_pcie *pcie = pcie_rc->pcie; + + ls_pcie_setup_atu(pcie_rc); + + ls_pcie_dbi_ro_wr_en(pcie); + ls_pcie_fix_class(pcie_rc); + ls_pcie_clear_multifunction(pcie_rc); + ls_pcie_drop_msg_tlp(pcie_rc); + ls_pcie_dbi_ro_wr_dis(pcie); + + ls_pcie_disable_bars(pcie_rc); + pcie_rc->stream_id_cur = 0; +} + +static int ls_pcie_probe(struct udevice *dev) +{ + struct ls_pcie_rc *pcie_rc = dev_get_priv(dev); + const void *fdt = gd->fdt_blob; + int node = dev_of_offset(dev); + struct ls_pcie *pcie; + u16 link_sta; + uint svr; + int ret; + fdt_size_t cfg_size; + + pcie_rc->bus = dev; + + pcie = devm_kmalloc(dev, sizeof(*pcie), GFP_KERNEL); + if (!pcie) + return -ENOMEM; + + pcie_rc->pcie = pcie; + + ret = fdt_get_named_resource(fdt, node, "reg", "reg-names", + "dbi", &pcie_rc->dbi_res); + if (ret) { + printf("ls-pcie: resource \"dbi\" not found\n"); + return ret; + } + + pcie->idx = (pcie_rc->dbi_res.start - PCIE_SYS_BASE_ADDR) / + PCIE_CCSR_SIZE; + + list_add(&pcie_rc->list, &ls_pcie_list); + + pcie_rc->enabled = is_serdes_configured(PCIE_SRDS_PRTCL(pcie->idx)); + if (!pcie_rc->enabled) { + printf("PCIe%d: %s disabled\n", pcie->idx, dev->name); + return 0; + } + + pcie->dbi = map_physmem(pcie_rc->dbi_res.start, + fdt_resource_size(&pcie_rc->dbi_res), + MAP_NOCACHE); + + pcie->mode = readb(pcie->dbi + PCI_HEADER_TYPE) & 0x7f; + if (pcie->mode == PCI_HEADER_TYPE_NORMAL) + return 0; + + ret = fdt_get_named_resource(fdt, node, "reg", "reg-names", + "lut", &pcie_rc->lut_res); + if (!ret) + pcie->lut = map_physmem(pcie_rc->lut_res.start, + fdt_resource_size(&pcie_rc->lut_res), + MAP_NOCACHE); + + ret = fdt_get_named_resource(fdt, node, "reg", "reg-names", + "ctrl", &pcie_rc->ctrl_res); + if (!ret) + pcie->ctrl = map_physmem(pcie_rc->ctrl_res.start, + fdt_resource_size(&pcie_rc->ctrl_res), + MAP_NOCACHE); + if (!pcie->ctrl) + pcie->ctrl = pcie->lut; + + if (!pcie->ctrl) { + printf("%s: NOT find CTRL\n", dev->name); + return -1; + } + + ret = fdt_get_named_resource(fdt, node, "reg", "reg-names", + "config", &pcie_rc->cfg_res); + if (ret) { + printf("%s: resource \"config\" not found\n", dev->name); + return ret; + } + + /* + * Fix the pcie memory map address and PF control registers address + * for LS2088A series SoCs + */ + svr = get_svr(); + svr = (svr >> SVR_VAR_PER_SHIFT) & 0xFFFFFE; + if (svr == SVR_LS2088A || svr == SVR_LS2084A || + svr == SVR_LS2048A || svr == SVR_LS2044A || + svr == SVR_LS2081A || svr == SVR_LS2041A) { + cfg_size = fdt_resource_size(&pcie_rc->cfg_res); + pcie_rc->cfg_res.start = LS2088A_PCIE1_PHYS_ADDR + + LS2088A_PCIE_PHYS_SIZE * pcie->idx; + pcie_rc->cfg_res.end = pcie_rc->cfg_res.start + cfg_size; + pcie->ctrl = pcie->lut + 0x40000; + } + + pcie_rc->cfg0 = map_physmem(pcie_rc->cfg_res.start, + fdt_resource_size(&pcie_rc->cfg_res), + MAP_NOCACHE); + pcie_rc->cfg1 = pcie_rc->cfg0 + + fdt_resource_size(&pcie_rc->cfg_res) / 2; + + pcie->big_endian = fdtdec_get_bool(fdt, node, "big-endian"); + + debug("%s dbi:%lx lut:%lx ctrl:0x%lx cfg0:0x%lx, big-endian:%d\n", + dev->name, (unsigned long)pcie->dbi, (unsigned long)pcie->lut, + (unsigned long)pcie->ctrl, (unsigned long)pcie_rc->cfg0, + pcie->big_endian); + + printf("PCIe%u: %s %s", pcie->idx, dev->name, "Root Complex"); + ls_pcie_setup_ctrl(pcie_rc); + + if (!ls_pcie_link_up(pcie)) { + /* Let the user know there's no PCIe link */ + printf(": no link\n"); + return 0; + } + + /* Print the negotiated PCIe link width */ + link_sta = readw(pcie->dbi + PCIE_LINK_STA); + printf(": x%d gen%d\n", (link_sta & PCIE_LINK_WIDTH_MASK) >> 4, + link_sta & PCIE_LINK_SPEED_MASK); + + return 0; +} + +static const struct dm_pci_ops ls_pcie_ops = { + .read_config = ls_pcie_read_config, + .write_config = ls_pcie_write_config, +}; + +static const struct udevice_id ls_pcie_ids[] = { + { .compatible = "fsl,ls-pcie" }, + { } +}; + +U_BOOT_DRIVER(pci_layerscape) = { + .name = "pci_layerscape", + .id = UCLASS_PCI, + .of_match = ls_pcie_ids, + .ops = &ls_pcie_ops, + .probe = ls_pcie_probe, + .priv_auto_alloc_size = sizeof(struct ls_pcie_rc), +}; diff --git a/drivers/pci_endpoint/pci_ep-uclass.c b/drivers/pci_endpoint/pci_ep-uclass.c index 9f53a9a9b9..38a5f08376 100644 --- a/drivers/pci_endpoint/pci_ep-uclass.c +++ b/drivers/pci_endpoint/pci_ep-uclass.c @@ -209,3 +209,14 @@ UCLASS_DRIVER(pci_ep) = { .name = "pci_ep", .flags = DM_UC_FLAG_SEQ_ALIAS, }; + +void pci_ep_init(void) +{ + struct udevice *dev; + + for (uclass_first_device_check(UCLASS_PCI_EP, &dev); + dev; + uclass_next_device_check(&dev)) { + ; + } +} diff --git a/drivers/pci_endpoint/pcie-cadence-ep.c b/drivers/pci_endpoint/pcie-cadence-ep.c index 59231d340a..74dfdde154 100644 --- a/drivers/pci_endpoint/pcie-cadence-ep.c +++ b/drivers/pci_endpoint/pcie-cadence-ep.c @@ -144,7 +144,7 @@ static int cdns_pci_ep_probe(struct udevice *dev) { struct cdns_pcie *pdata = dev_get_priv(dev); - pdata->reg_base = (void __iomem *)devfdt_get_addr(dev); + pdata->reg_base = dev_read_addr_ptr(dev); if (!pdata->reg_base) return -ENOMEM; diff --git a/drivers/phy/phy-stm32-usbphyc.c b/drivers/phy/phy-stm32-usbphyc.c index 464b0735e8..c6d3048602 100644 --- a/drivers/phy/phy-stm32-usbphyc.c +++ b/drivers/phy/phy-stm32-usbphyc.c @@ -263,7 +263,7 @@ static int stm32_usbphyc_phy_power_off(struct phy *phy) return 0; if (usbphyc_phy->vdd) { - ret = regulator_set_enable(usbphyc_phy->vdd, false); + ret = regulator_set_enable_if_allowed(usbphyc_phy->vdd, false); if (ret) return ret; } diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index 83e39b9de3..bd2061b765 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -294,6 +294,7 @@ source "drivers/pinctrl/meson/Kconfig" source "drivers/pinctrl/mscc/Kconfig" source "drivers/pinctrl/mtmips/Kconfig" source "drivers/pinctrl/mvebu/Kconfig" +source "drivers/pinctrl/nexell/Kconfig" source "drivers/pinctrl/nxp/Kconfig" source "drivers/pinctrl/renesas/Kconfig" source "drivers/pinctrl/rockchip/Kconfig" diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile index 4f662c4f6d..92cff1b100 100644 --- a/drivers/pinctrl/Makefile +++ b/drivers/pinctrl/Makefile @@ -21,6 +21,7 @@ obj-$(CONFIG_PINCTRL_MESON) += meson/ obj-$(CONFIG_PINCTRL_MTK) += mediatek/ obj-$(CONFIG_PINCTRL_MSCC) += mscc/ obj-$(CONFIG_ARCH_MVEBU) += mvebu/ +obj-$(CONFIG_ARCH_NEXELL) += nexell/ obj-$(CONFIG_PINCTRL_SINGLE) += pinctrl-single.o obj-$(CONFIG_PINCTRL_STI) += pinctrl-sti.o obj-$(CONFIG_PINCTRL_STM32) += pinctrl_stm32.o diff --git a/drivers/pinctrl/ath79/pinctrl_ar933x.c b/drivers/pinctrl/ath79/pinctrl_ar933x.c index a0625d7c83..61e8081874 100644 --- a/drivers/pinctrl/ath79/pinctrl_ar933x.c +++ b/drivers/pinctrl/ath79/pinctrl_ar933x.c @@ -111,7 +111,7 @@ static int ar933x_pinctrl_probe(struct udevice *dev) struct ar933x_pinctrl_priv *priv = dev_get_priv(dev); fdt_addr_t addr; - addr = devfdt_get_addr(dev); + addr = dev_read_addr(dev); if (addr == FDT_ADDR_T_NONE) return -EINVAL; diff --git a/drivers/pinctrl/ath79/pinctrl_qca953x.c b/drivers/pinctrl/ath79/pinctrl_qca953x.c index c9f9608c92..2d5a4a3ab2 100644 --- a/drivers/pinctrl/ath79/pinctrl_qca953x.c +++ b/drivers/pinctrl/ath79/pinctrl_qca953x.c @@ -131,7 +131,7 @@ static int qca953x_pinctrl_probe(struct udevice *dev) struct qca953x_pinctrl_priv *priv = dev_get_priv(dev); fdt_addr_t addr; - addr = devfdt_get_addr(dev); + addr = dev_read_addr(dev); if (addr == FDT_ADDR_T_NONE) return -EINVAL; diff --git a/drivers/pinctrl/exynos/pinctrl-exynos.c b/drivers/pinctrl/exynos/pinctrl-exynos.c index e3ac5a6e49..4cdc071d55 100644 --- a/drivers/pinctrl/exynos/pinctrl-exynos.c +++ b/drivers/pinctrl/exynos/pinctrl-exynos.c @@ -127,7 +127,7 @@ int exynos_pinctrl_probe(struct udevice *dev) if (!priv) return -EINVAL; - base = devfdt_get_addr(dev); + base = dev_read_addr(dev); if (base == FDT_ADDR_T_NONE) return -EINVAL; diff --git a/drivers/pinctrl/mediatek/pinctrl-mt7623.c b/drivers/pinctrl/mediatek/pinctrl-mt7623.c index d58d840e08..0f5dcb2c63 100644 --- a/drivers/pinctrl/mediatek/pinctrl-mt7623.c +++ b/drivers/pinctrl/mediatek/pinctrl-mt7623.c @@ -262,6 +262,132 @@ static const struct mtk_pin_field_calc mt7623_pin_drv_range[] = { PIN_FIELD16(278, 278, 0xf70, 0x10, 8, 4), }; +static const struct mtk_pin_field_calc mt7623_pin_pupd_range[] = { + /* MSDC0 */ + PIN_FIELD16(111, 111, 0xd00, 0x10, 12, 1), + PIN_FIELD16(112, 112, 0xd00, 0x10, 8, 1), + PIN_FIELD16(113, 113, 0xd00, 0x10, 4, 1), + PIN_FIELD16(114, 114, 0xd00, 0x10, 0, 1), + PIN_FIELD16(115, 115, 0xd10, 0x10, 0, 1), + PIN_FIELD16(116, 116, 0xcd0, 0x10, 8, 1), + PIN_FIELD16(117, 117, 0xcc0, 0x10, 8, 1), + PIN_FIELD16(118, 118, 0xcf0, 0x10, 12, 1), + PIN_FIELD16(119, 119, 0xcf0, 0x10, 8, 1), + PIN_FIELD16(120, 120, 0xcf0, 0x10, 4, 1), + PIN_FIELD16(121, 121, 0xcf0, 0x10, 0, 1), + /* MSDC1 */ + PIN_FIELD16(105, 105, 0xd40, 0x10, 8, 1), + PIN_FIELD16(106, 106, 0xd30, 0x10, 8, 1), + PIN_FIELD16(107, 107, 0xd60, 0x10, 0, 1), + PIN_FIELD16(108, 108, 0xd60, 0x10, 10, 1), + PIN_FIELD16(109, 109, 0xd60, 0x10, 4, 1), + PIN_FIELD16(110, 110, 0xc60, 0x10, 12, 1), + /* MSDC1 */ + PIN_FIELD16(85, 85, 0xda0, 0x10, 8, 1), + PIN_FIELD16(86, 86, 0xd90, 0x10, 8, 1), + PIN_FIELD16(87, 87, 0xdc0, 0x10, 0, 1), + PIN_FIELD16(88, 88, 0xdc0, 0x10, 10, 1), + PIN_FIELD16(89, 89, 0xdc0, 0x10, 4, 1), + PIN_FIELD16(90, 90, 0xdc0, 0x10, 12, 1), + /* MSDC0E */ + PIN_FIELD16(249, 249, 0x140, 0x10, 0, 1), + PIN_FIELD16(250, 250, 0x130, 0x10, 12, 1), + PIN_FIELD16(251, 251, 0x130, 0x10, 8, 1), + PIN_FIELD16(252, 252, 0x130, 0x10, 4, 1), + PIN_FIELD16(253, 253, 0x130, 0x10, 0, 1), + PIN_FIELD16(254, 254, 0xf40, 0x10, 12, 1), + PIN_FIELD16(255, 255, 0xf40, 0x10, 8, 1), + PIN_FIELD16(256, 256, 0xf40, 0x10, 4, 1), + PIN_FIELD16(257, 257, 0xf40, 0x10, 0, 1), + PIN_FIELD16(258, 258, 0xcb0, 0x10, 8, 1), + PIN_FIELD16(259, 259, 0xc90, 0x10, 8, 1), + PIN_FIELD16(261, 261, 0x140, 0x10, 8, 1), +}; + +static const struct mtk_pin_field_calc mt7623_pin_r1_range[] = { + /* MSDC0 */ + PIN_FIELD16(111, 111, 0xd00, 0x10, 13, 1), + PIN_FIELD16(112, 112, 0xd00, 0x10, 9, 1), + PIN_FIELD16(113, 113, 0xd00, 0x10, 5, 1), + PIN_FIELD16(114, 114, 0xd00, 0x10, 1, 1), + PIN_FIELD16(115, 115, 0xd10, 0x10, 1, 1), + PIN_FIELD16(116, 116, 0xcd0, 0x10, 9, 1), + PIN_FIELD16(117, 117, 0xcc0, 0x10, 9, 1), + PIN_FIELD16(118, 118, 0xcf0, 0x10, 13, 1), + PIN_FIELD16(119, 119, 0xcf0, 0x10, 9, 1), + PIN_FIELD16(120, 120, 0xcf0, 0x10, 5, 1), + PIN_FIELD16(121, 121, 0xcf0, 0x10, 1, 1), + /* MSDC1 */ + PIN_FIELD16(105, 105, 0xd40, 0x10, 9, 1), + PIN_FIELD16(106, 106, 0xd30, 0x10, 9, 1), + PIN_FIELD16(107, 107, 0xd60, 0x10, 1, 1), + PIN_FIELD16(108, 108, 0xd60, 0x10, 9, 1), + PIN_FIELD16(109, 109, 0xd60, 0x10, 5, 1), + PIN_FIELD16(110, 110, 0xc60, 0x10, 13, 1), + /* MSDC2 */ + PIN_FIELD16(85, 85, 0xda0, 0x10, 9, 1), + PIN_FIELD16(86, 86, 0xd90, 0x10, 9, 1), + PIN_FIELD16(87, 87, 0xdc0, 0x10, 1, 1), + PIN_FIELD16(88, 88, 0xdc0, 0x10, 9, 1), + PIN_FIELD16(89, 89, 0xdc0, 0x10, 5, 1), + PIN_FIELD16(90, 90, 0xdc0, 0x10, 13, 1), + /* MSDC0E */ + PIN_FIELD16(249, 249, 0x140, 0x10, 1, 1), + PIN_FIELD16(250, 250, 0x130, 0x10, 13, 1), + PIN_FIELD16(251, 251, 0x130, 0x10, 9, 1), + PIN_FIELD16(252, 252, 0x130, 0x10, 5, 1), + PIN_FIELD16(253, 253, 0x130, 0x10, 1, 1), + PIN_FIELD16(254, 254, 0xf40, 0x10, 13, 1), + PIN_FIELD16(255, 255, 0xf40, 0x10, 9, 1), + PIN_FIELD16(256, 256, 0xf40, 0x10, 5, 1), + PIN_FIELD16(257, 257, 0xf40, 0x10, 1, 1), + PIN_FIELD16(258, 258, 0xcb0, 0x10, 9, 1), + PIN_FIELD16(259, 259, 0xc90, 0x10, 9, 1), + PIN_FIELD16(261, 261, 0x140, 0x10, 9, 1), +}; + +static const struct mtk_pin_field_calc mt7623_pin_r0_range[] = { + /* MSDC0 */ + PIN_FIELD16(111, 111, 0xd00, 0x10, 14, 1), + PIN_FIELD16(112, 112, 0xd00, 0x10, 10, 1), + PIN_FIELD16(113, 113, 0xd00, 0x10, 6, 1), + PIN_FIELD16(114, 114, 0xd00, 0x10, 2, 1), + PIN_FIELD16(115, 115, 0xd10, 0x10, 2, 1), + PIN_FIELD16(116, 116, 0xcd0, 0x10, 10, 1), + PIN_FIELD16(117, 117, 0xcc0, 0x10, 10, 1), + PIN_FIELD16(118, 118, 0xcf0, 0x10, 14, 1), + PIN_FIELD16(119, 119, 0xcf0, 0x10, 10, 1), + PIN_FIELD16(120, 120, 0xcf0, 0x10, 6, 1), + PIN_FIELD16(121, 121, 0xcf0, 0x10, 2, 1), + /* MSDC1 */ + PIN_FIELD16(105, 105, 0xd40, 0x10, 10, 1), + PIN_FIELD16(106, 106, 0xd30, 0x10, 10, 1), + PIN_FIELD16(107, 107, 0xd60, 0x10, 2, 1), + PIN_FIELD16(108, 108, 0xd60, 0x10, 8, 1), + PIN_FIELD16(109, 109, 0xd60, 0x10, 6, 1), + PIN_FIELD16(110, 110, 0xc60, 0x10, 14, 1), + /* MSDC2 */ + PIN_FIELD16(85, 85, 0xda0, 0x10, 10, 1), + PIN_FIELD16(86, 86, 0xd90, 0x10, 10, 1), + PIN_FIELD16(87, 87, 0xdc0, 0x10, 2, 1), + PIN_FIELD16(88, 88, 0xdc0, 0x10, 8, 1), + PIN_FIELD16(89, 89, 0xdc0, 0x10, 6, 1), + PIN_FIELD16(90, 90, 0xdc0, 0x10, 14, 1), + /* MSDC0E */ + PIN_FIELD16(249, 249, 0x140, 0x10, 2, 1), + PIN_FIELD16(250, 250, 0x130, 0x10, 14, 1), + PIN_FIELD16(251, 251, 0x130, 0x10, 10, 1), + PIN_FIELD16(252, 252, 0x130, 0x10, 6, 1), + PIN_FIELD16(253, 253, 0x130, 0x10, 2, 1), + PIN_FIELD16(254, 254, 0xf40, 0x10, 14, 1), + PIN_FIELD16(255, 255, 0xf40, 0x10, 10, 1), + PIN_FIELD16(256, 256, 0xf40, 0x10, 6, 1), + PIN_FIELD16(257, 257, 0xf40, 0x10, 5, 1), + PIN_FIELD16(258, 258, 0xcb0, 0x10, 10, 1), + PIN_FIELD16(259, 259, 0xc90, 0x10, 10, 1), + PIN_FIELD16(261, 261, 0x140, 0x10, 10, 1), +}; + static const struct mtk_pin_reg_calc mt7623_reg_cals[] = { [PINCTRL_PIN_REG_MODE] = MTK_RANGE(mt7623_pin_mode_range), [PINCTRL_PIN_REG_DIR] = MTK_RANGE(mt7623_pin_dir_range), @@ -272,6 +398,9 @@ static const struct mtk_pin_reg_calc mt7623_reg_cals[] = { [PINCTRL_PIN_REG_PULLSEL] = MTK_RANGE(mt7623_pin_pullsel_range), [PINCTRL_PIN_REG_PULLEN] = MTK_RANGE(mt7623_pin_pullen_range), [PINCTRL_PIN_REG_DRV] = MTK_RANGE(mt7623_pin_drv_range), + [PINCTRL_PIN_REG_PUPD] = MTK_RANGE(mt7623_pin_pupd_range), + [PINCTRL_PIN_REG_R0] = MTK_RANGE(mt7623_pin_r0_range), + [PINCTRL_PIN_REG_R1] = MTK_RANGE(mt7623_pin_r1_range), }; static const struct mtk_pin_desc mt7623_pins[] = { diff --git a/drivers/pinctrl/mediatek/pinctrl-mtk-common.c b/drivers/pinctrl/mediatek/pinctrl-mtk-common.c index e8187a3780..6553dde45c 100644 --- a/drivers/pinctrl/mediatek/pinctrl-mtk-common.c +++ b/drivers/pinctrl/mediatek/pinctrl-mtk-common.c @@ -296,7 +296,7 @@ static const struct pinconf_param mtk_conf_params[] = { }; -int mtk_pinconf_bias_set_v0(struct udevice *dev, u32 pin, u32 arg) +int mtk_pinconf_bias_set_v0(struct udevice *dev, u32 pin, u32 arg, u32 val) { int err, disable, pullup; @@ -323,12 +323,14 @@ int mtk_pinconf_bias_set_v0(struct udevice *dev, u32 pin, u32 arg) return 0; } -int mtk_pinconf_bias_set_v1(struct udevice *dev, u32 pin, u32 arg) +int mtk_pinconf_bias_set_v1(struct udevice *dev, u32 pin, u32 arg, u32 val) { - int err, disable, pullup; + int err, disable, pullup, r0, r1; disable = (arg == PIN_CONFIG_BIAS_DISABLE); pullup = (arg == PIN_CONFIG_BIAS_PULL_UP); + r0 = !!(val & 1); + r1 = !!(val & 2); if (disable) { err = mtk_hw_set_value(dev, pin, PINCTRL_PIN_REG_PULLEN, 0); @@ -344,6 +346,13 @@ int mtk_pinconf_bias_set_v1(struct udevice *dev, u32 pin, u32 arg) return err; } + /* Also set PUPD/R0/R1 if the pin has them */ + err = mtk_hw_set_value(dev, pin, PINCTRL_PIN_REG_PUPD, !pullup); + if (err != -EINVAL) { + mtk_hw_set_value(dev, pin, PINCTRL_PIN_REG_R0, r0); + mtk_hw_set_value(dev, pin, PINCTRL_PIN_REG_R1, r1); + } + return 0; } @@ -419,9 +428,9 @@ static int mtk_pinconf_set(struct udevice *dev, unsigned int pin, case PIN_CONFIG_BIAS_PULL_UP: case PIN_CONFIG_BIAS_PULL_DOWN: if (rev == MTK_PINCTRL_V0) - err = mtk_pinconf_bias_set_v0(dev, pin, param); + err = mtk_pinconf_bias_set_v0(dev, pin, param, arg); else - err = mtk_pinconf_bias_set_v1(dev, pin, param); + err = mtk_pinconf_bias_set_v1(dev, pin, param, arg); if (err) goto err; break; diff --git a/drivers/pinctrl/mediatek/pinctrl-mtk-common.h b/drivers/pinctrl/mediatek/pinctrl-mtk-common.h index e815761450..5e51a9a90c 100644 --- a/drivers/pinctrl/mediatek/pinctrl-mtk-common.h +++ b/drivers/pinctrl/mediatek/pinctrl-mtk-common.h @@ -51,6 +51,9 @@ enum { PINCTRL_PIN_REG_PULLEN, PINCTRL_PIN_REG_PULLSEL, PINCTRL_PIN_REG_DRV, + PINCTRL_PIN_REG_PUPD, + PINCTRL_PIN_REG_R0, + PINCTRL_PIN_REG_R1, PINCTRL_PIN_REG_MAX, }; diff --git a/drivers/pinctrl/mvebu/pinctrl-armada-37xx.c b/drivers/pinctrl/mvebu/pinctrl-armada-37xx.c index 2dee79af17..fb497803b9 100644 --- a/drivers/pinctrl/mvebu/pinctrl-armada-37xx.c +++ b/drivers/pinctrl/mvebu/pinctrl-armada-37xx.c @@ -592,7 +592,7 @@ int armada_37xx_pinctrl_probe(struct udevice *dev) info->data = (struct armada_37xx_pin_data *)dev_get_driver_data(dev); pin_data = info->data; - info->base = (void __iomem *)devfdt_get_addr(dev); + info->base = dev_read_addr_ptr(dev); if (!info->base) { pr_err("unable to find regmap\n"); return -ENODEV; diff --git a/drivers/pinctrl/nexell/Kconfig b/drivers/pinctrl/nexell/Kconfig new file mode 100644 index 0000000000..8f1e472239 --- /dev/null +++ b/drivers/pinctrl/nexell/Kconfig @@ -0,0 +1,18 @@ +if ARCH_NEXELL + +config PINCTRL_NEXELL + bool "Nexell pinctrl driver" + help + Support of pin multiplexing and pin configuration for Nexell + SoCs. + +config PINCTRL_NEXELL_S5PXX18 + bool "Nexell s5pxx18 SoC pinctrl driver" + default y if ARCH_S5P4418 || ARCH_S5P6818 + depends on ARCH_NEXELL && PINCTRL_FULL + select PINCTRL_NEXELL + help + Support of pin multiplexing and pin configuration for S5P4418 + and S5P6818 SoC. + +endif diff --git a/drivers/pinctrl/nexell/Makefile b/drivers/pinctrl/nexell/Makefile new file mode 100644 index 0000000000..74df414d55 --- /dev/null +++ b/drivers/pinctrl/nexell/Makefile @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: GPL-2.0+ +# +# (C) Copyright 2016 Nexell +# Bongyu, KOO <freestyle@nexell.co.kr> + +obj-$(CONFIG_PINCTRL_NEXELL) += pinctrl-nexell.o +obj-$(CONFIG_PINCTRL_NEXELL_S5PXX18) += pinctrl-s5pxx18.o diff --git a/drivers/pinctrl/nexell/pinctrl-nexell.c b/drivers/pinctrl/nexell/pinctrl-nexell.c new file mode 100644 index 0000000000..4518c05d46 --- /dev/null +++ b/drivers/pinctrl/nexell/pinctrl-nexell.c @@ -0,0 +1,66 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Pinctrl driver for Nexell SoCs + * (C) Copyright 2016 Nexell + * Bongyu, KOO <freestyle@nexell.co.kr> + */ + +#include <common.h> +#include <dm.h> +#include <errno.h> +#include <asm/io.h> +#include "pinctrl-nexell.h" +#include "pinctrl-s5pxx18.h" + +DECLARE_GLOBAL_DATA_PTR; + +/* given a pin-name, return the address of pin config registers */ +unsigned long pin_to_bank_base(struct udevice *dev, const char *pin_name, + u32 *pin) +{ + struct nexell_pinctrl_priv *priv = dev_get_priv(dev); + const struct nexell_pin_ctrl *pin_ctrl = priv->pin_ctrl; + const struct nexell_pin_bank_data *bank_data = pin_ctrl->pin_banks; + u32 nr_banks = pin_ctrl->nr_banks, idx = 0; + char bank[10]; + + /* + * The format of the pin name is <bank name>-<pin_number>. + * Example: gpioa-4 (gpioa is the bank name and 4 is the pin number) + */ + while (pin_name[idx] != '-') { + bank[idx] = pin_name[idx]; + idx++; + } + bank[idx] = '\0'; + *pin = (u32)simple_strtoul(&pin_name[++idx], NULL, 10); + + /* lookup the pin bank data using the pin bank name */ + for (idx = 0; idx < nr_banks; idx++) + if (!strcmp(bank, bank_data[idx].name)) + break; + + return priv->base + bank_data[idx].offset; +} + +int nexell_pinctrl_probe(struct udevice *dev) +{ + struct nexell_pinctrl_priv *priv; + fdt_addr_t base; + + priv = dev_get_priv(dev); + if (!priv) + return -EINVAL; + + base = devfdt_get_addr(dev); + if (base == FDT_ADDR_T_NONE) + return -EINVAL; + + priv->base = base; + + priv->pin_ctrl = (struct nexell_pin_ctrl *)dev_get_driver_data(dev); + + s5pxx18_pinctrl_init(dev); + + return 0; +} diff --git a/drivers/pinctrl/nexell/pinctrl-nexell.h b/drivers/pinctrl/nexell/pinctrl-nexell.h new file mode 100644 index 0000000000..b21eefcabe --- /dev/null +++ b/drivers/pinctrl/nexell/pinctrl-nexell.h @@ -0,0 +1,68 @@ +/* SPDX-License-Identifier: GPL-2.0+ + * + * Pinctrl driver for Nexell SoCs + * (C) Copyright 2016 Nexell + * Bongyu, KOO <freestyle@nexell.co.kr> + * + */ + +#ifndef __PINCTRL_NEXELL_H_ +#define __PINCTRL_NEXELL_H_ + +/** + * struct nexell_pin_bank_data: represent a controller pin-bank data. + * @offset: starting offset of the pin-bank registers. + * @nr_pins: number of pins included in this bank. + * @name: name to be prefixed for each pin in this pin bank. + */ +struct nexell_pin_bank_data { + u32 offset; + u8 nr_pins; + const char *name; + u8 type; +}; + +#define NEXELL_PIN_BANK(pins, reg, id) \ + { \ + .offset = reg, \ + .nr_pins = pins, \ + .name = id \ + } + +/** + * struct nexell_pin_ctrl: represent a pin controller. + * @pin_banks: list of pin banks included in this controller. + * @nr_banks: number of pin banks. + */ +struct nexell_pin_ctrl { + const struct nexell_pin_bank_data *pin_banks; + u32 nr_banks; +}; + +/** + * struct nexell_pinctrl_priv: nexell pin controller driver private data + * @pin_ctrl: pin controller bank information. + * @base: base address of the pin controller instance. + */ +struct nexell_pinctrl_priv { + const struct nexell_pin_ctrl *pin_ctrl; + unsigned long base; +}; + +/** + * struct nexell_pinctrl_config_data: configuration for a peripheral. + * @offset: offset of the config registers in the controller. + * @mask: value of the register to be masked with. + * @value: new value to be programmed. + */ +struct nexell_pinctrl_config_data { + const unsigned int offset; + const unsigned int mask; + const unsigned int value; +}; + +unsigned long pin_to_bank_base(struct udevice *dev, const char *pin_name, + u32 *pin); +int nexell_pinctrl_probe(struct udevice *dev); + +#endif /* __PINCTRL_NEXELL_H_ */ diff --git a/drivers/pinctrl/nexell/pinctrl-s5pxx18.c b/drivers/pinctrl/nexell/pinctrl-s5pxx18.c new file mode 100644 index 0000000000..96a2ed38a0 --- /dev/null +++ b/drivers/pinctrl/nexell/pinctrl-s5pxx18.c @@ -0,0 +1,220 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Pinctrl driver for Nexell SoCs + * (C) Copyright 2016 Nexell + * Bongyu, KOO <freestyle@nexell.co.kr> + * + * (C) Copyright 2019 Stefan Bosch <stefan_b@posteo.net> + */ + +#include <common.h> +#include <dm.h> +#include <errno.h> +#include <asm/io.h> +#include <dm/pinctrl.h> +#include <dm/root.h> +#include "pinctrl-nexell.h" +#include "pinctrl-s5pxx18.h" + +DECLARE_GLOBAL_DATA_PTR; + +static void nx_gpio_set_bit(u32 *value, u32 bit, int enable) +{ + register u32 newvalue; + + newvalue = *value; + newvalue &= ~(1ul << bit); + newvalue |= (u32)enable << bit; + writel(newvalue, value); +} + +static void nx_gpio_set_bit2(u32 *value, u32 bit, u32 bit_value) +{ + register u32 newvalue = *value; + + newvalue = (u32)(newvalue & ~(3ul << (bit * 2))); + newvalue = (u32)(newvalue | (bit_value << (bit * 2))); + + writel(newvalue, value); +} + +static int nx_gpio_open_module(void *base) +{ + writel(0xFFFFFFFF, base + GPIOX_SLEW_DISABLE_DEFAULT); + writel(0xFFFFFFFF, base + GPIOX_DRV1_DISABLE_DEFAULT); + writel(0xFFFFFFFF, base + GPIOX_DRV0_DISABLE_DEFAULT); + writel(0xFFFFFFFF, base + GPIOX_PULLSEL_DISABLE_DEFAULT); + writel(0xFFFFFFFF, base + GPIOX_PULLENB_DISABLE_DEFAULT); + return true; +} + +static void nx_gpio_set_pad_function(void *base, u32 pin, u32 padfunc) +{ + u32 reg = (pin / 16) ? GPIOX_ALTFN1 : GPIOX_ALTFN0; + + nx_gpio_set_bit2(base + reg, pin % 16, padfunc); +} + +static void nx_gpio_set_drive_strength(void *base, u32 pin, u32 drv) +{ + nx_gpio_set_bit(base + GPIOX_DRV1, pin, (int)(((u32)drv >> 0) & 0x1)); + nx_gpio_set_bit(base + GPIOX_DRV0, pin, (int)(((u32)drv >> 1) & 0x1)); +} + +static void nx_gpio_set_pull_mode(void *base, u32 pin, u32 mode) +{ + if (mode == nx_gpio_pull_off) { + nx_gpio_set_bit(base + GPIOX_PULLENB, pin, false); + nx_gpio_set_bit(base + GPIOX_PULLSEL, pin, false); + } else { + nx_gpio_set_bit(base + GPIOX_PULLSEL, + pin, (mode & 1 ? true : false)); + nx_gpio_set_bit(base + GPIOX_PULLENB, pin, true); + } +} + +static void nx_alive_set_pullup(void *base, u32 pin, bool enable) +{ + u32 PULLUP_MASK; + + PULLUP_MASK = (1UL << pin); + if (enable) + writel(PULLUP_MASK, base + ALIVE_PADPULLUPSET); + else + writel(PULLUP_MASK, base + ALIVE_PADPULLUPRST); +} + +static int s5pxx18_pinctrl_gpio_init(struct udevice *dev) +{ + struct nexell_pinctrl_priv *priv = dev_get_priv(dev); + const struct nexell_pin_ctrl *ctrl = priv->pin_ctrl; + unsigned long reg = priv->base; + int i; + + for (i = 0; i < ctrl->nr_banks - 1; i++) /* except alive bank */ + nx_gpio_open_module((void *)(reg + ctrl->pin_banks[i].offset)); + + return 0; +} + +static int s5pxx18_pinctrl_alive_init(struct udevice *dev) +{ + struct nexell_pinctrl_priv *priv = dev_get_priv(dev); + const struct nexell_pin_ctrl *ctrl = priv->pin_ctrl; + unsigned long reg = priv->base; + + reg += ctrl->pin_banks[ctrl->nr_banks - 1].offset; + + writel(1, reg + ALIVE_PWRGATE); + return 0; +} + +int s5pxx18_pinctrl_init(struct udevice *dev) +{ + s5pxx18_pinctrl_gpio_init(dev); + s5pxx18_pinctrl_alive_init(dev); + + return 0; +} + +static int is_pin_alive(const char *name) +{ + return !strncmp(name, "alive", 5); +} + +/** + * s5pxx18_pinctrl_set_state: configure a pin state. + * dev: the pinctrl device to be configured. + * config: the state to be configured. + */ +static int s5pxx18_pinctrl_set_state(struct udevice *dev, + struct udevice *config) +{ + unsigned int count, idx, pin; + unsigned int pinfunc, pinpud, pindrv; + unsigned long reg; + const char *name; + int ret; + + /* + * refer to the following document for the pinctrl bindings + * doc/device-tree-bindings/pinctrl/nexell,s5pxx18-pinctrl.txt + */ + count = dev_read_string_count(config, "pins"); + + if (count <= 0) + return -EINVAL; + + pinfunc = dev_read_s32_default(config, "pin-function", -1); + pinpud = dev_read_s32_default(config, "pin-pull", -1); + pindrv = dev_read_s32_default(config, "pin-strength", -1); + + for (idx = 0; idx < count; idx++) { + ret = dev_read_string_index(config, "pins", idx, &name); + if (ret) + return ret; + if (!name) + continue; + reg = pin_to_bank_base(dev, name, &pin); + + if (is_pin_alive(name)) { + /* pin pull up/down */ + if (pinpud != -1) + nx_alive_set_pullup((void *)reg, pin, + pinpud & 1); + continue; + } + + /* pin function */ + if (pinfunc != -1) + nx_gpio_set_pad_function((void *)reg, pin, pinfunc); + + /* pin pull up/down/off */ + if (pinpud != -1) + nx_gpio_set_pull_mode((void *)reg, pin, pinpud); + + /* pin drive strength */ + if (pindrv != -1) + nx_gpio_set_drive_strength((void *)reg, pin, pindrv); + } + + return 0; +} + +static struct pinctrl_ops s5pxx18_pinctrl_ops = { + .set_state = s5pxx18_pinctrl_set_state, +}; + +/* pin banks of s5pxx18 pin-controller */ +static const struct nexell_pin_bank_data s5pxx18_pin_banks[] = { + NEXELL_PIN_BANK(32, 0xA000, "gpioa"), + NEXELL_PIN_BANK(32, 0xB000, "gpiob"), + NEXELL_PIN_BANK(32, 0xC000, "gpioc"), + NEXELL_PIN_BANK(32, 0xD000, "gpiod"), + NEXELL_PIN_BANK(32, 0xE000, "gpioe"), + NEXELL_PIN_BANK(6, 0x0800, "alive"), +}; + +const struct nexell_pin_ctrl s5pxx18_pin_ctrl[] = { + { + /* pin-controller data */ + .pin_banks = s5pxx18_pin_banks, + .nr_banks = ARRAY_SIZE(s5pxx18_pin_banks), + }, +}; + +static const struct udevice_id s5pxx18_pinctrl_ids[] = { + { .compatible = "nexell,s5pxx18-pinctrl", + .data = (ulong)s5pxx18_pin_ctrl }, + { } +}; + +U_BOOT_DRIVER(pinctrl_s5pxx18) = { + .name = "pinctrl_s5pxx18", + .id = UCLASS_PINCTRL, + .of_match = s5pxx18_pinctrl_ids, + .priv_auto_alloc_size = sizeof(struct nexell_pinctrl_priv), + .ops = &s5pxx18_pinctrl_ops, + .probe = nexell_pinctrl_probe, + .flags = DM_FLAG_PRE_RELOC +}; diff --git a/drivers/pinctrl/nexell/pinctrl-s5pxx18.h b/drivers/pinctrl/nexell/pinctrl-s5pxx18.h new file mode 100644 index 0000000000..843a00b955 --- /dev/null +++ b/drivers/pinctrl/nexell/pinctrl-s5pxx18.h @@ -0,0 +1,53 @@ +/* SPDX-License-Identifier: GPL-2.0+ + * + * Pinctrl driver for Nexell SoCs + * (C) Copyright 2016 Nexell + * Bongyu, KOO <freestyle@nexell.co.kr> + */ + +#ifndef __PINCTRL_S5PXX18_H_ +#define __PINCTRL_S5PXX18_H_ + +#include <linux/types.h> +#include <asm/io.h> + +#define GPIOX_ALTFN0 0x20 +#define GPIOX_ALTFN1 0x24 +#define GPIOX_DRV1 0x48 +#define GPIOX_DRV0 0x50 +#define GPIOX_PULLSEL 0x58 +#define GPIOX_PULLENB 0x60 + +#define GPIOX_SLEW_DISABLE_DEFAULT 0x44 +#define GPIOX_DRV1_DISABLE_DEFAULT 0x4C +#define GPIOX_DRV0_DISABLE_DEFAULT 0x54 +#define GPIOX_PULLSEL_DISABLE_DEFAULT 0x5C +#define GPIOX_PULLENB_DISABLE_DEFAULT 0x64 + +#define ALIVE_PWRGATE 0x0 +#define ALIVE_PADPULLUPRST 0x80 +#define ALIVE_PADPULLUPSET 0x84 +#define ALIVE_PADPULLUPREAD 0x88 + +enum { + nx_gpio_padfunc_0 = 0ul, + nx_gpio_padfunc_1 = 1ul, + nx_gpio_padfunc_2 = 2ul, + nx_gpio_padfunc_3 = 3ul +}; + +enum { + nx_gpio_drvstrength_0 = 0ul, + nx_gpio_drvstrength_1 = 1ul, + nx_gpio_drvstrength_2 = 2ul, + nx_gpio_drvstrength_3 = 3ul +}; + +enum { + nx_gpio_pull_down = 0ul, + nx_gpio_pull_up = 1ul, + nx_gpio_pull_off = 2ul +}; + +int s5pxx18_pinctrl_init(struct udevice *dev); +#endif /* __PINCTRL_S5PXX18_H_ */ diff --git a/drivers/pinctrl/pinctrl-at91-pio4.c b/drivers/pinctrl/pinctrl-at91-pio4.c index 801d14253c..fdb7920b55 100644 --- a/drivers/pinctrl/pinctrl-at91-pio4.c +++ b/drivers/pinctrl/pinctrl-at91-pio4.c @@ -158,7 +158,7 @@ static int atmel_pinctrl_probe(struct udevice *dev) fdt_addr_t addr_base; dev = dev_get_parent(dev); - addr_base = devfdt_get_addr(dev); + addr_base = dev_read_addr(dev); if (addr_base == FDT_ADDR_T_NONE) return -EINVAL; diff --git a/drivers/pinctrl/renesas/Kconfig b/drivers/pinctrl/renesas/Kconfig index 4d3d68d307..8327bcabd6 100644 --- a/drivers/pinctrl/renesas/Kconfig +++ b/drivers/pinctrl/renesas/Kconfig @@ -77,6 +77,16 @@ config PINCTRL_PFC_R8A7796 the GPIO definitions and pin control functions for each available multiplex function. +config PINCTRL_PFC_R8A774A1 + bool "Renesas RCar Gen3 R8A774A1 pin control driver" + depends on PINCTRL_PFC + help + Support pin multiplexing control on Renesas RZG2M R8A774A1 SoCs. + + The driver is controlled by a device tree node which contains both + the GPIO definitions and pin control functions for each available + multiplex function. + config PINCTRL_PFC_R8A77965 bool "Renesas RCar Gen3 R8A77965 pin control driver" depends on PINCTRL_PFC diff --git a/drivers/pinctrl/renesas/Makefile b/drivers/pinctrl/renesas/Makefile index a92f787a89..a4eb912d54 100644 --- a/drivers/pinctrl/renesas/Makefile +++ b/drivers/pinctrl/renesas/Makefile @@ -1,4 +1,5 @@ obj-$(CONFIG_PINCTRL_PFC) += pfc.o +obj-$(CONFIG_PINCTRL_PFC_R8A774A1) += pfc-r8a7796.o obj-$(CONFIG_PINCTRL_PFC_R8A7790) += pfc-r8a7790.o obj-$(CONFIG_PINCTRL_PFC_R8A7791) += pfc-r8a7791.o obj-$(CONFIG_PINCTRL_PFC_R8A7792) += pfc-r8a7792.o diff --git a/drivers/pinctrl/renesas/pfc-r7s72100.c b/drivers/pinctrl/renesas/pfc-r7s72100.c index 5055780bf7..9d7814a5f2 100644 --- a/drivers/pinctrl/renesas/pfc-r7s72100.c +++ b/drivers/pinctrl/renesas/pfc-r7s72100.c @@ -112,7 +112,7 @@ static int r7s72100_pfc_probe(struct udevice *dev) fdt_addr_t addr_base; ofnode node; - addr_base = devfdt_get_addr(dev); + addr_base = dev_read_addr(dev); if (addr_base == FDT_ADDR_T_NONE) return -EINVAL; diff --git a/drivers/pinctrl/renesas/pfc.c b/drivers/pinctrl/renesas/pfc.c index 1179afd2e7..7183b11808 100644 --- a/drivers/pinctrl/renesas/pfc.c +++ b/drivers/pinctrl/renesas/pfc.c @@ -32,6 +32,7 @@ enum sh_pfc_model { SH_PFC_R8A7794, SH_PFC_R8A7795, SH_PFC_R8A7796, + SH_PFC_R8A774A1, SH_PFC_R8A77965, SH_PFC_R8A77970, SH_PFC_R8A77980, @@ -817,7 +818,7 @@ static int sh_pfc_pinctrl_probe(struct udevice *dev) enum sh_pfc_model model = dev_get_driver_data(dev); fdt_addr_t base; - base = devfdt_get_addr(dev); + base = dev_read_addr(dev); if (base == FDT_ADDR_T_NONE) return -EINVAL; @@ -853,6 +854,10 @@ static int sh_pfc_pinctrl_probe(struct udevice *dev) if (model == SH_PFC_R8A7796) priv->pfc.info = &r8a7796_pinmux_info; #endif +#ifdef CONFIG_PINCTRL_PFC_R8A774A1 + if (model == SH_PFC_R8A774A1) + priv->pfc.info = &r8a774a1_pinmux_info; +#endif #ifdef CONFIG_PINCTRL_PFC_R8A77965 if (model == SH_PFC_R8A77965) priv->pfc.info = &r8a77965_pinmux_info; @@ -924,6 +929,12 @@ static const struct udevice_id sh_pfc_pinctrl_ids[] = { .data = SH_PFC_R8A7796, }, #endif +#ifdef CONFIG_PINCTRL_PFC_R8A774A1 + { + .compatible = "renesas,pfc-r8a774a1", + .data = SH_PFC_R8A774A1, + }, +#endif #ifdef CONFIG_PINCTRL_PFC_R8A77965 { .compatible = "renesas,pfc-r8a77965", diff --git a/drivers/pinctrl/renesas/sh_pfc.h b/drivers/pinctrl/renesas/sh_pfc.h index db3d513358..81c0179948 100644 --- a/drivers/pinctrl/renesas/sh_pfc.h +++ b/drivers/pinctrl/renesas/sh_pfc.h @@ -293,6 +293,7 @@ const struct pinmux_bias_reg * sh_pfc_pin_to_bias_reg(const struct sh_pfc *pfc, unsigned int pin, unsigned int *bit); +extern const struct sh_pfc_soc_info r8a774a1_pinmux_info; extern const struct sh_pfc_soc_info r8a7790_pinmux_info; extern const struct sh_pfc_soc_info r8a7791_pinmux_info; extern const struct sh_pfc_soc_info r8a7792_pinmux_info; diff --git a/drivers/pinctrl/uniphier/pinctrl-uniphier-core.c b/drivers/pinctrl/uniphier/pinctrl-uniphier-core.c index 8545b9d070..631bb1f963 100644 --- a/drivers/pinctrl/uniphier/pinctrl-uniphier-core.c +++ b/drivers/pinctrl/uniphier/pinctrl-uniphier-core.c @@ -422,7 +422,7 @@ int uniphier_pinctrl_probe(struct udevice *dev, struct uniphier_pinctrl_priv *priv = dev_get_priv(dev); fdt_addr_t addr; - addr = devfdt_get_addr(dev->parent); + addr = dev_read_addr(dev->parent); if (addr == FDT_ADDR_T_NONE) return -EINVAL; diff --git a/drivers/power/regulator/fixed.c b/drivers/power/regulator/fixed.c index b5f7aec353..2fa6c7e6b2 100644 --- a/drivers/power/regulator/fixed.c +++ b/drivers/power/regulator/fixed.c @@ -5,7 +5,6 @@ * Przemyslaw Marczak <p.marczak@samsung.com> */ -#include "regulator_common.h" #include <common.h> #include <errno.h> #include <dm.h> @@ -13,6 +12,8 @@ #include <power/pmic.h> #include <power/regulator.h> +#include "regulator_common.h" + static int fixed_regulator_ofdata_to_platdata(struct udevice *dev) { struct dm_regulator_uclass_platdata *uc_pdata; diff --git a/drivers/power/regulator/gpio-regulator.c b/drivers/power/regulator/gpio-regulator.c index cf3fbae79d..947f812d09 100644 --- a/drivers/power/regulator/gpio-regulator.c +++ b/drivers/power/regulator/gpio-regulator.c @@ -4,7 +4,6 @@ * Keerthy <j-keerthy@ti.com> */ -#include "regulator_common.h" #include <common.h> #include <fdtdec.h> #include <errno.h> @@ -15,6 +14,8 @@ #include <power/pmic.h> #include <power/regulator.h> +#include "regulator_common.h" + #define GPIO_REGULATOR_MAX_STATES 2 DECLARE_GLOBAL_DATA_PTR; diff --git a/drivers/power/regulator/regulator_common.c b/drivers/power/regulator/regulator_common.c index 4cfcc31298..13906b9c6e 100644 --- a/drivers/power/regulator/regulator_common.c +++ b/drivers/power/regulator/regulator_common.c @@ -4,12 +4,14 @@ * Sven Schwermer <sven.svenschwermer@disruptive-technologies.com> */ -#include "regulator_common.h" #include <common.h> +#include <dm.h> #include <log.h> #include <linux/delay.h> #include <power/regulator.h> +#include "regulator_common.h" + int regulator_common_ofdata_to_platdata(struct udevice *dev, struct regulator_common_platdata *dev_pdata, const char *enable_gpio_name) { diff --git a/drivers/power/regulator/regulator_common.h b/drivers/power/regulator/regulator_common.h index 18a525880a..bf80439c78 100644 --- a/drivers/power/regulator/regulator_common.h +++ b/drivers/power/regulator/regulator_common.h @@ -7,9 +7,7 @@ #ifndef _REGULATOR_COMMON_H #define _REGULATOR_COMMON_H -#include <common.h> #include <asm/gpio.h> -#include <dm.h> struct regulator_common_platdata { struct gpio_desc gpio; /* GPIO for regulator enable control */ diff --git a/drivers/pwm/exynos_pwm.c b/drivers/pwm/exynos_pwm.c index fed1583796..e55fcceafd 100644 --- a/drivers/pwm/exynos_pwm.c +++ b/drivers/pwm/exynos_pwm.c @@ -92,7 +92,7 @@ static int exynos_pwm_ofdata_to_platdata(struct udevice *dev) { struct exynos_pwm_priv *priv = dev_get_priv(dev); - priv->regs = (struct s5p_timer *)devfdt_get_addr(dev); + priv->regs = dev_read_addr_ptr(dev); return 0; } diff --git a/drivers/pwm/pwm-imx.c b/drivers/pwm/pwm-imx.c index f5b9544cb8..77a1907fd3 100644 --- a/drivers/pwm/pwm-imx.c +++ b/drivers/pwm/pwm-imx.c @@ -130,7 +130,7 @@ static int imx_pwm_ofdata_to_platdata(struct udevice *dev) { struct imx_pwm_priv *priv = dev_get_priv(dev); - priv->regs = (struct pwm_regs *)devfdt_get_addr(dev); + priv->regs = dev_read_addr_ptr(dev); return 0; } diff --git a/drivers/pwm/pwm-mtk.c b/drivers/pwm/pwm-mtk.c index 97ed477025..7bd82518d6 100644 --- a/drivers/pwm/pwm-mtk.c +++ b/drivers/pwm/pwm-mtk.c @@ -130,7 +130,7 @@ static int mtk_pwm_probe(struct udevice *dev) int i; priv->soc = (struct mtk_pwm_soc *)dev_get_driver_data(dev); - priv->base = (void __iomem *)devfdt_get_addr(dev); + priv->base = dev_read_addr_ptr(dev); if (!priv->base) return -EINVAL; ret = clk_get_by_name(dev, "top", &priv->top_clk); diff --git a/drivers/pwm/sunxi_pwm.c b/drivers/pwm/sunxi_pwm.c index 56215dbf6c..e2ae1a8009 100644 --- a/drivers/pwm/sunxi_pwm.c +++ b/drivers/pwm/sunxi_pwm.c @@ -152,7 +152,7 @@ static int sunxi_pwm_ofdata_to_platdata(struct udevice *dev) { struct sunxi_pwm_priv *priv = dev_get_priv(dev); - priv->regs = (struct sunxi_pwm *)devfdt_get_addr(dev); + priv->regs = dev_read_addr_ptr(dev); return 0; } diff --git a/drivers/ram/k3-am654-ddrss.c b/drivers/ram/k3-am654-ddrss.c index 8bbd8cfa83..21e5a65529 100644 --- a/drivers/ram/k3-am654-ddrss.c +++ b/drivers/ram/k3-am654-ddrss.c @@ -13,7 +13,6 @@ #include <ram.h> #include <asm/io.h> #include <power-domain.h> -#include <dm.h> #include <asm/arch/sys_proto.h> #include <dm/device_compat.h> #include <power/regulator.h> diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig index 6d53561223..253902ff57 100644 --- a/drivers/reset/Kconfig +++ b/drivers/reset/Kconfig @@ -148,6 +148,15 @@ config RESET_IMX7 help Support for reset controller on i.MX7/8 SoCs. +config RESET_SIFIVE + bool "Reset Driver for SiFive SoC's" + depends on DM_RESET && CLK_SIFIVE_FU540_PRCI && TARGET_SIFIVE_FU540 + default y + help + PRCI module within SiFive SoC's provides mechanism to reset + different hw blocks like DDR, gemgxl. With this driver we leverage + U-Boot's reset framework to reset these hardware blocks. + config RESET_SYSCON bool "Enable generic syscon reset driver support" depends on DM_RESET diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile index 8e0124b8de..3c7f066ae3 100644 --- a/drivers/reset/Makefile +++ b/drivers/reset/Makefile @@ -23,5 +23,6 @@ obj-$(CONFIG_RESET_MTMIPS) += reset-mtmips.o obj-$(CONFIG_RESET_SUNXI) += reset-sunxi.o obj-$(CONFIG_RESET_HISILICON) += reset-hisilicon.o obj-$(CONFIG_RESET_IMX7) += reset-imx7.o +obj-$(CONFIG_RESET_SIFIVE) += reset-sifive.o obj-$(CONFIG_RESET_SYSCON) += reset-syscon.o obj-$(CONFIG_RESET_RASPBERRYPI) += reset-raspberrypi.o diff --git a/drivers/reset/reset-sifive.c b/drivers/reset/reset-sifive.c new file mode 100644 index 0000000000..527757f853 --- /dev/null +++ b/drivers/reset/reset-sifive.c @@ -0,0 +1,118 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2020 Sifive, Inc. + * Author: Sagar Kadam <sagar.kadam@sifive.com> + */ + +#include <common.h> +#include <dm.h> +#include <reset-uclass.h> +#include <asm/io.h> +#include <dm/device_compat.h> +#include <dm/lists.h> +#include <linux/bitops.h> + +#define PRCI_RESETREG_OFFSET 0x28 + +struct sifive_reset_priv { + void *base; + /* number of reset signals */ + int nr_reset; +}; + +static int sifive_rst_trigger(struct reset_ctl *rst, bool level) +{ + struct sifive_reset_priv *priv = dev_get_priv(rst->dev); + int id = rst->id; + int regval = readl(priv->base + PRCI_RESETREG_OFFSET); + + /* Derive bitposition from rst id */ + if (level) + /* Reset deassert */ + regval |= BIT(id); + else + /* Reset assert */ + regval &= ~BIT(id); + + writel(regval, priv->base + PRCI_RESETREG_OFFSET); + + return 0; +} + +static int sifive_reset_assert(struct reset_ctl *rst) +{ + return sifive_rst_trigger(rst, false); +} + +static int sifive_reset_deassert(struct reset_ctl *rst) +{ + return sifive_rst_trigger(rst, true); +} + +static int sifive_reset_request(struct reset_ctl *rst) +{ + struct sifive_reset_priv *priv = dev_get_priv(rst->dev); + + debug("%s(rst=%p) (dev=%p, id=%lu) (nr_reset=%d)\n", __func__, + rst, rst->dev, rst->id, priv->nr_reset); + + if (rst->id > priv->nr_reset) + return -EINVAL; + + return 0; +} + +static int sifive_reset_free(struct reset_ctl *rst) +{ + struct sifive_reset_priv *priv = dev_get_priv(rst->dev); + + debug("%s(rst=%p) (dev=%p, id=%lu) (nr_reset=%d)\n", __func__, + rst, rst->dev, rst->id, priv->nr_reset); + + return 0; +} + +static int sifive_reset_probe(struct udevice *dev) +{ + struct sifive_reset_priv *priv = dev_get_priv(dev); + + priv->base = dev_remap_addr(dev); + if (!priv->base) + return -ENOMEM; + + return 0; +} + +int sifive_reset_bind(struct udevice *dev, ulong count) +{ + struct udevice *rst_dev; + struct sifive_reset_priv *priv; + int ret; + + ret = device_bind_driver_to_node(dev, "sifive-reset", "reset", + dev_ofnode(dev), &rst_dev); + if (ret) { + dev_err(dev, "failed to bind sifive_reset driver (ret=%d)\n", ret); + return ret; + } + priv = malloc(sizeof(struct sifive_reset_priv)); + priv->nr_reset = count; + rst_dev->priv = priv; + + return 0; +} + +const struct reset_ops sifive_reset_ops = { + .request = sifive_reset_request, + .rfree = sifive_reset_free, + .rst_assert = sifive_reset_assert, + .rst_deassert = sifive_reset_deassert, +}; + +U_BOOT_DRIVER(sifive_reset) = { + .name = "sifive-reset", + .id = UCLASS_RESET, + .ops = &sifive_reset_ops, + .probe = sifive_reset_probe, + .priv_auto_alloc_size = sizeof(struct sifive_reset_priv), +}; diff --git a/drivers/reset/reset-uniphier.c b/drivers/reset/reset-uniphier.c index 06079d2a9c..fe1bd5541b 100644 --- a/drivers/reset/reset-uniphier.c +++ b/drivers/reset/reset-uniphier.c @@ -247,7 +247,7 @@ static int uniphier_reset_probe(struct udevice *dev) struct uniphier_reset_priv *priv = dev_get_priv(dev); fdt_addr_t addr; - addr = devfdt_get_addr(dev->parent); + addr = dev_read_addr(dev->parent); if (addr == FDT_ADDR_T_NONE) return -EINVAL; diff --git a/drivers/rtc/mvrtc.c b/drivers/rtc/mvrtc.c index 6f49505d4e..ed057f7bc4 100644 --- a/drivers/rtc/mvrtc.c +++ b/drivers/rtc/mvrtc.c @@ -172,7 +172,7 @@ static int mv_rtc_ofdata_to_platdata(struct udevice *dev) { struct mvrtc_pdata *pdata = dev_get_platdata(dev); - pdata->iobase = devfdt_get_addr(dev); + pdata->iobase = dev_read_addr(dev); return 0; } diff --git a/drivers/serial/altera_jtag_uart.c b/drivers/serial/altera_jtag_uart.c index 7a86161a0d..35b76f53f9 100644 --- a/drivers/serial/altera_jtag_uart.c +++ b/drivers/serial/altera_jtag_uart.c @@ -95,7 +95,7 @@ static int altera_jtaguart_ofdata_to_platdata(struct udevice *dev) { struct altera_jtaguart_platdata *plat = dev_get_platdata(dev); - plat->regs = map_physmem(devfdt_get_addr(dev), + plat->regs = map_physmem(dev_read_addr(dev), sizeof(struct altera_jtaguart_regs), MAP_NOCACHE); diff --git a/drivers/serial/altera_uart.c b/drivers/serial/altera_uart.c index f88a293d56..0be5cd75c8 100644 --- a/drivers/serial/altera_uart.c +++ b/drivers/serial/altera_uart.c @@ -87,7 +87,7 @@ static int altera_uart_ofdata_to_platdata(struct udevice *dev) { struct altera_uart_platdata *plat = dev_get_platdata(dev); - plat->regs = map_physmem(devfdt_get_addr(dev), + plat->regs = map_physmem(dev_read_addr(dev), sizeof(struct altera_uart_regs), MAP_NOCACHE); plat->uartclk = dev_read_u32_default(dev, "clock-frequency", 0); diff --git a/drivers/serial/atmel_usart.c b/drivers/serial/atmel_usart.c index 71cb31ff75..f759ea8893 100644 --- a/drivers/serial/atmel_usart.c +++ b/drivers/serial/atmel_usart.c @@ -268,7 +268,7 @@ static int atmel_serial_probe(struct udevice *dev) #if CONFIG_IS_ENABLED(OF_CONTROL) fdt_addr_t addr_base; - addr_base = devfdt_get_addr(dev); + addr_base = dev_read_addr(dev); if (addr_base == FDT_ADDR_T_NONE) return -ENODEV; diff --git a/drivers/serial/serial_ar933x.c b/drivers/serial/serial_ar933x.c index 382c3b3d34..9de94b69bd 100644 --- a/drivers/serial/serial_ar933x.c +++ b/drivers/serial/serial_ar933x.c @@ -150,7 +150,7 @@ static int ar933x_serial_probe(struct udevice *dev) fdt_addr_t addr; u32 val; - addr = devfdt_get_addr(dev); + addr = dev_read_addr(dev); if (addr == FDT_ADDR_T_NONE) return -EINVAL; diff --git a/drivers/serial/serial_arc.c b/drivers/serial/serial_arc.c index 70dbc6d6b5..04063fbe39 100644 --- a/drivers/serial/serial_arc.c +++ b/drivers/serial/serial_arc.c @@ -114,7 +114,7 @@ static int arc_serial_ofdata_to_platdata(struct udevice *dev) struct arc_serial_platdata *plat = dev_get_platdata(dev); DECLARE_GLOBAL_DATA_PTR; - plat->reg = (struct arc_serial_regs *)devfdt_get_addr(dev); + plat->reg = dev_read_addr_ptr(dev); plat->uartclk = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev), "clock-frequency", 0); diff --git a/drivers/serial/serial_bcm283x_mu.c b/drivers/serial/serial_bcm283x_mu.c index 0102b10ed2..8a4af87eb6 100644 --- a/drivers/serial/serial_bcm283x_mu.c +++ b/drivers/serial/serial_bcm283x_mu.c @@ -171,7 +171,7 @@ static int bcm283x_mu_serial_probe(struct udevice *dev) * since we need the soc simple-bus to be probed so that the 'ranges' * property is used. */ - addr = devfdt_get_addr(dev); + addr = dev_read_addr(dev); if (addr == FDT_ADDR_T_NONE) return -EINVAL; diff --git a/drivers/serial/serial_lpuart.c b/drivers/serial/serial_lpuart.c index 0c63c41270..95cbe63b3d 100644 --- a/drivers/serial/serial_lpuart.c +++ b/drivers/serial/serial_lpuart.c @@ -518,7 +518,7 @@ static int lpuart_serial_ofdata_to_platdata(struct udevice *dev) int node = dev_of_offset(dev); fdt_addr_t addr; - addr = devfdt_get_addr(dev); + addr = dev_read_addr(dev); if (addr == FDT_ADDR_T_NONE) return -EINVAL; diff --git a/drivers/serial/serial_mcf.c b/drivers/serial/serial_mcf.c index b599064b48..402fd5343c 100644 --- a/drivers/serial/serial_mcf.c +++ b/drivers/serial/serial_mcf.c @@ -145,7 +145,7 @@ static int coldfire_ofdata_to_platdata(struct udevice *dev) struct coldfire_serial_platdata *plat = dev_get_platdata(dev); fdt_addr_t addr_base; - addr_base = devfdt_get_addr(dev); + addr_base = dev_read_addr(dev); if (addr_base == FDT_ADDR_T_NONE) return -ENODEV; diff --git a/drivers/serial/serial_meson.c b/drivers/serial/serial_meson.c index 439057b1b9..496a2ca2c3 100644 --- a/drivers/serial/serial_meson.c +++ b/drivers/serial/serial_meson.c @@ -65,14 +65,36 @@ static int meson_serial_probe(struct udevice *dev) return 0; } +static void meson_serial_rx_error(struct udevice *dev) +{ + struct meson_serial_platdata *plat = dev->platdata; + struct meson_uart *const uart = plat->reg; + u32 val = readl(&uart->control); + + /* Clear error */ + val |= AML_UART_CLR_ERR; + writel(val, &uart->control); + val &= ~AML_UART_CLR_ERR; + writel(val, &uart->control); + + /* Remove spurious byte from fifo */ + readl(&uart->rfifo); +} + static int meson_serial_getc(struct udevice *dev) { struct meson_serial_platdata *plat = dev->platdata; struct meson_uart *const uart = plat->reg; + uint32_t status = readl(&uart->status); - if (readl(&uart->status) & AML_UART_RX_EMPTY) + if (status & AML_UART_RX_EMPTY) return -EAGAIN; + if (status & AML_UART_ERR) { + meson_serial_rx_error(dev); + return -EIO; + } + return readl(&uart->rfifo) & 0xff; } @@ -95,10 +117,23 @@ static int meson_serial_pending(struct udevice *dev, bool input) struct meson_uart *const uart = plat->reg; uint32_t status = readl(&uart->status); - if (input) - return !(status & AML_UART_RX_EMPTY); - else + if (input) { + if (status & AML_UART_RX_EMPTY) + return false; + + /* + * Handle and drop any RX error here to avoid + * returning true here when an error byte is in the FIFO + */ + if (status & AML_UART_ERR) { + meson_serial_rx_error(dev); + return false; + } + + return true; + } else { return !(status & AML_UART_TX_FULL); + } } static int meson_serial_ofdata_to_platdata(struct udevice *dev) @@ -106,7 +141,7 @@ static int meson_serial_ofdata_to_platdata(struct udevice *dev) struct meson_serial_platdata *plat = dev->platdata; fdt_addr_t addr; - addr = devfdt_get_addr(dev); + addr = dev_read_addr(dev); if (addr == FDT_ADDR_T_NONE) return -EINVAL; diff --git a/drivers/serial/serial_msm.c b/drivers/serial/serial_msm.c index 0cc1aadce4..c8946c3aae 100644 --- a/drivers/serial/serial_msm.c +++ b/drivers/serial/serial_msm.c @@ -61,6 +61,7 @@ struct msm_serial_data { phys_addr_t base; unsigned chars_cnt; /* number of buffered chars */ uint32_t chars_buf; /* buffered chars */ + uint32_t clk_bit_rate; /* data mover mode bit rate register value */ }; static int msm_serial_fetch(struct udevice *dev) @@ -190,7 +191,7 @@ static int msm_uart_clk_init(struct udevice *dev) static void uart_dm_init(struct msm_serial_data *priv) { - writel(UART_DM_CLK_RX_TX_BIT_RATE, priv->base + UARTDM_CSR); + writel(priv->clk_bit_rate, priv->base + UARTDM_CSR); writel(0x0, priv->base + UARTDM_MR1); writel(MSM_BOOT_UART_DM_8_N_1_MODE, priv->base + UARTDM_MR2); writel(MSM_BOOT_UART_DM_CMD_RESET_RX, priv->base + UARTDM_CR); @@ -219,10 +220,13 @@ static int msm_serial_ofdata_to_platdata(struct udevice *dev) { struct msm_serial_data *priv = dev_get_priv(dev); - priv->base = devfdt_get_addr(dev); + priv->base = dev_read_addr(dev); if (priv->base == FDT_ADDR_T_NONE) return -EINVAL; + priv->clk_bit_rate = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev), + "bit-rate", UART_DM_CLK_RX_TX_BIT_RATE); + return 0; } diff --git a/drivers/serial/serial_mxc.c b/drivers/serial/serial_mxc.c index 42abb96a26..de6cefcd3a 100644 --- a/drivers/serial/serial_mxc.c +++ b/drivers/serial/serial_mxc.c @@ -330,7 +330,7 @@ static int mxc_serial_ofdata_to_platdata(struct udevice *dev) struct mxc_serial_platdata *plat = dev->platdata; fdt_addr_t addr; - addr = devfdt_get_addr(dev); + addr = dev_read_addr(dev); if (addr == FDT_ADDR_T_NONE) return -EINVAL; diff --git a/drivers/serial/serial_pl01x.c b/drivers/serial/serial_pl01x.c index 6e5d81ce34..2772c25f1d 100644 --- a/drivers/serial/serial_pl01x.c +++ b/drivers/serial/serial_pl01x.c @@ -354,7 +354,7 @@ int pl01x_serial_ofdata_to_platdata(struct udevice *dev) fdt_addr_t addr; int ret; - addr = devfdt_get_addr(dev); + addr = dev_read_addr(dev); if (addr == FDT_ADDR_T_NONE) return -EINVAL; diff --git a/drivers/serial/serial_s5p.c b/drivers/serial/serial_s5p.c index e3160cf1bd..9bb2be21e7 100644 --- a/drivers/serial/serial_s5p.c +++ b/drivers/serial/serial_s5p.c @@ -181,7 +181,7 @@ static int s5p_serial_ofdata_to_platdata(struct udevice *dev) struct s5p_serial_platdata *plat = dev->platdata; fdt_addr_t addr; - addr = devfdt_get_addr(dev); + addr = dev_read_addr(dev); if (addr == FDT_ADDR_T_NONE) return -EINVAL; diff --git a/drivers/serial/serial_sh.c b/drivers/serial/serial_sh.c index 5f45d58e58..13b179f03d 100644 --- a/drivers/serial/serial_sh.c +++ b/drivers/serial/serial_sh.c @@ -211,7 +211,7 @@ static int sh_serial_ofdata_to_platdata(struct udevice *dev) fdt_addr_t addr; int ret; - addr = devfdt_get_addr(dev); + addr = dev_read_addr(dev); if (!addr) return -EINVAL; diff --git a/drivers/serial/serial_sti_asc.c b/drivers/serial/serial_sti_asc.c index 5fbbfac820..33ff396bff 100644 --- a/drivers/serial/serial_sti_asc.c +++ b/drivers/serial/serial_sti_asc.c @@ -171,7 +171,7 @@ static int sti_asc_serial_probe(struct udevice *dev) unsigned long val; fdt_addr_t base; - base = devfdt_get_addr(dev); + base = dev_read_addr(dev); if (base == FDT_ADDR_T_NONE) return -EINVAL; diff --git a/drivers/serial/serial_stm32.c b/drivers/serial/serial_stm32.c index e77b90670a..cab0db2c96 100644 --- a/drivers/serial/serial_stm32.c +++ b/drivers/serial/serial_stm32.c @@ -221,7 +221,7 @@ static int stm32_serial_ofdata_to_platdata(struct udevice *dev) { struct stm32x7_serial_platdata *plat = dev_get_platdata(dev); - plat->base = devfdt_get_addr(dev); + plat->base = dev_read_addr(dev); if (plat->base == FDT_ADDR_T_NONE) return -EINVAL; diff --git a/drivers/serial/serial_uniphier.c b/drivers/serial/serial_uniphier.c index ad691b66da..4004cb8d48 100644 --- a/drivers/serial/serial_uniphier.c +++ b/drivers/serial/serial_uniphier.c @@ -115,7 +115,7 @@ static int uniphier_serial_probe(struct udevice *dev) fdt_addr_t base; u32 tmp; - base = devfdt_get_addr(dev); + base = dev_read_addr(dev); if (base == FDT_ADDR_T_NONE) return -EINVAL; diff --git a/drivers/serial/serial_xuartlite.c b/drivers/serial/serial_xuartlite.c index f29a9a0b56..5116d13751 100644 --- a/drivers/serial/serial_xuartlite.c +++ b/drivers/serial/serial_xuartlite.c @@ -85,7 +85,7 @@ static int uartlite_serial_ofdata_to_platdata(struct udevice *dev) { struct uartlite_platdata *plat = dev_get_platdata(dev); - plat->regs = (struct uartlite *)devfdt_get_addr(dev); + plat->regs = dev_read_addr_ptr(dev); return 0; } diff --git a/drivers/soc/Kconfig b/drivers/soc/Kconfig index 7b4e4d6130..864d00a885 100644 --- a/drivers/soc/Kconfig +++ b/drivers/soc/Kconfig @@ -1,5 +1,21 @@ menu "SOC (System On Chip) specific Drivers" +config SOC_DEVICE + bool "Enable SoC Device ID drivers using Driver Model" + help + This allows drivers to be provided for SoCs to help in identifying + the SoC in use and matching SoC attributes for selecting SoC + specific data. This is useful for other device drivers that may + need different parameters or quirks enabled depending on the + specific device variant in use. + +config SOC_DEVICE_TI_K3 + depends on SOC_DEVICE + bool "Enable SoC Device ID driver for TI K3 SoCs" + help + This allows Texas Instruments Keystone 3 SoCs to identify + specifics about the SoC in use. + source "drivers/soc/ti/Kconfig" endmenu diff --git a/drivers/soc/Makefile b/drivers/soc/Makefile index ce253b7aa8..9ef20ca506 100644 --- a/drivers/soc/Makefile +++ b/drivers/soc/Makefile @@ -3,3 +3,6 @@ # Makefile for the U-Boot SOC specific device drivers. obj-$(CONFIG_SOC_TI) += ti/ +obj-$(CONFIG_SOC_DEVICE) += soc-uclass.o +obj-$(CONFIG_SOC_DEVICE_TI_K3) += soc_ti_k3.o +obj-$(CONFIG_SANDBOX) += soc_sandbox.o diff --git a/drivers/soc/soc-uclass.c b/drivers/soc/soc-uclass.c new file mode 100644 index 0000000000..c32d647864 --- /dev/null +++ b/drivers/soc/soc-uclass.c @@ -0,0 +1,102 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (C) Copyright 2020 - Texas Instruments Incorporated - http://www.ti.com/ + * Dave Gerlach <d-gerlach@ti.com> + */ + +#include <common.h> +#include <soc.h> +#include <dm.h> +#include <errno.h> +#include <dm/lists.h> +#include <dm/root.h> + +int soc_get(struct udevice **devp) +{ + return uclass_first_device_err(UCLASS_SOC, devp); +} + +int soc_get_machine(struct udevice *dev, char *buf, int size) +{ + struct soc_ops *ops = soc_get_ops(dev); + + if (!ops->get_machine) + return -ENOSYS; + + return ops->get_machine(dev, buf, size); +} + +int soc_get_family(struct udevice *dev, char *buf, int size) +{ + struct soc_ops *ops = soc_get_ops(dev); + + if (!ops->get_family) + return -ENOSYS; + + return ops->get_family(dev, buf, size); +} + +int soc_get_revision(struct udevice *dev, char *buf, int size) +{ + struct soc_ops *ops = soc_get_ops(dev); + + if (!ops->get_revision) + return -ENOSYS; + + return ops->get_revision(dev, buf, size); +} + +const struct soc_attr * +soc_device_match(const struct soc_attr *matches) +{ + bool match; + struct udevice *soc; + char str[SOC_MAX_STR_SIZE]; + + if (!matches) + return NULL; + + if (soc_get(&soc)) + return NULL; + + while (1) { + if (!(matches->machine || matches->family || + matches->revision)) + break; + + match = true; + + if (matches->machine) { + if (!soc_get_machine(soc, str, SOC_MAX_STR_SIZE)) { + if (strcmp(matches->machine, str)) + match = false; + } + } + + if (matches->family) { + if (!soc_get_family(soc, str, SOC_MAX_STR_SIZE)) { + if (strcmp(matches->family, str)) + match = false; + } + } + + if (matches->revision) { + if (!soc_get_revision(soc, str, SOC_MAX_STR_SIZE)) { + if (strcmp(matches->revision, str)) + match = false; + } + } + + if (match) + return matches; + + matches++; + } + + return NULL; +} + +UCLASS_DRIVER(soc) = { + .id = UCLASS_SOC, + .name = "soc", +}; diff --git a/drivers/soc/soc_sandbox.c b/drivers/soc/soc_sandbox.c new file mode 100644 index 0000000000..5c82ad84fc --- /dev/null +++ b/drivers/soc/soc_sandbox.c @@ -0,0 +1,56 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Sandbox driver for the SOC uclass + * + * (C) Copyright 2020 - Texas Instruments Incorporated - http://www.ti.com/ + * Dave Gerlach <d-gerlach@ti.com> + */ + +#include <common.h> +#include <dm.h> +#include <soc.h> + +int soc_sandbox_get_family(struct udevice *dev, char *buf, int size) +{ + snprintf(buf, size, "SANDBOX1xx"); + + return 0; +} + +int soc_sandbox_get_machine(struct udevice *dev, char *buf, int size) +{ + snprintf(buf, size, "SANDBOX123"); + + return 0; +} + +int soc_sandbox_get_revision(struct udevice *dev, char *buf, int size) +{ + snprintf(buf, size, "1.0"); + + return 0; +} + +static const struct soc_ops soc_sandbox_ops = { + .get_family = soc_sandbox_get_family, + .get_revision = soc_sandbox_get_revision, + .get_machine = soc_sandbox_get_machine, +}; + +int soc_sandbox_probe(struct udevice *dev) +{ + return 0; +} + +static const struct udevice_id soc_sandbox_ids[] = { + { .compatible = "sandbox,soc" }, + { } +}; + +U_BOOT_DRIVER(soc_sandbox) = { + .name = "soc_sandbox", + .id = UCLASS_SOC, + .ops = &soc_sandbox_ops, + .of_match = soc_sandbox_ids, + .probe = soc_sandbox_probe, +}; diff --git a/drivers/soc/soc_ti_k3.c b/drivers/soc/soc_ti_k3.c new file mode 100644 index 0000000000..ae23ef7475 --- /dev/null +++ b/drivers/soc/soc_ti_k3.c @@ -0,0 +1,124 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2020 Texas Instruments Incorporated - http://www.ti.com/ + * Dave Gerlach <d-gerlach@ti.com> + */ + +#include <common.h> +#include <dm.h> +#include <soc.h> + +#include <asm/io.h> + +#define AM65X 0xbb5a +#define J721E 0xbb64 + +#define REV_SR1_0 0 +#define REV_SR2_0 1 + +#define JTAG_ID_VARIANT_SHIFT 28 +#define JTAG_ID_VARIANT_MASK (0xf << 28) +#define JTAG_ID_PARTNO_SHIFT 12 +#define JTAG_ID_PARTNO_MASK (0xffff << 12) + +struct soc_ti_k3_platdata { + const char *family; + const char *revision; +}; + +static const char *get_family_string(u32 idreg) +{ + const char *family; + u32 soc; + + soc = (idreg & JTAG_ID_PARTNO_MASK) >> JTAG_ID_PARTNO_SHIFT; + + switch (soc) { + case AM65X: + family = "AM65X"; + break; + case J721E: + family = "J721E"; + break; + default: + family = "Unknown Silicon"; + }; + + return family; +} + +static const char *get_rev_string(u32 idreg) +{ + const char *revision; + u32 rev; + + rev = (idreg & JTAG_ID_VARIANT_MASK) >> JTAG_ID_VARIANT_SHIFT; + + switch (rev) { + case REV_SR1_0: + revision = "1.0"; + break; + case REV_SR2_0: + revision = "2.0"; + break; + default: + revision = "Unknown Revision"; + }; + + return revision; +} + +static int soc_ti_k3_get_family(struct udevice *dev, char *buf, int size) +{ + struct soc_ti_k3_platdata *plat = dev_get_platdata(dev); + + snprintf(buf, size, "%s", plat->family); + + return 0; +} + +static int soc_ti_k3_get_revision(struct udevice *dev, char *buf, int size) +{ + struct soc_ti_k3_platdata *plat = dev_get_platdata(dev); + + snprintf(buf, size, "SR%s", plat->revision); + + return 0; +} + +static const struct soc_ops soc_ti_k3_ops = { + .get_family = soc_ti_k3_get_family, + .get_revision = soc_ti_k3_get_revision, +}; + +int soc_ti_k3_probe(struct udevice *dev) +{ + struct soc_ti_k3_platdata *plat = dev_get_platdata(dev); + u32 idreg; + void *idreg_addr; + + idreg_addr = dev_read_addr_ptr(dev); + if (!idreg_addr) + return -EINVAL; + + idreg = readl(idreg_addr); + + plat->family = get_family_string(idreg); + plat->revision = get_rev_string(idreg); + + return 0; +} + +static const struct udevice_id soc_ti_k3_ids[] = { + { .compatible = "ti,am654-chipid" }, + { } +}; + +U_BOOT_DRIVER(soc_ti_k3) = { + .name = "soc_ti_k3", + .id = UCLASS_SOC, + .ops = &soc_ti_k3_ops, + .of_match = soc_ti_k3_ids, + .probe = soc_ti_k3_probe, + .platdata_auto_alloc_size = sizeof(struct soc_ti_k3_platdata), +}; diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 30d808d7bb..3fc2d0674a 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -240,6 +240,14 @@ config NXP_FSPI Enable the NXP FlexSPI (FSPI) driver. This driver can be used to access the SPI NOR flash on platforms embedding this NXP IP core. +config OCTEON_SPI + bool "Octeon SPI driver" + depends on DM_PCI && (ARCH_OCTEON || ARCH_OCTEONTX || ARCH_OCTEONTX2) + help + Enable the Octeon SPI driver. This driver can be used to + access the SPI NOR flash on Octeon II/III and OcteonTX/TX2 + SoC platforms. + config OMAP3_SPI bool "McSPI driver for OMAP" help diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index 4e7461771f..b5c9ff1af8 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -43,6 +43,7 @@ obj-$(CONFIG_MXC_SPI) += mxc_spi.o obj-$(CONFIG_MXS_SPI) += mxs_spi.o obj-$(CONFIG_NXP_FSPI) += nxp_fspi.o obj-$(CONFIG_ATCSPI200_SPI) += atcspi200_spi.o +obj-$(CONFIG_OCTEON_SPI) += octeon_spi.o obj-$(CONFIG_OMAP3_SPI) += omap3_spi.o obj-$(CONFIG_PIC32_SPI) += pic32_spi.o obj-$(CONFIG_PL022_SPI) += pl022_spi.o diff --git a/drivers/spi/altera_spi.c b/drivers/spi/altera_spi.c index 3aa7a40b77..61372c52b0 100644 --- a/drivers/spi/altera_spi.c +++ b/drivers/spi/altera_spi.c @@ -173,7 +173,7 @@ static int altera_spi_ofdata_to_platdata(struct udevice *bus) { struct altera_spi_platdata *plat = dev_get_platdata(bus); - plat->regs = map_physmem(devfdt_get_addr(bus), + plat->regs = map_physmem(dev_read_addr(bus), sizeof(struct altera_spi_regs), MAP_NOCACHE); diff --git a/drivers/spi/atcspi200_spi.c b/drivers/spi/atcspi200_spi.c index 328b16c277..39c6e226ba 100644 --- a/drivers/spi/atcspi200_spi.c +++ b/drivers/spi/atcspi200_spi.c @@ -378,7 +378,7 @@ static int atcspi200_ofdata_to_platadata(struct udevice *bus) const void *blob = gd->fdt_blob; int node = dev_of_offset(bus); - ns->regs = map_physmem(devfdt_get_addr(bus), + ns->regs = map_physmem(dev_read_addr(bus), sizeof(struct atcspi200_spi_regs), MAP_NOCACHE); if (!ns->regs) { diff --git a/drivers/spi/ath79_spi.c b/drivers/spi/ath79_spi.c index f64a28c6e0..70bedc7fbe 100644 --- a/drivers/spi/ath79_spi.c +++ b/drivers/spi/ath79_spi.c @@ -178,7 +178,7 @@ static int ath79_spi_probe(struct udevice *bus) struct ath79_spi_priv *priv = dev_get_priv(bus); fdt_addr_t addr; - addr = devfdt_get_addr(bus); + addr = dev_read_addr(bus); if (addr == FDT_ADDR_T_NONE) return -EINVAL; diff --git a/drivers/spi/atmel_spi.c b/drivers/spi/atmel_spi.c index b120664661..c65733c87a 100644 --- a/drivers/spi/atmel_spi.c +++ b/drivers/spi/atmel_spi.c @@ -351,7 +351,7 @@ static int atmel_spi_probe(struct udevice *bus) if (ret) return ret; - bus_plat->regs = (struct at91_spi *)devfdt_get_addr(bus); + bus_plat->regs = dev_read_addr_ptr(bus); #if CONFIG_IS_ENABLED(DM_GPIO) struct atmel_spi_priv *priv = dev_get_priv(bus); diff --git a/drivers/spi/cf_spi.c b/drivers/spi/cf_spi.c index dec92df69b..8fa6d35107 100644 --- a/drivers/spi/cf_spi.c +++ b/drivers/spi/cf_spi.c @@ -392,7 +392,7 @@ static int coldfire_dspi_ofdata_to_platdata(struct udevice *bus) int node = dev_of_offset(bus); int *ctar, len; - addr = devfdt_get_addr(bus); + addr = dev_read_addr(bus); if (addr == FDT_ADDR_T_NONE) return -ENOMEM; diff --git a/drivers/spi/davinci_spi.c b/drivers/spi/davinci_spi.c index e1e9b45cc9..a11433db1e 100644 --- a/drivers/spi/davinci_spi.c +++ b/drivers/spi/davinci_spi.c @@ -396,7 +396,7 @@ static int davinci_ofdata_to_platadata(struct udevice *bus) struct davinci_spi_platdata *plat = bus->platdata; fdt_addr_t addr; - addr = devfdt_get_addr(bus); + addr = dev_read_addr(bus); if (addr == FDT_ADDR_T_NONE) return -EINVAL; diff --git a/drivers/spi/designware_spi.c b/drivers/spi/designware_spi.c index c9b14f9029..2559aac2e9 100644 --- a/drivers/spi/designware_spi.c +++ b/drivers/spi/designware_spi.c @@ -157,7 +157,7 @@ static int dw_spi_ofdata_to_platdata(struct udevice *bus) { struct dw_spi_platdata *plat = bus->platdata; - plat->regs = (struct dw_spi *)devfdt_get_addr(bus); + plat->regs = dev_read_addr_ptr(bus); /* Use 500KHz as a suitable default */ plat->frequency = dev_read_u32_default(bus, "spi-max-frequency", diff --git a/drivers/spi/exynos_spi.c b/drivers/spi/exynos_spi.c index 746686a18a..d338ff5a0b 100644 --- a/drivers/spi/exynos_spi.c +++ b/drivers/spi/exynos_spi.c @@ -257,7 +257,7 @@ static int exynos_spi_ofdata_to_platdata(struct udevice *bus) const void *blob = gd->fdt_blob; int node = dev_of_offset(bus); - plat->regs = (struct exynos_spi *)devfdt_get_addr(bus); + plat->regs = dev_read_addr_ptr(bus); plat->periph_id = pinmux_decode_periph_id(blob, node); if (plat->periph_id == PERIPH_ID_NONE) { diff --git a/drivers/spi/fsl_dspi.c b/drivers/spi/fsl_dspi.c index 78ad61ca37..b22c9b3a09 100644 --- a/drivers/spi/fsl_dspi.c +++ b/drivers/spi/fsl_dspi.c @@ -9,6 +9,7 @@ * Haikun Wang (B53464@freescale.com) */ +#include <linux/math64.h> #include <common.h> #include <dm.h> #include <errno.h> @@ -25,6 +26,9 @@ #include <linux/bitops.h> #include <linux/delay.h> +/* linux/include/time.h */ +#define NSEC_PER_SEC 1000000000L + DECLARE_GLOBAL_DATA_PTR; /* fsl_dspi_platdata flags */ @@ -379,6 +383,40 @@ static int fsl_dspi_hz_to_spi_baud(int *pbr, int *br, return -EINVAL; } +static void ns_delay_scale(unsigned char *psc, unsigned char *sc, int delay_ns, + unsigned long clkrate) +{ + int scale_needed, scale, minscale = INT_MAX; + int pscale_tbl[4] = {1, 3, 5, 7}; + u32 remainder; + int i, j; + + scale_needed = div_u64_rem((u64)delay_ns * clkrate, NSEC_PER_SEC, + &remainder); + if (remainder) + scale_needed++; + + for (i = 0; i < ARRAY_SIZE(pscale_tbl); i++) + for (j = 0; j <= DSPI_CTAR_SCALE_BITS; j++) { + scale = pscale_tbl[i] * (2 << j); + if (scale >= scale_needed) { + if (scale < minscale) { + minscale = scale; + *psc = i; + *sc = j; + } + break; + } + } + + if (minscale == INT_MAX) { + pr_warn("Cannot find correct scale values for %dns delay at clkrate %ld, using max prescaler value", + delay_ns, clkrate); + *psc = ARRAY_SIZE(pscale_tbl) - 1; + *sc = DSPI_CTAR_SCALE_BITS; + } +} + static int fsl_dspi_cfg_speed(struct fsl_dspi_priv *priv, uint speed) { int ret; @@ -412,6 +450,9 @@ static int fsl_dspi_child_pre_probe(struct udevice *dev) { struct dm_spi_slave_platdata *slave_plat = dev_get_parent_platdata(dev); struct fsl_dspi_priv *priv = dev_get_priv(dev->parent); + u32 cs_sck_delay = 0, sck_cs_delay = 0; + unsigned char pcssck = 0, cssck = 0; + unsigned char pasc = 0, asc = 0; if (slave_plat->cs >= priv->num_chipselect) { debug("DSPI invalid chipselect number %d(max %d)!\n", @@ -419,7 +460,18 @@ static int fsl_dspi_child_pre_probe(struct udevice *dev) return -EINVAL; } - priv->ctar_val[slave_plat->cs] = DSPI_CTAR_DEFAULT_VALUE; + ofnode_read_u32(dev->node, "fsl,spi-cs-sck-delay", &cs_sck_delay); + ofnode_read_u32(dev->node, "fsl,spi-sck-cs-delay", &sck_cs_delay); + + /* Set PCS to SCK delay scale values */ + ns_delay_scale(&pcssck, &cssck, cs_sck_delay, priv->bus_clk); + + /* Set After SCK delay scale values */ + ns_delay_scale(&pasc, &asc, sck_cs_delay, priv->bus_clk); + + priv->ctar_val[slave_plat->cs] = DSPI_CTAR_DEFAULT_VALUE | + DSPI_CTAR_PCSSCK(pcssck) | + DSPI_CTAR_PASC(pasc); debug("DSPI pre_probe slave device on CS %u, max_hz %u, mode 0x%x.\n", slave_plat->cs, slave_plat->max_hz, slave_plat->mode); @@ -534,7 +586,7 @@ static int fsl_dspi_ofdata_to_platdata(struct udevice *bus) plat->num_chipselect = fdtdec_get_int(blob, node, "num-cs", FSL_DSPI_MAX_CHIPSELECT); - addr = devfdt_get_addr(bus); + addr = dev_read_addr(bus); if (addr == FDT_ADDR_T_NONE) { debug("DSPI: Can't get base address or size\n"); return -ENOMEM; diff --git a/drivers/spi/kirkwood_spi.c b/drivers/spi/kirkwood_spi.c index 92dc2e13c5..dc7d2bc1f0 100644 --- a/drivers/spi/kirkwood_spi.c +++ b/drivers/spi/kirkwood_spi.c @@ -236,7 +236,7 @@ static int mvebu_spi_ofdata_to_platdata(struct udevice *bus) const struct mvebu_spi_dev *drvdata = (struct mvebu_spi_dev *)dev_get_driver_data(bus); - plat->spireg = (struct kwspi_registers *)devfdt_get_addr(bus); + plat->spireg = dev_read_addr_ptr(bus); plat->is_errata_50mhz_ac = drvdata->is_errata_50mhz_ac; return 0; diff --git a/drivers/spi/mscc_bb_spi.c b/drivers/spi/mscc_bb_spi.c index 0454410ee9..e77447b655 100644 --- a/drivers/spi/mscc_bb_spi.c +++ b/drivers/spi/mscc_bb_spi.c @@ -11,7 +11,6 @@ #include <log.h> #include <malloc.h> #include <spi.h> -#include <dm.h> #include <asm/gpio.h> #include <asm/io.h> #include <linux/bitops.h> diff --git a/drivers/spi/mtk_snfi_spi.c b/drivers/spi/mtk_snfi_spi.c index 2a89476515..c30c8f4ff6 100644 --- a/drivers/spi/mtk_snfi_spi.c +++ b/drivers/spi/mtk_snfi_spi.c @@ -253,7 +253,7 @@ static int mtk_snfi_spi_probe(struct udevice *bus) struct mtk_snfi_priv *priv = dev_get_priv(bus); int ret; - priv->base = (void __iomem *)devfdt_get_addr(bus); + priv->base = dev_read_addr_ptr(bus); if (!priv->base) return -EINVAL; diff --git a/drivers/spi/mvebu_a3700_spi.c b/drivers/spi/mvebu_a3700_spi.c index 2302e62be4..e860b9ec64 100644 --- a/drivers/spi/mvebu_a3700_spi.c +++ b/drivers/spi/mvebu_a3700_spi.c @@ -255,7 +255,7 @@ static int mvebu_spi_ofdata_to_platdata(struct udevice *bus) struct mvebu_spi_platdata *plat = dev_get_platdata(bus); int ret; - plat->spireg = (struct spi_reg *)devfdt_get_addr(bus); + plat->spireg = dev_read_addr_ptr(bus); ret = clk_get_by_index(bus, 0, &plat->clk); if (ret) { diff --git a/drivers/spi/mxc_spi.c b/drivers/spi/mxc_spi.c index aad3780365..e90a06a66d 100644 --- a/drivers/spi/mxc_spi.c +++ b/drivers/spi/mxc_spi.c @@ -537,7 +537,7 @@ static int mxc_spi_probe(struct udevice *bus) } } - mxcs->base = devfdt_get_addr(bus); + mxcs->base = dev_read_addr(bus); if (mxcs->base == FDT_ADDR_T_NONE) return -ENODEV; diff --git a/drivers/spi/mxs_spi.c b/drivers/spi/mxs_spi.c index 3c1af839c0..fb0af02be0 100644 --- a/drivers/spi/mxs_spi.c +++ b/drivers/spi/mxs_spi.c @@ -41,15 +41,9 @@ #define MXS_SSP_IMX23_CLKID_SSP0 33 #define MXS_SSP_IMX28_CLKID_SSP0 46 -#ifdef CONFIG_MX28 -#define dtd_fsl_imx_spi dtd_fsl_imx28_spi -#else /* CONFIG_MX23 */ -#define dtd_fsl_imx_spi dtd_fsl_imx23_spi -#endif - struct mxs_spi_platdata { #if CONFIG_IS_ENABLED(OF_PLATDATA) - struct dtd_fsl_imx_spi dtplat; + struct dtd_fsl_imx23_spi dtplat; #endif s32 frequency; /* Default clock frequency, -1 for none */ fdt_addr_t base; /* SPI IP block base address */ @@ -324,7 +318,7 @@ static int mxs_spi_probe(struct udevice *bus) debug("%s: probe\n", __func__); #if CONFIG_IS_ENABLED(OF_PLATDATA) - struct dtd_fsl_imx_spi *dtplat = &plat->dtplat; + struct dtd_fsl_imx23_spi *dtplat = &plat->dtplat; struct phandle_1_arg *p1a = &dtplat->clocks[0]; priv->regs = (struct mxs_ssp_regs *)dtplat->reg[0]; diff --git a/drivers/spi/octeon_spi.c b/drivers/spi/octeon_spi.c new file mode 100644 index 0000000000..83fe6330a1 --- /dev/null +++ b/drivers/spi/octeon_spi.c @@ -0,0 +1,613 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2018 Marvell International Ltd. + */ + +#include <clk.h> +#include <dm.h> +#include <malloc.h> +#include <spi.h> +#include <spi-mem.h> +#include <watchdog.h> +#include <asm/io.h> +#include <asm/unaligned.h> +#include <linux/bitfield.h> +#include <linux/compat.h> +#include <linux/delay.h> + +#define OCTEON_SPI_MAX_BYTES 9 +#define OCTEON_SPI_MAX_CLOCK_HZ 50000000 + +#define OCTEON_SPI_NUM_CS 4 + +#define OCTEON_SPI_CS_VALID(cs) ((cs) < OCTEON_SPI_NUM_CS) + +#define MPI_CFG 0x0000 +#define MPI_STS 0x0008 +#define MPI_TX 0x0010 +#define MPI_XMIT 0x0018 +#define MPI_WIDE_DAT 0x0040 +#define MPI_IO_CTL 0x0048 +#define MPI_DAT(X) (0x0080 + ((X) << 3)) +#define MPI_WIDE_BUF(X) (0x0800 + ((X) << 3)) +#define MPI_CYA_CFG 0x1000 +#define MPI_CLKEN 0x1080 + +#define MPI_CFG_ENABLE BIT_ULL(0) +#define MPI_CFG_IDLELO BIT_ULL(1) +#define MPI_CFG_CLK_CONT BIT_ULL(2) +#define MPI_CFG_WIREOR BIT_ULL(3) +#define MPI_CFG_LSBFIRST BIT_ULL(4) +#define MPI_CFG_CS_STICKY BIT_ULL(5) +#define MPI_CFG_CSHI BIT_ULL(7) +#define MPI_CFG_IDLECLKS GENMASK_ULL(9, 8) +#define MPI_CFG_TRITX BIT_ULL(10) +#define MPI_CFG_CSLATE BIT_ULL(11) +#define MPI_CFG_CSENA0 BIT_ULL(12) +#define MPI_CFG_CSENA1 BIT_ULL(13) +#define MPI_CFG_CSENA2 BIT_ULL(14) +#define MPI_CFG_CSENA3 BIT_ULL(15) +#define MPI_CFG_CLKDIV GENMASK_ULL(28, 16) +#define MPI_CFG_LEGACY_DIS BIT_ULL(31) +#define MPI_CFG_IOMODE GENMASK_ULL(35, 34) +#define MPI_CFG_TB100_EN BIT_ULL(49) + +#define MPI_DAT_DATA GENMASK_ULL(7, 0) + +#define MPI_STS_BUSY BIT_ULL(0) +#define MPI_STS_MPI_INTR BIT_ULL(1) +#define MPI_STS_RXNUM GENMASK_ULL(12, 8) + +#define MPI_TX_TOTNUM GENMASK_ULL(4, 0) +#define MPI_TX_TXNUM GENMASK_ULL(12, 8) +#define MPI_TX_LEAVECS BIT_ULL(16) +#define MPI_TX_CSID GENMASK_ULL(21, 20) + +#define MPI_XMIT_TOTNUM GENMASK_ULL(10, 0) +#define MPI_XMIT_TXNUM GENMASK_ULL(30, 20) +#define MPI_XMIT_BUF_SEL BIT_ULL(59) +#define MPI_XMIT_LEAVECS BIT_ULL(60) +#define MPI_XMIT_CSID GENMASK_ULL(62, 61) + +/* Used on Octeon TX2 */ +void board_acquire_flash_arb(bool acquire); + +/* Local driver data structure */ +struct octeon_spi { + void __iomem *base; /* Register base address */ + struct clk clk; + u32 clkdiv; /* Clock divisor for device speed */ +}; + +static u64 octeon_spi_set_mpicfg(struct udevice *dev) +{ + struct dm_spi_slave_platdata *slave = dev_get_parent_platdata(dev); + struct udevice *bus = dev_get_parent(dev); + struct octeon_spi *priv = dev_get_priv(bus); + u64 mpi_cfg; + uint max_speed = slave->max_hz; + bool cpha, cpol; + + if (!max_speed) + max_speed = 12500000; + if (max_speed > OCTEON_SPI_MAX_CLOCK_HZ) + max_speed = OCTEON_SPI_MAX_CLOCK_HZ; + + debug("\n slave params %d %d %d\n", slave->cs, + slave->max_hz, slave->mode); + cpha = !!(slave->mode & SPI_CPHA); + cpol = !!(slave->mode & SPI_CPOL); + + mpi_cfg = FIELD_PREP(MPI_CFG_CLKDIV, priv->clkdiv & 0x1fff) | + FIELD_PREP(MPI_CFG_CSHI, !!(slave->mode & SPI_CS_HIGH)) | + FIELD_PREP(MPI_CFG_LSBFIRST, !!(slave->mode & SPI_LSB_FIRST)) | + FIELD_PREP(MPI_CFG_WIREOR, !!(slave->mode & SPI_3WIRE)) | + FIELD_PREP(MPI_CFG_IDLELO, cpha != cpol) | + FIELD_PREP(MPI_CFG_CSLATE, cpha) | + MPI_CFG_CSENA0 | MPI_CFG_CSENA1 | + MPI_CFG_CSENA2 | MPI_CFG_CSENA1 | + MPI_CFG_ENABLE; + + debug("\n mpi_cfg %llx\n", mpi_cfg); + return mpi_cfg; +} + +/** + * Wait until the SPI bus is ready + * + * @param dev SPI device to wait for + */ +static void octeon_spi_wait_ready(struct udevice *dev) +{ + struct udevice *bus = dev_get_parent(dev); + struct octeon_spi *priv = dev_get_priv(bus); + void *base = priv->base; + u64 mpi_sts; + + do { + mpi_sts = readq(base + MPI_STS); + WATCHDOG_RESET(); + } while (mpi_sts & MPI_STS_BUSY); + + debug("%s(%s)\n", __func__, dev->name); +} + +/** + * Claim the bus for a slave device + * + * @param dev SPI bus + * + * @return 0 for success, -EINVAL if chip select is invalid + */ +static int octeon_spi_claim_bus(struct udevice *dev) +{ + struct udevice *bus = dev_get_parent(dev); + struct octeon_spi *priv = dev_get_priv(bus); + void *base = priv->base; + u64 mpi_cfg; + + debug("\n\n%s(%s)\n", __func__, dev->name); + if (!OCTEON_SPI_CS_VALID(spi_chip_select(dev))) + return -EINVAL; + + if (IS_ENABLED(CONFIG_ARCH_OCTEONTX2)) + board_acquire_flash_arb(true); + + mpi_cfg = readq(base + MPI_CFG); + mpi_cfg &= ~MPI_CFG_TRITX; + mpi_cfg |= MPI_CFG_ENABLE; + writeq(mpi_cfg, base + MPI_CFG); + mpi_cfg = readq(base + MPI_CFG); + udelay(5); /** Wait for bus to settle */ + + return 0; +} + +/** + * Release the bus to a slave device + * + * @param dev SPI bus + * + * @return 0 for success, -EINVAL if chip select is invalid + */ +static int octeon_spi_release_bus(struct udevice *dev) +{ + struct udevice *bus = dev_get_parent(dev); + struct octeon_spi *priv = dev_get_priv(bus); + void *base = priv->base; + u64 mpi_cfg; + + debug("%s(%s)\n\n", __func__, dev->name); + if (!OCTEON_SPI_CS_VALID(spi_chip_select(dev))) + return -EINVAL; + + if (IS_ENABLED(CONFIG_ARCH_OCTEONTX2)) + board_acquire_flash_arb(false); + + mpi_cfg = readq(base + MPI_CFG); + mpi_cfg &= ~MPI_CFG_ENABLE; + writeq(mpi_cfg, base + MPI_CFG); + mpi_cfg = readq(base + MPI_CFG); + udelay(1); + + return 0; +} + +static int octeon_spi_xfer(struct udevice *dev, unsigned int bitlen, + const void *dout, void *din, unsigned long flags) +{ + struct udevice *bus = dev_get_parent(dev); + struct octeon_spi *priv = dev_get_priv(bus); + void *base = priv->base; + u64 mpi_tx; + u64 mpi_cfg; + u64 wide_dat = 0; + int len = bitlen / 8; + int i; + const u8 *tx_data = dout; + u8 *rx_data = din; + int cs = spi_chip_select(dev); + + if (!OCTEON_SPI_CS_VALID(cs)) + return -EINVAL; + + debug("\n %s(%s, %u, %p, %p, 0x%lx), cs: %d\n", + __func__, dev->name, bitlen, dout, din, flags, cs); + + mpi_cfg = octeon_spi_set_mpicfg(dev); + if (mpi_cfg != readq(base + MPI_CFG)) { + writeq(mpi_cfg, base + MPI_CFG); + mpi_cfg = readq(base + MPI_CFG); + udelay(10); + } + + debug("\n mpi_cfg upd %llx\n", mpi_cfg); + + /* + * Start by writing and reading 8 bytes at a time. While we can support + * up to 10, it's easier to just use 8 with the MPI_WIDE_DAT register. + */ + while (len > 8) { + if (tx_data) { + wide_dat = get_unaligned((u64 *)tx_data); + debug(" tx: %016llx \t", (unsigned long long)wide_dat); + tx_data += 8; + writeq(wide_dat, base + MPI_WIDE_DAT); + } + + mpi_tx = FIELD_PREP(MPI_TX_CSID, cs) | + FIELD_PREP(MPI_TX_LEAVECS, 1) | + FIELD_PREP(MPI_TX_TXNUM, tx_data ? 8 : 0) | + FIELD_PREP(MPI_TX_TOTNUM, 8); + writeq(mpi_tx, base + MPI_TX); + + octeon_spi_wait_ready(dev); + + debug("\n "); + + if (rx_data) { + wide_dat = readq(base + MPI_WIDE_DAT); + debug(" rx: %016llx\t", (unsigned long long)wide_dat); + *(u64 *)rx_data = wide_dat; + rx_data += 8; + } + len -= 8; + } + + debug("\n "); + + /* Write and read the rest of the data */ + if (tx_data) { + for (i = 0; i < len; i++) { + debug(" tx: %02x\n", *tx_data); + writeq(*tx_data++, base + MPI_DAT(i)); + } + } + + mpi_tx = FIELD_PREP(MPI_TX_CSID, cs) | + FIELD_PREP(MPI_TX_LEAVECS, !(flags & SPI_XFER_END)) | + FIELD_PREP(MPI_TX_TXNUM, tx_data ? len : 0) | + FIELD_PREP(MPI_TX_TOTNUM, len); + writeq(mpi_tx, base + MPI_TX); + + octeon_spi_wait_ready(dev); + + debug("\n "); + + if (rx_data) { + for (i = 0; i < len; i++) { + *rx_data = readq(base + MPI_DAT(i)) & 0xff; + debug(" rx: %02x\n", *rx_data); + rx_data++; + } + } + + return 0; +} + +static int octeontx2_spi_xfer(struct udevice *dev, unsigned int bitlen, + const void *dout, void *din, unsigned long flags) +{ + struct udevice *bus = dev_get_parent(dev); + struct octeon_spi *priv = dev_get_priv(bus); + void *base = priv->base; + u64 mpi_xmit; + u64 mpi_cfg; + u64 wide_dat = 0; + int len = bitlen / 8; + int rem; + int i; + const u8 *tx_data = dout; + u8 *rx_data = din; + int cs = spi_chip_select(dev); + + if (!OCTEON_SPI_CS_VALID(cs)) + return -EINVAL; + + debug("\n %s(%s, %u, %p, %p, 0x%lx), cs: %d\n", + __func__, dev->name, bitlen, dout, din, flags, cs); + + mpi_cfg = octeon_spi_set_mpicfg(dev); + + mpi_cfg |= MPI_CFG_TRITX | MPI_CFG_LEGACY_DIS | MPI_CFG_CS_STICKY | + MPI_CFG_TB100_EN; + + mpi_cfg &= ~MPI_CFG_IOMODE; + if (flags & (SPI_TX_DUAL | SPI_RX_DUAL)) + mpi_cfg |= FIELD_PREP(MPI_CFG_IOMODE, 2); + if (flags & (SPI_TX_QUAD | SPI_RX_QUAD)) + mpi_cfg |= FIELD_PREP(MPI_CFG_IOMODE, 3); + + if (mpi_cfg != readq(base + MPI_CFG)) { + writeq(mpi_cfg, base + MPI_CFG); + mpi_cfg = readq(base + MPI_CFG); + udelay(10); + } + + debug("\n mpi_cfg upd %llx\n\n", mpi_cfg); + + /* Start by writing or reading 1024 bytes at a time. */ + while (len > 1024) { + if (tx_data) { + /* 8 bytes per iteration */ + for (i = 0; i < 128; i++) { + wide_dat = get_unaligned((u64 *)tx_data); + debug(" tx: %016llx \t", + (unsigned long long)wide_dat); + if ((i % 4) == 3) + debug("\n"); + tx_data += 8; + writeq(wide_dat, base + MPI_WIDE_BUF(i)); + } + } + + mpi_xmit = FIELD_PREP(MPI_XMIT_CSID, cs) | MPI_XMIT_LEAVECS | + FIELD_PREP(MPI_XMIT_TXNUM, tx_data ? 1024 : 0) | + FIELD_PREP(MPI_XMIT_TOTNUM, 1024); + writeq(mpi_xmit, base + MPI_XMIT); + + octeon_spi_wait_ready(dev); + + debug("\n "); + + if (rx_data) { + /* 8 bytes per iteration */ + for (i = 0; i < 128; i++) { + wide_dat = readq(base + MPI_WIDE_BUF(i)); + debug(" rx: %016llx\t", + (unsigned long long)wide_dat); + if ((i % 4) == 3) + debug("\n"); + *(u64 *)rx_data = wide_dat; + rx_data += 8; + } + } + len -= 1024; + } + + if (tx_data) { + rem = len % 8; + /* 8 bytes per iteration */ + for (i = 0; i < len / 8; i++) { + wide_dat = get_unaligned((u64 *)tx_data); + debug(" tx: %016llx \t", + (unsigned long long)wide_dat); + if ((i % 4) == 3) + debug("\n"); + tx_data += 8; + writeq(wide_dat, base + MPI_WIDE_BUF(i)); + } + if (rem) { + memcpy(&wide_dat, tx_data, rem); + debug(" rtx: %016llx\t", wide_dat); + writeq(wide_dat, base + MPI_WIDE_BUF(i)); + } + } + + mpi_xmit = FIELD_PREP(MPI_XMIT_CSID, cs) | + FIELD_PREP(MPI_XMIT_LEAVECS, !(flags & SPI_XFER_END)) | + FIELD_PREP(MPI_XMIT_TXNUM, tx_data ? len : 0) | + FIELD_PREP(MPI_XMIT_TOTNUM, len); + writeq(mpi_xmit, base + MPI_XMIT); + + octeon_spi_wait_ready(dev); + + debug("\n "); + + if (rx_data) { + rem = len % 8; + /* 8 bytes per iteration */ + for (i = 0; i < len / 8; i++) { + wide_dat = readq(base + MPI_WIDE_BUF(i)); + debug(" rx: %016llx\t", + (unsigned long long)wide_dat); + if ((i % 4) == 3) + debug("\n"); + *(u64 *)rx_data = wide_dat; + rx_data += 8; + } + if (rem) { + wide_dat = readq(base + MPI_WIDE_BUF(i)); + debug(" rrx: %016llx\t", + (unsigned long long)wide_dat); + memcpy(rx_data, &wide_dat, rem); + rx_data += rem; + } + } + + return 0; +} + +static bool octeon_spi_supports_op(struct spi_slave *slave, + const struct spi_mem_op *op) +{ + /* For now, support only below combinations + * 1-1-1 + * 1-1-2 1-2-2 + * 1-1-4 1-4-4 + */ + if (op->cmd.buswidth != 1) + return false; + return true; +} + +static int octeon_spi_exec_op(struct spi_slave *slave, + const struct spi_mem_op *op) +{ + unsigned long flags = SPI_XFER_BEGIN; + const void *tx; + void *rx; + u8 opcode, *buf; + u8 *addr; + int i, temp, ret; + + if (op->cmd.buswidth != 1) + return -ENOTSUPP; + + /* Send CMD */ + i = 0; + opcode = op->cmd.opcode; + + if (!op->data.nbytes && !op->addr.nbytes && !op->dummy.nbytes) + flags |= SPI_XFER_END; + + ret = octeontx2_spi_xfer(slave->dev, 8, (void *)&opcode, NULL, flags); + if (ret < 0) + return ret; + + /* Send Address and dummy */ + if (op->addr.nbytes) { + /* Alloc buffer for address+dummy */ + buf = (u8 *)calloc(1, op->addr.nbytes + op->dummy.nbytes); + if (!buf) { + printf("%s Out of memory\n", __func__); + return -ENOMEM; + } + addr = (u8 *)&op->addr.val; + for (temp = 0; temp < op->addr.nbytes; temp++) + buf[i++] = *(u8 *)(addr + op->addr.nbytes - 1 - temp); + for (temp = 0; temp < op->dummy.nbytes; temp++) + buf[i++] = 0xff; + if (op->addr.buswidth == 2) + flags |= SPI_RX_DUAL; + if (op->addr.buswidth == 4) + flags |= SPI_RX_QUAD; + + if (!op->data.nbytes) + flags |= SPI_XFER_END; + ret = octeontx2_spi_xfer(slave->dev, i * 8, (void *)buf, NULL, + flags); + free(buf); + if (ret < 0) + return ret; + } + if (!op->data.nbytes) + return 0; + + /* Send/Receive Data */ + flags |= SPI_XFER_END; + if (op->data.buswidth == 2) + flags |= SPI_RX_DUAL; + if (op->data.buswidth == 4) + flags |= SPI_RX_QUAD; + + rx = (op->data.dir == SPI_MEM_DATA_IN) ? op->data.buf.in : NULL; + tx = (op->data.dir == SPI_MEM_DATA_OUT) ? op->data.buf.out : NULL; + + ret = octeontx2_spi_xfer(slave->dev, (op->data.nbytes * 8), tx, rx, + flags); + return ret; +} + +static const struct spi_controller_mem_ops octeontx2_spi_mem_ops = { + .supports_op = octeon_spi_supports_op, + .exec_op = octeon_spi_exec_op, +}; + +/** + * Set the speed of the SPI bus + * + * @param bus bus to set + * @param max_hz maximum speed supported + */ +static int octeon_spi_set_speed(struct udevice *bus, uint max_hz) +{ + struct octeon_spi *priv = dev_get_priv(bus); + ulong clk_rate; + u32 calc_hz; + + if (max_hz > OCTEON_SPI_MAX_CLOCK_HZ) + max_hz = OCTEON_SPI_MAX_CLOCK_HZ; + + clk_rate = clk_get_rate(&priv->clk); + if (IS_ERR_VALUE(clk_rate)) + return -EINVAL; + + debug("%s(%s, %u, %lu)\n", __func__, bus->name, max_hz, clk_rate); + + priv->clkdiv = clk_rate / (2 * max_hz); + while (1) { + calc_hz = clk_rate / (2 * priv->clkdiv); + if (calc_hz <= max_hz) + break; + priv->clkdiv += 1; + } + + if (priv->clkdiv > 8191) + return -EINVAL; + + debug("%s: clkdiv=%d\n", __func__, priv->clkdiv); + + return 0; +} + +static int octeon_spi_set_mode(struct udevice *bus, uint mode) +{ + /* We don't set it here */ + return 0; +} + +static struct dm_spi_ops octeon_spi_ops = { + .claim_bus = octeon_spi_claim_bus, + .release_bus = octeon_spi_release_bus, + .set_speed = octeon_spi_set_speed, + .set_mode = octeon_spi_set_mode, + .xfer = octeon_spi_xfer, +}; + +static int octeon_spi_probe(struct udevice *dev) +{ + struct octeon_spi *priv = dev_get_priv(dev); + int ret; + + /* Octeon TX & TX2 use PCI based probing */ + if (device_is_compatible(dev, "cavium,thunder-8190-spi")) { + pci_dev_t bdf = dm_pci_get_bdf(dev); + + debug("SPI PCI device: %x\n", bdf); + priv->base = dm_pci_map_bar(dev, PCI_BASE_ADDRESS_0, + PCI_REGION_MEM); + /* Add base offset */ + priv->base += 0x1000; + + /* + * Octeon TX2 needs a different xfer function and supports + * mem_ops + */ + if (device_is_compatible(dev, "cavium,thunderx-spi")) { + octeon_spi_ops.xfer = octeontx2_spi_xfer; + octeon_spi_ops.mem_ops = &octeontx2_spi_mem_ops; + } + } else { + priv->base = dev_remap_addr(dev); + } + + ret = clk_get_by_index(dev, 0, &priv->clk); + if (ret < 0) + return ret; + + ret = clk_enable(&priv->clk); + if (ret) + return ret; + + debug("SPI bus %s %d at %p\n", dev->name, dev->seq, priv->base); + + return 0; +} + +static const struct udevice_id octeon_spi_ids[] = { + /* MIPS Octeon */ + { .compatible = "cavium,octeon-3010-spi" }, + /* ARM Octeon TX / TX2 */ + { .compatible = "cavium,thunder-8190-spi" }, + { } +}; + +U_BOOT_DRIVER(octeon_spi) = { + .name = "spi_octeon", + .id = UCLASS_SPI, + .of_match = octeon_spi_ids, + .probe = octeon_spi_probe, + .priv_auto_alloc_size = sizeof(struct octeon_spi), + .ops = &octeon_spi_ops, +}; diff --git a/drivers/spi/omap3_spi.c b/drivers/spi/omap3_spi.c index 39e6813469..fbf9575851 100644 --- a/drivers/spi/omap3_spi.c +++ b/drivers/spi/omap3_spi.c @@ -488,7 +488,7 @@ static int omap3_spi_probe(struct udevice *dev) struct omap2_mcspi_platform_config* data = (struct omap2_mcspi_platform_config*)dev_get_driver_data(dev); - priv->regs = (struct mcspi *)(devfdt_get_addr(dev) + data->regs_offset); + priv->regs = (struct mcspi *)(dev_read_addr(dev) + data->regs_offset); if (fdtdec_get_bool(blob, node, "ti,pindir-d0-out-d1-in")) priv->pin_dir = MCSPI_PINDIR_D0_OUT_D1_IN; else diff --git a/drivers/spi/spi-mem.c b/drivers/spi/spi-mem.c index d344701aeb..c095ae9505 100644 --- a/drivers/spi/spi-mem.c +++ b/drivers/spi/spi-mem.c @@ -13,9 +13,14 @@ #include <linux/pm_runtime.h> #include "internals.h" #else -#include <dm/device_compat.h> +#include <common.h> +#include <dm.h> +#include <errno.h> +#include <malloc.h> +#include <spi.h> #include <spi.h> #include <spi-mem.h> +#include <dm/device_compat.h> #endif #ifndef __UBOOT__ diff --git a/drivers/spi/spi-sifive.c b/drivers/spi/spi-sifive.c index 0e0ce25abb..c7345d9042 100644 --- a/drivers/spi/spi-sifive.c +++ b/drivers/spi/spi-sifive.c @@ -10,6 +10,7 @@ #include <dm.h> #include <dm/device_compat.h> #include <malloc.h> +#include <spi.h> #include <spi-mem.h> #include <wait_bit.h> #include <asm/io.h> diff --git a/drivers/spi/spi-sunxi.c b/drivers/spi/spi-sunxi.c index d2dccd67e5..cd2e17bfd1 100644 --- a/drivers/spi/spi-sunxi.c +++ b/drivers/spi/spi-sunxi.c @@ -519,7 +519,7 @@ static int sun4i_spi_ofdata_to_platdata(struct udevice *bus) struct sun4i_spi_platdata *plat = dev_get_platdata(bus); int node = dev_of_offset(bus); - plat->base = devfdt_get_addr(bus); + plat->base = dev_read_addr(bus); plat->variant = (struct sun4i_spi_variant *)dev_get_driver_data(bus); plat->max_hz = fdtdec_get_int(gd->fdt_blob, node, "spi-max-frequency", diff --git a/drivers/spi/stm32_qspi.c b/drivers/spi/stm32_qspi.c index 001f0703e3..a53b941410 100644 --- a/drivers/spi/stm32_qspi.c +++ b/drivers/spi/stm32_qspi.c @@ -9,8 +9,10 @@ #include <common.h> #include <clk.h> +#include <dm.h> #include <log.h> #include <reset.h> +#include <spi.h> #include <spi-mem.h> #include <dm/device_compat.h> #include <linux/bitops.h> diff --git a/drivers/spi/tegra20_sflash.c b/drivers/spi/tegra20_sflash.c index 22a0304bfc..771744dfe4 100644 --- a/drivers/spi/tegra20_sflash.c +++ b/drivers/spi/tegra20_sflash.c @@ -93,7 +93,7 @@ static int tegra20_sflash_ofdata_to_platdata(struct udevice *bus) const void *blob = gd->fdt_blob; int node = dev_of_offset(bus); - plat->base = devfdt_get_addr(bus); + plat->base = dev_read_addr(bus); plat->periph_id = clock_decode_periph_id(bus); if (plat->periph_id == PERIPH_ID_NONE) { diff --git a/drivers/spi/tegra20_slink.c b/drivers/spi/tegra20_slink.c index 3679cf06a0..f9846ee366 100644 --- a/drivers/spi/tegra20_slink.c +++ b/drivers/spi/tegra20_slink.c @@ -99,7 +99,7 @@ static int tegra30_spi_ofdata_to_platdata(struct udevice *bus) const void *blob = gd->fdt_blob; int node = dev_of_offset(bus); - plat->base = devfdt_get_addr(bus); + plat->base = dev_read_addr(bus); plat->periph_id = clock_decode_periph_id(bus); if (plat->periph_id == PERIPH_ID_NONE) { diff --git a/drivers/spi/ti_qspi.c b/drivers/spi/ti_qspi.c index 0db0de8f1b..5fdbb49442 100644 --- a/drivers/spi/ti_qspi.c +++ b/drivers/spi/ti_qspi.c @@ -461,7 +461,7 @@ static int ti_qspi_ofdata_to_platdata(struct udevice *bus) fdt_addr_t mmap_size; priv->ctrl_mod_mmap = map_syscon_chipselects(bus); - priv->base = map_physmem(devfdt_get_addr(bus), + priv->base = map_physmem(dev_read_addr(bus), sizeof(struct ti_qspi_regs), MAP_NOCACHE); mmap_addr = devfdt_get_addr_size_index(bus, 1, &mmap_size); priv->memory_map = map_physmem(mmap_addr, mmap_size, MAP_NOCACHE); diff --git a/drivers/spi/zynq_spi.c b/drivers/spi/zynq_spi.c index 78ffd3e2fe..9923931e36 100644 --- a/drivers/spi/zynq_spi.c +++ b/drivers/spi/zynq_spi.c @@ -77,7 +77,7 @@ static int zynq_spi_ofdata_to_platdata(struct udevice *bus) const void *blob = gd->fdt_blob; int node = dev_of_offset(bus); - plat->regs = (struct zynq_spi_regs *)devfdt_get_addr(bus); + plat->regs = dev_read_addr_ptr(bus); /* FIXME: Use 250MHz as a suitable default */ plat->frequency = fdtdec_get_int(blob, node, "spi-max-frequency", diff --git a/drivers/spi/zynqmp_gqspi.c b/drivers/spi/zynqmp_gqspi.c index c3a5b3e301..a72986be90 100644 --- a/drivers/spi/zynqmp_gqspi.c +++ b/drivers/spi/zynqmp_gqspi.c @@ -181,10 +181,10 @@ static int zynqmp_qspi_ofdata_to_platdata(struct udevice *bus) debug("%s\n", __func__); - plat->regs = (struct zynqmp_qspi_regs *)(devfdt_get_addr(bus) + + plat->regs = (struct zynqmp_qspi_regs *)(dev_read_addr(bus) + GQSPI_REG_OFFSET); plat->dma_regs = (struct zynqmp_qspi_dma_regs *) - (devfdt_get_addr(bus) + GQSPI_DMA_REG_OFFSET); + (dev_read_addr(bus) + GQSPI_DMA_REG_OFFSET); return 0; } diff --git a/drivers/spmi/spmi-msm.c b/drivers/spmi/spmi-msm.c index ed93faffcb..2f430aed9c 100644 --- a/drivers/spmi/spmi-msm.c +++ b/drivers/spmi/spmi-msm.c @@ -156,7 +156,7 @@ static int msm_spmi_probe(struct udevice *dev) bool is_v1; int i; - priv->arb_chnl = devfdt_get_addr(dev); + priv->arb_chnl = dev_read_addr(dev); priv->spmi_core = fdtdec_get_addr_size_auto_parent(gd->fdt_blob, dev_of_offset(parent), node, "reg", 1, NULL, false); priv->spmi_obs = fdtdec_get_addr_size_auto_parent(gd->fdt_blob, diff --git a/drivers/sysreset/sysreset-uclass.c b/drivers/sysreset/sysreset-uclass.c index 995240f0cb..3f5414ed1f 100644 --- a/drivers/sysreset/sysreset-uclass.c +++ b/drivers/sysreset/sysreset-uclass.c @@ -117,6 +117,7 @@ void reset_cpu(ulong addr) int do_reset(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) { printf("resetting ...\n"); + mdelay(100); sysreset_walk_halt(SYSRESET_COLD); diff --git a/drivers/tee/Kconfig b/drivers/tee/Kconfig index 5c0c89043f..5ca5a0836c 100644 --- a/drivers/tee/Kconfig +++ b/drivers/tee/Kconfig @@ -29,6 +29,7 @@ config SANDBOX_TEE "avb" commands. source "drivers/tee/optee/Kconfig" +source "drivers/tee/broadcom/Kconfig" endmenu diff --git a/drivers/tee/Makefile b/drivers/tee/Makefile index f72c68c09f..5c8ffdbce8 100644 --- a/drivers/tee/Makefile +++ b/drivers/tee/Makefile @@ -3,3 +3,4 @@ obj-y += tee-uclass.o obj-$(CONFIG_SANDBOX) += sandbox.o obj-$(CONFIG_OPTEE) += optee/ +obj-y += broadcom/ diff --git a/drivers/tee/broadcom/Kconfig b/drivers/tee/broadcom/Kconfig new file mode 100644 index 0000000000..ce95072d4e --- /dev/null +++ b/drivers/tee/broadcom/Kconfig @@ -0,0 +1,7 @@ +config CHIMP_OPTEE + bool "Enable secure ChiMP firmware loading" + depends on OPTEE + default y + help + This driver is used to load bnxt firmware binary using OpTEE. + bnxt is Broadcom NetXtreme controller Ethernet card. diff --git a/drivers/tee/broadcom/Makefile b/drivers/tee/broadcom/Makefile new file mode 100644 index 0000000000..cb3cef16df --- /dev/null +++ b/drivers/tee/broadcom/Makefile @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0+ + +obj-y += chimp_optee.o diff --git a/drivers/tee/broadcom/chimp_optee.c b/drivers/tee/broadcom/chimp_optee.c new file mode 100644 index 0000000000..37f9b094f7 --- /dev/null +++ b/drivers/tee/broadcom/chimp_optee.c @@ -0,0 +1,183 @@ +// SPDX-License-Identifier: BSD-2-Clause +/* + * Copyright 2020 Broadcom. + */ + +#include <common.h> +#include <tee.h> +#include <broadcom/chimp.h> + +#ifdef CONFIG_CHIMP_OPTEE + +#define CHMIP_BOOT_UUID { 0x6272636D, 0x2019, 0x0716, \ + { 0x42, 0x43, 0x4D, 0x5F, 0x53, 0x43, 0x48, 0x49 } } + +enum { + TEE_CHIMP_FASTBOOT = 0, + TEE_CHIMP_HEALTH_STATUS, + TEE_CHIMP_HANDSHAKE_STATUS, +} tee_chmip_cmd; + +struct bcm_chimp_data { + struct udevice *tee; + u32 session; +} chimp_data; + +static int get_open_session(struct bcm_chimp_data *b_data) +{ + const struct tee_optee_ta_uuid uuid = CHMIP_BOOT_UUID; + struct tee_open_session_arg arg; + struct udevice *tee = NULL; + int rc; + + tee = tee_find_device(NULL, NULL, NULL, NULL); + if (!tee) + return -ENODEV; + + memset(&arg, 0, sizeof(arg)); + tee_optee_ta_uuid_to_octets(arg.uuid, &uuid); + rc = tee_open_session(tee, &arg, 0, NULL); + if (rc < 0) + return -ENODEV; + + b_data->tee = tee; + b_data->session = arg.session; + + return 0; +} + +static int init_arg(struct tee_invoke_arg *arg, u32 func) +{ + if (get_open_session(&chimp_data)) + return -EINVAL; + + memset(arg, 0, sizeof(struct tee_invoke_arg)); + arg->func = func; + arg->session = chimp_data.session; + + return 0; +} + +int chimp_handshake_status_optee(u32 timeout, u32 *hs) +{ + struct tee_invoke_arg arg; + struct tee_param param[1]; + int ret; + + ret = init_arg(&arg, TEE_CHIMP_HANDSHAKE_STATUS); + if (ret < 0) + return ret; + + param[0].attr = TEE_PARAM_ATTR_TYPE_VALUE_INOUT; + param[0].u.value.a = timeout; + + ret = tee_invoke_func(chimp_data.tee, &arg, ARRAY_SIZE(param), param); + if (ret < 0) { + printf("Handshake status command failed\n"); + goto out; + } + + switch (arg.ret) { + case TEE_SUCCESS: + *hs = param[0].u.value.a; + ret = 0; + break; + default: + ret = -EINVAL; + break; + } + +out: + tee_close_session(chimp_data.tee, chimp_data.session); + chimp_data.tee = NULL; + + return ret; +} + +int chimp_health_status_optee(u32 *health) +{ + struct tee_invoke_arg arg; + struct tee_param param[1]; + int ret; + + ret = init_arg(&arg, TEE_CHIMP_HEALTH_STATUS); + if (ret < 0) + return ret; + + param[0].attr = TEE_PARAM_ATTR_TYPE_VALUE_OUTPUT; + + ret = tee_invoke_func(chimp_data.tee, &arg, ARRAY_SIZE(param), param); + if (ret < 0) { + printf("Helath status command failed\n"); + goto out; + } + + switch (arg.ret) { + case TEE_SUCCESS: + *health = param[0].u.value.a; + ret = 0; + break; + default: + ret = -EINVAL; + break; + } + +out: + tee_close_session(chimp_data.tee, chimp_data.session); + chimp_data.tee = NULL; + + return ret; +} + +int chimp_fastboot_optee(void) +{ + struct tee_invoke_arg arg; + int ret; + + ret = init_arg(&arg, TEE_CHIMP_FASTBOOT); + if (ret < 0) + return ret; + + ret = tee_invoke_func(chimp_data.tee, &arg, 0, NULL); + if (ret < 0) { + printf("Chimp boot_fail\n"); + goto out; + } + + switch (arg.ret) { + case TEE_SUCCESS: + ret = 0; + break; + default: + ret = -EINVAL; + break; + } + +out: + tee_close_session(chimp_data.tee, chimp_data.session); + chimp_data.tee = NULL; + + return ret; +} +#else +int chimp_handshake_status_optee(u32 timeout, u32 *status) +{ + printf("ChiMP handshake status fail (OPTEE not enabled)\n"); + + return -EINVAL; +} + +int chimp_health_status_optee(u32 *status) +{ + printf("ChiMP health status fail (OPTEE not enabled)\n"); + + return -EINVAL; +} + +int chimp_fastboot_optee(void) +{ + printf("ChiMP secure boot fail (OPTEE not enabled)\n"); + + return -EINVAL; +} +#endif /* CONFIG_CHIMP_OPTEE */ diff --git a/drivers/timer/ag101p_timer.c b/drivers/timer/ag101p_timer.c index 6e20b4fc33..c011906b93 100644 --- a/drivers/timer/ag101p_timer.c +++ b/drivers/timer/ag101p_timer.c @@ -92,7 +92,7 @@ static int atftmr_timer_probe(struct udevice *dev) static int atftme_timer_ofdata_to_platdata(struct udevice *dev) { struct atftmr_timer_platdata *plat = dev_get_platdata(dev); - plat->regs = map_physmem(devfdt_get_addr(dev), + plat->regs = map_physmem(dev_read_addr(dev), sizeof(struct atftmr_timer_regs), MAP_NOCACHE); return 0; diff --git a/drivers/timer/altera_timer.c b/drivers/timer/altera_timer.c index 6ca9501eb1..6cb2923e0b 100644 --- a/drivers/timer/altera_timer.c +++ b/drivers/timer/altera_timer.c @@ -69,7 +69,7 @@ static int altera_timer_ofdata_to_platdata(struct udevice *dev) { struct altera_timer_platdata *plat = dev_get_platdata(dev); - plat->regs = map_physmem(devfdt_get_addr(dev), + plat->regs = map_physmem(dev_read_addr(dev), sizeof(struct altera_timer_regs), MAP_NOCACHE); diff --git a/drivers/timer/atcpit100_timer.c b/drivers/timer/atcpit100_timer.c index c5d43b4a4a..5d4ae68509 100644 --- a/drivers/timer/atcpit100_timer.c +++ b/drivers/timer/atcpit100_timer.c @@ -89,7 +89,7 @@ static int atcpit_timer_probe(struct udevice *dev) static int atcpit_timer_ofdata_to_platdata(struct udevice *dev) { struct atcpit_timer_platdata *plat = dev_get_platdata(dev); - plat->regs = map_physmem(devfdt_get_addr(dev) , 0x100 , MAP_NOCACHE); + plat->regs = map_physmem(dev_read_addr(dev), 0x100 , MAP_NOCACHE); return 0; } diff --git a/drivers/timer/omap-timer.c b/drivers/timer/omap-timer.c index 700c349f37..cf3d27b96b 100644 --- a/drivers/timer/omap-timer.c +++ b/drivers/timer/omap-timer.c @@ -79,7 +79,7 @@ static int omap_timer_ofdata_to_platdata(struct udevice *dev) { struct omap_timer_priv *priv = dev_get_priv(dev); - priv->regs = map_physmem(devfdt_get_addr(dev), + priv->regs = map_physmem(dev_read_addr(dev), sizeof(struct omap_gptimer_regs), MAP_NOCACHE); return 0; diff --git a/drivers/ufs/cdns-platform.c b/drivers/ufs/cdns-platform.c index 1a7bb7bed8..bad1bf7de5 100644 --- a/drivers/ufs/cdns-platform.c +++ b/drivers/ufs/cdns-platform.c @@ -9,6 +9,7 @@ #include <common.h> #include <dm.h> #include <ufs.h> +#include <asm/io.h> #include <dm/device_compat.h> #include <linux/bitops.h> #include <linux/err.h> diff --git a/drivers/ufs/ufs.c b/drivers/ufs/ufs.c index 87b4e5fc56..92b7e9fd7c 100644 --- a/drivers/ufs/ufs.c +++ b/drivers/ufs/ufs.c @@ -19,9 +19,10 @@ #include <malloc.h> #include <hexdump.h> #include <scsi.h> +#include <asm/io.h> +#include <asm/dma-mapping.h> #include <linux/bitops.h> #include <linux/delay.h> - #include <linux/dma-mapping.h> #include "ufs.h" diff --git a/drivers/ufs/ufs.h b/drivers/ufs/ufs.h index e0bde93776..069888fdd9 100644 --- a/drivers/ufs/ufs.h +++ b/drivers/ufs/ufs.h @@ -2,11 +2,10 @@ #ifndef __UFS_H #define __UFS_H -#include <asm/io.h> -#include <dm.h> - #include "unipro.h" +struct udevice; + #define UFS_CDB_SIZE 16 #define UPIU_TRANSACTION_UIC_CMD 0x1F #define UIC_CMD_SIZE (sizeof(u32) * 4) diff --git a/drivers/usb/dwc3/dwc3-uniphier.c b/drivers/usb/dwc3/dwc3-uniphier.c index 88317b19ac..54b52dcd66 100644 --- a/drivers/usb/dwc3/dwc3-uniphier.c +++ b/drivers/usb/dwc3/dwc3-uniphier.c @@ -70,7 +70,7 @@ static int uniphier_dwc3_probe(struct udevice *dev) int (*init)(void __iomem *regs); int ret; - base = devfdt_get_addr(dev); + base = dev_read_addr(dev); if (base == FDT_ADDR_T_NONE) return -EINVAL; diff --git a/drivers/usb/host/ehci-atmel.c b/drivers/usb/host/ehci-atmel.c index f9083d9a64..3b208e8eb2 100644 --- a/drivers/usb/host/ehci-atmel.c +++ b/drivers/usb/host/ehci-atmel.c @@ -95,7 +95,7 @@ static int ehci_atmel_probe(struct udevice *dev) /* * Get the base address for EHCI controller from the device node */ - hcd_base = devfdt_get_addr(dev); + hcd_base = dev_read_addr(dev); if (hcd_base == FDT_ADDR_T_NONE) { debug("Can't get the EHCI register base address\n"); return -ENXIO; diff --git a/drivers/usb/host/ehci-exynos.c b/drivers/usb/host/ehci-exynos.c index 0b0b2137c7..6a37c5d982 100644 --- a/drivers/usb/host/ehci-exynos.c +++ b/drivers/usb/host/ehci-exynos.c @@ -53,7 +53,7 @@ static int ehci_usb_ofdata_to_platdata(struct udevice *dev) /* * Get the base address for XHCI controller from the device node */ - plat->hcd_base = devfdt_get_addr(dev); + plat->hcd_base = dev_read_addr(dev); if (plat->hcd_base == FDT_ADDR_T_NONE) { debug("Can't get the XHCI register base address\n"); return -ENXIO; diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c index ac6c5b5845..5423d10abe 100644 --- a/drivers/usb/host/ehci-fsl.c +++ b/drivers/usb/host/ehci-fsl.c @@ -105,7 +105,7 @@ static int ehci_fsl_probe(struct udevice *dev) /* * Get the base address for EHCI controller from the device node */ - priv->hcd_base = devfdt_get_addr(dev); + priv->hcd_base = dev_read_addr(dev); if (priv->hcd_base == FDT_ADDR_T_NONE) { debug("Can't get the EHCI register base address\n"); return -ENXIO; diff --git a/drivers/usb/host/ehci-marvell.c b/drivers/usb/host/ehci-marvell.c index 8fe685af26..62414bb110 100644 --- a/drivers/usb/host/ehci-marvell.c +++ b/drivers/usb/host/ehci-marvell.c @@ -109,7 +109,7 @@ static int ehci_mvebu_probe(struct udevice *dev) /* * Get the base address for EHCI controller from the device node */ - priv->hcd_base = devfdt_get_addr(dev); + priv->hcd_base = dev_read_addr(dev); if (priv->hcd_base == FDT_ADDR_T_NONE) { debug("Can't get the EHCI register base address\n"); return -ENXIO; diff --git a/drivers/usb/host/ehci-mx5.c b/drivers/usb/host/ehci-mx5.c index 212b362332..caafa68899 100644 --- a/drivers/usb/host/ehci-mx5.c +++ b/drivers/usb/host/ehci-mx5.c @@ -306,7 +306,7 @@ static int ehci_usb_ofdata_to_platdata(struct udevice *dev) static int ehci_usb_probe(struct udevice *dev) { struct usb_platdata *plat = dev_get_platdata(dev); - struct usb_ehci *ehci = (struct usb_ehci *)devfdt_get_addr(dev); + struct usb_ehci *ehci = dev_read_addr_ptr(dev); struct ehci_mx5_priv_data *priv = dev_get_priv(dev); enum usb_init_type type = plat->init_type; struct ehci_hccr *hccr; diff --git a/drivers/usb/host/ehci-mx6.c b/drivers/usb/host/ehci-mx6.c index 5f84c7b91d..37b59758bb 100644 --- a/drivers/usb/host/ehci-mx6.c +++ b/drivers/usb/host/ehci-mx6.c @@ -473,7 +473,7 @@ static const struct ehci_ops mx6_ehci_ops = { static int ehci_usb_phy_mode(struct udevice *dev) { struct usb_platdata *plat = dev_get_platdata(dev); - void *__iomem addr = (void *__iomem)devfdt_get_addr(dev); + void *__iomem addr = dev_read_addr_ptr(dev); void *__iomem phy_ctrl, *__iomem phy_status; const void *blob = gd->fdt_blob; int offset = dev_of_offset(dev), phy_off; @@ -580,7 +580,7 @@ static int ehci_usb_bind(struct udevice *dev) static int ehci_usb_probe(struct udevice *dev) { struct usb_platdata *plat = dev_get_platdata(dev); - struct usb_ehci *ehci = (struct usb_ehci *)devfdt_get_addr(dev); + struct usb_ehci *ehci = dev_read_addr_ptr(dev); struct ehci_mx6_priv_data *priv = dev_get_priv(dev); enum usb_init_type type = plat->init_type; struct ehci_hccr *hccr; diff --git a/drivers/usb/host/ehci-omap.c b/drivers/usb/host/ehci-omap.c index 93ab83941d..82b99eeef1 100644 --- a/drivers/usb/host/ehci-omap.c +++ b/drivers/usb/host/ehci-omap.c @@ -382,7 +382,7 @@ static int omap_ehci_probe(struct udevice *dev) struct ehci_hccr *hccr; struct ehci_hcor *hcor; - priv->ehci = (struct omap_ehci *)devfdt_get_addr(dev); + priv->ehci = dev_read_addr_ptr(dev); priv->portnr = dev->seq; priv->init_type = plat->init_type; diff --git a/drivers/usb/host/ehci-vf.c b/drivers/usb/host/ehci-vf.c index 562207d3d2..2768d40974 100644 --- a/drivers/usb/host/ehci-vf.c +++ b/drivers/usb/host/ehci-vf.c @@ -224,7 +224,7 @@ static int vf_usb_ofdata_to_platdata(struct udevice *dev) priv->portnr = dev->seq; - priv->ehci = (struct usb_ehci *)devfdt_get_addr(dev); + priv->ehci = dev_read_addr_ptr(dev); mode = fdt_getprop(dt_blob, node, "dr_mode", NULL); if (mode) { if (0 == strcmp(mode, "host")) { diff --git a/drivers/usb/host/ohci-da8xx.c b/drivers/usb/host/ohci-da8xx.c index 692018243c..22e7b565b5 100644 --- a/drivers/usb/host/ohci-da8xx.c +++ b/drivers/usb/host/ohci-da8xx.c @@ -89,7 +89,7 @@ int usb_cpu_init_fail(void) #if CONFIG_IS_ENABLED(DM_USB) static int ohci_da8xx_probe(struct udevice *dev) { - struct ohci_regs *regs = (struct ohci_regs *)devfdt_get_addr(dev); + struct ohci_regs *regs = dev_read_addr_ptr(dev); struct da8xx_ohci *priv = dev_get_priv(dev); int i, err, ret, clock_nb; diff --git a/drivers/usb/host/ohci-generic.c b/drivers/usb/host/ohci-generic.c index 631711a9e8..b84bf8ac0f 100644 --- a/drivers/usb/host/ohci-generic.c +++ b/drivers/usb/host/ohci-generic.c @@ -79,7 +79,7 @@ static int ohci_shutdown_phy(struct udevice *dev) static int ohci_usb_probe(struct udevice *dev) { - struct ohci_regs *regs = (struct ohci_regs *)devfdt_get_addr(dev); + struct ohci_regs *regs = dev_read_addr_ptr(dev); struct generic_ohci *priv = dev_get_priv(dev); int i, err, ret, clock_nb, reset_nb; diff --git a/drivers/usb/host/xhci-exynos5.c b/drivers/usb/host/xhci-exynos5.c index 1705accbde..6fb7a7f6e0 100644 --- a/drivers/usb/host/xhci-exynos5.c +++ b/drivers/usb/host/xhci-exynos5.c @@ -62,7 +62,7 @@ static int xhci_usb_ofdata_to_platdata(struct udevice *dev) /* * Get the base address for XHCI controller from the device node */ - plat->hcd_base = devfdt_get_addr(dev); + plat->hcd_base = dev_read_addr(dev); if (plat->hcd_base == FDT_ADDR_T_NONE) { debug("Can't get the XHCI register base address\n"); return -ENXIO; diff --git a/drivers/usb/host/xhci-fsl.c b/drivers/usb/host/xhci-fsl.c index d8fb2c5345..0a2da70e20 100644 --- a/drivers/usb/host/xhci-fsl.c +++ b/drivers/usb/host/xhci-fsl.c @@ -120,7 +120,7 @@ static int xhci_fsl_probe(struct udevice *dev) /* * Get the base address for XHCI controller from the device node */ - priv->hcd_base = devfdt_get_addr(dev); + priv->hcd_base = dev_read_addr(dev); if (priv->hcd_base == FDT_ADDR_T_NONE) { debug("Can't get the XHCI register base address\n"); return -ENXIO; diff --git a/drivers/usb/host/xhci-mvebu.c b/drivers/usb/host/xhci-mvebu.c index 5fb74848c2..f2e338f6fb 100644 --- a/drivers/usb/host/xhci-mvebu.c +++ b/drivers/usb/host/xhci-mvebu.c @@ -72,7 +72,7 @@ static int xhci_usb_ofdata_to_platdata(struct udevice *dev) /* * Get the base address for XHCI controller from the device node */ - plat->hcd_base = devfdt_get_addr(dev); + plat->hcd_base = dev_read_addr(dev); if (plat->hcd_base == FDT_ADDR_T_NONE) { debug("Can't get the XHCI register base address\n"); return -ENXIO; diff --git a/drivers/usb/host/xhci-rcar.c b/drivers/usb/host/xhci-rcar.c index 4964697f27..8fc51df3d1 100644 --- a/drivers/usb/host/xhci-rcar.c +++ b/drivers/usb/host/xhci-rcar.c @@ -136,7 +136,7 @@ static int xhci_rcar_ofdata_to_platdata(struct udevice *dev) { struct rcar_xhci_platdata *plat = dev_get_platdata(dev); - plat->hcd_base = devfdt_get_addr(dev); + plat->hcd_base = dev_read_addr(dev); if (plat->hcd_base == FDT_ADDR_T_NONE) { debug("Can't get the XHCI register base address\n"); return -ENXIO; diff --git a/drivers/usb/musb-new/musb_uboot.c b/drivers/usb/musb-new/musb_uboot.c index 988071a61d..8ac2f0a78a 100644 --- a/drivers/usb/musb-new/musb_uboot.c +++ b/drivers/usb/musb-new/musb_uboot.c @@ -1,5 +1,6 @@ #include <common.h> #include <console.h> +#include <dm.h> #include <malloc.h> #include <watchdog.h> #include <linux/delay.h> @@ -452,3 +453,39 @@ struct musb *musb_register(struct musb_hdrc_platform_data *plat, void *bdata, return *musbp; } + +#if CONFIG_IS_ENABLED(DM_USB) +struct usb_device *usb_dev_get_parent(struct usb_device *udev) +{ + struct udevice *parent = udev->dev->parent; + + /* + * When called from usb-uclass.c: usb_scan_device() udev->dev points + * to the parent udevice, not the actual udevice belonging to the + * udev as the device is not instantiated yet. + * + * If dev is an usb-bus, then we are called from usb_scan_device() for + * an usb-device plugged directly into the root port, return NULL. + */ + if (device_get_uclass_id(udev->dev) == UCLASS_USB) + return NULL; + + /* + * If these 2 are not the same we are being called from + * usb_scan_device() and udev itself is the parent. + */ + if (dev_get_parent_priv(udev->dev) != udev) + return udev; + + /* We are being called normally, use the parent pointer */ + if (device_get_uclass_id(parent) == UCLASS_USB_HUB) + return dev_get_parent_priv(parent); + + return NULL; +} +#else +struct usb_device *usb_dev_get_parent(struct usb_device *udev) +{ + return udev->parent; +} +#endif diff --git a/drivers/usb/musb-new/pic32.c b/drivers/usb/musb-new/pic32.c index 74a841af46..2fbe9bebf1 100644 --- a/drivers/usb/musb-new/pic32.c +++ b/drivers/usb/musb-new/pic32.c @@ -10,6 +10,7 @@ */ #include <common.h> +#include <dm.h> #include <dm/device_compat.h> #include <linux/bitops.h> #include <linux/delay.h> diff --git a/drivers/usb/musb-new/usb-compat.h b/drivers/usb/musb-new/usb-compat.h index f2c18ad3a2..1c66c4fe36 100644 --- a/drivers/usb/musb-new/usb-compat.h +++ b/drivers/usb/musb-new/usb-compat.h @@ -1,9 +1,10 @@ #ifndef __USB_COMPAT_H__ #define __USB_COMPAT_H__ -#include <dm.h> #include "usb.h" +struct udevice; + struct usb_hcd { void *hcd_priv; }; @@ -67,40 +68,12 @@ static inline int usb_hcd_unmap_urb_for_dma(struct usb_hcd *hcd, return 0; } -#if CONFIG_IS_ENABLED(DM_USB) -static inline struct usb_device *usb_dev_get_parent(struct usb_device *udev) -{ - struct udevice *parent = udev->dev->parent; - - /* - * When called from usb-uclass.c: usb_scan_device() udev->dev points - * to the parent udevice, not the actual udevice belonging to the - * udev as the device is not instantiated yet. - * - * If dev is an usb-bus, then we are called from usb_scan_device() for - * an usb-device plugged directly into the root port, return NULL. - */ - if (device_get_uclass_id(udev->dev) == UCLASS_USB) - return NULL; - - /* - * If these 2 are not the same we are being called from - * usb_scan_device() and udev itself is the parent. - */ - if (dev_get_parent_priv(udev->dev) != udev) - return udev; - - /* We are being called normally, use the parent pointer */ - if (device_get_uclass_id(parent) == UCLASS_USB_HUB) - return dev_get_parent_priv(parent); - - return NULL; -} -#else -static inline struct usb_device *usb_dev_get_parent(struct usb_device *dev) -{ - return dev->parent; -} -#endif +/** + * usb_dev_get_parent() - Get the parent of a USB device + * + * @udev: USB struct containing information about the device + * @return associated device for which udev == dev_get_parent_priv(dev) + */ +struct usb_device *usb_dev_get_parent(struct usb_device *udev); #endif /* __USB_COMPAT_H__ */ diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 89ad603d88..55f4fa42ab 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -644,6 +644,16 @@ source "drivers/video/bridge/Kconfig" source "drivers/video/imx/Kconfig" +config VIDEO_NX + bool "Enable video support on Nexell SoC" + depends on ARCH_S5P6818 || ARCH_S5P4418 + help + Nexell SoC supports many video output options including eDP and + HDMI. This option enables this support which can be used on devices + which have an eDP display connected. + +source "drivers/video/nexell/Kconfig" + config VIDEO bool "Enable legacy video support" depends on !DM_VIDEO diff --git a/drivers/video/Makefile b/drivers/video/Makefile index 1dbd09a172..67a492a2d6 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile @@ -62,6 +62,7 @@ obj-${CONFIG_VIDEO_MIPI_DSI} += mipi_dsi.o obj-$(CONFIG_VIDEO_MVEBU) += mvebu_lcd.o obj-$(CONFIG_VIDEO_MX3) += mx3fb.o videomodes.o obj-$(CONFIG_VIDEO_MXS) += mxsfb.o videomodes.o +obj-$(CONFIG_VIDEO_NX) += nexell_display.o videomodes.o nexell/ obj-$(CONFIG_VIDEO_OMAP3) += omap3_dss.o obj-$(CONFIG_VIDEO_DSI_HOST_SANDBOX) += sandbox_dsi_host.o obj-$(CONFIG_VIDEO_SANDBOX_SDL) += sandbox_sdl.o diff --git a/drivers/video/atmel_hlcdfb.c b/drivers/video/atmel_hlcdfb.c index 35a56a8eab..38def2816b 100644 --- a/drivers/video/atmel_hlcdfb.c +++ b/drivers/video/atmel_hlcdfb.c @@ -507,7 +507,7 @@ static int atmel_hlcdc_ofdata_to_platdata(struct udevice *dev) const void *blob = gd->fdt_blob; int node = dev_of_offset(dev); - priv->regs = (struct atmel_hlcd_regs *)devfdt_get_addr(dev); + priv->regs = dev_read_addr_ptr(dev); if (!priv->regs) { debug("%s: No display controller address\n", __func__); return -EINVAL; diff --git a/drivers/video/exynos/exynos_dp.c b/drivers/video/exynos/exynos_dp.c index 749bde862e..999ee1c14a 100644 --- a/drivers/video/exynos/exynos_dp.c +++ b/drivers/video/exynos/exynos_dp.c @@ -884,7 +884,7 @@ static int exynos_dp_ofdata_to_platdata(struct udevice *dev) unsigned int node = dev_of_offset(dev); fdt_addr_t addr; - addr = devfdt_get_addr(dev); + addr = dev_read_addr(dev); if (addr == FDT_ADDR_T_NONE) { debug("Can't get the DP base address\n"); return -EINVAL; diff --git a/drivers/video/exynos/exynos_fb.c b/drivers/video/exynos/exynos_fb.c index d5b13a6723..979b909182 100644 --- a/drivers/video/exynos/exynos_fb.c +++ b/drivers/video/exynos/exynos_fb.c @@ -486,7 +486,7 @@ int exynos_fb_ofdata_to_platdata(struct udevice *dev) const void *blob = gd->fdt_blob; fdt_addr_t addr; - addr = devfdt_get_addr(dev); + addr = dev_read_addr(dev); if (addr == FDT_ADDR_T_NONE) { debug("Can't get the FIMD base address\n"); return -EINVAL; diff --git a/drivers/video/imx/mxc_ipuv3_fb.c b/drivers/video/imx/mxc_ipuv3_fb.c index 492bc3e829..eb93a4f1fa 100644 --- a/drivers/video/imx/mxc_ipuv3_fb.c +++ b/drivers/video/imx/mxc_ipuv3_fb.c @@ -66,6 +66,7 @@ static void fb_videomode_to_var(struct fb_var_screeninfo *var, * Structure containing the MXC specific framebuffer information. */ struct mxcfb_info { + struct udevice *udev; int blank; ipu_channel_t ipu_ch; int ipu_di; @@ -381,13 +382,16 @@ static int mxcfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) static int mxcfb_map_video_memory(struct fb_info *fbi) { + struct mxcfb_info *mxc_fbi = (struct mxcfb_info *)fbi->par; + struct video_uc_platdata *plat = dev_get_uclass_platdata(mxc_fbi->udev); + if (fbi->fix.smem_len < fbi->var.yres_virtual * fbi->fix.line_length) { fbi->fix.smem_len = fbi->var.yres_virtual * fbi->fix.line_length; } fbi->fix.smem_len = roundup(fbi->fix.smem_len, ARCH_DMA_MINALIGN); - fbi->screen_base = (char *)gd->video_bottom; + fbi->screen_base = (char *)plat->base; fbi->fix.smem_start = (unsigned long)fbi->screen_base; if (fbi->screen_base == 0) { @@ -477,8 +481,8 @@ extern struct clk *g_ipu_clk; * * @return Appropriate error code to the kernel common code */ -static int mxcfb_probe(u32 interface_pix_fmt, uint8_t disp, - struct fb_videomode const *mode) +static int mxcfb_probe(struct udevice *dev, u32 interface_pix_fmt, + uint8_t disp, struct fb_videomode const *mode) { struct fb_info *fbi; struct mxcfb_info *mxcfbi; @@ -501,6 +505,7 @@ static int mxcfb_probe(u32 interface_pix_fmt, uint8_t disp, } mxcfbi->ipu_di = disp; + mxcfbi->udev = dev; if (!ipu_clk_enabled()) clk_enable(g_ipu_clk); @@ -600,7 +605,7 @@ static int ipuv3_video_probe(struct udevice *dev) if (ret < 0) return ret; - ret = mxcfb_probe(gpixfmt, gdisp, gmode); + ret = mxcfb_probe(dev, gpixfmt, gdisp, gmode); if (ret < 0) return ret; diff --git a/drivers/video/nexell/Kconfig b/drivers/video/nexell/Kconfig new file mode 100644 index 0000000000..54b8ccb56e --- /dev/null +++ b/drivers/video/nexell/Kconfig @@ -0,0 +1,27 @@ +if VIDEO_NX + +menu "LCD select" + +config VIDEO_NX_RGB + bool "RGB LCD" + help + Support for RGB lcd output. + +config VIDEO_NX_LVDS + bool "LVDS LCD" + help + Support for LVDS lcd output. + +config VIDEO_NX_MIPI + bool "MiPi" + help + Support for MiPi lcd output. + +config VIDEO_NX_HDMI + bool "HDMI" + help + Support for hdmi output. + +endmenu + +endif diff --git a/drivers/video/nexell/Makefile b/drivers/video/nexell/Makefile new file mode 100644 index 0000000000..111ab4533c --- /dev/null +++ b/drivers/video/nexell/Makefile @@ -0,0 +1,12 @@ +# SPDX-License-Identifier: GPL-2.0+ +# +# (C) Copyright 2016 Nexell +# Junghyun, kim<jhkim@nexell.co.kr> + +obj-$(CONFIG_VIDEO_NX) += s5pxx18_dp.o +obj-$(CONFIG_VIDEO_NX) += soc/ + +obj-$(CONFIG_VIDEO_NX_RGB) += s5pxx18_dp_rgb.o +obj-$(CONFIG_VIDEO_NX_LVDS) += s5pxx18_dp_lvds.o +obj-$(CONFIG_VIDEO_NX_MIPI) += s5pxx18_dp_mipi.o +obj-$(CONFIG_VIDEO_NX_HDMI) += s5pxx18_dp_hdmi.o diff --git a/drivers/video/nexell/s5pxx18_dp.c b/drivers/video/nexell/s5pxx18_dp.c new file mode 100644 index 0000000000..2248f47905 --- /dev/null +++ b/drivers/video/nexell/s5pxx18_dp.c @@ -0,0 +1,341 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2016 Nexell Co., Ltd. + * + * Author: junghyun, kim <jhkim@nexell.co.kr> + */ + +#include <config.h> +#include <common.h> +#include <errno.h> +#include <log.h> +#include <asm/arch/reset.h> +#include <asm/arch/nexell.h> +#include <asm/arch/display.h> + +#include "soc/s5pxx18_soc_disptop.h" +#include "soc/s5pxx18_soc_dpc.h" +#include "soc/s5pxx18_soc_mlc.h" + +#define MLC_LAYER_RGB_0 0 /* number of RGB layer 0 */ +#define MLC_LAYER_RGB_1 1 /* number of RGB layer 1 */ +#define MLC_LAYER_VIDEO 3 /* number of Video layer: 3 = VIDEO */ + +#define __io_address(a) (void *)(uintptr_t)(a) + +void dp_control_init(int module) +{ + void *base; + + /* top */ + base = __io_address(nx_disp_top_get_physical_address()); + nx_disp_top_set_base_address(base); + + /* control */ + base = __io_address(nx_dpc_get_physical_address(module)); + nx_dpc_set_base_address(module, base); + + /* top controller */ + nx_rstcon_setrst(RESET_ID_DISP_TOP, RSTCON_ASSERT); + nx_rstcon_setrst(RESET_ID_DISP_TOP, RSTCON_NEGATE); + + /* display controller */ + nx_rstcon_setrst(RESET_ID_DISPLAY, RSTCON_ASSERT); + nx_rstcon_setrst(RESET_ID_DISPLAY, RSTCON_NEGATE); + + nx_dpc_set_clock_pclk_mode(module, nx_pclkmode_always); +} + +int dp_control_setup(int module, + struct dp_sync_info *sync, struct dp_ctrl_info *ctrl) +{ + unsigned int out_format; + unsigned int delay_mask; + int rgb_pvd = 0, hsync_cp1 = 7, vsync_fram = 7, de_cp2 = 7; + int v_vso = 1, v_veo = 1, e_vso = 1, e_veo = 1; + + int interlace = 0; + int invert_field; + int swap_rb; + unsigned int yc_order; + int vck_select; + int vclk_invert; + int emb_sync; + + enum nx_dpc_dither r_dither, g_dither, b_dither; + int rgb_mode = 0; + + if (NULL == sync || NULL == ctrl) { + debug("error, dp.%d not set sync or pad clock info !!!\n", + module); + return -EINVAL; + } + + out_format = ctrl->out_format; + delay_mask = ctrl->delay_mask; + interlace = sync->interlace; + invert_field = ctrl->invert_field; + swap_rb = ctrl->swap_RB; + yc_order = ctrl->yc_order; + vck_select = ctrl->vck_select; + vclk_invert = ctrl->clk_inv_lv0 | ctrl->clk_inv_lv1; + emb_sync = (out_format == DPC_FORMAT_CCIR656 ? 1 : 0); + + /* set delay mask */ + if (delay_mask & DP_SYNC_DELAY_RGB_PVD) + rgb_pvd = ctrl->d_rgb_pvd; + if (delay_mask & DP_SYNC_DELAY_HSYNC_CP1) + hsync_cp1 = ctrl->d_hsync_cp1; + if (delay_mask & DP_SYNC_DELAY_VSYNC_FRAM) + vsync_fram = ctrl->d_vsync_fram; + if (delay_mask & DP_SYNC_DELAY_DE_CP) + de_cp2 = ctrl->d_de_cp2; + + if (ctrl->vs_start_offset != 0 || + ctrl->vs_end_offset != 0 || + ctrl->ev_start_offset != 0 || ctrl->ev_end_offset != 0) { + v_vso = ctrl->vs_start_offset; + v_veo = ctrl->vs_end_offset; + e_vso = ctrl->ev_start_offset; + e_veo = ctrl->ev_end_offset; + } + + if (nx_dpc_format_rgb555 == out_format || + nx_dpc_format_mrgb555a == out_format || + nx_dpc_format_mrgb555b == out_format) { + r_dither = nx_dpc_dither_5bit; + g_dither = nx_dpc_dither_5bit; + b_dither = nx_dpc_dither_5bit; + rgb_mode = 1; + } else if (nx_dpc_format_rgb565 == out_format || + nx_dpc_format_mrgb565 == out_format) { + r_dither = nx_dpc_dither_5bit; + b_dither = nx_dpc_dither_5bit; + g_dither = nx_dpc_dither_6bit, rgb_mode = 1; + } else if ((nx_dpc_format_rgb666 == out_format) || + (nx_dpc_format_mrgb666 == out_format)) { + r_dither = nx_dpc_dither_6bit; + g_dither = nx_dpc_dither_6bit; + b_dither = nx_dpc_dither_6bit; + rgb_mode = 1; + } else { + r_dither = nx_dpc_dither_bypass; + g_dither = nx_dpc_dither_bypass; + b_dither = nx_dpc_dither_bypass; + rgb_mode = 1; + } + + /* CLKGEN0/1 */ + nx_dpc_set_clock_source(module, 0, ctrl->clk_src_lv0 == 3 ? + 6 : ctrl->clk_src_lv0); + nx_dpc_set_clock_divisor(module, 0, ctrl->clk_div_lv0); + nx_dpc_set_clock_source(module, 1, ctrl->clk_src_lv1); + nx_dpc_set_clock_divisor(module, 1, ctrl->clk_div_lv1); + nx_dpc_set_clock_out_delay(module, 0, ctrl->clk_delay_lv0); + nx_dpc_set_clock_out_delay(module, 1, ctrl->clk_delay_lv1); + + /* LCD out */ + nx_dpc_set_mode(module, out_format, interlace, invert_field, + rgb_mode, swap_rb, yc_order, emb_sync, emb_sync, + vck_select, vclk_invert, 0); + nx_dpc_set_hsync(module, sync->h_active_len, sync->h_sync_width, + sync->h_front_porch, sync->h_back_porch, + sync->h_sync_invert); + nx_dpc_set_vsync(module, sync->v_active_len, sync->v_sync_width, + sync->v_front_porch, sync->v_back_porch, + sync->v_sync_invert, sync->v_active_len, + sync->v_sync_width, sync->v_front_porch, + sync->v_back_porch); + nx_dpc_set_vsync_offset(module, v_vso, v_veo, e_vso, e_veo); + nx_dpc_set_delay(module, rgb_pvd, hsync_cp1, vsync_fram, de_cp2); + nx_dpc_set_dither(module, r_dither, g_dither, b_dither); + + if (IS_ENABLED(CONFIG_MACH_S5P6818)) { + /* Set TFT_CLKCTRL (offset : 1030h) + * Field name : DPC0_CLKCTRL, DPC1_CLKCRL + * Default value : clk_inv_lv0/1 = 0 : PADCLK_InvCLK + * Invert case : clk_inv_lv0/1 = 1 : PADCLK_CLK + */ + if (module == 0 && ctrl->clk_inv_lv0) + nx_disp_top_set_padclock(padmux_primary_mlc, + padclk_clk); + if (module == 1 && ctrl->clk_inv_lv1) + nx_disp_top_set_padclock(padmux_secondary_mlc, + padclk_clk); + } + + debug("%s: dp.%d x:%4d, hf:%3d, hb:%3d, hs:%3d, hi=%d\n", + __func__, module, sync->h_active_len, sync->h_front_porch, + sync->h_back_porch, sync->h_sync_width, sync->h_sync_invert); + debug("%s: dp.%d y:%4d, vf:%3d, vb:%3d, vs:%3d, vi=%d\n", + __func__, module, sync->v_active_len, sync->v_front_porch, + sync->v_back_porch, sync->v_sync_width, sync->h_sync_invert); + debug("%s: dp.%d ck.0:%d:%d:%d, ck.1:%d:%d:%d\n", + __func__, module, + ctrl->clk_src_lv0, ctrl->clk_div_lv0, ctrl->clk_inv_lv0, + ctrl->clk_src_lv1, ctrl->clk_div_lv1, ctrl->clk_inv_lv1); + debug("%s: dp.%d vs:%d, ve:%d, es:%d, ee:%d\n", + __func__, module, v_vso, v_veo, e_vso, e_veo); + debug("%s: dp.%d delay RGB:%d, hs:%d, vs:%d, de:%d, fmt:0x%x\n", + __func__, module, rgb_pvd, hsync_cp1, vsync_fram, de_cp2, + out_format); + + return 0; +} + +void dp_control_enable(int module, int on) +{ + debug("%s: dp.%d top %s\n", __func__, module, on ? "ON" : "OFF"); + + nx_dpc_set_dpc_enable(module, on); + nx_dpc_set_clock_divisor_enable(module, on); +} + +void dp_plane_init(int module) +{ + void *base = __io_address(nx_mlc_get_physical_address(module)); + + nx_mlc_set_base_address(module, base); + nx_mlc_set_clock_pclk_mode(module, nx_pclkmode_always); + nx_mlc_set_clock_bclk_mode(module, nx_bclkmode_always); +} + +int dp_plane_screen_setup(int module, struct dp_plane_top *top) +{ + int width = top->screen_width; + int height = top->screen_height; + int interlace = top->interlace; + int video_prior = top->video_prior; + unsigned int bg_color = top->back_color; + + /* MLC TOP layer */ + nx_mlc_set_screen_size(module, width, height); + nx_mlc_set_layer_priority(module, video_prior); + nx_mlc_set_background(module, bg_color); + nx_mlc_set_field_enable(module, interlace); + nx_mlc_set_rgblayer_gama_table_power_mode(module, 0, 0, 0); + nx_mlc_set_rgblayer_gama_table_sleep_mode(module, 1, 1, 1); + nx_mlc_set_rgblayer_gamma_enable(module, 0); + nx_mlc_set_dither_enable_when_using_gamma(module, 0); + nx_mlc_set_gamma_priority(module, 0); + nx_mlc_set_top_power_mode(module, 1); + nx_mlc_set_top_sleep_mode(module, 0); + + debug("%s: dp.%d screen %dx%d, %s, priority:%d, bg:0x%x\n", + __func__, module, width, height, + interlace ? "Interlace" : "Progressive", + video_prior, bg_color); + + return 0; +} + +void dp_plane_screen_enable(int module, int on) +{ + /* enable top screen */ + nx_mlc_set_mlc_enable(module, on); + nx_mlc_set_top_dirty_flag(module); + debug("%s: dp.%d top %s\n", __func__, module, on ? "ON" : "OFF"); +} + +int dp_plane_layer_setup(int module, struct dp_plane_info *plane) +{ + int sx = plane->left; + int sy = plane->top; + int ex = sx + plane->width - 1; + int ey = sy + plane->height - 1; + int pixel_byte = plane->pixel_byte; + int mem_lock_size = 16; /* fix mem lock size */ + int layer = plane->layer; + unsigned int format = plane->format; + + if (!plane->enable) + return -EINVAL; + + /* MLC layer */ + nx_mlc_set_lock_size(module, layer, mem_lock_size); + nx_mlc_set_alpha_blending(module, layer, 0, 15); + nx_mlc_set_transparency(module, layer, 0, 0); + nx_mlc_set_color_inversion(module, layer, 0, 0); + nx_mlc_set_rgblayer_invalid_position(module, layer, 0, 0, 0, 0, 0, 0); + nx_mlc_set_rgblayer_invalid_position(module, layer, 1, 0, 0, 0, 0, 0); + nx_mlc_set_format_rgb(module, layer, format); + nx_mlc_set_position(module, layer, sx, sy, ex, ey); + nx_mlc_set_rgblayer_stride(module, layer, pixel_byte, + plane->width * pixel_byte); + nx_mlc_set_rgblayer_address(module, layer, plane->fb_base); + + debug("%s: dp.%d.%d %d * %d, %dbpp, fmt:0x%x\n", + __func__, module, layer, plane->width, plane->height, + pixel_byte * 8, format); + debug("%s: b:0x%x, l:%d, t:%d, r:%d, b:%d, hs:%d, vs:%d\n", + __func__, plane->fb_base, sx, sy, ex, ey, + plane->width * pixel_byte, pixel_byte); + + return 0; +} + +int dp_plane_set_enable(int module, int layer, int on) +{ + int hl, hc; + int vl, vc; + + debug("%s: dp.%d.%d %s:%s\n", + __func__, module, layer, + layer == MLC_LAYER_VIDEO ? "Video" : "RGB", + on ? "ON" : "OFF"); + + if (layer != MLC_LAYER_VIDEO) { + nx_mlc_set_layer_enable(module, layer, on); + nx_mlc_set_dirty_flag(module, layer); + return 0; + } + + /* video layer */ + if (on) { + nx_mlc_set_video_layer_line_buffer_power_mode(module, 1); + nx_mlc_set_video_layer_line_buffer_sleep_mode(module, 0); + nx_mlc_set_layer_enable(module, layer, 1); + nx_mlc_set_dirty_flag(module, layer); + } else { + nx_mlc_set_layer_enable(module, layer, 0); + nx_mlc_set_dirty_flag(module, layer); + nx_mlc_get_video_layer_scale_filter(module, + &hl, &hc, &vl, &vc); + if (hl || hc || vl || vc) + nx_mlc_set_video_layer_scale_filter(module, 0, 0, 0, 0); + nx_mlc_set_video_layer_line_buffer_power_mode(module, 0); + nx_mlc_set_video_layer_line_buffer_sleep_mode(module, 1); + nx_mlc_set_dirty_flag(module, layer); + } + + return 0; +} + +void dp_plane_layer_enable(int module, + struct dp_plane_info *plane, int on) +{ + dp_plane_set_enable(module, plane->layer, on); +} + +int dp_plane_set_address(int module, int layer, unsigned int address) +{ + nx_mlc_set_rgblayer_address(module, layer, address); + nx_mlc_set_dirty_flag(module, layer); + + return 0; +} + +int dp_plane_wait_vsync(int module, int layer, int fps) +{ + int cnt = 0; + + if (fps == 0) + return (int)nx_mlc_get_dirty_flag(module, layer); + + while (fps > cnt++) { + while (nx_mlc_get_dirty_flag(module, layer)) + ; + nx_mlc_set_dirty_flag(module, layer); + } + return 0; +} diff --git a/drivers/video/nexell/s5pxx18_dp_hdmi.c b/drivers/video/nexell/s5pxx18_dp_hdmi.c new file mode 100644 index 0000000000..3f1fb8a575 --- /dev/null +++ b/drivers/video/nexell/s5pxx18_dp_hdmi.c @@ -0,0 +1,545 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2016 Nexell Co., Ltd. + * + * Author: junghyun, kim <jhkim@nexell.co.kr> + */ + +#include <config.h> +#include <common.h> +#include <errno.h> +#include <log.h> + +#include <asm/arch/nexell.h> +#include <asm/arch/tieoff.h> +#include <asm/arch/reset.h> +#include <asm/arch/display.h> + +#include <linux/delay.h> + +#include "soc/s5pxx18_soc_dpc.h" +#include "soc/s5pxx18_soc_hdmi.h" +#include "soc/s5pxx18_soc_disptop.h" +#include "soc/s5pxx18_soc_disptop_clk.h" + +#define __io_address(a) (void *)(uintptr_t)(a) + +static const u8 hdmiphy_preset74_25[32] = { + 0xd1, 0x1f, 0x10, 0x40, 0x40, 0xf8, 0xc8, 0x81, + 0xe8, 0xba, 0xd8, 0x45, 0xa0, 0xac, 0x80, 0x0a, + 0x80, 0x09, 0x84, 0x05, 0x22, 0x24, 0x86, 0x54, + 0xa5, 0x24, 0x01, 0x00, 0x00, 0x01, 0x10, 0x80, +}; + +static const u8 hdmiphy_preset148_5[32] = { + 0xd1, 0x1f, 0x00, 0x40, 0x40, 0xf8, 0xc8, 0x81, + 0xe8, 0xba, 0xd8, 0x45, 0xa0, 0xac, 0x80, 0x0a, + 0x80, 0x09, 0x84, 0x05, 0x22, 0x24, 0x86, 0x54, + 0x4b, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80, +}; + +#define HDMIPHY_PRESET_TABLE_SIZE (32) + +enum NXP_HDMI_PRESET { + NXP_HDMI_PRESET_720P = 0, /* 1280 x 720 */ + NXP_HDMI_PRESET_1080P, /* 1920 x 1080 */ + NXP_HDMI_PRESET_MAX +}; + +static void hdmi_reset(void) +{ + nx_rstcon_setrst(RESET_ID_HDMI_VIDEO, RSTCON_ASSERT); + nx_rstcon_setrst(RESET_ID_HDMI_SPDIF, RSTCON_ASSERT); + nx_rstcon_setrst(RESET_ID_HDMI_TMDS, RSTCON_ASSERT); + nx_rstcon_setrst(RESET_ID_HDMI_VIDEO, RSTCON_NEGATE); + nx_rstcon_setrst(RESET_ID_HDMI_SPDIF, RSTCON_NEGATE); + nx_rstcon_setrst(RESET_ID_HDMI_TMDS, RSTCON_NEGATE); +} + +static int hdmi_phy_enable(int preset, int enable) +{ + const u8 *table = NULL; + int size = 0; + u32 addr, i = 0; + + if (!enable) + return 0; + + switch (preset) { + case NXP_HDMI_PRESET_720P: + table = hdmiphy_preset74_25; + size = 32; + break; + case NXP_HDMI_PRESET_1080P: + table = hdmiphy_preset148_5; + size = 31; + break; + default: + printf("hdmi: phy not support preset %d\n", preset); + return -EINVAL; + } + + nx_hdmi_set_reg(0, HDMI_PHY_REG7C, (0 << 7)); + nx_hdmi_set_reg(0, HDMI_PHY_REG7C, (0 << 7)); + nx_hdmi_set_reg(0, HDMI_PHY_REG04, (0 << 4)); + nx_hdmi_set_reg(0, HDMI_PHY_REG04, (0 << 4)); + nx_hdmi_set_reg(0, HDMI_PHY_REG24, (1 << 7)); + nx_hdmi_set_reg(0, HDMI_PHY_REG24, (1 << 7)); + + for (i = 0, addr = HDMI_PHY_REG04; size > i; i++, addr += 4) { + nx_hdmi_set_reg(0, addr, table[i]); + nx_hdmi_set_reg(0, addr, table[i]); + } + + nx_hdmi_set_reg(0, HDMI_PHY_REG7C, 0x80); + nx_hdmi_set_reg(0, HDMI_PHY_REG7C, 0x80); + nx_hdmi_set_reg(0, HDMI_PHY_REG7C, (1 << 7)); + nx_hdmi_set_reg(0, HDMI_PHY_REG7C, (1 << 7)); + debug("%s: preset = %d\n", __func__, preset); + + return 0; +} + +static inline int hdmi_wait_phy_ready(void) +{ + int count = 500; + + do { + u32 val = nx_hdmi_get_reg(0, HDMI_LINK_PHY_STATUS_0); + + if (val & 0x01) { + printf("HDMI: phy ready...\n"); + return 1; + } + mdelay(10); + } while (count--); + + return 0; +} + +static inline int hdmi_get_vsync(int preset, + struct dp_sync_info *sync, + struct dp_ctrl_info *ctrl) +{ + switch (preset) { + case NXP_HDMI_PRESET_720P: /* 720p: 1280x720 */ + sync->h_active_len = 1280; + sync->h_sync_width = 40; + sync->h_back_porch = 220; + sync->h_front_porch = 110; + sync->h_sync_invert = 0; + sync->v_active_len = 720; + sync->v_sync_width = 5; + sync->v_back_porch = 20; + sync->v_front_porch = 5; + sync->v_sync_invert = 0; + break; + + case NXP_HDMI_PRESET_1080P: /* 1080p: 1920x1080 */ + sync->h_active_len = 1920; + sync->h_sync_width = 44; + sync->h_back_porch = 148; + sync->h_front_porch = 88; + sync->h_sync_invert = 0; + sync->v_active_len = 1080; + sync->v_sync_width = 5; + sync->v_back_porch = 36; + sync->v_front_porch = 4; + sync->v_sync_invert = 0; + break; + default: + printf("HDMI: not support preset sync %d\n", preset); + return -EINVAL; + } + + ctrl->clk_src_lv0 = 4; + ctrl->clk_div_lv0 = 1; + ctrl->clk_src_lv1 = 7; + ctrl->clk_div_lv1 = 1; + + ctrl->out_format = outputformat_rgb888; + ctrl->delay_mask = (DP_SYNC_DELAY_RGB_PVD | DP_SYNC_DELAY_HSYNC_CP1 | + DP_SYNC_DELAY_VSYNC_FRAM | DP_SYNC_DELAY_DE_CP); + ctrl->d_rgb_pvd = 0; + ctrl->d_hsync_cp1 = 0; + ctrl->d_vsync_fram = 0; + ctrl->d_de_cp2 = 7; + + /* HFP + HSW + HBP + AVWidth-VSCLRPIXEL- 1; */ + ctrl->vs_start_offset = (sync->h_front_porch + sync->h_sync_width + + sync->h_back_porch + sync->h_active_len - 1); + ctrl->vs_end_offset = 0; + + /* HFP + HSW + HBP + AVWidth-EVENVSCLRPIXEL- 1 */ + ctrl->ev_start_offset = (sync->h_front_porch + sync->h_sync_width + + sync->h_back_porch + sync->h_active_len - 1); + ctrl->ev_end_offset = 0; + debug("%s: preset: %d\n", __func__, preset); + + return 0; +} + +static void hdmi_clock(void) +{ + void *base = + __io_address(nx_disp_top_clkgen_get_physical_address + (to_mipi_clkgen)); + + nx_disp_top_clkgen_set_base_address(to_mipi_clkgen, base); + nx_disp_top_clkgen_set_clock_divisor_enable(to_mipi_clkgen, 0); + nx_disp_top_clkgen_set_clock_pclk_mode(to_mipi_clkgen, + nx_pclkmode_always); + nx_disp_top_clkgen_set_clock_source(to_mipi_clkgen, HDMI_SPDIF_CLKOUT, + 2); + nx_disp_top_clkgen_set_clock_divisor(to_mipi_clkgen, HDMI_SPDIF_CLKOUT, + 2); + nx_disp_top_clkgen_set_clock_source(to_mipi_clkgen, 1, 7); + nx_disp_top_clkgen_set_clock_divisor_enable(to_mipi_clkgen, 1); + + /* must initialize this !!! */ + nx_disp_top_hdmi_set_vsync_hsstart_end(0, 0); + nx_disp_top_hdmi_set_vsync_start(0); + nx_disp_top_hdmi_set_hactive_start(0); + nx_disp_top_hdmi_set_hactive_end(0); +} + +static void hdmi_vsync(struct dp_sync_info *sync) +{ + int width = sync->h_active_len; + int hsw = sync->h_sync_width; + int hbp = sync->h_back_porch; + int height = sync->v_active_len; + int vsw = sync->v_sync_width; + int vbp = sync->v_back_porch; + + int v_sync_s = vsw + vbp + height - 1; + int h_active_s = hsw + hbp; + int h_active_e = width + hsw + hbp; + int v_sync_hs_se0 = hsw + hbp + 1; + int v_sync_hs_se1 = hsw + hbp + 2; + + nx_disp_top_hdmi_set_vsync_start(v_sync_s); + nx_disp_top_hdmi_set_hactive_start(h_active_s); + nx_disp_top_hdmi_set_hactive_end(h_active_e); + nx_disp_top_hdmi_set_vsync_hsstart_end(v_sync_hs_se0, v_sync_hs_se1); +} + +static int hdmi_prepare(struct dp_sync_info *sync) +{ + int width = sync->h_active_len; + int hsw = sync->h_sync_width; + int hfp = sync->h_front_porch; + int hbp = sync->h_back_porch; + int height = sync->v_active_len; + int vsw = sync->v_sync_width; + int vfp = sync->v_front_porch; + int vbp = sync->v_back_porch; + + u32 h_blank, h_line, h_sync_start, h_sync_end; + u32 v_blank, v2_blank, v_line; + u32 v_sync_line_bef_1, v_sync_line_bef_2; + + u32 fixed_ffff = 0xffff; + + /* calculate sync variables */ + h_blank = hfp + hsw + hbp; + v_blank = vfp + vsw + vbp; + v2_blank = height + vfp + vsw + vbp; + v_line = height + vfp + vsw + vbp; /* total v */ + h_line = width + hfp + hsw + hbp; /* total h */ + h_sync_start = hfp; + h_sync_end = hfp + hsw; + v_sync_line_bef_1 = vfp; + v_sync_line_bef_2 = vfp + vsw; + + /* no blue screen mode, encoding order as it is */ + nx_hdmi_set_reg(0, HDMI_LINK_HDMI_CON_0, (0 << 5) | (1 << 4)); + + /* set HDMI_LINK_BLUE_SCREEN_* to 0x0 */ + nx_hdmi_set_reg(0, HDMI_LINK_BLUE_SCREEN_R_0, 0x5555); + nx_hdmi_set_reg(0, HDMI_LINK_BLUE_SCREEN_R_1, 0x5555); + nx_hdmi_set_reg(0, HDMI_LINK_BLUE_SCREEN_G_0, 0x5555); + nx_hdmi_set_reg(0, HDMI_LINK_BLUE_SCREEN_G_1, 0x5555); + nx_hdmi_set_reg(0, HDMI_LINK_BLUE_SCREEN_B_0, 0x5555); + nx_hdmi_set_reg(0, HDMI_LINK_BLUE_SCREEN_B_1, 0x5555); + + /* set HDMI_CON_1 to 0x0 */ + nx_hdmi_set_reg(0, HDMI_LINK_HDMI_CON_1, 0x0); + nx_hdmi_set_reg(0, HDMI_LINK_HDMI_CON_2, 0x0); + + /* set interrupt : enable hpd_plug, hpd_unplug */ + nx_hdmi_set_reg(0, HDMI_LINK_INTC_CON_0, + (1 << 6) | (1 << 3) | (1 << 2)); + + /* set STATUS_EN to 0x17 */ + nx_hdmi_set_reg(0, HDMI_LINK_STATUS_EN, 0x17); + + /* TODO set HDP to 0x0 : later check hpd */ + nx_hdmi_set_reg(0, HDMI_LINK_HPD, 0x0); + + /* set MODE_SEL to 0x02 */ + nx_hdmi_set_reg(0, HDMI_LINK_MODE_SEL, 0x2); + + /* set H_BLANK_*, V1_BLANK_*, V2_BLANK_*, V_LINE_*, + * H_LINE_*, H_SYNC_START_*, H_SYNC_END_ * + * V_SYNC_LINE_BEF_1_*, V_SYNC_LINE_BEF_2_* + */ + nx_hdmi_set_reg(0, HDMI_LINK_H_BLANK_0, h_blank % 256); + nx_hdmi_set_reg(0, HDMI_LINK_H_BLANK_1, h_blank >> 8); + nx_hdmi_set_reg(0, HDMI_LINK_V1_BLANK_0, v_blank % 256); + nx_hdmi_set_reg(0, HDMI_LINK_V1_BLANK_1, v_blank >> 8); + nx_hdmi_set_reg(0, HDMI_LINK_V2_BLANK_0, v2_blank % 256); + nx_hdmi_set_reg(0, HDMI_LINK_V2_BLANK_1, v2_blank >> 8); + nx_hdmi_set_reg(0, HDMI_LINK_V_LINE_0, v_line % 256); + nx_hdmi_set_reg(0, HDMI_LINK_V_LINE_1, v_line >> 8); + nx_hdmi_set_reg(0, HDMI_LINK_H_LINE_0, h_line % 256); + nx_hdmi_set_reg(0, HDMI_LINK_H_LINE_1, h_line >> 8); + + if (width == 1280) { + nx_hdmi_set_reg(0, HDMI_LINK_HSYNC_POL, 0x1); + nx_hdmi_set_reg(0, HDMI_LINK_VSYNC_POL, 0x1); + } else { + nx_hdmi_set_reg(0, HDMI_LINK_HSYNC_POL, 0x0); + nx_hdmi_set_reg(0, HDMI_LINK_VSYNC_POL, 0x0); + } + + nx_hdmi_set_reg(0, HDMI_LINK_INT_PRO_MODE, 0x0); + + nx_hdmi_set_reg(0, HDMI_LINK_H_SYNC_START_0, (h_sync_start % 256) - 2); + nx_hdmi_set_reg(0, HDMI_LINK_H_SYNC_START_1, h_sync_start >> 8); + nx_hdmi_set_reg(0, HDMI_LINK_H_SYNC_END_0, (h_sync_end % 256) - 2); + nx_hdmi_set_reg(0, HDMI_LINK_H_SYNC_END_1, h_sync_end >> 8); + nx_hdmi_set_reg(0, HDMI_LINK_V_SYNC_LINE_BEF_1_0, + v_sync_line_bef_1 % 256); + nx_hdmi_set_reg(0, HDMI_LINK_V_SYNC_LINE_BEF_1_1, + v_sync_line_bef_1 >> 8); + nx_hdmi_set_reg(0, HDMI_LINK_V_SYNC_LINE_BEF_2_0, + v_sync_line_bef_2 % 256); + nx_hdmi_set_reg(0, HDMI_LINK_V_SYNC_LINE_BEF_2_1, + v_sync_line_bef_2 >> 8); + + /* Set V_SYNC_LINE_AFT*, V_SYNC_LINE_AFT_PXL*, VACT_SPACE* */ + nx_hdmi_set_reg(0, HDMI_LINK_V_SYNC_LINE_AFT_1_0, fixed_ffff % 256); + nx_hdmi_set_reg(0, HDMI_LINK_V_SYNC_LINE_AFT_1_1, fixed_ffff >> 8); + nx_hdmi_set_reg(0, HDMI_LINK_V_SYNC_LINE_AFT_2_0, fixed_ffff % 256); + nx_hdmi_set_reg(0, HDMI_LINK_V_SYNC_LINE_AFT_2_1, fixed_ffff >> 8); + nx_hdmi_set_reg(0, HDMI_LINK_V_SYNC_LINE_AFT_3_0, fixed_ffff % 256); + nx_hdmi_set_reg(0, HDMI_LINK_V_SYNC_LINE_AFT_3_1, fixed_ffff >> 8); + nx_hdmi_set_reg(0, HDMI_LINK_V_SYNC_LINE_AFT_4_0, fixed_ffff % 256); + nx_hdmi_set_reg(0, HDMI_LINK_V_SYNC_LINE_AFT_4_1, fixed_ffff >> 8); + nx_hdmi_set_reg(0, HDMI_LINK_V_SYNC_LINE_AFT_5_0, fixed_ffff % 256); + nx_hdmi_set_reg(0, HDMI_LINK_V_SYNC_LINE_AFT_5_1, fixed_ffff >> 8); + nx_hdmi_set_reg(0, HDMI_LINK_V_SYNC_LINE_AFT_6_0, fixed_ffff % 256); + nx_hdmi_set_reg(0, HDMI_LINK_V_SYNC_LINE_AFT_6_1, fixed_ffff >> 8); + + nx_hdmi_set_reg(0, HDMI_LINK_V_SYNC_LINE_AFT_PXL_1_0, fixed_ffff % 256); + nx_hdmi_set_reg(0, HDMI_LINK_V_SYNC_LINE_AFT_PXL_1_1, fixed_ffff >> 8); + nx_hdmi_set_reg(0, HDMI_LINK_V_SYNC_LINE_AFT_PXL_2_0, fixed_ffff % 256); + nx_hdmi_set_reg(0, HDMI_LINK_V_SYNC_LINE_AFT_PXL_2_1, fixed_ffff >> 8); + nx_hdmi_set_reg(0, HDMI_LINK_V_SYNC_LINE_AFT_PXL_3_0, fixed_ffff % 256); + nx_hdmi_set_reg(0, HDMI_LINK_V_SYNC_LINE_AFT_PXL_3_1, fixed_ffff >> 8); + nx_hdmi_set_reg(0, HDMI_LINK_V_SYNC_LINE_AFT_PXL_4_0, fixed_ffff % 256); + nx_hdmi_set_reg(0, HDMI_LINK_V_SYNC_LINE_AFT_PXL_4_1, fixed_ffff >> 8); + nx_hdmi_set_reg(0, HDMI_LINK_V_SYNC_LINE_AFT_PXL_5_0, fixed_ffff % 256); + nx_hdmi_set_reg(0, HDMI_LINK_V_SYNC_LINE_AFT_PXL_5_1, fixed_ffff >> 8); + nx_hdmi_set_reg(0, HDMI_LINK_V_SYNC_LINE_AFT_PXL_6_0, fixed_ffff % 256); + nx_hdmi_set_reg(0, HDMI_LINK_V_SYNC_LINE_AFT_PXL_6_1, fixed_ffff >> 8); + + nx_hdmi_set_reg(0, HDMI_LINK_VACT_SPACE1_0, fixed_ffff % 256); + nx_hdmi_set_reg(0, HDMI_LINK_VACT_SPACE1_1, fixed_ffff >> 8); + nx_hdmi_set_reg(0, HDMI_LINK_VACT_SPACE2_0, fixed_ffff % 256); + nx_hdmi_set_reg(0, HDMI_LINK_VACT_SPACE2_1, fixed_ffff >> 8); + nx_hdmi_set_reg(0, HDMI_LINK_VACT_SPACE3_0, fixed_ffff % 256); + nx_hdmi_set_reg(0, HDMI_LINK_VACT_SPACE3_1, fixed_ffff >> 8); + nx_hdmi_set_reg(0, HDMI_LINK_VACT_SPACE4_0, fixed_ffff % 256); + nx_hdmi_set_reg(0, HDMI_LINK_VACT_SPACE4_1, fixed_ffff >> 8); + nx_hdmi_set_reg(0, HDMI_LINK_VACT_SPACE5_0, fixed_ffff % 256); + nx_hdmi_set_reg(0, HDMI_LINK_VACT_SPACE5_1, fixed_ffff >> 8); + nx_hdmi_set_reg(0, HDMI_LINK_VACT_SPACE6_0, fixed_ffff % 256); + nx_hdmi_set_reg(0, HDMI_LINK_VACT_SPACE6_1, fixed_ffff >> 8); + + nx_hdmi_set_reg(0, HDMI_LINK_CSC_MUX, 0x0); + nx_hdmi_set_reg(0, HDMI_LINK_SYNC_GEN_MUX, 0x0); + + nx_hdmi_set_reg(0, HDMI_LINK_SEND_START_0, 0xfd); + nx_hdmi_set_reg(0, HDMI_LINK_SEND_START_1, 0x01); + nx_hdmi_set_reg(0, HDMI_LINK_SEND_END_0, 0x0d); + nx_hdmi_set_reg(0, HDMI_LINK_SEND_END_1, 0x3a); + nx_hdmi_set_reg(0, HDMI_LINK_SEND_END_2, 0x08); + + /* Set DC_CONTROL to 0x00 */ + nx_hdmi_set_reg(0, HDMI_LINK_DC_CONTROL, 0x0); + + if (IS_ENABLED(CONFIG_HDMI_PATTERN)) + nx_hdmi_set_reg(0, HDMI_LINK_VIDEO_PATTERN_GEN, 0x1); + else + nx_hdmi_set_reg(0, HDMI_LINK_VIDEO_PATTERN_GEN, 0x0); + + nx_hdmi_set_reg(0, HDMI_LINK_GCP_CON, 0x0a); + return 0; +} + +static void hdmi_init(void) +{ + void *base; + /** + * [SEQ 2] set the HDMI CLKGEN's PCLKMODE to always enabled + */ + base = + __io_address(nx_disp_top_clkgen_get_physical_address(hdmi_clkgen)); + nx_disp_top_clkgen_set_base_address(hdmi_clkgen, base); + nx_disp_top_clkgen_set_clock_pclk_mode(hdmi_clkgen, nx_pclkmode_always); + + base = __io_address(nx_hdmi_get_physical_address(0)); + nx_hdmi_set_base_address(0, base); + + /** + * [SEQ 3] set the 0xC001100C[0] to 1 + */ + nx_tieoff_set(NX_TIEOFF_DISPLAYTOP0_i_HDMI_PHY_REFCLK_SEL, 1); + + /** + * [SEQ 4] release the resets of HDMI.i_PHY_nRST and HDMI.i_nRST + */ + nx_rstcon_setrst(RESET_ID_HDMI_PHY, RSTCON_ASSERT); + nx_rstcon_setrst(RESET_ID_HDMI, RSTCON_ASSERT); + nx_rstcon_setrst(RESET_ID_HDMI_PHY, RSTCON_NEGATE); + nx_rstcon_setrst(RESET_ID_HDMI, RSTCON_NEGATE); +} + +void hdmi_enable(int input, int preset, struct dp_sync_info *sync, int enable) +{ + if (enable) { + nx_hdmi_set_reg(0, HDMI_LINK_HDMI_CON_0, + (nx_hdmi_get_reg(0, HDMI_LINK_HDMI_CON_0) | + 0x1)); + hdmi_vsync(sync); + } else { + hdmi_phy_enable(preset, 0); + } +} + +static int hdmi_setup(int input, int preset, + struct dp_sync_info *sync, struct dp_ctrl_info *ctrl) +{ + u32 HDMI_SEL = 0; + int ret; + + switch (input) { + case DP_DEVICE_DP0: + HDMI_SEL = primary_mlc; + break; + case DP_DEVICE_DP1: + HDMI_SEL = secondary_mlc; + break; + case DP_DEVICE_RESCONV: + HDMI_SEL = resolution_conv; + break; + default: + printf("HDMI: not support source device %d\n", input); + return -EINVAL; + } + + /** + * [SEQ 5] set up the HDMI PHY to specific video clock. + */ + ret = hdmi_phy_enable(preset, 1); + if (ret < 0) + return ret; + + /** + * [SEQ 6] I2S (or SPDIFTX) configuration for the source audio data + * this is done in another user app - ex> Android Audio HAL + */ + + /** + * [SEQ 7] Wait for ECID ready + */ + + /** + * [SEQ 8] release the resets of HDMI.i_VIDEO_nRST and HDMI.i_SPDIF_nRST + * and HDMI.i_TMDS_nRST + */ + hdmi_reset(); + + /** + * [SEQ 9] Wait for HDMI PHY ready (wait until 0xC0200020.[0], 1) + */ + if (hdmi_wait_phy_ready() == 0) { + printf("%s: failed to wait for hdmiphy ready\n", __func__); + hdmi_phy_enable(preset, 0); + return -EIO; + } + /* set mux */ + nx_disp_top_set_hdmimux(1, HDMI_SEL); + + /** + * [SEC 10] Set the DPC CLKGEN's Source Clock to HDMI_CLK & + * Set Sync Parameter + */ + hdmi_clock(); + /* set hdmi link clk to clkgen vs default is hdmi phy clk */ + + /** + * [SEQ 11] Set up the HDMI Converter parameters + */ + hdmi_get_vsync(preset, sync, ctrl); + hdmi_prepare(sync); + + return 0; +} + +void nx_hdmi_display(int module, + struct dp_sync_info *sync, struct dp_ctrl_info *ctrl, + struct dp_plane_top *top, struct dp_plane_info *planes, + struct dp_hdmi_dev *dev) +{ + struct dp_plane_info *plane = planes; + int input = module == 0 ? DP_DEVICE_DP0 : DP_DEVICE_DP1; + int count = top->plane_num; + int preset = dev->preset; + int i = 0; + + debug("HDMI: display.%d\n", module); + + switch (preset) { + case 0: + top->screen_width = 1280; + top->screen_height = 720; + sync->h_active_len = 1280; + sync->v_active_len = 720; + break; + case 1: + top->screen_width = 1920; + top->screen_height = 1080; + sync->h_active_len = 1920; + sync->v_active_len = 1080; + break; + default: + printf("hdmi not support preset %d\n", preset); + return; + } + + printf("HDMI: display.%d, preset %d (%4d * %4d)\n", + module, preset, top->screen_width, top->screen_height); + + dp_control_init(module); + dp_plane_init(module); + + hdmi_init(); + hdmi_setup(input, preset, sync, ctrl); + + dp_plane_screen_setup(module, top); + for (i = 0; count > i; i++, plane++) { + if (!plane->enable) + continue; + dp_plane_layer_setup(module, plane); + dp_plane_layer_enable(module, plane, 1); + } + dp_plane_screen_enable(module, 1); + + dp_control_setup(module, sync, ctrl); + dp_control_enable(module, 1); + + hdmi_enable(input, preset, sync, 1); +} diff --git a/drivers/video/nexell/s5pxx18_dp_lvds.c b/drivers/video/nexell/s5pxx18_dp_lvds.c new file mode 100644 index 0000000000..f8ea63fdf1 --- /dev/null +++ b/drivers/video/nexell/s5pxx18_dp_lvds.c @@ -0,0 +1,274 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2016 Nexell Co., Ltd. + * + * Author: junghyun, kim <jhkim@nexell.co.kr> + */ + +#include <config.h> +#include <common.h> +#include <errno.h> + +#include <asm/arch/nexell.h> +#include <asm/arch/reset.h> +#include <asm/arch/display.h> + +#include "soc/s5pxx18_soc_lvds.h" +#include "soc/s5pxx18_soc_disptop.h" +#include "soc/s5pxx18_soc_disptop_clk.h" + +#define __io_address(a) (void *)(uintptr_t)(a) + +static void lvds_phy_reset(void) +{ + nx_rstcon_setrst(RESET_ID_LVDS, RSTCON_ASSERT); + nx_rstcon_setrst(RESET_ID_LVDS, RSTCON_NEGATE); +} + +static void lvds_init(void) +{ + int clkid = DP_CLOCK_LVDS; + int index = 0; + void *base; + + base = __io_address(nx_disp_top_clkgen_get_physical_address(clkid)); + nx_disp_top_clkgen_set_base_address(clkid, base); + + nx_lvds_initialize(); + + for (index = 0; nx_lvds_get_number_of_module() > index; index++) + nx_lvds_set_base_address(index, + (void *)__io_address(nx_lvds_get_physical_address(index))); + + nx_disp_top_clkgen_set_clock_pclk_mode(clkid, nx_pclkmode_always); +} + +static void lvds_enable(int enable) +{ + int clkid = DP_CLOCK_LVDS; + int on = (enable ? 1 : 0); + + nx_disp_top_clkgen_set_clock_divisor_enable(clkid, on); +} + +static int lvds_setup(int module, int input, + struct dp_sync_info *sync, struct dp_ctrl_info *ctrl, + struct dp_lvds_dev *dev) +{ + unsigned int val; + int clkid = DP_CLOCK_LVDS; + enum dp_lvds_format format = DP_LVDS_FORMAT_JEIDA; + u32 voltage = DEF_VOLTAGE_LEVEL; + + if (dev) { + format = dev->lvds_format; + voltage = dev->voltage_level; + } + + printf("LVDS: "); + printf("%s, ", format == DP_LVDS_FORMAT_VESA ? "VESA" : + format == DP_LVDS_FORMAT_JEIDA ? "JEIDA" : "LOC"); + printf("voltage LV:0x%x\n", voltage); + + /* + *-------- predefined type. + * only change iTA to iTE in VESA mode + * wire [34:0] loc_VideoIn = + * {4'hf, 4'h0, i_VDEN, i_VSYNC, i_HSYNC, i_VD[23:0] }; + */ + u32 VSYNC = 25; + u32 HSYNC = 24; + u32 VDEN = 26; /* bit position */ + u32 ONE = 34; + u32 ZERO = 27; + + /*==================================================== + * current not use location mode + *==================================================== + */ + u32 LOC_A[7] = {ONE, ONE, ONE, ONE, ONE, ONE, ONE}; + u32 LOC_B[7] = {ONE, ONE, ONE, ONE, ONE, ONE, ONE}; + u32 LOC_C[7] = {VDEN, VSYNC, HSYNC, ONE, HSYNC, VSYNC, VDEN}; + u32 LOC_D[7] = {ZERO, ZERO, ZERO, ZERO, ZERO, ZERO, ZERO}; + u32 LOC_E[7] = {ZERO, ZERO, ZERO, ZERO, ZERO, ZERO, ZERO}; + + switch (input) { + case DP_DEVICE_DP0: + input = 0; + break; + case DP_DEVICE_DP1: + input = 1; + break; + case DP_DEVICE_RESCONV: + input = 2; + break; + default: + return -EINVAL; + } + + /* + * select TOP MUX + */ + nx_disp_top_clkgen_set_clock_divisor_enable(clkid, 0); + nx_disp_top_clkgen_set_clock_source(clkid, 0, ctrl->clk_src_lv0); + nx_disp_top_clkgen_set_clock_divisor(clkid, 0, ctrl->clk_div_lv0); + nx_disp_top_clkgen_set_clock_source(clkid, 1, ctrl->clk_src_lv1); + nx_disp_top_clkgen_set_clock_divisor(clkid, 1, ctrl->clk_div_lv1); + + /* + * LVDS Control Pin Setting + */ + val = (0 << 30) | /* CPU_I_VBLK_FLAG_SEL */ + (0 << 29) | /* CPU_I_BVLK_FLAG */ + (1 << 28) | /* SKINI_BST */ + (1 << 27) | /* DLYS_BST */ + (0 << 26) | /* I_AUTO_SEL */ + (format << 19) | /* JEiDA data packing */ + (0x1B << 13) | /* I_LOCK_PPM_SET, PPM setting for PLL lock */ + (0x638 << 1); /* I_DESKEW_CNT_SEL, period of de-skew region */ + nx_lvds_set_lvdsctrl0(0, val); + + val = (0 << 28) | /* I_ATE_MODE, function mode */ + (0 << 27) | /* I_TEST_CON_MODE, DA (test ctrl mode) */ + (0 << 24) | /* I_TX4010X_DUMMY */ + (0 << 15) | /* SKCCK 0 */ + (0 << 12) | /* SKC4 (TX output skew control pin at ODD ch4) */ + (0 << 9) | /* SKC3 (TX output skew control pin at ODD ch3) */ + (0 << 6) | /* SKC2 (TX output skew control pin at ODD ch2) */ + (0 << 3) | /* SKC1 (TX output skew control pin at ODD ch1) */ + (0 << 0); /* SKC0 (TX output skew control pin at ODD ch0) */ + nx_lvds_set_lvdsctrl1(0, val); + + val = (0 << 15) | /* CK_POL_SEL, Input clock, bypass */ + (0 << 14) | /* VSEL, VCO Freq. range. 0: Low(40MHz~90MHz), + * 1: High(90MHz~160MHz) */ + (0x1 << 12) | /* S (Post-scaler) */ + (0xA << 6) | /* M (Main divider) */ + (0xA << 0); /* P (Pre-divider) */ + + nx_lvds_set_lvdsctrl2(0, val); + val = (0x03 << 6) | /* SK_BIAS, Bias current ctrl pin */ + (0 << 5) | /* SKEWINI, skew selection pin, 0: bypass, + * 1: skew enable */ + (0 << 4) | /* SKEW_EN_H, skew block power down, 0: power down, + * 1: operating */ + (1 << 3) | /* CNTB_TDLY, delay control pin */ + (0 << 2) | /* SEL_DATABF, input clock 1/2 division cont. pin */ + (0x3 << 0); /* SKEW_REG_CUR, regulator bias current selection + * in SKEW block */ + + nx_lvds_set_lvdsctrl3(0, val); + val = (0 << 28) | /* FLT_CNT, filter control pin for PLL */ + (0 << 27) | /* VOD_ONLY_CNT, the pre-emphasis's pre-diriver + * control pin (VOD only) */ + (0 << 26) | /* CNNCT_MODE_SEL, connectivity mode selection, + * 0:TX operating, 1:con check */ + (0 << 24) | /* CNNCT_CNT, connectivity ctrl pin, + * 0: tx operating, 1: con check */ + (0 << 23) | /* VOD_HIGH_S, VOD control pin, 1: Vod only */ + (0 << 22) | /* SRC_TRH, source termination resistor sel. pin */ + (voltage << 14) | + (0x01 << 6) | /* CNT_PEN_H, TX driver pre-emphasis level cont. */ + (0x4 << 3) | /* FC_CODE, vos control pin */ + (0 << 2) | /* OUTCON, TX Driver state selectioin pin, 0:Hi-z, + * 1:Low */ + (0 << 1) | /* LOCK_CNT, Lock signal selection pin, enable */ + (0 << 0); /* AUTO_DSK_SEL, auto deskew sel. pin, normal */ + nx_lvds_set_lvdsctrl4(0, val); + + val = (0 << 24) | /* I_BIST_RESETB */ + (0 << 23) | /* I_BIST_EN */ + (0 << 21) | /* I_BIST_PAT_SEL */ + (0 << 14) | /* I_BIST_USER_PATTERN */ + (0 << 13) | /* I_BIST_FORCE_ERROR */ + (0 << 7) | /* I_BIST_SKEW_CTRL */ + (0 << 5) | /* I_BIST_CLK_INV */ + (0 << 3) | /* I_BIST_DATA_INV */ + (0 << 0); /* I_BIST_CH_SEL */ + nx_lvds_set_lvdstmode0(0, val); + + /* user do not need to modify this codes. */ + val = (LOC_A[4] << 24) | (LOC_A[3] << 18) | (LOC_A[2] << 12) | + (LOC_A[1] << 6) | (LOC_A[0] << 0); + nx_lvds_set_lvdsloc0(0, val); + + val = (LOC_B[2] << 24) | (LOC_B[1] << 18) | (LOC_B[0] << 12) | + (LOC_A[6] << 6) | (LOC_A[5] << 0); + nx_lvds_set_lvdsloc1(0, val); + + val = (LOC_C[0] << 24) | (LOC_B[6] << 18) | (LOC_B[5] << 12) | + (LOC_B[4] << 6) | (LOC_B[3] << 0); + nx_lvds_set_lvdsloc2(0, val); + + val = (LOC_C[5] << 24) | (LOC_C[4] << 18) | (LOC_C[3] << 12) | + (LOC_C[2] << 6) | (LOC_C[1] << 0); + nx_lvds_set_lvdsloc3(0, val); + + val = (LOC_D[3] << 24) | (LOC_D[2] << 18) | (LOC_D[1] << 12) | + (LOC_D[0] << 6) | (LOC_C[6] << 0); + nx_lvds_set_lvdsloc4(0, val); + + val = (LOC_E[1] << 24) | (LOC_E[0] << 18) | (LOC_D[6] << 12) | + (LOC_D[5] << 6) | (LOC_D[4] << 0); + nx_lvds_set_lvdsloc5(0, val); + + val = (LOC_E[6] << 24) | (LOC_E[5] << 18) | (LOC_E[4] << 12) | + (LOC_E[3] << 6) | (LOC_E[2] << 0); + nx_lvds_set_lvdsloc6(0, val); + + nx_lvds_set_lvdslocmask0(0, 0xffffffff); + nx_lvds_set_lvdslocmask1(0, 0xffffffff); + + nx_lvds_set_lvdslocpol0(0, (0 << 19) | (0 << 18)); + + /* + * select TOP MUX + */ + nx_disp_top_set_lvdsmux(1, input); + + /* + * LVDS PHY Reset, make sure last. + */ + lvds_phy_reset(); + + return 0; +} + +void nx_lvds_display(int module, + struct dp_sync_info *sync, struct dp_ctrl_info *ctrl, + struct dp_plane_top *top, struct dp_plane_info *planes, + struct dp_lvds_dev *dev) +{ + struct dp_plane_info *plane = planes; + int input = module == 0 ? DP_DEVICE_DP0 : DP_DEVICE_DP1; + int count = top->plane_num; + int i = 0; + + printf("LVDS: dp.%d\n", module); + + dp_control_init(module); + dp_plane_init(module); + + lvds_init(); + + /* set plane */ + dp_plane_screen_setup(module, top); + + for (i = 0; count > i; i++, plane++) { + if (!plane->enable) + continue; + dp_plane_layer_setup(module, plane); + dp_plane_layer_enable(module, plane, 1); + } + + dp_plane_screen_enable(module, 1); + + /* set lvds */ + lvds_setup(module, input, sync, ctrl, dev); + + lvds_enable(1); + + /* set dp control */ + dp_control_setup(module, sync, ctrl); + dp_control_enable(module, 1); +} diff --git a/drivers/video/nexell/s5pxx18_dp_mipi.c b/drivers/video/nexell/s5pxx18_dp_mipi.c new file mode 100644 index 0000000000..670272b268 --- /dev/null +++ b/drivers/video/nexell/s5pxx18_dp_mipi.c @@ -0,0 +1,677 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2016 Nexell Co., Ltd. + * + * Author: junghyun, kim <jhkim@nexell.co.kr> + */ + +#include <config.h> +#include <common.h> +#include <errno.h> + +#include <asm/arch/nexell.h> +#include <asm/arch/tieoff.h> +#include <asm/arch/reset.h> +#include <asm/arch/display.h> + +#include "soc/s5pxx18_soc_mipi.h" +#include "soc/s5pxx18_soc_disptop.h" +#include "soc/s5pxx18_soc_disptop_clk.h" + +#define PLLPMS_1000MHZ 0x33E8 +#define BANDCTL_1000MHZ 0xF +#define PLLPMS_960MHZ 0x2280 +#define BANDCTL_960MHZ 0xF +#define PLLPMS_900MHZ 0x2258 +#define BANDCTL_900MHZ 0xE +#define PLLPMS_840MHZ 0x2230 +#define BANDCTL_840MHZ 0xD +#define PLLPMS_750MHZ 0x43E8 +#define BANDCTL_750MHZ 0xC +#define PLLPMS_660MHZ 0x21B8 +#define BANDCTL_660MHZ 0xB +#define PLLPMS_600MHZ 0x2190 +#define BANDCTL_600MHZ 0xA +#define PLLPMS_540MHZ 0x2168 +#define BANDCTL_540MHZ 0x9 +#define PLLPMS_512MHZ 0x03200 +#define BANDCTL_512MHZ 0x9 +#define PLLPMS_480MHZ 0x2281 +#define BANDCTL_480MHZ 0x8 +#define PLLPMS_420MHZ 0x2231 +#define BANDCTL_420MHZ 0x7 +#define PLLPMS_402MHZ 0x2219 +#define BANDCTL_402MHZ 0x7 +#define PLLPMS_330MHZ 0x21B9 +#define BANDCTL_330MHZ 0x6 +#define PLLPMS_300MHZ 0x2191 +#define BANDCTL_300MHZ 0x5 +#define PLLPMS_210MHZ 0x2232 +#define BANDCTL_210MHZ 0x4 +#define PLLPMS_180MHZ 0x21E2 +#define BANDCTL_180MHZ 0x3 +#define PLLPMS_150MHZ 0x2192 +#define BANDCTL_150MHZ 0x2 +#define PLLPMS_100MHZ 0x3323 +#define BANDCTL_100MHZ 0x1 +#define PLLPMS_80MHZ 0x3283 +#define BANDCTL_80MHZ 0x0 + +#define MIPI_INDEX 0 +#define MIPI_EXC_PRE_VALUE 1 +#define MIPI_DSI_IRQ_MASK 29 + +#define __io_address(a) (void *)(uintptr_t)(a) + +struct mipi_xfer_msg { + u8 id, data[2]; + u16 flags; + const u8 *tx_buf; + u16 tx_len; + u8 *rx_buf; + u16 rx_len; +}; + +static void mipi_reset(void) +{ + /* tieoff */ + nx_tieoff_set(NX_TIEOFF_MIPI0_NX_DPSRAM_1R1W_EMAA, 3); + nx_tieoff_set(NX_TIEOFF_MIPI0_NX_DPSRAM_1R1W_EMAB, 3); + + /* reset */ + nx_rstcon_setrst(RESET_ID_MIPI, RSTCON_ASSERT); + nx_rstcon_setrst(RESET_ID_MIPI_DSI, RSTCON_ASSERT); + nx_rstcon_setrst(RESET_ID_MIPI_CSI, RSTCON_ASSERT); + nx_rstcon_setrst(RESET_ID_MIPI_PHY_S, RSTCON_ASSERT); + nx_rstcon_setrst(RESET_ID_MIPI_PHY_M, RSTCON_ASSERT); + + nx_rstcon_setrst(RESET_ID_MIPI, RSTCON_NEGATE); + nx_rstcon_setrst(RESET_ID_MIPI_DSI, RSTCON_NEGATE); + nx_rstcon_setrst(RESET_ID_MIPI_PHY_S, RSTCON_NEGATE); + nx_rstcon_setrst(RESET_ID_MIPI_PHY_M, RSTCON_NEGATE); +} + +static void mipi_init(void) +{ + int clkid = DP_CLOCK_MIPI; + void *base; + + /* + * neet to reset before open + */ + mipi_reset(); + + base = __io_address(nx_disp_top_clkgen_get_physical_address(clkid)); + nx_disp_top_clkgen_set_base_address(clkid, base); + nx_disp_top_clkgen_set_clock_pclk_mode(clkid, nx_pclkmode_always); + + base = __io_address(nx_mipi_get_physical_address(0)); + nx_mipi_set_base_address(0, base); +} + +static int mipi_get_phy_pll(int bitrate, unsigned int *pllpms, + unsigned int *bandctl) +{ + unsigned int pms, ctl; + + switch (bitrate) { + case 1000: + pms = PLLPMS_1000MHZ; + ctl = BANDCTL_1000MHZ; + break; + case 960: + pms = PLLPMS_960MHZ; + ctl = BANDCTL_960MHZ; + break; + case 900: + pms = PLLPMS_900MHZ; + ctl = BANDCTL_900MHZ; + break; + case 840: + pms = PLLPMS_840MHZ; + ctl = BANDCTL_840MHZ; + break; + case 750: + pms = PLLPMS_750MHZ; + ctl = BANDCTL_750MHZ; + break; + case 660: + pms = PLLPMS_660MHZ; + ctl = BANDCTL_660MHZ; + break; + case 600: + pms = PLLPMS_600MHZ; + ctl = BANDCTL_600MHZ; + break; + case 540: + pms = PLLPMS_540MHZ; + ctl = BANDCTL_540MHZ; + break; + case 512: + pms = PLLPMS_512MHZ; + ctl = BANDCTL_512MHZ; + break; + case 480: + pms = PLLPMS_480MHZ; + ctl = BANDCTL_480MHZ; + break; + case 420: + pms = PLLPMS_420MHZ; + ctl = BANDCTL_420MHZ; + break; + case 402: + pms = PLLPMS_402MHZ; + ctl = BANDCTL_402MHZ; + break; + case 330: + pms = PLLPMS_330MHZ; + ctl = BANDCTL_330MHZ; + break; + case 300: + pms = PLLPMS_300MHZ; + ctl = BANDCTL_300MHZ; + break; + case 210: + pms = PLLPMS_210MHZ; + ctl = BANDCTL_210MHZ; + break; + case 180: + pms = PLLPMS_180MHZ; + ctl = BANDCTL_180MHZ; + break; + case 150: + pms = PLLPMS_150MHZ; + ctl = BANDCTL_150MHZ; + break; + case 100: + pms = PLLPMS_100MHZ; + ctl = BANDCTL_100MHZ; + break; + case 80: + pms = PLLPMS_80MHZ; + ctl = BANDCTL_80MHZ; + break; + default: + return -EINVAL; + } + + *pllpms = pms; + *bandctl = ctl; + + return 0; +} + +static int mipi_prepare(int module, int input, + struct dp_sync_info *sync, struct dp_ctrl_info *ctrl, + struct dp_mipi_dev *mipi) +{ + int index = MIPI_INDEX; + u32 esc_pre_value = MIPI_EXC_PRE_VALUE; + int lpm = mipi->lpm_trans; + int ret = 0; + + ret = mipi_get_phy_pll(mipi->hs_bitrate, + &mipi->hs_pllpms, &mipi->hs_bandctl); + if (ret < 0) + return ret; + + ret = mipi_get_phy_pll(mipi->lp_bitrate, + &mipi->lp_pllpms, &mipi->lp_bandctl); + if (ret < 0) + return ret; + + debug("%s: mipi lp:%dmhz:0x%x:0x%x, hs:%dmhz:0x%x:0x%x, %s trans\n", + __func__, mipi->lp_bitrate, mipi->lp_pllpms, mipi->lp_bandctl, + mipi->hs_bitrate, mipi->hs_pllpms, mipi->hs_bandctl, + lpm ? "low" : "high"); + + if (lpm) + nx_mipi_dsi_set_pll(index, 1, 0xFFFFFFFF, + mipi->lp_pllpms, mipi->lp_bandctl, 0, 0); + else + nx_mipi_dsi_set_pll(index, 1, 0xFFFFFFFF, + mipi->hs_pllpms, mipi->hs_bandctl, 0, 0); + +#ifdef CONFIG_ARCH_S5P4418 + /* + * disable the escape clock generating prescaler + * before soft reset. + */ + nx_mipi_dsi_set_clock(index, 0, 0, 1, 1, 1, 0, 0, 0, 0, 10); + mdelay(1); +#endif + + nx_mipi_dsi_software_reset(index); + nx_mipi_dsi_set_clock(index, 0, 0, 1, 1, 1, 0, 0, 0, 1, esc_pre_value); + nx_mipi_dsi_set_phy(index, 0, 1, 1, 0, 0, 0, 0, 0); + + if (lpm) + nx_mipi_dsi_set_escape_lp(index, nx_mipi_dsi_lpmode_lp, + nx_mipi_dsi_lpmode_lp); + else + nx_mipi_dsi_set_escape_lp(index, nx_mipi_dsi_lpmode_hs, + nx_mipi_dsi_lpmode_hs); + mdelay(20); + + return 0; +} + +static int mipi_enable(int module, int input, + struct dp_sync_info *sync, struct dp_ctrl_info *ctrl, + struct dp_mipi_dev *mipi) +{ + struct mipi_dsi_device *dsi = &mipi->dsi; + int clkid = DP_CLOCK_MIPI; + int index = MIPI_INDEX; + int width = sync->h_active_len; + int height = sync->v_active_len; + int HFP = sync->h_front_porch; + int HBP = sync->h_back_porch; + int HS = sync->h_sync_width; + int VFP = sync->v_front_porch; + int VBP = sync->v_back_porch; + int VS = sync->v_sync_width; + int en_prescaler = 1; + u32 esc_pre_value = MIPI_EXC_PRE_VALUE; + + int txhsclock = 1; + int lpm = mipi->lpm_trans; + bool command_mode = mipi->command_mode; + + enum nx_mipi_dsi_format dsi_format; + int data_len = dsi->lanes - 1; + bool burst = dsi->mode_flags & MIPI_DSI_MODE_VIDEO_BURST ? true : false; + bool eot_enable = dsi->mode_flags & MIPI_DSI_MODE_EOT_PACKET ? + false : true; + + /* + * disable the escape clock generating prescaler + * before soft reset. + */ +#ifdef CONFIG_ARCH_S5P4418 + en_prescaler = 0; +#endif + + debug("%s: mode:%s, lanes.%d\n", __func__, + command_mode ? "command" : "video", data_len + 1); + + if (lpm) + nx_mipi_dsi_set_escape_lp(index, + nx_mipi_dsi_lpmode_hs, + nx_mipi_dsi_lpmode_hs); + + nx_mipi_dsi_set_pll(index, 1, 0xFFFFFFFF, + mipi->hs_pllpms, mipi->hs_bandctl, 0, 0); + mdelay(1); + + nx_mipi_dsi_set_clock(index, 0, 0, 1, 1, 1, 0, 0, 0, en_prescaler, 10); + mdelay(1); + + nx_mipi_dsi_software_reset(index); + nx_mipi_dsi_set_clock(index, txhsclock, 0, 1, + 1, 1, 0, 0, 0, 1, esc_pre_value); + + switch (data_len) { + case 0: /* 1 lane */ + nx_mipi_dsi_set_phy(index, data_len, 1, 1, 0, 0, 0, 0, 0); + break; + case 1: /* 2 lane */ + nx_mipi_dsi_set_phy(index, data_len, 1, 1, 1, 0, 0, 0, 0); + break; + case 2: /* 3 lane */ + nx_mipi_dsi_set_phy(index, data_len, 1, 1, 1, 1, 0, 0, 0); + break; + case 3: /* 3 lane */ + nx_mipi_dsi_set_phy(index, data_len, 1, 1, 1, 1, 1, 0, 0); + break; + default: + printf("%s: not support data lanes %d\n", + __func__, data_len + 1); + return -EINVAL; + } + + switch (dsi->format) { + case MIPI_DSI_FMT_RGB565: + dsi_format = nx_mipi_dsi_format_rgb565; + break; + case MIPI_DSI_FMT_RGB666: + dsi_format = nx_mipi_dsi_format_rgb666; + break; + case MIPI_DSI_FMT_RGB666_PACKED: + dsi_format = nx_mipi_dsi_format_rgb666_packed; + break; + case MIPI_DSI_FMT_RGB888: + dsi_format = nx_mipi_dsi_format_rgb888; + break; + default: + printf("%s: not support format %d\n", __func__, dsi->format); + return -EINVAL; + } + + nx_mipi_dsi_set_config_video_mode(index, 1, 0, burst, + nx_mipi_dsi_syncmode_event, + eot_enable, 1, 1, 1, 1, 0, dsi_format, + HFP, HBP, HS, VFP, VBP, VS, 0); + + nx_mipi_dsi_set_size(index, width, height); + + /* set mux */ + nx_disp_top_set_mipimux(1, module); + + /* 0 is spdif, 1 is mipi vclk */ + nx_disp_top_clkgen_set_clock_source(clkid, 1, ctrl->clk_src_lv0); + nx_disp_top_clkgen_set_clock_divisor(clkid, 1, + ctrl->clk_div_lv1 * + ctrl->clk_div_lv0); + + /* SPDIF and MIPI */ + nx_disp_top_clkgen_set_clock_divisor_enable(clkid, 1); + + /* START: CLKGEN, MIPI is started in setup function */ + nx_disp_top_clkgen_set_clock_divisor_enable(clkid, true); + nx_mipi_dsi_set_enable(index, true); + + return 0; +} + +static int nx_mipi_transfer_tx(struct mipi_dsi_device *dsi, + struct mipi_xfer_msg *xfer) +{ + const u8 *txb; + int size, index = 0; + u32 data; + + if (xfer->tx_len > DSI_TX_FIFO_SIZE) + printf("warn: tx %d size over fifo %d\n", + (int)xfer->tx_len, DSI_TX_FIFO_SIZE); + + /* write payload */ + size = xfer->tx_len; + txb = xfer->tx_buf; + + while (size >= 4) { + data = (txb[3] << 24) | (txb[2] << 16) | + (txb[1] << 8) | (txb[0]); + nx_mipi_dsi_write_payload(index, data); + txb += 4, size -= 4; + data = 0; + } + + switch (size) { + case 3: + data |= txb[2] << 16; + case 2: + data |= txb[1] << 8; + case 1: + data |= txb[0]; + nx_mipi_dsi_write_payload(index, data); + break; + case 0: + break; /* no payload */ + } + + /* write packet hdr */ + data = (xfer->data[1] << 16) | (xfer->data[0] << 8) | xfer->id; + + nx_mipi_dsi_write_pkheader(index, data); + + return 0; +} + +static int nx_mipi_transfer_done(struct mipi_dsi_device *dsi) +{ + int index = 0, count = 100; + u32 value; + + do { + mdelay(1); + value = nx_mipi_dsi_read_fifo_status(index); + if (((1 << 22) & value)) + break; + } while (count-- > 0); + + if (count < 0) + return -EINVAL; + + return 0; +} + +static int nx_mipi_transfer_rx(struct mipi_dsi_device *dsi, + struct mipi_xfer_msg *xfer) +{ + u8 *rxb = xfer->rx_buf; + int index = 0, rx_len = 0; + u32 data, count = 0; + u16 size; + int err = -EINVAL; + + nx_mipi_dsi_clear_interrupt_pending(index, 18); + + while (1) { + /* Completes receiving data. */ + if (nx_mipi_dsi_get_interrupt_pending(index, 18)) + break; + + mdelay(1); + + if (count > 500) { + printf("%s: error recevice data\n", __func__); + err = -EINVAL; + goto clear_fifo; + } else { + count++; + } + } + + data = nx_mipi_dsi_read_fifo(index); + + switch (data & 0x3f) { + case MIPI_DSI_RX_GENERIC_SHORT_READ_RESPONSE_2BYTE: + case MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_2BYTE: + if (xfer->rx_len >= 2) { + rxb[1] = data >> 16; + rx_len++; + } + + /* Fall through */ + case MIPI_DSI_RX_GENERIC_SHORT_READ_RESPONSE_1BYTE: + case MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_1BYTE: + rxb[0] = data >> 8; + rx_len++; + xfer->rx_len = rx_len; + err = rx_len; + goto clear_fifo; + + case MIPI_DSI_RX_ACKNOWLEDGE_AND_ERROR_REPORT: + printf("DSI Error Report: 0x%04x\n", (data >> 8) & 0xffff); + err = rx_len; + goto clear_fifo; + } + + size = (data >> 8) & 0xffff; + + if (size > xfer->rx_len) + size = xfer->rx_len; + else if (size < xfer->rx_len) + xfer->rx_len = size; + + size = xfer->rx_len - rx_len; + rx_len += size; + + /* Receive payload */ + while (size >= 4) { + data = nx_mipi_dsi_read_fifo(index); + rxb[0] = (data >> 0) & 0xff; + rxb[1] = (data >> 8) & 0xff; + rxb[2] = (data >> 16) & 0xff; + rxb[3] = (data >> 24) & 0xff; + rxb += 4, size -= 4; + } + + if (size) { + data = nx_mipi_dsi_read_fifo(index); + switch (size) { + case 3: + rxb[2] = (data >> 16) & 0xff; + case 2: + rxb[1] = (data >> 8) & 0xff; + case 1: + rxb[0] = data & 0xff; + } + } + + if (rx_len == xfer->rx_len) + err = rx_len; + +clear_fifo: + size = DSI_RX_FIFO_SIZE / 4; + do { + data = nx_mipi_dsi_read_fifo(index); + if (data == DSI_RX_FIFO_EMPTY) + break; + } while (--size); + + return err; +} + +#define IS_SHORT(t) (9 > ((t) & 0x0f)) + +static int nx_mipi_transfer(struct mipi_dsi_device *dsi, + const struct mipi_dsi_msg *msg) +{ + struct mipi_xfer_msg xfer; + int err; + + if (!msg->tx_len) + return -EINVAL; + + /* set id */ + xfer.id = msg->type | (msg->channel << 6); + + /* short type msg */ + if (IS_SHORT(msg->type)) { + const char *txb = msg->tx_buf; + + if (msg->tx_len > 2) + return -EINVAL; + + xfer.tx_len = 0; /* no payload */ + xfer.data[0] = txb[0]; + xfer.data[1] = (msg->tx_len == 2) ? txb[1] : 0; + xfer.tx_buf = NULL; + } else { + xfer.tx_len = msg->tx_len; + xfer.data[0] = msg->tx_len & 0xff; + xfer.data[1] = msg->tx_len >> 8; + xfer.tx_buf = msg->tx_buf; + } + + xfer.rx_len = msg->rx_len; + xfer.rx_buf = msg->rx_buf; + xfer.flags = msg->flags; + + err = nx_mipi_transfer_tx(dsi, &xfer); + + if (xfer.rx_len) + err = nx_mipi_transfer_rx(dsi, &xfer); + + nx_mipi_transfer_done(dsi); + + return err; +} + +static ssize_t nx_mipi_write_buffer(struct mipi_dsi_device *dsi, + const void *data, size_t len) +{ + struct mipi_dsi_msg msg = { + .channel = dsi->channel, + .tx_buf = data, + .tx_len = len + }; + + switch (len) { + case 0: + return -EINVAL; + case 1: + msg.type = MIPI_DSI_DCS_SHORT_WRITE; + break; + case 2: + msg.type = MIPI_DSI_DCS_SHORT_WRITE_PARAM; + break; + default: + msg.type = MIPI_DSI_DCS_LONG_WRITE; + break; + } + + if (dsi->mode_flags & MIPI_DSI_MODE_LPM) + msg.flags |= MIPI_DSI_MSG_USE_LPM; + + return nx_mipi_transfer(dsi, &msg); +} + +__weak int nx_mipi_dsi_lcd_bind(struct mipi_dsi_device *dsi) +{ + return 0; +} + +/* + * disply + * MIPI DSI Setting + * (1) Initiallize MIPI(DSIM,DPHY,PLL) + * (2) Initiallize LCD + * (3) ReInitiallize MIPI(DSIM only) + * (4) Turn on display(MLC,DPC,...) + */ +void nx_mipi_display(int module, + struct dp_sync_info *sync, struct dp_ctrl_info *ctrl, + struct dp_plane_top *top, struct dp_plane_info *planes, + struct dp_mipi_dev *dev) +{ + struct dp_plane_info *plane = planes; + struct mipi_dsi_device *dsi = &dev->dsi; + int input = module == 0 ? DP_DEVICE_DP0 : DP_DEVICE_DP1; + int count = top->plane_num; + int i = 0, ret; + + printf("MIPI: dp.%d\n", module); + + /* map mipi-dsi write callback func */ + dsi->write_buffer = nx_mipi_write_buffer; + + ret = nx_mipi_dsi_lcd_bind(dsi); + if (ret) { + printf("Error: bind mipi-dsi lcd driver !\n"); + return; + } + + dp_control_init(module); + dp_plane_init(module); + + mipi_init(); + + /* set plane */ + dp_plane_screen_setup(module, top); + + for (i = 0; count > i; i++, plane++) { + if (!plane->enable) + continue; + dp_plane_layer_setup(module, plane); + dp_plane_layer_enable(module, plane, 1); + } + dp_plane_screen_enable(module, 1); + + /* set mipi */ + mipi_prepare(module, input, sync, ctrl, dev); + + if (dsi->ops && dsi->ops->prepare) + dsi->ops->prepare(dsi); + + if (dsi->ops && dsi->ops->enable) + dsi->ops->enable(dsi); + + mipi_enable(module, input, sync, ctrl, dev); + + /* set dp control */ + dp_control_setup(module, sync, ctrl); + dp_control_enable(module, 1); +} diff --git a/drivers/video/nexell/s5pxx18_dp_rgb.c b/drivers/video/nexell/s5pxx18_dp_rgb.c new file mode 100644 index 0000000000..44e8edb02a --- /dev/null +++ b/drivers/video/nexell/s5pxx18_dp_rgb.c @@ -0,0 +1,69 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2016 Nexell Co., Ltd. + * + * Author: junghyun, kim <jhkim@nexell.co.kr> + */ + +#include <config.h> +#include <common.h> +#include <errno.h> + +#include <asm/arch/display.h> + +#include "soc/s5pxx18_soc_disptop.h" + +static int rgb_switch(int module, int input, struct dp_sync_info *sync, + struct dp_rgb_dev *dev) +{ + int mpu = dev->lcd_mpu_type; + int rsc = 0, sel = 0; + + switch (module) { + case 0: + sel = mpu ? 1 : 0; + break; + case 1: + sel = rsc ? 3 : 2; + break; + default: + printf("Fail, %s nuknown module %d\n", __func__, module); + return -1; + } + + nx_disp_top_set_primary_mux(sel); + return 0; +} + +void nx_rgb_display(int module, + struct dp_sync_info *sync, struct dp_ctrl_info *ctrl, + struct dp_plane_top *top, struct dp_plane_info *planes, + struct dp_rgb_dev *dev) +{ + struct dp_plane_info *plane = planes; + int input = module == 0 ? DP_DEVICE_DP0 : DP_DEVICE_DP1; + int count = top->plane_num; + int i = 0; + + printf("RGB: dp.%d\n", module); + + dp_control_init(module); + dp_plane_init(module); + + /* set plane */ + dp_plane_screen_setup(module, top); + + for (i = 0; count > i; i++, plane++) { + if (!plane->enable) + continue; + dp_plane_layer_setup(module, plane); + dp_plane_layer_enable(module, plane, 1); + } + + dp_plane_screen_enable(module, 1); + + rgb_switch(module, input, sync, dev); + + dp_control_setup(module, sync, ctrl); + dp_control_enable(module, 1); +} diff --git a/drivers/video/nexell/soc/Makefile b/drivers/video/nexell/soc/Makefile new file mode 100644 index 0000000000..a3036e52ee --- /dev/null +++ b/drivers/video/nexell/soc/Makefile @@ -0,0 +1,11 @@ +# SPDX-License-Identifier: GPL-2.0+ +# +# (C) Copyright 2016 Nexell +# Junghyun, kim<jhkim@nexell.co.kr> + +obj-$(CONFIG_VIDEO_NX) += s5pxx18_soc_dpc.o s5pxx18_soc_mlc.o \ + s5pxx18_soc_disptop.o s5pxx18_soc_disptop_clk.o + +obj-$(CONFIG_VIDEO_NX_LVDS) += s5pxx18_soc_lvds.o +obj-$(CONFIG_VIDEO_NX_MIPI) += s5pxx18_soc_mipi.o +obj-$(CONFIG_VIDEO_NX_HDMI) += s5pxx18_soc_hdmi.o diff --git a/drivers/video/nexell/soc/s5pxx18_soc_disptop.c b/drivers/video/nexell/soc/s5pxx18_soc_disptop.c new file mode 100644 index 0000000000..626e53a876 --- /dev/null +++ b/drivers/video/nexell/soc/s5pxx18_soc_disptop.c @@ -0,0 +1,185 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2016 Nexell Co., Ltd. + * + * Author: junghyun, kim <jhkim@nexell.co.kr> + */ + +#include <linux/types.h> +#include <linux/io.h> + +#include "s5pxx18_soc_disptop.h" + +static struct { + struct nx_disp_top_register_set *pregister; +} __g_module_variables = { NULL, }; + +int nx_disp_top_initialize(void) +{ + static int binit; + u32 i; + + if (binit == 0) { + for (i = 0; i < NUMBER_OF_DISPTOP_MODULE; i++) + __g_module_variables.pregister = NULL; + binit = 1; + } + return 1; +} + +u32 nx_disp_top_get_number_of_module(void) +{ + return NUMBER_OF_DISPTOP_MODULE; +} + +u32 nx_disp_top_get_physical_address(void) +{ + static const u32 physical_addr[] = PHY_BASEADDR_DISPTOP_LIST; + + return (u32)(physical_addr[0] + PHY_BASEADDR_DISPLAYTOP_MODULE_OFFSET); +} + +u32 nx_disp_top_get_size_of_register_set(void) +{ + return sizeof(struct nx_disp_top_register_set); +} + +void nx_disp_top_set_base_address(void *base_address) +{ + __g_module_variables.pregister = + (struct nx_disp_top_register_set *)base_address; +} + +void *nx_disp_top_get_base_address(void) +{ + return (void *)__g_module_variables.pregister; +} + +void nx_disp_top_set_resconvmux(int benb, u32 sel) +{ + register struct nx_disp_top_register_set *pregister; + u32 regvalue; + + pregister = __g_module_variables.pregister; + regvalue = (benb << 31) | (sel << 0); + writel((u32)regvalue, &pregister->resconv_mux_ctrl); +} + +void nx_disp_top_set_hdmimux(int benb, u32 sel) +{ + register struct nx_disp_top_register_set *pregister; + u32 regvalue; + + pregister = __g_module_variables.pregister; + regvalue = (benb << 31) | (sel << 0); + writel((u32)regvalue, &pregister->interconv_mux_ctrl); +} + +void nx_disp_top_set_mipimux(int benb, u32 sel) +{ + register struct nx_disp_top_register_set *pregister; + u32 regvalue; + + pregister = __g_module_variables.pregister; + regvalue = (benb << 31) | (sel << 0); + writel((u32)regvalue, &pregister->mipi_mux_ctrl); +} + +void nx_disp_top_set_lvdsmux(int benb, u32 sel) +{ + register struct nx_disp_top_register_set *pregister; + u32 regvalue; + + pregister = __g_module_variables.pregister; + regvalue = (benb << 31) | (sel << 0); + writel((u32)regvalue, &pregister->lvds_mux_ctrl); +} + +void nx_disp_top_set_primary_mux(u32 sel) +{ + register struct nx_disp_top_register_set *pregister; + + pregister = __g_module_variables.pregister; + writel((u32)sel, &pregister->tftmpu_mux); +} + +void nx_disp_top_hdmi_set_vsync_start(u32 sel) +{ + register struct nx_disp_top_register_set *pregister; + + pregister = __g_module_variables.pregister; + writel((u32)sel, &pregister->hdmisyncctrl0); +} + +void nx_disp_top_hdmi_set_vsync_hsstart_end(u32 start, u32 end) +{ + register struct nx_disp_top_register_set *pregister; + + pregister = __g_module_variables.pregister; + writel((u32)(end << 16) | (start << 0), &pregister->hdmisyncctrl3); +} + +void nx_disp_top_hdmi_set_hactive_start(u32 sel) +{ + register struct nx_disp_top_register_set *pregister; + + pregister = __g_module_variables.pregister; + writel((u32)sel, &pregister->hdmisyncctrl1); +} + +void nx_disp_top_hdmi_set_hactive_end(u32 sel) +{ + register struct nx_disp_top_register_set *pregister; + + pregister = __g_module_variables.pregister; + writel((u32)sel, &pregister->hdmisyncctrl2); +} + +void nx_disp_top_set_hdmifield(u32 enable, u32 init_val, u32 vsynctoggle, + u32 hsynctoggle, u32 vsyncclr, u32 hsyncclr, + u32 field_use, u32 muxsel) +{ + register struct nx_disp_top_register_set *pregister; + u32 regvalue; + + pregister = __g_module_variables.pregister; + regvalue = ((enable & 0x01) << 0) | ((init_val & 0x01) << 1) | + ((vsynctoggle & 0x3fff) << 2) | + ((hsynctoggle & 0x3fff) << 17); + writel(regvalue, &pregister->hdmifieldctrl); + regvalue = ((field_use & 0x01) << 31) | ((muxsel & 0x01) << 30) | + ((hsyncclr) << 15) | ((vsyncclr) << 0); + writel(regvalue, &pregister->greg0); +} + +void nx_disp_top_set_padclock(u32 mux_index, u32 padclk_cfg) +{ + register struct nx_disp_top_register_set *pregister; + u32 regvalue; + + pregister = __g_module_variables.pregister; + regvalue = readl(&pregister->greg1); + if (padmux_secondary_mlc == mux_index) { + regvalue = regvalue & (~(0x7 << 3)); + regvalue = regvalue | (padclk_cfg << 3); + } else if (padmux_resolution_conv == mux_index) { + regvalue = regvalue & (~(0x7 << 6)); + regvalue = regvalue | (padclk_cfg << 6); + } else { + regvalue = regvalue & (~(0x7 << 0)); + regvalue = regvalue | (padclk_cfg << 0); + } + writel(regvalue, &pregister->greg1); +} + +void nx_disp_top_set_lcdif_enb(int enb) +{ + register struct nx_disp_top_register_set *pregister; + u32 regvalue; + + pregister = __g_module_variables.pregister; + regvalue = readl(&pregister->greg1); + regvalue = regvalue & (~(0x1 << 9)); + regvalue = regvalue | ((enb & 0x1) << 9); + writel(regvalue, &pregister->greg1); +} diff --git a/drivers/video/nexell/soc/s5pxx18_soc_disptop.h b/drivers/video/nexell/soc/s5pxx18_soc_disptop.h new file mode 100644 index 0000000000..c7bf5043e6 --- /dev/null +++ b/drivers/video/nexell/soc/s5pxx18_soc_disptop.h @@ -0,0 +1,385 @@ +/* SPDX-License-Identifier: GPL-2.0+ + * + * Copyright (C) 2016 Nexell Co., Ltd. + * + * Author: junghyun, kim <jhkim@nexell.co.kr> + */ + +#ifndef _S5PXX18_SOC_DISPTOP_H_ +#define _S5PXX18_SOC_DISPTOP_H_ + +#include "s5pxx18_soc_disptype.h" + +#define NUMBER_OF_DISPTOP_MODULE 1 +#define PHY_BASEADDR_DISPLAYTOP_MODULE 0xC0100000 +#define PHY_BASEADDR_DISPTOP_LIST \ + { PHY_BASEADDR_DISPLAYTOP_MODULE } + +#define HDMI_ADDR_OFFSET \ + (((PHY_BASEADDR_DISPLAYTOP_MODULE / 0x00100000) % 2) ? 0x100000 \ + : 0x000000) +#define OTHER_ADDR_OFFSET \ + (((PHY_BASEADDR_DISPLAYTOP_MODULE / 0x00100000) % 2) ? 0x000000 \ + : 0x100000) +#define PHY_BASEADDR_DISPLAYTOP_MODULE_OFFSET (OTHER_ADDR_OFFSET + 0x001000) +#define PHY_BASEADDR_DUALDISPLAY_MODULE \ + (PHY_BASEADDR_DISPLAYTOP_MODULE + OTHER_ADDR_OFFSET + 0x002000) +#define PHY_BASEADDR_RESCONV_MODULE \ + (PHY_BASEADDR_DISPLAYTOP_MODULE + OTHER_ADDR_OFFSET + 0x003000) +#define PHY_BASEADDR_LCDINTERFACE_MODULE \ + (PHY_BASEADDR_DISPLAYTOP_MODULE + OTHER_ADDR_OFFSET + 0x004000) +#define PHY_BASEADDR_HDMI_MODULE (PHY_BASEADDR_DISPLAYTOP_MODULE + 0x000000) +#define PHY_BASEADDR_LVDS_MODULE \ + (PHY_BASEADDR_DISPLAYTOP_MODULE + OTHER_ADDR_OFFSET + 0x00a000) + +#define NUMBER_OF_DUALDISPLAY_MODULE 1 +#define INTNUM_OF_DUALDISPLAY_MODULE_PRIMIRQ \ + INTNUM_OF_DISPLAYTOP_MODULE_DUALDISPLAY_PRIMIRQ +#define INTNUM_OF_DUALDISPLAY_MODULE_SECONDIRQ \ + INTNUM_OF_DISPLAYTOP_MODULE_DUALDISPLAY_SECONDIRQ +#define RESETINDEX_OF_DUALDISPLAY_MODULE_I_NRST \ + RESETINDEX_OF_DISPLAYTOP_MODULE_I_DUALDISPLAY_NRST +#define PADINDEX_OF_DUALDISPLAY_O_NCS \ + PADINDEX_OF_DISPLAYTOP_O_DUAL_DISPLAY_PADPRIMVCLK +#define PADINDEX_OF_DUALDISPLAY_O_NRD \ + PADINDEX_OF_DISPLAYTOP_O_DUAL_DISPLAY_PRIM_PADN_HSYNC +#define PADINDEX_OF_DUALDISPLAY_O_RS \ + PADINDEX_OF_DISPLAYTOP_O_DUAL_DISPLAY_PRIM_PADN_VSYNC +#define PADINDEX_OF_DUALDISPLAY_O_NWR \ + PADINDEX_OF_DISPLAYTOP_O_DUAL_DISPLAY_PRIM_PADDE +#define PADINDEX_OF_DUALDISPLAY_PADPRIMVCLK \ + PADINDEX_OF_DISPLAYTOP_O_DUAL_DISPLAY_PADPRIMVCLK +#define PADINDEX_OF_DUALDISPLAY_O_PRIM_PADN_HSYNC \ + PADINDEX_OF_DISPLAYTOP_O_DUAL_DISPLAY_PRIM_PADN_HSYNC +#define PADINDEX_OF_DUALDISPLAY_O_PRIM_PADN_VSYNC \ + PADINDEX_OF_DISPLAYTOP_O_DUAL_DISPLAY_PRIM_PADN_VSYNC +#define PADINDEX_OF_DUALDISPLAY_O_PRIM_PADDE \ + PADINDEX_OF_DISPLAYTOP_O_DUAL_DISPLAY_PRIM_PADDE +#define PADINDEX_OF_DUALDISPLAY_PRIM_0_ \ + PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_0_ +#define PADINDEX_OF_DUALDISPLAY_PRIM_1_ \ + PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_1_ +#define PADINDEX_OF_DUALDISPLAY_PRIM_2_ \ + PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_2_ +#define PADINDEX_OF_DUALDISPLAY_PRIM_3_ \ + PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_3_ +#define PADINDEX_OF_DUALDISPLAY_PRIM_4_ \ + PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_4_ +#define PADINDEX_OF_DUALDISPLAY_PRIM_5_ \ + PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_5_ +#define PADINDEX_OF_DUALDISPLAY_PRIM_6_ \ + PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_6_ +#define PADINDEX_OF_DUALDISPLAY_PRIM_7_ \ + PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_7_ +#define PADINDEX_OF_DUALDISPLAY_PRIM_8_ \ + PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_8_ +#define PADINDEX_OF_DUALDISPLAY_PRIM_9_ \ + PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_9_ +#define PADINDEX_OF_DUALDISPLAY_PRIM_10_ \ + PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_10_ +#define PADINDEX_OF_DUALDISPLAY_PRIM_11_ \ + PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_11_ +#define PADINDEX_OF_DUALDISPLAY_PRIM_12_ \ + PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_12_ +#define PADINDEX_OF_DUALDISPLAY_PRIM_13_ \ + PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_13_ +#define PADINDEX_OF_DUALDISPLAY_PRIM_14_ \ + PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_14_ +#define PADINDEX_OF_DUALDISPLAY_PRIM_15_ \ + PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_15_ +#define PADINDEX_OF_DUALDISPLAY_PRIM_16_ \ + PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_16_ +#define PADINDEX_OF_DUALDISPLAY_PRIM_17_ \ + PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_17_ +#define PADINDEX_OF_DUALDISPLAY_PRIM_18_ \ + PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_18_ +#define PADINDEX_OF_DUALDISPLAY_PRIM_19_ \ + PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_19_ +#define PADINDEX_OF_DUALDISPLAY_PRIM_20_ \ + PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_20_ +#define PADINDEX_OF_DUALDISPLAY_PRIM_21_ \ + PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_21_ +#define PADINDEX_OF_DUALDISPLAY_PRIM_22_ \ + PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_22_ +#define PADINDEX_OF_DUALDISPLAY_PRIM_23_ \ + PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_23_ +#define PADINDEX_OF_DUALDISPLAY_PADSECONDVCLK \ + PADINDEX_OF_DISPLAYTOP_O_DUAL_DISPLAY_PADPRIMVCLK +#define PADINDEX_OF_DUALDISPLAY_O_SECOND_PADN_HSYNC \ + PADINDEX_OF_DISPLAYTOP_O_DUAL_DISPLAY_PRIM_PADN_HSYNC +#define PADINDEX_OF_DUALDISPLAY_O_SECOND_PADN_VSYNC \ + PADINDEX_OF_DISPLAYTOP_O_DUAL_DISPLAY_PRIM_PADN_VSYNC +#define PADINDEX_OF_DUALDISPLAY_O_SECOND_PADDE \ + PADINDEX_OF_DISPLAYTOP_O_DUAL_DISPLAY_PRIM_PADDE +#define PADINDEX_OF_DUALDISPLAY_SECOND_0_ \ + PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_0_ +#define PADINDEX_OF_DUALDISPLAY_SECOND_1_ \ + PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_1_ +#define PADINDEX_OF_DUALDISPLAY_SECOND_2_ \ + PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_2_ +#define PADINDEX_OF_DUALDISPLAY_SECOND_3_ \ + PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_3_ +#define PADINDEX_OF_DUALDISPLAY_SECOND_4_ \ + PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_4_ +#define PADINDEX_OF_DUALDISPLAY_SECOND_5_ \ + PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_5_ +#define PADINDEX_OF_DUALDISPLAY_SECOND_6_ \ + PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_6_ +#define PADINDEX_OF_DUALDISPLAY_SECOND_7_ \ + PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_7_ +#define PADINDEX_OF_DUALDISPLAY_SECOND_8_ \ + PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_8_ +#define PADINDEX_OF_DUALDISPLAY_SECOND_9_ \ + PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_9_ +#define PADINDEX_OF_DUALDISPLAY_SECOND_10_ \ + PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_10_ +#define PADINDEX_OF_DUALDISPLAY_SECOND_11_ \ + PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_11_ +#define PADINDEX_OF_DUALDISPLAY_SECOND_12_ \ + PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_12_ +#define PADINDEX_OF_DUALDISPLAY_SECOND_13_ \ + PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_13_ +#define PADINDEX_OF_DUALDISPLAY_SECOND_14_ \ + PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_14_ +#define PADINDEX_OF_DUALDISPLAY_SECOND_15_ \ + PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_15_ +#define PADINDEX_OF_DUALDISPLAY_SECOND_16_ \ + PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_16_ +#define PADINDEX_OF_DUALDISPLAY_SECOND_17_ \ + PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_17_ +#define PADINDEX_OF_DUALDISPLAY_SECOND_18_ \ + PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_18_ +#define PADINDEX_OF_DUALDISPLAY_SECOND_19_ \ + PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_19_ +#define PADINDEX_OF_DUALDISPLAY_SECOND_20_ \ + PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_20_ +#define PADINDEX_OF_DUALDISPLAY_SECOND_21_ \ + PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_21_ +#define PADINDEX_OF_DUALDISPLAY_SECOND_22_ \ + PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_22_ +#define PADINDEX_OF_DUALDISPLAY_SECOND_23_ \ + PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_23_ + +#define NUMBER_OF_RESCONV_MODULE 1 +#define INTNUM_OF_RESCONV_MODULE INTNUM_OF_DISPLAYTOP_MODULE_RESCONV_IRQ +#define RESETINDEX_OF_RESCONV_MODULE_I_NRST \ + RESETINDEX_OF_DISPLAYTOP_MODULE_I_RESCONV_NRST +#define RESETINDEX_OF_RESCONV_MODULE RESETINDEX_OF_RESCONV_MODULE_I_NRST +#define NUMBER_OF_LCDINTERFACE_MODULE 1 +#define RESETINDEX_OF_LCDINTERFACE_MODULE_I_NRST \ + RESETINDEX_OF_DISPLAYTOP_MODULE_I_LCDIF_NRST +#define PADINDEX_OF_LCDINTERFACE_O_VCLK \ + PADINDEX_OF_DISPLAYTOP_O_DUAL_DISPLAY_PADPRIMVCLK +#define PADINDEX_OF_LCDINTERFACE_O_NHSYNC \ + PADINDEX_OF_DISPLAYTOP_O_DUAL_DISPLAY_PRIM_PADN_HSYNC +#define PADINDEX_OF_LCDINTERFACE_O_NVSYNC \ + PADINDEX_OF_DISPLAYTOP_O_DUAL_DISPLAY_PRIM_PADN_VSYNC +#define PADINDEX_OF_LCDINTERFACE_O_DE \ + PADINDEX_OF_DISPLAYTOP_O_DUAL_DISPLAY_PRIM_PADDE +#define PADINDEX_OF_LCDINTERFACE_RGB24_0_ \ + PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_0_ +#define PADINDEX_OF_LCDINTERFACE_RGB24_1_ \ + PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_1_ +#define PADINDEX_OF_LCDINTERFACE_RGB24_2_ \ + PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_2_ +#define PADINDEX_OF_LCDINTERFACE_RGB24_3_ \ + PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_3_ +#define PADINDEX_OF_LCDINTERFACE_RGB24_4_ \ + PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_4_ +#define PADINDEX_OF_LCDINTERFACE_RGB24_5_ \ + PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_5_ +#define PADINDEX_OF_LCDINTERFACE_RGB24_6_ \ + PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_6_ +#define PADINDEX_OF_LCDINTERFACE_RGB24_7_ \ + PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_7_ +#define PADINDEX_OF_LCDINTERFACE_RGB24_8_ \ + PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_8_ +#define PADINDEX_OF_LCDINTERFACE_RGB24_9_ \ + PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_9_ +#define PADINDEX_OF_LCDINTERFACE_RGB24_10_ \ + PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_10_ +#define PADINDEX_OF_LCDINTERFACE_RGB24_11_ \ + PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_11_ +#define PADINDEX_OF_LCDINTERFACE_RGB24_12_ \ + PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_12_ +#define PADINDEX_OF_LCDINTERFACE_RGB24_13_ \ + PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_13_ +#define PADINDEX_OF_LCDINTERFACE_RGB24_14_ \ + PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_14_ +#define PADINDEX_OF_LCDINTERFACE_RGB24_15_ \ + PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_15_ +#define PADINDEX_OF_LCDINTERFACE_RGB24_16_ \ + PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_16_ +#define PADINDEX_OF_LCDINTERFACE_RGB24_17_ \ + PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_17_ +#define PADINDEX_OF_LCDINTERFACE_RGB24_18_ \ + PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_18_ +#define PADINDEX_OF_LCDINTERFACE_RGB24_19_ \ + PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_19_ +#define PADINDEX_OF_LCDINTERFACE_RGB24_20_ \ + PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_20_ +#define PADINDEX_OF_LCDINTERFACE_RGB24_21_ \ + PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_21_ +#define PADINDEX_OF_LCDINTERFACE_RGB24_22_ \ + PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_22_ +#define PADINDEX_OF_LCDINTERFACE_RGB24_23_ \ + PADINDEX_OF_DISPLAYTOP_DUAL_DISPLAY_PRIM_23_ + +#define NUMBER_OF_HDMI_MODULE 1 +#define INTNUM_OF_HDMI_MODULE INTNUM_OF_DISPLAYTOP_MODULE_HDMI_IRQ +#define RESETINDEX_OF_HDMI_MODULE_I_NRST \ + RESETINDEX_OF_DISPLAYTOP_MODULE_I_HDMI_NRST +#define RESETINDEX_OF_HDMI_MODULE_I_NRST_VIDEO \ + RESETINDEX_OF_DISPLAYTOP_MODULE_I_HDMI_VIDEO_NRST +#define RESETINDEX_OF_HDMI_MODULE_I_NRST_SPDIF \ + RESETINDEX_OF_DISPLAYTOP_MODULE_I_HDMI_SPDIF_NRST +#define RESETINDEX_OF_HDMI_MODULE_I_NRST_TMDS \ + RESETINDEX_OF_DISPLAYTOP_MODULE_I_HDMI_TMDS_NRST +#define RESETINDEX_OF_HDMI_MODULE_I_NRST_PHY \ + RESETINDEX_OF_DISPLAYTOP_MODULE_I_HDMI_PHY_NRST +#define PADINDEX_OF_HDMI_I_PHY_CLKI PADINDEX_OF_DISPLAYTOP_I_HDMI_CLKI +#define PADINDEX_OF_HDMI_O_PHY_CLKO PADINDEX_OF_DISPLAYTOP_O_HDMI_CLKO +#define PADINDEX_OF_HDMI_IO_PHY_REXT PADINDEX_OF_DISPLAYTOP_IO_HDMI_REXT +#define PADINDEX_OF_HDMI_O_PHY_TX0P PADINDEX_OF_DISPLAYTOP_O_HDMI_TX0P +#define PADINDEX_OF_HDMI_O_PHY_TX0N PADINDEX_OF_DISPLAYTOP_O_HDMI_TX0N +#define PADINDEX_OF_HDMI_O_PHY_TX1P PADINDEX_OF_DISPLAYTOP_O_HDMI_TX1P +#define PADINDEX_OF_HDMI_O_PHY_TX1N PADINDEX_OF_DISPLAYTOP_O_HDMI_TX1N +#define PADINDEX_OF_HDMI_O_PHY_TX2P PADINDEX_OF_DISPLAYTOP_O_HDMI_TX2P +#define PADINDEX_OF_HDMI_O_PHY_TX2N PADINDEX_OF_DISPLAYTOP_O_HDMI_TX2N +#define PADINDEX_OF_HDMI_O_PHY_TXCP PADINDEX_OF_DISPLAYTOP_O_HDMI_TXCP +#define PADINDEX_OF_HDMI_O_PHY_TXCN PADINDEX_OF_DISPLAYTOP_O_HDMI_TXCN +#define PADINDEX_OF_HDMI_I_HOTPLUG PADINDEX_OF_DISPLAYTOP_I_HDMI_HOTPLUG_5V +#define PADINDEX_OF_HDMI_IO_PAD_CEC PADINDEX_OF_DISPLAYTOP_IO_HDMI_CEC +#define NUMBER_OF_LVDS_MODULE 1 + +#define RESETINDEX_OF_LVDS_MODULE_I_RESETN \ + RESETINDEX_OF_DISPLAYTOP_MODULE_I_LVDS_NRST +#define RESETINDEX_OF_LVDS_MODULE RESETINDEX_OF_LVDS_MODULE_I_RESETN + +#define PADINDEX_OF_LVDS_TAP PADINDEX_OF_DISPLAYTOP_LVDS_TXP_A +#define PADINDEX_OF_LVDS_TAN PADINDEX_OF_DISPLAYTOP_LVDS_TXN_A +#define PADINDEX_OF_LVDS_TBP PADINDEX_OF_DISPLAYTOP_LVDS_TXP_B +#define PADINDEX_OF_LVDS_TBN PADINDEX_OF_DISPLAYTOP_LVDS_TXN_B +#define PADINDEX_OF_LVDS_TCP PADINDEX_OF_DISPLAYTOP_LVDS_TXP_C +#define PADINDEX_OF_LVDS_TCN PADINDEX_OF_DISPLAYTOP_LVDS_TXN_C +#define PADINDEX_OF_LVDS_TDP PADINDEX_OF_DISPLAYTOP_LVDS_TXP_D +#define PADINDEX_OF_LVDS_TDN PADINDEX_OF_DISPLAYTOP_LVDS_TXN_D +#define PADINDEX_OF_LVDS_TCLKP PADINDEX_OF_DISPLAYTOP_LVDS_TXP_CLK +#define PADINDEX_OF_LVDS_TCLKN PADINDEX_OF_DISPLAYTOP_LVDS_TXN_CLK +#define PADINDEX_OF_LVDS_ROUT PADINDEX_OF_DISPLAYTOP_LVDS_ROUT +#define PADINDEX_OF_LVDS_TEP PADINDEX_OF_DISPLAYTOP_LVDS_TXN_E +#define PADINDEX_OF_LVDS_TEN PADINDEX_OF_DISPLAYTOP_LVDS_TXN_E +#define NUMBER_OF_DISPTOP_CLKGEN_MODULE 5 + +enum disptop_clkgen_module_index { + res_conv_clkgen = 0, + lcdif_clkgen = 1, + to_mipi_clkgen = 2, + to_lvds_clkgen = 3, + hdmi_clkgen = 4, +}; + +enum disptop_res_conv_iclk_cclk { + res_conv_iclk = 0, + res_conv_cclk = 1, +}; + +enum disptop_res_conv_oclk { + res_conv_oclk = 1, +}; + +enum disptop_lcdif_clk { + lcdif_pixel_clkx_n = 0, + lcdif_pixel_clk = 1, +}; + +#define HDMI_SPDIF_CLKGEN 2 +#define HDMI_SPDIF_CLKOUT 0 +#define HDMI_I_VCLK_CLKOUT 0 +#define PHY_BASEADDR_DISPTOP_CLKGEN0_MODULE \ + (PHY_BASEADDR_DISPLAYTOP_MODULE + OTHER_ADDR_OFFSET + 0x006000) +#define PHY_BASEADDR_DISPTOP_CLKGEN1_MODULE \ + (PHY_BASEADDR_DISPLAYTOP_MODULE + OTHER_ADDR_OFFSET + 0x007000) +#define PHY_BASEADDR_DISPTOP_CLKGEN2_MODULE \ + (PHY_BASEADDR_DISPLAYTOP_MODULE + OTHER_ADDR_OFFSET + 0x005000) +#define PHY_BASEADDR_DISPTOP_CLKGEN3_MODULE \ + (PHY_BASEADDR_DISPLAYTOP_MODULE + OTHER_ADDR_OFFSET + 0x008000) +#define PHY_BASEADDR_DISPTOP_CLKGEN4_MODULE \ + (PHY_BASEADDR_DISPLAYTOP_MODULE + OTHER_ADDR_OFFSET + 0x009000) + +struct nx_disp_top_register_set { + u32 resconv_mux_ctrl; + u32 interconv_mux_ctrl; + u32 mipi_mux_ctrl; + u32 lvds_mux_ctrl; + u32 hdmifixctrl0; + u32 hdmisyncctrl0; + u32 hdmisyncctrl1; + u32 hdmisyncctrl2; + u32 hdmisyncctrl3; + u32 tftmpu_mux; + u32 hdmifieldctrl; + u32 greg0; + u32 greg1; + u32 greg2; + u32 greg3; + u32 greg4; + u32 greg5; +}; + +int nx_disp_top_initialize(void); +u32 nx_disp_top_get_number_of_module(void); + +u32 nx_disp_top_get_physical_address(void); +u32 nx_disp_top_get_size_of_register_set(void); +void nx_disp_top_set_base_address(void *base_address); +void *nx_disp_top_get_base_address(void); +int nx_disp_top_open_module(void); +int nx_disp_top_close_module(void); +int nx_disp_top_check_busy(void); + +enum mux_index { + primary_mlc = 0, + secondary_mlc = 1, + resolution_conv = 2, +}; + +enum prim_pad_mux_index { + padmux_primary_mlc = 0, + padmux_primary_mpu = 1, + padmux_secondary_mlc = 2, + padmux_resolution_conv = 3, +}; + +void nx_disp_top_set_resconvmux(int benb, u32 sel); +void nx_disp_top_set_hdmimux(int benb, u32 sel); +void nx_disp_top_set_mipimux(int benb, u32 sel); +void nx_disp_top_set_lvdsmux(int benb, u32 sel); +void nx_disp_top_set_primary_mux(u32 sel); +void nx_disp_top_hdmi_set_vsync_start(u32 sel); +void nx_disp_top_hdmi_set_vsync_hsstart_end(u32 start, u32 end); +void nx_disp_top_hdmi_set_hactive_start(u32 sel); +void nx_disp_top_hdmi_set_hactive_end(u32 sel); + +void nx_disp_top_set_hdmifield(u32 enable, u32 init_val, u32 vsynctoggle, + u32 hsynctoggle, u32 vsyncclr, u32 hsyncclr, + u32 field_use, u32 muxsel); + +enum padclk_config { + padclk_clk = 0, + padclk_inv_clk = 1, + padclk_reserved_clk = 2, + padclk_reserved_inv_clk = 3, + padclk_clk_div2_0 = 4, + padclk_clk_div2_90 = 5, + padclk_clk_div2_180 = 6, + padclk_clk_div2_270 = 7, +}; + +void nx_disp_top_set_padclock(u32 mux_index, u32 padclk_cfg); +void nx_disp_top_set_lcdif_enb(int enb); +void nx_disp_top_set_hdmifield(u32 enable, u32 init_val, u32 vsynctoggle, + u32 hsynctoggle, u32 vsyncclr, u32 hsyncclr, + u32 field_use, u32 muxsel); + +#endif diff --git a/drivers/video/nexell/soc/s5pxx18_soc_disptop_clk.c b/drivers/video/nexell/soc/s5pxx18_soc_disptop_clk.c new file mode 100644 index 0000000000..02361ba411 --- /dev/null +++ b/drivers/video/nexell/soc/s5pxx18_soc_disptop_clk.c @@ -0,0 +1,309 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2016 Nexell Co., Ltd. + * + * Author: junghyun, kim <jhkim@nexell.co.kr> + */ + +#include <linux/types.h> +#include <linux/io.h> + +#include "s5pxx18_soc_disptop_clk.h" +#include "s5pxx18_soc_disptop.h" + +static struct { + struct nx_disptop_clkgen_register_set *__g_pregister; +} __g_module_variables[NUMBER_OF_DISPTOP_CLKGEN_MODULE] = { + { NULL,}, +}; + +int nx_disp_top_clkgen_initialize(void) +{ + static int binit; + u32 i; + + if (binit == 0) { + for (i = 0; i < NUMBER_OF_DISPTOP_CLKGEN_MODULE; i++) + __g_module_variables[i].__g_pregister = NULL; + binit = 1; + } + return 1; +} + +u32 nx_disp_top_clkgen_get_number_of_module(void) +{ + return NUMBER_OF_DISPTOP_CLKGEN_MODULE; +} + +u32 nx_disp_top_clkgen_get_physical_address(u32 module_index) +{ + static const u32 physical_addr[] = + PHY_BASEADDR_DISPTOP_CLKGEN_LIST; + + return (u32)physical_addr[module_index]; +} + +u32 nx_disp_top_clkgen_get_size_of_register_set(void) +{ + return sizeof(struct nx_disptop_clkgen_register_set); +} + +void nx_disp_top_clkgen_set_base_address(u32 module_index, void *base_address) +{ + __g_module_variables[module_index].__g_pregister = + (struct nx_disptop_clkgen_register_set *)base_address; +} + +void *nx_disp_top_clkgen_get_base_address(u32 module_index) +{ + return (void *)__g_module_variables[module_index].__g_pregister; +} + +void nx_disp_top_clkgen_set_clock_bclk_mode(u32 module_index, + enum nx_bclkmode mode) +{ + register struct nx_disptop_clkgen_register_set *pregister; + register u32 regvalue; + u32 clkmode = 0; + + pregister = __g_module_variables[module_index].__g_pregister; + switch (mode) { + case nx_bclkmode_disable: + clkmode = 0; + case nx_bclkmode_dynamic: + clkmode = 2; + break; + case nx_bclkmode_always: + clkmode = 3; + break; + default: + break; + } + + regvalue = pregister->clkenb; + regvalue &= ~3ul; + regvalue |= (clkmode & 0x03); + + writel(regvalue, &pregister->clkenb); +} + +enum nx_bclkmode nx_disp_top_clkgen_get_clock_bclk_mode(u32 module_index) +{ + register struct nx_disptop_clkgen_register_set *pregister; + u32 mode = 0; + + pregister = __g_module_variables[module_index].__g_pregister; + mode = (pregister->clkenb & 3ul); + + switch (mode) { + case 0: + return nx_bclkmode_disable; + case 2: + return nx_bclkmode_dynamic; + case 3: + return nx_bclkmode_always; + default: + break; + } + return nx_bclkmode_disable; +} + +void nx_disp_top_clkgen_set_clock_pclk_mode(u32 module_index, + enum nx_pclkmode mode) +{ + register struct nx_disptop_clkgen_register_set *pregister; + register u32 regvalue; + const u32 pclkmode_pos = 3; + u32 clkmode = 0; + + pregister = __g_module_variables[module_index].__g_pregister; + switch (mode) { + case nx_pclkmode_dynamic: + clkmode = 0; + break; + case nx_pclkmode_always: + clkmode = 1; + break; + default: + break; + } + + regvalue = pregister->clkenb; + regvalue &= ~(1ul << pclkmode_pos); + regvalue |= (clkmode & 0x01) << pclkmode_pos; + + writel(regvalue, &pregister->clkenb); +} + +enum nx_pclkmode nx_disp_top_clkgen_get_clock_pclk_mode(u32 module_index) +{ + register struct nx_disptop_clkgen_register_set *pregister; + const u32 pclkmode_pos = 3; + + pregister = __g_module_variables[module_index].__g_pregister; + + if (pregister->clkenb & (1ul << pclkmode_pos)) + return nx_pclkmode_always; + + return nx_pclkmode_dynamic; +} + +void nx_disp_top_clkgen_set_clock_source(u32 module_index, u32 index, + u32 clk_src) +{ + register struct nx_disptop_clkgen_register_set *pregister; + register u32 read_value; + + const u32 clksrcsel_pos = 2; + const u32 clksrcsel_mask = 0x07 << clksrcsel_pos; + + pregister = __g_module_variables[module_index].__g_pregister; + + read_value = pregister->CLKGEN[index << 1]; + read_value &= ~clksrcsel_mask; + read_value |= clk_src << clksrcsel_pos; + + writel(read_value, &pregister->CLKGEN[index << 1]); +} + +u32 nx_disp_top_clkgen_get_clock_source(u32 module_index, u32 index) +{ + register struct nx_disptop_clkgen_register_set *pregister; + const u32 clksrcsel_pos = 2; + const u32 clksrcsel_mask = 0x07 << clksrcsel_pos; + + pregister = __g_module_variables[module_index].__g_pregister; + + return (pregister->CLKGEN[index << 1] & + clksrcsel_mask) >> clksrcsel_pos; +} + +void nx_disp_top_clkgen_set_clock_divisor(u32 module_index, u32 index, + u32 divisor) +{ + register struct nx_disptop_clkgen_register_set *pregister; + const u32 clkdiv_pos = 5; + const u32 clkdiv_mask = 0xff << clkdiv_pos; + register u32 read_value; + + pregister = __g_module_variables[module_index].__g_pregister; + + read_value = pregister->CLKGEN[index << 1]; + read_value &= ~clkdiv_mask; + read_value |= (divisor - 1) << clkdiv_pos; + writel(read_value, &pregister->CLKGEN[index << 1]); +} + +u32 nx_disp_top_clkgen_get_clock_divisor(u32 module_index, u32 index) +{ + register struct nx_disptop_clkgen_register_set *pregister; + const u32 clkdiv_pos = 5; + const u32 clkdiv_mask = 0xff << clkdiv_pos; + + pregister = __g_module_variables[module_index].__g_pregister; + + return ((pregister->CLKGEN[index << 1] & + clkdiv_mask) >> clkdiv_pos) + 1; +} + +void nx_disp_top_clkgen_set_clock_divisor_enable(u32 module_index, int enable) +{ + register struct nx_disptop_clkgen_register_set *pregister; + register u32 read_value; + const u32 clkgenenb_pos = 2; + const u32 clkgenenb_mask = 1ul << clkgenenb_pos; + + pregister = __g_module_variables[module_index].__g_pregister; + + read_value = pregister->clkenb; + read_value &= ~clkgenenb_mask; + read_value |= (u32)enable << clkgenenb_pos; + + writel(read_value, &pregister->clkenb); +} + +int nx_disp_top_clkgen_get_clock_divisor_enable(u32 module_index) +{ + register struct nx_disptop_clkgen_register_set *pregister; + const u32 clkgenenb_pos = 2; + const u32 clkgenenb_mask = 1ul << clkgenenb_pos; + + pregister = __g_module_variables[module_index].__g_pregister; + + return (int)((pregister->clkenb & + clkgenenb_mask) >> clkgenenb_pos); +} + +void nx_disp_top_clkgen_set_clock_out_inv(u32 module_index, u32 index, + int out_clk_inv) +{ + register struct nx_disptop_clkgen_register_set *pregister; + register u32 read_value; + const u32 outclkinv_pos = 1; + const u32 outclkinv_mask = 1ul << outclkinv_pos; + + pregister = __g_module_variables[module_index].__g_pregister; + + read_value = pregister->CLKGEN[index << 1]; + read_value &= ~outclkinv_mask; + read_value |= out_clk_inv << outclkinv_pos; + + writel(read_value, &pregister->CLKGEN[index << 1]); +} + +int nx_disp_top_clkgen_get_clock_out_inv(u32 module_index, u32 index) +{ + register struct nx_disptop_clkgen_register_set *pregister; + const u32 outclkinv_pos = 1; + const u32 outclkinv_mask = 1ul << outclkinv_pos; + + pregister = __g_module_variables[module_index].__g_pregister; + + return (int)((pregister->CLKGEN[index << 1] & + outclkinv_mask) >> outclkinv_pos); +} + +int nx_disp_top_clkgen_set_input_inv(u32 module_index, + u32 index, int in_clk_inv) +{ + register struct nx_disptop_clkgen_register_set *pregister; + register u32 read_value; + const u32 inclkinv_pos = 4 + index; + const u32 inclkinv_mask = 1ul << inclkinv_pos; + + pregister = __g_module_variables[module_index].__g_pregister; + + read_value = pregister->clkenb; + read_value &= ~inclkinv_mask; + read_value |= in_clk_inv << inclkinv_pos; + + writel(read_value, &pregister->clkenb); + return true; +} + +int nx_disp_top_clkgen_get_input_inv(u32 module_index, u32 index) +{ + register struct nx_disptop_clkgen_register_set *pregister; + const u32 inclkinv_pos = 4 + index; + const u32 inclkinv_mask = 1ul << inclkinv_pos; + + pregister = __g_module_variables[module_index].__g_pregister; + + return (int)((pregister->clkenb & + inclkinv_mask) >> inclkinv_pos); +} + +void nx_disp_top_clkgen_set_clock_out_select(u32 module_index, u32 index, + int bbypass) +{ + register struct nx_disptop_clkgen_register_set *pregister; + register u32 read_value; + + pregister = __g_module_variables[module_index].__g_pregister; + + read_value = pregister->CLKGEN[index << 1]; + read_value = read_value & (~0x01); + read_value = read_value | bbypass; + + writel(read_value, &pregister->CLKGEN[index << 1]); +} diff --git a/drivers/video/nexell/soc/s5pxx18_soc_disptop_clk.h b/drivers/video/nexell/soc/s5pxx18_soc_disptop_clk.h new file mode 100644 index 0000000000..d55fef7730 --- /dev/null +++ b/drivers/video/nexell/soc/s5pxx18_soc_disptop_clk.h @@ -0,0 +1,59 @@ +/* SPDX-License-Identifier: GPL-2.0+ + * + * Copyright (C) 2016 Nexell Co., Ltd. + * + * Author: junghyun, kim <jhkim@nexell.co.kr> + */ + +#ifndef _S5PXX18_SOC_DISPTOP_CLK_H_ +#define _S5PXX18_SOC_DISPTOP_CLK_H_ + +#include "s5pxx18_soc_disptype.h" + +#define PHY_BASEADDR_DISPTOP_CLKGEN_LIST \ + { PHY_BASEADDR_DISPTOP_CLKGEN0_MODULE, \ + PHY_BASEADDR_DISPTOP_CLKGEN1_MODULE, \ + PHY_BASEADDR_DISPTOP_CLKGEN2_MODULE, \ + PHY_BASEADDR_DISPTOP_CLKGEN3_MODULE, \ + PHY_BASEADDR_DISPTOP_CLKGEN4_MODULE, \ + } + +struct nx_disptop_clkgen_register_set { + u32 clkenb; + u32 CLKGEN[4]; +}; + +int nx_disp_top_clkgen_initialize(void); +u32 nx_disp_top_clkgen_get_number_of_module(void); +u32 nx_disp_top_clkgen_get_physical_address(u32 module_index); +u32 nx_disp_top_clkgen_get_size_of_register_set(void); +void nx_disp_top_clkgen_set_base_address(u32 module_index, + void *base_address); +void *nx_disp_top_clkgen_get_base_address(u32 module_index); +void nx_disp_top_clkgen_set_clock_pclk_mode(u32 module_index, + enum nx_pclkmode mode); +enum nx_pclkmode nx_disp_top_clkgen_get_clock_pclk_mode(u32 module_index); +void nx_disp_top_clkgen_set_clock_source(u32 module_index, u32 index, + u32 clk_src); +u32 nx_disp_top_clkgen_get_clock_source(u32 module_index, u32 index); +void nx_disp_top_clkgen_set_clock_divisor(u32 module_index, u32 index, + u32 divisor); +u32 nx_disp_top_clkgen_get_clock_divisor(u32 module_index, u32 index); +void nx_disp_top_clkgen_set_clock_divisor_enable(u32 module_index, + int enable); +int nx_disp_top_clkgen_get_clock_divisor_enable(u32 module_index); +void nx_disp_top_clkgen_set_clock_bclk_mode(u32 module_index, + enum nx_bclkmode mode); +enum nx_bclkmode nx_disp_top_clkgen_get_clock_bclk_mode(u32 module_index); + +void nx_disp_top_clkgen_set_clock_out_inv(u32 module_index, u32 index, + int out_clk_inv); +int nx_disp_top_clkgen_get_clock_out_inv(u32 module_index, u32 index); +int nx_disp_top_clkgen_set_input_inv(u32 module_index, u32 index, + int out_clk_inv); +int nx_disp_top_clkgen_get_input_inv(u32 module_index, u32 index); + +void nx_disp_top_clkgen_set_clock_out_select(u32 module_index, u32 index, + int bbypass); + +#endif diff --git a/drivers/video/nexell/soc/s5pxx18_soc_disptype.h b/drivers/video/nexell/soc/s5pxx18_soc_disptype.h new file mode 100644 index 0000000000..b5df7a7344 --- /dev/null +++ b/drivers/video/nexell/soc/s5pxx18_soc_disptype.h @@ -0,0 +1,23 @@ +/* SPDX-License-Identifier: GPL-2.0+ + * + * Copyright (C) 2016 Nexell Co., Ltd. + * + * Author: junghyun, kim <jhkim@nexell.co.kr> + */ + +#ifndef _S5PXX18_SOC_DISP_TYPE_H_ +#define _S5PXX18_SOC_DISP_TYPE_H_ + +/* clock control types */ +enum nx_pclkmode { + nx_pclkmode_dynamic = 0UL, + nx_pclkmode_always = 1UL +}; + +enum nx_bclkmode { + nx_bclkmode_disable = 0UL, + nx_bclkmode_dynamic = 2UL, + nx_bclkmode_always = 3UL +}; + +#endif diff --git a/drivers/video/nexell/soc/s5pxx18_soc_dpc.c b/drivers/video/nexell/soc/s5pxx18_soc_dpc.c new file mode 100644 index 0000000000..fc15d6b4d0 --- /dev/null +++ b/drivers/video/nexell/soc/s5pxx18_soc_dpc.c @@ -0,0 +1,1569 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2016 Nexell Co., Ltd. + * + * Author: junghyun, kim <jhkim@nexell.co.kr> + */ + +#include <linux/types.h> +#include <linux/io.h> + +#include "s5pxx18_soc_dpc.h" + +static struct { + struct nx_dpc_register_set *pregister; +} __g_module_variables[NUMBER_OF_DPC_MODULE] = { { NULL,},}; + +int nx_dpc_initialize(void) +{ + static int binit; + u32 i; + + if (binit == 0) { + for (i = 0; i < NUMBER_OF_DPC_MODULE; i++) + __g_module_variables[i].pregister = NULL; + binit = 1; + } + return 1; +} + +u32 nx_dpc_get_number_of_module(void) +{ + return NUMBER_OF_DPC_MODULE; +} + +u32 nx_dpc_get_physical_address(u32 module_index) +{ + const u32 physical_addr[] = PHY_BASEADDR_DPC_LIST; + + return physical_addr[module_index]; +} + +void nx_dpc_set_base_address(u32 module_index, void *base_address) +{ + __g_module_variables[module_index].pregister = + (struct nx_dpc_register_set *)base_address; +} + +void *nx_dpc_get_base_address(u32 module_index) +{ + return (void *)__g_module_variables[module_index].pregister; +} + +void nx_dpc_set_interrupt_enable(u32 module_index, int32_t int_num, int enable) +{ + const u32 intenb_pos = 11; + const u32 intenb_mask = 1ul << intenb_pos; + const u32 intpend_pos = 10; + const u32 intpend_mask = 1ul << intpend_pos; + + register u32 regvalue; + register struct nx_dpc_register_set *pregister; + + pregister = __g_module_variables[module_index].pregister; + regvalue = pregister->dpcctrl0; + regvalue &= ~(intenb_mask | intpend_mask); + regvalue |= (u32)enable << intenb_pos; + + writel(regvalue, &pregister->dpcctrl0); +} + +int nx_dpc_get_interrupt_enable(u32 module_index, int32_t int_num) +{ + const u32 intenb_pos = 11; + const u32 intenb_mask = 1ul << intenb_pos; + + return (int)((__g_module_variables[module_index].pregister->dpcctrl0 & + intenb_mask) >> intenb_pos); +} + +void nx_dpc_set_interrupt_enable32(u32 module_index, u32 enable_flag) +{ + const u32 intenb_pos = 11; + const u32 intenb_mask = 1 << intenb_pos; + const u32 intpend_pos = 10; + const u32 intpend_mask = 1 << intpend_pos; + + register struct nx_dpc_register_set *pregister; + register u32 read_value; + + pregister = __g_module_variables[module_index].pregister; + read_value = pregister->dpcctrl0 & ~(intpend_mask | intenb_mask); + + writel((u32)(read_value | (enable_flag & 0x01) << intenb_pos), + &pregister->dpcctrl0); +} + +u32 nx_dpc_get_interrupt_enable32(u32 module_index) +{ + const u32 intenb_pos = 11; + const u32 intenb_mask = 1 << intenb_pos; + + return (u32)((__g_module_variables[module_index].pregister->dpcctrl0 & + intenb_mask) >> intenb_pos); +} + +int nx_dpc_get_interrupt_pending(u32 module_index, int32_t int_num) +{ + const u32 intpend_pos = 10; + const u32 intpend_mask = 1ul << intpend_pos; + + return (int)((__g_module_variables[module_index].pregister->dpcctrl0 & + intpend_mask) >> intpend_pos); +} + +u32 nx_dpc_get_interrupt_pending32(u32 module_index) +{ + const u32 intpend_pos = 10; + const u32 intpend_mask = 1 << intpend_pos; + + return (u32)((__g_module_variables[module_index].pregister->dpcctrl0 & + intpend_mask) >> intpend_pos); +} + +void nx_dpc_clear_interrupt_pending(u32 module_index, int32_t int_num) +{ + const u32 intpend_pos = 10; + register struct nx_dpc_register_set *pregister; + register u32 regvalue; + + pregister = __g_module_variables[module_index].pregister; + regvalue = pregister->dpcctrl0; + regvalue |= 1ul << intpend_pos; + + writel(regvalue, &pregister->dpcctrl0); +} + +void nx_dpc_clear_interrupt_pending32(u32 module_index, u32 pending_flag) +{ + const u32 intpend_pos = 10; + const u32 intpend_mask = 1 << intpend_pos; + register struct nx_dpc_register_set *pregister; + register u32 read_value; + + pregister = __g_module_variables[module_index].pregister; + read_value = pregister->dpcctrl0 & ~intpend_mask; + + writel((u32)(read_value | ((pending_flag & 0x01) << intpend_pos)), + &pregister->dpcctrl0); +} + +void nx_dpc_set_interrupt_enable_all(u32 module_index, int enable) +{ + const u32 intenb_pos = 11; + const u32 intenb_mask = 1ul << intenb_pos; + const u32 intpend_pos = 10; + const u32 intpend_mask = 1ul << intpend_pos; + register u32 regvalue; + register struct nx_dpc_register_set *pregister; + + pregister = __g_module_variables[module_index].pregister; + regvalue = pregister->dpcctrl0; + regvalue &= ~(intenb_mask | intpend_mask); + regvalue |= (u32)enable << intenb_pos; + + writel(regvalue, &pregister->dpcctrl0); +} + +int nx_dpc_get_interrupt_enable_all(u32 module_index) +{ + const u32 intenb_pos = 11; + const u32 intenb_mask = 1ul << intenb_pos; + + return (int)((__g_module_variables[module_index].pregister->dpcctrl0 & + intenb_mask) >> intenb_pos); +} + +int nx_dpc_get_interrupt_pending_all(u32 module_index) +{ + const u32 intpend_pos = 10; + const u32 intpend_mask = 1ul << intpend_pos; + + return (int)((__g_module_variables[module_index].pregister->dpcctrl0 & + intpend_mask) >> intpend_pos); +} + +void nx_dpc_clear_interrupt_pending_all(u32 module_index) +{ + const u32 intpend_pos = 10; + register struct nx_dpc_register_set *pregister; + register u32 regvalue; + + pregister = __g_module_variables[module_index].pregister; + regvalue = pregister->dpcctrl0; + regvalue |= 1ul << intpend_pos; + + writel(regvalue, &pregister->dpcctrl0); +} + +int32_t nx_dpc_get_interrupt_pending_number(u32 module_index) +{ + const u32 intenb_pos = 11; + const u32 intpend_pos = 10; + register struct nx_dpc_register_set *pregister; + register u32 pend; + + pregister = __g_module_variables[module_index].pregister; + pend = ((pregister->dpcctrl0 >> intenb_pos) && + (pregister->dpcctrl0 >> intpend_pos)); + + if (pend & 0x01) + return 0; + + return -1; +} + +void nx_dpc_set_clock_pclk_mode(u32 module_index, enum nx_pclkmode mode) +{ + const u32 pclkmode_pos = 3; + register u32 regvalue; + register struct nx_dpc_register_set *pregister; + u32 clkmode = 0; + + pregister = __g_module_variables[module_index].pregister; + switch (mode) { + case nx_pclkmode_dynamic: + clkmode = 0; + break; + case nx_pclkmode_always: + clkmode = 1; + break; + default: + break; + } + regvalue = pregister->dpcclkenb; + regvalue &= ~(1ul << pclkmode_pos); + regvalue |= (clkmode & 0x01) << pclkmode_pos; + + writel(regvalue, &pregister->dpcclkenb); +} + +enum nx_pclkmode nx_dpc_get_clock_pclk_mode(u32 module_index) +{ + const u32 pclkmode_pos = 3; + + if (__g_module_variables[module_index].pregister->dpcclkenb & + (1ul << pclkmode_pos)) { + return nx_pclkmode_always; + } + return nx_pclkmode_dynamic; +} + +void nx_dpc_set_clock_source(u32 module_index, u32 index, u32 clk_src) +{ + const u32 clksrcsel_pos = 2; + const u32 clksrcsel_mask = 0x07 << clksrcsel_pos; + register struct nx_dpc_register_set *pregister; + register u32 read_value; + + pregister = __g_module_variables[module_index].pregister; + read_value = pregister->dpcclkgen[index][0]; + read_value &= ~clksrcsel_mask; + read_value |= clk_src << clksrcsel_pos; + + writel(read_value, &pregister->dpcclkgen[index][0]); +} + +u32 nx_dpc_get_clock_source(u32 module_index, u32 index) +{ + const u32 clksrcsel_pos = 2; + const u32 clksrcsel_mask = 0x07 << clksrcsel_pos; + + return (__g_module_variables[module_index] + .pregister->dpcclkgen[index][0] & + clksrcsel_mask) >> clksrcsel_pos; +} + +void nx_dpc_set_clock_divisor(u32 module_index, u32 index, u32 divisor) +{ + const u32 clkdiv_pos = 5; + const u32 clkdiv_mask = ((1 << 8) - 1) << clkdiv_pos; + register struct nx_dpc_register_set *pregister; + register u32 read_value; + + pregister = __g_module_variables[module_index].pregister; + read_value = pregister->dpcclkgen[index][0]; + read_value &= ~clkdiv_mask; + read_value |= (divisor - 1) << clkdiv_pos; + + writel(read_value, &pregister->dpcclkgen[index][0]); +} + +u32 nx_dpc_get_clock_divisor(u32 module_index, u32 index) +{ + const u32 clkdiv_pos = 5; + const u32 clkdiv_mask = ((1 << 8) - 1) << clkdiv_pos; + + return ((__g_module_variables[module_index] + .pregister->dpcclkgen[index][0] & + clkdiv_mask) >> clkdiv_pos) + 1; +} + +void nx_dpc_set_clock_out_inv(u32 module_index, u32 index, int out_clk_inv) +{ + const u32 outclkinv_pos = 1; + const u32 outclkinv_mask = 1ul << outclkinv_pos; + register struct nx_dpc_register_set *pregister; + register u32 read_value; + + pregister = __g_module_variables[module_index].pregister; + read_value = pregister->dpcclkgen[index][0]; + read_value &= ~outclkinv_mask; + read_value |= out_clk_inv << outclkinv_pos; + + writel(read_value, &pregister->dpcclkgen[index][0]); +} + +int nx_dpc_get_clock_out_inv(u32 module_index, u32 index) +{ + const u32 outclkinv_pos = 1; + const u32 outclkinv_mask = 1ul << outclkinv_pos; + + return (int)((__g_module_variables[module_index] + .pregister->dpcclkgen[index][0] & + outclkinv_mask) >> outclkinv_pos); +} + +void nx_dpc_set_clock_out_select(u32 module_index, u32 index, int bbypass) +{ + const u32 outclksel_pos = 0; + const u32 outclksel_mask = 1ul << outclksel_pos; + register struct nx_dpc_register_set *pregister; + register u32 read_value; + + pregister = __g_module_variables[module_index].pregister; + read_value = pregister->dpcclkgen[index][0]; + read_value &= ~outclksel_mask; + if (bbypass == 0) + read_value |= outclksel_mask; + + writel(read_value, &pregister->dpcclkgen[index][0]); +} + +int nx_dpc_get_clock_out_select(u32 module_index, u32 index) +{ + const u32 outclksel_pos = 0; + const u32 outclksel_mask = 1ul << outclksel_pos; + + if (__g_module_variables[module_index].pregister->dpcclkgen[index][0] & + outclksel_mask) { + return 0; + } else { + return 1; + } +} + +void nx_dpc_set_clock_polarity(u32 module_index, int bpolarity) +{ + const u32 clkpol_pos = 2; + const u32 clkpol_mask = 1ul << clkpol_pos; + register struct nx_dpc_register_set *pregister; + register u32 read_value; + + pregister = __g_module_variables[module_index].pregister; + read_value = pregister->dpcctrl1; + read_value &= ~clkpol_mask; + if (bpolarity == 1) + read_value |= clkpol_mask; + + writel(read_value, &pregister->dpcctrl1); +} + +int nx_dpc_get_clock_polarity(u32 module_index) +{ + const u32 clkpol_pos = 2; + const u32 clkpol_mask = 1ul << clkpol_pos; + + if (__g_module_variables[module_index].pregister->dpcctrl1 & + clkpol_mask) { + return 1; + } else { + return 0; + } +} + +void nx_dpc_set_clock_out_enb(u32 module_index, u32 index, int out_clk_enb) +{ + const u32 outclkenb_pos = 15; + const u32 outclkenb_mask = 1ul << outclkenb_pos; + register struct nx_dpc_register_set *pregister; + register u32 read_value; + + pregister = __g_module_variables[module_index].pregister; + read_value = pregister->dpcclkgen[index][0]; + read_value &= ~outclkenb_mask; + + if (out_clk_enb == 1) + read_value |= outclkenb_mask; + + writel(read_value, &pregister->dpcclkgen[index][0]); +} + +int nx_dpc_get_clock_out_enb(u32 module_index, u32 index) +{ + const u32 outclkenb_pos = 15; + const u32 outclkenb_mask = 1ul << outclkenb_pos; + + if (__g_module_variables[module_index].pregister->dpcclkgen[index][0] & + outclkenb_mask) { + return 1; + } else { + return 0; + } +} + +void nx_dpc_set_clock_out_delay(u32 module_index, u32 index, u32 delay) +{ + const u32 outclkdelay_pos = 0; + const u32 outclkdelay_mask = 0x1f << outclkdelay_pos; + register struct nx_dpc_register_set *pregister; + register u32 read_value; + + pregister = __g_module_variables[module_index].pregister; + read_value = pregister->dpcclkgen[index][1]; + read_value &= ~outclkdelay_mask; + read_value |= (u32)delay << outclkdelay_pos; + + writel(read_value, &pregister->dpcclkgen[index][1]); +} + +u32 nx_dpc_get_clock_out_delay(u32 module_index, u32 index) +{ + register struct nx_dpc_register_set *pregister; + const u32 outclkdelay_pos = 0; + const u32 outclkdelay_mask = 0x1f << outclkdelay_pos; + + pregister = __g_module_variables[module_index].pregister; + + return (u32)((pregister->dpcclkgen[index][1] & outclkdelay_mask) >> + outclkdelay_pos); +} + +void nx_dpc_set_clock_divisor_enable(u32 module_index, int enable) +{ + const u32 clkgenenb_pos = 2; + const u32 clkgenenb_mask = 1ul << clkgenenb_pos; + register struct nx_dpc_register_set *pregister; + register u32 read_value; + + pregister = __g_module_variables[module_index].pregister; + read_value = pregister->dpcclkenb; + read_value &= ~clkgenenb_mask; + read_value |= (u32)enable << clkgenenb_pos; + + writel(read_value, &pregister->dpcclkenb); +} + +int nx_dpc_get_clock_divisor_enable(u32 module_index) +{ + const u32 clkgenenb_pos = 2; + const u32 clkgenenb_mask = 1ul << clkgenenb_pos; + + return (int)((__g_module_variables[module_index].pregister->dpcclkenb & + clkgenenb_mask) >> clkgenenb_pos); +} + +void nx_dpc_set_dpc_enable(u32 module_index, int benb) +{ + const u32 intpend_pos = 10; + const u32 intpend_mask = 1ul << intpend_pos; + const u32 dpcenb_pos = 15; + const u32 dpcenb_mask = 1ul << dpcenb_pos; + register struct nx_dpc_register_set *pregister; + register u32 read_value; + + pregister = __g_module_variables[module_index].pregister; + read_value = pregister->dpcctrl0; + read_value &= ~(intpend_mask | dpcenb_mask); + read_value |= (u32)benb << dpcenb_pos; + + writel(read_value, &pregister->dpcctrl0); +} + +int nx_dpc_get_dpc_enable(u32 module_index) +{ + const u32 dpcenb_pos = 15; + const u32 dpcenb_mask = 1ul << dpcenb_pos; + + return (int)((__g_module_variables[module_index].pregister->dpcctrl0 & + dpcenb_mask) >> dpcenb_pos); +} + +void nx_dpc_set_delay(u32 module_index, u32 delay_rgb_pvd, u32 delay_hs_cp1, + u32 delay_vs_fram, u32 delay_de_cp2) +{ + const u32 intpend_mask = 1u << 10; + const u32 delayrgb_pos = 4; + const u32 delayrgb_mask = 0xfu << delayrgb_pos; + register u32 temp; + const u32 delayde_pos = 0; + const u32 delayvs_pos = 8; + const u32 delayhs_pos = 0; + register struct nx_dpc_register_set *pregister; + + pregister = __g_module_variables[module_index].pregister; + temp = pregister->dpcctrl0; + temp &= (u32)~(intpend_mask | delayrgb_mask); + temp = (u32)(temp | (delay_rgb_pvd << delayrgb_pos)); + + writel(temp, &pregister->dpcctrl0); + + writel((u32)((delay_vs_fram << delayvs_pos) | + (delay_hs_cp1 << delayhs_pos)), &pregister->dpcdelay0); + + writel((u32)(delay_de_cp2 << delayde_pos), &pregister->dpcdelay1); +} + +void nx_dpc_get_delay(u32 module_index, u32 *pdelayrgb_pvd, u32 *pdelayhs_cp1, + u32 *pdelayvs_fram, u32 *pdelayde_cp2) +{ + const u32 delayrgb_pos = 4; + const u32 delayrgb_mask = 0xfu << delayrgb_pos; + const u32 delayde_pos = 0; + const u32 delayde_mask = 0x3fu << delayde_pos; + const u32 delayvs_pos = 8; + const u32 delayvs_mask = 0x3fu << delayvs_pos; + const u32 delayhs_pos = 0; + const u32 delayhs_mask = 0x3fu << delayhs_pos; + register u32 temp; + + temp = __g_module_variables[module_index].pregister->dpcctrl0; + if (pdelayrgb_pvd) + *pdelayrgb_pvd = (u32)((temp & delayrgb_mask) >> delayrgb_pos); + temp = __g_module_variables[module_index].pregister->dpcdelay0; + if (pdelayhs_cp1) + *pdelayhs_cp1 = (u32)((temp & delayhs_mask) >> delayhs_pos); + if (pdelayvs_fram) + *pdelayvs_fram = (u32)((temp & delayvs_mask) >> delayvs_pos); + temp = __g_module_variables[module_index].pregister->dpcdelay1; + if (pdelayde_cp2) + *pdelayde_cp2 = (u32)((temp & delayde_mask) >> delayde_pos); +} + +void nx_dpc_set_dither(u32 module_index, enum nx_dpc_dither dither_r, + enum nx_dpc_dither dither_g, enum nx_dpc_dither dither_b) +{ + const u32 dither_mask = 0x3fu; + const u32 rdither_pos = 0; + const u32 gdither_pos = 2; + const u32 bdither_pos = 4; + register u32 temp; + register struct nx_dpc_register_set *pregister; + + pregister = __g_module_variables[module_index].pregister; + temp = pregister->dpcctrl1; + temp &= (u32)~dither_mask; + temp = (u32)(temp | + ((dither_b << bdither_pos) | (dither_g << gdither_pos) | + (dither_r << rdither_pos))); + + writel(temp, &pregister->dpcctrl1); +} + +void nx_dpc_get_dither(u32 module_index, enum nx_dpc_dither *pditherr, + enum nx_dpc_dither *pditherg, + enum nx_dpc_dither *pditherb) +{ + const u32 rdither_pos = 0; + const u32 rdither_mask = 0x3u << rdither_pos; + const u32 gdither_pos = 2; + const u32 gdither_mask = 0x3u << gdither_pos; + const u32 bdither_pos = 4; + const u32 bdither_mask = 0x3u << bdither_pos; + register u32 temp; + + temp = __g_module_variables[module_index].pregister->dpcctrl1; + if (pditherr) + *pditherr = + (enum nx_dpc_dither)((temp & rdither_mask) >> rdither_pos); + if (pditherg) + *pditherg = + (enum nx_dpc_dither)((temp & gdither_mask) >> gdither_pos); + if (pditherb) + *pditherb = + (enum nx_dpc_dither)((temp & bdither_mask) >> bdither_pos); +} + +void nx_dpc_set_mode(u32 module_index, enum nx_dpc_format format, + int binterlace, int binvertfield, int brgbmode, + int bswaprb, enum nx_dpc_ycorder ycorder, int bclipyc, + int bembeddedsync, enum nx_dpc_padclk clock, + int binvertclock, int bdualview) +{ + const u32 polfield_pos = 2; + const u32 seavenb_pos = 8; + const u32 scanmode_pos = 9; + const u32 intpend_pos = 10; + const u32 rgbmode_pos = 12; + + const u32 dither_mask = 0x3f; + const u32 ycorder_pos = 6; + const u32 format_pos = 8; + const u32 ycrange_pos = 13; + const u32 swaprb_pos = 15; + + const u32 padclksel_pos = 0; + const u32 padclksel_mask = 3u << padclksel_pos; + const u32 lcdtype_pos = 7; + const u32 lcdtype_mask = 3u << lcdtype_pos; + register struct nx_dpc_register_set *pregister; + register u32 temp; + + pregister = __g_module_variables[module_index].pregister; + temp = pregister->dpcctrl0; + temp &= (u32)~(1u << intpend_pos); + if (binterlace) + temp |= (u32)(1u << scanmode_pos); + else + temp &= (u32)~(1u << scanmode_pos); + if (binvertfield) + temp |= (u32)(1u << polfield_pos); + else + temp &= (u32)~(1u << polfield_pos); + if (brgbmode) + temp |= (u32)(1u << rgbmode_pos); + else + temp &= (u32)~(1u << rgbmode_pos); + if (bembeddedsync) + temp |= (u32)(1u << seavenb_pos); + else + temp &= (u32)~(1u << seavenb_pos); + + writel(temp, &pregister->dpcctrl0); + temp = pregister->dpcctrl1; + temp &= (u32)dither_mask; + temp = (u32)(temp | (ycorder << ycorder_pos)); + if (format >= 16) { + register u32 temp1; + + temp1 = pregister->dpcctrl2; + temp1 = temp1 | (1 << 4); + writel(temp1, &pregister->dpcctrl2); + } else { + register u32 temp1; + + temp1 = pregister->dpcctrl2; + temp1 = temp1 & ~(1 << 4); + writel(temp1, &pregister->dpcctrl2); + } + temp = (u32)(temp | ((format & 0xf) << format_pos)); + if (!bclipyc) + temp |= (u32)(1u << ycrange_pos); + if (bswaprb) + temp |= (u32)(1u << swaprb_pos); + + writel(temp, &pregister->dpcctrl1); + temp = pregister->dpcctrl2; + temp &= (u32)~(padclksel_mask | lcdtype_mask); + temp = (u32)(temp | (clock << padclksel_pos)); + + writel(temp, &pregister->dpcctrl2); + + nx_dpc_set_clock_out_inv(module_index, 0, binvertclock); + nx_dpc_set_clock_out_inv(module_index, 1, binvertclock); +} + +void nx_dpc_get_mode(u32 module_index, enum nx_dpc_format *pformat, + int *pbinterlace, int *pbinvertfield, int *pbrgbmode, + int *pbswaprb, enum nx_dpc_ycorder *pycorder, + int *pbclipyc, int *pbembeddedsync, + enum nx_dpc_padclk *pclock, int *pbinvertclock, + int *pbdualview) +{ + const u32 polfield = 1u << 2; + const u32 seavenb = 1u << 8; + const u32 scanmode = 1u << 9; + const u32 rgbmode = 1u << 12; + + const u32 ycorder_pos = 6; + const u32 ycorder_mask = 0x3u << ycorder_pos; + const u32 format_pos = 8; + const u32 format_mask = 0xfu << format_pos; + const u32 ycrange = 1u << 13; + const u32 swaprb = 1u << 15; + + const u32 padclksel_pos = 0; + const u32 padclksel_mask = 3u << padclksel_pos; + const u32 lcdtype_pos = 7; + const u32 lcdtype_mask = 3u << lcdtype_pos; + register u32 temp; + + temp = __g_module_variables[module_index].pregister->dpcctrl0; + if (pbinterlace) + *pbinterlace = (temp & scanmode) ? 1 : 0; + + if (pbinvertfield) + *pbinvertfield = (temp & polfield) ? 1 : 0; + + if (pbrgbmode) + *pbrgbmode = (temp & rgbmode) ? 1 : 0; + + if (pbembeddedsync) + *pbembeddedsync = (temp & seavenb) ? 1 : 0; + + temp = __g_module_variables[module_index].pregister->dpcctrl1; + + if (pycorder) + *pycorder = + (enum nx_dpc_ycorder)((temp & ycorder_mask) >> ycorder_pos); + + if (pformat) + *pformat = + (enum nx_dpc_format)((temp & format_mask) >> format_pos); + if (pbclipyc) + *pbclipyc = (temp & ycrange) ? 0 : 1; + if (pbswaprb) + *pbswaprb = (temp & swaprb) ? 1 : 0; + + temp = __g_module_variables[module_index].pregister->dpcctrl2; + + if (pclock) + *pclock = + (enum nx_dpc_padclk)((temp & padclksel_mask) >> + padclksel_pos); + + if (pbdualview) + *pbdualview = (2 == ((temp & lcdtype_mask) >> lcdtype_pos)) + ? 1 : 0; + + if (pbinvertclock) + *pbinvertclock = nx_dpc_get_clock_out_inv(module_index, 1); +} + +void nx_dpc_set_hsync(u32 module_index, u32 avwidth, u32 hsw, u32 hfp, u32 hbp, + int binvhsync) +{ + const u32 intpend = 1u << 10; + const u32 polhsync = 1u << 0; + register u32 temp; + register struct nx_dpc_register_set *pregister; + + pregister = __g_module_variables[module_index].pregister; + + writel((u32)(hsw + hbp + avwidth + hfp - 1), &pregister->dpchtotal); + + writel((u32)(hsw - 1), &pregister->dpchswidth); + + writel((u32)(hsw + hbp - 1), &pregister->dpchastart); + + writel((u32)(hsw + hbp + avwidth - 1), &pregister->dpchaend); + temp = pregister->dpcctrl0; + temp &= ~intpend; + if (binvhsync) + temp |= (u32)polhsync; + else + temp &= (u32)~polhsync; + + writel(temp, &pregister->dpcctrl0); +} + +void nx_dpc_get_hsync(u32 module_index, u32 *pavwidth, u32 *phsw, u32 *phfp, + u32 *phbp, int *pbinvhsync) +{ + const u32 polhsync = 1u << 0; + u32 htotal, hsw, hab, hae; + u32 avw, hfp, hbp; + register struct nx_dpc_register_set *pregister; + + pregister = __g_module_variables[module_index].pregister; + htotal = (u32)pregister->dpchtotal + 1; + hsw = (u32)pregister->dpchswidth + 1; + hab = (u32)pregister->dpchastart + 1; + hae = (u32)pregister->dpchaend + 1; + hbp = hab - hsw; + avw = hae - hab; + hfp = htotal - hae; + if (pavwidth) + *pavwidth = avw; + if (phsw) + *phsw = hsw; + if (phfp) + *phfp = hfp; + if (phbp) + *phbp = hbp; + if (pbinvhsync) + *pbinvhsync = (pregister->dpcctrl0 & polhsync) ? 1 : 0; +} + +void nx_dpc_set_vsync(u32 module_index, u32 avheight, u32 vsw, u32 vfp, u32 vbp, + int binvvsync, u32 eavheight, u32 evsw, u32 evfp, + u32 evbp) +{ + const u32 intpend = 1u << 10; + const u32 polvsync = 1u << 1; + register u32 temp; + register struct nx_dpc_register_set *pregister; + + pregister = __g_module_variables[module_index].pregister; + + writel((u32)(vsw + vbp + avheight + vfp - 1), &pregister->dpcvtotal); + + writel((u32)(vsw - 1), &pregister->dpcvswidth); + + writel((u32)(vsw + vbp - 1), &pregister->dpcvastart); + + writel((u32)(vsw + vbp + avheight - 1), &pregister->dpcvaend); + + writel((u32)(evsw + evbp + eavheight + evfp - 1), + &pregister->dpcevtotal); + + writel((u32)(evsw - 1), &pregister->dpcevswidth); + + writel((u32)(evsw + evbp - 1), &pregister->dpcevastart); + + writel((u32)(evsw + evbp + eavheight - 1), &pregister->dpcevaend); + temp = pregister->dpcctrl0; + temp &= ~intpend; + if (binvvsync) + temp |= (u32)polvsync; + else + temp &= (u32)~polvsync; + + writel(temp, &pregister->dpcctrl0); +} + +void nx_dpc_get_vsync(u32 module_index, u32 *pavheight, u32 *pvsw, u32 *pvfp, + u32 *pvbp, int *pbinvvsync, u32 *peavheight, + u32 *pevsw, u32 *pevfp, u32 *pevbp) +{ + const u32 polvsync = 1u << 1; + u32 vtotal, vsw, vab, vae; + u32 avh, vfp, vbp; + register struct nx_dpc_register_set *pregister; + + pregister = __g_module_variables[module_index].pregister; + vtotal = (u32)pregister->dpcvtotal + 1; + vsw = (u32)pregister->dpcvswidth + 1; + vab = (u32)pregister->dpcvastart + 1; + vae = (u32)pregister->dpcvaend + 1; + vbp = vab - vsw; + avh = vae - vab; + vfp = vtotal - vae; + if (pavheight) + *pavheight = avh; + if (pvsw) + *pvsw = vsw; + if (pvfp) + *pvfp = vfp; + if (pvbp) + *pvbp = vbp; + vtotal = (u32)pregister->dpcevtotal + 1; + vsw = (u32)pregister->dpcevswidth + 1; + vab = (u32)pregister->dpcevastart + 1; + vae = (u32)pregister->dpcevaend + 1; + vbp = vab - vsw; + avh = vae - vab; + vfp = vtotal - vae; + if (peavheight) + *peavheight = avh; + if (pevsw) + *pevsw = vsw; + if (pevfp) + *pevfp = vfp; + if (pevbp) + *pevbp = vbp; + if (pbinvvsync) + *pbinvvsync = (pregister->dpcctrl0 & polvsync) ? 1 : 0; +} + +void nx_dpc_set_vsync_offset(u32 module_index, u32 vssoffset, u32 vseoffset, + u32 evssoffset, u32 evseoffset) +{ + register struct nx_dpc_register_set *pregister; + + pregister = __g_module_variables[module_index].pregister; + + writel((u32)vseoffset, &pregister->dpcvseoffset); + + writel((u32)vssoffset, &pregister->dpcvssoffset); + + writel((u32)evseoffset, &pregister->dpcevseoffset); + + writel((u32)evssoffset, &pregister->dpcevssoffset); +} + +void nx_dpc_get_vsync_offset(u32 module_index, u32 *pvssoffset, + u32 *pvseoffset, u32 *pevssoffset, + u32 *pevseoffset) +{ + register struct nx_dpc_register_set *pregister; + + pregister = __g_module_variables[module_index].pregister; + + if (pvseoffset) + *pvseoffset = (u32)pregister->dpcvseoffset; + + if (pvssoffset) + *pvssoffset = (u32)pregister->dpcvssoffset; + + if (pevseoffset) + *pevseoffset = (u32)pregister->dpcevseoffset; + + if (pevssoffset) + *pevssoffset = (u32)pregister->dpcevssoffset; +} + +void nx_dpc_set_horizontal_up_scaler(u32 module_index, int benb, + u32 sourcewidth, u32 destwidth) +{ + const u32 upscalel_pos = 8; + const u32 upscaleh_pos = 0; + const u32 upscaleh_mask = ((1 << 15) - 1) << upscaleh_pos; + const u32 upscalerenb_pos = 0; + register struct nx_dpc_register_set *pregister; + register u32 regvalue; + register u32 up_scale; + + pregister = __g_module_variables[module_index].pregister; + up_scale = ((sourcewidth - 1) * (1 << 11)) / (destwidth - 1); + regvalue = 0; + regvalue |= (((u32)benb << upscalerenb_pos) | + (up_scale & 0xff) << upscalel_pos); + + writel(regvalue, &pregister->dpcupscalecon0); + + writel((up_scale >> 0x08) & upscaleh_mask, &pregister->dpcupscalecon1); + + writel(sourcewidth - 1, &pregister->dpcupscalecon2); +} + +void nx_dpc_get_horizontal_up_scaler(u32 module_index, int *pbenb, + u32 *psourcewidth, u32 *pdestwidth) +{ + const u32 upscalerenb_pos = 0; + const u32 upscalerenb_mask = 1u << upscalerenb_pos; + register struct nx_dpc_register_set *pregister; + + u32 up_scale; + u32 destwidth, srcwidth; + + pregister = __g_module_variables[module_index].pregister; + up_scale = ((u32)(pregister->dpcupscalecon1 & 0x7fff) << 8) | + ((u32)(pregister->dpcupscalecon0 >> 8) & 0xff); + srcwidth = pregister->dpcupscalecon2; + destwidth = (srcwidth * (1 << 11)) / up_scale; + if (pbenb) + *pbenb = (pregister->dpcupscalecon0 & upscalerenb_mask); + if (psourcewidth) + *psourcewidth = srcwidth + 1; + if (pdestwidth) + *pdestwidth = destwidth + 1; +} + +void nx_dpc_set_sync(u32 module_index, enum syncgenmode sync_gen_mode, + u32 avwidth, u32 avheight, u32 hsw, u32 hfp, u32 hbp, + u32 vsw, u32 vfp, u32 vbp, enum polarity field_polarity, + enum polarity hsyncpolarity, enum polarity vsyncpolarity, + u32 even_vsw, u32 even_vfp, u32 even_vbp, u32 vsetpixel, + u32 vsclrpixel, u32 evenvsetpixel, u32 evenvsclrpixel) +{ + register struct nx_dpc_register_set *pregister; + u32 regvalue = 0; + + pregister = __g_module_variables[module_index].pregister; + + writel((u32)(hfp + hsw + hbp + avwidth - 1), &pregister->dpchtotal); + writel((u32)(hsw - 1), &pregister->dpchswidth); + writel((u32)(hsw + hbp - 1), &pregister->dpchastart); + writel((u32)(hsw + hbp + avwidth - 1), &pregister->dpchaend); + writel((u32)(vfp + vsw + vbp + avheight - 1), &pregister->dpcvtotal); + writel((u32)(vsw - 1), &pregister->dpcvswidth); + writel((u32)(vsw + vbp - 1), &pregister->dpcvastart); + writel((u32)(vsw + vbp + avheight - 1), &pregister->dpcvaend); + writel((u32)vsetpixel, &pregister->dpcvseoffset); + writel((u32)(hfp + hsw + hbp + avwidth - vsclrpixel - 1), + &pregister->dpcvssoffset); + writel((u32)evenvsetpixel, &pregister->dpcevseoffset); + writel((u32)(hfp + hsw + hbp + avwidth - evenvsclrpixel - 1), + &pregister->dpcevssoffset); + if (sync_gen_mode == 1) { + writel((u32)(even_vfp + even_vsw + even_vbp + avheight - 1), + &pregister->dpcevtotal); + writel((u32)(even_vsw - 1), &pregister->dpcevswidth); + writel((u32)(even_vsw + even_vbp - 1), + &pregister->dpcevastart); + writel((u32)(even_vsw + even_vbp + avheight - 1), + &pregister->dpcevaend); + } + regvalue = readl(&pregister->dpcctrl0) & 0xfff0ul; + regvalue |= (((u32)field_polarity << 2) | ((u32)vsyncpolarity << 1) | + ((u32)hsyncpolarity << 0)); + writel((u32)regvalue, &pregister->dpcctrl0); +} + +void nx_dpc_set_output_format(u32 module_index, enum outputformat output_format, + u8 output_video_config) +{ + const u32 format_table[] = { + (0 << 0), (1 << 0), (2 << 0), (3 << 0), (4 << 0), (5 << 0), + (6 << 0), (7 << 0), (8 << 0), (9 << 0), (0 << 0) | (1 << 7), + (1 << 0) | (1 << 7), (2 << 0) | (1 << 7), (3 << 0) | (1 << 7), + (4 << 0) | (1 << 7), (5 << 0) | (1 << 7), (6 << 0) | (1 << 7), + (7 << 0) | (1 << 7), (8 << 0) | (1 << 7), (9 << 0) | (1 << 7), + (10 << 0), (11 << 0), (12 << 0), (13 << 0), (14 << 0), (15 << 0) + }; + u32 regvalue; + u32 regvalue0; + register struct nx_dpc_register_set *pregister; + + pregister = __g_module_variables[module_index].pregister; + regvalue = readl(&pregister->dpcctrl1) & 0x30fful; + + regvalue |= (format_table[output_format] << 8); + writel((u32)regvalue, &pregister->dpcctrl1); + regvalue0 = (u32)(readl(&pregister->dpcctrl1) & 0xff3f); + regvalue0 = (u32)((output_video_config << 6) | regvalue0); + writel((u32)regvalue0, &pregister->dpcctrl1); +} + +void nx_dpc_set_quantization_mode(u32 module_index, enum qmode rgb2yc, + enum qmode yc2rgb) +{ + register struct nx_dpc_register_set *pregister; + u32 regvalue; + + pregister = __g_module_variables[module_index].pregister; + regvalue = readl(&pregister->dpcctrl1) & 0x8ffful; + regvalue |= ((u32)rgb2yc << 13) | ((u32)yc2rgb << 12); + writel((u32)regvalue, &pregister->dpcctrl1); +} + +void nx_dpc_set_enable(u32 module_index, int enable, int rgbmode, + int use_ntscsync, int use_analog_output, int seavenable) +{ + u32 regvalue; + register struct nx_dpc_register_set *pregister; + + pregister = __g_module_variables[module_index].pregister; + regvalue = readl(&pregister->dpcctrl0) & 0x0efful; + regvalue |= ((u32)enable << 15) | ((u32)use_ntscsync << 14) | + ((u32)seavenable << 8) | ((u32)use_analog_output << 13) | + ((u32)rgbmode << 12); + writel((u32)regvalue, &pregister->dpcctrl0); +} + +void nx_dpc_set_out_video_clk_select(u32 module_index, + enum outpadclksel out_pad_vclk_sel) +{ + register struct nx_dpc_register_set *pregister; + + pregister = __g_module_variables[module_index].pregister; + + writel((u32)((readl(&pregister->dpcctrl2)) | (out_pad_vclk_sel & 0x3)), + &pregister->dpcctrl2); +} + +void nx_dpc_set_reg_flush(u32 module_index) +{ + u32 reg; + register struct nx_dpc_register_set *pregister; + + pregister = __g_module_variables[module_index].pregister; + reg = readl(&pregister->dpcdataflush); + writel((u32)(reg | (1ul << 4)), &pregister->dpcdataflush); +} + +void nx_dpc_set_sramon(u32 module_index) +{ + u32 reg; + register struct nx_dpc_register_set *pregister; + + pregister = __g_module_variables[module_index].pregister; + reg = (u32)(readl(&pregister->dpcctrl2) & 0xf3ff); + writel((u32)(reg | (1ul << 10)), &pregister->dpcctrl2); + reg = (u32)(readl(&pregister->dpcctrl2) & 0xf7ff); + writel((u32)(reg | (1ul << 11)), &pregister->dpcctrl2); +} + +void nx_dpc_set_sync_lcdtype(u32 module_index, int stnlcd, int dual_view_enb, + int bit_widh, u8 cpcycle) +{ + u32 reg; + register struct nx_dpc_register_set *pregister; + + pregister = __g_module_variables[module_index].pregister; + + reg = (u32)(readl(&pregister->dpcctrl2) & 0xc0f); + writel((u32)(reg | (cpcycle << 12) | (bit_widh << 9) | + (dual_view_enb << 8) | (stnlcd << 7)), + &pregister->dpcctrl2); +} + +void nx_dpc_set_up_scale_control(u32 module_index, int up_scale_enb, + int filter_enb, u32 hscale, u16 source_width) +{ + register struct nx_dpc_register_set *pregister; + + pregister = __g_module_variables[module_index].pregister; + writel((u32)((hscale << 8) | ((u32)filter_enb << 1) | (up_scale_enb)), + &pregister->dpcupscalecon0); + writel((u32)(hscale >> 8), &pregister->dpcupscalecon1); + writel(source_width, &pregister->dpcupscalecon2); +} + +void nx_dpc_set_mputime(u32 module_index, u8 setup, u8 hold, u8 acc) +{ + register struct nx_dpc_register_set *pregister; + + pregister = __g_module_variables[module_index].pregister; + writel((u32)((setup << 8) | (hold & 0xff)), &pregister->dpcmputime0); + writel((u32)(acc), &pregister->dpcmputime1); +} + +void nx_dpc_set_index(u32 module_index, u32 index) +{ + u32 regvalue; + register struct nx_dpc_register_set *pregister; + + pregister = __g_module_variables[module_index].pregister; + writel((u32)(index & 0xffff), &pregister->dpcmpuwrdatal); + writel((u32)((index >> 16) & 0xff), &pregister->dpcmpuindex); + if (index == 0x22) { + regvalue = readl(&pregister->dpcctrl2); + writel((regvalue | 0x10), &pregister->dpcctrl2); + } +} + +void nx_dpc_set_data(u32 module_index, u32 data) +{ + register struct nx_dpc_register_set *pregister; + + pregister = __g_module_variables[module_index].pregister; + writel((u32)(data & 0xffff), &pregister->dpcmpuwrdatal); + writel((u32)((data >> 16) & 0xff), &pregister->dpcmpudatah); +} + +void nx_dpc_set_cmd_buffer_flush(u32 module_index) +{ + u32 reg; + register struct nx_dpc_register_set *pregister; + + pregister = __g_module_variables[module_index].pregister; + reg = readl(&pregister->dpcdataflush); + writel((u32)(reg | (1 << 1)), &pregister->dpcdataflush); +} + +void nx_dpc_set_cmd_buffer_clear(u32 module_index) +{ + u32 reg; + register struct nx_dpc_register_set *pregister; + + pregister = __g_module_variables[module_index].pregister; + reg = readl(&pregister->dpcdataflush); + writel((u32)(reg | (1 << 0)), &pregister->dpcdataflush); +} + +void nx_dpc_set_cmd_buffer_write(u32 module_index, u32 cmd_data) +{ + register struct nx_dpc_register_set *pregister; + + pregister = __g_module_variables[module_index].pregister; + writel((u32)(cmd_data & 0xffff), &pregister->dpccmdbufferdatal); + writel((u32)(cmd_data >> 16), &pregister->dpccmdbufferdatah); +} + +void nx_dpc_set(u32 module_index) +{ + u32 reg; + register struct nx_dpc_register_set *pregister; + + pregister = __g_module_variables[module_index].pregister; + reg = readl(&pregister->dpcpolctrl); + writel((u32)(reg | 0x1), &pregister->dpcpolctrl); +} + +u32 nx_dpc_get_data(u32 module_index) +{ + u32 reg = 0; + register struct nx_dpc_register_set *pregister; + + pregister = __g_module_variables[module_index].pregister; + reg = readl(&pregister->dpcmpudatah); + reg = (reg << 16) | readl(&pregister->dpcmpurdatal); + return reg; +} + +u32 nx_dpc_get_status(u32 module_index) +{ + u32 reg = 0; + register struct nx_dpc_register_set *pregister; + + pregister = __g_module_variables[module_index].pregister; + reg = readl(&pregister->dpcmpustatus); + reg = (reg << 16) | readl(&pregister->dpcmpurdatal); + return reg; +} + +void nx_dpc_rgbmask(u32 module_index, u32 rgbmask) +{ + register struct nx_dpc_register_set *pregister; + + pregister = __g_module_variables[module_index].pregister; + writel((rgbmask >> 0) & 0xffff, &pregister->dpcrgbmask[0]); + writel((rgbmask >> 16) & 0x00ff, &pregister->dpcrgbmask[1]); +} + +void nx_dpc_set_pad_location(u32 module_index, u32 index, u32 regvalue) +{ + register struct nx_dpc_register_set *pregister; + + pregister = __g_module_variables[module_index].pregister; + writel(regvalue, &pregister->dpcpadposition[index]); +} + +u32 nx_dpc_get_field_flag(u32 module_index) +{ + register struct nx_dpc_register_set *pregister; + u32 regvalue; + + pregister = __g_module_variables[module_index].pregister; + regvalue = readl(&pregister->dpcrgbshift); + + return (u32)((regvalue >> 5) & 0x01); +} + +void nx_dpc_set_enable_with_interlace(u32 module_index, int enable, int rgbmode, + int use_ntscsync, int use_analog_output, + int seavenable) +{ + u32 regvalue; + register struct nx_dpc_register_set *pregister; + + pregister = __g_module_variables[module_index].pregister; + regvalue = readl(&pregister->dpcctrl0) & 0x0eff; + regvalue = readl(&pregister->dpcctrl0) & 0x0eff; + regvalue |= ((u32)enable << 15) | ((u32)use_ntscsync << 14) | + ((u32)seavenable << 8) | ((u32)use_analog_output << 13) | + ((u32)rgbmode << 12); + + regvalue |= (1 << 9); + writel((u16)regvalue, &pregister->dpcctrl0); +} + +void nx_dpc_set_encoder_control_reg(u32 module_index, u32 param_a, u32 param_b, + u32 param_c) +{ + register struct nx_dpc_register_set *pregister; + + pregister = __g_module_variables[module_index].pregister; + writel(param_a, &pregister->ntsc_ecmda); + writel(param_b, &pregister->ntsc_ecmdb); + writel(param_c, &pregister->ntsc_ecmdc); +} + +void nx_dpc_set_encoder_shcphase_control(u32 module_index, u32 chroma_param) +{ + register struct nx_dpc_register_set *pregister; + + pregister = __g_module_variables[module_index].pregister; + writel(chroma_param, &pregister->ntsc_sch); +} + +void nx_dpc_set_encoder_timing_config_reg(u32 module_index, u32 icntl) +{ + register struct nx_dpc_register_set *pregister; + + pregister = __g_module_variables[module_index].pregister; + writel(icntl, &pregister->ntsc_icntl); +} + +void nx_dpc_set_encoder_dacoutput_select(u32 module_index, u8 dacsel0, + u8 dacsel1, u8 dacsel2, u8 dacsel3, + u8 dacsel4, u8 dacsel5) +{ + register struct nx_dpc_register_set *pregister; + + pregister = __g_module_variables[module_index].pregister; + writel(((dacsel1 & 0xf) << 4) | (dacsel0 & 0xf), + &pregister->ntsc_dacsel10); + writel(((dacsel3 & 0xf) << 4) | (dacsel2 & 0xf), + &pregister->ntsc_dacsel32); + writel(((dacsel5 & 0xf) << 4) | (dacsel4 & 0xf), + &pregister->ntsc_dacsel54); +} + +void nx_dpc_set_encoder_sync_location(u32 module_index, u16 hsoe, u16 hsob, + u16 vsob, u16 vsoe, u8 vsost, int novrst) +{ + register struct nx_dpc_register_set *pregister; + + pregister = __g_module_variables[module_index].pregister; + writel((u16)((((vsob & 0x100) >> 2) | ((hsob & 0x700) >> 5) | + (hsoe & 0x700) >> 8)), &pregister->ntsc_hsvso); + writel((u16)(hsoe & 0xff), &pregister->ntsc_hsoe); + writel((u16)(hsob & 0xff), &pregister->ntsc_hsob); + writel((u16)(vsob & 0xff), &pregister->ntsc_vsob); + writel((u16)(((vsost & 0x3) << 6) | (novrst << 5) | (vsoe & 0x1f)), + &pregister->ntsc_vsoe); +} + +void nx_dpc_set_encoder_dacpower_enable(u32 module_index, u8 dacpd) +{ + register struct nx_dpc_register_set *pregister; + + pregister = __g_module_variables[module_index].pregister; + writel(dacpd, &pregister->ntsc_dacpd); +} + +void nx_dpc_set_ycorder(u32 module_index, enum nx_dpc_ycorder ycorder) +{ + const u16 ycorder_pos = 6; + register struct nx_dpc_register_set *pregister; + u32 temp; + + pregister = __g_module_variables[module_index].pregister; + temp = pregister->dpcctrl1 & (~(0xf << ycorder_pos)); + temp = (u16)(temp | (ycorder << ycorder_pos)); + writel(temp, &pregister->dpcctrl1); +} + +void nx_dpc_set_luma_gain(u32 module_index, u32 luma_gain) +{ + register struct nx_dpc_register_set *pregister; + + pregister = __g_module_variables[module_index].pregister; + writel(luma_gain, &pregister->ntsc_cont); +} + +void nx_dpc_set_encenable(u32 module_index, int benb) +{ + const u16 encmode = 1u << 14; + const u16 encrst = 1u << 13; + const u16 intpend = 1u << 10; + register struct nx_dpc_register_set *pregister; + register u16 temp; + + pregister = __g_module_variables[module_index].pregister; + temp = readl(&pregister->dpcctrl0); + temp &= (u16)~intpend; + if (benb) + temp |= (u16)encrst; + else + temp &= (u16)~encrst; + writel((temp | encmode), &pregister->dpcctrl0); + writel(7, &pregister->ntsc_icntl); +} + +int nx_dpc_get_encenable(u32 module_index) +{ + const u16 encrst = 1u << 13; + register struct nx_dpc_register_set *pregister; + + pregister = __g_module_variables[module_index].pregister; + return (readl(&pregister->dpcctrl0) & encrst) ? 1 : 0; +} + +void nx_dpc_set_video_encoder_power_down(u32 module_index, int benb) +{ + const u16 pwdenc = 1u << 7; + register struct nx_dpc_register_set *pregister; + + pregister = __g_module_variables[module_index].pregister; + if (benb) { + writel(readl(&pregister->ntsc_ecmda) | (u16)pwdenc, + &pregister->ntsc_ecmda); + writel(0, &pregister->ntsc_dacsel10); + } else { + writel(1, &pregister->ntsc_dacsel10); + writel(readl(&pregister->ntsc_ecmda) & (u16)~pwdenc, + &pregister->ntsc_ecmda); + } +} + +int nx_dpc_get_video_encoder_power_down(u32 module_index) +{ + const u16 pwdenc = 1u << 7; + register struct nx_dpc_register_set *pregister; + + pregister = __g_module_variables[module_index].pregister; + return (readl(&pregister->ntsc_ecmda) & pwdenc) ? 1 : 0; +} + +void nx_dpc_set_video_encoder_mode(u32 module_index, enum nx_dpc_vbs vbs, + int bpedestal) +{ + register struct nx_dpc_register_set *pregister; + +#define phalt (1u << 0) +#define ifmt (1u << 1) +#define ped (1u << 3) +#define fscsel_ntsc (0u << 4) +#define fscsel_pal (1u << 4) +#define fscsel_palm (2u << 4) +#define fscsel_paln (3u << 4) +#define fdrst (1u << 6) +#define pwdenc (1u << 7) + register u16 temp; + static const u8 ntsc_ecmda_table[] = { + (u8)(fscsel_ntsc | fdrst), (u8)(ifmt | fscsel_ntsc), + (u8)(fscsel_pal), (u8)(fscsel_palm | phalt), + (u8)(ifmt | fscsel_paln | phalt), + (u8)(ifmt | fscsel_pal | phalt | fdrst), + (u8)(fscsel_pal | phalt), + (u8)(ifmt | fscsel_ntsc) + }; + pregister = __g_module_variables[module_index].pregister; + temp = readl(&pregister->ntsc_ecmda); + temp &= (u16)pwdenc; + temp = (u16)(temp | (u16)ntsc_ecmda_table[vbs]); + if (bpedestal) + temp |= (u16)ped; + writel(temp, &pregister->ntsc_ecmda); +#undef phalt +#undef ifmt +#undef ped +#undef fscsel_ntsc +#undef fscsel_pal +#undef fscsel_palm +#undef fscsel_paln +#undef fdrst +#undef pwdenc +} + +void nx_dpc_set_video_encoder_schlock_control(u32 module_index, int bfreerun) +{ + const u16 fdrst = 1u << 6; + register struct nx_dpc_register_set *pregister; + register u16 temp; + + pregister = __g_module_variables[module_index].pregister; + temp = readl(&pregister->ntsc_ecmda); + if (bfreerun) + temp |= (u16)fdrst; + else + temp &= (u16)~fdrst; + writel(temp, &pregister->ntsc_ecmda); +} + +int nx_dpc_get_video_encoder_schlock_control(u32 module_index) +{ + const u16 fdrst = 1u << 6; + register struct nx_dpc_register_set *pregister; + + pregister = __g_module_variables[module_index].pregister; + return (readl(&pregister->ntsc_ecmda) & fdrst) ? 1 : 0; +} + +void nx_dpc_set_video_encoder_bandwidth(u32 module_index, + enum nx_dpc_bandwidth luma, + enum nx_dpc_bandwidth chroma) +{ + const u16 ybw_pos = 0; + const u16 cbw_pos = 2; + register struct nx_dpc_register_set *pregister; + + pregister = __g_module_variables[module_index].pregister; + writel((u16)((chroma << cbw_pos) | (luma << ybw_pos)), + &pregister->ntsc_ecmdb); +} + +void nx_dpc_get_video_encoder_bandwidth(u32 module_index, + enum nx_dpc_bandwidth *pluma, + enum nx_dpc_bandwidth *pchroma) +{ + const u16 ybw_pos = 0; + const u16 ybw_mask = 3u << ybw_pos; + const u16 cbw_pos = 2; + const u16 cbw_mask = 3u << cbw_pos; + register struct nx_dpc_register_set *pregister; + register u16 temp; + + pregister = __g_module_variables[module_index].pregister; + temp = readl(&pregister->ntsc_ecmdb); + if (pluma) + *pluma = (enum nx_dpc_bandwidth)((temp & ybw_mask) >> ybw_pos); + if (pchroma) + *pchroma = + (enum nx_dpc_bandwidth)((temp & cbw_mask) >> cbw_pos); +} + +void nx_dpc_set_video_encoder_color_control(u32 module_index, s8 sch, + s8 hue, s8 sat, s8 crt, + s8 brt) +{ + register struct nx_dpc_register_set *pregister; + + pregister = __g_module_variables[module_index].pregister; + writel((u16)sch, &pregister->ntsc_sch); + writel((u16)hue, &pregister->ntsc_hue); + writel((u16)sat, &pregister->ntsc_sat); + writel((u16)crt, &pregister->ntsc_cont); + writel((u16)brt, &pregister->ntsc_bright); +} + +void nx_dpc_get_video_encoder_color_control(u32 module_index, s8 *psch, + s8 *phue, s8 *psat, + s8 *pcrt, s8 *pbrt) +{ + register struct nx_dpc_register_set *pregister; + + pregister = __g_module_variables[module_index].pregister; + if (psch) + *psch = (s8)readl(&pregister->ntsc_sch); + if (phue) + *phue = (s8)readl(&pregister->ntsc_hue); + if (psat) + *psat = (s8)readl(&pregister->ntsc_sat); + if (pcrt) + *pcrt = (s8)readl(&pregister->ntsc_cont); + if (pbrt) + *pbrt = (s8)readl(&pregister->ntsc_bright); +} + +void nx_dpc_set_video_encoder_fscadjust(u32 module_index, int16_t adjust) +{ + register struct nx_dpc_register_set *pregister; + + pregister = __g_module_variables[module_index].pregister; + writel((u16)(adjust >> 8), &pregister->ntsc_fsc_adjh); + writel((u16)(adjust & 0xff), &pregister->ntsc_fsc_adjl); +} + +u16 nx_dpc_get_video_encoder_fscadjust(u32 module_index) +{ + register u32 temp; + register struct nx_dpc_register_set *pregister; + + pregister = __g_module_variables[module_index].pregister; + temp = (u32)readl(&pregister->ntsc_fsc_adjh); + temp <<= 8; + temp |= (((u32)readl(&pregister->ntsc_fsc_adjl)) & 0xff); + return (u16)temp; +} + +void nx_dpc_set_video_encoder_timing(u32 module_index, u32 hsos, u32 hsoe, + u32 vsos, u32 vsoe) +{ + register struct nx_dpc_register_set *pregister; + + pregister = __g_module_variables[module_index].pregister; + hsos -= 1; + hsoe -= 1; + writel((u16)((((vsos >> 8) & 1u) << 6) | (((hsos >> 8) & 7u) << 3) | + (((hsoe >> 8) & 7u) << 0)), &pregister->ntsc_hsvso); + writel((u16)(hsos & 0xffu), &pregister->ntsc_hsob); + writel((u16)(hsoe & 0xffu), &pregister->ntsc_hsoe); + writel((u16)(vsos & 0xffu), &pregister->ntsc_vsob); + writel((u16)(vsoe & 0x1fu), &pregister->ntsc_vsoe); +} + +void nx_dpc_get_video_encoder_timing(u32 module_index, u32 *phsos, u32 *phsoe, + u32 *pvsos, u32 *pvsoe) +{ + register u16 hsvso; + register struct nx_dpc_register_set *pregister; + + pregister = __g_module_variables[module_index].pregister; + hsvso = readl(&pregister->ntsc_hsvso); + if (phsos) + *phsos = (u32)((((hsvso >> 3) & 7u) << 8) | + (readl(&pregister->ntsc_hsob) & 0xffu)) + 1; + if (phsoe) + *phsoe = (u32)((((hsvso >> 0) & 7u) << 8) | + (readl(&pregister->ntsc_hsoe) & 0xffu)) + 1; + if (pvsos) + *pvsos = (u32)((((hsvso >> 6) & 1u) << 8) | + (readl(&pregister->ntsc_vsob) & 0xffu)); + if (pvsoe) + *pvsoe = (u32)(readl(&pregister->ntsc_vsoe) & 0x1fu); +} diff --git a/drivers/video/nexell/soc/s5pxx18_soc_dpc.h b/drivers/video/nexell/soc/s5pxx18_soc_dpc.h new file mode 100644 index 0000000000..cfa53c3fdb --- /dev/null +++ b/drivers/video/nexell/soc/s5pxx18_soc_dpc.h @@ -0,0 +1,444 @@ +/* SPDX-License-Identifier: GPL-2.0+ + * + * Copyright (C) 2016 Nexell Co., Ltd. + * + * Author: junghyun, kim <jhkim@nexell.co.kr> + */ + +#ifndef _S5PXX18_SOC_DPC_H_ +#define _S5PXX18_SOC_DPC_H_ + +#include "s5pxx18_soc_disptype.h" + +#define IRQ_OFFSET 32 +#define IRQ_DPC_P (IRQ_OFFSET + 33) +#define IRQ_DPC_S (IRQ_OFFSET + 34) + +#define NUMBER_OF_DPC_MODULE 2 +#define PHY_BASEADDR_DPC0 0xC0102800 +#define PHY_BASEADDR_DPC1 0xC0102C00 + +#define PHY_BASEADDR_DPC_LIST \ + { PHY_BASEADDR_DPC0, PHY_BASEADDR_DPC1 } + +struct nx_dpc_register_set { + u32 ntsc_stata; + u32 ntsc_ecmda; + u32 ntsc_ecmdb; + u32 ntsc_glk; + u32 ntsc_sch; + u32 ntsc_hue; + u32 ntsc_sat; + u32 ntsc_cont; + u32 ntsc_bright; + u32 ntsc_fsc_adjh; + u32 ntsc_fsc_adjl; + u32 ntsc_ecmdc; + u32 ntsc_csdly; + u32 __ntsc_reserved_0_[3]; + u32 ntsc_dacsel10; + u32 ntsc_dacsel32; + u32 ntsc_dacsel54; + u32 ntsc_daclp; + u32 ntsc_dacpd; + u32 __ntsc_reserved_1_[(0x20 - 0x15)]; + u32 ntsc_icntl; + u32 ntsc_hvoffst; + u32 ntsc_hoffst; + u32 ntsc_voffset; + u32 ntsc_hsvso; + u32 ntsc_hsob; + u32 ntsc_hsoe; + u32 ntsc_vsob; + u32 ntsc_vsoe; + u32 __reserved[(0xf8 / 4) - 0x29]; + u32 dpchtotal; + u32 dpchswidth; + u32 dpchastart; + u32 dpchaend; + u32 dpcvtotal; + u32 dpcvswidth; + u32 dpcvastart; + u32 dpcvaend; + u32 dpcctrl0; + u32 dpcctrl1; + u32 dpcevtotal; + u32 dpcevswidth; + u32 dpcevastart; + u32 dpcevaend; + u32 dpcctrl2; + u32 dpcvseoffset; + u32 dpcvssoffset; + u32 dpcevseoffset; + u32 dpcevssoffset; + u32 dpcdelay0; + u32 dpcupscalecon0; + u32 dpcupscalecon1; + u32 dpcupscalecon2; + + u32 dpcrnumgencon0; + u32 dpcrnumgencon1; + u32 dpcrnumgencon2; + u32 dpcrndconformula_l; + u32 dpcrndconformula_h; + u32 dpcfdtaddr; + u32 dpcfrdithervalue; + u32 dpcfgdithervalue; + u32 dpcfbdithervalue; + u32 dpcdelay1; + u32 dpcmputime0; + u32 dpcmputime1; + u32 dpcmpuwrdatal; + u32 dpcmpuindex; + u32 dpcmpustatus; + u32 dpcmpudatah; + u32 dpcmpurdatal; + u32 dpcdummy12; + u32 dpccmdbufferdatal; + u32 dpccmdbufferdatah; + u32 dpcpolctrl; + u32 dpcpadposition[8]; + u32 dpcrgbmask[2]; + u32 dpcrgbshift; + u32 dpcdataflush; + u32 __reserved06[((0x3c0) - (2 * 0x0ec)) / 4]; + + u32 dpcclkenb; + u32 dpcclkgen[2][2]; +}; + +enum { + nx_dpc_int_vsync = 0 +}; + +enum nx_dpc_format { + nx_dpc_format_rgb555 = 0ul, + nx_dpc_format_rgb565 = 1ul, + nx_dpc_format_rgb666 = 2ul, + nx_dpc_format_rgb666b = 18ul, + nx_dpc_format_rgb888 = 3ul, + nx_dpc_format_mrgb555a = 4ul, + nx_dpc_format_mrgb555b = 5ul, + nx_dpc_format_mrgb565 = 6ul, + nx_dpc_format_mrgb666 = 7ul, + nx_dpc_format_mrgb888a = 8ul, + nx_dpc_format_mrgb888b = 9ul, + nx_dpc_format_ccir656 = 10ul, + nx_dpc_format_ccir601a = 12ul, + nx_dpc_format_ccir601b = 13ul, + nx_dpc_format_srgb888 = 14ul, + nx_dpc_format_srgbd8888 = 15ul, + nx_dpc_format_4096color = 1ul, + nx_dpc_format_16gray = 3ul +}; + +enum nx_dpc_ycorder { + nx_dpc_ycorder_cb_ycr_y = 0ul, + nx_dpc_ycorder_cr_ycb_y = 1ul, + nx_dpc_ycorder_ycbycr = 2ul, + nx_dpc_ycorder_ycrycb = 3ul +}; + +enum nx_dpc_padclk { + nx_dpc_padclk_vclk = 0ul, + nx_dpc_padclk_vclk2 = 1ul, + nx_dpc_padclk_vclk3 = 2ul +}; + +enum nx_dpc_dither { + nx_dpc_dither_bypass = 0ul, + nx_dpc_dither_4bit = 1ul, + nx_dpc_dither_5bit = 2ul, + nx_dpc_dither_6bit = 3ul +}; + +enum nx_dpc_vbs { + nx_dpc_vbs_ntsc_m = 0ul, + nx_dpc_vbs_ntsc_n = 1ul, + nx_dpc_vbs_ntsc_443 = 2ul, + nx_dpc_vbs_pal_m = 3ul, + nx_dpc_vbs_pal_n = 4ul, + nx_dpc_vbs_pal_bghi = 5ul, + nx_dpc_vbs_pseudo_pal = 6ul, + nx_dpc_vbs_pseudo_ntsc = 7ul +}; + +enum nx_dpc_bandwidth { + nx_dpc_bandwidth_low = 0ul, + nx_dpc_bandwidth_medium = 1ul, + nx_dpc_bandwidth_high = 2ul +}; + +int nx_dpc_initialize(void); +u32 nx_dpc_get_number_of_module(void); +u32 nx_dpc_get_physical_address(u32 module_index); +u32 nx_dpc_get_size_of_register_set(void); +void nx_dpc_set_base_address(u32 module_index, void *base_address); +void *nx_dpc_get_base_address(u32 module_index); +int nx_dpc_open_module(u32 module_index); +int nx_dpc_close_module(u32 module_index); +int nx_dpc_check_busy(u32 module_index); +int nx_dpc_can_power_down(u32 module_index); +int32_t nx_dpc_get_interrupt_number(u32 module_index); +void nx_dpc_set_interrupt_enable(u32 module_index, int32_t int_num, + int enable); +int nx_dpc_get_interrupt_enable(u32 module_index, int32_t int_num); +int nx_dpc_get_interrupt_pending(u32 module_index, int32_t int_num); +void nx_dpc_clear_interrupt_pending(u32 module_index, int32_t int_num); +void nx_dpc_set_interrupt_enable_all(u32 module_index, int enable); +int nx_dpc_get_interrupt_enable_all(u32 module_index); +int nx_dpc_get_interrupt_pending_all(u32 module_index); +void nx_dpc_clear_interrupt_pending_all(u32 module_index); +void nx_dpc_set_interrupt_enable32(u32 module_index, u32 enable_flag); +u32 nx_dpc_get_interrupt_enable32(u32 module_index); +u32 nx_dpc_get_interrupt_pending32(u32 module_index); +void nx_dpc_clear_interrupt_pending32(u32 module_index, + u32 pending_flag); +int32_t nx_dpc_get_interrupt_pending_number(u32 module_index); +void nx_dpc_set_clock_pclk_mode(u32 module_index, enum nx_pclkmode mode); +enum nx_pclkmode nx_dpc_get_clock_pclk_mode(u32 module_index); +void nx_dpc_set_clock_source(u32 module_index, u32 index, u32 clk_src); +u32 nx_dpc_get_clock_source(u32 module_index, u32 index); +void nx_dpc_set_clock_divisor(u32 module_index, u32 index, u32 divisor); +u32 nx_dpc_get_clock_divisor(u32 module_index, u32 index); +void nx_dpc_set_clock_out_inv(u32 module_index, u32 index, + int out_clk_inv); +int nx_dpc_get_clock_out_inv(u32 module_index, u32 index); +void nx_dpc_set_clock_out_select(u32 module_index, u32 index, + int bbypass); +int nx_dpc_get_clock_out_select(u32 module_index, u32 index); +void nx_dpc_set_clock_polarity(u32 module_index, int bpolarity); +int nx_dpc_get_clock_polarity(u32 module_index); +void nx_dpc_set_clock_out_enb(u32 module_index, u32 index, + int out_clk_enb); +int nx_dpc_get_clock_out_enb(u32 module_index, u32 index); +void nx_dpc_set_clock_out_delay(u32 module_index, u32 index, u32 delay); +u32 nx_dpc_get_clock_out_delay(u32 module_index, u32 index); +void nx_dpc_set_clock_divisor_enable(u32 module_index, int enable); +int nx_dpc_get_clock_divisor_enable(u32 module_index); + +void nx_dpc_set_dpc_enable(u32 module_index, int benb); +int nx_dpc_get_dpc_enable(u32 module_index); +void nx_dpc_set_delay(u32 module_index, u32 delay_rgb_pvd, + u32 delay_hs_cp1, u32 delay_vs_fram, + u32 delay_de_cp2); +void nx_dpc_get_delay(u32 module_index, u32 *pdelayrgb_pvd, + u32 *pdelayhs_cp1, u32 *pdelayvs_fram, + u32 *pdelayde_cp2); +void nx_dpc_set_dither(u32 module_index, enum nx_dpc_dither dither_r, + enum nx_dpc_dither dither_g, + enum nx_dpc_dither dither_b); +void nx_dpc_get_dither(u32 module_index, enum nx_dpc_dither *pditherr, + enum nx_dpc_dither *pditherg, + enum nx_dpc_dither *pditherb); +void nx_dpc_set_horizontal_up_scaler(u32 module_index, int benb, + u32 sourcewidth, u32 destwidth); +void nx_dpc_get_horizontal_up_scaler(u32 module_index, int *pbenb, + u32 *psourcewidth, + u32 *pdestwidth); + +void nx_dpc_set_mode(u32 module_index, enum nx_dpc_format format, + int binterlace, int binvertfield, int brgbmode, + int bswaprb, enum nx_dpc_ycorder ycorder, + int bclipyc, int bembeddedsync, + enum nx_dpc_padclk clock, int binvertclock, + int bdualview); +void nx_dpc_get_mode(u32 module_index, enum nx_dpc_format *pformat, + int *pbinterlace, int *pbinvertfield, + int *pbrgbmode, int *pbswaprb, + enum nx_dpc_ycorder *pycorder, int *pbclipyc, + int *pbembeddedsync, enum nx_dpc_padclk *pclock, + int *pbinvertclock, int *pbdualview); +void nx_dpc_set_hsync(u32 module_index, u32 avwidth, u32 hsw, u32 hfp, + u32 hbp, int binvhsync); +void nx_dpc_get_hsync(u32 module_index, u32 *pavwidth, u32 *phsw, + u32 *phfp, u32 *phbp, int *pbinvhsync); +void nx_dpc_set_vsync(u32 module_index, u32 avheight, u32 vsw, u32 vfp, + u32 vbp, int binvvsync, u32 eavheight, u32 evsw, + u32 evfp, u32 evbp); +void nx_dpc_get_vsync(u32 module_index, u32 *pavheight, u32 *pvsw, + u32 *pvfp, u32 *pvbp, int *pbinvvsync, + u32 *peavheight, u32 *pevsw, u32 *pevfp, + u32 *pevbp); +void nx_dpc_set_vsync_offset(u32 module_index, u32 vssoffset, + u32 vseoffset, u32 evssoffset, + u32 evseoffset); +void nx_dpc_get_vsync_offset(u32 module_index, u32 *pvssoffset, + u32 *pvseoffset, u32 *pevssoffset, + u32 *pevseoffset); + +u32 nx_dpc_enable_pad_tft(u32 module_index, u32 mode_index); +u32 nx_dpc_enable_pad_i80(u32 module_index, u32 mode_index); + +enum syncgenmode { + progressive = 0, + interlace = 1 +}; + +enum polarity { + polarity_activehigh = 0, + polarity_activelow = 1 +}; + +enum outputformat { + outputformat_rgb555 = 0, + outputformat_rgb565 = 1, + outputformat_rgb666 = 2, + outputformat_rgb888 = 3, + outputformat_mrgb555a = 4, + outputformat_mrgb555b = 5, + outputformat_mrgb565 = 6, + outputformat_mrgb666 = 7, + outputformat_mrgb888a = 8, + outputformat_mrgb888b = 9, + outputformat_bgr555 = 10, + outputformat_bgr565 = 11, + outputformat_bgr666 = 12, + outputformat_bgr888 = 13, + outputformat_mbgr555a = 14, + outputformat_mbgr555b = 15, + outputformat_mbgr565 = 16, + outputformat_mbgr666 = 17, + outputformat_mbgr888a = 18, + outputformat_mbgr888b = 19, + outputformat_ccir656 = 20, + outputformat_ccir601_8 = 21, + outputformat_ccir601_16a = 22, + outputformat_ccir601_16b = 23, + outputformat_srgb888 = 24, + outputformat_srgbd8888 = 25 +}; + +enum outpadclksel { + padvclk = 0, + padvclk2 = 1, + padvclk3 = 2 +}; + +enum qmode { + qmode_220 = 0, + qmode_256 = 1 +}; + +void nx_dpc_set_sync(u32 module_index, enum syncgenmode sync_gen_mode, + u32 avwidth, u32 avheight, u32 hsw, u32 hfp, + u32 hbp, u32 vsw, u32 vfp, u32 vbp, + enum polarity field_polarity, + enum polarity hsyncpolarity, + enum polarity vsyncpolarity, u32 even_vsw, + u32 even_vfp, u32 even_vbp, u32 vsetpixel, + u32 vsclrpixel, u32 evenvsetpixel, + u32 evenvsclrpixel); +void nx_dpc_set_output_format(u32 module_index, + enum outputformat output_format, + u8 output_video_config); +void nx_dpc_set_quantization_mode(u32 module_index, enum qmode rgb2yc, + enum qmode yc2rgb); +void nx_dpc_set_enable(u32 module_index, int enable, int rgbmode, + int use_ntscsync, int use_analog_output, + int seavenable); +void nx_dpc_set_enable_with_interlace(u32 module_index, int enable, + int rgbmode, int use_ntscsync, + int use_analog_output, + int seavenable); +void nx_dpc_set_enable_with_interlace(u32 module_index, int enable, + int rgbmode, int use_ntscsync, + int use_analog_output, + int seavenable); +void nx_dpc_set_out_video_clk_select(u32 module_index, + enum outpadclksel out_pad_vclk_sel); +void nx_dpc_set_reg_flush(u32 module_index); +void nx_dpc_set_sramon(u32 module_index); +void nx_dpc_set_sync_lcdtype(u32 module_index, int stnlcd, + int dual_view_enb, int bit_widh, + u8 cpcycle); +void nx_dpc_set_up_scale_control(u32 module_index, int up_scale_enb, + int filter_enb, u32 hscale, + u16 source_width); + +void nx_dpc_set_mputime(u32 module_index, u8 setup, u8 hold, u8 acc); +void nx_dpc_set_index(u32 module_index, u32 index); +void nx_dpc_set_data(u32 module_index, u32 data); +void nx_dpc_set_cmd_buffer_flush(u32 module_index); +void nx_dpc_set_cmd_buffer_clear(u32 module_index); +void nx_dpc_set_cmd_buffer_write(u32 module_index, u32 cmd_data); +void nx_dpc_set(u32 module_index); +u32 nx_dpc_get_data(u32 module_index); +u32 nx_dpc_get_status(u32 module_index); +void nx_dpc_rgbmask(u32 module_index, u32 rgbmask); +void nx_dpc_set_pad_location(u32 module_index, u32 index, u32 regvalue); +u32 nx_dpc_get_field_flag(u32 module_index); + +void nx_dpc_set_sync_v(u32 module_index, u32 avheight, u32 vsw, u32 vfp, + u32 vbp); + +int nx_dpc_init_reg_test(u32 module_index); +void nx_dpc_set_encoder_control_reg(u32 module_index, u32 param_a, + u32 param_b, u32 param_c); +void nx_dpc_set_encoder_shcphase_control(u32 module_index, + u32 chroma_param); +void nx_dpc_set_encoder_timing_config_reg(u32 module_index, u32 inctl); +void nx_dpc_set_encoder_dacoutput_select(u32 module_index, u8 dacsel0, + u8 dacsel1, u8 dacsel2, + u8 dacsel3, u8 dacsel4, + u8 dacsel5); +void nx_dpc_set_encoder_sync_location(u32 module_index, u16 hsoe, + u16 hsob, u16 vsob, u16 vsoe, + u8 vsost, int novrst); +void nx_dpc_set_encoder_dacpower_enable(u32 module_index, u8 dacpd); +void nx_dpc_set_ycorder(u32 module_index, enum nx_dpc_ycorder ycorder); +void nx_dpc_set_luma_gain(u32 module_index, u32 luma_gain); + +void nx_dpc_set_secondary_dpcsync(u32 module_index, int benb); +int nx_dpc_get_secondary_dpcsync(u32 module_index); +void nx_dpc_set_encenable(u32 module_index, int benb); +int nx_dpc_get_encenable(u32 module_index); +void nx_dpc_set_video_encoder_power_down(u32 module_index, int benb); +int nx_dpc_get_video_encoder_power_down(u32 module_index); +void nx_dpc_set_video_encoder_mode(u32 module_index, enum nx_dpc_vbs vbs, + int bpedestal); +void nx_dpc_set_video_encoder_schlock_control(u32 module_index, + int bfreerun); +int nx_dpc_get_video_encoder_schlock_control(u32 module_index); +void nx_dpc_set_video_encoder_bandwidth(u32 module_index, + enum nx_dpc_bandwidth luma, + enum nx_dpc_bandwidth chroma); +void nx_dpc_get_video_encoder_bandwidth(u32 module_index, + enum nx_dpc_bandwidth *pluma, + enum nx_dpc_bandwidth *pchroma); +void nx_dpc_set_video_encoder_color_control(u32 module_index, s8 sch, + s8 hue, s8 sat, + s8 crt, s8 brt); +void nx_dpc_get_video_encoder_color_control(u32 module_index, + s8 *psch, s8 *phue, + s8 *psat, s8 *pcrt, + s8 *pbrt); +void nx_dpc_set_video_encoder_fscadjust(u32 module_index, + int16_t adjust); +u16 nx_dpc_get_video_encoder_fscadjust(u32 module_index); +void nx_dpc_set_video_encoder_timing(u32 module_index, u32 hsos, + u32 hsoe, u32 vsos, u32 vsoe); +void nx_dpc_get_video_encoder_timing(u32 module_index, u32 *phsos, + u32 *phsoe, u32 *pvsos, + u32 *pvsoe); +void nx_dpc_set_sync_v(u32 module_index, u32 avheight, u32 vsw, u32 vfp, + u32 vbp); + +int nx_dpc_init_reg_test(u32 module_index); +void nx_dpc_set_encoder_control_reg(u32 module_index, u32 param_a, + u32 param_b, u32 param_c); +void nx_dpc_set_encoder_shcphase_control(u32 module_index, + u32 chroma_param); +void nx_dpc_set_encoder_timing_config_reg(u32 module_index, u32 inctl); +void nx_dpc_set_encoder_dacoutput_select(u32 module_index, u8 dacsel0, + u8 dacsel1, u8 dacsel2, + u8 dacsel3, u8 dacsel4, + u8 dacsel5); +void nx_dpc_set_encoder_sync_location(u32 module_index, u16 hsoe, + u16 hsob, u16 vsob, u16 vsoe, + u8 vsost, int novrst); +void nx_dpc_set_encoder_dacpower_enable(u32 module_index, u8 dacpd); +void nx_dpc_set_ycorder(u32 module_index, enum nx_dpc_ycorder ycorder); +void nx_dpc_set_luma_gain(u32 module_index, u32 luma_gain); + +#endif diff --git a/drivers/video/nexell/soc/s5pxx18_soc_hdmi.c b/drivers/video/nexell/soc/s5pxx18_soc_hdmi.c new file mode 100644 index 0000000000..7b8be7e2b5 --- /dev/null +++ b/drivers/video/nexell/soc/s5pxx18_soc_hdmi.c @@ -0,0 +1,50 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2016 Nexell Co., Ltd. + * + * Author: junghyun, kim <jhkim@nexell.co.kr> + */ + +#include <linux/types.h> +#include <linux/io.h> + +#include "s5pxx18_soc_hdmi.h" + +static u32 *hdmi_base_addr; + +u32 nx_hdmi_get_reg(u32 module_index, u32 offset) +{ + u32 *reg_addr; + u32 regvalue; + + reg_addr = hdmi_base_addr + (offset / sizeof(u32)); + regvalue = readl((u32 *)reg_addr); + + return regvalue; +} + +void nx_hdmi_set_reg(u32 module_index, u32 offset, u32 regvalue) +{ + s64 offset_new = (s64)((int32_t)offset); + u32 *reg_addr; + + reg_addr = hdmi_base_addr + (offset_new / sizeof(u32)); + writel(regvalue, (u32 *)reg_addr); +} + +void nx_hdmi_set_base_address(u32 module_index, void *base_address) +{ + hdmi_base_addr = (u32 *)base_address; +} + +void *nx_hdmi_get_base_address(u32 module_index) +{ + return (u32 *)hdmi_base_addr; +} + +u32 nx_hdmi_get_physical_address(u32 module_index) +{ + const u32 physical_addr[] = PHY_BASEADDR_HDMI_LIST; + + return physical_addr[module_index]; +} diff --git a/drivers/video/nexell/soc/s5pxx18_soc_hdmi.h b/drivers/video/nexell/soc/s5pxx18_soc_hdmi.h new file mode 100644 index 0000000000..a4c5ab5e59 --- /dev/null +++ b/drivers/video/nexell/soc/s5pxx18_soc_hdmi.h @@ -0,0 +1,488 @@ +/* SPDX-License-Identifier: GPL-2.0+ + * + * Copyright (C) 2016 Nexell Co., Ltd. + * + * Author: junghyun, kim <jhkim@nexell.co.kr> + */ + +#ifndef _S5PXX18_SOC_HDMI_H_ +#define _S5PXX18_SOC_HDMI_H_ + +#include "s5pxx18_soc_disptop.h" + +#define PHY_BASEADDR_HDMI_PHY_MODULE 0xc00f0000 +#define PHY_BASEADDR_HDMI_LIST \ + { PHY_BASEADDR_HDMI_MODULE } + +#define HDMI_LINK_INTC_CON_0 (HDMI_ADDR_OFFSET + 0x00000000) +#define HDMI_LINK_INTC_FLAG_0 (HDMI_ADDR_OFFSET + 0x00000004) +#define HDMI_LINK_AESKEY_VALID (HDMI_ADDR_OFFSET + 0x00000008) +#define HDMI_LINK_HPD (HDMI_ADDR_OFFSET + 0x0000000C) +#define HDMI_LINK_INTC_CON_1 (HDMI_ADDR_OFFSET + 0x00000010) +#define HDMI_LINK_INTC_FLAG_1 (HDMI_ADDR_OFFSET + 0x00000014) +#define HDMI_LINK_PHY_STATUS_0 (HDMI_ADDR_OFFSET + 0x00000020) +#define HDMI_LINK_PHY_STATUS_CMU (HDMI_ADDR_OFFSET + 0x00000024) +#define HDMI_LINK_PHY_STATUS_PLL (HDMI_ADDR_OFFSET + 0x00000028) +#define HDMI_LINK_PHY_CON_0 (HDMI_ADDR_OFFSET + 0x00000030) +#define HDMI_LINK_HPD_CTRL (HDMI_ADDR_OFFSET + 0x00000040) +#define HDMI_LINK_HPD_STATUS (HDMI_ADDR_OFFSET + 0x00000044) +#define HDMI_LINK_HPD_TH_x (HDMI_ADDR_OFFSET + 0x00000050) + +#define HDMI_LINK_HDMI_CON_0 (HDMI_ADDR_OFFSET + 0x00010000) +#define HDMI_LINK_HDMI_CON_1 (HDMI_ADDR_OFFSET + 0x00010004) +#define HDMI_LINK_HDMI_CON_2 (HDMI_ADDR_OFFSET + 0x00010008) +#define HDMI_LINK_STATUS (HDMI_ADDR_OFFSET + 0x00010010) +#define HDMI_LINK_STATUS_EN (HDMI_ADDR_OFFSET + 0x00010020) + +#define HDMI_LINK_HDCP_SHA1_REN0 (HDMI_ADDR_OFFSET + 0x00010024) +#define HDMI_LINK_HDCP_SHA1_REN1 (HDMI_ADDR_OFFSET + 0x00010028) + +#define HDMI_LINK_MODE_SEL (HDMI_ADDR_OFFSET + 0x00010040) +#define HDMI_LINK_ENC_EN (HDMI_ADDR_OFFSET + 0x00010044) +#define HDMI_LINK_HDMI_YMAX (HDMI_ADDR_OFFSET + 0x00010060) +#define HDMI_LINK_HDMI_YMIN (HDMI_ADDR_OFFSET + 0x00010064) +#define HDMI_LINK_HDMI_CMAX (HDMI_ADDR_OFFSET + 0x00010068) +#define HDMI_LINK_HDMI_CMIN (HDMI_ADDR_OFFSET + 0x0001006C) +#define HDMI_LINK_H_BLANK_0 (HDMI_ADDR_OFFSET + 0x000100A0) +#define HDMI_LINK_H_BLANK_1 (HDMI_ADDR_OFFSET + 0x000100A4) +#define HDMI_LINK_V2_BLANK_0 (HDMI_ADDR_OFFSET + 0x000100B0) +#define HDMI_LINK_V2_BLANK_1 (HDMI_ADDR_OFFSET + 0x000100B4) +#define HDMI_LINK_V1_BLANK_0 (HDMI_ADDR_OFFSET + 0x000100B8) +#define HDMI_LINK_V1_BLANK_1 (HDMI_ADDR_OFFSET + 0x000100BC) +#define HDMI_LINK_V_LINE_0 (HDMI_ADDR_OFFSET + 0x000100C0) +#define HDMI_LINK_V_LINE_1 (HDMI_ADDR_OFFSET + 0x000100C4) +#define HDMI_LINK_H_LINE_0 (HDMI_ADDR_OFFSET + 0x000100C8) +#define HDMI_LINK_H_LINE_1 (HDMI_ADDR_OFFSET + 0x000100CC) +#define HDMI_LINK_HSYNC_POL (HDMI_ADDR_OFFSET + 0x000100E0) +#define HDMI_LINK_VSYNC_POL (HDMI_ADDR_OFFSET + 0x000100E4) +#define HDMI_LINK_INT_PRO_MODE (HDMI_ADDR_OFFSET + 0x000100E8) +#define HDMI_LINK_SEND_START_0 (HDMI_ADDR_OFFSET + 0x000100F0) +#define HDMI_LINK_SEND_START_1 (HDMI_ADDR_OFFSET + 0x000100F4) +#define HDMI_LINK_SEND_END_0 (HDMI_ADDR_OFFSET + 0x00010100) +#define HDMI_LINK_SEND_END_1 (HDMI_ADDR_OFFSET + 0x00010104) +#define HDMI_LINK_SEND_END_2 (HDMI_ADDR_OFFSET + 0x00010108) +#define HDMI_LINK_V_BLANK_F0_0 (HDMI_ADDR_OFFSET + 0x00010110) +#define HDMI_LINK_V_BLANK_F0_1 (HDMI_ADDR_OFFSET + 0x00010114) +#define HDMI_LINK_V_BLANK_F1_0 (HDMI_ADDR_OFFSET + 0x00010118) +#define HDMI_LINK_V_BLANK_F1_1 (HDMI_ADDR_OFFSET + 0x0001011C) +#define HDMI_LINK_H_SYNC_START_0 (HDMI_ADDR_OFFSET + 0x00010120) +#define HDMI_LINK_H_SYNC_START_1 (HDMI_ADDR_OFFSET + 0x00010124) +#define HDMI_LINK_H_SYNC_END_0 (HDMI_ADDR_OFFSET + 0x00010128) +#define HDMI_LINK_H_SYNC_END_1 (HDMI_ADDR_OFFSET + 0x0001012C) +#define HDMI_LINK_V_SYNC_LINE_BEF_2_0 (HDMI_ADDR_OFFSET + 0x00010130) +#define HDMI_LINK_V_SYNC_LINE_BEF_2_1 (HDMI_ADDR_OFFSET + 0x00010134) +#define HDMI_LINK_V_SYNC_LINE_BEF_1_0 (HDMI_ADDR_OFFSET + 0x00010138) +#define HDMI_LINK_V_SYNC_LINE_BEF_1_1 (HDMI_ADDR_OFFSET + 0x0001013C) +#define HDMI_LINK_V_SYNC_LINE_AFT_2_0 (HDMI_ADDR_OFFSET + 0x00010140) +#define HDMI_LINK_V_SYNC_LINE_AFT_2_1 (HDMI_ADDR_OFFSET + 0x00010144) +#define HDMI_LINK_V_SYNC_LINE_AFT_1_0 (HDMI_ADDR_OFFSET + 0x00010148) +#define HDMI_LINK_V_SYNC_LINE_AFT_1_1 (HDMI_ADDR_OFFSET + 0x0001014C) +#define HDMI_LINK_V_SYNC_LINE_AFT_PXL_2_0 (HDMI_ADDR_OFFSET + 0x00010150) +#define HDMI_LINK_V_SYNC_LINE_AFT_PXL_2_1 (HDMI_ADDR_OFFSET + 0x00010154) +#define HDMI_LINK_V_SYNC_LINE_AFT_PXL_1_0 (HDMI_ADDR_OFFSET + 0x00010158) +#define HDMI_LINK_V_SYNC_LINE_AFT_PXL_1_1 (HDMI_ADDR_OFFSET + 0x0001015C) +#define HDMI_LINK_V_BLANK_F2_0 (HDMI_ADDR_OFFSET + 0x00010160) +#define HDMI_LINK_V_BLANK_F2_1 (HDMI_ADDR_OFFSET + 0x00010164) +#define HDMI_LINK_V_BLANK_F3_0 (HDMI_ADDR_OFFSET + 0x00010168) +#define HDMI_LINK_V_BLANK_F3_1 (HDMI_ADDR_OFFSET + 0x0001016C) +#define HDMI_LINK_V_BLANK_F4_0 (HDMI_ADDR_OFFSET + 0x00010170) +#define HDMI_LINK_V_BLANK_F4_1 (HDMI_ADDR_OFFSET + 0x00010174) +#define HDMI_LINK_V_BLANK_F5_0 (HDMI_ADDR_OFFSET + 0x00010178) +#define HDMI_LINK_V_BLANK_F5_1 (HDMI_ADDR_OFFSET + 0x0001017C) +#define HDMI_LINK_V_SYNC_LINE_AFT_3_0 (HDMI_ADDR_OFFSET + 0x00010180) +#define HDMI_LINK_V_SYNC_LINE_AFT_3_1 (HDMI_ADDR_OFFSET + 0x00010184) +#define HDMI_LINK_V_SYNC_LINE_AFT_4_0 (HDMI_ADDR_OFFSET + 0x00010188) +#define HDMI_LINK_V_SYNC_LINE_AFT_4_1 (HDMI_ADDR_OFFSET + 0x0001018C) +#define HDMI_LINK_V_SYNC_LINE_AFT_5_0 (HDMI_ADDR_OFFSET + 0x00010190) +#define HDMI_LINK_V_SYNC_LINE_AFT_5_1 (HDMI_ADDR_OFFSET + 0x00010194) +#define HDMI_LINK_V_SYNC_LINE_AFT_6_0 (HDMI_ADDR_OFFSET + 0x00010198) +#define HDMI_LINK_V_SYNC_LINE_AFT_6_1 (HDMI_ADDR_OFFSET + 0x0001019C) +#define HDMI_LINK_V_SYNC_LINE_AFT_PXL_3_0 (HDMI_ADDR_OFFSET + 0x000101A0) +#define HDMI_LINK_V_SYNC_LINE_AFT_PXL_3_1 (HDMI_ADDR_OFFSET + 0x000101A4) +#define HDMI_LINK_V_SYNC_LINE_AFT_PXL_4_0 (HDMI_ADDR_OFFSET + 0x000101A8) +#define HDMI_LINK_V_SYNC_LINE_AFT_PXL_4_1 (HDMI_ADDR_OFFSET + 0x000101AC) +#define HDMI_LINK_V_SYNC_LINE_AFT_PXL_5_0 (HDMI_ADDR_OFFSET + 0x000101B0) +#define HDMI_LINK_V_SYNC_LINE_AFT_PXL_5_1 (HDMI_ADDR_OFFSET + 0x000101B4) +#define HDMI_LINK_V_SYNC_LINE_AFT_PXL_6_0 (HDMI_ADDR_OFFSET + 0x000101B8) +#define HDMI_LINK_V_SYNC_LINE_AFT_PXL_6_1 (HDMI_ADDR_OFFSET + 0x000101BC) +#define HDMI_LINK_VACT_SPACE1_0 (HDMI_ADDR_OFFSET + 0x000101C0) +#define HDMI_LINK_VACT_SPACE1_1 (HDMI_ADDR_OFFSET + 0x000101C4) +#define HDMI_LINK_VACT_SPACE2_0 (HDMI_ADDR_OFFSET + 0x000101C8) +#define HDMI_LINK_VACT_SPACE2_1 (HDMI_ADDR_OFFSET + 0x000101CC) +#define HDMI_LINK_VACT_SPACE3_0 (HDMI_ADDR_OFFSET + 0x000101D0) +#define HDMI_LINK_VACT_SPACE3_1 (HDMI_ADDR_OFFSET + 0x000101D4) +#define HDMI_LINK_VACT_SPACE4_0 (HDMI_ADDR_OFFSET + 0x000101D8) +#define HDMI_LINK_VACT_SPACE4_1 (HDMI_ADDR_OFFSET + 0x000101DC) +#define HDMI_LINK_VACT_SPACE5_0 (HDMI_ADDR_OFFSET + 0x000101E0) +#define HDMI_LINK_VACT_SPACE5_1 (HDMI_ADDR_OFFSET + 0x000101E4) +#define HDMI_LINK_VACT_SPACE6_0 (HDMI_ADDR_OFFSET + 0x000101E8) +#define HDMI_LINK_VACT_SPACE6_1 (HDMI_ADDR_OFFSET + 0x000101EC) + +#define HDMI_LINK_CSC_MUX (HDMI_ADDR_OFFSET + 0x000101F0) +#define HDMI_LINK_SYNC_GEN_MUX (HDMI_ADDR_OFFSET + 0x000101F4) + +#define HDMI_LINK_GCP_CON (HDMI_ADDR_OFFSET + 0x00010200) +#define HDMI_LINK_GCP_BYTE1 (HDMI_ADDR_OFFSET + 0x00010210) +#define HDMI_LINK_GCP_BYTE2 (HDMI_ADDR_OFFSET + 0x00010214) +#define HDMI_LINK_GCP_BYTE3 (HDMI_ADDR_OFFSET + 0x00010218) +#define HDMI_LINK_ASP_CON (HDMI_ADDR_OFFSET + 0x00010300) +#define HDMI_LINK_ASP_SP_FLAT (HDMI_ADDR_OFFSET + 0x00010304) +#define HDMI_LINK_ASP_CHCFG0 (HDMI_ADDR_OFFSET + 0x00010310) +#define HDMI_LINK_ASP_CHCFG1 (HDMI_ADDR_OFFSET + 0x00010314) +#define HDMI_LINK_ASP_CHCFG2 (HDMI_ADDR_OFFSET + 0x00010318) +#define HDMI_LINK_ASP_CHCFG3 (HDMI_ADDR_OFFSET + 0x0001031C) +#define HDMI_LINK_ACR_CON (HDMI_ADDR_OFFSET + 0x00010400) +#define HDMI_LINK_ACR_MCTS0 (HDMI_ADDR_OFFSET + 0x00010410) +#define HDMI_LINK_ACR_MCTS1 (HDMI_ADDR_OFFSET + 0x00010414) +#define HDMI_LINK_ACR_MCTS2 (HDMI_ADDR_OFFSET + 0x00010418) +#define HDMI_LINK_ACR_N0 (HDMI_ADDR_OFFSET + 0x00010430) +#define HDMI_LINK_ACR_N1 (HDMI_ADDR_OFFSET + 0x00010434) +#define HDMI_LINK_ACR_N2 (HDMI_ADDR_OFFSET + 0x00010438) +#define HDMI_LINK_ACP_CON (HDMI_ADDR_OFFSET + 0x00010500) +#define HDMI_LINK_ACP_TYPE (HDMI_ADDR_OFFSET + 0x00010514) +#define HDMI_LINK_ACP_DATAX (HDMI_ADDR_OFFSET + 0x00010520) +#define HDMI_LINK_ISRC_CON (HDMI_ADDR_OFFSET + 0x00010600) +#define HDMI_LINK_ISRC1_HEADER1 (HDMI_ADDR_OFFSET + 0x00010614) +#define HDMI_LINK_ISRC1_DATAX (HDMI_ADDR_OFFSET + 0x00010620) +#define HDMI_LINK_ISRC2_DATAX (HDMI_ADDR_OFFSET + 0x000106A0) +#define HDMI_LINK_AVI_CON (HDMI_ADDR_OFFSET + 0x00010700) +#define HDMI_LINK_AVI_HEADER0 (HDMI_ADDR_OFFSET + 0x00010710) +#define HDMI_LINK_AVI_HEADER1 (HDMI_ADDR_OFFSET + 0x00010714) +#define HDMI_LINK_AVI_HEADER2 (HDMI_ADDR_OFFSET + 0x00010718) +#define HDMI_LINK_AVI_CHECK_SUM (HDMI_ADDR_OFFSET + 0x0001071C) +#define HDMI_LINK_AVI_BYTEX (HDMI_ADDR_OFFSET + 0x00010720) +#define HDMI_LINK_AVI_BYTE00 (HDMI_ADDR_OFFSET + 0x00010720) +#define HDMI_LINK_AVI_BYTE01 (HDMI_ADDR_OFFSET + 0x00010724) +#define HDMI_LINK_AVI_BYTE02 (HDMI_ADDR_OFFSET + 0x00010728) +#define HDMI_LINK_AVI_BYTE03 (HDMI_ADDR_OFFSET + 0x0001073C) +#define HDMI_LINK_AVI_BYTE04 (HDMI_ADDR_OFFSET + 0x00010730) +#define HDMI_LINK_AVI_BYTE05 (HDMI_ADDR_OFFSET + 0x00010734) +#define HDMI_LINK_AVI_BYTE06 (HDMI_ADDR_OFFSET + 0x00010738) +#define HDMI_LINK_AVI_BYTE07 (HDMI_ADDR_OFFSET + 0x0001074C) +#define HDMI_LINK_AVI_BYTE08 (HDMI_ADDR_OFFSET + 0x00010740) +#define HDMI_LINK_AVI_BYTE09 (HDMI_ADDR_OFFSET + 0x00010744) +#define HDMI_LINK_AVI_BYTE10 (HDMI_ADDR_OFFSET + 0x00010748) +#define HDMI_LINK_AVI_BYTE11 (HDMI_ADDR_OFFSET + 0x0001074C) +#define HDMI_LINK_AVI_BYTE12 (HDMI_ADDR_OFFSET + 0x00010750) +#define HDMI_LINK_AUI_CON (HDMI_ADDR_OFFSET + 0x00010800) +#define HDMI_LINK_AUI_HEADER0 (HDMI_ADDR_OFFSET + 0x00010810) +#define HDMI_LINK_AUI_HEADER1 (HDMI_ADDR_OFFSET + 0x00010814) +#define HDMI_LINK_AUI_HEADER2 (HDMI_ADDR_OFFSET + 0x00010818) +#define HDMI_LINK_AUI_CHECK_SUM (HDMI_ADDR_OFFSET + 0x0001081C) +#define HDMI_LINK_AUI_BYTEX (HDMI_ADDR_OFFSET + 0x00010820) +#define HDMI_LINK_MPG_CON (HDMI_ADDR_OFFSET + 0x00010900) +#define HDMI_LINK_MPG_CHECK_SUM (HDMI_ADDR_OFFSET + 0x0001091C) +#define HDMI_LINK_MPG_DATAX (HDMI_ADDR_OFFSET + 0x00010920) +#define HDMI_LINK_SPD_CON (HDMI_ADDR_OFFSET + 0x00010A00) +#define HDMI_LINK_SPD_HEADER0 (HDMI_ADDR_OFFSET + 0x00010A10) +#define HDMI_LINK_SPD_HEADER1 (HDMI_ADDR_OFFSET + 0x00010A14) +#define HDMI_LINK_SPD_HEADER2 (HDMI_ADDR_OFFSET + 0x00010A18) +#define HDMI_LINK_SPD_DATAX (HDMI_ADDR_OFFSET + 0x00010A20) +#define HDMI_LINK_GAMUT_CON (HDMI_ADDR_OFFSET + 0x00010B00) +#define HDMI_LINK_GAMUT_HEADER0 (HDMI_ADDR_OFFSET + 0x00010B10) +#define HDMI_LINK_GAMUT_HEADER1 (HDMI_ADDR_OFFSET + 0x00010B14) +#define HDMI_LINK_GAMUT_HEADER2 (HDMI_ADDR_OFFSET + 0x00010B18) +#define HDMI_LINK_GAMUT_METADATAX (HDMI_ADDR_OFFSET + 0x00010B20) +#define HDMI_LINK_VSI_CON (HDMI_ADDR_OFFSET + 0x00010C00) +#define HDMI_LINK_VSI_HEADER0 (HDMI_ADDR_OFFSET + 0x00010C10) +#define HDMI_LINK_VSI_HEADER1 (HDMI_ADDR_OFFSET + 0x00010C14) +#define HDMI_LINK_VSI_HEADER2 (HDMI_ADDR_OFFSET + 0x00010C18) +#define HDMI_LINK_VSI_DATAX (HDMI_ADDR_OFFSET + 0x00010C20) +#define HDMI_LINK_VSI_DATA00 (HDMI_ADDR_OFFSET + 0x00010C20) +#define HDMI_LINK_VSI_DATA01 (HDMI_ADDR_OFFSET + 0x00010C24) +#define HDMI_LINK_VSI_DATA02 (HDMI_ADDR_OFFSET + 0x00010C28) +#define HDMI_LINK_VSI_DATA03 (HDMI_ADDR_OFFSET + 0x00010C2C) +#define HDMI_LINK_VSI_DATA04 (HDMI_ADDR_OFFSET + 0x00010C30) +#define HDMI_LINK_VSI_DATA05 (HDMI_ADDR_OFFSET + 0x00010C34) +#define HDMI_LINK_VSI_DATA06 (HDMI_ADDR_OFFSET + 0x00010C38) +#define HDMI_LINK_VSI_DATA07 (HDMI_ADDR_OFFSET + 0x00010C3C) +#define HDMI_LINK_VSI_DATA08 (HDMI_ADDR_OFFSET + 0x00010C40) +#define HDMI_LINK_VSI_DATA09 (HDMI_ADDR_OFFSET + 0x00010C44) +#define HDMI_LINK_VSI_DATA10 (HDMI_ADDR_OFFSET + 0x00010C48) +#define HDMI_LINK_VSI_DATA11 (HDMI_ADDR_OFFSET + 0x00010c4c) +#define HDMI_LINK_VSI_DATA12 (HDMI_ADDR_OFFSET + 0x00010C50) +#define HDMI_LINK_VSI_DATA13 (HDMI_ADDR_OFFSET + 0x00010C54) +#define HDMI_LINK_VSI_DATA14 (HDMI_ADDR_OFFSET + 0x00010C58) +#define HDMI_LINK_VSI_DATA15 (HDMI_ADDR_OFFSET + 0x00010C5c) +#define HDMI_LINK_VSI_DATA16 (HDMI_ADDR_OFFSET + 0x00010C60) +#define HDMI_LINK_VSI_DATA17 (HDMI_ADDR_OFFSET + 0x00010C64) +#define HDMI_LINK_VSI_DATA18 (HDMI_ADDR_OFFSET + 0x00010C68) +#define HDMI_LINK_VSI_DATA19 (HDMI_ADDR_OFFSET + 0x00010C6c) +#define HDMI_LINK_VSI_DATA20 (HDMI_ADDR_OFFSET + 0x00010C70) +#define HDMI_LINK_VSI_DATA21 (HDMI_ADDR_OFFSET + 0x00010c74) +#define HDMI_LINK_VSI_DATA22 (HDMI_ADDR_OFFSET + 0x00010C78) +#define HDMI_LINK_VSI_DATA23 (HDMI_ADDR_OFFSET + 0x00010C7c) +#define HDMI_LINK_VSI_DATA24 (HDMI_ADDR_OFFSET + 0x00010C80) +#define HDMI_LINK_VSI_DATA25 (HDMI_ADDR_OFFSET + 0x00010C84) +#define HDMI_LINK_VSI_DATA26 (HDMI_ADDR_OFFSET + 0x00010C88) +#define HDMI_LINK_VSI_DATA27 (HDMI_ADDR_OFFSET + 0x00010C8C) +#define HDMI_LINK_DC_CONTROL (HDMI_ADDR_OFFSET + 0x00010D00) +#define HDMI_LINK_VIDEO_PATTERN_GEN (HDMI_ADDR_OFFSET + 0x00010D04) +#define HDMI_LINK_AN_SEED_SEL (HDMI_ADDR_OFFSET + 0x00010E48) +#define HDMI_LINK_AN_SEED_0 (HDMI_ADDR_OFFSET + 0x00010E58) +#define HDMI_LINK_AN_SEED_1 (HDMI_ADDR_OFFSET + 0x00010E5C) +#define HDMI_LINK_AN_SEED_2 (HDMI_ADDR_OFFSET + 0x00010E60) +#define HDMI_LINK_AN_SEED_3 (HDMI_ADDR_OFFSET + 0x00010E64) +#define HDMI_LINK_HDCP_SHA1_X (HDMI_ADDR_OFFSET + 0x00017000) + +#define HDMI_LINK_HDCP_SHA1_0_0 (HDMI_LINK_HDCP_SHA1_x + 0x00) +#define HDMI_LINK_HDCP_SHA1_0_1 (HDMI_LINK_HDCP_SHA1_0_0 + 0x04) +#define HDMI_LINK_HDCP_SHA1_0_2 (HDMI_LINK_HDCP_SHA1_0_0 + 0x08) +#define HDMI_LINK_HDCP_SHA1_0_3 (HDMI_LINK_HDCP_SHA1_0_0 + 0x0C) +#define HDMI_LINK_HDCP_SHA1_1_0 (HDMI_LINK_HDCP_SHA1_x + 0x10) +#define HDMI_LINK_HDCP_SHA1_1_1 (HDMI_LINK_HDCP_SHA1_1_0 + 0x04) +#define HDMI_LINK_HDCP_SHA1_1_2 (HDMI_LINK_HDCP_SHA1_1_0 + 0x08) +#define HDMI_LINK_HDCP_SHA1_1_3 (HDMI_LINK_HDCP_SHA1_1_0 + 0x0C) +#define HDMI_LINK_HDCP_SHA1_2_0 (HDMI_LINK_HDCP_SHA1_x + 0x20) +#define HDMI_LINK_HDCP_SHA1_2_1 (HDMI_LINK_HDCP_SHA1_2_0 + 0x04) +#define HDMI_LINK_HDCP_SHA1_2_2 (HDMI_LINK_HDCP_SHA1_2_0 + 0x08) +#define HDMI_LINK_HDCP_SHA1_2_3 (HDMI_LINK_HDCP_SHA1_2_0 + 0x0C) +#define HDMI_LINK_HDCP_SHA1_3_0 (HDMI_LINK_HDCP_SHA1_x + 0x30) +#define HDMI_LINK_HDCP_SHA1_3_1 (HDMI_LINK_HDCP_SHA1_3_0 + 0x04) +#define HDMI_LINK_HDCP_SHA1_3_2 (HDMI_LINK_HDCP_SHA1_3_0 + 0x08) +#define HDMI_LINK_HDCP_SHA1_3_3 (HDMI_LINK_HDCP_SHA1_3_0 + 0x0C) +#define HDMI_LINK_HDCP_SHA1_4_0 (HDMI_LINK_HDCP_SHA1_x + 0x40) +#define HDMI_LINK_HDCP_SHA1_4_1 (HDMI_LINK_HDCP_SHA1_4_0 + 0x04) +#define HDMI_LINK_HDCP_SHA1_4_2 (HDMI_LINK_HDCP_SHA1_4_0 + 0x08) +#define HDMI_LINK_HDCP_SHA1_4_3 (HDMI_LINK_HDCP_SHA1_4_0 + 0x0C) + +#define HDMI_LINK_HDCP_KSV_LIST_X (HDMI_ADDR_OFFSET + 0x00017050) + +#define HDMI_LINK_HDCP_KSV_0_0 (HDMI_LINK_HDCP_KSV_LIST_X + 0x00) +#define HDMI_LINK_HDCP_KSV_0_1 (HDMI_LINK_HDCP_KSV_LIST_X + 0x04) +#define HDMI_LINK_HDCP_KSV_0_2 (HDMI_LINK_HDCP_KSV_LIST_X + 0x08) +#define HDMI_LINK_HDCP_KSV_0_3 (HDMI_LINK_HDCP_KSV_LIST_X + 0x0C) +#define HDMI_LINK_HDCP_KSV_1_0 (HDMI_LINK_HDCP_KSV_LIST_X + 0x10) +#define HDMI_LINK_HDCP_KSV_1_1 (HDMI_LINK_HDCP_KSV_LIST_X + 0x14) + +#define HDMI_LINK_HDCP_KSV_LIST_0_0 (HDMI_LINK_HDCP_KSV_LIST_X + 0x00) +#define HDMI_LINK_HDCP_KSV_LIST_0_1 (HDMI_LINK_HDCP_KSV_LIST_X + 0x04) +#define HDMI_LINK_HDCP_KSV_LIST_0_2 (HDMI_LINK_HDCP_KSV_LIST_X + 0x08) +#define HDMI_LINK_HDCP_KSV_LIST_0_3 (HDMI_LINK_HDCP_KSV_LIST_X + 0x0C) +#define HDMI_LINK_HDCP_KSV_LIST_1_0 (HDMI_LINK_HDCP_KSV_LIST_X + 0x10) +#define HDMI_LINK_HDCP_KSV_LIST_1_1 (HDMI_LINK_HDCP_KSV_LIST_X + 0x14) + +#define HDMI_LINK_HDCP_KSV_LIST_CON (HDMI_ADDR_OFFSET + 0x00017064) +#define HDMI_LINK_HDCP_SHA_RESULT (HDMI_ADDR_OFFSET + 0x00017070) +#define HDMI_LINK_HDCP_CTRL1 (HDMI_ADDR_OFFSET + 0x00017080) +#define HDMI_LINK_HDCP_CTRL2 (HDMI_ADDR_OFFSET + 0x00017084) +#define HDMI_LINK_HDCP_CHECK_RESULT (HDMI_ADDR_OFFSET + 0x00017090) +#define HDMI_LINK_HDCP_BKSV_X (HDMI_ADDR_OFFSET + 0x000170A0) + +#define HDMI_LINK_HDCP_BKSV0_0 (HDMI_ADDR_OFFSET + 0x000170A0) +#define HDMI_LINK_HDCP_BKSV0_1 (HDMI_ADDR_OFFSET + 0x000170A4) +#define HDMI_LINK_HDCP_BKSV0_2 (HDMI_ADDR_OFFSET + 0x000170A8) +#define HDMI_LINK_HDCP_BKSV0_3 (HDMI_ADDR_OFFSET + 0x000170AC) +#define HDMI_LINK_HDCP_BKSV1 (HDMI_ADDR_OFFSET + 0x000170B0) + +#define HDMI_LINK_HDCP_AKSV_X (HDMI_ADDR_OFFSET + 0x000170C0) +#define HDMI_LINK_HDCP_AN_X (HDMI_ADDR_OFFSET + 0x000170E0) +#define HDMI_LINK_HDCP_BCAPS (HDMI_ADDR_OFFSET + 0x00017100) +#define HDMI_LINK_HDCP_BSTATUS_0 (HDMI_ADDR_OFFSET + 0x00017110) +#define HDMI_LINK_HDCP_BSTATUS_1 (HDMI_ADDR_OFFSET + 0x00017114) +#define HDMI_LINK_HDCP_RI_0 (HDMI_ADDR_OFFSET + 0x00017140) +#define HDMI_LINK_HDCP_RI_1 (HDMI_ADDR_OFFSET + 0x00017144) + +#define HDMI_LINK_HDCP_OFFSET_TX_0 (HDMI_ADDR_OFFSET + 0x00017160) +#define HDMI_LINK_HDCP_OFFSET_TX_1 (HDMI_ADDR_OFFSET + 0x00017164) +#define HDMI_LINK_HDCP_OFFSET_TX_2 (HDMI_ADDR_OFFSET + 0x00017168) +#define HDMI_LINK_HDCP_OFFSET_TX_3 (HDMI_ADDR_OFFSET + 0x0001716C) +#define HDMI_LINK_HDCP_CYCLE_AA (HDMI_ADDR_OFFSET + 0x00017170) + +#define HDMI_LINK_HDCP_I2C_INT (HDMI_ADDR_OFFSET + 0x00017180) +#define HDMI_LINK_HDCP_AN_INT (HDMI_ADDR_OFFSET + 0x00017190) +#define HDMI_LINK_HDCP_WATCHDOG_INT (HDMI_ADDR_OFFSET + 0x000171A0) +#define HDMI_LINK_HDCP_RI_INT (HDMI_ADDR_OFFSET + 0x000171B0) +#define HDMI_LINK_HDCP_RI_COMPARE_0 (HDMI_ADDR_OFFSET + 0x000171D0) +#define HDMI_LINK_HDCP_RI_COMPARE_1 (HDMI_ADDR_OFFSET + 0x000171D4) + +#define HDMI_LINK_HDCP_RI_INT (HDMI_ADDR_OFFSET + 0x000171B0) +#define HDMI_LINK_HDCP_RI_COMPARE_0 (HDMI_ADDR_OFFSET + 0x000171D0) +#define HDMI_LINK_HDCP_RI_COMPARE_1 (HDMI_ADDR_OFFSET + 0x000171D4) + +#define HDMI_LINK_HDCP_FRAME_COUNT (HDMI_ADDR_OFFSET + 0x000171E0) +#define HDMI_LINK_RGB_ROUND_EN (HDMI_ADDR_OFFSET + 0x0001D500) +#define HDMI_LINK_VACT_SPACE_R_0 (HDMI_ADDR_OFFSET + 0x0001D504) +#define HDMI_LINK_VACT_SPACE_R_1 (HDMI_ADDR_OFFSET + 0x0001D508) +#define HDMI_LINK_VACT_SPACE_G_0 (HDMI_ADDR_OFFSET + 0x0001D50C) +#define HDMI_LINK_VACT_SPACE_G_1 (HDMI_ADDR_OFFSET + 0x0001D510) +#define HDMI_LINK_VACT_SPACE_B_0 (HDMI_ADDR_OFFSET + 0x0001D514) +#define HDMI_LINK_VACT_SPACE_B_1 (HDMI_ADDR_OFFSET + 0x0001D518) +#define HDMI_LINK_BLUE_SCREEN_R_0 (HDMI_ADDR_OFFSET + 0x0001D520) +#define HDMI_LINK_BLUE_SCREEN_R_1 (HDMI_ADDR_OFFSET + 0x0001D524) +#define HDMI_LINK_BLUE_SCREEN_G_0 (HDMI_ADDR_OFFSET + 0x0001D528) +#define HDMI_LINK_BLUE_SCREEN_G_1 (HDMI_ADDR_OFFSET + 0x0001D52C) +#define HDMI_LINK_BLUE_SCREEN_B_0 (HDMI_ADDR_OFFSET + 0x0001D530) +#define HDMI_LINK_BLUE_SCREEN_B_1 (HDMI_ADDR_OFFSET + 0x0001D534) +#define HDMI_LINK_AES_START (HDMI_ADDR_OFFSET + 0x00020000) +#define HDMI_LINK_AES_DATA_SIZE_L (HDMI_ADDR_OFFSET + 0x00020020) +#define HDMI_LINK_AES_DATA_SIZE_H (HDMI_ADDR_OFFSET + 0x00020024) +#define HDMI_LINK_AES_DATA (HDMI_ADDR_OFFSET + 0x00020040) +#define HDMI_LINK_SPDIFIN_CLK_CTRL (HDMI_ADDR_OFFSET + 0x00030000) +#define HDMI_LINK_SPDIFIN_OP_CTRL (HDMI_ADDR_OFFSET + 0x00030004) +#define HDMI_LINK_SPDIFIN_IRQ_MASK (HDMI_ADDR_OFFSET + 0x00030008) +#define HDMI_LINK_SPDIFIN_IRQ_STATUS (HDMI_ADDR_OFFSET + 0x0003000C) +#define HDMI_LINK_SPDIFIN_CONFIG_1 (HDMI_ADDR_OFFSET + 0x00030010) +#define HDMI_LINK_SPDIFIN_CONFIG_2 (HDMI_ADDR_OFFSET + 0x00030014) +#define HDMI_LINK_SPDIFIN_USER_VALUE_1 (HDMI_ADDR_OFFSET + 0x00030020) +#define HDMI_LINK_SPDIFIN_USER_VALUE_2 (HDMI_ADDR_OFFSET + 0x00030024) +#define HDMI_LINK_SPDIFIN_USER_VALUE_3 (HDMI_ADDR_OFFSET + 0x00030028) +#define HDMI_LINK_SPDIFIN_USER_VALUE_4 (HDMI_ADDR_OFFSET + 0x0003002C) +#define HDMI_LINK_SPDIFIN_CH_STATUS_0_1 (HDMI_ADDR_OFFSET + 0x00030030) +#define HDMI_LINK_SPDIFIN_CH_STATUS_0_2 (HDMI_ADDR_OFFSET + 0x00030034) +#define HDMI_LINK_SPDIFIN_CH_STATUS_0_3 (HDMI_ADDR_OFFSET + 0x00030038) +#define HDMI_LINK_SPDIFIN_CH_STATUS_0_4 (HDMI_ADDR_OFFSET + 0x0003003C) +#define HDMI_LINK_SPDIFIN_CH_STATUS_1 (HDMI_ADDR_OFFSET + 0x00030040) +#define HDMI_LINK_SPDIFIN_FRAME_PERIOD_1 (HDMI_ADDR_OFFSET + 0x00030048) +#define HDMI_LINK_SPDIFIN_FRAME_PERIOD_2 (HDMI_ADDR_OFFSET + 0x0003004C) +#define HDMI_LINK_SPDIFIN_PC_INFO_1 (HDMI_ADDR_OFFSET + 0x00030050) +#define HDMI_LINK_SPDIFIN_PC_INFO_2 (HDMI_ADDR_OFFSET + 0x00030054) +#define HDMI_LINK_SPDIFIN_PD_INFO_1 (HDMI_ADDR_OFFSET + 0x00030058) +#define HDMI_LINK_SPDIFIN_PD_INFO_2 (HDMI_ADDR_OFFSET + 0x0003005C) +#define HDMI_LINK_SPDIFIN_DATA_BUF_0_1 (HDMI_ADDR_OFFSET + 0x00030060) +#define HDMI_LINK_SPDIFIN_DATA_BUF_0_2 (HDMI_ADDR_OFFSET + 0x00030064) +#define HDMI_LINK_SPDIFIN_DATA_BUF_0_3 (HDMI_ADDR_OFFSET + 0x00030068) +#define HDMI_LINK_SPDIFIN_USER_BUF_0 (HDMI_ADDR_OFFSET + 0x0003006C) +#define HDMI_LINK_SPDIFIN_DATA_BUF_1_1 (HDMI_ADDR_OFFSET + 0x00030070) +#define HDMI_LINK_SPDIFIN_DATA_BUF_1_2 (HDMI_ADDR_OFFSET + 0x00030074) +#define HDMI_LINK_SPDIFIN_DATA_BUF_1_3 (HDMI_ADDR_OFFSET + 0x00030078) +#define HDMI_LINK_SPDIFIN_USER_BUF_1 (HDMI_ADDR_OFFSET + 0x0003007C) +#define HDMI_LINK_I2S_CLK_CON (HDMI_ADDR_OFFSET + 0x00040000) +#define HDMI_LINK_I2S_CON_1 (HDMI_ADDR_OFFSET + 0x00040004) +#define HDMI_LINK_I2S_CON_2 (HDMI_ADDR_OFFSET + 0x00040008) +#define HDMI_LINK_I2S_PIN_SEL_0 (HDMI_ADDR_OFFSET + 0x0004000C) +#define HDMI_LINK_I2S_PIN_SEL_1 (HDMI_ADDR_OFFSET + 0x00040010) +#define HDMI_LINK_I2S_PIN_SEL_2 (HDMI_ADDR_OFFSET + 0x00040014) +#define HDMI_LINK_I2S_PIN_SEL_3 (HDMI_ADDR_OFFSET + 0x00040018) +#define HDMI_LINK_I2S_DSD_CON (HDMI_ADDR_OFFSET + 0x0004001C) +#define HDMI_LINK_I2S_MUX_CON (HDMI_ADDR_OFFSET + 0x00040020) +#define HDMI_LINK_I2S_CH_ST_CON (HDMI_ADDR_OFFSET + 0x00040024) +#define HDMI_LINK_I2S_CH_ST_0 (HDMI_ADDR_OFFSET + 0x00040028) +#define HDMI_LINK_I2S_CH_ST_1 (HDMI_ADDR_OFFSET + 0x0004002C) +#define HDMI_LINK_I2S_CH_ST_2 (HDMI_ADDR_OFFSET + 0x00040030) +#define HDMI_LINK_I2S_CH_ST_3 (HDMI_ADDR_OFFSET + 0x00040034) +#define HDMI_LINK_I2S_CH_ST_4 (HDMI_ADDR_OFFSET + 0x00040038) +#define HDMI_LINK_I2S_CH_ST_SH_0 (HDMI_ADDR_OFFSET + 0x0004003C) +#define HDMI_LINK_I2S_CH_ST_SH_1 (HDMI_ADDR_OFFSET + 0x00040040) +#define HDMI_LINK_I2S_CH_ST_SH_2 (HDMI_ADDR_OFFSET + 0x00040044) +#define HDMI_LINK_I2S_CH_ST_SH_3 (HDMI_ADDR_OFFSET + 0x00040048) +#define HDMI_LINK_I2S_CH_ST_SH_4 (HDMI_ADDR_OFFSET + 0x0004004C) +#define HDMI_LINK_I2S_VD_DATA (HDMI_ADDR_OFFSET + 0x00040050) +#define HDMI_LINK_I2S_MUX_CH (HDMI_ADDR_OFFSET + 0x00040054) +#define HDMI_LINK_I2S_MUX_CUV (HDMI_ADDR_OFFSET + 0x00040058) +#define HDMI_LINK_I2S_CH0_L_0 (HDMI_ADDR_OFFSET + 0x00040064) +#define HDMI_LINK_I2S_CH0_L_1 (HDMI_ADDR_OFFSET + 0x00040068) +#define HDMI_LINK_I2S_CH0_L_2 (HDMI_ADDR_OFFSET + 0x0004006C) +#define HDMI_LINK_I2S_CH0_R_0 (HDMI_ADDR_OFFSET + 0x00040074) +#define HDMI_LINK_I2S_CH0_R_1 (HDMI_ADDR_OFFSET + 0x00040078) +#define HDMI_LINK_I2S_CH0_R_2 (HDMI_ADDR_OFFSET + 0x0004007C) +#define HDMI_LINK_I2S_CH0_R_3 (HDMI_ADDR_OFFSET + 0x00040080) +#define HDMI_LINK_I2S_CH1_L_0 (HDMI_ADDR_OFFSET + 0x00040084) +#define HDMI_LINK_I2S_CH1_L_1 (HDMI_ADDR_OFFSET + 0x00040088) +#define HDMI_LINK_I2S_CH1_L_2 (HDMI_ADDR_OFFSET + 0x0004008C) +#define HDMI_LINK_I2S_CH1_L_3 (HDMI_ADDR_OFFSET + 0x00040090) +#define HDMI_LINK_I2S_CH1_R_0 (HDMI_ADDR_OFFSET + 0x00040094) +#define HDMI_LINK_I2S_CH1_R_1 (HDMI_ADDR_OFFSET + 0x00040098) +#define HDMI_LINK_I2S_CH1_R_2 (HDMI_ADDR_OFFSET + 0x0004009C) +#define HDMI_LINK_I2S_CH1_R_3 (HDMI_ADDR_OFFSET + 0x000400A0) +#define HDMI_LINK_I2S_CH2_L_0 (HDMI_ADDR_OFFSET + 0x000400A4) +#define HDMI_LINK_I2S_CH2_L_1 (HDMI_ADDR_OFFSET + 0x000400A8) +#define HDMI_LINK_I2S_CH2_L_2 (HDMI_ADDR_OFFSET + 0x000400AC) +#define HDMI_LINK_I2S_CH2_L_3 (HDMI_ADDR_OFFSET + 0x000400B0) +#define HDMI_LINK_I2S_CH2_R_0 (HDMI_ADDR_OFFSET + 0x000400B4) +#define HDMI_LINK_I2S_CH2_R_1 (HDMI_ADDR_OFFSET + 0x000400B8) +#define HDMI_LINK_I2S_CH2_R_2 (HDMI_ADDR_OFFSET + 0x000400BC) +#define HDMI_LINK_I2S_CH2_R_3 (HDMI_ADDR_OFFSET + 0x000400C0) +#define HDMI_LINK_I2S_CH3_L_0 (HDMI_ADDR_OFFSET + 0x000400C4) +#define HDMI_LINK_I2S_CH3_L_1 (HDMI_ADDR_OFFSET + 0x000400C8) +#define HDMI_LINK_I2S_CH3_L_2 (HDMI_ADDR_OFFSET + 0x000400CC) +#define HDMI_LINK_I2S_CH3_R_0 (HDMI_ADDR_OFFSET + 0x000400D0) +#define HDMI_LINK_I2S_CH3_R_1 (HDMI_ADDR_OFFSET + 0x000400D4) +#define HDMI_LINK_I2S_CH3_R_2 (HDMI_ADDR_OFFSET + 0x000400D8) +#define HDMI_LINK_I2S_CUV_L_R (HDMI_ADDR_OFFSET + 0x000400DC) + +#define HDMI_CEC_TX_STATUS_0 (OTHER_ADDR_OFFSET + 0x00000000) +#define HDMI_CEC_TX_STATUS_1 (OTHER_ADDR_OFFSET + 0x00000004) +#define HDMI_CEC_RX_STATUS_0 (OTHER_ADDR_OFFSET + 0x00000008) +#define HDMI_CEC_RX_STATUS_1 (OTHER_ADDR_OFFSET + 0x0000000C) +#define HDMI_CEC_INTR_MASK (OTHER_ADDR_OFFSET + 0x00000010) +#define HDMI_CEC_INTR_CLEAR (OTHER_ADDR_OFFSET + 0x00000014) +#define HDMI_CEC_LOGIC_ADDR (OTHER_ADDR_OFFSET + 0x00000020) +#define HDMI_CEC_DIVISOR_0 (OTHER_ADDR_OFFSET + 0x00000030) +#define HDMI_CEC_DIVISOR_1 (OTHER_ADDR_OFFSET + 0x00000034) +#define HDMI_CEC_DIVISOR_2 (OTHER_ADDR_OFFSET + 0x00000038) +#define HDMI_CEC_DIVISOR_3 (OTHER_ADDR_OFFSET + 0x0000003C) +#define HDMI_CEC_TX_CTRL (OTHER_ADDR_OFFSET + 0x00000040) +#define HDMI_CEC_TX_BYTE_NUM (OTHER_ADDR_OFFSET + 0x00000044) +#define HDMI_CEC_TX_STATUS_2 (OTHER_ADDR_OFFSET + 0x00000060) +#define HDMI_CEC_TX_STATUS_3 (OTHER_ADDR_OFFSET + 0x00000064) +#define HDMI_CEC_TX_BUFFER_x (OTHER_ADDR_OFFSET + 0x00000080) +#define HDMI_CEC_TX_BUFFER00 (OTHER_ADDR_OFFSET + 0x00000080) +#define HDMI_CEC_RX_CTRL (OTHER_ADDR_OFFSET + 0x000000C0) +#define HDMI_CEC_RX_STATUS_2 (OTHER_ADDR_OFFSET + 0x000000E0) +#define HDMI_CEC_RX_STATUS_3 (OTHER_ADDR_OFFSET + 0x000000E4) +#define HDMI_CEC_RX_BUFFER_x (OTHER_ADDR_OFFSET + 0x00000100) +#define HDMI_CEC_FILTER_CTRL (OTHER_ADDR_OFFSET + 0x00000180) +#define HDMI_CEC_FILTER_TH (OTHER_ADDR_OFFSET + 0x00000184) + +#ifdef CONFIG_MACH_S5P6818 +#define HDMI_PHY_OFFSET \ + (PHY_BASEADDR_HDMI_PHY_MODULE - PHY_BASEADDR_HDMI_MODULE) +#else +#define HDMI_PHY_OFFSET 0x400 +#endif + +#define HDMI_PHY_REG00 (OTHER_ADDR_OFFSET + HDMI_PHY_OFFSET + 0x00000000) +#define HDMI_PHY_REG04 (OTHER_ADDR_OFFSET + HDMI_PHY_OFFSET + 0x00000004) +#define HDMI_PHY_REG08 (OTHER_ADDR_OFFSET + HDMI_PHY_OFFSET + 0x00000008) +#define HDMI_PHY_REG0C (OTHER_ADDR_OFFSET + HDMI_PHY_OFFSET + 0x0000000C) +#define HDMI_PHY_REG10 (OTHER_ADDR_OFFSET + HDMI_PHY_OFFSET + 0x00000010) +#define HDMI_PHY_REG14 (OTHER_ADDR_OFFSET + HDMI_PHY_OFFSET + 0x00000014) +#define HDMI_PHY_REG18 (OTHER_ADDR_OFFSET + HDMI_PHY_OFFSET + 0x00000018) +#define HDMI_PHY_REG1C (OTHER_ADDR_OFFSET + HDMI_PHY_OFFSET + 0x0000001C) +#define HDMI_PHY_REG20 (OTHER_ADDR_OFFSET + HDMI_PHY_OFFSET + 0x00000020) +#define HDMI_PHY_REG24 (OTHER_ADDR_OFFSET + HDMI_PHY_OFFSET + 0x00000024) +#define HDMI_PHY_REG28 (OTHER_ADDR_OFFSET + HDMI_PHY_OFFSET + 0x00000028) +#define HDMI_PHY_REG2C (OTHER_ADDR_OFFSET + HDMI_PHY_OFFSET + 0x0000002C) +#define HDMI_PHY_REG30 (OTHER_ADDR_OFFSET + HDMI_PHY_OFFSET + 0x00000030) +#define HDMI_PHY_REG34 (OTHER_ADDR_OFFSET + HDMI_PHY_OFFSET + 0x00000034) +#define HDMI_PHY_REG38 (OTHER_ADDR_OFFSET + HDMI_PHY_OFFSET + 0x00000038) +#define HDMI_PHY_REG3C (OTHER_ADDR_OFFSET + HDMI_PHY_OFFSET + 0x0000003C) +#define HDMI_PHY_REG40 (OTHER_ADDR_OFFSET + HDMI_PHY_OFFSET + 0x00000040) +#define HDMI_PHY_REG44 (OTHER_ADDR_OFFSET + HDMI_PHY_OFFSET + 0x00000044) +#define HDMI_PHY_REG48 (OTHER_ADDR_OFFSET + HDMI_PHY_OFFSET + 0x00000048) +#define HDMI_PHY_REG4C (OTHER_ADDR_OFFSET + HDMI_PHY_OFFSET + 0x0000004C) +#define HDMI_PHY_REG50 (OTHER_ADDR_OFFSET + HDMI_PHY_OFFSET + 0x00000050) +#define HDMI_PHY_REG54 (OTHER_ADDR_OFFSET + HDMI_PHY_OFFSET + 0x00000054) +#define HDMI_PHY_REG58 (OTHER_ADDR_OFFSET + HDMI_PHY_OFFSET + 0x00000058) +#define HDMI_PHY_REG5C (OTHER_ADDR_OFFSET + HDMI_PHY_OFFSET + 0x0000005C) +#define HDMI_PHY_REG60 (OTHER_ADDR_OFFSET + HDMI_PHY_OFFSET + 0x00000060) +#define HDMI_PHY_REG64 (OTHER_ADDR_OFFSET + HDMI_PHY_OFFSET + 0x00000064) +#define HDMI_PHY_REG68 (OTHER_ADDR_OFFSET + HDMI_PHY_OFFSET + 0x00000068) +#define HDMI_PHY_REG6C (OTHER_ADDR_OFFSET + HDMI_PHY_OFFSET + 0x0000006C) +#define HDMI_PHY_REG70 (OTHER_ADDR_OFFSET + HDMI_PHY_OFFSET + 0x00000070) +#define HDMI_PHY_REG74 (OTHER_ADDR_OFFSET + HDMI_PHY_OFFSET + 0x00000074) +#define HDMI_PHY_REG78 (OTHER_ADDR_OFFSET + HDMI_PHY_OFFSET + 0x00000078) +#define HDMI_PHY_REG7C (OTHER_ADDR_OFFSET + HDMI_PHY_OFFSET + 0x0000007C) +#define HDMI_PHY_REG80 (OTHER_ADDR_OFFSET + HDMI_PHY_OFFSET + 0x00000080) +#define HDMI_PHY_REG84 (OTHER_ADDR_OFFSET + HDMI_PHY_OFFSET + 0x00000084) +#define HDMI_PHY_REG88 (OTHER_ADDR_OFFSET + HDMI_PHY_OFFSET + 0x00000088) +#define HDMI_PHY_REG8C (OTHER_ADDR_OFFSET + HDMI_PHY_OFFSET + 0x0000008C) +#define HDMI_PHY_REG90 (OTHER_ADDR_OFFSET + HDMI_PHY_OFFSET + 0x00000090) + +enum hdmi_reset { + i_nRST = 0, + i_nRST_VIDEO = 1, + i_nRST_SPDIF = 2, + i_nRST_TMDS = 3, + i_nRST_PHY = 4, +}; + +u32 nx_hdmi_get_reg(u32 module_index, u32 offset); +void nx_hdmi_set_reg(u32 module_index, u32 offset, u32 regvalue); + +void nx_hdmi_set_base_address(u32 module_index, void *base_address); +void *nx_hdmi_get_base_address(u32 module_index); +u32 nx_hdmi_get_physical_address(u32 module_index); + +#endif diff --git a/drivers/video/nexell/soc/s5pxx18_soc_lvds.c b/drivers/video/nexell/soc/s5pxx18_soc_lvds.c new file mode 100644 index 0000000000..18c101bda7 --- /dev/null +++ b/drivers/video/nexell/soc/s5pxx18_soc_lvds.c @@ -0,0 +1,278 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2016 Nexell Co., Ltd. + * + * Author: junghyun, kim <jhkim@nexell.co.kr> + */ + +#include <linux/types.h> +#include <linux/io.h> + +#include "s5pxx18_soc_disptop.h" +#include "s5pxx18_soc_lvds.h" + +#ifndef pow +static inline unsigned int pow(int a, int b) +{ + if (b == 0) + return 1; + else + return a * pow(a, b - 1); +} +#endif + +static struct nx_lvds_register_set *__g_pregister[NUMBER_OF_LVDS_MODULE]; + +int nx_lvds_initialize(void) +{ + static int binit; + u32 i; + + if (binit == 0) { + for (i = 0; i < NUMBER_OF_LVDS_MODULE; i++) + __g_pregister[i] = NULL; + binit = 1; + } + + return 1; +} + +u32 nx_lvds_get_number_of_module(void) +{ + return NUMBER_OF_LVDS_MODULE; +} + +u32 nx_lvds_get_size_of_register_set(void) +{ + return sizeof(struct nx_lvds_register_set); +} + +void nx_lvds_set_base_address(u32 module_index, void *base_address) +{ + __g_pregister[module_index] = + (struct nx_lvds_register_set *)base_address; +} + +void *nx_lvds_get_base_address(u32 module_index) +{ + return (void *)__g_pregister[module_index]; +} + +u32 nx_lvds_get_physical_address(u32 module_index) +{ + const u32 physical_addr[] = PHY_BASEADDR_LVDS_LIST; + + return physical_addr[module_index]; +} + +int nx_lvds_open_module(u32 module_index) +{ + return true; +} + +int nx_lvds_close_module(u32 module_index) +{ + return true; +} + +int nx_lvds_check_busy(u32 module_index) +{ + return false; +} + +void nx_lvds_set_lvdsctrl0(u32 module_index, u32 regvalue) +{ + register struct nx_lvds_register_set *pregister; + + pregister = __g_pregister[module_index]; + writel(regvalue, &pregister->lvdsctrl0); +} + +void nx_lvds_set_lvdsctrl1(u32 module_index, u32 regvalue) +{ + register struct nx_lvds_register_set *pregister; + + pregister = __g_pregister[module_index]; + writel(regvalue, &pregister->lvdsctrl1); +} + +void nx_lvds_set_lvdsctrl2(u32 module_index, u32 regvalue) +{ + register struct nx_lvds_register_set *pregister; + + pregister = __g_pregister[module_index]; + writel(regvalue, &pregister->lvdsctrl2); +} + +void nx_lvds_set_lvdsctrl3(u32 module_index, u32 regvalue) +{ + register struct nx_lvds_register_set *pregister; + + pregister = __g_pregister[module_index]; + writel(regvalue, &pregister->lvdsctrl3); +} + +void nx_lvds_set_lvdsctrl4(u32 module_index, u32 regvalue) +{ + register struct nx_lvds_register_set *pregister; + + pregister = __g_pregister[module_index]; + writel(regvalue, &pregister->lvdsctrl4); +} + +void nx_lvds_set_lvdstmode0(u32 module_index, u32 regvalue) +{ + register struct nx_lvds_register_set *pregister; + + pregister = __g_pregister[module_index]; + writel(regvalue, &pregister->lvdstmode0); +} + +void nx_lvds_set_lvdsloc0(u32 module_index, u32 regvalue) +{ + register struct nx_lvds_register_set *pregister; + + pregister = __g_pregister[module_index]; + writel(regvalue, &pregister->lvdsloc0); +} + +void nx_lvds_set_lvdsloc1(u32 module_index, u32 regvalue) +{ + register struct nx_lvds_register_set *pregister; + + pregister = __g_pregister[module_index]; + writel(regvalue, &pregister->lvdsloc1); +} + +void nx_lvds_set_lvdsloc2(u32 module_index, u32 regvalue) +{ + register struct nx_lvds_register_set *pregister; + + pregister = __g_pregister[module_index]; + writel(regvalue, &pregister->lvdsloc2); +} + +void nx_lvds_set_lvdsloc3(u32 module_index, u32 regvalue) +{ + register struct nx_lvds_register_set *pregister; + + pregister = __g_pregister[module_index]; + writel(regvalue, &pregister->lvdsloc3); +} + +void nx_lvds_set_lvdsloc4(u32 module_index, u32 regvalue) +{ + register struct nx_lvds_register_set *pregister; + + pregister = __g_pregister[module_index]; + writel(regvalue, &pregister->lvdsloc4); +} + +void nx_lvds_set_lvdsloc5(u32 module_index, u32 regvalue) +{ + register struct nx_lvds_register_set *pregister; + + pregister = __g_pregister[module_index]; + writel(regvalue, &pregister->lvdsloc5); +} + +void nx_lvds_set_lvdsloc6(u32 module_index, u32 regvalue) +{ + register struct nx_lvds_register_set *pregister; + + pregister = __g_pregister[module_index]; + writel(regvalue, &pregister->lvdsloc6); +} + +void nx_lvds_set_lvdslocmask0(u32 module_index, u32 regvalue) +{ + register struct nx_lvds_register_set *pregister; + + pregister = __g_pregister[module_index]; + writel(regvalue, &pregister->lvdslocmask0); +} + +void nx_lvds_set_lvdslocmask1(u32 module_index, u32 regvalue) +{ + register struct nx_lvds_register_set *pregister; + + pregister = __g_pregister[module_index]; + writel(regvalue, &pregister->lvdslocmask1); +} + +void nx_lvds_set_lvdslocpol0(u32 module_index, u32 regvalue) +{ + register struct nx_lvds_register_set *pregister; + + pregister = __g_pregister[module_index]; + writel(regvalue, &pregister->lvdslocpol0); +} + +void nx_lvds_set_lvdslocpol1(u32 module_index, u32 regvalue) +{ + register struct nx_lvds_register_set *pregister; + + pregister = __g_pregister[module_index]; + writel(regvalue, &pregister->lvdslocpol1); +} + +void nx_lvds_set_lvdsdummy(u32 module_index, u32 regvalue) +{ + register struct nx_lvds_register_set *pregister; + u32 oldvalue; + + pregister = __g_pregister[module_index]; + oldvalue = readl(&pregister->lvdsctrl1) & 0x00ffffff; + writel(oldvalue | ((regvalue & 0xff) << 24), &pregister->lvdsctrl1); +} + +u32 nx_lvds_get_lvdsdummy(u32 module_index) +{ + register struct nx_lvds_register_set *pregister; + u32 oldvalue; + + pregister = __g_pregister[module_index]; + oldvalue = readl(&pregister->lvdsctrl1); + oldvalue = oldvalue >> 24; + return oldvalue; +} + +u32 nx_lvds_get_lvdsctrl0(u32 module_index) +{ + register struct nx_lvds_register_set *pregister; + + pregister = __g_pregister[module_index]; + return (u32)readl(&pregister->lvdsctrl0); +} + +u32 nx_lvds_get_lvdsctrl1(u32 module_index) +{ + register struct nx_lvds_register_set *pregister; + + pregister = __g_pregister[module_index]; + return (u32)readl(&pregister->lvdsctrl1); +} + +u32 nx_lvds_get_lvdsctrl2(u32 module_index) +{ + register struct nx_lvds_register_set *pregister; + + pregister = __g_pregister[module_index]; + return (u32)readl(&pregister->lvdsctrl2); +} + +u32 nx_lvds_get_lvdsctrl3(u32 module_index) +{ + register struct nx_lvds_register_set *pregister; + + pregister = __g_pregister[module_index]; + return (u32)readl(&pregister->lvdsctrl3); +} + +u32 nx_lvds_get_lvdsctrl4(u32 module_index) +{ + register struct nx_lvds_register_set *pregister; + + pregister = __g_pregister[module_index]; + return (u32)readl(&pregister->lvdsctrl4); +} diff --git a/drivers/video/nexell/soc/s5pxx18_soc_lvds.h b/drivers/video/nexell/soc/s5pxx18_soc_lvds.h new file mode 100644 index 0000000000..08f8e5c406 --- /dev/null +++ b/drivers/video/nexell/soc/s5pxx18_soc_lvds.h @@ -0,0 +1,83 @@ +/* SPDX-License-Identifier: GPL-2.0+ + * + * Copyright (C) 2016 Nexell Co., Ltd. + * + * Author: junghyun, kim <jhkim@nexell.co.kr> + */ + +#ifndef _S5PXX18_SOC_LVDS_H_ +#define _S5PXX18_SOC_LVDS_H_ + +/* + * refter to s5pxx18_soc_disptop.h + * + * #define NUMBER_OF_LVDS_MODULE 1 + * #define PHY_BASEADDR_LVDS_MODULE 0xC010A000 + */ +#define PHY_BASEADDR_LVDS_LIST \ + { PHY_BASEADDR_LVDS_MODULE } + +struct nx_lvds_register_set { + u32 lvdsctrl0; + u32 lvdsctrl1; + u32 lvdsctrl2; + u32 lvdsctrl3; + u32 lvdsctrl4; + u32 _reserved0[3]; + u32 lvdsloc0; + u32 lvdsloc1; + u32 lvdsloc2; + u32 lvdsloc3; + u32 lvdsloc4; + u32 lvdsloc5; + u32 lvdsloc6; + u32 _reserved1; + u32 lvdslocmask0; + u32 lvdslocmask1; + u32 lvdslocpol0; + u32 lvdslocpol1; + u32 lvdstmode0; + u32 lvdstmode1; + u32 _reserved2[2]; +}; + +int nx_lvds_initialize(void); +u32 nx_lvds_get_number_of_module(void); +u32 nx_lvds_get_size_of_register_set(void); +void nx_lvds_set_base_address(u32 module_index, void *base_address); +void *nx_lvds_get_base_address(u32 module_index); +u32 nx_lvds_get_physical_address(u32 module_index); +int nx_lvds_open_module(u32 module_index); +int nx_lvds_close_module(u32 module_index); +int nx_lvds_check_busy(u32 module_index); + +void nx_lvds_set_lvdsctrl0(u32 module_index, u32 regvalue); +void nx_lvds_set_lvdsctrl1(u32 module_index, u32 regvalue); +void nx_lvds_set_lvdsctrl2(u32 module_index, u32 regvalue); +void nx_lvds_set_lvdsctrl3(u32 module_index, u32 regvalue); +void nx_lvds_set_lvdsctrl4(u32 module_index, u32 regvalue); +u32 nx_lvds_get_lvdsctrl0(u32 module_index); +u32 nx_lvds_get_lvdsctrl1(u32 module_index); +u32 nx_lvds_get_lvdsctrl2(u32 module_index); +u32 nx_lvds_get_lvdsctrl3(u32 module_index); +u32 nx_lvds_get_lvdsctrl4(u32 module_index); + +void nx_lvds_set_lvdstmode0(u32 module_index, u32 regvalue); +void nx_lvds_set_lvdsloc0(u32 module_index, u32 regvalue); +void nx_lvds_set_lvdsloc1(u32 module_index, u32 regvalue); +void nx_lvds_set_lvdsloc2(u32 module_index, u32 regvalue); +void nx_lvds_set_lvdsloc3(u32 module_index, u32 regvalue); +void nx_lvds_set_lvdsloc4(u32 module_index, u32 regvalue); +void nx_lvds_set_lvdsloc5(u32 module_index, u32 regvalue); +void nx_lvds_set_lvdsloc6(u32 module_index, u32 regvalue); +void nx_lvds_set_lvdslocmask0(u32 module_index, u32 regvalue); +void nx_lvds_set_lvdslocmask1(u32 module_index, u32 regvalue); +void nx_lvds_set_lvdslocpol0(u32 module_index, u32 regvalue); +void nx_lvds_set_lvdslocpol1(u32 module_index, u32 regvalue); + +void nx_lvds_set_lvdslocpol1(u32 module_index, u32 regvalue); + +void nx_lvds_set_lvdsdummy(u32 module_index, u32 regvalue); +u32 nx_lvds_get_lvdsdummy(u32 module_index); + +#endif diff --git a/drivers/video/nexell/soc/s5pxx18_soc_mipi.c b/drivers/video/nexell/soc/s5pxx18_soc_mipi.c new file mode 100644 index 0000000000..1000ddb642 --- /dev/null +++ b/drivers/video/nexell/soc/s5pxx18_soc_mipi.c @@ -0,0 +1,580 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2016 Nexell Co., Ltd. + * + * Author: junghyun, kim <jhkim@nexell.co.kr> + */ + +#include <linux/types.h> +#include <linux/io.h> + +#include "s5pxx18_soc_disptop.h" +#include "s5pxx18_soc_mipi.h" + +static struct nx_mipi_register_set *__g_pregister[NUMBER_OF_MIPI_MODULE]; + +int nx_mipi_smoke_test(u32 module_index) +{ + register struct nx_mipi_register_set *pregister; + + pregister = __g_pregister[module_index]; + + if (pregister->csis_config_ch0 != 0x000000FC) + return false; + + if (pregister->dsim_intmsk != 0xB337FFFF) + return false; + + writel(0xDEADC0DE, &pregister->csis_dphyctrl); + writel(0xFFFFFFFF, &pregister->csis_ctrl2); + writel(0xDEADC0DE, &pregister->dsim_msync); + + if (pregister->csis_dphyctrl != 0xDE80001E) + return false; + + if ((pregister->csis_ctrl2 & (~1)) != 0xEEE00010) + return false; + + if (pregister->dsim_msync != 0xDE80C0DE) + return false; + + return true; +} + +void nx_mipi_set_base_address(u32 module_index, void *base_address) +{ + __g_pregister[module_index] = + (struct nx_mipi_register_set *)base_address; +} + +void *nx_mipi_get_base_address(u32 module_index) +{ + return (void *)__g_pregister[module_index]; +} + +u32 nx_mipi_get_physical_address(u32 module_index) +{ + const u32 physical_addr[] = PHY_BASEADDR_MIPI_LIST; + + return physical_addr[module_index]; +} + +#define __nx_mipi_valid_dsi_intmask__ \ + (~((1 << 26) | (1 << 23) | (1 << 22) | (1 << 19))) + +void nx_mipi_set_interrupt_enable(u32 module_index, u32 int_num, int enable) +{ + register struct nx_mipi_register_set *pregister; + register u32 regvalue; + + pregister = __g_pregister[module_index]; + if (int_num < 32) { + regvalue = pregister->csis_intmsk; + regvalue &= ~(1ul << int_num); + regvalue |= (u32)enable << int_num; + writel(regvalue, &pregister->csis_intmsk); + } else { + regvalue = pregister->dsim_intmsk; + regvalue &= ~(1ul << (int_num - 32)); + regvalue |= (u32)enable << (int_num - 32); + writel(regvalue, &pregister->dsim_intmsk); + } +} + +int nx_mipi_get_interrupt_enable(u32 module_index, u32 int_num) +{ + if (int_num < 32) + return (int)((__g_pregister[module_index]->csis_intmsk >> + int_num) & 0x01); + else + return (int)((__g_pregister[module_index]->dsim_intmsk >> + (int_num - 32)) & 0x01); +} + +int nx_mipi_get_interrupt_pending(u32 module_index, u32 int_num) +{ + register struct nx_mipi_register_set *pregister; + register u32 regvalue; + int ret; + + pregister = __g_pregister[module_index]; + if (int_num < 32) { + regvalue = pregister->csis_intmsk; + regvalue &= pregister->csis_intsrc; + ret = (int)((regvalue >> int_num) & 0x01); + } else { + regvalue = pregister->dsim_intmsk; + regvalue &= pregister->dsim_intsrc; + ret = (int)((regvalue >> (int_num - 32)) & 0x01); + } + + return ret; +} + +void nx_mipi_clear_interrupt_pending(u32 module_index, u32 int_num) +{ + register struct nx_mipi_register_set *pregister; + + pregister = __g_pregister[module_index]; + if (int_num < 32) + writel(1ul << int_num, &pregister->csis_intsrc); + else + writel(1ul << (int_num - 32), &pregister->dsim_intsrc); +} + +void nx_mipi_set_interrupt_enable_all(u32 module_index, int enable) +{ + register struct nx_mipi_register_set *pregister; + + pregister = __g_pregister[module_index]; + if (enable) + writel(__nx_mipi_valid_dsi_intmask__, &pregister->dsim_intmsk); + else + writel(0, &pregister->dsim_intmsk); +} + +int nx_mipi_get_interrupt_enable_all(u32 module_index) +{ + if (__g_pregister[module_index]->csis_intmsk) + return true; + + if (__g_pregister[module_index]->dsim_intmsk) + return true; + + return false; +} + +int nx_mipi_get_interrupt_pending_all(u32 module_index) +{ + register struct nx_mipi_register_set *pregister; + register u32 regvalue; + + pregister = __g_pregister[module_index]; + regvalue = pregister->csis_intmsk; + regvalue &= pregister->csis_intsrc; + + if (regvalue) + return true; + + regvalue = pregister->dsim_intmsk; + regvalue &= pregister->dsim_intsrc; + + if (regvalue) + return true; + + return false; +} + +void nx_mipi_clear_interrupt_pending_all(u32 module_index) +{ + register struct nx_mipi_register_set *pregister; + + pregister = __g_pregister[module_index]; + writel(__nx_mipi_valid_dsi_intmask__, &pregister->dsim_intsrc); +} + +int32_t nx_mipi_get_interrupt_pending_number(u32 module_index) +{ + register struct nx_mipi_register_set *pregister; + register u32 regvalue; + int i; + + pregister = __g_pregister[module_index]; + regvalue = pregister->csis_intmsk; + regvalue &= pregister->csis_intsrc; + if (regvalue != 0) { + for (i = 0; i < 32; i++) { + if (regvalue & 1ul) + return i; + regvalue >>= 1; + } + } + + regvalue = pregister->dsim_intmsk; + regvalue &= pregister->dsim_intsrc; + if (regvalue != 0) { + for (i = 0; i < 32; i++) { + if (regvalue & 1ul) + return i + 32; + regvalue >>= 1; + } + } + return -1; +} + +#define writereg(regname, mask, value) \ + regvalue = pregister->(regname); \ + regvalue = (regvalue & (~(mask))) | (value); \ + writel(regvalue, &pregister->(regname)) + +void nx_mipi_dsi_get_status(u32 module_index, u32 *pulps, u32 *pstop, + u32 *pispllstable, u32 *pisinreset, + u32 *pisbackward, u32 *pishsclockready) +{ + register struct nx_mipi_register_set *pregister; + register u32 regvalue; + + pregister = __g_pregister[module_index]; + regvalue = pregister->dsim_status; + if (pulps) { + *pulps = 0; + if (regvalue & (1 << 4)) + *pulps |= (1 << 0); + if (regvalue & (1 << 5)) + *pulps |= (1 << 1); + if (regvalue & (1 << 6)) + *pulps |= (1 << 2); + if (regvalue & (1 << 7)) + *pulps |= (1 << 3); + if (regvalue & (1 << 9)) + *pulps |= (1 << 4); + } + + if (pstop) { + *pstop = 0; + if (regvalue & (1 << 0)) + *pstop |= (1 << 0); + if (regvalue & (1 << 1)) + *pstop |= (1 << 1); + if (regvalue & (1 << 2)) + *pstop |= (1 << 2); + if (regvalue & (1 << 3)) + *pstop |= (1 << 3); + if (regvalue & (1 << 8)) + *pstop |= (1 << 4); + } + + if (pispllstable) + *pispllstable = (regvalue >> 31) & 1; + + if (pisinreset) + *pisinreset = ((regvalue >> 20) & 1) ? 0 : 1; + + if (pisbackward) + *pisbackward = (regvalue >> 16) & 1; + + if (pishsclockready) + *pishsclockready = (regvalue >> 10) & 1; +} + +void nx_mipi_dsi_software_reset(u32 module_index) +{ + register struct nx_mipi_register_set *pregister; + + pregister = __g_pregister[module_index]; + + writel(0x00010001, &pregister->dsim_swrst); + + while (0 != (readl(&pregister->dsim_status) & (1 << 20))) + ; + + writel(0x00000000, &pregister->dsim_swrst); +} + +void nx_mipi_dsi_set_clock(u32 module_index, int enable_txhsclock, + int use_external_clock, int enable_byte_clock, + int enable_escclock_clock_lane, + int enable_escclock_data_lane0, + int enable_escclock_data_lane1, + int enable_escclock_data_lane2, + int enable_escclock_data_lane3, + int enable_escprescaler, u32 escprescalervalue) +{ + register struct nx_mipi_register_set *pregister; + register u32 regvalue; + + pregister = __g_pregister[module_index]; + regvalue = 0; + regvalue |= (enable_txhsclock << 31); + regvalue |= (use_external_clock << 27); + regvalue |= (enable_byte_clock << 24); + regvalue |= (enable_escclock_clock_lane << 19); + regvalue |= (enable_escclock_data_lane0 << 20); + regvalue |= (enable_escclock_data_lane1 << 21); + regvalue |= (enable_escclock_data_lane2 << 22); + regvalue |= (enable_escclock_data_lane3 << 23); + regvalue |= (enable_escprescaler << 28); + regvalue |= escprescalervalue; + + writel(regvalue, &pregister->dsim_clkctrl); +} + +void nx_mipi_dsi_set_timeout(u32 module_index, u32 bta_tout, u32 lpdrtout) +{ + register struct nx_mipi_register_set *pregister; + register u32 regvalue; + + pregister = __g_pregister[module_index]; + regvalue = 0; + regvalue |= (bta_tout << 16); + regvalue |= (lpdrtout << 0); + + writel(regvalue, &pregister->dsim_timeout); +} + +void nx_mipi_dsi_set_config_video_mode(u32 module_index, + int enable_auto_flush_main_display_fifo, + int enable_auto_vertical_count, + int enable_burst, + enum nx_mipi_dsi_syncmode sync_mode, + int enable_eo_tpacket, + int enable_hsync_end_packet, + int enable_hfp, int enable_hbp, + int enable_hsa, + u32 number_of_virtual_channel, + enum nx_mipi_dsi_format format, + u32 number_of_words_in_hfp, + u32 number_of_words_in_hbp, + u32 number_of_words_in_hsync, + u32 number_of_lines_in_vfp, + u32 number_of_lines_in_vbp, + u32 number_of_lines_in_vsync, + u32 number_of_lines_in_command_allow) +{ + register struct nx_mipi_register_set *pregister; + register u32 regvalue; + u32 newvalue; + + pregister = __g_pregister[module_index]; + newvalue = (1 << 25); + newvalue |= ((1 - enable_auto_flush_main_display_fifo) << 29); + newvalue |= (enable_auto_vertical_count << 24); + newvalue |= (enable_burst << 26); + newvalue |= (sync_mode << 27); + newvalue |= ((1 - enable_eo_tpacket) << 28); + newvalue |= (enable_hsync_end_packet << 23); + newvalue |= ((1 - enable_hfp) << 22); + newvalue |= ((1 - enable_hbp) << 21); + newvalue |= ((1 - enable_hsa) << 20); + newvalue |= (number_of_virtual_channel << 18); + newvalue |= (format << 12); + + writereg(dsim_config, 0xFFFFFF00, newvalue); + + newvalue = (number_of_lines_in_command_allow << 28); + newvalue |= (number_of_lines_in_vfp << 16); + newvalue |= (number_of_lines_in_vbp << 0); + + writel(newvalue, &pregister->dsim_mvporch); + + newvalue = (number_of_words_in_hfp << 16); + newvalue |= (number_of_words_in_hbp << 0); + + writel(newvalue, &pregister->dsim_mhporch); + + newvalue = (number_of_words_in_hsync << 0); + newvalue |= (number_of_lines_in_vsync << 22); + + writel(newvalue, &pregister->dsim_msync); +} + +void nx_mipi_dsi_set_config_command_mode(u32 module_index, + int + enable_auto_flush_main_display_fifo, + int enable_eo_tpacket, + u32 number_of_virtual_channel, + enum nx_mipi_dsi_format format) +{ + register struct nx_mipi_register_set *pregister; + register u32 regvalue; + u32 newvalue; + + pregister = __g_pregister[module_index]; + newvalue = (0 << 25); + newvalue |= (enable_auto_flush_main_display_fifo << 29); + newvalue |= (enable_eo_tpacket << 28); + newvalue |= (number_of_virtual_channel << 18); + newvalue |= (format << 12); + writereg(dsim_config, 0xFFFFFF00, newvalue); +} + +void nx_mipi_dsi_set_escape_mode(u32 module_index, u32 stop_state_count, + int force_stop_state, int force_bta, + enum nx_mipi_dsi_lpmode cmdin_lp, + enum nx_mipi_dsi_lpmode txinlp) +{ + register struct nx_mipi_register_set *pregister; + register u32 regvalue; + u32 newvalue; + + pregister = __g_pregister[module_index]; + newvalue = (stop_state_count << 21); + newvalue |= (force_stop_state << 20); + newvalue |= (force_bta << 16); + newvalue |= (cmdin_lp << 7); + newvalue |= (txinlp << 6); + writereg(dsim_escmode, 0xFFFFFFC0, newvalue); +} + +void nx_mipi_dsi_set_escape_lp(u32 module_index, + enum nx_mipi_dsi_lpmode cmdin_lp, + enum nx_mipi_dsi_lpmode txinlp) +{ + register struct nx_mipi_register_set *pregister; + register u32 regvalue; + u32 newvalue = 0; + + pregister = __g_pregister[module_index]; + newvalue |= (cmdin_lp << 7); + newvalue |= (txinlp << 6); + writereg(dsim_escmode, 0xC0, newvalue); +} + +void nx_mipi_dsi_remote_reset_trigger(u32 module_index) +{ + register struct nx_mipi_register_set *pregister; + register u32 regvalue; + u32 newvalue; + + pregister = __g_pregister[module_index]; + newvalue = (1 << 4); + writereg(dsim_escmode, (1 << 4), newvalue); + + while (readl(&pregister->dsim_escmode) & (1 << 4)) + ; +} + +void nx_mipi_dsi_set_ulps(u32 module_index, int ulpsclocklane, int ulpsdatalane) +{ + register struct nx_mipi_register_set *pregister; + register u32 regvalue; + + pregister = __g_pregister[module_index]; + regvalue = pregister->dsim_escmode; + + if (ulpsclocklane) { + regvalue &= ~(1 << 0); + regvalue |= (1 << 1); + } else { + regvalue |= (1 << 0); + } + + if (ulpsdatalane) { + regvalue &= ~(1 << 2); + regvalue |= (1 << 3); + } else { + regvalue |= (1 << 2); + } + + writel(regvalue, &pregister->dsim_escmode); + + if (ulpsclocklane) + while ((1 << 9) == + (readl(&pregister->dsim_status) & (1 << 9))) + ; + else + while (0 != (readl(&pregister->dsim_status) & (1 << 9))) + ; + + if (ulpsdatalane) + while ((15 << 4) == + (readl(&pregister->dsim_status) & (15 << 4))) + ; + else + while (0 != (readl(&pregister->dsim_status) & (15 << 4))) + ; + + if (!ulpsclocklane) + regvalue &= (3 << 0); + + if (!ulpsdatalane) + regvalue |= (3 << 2); + + writel(regvalue, &pregister->dsim_escmode); +} + +void nx_mipi_dsi_set_size(u32 module_index, u32 width, u32 height) +{ + register struct nx_mipi_register_set *pregister; + register u32 regvalue; + u32 newvalue; + + pregister = __g_pregister[module_index]; + newvalue = (height << 16); + newvalue |= (width << 0); + writereg(dsim_mdresol, 0x0FFFFFFF, newvalue); +} + +void nx_mipi_dsi_set_enable(u32 module_index, int enable) +{ + register struct nx_mipi_register_set *pregister; + register u32 regvalue; + + pregister = __g_pregister[module_index]; + writereg(dsim_mdresol, (1 << 31), (enable << 31)); +} + +void nx_mipi_dsi_set_phy(u32 module_index, u32 number_of_data_lanes, + int enable_clock_lane, int enable_data_lane0, + int enable_data_lane1, int enable_data_lane2, + int enable_data_lane3, int swap_clock_lane, + int swap_data_lane) +{ + register struct nx_mipi_register_set *pregister; + register u32 regvalue; + u32 newvalue; + + pregister = __g_pregister[module_index]; + newvalue = (number_of_data_lanes << 5); + newvalue |= (enable_clock_lane << 0); + newvalue |= (enable_data_lane0 << 1); + newvalue |= (enable_data_lane1 << 2); + newvalue |= (enable_data_lane2 << 3); + newvalue |= (enable_data_lane3 << 4); + writereg(dsim_config, 0xFF, newvalue); + newvalue = (swap_clock_lane << 1); + newvalue |= (swap_data_lane << 0); + writereg(dsim_phyacchr1, 0x3, newvalue); +} + +void nx_mipi_dsi_set_pll(u32 module_index, int enable, u32 pllstabletimer, + u32 m_pllpms, u32 m_bandctl, u32 m_dphyctl, + u32 b_dphyctl) +{ + register struct nx_mipi_register_set *pregister; + register u32 regvalue; + u32 newvalue; + + pregister = __g_pregister[module_index]; + if (!enable) { + newvalue = (enable << 23); + newvalue |= (m_pllpms << 1); + newvalue |= (m_bandctl << 24); + writereg(dsim_pllctrl, 0x0FFFFFFF, newvalue); + } + + writel(m_dphyctl, &pregister->dsim_phyacchr); + writel(pllstabletimer, &pregister->dsim_plltmr); + writel((b_dphyctl << 9), &pregister->dsim_phyacchr1); + + if (enable) { + newvalue = (enable << 23); + newvalue |= (m_pllpms << 1); + newvalue |= (m_bandctl << 24); + writereg(dsim_pllctrl, 0x0FFFFFFF, newvalue); + } +} + +void nx_mipi_dsi_write_pkheader(u32 module_index, u32 data) +{ + register struct nx_mipi_register_set *pregister; + + pregister = __g_pregister[module_index]; + writel(data, &pregister->dsim_pkthdr); +} + +void nx_mipi_dsi_write_payload(u32 module_index, u32 data) +{ + register struct nx_mipi_register_set *pregister; + + pregister = __g_pregister[module_index]; + writel(data, &pregister->dsim_payload); +} + +u32 nx_mipi_dsi_read_fifo_status(u32 module_index) +{ + register struct nx_mipi_register_set *pregister; + + pregister = __g_pregister[module_index]; + return readl(&pregister->dsim_fifoctrl); +} diff --git a/drivers/video/nexell/soc/s5pxx18_soc_mipi.h b/drivers/video/nexell/soc/s5pxx18_soc_mipi.h new file mode 100644 index 0000000000..63751ca83f --- /dev/null +++ b/drivers/video/nexell/soc/s5pxx18_soc_mipi.h @@ -0,0 +1,291 @@ +/* SPDX-License-Identifier: GPL-2.0+ + * + * Copyright (C) 2016 Nexell Co., Ltd. + * + * Author: junghyun, kim <jhkim@nexell.co.kr> + */ + +#ifndef _S5PXX18_SOC_MIPI_H_ +#define _S5PXX18_SOC_MIPI_H_ + +#define NUMBER_OF_MIPI_MODULE 1 +#define PHY_BASEADDR_MIPI_MODULE 0xC00D0000 +#define PHY_BASEADDR_MIPI_LIST \ + { PHY_BASEADDR_MIPI_MODULE } + +#define nx_mipi_numberof_csi_channels 2 + +struct nx_mipi_register_set { + u32 csis_control; + u32 csis_dphyctrl; + u32 csis_config_ch0; + u32 csis_dphysts; + u32 csis_intmsk; + u32 csis_intsrc; + u32 csis_ctrl2; + u32 csis_version; + u32 csis_dphyctrl_0; + u32 csis_dphyctrl_1; + u32 __reserved0; + u32 csis_resol_ch0; + u32 __reserved1; + u32 __reserved2; + u32 sdw_config_ch0; + u32 sdw_resol_ch0; + u32 csis_config_ch1; + u32 csis_resol_ch1; + u32 sdw_config_ch1; + u32 sdw_resol_ch1; + u32 csis_config_ch2; + u32 csis_resol_ch2; + u32 sdw_config_ch2; + u32 sdw_resol_ch2; + u32 csis_config_ch3; + u32 csis_resol_ch3; + u32 sdw_config_ch3; + u32 sdw_resol_3; + u32 __reserved3[(16 + 128) / 4]; + + u32 dsim_status; + u32 dsim_swrst; + u32 dsim_clkctrl; + u32 dsim_timeout; + u32 dsim_config; + u32 dsim_escmode; + u32 dsim_mdresol; + u32 dsim_mvporch; + u32 dsim_mhporch; + u32 dsim_msync; + u32 dsim_sdresol; + u32 dsim_intsrc; + u32 dsim_intmsk; + u32 dsim_pkthdr; + u32 dsim_payload; + u32 dsim_rxfifo; + u32 dsim_fifothld; + u32 dsim_fifoctrl; + u32 dsim_memacchr; + u32 dsim_pllctrl; + u32 dsim_plltmr; + u32 dsim_phyacchr; + u32 dsim_phyacchr1; + + u32 __reserved4[(0x2000 - 0x015C) / 4]; + u32 mipi_csis_pktdata[0x2000 / 4]; +}; + +enum nx_mipi_dsi_syncmode { + nx_mipi_dsi_syncmode_event = 0, + nx_mipi_dsi_syncmode_pulse = 1, +}; + +enum nx_mipi_dsi_format { + nx_mipi_dsi_format_command3 = 0, + nx_mipi_dsi_format_command8 = 1, + nx_mipi_dsi_format_command12 = 2, + nx_mipi_dsi_format_command16 = 3, + nx_mipi_dsi_format_rgb565 = 4, + nx_mipi_dsi_format_rgb666_packed = 5, + nx_mipi_dsi_format_rgb666 = 6, + nx_mipi_dsi_format_rgb888 = 7 +}; + +enum nx_mipi_dsi_lpmode { + nx_mipi_dsi_lpmode_hs = 0, + nx_mipi_dsi_lpmode_lp = 1 +}; + +enum nx_mipi_phy_b_dphyctl { + nx_mipi_phy_b_dphyctl_m_txclkesc_20_mhz = 0x1F4, + nx_mipi_phy_b_dphyctl_m_txclkesc_19_mhz = 0x1DB, + nx_mipi_phy_b_dphyctl_m_txclkesc_18_mhz = 0x1C2, + nx_mipi_phy_b_dphyctl_m_txclkesc_17_mhz = 0x1A9, + nx_mipi_phy_b_dphyctl_m_txclkesc_16_mhz = 0x190, + nx_mipi_phy_b_dphyctl_m_txclkesc_15_mhz = 0x177, + nx_mipi_phy_b_dphyctl_m_txclkesc_14_mhz = 0x15E, + nx_mipi_phy_b_dphyctl_m_txclkesc_13_mhz = 0x145, + nx_mipi_phy_b_dphyctl_m_txclkesc_12_mhz = 0x12C, + nx_mipi_phy_b_dphyctl_m_txclkesc_11_mhz = 0x113, + nx_mipi_phy_b_dphyctl_m_txclkesc_10_mhz = 0x0FA, + nx_mipi_phy_b_dphyctl_m_txclkesc_9_mhz = 0x0E1, + nx_mipi_phy_b_dphyctl_m_txclkesc_8_mhz = 0x0C8, + nx_mipi_phy_b_dphyctl_m_txclkesc_7_mhz = 0x0AF, + nx_mipi_phy_b_dphyctl_m_txclkesc_6_mhz = 0x096, + nx_mipi_phy_b_dphyctl_m_txclkesc_5_mhz = 0x07D, + nx_mipi_phy_b_dphyctl_m_txclkesc_4_mhz = 0x064, + nx_mipi_phy_b_dphyctl_m_txclkesc_3_mhz = 0x04B, + nx_mipi_phy_b_dphyctl_m_txclkesc_2_mhz = 0x032, + nx_mipi_phy_b_dphyctl_m_txclkesc_1_mhz = 0x019, + nx_mipi_phy_b_dphyctl_m_txclkesc_0_10_mhz = 0x003, + nx_mipi_phy_b_dphyctl_m_txclkesc_0_01_mhz = 0x000 +}; + +enum { + nx_mipi_rst = 0, + nx_mipi_rst_dsi_i, + nx_mipi_rst_csi_i, + nx_mipi_rst_phy_s, + nx_mipi_rst_phy_m +}; + +enum nx_mipi_int { + nx_mipi_int_csi_even_before = 31, + nx_mipi_int_csi_even_after = 30, + nx_mipi_int_csi_odd_before = 29, + nx_mipi_int_csi_odd_after = 28, + nx_mipi_int_csi_frame_start_ch3 = 27, + nx_mipi_int_csi_frame_start_ch2 = 26, + nx_mipi_int_csi_frame_start_ch1 = 25, + nx_mipi_int_csi_frame_start_ch0 = 24, + nx_mipi_int_csi_frame_end_ch3 = 23, + nx_mipi_int_csi_frame_end_ch2 = 22, + nx_mipi_int_csi_frame_end_ch1 = 21, + nx_mipi_int_csi_frame_end_ch0 = 20, + nx_mipi_int_csi_err_sot_hs_ch3 = 19, + nx_mipi_int_csi_err_sot_hs_ch2 = 18, + nx_mipi_int_csi_err_sot_hs_ch1 = 17, + nx_mipi_int_csi_err_sot_hs_ch0 = 16, + nx_mipi_int_csi_err_lost_fs_ch3 = 15, + nx_mipi_int_csi_err_lost_fs_ch2 = 14, + nx_mipi_int_csi_err_lost_fs_ch1 = 13, + nx_mipi_int_csi_err_lost_fs_ch0 = 12, + nx_mipi_int_csi_err_lost_fe_ch3 = 11, + nx_mipi_int_csi_err_lost_fe_ch2 = 10, + nx_mipi_int_csi_err_lost_fe_ch1 = 9, + nx_mipi_int_csi_err_lost_fe_ch0 = 8, + nx_mipi_int_csi_err_over_ch3 = 7, + nx_mipi_int_csi_err_over_ch2 = 6, + nx_mipi_int_csi_err_over_ch1 = 5, + nx_mipi_int_csi_err_over_ch0 = 4, + + nx_mipi_int_csi_err_ecc = 2, + nx_mipi_int_csi_err_crc = 1, + nx_mipi_int_csi_err_id = 0, + nx_mipi_int_dsi_pll_stable = 32 + 31, + nx_mipi_int_dsi_sw_rst_release = 32 + 30, + nx_mipi_int_dsi_sfrplfifoempty = 32 + 29, + nx_mipi_int_dsi_sfrphfifoempty = 32 + 28, + nx_mipi_int_dsi_sync_override = 32 + 27, + + nx_mipi_int_dsi_bus_turn_over = 32 + 25, + nx_mipi_int_dsi_frame_done = 32 + 24, + + nx_mipi_int_dsi_lpdr_tout = 32 + 21, + nx_mipi_int_dsi_ta_tout = 32 + 20, + + nx_mipi_int_dsi_rx_dat_done = 32 + 18, + nx_mipi_int_dsi_rx_te = 32 + 17, + nx_mipi_int_dsi_rx_ack = 32 + 16, + nx_mipi_int_dsi_err_rx_ecc = 32 + 15, + nx_mipi_int_dsi_err_rx_crc = 32 + 14, + nx_mipi_int_dsi_err_esc3 = 32 + 13, + nx_mipi_int_dsi_err_esc2 = 32 + 12, + nx_mipi_int_dsi_err_esc1 = 32 + 11, + nx_mipi_int_dsi_err_esc0 = 32 + 10, + nx_mipi_int_dsi_err_sync3 = 32 + 9, + nx_mipi_int_dsi_err_sync2 = 32 + 8, + nx_mipi_int_dsi_err_sync1 = 32 + 7, + nx_mipi_int_dsi_err_sync0 = 32 + 6, + nx_mipi_int_dsi_err_control3 = 32 + 5, + nx_mipi_int_dsi_err_control2 = 32 + 4, + nx_mipi_int_dsi_err_control1 = 32 + 3, + nx_mipi_int_dsi_err_control0 = 32 + 2, + nx_mipi_int_dsi_err_content_lp0 = 32 + 1, + nx_mipi_int_dsi_err_content_lp1 = 32 + 0, +}; + +#define DSI_TX_FIFO_SIZE 2048 +#define DSI_RX_FIFO_SIZE 256 +#define DSI_RX_FIFO_EMPTY 0x30800002 + +void nx_mipi_dsi_get_status(u32 module_index, u32 *pulps, u32 *pstop, + u32 *pispllstable, u32 *pisinreset, + u32 *pisbackward, u32 *pishsclockready); + +void nx_mipi_dsi_software_reset(u32 module_index); + +void nx_mipi_dsi_set_clock(u32 module_index, int enable_txhsclock, + int use_external_clock, int enable_byte_clock, + int enable_escclock_clock_lane, + int enable_escclock_data_lane0, + int enable_escclock_data_lane1, + int enable_escclock_data_lane2, + int enable_escclock_data_lane3, + int enable_escprescaler, + u32 escprescalervalue); + +void nx_mipi_dsi_set_timeout(u32 module_index, u32 bta_tout, + u32 lpdrtout); + +void nx_mipi_dsi_set_config_video_mode(u32 module_index, + int enable_auto_flush_main_display_fifo, + int enable_auto_vertical_count, + int enable_burst, + enum nx_mipi_dsi_syncmode + sync_mode, int enable_eo_tpacket, + int enable_hsync_end_packet, + int enable_hfp, int enable_hbp, + int enable_hsa, + u32 number_of_virtual_channel, + enum nx_mipi_dsi_format format, + u32 number_of_words_in_hfp, + u32 number_of_words_in_hbp, + u32 number_of_words_in_hsync, + u32 number_of_lines_in_vfp, + u32 number_of_lines_in_vbp, + u32 number_of_lines_in_vsync, + u32 number_of_lines_in_command_allow); + +void nx_mipi_dsi_set_config_command_mode(u32 module_index, + int enable_auto_flush_main_display_fifo, + int enable_eo_tpacket, + u32 number_of_virtual_channel, + enum nx_mipi_dsi_format format); + +void nx_mipi_dsi_set_escape_mode(u32 module_index, u32 stop_state_count, + int force_stop_state, int force_bta, + enum nx_mipi_dsi_lpmode cmdin_lp, + enum nx_mipi_dsi_lpmode txinlp); +void nx_mipi_dsi_set_escape_lp(u32 module_index, + enum nx_mipi_dsi_lpmode cmdin_lp, + enum nx_mipi_dsi_lpmode txinlp); + +void nx_mipi_dsi_remote_reset_trigger(u32 module_index); +void nx_mipi_dsi_set_ulps(u32 module_index, int ulpsclocklane, + int ulpsdatalane); +void nx_mipi_dsi_set_size(u32 module_index, u32 width, u32 height); +void nx_mipi_dsi_set_enable(u32 module_index, int enable); +void nx_mipi_dsi_set_phy(u32 module_index, u32 number_of_data_lanes, + int enable_clock_lane, int enable_data_lane0, + int enable_data_lane1, int enable_data_lane2, + int enable_data_lane3, int swap_clock_lane, + int swap_data_lane); + +void nx_mipi_dsi_set_pll(u32 module_index, int enable, + u32 pllstabletimer, u32 m_pllpms, u32 m_bandctl, + u32 m_dphyctl, u32 b_dphyctl); + +void nx_mipi_dsi_write_pkheader(u32 module_index, u32 data); +void nx_mipi_dsi_write_payload(u32 module_index, u32 data); +u32 nx_mipi_dsi_read_fifo(u32 module_index); +u32 nx_mipi_dsi_read_fifo_status(u32 module_index); + +int nx_mipi_smoke_test(u32 module_index); +void nx_mipi_set_base_address(u32 module_index, void *base_address); +void *nx_mipi_get_base_address(u32 module_index); +u32 nx_mipi_get_physical_address(u32 module_index); + +void nx_mipi_dsi_set_interrupt_enable_all(u32 module_index, int enable); +void nx_mipi_dsi_set_interrupt_enable(u32 module_index, + u32 int_num, int enable); +int nx_mipi_dsi_get_interrupt_enable(u32 module_index, u32 int_num); +int nx_mipi_dsi_get_interrupt_enable_all(u32 module_index); + +int nx_mipi_dsi_get_interrupt_pending(u32 module_index, u32 int_num); +int nx_mipi_dsi_get_interrupt_pending_all(u32 module_index); +int32_t nx_mipi_dsi_get_interrupt_pending_number(u32 module_index); + +void nx_mipi_dsi_clear_interrupt_pending(u32 module_index, u32 int_num); +void nx_mipi_dsi_clear_interrupt_pending_all(u32 module_index); + +#endif diff --git a/drivers/video/nexell/soc/s5pxx18_soc_mlc.c b/drivers/video/nexell/soc/s5pxx18_soc_mlc.c new file mode 100644 index 0000000000..c8cf833f30 --- /dev/null +++ b/drivers/video/nexell/soc/s5pxx18_soc_mlc.c @@ -0,0 +1,1861 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2016 Nexell Co., Ltd. + * + * Author: junghyun, kim <jhkim@nexell.co.kr> + */ + +#include <linux/types.h> +#include <linux/io.h> + +#include "s5pxx18_soc_mlc.h" + +static struct { + struct nx_mlc_register_set *pregister; +} __g_module_variables[NUMBER_OF_MLC_MODULE] = { { NULL, },}; + +int nx_mlc_initialize(void) +{ + static int binit; + u32 i; + + if (binit == 0) { + for (i = 0; i < NUMBER_OF_MLC_MODULE; i++) + __g_module_variables[i].pregister = NULL; + binit = 1; + } + return 1; +} + +u32 nx_mlc_get_physical_address(u32 module_index) +{ + const u32 physical_addr[] = PHY_BASEADDR_MLC_LIST; + + return physical_addr[module_index]; +} + +void nx_mlc_set_base_address(u32 module_index, void *base_address) +{ + __g_module_variables[module_index].pregister = + (struct nx_mlc_register_set *)base_address; +} + +void *nx_mlc_get_base_address(u32 module_index) +{ + return (void *)__g_module_variables[module_index].pregister; +} + +void nx_mlc_set_clock_pclk_mode(u32 module_index, enum nx_pclkmode mode) +{ + const u32 pclkmode_pos = 3; + u32 clkmode = 0; + + register u32 regvalue; + register struct nx_mlc_register_set *pregister; + + pregister = __g_module_variables[module_index].pregister; + switch (mode) { + case nx_pclkmode_dynamic: + clkmode = 0; + break; + case nx_pclkmode_always: + clkmode = 1; + break; + default: + break; + } + regvalue = pregister->mlcclkenb; + regvalue &= ~(1ul << pclkmode_pos); + regvalue |= (clkmode & 0x01) << pclkmode_pos; + + writel(regvalue, &pregister->mlcclkenb); +} + +enum nx_pclkmode nx_mlc_get_clock_pclk_mode(u32 module_index) +{ + const u32 pclkmode_pos = 3; + + if (__g_module_variables[module_index].pregister->mlcclkenb & + (1ul << pclkmode_pos)) { + return nx_pclkmode_always; + } + return nx_pclkmode_dynamic; +} + +void nx_mlc_set_clock_bclk_mode(u32 module_index, enum nx_bclkmode mode) +{ + register u32 regvalue; + register struct nx_mlc_register_set *pregister; + u32 clkmode = 0; + + pregister = __g_module_variables[module_index].pregister; + switch (mode) { + case nx_bclkmode_disable: + clkmode = 0; + break; + case nx_bclkmode_dynamic: + clkmode = 2; + break; + case nx_bclkmode_always: + clkmode = 3; + break; + default: + break; + } + regvalue = pregister->mlcclkenb; + regvalue &= ~(0x3); + regvalue |= clkmode & 0x3; + + writel(regvalue, &pregister->mlcclkenb); +} + +enum nx_bclkmode nx_mlc_get_clock_bclk_mode(u32 module_index) +{ + const u32 bclkmode = 3ul << 0; + + switch (__g_module_variables[module_index].pregister->mlcclkenb & + bclkmode) { + case 0: + return nx_bclkmode_disable; + case 2: + return nx_bclkmode_dynamic; + case 3: + return nx_bclkmode_always; + } + return nx_bclkmode_disable; +} + +void nx_mlc_set_top_power_mode(u32 module_index, int bpower) +{ + const u32 pixelbuffer_pwd_pos = 11; + const u32 pixelbuffer_pwd_mask = 1ul << pixelbuffer_pwd_pos; + const u32 dittyflag_mask = 1ul << 3; + register struct nx_mlc_register_set *pregister; + register u32 regvalue; + + pregister = __g_module_variables[module_index].pregister; + regvalue = pregister->mlccontrolt; + regvalue &= ~(pixelbuffer_pwd_mask | dittyflag_mask); + regvalue |= (bpower << pixelbuffer_pwd_pos); + + writel(regvalue, &pregister->mlccontrolt); +} + +int nx_mlc_get_top_power_mode(u32 module_index) +{ + const u32 pixelbuffer_pwd_pos = 11; + const u32 pixelbuffer_pwd_mask = 1ul << pixelbuffer_pwd_pos; + + return (int)((__g_module_variables[module_index].pregister->mlccontrolt + & pixelbuffer_pwd_mask) >> + pixelbuffer_pwd_pos); +} + +void nx_mlc_set_top_sleep_mode(u32 module_index, int bsleep) +{ + const u32 pixelbuffer_sld_pos = 10; + const u32 pixelbuffer_sld_mask = 1ul << pixelbuffer_sld_pos; + const u32 dittyflag_mask = 1ul << 3; + register struct nx_mlc_register_set *pregister; + register u32 regvalue; + + bsleep = (int)((u32)bsleep ^ 1); + pregister = __g_module_variables[module_index].pregister; + regvalue = pregister->mlccontrolt; + regvalue &= ~(pixelbuffer_sld_mask | dittyflag_mask); + regvalue |= (bsleep << pixelbuffer_sld_pos); + + writel(regvalue, &pregister->mlccontrolt); +} + +int nx_mlc_get_top_sleep_mode(u32 module_index) +{ + const u32 pixelbuffer_sld_pos = 11; + const u32 pixelbuffer_sld_mask = 1ul << pixelbuffer_sld_pos; + + return (int)(((__g_module_variables[module_index].pregister->mlccontrolt + & pixelbuffer_sld_mask) >> + pixelbuffer_sld_pos) ^ 0x01); +} + +void nx_mlc_set_top_dirty_flag(u32 module_index) +{ + const u32 dirtyflag = 1ul << 3; + register struct nx_mlc_register_set *pregister; + register u32 regvalue; + + pregister = __g_module_variables[module_index].pregister; + regvalue = pregister->mlccontrolt; + regvalue |= dirtyflag; + + writel(regvalue, &pregister->mlccontrolt); +} + +int nx_mlc_get_top_dirty_flag(u32 module_index) +{ + const u32 dirtyflag_pos = 3; + const u32 dirtyflag_mask = 1ul << dirtyflag_pos; + + return (int)((readl(&__g_module_variables[module_index] + .pregister->mlccontrolt) & + dirtyflag_mask) >> dirtyflag_pos); +} + +void nx_mlc_set_mlc_enable(u32 module_index, int benb) +{ + const u32 mlcenb_pos = 1; + const u32 mlcenb_mask = 1ul << mlcenb_pos; + const u32 dirtyflag_pos = 3; + const u32 dirtyflag_mask = 1ul << dirtyflag_pos; + register u32 regvalue; + register struct nx_mlc_register_set *pregister; + + pregister = __g_module_variables[module_index].pregister; + regvalue = pregister->mlccontrolt; + regvalue &= ~(mlcenb_mask | dirtyflag_mask); + regvalue |= (benb << mlcenb_pos); + + writel(regvalue, &pregister->mlccontrolt); +} + +int nx_mlc_get_mlc_enable(u32 module_index) +{ + const u32 mlcenb_pos = 1; + const u32 mlcenb_mask = 1ul << mlcenb_pos; + + return (int)((__g_module_variables[module_index].pregister->mlccontrolt + & mlcenb_mask) >> mlcenb_pos); +} + +void nx_mlc_set_field_enable(u32 module_index, int benb) +{ + const u32 fieldenb_pos = 0; + const u32 fieldenb_mask = 1ul << fieldenb_pos; + const u32 dirtyflag_pos = 3; + const u32 dirtyflag_mask = 1ul << dirtyflag_pos; + register u32 regvalue; + register struct nx_mlc_register_set *pregister; + + pregister = __g_module_variables[module_index].pregister; + regvalue = pregister->mlccontrolt; + regvalue &= ~(fieldenb_mask | dirtyflag_mask); + regvalue |= (benb << fieldenb_pos); + + writel(regvalue, &pregister->mlccontrolt); +} + +int nx_mlc_get_field_enable(u32 module_index) +{ + const u32 fieldenb_pos = 0; + const u32 fieldenb_mask = 1ul << fieldenb_pos; + + return (int)(__g_module_variables[module_index].pregister->mlccontrolt & + fieldenb_mask); +} + +void nx_mlc_set_layer_priority(u32 module_index, enum nx_mlc_priority priority) +{ + const u32 priority_pos = 8; + const u32 priority_mask = 0x03 << priority_pos; + const u32 dirtyflag_pos = 3; + const u32 dirtyflag_mask = 1ul << dirtyflag_pos; + register struct nx_mlc_register_set *pregister; + register u32 regvalue; + + pregister = __g_module_variables[module_index].pregister; + regvalue = pregister->mlccontrolt; + regvalue &= ~(priority_mask | dirtyflag_mask); + regvalue |= (priority << priority_pos); + + writel(regvalue, &pregister->mlccontrolt); +} + +void nx_mlc_set_screen_size(u32 module_index, u32 width, u32 height) +{ + register struct nx_mlc_register_set *pregister; + register u32 regvalue; + + pregister = __g_module_variables[module_index].pregister; + regvalue = ((height - 1) << 16) | (width - 1); + + writel(regvalue, &pregister->mlcscreensize); +} + +void nx_mlc_get_screen_size(u32 module_index, u32 *pwidth, u32 *pheight) +{ + register struct nx_mlc_register_set *pregister; + + pregister = __g_module_variables[module_index].pregister; + + if (pwidth) + *pwidth = (pregister->mlcscreensize & 0x0fff) + 1; + + if (pheight) + *pheight = ((pregister->mlcscreensize >> 16) & 0x0fff) + 1; +} + +void nx_mlc_set_background(u32 module_index, u32 color) +{ + register struct nx_mlc_register_set *pregister; + + pregister = __g_module_variables[module_index].pregister; + writel(color, &pregister->mlcbgcolor); +} + +void nx_mlc_set_dirty_flag(u32 module_index, u32 layer) +{ + register struct nx_mlc_register_set *pregister; + register u32 regvalue; + const u32 dirtyflg_mask = 1ul << 4; + + pregister = __g_module_variables[module_index].pregister; + if (layer == 0 || layer == 1) { + regvalue = pregister->mlcrgblayer[layer].mlccontrol; + regvalue |= dirtyflg_mask; + + writel(regvalue, &pregister->mlcrgblayer[layer].mlccontrol); + } else if (layer == 3) { + regvalue = pregister->mlcvideolayer.mlccontrol; + regvalue |= dirtyflg_mask; + + writel(regvalue, &pregister->mlcvideolayer.mlccontrol); + } +} + +int nx_mlc_get_dirty_flag(u32 module_index, u32 layer) +{ + const u32 dirtyflg_pos = 4; + const u32 dirtyflg_mask = 1ul << dirtyflg_pos; + + if (layer == 0 || layer == 1) { + return (int)((__g_module_variables[module_index] + .pregister->mlcrgblayer[layer] + .mlccontrol & dirtyflg_mask) >> dirtyflg_pos); + } else if (layer == 2) { + return (int)((__g_module_variables[module_index] + .pregister->mlcrgblayer2.mlccontrol & + dirtyflg_mask) >> dirtyflg_pos); + } else if (layer == 3) { + return (int)((__g_module_variables[module_index] + .pregister->mlcvideolayer.mlccontrol & + dirtyflg_mask) >> dirtyflg_pos); + } + return 0; +} + +void nx_mlc_set_layer_enable(u32 module_index, u32 layer, int benb) +{ + const u32 layerenb_pos = 5; + const u32 layerenb_mask = 0x01 << layerenb_pos; + const u32 dirtyflag_pos = 4; + const u32 dirtyflag_mask = 1ul << dirtyflag_pos; + register u32 regvalue; + register struct nx_mlc_register_set *pregister; + + pregister = __g_module_variables[module_index].pregister; + if (layer == 0 || layer == 1) { + regvalue = pregister->mlcrgblayer[layer].mlccontrol; + regvalue &= ~(layerenb_mask | dirtyflag_mask); + regvalue |= (benb << layerenb_pos); + + writel(regvalue, &pregister->mlcrgblayer[layer].mlccontrol); + } else if (layer == 3) { + regvalue = pregister->mlcvideolayer.mlccontrol; + regvalue &= ~(layerenb_mask | dirtyflag_mask); + regvalue |= (benb << layerenb_pos); + + writel(regvalue, &pregister->mlcvideolayer.mlccontrol); + } +} + +int nx_mlc_get_layer_enable(u32 module_index, u32 layer) +{ + const u32 layerenb_pos = 5; + const u32 layerenb_mask = 0x01 << layerenb_pos; + + if (layer == 0 || layer == 1) { + return (int)((__g_module_variables[module_index] + .pregister->mlcrgblayer[layer] + .mlccontrol & layerenb_mask) >> layerenb_pos); + } else if (layer == 3) { + return (int)((__g_module_variables[module_index] + .pregister->mlcvideolayer.mlccontrol & + layerenb_mask) >> layerenb_pos); + } + return 0; +} + +void nx_mlc_set_lock_size(u32 module_index, u32 layer, u32 locksize) +{ + const u32 locksize_mask = 3ul << 12; + const u32 dirtyflag_pos = 4; + const u32 dirtyflag_mask = 1ul << dirtyflag_pos; + register struct nx_mlc_register_set *pregister; + register u32 regvalue; + + pregister = __g_module_variables[module_index].pregister; + locksize >>= 3; + if (layer == 0 || layer == 1) { + regvalue = pregister->mlcrgblayer[layer].mlccontrol; + regvalue &= ~(locksize_mask | dirtyflag_mask); + regvalue |= (locksize << 12); + + writel(regvalue, &pregister->mlcrgblayer[layer].mlccontrol); + } +} + +void nx_mlc_set_alpha_blending(u32 module_index, u32 layer, int benb, u32 alpha) +{ + const u32 blendenb_pos = 2; + const u32 blendenb_mask = 0x01 << blendenb_pos; + const u32 dirtyflag_pos = 4; + const u32 dirtyflag_mask = 1ul << dirtyflag_pos; + const u32 alpha_pos = 28; + const u32 alpha_mask = 0xf << alpha_pos; + register u32 regvalue; + register struct nx_mlc_register_set *pregister; + + pregister = __g_module_variables[module_index].pregister; + if (layer == 0 || layer == 1) { + regvalue = pregister->mlcrgblayer[layer].mlccontrol; + regvalue &= ~(blendenb_mask | dirtyflag_mask); + regvalue |= (benb << blendenb_pos); + + writel(regvalue, &pregister->mlcrgblayer[layer].mlccontrol); + regvalue = pregister->mlcrgblayer[layer].mlctpcolor; + regvalue &= ~alpha_mask; + regvalue |= alpha << alpha_pos; + + writel(regvalue, &pregister->mlcrgblayer[layer].mlctpcolor); + } else if (layer == 3) { + regvalue = pregister->mlcvideolayer.mlccontrol; + regvalue &= ~(blendenb_mask | dirtyflag_mask); + regvalue |= (benb << blendenb_pos); + + writel(regvalue, &pregister->mlcvideolayer.mlccontrol); + + writel(alpha << alpha_pos, + &pregister->mlcvideolayer.mlctpcolor); + } +} + +void nx_mlc_set_transparency(u32 module_index, u32 layer, int benb, u32 color) +{ + const u32 tpenb_pos = 0; + const u32 tpenb_mask = 0x01 << tpenb_pos; + const u32 dirtyflag_pos = 4; + const u32 dirtyflag_mask = 1ul << dirtyflag_pos; + const u32 tpcolor_pos = 0; + const u32 tpcolor_mask = ((1 << 24) - 1) << tpcolor_pos; + register u32 regvalue; + register struct nx_mlc_register_set *pregister; + + pregister = __g_module_variables[module_index].pregister; + if (layer == 0 || layer == 1) { + regvalue = pregister->mlcrgblayer[layer].mlccontrol; + regvalue &= ~(tpenb_mask | dirtyflag_mask); + regvalue |= (benb << tpenb_pos); + + writel(regvalue, &pregister->mlcrgblayer[layer].mlccontrol); + regvalue = pregister->mlcrgblayer[layer].mlctpcolor; + regvalue &= ~tpcolor_mask; + regvalue |= (color & tpcolor_mask); + + writel(regvalue, &pregister->mlcrgblayer[layer].mlctpcolor); + } +} + +void nx_mlc_set_color_inversion(u32 module_index, u32 layer, int benb, + u32 color) +{ + const u32 invenb_pos = 1; + const u32 invenb_mask = 0x01 << invenb_pos; + const u32 dirtyflag_pos = 4; + const u32 dirtyflag_mask = 1ul << dirtyflag_pos; + const u32 invcolor_pos = 0; + const u32 invcolor_mask = ((1 << 24) - 1) << invcolor_pos; + register u32 regvalue; + register struct nx_mlc_register_set *pregister; + + pregister = __g_module_variables[module_index].pregister; + if (layer == 0 || layer == 1) { + regvalue = pregister->mlcrgblayer[layer].mlccontrol; + regvalue &= ~(invenb_mask | dirtyflag_mask); + regvalue |= (benb << invenb_pos); + + writel(regvalue, &pregister->mlcrgblayer[layer].mlccontrol); + regvalue = pregister->mlcrgblayer[layer].mlcinvcolor; + regvalue &= ~invcolor_mask; + regvalue |= (color & invcolor_mask); + + writel(regvalue, &pregister->mlcrgblayer[layer].mlcinvcolor); + } +} + +u32 nx_mlc_get_extended_color(u32 module_index, u32 color, + enum nx_mlc_rgbfmt format) +{ + u32 rgb[3] = { + 0, + }; + u32 bw[3] = { + 0, + }; + u32 bp[3] = { + 0, + }; + u32 blank = 0; + u32 fill = 0; + u32 i = 0; + + switch (format) { + case nx_mlc_rgbfmt_r5g6b5: + bw[0] = 5; + bw[1] = 6; + bw[2] = 5; + bp[0] = 11; + bp[1] = 5; + bp[2] = 0; + break; + case nx_mlc_rgbfmt_b5g6r5: + bw[0] = 5; + bw[1] = 6; + bw[2] = 5; + bp[0] = 0; + bp[1] = 5; + bp[2] = 11; + break; + case nx_mlc_rgbfmt_x1r5g5b5: + case nx_mlc_rgbfmt_a1r5g5b5: + bw[0] = 5; + bw[1] = 5; + bw[2] = 5; + bp[0] = 10; + bp[1] = 5; + bp[2] = 0; + break; + case nx_mlc_rgbfmt_x1b5g5r5: + case nx_mlc_rgbfmt_a1b5g5r5: + bw[0] = 5; + bw[1] = 5; + bw[2] = 5; + bp[0] = 0; + bp[1] = 5; + bp[2] = 10; + break; + case nx_mlc_rgbfmt_x4r4g4b4: + case nx_mlc_rgbfmt_a4r4g4b4: + bw[0] = 4; + bw[1] = 4; + bw[2] = 4; + bp[0] = 8; + bp[1] = 4; + bp[2] = 0; + break; + case nx_mlc_rgbfmt_x4b4g4r4: + case nx_mlc_rgbfmt_a4b4g4r4: + bw[0] = 4; + bw[1] = 4; + bw[2] = 4; + bp[0] = 0; + bp[1] = 4; + bp[2] = 8; + break; + case nx_mlc_rgbfmt_x8r3g3b2: + case nx_mlc_rgbfmt_a8r3g3b2: + bw[0] = 3; + bw[1] = 3; + bw[2] = 2; + bp[0] = 5; + bp[1] = 2; + bp[2] = 0; + break; + case nx_mlc_rgbfmt_x8b3g3r2: + case nx_mlc_rgbfmt_a8b3g3r2: + bw[0] = 2; + bw[1] = 3; + bw[2] = 3; + bp[0] = 0; + bp[1] = 2; + bp[2] = 5; + break; + case nx_mlc_rgbfmt_r8g8b8: + case nx_mlc_rgbfmt_a8r8g8b8: + bw[0] = 8; + bw[1] = 8; + bw[2] = 8; + bp[0] = 16; + bp[1] = 8; + bp[2] = 0; + break; + case nx_mlc_rgbfmt_b8g8r8: + case nx_mlc_rgbfmt_a8b8g8r8: + bw[0] = 8; + bw[1] = 8; + bw[2] = 8; + bp[0] = 0; + bp[1] = 8; + bp[2] = 16; + break; + default: + break; + } + for (i = 0; i < 3; i++) { + rgb[i] = (color >> bp[i]) & ((u32)(1 << bw[i]) - 1); + fill = bw[i]; + blank = 8 - fill; + rgb[i] <<= blank; + while (blank > 0) { + rgb[i] |= (rgb[i] >> fill); + blank -= fill; + fill += fill; + } + } + + return (rgb[0] << 16) | (rgb[1] << 8) | (rgb[2] << 0); +} + +void nx_mlc_set_format_rgb(u32 module_index, u32 layer, + enum nx_mlc_rgbfmt format) +{ + const u32 dirtyflag_pos = 4; + const u32 dirtyflag_mask = 1ul << dirtyflag_pos; + const u32 format_mask = 0xffff0000ul; + register u32 regvalue; + register struct nx_mlc_register_set *pregister; + + pregister = __g_module_variables[module_index].pregister; + if (layer == 0 || layer == 1) { + regvalue = pregister->mlcrgblayer[layer].mlccontrol; + regvalue &= ~(format_mask | dirtyflag_mask); + regvalue |= (u32)format; + + writel(regvalue, &pregister->mlcrgblayer[layer].mlccontrol); + } +} + +void nx_mlc_set_format_yuv(u32 module_index, enum nx_mlc_yuvfmt format) +{ + const u32 format_mask = 0xffff0000ul; + register u32 temp; + register struct nx_mlc_register_set *pregister; + + pregister = __g_module_variables[module_index].pregister; + temp = pregister->mlcvideolayer.mlccontrol; + temp &= ~format_mask; + temp |= (u32)format; + + writel(temp, &pregister->mlcvideolayer.mlccontrol); +} + +void nx_mlc_set_position(u32 module_index, u32 layer, s32 sx, s32 sy, + s32 ex, s32 ey) +{ + register struct nx_mlc_register_set *pregister; + + pregister = __g_module_variables[module_index].pregister; + if (layer == 0 || layer == 1) { + writel((((u32)sx & 0xffful) << 16) | ((u32)ex & 0xffful), + &pregister->mlcrgblayer[layer].mlcleftright); + + writel((((u32)sy & 0xffful) << 16) | ((u32)ey & 0xffful), + &pregister->mlcrgblayer[layer].mlctopbottom); + } else if (layer == 2) { + writel((((u32)sx & 0xffful) << 16) | ((u32)ex & 0xffful), + &pregister->mlcrgblayer2.mlcleftright); + + writel((((u32)sy & 0xffful) << 16) | ((u32)ey & 0xffful), + &pregister->mlcrgblayer2.mlctopbottom); + } else if (layer == 3) { + writel((((u32)sx & 0xffful) << 16) | ((u32)ex & 0xffful), + &pregister->mlcvideolayer.mlcleftright); + + writel((((u32)sy & 0xffful) << 16) | ((u32)ey & 0xffful), + &pregister->mlcvideolayer.mlctopbottom); + } +} + +void nx_mlc_set_dither_enable_when_using_gamma(u32 module_index, int benable) +{ + const u32 ditherenb_bitpos = 0; + const u32 ditherenb_mask = 1 << ditherenb_bitpos; + register struct nx_mlc_register_set *pregister; + register u32 read_value; + + pregister = __g_module_variables[module_index].pregister; + read_value = pregister->mlcgammacont; + read_value &= ~ditherenb_mask; + read_value |= ((u32)benable << ditherenb_bitpos); + + writel(read_value, &pregister->mlcgammacont); +} + +int nx_mlc_get_dither_enable_when_using_gamma(u32 module_index) +{ + const u32 ditherenb_bitpos = 0; + const u32 ditherenb_mask = 1 << ditherenb_bitpos; + + return (int)(__g_module_variables[module_index].pregister->mlcgammacont + & ditherenb_mask); +} + +void nx_mlc_set_gamma_priority(u32 module_index, int bvideolayer) +{ + const u32 alphaselect_bitpos = 5; + const u32 alphaselect_mask = 1 << alphaselect_bitpos; + register struct nx_mlc_register_set *pregister; + register u32 read_value; + + pregister = __g_module_variables[module_index].pregister; + read_value = pregister->mlcgammacont; + read_value &= ~alphaselect_mask; + read_value |= ((u32)bvideolayer << alphaselect_bitpos); + + writel(read_value, &pregister->mlcgammacont); +} + +int nx_mlc_get_gamma_priority(u32 module_index) +{ + const u32 alphaselect_bitpos = 5; + const u32 alphaselect_mask = 1 << alphaselect_bitpos; + + return (int)((__g_module_variables[module_index].pregister->mlcgammacont + & alphaselect_mask) >> alphaselect_bitpos); +} + +void nx_mlc_set_rgblayer_invalid_position(u32 module_index, u32 layer, + u32 region, s32 sx, s32 sy, + s32 ex, s32 ey, int benb) +{ + const u32 invalidenb_pos = 28; + register struct nx_mlc_register_set *pregister; + + pregister = __g_module_variables[module_index].pregister; + if (layer == 0 || layer == 1) { + if (region == 0) { + writel(((benb << invalidenb_pos) | + ((sx & 0x7ff) << 16) | (ex & 0x7ff)), + &pregister->mlcrgblayer[layer] + .mlcinvalidleftright0); + + writel((((sy & 0x7ff) << 16) | (ey & 0x7ff)), + &pregister->mlcrgblayer[layer] + .mlcinvalidtopbottom0); + } else { + writel(((benb << invalidenb_pos) | + ((sx & 0x7ff) << 16) | (ex & 0x7ff)), + &pregister->mlcrgblayer[layer] + .mlcinvalidleftright1); + + writel((((sy & 0x7ff) << 16) | (ey & 0x7ff)), + &pregister->mlcrgblayer[layer] + .mlcinvalidtopbottom1); + } + } +} + +void nx_mlc_set_rgblayer_stride(u32 module_index, u32 layer, s32 hstride, + s32 vstride) +{ + register struct nx_mlc_register_set *pregister; + + pregister = __g_module_variables[module_index].pregister; + if (layer == 0 || layer == 1) { + writel(hstride, &pregister->mlcrgblayer[layer].mlchstride); + writel(vstride, &pregister->mlcrgblayer[layer].mlcvstride); + } else if (layer == 2) { + writel(hstride, &pregister->mlcrgblayer2.mlchstride); + writel(vstride, &pregister->mlcrgblayer2.mlcvstride); + } +} + +void nx_mlc_set_rgblayer_address(u32 module_index, u32 layer, u32 addr) +{ + register struct nx_mlc_register_set *pregister; + + pregister = __g_module_variables[module_index].pregister; + if (layer == 0 || layer == 1) + writel(addr, &pregister->mlcrgblayer[layer].mlcaddress); + else if (layer == 2) + writel(addr, &pregister->mlcrgblayer2.mlcaddress); +} + +void nx_mlc_set_rgblayer_gama_table_power_mode(u32 module_index, int bred, + int bgreen, int bblue) +{ + const u32 bgammatable_pwd_bitpos = 11; + const u32 ggammatable_pwd_bitpos = 9; + const u32 rgammatable_pwd_bitpos = 3; + const u32 bgammatable_pwd_mask = (1 << bgammatable_pwd_bitpos); + const u32 ggammatable_pwd_mask = (1 << ggammatable_pwd_bitpos); + const u32 rgammatable_pwd_mask = (1 << rgammatable_pwd_bitpos); + register u32 read_value; + register struct nx_mlc_register_set *pregister; + + pregister = __g_module_variables[module_index].pregister; + read_value = pregister->mlcgammacont; + read_value &= ~(bgammatable_pwd_mask | ggammatable_pwd_mask | + rgammatable_pwd_mask); + read_value |= (((u32)bred << rgammatable_pwd_bitpos) | + ((u32)bgreen << ggammatable_pwd_bitpos) | + ((u32)bblue << bgammatable_pwd_bitpos)); + + writel(read_value, &pregister->mlcgammacont); +} + +void nx_mlc_get_rgblayer_gama_table_power_mode(u32 module_index, int *pbred, + int *pbgreen, int *pbblue) +{ + const u32 bgammatable_pwd_bitpos = 11; + const u32 ggammatable_pwd_bitpos = 9; + const u32 rgammatable_pwd_bitpos = 3; + const u32 bgammatable_pwd_mask = (1 << bgammatable_pwd_bitpos); + const u32 ggammatable_pwd_mask = (1 << ggammatable_pwd_bitpos); + const u32 rgammatable_pwd_mask = (1 << rgammatable_pwd_bitpos); + register u32 read_value; + register struct nx_mlc_register_set *pregister; + + pregister = __g_module_variables[module_index].pregister; + read_value = pregister->mlcgammacont; + if (pbred) + *pbred = (read_value & rgammatable_pwd_mask) ? 1 : 0; + + if (pbgreen) + *pbgreen = (read_value & ggammatable_pwd_mask) ? 1 : 0; + + if (pbblue) + *pbblue = (read_value & bgammatable_pwd_mask) ? 1 : 0; +} + +void nx_mlc_set_rgblayer_gama_table_sleep_mode(u32 module_index, int bred, + int bgreen, int bblue) +{ + const u32 bgammatable_sld_bitpos = 10; + const u32 ggammatable_sld_bitpos = 8; + const u32 rgammatable_sld_bitpos = 2; + const u32 bgammatable_sld_mask = (1 << bgammatable_sld_bitpos); + const u32 ggammatable_sld_mask = (1 << ggammatable_sld_bitpos); + const u32 rgammatable_sld_mask = (1 << rgammatable_sld_bitpos); + register u32 read_value; + register struct nx_mlc_register_set *pregister; + + pregister = __g_module_variables[module_index].pregister; + read_value = pregister->mlcgammacont; + if (bred) + read_value &= ~rgammatable_sld_mask; + else + read_value |= rgammatable_sld_mask; + + if (bgreen) + read_value &= ~ggammatable_sld_mask; + else + read_value |= ggammatable_sld_mask; + + if (bblue) + read_value &= ~bgammatable_sld_mask; + else + read_value |= bgammatable_sld_mask; + + writel(read_value, &pregister->mlcgammacont); +} + +void nx_mlc_get_rgblayer_gama_table_sleep_mode(u32 module_index, int *pbred, + int *pbgreen, int *pbblue) +{ + const u32 bgammatable_sld_bitpos = 10; + const u32 ggammatable_sld_bitpos = 8; + const u32 rgammatable_sld_bitpos = 2; + const u32 bgammatable_sld_mask = (1 << bgammatable_sld_bitpos); + const u32 ggammatable_sld_mask = (1 << ggammatable_sld_bitpos); + const u32 rgammatable_sld_mask = (1 << rgammatable_sld_bitpos); + register u32 read_value; + register struct nx_mlc_register_set *pregister; + + pregister = __g_module_variables[module_index].pregister; + read_value = pregister->mlcgammacont; + + if (pbred) + *pbred = (read_value & rgammatable_sld_mask) ? 0 : 1; + + if (pbgreen) + *pbgreen = (read_value & ggammatable_sld_mask) ? 0 : 1; + + if (pbblue) + *pbblue = (read_value & bgammatable_sld_mask) ? 0 : 1; +} + +void nx_mlc_set_rgblayer_rgamma_table(u32 module_index, u32 dwaddress, + u32 dwdata) +{ + register struct nx_mlc_register_set *pregister; + const u32 tableaddr_bitpos = 24; + + pregister = __g_module_variables[module_index].pregister; + writel(((dwaddress << tableaddr_bitpos) | dwdata), + &pregister->mlcrgammatablewrite); +} + +void nx_mlc_set_rgblayer_ggamma_table(u32 module_index, u32 dwaddress, + u32 dwdata) +{ + register struct nx_mlc_register_set *pregister; + const u32 tableaddr_bitpos = 24; + + pregister = __g_module_variables[module_index].pregister; + writel(((dwaddress << tableaddr_bitpos) | dwdata), + &pregister->mlcggammatablewrite); +} + +void nx_mlc_set_rgblayer_bgamma_table(u32 module_index, u32 dwaddress, + u32 dwdata) +{ + register struct nx_mlc_register_set *pregister; + const u32 tableaddr_bitpos = 24; + + pregister = __g_module_variables[module_index].pregister; + writel(((dwaddress << tableaddr_bitpos) | dwdata), + &pregister->mlcbgammatablewrite); +} + +void nx_mlc_set_rgblayer_gamma_enable(u32 module_index, int benable) +{ + const u32 rgbgammaemb_bitpos = 1; + const u32 rgbgammaemb_mask = 1 << rgbgammaemb_bitpos; + register u32 read_value; + register struct nx_mlc_register_set *pregister; + + pregister = __g_module_variables[module_index].pregister; + read_value = pregister->mlcgammacont; + read_value &= ~rgbgammaemb_mask; + read_value |= (u32)benable << rgbgammaemb_bitpos; + + writel(read_value, &pregister->mlcgammacont); +} + +int nx_mlc_get_rgblayer_gamma_enable(u32 module_index) +{ + const u32 rgbgammaemb_bitpos = 1; + const u32 rgbgammaemb_mask = 1 << rgbgammaemb_bitpos; + + return (int)((__g_module_variables[module_index].pregister->mlcgammacont + & rgbgammaemb_mask) >> rgbgammaemb_bitpos); +} + +void nx_mlc_set_video_layer_stride(u32 module_index, s32 lu_stride, + s32 cb_stride, s32 cr_stride) +{ + register struct nx_mlc_register_set *pregister; + + pregister = __g_module_variables[module_index].pregister; + + writel(lu_stride, &pregister->mlcvideolayer.mlcvstride); + writel(cb_stride, &pregister->mlcvideolayer.mlcvstridecb); + writel(cr_stride, &pregister->mlcvideolayer.mlcvstridecr); +} + +void nx_mlc_set_video_layer_address(u32 module_index, u32 lu_addr, u32 cb_addr, + u32 cr_addr) +{ + register struct nx_mlc_register_set *pregister; + + pregister = __g_module_variables[module_index].pregister; + writel(lu_addr, &pregister->mlcvideolayer.mlcaddress); + writel(cb_addr, &pregister->mlcvideolayer.mlcaddresscb); + writel(cr_addr, &pregister->mlcvideolayer.mlcaddresscr); +} + +void nx_mlc_set_video_layer_address_yuyv(u32 module_index, u32 addr, + s32 stride) +{ + register struct nx_mlc_register_set *pregister; + + pregister = __g_module_variables[module_index].pregister; + writel(addr, &pregister->mlcvideolayer.mlcaddress); + writel(stride, &pregister->mlcvideolayer.mlcvstride); +} + +void nx_mlc_set_video_layer_scale_factor(u32 module_index, u32 hscale, + u32 vscale, int bhlumaenb, + int bhchromaenb, int bvlumaenb, + int bvchromaenb) +{ + const u32 filter_luma_pos = 28; + const u32 filter_choma_pos = 29; + const u32 scale_mask = ((1 << 23) - 1); + register struct nx_mlc_register_set *pregister; + + pregister = __g_module_variables[module_index].pregister; + + writel(((bhlumaenb << filter_luma_pos) | + (bhchromaenb << filter_choma_pos) | (hscale & scale_mask)), + &pregister->mlcvideolayer.mlchscale); + + writel(((bvlumaenb << filter_luma_pos) | + (bvchromaenb << filter_choma_pos) | (vscale & scale_mask)), + &pregister->mlcvideolayer.mlcvscale); +} + +void nx_mlc_set_video_layer_scale_filter(u32 module_index, int bhlumaenb, + int bhchromaenb, int bvlumaenb, + int bvchromaenb) +{ + const u32 filter_luma_pos = 28; + const u32 filter_choma_pos = 29; + const u32 scale_mask = ((1 << 23) - 1); + register struct nx_mlc_register_set *pregister; + register u32 read_value; + + pregister = __g_module_variables[module_index].pregister; + read_value = pregister->mlcvideolayer.mlchscale; + read_value &= scale_mask; + read_value |= + (bhlumaenb << filter_luma_pos) | (bhchromaenb << filter_choma_pos); + + writel(read_value, &pregister->mlcvideolayer.mlchscale); + read_value = pregister->mlcvideolayer.mlcvscale; + read_value &= scale_mask; + read_value |= + (bvlumaenb << filter_luma_pos) | (bvchromaenb << filter_choma_pos); + + writel(read_value, &pregister->mlcvideolayer.mlcvscale); +} + +void nx_mlc_get_video_layer_scale_filter(u32 module_index, int *bhlumaenb, + int *bhchromaenb, int *bvlumaenb, + int *bvchromaenb) +{ + const u32 filter_luma_pos = 28; + const u32 filter_choma_pos = 29; + const u32 filter_mask = 1ul; + register struct nx_mlc_register_set *pregister; + register u32 read_value; + + pregister = __g_module_variables[module_index].pregister; + read_value = pregister->mlcvideolayer.mlchscale; + *bhlumaenb = (read_value >> filter_luma_pos) & filter_mask; + *bhchromaenb = (read_value >> filter_choma_pos) & filter_mask; + read_value = pregister->mlcvideolayer.mlcvscale; + *bvlumaenb = (read_value >> filter_luma_pos) & filter_mask; + *bvchromaenb = (read_value >> filter_choma_pos) & filter_mask; +} + +void nx_mlc_set_video_layer_scale(u32 module_index, u32 sw, u32 sh, u32 dw, + u32 dh, int bhlumaenb, int bhchromaenb, + int bvlumaenb, int bvchromaenb) +{ + const u32 filter_luma_pos = 28; + const u32 filter_choma_pos = 29; + const u32 scale_mask = ((1 << 23) - 1); + register u32 hscale, vscale, cal_sh; + register struct nx_mlc_register_set *pregister; + + pregister = __g_module_variables[module_index].pregister; + + if ((bhlumaenb || bhchromaenb) && dw > sw) { + sw--; + dw--; + } + hscale = (sw << 11) / dw; + + if ((bvlumaenb || bvchromaenb) && dh > sh) { + sh--; + dh--; + vscale = (sh << 11) / dh; + + cal_sh = ((vscale * dh) >> 11); + if (sh <= cal_sh) + vscale--; + + } else { + vscale = (sh << 11) / dh; + } + + writel(((bhlumaenb << filter_luma_pos) | + (bhchromaenb << filter_choma_pos) | (hscale & scale_mask)), + &pregister->mlcvideolayer.mlchscale); + + writel(((bvlumaenb << filter_luma_pos) | + (bvchromaenb << filter_choma_pos) | (vscale & scale_mask)), + &pregister->mlcvideolayer.mlcvscale); +} + +void nx_mlc_set_video_layer_luma_enhance(u32 module_index, u32 contrast, + s32 brightness) +{ + register struct nx_mlc_register_set *pregister; + + pregister = __g_module_variables[module_index].pregister; + + writel((((u32)brightness & 0xfful) << 8) | contrast, + &pregister->mlcvideolayer.mlcluenh); +} + +void nx_mlc_set_video_layer_chroma_enhance(u32 module_index, u32 quadrant, + s32 cb_a, s32 cb_b, + s32 cr_a, s32 cr_b) +{ + register struct nx_mlc_register_set *pregister; + register u32 temp; + + pregister = __g_module_variables[module_index].pregister; + temp = (((u32)cr_b & 0xfful) << 24) | (((u32)cr_a & 0xfful) << 16) | + (((u32)cb_b & 0xfful) << 8) | (((u32)cb_a & 0xfful) << 0); + if (quadrant > 0) { + writel(temp, &pregister->mlcvideolayer.mlcchenh[quadrant - 1]); + } else { + writel(temp, &pregister->mlcvideolayer.mlcchenh[0]); + writel(temp, &pregister->mlcvideolayer.mlcchenh[1]); + writel(temp, &pregister->mlcvideolayer.mlcchenh[2]); + writel(temp, &pregister->mlcvideolayer.mlcchenh[3]); + } +} + +void nx_mlc_set_video_layer_line_buffer_power_mode(u32 module_index, + int benable) +{ + const u32 linebuff_pwd_pos = 15; + const u32 linebuff_pwd_mask = 1ul << linebuff_pwd_pos; + const u32 dirtyflag_mask = 1ul << 4; + register u32 regvalue; + register struct nx_mlc_register_set *pregister; + + pregister = __g_module_variables[module_index].pregister; + regvalue = pregister->mlcvideolayer.mlccontrol; + regvalue &= ~(linebuff_pwd_mask | dirtyflag_mask); + regvalue |= ((u32)benable << linebuff_pwd_pos); + + writel(regvalue, &pregister->mlcvideolayer.mlccontrol); +} + +int nx_mlc_get_video_layer_line_buffer_power_mode(u32 module_index) +{ + const u32 linebuff_pwd_pos = 15; + const u32 linebuff_pwd_mask = 1ul << linebuff_pwd_pos; + + return (int)((__g_module_variables[module_index] + .pregister->mlcvideolayer.mlccontrol & + linebuff_pwd_mask) >> linebuff_pwd_pos); +} + +void nx_mlc_set_video_layer_line_buffer_sleep_mode(u32 module_index, + int benable) +{ + const u32 linebuff_slmd_pos = 14; + const u32 linebuff_slmd_mask = 1ul << linebuff_slmd_pos; + const u32 dirtyflag_mask = 1ul << 4; + register u32 regvalue; + register struct nx_mlc_register_set *pregister; + + benable = (int)((u32)benable ^ 1); + pregister = __g_module_variables[module_index].pregister; + regvalue = pregister->mlcvideolayer.mlccontrol; + regvalue &= ~(linebuff_slmd_mask | dirtyflag_mask); + regvalue |= (benable << linebuff_slmd_pos); + + writel(regvalue, &pregister->mlcvideolayer.mlccontrol); +} + +int nx_mlc_get_video_layer_line_buffer_sleep_mode(u32 module_index) +{ + const u32 linebuff_slmd_pos = 14; + const u32 linebuff_slmd_mask = 1ul << linebuff_slmd_pos; + register struct nx_mlc_register_set *pregister; + + pregister = __g_module_variables[module_index].pregister; + if (linebuff_slmd_mask & pregister->mlcvideolayer.mlccontrol) + return 0; + else + return 1; +} + +void nx_mlc_set_video_layer_gama_table_power_mode(u32 module_index, int by, + int bu, int bv) +{ + const u32 vgammatable_pwd_bitpos = 17; + const u32 ugammatable_pwd_bitpos = 15; + const u32 ygammatable_pwd_bitpos = 13; + const u32 vgammatable_pwd_mask = (1 << vgammatable_pwd_bitpos); + const u32 ugammatable_pwd_mask = (1 << ugammatable_pwd_bitpos); + const u32 ygammatable_pwd_mask = (1 << ygammatable_pwd_bitpos); + register u32 read_value; + register struct nx_mlc_register_set *pregister; + + pregister = __g_module_variables[module_index].pregister; + read_value = pregister->mlcgammacont; + read_value &= ~(ygammatable_pwd_mask | ugammatable_pwd_mask | + vgammatable_pwd_mask); + read_value |= (((u32)by << ygammatable_pwd_bitpos) | + ((u32)bu << ugammatable_pwd_bitpos) | + ((u32)bv << vgammatable_pwd_bitpos)); + + writel(read_value, &pregister->mlcgammacont); +} + +void nx_mlc_get_video_layer_gama_table_power_mode(u32 module_index, int *pby, + int *pbu, int *pbv) +{ + const u32 vgammatable_pwd_bitpos = 17; + const u32 ugammatable_pwd_bitpos = 15; + const u32 ygammatable_pwd_bitpos = 13; + const u32 vgammatable_pwd_mask = (1 << vgammatable_pwd_bitpos); + const u32 ugammatable_pwd_mask = (1 << ugammatable_pwd_bitpos); + const u32 ygammatable_pwd_mask = (1 << ygammatable_pwd_bitpos); + register u32 read_value; + register struct nx_mlc_register_set *pregister; + + pregister = __g_module_variables[module_index].pregister; + read_value = pregister->mlcgammacont; + if (pby) + *pby = (read_value & ygammatable_pwd_mask) ? 1 : 0; + + if (pbu) + *pbu = (read_value & ugammatable_pwd_mask) ? 1 : 0; + + if (pbv) + *pbv = (read_value & vgammatable_pwd_mask) ? 1 : 0; +} + +void nx_mlc_set_video_layer_gama_table_sleep_mode(u32 module_index, int by, + int bu, int bv) +{ + const u32 vgammatable_sld_bitpos = 16; + const u32 ugammatable_sld_bitpos = 14; + const u32 ygammatable_sld_bitpos = 12; + const u32 vgammatable_sld_mask = (1 << vgammatable_sld_bitpos); + const u32 ugammatable_sld_mask = (1 << ugammatable_sld_bitpos); + const u32 ygammatable_sld_mask = (1 << ygammatable_sld_bitpos); + register u32 read_value; + register struct nx_mlc_register_set *pregister; + + pregister = __g_module_variables[module_index].pregister; + read_value = pregister->mlcgammacont; + if (by) + read_value &= ~ygammatable_sld_mask; + else + read_value |= ygammatable_sld_mask; + + if (bu) + read_value &= ~ugammatable_sld_mask; + else + read_value |= ugammatable_sld_mask; + + if (bv) + read_value &= ~vgammatable_sld_mask; + else + read_value |= vgammatable_sld_mask; + + writel(read_value, &pregister->mlcgammacont); +} + +void nx_mlc_get_video_layer_gama_table_sleep_mode(u32 module_index, int *pby, + int *pbu, int *pbv) +{ + const u32 vgammatable_sld_bitpos = 16; + const u32 ugammatable_sld_bitpos = 14; + const u32 ygammatable_sld_bitpos = 12; + const u32 vgammatable_sld_mask = (1 << vgammatable_sld_bitpos); + const u32 ugammatable_sld_mask = (1 << ugammatable_sld_bitpos); + const u32 ygammatable_sld_mask = (1 << ygammatable_sld_bitpos); + register u32 read_value; + register struct nx_mlc_register_set *pregister; + + pregister = __g_module_variables[module_index].pregister; + read_value = pregister->mlcgammacont; + + if (pby) + *pby = (read_value & vgammatable_sld_mask) ? 0 : 1; + + if (pbu) + *pbu = (read_value & ugammatable_sld_mask) ? 0 : 1; + + if (pbv) + *pbv = (read_value & ygammatable_sld_mask) ? 0 : 1; +} + +void nx_mlc_set_video_layer_gamma_enable(u32 module_index, int benable) +{ + const u32 yuvgammaemb_bitpos = 4; + const u32 yuvgammaemb_mask = 1 << yuvgammaemb_bitpos; + register u32 read_value; + register struct nx_mlc_register_set *pregister; + + pregister = __g_module_variables[module_index].pregister; + read_value = pregister->mlcgammacont; + read_value &= ~yuvgammaemb_mask; + read_value |= (u32)benable << yuvgammaemb_bitpos; + + writel(read_value, &pregister->mlcgammacont); +} + +int nx_mlc_get_video_layer_gamma_enable(u32 module_index) +{ + const u32 yuvgammaemb_bitpos = 4; + const u32 yuvgammaemb_mask = 1 << yuvgammaemb_bitpos; + + return (int)((__g_module_variables[module_index].pregister->mlcgammacont + & yuvgammaemb_mask) >> yuvgammaemb_bitpos); +} + +void nx_mlc_set_gamma_table_poweroff(u32 module_index, int enb) +{ + register struct nx_mlc_register_set *pregister; + u32 regvalue; + + pregister = __g_module_variables[module_index].pregister; + if (enb == 1) { + regvalue = pregister->mlcgammacont; + regvalue = regvalue & 0xf3; + writel(regvalue, &pregister->mlcgammacont); + } +} + +void nx_mlc_set_mlctop_control_parameter(u32 module_index, int field_enable, + int mlcenable, u8 priority, + enum g3daddrchangeallowed + g3daddr_change_allowed) +{ + register u32 mlctopcontrolreg; + register struct nx_mlc_register_set *pregister; + + pregister = __g_module_variables[module_index].pregister; + mlctopcontrolreg = (readl(&pregister->mlccontrolt)) & 0xfffffcfc; + mlctopcontrolreg = (u32)(mlctopcontrolreg | + ((priority << 8) | ((mlcenable == 1) << 1) | + (1 == + field_enable)) | (g3daddr_change_allowed << + 12)); + writel(mlctopcontrolreg, &pregister->mlccontrolt); +} + +void nx_mlc_set_rgb0layer_control_parameter(u32 module_index, int layer_enable, + int grp3denable, int tp_enable, + u32 transparency_color, + int inv_enable, u32 inverse_color, + int blend_enable, u8 alpha_value, + enum mlc_rgbfmt rbgformat, + enum locksizesel lock_size_select) +{ + u32 layer_format; + u32 control_enb; + u32 alpha_argument; + u32 lock_size = (u32)(lock_size_select & 0x3); + u32 rgb0controlreg; + u32 regvalue; + register struct nx_mlc_register_set *pregister; + + layer_format = nx_mlc_get_rgbformat(rbgformat); + pregister = __g_module_variables[module_index].pregister; + control_enb = + (u32)((grp3denable << 8) | (layer_enable << 5) | + (blend_enable << 2) | (inv_enable << 1) | tp_enable) & 0x127; + alpha_argument = (u32)(alpha_value & 0xf); + + rgb0controlreg = readl(&pregister->mlcrgblayer[0].mlccontrol) & 0x10; + regvalue = + (u32)(((layer_format << 16) | control_enb | (lock_size << 12)) | + rgb0controlreg); + writel(regvalue, &pregister->mlcrgblayer[0].mlccontrol); + + regvalue = (u32)((alpha_argument << 28) | transparency_color); + writel(regvalue, &pregister->mlcrgblayer[0].mlctpcolor); + regvalue = inverse_color; + writel(regvalue, &pregister->mlcrgblayer[0].mlcinvcolor); +} + +u32 nx_mlc_get_rgbformat(enum mlc_rgbfmt rbgformat) +{ + u32 rgbformatvalue; + const u32 format_table[] = { + 0x4432ul, 0x4342ul, 0x4211ul, 0x4120ul, 0x4003ul, 0x4554ul, + 0x3342ul, 0x2211ul, 0x1120ul, 0x1003ul, 0x4653ul, 0x4653ul, + 0x0653ul, 0x4ed3ul, 0x4f84ul, 0xc432ul, 0xc342ul, 0xc211ul, + 0xc120ul, 0xb342ul, 0xa211ul, 0x9120ul, 0xc653ul, 0xc653ul, + 0x8653ul, 0xced3ul, 0xcf84ul, 0x443aul + }; + + return rgbformatvalue = format_table[rbgformat]; +} + +void nx_mlc_set_rgb1layer_control_parameter(u32 module_index, int layer_enable, + int grp3denable, int tp_enable, + u32 transparency_color, + int inv_enable, u32 inverse_color, + int blend_enable, u8 alpha_value, + enum mlc_rgbfmt rbgformat, + enum locksizesel lock_size_select) +{ + u32 layer_format; + u32 control_enb; + u32 alpha_argument; + u32 lock_size = (u32)(lock_size_select & 0x3); + u32 rgb0controlreg; + u32 regvalue; + register struct nx_mlc_register_set *pregister; + + layer_format = nx_mlc_get_rgbformat(rbgformat); + pregister = __g_module_variables[module_index].pregister; + + rgb0controlreg = readl(&pregister->mlcrgblayer[1].mlccontrol) & 0x10; + control_enb = + (u32)((grp3denable << 8) | (layer_enable << 5) | + (blend_enable << 2) | (inv_enable << 1) | tp_enable) & 0x127; + alpha_argument = (u32)(alpha_value & 0xf); + regvalue = + (u32)(((layer_format << 16) | control_enb | (lock_size << 12)) | + rgb0controlreg); + writel(regvalue, &pregister->mlcrgblayer[1].mlccontrol); + regvalue = (u32)((alpha_argument << 28) | transparency_color); + writel(regvalue, &pregister->mlcrgblayer[1].mlctpcolor); + regvalue = inverse_color; + writel(regvalue, &pregister->mlcrgblayer[1].mlcinvcolor); +} + +void nx_mlc_set_rgb2layer_control_parameter(u32 module_index, int layer_enable, + int grp3denable, int tp_enable, + u32 transparency_color, + int inv_enable, u32 inverse_color, + int blend_enable, u8 alpha_value, + enum mlc_rgbfmt rbgformat, + enum locksizesel lock_size_select) +{ + u32 layer_format; + u32 control_enb; + u32 alpha_argument; + u32 lock_size = (u32)(lock_size_select & 0x3); + u32 rgb0controlreg; + u32 regvalue; + register struct nx_mlc_register_set *pregister; + + layer_format = nx_mlc_get_rgbformat(rbgformat); + pregister = __g_module_variables[module_index].pregister; + + rgb0controlreg = readl(&pregister->mlcrgblayer2.mlccontrol) & 0x10; + control_enb = + (u32)((grp3denable << 8) | (layer_enable << 5) | + (blend_enable << 2) | (inv_enable << 1) | tp_enable) & 0x127; + alpha_argument = (u32)(alpha_value & 0xf); + regvalue = + (u32)(((layer_format << 16) | control_enb | (lock_size << 12)) | + rgb0controlreg); + writel(regvalue, &pregister->mlcrgblayer2.mlccontrol); + regvalue = (u32)((alpha_argument << 28) | transparency_color); + writel(regvalue, &pregister->mlcrgblayer2.mlctpcolor); + regvalue = inverse_color; + writel(regvalue, &pregister->mlcrgblayer2.mlcinvcolor); +} + +void nx_mlc_set_video_layer_control_parameter(u32 module_index, + int layer_enable, int tp_enable, + u32 transparency_color, + int inv_enable, u32 inverse_color, + int blend_enable, u8 alpha_value, + enum nx_mlc_yuvfmt yuvformat) +{ + u32 control_enb; + u32 alpha_argument; + u32 regvalue; + register struct nx_mlc_register_set *pregister; + u32 video_control_reg; + + pregister = __g_module_variables[module_index].pregister; + + video_control_reg = readl(&pregister->mlcvideolayer.mlccontrol); + control_enb = + (u32)((yuvformat) | (layer_enable << 5) | (blend_enable << 2) | + (inv_enable << 1) | tp_enable) & 0x30027; + alpha_argument = (u32)(alpha_value & 0xf); + regvalue = (u32)(control_enb | video_control_reg); + writel(regvalue, &pregister->mlcvideolayer.mlccontrol); + regvalue = (u32)((alpha_argument << 28) | transparency_color); + writel(regvalue, &pregister->mlcvideolayer.mlctpcolor); + regvalue = (u32)((alpha_argument << 28) | transparency_color); + writel(regvalue, &pregister->mlcvideolayer.mlcinvcolor); +} + +void nx_mlc_set_srammode(u32 module_index, enum latyername layer_name, + enum srammode sram_mode) +{ + u32 control_reg_value; + register struct nx_mlc_register_set *pregister; + + pregister = __g_module_variables[module_index].pregister; + switch (layer_name) { + case topmlc: + control_reg_value = readl(&pregister->mlccontrolt); + writel((u32)(control_reg_value | (sram_mode << 10)), + &pregister->mlccontrolt); + control_reg_value = 0; + break; + case rgb0: + control_reg_value = + readl(&pregister->mlcrgblayer[0].mlccontrol); + writel((u32)(control_reg_value | (sram_mode << 14)), + &pregister->mlcrgblayer[0].mlccontrol); + control_reg_value = 0; + break; + case rgb1: + control_reg_value = + readl(&pregister->mlcrgblayer[1].mlccontrol); + writel((u32)(control_reg_value | (sram_mode << 14)), + &pregister->mlcrgblayer[1].mlccontrol); + control_reg_value = 0; + break; + case rgb2: + control_reg_value = readl(&pregister->mlcrgblayer2.mlccontrol); + writel((u32)(control_reg_value | (sram_mode << 14)), + &pregister->mlcrgblayer2.mlccontrol); + control_reg_value = 0; + break; + case video: + control_reg_value = readl(&pregister->mlcvideolayer.mlccontrol); + writel((u32)(control_reg_value | (sram_mode << 14)), + &pregister->mlcvideolayer.mlccontrol); + control_reg_value = 0; + break; + default: + break; + } +} + +void nx_mlc_set_layer_reg_finish(u32 module_index, enum latyername layer_name) +{ + u32 control_reg_value; + register struct nx_mlc_register_set *pregister; + + pregister = __g_module_variables[module_index].pregister; + + switch (layer_name) { + case topmlc: + control_reg_value = readl(&pregister->mlccontrolt); + writel((u32)(control_reg_value | (1ul << 3)), + &pregister->mlccontrolt); + control_reg_value = 0; + break; + case rgb0: + control_reg_value = + readl(&pregister->mlcrgblayer[0].mlccontrol); + writel((u32)(control_reg_value | (1ul << 4)), + &pregister->mlcrgblayer[0].mlccontrol); + control_reg_value = 0; + break; + case rgb1: + control_reg_value = + readl(&pregister->mlcrgblayer[1].mlccontrol); + writel((u32)(control_reg_value | (1ul << 4)), + &pregister->mlcrgblayer[1].mlccontrol); + control_reg_value = 0; + break; + case rgb2: + control_reg_value = readl(&pregister->mlcrgblayer2.mlccontrol); + writel((u32)(control_reg_value | (1ul << 4)), + &pregister->mlcrgblayer2.mlccontrol); + control_reg_value = 0; + break; + case video: + control_reg_value = readl(&pregister->mlcvideolayer.mlccontrol); + writel((u32)(control_reg_value | (1ul << 4)), + &pregister->mlcvideolayer.mlccontrol); + control_reg_value = 0; + break; + default: + break; + } +} + +void nx_mlc_set_video_layer_coordinate(u32 module_index, int vfilterenable, + int hfilterenable, int vfilterenable_c, + int hfilterenable_c, + u16 video_layer_with, + u16 video_layer_height, s16 left, + s16 right, s16 top, + s16 bottom) +{ + s32 source_width, source_height; + s32 destination_width; + s32 destination_height; + s32 hscale, vscale; + s32 hfilterenb, vfilterenb; + register struct nx_mlc_register_set *pregister; + + pregister = __g_module_variables[module_index].pregister; + writel((s32)(((left & 0x0fff) << 16) | (right & 0x0fff)), + &pregister->mlcvideolayer.mlcleftright); + writel((s32)(((top & 0x0fff) << 16) | (bottom & 0x0fff)), + &pregister->mlcvideolayer.mlctopbottom); + source_width = (s32)(video_layer_with - 1); + source_height = (s32)(video_layer_height - 1); + destination_width = (s32)(right - left); + destination_height = (s32)(bottom - top); + + hscale = + (s32)((source_width * (1ul << 11) + (destination_width / 2)) / + destination_width); + vscale = + (s32)((source_height * (1ul << 11) + + (destination_height / 2)) / destination_height); + + hfilterenb = (u32)(((hfilterenable_c << 29) | (hfilterenable) << 28)) & + 0x30000000; + vfilterenb = (u32)(((vfilterenable_c << 29) | (vfilterenable) << 28)) & + 0x30000000; + writel((u32)(hfilterenb | (hscale & 0x00ffffff)), + &pregister->mlcvideolayer.mlchscale); + writel((u32)(vfilterenb | (vscale & 0x00ffffff)), + &pregister->mlcvideolayer.mlcvscale); +} + +void nx_mlc_set_video_layer_filter_scale(u32 module_index, u32 hscale, + u32 vscale) +{ + register struct nx_mlc_register_set *pregister; + u32 mlchscale = 0; + u32 mlcvscale = 0; + + pregister = __g_module_variables[module_index].pregister; + mlchscale = readl(&pregister->mlcvideolayer.mlchscale) & (~0x00ffffff); + mlcvscale = readl(&pregister->mlcvideolayer.mlcvscale) & (~0x00ffffff); + + writel((u32)(mlchscale | (hscale & 0x00ffffff)), + &pregister->mlcvideolayer.mlchscale); + writel((u32)(mlcvscale | (vscale & 0x00ffffff)), + &pregister->mlcvideolayer.mlcvscale); +} + +void nx_mlc_set_gamma_control_parameter(u32 module_index, int rgbgammaenb, + int yuvgammaenb, int yuvalphaarray, + int dither_enb) +{ + u32 register_data; + register struct nx_mlc_register_set *pregister; + + pregister = __g_module_variables[module_index].pregister; + register_data = readl(&pregister->mlcgammacont); + register_data = (register_data & 0xf0c) | + ((yuvalphaarray << 5) | (yuvgammaenb << 4) | + (rgbgammaenb << 1) | (dither_enb << 0)); + writel(register_data, &pregister->mlcgammacont); +} + +void nx_mlc_set_layer_alpha256(u32 module_index, u32 layer, u32 alpha) +{ + u32 register_data; + register struct nx_mlc_register_set *pregister; + + if (alpha < 0) + alpha = 0; + if (alpha > 255) + alpha = 255; + + pregister = __g_module_variables[module_index].pregister; + if (layer == 0) { + register_data = + readl(&pregister->mlcrgblayer[0].mlctpcolor) & 0x00ffffff; + register_data = register_data | (alpha << 24); + writel(register_data, &pregister->mlcrgblayer[0].mlctpcolor); + } else if (layer == 1) { + register_data = + readl(&pregister->mlcrgblayer[1].mlctpcolor) & 0x00ffffff; + register_data = register_data | (alpha << 24); + writel(register_data, &pregister->mlcrgblayer[1].mlctpcolor); + } else if (layer == 2) { + register_data = + readl(&pregister->mlcrgblayer[1].mlctpcolor) & 0x00ffffff; + register_data = register_data | (alpha << 24); + writel(register_data, &pregister->mlcrgblayer2.mlctpcolor); + } else { + register_data = + readl(&pregister->mlcvideolayer.mlctpcolor) & 0x00ffffff; + register_data = register_data | (alpha << 24); + writel(register_data, &pregister->mlcvideolayer.mlctpcolor); + } +} + +int nx_mlc_is_under_flow(u32 module_index) +{ + const u32 underflow_pend_pos = 31; + const u32 underflow_pend_mask = 1ul << underflow_pend_pos; + + return (int)((__g_module_variables[module_index].pregister->mlccontrolt + & underflow_pend_mask) >> underflow_pend_pos); +} + +void nx_mlc_set_gamma_table(u32 module_index, int enb, + struct nx_mlc_gamma_table_parameter *p_gammatable) +{ + register struct nx_mlc_register_set *pregister; + u32 i, regval = 0; + + pregister = __g_module_variables[module_index].pregister; + if (enb == 1) { + regval = readl(&pregister->mlcgammacont); + + regval = (1 << 11) | (1 << 9) | (1 << 3); + writel(regval, &pregister->mlcgammacont); + + regval = regval | (1 << 10) | (1 << 8) | (1 << 2); + writel(regval, &pregister->mlcgammacont); + + for (i = 0; i < 256; i++) { + nx_mlc_set_rgblayer_rgamma_table(module_index, i, + p_gammatable->r_table[i]); + nx_mlc_set_rgblayer_ggamma_table(module_index, i, + p_gammatable->g_table[i]); + nx_mlc_set_rgblayer_bgamma_table(module_index, i, + p_gammatable->b_table[i]); + } + + regval = regval | (p_gammatable->alphaselect << 5) | + (p_gammatable->yuvgammaenb << 4 | + p_gammatable->allgammaenb << 4) | + (p_gammatable->rgbgammaenb << 1 | + p_gammatable->allgammaenb << 1) | + (p_gammatable->ditherenb << 1); + writel(regval, &pregister->mlcgammacont); + } else { + regval = regval & ~(1 << 10) & ~(1 << 8) & ~(1 << 2); + writel(regval, &pregister->mlcgammacont); + + regval = regval & ~(1 << 11) & ~(1 << 9) & ~(1 << 3); + writel(regval, &pregister->mlcgammacont); + } +} + +void nx_mlc_get_rgblayer_stride(u32 module_index, u32 layer, s32 *hstride, + s32 *vstride) +{ + unsigned int hs, vs; + register struct nx_mlc_register_set *pregister; + + pregister = __g_module_variables[module_index].pregister; + + hs = readl(&pregister->mlcrgblayer[layer].mlchstride); + vs = readl(&pregister->mlcrgblayer[layer].mlcvstride); + + if (hstride) + *(s32 *)hstride = hs; + + if (vstride) + *(s32 *)vstride = vs; +} + +void nx_mlc_get_rgblayer_address(u32 module_index, u32 layer, + u32 *phys_address) +{ + u32 pa; + register struct nx_mlc_register_set *pregister; + + pregister = __g_module_variables[module_index].pregister; + pa = readl(&pregister->mlcrgblayer[layer].mlcaddress); + + if (phys_address) + *(u32 *)phys_address = pa; +} + +void nx_mlc_get_position(u32 module_index, u32 layer, int *left, int *top, + int *right, int *bottom) +{ + int lr, tb; + register struct nx_mlc_register_set *pregister; + + pregister = __g_module_variables[module_index].pregister; + + lr = readl(&pregister->mlcrgblayer[layer].mlcleftright); + tb = readl(&pregister->mlcrgblayer[layer].mlctopbottom); + + if (left) + *(int *)left = ((lr >> 16) & 0xFFUL); + + if (top) + *(int *)top = ((tb >> 16) & 0xFFUL); + + if (right) + *(int *)right = ((lr >> 0) & 0xFFUL); + + if (bottom) + *(int *)bottom = ((tb >> 0) & 0xFFUL); +} + +void nx_mlc_get_video_layer_address_yuyv(u32 module_index, u32 *address, + u32 *stride) +{ + u32 a, s; + register struct nx_mlc_register_set *pregister; + + pregister = __g_module_variables[module_index].pregister; + a = readl(&pregister->mlcvideolayer.mlcaddress); + s = readl(&pregister->mlcvideolayer.mlcvstride); + + if (address) + *(u32 *)address = a; + + if (stride) + *(u32 *)stride = s; +} + +void nx_mlc_get_video_layer_address(u32 module_index, u32 *lu_address, + u32 *cb_address, u32 *cr_address) +{ + u32 lua, cba, cra; + register struct nx_mlc_register_set *pregister; + + pregister = __g_module_variables[module_index].pregister; + + lua = readl(&pregister->mlcvideolayer.mlcaddress); + cba = readl(&pregister->mlcvideolayer.mlcaddresscb); + cra = readl(&pregister->mlcvideolayer.mlcaddresscr); + + if (lu_address) + *(u32 *)lu_address = lua; + + if (cb_address) + *(u32 *)cb_address = cba; + + if (cr_address) + *(u32 *)cr_address = cra; +} + +void nx_mlc_get_video_layer_stride(u32 module_index, u32 *lu_stride, + u32 *cb_stride, u32 *cr_stride) +{ + u32 lus, cbs, crs; + register struct nx_mlc_register_set *pregister; + + pregister = __g_module_variables[module_index].pregister; + + lus = readl(&pregister->mlcvideolayer.mlcvstride); + cbs = readl(&pregister->mlcvideolayer.mlcvstridecb); + crs = readl(&pregister->mlcvideolayer.mlcvstridecr); + + if (lu_stride) + *(u32 *)lu_stride = lus; + + if (cb_stride) + *(u32 *)cb_stride = cbs; + + if (cr_stride) + *(u32 *)cr_stride = crs; +} + +void nx_mlc_get_video_position(u32 module_index, int *left, int *top, + int *right, int *bottom) +{ + int lr, tb; + register struct nx_mlc_register_set *pregister; + + pregister = __g_module_variables[module_index].pregister; + + lr = readl(&pregister->mlcvideolayer.mlcleftright); + tb = readl(&pregister->mlcvideolayer.mlctopbottom); + + if (left) + *(int *)left = ((lr >> 16) & 0xFFUL); + + if (top) + *(int *)top = ((tb >> 16) & 0xFFUL); + + if (right) + *(int *)right = ((lr >> 0) & 0xFFUL); + + if (bottom) + *(int *)bottom = ((tb >> 0) & 0xFFUL); +} diff --git a/drivers/video/nexell/soc/s5pxx18_soc_mlc.h b/drivers/video/nexell/soc/s5pxx18_soc_mlc.h new file mode 100644 index 0000000000..77ceca6bd6 --- /dev/null +++ b/drivers/video/nexell/soc/s5pxx18_soc_mlc.h @@ -0,0 +1,429 @@ +/* SPDX-License-Identifier: GPL-2.0+ + * + * Copyright (C) 2016 Nexell Co., Ltd. + * + * Author: junghyun, kim <jhkim@nexell.co.kr> + */ + +#ifndef _S5PXX18_SOC_MLC_H_ +#define _S5PXX18_SOC_MLC_H_ + +#include "s5pxx18_soc_disptype.h" + +#define NUMBER_OF_MLC_MODULE 2 +#define PHY_BASEADDR_MLC0 0xC0102000 +#define PHY_BASEADDR_MLC1 0xC0102400 + +#define PHY_BASEADDR_MLC_LIST \ + { PHY_BASEADDR_MLC0, PHY_BASEADDR_MLC1 } + +struct nx_mlc_register_set { + u32 mlccontrolt; + u32 mlcscreensize; + u32 mlcbgcolor; + struct { + u32 mlcleftright; + u32 mlctopbottom; + u32 mlcinvalidleftright0; + u32 mlcinvalidtopbottom0; + u32 mlcinvalidleftright1; + u32 mlcinvalidtopbottom1; + u32 mlccontrol; + s32 mlchstride; + s32 mlcvstride; + u32 mlctpcolor; + u32 mlcinvcolor; + u32 mlcaddress; + u32 __reserved0; + } mlcrgblayer[2]; + struct { + u32 mlcleftright; + u32 mlctopbottom; + u32 mlccontrol; + u32 mlcvstride; + u32 mlctpcolor; + + u32 mlcinvcolor; + u32 mlcaddress; + u32 mlcaddresscb; + u32 mlcaddresscr; + s32 mlcvstridecb; + s32 mlcvstridecr; + u32 mlchscale; + u32 mlcvscale; + u32 mlcluenh; + u32 mlcchenh[4]; + } mlcvideolayer; + struct { + u32 mlcleftright; + u32 mlctopbottom; + u32 mlcinvalidleftright0; + u32 mlcinvalidtopbottom0; + u32 mlcinvalidleftright1; + u32 mlcinvalidtopbottom1; + u32 mlccontrol; + s32 mlchstride; + s32 mlcvstride; + u32 mlctpcolor; + u32 mlcinvcolor; + u32 mlcaddress; + } mlcrgblayer2; + u32 mlcpaletetable2; + u32 mlcgammacont; + u32 mlcrgammatablewrite; + u32 mlcggammatablewrite; + u32 mlcbgammatablewrite; + u32 yuvlayergammatable_red; + u32 yuvlayergammatable_green; + u32 yuvlayergammatable_blue; + + u32 dimctrl; + u32 dimlut0; + u32 dimlut1; + u32 dimbusyflag; + u32 dimprdarrr0; + u32 dimprdarrr1; + u32 dimram0rddata; + u32 dimram1rddata; + u32 __reserved2[(0x3c0 - 0x12c) / 4]; + u32 mlcclkenb; +}; + +enum nx_mlc_priority { + nx_mlc_priority_videofirst = 0ul, + nx_mlc_priority_videosecond = 1ul, + nx_mlc_priority_videothird = 2ul, + nx_mlc_priority_videofourth = 3ul +}; + +enum nx_mlc_rgbfmt { + nx_mlc_rgbfmt_r5g6b5 = 0x44320000ul, + nx_mlc_rgbfmt_b5g6r5 = 0xc4320000ul, + nx_mlc_rgbfmt_x1r5g5b5 = 0x43420000ul, + nx_mlc_rgbfmt_x1b5g5r5 = 0xc3420000ul, + nx_mlc_rgbfmt_x4r4g4b4 = 0x42110000ul, + nx_mlc_rgbfmt_x4b4g4r4 = 0xc2110000ul, + nx_mlc_rgbfmt_x8r3g3b2 = 0x41200000ul, + nx_mlc_rgbfmt_x8b3g3r2 = 0xc1200000ul, + nx_mlc_rgbfmt_a1r5g5b5 = 0x33420000ul, + nx_mlc_rgbfmt_a1b5g5r5 = 0xb3420000ul, + nx_mlc_rgbfmt_a4r4g4b4 = 0x22110000ul, + nx_mlc_rgbfmt_a4b4g4r4 = 0xa2110000ul, + nx_mlc_rgbfmt_a8r3g3b2 = 0x11200000ul, + nx_mlc_rgbfmt_a8b3g3r2 = 0x91200000ul, + nx_mlc_rgbfmt_r8g8b8 = 0x46530000ul, + nx_mlc_rgbfmt_b8g8r8 = 0xc6530000ul, + nx_mlc_rgbfmt_x8r8g8b8 = 0x46530000ul, + nx_mlc_rgbfmt_x8b8g8r8 = 0xc6530000ul, + nx_mlc_rgbfmt_a8r8g8b8 = 0x06530000ul, + nx_mlc_rgbfmt_a8b8g8r8 = 0x86530000ul +}; + +enum nx_mlc_yuvfmt { + nx_mlc_yuvfmt_420 = 0ul << 16, + nx_mlc_yuvfmt_422 = 1ul << 16, + nx_mlc_yuvfmt_444 = 3ul << 16, + nx_mlc_yuvfmt_yuyv = 2ul << 16, + nx_mlc_yuvfmt_422_cbcr = 4ul << 16, + nx_mlc_yuvfmt_420_cbcr = 5ul << 16, +}; + +#ifdef __arm +#pragma diag_default 66 +#endif + +int nx_mlc_initialize(void); +u32 nx_mlc_get_number_of_module(void); +u32 nx_mlc_get_physical_address(u32 module_index); +u32 nx_mlc_get_size_of_register_set(void); +void nx_mlc_set_base_address(u32 module_index, void *base_address); +void *nx_mlc_get_base_address(u32 module_index); +int nx_mlc_open_module(u32 module_index); +int nx_mlc_close_module(u32 module_index); +int nx_mlc_check_busy(u32 module_index); +int nx_mlc_can_power_down(u32 module_index); +void nx_mlc_set_clock_pclk_mode(u32 module_index, enum nx_pclkmode mode); +enum nx_pclkmode nx_mlc_get_clock_pclk_mode(u32 module_index); +void nx_mlc_set_clock_bclk_mode(u32 module_index, enum nx_bclkmode mode); +enum nx_bclkmode nx_mlc_get_clock_bclk_mode(u32 module_index); + +void nx_mlc_set_top_power_mode(u32 module_index, int bpower); +int nx_mlc_get_top_power_mode(u32 module_index); +void nx_mlc_set_top_sleep_mode(u32 module_index, int bsleep); +int nx_mlc_get_top_sleep_mode(u32 module_index); +void nx_mlc_set_top_dirty_flag(u32 module_index); +int nx_mlc_get_top_dirty_flag(u32 module_index); +void nx_mlc_set_mlc_enable(u32 module_index, int benb); +int nx_mlc_get_mlc_enable(u32 module_index); +void nx_mlc_set_field_enable(u32 module_index, int benb); +int nx_mlc_get_field_enable(u32 module_index); +void nx_mlc_set_layer_priority(u32 module_index, + enum nx_mlc_priority priority); +void nx_mlc_set_screen_size(u32 module_index, u32 width, u32 height); +void nx_mlc_get_screen_size(u32 module_index, u32 *pwidth, + u32 *pheight); +void nx_mlc_set_background(u32 module_index, u32 color); + +void nx_mlc_set_dirty_flag(u32 module_index, u32 layer); +int nx_mlc_get_dirty_flag(u32 module_index, u32 layer); +void nx_mlc_set_layer_enable(u32 module_index, u32 layer, int benb); +int nx_mlc_get_layer_enable(u32 module_index, u32 layer); +void nx_mlc_set_lock_size(u32 module_index, u32 layer, u32 locksize); +void nx_mlc_set_alpha_blending(u32 module_index, u32 layer, int benb, + u32 alpha); +void nx_mlc_set_transparency(u32 module_index, u32 layer, int benb, + u32 color); +void nx_mlc_set_color_inversion(u32 module_index, u32 layer, int benb, + u32 color); +u32 nx_mlc_get_extended_color(u32 module_index, u32 color, + enum nx_mlc_rgbfmt format); +void nx_mlc_set_format_rgb(u32 module_index, u32 layer, + enum nx_mlc_rgbfmt format); +void nx_mlc_set_format_yuv(u32 module_index, enum nx_mlc_yuvfmt format); +void nx_mlc_set_position(u32 module_index, u32 layer, s32 sx, + s32 sy, s32 ex, s32 ey); +void nx_mlc_set_dither_enable_when_using_gamma(u32 module_index, + int benable); +int nx_mlc_get_dither_enable_when_using_gamma(u32 module_index); +void nx_mlc_set_gamma_priority(u32 module_index, int bvideolayer); +int nx_mlc_get_gamma_priority(u32 module_index); + +void nx_mlc_set_rgblayer_invalid_position(u32 module_index, u32 layer, + u32 region, s32 sx, + s32 sy, s32 ex, + s32 ey, int benb); +void nx_mlc_set_rgblayer_stride(u32 module_index, u32 layer, + s32 hstride, s32 vstride); +void nx_mlc_set_rgblayer_address(u32 module_index, u32 layer, u32 addr); +void nx_mlc_set_rgblayer_gama_table_power_mode(u32 module_index, + int bred, int bgreen, + int bblue); +void nx_mlc_get_rgblayer_gama_table_power_mode(u32 module_index, + int *pbred, int *pbgreen, + int *pbblue); +void nx_mlc_set_rgblayer_gama_table_sleep_mode(u32 module_index, + int bred, int bgreen, + int bblue); +void nx_mlc_get_rgblayer_gama_table_sleep_mode(u32 module_index, + int *pbred, int *pbgreen, + int *pbblue); +void nx_mlc_set_rgblayer_rgamma_table(u32 module_index, u32 dwaddress, + u32 dwdata); +void nx_mlc_set_rgblayer_ggamma_table(u32 module_index, u32 dwaddress, + u32 dwdata); +void nx_mlc_set_rgblayer_bgamma_table(u32 module_index, u32 dwaddress, + u32 dwdata); +void nx_mlc_set_rgblayer_gamma_enable(u32 module_index, int benable); +int nx_mlc_get_rgblayer_gamma_enable(u32 module_index); + +void nx_mlc_set_video_layer_stride(u32 module_index, s32 lu_stride, + s32 cb_stride, s32 cr_stride); +void nx_mlc_set_video_layer_address(u32 module_index, u32 lu_addr, + u32 cb_addr, u32 cr_addr); +void nx_mlc_set_video_layer_address_yuyv(u32 module_index, u32 addr, + s32 stride); +void nx_mlc_set_video_layer_scale_factor(u32 module_index, u32 hscale, + u32 vscale, int bhlumaenb, + int bhchromaenb, int bvlumaenb, + int bvchromaenb); +void nx_mlc_set_video_layer_scale_filter(u32 module_index, int bhlumaenb, + int bhchromaenb, int bvlumaenb, + int bvchromaenb); +void nx_mlc_get_video_layer_scale_filter(u32 module_index, + int *bhlumaenb, + int *bhchromaenb, + int *bvlumaenb, + int *bvchromaenb); +void nx_mlc_set_video_layer_scale(u32 module_index, u32 sw, u32 sh, + u32 dw, u32 dh, int bhlumaenb, + int bhchromaenb, int bvlumaenb, + int bvchromaenb); +void nx_mlc_set_video_layer_luma_enhance(u32 module_index, u32 contrast, + s32 brightness); +void nx_mlc_set_video_layer_chroma_enhance(u32 module_index, + u32 quadrant, s32 cb_a, + s32 cb_b, s32 cr_a, + s32 cr_b); +void nx_mlc_set_video_layer_line_buffer_power_mode(u32 module_index, + int benable); +int nx_mlc_get_video_layer_line_buffer_power_mode(u32 module_index); +void nx_mlc_set_video_layer_line_buffer_sleep_mode(u32 module_index, + int benable); +int nx_mlc_get_video_layer_line_buffer_sleep_mode(u32 module_index); +void nx_mlc_set_video_layer_gamma_enable(u32 module_index, int benable); +int nx_mlc_get_video_layer_gamma_enable(u32 module_index); + +void nx_mlc_set_gamma_table_poweroff(u32 module_index, int enb); + +enum mlc_rgbfmt { + rgbfmt_r5g6b5 = 0, + rgbfmt_x1r5g5b5 = 1, + rgbfmt_x4r4g4b4 = 2, + rgbfmt_x8r3g3b2 = 3, + rgbfmt_x8l8 = 4, + rgbfmt_l16 = 5, + rgbfmt_a1r5g5b5 = 6, + rgbfmt_a4r4g4b4 = 7, + rgbfmt_a8r3g3b2 = 8, + rgbfmt_a8l8 = 9, + rgbfmt_r8g8b8 = 10, + rgbfmt_x8r8g8b8 = 11, + rgbfmt_a8r8g8b8 = 12, + rgbfmt_g8r8_g8b8 = 13, + rgbfmt_r8g8_b8g8 = 14, + rgbfmt_b5g6r5 = 15, + rgbfmt_x1b5g5r5 = 16, + rgbfmt_x4b4g4r4 = 17, + rgbfmt_x8b3g3r2 = 18, + rgbfmt_a1b5g5r5 = 19, + rgbfmt_a4b4g4r4 = 20, + rgbfmt_a8b3g3r2 = 21, + rgbfmt_b8g8r8 = 22, + rgbfmt_x8b8g8r8 = 23, + rgbfmt_a8b8g8r8 = 24, + rgbfmt_g8b8_g8r8 = 25, + rgbfmt_b8g8_r8g8 = 26, + rgbfmt_pataletb = 27 +}; + +enum latyername { + topmlc = 0, + rgb0 = 1, + rgb1 = 2, + rgb2 = 3, + video = 4 +}; + +enum srammode { + poweroff = 0, + sleepmode = 2, + run = 3 +}; + +enum locksizesel { + locksize_4 = 0, + locksize_8 = 1, + locksize_16 = 2 +}; + +enum g3daddrchangeallowed { + prim = 0, + secon = 1, + primorsecon = 2, + primandsecon = 3 +}; + +void nx_mlc_set_mlctop_control_parameter(u32 module_index, + int field_enable, int mlcenable, + u8 priority, + enum g3daddrchangeallowed + g3daddr_change_allowed); +void nx_mlc_set_rgb0layer_control_parameter(u32 module_index, + int layer_enable, + int grp3denable, + int tp_enable, + u32 transparency_color, + int inv_enable, + u32 inverse_color, + int blend_enable, + u8 alpha_value, + enum mlc_rgbfmt rbgformat, + enum locksizesel + lock_size_select); + +u32 nx_mlc_get_rgbformat(enum mlc_rgbfmt rbgformat); +void nx_mlc_set_rgb1layer_control_parameter(u32 module_index, + int layer_enable, + int grp3denable, + int tp_enable, + u32 transparency_color, + int inv_enable, + u32 inverse_color, + int blend_enable, + u8 alpha_value, + enum mlc_rgbfmt rbgformat, + enum locksizesel + lock_size_select); + +void nx_mlc_set_rgb2layer_control_parameter(u32 module_index, + int layer_enable, + int grp3denable, + int tp_enable, + u32 transparency_color, + int inv_enable, + u32 inverse_color, + int blend_enable, + u8 alpha_value, + enum mlc_rgbfmt rbgformat, + enum locksizesel + lock_size_select); + +void nx_mlc_set_video_layer_control_parameter(u32 module_index, + int layer_enable, + int tp_enable, + u32 transparency_color, + int inv_enable, + u32 inverse_color, + int blend_enable, + u8 alpha_value, + enum nx_mlc_yuvfmt + yuvformat); + +void nx_mlc_set_srammode(u32 module_index, enum latyername layer_name, + enum srammode sram_mode); + +void nx_mlc_set_layer_reg_finish(u32 module_index, + enum latyername layer_name); + +void nx_mlc_set_video_layer_coordinate(u32 module_index, + int vfilterenable, + int hfilterenable, + int vfilterenable_c, + int hfilterenable_c, + u16 video_layer_with, + u16 video_layer_height, + s16 left, s16 right, + s16 top, s16 bottom); + +void nx_mlc_set_video_layer_filter_scale(u32 module_index, u32 hscale, + u32 vscale); +void nx_mlcsetgammasrammode(u32 module_index, enum srammode sram_mode); +void nx_mlc_set_gamma_control_parameter(u32 module_index, + int rgbgammaenb, int yuvgammaenb, + int yuvalphaarray, + int dither_enb); + +void nx_mlc_set_layer_alpha256(u32 module_index, u32 layer, u32 alpha); +int nx_mlc_is_under_flow(u32 module_index); + +struct nx_mlc_gamma_table_parameter { + u32 r_table[256]; + u32 g_table[256]; + u32 b_table[256]; + u32 ditherenb; + u32 alphaselect; + u32 yuvgammaenb; + u32 rgbgammaenb; + u32 allgammaenb; +}; + +void nx_mlc_set_gamma_table(u32 module_index, int enb, + struct nx_mlc_gamma_table_parameter *p_gammatable); +void nx_mlc_get_rgblayer_stride(u32 module_index, u32 layer, + s32 *hstride, s32 *vstride); +void nx_mlc_get_rgblayer_address(u32 module_index, u32 layer, + u32 *phys_address); +void nx_mlc_get_position(u32 module_index, u32 layer, int *left, + int *top, int *right, int *bottom); +void nx_mlc_get_video_layer_address_yuyv(u32 module_index, u32 *address, + u32 *stride); +void nx_mlc_get_video_layer_address(u32 module_index, u32 *lu_address, + u32 *cb_address, u32 *cr_address); +void nx_mlc_get_video_layer_stride(u32 module_index, u32 *lu_stride, + u32 *cb_stride, u32 *cr_stride); +void nx_mlc_get_video_layer_stride(u32 module_index, u32 *lu_stride, + u32 *cb_stride, u32 *cr_stride); +void nx_mlc_get_video_position(u32 module_index, int *left, int *top, + int *right, int *bottom); + +#endif diff --git a/drivers/video/nexell_display.c b/drivers/video/nexell_display.c new file mode 100644 index 0000000000..4101e0962a --- /dev/null +++ b/drivers/video/nexell_display.c @@ -0,0 +1,651 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2016 Nexell Co., Ltd. + * + * Author: junghyun, kim <jhkim@nexell.co.kr> + * + * Copyright (C) 2020 Stefan Bosch <stefan_b@posteo.net> + */ + +#include <config.h> +#include <common.h> +#include <command.h> +#include <dm.h> +#include <mapmem.h> +#include <malloc.h> +#include <linux/compat.h> +#include <linux/err.h> +#include <video.h> /* For struct video_uc_platdata */ +#include <video_fb.h> +#include <lcd.h> +#include <asm/global_data.h> +#include <asm/io.h> +#include <asm/arch/display.h> +#include <asm/arch/display_dev.h> +#include "videomodes.h" + +DECLARE_GLOBAL_DATA_PTR; + +#if !defined(CONFIG_DM) && !defined(CONFIG_OF_CONTROL) +static struct nx_display_dev *dp_dev; +#endif + +static char *const dp_dev_str[] = { + [DP_DEVICE_RESCONV] = "RESCONV", + [DP_DEVICE_RGBLCD] = "LCD", + [DP_DEVICE_HDMI] = "HDMI", + [DP_DEVICE_MIPI] = "MiPi", + [DP_DEVICE_LVDS] = "LVDS", + [DP_DEVICE_CVBS] = "TVOUT", + [DP_DEVICE_DP0] = "DP0", + [DP_DEVICE_DP1] = "DP1", +}; + +#if CONFIG_IS_ENABLED(OF_CONTROL) +static void nx_display_parse_dp_sync(ofnode node, struct dp_sync_info *sync) +{ + sync->h_active_len = ofnode_read_s32_default(node, "h_active_len", 0); + sync->h_sync_width = ofnode_read_s32_default(node, "h_sync_width", 0); + sync->h_back_porch = ofnode_read_s32_default(node, "h_back_porch", 0); + sync->h_front_porch = ofnode_read_s32_default(node, "h_front_porch", 0); + sync->h_sync_invert = ofnode_read_s32_default(node, "h_sync_invert", 0); + sync->v_active_len = ofnode_read_s32_default(node, "v_active_len", 0); + sync->v_sync_width = ofnode_read_s32_default(node, "v_sync_width", 0); + sync->v_back_porch = ofnode_read_s32_default(node, "v_back_porch", 0); + sync->v_front_porch = ofnode_read_s32_default(node, "v_front_porch", 0); + sync->v_sync_invert = ofnode_read_s32_default(node, "v_sync_invert", 0); + sync->pixel_clock_hz = ofnode_read_s32_default(node, "pixel_clock_hz", 0); + + debug("DP: sync ->\n"); + debug("ha:%d, hs:%d, hb:%d, hf:%d, hi:%d\n", + sync->h_active_len, sync->h_sync_width, + sync->h_back_porch, sync->h_front_porch, sync->h_sync_invert); + debug("va:%d, vs:%d, vb:%d, vf:%d, vi:%d\n", + sync->v_active_len, sync->v_sync_width, + sync->v_back_porch, sync->v_front_porch, sync->v_sync_invert); +} + +static void nx_display_parse_dp_ctrl(ofnode node, struct dp_ctrl_info *ctrl) +{ + /* clock gen */ + ctrl->clk_src_lv0 = ofnode_read_s32_default(node, "clk_src_lv0", 0); + ctrl->clk_div_lv0 = ofnode_read_s32_default(node, "clk_div_lv0", 0); + ctrl->clk_src_lv1 = ofnode_read_s32_default(node, "clk_src_lv1", 0); + ctrl->clk_div_lv1 = ofnode_read_s32_default(node, "clk_div_lv1", 0); + + /* scan format */ + ctrl->interlace = ofnode_read_s32_default(node, "interlace", 0); + + /* syncgen format */ + ctrl->out_format = ofnode_read_s32_default(node, "out_format", 0); + ctrl->invert_field = ofnode_read_s32_default(node, "invert_field", 0); + ctrl->swap_RB = ofnode_read_s32_default(node, "swap_RB", 0); + ctrl->yc_order = ofnode_read_s32_default(node, "yc_order", 0); + + /* extern sync delay */ + ctrl->delay_mask = ofnode_read_s32_default(node, "delay_mask", 0); + ctrl->d_rgb_pvd = ofnode_read_s32_default(node, "d_rgb_pvd", 0); + ctrl->d_hsync_cp1 = ofnode_read_s32_default(node, "d_hsync_cp1", 0); + ctrl->d_vsync_fram = ofnode_read_s32_default(node, "d_vsync_fram", 0); + ctrl->d_de_cp2 = ofnode_read_s32_default(node, "d_de_cp2", 0); + + /* extern sync delay */ + ctrl->vs_start_offset = + ofnode_read_s32_default(node, "vs_start_offset", 0); + ctrl->vs_end_offset = ofnode_read_s32_default(node, "vs_end_offset", 0); + ctrl->ev_start_offset = + ofnode_read_s32_default(node, "ev_start_offset", 0); + ctrl->ev_end_offset = ofnode_read_s32_default(node, "ev_end_offset", 0); + + /* pad clock seletor */ + ctrl->vck_select = ofnode_read_s32_default(node, "vck_select", 0); + ctrl->clk_inv_lv0 = ofnode_read_s32_default(node, "clk_inv_lv0", 0); + ctrl->clk_delay_lv0 = ofnode_read_s32_default(node, "clk_delay_lv0", 0); + ctrl->clk_inv_lv1 = ofnode_read_s32_default(node, "clk_inv_lv1", 0); + ctrl->clk_delay_lv1 = ofnode_read_s32_default(node, "clk_delay_lv1", 0); + ctrl->clk_sel_div1 = ofnode_read_s32_default(node, "clk_sel_div1", 0); + + debug("DP: ctrl [%s] ->\n", + ctrl->interlace ? "Interlace" : " Progressive"); + debug("cs0:%d, cd0:%d, cs1:%d, cd1:%d\n", + ctrl->clk_src_lv0, ctrl->clk_div_lv0, + ctrl->clk_src_lv1, ctrl->clk_div_lv1); + debug("fmt:0x%x, inv:%d, swap:%d, yb:0x%x\n", + ctrl->out_format, ctrl->invert_field, + ctrl->swap_RB, ctrl->yc_order); + debug("dm:0x%x, drp:%d, dhs:%d, dvs:%d, dde:0x%x\n", + ctrl->delay_mask, ctrl->d_rgb_pvd, + ctrl->d_hsync_cp1, ctrl->d_vsync_fram, ctrl->d_de_cp2); + debug("vss:%d, vse:%d, evs:%d, eve:%d\n", + ctrl->vs_start_offset, ctrl->vs_end_offset, + ctrl->ev_start_offset, ctrl->ev_end_offset); + debug("sel:%d, i0:%d, d0:%d, i1:%d, d1:%d, s1:%d\n", + ctrl->vck_select, ctrl->clk_inv_lv0, ctrl->clk_delay_lv0, + ctrl->clk_inv_lv1, ctrl->clk_delay_lv1, ctrl->clk_sel_div1); +} + +static void nx_display_parse_dp_top_layer(ofnode node, struct dp_plane_top *top) +{ + top->screen_width = ofnode_read_s32_default(node, "screen_width", 0); + top->screen_height = ofnode_read_s32_default(node, "screen_height", 0); + top->video_prior = ofnode_read_s32_default(node, "video_prior", 0); + top->interlace = ofnode_read_s32_default(node, "interlace", 0); + top->back_color = ofnode_read_s32_default(node, "back_color", 0); + top->plane_num = DP_PLANS_NUM; + + debug("DP: top [%s] ->\n", + top->interlace ? "Interlace" : " Progressive"); + debug("w:%d, h:%d, prior:%d, bg:0x%x\n", + top->screen_width, top->screen_height, + top->video_prior, top->back_color); +} + +static void nx_display_parse_dp_layer(ofnode node, struct dp_plane_info *plane) +{ + plane->left = ofnode_read_s32_default(node, "left", 0); + plane->width = ofnode_read_s32_default(node, "width", 0); + plane->top = ofnode_read_s32_default(node, "top", 0); + plane->height = ofnode_read_s32_default(node, "height", 0); + plane->pixel_byte = ofnode_read_s32_default(node, "pixel_byte", 0); + plane->format = ofnode_read_s32_default(node, "format", 0); + plane->alpha_on = ofnode_read_s32_default(node, "alpha_on", 0); + plane->alpha_depth = ofnode_read_s32_default(node, "alpha", 0); + plane->tp_on = ofnode_read_s32_default(node, "tp_on", 0); + plane->tp_color = ofnode_read_s32_default(node, "tp_color", 0); + + /* enable layer */ + if (plane->fb_base) + plane->enable = 1; + else + plane->enable = 0; + + if (plane->fb_base == 0) { + printf("fail : dp plane.%d invalid fb base [0x%x] ->\n", + plane->layer, plane->fb_base); + return; + } + + debug("DP: plane.%d [0x%x] ->\n", plane->layer, plane->fb_base); + debug("f:0x%x, l:%d, t:%d, %d * %d, bpp:%d, a:%d(%d), t:%d(0x%x)\n", + plane->format, plane->left, plane->top, plane->width, + plane->height, plane->pixel_byte, plane->alpha_on, + plane->alpha_depth, plane->tp_on, plane->tp_color); +} + +static void nx_display_parse_dp_planes(ofnode node, + struct nx_display_dev *dp, + struct video_uc_platdata *plat) +{ + const char *name; + ofnode subnode; + + ofnode_for_each_subnode(subnode, node) { + name = ofnode_get_name(subnode); + + if (strcmp(name, "layer_top") == 0) + nx_display_parse_dp_top_layer(subnode, &dp->top); + + /* + * TODO: Is it sure that only one layer is used? Otherwise + * fb_base must be different? + */ + if (strcmp(name, "layer_0") == 0) { + dp->planes[0].fb_base = + (uint)map_sysmem(plat->base, plat->size); + debug("%s(): dp->planes[0].fb_base == 0x%x\n", __func__, + (uint)dp->planes[0].fb_base); + nx_display_parse_dp_layer(subnode, &dp->planes[0]); + } + + if (strcmp(name, "layer_1") == 0) { + dp->planes[1].fb_base = + (uint)map_sysmem(plat->base, plat->size); + debug("%s(): dp->planes[1].fb_base == 0x%x\n", __func__, + (uint)dp->planes[1].fb_base); + nx_display_parse_dp_layer(subnode, &dp->planes[1]); + } + + if (strcmp(name, "layer_2") == 0) { + dp->planes[2].fb_base = + (uint)map_sysmem(plat->base, plat->size); + debug("%s(): dp->planes[2].fb_base == 0x%x\n", __func__, + (uint)dp->planes[2].fb_base); + nx_display_parse_dp_layer(subnode, &dp->planes[2]); + } + } +} + +static int nx_display_parse_dp_lvds(ofnode node, struct nx_display_dev *dp) +{ + struct dp_lvds_dev *dev = kzalloc(sizeof(*dev), GFP_KERNEL); + + if (!dev) { + printf("failed to allocate display LVDS object.\n"); + return -ENOMEM; + } + + dp->device = dev; + + dev->lvds_format = ofnode_read_s32_default(node, "format", 0); + dev->pol_inv_hs = ofnode_read_s32_default(node, "pol_inv_hs", 0); + dev->pol_inv_vs = ofnode_read_s32_default(node, "pol_inv_vs", 0); + dev->pol_inv_de = ofnode_read_s32_default(node, "pol_inv_de", 0); + dev->pol_inv_ck = ofnode_read_s32_default(node, "pol_inv_ck", 0); + dev->voltage_level = ofnode_read_s32_default(node, "voltage_level", 0); + + if (!dev->voltage_level) + dev->voltage_level = DEF_VOLTAGE_LEVEL; + + debug("DP: LVDS -> %s, voltage LV:0x%x\n", + dev->lvds_format == DP_LVDS_FORMAT_VESA ? "VESA" : + dev->lvds_format == DP_LVDS_FORMAT_JEIDA ? "JEIDA" : "LOC", + dev->voltage_level); + debug("pol inv hs:%d, vs:%d, de:%d, ck:%d\n", + dev->pol_inv_hs, dev->pol_inv_vs, + dev->pol_inv_de, dev->pol_inv_ck); + + return 0; +} + +static int nx_display_parse_dp_rgb(ofnode node, struct nx_display_dev *dp) +{ + struct dp_rgb_dev *dev = kzalloc(sizeof(*dev), GFP_KERNEL); + + if (!dev) { + printf("failed to allocate display RGB LCD object.\n"); + return -ENOMEM; + } + dp->device = dev; + + dev->lcd_mpu_type = ofnode_read_s32_default(node, "lcd_mpu_type", 0); + + debug("DP: RGB -> MPU[%s]\n", dev->lcd_mpu_type ? "O" : "X"); + return 0; +} + +static int nx_display_parse_dp_mipi(ofnode node, struct nx_display_dev *dp) +{ + struct dp_mipi_dev *dev = kzalloc(sizeof(*dev), GFP_KERNEL); + + if (!dev) { + printf("failed to allocate display MiPi object.\n"); + return -ENOMEM; + } + dp->device = dev; + + dev->lp_bitrate = ofnode_read_s32_default(node, "lp_bitrate", 0); + dev->hs_bitrate = ofnode_read_s32_default(node, "hs_bitrate", 0); + dev->lpm_trans = 1; + dev->command_mode = 0; + + debug("DP: MIPI ->\n"); + debug("lp:%dmhz, hs:%dmhz\n", dev->lp_bitrate, dev->hs_bitrate); + + return 0; +} + +static int nx_display_parse_dp_hdmi(ofnode node, struct nx_display_dev *dp) +{ + struct dp_hdmi_dev *dev = kzalloc(sizeof(*dev), GFP_KERNEL); + + if (!dev) { + printf("failed to allocate display HDMI object.\n"); + return -ENOMEM; + } + dp->device = dev; + + dev->preset = ofnode_read_s32_default(node, "preset", 0); + + debug("DP: HDMI -> %d\n", dev->preset); + + return 0; +} + +static int nx_display_parse_dp_lcds(ofnode node, const char *type, + struct nx_display_dev *dp) +{ + if (strcmp(type, "lvds") == 0) { + dp->dev_type = DP_DEVICE_LVDS; + return nx_display_parse_dp_lvds(node, dp); + } else if (strcmp(type, "rgb") == 0) { + dp->dev_type = DP_DEVICE_RGBLCD; + return nx_display_parse_dp_rgb(node, dp); + } else if (strcmp(type, "mipi") == 0) { + dp->dev_type = DP_DEVICE_MIPI; + return nx_display_parse_dp_mipi(node, dp); + } else if (strcmp(type, "hdmi") == 0) { + dp->dev_type = DP_DEVICE_HDMI; + return nx_display_parse_dp_hdmi(node, dp); + } + + printf("%s: node %s unknown display type\n", __func__, + ofnode_get_name(node)); + return -EINVAL; + + return 0; +} + +#define DT_SYNC (1 << 0) +#define DT_CTRL (1 << 1) +#define DT_PLANES (1 << 2) +#define DT_DEVICE (1 << 3) + +static int nx_display_parse_dt(struct udevice *dev, + struct nx_display_dev *dp, + struct video_uc_platdata *plat) +{ + const char *name, *dtype; + int ret = 0; + unsigned int dt_status = 0; + ofnode subnode; + + if (!dev) + return -ENODEV; + + dp->module = dev_read_s32_default(dev, "module", -1); + if (dp->module == -1) + dp->module = dev_read_s32_default(dev, "index", 0); + + dtype = dev_read_string(dev, "lcd-type"); + + ofnode_for_each_subnode(subnode, dev_ofnode(dev)) { + name = ofnode_get_name(subnode); + + if (strcmp("dp-sync", name) == 0) { + dt_status |= DT_SYNC; + nx_display_parse_dp_sync(subnode, &dp->sync); + } + + if (strcmp("dp-ctrl", name) == 0) { + dt_status |= DT_CTRL; + nx_display_parse_dp_ctrl(subnode, &dp->ctrl); + } + + if (strcmp("dp-planes", name) == 0) { + dt_status |= DT_PLANES; + nx_display_parse_dp_planes(subnode, dp, plat); + } + + if (strcmp("dp-device", name) == 0) { + dt_status |= DT_DEVICE; + ret = nx_display_parse_dp_lcds(subnode, dtype, dp); + } + } + + if (dt_status != (DT_SYNC | DT_CTRL | DT_PLANES | DT_DEVICE)) { + printf("Not enough DT config for display [0x%x]\n", dt_status); + return -ENODEV; + } + + return ret; +} +#endif + +__weak int nx_display_fixup_dp(struct nx_display_dev *dp) +{ + return 0; +} + +static struct nx_display_dev *nx_display_setup(void) +{ + struct nx_display_dev *dp; + int i, ret; + int node = 0; + struct video_uc_platdata *plat = NULL; + + struct udevice *dev; + + /* call driver probe */ + debug("DT: uclass device call...\n"); + + ret = uclass_get_device(UCLASS_VIDEO, 0, &dev); + if (ret) { + debug("%s(): uclass_get_device(UCLASS_VIDEO, 0, &dev) != 0 --> return NULL\n", + __func__); + return NULL; + } + plat = dev_get_uclass_platdata(dev); + if (!dev) { + debug("%s(): dev_get_uclass_platdata(dev) == NULL --> return NULL\n", + __func__); + return NULL; + } + dp = dev_get_priv(dev); + if (!dp) { + debug("%s(): dev_get_priv(dev) == NULL --> return NULL\n", + __func__); + return NULL; + } + node = dev->node.of_offset; + + if (CONFIG_IS_ENABLED(OF_CONTROL)) { + ret = nx_display_parse_dt(dev, dp, plat); + if (ret) + goto err_setup; + } + + nx_display_fixup_dp(dp); + + for (i = 0; dp->top.plane_num > i; i++) { + dp->planes[i].layer = i; + if (dp->planes[i].enable && !dp->fb_plane) { + dp->fb_plane = &dp->planes[i]; + dp->fb_addr = dp->fb_plane->fb_base; + dp->depth = dp->fb_plane->pixel_byte; + } + } + + switch (dp->dev_type) { +#ifdef CONFIG_VIDEO_NX_RGB + case DP_DEVICE_RGBLCD: + nx_rgb_display(dp->module, + &dp->sync, &dp->ctrl, &dp->top, + dp->planes, (struct dp_rgb_dev *)dp->device); + break; +#endif +#ifdef CONFIG_VIDEO_NX_LVDS + case DP_DEVICE_LVDS: + nx_lvds_display(dp->module, + &dp->sync, &dp->ctrl, &dp->top, + dp->planes, (struct dp_lvds_dev *)dp->device); + break; +#endif +#ifdef CONFIG_VIDEO_NX_MIPI + case DP_DEVICE_MIPI: + nx_mipi_display(dp->module, + &dp->sync, &dp->ctrl, &dp->top, + dp->planes, (struct dp_mipi_dev *)dp->device); + break; +#endif +#ifdef CONFIG_VIDEO_NX_HDMI + case DP_DEVICE_HDMI: + nx_hdmi_display(dp->module, + &dp->sync, &dp->ctrl, &dp->top, + dp->planes, (struct dp_hdmi_dev *)dp->device); + break; +#endif + default: + printf("fail : not support lcd type %d !!!\n", dp->dev_type); + goto err_setup; + }; + + printf("LCD: [%s] dp.%d.%d %dx%d %dbpp FB:0x%08x\n", + dp_dev_str[dp->dev_type], dp->module, dp->fb_plane->layer, + dp->fb_plane->width, dp->fb_plane->height, dp->depth * 8, + dp->fb_addr); + + return dp; + +err_setup: + kfree(dp); + + return NULL; +} + +#if defined CONFIG_LCD + +/* default lcd */ +struct vidinfo panel_info = { + .vl_col = 320, .vl_row = 240, .vl_bpix = 32, +}; + +void lcd_ctrl_init(void *lcdbase) +{ + vidinfo_t *pi = &panel_info; + struct nx_display_dev *dp; + int bpix; + + dp = nx_display_setup(); + if (!dp) + return NULL; + + switch (dp->depth) { + case 2: + bpix = LCD_COLOR16; + break; + case 3: + case 4: + bpix = LCD_COLOR32; + break; + default: + printf("fail : not support LCD bit per pixel %d\n", + dp->depth * 8); + return NULL; + } + + dp->panel_info = pi; + + /* set resolution with config */ + pi->vl_bpix = bpix; + pi->vl_col = dp->fb_plane->width; + pi->vl_row = dp->fb_plane->height; + pi->priv = dp; + gd->fb_base = dp->fb_addr; +} + +void lcd_setcolreg(ushort regno, ushort red, ushort green, ushort blue) +{ +} + +__weak void lcd_enable(void) +{ +} +#endif + +static int nx_display_probe(struct udevice *dev) +{ + struct video_uc_platdata *uc_plat = dev_get_uclass_platdata(dev); + struct video_priv *uc_priv = dev_get_uclass_priv(dev); + struct nx_display_platdata *plat = dev_get_platdata(dev); + static GraphicDevice *graphic_device; + char addr[64]; + + debug("%s()\n", __func__); + + if (!dev) + return -EINVAL; + + if (!uc_plat) { + debug("%s(): video_uc_platdata *plat == NULL --> return -EINVAL\n", + __func__); + return -EINVAL; + } + + if (!uc_priv) { + debug("%s(): video_priv *uc_priv == NULL --> return -EINVAL\n", + __func__); + return -EINVAL; + } + + if (!plat) { + debug("%s(): nx_display_platdata *plat == NULL --> return -EINVAL\n", + __func__); + return -EINVAL; + } + + struct nx_display_dev *dp; + unsigned int pp_index = 0; + + dp = nx_display_setup(); + if (!dp) { + debug("%s(): nx_display_setup() == 0 --> return -EINVAL\n", + __func__); + return -EINVAL; + } + + switch (dp->depth) { + case 2: + pp_index = GDF_16BIT_565RGB; + uc_priv->bpix = VIDEO_BPP16; + break; + case 3: + /* There is no VIDEO_BPP24 because these values are of + * type video_log2_bpp + */ + case 4: + pp_index = GDF_32BIT_X888RGB; + uc_priv->bpix = VIDEO_BPP32; + break; + default: + printf("fail : not support LCD bit per pixel %d\n", + dp->depth * 8); + return -EINVAL; + } + + uc_priv->xsize = dp->fb_plane->width; + uc_priv->ysize = dp->fb_plane->height; + uc_priv->rot = 0; + + graphic_device = &dp->graphic_device; + graphic_device->frameAdrs = dp->fb_addr; + graphic_device->gdfIndex = pp_index; + graphic_device->gdfBytesPP = dp->depth; + graphic_device->winSizeX = dp->fb_plane->width; + graphic_device->winSizeY = dp->fb_plane->height; + graphic_device->plnSizeX = + graphic_device->winSizeX * graphic_device->gdfBytesPP; + + /* + * set environment variable "fb_addr" (frame buffer address), required + * for splash image. Because drv_video_init() in common/stdio.c is only + * called when CONFIG_VIDEO is set (and not if CONFIG_DM_VIDEO is set). + */ + sprintf(addr, "0x%x", dp->fb_addr); + debug("%s(): env_set(\"fb_addr\", %s) ...\n", __func__, addr); + env_set("fb_addr", addr); + + return 0; +} + +static int nx_display_bind(struct udevice *dev) +{ + struct video_uc_platdata *plat = dev_get_uclass_platdata(dev); + + debug("%s()\n", __func__); + + /* Datasheet S5p4418: + * Resolution up to 2048 x 1280, up to 12 Bit per color (HDMI) + * Actual (max.) size is 0x1000000 because in U-Boot nanopi2-2016.01 + * "#define CONFIG_FB_ADDR 0x77000000" and next address is + * "#define BMP_LOAD_ADDR 0x78000000" + */ + plat->size = 0x1000000; + + return 0; +} + +static const struct udevice_id nx_display_ids[] = { + {.compatible = "nexell,nexell-display", }, + {} +}; + +U_BOOT_DRIVER(nexell_display) = { + .name = "nexell-display", + .id = UCLASS_VIDEO, + .of_match = nx_display_ids, + .platdata_auto_alloc_size = + sizeof(struct nx_display_platdata), + .bind = nx_display_bind, + .probe = nx_display_probe, + .priv_auto_alloc_size = sizeof(struct nx_display_dev), +}; diff --git a/drivers/video/tegra.c b/drivers/video/tegra.c index 1208d91286..827ea13d13 100644 --- a/drivers/video/tegra.c +++ b/drivers/video/tegra.c @@ -346,7 +346,7 @@ static int tegra_lcd_ofdata_to_platdata(struct udevice *dev) int rgb; int ret; - priv->disp = (struct disp_ctlr *)devfdt_get_addr(dev); + priv->disp = dev_read_addr_ptr(dev); if (!priv->disp) { debug("%s: No display controller address\n", __func__); return -EINVAL; diff --git a/drivers/w1/mxc_w1.c b/drivers/w1/mxc_w1.c index 5bf08653a9..8e6372f0be 100644 --- a/drivers/w1/mxc_w1.c +++ b/drivers/w1/mxc_w1.c @@ -171,7 +171,7 @@ static int mxc_w1_ofdata_to_platdata(struct udevice *dev) struct mxc_w1_pdata *pdata = dev_get_platdata(dev); fdt_addr_t addr; - addr = devfdt_get_addr(dev); + addr = dev_read_addr(dev); if (addr == FDT_ADDR_T_NONE) return -EINVAL; diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index bf06180cdd..6d5c4fcfeb 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -163,6 +163,15 @@ config WDT_SANDBOX can be probed and supports all of the methods of WDT, but does not really do anything. +config WDT_SBSA + bool "SBSA watchdog timer support" + depends on WDT + help + Select this to enable SBSA watchdog timer. + This driver can operate ARM SBSA Generic Watchdog as a single stage. + In the single stage mode, when the timeout is reached, your system + will be reset by WS1. The first signal (WS0) is ignored. + config WDT_SP805 bool "SP805 watchdog timer support" depends on WDT diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile index 519bbd3a40..0f0b2eb5bc 100644 --- a/drivers/watchdog/Makefile +++ b/drivers/watchdog/Makefile @@ -27,6 +27,7 @@ obj-$(CONFIG_WDT_MPC8xx) += mpc8xx_wdt.o obj-$(CONFIG_WDT_MT7621) += mt7621_wdt.o obj-$(CONFIG_WDT_MTK) += mtk_wdt.o obj-$(CONFIG_WDT_OMAP3) += omap_wdt.o +obj-$(CONFIG_WDT_SBSA) += sbsa_gwdt.o obj-$(CONFIG_WDT_SP805) += sp805_wdt.o obj-$(CONFIG_WDT_STM32MP) += stm32mp_wdt.o obj-$(CONFIG_WDT_TANGIER) += tangier_wdt.o diff --git a/drivers/watchdog/omap_wdt.c b/drivers/watchdog/omap_wdt.c index ed8b2199c2..9059a4c610 100644 --- a/drivers/watchdog/omap_wdt.c +++ b/drivers/watchdog/omap_wdt.c @@ -237,7 +237,7 @@ static int omap3_wdt_probe(struct udevice *dev) { struct omap3_wdt_priv *priv = dev_get_priv(dev); - priv->regs = (struct wd_timer *)devfdt_get_addr(dev); + priv->regs = dev_read_addr_ptr(dev); if (!priv->regs) return -EINVAL; diff --git a/drivers/watchdog/sbsa_gwdt.c b/drivers/watchdog/sbsa_gwdt.c new file mode 100644 index 0000000000..2eae431ba6 --- /dev/null +++ b/drivers/watchdog/sbsa_gwdt.c @@ -0,0 +1,131 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Watchdog driver for SBSA + * + * Copyright 2020 NXP + */ + +#include <asm/io.h> +#include <common.h> +#include <dm/device.h> +#include <dm/fdtaddr.h> +#include <dm/read.h> +#include <linux/bitops.h> +#include <linux/err.h> +#include <watchdog.h> +#include <wdt.h> + +DECLARE_GLOBAL_DATA_PTR; + +/* SBSA Generic Watchdog register definitions */ +/* refresh frame */ +#define SBSA_GWDT_WRR 0x000 + +/* control frame */ +#define SBSA_GWDT_WCS 0x000 +#define SBSA_GWDT_WOR 0x008 +#define SBSA_GWDT_WCV 0x010 + +/* refresh/control frame */ +#define SBSA_GWDT_W_IIDR 0xfcc +#define SBSA_GWDT_IDR 0xfd0 + +/* Watchdog Control and Status Register */ +#define SBSA_GWDT_WCS_EN BIT(0) +#define SBSA_GWDT_WCS_WS0 BIT(1) +#define SBSA_GWDT_WCS_WS1 BIT(2) + +struct sbsa_gwdt_priv { + void __iomem *reg_refresh; + void __iomem *reg_control; +}; + +static int sbsa_gwdt_reset(struct udevice *dev) +{ + struct sbsa_gwdt_priv *priv = dev_get_priv(dev); + + writel(0, priv->reg_refresh + SBSA_GWDT_WRR); + + return 0; +} + +static int sbsa_gwdt_start(struct udevice *dev, u64 timeout, ulong flags) +{ + struct sbsa_gwdt_priv *priv = dev_get_priv(dev); + u32 clk; + + /* + * it work in the single stage mode in u-boot, + * The first signal (WS0) is ignored, + * the timeout is (WOR * 2), so the WOR should be configured + * to half value of timeout. + */ + clk = get_tbclk(); + writel(clk / 2 * timeout, + priv->reg_control + SBSA_GWDT_WOR); + + /* writing WCS will cause an explicit watchdog refresh */ + writel(SBSA_GWDT_WCS_EN, priv->reg_control + SBSA_GWDT_WCS); + + return 0; +} + +static int sbsa_gwdt_stop(struct udevice *dev) +{ + struct sbsa_gwdt_priv *priv = dev_get_priv(dev); + + writel(0, priv->reg_control + SBSA_GWDT_WCS); + + return 0; +} + +static int sbsa_gwdt_expire_now(struct udevice *dev, ulong flags) +{ + sbsa_gwdt_start(dev, 0, flags); + + return 0; +} + +static int sbsa_gwdt_probe(struct udevice *dev) +{ + debug("%s: Probing wdt%u (sbsa-gwdt)\n", __func__, dev->seq); + + return 0; +} + +static int sbsa_gwdt_ofdata_to_platdata(struct udevice *dev) +{ + struct sbsa_gwdt_priv *priv = dev_get_priv(dev); + + priv->reg_control = (void __iomem *)dev_read_addr_index(dev, 0); + if (IS_ERR(priv->reg_control)) + return PTR_ERR(priv->reg_control); + + priv->reg_refresh = (void __iomem *)dev_read_addr_index(dev, 1); + if (IS_ERR(priv->reg_refresh)) + return PTR_ERR(priv->reg_refresh); + + return 0; +} + +static const struct wdt_ops sbsa_gwdt_ops = { + .start = sbsa_gwdt_start, + .reset = sbsa_gwdt_reset, + .stop = sbsa_gwdt_stop, + .expire_now = sbsa_gwdt_expire_now, +}; + +static const struct udevice_id sbsa_gwdt_ids[] = { + { .compatible = "arm,sbsa-gwdt" }, + {} +}; + +U_BOOT_DRIVER(sbsa_gwdt) = { + .name = "sbsa_gwdt", + .id = UCLASS_WDT, + .of_match = sbsa_gwdt_ids, + .probe = sbsa_gwdt_probe, + .priv_auto_alloc_size = sizeof(struct sbsa_gwdt_priv), + .ofdata_to_platdata = sbsa_gwdt_ofdata_to_platdata, + .ops = &sbsa_gwdt_ops, +}; diff --git a/drivers/watchdog/stm32mp_wdt.c b/drivers/watchdog/stm32mp_wdt.c index 2d8bfc09a0..f673fce327 100644 --- a/drivers/watchdog/stm32mp_wdt.c +++ b/drivers/watchdog/stm32mp_wdt.c @@ -92,7 +92,7 @@ static int stm32mp_wdt_probe(struct udevice *dev) debug("IWDG init\n"); - priv->base = devfdt_get_addr(dev); + priv->base = dev_read_addr(dev); if (priv->base == FDT_ADDR_T_NONE) return -EINVAL; |