diff options
author | Gary King <gking@nvidia.com> | 2009-12-15 13:37:56 -0800 |
---|---|---|
committer | Gary King <gking@nvidia.com> | 2009-12-15 18:42:25 -0800 |
commit | 34c5f91521ca1533ad0407519ee797c141aedf74 (patch) | |
tree | 0035195e6439629f0173de2c3a2172cc8db2d10b /arch | |
parent | 2788a80231389279dce99263dee1109b4947a5db (diff) |
tegra: add generic machine initialization and platform device registration
adds platform device driver registration routines, UART, SDIO, etc init for
the MACH_TEGRA_GENERIC machine
Change-Id: I16e8d328731bbbb5c042260bf5073b6cdee35eab
Diffstat (limited to 'arch')
-rw-r--r-- | arch/arm/mach-tegra/Makefile | 2 | ||||
-rw-r--r-- | arch/arm/mach-tegra/board_nvodm.c | 420 | ||||
-rw-r--r-- | arch/arm/mach-tegra/init_common.c | 794 |
3 files changed, 1216 insertions, 0 deletions
diff --git a/arch/arm/mach-tegra/Makefile b/arch/arm/mach-tegra/Makefile index a3acef069c1d..dea16e4d80ca 100644 --- a/arch/arm/mach-tegra/Makefile +++ b/arch/arm/mach-tegra/Makefile @@ -38,6 +38,8 @@ obj-$(CONFIG_MACH_TEGRA_GENERIC) += nvodm/ obj-$(CONFIG_MACH_TEGRA_GENERIC) += odm_kit/ obj-$(CONFIG_MACH_TEGRA_GENERIC) += nvos_user.o obj-$(CONFIG_MACH_TEGRA_GENERIC) += nvrm_user.o +obj-$(CONFIG_MACH_TEGRA_GENERIC) += init_common.o +obj-$(CONFIG_MACH_TEGRA_GENERIC) += board_nvodm.o # Misc drivers obj-$(CONFIG_TEGRA_ODM_RFKILL) += tegra_rfkill_odm.o diff --git a/arch/arm/mach-tegra/board_nvodm.c b/arch/arm/mach-tegra/board_nvodm.c new file mode 100644 index 000000000000..f6aaddf059c1 --- /dev/null +++ b/arch/arm/mach-tegra/board_nvodm.c @@ -0,0 +1,420 @@ +/* + * arch/arm/mach-tegra/board-nvodm.c + * + * Board registration for ODM-kit generic Tegra boards + * + * Copyright (c) 2009, NVIDIA Corporation. + * + * 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/kernel.h> +#include <linux/init.h> +#include <linux/irq.h> +#include <linux/platform_device.h> +#include <linux/synaptics_i2c_rmi.h> +#include <linux/i2c.h> +#include <linux/spi/spi.h> + +#include <asm/mach-types.h> +#include <asm/mach/arch.h> + +#include <mach/board.h> + +#include <linux/mtd/mtd.h> +#include <linux/mtd/partitions.h> + +#include <linux/io.h> +#include <linux/serial_8250.h> + +#include <linux/delay.h> + +#include "nvcommon.h" +#include "nvrm_init.h" +#include "nvrm_module.h" +#include "nvrm_interrupt.h" +#include "nvrm_pinmux.h" +#include "nvrm_power.h" +#include "nvodm_query.h" +#include "nvodm_services.h" +#include "nvodm_sdio.h" +#include "nvodm_pmu.h" +#include "nvrm_gpio.h" +#include "mach/nvrm_linux.h" +#include "nvassert.h" +#include "nvodm_query_discovery.h" + +#include <../../../drivers/staging/android/timed_output.h> + +#if defined(CONFIG_USB_ANDROID) || defined(CONFIG_USB_ANDROID_MODULE) +#include <linux/usb/android.h> +#endif + +extern struct sys_timer tegra_timer; +extern const char* tegra_boot_device; +extern void __init tegra_init_irq(void); +extern void __init tegra_map_common_io(void); + + +#ifdef CONFIG_DEVNVMAP +static struct platform_device nvmap_device = { + .name = "nvmap_drv" +}; +#endif + +#if defined(CONFIG_USB_ANDROID) || defined(CONFIG_USB_ANDROID_MODULE) +static struct android_usb_platform_data android_usb_plat = +{ + .vendor_id = 0x0955, + .product_id = 0x7000, + .adb_product_id = 0x7100, + .product_name = "ADB Composite Device", + .manufacturer_name = "NVIDIA Corporation", + .nluns = 1, +}; + +static struct platform_device android_usb_device = +{ + .name = "android_usb", + .dev = + { + .platform_data = &android_usb_plat, + }, +}; +#endif + +#if defined(CONFIG_USB_GADGETFS) || defined(CONFIG_USB_GADGETFS_MODULE) +static struct platform_device android_gadgetfs_device = +{ + .name = "gadgetfs", + .id = -1, +}; +#endif + +#if defined(CONFIG_BATTERY_TEGRA_ODM) || defined(CONFIG_TEGRA_BATTERY_NVEC) +static struct platform_device tegra_battery_device = +{ + .name = "tegra_battery", + .id = -1, +}; +#endif + +#ifdef CONFIG_MTD_NAND_TEGRA +static struct platform_device tegra_nand_device = +{ + .name = "tegra_nand", + .id = -1, +}; +#endif + + +#ifdef CONFIG_RTC_DRV_TEGRA_ODM +static struct platform_device tegra_rtc_device = +{ + .name = "tegra_rtc", + .id = -1, +}; +#endif + +#ifdef CONFIG_TOUCHSCREEN_TEGRA_ODM +static struct platform_device tegra_touch_device = +{ + .name = "tegra_touch", + .id = -1, +}; +#endif + +#ifdef CONFIG_INPUT_TEGRA_ODM_ACCEL +static struct platform_device tegra_accelerometer_device = +{ + .name = "tegra_accelerometer", + .id = -1, +}; +#endif + +#ifdef CONFIG_KEYBOARD_TEGRA +static struct platform_device tegra_kbc_device = +{ + .name = "tegra_kbc", + .id = -1, +}; +#endif + +#ifdef CONFIG_INPUT_TEGRA_ODM_SCROLL +static struct platform_device tegra_scrollwheel_device = +{ + .name = "tegra_scrollwheel", + .id = -1, +}; +#endif + +#ifdef CONFIG_TEGRA_ODM_VIBRATE +static struct timed_output_dev tegra_vibrator_device = { + .name = "tegra_vibrator", +}; +#endif + +#ifdef CONFIG_TEGRA_ODM_RFKILL +static struct platform_device tegra_rfkill = +{ + .name = "tegra_rfkill", + .id = -1, +}; +#endif + + +/* FIXME: NvBl uses 57.6k for FPGAs. 16x multiplier for UART baud rate + * should be chip-dependent. */ +#define TARGET_BAUD_RATE 115200 +static void __init NvGetUartClockRange(NvU32 BaudBitRate, NvU32 *pTargetClkKHz, + NvU32 *pMinClkKHz, NvU32 *pMaxClkKHz) +{ + NvU32 TargetClkKHz = (BaudBitRate * 16) / 1000; + // DDK uses +- 5% tolerance. We use +- 6.25% to remove the extra divides + *pMinClkKHz = TargetClkKHz - (TargetClkKHz>>4); + *pMaxClkKHz = TargetClkKHz + (TargetClkKHz>>4); + *pTargetClkKHz = TargetClkKHz; +} + +static void __init NvConfigDebugConsole( + NvRmDeviceHandle hRm) +{ + NvOdmDebugConsole Console = NvOdmQueryDebugConsole(); + struct plat_serial8250_port *pUartDebugPort = NULL; + struct platform_device *pDebugConsole = NULL; + NvU32 ModId = 0; + + /* The debug console uses the standard serial 8250 driver, + * rather than the power-managed Tegra UART driver */ + if (((NvU32)Console >= (NvU32)NvOdmDebugConsole_UartA) && + ((NvU32)Console <= (NvU32)NvOdmDebugConsole_UartE)) + { + NvU32 Port = (NvU32)(Console - NvOdmDebugConsole_UartA); + NvU32 Clk, TargetClk, MinClk, MaxClk, Temp; + + ModId = NVRM_MODULE_ID(NvRmModuleID_Uart, Port); + + if (NvRmSetModuleTristate(hRm, ModId, NV_FALSE)!=NvSuccess) + goto exit_fail; + + NvGetUartClockRange(TARGET_BAUD_RATE, &TargetClk, &MinClk, &MaxClk); + + if (NvRmPowerModuleClockConfig(hRm, ModId, 0, MinClk, MaxClk, + &TargetClk, 1, &Clk, 0)!=NvSuccess) + goto cleanup_ts; + + if (NvRmPowerModuleClockControl(hRm, ModId, 0, NV_TRUE)!=NvSuccess) + goto cleanup_ts; + + NvRmModuleReset(hRm, ModId); + pDebugConsole = (struct platform_device *) + NvOsAlloc(sizeof(struct platform_device)); + if (!pDebugConsole) + goto cleanup; + pUartDebugPort = (struct plat_serial8250_port *) + NvOsAlloc(2*sizeof(struct plat_serial8250_port)); + if (!pUartDebugPort) + goto cleanup; + + NvOsMemset(pUartDebugPort, 0, 2*sizeof(struct plat_serial8250_port)); + NvOsMemset(pDebugConsole, 0, sizeof(struct platform_device)); + pDebugConsole->name = "serial8250"; + pDebugConsole->id = PLAT8250_DEV_PLATFORM; + + NvRmModuleGetBaseAddress(hRm, ModId, &pUartDebugPort->mapbase, &Temp); + pUartDebugPort->membase = IO_ADDRESS(pUartDebugPort->mapbase); + pUartDebugPort->uartclk = Clk * 1000; + pUartDebugPort->irq = NvRmGetIrqForLogicalInterrupt(hRm, ModId, 0); + pUartDebugPort->iotype = UPIO_MEM32; + pUartDebugPort->regshift = 2; + pUartDebugPort->flags = UPF_BOOT_AUTOCONF; + pDebugConsole->dev.platform_data = pUartDebugPort; + if (platform_device_register(pDebugConsole)) + { + NV_ASSERT(!"Unable to register debug console device"); + } + } + + return; + + cleanup: + if (pDebugConsole) + NvOsFree(pDebugConsole); + if (pUartDebugPort) + NvOsFree(pUartDebugPort); + (void) NvRmPowerModuleClockControl(hRm, ModId, 0, NV_FALSE); + cleanup_ts: + (void) NvRmSetModuleTristate(hRm, ModId, NV_TRUE); + exit_fail: + return; +} + +extern void __init tegra_common_init(void); +extern void __init tegra_clk_init(void); +#ifdef CONFIG_TEGRA_DPRAM +extern void __init tegra_init_snor_controller(void); +#endif + +#if !(defined(CONFIG_ENC28J60) && defined(CONFIG_SPI_TEGRA)) +#define register_enc28j60() do {} while (0) +#else +static struct spi_board_info tegra_spi_devices[] __initdata = { + { + .modalias = "enc28j60", + .bus_num = 1, + .chip_select = 0, + .mode = SPI_MODE_0, + .max_speed_hz = 18000000, + .platform_data = NULL, + .irq = 0, + }, +}; + +static void __init register_enc28j60(void) +{ + NvError err; + NvRmGpioPinHandle hPin; + NvU32 irq; + NvU32 instance = 0xFFFF; + NvU32 cs = 0xFFF; + NvU32 pin = 0xFFFF, port = 0xFFFF; + const NvOdmPeripheralConnectivity *pConnectivity = NULL; + int i; + const NvOdmQuerySpiDeviceInfo *pSpiDeviceInfo; + + pConnectivity = + NvOdmPeripheralGetGuid(NV_ODM_GUID('e','n','c','2','8','j','6','0')); + if (!pConnectivity) + return; + + for (i = 0; i < pConnectivity->NumAddress; i++) + { + switch (pConnectivity->AddressList[i].Interface) + { + case NvOdmIoModule_Spi: + instance = pConnectivity->AddressList[i].Instance; + cs = pConnectivity->AddressList[i].Address; + break; + case NvOdmIoModule_Gpio: + port = pConnectivity->AddressList[i].Instance; + pin = pConnectivity->AddressList[i].Address; + break; + default: + break; + } + } + + /* SPI ethernet driver needs one SPI info and a gpio for interrupt */ + if (instance == 0xffff || cs == 0xffff || port == 0xFFFF || pin == 0xFFFF) + return; + + /* Check if the SPI is configured as a master for this instance + * If it it not, don't register the device. + * */ + pSpiDeviceInfo = NvOdmQuerySpiGetDeviceInfo(NvOdmIoModule_Spi, instance, cs); + if (pSpiDeviceInfo && pSpiDeviceInfo->IsSlave) + return; + + err = NvRmGpioAcquirePinHandle(s_hGpioGlobal, port, pin, &hPin); + if (err) + { + return; + } + NvRmGpioConfigPins(s_hGpioGlobal, &hPin, 1, + NvRmGpioPinMode_InputInterruptFallingEdge); + NvRmGpioGetIrqs(s_hRmGlobal, &hPin, &irq, 1); + + printk("Enabled SPI driver\n"); + + tegra_spi_devices[0].irq = irq; + /* FIXME, instance need not be same as bus number. */ + tegra_spi_devices[0].bus_num = instance; + tegra_spi_devices[0].chip_select = cs; + spi_register_board_info(tegra_spi_devices, ARRAY_SIZE(tegra_spi_devices)); +} +#endif + +static void __init tegra_machine_init(void) +{ + tegra_common_init(); + tegra_clk_init(); + NvConfigDebugConsole(s_hRmGlobal); + +#ifdef CONFIG_TEGRA_DPRAM + tegra_init_snor_controller(); +#endif + +#ifdef CONFIG_TOUCHSCREEN_TEGRA_ODM + (void) platform_device_register(&tegra_touch_device); +#endif + +#ifdef CONFIG_DEVNVMAP + (void) platform_device_register(&nvmap_device); +#endif + +#ifdef CONFIG_INPUT_TEGRA_ODM_ACCEL + (void) platform_device_register(&tegra_accelerometer_device); +#endif + +#ifdef CONFIG_TEGRA_ODM_VIBRATE + (void) timed_output_dev_register(&tegra_vibrator_device); +#endif + + register_enc28j60(); + + /* register the devices */ +#ifdef CONFIG_MTD_NAND_TEGRA + if (tegra_boot_device && !NvOsMemcmp(tegra_boot_device, "nand", 4)) + (void) platform_device_register(&tegra_nand_device); +#endif + +#ifdef CONFIG_RTC_DRV_TEGRA_ODM + (void) platform_device_register(&tegra_rtc_device); +#endif + +#ifdef CONFIG_KEYBOARD_TEGRA + (void) platform_device_register(&tegra_kbc_device); +#endif + +#if defined(CONFIG_BATTERY_TEGRA_ODM) || defined(CONFIG_TEGRA_BATTERY_NVEC) + (void) platform_device_register(&tegra_battery_device); +#endif + +#if defined(CONFIG_USB_ANDROID) || defined(CONFIG_USB_ANDROID_MODULE) + (void) platform_device_register(&android_usb_device); +#endif +#if defined(CONFIG_USB_GADGETFS) || defined(CONFIG_USB_GADGETFS_MODULE) + (void) platform_device_register(&android_gadgetfs_device); +#endif + +#ifdef CONFIG_INPUT_TEGRA_ODM_SCROLL + (void) platform_device_register(&tegra_scrollwheel_device); +#endif + + +#ifdef CONFIG_TEGRA_ODM_RFKILL + (void) platform_device_register(&tegra_rfkill); +#endif +} + +MACHINE_START(TEGRA_GENERIC, "Tegra generic") + + .boot_params = 0x00000100, + .map_io = tegra_map_common_io, + .init_irq = tegra_init_irq, + .init_machine = tegra_machine_init, + .timer = &tegra_timer, + +MACHINE_END diff --git a/arch/arm/mach-tegra/init_common.c b/arch/arm/mach-tegra/init_common.c new file mode 100644 index 000000000000..97bd0cb1da0e --- /dev/null +++ b/arch/arm/mach-tegra/init_common.c @@ -0,0 +1,794 @@ +/* + * arch/arm/mach-tegra/init_common.c + * + * Miscellaneous driver registration routines for Tegra + * + * Copyright (c) 2009, NVIDIA Corporation. + * + * 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/kernel.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/fsl_devices.h> +#include <linux/dma-mapping.h> +#include "nvcommon.h" +#include "nvrm_init.h" +#include "nvrm_drf.h" +#include "mach/nvrm_linux.h" +#include "nvos.h" +#include "nvutil.h" +#include "nvassert.h" +#include "nvrm_hardware_access.h" +#include "ap15/arapb_misc.h" +#include "nvrm_module.h" +#include "nvodm_modules.h" +#include "nvodm_query.h" +#include "nvrm_arm_cp.h" +#include "nvrm_interrupt.h" +#include "ap20/arusb.h" + +const char *tegra_partition_list = NULL; +char *tegra_boot_device = NULL; +NvRmGpioHandle s_hGpioGlobal = NULL; + +/* + * The format for the partition list command line parameter is + * tagrapart=<linux_name>:<start_sector>:<length_in_sectors>:<sector_size>,... + */ +static int __init tegrapart_setup(char *options) +{ + if (options && *options && !tegra_partition_list) + tegra_partition_list = options; + + return 0; +} + +__setup("tegrapart=", tegrapart_setup); +static int __init tegraboot_setup(char *options) +{ + tegra_boot_device = options; + return 0; + +} +__setup("tegraboot=", tegraboot_setup); +int tegra_was_boot_device(const char *boot) +{ + if (!tegra_boot_device) + return 0; + + if (!NvOsMemcmp(boot, tegra_boot_device, NvOsStrlen(boot))) + return 1; + + return 0; +} + +int tegra_get_partition_info_by_num( + int PartitionNum, + char **pName, + NvU64 *pSectorStart, + NvU64 *pSectorLength, + NvU32 *pSectorSize) +{ + const char *Ptr = tegra_partition_list; + int Cnt = 0; + int Len = 0; + + if (!Ptr) + return -1; + + while (Cnt<PartitionNum && *Ptr && *Ptr!=' ') + { + if (*Ptr==',') + Cnt++; + Ptr++; + } + + if (pName) + *pName = NULL; + + if (Cnt==PartitionNum && *Ptr!=' ' && *Ptr) + { + char *End; + NvU64 Temp; + for (Len=0; Ptr[Len] && Ptr[Len]!=' ' && Ptr[Len]!=':'; Len++) { } + if (pName) + { + *pName = NvOsAlloc(Len+1); + if (!*pName) + return -ENOMEM; + (*pName)[Len] = 0; + NvOsMemcpy(*pName, Ptr, Len); + } + Ptr += Len+1; + Temp = NvUStrtoull(Ptr, &End, 16); + if (*End!=':') + goto fail; + if (pSectorStart) + *pSectorStart = Temp; + Ptr = End+1; + Temp = NvUStrtoull(Ptr, &End, 16); + if (*End!=':') + goto fail; + if (pSectorLength) + *pSectorLength = Temp; + Ptr = End+1; + Temp = NvUStrtoull(Ptr, &End, 16); + if (*End!=',' && *End!=' ' && *End) + goto fail; + if (pSectorSize) + *pSectorSize = (NvU32)Temp; + + return 0; + } + + fail: + if (pName && *pName) + NvOsFree(*pName); + + return -1; +} + +int tegra_get_partition_info_by_name( + const char *PartName, + NvU64 *pSectorStart, + NvU64 *pSectorLength, + NvU32 *pSectorSize) +{ + int Len = NvOsStrlen(PartName); + const char *Ptr = tegra_partition_list; + char *End; + + if (!Ptr) + return -1; + + while (*Ptr && *Ptr!=' ') + { + if (!NvOsStrncmp(Ptr, PartName, Len) && Ptr[Len]==':') + { + Ptr += Len + 1; + *pSectorStart = NvUStrtoull(Ptr, &End, 16); + if (*End!=':') + return -1; + Ptr = End+1; + *pSectorLength = NvUStrtoull(Ptr, &End, 16); + if (*End!=':') + return -1; + Ptr = End+1; + *pSectorSize = NvUStrtoul(Ptr, &End, 16); + if (*End!=',' && *End!=' ' && *End) + return -1; + return 0; + } + else + { + while (*Ptr != ',' && *Ptr) + Ptr++; + if (!*Ptr) + return -1; + Ptr++; + } + } + return -1; +} + + +#if !defined(CONFIG_SPI_TEGRA) +#define tegra_register_spi() do {} while (0) +#else +static void __init tegra_register_spi(void) +{ + NvU32 Num, Cnt; + const NvU32 *pPinMuxes; + NvU32 NumPinMuxes; + struct platform_device *pDev; + const NvRmModuleID Modules[] = { NvRmModuleID_Slink, NvRmModuleID_Spi}; + const NvOdmIoModule OdmModules[] = + { NvOdmIoModule_Spi, NvOdmIoModule_Sflash }; + const NvOdmQuerySpiDeviceInfo *pSpiDeviceInfo; + unsigned int i, j, k, ToAdd; + struct tegra_spi_pdata SpiData; + + for (i=0, Cnt=0; i<NV_ARRAY_SIZE(Modules); i++) + { + Num = NvRmModuleGetNumInstances(s_hRmGlobal, Modules[i]); + NvOdmQueryPinMux(OdmModules[i], &pPinMuxes, &NumPinMuxes); + for (j=0; j<Num && j<NumPinMuxes; j++) + { + if (!pPinMuxes[j]) + continue; + + pSpiDeviceInfo = NvOdmQuerySpiGetDeviceInfo(OdmModules[i], j, 0); + if (pSpiDeviceInfo && pSpiDeviceInfo->IsSlave) + continue; + + if (pPinMuxes[j]==NvOdmSpiPinMap_Multiplexed) + ToAdd = (unsigned int)NvOdmSpiPinMap_Config6; + else + ToAdd = 1; + + for (k=0; k<ToAdd; k++) + { + pDev = platform_device_alloc("tegra_spi", Cnt); + if (!pDev) + goto fail; + Cnt++; + + SpiData.IoModuleID = OdmModules[i]; + SpiData.Instance = j; + SpiData.PinMuxConfig = + (ToAdd==1) ? 0 : (NvOdmSpiPinMap_Config1 + k); + if (platform_device_add_data(pDev, &SpiData, sizeof(SpiData))) + goto fail; + + if (platform_device_add(pDev)) + goto fail; + } + } + } + + return; + + fail: + if (pDev) + platform_device_del(pDev); + // just stop adding new devices +} +#endif + +#if !defined(CONFIG_I2C_TEGRA) +#define tegra_register_i2c() do { } while (0) +#else +static int __init tegra_map_i2c_odm_to_bus(NvOdmIoModule Module, + NvU32 Instance, NvU32 PinMuxConfig) +{ + NvOdmIoModule SearchModule; + NvU32 SearchInstance; + int cnt = 0; + + const NvU32 *pPinMuxes; + NvU32 NumPinMuxes; + + // FIXME: Pinmux multiplexing is an ugly hack.. we instantiate + // "N" buses (hard-coded to the maximum number of I2C instance 2 + // configurations), and assign peripherals to the bus ID which + // matches the requested pin mux. Too much chip-specific stuff + // here, but pin-muxing has always been ugly... + if (PinMuxConfig && (Module!=NvOdmIoModule_I2c || Instance!= 2 || + PinMuxConfig > NvOdmI2cPinMap_Config4)) + return -1; + + for (SearchModule = NvOdmIoModule_I2c_Pmu; + SearchModule >= NvOdmIoModule_I2c; + SearchModule--) + { + NvOdmQueryPinMux(SearchModule, &pPinMuxes, &NumPinMuxes); + for (SearchInstance = 0; SearchInstance < NumPinMuxes; + SearchInstance++) + { + if (!pPinMuxes[SearchInstance]) + continue; + +#ifdef CONFIG_NVEC + /* nvec uses instance 0 as I2C slave */ + if (SearchModule == NvOdmIoModule_I2c && + SearchInstance == 0) + { + continue; + } +#endif + if (SearchModule==Module && SearchInstance==Instance) + { + if (PinMuxConfig && + pPinMuxes[Instance]!=NvOdmI2cPinMap_Multiplexed) + return -1; + + if (pPinMuxes[Instance]==NvOdmI2cPinMap_Multiplexed && + !PinMuxConfig) + return -1; + + if (PinMuxConfig) + return cnt + (PinMuxConfig - NvOdmI2cPinMap_Config1); + + return cnt; + } + + if (pPinMuxes[SearchInstance]==NvOdmI2cPinMap_Multiplexed) + cnt += (int)NvOdmI2cPinMap_Config4; + else + cnt++; + } + + } + return -1; +} + +static void __init tegra_register_i2c(void) +{ + NvU32 Num, Cnt; + const NvU32 *pPinMuxes; + NvU32 NumPinMuxes; + struct platform_device *pDev; + const NvRmModuleID Modules[] = { NvRmModuleID_Dvc, NvRmModuleID_I2c }; + const NvOdmIoModule OdmModules[] = { NvOdmIoModule_I2c_Pmu, + NvOdmIoModule_I2c }; + unsigned int i, j, k, ToAdd; + struct tegra_i2c_pdata I2cData; + + + for (i=0, Cnt=0; i<NV_ARRAY_SIZE(Modules); i++) + { + Num = NvRmModuleGetNumInstances(s_hRmGlobal, Modules[i]); + NvOdmQueryPinMux(OdmModules[i], &pPinMuxes, &NumPinMuxes); + /* nvec uses i2c instance 0 as I2C slave */ + for (j=0; j<Num && j<NumPinMuxes; j++) + { + if (!pPinMuxes[j]) + continue; + + if (pPinMuxes[j]==NvOdmI2cPinMap_Multiplexed) + ToAdd = (unsigned int)NvOdmI2cPinMap_Config4; + else + ToAdd = 1; + + for (k=0; k<ToAdd; k++) + { + pDev = platform_device_alloc("tegra_i2c", Cnt); + if (!pDev) + goto fail; + Cnt++; + + I2cData.IoModuleID = OdmModules[i]; + I2cData.Instance = j; + I2cData.PinMuxConfig = + (ToAdd==1) ? 0 : (NvOdmI2cPinMap_Config1 + k); + // FIXME: Always defaulting to 100KHz for now. + I2cData.ClockInKHz = 100; + if (platform_device_add_data(pDev, &I2cData, sizeof(I2cData))) + goto fail; + + if (platform_device_add(pDev)) + goto fail; + } + + } + } + + return; + + fail: + if (pDev) + platform_device_del(pDev); + // just stop adding new devices +} +#endif + +#if !defined(CONFIG_SERIAL_TEGRA_DDK) +#define tegra_register_uart() do {} while (0) +#else +void __init tegra_register_uart(void) +{ + struct platform_device *pDev = NULL; + NvU32 NumberOfUarts; + NvU32 i; + NvOdmDebugConsole Console; + NvU32 Port = ~0; + + Console = NvOdmQueryDebugConsole(); + NumberOfUarts = NvRmModuleGetNumInstances(s_hRmGlobal, + NvRmModuleID_Uart); + + /* Skip the UART port used as a debug console */ + if (((NvU32)Console >= (NvU32)NvOdmDebugConsole_UartA) && + ((NvU32)Console <= (NvU32)NvOdmDebugConsole_UartE)) + { + Port = (NvU32)(Console - NvOdmDebugConsole_UartA); + } + + for (i=0; i< NumberOfUarts ; i++) + { + if (i == Port) + continue; + + pDev = platform_device_alloc("tegra_uart", i); + if (!pDev) + goto fail; + if (platform_device_add(pDev)) + goto fail; + } +fail: + if (pDev) + return; +} +#endif + +/* FIXME: Needed for filling the USB gadget device platform data structure */ +#if !defined(CONFIG_USB_TEGRA) +#define tegra_register_usb_gadget() do {} while (0) +#define tegra_is_udc(p) 0 +#else + +#ifdef CONFIG_ARCH_TEGRA_1x_SOC +static inline unsigned long tegra_get_phy_base(void) +{ + NvRmPhysAddr pa; + NvU32 len; + + NvU32 mod = NVRM_MODULE_ID(NvRmModuleID_Misc, 0); + NvRmModuleGetBaseAddress(s_hRmGlobal, mod, &pa, &len); + return (unsigned long)pa; +} +#else +#define tegra_get_phy_base() ~0UL +#endif + +static u64 tegra_udc_dma_mask = DMA_32BIT_MASK; + +static void __init tegra_register_usb_gadget(void) +{ + struct fsl_usb2_platform_data pdata; + struct platform_device *platdev = NULL; + NvU32 port_count, i; + + port_count = NvRmModuleGetNumInstances(s_hRmGlobal, NvRmModuleID_Usb2Otg); + + for (i=0; i<port_count && !platdev; i++) { + const NvOdmUsbProperty *p; + struct resource *res; + NvU32 mod = NVRM_MODULE_ID(NvRmModuleID_Usb2Otg, i); + unsigned long phy_addr = tegra_get_phy_base(); + NvRmPhysAddr cont_addr; + NvU32 len; + NvU16 irq; + + /* fixme: add ulpi here? */ + p = NvOdmQueryGetUsbProperty(NvOdmIoModule_Usb, i); + if (!p || !(p->UsbMode & NvOdmUsbModeType_Device)) + continue; + + irq = NvRmGetIrqForLogicalInterrupt(s_hRmGlobal, mod, 0); + NvRmModuleGetBaseAddress(s_hRmGlobal, mod, &cont_addr, &len); + if (irq==0xffff || !(~cont_addr) || !len) + continue; + + platdev = platform_device_alloc("tegra-udc", i); + if (!platdev) { + pr_err("unable to allocate platform device for tegra-udc\n"); + goto fail; + } + + res = kzalloc(sizeof(struct resource)*3, GFP_KERNEL); + res[0].flags = IORESOURCE_MEM; + res[0].start = cont_addr; + res[0].end = cont_addr + len - 1; + res[2].flags = IORESOURCE_IRQ; + res[2].start = res[2].end = irq; + if (phy_addr != ~0UL) { + res[1].flags = IORESOURCE_MEM; + res[1].start = phy_addr + APB_MISC_PP_USB_PHY_SELF_TEST_0; + res[1].end = phy_addr + APB_MISC_PP_USB_PHY_ALT_VBUS_STS_0 + 4 - 1; + } + if (platform_device_add_resources(platdev, res, 3)) { + pr_err("unable to add resources to tegra-udc device\n"); + goto fail; + } + memset(&pdata, 0, sizeof(pdata)); + /* FIXME: add support for ULPI and HSIC here */ + pdata.phy_mode = FSL_USB2_PHY_UTMI; + pdata.operating_mode = FSL_USB2_DR_DEVICE; + if (platform_device_add_data(platdev, &pdata, sizeof(pdata))) { + pr_err("unable to add data to tegra-udc device\n"); + goto fail; + } + + if (platform_device_add(platdev)) { + pr_err("unable to add tegra-udc device\n"); + goto fail; + } + + platdev->dev.coherent_dma_mask = ~0; + platdev->dev.dma_mask = &tegra_udc_dma_mask; + } +fail: + ; +} +/* when both device & host are enabled w/o OTG, the first USB port specified + * with device capabilities is registered as tegra-udc, the rest (if Host is also' + * specified for the ports) are registered as tegra-ehci + */ +static inline int tegra_is_udc(const NvOdmUsbProperty *p) +{ + static int dev_found = 0; + int prev = dev_found; + + dev_found |= (p->UsbMode & NvOdmUsbModeType_Device); + + return (p->UsbMode & NvOdmUsbModeType_Device) && !prev; +} +#endif /* CONFIG_USB_TEGRA */ + +#if !defined(CONFIG_USB_TEGRA_HCD) +#define tegra_register_usb_host() do {} while (0) +#else +static void __init tegra_register_usb_host(void) +{ + NvU32 port_count, i; + + port_count = NvRmModuleGetNumInstances(s_hRmGlobal, NvRmModuleID_Usb2Otg); + + for (i=0; i<port_count; i++) { + const NvOdmUsbProperty *p; + struct platform_device *platdev = NULL; + struct tegra_hcd_platform_data pdata; + + NvU32 mod = NVRM_MODULE_ID(NvRmModuleID_Usb2Otg, i); + NvRmPhysAddr cont_addr; + NvU32 len; + NvU16 irq; + + /* fixme: add ulpi here? */ + p = NvOdmQueryGetUsbProperty(NvOdmIoModule_Usb, i); + if (!p || !(p->UsbMode & NvOdmUsbModeType_Host) || tegra_is_udc(p)) + continue; + + platdev = platform_device_alloc("tegra-ehci", i); + if (!platdev) { + pr_err("unable to allocate device for tegra-ehci\n"); + goto fail; + } + + irq = NvRmGetIrqForLogicalInterrupt(s_hRmGlobal, mod, 0); + NvRmModuleGetBaseAddress(s_hRmGlobal, mod, &cont_addr, &len); + if (irq==0xffff || !(~cont_addr) || !len) + continue; + + platdev = platform_device_alloc("tegra-udc", i); + if (!platdev) { + pr_err("unable to allocate platform device for tegra-udc\n"); + goto fail; + } + + memset(&pdata, 0, sizeof(pdata)); + pdata.instance = i; + + if (platform_device_add_data(platdev, &pdata, sizeof(pdata))) { + pr_err("unable to add data to tegra-ehci device\n"); + goto fail; + } + + if (platform_device_add(platdev)) { + pr_err("unable to add tegra-ehci device\n"); + goto fail; + } + } +fail: + ; +} +#endif + +void __init tegra_register_usb(void) +{ + tegra_register_usb_gadget(); + tegra_register_usb_host(); +} + +#define MAX_SDIO_INSTANCES 8 + +#if !(defined(CONFIG_MMC_SDHCI_TEGRA) || defined(CONFIG_MMC_TEGRA_SDIO)) +#define tegra_register_sdio() do {} while (0) +#else +#ifdef CONFIG_MMC_SDHCI_TEGRA +#define tegra_register_sdio() tegra_register_sdio_int("tegra-sdhci") +#else +#define tegra_register_sdio() tegra_register_sdio_int("tegra-sdio") +#endif + +#define register_sdio(_drv, _cnt, _boot, _comparison, _fail) \ + do { \ + NvU32 i; \ + for (i=0; i<(_cnt); i++) { \ + const NvOdmQuerySdioInterfaceProperty *prop; \ + struct platform_device *platdev; \ + struct tegra_sdio_pdata pdata; \ + if (i==(_boot)) \ + continue; \ + prop = NvOdmQueryGetSdioInterfaceProperty(i); \ + if (!prop || !_comparison(prop)) \ + continue; \ + platdev = platform_device_alloc((_drv), i); \ + pdata.StartOffset = 0; \ + if (!platdev) { \ + pr_err("error allocating SDIO devices\n"); \ + _fail; \ + } \ + if (platform_device_add_data(platdev, &pdata, sizeof(pdata))) { \ + pr_err("error adding platform data to SDIO devices\n"); \ + _fail; \ + } \ + if (platform_device_add(platdev)) { \ + pr_err("error adding SDIO platform devices\n"); \ + _fail; \ + } \ + } \ + } while (0) + + +#define is_media_slot(port) ((port)->usage == NvOdmQuerySdioSlotUsage_Media) + +#define is_used_slot(port) ((port)->usage != NvOdmQuerySdioSlotUsage_unused) + +#define is_sdio_slot(port) (!is_media_slot(port) && is_used_slot(port)) + +static void __init tegra_register_sdio_int(const char *driver_name) +{ + NvU32 port_count; + NvU32 boot_id = (NvU32)-1; + + port_count = NvRmModuleGetNumInstances(s_hRmGlobal, + NvRmModuleID_Sdio); + BUG_ON(port_count > MAX_SDIO_INSTANCES); + + /* register the boot device first, so that it always registers as + * mmcblk0 + */ + if (tegra_boot_device && !memcmp(tegra_boot_device, "sdmmc", 5)) { + struct platform_device *platdev; + struct tegra_sdio_pdata pdata; + NvU64 start, length; + NvU32 sector_size; + boot_id = 3; + tegra_get_partition_info_by_name("mbr", &start, &length, §or_size); + pdata.StartOffset = start * (NvU64)sector_size; + platdev = platform_device_alloc(driver_name, boot_id); + if (!platdev) { + pr_err("unable to allocate device memory for SDIO boot device\n"); + goto fail; + } + if (platform_device_add_data(platdev, &pdata, sizeof(pdata))) { + pr_err("failed to add data to SDIO boot device\n"); + goto fail; + } + if (platform_device_add(platdev)) { + pr_err("failed to add SDIO boot device\n"); + goto fail; + } + } + + register_sdio(driver_name, port_count, boot_id, is_media_slot, goto fail); + register_sdio(driver_name, port_count, boot_id, is_sdio_slot, goto fail); + +fail: + ; +} +#endif + +#if !defined(CONFIG_CACHE_L2X0) +#define tegra_pl310_init() do {} while (0) +#else +#include <asm/hardware/cache-l2x0.h> +#include "ap20/arpl310.h" +static void __init tegra_pl310_init(void) +{ + NvRmPhysAddr CachePa; + NvU32 Len; + volatile NvU8 *pCache = NULL; + NvU32 AuxValue = + NV_DRF_NUM(PL310, AUXILIARY_CONTROL, FULL_LINE_OF_ZERO, 1) | + NV_DRF_NUM(PL310, AUXILIARY_CONTROL, SO_DEV_HIGH_PRIORITY, 0) | + /* FIXME: Read performance tests show ~8-10% performance loss (uniprocessor + * config) when L1/L2 exclusive operation is enabled for L1 miss / L2 hit heavy + * tests, and up to 30% performance loss in some extreme cases. Need to + * understand this better before enabling this bit */ + NV_DRF_NUM(PL310, AUXILIARY_CONTROL, EXCLUSIVE, 0) | + NV_DRF_DEF(PL310, AUXILIARY_CONTROL, WAY_SIZE, WAY_128KB) | + NV_DRF_DEF(PL310, AUXILIARY_CONTROL, ASSOCIATIVITY, ASSOC_8) | + NV_DRF_NUM(PL310, AUXILIARY_CONTROL, PARITY, 0) | + NV_DRF_NUM(PL310, AUXILIARY_CONTROL, EVENT_MONITOR_BUS, 0) | + NV_DRF_NUM(PL310, AUXILIARY_CONTROL, NON_SECURE_LOCKDOWN_WR, 1) | + NV_DRF_NUM(PL310, AUXILIARY_CONTROL, NON_SECURE_INTERRUPT_ACCESS, 1) | + NV_DRF_NUM(PL310, AUXILIARY_CONTROL, DATA_PREFETCH, 0) | + NV_DRF_NUM(PL310, AUXILIARY_CONTROL, INSTRUCTION_PREFETCH, 1) | + NV_DRF_DEF(PL310, AUXILIARY_CONTROL, FORCE_WRITE_ALLOCATE, DISABLED) | + NV_DRF_NUM(PL310, AUXILIARY_CONTROL, SHARED_ATTRIBUTE_OVERRIDE, 0) | + NV_DRF_NUM(PL310, AUXILIARY_CONTROL, EARLY_BRESP, 1); + + if (!NvRmModuleGetNumInstances(s_hRmGlobal, NvRmPrivModuleID_Pl310)) + return; + + NvRmModuleGetBaseAddress(s_hRmGlobal, + NVRM_MODULE_ID(NvRmPrivModuleID_Pl310, 0), &CachePa, &Len); + + if (NvRmPhysicalMemMap(CachePa, Len, NVOS_MEM_READ_WRITE, + NvOsMemAttribute_Uncached, (void **)&pCache)!=NvSuccess) + { + printk(__FILE__ ":%d failed to map PL310\n", __LINE__); + return; + } + + NV_WRITE32(pCache + PL310_TAG_RAM_LATENCY_0, + NV_DRF_DEF(PL310, TAG_RAM_LATENCY, SETUP, SW_DEFAULT) | + NV_DRF_DEF(PL310, TAG_RAM_LATENCY, READ, SW_DEFAULT) | + NV_DRF_DEF(PL310, TAG_RAM_LATENCY, WRITE, SW_DEFAULT)); + NV_WRITE32(pCache + PL310_DATA_RAM_LATENCY_0, + NV_DRF_DEF(PL310, DATA_RAM_LATENCY, SETUP, SW_DEFAULT) | + NV_DRF_DEF(PL310, DATA_RAM_LATENCY, READ, SW_DEFAULT) | + NV_DRF_DEF(PL310, DATA_RAM_LATENCY, WRITE, SW_DEFAULT)); + + if (NV_DRF_VAL(PL310, AUXILIARY_CONTROL, EXCLUSIVE, AuxValue) || + NV_DRF_VAL(PL310, AUXILIARY_CONTROL, FULL_LINE_OF_ZERO, AuxValue)) + { + unsigned long flags; + NvU32 Reg; + local_irq_save(flags); + MRC(p15, 0, Reg, c1, c0, 1); + if (NV_DRF_VAL(PL310, AUXILIARY_CONTROL, EXCLUSIVE, AuxValue)) + Reg |= (1<<7); + else + Reg &= ~(1<<7); + + if (NV_DRF_VAL(PL310, AUXILIARY_CONTROL, FULL_LINE_OF_ZERO, AuxValue)) + Reg |= (1<<3); + else + Reg &= ~(1<<3); + + MCR(p15, 0, Reg, c1, c0, 1); + local_irq_restore(flags); + } + l2x0_init((void __iomem *)pCache, AuxValue, 0x8200c3fe); +} +#endif + + +#if defined(CONFIG_ARCH_TEGRA_1x_SOC) +extern void __init NvAp15InitFlowController(void); +#if defined(CONFIG_CACHE_TEGRA_CMC) +extern void __init tegra_cmc_enable(void); +#else +#define tegra_cmc_enable() do {} while (0) +#endif + +static void __init tegra_init_cpu(void) +{ + tegra_cmc_enable(); + NvAp15InitFlowController(); +} + +#elif defined(CONFIG_ARCH_TEGRA_2x_SOC) +extern void __init NvAp20InitFlowController(void); + +static void __init tegra_init_cpu(void) +{ + tegra_pl310_init(); + NvAp20InitFlowController(); +} + +#else +#error "Unrecognized Tegra SoC family" +#endif + +void __init tegra_common_init(void) +{ + NV_ASSERT_SUCCESS(NvRmOpen(&s_hRmGlobal,0)); + NV_ASSERT_SUCCESS(NvRmGpioOpen(s_hRmGlobal, &s_hGpioGlobal)); + + tegra_init_cpu(); + tegra_register_i2c(); + tegra_register_spi(); + tegra_register_uart(); + tegra_register_sdio(); + tegra_register_usb(); +} + |