summaryrefslogtreecommitdiff
path: root/arch/arm/mach-tegra/board-p2360.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-tegra/board-p2360.c')
-rw-r--r--arch/arm/mach-tegra/board-p2360.c551
1 files changed, 551 insertions, 0 deletions
diff --git a/arch/arm/mach-tegra/board-p2360.c b/arch/arm/mach-tegra/board-p2360.c
new file mode 100644
index 000000000000..1c83e5931e73
--- /dev/null
+++ b/arch/arm/mach-tegra/board-p2360.c
@@ -0,0 +1,551 @@
+/*
+ * arch/arm/mach-tegra/board-p2360.c
+ * Based on arch/arm/mach-tegra/board-vcm30_t124.c
+ *
+ * Copyright (c) 2014, NVIDIA CORPORATION. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/platform_device.h>
+#include <linux/i2c-tegra.h>
+#include <linux/i2c.h>
+#include <linux/platform_data/serial-tegra.h>
+#include <linux/platform_data/tegra_usb.h>
+#include <linux/platform_data/tegra_nor.h>
+#include <linux/platform_data/tegra_ahci.h>
+#include <linux/of_platform.h>
+#include <linux/kernel.h>
+#include <linux/clocksource.h>
+#include <linux/irqchip.h>
+
+#include <mach/tegra_asoc_pdata.h>
+#include <mach/io_dpd.h>
+#include <asm/mach/arch.h>
+#include <mach/isomgr.h>
+#include <mach/board_id.h>
+
+#include "iomap.h"
+#include "board.h"
+#include "clock.h"
+#include "board-p2360.h"
+#include "devices.h"
+#include "board-common.h"
+#include "common.h"
+
+#include <asm/mach-types.h>
+#include "tegra-of-dev-auxdata.h"
+
+static struct board_info board_info, display_board_info;
+
+/*
+ * Set clock values as per automotive POR
+ * Values taken from VCM30T124 and curtailed for P2360
+ */
+static __initdata struct tegra_clk_init_table p2360_clk_init_table[] = {
+ /* name parent rate enabled (always on)*/
+
+ { "pll_c", NULL, 792000000, true},
+
+ { "automotive.sclk", NULL, 316800000, true},
+ { "automotive.hclk", NULL, 316800000, true},
+ { "automotive.pclk", NULL, 158400000, true},
+
+ { "mselect", "pll_p", 408000000, true},
+ { "automotive.mselect", NULL, 408000000, true},
+
+ { "se.cbus", NULL, 432000000, false},
+ { "msenc.cbus", NULL, 432000000, false},
+ { "vde.cbus", NULL, 432000000, false},
+
+ { "vic03.cbus", NULL, 660000000, false},
+ { "tsec.cbus", NULL, 660000000, false},
+
+ { "vi.c4bus", NULL, 600000000, false},
+ { "isp.c4bus", NULL, 600000000, false},
+
+ { "pll_d_out0", "pll_d", 474000000, true},
+ { "disp2", "pll_d_out0", 474000000, false},
+ { "disp1", "pll_d_out0", 474000000, false},
+
+ { "pll_d2", NULL, 297000000, true},
+ { "hdmi", "pll_d2", 297000000, false},
+
+ { "pll_a_out0", NULL, 24600000, true},
+ { "i2s0", "pll_a_out0", 24600000, false},
+ { "i2s1", "pll_a_out0", 24600000, false},
+ { "i2s2", "pll_a_out0", 24600000, false},
+ { "i2s3", "pll_a_out0", 24600000, false},
+ { "i2s4", "pll_a_out0", 24600000, false},
+
+ { "dam0", "pll_p", 19900000, false},
+ { "dam1", "pll_p", 19900000, false},
+ { "dam2", "pll_p", 19900000, false},
+ { "adx", "pll_p", 19900000, false},
+ { "adx1", "pll_p", 19900000, false},
+ { "amx", "pll_p", 19900000, false},
+ { "amx1", "pll_p", 19900000, false},
+
+ { "spdif_out", "pll_a_out0", 24600000, false},
+ { "hda", "pll_p", 48000000, false},
+ { "cilab", "pll_p", 10200000, false},
+ { "cilcd", "pll_p", 10200000, false},
+ { "cile", "pll_p", 10200000, false},
+
+ { "nor", "pll_p", 102000000, false},
+
+ { "sbc1", "pll_p", 25000000, false},
+ { "sbc2", "pll_p", 25000000, false},
+ { "sbc3", "pll_p", 25000000, false},
+ { "sbc4", "pll_p", 25000000, false},
+ { "sbc5", "pll_p", 25000000, false},
+ { "sbc6", "pll_p", 25000000, false},
+
+ { "uarta", "pll_p", 408000000, false},
+ { "uartb", "pll_p", 408000000, false},
+ { "uartc", "pll_p", 408000000, false},
+ { "uartd", "pll_p", 408000000, false},
+
+ { "vi_sensor", "pll_p", 68000000, false},
+ { "vi_sensor2", "pll_p", 68000000, false},
+
+ { "automotive.host1x", NULL, 264000000, true},
+
+ { NULL, NULL, 0, 0},
+};
+
+#define SET_FIXED_TARGET_RATE(clk_name, fixed_target_rate) \
+ {clk_name, NULL, fixed_target_rate, false}
+
+/*
+ * FIXME: Need to revisit for following clocks:
+ * csi, dsi, dsilp, audio
+ */
+
+/*
+ * Table of fixed target rates for automotive. parent and enable field are
+ * don't care for this table.
+ */
+
+static struct tegra_clk_init_table p2360_fixed_target_clk_table[] = {
+
+ /* name, fixed target rate*/
+ SET_FIXED_TARGET_RATE("pll_m", 792000000),
+#ifdef CONFIG_ANDROID
+ /* [WAR] : bug 1440706
+ There are lots of WARN_ON messages during Video playback.
+ Those make some jerky Video playback issues.
+ Temporarily changed the expected rate from 316800000
+ to 12000000 but it should be fixed correctly.
+ */
+ SET_FIXED_TARGET_RATE("sbus", 12000000),
+#else
+ SET_FIXED_TARGET_RATE("sbus", 316800000),
+#endif
+
+#ifdef CONFIG_TEGRA_DUAL_CBUS
+ SET_FIXED_TARGET_RATE("pll_c2", 432000000),
+ SET_FIXED_TARGET_RATE("c2bus", 432000000),
+ SET_FIXED_TARGET_RATE("pll_c3", 660000000),
+ SET_FIXED_TARGET_RATE("c3bus", 660000000),
+#endif
+ SET_FIXED_TARGET_RATE("pll_c", 792000000),
+ SET_FIXED_TARGET_RATE("pll_c4", 600000000),
+ SET_FIXED_TARGET_RATE("c4bus", 600000000),
+ SET_FIXED_TARGET_RATE("pll_c_out1", 316800000),
+ SET_FIXED_TARGET_RATE("pll_p", 408000000),
+ SET_FIXED_TARGET_RATE("pll_x", 150000000),
+ SET_FIXED_TARGET_RATE("gbus", 600000000),
+
+ SET_FIXED_TARGET_RATE("gk20a.gbus", 600000000),
+ SET_FIXED_TARGET_RATE("sclk", 316800000),
+ SET_FIXED_TARGET_RATE("hclk", 316800000),
+ SET_FIXED_TARGET_RATE("ahb.sclk", 316800000),
+ SET_FIXED_TARGET_RATE("pclk", 158400000),
+ SET_FIXED_TARGET_RATE("apb.sclk", 158400000),
+
+ SET_FIXED_TARGET_RATE("cpu_g", 150000000),
+ SET_FIXED_TARGET_RATE("cpu_lp", 109200000),
+
+ SET_FIXED_TARGET_RATE("vde", 432000000),
+ SET_FIXED_TARGET_RATE("se", 432000000),
+ SET_FIXED_TARGET_RATE("msenc", 432000000),
+
+ SET_FIXED_TARGET_RATE("tsec", 660000000),
+ SET_FIXED_TARGET_RATE("vic03", 660000000),
+
+ SET_FIXED_TARGET_RATE("vi", 600000000),
+ SET_FIXED_TARGET_RATE("isp", 600000000),
+
+ SET_FIXED_TARGET_RATE("host1x", 264000000),
+ SET_FIXED_TARGET_RATE("mselect", 408000000),
+
+ SET_FIXED_TARGET_RATE("dam0", 40000000),
+ SET_FIXED_TARGET_RATE("dam1", 40000000),
+ SET_FIXED_TARGET_RATE("dam2", 40000000),
+
+ SET_FIXED_TARGET_RATE("adx", 24600000),
+ SET_FIXED_TARGET_RATE("adx1", 24600000),
+ SET_FIXED_TARGET_RATE("amx", 24600000),
+ SET_FIXED_TARGET_RATE("amx1", 24600000),
+
+ SET_FIXED_TARGET_RATE("spdif_out", 24576000),
+ SET_FIXED_TARGET_RATE("hda", 108000000),
+
+ SET_FIXED_TARGET_RATE("cilab", 102000000),
+ SET_FIXED_TARGET_RATE("cilcd", 102000000),
+ SET_FIXED_TARGET_RATE("cile", 102000000),
+
+ SET_FIXED_TARGET_RATE("uarta", 408000000),
+ SET_FIXED_TARGET_RATE("uartb", 408000000),
+ SET_FIXED_TARGET_RATE("uartc", 408000000),
+#ifndef CONFIG_ANDROID
+ SET_FIXED_TARGET_RATE("uartd", 408000000),
+#endif
+};
+
+static int __init tegra_fixed_target_rate_init(void)
+{
+ struct clk *c;
+ unsigned long flags;
+ int i, is_e1860_b00 = 0;
+
+ is_e1860_b00 = tegra_is_board(NULL, "61860", NULL, "300", NULL);
+
+ /* Set POR value for all clocks given in the table */
+ for (i = 0; i < ARRAY_SIZE(p2360_fixed_target_clk_table); i++) {
+
+ c = tegra_get_clock_by_name(
+ p2360_fixed_target_clk_table[i].name);
+ if (c) {
+ clk_lock_save(c, &flags);
+ c->fixed_target_rate =
+ p2360_fixed_target_clk_table[i].rate;
+ clk_unlock_restore(c, &flags);
+ } else {
+ pr_warn("%s: Clock %s not found\n", __func__,
+ p2360_fixed_target_clk_table[i].name);
+ }
+ }
+
+ return 0;
+}
+late_initcall_sync(tegra_fixed_target_rate_init);
+
+static struct tegra_nor_platform_data p2360_nor_data = {
+ .flash = {
+ .map_name = "cfi_probe",
+ .width = 2,
+ },
+ .chip_parms = {
+ .MuxMode = NorMuxMode_ADNonMux,
+ .ReadMode = NorReadMode_Page,
+ .PageLength = NorPageLength_8Word,
+ .ReadyActive = NorReadyActive_WithData,
+ /* FIXME: Need to use characterized value */
+ .timing_default = {
+ .timing0 = 0x30300273,
+ .timing1 = 0x00030302,
+ },
+ .timing_read = {
+ .timing0 = 0x30300273,
+ .timing1 = 0x00030302,
+ },
+ },
+};
+
+static struct cs_info p2360_cs_info[] = {
+ {
+ .cs = CS_0,
+ .num_cs_gpio = 0,
+ .virt = IO_ADDRESS(TEGRA_NOR_FLASH_BASE),
+ .size = SZ_64M,
+ .phys = TEGRA_NOR_FLASH_BASE,
+ },
+};
+
+static void p2360_nor_init(void)
+{
+ tegra_nor_device.resource[2].end = TEGRA_NOR_FLASH_BASE + SZ_64M - 1;
+
+ p2360_nor_data.info.cs = kzalloc(sizeof(struct cs_info) *
+ ARRAY_SIZE(p2360_cs_info),
+ GFP_KERNEL);
+ if (!p2360_nor_data.info.cs)
+ BUG();
+
+ p2360_nor_data.info.num_chips = ARRAY_SIZE(p2360_cs_info);
+
+ memcpy(p2360_nor_data.info.cs, p2360_cs_info,
+ sizeof(struct cs_info) * ARRAY_SIZE(p2360_cs_info));
+
+ tegra_nor_device.dev.platform_data = &p2360_nor_data;
+ platform_device_register(&tegra_nor_device);
+}
+
+
+/* Register debug UART in old fashion and use DT for all others */
+static struct tegra_serial_platform_data p2360_uartb_pdata = {
+ .dma_req_selector = 9,
+ .modem_interrupt = false,
+};
+
+static void __init p2360_uart_init(void)
+{
+ int debug_port_id;
+
+ if (!is_tegra_debug_uartport_hs()) {
+ debug_port_id = uart_console_debug_init(1);
+ if (debug_port_id < 0)
+ return;
+
+ platform_device_register(uart_console_debug_device);
+ } else {
+ tegra_uartb_device.dev.platform_data = &p2360_uartb_pdata;
+ platform_device_register(&tegra_uartb_device);
+ }
+}
+
+/* FIXME: Check which devices are needed from the below list */
+static struct platform_device *p2360_devices[] __initdata = {
+ &tegra_pmu_device,
+#if defined(CONFIG_TEGRA_AVP)
+ &tegra_avp_device,
+#endif
+#if defined(CONFIG_CRYPTO_DEV_TEGRA_SE)
+ &tegra12_se_device,
+#endif
+};
+
+static struct tegra_usb_platform_data tegra_udc_pdata = {
+#if defined(CONFIG_USB_TEGRA_OTG)
+ .port_otg = true,
+#else
+ .port_otg = false,
+#endif
+ .has_hostpc = true,
+ .phy_intf = TEGRA_USB_PHY_INTF_UTMI,
+ .op_mode = TEGRA_USB_OPMODE_DEVICE,
+ .u_data.dev = {
+ .vbus_pmu_irq = 0,
+ .vbus_gpio = -1,
+ .charging_supported = false,
+ .remote_wakeup_supported = false,
+ },
+ .u_cfg.utmi = {
+ .hssync_start_delay = 0,
+ .idle_wait_delay = 17,
+ .elastic_limit = 16,
+ .term_range_adj = 6,
+ .xcvr_setup = 63,
+ .xcvr_setup_offset = 6,
+ .xcvr_use_fuses = 1,
+ .xcvr_lsfslew = 2,
+ .xcvr_lsrslew = 2,
+ .xcvr_use_lsb = 1,
+ },
+};
+
+static struct tegra_usb_platform_data tegra_ehci1_utmi_pdata = {
+#if defined(CONFIG_USB_TEGRA_OTG)
+ .port_otg = true,
+ .id_det_type = TEGRA_USB_VIRTUAL_ID,
+#else
+ .port_otg = false,
+#endif
+ .has_hostpc = true,
+ .unaligned_dma_buf_supported = true,
+ .phy_intf = TEGRA_USB_PHY_INTF_UTMI,
+ .op_mode = TEGRA_USB_OPMODE_HOST,
+ .u_data.host = {
+ .vbus_gpio = -1,
+ .hot_plug = false,
+ .remote_wakeup_supported = false,
+ .power_off_on_suspend = false,
+ .turn_off_vbus_on_lp0 = true,
+ },
+ .u_cfg.utmi = {
+ .hssync_start_delay = 0,
+ .elastic_limit = 16,
+ .idle_wait_delay = 17,
+ .term_range_adj = 6,
+ .xcvr_setup = 15,
+ .xcvr_lsfslew = 2,
+ .xcvr_lsrslew = 2,
+ .xcvr_setup_offset = 0,
+ .xcvr_use_fuses = 1,
+ .vbus_oc_map = 0x4,
+ },
+};
+
+
+static struct tegra_usb_platform_data tegra_ehci2_utmi_pdata = {
+ .port_otg = false,
+ .has_hostpc = true,
+ .unaligned_dma_buf_supported = true,
+ .phy_intf = TEGRA_USB_PHY_INTF_UTMI,
+ .op_mode = TEGRA_USB_OPMODE_HOST,
+ .u_data.host = {
+ .vbus_gpio = -1,
+ .hot_plug = true,
+ .remote_wakeup_supported = false,
+ .power_off_on_suspend = false,
+ .turn_off_vbus_on_lp0 = true,
+ },
+ .u_cfg.utmi = {
+ .hssync_start_delay = 0,
+ .elastic_limit = 16,
+ .idle_wait_delay = 17,
+ .term_range_adj = 6,
+ .xcvr_setup = 8,
+ .xcvr_lsfslew = 2,
+ .xcvr_lsrslew = 2,
+ .xcvr_setup_offset = 0,
+ .xcvr_use_fuses = 1,
+ .vbus_oc_map = 0x5,
+ },
+};
+
+static struct tegra_usb_otg_data tegra_otg_pdata = {
+ .ehci_device = &tegra_ehci1_device,
+ .ehci_pdata = &tegra_ehci1_utmi_pdata,
+};
+
+static void p2360_usb_init(void)
+{
+ int usb_port_owner_info = tegra_get_usb_port_owner_info();
+
+ if (!(usb_port_owner_info & UTMI1_PORT_OWNER_XUSB)) {
+ tegra_otg_pdata.is_xhci = false;
+ tegra_udc_pdata.u_data.dev.is_xhci = false;
+
+#if defined(CONFIG_USB_TEGRA_OTG)
+ /* register OTG device */
+ tegra_otg_device.dev.platform_data = &tegra_otg_pdata;
+ platform_device_register(&tegra_otg_device);
+
+ /* Setup the udc platform data */
+ tegra_udc_device.dev.platform_data = &tegra_udc_pdata;
+ platform_device_register(&tegra_udc_device);
+#else
+ /* register host mode */
+ tegra_ehci1_device.dev.platform_data = &tegra_ehci1_utmi_pdata;
+ platform_device_register(&tegra_ehci1_device);
+#endif
+ }
+
+ if (!(usb_port_owner_info & UTMI2_PORT_OWNER_XUSB)) {
+ tegra_ehci2_device.dev.platform_data = &tegra_ehci2_utmi_pdata;
+ platform_device_register(&tegra_ehci2_device);
+ }
+}
+
+#ifdef CONFIG_USE_OF
+struct of_dev_auxdata p2360_auxdata_lookup[] __initdata = {
+ OF_DEV_AUXDATA("nvidia,tegra114-hsuart", TEGRA_UARTB_BASE,
+ "serial-tegra.1", NULL),
+ OF_DEV_AUXDATA("nvidia,tegra124-host1x", TEGRA_HOST1X_BASE, "host1x",
+ NULL),
+ OF_DEV_AUXDATA("nvidia,tegra124-gk20a", TEGRA_GK20A_BAR0_BASE, "gk20a.0", NULL),
+ OF_DEV_AUXDATA("nvidia,tegra124-vic", TEGRA_VIC_BASE, "vic03.0", NULL),
+ OF_DEV_AUXDATA("nvidia,tegra124-msenc", TEGRA_MSENC_BASE, "msenc",
+ NULL),
+ OF_DEV_AUXDATA("nvidia,tegra124-vi", TEGRA_VI_BASE, "vi.0", NULL),
+ OF_DEV_AUXDATA("nvidia,tegra124-isp", TEGRA_ISP_BASE, "isp.0", NULL),
+ OF_DEV_AUXDATA("nvidia,tegra124-isp", TEGRA_ISPB_BASE, "isp.1", NULL),
+ OF_DEV_AUXDATA("nvidia,tegra124-tsec", TEGRA_TSEC_BASE, "tsec", NULL),
+ T124_I2C_OF_DEV_AUXDATA,
+ OF_DEV_AUXDATA("nvidia,tegra114-nvavp", 0x60001000, "nvavp",
+ NULL),
+ OF_DEV_AUXDATA("nvidia,tegra124-efuse", TEGRA_FUSE_BASE, "tegra-fuse",
+ NULL),
+ {}
+};
+#endif
+
+static void __init tegra_p2360_early_init(void)
+{
+ tegra_clk_init_from_table(p2360_clk_init_table);
+ tegra_clk_verify_parents();
+ tegra_soc_device_init("p2360");
+}
+
+static void __init tegra_p2360_late_init(void)
+{
+ struct board_info board_info;
+ tegra_get_board_info(&board_info);
+ pr_info("board_info: id:sku:fab:major:minor = 0x%04x:0x%04x:0x%02x:0x%02x:0x%02x\n",
+ board_info.board_id, board_info.sku,
+ board_info.fab, board_info.major_revision,
+ board_info.minor_revision);
+ p2360_usb_init();
+
+ p2360_nor_init();
+
+ p2360_uart_init();
+ platform_add_devices(p2360_devices, ARRAY_SIZE(p2360_devices));
+ tegra_io_dpd_init();
+ p2360_sdhci_init();
+
+ isomgr_init();
+
+ p2360_panel_init();
+}
+
+static void __init tegra_p2360_dt_init(void)
+{
+ tegra_get_board_info(&board_info);
+ tegra_get_display_board_info(&display_board_info);
+
+ tegra_p2360_early_init();
+#ifdef CONFIG_NVMAP_USE_CMA_FOR_CARVEOUT
+ carveout_linear_set(&tegra_generic_cma_dev);
+ carveout_linear_set(&tegra_vpr_cma_dev);
+#endif
+#ifdef CONFIG_USE_OF
+ of_platform_populate(NULL,
+ of_default_bus_match_table, p2360_auxdata_lookup,
+ &platform_bus);
+#endif
+
+ tegra_p2360_late_init();
+}
+
+static void __init tegra_p2360_reserve(void)
+{
+#if defined(CONFIG_NVMAP_CONVERT_CARVEOUT_TO_IOVMM)
+ /* 1920*1200*4*2 = 18432000 bytes */
+ tegra_reserve4(0, SZ_16M + SZ_2M, SZ_16M + SZ_2M, 64 * SZ_1M);
+#else
+ tegra_reserve4(SZ_128M, SZ_16M + SZ_2M, SZ_16M + SZ_2M, 64 * SZ_1M);
+#endif
+}
+
+static const char * const p2360_dt_board_compat[] = {
+ "nvidia,p2360",
+ NULL
+};
+
+DT_MACHINE_START(P2360, "p2360")
+ .atag_offset = 0x100,
+ .smp = smp_ops(tegra_smp_ops),
+ .map_io = tegra_map_common_io,
+ .reserve = tegra_p2360_reserve,
+ .init_early = tegra12x_init_early,
+ .init_irq = irqchip_init,
+ .init_time = clocksource_of_init,
+ .init_machine = tegra_p2360_dt_init,
+ .restart = tegra_assert_system_reset,
+ .dt_compat = p2360_dt_board_compat,
+ .init_late = tegra_init_late
+MACHINE_END