summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/dfu/dfu.c6
-rw-r--r--drivers/misc/Makefile1
-rw-r--r--drivers/misc/mxs_ocotp.c311
-rw-r--r--drivers/mmc/s5p_sdhci.c129
-rw-r--r--drivers/net/cpsw.c6
-rw-r--r--drivers/pci/pcie_imx.c13
-rw-r--r--drivers/power/pmic/Makefile1
-rw-r--r--drivers/power/pmic/pmic_pfuze100.c32
-rw-r--r--drivers/spi/omap3_spi.c5
-rw-r--r--drivers/video/exynos_fb.c12
-rw-r--r--drivers/video/exynos_mipi_dsi.c96
11 files changed, 603 insertions, 9 deletions
diff --git a/drivers/dfu/dfu.c b/drivers/dfu/dfu.c
index f94c412..8a09aaf 100644
--- a/drivers/dfu/dfu.c
+++ b/drivers/dfu/dfu.c
@@ -19,6 +19,7 @@
static bool dfu_reset_request;
static LIST_HEAD(dfu_list);
static int dfu_alt_num;
+static int alt_num_cnt;
bool dfu_reset(void)
{
@@ -379,6 +380,8 @@ void dfu_free_entities(void)
if (t)
free(t);
INIT_LIST_HEAD(&dfu_list);
+
+ alt_num_cnt = 0;
}
int dfu_config_entities(char *env, char *interface, int num)
@@ -396,11 +399,12 @@ int dfu_config_entities(char *env, char *interface, int num)
for (i = 0; i < dfu_alt_num; i++) {
s = strsep(&env, ";");
- ret = dfu_fill_entity(&dfu[i], s, i, interface, num);
+ ret = dfu_fill_entity(&dfu[i], s, alt_num_cnt, interface, num);
if (ret)
return -1;
list_add_tail(&dfu[i].list, &dfu_list);
+ alt_num_cnt++;
}
return 0;
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index c25e92d..2f2e48f 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -17,6 +17,7 @@ obj-$(CONFIG_FSL_IIM) += fsl_iim.o
obj-$(CONFIG_GPIO_LED) += gpio_led.o
obj-$(CONFIG_FSL_MC9SDZ60) += mc9sdz60.o
obj-$(CONFIG_MXC_OCOTP) += mxc_ocotp.o
+obj-$(CONFIG_MXS_OCOTP) += mxs_ocotp.o
obj-$(CONFIG_NS87308) += ns87308.o
obj-$(CONFIG_PDSP188x) += pdsp188x.o
obj-$(CONFIG_STATUS_LED) += status_led.o
diff --git a/drivers/misc/mxs_ocotp.c b/drivers/misc/mxs_ocotp.c
new file mode 100644
index 0000000..545d3eb
--- /dev/null
+++ b/drivers/misc/mxs_ocotp.c
@@ -0,0 +1,311 @@
+/*
+ * Freescale i.MX28 OCOTP Driver
+ *
+ * Copyright (C) 2014 Marek Vasut <marex@denx.de>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ *
+ * Note: The i.MX23/i.MX28 OCOTP block is a predecessor to the OCOTP block
+ * used in i.MX6 . While these blocks are very similar at the first
+ * glance, by digging deeper, one will notice differences (like the
+ * tight dependence on MXS power block, some completely new registers
+ * etc.) which would make common driver an ifdef nightmare :-(
+ */
+
+#include <common.h>
+#include <fuse.h>
+#include <asm/errno.h>
+#include <asm/io.h>
+#include <asm/arch/clock.h>
+#include <asm/arch/imx-regs.h>
+#include <asm/arch/sys_proto.h>
+
+#define MXS_OCOTP_TIMEOUT 100000
+
+static struct mxs_ocotp_regs *ocotp_regs =
+ (struct mxs_ocotp_regs *)MXS_OCOTP_BASE;
+static struct mxs_power_regs *power_regs =
+ (struct mxs_power_regs *)MXS_POWER_BASE;
+static struct mxs_clkctrl_regs *clkctrl_regs =
+ (struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE;
+
+static int mxs_ocotp_wait_busy_clear(void)
+{
+ uint32_t reg;
+ int timeout = MXS_OCOTP_TIMEOUT;
+
+ while (--timeout) {
+ reg = readl(&ocotp_regs->hw_ocotp_ctrl);
+ if (!(reg & OCOTP_CTRL_BUSY))
+ break;
+ udelay(10);
+ }
+
+ if (!timeout)
+ return -EINVAL;
+
+ /* Wait a little as per FSL datasheet's 'write postamble' section. */
+ udelay(10);
+
+ return 0;
+}
+
+static void mxs_ocotp_clear_error(void)
+{
+ writel(OCOTP_CTRL_ERROR, &ocotp_regs->hw_ocotp_ctrl_clr);
+}
+
+static int mxs_ocotp_read_bank_open(bool open)
+{
+ int ret = 0;
+
+ if (open) {
+ writel(OCOTP_CTRL_RD_BANK_OPEN,
+ &ocotp_regs->hw_ocotp_ctrl_set);
+
+ /*
+ * Wait before polling the BUSY bit, since the BUSY bit might
+ * be asserted only after a few HCLK cycles and if we were to
+ * poll immediatelly, we could miss the busy bit.
+ */
+ udelay(10);
+ ret = mxs_ocotp_wait_busy_clear();
+ } else {
+ writel(OCOTP_CTRL_RD_BANK_OPEN,
+ &ocotp_regs->hw_ocotp_ctrl_clr);
+ }
+
+ return ret;
+}
+
+static void mxs_ocotp_scale_vddio(bool enter, uint32_t *val)
+{
+ uint32_t scale_val;
+
+ if (enter) {
+ /*
+ * Enter the fuse programming VDDIO voltage setup. We start
+ * scaling the voltage from it's current value down to 2.8V
+ * which is the one and only correct voltage for programming
+ * the OCOTP fuses (according to datasheet).
+ */
+ scale_val = readl(&power_regs->hw_power_vddioctrl);
+ scale_val &= POWER_VDDIOCTRL_TRG_MASK;
+
+ /* Return the original voltage. */
+ *val = scale_val;
+
+ /*
+ * Start scaling VDDIO down to 0x2, which is 2.8V . Actually,
+ * the value 0x0 should be 2.8V, but that's not the case on
+ * most designs due to load etc., so we play safe. Undervolt
+ * can actually cause incorrect programming of the fuses and
+ * or reboots of the board.
+ */
+ while (scale_val > 2) {
+ clrsetbits_le32(&power_regs->hw_power_vddioctrl,
+ POWER_VDDIOCTRL_TRG_MASK, --scale_val);
+ udelay(500);
+ }
+ } else {
+ /* Start scaling VDDIO up to original value . */
+ for (scale_val = 2; scale_val <= *val; scale_val++) {
+ clrsetbits_le32(&power_regs->hw_power_vddioctrl,
+ POWER_VDDIOCTRL_TRG_MASK, scale_val);
+ udelay(500);
+ }
+ }
+
+ mdelay(10);
+}
+
+static int mxs_ocotp_wait_hclk_ready(void)
+{
+ uint32_t reg, timeout = MXS_OCOTP_TIMEOUT;
+
+ while (--timeout) {
+ reg = readl(&clkctrl_regs->hw_clkctrl_hbus);
+ if (!(reg & CLKCTRL_HBUS_ASM_BUSY))
+ break;
+ }
+
+ if (!timeout)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int mxs_ocotp_scale_hclk(bool enter, uint32_t *val)
+{
+ uint32_t scale_val;
+ int ret;
+
+ ret = mxs_ocotp_wait_hclk_ready();
+ if (ret)
+ return ret;
+
+ /* Set CPU bypass */
+ writel(CLKCTRL_CLKSEQ_BYPASS_CPU,
+ &clkctrl_regs->hw_clkctrl_clkseq_set);
+
+ if (enter) {
+ /* Return the original HCLK clock speed. */
+ *val = readl(&clkctrl_regs->hw_clkctrl_hbus);
+ *val &= CLKCTRL_HBUS_DIV_MASK;
+
+ /* Scale the HCLK to 454/19 = 23.9 MHz . */
+ scale_val = (~19) << CLKCTRL_HBUS_DIV_OFFSET;
+ scale_val &= CLKCTRL_HBUS_DIV_MASK;
+ } else {
+ /* Scale the HCLK back to original frequency. */
+ scale_val = (~(*val)) << CLKCTRL_HBUS_DIV_OFFSET;
+ scale_val &= CLKCTRL_HBUS_DIV_MASK;
+ }
+
+ writel(CLKCTRL_HBUS_DIV_MASK,
+ &clkctrl_regs->hw_clkctrl_hbus_set);
+ writel(scale_val,
+ &clkctrl_regs->hw_clkctrl_hbus_clr);
+
+ mdelay(10);
+
+ ret = mxs_ocotp_wait_hclk_ready();
+ if (ret)
+ return ret;
+
+ /* Disable CPU bypass */
+ writel(CLKCTRL_CLKSEQ_BYPASS_CPU,
+ &clkctrl_regs->hw_clkctrl_clkseq_clr);
+
+ mdelay(10);
+
+ return 0;
+}
+
+static int mxs_ocotp_write_fuse(uint32_t addr, uint32_t mask)
+{
+ uint32_t hclk_val, vddio_val;
+ int ret;
+
+ /* Make sure the banks are closed for reading. */
+ ret = mxs_ocotp_read_bank_open(0);
+ if (ret) {
+ puts("Failed closing banks for reading!\n");
+ return ret;
+ }
+
+ ret = mxs_ocotp_scale_hclk(1, &hclk_val);
+ if (ret) {
+ puts("Failed scaling down the HCLK!\n");
+ return ret;
+ }
+ mxs_ocotp_scale_vddio(1, &vddio_val);
+
+ ret = mxs_ocotp_wait_busy_clear();
+ if (ret) {
+ puts("Failed waiting for ready state!\n");
+ goto fail;
+ }
+
+ /* Program the fuse address */
+ writel(addr | OCOTP_CTRL_WR_UNLOCK_KEY, &ocotp_regs->hw_ocotp_ctrl);
+
+ /* Program the data. */
+ writel(mask, &ocotp_regs->hw_ocotp_data);
+
+ udelay(10);
+
+ ret = mxs_ocotp_wait_busy_clear();
+ if (ret) {
+ puts("Failed waiting for ready state!\n");
+ goto fail;
+ }
+
+fail:
+ mxs_ocotp_scale_vddio(0, &vddio_val);
+ ret = mxs_ocotp_scale_hclk(0, &hclk_val);
+ if (ret) {
+ puts("Failed scaling up the HCLK!\n");
+ return ret;
+ }
+
+ return ret;
+}
+
+static int mxs_ocotp_read_fuse(uint32_t reg, uint32_t *val)
+{
+ int ret;
+
+ /* Register offset from CUST0 */
+ reg = ((uint32_t)&ocotp_regs->hw_ocotp_cust0) + (reg << 4);
+
+ ret = mxs_ocotp_wait_busy_clear();
+ if (ret) {
+ puts("Failed waiting for ready state!\n");
+ return ret;
+ }
+
+ mxs_ocotp_clear_error();
+
+ ret = mxs_ocotp_read_bank_open(1);
+ if (ret) {
+ puts("Failed opening banks for reading!\n");
+ return ret;
+ }
+
+ *val = readl(reg);
+
+ ret = mxs_ocotp_read_bank_open(0);
+ if (ret) {
+ puts("Failed closing banks for reading!\n");
+ return ret;
+ }
+
+ return ret;
+}
+
+static int mxs_ocotp_valid(u32 bank, u32 word)
+{
+ if (bank > 4)
+ return -EINVAL;
+ if (word > 7)
+ return -EINVAL;
+ return 0;
+}
+
+/*
+ * The 'fuse' command API
+ */
+int fuse_read(u32 bank, u32 word, u32 *val)
+{
+ int ret;
+
+ ret = mxs_ocotp_valid(bank, word);
+ if (ret)
+ return ret;
+
+ return mxs_ocotp_read_fuse((bank << 3) | word, val);
+}
+
+int fuse_prog(u32 bank, u32 word, u32 val)
+{
+ int ret;
+
+ ret = mxs_ocotp_valid(bank, word);
+ if (ret)
+ return ret;
+
+ return mxs_ocotp_write_fuse((bank << 3) | word, val);
+}
+
+int fuse_sense(u32 bank, u32 word, u32 *val)
+{
+ /* We do not support sensing :-( */
+ return -EINVAL;
+}
+
+int fuse_override(u32 bank, u32 word, u32 val)
+{
+ /* We do not support overriding :-( */
+ return -EINVAL;
+}
diff --git a/drivers/mmc/s5p_sdhci.c b/drivers/mmc/s5p_sdhci.c
index 40ff873..ccae4cc 100644
--- a/drivers/mmc/s5p_sdhci.c
+++ b/drivers/mmc/s5p_sdhci.c
@@ -8,8 +8,15 @@
#include <common.h>
#include <malloc.h>
#include <sdhci.h>
+#include <fdtdec.h>
+#include <libfdt.h>
+#include <asm/gpio.h>
#include <asm/arch/mmc.h>
#include <asm/arch/clk.h>
+#include <errno.h>
+#ifdef CONFIG_OF_CONTROL
+#include <asm/arch/pinmux.h>
+#endif
static char *S5P_NAME = "SAMSUNG SDHCI";
static void s5p_sdhci_set_control_reg(struct sdhci_host *host)
@@ -86,3 +93,125 @@ int s5p_sdhci_init(u32 regbase, int index, int bus_width)
return add_sdhci(host, 52000000, 400000);
}
+
+#ifdef CONFIG_OF_CONTROL
+struct sdhci_host sdhci_host[SDHCI_MAX_HOSTS];
+
+static int do_sdhci_init(struct sdhci_host *host)
+{
+ int dev_id, flag;
+ int err = 0;
+
+ flag = host->bus_width == 8 ? PINMUX_FLAG_8BIT_MODE : PINMUX_FLAG_NONE;
+ dev_id = host->index + PERIPH_ID_SDMMC0;
+
+ if (fdt_gpio_isvalid(&host->pwr_gpio)) {
+ gpio_direction_output(host->pwr_gpio.gpio, 1);
+ err = exynos_pinmux_config(dev_id, flag);
+ if (err) {
+ debug("MMC not configured\n");
+ return err;
+ }
+ }
+
+ if (fdt_gpio_isvalid(&host->cd_gpio)) {
+ gpio_direction_output(host->cd_gpio.gpio, 0xf);
+ if (gpio_get_value(host->cd_gpio.gpio))
+ return -ENODEV;
+
+ err = exynos_pinmux_config(dev_id, flag);
+ if (err) {
+ printf("external SD not configured\n");
+ return err;
+ }
+ }
+
+ host->name = S5P_NAME;
+
+ host->quirks = SDHCI_QUIRK_NO_HISPD_BIT | SDHCI_QUIRK_BROKEN_VOLTAGE |
+ SDHCI_QUIRK_BROKEN_R1B | SDHCI_QUIRK_32BIT_DMA_ADDR |
+ SDHCI_QUIRK_WAIT_SEND_CMD;
+ host->voltages = MMC_VDD_32_33 | MMC_VDD_33_34 | MMC_VDD_165_195;
+ host->version = sdhci_readw(host, SDHCI_HOST_VERSION);
+
+ host->set_control_reg = &s5p_sdhci_set_control_reg;
+ host->set_clock = set_mmc_clk;
+
+ host->host_caps = MMC_MODE_HC;
+
+ return add_sdhci(host, 52000000, 400000);
+}
+
+static int sdhci_get_config(const void *blob, int node, struct sdhci_host *host)
+{
+ int bus_width, dev_id;
+ unsigned int base;
+
+ /* Get device id */
+ dev_id = pinmux_decode_periph_id(blob, node);
+ if (dev_id < PERIPH_ID_SDMMC0 && dev_id > PERIPH_ID_SDMMC3) {
+ debug("MMC: Can't get device id\n");
+ return -1;
+ }
+ host->index = dev_id - PERIPH_ID_SDMMC0;
+
+ /* Get bus width */
+ bus_width = fdtdec_get_int(blob, node, "samsung,bus-width", 0);
+ if (bus_width <= 0) {
+ debug("MMC: Can't get bus-width\n");
+ return -1;
+ }
+ host->bus_width = bus_width;
+
+ /* Get the base address from the device node */
+ base = fdtdec_get_addr(blob, node, "reg");
+ if (!base) {
+ debug("MMC: Can't get base address\n");
+ return -1;
+ }
+ host->ioaddr = (void *)base;
+
+ fdtdec_decode_gpio(blob, node, "pwr-gpios", &host->pwr_gpio);
+ fdtdec_decode_gpio(blob, node, "cd-gpios", &host->cd_gpio);
+
+ return 0;
+}
+
+static int process_nodes(const void *blob, int node_list[], int count)
+{
+ struct sdhci_host *host;
+ int i, node;
+
+ debug("%s: count = %d\n", __func__, count);
+
+ /* build sdhci_host[] for each controller */
+ for (i = 0; i < count; i++) {
+ node = node_list[i];
+ if (node <= 0)
+ continue;
+
+ host = &sdhci_host[i];
+
+ if (sdhci_get_config(blob, node, host)) {
+ printf("%s: failed to decode dev %d\n", __func__, i);
+ return -1;
+ }
+ do_sdhci_init(host);
+ }
+ return 0;
+}
+
+int exynos_mmc_init(const void *blob)
+{
+ int count;
+ int node_list[SDHCI_MAX_HOSTS];
+
+ count = fdtdec_find_aliases_for_id(blob, "mmc",
+ COMPAT_SAMSUNG_EXYNOS_MMC, node_list,
+ SDHCI_MAX_HOSTS);
+
+ process_nodes(blob, node_list, count);
+
+ return 1;
+}
+#endif
diff --git a/drivers/net/cpsw.c b/drivers/net/cpsw.c
index dd6c26a..bd5fba2 100644
--- a/drivers/net/cpsw.c
+++ b/drivers/net/cpsw.c
@@ -941,11 +941,7 @@ static int cpsw_phy_init(struct eth_device *dev, struct cpsw_slave *slave)
{
struct cpsw_priv *priv = (struct cpsw_priv *)dev->priv;
struct phy_device *phydev;
- u32 supported = (SUPPORTED_10baseT_Half |
- SUPPORTED_10baseT_Full |
- SUPPORTED_100baseT_Half |
- SUPPORTED_100baseT_Full |
- SUPPORTED_1000baseT_Full);
+ u32 supported = PHY_GBIT_FEATURES;
phydev = phy_connect(priv->bus,
slave->data->phy_addr,
diff --git a/drivers/pci/pcie_imx.c b/drivers/pci/pcie_imx.c
index 1f600aa..c48737e 100644
--- a/drivers/pci/pcie_imx.c
+++ b/drivers/pci/pcie_imx.c
@@ -451,6 +451,17 @@ static int imx6_pcie_init_phy(void)
return 0;
}
+__weak int imx6_pcie_toggle_power(void)
+{
+#ifdef CONFIG_PCIE_IMX_POWER_GPIO
+ gpio_direction_output(CONFIG_PCIE_IMX_POWER_GPIO, 0);
+ mdelay(20);
+ gpio_set_value(CONFIG_PCIE_IMX_POWER_GPIO, 1);
+ mdelay(20);
+#endif
+ return 0;
+}
+
__weak int imx6_pcie_toggle_reset(void)
{
/*
@@ -496,7 +507,7 @@ static int imx6_pcie_deassert_core_reset(void)
{
struct iomuxc *iomuxc_regs = (struct iomuxc *)IOMUXC_BASE_ADDR;
- /* FIXME: Power-up GPIO goes here. */
+ imx6_pcie_toggle_power();
/* Enable PCIe */
clrbits_le32(&iomuxc_regs->gpr[1], IOMUXC_GPR1_TEST_POWERDOWN);
diff --git a/drivers/power/pmic/Makefile b/drivers/power/pmic/Makefile
index 0b45ffa..4129bda 100644
--- a/drivers/power/pmic/Makefile
+++ b/drivers/power/pmic/Makefile
@@ -9,5 +9,6 @@ obj-$(CONFIG_POWER_MAX8998) += pmic_max8998.o
obj-$(CONFIG_POWER_MAX8997) += pmic_max8997.o
obj-$(CONFIG_POWER_MUIC_MAX8997) += muic_max8997.o
obj-$(CONFIG_POWER_MAX77686) += pmic_max77686.o
+obj-$(CONFIG_POWER_PFUZE100) += pmic_pfuze100.o
obj-$(CONFIG_POWER_TPS65217) += pmic_tps65217.o
obj-$(CONFIG_POWER_TPS65910) += pmic_tps65910.o
diff --git a/drivers/power/pmic/pmic_pfuze100.c b/drivers/power/pmic/pmic_pfuze100.c
new file mode 100644
index 0000000..22c1f15
--- /dev/null
+++ b/drivers/power/pmic/pmic_pfuze100.c
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2014 Gateworks Corporation
+ * Tim Harvey <tharvey@gateworks.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <errno.h>
+#include <i2c.h>
+#include <power/pmic.h>
+#include <power/pfuze100_pmic.h>
+
+int pmic_init(unsigned char bus)
+{
+ static const char name[] = "PFUZE100_PMIC";
+ struct pmic *p = pmic_alloc();
+
+ if (!p) {
+ printf("%s: POWER allocation error!\n", __func__);
+ return -ENOMEM;
+ }
+
+ p->name = name;
+ p->interface = PMIC_I2C;
+ p->number_of_regs = PMIC_NUM_OF_REGS;
+ p->hw.i2c.addr = CONFIG_POWER_PFUZE100_I2C_ADDR;
+ p->hw.i2c.tx_num = 1;
+ p->bus = bus;
+
+ return 0;
+}
diff --git a/drivers/spi/omap3_spi.c b/drivers/spi/omap3_spi.c
index a3ad056..651e46e 100644
--- a/drivers/spi/omap3_spi.c
+++ b/drivers/spi/omap3_spi.c
@@ -260,8 +260,9 @@ int omap3_spi_write(struct spi_slave *slave, unsigned int len, const void *txp,
}
/* wait to finish of transfer */
- while (!(readl(&ds->regs->channel[ds->slave.cs].chstat) &
- OMAP3_MCSPI_CHSTAT_EOT));
+ while ((readl(&ds->regs->channel[ds->slave.cs].chstat) &
+ (OMAP3_MCSPI_CHSTAT_EOT | OMAP3_MCSPI_CHSTAT_TXS)) !=
+ (OMAP3_MCSPI_CHSTAT_EOT | OMAP3_MCSPI_CHSTAT_TXS));
/* Disable the channel otherwise the next immediate RX will get affected */
omap3_spi_set_enable(ds,OMAP3_MCSPI_CHCTRL_DIS);
diff --git a/drivers/video/exynos_fb.c b/drivers/video/exynos_fb.c
index 00a0a11..e1e0d80 100644
--- a/drivers/video/exynos_fb.c
+++ b/drivers/video/exynos_fb.c
@@ -104,6 +104,13 @@ void __exynos_backlight_reset(void)
void exynos_backlight_reset(void)
__attribute__((weak, alias("__exynos_backlight_reset")));
+int __exynos_lcd_misc_init(vidinfo_t *vid)
+{
+ return 0;
+}
+int exynos_lcd_misc_init(vidinfo_t *vid)
+ __attribute__((weak, alias("__exynos_lcd_misc_init")));
+
static void lcd_panel_on(vidinfo_t *vid)
{
udelay(vid->init_delay);
@@ -281,10 +288,15 @@ void lcd_ctrl_init(void *lcdbase)
#ifdef CONFIG_OF_CONTROL
if (exynos_fimd_parse_dt(gd->fdt_blob))
debug("Can't get proper panel info\n");
+#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_mipi_dsi.c b/drivers/video/exynos_mipi_dsi.c
index 8bb8fea..7dd4652 100644
--- a/drivers/video/exynos_mipi_dsi.c
+++ b/drivers/video/exynos_mipi_dsi.c
@@ -9,6 +9,8 @@
#include <common.h>
#include <malloc.h>
+#include <fdtdec.h>
+#include <libfdt.h>
#include <linux/err.h>
#include <asm/arch/dsim.h>
#include <asm/arch/mipi_dsim.h>
@@ -22,7 +24,14 @@
#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;
+#ifdef CONFIG_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;
@@ -238,3 +247,90 @@ void exynos_set_dsim_platform_data(struct exynos_platform_mipi_dsim *pd)
dsim_pd = pd;
}
+
+#ifdef CONFIG_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