summaryrefslogtreecommitdiff
path: root/arch/arm/mach-tegra/board-apalis-tk1-panel.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-tegra/board-apalis-tk1-panel.c')
-rw-r--r--arch/arm/mach-tegra/board-apalis-tk1-panel.c804
1 files changed, 804 insertions, 0 deletions
diff --git a/arch/arm/mach-tegra/board-apalis-tk1-panel.c b/arch/arm/mach-tegra/board-apalis-tk1-panel.c
new file mode 100644
index 000000000000..7e95326d75a8
--- /dev/null
+++ b/arch/arm/mach-tegra/board-apalis-tk1-panel.c
@@ -0,0 +1,804 @@
+/*
+ * arch/arm/mach-tegra/board-apalis-tk1-panel.c
+ *
+ * Copyright (c) 2016, Toradex AG. 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+#include <linux/ioport.h>
+#include <linux/fb.h>
+#include <linux/nvmap.h>
+#include <linux/nvhost.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/regulator/consumer.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/dma-contiguous.h>
+#include <linux/clk.h>
+#include <linux/dma-mapping.h>
+
+#include <mach/irqs.h>
+#include <mach/dc.h>
+#include <mach/io_dpd.h>
+
+#include "board.h"
+#include "tegra-board-id.h"
+#include "devices.h"
+#include "gpio-names.h"
+#include "board-apalis-tk1.h"
+#include "board-panel.h"
+#include "common.h"
+#include "iomap.h"
+#include "tegra12_host1x_devices.h"
+#include "dvfs.h"
+
+struct platform_device *__init apalis_tk1_host1x_init(void)
+{
+ struct platform_device *pdev = NULL;
+
+#ifdef CONFIG_TEGRA_GRHOST
+ if (!of_have_populated_dt())
+ pdev = tegra12_register_host1x_devices();
+ else
+ pdev =
+ to_platform_device(bus_find_device_by_name
+ (&platform_bus_type, NULL, "host1x"));
+
+ if (!pdev) {
+ pr_err("host1x devices registration failed\n");
+ return NULL;
+ }
+#endif
+ return pdev;
+}
+
+/* hdmi related regulators */
+static struct regulator *apalis_tk1_hdmi_reg;
+static struct regulator *apalis_tk1_hdmi_pll;
+static struct regulator *apalis_tk1_hdmi_vddio;
+
+#ifndef CONFIG_TEGRA_HDMI_PRIMARY
+static struct resource apalis_tk1_disp1_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 apalis_tk1_panel_init() */
+ .end = 0, /* Filled in by apalis_tk1_panel_init() */
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .name = "ganged_dsia_regs",
+ .start = 0, /* Filled in the panel file by init_resources() */
+ .end = 0, /* Filled in the panel file by init_resources() */
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .name = "ganged_dsib_regs",
+ .start = 0, /* Filled in the panel file by init_resources() */
+ .end = 0, /* Filled in the panel file by init_resources() */
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .name = "dsi_regs",
+ .start = 0, /* Filled in the panel file by init_resources() */
+ .end = 0, /* Filled in the panel file by init_resources() */
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .name = "mipi_cal",
+ .start = TEGRA_MIPI_CAL_BASE,
+ .end = TEGRA_MIPI_CAL_BASE + TEGRA_MIPI_CAL_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static struct resource apalis_tk1_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 apalis_tk1_panel_init() */
+ .end = 0, /* Filled in by apalis_tk1_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,
+ },
+};
+#endif
+
+static struct resource apalis_tk1_disp2_resources[] = {
+ {
+ .name = "irq",
+#ifndef CONFIG_TEGRA_HDMI_PRIMARY
+ .start = INT_DISPLAY_B_GENERAL,
+ .end = INT_DISPLAY_B_GENERAL,
+#else
+ .start = INT_DISPLAY_GENERAL,
+ .end = INT_DISPLAY_GENERAL,
+#endif
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "regs",
+#ifndef CONFIG_TEGRA_HDMI_PRIMARY
+ .start = TEGRA_DISPLAY2_BASE,
+ .end = TEGRA_DISPLAY2_BASE + TEGRA_DISPLAY2_SIZE - 1,
+#else
+ .start = TEGRA_DISPLAY_BASE,
+ .end = TEGRA_DISPLAY_BASE + TEGRA_DISPLAY_SIZE - 1,
+#endif
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .name = "fbmem",
+ .start = 0, /* Filled in by apalis_tk1_panel_init() */
+ .end = 0, /* Filled in by apalis_tk1_panel_init() */
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .name = "hdmi_regs",
+ .start = TEGRA_HDMI_BASE,
+ .end = TEGRA_HDMI_BASE + TEGRA_HDMI_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+#ifndef CONFIG_TEGRA_HDMI_PRIMARY
+static struct tegra_dc_sd_settings sd_settings;
+
+static struct tegra_dc_mode apalis_tk1_lvds_panel_modes[] = {
+ {
+ .pclk = 27000000,
+ .h_ref_to_sync = 1,
+ .v_ref_to_sync = 1,
+ .h_sync_width = 32,
+ .v_sync_width = 5,
+ .h_back_porch = 20,
+ .v_back_porch = 12,
+ .h_active = 1366,
+ .v_active = 768,
+ .h_front_porch = 48,
+ .v_front_porch = 3,
+ },
+};
+
+static struct tegra_dc_out_pin lvds_out_pins[] = {
+ {
+ .name = TEGRA_DC_OUT_PIN_H_SYNC,
+ .pol = TEGRA_DC_OUT_PIN_POL_LOW,
+ },
+ {
+ .name = TEGRA_DC_OUT_PIN_V_SYNC,
+ .pol = TEGRA_DC_OUT_PIN_POL_LOW,
+ },
+ {
+ .name = TEGRA_DC_OUT_PIN_PIXEL_CLOCK,
+ .pol = TEGRA_DC_OUT_PIN_POL_HIGH,
+ },
+ {
+ .name = TEGRA_DC_OUT_PIN_DATA_ENABLE,
+ .pol = TEGRA_DC_OUT_PIN_POL_HIGH,
+ },
+};
+
+static struct tegra_dc_out apalis_tk1_disp1_out = {
+ .align = TEGRA_DC_ALIGN_MSB,
+ .order = TEGRA_DC_ORDER_RED_BLUE,
+ .flags = TEGRA_DC_OUT_CONTINUOUS_MODE,
+ .type = TEGRA_DC_OUT_LVDS,
+ .modes = apalis_tk1_lvds_panel_modes,
+ .n_modes = ARRAY_SIZE(apalis_tk1_lvds_panel_modes),
+ .out_pins = lvds_out_pins,
+ .n_out_pins = ARRAY_SIZE(lvds_out_pins),
+};
+#endif
+
+static int apalis_tk1_hdmi_enable(struct device *dev)
+{
+ int ret;
+ if (!apalis_tk1_hdmi_reg) {
+ apalis_tk1_hdmi_reg = regulator_get(dev, "avdd_hdmi");
+ if (IS_ERR(apalis_tk1_hdmi_reg)) {
+ pr_err("hdmi: couldn't get regulator avdd_hdmi\n");
+ apalis_tk1_hdmi_reg = NULL;
+ return PTR_ERR(apalis_tk1_hdmi_reg);
+ }
+ }
+ ret = regulator_enable(apalis_tk1_hdmi_reg);
+ if (ret < 0) {
+ pr_err("hdmi: couldn't enable regulator avdd_hdmi\n");
+ return ret;
+ }
+ if (!apalis_tk1_hdmi_pll) {
+ apalis_tk1_hdmi_pll = regulator_get(dev, "avdd_hdmi_pll");
+ if (IS_ERR(apalis_tk1_hdmi_pll)) {
+ pr_err("hdmi: couldn't get regulator avdd_hdmi_pll\n");
+ apalis_tk1_hdmi_pll = NULL;
+ regulator_put(apalis_tk1_hdmi_reg);
+ apalis_tk1_hdmi_reg = NULL;
+ return PTR_ERR(apalis_tk1_hdmi_pll);
+ }
+ }
+ ret = regulator_enable(apalis_tk1_hdmi_pll);
+ if (ret < 0) {
+ pr_err("hdmi: couldn't enable regulator avdd_hdmi_pll\n");
+ return ret;
+ }
+ return 0;
+}
+
+static int apalis_tk1_hdmi_disable(void)
+{
+ if (apalis_tk1_hdmi_reg) {
+ regulator_disable(apalis_tk1_hdmi_reg);
+ regulator_put(apalis_tk1_hdmi_reg);
+ apalis_tk1_hdmi_reg = NULL;
+ }
+
+ if (apalis_tk1_hdmi_pll) {
+ regulator_disable(apalis_tk1_hdmi_pll);
+ regulator_put(apalis_tk1_hdmi_pll);
+ apalis_tk1_hdmi_pll = NULL;
+ }
+ return 0;
+}
+
+static int apalis_tk1_hdmi_postsuspend(void)
+{
+ if (apalis_tk1_hdmi_vddio) {
+ regulator_disable(apalis_tk1_hdmi_vddio);
+ regulator_put(apalis_tk1_hdmi_vddio);
+ apalis_tk1_hdmi_vddio = NULL;
+ }
+ return 0;
+}
+
+static int apalis_tk1_hdmi_hotplug_init(struct device *dev)
+{
+ if (!apalis_tk1_hdmi_vddio) {
+ apalis_tk1_hdmi_vddio = regulator_get(dev, "vdd_hdmi_5v0");
+ if (WARN_ON(IS_ERR(apalis_tk1_hdmi_vddio))) {
+ pr_err("%s: couldn't get regulator vdd_hdmi_5v0: %ld\n",
+ __func__, PTR_ERR(apalis_tk1_hdmi_vddio));
+ apalis_tk1_hdmi_vddio = NULL;
+ } else {
+ return regulator_enable(apalis_tk1_hdmi_vddio);
+ }
+ }
+
+ return 0;
+}
+
+struct tmds_config apalis_tk1_tmds_config[] = {
+ { /* 480p/576p / 25.2MHz/27MHz modes */
+ .version = MKDEV(1, 0),
+ .pclk = 27000000,
+ .pll0 = 0x01003010,
+ .pll1 = 0x00301B00,
+ .pe_current = 0x00000000,
+ .drive_current = 0x1F1F1F1F,
+ .peak_current = 0x03030303,
+ .pad_ctls0_mask = 0xfffff0ff,
+ .pad_ctls0_setting = 0x00000400, /* BG_VREF_LEVEL */
+ },
+ { /* 720p / 74.25MHz modes */
+ .version = MKDEV(1, 0),
+ .pclk = 74250000,
+ .pll0 = 0x01003110,
+ .pll1 = 0x00301500,
+ .pe_current = 0x00000000,
+ .drive_current = 0x2C2C2C2C,
+ .peak_current = 0x07070707,
+ .pad_ctls0_mask = 0xfffff0ff,
+ .pad_ctls0_setting = 0x00000400, /* BG_VREF_LEVEL */
+ },
+ { /* 1080p / 148.5MHz modes */
+ .version = MKDEV(1, 0),
+ .pclk = 148500000,
+ .pll0 = 0x01003310,
+ .pll1 = 0x00301500,
+ .pe_current = 0x00000000,
+ .drive_current = 0x33333333,
+ .peak_current = 0x0C0C0C0C,
+ .pad_ctls0_mask = 0xfffff0ff,
+ .pad_ctls0_setting = 0x00000400, /* BG_VREF_LEVEL */
+ },
+ {
+ .version = MKDEV(1, 0),
+ .pclk = INT_MAX,
+ .pll0 = 0x01003F10,
+ .pll1 = 0x00300F00,
+ .pe_current = 0x00000000,
+ /* lane3 needs a slightly lower current */
+ .drive_current = 0x37373737,
+ .peak_current = 0x17171717,
+ .pad_ctls0_mask = 0xfffff0ff,
+ .pad_ctls0_setting = 0x00000600, /* BG_VREF_LEVEL */
+ },
+};
+
+struct tegra_hdmi_out apalis_tk1_hdmi_out = {
+ .tmds_config = apalis_tk1_tmds_config,
+ .n_tmds_config = ARRAY_SIZE(apalis_tk1_tmds_config),
+};
+
+#if defined(CONFIG_FRAMEBUFFER_CONSOLE)
+static struct tegra_dc_mode hdmi_panel_modes[] = {
+ {
+ .pclk = 25200000,
+ .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 */
+ },
+};
+#elif defined(CONFIG_TEGRA_HDMI_PRIMARY)
+static struct tegra_dc_mode hdmi_panel_modes[] = {
+ {
+ .pclk = 148500000,
+ .h_ref_to_sync = 1,
+ .v_ref_to_sync = 1,
+ .h_sync_width = 44, /* hsync_len */
+ .v_sync_width = 5, /* vsync_len */
+ .h_back_porch = 148, /* left_margin */
+ .v_back_porch = 36, /* upper_margin */
+ .h_active = 1920, /* xres */
+ .v_active = 1080, /* yres */
+ .h_front_porch = 88, /* right_margin */
+ .v_front_porch = 4, /* lower_margin */
+ },
+};
+#endif /* CONFIG_FRAMEBUFFER_CONSOLE || CONFIG_TEGRA_HDMI_PRIMARY */
+
+static struct tegra_dc_out apalis_tk1_disp2_out = {
+ .type = TEGRA_DC_OUT_HDMI,
+ .flags = TEGRA_DC_OUT_HOTPLUG_HIGH,
+#ifndef CONFIG_TEGRA_HDMI_PRIMARY
+ .parent_clk = "pll_d2",
+#else
+ .parent_clk = "pll_d",
+#endif /* CONFIG_TEGRA_HDMI_PRIMARY */
+
+ .ddc_bus = 1,
+ .hotplug_gpio = apalis_tk1_hdmi_hpd,
+ .hdmi_out = &apalis_tk1_hdmi_out,
+
+ /* TODO: update max pclk to POR */
+ .max_pixclock = KHZ2PICOS(297000),
+#if defined(CONFIG_FRAMEBUFFER_CONSOLE) || defined(CONFIG_TEGRA_HDMI_PRIMARY)
+ .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,
+
+ .enable = apalis_tk1_hdmi_enable,
+ .disable = apalis_tk1_hdmi_disable,
+ .postsuspend = apalis_tk1_hdmi_postsuspend,
+ .hotplug_init = apalis_tk1_hdmi_hotplug_init,
+};
+
+#ifndef CONFIG_TEGRA_HDMI_PRIMARY
+static struct tegra_fb_data apalis_tk1_disp1_fb_data = {
+ .win = 0,
+ .bits_per_pixel = 32,
+ .flags = TEGRA_FB_FLIP_ON_PROBE,
+};
+
+static struct tegra_dc_platform_data apalis_tk1_disp1_pdata = {
+ .flags = TEGRA_DC_FLAG_ENABLED,
+ .default_out = &apalis_tk1_disp1_out,
+ .fb = &apalis_tk1_disp1_fb_data,
+ .emc_clk_rate = 204000000,
+#ifdef CONFIG_TEGRA_DC_CMU
+ .cmu_enable = 1,
+#endif
+ .low_v_win = 0x02,
+};
+#endif
+
+static struct tegra_fb_data apalis_tk1_disp2_fb_data = {
+ .win = 0,
+ .xres = 1920,
+ .yres = 1080,
+ .bits_per_pixel = 32,
+ .flags = TEGRA_FB_FLIP_ON_PROBE,
+};
+
+static struct tegra_dc_platform_data apalis_tk1_disp2_pdata = {
+ .flags = TEGRA_DC_FLAG_ENABLED,
+ .default_out = &apalis_tk1_disp2_out,
+ .fb = &apalis_tk1_disp2_fb_data,
+ .emc_clk_rate = 300000000,
+};
+
+static struct platform_device apalis_tk1_disp2_device = {
+ .name = "tegradc",
+#ifndef CONFIG_TEGRA_HDMI_PRIMARY
+ .id = 1,
+#else
+ .id = 0,
+#endif
+ .resource = apalis_tk1_disp2_resources,
+ .num_resources = ARRAY_SIZE(apalis_tk1_disp2_resources),
+ .dev = {
+ .platform_data = &apalis_tk1_disp2_pdata,
+ },
+};
+
+#ifndef CONFIG_TEGRA_HDMI_PRIMARY
+static struct platform_device apalis_tk1_disp1_device = {
+ .name = "tegradc",
+ .id = 0,
+ .resource = apalis_tk1_disp1_resources,
+ .num_resources = ARRAY_SIZE(apalis_tk1_disp1_resources),
+ .dev = {
+ .platform_data = &apalis_tk1_disp1_pdata,
+ },
+};
+#endif
+
+static struct nvmap_platform_carveout apalis_tk1_carveouts[] = {
+ [0] = {
+ .name = "iram",
+ .usage_mask = NVMAP_HEAP_CARVEOUT_IRAM,
+ .base = TEGRA_IRAM_BASE + TEGRA_RESET_HANDLER_SIZE,
+ .size = TEGRA_IRAM_SIZE - TEGRA_RESET_HANDLER_SIZE,
+ .dma_dev = &tegra_iram_dev,
+ },
+ [1] = {
+ .name = "generic-0",
+ .usage_mask = NVMAP_HEAP_CARVEOUT_GENERIC,
+ .base = 0, /* Filled in by apalis_tk1_panel_init() */
+ .size = 0, /* Filled in by apalis_tk1_panel_init() */
+ .dma_dev = &tegra_generic_dev,
+ },
+ [2] = {
+ .name = "vpr",
+ .usage_mask = NVMAP_HEAP_CARVEOUT_VPR,
+ .base = 0, /* Filled in by apalis_tk1_panel_init() */
+ .size = 0, /* Filled in by apalis_tk1_panel_init() */
+ .dma_dev = &tegra_vpr_dev,
+ },
+};
+
+static struct nvmap_platform_data apalis_tk1_nvmap_data = {
+ .carveouts = apalis_tk1_carveouts,
+ .nr_carveouts = ARRAY_SIZE(apalis_tk1_carveouts),
+};
+
+static struct platform_device apalis_tk1_nvmap_device = {
+ .name = "tegra-nvmap",
+ .id = -1,
+ .dev = {
+ .platform_data = &apalis_tk1_nvmap_data,
+ },
+};
+
+#ifndef CONFIG_TEGRA_HDMI_PRIMARY
+/* can be called multiple times */
+static struct tegra_panel *apalis_tk1_panel_configure(void)
+{
+ struct tegra_panel *panel = NULL;
+
+ panel = &lvds_c_1366_14;
+ apalis_tk1_disp1_out.type = TEGRA_DC_OUT_LVDS;
+ apalis_tk1_disp1_device.resource = apalis_tk1_disp1_edp_resources;
+ apalis_tk1_disp1_device.num_resources =
+ ARRAY_SIZE(apalis_tk1_disp1_edp_resources);
+
+ return panel;
+}
+
+static void apalis_tk1_panel_select(void)
+{
+ struct tegra_panel *panel = NULL;
+
+ panel = apalis_tk1_panel_configure();
+
+ if (panel) {
+ if (panel->init_sd_settings)
+ panel->init_sd_settings(&sd_settings);
+
+ if (panel->init_dc_out)
+ panel->init_dc_out(&apalis_tk1_disp1_out);
+
+ if (panel->init_fb_data)
+ panel->init_fb_data(&apalis_tk1_disp1_fb_data);
+
+ if (panel->init_cmu_data)
+ panel->init_cmu_data(&apalis_tk1_disp1_pdata);
+
+ if (panel->set_disp_device)
+ panel->set_disp_device(&apalis_tk1_disp1_device);
+
+ if (panel->register_bl_dev)
+ panel->register_bl_dev();
+
+ if (panel->register_i2c_bridge)
+ panel->register_i2c_bridge();
+ }
+
+}
+#endif
+
+int __init apalis_tk1_panel_init(void)
+{
+ int err = 0;
+ struct resource __maybe_unused *res;
+ struct platform_device *phost1x = NULL;
+
+ struct device_node *dc1_node = NULL;
+ struct device_node *dc2_node = NULL;
+#ifdef CONFIG_NVMAP_USE_CMA_FOR_CARVEOUT
+ struct dma_declare_info vpr_dma_info;
+ struct dma_declare_info generic_dma_info;
+#endif
+
+ find_dc_node(&dc1_node, &dc2_node);
+
+#ifndef CONFIG_TEGRA_HDMI_PRIMARY
+ apalis_tk1_panel_select();
+#endif
+
+#ifdef CONFIG_TEGRA_NVMAP
+ apalis_tk1_carveouts[1].base = tegra_carveout_start;
+ apalis_tk1_carveouts[1].size = tegra_carveout_size;
+
+ apalis_tk1_carveouts[2].base = tegra_vpr_start;
+ apalis_tk1_carveouts[2].size = tegra_vpr_size;
+
+#ifdef CONFIG_NVMAP_USE_CMA_FOR_CARVEOUT
+ generic_dma_info.name = "generic";
+ generic_dma_info.base = tegra_carveout_start;
+ generic_dma_info.size = tegra_carveout_size;
+ generic_dma_info.resize = false;
+ generic_dma_info.cma_dev = NULL;
+
+ vpr_dma_info.name = "vpr";
+ vpr_dma_info.base = tegra_vpr_start;
+ vpr_dma_info.size = tegra_vpr_size;
+ vpr_dma_info.resize = false;
+ vpr_dma_info.cma_dev = NULL;
+ apalis_tk1_carveouts[1].cma_dev = &tegra_generic_cma_dev;
+ apalis_tk1_carveouts[1].resize = false;
+ apalis_tk1_carveouts[2].cma_dev = &tegra_vpr_cma_dev;
+ apalis_tk1_carveouts[2].resize = true;
+
+ vpr_dma_info.size = SZ_32M;
+ vpr_dma_info.resize = true;
+ vpr_dma_info.cma_dev = &tegra_vpr_cma_dev;
+ vpr_dma_info.notifier.ops = &vpr_dev_ops;
+
+ if (tegra_carveout_size) {
+ err = dma_declare_coherent_resizable_cma_memory(
+ &tegra_generic_dev, &generic_dma_info);
+ if (err) {
+ pr_err("Generic coherent memory declaration failed\n");
+ return err;
+ }
+ }
+ if (tegra_vpr_size) {
+ err =
+ dma_declare_coherent_resizable_cma_memory(&tegra_vpr_dev,
+ &vpr_dma_info);
+ if (err) {
+ pr_err("VPR coherent memory declaration failed\n");
+ return err;
+ }
+ }
+#endif
+
+ err = platform_device_register(&apalis_tk1_nvmap_device);
+ if (err) {
+ pr_err("nvmap device registration failed\n");
+ return err;
+ }
+#endif
+
+ phost1x = apalis_tk1_host1x_init();
+ if (!phost1x) {
+ pr_err("host1x devices registration failed\n");
+ return -EINVAL;
+ }
+
+ if (!of_have_populated_dt() || !dc1_node ||
+ !of_device_is_available(dc1_node)) {
+#ifndef CONFIG_TEGRA_HDMI_PRIMARY
+ res = platform_get_resource_byname(&apalis_tk1_disp1_device,
+ IORESOURCE_MEM, "fbmem");
+#else
+ res = platform_get_resource_byname(&apalis_tk1_disp2_device,
+ IORESOURCE_MEM, "fbmem");
+#endif
+ res->start = tegra_fb_start;
+ res->end = tegra_fb_start + tegra_fb_size - 1;
+ }
+
+ /* Copy the bootloader fb to the fb. */
+ if (tegra_bootloader_fb_size)
+ __tegra_move_framebuffer(&apalis_tk1_nvmap_device,
+ tegra_fb_start,
+ tegra_bootloader_fb_start,
+ min(tegra_fb_size,
+ tegra_bootloader_fb_size));
+ else
+ __tegra_clear_framebuffer(&apalis_tk1_nvmap_device,
+ tegra_fb_start, tegra_fb_size);
+
+ /* Copy the bootloader fb2 to the fb2. */
+ if (tegra_bootloader_fb2_size)
+ __tegra_move_framebuffer(&apalis_tk1_nvmap_device,
+ tegra_fb2_start,
+ tegra_bootloader_fb2_start,
+ min(tegra_fb2_size,
+ tegra_bootloader_fb2_size));
+ else
+ __tegra_clear_framebuffer(&apalis_tk1_nvmap_device,
+ tegra_fb2_start, tegra_fb2_size);
+
+#ifndef CONFIG_TEGRA_HDMI_PRIMARY
+ if (!of_have_populated_dt() || !dc1_node ||
+ !of_device_is_available(dc1_node)) {
+ apalis_tk1_disp1_device.dev.parent = &phost1x->dev;
+ err = platform_device_register(&apalis_tk1_disp1_device);
+ if (err) {
+ pr_err("disp1 device registration failed\n");
+ return err;
+ }
+ }
+#endif
+
+ apalis_tk1_tmds_config[1].pe_current = 0x08080808;
+ apalis_tk1_tmds_config[1].drive_current = 0x2d2d2d2d;
+ apalis_tk1_tmds_config[1].peak_current = 0x0;
+ apalis_tk1_tmds_config[2].pe_current = 0x0;
+ apalis_tk1_tmds_config[2].drive_current = 0x2d2d2d2d;
+ apalis_tk1_tmds_config[2].peak_current = 0x05050505;
+
+ if (!of_have_populated_dt() || !dc2_node ||
+ !of_device_is_available(dc2_node)) {
+#ifndef CONFIG_TEGRA_HDMI_PRIMARY
+ res = platform_get_resource_byname(&apalis_tk1_disp2_device,
+ IORESOURCE_MEM, "fbmem");
+ res->start = tegra_fb2_start;
+ res->end = tegra_fb2_start + tegra_fb2_size - 1;
+#endif
+ apalis_tk1_disp2_device.dev.parent = &phost1x->dev;
+ err = platform_device_register(&apalis_tk1_disp2_device);
+ if (err) {
+ pr_err("disp2 device registration failed\n");
+ return err;
+ }
+ }
+
+ return err;
+}
+
+int __init apalis_tk1_display_init(void)
+{
+ struct clk *disp1_clk = clk_get_sys("tegradc.0", NULL);
+ struct clk *disp2_clk = clk_get_sys("tegradc.1", NULL);
+#ifndef CONFIG_TEGRA_HDMI_PRIMARY
+ struct tegra_panel *panel;
+ long disp1_rate = 0;
+#endif
+ long disp2_rate = 0;
+
+ /*
+ * TODO
+ * Need to skip apalis_tk1_display_init
+ * when disp is registered by device_tree
+ */
+
+ 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);
+ }
+#ifndef CONFIG_TEGRA_HDMI_PRIMARY
+ panel = apalis_tk1_panel_configure();
+
+ if (panel && panel->init_dc_out) {
+ panel->init_dc_out(&apalis_tk1_disp1_out);
+ if (apalis_tk1_disp1_out.n_modes && apalis_tk1_disp1_out.modes)
+ disp1_rate = apalis_tk1_disp1_out.modes[0].pclk;
+ } else {
+ disp1_rate = 0;
+ if (!panel || !panel->init_dc_out)
+ pr_err("disp1 panel output not specified!\n");
+ }
+
+ pr_debug("disp1 pclk=%ld\n", disp1_rate);
+ if (disp1_rate)
+ tegra_dvfs_resolve_override(disp1_clk, disp1_rate);
+#endif
+
+ /* set up disp2 */
+ if (apalis_tk1_disp2_out.max_pixclock)
+ disp2_rate = PICOS2KHZ(apalis_tk1_disp2_out.max_pixclock)
+ * 1000;
+ else
+ disp2_rate = 297000000; /* HDMI 4K */
+ pr_debug("disp2 pclk=%ld\n", disp2_rate);
+ if (disp2_rate)
+#ifndef CONFIG_TEGRA_HDMI_PRIMARY
+ tegra_dvfs_resolve_override(disp2_clk, disp2_rate);
+#else
+ tegra_dvfs_resolve_override(disp1_clk, disp2_rate);
+#endif
+
+ clk_put(disp1_clk);
+ clk_put(disp2_clk);
+ return 0;
+}