/*
* arch/arm/mach-tegra/board-p852.c
*
* Copyright (c) 2010-2011, NVIDIA Corporation.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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.
*
*/
#include "board-p852.h"
#include <mach/spdif.h>
unsigned int p852_sku_peripherals;
unsigned int p852_spi_peripherals;
unsigned int p852_i2s_peripherals;
unsigned int p852_uart_peripherals;
unsigned int p852_i2c_peripherals;
unsigned int p852_sdhci_peripherals;
unsigned int p852_display_peripherals;
/* If enable_usb3 can have two options ehci3=eth or usb*/
static char enable_usb3[4];
int __init parse_enable_usb3(char *arg)
{
if (!arg)
return 0;
strncpy(enable_usb3, arg, sizeof(enable_usb3));
return 0;
}
early_param("ehci3", parse_enable_usb3);
static __initdata struct tegra_clk_init_table p852_clk_init_table[] = {
/* name parent rate enabled */
{"uarta", "pll_p", 216000000, true},
{"uartb", "pll_p", 216000000, true},
{"uartc", "pll_p", 216000000, true},
{"uartd", "pll_p", 216000000, true},
{"pll_m", "clk_m", 600000000, true},
{"pll_m_out1", "pll_m", 240000000, true},
{"pll_p_out4", "pll_p", 240000000, true},
{"host1x", "pll_p", 166000000, true},
{"disp1", "pll_p", 216000000, true},
{"vi", "pll_m", 100000000, true},
{"csus", "pll_m", 100000000, true},
{"emc", "pll_m", 600000000, true},
{"pll_c", "clk_m", 600000000, true},
{"pll_c_out1", "pll_c", 240000000, true},
{"pwm", "clk_32k", 32768, false},
{"clk_32k", NULL, 32768, true},
{"pll_a", NULL, 56448000, true},
{"pll_a_out0", "pll_a", 11289600, true},
{"audio", "pll_a_out0", 11289600, true},
{"audio_2x", "audio", 22579200, false},
{"vde", "pll_c", 240000000, false},
{"vi_sensor", "pll_m", 111000000, true},
{"epp", "pll_m", 111000000, true},
{"mpe", "pll_m", 111000000, true},
{"i2s1", "pll_a_out0", 11289600, true},
{"i2s2", "pll_a_out0", 11289600, true},
{"ndflash", "pll_p", 86500000, true},
{"sbc1", "pll_p", 12000000, false},
{"spdif_in", "pll_m", 22579000, true},
{"spdif_out", "pll_a_out0", 5644800, true},
{"sbc2", "pll_p", 12000000, false},
{"sbc3", "pll_p", 12000000, false},
{"sbc4", "pll_p", 12000000, false},
{"nor", "pll_p", 86500000, true},
{NULL, NULL, 0, 0},
};
static struct tegra_nand_chip_parms nand_chip_parms[] = {
/* Micron 29F4G08ABADA */
[0] = {
.vendor_id = 0x2C,
.device_id = 0xDC,
.capacity = 512,
.read_id_fourth_byte = 0x95,
.timing = {
.trp = 1,
.trh = 1,
.twp = 12,
.twh = 12,
.tcs = 24,
.twhr = 58,
.tcr_tar_trr = 12,
.twb = 116,
.trp_resp = 24,
.tadl = 24,
},
},
/* Micron 29F4G16ABADA */
[1] = {
.vendor_id = 0x2C,
.device_id = 0xCC,
.capacity = 512,
.read_id_fourth_byte = 0xD5,
.timing = {
.trp = 10,
.trh = 7,
.twp = 10,
.twh = 7,
.tcs = 15,
.twhr = 60,
.tcr_tar_trr = 20,
.twb = 100,
.trp_resp = 20,
.tadl = 70,
},
},
/* Hynix HY27UF084G2B */
[2] = {
.vendor_id = 0xAD,
.device_id = 0xDC,
.read_id_fourth_byte = 0x95,
.capacity = 512,
.timing = {
.trp = 12,
.trh = 1,
.twp = 12,
.twh = 0,
.tcs = 24,
.twhr = 58,
.tcr_tar_trr = 0,
.twb = 116,
.trp_resp = 24,
.tadl = 24,
},
},
};
struct tegra_nand_platform p852_nand_data = {
.max_chips = 8,
.chip_parms = nand_chip_parms,
.nr_chip_parms = ARRAY_SIZE(nand_chip_parms),
.wp_gpio = TEGRA_GPIO_PC7,
};
static struct resource resources_nand[] = {
[0] = {
.start = INT_NANDFLASH,
.end = INT_NANDFLASH,
.flags = IORESOURCE_IRQ,
},
};
static struct platform_device p852_nand_device = {
.name = "tegra_nand",
.id = -1,
.num_resources = ARRAY_SIZE(resources_nand),
.resource = resources_nand,
.dev = {
.platform_data = &p852_nand_data,
},
};
unsigned int p852_uart_irqs[] = {
INT_UARTA,
INT_UARTB,
INT_UARTC,
INT_UARTD,
};
unsigned int p852_uart_bases[] = {
TEGRA_UARTA_BASE,
TEGRA_UARTB_BASE,
TEGRA_UARTC_BASE,
TEGRA_UARTD_BASE,
};
static struct platform_device *p852_spi_devices[] __initdata = {
&tegra_spi_device1,
&tegra_spi_device2,
&tegra_spi_device3,
&tegra_spi_device4,
};
static struct plat_serial8250_port debug_uart_platform_data[] = {
{
.flags = UPF_BOOT_AUTOCONF,
.iotype = UPIO_MEM,
.regshift = 2,
.uartclk = 216000000,
},
{
.flags = 0,
}
};
#define DEF_8250_PLATFORM_DATA(_base, _irq) { \
.flags = UPF_BOOT_AUTOCONF, \
.iotype = UPIO_MEM, \
.membase = IO_ADDRESS(_base), \
.mapbase = _base, \
.irq = _irq, \
.regshift = 2, \
.uartclk = 216000000, \
}
static struct plat_serial8250_port tegra_8250_uarta_platform_data[] = {
DEF_8250_PLATFORM_DATA(TEGRA_UARTA_BASE, INT_UARTA),
{
.flags = 0,
}
};
static struct plat_serial8250_port tegra_8250_uartb_platform_data[] = {
DEF_8250_PLATFORM_DATA(TEGRA_UARTB_BASE, INT_UARTB),
{
.flags = 0,
}
};
static struct plat_serial8250_port tegra_8250_uartc_platform_data[] = {
DEF_8250_PLATFORM_DATA(TEGRA_UARTC_BASE, INT_UARTC),
{
.flags = 0,
}
};
static struct plat_serial8250_port tegra_8250_uartd_platform_data[] = {
DEF_8250_PLATFORM_DATA(TEGRA_UARTD_BASE, INT_UARTD),
{
.flags = 0,
}
};
static struct plat_serial8250_port tegra_8250_uarte_platform_data[] = {
DEF_8250_PLATFORM_DATA(TEGRA_UARTE_BASE, INT_UARTE),
{
.flags = 0,
}
};
struct platform_device tegra_8250_uarta_device = {
.name = "serial8250",
.id = PLAT8250_DEV_PLATFORM,
.dev = {
.platform_data = tegra_8250_uarta_platform_data,
},
};
struct platform_device tegra_8250_uartb_device = {
.name = "serial8250",
.id = PLAT8250_DEV_PLATFORM1,
.dev = {
.platform_data = tegra_8250_uartb_platform_data,
},
};
struct platform_device tegra_8250_uartc_device = {
.name = "serial8250",
.id = PLAT8250_DEV_PLATFORM2,
.dev = {
.platform_data = tegra_8250_uartc_platform_data,
},
};
struct platform_device tegra_8250_uartd_device = {
.name = "serial8250",
.id = PLAT8250_DEV_FOURPORT,
.dev = {
.platform_data = tegra_8250_uartd_platform_data,
},
};
struct platform_device tegra_8250_uarte_device = {
.name = "serial8250",
.id = PLAT8250_DEV_ACCENT,
.dev = {
.platform_data = tegra_8250_uarte_platform_data,
},
};
static struct platform_device debug_uart = {
.name = "serial8250",
.id = PLAT8250_DEV_PLATFORM,
.dev = {
.platform_data = debug_uart_platform_data,
},
};
static struct tegra_utmip_config utmi_phy_config[] = {
[0] = {
.hssync_start_delay = 0,
.idle_wait_delay = 17,
.elastic_limit = 16,
.term_range_adj = 6,
.xcvr_setup = 15,
.xcvr_lsfslew = 2,
.xcvr_lsrslew = 2,
},
[1] = {
.hssync_start_delay = 0,
.idle_wait_delay = 17,
.elastic_limit = 16,
.term_range_adj = 6,
.xcvr_setup = 8,
.xcvr_lsfslew = 2,
.xcvr_lsrslew = 2,
},
};
static struct tegra_ulpi_config ulpi_usb2_config = {
.reset_gpio = TEGRA_GPIO_PI5,
};
static struct tegra_ehci_platform_data tegra_ehci_pdata[] = {
[0] = {
.phy_config = &utmi_phy_config[0],
.operating_mode = TEGRA_USB_HOST,
.power_down_on_bus_suspend = 0,
},
[1] = {
.phy_config = &ulpi_usb2_config,
.operating_mode = TEGRA_USB_HOST,
.power_down_on_bus_suspend = 0,
.phy_type = TEGRA_USB_PHY_TYPE_LINK_ULPI,
},
[2] = {
.phy_config = &utmi_phy_config[1],
.operating_mode = TEGRA_USB_HOST,
.power_down_on_bus_suspend = 0,
},
};
static void p852_usb_gpio_config(void)
{
unsigned int usbeth_mux_gpio = 0, usb_ena_val;
unsigned int has_onboard_ethernet = 0;
unsigned int p852_eth_reset = TEGRA_GPIO_PD3;
switch (system_rev) {
case P852_SKU13_B00:
case P852_SKU23_B00:
case P852_SKU23_C01:
case P852_SKU8_B00:
case P852_SKU8_C01:
case P852_SKU9_B00:
case P852_SKU9_C01:
{
usbeth_mux_gpio = TEGRA_GPIO_PS3;
has_onboard_ethernet = 1;
usb_ena_val = 1;
}
break;
case P852_SKU5_B00:
case P852_SKU5_C01:
{
usb_ena_val = 1;
has_onboard_ethernet = 0;
}
break;
case P852_SKU1:
{
has_onboard_ethernet = 0;
usb_ena_val = 0;
strncpy(enable_usb3, "usb", sizeof(enable_usb3));
}
break;
case P852_SKU1_B00:
case P852_SKU1_C0X:
{
has_onboard_ethernet = 0;
usb_ena_val = 1;
strncpy(enable_usb3, "usb", sizeof(enable_usb3));
}
break;
default:
{
usbeth_mux_gpio = TEGRA_GPIO_PD4;
has_onboard_ethernet = 1;
usb_ena_val = 0;
}
}
if (has_onboard_ethernet) {
gpio_request_one(usbeth_mux_gpio, GPIOF_OUT_INIT_LOW,
"eth_ena");
tegra_gpio_enable(usbeth_mux_gpio);
/* eth reset */
gpio_request_one(p852_eth_reset, GPIOF_OUT_INIT_LOW,
"eth_reset");
tegra_gpio_enable(p852_eth_reset);
udelay(1);
gpio_direction_output(p852_eth_reset, 1);
if (!strcmp(enable_usb3, "eth"))
gpio_direction_output(usbeth_mux_gpio, 1);
/* exporting usbeth_mux_gpio */
gpio_export(usbeth_mux_gpio, true);
}
if (!strcmp(enable_usb3, "usb")) {
gpio_direction_output(TEGRA_GPIO_PB2, usb_ena_val);
gpio_direction_output(TEGRA_GPIO_PW1, usb_ena_val);
}
}
static struct platform_device *p852_uart_devices[] __initdata = {
&tegra_uarta_device,
&tegra_uartb_device,
&tegra_uartc_device,
&tegra_uartd_device,
};
static struct platform_device *p852_8250_uart_devices[] __initdata = {
&tegra_8250_uarta_device,
&tegra_8250_uartb_device,
&tegra_8250_uartc_device,
&tegra_8250_uartd_device,
&tegra_8250_uarte_device,
};
static struct platform_device tegra_itu656 = {
.name = "tegra_itu656",
.id = -1,
};
static struct platform_device *p852_devices[] __initdata = {
&tegra_gart_device,
&tegra_avp_device,
&tegra_itu656,
};
static struct tegra_nor_platform_data p852_nor_data = {
.flash = {
.map_name = "cfi_probe",
.width = 2,
},
.chip_parms = {
/* FIXME: use characterized clock freq */
.timing_default = {
.timing0 = 0xA0200253,
.timing1 = 0x00040406,
},
.timing_read = {
.timing0 = 0xA0200253,
.timing1 = 0x00000A00,
},
},
};
#ifdef CONFIG_TEGRA_SPI_I2S
struct spi_board_info tegra_spi_i2s_device __initdata = {
.modalias = "spi_i2s_pcm",
.bus_num = 2,
.chip_select = 2,
.mode = SPI_MODE_0,
.max_speed_hz = 18000000,
.platform_data = NULL,
.irq = 0,
};
void __init p852_spi_i2s_init(void)
{
struct tegra_spi_i2s_platform_data *pdata;
pdata = (struct tegra_spi_i2s_platform_data *)
tegra_spi_i2s_device.platform_data;
if (pdata->gpio_i2s.active_state) {
gpio_request_one(pdata->gpio_i2s.gpio_no, GPIOF_OUT_INIT_LOW,
"i2s_cpld_dir1");
} else {
gpio_request_one(pdata->gpio_i2s.gpio_no, GPIOF_OUT_INIT_HIGH,
"i2s_cpld_dir1");
}
tegra_gpio_enable(pdata->gpio_i2s.gpio_no);
if (pdata->gpio_spi.active_state) {
gpio_request_one(pdata->gpio_spi.gpio_no, GPIOF_OUT_INIT_LOW,
"spi_cpld_dir2");
} else {
gpio_request_one(pdata->gpio_spi.gpio_no, GPIOF_OUT_INIT_HIGH,
"spi_cpld_dir2");
}
tegra_gpio_enable(pdata->gpio_spi.gpio_no);
spi_register_board_info(&tegra_spi_i2s_device, 1);
}
#endif
#if defined(CONFIG_SPI_TEGRA) && defined(CONFIG_SPI_SPIDEV)
static struct spi_board_info tegra_spi_devices[] __initdata = {
{
.modalias = "spidev",
.bus_num = 0,
.chip_select = 0,
.mode = SPI_MODE_0,
.max_speed_hz = 18000000,
.platform_data = NULL,
.irq = 0,
},
{
.modalias = "spidev",
.bus_num = 1,
.chip_select = 1,
.mode = SPI_MODE_0,
.max_speed_hz = 18000000,
.platform_data = NULL,
.irq = 0,
},
{
.modalias = "spidev",
.bus_num = 3,
.chip_select = 1,
.mode = SPI_MODE_0,
.max_speed_hz = 18000000,
.platform_data = NULL,
.irq = 0,
},
};
static void __init p852_register_spidev(void)
{
spi_register_board_info(tegra_spi_devices,
ARRAY_SIZE(tegra_spi_devices));
}
#else
#define p852_register_spidev() do {} while (0)
#endif
static void __init p852_usb_init(void)
{
p852_usb_gpio_config();
/*
if (system_rev == P852_SKU8)
{
platform_device_register(&tegra_udc_device);
}
else
*/
{
tegra_ehci1_device.dev.platform_data = &tegra_ehci_pdata[0];
platform_device_register(&tegra_ehci1_device);
}
if (!(p852_sku_peripherals & P852_SKU_ULPI_DISABLE)) {
tegra_ehci2_device.dev.platform_data = &tegra_ehci_pdata[1];
platform_device_register(&tegra_ehci2_device);
}
tegra_ehci3_device.dev.platform_data = &tegra_ehci_pdata[2];
platform_device_register(&tegra_ehci3_device);
}
static void __init spi3_pingroup_clear_tristate(void)
{
/* spi3 mosi, miso, cs, clk */
tegra_pinmux_set_tristate(TEGRA_PINGROUP_LSDI, TEGRA_TRI_NORMAL);
tegra_pinmux_set_tristate(TEGRA_PINGROUP_LSDA, TEGRA_TRI_NORMAL);
tegra_pinmux_set_tristate(TEGRA_PINGROUP_LCSN, TEGRA_TRI_NORMAL);
tegra_pinmux_set_tristate(TEGRA_PINGROUP_LSCK, TEGRA_TRI_NORMAL);
}
static void __init p852_spi_init(void)
{
if (p852_sku_peripherals & P852_SKU_SPI_ENABLE) {
int i = 0;
unsigned int spi_config = 0;
unsigned int spi3_config =
(p852_spi_peripherals >> P852_SPI3_SHIFT) & P852_SPI_MASK;
for (i = 0; i < P852_MAX_SPI; i++) {
spi_config =
(p852_spi_peripherals >> (P852_SPI_SHIFT * i)) &
P852_SPI_MASK;
if (spi_config & P852_SPI_ENABLE) {
if (spi_config & P852_SPI_SLAVE)
p852_spi_devices[i]->name =
"tegra_spi_slave";
platform_device_register(p852_spi_devices[i]);
}
}
/* Default spi3 pingroups are in tristate */
if (spi3_config & P852_SPI_ENABLE)
spi3_pingroup_clear_tristate();
}
}
static void __init p852_uart_init(void)
{
if (p852_sku_peripherals & P852_SKU_UART_ENABLE) {
int i = 0;
unsigned int uart_config = 0, uart8250Id = 0;
int debug_console = -1;
/* register the debug console as the first serial console */
for (i = 0; i < P852_MAX_UART; i++) {
uart_config =
(p852_uart_peripherals >> (P852_UART_SHIFT * i));
if (uart_config & P852_UART_DB) {
debug_console = i;
debug_uart_platform_data[0].membase =
IO_ADDRESS(p852_uart_bases[i]);
debug_uart_platform_data[0].mapbase =
p852_uart_bases[i];
debug_uart_platform_data[0].irq =
p852_uart_irqs[i];
uart8250Id++;
platform_device_register(&debug_uart);
break;
}
}
/* register remaining UARTS */
for (i = 0; i < P852_MAX_UART; i++) {
uart_config =
(p852_uart_peripherals >> (P852_UART_SHIFT * i)) &
P852_UART_MASK;
if ((uart_config & P852_UART_ENABLE)
&& i != debug_console) {
if (uart_config & P852_UART_HS) {
platform_device_register
(p852_uart_devices[i]);
} else {
p852_8250_uart_devices[i]->id =
uart8250Id++;
platform_device_register
(p852_8250_uart_devices[i]);
}
}
}
}
}
static struct platform_device generic_codec_driver = {
.name = "generic-dit",
};
static void __init p852_flash_init(void)
{
if (p852_sku_peripherals & P852_SKU_NAND_ENABLE)
platform_device_register(&p852_nand_device);
if (p852_sku_peripherals & P852_SKU_NOR_ENABLE) {
tegra_nor_device.resource[2].end = TEGRA_NOR_FLASH_BASE + SZ_64M - 1;
tegra_nor_device.dev.platform_data = &p852_nor_data;
platform_device_register(&tegra_nor_device);
}
}
void __init p852_common_init(void)
{
tegra_clk_init_from_table(p852_clk_init_table);
p852_pinmux_init();
p852_i2c_init();
p852_regulator_init();
p852_uart_init();
p852_flash_init();
platform_add_devices(p852_devices, ARRAY_SIZE(p852_devices));
//p852_panel_init();
p852_spi_init();
p852_register_spidev();
p852_usb_init();
p852_sdhci_init();
p852_gpio_init();
}
void __init tegra_p852_init(void)
{
switch (system_rev) {
case P852_SKU3:
p852_sku3_init();
break;
case P852_SKU13:
p852_sku13_init();
break;
case P852_SKU13_B00:
case P852_SKU13_C01:
p852_sku13_b00_init();
break;
case P852_SKU23:
p852_sku23_init();
break;
case P852_SKU23_B00:
p852_sku23_b00_init();
break;
case P852_SKU23_C01:
p852_sku23_c01_init();
break;
case P852_SKU1:
p852_sku1_init();
break;
case P852_SKU11:
case P852_SKU1_B00:
p852_sku1_b00_init();
break;
case P852_SKU1_C0X:
p852_sku1_c0x_init();
break;
case P852_SKU5_B00:
p852_sku5_b00_init();
break;
case P852_SKU5_C01:
p852_sku5_c01_init();
break;
case P852_SKU8_B00:
p852_sku8_b00_init();
break;
case P852_SKU8_C01:
p852_sku8_c00_init();
break;
case P852_SKU9_B00:
p852_sku9_b00_init();
break;
case P852_SKU9_C01:
p852_sku9_c00_init();
break;
default:
printk(KERN_ERR "Unknow Board Revision\n");
break;
}
}
static void __init tegra_p852_reserve(void)
{
switch (system_rev) {
case P852_SKU3:
case P852_SKU5_B00:
case P852_SKU5_C01:
case P852_SKU9_B00:
case P852_SKU9_C01:
tegra_reserve(SZ_64M + SZ_16M, SZ_8M, 0);
break;
default:
tegra_reserve(SZ_128M, SZ_8M, 0);
break;
}
}
MACHINE_START(P852, "Tegra P852")
.boot_params = 0x00000100,
.map_io = tegra_map_common_io,
.reserve = tegra_p852_reserve,
.init_early = tegra_init_early,
.init_irq = tegra_init_irq,
.timer = &tegra_timer,
.init_machine = tegra_p852_init,
MACHINE_END