ARM: tegra: fix regulator_get() return value check
[linux-3.10.git] / arch / arm / mach-tegra / board-ardbeg-panel.c
index 264c63f..8e20fde 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * arch/arm/mach-tegra/board-ardbeg-panel.c
  *
- * Copyright (c) 2013, NVIDIA Corporation. All rights reserved
+ * Copyright (c) 2013, NVIDIA CORPORATION.  All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -28,6 +28,8 @@
 #include <linux/regulator/consumer.h>
 #include <linux/pwm_backlight.h>
 #include <linux/of.h>
+#include <linux/dma-contiguous.h>
+#include <linux/clk.h>
 
 #include <mach/irqs.h>
 #include <mach/dc.h>
 #include "board-panel.h"
 #include "common.h"
 #include "iomap.h"
-
-#ifdef CONFIG_ARCH_TEGRA_11x_SOC
-#include "tegra11_host1x_devices.h"
-#else
 #include "tegra12_host1x_devices.h"
-#endif
+#include "dvfs.h"
 
-#ifdef CONFIG_ARCH_TEGRA_11x_SOC
-#define DSI_PANEL_RST_GPIO      TEGRA_GPIO_PH3
-#define DSI_PANEL_BL_PWM_GPIO   TEGRA_GPIO_PH1
-#else
-/* TODO: update gpio for t124 ardbeg */
-#define DSI_PANEL_RST_GPIO      TEGRA_GPIO_PH3
-#define DSI_PANEL_BL_PWM_GPIO   TEGRA_GPIO_PH1
-#endif
 
 struct platform_device * __init ardbeg_host1x_init(void)
 {
        struct platform_device *pdev = NULL;
 
 #ifdef CONFIG_TEGRA_GRHOST
-       if (!of_have_populated_dt()) {
-#ifdef CONFIG_ARCH_TEGRA_11x_SOC
-               pdev = tegra11_register_host1x_devices();
-#else
+       if (!of_have_populated_dt())
                pdev = tegra12_register_host1x_devices();
-#endif
-       } else {
+       else
                pdev = to_platform_device(bus_find_device_by_name(
                        &platform_bus_type, NULL, "host1x"));
-       }
 
        if (!pdev) {
                pr_err("host1x devices registration failed\n");
@@ -79,16 +64,6 @@ struct platform_device * __init ardbeg_host1x_init(void)
        return pdev;
 }
 
-#ifdef CONFIG_TEGRA_DC
-
-/* HDMI Hotplug detection pin */
-#ifdef CONFIG_ARCH_TEGRA_11x_SOC
-#define ardbeg_hdmi_hpd        TEGRA_GPIO_PN7
-#else
-/* TODO: update for t124 ardbeg */
-#define ardbeg_hdmi_hpd        TEGRA_GPIO_PN7
-#endif
-
 /* hdmi related regulators */
 static struct regulator *ardbeg_hdmi_reg;
 static struct regulator *ardbeg_hdmi_pll;
@@ -139,6 +114,51 @@ static struct resource ardbeg_disp1_resources[] = {
        },
 };
 
+static struct resource ardbeg_disp1_edp_resources[] = {
+       {
+               .name   = "irq",
+               .start  = INT_DISPLAY_GENERAL,
+               .end    = INT_DISPLAY_GENERAL,
+               .flags  = IORESOURCE_IRQ,
+       },
+       {
+               .name   = "regs",
+               .start  = TEGRA_DISPLAY_BASE,
+               .end    = TEGRA_DISPLAY_BASE + TEGRA_DISPLAY_SIZE - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       {
+               .name   = "fbmem",
+               .start  = 0, /* Filled in by ardbeg_panel_init() */
+               .end    = 0, /* Filled in by ardbeg_panel_init() */
+               .flags  = IORESOURCE_MEM,
+       },
+       {
+               .name   = "mipi_cal",
+               .start  = TEGRA_MIPI_CAL_BASE,
+               .end    = TEGRA_MIPI_CAL_BASE + TEGRA_MIPI_CAL_SIZE - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       {
+               .name   = "sor",
+               .start  = TEGRA_SOR_BASE,
+               .end    = TEGRA_SOR_BASE + TEGRA_SOR_SIZE - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       {
+               .name   = "dpaux",
+               .start  = TEGRA_DPAUX_BASE,
+               .end    = TEGRA_DPAUX_BASE + TEGRA_DPAUX_SIZE - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       {
+               .name   = "irq_dp",
+               .start  = INT_DPAUX,
+               .end    = INT_DPAUX,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
 static struct resource ardbeg_disp2_resources[] = {
        {
                .name   = "irq",
@@ -179,7 +199,7 @@ static int ardbeg_hdmi_enable(struct device *dev)
        int ret;
        if (!ardbeg_hdmi_reg) {
                ardbeg_hdmi_reg = regulator_get(dev, "avdd_hdmi");
-               if (IS_ERR_OR_NULL(ardbeg_hdmi_reg)) {
+               if (IS_ERR(ardbeg_hdmi_reg)) {
                        pr_err("hdmi: couldn't get regulator avdd_hdmi\n");
                        ardbeg_hdmi_reg = NULL;
                        return PTR_ERR(ardbeg_hdmi_reg);
@@ -192,7 +212,7 @@ static int ardbeg_hdmi_enable(struct device *dev)
        }
        if (!ardbeg_hdmi_pll) {
                ardbeg_hdmi_pll = regulator_get(dev, "avdd_hdmi_pll");
-               if (IS_ERR_OR_NULL(ardbeg_hdmi_pll)) {
+               if (IS_ERR(ardbeg_hdmi_pll)) {
                        pr_err("hdmi: couldn't get regulator avdd_hdmi_pll\n");
                        ardbeg_hdmi_pll = NULL;
                        regulator_put(ardbeg_hdmi_reg);
@@ -243,23 +263,88 @@ static int ardbeg_hdmi_hotplug_init(struct device *dev)
                                __func__, PTR_ERR(ardbeg_hdmi_vddio));
                                ardbeg_hdmi_vddio = NULL;
                } else {
-                       regulator_enable(ardbeg_hdmi_vddio);
+                       return regulator_enable(ardbeg_hdmi_vddio);
                }
        }
 
        return 0;
 }
 
+struct tmds_config ardbeg_tmds_config[] = {
+       { /* 480p/576p / 25.2MHz/27MHz modes */
+       .pclk = 27000000,
+       .pll0 = 0x01003110,
+       .pll1 = 0x00300F00,
+       .pe_current = 0x08080808,
+       .drive_current = 0x2e2e2e2e,
+       .peak_current = 0x00000000,
+       },
+       { /* 720p / 74.25MHz modes */
+       .pclk = 74250000,
+       .pll0 =  0x01003310,
+       .pll1 = 0x10300F00,
+       .pe_current = 0x08080808,
+       .drive_current = 0x20202020,
+       .peak_current = 0x00000000,
+       },
+       { /* 1080p / 148.5MHz modes */
+       .pclk = 148500000,
+       .pll0 = 0x01003310,
+       .pll1 = 0x10300F00,
+       .pe_current = 0x08080808,
+       .drive_current = 0x20202020,
+       .peak_current = 0x00000000,
+       },
+       {
+       .pclk = INT_MAX,
+       .pll0 = 0x01003310,
+       .pll1 = 0x10300F00,
+       .pe_current = 0x08080808,
+       .drive_current = 0x3A353536, /* lane3 needs a slightly lower current */
+       .peak_current = 0x00000000,
+       },
+};
+
+struct tegra_hdmi_out ardbeg_hdmi_out = {
+       .tmds_config = ardbeg_tmds_config,
+       .n_tmds_config = ARRAY_SIZE(ardbeg_tmds_config),
+};
+
+
+#ifdef CONFIG_FRAMEBUFFER_CONSOLE
+static struct tegra_dc_mode hdmi_panel_modes[] = {
+       {
+               .pclk =                 KHZ2PICOS(25200),
+               .h_ref_to_sync =        1,
+               .v_ref_to_sync =        1,
+               .h_sync_width =         96,     /* hsync_len */
+               .v_sync_width =         2,      /* vsync_len */
+               .h_back_porch =         48,     /* left_margin */
+               .v_back_porch =         33,     /* upper_margin */
+               .h_active =             640,    /* xres */
+               .v_active =             480,    /* yres */
+               .h_front_porch =        16,     /* right_margin */
+               .v_front_porch =        10,     /* lower_margin */
+       },
+};
+#endif /* CONFIG_FRAMEBUFFER_CONSOLE */
+
 static struct tegra_dc_out ardbeg_disp2_out = {
        .type           = TEGRA_DC_OUT_HDMI,
        .flags          = TEGRA_DC_OUT_HOTPLUG_HIGH,
-       .parent_clk     = "pll_d2_out0",
+       .parent_clk     = "pll_d2",
 
        .dcc_bus        = 3,
        .hotplug_gpio   = ardbeg_hdmi_hpd,
+       .hdmi_out       = &ardbeg_hdmi_out,
 
        /* TODO: update max pclk to POR */
        .max_pixclock   = KHZ2PICOS(297000),
+#ifdef CONFIG_FRAMEBUFFER_CONSOLE
+       .modes = hdmi_panel_modes,
+       .n_modes = ARRAY_SIZE(hdmi_panel_modes),
+       .depth = 24,
+#endif /* CONFIG_FRAMEBUFFER_CONSOLE */
 
        .align          = TEGRA_DC_ALIGN_MSB,
        .order          = TEGRA_DC_ORDER_RED_BLUE,
@@ -327,21 +412,18 @@ static struct nvmap_platform_carveout ardbeg_carveouts[] = {
                .usage_mask     = NVMAP_HEAP_CARVEOUT_IRAM,
                .base           = TEGRA_IRAM_BASE + TEGRA_RESET_HANDLER_SIZE,
                .size           = TEGRA_IRAM_SIZE - TEGRA_RESET_HANDLER_SIZE,
-               .buddy_size     = 0, /* no buddy allocation for IRAM */
        },
        [1] = {
                .name           = "generic-0",
                .usage_mask     = NVMAP_HEAP_CARVEOUT_GENERIC,
                .base           = 0, /* Filled in by ardbeg_panel_init() */
                .size           = 0, /* Filled in by ardbeg_panel_init() */
-               .buddy_size     = SZ_32K,
        },
        [2] = {
                .name           = "vpr",
                .usage_mask     = NVMAP_HEAP_CARVEOUT_VPR,
                .base           = 0, /* Filled in by ardbeg_panel_init() */
                .size           = 0, /* Filled in by ardbeg_panel_init() */
-               .buddy_size     = SZ_32K,
        },
 };
 
@@ -406,15 +488,19 @@ static struct tegra_dc_sd_settings ardbeg_sd_settings = {
        .use_vpulse2 = true,
 };
 
-static void ardbeg_panel_select(void)
+/* can be called multiple times */
+static struct tegra_panel *ardbeg_panel_configure(struct board_info *board_out,
+       u8 *dsi_instance_out)
 {
        struct tegra_panel *panel = NULL;
-       struct board_info board;
        u8 dsi_instance;
+       struct board_info boardtmp;
 
-       tegra_get_display_board_info(&board);
+       if (!board_out)
+               board_out = &boardtmp;
+       tegra_get_display_board_info(board_out);
 
-       switch (board.board_id) {
+       switch (board_out->board_id) {
        case BOARD_E1639:
        case BOARD_E1813:
                panel = &dsi_s_wqxga_10_1;
@@ -425,12 +511,45 @@ static void ardbeg_panel_select(void)
                dsi_instance = DSI_INSTANCE_0;
                break;
        case BOARD_E1627:
-       /* fall through */
+               panel = &dsi_p_wuxga_10_1;
+               dsi_instance = DSI_INSTANCE_0;
+               break;
+       case BOARD_E1549:
+               panel = &dsi_lgd_wxga_7_0;
+               dsi_instance = DSI_INSTANCE_0;
+               break;
+       case BOARD_PM363:
+       case BOARD_E1824:
+               panel = &edp_a_1080p_14_0;
+               ardbeg_disp1_out.type = TEGRA_DC_OUT_DP;
+               ardbeg_disp1_device.resource = ardbeg_disp1_edp_resources;
+               ardbeg_disp1_device.num_resources =
+                       ARRAY_SIZE(ardbeg_disp1_edp_resources);
+               break;
+       case BOARD_PM366:
+               panel = &lvds_c_1366_14;
+               ardbeg_disp1_out.type = TEGRA_DC_OUT_LVDS;
+               ardbeg_disp1_device.resource = ardbeg_disp1_edp_resources;
+               ardbeg_disp1_device.num_resources =
+                       ARRAY_SIZE(ardbeg_disp1_edp_resources);
+               break;
        default:
                panel = &dsi_p_wuxga_10_1;
                dsi_instance = DSI_INSTANCE_0;
                break;
        }
+       if (dsi_instance_out)
+               *dsi_instance_out = dsi_instance;
+       return panel;
+}
+
+static void ardbeg_panel_select(void)
+{
+       struct tegra_panel *panel = NULL;
+       struct board_info board;
+       u8 dsi_instance;
+
+       panel = ardbeg_panel_configure(&board, &dsi_instance);
 
        if (panel) {
                if (panel->init_sd_settings)
@@ -438,11 +557,15 @@ static void ardbeg_panel_select(void)
 
                if (panel->init_dc_out) {
                        panel->init_dc_out(&ardbeg_disp1_out);
-                       ardbeg_disp1_out.dsi->dsi_instance = dsi_instance;
-                       ardbeg_disp1_out.dsi->dsi_panel_rst_gpio =
-                               DSI_PANEL_RST_GPIO;
-                       ardbeg_disp1_out.dsi->dsi_panel_bl_pwm_gpio =
-                               DSI_PANEL_BL_PWM_GPIO;
+                       if (ardbeg_disp1_out.type == TEGRA_DC_OUT_DSI) {
+                               ardbeg_disp1_out.dsi->dsi_instance =
+                                       dsi_instance;
+                               ardbeg_disp1_out.dsi->dsi_panel_rst_gpio =
+                                       DSI_PANEL_RST_GPIO;
+                               ardbeg_disp1_out.dsi->dsi_panel_bl_pwm_gpio =
+                                       DSI_PANEL_BL_PWM_GPIO;
+                               ardbeg_disp1_out.dsi->te_gpio = TEGRA_GPIO_PR6;
+                       }
                }
 
                if (panel->init_fb_data)
@@ -454,8 +577,11 @@ static void ardbeg_panel_select(void)
                if (panel->set_disp_device)
                        panel->set_disp_device(&ardbeg_disp1_device);
 
-               tegra_dsi_resources_init(dsi_instance, ardbeg_disp1_resources,
-                       ARRAY_SIZE(ardbeg_disp1_resources));
+               if (ardbeg_disp1_out.type == TEGRA_DC_OUT_DSI) {
+                       tegra_dsi_resources_init(dsi_instance,
+                               ardbeg_disp1_resources,
+                               ARRAY_SIZE(ardbeg_disp1_resources));
+               }
 
                if (panel->register_bl_dev)
                        panel->register_bl_dev();
@@ -480,6 +606,15 @@ int __init ardbeg_panel_init(void)
        ardbeg_carveouts[1].size = tegra_carveout_size;
        ardbeg_carveouts[2].base = tegra_vpr_start;
        ardbeg_carveouts[2].size = tegra_vpr_size;
+#ifdef CONFIG_NVMAP_USE_CMA_FOR_CARVEOUT
+       carveout_linear_set(&tegra_generic_cma_dev);
+       ardbeg_carveouts[1].cma_dev = &tegra_generic_cma_dev;
+       ardbeg_carveouts[1].resize = false;
+       carveout_linear_set(&tegra_vpr_cma_dev);
+       ardbeg_carveouts[2].cma_dev = &tegra_vpr_cma_dev;
+       ardbeg_carveouts[2].resize = true;
+       ardbeg_carveouts[2].cma_chunk_size = SZ_32M;
+#endif
 
        err = platform_device_register(&ardbeg_nvmap_device);
        if (err) {
@@ -500,15 +635,13 @@ int __init ardbeg_panel_init(void)
        res->end = tegra_fb_start + tegra_fb_size - 1;
 
        /* Copy the bootloader fb to the fb. */
-       __tegra_move_framebuffer(&ardbeg_nvmap_device,
-               tegra_fb_start, tegra_bootloader_fb_start,
-                       min(tegra_fb_size, tegra_bootloader_fb_size));
-
-       res = platform_get_resource_byname(&ardbeg_disp2_device,
-                                        IORESOURCE_MEM, "fbmem");
-
-       res->start = tegra_fb2_start;
-       res->end = tegra_fb2_start + tegra_fb2_size - 1;
+       if (tegra_bootloader_fb_size)
+               __tegra_move_framebuffer(&ardbeg_nvmap_device,
+                               tegra_fb_start, tegra_bootloader_fb_start,
+                               min(tegra_fb_size, tegra_bootloader_fb_size));
+       else
+               __tegra_clear_framebuffer(&ardbeg_nvmap_device,
+                                         tegra_fb_start, tegra_fb_size);
 
        ardbeg_disp1_device.dev.parent = &phost1x->dev;
        err = platform_device_register(&ardbeg_disp1_device);
@@ -517,12 +650,9 @@ int __init ardbeg_panel_init(void)
                return err;
        }
 
-       ardbeg_disp2_device.dev.parent = &phost1x->dev;
-       err = platform_device_register(&ardbeg_disp2_device);
-       if (err) {
-               pr_err("disp2 device registration failed\n");
+       err = tegra_init_hdmi(&ardbeg_disp2_device, phost1x);
+       if (err)
                return err;
-       }
 
 #ifdef CONFIG_TEGRA_NVAVP
        nvavp_device.dev.parent = &phost1x->dev;
@@ -534,12 +664,54 @@ int __init ardbeg_panel_init(void)
 #endif
        return err;
 }
-#else
-int __init ardbeg_panel_init(void)
+
+int __init ardbeg_display_init(void)
 {
-       if (ardbeg_host1x_init())
-               return 0;
+       struct clk *disp1_clk = clk_get_sys("tegradc.0", NULL);
+       struct clk *disp2_clk = clk_get_sys("tegradc.1", NULL);
+       struct tegra_panel *panel;
+       struct board_info board;
+       long disp1_rate;
+       long disp2_rate;
+
+       if (WARN_ON(IS_ERR(disp1_clk))) {
+               if (disp2_clk && !IS_ERR(disp2_clk))
+                       clk_put(disp2_clk);
+               return PTR_ERR(disp1_clk);
+       }
+
+       if (WARN_ON(IS_ERR(disp2_clk))) {
+               clk_put(disp1_clk);
+               return PTR_ERR(disp1_clk);
+       }
+
+       panel = ardbeg_panel_configure(&board, NULL);
+
+       if (panel && panel->init_dc_out) {
+               panel->init_dc_out(&ardbeg_disp1_out);
+               if (ardbeg_disp1_out.n_modes && ardbeg_disp1_out.modes)
+                       disp1_rate = ardbeg_disp1_out.modes[0].pclk;
+       } else {
+               disp1_rate = 0;
+               if (!panel || !panel->init_dc_out)
+                       printk(KERN_ERR "disp1 panel output not specified!\n");
+       }
+
+       printk(KERN_DEBUG "disp1 pclk=%ld\n", disp1_rate);
+       if (disp1_rate)
+               tegra_dvfs_resolve_override(disp1_clk, disp1_rate);
+
+
+       /* set up disp2 */
+       if (ardbeg_disp2_out.max_pixclock)
+               disp2_rate = PICOS2KHZ(ardbeg_disp2_out.max_pixclock) * 1000;
        else
-               return -EINVAL;
+               disp2_rate = 297000000; /* HDMI 4K */
+       printk(KERN_DEBUG "disp2 pclk=%ld\n", disp2_rate);
+       if (disp2_rate)
+               tegra_dvfs_resolve_override(disp2_clk, disp2_rate);
+
+       clk_put(disp1_clk);
+       clk_put(disp2_clk);
+       return 0;
 }
-#endif