arm: tegra: tegratab: display controller and panel with DT
Min-wuk Lee [Mon, 20 May 2013 08:32:03 +0000 (17:32 +0900)]
Instead of Disp0 and Disp1 platform data delivery by
platform_device_register from the board file, this change
will parse these data from device tree of display controller
node and panel node in tegratab dts.
Separate lcd device data generating driver with device tree
info is prepared.

Bug 1240921

Change-Id: I1f8c75822612c1611a7c0c2b716ebd4d65277109
Signed-off-by: Min-wuk Lee <mlee@nvidia.com>
Reviewed-on: http://git-master/r/240021
(cherry picked from commit 8c36af0d1fdc01814b3d4d939d149536368fb5ca)
Reviewed-on: http://git-master/r/289668
Reviewed-by: Gabby Lee <galee@nvidia.com>
Tested-by: Gabby Lee <galee@nvidia.com>

arch/arm/mach-tegra/board-tegratab-panel.c
arch/arm/mach-tegra/board-tegratab.c
drivers/video/tegra/Makefile
drivers/video/tegra/of_lcd_device_data/Makefile [new file with mode: 0644]
drivers/video/tegra/of_lcd_device_data/tegratab_lcd_dev_data.c [new file with mode: 0644]

index dda6227..a9aabba 100644 (file)
@@ -428,6 +428,21 @@ static void tegratab_panel_select(void)
        }
 
 }
+
+static void fb2_copy_or_clear(void)
+{
+       /*
+        * If the bootloader fb2 is valid, copy it to the fb2, or else
+        * clear fb2 to avoid garbage on dispaly2.
+        */
+       if (tegra_bootloader_fb2_size)
+               tegra_move_framebuffer(tegra_fb2_start,
+                       tegra_bootloader_fb2_start,
+                       min(tegra_fb2_size, tegra_bootloader_fb2_size));
+       else
+               tegra_clear_framebuffer(tegra_fb2_start, tegra_fb2_size);
+}
+
 int __init tegratab_panel_init(void)
 {
        int err = 0;
@@ -466,26 +481,47 @@ int __init tegratab_panel_init(void)
        gpio_request(tegratab_hdmi_hpd, "hdmi_hpd");
        gpio_direction_input(tegratab_hdmi_hpd);
 
-       res = platform_get_resource_byname(&tegratab_disp1_device,
+       if (!of_have_populated_dt()) {
+               res = platform_get_resource_byname(&tegratab_disp1_device,
                                         IORESOURCE_MEM, "fbmem");
-       res->start = tegra_fb_start;
-       res->end = tegra_fb_start + tegra_fb_size - 1;
+               res->start = tegra_fb_start;
+               res->end = tegra_fb_start + tegra_fb_size - 1;
+       }
 
        /* Copy the bootloader fb to the fb. */
        __tegra_move_framebuffer(&tegratab_nvmap_device,
                tegra_fb_start, tegra_bootloader_fb_start,
                        min(tegra_fb_size, tegra_bootloader_fb_size));
 
-       tegratab_disp1_device.dev.parent = &phost1x->dev;
-       err = platform_device_register(&tegratab_disp1_device);
-       if (err) {
-               pr_err("disp1 device registration failed\n");
-               return err;
-       }
+       if (!of_have_populated_dt()) {
+               fb2_copy_or_clear();
+               res = platform_get_resource_byname(&tegratab_disp2_device,
+                       IORESOURCE_MEM, "fbmem");
+               res->start = tegra_fb2_start;
+               res->end = tegra_fb2_start + tegra_fb2_size - 1;
+
+               tegratab_disp1_device.dev.parent = &phost1x->dev;
+               err = platform_device_register(&tegratab_disp1_device);
+               if (err) {
+                       pr_err("disp1 device registration failed\n");
+                       return err;
+               }
 
-       err = tegra_init_hdmi(&tegratab_disp2_device, phost1x);
-       if (err)
-               return err;
+               tegratab_disp2_device.dev.parent = &phost1x->dev;
+               err = platform_device_register(&tegratab_disp2_device);
+               if (err) {
+                       pr_err("disp2 device registration failed\n");
+                       return err;
+               }
+       } else {
+#ifdef CONFIG_OF
+               struct device_node *hdmi_node = NULL;
+
+               hdmi_node = of_find_node_by_path("/host1x/hdmi");
+               if (hdmi_node && of_device_is_available(hdmi_node))
+#endif
+                       fb2_copy_or_clear();
+       }
 
 #ifdef CONFIG_TEGRA_NVAVP
        nvavp_device.dev.parent = &phost1x->dev;
index 9dab04f..021fedf 100644 (file)
@@ -66,6 +66,7 @@
 #include <mach/gpio-tegra.h>
 #include <mach/tegra_fiq_debugger.h>
 #include <mach/hardware.h>
+#include <mach/dc.h>
 
 #include "board-touch-raydium.h"
 #include "board.h"
 #include "common.h"
 #include "tegra-board-id.h"
 
+#ifdef CONFIG_USE_OF
+struct tegra_dc_platform_data tegratab_dc0_platform_data;
+struct tegra_dc_platform_data tegratab_dc1_platform_data;
+#endif
+
 #if defined CONFIG_TI_ST || defined CONFIG_TI_ST_MODULE
 struct ti_st_plat_data tegratab_wilink_pdata = {
        .nshutdown_gpio = TEGRA_GPIO_PQ7,
@@ -178,6 +184,7 @@ static __initdata struct tegra_clk_init_table P1640_wifi_clk_init_table[] = {
        { NULL,         NULL,           0,              0},
 };
 
+#ifdef CONFIG_USE_OF
 static struct tegra_i2c_platform_data tegratab_i2c1_platform_data = {
        .adapter_nr     = 0,
        .bus_count      = 1,
@@ -223,6 +230,7 @@ static struct tegra_i2c_platform_data tegratab_i2c5_platform_data = {
        .sda_gpio               = {TEGRA_GPIO_I2C5_SDA, 0},
        .arb_recovery = arb_lost_recovery,
 };
+#endif
 
 static struct i2c_board_info __initdata rt5640_board_info = {
        I2C_BOARD_INFO("rt5640", 0x1c),
@@ -727,6 +735,7 @@ static void __init tegra_tegratab_early_init(void)
 #endif
 }
 
+#ifdef CONFIG_USE_OF
 struct of_dev_auxdata tegratab_auxdata_lookup[] __initdata = {
        OF_DEV_AUXDATA("nvidia,tegra114-host1x", TEGRA_HOST1X_BASE, "host1x",
                                NULL),
@@ -742,6 +751,10 @@ struct of_dev_auxdata tegratab_auxdata_lookup[] __initdata = {
                                NULL),
        OF_DEV_AUXDATA("nvidia,tegra114-tsec", TEGRA_TSEC_BASE, "tsec",
                                NULL),
+       OF_DEV_AUXDATA("nvidia,tegra114-dc", TEGRA_DISPLAY_BASE, "tegradc.0",
+               &tegratab_dc0_platform_data),
+       OF_DEV_AUXDATA("nvidia,tegra114-dc", TEGRA_DISPLAY2_BASE, "tegradc.1",
+               &tegratab_dc1_platform_data),
        OF_DEV_AUXDATA("nvidia,tegra114-i2c", 0x7000c000, "tegra11-i2c.0",
                &tegratab_i2c1_platform_data),
        OF_DEV_AUXDATA("nvidia,tegra114-i2c", 0x7000c400, "tegra11-i2c.1",
@@ -754,6 +767,7 @@ struct of_dev_auxdata tegratab_auxdata_lookup[] __initdata = {
                &tegratab_i2c5_platform_data),
        {},
 };
+#endif
 
 static void __init tegra_tegratab_late_init(void)
 {
@@ -804,6 +818,16 @@ static void __init tegra_tegratab_dt_init(void)
        tegra_tegratab_early_init();
 
 #ifdef CONFIG_USE_OF
+#if defined(CONFIG_NVMAP_CONVERT_CARVEOUT_TO_IOVMM)
+       tegratab_dc0_platform_data.of_data.fb_size = SZ_16M + SZ_2M;
+       tegratab_dc1_platform_data.of_data.fb_size = SZ_16M;
+#else
+       tegratab_dc0_platform_data.of_data.fb_size = SZ_16M + SZ_2M;
+       tegratab_dc1_platform_data.of_data.fb_size = SZ_4M;
+#endif
+       tegratab_dc0_platform_data.of_data.fb_start = tegra_fb_start;
+       tegratab_dc1_platform_data.of_data.fb_start = tegra_fb2_start;
+
        of_platform_populate(NULL, of_default_bus_match_table,
                tegratab_auxdata_lookup, &platform_bus);
 #endif
index 1db5abc..019354b 100644 (file)
@@ -3,6 +3,7 @@ subdir-ccflags-y := -Werror
 EXTRA_CFLAGS += -Idrivers/video/tegra/host
 obj-$(CONFIG_TEGRA_GRHOST) += host/
 obj-$(CONFIG_TEGRA_DC) += dc/
+obj-$(CONFIG_USE_OF) += of_lcd_device_data/
 obj-$(CONFIG_FB_TEGRA) += fb.o
 obj-$(CONFIG_TEGRA_NVMAP) += nvmap/
 obj-$(CONFIG_TEGRA_CAMERA) += camera/
diff --git a/drivers/video/tegra/of_lcd_device_data/Makefile b/drivers/video/tegra/of_lcd_device_data/Makefile
new file mode 100644 (file)
index 0000000..c5541ad
--- /dev/null
@@ -0,0 +1,2 @@
+GCOV_PROFILE := y
+obj-${CONFIG_MACH_TEGRATAB}            += tegratab_lcd_dev_data.o
diff --git a/drivers/video/tegra/of_lcd_device_data/tegratab_lcd_dev_data.c b/drivers/video/tegra/of_lcd_device_data/tegratab_lcd_dev_data.c
new file mode 100644 (file)
index 0000000..60a7068
--- /dev/null
@@ -0,0 +1,228 @@
+/*
+ * Copyright (c) 2013, NVIDIA CORPORATION, All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/err.h>
+#include <linux/device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+#include <mach/dc.h>
+#include <linux/delay.h>
+
+static struct platform_driver tegratab_lcd_devdata_gen_drv;
+static struct device_node *gp_node;
+
+/* LCDs list */
+struct of_tegra_lcd_devdata tegratab_lgd_lcd;
+
+#define LGD_LCD_REGULATORS_COUNT               3
+
+static bool lgd_lcd_reg_requested;
+static struct regulator *lgd_lcd_regs[LGD_LCD_REGULATORS_COUNT];
+
+static struct tegra_dsi_cmd lgd_wxga_7_0_init_cmd[] = {
+       DSI_CMD_SHORT(0x15, 0x01, 0x0),
+       DSI_DLY_MS(20),
+       DSI_CMD_SHORT(0x15, 0xAE, 0x0B),
+       DSI_CMD_SHORT(0x15, 0xEE, 0xEA),
+       DSI_CMD_SHORT(0x15, 0xEF, 0x5F),
+       DSI_CMD_SHORT(0x15, 0xF2, 0x68),
+       DSI_CMD_SHORT(0x15, 0xEE, 0x0),
+       DSI_CMD_SHORT(0x15, 0xEF, 0x0),
+};
+
+static struct tegra_dsi_cmd lgd_wxga_7_0_late_resume_cmd[] = {
+       DSI_CMD_SHORT(0x15, 0x10, 0x0),
+       DSI_DLY_MS(120),
+};
+
+static struct tegra_dsi_cmd lgd_wxga_7_0_early_suspend_cmd[] = {
+       DSI_CMD_SHORT(0x15, 0x11, 0x0),
+       DSI_DLY_MS(160),
+};
+
+static struct tegra_dsi_cmd lgd_wxga_7_0_suspend_cmd[] = {
+       DSI_CMD_SHORT(0x15, 0x11, 0x0),
+       DSI_DLY_MS(160),
+};
+
+static int lgd_lcd_regulators_get(struct device *dev)
+{
+       int err = 0;
+       struct property *prop;
+       const char *regulator;
+       int reg_i = 0;
+
+       if (lgd_lcd_reg_requested)
+               return 0;
+       of_property_for_each_string(gp_node, "nvidia,regulators",
+                       prop, regulator) {
+               lgd_lcd_regs[reg_i] =
+                       regulator_get(dev, regulator);
+               if (IS_ERR_OR_NULL(lgd_lcd_regs[reg_i])) {
+                       err = PTR_ERR(lgd_lcd_regs[reg_i]);
+                       lgd_lcd_regs[reg_i] = NULL;
+                       return err;
+               } else
+                       reg_i++;
+       }
+       lgd_lcd_reg_requested = true;
+       return 0;
+}
+
+static int lgd_wxga_7_0_enable(struct device *dev)
+{
+       int err = 0;
+       int reg_i;
+
+       err = lgd_lcd_regulators_get(dev);
+       if (err < 0) {
+               pr_err("lgd lcd regulator get failed\n");
+               goto fail;
+       }
+
+       msleep(20);
+       for (reg_i = 0; reg_i < LGD_LCD_REGULATORS_COUNT; reg_i++) {
+               if (lgd_lcd_regs[reg_i]) {
+                       err = regulator_enable(lgd_lcd_regs[reg_i]);
+                       if (err < 0) {
+                               pr_err("%s: reg en failed\n", __func__);
+                               goto fail;
+                       }
+               }
+               if (reg_i == 0)
+                       msleep(150);
+               else
+                       msleep(100);
+       }
+       return 0;
+fail:
+       return err;
+}
+
+static int lgd_wxga_7_0_disable(void)
+{
+       int reg_i;
+
+       for (reg_i = 0; reg_i < LGD_LCD_REGULATORS_COUNT; reg_i++)
+               regulator_disable(
+                       lgd_lcd_regs[LGD_LCD_REGULATORS_COUNT-reg_i-1]);
+
+       return 0;
+}
+
+static int lgd_wxga_7_0_postsuspend(void)
+{
+       return 0;
+}
+
+static void tegratab_lgd_lcd_devdata(struct of_tegra_lcd_devdata *lcd_dev_data)
+{
+       lcd_dev_data->enable = lgd_wxga_7_0_enable;
+       lcd_dev_data->disable = lgd_wxga_7_0_disable;
+       lcd_dev_data->postsuspend = lgd_wxga_7_0_postsuspend;
+       lcd_dev_data->dsi_init_cmd =
+               lgd_wxga_7_0_init_cmd;
+       lcd_dev_data->n_init_cmd =
+               ARRAY_SIZE(lgd_wxga_7_0_init_cmd);
+       lcd_dev_data->dsi_early_suspend_cmd =
+               lgd_wxga_7_0_early_suspend_cmd;
+       lcd_dev_data->n_early_suspend_cmd =
+               ARRAY_SIZE(lgd_wxga_7_0_early_suspend_cmd);
+       lcd_dev_data->dsi_late_resume_cmd =
+               lgd_wxga_7_0_late_resume_cmd;
+       lcd_dev_data->n_late_resume_cmd =
+               ARRAY_SIZE(lgd_wxga_7_0_late_resume_cmd);
+       lcd_dev_data->dsi_suspend_cmd =
+               lgd_wxga_7_0_suspend_cmd;
+       lcd_dev_data->n_suspend_cmd =
+               ARRAY_SIZE(lgd_wxga_7_0_suspend_cmd);
+}
+
+static int tegra_lcd_match_in_dc(struct device *dev, void *data)
+{
+       struct device_node *dn = data;
+
+       return (dev->of_node == dn) ? 1 : 0;
+}
+
+struct device *tegratab_lcd_devdata_to_dc(struct device_node *dn)
+{
+       struct device *dev;
+       dev = driver_find_device(&tegratab_lcd_devdata_gen_drv.driver,
+               NULL, dn, tegra_lcd_match_in_dc);
+       if (!dev)
+               return NULL;
+       return dev;
+}
+
+static int tegratab_lcd_devdata_gen_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct device_node *np = pdev->dev.of_node;
+       struct of_tegra_lcd_devdata *lcd_devdata;
+
+       gp_node = np;
+
+       lcd_devdata = devm_kzalloc(dev, sizeof(*lcd_devdata), GFP_KERNEL);
+       if (!lcd_devdata)
+               return -ENOMEM;
+
+
+       if (of_find_compatible_node(NULL, NULL, "lgd,tegratab")) {
+               tegratab_lgd_lcd_devdata(&tegratab_lgd_lcd);
+               memcpy(lcd_devdata, &tegratab_lgd_lcd,
+                               sizeof(struct of_tegra_lcd_devdata));
+       }
+
+       platform_set_drvdata(pdev, lcd_devdata);
+       lcd_devdata_to_dc_set_callback(tegratab_lcd_devdata_to_dc);
+       return 0;
+}
+
+static int tegratab_lcd_devdata_gen_remove(struct platform_device *pdev)
+{
+       return 0;
+}
+
+static struct of_device_id tegratab_lcd_of_match[] = {
+       { .compatible = "lgd,tegratab", },
+       { },
+};
+
+static struct platform_driver tegratab_lcd_devdata_gen_drv = {
+       .probe = tegratab_lcd_devdata_gen_probe,
+       .remove = tegratab_lcd_devdata_gen_remove,
+       .driver = {
+               .owner = THIS_MODULE,
+               .name = "of_tegratab_lcd_devdata_generate",
+               .of_match_table = tegratab_lcd_of_match,
+       },
+};
+
+int __init of_tegratab_lcd_devdata_init(void)
+{
+       return platform_driver_register(&tegratab_lcd_devdata_gen_drv);
+}
+
+void __exit of_tegratab_lcd_devdata_exit(void)
+{
+       platform_driver_unregister(&tegratab_lcd_devdata_gen_drv);
+}
+
+subsys_initcall(of_tegratab_lcd_devdata_init);
+module_exit(of_tegratab_lcd_devdata_exit);
+MODULE_DESCRIPTION("tegratab lcd devdata generate driver with device tree info");