blob: 30ec927862c4644dd6e0badcc2e72d691f4ff24d [file] [log] [blame]
/*
* arch/arm/mach-tegra/board-vcm30_t124-panel.c
*
* Copyright (c) 2013-2014, 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
* 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/of.h>
#include <linux/dma-mapping.h>
#include <mach/irqs.h>
#include <mach/dc.h>
#include "board.h"
#include "devices.h"
#include "gpio-names.h"
#include "board-vcm30_t124.h"
#include "board-panel.h"
#include "common.h"
#include "iomap.h"
#include "tegra12_host1x_devices.h"
struct platform_device * __init vcm30_t124_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;
}
#ifndef CONFIG_TEGRA_HDMI_PRIMARY
static struct resource vcm30_t124_disp1_dp_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 vcm30_t124_panel_init() */
.end = 0, /* Filled in by vcm30_t124_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 tegra_fb_data vcm30_t124_disp1_fb_data = {
.win = 0,
.bits_per_pixel = 32,
};
static struct tegra_dc_sd_settings sd_settings;
static struct tegra_dc_out vcm30_t124_disp1_out = {
.type = TEGRA_DC_OUT_DP,
.sd_settings = &sd_settings,
/* eDP max pixel rate to T124 POR */
.max_pixclock = KHZ2PICOS(540000), /* 540MPix/S 3840x2160@60 */
};
static struct tegra_dc_platform_data vcm30_t124_disp1_pdata = {
.flags = TEGRA_DC_FLAG_ENABLED,
.default_out = &vcm30_t124_disp1_out,
.fb = &vcm30_t124_disp1_fb_data,
.emc_clk_rate = 204000000,
#ifdef CONFIG_TEGRA_DC_CMU
.cmu_enable = 1,
#endif
};
static struct platform_device vcm30_t124_disp1_device = {
.name = "tegradc",
.id = 0,
.resource = vcm30_t124_disp1_dp_resources,
.num_resources = ARRAY_SIZE(vcm30_t124_disp1_dp_resources),
.dev = {
.platform_data = &vcm30_t124_disp1_pdata,
},
};
#endif
static struct resource vcm30_t124_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 tegra_init_hdmi() */
.end = 0, /* Filled in by tegra_init_hdmi() */
.flags = IORESOURCE_MEM,
},
{
.name = "hdmi_regs",
.start = TEGRA_HDMI_BASE,
.end = TEGRA_HDMI_BASE + TEGRA_HDMI_SIZE - 1,
.flags = IORESOURCE_MEM,
},
};
static int vcm30_t124_hdmi_enable(struct device *dev)
{
return 0;
}
static int vcm30_t124_hdmi_disable(void)
{
return 0;
}
static int vcm30_t124_hdmi_postsuspend(void)
{
return 0;
}
static int vcm30_t124_hdmi_hotplug_init(struct device *dev)
{
return 0;
}
/* XXX: These values are taken from ardbeg. To be fixed after VCM char */
struct tmds_config vcm30_t124_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 vcm30_t124_hdmi_out = {
.tmds_config = vcm30_t124_tmds_config,
.n_tmds_config = ARRAY_SIZE(vcm30_t124_tmds_config),
};
#ifdef 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 = 1280, /* xres */
.v_active = 720, /* yres */
.h_front_porch = 88, /* right_margin */
.v_front_porch = 4, /* lower_margin */
},
};
#endif
#define VCM30_T124_HDMI_HPD TEGRA_GPIO_PN7
static struct tegra_dc_out vcm30_t124_disp2_out = {
.type = TEGRA_DC_OUT_HDMI,
.flags = TEGRA_DC_OUT_HOTPLUG_LOW |
TEGRA_DC_OUT_NVHDCP_POLICY_ON_DEMAND,
.parent_clk = "pll_d2",
.ddc_bus = 3,
.hotplug_gpio = VCM30_T124_HDMI_HPD,
.hdmi_out = &vcm30_t124_hdmi_out,
/* TODO: update max pclk to POR */
.max_pixclock = KHZ2PICOS(297000),
#if 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 = vcm30_t124_hdmi_enable,
.disable = vcm30_t124_hdmi_disable,
.postsuspend = vcm30_t124_hdmi_postsuspend,
.hotplug_init = vcm30_t124_hdmi_hotplug_init,
};
static struct tegra_fb_data vcm30_t124_disp2_fb_data = {
.win = 0,
.xres = 1280,
.yres = 720,
.bits_per_pixel = 32,
};
static struct tegra_dc_platform_data vcm30_t124_disp2_pdata = {
.default_out = &vcm30_t124_disp2_out,
.fb = &vcm30_t124_disp2_fb_data,
.emc_clk_rate = 300000000,
};
static struct platform_device vcm30_t124_disp2_device = {
.name = "tegradc",
#ifndef CONFIG_TEGRA_HDMI_PRIMARY
.id = 1,
#else
.id = 0,
#endif
.resource = vcm30_t124_disp2_resources,
.num_resources = ARRAY_SIZE(vcm30_t124_disp2_resources),
.dev = {
.platform_data = &vcm30_t124_disp2_pdata,
},
};
static struct nvmap_platform_carveout vcm30_t124_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 vcm30_t124_panel_init() */
.size = 0, /* Filled in by vcm30_t124_panel_init() */
.dma_dev = &tegra_generic_dev,
},
[2] = {
.name = "vpr",
.usage_mask = NVMAP_HEAP_CARVEOUT_VPR,
.base = 0, /* Filled in by vcm30_t124_panel_init() */
.size = 0, /* Filled in by vcm30_t124_panel_init() */
.dma_dev = &tegra_vpr_dev,
},
};
static struct nvmap_platform_data vcm30_t124_nvmap_data = {
.carveouts = vcm30_t124_carveouts,
.nr_carveouts = ARRAY_SIZE(vcm30_t124_carveouts),
};
static struct platform_device vcm30_t124_nvmap_device = {
.name = "tegra-nvmap",
.id = -1,
.dev = {
.platform_data = &vcm30_t124_nvmap_data,
},
};
#ifndef CONFIG_TEGRA_HDMI_PRIMARY
static void __init vcm30_t124_panel_select(void)
{
struct tegra_panel *panel = NULL;
/* for eDP */
panel = &edp_a_1080p_14_0;
vcm30_t124_disp1_out.type = TEGRA_DC_OUT_DP;
vcm30_t124_disp1_device.resource = vcm30_t124_disp1_dp_resources;
vcm30_t124_disp1_device.num_resources =
ARRAY_SIZE(vcm30_t124_disp1_dp_resources);
if (panel) {
if (panel->init_sd_settings)
panel->init_sd_settings(&sd_settings);
if (panel->init_dc_out)
panel->init_dc_out(&vcm30_t124_disp1_out);
if (panel->init_fb_data)
panel->init_fb_data(&vcm30_t124_disp1_fb_data);
if (panel->init_cmu_data)
panel->init_cmu_data(&vcm30_t124_disp1_pdata);
if (panel->set_disp_device)
panel->set_disp_device(&vcm30_t124_disp1_device);
if (panel->register_bl_dev)
panel->register_bl_dev();
if (panel->register_i2c_bridge)
panel->register_i2c_bridge();
}
}
#endif
int __init vcm30_t124_panel_init(void)
{
int err = 0;
struct resource *res;
struct platform_device *phost1x = NULL;
#ifdef CONFIG_NVMAP_USE_CMA_FOR_CARVEOUT
struct dma_declare_info vpr_dma_info;
struct dma_declare_info generic_dma_info;
#endif
#ifndef CONFIG_TEGRA_HDMI_PRIMARY
vcm30_t124_panel_select();
#endif
#ifdef CONFIG_TEGRA_NVMAP
vcm30_t124_carveouts[1].base = tegra_carveout_start;
vcm30_t124_carveouts[1].size = tegra_carveout_size;
vcm30_t124_carveouts[2].base = tegra_vpr_start;
vcm30_t124_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;
vcm30_t124_carveouts[1].cma_dev = &tegra_generic_cma_dev;
vcm30_t124_carveouts[1].resize = false;
vcm30_t124_carveouts[2].cma_dev = &tegra_vpr_cma_dev;
vcm30_t124_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(&vcm30_t124_nvmap_device);
if (err) {
pr_err("nvmap device registration failed\n");
return err;
}
#endif
phost1x = vcm30_t124_host1x_init();
if (!phost1x) {
pr_err("host1x devices registration failed\n");
return -EINVAL;
}
#ifndef CONFIG_TEGRA_HDMI_PRIMARY
res = platform_get_resource_byname(&vcm30_t124_disp1_device,
IORESOURCE_MEM, "fbmem");
#else
res = platform_get_resource_byname(&vcm30_t124_disp2_device,
IORESOURCE_MEM, "fbmem");
#endif
res->start = tegra_fb_start;
res->end = tegra_fb_start + tegra_fb_size - 1;
/* clear FB for both DC and copy the bootloader FB */
__tegra_clear_framebuffer(&vcm30_t124_nvmap_device,
tegra_fb_start, tegra_fb_size);
if (tegra_bootloader_fb_size)
__tegra_move_framebuffer(&vcm30_t124_nvmap_device,
tegra_fb_start, tegra_bootloader_fb_start,
min(tegra_fb_size, tegra_bootloader_fb_size));
if (tegra_fb2_size) {
__tegra_clear_framebuffer(&vcm30_t124_nvmap_device,
tegra_fb2_start, tegra_fb2_size);
if (tegra_bootloader_fb2_size)
__tegra_move_framebuffer(&vcm30_t124_nvmap_device,
tegra_fb2_start, tegra_bootloader_fb2_start,
min(tegra_fb2_size,
tegra_bootloader_fb2_size));
}
#ifndef CONFIG_TEGRA_HDMI_PRIMARY
vcm30_t124_disp1_device.dev.parent = &phost1x->dev;
err = platform_device_register(&vcm30_t124_disp1_device);
if (err) {
pr_err("disp1 device registration failed\n");
return err;
}
#endif
err = tegra_init_hdmi(&vcm30_t124_disp2_device, phost1x);
if (err)
return err;
#ifdef CONFIG_TEGRA_NVAVP
nvavp_device.dev.parent = &phost1x->dev;
err = platform_device_register(&nvavp_device);
if (err) {
pr_err("nvavp device registration failed\n");
return err;
}
#endif
return err;
}