From ac985273135762a596482812551221019c319731 Mon Sep 17 00:00:00 2001 From: Thomas Abraham Date: Sat, 23 Apr 2016 22:18:07 +0530 Subject: pinctrl: add the DM_UC_FLAG_SEQ_ALIAS flag for numbering the devices It is possible to have multiple pin controllers in the system. Use the DM_UC_FLAG_SEQ_ALIAS flag so that the pinctrl instances are assigned a sequence number. Cc: Masahiro Yamada Cc: Simon Glass Signed-off-by: Thomas Abraham Reviewed-by: Simon Glass Signed-off-by: Minkyu Kang diff --git a/drivers/pinctrl/pinctrl-uclass.c b/drivers/pinctrl/pinctrl-uclass.c index ccc5d30..fd04b26 100644 --- a/drivers/pinctrl/pinctrl-uclass.c +++ b/drivers/pinctrl/pinctrl-uclass.c @@ -287,5 +287,6 @@ static int pinctrl_post_bind(struct udevice *dev) UCLASS_DRIVER(pinctrl) = { .id = UCLASS_PINCTRL, .post_bind = pinctrl_post_bind, + .flags = DM_UC_FLAG_SEQ_ALIAS, .name = "pinctrl", }; -- cgit v0.10.2 From 16ca80adc551808b6be1d43f30997f8b4fdfbd39 Mon Sep 17 00:00:00 2001 From: Thomas Abraham Date: Sat, 23 Apr 2016 22:18:08 +0530 Subject: pinctrl: Add pinctrl driver support for Exynos7420 SoC Add pinctrl driver support for Samsung's Exynos7420 SoC. The changes have been split into Exynos7420 specific and common Exynos specific portions so that this implementation is reusable on other Exynos SoCs as well. The Exynos pinctrl driver supports only device tree based pin configuration. The bindings used are similar to the ones used in the linux kernel. Cc: Masahiro Yamada Cc: Simon Glass Cc: Minkyu Kang Signed-off-by: Thomas Abraham Reviewed-by: Simon Glass Acked-by: Minkyu Kang Signed-off-by: Minkyu Kang diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index 567b766..1785e3b 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -163,5 +163,6 @@ endif source "drivers/pinctrl/nxp/Kconfig" source "drivers/pinctrl/uniphier/Kconfig" +source "drivers/pinctrl/exynos/Kconfig" endmenu diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile index b99ed2f..7f94681 100644 --- a/drivers/pinctrl/Makefile +++ b/drivers/pinctrl/Makefile @@ -12,3 +12,4 @@ obj-$(CONFIG_PINCTRL_SANDBOX) += pinctrl-sandbox.o obj-$(CONFIG_PINCTRL_UNIPHIER) += uniphier/ obj-$(CONFIG_PIC32_PINCTRL) += pinctrl_pic32.o +obj-$(CONFIG_PINCTRL_EXYNOS) += exynos/ diff --git a/drivers/pinctrl/exynos/Kconfig b/drivers/pinctrl/exynos/Kconfig new file mode 100644 index 0000000..84b6aaa --- /dev/null +++ b/drivers/pinctrl/exynos/Kconfig @@ -0,0 +1,10 @@ +config PINCTRL_EXYNOS + bool + +config PINCTRL_EXYNOS7420 + bool "Samsung Exynos7420 pinctrl driver" + depends on ARCH_EXYNOS && PINCTRL_FULL + select PINCTRL_EXYNOS + help + Support pin multiplexing and pin configuration control on + Samsung's Exynos7420 SoC. diff --git a/drivers/pinctrl/exynos/Makefile b/drivers/pinctrl/exynos/Makefile new file mode 100644 index 0000000..d9b941a --- /dev/null +++ b/drivers/pinctrl/exynos/Makefile @@ -0,0 +1,9 @@ +# +# Copyright (C) 2016 Samsung Electronics +# Thomas Abraham +# +# SPDX-License-Identifier: GPL-2.0+ +# + +obj-$(CONFIG_PINCTRL_EXYNOS) += pinctrl-exynos.o +obj-$(CONFIG_PINCTRL_EXYNOS7420) += pinctrl-exynos7420.o diff --git a/drivers/pinctrl/exynos/pinctrl-exynos.c b/drivers/pinctrl/exynos/pinctrl-exynos.c new file mode 100644 index 0000000..a28405f --- /dev/null +++ b/drivers/pinctrl/exynos/pinctrl-exynos.c @@ -0,0 +1,141 @@ +/* + * Exynos pinctrl driver common code. + * Copyright (C) 2016 Samsung Electronics + * Thomas Abraham + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include "pinctrl-exynos.h" + +DECLARE_GLOBAL_DATA_PTR; + +/** + * exynos_pinctrl_setup_peri: setup pinctrl for a peripheral. + * conf: soc specific pin configuration data array + * num_conf: number of configurations in the conf array. + * base: base address of the pin controller. + */ +void exynos_pinctrl_setup_peri(struct exynos_pinctrl_config_data *conf, + unsigned int num_conf, unsigned long base) +{ + unsigned int idx, val; + + for (idx = 0; idx < num_conf; idx++) { + val = readl(base + conf[idx].offset); + val &= ~(conf[idx].mask); + val |= conf[idx].value; + writel(val, base + conf[idx].offset); + } +} + +/* given a pin-name, return the address of pin config registers */ +static unsigned long pin_to_bank_base(struct udevice *dev, const char *pin_name, + u32 *pin) +{ + struct exynos_pinctrl_priv *priv = dev_get_priv(dev); + const struct samsung_pin_ctrl *pin_ctrl = priv->pin_ctrl; + const struct samsung_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 -. + * Example: gpa0-4 (gpa0 is the bank name and 4 is the pin number. + */ + while (pin_name[idx] != '-') { + bank[idx] = pin_name[idx]; + idx++; + } + bank[idx] = '\0'; + *pin = pin_name[++idx] - '0'; + + /* 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; +} + +/** + * exynos_pinctrl_set_state: configure a pin state. + * dev: the pinctrl device to be configured. + * config: the state to be configured. + */ +int exynos_pinctrl_set_state(struct udevice *dev, struct udevice *config) +{ + const void *fdt = gd->fdt_blob; + int node = config->of_offset; + unsigned int count, idx, pin_num, ret; + unsigned int pinfunc, pinpud, pindrv; + unsigned long reg, value; + const char *name; + + /* + * refer to the following document for the pinctrl bindings + * linux/Documentation/devicetree/bindings/pinctrl/samsung-pinctrl.txt + */ + count = fdt_count_strings(fdt, node, "samsung,pins"); + if (count <= 0) + return -EINVAL; + + pinfunc = fdtdec_get_int(fdt, node, "samsung,pin-function", -1); + pinpud = fdtdec_get_int(fdt, node, "samsung,pin-pud", -1); + pindrv = fdtdec_get_int(fdt, node, "samsung,pin-drv", -1); + + for (idx = 0; idx < count; idx++) { + ret = fdt_get_string_index(fdt, node, "samsung,pins", + idx, &name); + if (ret < 0) + continue; + reg = pin_to_bank_base(dev, name, &pin_num); + + if (pinfunc != -1) { + value = readl(reg + PIN_CON); + value &= ~(0xf << (pin_num << 2)); + value |= (pinfunc << (pin_num << 2)); + writel(value, reg + PIN_CON); + } + + if (pinpud != -1) { + value = readl(reg + PIN_PUD); + value &= ~(0x3 << (pin_num << 1)); + value |= (pinpud << (pin_num << 1)); + writel(value, reg + PIN_PUD); + } + + if (pindrv != -1) { + value = readl(reg + PIN_DRV); + value &= ~(0x3 << (pin_num << 1)); + value |= (pindrv << (pin_num << 1)); + writel(value, reg + PIN_DRV); + } + } + + return 0; +} + +int exynos_pinctrl_probe(struct udevice *dev) +{ + struct exynos_pinctrl_priv *priv; + fdt_addr_t base; + + priv = dev_get_priv(dev); + if (!priv) + return -EINVAL; + + base = dev_get_addr(dev); + if (base == FDT_ADDR_T_NONE) + return -EINVAL; + + priv->base = base; + priv->pin_ctrl = (struct samsung_pin_ctrl *)dev_get_driver_data(dev) + + dev->req_seq; + + return 0; +} diff --git a/drivers/pinctrl/exynos/pinctrl-exynos.h b/drivers/pinctrl/exynos/pinctrl-exynos.h new file mode 100644 index 0000000..abd582d --- /dev/null +++ b/drivers/pinctrl/exynos/pinctrl-exynos.h @@ -0,0 +1,77 @@ +/* + * Exynos pinctrl driver header. + * Copyright (C) 2016 Samsung Electronics + * Thomas Abraham + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef __PINCTRL_EXYNOS_H_ +#define __PINCTRL_EXYNOS__H_ + +#define PIN_CON 0x00 /* Offset of pin function register */ +#define PIN_DAT 0x04 /* Offset of pin data register */ +#define PIN_PUD 0x08 /* Offset of pin pull up/down config register */ +#define PIN_DRV 0x0C /* Offset of pin drive strength register */ + +/** + * struct samsung_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 samsung_pin_bank_data { + u32 offset; + u8 nr_pins; + const char *name; +}; + +#define EXYNOS_PIN_BANK(pins, reg, id) \ + { \ + .offset = reg, \ + .nr_pins = pins, \ + .name = id \ + } + +/** + * struct samsung_pin_ctrl: represent a pin controller. + * @pin_banks: list of pin banks included in this controller. + * @nr_banks: number of pin banks. + */ +struct samsung_pin_ctrl { + const struct samsung_pin_bank_data *pin_banks; + u32 nr_banks; +}; + +/** + * struct exynos_pinctrl_priv: exynos pin controller driver private data + * @pin_ctrl: pin controller bank information. + * @base: base address of the pin controller instance. + * @num_banks: number of pin banks included in the pin controller. + */ +struct exynos_pinctrl_priv { + const struct samsung_pin_ctrl *pin_ctrl; + unsigned long base; + int num_banks; +}; + +/** + * struct exynos_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 exynos_pinctrl_config_data { + const unsigned int offset; + const unsigned int mask; + const unsigned int value; +}; + + +void exynos_pinctrl_setup_peri(struct exynos_pinctrl_config_data *conf, + unsigned int num_conf, unsigned long base); +int exynos_pinctrl_set_state(struct udevice *dev, + struct udevice *config); +int exynos_pinctrl_probe(struct udevice *dev); + +#endif /* __PINCTRL_EXYNOS_H_ */ diff --git a/drivers/pinctrl/exynos/pinctrl-exynos7420.c b/drivers/pinctrl/exynos/pinctrl-exynos7420.c new file mode 100644 index 0000000..8ae5ce7 --- /dev/null +++ b/drivers/pinctrl/exynos/pinctrl-exynos7420.c @@ -0,0 +1,120 @@ +/* + * Exynos7420 pinctrl driver. + * Copyright (C) 2016 Samsung Electronics + * Thomas Abraham + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "pinctrl-exynos.h" + +DECLARE_GLOBAL_DATA_PTR; + +#define GPD1_OFFSET 0xc0 + +static struct exynos_pinctrl_config_data serial2_conf[] = { + { + .offset = GPD1_OFFSET + PIN_CON, + .mask = 0x00ff0000, + .value = 0x00220000, + }, { + .offset = GPD1_OFFSET + PIN_PUD, + .mask = 0x00000f00, + .value = 0x00000f00, + }, +}; + +static int exynos7420_pinctrl_request(struct udevice *dev, int peripheral, + int flags) +{ + struct exynos_pinctrl_priv *priv = dev_get_priv(dev); + unsigned long base = priv->base; + + switch (PERIPH_ID_UART2) { + case PERIPH_ID_UART2: + exynos_pinctrl_setup_peri(serial2_conf, + ARRAY_SIZE(serial2_conf), base); + break; + default: + return -ENODEV; + } + + return 0; +} + +static struct pinctrl_ops exynos7420_pinctrl_ops = { + .set_state = exynos_pinctrl_set_state, + .request = exynos7420_pinctrl_request, +}; + +/* pin banks of Exynos7420 pin-controller - BUS0 */ +static const struct samsung_pin_bank_data exynos7420_pin_banks0[] = { + EXYNOS_PIN_BANK(5, 0x000, "gpb0"), + EXYNOS_PIN_BANK(8, 0x020, "gpc0"), + EXYNOS_PIN_BANK(2, 0x040, "gpc1"), + EXYNOS_PIN_BANK(6, 0x060, "gpc2"), + EXYNOS_PIN_BANK(8, 0x080, "gpc3"), + EXYNOS_PIN_BANK(4, 0x0a0, "gpd0"), + EXYNOS_PIN_BANK(6, 0x0c0, "gpd1"), + EXYNOS_PIN_BANK(8, 0x0e0, "gpd2"), + EXYNOS_PIN_BANK(5, 0x100, "gpd4"), + EXYNOS_PIN_BANK(4, 0x120, "gpd5"), + EXYNOS_PIN_BANK(6, 0x140, "gpd6"), + EXYNOS_PIN_BANK(3, 0x160, "gpd7"), + EXYNOS_PIN_BANK(2, 0x180, "gpd8"), + EXYNOS_PIN_BANK(2, 0x1a0, "gpg0"), + EXYNOS_PIN_BANK(4, 0x1c0, "gpg3"), +}; + +/* pin banks of Exynos7420 pin-controller - FSYS0 */ +static const struct samsung_pin_bank_data exynos7420_pin_banks1[] = { + EXYNOS_PIN_BANK(7, 0x000, "gpr4"), +}; + +/* pin banks of Exynos7420 pin-controller - FSYS1 */ +static const struct samsung_pin_bank_data exynos7420_pin_banks2[] = { + EXYNOS_PIN_BANK(4, 0x000, "gpr0"), + EXYNOS_PIN_BANK(8, 0x020, "gpr1"), + EXYNOS_PIN_BANK(5, 0x040, "gpr2"), + EXYNOS_PIN_BANK(8, 0x060, "gpr3"), +}; + +const struct samsung_pin_ctrl exynos7420_pin_ctrl[] = { + { + /* pin-controller instance BUS0 data */ + .pin_banks = exynos7420_pin_banks0, + .nr_banks = ARRAY_SIZE(exynos7420_pin_banks0), + }, { + /* pin-controller instance FSYS0 data */ + .pin_banks = exynos7420_pin_banks1, + .nr_banks = ARRAY_SIZE(exynos7420_pin_banks1), + }, { + /* pin-controller instance FSYS1 data */ + .pin_banks = exynos7420_pin_banks2, + .nr_banks = ARRAY_SIZE(exynos7420_pin_banks2), + }, +}; + +static const struct udevice_id exynos7420_pinctrl_ids[] = { + { .compatible = "samsung,exynos7420-pinctrl", + .data = (ulong)exynos7420_pin_ctrl }, + { } +}; + +U_BOOT_DRIVER(pinctrl_exynos7420) = { + .name = "pinctrl_exynos7420", + .id = UCLASS_PINCTRL, + .of_match = exynos7420_pinctrl_ids, + .priv_auto_alloc_size = sizeof(struct exynos_pinctrl_priv), + .ops = &exynos7420_pinctrl_ops, + .probe = exynos_pinctrl_probe, + .flags = DM_FLAG_PRE_RELOC +}; -- cgit v0.10.2 From 166097e8775343898cab84f1f23b4aacb35783db Mon Sep 17 00:00:00 2001 From: Thomas Abraham Date: Sat, 23 Apr 2016 22:18:09 +0530 Subject: clk: exynos: add clock driver for Exynos7420 Soc Add a clock driver for Exynos7420 SoC. There are about 25 clock controller blocks in Exynos7420 out of which support for topc, top0 and peric1 blocks are added in this initial version of the driver. Cc: Minkyu Kang Cc: Simon Glass Signed-off-by: Thomas Abraham Reviewed-by: Simon Glass Signed-off-by: Minkyu Kang diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig index a98b74b..6eee8eb 100644 --- a/drivers/clk/Kconfig +++ b/drivers/clk/Kconfig @@ -21,5 +21,6 @@ config SPL_CLK used as U-Boot proper. source "drivers/clk/uniphier/Kconfig" +source "drivers/clk/exynos/Kconfig" endmenu diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index c51db15..81fe600 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -11,3 +11,4 @@ obj-$(CONFIG_ROCKCHIP_RK3288) += clk_rk3288.o obj-$(CONFIG_SANDBOX) += clk_sandbox.o obj-$(CONFIG_MACH_PIC32) += clk_pic32.o obj-$(CONFIG_CLK_UNIPHIER) += uniphier/ +obj-$(CONFIG_CLK_EXYNOS) += exynos/ diff --git a/drivers/clk/exynos/Kconfig b/drivers/clk/exynos/Kconfig new file mode 100644 index 0000000..eb0efa9 --- /dev/null +++ b/drivers/clk/exynos/Kconfig @@ -0,0 +1,18 @@ +config CLK_EXYNOS + bool + select CLK + help + This enables support for common clock driver API on Samsung + Exynos SoCs. + +menu "Clock drivers for Exynos SoCs" + depends on CLK_EXYNOS + +config CLK_EXYNOS7420 + bool "Clock driver for Samsung's Exynos7420 SoC" + default y + help + This enables common clock driver support for platforms based + on Samsung Exynos7420 SoC. + +endmenu diff --git a/drivers/clk/exynos/Makefile b/drivers/clk/exynos/Makefile new file mode 100644 index 0000000..1df10fe --- /dev/null +++ b/drivers/clk/exynos/Makefile @@ -0,0 +1,9 @@ +# +# Copyright (C) 2016 Samsung Electronics +# Thomas Abraham +# +# SPDX-License-Identifier: GPL-2.0+ +# + +obj-y += clk-pll.o +obj-$(CONFIG_CLK_EXYNOS7420) += clk-exynos7420.o diff --git a/drivers/clk/exynos/clk-exynos7420.c b/drivers/clk/exynos/clk-exynos7420.c new file mode 100644 index 0000000..bf5d0e6 --- /dev/null +++ b/drivers/clk/exynos/clk-exynos7420.c @@ -0,0 +1,236 @@ +/* + * Samsung Exynos7420 clock driver. + * Copyright (C) 2016 Samsung Electronics + * Thomas Abraham + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include +#include +#include "clk-pll.h" + +DECLARE_GLOBAL_DATA_PTR; + +#define DIVIDER(reg, shift, mask) \ + (((readl(reg) >> shift) & mask) + 1) + +/* CMU TOPC block device structure */ +struct exynos7420_clk_cmu_topc { + unsigned int rsvd1[68]; + unsigned int bus0_pll_con[2]; + unsigned int rsvd2[2]; + unsigned int bus1_pll_con[2]; + unsigned int rsvd3[54]; + unsigned int mux_sel[6]; + unsigned int rsvd4[250]; + unsigned int div[4]; +}; + +/* CMU TOP0 block device structure */ +struct exynos7420_clk_cmu_top0 { + unsigned int rsvd0[128]; + unsigned int mux_sel[7]; + unsigned int rsvd1[261]; + unsigned int div_peric[5]; +}; + +/** + * struct exynos7420_clk_topc_priv - private data for CMU topc clock driver. + * + * @topc: base address of the memory mapped CMU TOPC controller. + * @fin_freq: frequency of the Oscillator clock. + * @sclk_bus0_pll_a: frequency of sclk_bus0_pll_a clock. + * @sclk_bus1_pll_a: frequency of sclk_bus1_pll_a clock. + */ +struct exynos7420_clk_topc_priv { + struct exynos7420_clk_cmu_topc *topc; + unsigned long fin_freq; + unsigned long sclk_bus0_pll_a; + unsigned long sclk_bus1_pll_a; +}; + +/** + * struct exynos7420_clk_top0_priv - private data for CMU top0 clock driver. + * + * @top0: base address of the memory mapped CMU TOP0 controller. + * @mout_top0_bus0_pll_half: frequency of mout_top0_bus0_pll_half clock + * @sclk_uart2: frequency of sclk_uart2 clock. + */ +struct exynos7420_clk_top0_priv { + struct exynos7420_clk_cmu_top0 *top0; + unsigned long mout_top0_bus0_pll_half; + unsigned long sclk_uart2; +}; + +static ulong exynos7420_topc_get_periph_rate(struct udevice *dev, int periph) +{ + struct exynos7420_clk_topc_priv *priv = dev_get_priv(dev); + + switch (periph) { + case DOUT_SCLK_BUS0_PLL: + case SCLK_BUS0_PLL_A: + case SCLK_BUS0_PLL_B: + return priv->sclk_bus0_pll_a; + case DOUT_SCLK_BUS1_PLL: + case SCLK_BUS1_PLL_A: + case SCLK_BUS1_PLL_B: + return priv->sclk_bus1_pll_a; + default: + return 0; + } +} + +static struct clk_ops exynos7420_clk_topc_ops = { + .get_periph_rate = exynos7420_topc_get_periph_rate, +}; + +static int exynos7420_clk_topc_probe(struct udevice *dev) +{ + struct exynos7420_clk_topc_priv *priv = dev_get_priv(dev); + struct exynos7420_clk_cmu_topc *topc; + struct udevice *clk_dev; + unsigned long rate; + fdt_addr_t base; + int ret; + + base = dev_get_addr(dev); + if (base == FDT_ADDR_T_NONE) + return -EINVAL; + + topc = (struct exynos7420_clk_cmu_topc *)base; + priv->topc = topc; + + ret = clk_get_by_index(dev, 0, &clk_dev); + if (ret >= 0) + priv->fin_freq = clk_get_rate(clk_dev); + + rate = pll145x_get_rate(&topc->bus0_pll_con[0], priv->fin_freq); + if (readl(&topc->mux_sel[1]) & (1 << 16)) + rate >>= 1; + rate /= DIVIDER(&topc->div[3], 0, 0xf); + priv->sclk_bus0_pll_a = rate; + + rate = pll145x_get_rate(&topc->bus1_pll_con[0], priv->fin_freq) / + DIVIDER(&topc->div[3], 8, 0xf); + priv->sclk_bus1_pll_a = rate; + + return 0; +} + +static ulong exynos7420_top0_get_periph_rate(struct udevice *dev, int periph) +{ + struct exynos7420_clk_top0_priv *priv = dev_get_priv(dev); + struct exynos7420_clk_cmu_top0 *top0 = priv->top0; + + switch (periph) { + case CLK_SCLK_UART2: + return priv->mout_top0_bus0_pll_half / + DIVIDER(&top0->div_peric[3], 8, 0xf); + default: + return 0; + } +} + +static struct clk_ops exynos7420_clk_top0_ops = { + .get_periph_rate = exynos7420_top0_get_periph_rate, +}; + +static int exynos7420_clk_top0_probe(struct udevice *dev) +{ + struct exynos7420_clk_top0_priv *priv; + struct exynos7420_clk_cmu_top0 *top0; + struct udevice *clk_dev; + fdt_addr_t base; + int ret; + + priv = dev_get_priv(dev); + if (!priv) + return -EINVAL; + + base = dev_get_addr(dev); + if (base == FDT_ADDR_T_NONE) + return -EINVAL; + + top0 = (struct exynos7420_clk_cmu_top0 *)base; + priv->top0 = top0; + + ret = clk_get_by_index(dev, 1, &clk_dev); + if (ret >= 0) { + priv->mout_top0_bus0_pll_half = + clk_get_periph_rate(clk_dev, ret); + if (readl(&top0->mux_sel[1]) & (1 << 16)) + priv->mout_top0_bus0_pll_half >>= 1; + } + + return 0; +} + +static ulong exynos7420_peric1_get_periph_rate(struct udevice *dev, int periph) +{ + struct udevice *clk_dev; + unsigned int ret; + unsigned long freq = 0; + + switch (periph) { + case SCLK_UART2: + ret = clk_get_by_index(dev, 3, &clk_dev); + if (ret < 0) + return ret; + freq = clk_get_periph_rate(clk_dev, ret); + break; + } + + return freq; +} + +static struct clk_ops exynos7420_clk_peric1_ops = { + .get_periph_rate = exynos7420_peric1_get_periph_rate, +}; + +static const struct udevice_id exynos7420_clk_topc_compat[] = { + { .compatible = "samsung,exynos7-clock-topc" }, + { } +}; + +U_BOOT_DRIVER(exynos7420_clk_topc) = { + .name = "exynos7420-clock-topc", + .id = UCLASS_CLK, + .of_match = exynos7420_clk_topc_compat, + .probe = exynos7420_clk_topc_probe, + .priv_auto_alloc_size = sizeof(struct exynos7420_clk_topc_priv), + .ops = &exynos7420_clk_topc_ops, + .flags = DM_FLAG_PRE_RELOC, +}; + +static const struct udevice_id exynos7420_clk_top0_compat[] = { + { .compatible = "samsung,exynos7-clock-top0" }, + { } +}; + +U_BOOT_DRIVER(exynos7420_clk_top0) = { + .name = "exynos7420-clock-top0", + .id = UCLASS_CLK, + .of_match = exynos7420_clk_top0_compat, + .probe = exynos7420_clk_top0_probe, + .priv_auto_alloc_size = sizeof(struct exynos7420_clk_top0_priv), + .ops = &exynos7420_clk_top0_ops, + .flags = DM_FLAG_PRE_RELOC, +}; + +static const struct udevice_id exynos7420_clk_peric1_compat[] = { + { .compatible = "samsung,exynos7-clock-peric1" }, + { } +}; + +U_BOOT_DRIVER(exynos7420_clk_peric1) = { + .name = "exynos7420-clock-peric1", + .id = UCLASS_CLK, + .of_match = exynos7420_clk_peric1_compat, + .ops = &exynos7420_clk_peric1_ops, + .flags = DM_FLAG_PRE_RELOC, +}; diff --git a/drivers/clk/exynos/clk-pll.c b/drivers/clk/exynos/clk-pll.c new file mode 100644 index 0000000..27220c5 --- /dev/null +++ b/drivers/clk/exynos/clk-pll.c @@ -0,0 +1,33 @@ +/* + * Exynos PLL helper functions for clock drivers. + * Copyright (C) 2016 Samsung Electronics + * Thomas Abraham + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include + +#define PLL145X_MDIV_SHIFT 16 +#define PLL145X_MDIV_MASK 0x3ff +#define PLL145X_PDIV_SHIFT 8 +#define PLL145X_PDIV_MASK 0x3f +#define PLL145X_SDIV_SHIFT 0 +#define PLL145X_SDIV_MASK 0x7 + +unsigned long pll145x_get_rate(unsigned int *con1, unsigned long fin_freq) +{ + unsigned long pll_con1 = readl(con1); + unsigned long mdiv, sdiv, pdiv; + uint64_t fvco = fin_freq; + + mdiv = (pll_con1 >> PLL145X_MDIV_SHIFT) & PLL145X_MDIV_MASK; + pdiv = (pll_con1 >> PLL145X_PDIV_SHIFT) & PLL145X_PDIV_MASK; + sdiv = (pll_con1 >> PLL145X_SDIV_SHIFT) & PLL145X_SDIV_MASK; + + fvco *= mdiv; + do_div(fvco, (pdiv << sdiv)); + return (unsigned long)fvco; +} diff --git a/drivers/clk/exynos/clk-pll.h b/drivers/clk/exynos/clk-pll.h new file mode 100644 index 0000000..631d035 --- /dev/null +++ b/drivers/clk/exynos/clk-pll.h @@ -0,0 +1,9 @@ +/* + * Exynos PLL helper functions for clock drivers. + * Copyright (C) 2016 Samsung Electronics + * Thomas Abraham + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +unsigned long pll145x_get_rate(unsigned int *con1, unsigned long fin_freq); diff --git a/include/dt-bindings/clock/exynos7420-clk.h b/include/dt-bindings/clock/exynos7420-clk.h new file mode 100644 index 0000000..10c5586 --- /dev/null +++ b/include/dt-bindings/clock/exynos7420-clk.h @@ -0,0 +1,207 @@ +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd. + * Author: Naveen Krishna Ch + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. +*/ + +#ifndef _DT_BINDINGS_CLOCK_EXYNOS7_H +#define _DT_BINDINGS_CLOCK_EXYNOS7_H + +/* TOPC */ +#define DOUT_ACLK_PERIS 1 +#define DOUT_SCLK_BUS0_PLL 2 +#define DOUT_SCLK_BUS1_PLL 3 +#define DOUT_SCLK_CC_PLL 4 +#define DOUT_SCLK_MFC_PLL 5 +#define DOUT_ACLK_CCORE_133 6 +#define DOUT_ACLK_MSCL_532 7 +#define ACLK_MSCL_532 8 +#define DOUT_SCLK_AUD_PLL 9 +#define FOUT_AUD_PLL 10 +#define SCLK_AUD_PLL 11 +#define SCLK_MFC_PLL_B 12 +#define SCLK_MFC_PLL_A 13 +#define SCLK_BUS1_PLL_B 14 +#define SCLK_BUS1_PLL_A 15 +#define SCLK_BUS0_PLL_B 16 +#define SCLK_BUS0_PLL_A 17 +#define SCLK_CC_PLL_B 18 +#define SCLK_CC_PLL_A 19 +#define ACLK_CCORE_133 20 +#define ACLK_PERIS_66 21 +#define TOPC_NR_CLK 22 + +/* TOP0 */ +#define DOUT_ACLK_PERIC1 1 +#define DOUT_ACLK_PERIC0 2 +#define CLK_SCLK_UART0 3 +#define CLK_SCLK_UART1 4 +#define CLK_SCLK_UART2 5 +#define CLK_SCLK_UART3 6 +#define CLK_SCLK_SPI0 7 +#define CLK_SCLK_SPI1 8 +#define CLK_SCLK_SPI2 9 +#define CLK_SCLK_SPI3 10 +#define CLK_SCLK_SPI4 11 +#define CLK_SCLK_SPDIF 12 +#define CLK_SCLK_PCM1 13 +#define CLK_SCLK_I2S1 14 +#define CLK_ACLK_PERIC0_66 15 +#define CLK_ACLK_PERIC1_66 16 +#define TOP0_NR_CLK 17 + +/* TOP1 */ +#define DOUT_ACLK_FSYS1_200 1 +#define DOUT_ACLK_FSYS0_200 2 +#define DOUT_SCLK_MMC2 3 +#define DOUT_SCLK_MMC1 4 +#define DOUT_SCLK_MMC0 5 +#define CLK_SCLK_MMC2 6 +#define CLK_SCLK_MMC1 7 +#define CLK_SCLK_MMC0 8 +#define CLK_ACLK_FSYS0_200 9 +#define CLK_ACLK_FSYS1_200 10 +#define CLK_SCLK_PHY_FSYS1 11 +#define CLK_SCLK_PHY_FSYS1_26M 12 +#define MOUT_SCLK_UFSUNIPRO20 13 +#define DOUT_SCLK_UFSUNIPRO20 14 +#define CLK_SCLK_UFSUNIPRO20 15 +#define DOUT_SCLK_PHY_FSYS1 16 +#define DOUT_SCLK_PHY_FSYS1_26M 17 +#define TOP1_NR_CLK 18 + +/* CCORE */ +#define PCLK_RTC 1 +#define CCORE_NR_CLK 2 + +/* PERIC0 */ +#define PCLK_UART0 1 +#define SCLK_UART0 2 +#define PCLK_HSI2C0 3 +#define PCLK_HSI2C1 4 +#define PCLK_HSI2C4 5 +#define PCLK_HSI2C5 6 +#define PCLK_HSI2C9 7 +#define PCLK_HSI2C10 8 +#define PCLK_HSI2C11 9 +#define PCLK_PWM 10 +#define SCLK_PWM 11 +#define PCLK_ADCIF 12 +#define PERIC0_NR_CLK 13 + +/* PERIC1 */ +#define PCLK_UART1 1 +#define PCLK_UART2 2 +#define PCLK_UART3 3 +#define SCLK_UART1 4 +#define SCLK_UART2 5 +#define SCLK_UART3 6 +#define PCLK_HSI2C2 7 +#define PCLK_HSI2C3 8 +#define PCLK_HSI2C6 9 +#define PCLK_HSI2C7 10 +#define PCLK_HSI2C8 11 +#define PCLK_SPI0 12 +#define PCLK_SPI1 13 +#define PCLK_SPI2 14 +#define PCLK_SPI3 15 +#define PCLK_SPI4 16 +#define SCLK_SPI0 17 +#define SCLK_SPI1 18 +#define SCLK_SPI2 19 +#define SCLK_SPI3 20 +#define SCLK_SPI4 21 +#define PCLK_I2S1 22 +#define PCLK_PCM1 23 +#define PCLK_SPDIF 24 +#define SCLK_I2S1 25 +#define SCLK_PCM1 26 +#define SCLK_SPDIF 27 +#define PERIC1_NR_CLK 28 + +/* PERIS */ +#define PCLK_CHIPID 1 +#define SCLK_CHIPID 2 +#define PCLK_WDT 3 +#define PCLK_TMU 4 +#define SCLK_TMU 5 +#define PERIS_NR_CLK 6 + +/* FSYS0 */ +#define ACLK_MMC2 1 +#define ACLK_AXIUS_USBDRD30X_FSYS0X 2 +#define ACLK_USBDRD300 3 +#define SCLK_USBDRD300_SUSPENDCLK 4 +#define SCLK_USBDRD300_REFCLK 5 +#define PHYCLK_USBDRD300_UDRD30_PIPE_PCLK_USER 6 +#define PHYCLK_USBDRD300_UDRD30_PHYCLK_USER 7 +#define OSCCLK_PHY_CLKOUT_USB30_PHY 8 +#define ACLK_PDMA0 9 +#define ACLK_PDMA1 10 +#define FSYS0_NR_CLK 11 + +/* FSYS1 */ +#define ACLK_MMC1 1 +#define ACLK_MMC0 2 +#define PHYCLK_UFS20_TX0_SYMBOL 3 +#define PHYCLK_UFS20_RX0_SYMBOL 4 +#define PHYCLK_UFS20_RX1_SYMBOL 5 +#define ACLK_UFS20_LINK 6 +#define SCLK_UFSUNIPRO20_USER 7 +#define PHYCLK_UFS20_RX1_SYMBOL_USER 8 +#define PHYCLK_UFS20_RX0_SYMBOL_USER 9 +#define PHYCLK_UFS20_TX0_SYMBOL_USER 10 +#define OSCCLK_PHY_CLKOUT_EMBEDDED_COMBO_PHY 11 +#define SCLK_COMBO_PHY_EMBEDDED_26M 12 +#define DOUT_PCLK_FSYS1 13 +#define PCLK_GPIO_FSYS1 14 +#define MOUT_FSYS1_PHYCLK_SEL1 15 +#define FSYS1_NR_CLK 16 + +/* MSCL */ +#define USERMUX_ACLK_MSCL_532 1 +#define DOUT_PCLK_MSCL 2 +#define ACLK_MSCL_0 3 +#define ACLK_MSCL_1 4 +#define ACLK_JPEG 5 +#define ACLK_G2D 6 +#define ACLK_LH_ASYNC_SI_MSCL_0 7 +#define ACLK_LH_ASYNC_SI_MSCL_1 8 +#define ACLK_AXI2ACEL_BRIDGE 9 +#define ACLK_XIU_MSCLX_0 10 +#define ACLK_XIU_MSCLX_1 11 +#define ACLK_QE_MSCL_0 12 +#define ACLK_QE_MSCL_1 13 +#define ACLK_QE_JPEG 14 +#define ACLK_QE_G2D 15 +#define ACLK_PPMU_MSCL_0 16 +#define ACLK_PPMU_MSCL_1 17 +#define ACLK_MSCLNP_133 18 +#define ACLK_AHB2APB_MSCL0P 19 +#define ACLK_AHB2APB_MSCL1P 20 + +#define PCLK_MSCL_0 21 +#define PCLK_MSCL_1 22 +#define PCLK_JPEG 23 +#define PCLK_G2D 24 +#define PCLK_QE_MSCL_0 25 +#define PCLK_QE_MSCL_1 26 +#define PCLK_QE_JPEG 27 +#define PCLK_QE_G2D 28 +#define PCLK_PPMU_MSCL_0 29 +#define PCLK_PPMU_MSCL_1 30 +#define PCLK_AXI2ACEL_BRIDGE 31 +#define PCLK_PMU_MSCL 32 +#define MSCL_NR_CLK 33 + +/* AUD */ +#define SCLK_I2S 1 +#define SCLK_PCM 2 +#define PCLK_I2S 3 +#define PCLK_PCM 4 +#define ACLK_ADMA 5 +#define AUD_NR_CLK 6 +#endif /* _DT_BINDINGS_CLOCK_EXYNOS7_H */ -- cgit v0.10.2 From 5ab6c4df27c9188251ff43a536c90ede57ba48fe Mon Sep 17 00:00:00 2001 From: Thomas Abraham Date: Sat, 23 Apr 2016 22:18:10 +0530 Subject: serial: s5p: get the port id number from the alias of the device node The port id, if not specified in the device node, can be obtained from the alias of the device node listed in the aliases node. Cc: Minkyu Kang Signed-off-by: Thomas Abraham Reviewed-by: Simon Glass Signed-off-by: Minkyu Kang diff --git a/drivers/serial/serial_s5p.c b/drivers/serial/serial_s5p.c index feba467..8590dfd 100644 --- a/drivers/serial/serial_s5p.c +++ b/drivers/serial/serial_s5p.c @@ -174,8 +174,8 @@ static int s5p_serial_ofdata_to_platdata(struct udevice *dev) return -EINVAL; plat->reg = (struct s5p_uart *)addr; - plat->port_id = fdtdec_get_int(gd->fdt_blob, dev->of_offset, "id", -1); - + plat->port_id = fdtdec_get_int(gd->fdt_blob, dev->of_offset, + "id", dev->seq); return 0; } -- cgit v0.10.2 From cf75cdf96ef288410222737eca98cf28cdbafbe2 Mon Sep 17 00:00:00 2001 From: Thomas Abraham Date: Sat, 23 Apr 2016 22:18:11 +0530 Subject: serial: s5p: use clock api to get clock rate On Exynos platforms that support clock driver API, allow the driver to use clock api get the SCLK clock rate. Cc: Minkyu Kang Signed-off-by: Thomas Abraham Reviewed-by: Simon Glass Signed-off-by: Minkyu Kang diff --git a/drivers/serial/serial_s5p.c b/drivers/serial/serial_s5p.c index 8590dfd..cb55c5a 100644 --- a/drivers/serial/serial_s5p.c +++ b/drivers/serial/serial_s5p.c @@ -17,6 +17,7 @@ #include #include #include +#include DECLARE_GLOBAL_DATA_PTR; @@ -90,7 +91,19 @@ int s5p_serial_setbrg(struct udevice *dev, int baudrate) { struct s5p_serial_platdata *plat = dev->platdata; struct s5p_uart *const uart = plat->reg; - u32 uclk = get_uart_clk(plat->port_id); + u32 uclk; + +#ifdef CONFIG_CLK_EXYNOS + struct udevice *clk_dev; + u32 ret; + + ret = clk_get_by_index(dev, 1, &clk_dev); + if (ret < 0) + return ret; + uclk = clk_get_periph_rate(clk_dev, ret); +#else + uclk = get_uart_clk(plat->port_id); +#endif s5p_serial_baud(uart, uclk, baudrate); -- cgit v0.10.2 From 36aa893775b809ea3b508a225992311582f6379a Mon Sep 17 00:00:00 2001 From: Thomas Abraham Date: Sat, 23 Apr 2016 22:18:12 +0530 Subject: arm: exynos: realign the code to allow support for newer 64-bit platforms The existing Exynos 32-bit platform support needs to be realigned in order to support newer 64-bit Exynos platforms. The driver model will be utlized for drivers on the 64-bit Exynos platforms and so some of the older platform support code would not be required for the newer 64-bit Exynos platforms. Cc: Minkyu Kang Signed-off-by: Thomas Abraham Reviewed-by: Simon Glass Signed-off-by: Minkyu Kang diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 729b181..3eb6e5d 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -426,7 +426,6 @@ config TARGET_BCMNSP config ARCH_EXYNOS bool "Samsung EXYNOS" - select CPU_V7 select DM select DM_SPI_FLASH select DM_SERIAL diff --git a/arch/arm/mach-exynos/Kconfig b/arch/arm/mach-exynos/Kconfig index a6a7597..28a6a60 100644 --- a/arch/arm/mach-exynos/Kconfig +++ b/arch/arm/mach-exynos/Kconfig @@ -1,9 +1,32 @@ if ARCH_EXYNOS choice - prompt "EXYNOS board select" + prompt "EXYNOS architecture type select" optional +config ARCH_EXYNOS4 + bool "Exynos4 SoC family" + select CPU_V7 + help + Samsung Exynos4 SoC family are based on ARM Cortex-A9 CPU. There + are multiple SoCs in this family including Exynos4210, Exynos4412, + and Exynos4212. + +config ARCH_EXYNOS5 + bool "Exynos5 SoC family" + select CPU_V7 + help + Samsung Exynos5 SoC family are based on ARM Cortex-A15 CPU (and + Cortex-A7 CPU in big.LITTLE configuration). There are multiple SoCs + in this family including Exynos5250, Exynos5420 and Exynos5800. + +endchoice + +if ARCH_EXYNOS4 + +choice + prompt "EXYNOS4 board select" + config TARGET_SMDKV310 select SUPPORT_SPL bool "Exynos4210 SMDKV310 board" @@ -25,6 +48,14 @@ config TARGET_TRATS2 config TARGET_ODROID bool "Exynos4412 Odroid board" +endchoice +endif + +if ARCH_EXYNOS5 + +choice + prompt "EXYNOS5 board select" + config TARGET_ODROID_XU3 bool "Exynos5422 Odroid board" select OF_CONTROL @@ -68,6 +99,7 @@ config TARGET_PEACH_PIT select OF_CONTROL endchoice +endif config SYS_SOC default "exynos" diff --git a/arch/arm/mach-exynos/Makefile b/arch/arm/mach-exynos/Makefile index 8542f89..f3c07b7 100644 --- a/arch/arm/mach-exynos/Makefile +++ b/arch/arm/mach-exynos/Makefile @@ -5,7 +5,8 @@ # SPDX-License-Identifier: GPL-2.0+ # -obj-y += clock.o power.o soc.o system.o pinmux.o tzpc.o +obj-y += soc.o +obj-$(CONFIG_CPU_V7) += clock.o pinmux.o power.o system.o obj-$(CONFIG_EXYNOS5420) += sec_boot.o @@ -13,6 +14,6 @@ ifdef CONFIG_SPL_BUILD obj-$(CONFIG_EXYNOS5) += clock_init_exynos5.o obj-$(CONFIG_EXYNOS5) += dmc_common.o dmc_init_ddr3.o obj-$(CONFIG_EXYNOS4210)+= dmc_init_exynos4.o clock_init_exynos4.o -obj-y += spl_boot.o +obj-y += spl_boot.o tzpc.o obj-y += lowlevel_init.o endif diff --git a/arch/arm/mach-exynos/include/mach/cpu.h b/arch/arm/mach-exynos/include/mach/cpu.h index 14a1692..f12e3d6 100644 --- a/arch/arm/mach-exynos/include/mach/cpu.h +++ b/arch/arm/mach-exynos/include/mach/cpu.h @@ -270,7 +270,7 @@ IS_EXYNOS_TYPE(exynos5420, 0x5420) IS_EXYNOS_TYPE(exynos5422, 0x5422) #define SAMSUNG_BASE(device, base) \ -static inline unsigned int __attribute__((no_instrument_function)) \ +static inline unsigned long __attribute__((no_instrument_function)) \ samsung_get_base_##device(void) \ { \ if (cpu_is_exynos4()) { \ diff --git a/arch/arm/mach-exynos/include/mach/gpio.h b/arch/arm/mach-exynos/include/mach/gpio.h index 7fc8e61..81363bd 100644 --- a/arch/arm/mach-exynos/include/mach/gpio.h +++ b/arch/arm/mach-exynos/include/mach/gpio.h @@ -1349,7 +1349,7 @@ enum exynos5420_gpio_pin { }; struct gpio_info { - unsigned int reg_addr; /* Address of register for this part */ + unsigned long reg_addr; /* Address of register for this part */ unsigned int max_gpio; /* Maximum GPIO in this part */ }; diff --git a/arch/arm/mach-exynos/soc.c b/arch/arm/mach-exynos/soc.c index 0f116b1..737a8dd 100644 --- a/arch/arm/mach-exynos/soc.c +++ b/arch/arm/mach-exynos/soc.c @@ -11,7 +11,9 @@ void reset_cpu(ulong addr) { +#ifdef CONFIG_CPU_V7 writel(0x1, samsung_get_base_swreset()); +#endif } #ifndef CONFIG_SYS_DCACHE_OFF diff --git a/configs/arndale_defconfig b/configs/arndale_defconfig index 0cd529e..a026fd6 100644 --- a/configs/arndale_defconfig +++ b/configs/arndale_defconfig @@ -1,5 +1,6 @@ CONFIG_ARM=y CONFIG_ARCH_EXYNOS=y +CONFIG_ARCH_EXYNOS5=y CONFIG_TARGET_ARNDALE=y CONFIG_DM_I2C=y CONFIG_DEFAULT_DEVICE_TREE="exynos5250-arndale" diff --git a/configs/odroid-xu3_defconfig b/configs/odroid-xu3_defconfig index 8995cc2..c7708f1 100644 --- a/configs/odroid-xu3_defconfig +++ b/configs/odroid-xu3_defconfig @@ -1,5 +1,6 @@ CONFIG_ARM=y CONFIG_ARCH_EXYNOS=y +CONFIG_ARCH_EXYNOS5=y CONFIG_TARGET_ODROID_XU3=y CONFIG_DM_I2C=y CONFIG_DEFAULT_DEVICE_TREE="exynos5422-odroidxu3" diff --git a/configs/odroid_defconfig b/configs/odroid_defconfig index ff3b339..76ab144 100644 --- a/configs/odroid_defconfig +++ b/configs/odroid_defconfig @@ -1,5 +1,6 @@ CONFIG_ARM=y CONFIG_ARCH_EXYNOS=y +CONFIG_ARCH_EXYNOS4=y CONFIG_TARGET_ODROID=y CONFIG_DM_I2C=y CONFIG_DEFAULT_DEVICE_TREE="exynos4412-odroid" diff --git a/configs/origen_defconfig b/configs/origen_defconfig index b1740dc..6ad01af 100644 --- a/configs/origen_defconfig +++ b/configs/origen_defconfig @@ -1,5 +1,6 @@ CONFIG_ARM=y CONFIG_ARCH_EXYNOS=y +CONFIG_ARCH_EXYNOS4=y CONFIG_TARGET_ORIGEN=y CONFIG_DEFAULT_DEVICE_TREE="exynos4210-origen" CONFIG_SPL=y diff --git a/configs/peach-pi_defconfig b/configs/peach-pi_defconfig index c8c74c0..ce07052 100644 --- a/configs/peach-pi_defconfig +++ b/configs/peach-pi_defconfig @@ -1,5 +1,6 @@ CONFIG_ARM=y CONFIG_ARCH_EXYNOS=y +CONFIG_ARCH_EXYNOS5=y CONFIG_TARGET_PEACH_PI=y CONFIG_DM_I2C=y CONFIG_DEFAULT_DEVICE_TREE="exynos5800-peach-pi" diff --git a/configs/peach-pit_defconfig b/configs/peach-pit_defconfig index c5fbf8c..4479fe8 100644 --- a/configs/peach-pit_defconfig +++ b/configs/peach-pit_defconfig @@ -1,5 +1,6 @@ CONFIG_ARM=y CONFIG_ARCH_EXYNOS=y +CONFIG_ARCH_EXYNOS5=y CONFIG_TARGET_PEACH_PIT=y CONFIG_DM_I2C=y CONFIG_DEFAULT_DEVICE_TREE="exynos5420-peach-pit" diff --git a/configs/s5pc210_universal_defconfig b/configs/s5pc210_universal_defconfig index 638b728..5eb7a40 100644 --- a/configs/s5pc210_universal_defconfig +++ b/configs/s5pc210_universal_defconfig @@ -1,5 +1,6 @@ CONFIG_ARM=y CONFIG_ARCH_EXYNOS=y +CONFIG_ARCH_EXYNOS4=y CONFIG_TARGET_S5PC210_UNIVERSAL=y CONFIG_DEFAULT_DEVICE_TREE="exynos4210-universal_c210" CONFIG_HUSH_PARSER=y diff --git a/configs/smdk5250_defconfig b/configs/smdk5250_defconfig index 5d88391..7fe410d 100644 --- a/configs/smdk5250_defconfig +++ b/configs/smdk5250_defconfig @@ -1,5 +1,6 @@ CONFIG_ARM=y CONFIG_ARCH_EXYNOS=y +CONFIG_ARCH_EXYNOS5=y CONFIG_TARGET_SMDK5250=y CONFIG_DM_I2C=y CONFIG_DEFAULT_DEVICE_TREE="exynos5250-smdk5250" diff --git a/configs/smdk5420_defconfig b/configs/smdk5420_defconfig index 40de7c1..23b9c1e 100644 --- a/configs/smdk5420_defconfig +++ b/configs/smdk5420_defconfig @@ -1,5 +1,6 @@ CONFIG_ARM=y CONFIG_ARCH_EXYNOS=y +CONFIG_ARCH_EXYNOS5=y CONFIG_TARGET_SMDK5420=y CONFIG_DM_I2C=y CONFIG_DEFAULT_DEVICE_TREE="exynos5420-smdk5420" diff --git a/configs/smdkv310_defconfig b/configs/smdkv310_defconfig index b8638e2..5ba6523 100644 --- a/configs/smdkv310_defconfig +++ b/configs/smdkv310_defconfig @@ -1,5 +1,6 @@ CONFIG_ARM=y CONFIG_ARCH_EXYNOS=y +CONFIG_ARCH_EXYNOS4=y CONFIG_TARGET_SMDKV310=y CONFIG_DEFAULT_DEVICE_TREE="exynos4210-smdkv310" CONFIG_SPL=y diff --git a/configs/snow_defconfig b/configs/snow_defconfig index 97133df..77b97a3 100644 --- a/configs/snow_defconfig +++ b/configs/snow_defconfig @@ -1,5 +1,6 @@ CONFIG_ARM=y CONFIG_ARCH_EXYNOS=y +CONFIG_ARCH_EXYNOS5=y CONFIG_TARGET_SNOW=y CONFIG_DM_I2C=y CONFIG_DEFAULT_DEVICE_TREE="exynos5250-snow" diff --git a/configs/spring_defconfig b/configs/spring_defconfig index b720e04..d3b174a 100644 --- a/configs/spring_defconfig +++ b/configs/spring_defconfig @@ -1,5 +1,6 @@ CONFIG_ARM=y CONFIG_ARCH_EXYNOS=y +CONFIG_ARCH_EXYNOS5=y CONFIG_TARGET_SPRING=y CONFIG_DM_I2C=y CONFIG_DEFAULT_DEVICE_TREE="exynos5250-spring" diff --git a/configs/trats2_defconfig b/configs/trats2_defconfig index c2ed8c8..1362ffb 100644 --- a/configs/trats2_defconfig +++ b/configs/trats2_defconfig @@ -1,5 +1,6 @@ CONFIG_ARM=y CONFIG_ARCH_EXYNOS=y +CONFIG_ARCH_EXYNOS4=y CONFIG_TARGET_TRATS2=y CONFIG_DEFAULT_DEVICE_TREE="exynos4412-trats2" # CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set diff --git a/configs/trats_defconfig b/configs/trats_defconfig index 46bfc4e..525bbef 100644 --- a/configs/trats_defconfig +++ b/configs/trats_defconfig @@ -1,5 +1,6 @@ CONFIG_ARM=y CONFIG_ARCH_EXYNOS=y +CONFIG_ARCH_EXYNOS4=y CONFIG_TARGET_TRATS=y CONFIG_DEFAULT_DEVICE_TREE="exynos4210-trats" CONFIG_FIT=y -- cgit v0.10.2 From e39448e8be8389f5ddeabae0ec9c6a3b7b8a2ca6 Mon Sep 17 00:00:00 2001 From: Thomas Abraham Date: Sat, 23 Apr 2016 22:18:13 +0530 Subject: arm: exynos: add support for Exynos7420 SoC Add support for Exynos7420 SoC. The Exynos7420 SoC has four Cortex-A57 and four Cortex-A53 CPUs and includes various peripheral controllers. Signed-off-by: Thomas Abraham Reviewed-by: Simon Glass Signed-off-by: Minkyu Kang diff --git a/arch/arm/dts/exynos7420.dtsi b/arch/arm/dts/exynos7420.dtsi new file mode 100644 index 0000000..b398021 --- /dev/null +++ b/arch/arm/dts/exynos7420.dtsi @@ -0,0 +1,83 @@ +/* + * Samsung Exynos7420 SoC device tree source + * + * Copyright (c) 2016 Samsung Electronics Co., Ltd. + * http://www.samsung.com + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +/dts-v1/; +#include "skeleton.dtsi" +#include +/ { + compatible = "samsung,exynos7420"; + + fin_pll: xxti { + compatible = "fixed-clock"; + clock-output-names = "fin_pll"; + u-boot,dm-pre-reloc; + #clock-cells = <0>; + }; + + clock_topc: clock-controller@10570000 { + compatible = "samsung,exynos7-clock-topc"; + reg = <0x10570000 0x10000>; + u-boot,dm-pre-reloc; + #clock-cells = <1>; + clocks = <&fin_pll>; + clock-names = "fin_pll"; + }; + + clock_top0: clock-controller@105d0000 { + compatible = "samsung,exynos7-clock-top0"; + reg = <0x105d0000 0xb000>; + u-boot,dm-pre-reloc; + #clock-cells = <1>; + clocks = <&fin_pll>, <&clock_topc DOUT_SCLK_BUS0_PLL>, + <&clock_topc DOUT_SCLK_BUS1_PLL>, + <&clock_topc DOUT_SCLK_CC_PLL>, + <&clock_topc DOUT_SCLK_MFC_PLL>; + clock-names = "fin_pll", "dout_sclk_bus0_pll", + "dout_sclk_bus1_pll", "dout_sclk_cc_pll", + "dout_sclk_mfc_pll"; + }; + + clock_peric1: clock-controller@14c80000 { + compatible = "samsung,exynos7-clock-peric1"; + reg = <0x14c80000 0xd00>; + u-boot,dm-pre-reloc; + #clock-cells = <1>; + clocks = <&fin_pll>, <&clock_top0 DOUT_ACLK_PERIC1>, + <&clock_top0 CLK_SCLK_UART1>, + <&clock_top0 CLK_SCLK_UART2>, + <&clock_top0 CLK_SCLK_UART3>; + clock-names = "fin_pll", "dout_aclk_peric1_66", + "sclk_uart1", "sclk_uart2", "sclk_uart3"; + }; + + pinctrl@13470000 { + compatible = "samsung,exynos7420-pinctrl"; + reg = <0x13470000 0x1000>; + u-boot,dm-pre-reloc; + + serial2_bus: serial2-bus { + samsung,pins = "gpd1-4", "gpd1-5"; + samsung,pin-function = <2>; + samsung,pin-pud = <3>; + samsung,pin-drv = <0>; + u-boot,dm-pre-reloc; + }; + }; + + serial@14C30000 { + compatible = "samsung,exynos4210-uart"; + reg = <0x14C30000 0x100>; + u-boot,dm-pre-reloc; + clocks = <&clock_peric1 PCLK_UART2>, + <&clock_peric1 SCLK_UART2>; + clock-names = "uart", "clk_uart_baud0"; + pinctrl-names = "default"; + pinctrl-0 = <&serial2_bus>; + }; +}; diff --git a/arch/arm/mach-exynos/Kconfig b/arch/arm/mach-exynos/Kconfig index 28a6a60..0a6cb33 100644 --- a/arch/arm/mach-exynos/Kconfig +++ b/arch/arm/mach-exynos/Kconfig @@ -20,6 +20,14 @@ config ARCH_EXYNOS5 Cortex-A7 CPU in big.LITTLE configuration). There are multiple SoCs in this family including Exynos5250, Exynos5420 and Exynos5800. +config ARCH_EXYNOS7 + bool "Exynos7 SoC family" + select ARM64 + help + Samsung Exynos7 SoC family are based on ARM Cortex-A57 CPU or + Cortex-A53 CPU (and some in a big.LITTLE configuration). There are + multiple SoCs in this family including Exynos7420. + endchoice if ARCH_EXYNOS4 diff --git a/arch/arm/mach-exynos/Makefile b/arch/arm/mach-exynos/Makefile index f3c07b7..0cc6c32 100644 --- a/arch/arm/mach-exynos/Makefile +++ b/arch/arm/mach-exynos/Makefile @@ -7,6 +7,7 @@ obj-y += soc.o obj-$(CONFIG_CPU_V7) += clock.o pinmux.o power.o system.o +obj-$(CONFIG_ARM64) += mmu-arm64.o obj-$(CONFIG_EXYNOS5420) += sec_boot.o diff --git a/arch/arm/mach-exynos/mmu-arm64.c b/arch/arm/mach-exynos/mmu-arm64.c new file mode 100644 index 0000000..ba6d99d --- /dev/null +++ b/arch/arm/mach-exynos/mmu-arm64.c @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2016 Samsung Electronics + * Thomas Abraham + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include + +DECLARE_GLOBAL_DATA_PTR; + +#ifdef CONFIG_EXYNOS7420 +static struct mm_region exynos7420_mem_map[] = { + { + .base = 0x10000000UL, + .size = 0x10000000UL, + .attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) | + PTE_BLOCK_NON_SHARE | + PTE_BLOCK_PXN | PTE_BLOCK_UXN, + }, { + .base = 0x40000000UL, + .size = 0x80000000UL, + .attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) | + PTE_BLOCK_INNER_SHARE, + }, { + /* List terminator */ + .base = 0, + .size = 0, + .attrs = 0, + }, +}; + +struct mm_region *mem_map = exynos7420_mem_map; +#endif diff --git a/arch/arm/mach-exynos/soc.c b/arch/arm/mach-exynos/soc.c index 737a8dd..f9c7468 100644 --- a/arch/arm/mach-exynos/soc.c +++ b/arch/arm/mach-exynos/soc.c @@ -23,3 +23,11 @@ void enable_caches(void) dcache_enable(); } #endif + +#ifdef CONFIG_ARM64 +void lowlevel_init(void) +{ + armv8_switch_to_el2(); + armv8_switch_to_el1(); +} +#endif diff --git a/include/configs/espresso7420.h b/include/configs/espresso7420.h new file mode 100644 index 0000000..c6a756d --- /dev/null +++ b/include/configs/espresso7420.h @@ -0,0 +1,34 @@ +/* + * Configuration settings for the SAMSUNG ESPRESSO7420 board. + * Copyright (C) 2016 Samsung Electronics + * Thomas Abraham + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef __CONFIG_ESPRESSO7420_H +#define __CONFIG_ESPRESSO7420_H + +#include + +#define CONFIG_BOARD_COMMON + +#define CONFIG_ESPRESSO7420 +#define CONFIG_ENV_IS_NOWHERE + +#define CONFIG_SYS_SDRAM_BASE 0x40000000 +#define CONFIG_SYS_TEXT_BASE 0x43E00000 +#define CONFIG_SPL_STACK CONFIG_IRAM_END +#define CONFIG_SYS_INIT_SP_ADDR CONFIG_IRAM_END + +/* select serial console configuration */ +#define CONFIG_DEFAULT_CONSOLE "console=ttySAC1,115200n8\0" + +#define CONFIG_IDENT_STRING " for ESPRESSO7420" +#define CONFIG_DEFAULT_CONSOLE "console=ttySAC1,115200n8\0" + +/* DRAM Memory Banks */ +#define CONFIG_NR_DRAM_BANKS 8 +#define SDRAM_BANK_SIZE (256UL << 20UL) /* 256 MB */ + +#endif /* __CONFIG_ESPRESSO7420_H */ diff --git a/include/configs/exynos7420-common.h b/include/configs/exynos7420-common.h new file mode 100644 index 0000000..9e03962 --- /dev/null +++ b/include/configs/exynos7420-common.h @@ -0,0 +1,113 @@ +/* + * Configuration settings for the Espresso7420 board. + * Copyright (C) 2016 Samsung Electronics + * Thomas Abraham + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef __CONFIG_EXYNOS7420_COMMON_H +#define __CONFIG_EXYNOS7420_COMMON_H + +/* High Level Configuration Options */ +#define CONFIG_SAMSUNG /* in a SAMSUNG core */ +#define CONFIG_EXYNOS7420 /* Exynos7 Family */ +#define CONFIG_S5P + +#include /* get chip and board defs */ +#include + +#define CONFIG_ARCH_CPU_INIT +#define CONFIG_DISPLAY_BOARDINFO +#define CONFIG_BOARD_EARLY_INIT_F + +/* Size of malloc() pool before and after relocation */ +#define CONFIG_SYS_MALLOC_LEN (CONFIG_ENV_SIZE + (80 << 20)) + +/* Miscellaneous configurable options */ +#define CONFIG_SYS_CBSIZE 1024 /* Console I/O Buffer Size */ +#define CONFIG_SYS_PBSIZE 1024 /* Print Buffer Size */ +#define CONFIG_SYS_MAXARGS 16 /* max number of command args */ + +/* Boot Argument Buffer Size */ +#define CONFIG_SYS_BARGSIZE CONFIG_SYS_CBSIZE + +/* select serial console configuration */ +#define CONFIG_BAUDRATE 115200 + +/* FLASH and environment organization */ +#define CONFIG_SYS_NO_FLASH + +/* Timer input clock frequency */ +#define COUNTER_FREQUENCY 24000000 + +/* Device Tree */ +#define CONFIG_DEVICE_TREE_LIST "exynos7420-espresso7420" + +/* IRAM Layout */ +#define CONFIG_IRAM_BASE 0x02100000 +#define CONFIG_IRAM_SIZE 0x58000 +#define CONFIG_IRAM_END (CONFIG_IRAM_BASE + CONFIG_IRAM_SIZE) + +/* Number of CPUs available */ +#define CONFIG_CORE_COUNT 0x8 + +/* select serial console configuration */ +#define CONFIG_BAUDRATE 115200 +#define CONFIG_SILENT_CONSOLE +#define CONFIG_SYS_CONSOLE_IS_IN_ENV +#define CONFIG_CONSOLE_MUX + +#define CONFIG_SYS_LOAD_ADDR (CONFIG_SYS_SDRAM_BASE + 0x3E00000) + +#define PHYS_SDRAM_1 CONFIG_SYS_SDRAM_BASE +#define PHYS_SDRAM_1_SIZE SDRAM_BANK_SIZE +#define PHYS_SDRAM_2 (CONFIG_SYS_SDRAM_BASE + SDRAM_BANK_SIZE) +#define PHYS_SDRAM_2_SIZE SDRAM_BANK_SIZE +#define PHYS_SDRAM_3 (CONFIG_SYS_SDRAM_BASE + (2 * SDRAM_BANK_SIZE)) +#define PHYS_SDRAM_3_SIZE SDRAM_BANK_SIZE +#define PHYS_SDRAM_4 (CONFIG_SYS_SDRAM_BASE + (3 * SDRAM_BANK_SIZE)) +#define PHYS_SDRAM_4_SIZE SDRAM_BANK_SIZE +#define PHYS_SDRAM_5 (CONFIG_SYS_SDRAM_BASE + (4 * SDRAM_BANK_SIZE)) +#define PHYS_SDRAM_5_SIZE SDRAM_BANK_SIZE +#define PHYS_SDRAM_6 (CONFIG_SYS_SDRAM_BASE + (5 * SDRAM_BANK_SIZE)) +#define PHYS_SDRAM_6_SIZE SDRAM_BANK_SIZE +#define PHYS_SDRAM_7 (CONFIG_SYS_SDRAM_BASE + (6 * SDRAM_BANK_SIZE)) +#define PHYS_SDRAM_7_SIZE SDRAM_BANK_SIZE +#define PHYS_SDRAM_8 (CONFIG_SYS_SDRAM_BASE + (7 * SDRAM_BANK_SIZE)) +#define PHYS_SDRAM_8_SIZE SDRAM_BANK_SIZE + +/* Configuration of ENV Blocks */ +#define CONFIG_ENV_SIZE (16 << 10) /* 16 KB */ + +#define BOOT_TARGET_DEVICES(func) \ + func(MMC, mmc, 1) \ + func(MMC, mmc, 0) \ + +#ifndef MEM_LAYOUT_ENV_SETTINGS +#define MEM_LAYOUT_ENV_SETTINGS \ + "bootm_size=0x10000000\0" \ + "kernel_addr_r=0x42000000\0" \ + "fdt_addr_r=0x43000000\0" \ + "ramdisk_addr_r=0x43300000\0" \ + "scriptaddr=0x50000000\0" \ + "pxefile_addr_r=0x51000000\0" +#endif + +#ifndef EXYNOS_DEVICE_SETTINGS +#define EXYNOS_DEVICE_SETTINGS \ + "stdin=serial\0" \ + "stdout=serial\0" \ + "stderr=serial\0" +#endif + +#ifndef EXYNOS_FDTFILE_SETTING +#define EXYNOS_FDTFILE_SETTING +#endif + +#define CONFIG_EXTRA_ENV_SETTINGS \ + EXYNOS_DEVICE_SETTINGS \ + EXYNOS_FDTFILE_SETTING \ + MEM_LAYOUT_ENV_SETTINGS + +#endif /* __CONFIG_EXYNOS7420_COMMON_H */ -- cgit v0.10.2 From 6c15a2a996214574e8145bff69d110a302edf277 Mon Sep 17 00:00:00 2001 From: Thomas Abraham Date: Sat, 23 Apr 2016 22:18:14 +0530 Subject: board: samsung: add initial Espresso7420 board support Espresso7420 is a development/evaluation board for Exynos7420 SoC. It includes multiple onboard compoments (EMMC/Codec) and various interconnects (USB/HDMI). Signed-off-by: Thomas Abraham Reviewed-by: Simon Glass Signed-off-by: Minkyu Kang diff --git a/arch/arm/dts/Makefile b/arch/arm/dts/Makefile index d1f8e22..da25715 100644 --- a/arch/arm/dts/Makefile +++ b/arch/arm/dts/Makefile @@ -21,6 +21,7 @@ dtb-$(CONFIG_EXYNOS5) += exynos5250-arndale.dtb \ exynos5420-peach-pit.dtb \ exynos5800-peach-pi.dtb \ exynos5422-odroidxu3.dtb +dtb-$(CONFIG_EXYNOS7420) += exynos7420-espresso7420.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += \ rk3288-firefly.dtb \ rk3288-jerry.dtb \ diff --git a/arch/arm/dts/exynos7420-espresso7420.dts b/arch/arm/dts/exynos7420-espresso7420.dts new file mode 100644 index 0000000..f17a848 --- /dev/null +++ b/arch/arm/dts/exynos7420-espresso7420.dts @@ -0,0 +1,24 @@ +/* + * Samsung Espresso7420 board device tree source + * + * Copyright (c) 2016 Samsung Electronics Co., Ltd. + * http://www.samsung.com + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include "exynos7420.dtsi" +/ { + model = "Samsung Espresso7420 board based on Exynos7420"; + compatible = "samsung,espresso7420", "samsung,exynos7420"; + + aliases { + serial2 = "/serial@14C30000"; + console = "/serial@14C30000"; + pinctrl0 = "/pinctrl@13470000"; + }; +}; + +&fin_pll { + clock-frequency = <24000000>; +}; diff --git a/arch/arm/mach-exynos/Kconfig b/arch/arm/mach-exynos/Kconfig index 0a6cb33..c25fcf3 100644 --- a/arch/arm/mach-exynos/Kconfig +++ b/arch/arm/mach-exynos/Kconfig @@ -109,6 +109,24 @@ config TARGET_PEACH_PIT endchoice endif +if ARCH_EXYNOS7 + +choice + prompt "EXYNOS7 board select" + +config TARGET_ESPRESSO7420 + bool "ESPRESSO7420 board" + select ARM64 + select SUPPORT_SPL + select OF_CONTROL + select SPL_DISABLE_OF_CONTROL + select PINCTRL + select PINCTRL_EXYNOS7420 + select CLK_EXYNOS + +endchoice +endif + config SYS_SOC default "exynos" @@ -121,5 +139,6 @@ source "board/samsung/odroid/Kconfig" source "board/samsung/arndale/Kconfig" source "board/samsung/smdk5250/Kconfig" source "board/samsung/smdk5420/Kconfig" +source "board/samsung/espresso7420/Kconfig" endif diff --git a/board/samsung/common/board.c b/board/samsung/common/board.c index 1334c22..7995174 100644 --- a/board/samsung/common/board.c +++ b/board/samsung/common/board.c @@ -27,6 +27,8 @@ #include #include #include +#include +#include DECLARE_GLOBAL_DATA_PTR; @@ -97,7 +99,7 @@ int board_init(void) int dram_init(void) { unsigned int i; - u32 addr; + unsigned long addr; for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) { addr = CONFIG_SYS_SDRAM_BASE + (i * SDRAM_BANK_SIZE); @@ -109,7 +111,7 @@ int dram_init(void) void dram_init_banksize(void) { unsigned int i; - u32 addr, size; + unsigned long addr, size; for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) { addr = CONFIG_SYS_SDRAM_BASE + (i * SDRAM_BANK_SIZE); @@ -122,6 +124,7 @@ void dram_init_banksize(void) static int board_uart_init(void) { +#ifndef CONFIG_PINCTRL_EXYNOS int err, uart_id, ret = 0; for (uart_id = PERIPH_ID_UART0; uart_id <= PERIPH_ID_UART3; uart_id++) { @@ -133,6 +136,9 @@ static int board_uart_init(void) } } return ret; +#else + return 0; +#endif } #ifdef CONFIG_BOARD_EARLY_INIT_F diff --git a/board/samsung/espresso7420/Kconfig b/board/samsung/espresso7420/Kconfig new file mode 100644 index 0000000..62251c5 --- /dev/null +++ b/board/samsung/espresso7420/Kconfig @@ -0,0 +1,16 @@ +if TARGET_ESPRESSO7420 + +config SYS_BOARD + default "espresso7420" + help + Espresso7420 is a development/evaluation board for Exynos7420 SoC. + It includes multiple onboard compoments (EMMC/Codec) and various + interconnects (USB/HDMI). + +config SYS_VENDOR + default "samsung" + +config SYS_CONFIG_NAME + default "espresso7420" + +endif diff --git a/board/samsung/espresso7420/MAINTAINERS b/board/samsung/espresso7420/MAINTAINERS new file mode 100644 index 0000000..aaebc4c --- /dev/null +++ b/board/samsung/espresso7420/MAINTAINERS @@ -0,0 +1,5 @@ +ESPRESSO7420 Board +M: Thomas Abraham +S: Maintained +F: board/samsung/espresso7420/ +F: include/configs/espresso7420.h diff --git a/board/samsung/espresso7420/Makefile b/board/samsung/espresso7420/Makefile new file mode 100644 index 0000000..d514dc2 --- /dev/null +++ b/board/samsung/espresso7420/Makefile @@ -0,0 +1,10 @@ +# +# Copyright (C) 2016 Samsung Electronics +# Thomas Abraham +# +# SPDX-License-Identifier: GPL-2.0+ +# + +ifndef CONFIG_SPL_BUILD +obj-y += espresso7420.o +endif diff --git a/board/samsung/espresso7420/espresso7420.c b/board/samsung/espresso7420/espresso7420.c new file mode 100644 index 0000000..04a83bc --- /dev/null +++ b/board/samsung/espresso7420/espresso7420.c @@ -0,0 +1,16 @@ +/* + * Espresso7420 board file + * Copyright (C) 2016 Samsung Electronics + * Thomas Abraham + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include + +DECLARE_GLOBAL_DATA_PTR; + +int exynos_init(void) +{ + return 0; +} diff --git a/configs/espresso7420_defconfig b/configs/espresso7420_defconfig new file mode 100644 index 0000000..0fe2759 --- /dev/null +++ b/configs/espresso7420_defconfig @@ -0,0 +1,9 @@ +CONFIG_ARM=y +CONFIG_ARCH_EXYNOS=y +CONFIG_ARCH_EXYNOS7=y +CONFIG_TARGET_ESPRESSO7420=y +CONFIG_DEFAULT_DEVICE_TREE="exynos7420-espresso7420" +CONFIG_SYS_MALLOC_F_LEN=0x2000 +CONFIG_SYS_PROMPT="ESPRESSO7420 # " +# CONFIG_CMD_IMLS is not set +# CONFIG_CMD_SETEXPR is not set -- cgit v0.10.2 From 08a7aa1e5be7059d680fedf0a885655a895f638e Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 21 Feb 2016 21:08:38 -0700 Subject: exynos: video: Move driver files into their own directory Move all the exynos video drivers into one place for ease of maintenance. Signed-off-by: Simon Glass Acked-by: Anatolij Gustschin Signed-off-by: Minkyu Kang diff --git a/drivers/video/Makefile b/drivers/video/Makefile index 2fd0891..3f045fe 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile @@ -25,11 +25,6 @@ obj-$(CONFIG_ATI_RADEON_FB) += ati_radeon_fb.o videomodes.o obj-$(CONFIG_ATMEL_HLCD) += atmel_hlcdfb.o obj-$(CONFIG_ATMEL_LCD) += atmel_lcdfb.o obj-$(CONFIG_CFB_CONSOLE) += cfb_console.o -obj-$(CONFIG_EXYNOS_DP) += exynos_dp.o exynos_dp_lowlevel.o -obj-$(CONFIG_EXYNOS_FB) += exynos_fb.o exynos_fimd.o -obj-$(CONFIG_EXYNOS_MIPI_DSIM) += exynos_mipi_dsi.o exynos_mipi_dsi_common.o \ - exynos_mipi_dsi_lowlevel.o -obj-$(CONFIG_EXYNOS_PWM_BL) += exynos_pwm_bl.o obj-$(CONFIG_FSL_DIU_FB) += fsl_diu_fb.o videomodes.o obj-$(CONFIG_FSL_DCU_FB) += fsl_dcu_fb.o videomodes.o obj-$(CONFIG_L5F31188) += l5f31188.o @@ -68,6 +63,7 @@ obj-$(CONFIG_LG4573) += lg4573.o obj-$(CONFIG_AM335X_LCD) += am335x-fb.o obj-${CONFIG_VIDEO_TEGRA124} += tegra124/ +obj-${CONFIG_EXYNOS_FB} += exynos/ obj-${CONFIG_VIDEO_ROCKCHIP} += rockchip/ obj-y += bridge/ diff --git a/drivers/video/exynos/Makefile b/drivers/video/exynos/Makefile new file mode 100644 index 0000000..d4bdf32 --- /dev/null +++ b/drivers/video/exynos/Makefile @@ -0,0 +1,12 @@ +# +# (C) Copyright 2000-2007 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# SPDX-License-Identifier: GPL-2.0+ +# + +obj-$(CONFIG_EXYNOS_DP) += exynos_dp.o exynos_dp_lowlevel.o +obj-$(CONFIG_EXYNOS_FB) += exynos_fb.o exynos_fimd.o +obj-$(CONFIG_EXYNOS_MIPI_DSIM) += exynos_mipi_dsi.o exynos_mipi_dsi_common.o \ + exynos_mipi_dsi_lowlevel.o +obj-$(CONFIG_EXYNOS_PWM_BL) += exynos_pwm_bl.o diff --git a/drivers/video/exynos/exynos_dp.c b/drivers/video/exynos/exynos_dp.c new file mode 100644 index 0000000..0d5d090 --- /dev/null +++ b/drivers/video/exynos/exynos_dp.c @@ -0,0 +1,961 @@ +/* + * Copyright (C) 2012 Samsung Electronics + * + * Author: Donghwa Lee + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "exynos_dp_lowlevel.h" + +DECLARE_GLOBAL_DATA_PTR; + +void __exynos_set_dp_phy(unsigned int onoff) +{ +} +void exynos_set_dp_phy(unsigned int onoff) + __attribute__((weak, alias("__exynos_set_dp_phy"))); + +static void exynos_dp_disp_info(struct edp_disp_info *disp_info) +{ + disp_info->h_total = disp_info->h_res + disp_info->h_sync_width + + disp_info->h_back_porch + disp_info->h_front_porch; + disp_info->v_total = disp_info->v_res + disp_info->v_sync_width + + disp_info->v_back_porch + disp_info->v_front_porch; + + return; +} + +static int exynos_dp_init_dp(void) +{ + int ret; + exynos_dp_reset(); + + /* SW defined function Normal operation */ + exynos_dp_enable_sw_func(DP_ENABLE); + + ret = exynos_dp_init_analog_func(); + if (ret != EXYNOS_DP_SUCCESS) + return ret; + + exynos_dp_init_hpd(); + exynos_dp_init_aux(); + + return ret; +} + +static unsigned char exynos_dp_calc_edid_check_sum(unsigned char *edid_data) +{ + int i; + unsigned char sum = 0; + + for (i = 0; i < EDID_BLOCK_LENGTH; i++) + sum = sum + edid_data[i]; + + return sum; +} + +static unsigned int exynos_dp_read_edid(void) +{ + unsigned char edid[EDID_BLOCK_LENGTH * 2]; + unsigned int extend_block = 0; + unsigned char sum; + unsigned char test_vector; + int retval; + + /* + * EDID device address is 0x50. + * However, if necessary, you must have set upper address + * into E-EDID in I2C device, 0x30. + */ + + /* Read Extension Flag, Number of 128-byte EDID extension blocks */ + exynos_dp_read_byte_from_i2c(I2C_EDID_DEVICE_ADDR, EDID_EXTENSION_FLAG, + &extend_block); + + if (extend_block > 0) { + printf("DP EDID data includes a single extension!\n"); + + /* Read EDID data */ + retval = exynos_dp_read_bytes_from_i2c(I2C_EDID_DEVICE_ADDR, + EDID_HEADER_PATTERN, + EDID_BLOCK_LENGTH, + &edid[EDID_HEADER_PATTERN]); + if (retval != 0) { + printf("DP EDID Read failed!\n"); + return -1; + } + sum = exynos_dp_calc_edid_check_sum(edid); + if (sum != 0) { + printf("DP EDID bad checksum!\n"); + return -1; + } + + /* Read additional EDID data */ + retval = exynos_dp_read_bytes_from_i2c(I2C_EDID_DEVICE_ADDR, + EDID_BLOCK_LENGTH, + EDID_BLOCK_LENGTH, + &edid[EDID_BLOCK_LENGTH]); + if (retval != 0) { + printf("DP EDID Read failed!\n"); + return -1; + } + sum = exynos_dp_calc_edid_check_sum(&edid[EDID_BLOCK_LENGTH]); + if (sum != 0) { + printf("DP EDID bad checksum!\n"); + return -1; + } + + exynos_dp_read_byte_from_dpcd(DPCD_TEST_REQUEST, + &test_vector); + if (test_vector & DPCD_TEST_EDID_READ) { + exynos_dp_write_byte_to_dpcd(DPCD_TEST_EDID_CHECKSUM, + edid[EDID_BLOCK_LENGTH + EDID_CHECKSUM]); + exynos_dp_write_byte_to_dpcd(DPCD_TEST_RESPONSE, + DPCD_TEST_EDID_CHECKSUM_WRITE); + } + } else { + debug("DP EDID data does not include any extensions.\n"); + + /* Read EDID data */ + retval = exynos_dp_read_bytes_from_i2c(I2C_EDID_DEVICE_ADDR, + EDID_HEADER_PATTERN, + EDID_BLOCK_LENGTH, + &edid[EDID_HEADER_PATTERN]); + + if (retval != 0) { + printf("DP EDID Read failed!\n"); + return -1; + } + sum = exynos_dp_calc_edid_check_sum(edid); + if (sum != 0) { + printf("DP EDID bad checksum!\n"); + return -1; + } + + exynos_dp_read_byte_from_dpcd(DPCD_TEST_REQUEST, + &test_vector); + if (test_vector & DPCD_TEST_EDID_READ) { + exynos_dp_write_byte_to_dpcd(DPCD_TEST_EDID_CHECKSUM, + edid[EDID_CHECKSUM]); + exynos_dp_write_byte_to_dpcd(DPCD_TEST_RESPONSE, + DPCD_TEST_EDID_CHECKSUM_WRITE); + } + } + + debug("DP EDID Read success!\n"); + + return 0; +} + +static unsigned int exynos_dp_handle_edid(struct edp_device_info *edp_info) +{ + unsigned char buf[12]; + unsigned int ret; + unsigned char temp; + unsigned char retry_cnt; + unsigned char dpcd_rev[16]; + unsigned char lane_bw[16]; + unsigned char lane_cnt[16]; + + memset(dpcd_rev, 0, 16); + memset(lane_bw, 0, 16); + memset(lane_cnt, 0, 16); + memset(buf, 0, 12); + + retry_cnt = 5; + while (retry_cnt) { + /* Read DPCD 0x0000-0x000b */ + ret = exynos_dp_read_bytes_from_dpcd(DPCD_DPCD_REV, 12, + buf); + if (ret != EXYNOS_DP_SUCCESS) { + if (retry_cnt == 0) { + printf("DP read_byte_from_dpcd() failed\n"); + return ret; + } + retry_cnt--; + } else + break; + } + + /* */ + temp = buf[DPCD_DPCD_REV]; + if (temp == DP_DPCD_REV_10 || temp == DP_DPCD_REV_11) + edp_info->dpcd_rev = temp; + else { + printf("DP Wrong DPCD Rev : %x\n", temp); + return -ENODEV; + } + + temp = buf[DPCD_MAX_LINK_RATE]; + if (temp == DP_LANE_BW_1_62 || temp == DP_LANE_BW_2_70) + edp_info->lane_bw = temp; + else { + printf("DP Wrong MAX LINK RATE : %x\n", temp); + return -EINVAL; + } + + /* Refer VESA Display Port Standard Ver1.1a Page 120 */ + if (edp_info->dpcd_rev == DP_DPCD_REV_11) { + temp = buf[DPCD_MAX_LANE_COUNT] & 0x1f; + if (buf[DPCD_MAX_LANE_COUNT] & 0x80) + edp_info->dpcd_efc = 1; + else + edp_info->dpcd_efc = 0; + } else { + temp = buf[DPCD_MAX_LANE_COUNT]; + edp_info->dpcd_efc = 0; + } + + if (temp == DP_LANE_CNT_1 || temp == DP_LANE_CNT_2 || + temp == DP_LANE_CNT_4) { + edp_info->lane_cnt = temp; + } else { + printf("DP Wrong MAX LANE COUNT : %x\n", temp); + return -EINVAL; + } + + ret = exynos_dp_read_edid(); + if (ret != EXYNOS_DP_SUCCESS) { + printf("DP exynos_dp_read_edid() failed\n"); + return -EINVAL; + } + + return ret; +} + +static void exynos_dp_init_training(void) +{ + /* + * MACRO_RST must be applied after the PLL_LOCK to avoid + * the DP inter pair skew issue for at least 10 us + */ + exynos_dp_reset_macro(); + + /* All DP analog module power up */ + exynos_dp_set_analog_power_down(POWER_ALL, 0); +} + +static unsigned int exynos_dp_link_start(struct edp_device_info *edp_info) +{ + unsigned char buf[5]; + unsigned int ret = 0; + + debug("DP: %s was called\n", __func__); + + edp_info->lt_info.lt_status = DP_LT_CR; + edp_info->lt_info.ep_loop = 0; + edp_info->lt_info.cr_loop[0] = 0; + edp_info->lt_info.cr_loop[1] = 0; + edp_info->lt_info.cr_loop[2] = 0; + edp_info->lt_info.cr_loop[3] = 0; + + /* Set sink to D0 (Sink Not Ready) mode. */ + ret = exynos_dp_write_byte_to_dpcd(DPCD_SINK_POWER_STATE, + DPCD_SET_POWER_STATE_D0); + if (ret != EXYNOS_DP_SUCCESS) { + printf("DP write_dpcd_byte failed\n"); + return ret; + } + + /* Set link rate and count as you want to establish */ + exynos_dp_set_link_bandwidth(edp_info->lane_bw); + exynos_dp_set_lane_count(edp_info->lane_cnt); + + /* Setup RX configuration */ + buf[0] = edp_info->lane_bw; + buf[1] = edp_info->lane_cnt; + + ret = exynos_dp_write_bytes_to_dpcd(DPCD_LINK_BW_SET, 2, + buf); + if (ret != EXYNOS_DP_SUCCESS) { + printf("DP write_dpcd_byte failed\n"); + return ret; + } + + exynos_dp_set_lane_pre_emphasis(PRE_EMPHASIS_LEVEL_0, + edp_info->lane_cnt); + + /* Set training pattern 1 */ + exynos_dp_set_training_pattern(TRAINING_PTN1); + + /* Set RX training pattern */ + buf[0] = DPCD_SCRAMBLING_DISABLED | DPCD_TRAINING_PATTERN_1; + + buf[1] = DPCD_PRE_EMPHASIS_SET_PATTERN_2_LEVEL_0 | + DPCD_VOLTAGE_SWING_SET_PATTERN_1_LEVEL_0; + buf[2] = DPCD_PRE_EMPHASIS_SET_PATTERN_2_LEVEL_0 | + DPCD_VOLTAGE_SWING_SET_PATTERN_1_LEVEL_0; + buf[3] = DPCD_PRE_EMPHASIS_SET_PATTERN_2_LEVEL_0 | + DPCD_VOLTAGE_SWING_SET_PATTERN_1_LEVEL_0; + buf[4] = DPCD_PRE_EMPHASIS_SET_PATTERN_2_LEVEL_0 | + DPCD_VOLTAGE_SWING_SET_PATTERN_1_LEVEL_0; + + ret = exynos_dp_write_bytes_to_dpcd(DPCD_TRAINING_PATTERN_SET, + 5, buf); + if (ret != EXYNOS_DP_SUCCESS) { + printf("DP write_dpcd_byte failed\n"); + return ret; + } + + return ret; +} + +static unsigned int exynos_dp_training_pattern_dis(void) +{ + unsigned int ret = EXYNOS_DP_SUCCESS; + + exynos_dp_set_training_pattern(DP_NONE); + + ret = exynos_dp_write_byte_to_dpcd(DPCD_TRAINING_PATTERN_SET, + DPCD_TRAINING_PATTERN_DISABLED); + if (ret != EXYNOS_DP_SUCCESS) { + printf("DP request_link_training_req failed\n"); + return -EAGAIN; + } + + return ret; +} + +static unsigned int exynos_dp_enable_rx_to_enhanced_mode(unsigned char enable) +{ + unsigned char data; + unsigned int ret = EXYNOS_DP_SUCCESS; + + ret = exynos_dp_read_byte_from_dpcd(DPCD_LANE_COUNT_SET, + &data); + if (ret != EXYNOS_DP_SUCCESS) { + printf("DP read_from_dpcd failed\n"); + return -EAGAIN; + } + + if (enable) + data = DPCD_ENHANCED_FRAME_EN | DPCD_LN_COUNT_SET(data); + else + data = DPCD_LN_COUNT_SET(data); + + ret = exynos_dp_write_byte_to_dpcd(DPCD_LANE_COUNT_SET, + data); + if (ret != EXYNOS_DP_SUCCESS) { + printf("DP write_to_dpcd failed\n"); + return -EAGAIN; + + } + + return ret; +} + +static unsigned int exynos_dp_set_enhanced_mode(unsigned char enhance_mode) +{ + unsigned int ret = EXYNOS_DP_SUCCESS; + + ret = exynos_dp_enable_rx_to_enhanced_mode(enhance_mode); + if (ret != EXYNOS_DP_SUCCESS) { + printf("DP rx_enhance_mode failed\n"); + return -EAGAIN; + } + + exynos_dp_enable_enhanced_mode(enhance_mode); + + return ret; +} + +static int exynos_dp_read_dpcd_lane_stat(struct edp_device_info *edp_info, + unsigned char *status) +{ + unsigned int ret, i; + unsigned char buf[2]; + unsigned char lane_stat[DP_LANE_CNT_4] = {0,}; + unsigned char shift_val[DP_LANE_CNT_4] = {0,}; + + shift_val[0] = 0; + shift_val[1] = 4; + shift_val[2] = 0; + shift_val[3] = 4; + + ret = exynos_dp_read_bytes_from_dpcd(DPCD_LANE0_1_STATUS, 2, buf); + if (ret != EXYNOS_DP_SUCCESS) { + printf("DP read lane status failed\n"); + return ret; + } + + for (i = 0; i < edp_info->lane_cnt; i++) { + lane_stat[i] = (buf[(i / 2)] >> shift_val[i]) & 0x0f; + if (lane_stat[0] != lane_stat[i]) { + printf("Wrong lane status\n"); + return -EINVAL; + } + } + + *status = lane_stat[0]; + + return ret; +} + +static unsigned int exynos_dp_read_dpcd_adj_req(unsigned char lane_num, + unsigned char *sw, unsigned char *em) +{ + unsigned int ret = EXYNOS_DP_SUCCESS; + unsigned char buf; + unsigned int dpcd_addr; + unsigned char shift_val[DP_LANE_CNT_4] = {0, 4, 0, 4}; + + /* lane_num value is used as array index, so this range 0 ~ 3 */ + dpcd_addr = DPCD_ADJUST_REQUEST_LANE0_1 + (lane_num / 2); + + ret = exynos_dp_read_byte_from_dpcd(dpcd_addr, &buf); + if (ret != EXYNOS_DP_SUCCESS) { + printf("DP read adjust request failed\n"); + return -EAGAIN; + } + + *sw = ((buf >> shift_val[lane_num]) & 0x03); + *em = ((buf >> shift_val[lane_num]) & 0x0c) >> 2; + + return ret; +} + +static int exynos_dp_equalizer_err_link(struct edp_device_info *edp_info) +{ + int ret; + + ret = exynos_dp_training_pattern_dis(); + if (ret != EXYNOS_DP_SUCCESS) { + printf("DP training_pattern_disable() failed\n"); + edp_info->lt_info.lt_status = DP_LT_FAIL; + } + + ret = exynos_dp_set_enhanced_mode(edp_info->dpcd_efc); + if (ret != EXYNOS_DP_SUCCESS) { + printf("DP set_enhanced_mode() failed\n"); + edp_info->lt_info.lt_status = DP_LT_FAIL; + } + + return ret; +} + +static int exynos_dp_reduce_link_rate(struct edp_device_info *edp_info) +{ + int ret; + + if (edp_info->lane_bw == DP_LANE_BW_2_70) { + edp_info->lane_bw = DP_LANE_BW_1_62; + printf("DP Change lane bw to 1.62Gbps\n"); + edp_info->lt_info.lt_status = DP_LT_START; + ret = EXYNOS_DP_SUCCESS; + } else { + ret = exynos_dp_training_pattern_dis(); + if (ret != EXYNOS_DP_SUCCESS) + printf("DP training_patter_disable() failed\n"); + + ret = exynos_dp_set_enhanced_mode(edp_info->dpcd_efc); + if (ret != EXYNOS_DP_SUCCESS) + printf("DP set_enhanced_mode() failed\n"); + + edp_info->lt_info.lt_status = DP_LT_FAIL; + } + + return ret; +} + +static unsigned int exynos_dp_process_clock_recovery(struct edp_device_info + *edp_info) +{ + unsigned int ret = EXYNOS_DP_SUCCESS; + unsigned char lane_stat; + unsigned char lt_ctl_val[DP_LANE_CNT_4] = {0, }; + unsigned int i; + unsigned char adj_req_sw; + unsigned char adj_req_em; + unsigned char buf[5]; + + debug("DP: %s was called\n", __func__); + mdelay(1); + + ret = exynos_dp_read_dpcd_lane_stat(edp_info, &lane_stat); + if (ret != EXYNOS_DP_SUCCESS) { + printf("DP read lane status failed\n"); + edp_info->lt_info.lt_status = DP_LT_FAIL; + return ret; + } + + if (lane_stat & DP_LANE_STAT_CR_DONE) { + debug("DP clock Recovery training succeed\n"); + exynos_dp_set_training_pattern(TRAINING_PTN2); + + for (i = 0; i < edp_info->lane_cnt; i++) { + ret = exynos_dp_read_dpcd_adj_req(i, &adj_req_sw, + &adj_req_em); + if (ret != EXYNOS_DP_SUCCESS) { + edp_info->lt_info.lt_status = DP_LT_FAIL; + return ret; + } + + lt_ctl_val[i] = 0; + lt_ctl_val[i] = adj_req_em << 3 | adj_req_sw; + + if ((adj_req_sw == VOLTAGE_LEVEL_3) + || (adj_req_em == PRE_EMPHASIS_LEVEL_3)) { + lt_ctl_val[i] |= MAX_DRIVE_CURRENT_REACH_3 | + MAX_PRE_EMPHASIS_REACH_3; + } + exynos_dp_set_lanex_pre_emphasis(lt_ctl_val[i], i); + } + + buf[0] = DPCD_SCRAMBLING_DISABLED | DPCD_TRAINING_PATTERN_2; + buf[1] = lt_ctl_val[0]; + buf[2] = lt_ctl_val[1]; + buf[3] = lt_ctl_val[2]; + buf[4] = lt_ctl_val[3]; + + ret = exynos_dp_write_bytes_to_dpcd( + DPCD_TRAINING_PATTERN_SET, 5, buf); + if (ret != EXYNOS_DP_SUCCESS) { + printf("DP write training pattern1 failed\n"); + edp_info->lt_info.lt_status = DP_LT_FAIL; + return ret; + } else + edp_info->lt_info.lt_status = DP_LT_ET; + } else { + for (i = 0; i < edp_info->lane_cnt; i++) { + lt_ctl_val[i] = exynos_dp_get_lanex_pre_emphasis(i); + ret = exynos_dp_read_dpcd_adj_req(i, + &adj_req_sw, &adj_req_em); + if (ret != EXYNOS_DP_SUCCESS) { + printf("DP read adj req failed\n"); + edp_info->lt_info.lt_status = DP_LT_FAIL; + return ret; + } + + if ((adj_req_sw == VOLTAGE_LEVEL_3) || + (adj_req_em == PRE_EMPHASIS_LEVEL_3)) + ret = exynos_dp_reduce_link_rate(edp_info); + + if ((DRIVE_CURRENT_SET_0_GET(lt_ctl_val[i]) == + adj_req_sw) && + (PRE_EMPHASIS_SET_0_GET(lt_ctl_val[i]) == + adj_req_em)) { + edp_info->lt_info.cr_loop[i]++; + if (edp_info->lt_info.cr_loop[i] == MAX_CR_LOOP) + ret = exynos_dp_reduce_link_rate( + edp_info); + } + + lt_ctl_val[i] = 0; + lt_ctl_val[i] = adj_req_em << 3 | adj_req_sw; + + if ((adj_req_sw == VOLTAGE_LEVEL_3) || + (adj_req_em == PRE_EMPHASIS_LEVEL_3)) { + lt_ctl_val[i] |= MAX_DRIVE_CURRENT_REACH_3 | + MAX_PRE_EMPHASIS_REACH_3; + } + exynos_dp_set_lanex_pre_emphasis(lt_ctl_val[i], i); + } + + ret = exynos_dp_write_bytes_to_dpcd( + DPCD_TRAINING_LANE0_SET, 4, lt_ctl_val); + if (ret != EXYNOS_DP_SUCCESS) { + printf("DP write training pattern2 failed\n"); + edp_info->lt_info.lt_status = DP_LT_FAIL; + return ret; + } + } + + return ret; +} + +static unsigned int exynos_dp_process_equalizer_training(struct edp_device_info + *edp_info) +{ + unsigned int ret = EXYNOS_DP_SUCCESS; + unsigned char lane_stat, adj_req_sw, adj_req_em, i; + unsigned char lt_ctl_val[DP_LANE_CNT_4] = {0,}; + unsigned char interlane_aligned = 0; + unsigned char f_bw; + unsigned char f_lane_cnt; + unsigned char sink_stat; + + mdelay(1); + + ret = exynos_dp_read_dpcd_lane_stat(edp_info, &lane_stat); + if (ret != EXYNOS_DP_SUCCESS) { + printf("DP read lane status failed\n"); + edp_info->lt_info.lt_status = DP_LT_FAIL; + return ret; + } + + debug("DP lane stat : %x\n", lane_stat); + + if (lane_stat & DP_LANE_STAT_CR_DONE) { + ret = exynos_dp_read_byte_from_dpcd(DPCD_LN_ALIGN_UPDATED, + &sink_stat); + if (ret != EXYNOS_DP_SUCCESS) { + edp_info->lt_info.lt_status = DP_LT_FAIL; + + return ret; + } + + interlane_aligned = (sink_stat & DPCD_INTERLANE_ALIGN_DONE); + + for (i = 0; i < edp_info->lane_cnt; i++) { + ret = exynos_dp_read_dpcd_adj_req(i, + &adj_req_sw, &adj_req_em); + if (ret != EXYNOS_DP_SUCCESS) { + printf("DP read adj req 1 failed\n"); + edp_info->lt_info.lt_status = DP_LT_FAIL; + + return ret; + } + + lt_ctl_val[i] = 0; + lt_ctl_val[i] = adj_req_em << 3 | adj_req_sw; + + if ((adj_req_sw == VOLTAGE_LEVEL_3) || + (adj_req_em == PRE_EMPHASIS_LEVEL_3)) { + lt_ctl_val[i] |= MAX_DRIVE_CURRENT_REACH_3; + lt_ctl_val[i] |= MAX_PRE_EMPHASIS_REACH_3; + } + } + + if (((lane_stat&DP_LANE_STAT_CE_DONE) && + (lane_stat&DP_LANE_STAT_SYM_LOCK)) + && (interlane_aligned == DPCD_INTERLANE_ALIGN_DONE)) { + debug("DP Equalizer training succeed\n"); + + f_bw = exynos_dp_get_link_bandwidth(); + f_lane_cnt = exynos_dp_get_lane_count(); + + debug("DP final BandWidth : %x\n", f_bw); + debug("DP final Lane Count : %x\n", f_lane_cnt); + + edp_info->lt_info.lt_status = DP_LT_FINISHED; + + exynos_dp_equalizer_err_link(edp_info); + + } else { + edp_info->lt_info.ep_loop++; + + if (edp_info->lt_info.ep_loop > MAX_EQ_LOOP) { + if (edp_info->lane_bw == DP_LANE_BW_2_70) { + ret = exynos_dp_reduce_link_rate( + edp_info); + } else { + edp_info->lt_info.lt_status = + DP_LT_FAIL; + exynos_dp_equalizer_err_link(edp_info); + } + } else { + for (i = 0; i < edp_info->lane_cnt; i++) + exynos_dp_set_lanex_pre_emphasis( + lt_ctl_val[i], i); + + ret = exynos_dp_write_bytes_to_dpcd( + DPCD_TRAINING_LANE0_SET, + 4, lt_ctl_val); + if (ret != EXYNOS_DP_SUCCESS) { + printf("DP set lt pattern failed\n"); + edp_info->lt_info.lt_status = + DP_LT_FAIL; + exynos_dp_equalizer_err_link(edp_info); + } + } + } + } else if (edp_info->lane_bw == DP_LANE_BW_2_70) { + ret = exynos_dp_reduce_link_rate(edp_info); + } else { + edp_info->lt_info.lt_status = DP_LT_FAIL; + exynos_dp_equalizer_err_link(edp_info); + } + + return ret; +} + +static unsigned int exynos_dp_sw_link_training(struct edp_device_info *edp_info) +{ + unsigned int ret = 0; + int training_finished; + + /* Turn off unnecessary lane */ + if (edp_info->lane_cnt == 1) + exynos_dp_set_analog_power_down(CH1_BLOCK, 1); + + training_finished = 0; + + edp_info->lt_info.lt_status = DP_LT_START; + + /* Process here */ + while (!training_finished) { + switch (edp_info->lt_info.lt_status) { + case DP_LT_START: + ret = exynos_dp_link_start(edp_info); + if (ret != EXYNOS_DP_SUCCESS) { + printf("DP LT:link start failed\n"); + return ret; + } + break; + case DP_LT_CR: + ret = exynos_dp_process_clock_recovery(edp_info); + if (ret != EXYNOS_DP_SUCCESS) { + printf("DP LT:clock recovery failed\n"); + return ret; + } + break; + case DP_LT_ET: + ret = exynos_dp_process_equalizer_training(edp_info); + if (ret != EXYNOS_DP_SUCCESS) { + printf("DP LT:equalizer training failed\n"); + return ret; + } + break; + case DP_LT_FINISHED: + training_finished = 1; + break; + case DP_LT_FAIL: + return -1; + } + } + + return ret; +} + +static unsigned int exynos_dp_set_link_train(struct edp_device_info *edp_info) +{ + unsigned int ret; + + exynos_dp_init_training(); + + ret = exynos_dp_sw_link_training(edp_info); + if (ret != EXYNOS_DP_SUCCESS) + printf("DP dp_sw_link_training() failed\n"); + + return ret; +} + +static void exynos_dp_enable_scramble(unsigned int enable) +{ + unsigned char data; + + if (enable) { + exynos_dp_enable_scrambling(DP_ENABLE); + + exynos_dp_read_byte_from_dpcd(DPCD_TRAINING_PATTERN_SET, + &data); + exynos_dp_write_byte_to_dpcd(DPCD_TRAINING_PATTERN_SET, + (u8)(data & ~DPCD_SCRAMBLING_DISABLED)); + } else { + exynos_dp_enable_scrambling(DP_DISABLE); + exynos_dp_read_byte_from_dpcd(DPCD_TRAINING_PATTERN_SET, + &data); + exynos_dp_write_byte_to_dpcd(DPCD_TRAINING_PATTERN_SET, + (u8)(data | DPCD_SCRAMBLING_DISABLED)); + } +} + +static unsigned int exynos_dp_config_video(struct edp_device_info *edp_info) +{ + unsigned int ret = 0; + unsigned int retry_cnt; + + mdelay(1); + + if (edp_info->video_info.master_mode) { + printf("DP does not support master mode\n"); + return -ENODEV; + } else { + /* debug slave */ + exynos_dp_config_video_slave_mode(&edp_info->video_info); + } + + exynos_dp_set_video_color_format(&edp_info->video_info); + + if (edp_info->video_info.bist_mode) { + if (exynos_dp_config_video_bist(edp_info) != 0) + return -1; + } + + ret = exynos_dp_get_pll_lock_status(); + if (ret != PLL_LOCKED) { + printf("DP PLL is not locked yet\n"); + return -EIO; + } + + if (edp_info->video_info.master_mode == 0) { + retry_cnt = 10; + while (retry_cnt) { + ret = exynos_dp_is_slave_video_stream_clock_on(); + if (ret != EXYNOS_DP_SUCCESS) { + if (retry_cnt == 0) { + printf("DP stream_clock_on failed\n"); + return ret; + } + retry_cnt--; + mdelay(1); + } else + break; + } + } + + /* Set to use the register calculated M/N video */ + exynos_dp_set_video_cr_mn(CALCULATED_M, 0, 0); + + /* For video bist, Video timing must be generated by register */ + exynos_dp_set_video_timing_mode(VIDEO_TIMING_FROM_CAPTURE); + + /* Enable video bist */ + if (edp_info->video_info.bist_pattern != COLOR_RAMP && + edp_info->video_info.bist_pattern != BALCK_WHITE_V_LINES && + edp_info->video_info.bist_pattern != COLOR_SQUARE) + exynos_dp_enable_video_bist(edp_info->video_info.bist_mode); + else + exynos_dp_enable_video_bist(DP_DISABLE); + + /* Disable video mute */ + exynos_dp_enable_video_mute(DP_DISABLE); + + /* Configure video Master or Slave mode */ + exynos_dp_enable_video_master(edp_info->video_info.master_mode); + + /* Enable video */ + exynos_dp_start_video(); + + if (edp_info->video_info.master_mode == 0) { + retry_cnt = 100; + while (retry_cnt) { + ret = exynos_dp_is_video_stream_on(); + if (ret != EXYNOS_DP_SUCCESS) { + if (retry_cnt == 0) { + printf("DP Timeout of video stream\n"); + return ret; + } + retry_cnt--; + mdelay(5); + } else + break; + } + } + + return ret; +} + +int exynos_dp_parse_dt(const void *blob, struct edp_device_info *edp_info) +{ + unsigned int node = fdtdec_next_compatible(blob, 0, + COMPAT_SAMSUNG_EXYNOS5_DP); + if (node <= 0) { + debug("exynos_dp: Can't get device node for dp\n"); + return -ENODEV; + } + + edp_info->disp_info.h_res = fdtdec_get_int(blob, node, + "samsung,h-res", 0); + edp_info->disp_info.h_sync_width = fdtdec_get_int(blob, node, + "samsung,h-sync-width", 0); + edp_info->disp_info.h_back_porch = fdtdec_get_int(blob, node, + "samsung,h-back-porch", 0); + edp_info->disp_info.h_front_porch = fdtdec_get_int(blob, node, + "samsung,h-front-porch", 0); + edp_info->disp_info.v_res = fdtdec_get_int(blob, node, + "samsung,v-res", 0); + edp_info->disp_info.v_sync_width = fdtdec_get_int(blob, node, + "samsung,v-sync-width", 0); + edp_info->disp_info.v_back_porch = fdtdec_get_int(blob, node, + "samsung,v-back-porch", 0); + edp_info->disp_info.v_front_porch = fdtdec_get_int(blob, node, + "samsung,v-front-porch", 0); + edp_info->disp_info.v_sync_rate = fdtdec_get_int(blob, node, + "samsung,v-sync-rate", 0); + + edp_info->lt_info.lt_status = fdtdec_get_int(blob, node, + "samsung,lt-status", 0); + + edp_info->video_info.master_mode = fdtdec_get_int(blob, node, + "samsung,master-mode", 0); + edp_info->video_info.bist_mode = fdtdec_get_int(blob, node, + "samsung,bist-mode", 0); + edp_info->video_info.bist_pattern = fdtdec_get_int(blob, node, + "samsung,bist-pattern", 0); + edp_info->video_info.h_sync_polarity = fdtdec_get_int(blob, node, + "samsung,h-sync-polarity", 0); + edp_info->video_info.v_sync_polarity = fdtdec_get_int(blob, node, + "samsung,v-sync-polarity", 0); + edp_info->video_info.interlaced = fdtdec_get_int(blob, node, + "samsung,interlaced", 0); + edp_info->video_info.color_space = fdtdec_get_int(blob, node, + "samsung,color-space", 0); + edp_info->video_info.dynamic_range = fdtdec_get_int(blob, node, + "samsung,dynamic-range", 0); + edp_info->video_info.ycbcr_coeff = fdtdec_get_int(blob, node, + "samsung,ycbcr-coeff", 0); + edp_info->video_info.color_depth = fdtdec_get_int(blob, node, + "samsung,color-depth", 0); + return 0; +} + +unsigned int exynos_init_dp(void) +{ + unsigned int ret; + struct edp_device_info *edp_info; + + edp_info = kzalloc(sizeof(struct edp_device_info), GFP_KERNEL); + if (!edp_info) { + debug("failed to allocate edp device object.\n"); + return -EFAULT; + } + + if (exynos_dp_parse_dt(gd->fdt_blob, edp_info)) + debug("unable to parse DP DT node\n"); + + exynos_dp_set_base_addr(); + + exynos_dp_disp_info(&edp_info->disp_info); + + exynos_set_dp_phy(1); + + ret = exynos_dp_init_dp(); + if (ret != EXYNOS_DP_SUCCESS) { + printf("DP exynos_dp_init_dp() failed\n"); + return ret; + } + + ret = exynos_dp_handle_edid(edp_info); + if (ret != EXYNOS_DP_SUCCESS) { + printf("EDP handle_edid fail\n"); + return ret; + } + + ret = exynos_dp_set_link_train(edp_info); + if (ret != EXYNOS_DP_SUCCESS) { + printf("DP link training fail\n"); + return ret; + } + + exynos_dp_enable_scramble(DP_ENABLE); + exynos_dp_enable_rx_to_enhanced_mode(DP_ENABLE); + exynos_dp_enable_enhanced_mode(DP_ENABLE); + + exynos_dp_set_link_bandwidth(edp_info->lane_bw); + exynos_dp_set_lane_count(edp_info->lane_cnt); + + exynos_dp_init_video(); + ret = exynos_dp_config_video(edp_info); + if (ret != EXYNOS_DP_SUCCESS) { + printf("Exynos DP init failed\n"); + return ret; + } + + debug("Exynos DP init done\n"); + + return ret; +} diff --git a/drivers/video/exynos/exynos_dp_lowlevel.c b/drivers/video/exynos/exynos_dp_lowlevel.c new file mode 100644 index 0000000..acb5bc8 --- /dev/null +++ b/drivers/video/exynos/exynos_dp_lowlevel.c @@ -0,0 +1,1257 @@ +/* + * Copyright (C) 2012 Samsung Electronics + * + * Author: Donghwa Lee + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/* Declare global data pointer */ +DECLARE_GLOBAL_DATA_PTR; + +struct exynos_dp *dp_regs; + +void exynos_dp_set_base_addr(void) +{ +#if CONFIG_IS_ENABLED(OF_CONTROL) + unsigned int node = fdtdec_next_compatible(gd->fdt_blob, + 0, COMPAT_SAMSUNG_EXYNOS5_DP); + if (node <= 0) + debug("exynos_dp: Can't get device node for dp\n"); + + dp_regs = (struct exynos_dp *)fdtdec_get_addr(gd->fdt_blob, + node, "reg"); + if (dp_regs == NULL) + debug("Can't get the DP base address\n"); +#else + dp_regs = (struct exynos_dp *)samsung_get_base_dp(); +#endif +} + +static void exynos_dp_enable_video_input(unsigned int enable) +{ + unsigned int reg; + + reg = readl(&dp_regs->video_ctl1); + reg &= ~VIDEO_EN_MASK; + + /* enable video input */ + if (enable) + reg |= VIDEO_EN_MASK; + + writel(reg, &dp_regs->video_ctl1); + + return; +} + +void exynos_dp_enable_video_bist(unsigned int enable) +{ + /* enable video bist */ + unsigned int reg; + + reg = readl(&dp_regs->video_ctl4); + reg &= ~VIDEO_BIST_MASK; + + /* enable video bist */ + if (enable) + reg |= VIDEO_BIST_MASK; + + writel(reg, &dp_regs->video_ctl4); + + return; +} + +void exynos_dp_enable_video_mute(unsigned int enable) +{ + unsigned int reg; + + reg = readl(&dp_regs->video_ctl1); + reg &= ~(VIDEO_MUTE_MASK); + if (enable) + reg |= VIDEO_MUTE_MASK; + + writel(reg, &dp_regs->video_ctl1); + + return; +} + + +static void exynos_dp_init_analog_param(void) +{ + unsigned int reg; + + /* + * Set termination + * Normal bandgap, Normal swing, Tx terminal registor 61 ohm + * 24M Phy clock, TX digital logic power is 100:1.0625V + */ + reg = SEL_BG_NEW_BANDGAP | TX_TERMINAL_CTRL_61_OHM | + SWING_A_30PER_G_NORMAL; + writel(reg, &dp_regs->analog_ctl1); + + reg = SEL_24M | TX_DVDD_BIT_1_0625V; + writel(reg, &dp_regs->analog_ctl2); + + /* + * Set power source for internal clk driver to 1.0625v. + * Select current reference of TX driver current to 00:Ipp/2+Ic/2. + * Set VCO range of PLL +- 0uA + */ + reg = DRIVE_DVDD_BIT_1_0625V | SEL_CURRENT_DEFAULT | VCO_BIT_000_MICRO; + writel(reg, &dp_regs->analog_ctl3); + + /* + * Set AUX TX terminal resistor to 102 ohm + * Set AUX channel amplitude control + */ + reg = PD_RING_OSC | AUX_TERMINAL_CTRL_52_OHM | TX_CUR1_2X | TX_CUR_4_MA; + writel(reg, &dp_regs->pll_filter_ctl1); + + /* + * PLL loop filter bandwidth + * For 2.7Gbps: 175KHz, For 1.62Gbps: 234KHz + * PLL digital power select: 1.2500V + */ + reg = CH3_AMP_0_MV | CH2_AMP_0_MV | CH1_AMP_0_MV | CH0_AMP_0_MV; + + writel(reg, &dp_regs->amp_tuning_ctl); + + /* + * PLL loop filter bandwidth + * For 2.7Gbps: 175KHz, For 1.62Gbps: 234KHz + * PLL digital power select: 1.1250V + */ + reg = DP_PLL_LOOP_BIT_DEFAULT | DP_PLL_REF_BIT_1_1250V; + writel(reg, &dp_regs->pll_ctl); +} + +static void exynos_dp_init_interrupt(void) +{ + /* Set interrupt registers to initial states */ + + /* + * Disable interrupt + * INT pin assertion polarity. It must be configured + * correctly according to ICU setting. + * 1 = assert high, 0 = assert low + */ + writel(INT_POL, &dp_regs->int_ctl); + + /* Clear pending registers */ + writel(0xff, &dp_regs->common_int_sta1); + writel(0xff, &dp_regs->common_int_sta2); + writel(0xff, &dp_regs->common_int_sta3); + writel(0xff, &dp_regs->common_int_sta4); + writel(0xff, &dp_regs->int_sta); + + /* 0:mask,1: unmask */ + writel(0x00, &dp_regs->int_sta_mask1); + writel(0x00, &dp_regs->int_sta_mask2); + writel(0x00, &dp_regs->int_sta_mask3); + writel(0x00, &dp_regs->int_sta_mask4); + writel(0x00, &dp_regs->int_sta_mask); +} + +void exynos_dp_reset(void) +{ + unsigned int reg_func_1; + + /* dp tx sw reset */ + writel(RESET_DP_TX, &dp_regs->tx_sw_reset); + + exynos_dp_enable_video_input(DP_DISABLE); + exynos_dp_enable_video_bist(DP_DISABLE); + exynos_dp_enable_video_mute(DP_DISABLE); + + /* software reset */ + reg_func_1 = MASTER_VID_FUNC_EN_N | SLAVE_VID_FUNC_EN_N | + AUD_FIFO_FUNC_EN_N | AUD_FUNC_EN_N | + HDCP_FUNC_EN_N | SW_FUNC_EN_N; + + writel(reg_func_1, &dp_regs->func_en1); + writel(reg_func_1, &dp_regs->func_en2); + + mdelay(1); + + exynos_dp_init_analog_param(); + exynos_dp_init_interrupt(); + + return; +} + +void exynos_dp_enable_sw_func(unsigned int enable) +{ + unsigned int reg; + + reg = readl(&dp_regs->func_en1); + reg &= ~(SW_FUNC_EN_N); + + if (!enable) + reg |= SW_FUNC_EN_N; + + writel(reg, &dp_regs->func_en1); + + return; +} + +unsigned int exynos_dp_set_analog_power_down(unsigned int block, u32 enable) +{ + unsigned int reg; + + reg = readl(&dp_regs->phy_pd); + switch (block) { + case AUX_BLOCK: + reg &= ~(AUX_PD); + if (enable) + reg |= AUX_PD; + break; + case CH0_BLOCK: + reg &= ~(CH0_PD); + if (enable) + reg |= CH0_PD; + break; + case CH1_BLOCK: + reg &= ~(CH1_PD); + if (enable) + reg |= CH1_PD; + break; + case CH2_BLOCK: + reg &= ~(CH2_PD); + if (enable) + reg |= CH2_PD; + break; + case CH3_BLOCK: + reg &= ~(CH3_PD); + if (enable) + reg |= CH3_PD; + break; + case ANALOG_TOTAL: + reg &= ~PHY_PD; + if (enable) + reg |= PHY_PD; + break; + case POWER_ALL: + reg &= ~(PHY_PD | AUX_PD | CH0_PD | CH1_PD | CH2_PD | + CH3_PD); + if (enable) + reg |= (PHY_PD | AUX_PD | CH0_PD | CH1_PD | + CH2_PD | CH3_PD); + break; + default: + printf("DP undefined block number : %d\n", block); + return -1; + } + + writel(reg, &dp_regs->phy_pd); + + return 0; +} + +unsigned int exynos_dp_get_pll_lock_status(void) +{ + unsigned int reg; + + reg = readl(&dp_regs->debug_ctl); + + if (reg & PLL_LOCK) + return PLL_LOCKED; + else + return PLL_UNLOCKED; +} + +static void exynos_dp_set_pll_power(unsigned int enable) +{ + unsigned int reg; + + reg = readl(&dp_regs->pll_ctl); + reg &= ~(DP_PLL_PD); + + if (!enable) + reg |= DP_PLL_PD; + + writel(reg, &dp_regs->pll_ctl); +} + +int exynos_dp_init_analog_func(void) +{ + int ret = EXYNOS_DP_SUCCESS; + unsigned int retry_cnt = 10; + unsigned int reg; + + /* Power On All Analog block */ + exynos_dp_set_analog_power_down(POWER_ALL, DP_DISABLE); + + reg = PLL_LOCK_CHG; + writel(reg, &dp_regs->common_int_sta1); + + reg = readl(&dp_regs->debug_ctl); + reg &= ~(F_PLL_LOCK | PLL_LOCK_CTRL); + writel(reg, &dp_regs->debug_ctl); + + /* Assert DP PLL Reset */ + reg = readl(&dp_regs->pll_ctl); + reg |= DP_PLL_RESET; + writel(reg, &dp_regs->pll_ctl); + + mdelay(1); + + /* Deassert DP PLL Reset */ + reg = readl(&dp_regs->pll_ctl); + reg &= ~(DP_PLL_RESET); + writel(reg, &dp_regs->pll_ctl); + + exynos_dp_set_pll_power(DP_ENABLE); + + while (exynos_dp_get_pll_lock_status() == PLL_UNLOCKED) { + mdelay(1); + retry_cnt--; + if (retry_cnt == 0) { + printf("DP dp's pll lock failed : retry : %d\n", + retry_cnt); + return -EINVAL; + } + } + + debug("dp's pll lock success(%d)\n", retry_cnt); + + /* Enable Serdes FIFO function and Link symbol clock domain module */ + reg = readl(&dp_regs->func_en2); + reg &= ~(SERDES_FIFO_FUNC_EN_N | LS_CLK_DOMAIN_FUNC_EN_N + | AUX_FUNC_EN_N); + writel(reg, &dp_regs->func_en2); + + return ret; +} + +void exynos_dp_init_hpd(void) +{ + unsigned int reg; + + /* Clear interrupts related to Hot Plug Detect */ + reg = HOTPLUG_CHG | HPD_LOST | PLUG; + writel(reg, &dp_regs->common_int_sta4); + + reg = INT_HPD; + writel(reg, &dp_regs->int_sta); + + reg = readl(&dp_regs->sys_ctl3); + reg &= ~(F_HPD | HPD_CTRL); + writel(reg, &dp_regs->sys_ctl3); + + return; +} + +static inline void exynos_dp_reset_aux(void) +{ + unsigned int reg; + + /* Disable AUX channel module */ + reg = readl(&dp_regs->func_en2); + reg |= AUX_FUNC_EN_N; + writel(reg, &dp_regs->func_en2); + + return; +} + +void exynos_dp_init_aux(void) +{ + unsigned int reg; + + /* Clear interrupts related to AUX channel */ + reg = RPLY_RECEIV | AUX_ERR; + writel(reg, &dp_regs->int_sta); + + exynos_dp_reset_aux(); + + /* Disable AUX transaction H/W retry */ + reg = AUX_BIT_PERIOD_EXPECTED_DELAY(3) | AUX_HW_RETRY_COUNT_SEL(3)| + AUX_HW_RETRY_INTERVAL_600_MICROSECONDS; + writel(reg, &dp_regs->aux_hw_retry_ctl); + + /* Receive AUX Channel DEFER commands equal to DEFER_COUNT*64 */ + reg = DEFER_CTRL_EN | DEFER_COUNT(1); + writel(reg, &dp_regs->aux_ch_defer_ctl); + + /* Enable AUX channel module */ + reg = readl(&dp_regs->func_en2); + reg &= ~AUX_FUNC_EN_N; + writel(reg, &dp_regs->func_en2); + + return; +} + +void exynos_dp_config_interrupt(void) +{ + unsigned int reg; + + /* 0: mask, 1: unmask */ + reg = COMMON_INT_MASK_1; + writel(reg, &dp_regs->common_int_mask1); + + reg = COMMON_INT_MASK_2; + writel(reg, &dp_regs->common_int_mask2); + + reg = COMMON_INT_MASK_3; + writel(reg, &dp_regs->common_int_mask3); + + reg = COMMON_INT_MASK_4; + writel(reg, &dp_regs->common_int_mask4); + + reg = INT_STA_MASK; + writel(reg, &dp_regs->int_sta_mask); + + return; +} + +unsigned int exynos_dp_get_plug_in_status(void) +{ + unsigned int reg; + + reg = readl(&dp_regs->sys_ctl3); + if (reg & HPD_STATUS) + return 0; + + return -1; +} + +unsigned int exynos_dp_detect_hpd(void) +{ + int timeout_loop = DP_TIMEOUT_LOOP_COUNT; + + mdelay(2); + + while (exynos_dp_get_plug_in_status() != 0) { + if (timeout_loop == 0) + return -EINVAL; + mdelay(10); + timeout_loop--; + } + + return EXYNOS_DP_SUCCESS; +} + +unsigned int exynos_dp_start_aux_transaction(void) +{ + unsigned int reg; + unsigned int ret = 0; + unsigned int retry_cnt; + + /* Enable AUX CH operation */ + reg = readl(&dp_regs->aux_ch_ctl2); + reg |= AUX_EN; + writel(reg, &dp_regs->aux_ch_ctl2); + + retry_cnt = 10; + while (retry_cnt) { + reg = readl(&dp_regs->int_sta); + if (!(reg & RPLY_RECEIV)) { + if (retry_cnt == 0) { + printf("DP Reply Timeout!!\n"); + ret = -EAGAIN; + return ret; + } + mdelay(1); + retry_cnt--; + } else + break; + } + + /* Clear interrupt source for AUX CH command reply */ + writel(reg, &dp_regs->int_sta); + + /* Clear interrupt source for AUX CH access error */ + reg = readl(&dp_regs->int_sta); + if (reg & AUX_ERR) { + printf("DP Aux Access Error\n"); + writel(AUX_ERR, &dp_regs->int_sta); + ret = -EAGAIN; + return ret; + } + + /* Check AUX CH error access status */ + reg = readl(&dp_regs->aux_ch_sta); + if ((reg & AUX_STATUS_MASK) != 0) { + debug("DP AUX CH error happens: %x\n", reg & AUX_STATUS_MASK); + ret = -EAGAIN; + return ret; + } + + return EXYNOS_DP_SUCCESS; +} + +unsigned int exynos_dp_write_byte_to_dpcd(unsigned int reg_addr, + unsigned char data) +{ + unsigned int reg, ret; + + /* Clear AUX CH data buffer */ + reg = BUF_CLR; + writel(reg, &dp_regs->buffer_data_ctl); + + /* Select DPCD device address */ + reg = AUX_ADDR_7_0(reg_addr); + writel(reg, &dp_regs->aux_addr_7_0); + reg = AUX_ADDR_15_8(reg_addr); + writel(reg, &dp_regs->aux_addr_15_8); + reg = AUX_ADDR_19_16(reg_addr); + writel(reg, &dp_regs->aux_addr_19_16); + + /* Write data buffer */ + reg = (unsigned int)data; + writel(reg, &dp_regs->buf_data0); + + /* + * Set DisplayPort transaction and write 1 byte + * If bit 3 is 1, DisplayPort transaction. + * If Bit 3 is 0, I2C transaction. + */ + reg = AUX_TX_COMM_DP_TRANSACTION | AUX_TX_COMM_WRITE; + writel(reg, &dp_regs->aux_ch_ctl1); + + /* Start AUX transaction */ + ret = exynos_dp_start_aux_transaction(); + if (ret != EXYNOS_DP_SUCCESS) { + printf("DP Aux transaction failed\n"); + return ret; + } + + return ret; +} + +unsigned int exynos_dp_read_byte_from_dpcd(unsigned int reg_addr, + unsigned char *data) +{ + unsigned int reg; + int retval; + + /* Clear AUX CH data buffer */ + reg = BUF_CLR; + writel(reg, &dp_regs->buffer_data_ctl); + + /* Select DPCD device address */ + reg = AUX_ADDR_7_0(reg_addr); + writel(reg, &dp_regs->aux_addr_7_0); + reg = AUX_ADDR_15_8(reg_addr); + writel(reg, &dp_regs->aux_addr_15_8); + reg = AUX_ADDR_19_16(reg_addr); + writel(reg, &dp_regs->aux_addr_19_16); + + /* + * Set DisplayPort transaction and read 1 byte + * If bit 3 is 1, DisplayPort transaction. + * If Bit 3 is 0, I2C transaction. + */ + reg = AUX_TX_COMM_DP_TRANSACTION | AUX_TX_COMM_READ; + writel(reg, &dp_regs->aux_ch_ctl1); + + /* Start AUX transaction */ + retval = exynos_dp_start_aux_transaction(); + if (!retval) + debug("DP Aux Transaction fail!\n"); + + /* Read data buffer */ + reg = readl(&dp_regs->buf_data0); + *data = (unsigned char)(reg & 0xff); + + return retval; +} + +unsigned int exynos_dp_write_bytes_to_dpcd(unsigned int reg_addr, + unsigned int count, + unsigned char data[]) +{ + unsigned int reg; + unsigned int start_offset; + unsigned int cur_data_count; + unsigned int cur_data_idx; + unsigned int retry_cnt; + unsigned int ret = 0; + + /* Clear AUX CH data buffer */ + reg = BUF_CLR; + writel(reg, &dp_regs->buffer_data_ctl); + + start_offset = 0; + while (start_offset < count) { + /* Buffer size of AUX CH is 16 * 4bytes */ + if ((count - start_offset) > 16) + cur_data_count = 16; + else + cur_data_count = count - start_offset; + + retry_cnt = 5; + while (retry_cnt) { + /* Select DPCD device address */ + reg = AUX_ADDR_7_0(reg_addr + start_offset); + writel(reg, &dp_regs->aux_addr_7_0); + reg = AUX_ADDR_15_8(reg_addr + start_offset); + writel(reg, &dp_regs->aux_addr_15_8); + reg = AUX_ADDR_19_16(reg_addr + start_offset); + writel(reg, &dp_regs->aux_addr_19_16); + + for (cur_data_idx = 0; cur_data_idx < cur_data_count; + cur_data_idx++) { + reg = data[start_offset + cur_data_idx]; + writel(reg, (unsigned int)&dp_regs->buf_data0 + + (4 * cur_data_idx)); + } + /* + * Set DisplayPort transaction and write + * If bit 3 is 1, DisplayPort transaction. + * If Bit 3 is 0, I2C transaction. + */ + reg = AUX_LENGTH(cur_data_count) | + AUX_TX_COMM_DP_TRANSACTION | AUX_TX_COMM_WRITE; + writel(reg, &dp_regs->aux_ch_ctl1); + + /* Start AUX transaction */ + ret = exynos_dp_start_aux_transaction(); + if (ret != EXYNOS_DP_SUCCESS) { + if (retry_cnt == 0) { + printf("DP Aux Transaction failed\n"); + return ret; + } + retry_cnt--; + } else + break; + } + start_offset += cur_data_count; + } + + return ret; +} + +unsigned int exynos_dp_read_bytes_from_dpcd(unsigned int reg_addr, + unsigned int count, + unsigned char data[]) +{ + unsigned int reg; + unsigned int start_offset; + unsigned int cur_data_count; + unsigned int cur_data_idx; + unsigned int retry_cnt; + unsigned int ret = 0; + + /* Clear AUX CH data buffer */ + reg = BUF_CLR; + writel(reg, &dp_regs->buffer_data_ctl); + + start_offset = 0; + while (start_offset < count) { + /* Buffer size of AUX CH is 16 * 4bytes */ + if ((count - start_offset) > 16) + cur_data_count = 16; + else + cur_data_count = count - start_offset; + + retry_cnt = 5; + while (retry_cnt) { + /* Select DPCD device address */ + reg = AUX_ADDR_7_0(reg_addr + start_offset); + writel(reg, &dp_regs->aux_addr_7_0); + reg = AUX_ADDR_15_8(reg_addr + start_offset); + writel(reg, &dp_regs->aux_addr_15_8); + reg = AUX_ADDR_19_16(reg_addr + start_offset); + writel(reg, &dp_regs->aux_addr_19_16); + /* + * Set DisplayPort transaction and read + * If bit 3 is 1, DisplayPort transaction. + * If Bit 3 is 0, I2C transaction. + */ + reg = AUX_LENGTH(cur_data_count) | + AUX_TX_COMM_DP_TRANSACTION | AUX_TX_COMM_READ; + writel(reg, &dp_regs->aux_ch_ctl1); + + /* Start AUX transaction */ + ret = exynos_dp_start_aux_transaction(); + if (ret != EXYNOS_DP_SUCCESS) { + if (retry_cnt == 0) { + printf("DP Aux Transaction failed\n"); + return ret; + } + retry_cnt--; + } else + break; + } + + for (cur_data_idx = 0; cur_data_idx < cur_data_count; + cur_data_idx++) { + reg = readl((unsigned int)&dp_regs->buf_data0 + + 4 * cur_data_idx); + data[start_offset + cur_data_idx] = (unsigned char)reg; + } + + start_offset += cur_data_count; + } + + return ret; +} + +int exynos_dp_select_i2c_device(unsigned int device_addr, + unsigned int reg_addr) +{ + unsigned int reg; + int retval; + + /* Set EDID device address */ + reg = device_addr; + writel(reg, &dp_regs->aux_addr_7_0); + writel(0x0, &dp_regs->aux_addr_15_8); + writel(0x0, &dp_regs->aux_addr_19_16); + + /* Set offset from base address of EDID device */ + writel(reg_addr, &dp_regs->buf_data0); + + /* + * Set I2C transaction and write address + * If bit 3 is 1, DisplayPort transaction. + * If Bit 3 is 0, I2C transaction. + */ + reg = AUX_TX_COMM_I2C_TRANSACTION | AUX_TX_COMM_MOT | + AUX_TX_COMM_WRITE; + writel(reg, &dp_regs->aux_ch_ctl1); + + /* Start AUX transaction */ + retval = exynos_dp_start_aux_transaction(); + if (retval != 0) + printf("%s: DP Aux Transaction fail!\n", __func__); + + return retval; +} + +int exynos_dp_read_byte_from_i2c(unsigned int device_addr, + unsigned int reg_addr, + unsigned int *data) +{ + unsigned int reg; + int i; + int retval; + + for (i = 0; i < 10; i++) { + /* Clear AUX CH data buffer */ + reg = BUF_CLR; + writel(reg, &dp_regs->buffer_data_ctl); + + /* Select EDID device */ + retval = exynos_dp_select_i2c_device(device_addr, reg_addr); + if (retval != 0) { + printf("DP Select EDID device fail. retry !\n"); + continue; + } + + /* + * Set I2C transaction and read data + * If bit 3 is 1, DisplayPort transaction. + * If Bit 3 is 0, I2C transaction. + */ + reg = AUX_TX_COMM_I2C_TRANSACTION | + AUX_TX_COMM_READ; + writel(reg, &dp_regs->aux_ch_ctl1); + + /* Start AUX transaction */ + retval = exynos_dp_start_aux_transaction(); + if (retval != EXYNOS_DP_SUCCESS) + printf("%s: DP Aux Transaction fail!\n", __func__); + } + + /* Read data */ + if (retval == 0) + *data = readl(&dp_regs->buf_data0); + + return retval; +} + +int exynos_dp_read_bytes_from_i2c(unsigned int device_addr, + unsigned int reg_addr, unsigned int count, unsigned char edid[]) +{ + unsigned int reg; + unsigned int i, j; + unsigned int cur_data_idx; + unsigned int defer = 0; + int retval = 0; + + for (i = 0; i < count; i += 16) { /* use 16 burst */ + for (j = 0; j < 100; j++) { + /* Clear AUX CH data buffer */ + reg = BUF_CLR; + writel(reg, &dp_regs->buffer_data_ctl); + + /* Set normal AUX CH command */ + reg = readl(&dp_regs->aux_ch_ctl2); + reg &= ~ADDR_ONLY; + writel(reg, &dp_regs->aux_ch_ctl2); + + /* + * If Rx sends defer, Tx sends only reads + * request without sending addres + */ + if (!defer) + retval = + exynos_dp_select_i2c_device(device_addr, + reg_addr + i); + else + defer = 0; + + if (retval == EXYNOS_DP_SUCCESS) { + /* + * Set I2C transaction and write data + * If bit 3 is 1, DisplayPort transaction. + * If Bit 3 is 0, I2C transaction. + */ + reg = AUX_LENGTH(16) | + AUX_TX_COMM_I2C_TRANSACTION | + AUX_TX_COMM_READ; + writel(reg, &dp_regs->aux_ch_ctl1); + + /* Start AUX transaction */ + retval = exynos_dp_start_aux_transaction(); + if (retval == 0) + break; + else + printf("DP Aux Transaction fail!\n"); + } + /* Check if Rx sends defer */ + reg = readl(&dp_regs->aux_rx_comm); + if (reg == AUX_RX_COMM_AUX_DEFER || + reg == AUX_RX_COMM_I2C_DEFER) { + printf("DP Defer: %d\n", reg); + defer = 1; + } + } + + for (cur_data_idx = 0; cur_data_idx < 16; cur_data_idx++) { + reg = readl((unsigned int)&dp_regs->buf_data0 + + 4 * cur_data_idx); + edid[i + cur_data_idx] = (unsigned char)reg; + } + } + + return retval; +} + +void exynos_dp_reset_macro(void) +{ + unsigned int reg; + + reg = readl(&dp_regs->phy_test); + reg |= MACRO_RST; + writel(reg, &dp_regs->phy_test); + + /* 10 us is the minimum Macro reset time. */ + mdelay(1); + + reg &= ~MACRO_RST; + writel(reg, &dp_regs->phy_test); +} + +void exynos_dp_set_link_bandwidth(unsigned char bwtype) +{ + unsigned int reg; + + reg = (unsigned int)bwtype; + + /* Set bandwidth to 2.7G or 1.62G */ + if ((bwtype == DP_LANE_BW_1_62) || (bwtype == DP_LANE_BW_2_70)) + writel(reg, &dp_regs->link_bw_set); +} + +unsigned char exynos_dp_get_link_bandwidth(void) +{ + unsigned char ret; + unsigned int reg; + + reg = readl(&dp_regs->link_bw_set); + ret = (unsigned char)reg; + + return ret; +} + +void exynos_dp_set_lane_count(unsigned char count) +{ + unsigned int reg; + + reg = (unsigned int)count; + + if ((count == DP_LANE_CNT_1) || (count == DP_LANE_CNT_2) || + (count == DP_LANE_CNT_4)) + writel(reg, &dp_regs->lane_count_set); +} + +unsigned int exynos_dp_get_lane_count(void) +{ + unsigned int reg; + + reg = readl(&dp_regs->lane_count_set); + + return reg; +} + +unsigned char exynos_dp_get_lanex_pre_emphasis(unsigned char lanecnt) +{ + unsigned int reg_list[DP_LANE_CNT_4] = { + (unsigned int)&dp_regs->ln0_link_training_ctl, + (unsigned int)&dp_regs->ln1_link_training_ctl, + (unsigned int)&dp_regs->ln2_link_training_ctl, + (unsigned int)&dp_regs->ln3_link_training_ctl, + }; + + return readl(reg_list[lanecnt]); +} + +void exynos_dp_set_lanex_pre_emphasis(unsigned char request_val, + unsigned char lanecnt) +{ + unsigned int reg_list[DP_LANE_CNT_4] = { + (unsigned int)&dp_regs->ln0_link_training_ctl, + (unsigned int)&dp_regs->ln1_link_training_ctl, + (unsigned int)&dp_regs->ln2_link_training_ctl, + (unsigned int)&dp_regs->ln3_link_training_ctl, + }; + + writel(request_val, reg_list[lanecnt]); +} + +void exynos_dp_set_lane_pre_emphasis(unsigned int level, unsigned char lanecnt) +{ + unsigned char i; + unsigned int reg; + unsigned int reg_list[DP_LANE_CNT_4] = { + (unsigned int)&dp_regs->ln0_link_training_ctl, + (unsigned int)&dp_regs->ln1_link_training_ctl, + (unsigned int)&dp_regs->ln2_link_training_ctl, + (unsigned int)&dp_regs->ln3_link_training_ctl, + }; + unsigned int reg_shift[DP_LANE_CNT_4] = { + PRE_EMPHASIS_SET_0_SHIFT, + PRE_EMPHASIS_SET_1_SHIFT, + PRE_EMPHASIS_SET_2_SHIFT, + PRE_EMPHASIS_SET_3_SHIFT + }; + + for (i = 0; i < lanecnt; i++) { + reg = level << reg_shift[i]; + writel(reg, reg_list[i]); + } +} + +void exynos_dp_set_training_pattern(unsigned int pattern) +{ + unsigned int reg = 0; + + switch (pattern) { + case PRBS7: + reg = SCRAMBLING_ENABLE | LINK_QUAL_PATTERN_SET_PRBS7; + break; + case D10_2: + reg = SCRAMBLING_ENABLE | LINK_QUAL_PATTERN_SET_D10_2; + break; + case TRAINING_PTN1: + reg = SCRAMBLING_DISABLE | SW_TRAINING_PATTERN_SET_PTN1; + break; + case TRAINING_PTN2: + reg = SCRAMBLING_DISABLE | SW_TRAINING_PATTERN_SET_PTN2; + break; + case DP_NONE: + reg = SCRAMBLING_ENABLE | LINK_QUAL_PATTERN_SET_DISABLE | + SW_TRAINING_PATTERN_SET_NORMAL; + break; + default: + break; + } + + writel(reg, &dp_regs->training_ptn_set); +} + +void exynos_dp_enable_enhanced_mode(unsigned char enable) +{ + unsigned int reg; + + reg = readl(&dp_regs->sys_ctl4); + reg &= ~ENHANCED; + + if (enable) + reg |= ENHANCED; + + writel(reg, &dp_regs->sys_ctl4); +} + +void exynos_dp_enable_scrambling(unsigned int enable) +{ + unsigned int reg; + + reg = readl(&dp_regs->training_ptn_set); + reg &= ~(SCRAMBLING_DISABLE); + + if (!enable) + reg |= SCRAMBLING_DISABLE; + + writel(reg, &dp_regs->training_ptn_set); +} + +int exynos_dp_init_video(void) +{ + unsigned int reg; + + /* Clear VID_CLK_CHG[1] and VID_FORMAT_CHG[3] and VSYNC_DET[7] */ + reg = VSYNC_DET | VID_FORMAT_CHG | VID_CLK_CHG; + writel(reg, &dp_regs->common_int_sta1); + + /* I_STRM__CLK detect : DE_CTL : Auto detect */ + reg &= ~DET_CTRL; + writel(reg, &dp_regs->sys_ctl1); + + return 0; +} + +void exynos_dp_config_video_slave_mode(struct edp_video_info *video_info) +{ + unsigned int reg; + + /* Video Slave mode setting */ + reg = readl(&dp_regs->func_en1); + reg &= ~(MASTER_VID_FUNC_EN_N|SLAVE_VID_FUNC_EN_N); + reg |= MASTER_VID_FUNC_EN_N; + writel(reg, &dp_regs->func_en1); + + /* Configure Interlaced for slave mode video */ + reg = readl(&dp_regs->video_ctl10); + reg &= ~INTERACE_SCAN_CFG; + reg |= (video_info->interlaced << INTERACE_SCAN_CFG_SHIFT); + writel(reg, &dp_regs->video_ctl10); + + /* Configure V sync polarity for slave mode video */ + reg = readl(&dp_regs->video_ctl10); + reg &= ~VSYNC_POLARITY_CFG; + reg |= (video_info->v_sync_polarity << V_S_POLARITY_CFG_SHIFT); + writel(reg, &dp_regs->video_ctl10); + + /* Configure H sync polarity for slave mode video */ + reg = readl(&dp_regs->video_ctl10); + reg &= ~HSYNC_POLARITY_CFG; + reg |= (video_info->h_sync_polarity << H_S_POLARITY_CFG_SHIFT); + writel(reg, &dp_regs->video_ctl10); + + /* Set video mode to slave mode */ + reg = AUDIO_MODE_SPDIF_MODE | VIDEO_MODE_SLAVE_MODE; + writel(reg, &dp_regs->soc_general_ctl); +} + +void exynos_dp_set_video_color_format(struct edp_video_info *video_info) +{ + unsigned int reg; + + /* Configure the input color depth, color space, dynamic range */ + reg = (video_info->dynamic_range << IN_D_RANGE_SHIFT) | + (video_info->color_depth << IN_BPC_SHIFT) | + (video_info->color_space << IN_COLOR_F_SHIFT); + writel(reg, &dp_regs->video_ctl2); + + /* Set Input Color YCbCr Coefficients to ITU601 or ITU709 */ + reg = readl(&dp_regs->video_ctl3); + reg &= ~IN_YC_COEFFI_MASK; + if (video_info->ycbcr_coeff) + reg |= IN_YC_COEFFI_ITU709; + else + reg |= IN_YC_COEFFI_ITU601; + writel(reg, &dp_regs->video_ctl3); +} + +int exynos_dp_config_video_bist(struct edp_device_info *edp_info) +{ + unsigned int reg; + unsigned int bist_type = 0; + struct edp_video_info video_info = edp_info->video_info; + + /* For master mode, you don't need to set the video format */ + if (video_info.master_mode == 0) { + writel(TOTAL_LINE_CFG_L(edp_info->disp_info.v_total), + &dp_regs->total_ln_cfg_l); + writel(TOTAL_LINE_CFG_H(edp_info->disp_info.v_total), + &dp_regs->total_ln_cfg_h); + writel(ACTIVE_LINE_CFG_L(edp_info->disp_info.v_res), + &dp_regs->active_ln_cfg_l); + writel(ACTIVE_LINE_CFG_H(edp_info->disp_info.v_res), + &dp_regs->active_ln_cfg_h); + writel(edp_info->disp_info.v_sync_width, + &dp_regs->vsw_cfg); + writel(edp_info->disp_info.v_back_porch, + &dp_regs->vbp_cfg); + writel(edp_info->disp_info.v_front_porch, + &dp_regs->vfp_cfg); + + writel(TOTAL_PIXEL_CFG_L(edp_info->disp_info.h_total), + &dp_regs->total_pix_cfg_l); + writel(TOTAL_PIXEL_CFG_H(edp_info->disp_info.h_total), + &dp_regs->total_pix_cfg_h); + writel(ACTIVE_PIXEL_CFG_L(edp_info->disp_info.h_res), + &dp_regs->active_pix_cfg_l); + writel(ACTIVE_PIXEL_CFG_H(edp_info->disp_info.h_res), + &dp_regs->active_pix_cfg_h); + writel(H_F_PORCH_CFG_L(edp_info->disp_info.h_front_porch), + &dp_regs->hfp_cfg_l); + writel(H_F_PORCH_CFG_H(edp_info->disp_info.h_front_porch), + &dp_regs->hfp_cfg_h); + writel(H_SYNC_PORCH_CFG_L(edp_info->disp_info.h_sync_width), + &dp_regs->hsw_cfg_l); + writel(H_SYNC_PORCH_CFG_H(edp_info->disp_info.h_sync_width), + &dp_regs->hsw_cfg_h); + writel(H_B_PORCH_CFG_L(edp_info->disp_info.h_back_porch), + &dp_regs->hbp_cfg_l); + writel(H_B_PORCH_CFG_H(edp_info->disp_info.h_back_porch), + &dp_regs->hbp_cfg_h); + + /* + * Set SLAVE_I_SCAN_CFG[2], VSYNC_P_CFG[1], + * HSYNC_P_CFG[0] properly + */ + reg = (video_info.interlaced << INTERACE_SCAN_CFG_SHIFT | + video_info.v_sync_polarity << V_S_POLARITY_CFG_SHIFT | + video_info.h_sync_polarity << H_S_POLARITY_CFG_SHIFT); + writel(reg, &dp_regs->video_ctl10); + } + + /* BIST color bar width set--set to each bar is 32 pixel width */ + switch (video_info.bist_pattern) { + case COLORBAR_32: + bist_type = BIST_WIDTH_BAR_32_PIXEL | + BIST_TYPE_COLOR_BAR; + break; + case COLORBAR_64: + bist_type = BIST_WIDTH_BAR_64_PIXEL | + BIST_TYPE_COLOR_BAR; + break; + case WHITE_GRAY_BALCKBAR_32: + bist_type = BIST_WIDTH_BAR_32_PIXEL | + BIST_TYPE_WHITE_GRAY_BLACK_BAR; + break; + case WHITE_GRAY_BALCKBAR_64: + bist_type = BIST_WIDTH_BAR_64_PIXEL | + BIST_TYPE_WHITE_GRAY_BLACK_BAR; + break; + case MOBILE_WHITEBAR_32: + bist_type = BIST_WIDTH_BAR_32_PIXEL | + BIST_TYPE_MOBILE_WHITE_BAR; + break; + case MOBILE_WHITEBAR_64: + bist_type = BIST_WIDTH_BAR_64_PIXEL | + BIST_TYPE_MOBILE_WHITE_BAR; + break; + default: + return -1; + } + + reg = bist_type; + writel(reg, &dp_regs->video_ctl4); + + return 0; +} + +unsigned int exynos_dp_is_slave_video_stream_clock_on(void) +{ + unsigned int reg; + + /* Update Video stream clk detect status */ + reg = readl(&dp_regs->sys_ctl1); + writel(reg, &dp_regs->sys_ctl1); + + reg = readl(&dp_regs->sys_ctl1); + + if (!(reg & DET_STA)) { + debug("DP Input stream clock not detected.\n"); + return -EIO; + } + + return EXYNOS_DP_SUCCESS; +} + +void exynos_dp_set_video_cr_mn(unsigned int type, unsigned int m_value, + unsigned int n_value) +{ + unsigned int reg; + + if (type == REGISTER_M) { + reg = readl(&dp_regs->sys_ctl4); + reg |= FIX_M_VID; + writel(reg, &dp_regs->sys_ctl4); + reg = M_VID0_CFG(m_value); + writel(reg, &dp_regs->m_vid0); + reg = M_VID1_CFG(m_value); + writel(reg, &dp_regs->m_vid1); + reg = M_VID2_CFG(m_value); + writel(reg, &dp_regs->m_vid2); + + reg = N_VID0_CFG(n_value); + writel(reg, &dp_regs->n_vid0); + reg = N_VID1_CFG(n_value); + writel(reg, &dp_regs->n_vid1); + reg = N_VID2_CFG(n_value); + writel(reg, &dp_regs->n_vid2); + } else { + reg = readl(&dp_regs->sys_ctl4); + reg &= ~FIX_M_VID; + writel(reg, &dp_regs->sys_ctl4); + } +} + +void exynos_dp_set_video_timing_mode(unsigned int type) +{ + unsigned int reg; + + reg = readl(&dp_regs->video_ctl10); + reg &= ~FORMAT_SEL; + + if (type != VIDEO_TIMING_FROM_CAPTURE) + reg |= FORMAT_SEL; + + writel(reg, &dp_regs->video_ctl10); +} + +void exynos_dp_enable_video_master(unsigned int enable) +{ + unsigned int reg; + + reg = readl(&dp_regs->soc_general_ctl); + if (enable) { + reg &= ~VIDEO_MODE_MASK; + reg |= VIDEO_MASTER_MODE_EN | VIDEO_MODE_MASTER_MODE; + } else { + reg &= ~VIDEO_MODE_MASK; + reg |= VIDEO_MODE_SLAVE_MODE; + } + + writel(reg, &dp_regs->soc_general_ctl); +} + +void exynos_dp_start_video(void) +{ + unsigned int reg; + + /* Enable Video input and disable Mute */ + reg = readl(&dp_regs->video_ctl1); + reg |= VIDEO_EN; + writel(reg, &dp_regs->video_ctl1); +} + +unsigned int exynos_dp_is_video_stream_on(void) +{ + unsigned int reg; + + /* Update STRM_VALID */ + reg = readl(&dp_regs->sys_ctl3); + writel(reg, &dp_regs->sys_ctl3); + + reg = readl(&dp_regs->sys_ctl3); + if (!(reg & STRM_VALID)) + return -EIO; + + return EXYNOS_DP_SUCCESS; +} diff --git a/drivers/video/exynos/exynos_dp_lowlevel.h b/drivers/video/exynos/exynos_dp_lowlevel.h new file mode 100644 index 0000000..8651681 --- /dev/null +++ b/drivers/video/exynos/exynos_dp_lowlevel.h @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2012 Samsung Electronics + * + * Author: Donghwa Lee + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef _EXYNOS_EDP_LOWLEVEL_H +#define _EXYNOS_EDP_LOWLEVEL_H + +void exynos_dp_enable_video_bist(unsigned int enable); +void exynos_dp_enable_video_mute(unsigned int enable); +void exynos_dp_reset(void); +void exynos_dp_enable_sw_func(unsigned int enable); +unsigned int exynos_dp_set_analog_power_down(unsigned int block, u32 enable); +unsigned int exynos_dp_get_pll_lock_status(void); +int exynos_dp_init_analog_func(void); +void exynos_dp_init_hpd(void); +void exynos_dp_init_aux(void); +void exynos_dp_config_interrupt(void); +unsigned int exynos_dp_get_plug_in_status(void); +unsigned int exynos_dp_detect_hpd(void); +unsigned int exynos_dp_start_aux_transaction(void); +unsigned int exynos_dp_write_byte_to_dpcd(unsigned int reg_addr, + unsigned char data); +unsigned int exynos_dp_read_byte_from_dpcd(unsigned int reg_addr, + unsigned char *data); +unsigned int exynos_dp_write_bytes_to_dpcd(unsigned int reg_addr, + unsigned int count, + unsigned char data[]); +unsigned int exynos_dp_read_bytes_from_dpcd( unsigned int reg_addr, + unsigned int count, + unsigned char data[]); +int exynos_dp_select_i2c_device( unsigned int device_addr, + unsigned int reg_addr); +int exynos_dp_read_byte_from_i2c(unsigned int device_addr, + unsigned int reg_addr, unsigned int *data); +int exynos_dp_read_bytes_from_i2c(unsigned int device_addr, + unsigned int reg_addr, unsigned int count, + unsigned char edid[]); +void exynos_dp_reset_macro(void); +void exynos_dp_set_link_bandwidth(unsigned char bwtype); +unsigned char exynos_dp_get_link_bandwidth(void); +void exynos_dp_set_lane_count(unsigned char count); +unsigned int exynos_dp_get_lane_count(void); +unsigned char exynos_dp_get_lanex_pre_emphasis(unsigned char lanecnt); +void exynos_dp_set_lane_pre_emphasis(unsigned int level, + unsigned char lanecnt); +void exynos_dp_set_lanex_pre_emphasis(unsigned char request_val, + unsigned char lanecnt); +void exynos_dp_set_training_pattern(unsigned int pattern); +void exynos_dp_enable_enhanced_mode(unsigned char enable); +void exynos_dp_enable_scrambling(unsigned int enable); +int exynos_dp_init_video(void); +void exynos_dp_config_video_slave_mode(struct edp_video_info *video_info); +void exynos_dp_set_video_color_format(struct edp_video_info *video_info); +int exynos_dp_config_video_bist(struct edp_device_info *edp_info); +unsigned int exynos_dp_is_slave_video_stream_clock_on(void); +void exynos_dp_set_video_cr_mn(unsigned int type, unsigned int m_value, + unsigned int n_value); +void exynos_dp_set_video_timing_mode(unsigned int type); +void exynos_dp_enable_video_master(unsigned int enable); +void exynos_dp_start_video(void); +unsigned int exynos_dp_is_video_stream_on(void); +void exynos_dp_set_base_addr(void); + +#endif /* _EXYNOS_DP_LOWLEVEL_H */ diff --git a/drivers/video/exynos/exynos_fb.c b/drivers/video/exynos/exynos_fb.c new file mode 100644 index 0000000..69edc3a --- /dev/null +++ b/drivers/video/exynos/exynos_fb.c @@ -0,0 +1,330 @@ +/* + * Copyright (C) 2012 Samsung Electronics + * + * Author: InKi Dae + * Author: Donghwa Lee + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "exynos_fb.h" + +DECLARE_GLOBAL_DATA_PTR; + +static unsigned int panel_width, panel_height; + +#if CONFIG_IS_ENABLED(OF_CONTROL) +vidinfo_t panel_info = { + /* + * Insert a value here so that we don't end up in the BSS + * Reference: drivers/video/tegra.c + */ + .vl_col = -1, +}; +#endif + +ushort *configuration_get_cmap(void) +{ +#if defined(CONFIG_LCD_LOGO) + return bmp_logo_palette; +#else + return NULL; +#endif +} + +static void exynos_lcd_init_mem(void *lcdbase, vidinfo_t *vid) +{ + unsigned long palette_size; + unsigned int fb_size; + + fb_size = vid->vl_row * vid->vl_col * (NBITS(vid->vl_bpix) >> 3); + + palette_size = NBITS(vid->vl_bpix) == 8 ? 256 : 16; + + exynos_fimd_lcd_init_mem((unsigned long)lcdbase, + (unsigned long)fb_size, palette_size); +} + +static void exynos_lcd_init(vidinfo_t *vid) +{ + exynos_fimd_lcd_init(vid); + + /* Enable flushing after LCD writes if requested */ + lcd_set_flush_dcache(1); +} + +__weak void exynos_cfg_lcd_gpio(void) +{ +} + +__weak void exynos_backlight_on(unsigned int onoff) +{ +} + +__weak void exynos_reset_lcd(void) +{ +} + +__weak void exynos_lcd_power_on(void) +{ +} + +__weak void exynos_cfg_ldo(void) +{ +} + +__weak void exynos_enable_ldo(unsigned int onoff) +{ +} + +__weak void exynos_backlight_reset(void) +{ +} + +__weak int exynos_lcd_misc_init(vidinfo_t *vid) +{ + return 0; +} + +static void lcd_panel_on(vidinfo_t *vid) +{ + struct gpio_desc pwm_out_gpio; + struct gpio_desc bl_en_gpio; + unsigned int node; + + udelay(vid->init_delay); + + exynos_backlight_reset(); + + exynos_cfg_lcd_gpio(); + + exynos_lcd_power_on(); + + udelay(vid->power_on_delay); + + if (vid->dp_enabled) + exynos_init_dp(); + + exynos_reset_lcd(); + + udelay(vid->reset_delay); + + exynos_backlight_on(1); + +#if CONFIG_IS_ENABLED(OF_CONTROL) + node = fdtdec_next_compatible(gd->fdt_blob, 0, + COMPAT_SAMSUNG_EXYNOS_FIMD); + if (node <= 0) { + debug("FIMD: Can't get device node for FIMD\n"); + return; + } + gpio_request_by_name_nodev(gd->fdt_blob, node, "samsung,pwm-out-gpio", + 0, &pwm_out_gpio, + GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE); + + gpio_request_by_name_nodev(gd->fdt_blob, node, "samsung,bl-en-gpio", 0, + &bl_en_gpio, + GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE); + +#endif + exynos_cfg_ldo(); + + exynos_enable_ldo(1); + + if (vid->mipi_enabled) + exynos_mipi_dsi_init(); +} + +#if CONFIG_IS_ENABLED(OF_CONTROL) +int exynos_lcd_early_init(const void *blob) +{ + unsigned int node; + node = fdtdec_next_compatible(blob, 0, COMPAT_SAMSUNG_EXYNOS_FIMD); + if (node <= 0) { + debug("exynos_fb: Can't get device node for fimd\n"); + return -ENODEV; + } + + panel_info.vl_col = fdtdec_get_int(blob, node, "samsung,vl-col", 0); + if (panel_info.vl_col == 0) { + debug("Can't get XRES\n"); + return -ENXIO; + } + + panel_info.vl_row = fdtdec_get_int(blob, node, "samsung,vl-row", 0); + if (panel_info.vl_row == 0) { + debug("Can't get YRES\n"); + return -ENXIO; + } + + panel_info.vl_width = fdtdec_get_int(blob, node, + "samsung,vl-width", 0); + + panel_info.vl_height = fdtdec_get_int(blob, node, + "samsung,vl-height", 0); + + panel_info.vl_freq = fdtdec_get_int(blob, node, "samsung,vl-freq", 0); + if (panel_info.vl_freq == 0) { + debug("Can't get refresh rate\n"); + return -ENXIO; + } + + if (fdtdec_get_bool(blob, node, "samsung,vl-clkp")) + panel_info.vl_clkp = CONFIG_SYS_LOW; + + if (fdtdec_get_bool(blob, node, "samsung,vl-oep")) + panel_info.vl_oep = CONFIG_SYS_LOW; + + if (fdtdec_get_bool(blob, node, "samsung,vl-hsp")) + panel_info.vl_hsp = CONFIG_SYS_LOW; + + if (fdtdec_get_bool(blob, node, "samsung,vl-vsp")) + panel_info.vl_vsp = CONFIG_SYS_LOW; + + if (fdtdec_get_bool(blob, node, "samsung,vl-dp")) + panel_info.vl_dp = CONFIG_SYS_LOW; + + panel_info.vl_bpix = fdtdec_get_int(blob, node, "samsung,vl-bpix", 0); + if (panel_info.vl_bpix == 0) { + debug("Can't get bits per pixel\n"); + return -ENXIO; + } + + panel_info.vl_hspw = fdtdec_get_int(blob, node, "samsung,vl-hspw", 0); + if (panel_info.vl_hspw == 0) { + debug("Can't get hsync width\n"); + return -ENXIO; + } + + panel_info.vl_hfpd = fdtdec_get_int(blob, node, "samsung,vl-hfpd", 0); + if (panel_info.vl_hfpd == 0) { + debug("Can't get right margin\n"); + return -ENXIO; + } + + panel_info.vl_hbpd = (u_char)fdtdec_get_int(blob, node, + "samsung,vl-hbpd", 0); + if (panel_info.vl_hbpd == 0) { + debug("Can't get left margin\n"); + return -ENXIO; + } + + panel_info.vl_vspw = (u_char)fdtdec_get_int(blob, node, + "samsung,vl-vspw", 0); + if (panel_info.vl_vspw == 0) { + debug("Can't get vsync width\n"); + return -ENXIO; + } + + panel_info.vl_vfpd = fdtdec_get_int(blob, node, + "samsung,vl-vfpd", 0); + if (panel_info.vl_vfpd == 0) { + debug("Can't get lower margin\n"); + return -ENXIO; + } + + panel_info.vl_vbpd = fdtdec_get_int(blob, node, "samsung,vl-vbpd", 0); + if (panel_info.vl_vbpd == 0) { + debug("Can't get upper margin\n"); + return -ENXIO; + } + + panel_info.vl_cmd_allow_len = fdtdec_get_int(blob, node, + "samsung,vl-cmd-allow-len", 0); + + panel_info.win_id = fdtdec_get_int(blob, node, "samsung,winid", 0); + panel_info.init_delay = fdtdec_get_int(blob, node, + "samsung,init-delay", 0); + panel_info.power_on_delay = fdtdec_get_int(blob, node, + "samsung,power-on-delay", 0); + panel_info.reset_delay = fdtdec_get_int(blob, node, + "samsung,reset-delay", 0); + panel_info.interface_mode = fdtdec_get_int(blob, node, + "samsung,interface-mode", 0); + panel_info.mipi_enabled = fdtdec_get_int(blob, node, + "samsung,mipi-enabled", 0); + panel_info.dp_enabled = fdtdec_get_int(blob, node, + "samsung,dp-enabled", 0); + panel_info.cs_setup = fdtdec_get_int(blob, node, + "samsung,cs-setup", 0); + panel_info.wr_setup = fdtdec_get_int(blob, node, + "samsung,wr-setup", 0); + panel_info.wr_act = fdtdec_get_int(blob, node, "samsung,wr-act", 0); + panel_info.wr_hold = fdtdec_get_int(blob, node, "samsung,wr-hold", 0); + + panel_info.logo_on = fdtdec_get_int(blob, node, "samsung,logo-on", 0); + if (panel_info.logo_on) { + panel_info.logo_width = fdtdec_get_int(blob, node, + "samsung,logo-width", 0); + panel_info.logo_height = fdtdec_get_int(blob, node, + "samsung,logo-height", 0); + panel_info.logo_addr = fdtdec_get_int(blob, node, + "samsung,logo-addr", 0); + } + + panel_info.rgb_mode = fdtdec_get_int(blob, node, + "samsung,rgb-mode", 0); + panel_info.pclk_name = fdtdec_get_int(blob, node, + "samsung,pclk-name", 0); + panel_info.sclk_div = fdtdec_get_int(blob, node, + "samsung,sclk-div", 0); + panel_info.dual_lcd_enabled = fdtdec_get_int(blob, node, + "samsung,dual-lcd-enabled", 0); + + return 0; +} +#endif + +void lcd_ctrl_init(void *lcdbase) +{ + set_system_display_ctrl(); + set_lcd_clk(); + +#if CONFIG_IS_ENABLED(OF_CONTROL) +#ifdef CONFIG_EXYNOS_MIPI_DSIM + exynos_init_dsim_platform_data(&panel_info); +#endif + exynos_lcd_misc_init(&panel_info); +#else + /* initialize parameters which is specific to panel. */ + init_panel_info(&panel_info); +#endif + + panel_width = panel_info.vl_width; + panel_height = panel_info.vl_height; + + exynos_lcd_init_mem(lcdbase, &panel_info); + + exynos_lcd_init(&panel_info); +} + +void lcd_enable(void) +{ + if (panel_info.logo_on) { + memset((void *) gd->fb_base, 0, panel_width * panel_height * + (NBITS(panel_info.vl_bpix) >> 3)); + } + + lcd_panel_on(&panel_info); +} + +/* dummy function */ +void lcd_setcolreg(ushort regno, ushort red, ushort green, ushort blue) +{ + return; +} diff --git a/drivers/video/exynos/exynos_fb.h b/drivers/video/exynos/exynos_fb.h new file mode 100644 index 0000000..2c2f94b --- /dev/null +++ b/drivers/video/exynos/exynos_fb.h @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2012 Samsung Electronics + * + * Author: InKi Dae + * Author: Donghwa Lee + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef _EXYNOS_FB_H_ +#define _EXYNOS_FB_H_ + +#include + +#define MAX_CLOCK (86 * 1000000) + +enum exynos_cpu_auto_cmd_rate { + DISABLE_AUTO_FRM, + PER_TWO_FRM, + PER_FOUR_FRM, + PER_SIX_FRM, + PER_EIGHT_FRM, + PER_TEN_FRM, + PER_TWELVE_FRM, + PER_FOURTEEN_FRM, + PER_SIXTEEN_FRM, + PER_EIGHTEEN_FRM, + PER_TWENTY_FRM, + PER_TWENTY_TWO_FRM, + PER_TWENTY_FOUR_FRM, + PER_TWENTY_SIX_FRM, + PER_TWENTY_EIGHT_FRM, + PER_THIRTY_FRM, +}; + +void exynos_fimd_lcd_init_mem(unsigned long screen_base, unsigned long fb_size, + unsigned long palette_size); +void exynos_fimd_lcd_init(vidinfo_t *vid); +unsigned long exynos_fimd_calc_fbsize(void); + +#endif diff --git a/drivers/video/exynos/exynos_fimd.c b/drivers/video/exynos/exynos_fimd.c new file mode 100644 index 0000000..ac001a8 --- /dev/null +++ b/drivers/video/exynos/exynos_fimd.c @@ -0,0 +1,409 @@ +/* + * Copyright (C) 2012 Samsung Electronics + * + * Author: InKi Dae + * Author: Donghwa Lee + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "exynos_fb.h" + +DECLARE_GLOBAL_DATA_PTR; + +static unsigned long *lcd_base_addr; +static vidinfo_t *pvid; +static struct exynos_fb *fimd_ctrl; + +void exynos_fimd_lcd_init_mem(u_long screen_base, u_long fb_size, + u_long palette_size) +{ + lcd_base_addr = (unsigned long *)screen_base; +} + +static void exynos_fimd_set_dualrgb(unsigned int enabled) +{ + unsigned int cfg = 0; + + if (enabled) { + cfg = EXYNOS_DUALRGB_BYPASS_DUAL | EXYNOS_DUALRGB_LINESPLIT | + EXYNOS_DUALRGB_VDEN_EN_ENABLE; + + /* in case of Line Split mode, MAIN_CNT doesn't neet to set. */ + cfg |= EXYNOS_DUALRGB_SUB_CNT(pvid->vl_col / 2) | + EXYNOS_DUALRGB_MAIN_CNT(0); + } + + writel(cfg, &fimd_ctrl->dualrgb); +} + +static void exynos_fimd_set_dp_clkcon(unsigned int enabled) +{ + unsigned int cfg = 0; + + if (enabled) + cfg = EXYNOS_DP_CLK_ENABLE; + + writel(cfg, &fimd_ctrl->dp_mie_clkcon); +} + +static void exynos_fimd_set_par(unsigned int win_id) +{ + unsigned int cfg = 0; + + /* set window control */ + cfg = readl((unsigned int)&fimd_ctrl->wincon0 + + EXYNOS_WINCON(win_id)); + + cfg &= ~(EXYNOS_WINCON_BITSWP_ENABLE | EXYNOS_WINCON_BYTESWP_ENABLE | + EXYNOS_WINCON_HAWSWP_ENABLE | EXYNOS_WINCON_WSWP_ENABLE | + EXYNOS_WINCON_BURSTLEN_MASK | EXYNOS_WINCON_BPPMODE_MASK | + EXYNOS_WINCON_INRGB_MASK | EXYNOS_WINCON_DATAPATH_MASK); + + /* DATAPATH is DMA */ + cfg |= EXYNOS_WINCON_DATAPATH_DMA; + + cfg |= EXYNOS_WINCON_HAWSWP_ENABLE; + + /* dma burst is 16 */ + cfg |= EXYNOS_WINCON_BURSTLEN_16WORD; + + switch (pvid->vl_bpix) { + case 4: + cfg |= EXYNOS_WINCON_BPPMODE_16BPP_565; + break; + default: + cfg |= EXYNOS_WINCON_BPPMODE_24BPP_888; + break; + } + + writel(cfg, (unsigned int)&fimd_ctrl->wincon0 + + EXYNOS_WINCON(win_id)); + + /* set window position to x=0, y=0*/ + cfg = EXYNOS_VIDOSD_LEFT_X(0) | EXYNOS_VIDOSD_TOP_Y(0); + writel(cfg, (unsigned int)&fimd_ctrl->vidosd0a + + EXYNOS_VIDOSD(win_id)); + + cfg = EXYNOS_VIDOSD_RIGHT_X(pvid->vl_col - 1) | + EXYNOS_VIDOSD_BOTTOM_Y(pvid->vl_row - 1) | + EXYNOS_VIDOSD_RIGHT_X_E(1) | + EXYNOS_VIDOSD_BOTTOM_Y_E(0); + + writel(cfg, (unsigned int)&fimd_ctrl->vidosd0b + + EXYNOS_VIDOSD(win_id)); + + /* set window size for window0*/ + cfg = EXYNOS_VIDOSD_SIZE(pvid->vl_col * pvid->vl_row); + writel(cfg, (unsigned int)&fimd_ctrl->vidosd0c + + EXYNOS_VIDOSD(win_id)); +} + +static void exynos_fimd_set_buffer_address(unsigned int win_id) +{ + unsigned long start_addr, end_addr; + + start_addr = (unsigned long)lcd_base_addr; + end_addr = start_addr + ((pvid->vl_col * (NBITS(pvid->vl_bpix) / 8)) * + pvid->vl_row); + + writel(start_addr, (unsigned int)&fimd_ctrl->vidw00add0b0 + + EXYNOS_BUFFER_OFFSET(win_id)); + writel(end_addr, (unsigned int)&fimd_ctrl->vidw00add1b0 + + EXYNOS_BUFFER_OFFSET(win_id)); +} + +static void exynos_fimd_set_clock(vidinfo_t *pvid) +{ + unsigned int cfg = 0, div = 0, remainder, remainder_div; + unsigned long pixel_clock; + unsigned long long src_clock; + + if (pvid->dual_lcd_enabled) { + pixel_clock = pvid->vl_freq * + (pvid->vl_hspw + pvid->vl_hfpd + + pvid->vl_hbpd + pvid->vl_col / 2) * + (pvid->vl_vspw + pvid->vl_vfpd + + pvid->vl_vbpd + pvid->vl_row); + } else if (pvid->interface_mode == FIMD_CPU_INTERFACE) { + pixel_clock = pvid->vl_freq * + pvid->vl_width * pvid->vl_height * + (pvid->cs_setup + pvid->wr_setup + + pvid->wr_act + pvid->wr_hold + 1); + } else { + pixel_clock = pvid->vl_freq * + (pvid->vl_hspw + pvid->vl_hfpd + + pvid->vl_hbpd + pvid->vl_col) * + (pvid->vl_vspw + pvid->vl_vfpd + + pvid->vl_vbpd + pvid->vl_row); + } + + cfg = readl(&fimd_ctrl->vidcon0); + cfg &= ~(EXYNOS_VIDCON0_CLKSEL_MASK | EXYNOS_VIDCON0_CLKVALUP_MASK | + EXYNOS_VIDCON0_CLKVAL_F(0xFF) | EXYNOS_VIDCON0_VCLKEN_MASK | + EXYNOS_VIDCON0_CLKDIR_MASK); + cfg |= (EXYNOS_VIDCON0_CLKSEL_SCLK | EXYNOS_VIDCON0_CLKVALUP_ALWAYS | + EXYNOS_VIDCON0_VCLKEN_NORMAL | EXYNOS_VIDCON0_CLKDIR_DIVIDED); + + src_clock = (unsigned long long) get_lcd_clk(); + + /* get quotient and remainder. */ + remainder = do_div(src_clock, pixel_clock); + div = src_clock; + + remainder *= 10; + remainder_div = remainder / pixel_clock; + + /* round about one places of decimals. */ + if (remainder_div >= 5) + div++; + + /* in case of dual lcd mode. */ + if (pvid->dual_lcd_enabled) + div--; + + cfg |= EXYNOS_VIDCON0_CLKVAL_F(div - 1); + writel(cfg, &fimd_ctrl->vidcon0); +} + +void exynos_set_trigger(void) +{ + unsigned int cfg = 0; + + cfg = readl(&fimd_ctrl->trigcon); + + cfg |= (EXYNOS_I80SOFT_TRIG_EN | EXYNOS_I80START_TRIG); + + writel(cfg, &fimd_ctrl->trigcon); +} + +int exynos_is_i80_frame_done(void) +{ + unsigned int cfg = 0; + int status; + + cfg = readl(&fimd_ctrl->trigcon); + + /* frame done func is valid only when TRIMODE[0] is set to 1. */ + status = (cfg & EXYNOS_I80STATUS_TRIG_DONE) == + EXYNOS_I80STATUS_TRIG_DONE; + + return status; +} + +static void exynos_fimd_lcd_on(void) +{ + unsigned int cfg = 0; + + /* display on */ + cfg = readl(&fimd_ctrl->vidcon0); + cfg |= (EXYNOS_VIDCON0_ENVID_ENABLE | EXYNOS_VIDCON0_ENVID_F_ENABLE); + writel(cfg, &fimd_ctrl->vidcon0); +} + +static void exynos_fimd_window_on(unsigned int win_id) +{ + unsigned int cfg = 0; + + /* enable window */ + cfg = readl((unsigned int)&fimd_ctrl->wincon0 + + EXYNOS_WINCON(win_id)); + cfg |= EXYNOS_WINCON_ENWIN_ENABLE; + writel(cfg, (unsigned int)&fimd_ctrl->wincon0 + + EXYNOS_WINCON(win_id)); + + cfg = readl(&fimd_ctrl->winshmap); + cfg |= EXYNOS_WINSHMAP_CH_ENABLE(win_id); + writel(cfg, &fimd_ctrl->winshmap); +} + +void exynos_fimd_lcd_off(void) +{ + unsigned int cfg = 0; + + cfg = readl(&fimd_ctrl->vidcon0); + cfg &= (EXYNOS_VIDCON0_ENVID_DISABLE | EXYNOS_VIDCON0_ENVID_F_DISABLE); + writel(cfg, &fimd_ctrl->vidcon0); +} + +void exynos_fimd_window_off(unsigned int win_id) +{ + unsigned int cfg = 0; + + cfg = readl((unsigned int)&fimd_ctrl->wincon0 + + EXYNOS_WINCON(win_id)); + cfg &= EXYNOS_WINCON_ENWIN_DISABLE; + writel(cfg, (unsigned int)&fimd_ctrl->wincon0 + + EXYNOS_WINCON(win_id)); + + cfg = readl(&fimd_ctrl->winshmap); + cfg &= ~EXYNOS_WINSHMAP_CH_DISABLE(win_id); + writel(cfg, &fimd_ctrl->winshmap); +} + +#if CONFIG_IS_ENABLED(OF_CONTROL) +/* +* The reset value for FIMD SYSMMU register MMU_CTRL is 3 +* on Exynos5420 and newer versions. +* This means FIMD SYSMMU is on by default on Exynos5420 +* and newer versions. +* Since in u-boot we don't use SYSMMU, we should disable +* those FIMD SYSMMU. +* Note that there are 2 SYSMMU for FIMD: m0 and m1. +* m0 handles windows 0 and 4, and m1 handles windows 1, 2 and 3. +* We disable both of them here. +*/ +void exynos_fimd_disable_sysmmu(void) +{ + u32 *sysmmufimd; + unsigned int node; + int node_list[2]; + int count; + int i; + + count = fdtdec_find_aliases_for_id(gd->fdt_blob, "fimd", + COMPAT_SAMSUNG_EXYNOS_SYSMMU, node_list, 2); + for (i = 0; i < count; i++) { + node = node_list[i]; + if (node <= 0) { + debug("Can't get device node for fimd sysmmu\n"); + return; + } + + sysmmufimd = (u32 *)fdtdec_get_addr(gd->fdt_blob, node, "reg"); + if (!sysmmufimd) { + debug("Can't get base address for sysmmu fimdm0"); + return; + } + + writel(0x0, sysmmufimd); + } +} +#endif + +void exynos_fimd_lcd_init(vidinfo_t *vid) +{ + unsigned int cfg = 0, rgb_mode; + unsigned int offset; +#if CONFIG_IS_ENABLED(OF_CONTROL) + unsigned int node; + + node = fdtdec_next_compatible(gd->fdt_blob, + 0, COMPAT_SAMSUNG_EXYNOS_FIMD); + if (node <= 0) + debug("exynos_fb: Can't get device node for fimd\n"); + + fimd_ctrl = (struct exynos_fb *)fdtdec_get_addr(gd->fdt_blob, + node, "reg"); + if (fimd_ctrl == NULL) + debug("Can't get the FIMD base address\n"); + + if (fdtdec_get_bool(gd->fdt_blob, node, "samsung,disable-sysmmu")) + exynos_fimd_disable_sysmmu(); + +#else + fimd_ctrl = (struct exynos_fb *)samsung_get_base_fimd(); +#endif + + offset = exynos_fimd_get_base_offset(); + + /* store panel info to global variable */ + pvid = vid; + + rgb_mode = vid->rgb_mode; + + if (vid->interface_mode == FIMD_RGB_INTERFACE) { + cfg |= EXYNOS_VIDCON0_VIDOUT_RGB; + writel(cfg, &fimd_ctrl->vidcon0); + + cfg = readl(&fimd_ctrl->vidcon2); + cfg &= ~(EXYNOS_VIDCON2_WB_MASK | + EXYNOS_VIDCON2_TVFORMATSEL_MASK | + EXYNOS_VIDCON2_TVFORMATSEL_YUV_MASK); + cfg |= EXYNOS_VIDCON2_WB_DISABLE; + writel(cfg, &fimd_ctrl->vidcon2); + + /* set polarity */ + cfg = 0; + if (!pvid->vl_clkp) + cfg |= EXYNOS_VIDCON1_IVCLK_RISING_EDGE; + if (!pvid->vl_hsp) + cfg |= EXYNOS_VIDCON1_IHSYNC_INVERT; + if (!pvid->vl_vsp) + cfg |= EXYNOS_VIDCON1_IVSYNC_INVERT; + if (!pvid->vl_dp) + cfg |= EXYNOS_VIDCON1_IVDEN_INVERT; + + writel(cfg, (unsigned int)&fimd_ctrl->vidcon1 + offset); + + /* set timing */ + cfg = EXYNOS_VIDTCON0_VFPD(pvid->vl_vfpd - 1); + cfg |= EXYNOS_VIDTCON0_VBPD(pvid->vl_vbpd - 1); + cfg |= EXYNOS_VIDTCON0_VSPW(pvid->vl_vspw - 1); + writel(cfg, (unsigned int)&fimd_ctrl->vidtcon0 + offset); + + cfg = EXYNOS_VIDTCON1_HFPD(pvid->vl_hfpd - 1); + cfg |= EXYNOS_VIDTCON1_HBPD(pvid->vl_hbpd - 1); + cfg |= EXYNOS_VIDTCON1_HSPW(pvid->vl_hspw - 1); + + writel(cfg, (unsigned int)&fimd_ctrl->vidtcon1 + offset); + + /* set lcd size */ + cfg = EXYNOS_VIDTCON2_HOZVAL(pvid->vl_col - 1) | + EXYNOS_VIDTCON2_LINEVAL(pvid->vl_row - 1) | + EXYNOS_VIDTCON2_HOZVAL_E(pvid->vl_col - 1) | + EXYNOS_VIDTCON2_LINEVAL_E(pvid->vl_row - 1); + + writel(cfg, (unsigned int)&fimd_ctrl->vidtcon2 + offset); + } + + /* set display mode */ + cfg = readl(&fimd_ctrl->vidcon0); + cfg &= ~EXYNOS_VIDCON0_PNRMODE_MASK; + cfg |= (rgb_mode << EXYNOS_VIDCON0_PNRMODE_SHIFT); + writel(cfg, &fimd_ctrl->vidcon0); + + /* set par */ + exynos_fimd_set_par(pvid->win_id); + + /* set memory address */ + exynos_fimd_set_buffer_address(pvid->win_id); + + /* set buffer size */ + cfg = EXYNOS_VIDADDR_PAGEWIDTH(pvid->vl_col * NBITS(pvid->vl_bpix) / 8) | + EXYNOS_VIDADDR_PAGEWIDTH_E(pvid->vl_col * NBITS(pvid->vl_bpix) / 8) | + EXYNOS_VIDADDR_OFFSIZE(0) | + EXYNOS_VIDADDR_OFFSIZE_E(0); + + writel(cfg, (unsigned int)&fimd_ctrl->vidw00add2 + + EXYNOS_BUFFER_SIZE(pvid->win_id)); + + /* set clock */ + exynos_fimd_set_clock(pvid); + + /* set rgb mode to dual lcd. */ + exynos_fimd_set_dualrgb(pvid->dual_lcd_enabled); + + /* display on */ + exynos_fimd_lcd_on(); + + /* window on */ + exynos_fimd_window_on(pvid->win_id); + + exynos_fimd_set_dp_clkcon(pvid->dp_enabled); +} + +unsigned long exynos_fimd_calc_fbsize(void) +{ + return pvid->vl_col * pvid->vl_row * (NBITS(pvid->vl_bpix) / 8); +} diff --git a/drivers/video/exynos/exynos_mipi_dsi.c b/drivers/video/exynos/exynos_mipi_dsi.c new file mode 100644 index 0000000..b597acc --- /dev/null +++ b/drivers/video/exynos/exynos_mipi_dsi.c @@ -0,0 +1,337 @@ +/* + * Copyright (C) 2012 Samsung Electronics + * + * Author: InKi Dae + * Author: Donghwa Lee + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "exynos_mipi_dsi_lowlevel.h" +#include "exynos_mipi_dsi_common.h" + +#define master_to_driver(a) (a->dsim_lcd_drv) +#define master_to_device(a) (a->dsim_lcd_dev) + +DECLARE_GLOBAL_DATA_PTR; + +static struct exynos_platform_mipi_dsim *dsim_pd; +#if CONFIG_IS_ENABLED(OF_CONTROL) +static struct mipi_dsim_config dsim_config_dt; +static struct exynos_platform_mipi_dsim dsim_platform_data_dt; +static struct mipi_dsim_lcd_device mipi_lcd_device_dt; +#endif + +struct mipi_dsim_ddi { + int bus_id; + struct list_head list; + struct mipi_dsim_lcd_device *dsim_lcd_dev; + struct mipi_dsim_lcd_driver *dsim_lcd_drv; +}; + +static LIST_HEAD(dsim_ddi_list); +static LIST_HEAD(dsim_lcd_dev_list); + +int exynos_mipi_dsi_register_lcd_device(struct mipi_dsim_lcd_device *lcd_dev) +{ + struct mipi_dsim_ddi *dsim_ddi; + + if (!lcd_dev) { + debug("mipi_dsim_lcd_device is NULL.\n"); + return -EFAULT; + } + + if (!lcd_dev->name) { + debug("dsim_lcd_device name is NULL.\n"); + return -EFAULT; + } + + dsim_ddi = kzalloc(sizeof(struct mipi_dsim_ddi), GFP_KERNEL); + if (!dsim_ddi) { + debug("failed to allocate dsim_ddi object.\n"); + return -EFAULT; + } + + dsim_ddi->dsim_lcd_dev = lcd_dev; + + list_add_tail(&dsim_ddi->list, &dsim_ddi_list); + + return 0; +} + +struct mipi_dsim_ddi + *exynos_mipi_dsi_find_lcd_device(struct mipi_dsim_lcd_driver *lcd_drv) +{ + struct mipi_dsim_ddi *dsim_ddi; + struct mipi_dsim_lcd_device *lcd_dev; + + list_for_each_entry(dsim_ddi, &dsim_ddi_list, list) { + lcd_dev = dsim_ddi->dsim_lcd_dev; + if (!lcd_dev) + continue; + + if (lcd_drv->id >= 0) { + if ((strcmp(lcd_drv->name, lcd_dev->name)) == 0 && + lcd_drv->id == lcd_dev->id) { + /** + * bus_id would be used to identify + * connected bus. + */ + dsim_ddi->bus_id = lcd_dev->bus_id; + + return dsim_ddi; + } + } else { + if ((strcmp(lcd_drv->name, lcd_dev->name)) == 0) { + /** + * bus_id would be used to identify + * connected bus. + */ + dsim_ddi->bus_id = lcd_dev->bus_id; + + return dsim_ddi; + } + } + + kfree(dsim_ddi); + list_del(&dsim_ddi_list); + } + + return NULL; +} + +int exynos_mipi_dsi_register_lcd_driver(struct mipi_dsim_lcd_driver *lcd_drv) +{ + struct mipi_dsim_ddi *dsim_ddi; + + if (!lcd_drv) { + debug("mipi_dsim_lcd_driver is NULL.\n"); + return -EFAULT; + } + + if (!lcd_drv->name) { + debug("dsim_lcd_driver name is NULL.\n"); + return -EFAULT; + } + + dsim_ddi = exynos_mipi_dsi_find_lcd_device(lcd_drv); + if (!dsim_ddi) { + debug("mipi_dsim_ddi object not found.\n"); + return -EFAULT; + } + + dsim_ddi->dsim_lcd_drv = lcd_drv; + + debug("registered panel driver(%s) to mipi-dsi driver.\n", + lcd_drv->name); + + return 0; + +} + +struct mipi_dsim_ddi + *exynos_mipi_dsi_bind_lcd_ddi(struct mipi_dsim_device *dsim, + const char *name) +{ + struct mipi_dsim_ddi *dsim_ddi; + struct mipi_dsim_lcd_driver *lcd_drv; + struct mipi_dsim_lcd_device *lcd_dev; + + list_for_each_entry(dsim_ddi, &dsim_ddi_list, list) { + lcd_drv = dsim_ddi->dsim_lcd_drv; + lcd_dev = dsim_ddi->dsim_lcd_dev; + if (!lcd_drv || !lcd_dev) + continue; + + debug("lcd_drv->id = %d, lcd_dev->id = %d\n", + lcd_drv->id, lcd_dev->id); + + if ((strcmp(lcd_drv->name, name) == 0)) { + lcd_dev->master = dsim; + + dsim->dsim_lcd_dev = lcd_dev; + dsim->dsim_lcd_drv = lcd_drv; + + return dsim_ddi; + } + } + + return NULL; +} + +/* define MIPI-DSI Master operations. */ +static struct mipi_dsim_master_ops master_ops = { + .cmd_write = exynos_mipi_dsi_wr_data, + .get_dsim_frame_done = exynos_mipi_dsi_get_frame_done_status, + .clear_dsim_frame_done = exynos_mipi_dsi_clear_frame_done, +}; + +int exynos_mipi_dsi_init(void) +{ + struct mipi_dsim_device *dsim; + struct mipi_dsim_config *dsim_config; + struct mipi_dsim_ddi *dsim_ddi; + + dsim = kzalloc(sizeof(struct mipi_dsim_device), GFP_KERNEL); + if (!dsim) { + debug("failed to allocate dsim object.\n"); + return -EFAULT; + } + + /* get mipi_dsim_config. */ + dsim_config = dsim_pd->dsim_config; + if (dsim_config == NULL) { + debug("failed to get dsim config data.\n"); + return -EFAULT; + } + + dsim->pd = dsim_pd; + dsim->dsim_config = dsim_config; + dsim->master_ops = &master_ops; + + /* bind lcd ddi matched with panel name. */ + dsim_ddi = exynos_mipi_dsi_bind_lcd_ddi(dsim, dsim_pd->lcd_panel_name); + if (!dsim_ddi) { + debug("mipi_dsim_ddi object not found.\n"); + return -ENOSYS; + } + if (dsim_pd->lcd_power) + dsim_pd->lcd_power(); + + if (dsim_pd->mipi_power) + dsim_pd->mipi_power(); + + /* phy_enable(unsigned int dev_index, unsigned int enable) */ + if (dsim_pd->phy_enable) + dsim_pd->phy_enable(0, 1); + + set_mipi_clk(); + + exynos_mipi_dsi_init_dsim(dsim); + exynos_mipi_dsi_init_link(dsim); + exynos_mipi_dsi_set_hs_enable(dsim); + + /* set display timing. */ + exynos_mipi_dsi_set_display_mode(dsim, dsim->dsim_config); + + /* initialize mipi-dsi client(lcd panel). */ + if (dsim_ddi->dsim_lcd_drv && dsim_ddi->dsim_lcd_drv->mipi_panel_init) { + dsim_ddi->dsim_lcd_drv->mipi_panel_init(dsim); + dsim_ddi->dsim_lcd_drv->mipi_display_on(dsim); + } + + debug("mipi-dsi driver(%s mode) has been probed.\n", + (dsim_config->e_interface == DSIM_COMMAND) ? + "CPU" : "RGB"); + + return 0; +} + +void exynos_set_dsim_platform_data(struct exynos_platform_mipi_dsim *pd) +{ + if (pd == NULL) { + debug("pd is NULL\n"); + return; + } + + dsim_pd = pd; +} + +#if CONFIG_IS_ENABLED(OF_CONTROL) +int exynos_dsim_config_parse_dt(const void *blob) +{ + int node; + + node = fdtdec_next_compatible(blob, 0, COMPAT_SAMSUNG_EXYNOS_MIPI_DSI); + if (node <= 0) { + printf("exynos_mipi_dsi: Can't get device node for mipi dsi\n"); + return -ENODEV; + } + + dsim_config_dt.e_interface = fdtdec_get_int(blob, node, + "samsung,dsim-config-e-interface", 0); + + dsim_config_dt.e_virtual_ch = fdtdec_get_int(blob, node, + "samsung,dsim-config-e-virtual-ch", 0); + + dsim_config_dt.e_pixel_format = fdtdec_get_int(blob, node, + "samsung,dsim-config-e-pixel-format", 0); + + dsim_config_dt.e_burst_mode = fdtdec_get_int(blob, node, + "samsung,dsim-config-e-burst-mode", 0); + + dsim_config_dt.e_no_data_lane = fdtdec_get_int(blob, node, + "samsung,dsim-config-e-no-data-lane", 0); + + dsim_config_dt.e_byte_clk = fdtdec_get_int(blob, node, + "samsung,dsim-config-e-byte-clk", 0); + + dsim_config_dt.hfp = fdtdec_get_int(blob, node, + "samsung,dsim-config-hfp", 0); + + dsim_config_dt.p = fdtdec_get_int(blob, node, + "samsung,dsim-config-p", 0); + dsim_config_dt.m = fdtdec_get_int(blob, node, + "samsung,dsim-config-m", 0); + dsim_config_dt.s = fdtdec_get_int(blob, node, + "samsung,dsim-config-s", 0); + + dsim_config_dt.pll_stable_time = fdtdec_get_int(blob, node, + "samsung,dsim-config-pll-stable-time", 0); + + dsim_config_dt.esc_clk = fdtdec_get_int(blob, node, + "samsung,dsim-config-esc-clk", 0); + + dsim_config_dt.stop_holding_cnt = fdtdec_get_int(blob, node, + "samsung,dsim-config-stop-holding-cnt", 0); + + dsim_config_dt.bta_timeout = fdtdec_get_int(blob, node, + "samsung,dsim-config-bta-timeout", 0); + + dsim_config_dt.rx_timeout = fdtdec_get_int(blob, node, + "samsung,dsim-config-rx-timeout", 0); + + mipi_lcd_device_dt.name = fdtdec_get_config_string(blob, + "samsung,dsim-device-name"); + + mipi_lcd_device_dt.id = fdtdec_get_int(blob, node, + "samsung,dsim-device-id", 0); + + mipi_lcd_device_dt.bus_id = fdtdec_get_int(blob, node, + "samsung,dsim-device-bus_id", 0); + + mipi_lcd_device_dt.reverse_panel = fdtdec_get_int(blob, node, + "samsung,dsim-device-reverse-panel", 0); + + return 0; +} + +void exynos_init_dsim_platform_data(vidinfo_t *vid) +{ + if (exynos_dsim_config_parse_dt(gd->fdt_blob)) + debug("Can't get proper dsim config.\n"); + + strcpy(dsim_platform_data_dt.lcd_panel_name, mipi_lcd_device_dt.name); + dsim_platform_data_dt.dsim_config = &dsim_config_dt; + dsim_platform_data_dt.mipi_power = mipi_power; + dsim_platform_data_dt.phy_enable = set_mipi_phy_ctrl; + dsim_platform_data_dt.lcd_panel_info = (void *)vid; + + mipi_lcd_device_dt.platform_data = (void *)&dsim_platform_data_dt; + exynos_mipi_dsi_register_lcd_device(&mipi_lcd_device_dt); + + dsim_pd = &dsim_platform_data_dt; +} +#endif diff --git a/drivers/video/exynos/exynos_mipi_dsi_common.c b/drivers/video/exynos/exynos_mipi_dsi_common.c new file mode 100644 index 0000000..925d515 --- /dev/null +++ b/drivers/video/exynos/exynos_mipi_dsi_common.c @@ -0,0 +1,620 @@ +/* + * Copyright (C) 2012 Samsung Electronics + * + * Author: InKi Dae + * Author: Donghwa Lee + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include + +#include "exynos_mipi_dsi_lowlevel.h" + +#define MHZ (1000 * 1000) +#define FIN_HZ (24 * MHZ) + +#define DFIN_PLL_MIN_HZ (6 * MHZ) +#define DFIN_PLL_MAX_HZ (12 * MHZ) + +#define DFVCO_MIN_HZ (500 * MHZ) +#define DFVCO_MAX_HZ (1000 * MHZ) + +#define TRY_GET_FIFO_TIMEOUT (5000 * 2) + +/* MIPI-DSIM status types. */ +enum { + DSIM_STATE_INIT, /* should be initialized. */ + DSIM_STATE_STOP, /* CPU and LCDC are LP mode. */ + DSIM_STATE_HSCLKEN, /* HS clock was enabled. */ + DSIM_STATE_ULPS +}; + +/* define DSI lane types. */ +enum { + DSIM_LANE_CLOCK = (1 << 0), + DSIM_LANE_DATA0 = (1 << 1), + DSIM_LANE_DATA1 = (1 << 2), + DSIM_LANE_DATA2 = (1 << 3), + DSIM_LANE_DATA3 = (1 << 4) +}; + +static unsigned int dpll_table[15] = { + 100, 120, 170, 220, 270, + 320, 390, 450, 510, 560, + 640, 690, 770, 870, 950 +}; + +static void exynos_mipi_dsi_long_data_wr(struct mipi_dsim_device *dsim, + const unsigned char *data0, unsigned int data1) +{ + unsigned int data_cnt = 0, payload = 0; + + /* in case that data count is more then 4 */ + for (data_cnt = 0; data_cnt < data1; data_cnt += 4) { + /* + * after sending 4bytes per one time, + * send remainder data less then 4. + */ + if ((data1 - data_cnt) < 4) { + if ((data1 - data_cnt) == 3) { + payload = data0[data_cnt] | + data0[data_cnt + 1] << 8 | + data0[data_cnt + 2] << 16; + debug("count = 3 payload = %x, %x %x %x\n", + payload, data0[data_cnt], + data0[data_cnt + 1], + data0[data_cnt + 2]); + } else if ((data1 - data_cnt) == 2) { + payload = data0[data_cnt] | + data0[data_cnt + 1] << 8; + debug("count = 2 payload = %x, %x %x\n", payload, + data0[data_cnt], data0[data_cnt + 1]); + } else if ((data1 - data_cnt) == 1) { + payload = data0[data_cnt]; + } + } else { + /* send 4bytes per one time. */ + payload = data0[data_cnt] | + data0[data_cnt + 1] << 8 | + data0[data_cnt + 2] << 16 | + data0[data_cnt + 3] << 24; + + debug("count = 4 payload = %x, %x %x %x %x\n", + payload, *(u8 *)(data0 + data_cnt), + data0[data_cnt + 1], + data0[data_cnt + 2], + data0[data_cnt + 3]); + } + exynos_mipi_dsi_wr_tx_data(dsim, payload); + } +} + +int exynos_mipi_dsi_wr_data(struct mipi_dsim_device *dsim, unsigned int data_id, + const unsigned char *data0, unsigned int data1) +{ + unsigned int timeout = TRY_GET_FIFO_TIMEOUT; + unsigned long delay_val, delay; + unsigned int check_rx_ack = 0; + + if (dsim->state == DSIM_STATE_ULPS) { + debug("state is ULPS.\n"); + + return -EINVAL; + } + + delay_val = MHZ / dsim->dsim_config->esc_clk; + delay = 10 * delay_val; + + mdelay(delay); + + /* only if transfer mode is LPDT, wait SFR becomes empty. */ + if (dsim->state == DSIM_STATE_STOP) { + while (!(exynos_mipi_dsi_get_fifo_state(dsim) & + SFR_HEADER_EMPTY)) { + if ((timeout--) > 0) + mdelay(1); + else { + debug("SRF header fifo is not empty.\n"); + return -EINVAL; + } + } + } + + switch (data_id) { + /* short packet types of packet types for command. */ + case MIPI_DSI_GENERIC_SHORT_WRITE_0_PARAM: + case MIPI_DSI_GENERIC_SHORT_WRITE_1_PARAM: + case MIPI_DSI_GENERIC_SHORT_WRITE_2_PARAM: + case MIPI_DSI_DCS_SHORT_WRITE: + case MIPI_DSI_DCS_SHORT_WRITE_PARAM: + case MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE: + debug("data0 = %x data1 = %x\n", + data0[0], data0[1]); + exynos_mipi_dsi_wr_tx_header(dsim, data_id, data0[0], data0[1]); + if (check_rx_ack) { + /* process response func should be implemented */ + return 0; + } else { + return -EINVAL; + } + + /* general command */ + case MIPI_DSI_COLOR_MODE_OFF: + case MIPI_DSI_COLOR_MODE_ON: + case MIPI_DSI_SHUTDOWN_PERIPHERAL: + case MIPI_DSI_TURN_ON_PERIPHERAL: + exynos_mipi_dsi_wr_tx_header(dsim, data_id, data0[0], data0[1]); + if (check_rx_ack) { + /* process response func should be implemented. */ + return 0; + } else { + return -EINVAL; + } + + /* packet types for video data */ + case MIPI_DSI_V_SYNC_START: + case MIPI_DSI_V_SYNC_END: + case MIPI_DSI_H_SYNC_START: + case MIPI_DSI_H_SYNC_END: + case MIPI_DSI_END_OF_TRANSMISSION: + return 0; + + /* short and response packet types for command */ + case MIPI_DSI_GENERIC_READ_REQUEST_0_PARAM: + case MIPI_DSI_GENERIC_READ_REQUEST_1_PARAM: + case MIPI_DSI_GENERIC_READ_REQUEST_2_PARAM: + case MIPI_DSI_DCS_READ: + exynos_mipi_dsi_clear_all_interrupt(dsim); + exynos_mipi_dsi_wr_tx_header(dsim, data_id, data0[0], data0[1]); + /* process response func should be implemented. */ + return 0; + + /* long packet type and null packet */ + case MIPI_DSI_NULL_PACKET: + case MIPI_DSI_BLANKING_PACKET: + return 0; + case MIPI_DSI_GENERIC_LONG_WRITE: + case MIPI_DSI_DCS_LONG_WRITE: + { + unsigned int payload = 0; + + /* if data count is less then 4, then send 3bytes data. */ + if (data1 < 4) { + payload = data0[0] | + data0[1] << 8 | + data0[2] << 16; + + exynos_mipi_dsi_wr_tx_data(dsim, payload); + + debug("count = %d payload = %x,%x %x %x\n", + data1, payload, data0[0], + data0[1], data0[2]); + } else { + /* in case that data count is more then 4 */ + exynos_mipi_dsi_long_data_wr(dsim, data0, data1); + } + + /* put data into header fifo */ + exynos_mipi_dsi_wr_tx_header(dsim, data_id, data1 & 0xff, + (data1 & 0xff00) >> 8); + + } + if (check_rx_ack) + /* process response func should be implemented. */ + return 0; + else + return -EINVAL; + + /* packet typo for video data */ + case MIPI_DSI_PACKED_PIXEL_STREAM_16: + case MIPI_DSI_PACKED_PIXEL_STREAM_18: + case MIPI_DSI_PIXEL_STREAM_3BYTE_18: + case MIPI_DSI_PACKED_PIXEL_STREAM_24: + if (check_rx_ack) { + /* process response func should be implemented. */ + return 0; + } else { + return -EINVAL; + } + default: + debug("data id %x is not supported current DSI spec.\n", + data_id); + + return -EINVAL; + } + + return 0; +} + +int exynos_mipi_dsi_pll_on(struct mipi_dsim_device *dsim, unsigned int enable) +{ + int sw_timeout; + + if (enable) { + sw_timeout = 1000; + + exynos_mipi_dsi_clear_interrupt(dsim); + exynos_mipi_dsi_enable_pll(dsim, 1); + while (1) { + sw_timeout--; + if (exynos_mipi_dsi_is_pll_stable(dsim)) + return 0; + if (sw_timeout == 0) + return -EINVAL; + } + } else + exynos_mipi_dsi_enable_pll(dsim, 0); + + return 0; +} + +unsigned long exynos_mipi_dsi_change_pll(struct mipi_dsim_device *dsim, + unsigned int pre_divider, unsigned int main_divider, + unsigned int scaler) +{ + unsigned long dfin_pll, dfvco, dpll_out; + unsigned int i, freq_band = 0xf; + + dfin_pll = (FIN_HZ / pre_divider); + + /****************************************************** + * Serial Clock(=ByteClk X 8) FreqBand[3:0] * + ****************************************************** + * ~ 99.99 MHz 0000 + * 100 ~ 119.99 MHz 0001 + * 120 ~ 159.99 MHz 0010 + * 160 ~ 199.99 MHz 0011 + * 200 ~ 239.99 MHz 0100 + * 140 ~ 319.99 MHz 0101 + * 320 ~ 389.99 MHz 0110 + * 390 ~ 449.99 MHz 0111 + * 450 ~ 509.99 MHz 1000 + * 510 ~ 559.99 MHz 1001 + * 560 ~ 639.99 MHz 1010 + * 640 ~ 689.99 MHz 1011 + * 690 ~ 769.99 MHz 1100 + * 770 ~ 869.99 MHz 1101 + * 870 ~ 949.99 MHz 1110 + * 950 ~ 1000 MHz 1111 + ******************************************************/ + if (dfin_pll < DFIN_PLL_MIN_HZ || dfin_pll > DFIN_PLL_MAX_HZ) { + debug("fin_pll range should be 6MHz ~ 12MHz\n"); + exynos_mipi_dsi_enable_afc(dsim, 0, 0); + } else { + if (dfin_pll < 7 * MHZ) + exynos_mipi_dsi_enable_afc(dsim, 1, 0x1); + else if (dfin_pll < 8 * MHZ) + exynos_mipi_dsi_enable_afc(dsim, 1, 0x0); + else if (dfin_pll < 9 * MHZ) + exynos_mipi_dsi_enable_afc(dsim, 1, 0x3); + else if (dfin_pll < 10 * MHZ) + exynos_mipi_dsi_enable_afc(dsim, 1, 0x2); + else if (dfin_pll < 11 * MHZ) + exynos_mipi_dsi_enable_afc(dsim, 1, 0x5); + else + exynos_mipi_dsi_enable_afc(dsim, 1, 0x4); + } + + dfvco = dfin_pll * main_divider; + debug("dfvco = %lu, dfin_pll = %lu, main_divider = %d\n", + dfvco, dfin_pll, main_divider); + if (dfvco < DFVCO_MIN_HZ || dfvco > DFVCO_MAX_HZ) + debug("fvco range should be 500MHz ~ 1000MHz\n"); + + dpll_out = dfvco / (1 << scaler); + debug("dpll_out = %lu, dfvco = %lu, scaler = %d\n", + dpll_out, dfvco, scaler); + + for (i = 0; i < ARRAY_SIZE(dpll_table); i++) { + if (dpll_out < dpll_table[i] * MHZ) { + freq_band = i; + break; + } + } + + debug("freq_band = %d\n", freq_band); + + exynos_mipi_dsi_pll_freq(dsim, pre_divider, main_divider, scaler); + + exynos_mipi_dsi_hs_zero_ctrl(dsim, 0); + exynos_mipi_dsi_prep_ctrl(dsim, 0); + + /* Freq Band */ + exynos_mipi_dsi_pll_freq_band(dsim, freq_band); + + /* Stable time */ + exynos_mipi_dsi_pll_stable_time(dsim, + dsim->dsim_config->pll_stable_time); + + /* Enable PLL */ + debug("FOUT of mipi dphy pll is %luMHz\n", + (dpll_out / MHZ)); + + return dpll_out; +} + +int exynos_mipi_dsi_set_clock(struct mipi_dsim_device *dsim, + unsigned int byte_clk_sel, unsigned int enable) +{ + unsigned int esc_div; + unsigned long esc_clk_error_rate; + unsigned long hs_clk = 0, byte_clk = 0, escape_clk = 0; + + if (enable) { + dsim->e_clk_src = byte_clk_sel; + + /* Escape mode clock and byte clock source */ + exynos_mipi_dsi_set_byte_clock_src(dsim, byte_clk_sel); + + /* DPHY, DSIM Link : D-PHY clock out */ + if (byte_clk_sel == DSIM_PLL_OUT_DIV8) { + hs_clk = exynos_mipi_dsi_change_pll(dsim, + dsim->dsim_config->p, dsim->dsim_config->m, + dsim->dsim_config->s); + if (hs_clk == 0) { + debug("failed to get hs clock.\n"); + return -EINVAL; + } + + byte_clk = hs_clk / 8; + exynos_mipi_dsi_enable_pll_bypass(dsim, 0); + exynos_mipi_dsi_pll_on(dsim, 1); + /* DPHY : D-PHY clock out, DSIM link : external clock out */ + } else if (byte_clk_sel == DSIM_EXT_CLK_DIV8) + debug("not support EXT CLK source for MIPI DSIM\n"); + else if (byte_clk_sel == DSIM_EXT_CLK_BYPASS) + debug("not support EXT CLK source for MIPI DSIM\n"); + + /* escape clock divider */ + esc_div = byte_clk / (dsim->dsim_config->esc_clk); + debug("esc_div = %d, byte_clk = %lu, esc_clk = %lu\n", + esc_div, byte_clk, dsim->dsim_config->esc_clk); + if ((byte_clk / esc_div) >= (20 * MHZ) || + (byte_clk / esc_div) > dsim->dsim_config->esc_clk) + esc_div += 1; + + escape_clk = byte_clk / esc_div; + debug("escape_clk = %lu, byte_clk = %lu, esc_div = %d\n", + escape_clk, byte_clk, esc_div); + + /* enable escape clock. */ + exynos_mipi_dsi_enable_byte_clock(dsim, 1); + + /* enable byte clk and escape clock */ + exynos_mipi_dsi_set_esc_clk_prs(dsim, 1, esc_div); + /* escape clock on lane */ + exynos_mipi_dsi_enable_esc_clk_on_lane(dsim, + (DSIM_LANE_CLOCK | dsim->data_lane), 1); + + debug("byte clock is %luMHz\n", + (byte_clk / MHZ)); + debug("escape clock that user's need is %lu\n", + (dsim->dsim_config->esc_clk / MHZ)); + debug("escape clock divider is %x\n", esc_div); + debug("escape clock is %luMHz\n", + ((byte_clk / esc_div) / MHZ)); + + if ((byte_clk / esc_div) > escape_clk) { + esc_clk_error_rate = escape_clk / + (byte_clk / esc_div); + debug("error rate is %lu over.\n", + (esc_clk_error_rate / 100)); + } else if ((byte_clk / esc_div) < (escape_clk)) { + esc_clk_error_rate = (byte_clk / esc_div) / + escape_clk; + debug("error rate is %lu under.\n", + (esc_clk_error_rate / 100)); + } + } else { + exynos_mipi_dsi_enable_esc_clk_on_lane(dsim, + (DSIM_LANE_CLOCK | dsim->data_lane), 0); + exynos_mipi_dsi_set_esc_clk_prs(dsim, 0, 0); + + /* disable escape clock. */ + exynos_mipi_dsi_enable_byte_clock(dsim, 0); + + if (byte_clk_sel == DSIM_PLL_OUT_DIV8) + exynos_mipi_dsi_pll_on(dsim, 0); + } + + return 0; +} + +int exynos_mipi_dsi_init_dsim(struct mipi_dsim_device *dsim) +{ + dsim->state = DSIM_STATE_INIT; + + switch (dsim->dsim_config->e_no_data_lane) { + case DSIM_DATA_LANE_1: + dsim->data_lane = DSIM_LANE_DATA0; + break; + case DSIM_DATA_LANE_2: + dsim->data_lane = DSIM_LANE_DATA0 | DSIM_LANE_DATA1; + break; + case DSIM_DATA_LANE_3: + dsim->data_lane = DSIM_LANE_DATA0 | DSIM_LANE_DATA1 | + DSIM_LANE_DATA2; + break; + case DSIM_DATA_LANE_4: + dsim->data_lane = DSIM_LANE_DATA0 | DSIM_LANE_DATA1 | + DSIM_LANE_DATA2 | DSIM_LANE_DATA3; + break; + default: + debug("data lane is invalid.\n"); + return -EINVAL; + }; + + exynos_mipi_dsi_sw_reset(dsim); + exynos_mipi_dsi_dp_dn_swap(dsim, 0); + + return 0; +} + +int exynos_mipi_dsi_enable_frame_done_int(struct mipi_dsim_device *dsim, + unsigned int enable) +{ + /* enable only frame done interrupt */ + exynos_mipi_dsi_set_interrupt_mask(dsim, INTMSK_FRAME_DONE, enable); + + return 0; +} + +static void convert_to_fb_videomode(struct fb_videomode *mode1, + vidinfo_t *mode2) +{ + mode1->xres = mode2->vl_width; + mode1->yres = mode2->vl_height; + mode1->upper_margin = mode2->vl_vfpd; + mode1->lower_margin = mode2->vl_vbpd; + mode1->left_margin = mode2->vl_hfpd; + mode1->right_margin = mode2->vl_hbpd; + mode1->vsync_len = mode2->vl_vspw; + mode1->hsync_len = mode2->vl_hspw; +} + +int exynos_mipi_dsi_set_display_mode(struct mipi_dsim_device *dsim, + struct mipi_dsim_config *dsim_config) +{ + struct exynos_platform_mipi_dsim *dsim_pd; + struct fb_videomode lcd_video; + vidinfo_t *vid; + + dsim_pd = (struct exynos_platform_mipi_dsim *)dsim->pd; + vid = (vidinfo_t *)dsim_pd->lcd_panel_info; + + convert_to_fb_videomode(&lcd_video, vid); + + /* in case of VIDEO MODE (RGB INTERFACE), it sets polarities. */ + if (dsim->dsim_config->e_interface == (u32) DSIM_VIDEO) { + if (dsim->dsim_config->auto_vertical_cnt == 0) { + exynos_mipi_dsi_set_main_disp_vporch(dsim, + vid->vl_cmd_allow_len, + lcd_video.upper_margin, + lcd_video.lower_margin); + exynos_mipi_dsi_set_main_disp_hporch(dsim, + lcd_video.left_margin, + lcd_video.right_margin); + exynos_mipi_dsi_set_main_disp_sync_area(dsim, + lcd_video.vsync_len, + lcd_video.hsync_len); + } + } + + exynos_mipi_dsi_set_main_disp_resol(dsim, lcd_video.xres, + lcd_video.yres); + + exynos_mipi_dsi_display_config(dsim, dsim->dsim_config); + + debug("lcd panel ==> width = %d, height = %d\n", + lcd_video.xres, lcd_video.yres); + + return 0; +} + +int exynos_mipi_dsi_init_link(struct mipi_dsim_device *dsim) +{ + unsigned int time_out = 100; + + switch (dsim->state) { + case DSIM_STATE_INIT: + exynos_mipi_dsi_init_fifo_pointer(dsim, 0x1f); + + /* dsi configuration */ + exynos_mipi_dsi_init_config(dsim); + exynos_mipi_dsi_enable_lane(dsim, DSIM_LANE_CLOCK, 1); + exynos_mipi_dsi_enable_lane(dsim, dsim->data_lane, 1); + + /* set clock configuration */ + exynos_mipi_dsi_set_clock(dsim, + dsim->dsim_config->e_byte_clk, 1); + + /* check clock and data lane state are stop state */ + while (!(exynos_mipi_dsi_is_lane_state(dsim))) { + time_out--; + if (time_out == 0) { + debug("DSI Master is not stop state.\n"); + debug("Check initialization process\n"); + + return -EINVAL; + } + } + + dsim->state = DSIM_STATE_STOP; + + /* BTA sequence counters */ + exynos_mipi_dsi_set_stop_state_counter(dsim, + dsim->dsim_config->stop_holding_cnt); + exynos_mipi_dsi_set_bta_timeout(dsim, + dsim->dsim_config->bta_timeout); + exynos_mipi_dsi_set_lpdr_timeout(dsim, + dsim->dsim_config->rx_timeout); + + return 0; + default: + debug("DSI Master is already init.\n"); + return 0; + } + + return 0; +} + +int exynos_mipi_dsi_set_hs_enable(struct mipi_dsim_device *dsim) +{ + if (dsim->state == DSIM_STATE_STOP) { + if (dsim->e_clk_src != DSIM_EXT_CLK_BYPASS) { + dsim->state = DSIM_STATE_HSCLKEN; + + /* set LCDC and CPU transfer mode to HS. */ + exynos_mipi_dsi_set_lcdc_transfer_mode(dsim, 0); + exynos_mipi_dsi_set_cpu_transfer_mode(dsim, 0); + + exynos_mipi_dsi_enable_hs_clock(dsim, 1); + + return 0; + } else + debug("clock source is external bypass.\n"); + } else + debug("DSIM is not stop state.\n"); + + return 0; +} + +int exynos_mipi_dsi_set_data_transfer_mode(struct mipi_dsim_device *dsim, + unsigned int mode) +{ + if (mode) { + if (dsim->state != DSIM_STATE_HSCLKEN) { + debug("HS Clock lane is not enabled.\n"); + return -EINVAL; + } + + exynos_mipi_dsi_set_lcdc_transfer_mode(dsim, 0); + } else { + if (dsim->state == DSIM_STATE_INIT || dsim->state == + DSIM_STATE_ULPS) { + debug("DSI Master is not STOP or HSDT state.\n"); + return -EINVAL; + } + + exynos_mipi_dsi_set_cpu_transfer_mode(dsim, 0); + } + + return 0; +} + +int exynos_mipi_dsi_get_frame_done_status(struct mipi_dsim_device *dsim) +{ + return _exynos_mipi_dsi_get_frame_done_status(dsim); +} + +int exynos_mipi_dsi_clear_frame_done(struct mipi_dsim_device *dsim) +{ + _exynos_mipi_dsi_clear_frame_done(dsim); + + return 0; +} diff --git a/drivers/video/exynos/exynos_mipi_dsi_common.h b/drivers/video/exynos/exynos_mipi_dsi_common.h new file mode 100644 index 0000000..98eb78e --- /dev/null +++ b/drivers/video/exynos/exynos_mipi_dsi_common.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2012 Samsung Electronics + * + * Author: InKi Dae + * Author: Donghwa Lee + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include + +#ifndef _EXYNOS_MIPI_DSI_COMMON_H +#define _EXYNOS_MIPI_DSI_COMMON_H + +int exynos_mipi_dsi_wr_data(struct mipi_dsim_device *dsim, unsigned int data_id, + const unsigned char *data0, unsigned int data1); +int exynos_mipi_dsi_pll_on(struct mipi_dsim_device *dsim, unsigned int enable); +unsigned long exynos_mipi_dsi_change_pll(struct mipi_dsim_device *dsim, + unsigned int pre_divider, unsigned int main_divider, + unsigned int scaler); +int exynos_mipi_dsi_set_clock(struct mipi_dsim_device *dsim, + unsigned int byte_clk_sel, unsigned int enable); +int exynos_mipi_dsi_init_dsim(struct mipi_dsim_device *dsim); +int exynos_mipi_dsi_set_display_mode(struct mipi_dsim_device *dsim, + struct mipi_dsim_config *dsim_info); +int exynos_mipi_dsi_init_link(struct mipi_dsim_device *dsim); +int exynos_mipi_dsi_set_hs_enable(struct mipi_dsim_device *dsim); +int exynos_mipi_dsi_set_data_transfer_mode(struct mipi_dsim_device *dsim, + unsigned int mode); +int exynos_mipi_dsi_enable_frame_done_int(struct mipi_dsim_device *dsim, + unsigned int enable); +int exynos_mipi_dsi_get_frame_done_status(struct mipi_dsim_device *dsim); +int exynos_mipi_dsi_clear_frame_done(struct mipi_dsim_device *dsim); + +#endif /* _EXYNOS_MIPI_DSI_COMMON_H */ diff --git a/drivers/video/exynos/exynos_mipi_dsi_lowlevel.c b/drivers/video/exynos/exynos_mipi_dsi_lowlevel.c new file mode 100644 index 0000000..fcfdc8d --- /dev/null +++ b/drivers/video/exynos/exynos_mipi_dsi_lowlevel.c @@ -0,0 +1,639 @@ +/* + * Copyright (C) 2012 Samsung Electronics + * + * Author: InKi Dae + * Author: Donghwa Lee + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include + +#include "exynos_mipi_dsi_lowlevel.h" +#include "exynos_mipi_dsi_common.h" + +void exynos_mipi_dsi_func_reset(struct mipi_dsim_device *dsim) +{ + unsigned int reg; + + struct exynos_mipi_dsim *mipi_dsim = + (struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim(); + + reg = readl(&mipi_dsim->swrst); + + reg |= DSIM_FUNCRST; + + writel(reg, &mipi_dsim->swrst); +} + +void exynos_mipi_dsi_sw_reset(struct mipi_dsim_device *dsim) +{ + unsigned int reg = 0; + + struct exynos_mipi_dsim *mipi_dsim = + (struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim(); + + reg = readl(&mipi_dsim->swrst); + + reg |= DSIM_SWRST; + reg |= DSIM_FUNCRST; + + writel(reg, &mipi_dsim->swrst); +} + +void exynos_mipi_dsi_sw_release(struct mipi_dsim_device *dsim) +{ + struct exynos_mipi_dsim *mipi_dsim = + (struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim(); + unsigned int reg = readl(&mipi_dsim->intsrc); + + reg |= INTSRC_SWRST_RELEASE; + + writel(reg, &mipi_dsim->intsrc); +} + +void exynos_mipi_dsi_set_interrupt_mask(struct mipi_dsim_device *dsim, + unsigned int mode, unsigned int mask) +{ + struct exynos_mipi_dsim *mipi_dsim = + (struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim(); + unsigned int reg = readl(&mipi_dsim->intmsk); + + if (mask) + reg |= mode; + else + reg &= ~mode; + + writel(reg, &mipi_dsim->intmsk); +} + +void exynos_mipi_dsi_init_fifo_pointer(struct mipi_dsim_device *dsim, + unsigned int cfg) +{ + unsigned int reg; + struct exynos_mipi_dsim *mipi_dsim = + (struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim(); + + reg = readl(&mipi_dsim->fifoctrl); + + writel(reg & ~(cfg), &mipi_dsim->fifoctrl); + udelay(10 * 1000); + reg |= cfg; + + writel(reg, &mipi_dsim->fifoctrl); +} + +/* + * this function set PLL P, M and S value in D-PHY + */ +void exynos_mipi_dsi_set_phy_tunning(struct mipi_dsim_device *dsim, + unsigned int value) +{ + struct exynos_mipi_dsim *mipi_dsim = + (struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim(); + + writel(DSIM_AFC_CTL(value), &mipi_dsim->phyacchr); +} + +void exynos_mipi_dsi_set_main_disp_resol(struct mipi_dsim_device *dsim, + unsigned int width_resol, unsigned int height_resol) +{ + unsigned int reg; + struct exynos_mipi_dsim *mipi_dsim = + (struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim(); + + /* standby should be set after configuration so set to not ready*/ + reg = (readl(&mipi_dsim->mdresol)) & ~(DSIM_MAIN_STAND_BY); + writel(reg, &mipi_dsim->mdresol); + + /* reset resolution */ + reg &= ~(DSIM_MAIN_VRESOL(0x7ff) | DSIM_MAIN_HRESOL(0x7ff)); + reg |= DSIM_MAIN_VRESOL(height_resol) | DSIM_MAIN_HRESOL(width_resol); + + reg |= DSIM_MAIN_STAND_BY; + writel(reg, &mipi_dsim->mdresol); +} + +void exynos_mipi_dsi_set_main_disp_vporch(struct mipi_dsim_device *dsim, + unsigned int cmd_allow, unsigned int vfront, unsigned int vback) +{ + unsigned int reg; + struct exynos_mipi_dsim *mipi_dsim = + (struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim(); + + reg = (readl(&mipi_dsim->mvporch)) & + ~((DSIM_CMD_ALLOW_MASK) | (DSIM_STABLE_VFP_MASK) | + (DSIM_MAIN_VBP_MASK)); + + reg |= ((cmd_allow & 0xf) << DSIM_CMD_ALLOW_SHIFT) | + ((vfront & 0x7ff) << DSIM_STABLE_VFP_SHIFT) | + ((vback & 0x7ff) << DSIM_MAIN_VBP_SHIFT); + + writel(reg, &mipi_dsim->mvporch); +} + +void exynos_mipi_dsi_set_main_disp_hporch(struct mipi_dsim_device *dsim, + unsigned int front, unsigned int back) +{ + unsigned int reg; + struct exynos_mipi_dsim *mipi_dsim = + (struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim(); + + reg = (readl(&mipi_dsim->mhporch)) & + ~((DSIM_MAIN_HFP_MASK) | (DSIM_MAIN_HBP_MASK)); + + reg |= (front << DSIM_MAIN_HFP_SHIFT) | (back << DSIM_MAIN_HBP_SHIFT); + + writel(reg, &mipi_dsim->mhporch); +} + +void exynos_mipi_dsi_set_main_disp_sync_area(struct mipi_dsim_device *dsim, + unsigned int vert, unsigned int hori) +{ + unsigned int reg; + struct exynos_mipi_dsim *mipi_dsim = + (struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim(); + + reg = (readl(&mipi_dsim->msync)) & + ~((DSIM_MAIN_VSA_MASK) | (DSIM_MAIN_HSA_MASK)); + + reg |= ((vert & 0x3ff) << DSIM_MAIN_VSA_SHIFT) | + (hori << DSIM_MAIN_HSA_SHIFT); + + writel(reg, &mipi_dsim->msync); +} + +void exynos_mipi_dsi_set_sub_disp_resol(struct mipi_dsim_device *dsim, + unsigned int vert, unsigned int hori) +{ + unsigned int reg; + struct exynos_mipi_dsim *mipi_dsim = + (struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim(); + + reg = (readl(&mipi_dsim->sdresol)) & + ~(DSIM_SUB_STANDY_MASK); + + writel(reg, &mipi_dsim->sdresol); + + reg &= ~(DSIM_SUB_VRESOL_MASK) | ~(DSIM_SUB_HRESOL_MASK); + reg |= ((vert & 0x7ff) << DSIM_SUB_VRESOL_SHIFT) | + ((hori & 0x7ff) << DSIM_SUB_HRESOL_SHIFT); + writel(reg, &mipi_dsim->sdresol); + + /* DSIM STANDBY */ + reg |= (1 << DSIM_SUB_STANDY_SHIFT); + writel(reg, &mipi_dsim->sdresol); +} + +void exynos_mipi_dsi_init_config(struct mipi_dsim_device *dsim) +{ + struct mipi_dsim_config *dsim_config = dsim->dsim_config; + struct exynos_mipi_dsim *mipi_dsim = + (struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim(); + unsigned int cfg = (readl(&mipi_dsim->config)) & + ~((1 << DSIM_EOT_PACKET_SHIFT) | + (0x1f << DSIM_HSA_MODE_SHIFT) | + (0x3 << DSIM_NUM_OF_DATALANE_SHIFT)); + + cfg |= (dsim_config->auto_flush << DSIM_AUTO_FLUSH_SHIFT) | + (dsim_config->eot_disable << DSIM_EOT_PACKET_SHIFT) | + (dsim_config->auto_vertical_cnt << DSIM_AUTO_MODE_SHIFT) | + (dsim_config->hse << DSIM_HSE_MODE_SHIFT) | + (dsim_config->hfp << DSIM_HFP_MODE_SHIFT) | + (dsim_config->hbp << DSIM_HBP_MODE_SHIFT) | + (dsim_config->hsa << DSIM_HSA_MODE_SHIFT) | + (dsim_config->e_no_data_lane << DSIM_NUM_OF_DATALANE_SHIFT); + + writel(cfg, &mipi_dsim->config); +} + +void exynos_mipi_dsi_display_config(struct mipi_dsim_device *dsim, + struct mipi_dsim_config *dsim_config) +{ + struct exynos_mipi_dsim *mipi_dsim = + (struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim(); + + u32 reg = (readl(&mipi_dsim->config)) & + ~((0x3 << DSIM_BURST_MODE_SHIFT) | (1 << DSIM_VIDEO_MODE_SHIFT) + | (0x3 << DSIM_MAINVC_SHIFT) | (0x7 << DSIM_MAINPIX_SHIFT) + | (0x3 << DSIM_SUBVC_SHIFT) | (0x7 << DSIM_SUBPIX_SHIFT)); + + if (dsim_config->e_interface == DSIM_VIDEO) + reg |= (1 << DSIM_VIDEO_MODE_SHIFT); + else if (dsim_config->e_interface == DSIM_COMMAND) + reg &= ~(1 << DSIM_VIDEO_MODE_SHIFT); + else { + printf("unknown lcd type.\n"); + return; + } + + /* main lcd */ + reg |= ((u8) (dsim_config->e_burst_mode) & 0x3) << DSIM_BURST_MODE_SHIFT + | ((u8) (dsim_config->e_virtual_ch) & 0x3) << DSIM_MAINVC_SHIFT + | ((u8) (dsim_config->e_pixel_format) & 0x7) << DSIM_MAINPIX_SHIFT; + + writel(reg, &mipi_dsim->config); +} + +void exynos_mipi_dsi_enable_lane(struct mipi_dsim_device *dsim, + unsigned int lane, unsigned int enable) +{ + unsigned int reg; + struct exynos_mipi_dsim *mipi_dsim = + (struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim(); + + reg = readl(&mipi_dsim->config); + + if (enable) + reg |= DSIM_LANE_ENx(lane); + else + reg &= ~DSIM_LANE_ENx(lane); + + writel(reg, &mipi_dsim->config); +} + +void exynos_mipi_dsi_set_data_lane_number(struct mipi_dsim_device *dsim, + unsigned int count) +{ + unsigned int cfg; + struct exynos_mipi_dsim *mipi_dsim = + (struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim(); + + /* get the data lane number. */ + cfg = DSIM_NUM_OF_DATA_LANE(count); + + writel(cfg, &mipi_dsim->config); +} + +void exynos_mipi_dsi_enable_afc(struct mipi_dsim_device *dsim, + unsigned int enable, unsigned int afc_code) +{ + struct exynos_mipi_dsim *mipi_dsim = + (struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim(); + unsigned int reg = readl(&mipi_dsim->phyacchr); + + reg = 0; + + if (enable) { + reg |= DSIM_AFC_EN; + reg &= ~(0x7 << DSIM_AFC_CTL_SHIFT); + reg |= DSIM_AFC_CTL(afc_code); + } else + reg &= ~DSIM_AFC_EN; + + writel(reg, &mipi_dsim->phyacchr); +} + +void exynos_mipi_dsi_enable_pll_bypass(struct mipi_dsim_device *dsim, + unsigned int enable) +{ + struct exynos_mipi_dsim *mipi_dsim = + (struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim(); + unsigned int reg = (readl(&mipi_dsim->clkctrl)) & + ~(DSIM_PLL_BYPASS_EXTERNAL); + + reg |= enable << DSIM_PLL_BYPASS_SHIFT; + + writel(reg, &mipi_dsim->clkctrl); +} + +void exynos_mipi_dsi_pll_freq_band(struct mipi_dsim_device *dsim, + unsigned int freq_band) +{ + struct exynos_mipi_dsim *mipi_dsim = + (struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim(); + unsigned int reg = (readl(&mipi_dsim->pllctrl)) & + ~(0x1f << DSIM_FREQ_BAND_SHIFT); + + reg |= ((freq_band & 0x1f) << DSIM_FREQ_BAND_SHIFT); + + writel(reg, &mipi_dsim->pllctrl); +} + +void exynos_mipi_dsi_pll_freq(struct mipi_dsim_device *dsim, + unsigned int pre_divider, unsigned int main_divider, + unsigned int scaler) +{ + struct exynos_mipi_dsim *mipi_dsim = + (struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim(); + unsigned int reg = (readl(&mipi_dsim->pllctrl)) & + ~(0x7ffff << 1); + + reg |= ((pre_divider & 0x3f) << DSIM_PREDIV_SHIFT) | + ((main_divider & 0x1ff) << DSIM_MAIN_SHIFT) | + ((scaler & 0x7) << DSIM_SCALER_SHIFT); + + writel(reg, &mipi_dsim->pllctrl); +} + +void exynos_mipi_dsi_pll_stable_time(struct mipi_dsim_device *dsim, + unsigned int lock_time) +{ + struct exynos_mipi_dsim *mipi_dsim = + (struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim(); + + writel(lock_time, &mipi_dsim->plltmr); +} + +void exynos_mipi_dsi_enable_pll(struct mipi_dsim_device *dsim, + unsigned int enable) +{ + struct exynos_mipi_dsim *mipi_dsim = + (struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim(); + unsigned int reg = (readl(&mipi_dsim->pllctrl)) & + ~(0x1 << DSIM_PLL_EN_SHIFT); + + reg |= ((enable & 0x1) << DSIM_PLL_EN_SHIFT); + + writel(reg, &mipi_dsim->pllctrl); +} + +void exynos_mipi_dsi_set_byte_clock_src(struct mipi_dsim_device *dsim, + unsigned int src) +{ + struct exynos_mipi_dsim *mipi_dsim = + (struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim(); + unsigned int reg = (readl(&mipi_dsim->clkctrl)) & + ~(0x3 << DSIM_BYTE_CLK_SRC_SHIFT); + + reg |= ((unsigned int) src) << DSIM_BYTE_CLK_SRC_SHIFT; + + writel(reg, &mipi_dsim->clkctrl); +} + +void exynos_mipi_dsi_enable_byte_clock(struct mipi_dsim_device *dsim, + unsigned int enable) +{ + struct exynos_mipi_dsim *mipi_dsim = + (struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim(); + unsigned int reg = (readl(&mipi_dsim->clkctrl)) & + ~(1 << DSIM_BYTE_CLKEN_SHIFT); + + reg |= enable << DSIM_BYTE_CLKEN_SHIFT; + + writel(reg, &mipi_dsim->clkctrl); +} + +void exynos_mipi_dsi_set_esc_clk_prs(struct mipi_dsim_device *dsim, + unsigned int enable, unsigned int prs_val) +{ + struct exynos_mipi_dsim *mipi_dsim = + (struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim(); + unsigned int reg = (readl(&mipi_dsim->clkctrl)) & + ~((1 << DSIM_ESC_CLKEN_SHIFT) | (0xffff)); + + reg |= enable << DSIM_ESC_CLKEN_SHIFT; + if (enable) + reg |= prs_val; + + writel(reg, &mipi_dsim->clkctrl); +} + +void exynos_mipi_dsi_enable_esc_clk_on_lane(struct mipi_dsim_device *dsim, + unsigned int lane_sel, unsigned int enable) +{ + struct exynos_mipi_dsim *mipi_dsim = + (struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim(); + unsigned int reg = readl(&mipi_dsim->clkctrl); + + if (enable) + reg |= DSIM_LANE_ESC_CLKEN(lane_sel); + else + reg &= ~DSIM_LANE_ESC_CLKEN(lane_sel); + + writel(reg, &mipi_dsim->clkctrl); +} + +void exynos_mipi_dsi_force_dphy_stop_state(struct mipi_dsim_device *dsim, + unsigned int enable) +{ + struct exynos_mipi_dsim *mipi_dsim = + (struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim(); + unsigned int reg = (readl(&mipi_dsim->escmode)) & + ~(0x1 << DSIM_FORCE_STOP_STATE_SHIFT); + + reg |= ((enable & 0x1) << DSIM_FORCE_STOP_STATE_SHIFT); + + writel(reg, &mipi_dsim->escmode); +} + +unsigned int exynos_mipi_dsi_is_lane_state(struct mipi_dsim_device *dsim) +{ + struct exynos_mipi_dsim *mipi_dsim = + (struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim(); + unsigned int reg = readl(&mipi_dsim->status); + + /** + * check clock and data lane states. + * if MIPI-DSI controller was enabled at bootloader then + * TX_READY_HS_CLK is enabled otherwise STOP_STATE_CLK. + * so it should be checked for two case. + */ + if ((reg & DSIM_STOP_STATE_DAT(0xf)) && + ((reg & DSIM_STOP_STATE_CLK) || + (reg & DSIM_TX_READY_HS_CLK))) + return 1; + else + return 0; +} + +void exynos_mipi_dsi_set_stop_state_counter(struct mipi_dsim_device *dsim, + unsigned int cnt_val) +{ + struct exynos_mipi_dsim *mipi_dsim = + (struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim(); + unsigned int reg = (readl(&mipi_dsim->escmode)) & + ~(0x7ff << DSIM_STOP_STATE_CNT_SHIFT); + + reg |= ((cnt_val & 0x7ff) << DSIM_STOP_STATE_CNT_SHIFT); + + writel(reg, &mipi_dsim->escmode); +} + +void exynos_mipi_dsi_set_bta_timeout(struct mipi_dsim_device *dsim, + unsigned int timeout) +{ + struct exynos_mipi_dsim *mipi_dsim = + (struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim(); + unsigned int reg = (readl(&mipi_dsim->timeout)) & + ~(0xff << DSIM_BTA_TOUT_SHIFT); + + reg |= (timeout << DSIM_BTA_TOUT_SHIFT); + + writel(reg, &mipi_dsim->timeout); +} + +void exynos_mipi_dsi_set_lpdr_timeout(struct mipi_dsim_device *dsim, + unsigned int timeout) +{ + struct exynos_mipi_dsim *mipi_dsim = + (struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim(); + unsigned int reg = (readl(&mipi_dsim->timeout)) & + ~(0xffff << DSIM_LPDR_TOUT_SHIFT); + + reg |= (timeout << DSIM_LPDR_TOUT_SHIFT); + + writel(reg, &mipi_dsim->timeout); +} + +void exynos_mipi_dsi_set_cpu_transfer_mode(struct mipi_dsim_device *dsim, + unsigned int lp) +{ + struct exynos_mipi_dsim *mipi_dsim = + (struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim(); + unsigned int reg = readl(&mipi_dsim->escmode); + + reg &= ~DSIM_CMD_LPDT_LP; + + if (lp) + reg |= DSIM_CMD_LPDT_LP; + + writel(reg, &mipi_dsim->escmode); +} + +void exynos_mipi_dsi_set_lcdc_transfer_mode(struct mipi_dsim_device *dsim, + unsigned int lp) +{ + struct exynos_mipi_dsim *mipi_dsim = + (struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim(); + unsigned int reg = readl(&mipi_dsim->escmode); + + reg &= ~DSIM_TX_LPDT_LP; + + if (lp) + reg |= DSIM_TX_LPDT_LP; + + writel(reg, &mipi_dsim->escmode); +} + +void exynos_mipi_dsi_enable_hs_clock(struct mipi_dsim_device *dsim, + unsigned int enable) +{ + struct exynos_mipi_dsim *mipi_dsim = + (struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim(); + unsigned int reg = (readl(&mipi_dsim->clkctrl)) & + ~(1 << DSIM_TX_REQUEST_HSCLK_SHIFT); + + reg |= enable << DSIM_TX_REQUEST_HSCLK_SHIFT; + + writel(reg, &mipi_dsim->clkctrl); +} + +void exynos_mipi_dsi_dp_dn_swap(struct mipi_dsim_device *dsim, + unsigned int swap_en) +{ + struct exynos_mipi_dsim *mipi_dsim = + (struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim(); + unsigned int reg = readl(&mipi_dsim->phyacchr1); + + reg &= ~(0x3 << DSIM_DPDN_SWAP_DATA_SHIFT); + reg |= (swap_en & 0x3) << DSIM_DPDN_SWAP_DATA_SHIFT; + + writel(reg, &mipi_dsim->phyacchr1); +} + +void exynos_mipi_dsi_hs_zero_ctrl(struct mipi_dsim_device *dsim, + unsigned int hs_zero) +{ + struct exynos_mipi_dsim *mipi_dsim = + (struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim(); + unsigned int reg = (readl(&mipi_dsim->pllctrl)) & + ~(0xf << DSIM_ZEROCTRL_SHIFT); + + reg |= ((hs_zero & 0xf) << DSIM_ZEROCTRL_SHIFT); + + writel(reg, &mipi_dsim->pllctrl); +} + +void exynos_mipi_dsi_prep_ctrl(struct mipi_dsim_device *dsim, unsigned int prep) +{ + struct exynos_mipi_dsim *mipi_dsim = + (struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim(); + unsigned int reg = (readl(&mipi_dsim->pllctrl)) & + ~(0x7 << DSIM_PRECTRL_SHIFT); + + reg |= ((prep & 0x7) << DSIM_PRECTRL_SHIFT); + + writel(reg, &mipi_dsim->pllctrl); +} + +void exynos_mipi_dsi_clear_interrupt(struct mipi_dsim_device *dsim) +{ + struct exynos_mipi_dsim *mipi_dsim = + (struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim(); + unsigned int reg = readl(&mipi_dsim->intsrc); + + reg |= INTSRC_PLL_STABLE; + + writel(reg, &mipi_dsim->intsrc); +} + +void exynos_mipi_dsi_clear_all_interrupt(struct mipi_dsim_device *dsim) +{ + struct exynos_mipi_dsim *mipi_dsim = + (struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim(); + + writel(0xffffffff, &mipi_dsim->intsrc); +} + +unsigned int exynos_mipi_dsi_is_pll_stable(struct mipi_dsim_device *dsim) +{ + unsigned int reg; + struct exynos_mipi_dsim *mipi_dsim = + (struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim(); + + reg = readl(&mipi_dsim->status); + + return reg & DSIM_PLL_STABLE ? 1 : 0; +} + +unsigned int exynos_mipi_dsi_get_fifo_state(struct mipi_dsim_device *dsim) +{ + struct exynos_mipi_dsim *mipi_dsim = + (struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim(); + + return readl(&mipi_dsim->fifoctrl) & ~(0x1f); +} + +void exynos_mipi_dsi_wr_tx_header(struct mipi_dsim_device *dsim, + unsigned int di, const unsigned char data0, const unsigned char data1) +{ + struct exynos_mipi_dsim *mipi_dsim = + (struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim(); + unsigned int reg = (DSIM_PKTHDR_DAT1(data1) | DSIM_PKTHDR_DAT0(data0) | + DSIM_PKTHDR_DI(di)); + + writel(reg, &mipi_dsim->pkthdr); +} + +unsigned int _exynos_mipi_dsi_get_frame_done_status(struct mipi_dsim_device + *dsim) +{ + struct exynos_mipi_dsim *mipi_dsim = + (struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim(); + unsigned int reg = readl(&mipi_dsim->intsrc); + + return (reg & INTSRC_FRAME_DONE) ? 1 : 0; +} + +void _exynos_mipi_dsi_clear_frame_done(struct mipi_dsim_device *dsim) +{ + struct exynos_mipi_dsim *mipi_dsim = + (struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim(); + unsigned int reg = readl(&mipi_dsim->intsrc); + + writel(reg | INTSRC_FRAME_DONE, &mipi_dsim->intsrc); +} + +void exynos_mipi_dsi_wr_tx_data(struct mipi_dsim_device *dsim, + unsigned int tx_data) +{ + struct exynos_mipi_dsim *mipi_dsim = + (struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim(); + + writel(tx_data, &mipi_dsim->payload); +} diff --git a/drivers/video/exynos/exynos_mipi_dsi_lowlevel.h b/drivers/video/exynos/exynos_mipi_dsi_lowlevel.h new file mode 100644 index 0000000..0bede25 --- /dev/null +++ b/drivers/video/exynos/exynos_mipi_dsi_lowlevel.h @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2012 Samsung Electronics + * + * Author: InKi Dae + * Author: Donghwa Lee + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef _EXYNOS_MIPI_DSI_LOWLEVEL_H +#define _EXYNOS_MIPI_DSI_LOWLEVEL_H + +void exynos_mipi_dsi_register(struct mipi_dsim_device *dsim); +void exynos_mipi_dsi_func_reset(struct mipi_dsim_device *dsim); +void exynos_mipi_dsi_sw_reset(struct mipi_dsim_device *dsim); +void exynos_mipi_dsi_sw_release(struct mipi_dsim_device *dsim); +void exynos_mipi_dsi_set_interrupt_mask(struct mipi_dsim_device *dsim, + unsigned int mode, unsigned int mask); +void exynos_mipi_dsi_set_data_lane_number(struct mipi_dsim_device *dsim, + unsigned int count); +void exynos_mipi_dsi_init_fifo_pointer(struct mipi_dsim_device *dsim, + unsigned int cfg); +void exynos_mipi_dsi_set_phy_tunning(struct mipi_dsim_device *dsim, + unsigned int value); +void exynos_mipi_dsi_set_phy_tunning(struct mipi_dsim_device *dsim, + unsigned int value); +void exynos_mipi_dsi_set_main_disp_resol(struct mipi_dsim_device *dsim, + unsigned int width_resol, unsigned int height_resol); +void exynos_mipi_dsi_set_main_disp_vporch(struct mipi_dsim_device *dsim, + unsigned int cmd_allow, unsigned int vfront, unsigned int vback); +void exynos_mipi_dsi_set_main_disp_hporch(struct mipi_dsim_device *dsim, + unsigned int front, unsigned int back); +void exynos_mipi_dsi_set_main_disp_sync_area(struct mipi_dsim_device *dsim, + unsigned int vert, unsigned int hori); +void exynos_mipi_dsi_set_sub_disp_resol(struct mipi_dsim_device *dsim, + unsigned int vert, unsigned int hori); +void exynos_mipi_dsi_init_config(struct mipi_dsim_device *dsim); +void exynos_mipi_dsi_display_config(struct mipi_dsim_device *dsim, + struct mipi_dsim_config *dsim_config); +void exynos_mipi_dsi_set_data_lane_number(struct mipi_dsim_device *dsim, + unsigned int count); +void exynos_mipi_dsi_enable_lane(struct mipi_dsim_device *dsim, + unsigned int lane, unsigned int enable); +void exynos_mipi_dsi_enable_afc(struct mipi_dsim_device *dsim, + unsigned int enable, unsigned int afc_code); +void exynos_mipi_dsi_enable_pll_bypass(struct mipi_dsim_device *dsim, + unsigned int enable); +void exynos_mipi_dsi_pll_freq_band(struct mipi_dsim_device *dsim, + unsigned int freq_band); +void exynos_mipi_dsi_pll_freq(struct mipi_dsim_device *dsim, + unsigned int pre_divider, unsigned int main_divider, + unsigned int scaler); +void exynos_mipi_dsi_pll_stable_time(struct mipi_dsim_device *dsim, + unsigned int lock_time); +void exynos_mipi_dsi_enable_pll(struct mipi_dsim_device *dsim, + unsigned int enable); +void exynos_mipi_dsi_set_byte_clock_src(struct mipi_dsim_device *dsim, + unsigned int src); +void exynos_mipi_dsi_enable_byte_clock(struct mipi_dsim_device *dsim, + unsigned int enable); +void exynos_mipi_dsi_set_esc_clk_prs(struct mipi_dsim_device *dsim, + unsigned int enable, unsigned int prs_val); +void exynos_mipi_dsi_enable_esc_clk_on_lane(struct mipi_dsim_device *dsim, + unsigned int lane_sel, unsigned int enable); +void exynos_mipi_dsi_force_dphy_stop_state(struct mipi_dsim_device *dsim, + unsigned int enable); +unsigned int exynos_mipi_dsi_is_lane_state(struct mipi_dsim_device *dsim); +void exynos_mipi_dsi_set_stop_state_counter(struct mipi_dsim_device *dsim, + unsigned int cnt_val); +void exynos_mipi_dsi_set_bta_timeout(struct mipi_dsim_device *dsim, + unsigned int timeout); +void exynos_mipi_dsi_set_lpdr_timeout(struct mipi_dsim_device *dsim, + unsigned int timeout); +void exynos_mipi_dsi_set_lcdc_transfer_mode(struct mipi_dsim_device *dsim, + unsigned int lp); +void exynos_mipi_dsi_set_cpu_transfer_mode(struct mipi_dsim_device *dsim, + unsigned int lp); +void exynos_mipi_dsi_enable_hs_clock(struct mipi_dsim_device *dsim, + unsigned int enable); +void exynos_mipi_dsi_dp_dn_swap(struct mipi_dsim_device *dsim, + unsigned int swap_en); +void exynos_mipi_dsi_hs_zero_ctrl(struct mipi_dsim_device *dsim, + unsigned int hs_zero); +void exynos_mipi_dsi_prep_ctrl(struct mipi_dsim_device *dsim, + unsigned int prep); +void exynos_mipi_dsi_clear_interrupt(struct mipi_dsim_device *dsim); +void exynos_mipi_dsi_clear_all_interrupt(struct mipi_dsim_device *dsim); +unsigned int exynos_mipi_dsi_is_pll_stable(struct mipi_dsim_device *dsim); +unsigned int exynos_mipi_dsi_get_fifo_state(struct mipi_dsim_device *dsim); +unsigned int _exynos_mipi_dsi_get_frame_done_status(struct mipi_dsim_device + *dsim); +void _exynos_mipi_dsi_clear_frame_done(struct mipi_dsim_device *dsim); +void exynos_mipi_dsi_wr_tx_header(struct mipi_dsim_device *dsim, + unsigned int di, const unsigned char data0, const unsigned char data1); +void exynos_mipi_dsi_wr_tx_data(struct mipi_dsim_device *dsim, + unsigned int tx_data); + +#endif /* _EXYNOS_MIPI_DSI_LOWLEVEL_H */ diff --git a/drivers/video/exynos/exynos_pwm_bl.c b/drivers/video/exynos/exynos_pwm_bl.c new file mode 100644 index 0000000..a6890da --- /dev/null +++ b/drivers/video/exynos/exynos_pwm_bl.c @@ -0,0 +1,45 @@ +/* + * PWM BACKLIGHT driver for Board based on EXYNOS. + * + * Author: Donghwa Lee + * + * Derived from linux/drivers/video/backlight/pwm_backlight.c + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +static struct pwm_backlight_data *pwm; + +static int exynos_pwm_backlight_update_status(void) +{ + int brightness = pwm->brightness; + int max = pwm->max_brightness; + + if (brightness == 0) { + pwm_config(pwm->pwm_id, 0, pwm->period); + pwm_disable(pwm->pwm_id); + } else { + pwm_config(pwm->pwm_id, + brightness * pwm->period / max, pwm->period); + pwm_enable(pwm->pwm_id); + } + return 0; +} + +int exynos_pwm_backlight_init(struct pwm_backlight_data *pd) +{ + pwm = pd; + + exynos_pwm_backlight_update_status(); + + return 0; +} diff --git a/drivers/video/exynos_dp.c b/drivers/video/exynos_dp.c deleted file mode 100644 index 0d5d090..0000000 --- a/drivers/video/exynos_dp.c +++ /dev/null @@ -1,961 +0,0 @@ -/* - * Copyright (C) 2012 Samsung Electronics - * - * Author: Donghwa Lee - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "exynos_dp_lowlevel.h" - -DECLARE_GLOBAL_DATA_PTR; - -void __exynos_set_dp_phy(unsigned int onoff) -{ -} -void exynos_set_dp_phy(unsigned int onoff) - __attribute__((weak, alias("__exynos_set_dp_phy"))); - -static void exynos_dp_disp_info(struct edp_disp_info *disp_info) -{ - disp_info->h_total = disp_info->h_res + disp_info->h_sync_width + - disp_info->h_back_porch + disp_info->h_front_porch; - disp_info->v_total = disp_info->v_res + disp_info->v_sync_width + - disp_info->v_back_porch + disp_info->v_front_porch; - - return; -} - -static int exynos_dp_init_dp(void) -{ - int ret; - exynos_dp_reset(); - - /* SW defined function Normal operation */ - exynos_dp_enable_sw_func(DP_ENABLE); - - ret = exynos_dp_init_analog_func(); - if (ret != EXYNOS_DP_SUCCESS) - return ret; - - exynos_dp_init_hpd(); - exynos_dp_init_aux(); - - return ret; -} - -static unsigned char exynos_dp_calc_edid_check_sum(unsigned char *edid_data) -{ - int i; - unsigned char sum = 0; - - for (i = 0; i < EDID_BLOCK_LENGTH; i++) - sum = sum + edid_data[i]; - - return sum; -} - -static unsigned int exynos_dp_read_edid(void) -{ - unsigned char edid[EDID_BLOCK_LENGTH * 2]; - unsigned int extend_block = 0; - unsigned char sum; - unsigned char test_vector; - int retval; - - /* - * EDID device address is 0x50. - * However, if necessary, you must have set upper address - * into E-EDID in I2C device, 0x30. - */ - - /* Read Extension Flag, Number of 128-byte EDID extension blocks */ - exynos_dp_read_byte_from_i2c(I2C_EDID_DEVICE_ADDR, EDID_EXTENSION_FLAG, - &extend_block); - - if (extend_block > 0) { - printf("DP EDID data includes a single extension!\n"); - - /* Read EDID data */ - retval = exynos_dp_read_bytes_from_i2c(I2C_EDID_DEVICE_ADDR, - EDID_HEADER_PATTERN, - EDID_BLOCK_LENGTH, - &edid[EDID_HEADER_PATTERN]); - if (retval != 0) { - printf("DP EDID Read failed!\n"); - return -1; - } - sum = exynos_dp_calc_edid_check_sum(edid); - if (sum != 0) { - printf("DP EDID bad checksum!\n"); - return -1; - } - - /* Read additional EDID data */ - retval = exynos_dp_read_bytes_from_i2c(I2C_EDID_DEVICE_ADDR, - EDID_BLOCK_LENGTH, - EDID_BLOCK_LENGTH, - &edid[EDID_BLOCK_LENGTH]); - if (retval != 0) { - printf("DP EDID Read failed!\n"); - return -1; - } - sum = exynos_dp_calc_edid_check_sum(&edid[EDID_BLOCK_LENGTH]); - if (sum != 0) { - printf("DP EDID bad checksum!\n"); - return -1; - } - - exynos_dp_read_byte_from_dpcd(DPCD_TEST_REQUEST, - &test_vector); - if (test_vector & DPCD_TEST_EDID_READ) { - exynos_dp_write_byte_to_dpcd(DPCD_TEST_EDID_CHECKSUM, - edid[EDID_BLOCK_LENGTH + EDID_CHECKSUM]); - exynos_dp_write_byte_to_dpcd(DPCD_TEST_RESPONSE, - DPCD_TEST_EDID_CHECKSUM_WRITE); - } - } else { - debug("DP EDID data does not include any extensions.\n"); - - /* Read EDID data */ - retval = exynos_dp_read_bytes_from_i2c(I2C_EDID_DEVICE_ADDR, - EDID_HEADER_PATTERN, - EDID_BLOCK_LENGTH, - &edid[EDID_HEADER_PATTERN]); - - if (retval != 0) { - printf("DP EDID Read failed!\n"); - return -1; - } - sum = exynos_dp_calc_edid_check_sum(edid); - if (sum != 0) { - printf("DP EDID bad checksum!\n"); - return -1; - } - - exynos_dp_read_byte_from_dpcd(DPCD_TEST_REQUEST, - &test_vector); - if (test_vector & DPCD_TEST_EDID_READ) { - exynos_dp_write_byte_to_dpcd(DPCD_TEST_EDID_CHECKSUM, - edid[EDID_CHECKSUM]); - exynos_dp_write_byte_to_dpcd(DPCD_TEST_RESPONSE, - DPCD_TEST_EDID_CHECKSUM_WRITE); - } - } - - debug("DP EDID Read success!\n"); - - return 0; -} - -static unsigned int exynos_dp_handle_edid(struct edp_device_info *edp_info) -{ - unsigned char buf[12]; - unsigned int ret; - unsigned char temp; - unsigned char retry_cnt; - unsigned char dpcd_rev[16]; - unsigned char lane_bw[16]; - unsigned char lane_cnt[16]; - - memset(dpcd_rev, 0, 16); - memset(lane_bw, 0, 16); - memset(lane_cnt, 0, 16); - memset(buf, 0, 12); - - retry_cnt = 5; - while (retry_cnt) { - /* Read DPCD 0x0000-0x000b */ - ret = exynos_dp_read_bytes_from_dpcd(DPCD_DPCD_REV, 12, - buf); - if (ret != EXYNOS_DP_SUCCESS) { - if (retry_cnt == 0) { - printf("DP read_byte_from_dpcd() failed\n"); - return ret; - } - retry_cnt--; - } else - break; - } - - /* */ - temp = buf[DPCD_DPCD_REV]; - if (temp == DP_DPCD_REV_10 || temp == DP_DPCD_REV_11) - edp_info->dpcd_rev = temp; - else { - printf("DP Wrong DPCD Rev : %x\n", temp); - return -ENODEV; - } - - temp = buf[DPCD_MAX_LINK_RATE]; - if (temp == DP_LANE_BW_1_62 || temp == DP_LANE_BW_2_70) - edp_info->lane_bw = temp; - else { - printf("DP Wrong MAX LINK RATE : %x\n", temp); - return -EINVAL; - } - - /* Refer VESA Display Port Standard Ver1.1a Page 120 */ - if (edp_info->dpcd_rev == DP_DPCD_REV_11) { - temp = buf[DPCD_MAX_LANE_COUNT] & 0x1f; - if (buf[DPCD_MAX_LANE_COUNT] & 0x80) - edp_info->dpcd_efc = 1; - else - edp_info->dpcd_efc = 0; - } else { - temp = buf[DPCD_MAX_LANE_COUNT]; - edp_info->dpcd_efc = 0; - } - - if (temp == DP_LANE_CNT_1 || temp == DP_LANE_CNT_2 || - temp == DP_LANE_CNT_4) { - edp_info->lane_cnt = temp; - } else { - printf("DP Wrong MAX LANE COUNT : %x\n", temp); - return -EINVAL; - } - - ret = exynos_dp_read_edid(); - if (ret != EXYNOS_DP_SUCCESS) { - printf("DP exynos_dp_read_edid() failed\n"); - return -EINVAL; - } - - return ret; -} - -static void exynos_dp_init_training(void) -{ - /* - * MACRO_RST must be applied after the PLL_LOCK to avoid - * the DP inter pair skew issue for at least 10 us - */ - exynos_dp_reset_macro(); - - /* All DP analog module power up */ - exynos_dp_set_analog_power_down(POWER_ALL, 0); -} - -static unsigned int exynos_dp_link_start(struct edp_device_info *edp_info) -{ - unsigned char buf[5]; - unsigned int ret = 0; - - debug("DP: %s was called\n", __func__); - - edp_info->lt_info.lt_status = DP_LT_CR; - edp_info->lt_info.ep_loop = 0; - edp_info->lt_info.cr_loop[0] = 0; - edp_info->lt_info.cr_loop[1] = 0; - edp_info->lt_info.cr_loop[2] = 0; - edp_info->lt_info.cr_loop[3] = 0; - - /* Set sink to D0 (Sink Not Ready) mode. */ - ret = exynos_dp_write_byte_to_dpcd(DPCD_SINK_POWER_STATE, - DPCD_SET_POWER_STATE_D0); - if (ret != EXYNOS_DP_SUCCESS) { - printf("DP write_dpcd_byte failed\n"); - return ret; - } - - /* Set link rate and count as you want to establish */ - exynos_dp_set_link_bandwidth(edp_info->lane_bw); - exynos_dp_set_lane_count(edp_info->lane_cnt); - - /* Setup RX configuration */ - buf[0] = edp_info->lane_bw; - buf[1] = edp_info->lane_cnt; - - ret = exynos_dp_write_bytes_to_dpcd(DPCD_LINK_BW_SET, 2, - buf); - if (ret != EXYNOS_DP_SUCCESS) { - printf("DP write_dpcd_byte failed\n"); - return ret; - } - - exynos_dp_set_lane_pre_emphasis(PRE_EMPHASIS_LEVEL_0, - edp_info->lane_cnt); - - /* Set training pattern 1 */ - exynos_dp_set_training_pattern(TRAINING_PTN1); - - /* Set RX training pattern */ - buf[0] = DPCD_SCRAMBLING_DISABLED | DPCD_TRAINING_PATTERN_1; - - buf[1] = DPCD_PRE_EMPHASIS_SET_PATTERN_2_LEVEL_0 | - DPCD_VOLTAGE_SWING_SET_PATTERN_1_LEVEL_0; - buf[2] = DPCD_PRE_EMPHASIS_SET_PATTERN_2_LEVEL_0 | - DPCD_VOLTAGE_SWING_SET_PATTERN_1_LEVEL_0; - buf[3] = DPCD_PRE_EMPHASIS_SET_PATTERN_2_LEVEL_0 | - DPCD_VOLTAGE_SWING_SET_PATTERN_1_LEVEL_0; - buf[4] = DPCD_PRE_EMPHASIS_SET_PATTERN_2_LEVEL_0 | - DPCD_VOLTAGE_SWING_SET_PATTERN_1_LEVEL_0; - - ret = exynos_dp_write_bytes_to_dpcd(DPCD_TRAINING_PATTERN_SET, - 5, buf); - if (ret != EXYNOS_DP_SUCCESS) { - printf("DP write_dpcd_byte failed\n"); - return ret; - } - - return ret; -} - -static unsigned int exynos_dp_training_pattern_dis(void) -{ - unsigned int ret = EXYNOS_DP_SUCCESS; - - exynos_dp_set_training_pattern(DP_NONE); - - ret = exynos_dp_write_byte_to_dpcd(DPCD_TRAINING_PATTERN_SET, - DPCD_TRAINING_PATTERN_DISABLED); - if (ret != EXYNOS_DP_SUCCESS) { - printf("DP request_link_training_req failed\n"); - return -EAGAIN; - } - - return ret; -} - -static unsigned int exynos_dp_enable_rx_to_enhanced_mode(unsigned char enable) -{ - unsigned char data; - unsigned int ret = EXYNOS_DP_SUCCESS; - - ret = exynos_dp_read_byte_from_dpcd(DPCD_LANE_COUNT_SET, - &data); - if (ret != EXYNOS_DP_SUCCESS) { - printf("DP read_from_dpcd failed\n"); - return -EAGAIN; - } - - if (enable) - data = DPCD_ENHANCED_FRAME_EN | DPCD_LN_COUNT_SET(data); - else - data = DPCD_LN_COUNT_SET(data); - - ret = exynos_dp_write_byte_to_dpcd(DPCD_LANE_COUNT_SET, - data); - if (ret != EXYNOS_DP_SUCCESS) { - printf("DP write_to_dpcd failed\n"); - return -EAGAIN; - - } - - return ret; -} - -static unsigned int exynos_dp_set_enhanced_mode(unsigned char enhance_mode) -{ - unsigned int ret = EXYNOS_DP_SUCCESS; - - ret = exynos_dp_enable_rx_to_enhanced_mode(enhance_mode); - if (ret != EXYNOS_DP_SUCCESS) { - printf("DP rx_enhance_mode failed\n"); - return -EAGAIN; - } - - exynos_dp_enable_enhanced_mode(enhance_mode); - - return ret; -} - -static int exynos_dp_read_dpcd_lane_stat(struct edp_device_info *edp_info, - unsigned char *status) -{ - unsigned int ret, i; - unsigned char buf[2]; - unsigned char lane_stat[DP_LANE_CNT_4] = {0,}; - unsigned char shift_val[DP_LANE_CNT_4] = {0,}; - - shift_val[0] = 0; - shift_val[1] = 4; - shift_val[2] = 0; - shift_val[3] = 4; - - ret = exynos_dp_read_bytes_from_dpcd(DPCD_LANE0_1_STATUS, 2, buf); - if (ret != EXYNOS_DP_SUCCESS) { - printf("DP read lane status failed\n"); - return ret; - } - - for (i = 0; i < edp_info->lane_cnt; i++) { - lane_stat[i] = (buf[(i / 2)] >> shift_val[i]) & 0x0f; - if (lane_stat[0] != lane_stat[i]) { - printf("Wrong lane status\n"); - return -EINVAL; - } - } - - *status = lane_stat[0]; - - return ret; -} - -static unsigned int exynos_dp_read_dpcd_adj_req(unsigned char lane_num, - unsigned char *sw, unsigned char *em) -{ - unsigned int ret = EXYNOS_DP_SUCCESS; - unsigned char buf; - unsigned int dpcd_addr; - unsigned char shift_val[DP_LANE_CNT_4] = {0, 4, 0, 4}; - - /* lane_num value is used as array index, so this range 0 ~ 3 */ - dpcd_addr = DPCD_ADJUST_REQUEST_LANE0_1 + (lane_num / 2); - - ret = exynos_dp_read_byte_from_dpcd(dpcd_addr, &buf); - if (ret != EXYNOS_DP_SUCCESS) { - printf("DP read adjust request failed\n"); - return -EAGAIN; - } - - *sw = ((buf >> shift_val[lane_num]) & 0x03); - *em = ((buf >> shift_val[lane_num]) & 0x0c) >> 2; - - return ret; -} - -static int exynos_dp_equalizer_err_link(struct edp_device_info *edp_info) -{ - int ret; - - ret = exynos_dp_training_pattern_dis(); - if (ret != EXYNOS_DP_SUCCESS) { - printf("DP training_pattern_disable() failed\n"); - edp_info->lt_info.lt_status = DP_LT_FAIL; - } - - ret = exynos_dp_set_enhanced_mode(edp_info->dpcd_efc); - if (ret != EXYNOS_DP_SUCCESS) { - printf("DP set_enhanced_mode() failed\n"); - edp_info->lt_info.lt_status = DP_LT_FAIL; - } - - return ret; -} - -static int exynos_dp_reduce_link_rate(struct edp_device_info *edp_info) -{ - int ret; - - if (edp_info->lane_bw == DP_LANE_BW_2_70) { - edp_info->lane_bw = DP_LANE_BW_1_62; - printf("DP Change lane bw to 1.62Gbps\n"); - edp_info->lt_info.lt_status = DP_LT_START; - ret = EXYNOS_DP_SUCCESS; - } else { - ret = exynos_dp_training_pattern_dis(); - if (ret != EXYNOS_DP_SUCCESS) - printf("DP training_patter_disable() failed\n"); - - ret = exynos_dp_set_enhanced_mode(edp_info->dpcd_efc); - if (ret != EXYNOS_DP_SUCCESS) - printf("DP set_enhanced_mode() failed\n"); - - edp_info->lt_info.lt_status = DP_LT_FAIL; - } - - return ret; -} - -static unsigned int exynos_dp_process_clock_recovery(struct edp_device_info - *edp_info) -{ - unsigned int ret = EXYNOS_DP_SUCCESS; - unsigned char lane_stat; - unsigned char lt_ctl_val[DP_LANE_CNT_4] = {0, }; - unsigned int i; - unsigned char adj_req_sw; - unsigned char adj_req_em; - unsigned char buf[5]; - - debug("DP: %s was called\n", __func__); - mdelay(1); - - ret = exynos_dp_read_dpcd_lane_stat(edp_info, &lane_stat); - if (ret != EXYNOS_DP_SUCCESS) { - printf("DP read lane status failed\n"); - edp_info->lt_info.lt_status = DP_LT_FAIL; - return ret; - } - - if (lane_stat & DP_LANE_STAT_CR_DONE) { - debug("DP clock Recovery training succeed\n"); - exynos_dp_set_training_pattern(TRAINING_PTN2); - - for (i = 0; i < edp_info->lane_cnt; i++) { - ret = exynos_dp_read_dpcd_adj_req(i, &adj_req_sw, - &adj_req_em); - if (ret != EXYNOS_DP_SUCCESS) { - edp_info->lt_info.lt_status = DP_LT_FAIL; - return ret; - } - - lt_ctl_val[i] = 0; - lt_ctl_val[i] = adj_req_em << 3 | adj_req_sw; - - if ((adj_req_sw == VOLTAGE_LEVEL_3) - || (adj_req_em == PRE_EMPHASIS_LEVEL_3)) { - lt_ctl_val[i] |= MAX_DRIVE_CURRENT_REACH_3 | - MAX_PRE_EMPHASIS_REACH_3; - } - exynos_dp_set_lanex_pre_emphasis(lt_ctl_val[i], i); - } - - buf[0] = DPCD_SCRAMBLING_DISABLED | DPCD_TRAINING_PATTERN_2; - buf[1] = lt_ctl_val[0]; - buf[2] = lt_ctl_val[1]; - buf[3] = lt_ctl_val[2]; - buf[4] = lt_ctl_val[3]; - - ret = exynos_dp_write_bytes_to_dpcd( - DPCD_TRAINING_PATTERN_SET, 5, buf); - if (ret != EXYNOS_DP_SUCCESS) { - printf("DP write training pattern1 failed\n"); - edp_info->lt_info.lt_status = DP_LT_FAIL; - return ret; - } else - edp_info->lt_info.lt_status = DP_LT_ET; - } else { - for (i = 0; i < edp_info->lane_cnt; i++) { - lt_ctl_val[i] = exynos_dp_get_lanex_pre_emphasis(i); - ret = exynos_dp_read_dpcd_adj_req(i, - &adj_req_sw, &adj_req_em); - if (ret != EXYNOS_DP_SUCCESS) { - printf("DP read adj req failed\n"); - edp_info->lt_info.lt_status = DP_LT_FAIL; - return ret; - } - - if ((adj_req_sw == VOLTAGE_LEVEL_3) || - (adj_req_em == PRE_EMPHASIS_LEVEL_3)) - ret = exynos_dp_reduce_link_rate(edp_info); - - if ((DRIVE_CURRENT_SET_0_GET(lt_ctl_val[i]) == - adj_req_sw) && - (PRE_EMPHASIS_SET_0_GET(lt_ctl_val[i]) == - adj_req_em)) { - edp_info->lt_info.cr_loop[i]++; - if (edp_info->lt_info.cr_loop[i] == MAX_CR_LOOP) - ret = exynos_dp_reduce_link_rate( - edp_info); - } - - lt_ctl_val[i] = 0; - lt_ctl_val[i] = adj_req_em << 3 | adj_req_sw; - - if ((adj_req_sw == VOLTAGE_LEVEL_3) || - (adj_req_em == PRE_EMPHASIS_LEVEL_3)) { - lt_ctl_val[i] |= MAX_DRIVE_CURRENT_REACH_3 | - MAX_PRE_EMPHASIS_REACH_3; - } - exynos_dp_set_lanex_pre_emphasis(lt_ctl_val[i], i); - } - - ret = exynos_dp_write_bytes_to_dpcd( - DPCD_TRAINING_LANE0_SET, 4, lt_ctl_val); - if (ret != EXYNOS_DP_SUCCESS) { - printf("DP write training pattern2 failed\n"); - edp_info->lt_info.lt_status = DP_LT_FAIL; - return ret; - } - } - - return ret; -} - -static unsigned int exynos_dp_process_equalizer_training(struct edp_device_info - *edp_info) -{ - unsigned int ret = EXYNOS_DP_SUCCESS; - unsigned char lane_stat, adj_req_sw, adj_req_em, i; - unsigned char lt_ctl_val[DP_LANE_CNT_4] = {0,}; - unsigned char interlane_aligned = 0; - unsigned char f_bw; - unsigned char f_lane_cnt; - unsigned char sink_stat; - - mdelay(1); - - ret = exynos_dp_read_dpcd_lane_stat(edp_info, &lane_stat); - if (ret != EXYNOS_DP_SUCCESS) { - printf("DP read lane status failed\n"); - edp_info->lt_info.lt_status = DP_LT_FAIL; - return ret; - } - - debug("DP lane stat : %x\n", lane_stat); - - if (lane_stat & DP_LANE_STAT_CR_DONE) { - ret = exynos_dp_read_byte_from_dpcd(DPCD_LN_ALIGN_UPDATED, - &sink_stat); - if (ret != EXYNOS_DP_SUCCESS) { - edp_info->lt_info.lt_status = DP_LT_FAIL; - - return ret; - } - - interlane_aligned = (sink_stat & DPCD_INTERLANE_ALIGN_DONE); - - for (i = 0; i < edp_info->lane_cnt; i++) { - ret = exynos_dp_read_dpcd_adj_req(i, - &adj_req_sw, &adj_req_em); - if (ret != EXYNOS_DP_SUCCESS) { - printf("DP read adj req 1 failed\n"); - edp_info->lt_info.lt_status = DP_LT_FAIL; - - return ret; - } - - lt_ctl_val[i] = 0; - lt_ctl_val[i] = adj_req_em << 3 | adj_req_sw; - - if ((adj_req_sw == VOLTAGE_LEVEL_3) || - (adj_req_em == PRE_EMPHASIS_LEVEL_3)) { - lt_ctl_val[i] |= MAX_DRIVE_CURRENT_REACH_3; - lt_ctl_val[i] |= MAX_PRE_EMPHASIS_REACH_3; - } - } - - if (((lane_stat&DP_LANE_STAT_CE_DONE) && - (lane_stat&DP_LANE_STAT_SYM_LOCK)) - && (interlane_aligned == DPCD_INTERLANE_ALIGN_DONE)) { - debug("DP Equalizer training succeed\n"); - - f_bw = exynos_dp_get_link_bandwidth(); - f_lane_cnt = exynos_dp_get_lane_count(); - - debug("DP final BandWidth : %x\n", f_bw); - debug("DP final Lane Count : %x\n", f_lane_cnt); - - edp_info->lt_info.lt_status = DP_LT_FINISHED; - - exynos_dp_equalizer_err_link(edp_info); - - } else { - edp_info->lt_info.ep_loop++; - - if (edp_info->lt_info.ep_loop > MAX_EQ_LOOP) { - if (edp_info->lane_bw == DP_LANE_BW_2_70) { - ret = exynos_dp_reduce_link_rate( - edp_info); - } else { - edp_info->lt_info.lt_status = - DP_LT_FAIL; - exynos_dp_equalizer_err_link(edp_info); - } - } else { - for (i = 0; i < edp_info->lane_cnt; i++) - exynos_dp_set_lanex_pre_emphasis( - lt_ctl_val[i], i); - - ret = exynos_dp_write_bytes_to_dpcd( - DPCD_TRAINING_LANE0_SET, - 4, lt_ctl_val); - if (ret != EXYNOS_DP_SUCCESS) { - printf("DP set lt pattern failed\n"); - edp_info->lt_info.lt_status = - DP_LT_FAIL; - exynos_dp_equalizer_err_link(edp_info); - } - } - } - } else if (edp_info->lane_bw == DP_LANE_BW_2_70) { - ret = exynos_dp_reduce_link_rate(edp_info); - } else { - edp_info->lt_info.lt_status = DP_LT_FAIL; - exynos_dp_equalizer_err_link(edp_info); - } - - return ret; -} - -static unsigned int exynos_dp_sw_link_training(struct edp_device_info *edp_info) -{ - unsigned int ret = 0; - int training_finished; - - /* Turn off unnecessary lane */ - if (edp_info->lane_cnt == 1) - exynos_dp_set_analog_power_down(CH1_BLOCK, 1); - - training_finished = 0; - - edp_info->lt_info.lt_status = DP_LT_START; - - /* Process here */ - while (!training_finished) { - switch (edp_info->lt_info.lt_status) { - case DP_LT_START: - ret = exynos_dp_link_start(edp_info); - if (ret != EXYNOS_DP_SUCCESS) { - printf("DP LT:link start failed\n"); - return ret; - } - break; - case DP_LT_CR: - ret = exynos_dp_process_clock_recovery(edp_info); - if (ret != EXYNOS_DP_SUCCESS) { - printf("DP LT:clock recovery failed\n"); - return ret; - } - break; - case DP_LT_ET: - ret = exynos_dp_process_equalizer_training(edp_info); - if (ret != EXYNOS_DP_SUCCESS) { - printf("DP LT:equalizer training failed\n"); - return ret; - } - break; - case DP_LT_FINISHED: - training_finished = 1; - break; - case DP_LT_FAIL: - return -1; - } - } - - return ret; -} - -static unsigned int exynos_dp_set_link_train(struct edp_device_info *edp_info) -{ - unsigned int ret; - - exynos_dp_init_training(); - - ret = exynos_dp_sw_link_training(edp_info); - if (ret != EXYNOS_DP_SUCCESS) - printf("DP dp_sw_link_training() failed\n"); - - return ret; -} - -static void exynos_dp_enable_scramble(unsigned int enable) -{ - unsigned char data; - - if (enable) { - exynos_dp_enable_scrambling(DP_ENABLE); - - exynos_dp_read_byte_from_dpcd(DPCD_TRAINING_PATTERN_SET, - &data); - exynos_dp_write_byte_to_dpcd(DPCD_TRAINING_PATTERN_SET, - (u8)(data & ~DPCD_SCRAMBLING_DISABLED)); - } else { - exynos_dp_enable_scrambling(DP_DISABLE); - exynos_dp_read_byte_from_dpcd(DPCD_TRAINING_PATTERN_SET, - &data); - exynos_dp_write_byte_to_dpcd(DPCD_TRAINING_PATTERN_SET, - (u8)(data | DPCD_SCRAMBLING_DISABLED)); - } -} - -static unsigned int exynos_dp_config_video(struct edp_device_info *edp_info) -{ - unsigned int ret = 0; - unsigned int retry_cnt; - - mdelay(1); - - if (edp_info->video_info.master_mode) { - printf("DP does not support master mode\n"); - return -ENODEV; - } else { - /* debug slave */ - exynos_dp_config_video_slave_mode(&edp_info->video_info); - } - - exynos_dp_set_video_color_format(&edp_info->video_info); - - if (edp_info->video_info.bist_mode) { - if (exynos_dp_config_video_bist(edp_info) != 0) - return -1; - } - - ret = exynos_dp_get_pll_lock_status(); - if (ret != PLL_LOCKED) { - printf("DP PLL is not locked yet\n"); - return -EIO; - } - - if (edp_info->video_info.master_mode == 0) { - retry_cnt = 10; - while (retry_cnt) { - ret = exynos_dp_is_slave_video_stream_clock_on(); - if (ret != EXYNOS_DP_SUCCESS) { - if (retry_cnt == 0) { - printf("DP stream_clock_on failed\n"); - return ret; - } - retry_cnt--; - mdelay(1); - } else - break; - } - } - - /* Set to use the register calculated M/N video */ - exynos_dp_set_video_cr_mn(CALCULATED_M, 0, 0); - - /* For video bist, Video timing must be generated by register */ - exynos_dp_set_video_timing_mode(VIDEO_TIMING_FROM_CAPTURE); - - /* Enable video bist */ - if (edp_info->video_info.bist_pattern != COLOR_RAMP && - edp_info->video_info.bist_pattern != BALCK_WHITE_V_LINES && - edp_info->video_info.bist_pattern != COLOR_SQUARE) - exynos_dp_enable_video_bist(edp_info->video_info.bist_mode); - else - exynos_dp_enable_video_bist(DP_DISABLE); - - /* Disable video mute */ - exynos_dp_enable_video_mute(DP_DISABLE); - - /* Configure video Master or Slave mode */ - exynos_dp_enable_video_master(edp_info->video_info.master_mode); - - /* Enable video */ - exynos_dp_start_video(); - - if (edp_info->video_info.master_mode == 0) { - retry_cnt = 100; - while (retry_cnt) { - ret = exynos_dp_is_video_stream_on(); - if (ret != EXYNOS_DP_SUCCESS) { - if (retry_cnt == 0) { - printf("DP Timeout of video stream\n"); - return ret; - } - retry_cnt--; - mdelay(5); - } else - break; - } - } - - return ret; -} - -int exynos_dp_parse_dt(const void *blob, struct edp_device_info *edp_info) -{ - unsigned int node = fdtdec_next_compatible(blob, 0, - COMPAT_SAMSUNG_EXYNOS5_DP); - if (node <= 0) { - debug("exynos_dp: Can't get device node for dp\n"); - return -ENODEV; - } - - edp_info->disp_info.h_res = fdtdec_get_int(blob, node, - "samsung,h-res", 0); - edp_info->disp_info.h_sync_width = fdtdec_get_int(blob, node, - "samsung,h-sync-width", 0); - edp_info->disp_info.h_back_porch = fdtdec_get_int(blob, node, - "samsung,h-back-porch", 0); - edp_info->disp_info.h_front_porch = fdtdec_get_int(blob, node, - "samsung,h-front-porch", 0); - edp_info->disp_info.v_res = fdtdec_get_int(blob, node, - "samsung,v-res", 0); - edp_info->disp_info.v_sync_width = fdtdec_get_int(blob, node, - "samsung,v-sync-width", 0); - edp_info->disp_info.v_back_porch = fdtdec_get_int(blob, node, - "samsung,v-back-porch", 0); - edp_info->disp_info.v_front_porch = fdtdec_get_int(blob, node, - "samsung,v-front-porch", 0); - edp_info->disp_info.v_sync_rate = fdtdec_get_int(blob, node, - "samsung,v-sync-rate", 0); - - edp_info->lt_info.lt_status = fdtdec_get_int(blob, node, - "samsung,lt-status", 0); - - edp_info->video_info.master_mode = fdtdec_get_int(blob, node, - "samsung,master-mode", 0); - edp_info->video_info.bist_mode = fdtdec_get_int(blob, node, - "samsung,bist-mode", 0); - edp_info->video_info.bist_pattern = fdtdec_get_int(blob, node, - "samsung,bist-pattern", 0); - edp_info->video_info.h_sync_polarity = fdtdec_get_int(blob, node, - "samsung,h-sync-polarity", 0); - edp_info->video_info.v_sync_polarity = fdtdec_get_int(blob, node, - "samsung,v-sync-polarity", 0); - edp_info->video_info.interlaced = fdtdec_get_int(blob, node, - "samsung,interlaced", 0); - edp_info->video_info.color_space = fdtdec_get_int(blob, node, - "samsung,color-space", 0); - edp_info->video_info.dynamic_range = fdtdec_get_int(blob, node, - "samsung,dynamic-range", 0); - edp_info->video_info.ycbcr_coeff = fdtdec_get_int(blob, node, - "samsung,ycbcr-coeff", 0); - edp_info->video_info.color_depth = fdtdec_get_int(blob, node, - "samsung,color-depth", 0); - return 0; -} - -unsigned int exynos_init_dp(void) -{ - unsigned int ret; - struct edp_device_info *edp_info; - - edp_info = kzalloc(sizeof(struct edp_device_info), GFP_KERNEL); - if (!edp_info) { - debug("failed to allocate edp device object.\n"); - return -EFAULT; - } - - if (exynos_dp_parse_dt(gd->fdt_blob, edp_info)) - debug("unable to parse DP DT node\n"); - - exynos_dp_set_base_addr(); - - exynos_dp_disp_info(&edp_info->disp_info); - - exynos_set_dp_phy(1); - - ret = exynos_dp_init_dp(); - if (ret != EXYNOS_DP_SUCCESS) { - printf("DP exynos_dp_init_dp() failed\n"); - return ret; - } - - ret = exynos_dp_handle_edid(edp_info); - if (ret != EXYNOS_DP_SUCCESS) { - printf("EDP handle_edid fail\n"); - return ret; - } - - ret = exynos_dp_set_link_train(edp_info); - if (ret != EXYNOS_DP_SUCCESS) { - printf("DP link training fail\n"); - return ret; - } - - exynos_dp_enable_scramble(DP_ENABLE); - exynos_dp_enable_rx_to_enhanced_mode(DP_ENABLE); - exynos_dp_enable_enhanced_mode(DP_ENABLE); - - exynos_dp_set_link_bandwidth(edp_info->lane_bw); - exynos_dp_set_lane_count(edp_info->lane_cnt); - - exynos_dp_init_video(); - ret = exynos_dp_config_video(edp_info); - if (ret != EXYNOS_DP_SUCCESS) { - printf("Exynos DP init failed\n"); - return ret; - } - - debug("Exynos DP init done\n"); - - return ret; -} diff --git a/drivers/video/exynos_dp_lowlevel.c b/drivers/video/exynos_dp_lowlevel.c deleted file mode 100644 index acb5bc8..0000000 --- a/drivers/video/exynos_dp_lowlevel.c +++ /dev/null @@ -1,1257 +0,0 @@ -/* - * Copyright (C) 2012 Samsung Electronics - * - * Author: Donghwa Lee - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -/* Declare global data pointer */ -DECLARE_GLOBAL_DATA_PTR; - -struct exynos_dp *dp_regs; - -void exynos_dp_set_base_addr(void) -{ -#if CONFIG_IS_ENABLED(OF_CONTROL) - unsigned int node = fdtdec_next_compatible(gd->fdt_blob, - 0, COMPAT_SAMSUNG_EXYNOS5_DP); - if (node <= 0) - debug("exynos_dp: Can't get device node for dp\n"); - - dp_regs = (struct exynos_dp *)fdtdec_get_addr(gd->fdt_blob, - node, "reg"); - if (dp_regs == NULL) - debug("Can't get the DP base address\n"); -#else - dp_regs = (struct exynos_dp *)samsung_get_base_dp(); -#endif -} - -static void exynos_dp_enable_video_input(unsigned int enable) -{ - unsigned int reg; - - reg = readl(&dp_regs->video_ctl1); - reg &= ~VIDEO_EN_MASK; - - /* enable video input */ - if (enable) - reg |= VIDEO_EN_MASK; - - writel(reg, &dp_regs->video_ctl1); - - return; -} - -void exynos_dp_enable_video_bist(unsigned int enable) -{ - /* enable video bist */ - unsigned int reg; - - reg = readl(&dp_regs->video_ctl4); - reg &= ~VIDEO_BIST_MASK; - - /* enable video bist */ - if (enable) - reg |= VIDEO_BIST_MASK; - - writel(reg, &dp_regs->video_ctl4); - - return; -} - -void exynos_dp_enable_video_mute(unsigned int enable) -{ - unsigned int reg; - - reg = readl(&dp_regs->video_ctl1); - reg &= ~(VIDEO_MUTE_MASK); - if (enable) - reg |= VIDEO_MUTE_MASK; - - writel(reg, &dp_regs->video_ctl1); - - return; -} - - -static void exynos_dp_init_analog_param(void) -{ - unsigned int reg; - - /* - * Set termination - * Normal bandgap, Normal swing, Tx terminal registor 61 ohm - * 24M Phy clock, TX digital logic power is 100:1.0625V - */ - reg = SEL_BG_NEW_BANDGAP | TX_TERMINAL_CTRL_61_OHM | - SWING_A_30PER_G_NORMAL; - writel(reg, &dp_regs->analog_ctl1); - - reg = SEL_24M | TX_DVDD_BIT_1_0625V; - writel(reg, &dp_regs->analog_ctl2); - - /* - * Set power source for internal clk driver to 1.0625v. - * Select current reference of TX driver current to 00:Ipp/2+Ic/2. - * Set VCO range of PLL +- 0uA - */ - reg = DRIVE_DVDD_BIT_1_0625V | SEL_CURRENT_DEFAULT | VCO_BIT_000_MICRO; - writel(reg, &dp_regs->analog_ctl3); - - /* - * Set AUX TX terminal resistor to 102 ohm - * Set AUX channel amplitude control - */ - reg = PD_RING_OSC | AUX_TERMINAL_CTRL_52_OHM | TX_CUR1_2X | TX_CUR_4_MA; - writel(reg, &dp_regs->pll_filter_ctl1); - - /* - * PLL loop filter bandwidth - * For 2.7Gbps: 175KHz, For 1.62Gbps: 234KHz - * PLL digital power select: 1.2500V - */ - reg = CH3_AMP_0_MV | CH2_AMP_0_MV | CH1_AMP_0_MV | CH0_AMP_0_MV; - - writel(reg, &dp_regs->amp_tuning_ctl); - - /* - * PLL loop filter bandwidth - * For 2.7Gbps: 175KHz, For 1.62Gbps: 234KHz - * PLL digital power select: 1.1250V - */ - reg = DP_PLL_LOOP_BIT_DEFAULT | DP_PLL_REF_BIT_1_1250V; - writel(reg, &dp_regs->pll_ctl); -} - -static void exynos_dp_init_interrupt(void) -{ - /* Set interrupt registers to initial states */ - - /* - * Disable interrupt - * INT pin assertion polarity. It must be configured - * correctly according to ICU setting. - * 1 = assert high, 0 = assert low - */ - writel(INT_POL, &dp_regs->int_ctl); - - /* Clear pending registers */ - writel(0xff, &dp_regs->common_int_sta1); - writel(0xff, &dp_regs->common_int_sta2); - writel(0xff, &dp_regs->common_int_sta3); - writel(0xff, &dp_regs->common_int_sta4); - writel(0xff, &dp_regs->int_sta); - - /* 0:mask,1: unmask */ - writel(0x00, &dp_regs->int_sta_mask1); - writel(0x00, &dp_regs->int_sta_mask2); - writel(0x00, &dp_regs->int_sta_mask3); - writel(0x00, &dp_regs->int_sta_mask4); - writel(0x00, &dp_regs->int_sta_mask); -} - -void exynos_dp_reset(void) -{ - unsigned int reg_func_1; - - /* dp tx sw reset */ - writel(RESET_DP_TX, &dp_regs->tx_sw_reset); - - exynos_dp_enable_video_input(DP_DISABLE); - exynos_dp_enable_video_bist(DP_DISABLE); - exynos_dp_enable_video_mute(DP_DISABLE); - - /* software reset */ - reg_func_1 = MASTER_VID_FUNC_EN_N | SLAVE_VID_FUNC_EN_N | - AUD_FIFO_FUNC_EN_N | AUD_FUNC_EN_N | - HDCP_FUNC_EN_N | SW_FUNC_EN_N; - - writel(reg_func_1, &dp_regs->func_en1); - writel(reg_func_1, &dp_regs->func_en2); - - mdelay(1); - - exynos_dp_init_analog_param(); - exynos_dp_init_interrupt(); - - return; -} - -void exynos_dp_enable_sw_func(unsigned int enable) -{ - unsigned int reg; - - reg = readl(&dp_regs->func_en1); - reg &= ~(SW_FUNC_EN_N); - - if (!enable) - reg |= SW_FUNC_EN_N; - - writel(reg, &dp_regs->func_en1); - - return; -} - -unsigned int exynos_dp_set_analog_power_down(unsigned int block, u32 enable) -{ - unsigned int reg; - - reg = readl(&dp_regs->phy_pd); - switch (block) { - case AUX_BLOCK: - reg &= ~(AUX_PD); - if (enable) - reg |= AUX_PD; - break; - case CH0_BLOCK: - reg &= ~(CH0_PD); - if (enable) - reg |= CH0_PD; - break; - case CH1_BLOCK: - reg &= ~(CH1_PD); - if (enable) - reg |= CH1_PD; - break; - case CH2_BLOCK: - reg &= ~(CH2_PD); - if (enable) - reg |= CH2_PD; - break; - case CH3_BLOCK: - reg &= ~(CH3_PD); - if (enable) - reg |= CH3_PD; - break; - case ANALOG_TOTAL: - reg &= ~PHY_PD; - if (enable) - reg |= PHY_PD; - break; - case POWER_ALL: - reg &= ~(PHY_PD | AUX_PD | CH0_PD | CH1_PD | CH2_PD | - CH3_PD); - if (enable) - reg |= (PHY_PD | AUX_PD | CH0_PD | CH1_PD | - CH2_PD | CH3_PD); - break; - default: - printf("DP undefined block number : %d\n", block); - return -1; - } - - writel(reg, &dp_regs->phy_pd); - - return 0; -} - -unsigned int exynos_dp_get_pll_lock_status(void) -{ - unsigned int reg; - - reg = readl(&dp_regs->debug_ctl); - - if (reg & PLL_LOCK) - return PLL_LOCKED; - else - return PLL_UNLOCKED; -} - -static void exynos_dp_set_pll_power(unsigned int enable) -{ - unsigned int reg; - - reg = readl(&dp_regs->pll_ctl); - reg &= ~(DP_PLL_PD); - - if (!enable) - reg |= DP_PLL_PD; - - writel(reg, &dp_regs->pll_ctl); -} - -int exynos_dp_init_analog_func(void) -{ - int ret = EXYNOS_DP_SUCCESS; - unsigned int retry_cnt = 10; - unsigned int reg; - - /* Power On All Analog block */ - exynos_dp_set_analog_power_down(POWER_ALL, DP_DISABLE); - - reg = PLL_LOCK_CHG; - writel(reg, &dp_regs->common_int_sta1); - - reg = readl(&dp_regs->debug_ctl); - reg &= ~(F_PLL_LOCK | PLL_LOCK_CTRL); - writel(reg, &dp_regs->debug_ctl); - - /* Assert DP PLL Reset */ - reg = readl(&dp_regs->pll_ctl); - reg |= DP_PLL_RESET; - writel(reg, &dp_regs->pll_ctl); - - mdelay(1); - - /* Deassert DP PLL Reset */ - reg = readl(&dp_regs->pll_ctl); - reg &= ~(DP_PLL_RESET); - writel(reg, &dp_regs->pll_ctl); - - exynos_dp_set_pll_power(DP_ENABLE); - - while (exynos_dp_get_pll_lock_status() == PLL_UNLOCKED) { - mdelay(1); - retry_cnt--; - if (retry_cnt == 0) { - printf("DP dp's pll lock failed : retry : %d\n", - retry_cnt); - return -EINVAL; - } - } - - debug("dp's pll lock success(%d)\n", retry_cnt); - - /* Enable Serdes FIFO function and Link symbol clock domain module */ - reg = readl(&dp_regs->func_en2); - reg &= ~(SERDES_FIFO_FUNC_EN_N | LS_CLK_DOMAIN_FUNC_EN_N - | AUX_FUNC_EN_N); - writel(reg, &dp_regs->func_en2); - - return ret; -} - -void exynos_dp_init_hpd(void) -{ - unsigned int reg; - - /* Clear interrupts related to Hot Plug Detect */ - reg = HOTPLUG_CHG | HPD_LOST | PLUG; - writel(reg, &dp_regs->common_int_sta4); - - reg = INT_HPD; - writel(reg, &dp_regs->int_sta); - - reg = readl(&dp_regs->sys_ctl3); - reg &= ~(F_HPD | HPD_CTRL); - writel(reg, &dp_regs->sys_ctl3); - - return; -} - -static inline void exynos_dp_reset_aux(void) -{ - unsigned int reg; - - /* Disable AUX channel module */ - reg = readl(&dp_regs->func_en2); - reg |= AUX_FUNC_EN_N; - writel(reg, &dp_regs->func_en2); - - return; -} - -void exynos_dp_init_aux(void) -{ - unsigned int reg; - - /* Clear interrupts related to AUX channel */ - reg = RPLY_RECEIV | AUX_ERR; - writel(reg, &dp_regs->int_sta); - - exynos_dp_reset_aux(); - - /* Disable AUX transaction H/W retry */ - reg = AUX_BIT_PERIOD_EXPECTED_DELAY(3) | AUX_HW_RETRY_COUNT_SEL(3)| - AUX_HW_RETRY_INTERVAL_600_MICROSECONDS; - writel(reg, &dp_regs->aux_hw_retry_ctl); - - /* Receive AUX Channel DEFER commands equal to DEFER_COUNT*64 */ - reg = DEFER_CTRL_EN | DEFER_COUNT(1); - writel(reg, &dp_regs->aux_ch_defer_ctl); - - /* Enable AUX channel module */ - reg = readl(&dp_regs->func_en2); - reg &= ~AUX_FUNC_EN_N; - writel(reg, &dp_regs->func_en2); - - return; -} - -void exynos_dp_config_interrupt(void) -{ - unsigned int reg; - - /* 0: mask, 1: unmask */ - reg = COMMON_INT_MASK_1; - writel(reg, &dp_regs->common_int_mask1); - - reg = COMMON_INT_MASK_2; - writel(reg, &dp_regs->common_int_mask2); - - reg = COMMON_INT_MASK_3; - writel(reg, &dp_regs->common_int_mask3); - - reg = COMMON_INT_MASK_4; - writel(reg, &dp_regs->common_int_mask4); - - reg = INT_STA_MASK; - writel(reg, &dp_regs->int_sta_mask); - - return; -} - -unsigned int exynos_dp_get_plug_in_status(void) -{ - unsigned int reg; - - reg = readl(&dp_regs->sys_ctl3); - if (reg & HPD_STATUS) - return 0; - - return -1; -} - -unsigned int exynos_dp_detect_hpd(void) -{ - int timeout_loop = DP_TIMEOUT_LOOP_COUNT; - - mdelay(2); - - while (exynos_dp_get_plug_in_status() != 0) { - if (timeout_loop == 0) - return -EINVAL; - mdelay(10); - timeout_loop--; - } - - return EXYNOS_DP_SUCCESS; -} - -unsigned int exynos_dp_start_aux_transaction(void) -{ - unsigned int reg; - unsigned int ret = 0; - unsigned int retry_cnt; - - /* Enable AUX CH operation */ - reg = readl(&dp_regs->aux_ch_ctl2); - reg |= AUX_EN; - writel(reg, &dp_regs->aux_ch_ctl2); - - retry_cnt = 10; - while (retry_cnt) { - reg = readl(&dp_regs->int_sta); - if (!(reg & RPLY_RECEIV)) { - if (retry_cnt == 0) { - printf("DP Reply Timeout!!\n"); - ret = -EAGAIN; - return ret; - } - mdelay(1); - retry_cnt--; - } else - break; - } - - /* Clear interrupt source for AUX CH command reply */ - writel(reg, &dp_regs->int_sta); - - /* Clear interrupt source for AUX CH access error */ - reg = readl(&dp_regs->int_sta); - if (reg & AUX_ERR) { - printf("DP Aux Access Error\n"); - writel(AUX_ERR, &dp_regs->int_sta); - ret = -EAGAIN; - return ret; - } - - /* Check AUX CH error access status */ - reg = readl(&dp_regs->aux_ch_sta); - if ((reg & AUX_STATUS_MASK) != 0) { - debug("DP AUX CH error happens: %x\n", reg & AUX_STATUS_MASK); - ret = -EAGAIN; - return ret; - } - - return EXYNOS_DP_SUCCESS; -} - -unsigned int exynos_dp_write_byte_to_dpcd(unsigned int reg_addr, - unsigned char data) -{ - unsigned int reg, ret; - - /* Clear AUX CH data buffer */ - reg = BUF_CLR; - writel(reg, &dp_regs->buffer_data_ctl); - - /* Select DPCD device address */ - reg = AUX_ADDR_7_0(reg_addr); - writel(reg, &dp_regs->aux_addr_7_0); - reg = AUX_ADDR_15_8(reg_addr); - writel(reg, &dp_regs->aux_addr_15_8); - reg = AUX_ADDR_19_16(reg_addr); - writel(reg, &dp_regs->aux_addr_19_16); - - /* Write data buffer */ - reg = (unsigned int)data; - writel(reg, &dp_regs->buf_data0); - - /* - * Set DisplayPort transaction and write 1 byte - * If bit 3 is 1, DisplayPort transaction. - * If Bit 3 is 0, I2C transaction. - */ - reg = AUX_TX_COMM_DP_TRANSACTION | AUX_TX_COMM_WRITE; - writel(reg, &dp_regs->aux_ch_ctl1); - - /* Start AUX transaction */ - ret = exynos_dp_start_aux_transaction(); - if (ret != EXYNOS_DP_SUCCESS) { - printf("DP Aux transaction failed\n"); - return ret; - } - - return ret; -} - -unsigned int exynos_dp_read_byte_from_dpcd(unsigned int reg_addr, - unsigned char *data) -{ - unsigned int reg; - int retval; - - /* Clear AUX CH data buffer */ - reg = BUF_CLR; - writel(reg, &dp_regs->buffer_data_ctl); - - /* Select DPCD device address */ - reg = AUX_ADDR_7_0(reg_addr); - writel(reg, &dp_regs->aux_addr_7_0); - reg = AUX_ADDR_15_8(reg_addr); - writel(reg, &dp_regs->aux_addr_15_8); - reg = AUX_ADDR_19_16(reg_addr); - writel(reg, &dp_regs->aux_addr_19_16); - - /* - * Set DisplayPort transaction and read 1 byte - * If bit 3 is 1, DisplayPort transaction. - * If Bit 3 is 0, I2C transaction. - */ - reg = AUX_TX_COMM_DP_TRANSACTION | AUX_TX_COMM_READ; - writel(reg, &dp_regs->aux_ch_ctl1); - - /* Start AUX transaction */ - retval = exynos_dp_start_aux_transaction(); - if (!retval) - debug("DP Aux Transaction fail!\n"); - - /* Read data buffer */ - reg = readl(&dp_regs->buf_data0); - *data = (unsigned char)(reg & 0xff); - - return retval; -} - -unsigned int exynos_dp_write_bytes_to_dpcd(unsigned int reg_addr, - unsigned int count, - unsigned char data[]) -{ - unsigned int reg; - unsigned int start_offset; - unsigned int cur_data_count; - unsigned int cur_data_idx; - unsigned int retry_cnt; - unsigned int ret = 0; - - /* Clear AUX CH data buffer */ - reg = BUF_CLR; - writel(reg, &dp_regs->buffer_data_ctl); - - start_offset = 0; - while (start_offset < count) { - /* Buffer size of AUX CH is 16 * 4bytes */ - if ((count - start_offset) > 16) - cur_data_count = 16; - else - cur_data_count = count - start_offset; - - retry_cnt = 5; - while (retry_cnt) { - /* Select DPCD device address */ - reg = AUX_ADDR_7_0(reg_addr + start_offset); - writel(reg, &dp_regs->aux_addr_7_0); - reg = AUX_ADDR_15_8(reg_addr + start_offset); - writel(reg, &dp_regs->aux_addr_15_8); - reg = AUX_ADDR_19_16(reg_addr + start_offset); - writel(reg, &dp_regs->aux_addr_19_16); - - for (cur_data_idx = 0; cur_data_idx < cur_data_count; - cur_data_idx++) { - reg = data[start_offset + cur_data_idx]; - writel(reg, (unsigned int)&dp_regs->buf_data0 + - (4 * cur_data_idx)); - } - /* - * Set DisplayPort transaction and write - * If bit 3 is 1, DisplayPort transaction. - * If Bit 3 is 0, I2C transaction. - */ - reg = AUX_LENGTH(cur_data_count) | - AUX_TX_COMM_DP_TRANSACTION | AUX_TX_COMM_WRITE; - writel(reg, &dp_regs->aux_ch_ctl1); - - /* Start AUX transaction */ - ret = exynos_dp_start_aux_transaction(); - if (ret != EXYNOS_DP_SUCCESS) { - if (retry_cnt == 0) { - printf("DP Aux Transaction failed\n"); - return ret; - } - retry_cnt--; - } else - break; - } - start_offset += cur_data_count; - } - - return ret; -} - -unsigned int exynos_dp_read_bytes_from_dpcd(unsigned int reg_addr, - unsigned int count, - unsigned char data[]) -{ - unsigned int reg; - unsigned int start_offset; - unsigned int cur_data_count; - unsigned int cur_data_idx; - unsigned int retry_cnt; - unsigned int ret = 0; - - /* Clear AUX CH data buffer */ - reg = BUF_CLR; - writel(reg, &dp_regs->buffer_data_ctl); - - start_offset = 0; - while (start_offset < count) { - /* Buffer size of AUX CH is 16 * 4bytes */ - if ((count - start_offset) > 16) - cur_data_count = 16; - else - cur_data_count = count - start_offset; - - retry_cnt = 5; - while (retry_cnt) { - /* Select DPCD device address */ - reg = AUX_ADDR_7_0(reg_addr + start_offset); - writel(reg, &dp_regs->aux_addr_7_0); - reg = AUX_ADDR_15_8(reg_addr + start_offset); - writel(reg, &dp_regs->aux_addr_15_8); - reg = AUX_ADDR_19_16(reg_addr + start_offset); - writel(reg, &dp_regs->aux_addr_19_16); - /* - * Set DisplayPort transaction and read - * If bit 3 is 1, DisplayPort transaction. - * If Bit 3 is 0, I2C transaction. - */ - reg = AUX_LENGTH(cur_data_count) | - AUX_TX_COMM_DP_TRANSACTION | AUX_TX_COMM_READ; - writel(reg, &dp_regs->aux_ch_ctl1); - - /* Start AUX transaction */ - ret = exynos_dp_start_aux_transaction(); - if (ret != EXYNOS_DP_SUCCESS) { - if (retry_cnt == 0) { - printf("DP Aux Transaction failed\n"); - return ret; - } - retry_cnt--; - } else - break; - } - - for (cur_data_idx = 0; cur_data_idx < cur_data_count; - cur_data_idx++) { - reg = readl((unsigned int)&dp_regs->buf_data0 + - 4 * cur_data_idx); - data[start_offset + cur_data_idx] = (unsigned char)reg; - } - - start_offset += cur_data_count; - } - - return ret; -} - -int exynos_dp_select_i2c_device(unsigned int device_addr, - unsigned int reg_addr) -{ - unsigned int reg; - int retval; - - /* Set EDID device address */ - reg = device_addr; - writel(reg, &dp_regs->aux_addr_7_0); - writel(0x0, &dp_regs->aux_addr_15_8); - writel(0x0, &dp_regs->aux_addr_19_16); - - /* Set offset from base address of EDID device */ - writel(reg_addr, &dp_regs->buf_data0); - - /* - * Set I2C transaction and write address - * If bit 3 is 1, DisplayPort transaction. - * If Bit 3 is 0, I2C transaction. - */ - reg = AUX_TX_COMM_I2C_TRANSACTION | AUX_TX_COMM_MOT | - AUX_TX_COMM_WRITE; - writel(reg, &dp_regs->aux_ch_ctl1); - - /* Start AUX transaction */ - retval = exynos_dp_start_aux_transaction(); - if (retval != 0) - printf("%s: DP Aux Transaction fail!\n", __func__); - - return retval; -} - -int exynos_dp_read_byte_from_i2c(unsigned int device_addr, - unsigned int reg_addr, - unsigned int *data) -{ - unsigned int reg; - int i; - int retval; - - for (i = 0; i < 10; i++) { - /* Clear AUX CH data buffer */ - reg = BUF_CLR; - writel(reg, &dp_regs->buffer_data_ctl); - - /* Select EDID device */ - retval = exynos_dp_select_i2c_device(device_addr, reg_addr); - if (retval != 0) { - printf("DP Select EDID device fail. retry !\n"); - continue; - } - - /* - * Set I2C transaction and read data - * If bit 3 is 1, DisplayPort transaction. - * If Bit 3 is 0, I2C transaction. - */ - reg = AUX_TX_COMM_I2C_TRANSACTION | - AUX_TX_COMM_READ; - writel(reg, &dp_regs->aux_ch_ctl1); - - /* Start AUX transaction */ - retval = exynos_dp_start_aux_transaction(); - if (retval != EXYNOS_DP_SUCCESS) - printf("%s: DP Aux Transaction fail!\n", __func__); - } - - /* Read data */ - if (retval == 0) - *data = readl(&dp_regs->buf_data0); - - return retval; -} - -int exynos_dp_read_bytes_from_i2c(unsigned int device_addr, - unsigned int reg_addr, unsigned int count, unsigned char edid[]) -{ - unsigned int reg; - unsigned int i, j; - unsigned int cur_data_idx; - unsigned int defer = 0; - int retval = 0; - - for (i = 0; i < count; i += 16) { /* use 16 burst */ - for (j = 0; j < 100; j++) { - /* Clear AUX CH data buffer */ - reg = BUF_CLR; - writel(reg, &dp_regs->buffer_data_ctl); - - /* Set normal AUX CH command */ - reg = readl(&dp_regs->aux_ch_ctl2); - reg &= ~ADDR_ONLY; - writel(reg, &dp_regs->aux_ch_ctl2); - - /* - * If Rx sends defer, Tx sends only reads - * request without sending addres - */ - if (!defer) - retval = - exynos_dp_select_i2c_device(device_addr, - reg_addr + i); - else - defer = 0; - - if (retval == EXYNOS_DP_SUCCESS) { - /* - * Set I2C transaction and write data - * If bit 3 is 1, DisplayPort transaction. - * If Bit 3 is 0, I2C transaction. - */ - reg = AUX_LENGTH(16) | - AUX_TX_COMM_I2C_TRANSACTION | - AUX_TX_COMM_READ; - writel(reg, &dp_regs->aux_ch_ctl1); - - /* Start AUX transaction */ - retval = exynos_dp_start_aux_transaction(); - if (retval == 0) - break; - else - printf("DP Aux Transaction fail!\n"); - } - /* Check if Rx sends defer */ - reg = readl(&dp_regs->aux_rx_comm); - if (reg == AUX_RX_COMM_AUX_DEFER || - reg == AUX_RX_COMM_I2C_DEFER) { - printf("DP Defer: %d\n", reg); - defer = 1; - } - } - - for (cur_data_idx = 0; cur_data_idx < 16; cur_data_idx++) { - reg = readl((unsigned int)&dp_regs->buf_data0 - + 4 * cur_data_idx); - edid[i + cur_data_idx] = (unsigned char)reg; - } - } - - return retval; -} - -void exynos_dp_reset_macro(void) -{ - unsigned int reg; - - reg = readl(&dp_regs->phy_test); - reg |= MACRO_RST; - writel(reg, &dp_regs->phy_test); - - /* 10 us is the minimum Macro reset time. */ - mdelay(1); - - reg &= ~MACRO_RST; - writel(reg, &dp_regs->phy_test); -} - -void exynos_dp_set_link_bandwidth(unsigned char bwtype) -{ - unsigned int reg; - - reg = (unsigned int)bwtype; - - /* Set bandwidth to 2.7G or 1.62G */ - if ((bwtype == DP_LANE_BW_1_62) || (bwtype == DP_LANE_BW_2_70)) - writel(reg, &dp_regs->link_bw_set); -} - -unsigned char exynos_dp_get_link_bandwidth(void) -{ - unsigned char ret; - unsigned int reg; - - reg = readl(&dp_regs->link_bw_set); - ret = (unsigned char)reg; - - return ret; -} - -void exynos_dp_set_lane_count(unsigned char count) -{ - unsigned int reg; - - reg = (unsigned int)count; - - if ((count == DP_LANE_CNT_1) || (count == DP_LANE_CNT_2) || - (count == DP_LANE_CNT_4)) - writel(reg, &dp_regs->lane_count_set); -} - -unsigned int exynos_dp_get_lane_count(void) -{ - unsigned int reg; - - reg = readl(&dp_regs->lane_count_set); - - return reg; -} - -unsigned char exynos_dp_get_lanex_pre_emphasis(unsigned char lanecnt) -{ - unsigned int reg_list[DP_LANE_CNT_4] = { - (unsigned int)&dp_regs->ln0_link_training_ctl, - (unsigned int)&dp_regs->ln1_link_training_ctl, - (unsigned int)&dp_regs->ln2_link_training_ctl, - (unsigned int)&dp_regs->ln3_link_training_ctl, - }; - - return readl(reg_list[lanecnt]); -} - -void exynos_dp_set_lanex_pre_emphasis(unsigned char request_val, - unsigned char lanecnt) -{ - unsigned int reg_list[DP_LANE_CNT_4] = { - (unsigned int)&dp_regs->ln0_link_training_ctl, - (unsigned int)&dp_regs->ln1_link_training_ctl, - (unsigned int)&dp_regs->ln2_link_training_ctl, - (unsigned int)&dp_regs->ln3_link_training_ctl, - }; - - writel(request_val, reg_list[lanecnt]); -} - -void exynos_dp_set_lane_pre_emphasis(unsigned int level, unsigned char lanecnt) -{ - unsigned char i; - unsigned int reg; - unsigned int reg_list[DP_LANE_CNT_4] = { - (unsigned int)&dp_regs->ln0_link_training_ctl, - (unsigned int)&dp_regs->ln1_link_training_ctl, - (unsigned int)&dp_regs->ln2_link_training_ctl, - (unsigned int)&dp_regs->ln3_link_training_ctl, - }; - unsigned int reg_shift[DP_LANE_CNT_4] = { - PRE_EMPHASIS_SET_0_SHIFT, - PRE_EMPHASIS_SET_1_SHIFT, - PRE_EMPHASIS_SET_2_SHIFT, - PRE_EMPHASIS_SET_3_SHIFT - }; - - for (i = 0; i < lanecnt; i++) { - reg = level << reg_shift[i]; - writel(reg, reg_list[i]); - } -} - -void exynos_dp_set_training_pattern(unsigned int pattern) -{ - unsigned int reg = 0; - - switch (pattern) { - case PRBS7: - reg = SCRAMBLING_ENABLE | LINK_QUAL_PATTERN_SET_PRBS7; - break; - case D10_2: - reg = SCRAMBLING_ENABLE | LINK_QUAL_PATTERN_SET_D10_2; - break; - case TRAINING_PTN1: - reg = SCRAMBLING_DISABLE | SW_TRAINING_PATTERN_SET_PTN1; - break; - case TRAINING_PTN2: - reg = SCRAMBLING_DISABLE | SW_TRAINING_PATTERN_SET_PTN2; - break; - case DP_NONE: - reg = SCRAMBLING_ENABLE | LINK_QUAL_PATTERN_SET_DISABLE | - SW_TRAINING_PATTERN_SET_NORMAL; - break; - default: - break; - } - - writel(reg, &dp_regs->training_ptn_set); -} - -void exynos_dp_enable_enhanced_mode(unsigned char enable) -{ - unsigned int reg; - - reg = readl(&dp_regs->sys_ctl4); - reg &= ~ENHANCED; - - if (enable) - reg |= ENHANCED; - - writel(reg, &dp_regs->sys_ctl4); -} - -void exynos_dp_enable_scrambling(unsigned int enable) -{ - unsigned int reg; - - reg = readl(&dp_regs->training_ptn_set); - reg &= ~(SCRAMBLING_DISABLE); - - if (!enable) - reg |= SCRAMBLING_DISABLE; - - writel(reg, &dp_regs->training_ptn_set); -} - -int exynos_dp_init_video(void) -{ - unsigned int reg; - - /* Clear VID_CLK_CHG[1] and VID_FORMAT_CHG[3] and VSYNC_DET[7] */ - reg = VSYNC_DET | VID_FORMAT_CHG | VID_CLK_CHG; - writel(reg, &dp_regs->common_int_sta1); - - /* I_STRM__CLK detect : DE_CTL : Auto detect */ - reg &= ~DET_CTRL; - writel(reg, &dp_regs->sys_ctl1); - - return 0; -} - -void exynos_dp_config_video_slave_mode(struct edp_video_info *video_info) -{ - unsigned int reg; - - /* Video Slave mode setting */ - reg = readl(&dp_regs->func_en1); - reg &= ~(MASTER_VID_FUNC_EN_N|SLAVE_VID_FUNC_EN_N); - reg |= MASTER_VID_FUNC_EN_N; - writel(reg, &dp_regs->func_en1); - - /* Configure Interlaced for slave mode video */ - reg = readl(&dp_regs->video_ctl10); - reg &= ~INTERACE_SCAN_CFG; - reg |= (video_info->interlaced << INTERACE_SCAN_CFG_SHIFT); - writel(reg, &dp_regs->video_ctl10); - - /* Configure V sync polarity for slave mode video */ - reg = readl(&dp_regs->video_ctl10); - reg &= ~VSYNC_POLARITY_CFG; - reg |= (video_info->v_sync_polarity << V_S_POLARITY_CFG_SHIFT); - writel(reg, &dp_regs->video_ctl10); - - /* Configure H sync polarity for slave mode video */ - reg = readl(&dp_regs->video_ctl10); - reg &= ~HSYNC_POLARITY_CFG; - reg |= (video_info->h_sync_polarity << H_S_POLARITY_CFG_SHIFT); - writel(reg, &dp_regs->video_ctl10); - - /* Set video mode to slave mode */ - reg = AUDIO_MODE_SPDIF_MODE | VIDEO_MODE_SLAVE_MODE; - writel(reg, &dp_regs->soc_general_ctl); -} - -void exynos_dp_set_video_color_format(struct edp_video_info *video_info) -{ - unsigned int reg; - - /* Configure the input color depth, color space, dynamic range */ - reg = (video_info->dynamic_range << IN_D_RANGE_SHIFT) | - (video_info->color_depth << IN_BPC_SHIFT) | - (video_info->color_space << IN_COLOR_F_SHIFT); - writel(reg, &dp_regs->video_ctl2); - - /* Set Input Color YCbCr Coefficients to ITU601 or ITU709 */ - reg = readl(&dp_regs->video_ctl3); - reg &= ~IN_YC_COEFFI_MASK; - if (video_info->ycbcr_coeff) - reg |= IN_YC_COEFFI_ITU709; - else - reg |= IN_YC_COEFFI_ITU601; - writel(reg, &dp_regs->video_ctl3); -} - -int exynos_dp_config_video_bist(struct edp_device_info *edp_info) -{ - unsigned int reg; - unsigned int bist_type = 0; - struct edp_video_info video_info = edp_info->video_info; - - /* For master mode, you don't need to set the video format */ - if (video_info.master_mode == 0) { - writel(TOTAL_LINE_CFG_L(edp_info->disp_info.v_total), - &dp_regs->total_ln_cfg_l); - writel(TOTAL_LINE_CFG_H(edp_info->disp_info.v_total), - &dp_regs->total_ln_cfg_h); - writel(ACTIVE_LINE_CFG_L(edp_info->disp_info.v_res), - &dp_regs->active_ln_cfg_l); - writel(ACTIVE_LINE_CFG_H(edp_info->disp_info.v_res), - &dp_regs->active_ln_cfg_h); - writel(edp_info->disp_info.v_sync_width, - &dp_regs->vsw_cfg); - writel(edp_info->disp_info.v_back_porch, - &dp_regs->vbp_cfg); - writel(edp_info->disp_info.v_front_porch, - &dp_regs->vfp_cfg); - - writel(TOTAL_PIXEL_CFG_L(edp_info->disp_info.h_total), - &dp_regs->total_pix_cfg_l); - writel(TOTAL_PIXEL_CFG_H(edp_info->disp_info.h_total), - &dp_regs->total_pix_cfg_h); - writel(ACTIVE_PIXEL_CFG_L(edp_info->disp_info.h_res), - &dp_regs->active_pix_cfg_l); - writel(ACTIVE_PIXEL_CFG_H(edp_info->disp_info.h_res), - &dp_regs->active_pix_cfg_h); - writel(H_F_PORCH_CFG_L(edp_info->disp_info.h_front_porch), - &dp_regs->hfp_cfg_l); - writel(H_F_PORCH_CFG_H(edp_info->disp_info.h_front_porch), - &dp_regs->hfp_cfg_h); - writel(H_SYNC_PORCH_CFG_L(edp_info->disp_info.h_sync_width), - &dp_regs->hsw_cfg_l); - writel(H_SYNC_PORCH_CFG_H(edp_info->disp_info.h_sync_width), - &dp_regs->hsw_cfg_h); - writel(H_B_PORCH_CFG_L(edp_info->disp_info.h_back_porch), - &dp_regs->hbp_cfg_l); - writel(H_B_PORCH_CFG_H(edp_info->disp_info.h_back_porch), - &dp_regs->hbp_cfg_h); - - /* - * Set SLAVE_I_SCAN_CFG[2], VSYNC_P_CFG[1], - * HSYNC_P_CFG[0] properly - */ - reg = (video_info.interlaced << INTERACE_SCAN_CFG_SHIFT | - video_info.v_sync_polarity << V_S_POLARITY_CFG_SHIFT | - video_info.h_sync_polarity << H_S_POLARITY_CFG_SHIFT); - writel(reg, &dp_regs->video_ctl10); - } - - /* BIST color bar width set--set to each bar is 32 pixel width */ - switch (video_info.bist_pattern) { - case COLORBAR_32: - bist_type = BIST_WIDTH_BAR_32_PIXEL | - BIST_TYPE_COLOR_BAR; - break; - case COLORBAR_64: - bist_type = BIST_WIDTH_BAR_64_PIXEL | - BIST_TYPE_COLOR_BAR; - break; - case WHITE_GRAY_BALCKBAR_32: - bist_type = BIST_WIDTH_BAR_32_PIXEL | - BIST_TYPE_WHITE_GRAY_BLACK_BAR; - break; - case WHITE_GRAY_BALCKBAR_64: - bist_type = BIST_WIDTH_BAR_64_PIXEL | - BIST_TYPE_WHITE_GRAY_BLACK_BAR; - break; - case MOBILE_WHITEBAR_32: - bist_type = BIST_WIDTH_BAR_32_PIXEL | - BIST_TYPE_MOBILE_WHITE_BAR; - break; - case MOBILE_WHITEBAR_64: - bist_type = BIST_WIDTH_BAR_64_PIXEL | - BIST_TYPE_MOBILE_WHITE_BAR; - break; - default: - return -1; - } - - reg = bist_type; - writel(reg, &dp_regs->video_ctl4); - - return 0; -} - -unsigned int exynos_dp_is_slave_video_stream_clock_on(void) -{ - unsigned int reg; - - /* Update Video stream clk detect status */ - reg = readl(&dp_regs->sys_ctl1); - writel(reg, &dp_regs->sys_ctl1); - - reg = readl(&dp_regs->sys_ctl1); - - if (!(reg & DET_STA)) { - debug("DP Input stream clock not detected.\n"); - return -EIO; - } - - return EXYNOS_DP_SUCCESS; -} - -void exynos_dp_set_video_cr_mn(unsigned int type, unsigned int m_value, - unsigned int n_value) -{ - unsigned int reg; - - if (type == REGISTER_M) { - reg = readl(&dp_regs->sys_ctl4); - reg |= FIX_M_VID; - writel(reg, &dp_regs->sys_ctl4); - reg = M_VID0_CFG(m_value); - writel(reg, &dp_regs->m_vid0); - reg = M_VID1_CFG(m_value); - writel(reg, &dp_regs->m_vid1); - reg = M_VID2_CFG(m_value); - writel(reg, &dp_regs->m_vid2); - - reg = N_VID0_CFG(n_value); - writel(reg, &dp_regs->n_vid0); - reg = N_VID1_CFG(n_value); - writel(reg, &dp_regs->n_vid1); - reg = N_VID2_CFG(n_value); - writel(reg, &dp_regs->n_vid2); - } else { - reg = readl(&dp_regs->sys_ctl4); - reg &= ~FIX_M_VID; - writel(reg, &dp_regs->sys_ctl4); - } -} - -void exynos_dp_set_video_timing_mode(unsigned int type) -{ - unsigned int reg; - - reg = readl(&dp_regs->video_ctl10); - reg &= ~FORMAT_SEL; - - if (type != VIDEO_TIMING_FROM_CAPTURE) - reg |= FORMAT_SEL; - - writel(reg, &dp_regs->video_ctl10); -} - -void exynos_dp_enable_video_master(unsigned int enable) -{ - unsigned int reg; - - reg = readl(&dp_regs->soc_general_ctl); - if (enable) { - reg &= ~VIDEO_MODE_MASK; - reg |= VIDEO_MASTER_MODE_EN | VIDEO_MODE_MASTER_MODE; - } else { - reg &= ~VIDEO_MODE_MASK; - reg |= VIDEO_MODE_SLAVE_MODE; - } - - writel(reg, &dp_regs->soc_general_ctl); -} - -void exynos_dp_start_video(void) -{ - unsigned int reg; - - /* Enable Video input and disable Mute */ - reg = readl(&dp_regs->video_ctl1); - reg |= VIDEO_EN; - writel(reg, &dp_regs->video_ctl1); -} - -unsigned int exynos_dp_is_video_stream_on(void) -{ - unsigned int reg; - - /* Update STRM_VALID */ - reg = readl(&dp_regs->sys_ctl3); - writel(reg, &dp_regs->sys_ctl3); - - reg = readl(&dp_regs->sys_ctl3); - if (!(reg & STRM_VALID)) - return -EIO; - - return EXYNOS_DP_SUCCESS; -} diff --git a/drivers/video/exynos_dp_lowlevel.h b/drivers/video/exynos_dp_lowlevel.h deleted file mode 100644 index 8651681..0000000 --- a/drivers/video/exynos_dp_lowlevel.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (C) 2012 Samsung Electronics - * - * Author: Donghwa Lee - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#ifndef _EXYNOS_EDP_LOWLEVEL_H -#define _EXYNOS_EDP_LOWLEVEL_H - -void exynos_dp_enable_video_bist(unsigned int enable); -void exynos_dp_enable_video_mute(unsigned int enable); -void exynos_dp_reset(void); -void exynos_dp_enable_sw_func(unsigned int enable); -unsigned int exynos_dp_set_analog_power_down(unsigned int block, u32 enable); -unsigned int exynos_dp_get_pll_lock_status(void); -int exynos_dp_init_analog_func(void); -void exynos_dp_init_hpd(void); -void exynos_dp_init_aux(void); -void exynos_dp_config_interrupt(void); -unsigned int exynos_dp_get_plug_in_status(void); -unsigned int exynos_dp_detect_hpd(void); -unsigned int exynos_dp_start_aux_transaction(void); -unsigned int exynos_dp_write_byte_to_dpcd(unsigned int reg_addr, - unsigned char data); -unsigned int exynos_dp_read_byte_from_dpcd(unsigned int reg_addr, - unsigned char *data); -unsigned int exynos_dp_write_bytes_to_dpcd(unsigned int reg_addr, - unsigned int count, - unsigned char data[]); -unsigned int exynos_dp_read_bytes_from_dpcd( unsigned int reg_addr, - unsigned int count, - unsigned char data[]); -int exynos_dp_select_i2c_device( unsigned int device_addr, - unsigned int reg_addr); -int exynos_dp_read_byte_from_i2c(unsigned int device_addr, - unsigned int reg_addr, unsigned int *data); -int exynos_dp_read_bytes_from_i2c(unsigned int device_addr, - unsigned int reg_addr, unsigned int count, - unsigned char edid[]); -void exynos_dp_reset_macro(void); -void exynos_dp_set_link_bandwidth(unsigned char bwtype); -unsigned char exynos_dp_get_link_bandwidth(void); -void exynos_dp_set_lane_count(unsigned char count); -unsigned int exynos_dp_get_lane_count(void); -unsigned char exynos_dp_get_lanex_pre_emphasis(unsigned char lanecnt); -void exynos_dp_set_lane_pre_emphasis(unsigned int level, - unsigned char lanecnt); -void exynos_dp_set_lanex_pre_emphasis(unsigned char request_val, - unsigned char lanecnt); -void exynos_dp_set_training_pattern(unsigned int pattern); -void exynos_dp_enable_enhanced_mode(unsigned char enable); -void exynos_dp_enable_scrambling(unsigned int enable); -int exynos_dp_init_video(void); -void exynos_dp_config_video_slave_mode(struct edp_video_info *video_info); -void exynos_dp_set_video_color_format(struct edp_video_info *video_info); -int exynos_dp_config_video_bist(struct edp_device_info *edp_info); -unsigned int exynos_dp_is_slave_video_stream_clock_on(void); -void exynos_dp_set_video_cr_mn(unsigned int type, unsigned int m_value, - unsigned int n_value); -void exynos_dp_set_video_timing_mode(unsigned int type); -void exynos_dp_enable_video_master(unsigned int enable); -void exynos_dp_start_video(void); -unsigned int exynos_dp_is_video_stream_on(void); -void exynos_dp_set_base_addr(void); - -#endif /* _EXYNOS_DP_LOWLEVEL_H */ diff --git a/drivers/video/exynos_fb.c b/drivers/video/exynos_fb.c deleted file mode 100644 index 69edc3a..0000000 --- a/drivers/video/exynos_fb.c +++ /dev/null @@ -1,330 +0,0 @@ -/* - * Copyright (C) 2012 Samsung Electronics - * - * Author: InKi Dae - * Author: Donghwa Lee - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "exynos_fb.h" - -DECLARE_GLOBAL_DATA_PTR; - -static unsigned int panel_width, panel_height; - -#if CONFIG_IS_ENABLED(OF_CONTROL) -vidinfo_t panel_info = { - /* - * Insert a value here so that we don't end up in the BSS - * Reference: drivers/video/tegra.c - */ - .vl_col = -1, -}; -#endif - -ushort *configuration_get_cmap(void) -{ -#if defined(CONFIG_LCD_LOGO) - return bmp_logo_palette; -#else - return NULL; -#endif -} - -static void exynos_lcd_init_mem(void *lcdbase, vidinfo_t *vid) -{ - unsigned long palette_size; - unsigned int fb_size; - - fb_size = vid->vl_row * vid->vl_col * (NBITS(vid->vl_bpix) >> 3); - - palette_size = NBITS(vid->vl_bpix) == 8 ? 256 : 16; - - exynos_fimd_lcd_init_mem((unsigned long)lcdbase, - (unsigned long)fb_size, palette_size); -} - -static void exynos_lcd_init(vidinfo_t *vid) -{ - exynos_fimd_lcd_init(vid); - - /* Enable flushing after LCD writes if requested */ - lcd_set_flush_dcache(1); -} - -__weak void exynos_cfg_lcd_gpio(void) -{ -} - -__weak void exynos_backlight_on(unsigned int onoff) -{ -} - -__weak void exynos_reset_lcd(void) -{ -} - -__weak void exynos_lcd_power_on(void) -{ -} - -__weak void exynos_cfg_ldo(void) -{ -} - -__weak void exynos_enable_ldo(unsigned int onoff) -{ -} - -__weak void exynos_backlight_reset(void) -{ -} - -__weak int exynos_lcd_misc_init(vidinfo_t *vid) -{ - return 0; -} - -static void lcd_panel_on(vidinfo_t *vid) -{ - struct gpio_desc pwm_out_gpio; - struct gpio_desc bl_en_gpio; - unsigned int node; - - udelay(vid->init_delay); - - exynos_backlight_reset(); - - exynos_cfg_lcd_gpio(); - - exynos_lcd_power_on(); - - udelay(vid->power_on_delay); - - if (vid->dp_enabled) - exynos_init_dp(); - - exynos_reset_lcd(); - - udelay(vid->reset_delay); - - exynos_backlight_on(1); - -#if CONFIG_IS_ENABLED(OF_CONTROL) - node = fdtdec_next_compatible(gd->fdt_blob, 0, - COMPAT_SAMSUNG_EXYNOS_FIMD); - if (node <= 0) { - debug("FIMD: Can't get device node for FIMD\n"); - return; - } - gpio_request_by_name_nodev(gd->fdt_blob, node, "samsung,pwm-out-gpio", - 0, &pwm_out_gpio, - GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE); - - gpio_request_by_name_nodev(gd->fdt_blob, node, "samsung,bl-en-gpio", 0, - &bl_en_gpio, - GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE); - -#endif - exynos_cfg_ldo(); - - exynos_enable_ldo(1); - - if (vid->mipi_enabled) - exynos_mipi_dsi_init(); -} - -#if CONFIG_IS_ENABLED(OF_CONTROL) -int exynos_lcd_early_init(const void *blob) -{ - unsigned int node; - node = fdtdec_next_compatible(blob, 0, COMPAT_SAMSUNG_EXYNOS_FIMD); - if (node <= 0) { - debug("exynos_fb: Can't get device node for fimd\n"); - return -ENODEV; - } - - panel_info.vl_col = fdtdec_get_int(blob, node, "samsung,vl-col", 0); - if (panel_info.vl_col == 0) { - debug("Can't get XRES\n"); - return -ENXIO; - } - - panel_info.vl_row = fdtdec_get_int(blob, node, "samsung,vl-row", 0); - if (panel_info.vl_row == 0) { - debug("Can't get YRES\n"); - return -ENXIO; - } - - panel_info.vl_width = fdtdec_get_int(blob, node, - "samsung,vl-width", 0); - - panel_info.vl_height = fdtdec_get_int(blob, node, - "samsung,vl-height", 0); - - panel_info.vl_freq = fdtdec_get_int(blob, node, "samsung,vl-freq", 0); - if (panel_info.vl_freq == 0) { - debug("Can't get refresh rate\n"); - return -ENXIO; - } - - if (fdtdec_get_bool(blob, node, "samsung,vl-clkp")) - panel_info.vl_clkp = CONFIG_SYS_LOW; - - if (fdtdec_get_bool(blob, node, "samsung,vl-oep")) - panel_info.vl_oep = CONFIG_SYS_LOW; - - if (fdtdec_get_bool(blob, node, "samsung,vl-hsp")) - panel_info.vl_hsp = CONFIG_SYS_LOW; - - if (fdtdec_get_bool(blob, node, "samsung,vl-vsp")) - panel_info.vl_vsp = CONFIG_SYS_LOW; - - if (fdtdec_get_bool(blob, node, "samsung,vl-dp")) - panel_info.vl_dp = CONFIG_SYS_LOW; - - panel_info.vl_bpix = fdtdec_get_int(blob, node, "samsung,vl-bpix", 0); - if (panel_info.vl_bpix == 0) { - debug("Can't get bits per pixel\n"); - return -ENXIO; - } - - panel_info.vl_hspw = fdtdec_get_int(blob, node, "samsung,vl-hspw", 0); - if (panel_info.vl_hspw == 0) { - debug("Can't get hsync width\n"); - return -ENXIO; - } - - panel_info.vl_hfpd = fdtdec_get_int(blob, node, "samsung,vl-hfpd", 0); - if (panel_info.vl_hfpd == 0) { - debug("Can't get right margin\n"); - return -ENXIO; - } - - panel_info.vl_hbpd = (u_char)fdtdec_get_int(blob, node, - "samsung,vl-hbpd", 0); - if (panel_info.vl_hbpd == 0) { - debug("Can't get left margin\n"); - return -ENXIO; - } - - panel_info.vl_vspw = (u_char)fdtdec_get_int(blob, node, - "samsung,vl-vspw", 0); - if (panel_info.vl_vspw == 0) { - debug("Can't get vsync width\n"); - return -ENXIO; - } - - panel_info.vl_vfpd = fdtdec_get_int(blob, node, - "samsung,vl-vfpd", 0); - if (panel_info.vl_vfpd == 0) { - debug("Can't get lower margin\n"); - return -ENXIO; - } - - panel_info.vl_vbpd = fdtdec_get_int(blob, node, "samsung,vl-vbpd", 0); - if (panel_info.vl_vbpd == 0) { - debug("Can't get upper margin\n"); - return -ENXIO; - } - - panel_info.vl_cmd_allow_len = fdtdec_get_int(blob, node, - "samsung,vl-cmd-allow-len", 0); - - panel_info.win_id = fdtdec_get_int(blob, node, "samsung,winid", 0); - panel_info.init_delay = fdtdec_get_int(blob, node, - "samsung,init-delay", 0); - panel_info.power_on_delay = fdtdec_get_int(blob, node, - "samsung,power-on-delay", 0); - panel_info.reset_delay = fdtdec_get_int(blob, node, - "samsung,reset-delay", 0); - panel_info.interface_mode = fdtdec_get_int(blob, node, - "samsung,interface-mode", 0); - panel_info.mipi_enabled = fdtdec_get_int(blob, node, - "samsung,mipi-enabled", 0); - panel_info.dp_enabled = fdtdec_get_int(blob, node, - "samsung,dp-enabled", 0); - panel_info.cs_setup = fdtdec_get_int(blob, node, - "samsung,cs-setup", 0); - panel_info.wr_setup = fdtdec_get_int(blob, node, - "samsung,wr-setup", 0); - panel_info.wr_act = fdtdec_get_int(blob, node, "samsung,wr-act", 0); - panel_info.wr_hold = fdtdec_get_int(blob, node, "samsung,wr-hold", 0); - - panel_info.logo_on = fdtdec_get_int(blob, node, "samsung,logo-on", 0); - if (panel_info.logo_on) { - panel_info.logo_width = fdtdec_get_int(blob, node, - "samsung,logo-width", 0); - panel_info.logo_height = fdtdec_get_int(blob, node, - "samsung,logo-height", 0); - panel_info.logo_addr = fdtdec_get_int(blob, node, - "samsung,logo-addr", 0); - } - - panel_info.rgb_mode = fdtdec_get_int(blob, node, - "samsung,rgb-mode", 0); - panel_info.pclk_name = fdtdec_get_int(blob, node, - "samsung,pclk-name", 0); - panel_info.sclk_div = fdtdec_get_int(blob, node, - "samsung,sclk-div", 0); - panel_info.dual_lcd_enabled = fdtdec_get_int(blob, node, - "samsung,dual-lcd-enabled", 0); - - return 0; -} -#endif - -void lcd_ctrl_init(void *lcdbase) -{ - set_system_display_ctrl(); - set_lcd_clk(); - -#if CONFIG_IS_ENABLED(OF_CONTROL) -#ifdef CONFIG_EXYNOS_MIPI_DSIM - exynos_init_dsim_platform_data(&panel_info); -#endif - exynos_lcd_misc_init(&panel_info); -#else - /* initialize parameters which is specific to panel. */ - init_panel_info(&panel_info); -#endif - - panel_width = panel_info.vl_width; - panel_height = panel_info.vl_height; - - exynos_lcd_init_mem(lcdbase, &panel_info); - - exynos_lcd_init(&panel_info); -} - -void lcd_enable(void) -{ - if (panel_info.logo_on) { - memset((void *) gd->fb_base, 0, panel_width * panel_height * - (NBITS(panel_info.vl_bpix) >> 3)); - } - - lcd_panel_on(&panel_info); -} - -/* dummy function */ -void lcd_setcolreg(ushort regno, ushort red, ushort green, ushort blue) -{ - return; -} diff --git a/drivers/video/exynos_fb.h b/drivers/video/exynos_fb.h deleted file mode 100644 index 2c2f94b..0000000 --- a/drivers/video/exynos_fb.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (C) 2012 Samsung Electronics - * - * Author: InKi Dae - * Author: Donghwa Lee - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#ifndef _EXYNOS_FB_H_ -#define _EXYNOS_FB_H_ - -#include - -#define MAX_CLOCK (86 * 1000000) - -enum exynos_cpu_auto_cmd_rate { - DISABLE_AUTO_FRM, - PER_TWO_FRM, - PER_FOUR_FRM, - PER_SIX_FRM, - PER_EIGHT_FRM, - PER_TEN_FRM, - PER_TWELVE_FRM, - PER_FOURTEEN_FRM, - PER_SIXTEEN_FRM, - PER_EIGHTEEN_FRM, - PER_TWENTY_FRM, - PER_TWENTY_TWO_FRM, - PER_TWENTY_FOUR_FRM, - PER_TWENTY_SIX_FRM, - PER_TWENTY_EIGHT_FRM, - PER_THIRTY_FRM, -}; - -void exynos_fimd_lcd_init_mem(unsigned long screen_base, unsigned long fb_size, - unsigned long palette_size); -void exynos_fimd_lcd_init(vidinfo_t *vid); -unsigned long exynos_fimd_calc_fbsize(void); - -#endif diff --git a/drivers/video/exynos_fimd.c b/drivers/video/exynos_fimd.c deleted file mode 100644 index ac001a8..0000000 --- a/drivers/video/exynos_fimd.c +++ /dev/null @@ -1,409 +0,0 @@ -/* - * Copyright (C) 2012 Samsung Electronics - * - * Author: InKi Dae - * Author: Donghwa Lee - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "exynos_fb.h" - -DECLARE_GLOBAL_DATA_PTR; - -static unsigned long *lcd_base_addr; -static vidinfo_t *pvid; -static struct exynos_fb *fimd_ctrl; - -void exynos_fimd_lcd_init_mem(u_long screen_base, u_long fb_size, - u_long palette_size) -{ - lcd_base_addr = (unsigned long *)screen_base; -} - -static void exynos_fimd_set_dualrgb(unsigned int enabled) -{ - unsigned int cfg = 0; - - if (enabled) { - cfg = EXYNOS_DUALRGB_BYPASS_DUAL | EXYNOS_DUALRGB_LINESPLIT | - EXYNOS_DUALRGB_VDEN_EN_ENABLE; - - /* in case of Line Split mode, MAIN_CNT doesn't neet to set. */ - cfg |= EXYNOS_DUALRGB_SUB_CNT(pvid->vl_col / 2) | - EXYNOS_DUALRGB_MAIN_CNT(0); - } - - writel(cfg, &fimd_ctrl->dualrgb); -} - -static void exynos_fimd_set_dp_clkcon(unsigned int enabled) -{ - unsigned int cfg = 0; - - if (enabled) - cfg = EXYNOS_DP_CLK_ENABLE; - - writel(cfg, &fimd_ctrl->dp_mie_clkcon); -} - -static void exynos_fimd_set_par(unsigned int win_id) -{ - unsigned int cfg = 0; - - /* set window control */ - cfg = readl((unsigned int)&fimd_ctrl->wincon0 + - EXYNOS_WINCON(win_id)); - - cfg &= ~(EXYNOS_WINCON_BITSWP_ENABLE | EXYNOS_WINCON_BYTESWP_ENABLE | - EXYNOS_WINCON_HAWSWP_ENABLE | EXYNOS_WINCON_WSWP_ENABLE | - EXYNOS_WINCON_BURSTLEN_MASK | EXYNOS_WINCON_BPPMODE_MASK | - EXYNOS_WINCON_INRGB_MASK | EXYNOS_WINCON_DATAPATH_MASK); - - /* DATAPATH is DMA */ - cfg |= EXYNOS_WINCON_DATAPATH_DMA; - - cfg |= EXYNOS_WINCON_HAWSWP_ENABLE; - - /* dma burst is 16 */ - cfg |= EXYNOS_WINCON_BURSTLEN_16WORD; - - switch (pvid->vl_bpix) { - case 4: - cfg |= EXYNOS_WINCON_BPPMODE_16BPP_565; - break; - default: - cfg |= EXYNOS_WINCON_BPPMODE_24BPP_888; - break; - } - - writel(cfg, (unsigned int)&fimd_ctrl->wincon0 + - EXYNOS_WINCON(win_id)); - - /* set window position to x=0, y=0*/ - cfg = EXYNOS_VIDOSD_LEFT_X(0) | EXYNOS_VIDOSD_TOP_Y(0); - writel(cfg, (unsigned int)&fimd_ctrl->vidosd0a + - EXYNOS_VIDOSD(win_id)); - - cfg = EXYNOS_VIDOSD_RIGHT_X(pvid->vl_col - 1) | - EXYNOS_VIDOSD_BOTTOM_Y(pvid->vl_row - 1) | - EXYNOS_VIDOSD_RIGHT_X_E(1) | - EXYNOS_VIDOSD_BOTTOM_Y_E(0); - - writel(cfg, (unsigned int)&fimd_ctrl->vidosd0b + - EXYNOS_VIDOSD(win_id)); - - /* set window size for window0*/ - cfg = EXYNOS_VIDOSD_SIZE(pvid->vl_col * pvid->vl_row); - writel(cfg, (unsigned int)&fimd_ctrl->vidosd0c + - EXYNOS_VIDOSD(win_id)); -} - -static void exynos_fimd_set_buffer_address(unsigned int win_id) -{ - unsigned long start_addr, end_addr; - - start_addr = (unsigned long)lcd_base_addr; - end_addr = start_addr + ((pvid->vl_col * (NBITS(pvid->vl_bpix) / 8)) * - pvid->vl_row); - - writel(start_addr, (unsigned int)&fimd_ctrl->vidw00add0b0 + - EXYNOS_BUFFER_OFFSET(win_id)); - writel(end_addr, (unsigned int)&fimd_ctrl->vidw00add1b0 + - EXYNOS_BUFFER_OFFSET(win_id)); -} - -static void exynos_fimd_set_clock(vidinfo_t *pvid) -{ - unsigned int cfg = 0, div = 0, remainder, remainder_div; - unsigned long pixel_clock; - unsigned long long src_clock; - - if (pvid->dual_lcd_enabled) { - pixel_clock = pvid->vl_freq * - (pvid->vl_hspw + pvid->vl_hfpd + - pvid->vl_hbpd + pvid->vl_col / 2) * - (pvid->vl_vspw + pvid->vl_vfpd + - pvid->vl_vbpd + pvid->vl_row); - } else if (pvid->interface_mode == FIMD_CPU_INTERFACE) { - pixel_clock = pvid->vl_freq * - pvid->vl_width * pvid->vl_height * - (pvid->cs_setup + pvid->wr_setup + - pvid->wr_act + pvid->wr_hold + 1); - } else { - pixel_clock = pvid->vl_freq * - (pvid->vl_hspw + pvid->vl_hfpd + - pvid->vl_hbpd + pvid->vl_col) * - (pvid->vl_vspw + pvid->vl_vfpd + - pvid->vl_vbpd + pvid->vl_row); - } - - cfg = readl(&fimd_ctrl->vidcon0); - cfg &= ~(EXYNOS_VIDCON0_CLKSEL_MASK | EXYNOS_VIDCON0_CLKVALUP_MASK | - EXYNOS_VIDCON0_CLKVAL_F(0xFF) | EXYNOS_VIDCON0_VCLKEN_MASK | - EXYNOS_VIDCON0_CLKDIR_MASK); - cfg |= (EXYNOS_VIDCON0_CLKSEL_SCLK | EXYNOS_VIDCON0_CLKVALUP_ALWAYS | - EXYNOS_VIDCON0_VCLKEN_NORMAL | EXYNOS_VIDCON0_CLKDIR_DIVIDED); - - src_clock = (unsigned long long) get_lcd_clk(); - - /* get quotient and remainder. */ - remainder = do_div(src_clock, pixel_clock); - div = src_clock; - - remainder *= 10; - remainder_div = remainder / pixel_clock; - - /* round about one places of decimals. */ - if (remainder_div >= 5) - div++; - - /* in case of dual lcd mode. */ - if (pvid->dual_lcd_enabled) - div--; - - cfg |= EXYNOS_VIDCON0_CLKVAL_F(div - 1); - writel(cfg, &fimd_ctrl->vidcon0); -} - -void exynos_set_trigger(void) -{ - unsigned int cfg = 0; - - cfg = readl(&fimd_ctrl->trigcon); - - cfg |= (EXYNOS_I80SOFT_TRIG_EN | EXYNOS_I80START_TRIG); - - writel(cfg, &fimd_ctrl->trigcon); -} - -int exynos_is_i80_frame_done(void) -{ - unsigned int cfg = 0; - int status; - - cfg = readl(&fimd_ctrl->trigcon); - - /* frame done func is valid only when TRIMODE[0] is set to 1. */ - status = (cfg & EXYNOS_I80STATUS_TRIG_DONE) == - EXYNOS_I80STATUS_TRIG_DONE; - - return status; -} - -static void exynos_fimd_lcd_on(void) -{ - unsigned int cfg = 0; - - /* display on */ - cfg = readl(&fimd_ctrl->vidcon0); - cfg |= (EXYNOS_VIDCON0_ENVID_ENABLE | EXYNOS_VIDCON0_ENVID_F_ENABLE); - writel(cfg, &fimd_ctrl->vidcon0); -} - -static void exynos_fimd_window_on(unsigned int win_id) -{ - unsigned int cfg = 0; - - /* enable window */ - cfg = readl((unsigned int)&fimd_ctrl->wincon0 + - EXYNOS_WINCON(win_id)); - cfg |= EXYNOS_WINCON_ENWIN_ENABLE; - writel(cfg, (unsigned int)&fimd_ctrl->wincon0 + - EXYNOS_WINCON(win_id)); - - cfg = readl(&fimd_ctrl->winshmap); - cfg |= EXYNOS_WINSHMAP_CH_ENABLE(win_id); - writel(cfg, &fimd_ctrl->winshmap); -} - -void exynos_fimd_lcd_off(void) -{ - unsigned int cfg = 0; - - cfg = readl(&fimd_ctrl->vidcon0); - cfg &= (EXYNOS_VIDCON0_ENVID_DISABLE | EXYNOS_VIDCON0_ENVID_F_DISABLE); - writel(cfg, &fimd_ctrl->vidcon0); -} - -void exynos_fimd_window_off(unsigned int win_id) -{ - unsigned int cfg = 0; - - cfg = readl((unsigned int)&fimd_ctrl->wincon0 + - EXYNOS_WINCON(win_id)); - cfg &= EXYNOS_WINCON_ENWIN_DISABLE; - writel(cfg, (unsigned int)&fimd_ctrl->wincon0 + - EXYNOS_WINCON(win_id)); - - cfg = readl(&fimd_ctrl->winshmap); - cfg &= ~EXYNOS_WINSHMAP_CH_DISABLE(win_id); - writel(cfg, &fimd_ctrl->winshmap); -} - -#if CONFIG_IS_ENABLED(OF_CONTROL) -/* -* The reset value for FIMD SYSMMU register MMU_CTRL is 3 -* on Exynos5420 and newer versions. -* This means FIMD SYSMMU is on by default on Exynos5420 -* and newer versions. -* Since in u-boot we don't use SYSMMU, we should disable -* those FIMD SYSMMU. -* Note that there are 2 SYSMMU for FIMD: m0 and m1. -* m0 handles windows 0 and 4, and m1 handles windows 1, 2 and 3. -* We disable both of them here. -*/ -void exynos_fimd_disable_sysmmu(void) -{ - u32 *sysmmufimd; - unsigned int node; - int node_list[2]; - int count; - int i; - - count = fdtdec_find_aliases_for_id(gd->fdt_blob, "fimd", - COMPAT_SAMSUNG_EXYNOS_SYSMMU, node_list, 2); - for (i = 0; i < count; i++) { - node = node_list[i]; - if (node <= 0) { - debug("Can't get device node for fimd sysmmu\n"); - return; - } - - sysmmufimd = (u32 *)fdtdec_get_addr(gd->fdt_blob, node, "reg"); - if (!sysmmufimd) { - debug("Can't get base address for sysmmu fimdm0"); - return; - } - - writel(0x0, sysmmufimd); - } -} -#endif - -void exynos_fimd_lcd_init(vidinfo_t *vid) -{ - unsigned int cfg = 0, rgb_mode; - unsigned int offset; -#if CONFIG_IS_ENABLED(OF_CONTROL) - unsigned int node; - - node = fdtdec_next_compatible(gd->fdt_blob, - 0, COMPAT_SAMSUNG_EXYNOS_FIMD); - if (node <= 0) - debug("exynos_fb: Can't get device node for fimd\n"); - - fimd_ctrl = (struct exynos_fb *)fdtdec_get_addr(gd->fdt_blob, - node, "reg"); - if (fimd_ctrl == NULL) - debug("Can't get the FIMD base address\n"); - - if (fdtdec_get_bool(gd->fdt_blob, node, "samsung,disable-sysmmu")) - exynos_fimd_disable_sysmmu(); - -#else - fimd_ctrl = (struct exynos_fb *)samsung_get_base_fimd(); -#endif - - offset = exynos_fimd_get_base_offset(); - - /* store panel info to global variable */ - pvid = vid; - - rgb_mode = vid->rgb_mode; - - if (vid->interface_mode == FIMD_RGB_INTERFACE) { - cfg |= EXYNOS_VIDCON0_VIDOUT_RGB; - writel(cfg, &fimd_ctrl->vidcon0); - - cfg = readl(&fimd_ctrl->vidcon2); - cfg &= ~(EXYNOS_VIDCON2_WB_MASK | - EXYNOS_VIDCON2_TVFORMATSEL_MASK | - EXYNOS_VIDCON2_TVFORMATSEL_YUV_MASK); - cfg |= EXYNOS_VIDCON2_WB_DISABLE; - writel(cfg, &fimd_ctrl->vidcon2); - - /* set polarity */ - cfg = 0; - if (!pvid->vl_clkp) - cfg |= EXYNOS_VIDCON1_IVCLK_RISING_EDGE; - if (!pvid->vl_hsp) - cfg |= EXYNOS_VIDCON1_IHSYNC_INVERT; - if (!pvid->vl_vsp) - cfg |= EXYNOS_VIDCON1_IVSYNC_INVERT; - if (!pvid->vl_dp) - cfg |= EXYNOS_VIDCON1_IVDEN_INVERT; - - writel(cfg, (unsigned int)&fimd_ctrl->vidcon1 + offset); - - /* set timing */ - cfg = EXYNOS_VIDTCON0_VFPD(pvid->vl_vfpd - 1); - cfg |= EXYNOS_VIDTCON0_VBPD(pvid->vl_vbpd - 1); - cfg |= EXYNOS_VIDTCON0_VSPW(pvid->vl_vspw - 1); - writel(cfg, (unsigned int)&fimd_ctrl->vidtcon0 + offset); - - cfg = EXYNOS_VIDTCON1_HFPD(pvid->vl_hfpd - 1); - cfg |= EXYNOS_VIDTCON1_HBPD(pvid->vl_hbpd - 1); - cfg |= EXYNOS_VIDTCON1_HSPW(pvid->vl_hspw - 1); - - writel(cfg, (unsigned int)&fimd_ctrl->vidtcon1 + offset); - - /* set lcd size */ - cfg = EXYNOS_VIDTCON2_HOZVAL(pvid->vl_col - 1) | - EXYNOS_VIDTCON2_LINEVAL(pvid->vl_row - 1) | - EXYNOS_VIDTCON2_HOZVAL_E(pvid->vl_col - 1) | - EXYNOS_VIDTCON2_LINEVAL_E(pvid->vl_row - 1); - - writel(cfg, (unsigned int)&fimd_ctrl->vidtcon2 + offset); - } - - /* set display mode */ - cfg = readl(&fimd_ctrl->vidcon0); - cfg &= ~EXYNOS_VIDCON0_PNRMODE_MASK; - cfg |= (rgb_mode << EXYNOS_VIDCON0_PNRMODE_SHIFT); - writel(cfg, &fimd_ctrl->vidcon0); - - /* set par */ - exynos_fimd_set_par(pvid->win_id); - - /* set memory address */ - exynos_fimd_set_buffer_address(pvid->win_id); - - /* set buffer size */ - cfg = EXYNOS_VIDADDR_PAGEWIDTH(pvid->vl_col * NBITS(pvid->vl_bpix) / 8) | - EXYNOS_VIDADDR_PAGEWIDTH_E(pvid->vl_col * NBITS(pvid->vl_bpix) / 8) | - EXYNOS_VIDADDR_OFFSIZE(0) | - EXYNOS_VIDADDR_OFFSIZE_E(0); - - writel(cfg, (unsigned int)&fimd_ctrl->vidw00add2 + - EXYNOS_BUFFER_SIZE(pvid->win_id)); - - /* set clock */ - exynos_fimd_set_clock(pvid); - - /* set rgb mode to dual lcd. */ - exynos_fimd_set_dualrgb(pvid->dual_lcd_enabled); - - /* display on */ - exynos_fimd_lcd_on(); - - /* window on */ - exynos_fimd_window_on(pvid->win_id); - - exynos_fimd_set_dp_clkcon(pvid->dp_enabled); -} - -unsigned long exynos_fimd_calc_fbsize(void) -{ - return pvid->vl_col * pvid->vl_row * (NBITS(pvid->vl_bpix) / 8); -} diff --git a/drivers/video/exynos_mipi_dsi.c b/drivers/video/exynos_mipi_dsi.c deleted file mode 100644 index b597acc..0000000 --- a/drivers/video/exynos_mipi_dsi.c +++ /dev/null @@ -1,337 +0,0 @@ -/* - * Copyright (C) 2012 Samsung Electronics - * - * Author: InKi Dae - * Author: Donghwa Lee - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "exynos_mipi_dsi_lowlevel.h" -#include "exynos_mipi_dsi_common.h" - -#define master_to_driver(a) (a->dsim_lcd_drv) -#define master_to_device(a) (a->dsim_lcd_dev) - -DECLARE_GLOBAL_DATA_PTR; - -static struct exynos_platform_mipi_dsim *dsim_pd; -#if CONFIG_IS_ENABLED(OF_CONTROL) -static struct mipi_dsim_config dsim_config_dt; -static struct exynos_platform_mipi_dsim dsim_platform_data_dt; -static struct mipi_dsim_lcd_device mipi_lcd_device_dt; -#endif - -struct mipi_dsim_ddi { - int bus_id; - struct list_head list; - struct mipi_dsim_lcd_device *dsim_lcd_dev; - struct mipi_dsim_lcd_driver *dsim_lcd_drv; -}; - -static LIST_HEAD(dsim_ddi_list); -static LIST_HEAD(dsim_lcd_dev_list); - -int exynos_mipi_dsi_register_lcd_device(struct mipi_dsim_lcd_device *lcd_dev) -{ - struct mipi_dsim_ddi *dsim_ddi; - - if (!lcd_dev) { - debug("mipi_dsim_lcd_device is NULL.\n"); - return -EFAULT; - } - - if (!lcd_dev->name) { - debug("dsim_lcd_device name is NULL.\n"); - return -EFAULT; - } - - dsim_ddi = kzalloc(sizeof(struct mipi_dsim_ddi), GFP_KERNEL); - if (!dsim_ddi) { - debug("failed to allocate dsim_ddi object.\n"); - return -EFAULT; - } - - dsim_ddi->dsim_lcd_dev = lcd_dev; - - list_add_tail(&dsim_ddi->list, &dsim_ddi_list); - - return 0; -} - -struct mipi_dsim_ddi - *exynos_mipi_dsi_find_lcd_device(struct mipi_dsim_lcd_driver *lcd_drv) -{ - struct mipi_dsim_ddi *dsim_ddi; - struct mipi_dsim_lcd_device *lcd_dev; - - list_for_each_entry(dsim_ddi, &dsim_ddi_list, list) { - lcd_dev = dsim_ddi->dsim_lcd_dev; - if (!lcd_dev) - continue; - - if (lcd_drv->id >= 0) { - if ((strcmp(lcd_drv->name, lcd_dev->name)) == 0 && - lcd_drv->id == lcd_dev->id) { - /** - * bus_id would be used to identify - * connected bus. - */ - dsim_ddi->bus_id = lcd_dev->bus_id; - - return dsim_ddi; - } - } else { - if ((strcmp(lcd_drv->name, lcd_dev->name)) == 0) { - /** - * bus_id would be used to identify - * connected bus. - */ - dsim_ddi->bus_id = lcd_dev->bus_id; - - return dsim_ddi; - } - } - - kfree(dsim_ddi); - list_del(&dsim_ddi_list); - } - - return NULL; -} - -int exynos_mipi_dsi_register_lcd_driver(struct mipi_dsim_lcd_driver *lcd_drv) -{ - struct mipi_dsim_ddi *dsim_ddi; - - if (!lcd_drv) { - debug("mipi_dsim_lcd_driver is NULL.\n"); - return -EFAULT; - } - - if (!lcd_drv->name) { - debug("dsim_lcd_driver name is NULL.\n"); - return -EFAULT; - } - - dsim_ddi = exynos_mipi_dsi_find_lcd_device(lcd_drv); - if (!dsim_ddi) { - debug("mipi_dsim_ddi object not found.\n"); - return -EFAULT; - } - - dsim_ddi->dsim_lcd_drv = lcd_drv; - - debug("registered panel driver(%s) to mipi-dsi driver.\n", - lcd_drv->name); - - return 0; - -} - -struct mipi_dsim_ddi - *exynos_mipi_dsi_bind_lcd_ddi(struct mipi_dsim_device *dsim, - const char *name) -{ - struct mipi_dsim_ddi *dsim_ddi; - struct mipi_dsim_lcd_driver *lcd_drv; - struct mipi_dsim_lcd_device *lcd_dev; - - list_for_each_entry(dsim_ddi, &dsim_ddi_list, list) { - lcd_drv = dsim_ddi->dsim_lcd_drv; - lcd_dev = dsim_ddi->dsim_lcd_dev; - if (!lcd_drv || !lcd_dev) - continue; - - debug("lcd_drv->id = %d, lcd_dev->id = %d\n", - lcd_drv->id, lcd_dev->id); - - if ((strcmp(lcd_drv->name, name) == 0)) { - lcd_dev->master = dsim; - - dsim->dsim_lcd_dev = lcd_dev; - dsim->dsim_lcd_drv = lcd_drv; - - return dsim_ddi; - } - } - - return NULL; -} - -/* define MIPI-DSI Master operations. */ -static struct mipi_dsim_master_ops master_ops = { - .cmd_write = exynos_mipi_dsi_wr_data, - .get_dsim_frame_done = exynos_mipi_dsi_get_frame_done_status, - .clear_dsim_frame_done = exynos_mipi_dsi_clear_frame_done, -}; - -int exynos_mipi_dsi_init(void) -{ - struct mipi_dsim_device *dsim; - struct mipi_dsim_config *dsim_config; - struct mipi_dsim_ddi *dsim_ddi; - - dsim = kzalloc(sizeof(struct mipi_dsim_device), GFP_KERNEL); - if (!dsim) { - debug("failed to allocate dsim object.\n"); - return -EFAULT; - } - - /* get mipi_dsim_config. */ - dsim_config = dsim_pd->dsim_config; - if (dsim_config == NULL) { - debug("failed to get dsim config data.\n"); - return -EFAULT; - } - - dsim->pd = dsim_pd; - dsim->dsim_config = dsim_config; - dsim->master_ops = &master_ops; - - /* bind lcd ddi matched with panel name. */ - dsim_ddi = exynos_mipi_dsi_bind_lcd_ddi(dsim, dsim_pd->lcd_panel_name); - if (!dsim_ddi) { - debug("mipi_dsim_ddi object not found.\n"); - return -ENOSYS; - } - if (dsim_pd->lcd_power) - dsim_pd->lcd_power(); - - if (dsim_pd->mipi_power) - dsim_pd->mipi_power(); - - /* phy_enable(unsigned int dev_index, unsigned int enable) */ - if (dsim_pd->phy_enable) - dsim_pd->phy_enable(0, 1); - - set_mipi_clk(); - - exynos_mipi_dsi_init_dsim(dsim); - exynos_mipi_dsi_init_link(dsim); - exynos_mipi_dsi_set_hs_enable(dsim); - - /* set display timing. */ - exynos_mipi_dsi_set_display_mode(dsim, dsim->dsim_config); - - /* initialize mipi-dsi client(lcd panel). */ - if (dsim_ddi->dsim_lcd_drv && dsim_ddi->dsim_lcd_drv->mipi_panel_init) { - dsim_ddi->dsim_lcd_drv->mipi_panel_init(dsim); - dsim_ddi->dsim_lcd_drv->mipi_display_on(dsim); - } - - debug("mipi-dsi driver(%s mode) has been probed.\n", - (dsim_config->e_interface == DSIM_COMMAND) ? - "CPU" : "RGB"); - - return 0; -} - -void exynos_set_dsim_platform_data(struct exynos_platform_mipi_dsim *pd) -{ - if (pd == NULL) { - debug("pd is NULL\n"); - return; - } - - dsim_pd = pd; -} - -#if CONFIG_IS_ENABLED(OF_CONTROL) -int exynos_dsim_config_parse_dt(const void *blob) -{ - int node; - - node = fdtdec_next_compatible(blob, 0, COMPAT_SAMSUNG_EXYNOS_MIPI_DSI); - if (node <= 0) { - printf("exynos_mipi_dsi: Can't get device node for mipi dsi\n"); - return -ENODEV; - } - - dsim_config_dt.e_interface = fdtdec_get_int(blob, node, - "samsung,dsim-config-e-interface", 0); - - dsim_config_dt.e_virtual_ch = fdtdec_get_int(blob, node, - "samsung,dsim-config-e-virtual-ch", 0); - - dsim_config_dt.e_pixel_format = fdtdec_get_int(blob, node, - "samsung,dsim-config-e-pixel-format", 0); - - dsim_config_dt.e_burst_mode = fdtdec_get_int(blob, node, - "samsung,dsim-config-e-burst-mode", 0); - - dsim_config_dt.e_no_data_lane = fdtdec_get_int(blob, node, - "samsung,dsim-config-e-no-data-lane", 0); - - dsim_config_dt.e_byte_clk = fdtdec_get_int(blob, node, - "samsung,dsim-config-e-byte-clk", 0); - - dsim_config_dt.hfp = fdtdec_get_int(blob, node, - "samsung,dsim-config-hfp", 0); - - dsim_config_dt.p = fdtdec_get_int(blob, node, - "samsung,dsim-config-p", 0); - dsim_config_dt.m = fdtdec_get_int(blob, node, - "samsung,dsim-config-m", 0); - dsim_config_dt.s = fdtdec_get_int(blob, node, - "samsung,dsim-config-s", 0); - - dsim_config_dt.pll_stable_time = fdtdec_get_int(blob, node, - "samsung,dsim-config-pll-stable-time", 0); - - dsim_config_dt.esc_clk = fdtdec_get_int(blob, node, - "samsung,dsim-config-esc-clk", 0); - - dsim_config_dt.stop_holding_cnt = fdtdec_get_int(blob, node, - "samsung,dsim-config-stop-holding-cnt", 0); - - dsim_config_dt.bta_timeout = fdtdec_get_int(blob, node, - "samsung,dsim-config-bta-timeout", 0); - - dsim_config_dt.rx_timeout = fdtdec_get_int(blob, node, - "samsung,dsim-config-rx-timeout", 0); - - mipi_lcd_device_dt.name = fdtdec_get_config_string(blob, - "samsung,dsim-device-name"); - - mipi_lcd_device_dt.id = fdtdec_get_int(blob, node, - "samsung,dsim-device-id", 0); - - mipi_lcd_device_dt.bus_id = fdtdec_get_int(blob, node, - "samsung,dsim-device-bus_id", 0); - - mipi_lcd_device_dt.reverse_panel = fdtdec_get_int(blob, node, - "samsung,dsim-device-reverse-panel", 0); - - return 0; -} - -void exynos_init_dsim_platform_data(vidinfo_t *vid) -{ - if (exynos_dsim_config_parse_dt(gd->fdt_blob)) - debug("Can't get proper dsim config.\n"); - - strcpy(dsim_platform_data_dt.lcd_panel_name, mipi_lcd_device_dt.name); - dsim_platform_data_dt.dsim_config = &dsim_config_dt; - dsim_platform_data_dt.mipi_power = mipi_power; - dsim_platform_data_dt.phy_enable = set_mipi_phy_ctrl; - dsim_platform_data_dt.lcd_panel_info = (void *)vid; - - mipi_lcd_device_dt.platform_data = (void *)&dsim_platform_data_dt; - exynos_mipi_dsi_register_lcd_device(&mipi_lcd_device_dt); - - dsim_pd = &dsim_platform_data_dt; -} -#endif diff --git a/drivers/video/exynos_mipi_dsi_common.c b/drivers/video/exynos_mipi_dsi_common.c deleted file mode 100644 index 925d515..0000000 --- a/drivers/video/exynos_mipi_dsi_common.c +++ /dev/null @@ -1,620 +0,0 @@ -/* - * Copyright (C) 2012 Samsung Electronics - * - * Author: InKi Dae - * Author: Donghwa Lee - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#include -#include -#include -#include -#include - -#include "exynos_mipi_dsi_lowlevel.h" - -#define MHZ (1000 * 1000) -#define FIN_HZ (24 * MHZ) - -#define DFIN_PLL_MIN_HZ (6 * MHZ) -#define DFIN_PLL_MAX_HZ (12 * MHZ) - -#define DFVCO_MIN_HZ (500 * MHZ) -#define DFVCO_MAX_HZ (1000 * MHZ) - -#define TRY_GET_FIFO_TIMEOUT (5000 * 2) - -/* MIPI-DSIM status types. */ -enum { - DSIM_STATE_INIT, /* should be initialized. */ - DSIM_STATE_STOP, /* CPU and LCDC are LP mode. */ - DSIM_STATE_HSCLKEN, /* HS clock was enabled. */ - DSIM_STATE_ULPS -}; - -/* define DSI lane types. */ -enum { - DSIM_LANE_CLOCK = (1 << 0), - DSIM_LANE_DATA0 = (1 << 1), - DSIM_LANE_DATA1 = (1 << 2), - DSIM_LANE_DATA2 = (1 << 3), - DSIM_LANE_DATA3 = (1 << 4) -}; - -static unsigned int dpll_table[15] = { - 100, 120, 170, 220, 270, - 320, 390, 450, 510, 560, - 640, 690, 770, 870, 950 -}; - -static void exynos_mipi_dsi_long_data_wr(struct mipi_dsim_device *dsim, - const unsigned char *data0, unsigned int data1) -{ - unsigned int data_cnt = 0, payload = 0; - - /* in case that data count is more then 4 */ - for (data_cnt = 0; data_cnt < data1; data_cnt += 4) { - /* - * after sending 4bytes per one time, - * send remainder data less then 4. - */ - if ((data1 - data_cnt) < 4) { - if ((data1 - data_cnt) == 3) { - payload = data0[data_cnt] | - data0[data_cnt + 1] << 8 | - data0[data_cnt + 2] << 16; - debug("count = 3 payload = %x, %x %x %x\n", - payload, data0[data_cnt], - data0[data_cnt + 1], - data0[data_cnt + 2]); - } else if ((data1 - data_cnt) == 2) { - payload = data0[data_cnt] | - data0[data_cnt + 1] << 8; - debug("count = 2 payload = %x, %x %x\n", payload, - data0[data_cnt], data0[data_cnt + 1]); - } else if ((data1 - data_cnt) == 1) { - payload = data0[data_cnt]; - } - } else { - /* send 4bytes per one time. */ - payload = data0[data_cnt] | - data0[data_cnt + 1] << 8 | - data0[data_cnt + 2] << 16 | - data0[data_cnt + 3] << 24; - - debug("count = 4 payload = %x, %x %x %x %x\n", - payload, *(u8 *)(data0 + data_cnt), - data0[data_cnt + 1], - data0[data_cnt + 2], - data0[data_cnt + 3]); - } - exynos_mipi_dsi_wr_tx_data(dsim, payload); - } -} - -int exynos_mipi_dsi_wr_data(struct mipi_dsim_device *dsim, unsigned int data_id, - const unsigned char *data0, unsigned int data1) -{ - unsigned int timeout = TRY_GET_FIFO_TIMEOUT; - unsigned long delay_val, delay; - unsigned int check_rx_ack = 0; - - if (dsim->state == DSIM_STATE_ULPS) { - debug("state is ULPS.\n"); - - return -EINVAL; - } - - delay_val = MHZ / dsim->dsim_config->esc_clk; - delay = 10 * delay_val; - - mdelay(delay); - - /* only if transfer mode is LPDT, wait SFR becomes empty. */ - if (dsim->state == DSIM_STATE_STOP) { - while (!(exynos_mipi_dsi_get_fifo_state(dsim) & - SFR_HEADER_EMPTY)) { - if ((timeout--) > 0) - mdelay(1); - else { - debug("SRF header fifo is not empty.\n"); - return -EINVAL; - } - } - } - - switch (data_id) { - /* short packet types of packet types for command. */ - case MIPI_DSI_GENERIC_SHORT_WRITE_0_PARAM: - case MIPI_DSI_GENERIC_SHORT_WRITE_1_PARAM: - case MIPI_DSI_GENERIC_SHORT_WRITE_2_PARAM: - case MIPI_DSI_DCS_SHORT_WRITE: - case MIPI_DSI_DCS_SHORT_WRITE_PARAM: - case MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE: - debug("data0 = %x data1 = %x\n", - data0[0], data0[1]); - exynos_mipi_dsi_wr_tx_header(dsim, data_id, data0[0], data0[1]); - if (check_rx_ack) { - /* process response func should be implemented */ - return 0; - } else { - return -EINVAL; - } - - /* general command */ - case MIPI_DSI_COLOR_MODE_OFF: - case MIPI_DSI_COLOR_MODE_ON: - case MIPI_DSI_SHUTDOWN_PERIPHERAL: - case MIPI_DSI_TURN_ON_PERIPHERAL: - exynos_mipi_dsi_wr_tx_header(dsim, data_id, data0[0], data0[1]); - if (check_rx_ack) { - /* process response func should be implemented. */ - return 0; - } else { - return -EINVAL; - } - - /* packet types for video data */ - case MIPI_DSI_V_SYNC_START: - case MIPI_DSI_V_SYNC_END: - case MIPI_DSI_H_SYNC_START: - case MIPI_DSI_H_SYNC_END: - case MIPI_DSI_END_OF_TRANSMISSION: - return 0; - - /* short and response packet types for command */ - case MIPI_DSI_GENERIC_READ_REQUEST_0_PARAM: - case MIPI_DSI_GENERIC_READ_REQUEST_1_PARAM: - case MIPI_DSI_GENERIC_READ_REQUEST_2_PARAM: - case MIPI_DSI_DCS_READ: - exynos_mipi_dsi_clear_all_interrupt(dsim); - exynos_mipi_dsi_wr_tx_header(dsim, data_id, data0[0], data0[1]); - /* process response func should be implemented. */ - return 0; - - /* long packet type and null packet */ - case MIPI_DSI_NULL_PACKET: - case MIPI_DSI_BLANKING_PACKET: - return 0; - case MIPI_DSI_GENERIC_LONG_WRITE: - case MIPI_DSI_DCS_LONG_WRITE: - { - unsigned int payload = 0; - - /* if data count is less then 4, then send 3bytes data. */ - if (data1 < 4) { - payload = data0[0] | - data0[1] << 8 | - data0[2] << 16; - - exynos_mipi_dsi_wr_tx_data(dsim, payload); - - debug("count = %d payload = %x,%x %x %x\n", - data1, payload, data0[0], - data0[1], data0[2]); - } else { - /* in case that data count is more then 4 */ - exynos_mipi_dsi_long_data_wr(dsim, data0, data1); - } - - /* put data into header fifo */ - exynos_mipi_dsi_wr_tx_header(dsim, data_id, data1 & 0xff, - (data1 & 0xff00) >> 8); - - } - if (check_rx_ack) - /* process response func should be implemented. */ - return 0; - else - return -EINVAL; - - /* packet typo for video data */ - case MIPI_DSI_PACKED_PIXEL_STREAM_16: - case MIPI_DSI_PACKED_PIXEL_STREAM_18: - case MIPI_DSI_PIXEL_STREAM_3BYTE_18: - case MIPI_DSI_PACKED_PIXEL_STREAM_24: - if (check_rx_ack) { - /* process response func should be implemented. */ - return 0; - } else { - return -EINVAL; - } - default: - debug("data id %x is not supported current DSI spec.\n", - data_id); - - return -EINVAL; - } - - return 0; -} - -int exynos_mipi_dsi_pll_on(struct mipi_dsim_device *dsim, unsigned int enable) -{ - int sw_timeout; - - if (enable) { - sw_timeout = 1000; - - exynos_mipi_dsi_clear_interrupt(dsim); - exynos_mipi_dsi_enable_pll(dsim, 1); - while (1) { - sw_timeout--; - if (exynos_mipi_dsi_is_pll_stable(dsim)) - return 0; - if (sw_timeout == 0) - return -EINVAL; - } - } else - exynos_mipi_dsi_enable_pll(dsim, 0); - - return 0; -} - -unsigned long exynos_mipi_dsi_change_pll(struct mipi_dsim_device *dsim, - unsigned int pre_divider, unsigned int main_divider, - unsigned int scaler) -{ - unsigned long dfin_pll, dfvco, dpll_out; - unsigned int i, freq_band = 0xf; - - dfin_pll = (FIN_HZ / pre_divider); - - /****************************************************** - * Serial Clock(=ByteClk X 8) FreqBand[3:0] * - ****************************************************** - * ~ 99.99 MHz 0000 - * 100 ~ 119.99 MHz 0001 - * 120 ~ 159.99 MHz 0010 - * 160 ~ 199.99 MHz 0011 - * 200 ~ 239.99 MHz 0100 - * 140 ~ 319.99 MHz 0101 - * 320 ~ 389.99 MHz 0110 - * 390 ~ 449.99 MHz 0111 - * 450 ~ 509.99 MHz 1000 - * 510 ~ 559.99 MHz 1001 - * 560 ~ 639.99 MHz 1010 - * 640 ~ 689.99 MHz 1011 - * 690 ~ 769.99 MHz 1100 - * 770 ~ 869.99 MHz 1101 - * 870 ~ 949.99 MHz 1110 - * 950 ~ 1000 MHz 1111 - ******************************************************/ - if (dfin_pll < DFIN_PLL_MIN_HZ || dfin_pll > DFIN_PLL_MAX_HZ) { - debug("fin_pll range should be 6MHz ~ 12MHz\n"); - exynos_mipi_dsi_enable_afc(dsim, 0, 0); - } else { - if (dfin_pll < 7 * MHZ) - exynos_mipi_dsi_enable_afc(dsim, 1, 0x1); - else if (dfin_pll < 8 * MHZ) - exynos_mipi_dsi_enable_afc(dsim, 1, 0x0); - else if (dfin_pll < 9 * MHZ) - exynos_mipi_dsi_enable_afc(dsim, 1, 0x3); - else if (dfin_pll < 10 * MHZ) - exynos_mipi_dsi_enable_afc(dsim, 1, 0x2); - else if (dfin_pll < 11 * MHZ) - exynos_mipi_dsi_enable_afc(dsim, 1, 0x5); - else - exynos_mipi_dsi_enable_afc(dsim, 1, 0x4); - } - - dfvco = dfin_pll * main_divider; - debug("dfvco = %lu, dfin_pll = %lu, main_divider = %d\n", - dfvco, dfin_pll, main_divider); - if (dfvco < DFVCO_MIN_HZ || dfvco > DFVCO_MAX_HZ) - debug("fvco range should be 500MHz ~ 1000MHz\n"); - - dpll_out = dfvco / (1 << scaler); - debug("dpll_out = %lu, dfvco = %lu, scaler = %d\n", - dpll_out, dfvco, scaler); - - for (i = 0; i < ARRAY_SIZE(dpll_table); i++) { - if (dpll_out < dpll_table[i] * MHZ) { - freq_band = i; - break; - } - } - - debug("freq_band = %d\n", freq_band); - - exynos_mipi_dsi_pll_freq(dsim, pre_divider, main_divider, scaler); - - exynos_mipi_dsi_hs_zero_ctrl(dsim, 0); - exynos_mipi_dsi_prep_ctrl(dsim, 0); - - /* Freq Band */ - exynos_mipi_dsi_pll_freq_band(dsim, freq_band); - - /* Stable time */ - exynos_mipi_dsi_pll_stable_time(dsim, - dsim->dsim_config->pll_stable_time); - - /* Enable PLL */ - debug("FOUT of mipi dphy pll is %luMHz\n", - (dpll_out / MHZ)); - - return dpll_out; -} - -int exynos_mipi_dsi_set_clock(struct mipi_dsim_device *dsim, - unsigned int byte_clk_sel, unsigned int enable) -{ - unsigned int esc_div; - unsigned long esc_clk_error_rate; - unsigned long hs_clk = 0, byte_clk = 0, escape_clk = 0; - - if (enable) { - dsim->e_clk_src = byte_clk_sel; - - /* Escape mode clock and byte clock source */ - exynos_mipi_dsi_set_byte_clock_src(dsim, byte_clk_sel); - - /* DPHY, DSIM Link : D-PHY clock out */ - if (byte_clk_sel == DSIM_PLL_OUT_DIV8) { - hs_clk = exynos_mipi_dsi_change_pll(dsim, - dsim->dsim_config->p, dsim->dsim_config->m, - dsim->dsim_config->s); - if (hs_clk == 0) { - debug("failed to get hs clock.\n"); - return -EINVAL; - } - - byte_clk = hs_clk / 8; - exynos_mipi_dsi_enable_pll_bypass(dsim, 0); - exynos_mipi_dsi_pll_on(dsim, 1); - /* DPHY : D-PHY clock out, DSIM link : external clock out */ - } else if (byte_clk_sel == DSIM_EXT_CLK_DIV8) - debug("not support EXT CLK source for MIPI DSIM\n"); - else if (byte_clk_sel == DSIM_EXT_CLK_BYPASS) - debug("not support EXT CLK source for MIPI DSIM\n"); - - /* escape clock divider */ - esc_div = byte_clk / (dsim->dsim_config->esc_clk); - debug("esc_div = %d, byte_clk = %lu, esc_clk = %lu\n", - esc_div, byte_clk, dsim->dsim_config->esc_clk); - if ((byte_clk / esc_div) >= (20 * MHZ) || - (byte_clk / esc_div) > dsim->dsim_config->esc_clk) - esc_div += 1; - - escape_clk = byte_clk / esc_div; - debug("escape_clk = %lu, byte_clk = %lu, esc_div = %d\n", - escape_clk, byte_clk, esc_div); - - /* enable escape clock. */ - exynos_mipi_dsi_enable_byte_clock(dsim, 1); - - /* enable byte clk and escape clock */ - exynos_mipi_dsi_set_esc_clk_prs(dsim, 1, esc_div); - /* escape clock on lane */ - exynos_mipi_dsi_enable_esc_clk_on_lane(dsim, - (DSIM_LANE_CLOCK | dsim->data_lane), 1); - - debug("byte clock is %luMHz\n", - (byte_clk / MHZ)); - debug("escape clock that user's need is %lu\n", - (dsim->dsim_config->esc_clk / MHZ)); - debug("escape clock divider is %x\n", esc_div); - debug("escape clock is %luMHz\n", - ((byte_clk / esc_div) / MHZ)); - - if ((byte_clk / esc_div) > escape_clk) { - esc_clk_error_rate = escape_clk / - (byte_clk / esc_div); - debug("error rate is %lu over.\n", - (esc_clk_error_rate / 100)); - } else if ((byte_clk / esc_div) < (escape_clk)) { - esc_clk_error_rate = (byte_clk / esc_div) / - escape_clk; - debug("error rate is %lu under.\n", - (esc_clk_error_rate / 100)); - } - } else { - exynos_mipi_dsi_enable_esc_clk_on_lane(dsim, - (DSIM_LANE_CLOCK | dsim->data_lane), 0); - exynos_mipi_dsi_set_esc_clk_prs(dsim, 0, 0); - - /* disable escape clock. */ - exynos_mipi_dsi_enable_byte_clock(dsim, 0); - - if (byte_clk_sel == DSIM_PLL_OUT_DIV8) - exynos_mipi_dsi_pll_on(dsim, 0); - } - - return 0; -} - -int exynos_mipi_dsi_init_dsim(struct mipi_dsim_device *dsim) -{ - dsim->state = DSIM_STATE_INIT; - - switch (dsim->dsim_config->e_no_data_lane) { - case DSIM_DATA_LANE_1: - dsim->data_lane = DSIM_LANE_DATA0; - break; - case DSIM_DATA_LANE_2: - dsim->data_lane = DSIM_LANE_DATA0 | DSIM_LANE_DATA1; - break; - case DSIM_DATA_LANE_3: - dsim->data_lane = DSIM_LANE_DATA0 | DSIM_LANE_DATA1 | - DSIM_LANE_DATA2; - break; - case DSIM_DATA_LANE_4: - dsim->data_lane = DSIM_LANE_DATA0 | DSIM_LANE_DATA1 | - DSIM_LANE_DATA2 | DSIM_LANE_DATA3; - break; - default: - debug("data lane is invalid.\n"); - return -EINVAL; - }; - - exynos_mipi_dsi_sw_reset(dsim); - exynos_mipi_dsi_dp_dn_swap(dsim, 0); - - return 0; -} - -int exynos_mipi_dsi_enable_frame_done_int(struct mipi_dsim_device *dsim, - unsigned int enable) -{ - /* enable only frame done interrupt */ - exynos_mipi_dsi_set_interrupt_mask(dsim, INTMSK_FRAME_DONE, enable); - - return 0; -} - -static void convert_to_fb_videomode(struct fb_videomode *mode1, - vidinfo_t *mode2) -{ - mode1->xres = mode2->vl_width; - mode1->yres = mode2->vl_height; - mode1->upper_margin = mode2->vl_vfpd; - mode1->lower_margin = mode2->vl_vbpd; - mode1->left_margin = mode2->vl_hfpd; - mode1->right_margin = mode2->vl_hbpd; - mode1->vsync_len = mode2->vl_vspw; - mode1->hsync_len = mode2->vl_hspw; -} - -int exynos_mipi_dsi_set_display_mode(struct mipi_dsim_device *dsim, - struct mipi_dsim_config *dsim_config) -{ - struct exynos_platform_mipi_dsim *dsim_pd; - struct fb_videomode lcd_video; - vidinfo_t *vid; - - dsim_pd = (struct exynos_platform_mipi_dsim *)dsim->pd; - vid = (vidinfo_t *)dsim_pd->lcd_panel_info; - - convert_to_fb_videomode(&lcd_video, vid); - - /* in case of VIDEO MODE (RGB INTERFACE), it sets polarities. */ - if (dsim->dsim_config->e_interface == (u32) DSIM_VIDEO) { - if (dsim->dsim_config->auto_vertical_cnt == 0) { - exynos_mipi_dsi_set_main_disp_vporch(dsim, - vid->vl_cmd_allow_len, - lcd_video.upper_margin, - lcd_video.lower_margin); - exynos_mipi_dsi_set_main_disp_hporch(dsim, - lcd_video.left_margin, - lcd_video.right_margin); - exynos_mipi_dsi_set_main_disp_sync_area(dsim, - lcd_video.vsync_len, - lcd_video.hsync_len); - } - } - - exynos_mipi_dsi_set_main_disp_resol(dsim, lcd_video.xres, - lcd_video.yres); - - exynos_mipi_dsi_display_config(dsim, dsim->dsim_config); - - debug("lcd panel ==> width = %d, height = %d\n", - lcd_video.xres, lcd_video.yres); - - return 0; -} - -int exynos_mipi_dsi_init_link(struct mipi_dsim_device *dsim) -{ - unsigned int time_out = 100; - - switch (dsim->state) { - case DSIM_STATE_INIT: - exynos_mipi_dsi_init_fifo_pointer(dsim, 0x1f); - - /* dsi configuration */ - exynos_mipi_dsi_init_config(dsim); - exynos_mipi_dsi_enable_lane(dsim, DSIM_LANE_CLOCK, 1); - exynos_mipi_dsi_enable_lane(dsim, dsim->data_lane, 1); - - /* set clock configuration */ - exynos_mipi_dsi_set_clock(dsim, - dsim->dsim_config->e_byte_clk, 1); - - /* check clock and data lane state are stop state */ - while (!(exynos_mipi_dsi_is_lane_state(dsim))) { - time_out--; - if (time_out == 0) { - debug("DSI Master is not stop state.\n"); - debug("Check initialization process\n"); - - return -EINVAL; - } - } - - dsim->state = DSIM_STATE_STOP; - - /* BTA sequence counters */ - exynos_mipi_dsi_set_stop_state_counter(dsim, - dsim->dsim_config->stop_holding_cnt); - exynos_mipi_dsi_set_bta_timeout(dsim, - dsim->dsim_config->bta_timeout); - exynos_mipi_dsi_set_lpdr_timeout(dsim, - dsim->dsim_config->rx_timeout); - - return 0; - default: - debug("DSI Master is already init.\n"); - return 0; - } - - return 0; -} - -int exynos_mipi_dsi_set_hs_enable(struct mipi_dsim_device *dsim) -{ - if (dsim->state == DSIM_STATE_STOP) { - if (dsim->e_clk_src != DSIM_EXT_CLK_BYPASS) { - dsim->state = DSIM_STATE_HSCLKEN; - - /* set LCDC and CPU transfer mode to HS. */ - exynos_mipi_dsi_set_lcdc_transfer_mode(dsim, 0); - exynos_mipi_dsi_set_cpu_transfer_mode(dsim, 0); - - exynos_mipi_dsi_enable_hs_clock(dsim, 1); - - return 0; - } else - debug("clock source is external bypass.\n"); - } else - debug("DSIM is not stop state.\n"); - - return 0; -} - -int exynos_mipi_dsi_set_data_transfer_mode(struct mipi_dsim_device *dsim, - unsigned int mode) -{ - if (mode) { - if (dsim->state != DSIM_STATE_HSCLKEN) { - debug("HS Clock lane is not enabled.\n"); - return -EINVAL; - } - - exynos_mipi_dsi_set_lcdc_transfer_mode(dsim, 0); - } else { - if (dsim->state == DSIM_STATE_INIT || dsim->state == - DSIM_STATE_ULPS) { - debug("DSI Master is not STOP or HSDT state.\n"); - return -EINVAL; - } - - exynos_mipi_dsi_set_cpu_transfer_mode(dsim, 0); - } - - return 0; -} - -int exynos_mipi_dsi_get_frame_done_status(struct mipi_dsim_device *dsim) -{ - return _exynos_mipi_dsi_get_frame_done_status(dsim); -} - -int exynos_mipi_dsi_clear_frame_done(struct mipi_dsim_device *dsim) -{ - _exynos_mipi_dsi_clear_frame_done(dsim); - - return 0; -} diff --git a/drivers/video/exynos_mipi_dsi_common.h b/drivers/video/exynos_mipi_dsi_common.h deleted file mode 100644 index 98eb78e..0000000 --- a/drivers/video/exynos_mipi_dsi_common.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (C) 2012 Samsung Electronics - * - * Author: InKi Dae - * Author: Donghwa Lee - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#include - -#ifndef _EXYNOS_MIPI_DSI_COMMON_H -#define _EXYNOS_MIPI_DSI_COMMON_H - -int exynos_mipi_dsi_wr_data(struct mipi_dsim_device *dsim, unsigned int data_id, - const unsigned char *data0, unsigned int data1); -int exynos_mipi_dsi_pll_on(struct mipi_dsim_device *dsim, unsigned int enable); -unsigned long exynos_mipi_dsi_change_pll(struct mipi_dsim_device *dsim, - unsigned int pre_divider, unsigned int main_divider, - unsigned int scaler); -int exynos_mipi_dsi_set_clock(struct mipi_dsim_device *dsim, - unsigned int byte_clk_sel, unsigned int enable); -int exynos_mipi_dsi_init_dsim(struct mipi_dsim_device *dsim); -int exynos_mipi_dsi_set_display_mode(struct mipi_dsim_device *dsim, - struct mipi_dsim_config *dsim_info); -int exynos_mipi_dsi_init_link(struct mipi_dsim_device *dsim); -int exynos_mipi_dsi_set_hs_enable(struct mipi_dsim_device *dsim); -int exynos_mipi_dsi_set_data_transfer_mode(struct mipi_dsim_device *dsim, - unsigned int mode); -int exynos_mipi_dsi_enable_frame_done_int(struct mipi_dsim_device *dsim, - unsigned int enable); -int exynos_mipi_dsi_get_frame_done_status(struct mipi_dsim_device *dsim); -int exynos_mipi_dsi_clear_frame_done(struct mipi_dsim_device *dsim); - -#endif /* _EXYNOS_MIPI_DSI_COMMON_H */ diff --git a/drivers/video/exynos_mipi_dsi_lowlevel.c b/drivers/video/exynos_mipi_dsi_lowlevel.c deleted file mode 100644 index fcfdc8d..0000000 --- a/drivers/video/exynos_mipi_dsi_lowlevel.c +++ /dev/null @@ -1,639 +0,0 @@ -/* - * Copyright (C) 2012 Samsung Electronics - * - * Author: InKi Dae - * Author: Donghwa Lee - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#include -#include -#include -#include -#include - -#include "exynos_mipi_dsi_lowlevel.h" -#include "exynos_mipi_dsi_common.h" - -void exynos_mipi_dsi_func_reset(struct mipi_dsim_device *dsim) -{ - unsigned int reg; - - struct exynos_mipi_dsim *mipi_dsim = - (struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim(); - - reg = readl(&mipi_dsim->swrst); - - reg |= DSIM_FUNCRST; - - writel(reg, &mipi_dsim->swrst); -} - -void exynos_mipi_dsi_sw_reset(struct mipi_dsim_device *dsim) -{ - unsigned int reg = 0; - - struct exynos_mipi_dsim *mipi_dsim = - (struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim(); - - reg = readl(&mipi_dsim->swrst); - - reg |= DSIM_SWRST; - reg |= DSIM_FUNCRST; - - writel(reg, &mipi_dsim->swrst); -} - -void exynos_mipi_dsi_sw_release(struct mipi_dsim_device *dsim) -{ - struct exynos_mipi_dsim *mipi_dsim = - (struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim(); - unsigned int reg = readl(&mipi_dsim->intsrc); - - reg |= INTSRC_SWRST_RELEASE; - - writel(reg, &mipi_dsim->intsrc); -} - -void exynos_mipi_dsi_set_interrupt_mask(struct mipi_dsim_device *dsim, - unsigned int mode, unsigned int mask) -{ - struct exynos_mipi_dsim *mipi_dsim = - (struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim(); - unsigned int reg = readl(&mipi_dsim->intmsk); - - if (mask) - reg |= mode; - else - reg &= ~mode; - - writel(reg, &mipi_dsim->intmsk); -} - -void exynos_mipi_dsi_init_fifo_pointer(struct mipi_dsim_device *dsim, - unsigned int cfg) -{ - unsigned int reg; - struct exynos_mipi_dsim *mipi_dsim = - (struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim(); - - reg = readl(&mipi_dsim->fifoctrl); - - writel(reg & ~(cfg), &mipi_dsim->fifoctrl); - udelay(10 * 1000); - reg |= cfg; - - writel(reg, &mipi_dsim->fifoctrl); -} - -/* - * this function set PLL P, M and S value in D-PHY - */ -void exynos_mipi_dsi_set_phy_tunning(struct mipi_dsim_device *dsim, - unsigned int value) -{ - struct exynos_mipi_dsim *mipi_dsim = - (struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim(); - - writel(DSIM_AFC_CTL(value), &mipi_dsim->phyacchr); -} - -void exynos_mipi_dsi_set_main_disp_resol(struct mipi_dsim_device *dsim, - unsigned int width_resol, unsigned int height_resol) -{ - unsigned int reg; - struct exynos_mipi_dsim *mipi_dsim = - (struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim(); - - /* standby should be set after configuration so set to not ready*/ - reg = (readl(&mipi_dsim->mdresol)) & ~(DSIM_MAIN_STAND_BY); - writel(reg, &mipi_dsim->mdresol); - - /* reset resolution */ - reg &= ~(DSIM_MAIN_VRESOL(0x7ff) | DSIM_MAIN_HRESOL(0x7ff)); - reg |= DSIM_MAIN_VRESOL(height_resol) | DSIM_MAIN_HRESOL(width_resol); - - reg |= DSIM_MAIN_STAND_BY; - writel(reg, &mipi_dsim->mdresol); -} - -void exynos_mipi_dsi_set_main_disp_vporch(struct mipi_dsim_device *dsim, - unsigned int cmd_allow, unsigned int vfront, unsigned int vback) -{ - unsigned int reg; - struct exynos_mipi_dsim *mipi_dsim = - (struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim(); - - reg = (readl(&mipi_dsim->mvporch)) & - ~((DSIM_CMD_ALLOW_MASK) | (DSIM_STABLE_VFP_MASK) | - (DSIM_MAIN_VBP_MASK)); - - reg |= ((cmd_allow & 0xf) << DSIM_CMD_ALLOW_SHIFT) | - ((vfront & 0x7ff) << DSIM_STABLE_VFP_SHIFT) | - ((vback & 0x7ff) << DSIM_MAIN_VBP_SHIFT); - - writel(reg, &mipi_dsim->mvporch); -} - -void exynos_mipi_dsi_set_main_disp_hporch(struct mipi_dsim_device *dsim, - unsigned int front, unsigned int back) -{ - unsigned int reg; - struct exynos_mipi_dsim *mipi_dsim = - (struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim(); - - reg = (readl(&mipi_dsim->mhporch)) & - ~((DSIM_MAIN_HFP_MASK) | (DSIM_MAIN_HBP_MASK)); - - reg |= (front << DSIM_MAIN_HFP_SHIFT) | (back << DSIM_MAIN_HBP_SHIFT); - - writel(reg, &mipi_dsim->mhporch); -} - -void exynos_mipi_dsi_set_main_disp_sync_area(struct mipi_dsim_device *dsim, - unsigned int vert, unsigned int hori) -{ - unsigned int reg; - struct exynos_mipi_dsim *mipi_dsim = - (struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim(); - - reg = (readl(&mipi_dsim->msync)) & - ~((DSIM_MAIN_VSA_MASK) | (DSIM_MAIN_HSA_MASK)); - - reg |= ((vert & 0x3ff) << DSIM_MAIN_VSA_SHIFT) | - (hori << DSIM_MAIN_HSA_SHIFT); - - writel(reg, &mipi_dsim->msync); -} - -void exynos_mipi_dsi_set_sub_disp_resol(struct mipi_dsim_device *dsim, - unsigned int vert, unsigned int hori) -{ - unsigned int reg; - struct exynos_mipi_dsim *mipi_dsim = - (struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim(); - - reg = (readl(&mipi_dsim->sdresol)) & - ~(DSIM_SUB_STANDY_MASK); - - writel(reg, &mipi_dsim->sdresol); - - reg &= ~(DSIM_SUB_VRESOL_MASK) | ~(DSIM_SUB_HRESOL_MASK); - reg |= ((vert & 0x7ff) << DSIM_SUB_VRESOL_SHIFT) | - ((hori & 0x7ff) << DSIM_SUB_HRESOL_SHIFT); - writel(reg, &mipi_dsim->sdresol); - - /* DSIM STANDBY */ - reg |= (1 << DSIM_SUB_STANDY_SHIFT); - writel(reg, &mipi_dsim->sdresol); -} - -void exynos_mipi_dsi_init_config(struct mipi_dsim_device *dsim) -{ - struct mipi_dsim_config *dsim_config = dsim->dsim_config; - struct exynos_mipi_dsim *mipi_dsim = - (struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim(); - unsigned int cfg = (readl(&mipi_dsim->config)) & - ~((1 << DSIM_EOT_PACKET_SHIFT) | - (0x1f << DSIM_HSA_MODE_SHIFT) | - (0x3 << DSIM_NUM_OF_DATALANE_SHIFT)); - - cfg |= (dsim_config->auto_flush << DSIM_AUTO_FLUSH_SHIFT) | - (dsim_config->eot_disable << DSIM_EOT_PACKET_SHIFT) | - (dsim_config->auto_vertical_cnt << DSIM_AUTO_MODE_SHIFT) | - (dsim_config->hse << DSIM_HSE_MODE_SHIFT) | - (dsim_config->hfp << DSIM_HFP_MODE_SHIFT) | - (dsim_config->hbp << DSIM_HBP_MODE_SHIFT) | - (dsim_config->hsa << DSIM_HSA_MODE_SHIFT) | - (dsim_config->e_no_data_lane << DSIM_NUM_OF_DATALANE_SHIFT); - - writel(cfg, &mipi_dsim->config); -} - -void exynos_mipi_dsi_display_config(struct mipi_dsim_device *dsim, - struct mipi_dsim_config *dsim_config) -{ - struct exynos_mipi_dsim *mipi_dsim = - (struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim(); - - u32 reg = (readl(&mipi_dsim->config)) & - ~((0x3 << DSIM_BURST_MODE_SHIFT) | (1 << DSIM_VIDEO_MODE_SHIFT) - | (0x3 << DSIM_MAINVC_SHIFT) | (0x7 << DSIM_MAINPIX_SHIFT) - | (0x3 << DSIM_SUBVC_SHIFT) | (0x7 << DSIM_SUBPIX_SHIFT)); - - if (dsim_config->e_interface == DSIM_VIDEO) - reg |= (1 << DSIM_VIDEO_MODE_SHIFT); - else if (dsim_config->e_interface == DSIM_COMMAND) - reg &= ~(1 << DSIM_VIDEO_MODE_SHIFT); - else { - printf("unknown lcd type.\n"); - return; - } - - /* main lcd */ - reg |= ((u8) (dsim_config->e_burst_mode) & 0x3) << DSIM_BURST_MODE_SHIFT - | ((u8) (dsim_config->e_virtual_ch) & 0x3) << DSIM_MAINVC_SHIFT - | ((u8) (dsim_config->e_pixel_format) & 0x7) << DSIM_MAINPIX_SHIFT; - - writel(reg, &mipi_dsim->config); -} - -void exynos_mipi_dsi_enable_lane(struct mipi_dsim_device *dsim, - unsigned int lane, unsigned int enable) -{ - unsigned int reg; - struct exynos_mipi_dsim *mipi_dsim = - (struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim(); - - reg = readl(&mipi_dsim->config); - - if (enable) - reg |= DSIM_LANE_ENx(lane); - else - reg &= ~DSIM_LANE_ENx(lane); - - writel(reg, &mipi_dsim->config); -} - -void exynos_mipi_dsi_set_data_lane_number(struct mipi_dsim_device *dsim, - unsigned int count) -{ - unsigned int cfg; - struct exynos_mipi_dsim *mipi_dsim = - (struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim(); - - /* get the data lane number. */ - cfg = DSIM_NUM_OF_DATA_LANE(count); - - writel(cfg, &mipi_dsim->config); -} - -void exynos_mipi_dsi_enable_afc(struct mipi_dsim_device *dsim, - unsigned int enable, unsigned int afc_code) -{ - struct exynos_mipi_dsim *mipi_dsim = - (struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim(); - unsigned int reg = readl(&mipi_dsim->phyacchr); - - reg = 0; - - if (enable) { - reg |= DSIM_AFC_EN; - reg &= ~(0x7 << DSIM_AFC_CTL_SHIFT); - reg |= DSIM_AFC_CTL(afc_code); - } else - reg &= ~DSIM_AFC_EN; - - writel(reg, &mipi_dsim->phyacchr); -} - -void exynos_mipi_dsi_enable_pll_bypass(struct mipi_dsim_device *dsim, - unsigned int enable) -{ - struct exynos_mipi_dsim *mipi_dsim = - (struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim(); - unsigned int reg = (readl(&mipi_dsim->clkctrl)) & - ~(DSIM_PLL_BYPASS_EXTERNAL); - - reg |= enable << DSIM_PLL_BYPASS_SHIFT; - - writel(reg, &mipi_dsim->clkctrl); -} - -void exynos_mipi_dsi_pll_freq_band(struct mipi_dsim_device *dsim, - unsigned int freq_band) -{ - struct exynos_mipi_dsim *mipi_dsim = - (struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim(); - unsigned int reg = (readl(&mipi_dsim->pllctrl)) & - ~(0x1f << DSIM_FREQ_BAND_SHIFT); - - reg |= ((freq_band & 0x1f) << DSIM_FREQ_BAND_SHIFT); - - writel(reg, &mipi_dsim->pllctrl); -} - -void exynos_mipi_dsi_pll_freq(struct mipi_dsim_device *dsim, - unsigned int pre_divider, unsigned int main_divider, - unsigned int scaler) -{ - struct exynos_mipi_dsim *mipi_dsim = - (struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim(); - unsigned int reg = (readl(&mipi_dsim->pllctrl)) & - ~(0x7ffff << 1); - - reg |= ((pre_divider & 0x3f) << DSIM_PREDIV_SHIFT) | - ((main_divider & 0x1ff) << DSIM_MAIN_SHIFT) | - ((scaler & 0x7) << DSIM_SCALER_SHIFT); - - writel(reg, &mipi_dsim->pllctrl); -} - -void exynos_mipi_dsi_pll_stable_time(struct mipi_dsim_device *dsim, - unsigned int lock_time) -{ - struct exynos_mipi_dsim *mipi_dsim = - (struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim(); - - writel(lock_time, &mipi_dsim->plltmr); -} - -void exynos_mipi_dsi_enable_pll(struct mipi_dsim_device *dsim, - unsigned int enable) -{ - struct exynos_mipi_dsim *mipi_dsim = - (struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim(); - unsigned int reg = (readl(&mipi_dsim->pllctrl)) & - ~(0x1 << DSIM_PLL_EN_SHIFT); - - reg |= ((enable & 0x1) << DSIM_PLL_EN_SHIFT); - - writel(reg, &mipi_dsim->pllctrl); -} - -void exynos_mipi_dsi_set_byte_clock_src(struct mipi_dsim_device *dsim, - unsigned int src) -{ - struct exynos_mipi_dsim *mipi_dsim = - (struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim(); - unsigned int reg = (readl(&mipi_dsim->clkctrl)) & - ~(0x3 << DSIM_BYTE_CLK_SRC_SHIFT); - - reg |= ((unsigned int) src) << DSIM_BYTE_CLK_SRC_SHIFT; - - writel(reg, &mipi_dsim->clkctrl); -} - -void exynos_mipi_dsi_enable_byte_clock(struct mipi_dsim_device *dsim, - unsigned int enable) -{ - struct exynos_mipi_dsim *mipi_dsim = - (struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim(); - unsigned int reg = (readl(&mipi_dsim->clkctrl)) & - ~(1 << DSIM_BYTE_CLKEN_SHIFT); - - reg |= enable << DSIM_BYTE_CLKEN_SHIFT; - - writel(reg, &mipi_dsim->clkctrl); -} - -void exynos_mipi_dsi_set_esc_clk_prs(struct mipi_dsim_device *dsim, - unsigned int enable, unsigned int prs_val) -{ - struct exynos_mipi_dsim *mipi_dsim = - (struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim(); - unsigned int reg = (readl(&mipi_dsim->clkctrl)) & - ~((1 << DSIM_ESC_CLKEN_SHIFT) | (0xffff)); - - reg |= enable << DSIM_ESC_CLKEN_SHIFT; - if (enable) - reg |= prs_val; - - writel(reg, &mipi_dsim->clkctrl); -} - -void exynos_mipi_dsi_enable_esc_clk_on_lane(struct mipi_dsim_device *dsim, - unsigned int lane_sel, unsigned int enable) -{ - struct exynos_mipi_dsim *mipi_dsim = - (struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim(); - unsigned int reg = readl(&mipi_dsim->clkctrl); - - if (enable) - reg |= DSIM_LANE_ESC_CLKEN(lane_sel); - else - reg &= ~DSIM_LANE_ESC_CLKEN(lane_sel); - - writel(reg, &mipi_dsim->clkctrl); -} - -void exynos_mipi_dsi_force_dphy_stop_state(struct mipi_dsim_device *dsim, - unsigned int enable) -{ - struct exynos_mipi_dsim *mipi_dsim = - (struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim(); - unsigned int reg = (readl(&mipi_dsim->escmode)) & - ~(0x1 << DSIM_FORCE_STOP_STATE_SHIFT); - - reg |= ((enable & 0x1) << DSIM_FORCE_STOP_STATE_SHIFT); - - writel(reg, &mipi_dsim->escmode); -} - -unsigned int exynos_mipi_dsi_is_lane_state(struct mipi_dsim_device *dsim) -{ - struct exynos_mipi_dsim *mipi_dsim = - (struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim(); - unsigned int reg = readl(&mipi_dsim->status); - - /** - * check clock and data lane states. - * if MIPI-DSI controller was enabled at bootloader then - * TX_READY_HS_CLK is enabled otherwise STOP_STATE_CLK. - * so it should be checked for two case. - */ - if ((reg & DSIM_STOP_STATE_DAT(0xf)) && - ((reg & DSIM_STOP_STATE_CLK) || - (reg & DSIM_TX_READY_HS_CLK))) - return 1; - else - return 0; -} - -void exynos_mipi_dsi_set_stop_state_counter(struct mipi_dsim_device *dsim, - unsigned int cnt_val) -{ - struct exynos_mipi_dsim *mipi_dsim = - (struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim(); - unsigned int reg = (readl(&mipi_dsim->escmode)) & - ~(0x7ff << DSIM_STOP_STATE_CNT_SHIFT); - - reg |= ((cnt_val & 0x7ff) << DSIM_STOP_STATE_CNT_SHIFT); - - writel(reg, &mipi_dsim->escmode); -} - -void exynos_mipi_dsi_set_bta_timeout(struct mipi_dsim_device *dsim, - unsigned int timeout) -{ - struct exynos_mipi_dsim *mipi_dsim = - (struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim(); - unsigned int reg = (readl(&mipi_dsim->timeout)) & - ~(0xff << DSIM_BTA_TOUT_SHIFT); - - reg |= (timeout << DSIM_BTA_TOUT_SHIFT); - - writel(reg, &mipi_dsim->timeout); -} - -void exynos_mipi_dsi_set_lpdr_timeout(struct mipi_dsim_device *dsim, - unsigned int timeout) -{ - struct exynos_mipi_dsim *mipi_dsim = - (struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim(); - unsigned int reg = (readl(&mipi_dsim->timeout)) & - ~(0xffff << DSIM_LPDR_TOUT_SHIFT); - - reg |= (timeout << DSIM_LPDR_TOUT_SHIFT); - - writel(reg, &mipi_dsim->timeout); -} - -void exynos_mipi_dsi_set_cpu_transfer_mode(struct mipi_dsim_device *dsim, - unsigned int lp) -{ - struct exynos_mipi_dsim *mipi_dsim = - (struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim(); - unsigned int reg = readl(&mipi_dsim->escmode); - - reg &= ~DSIM_CMD_LPDT_LP; - - if (lp) - reg |= DSIM_CMD_LPDT_LP; - - writel(reg, &mipi_dsim->escmode); -} - -void exynos_mipi_dsi_set_lcdc_transfer_mode(struct mipi_dsim_device *dsim, - unsigned int lp) -{ - struct exynos_mipi_dsim *mipi_dsim = - (struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim(); - unsigned int reg = readl(&mipi_dsim->escmode); - - reg &= ~DSIM_TX_LPDT_LP; - - if (lp) - reg |= DSIM_TX_LPDT_LP; - - writel(reg, &mipi_dsim->escmode); -} - -void exynos_mipi_dsi_enable_hs_clock(struct mipi_dsim_device *dsim, - unsigned int enable) -{ - struct exynos_mipi_dsim *mipi_dsim = - (struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim(); - unsigned int reg = (readl(&mipi_dsim->clkctrl)) & - ~(1 << DSIM_TX_REQUEST_HSCLK_SHIFT); - - reg |= enable << DSIM_TX_REQUEST_HSCLK_SHIFT; - - writel(reg, &mipi_dsim->clkctrl); -} - -void exynos_mipi_dsi_dp_dn_swap(struct mipi_dsim_device *dsim, - unsigned int swap_en) -{ - struct exynos_mipi_dsim *mipi_dsim = - (struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim(); - unsigned int reg = readl(&mipi_dsim->phyacchr1); - - reg &= ~(0x3 << DSIM_DPDN_SWAP_DATA_SHIFT); - reg |= (swap_en & 0x3) << DSIM_DPDN_SWAP_DATA_SHIFT; - - writel(reg, &mipi_dsim->phyacchr1); -} - -void exynos_mipi_dsi_hs_zero_ctrl(struct mipi_dsim_device *dsim, - unsigned int hs_zero) -{ - struct exynos_mipi_dsim *mipi_dsim = - (struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim(); - unsigned int reg = (readl(&mipi_dsim->pllctrl)) & - ~(0xf << DSIM_ZEROCTRL_SHIFT); - - reg |= ((hs_zero & 0xf) << DSIM_ZEROCTRL_SHIFT); - - writel(reg, &mipi_dsim->pllctrl); -} - -void exynos_mipi_dsi_prep_ctrl(struct mipi_dsim_device *dsim, unsigned int prep) -{ - struct exynos_mipi_dsim *mipi_dsim = - (struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim(); - unsigned int reg = (readl(&mipi_dsim->pllctrl)) & - ~(0x7 << DSIM_PRECTRL_SHIFT); - - reg |= ((prep & 0x7) << DSIM_PRECTRL_SHIFT); - - writel(reg, &mipi_dsim->pllctrl); -} - -void exynos_mipi_dsi_clear_interrupt(struct mipi_dsim_device *dsim) -{ - struct exynos_mipi_dsim *mipi_dsim = - (struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim(); - unsigned int reg = readl(&mipi_dsim->intsrc); - - reg |= INTSRC_PLL_STABLE; - - writel(reg, &mipi_dsim->intsrc); -} - -void exynos_mipi_dsi_clear_all_interrupt(struct mipi_dsim_device *dsim) -{ - struct exynos_mipi_dsim *mipi_dsim = - (struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim(); - - writel(0xffffffff, &mipi_dsim->intsrc); -} - -unsigned int exynos_mipi_dsi_is_pll_stable(struct mipi_dsim_device *dsim) -{ - unsigned int reg; - struct exynos_mipi_dsim *mipi_dsim = - (struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim(); - - reg = readl(&mipi_dsim->status); - - return reg & DSIM_PLL_STABLE ? 1 : 0; -} - -unsigned int exynos_mipi_dsi_get_fifo_state(struct mipi_dsim_device *dsim) -{ - struct exynos_mipi_dsim *mipi_dsim = - (struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim(); - - return readl(&mipi_dsim->fifoctrl) & ~(0x1f); -} - -void exynos_mipi_dsi_wr_tx_header(struct mipi_dsim_device *dsim, - unsigned int di, const unsigned char data0, const unsigned char data1) -{ - struct exynos_mipi_dsim *mipi_dsim = - (struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim(); - unsigned int reg = (DSIM_PKTHDR_DAT1(data1) | DSIM_PKTHDR_DAT0(data0) | - DSIM_PKTHDR_DI(di)); - - writel(reg, &mipi_dsim->pkthdr); -} - -unsigned int _exynos_mipi_dsi_get_frame_done_status(struct mipi_dsim_device - *dsim) -{ - struct exynos_mipi_dsim *mipi_dsim = - (struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim(); - unsigned int reg = readl(&mipi_dsim->intsrc); - - return (reg & INTSRC_FRAME_DONE) ? 1 : 0; -} - -void _exynos_mipi_dsi_clear_frame_done(struct mipi_dsim_device *dsim) -{ - struct exynos_mipi_dsim *mipi_dsim = - (struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim(); - unsigned int reg = readl(&mipi_dsim->intsrc); - - writel(reg | INTSRC_FRAME_DONE, &mipi_dsim->intsrc); -} - -void exynos_mipi_dsi_wr_tx_data(struct mipi_dsim_device *dsim, - unsigned int tx_data) -{ - struct exynos_mipi_dsim *mipi_dsim = - (struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim(); - - writel(tx_data, &mipi_dsim->payload); -} diff --git a/drivers/video/exynos_mipi_dsi_lowlevel.h b/drivers/video/exynos_mipi_dsi_lowlevel.h deleted file mode 100644 index 0bede25..0000000 --- a/drivers/video/exynos_mipi_dsi_lowlevel.h +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright (C) 2012 Samsung Electronics - * - * Author: InKi Dae - * Author: Donghwa Lee - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#ifndef _EXYNOS_MIPI_DSI_LOWLEVEL_H -#define _EXYNOS_MIPI_DSI_LOWLEVEL_H - -void exynos_mipi_dsi_register(struct mipi_dsim_device *dsim); -void exynos_mipi_dsi_func_reset(struct mipi_dsim_device *dsim); -void exynos_mipi_dsi_sw_reset(struct mipi_dsim_device *dsim); -void exynos_mipi_dsi_sw_release(struct mipi_dsim_device *dsim); -void exynos_mipi_dsi_set_interrupt_mask(struct mipi_dsim_device *dsim, - unsigned int mode, unsigned int mask); -void exynos_mipi_dsi_set_data_lane_number(struct mipi_dsim_device *dsim, - unsigned int count); -void exynos_mipi_dsi_init_fifo_pointer(struct mipi_dsim_device *dsim, - unsigned int cfg); -void exynos_mipi_dsi_set_phy_tunning(struct mipi_dsim_device *dsim, - unsigned int value); -void exynos_mipi_dsi_set_phy_tunning(struct mipi_dsim_device *dsim, - unsigned int value); -void exynos_mipi_dsi_set_main_disp_resol(struct mipi_dsim_device *dsim, - unsigned int width_resol, unsigned int height_resol); -void exynos_mipi_dsi_set_main_disp_vporch(struct mipi_dsim_device *dsim, - unsigned int cmd_allow, unsigned int vfront, unsigned int vback); -void exynos_mipi_dsi_set_main_disp_hporch(struct mipi_dsim_device *dsim, - unsigned int front, unsigned int back); -void exynos_mipi_dsi_set_main_disp_sync_area(struct mipi_dsim_device *dsim, - unsigned int vert, unsigned int hori); -void exynos_mipi_dsi_set_sub_disp_resol(struct mipi_dsim_device *dsim, - unsigned int vert, unsigned int hori); -void exynos_mipi_dsi_init_config(struct mipi_dsim_device *dsim); -void exynos_mipi_dsi_display_config(struct mipi_dsim_device *dsim, - struct mipi_dsim_config *dsim_config); -void exynos_mipi_dsi_set_data_lane_number(struct mipi_dsim_device *dsim, - unsigned int count); -void exynos_mipi_dsi_enable_lane(struct mipi_dsim_device *dsim, - unsigned int lane, unsigned int enable); -void exynos_mipi_dsi_enable_afc(struct mipi_dsim_device *dsim, - unsigned int enable, unsigned int afc_code); -void exynos_mipi_dsi_enable_pll_bypass(struct mipi_dsim_device *dsim, - unsigned int enable); -void exynos_mipi_dsi_pll_freq_band(struct mipi_dsim_device *dsim, - unsigned int freq_band); -void exynos_mipi_dsi_pll_freq(struct mipi_dsim_device *dsim, - unsigned int pre_divider, unsigned int main_divider, - unsigned int scaler); -void exynos_mipi_dsi_pll_stable_time(struct mipi_dsim_device *dsim, - unsigned int lock_time); -void exynos_mipi_dsi_enable_pll(struct mipi_dsim_device *dsim, - unsigned int enable); -void exynos_mipi_dsi_set_byte_clock_src(struct mipi_dsim_device *dsim, - unsigned int src); -void exynos_mipi_dsi_enable_byte_clock(struct mipi_dsim_device *dsim, - unsigned int enable); -void exynos_mipi_dsi_set_esc_clk_prs(struct mipi_dsim_device *dsim, - unsigned int enable, unsigned int prs_val); -void exynos_mipi_dsi_enable_esc_clk_on_lane(struct mipi_dsim_device *dsim, - unsigned int lane_sel, unsigned int enable); -void exynos_mipi_dsi_force_dphy_stop_state(struct mipi_dsim_device *dsim, - unsigned int enable); -unsigned int exynos_mipi_dsi_is_lane_state(struct mipi_dsim_device *dsim); -void exynos_mipi_dsi_set_stop_state_counter(struct mipi_dsim_device *dsim, - unsigned int cnt_val); -void exynos_mipi_dsi_set_bta_timeout(struct mipi_dsim_device *dsim, - unsigned int timeout); -void exynos_mipi_dsi_set_lpdr_timeout(struct mipi_dsim_device *dsim, - unsigned int timeout); -void exynos_mipi_dsi_set_lcdc_transfer_mode(struct mipi_dsim_device *dsim, - unsigned int lp); -void exynos_mipi_dsi_set_cpu_transfer_mode(struct mipi_dsim_device *dsim, - unsigned int lp); -void exynos_mipi_dsi_enable_hs_clock(struct mipi_dsim_device *dsim, - unsigned int enable); -void exynos_mipi_dsi_dp_dn_swap(struct mipi_dsim_device *dsim, - unsigned int swap_en); -void exynos_mipi_dsi_hs_zero_ctrl(struct mipi_dsim_device *dsim, - unsigned int hs_zero); -void exynos_mipi_dsi_prep_ctrl(struct mipi_dsim_device *dsim, - unsigned int prep); -void exynos_mipi_dsi_clear_interrupt(struct mipi_dsim_device *dsim); -void exynos_mipi_dsi_clear_all_interrupt(struct mipi_dsim_device *dsim); -unsigned int exynos_mipi_dsi_is_pll_stable(struct mipi_dsim_device *dsim); -unsigned int exynos_mipi_dsi_get_fifo_state(struct mipi_dsim_device *dsim); -unsigned int _exynos_mipi_dsi_get_frame_done_status(struct mipi_dsim_device - *dsim); -void _exynos_mipi_dsi_clear_frame_done(struct mipi_dsim_device *dsim); -void exynos_mipi_dsi_wr_tx_header(struct mipi_dsim_device *dsim, - unsigned int di, const unsigned char data0, const unsigned char data1); -void exynos_mipi_dsi_wr_tx_data(struct mipi_dsim_device *dsim, - unsigned int tx_data); - -#endif /* _EXYNOS_MIPI_DSI_LOWLEVEL_H */ diff --git a/drivers/video/exynos_pwm_bl.c b/drivers/video/exynos_pwm_bl.c deleted file mode 100644 index a6890da..0000000 --- a/drivers/video/exynos_pwm_bl.c +++ /dev/null @@ -1,45 +0,0 @@ -/* - * PWM BACKLIGHT driver for Board based on EXYNOS. - * - * Author: Donghwa Lee - * - * Derived from linux/drivers/video/backlight/pwm_backlight.c - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -static struct pwm_backlight_data *pwm; - -static int exynos_pwm_backlight_update_status(void) -{ - int brightness = pwm->brightness; - int max = pwm->max_brightness; - - if (brightness == 0) { - pwm_config(pwm->pwm_id, 0, pwm->period); - pwm_disable(pwm->pwm_id); - } else { - pwm_config(pwm->pwm_id, - brightness * pwm->period / max, pwm->period); - pwm_enable(pwm->pwm_id); - } - return 0; -} - -int exynos_pwm_backlight_init(struct pwm_backlight_data *pd) -{ - pwm = pd; - - exynos_pwm_backlight_update_status(); - - return 0; -} diff --git a/drivers/video/s6e8ax0.c b/drivers/video/s6e8ax0.c index 8494817..1bd49ee 100644 --- a/drivers/video/s6e8ax0.c +++ b/drivers/video/s6e8ax0.c @@ -9,8 +9,8 @@ #include #include -#include "exynos_mipi_dsi_lowlevel.h" -#include "exynos_mipi_dsi_common.h" +#include "exynos/exynos_mipi_dsi_lowlevel.h" +#include "exynos/exynos_mipi_dsi_common.h" static void s6e8ax0_panel_cond(struct mipi_dsim_device *dsim_dev) { -- cgit v0.10.2 From b6feb2675b75c687b9ddb9e5a493cfe4035e387d Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 21 Feb 2016 21:08:39 -0700 Subject: exynos: video: Drop dead code We always use device tree with video, so can drop these #ifdefs. Some of the hardware addresses are not needed either. Signed-off-by: Simon Glass Acked-by: Anatolij Gustschin Acked-by: Anatolij Gustschin Signed-off-by: Minkyu Kang diff --git a/arch/arm/mach-exynos/include/mach/cpu.h b/arch/arm/mach-exynos/include/mach/cpu.h index f12e3d6..1f722df 100644 --- a/arch/arm/mach-exynos/include/mach/cpu.h +++ b/arch/arm/mach-exynos/include/mach/cpu.h @@ -288,9 +288,7 @@ static inline unsigned long __attribute__((no_instrument_function)) \ SAMSUNG_BASE(adc, ADC_BASE) SAMSUNG_BASE(clock, CLOCK_BASE) SAMSUNG_BASE(ace_sfr, ACE_SFR_BASE) -SAMSUNG_BASE(dp, DP_BASE) SAMSUNG_BASE(sysreg, SYSREG_BASE) -SAMSUNG_BASE(fimd, FIMD_BASE) SAMSUNG_BASE(i2c, I2C_BASE) SAMSUNG_BASE(i2s, I2S_BASE) SAMSUNG_BASE(mipi_dsim, MIPI_DSIM_BASE) diff --git a/drivers/video/exynos/exynos_dp_lowlevel.c b/drivers/video/exynos/exynos_dp_lowlevel.c index acb5bc8..e417cf8 100644 --- a/drivers/video/exynos/exynos_dp_lowlevel.c +++ b/drivers/video/exynos/exynos_dp_lowlevel.c @@ -22,7 +22,6 @@ struct exynos_dp *dp_regs; void exynos_dp_set_base_addr(void) { -#if CONFIG_IS_ENABLED(OF_CONTROL) unsigned int node = fdtdec_next_compatible(gd->fdt_blob, 0, COMPAT_SAMSUNG_EXYNOS5_DP); if (node <= 0) @@ -32,9 +31,6 @@ void exynos_dp_set_base_addr(void) node, "reg"); if (dp_regs == NULL) debug("Can't get the DP base address\n"); -#else - dp_regs = (struct exynos_dp *)samsung_get_base_dp(); -#endif } static void exynos_dp_enable_video_input(unsigned int enable) diff --git a/drivers/video/exynos/exynos_fb.c b/drivers/video/exynos/exynos_fb.c index 69edc3a..39e3ade 100644 --- a/drivers/video/exynos/exynos_fb.c +++ b/drivers/video/exynos/exynos_fb.c @@ -28,7 +28,6 @@ DECLARE_GLOBAL_DATA_PTR; static unsigned int panel_width, panel_height; -#if CONFIG_IS_ENABLED(OF_CONTROL) vidinfo_t panel_info = { /* * Insert a value here so that we don't end up in the BSS @@ -36,7 +35,6 @@ vidinfo_t panel_info = { */ .vl_col = -1, }; -#endif ushort *configuration_get_cmap(void) { @@ -126,7 +124,6 @@ static void lcd_panel_on(vidinfo_t *vid) exynos_backlight_on(1); -#if CONFIG_IS_ENABLED(OF_CONTROL) node = fdtdec_next_compatible(gd->fdt_blob, 0, COMPAT_SAMSUNG_EXYNOS_FIMD); if (node <= 0) { @@ -141,7 +138,6 @@ static void lcd_panel_on(vidinfo_t *vid) &bl_en_gpio, GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE); -#endif exynos_cfg_ldo(); exynos_enable_ldo(1); @@ -150,7 +146,6 @@ static void lcd_panel_on(vidinfo_t *vid) exynos_mipi_dsi_init(); } -#if CONFIG_IS_ENABLED(OF_CONTROL) int exynos_lcd_early_init(const void *blob) { unsigned int node; @@ -288,22 +283,16 @@ int exynos_lcd_early_init(const void *blob) return 0; } -#endif void lcd_ctrl_init(void *lcdbase) { set_system_display_ctrl(); set_lcd_clk(); -#if CONFIG_IS_ENABLED(OF_CONTROL) #ifdef CONFIG_EXYNOS_MIPI_DSIM exynos_init_dsim_platform_data(&panel_info); #endif exynos_lcd_misc_init(&panel_info); -#else - /* initialize parameters which is specific to panel. */ - init_panel_info(&panel_info); -#endif panel_width = panel_info.vl_width; panel_height = panel_info.vl_height; diff --git a/drivers/video/exynos/exynos_fimd.c b/drivers/video/exynos/exynos_fimd.c index ac001a8..019d88f 100644 --- a/drivers/video/exynos/exynos_fimd.c +++ b/drivers/video/exynos/exynos_fimd.c @@ -251,7 +251,6 @@ void exynos_fimd_window_off(unsigned int win_id) writel(cfg, &fimd_ctrl->winshmap); } -#if CONFIG_IS_ENABLED(OF_CONTROL) /* * The reset value for FIMD SYSMMU register MMU_CTRL is 3 * on Exynos5420 and newer versions. @@ -289,13 +288,11 @@ void exynos_fimd_disable_sysmmu(void) writel(0x0, sysmmufimd); } } -#endif void exynos_fimd_lcd_init(vidinfo_t *vid) { unsigned int cfg = 0, rgb_mode; unsigned int offset; -#if CONFIG_IS_ENABLED(OF_CONTROL) unsigned int node; node = fdtdec_next_compatible(gd->fdt_blob, @@ -311,10 +308,6 @@ void exynos_fimd_lcd_init(vidinfo_t *vid) if (fdtdec_get_bool(gd->fdt_blob, node, "samsung,disable-sysmmu")) exynos_fimd_disable_sysmmu(); -#else - fimd_ctrl = (struct exynos_fb *)samsung_get_base_fimd(); -#endif - offset = exynos_fimd_get_base_offset(); /* store panel info to global variable */ diff --git a/drivers/video/exynos/exynos_mipi_dsi.c b/drivers/video/exynos/exynos_mipi_dsi.c index b597acc..5001e16 100644 --- a/drivers/video/exynos/exynos_mipi_dsi.c +++ b/drivers/video/exynos/exynos_mipi_dsi.c @@ -28,11 +28,9 @@ DECLARE_GLOBAL_DATA_PTR; static struct exynos_platform_mipi_dsim *dsim_pd; -#if CONFIG_IS_ENABLED(OF_CONTROL) static struct mipi_dsim_config dsim_config_dt; static struct exynos_platform_mipi_dsim dsim_platform_data_dt; static struct mipi_dsim_lcd_device mipi_lcd_device_dt; -#endif struct mipi_dsim_ddi { int bus_id; @@ -249,7 +247,6 @@ void exynos_set_dsim_platform_data(struct exynos_platform_mipi_dsim *pd) dsim_pd = pd; } -#if CONFIG_IS_ENABLED(OF_CONTROL) int exynos_dsim_config_parse_dt(const void *blob) { int node; @@ -334,4 +331,3 @@ void exynos_init_dsim_platform_data(vidinfo_t *vid) dsim_pd = &dsim_platform_data_dt; } -#endif diff --git a/include/exynos_lcd.h b/include/exynos_lcd.h index 3969a6a..e1769f0 100644 --- a/include/exynos_lcd.h +++ b/include/exynos_lcd.h @@ -77,6 +77,4 @@ typedef struct vidinfo { unsigned int dual_lcd_enabled; } vidinfo_t; -void init_panel_info(vidinfo_t *vid); - #endif -- cgit v0.10.2 From aaca5b1902e1d711d34f2fb741417ec7bae59ad6 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 21 Feb 2016 21:08:40 -0700 Subject: exynos: video: Remove use of vidinfo_t typedef Use 'struct vidinfo' instead so that we can change this to a struct with a different name in future. Signed-off-by: Simon Glass Acked-by: Anatolij Gustschin Signed-off-by: Minkyu Kang diff --git a/arch/arm/mach-exynos/include/mach/mipi_dsim.h b/arch/arm/mach-exynos/include/mach/mipi_dsim.h index c9e8e06..a77b5c8 100644 --- a/arch/arm/mach-exynos/include/mach/mipi_dsim.h +++ b/arch/arm/mach-exynos/include/mach/mipi_dsim.h @@ -369,7 +369,8 @@ int exynos_mipi_dsi_register_lcd_device(struct mipi_dsim_lcd_device *lcd_dev); void exynos_set_dsim_platform_data(struct exynos_platform_mipi_dsim *pd); -void exynos_init_dsim_platform_data(vidinfo_t *vid); +struct vidinfo; +void exynos_init_dsim_platform_data(struct vidinfo *vid); /* panel driver init based on mipi dsi interface */ void s6e8ax0_init(void); diff --git a/drivers/video/exynos/exynos_fb.c b/drivers/video/exynos/exynos_fb.c index 39e3ade..90d2038 100644 --- a/drivers/video/exynos/exynos_fb.c +++ b/drivers/video/exynos/exynos_fb.c @@ -28,7 +28,7 @@ DECLARE_GLOBAL_DATA_PTR; static unsigned int panel_width, panel_height; -vidinfo_t panel_info = { +struct vidinfo panel_info = { /* * Insert a value here so that we don't end up in the BSS * Reference: drivers/video/tegra.c @@ -45,7 +45,7 @@ ushort *configuration_get_cmap(void) #endif } -static void exynos_lcd_init_mem(void *lcdbase, vidinfo_t *vid) +static void exynos_lcd_init_mem(void *lcdbase, struct vidinfo *vid) { unsigned long palette_size; unsigned int fb_size; @@ -58,7 +58,7 @@ static void exynos_lcd_init_mem(void *lcdbase, vidinfo_t *vid) (unsigned long)fb_size, palette_size); } -static void exynos_lcd_init(vidinfo_t *vid) +static void exynos_lcd_init(struct vidinfo *vid) { exynos_fimd_lcd_init(vid); @@ -94,12 +94,12 @@ __weak void exynos_backlight_reset(void) { } -__weak int exynos_lcd_misc_init(vidinfo_t *vid) +__weak int exynos_lcd_misc_init(struct vidinfo *vid) { return 0; } -static void lcd_panel_on(vidinfo_t *vid) +static void lcd_panel_on(struct vidinfo *vid) { struct gpio_desc pwm_out_gpio; struct gpio_desc bl_en_gpio; diff --git a/drivers/video/exynos/exynos_fimd.c b/drivers/video/exynos/exynos_fimd.c index 019d88f..e6fb5d1 100644 --- a/drivers/video/exynos/exynos_fimd.c +++ b/drivers/video/exynos/exynos_fimd.c @@ -22,7 +22,7 @@ DECLARE_GLOBAL_DATA_PTR; static unsigned long *lcd_base_addr; -static vidinfo_t *pvid; +static struct vidinfo *pvid; static struct exynos_fb *fimd_ctrl; void exynos_fimd_lcd_init_mem(u_long screen_base, u_long fb_size, @@ -123,7 +123,7 @@ static void exynos_fimd_set_buffer_address(unsigned int win_id) EXYNOS_BUFFER_OFFSET(win_id)); } -static void exynos_fimd_set_clock(vidinfo_t *pvid) +static void exynos_fimd_set_clock(struct vidinfo *pvid) { unsigned int cfg = 0, div = 0, remainder, remainder_div; unsigned long pixel_clock; @@ -289,7 +289,7 @@ void exynos_fimd_disable_sysmmu(void) } } -void exynos_fimd_lcd_init(vidinfo_t *vid) +void exynos_fimd_lcd_init(struct vidinfo *vid) { unsigned int cfg = 0, rgb_mode; unsigned int offset; diff --git a/drivers/video/exynos/exynos_mipi_dsi_common.c b/drivers/video/exynos/exynos_mipi_dsi_common.c index 925d515..85c5e0d 100644 --- a/drivers/video/exynos/exynos_mipi_dsi_common.c +++ b/drivers/video/exynos/exynos_mipi_dsi_common.c @@ -465,7 +465,7 @@ int exynos_mipi_dsi_enable_frame_done_int(struct mipi_dsim_device *dsim, } static void convert_to_fb_videomode(struct fb_videomode *mode1, - vidinfo_t *mode2) + struct vidinfo *mode2) { mode1->xres = mode2->vl_width; mode1->yres = mode2->vl_height; @@ -482,10 +482,10 @@ int exynos_mipi_dsi_set_display_mode(struct mipi_dsim_device *dsim, { struct exynos_platform_mipi_dsim *dsim_pd; struct fb_videomode lcd_video; - vidinfo_t *vid; + struct vidinfo *vid; dsim_pd = (struct exynos_platform_mipi_dsim *)dsim->pd; - vid = (vidinfo_t *)dsim_pd->lcd_panel_info; + vid = (struct vidinfo *)dsim_pd->lcd_panel_info; convert_to_fb_videomode(&lcd_video, vid); -- cgit v0.10.2 From 40d500212f74c92ef014ae8df697416e160ee743 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 21 Feb 2016 21:08:41 -0700 Subject: exynos: video: Drop the static lcd_base_addr variable Drop this and use parameters instead. Signed-off-by: Simon Glass Acked-by: Anatolij Gustschin Signed-off-by: Minkyu Kang diff --git a/drivers/video/exynos/exynos_fb.c b/drivers/video/exynos/exynos_fb.c index 90d2038..a3acdcc 100644 --- a/drivers/video/exynos/exynos_fb.c +++ b/drivers/video/exynos/exynos_fb.c @@ -45,22 +45,9 @@ ushort *configuration_get_cmap(void) #endif } -static void exynos_lcd_init_mem(void *lcdbase, struct vidinfo *vid) +static void exynos_lcd_init(struct vidinfo *vid, ulong lcd_base) { - unsigned long palette_size; - unsigned int fb_size; - - fb_size = vid->vl_row * vid->vl_col * (NBITS(vid->vl_bpix) >> 3); - - palette_size = NBITS(vid->vl_bpix) == 8 ? 256 : 16; - - exynos_fimd_lcd_init_mem((unsigned long)lcdbase, - (unsigned long)fb_size, palette_size); -} - -static void exynos_lcd_init(struct vidinfo *vid) -{ - exynos_fimd_lcd_init(vid); + exynos_fimd_lcd_init(vid, lcd_base); /* Enable flushing after LCD writes if requested */ lcd_set_flush_dcache(1); @@ -297,9 +284,7 @@ void lcd_ctrl_init(void *lcdbase) panel_width = panel_info.vl_width; panel_height = panel_info.vl_height; - exynos_lcd_init_mem(lcdbase, &panel_info); - - exynos_lcd_init(&panel_info); + exynos_lcd_init(&panel_info, (ulong)lcdbase); } void lcd_enable(void) diff --git a/drivers/video/exynos/exynos_fb.h b/drivers/video/exynos/exynos_fb.h index 2c2f94b..833be6a 100644 --- a/drivers/video/exynos/exynos_fb.h +++ b/drivers/video/exynos/exynos_fb.h @@ -35,7 +35,7 @@ enum exynos_cpu_auto_cmd_rate { void exynos_fimd_lcd_init_mem(unsigned long screen_base, unsigned long fb_size, unsigned long palette_size); -void exynos_fimd_lcd_init(vidinfo_t *vid); +void exynos_fimd_lcd_init(struct vidinfo *vid, ulong lcd_base_address); unsigned long exynos_fimd_calc_fbsize(void); #endif diff --git a/drivers/video/exynos/exynos_fimd.c b/drivers/video/exynos/exynos_fimd.c index e6fb5d1..a1de9ac 100644 --- a/drivers/video/exynos/exynos_fimd.c +++ b/drivers/video/exynos/exynos_fimd.c @@ -21,16 +21,9 @@ DECLARE_GLOBAL_DATA_PTR; -static unsigned long *lcd_base_addr; static struct vidinfo *pvid; static struct exynos_fb *fimd_ctrl; -void exynos_fimd_lcd_init_mem(u_long screen_base, u_long fb_size, - u_long palette_size) -{ - lcd_base_addr = (unsigned long *)screen_base; -} - static void exynos_fimd_set_dualrgb(unsigned int enabled) { unsigned int cfg = 0; @@ -47,7 +40,8 @@ static void exynos_fimd_set_dualrgb(unsigned int enabled) writel(cfg, &fimd_ctrl->dualrgb); } -static void exynos_fimd_set_dp_clkcon(unsigned int enabled) +static void exynos_fimd_set_dp_clkcon(struct vidinfo *pvid, + unsigned int enabled) { unsigned int cfg = 0; @@ -57,7 +51,7 @@ static void exynos_fimd_set_dp_clkcon(unsigned int enabled) writel(cfg, &fimd_ctrl->dp_mie_clkcon); } -static void exynos_fimd_set_par(unsigned int win_id) +static void exynos_fimd_set_par(struct vidinfo *pvid, unsigned int win_id) { unsigned int cfg = 0; @@ -109,11 +103,13 @@ static void exynos_fimd_set_par(unsigned int win_id) EXYNOS_VIDOSD(win_id)); } -static void exynos_fimd_set_buffer_address(unsigned int win_id) +static void exynos_fimd_set_buffer_address(struct vidinfo *pvid, + unsigned int win_id, + ulong lcd_base_addr) { unsigned long start_addr, end_addr; - start_addr = (unsigned long)lcd_base_addr; + start_addr = lcd_base_addr; end_addr = start_addr + ((pvid->vl_col * (NBITS(pvid->vl_bpix) / 8)) * pvid->vl_row); @@ -289,7 +285,7 @@ void exynos_fimd_disable_sysmmu(void) } } -void exynos_fimd_lcd_init(struct vidinfo *vid) +void exynos_fimd_lcd_init(struct vidinfo *vid, ulong lcd_base_address) { unsigned int cfg = 0, rgb_mode; unsigned int offset; @@ -367,10 +363,10 @@ void exynos_fimd_lcd_init(struct vidinfo *vid) writel(cfg, &fimd_ctrl->vidcon0); /* set par */ - exynos_fimd_set_par(pvid->win_id); + exynos_fimd_set_par(pvid, pvid->win_id); /* set memory address */ - exynos_fimd_set_buffer_address(pvid->win_id); + exynos_fimd_set_buffer_address(pvid, pvid->win_id, lcd_base_address); /* set buffer size */ cfg = EXYNOS_VIDADDR_PAGEWIDTH(pvid->vl_col * NBITS(pvid->vl_bpix) / 8) | @@ -393,7 +389,7 @@ void exynos_fimd_lcd_init(struct vidinfo *vid) /* window on */ exynos_fimd_window_on(pvid->win_id); - exynos_fimd_set_dp_clkcon(pvid->dp_enabled); + exynos_fimd_set_dp_clkcon(pvid, pvid->dp_enabled); } unsigned long exynos_fimd_calc_fbsize(void) -- cgit v0.10.2 From 162fa53c8d3c2f832d791d0bb7a72fec1562fba4 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 21 Feb 2016 21:08:42 -0700 Subject: exynos: video: Drop static variables in exynos_fimd.c Drop these and use parameters instead. Signed-off-by: Simon Glass Acked-by: Anatolij Gustschin Signed-off-by: Minkyu Kang diff --git a/drivers/video/exynos/exynos_fb.h b/drivers/video/exynos/exynos_fb.h index 833be6a..f59cce0 100644 --- a/drivers/video/exynos/exynos_fb.h +++ b/drivers/video/exynos/exynos_fb.h @@ -36,6 +36,6 @@ enum exynos_cpu_auto_cmd_rate { void exynos_fimd_lcd_init_mem(unsigned long screen_base, unsigned long fb_size, unsigned long palette_size); void exynos_fimd_lcd_init(struct vidinfo *vid, ulong lcd_base_address); -unsigned long exynos_fimd_calc_fbsize(void); +unsigned long exynos_fimd_calc_fbsize(struct vidinfo *pvid); #endif diff --git a/drivers/video/exynos/exynos_fimd.c b/drivers/video/exynos/exynos_fimd.c index a1de9ac..039d4c5 100644 --- a/drivers/video/exynos/exynos_fimd.c +++ b/drivers/video/exynos/exynos_fimd.c @@ -21,11 +21,9 @@ DECLARE_GLOBAL_DATA_PTR; -static struct vidinfo *pvid; -static struct exynos_fb *fimd_ctrl; - -static void exynos_fimd_set_dualrgb(unsigned int enabled) +static void exynos_fimd_set_dualrgb(struct vidinfo *pvid, unsigned int enabled) { + struct exynos_fb *fimd_ctrl = pvid->fimd_ctrl; unsigned int cfg = 0; if (enabled) { @@ -43,6 +41,7 @@ static void exynos_fimd_set_dualrgb(unsigned int enabled) static void exynos_fimd_set_dp_clkcon(struct vidinfo *pvid, unsigned int enabled) { + struct exynos_fb *fimd_ctrl = pvid->fimd_ctrl; unsigned int cfg = 0; if (enabled) @@ -53,6 +52,7 @@ static void exynos_fimd_set_dp_clkcon(struct vidinfo *pvid, static void exynos_fimd_set_par(struct vidinfo *pvid, unsigned int win_id) { + struct exynos_fb *fimd_ctrl = pvid->fimd_ctrl; unsigned int cfg = 0; /* set window control */ @@ -107,6 +107,7 @@ static void exynos_fimd_set_buffer_address(struct vidinfo *pvid, unsigned int win_id, ulong lcd_base_addr) { + struct exynos_fb *fimd_ctrl = pvid->fimd_ctrl; unsigned long start_addr, end_addr; start_addr = lcd_base_addr; @@ -121,6 +122,7 @@ static void exynos_fimd_set_buffer_address(struct vidinfo *pvid, static void exynos_fimd_set_clock(struct vidinfo *pvid) { + struct exynos_fb *fimd_ctrl = pvid->fimd_ctrl; unsigned int cfg = 0, div = 0, remainder, remainder_div; unsigned long pixel_clock; unsigned long long src_clock; @@ -172,8 +174,9 @@ static void exynos_fimd_set_clock(struct vidinfo *pvid) writel(cfg, &fimd_ctrl->vidcon0); } -void exynos_set_trigger(void) +void exynos_set_trigger(struct vidinfo *pvid) { + struct exynos_fb *fimd_ctrl = pvid->fimd_ctrl; unsigned int cfg = 0; cfg = readl(&fimd_ctrl->trigcon); @@ -183,8 +186,9 @@ void exynos_set_trigger(void) writel(cfg, &fimd_ctrl->trigcon); } -int exynos_is_i80_frame_done(void) +int exynos_is_i80_frame_done(struct vidinfo *pvid) { + struct exynos_fb *fimd_ctrl = pvid->fimd_ctrl; unsigned int cfg = 0; int status; @@ -197,8 +201,9 @@ int exynos_is_i80_frame_done(void) return status; } -static void exynos_fimd_lcd_on(void) +static void exynos_fimd_lcd_on(struct vidinfo *pvid) { + struct exynos_fb *fimd_ctrl = pvid->fimd_ctrl; unsigned int cfg = 0; /* display on */ @@ -207,8 +212,9 @@ static void exynos_fimd_lcd_on(void) writel(cfg, &fimd_ctrl->vidcon0); } -static void exynos_fimd_window_on(unsigned int win_id) +static void exynos_fimd_window_on(struct vidinfo *pvid, unsigned int win_id) { + struct exynos_fb *fimd_ctrl = pvid->fimd_ctrl; unsigned int cfg = 0; /* enable window */ @@ -223,8 +229,9 @@ static void exynos_fimd_window_on(unsigned int win_id) writel(cfg, &fimd_ctrl->winshmap); } -void exynos_fimd_lcd_off(void) +void exynos_fimd_lcd_off(struct vidinfo *pvid) { + struct exynos_fb *fimd_ctrl = pvid->fimd_ctrl; unsigned int cfg = 0; cfg = readl(&fimd_ctrl->vidcon0); @@ -232,8 +239,9 @@ void exynos_fimd_lcd_off(void) writel(cfg, &fimd_ctrl->vidcon0); } -void exynos_fimd_window_off(unsigned int win_id) +void exynos_fimd_window_off(struct vidinfo *pvid, unsigned int win_id) { + struct exynos_fb *fimd_ctrl = pvid->fimd_ctrl; unsigned int cfg = 0; cfg = readl((unsigned int)&fimd_ctrl->wincon0 + @@ -285,8 +293,9 @@ void exynos_fimd_disable_sysmmu(void) } } -void exynos_fimd_lcd_init(struct vidinfo *vid, ulong lcd_base_address) +void exynos_fimd_lcd_init(struct vidinfo *pvid, ulong lcd_base_address) { + struct exynos_fb *fimd_ctrl; unsigned int cfg = 0, rgb_mode; unsigned int offset; unsigned int node; @@ -296,22 +305,20 @@ void exynos_fimd_lcd_init(struct vidinfo *vid, ulong lcd_base_address) if (node <= 0) debug("exynos_fb: Can't get device node for fimd\n"); - fimd_ctrl = (struct exynos_fb *)fdtdec_get_addr(gd->fdt_blob, - node, "reg"); + fimd_ctrl = (struct exynos_fb *)fdtdec_get_addr(gd->fdt_blob, node, + "reg"); if (fimd_ctrl == NULL) debug("Can't get the FIMD base address\n"); + pvid->fimd_ctrl = fimd_ctrl; if (fdtdec_get_bool(gd->fdt_blob, node, "samsung,disable-sysmmu")) exynos_fimd_disable_sysmmu(); offset = exynos_fimd_get_base_offset(); - /* store panel info to global variable */ - pvid = vid; - - rgb_mode = vid->rgb_mode; + rgb_mode = pvid->rgb_mode; - if (vid->interface_mode == FIMD_RGB_INTERFACE) { + if (pvid->interface_mode == FIMD_RGB_INTERFACE) { cfg |= EXYNOS_VIDCON0_VIDOUT_RGB; writel(cfg, &fimd_ctrl->vidcon0); @@ -381,18 +388,18 @@ void exynos_fimd_lcd_init(struct vidinfo *vid, ulong lcd_base_address) exynos_fimd_set_clock(pvid); /* set rgb mode to dual lcd. */ - exynos_fimd_set_dualrgb(pvid->dual_lcd_enabled); + exynos_fimd_set_dualrgb(pvid, pvid->dual_lcd_enabled); /* display on */ - exynos_fimd_lcd_on(); + exynos_fimd_lcd_on(pvid); /* window on */ - exynos_fimd_window_on(pvid->win_id); + exynos_fimd_window_on(pvid, pvid->win_id); exynos_fimd_set_dp_clkcon(pvid, pvid->dp_enabled); } -unsigned long exynos_fimd_calc_fbsize(void) +unsigned long exynos_fimd_calc_fbsize(struct vidinfo *pvid) { return pvid->vl_col * pvid->vl_row * (NBITS(pvid->vl_bpix) / 8); } diff --git a/include/exynos_lcd.h b/include/exynos_lcd.h index e1769f0..1f6c6c7 100644 --- a/include/exynos_lcd.h +++ b/include/exynos_lcd.h @@ -75,6 +75,7 @@ typedef struct vidinfo { unsigned int sclk_div; unsigned int dual_lcd_enabled; + struct exynos_fb *fimd_ctrl; } vidinfo_t; #endif -- cgit v0.10.2 From 9c4d440e859c34994689504f1a0d028619042ef3 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 21 Feb 2016 21:08:43 -0700 Subject: exynos: video: Drop static variables in exynos_fb.c Drop these and use the existing variables instead. Signed-off-by: Simon Glass Acked-by: Anatolij Gustschin Signed-off-by: Minkyu Kang diff --git a/drivers/video/exynos/exynos_fb.c b/drivers/video/exynos/exynos_fb.c index a3acdcc..abc6091 100644 --- a/drivers/video/exynos/exynos_fb.c +++ b/drivers/video/exynos/exynos_fb.c @@ -26,8 +26,6 @@ DECLARE_GLOBAL_DATA_PTR; -static unsigned int panel_width, panel_height; - struct vidinfo panel_info = { /* * Insert a value here so that we don't end up in the BSS @@ -281,16 +279,14 @@ void lcd_ctrl_init(void *lcdbase) #endif exynos_lcd_misc_init(&panel_info); - panel_width = panel_info.vl_width; - panel_height = panel_info.vl_height; - exynos_lcd_init(&panel_info, (ulong)lcdbase); } void lcd_enable(void) { if (panel_info.logo_on) { - memset((void *) gd->fb_base, 0, panel_width * panel_height * + memset((void *)gd->fb_base, 0, + panel_info.vl_width * panel_info.vl_height * (NBITS(panel_info.vl_bpix) >> 3)); } -- cgit v0.10.2 From 8c9b8dc05aec6be390dae8a85da7cb56ed8b4ed9 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 21 Feb 2016 21:08:44 -0700 Subject: exynos: video: Drop static variables in exynos_dp_lowlevel.c Drop these and use parameters instead. Signed-off-by: Simon Glass Acked-by: Anatolij Gustschin Signed-off-by: Minkyu Kang diff --git a/drivers/video/exynos/exynos_dp.c b/drivers/video/exynos/exynos_dp.c index 0d5d090..9945c4b 100644 --- a/drivers/video/exynos/exynos_dp.c +++ b/drivers/video/exynos/exynos_dp.c @@ -38,20 +38,20 @@ static void exynos_dp_disp_info(struct edp_disp_info *disp_info) return; } -static int exynos_dp_init_dp(void) +static int exynos_dp_init_dp(struct exynos_dp *dp_regs) { int ret; - exynos_dp_reset(); + exynos_dp_reset(dp_regs); /* SW defined function Normal operation */ - exynos_dp_enable_sw_func(DP_ENABLE); + exynos_dp_enable_sw_func(dp_regs, DP_ENABLE); - ret = exynos_dp_init_analog_func(); + ret = exynos_dp_init_analog_func(dp_regs); if (ret != EXYNOS_DP_SUCCESS) return ret; - exynos_dp_init_hpd(); - exynos_dp_init_aux(); + exynos_dp_init_hpd(dp_regs); + exynos_dp_init_aux(dp_regs); return ret; } @@ -67,7 +67,7 @@ static unsigned char exynos_dp_calc_edid_check_sum(unsigned char *edid_data) return sum; } -static unsigned int exynos_dp_read_edid(void) +static unsigned int exynos_dp_read_edid(struct exynos_dp *dp_regs) { unsigned char edid[EDID_BLOCK_LENGTH * 2]; unsigned int extend_block = 0; @@ -82,14 +82,15 @@ static unsigned int exynos_dp_read_edid(void) */ /* Read Extension Flag, Number of 128-byte EDID extension blocks */ - exynos_dp_read_byte_from_i2c(I2C_EDID_DEVICE_ADDR, EDID_EXTENSION_FLAG, - &extend_block); + exynos_dp_read_byte_from_i2c(dp_regs, I2C_EDID_DEVICE_ADDR, + EDID_EXTENSION_FLAG, &extend_block); if (extend_block > 0) { printf("DP EDID data includes a single extension!\n"); /* Read EDID data */ - retval = exynos_dp_read_bytes_from_i2c(I2C_EDID_DEVICE_ADDR, + retval = exynos_dp_read_bytes_from_i2c(dp_regs, + I2C_EDID_DEVICE_ADDR, EDID_HEADER_PATTERN, EDID_BLOCK_LENGTH, &edid[EDID_HEADER_PATTERN]); @@ -104,7 +105,8 @@ static unsigned int exynos_dp_read_edid(void) } /* Read additional EDID data */ - retval = exynos_dp_read_bytes_from_i2c(I2C_EDID_DEVICE_ADDR, + retval = exynos_dp_read_bytes_from_i2c(dp_regs, + I2C_EDID_DEVICE_ADDR, EDID_BLOCK_LENGTH, EDID_BLOCK_LENGTH, &edid[EDID_BLOCK_LENGTH]); @@ -118,19 +120,22 @@ static unsigned int exynos_dp_read_edid(void) return -1; } - exynos_dp_read_byte_from_dpcd(DPCD_TEST_REQUEST, - &test_vector); + exynos_dp_read_byte_from_dpcd(dp_regs, DPCD_TEST_REQUEST, + &test_vector); if (test_vector & DPCD_TEST_EDID_READ) { - exynos_dp_write_byte_to_dpcd(DPCD_TEST_EDID_CHECKSUM, + exynos_dp_write_byte_to_dpcd(dp_regs, + DPCD_TEST_EDID_CHECKSUM, edid[EDID_BLOCK_LENGTH + EDID_CHECKSUM]); - exynos_dp_write_byte_to_dpcd(DPCD_TEST_RESPONSE, + exynos_dp_write_byte_to_dpcd(dp_regs, + DPCD_TEST_RESPONSE, DPCD_TEST_EDID_CHECKSUM_WRITE); } } else { debug("DP EDID data does not include any extensions.\n"); /* Read EDID data */ - retval = exynos_dp_read_bytes_from_i2c(I2C_EDID_DEVICE_ADDR, + retval = exynos_dp_read_bytes_from_i2c(dp_regs, + I2C_EDID_DEVICE_ADDR, EDID_HEADER_PATTERN, EDID_BLOCK_LENGTH, &edid[EDID_HEADER_PATTERN]); @@ -145,12 +150,13 @@ static unsigned int exynos_dp_read_edid(void) return -1; } - exynos_dp_read_byte_from_dpcd(DPCD_TEST_REQUEST, + exynos_dp_read_byte_from_dpcd(dp_regs, DPCD_TEST_REQUEST, &test_vector); if (test_vector & DPCD_TEST_EDID_READ) { - exynos_dp_write_byte_to_dpcd(DPCD_TEST_EDID_CHECKSUM, - edid[EDID_CHECKSUM]); - exynos_dp_write_byte_to_dpcd(DPCD_TEST_RESPONSE, + exynos_dp_write_byte_to_dpcd(dp_regs, + DPCD_TEST_EDID_CHECKSUM, edid[EDID_CHECKSUM]); + exynos_dp_write_byte_to_dpcd(dp_regs, + DPCD_TEST_RESPONSE, DPCD_TEST_EDID_CHECKSUM_WRITE); } } @@ -160,7 +166,8 @@ static unsigned int exynos_dp_read_edid(void) return 0; } -static unsigned int exynos_dp_handle_edid(struct edp_device_info *edp_info) +static unsigned int exynos_dp_handle_edid(struct exynos_dp *dp_regs, + struct edp_device_info *edp_info) { unsigned char buf[12]; unsigned int ret; @@ -178,8 +185,8 @@ static unsigned int exynos_dp_handle_edid(struct edp_device_info *edp_info) retry_cnt = 5; while (retry_cnt) { /* Read DPCD 0x0000-0x000b */ - ret = exynos_dp_read_bytes_from_dpcd(DPCD_DPCD_REV, 12, - buf); + ret = exynos_dp_read_bytes_from_dpcd(dp_regs, DPCD_DPCD_REV, 12, + buf); if (ret != EXYNOS_DP_SUCCESS) { if (retry_cnt == 0) { printf("DP read_byte_from_dpcd() failed\n"); @@ -227,7 +234,7 @@ static unsigned int exynos_dp_handle_edid(struct edp_device_info *edp_info) return -EINVAL; } - ret = exynos_dp_read_edid(); + ret = exynos_dp_read_edid(dp_regs); if (ret != EXYNOS_DP_SUCCESS) { printf("DP exynos_dp_read_edid() failed\n"); return -EINVAL; @@ -236,19 +243,20 @@ static unsigned int exynos_dp_handle_edid(struct edp_device_info *edp_info) return ret; } -static void exynos_dp_init_training(void) +static void exynos_dp_init_training(struct exynos_dp *dp_regs) { /* * MACRO_RST must be applied after the PLL_LOCK to avoid * the DP inter pair skew issue for at least 10 us */ - exynos_dp_reset_macro(); + exynos_dp_reset_macro(dp_regs); /* All DP analog module power up */ - exynos_dp_set_analog_power_down(POWER_ALL, 0); + exynos_dp_set_analog_power_down(dp_regs, POWER_ALL, 0); } -static unsigned int exynos_dp_link_start(struct edp_device_info *edp_info) +static unsigned int exynos_dp_link_start(struct exynos_dp *dp_regs, + struct edp_device_info *edp_info) { unsigned char buf[5]; unsigned int ret = 0; @@ -263,33 +271,32 @@ static unsigned int exynos_dp_link_start(struct edp_device_info *edp_info) edp_info->lt_info.cr_loop[3] = 0; /* Set sink to D0 (Sink Not Ready) mode. */ - ret = exynos_dp_write_byte_to_dpcd(DPCD_SINK_POWER_STATE, - DPCD_SET_POWER_STATE_D0); + ret = exynos_dp_write_byte_to_dpcd(dp_regs, DPCD_SINK_POWER_STATE, + DPCD_SET_POWER_STATE_D0); if (ret != EXYNOS_DP_SUCCESS) { printf("DP write_dpcd_byte failed\n"); return ret; } /* Set link rate and count as you want to establish */ - exynos_dp_set_link_bandwidth(edp_info->lane_bw); - exynos_dp_set_lane_count(edp_info->lane_cnt); + exynos_dp_set_link_bandwidth(dp_regs, edp_info->lane_bw); + exynos_dp_set_lane_count(dp_regs, edp_info->lane_cnt); /* Setup RX configuration */ buf[0] = edp_info->lane_bw; buf[1] = edp_info->lane_cnt; - ret = exynos_dp_write_bytes_to_dpcd(DPCD_LINK_BW_SET, 2, - buf); + ret = exynos_dp_write_bytes_to_dpcd(dp_regs, DPCD_LINK_BW_SET, 2, buf); if (ret != EXYNOS_DP_SUCCESS) { printf("DP write_dpcd_byte failed\n"); return ret; } - exynos_dp_set_lane_pre_emphasis(PRE_EMPHASIS_LEVEL_0, + exynos_dp_set_lane_pre_emphasis(dp_regs, PRE_EMPHASIS_LEVEL_0, edp_info->lane_cnt); /* Set training pattern 1 */ - exynos_dp_set_training_pattern(TRAINING_PTN1); + exynos_dp_set_training_pattern(dp_regs, TRAINING_PTN1); /* Set RX training pattern */ buf[0] = DPCD_SCRAMBLING_DISABLED | DPCD_TRAINING_PATTERN_1; @@ -303,8 +310,8 @@ static unsigned int exynos_dp_link_start(struct edp_device_info *edp_info) buf[4] = DPCD_PRE_EMPHASIS_SET_PATTERN_2_LEVEL_0 | DPCD_VOLTAGE_SWING_SET_PATTERN_1_LEVEL_0; - ret = exynos_dp_write_bytes_to_dpcd(DPCD_TRAINING_PATTERN_SET, - 5, buf); + ret = exynos_dp_write_bytes_to_dpcd(dp_regs, DPCD_TRAINING_PATTERN_SET, + 5, buf); if (ret != EXYNOS_DP_SUCCESS) { printf("DP write_dpcd_byte failed\n"); return ret; @@ -313,14 +320,14 @@ static unsigned int exynos_dp_link_start(struct edp_device_info *edp_info) return ret; } -static unsigned int exynos_dp_training_pattern_dis(void) +static unsigned int exynos_dp_training_pattern_dis(struct exynos_dp *dp_regs) { unsigned int ret = EXYNOS_DP_SUCCESS; - exynos_dp_set_training_pattern(DP_NONE); + exynos_dp_set_training_pattern(dp_regs, DP_NONE); - ret = exynos_dp_write_byte_to_dpcd(DPCD_TRAINING_PATTERN_SET, - DPCD_TRAINING_PATTERN_DISABLED); + ret = exynos_dp_write_byte_to_dpcd(dp_regs, DPCD_TRAINING_PATTERN_SET, + DPCD_TRAINING_PATTERN_DISABLED); if (ret != EXYNOS_DP_SUCCESS) { printf("DP request_link_training_req failed\n"); return -EAGAIN; @@ -329,13 +336,14 @@ static unsigned int exynos_dp_training_pattern_dis(void) return ret; } -static unsigned int exynos_dp_enable_rx_to_enhanced_mode(unsigned char enable) +static unsigned int exynos_dp_enable_rx_to_enhanced_mode( + struct exynos_dp *dp_regs, unsigned char enable) { unsigned char data; unsigned int ret = EXYNOS_DP_SUCCESS; - ret = exynos_dp_read_byte_from_dpcd(DPCD_LANE_COUNT_SET, - &data); + ret = exynos_dp_read_byte_from_dpcd(dp_regs, DPCD_LANE_COUNT_SET, + &data); if (ret != EXYNOS_DP_SUCCESS) { printf("DP read_from_dpcd failed\n"); return -EAGAIN; @@ -346,8 +354,7 @@ static unsigned int exynos_dp_enable_rx_to_enhanced_mode(unsigned char enable) else data = DPCD_LN_COUNT_SET(data); - ret = exynos_dp_write_byte_to_dpcd(DPCD_LANE_COUNT_SET, - data); + ret = exynos_dp_write_byte_to_dpcd(dp_regs, DPCD_LANE_COUNT_SET, data); if (ret != EXYNOS_DP_SUCCESS) { printf("DP write_to_dpcd failed\n"); return -EAGAIN; @@ -357,23 +364,25 @@ static unsigned int exynos_dp_enable_rx_to_enhanced_mode(unsigned char enable) return ret; } -static unsigned int exynos_dp_set_enhanced_mode(unsigned char enhance_mode) +static unsigned int exynos_dp_set_enhanced_mode(struct exynos_dp *dp_regs, + unsigned char enhance_mode) { unsigned int ret = EXYNOS_DP_SUCCESS; - ret = exynos_dp_enable_rx_to_enhanced_mode(enhance_mode); + ret = exynos_dp_enable_rx_to_enhanced_mode(dp_regs, enhance_mode); if (ret != EXYNOS_DP_SUCCESS) { printf("DP rx_enhance_mode failed\n"); return -EAGAIN; } - exynos_dp_enable_enhanced_mode(enhance_mode); + exynos_dp_enable_enhanced_mode(dp_regs, enhance_mode); return ret; } -static int exynos_dp_read_dpcd_lane_stat(struct edp_device_info *edp_info, - unsigned char *status) +static int exynos_dp_read_dpcd_lane_stat(struct exynos_dp *dp_regs, + struct edp_device_info *edp_info, + unsigned char *status) { unsigned int ret, i; unsigned char buf[2]; @@ -385,7 +394,8 @@ static int exynos_dp_read_dpcd_lane_stat(struct edp_device_info *edp_info, shift_val[2] = 0; shift_val[3] = 4; - ret = exynos_dp_read_bytes_from_dpcd(DPCD_LANE0_1_STATUS, 2, buf); + ret = exynos_dp_read_bytes_from_dpcd(dp_regs, DPCD_LANE0_1_STATUS, 2, + buf); if (ret != EXYNOS_DP_SUCCESS) { printf("DP read lane status failed\n"); return ret; @@ -404,8 +414,8 @@ static int exynos_dp_read_dpcd_lane_stat(struct edp_device_info *edp_info, return ret; } -static unsigned int exynos_dp_read_dpcd_adj_req(unsigned char lane_num, - unsigned char *sw, unsigned char *em) +static unsigned int exynos_dp_read_dpcd_adj_req(struct exynos_dp *dp_regs, + unsigned char lane_num, unsigned char *sw, unsigned char *em) { unsigned int ret = EXYNOS_DP_SUCCESS; unsigned char buf; @@ -415,7 +425,7 @@ static unsigned int exynos_dp_read_dpcd_adj_req(unsigned char lane_num, /* lane_num value is used as array index, so this range 0 ~ 3 */ dpcd_addr = DPCD_ADJUST_REQUEST_LANE0_1 + (lane_num / 2); - ret = exynos_dp_read_byte_from_dpcd(dpcd_addr, &buf); + ret = exynos_dp_read_byte_from_dpcd(dp_regs, dpcd_addr, &buf); if (ret != EXYNOS_DP_SUCCESS) { printf("DP read adjust request failed\n"); return -EAGAIN; @@ -427,17 +437,18 @@ static unsigned int exynos_dp_read_dpcd_adj_req(unsigned char lane_num, return ret; } -static int exynos_dp_equalizer_err_link(struct edp_device_info *edp_info) +static int exynos_dp_equalizer_err_link(struct exynos_dp *dp_regs, + struct edp_device_info *edp_info) { int ret; - ret = exynos_dp_training_pattern_dis(); + ret = exynos_dp_training_pattern_dis(dp_regs); if (ret != EXYNOS_DP_SUCCESS) { printf("DP training_pattern_disable() failed\n"); edp_info->lt_info.lt_status = DP_LT_FAIL; } - ret = exynos_dp_set_enhanced_mode(edp_info->dpcd_efc); + ret = exynos_dp_set_enhanced_mode(dp_regs, edp_info->dpcd_efc); if (ret != EXYNOS_DP_SUCCESS) { printf("DP set_enhanced_mode() failed\n"); edp_info->lt_info.lt_status = DP_LT_FAIL; @@ -446,7 +457,8 @@ static int exynos_dp_equalizer_err_link(struct edp_device_info *edp_info) return ret; } -static int exynos_dp_reduce_link_rate(struct edp_device_info *edp_info) +static int exynos_dp_reduce_link_rate(struct exynos_dp *dp_regs, + struct edp_device_info *edp_info) { int ret; @@ -456,11 +468,11 @@ static int exynos_dp_reduce_link_rate(struct edp_device_info *edp_info) edp_info->lt_info.lt_status = DP_LT_START; ret = EXYNOS_DP_SUCCESS; } else { - ret = exynos_dp_training_pattern_dis(); + ret = exynos_dp_training_pattern_dis(dp_regs); if (ret != EXYNOS_DP_SUCCESS) printf("DP training_patter_disable() failed\n"); - ret = exynos_dp_set_enhanced_mode(edp_info->dpcd_efc); + ret = exynos_dp_set_enhanced_mode(dp_regs, edp_info->dpcd_efc); if (ret != EXYNOS_DP_SUCCESS) printf("DP set_enhanced_mode() failed\n"); @@ -470,8 +482,8 @@ static int exynos_dp_reduce_link_rate(struct edp_device_info *edp_info) return ret; } -static unsigned int exynos_dp_process_clock_recovery(struct edp_device_info - *edp_info) +static unsigned int exynos_dp_process_clock_recovery(struct exynos_dp *dp_regs, + struct edp_device_info *edp_info) { unsigned int ret = EXYNOS_DP_SUCCESS; unsigned char lane_stat; @@ -484,7 +496,7 @@ static unsigned int exynos_dp_process_clock_recovery(struct edp_device_info debug("DP: %s was called\n", __func__); mdelay(1); - ret = exynos_dp_read_dpcd_lane_stat(edp_info, &lane_stat); + ret = exynos_dp_read_dpcd_lane_stat(dp_regs, edp_info, &lane_stat); if (ret != EXYNOS_DP_SUCCESS) { printf("DP read lane status failed\n"); edp_info->lt_info.lt_status = DP_LT_FAIL; @@ -493,11 +505,11 @@ static unsigned int exynos_dp_process_clock_recovery(struct edp_device_info if (lane_stat & DP_LANE_STAT_CR_DONE) { debug("DP clock Recovery training succeed\n"); - exynos_dp_set_training_pattern(TRAINING_PTN2); + exynos_dp_set_training_pattern(dp_regs, TRAINING_PTN2); for (i = 0; i < edp_info->lane_cnt; i++) { - ret = exynos_dp_read_dpcd_adj_req(i, &adj_req_sw, - &adj_req_em); + ret = exynos_dp_read_dpcd_adj_req(dp_regs, i, + &adj_req_sw, &adj_req_em); if (ret != EXYNOS_DP_SUCCESS) { edp_info->lt_info.lt_status = DP_LT_FAIL; return ret; @@ -511,7 +523,8 @@ static unsigned int exynos_dp_process_clock_recovery(struct edp_device_info lt_ctl_val[i] |= MAX_DRIVE_CURRENT_REACH_3 | MAX_PRE_EMPHASIS_REACH_3; } - exynos_dp_set_lanex_pre_emphasis(lt_ctl_val[i], i); + exynos_dp_set_lanex_pre_emphasis(dp_regs, + lt_ctl_val[i], i); } buf[0] = DPCD_SCRAMBLING_DISABLED | DPCD_TRAINING_PATTERN_2; @@ -520,7 +533,7 @@ static unsigned int exynos_dp_process_clock_recovery(struct edp_device_info buf[3] = lt_ctl_val[2]; buf[4] = lt_ctl_val[3]; - ret = exynos_dp_write_bytes_to_dpcd( + ret = exynos_dp_write_bytes_to_dpcd(dp_regs, DPCD_TRAINING_PATTERN_SET, 5, buf); if (ret != EXYNOS_DP_SUCCESS) { printf("DP write training pattern1 failed\n"); @@ -530,8 +543,9 @@ static unsigned int exynos_dp_process_clock_recovery(struct edp_device_info edp_info->lt_info.lt_status = DP_LT_ET; } else { for (i = 0; i < edp_info->lane_cnt; i++) { - lt_ctl_val[i] = exynos_dp_get_lanex_pre_emphasis(i); - ret = exynos_dp_read_dpcd_adj_req(i, + lt_ctl_val[i] = exynos_dp_get_lanex_pre_emphasis( + dp_regs, i); + ret = exynos_dp_read_dpcd_adj_req(dp_regs, i, &adj_req_sw, &adj_req_em); if (ret != EXYNOS_DP_SUCCESS) { printf("DP read adj req failed\n"); @@ -541,7 +555,8 @@ static unsigned int exynos_dp_process_clock_recovery(struct edp_device_info if ((adj_req_sw == VOLTAGE_LEVEL_3) || (adj_req_em == PRE_EMPHASIS_LEVEL_3)) - ret = exynos_dp_reduce_link_rate(edp_info); + ret = exynos_dp_reduce_link_rate(dp_regs, + edp_info); if ((DRIVE_CURRENT_SET_0_GET(lt_ctl_val[i]) == adj_req_sw) && @@ -550,7 +565,7 @@ static unsigned int exynos_dp_process_clock_recovery(struct edp_device_info edp_info->lt_info.cr_loop[i]++; if (edp_info->lt_info.cr_loop[i] == MAX_CR_LOOP) ret = exynos_dp_reduce_link_rate( - edp_info); + dp_regs, edp_info); } lt_ctl_val[i] = 0; @@ -561,10 +576,11 @@ static unsigned int exynos_dp_process_clock_recovery(struct edp_device_info lt_ctl_val[i] |= MAX_DRIVE_CURRENT_REACH_3 | MAX_PRE_EMPHASIS_REACH_3; } - exynos_dp_set_lanex_pre_emphasis(lt_ctl_val[i], i); + exynos_dp_set_lanex_pre_emphasis(dp_regs, + lt_ctl_val[i], i); } - ret = exynos_dp_write_bytes_to_dpcd( + ret = exynos_dp_write_bytes_to_dpcd(dp_regs, DPCD_TRAINING_LANE0_SET, 4, lt_ctl_val); if (ret != EXYNOS_DP_SUCCESS) { printf("DP write training pattern2 failed\n"); @@ -576,8 +592,8 @@ static unsigned int exynos_dp_process_clock_recovery(struct edp_device_info return ret; } -static unsigned int exynos_dp_process_equalizer_training(struct edp_device_info - *edp_info) +static unsigned int exynos_dp_process_equalizer_training( + struct exynos_dp *dp_regs, struct edp_device_info *edp_info) { unsigned int ret = EXYNOS_DP_SUCCESS; unsigned char lane_stat, adj_req_sw, adj_req_em, i; @@ -589,7 +605,7 @@ static unsigned int exynos_dp_process_equalizer_training(struct edp_device_info mdelay(1); - ret = exynos_dp_read_dpcd_lane_stat(edp_info, &lane_stat); + ret = exynos_dp_read_dpcd_lane_stat(dp_regs, edp_info, &lane_stat); if (ret != EXYNOS_DP_SUCCESS) { printf("DP read lane status failed\n"); edp_info->lt_info.lt_status = DP_LT_FAIL; @@ -599,8 +615,9 @@ static unsigned int exynos_dp_process_equalizer_training(struct edp_device_info debug("DP lane stat : %x\n", lane_stat); if (lane_stat & DP_LANE_STAT_CR_DONE) { - ret = exynos_dp_read_byte_from_dpcd(DPCD_LN_ALIGN_UPDATED, - &sink_stat); + ret = exynos_dp_read_byte_from_dpcd(dp_regs, + DPCD_LN_ALIGN_UPDATED, + &sink_stat); if (ret != EXYNOS_DP_SUCCESS) { edp_info->lt_info.lt_status = DP_LT_FAIL; @@ -610,7 +627,7 @@ static unsigned int exynos_dp_process_equalizer_training(struct edp_device_info interlane_aligned = (sink_stat & DPCD_INTERLANE_ALIGN_DONE); for (i = 0; i < edp_info->lane_cnt; i++) { - ret = exynos_dp_read_dpcd_adj_req(i, + ret = exynos_dp_read_dpcd_adj_req(dp_regs, i, &adj_req_sw, &adj_req_em); if (ret != EXYNOS_DP_SUCCESS) { printf("DP read adj req 1 failed\n"); @@ -634,15 +651,15 @@ static unsigned int exynos_dp_process_equalizer_training(struct edp_device_info && (interlane_aligned == DPCD_INTERLANE_ALIGN_DONE)) { debug("DP Equalizer training succeed\n"); - f_bw = exynos_dp_get_link_bandwidth(); - f_lane_cnt = exynos_dp_get_lane_count(); + f_bw = exynos_dp_get_link_bandwidth(dp_regs); + f_lane_cnt = exynos_dp_get_lane_count(dp_regs); debug("DP final BandWidth : %x\n", f_bw); debug("DP final Lane Count : %x\n", f_lane_cnt); edp_info->lt_info.lt_status = DP_LT_FINISHED; - exynos_dp_equalizer_err_link(edp_info); + exynos_dp_equalizer_err_link(dp_regs, edp_info); } else { edp_info->lt_info.ep_loop++; @@ -650,46 +667,49 @@ static unsigned int exynos_dp_process_equalizer_training(struct edp_device_info if (edp_info->lt_info.ep_loop > MAX_EQ_LOOP) { if (edp_info->lane_bw == DP_LANE_BW_2_70) { ret = exynos_dp_reduce_link_rate( - edp_info); + dp_regs, edp_info); } else { edp_info->lt_info.lt_status = DP_LT_FAIL; - exynos_dp_equalizer_err_link(edp_info); + exynos_dp_equalizer_err_link(dp_regs, + edp_info); } } else { for (i = 0; i < edp_info->lane_cnt; i++) exynos_dp_set_lanex_pre_emphasis( - lt_ctl_val[i], i); + dp_regs, lt_ctl_val[i], i); - ret = exynos_dp_write_bytes_to_dpcd( - DPCD_TRAINING_LANE0_SET, - 4, lt_ctl_val); + ret = exynos_dp_write_bytes_to_dpcd(dp_regs, + DPCD_TRAINING_LANE0_SET, + 4, lt_ctl_val); if (ret != EXYNOS_DP_SUCCESS) { printf("DP set lt pattern failed\n"); edp_info->lt_info.lt_status = DP_LT_FAIL; - exynos_dp_equalizer_err_link(edp_info); + exynos_dp_equalizer_err_link(dp_regs, + edp_info); } } } } else if (edp_info->lane_bw == DP_LANE_BW_2_70) { - ret = exynos_dp_reduce_link_rate(edp_info); + ret = exynos_dp_reduce_link_rate(dp_regs, edp_info); } else { edp_info->lt_info.lt_status = DP_LT_FAIL; - exynos_dp_equalizer_err_link(edp_info); + exynos_dp_equalizer_err_link(dp_regs, edp_info); } return ret; } -static unsigned int exynos_dp_sw_link_training(struct edp_device_info *edp_info) +static unsigned int exynos_dp_sw_link_training(struct exynos_dp *dp_regs, + struct edp_device_info *edp_info) { unsigned int ret = 0; int training_finished; /* Turn off unnecessary lane */ if (edp_info->lane_cnt == 1) - exynos_dp_set_analog_power_down(CH1_BLOCK, 1); + exynos_dp_set_analog_power_down(dp_regs, CH1_BLOCK, 1); training_finished = 0; @@ -699,21 +719,23 @@ static unsigned int exynos_dp_sw_link_training(struct edp_device_info *edp_info) while (!training_finished) { switch (edp_info->lt_info.lt_status) { case DP_LT_START: - ret = exynos_dp_link_start(edp_info); + ret = exynos_dp_link_start(dp_regs, edp_info); if (ret != EXYNOS_DP_SUCCESS) { printf("DP LT:link start failed\n"); return ret; } break; case DP_LT_CR: - ret = exynos_dp_process_clock_recovery(edp_info); + ret = exynos_dp_process_clock_recovery(dp_regs, + edp_info); if (ret != EXYNOS_DP_SUCCESS) { printf("DP LT:clock recovery failed\n"); return ret; } break; case DP_LT_ET: - ret = exynos_dp_process_equalizer_training(edp_info); + ret = exynos_dp_process_equalizer_training(dp_regs, + edp_info); if (ret != EXYNOS_DP_SUCCESS) { printf("DP LT:equalizer training failed\n"); return ret; @@ -730,40 +752,43 @@ static unsigned int exynos_dp_sw_link_training(struct edp_device_info *edp_info) return ret; } -static unsigned int exynos_dp_set_link_train(struct edp_device_info *edp_info) +static unsigned int exynos_dp_set_link_train(struct exynos_dp *dp_regs, + struct edp_device_info *edp_info) { unsigned int ret; - exynos_dp_init_training(); + exynos_dp_init_training(dp_regs); - ret = exynos_dp_sw_link_training(edp_info); + ret = exynos_dp_sw_link_training(dp_regs, edp_info); if (ret != EXYNOS_DP_SUCCESS) printf("DP dp_sw_link_training() failed\n"); return ret; } -static void exynos_dp_enable_scramble(unsigned int enable) +static void exynos_dp_enable_scramble(struct exynos_dp *dp_regs, + unsigned int enable) { unsigned char data; if (enable) { - exynos_dp_enable_scrambling(DP_ENABLE); + exynos_dp_enable_scrambling(dp_regs, DP_ENABLE); - exynos_dp_read_byte_from_dpcd(DPCD_TRAINING_PATTERN_SET, - &data); - exynos_dp_write_byte_to_dpcd(DPCD_TRAINING_PATTERN_SET, + exynos_dp_read_byte_from_dpcd(dp_regs, + DPCD_TRAINING_PATTERN_SET, &data); + exynos_dp_write_byte_to_dpcd(dp_regs, DPCD_TRAINING_PATTERN_SET, (u8)(data & ~DPCD_SCRAMBLING_DISABLED)); } else { - exynos_dp_enable_scrambling(DP_DISABLE); - exynos_dp_read_byte_from_dpcd(DPCD_TRAINING_PATTERN_SET, - &data); - exynos_dp_write_byte_to_dpcd(DPCD_TRAINING_PATTERN_SET, + exynos_dp_enable_scrambling(dp_regs, DP_DISABLE); + exynos_dp_read_byte_from_dpcd(dp_regs, + DPCD_TRAINING_PATTERN_SET, &data); + exynos_dp_write_byte_to_dpcd(dp_regs, DPCD_TRAINING_PATTERN_SET, (u8)(data | DPCD_SCRAMBLING_DISABLED)); } } -static unsigned int exynos_dp_config_video(struct edp_device_info *edp_info) +static unsigned int exynos_dp_config_video(struct exynos_dp *dp_regs, + struct edp_device_info *edp_info) { unsigned int ret = 0; unsigned int retry_cnt; @@ -775,17 +800,18 @@ static unsigned int exynos_dp_config_video(struct edp_device_info *edp_info) return -ENODEV; } else { /* debug slave */ - exynos_dp_config_video_slave_mode(&edp_info->video_info); + exynos_dp_config_video_slave_mode(dp_regs, + &edp_info->video_info); } - exynos_dp_set_video_color_format(&edp_info->video_info); + exynos_dp_set_video_color_format(dp_regs, &edp_info->video_info); if (edp_info->video_info.bist_mode) { - if (exynos_dp_config_video_bist(edp_info) != 0) + if (exynos_dp_config_video_bist(dp_regs, edp_info) != 0) return -1; } - ret = exynos_dp_get_pll_lock_status(); + ret = exynos_dp_get_pll_lock_status(dp_regs); if (ret != PLL_LOCKED) { printf("DP PLL is not locked yet\n"); return -EIO; @@ -794,7 +820,7 @@ static unsigned int exynos_dp_config_video(struct edp_device_info *edp_info) if (edp_info->video_info.master_mode == 0) { retry_cnt = 10; while (retry_cnt) { - ret = exynos_dp_is_slave_video_stream_clock_on(); + ret = exynos_dp_is_slave_video_stream_clock_on(dp_regs); if (ret != EXYNOS_DP_SUCCESS) { if (retry_cnt == 0) { printf("DP stream_clock_on failed\n"); @@ -808,32 +834,34 @@ static unsigned int exynos_dp_config_video(struct edp_device_info *edp_info) } /* Set to use the register calculated M/N video */ - exynos_dp_set_video_cr_mn(CALCULATED_M, 0, 0); + exynos_dp_set_video_cr_mn(dp_regs, CALCULATED_M, 0, 0); /* For video bist, Video timing must be generated by register */ - exynos_dp_set_video_timing_mode(VIDEO_TIMING_FROM_CAPTURE); + exynos_dp_set_video_timing_mode(dp_regs, VIDEO_TIMING_FROM_CAPTURE); /* Enable video bist */ if (edp_info->video_info.bist_pattern != COLOR_RAMP && edp_info->video_info.bist_pattern != BALCK_WHITE_V_LINES && edp_info->video_info.bist_pattern != COLOR_SQUARE) - exynos_dp_enable_video_bist(edp_info->video_info.bist_mode); + exynos_dp_enable_video_bist(dp_regs, + edp_info->video_info.bist_mode); else - exynos_dp_enable_video_bist(DP_DISABLE); + exynos_dp_enable_video_bist(dp_regs, DP_DISABLE); /* Disable video mute */ - exynos_dp_enable_video_mute(DP_DISABLE); + exynos_dp_enable_video_mute(dp_regs, DP_DISABLE); /* Configure video Master or Slave mode */ - exynos_dp_enable_video_master(edp_info->video_info.master_mode); + exynos_dp_enable_video_master(dp_regs, + edp_info->video_info.master_mode); /* Enable video */ - exynos_dp_start_video(); + exynos_dp_start_video(dp_regs); if (edp_info->video_info.master_mode == 0) { retry_cnt = 100; while (retry_cnt) { - ret = exynos_dp_is_video_stream_on(); + ret = exynos_dp_is_video_stream_on(dp_regs); if (ret != EXYNOS_DP_SUCCESS) { if (retry_cnt == 0) { printf("DP Timeout of video stream\n"); @@ -907,6 +935,8 @@ unsigned int exynos_init_dp(void) { unsigned int ret; struct edp_device_info *edp_info; + struct exynos_dp *dp_regs; + int node; edp_info = kzalloc(sizeof(struct edp_device_info), GFP_KERNEL); if (!edp_info) { @@ -917,39 +947,47 @@ unsigned int exynos_init_dp(void) if (exynos_dp_parse_dt(gd->fdt_blob, edp_info)) debug("unable to parse DP DT node\n"); - exynos_dp_set_base_addr(); + node = fdtdec_next_compatible(gd->fdt_blob, 0, + COMPAT_SAMSUNG_EXYNOS5_DP); + if (node <= 0) + debug("exynos_dp: Can't get device node for dp\n"); + + dp_regs = (struct exynos_dp *)fdtdec_get_addr(gd->fdt_blob, node, + "reg"); + if (dp_regs == NULL) + debug("Can't get the DP base address\n"); exynos_dp_disp_info(&edp_info->disp_info); exynos_set_dp_phy(1); - ret = exynos_dp_init_dp(); + ret = exynos_dp_init_dp(dp_regs); if (ret != EXYNOS_DP_SUCCESS) { printf("DP exynos_dp_init_dp() failed\n"); return ret; } - ret = exynos_dp_handle_edid(edp_info); + ret = exynos_dp_handle_edid(dp_regs, edp_info); if (ret != EXYNOS_DP_SUCCESS) { printf("EDP handle_edid fail\n"); return ret; } - ret = exynos_dp_set_link_train(edp_info); + ret = exynos_dp_set_link_train(dp_regs, edp_info); if (ret != EXYNOS_DP_SUCCESS) { printf("DP link training fail\n"); return ret; } - exynos_dp_enable_scramble(DP_ENABLE); - exynos_dp_enable_rx_to_enhanced_mode(DP_ENABLE); - exynos_dp_enable_enhanced_mode(DP_ENABLE); + exynos_dp_enable_scramble(dp_regs, DP_ENABLE); + exynos_dp_enable_rx_to_enhanced_mode(dp_regs, DP_ENABLE); + exynos_dp_enable_enhanced_mode(dp_regs, DP_ENABLE); - exynos_dp_set_link_bandwidth(edp_info->lane_bw); - exynos_dp_set_lane_count(edp_info->lane_cnt); + exynos_dp_set_link_bandwidth(dp_regs, edp_info->lane_bw); + exynos_dp_set_lane_count(dp_regs, edp_info->lane_cnt); - exynos_dp_init_video(); - ret = exynos_dp_config_video(edp_info); + exynos_dp_init_video(dp_regs); + ret = exynos_dp_config_video(dp_regs, edp_info); if (ret != EXYNOS_DP_SUCCESS) { printf("Exynos DP init failed\n"); return ret; diff --git a/drivers/video/exynos/exynos_dp_lowlevel.c b/drivers/video/exynos/exynos_dp_lowlevel.c index e417cf8..153c1c6 100644 --- a/drivers/video/exynos/exynos_dp_lowlevel.c +++ b/drivers/video/exynos/exynos_dp_lowlevel.c @@ -14,26 +14,13 @@ #include #include #include +#include "exynos_dp_lowlevel.h" /* Declare global data pointer */ DECLARE_GLOBAL_DATA_PTR; -struct exynos_dp *dp_regs; - -void exynos_dp_set_base_addr(void) -{ - unsigned int node = fdtdec_next_compatible(gd->fdt_blob, - 0, COMPAT_SAMSUNG_EXYNOS5_DP); - if (node <= 0) - debug("exynos_dp: Can't get device node for dp\n"); - - dp_regs = (struct exynos_dp *)fdtdec_get_addr(gd->fdt_blob, - node, "reg"); - if (dp_regs == NULL) - debug("Can't get the DP base address\n"); -} - -static void exynos_dp_enable_video_input(unsigned int enable) +static void exynos_dp_enable_video_input(struct exynos_dp *dp_regs, + unsigned int enable) { unsigned int reg; @@ -49,7 +36,7 @@ static void exynos_dp_enable_video_input(unsigned int enable) return; } -void exynos_dp_enable_video_bist(unsigned int enable) +void exynos_dp_enable_video_bist(struct exynos_dp *dp_regs, unsigned int enable) { /* enable video bist */ unsigned int reg; @@ -66,7 +53,7 @@ void exynos_dp_enable_video_bist(unsigned int enable) return; } -void exynos_dp_enable_video_mute(unsigned int enable) +void exynos_dp_enable_video_mute(struct exynos_dp *dp_regs, unsigned int enable) { unsigned int reg; @@ -81,7 +68,7 @@ void exynos_dp_enable_video_mute(unsigned int enable) } -static void exynos_dp_init_analog_param(void) +static void exynos_dp_init_analog_param(struct exynos_dp *dp_regs) { unsigned int reg; @@ -130,7 +117,7 @@ static void exynos_dp_init_analog_param(void) writel(reg, &dp_regs->pll_ctl); } -static void exynos_dp_init_interrupt(void) +static void exynos_dp_init_interrupt(struct exynos_dp *dp_regs) { /* Set interrupt registers to initial states */ @@ -157,16 +144,16 @@ static void exynos_dp_init_interrupt(void) writel(0x00, &dp_regs->int_sta_mask); } -void exynos_dp_reset(void) +void exynos_dp_reset(struct exynos_dp *dp_regs) { unsigned int reg_func_1; /* dp tx sw reset */ writel(RESET_DP_TX, &dp_regs->tx_sw_reset); - exynos_dp_enable_video_input(DP_DISABLE); - exynos_dp_enable_video_bist(DP_DISABLE); - exynos_dp_enable_video_mute(DP_DISABLE); + exynos_dp_enable_video_input(dp_regs, DP_DISABLE); + exynos_dp_enable_video_bist(dp_regs, DP_DISABLE); + exynos_dp_enable_video_mute(dp_regs, DP_DISABLE); /* software reset */ reg_func_1 = MASTER_VID_FUNC_EN_N | SLAVE_VID_FUNC_EN_N | @@ -178,13 +165,13 @@ void exynos_dp_reset(void) mdelay(1); - exynos_dp_init_analog_param(); - exynos_dp_init_interrupt(); + exynos_dp_init_analog_param(dp_regs); + exynos_dp_init_interrupt(dp_regs); return; } -void exynos_dp_enable_sw_func(unsigned int enable) +void exynos_dp_enable_sw_func(struct exynos_dp *dp_regs, unsigned int enable) { unsigned int reg; @@ -199,7 +186,8 @@ void exynos_dp_enable_sw_func(unsigned int enable) return; } -unsigned int exynos_dp_set_analog_power_down(unsigned int block, u32 enable) +unsigned int exynos_dp_set_analog_power_down(struct exynos_dp *dp_regs, + unsigned int block, u32 enable) { unsigned int reg; @@ -252,7 +240,7 @@ unsigned int exynos_dp_set_analog_power_down(unsigned int block, u32 enable) return 0; } -unsigned int exynos_dp_get_pll_lock_status(void) +unsigned int exynos_dp_get_pll_lock_status(struct exynos_dp *dp_regs) { unsigned int reg; @@ -264,7 +252,8 @@ unsigned int exynos_dp_get_pll_lock_status(void) return PLL_UNLOCKED; } -static void exynos_dp_set_pll_power(unsigned int enable) +static void exynos_dp_set_pll_power(struct exynos_dp *dp_regs, + unsigned int enable) { unsigned int reg; @@ -277,14 +266,14 @@ static void exynos_dp_set_pll_power(unsigned int enable) writel(reg, &dp_regs->pll_ctl); } -int exynos_dp_init_analog_func(void) +int exynos_dp_init_analog_func(struct exynos_dp *dp_regs) { int ret = EXYNOS_DP_SUCCESS; unsigned int retry_cnt = 10; unsigned int reg; /* Power On All Analog block */ - exynos_dp_set_analog_power_down(POWER_ALL, DP_DISABLE); + exynos_dp_set_analog_power_down(dp_regs, POWER_ALL, DP_DISABLE); reg = PLL_LOCK_CHG; writel(reg, &dp_regs->common_int_sta1); @@ -305,9 +294,9 @@ int exynos_dp_init_analog_func(void) reg &= ~(DP_PLL_RESET); writel(reg, &dp_regs->pll_ctl); - exynos_dp_set_pll_power(DP_ENABLE); + exynos_dp_set_pll_power(dp_regs, DP_ENABLE); - while (exynos_dp_get_pll_lock_status() == PLL_UNLOCKED) { + while (exynos_dp_get_pll_lock_status(dp_regs) == PLL_UNLOCKED) { mdelay(1); retry_cnt--; if (retry_cnt == 0) { @@ -328,7 +317,7 @@ int exynos_dp_init_analog_func(void) return ret; } -void exynos_dp_init_hpd(void) +void exynos_dp_init_hpd(struct exynos_dp *dp_regs) { unsigned int reg; @@ -346,7 +335,7 @@ void exynos_dp_init_hpd(void) return; } -static inline void exynos_dp_reset_aux(void) +static inline void exynos_dp_reset_aux(struct exynos_dp *dp_regs) { unsigned int reg; @@ -358,7 +347,7 @@ static inline void exynos_dp_reset_aux(void) return; } -void exynos_dp_init_aux(void) +void exynos_dp_init_aux(struct exynos_dp *dp_regs) { unsigned int reg; @@ -366,7 +355,7 @@ void exynos_dp_init_aux(void) reg = RPLY_RECEIV | AUX_ERR; writel(reg, &dp_regs->int_sta); - exynos_dp_reset_aux(); + exynos_dp_reset_aux(dp_regs); /* Disable AUX transaction H/W retry */ reg = AUX_BIT_PERIOD_EXPECTED_DELAY(3) | AUX_HW_RETRY_COUNT_SEL(3)| @@ -385,7 +374,7 @@ void exynos_dp_init_aux(void) return; } -void exynos_dp_config_interrupt(void) +void exynos_dp_config_interrupt(struct exynos_dp *dp_regs) { unsigned int reg; @@ -408,7 +397,7 @@ void exynos_dp_config_interrupt(void) return; } -unsigned int exynos_dp_get_plug_in_status(void) +unsigned int exynos_dp_get_plug_in_status(struct exynos_dp *dp_regs) { unsigned int reg; @@ -419,13 +408,13 @@ unsigned int exynos_dp_get_plug_in_status(void) return -1; } -unsigned int exynos_dp_detect_hpd(void) +unsigned int exynos_dp_detect_hpd(struct exynos_dp *dp_regs) { int timeout_loop = DP_TIMEOUT_LOOP_COUNT; mdelay(2); - while (exynos_dp_get_plug_in_status() != 0) { + while (exynos_dp_get_plug_in_status(dp_regs) != 0) { if (timeout_loop == 0) return -EINVAL; mdelay(10); @@ -435,7 +424,7 @@ unsigned int exynos_dp_detect_hpd(void) return EXYNOS_DP_SUCCESS; } -unsigned int exynos_dp_start_aux_transaction(void) +unsigned int exynos_dp_start_aux_transaction(struct exynos_dp *dp_regs) { unsigned int reg; unsigned int ret = 0; @@ -484,8 +473,9 @@ unsigned int exynos_dp_start_aux_transaction(void) return EXYNOS_DP_SUCCESS; } -unsigned int exynos_dp_write_byte_to_dpcd(unsigned int reg_addr, - unsigned char data) +unsigned int exynos_dp_write_byte_to_dpcd(struct exynos_dp *dp_regs, + unsigned int reg_addr, + unsigned char data) { unsigned int reg, ret; @@ -514,7 +504,7 @@ unsigned int exynos_dp_write_byte_to_dpcd(unsigned int reg_addr, writel(reg, &dp_regs->aux_ch_ctl1); /* Start AUX transaction */ - ret = exynos_dp_start_aux_transaction(); + ret = exynos_dp_start_aux_transaction(dp_regs); if (ret != EXYNOS_DP_SUCCESS) { printf("DP Aux transaction failed\n"); return ret; @@ -523,8 +513,9 @@ unsigned int exynos_dp_write_byte_to_dpcd(unsigned int reg_addr, return ret; } -unsigned int exynos_dp_read_byte_from_dpcd(unsigned int reg_addr, - unsigned char *data) +unsigned int exynos_dp_read_byte_from_dpcd(struct exynos_dp *dp_regs, + unsigned int reg_addr, + unsigned char *data) { unsigned int reg; int retval; @@ -550,7 +541,7 @@ unsigned int exynos_dp_read_byte_from_dpcd(unsigned int reg_addr, writel(reg, &dp_regs->aux_ch_ctl1); /* Start AUX transaction */ - retval = exynos_dp_start_aux_transaction(); + retval = exynos_dp_start_aux_transaction(dp_regs); if (!retval) debug("DP Aux Transaction fail!\n"); @@ -561,9 +552,10 @@ unsigned int exynos_dp_read_byte_from_dpcd(unsigned int reg_addr, return retval; } -unsigned int exynos_dp_write_bytes_to_dpcd(unsigned int reg_addr, - unsigned int count, - unsigned char data[]) +unsigned int exynos_dp_write_bytes_to_dpcd(struct exynos_dp *dp_regs, + unsigned int reg_addr, + unsigned int count, + unsigned char data[]) { unsigned int reg; unsigned int start_offset; @@ -610,7 +602,7 @@ unsigned int exynos_dp_write_bytes_to_dpcd(unsigned int reg_addr, writel(reg, &dp_regs->aux_ch_ctl1); /* Start AUX transaction */ - ret = exynos_dp_start_aux_transaction(); + ret = exynos_dp_start_aux_transaction(dp_regs); if (ret != EXYNOS_DP_SUCCESS) { if (retry_cnt == 0) { printf("DP Aux Transaction failed\n"); @@ -626,9 +618,10 @@ unsigned int exynos_dp_write_bytes_to_dpcd(unsigned int reg_addr, return ret; } -unsigned int exynos_dp_read_bytes_from_dpcd(unsigned int reg_addr, - unsigned int count, - unsigned char data[]) +unsigned int exynos_dp_read_bytes_from_dpcd(struct exynos_dp *dp_regs, + unsigned int reg_addr, + unsigned int count, + unsigned char data[]) { unsigned int reg; unsigned int start_offset; @@ -668,7 +661,7 @@ unsigned int exynos_dp_read_bytes_from_dpcd(unsigned int reg_addr, writel(reg, &dp_regs->aux_ch_ctl1); /* Start AUX transaction */ - ret = exynos_dp_start_aux_transaction(); + ret = exynos_dp_start_aux_transaction(dp_regs); if (ret != EXYNOS_DP_SUCCESS) { if (retry_cnt == 0) { printf("DP Aux Transaction failed\n"); @@ -692,8 +685,8 @@ unsigned int exynos_dp_read_bytes_from_dpcd(unsigned int reg_addr, return ret; } -int exynos_dp_select_i2c_device(unsigned int device_addr, - unsigned int reg_addr) +int exynos_dp_select_i2c_device(struct exynos_dp *dp_regs, + unsigned int device_addr, unsigned int reg_addr) { unsigned int reg; int retval; @@ -717,16 +710,16 @@ int exynos_dp_select_i2c_device(unsigned int device_addr, writel(reg, &dp_regs->aux_ch_ctl1); /* Start AUX transaction */ - retval = exynos_dp_start_aux_transaction(); + retval = exynos_dp_start_aux_transaction(dp_regs); if (retval != 0) printf("%s: DP Aux Transaction fail!\n", __func__); return retval; } -int exynos_dp_read_byte_from_i2c(unsigned int device_addr, - unsigned int reg_addr, - unsigned int *data) +int exynos_dp_read_byte_from_i2c(struct exynos_dp *dp_regs, + unsigned int device_addr, + unsigned int reg_addr, unsigned int *data) { unsigned int reg; int i; @@ -738,7 +731,8 @@ int exynos_dp_read_byte_from_i2c(unsigned int device_addr, writel(reg, &dp_regs->buffer_data_ctl); /* Select EDID device */ - retval = exynos_dp_select_i2c_device(device_addr, reg_addr); + retval = exynos_dp_select_i2c_device(dp_regs, device_addr, + reg_addr); if (retval != 0) { printf("DP Select EDID device fail. retry !\n"); continue; @@ -754,7 +748,7 @@ int exynos_dp_read_byte_from_i2c(unsigned int device_addr, writel(reg, &dp_regs->aux_ch_ctl1); /* Start AUX transaction */ - retval = exynos_dp_start_aux_transaction(); + retval = exynos_dp_start_aux_transaction(dp_regs); if (retval != EXYNOS_DP_SUCCESS) printf("%s: DP Aux Transaction fail!\n", __func__); } @@ -766,8 +760,10 @@ int exynos_dp_read_byte_from_i2c(unsigned int device_addr, return retval; } -int exynos_dp_read_bytes_from_i2c(unsigned int device_addr, - unsigned int reg_addr, unsigned int count, unsigned char edid[]) +int exynos_dp_read_bytes_from_i2c(struct exynos_dp *dp_regs, + unsigned int device_addr, + unsigned int reg_addr, unsigned int count, + unsigned char edid[]) { unsigned int reg; unsigned int i, j; @@ -791,9 +787,8 @@ int exynos_dp_read_bytes_from_i2c(unsigned int device_addr, * request without sending addres */ if (!defer) - retval = - exynos_dp_select_i2c_device(device_addr, - reg_addr + i); + retval = exynos_dp_select_i2c_device( + dp_regs, device_addr, reg_addr + i); else defer = 0; @@ -809,7 +804,8 @@ int exynos_dp_read_bytes_from_i2c(unsigned int device_addr, writel(reg, &dp_regs->aux_ch_ctl1); /* Start AUX transaction */ - retval = exynos_dp_start_aux_transaction(); + retval = exynos_dp_start_aux_transaction( + dp_regs); if (retval == 0) break; else @@ -834,7 +830,7 @@ int exynos_dp_read_bytes_from_i2c(unsigned int device_addr, return retval; } -void exynos_dp_reset_macro(void) +void exynos_dp_reset_macro(struct exynos_dp *dp_regs) { unsigned int reg; @@ -849,7 +845,8 @@ void exynos_dp_reset_macro(void) writel(reg, &dp_regs->phy_test); } -void exynos_dp_set_link_bandwidth(unsigned char bwtype) +void exynos_dp_set_link_bandwidth(struct exynos_dp *dp_regs, + unsigned char bwtype) { unsigned int reg; @@ -860,7 +857,7 @@ void exynos_dp_set_link_bandwidth(unsigned char bwtype) writel(reg, &dp_regs->link_bw_set); } -unsigned char exynos_dp_get_link_bandwidth(void) +unsigned char exynos_dp_get_link_bandwidth(struct exynos_dp *dp_regs) { unsigned char ret; unsigned int reg; @@ -871,7 +868,7 @@ unsigned char exynos_dp_get_link_bandwidth(void) return ret; } -void exynos_dp_set_lane_count(unsigned char count) +void exynos_dp_set_lane_count(struct exynos_dp *dp_regs, unsigned char count) { unsigned int reg; @@ -882,7 +879,7 @@ void exynos_dp_set_lane_count(unsigned char count) writel(reg, &dp_regs->lane_count_set); } -unsigned int exynos_dp_get_lane_count(void) +unsigned int exynos_dp_get_lane_count(struct exynos_dp *dp_regs) { unsigned int reg; @@ -891,7 +888,8 @@ unsigned int exynos_dp_get_lane_count(void) return reg; } -unsigned char exynos_dp_get_lanex_pre_emphasis(unsigned char lanecnt) +unsigned char exynos_dp_get_lanex_pre_emphasis(struct exynos_dp *dp_regs, + unsigned char lanecnt) { unsigned int reg_list[DP_LANE_CNT_4] = { (unsigned int)&dp_regs->ln0_link_training_ctl, @@ -903,8 +901,9 @@ unsigned char exynos_dp_get_lanex_pre_emphasis(unsigned char lanecnt) return readl(reg_list[lanecnt]); } -void exynos_dp_set_lanex_pre_emphasis(unsigned char request_val, - unsigned char lanecnt) +void exynos_dp_set_lanex_pre_emphasis(struct exynos_dp *dp_regs, + unsigned char request_val, + unsigned char lanecnt) { unsigned int reg_list[DP_LANE_CNT_4] = { (unsigned int)&dp_regs->ln0_link_training_ctl, @@ -916,7 +915,8 @@ void exynos_dp_set_lanex_pre_emphasis(unsigned char request_val, writel(request_val, reg_list[lanecnt]); } -void exynos_dp_set_lane_pre_emphasis(unsigned int level, unsigned char lanecnt) +void exynos_dp_set_lane_pre_emphasis(struct exynos_dp *dp_regs, + unsigned int level, unsigned char lanecnt) { unsigned char i; unsigned int reg; @@ -939,7 +939,8 @@ void exynos_dp_set_lane_pre_emphasis(unsigned int level, unsigned char lanecnt) } } -void exynos_dp_set_training_pattern(unsigned int pattern) +void exynos_dp_set_training_pattern(struct exynos_dp *dp_regs, + unsigned int pattern) { unsigned int reg = 0; @@ -967,7 +968,8 @@ void exynos_dp_set_training_pattern(unsigned int pattern) writel(reg, &dp_regs->training_ptn_set); } -void exynos_dp_enable_enhanced_mode(unsigned char enable) +void exynos_dp_enable_enhanced_mode(struct exynos_dp *dp_regs, + unsigned char enable) { unsigned int reg; @@ -980,7 +982,7 @@ void exynos_dp_enable_enhanced_mode(unsigned char enable) writel(reg, &dp_regs->sys_ctl4); } -void exynos_dp_enable_scrambling(unsigned int enable) +void exynos_dp_enable_scrambling(struct exynos_dp *dp_regs, unsigned int enable) { unsigned int reg; @@ -993,7 +995,7 @@ void exynos_dp_enable_scrambling(unsigned int enable) writel(reg, &dp_regs->training_ptn_set); } -int exynos_dp_init_video(void) +int exynos_dp_init_video(struct exynos_dp *dp_regs) { unsigned int reg; @@ -1008,7 +1010,8 @@ int exynos_dp_init_video(void) return 0; } -void exynos_dp_config_video_slave_mode(struct edp_video_info *video_info) +void exynos_dp_config_video_slave_mode(struct exynos_dp *dp_regs, + struct edp_video_info *video_info) { unsigned int reg; @@ -1041,7 +1044,8 @@ void exynos_dp_config_video_slave_mode(struct edp_video_info *video_info) writel(reg, &dp_regs->soc_general_ctl); } -void exynos_dp_set_video_color_format(struct edp_video_info *video_info) +void exynos_dp_set_video_color_format(struct exynos_dp *dp_regs, + struct edp_video_info *video_info) { unsigned int reg; @@ -1061,7 +1065,8 @@ void exynos_dp_set_video_color_format(struct edp_video_info *video_info) writel(reg, &dp_regs->video_ctl3); } -int exynos_dp_config_video_bist(struct edp_device_info *edp_info) +int exynos_dp_config_video_bist(struct exynos_dp *dp_regs, + struct edp_device_info *edp_info) { unsigned int reg; unsigned int bist_type = 0; @@ -1151,7 +1156,7 @@ int exynos_dp_config_video_bist(struct edp_device_info *edp_info) return 0; } -unsigned int exynos_dp_is_slave_video_stream_clock_on(void) +unsigned int exynos_dp_is_slave_video_stream_clock_on(struct exynos_dp *dp_regs) { unsigned int reg; @@ -1169,8 +1174,8 @@ unsigned int exynos_dp_is_slave_video_stream_clock_on(void) return EXYNOS_DP_SUCCESS; } -void exynos_dp_set_video_cr_mn(unsigned int type, unsigned int m_value, - unsigned int n_value) +void exynos_dp_set_video_cr_mn(struct exynos_dp *dp_regs, unsigned int type, + unsigned int m_value, unsigned int n_value) { unsigned int reg; @@ -1198,7 +1203,8 @@ void exynos_dp_set_video_cr_mn(unsigned int type, unsigned int m_value, } } -void exynos_dp_set_video_timing_mode(unsigned int type) +void exynos_dp_set_video_timing_mode(struct exynos_dp *dp_regs, + unsigned int type) { unsigned int reg; @@ -1211,7 +1217,8 @@ void exynos_dp_set_video_timing_mode(unsigned int type) writel(reg, &dp_regs->video_ctl10); } -void exynos_dp_enable_video_master(unsigned int enable) +void exynos_dp_enable_video_master(struct exynos_dp *dp_regs, + unsigned int enable) { unsigned int reg; @@ -1227,7 +1234,7 @@ void exynos_dp_enable_video_master(unsigned int enable) writel(reg, &dp_regs->soc_general_ctl); } -void exynos_dp_start_video(void) +void exynos_dp_start_video(struct exynos_dp *dp_regs) { unsigned int reg; @@ -1237,7 +1244,7 @@ void exynos_dp_start_video(void) writel(reg, &dp_regs->video_ctl1); } -unsigned int exynos_dp_is_video_stream_on(void) +unsigned int exynos_dp_is_video_stream_on(struct exynos_dp *dp_regs) { unsigned int reg; diff --git a/drivers/video/exynos/exynos_dp_lowlevel.h b/drivers/video/exynos/exynos_dp_lowlevel.h index 8651681..85459b5 100644 --- a/drivers/video/exynos/exynos_dp_lowlevel.h +++ b/drivers/video/exynos/exynos_dp_lowlevel.h @@ -9,60 +9,81 @@ #ifndef _EXYNOS_EDP_LOWLEVEL_H #define _EXYNOS_EDP_LOWLEVEL_H -void exynos_dp_enable_video_bist(unsigned int enable); -void exynos_dp_enable_video_mute(unsigned int enable); -void exynos_dp_reset(void); -void exynos_dp_enable_sw_func(unsigned int enable); -unsigned int exynos_dp_set_analog_power_down(unsigned int block, u32 enable); -unsigned int exynos_dp_get_pll_lock_status(void); -int exynos_dp_init_analog_func(void); -void exynos_dp_init_hpd(void); -void exynos_dp_init_aux(void); -void exynos_dp_config_interrupt(void); -unsigned int exynos_dp_get_plug_in_status(void); -unsigned int exynos_dp_detect_hpd(void); -unsigned int exynos_dp_start_aux_transaction(void); -unsigned int exynos_dp_write_byte_to_dpcd(unsigned int reg_addr, - unsigned char data); -unsigned int exynos_dp_read_byte_from_dpcd(unsigned int reg_addr, - unsigned char *data); -unsigned int exynos_dp_write_bytes_to_dpcd(unsigned int reg_addr, - unsigned int count, - unsigned char data[]); -unsigned int exynos_dp_read_bytes_from_dpcd( unsigned int reg_addr, - unsigned int count, - unsigned char data[]); -int exynos_dp_select_i2c_device( unsigned int device_addr, - unsigned int reg_addr); -int exynos_dp_read_byte_from_i2c(unsigned int device_addr, - unsigned int reg_addr, unsigned int *data); -int exynos_dp_read_bytes_from_i2c(unsigned int device_addr, - unsigned int reg_addr, unsigned int count, - unsigned char edid[]); -void exynos_dp_reset_macro(void); -void exynos_dp_set_link_bandwidth(unsigned char bwtype); -unsigned char exynos_dp_get_link_bandwidth(void); -void exynos_dp_set_lane_count(unsigned char count); -unsigned int exynos_dp_get_lane_count(void); -unsigned char exynos_dp_get_lanex_pre_emphasis(unsigned char lanecnt); -void exynos_dp_set_lane_pre_emphasis(unsigned int level, - unsigned char lanecnt); -void exynos_dp_set_lanex_pre_emphasis(unsigned char request_val, - unsigned char lanecnt); -void exynos_dp_set_training_pattern(unsigned int pattern); -void exynos_dp_enable_enhanced_mode(unsigned char enable); -void exynos_dp_enable_scrambling(unsigned int enable); -int exynos_dp_init_video(void); -void exynos_dp_config_video_slave_mode(struct edp_video_info *video_info); -void exynos_dp_set_video_color_format(struct edp_video_info *video_info); -int exynos_dp_config_video_bist(struct edp_device_info *edp_info); -unsigned int exynos_dp_is_slave_video_stream_clock_on(void); -void exynos_dp_set_video_cr_mn(unsigned int type, unsigned int m_value, - unsigned int n_value); -void exynos_dp_set_video_timing_mode(unsigned int type); -void exynos_dp_enable_video_master(unsigned int enable); -void exynos_dp_start_video(void); -unsigned int exynos_dp_is_video_stream_on(void); -void exynos_dp_set_base_addr(void); +void exynos_dp_enable_video_bist(struct exynos_dp *dp_regs, + unsigned int enable); +void exynos_dp_enable_video_mute(struct exynos_dp *dp_regs, + unsigned int enable); +void exynos_dp_reset(struct exynos_dp *dp_regs); +void exynos_dp_enable_sw_func(struct exynos_dp *dp_regs, unsigned int enable); +unsigned int exynos_dp_set_analog_power_down(struct exynos_dp *dp_regs, + unsigned int block, u32 enable); +unsigned int exynos_dp_get_pll_lock_status(struct exynos_dp *dp_regs); +int exynos_dp_init_analog_func(struct exynos_dp *dp_regs); +void exynos_dp_init_hpd(struct exynos_dp *dp_regs); +void exynos_dp_init_aux(struct exynos_dp *dp_regs); +void exynos_dp_config_interrupt(struct exynos_dp *dp_regs); +unsigned int exynos_dp_get_plug_in_status(struct exynos_dp *dp_regs); +unsigned int exynos_dp_detect_hpd(struct exynos_dp *dp_regs); +unsigned int exynos_dp_start_aux_transaction(struct exynos_dp *dp_regs); +unsigned int exynos_dp_write_byte_to_dpcd(struct exynos_dp *dp_regs, + unsigned int reg_addr, + unsigned char data); +unsigned int exynos_dp_read_byte_from_dpcd(struct exynos_dp *dp_regs, + unsigned int reg_addr, + unsigned char *data); +unsigned int exynos_dp_write_bytes_to_dpcd(struct exynos_dp *dp_regs, + unsigned int reg_addr, + unsigned int count, + unsigned char data[]); +unsigned int exynos_dp_read_bytes_from_dpcd(struct exynos_dp *dp_regs, + unsigned int reg_addr, + unsigned int count, + unsigned char data[]); +int exynos_dp_select_i2c_device(struct exynos_dp *dp_regs, + unsigned int device_addr, + unsigned int reg_addr); +int exynos_dp_read_byte_from_i2c(struct exynos_dp *dp_regs, + unsigned int device_addr, + unsigned int reg_addr, unsigned int *data); +int exynos_dp_read_bytes_from_i2c(struct exynos_dp *dp_regs, + unsigned int device_addr, + unsigned int reg_addr, unsigned int count, + unsigned char edid[]); +void exynos_dp_reset_macro(struct exynos_dp *dp_regs); +void exynos_dp_set_link_bandwidth(struct exynos_dp *dp_regs, + unsigned char bwtype); +unsigned char exynos_dp_get_link_bandwidth(struct exynos_dp *dp_regs); +void exynos_dp_set_lane_count(struct exynos_dp *dp_regs, unsigned char count); +unsigned int exynos_dp_get_lane_count(struct exynos_dp *dp_regs); +unsigned char exynos_dp_get_lanex_pre_emphasis(struct exynos_dp *dp_regs, + unsigned char lanecnt); +void exynos_dp_set_lane_pre_emphasis(struct exynos_dp *dp_regs, + unsigned int level, unsigned char lanecnt); +void exynos_dp_set_lanex_pre_emphasis(struct exynos_dp *dp_regs, + unsigned char request_val, + unsigned char lanecnt); +void exynos_dp_set_training_pattern(struct exynos_dp *dp_regs, + unsigned int pattern); +void exynos_dp_enable_enhanced_mode(struct exynos_dp *dp_regs, + unsigned char enable); +void exynos_dp_enable_scrambling(struct exynos_dp *dp_regs, + unsigned int enable); +int exynos_dp_init_video(struct exynos_dp *dp_regs); +void exynos_dp_config_video_slave_mode(struct exynos_dp *dp_regs, + struct edp_video_info *video_info); +void exynos_dp_set_video_color_format(struct exynos_dp *dp_regs, + struct edp_video_info *video_info); +int exynos_dp_config_video_bist(struct exynos_dp *dp_regs, + struct edp_device_info *edp_info); +unsigned int exynos_dp_is_slave_video_stream_clock_on( + struct exynos_dp *dp_regs); +void exynos_dp_set_video_cr_mn(struct exynos_dp *dp_regs, unsigned int type, + unsigned int m_value, unsigned int n_value); +void exynos_dp_set_video_timing_mode(struct exynos_dp *dp_regs, + unsigned int type); +void exynos_dp_enable_video_master(struct exynos_dp *dp_regs, + unsigned int enable); +void exynos_dp_start_video(struct exynos_dp *dp_regs); +unsigned int exynos_dp_is_video_stream_on(struct exynos_dp *dp_regs); #endif /* _EXYNOS_DP_LOWLEVEL_H */ -- cgit v0.10.2 From b04135c998b88b0d7c1f21fef64219c508dfbcad Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 21 Feb 2016 21:08:45 -0700 Subject: exynos: video: Move dsim_config_dt into a function In preparation for making this a parameter, move it into the function that sets it up. Signed-off-by: Simon Glass Acked-by: Anatolij Gustschin Signed-off-by: Minkyu Kang diff --git a/drivers/video/exynos/exynos_mipi_dsi.c b/drivers/video/exynos/exynos_mipi_dsi.c index 5001e16..fd96382 100644 --- a/drivers/video/exynos/exynos_mipi_dsi.c +++ b/drivers/video/exynos/exynos_mipi_dsi.c @@ -28,7 +28,6 @@ DECLARE_GLOBAL_DATA_PTR; static struct exynos_platform_mipi_dsim *dsim_pd; -static struct mipi_dsim_config dsim_config_dt; static struct exynos_platform_mipi_dsim dsim_platform_data_dt; static struct mipi_dsim_lcd_device mipi_lcd_device_dt; @@ -247,7 +246,7 @@ void exynos_set_dsim_platform_data(struct exynos_platform_mipi_dsim *pd) dsim_pd = pd; } -int exynos_dsim_config_parse_dt(const void *blob) +int exynos_dsim_config_parse_dt(const void *blob, struct mipi_dsim_config *dt) { int node; @@ -257,47 +256,47 @@ int exynos_dsim_config_parse_dt(const void *blob) return -ENODEV; } - dsim_config_dt.e_interface = fdtdec_get_int(blob, node, + dt->e_interface = fdtdec_get_int(blob, node, "samsung,dsim-config-e-interface", 0); - dsim_config_dt.e_virtual_ch = fdtdec_get_int(blob, node, + dt->e_virtual_ch = fdtdec_get_int(blob, node, "samsung,dsim-config-e-virtual-ch", 0); - dsim_config_dt.e_pixel_format = fdtdec_get_int(blob, node, + dt->e_pixel_format = fdtdec_get_int(blob, node, "samsung,dsim-config-e-pixel-format", 0); - dsim_config_dt.e_burst_mode = fdtdec_get_int(blob, node, + dt->e_burst_mode = fdtdec_get_int(blob, node, "samsung,dsim-config-e-burst-mode", 0); - dsim_config_dt.e_no_data_lane = fdtdec_get_int(blob, node, + dt->e_no_data_lane = fdtdec_get_int(blob, node, "samsung,dsim-config-e-no-data-lane", 0); - dsim_config_dt.e_byte_clk = fdtdec_get_int(blob, node, + dt->e_byte_clk = fdtdec_get_int(blob, node, "samsung,dsim-config-e-byte-clk", 0); - dsim_config_dt.hfp = fdtdec_get_int(blob, node, + dt->hfp = fdtdec_get_int(blob, node, "samsung,dsim-config-hfp", 0); - dsim_config_dt.p = fdtdec_get_int(blob, node, + dt->p = fdtdec_get_int(blob, node, "samsung,dsim-config-p", 0); - dsim_config_dt.m = fdtdec_get_int(blob, node, + dt->m = fdtdec_get_int(blob, node, "samsung,dsim-config-m", 0); - dsim_config_dt.s = fdtdec_get_int(blob, node, + dt->s = fdtdec_get_int(blob, node, "samsung,dsim-config-s", 0); - dsim_config_dt.pll_stable_time = fdtdec_get_int(blob, node, + dt->pll_stable_time = fdtdec_get_int(blob, node, "samsung,dsim-config-pll-stable-time", 0); - dsim_config_dt.esc_clk = fdtdec_get_int(blob, node, + dt->esc_clk = fdtdec_get_int(blob, node, "samsung,dsim-config-esc-clk", 0); - dsim_config_dt.stop_holding_cnt = fdtdec_get_int(blob, node, + dt->stop_holding_cnt = fdtdec_get_int(blob, node, "samsung,dsim-config-stop-holding-cnt", 0); - dsim_config_dt.bta_timeout = fdtdec_get_int(blob, node, + dt->bta_timeout = fdtdec_get_int(blob, node, "samsung,dsim-config-bta-timeout", 0); - dsim_config_dt.rx_timeout = fdtdec_get_int(blob, node, + dt->rx_timeout = fdtdec_get_int(blob, node, "samsung,dsim-config-rx-timeout", 0); mipi_lcd_device_dt.name = fdtdec_get_config_string(blob, @@ -317,7 +316,9 @@ int exynos_dsim_config_parse_dt(const void *blob) void exynos_init_dsim_platform_data(vidinfo_t *vid) { - if (exynos_dsim_config_parse_dt(gd->fdt_blob)) + struct mipi_dsim_config dsim_config_dt; + + if (exynos_dsim_config_parse_dt(gd->fdt_blob, &dsim_config_dt)) debug("Can't get proper dsim config.\n"); strcpy(dsim_platform_data_dt.lcd_panel_name, mipi_lcd_device_dt.name); -- cgit v0.10.2 From 652d15c06e65ea910bada28925b37483b2a1a0d6 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 21 Feb 2016 21:08:46 -0700 Subject: exynos: video: Move struct exynos_platform_mipi_dsim into vidinfo Put the pointer to this structure in struct vidinfo so that we can reference it without it being global. Signed-off-by: Simon Glass Acked-by: Anatolij Gustschin Signed-off-by: Minkyu Kang diff --git a/arch/arm/mach-exynos/include/mach/mipi_dsim.h b/arch/arm/mach-exynos/include/mach/mipi_dsim.h index a77b5c8..df68186 100644 --- a/arch/arm/mach-exynos/include/mach/mipi_dsim.h +++ b/arch/arm/mach-exynos/include/mach/mipi_dsim.h @@ -347,9 +347,10 @@ struct mipi_dsim_lcd_driver { }; #ifdef CONFIG_EXYNOS_MIPI_DSIM -int exynos_mipi_dsi_init(void); +int exynos_mipi_dsi_init(struct exynos_platform_mipi_dsim *dsim_pd); #else -static inline int exynos_mipi_dsi_init(void) +static inline int exynos_mipi_dsi_init( + struct exynos_platform_mipi_dsim *dsim_pd) { return 0; } diff --git a/drivers/video/exynos/exynos_fb.c b/drivers/video/exynos/exynos_fb.c index abc6091..22b9723 100644 --- a/drivers/video/exynos/exynos_fb.c +++ b/drivers/video/exynos/exynos_fb.c @@ -128,7 +128,7 @@ static void lcd_panel_on(struct vidinfo *vid) exynos_enable_ldo(1); if (vid->mipi_enabled) - exynos_mipi_dsi_init(); + exynos_mipi_dsi_init(panel_info.dsim_platform_data_dt); } int exynos_lcd_early_init(const void *blob) diff --git a/drivers/video/exynos/exynos_mipi_dsi.c b/drivers/video/exynos/exynos_mipi_dsi.c index fd96382..b39858a 100644 --- a/drivers/video/exynos/exynos_mipi_dsi.c +++ b/drivers/video/exynos/exynos_mipi_dsi.c @@ -27,8 +27,6 @@ DECLARE_GLOBAL_DATA_PTR; -static struct exynos_platform_mipi_dsim *dsim_pd; -static struct exynos_platform_mipi_dsim dsim_platform_data_dt; static struct mipi_dsim_lcd_device mipi_lcd_device_dt; struct mipi_dsim_ddi { @@ -175,7 +173,7 @@ static struct mipi_dsim_master_ops master_ops = { .clear_dsim_frame_done = exynos_mipi_dsi_clear_frame_done, }; -int exynos_mipi_dsi_init(void) +int exynos_mipi_dsi_init(struct exynos_platform_mipi_dsim *dsim_pd) { struct mipi_dsim_device *dsim; struct mipi_dsim_config *dsim_config; @@ -236,16 +234,6 @@ int exynos_mipi_dsi_init(void) return 0; } -void exynos_set_dsim_platform_data(struct exynos_platform_mipi_dsim *pd) -{ - if (pd == NULL) { - debug("pd is NULL\n"); - return; - } - - dsim_pd = pd; -} - int exynos_dsim_config_parse_dt(const void *blob, struct mipi_dsim_config *dt) { int node; @@ -316,7 +304,8 @@ int exynos_dsim_config_parse_dt(const void *blob, struct mipi_dsim_config *dt) void exynos_init_dsim_platform_data(vidinfo_t *vid) { - struct mipi_dsim_config dsim_config_dt; + static struct mipi_dsim_config dsim_config_dt; + static struct exynos_platform_mipi_dsim dsim_platform_data_dt; if (exynos_dsim_config_parse_dt(gd->fdt_blob, &dsim_config_dt)) debug("Can't get proper dsim config.\n"); @@ -330,5 +319,5 @@ void exynos_init_dsim_platform_data(vidinfo_t *vid) mipi_lcd_device_dt.platform_data = (void *)&dsim_platform_data_dt; exynos_mipi_dsi_register_lcd_device(&mipi_lcd_device_dt); - dsim_pd = &dsim_platform_data_dt; + vid->dsim_platform_data_dt = &dsim_platform_data_dt; } diff --git a/include/exynos_lcd.h b/include/exynos_lcd.h index 1f6c6c7..0aa0fc7 100644 --- a/include/exynos_lcd.h +++ b/include/exynos_lcd.h @@ -76,6 +76,7 @@ typedef struct vidinfo { unsigned int dual_lcd_enabled; struct exynos_fb *fimd_ctrl; + struct exynos_platform_mipi_dsim *dsim_platform_data_dt; } vidinfo_t; #endif -- cgit v0.10.2 From 37ea446b9d7942c0deb5833fede6eb7cabd5bc6d Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 21 Feb 2016 21:08:47 -0700 Subject: exynos: video: Move mipi_lcd_device_dt into a function In preparation for making this a parameter, move it into the function that sets it up. Signed-off-by: Simon Glass Acked-by: Anatolij Gustschin Signed-off-by: Minkyu Kang diff --git a/arch/arm/mach-exynos/include/mach/mipi_dsim.h b/arch/arm/mach-exynos/include/mach/mipi_dsim.h index df68186..43b5c01 100644 --- a/arch/arm/mach-exynos/include/mach/mipi_dsim.h +++ b/arch/arm/mach-exynos/include/mach/mipi_dsim.h @@ -320,7 +320,7 @@ struct mipi_dsim_lcd_device { int reverse_panel; struct mipi_dsim_device *master; - void *platform_data; + struct exynos_platform_mipi_dsim *platform_data; }; /* diff --git a/drivers/video/exynos/exynos_mipi_dsi.c b/drivers/video/exynos/exynos_mipi_dsi.c index b39858a..a5d9b59 100644 --- a/drivers/video/exynos/exynos_mipi_dsi.c +++ b/drivers/video/exynos/exynos_mipi_dsi.c @@ -27,8 +27,6 @@ DECLARE_GLOBAL_DATA_PTR; -static struct mipi_dsim_lcd_device mipi_lcd_device_dt; - struct mipi_dsim_ddi { int bus_id; struct list_head list; @@ -234,7 +232,8 @@ int exynos_mipi_dsi_init(struct exynos_platform_mipi_dsim *dsim_pd) return 0; } -int exynos_dsim_config_parse_dt(const void *blob, struct mipi_dsim_config *dt) +int exynos_dsim_config_parse_dt(const void *blob, struct mipi_dsim_config *dt, + struct mipi_dsim_lcd_device *lcd_dt) { int node; @@ -287,16 +286,16 @@ int exynos_dsim_config_parse_dt(const void *blob, struct mipi_dsim_config *dt) dt->rx_timeout = fdtdec_get_int(blob, node, "samsung,dsim-config-rx-timeout", 0); - mipi_lcd_device_dt.name = fdtdec_get_config_string(blob, + lcd_dt->name = fdtdec_get_config_string(blob, "samsung,dsim-device-name"); - mipi_lcd_device_dt.id = fdtdec_get_int(blob, node, + lcd_dt->id = fdtdec_get_int(blob, node, "samsung,dsim-device-id", 0); - mipi_lcd_device_dt.bus_id = fdtdec_get_int(blob, node, + lcd_dt->bus_id = fdtdec_get_int(blob, node, "samsung,dsim-device-bus_id", 0); - mipi_lcd_device_dt.reverse_panel = fdtdec_get_int(blob, node, + lcd_dt->reverse_panel = fdtdec_get_int(blob, node, "samsung,dsim-device-reverse-panel", 0); return 0; @@ -306,8 +305,10 @@ void exynos_init_dsim_platform_data(vidinfo_t *vid) { static struct mipi_dsim_config dsim_config_dt; static struct exynos_platform_mipi_dsim dsim_platform_data_dt; + static struct mipi_dsim_lcd_device mipi_lcd_device_dt; - if (exynos_dsim_config_parse_dt(gd->fdt_blob, &dsim_config_dt)) + if (exynos_dsim_config_parse_dt(gd->fdt_blob, &dsim_config_dt, + &mipi_lcd_device_dt)) debug("Can't get proper dsim config.\n"); strcpy(dsim_platform_data_dt.lcd_panel_name, mipi_lcd_device_dt.name); -- cgit v0.10.2 From 0c84358cb240953b467034a52fcc2f459ba4029b Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 21 Feb 2016 21:08:48 -0700 Subject: exynos: video: Combine LCD driver into one file At present exynos_fimd.c is the controller and exynos_fb.c is the U-Boot LCD interface. With driver model we want these in one file, so join them in preparation. Signed-off-by: Simon Glass Acked-by: Anatolij Gustschin Signed-off-by: Minkyu Kang diff --git a/drivers/video/exynos/Makefile b/drivers/video/exynos/Makefile index d4bdf32..001a80f 100644 --- a/drivers/video/exynos/Makefile +++ b/drivers/video/exynos/Makefile @@ -6,7 +6,7 @@ # obj-$(CONFIG_EXYNOS_DP) += exynos_dp.o exynos_dp_lowlevel.o -obj-$(CONFIG_EXYNOS_FB) += exynos_fb.o exynos_fimd.o +obj-$(CONFIG_EXYNOS_FB) += exynos_fb.o obj-$(CONFIG_EXYNOS_MIPI_DSIM) += exynos_mipi_dsi.o exynos_mipi_dsi_common.o \ exynos_mipi_dsi_lowlevel.o obj-$(CONFIG_EXYNOS_PWM_BL) += exynos_pwm_bl.o diff --git a/drivers/video/exynos/exynos_fb.c b/drivers/video/exynos/exynos_fb.c index 22b9723..e13d35a 100644 --- a/drivers/video/exynos/exynos_fb.c +++ b/drivers/video/exynos/exynos_fb.c @@ -9,6 +9,7 @@ #include #include +#include #include #include #include @@ -34,6 +35,391 @@ struct vidinfo panel_info = { .vl_col = -1, }; +static void exynos_fimd_set_dualrgb(struct vidinfo *pvid, unsigned int enabled) +{ + struct exynos_fb *fimd_ctrl = pvid->fimd_ctrl; + unsigned int cfg = 0; + + if (enabled) { + cfg = EXYNOS_DUALRGB_BYPASS_DUAL | EXYNOS_DUALRGB_LINESPLIT | + EXYNOS_DUALRGB_VDEN_EN_ENABLE; + + /* in case of Line Split mode, MAIN_CNT doesn't neet to set. */ + cfg |= EXYNOS_DUALRGB_SUB_CNT(pvid->vl_col / 2) | + EXYNOS_DUALRGB_MAIN_CNT(0); + } + + writel(cfg, &fimd_ctrl->dualrgb); +} + +static void exynos_fimd_set_dp_clkcon(struct vidinfo *pvid, + unsigned int enabled) +{ + struct exynos_fb *fimd_ctrl = pvid->fimd_ctrl; + unsigned int cfg = 0; + + if (enabled) + cfg = EXYNOS_DP_CLK_ENABLE; + + writel(cfg, &fimd_ctrl->dp_mie_clkcon); +} + +static void exynos_fimd_set_par(struct vidinfo *pvid, unsigned int win_id) +{ + struct exynos_fb *fimd_ctrl = pvid->fimd_ctrl; + unsigned int cfg = 0; + + /* set window control */ + cfg = readl((unsigned int)&fimd_ctrl->wincon0 + + EXYNOS_WINCON(win_id)); + + cfg &= ~(EXYNOS_WINCON_BITSWP_ENABLE | EXYNOS_WINCON_BYTESWP_ENABLE | + EXYNOS_WINCON_HAWSWP_ENABLE | EXYNOS_WINCON_WSWP_ENABLE | + EXYNOS_WINCON_BURSTLEN_MASK | EXYNOS_WINCON_BPPMODE_MASK | + EXYNOS_WINCON_INRGB_MASK | EXYNOS_WINCON_DATAPATH_MASK); + + /* DATAPATH is DMA */ + cfg |= EXYNOS_WINCON_DATAPATH_DMA; + + cfg |= EXYNOS_WINCON_HAWSWP_ENABLE; + + /* dma burst is 16 */ + cfg |= EXYNOS_WINCON_BURSTLEN_16WORD; + + switch (pvid->vl_bpix) { + case 4: + cfg |= EXYNOS_WINCON_BPPMODE_16BPP_565; + break; + default: + cfg |= EXYNOS_WINCON_BPPMODE_24BPP_888; + break; + } + + writel(cfg, (unsigned int)&fimd_ctrl->wincon0 + + EXYNOS_WINCON(win_id)); + + /* set window position to x=0, y=0*/ + cfg = EXYNOS_VIDOSD_LEFT_X(0) | EXYNOS_VIDOSD_TOP_Y(0); + writel(cfg, (unsigned int)&fimd_ctrl->vidosd0a + + EXYNOS_VIDOSD(win_id)); + + cfg = EXYNOS_VIDOSD_RIGHT_X(pvid->vl_col - 1) | + EXYNOS_VIDOSD_BOTTOM_Y(pvid->vl_row - 1) | + EXYNOS_VIDOSD_RIGHT_X_E(1) | + EXYNOS_VIDOSD_BOTTOM_Y_E(0); + + writel(cfg, (unsigned int)&fimd_ctrl->vidosd0b + + EXYNOS_VIDOSD(win_id)); + + /* set window size for window0*/ + cfg = EXYNOS_VIDOSD_SIZE(pvid->vl_col * pvid->vl_row); + writel(cfg, (unsigned int)&fimd_ctrl->vidosd0c + + EXYNOS_VIDOSD(win_id)); +} + +static void exynos_fimd_set_buffer_address(struct vidinfo *pvid, + unsigned int win_id, + ulong lcd_base_addr) +{ + struct exynos_fb *fimd_ctrl = pvid->fimd_ctrl; + unsigned long start_addr, end_addr; + + start_addr = lcd_base_addr; + end_addr = start_addr + ((pvid->vl_col * (NBITS(pvid->vl_bpix) / 8)) * + pvid->vl_row); + + writel(start_addr, (unsigned int)&fimd_ctrl->vidw00add0b0 + + EXYNOS_BUFFER_OFFSET(win_id)); + writel(end_addr, (unsigned int)&fimd_ctrl->vidw00add1b0 + + EXYNOS_BUFFER_OFFSET(win_id)); +} + +static void exynos_fimd_set_clock(struct vidinfo *pvid) +{ + struct exynos_fb *fimd_ctrl = pvid->fimd_ctrl; + unsigned int cfg = 0, div = 0, remainder, remainder_div; + unsigned long pixel_clock; + unsigned long long src_clock; + + if (pvid->dual_lcd_enabled) { + pixel_clock = pvid->vl_freq * + (pvid->vl_hspw + pvid->vl_hfpd + + pvid->vl_hbpd + pvid->vl_col / 2) * + (pvid->vl_vspw + pvid->vl_vfpd + + pvid->vl_vbpd + pvid->vl_row); + } else if (pvid->interface_mode == FIMD_CPU_INTERFACE) { + pixel_clock = pvid->vl_freq * + pvid->vl_width * pvid->vl_height * + (pvid->cs_setup + pvid->wr_setup + + pvid->wr_act + pvid->wr_hold + 1); + } else { + pixel_clock = pvid->vl_freq * + (pvid->vl_hspw + pvid->vl_hfpd + + pvid->vl_hbpd + pvid->vl_col) * + (pvid->vl_vspw + pvid->vl_vfpd + + pvid->vl_vbpd + pvid->vl_row); + } + + cfg = readl(&fimd_ctrl->vidcon0); + cfg &= ~(EXYNOS_VIDCON0_CLKSEL_MASK | EXYNOS_VIDCON0_CLKVALUP_MASK | + EXYNOS_VIDCON0_CLKVAL_F(0xFF) | EXYNOS_VIDCON0_VCLKEN_MASK | + EXYNOS_VIDCON0_CLKDIR_MASK); + cfg |= (EXYNOS_VIDCON0_CLKSEL_SCLK | EXYNOS_VIDCON0_CLKVALUP_ALWAYS | + EXYNOS_VIDCON0_VCLKEN_NORMAL | EXYNOS_VIDCON0_CLKDIR_DIVIDED); + + src_clock = (unsigned long long) get_lcd_clk(); + + /* get quotient and remainder. */ + remainder = do_div(src_clock, pixel_clock); + div = src_clock; + + remainder *= 10; + remainder_div = remainder / pixel_clock; + + /* round about one places of decimals. */ + if (remainder_div >= 5) + div++; + + /* in case of dual lcd mode. */ + if (pvid->dual_lcd_enabled) + div--; + + cfg |= EXYNOS_VIDCON0_CLKVAL_F(div - 1); + writel(cfg, &fimd_ctrl->vidcon0); +} + +void exynos_set_trigger(struct vidinfo *pvid) +{ + struct exynos_fb *fimd_ctrl = pvid->fimd_ctrl; + unsigned int cfg = 0; + + cfg = readl(&fimd_ctrl->trigcon); + + cfg |= (EXYNOS_I80SOFT_TRIG_EN | EXYNOS_I80START_TRIG); + + writel(cfg, &fimd_ctrl->trigcon); +} + +int exynos_is_i80_frame_done(struct vidinfo *pvid) +{ + struct exynos_fb *fimd_ctrl = pvid->fimd_ctrl; + unsigned int cfg = 0; + int status; + + cfg = readl(&fimd_ctrl->trigcon); + + /* frame done func is valid only when TRIMODE[0] is set to 1. */ + status = (cfg & EXYNOS_I80STATUS_TRIG_DONE) == + EXYNOS_I80STATUS_TRIG_DONE; + + return status; +} + +static void exynos_fimd_lcd_on(struct vidinfo *pvid) +{ + struct exynos_fb *fimd_ctrl = pvid->fimd_ctrl; + unsigned int cfg = 0; + + /* display on */ + cfg = readl(&fimd_ctrl->vidcon0); + cfg |= (EXYNOS_VIDCON0_ENVID_ENABLE | EXYNOS_VIDCON0_ENVID_F_ENABLE); + writel(cfg, &fimd_ctrl->vidcon0); +} + +static void exynos_fimd_window_on(struct vidinfo *pvid, unsigned int win_id) +{ + struct exynos_fb *fimd_ctrl = pvid->fimd_ctrl; + unsigned int cfg = 0; + + /* enable window */ + cfg = readl((unsigned int)&fimd_ctrl->wincon0 + + EXYNOS_WINCON(win_id)); + cfg |= EXYNOS_WINCON_ENWIN_ENABLE; + writel(cfg, (unsigned int)&fimd_ctrl->wincon0 + + EXYNOS_WINCON(win_id)); + + cfg = readl(&fimd_ctrl->winshmap); + cfg |= EXYNOS_WINSHMAP_CH_ENABLE(win_id); + writel(cfg, &fimd_ctrl->winshmap); +} + +void exynos_fimd_lcd_off(struct vidinfo *pvid) +{ + struct exynos_fb *fimd_ctrl = pvid->fimd_ctrl; + unsigned int cfg = 0; + + cfg = readl(&fimd_ctrl->vidcon0); + cfg &= (EXYNOS_VIDCON0_ENVID_DISABLE | EXYNOS_VIDCON0_ENVID_F_DISABLE); + writel(cfg, &fimd_ctrl->vidcon0); +} + +void exynos_fimd_window_off(struct vidinfo *pvid, unsigned int win_id) +{ + struct exynos_fb *fimd_ctrl = pvid->fimd_ctrl; + unsigned int cfg = 0; + + cfg = readl((unsigned int)&fimd_ctrl->wincon0 + + EXYNOS_WINCON(win_id)); + cfg &= EXYNOS_WINCON_ENWIN_DISABLE; + writel(cfg, (unsigned int)&fimd_ctrl->wincon0 + + EXYNOS_WINCON(win_id)); + + cfg = readl(&fimd_ctrl->winshmap); + cfg &= ~EXYNOS_WINSHMAP_CH_DISABLE(win_id); + writel(cfg, &fimd_ctrl->winshmap); +} + +/* +* The reset value for FIMD SYSMMU register MMU_CTRL is 3 +* on Exynos5420 and newer versions. +* This means FIMD SYSMMU is on by default on Exynos5420 +* and newer versions. +* Since in u-boot we don't use SYSMMU, we should disable +* those FIMD SYSMMU. +* Note that there are 2 SYSMMU for FIMD: m0 and m1. +* m0 handles windows 0 and 4, and m1 handles windows 1, 2 and 3. +* We disable both of them here. +*/ +void exynos_fimd_disable_sysmmu(void) +{ + u32 *sysmmufimd; + unsigned int node; + int node_list[2]; + int count; + int i; + + count = fdtdec_find_aliases_for_id(gd->fdt_blob, "fimd", + COMPAT_SAMSUNG_EXYNOS_SYSMMU, node_list, 2); + for (i = 0; i < count; i++) { + node = node_list[i]; + if (node <= 0) { + debug("Can't get device node for fimd sysmmu\n"); + return; + } + + sysmmufimd = (u32 *)fdtdec_get_addr(gd->fdt_blob, node, "reg"); + if (!sysmmufimd) { + debug("Can't get base address for sysmmu fimdm0"); + return; + } + + writel(0x0, sysmmufimd); + } +} + +void exynos_fimd_lcd_init(struct vidinfo *pvid, ulong lcd_base_address) +{ + struct exynos_fb *fimd_ctrl; + unsigned int cfg = 0, rgb_mode; + unsigned int offset; + unsigned int node; + + node = fdtdec_next_compatible(gd->fdt_blob, + 0, COMPAT_SAMSUNG_EXYNOS_FIMD); + if (node <= 0) + debug("exynos_fb: Can't get device node for fimd\n"); + + fimd_ctrl = (struct exynos_fb *)fdtdec_get_addr(gd->fdt_blob, node, + "reg"); + if (fimd_ctrl == NULL) + debug("Can't get the FIMD base address\n"); + pvid->fimd_ctrl = fimd_ctrl; + + if (fdtdec_get_bool(gd->fdt_blob, node, "samsung,disable-sysmmu")) + exynos_fimd_disable_sysmmu(); + + offset = exynos_fimd_get_base_offset(); + + rgb_mode = pvid->rgb_mode; + + if (pvid->interface_mode == FIMD_RGB_INTERFACE) { + cfg |= EXYNOS_VIDCON0_VIDOUT_RGB; + writel(cfg, &fimd_ctrl->vidcon0); + + cfg = readl(&fimd_ctrl->vidcon2); + cfg &= ~(EXYNOS_VIDCON2_WB_MASK | + EXYNOS_VIDCON2_TVFORMATSEL_MASK | + EXYNOS_VIDCON2_TVFORMATSEL_YUV_MASK); + cfg |= EXYNOS_VIDCON2_WB_DISABLE; + writel(cfg, &fimd_ctrl->vidcon2); + + /* set polarity */ + cfg = 0; + if (!pvid->vl_clkp) + cfg |= EXYNOS_VIDCON1_IVCLK_RISING_EDGE; + if (!pvid->vl_hsp) + cfg |= EXYNOS_VIDCON1_IHSYNC_INVERT; + if (!pvid->vl_vsp) + cfg |= EXYNOS_VIDCON1_IVSYNC_INVERT; + if (!pvid->vl_dp) + cfg |= EXYNOS_VIDCON1_IVDEN_INVERT; + + writel(cfg, (unsigned int)&fimd_ctrl->vidcon1 + offset); + + /* set timing */ + cfg = EXYNOS_VIDTCON0_VFPD(pvid->vl_vfpd - 1); + cfg |= EXYNOS_VIDTCON0_VBPD(pvid->vl_vbpd - 1); + cfg |= EXYNOS_VIDTCON0_VSPW(pvid->vl_vspw - 1); + writel(cfg, (unsigned int)&fimd_ctrl->vidtcon0 + offset); + + cfg = EXYNOS_VIDTCON1_HFPD(pvid->vl_hfpd - 1); + cfg |= EXYNOS_VIDTCON1_HBPD(pvid->vl_hbpd - 1); + cfg |= EXYNOS_VIDTCON1_HSPW(pvid->vl_hspw - 1); + + writel(cfg, (unsigned int)&fimd_ctrl->vidtcon1 + offset); + + /* set lcd size */ + cfg = EXYNOS_VIDTCON2_HOZVAL(pvid->vl_col - 1) | + EXYNOS_VIDTCON2_LINEVAL(pvid->vl_row - 1) | + EXYNOS_VIDTCON2_HOZVAL_E(pvid->vl_col - 1) | + EXYNOS_VIDTCON2_LINEVAL_E(pvid->vl_row - 1); + + writel(cfg, (unsigned int)&fimd_ctrl->vidtcon2 + offset); + } + + /* set display mode */ + cfg = readl(&fimd_ctrl->vidcon0); + cfg &= ~EXYNOS_VIDCON0_PNRMODE_MASK; + cfg |= (rgb_mode << EXYNOS_VIDCON0_PNRMODE_SHIFT); + writel(cfg, &fimd_ctrl->vidcon0); + + /* set par */ + exynos_fimd_set_par(pvid, pvid->win_id); + + /* set memory address */ + exynos_fimd_set_buffer_address(pvid, pvid->win_id, lcd_base_address); + + /* set buffer size */ + cfg = EXYNOS_VIDADDR_PAGEWIDTH(pvid->vl_col * + NBITS(pvid->vl_bpix) / 8) | + EXYNOS_VIDADDR_PAGEWIDTH_E(pvid->vl_col * + NBITS(pvid->vl_bpix) / 8) | + EXYNOS_VIDADDR_OFFSIZE(0) | + EXYNOS_VIDADDR_OFFSIZE_E(0); + + writel(cfg, (unsigned int)&fimd_ctrl->vidw00add2 + + EXYNOS_BUFFER_SIZE(pvid->win_id)); + + /* set clock */ + exynos_fimd_set_clock(pvid); + + /* set rgb mode to dual lcd. */ + exynos_fimd_set_dualrgb(pvid, pvid->dual_lcd_enabled); + + /* display on */ + exynos_fimd_lcd_on(pvid); + + /* window on */ + exynos_fimd_window_on(pvid, pvid->win_id); + + exynos_fimd_set_dp_clkcon(pvid, pvid->dp_enabled); +} + +unsigned long exynos_fimd_calc_fbsize(struct vidinfo *pvid) +{ + return pvid->vl_col * pvid->vl_row * (NBITS(pvid->vl_bpix) / 8); +} + ushort *configuration_get_cmap(void) { #if defined(CONFIG_LCD_LOGO) diff --git a/drivers/video/exynos/exynos_fimd.c b/drivers/video/exynos/exynos_fimd.c deleted file mode 100644 index 039d4c5..0000000 --- a/drivers/video/exynos/exynos_fimd.c +++ /dev/null @@ -1,405 +0,0 @@ -/* - * Copyright (C) 2012 Samsung Electronics - * - * Author: InKi Dae - * Author: Donghwa Lee - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "exynos_fb.h" - -DECLARE_GLOBAL_DATA_PTR; - -static void exynos_fimd_set_dualrgb(struct vidinfo *pvid, unsigned int enabled) -{ - struct exynos_fb *fimd_ctrl = pvid->fimd_ctrl; - unsigned int cfg = 0; - - if (enabled) { - cfg = EXYNOS_DUALRGB_BYPASS_DUAL | EXYNOS_DUALRGB_LINESPLIT | - EXYNOS_DUALRGB_VDEN_EN_ENABLE; - - /* in case of Line Split mode, MAIN_CNT doesn't neet to set. */ - cfg |= EXYNOS_DUALRGB_SUB_CNT(pvid->vl_col / 2) | - EXYNOS_DUALRGB_MAIN_CNT(0); - } - - writel(cfg, &fimd_ctrl->dualrgb); -} - -static void exynos_fimd_set_dp_clkcon(struct vidinfo *pvid, - unsigned int enabled) -{ - struct exynos_fb *fimd_ctrl = pvid->fimd_ctrl; - unsigned int cfg = 0; - - if (enabled) - cfg = EXYNOS_DP_CLK_ENABLE; - - writel(cfg, &fimd_ctrl->dp_mie_clkcon); -} - -static void exynos_fimd_set_par(struct vidinfo *pvid, unsigned int win_id) -{ - struct exynos_fb *fimd_ctrl = pvid->fimd_ctrl; - unsigned int cfg = 0; - - /* set window control */ - cfg = readl((unsigned int)&fimd_ctrl->wincon0 + - EXYNOS_WINCON(win_id)); - - cfg &= ~(EXYNOS_WINCON_BITSWP_ENABLE | EXYNOS_WINCON_BYTESWP_ENABLE | - EXYNOS_WINCON_HAWSWP_ENABLE | EXYNOS_WINCON_WSWP_ENABLE | - EXYNOS_WINCON_BURSTLEN_MASK | EXYNOS_WINCON_BPPMODE_MASK | - EXYNOS_WINCON_INRGB_MASK | EXYNOS_WINCON_DATAPATH_MASK); - - /* DATAPATH is DMA */ - cfg |= EXYNOS_WINCON_DATAPATH_DMA; - - cfg |= EXYNOS_WINCON_HAWSWP_ENABLE; - - /* dma burst is 16 */ - cfg |= EXYNOS_WINCON_BURSTLEN_16WORD; - - switch (pvid->vl_bpix) { - case 4: - cfg |= EXYNOS_WINCON_BPPMODE_16BPP_565; - break; - default: - cfg |= EXYNOS_WINCON_BPPMODE_24BPP_888; - break; - } - - writel(cfg, (unsigned int)&fimd_ctrl->wincon0 + - EXYNOS_WINCON(win_id)); - - /* set window position to x=0, y=0*/ - cfg = EXYNOS_VIDOSD_LEFT_X(0) | EXYNOS_VIDOSD_TOP_Y(0); - writel(cfg, (unsigned int)&fimd_ctrl->vidosd0a + - EXYNOS_VIDOSD(win_id)); - - cfg = EXYNOS_VIDOSD_RIGHT_X(pvid->vl_col - 1) | - EXYNOS_VIDOSD_BOTTOM_Y(pvid->vl_row - 1) | - EXYNOS_VIDOSD_RIGHT_X_E(1) | - EXYNOS_VIDOSD_BOTTOM_Y_E(0); - - writel(cfg, (unsigned int)&fimd_ctrl->vidosd0b + - EXYNOS_VIDOSD(win_id)); - - /* set window size for window0*/ - cfg = EXYNOS_VIDOSD_SIZE(pvid->vl_col * pvid->vl_row); - writel(cfg, (unsigned int)&fimd_ctrl->vidosd0c + - EXYNOS_VIDOSD(win_id)); -} - -static void exynos_fimd_set_buffer_address(struct vidinfo *pvid, - unsigned int win_id, - ulong lcd_base_addr) -{ - struct exynos_fb *fimd_ctrl = pvid->fimd_ctrl; - unsigned long start_addr, end_addr; - - start_addr = lcd_base_addr; - end_addr = start_addr + ((pvid->vl_col * (NBITS(pvid->vl_bpix) / 8)) * - pvid->vl_row); - - writel(start_addr, (unsigned int)&fimd_ctrl->vidw00add0b0 + - EXYNOS_BUFFER_OFFSET(win_id)); - writel(end_addr, (unsigned int)&fimd_ctrl->vidw00add1b0 + - EXYNOS_BUFFER_OFFSET(win_id)); -} - -static void exynos_fimd_set_clock(struct vidinfo *pvid) -{ - struct exynos_fb *fimd_ctrl = pvid->fimd_ctrl; - unsigned int cfg = 0, div = 0, remainder, remainder_div; - unsigned long pixel_clock; - unsigned long long src_clock; - - if (pvid->dual_lcd_enabled) { - pixel_clock = pvid->vl_freq * - (pvid->vl_hspw + pvid->vl_hfpd + - pvid->vl_hbpd + pvid->vl_col / 2) * - (pvid->vl_vspw + pvid->vl_vfpd + - pvid->vl_vbpd + pvid->vl_row); - } else if (pvid->interface_mode == FIMD_CPU_INTERFACE) { - pixel_clock = pvid->vl_freq * - pvid->vl_width * pvid->vl_height * - (pvid->cs_setup + pvid->wr_setup + - pvid->wr_act + pvid->wr_hold + 1); - } else { - pixel_clock = pvid->vl_freq * - (pvid->vl_hspw + pvid->vl_hfpd + - pvid->vl_hbpd + pvid->vl_col) * - (pvid->vl_vspw + pvid->vl_vfpd + - pvid->vl_vbpd + pvid->vl_row); - } - - cfg = readl(&fimd_ctrl->vidcon0); - cfg &= ~(EXYNOS_VIDCON0_CLKSEL_MASK | EXYNOS_VIDCON0_CLKVALUP_MASK | - EXYNOS_VIDCON0_CLKVAL_F(0xFF) | EXYNOS_VIDCON0_VCLKEN_MASK | - EXYNOS_VIDCON0_CLKDIR_MASK); - cfg |= (EXYNOS_VIDCON0_CLKSEL_SCLK | EXYNOS_VIDCON0_CLKVALUP_ALWAYS | - EXYNOS_VIDCON0_VCLKEN_NORMAL | EXYNOS_VIDCON0_CLKDIR_DIVIDED); - - src_clock = (unsigned long long) get_lcd_clk(); - - /* get quotient and remainder. */ - remainder = do_div(src_clock, pixel_clock); - div = src_clock; - - remainder *= 10; - remainder_div = remainder / pixel_clock; - - /* round about one places of decimals. */ - if (remainder_div >= 5) - div++; - - /* in case of dual lcd mode. */ - if (pvid->dual_lcd_enabled) - div--; - - cfg |= EXYNOS_VIDCON0_CLKVAL_F(div - 1); - writel(cfg, &fimd_ctrl->vidcon0); -} - -void exynos_set_trigger(struct vidinfo *pvid) -{ - struct exynos_fb *fimd_ctrl = pvid->fimd_ctrl; - unsigned int cfg = 0; - - cfg = readl(&fimd_ctrl->trigcon); - - cfg |= (EXYNOS_I80SOFT_TRIG_EN | EXYNOS_I80START_TRIG); - - writel(cfg, &fimd_ctrl->trigcon); -} - -int exynos_is_i80_frame_done(struct vidinfo *pvid) -{ - struct exynos_fb *fimd_ctrl = pvid->fimd_ctrl; - unsigned int cfg = 0; - int status; - - cfg = readl(&fimd_ctrl->trigcon); - - /* frame done func is valid only when TRIMODE[0] is set to 1. */ - status = (cfg & EXYNOS_I80STATUS_TRIG_DONE) == - EXYNOS_I80STATUS_TRIG_DONE; - - return status; -} - -static void exynos_fimd_lcd_on(struct vidinfo *pvid) -{ - struct exynos_fb *fimd_ctrl = pvid->fimd_ctrl; - unsigned int cfg = 0; - - /* display on */ - cfg = readl(&fimd_ctrl->vidcon0); - cfg |= (EXYNOS_VIDCON0_ENVID_ENABLE | EXYNOS_VIDCON0_ENVID_F_ENABLE); - writel(cfg, &fimd_ctrl->vidcon0); -} - -static void exynos_fimd_window_on(struct vidinfo *pvid, unsigned int win_id) -{ - struct exynos_fb *fimd_ctrl = pvid->fimd_ctrl; - unsigned int cfg = 0; - - /* enable window */ - cfg = readl((unsigned int)&fimd_ctrl->wincon0 + - EXYNOS_WINCON(win_id)); - cfg |= EXYNOS_WINCON_ENWIN_ENABLE; - writel(cfg, (unsigned int)&fimd_ctrl->wincon0 + - EXYNOS_WINCON(win_id)); - - cfg = readl(&fimd_ctrl->winshmap); - cfg |= EXYNOS_WINSHMAP_CH_ENABLE(win_id); - writel(cfg, &fimd_ctrl->winshmap); -} - -void exynos_fimd_lcd_off(struct vidinfo *pvid) -{ - struct exynos_fb *fimd_ctrl = pvid->fimd_ctrl; - unsigned int cfg = 0; - - cfg = readl(&fimd_ctrl->vidcon0); - cfg &= (EXYNOS_VIDCON0_ENVID_DISABLE | EXYNOS_VIDCON0_ENVID_F_DISABLE); - writel(cfg, &fimd_ctrl->vidcon0); -} - -void exynos_fimd_window_off(struct vidinfo *pvid, unsigned int win_id) -{ - struct exynos_fb *fimd_ctrl = pvid->fimd_ctrl; - unsigned int cfg = 0; - - cfg = readl((unsigned int)&fimd_ctrl->wincon0 + - EXYNOS_WINCON(win_id)); - cfg &= EXYNOS_WINCON_ENWIN_DISABLE; - writel(cfg, (unsigned int)&fimd_ctrl->wincon0 + - EXYNOS_WINCON(win_id)); - - cfg = readl(&fimd_ctrl->winshmap); - cfg &= ~EXYNOS_WINSHMAP_CH_DISABLE(win_id); - writel(cfg, &fimd_ctrl->winshmap); -} - -/* -* The reset value for FIMD SYSMMU register MMU_CTRL is 3 -* on Exynos5420 and newer versions. -* This means FIMD SYSMMU is on by default on Exynos5420 -* and newer versions. -* Since in u-boot we don't use SYSMMU, we should disable -* those FIMD SYSMMU. -* Note that there are 2 SYSMMU for FIMD: m0 and m1. -* m0 handles windows 0 and 4, and m1 handles windows 1, 2 and 3. -* We disable both of them here. -*/ -void exynos_fimd_disable_sysmmu(void) -{ - u32 *sysmmufimd; - unsigned int node; - int node_list[2]; - int count; - int i; - - count = fdtdec_find_aliases_for_id(gd->fdt_blob, "fimd", - COMPAT_SAMSUNG_EXYNOS_SYSMMU, node_list, 2); - for (i = 0; i < count; i++) { - node = node_list[i]; - if (node <= 0) { - debug("Can't get device node for fimd sysmmu\n"); - return; - } - - sysmmufimd = (u32 *)fdtdec_get_addr(gd->fdt_blob, node, "reg"); - if (!sysmmufimd) { - debug("Can't get base address for sysmmu fimdm0"); - return; - } - - writel(0x0, sysmmufimd); - } -} - -void exynos_fimd_lcd_init(struct vidinfo *pvid, ulong lcd_base_address) -{ - struct exynos_fb *fimd_ctrl; - unsigned int cfg = 0, rgb_mode; - unsigned int offset; - unsigned int node; - - node = fdtdec_next_compatible(gd->fdt_blob, - 0, COMPAT_SAMSUNG_EXYNOS_FIMD); - if (node <= 0) - debug("exynos_fb: Can't get device node for fimd\n"); - - fimd_ctrl = (struct exynos_fb *)fdtdec_get_addr(gd->fdt_blob, node, - "reg"); - if (fimd_ctrl == NULL) - debug("Can't get the FIMD base address\n"); - pvid->fimd_ctrl = fimd_ctrl; - - if (fdtdec_get_bool(gd->fdt_blob, node, "samsung,disable-sysmmu")) - exynos_fimd_disable_sysmmu(); - - offset = exynos_fimd_get_base_offset(); - - rgb_mode = pvid->rgb_mode; - - if (pvid->interface_mode == FIMD_RGB_INTERFACE) { - cfg |= EXYNOS_VIDCON0_VIDOUT_RGB; - writel(cfg, &fimd_ctrl->vidcon0); - - cfg = readl(&fimd_ctrl->vidcon2); - cfg &= ~(EXYNOS_VIDCON2_WB_MASK | - EXYNOS_VIDCON2_TVFORMATSEL_MASK | - EXYNOS_VIDCON2_TVFORMATSEL_YUV_MASK); - cfg |= EXYNOS_VIDCON2_WB_DISABLE; - writel(cfg, &fimd_ctrl->vidcon2); - - /* set polarity */ - cfg = 0; - if (!pvid->vl_clkp) - cfg |= EXYNOS_VIDCON1_IVCLK_RISING_EDGE; - if (!pvid->vl_hsp) - cfg |= EXYNOS_VIDCON1_IHSYNC_INVERT; - if (!pvid->vl_vsp) - cfg |= EXYNOS_VIDCON1_IVSYNC_INVERT; - if (!pvid->vl_dp) - cfg |= EXYNOS_VIDCON1_IVDEN_INVERT; - - writel(cfg, (unsigned int)&fimd_ctrl->vidcon1 + offset); - - /* set timing */ - cfg = EXYNOS_VIDTCON0_VFPD(pvid->vl_vfpd - 1); - cfg |= EXYNOS_VIDTCON0_VBPD(pvid->vl_vbpd - 1); - cfg |= EXYNOS_VIDTCON0_VSPW(pvid->vl_vspw - 1); - writel(cfg, (unsigned int)&fimd_ctrl->vidtcon0 + offset); - - cfg = EXYNOS_VIDTCON1_HFPD(pvid->vl_hfpd - 1); - cfg |= EXYNOS_VIDTCON1_HBPD(pvid->vl_hbpd - 1); - cfg |= EXYNOS_VIDTCON1_HSPW(pvid->vl_hspw - 1); - - writel(cfg, (unsigned int)&fimd_ctrl->vidtcon1 + offset); - - /* set lcd size */ - cfg = EXYNOS_VIDTCON2_HOZVAL(pvid->vl_col - 1) | - EXYNOS_VIDTCON2_LINEVAL(pvid->vl_row - 1) | - EXYNOS_VIDTCON2_HOZVAL_E(pvid->vl_col - 1) | - EXYNOS_VIDTCON2_LINEVAL_E(pvid->vl_row - 1); - - writel(cfg, (unsigned int)&fimd_ctrl->vidtcon2 + offset); - } - - /* set display mode */ - cfg = readl(&fimd_ctrl->vidcon0); - cfg &= ~EXYNOS_VIDCON0_PNRMODE_MASK; - cfg |= (rgb_mode << EXYNOS_VIDCON0_PNRMODE_SHIFT); - writel(cfg, &fimd_ctrl->vidcon0); - - /* set par */ - exynos_fimd_set_par(pvid, pvid->win_id); - - /* set memory address */ - exynos_fimd_set_buffer_address(pvid, pvid->win_id, lcd_base_address); - - /* set buffer size */ - cfg = EXYNOS_VIDADDR_PAGEWIDTH(pvid->vl_col * NBITS(pvid->vl_bpix) / 8) | - EXYNOS_VIDADDR_PAGEWIDTH_E(pvid->vl_col * NBITS(pvid->vl_bpix) / 8) | - EXYNOS_VIDADDR_OFFSIZE(0) | - EXYNOS_VIDADDR_OFFSIZE_E(0); - - writel(cfg, (unsigned int)&fimd_ctrl->vidw00add2 + - EXYNOS_BUFFER_SIZE(pvid->win_id)); - - /* set clock */ - exynos_fimd_set_clock(pvid); - - /* set rgb mode to dual lcd. */ - exynos_fimd_set_dualrgb(pvid, pvid->dual_lcd_enabled); - - /* display on */ - exynos_fimd_lcd_on(pvid); - - /* window on */ - exynos_fimd_window_on(pvid, pvid->win_id); - - exynos_fimd_set_dp_clkcon(pvid, pvid->dp_enabled); -} - -unsigned long exynos_fimd_calc_fbsize(struct vidinfo *pvid) -{ - return pvid->vl_col * pvid->vl_row * (NBITS(pvid->vl_bpix) / 8); -} -- cgit v0.10.2 From 5c2dd4cd7a41ec971a23eec9e993717e5aed8744 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 21 Feb 2016 21:08:49 -0700 Subject: exynos: pwm: Add a driver for the exynos5 PWM This driver supports the standard PWM API. There are 5 PWMs. Four are used normally and the last is normally used as a timer. Signed-off-by: Simon Glass Signed-off-by: Minkyu Kang diff --git a/arch/arm/cpu/armv7/s5p-common/timer.c b/arch/arm/cpu/armv7/s5p-common/timer.c index 949abb1..b63036c 100644 --- a/arch/arm/cpu/armv7/s5p-common/timer.c +++ b/arch/arm/cpu/armv7/s5p-common/timer.c @@ -12,6 +12,9 @@ #include #include #include + +/* Use the old PWM interface for now */ +#undef CONFIG_DM_PWM #include DECLARE_GLOBAL_DATA_PTR; diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig index 6f0d61e..37ea2b8 100644 --- a/drivers/pwm/Kconfig +++ b/drivers/pwm/Kconfig @@ -9,6 +9,15 @@ config DM_PWM frequency/period can be controlled along with the proportion of that time that the signal is high. +config PWM_EXYNOS + bool "Enable support for the Exynos PWM" + depends on DM_PWM + help + This PWM is found on Samsung Exynos 5250 and other Samsung SoCs. It + supports a programmable period and duty cycle. A 32-bit counter is + used. It provides 5 channels which can be independently + programmed. Channel 4 (the last) is normally used as a timer. + config PWM_ROCKCHIP bool "Enable support for the Rockchip PWM" depends on DM_PWM diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile index fd414b1..af39347 100644 --- a/drivers/pwm/Makefile +++ b/drivers/pwm/Makefile @@ -15,4 +15,5 @@ obj-$(CONFIG_PWM_ROCKCHIP) += rk_pwm.o obj-$(CONFIG_PWM_IMX) += pwm-imx.o pwm-imx-util.o ifdef CONFIG_DM_PWM obj-$(CONFIG_PWM_TEGRA) += tegra_pwm.o +obj-$(CONFIG_PWM_EXYNOS) += exynos_pwm.o endif diff --git a/drivers/pwm/exynos_pwm.c b/drivers/pwm/exynos_pwm.c new file mode 100644 index 0000000..a0edafc --- /dev/null +++ b/drivers/pwm/exynos_pwm.c @@ -0,0 +1,120 @@ +/* + * Copyright 2016 Google Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include +#include +#include + +DECLARE_GLOBAL_DATA_PTR; + +struct exynos_pwm_priv { + struct s5p_timer *regs; +}; + +static int exynos_pwm_set_config(struct udevice *dev, uint channel, + uint period_ns, uint duty_ns) +{ + struct exynos_pwm_priv *priv = dev_get_priv(dev); + struct s5p_timer *regs = priv->regs; + unsigned int offset, prescaler; + uint div = 4, rate, rate_ns; + u32 val; + u32 tcnt, tcmp, tcon; + + if (channel >= 5) + return -EINVAL; + debug("%s: Configure '%s' channel %u, period_ns %u, duty_ns %u\n", + __func__, dev->name, channel, period_ns, duty_ns); + + val = readl(®s->tcfg0); + prescaler = (channel < 2 ? val : (val >> 8)) & 0xff; + div = (readl(®s->tcfg1) >> MUX_DIV_SHIFT(channel)) & 0xf; + + rate = get_pwm_clk() / ((prescaler + 1) * (1 << div)); + debug("%s: pwm_clk %lu, rate %u\n", __func__, get_pwm_clk(), rate); + + if (channel < 4) { + rate_ns = 1000000000 / rate; + tcnt = period_ns / rate_ns; + tcmp = duty_ns / rate_ns; + debug("%s: tcnt %u, tcmp %u\n", __func__, tcnt, tcmp); + offset = channel * 3; + writel(tcnt, ®s->tcntb0 + offset); + writel(tcmp, ®s->tcmpb0 + offset); + } + + tcon = readl(®s->tcon); + tcon |= TCON_UPDATE(channel); + if (channel < 4) + tcon |= TCON_AUTO_RELOAD(channel); + else + tcon |= TCON4_AUTO_RELOAD; + writel(tcon, ®s->tcon); + + tcon &= ~TCON_UPDATE(channel); + writel(tcon, ®s->tcon); + + return 0; +} + +static int exynos_pwm_set_enable(struct udevice *dev, uint channel, + bool enable) +{ + struct exynos_pwm_priv *priv = dev_get_priv(dev); + struct s5p_timer *regs = priv->regs; + u32 mask; + + if (channel >= 4) + return -EINVAL; + debug("%s: Enable '%s' channel %u\n", __func__, dev->name, channel); + mask = TCON_START(channel); + clrsetbits_le32(®s->tcon, mask, enable ? mask : 0); + + return 0; +} + +static int exynos_pwm_probe(struct udevice *dev) +{ + struct exynos_pwm_priv *priv = dev_get_priv(dev); + struct s5p_timer *regs = priv->regs; + + writel(PRESCALER_0 | PRESCALER_1 << 8, ®s->tcfg0); + + return 0; +} + +static int exynos_pwm_ofdata_to_platdata(struct udevice *dev) +{ + struct exynos_pwm_priv *priv = dev_get_priv(dev); + + priv->regs = (struct s5p_timer *)dev_get_addr(dev); + + return 0; +} + +static const struct pwm_ops exynos_pwm_ops = { + .set_config = exynos_pwm_set_config, + .set_enable = exynos_pwm_set_enable, +}; + +static const struct udevice_id exynos_channels[] = { + { .compatible = "samsung,exynos4210-pwm" }, + { } +}; + +U_BOOT_DRIVER(exynos_pwm) = { + .name = "exynos_pwm", + .id = UCLASS_PWM, + .of_match = exynos_channels, + .ops = &exynos_pwm_ops, + .probe = exynos_pwm_probe, + .ofdata_to_platdata = exynos_pwm_ofdata_to_platdata, + .priv_auto_alloc_size = sizeof(struct exynos_pwm_priv), +}; -- cgit v0.10.2 From 21c561b7c906a05700534a4e420277e6c6012efb Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 21 Feb 2016 21:08:50 -0700 Subject: video: Add an enum for active low/high This is used for video signals in some drivers so provide a standard way of representing it in an enum. Signed-off-by: Simon Glass Acked-by: Anatolij Gustschin Signed-off-by: Minkyu Kang diff --git a/include/video.h b/include/video.h index c434bc7..0d5bd21 100644 --- a/include/video.h +++ b/include/video.h @@ -23,6 +23,11 @@ struct video_uc_platdata { ulong base; }; +enum video_polarity { + VIDEO_ACTIVE_HIGH, /* Pins are active high */ + VIDEO_ACTIVE_LOW, /* Pins are active low */ +}; + /* * Bits per pixel selector. Each value n is such that the bits-per-pixel is * 2 ^ n -- cgit v0.10.2 From 141c74350d1c107a9167e5a78923fcca79413bff Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 21 Feb 2016 21:08:51 -0700 Subject: exynos: dts: Add pwm device tree node Add this node from Linux v4.4 so that PWMs can be used in U-Boot. Signed-off-by: Simon Glass Signed-off-by: Minkyu Kang diff --git a/arch/arm/dts/exynos5250.dtsi b/arch/arm/dts/exynos5250.dtsi index 7eef3e3..d44c9f6 100644 --- a/arch/arm/dts/exynos5250.dtsi +++ b/arch/arm/dts/exynos5250.dtsi @@ -116,4 +116,11 @@ }; }; + pwm: pwm@12dd0000 { + compatible = "samsung,exynos4210-pwm"; + reg = <0x12dd0000 0x100>; + samsung,pwm-outputs = <0>, <1>, <2>, <3>; + #pwm-cells = <3>; + }; + }; diff --git a/arch/arm/dts/exynos54xx.dtsi b/arch/arm/dts/exynos54xx.dtsi index daa6a33..be99a82 100644 --- a/arch/arm/dts/exynos54xx.dtsi +++ b/arch/arm/dts/exynos54xx.dtsi @@ -197,6 +197,13 @@ mem-type = "ddr3"; }; + pwm: pwm@12dd0000 { + compatible = "samsung,exynos4210-pwm"; + reg = <0x12dd0000 0x100>; + samsung,pwm-outputs = <0>, <1>, <2>, <3>; + #pwm-cells = <3>; + }; + xhci1: xhci@12400000 { compatible = "samsung,exynos5250-xhci"; reg = <0x12400000 0x10000>; -- cgit v0.10.2 From c309365089283da1cb32c2a6eeaea9eb3f638f7c Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 21 Feb 2016 21:08:52 -0700 Subject: exynos: Allow tizen to be built without an LCD This file currently requires an LCD. Adjust it to work without one. Signed-off-by: Simon Glass Signed-off-by: Minkyu Kang diff --git a/include/libtizen.h b/include/libtizen.h index 6490fb5..55dccff 100644 --- a/include/libtizen.h +++ b/include/libtizen.h @@ -10,6 +10,8 @@ #define HD_RESOLUTION 0 +#ifdef CONFIG_LCD void get_tizen_logo_info(vidinfo_t *vid); +#endif #endif /* _LIBTIZEN_H_ */ diff --git a/lib/tizen/tizen.c b/lib/tizen/tizen.c index 814ed18..d207f77 100644 --- a/lib/tizen/tizen.c +++ b/lib/tizen/tizen.c @@ -12,6 +12,7 @@ #include "tizen_logo_16bpp.h" #include "tizen_logo_16bpp_gzip.h" +#ifdef CONFIG_LCD void get_tizen_logo_info(vidinfo_t *vid) { switch (vid->vl_bpix) { @@ -31,3 +32,4 @@ void get_tizen_logo_info(vidinfo_t *vid) break; } } +#endif -- cgit v0.10.2 From 531a4a66424946968b28241adbb41165e78d6d26 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 21 Feb 2016 21:08:53 -0700 Subject: exynos: Allow CONFIG_MISC_COMMON to be build without an LCD This file currently requires LCD support. Adjust it so that it can still be built without LCD support (even thought it won't work fully). Signed-off-by: Simon Glass Signed-off-by: Minkyu Kang diff --git a/board/samsung/common/misc.c b/board/samsung/common/misc.c index da0d4db..77d0a4e 100644 --- a/board/samsung/common/misc.c +++ b/board/samsung/common/misc.c @@ -147,6 +147,7 @@ static int key_pressed(int key) return value; } +#ifdef CONFIG_LCD static int check_keys(void) { int keys = 0; @@ -235,9 +236,11 @@ static void display_board_info(void) lcd_printf("\tDisplay BPP: %u\n", 1 << vid->vl_bpix); } +#endif static int mode_leave_menu(int mode) { +#ifdef CONFIG_LCD char *exit_option; char *exit_reset = "reset"; char *exit_back = "back"; @@ -301,8 +304,12 @@ static int mode_leave_menu(int mode) lcd_clear(); return leave; +#else + return 0; +#endif } +#ifdef CONFIG_LCD static void display_download_menu(int mode) { char *selection[BOOT_MODE_EXIT + 1]; @@ -320,9 +327,11 @@ static void display_download_menu(int mode) lcd_printf("\t%s %s - %s\n\n", selection[i], mode_name[i][0], mode_info[i]); } +#endif static void download_menu(void) { +#ifdef CONFIG_LCD int mode = 0; int last_mode = 0; int run; @@ -393,6 +402,7 @@ static void download_menu(void) } lcd_clear(); +#endif } void check_boot_mode(void) -- cgit v0.10.2 From ea743e659fbfa9ba4b00ba076cdbf212d6fff081 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 21 Feb 2016 21:08:54 -0700 Subject: exynos: Disable LCD display for boards we can't convert Some boards have the LCD enabled but I cannot test operation for the driver model conversion. Disable the LCD on these to avoid build errors. Signed-off-by: Simon Glass Signed-off-by: Minkyu Kang diff --git a/board/samsung/trats/trats.c b/board/samsung/trats/trats.c index 54d01ec..66a54d4 100644 --- a/board/samsung/trats/trats.c +++ b/board/samsung/trats/trats.c @@ -596,6 +596,7 @@ int mipi_power(void) return 0; } +#ifdef CONFIG_LCD void exynos_lcd_misc_init(vidinfo_t *vid) { #ifdef CONFIG_TIZEN @@ -606,3 +607,4 @@ void exynos_lcd_misc_init(vidinfo_t *vid) setenv("lcdinfo", "lcd=s6e8ax0"); #endif } +#endif diff --git a/board/samsung/universal_c210/universal.c b/board/samsung/universal_c210/universal.c index 426ae14..81e35b6 100644 --- a/board/samsung/universal_c210/universal.c +++ b/board/samsung/universal_c210/universal.c @@ -367,6 +367,7 @@ int exynos_init(void) return 0; } +#ifdef CONFIG_LCD void exynos_lcd_misc_init(vidinfo_t *vid) { #ifdef CONFIG_TIZEN @@ -379,3 +380,4 @@ void exynos_lcd_misc_init(vidinfo_t *vid) setenv("lcdinfo", "lcd=ld9040"); } +#endif diff --git a/include/configs/s5pc210_universal.h b/include/configs/s5pc210_universal.h index bdb368e..9915306 100644 --- a/include/configs/s5pc210_universal.h +++ b/include/configs/s5pc210_universal.h @@ -217,9 +217,6 @@ int universal_spi_read(void); /* * LCD Settings */ -#define CONFIG_EXYNOS_FB -#define CONFIG_LCD -#define CONFIG_CMD_BMP #define CONFIG_BMP_16BPP #define CONFIG_LD9040 #define CONFIG_VIDEO_BMP_GZIP diff --git a/include/configs/smdk5250.h b/include/configs/smdk5250.h index f66bb12..92a0833 100644 --- a/include/configs/smdk5250.h +++ b/include/configs/smdk5250.h @@ -13,6 +13,9 @@ #include #include +#undef CONFIG_LCD +#undef CONFIG_EXYNOS_FB +#undef CONFIG_EXYNOS_DP #undef CONFIG_KEYBOARD #define CONFIG_BOARD_COMMON diff --git a/include/configs/smdk5420.h b/include/configs/smdk5420.h index 9cf886c..5fe21d9 100644 --- a/include/configs/smdk5420.h +++ b/include/configs/smdk5420.h @@ -13,6 +13,10 @@ #include #include +#undef CONFIG_LCD +#undef CONFIG_EXYNOS_FB +#undef CONFIG_EXYNOS_DP + #undef CONFIG_KEYBOARD #define CONFIG_BOARD_COMMON diff --git a/include/configs/trats.h b/include/configs/trats.h index 0c875cb..22b0c90 100644 --- a/include/configs/trats.h +++ b/include/configs/trats.h @@ -242,12 +242,8 @@ #define CONFIG_SYS_WHITE_ON_BLACK /* LCD */ -#define CONFIG_EXYNOS_FB -#define CONFIG_LCD -#define CONFIG_CMD_BMP #define CONFIG_BMP_16BPP #define CONFIG_FB_ADDR 0x52504000 -#define CONFIG_S6E8AX0 #define CONFIG_EXYNOS_MIPI_DSIM #define CONFIG_VIDEO_BMP_GZIP #define CONFIG_SYS_VIDEO_LOGO_MAX_SIZE ((500 * 160 * 4) + 54) diff --git a/include/configs/trats2.h b/include/configs/trats2.h index 492a253..1febaae 100644 --- a/include/configs/trats2.h +++ b/include/configs/trats2.h @@ -222,12 +222,8 @@ int get_soft_i2c_sda_pin(void); #define CONFIG_SYS_WHITE_ON_BLACK /* LCD */ -#define CONFIG_EXYNOS_FB -#define CONFIG_LCD -#define CONFIG_CMD_BMP #define CONFIG_BMP_16BPP #define CONFIG_FB_ADDR 0x52504000 -#define CONFIG_S6E8AX0 #define CONFIG_EXYNOS_MIPI_DSIM #define CONFIG_VIDEO_BMP_GZIP #define CONFIG_SYS_VIDEO_LOGO_MAX_SIZE ((500 * 160 * 4) + 54) -- cgit v0.10.2 From 7b0789e8fcfe052113bcf06dad1d6da6b4d6b108 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 21 Feb 2016 21:08:55 -0700 Subject: dts: Add clock and regulator binding files for max77802 These are used by peach_pit and peach_pi. Add them so they can be referenced in the device tree files. Signed-off-by: Simon Glass Signed-off-by: Minkyu Kang diff --git a/include/dt-bindings/clock/maxim,max77802.h b/include/dt-bindings/clock/maxim,max77802.h new file mode 100644 index 0000000..997312e --- /dev/null +++ b/include/dt-bindings/clock/maxim,max77802.h @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2014 Google, Inc + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Device Tree binding constants clocks for the Maxim 77802 PMIC. + */ + +#ifndef _DT_BINDINGS_CLOCK_MAXIM_MAX77802_CLOCK_H +#define _DT_BINDINGS_CLOCK_MAXIM_MAX77802_CLOCK_H + +/* Fixed rate clocks. */ + +#define MAX77802_CLK_32K_AP 0 +#define MAX77802_CLK_32K_CP 1 + +/* Total number of clocks. */ +#define MAX77802_CLKS_NUM (MAX77802_CLK_32K_CP + 1) + +#endif /* _DT_BINDINGS_CLOCK_MAXIM_MAX77802_CLOCK_H */ diff --git a/include/dt-bindings/regulator/maxim,max77802.h b/include/dt-bindings/regulator/maxim,max77802.h new file mode 100644 index 0000000..cf28631 --- /dev/null +++ b/include/dt-bindings/regulator/maxim,max77802.h @@ -0,0 +1,18 @@ +/* + * Copyright (C) 2014 Google, Inc + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Device Tree binding constants for the Maxim 77802 PMIC regulators + */ + +#ifndef _DT_BINDINGS_REGULATOR_MAXIM_MAX77802_H +#define _DT_BINDINGS_REGULATOR_MAXIM_MAX77802_H + +/* Regulator operating modes */ +#define MAX77802_OPMODE_LP 1 +#define MAX77802_OPMODE_NORMAL 3 + +#endif /* _DT_BINDINGS_REGULATOR_MAXIM_MAX77802_H */ -- cgit v0.10.2 From af5b5eae53d2a9a79fc6fd9df862a75b65d1dccb Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 21 Feb 2016 21:08:56 -0700 Subject: exynos: Allow PWM0 pinmux to be set up This is commonly used for LCD backlight control. Add pinmux support for it on exynos5250 and 5420. Signed-off-by: Simon Glass Signed-off-by: Minkyu Kang diff --git a/arch/arm/mach-exynos/pinmux.c b/arch/arm/mach-exynos/pinmux.c index 12eb79c..fec2df9 100644 --- a/arch/arm/mach-exynos/pinmux.c +++ b/arch/arm/mach-exynos/pinmux.c @@ -506,6 +506,9 @@ static int exynos5_pinmux_config(int peripheral, int flags) */ gpio_set_pull(EXYNOS5_GPIO_X07, S5P_GPIO_PULL_NONE); break; + case PERIPH_ID_PWM0: + gpio_cfg_pin(EXYNOS5_GPIO_B20, S5P_GPIO_FUNC(2)); + break; default: debug("%s: invalid peripheral %d", __func__, peripheral); return -1; @@ -548,6 +551,9 @@ static int exynos5420_pinmux_config(int peripheral, int flags) case PERIPH_ID_I2C10: exynos5420_i2c_config(peripheral); break; + case PERIPH_ID_PWM0: + gpio_cfg_pin(EXYNOS5420_GPIO_B20, S5P_GPIO_FUNC(2)); + break; default: debug("%s: invalid peripheral %d", __func__, peripheral); return -1; -- cgit v0.10.2 From 7eb860df13ed3e40469eebd407b90c6f9216dd2e Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 21 Feb 2016 21:08:57 -0700 Subject: exynos: Simplify calling of exynos_dp_phy_ctrl() This function controls enabling the EDP PHY. Rename it and drop the existing weak functions, which are confusing. Signed-off-by: Simon Glass Signed-off-by: Minkyu Kang diff --git a/arch/arm/mach-exynos/include/mach/power.h b/arch/arm/mach-exynos/include/mach/power.h index 3f97b31..88f70d9 100644 --- a/arch/arm/mach-exynos/include/mach/power.h +++ b/arch/arm/mach-exynos/include/mach/power.h @@ -1717,7 +1717,7 @@ void set_usbdrd_phy_ctrl(unsigned int enable); #define POWER_USB_DRD_PHY_CTRL_EN (1 << 0) #define POWER_USB_DRD_PHY_CTRL_DISABLE (0 << 0) -void set_dp_phy_ctrl(unsigned int enable); +void exynos_dp_phy_ctrl(unsigned int enable); #define EXYNOS_DP_PHY_ENABLE (1 << 0) diff --git a/arch/arm/mach-exynos/power.c b/arch/arm/mach-exynos/power.c index cd2d661..c923460 100644 --- a/arch/arm/mach-exynos/power.c +++ b/arch/arm/mach-exynos/power.c @@ -147,7 +147,7 @@ static void exynos5_dp_phy_control(unsigned int enable) writel(cfg, &power->dptx_phy_control); } -void set_dp_phy_ctrl(unsigned int enable) +void exynos_dp_phy_ctrl(unsigned int enable) { if (cpu_is_exynos5()) exynos5_dp_phy_control(enable); diff --git a/board/samsung/common/exynos5-dt.c b/board/samsung/common/exynos5-dt.c index 4d9e151..0dcea71 100644 --- a/board/samsung/common/exynos5-dt.c +++ b/board/samsung/common/exynos5-dt.c @@ -235,11 +235,6 @@ void exynos_cfg_lcd_gpio(void) gpio_set_value(EXYNOS5_GPIO_B20, 1); } -void exynos_set_dp_phy(unsigned int onoff) -{ - set_dp_phy_ctrl(onoff); -} - static int board_dp_set_backlight(int percent) { struct udevice *dev; diff --git a/drivers/video/exynos/exynos_dp.c b/drivers/video/exynos/exynos_dp.c index 9945c4b..88926b9 100644 --- a/drivers/video/exynos/exynos_dp.c +++ b/drivers/video/exynos/exynos_dp.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include @@ -22,12 +23,6 @@ DECLARE_GLOBAL_DATA_PTR; -void __exynos_set_dp_phy(unsigned int onoff) -{ -} -void exynos_set_dp_phy(unsigned int onoff) - __attribute__((weak, alias("__exynos_set_dp_phy"))); - static void exynos_dp_disp_info(struct edp_disp_info *disp_info) { disp_info->h_total = disp_info->h_res + disp_info->h_sync_width + @@ -959,7 +954,7 @@ unsigned int exynos_init_dp(void) exynos_dp_disp_info(&edp_info->disp_info); - exynos_set_dp_phy(1); + exynos_dp_phy_ctrl(1); ret = exynos_dp_init_dp(dp_regs); if (ret != EXYNOS_DP_SUCCESS) { -- cgit v0.10.2 From f948f5de94822a372d01e0903b4fe8c682d230e4 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 21 Feb 2016 21:08:58 -0700 Subject: exynos: dts: Add display-related device tree fragments Bring in device tree pieces related to display from Linux 4.4 for: - snow - peach_pit - peach_pi - spring Signed-off-by: Simon Glass Signed-off-by: Minkyu Kang diff --git a/arch/arm/dts/exynos5.dtsi b/arch/arm/dts/exynos5.dtsi index 179584c..8650800 100644 --- a/arch/arm/dts/exynos5.dtsi +++ b/arch/arm/dts/exynos5.dtsi @@ -163,13 +163,14 @@ }; fimd@14400000 { + u-boot,dm-pre-reloc; compatible = "samsung,exynos-fimd"; reg = <0x14400000 0x10000>; #address-cells = <1>; #size-cells = <1>; }; - dp@145b0000 { + dp: dp@145b0000 { compatible = "samsung,exynos5-dp"; reg = <0x145b0000 0x1000>; #address-cells = <1>; diff --git a/arch/arm/dts/exynos5250-snow.dts b/arch/arm/dts/exynos5250-snow.dts index bda5499..29c13c1 100644 --- a/arch/arm/dts/exynos5250-snow.dts +++ b/arch/arm/dts/exynos5250-snow.dts @@ -198,6 +198,20 @@ reset-gpios = <&gpx1 5 GPIO_ACTIVE_LOW>; hotplug-gpios = <&gpx0 7 GPIO_ACTIVE_HIGH>; edid-emulation = <5>; + + ports { + port@0 { + bridge_out: endpoint { + remote-endpoint = <&panel_in>; + }; + }; + + port@1 { + bridge_in: endpoint { + remote-endpoint = <&dp_out>; + }; + }; + }; }; soundcodec@22 { @@ -223,6 +237,27 @@ }; }; + backlight: backlight { + compatible = "pwm-backlight"; + pwms = <&pwm 0 1000000 0>; + brightness-levels = <0 100 500 1000 1500 2000 2500 2800>; + default-brightness-level = <7>; + enable-gpios = <&gpx3 0 GPIO_ACTIVE_HIGH>; + power-supply = <&fet1>; + }; + + panel: panel { + compatible = "auo,b116xw03"; + power-supply = <&fet6>; + backlight = <&backlight>; + + port { + panel_in: endpoint { + remote-endpoint = <&bridge_out>; + }; + }; + }; + spi@131b0000 { spi-max-frequency = <1000000>; spi-deactivate-delay = <100>; @@ -337,6 +372,15 @@ samsung,dynamic-range = <0>; samsung,ycbcr-coeff = <0>; samsung,color-depth = <1>; + samsung,hpd-gpio = <&gpx0 7 GPIO_ACTIVE_HIGH>; + + ports { + port@0 { + dp_out: endpoint { + remote-endpoint = <&bridge_in>; + }; + }; + }; }; }; diff --git a/arch/arm/dts/exynos5250-spring.dts b/arch/arm/dts/exynos5250-spring.dts index 81b3d29..693501e 100644 --- a/arch/arm/dts/exynos5250-spring.dts +++ b/arch/arm/dts/exynos5250-spring.dts @@ -158,6 +158,27 @@ samsung,ycbcr-coeff = <0>; samsung,color-depth = <1>; }; + + backlight: backlight { + compatible = "pwm-backlight"; + pwms = <&pwm 0 1000000 0>; + brightness-levels = <0 100 500 1000 1500 2000 2500 2800>; + default-brightness-level = <1>; + enable-gpios = <&gpx3 0 GPIO_ACTIVE_HIGH>; + power-supply = <&fet1>; + }; + + panel: panel { + compatible = "auo,b116xw03"; + power-supply = <&fet6>; + backlight = <&backlight>; + + port { + panel_in: endpoint { + remote-endpoint = <&bridge_out>; + }; + }; + }; }; &i2c_0 { @@ -385,6 +406,25 @@ }; }; +&dp { + status = "okay"; + samsung,color-space = <0>; + samsung,dynamic-range = <0>; + samsung,ycbcr-coeff = <0>; + samsung,color-depth = <1>; + samsung,link-rate = <0x0a>; + samsung,lane-count = <1>; + samsung,hpd-gpio = <&gpc3 0 GPIO_ACTIVE_HIGH>; + + ports { + port@0 { + dp_out: endpoint { + remote-endpoint = <&bridge_in>; + }; + }; + }; +}; + &i2c_1 { status = "okay"; samsung,i2c-sda-delay = <100>; @@ -585,6 +625,19 @@ 0x04 0x59 0x60 /* MPU Clock source: LC => RCO */ 0x04 0x54 0x14 /* LC -> RCO */ 0x02 0xa1 0x91>; /* HPD high */ + ports { + port@0 { + bridge_out: endpoint { + remote-endpoint = <&panel_in>; + }; + }; + + port@1 { + bridge_in: endpoint { + remote-endpoint = <&dp_out>; + }; + }; + }; }; soundcodec@20 { diff --git a/arch/arm/dts/exynos5420-peach-pit.dts b/arch/arm/dts/exynos5420-peach-pit.dts index 16d52f4..2db4ad2 100644 --- a/arch/arm/dts/exynos5420-peach-pit.dts +++ b/arch/arm/dts/exynos5420-peach-pit.dts @@ -9,6 +9,8 @@ /dts-v1/; #include "exynos54xx.dtsi" +#include +#include / { model = "Samsung/Google Peach Pit board based on Exynos5420"; @@ -29,6 +31,14 @@ i2c104 = &i2c_tunnel; }; + backlight: backlight { + compatible = "pwm-backlight"; + pwms = <&pwm 0 1000000 0>; + brightness-levels = <0 100 500 1000 1500 2000 2500 2800>; + default-brightness-level = <7>; + power-supply = <&tps65090_fet1>; + }; + dmc { mem-manuf = "samsung"; mem-type = "ddr3"; @@ -188,6 +198,20 @@ 0x04 0x59 0x60 0x04 0x54 0x14 /* LC -> RCO */ 0x02 0xa1 0x91>; /* HPD high */ + + ports { + port@0 { + bridge_out: endpoint { + remote-endpoint = <&panel_in>; + }; + }; + + port@1 { + bridge_in: endpoint { + remote-endpoint = <&dp_out>; + }; + }; + }; }; }; @@ -203,6 +227,18 @@ }; }; + panel: panel { + compatible = "auo,b116xw03"; + power-supply = <&tps65090_fet6>; + backlight = <&backlight>; + + port { + panel_in: endpoint { + remote-endpoint = <&bridge_out>; + }; + }; + }; + spi@12d30000 { /* spi1 */ spi-max-frequency = <50000000>; firmware_storage_spi: flash@0 { @@ -254,6 +290,25 @@ }; }; +&dp { + status = "okay"; + samsung,color-space = <0>; + samsung,dynamic-range = <0>; + samsung,ycbcr-coeff = <0>; + samsung,color-depth = <1>; + samsung,link-rate = <0x06>; + samsung,lane-count = <2>; + samsung,hpd-gpio = <&gpx2 6 GPIO_ACTIVE_HIGH>; + + ports { + port@0 { + dp_out: endpoint { + remote-endpoint = <&bridge_in>; + }; + }; + }; +}; + &spi_2 { spi-max-frequency = <3125000>; spi-deactivate-delay = <200>; diff --git a/arch/arm/dts/exynos54xx.dtsi b/arch/arm/dts/exynos54xx.dtsi index be99a82..b4ddf53 100644 --- a/arch/arm/dts/exynos54xx.dtsi +++ b/arch/arm/dts/exynos54xx.dtsi @@ -49,7 +49,7 @@ status = "disabled"; }; - i2c@12CA0000 { + hsi2c_4: i2c@12CA0000 { #address-cells = <1>; #size-cells = <0>; compatible = "samsung,exynos5-hsi2c"; @@ -178,7 +178,7 @@ samsung,pwm-out-gpio = <&gpb2 0 GPIO_ACTIVE_HIGH>; }; - dp@145b0000 { + dp: dp@145b0000 { samsung,lt-status = <0>; samsung,master-mode = <0>; diff --git a/arch/arm/dts/exynos5800-peach-pi.dts b/arch/arm/dts/exynos5800-peach-pi.dts index 76826dc..4c139bf 100644 --- a/arch/arm/dts/exynos5800-peach-pi.dts +++ b/arch/arm/dts/exynos5800-peach-pi.dts @@ -30,6 +30,27 @@ i2c104 = &i2c_tunnel; }; + backlight: backlight { + compatible = "pwm-backlight"; + pwms = <&pwm 0 1000000 0>; + brightness-levels = <0 100 500 1000 1500 2000 2500 2800>; + default-brightness-level = <7>; + enable-gpios = <&gpx2 2 GPIO_ACTIVE_HIGH>; + power-supply = <&tps65090_fet1>; + }; + + panel: panel { + compatible = "auo,b133htn01"; + power-supply = <&tps65090_fet6>; + backlight = <&backlight>; + + port { + panel_in: endpoint { + remote-endpoint = <&dp_out>; + }; + }; + }; + dmc { mem-manuf = "samsung"; mem-type = "ddr3"; @@ -132,6 +153,25 @@ }; }; +&dp { + status = "okay"; + samsung,color-space = <0>; + samsung,dynamic-range = <0>; + samsung,ycbcr-coeff = <0>; + samsung,color-depth = <1>; + samsung,link-rate = <0x0a>; + samsung,lane-count = <2>; + samsung,hpd-gpio = <&gpx2 6 GPIO_ACTIVE_HIGH>; + + ports { + port { + dp_out: endpoint { + remote-endpoint = <&panel_in>; + }; + }; + }; +}; + &spi_2 { spi-max-frequency = <3125000>; spi-deactivate-delay = <200>; -- cgit v0.10.2 From 21f8f9bb084e276c490454c401fc23dc42c536bc Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 21 Feb 2016 21:08:59 -0700 Subject: exynos: video: Rename edp_device_info to exynos_dp_priv Rename this function to better fit with driver model. It is the private data for the exynos EDP driver. Signed-off-by: Simon Glass Acked-by: Anatolij Gustschin Signed-off-by: Minkyu Kang diff --git a/arch/arm/mach-exynos/include/mach/dp_info.h b/arch/arm/mach-exynos/include/mach/dp_info.h index 17e8f56..8ce33d6 100644 --- a/arch/arm/mach-exynos/include/mach/dp_info.h +++ b/arch/arm/mach-exynos/include/mach/dp_info.h @@ -61,7 +61,7 @@ struct edp_video_info { unsigned int color_depth; }; -struct edp_device_info { +struct exynos_dp_priv { struct edp_disp_info disp_info; struct edp_link_train_info lt_info; struct edp_video_info video_info; @@ -185,7 +185,7 @@ enum { struct exynos_dp_platform_data { - struct edp_device_info *edp_dev_info; + struct exynos_dp_priv *edp_dev_info; }; #ifdef CONFIG_EXYNOS_DP diff --git a/drivers/video/exynos/exynos_dp.c b/drivers/video/exynos/exynos_dp.c index 88926b9..0d4ceef 100644 --- a/drivers/video/exynos/exynos_dp.c +++ b/drivers/video/exynos/exynos_dp.c @@ -162,7 +162,7 @@ static unsigned int exynos_dp_read_edid(struct exynos_dp *dp_regs) } static unsigned int exynos_dp_handle_edid(struct exynos_dp *dp_regs, - struct edp_device_info *edp_info) + struct exynos_dp_priv *edp_info) { unsigned char buf[12]; unsigned int ret; @@ -251,7 +251,7 @@ static void exynos_dp_init_training(struct exynos_dp *dp_regs) } static unsigned int exynos_dp_link_start(struct exynos_dp *dp_regs, - struct edp_device_info *edp_info) + struct exynos_dp_priv *edp_info) { unsigned char buf[5]; unsigned int ret = 0; @@ -376,7 +376,7 @@ static unsigned int exynos_dp_set_enhanced_mode(struct exynos_dp *dp_regs, } static int exynos_dp_read_dpcd_lane_stat(struct exynos_dp *dp_regs, - struct edp_device_info *edp_info, + struct exynos_dp_priv *edp_info, unsigned char *status) { unsigned int ret, i; @@ -433,7 +433,7 @@ static unsigned int exynos_dp_read_dpcd_adj_req(struct exynos_dp *dp_regs, } static int exynos_dp_equalizer_err_link(struct exynos_dp *dp_regs, - struct edp_device_info *edp_info) + struct exynos_dp_priv *edp_info) { int ret; @@ -453,7 +453,7 @@ static int exynos_dp_equalizer_err_link(struct exynos_dp *dp_regs, } static int exynos_dp_reduce_link_rate(struct exynos_dp *dp_regs, - struct edp_device_info *edp_info) + struct exynos_dp_priv *edp_info) { int ret; @@ -478,7 +478,7 @@ static int exynos_dp_reduce_link_rate(struct exynos_dp *dp_regs, } static unsigned int exynos_dp_process_clock_recovery(struct exynos_dp *dp_regs, - struct edp_device_info *edp_info) + struct exynos_dp_priv *edp_info) { unsigned int ret = EXYNOS_DP_SUCCESS; unsigned char lane_stat; @@ -588,7 +588,7 @@ static unsigned int exynos_dp_process_clock_recovery(struct exynos_dp *dp_regs, } static unsigned int exynos_dp_process_equalizer_training( - struct exynos_dp *dp_regs, struct edp_device_info *edp_info) + struct exynos_dp *dp_regs, struct exynos_dp_priv *edp_info) { unsigned int ret = EXYNOS_DP_SUCCESS; unsigned char lane_stat, adj_req_sw, adj_req_em, i; @@ -697,7 +697,7 @@ static unsigned int exynos_dp_process_equalizer_training( } static unsigned int exynos_dp_sw_link_training(struct exynos_dp *dp_regs, - struct edp_device_info *edp_info) + struct exynos_dp_priv *edp_info) { unsigned int ret = 0; int training_finished; @@ -748,7 +748,7 @@ static unsigned int exynos_dp_sw_link_training(struct exynos_dp *dp_regs, } static unsigned int exynos_dp_set_link_train(struct exynos_dp *dp_regs, - struct edp_device_info *edp_info) + struct exynos_dp_priv *edp_info) { unsigned int ret; @@ -783,7 +783,7 @@ static void exynos_dp_enable_scramble(struct exynos_dp *dp_regs, } static unsigned int exynos_dp_config_video(struct exynos_dp *dp_regs, - struct edp_device_info *edp_info) + struct exynos_dp_priv *edp_info) { unsigned int ret = 0; unsigned int retry_cnt; @@ -872,7 +872,7 @@ static unsigned int exynos_dp_config_video(struct exynos_dp *dp_regs, return ret; } -int exynos_dp_parse_dt(const void *blob, struct edp_device_info *edp_info) +int exynos_dp_parse_dt(const void *blob, struct exynos_dp_priv *edp_info) { unsigned int node = fdtdec_next_compatible(blob, 0, COMPAT_SAMSUNG_EXYNOS5_DP); @@ -929,11 +929,11 @@ int exynos_dp_parse_dt(const void *blob, struct edp_device_info *edp_info) unsigned int exynos_init_dp(void) { unsigned int ret; - struct edp_device_info *edp_info; + struct exynos_dp_priv *edp_info; struct exynos_dp *dp_regs; int node; - edp_info = kzalloc(sizeof(struct edp_device_info), GFP_KERNEL); + edp_info = kzalloc(sizeof(struct exynos_dp_priv), GFP_KERNEL); if (!edp_info) { debug("failed to allocate edp device object.\n"); return -EFAULT; diff --git a/drivers/video/exynos/exynos_dp_lowlevel.c b/drivers/video/exynos/exynos_dp_lowlevel.c index 153c1c6..00a79ea 100644 --- a/drivers/video/exynos/exynos_dp_lowlevel.c +++ b/drivers/video/exynos/exynos_dp_lowlevel.c @@ -1066,7 +1066,7 @@ void exynos_dp_set_video_color_format(struct exynos_dp *dp_regs, } int exynos_dp_config_video_bist(struct exynos_dp *dp_regs, - struct edp_device_info *edp_info) + struct exynos_dp_priv *edp_info) { unsigned int reg; unsigned int bist_type = 0; diff --git a/drivers/video/exynos/exynos_dp_lowlevel.h b/drivers/video/exynos/exynos_dp_lowlevel.h index 85459b5..0a7657e 100644 --- a/drivers/video/exynos/exynos_dp_lowlevel.h +++ b/drivers/video/exynos/exynos_dp_lowlevel.h @@ -74,7 +74,7 @@ void exynos_dp_config_video_slave_mode(struct exynos_dp *dp_regs, void exynos_dp_set_video_color_format(struct exynos_dp *dp_regs, struct edp_video_info *video_info); int exynos_dp_config_video_bist(struct exynos_dp *dp_regs, - struct edp_device_info *edp_info); + struct exynos_dp_priv *edp_info); unsigned int exynos_dp_is_slave_video_stream_clock_on( struct exynos_dp *dp_regs); void exynos_dp_set_video_cr_mn(struct exynos_dp *dp_regs, unsigned int type, -- cgit v0.10.2 From 8b449a6639c6bee1a97c0eba2ab142a7c471d9b1 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 21 Feb 2016 21:09:00 -0700 Subject: exynos: video: Rename variables for driver model Use 'priv' for a private pointer and 'regs' for a register pointer. Signed-off-by: Simon Glass Acked-by: Anatolij Gustschin Signed-off-by: Minkyu Kang diff --git a/drivers/video/exynos/exynos_dp.c b/drivers/video/exynos/exynos_dp.c index 0d4ceef..d7bccc3 100644 --- a/drivers/video/exynos/exynos_dp.c +++ b/drivers/video/exynos/exynos_dp.c @@ -33,20 +33,20 @@ static void exynos_dp_disp_info(struct edp_disp_info *disp_info) return; } -static int exynos_dp_init_dp(struct exynos_dp *dp_regs) +static int exynos_dp_init_dp(struct exynos_dp *regs) { int ret; - exynos_dp_reset(dp_regs); + exynos_dp_reset(regs); /* SW defined function Normal operation */ - exynos_dp_enable_sw_func(dp_regs, DP_ENABLE); + exynos_dp_enable_sw_func(regs, DP_ENABLE); - ret = exynos_dp_init_analog_func(dp_regs); + ret = exynos_dp_init_analog_func(regs); if (ret != EXYNOS_DP_SUCCESS) return ret; - exynos_dp_init_hpd(dp_regs); - exynos_dp_init_aux(dp_regs); + exynos_dp_init_hpd(regs); + exynos_dp_init_aux(regs); return ret; } @@ -62,7 +62,7 @@ static unsigned char exynos_dp_calc_edid_check_sum(unsigned char *edid_data) return sum; } -static unsigned int exynos_dp_read_edid(struct exynos_dp *dp_regs) +static unsigned int exynos_dp_read_edid(struct exynos_dp *regs) { unsigned char edid[EDID_BLOCK_LENGTH * 2]; unsigned int extend_block = 0; @@ -77,14 +77,14 @@ static unsigned int exynos_dp_read_edid(struct exynos_dp *dp_regs) */ /* Read Extension Flag, Number of 128-byte EDID extension blocks */ - exynos_dp_read_byte_from_i2c(dp_regs, I2C_EDID_DEVICE_ADDR, + exynos_dp_read_byte_from_i2c(regs, I2C_EDID_DEVICE_ADDR, EDID_EXTENSION_FLAG, &extend_block); if (extend_block > 0) { printf("DP EDID data includes a single extension!\n"); /* Read EDID data */ - retval = exynos_dp_read_bytes_from_i2c(dp_regs, + retval = exynos_dp_read_bytes_from_i2c(regs, I2C_EDID_DEVICE_ADDR, EDID_HEADER_PATTERN, EDID_BLOCK_LENGTH, @@ -100,7 +100,7 @@ static unsigned int exynos_dp_read_edid(struct exynos_dp *dp_regs) } /* Read additional EDID data */ - retval = exynos_dp_read_bytes_from_i2c(dp_regs, + retval = exynos_dp_read_bytes_from_i2c(regs, I2C_EDID_DEVICE_ADDR, EDID_BLOCK_LENGTH, EDID_BLOCK_LENGTH, @@ -115,13 +115,13 @@ static unsigned int exynos_dp_read_edid(struct exynos_dp *dp_regs) return -1; } - exynos_dp_read_byte_from_dpcd(dp_regs, DPCD_TEST_REQUEST, + exynos_dp_read_byte_from_dpcd(regs, DPCD_TEST_REQUEST, &test_vector); if (test_vector & DPCD_TEST_EDID_READ) { - exynos_dp_write_byte_to_dpcd(dp_regs, + exynos_dp_write_byte_to_dpcd(regs, DPCD_TEST_EDID_CHECKSUM, edid[EDID_BLOCK_LENGTH + EDID_CHECKSUM]); - exynos_dp_write_byte_to_dpcd(dp_regs, + exynos_dp_write_byte_to_dpcd(regs, DPCD_TEST_RESPONSE, DPCD_TEST_EDID_CHECKSUM_WRITE); } @@ -129,7 +129,7 @@ static unsigned int exynos_dp_read_edid(struct exynos_dp *dp_regs) debug("DP EDID data does not include any extensions.\n"); /* Read EDID data */ - retval = exynos_dp_read_bytes_from_i2c(dp_regs, + retval = exynos_dp_read_bytes_from_i2c(regs, I2C_EDID_DEVICE_ADDR, EDID_HEADER_PATTERN, EDID_BLOCK_LENGTH, @@ -145,12 +145,12 @@ static unsigned int exynos_dp_read_edid(struct exynos_dp *dp_regs) return -1; } - exynos_dp_read_byte_from_dpcd(dp_regs, DPCD_TEST_REQUEST, + exynos_dp_read_byte_from_dpcd(regs, DPCD_TEST_REQUEST, &test_vector); if (test_vector & DPCD_TEST_EDID_READ) { - exynos_dp_write_byte_to_dpcd(dp_regs, + exynos_dp_write_byte_to_dpcd(regs, DPCD_TEST_EDID_CHECKSUM, edid[EDID_CHECKSUM]); - exynos_dp_write_byte_to_dpcd(dp_regs, + exynos_dp_write_byte_to_dpcd(regs, DPCD_TEST_RESPONSE, DPCD_TEST_EDID_CHECKSUM_WRITE); } @@ -161,8 +161,8 @@ static unsigned int exynos_dp_read_edid(struct exynos_dp *dp_regs) return 0; } -static unsigned int exynos_dp_handle_edid(struct exynos_dp *dp_regs, - struct exynos_dp_priv *edp_info) +static unsigned int exynos_dp_handle_edid(struct exynos_dp *regs, + struct exynos_dp_priv *priv) { unsigned char buf[12]; unsigned int ret; @@ -180,7 +180,7 @@ static unsigned int exynos_dp_handle_edid(struct exynos_dp *dp_regs, retry_cnt = 5; while (retry_cnt) { /* Read DPCD 0x0000-0x000b */ - ret = exynos_dp_read_bytes_from_dpcd(dp_regs, DPCD_DPCD_REV, 12, + ret = exynos_dp_read_bytes_from_dpcd(regs, DPCD_DPCD_REV, 12, buf); if (ret != EXYNOS_DP_SUCCESS) { if (retry_cnt == 0) { @@ -195,7 +195,7 @@ static unsigned int exynos_dp_handle_edid(struct exynos_dp *dp_regs, /* */ temp = buf[DPCD_DPCD_REV]; if (temp == DP_DPCD_REV_10 || temp == DP_DPCD_REV_11) - edp_info->dpcd_rev = temp; + priv->dpcd_rev = temp; else { printf("DP Wrong DPCD Rev : %x\n", temp); return -ENODEV; @@ -203,33 +203,33 @@ static unsigned int exynos_dp_handle_edid(struct exynos_dp *dp_regs, temp = buf[DPCD_MAX_LINK_RATE]; if (temp == DP_LANE_BW_1_62 || temp == DP_LANE_BW_2_70) - edp_info->lane_bw = temp; + priv->lane_bw = temp; else { printf("DP Wrong MAX LINK RATE : %x\n", temp); return -EINVAL; } /* Refer VESA Display Port Standard Ver1.1a Page 120 */ - if (edp_info->dpcd_rev == DP_DPCD_REV_11) { + if (priv->dpcd_rev == DP_DPCD_REV_11) { temp = buf[DPCD_MAX_LANE_COUNT] & 0x1f; if (buf[DPCD_MAX_LANE_COUNT] & 0x80) - edp_info->dpcd_efc = 1; + priv->dpcd_efc = 1; else - edp_info->dpcd_efc = 0; + priv->dpcd_efc = 0; } else { temp = buf[DPCD_MAX_LANE_COUNT]; - edp_info->dpcd_efc = 0; + priv->dpcd_efc = 0; } if (temp == DP_LANE_CNT_1 || temp == DP_LANE_CNT_2 || temp == DP_LANE_CNT_4) { - edp_info->lane_cnt = temp; + priv->lane_cnt = temp; } else { printf("DP Wrong MAX LANE COUNT : %x\n", temp); return -EINVAL; } - ret = exynos_dp_read_edid(dp_regs); + ret = exynos_dp_read_edid(regs); if (ret != EXYNOS_DP_SUCCESS) { printf("DP exynos_dp_read_edid() failed\n"); return -EINVAL; @@ -238,35 +238,35 @@ static unsigned int exynos_dp_handle_edid(struct exynos_dp *dp_regs, return ret; } -static void exynos_dp_init_training(struct exynos_dp *dp_regs) +static void exynos_dp_init_training(struct exynos_dp *regs) { /* * MACRO_RST must be applied after the PLL_LOCK to avoid * the DP inter pair skew issue for at least 10 us */ - exynos_dp_reset_macro(dp_regs); + exynos_dp_reset_macro(regs); /* All DP analog module power up */ - exynos_dp_set_analog_power_down(dp_regs, POWER_ALL, 0); + exynos_dp_set_analog_power_down(regs, POWER_ALL, 0); } -static unsigned int exynos_dp_link_start(struct exynos_dp *dp_regs, - struct exynos_dp_priv *edp_info) +static unsigned int exynos_dp_link_start(struct exynos_dp *regs, + struct exynos_dp_priv *priv) { unsigned char buf[5]; unsigned int ret = 0; debug("DP: %s was called\n", __func__); - edp_info->lt_info.lt_status = DP_LT_CR; - edp_info->lt_info.ep_loop = 0; - edp_info->lt_info.cr_loop[0] = 0; - edp_info->lt_info.cr_loop[1] = 0; - edp_info->lt_info.cr_loop[2] = 0; - edp_info->lt_info.cr_loop[3] = 0; + priv->lt_info.lt_status = DP_LT_CR; + priv->lt_info.ep_loop = 0; + priv->lt_info.cr_loop[0] = 0; + priv->lt_info.cr_loop[1] = 0; + priv->lt_info.cr_loop[2] = 0; + priv->lt_info.cr_loop[3] = 0; /* Set sink to D0 (Sink Not Ready) mode. */ - ret = exynos_dp_write_byte_to_dpcd(dp_regs, DPCD_SINK_POWER_STATE, + ret = exynos_dp_write_byte_to_dpcd(regs, DPCD_SINK_POWER_STATE, DPCD_SET_POWER_STATE_D0); if (ret != EXYNOS_DP_SUCCESS) { printf("DP write_dpcd_byte failed\n"); @@ -274,24 +274,24 @@ static unsigned int exynos_dp_link_start(struct exynos_dp *dp_regs, } /* Set link rate and count as you want to establish */ - exynos_dp_set_link_bandwidth(dp_regs, edp_info->lane_bw); - exynos_dp_set_lane_count(dp_regs, edp_info->lane_cnt); + exynos_dp_set_link_bandwidth(regs, priv->lane_bw); + exynos_dp_set_lane_count(regs, priv->lane_cnt); /* Setup RX configuration */ - buf[0] = edp_info->lane_bw; - buf[1] = edp_info->lane_cnt; + buf[0] = priv->lane_bw; + buf[1] = priv->lane_cnt; - ret = exynos_dp_write_bytes_to_dpcd(dp_regs, DPCD_LINK_BW_SET, 2, buf); + ret = exynos_dp_write_bytes_to_dpcd(regs, DPCD_LINK_BW_SET, 2, buf); if (ret != EXYNOS_DP_SUCCESS) { printf("DP write_dpcd_byte failed\n"); return ret; } - exynos_dp_set_lane_pre_emphasis(dp_regs, PRE_EMPHASIS_LEVEL_0, - edp_info->lane_cnt); + exynos_dp_set_lane_pre_emphasis(regs, PRE_EMPHASIS_LEVEL_0, + priv->lane_cnt); /* Set training pattern 1 */ - exynos_dp_set_training_pattern(dp_regs, TRAINING_PTN1); + exynos_dp_set_training_pattern(regs, TRAINING_PTN1); /* Set RX training pattern */ buf[0] = DPCD_SCRAMBLING_DISABLED | DPCD_TRAINING_PATTERN_1; @@ -305,7 +305,7 @@ static unsigned int exynos_dp_link_start(struct exynos_dp *dp_regs, buf[4] = DPCD_PRE_EMPHASIS_SET_PATTERN_2_LEVEL_0 | DPCD_VOLTAGE_SWING_SET_PATTERN_1_LEVEL_0; - ret = exynos_dp_write_bytes_to_dpcd(dp_regs, DPCD_TRAINING_PATTERN_SET, + ret = exynos_dp_write_bytes_to_dpcd(regs, DPCD_TRAINING_PATTERN_SET, 5, buf); if (ret != EXYNOS_DP_SUCCESS) { printf("DP write_dpcd_byte failed\n"); @@ -315,13 +315,13 @@ static unsigned int exynos_dp_link_start(struct exynos_dp *dp_regs, return ret; } -static unsigned int exynos_dp_training_pattern_dis(struct exynos_dp *dp_regs) +static unsigned int exynos_dp_training_pattern_dis(struct exynos_dp *regs) { unsigned int ret = EXYNOS_DP_SUCCESS; - exynos_dp_set_training_pattern(dp_regs, DP_NONE); + exynos_dp_set_training_pattern(regs, DP_NONE); - ret = exynos_dp_write_byte_to_dpcd(dp_regs, DPCD_TRAINING_PATTERN_SET, + ret = exynos_dp_write_byte_to_dpcd(regs, DPCD_TRAINING_PATTERN_SET, DPCD_TRAINING_PATTERN_DISABLED); if (ret != EXYNOS_DP_SUCCESS) { printf("DP request_link_training_req failed\n"); @@ -332,12 +332,12 @@ static unsigned int exynos_dp_training_pattern_dis(struct exynos_dp *dp_regs) } static unsigned int exynos_dp_enable_rx_to_enhanced_mode( - struct exynos_dp *dp_regs, unsigned char enable) + struct exynos_dp *regs, unsigned char enable) { unsigned char data; unsigned int ret = EXYNOS_DP_SUCCESS; - ret = exynos_dp_read_byte_from_dpcd(dp_regs, DPCD_LANE_COUNT_SET, + ret = exynos_dp_read_byte_from_dpcd(regs, DPCD_LANE_COUNT_SET, &data); if (ret != EXYNOS_DP_SUCCESS) { printf("DP read_from_dpcd failed\n"); @@ -349,7 +349,7 @@ static unsigned int exynos_dp_enable_rx_to_enhanced_mode( else data = DPCD_LN_COUNT_SET(data); - ret = exynos_dp_write_byte_to_dpcd(dp_regs, DPCD_LANE_COUNT_SET, data); + ret = exynos_dp_write_byte_to_dpcd(regs, DPCD_LANE_COUNT_SET, data); if (ret != EXYNOS_DP_SUCCESS) { printf("DP write_to_dpcd failed\n"); return -EAGAIN; @@ -359,24 +359,24 @@ static unsigned int exynos_dp_enable_rx_to_enhanced_mode( return ret; } -static unsigned int exynos_dp_set_enhanced_mode(struct exynos_dp *dp_regs, +static unsigned int exynos_dp_set_enhanced_mode(struct exynos_dp *regs, unsigned char enhance_mode) { unsigned int ret = EXYNOS_DP_SUCCESS; - ret = exynos_dp_enable_rx_to_enhanced_mode(dp_regs, enhance_mode); + ret = exynos_dp_enable_rx_to_enhanced_mode(regs, enhance_mode); if (ret != EXYNOS_DP_SUCCESS) { printf("DP rx_enhance_mode failed\n"); return -EAGAIN; } - exynos_dp_enable_enhanced_mode(dp_regs, enhance_mode); + exynos_dp_enable_enhanced_mode(regs, enhance_mode); return ret; } -static int exynos_dp_read_dpcd_lane_stat(struct exynos_dp *dp_regs, - struct exynos_dp_priv *edp_info, +static int exynos_dp_read_dpcd_lane_stat(struct exynos_dp *regs, + struct exynos_dp_priv *priv, unsigned char *status) { unsigned int ret, i; @@ -389,14 +389,14 @@ static int exynos_dp_read_dpcd_lane_stat(struct exynos_dp *dp_regs, shift_val[2] = 0; shift_val[3] = 4; - ret = exynos_dp_read_bytes_from_dpcd(dp_regs, DPCD_LANE0_1_STATUS, 2, + ret = exynos_dp_read_bytes_from_dpcd(regs, DPCD_LANE0_1_STATUS, 2, buf); if (ret != EXYNOS_DP_SUCCESS) { printf("DP read lane status failed\n"); return ret; } - for (i = 0; i < edp_info->lane_cnt; i++) { + for (i = 0; i < priv->lane_cnt; i++) { lane_stat[i] = (buf[(i / 2)] >> shift_val[i]) & 0x0f; if (lane_stat[0] != lane_stat[i]) { printf("Wrong lane status\n"); @@ -409,7 +409,7 @@ static int exynos_dp_read_dpcd_lane_stat(struct exynos_dp *dp_regs, return ret; } -static unsigned int exynos_dp_read_dpcd_adj_req(struct exynos_dp *dp_regs, +static unsigned int exynos_dp_read_dpcd_adj_req(struct exynos_dp *regs, unsigned char lane_num, unsigned char *sw, unsigned char *em) { unsigned int ret = EXYNOS_DP_SUCCESS; @@ -420,7 +420,7 @@ static unsigned int exynos_dp_read_dpcd_adj_req(struct exynos_dp *dp_regs, /* lane_num value is used as array index, so this range 0 ~ 3 */ dpcd_addr = DPCD_ADJUST_REQUEST_LANE0_1 + (lane_num / 2); - ret = exynos_dp_read_byte_from_dpcd(dp_regs, dpcd_addr, &buf); + ret = exynos_dp_read_byte_from_dpcd(regs, dpcd_addr, &buf); if (ret != EXYNOS_DP_SUCCESS) { printf("DP read adjust request failed\n"); return -EAGAIN; @@ -432,53 +432,53 @@ static unsigned int exynos_dp_read_dpcd_adj_req(struct exynos_dp *dp_regs, return ret; } -static int exynos_dp_equalizer_err_link(struct exynos_dp *dp_regs, - struct exynos_dp_priv *edp_info) +static int exynos_dp_equalizer_err_link(struct exynos_dp *regs, + struct exynos_dp_priv *priv) { int ret; - ret = exynos_dp_training_pattern_dis(dp_regs); + ret = exynos_dp_training_pattern_dis(regs); if (ret != EXYNOS_DP_SUCCESS) { printf("DP training_pattern_disable() failed\n"); - edp_info->lt_info.lt_status = DP_LT_FAIL; + priv->lt_info.lt_status = DP_LT_FAIL; } - ret = exynos_dp_set_enhanced_mode(dp_regs, edp_info->dpcd_efc); + ret = exynos_dp_set_enhanced_mode(regs, priv->dpcd_efc); if (ret != EXYNOS_DP_SUCCESS) { printf("DP set_enhanced_mode() failed\n"); - edp_info->lt_info.lt_status = DP_LT_FAIL; + priv->lt_info.lt_status = DP_LT_FAIL; } return ret; } -static int exynos_dp_reduce_link_rate(struct exynos_dp *dp_regs, - struct exynos_dp_priv *edp_info) +static int exynos_dp_reduce_link_rate(struct exynos_dp *regs, + struct exynos_dp_priv *priv) { int ret; - if (edp_info->lane_bw == DP_LANE_BW_2_70) { - edp_info->lane_bw = DP_LANE_BW_1_62; + if (priv->lane_bw == DP_LANE_BW_2_70) { + priv->lane_bw = DP_LANE_BW_1_62; printf("DP Change lane bw to 1.62Gbps\n"); - edp_info->lt_info.lt_status = DP_LT_START; + priv->lt_info.lt_status = DP_LT_START; ret = EXYNOS_DP_SUCCESS; } else { - ret = exynos_dp_training_pattern_dis(dp_regs); + ret = exynos_dp_training_pattern_dis(regs); if (ret != EXYNOS_DP_SUCCESS) printf("DP training_patter_disable() failed\n"); - ret = exynos_dp_set_enhanced_mode(dp_regs, edp_info->dpcd_efc); + ret = exynos_dp_set_enhanced_mode(regs, priv->dpcd_efc); if (ret != EXYNOS_DP_SUCCESS) printf("DP set_enhanced_mode() failed\n"); - edp_info->lt_info.lt_status = DP_LT_FAIL; + priv->lt_info.lt_status = DP_LT_FAIL; } return ret; } -static unsigned int exynos_dp_process_clock_recovery(struct exynos_dp *dp_regs, - struct exynos_dp_priv *edp_info) +static unsigned int exynos_dp_process_clock_recovery(struct exynos_dp *regs, + struct exynos_dp_priv *priv) { unsigned int ret = EXYNOS_DP_SUCCESS; unsigned char lane_stat; @@ -491,22 +491,22 @@ static unsigned int exynos_dp_process_clock_recovery(struct exynos_dp *dp_regs, debug("DP: %s was called\n", __func__); mdelay(1); - ret = exynos_dp_read_dpcd_lane_stat(dp_regs, edp_info, &lane_stat); + ret = exynos_dp_read_dpcd_lane_stat(regs, priv, &lane_stat); if (ret != EXYNOS_DP_SUCCESS) { printf("DP read lane status failed\n"); - edp_info->lt_info.lt_status = DP_LT_FAIL; + priv->lt_info.lt_status = DP_LT_FAIL; return ret; } if (lane_stat & DP_LANE_STAT_CR_DONE) { debug("DP clock Recovery training succeed\n"); - exynos_dp_set_training_pattern(dp_regs, TRAINING_PTN2); + exynos_dp_set_training_pattern(regs, TRAINING_PTN2); - for (i = 0; i < edp_info->lane_cnt; i++) { - ret = exynos_dp_read_dpcd_adj_req(dp_regs, i, + for (i = 0; i < priv->lane_cnt; i++) { + ret = exynos_dp_read_dpcd_adj_req(regs, i, &adj_req_sw, &adj_req_em); if (ret != EXYNOS_DP_SUCCESS) { - edp_info->lt_info.lt_status = DP_LT_FAIL; + priv->lt_info.lt_status = DP_LT_FAIL; return ret; } @@ -518,7 +518,7 @@ static unsigned int exynos_dp_process_clock_recovery(struct exynos_dp *dp_regs, lt_ctl_val[i] |= MAX_DRIVE_CURRENT_REACH_3 | MAX_PRE_EMPHASIS_REACH_3; } - exynos_dp_set_lanex_pre_emphasis(dp_regs, + exynos_dp_set_lanex_pre_emphasis(regs, lt_ctl_val[i], i); } @@ -528,39 +528,39 @@ static unsigned int exynos_dp_process_clock_recovery(struct exynos_dp *dp_regs, buf[3] = lt_ctl_val[2]; buf[4] = lt_ctl_val[3]; - ret = exynos_dp_write_bytes_to_dpcd(dp_regs, + ret = exynos_dp_write_bytes_to_dpcd(regs, DPCD_TRAINING_PATTERN_SET, 5, buf); if (ret != EXYNOS_DP_SUCCESS) { printf("DP write training pattern1 failed\n"); - edp_info->lt_info.lt_status = DP_LT_FAIL; + priv->lt_info.lt_status = DP_LT_FAIL; return ret; } else - edp_info->lt_info.lt_status = DP_LT_ET; + priv->lt_info.lt_status = DP_LT_ET; } else { - for (i = 0; i < edp_info->lane_cnt; i++) { + for (i = 0; i < priv->lane_cnt; i++) { lt_ctl_val[i] = exynos_dp_get_lanex_pre_emphasis( - dp_regs, i); - ret = exynos_dp_read_dpcd_adj_req(dp_regs, i, + regs, i); + ret = exynos_dp_read_dpcd_adj_req(regs, i, &adj_req_sw, &adj_req_em); if (ret != EXYNOS_DP_SUCCESS) { printf("DP read adj req failed\n"); - edp_info->lt_info.lt_status = DP_LT_FAIL; + priv->lt_info.lt_status = DP_LT_FAIL; return ret; } if ((adj_req_sw == VOLTAGE_LEVEL_3) || (adj_req_em == PRE_EMPHASIS_LEVEL_3)) - ret = exynos_dp_reduce_link_rate(dp_regs, - edp_info); + ret = exynos_dp_reduce_link_rate(regs, + priv); if ((DRIVE_CURRENT_SET_0_GET(lt_ctl_val[i]) == adj_req_sw) && (PRE_EMPHASIS_SET_0_GET(lt_ctl_val[i]) == adj_req_em)) { - edp_info->lt_info.cr_loop[i]++; - if (edp_info->lt_info.cr_loop[i] == MAX_CR_LOOP) + priv->lt_info.cr_loop[i]++; + if (priv->lt_info.cr_loop[i] == MAX_CR_LOOP) ret = exynos_dp_reduce_link_rate( - dp_regs, edp_info); + regs, priv); } lt_ctl_val[i] = 0; @@ -571,15 +571,15 @@ static unsigned int exynos_dp_process_clock_recovery(struct exynos_dp *dp_regs, lt_ctl_val[i] |= MAX_DRIVE_CURRENT_REACH_3 | MAX_PRE_EMPHASIS_REACH_3; } - exynos_dp_set_lanex_pre_emphasis(dp_regs, + exynos_dp_set_lanex_pre_emphasis(regs, lt_ctl_val[i], i); } - ret = exynos_dp_write_bytes_to_dpcd(dp_regs, + ret = exynos_dp_write_bytes_to_dpcd(regs, DPCD_TRAINING_LANE0_SET, 4, lt_ctl_val); if (ret != EXYNOS_DP_SUCCESS) { printf("DP write training pattern2 failed\n"); - edp_info->lt_info.lt_status = DP_LT_FAIL; + priv->lt_info.lt_status = DP_LT_FAIL; return ret; } } @@ -588,7 +588,7 @@ static unsigned int exynos_dp_process_clock_recovery(struct exynos_dp *dp_regs, } static unsigned int exynos_dp_process_equalizer_training( - struct exynos_dp *dp_regs, struct exynos_dp_priv *edp_info) + struct exynos_dp *regs, struct exynos_dp_priv *priv) { unsigned int ret = EXYNOS_DP_SUCCESS; unsigned char lane_stat, adj_req_sw, adj_req_em, i; @@ -600,33 +600,33 @@ static unsigned int exynos_dp_process_equalizer_training( mdelay(1); - ret = exynos_dp_read_dpcd_lane_stat(dp_regs, edp_info, &lane_stat); + ret = exynos_dp_read_dpcd_lane_stat(regs, priv, &lane_stat); if (ret != EXYNOS_DP_SUCCESS) { printf("DP read lane status failed\n"); - edp_info->lt_info.lt_status = DP_LT_FAIL; + priv->lt_info.lt_status = DP_LT_FAIL; return ret; } debug("DP lane stat : %x\n", lane_stat); if (lane_stat & DP_LANE_STAT_CR_DONE) { - ret = exynos_dp_read_byte_from_dpcd(dp_regs, + ret = exynos_dp_read_byte_from_dpcd(regs, DPCD_LN_ALIGN_UPDATED, &sink_stat); if (ret != EXYNOS_DP_SUCCESS) { - edp_info->lt_info.lt_status = DP_LT_FAIL; + priv->lt_info.lt_status = DP_LT_FAIL; return ret; } interlane_aligned = (sink_stat & DPCD_INTERLANE_ALIGN_DONE); - for (i = 0; i < edp_info->lane_cnt; i++) { - ret = exynos_dp_read_dpcd_adj_req(dp_regs, i, + for (i = 0; i < priv->lane_cnt; i++) { + ret = exynos_dp_read_dpcd_adj_req(regs, i, &adj_req_sw, &adj_req_em); if (ret != EXYNOS_DP_SUCCESS) { printf("DP read adj req 1 failed\n"); - edp_info->lt_info.lt_status = DP_LT_FAIL; + priv->lt_info.lt_status = DP_LT_FAIL; return ret; } @@ -646,91 +646,91 @@ static unsigned int exynos_dp_process_equalizer_training( && (interlane_aligned == DPCD_INTERLANE_ALIGN_DONE)) { debug("DP Equalizer training succeed\n"); - f_bw = exynos_dp_get_link_bandwidth(dp_regs); - f_lane_cnt = exynos_dp_get_lane_count(dp_regs); + f_bw = exynos_dp_get_link_bandwidth(regs); + f_lane_cnt = exynos_dp_get_lane_count(regs); debug("DP final BandWidth : %x\n", f_bw); debug("DP final Lane Count : %x\n", f_lane_cnt); - edp_info->lt_info.lt_status = DP_LT_FINISHED; + priv->lt_info.lt_status = DP_LT_FINISHED; - exynos_dp_equalizer_err_link(dp_regs, edp_info); + exynos_dp_equalizer_err_link(regs, priv); } else { - edp_info->lt_info.ep_loop++; + priv->lt_info.ep_loop++; - if (edp_info->lt_info.ep_loop > MAX_EQ_LOOP) { - if (edp_info->lane_bw == DP_LANE_BW_2_70) { + if (priv->lt_info.ep_loop > MAX_EQ_LOOP) { + if (priv->lane_bw == DP_LANE_BW_2_70) { ret = exynos_dp_reduce_link_rate( - dp_regs, edp_info); + regs, priv); } else { - edp_info->lt_info.lt_status = + priv->lt_info.lt_status = DP_LT_FAIL; - exynos_dp_equalizer_err_link(dp_regs, - edp_info); + exynos_dp_equalizer_err_link(regs, + priv); } } else { - for (i = 0; i < edp_info->lane_cnt; i++) + for (i = 0; i < priv->lane_cnt; i++) exynos_dp_set_lanex_pre_emphasis( - dp_regs, lt_ctl_val[i], i); + regs, lt_ctl_val[i], i); - ret = exynos_dp_write_bytes_to_dpcd(dp_regs, + ret = exynos_dp_write_bytes_to_dpcd(regs, DPCD_TRAINING_LANE0_SET, 4, lt_ctl_val); if (ret != EXYNOS_DP_SUCCESS) { printf("DP set lt pattern failed\n"); - edp_info->lt_info.lt_status = + priv->lt_info.lt_status = DP_LT_FAIL; - exynos_dp_equalizer_err_link(dp_regs, - edp_info); + exynos_dp_equalizer_err_link(regs, + priv); } } } - } else if (edp_info->lane_bw == DP_LANE_BW_2_70) { - ret = exynos_dp_reduce_link_rate(dp_regs, edp_info); + } else if (priv->lane_bw == DP_LANE_BW_2_70) { + ret = exynos_dp_reduce_link_rate(regs, priv); } else { - edp_info->lt_info.lt_status = DP_LT_FAIL; - exynos_dp_equalizer_err_link(dp_regs, edp_info); + priv->lt_info.lt_status = DP_LT_FAIL; + exynos_dp_equalizer_err_link(regs, priv); } return ret; } -static unsigned int exynos_dp_sw_link_training(struct exynos_dp *dp_regs, - struct exynos_dp_priv *edp_info) +static unsigned int exynos_dp_sw_link_training(struct exynos_dp *regs, + struct exynos_dp_priv *priv) { unsigned int ret = 0; int training_finished; /* Turn off unnecessary lane */ - if (edp_info->lane_cnt == 1) - exynos_dp_set_analog_power_down(dp_regs, CH1_BLOCK, 1); + if (priv->lane_cnt == 1) + exynos_dp_set_analog_power_down(regs, CH1_BLOCK, 1); training_finished = 0; - edp_info->lt_info.lt_status = DP_LT_START; + priv->lt_info.lt_status = DP_LT_START; /* Process here */ while (!training_finished) { - switch (edp_info->lt_info.lt_status) { + switch (priv->lt_info.lt_status) { case DP_LT_START: - ret = exynos_dp_link_start(dp_regs, edp_info); + ret = exynos_dp_link_start(regs, priv); if (ret != EXYNOS_DP_SUCCESS) { printf("DP LT:link start failed\n"); return ret; } break; case DP_LT_CR: - ret = exynos_dp_process_clock_recovery(dp_regs, - edp_info); + ret = exynos_dp_process_clock_recovery(regs, + priv); if (ret != EXYNOS_DP_SUCCESS) { printf("DP LT:clock recovery failed\n"); return ret; } break; case DP_LT_ET: - ret = exynos_dp_process_equalizer_training(dp_regs, - edp_info); + ret = exynos_dp_process_equalizer_training(regs, + priv); if (ret != EXYNOS_DP_SUCCESS) { printf("DP LT:equalizer training failed\n"); return ret; @@ -747,75 +747,75 @@ static unsigned int exynos_dp_sw_link_training(struct exynos_dp *dp_regs, return ret; } -static unsigned int exynos_dp_set_link_train(struct exynos_dp *dp_regs, - struct exynos_dp_priv *edp_info) +static unsigned int exynos_dp_set_link_train(struct exynos_dp *regs, + struct exynos_dp_priv *priv) { unsigned int ret; - exynos_dp_init_training(dp_regs); + exynos_dp_init_training(regs); - ret = exynos_dp_sw_link_training(dp_regs, edp_info); + ret = exynos_dp_sw_link_training(regs, priv); if (ret != EXYNOS_DP_SUCCESS) printf("DP dp_sw_link_training() failed\n"); return ret; } -static void exynos_dp_enable_scramble(struct exynos_dp *dp_regs, +static void exynos_dp_enable_scramble(struct exynos_dp *regs, unsigned int enable) { unsigned char data; if (enable) { - exynos_dp_enable_scrambling(dp_regs, DP_ENABLE); + exynos_dp_enable_scrambling(regs, DP_ENABLE); - exynos_dp_read_byte_from_dpcd(dp_regs, + exynos_dp_read_byte_from_dpcd(regs, DPCD_TRAINING_PATTERN_SET, &data); - exynos_dp_write_byte_to_dpcd(dp_regs, DPCD_TRAINING_PATTERN_SET, + exynos_dp_write_byte_to_dpcd(regs, DPCD_TRAINING_PATTERN_SET, (u8)(data & ~DPCD_SCRAMBLING_DISABLED)); } else { - exynos_dp_enable_scrambling(dp_regs, DP_DISABLE); - exynos_dp_read_byte_from_dpcd(dp_regs, + exynos_dp_enable_scrambling(regs, DP_DISABLE); + exynos_dp_read_byte_from_dpcd(regs, DPCD_TRAINING_PATTERN_SET, &data); - exynos_dp_write_byte_to_dpcd(dp_regs, DPCD_TRAINING_PATTERN_SET, + exynos_dp_write_byte_to_dpcd(regs, DPCD_TRAINING_PATTERN_SET, (u8)(data | DPCD_SCRAMBLING_DISABLED)); } } -static unsigned int exynos_dp_config_video(struct exynos_dp *dp_regs, - struct exynos_dp_priv *edp_info) +static unsigned int exynos_dp_config_video(struct exynos_dp *regs, + struct exynos_dp_priv *priv) { unsigned int ret = 0; unsigned int retry_cnt; mdelay(1); - if (edp_info->video_info.master_mode) { + if (priv->video_info.master_mode) { printf("DP does not support master mode\n"); return -ENODEV; } else { /* debug slave */ - exynos_dp_config_video_slave_mode(dp_regs, - &edp_info->video_info); + exynos_dp_config_video_slave_mode(regs, + &priv->video_info); } - exynos_dp_set_video_color_format(dp_regs, &edp_info->video_info); + exynos_dp_set_video_color_format(regs, &priv->video_info); - if (edp_info->video_info.bist_mode) { - if (exynos_dp_config_video_bist(dp_regs, edp_info) != 0) + if (priv->video_info.bist_mode) { + if (exynos_dp_config_video_bist(regs, priv) != 0) return -1; } - ret = exynos_dp_get_pll_lock_status(dp_regs); + ret = exynos_dp_get_pll_lock_status(regs); if (ret != PLL_LOCKED) { printf("DP PLL is not locked yet\n"); return -EIO; } - if (edp_info->video_info.master_mode == 0) { + if (priv->video_info.master_mode == 0) { retry_cnt = 10; while (retry_cnt) { - ret = exynos_dp_is_slave_video_stream_clock_on(dp_regs); + ret = exynos_dp_is_slave_video_stream_clock_on(regs); if (ret != EXYNOS_DP_SUCCESS) { if (retry_cnt == 0) { printf("DP stream_clock_on failed\n"); @@ -829,34 +829,34 @@ static unsigned int exynos_dp_config_video(struct exynos_dp *dp_regs, } /* Set to use the register calculated M/N video */ - exynos_dp_set_video_cr_mn(dp_regs, CALCULATED_M, 0, 0); + exynos_dp_set_video_cr_mn(regs, CALCULATED_M, 0, 0); /* For video bist, Video timing must be generated by register */ - exynos_dp_set_video_timing_mode(dp_regs, VIDEO_TIMING_FROM_CAPTURE); + exynos_dp_set_video_timing_mode(regs, VIDEO_TIMING_FROM_CAPTURE); /* Enable video bist */ - if (edp_info->video_info.bist_pattern != COLOR_RAMP && - edp_info->video_info.bist_pattern != BALCK_WHITE_V_LINES && - edp_info->video_info.bist_pattern != COLOR_SQUARE) - exynos_dp_enable_video_bist(dp_regs, - edp_info->video_info.bist_mode); + if (priv->video_info.bist_pattern != COLOR_RAMP && + priv->video_info.bist_pattern != BALCK_WHITE_V_LINES && + priv->video_info.bist_pattern != COLOR_SQUARE) + exynos_dp_enable_video_bist(regs, + priv->video_info.bist_mode); else - exynos_dp_enable_video_bist(dp_regs, DP_DISABLE); + exynos_dp_enable_video_bist(regs, DP_DISABLE); /* Disable video mute */ - exynos_dp_enable_video_mute(dp_regs, DP_DISABLE); + exynos_dp_enable_video_mute(regs, DP_DISABLE); /* Configure video Master or Slave mode */ - exynos_dp_enable_video_master(dp_regs, - edp_info->video_info.master_mode); + exynos_dp_enable_video_master(regs, + priv->video_info.master_mode); /* Enable video */ - exynos_dp_start_video(dp_regs); + exynos_dp_start_video(regs); - if (edp_info->video_info.master_mode == 0) { + if (priv->video_info.master_mode == 0) { retry_cnt = 100; while (retry_cnt) { - ret = exynos_dp_is_video_stream_on(dp_regs); + ret = exynos_dp_is_video_stream_on(regs); if (ret != EXYNOS_DP_SUCCESS) { if (retry_cnt == 0) { printf("DP Timeout of video stream\n"); @@ -872,7 +872,7 @@ static unsigned int exynos_dp_config_video(struct exynos_dp *dp_regs, return ret; } -int exynos_dp_parse_dt(const void *blob, struct exynos_dp_priv *edp_info) +int exynos_dp_parse_dt(const void *blob, struct exynos_dp_priv *priv) { unsigned int node = fdtdec_next_compatible(blob, 0, COMPAT_SAMSUNG_EXYNOS5_DP); @@ -881,47 +881,47 @@ int exynos_dp_parse_dt(const void *blob, struct exynos_dp_priv *edp_info) return -ENODEV; } - edp_info->disp_info.h_res = fdtdec_get_int(blob, node, + priv->disp_info.h_res = fdtdec_get_int(blob, node, "samsung,h-res", 0); - edp_info->disp_info.h_sync_width = fdtdec_get_int(blob, node, + priv->disp_info.h_sync_width = fdtdec_get_int(blob, node, "samsung,h-sync-width", 0); - edp_info->disp_info.h_back_porch = fdtdec_get_int(blob, node, + priv->disp_info.h_back_porch = fdtdec_get_int(blob, node, "samsung,h-back-porch", 0); - edp_info->disp_info.h_front_porch = fdtdec_get_int(blob, node, + priv->disp_info.h_front_porch = fdtdec_get_int(blob, node, "samsung,h-front-porch", 0); - edp_info->disp_info.v_res = fdtdec_get_int(blob, node, + priv->disp_info.v_res = fdtdec_get_int(blob, node, "samsung,v-res", 0); - edp_info->disp_info.v_sync_width = fdtdec_get_int(blob, node, + priv->disp_info.v_sync_width = fdtdec_get_int(blob, node, "samsung,v-sync-width", 0); - edp_info->disp_info.v_back_porch = fdtdec_get_int(blob, node, + priv->disp_info.v_back_porch = fdtdec_get_int(blob, node, "samsung,v-back-porch", 0); - edp_info->disp_info.v_front_porch = fdtdec_get_int(blob, node, + priv->disp_info.v_front_porch = fdtdec_get_int(blob, node, "samsung,v-front-porch", 0); - edp_info->disp_info.v_sync_rate = fdtdec_get_int(blob, node, + priv->disp_info.v_sync_rate = fdtdec_get_int(blob, node, "samsung,v-sync-rate", 0); - edp_info->lt_info.lt_status = fdtdec_get_int(blob, node, + priv->lt_info.lt_status = fdtdec_get_int(blob, node, "samsung,lt-status", 0); - edp_info->video_info.master_mode = fdtdec_get_int(blob, node, + priv->video_info.master_mode = fdtdec_get_int(blob, node, "samsung,master-mode", 0); - edp_info->video_info.bist_mode = fdtdec_get_int(blob, node, + priv->video_info.bist_mode = fdtdec_get_int(blob, node, "samsung,bist-mode", 0); - edp_info->video_info.bist_pattern = fdtdec_get_int(blob, node, + priv->video_info.bist_pattern = fdtdec_get_int(blob, node, "samsung,bist-pattern", 0); - edp_info->video_info.h_sync_polarity = fdtdec_get_int(blob, node, + priv->video_info.h_sync_polarity = fdtdec_get_int(blob, node, "samsung,h-sync-polarity", 0); - edp_info->video_info.v_sync_polarity = fdtdec_get_int(blob, node, + priv->video_info.v_sync_polarity = fdtdec_get_int(blob, node, "samsung,v-sync-polarity", 0); - edp_info->video_info.interlaced = fdtdec_get_int(blob, node, + priv->video_info.interlaced = fdtdec_get_int(blob, node, "samsung,interlaced", 0); - edp_info->video_info.color_space = fdtdec_get_int(blob, node, + priv->video_info.color_space = fdtdec_get_int(blob, node, "samsung,color-space", 0); - edp_info->video_info.dynamic_range = fdtdec_get_int(blob, node, + priv->video_info.dynamic_range = fdtdec_get_int(blob, node, "samsung,dynamic-range", 0); - edp_info->video_info.ycbcr_coeff = fdtdec_get_int(blob, node, + priv->video_info.ycbcr_coeff = fdtdec_get_int(blob, node, "samsung,ycbcr-coeff", 0); - edp_info->video_info.color_depth = fdtdec_get_int(blob, node, + priv->video_info.color_depth = fdtdec_get_int(blob, node, "samsung,color-depth", 0); return 0; } @@ -929,17 +929,17 @@ int exynos_dp_parse_dt(const void *blob, struct exynos_dp_priv *edp_info) unsigned int exynos_init_dp(void) { unsigned int ret; - struct exynos_dp_priv *edp_info; - struct exynos_dp *dp_regs; + struct exynos_dp_priv *priv; + struct exynos_dp *regs; int node; - edp_info = kzalloc(sizeof(struct exynos_dp_priv), GFP_KERNEL); - if (!edp_info) { + priv = kzalloc(sizeof(struct exynos_dp_priv), GFP_KERNEL); + if (!priv) { debug("failed to allocate edp device object.\n"); return -EFAULT; } - if (exynos_dp_parse_dt(gd->fdt_blob, edp_info)) + if (exynos_dp_parse_dt(gd->fdt_blob, priv)) debug("unable to parse DP DT node\n"); node = fdtdec_next_compatible(gd->fdt_blob, 0, @@ -947,42 +947,42 @@ unsigned int exynos_init_dp(void) if (node <= 0) debug("exynos_dp: Can't get device node for dp\n"); - dp_regs = (struct exynos_dp *)fdtdec_get_addr(gd->fdt_blob, node, + regs = (struct exynos_dp *)fdtdec_get_addr(gd->fdt_blob, node, "reg"); - if (dp_regs == NULL) + if (regs == NULL) debug("Can't get the DP base address\n"); - exynos_dp_disp_info(&edp_info->disp_info); + exynos_dp_disp_info(&priv->disp_info); exynos_dp_phy_ctrl(1); - ret = exynos_dp_init_dp(dp_regs); + ret = exynos_dp_init_dp(regs); if (ret != EXYNOS_DP_SUCCESS) { printf("DP exynos_dp_init_dp() failed\n"); return ret; } - ret = exynos_dp_handle_edid(dp_regs, edp_info); + ret = exynos_dp_handle_edid(regs, priv); if (ret != EXYNOS_DP_SUCCESS) { printf("EDP handle_edid fail\n"); return ret; } - ret = exynos_dp_set_link_train(dp_regs, edp_info); + ret = exynos_dp_set_link_train(regs, priv); if (ret != EXYNOS_DP_SUCCESS) { printf("DP link training fail\n"); return ret; } - exynos_dp_enable_scramble(dp_regs, DP_ENABLE); - exynos_dp_enable_rx_to_enhanced_mode(dp_regs, DP_ENABLE); - exynos_dp_enable_enhanced_mode(dp_regs, DP_ENABLE); + exynos_dp_enable_scramble(regs, DP_ENABLE); + exynos_dp_enable_rx_to_enhanced_mode(regs, DP_ENABLE); + exynos_dp_enable_enhanced_mode(regs, DP_ENABLE); - exynos_dp_set_link_bandwidth(dp_regs, edp_info->lane_bw); - exynos_dp_set_lane_count(dp_regs, edp_info->lane_cnt); + exynos_dp_set_link_bandwidth(regs, priv->lane_bw); + exynos_dp_set_lane_count(regs, priv->lane_cnt); - exynos_dp_init_video(dp_regs); - ret = exynos_dp_config_video(dp_regs, edp_info); + exynos_dp_init_video(regs); + ret = exynos_dp_config_video(regs, priv); if (ret != EXYNOS_DP_SUCCESS) { printf("Exynos DP init failed\n"); return ret; diff --git a/drivers/video/exynos/exynos_dp_lowlevel.c b/drivers/video/exynos/exynos_dp_lowlevel.c index 00a79ea..f978473 100644 --- a/drivers/video/exynos/exynos_dp_lowlevel.c +++ b/drivers/video/exynos/exynos_dp_lowlevel.c @@ -1066,49 +1066,46 @@ void exynos_dp_set_video_color_format(struct exynos_dp *dp_regs, } int exynos_dp_config_video_bist(struct exynos_dp *dp_regs, - struct exynos_dp_priv *edp_info) + struct exynos_dp_priv *priv) { unsigned int reg; unsigned int bist_type = 0; - struct edp_video_info video_info = edp_info->video_info; + struct edp_video_info video_info = priv->video_info; /* For master mode, you don't need to set the video format */ if (video_info.master_mode == 0) { - writel(TOTAL_LINE_CFG_L(edp_info->disp_info.v_total), - &dp_regs->total_ln_cfg_l); - writel(TOTAL_LINE_CFG_H(edp_info->disp_info.v_total), - &dp_regs->total_ln_cfg_h); - writel(ACTIVE_LINE_CFG_L(edp_info->disp_info.v_res), - &dp_regs->active_ln_cfg_l); - writel(ACTIVE_LINE_CFG_H(edp_info->disp_info.v_res), - &dp_regs->active_ln_cfg_h); - writel(edp_info->disp_info.v_sync_width, - &dp_regs->vsw_cfg); - writel(edp_info->disp_info.v_back_porch, - &dp_regs->vbp_cfg); - writel(edp_info->disp_info.v_front_porch, - &dp_regs->vfp_cfg); - - writel(TOTAL_PIXEL_CFG_L(edp_info->disp_info.h_total), - &dp_regs->total_pix_cfg_l); - writel(TOTAL_PIXEL_CFG_H(edp_info->disp_info.h_total), - &dp_regs->total_pix_cfg_h); - writel(ACTIVE_PIXEL_CFG_L(edp_info->disp_info.h_res), - &dp_regs->active_pix_cfg_l); - writel(ACTIVE_PIXEL_CFG_H(edp_info->disp_info.h_res), - &dp_regs->active_pix_cfg_h); - writel(H_F_PORCH_CFG_L(edp_info->disp_info.h_front_porch), - &dp_regs->hfp_cfg_l); - writel(H_F_PORCH_CFG_H(edp_info->disp_info.h_front_porch), - &dp_regs->hfp_cfg_h); - writel(H_SYNC_PORCH_CFG_L(edp_info->disp_info.h_sync_width), - &dp_regs->hsw_cfg_l); - writel(H_SYNC_PORCH_CFG_H(edp_info->disp_info.h_sync_width), - &dp_regs->hsw_cfg_h); - writel(H_B_PORCH_CFG_L(edp_info->disp_info.h_back_porch), - &dp_regs->hbp_cfg_l); - writel(H_B_PORCH_CFG_H(edp_info->disp_info.h_back_porch), - &dp_regs->hbp_cfg_h); + writel(TOTAL_LINE_CFG_L(priv->disp_info.v_total), + &dp_regs->total_ln_cfg_l); + writel(TOTAL_LINE_CFG_H(priv->disp_info.v_total), + &dp_regs->total_ln_cfg_h); + writel(ACTIVE_LINE_CFG_L(priv->disp_info.v_res), + &dp_regs->active_ln_cfg_l); + writel(ACTIVE_LINE_CFG_H(priv->disp_info.v_res), + &dp_regs->active_ln_cfg_h); + writel(priv->disp_info.v_sync_width, &dp_regs->vsw_cfg); + writel(priv->disp_info.v_back_porch, &dp_regs->vbp_cfg); + writel(priv->disp_info.v_front_porch, &dp_regs->vfp_cfg); + + writel(TOTAL_PIXEL_CFG_L(priv->disp_info.h_total), + &dp_regs->total_pix_cfg_l); + writel(TOTAL_PIXEL_CFG_H(priv->disp_info.h_total), + &dp_regs->total_pix_cfg_h); + writel(ACTIVE_PIXEL_CFG_L(priv->disp_info.h_res), + &dp_regs->active_pix_cfg_l); + writel(ACTIVE_PIXEL_CFG_H(priv->disp_info.h_res), + &dp_regs->active_pix_cfg_h); + writel(H_F_PORCH_CFG_L(priv->disp_info.h_front_porch), + &dp_regs->hfp_cfg_l); + writel(H_F_PORCH_CFG_H(priv->disp_info.h_front_porch), + &dp_regs->hfp_cfg_h); + writel(H_SYNC_PORCH_CFG_L(priv->disp_info.h_sync_width), + &dp_regs->hsw_cfg_l); + writel(H_SYNC_PORCH_CFG_H(priv->disp_info.h_sync_width), + &dp_regs->hsw_cfg_h); + writel(H_B_PORCH_CFG_L(priv->disp_info.h_back_porch), + &dp_regs->hbp_cfg_l); + writel(H_B_PORCH_CFG_H(priv->disp_info.h_back_porch), + &dp_regs->hbp_cfg_h); /* * Set SLAVE_I_SCAN_CFG[2], VSYNC_P_CFG[1], diff --git a/drivers/video/exynos/exynos_dp_lowlevel.h b/drivers/video/exynos/exynos_dp_lowlevel.h index 0a7657e..e4c867e 100644 --- a/drivers/video/exynos/exynos_dp_lowlevel.h +++ b/drivers/video/exynos/exynos_dp_lowlevel.h @@ -74,7 +74,7 @@ void exynos_dp_config_video_slave_mode(struct exynos_dp *dp_regs, void exynos_dp_set_video_color_format(struct exynos_dp *dp_regs, struct edp_video_info *video_info); int exynos_dp_config_video_bist(struct exynos_dp *dp_regs, - struct exynos_dp_priv *edp_info); + struct exynos_dp_priv *priv); unsigned int exynos_dp_is_slave_video_stream_clock_on( struct exynos_dp *dp_regs); void exynos_dp_set_video_cr_mn(struct exynos_dp *dp_regs, unsigned int type, diff --git a/drivers/video/exynos/exynos_fb.c b/drivers/video/exynos/exynos_fb.c index e13d35a..83b1187 100644 --- a/drivers/video/exynos/exynos_fb.c +++ b/drivers/video/exynos/exynos_fb.c @@ -35,9 +35,9 @@ struct vidinfo panel_info = { .vl_col = -1, }; -static void exynos_fimd_set_dualrgb(struct vidinfo *pvid, unsigned int enabled) +static void exynos_fimd_set_dualrgb(struct vidinfo *priv, unsigned int enabled) { - struct exynos_fb *fimd_ctrl = pvid->fimd_ctrl; + struct exynos_fb *reg = priv->reg; unsigned int cfg = 0; if (enabled) { @@ -45,32 +45,32 @@ static void exynos_fimd_set_dualrgb(struct vidinfo *pvid, unsigned int enabled) EXYNOS_DUALRGB_VDEN_EN_ENABLE; /* in case of Line Split mode, MAIN_CNT doesn't neet to set. */ - cfg |= EXYNOS_DUALRGB_SUB_CNT(pvid->vl_col / 2) | + cfg |= EXYNOS_DUALRGB_SUB_CNT(priv->vl_col / 2) | EXYNOS_DUALRGB_MAIN_CNT(0); } - writel(cfg, &fimd_ctrl->dualrgb); + writel(cfg, ®->dualrgb); } -static void exynos_fimd_set_dp_clkcon(struct vidinfo *pvid, +static void exynos_fimd_set_dp_clkcon(struct vidinfo *priv, unsigned int enabled) { - struct exynos_fb *fimd_ctrl = pvid->fimd_ctrl; + struct exynos_fb *reg = priv->reg; unsigned int cfg = 0; if (enabled) cfg = EXYNOS_DP_CLK_ENABLE; - writel(cfg, &fimd_ctrl->dp_mie_clkcon); + writel(cfg, ®->dp_mie_clkcon); } -static void exynos_fimd_set_par(struct vidinfo *pvid, unsigned int win_id) +static void exynos_fimd_set_par(struct vidinfo *priv, unsigned int win_id) { - struct exynos_fb *fimd_ctrl = pvid->fimd_ctrl; + struct exynos_fb *reg = priv->reg; unsigned int cfg = 0; /* set window control */ - cfg = readl((unsigned int)&fimd_ctrl->wincon0 + + cfg = readl((unsigned int)®->wincon0 + EXYNOS_WINCON(win_id)); cfg &= ~(EXYNOS_WINCON_BITSWP_ENABLE | EXYNOS_WINCON_BYTESWP_ENABLE | @@ -86,7 +86,7 @@ static void exynos_fimd_set_par(struct vidinfo *pvid, unsigned int win_id) /* dma burst is 16 */ cfg |= EXYNOS_WINCON_BURSTLEN_16WORD; - switch (pvid->vl_bpix) { + switch (priv->vl_bpix) { case 4: cfg |= EXYNOS_WINCON_BPPMODE_16BPP_565; break; @@ -95,72 +95,72 @@ static void exynos_fimd_set_par(struct vidinfo *pvid, unsigned int win_id) break; } - writel(cfg, (unsigned int)&fimd_ctrl->wincon0 + + writel(cfg, (unsigned int)®->wincon0 + EXYNOS_WINCON(win_id)); /* set window position to x=0, y=0*/ cfg = EXYNOS_VIDOSD_LEFT_X(0) | EXYNOS_VIDOSD_TOP_Y(0); - writel(cfg, (unsigned int)&fimd_ctrl->vidosd0a + + writel(cfg, (unsigned int)®->vidosd0a + EXYNOS_VIDOSD(win_id)); - cfg = EXYNOS_VIDOSD_RIGHT_X(pvid->vl_col - 1) | - EXYNOS_VIDOSD_BOTTOM_Y(pvid->vl_row - 1) | + cfg = EXYNOS_VIDOSD_RIGHT_X(priv->vl_col - 1) | + EXYNOS_VIDOSD_BOTTOM_Y(priv->vl_row - 1) | EXYNOS_VIDOSD_RIGHT_X_E(1) | EXYNOS_VIDOSD_BOTTOM_Y_E(0); - writel(cfg, (unsigned int)&fimd_ctrl->vidosd0b + + writel(cfg, (unsigned int)®->vidosd0b + EXYNOS_VIDOSD(win_id)); /* set window size for window0*/ - cfg = EXYNOS_VIDOSD_SIZE(pvid->vl_col * pvid->vl_row); - writel(cfg, (unsigned int)&fimd_ctrl->vidosd0c + + cfg = EXYNOS_VIDOSD_SIZE(priv->vl_col * priv->vl_row); + writel(cfg, (unsigned int)®->vidosd0c + EXYNOS_VIDOSD(win_id)); } -static void exynos_fimd_set_buffer_address(struct vidinfo *pvid, +static void exynos_fimd_set_buffer_address(struct vidinfo *priv, unsigned int win_id, ulong lcd_base_addr) { - struct exynos_fb *fimd_ctrl = pvid->fimd_ctrl; + struct exynos_fb *reg = priv->reg; unsigned long start_addr, end_addr; start_addr = lcd_base_addr; - end_addr = start_addr + ((pvid->vl_col * (NBITS(pvid->vl_bpix) / 8)) * - pvid->vl_row); + end_addr = start_addr + ((priv->vl_col * (NBITS(priv->vl_bpix) / 8)) * + priv->vl_row); - writel(start_addr, (unsigned int)&fimd_ctrl->vidw00add0b0 + + writel(start_addr, (unsigned int)®->vidw00add0b0 + EXYNOS_BUFFER_OFFSET(win_id)); - writel(end_addr, (unsigned int)&fimd_ctrl->vidw00add1b0 + + writel(end_addr, (unsigned int)®->vidw00add1b0 + EXYNOS_BUFFER_OFFSET(win_id)); } -static void exynos_fimd_set_clock(struct vidinfo *pvid) +static void exynos_fimd_set_clock(struct vidinfo *priv) { - struct exynos_fb *fimd_ctrl = pvid->fimd_ctrl; + struct exynos_fb *reg = priv->reg; unsigned int cfg = 0, div = 0, remainder, remainder_div; unsigned long pixel_clock; unsigned long long src_clock; - if (pvid->dual_lcd_enabled) { - pixel_clock = pvid->vl_freq * - (pvid->vl_hspw + pvid->vl_hfpd + - pvid->vl_hbpd + pvid->vl_col / 2) * - (pvid->vl_vspw + pvid->vl_vfpd + - pvid->vl_vbpd + pvid->vl_row); - } else if (pvid->interface_mode == FIMD_CPU_INTERFACE) { - pixel_clock = pvid->vl_freq * - pvid->vl_width * pvid->vl_height * - (pvid->cs_setup + pvid->wr_setup + - pvid->wr_act + pvid->wr_hold + 1); + if (priv->dual_lcd_enabled) { + pixel_clock = priv->vl_freq * + (priv->vl_hspw + priv->vl_hfpd + + priv->vl_hbpd + priv->vl_col / 2) * + (priv->vl_vspw + priv->vl_vfpd + + priv->vl_vbpd + priv->vl_row); + } else if (priv->interface_mode == FIMD_CPU_INTERFACE) { + pixel_clock = priv->vl_freq * + priv->vl_width * priv->vl_height * + (priv->cs_setup + priv->wr_setup + + priv->wr_act + priv->wr_hold + 1); } else { - pixel_clock = pvid->vl_freq * - (pvid->vl_hspw + pvid->vl_hfpd + - pvid->vl_hbpd + pvid->vl_col) * - (pvid->vl_vspw + pvid->vl_vfpd + - pvid->vl_vbpd + pvid->vl_row); + pixel_clock = priv->vl_freq * + (priv->vl_hspw + priv->vl_hfpd + + priv->vl_hbpd + priv->vl_col) * + (priv->vl_vspw + priv->vl_vfpd + + priv->vl_vbpd + priv->vl_row); } - cfg = readl(&fimd_ctrl->vidcon0); + cfg = readl(®->vidcon0); cfg &= ~(EXYNOS_VIDCON0_CLKSEL_MASK | EXYNOS_VIDCON0_CLKVALUP_MASK | EXYNOS_VIDCON0_CLKVAL_F(0xFF) | EXYNOS_VIDCON0_VCLKEN_MASK | EXYNOS_VIDCON0_CLKDIR_MASK); @@ -181,32 +181,32 @@ static void exynos_fimd_set_clock(struct vidinfo *pvid) div++; /* in case of dual lcd mode. */ - if (pvid->dual_lcd_enabled) + if (priv->dual_lcd_enabled) div--; cfg |= EXYNOS_VIDCON0_CLKVAL_F(div - 1); - writel(cfg, &fimd_ctrl->vidcon0); + writel(cfg, ®->vidcon0); } -void exynos_set_trigger(struct vidinfo *pvid) +void exynos_set_trigger(struct vidinfo *priv) { - struct exynos_fb *fimd_ctrl = pvid->fimd_ctrl; + struct exynos_fb *reg = priv->reg; unsigned int cfg = 0; - cfg = readl(&fimd_ctrl->trigcon); + cfg = readl(®->trigcon); cfg |= (EXYNOS_I80SOFT_TRIG_EN | EXYNOS_I80START_TRIG); - writel(cfg, &fimd_ctrl->trigcon); + writel(cfg, ®->trigcon); } -int exynos_is_i80_frame_done(struct vidinfo *pvid) +int exynos_is_i80_frame_done(struct vidinfo *priv) { - struct exynos_fb *fimd_ctrl = pvid->fimd_ctrl; + struct exynos_fb *reg = priv->reg; unsigned int cfg = 0; int status; - cfg = readl(&fimd_ctrl->trigcon); + cfg = readl(®->trigcon); /* frame done func is valid only when TRIMODE[0] is set to 1. */ status = (cfg & EXYNOS_I80STATUS_TRIG_DONE) == @@ -215,58 +215,58 @@ int exynos_is_i80_frame_done(struct vidinfo *pvid) return status; } -static void exynos_fimd_lcd_on(struct vidinfo *pvid) +static void exynos_fimd_lcd_on(struct vidinfo *priv) { - struct exynos_fb *fimd_ctrl = pvid->fimd_ctrl; + struct exynos_fb *reg = priv->reg; unsigned int cfg = 0; /* display on */ - cfg = readl(&fimd_ctrl->vidcon0); + cfg = readl(®->vidcon0); cfg |= (EXYNOS_VIDCON0_ENVID_ENABLE | EXYNOS_VIDCON0_ENVID_F_ENABLE); - writel(cfg, &fimd_ctrl->vidcon0); + writel(cfg, ®->vidcon0); } -static void exynos_fimd_window_on(struct vidinfo *pvid, unsigned int win_id) +static void exynos_fimd_window_on(struct vidinfo *priv, unsigned int win_id) { - struct exynos_fb *fimd_ctrl = pvid->fimd_ctrl; + struct exynos_fb *reg = priv->reg; unsigned int cfg = 0; /* enable window */ - cfg = readl((unsigned int)&fimd_ctrl->wincon0 + + cfg = readl((unsigned int)®->wincon0 + EXYNOS_WINCON(win_id)); cfg |= EXYNOS_WINCON_ENWIN_ENABLE; - writel(cfg, (unsigned int)&fimd_ctrl->wincon0 + + writel(cfg, (unsigned int)®->wincon0 + EXYNOS_WINCON(win_id)); - cfg = readl(&fimd_ctrl->winshmap); + cfg = readl(®->winshmap); cfg |= EXYNOS_WINSHMAP_CH_ENABLE(win_id); - writel(cfg, &fimd_ctrl->winshmap); + writel(cfg, ®->winshmap); } -void exynos_fimd_lcd_off(struct vidinfo *pvid) +void exynos_fimd_lcd_off(struct vidinfo *priv) { - struct exynos_fb *fimd_ctrl = pvid->fimd_ctrl; + struct exynos_fb *reg = priv->reg; unsigned int cfg = 0; - cfg = readl(&fimd_ctrl->vidcon0); + cfg = readl(®->vidcon0); cfg &= (EXYNOS_VIDCON0_ENVID_DISABLE | EXYNOS_VIDCON0_ENVID_F_DISABLE); - writel(cfg, &fimd_ctrl->vidcon0); + writel(cfg, ®->vidcon0); } -void exynos_fimd_window_off(struct vidinfo *pvid, unsigned int win_id) +void exynos_fimd_window_off(struct vidinfo *priv, unsigned int win_id) { - struct exynos_fb *fimd_ctrl = pvid->fimd_ctrl; + struct exynos_fb *reg = priv->reg; unsigned int cfg = 0; - cfg = readl((unsigned int)&fimd_ctrl->wincon0 + + cfg = readl((unsigned int)®->wincon0 + EXYNOS_WINCON(win_id)); cfg &= EXYNOS_WINCON_ENWIN_DISABLE; - writel(cfg, (unsigned int)&fimd_ctrl->wincon0 + + writel(cfg, (unsigned int)®->wincon0 + EXYNOS_WINCON(win_id)); - cfg = readl(&fimd_ctrl->winshmap); + cfg = readl(®->winshmap); cfg &= ~EXYNOS_WINSHMAP_CH_DISABLE(win_id); - writel(cfg, &fimd_ctrl->winshmap); + writel(cfg, ®->winshmap); } /* @@ -307,9 +307,9 @@ void exynos_fimd_disable_sysmmu(void) } } -void exynos_fimd_lcd_init(struct vidinfo *pvid, ulong lcd_base_address) +void exynos_fimd_lcd_init(struct vidinfo *priv, ulong lcd_base_address) { - struct exynos_fb *fimd_ctrl; + struct exynos_fb *reg; unsigned int cfg = 0, rgb_mode; unsigned int offset; unsigned int node; @@ -319,105 +319,105 @@ void exynos_fimd_lcd_init(struct vidinfo *pvid, ulong lcd_base_address) if (node <= 0) debug("exynos_fb: Can't get device node for fimd\n"); - fimd_ctrl = (struct exynos_fb *)fdtdec_get_addr(gd->fdt_blob, node, + reg = (struct exynos_fb *)fdtdec_get_addr(gd->fdt_blob, node, "reg"); - if (fimd_ctrl == NULL) + if (reg == NULL) debug("Can't get the FIMD base address\n"); - pvid->fimd_ctrl = fimd_ctrl; + priv->reg = reg; if (fdtdec_get_bool(gd->fdt_blob, node, "samsung,disable-sysmmu")) exynos_fimd_disable_sysmmu(); offset = exynos_fimd_get_base_offset(); - rgb_mode = pvid->rgb_mode; + rgb_mode = priv->rgb_mode; - if (pvid->interface_mode == FIMD_RGB_INTERFACE) { + if (priv->interface_mode == FIMD_RGB_INTERFACE) { cfg |= EXYNOS_VIDCON0_VIDOUT_RGB; - writel(cfg, &fimd_ctrl->vidcon0); + writel(cfg, ®->vidcon0); - cfg = readl(&fimd_ctrl->vidcon2); + cfg = readl(®->vidcon2); cfg &= ~(EXYNOS_VIDCON2_WB_MASK | EXYNOS_VIDCON2_TVFORMATSEL_MASK | EXYNOS_VIDCON2_TVFORMATSEL_YUV_MASK); cfg |= EXYNOS_VIDCON2_WB_DISABLE; - writel(cfg, &fimd_ctrl->vidcon2); + writel(cfg, ®->vidcon2); /* set polarity */ cfg = 0; - if (!pvid->vl_clkp) + if (!priv->vl_clkp) cfg |= EXYNOS_VIDCON1_IVCLK_RISING_EDGE; - if (!pvid->vl_hsp) + if (!priv->vl_hsp) cfg |= EXYNOS_VIDCON1_IHSYNC_INVERT; - if (!pvid->vl_vsp) + if (!priv->vl_vsp) cfg |= EXYNOS_VIDCON1_IVSYNC_INVERT; - if (!pvid->vl_dp) + if (!priv->vl_dp) cfg |= EXYNOS_VIDCON1_IVDEN_INVERT; - writel(cfg, (unsigned int)&fimd_ctrl->vidcon1 + offset); + writel(cfg, (unsigned int)®->vidcon1 + offset); /* set timing */ - cfg = EXYNOS_VIDTCON0_VFPD(pvid->vl_vfpd - 1); - cfg |= EXYNOS_VIDTCON0_VBPD(pvid->vl_vbpd - 1); - cfg |= EXYNOS_VIDTCON0_VSPW(pvid->vl_vspw - 1); - writel(cfg, (unsigned int)&fimd_ctrl->vidtcon0 + offset); + cfg = EXYNOS_VIDTCON0_VFPD(priv->vl_vfpd - 1); + cfg |= EXYNOS_VIDTCON0_VBPD(priv->vl_vbpd - 1); + cfg |= EXYNOS_VIDTCON0_VSPW(priv->vl_vspw - 1); + writel(cfg, (unsigned int)®->vidtcon0 + offset); - cfg = EXYNOS_VIDTCON1_HFPD(pvid->vl_hfpd - 1); - cfg |= EXYNOS_VIDTCON1_HBPD(pvid->vl_hbpd - 1); - cfg |= EXYNOS_VIDTCON1_HSPW(pvid->vl_hspw - 1); + cfg = EXYNOS_VIDTCON1_HFPD(priv->vl_hfpd - 1); + cfg |= EXYNOS_VIDTCON1_HBPD(priv->vl_hbpd - 1); + cfg |= EXYNOS_VIDTCON1_HSPW(priv->vl_hspw - 1); - writel(cfg, (unsigned int)&fimd_ctrl->vidtcon1 + offset); + writel(cfg, (unsigned int)®->vidtcon1 + offset); /* set lcd size */ - cfg = EXYNOS_VIDTCON2_HOZVAL(pvid->vl_col - 1) | - EXYNOS_VIDTCON2_LINEVAL(pvid->vl_row - 1) | - EXYNOS_VIDTCON2_HOZVAL_E(pvid->vl_col - 1) | - EXYNOS_VIDTCON2_LINEVAL_E(pvid->vl_row - 1); + cfg = EXYNOS_VIDTCON2_HOZVAL(priv->vl_col - 1) | + EXYNOS_VIDTCON2_LINEVAL(priv->vl_row - 1) | + EXYNOS_VIDTCON2_HOZVAL_E(priv->vl_col - 1) | + EXYNOS_VIDTCON2_LINEVAL_E(priv->vl_row - 1); - writel(cfg, (unsigned int)&fimd_ctrl->vidtcon2 + offset); + writel(cfg, (unsigned int)®->vidtcon2 + offset); } /* set display mode */ - cfg = readl(&fimd_ctrl->vidcon0); + cfg = readl(®->vidcon0); cfg &= ~EXYNOS_VIDCON0_PNRMODE_MASK; cfg |= (rgb_mode << EXYNOS_VIDCON0_PNRMODE_SHIFT); - writel(cfg, &fimd_ctrl->vidcon0); + writel(cfg, ®->vidcon0); /* set par */ - exynos_fimd_set_par(pvid, pvid->win_id); + exynos_fimd_set_par(priv, priv->win_id); /* set memory address */ - exynos_fimd_set_buffer_address(pvid, pvid->win_id, lcd_base_address); + exynos_fimd_set_buffer_address(priv, priv->win_id, lcd_base_address); /* set buffer size */ - cfg = EXYNOS_VIDADDR_PAGEWIDTH(pvid->vl_col * - NBITS(pvid->vl_bpix) / 8) | - EXYNOS_VIDADDR_PAGEWIDTH_E(pvid->vl_col * - NBITS(pvid->vl_bpix) / 8) | + cfg = EXYNOS_VIDADDR_PAGEWIDTH(priv->vl_col * + NBITS(priv->vl_bpix) / 8) | + EXYNOS_VIDADDR_PAGEWIDTH_E(priv->vl_col * + NBITS(priv->vl_bpix) / 8) | EXYNOS_VIDADDR_OFFSIZE(0) | EXYNOS_VIDADDR_OFFSIZE_E(0); - writel(cfg, (unsigned int)&fimd_ctrl->vidw00add2 + - EXYNOS_BUFFER_SIZE(pvid->win_id)); + writel(cfg, (unsigned int)®->vidw00add2 + + EXYNOS_BUFFER_SIZE(priv->win_id)); /* set clock */ - exynos_fimd_set_clock(pvid); + exynos_fimd_set_clock(priv); /* set rgb mode to dual lcd. */ - exynos_fimd_set_dualrgb(pvid, pvid->dual_lcd_enabled); + exynos_fimd_set_dualrgb(priv, priv->dual_lcd_enabled); /* display on */ - exynos_fimd_lcd_on(pvid); + exynos_fimd_lcd_on(priv); /* window on */ - exynos_fimd_window_on(pvid, pvid->win_id); + exynos_fimd_window_on(priv, priv->win_id); - exynos_fimd_set_dp_clkcon(pvid, pvid->dp_enabled); + exynos_fimd_set_dp_clkcon(priv, priv->dp_enabled); } -unsigned long exynos_fimd_calc_fbsize(struct vidinfo *pvid) +unsigned long exynos_fimd_calc_fbsize(struct vidinfo *priv) { - return pvid->vl_col * pvid->vl_row * (NBITS(pvid->vl_bpix) / 8); + return priv->vl_col * priv->vl_row * (NBITS(priv->vl_bpix) / 8); } ushort *configuration_get_cmap(void) diff --git a/include/exynos_lcd.h b/include/exynos_lcd.h index 0aa0fc7..ab92ffb 100644 --- a/include/exynos_lcd.h +++ b/include/exynos_lcd.h @@ -75,7 +75,7 @@ typedef struct vidinfo { unsigned int sclk_div; unsigned int dual_lcd_enabled; - struct exynos_fb *fimd_ctrl; + struct exynos_fb *reg; struct exynos_platform_mipi_dsim *dsim_platform_data_dt; } vidinfo_t; -- cgit v0.10.2 From bb5930d5c97fa22ed2fe048106fcabb5b7c77c96 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 21 Feb 2016 21:09:01 -0700 Subject: exynos: video: Convert several boards to driver model for video Update several boards to use driver model for video. This involves changes to the EDP and FIMD (frame buffer) drivers. Existing PWM, simple-panel and pwm-backlight drivers are used. These work without additional configuration since they use the device tree settings in the same way as Linux. Boards converted are: - snow - spring - peach-pit - peach-pi All have been tested. Not converted: - MIPI display driver - s5pc210_universal - smdk5420 - smdk5250 - trats - trats2 Signed-off-by: Simon Glass Acked-by: Anatolij Gustschin Signed-off-by: Minkyu Kang diff --git a/arch/arm/mach-exynos/include/mach/dp_info.h b/arch/arm/mach-exynos/include/mach/dp_info.h index 8ce33d6..1079e1e 100644 --- a/arch/arm/mach-exynos/include/mach/dp_info.h +++ b/arch/arm/mach-exynos/include/mach/dp_info.h @@ -72,6 +72,7 @@ struct exynos_dp_priv { unsigned char dpcd_rev; /*support enhanced frame cap */ unsigned char dpcd_efc; + struct exynos_dp *regs; }; enum analog_power_block { diff --git a/board/samsung/common/board.c b/board/samsung/common/board.c index 7995174..0eb066c 100644 --- a/board/samsung/common/board.c +++ b/board/samsung/common/board.c @@ -158,21 +158,6 @@ int board_early_init_f(void) board_i2c_init(gd->fdt_blob); #endif -#if defined(CONFIG_EXYNOS_FB) - /* - * board_init_f(arch/arm/lib/board.c) calls lcd_setmem() which needs - * panel_info.vl_col, panel_info.vl_row and panel_info.vl_bpix, - * to reserve frame-buffer memory at a very early stage. So, we need - * to fill panel_info.vl_col, panel_info.vl_row and panel_info.vl_bpix - * before lcd_setmem() is called. - */ - err = exynos_lcd_early_init(gd->fdt_blob); - if (err) { - debug("LCD early init failed\n"); - return err; - } -#endif - return exynos_early_init_f(); } #endif diff --git a/configs/peach-pi_defconfig b/configs/peach-pi_defconfig index ce07052..fea8bde 100644 --- a/configs/peach-pi_defconfig +++ b/configs/peach-pi_defconfig @@ -47,6 +47,8 @@ CONFIG_DM_PMIC=y CONFIG_PMIC_TPS65090=y CONFIG_DM_REGULATOR=y CONFIG_REGULATOR_TPS65090=y +CONFIG_DM_PWM=y +CONFIG_PWM_EXYNOS=y CONFIG_SOUND=y CONFIG_I2S=y CONFIG_I2S_SAMSUNG=y @@ -56,6 +58,8 @@ CONFIG_EXYNOS_SPI=y CONFIG_TPM_TIS_INFINEON=y CONFIG_USB=y CONFIG_DM_USB=y +CONFIG_DM_VIDEO=y +CONFIG_DISPLAY=y CONFIG_VIDEO_BRIDGE=y CONFIG_VIDEO_BRIDGE_PARADE_PS862X=y CONFIG_TPM=y diff --git a/configs/peach-pit_defconfig b/configs/peach-pit_defconfig index 4479fe8..41c3d12 100644 --- a/configs/peach-pit_defconfig +++ b/configs/peach-pit_defconfig @@ -47,6 +47,8 @@ CONFIG_DM_PMIC=y CONFIG_PMIC_TPS65090=y CONFIG_DM_REGULATOR=y CONFIG_REGULATOR_TPS65090=y +CONFIG_DM_PWM=y +CONFIG_PWM_EXYNOS=y CONFIG_SOUND=y CONFIG_I2S=y CONFIG_I2S_SAMSUNG=y @@ -56,6 +58,8 @@ CONFIG_EXYNOS_SPI=y CONFIG_TPM_TIS_INFINEON=y CONFIG_USB=y CONFIG_DM_USB=y +CONFIG_DM_VIDEO=y +CONFIG_DISPLAY=y CONFIG_VIDEO_BRIDGE=y CONFIG_VIDEO_BRIDGE_PARADE_PS862X=y CONFIG_TPM=y diff --git a/configs/snow_defconfig b/configs/snow_defconfig index 77b97a3..c16c90c 100644 --- a/configs/snow_defconfig +++ b/configs/snow_defconfig @@ -52,6 +52,8 @@ CONFIG_DM_REGULATOR=y CONFIG_DM_REGULATOR_MAX77686=y CONFIG_REGULATOR_S5M8767=y CONFIG_REGULATOR_TPS65090=y +CONFIG_DM_PWM=y +CONFIG_PWM_EXYNOS=y CONFIG_DEBUG_UART=y CONFIG_DEBUG_UART_S5P=y CONFIG_DEBUG_UART_BASE=0x12c30000 @@ -65,6 +67,8 @@ CONFIG_EXYNOS_SPI=y CONFIG_TPM_TIS_INFINEON=y CONFIG_USB=y CONFIG_DM_USB=y +CONFIG_DM_VIDEO=y +CONFIG_DISPLAY=y CONFIG_VIDEO_BRIDGE=y CONFIG_VIDEO_BRIDGE_PARADE_PS862X=y CONFIG_VIDEO_BRIDGE_NXP_PTN3460=y diff --git a/configs/spring_defconfig b/configs/spring_defconfig index d3b174a..b68cab0 100644 --- a/configs/spring_defconfig +++ b/configs/spring_defconfig @@ -52,6 +52,8 @@ CONFIG_DM_REGULATOR=y CONFIG_DM_REGULATOR_MAX77686=y CONFIG_REGULATOR_S5M8767=y CONFIG_REGULATOR_TPS65090=y +CONFIG_DM_PWM=y +CONFIG_PWM_EXYNOS=y CONFIG_DEBUG_UART=y CONFIG_DEBUG_UART_S5P=y CONFIG_DEBUG_UART_BASE=0x12c30000 @@ -65,6 +67,8 @@ CONFIG_EXYNOS_SPI=y CONFIG_TPM_TIS_INFINEON=y CONFIG_USB=y CONFIG_DM_USB=y +CONFIG_DM_VIDEO=y +CONFIG_DISPLAY=y CONFIG_VIDEO_BRIDGE=y CONFIG_VIDEO_BRIDGE_PARADE_PS862X=y CONFIG_TPM=y diff --git a/drivers/video/exynos/exynos_dp.c b/drivers/video/exynos/exynos_dp.c index d7bccc3..fc39f2c 100644 --- a/drivers/video/exynos/exynos_dp.c +++ b/drivers/video/exynos/exynos_dp.c @@ -7,17 +7,21 @@ */ #include +#include #include +#include +#include +#include #include +#include #include #include #include #include #include #include +#include #include -#include -#include #include "exynos_dp_lowlevel.h" @@ -872,15 +876,19 @@ static unsigned int exynos_dp_config_video(struct exynos_dp *regs, return ret; } -int exynos_dp_parse_dt(const void *blob, struct exynos_dp_priv *priv) +static int exynos_dp_ofdata_to_platdata(struct udevice *dev) { - unsigned int node = fdtdec_next_compatible(blob, 0, - COMPAT_SAMSUNG_EXYNOS5_DP); - if (node <= 0) { - debug("exynos_dp: Can't get device node for dp\n"); - return -ENODEV; - } + struct exynos_dp_priv *priv = dev_get_priv(dev); + const void *blob = gd->fdt_blob; + unsigned int node = dev->of_offset; + fdt_addr_t addr; + addr = dev_get_addr(dev); + if (addr == FDT_ADDR_T_NONE) { + debug("Can't get the DP base address\n"); + return -EINVAL; + } + priv->regs = (struct exynos_dp *)addr; priv->disp_info.h_res = fdtdec_get_int(blob, node, "samsung,h-res", 0); priv->disp_info.h_sync_width = fdtdec_get_int(blob, node, @@ -926,34 +934,97 @@ int exynos_dp_parse_dt(const void *blob, struct exynos_dp_priv *priv) return 0; } -unsigned int exynos_init_dp(void) +static int exynos_dp_bridge_init(struct udevice *dev) { - unsigned int ret; - struct exynos_dp_priv *priv; - struct exynos_dp *regs; - int node; + const int max_tries = 10; + int num_tries; + int ret; - priv = kzalloc(sizeof(struct exynos_dp_priv), GFP_KERNEL); - if (!priv) { - debug("failed to allocate edp device object.\n"); - return -EFAULT; + debug("%s\n", __func__); + ret = video_bridge_attach(dev); + if (ret) { + debug("video bridge init failed: %d\n", ret); + return ret; } - if (exynos_dp_parse_dt(gd->fdt_blob, priv)) - debug("unable to parse DP DT node\n"); + /* + * We need to wait for 90ms after bringing up the bridge since there + * is a phantom "high" on the HPD chip during its bootup. The phantom + * high comes within 7ms of de-asserting PD and persists for at least + * 15ms. The real high comes roughly 50ms after PD is de-asserted. The + * phantom high makes it hard for us to know when the NXP chip is up. + */ + mdelay(90); - node = fdtdec_next_compatible(gd->fdt_blob, 0, - COMPAT_SAMSUNG_EXYNOS5_DP); - if (node <= 0) - debug("exynos_dp: Can't get device node for dp\n"); + for (num_tries = 0; num_tries < max_tries; num_tries++) { + /* Check HPD. If it's high, or we don't have it, all is well */ + ret = video_bridge_check_attached(dev); + if (!ret || ret == -ENOENT) + return 0; - regs = (struct exynos_dp *)fdtdec_get_addr(gd->fdt_blob, node, - "reg"); - if (regs == NULL) - debug("Can't get the DP base address\n"); + debug("%s: eDP bridge failed to come up; try %d of %d\n", + __func__, num_tries, max_tries); + } + + /* Immediately go into bridge reset if the hp line is not high */ + return -EIO; +} + +static int exynos_dp_bridge_setup(const void *blob) +{ + const int max_tries = 2; + int num_tries; + struct udevice *dev; + int ret; + + /* Configure I2C registers for Parade bridge */ + ret = uclass_get_device(UCLASS_VIDEO_BRIDGE, 0, &dev); + if (ret) { + debug("video bridge init failed: %d\n", ret); + return ret; + } + + if (strncmp(dev->driver->name, "parade", 6)) { + /* Mux HPHPD to the special hotplug detect mode */ + exynos_pinmux_config(PERIPH_ID_DPHPD, 0); + } + + for (num_tries = 0; num_tries < max_tries; num_tries++) { + ret = exynos_dp_bridge_init(dev); + if (!ret) + return 0; + if (num_tries == max_tries - 1) + break; + + /* + * If we're here, the bridge chip failed to initialise. + * Power down the bridge in an attempt to reset. + */ + video_bridge_set_active(dev, false); + + /* + * Arbitrarily wait 300ms here with DP_N low. Don't know for + * sure how long we should wait, but we're being paranoid. + */ + mdelay(300); + } + return ret; +} +int exynos_dp_enable(struct udevice *dev, int panel_bpp, + const struct display_timing *timing) +{ + struct exynos_dp_priv *priv = dev_get_priv(dev); + struct exynos_dp *regs = priv->regs; + unsigned int ret; + + debug("%s: start\n", __func__); exynos_dp_disp_info(&priv->disp_info); + ret = exynos_dp_bridge_setup(gd->fdt_blob); + if (ret && ret != -ENODEV) + printf("LCD bridge failed to enable: %d\n", ret); + exynos_dp_phy_ctrl(1); ret = exynos_dp_init_dp(regs); @@ -992,3 +1063,22 @@ unsigned int exynos_init_dp(void) return ret; } + + +static const struct dm_display_ops exynos_dp_ops = { + .enable = exynos_dp_enable, +}; + +static const struct udevice_id exynos_dp_ids[] = { + { .compatible = "samsung,exynos5-dp" }, + { } +}; + +U_BOOT_DRIVER(exynos_dp) = { + .name = "eexynos_dp", + .id = UCLASS_DISPLAY, + .of_match = exynos_dp_ids, + .ops = &exynos_dp_ops, + .ofdata_to_platdata = exynos_dp_ofdata_to_platdata, + .priv_auto_alloc_size = sizeof(struct exynos_dp_priv), +}; diff --git a/drivers/video/exynos/exynos_fb.c b/drivers/video/exynos/exynos_fb.c index 83b1187..c8fef63 100644 --- a/drivers/video/exynos/exynos_fb.c +++ b/drivers/video/exynos/exynos_fb.c @@ -9,33 +9,98 @@ #include #include +#include #include -#include +#include #include #include +#include +#include +#include #include #include #include #include #include #include +#include +#include #include #include #include -#include "exynos_fb.h" - DECLARE_GLOBAL_DATA_PTR; -struct vidinfo panel_info = { - /* - * Insert a value here so that we don't end up in the BSS - * Reference: drivers/video/tegra.c - */ - .vl_col = -1, +enum { + FIMD_RGB_INTERFACE = 1, + FIMD_CPU_INTERFACE = 2, +}; + +enum exynos_fb_rgb_mode_t { + MODE_RGB_P = 0, + MODE_BGR_P = 1, + MODE_RGB_S = 2, + MODE_BGR_S = 3, }; -static void exynos_fimd_set_dualrgb(struct vidinfo *priv, unsigned int enabled) +struct exynos_fb_priv { + ushort vl_col; /* Number of columns (i.e. 640) */ + ushort vl_row; /* Number of rows (i.e. 480) */ + ushort vl_rot; /* Rotation of Display (0, 1, 2, 3) */ + ushort vl_width; /* Width of display area in millimeters */ + ushort vl_height; /* Height of display area in millimeters */ + + /* LCD configuration register */ + u_char vl_freq; /* Frequency */ + u_char vl_clkp; /* Clock polarity */ + u_char vl_oep; /* Output Enable polarity */ + u_char vl_hsp; /* Horizontal Sync polarity */ + u_char vl_vsp; /* Vertical Sync polarity */ + u_char vl_dp; /* Data polarity */ + u_char vl_bpix; /* Bits per pixel */ + + /* Horizontal control register. Timing from data sheet */ + u_char vl_hspw; /* Horz sync pulse width */ + u_char vl_hfpd; /* Wait before of line */ + u_char vl_hbpd; /* Wait end of line */ + + /* Vertical control register. */ + u_char vl_vspw; /* Vertical sync pulse width */ + u_char vl_vfpd; /* Wait before of frame */ + u_char vl_vbpd; /* Wait end of frame */ + u_char vl_cmd_allow_len; /* Wait end of frame */ + + unsigned int win_id; + unsigned int init_delay; + unsigned int power_on_delay; + unsigned int reset_delay; + unsigned int interface_mode; + unsigned int mipi_enabled; + unsigned int dp_enabled; + unsigned int cs_setup; + unsigned int wr_setup; + unsigned int wr_act; + unsigned int wr_hold; + unsigned int logo_on; + unsigned int logo_width; + unsigned int logo_height; + int logo_x_offset; + int logo_y_offset; + unsigned long logo_addr; + unsigned int rgb_mode; + unsigned int resolution; + + /* parent clock name(MPLL, EPLL or VPLL) */ + unsigned int pclk_name; + /* ratio value for source clock from parent clock. */ + unsigned int sclk_div; + + unsigned int dual_lcd_enabled; + struct exynos_fb *reg; + struct exynos_platform_mipi_dsim *dsim_platform_data_dt; +}; + +static void exynos_fimd_set_dualrgb(struct exynos_fb_priv *priv, bool enabled) { struct exynos_fb *reg = priv->reg; unsigned int cfg = 0; @@ -52,7 +117,7 @@ static void exynos_fimd_set_dualrgb(struct vidinfo *priv, unsigned int enabled) writel(cfg, ®->dualrgb); } -static void exynos_fimd_set_dp_clkcon(struct vidinfo *priv, +static void exynos_fimd_set_dp_clkcon(struct exynos_fb_priv *priv, unsigned int enabled) { struct exynos_fb *reg = priv->reg; @@ -64,7 +129,8 @@ static void exynos_fimd_set_dp_clkcon(struct vidinfo *priv, writel(cfg, ®->dp_mie_clkcon); } -static void exynos_fimd_set_par(struct vidinfo *priv, unsigned int win_id) +static void exynos_fimd_set_par(struct exynos_fb_priv *priv, + unsigned int win_id) { struct exynos_fb *reg = priv->reg; unsigned int cfg = 0; @@ -117,7 +183,7 @@ static void exynos_fimd_set_par(struct vidinfo *priv, unsigned int win_id) EXYNOS_VIDOSD(win_id)); } -static void exynos_fimd_set_buffer_address(struct vidinfo *priv, +static void exynos_fimd_set_buffer_address(struct exynos_fb_priv *priv, unsigned int win_id, ulong lcd_base_addr) { @@ -125,7 +191,7 @@ static void exynos_fimd_set_buffer_address(struct vidinfo *priv, unsigned long start_addr, end_addr; start_addr = lcd_base_addr; - end_addr = start_addr + ((priv->vl_col * (NBITS(priv->vl_bpix) / 8)) * + end_addr = start_addr + ((priv->vl_col * (VNBITS(priv->vl_bpix) / 8)) * priv->vl_row); writel(start_addr, (unsigned int)®->vidw00add0b0 + @@ -134,7 +200,7 @@ static void exynos_fimd_set_buffer_address(struct vidinfo *priv, EXYNOS_BUFFER_OFFSET(win_id)); } -static void exynos_fimd_set_clock(struct vidinfo *priv) +static void exynos_fimd_set_clock(struct exynos_fb_priv *priv) { struct exynos_fb *reg = priv->reg; unsigned int cfg = 0, div = 0, remainder, remainder_div; @@ -188,7 +254,7 @@ static void exynos_fimd_set_clock(struct vidinfo *priv) writel(cfg, ®->vidcon0); } -void exynos_set_trigger(struct vidinfo *priv) +void exynos_set_trigger(struct exynos_fb_priv *priv) { struct exynos_fb *reg = priv->reg; unsigned int cfg = 0; @@ -200,7 +266,7 @@ void exynos_set_trigger(struct vidinfo *priv) writel(cfg, ®->trigcon); } -int exynos_is_i80_frame_done(struct vidinfo *priv) +int exynos_is_i80_frame_done(struct exynos_fb_priv *priv) { struct exynos_fb *reg = priv->reg; unsigned int cfg = 0; @@ -215,7 +281,7 @@ int exynos_is_i80_frame_done(struct vidinfo *priv) return status; } -static void exynos_fimd_lcd_on(struct vidinfo *priv) +static void exynos_fimd_lcd_on(struct exynos_fb_priv *priv) { struct exynos_fb *reg = priv->reg; unsigned int cfg = 0; @@ -226,7 +292,8 @@ static void exynos_fimd_lcd_on(struct vidinfo *priv) writel(cfg, ®->vidcon0); } -static void exynos_fimd_window_on(struct vidinfo *priv, unsigned int win_id) +static void exynos_fimd_window_on(struct exynos_fb_priv *priv, + unsigned int win_id) { struct exynos_fb *reg = priv->reg; unsigned int cfg = 0; @@ -243,7 +310,7 @@ static void exynos_fimd_window_on(struct vidinfo *priv, unsigned int win_id) writel(cfg, ®->winshmap); } -void exynos_fimd_lcd_off(struct vidinfo *priv) +void exynos_fimd_lcd_off(struct exynos_fb_priv *priv) { struct exynos_fb *reg = priv->reg; unsigned int cfg = 0; @@ -253,7 +320,7 @@ void exynos_fimd_lcd_off(struct vidinfo *priv) writel(cfg, ®->vidcon0); } -void exynos_fimd_window_off(struct vidinfo *priv, unsigned int win_id) +void exynos_fimd_window_off(struct exynos_fb_priv *priv, unsigned int win_id) { struct exynos_fb *reg = priv->reg; unsigned int cfg = 0; @@ -307,24 +374,16 @@ void exynos_fimd_disable_sysmmu(void) } } -void exynos_fimd_lcd_init(struct vidinfo *priv, ulong lcd_base_address) +void exynos_fimd_lcd_init(struct udevice *dev) { - struct exynos_fb *reg; + struct exynos_fb_priv *priv = dev_get_priv(dev); + struct video_uc_platdata *plat = dev_get_uclass_platdata(dev); + struct exynos_fb *reg = priv->reg; unsigned int cfg = 0, rgb_mode; unsigned int offset; unsigned int node; - node = fdtdec_next_compatible(gd->fdt_blob, - 0, COMPAT_SAMSUNG_EXYNOS_FIMD); - if (node <= 0) - debug("exynos_fb: Can't get device node for fimd\n"); - - reg = (struct exynos_fb *)fdtdec_get_addr(gd->fdt_blob, node, - "reg"); - if (reg == NULL) - debug("Can't get the FIMD base address\n"); - priv->reg = reg; - + node = dev->of_offset; if (fdtdec_get_bool(gd->fdt_blob, node, "samsung,disable-sysmmu")) exynos_fimd_disable_sysmmu(); @@ -387,13 +446,13 @@ void exynos_fimd_lcd_init(struct vidinfo *priv, ulong lcd_base_address) exynos_fimd_set_par(priv, priv->win_id); /* set memory address */ - exynos_fimd_set_buffer_address(priv, priv->win_id, lcd_base_address); + exynos_fimd_set_buffer_address(priv, priv->win_id, plat->base); /* set buffer size */ cfg = EXYNOS_VIDADDR_PAGEWIDTH(priv->vl_col * - NBITS(priv->vl_bpix) / 8) | + VNBITS(priv->vl_bpix) / 8) | EXYNOS_VIDADDR_PAGEWIDTH_E(priv->vl_col * - NBITS(priv->vl_bpix) / 8) | + VNBITS(priv->vl_bpix) / 8) | EXYNOS_VIDADDR_OFFSIZE(0) | EXYNOS_VIDADDR_OFFSIZE_E(0); @@ -415,26 +474,9 @@ void exynos_fimd_lcd_init(struct vidinfo *priv, ulong lcd_base_address) exynos_fimd_set_dp_clkcon(priv, priv->dp_enabled); } -unsigned long exynos_fimd_calc_fbsize(struct vidinfo *priv) -{ - return priv->vl_col * priv->vl_row * (NBITS(priv->vl_bpix) / 8); -} - -ushort *configuration_get_cmap(void) -{ -#if defined(CONFIG_LCD_LOGO) - return bmp_logo_palette; -#else - return NULL; -#endif -} - -static void exynos_lcd_init(struct vidinfo *vid, ulong lcd_base) +unsigned long exynos_fimd_calc_fbsize(struct exynos_fb_priv *priv) { - exynos_fimd_lcd_init(vid, lcd_base); - - /* Enable flushing after LCD writes if requested */ - lcd_set_flush_dcache(1); + return priv->vl_col * priv->vl_row * (VNBITS(priv->vl_bpix) / 8); } __weak void exynos_cfg_lcd_gpio(void) @@ -470,217 +512,242 @@ __weak int exynos_lcd_misc_init(struct vidinfo *vid) return 0; } -static void lcd_panel_on(struct vidinfo *vid) +int exynos_fb_ofdata_to_platdata(struct udevice *dev) { - struct gpio_desc pwm_out_gpio; - struct gpio_desc bl_en_gpio; - unsigned int node; - - udelay(vid->init_delay); - - exynos_backlight_reset(); - - exynos_cfg_lcd_gpio(); - - exynos_lcd_power_on(); - - udelay(vid->power_on_delay); - - if (vid->dp_enabled) - exynos_init_dp(); - - exynos_reset_lcd(); - - udelay(vid->reset_delay); - - exynos_backlight_on(1); - - node = fdtdec_next_compatible(gd->fdt_blob, 0, - COMPAT_SAMSUNG_EXYNOS_FIMD); - if (node <= 0) { - debug("FIMD: Can't get device node for FIMD\n"); - return; - } - gpio_request_by_name_nodev(gd->fdt_blob, node, "samsung,pwm-out-gpio", - 0, &pwm_out_gpio, - GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE); - - gpio_request_by_name_nodev(gd->fdt_blob, node, "samsung,bl-en-gpio", 0, - &bl_en_gpio, - GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE); - - exynos_cfg_ldo(); + struct exynos_fb_priv *priv = dev_get_priv(dev); + unsigned int node = dev->of_offset; + const void *blob = gd->fdt_blob; + fdt_addr_t addr; - exynos_enable_ldo(1); - - if (vid->mipi_enabled) - exynos_mipi_dsi_init(panel_info.dsim_platform_data_dt); -} - -int exynos_lcd_early_init(const void *blob) -{ - unsigned int node; - node = fdtdec_next_compatible(blob, 0, COMPAT_SAMSUNG_EXYNOS_FIMD); - if (node <= 0) { - debug("exynos_fb: Can't get device node for fimd\n"); - return -ENODEV; + addr = dev_get_addr(dev); + if (addr == FDT_ADDR_T_NONE) { + debug("Can't get the FIMD base address\n"); + return -EINVAL; } + priv->reg = (struct exynos_fb *)addr; - panel_info.vl_col = fdtdec_get_int(blob, node, "samsung,vl-col", 0); - if (panel_info.vl_col == 0) { + priv->vl_col = fdtdec_get_int(blob, node, "samsung,vl-col", 0); + if (priv->vl_col == 0) { debug("Can't get XRES\n"); return -ENXIO; } - panel_info.vl_row = fdtdec_get_int(blob, node, "samsung,vl-row", 0); - if (panel_info.vl_row == 0) { + priv->vl_row = fdtdec_get_int(blob, node, "samsung,vl-row", 0); + if (priv->vl_row == 0) { debug("Can't get YRES\n"); return -ENXIO; } - panel_info.vl_width = fdtdec_get_int(blob, node, + priv->vl_width = fdtdec_get_int(blob, node, "samsung,vl-width", 0); - panel_info.vl_height = fdtdec_get_int(blob, node, + priv->vl_height = fdtdec_get_int(blob, node, "samsung,vl-height", 0); - panel_info.vl_freq = fdtdec_get_int(blob, node, "samsung,vl-freq", 0); - if (panel_info.vl_freq == 0) { + priv->vl_freq = fdtdec_get_int(blob, node, "samsung,vl-freq", 0); + if (priv->vl_freq == 0) { debug("Can't get refresh rate\n"); return -ENXIO; } if (fdtdec_get_bool(blob, node, "samsung,vl-clkp")) - panel_info.vl_clkp = CONFIG_SYS_LOW; + priv->vl_clkp = VIDEO_ACTIVE_LOW; if (fdtdec_get_bool(blob, node, "samsung,vl-oep")) - panel_info.vl_oep = CONFIG_SYS_LOW; + priv->vl_oep = VIDEO_ACTIVE_LOW; if (fdtdec_get_bool(blob, node, "samsung,vl-hsp")) - panel_info.vl_hsp = CONFIG_SYS_LOW; + priv->vl_hsp = VIDEO_ACTIVE_LOW; if (fdtdec_get_bool(blob, node, "samsung,vl-vsp")) - panel_info.vl_vsp = CONFIG_SYS_LOW; + priv->vl_vsp = VIDEO_ACTIVE_LOW; if (fdtdec_get_bool(blob, node, "samsung,vl-dp")) - panel_info.vl_dp = CONFIG_SYS_LOW; + priv->vl_dp = VIDEO_ACTIVE_LOW; - panel_info.vl_bpix = fdtdec_get_int(blob, node, "samsung,vl-bpix", 0); - if (panel_info.vl_bpix == 0) { + priv->vl_bpix = fdtdec_get_int(blob, node, "samsung,vl-bpix", 0); + if (priv->vl_bpix == 0) { debug("Can't get bits per pixel\n"); return -ENXIO; } - panel_info.vl_hspw = fdtdec_get_int(blob, node, "samsung,vl-hspw", 0); - if (panel_info.vl_hspw == 0) { + priv->vl_hspw = fdtdec_get_int(blob, node, "samsung,vl-hspw", 0); + if (priv->vl_hspw == 0) { debug("Can't get hsync width\n"); return -ENXIO; } - panel_info.vl_hfpd = fdtdec_get_int(blob, node, "samsung,vl-hfpd", 0); - if (panel_info.vl_hfpd == 0) { + priv->vl_hfpd = fdtdec_get_int(blob, node, "samsung,vl-hfpd", 0); + if (priv->vl_hfpd == 0) { debug("Can't get right margin\n"); return -ENXIO; } - panel_info.vl_hbpd = (u_char)fdtdec_get_int(blob, node, + priv->vl_hbpd = (u_char)fdtdec_get_int(blob, node, "samsung,vl-hbpd", 0); - if (panel_info.vl_hbpd == 0) { + if (priv->vl_hbpd == 0) { debug("Can't get left margin\n"); return -ENXIO; } - panel_info.vl_vspw = (u_char)fdtdec_get_int(blob, node, + priv->vl_vspw = (u_char)fdtdec_get_int(blob, node, "samsung,vl-vspw", 0); - if (panel_info.vl_vspw == 0) { + if (priv->vl_vspw == 0) { debug("Can't get vsync width\n"); return -ENXIO; } - panel_info.vl_vfpd = fdtdec_get_int(blob, node, + priv->vl_vfpd = fdtdec_get_int(blob, node, "samsung,vl-vfpd", 0); - if (panel_info.vl_vfpd == 0) { + if (priv->vl_vfpd == 0) { debug("Can't get lower margin\n"); return -ENXIO; } - panel_info.vl_vbpd = fdtdec_get_int(blob, node, "samsung,vl-vbpd", 0); - if (panel_info.vl_vbpd == 0) { + priv->vl_vbpd = fdtdec_get_int(blob, node, "samsung,vl-vbpd", 0); + if (priv->vl_vbpd == 0) { debug("Can't get upper margin\n"); return -ENXIO; } - panel_info.vl_cmd_allow_len = fdtdec_get_int(blob, node, + priv->vl_cmd_allow_len = fdtdec_get_int(blob, node, "samsung,vl-cmd-allow-len", 0); - panel_info.win_id = fdtdec_get_int(blob, node, "samsung,winid", 0); - panel_info.init_delay = fdtdec_get_int(blob, node, + priv->win_id = fdtdec_get_int(blob, node, "samsung,winid", 0); + priv->init_delay = fdtdec_get_int(blob, node, "samsung,init-delay", 0); - panel_info.power_on_delay = fdtdec_get_int(blob, node, + priv->power_on_delay = fdtdec_get_int(blob, node, "samsung,power-on-delay", 0); - panel_info.reset_delay = fdtdec_get_int(blob, node, + priv->reset_delay = fdtdec_get_int(blob, node, "samsung,reset-delay", 0); - panel_info.interface_mode = fdtdec_get_int(blob, node, + priv->interface_mode = fdtdec_get_int(blob, node, "samsung,interface-mode", 0); - panel_info.mipi_enabled = fdtdec_get_int(blob, node, + priv->mipi_enabled = fdtdec_get_int(blob, node, "samsung,mipi-enabled", 0); - panel_info.dp_enabled = fdtdec_get_int(blob, node, + priv->dp_enabled = fdtdec_get_int(blob, node, "samsung,dp-enabled", 0); - panel_info.cs_setup = fdtdec_get_int(blob, node, + priv->cs_setup = fdtdec_get_int(blob, node, "samsung,cs-setup", 0); - panel_info.wr_setup = fdtdec_get_int(blob, node, + priv->wr_setup = fdtdec_get_int(blob, node, "samsung,wr-setup", 0); - panel_info.wr_act = fdtdec_get_int(blob, node, "samsung,wr-act", 0); - panel_info.wr_hold = fdtdec_get_int(blob, node, "samsung,wr-hold", 0); + priv->wr_act = fdtdec_get_int(blob, node, "samsung,wr-act", 0); + priv->wr_hold = fdtdec_get_int(blob, node, "samsung,wr-hold", 0); - panel_info.logo_on = fdtdec_get_int(blob, node, "samsung,logo-on", 0); - if (panel_info.logo_on) { - panel_info.logo_width = fdtdec_get_int(blob, node, + priv->logo_on = fdtdec_get_int(blob, node, "samsung,logo-on", 0); + if (priv->logo_on) { + priv->logo_width = fdtdec_get_int(blob, node, "samsung,logo-width", 0); - panel_info.logo_height = fdtdec_get_int(blob, node, + priv->logo_height = fdtdec_get_int(blob, node, "samsung,logo-height", 0); - panel_info.logo_addr = fdtdec_get_int(blob, node, + priv->logo_addr = fdtdec_get_int(blob, node, "samsung,logo-addr", 0); } - panel_info.rgb_mode = fdtdec_get_int(blob, node, + priv->rgb_mode = fdtdec_get_int(blob, node, "samsung,rgb-mode", 0); - panel_info.pclk_name = fdtdec_get_int(blob, node, + priv->pclk_name = fdtdec_get_int(blob, node, "samsung,pclk-name", 0); - panel_info.sclk_div = fdtdec_get_int(blob, node, + priv->sclk_div = fdtdec_get_int(blob, node, "samsung,sclk-div", 0); - panel_info.dual_lcd_enabled = fdtdec_get_int(blob, node, + priv->dual_lcd_enabled = fdtdec_get_int(blob, node, "samsung,dual-lcd-enabled", 0); return 0; } -void lcd_ctrl_init(void *lcdbase) +static int exynos_fb_probe(struct udevice *dev) { + struct video_priv *uc_priv = dev_get_uclass_priv(dev); + struct exynos_fb_priv *priv = dev_get_priv(dev); + struct udevice *panel, *bridge; + struct udevice *dp; + int ret; + + debug("%s: start\n", __func__); set_system_display_ctrl(); set_lcd_clk(); #ifdef CONFIG_EXYNOS_MIPI_DSIM exynos_init_dsim_platform_data(&panel_info); #endif - exynos_lcd_misc_init(&panel_info); + exynos_fimd_lcd_init(dev); - exynos_lcd_init(&panel_info, (ulong)lcdbase); -} + ret = uclass_first_device(UCLASS_PANEL, &panel); + if (ret) { + printf("LCD panel failed to probe\n"); + return ret; + } + if (!panel) { + printf("LCD panel not found\n"); + return -ENODEV; + } -void lcd_enable(void) -{ - if (panel_info.logo_on) { - memset((void *)gd->fb_base, 0, - panel_info.vl_width * panel_info.vl_height * - (NBITS(panel_info.vl_bpix) >> 3)); + ret = uclass_first_device(UCLASS_DISPLAY, &dp); + if (ret) { + debug("%s: Display device error %d\n", __func__, ret); + return ret; + } + if (!dev) { + debug("%s: Display device missing\n", __func__); + return -ENODEV; + } + ret = display_enable(dp, 18, NULL); + if (ret) { + debug("%s: Display enable error %d\n", __func__, ret); + return ret; } - lcd_panel_on(&panel_info); + /* backlight / pwm */ + ret = panel_enable_backlight(panel); + if (ret) { + debug("%s: backlight error: %d\n", __func__, ret); + return ret; + } + + ret = uclass_get_device(UCLASS_VIDEO_BRIDGE, 0, &bridge); + if (!ret) + ret = video_bridge_set_backlight(bridge, 80); + if (ret) { + debug("%s: No video bridge, or no backlight on bridge\n", + __func__); + exynos_pinmux_config(PERIPH_ID_PWM0, 0); + } + + uc_priv->xsize = priv->vl_col; + uc_priv->ysize = priv->vl_row; + uc_priv->bpix = priv->vl_bpix; + + /* Enable flushing after LCD writes if requested */ + video_set_flush_dcache(dev, true); + + return 0; } -/* dummy function */ -void lcd_setcolreg(ushort regno, ushort red, ushort green, ushort blue) +static int exynos_fb_bind(struct udevice *dev) { - return; + struct video_uc_platdata *plat = dev_get_uclass_platdata(dev); + + /* This is the maximum panel size we expect to see */ + plat->size = 1920 * 1080 * 2; + + return 0; } + +static const struct video_ops exynos_fb_ops = { +}; + +static const struct udevice_id exynos_fb_ids[] = { + { .compatible = "samsung,exynos-fimd" }, + { } +}; + +U_BOOT_DRIVER(exynos_fb) = { + .name = "exynos_fb", + .id = UCLASS_VIDEO, + .of_match = exynos_fb_ids, + .ops = &exynos_fb_ops, + .bind = exynos_fb_bind, + .probe = exynos_fb_probe, + .ofdata_to_platdata = exynos_fb_ofdata_to_platdata, + .priv_auto_alloc_size = sizeof(struct exynos_fb_priv), +}; diff --git a/drivers/video/simple_panel.c b/drivers/video/simple_panel.c index 6219300..b2fe345 100644 --- a/drivers/video/simple_panel.c +++ b/drivers/video/simple_panel.c @@ -88,6 +88,8 @@ static const struct panel_ops simple_panel_ops = { static const struct udevice_id simple_panel_ids[] = { { .compatible = "simple-panel" }, { .compatible = "auo,b133xtn01" }, + { .compatible = "auo,b116xw03" }, + { .compatible = "auo,b133htn01" }, { } }; diff --git a/include/configs/exynos5-common.h b/include/configs/exynos5-common.h index b2ff4dd..311fd09 100644 --- a/include/configs/exynos5-common.h +++ b/include/configs/exynos5-common.h @@ -124,7 +124,6 @@ #define CONFIG_SYS_I2C_S3C24X0 #define CONFIG_SYS_I2C_S3C24X0_SPEED 100000 /* 100 Kbps */ #define CONFIG_SYS_I2C_S3C24X0_SLAVE 0x0 -#define CONFIG_I2C_EDID /* SPI */ #ifdef CONFIG_SPI_FLASH diff --git a/include/configs/exynos5-dt-common.h b/include/configs/exynos5-dt-common.h index 8b61a52..3d81f94 100644 --- a/include/configs/exynos5-dt-common.h +++ b/include/configs/exynos5-dt-common.h @@ -13,8 +13,8 @@ #undef EXYNOS_DEVICE_SETTINGS #define EXYNOS_DEVICE_SETTINGS \ "stdin=serial,cros-ec-keyb\0" \ - "stdout=serial,lcd\0" \ - "stderr=serial,lcd\0" + "stdout=serial,vidconsole\0" \ + "stderr=serial,vidconsole\0" #define CONFIG_EXYNOS5_DT @@ -32,6 +32,7 @@ #define CONFIG_EXYNOS_FB #define CONFIG_EXYNOS_DP #define LCD_BPP LCD_COLOR16 +#define CONFIG_SYS_WHITE_ON_BLACK #endif /* Enable keyboard */ -- cgit v0.10.2 From f4f2fce70ccf793b10a59e48eb12fd8daa0b1f34 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 21 Feb 2016 21:09:02 -0700 Subject: exynos: video: Drop old unused code Now that we are using driver model, we can drop the weak functions and LCD init in the board file. Signed-off-by: Simon Glass Acked-by: Anatolij Gustschin Signed-off-by: Minkyu Kang diff --git a/board/samsung/common/exynos5-dt.c b/board/samsung/common/exynos5-dt.c index 0dcea71..2e3b16d 100644 --- a/board/samsung/common/exynos5-dt.c +++ b/board/samsung/common/exynos5-dt.c @@ -147,159 +147,6 @@ int board_get_revision(void) return 0; } -#ifdef CONFIG_LCD - -static int board_dp_bridge_init(struct udevice *dev) -{ - const int max_tries = 10; - int num_tries; - int ret; - - debug("%s\n", __func__); - ret = video_bridge_attach(dev); - if (ret) { - debug("video bridge init failed: %d\n", ret); - return ret; - } - - /* - * We need to wait for 90ms after bringing up the bridge since there - * is a phantom "high" on the HPD chip during its bootup. The phantom - * high comes within 7ms of de-asserting PD and persists for at least - * 15ms. The real high comes roughly 50ms after PD is de-asserted. The - * phantom high makes it hard for us to know when the NXP chip is up. - */ - mdelay(90); - - for (num_tries = 0; num_tries < max_tries; num_tries++) { - /* Check HPD. If it's high, or we don't have it, all is well */ - ret = video_bridge_check_attached(dev); - if (!ret || ret == -ENOENT) - return 0; - - debug("%s: eDP bridge failed to come up; try %d of %d\n", - __func__, num_tries, max_tries); - } - - /* Immediately go into bridge reset if the hp line is not high */ - return -EIO; -} - -static int board_dp_bridge_setup(const void *blob) -{ - const int max_tries = 2; - int num_tries; - struct udevice *dev; - int ret; - - /* Configure I2C registers for Parade bridge */ - ret = uclass_get_device(UCLASS_VIDEO_BRIDGE, 0, &dev); - if (ret) { - debug("video bridge init failed: %d\n", ret); - return ret; - } - - if (strncmp(dev->driver->name, "parade", 6)) { - /* Mux HPHPD to the special hotplug detect mode */ - exynos_pinmux_config(PERIPH_ID_DPHPD, 0); - } - - for (num_tries = 0; num_tries < max_tries; num_tries++) { - ret = board_dp_bridge_init(dev); - if (!ret) - return 0; - if (num_tries == max_tries - 1) - break; - - /* - * If we're here, the bridge chip failed to initialise. - * Power down the bridge in an attempt to reset. - */ - video_bridge_set_active(dev, false); - - /* - * Arbitrarily wait 300ms here with DP_N low. Don't know for - * sure how long we should wait, but we're being paranoid. - */ - mdelay(300); - } - - return ret; -} - -void exynos_cfg_lcd_gpio(void) -{ - /* For Backlight */ - gpio_request(EXYNOS5_GPIO_B20, "lcd_backlight"); - gpio_cfg_pin(EXYNOS5_GPIO_B20, S5P_GPIO_OUTPUT); - gpio_set_value(EXYNOS5_GPIO_B20, 1); -} - -static int board_dp_set_backlight(int percent) -{ - struct udevice *dev; - int ret; - - ret = uclass_get_device(UCLASS_VIDEO_BRIDGE, 0, &dev); - if (!ret) - ret = video_bridge_set_backlight(dev, percent); - - return ret; -} - -void exynos_backlight_on(unsigned int on) -{ - struct udevice *dev; - int ret; - - debug("%s(%u)\n", __func__, on); - if (!on) - return; - - ret = regulator_get_by_platname("vcd_led", &dev); - if (!ret) - ret = regulator_set_enable(dev, true); - if (ret) - debug("Failed to enable backlight: ret=%d\n", ret); - - /* T5 in the LCD timing spec (defined as > 10ms) */ - mdelay(10); - - /* board_dp_backlight_pwm */ - gpio_direction_output(EXYNOS5_GPIO_B20, 1); - - /* T6 in the LCD timing spec (defined as > 10ms) */ - mdelay(10); - - /* try to set the backlight in the bridge registers */ - ret = board_dp_set_backlight(80); - - /* if we have no bridge or it does not support backlight, use a GPIO */ - if (ret == -ENODEV || ret == -ENOSYS) { - gpio_request(EXYNOS5_GPIO_X30, "board_dp_backlight_en"); - gpio_direction_output(EXYNOS5_GPIO_X30, 1); - } -} - -void exynos_lcd_power_on(void) -{ - struct udevice *dev; - int ret; - - debug("%s\n", __func__); - ret = regulator_get_by_platname("lcd_vdd", &dev); - if (!ret) - ret = regulator_set_enable(dev, true); - if (ret) - debug("Failed to enable LCD panel: ret=%d\n", ret); - - ret = board_dp_bridge_setup(gd->fdt_blob); - if (ret && ret != -ENODEV) - printf("LCD bridge failed to enable: %d\n", ret); -} - -#endif - #ifdef CONFIG_USB_DWC3 static struct dwc3_device dwc3_device_data = { .maximum_speed = USB_SPEED_SUPER, diff --git a/drivers/video/exynos/exynos_fb.c b/drivers/video/exynos/exynos_fb.c index c8fef63..97228cd 100644 --- a/drivers/video/exynos/exynos_fb.c +++ b/drivers/video/exynos/exynos_fb.c @@ -479,39 +479,6 @@ unsigned long exynos_fimd_calc_fbsize(struct exynos_fb_priv *priv) return priv->vl_col * priv->vl_row * (VNBITS(priv->vl_bpix) / 8); } -__weak void exynos_cfg_lcd_gpio(void) -{ -} - -__weak void exynos_backlight_on(unsigned int onoff) -{ -} - -__weak void exynos_reset_lcd(void) -{ -} - -__weak void exynos_lcd_power_on(void) -{ -} - -__weak void exynos_cfg_ldo(void) -{ -} - -__weak void exynos_enable_ldo(unsigned int onoff) -{ -} - -__weak void exynos_backlight_reset(void) -{ -} - -__weak int exynos_lcd_misc_init(struct vidinfo *vid) -{ - return 0; -} - int exynos_fb_ofdata_to_platdata(struct udevice *dev) { struct exynos_fb_priv *priv = dev_get_priv(dev); diff --git a/drivers/video/exynos/exynos_fb.h b/drivers/video/exynos/exynos_fb.h deleted file mode 100644 index f59cce0..0000000 --- a/drivers/video/exynos/exynos_fb.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (C) 2012 Samsung Electronics - * - * Author: InKi Dae - * Author: Donghwa Lee - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#ifndef _EXYNOS_FB_H_ -#define _EXYNOS_FB_H_ - -#include - -#define MAX_CLOCK (86 * 1000000) - -enum exynos_cpu_auto_cmd_rate { - DISABLE_AUTO_FRM, - PER_TWO_FRM, - PER_FOUR_FRM, - PER_SIX_FRM, - PER_EIGHT_FRM, - PER_TEN_FRM, - PER_TWELVE_FRM, - PER_FOURTEEN_FRM, - PER_SIXTEEN_FRM, - PER_EIGHTEEN_FRM, - PER_TWENTY_FRM, - PER_TWENTY_TWO_FRM, - PER_TWENTY_FOUR_FRM, - PER_TWENTY_SIX_FRM, - PER_TWENTY_EIGHT_FRM, - PER_THIRTY_FRM, -}; - -void exynos_fimd_lcd_init_mem(unsigned long screen_base, unsigned long fb_size, - unsigned long palette_size); -void exynos_fimd_lcd_init(struct vidinfo *vid, ulong lcd_base_address); -unsigned long exynos_fimd_calc_fbsize(struct vidinfo *pvid); - -#endif -- cgit v0.10.2 From c06bbab65b79c2a1c077d78269ed2bfa87f6e923 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Sun, 1 May 2016 00:36:11 +0200 Subject: ARM: exynos: Fix build error if SERIAL is disabled in SPL If CONFIG_SPL_SERIAL_SUPPORT is not defined in include/configs/exynos5-common.h the following error is produced during the build of the SPL: arch/arm/mach-exynos/built-in.o: In function `do_lowlevel_init': ...u-boot/arch/arm/mach-exynos/lowlevel_init.c:221: undefined reference to `debug_uart_init' Add additional condition to check if SPL build is in progress and in that case check if CONFIG_SPL_SERIAL_SUPPORT is also set before enabling the debug UART. Signed-off-by: Marek Vasut Cc: Simon Glass Cc: Tom Rini Reviewed-by: Simon Glass Signed-off-by: Minkyu Kang diff --git a/arch/arm/mach-exynos/lowlevel_init.c b/arch/arm/mach-exynos/lowlevel_init.c index 6c39cb2..1e090fd 100644 --- a/arch/arm/mach-exynos/lowlevel_init.c +++ b/arch/arm/mach-exynos/lowlevel_init.c @@ -216,9 +216,12 @@ int do_lowlevel_init(void) if (actions & DO_CLOCKS) { system_clock_init(); #ifdef CONFIG_DEBUG_UART +#if (defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_SERIAL_SUPPORT)) || \ + !defined(CONFIG_SPL_BUILD) exynos_pinmux_config(PERIPH_ID_UART3, PINMUX_FLAG_NONE); debug_uart_init(); #endif +#endif mem_ctrl_init(actions & DO_MEM_RESET); tzpc_init(); } -- cgit v0.10.2 From 086e13c5f6f79a68246d6b803cf4736cb6815e44 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Sun, 1 May 2016 00:36:12 +0200 Subject: ARM: exynos: Disable serial support in SPL The exynos5 platforms use DM in U-Boot and do not use DM in SPL. The serial driver, serial_s5p.c, is DM-only. This is OK for U-Boot, but in SPL, this will fail with the following compile error: drivers/built-in.o: In function `get_current': ...u-boot/drivers/serial/serial.c:387: undefined reference to `default_serial_console' This warning happens because common/console.c is compiled into U-Boot SPL if CONFIG_SPL_SERIAL_SUPPORT . The common/console.c invokes serial_*() functions and since exynos5 does not use DM in SPL, these functions come from drivers/serial/serial.c . The serial_*() locate default serial port by calling default_serial_console(), but because the serial_s5p.c is DM-only, it does no longer define default_serial_console(). Thus the error. Signed-off-by: Marek Vasut Cc: Simon Glass Cc: Tom Rini Reviewed-by: Simon Glass Signed-off-by: Minkyu Kang diff --git a/include/configs/exynos5-common.h b/include/configs/exynos5-common.h index 311fd09..061cac4 100644 --- a/include/configs/exynos5-common.h +++ b/include/configs/exynos5-common.h @@ -60,7 +60,6 @@ #define CONFIG_SPL_LIBCOMMON_SUPPORT #define CONFIG_SPL_GPIO_SUPPORT -#define CONFIG_SPL_SERIAL_SUPPORT #define CONFIG_SPL_LIBGENERIC_SUPPORT /* specific .lds file */ -- cgit v0.10.2