/* * 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 #include #include #include #include #include #include #include #include #include #include #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; }