/*
* 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 .
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "iomap.h"
#include "board.h"
#include "clock.h"
#include "board-p2360.h"
#include "devices.h"
#include "board-common.h"
#include "common.h"
#include
#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