Merge branch 'for-linus' of git://android.git.kernel.org/kernel/tegra
* 'for-linus' of git://android.git.kernel.org/kernel/tegra: (61 commits) ARM: tegra: trimslice: initialize PCI-e only when running on TrimSlice ARM: tegra: add PCI Express power gating ARM: tegra: PCIE minor code refactoring ARM: Tegra: DMA: Fail safe if initialization fails ARM: Tegra: Rename clk_dev1/2 to cdev1/2 ARM: Tegra: Rename I2S clocks to match driver name ARM: Tegra: Make tegra_dma_init a postcore_initcall ARM: tegra: add seaboard, wario and kaen boards ARM: tegra: harmony: fix pinmux for MMC slot ARM: tegra: harmony: register sdhci devices ARM: tegra: remove stale nvidia atag handler ARM: tegra: common device resources ARM: tegra: harmony: move over to tegra_gpio_config ARM: tegra: add tegra_gpio_table and tegra_gpio_config ARM: tegra: Hide EMC scaling config behind ARCH_TEGRA ARM: tegra: Fix typo in TEGRA_IRQ_TO_GPIO ARM: tegra: common: Enable core clocks ARM: tegra: timer: Enable timer and rtc clocks ARM: tegra: Move tegra_common_init to tegra_init_early ARM: tegra: clock: prevent accidental disables of cpu clock ...
This commit is contained in:
commit
0bbf211975
123
arch/arm/configs/tegra_defconfig
Normal file
123
arch/arm/configs/tegra_defconfig
Normal file
|
@ -0,0 +1,123 @@
|
|||
CONFIG_EXPERIMENTAL=y
|
||||
CONFIG_IKCONFIG=y
|
||||
CONFIG_IKCONFIG_PROC=y
|
||||
CONFIG_CGROUPS=y
|
||||
CONFIG_CGROUP_DEBUG=y
|
||||
CONFIG_CGROUP_FREEZER=y
|
||||
CONFIG_CGROUP_CPUACCT=y
|
||||
CONFIG_RESOURCE_COUNTERS=y
|
||||
CONFIG_CGROUP_SCHED=y
|
||||
CONFIG_RT_GROUP_SCHED=y
|
||||
CONFIG_BLK_DEV_INITRD=y
|
||||
CONFIG_EMBEDDED=y
|
||||
# CONFIG_SYSCTL_SYSCALL is not set
|
||||
# CONFIG_ELF_CORE is not set
|
||||
CONFIG_SLAB=y
|
||||
CONFIG_MODULES=y
|
||||
CONFIG_MODULE_UNLOAD=y
|
||||
CONFIG_MODULE_FORCE_UNLOAD=y
|
||||
# CONFIG_BLK_DEV_BSG is not set
|
||||
# CONFIG_IOSCHED_DEADLINE is not set
|
||||
# CONFIG_IOSCHED_CFQ is not set
|
||||
CONFIG_ARCH_TEGRA=y
|
||||
CONFIG_MACH_HARMONY=y
|
||||
CONFIG_TEGRA_DEBUG_UARTD=y
|
||||
CONFIG_ARM_ERRATA_742230=y
|
||||
CONFIG_NO_HZ=y
|
||||
CONFIG_HIGH_RES_TIMERS=y
|
||||
CONFIG_SMP=y
|
||||
CONFIG_NR_CPUS=2
|
||||
CONFIG_PREEMPT=y
|
||||
CONFIG_AEABI=y
|
||||
# CONFIG_OABI_COMPAT is not set
|
||||
CONFIG_HIGHMEM=y
|
||||
CONFIG_ZBOOT_ROM_TEXT=0x0
|
||||
CONFIG_ZBOOT_ROM_BSS=0x0
|
||||
CONFIG_VFP=y
|
||||
CONFIG_PM=y
|
||||
CONFIG_NET=y
|
||||
CONFIG_PACKET=y
|
||||
CONFIG_UNIX=y
|
||||
CONFIG_NET_KEY=y
|
||||
CONFIG_INET=y
|
||||
CONFIG_INET_ESP=y
|
||||
# CONFIG_INET_XFRM_MODE_TUNNEL is not set
|
||||
# CONFIG_INET_XFRM_MODE_BEET is not set
|
||||
# CONFIG_INET_LRO is not set
|
||||
# CONFIG_INET_DIAG is not set
|
||||
CONFIG_IPV6=y
|
||||
CONFIG_IPV6_PRIVACY=y
|
||||
CONFIG_IPV6_ROUTER_PREF=y
|
||||
CONFIG_IPV6_OPTIMISTIC_DAD=y
|
||||
CONFIG_INET6_AH=y
|
||||
CONFIG_INET6_ESP=y
|
||||
CONFIG_INET6_IPCOMP=y
|
||||
CONFIG_IPV6_MIP6=y
|
||||
CONFIG_IPV6_TUNNEL=y
|
||||
CONFIG_IPV6_MULTIPLE_TABLES=y
|
||||
# CONFIG_WIRELESS is not set
|
||||
# CONFIG_FIRMWARE_IN_KERNEL is not set
|
||||
CONFIG_BLK_DEV_LOOP=y
|
||||
CONFIG_MISC_DEVICES=y
|
||||
CONFIG_AD525X_DPOT=y
|
||||
CONFIG_AD525X_DPOT_I2C=y
|
||||
CONFIG_ICS932S401=y
|
||||
CONFIG_APDS9802ALS=y
|
||||
CONFIG_ISL29003=y
|
||||
CONFIG_NETDEVICES=y
|
||||
CONFIG_DUMMY=y
|
||||
# CONFIG_NETDEV_1000 is not set
|
||||
# CONFIG_NETDEV_10000 is not set
|
||||
# CONFIG_WLAN is not set
|
||||
# CONFIG_INPUT is not set
|
||||
# CONFIG_SERIO is not set
|
||||
# CONFIG_VT is not set
|
||||
# CONFIG_DEVKMEM is not set
|
||||
CONFIG_SERIAL_8250=y
|
||||
CONFIG_SERIAL_8250_CONSOLE=y
|
||||
# CONFIG_LEGACY_PTYS is not set
|
||||
# CONFIG_HW_RANDOM is not set
|
||||
CONFIG_I2C=y
|
||||
# CONFIG_HWMON is not set
|
||||
# CONFIG_MFD_SUPPORT is not set
|
||||
# CONFIG_USB_SUPPORT is not set
|
||||
CONFIG_MMC=y
|
||||
CONFIG_MMC_SDHCI=y
|
||||
CONFIG_MMC_SDHCI_PLTFM=y
|
||||
CONFIG_EXT2_FS=y
|
||||
CONFIG_EXT2_FS_XATTR=y
|
||||
CONFIG_EXT2_FS_POSIX_ACL=y
|
||||
CONFIG_EXT2_FS_SECURITY=y
|
||||
CONFIG_EXT3_FS=y
|
||||
# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
|
||||
CONFIG_EXT3_FS_POSIX_ACL=y
|
||||
CONFIG_EXT3_FS_SECURITY=y
|
||||
# CONFIG_DNOTIFY is not set
|
||||
CONFIG_VFAT_FS=y
|
||||
CONFIG_TMPFS=y
|
||||
CONFIG_NLS_CODEPAGE_437=y
|
||||
CONFIG_NLS_ISO8859_1=y
|
||||
CONFIG_PRINTK_TIME=y
|
||||
CONFIG_MAGIC_SYSRQ=y
|
||||
CONFIG_DEBUG_FS=y
|
||||
CONFIG_DEBUG_KERNEL=y
|
||||
CONFIG_DETECT_HUNG_TASK=y
|
||||
CONFIG_SCHEDSTATS=y
|
||||
CONFIG_TIMER_STATS=y
|
||||
CONFIG_DEBUG_SLAB=y
|
||||
# CONFIG_DEBUG_PREEMPT is not set
|
||||
CONFIG_DEBUG_MUTEXES=y
|
||||
CONFIG_DEBUG_SPINLOCK_SLEEP=y
|
||||
CONFIG_DEBUG_INFO=y
|
||||
CONFIG_DEBUG_VM=y
|
||||
CONFIG_DEBUG_SG=y
|
||||
# CONFIG_RCU_CPU_STALL_DETECTOR is not set
|
||||
CONFIG_DEBUG_LL=y
|
||||
CONFIG_EARLY_PRINTK=y
|
||||
CONFIG_CRYPTO_ECB=y
|
||||
CONFIG_CRYPTO_AES=y
|
||||
CONFIG_CRYPTO_ARC4=y
|
||||
CONFIG_CRYPTO_TWOFISH=y
|
||||
# CONFIG_CRYPTO_ANSI_CPRNG is not set
|
||||
CONFIG_CRC_CCITT=y
|
||||
CONFIG_CRC16=y
|
|
@ -27,6 +27,31 @@ config MACH_HARMONY
|
|||
help
|
||||
Support for nVidia Harmony development platform
|
||||
|
||||
config MACH_KAEN
|
||||
bool "Kaen board"
|
||||
select MACH_SEABOARD
|
||||
help
|
||||
Support for the Kaen version of Seaboard
|
||||
|
||||
config MACH_SEABOARD
|
||||
bool "Seaboard board"
|
||||
help
|
||||
Support for nVidia Seaboard development platform. It will
|
||||
also be included for some of the derivative boards that
|
||||
have large similarities with the seaboard design.
|
||||
|
||||
config MACH_TRIMSLICE
|
||||
bool "TrimSlice board"
|
||||
select TEGRA_PCI
|
||||
help
|
||||
Support for CompuLab TrimSlice platform
|
||||
|
||||
config MACH_WARIO
|
||||
bool "Wario board"
|
||||
select MACH_SEABOARD
|
||||
help
|
||||
Support for the Wario version of Seaboard
|
||||
|
||||
choice
|
||||
prompt "Low-level debug console UART"
|
||||
default TEGRA_DEBUG_UART_NONE
|
||||
|
@ -58,4 +83,7 @@ config TEGRA_SYSTEM_DMA
|
|||
Adds system DMA functionality for NVIDIA Tegra SoCs, used by
|
||||
several Tegra device drivers
|
||||
|
||||
config TEGRA_EMC_SCALING_ENABLE
|
||||
bool "Enable scaling the memory frequency"
|
||||
|
||||
endif
|
||||
|
|
|
@ -1,14 +1,16 @@
|
|||
obj-y += common.o
|
||||
obj-y += devices.o
|
||||
obj-y += io.o
|
||||
obj-y += irq.o legacy_irq.o
|
||||
obj-y += clock.o
|
||||
obj-y += timer.o
|
||||
obj-y += gpio.o
|
||||
obj-y += pinmux.o
|
||||
obj-y += powergate.o
|
||||
obj-y += fuse.o
|
||||
obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += clock.o
|
||||
obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra2_clocks.o
|
||||
obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra2_dvfs.o
|
||||
obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra2_emc.o
|
||||
obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += pinmux-t2-tables.o
|
||||
obj-$(CONFIG_SMP) += platsmp.o localtimer.o headsmp.o
|
||||
obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o
|
||||
|
@ -19,3 +21,9 @@ obj-$(CONFIG_TEGRA_PCI) += pcie.o
|
|||
obj-${CONFIG_MACH_HARMONY} += board-harmony.o
|
||||
obj-${CONFIG_MACH_HARMONY} += board-harmony-pinmux.o
|
||||
obj-${CONFIG_MACH_HARMONY} += board-harmony-pcie.o
|
||||
|
||||
obj-${CONFIG_MACH_SEABOARD} += board-seaboard.o
|
||||
obj-${CONFIG_MACH_SEABOARD} += board-seaboard-pinmux.o
|
||||
|
||||
obj-${CONFIG_MACH_TRIMSLICE} += board-trimslice.o
|
||||
obj-${CONFIG_MACH_TRIMSLICE} += board-trimslice-pinmux.o
|
||||
|
|
|
@ -15,8 +15,10 @@
|
|||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <mach/pinmux.h>
|
||||
|
||||
#include "gpio-names.h"
|
||||
#include "board-harmony.h"
|
||||
|
||||
static struct tegra_pingroup_config harmony_pinmux[] = {
|
||||
|
@ -34,10 +36,10 @@ static struct tegra_pingroup_config harmony_pinmux[] = {
|
|||
{TEGRA_PINGROUP_DAP3, TEGRA_MUX_DAP3, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
|
||||
{TEGRA_PINGROUP_DAP4, TEGRA_MUX_DAP4, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
|
||||
{TEGRA_PINGROUP_DDC, TEGRA_MUX_I2C2, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_DTA, TEGRA_MUX_SDIO2, TEGRA_PUPD_PULL_UP, TEGRA_TRI_TRISTATE},
|
||||
{TEGRA_PINGROUP_DTB, TEGRA_MUX_RSVD1, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
|
||||
{TEGRA_PINGROUP_DTA, TEGRA_MUX_SDIO2, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_DTB, TEGRA_MUX_RSVD1, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_DTC, TEGRA_MUX_RSVD1, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
|
||||
{TEGRA_PINGROUP_DTD, TEGRA_MUX_SDIO2, TEGRA_PUPD_PULL_UP, TEGRA_TRI_TRISTATE},
|
||||
{TEGRA_PINGROUP_DTD, TEGRA_MUX_SDIO2, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_DTE, TEGRA_MUX_RSVD1, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
|
||||
{TEGRA_PINGROUP_DTF, TEGRA_MUX_I2C3, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
|
||||
{TEGRA_PINGROUP_GMA, TEGRA_MUX_SDIO4, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
|
||||
|
@ -138,7 +140,18 @@ static struct tegra_pingroup_config harmony_pinmux[] = {
|
|||
{TEGRA_PINGROUP_XM2D, TEGRA_MUX_NONE, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
|
||||
};
|
||||
|
||||
static struct tegra_gpio_table gpio_table[] = {
|
||||
{ .gpio = TEGRA_GPIO_PI5, .enable = true }, /* mmc2 cd */
|
||||
{ .gpio = TEGRA_GPIO_PH1, .enable = true }, /* mmc2 wp */
|
||||
{ .gpio = TEGRA_GPIO_PT3, .enable = true }, /* mmc2 pwr */
|
||||
{ .gpio = TEGRA_GPIO_PH2, .enable = true }, /* mmc4 cd */
|
||||
{ .gpio = TEGRA_GPIO_PH3, .enable = true }, /* mmc4 wp */
|
||||
{ .gpio = TEGRA_GPIO_PI6, .enable = true }, /* mmc4 pwr */
|
||||
};
|
||||
|
||||
void harmony_pinmux_init(void)
|
||||
{
|
||||
tegra_pinmux_config_table(harmony_pinmux, ARRAY_SIZE(harmony_pinmux));
|
||||
|
||||
tegra_gpio_config(gpio_table, ARRAY_SIZE(gpio_table));
|
||||
}
|
||||
|
|
|
@ -30,35 +30,13 @@
|
|||
|
||||
#include <mach/iomap.h>
|
||||
#include <mach/irqs.h>
|
||||
#include <mach/sdhci.h>
|
||||
|
||||
#include "board.h"
|
||||
#include "board-harmony.h"
|
||||
#include "clock.h"
|
||||
|
||||
/* NVidia bootloader tags */
|
||||
#define ATAG_NVIDIA 0x41000801
|
||||
|
||||
#define ATAG_NVIDIA_RM 0x1
|
||||
#define ATAG_NVIDIA_DISPLAY 0x2
|
||||
#define ATAG_NVIDIA_FRAMEBUFFER 0x3
|
||||
#define ATAG_NVIDIA_CHIPSHMOO 0x4
|
||||
#define ATAG_NVIDIA_CHIPSHMOOPHYS 0x5
|
||||
#define ATAG_NVIDIA_PRESERVED_MEM_0 0x10000
|
||||
#define ATAG_NVIDIA_PRESERVED_MEM_N 2
|
||||
#define ATAG_NVIDIA_FORCE_32 0x7fffffff
|
||||
|
||||
struct tag_tegra {
|
||||
__u32 bootarg_key;
|
||||
__u32 bootarg_len;
|
||||
char bootarg[1];
|
||||
};
|
||||
|
||||
static int __init parse_tag_nvidia(const struct tag *tag)
|
||||
{
|
||||
|
||||
return 0;
|
||||
}
|
||||
__tagtable(ATAG_NVIDIA, parse_tag_nvidia);
|
||||
#include "devices.h"
|
||||
#include "gpio-names.h"
|
||||
|
||||
static struct plat_serial8250_port debug_uart_platform_data[] = {
|
||||
{
|
||||
|
@ -84,6 +62,9 @@ static struct platform_device debug_uart = {
|
|||
|
||||
static struct platform_device *harmony_devices[] __initdata = {
|
||||
&debug_uart,
|
||||
&tegra_sdhci_device1,
|
||||
&tegra_sdhci_device2,
|
||||
&tegra_sdhci_device4,
|
||||
};
|
||||
|
||||
static void __init tegra_harmony_fixup(struct machine_desc *desc,
|
||||
|
@ -102,22 +83,45 @@ static __initdata struct tegra_clk_init_table harmony_clk_init_table[] = {
|
|||
{ NULL, NULL, 0, 0},
|
||||
};
|
||||
|
||||
|
||||
static struct tegra_sdhci_platform_data sdhci_pdata1 = {
|
||||
.cd_gpio = -1,
|
||||
.wp_gpio = -1,
|
||||
.power_gpio = -1,
|
||||
};
|
||||
|
||||
static struct tegra_sdhci_platform_data sdhci_pdata2 = {
|
||||
.cd_gpio = TEGRA_GPIO_PI5,
|
||||
.wp_gpio = TEGRA_GPIO_PH1,
|
||||
.power_gpio = TEGRA_GPIO_PT3,
|
||||
};
|
||||
|
||||
static struct tegra_sdhci_platform_data sdhci_pdata4 = {
|
||||
.cd_gpio = TEGRA_GPIO_PH2,
|
||||
.wp_gpio = TEGRA_GPIO_PH3,
|
||||
.power_gpio = TEGRA_GPIO_PI6,
|
||||
.is_8bit = 1,
|
||||
};
|
||||
|
||||
static void __init tegra_harmony_init(void)
|
||||
{
|
||||
tegra_common_init();
|
||||
|
||||
tegra_clk_init_from_table(harmony_clk_init_table);
|
||||
|
||||
harmony_pinmux_init();
|
||||
|
||||
tegra_sdhci_device1.dev.platform_data = &sdhci_pdata1;
|
||||
tegra_sdhci_device2.dev.platform_data = &sdhci_pdata2;
|
||||
tegra_sdhci_device4.dev.platform_data = &sdhci_pdata4;
|
||||
|
||||
platform_add_devices(harmony_devices, ARRAY_SIZE(harmony_devices));
|
||||
}
|
||||
|
||||
MACHINE_START(HARMONY, "harmony")
|
||||
.boot_params = 0x00000100,
|
||||
.fixup = tegra_harmony_fixup,
|
||||
.init_irq = tegra_init_irq,
|
||||
.init_machine = tegra_harmony_init,
|
||||
.map_io = tegra_map_common_io,
|
||||
.init_early = tegra_init_early,
|
||||
.init_irq = tegra_init_irq,
|
||||
.timer = &tegra_timer,
|
||||
.init_machine = tegra_harmony_init,
|
||||
MACHINE_END
|
||||
|
|
179
arch/arm/mach-tegra/board-seaboard-pinmux.c
Normal file
179
arch/arm/mach-tegra/board-seaboard-pinmux.c
Normal file
|
@ -0,0 +1,179 @@
|
|||
/*
|
||||
* Copyright (C) 2010 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 <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/gpio.h>
|
||||
|
||||
#include <mach/pinmux.h>
|
||||
#include <mach/pinmux-t2.h>
|
||||
|
||||
#include "gpio-names.h"
|
||||
#include "board-seaboard.h"
|
||||
|
||||
#define DEFAULT_DRIVE(_name) \
|
||||
{ \
|
||||
.pingroup = TEGRA_DRIVE_PINGROUP_##_name, \
|
||||
.hsm = TEGRA_HSM_DISABLE, \
|
||||
.schmitt = TEGRA_SCHMITT_ENABLE, \
|
||||
.drive = TEGRA_DRIVE_DIV_1, \
|
||||
.pull_down = TEGRA_PULL_31, \
|
||||
.pull_up = TEGRA_PULL_31, \
|
||||
.slew_rising = TEGRA_SLEW_SLOWEST, \
|
||||
.slew_falling = TEGRA_SLEW_SLOWEST, \
|
||||
}
|
||||
|
||||
static __initdata struct tegra_drive_pingroup_config seaboard_drive_pinmux[] = {
|
||||
DEFAULT_DRIVE(SDIO1),
|
||||
};
|
||||
|
||||
static __initdata struct tegra_pingroup_config seaboard_pinmux[] = {
|
||||
{TEGRA_PINGROUP_ATA, TEGRA_MUX_IDE, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_ATB, TEGRA_MUX_SDIO4, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_ATC, TEGRA_MUX_NAND, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_ATD, TEGRA_MUX_GMI, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_ATE, TEGRA_MUX_GMI, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
|
||||
{TEGRA_PINGROUP_CDEV1, TEGRA_MUX_PLLA_OUT, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_CDEV2, TEGRA_MUX_PLLP_OUT4, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_CRTP, TEGRA_MUX_CRT, TEGRA_PUPD_PULL_UP, TEGRA_TRI_TRISTATE},
|
||||
{TEGRA_PINGROUP_CSUS, TEGRA_MUX_VI_SENSOR_CLK, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
|
||||
{TEGRA_PINGROUP_DAP1, TEGRA_MUX_DAP1, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_DAP2, TEGRA_MUX_DAP2, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
|
||||
{TEGRA_PINGROUP_DAP3, TEGRA_MUX_DAP3, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
|
||||
{TEGRA_PINGROUP_DAP4, TEGRA_MUX_DAP4, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_DDC, TEGRA_MUX_RSVD2, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
|
||||
{TEGRA_PINGROUP_DTA, TEGRA_MUX_VI, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_DTB, TEGRA_MUX_VI, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_DTC, TEGRA_MUX_VI, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_DTD, TEGRA_MUX_VI, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_DTE, TEGRA_MUX_VI, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_TRISTATE},
|
||||
{TEGRA_PINGROUP_DTF, TEGRA_MUX_I2C3, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_GMA, TEGRA_MUX_SDIO4, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_GMB, TEGRA_MUX_GMI, TEGRA_PUPD_PULL_UP, TEGRA_TRI_TRISTATE},
|
||||
{TEGRA_PINGROUP_GMC, TEGRA_MUX_UARTD, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_GMD, TEGRA_MUX_SFLASH, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_GME, TEGRA_MUX_SDIO4, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_GPU, TEGRA_MUX_PWM, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_GPU7, TEGRA_MUX_RTCK, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_GPV, TEGRA_MUX_PCIE, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
|
||||
{TEGRA_PINGROUP_HDINT, TEGRA_MUX_HDMI, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
|
||||
{TEGRA_PINGROUP_I2CP, TEGRA_MUX_I2C, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_IRRX, TEGRA_MUX_UARTB, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_IRTX, TEGRA_MUX_UARTB, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_KBCA, TEGRA_MUX_KBC, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_KBCB, TEGRA_MUX_KBC, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_KBCC, TEGRA_MUX_KBC, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_KBCD, TEGRA_MUX_KBC, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_KBCE, TEGRA_MUX_KBC, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_KBCF, TEGRA_MUX_KBC, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_LCSN, TEGRA_MUX_RSVD4, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
|
||||
{TEGRA_PINGROUP_LD0, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_LD1, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_LD10, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_LD11, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_LD12, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_LD13, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_LD14, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_LD15, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_LD16, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_LD17, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_LD2, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_LD3, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_LD4, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_LD5, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_LD6, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_LD7, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_LD8, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_LD9, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_LDC, TEGRA_MUX_RSVD4, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
|
||||
{TEGRA_PINGROUP_LDI, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_LHP0, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_LHP1, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_LHP2, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_LHS, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_LM0, TEGRA_MUX_RSVD4, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_LM1, TEGRA_MUX_CRT, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
|
||||
{TEGRA_PINGROUP_LPP, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_LPW0, TEGRA_MUX_HDMI, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_LPW1, TEGRA_MUX_RSVD4, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
|
||||
{TEGRA_PINGROUP_LPW2, TEGRA_MUX_HDMI, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_LSC0, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_LSC1, TEGRA_MUX_HDMI, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
|
||||
{TEGRA_PINGROUP_LSCK, TEGRA_MUX_HDMI, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
|
||||
{TEGRA_PINGROUP_LSDA, TEGRA_MUX_HDMI, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
|
||||
{TEGRA_PINGROUP_LSDI, TEGRA_MUX_RSVD4, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
|
||||
{TEGRA_PINGROUP_LSPI, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_LVP0, TEGRA_MUX_RSVD4, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
|
||||
{TEGRA_PINGROUP_LVP1, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_LVS, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_OWC, TEGRA_MUX_RSVD2, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
|
||||
{TEGRA_PINGROUP_PMC, TEGRA_MUX_PWR_ON, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_PTA, TEGRA_MUX_HDMI, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_RM, TEGRA_MUX_I2C, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_SDB, TEGRA_MUX_SDIO3, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_SDC, TEGRA_MUX_SDIO3, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_SDD, TEGRA_MUX_SDIO3, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_SDIO1, TEGRA_MUX_SDIO1, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_SLXA, TEGRA_MUX_PCIE, TEGRA_PUPD_PULL_UP, TEGRA_TRI_TRISTATE},
|
||||
{TEGRA_PINGROUP_SLXC, TEGRA_MUX_SPDIF, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
|
||||
{TEGRA_PINGROUP_SLXD, TEGRA_MUX_SPDIF, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_SLXK, TEGRA_MUX_PCIE, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_SPDI, TEGRA_MUX_RSVD2, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_SPDO, TEGRA_MUX_RSVD2, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_SPIA, TEGRA_MUX_GMI, TEGRA_PUPD_PULL_UP, TEGRA_TRI_TRISTATE},
|
||||
{TEGRA_PINGROUP_SPIB, TEGRA_MUX_GMI, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
|
||||
{TEGRA_PINGROUP_SPIC, TEGRA_MUX_GMI, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
|
||||
{TEGRA_PINGROUP_SPID, TEGRA_MUX_SPI1, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
|
||||
{TEGRA_PINGROUP_SPIE, TEGRA_MUX_SPI1, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
|
||||
{TEGRA_PINGROUP_SPIF, TEGRA_MUX_SPI1, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_TRISTATE},
|
||||
{TEGRA_PINGROUP_SPIG, TEGRA_MUX_SPI2_ALT, TEGRA_PUPD_PULL_UP, TEGRA_TRI_TRISTATE},
|
||||
{TEGRA_PINGROUP_SPIH, TEGRA_MUX_SPI2_ALT, TEGRA_PUPD_PULL_UP, TEGRA_TRI_TRISTATE},
|
||||
{TEGRA_PINGROUP_UAA, TEGRA_MUX_ULPI, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_UAB, TEGRA_MUX_ULPI, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_UAC, TEGRA_MUX_RSVD2, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_UAD, TEGRA_MUX_IRDA, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_UCA, TEGRA_MUX_UARTC, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_UCB, TEGRA_MUX_UARTC, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_UDA, TEGRA_MUX_ULPI, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_CK32, TEGRA_MUX_NONE, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_DDRC, TEGRA_MUX_NONE, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_PMCA, TEGRA_MUX_NONE, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_PMCB, TEGRA_MUX_NONE, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_PMCC, TEGRA_MUX_NONE, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_PMCD, TEGRA_MUX_NONE, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_PMCE, TEGRA_MUX_NONE, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_XM2C, TEGRA_MUX_NONE, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_XM2D, TEGRA_MUX_NONE, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
static struct tegra_gpio_table gpio_table[] = {
|
||||
{ .gpio = TEGRA_GPIO_PI5, .enable = true }, /* mmc2 cd */
|
||||
{ .gpio = TEGRA_GPIO_PH1, .enable = true }, /* mmc2 wp */
|
||||
{ .gpio = TEGRA_GPIO_PI6, .enable = true }, /* mmc2 pwr */
|
||||
{ .gpio = TEGRA_GPIO_LIDSWITCH, .enable = true }, /* lid switch */
|
||||
{ .gpio = TEGRA_GPIO_POWERKEY, .enable = true }, /* power key */
|
||||
};
|
||||
|
||||
void __init seaboard_pinmux_init(void)
|
||||
{
|
||||
tegra_pinmux_config_table(seaboard_pinmux, ARRAY_SIZE(seaboard_pinmux));
|
||||
|
||||
tegra_drive_pinmux_config_table(seaboard_drive_pinmux,
|
||||
ARRAY_SIZE(seaboard_drive_pinmux));
|
||||
|
||||
tegra_gpio_config(gpio_table, ARRAY_SIZE(gpio_table));
|
||||
}
|
196
arch/arm/mach-tegra/board-seaboard.c
Normal file
196
arch/arm/mach-tegra/board-seaboard.c
Normal file
|
@ -0,0 +1,196 @@
|
|||
/*
|
||||
* Copyright (c) 2010, 2011 NVIDIA Corporation.
|
||||
* Copyright (C) 2010, 2011 Google, Inc.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/serial_8250.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/gpio_keys.h>
|
||||
|
||||
#include <mach/iomap.h>
|
||||
#include <mach/irqs.h>
|
||||
#include <mach/sdhci.h>
|
||||
|
||||
#include <asm/mach-types.h>
|
||||
#include <asm/mach/arch.h>
|
||||
|
||||
#include "board.h"
|
||||
#include "board-seaboard.h"
|
||||
#include "clock.h"
|
||||
#include "devices.h"
|
||||
#include "gpio-names.h"
|
||||
|
||||
static struct plat_serial8250_port debug_uart_platform_data[] = {
|
||||
{
|
||||
/* Memory and IRQ filled in before registration */
|
||||
.flags = UPF_BOOT_AUTOCONF,
|
||||
.iotype = UPIO_MEM,
|
||||
.regshift = 2,
|
||||
.uartclk = 216000000,
|
||||
}, {
|
||||
.flags = 0,
|
||||
}
|
||||
};
|
||||
|
||||
static struct platform_device debug_uart = {
|
||||
.name = "serial8250",
|
||||
.id = PLAT8250_DEV_PLATFORM,
|
||||
.dev = {
|
||||
.platform_data = debug_uart_platform_data,
|
||||
},
|
||||
};
|
||||
|
||||
static __initdata struct tegra_clk_init_table seaboard_clk_init_table[] = {
|
||||
/* name parent rate enabled */
|
||||
{ "uartb", "pll_p", 216000000, true},
|
||||
{ "uartd", "pll_p", 216000000, true},
|
||||
{ NULL, NULL, 0, 0},
|
||||
};
|
||||
|
||||
static struct gpio_keys_button seaboard_gpio_keys_buttons[] = {
|
||||
{
|
||||
.code = SW_LID,
|
||||
.gpio = TEGRA_GPIO_LIDSWITCH,
|
||||
.active_low = 0,
|
||||
.desc = "Lid",
|
||||
.type = EV_SW,
|
||||
.wakeup = 1,
|
||||
.debounce_interval = 1,
|
||||
},
|
||||
{
|
||||
.code = KEY_POWER,
|
||||
.gpio = TEGRA_GPIO_POWERKEY,
|
||||
.active_low = 1,
|
||||
.desc = "Power",
|
||||
.type = EV_KEY,
|
||||
.wakeup = 1,
|
||||
},
|
||||
};
|
||||
|
||||
static struct gpio_keys_platform_data seaboard_gpio_keys = {
|
||||
.buttons = seaboard_gpio_keys_buttons,
|
||||
.nbuttons = ARRAY_SIZE(seaboard_gpio_keys_buttons),
|
||||
};
|
||||
|
||||
static struct platform_device seaboard_gpio_keys_device = {
|
||||
.name = "gpio-keys",
|
||||
.id = -1,
|
||||
.dev = {
|
||||
.platform_data = &seaboard_gpio_keys,
|
||||
}
|
||||
};
|
||||
|
||||
static struct tegra_sdhci_platform_data sdhci_pdata1 = {
|
||||
.cd_gpio = -1,
|
||||
.wp_gpio = -1,
|
||||
.power_gpio = -1,
|
||||
};
|
||||
|
||||
static struct tegra_sdhci_platform_data sdhci_pdata3 = {
|
||||
.cd_gpio = TEGRA_GPIO_PI5,
|
||||
.wp_gpio = TEGRA_GPIO_PH1,
|
||||
.power_gpio = TEGRA_GPIO_PI6,
|
||||
};
|
||||
|
||||
static struct tegra_sdhci_platform_data sdhci_pdata4 = {
|
||||
.cd_gpio = -1,
|
||||
.wp_gpio = -1,
|
||||
.power_gpio = -1,
|
||||
.is_8bit = 1,
|
||||
};
|
||||
|
||||
static struct platform_device *seaboard_devices[] __initdata = {
|
||||
&debug_uart,
|
||||
&tegra_pmu_device,
|
||||
&tegra_sdhci_device1,
|
||||
&tegra_sdhci_device3,
|
||||
&tegra_sdhci_device4,
|
||||
&seaboard_gpio_keys_device,
|
||||
};
|
||||
|
||||
static void __init __tegra_seaboard_init(void)
|
||||
{
|
||||
seaboard_pinmux_init();
|
||||
|
||||
tegra_clk_init_from_table(seaboard_clk_init_table);
|
||||
|
||||
tegra_sdhci_device1.dev.platform_data = &sdhci_pdata1;
|
||||
tegra_sdhci_device3.dev.platform_data = &sdhci_pdata3;
|
||||
tegra_sdhci_device4.dev.platform_data = &sdhci_pdata4;
|
||||
|
||||
platform_add_devices(seaboard_devices, ARRAY_SIZE(seaboard_devices));
|
||||
}
|
||||
|
||||
static void __init tegra_seaboard_init(void)
|
||||
{
|
||||
/* Seaboard uses UARTD for the debug port. */
|
||||
debug_uart_platform_data[0].membase = IO_ADDRESS(TEGRA_UARTD_BASE);
|
||||
debug_uart_platform_data[0].mapbase = TEGRA_UARTD_BASE;
|
||||
debug_uart_platform_data[0].irq = INT_UARTD;
|
||||
|
||||
__tegra_seaboard_init();
|
||||
}
|
||||
|
||||
static void __init tegra_kaen_init(void)
|
||||
{
|
||||
/* Kaen uses UARTB for the debug port. */
|
||||
debug_uart_platform_data[0].membase = IO_ADDRESS(TEGRA_UARTB_BASE);
|
||||
debug_uart_platform_data[0].mapbase = TEGRA_UARTB_BASE;
|
||||
debug_uart_platform_data[0].irq = INT_UARTB;
|
||||
|
||||
__tegra_seaboard_init();
|
||||
}
|
||||
|
||||
static void __init tegra_wario_init(void)
|
||||
{
|
||||
/* Wario uses UARTB for the debug port. */
|
||||
debug_uart_platform_data[0].membase = IO_ADDRESS(TEGRA_UARTB_BASE);
|
||||
debug_uart_platform_data[0].mapbase = TEGRA_UARTB_BASE;
|
||||
debug_uart_platform_data[0].irq = INT_UARTB;
|
||||
|
||||
__tegra_seaboard_init();
|
||||
}
|
||||
|
||||
|
||||
MACHINE_START(SEABOARD, "seaboard")
|
||||
.boot_params = 0x00000100,
|
||||
.map_io = tegra_map_common_io,
|
||||
.init_early = tegra_init_early,
|
||||
.init_irq = tegra_init_irq,
|
||||
.timer = &tegra_timer,
|
||||
.init_machine = tegra_seaboard_init,
|
||||
MACHINE_END
|
||||
|
||||
MACHINE_START(KAEN, "kaen")
|
||||
.boot_params = 0x00000100,
|
||||
.map_io = tegra_map_common_io,
|
||||
.init_early = tegra_init_early,
|
||||
.init_irq = tegra_init_irq,
|
||||
.timer = &tegra_timer,
|
||||
.init_machine = tegra_kaen_init,
|
||||
MACHINE_END
|
||||
|
||||
MACHINE_START(WARIO, "wario")
|
||||
.boot_params = 0x00000100,
|
||||
.map_io = tegra_map_common_io,
|
||||
.init_early = tegra_init_early,
|
||||
.init_irq = tegra_init_irq,
|
||||
.timer = &tegra_timer,
|
||||
.init_machine = tegra_wario_init,
|
||||
MACHINE_END
|
38
arch/arm/mach-tegra/board-seaboard.h
Normal file
38
arch/arm/mach-tegra/board-seaboard.h
Normal file
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* arch/arm/mach-tegra/board-seaboard.h
|
||||
*
|
||||
* Copyright (C) 2010 Google, Inc.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _MACH_TEGRA_BOARD_SEABOARD_H
|
||||
#define _MACH_TEGRA_BOARD_SEABOARD_H
|
||||
|
||||
#define TEGRA_GPIO_LIDSWITCH TEGRA_GPIO_PC7
|
||||
#define TEGRA_GPIO_USB1 TEGRA_GPIO_PD0
|
||||
#define TEGRA_GPIO_POWERKEY TEGRA_GPIO_PV2
|
||||
#define TEGRA_GPIO_BACKLIGHT TEGRA_GPIO_PD4
|
||||
#define TEGRA_GPIO_LVDS_SHUTDOWN TEGRA_GPIO_PB2
|
||||
#define TEGRA_GPIO_BACKLIGHT_PWM TEGRA_GPIO_PU5
|
||||
#define TEGRA_GPIO_BACKLIGHT_VDD TEGRA_GPIO_PW0
|
||||
#define TEGRA_GPIO_EN_VDD_PNL TEGRA_GPIO_PC6
|
||||
#define TEGRA_GPIO_MAGNETOMETER TEGRA_GPIO_PN5
|
||||
#define TEGRA_GPIO_ISL29018_IRQ TEGRA_GPIO_PZ2
|
||||
#define TEGRA_GPIO_AC_ONLINE TEGRA_GPIO_PV3
|
||||
|
||||
#define TPS_GPIO_BASE TEGRA_NR_GPIOS
|
||||
|
||||
#define TPS_GPIO_WWAN_PWR (TPS_GPIO_BASE + 2)
|
||||
|
||||
void seaboard_pinmux_init(void);
|
||||
|
||||
#endif
|
145
arch/arm/mach-tegra/board-trimslice-pinmux.c
Normal file
145
arch/arm/mach-tegra/board-trimslice-pinmux.c
Normal file
|
@ -0,0 +1,145 @@
|
|||
/*
|
||||
* arch/arm/mach-tegra/board-trimslice-pinmux.c
|
||||
*
|
||||
* Copyright (C) 2011 CompuLab, Ltd.
|
||||
*
|
||||
* 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 <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <mach/pinmux.h>
|
||||
|
||||
#include "board-trimslice.h"
|
||||
|
||||
static __initdata struct tegra_pingroup_config trimslice_pinmux[] = {
|
||||
{TEGRA_PINGROUP_ATA, TEGRA_MUX_IDE, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
|
||||
{TEGRA_PINGROUP_ATB, TEGRA_MUX_SDIO4, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_ATC, TEGRA_MUX_NAND, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
|
||||
{TEGRA_PINGROUP_ATD, TEGRA_MUX_GMI, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
|
||||
{TEGRA_PINGROUP_ATE, TEGRA_MUX_GMI, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
|
||||
{TEGRA_PINGROUP_CDEV1, TEGRA_MUX_OSC, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_CDEV2, TEGRA_MUX_PLLP_OUT4, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_TRISTATE},
|
||||
{TEGRA_PINGROUP_CRTP, TEGRA_MUX_CRT, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
|
||||
{TEGRA_PINGROUP_CSUS, TEGRA_MUX_VI_SENSOR_CLK, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_TRISTATE},
|
||||
{TEGRA_PINGROUP_DAP1, TEGRA_MUX_DAP1, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_DAP2, TEGRA_MUX_DAP2, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
|
||||
{TEGRA_PINGROUP_DAP3, TEGRA_MUX_DAP3, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_DAP4, TEGRA_MUX_DAP4, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
|
||||
{TEGRA_PINGROUP_DDC, TEGRA_MUX_I2C2, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_DTA, TEGRA_MUX_VI, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
|
||||
{TEGRA_PINGROUP_DTB, TEGRA_MUX_VI, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
|
||||
{TEGRA_PINGROUP_DTC, TEGRA_MUX_VI, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
|
||||
{TEGRA_PINGROUP_DTD, TEGRA_MUX_VI, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
|
||||
{TEGRA_PINGROUP_DTE, TEGRA_MUX_VI, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
|
||||
{TEGRA_PINGROUP_DTF, TEGRA_MUX_I2C3, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_GMA, TEGRA_MUX_SDIO4, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_GMB, TEGRA_MUX_NAND, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
|
||||
{TEGRA_PINGROUP_GMC, TEGRA_MUX_SFLASH, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_GMD, TEGRA_MUX_SFLASH, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_GME, TEGRA_MUX_GMI, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
|
||||
{TEGRA_PINGROUP_GPU, TEGRA_MUX_UARTA, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_GPU7, TEGRA_MUX_RTCK, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_GPV, TEGRA_MUX_PCIE, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_HDINT, TEGRA_MUX_HDMI, TEGRA_PUPD_PULL_UP, TEGRA_TRI_TRISTATE},
|
||||
{TEGRA_PINGROUP_I2CP, TEGRA_MUX_I2C, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
|
||||
{TEGRA_PINGROUP_IRRX, TEGRA_MUX_UARTB, TEGRA_PUPD_PULL_UP, TEGRA_TRI_TRISTATE},
|
||||
{TEGRA_PINGROUP_IRTX, TEGRA_MUX_UARTB, TEGRA_PUPD_PULL_UP, TEGRA_TRI_TRISTATE},
|
||||
{TEGRA_PINGROUP_KBCA, TEGRA_MUX_KBC, TEGRA_PUPD_PULL_UP, TEGRA_TRI_TRISTATE},
|
||||
{TEGRA_PINGROUP_KBCB, TEGRA_MUX_KBC, TEGRA_PUPD_PULL_UP, TEGRA_TRI_TRISTATE},
|
||||
{TEGRA_PINGROUP_KBCC, TEGRA_MUX_KBC, TEGRA_PUPD_PULL_UP, TEGRA_TRI_TRISTATE},
|
||||
{TEGRA_PINGROUP_KBCD, TEGRA_MUX_KBC, TEGRA_PUPD_PULL_UP, TEGRA_TRI_TRISTATE},
|
||||
{TEGRA_PINGROUP_KBCE, TEGRA_MUX_KBC, TEGRA_PUPD_PULL_UP, TEGRA_TRI_TRISTATE},
|
||||
{TEGRA_PINGROUP_KBCF, TEGRA_MUX_KBC, TEGRA_PUPD_PULL_UP, TEGRA_TRI_TRISTATE},
|
||||
{TEGRA_PINGROUP_LCSN, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_UP, TEGRA_TRI_TRISTATE},
|
||||
{TEGRA_PINGROUP_LD0, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_LD1, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_LD2, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_LD3, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_LD4, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_LD5, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_LD6, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_LD7, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_LD8, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_LD9, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_LD10, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_LD11, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_LD12, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_LD13, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_LD14, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_LD15, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_LD16, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_LD17, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_LDC, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_UP, TEGRA_TRI_TRISTATE},
|
||||
{TEGRA_PINGROUP_LDI, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_LHP0, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_LHP1, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_LHP2, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_LHS, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_LM0, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_LM1, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_UP, TEGRA_TRI_TRISTATE},
|
||||
{TEGRA_PINGROUP_LPP, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_LPW0, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_LPW1, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_UP, TEGRA_TRI_TRISTATE},
|
||||
{TEGRA_PINGROUP_LPW2, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_LSC0, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_LSC1, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_UP, TEGRA_TRI_TRISTATE},
|
||||
{TEGRA_PINGROUP_LSCK, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_UP, TEGRA_TRI_TRISTATE},
|
||||
{TEGRA_PINGROUP_LSDA, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_UP, TEGRA_TRI_TRISTATE},
|
||||
{TEGRA_PINGROUP_LSDI, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_UP, TEGRA_TRI_TRISTATE},
|
||||
{TEGRA_PINGROUP_LSPI, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_LVP0, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_UP, TEGRA_TRI_TRISTATE},
|
||||
{TEGRA_PINGROUP_LVP1, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_LVS, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_OWC, TEGRA_MUX_RSVD2, TEGRA_PUPD_PULL_UP, TEGRA_TRI_TRISTATE},
|
||||
{TEGRA_PINGROUP_PMC, TEGRA_MUX_PWR_ON, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
|
||||
{TEGRA_PINGROUP_PTA, TEGRA_MUX_RSVD3, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
|
||||
{TEGRA_PINGROUP_RM, TEGRA_MUX_I2C, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_SDB, TEGRA_MUX_PWM, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_SDC, TEGRA_MUX_PWM, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_SDD, TEGRA_MUX_PWM, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_SDIO1, TEGRA_MUX_SDIO1, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_SLXA, TEGRA_MUX_PCIE, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_SLXC, TEGRA_MUX_SDIO3, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
|
||||
{TEGRA_PINGROUP_SLXD, TEGRA_MUX_SDIO3, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
|
||||
{TEGRA_PINGROUP_SLXK, TEGRA_MUX_PCIE, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_SPDI, TEGRA_MUX_SPDIF, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
|
||||
{TEGRA_PINGROUP_SPDO, TEGRA_MUX_SPDIF, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
|
||||
{TEGRA_PINGROUP_SPIA, TEGRA_MUX_SPI2, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_TRISTATE},
|
||||
{TEGRA_PINGROUP_SPIB, TEGRA_MUX_SPI2, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_TRISTATE},
|
||||
{TEGRA_PINGROUP_SPIC, TEGRA_MUX_SPI2, TEGRA_PUPD_PULL_UP, TEGRA_TRI_TRISTATE},
|
||||
{TEGRA_PINGROUP_SPID, TEGRA_MUX_SPI1, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_TRISTATE},
|
||||
{TEGRA_PINGROUP_SPIE, TEGRA_MUX_SPI1, TEGRA_PUPD_PULL_UP, TEGRA_TRI_TRISTATE},
|
||||
{TEGRA_PINGROUP_SPIF, TEGRA_MUX_SPI1, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_TRISTATE},
|
||||
{TEGRA_PINGROUP_SPIG, TEGRA_MUX_SPI2_ALT, TEGRA_PUPD_PULL_UP, TEGRA_TRI_TRISTATE},
|
||||
{TEGRA_PINGROUP_SPIH, TEGRA_MUX_SPI2_ALT, TEGRA_PUPD_PULL_UP, TEGRA_TRI_TRISTATE},
|
||||
{TEGRA_PINGROUP_UAA, TEGRA_MUX_ULPI, TEGRA_PUPD_PULL_UP, TEGRA_TRI_TRISTATE},
|
||||
{TEGRA_PINGROUP_UAB, TEGRA_MUX_ULPI, TEGRA_PUPD_PULL_UP, TEGRA_TRI_TRISTATE},
|
||||
{TEGRA_PINGROUP_UAC, TEGRA_MUX_RSVD2, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
|
||||
{TEGRA_PINGROUP_UAD, TEGRA_MUX_IRDA, TEGRA_PUPD_PULL_UP, TEGRA_TRI_TRISTATE},
|
||||
{TEGRA_PINGROUP_UCA, TEGRA_MUX_UARTC, TEGRA_PUPD_PULL_UP, TEGRA_TRI_TRISTATE},
|
||||
{TEGRA_PINGROUP_UCB, TEGRA_MUX_UARTC, TEGRA_PUPD_PULL_UP, TEGRA_TRI_TRISTATE},
|
||||
{TEGRA_PINGROUP_UDA, TEGRA_MUX_ULPI, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
|
||||
{TEGRA_PINGROUP_CK32, TEGRA_MUX_NONE, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_DDRC, TEGRA_MUX_NONE, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_PMCA, TEGRA_MUX_NONE, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_PMCB, TEGRA_MUX_NONE, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_PMCC, TEGRA_MUX_NONE, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_PMCD, TEGRA_MUX_NONE, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_PMCE, TEGRA_MUX_NONE, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_XM2C, TEGRA_MUX_NONE, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
|
||||
{TEGRA_PINGROUP_XM2D, TEGRA_MUX_NONE, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
|
||||
};
|
||||
|
||||
void __init trimslice_pinmux_init(void)
|
||||
{
|
||||
tegra_pinmux_config_table(trimslice_pinmux, ARRAY_SIZE(trimslice_pinmux));
|
||||
}
|
106
arch/arm/mach-tegra/board-trimslice.c
Normal file
106
arch/arm/mach-tegra/board-trimslice.c
Normal file
|
@ -0,0 +1,106 @@
|
|||
/*
|
||||
* arch/arm/mach-tegra/board-trimslice.c
|
||||
*
|
||||
* Copyright (C) 2011 CompuLab, Ltd.
|
||||
* Author: Mike Rapoport <mike@compulab.co.il>
|
||||
*
|
||||
* Based on board-harmony.c
|
||||
* Copyright (C) 2010 Google, Inc.
|
||||
*
|
||||
* 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 <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/serial_8250.h>
|
||||
#include <linux/io.h>
|
||||
|
||||
#include <asm/mach-types.h>
|
||||
#include <asm/mach/arch.h>
|
||||
#include <asm/setup.h>
|
||||
|
||||
#include <mach/iomap.h>
|
||||
|
||||
#include "board.h"
|
||||
#include "clock.h"
|
||||
|
||||
#include "board-trimslice.h"
|
||||
|
||||
static struct plat_serial8250_port debug_uart_platform_data[] = {
|
||||
{
|
||||
.membase = IO_ADDRESS(TEGRA_UARTA_BASE),
|
||||
.mapbase = TEGRA_UARTA_BASE,
|
||||
.irq = INT_UARTA,
|
||||
.flags = UPF_BOOT_AUTOCONF,
|
||||
.iotype = UPIO_MEM,
|
||||
.regshift = 2,
|
||||
.uartclk = 216000000,
|
||||
}, {
|
||||
.flags = 0
|
||||
}
|
||||
};
|
||||
|
||||
static struct platform_device debug_uart = {
|
||||
.name = "serial8250",
|
||||
.id = PLAT8250_DEV_PLATFORM,
|
||||
.dev = {
|
||||
.platform_data = debug_uart_platform_data,
|
||||
},
|
||||
};
|
||||
|
||||
static struct platform_device *trimslice_devices[] __initdata = {
|
||||
&debug_uart,
|
||||
};
|
||||
|
||||
static void __init tegra_trimslice_fixup(struct machine_desc *desc,
|
||||
struct tag *tags, char **cmdline, struct meminfo *mi)
|
||||
{
|
||||
mi->nr_banks = 2;
|
||||
mi->bank[0].start = PHYS_OFFSET;
|
||||
mi->bank[0].size = 448 * SZ_1M;
|
||||
mi->bank[1].start = SZ_512M;
|
||||
mi->bank[1].size = SZ_512M;
|
||||
}
|
||||
|
||||
static __initdata struct tegra_clk_init_table trimslice_clk_init_table[] = {
|
||||
/* name parent rate enabled */
|
||||
{ "uarta", "pll_p", 216000000, true },
|
||||
{ NULL, NULL, 0, 0},
|
||||
};
|
||||
|
||||
static int __init tegra_trimslice_pci_init(void)
|
||||
{
|
||||
if (!machine_is_trimslice())
|
||||
return 0;
|
||||
|
||||
return tegra_pcie_init(true, true);
|
||||
}
|
||||
subsys_initcall(tegra_trimslice_pci_init);
|
||||
|
||||
static void __init tegra_trimslice_init(void)
|
||||
{
|
||||
tegra_clk_init_from_table(trimslice_clk_init_table);
|
||||
|
||||
trimslice_pinmux_init();
|
||||
|
||||
platform_add_devices(trimslice_devices, ARRAY_SIZE(trimslice_devices));
|
||||
}
|
||||
|
||||
MACHINE_START(TRIMSLICE, "trimslice")
|
||||
.boot_params = 0x00000100,
|
||||
.fixup = tegra_trimslice_fixup,
|
||||
.map_io = tegra_map_common_io,
|
||||
.init_early = tegra_init_early,
|
||||
.init_irq = tegra_init_irq,
|
||||
.timer = &tegra_timer,
|
||||
.init_machine = tegra_trimslice_init,
|
||||
MACHINE_END
|
|
@ -1,10 +1,7 @@
|
|||
/*
|
||||
* arch/arm/mach-tegra/tegra2_dvfs.h
|
||||
* arch/arm/mach-tegra/board-trimslice.h
|
||||
*
|
||||
* Copyright (C) 2010 Google, Inc.
|
||||
*
|
||||
* Author:
|
||||
* Colin Cross <ccross@google.com>
|
||||
* Copyright (C) 2011 CompuLab, Ltd.
|
||||
*
|
||||
* This software is licensed under the terms of the GNU General Public
|
||||
* License version 2, as published by the Free Software Foundation, and
|
||||
|
@ -17,4 +14,9 @@
|
|||
*
|
||||
*/
|
||||
|
||||
extern struct dvfs tegra_dvfs_virtual_cpu_dvfs;
|
||||
#ifndef _MACH_TEGRA_BOARD_TRIMSLICE_H
|
||||
#define _MACH_TEGRA_BOARD_TRIMSLICE_H
|
||||
|
||||
void trimslice_pinmux_init(void);
|
||||
|
||||
#endif
|
|
@ -23,7 +23,9 @@
|
|||
|
||||
#include <linux/types.h>
|
||||
|
||||
void __init tegra_common_init(void);
|
||||
void tegra_assert_system_reset(char mode, const char *cmd);
|
||||
|
||||
void __init tegra_init_early(void);
|
||||
void __init tegra_map_common_io(void);
|
||||
void __init tegra_init_irq(void);
|
||||
void __init tegra_init_clock(void);
|
||||
|
|
|
@ -18,238 +18,177 @@
|
|||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/clkdev.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include <mach/clk.h>
|
||||
|
||||
#include "clock.h"
|
||||
#include "board.h"
|
||||
#include "fuse.h"
|
||||
#include "clock.h"
|
||||
|
||||
/*
|
||||
* Locking:
|
||||
*
|
||||
* Each struct clk has a spinlock.
|
||||
*
|
||||
* To avoid AB-BA locking problems, locks must always be traversed from child
|
||||
* clock to parent clock. For example, when enabling a clock, the clock's lock
|
||||
* is taken, and then clk_enable is called on the parent, which take's the
|
||||
* parent clock's lock. There is one exceptions to this ordering: When dumping
|
||||
* the clock tree through debugfs. In this case, clk_lock_all is called,
|
||||
* which attemps to iterate through the entire list of clocks and take every
|
||||
* clock lock. If any call to spin_trylock fails, all locked clocks are
|
||||
* unlocked, and the process is retried. When all the locks are held,
|
||||
* the only clock operation that can be called is clk_get_rate_all_locked.
|
||||
*
|
||||
* Within a single clock, no clock operation can call another clock operation
|
||||
* on itself, except for clk_get_rate_locked and clk_set_rate_locked. Any
|
||||
* clock operation can call any other clock operation on any of it's possible
|
||||
* parents.
|
||||
*
|
||||
* An additional mutex, clock_list_lock, is used to protect the list of all
|
||||
* clocks.
|
||||
*
|
||||
* The clock operations must lock internally to protect against
|
||||
* read-modify-write on registers that are shared by multiple clocks
|
||||
*/
|
||||
static DEFINE_MUTEX(clock_list_lock);
|
||||
static LIST_HEAD(clocks);
|
||||
|
||||
static DEFINE_SPINLOCK(clock_lock);
|
||||
static DEFINE_MUTEX(dvfs_lock);
|
||||
|
||||
static int clk_is_dvfs(struct clk *c)
|
||||
{
|
||||
return (c->dvfs != NULL);
|
||||
};
|
||||
|
||||
static int dvfs_set_rate(struct dvfs *d, unsigned long rate)
|
||||
{
|
||||
struct dvfs_table *t;
|
||||
|
||||
if (d->table == NULL)
|
||||
return -ENODEV;
|
||||
|
||||
for (t = d->table; t->rate != 0; t++) {
|
||||
if (rate <= t->rate) {
|
||||
if (!d->reg)
|
||||
return 0;
|
||||
|
||||
return regulator_set_voltage(d->reg,
|
||||
t->millivolts * 1000,
|
||||
d->max_millivolts * 1000);
|
||||
}
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static void dvfs_init(struct clk *c)
|
||||
{
|
||||
int process_id;
|
||||
int i;
|
||||
struct dvfs_table *table;
|
||||
|
||||
process_id = c->dvfs->cpu ? tegra_core_process_id() :
|
||||
tegra_cpu_process_id();
|
||||
|
||||
for (i = 0; i < c->dvfs->process_id_table_length; i++)
|
||||
if (process_id == c->dvfs->process_id_table[i].process_id)
|
||||
c->dvfs->table = c->dvfs->process_id_table[i].table;
|
||||
|
||||
if (c->dvfs->table == NULL) {
|
||||
pr_err("Failed to find dvfs table for clock %s process %d\n",
|
||||
c->name, process_id);
|
||||
return;
|
||||
}
|
||||
|
||||
c->dvfs->max_millivolts = 0;
|
||||
for (table = c->dvfs->table; table->rate != 0; table++)
|
||||
if (c->dvfs->max_millivolts < table->millivolts)
|
||||
c->dvfs->max_millivolts = table->millivolts;
|
||||
|
||||
c->dvfs->reg = regulator_get(NULL, c->dvfs->reg_id);
|
||||
|
||||
if (IS_ERR(c->dvfs->reg)) {
|
||||
pr_err("Failed to get regulator %s for clock %s\n",
|
||||
c->dvfs->reg_id, c->name);
|
||||
c->dvfs->reg = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
if (c->refcnt > 0)
|
||||
dvfs_set_rate(c->dvfs, c->rate);
|
||||
}
|
||||
|
||||
struct clk *tegra_get_clock_by_name(const char *name)
|
||||
{
|
||||
struct clk *c;
|
||||
struct clk *ret = NULL;
|
||||
unsigned long flags;
|
||||
spin_lock_irqsave(&clock_lock, flags);
|
||||
mutex_lock(&clock_list_lock);
|
||||
list_for_each_entry(c, &clocks, node) {
|
||||
if (strcmp(c->name, name) == 0) {
|
||||
ret = c;
|
||||
break;
|
||||
}
|
||||
}
|
||||
spin_unlock_irqrestore(&clock_lock, flags);
|
||||
mutex_unlock(&clock_list_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void clk_recalculate_rate(struct clk *c)
|
||||
/* Must be called with c->spinlock held */
|
||||
static unsigned long clk_predict_rate_from_parent(struct clk *c, struct clk *p)
|
||||
{
|
||||
u64 rate;
|
||||
|
||||
if (!c->parent)
|
||||
return;
|
||||
|
||||
rate = c->parent->rate;
|
||||
rate = clk_get_rate(p);
|
||||
|
||||
if (c->mul != 0 && c->div != 0) {
|
||||
rate = rate * c->mul;
|
||||
rate *= c->mul;
|
||||
rate += c->div - 1; /* round up */
|
||||
do_div(rate, c->div);
|
||||
}
|
||||
|
||||
if (rate > c->max_rate)
|
||||
pr_warn("clocks: Set clock %s to rate %llu, max is %lu\n",
|
||||
c->name, rate, c->max_rate);
|
||||
|
||||
c->rate = rate;
|
||||
return rate;
|
||||
}
|
||||
|
||||
/* Must be called with c->spinlock held */
|
||||
unsigned long clk_get_rate_locked(struct clk *c)
|
||||
{
|
||||
unsigned long rate;
|
||||
|
||||
if (c->parent)
|
||||
rate = clk_predict_rate_from_parent(c, c->parent);
|
||||
else
|
||||
rate = c->rate;
|
||||
|
||||
return rate;
|
||||
}
|
||||
|
||||
unsigned long clk_get_rate(struct clk *c)
|
||||
{
|
||||
unsigned long flags;
|
||||
unsigned long rate;
|
||||
|
||||
spin_lock_irqsave(&c->spinlock, flags);
|
||||
|
||||
rate = clk_get_rate_locked(c);
|
||||
|
||||
spin_unlock_irqrestore(&c->spinlock, flags);
|
||||
|
||||
return rate;
|
||||
}
|
||||
EXPORT_SYMBOL(clk_get_rate);
|
||||
|
||||
int clk_reparent(struct clk *c, struct clk *parent)
|
||||
{
|
||||
pr_debug("%s: %s\n", __func__, c->name);
|
||||
c->parent = parent;
|
||||
list_del(&c->sibling);
|
||||
list_add_tail(&c->sibling, &parent->children);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void propagate_rate(struct clk *c)
|
||||
{
|
||||
struct clk *clkp;
|
||||
pr_debug("%s: %s\n", __func__, c->name);
|
||||
list_for_each_entry(clkp, &c->children, sibling) {
|
||||
pr_debug(" %s\n", clkp->name);
|
||||
clk_recalculate_rate(clkp);
|
||||
propagate_rate(clkp);
|
||||
}
|
||||
}
|
||||
|
||||
void clk_init(struct clk *c)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
pr_debug("%s: %s\n", __func__, c->name);
|
||||
|
||||
spin_lock_irqsave(&clock_lock, flags);
|
||||
|
||||
INIT_LIST_HEAD(&c->children);
|
||||
INIT_LIST_HEAD(&c->sibling);
|
||||
spin_lock_init(&c->spinlock);
|
||||
|
||||
if (c->ops && c->ops->init)
|
||||
c->ops->init(c);
|
||||
|
||||
clk_recalculate_rate(c);
|
||||
if (!c->ops || !c->ops->enable) {
|
||||
c->refcnt++;
|
||||
c->set = true;
|
||||
if (c->parent)
|
||||
c->state = c->parent->state;
|
||||
else
|
||||
c->state = ON;
|
||||
}
|
||||
|
||||
mutex_lock(&clock_list_lock);
|
||||
list_add(&c->node, &clocks);
|
||||
|
||||
if (c->parent)
|
||||
list_add_tail(&c->sibling, &c->parent->children);
|
||||
|
||||
spin_unlock_irqrestore(&clock_lock, flags);
|
||||
mutex_unlock(&clock_list_lock);
|
||||
}
|
||||
|
||||
int clk_enable_locked(struct clk *c)
|
||||
int clk_enable(struct clk *c)
|
||||
{
|
||||
int ret;
|
||||
pr_debug("%s: %s\n", __func__, c->name);
|
||||
int ret = 0;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&c->spinlock, flags);
|
||||
|
||||
if (c->refcnt == 0) {
|
||||
if (c->parent) {
|
||||
ret = clk_enable_locked(c->parent);
|
||||
ret = clk_enable(c->parent);
|
||||
if (ret)
|
||||
return ret;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (c->ops && c->ops->enable) {
|
||||
ret = c->ops->enable(c);
|
||||
if (ret) {
|
||||
if (c->parent)
|
||||
clk_disable_locked(c->parent);
|
||||
return ret;
|
||||
clk_disable(c->parent);
|
||||
goto out;
|
||||
}
|
||||
c->state = ON;
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
c->set = 1;
|
||||
#endif
|
||||
c->set = true;
|
||||
}
|
||||
}
|
||||
c->refcnt++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int clk_enable_cansleep(struct clk *c)
|
||||
{
|
||||
int ret;
|
||||
unsigned long flags;
|
||||
|
||||
mutex_lock(&dvfs_lock);
|
||||
|
||||
if (clk_is_dvfs(c) && c->refcnt > 0)
|
||||
dvfs_set_rate(c->dvfs, c->rate);
|
||||
|
||||
spin_lock_irqsave(&clock_lock, flags);
|
||||
ret = clk_enable_locked(c);
|
||||
spin_unlock_irqrestore(&clock_lock, flags);
|
||||
|
||||
mutex_unlock(&dvfs_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(clk_enable_cansleep);
|
||||
|
||||
int clk_enable(struct clk *c)
|
||||
{
|
||||
int ret;
|
||||
unsigned long flags;
|
||||
|
||||
if (clk_is_dvfs(c))
|
||||
BUG();
|
||||
|
||||
spin_lock_irqsave(&clock_lock, flags);
|
||||
ret = clk_enable_locked(c);
|
||||
spin_unlock_irqrestore(&clock_lock, flags);
|
||||
|
||||
out:
|
||||
spin_unlock_irqrestore(&c->spinlock, flags);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(clk_enable);
|
||||
|
||||
void clk_disable_locked(struct clk *c)
|
||||
void clk_disable(struct clk *c)
|
||||
{
|
||||
pr_debug("%s: %s\n", __func__, c->name);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&c->spinlock, flags);
|
||||
|
||||
if (c->refcnt == 0) {
|
||||
WARN(1, "Attempting to disable clock %s with refcnt 0", c->name);
|
||||
spin_unlock_irqrestore(&c->spinlock, flags);
|
||||
return;
|
||||
}
|
||||
if (c->refcnt == 1) {
|
||||
|
@ -257,71 +196,39 @@ void clk_disable_locked(struct clk *c)
|
|||
c->ops->disable(c);
|
||||
|
||||
if (c->parent)
|
||||
clk_disable_locked(c->parent);
|
||||
clk_disable(c->parent);
|
||||
|
||||
c->state = OFF;
|
||||
}
|
||||
c->refcnt--;
|
||||
}
|
||||
|
||||
void clk_disable_cansleep(struct clk *c)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
mutex_lock(&dvfs_lock);
|
||||
|
||||
spin_lock_irqsave(&clock_lock, flags);
|
||||
clk_disable_locked(c);
|
||||
spin_unlock_irqrestore(&clock_lock, flags);
|
||||
|
||||
if (clk_is_dvfs(c) && c->refcnt == 0)
|
||||
dvfs_set_rate(c->dvfs, c->rate);
|
||||
|
||||
mutex_unlock(&dvfs_lock);
|
||||
}
|
||||
EXPORT_SYMBOL(clk_disable_cansleep);
|
||||
|
||||
void clk_disable(struct clk *c)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
if (clk_is_dvfs(c))
|
||||
BUG();
|
||||
|
||||
spin_lock_irqsave(&clock_lock, flags);
|
||||
clk_disable_locked(c);
|
||||
spin_unlock_irqrestore(&clock_lock, flags);
|
||||
spin_unlock_irqrestore(&c->spinlock, flags);
|
||||
}
|
||||
EXPORT_SYMBOL(clk_disable);
|
||||
|
||||
int clk_set_parent_locked(struct clk *c, struct clk *parent)
|
||||
{
|
||||
int ret;
|
||||
|
||||
pr_debug("%s: %s\n", __func__, c->name);
|
||||
|
||||
if (!c->ops || !c->ops->set_parent)
|
||||
return -ENOSYS;
|
||||
|
||||
ret = c->ops->set_parent(c, parent);
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
clk_recalculate_rate(c);
|
||||
|
||||
propagate_rate(c);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int clk_set_parent(struct clk *c, struct clk *parent)
|
||||
{
|
||||
int ret;
|
||||
unsigned long flags;
|
||||
spin_lock_irqsave(&clock_lock, flags);
|
||||
ret = clk_set_parent_locked(c, parent);
|
||||
spin_unlock_irqrestore(&clock_lock, flags);
|
||||
unsigned long new_rate;
|
||||
unsigned long old_rate;
|
||||
|
||||
spin_lock_irqsave(&c->spinlock, flags);
|
||||
|
||||
if (!c->ops || !c->ops->set_parent) {
|
||||
ret = -ENOSYS;
|
||||
goto out;
|
||||
}
|
||||
|
||||
new_rate = clk_predict_rate_from_parent(c, parent);
|
||||
old_rate = clk_get_rate_locked(c);
|
||||
|
||||
ret = c->ops->set_parent(c, parent);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
out:
|
||||
spin_unlock_irqrestore(&c->spinlock, flags);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(clk_set_parent);
|
||||
|
@ -334,100 +241,86 @@ EXPORT_SYMBOL(clk_get_parent);
|
|||
|
||||
int clk_set_rate_locked(struct clk *c, unsigned long rate)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (rate > c->max_rate)
|
||||
rate = c->max_rate;
|
||||
long new_rate;
|
||||
|
||||
if (!c->ops || !c->ops->set_rate)
|
||||
return -ENOSYS;
|
||||
|
||||
ret = c->ops->set_rate(c, rate);
|
||||
if (rate > c->max_rate)
|
||||
rate = c->max_rate;
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
if (c->ops && c->ops->round_rate) {
|
||||
new_rate = c->ops->round_rate(c, rate);
|
||||
|
||||
clk_recalculate_rate(c);
|
||||
if (new_rate < 0)
|
||||
return new_rate;
|
||||
|
||||
propagate_rate(c);
|
||||
rate = new_rate;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return c->ops->set_rate(c, rate);
|
||||
}
|
||||
|
||||
int clk_set_rate_cansleep(struct clk *c, unsigned long rate)
|
||||
{
|
||||
int ret = 0;
|
||||
unsigned long flags;
|
||||
|
||||
pr_debug("%s: %s\n", __func__, c->name);
|
||||
|
||||
mutex_lock(&dvfs_lock);
|
||||
|
||||
if (rate > c->rate)
|
||||
ret = dvfs_set_rate(c->dvfs, rate);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
spin_lock_irqsave(&clock_lock, flags);
|
||||
ret = clk_set_rate_locked(c, rate);
|
||||
spin_unlock_irqrestore(&clock_lock, flags);
|
||||
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
ret = dvfs_set_rate(c->dvfs, rate);
|
||||
|
||||
out:
|
||||
mutex_unlock(&dvfs_lock);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(clk_set_rate_cansleep);
|
||||
|
||||
int clk_set_rate(struct clk *c, unsigned long rate)
|
||||
{
|
||||
int ret = 0;
|
||||
int ret;
|
||||
unsigned long flags;
|
||||
|
||||
pr_debug("%s: %s\n", __func__, c->name);
|
||||
spin_lock_irqsave(&c->spinlock, flags);
|
||||
|
||||
if (clk_is_dvfs(c))
|
||||
BUG();
|
||||
|
||||
spin_lock_irqsave(&clock_lock, flags);
|
||||
ret = clk_set_rate_locked(c, rate);
|
||||
spin_unlock_irqrestore(&clock_lock, flags);
|
||||
|
||||
spin_unlock_irqrestore(&c->spinlock, flags);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(clk_set_rate);
|
||||
|
||||
unsigned long clk_get_rate(struct clk *c)
|
||||
|
||||
/* Must be called with clocks lock and all indvidual clock locks held */
|
||||
unsigned long clk_get_rate_all_locked(struct clk *c)
|
||||
{
|
||||
unsigned long flags;
|
||||
unsigned long ret;
|
||||
u64 rate;
|
||||
int mul = 1;
|
||||
int div = 1;
|
||||
struct clk *p = c;
|
||||
|
||||
spin_lock_irqsave(&clock_lock, flags);
|
||||
while (p) {
|
||||
c = p;
|
||||
if (c->mul != 0 && c->div != 0) {
|
||||
mul *= c->mul;
|
||||
div *= c->div;
|
||||
}
|
||||
p = c->parent;
|
||||
}
|
||||
|
||||
pr_debug("%s: %s\n", __func__, c->name);
|
||||
rate = c->rate;
|
||||
rate *= mul;
|
||||
do_div(rate, div);
|
||||
|
||||
ret = c->rate;
|
||||
|
||||
spin_unlock_irqrestore(&clock_lock, flags);
|
||||
return ret;
|
||||
return rate;
|
||||
}
|
||||
EXPORT_SYMBOL(clk_get_rate);
|
||||
|
||||
long clk_round_rate(struct clk *c, unsigned long rate)
|
||||
{
|
||||
pr_debug("%s: %s\n", __func__, c->name);
|
||||
unsigned long flags;
|
||||
long ret;
|
||||
|
||||
if (!c->ops || !c->ops->round_rate)
|
||||
return -ENOSYS;
|
||||
spin_lock_irqsave(&c->spinlock, flags);
|
||||
|
||||
if (!c->ops || !c->ops->round_rate) {
|
||||
ret = -ENOSYS;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (rate > c->max_rate)
|
||||
rate = c->max_rate;
|
||||
|
||||
return c->ops->round_rate(c, rate);
|
||||
ret = c->ops->round_rate(c, rate);
|
||||
|
||||
out:
|
||||
spin_unlock_irqrestore(&c->spinlock, flags);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(clk_round_rate);
|
||||
|
||||
|
@ -509,31 +402,90 @@ void __init tegra_init_clock(void)
|
|||
tegra2_init_clocks();
|
||||
}
|
||||
|
||||
int __init tegra_init_dvfs(void)
|
||||
/*
|
||||
* The SDMMC controllers have extra bits in the clock source register that
|
||||
* adjust the delay between the clock and data to compenstate for delays
|
||||
* on the PCB.
|
||||
*/
|
||||
void tegra_sdmmc_tap_delay(struct clk *c, int delay)
|
||||
{
|
||||
struct clk *c, *safe;
|
||||
unsigned long flags;
|
||||
|
||||
mutex_lock(&dvfs_lock);
|
||||
|
||||
list_for_each_entry_safe(c, safe, &clocks, node)
|
||||
if (c->dvfs)
|
||||
dvfs_init(c);
|
||||
|
||||
mutex_unlock(&dvfs_lock);
|
||||
|
||||
return 0;
|
||||
spin_lock_irqsave(&c->spinlock, flags);
|
||||
tegra2_sdmmc_tap_delay(c, delay);
|
||||
spin_unlock_irqrestore(&c->spinlock, flags);
|
||||
}
|
||||
|
||||
late_initcall(tegra_init_dvfs);
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
|
||||
static int __clk_lock_all_spinlocks(void)
|
||||
{
|
||||
struct clk *c;
|
||||
|
||||
list_for_each_entry(c, &clocks, node)
|
||||
if (!spin_trylock(&c->spinlock))
|
||||
goto unlock_spinlocks;
|
||||
|
||||
return 0;
|
||||
|
||||
unlock_spinlocks:
|
||||
list_for_each_entry_continue_reverse(c, &clocks, node)
|
||||
spin_unlock(&c->spinlock);
|
||||
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
static void __clk_unlock_all_spinlocks(void)
|
||||
{
|
||||
struct clk *c;
|
||||
|
||||
list_for_each_entry_reverse(c, &clocks, node)
|
||||
spin_unlock(&c->spinlock);
|
||||
}
|
||||
|
||||
/*
|
||||
* This function retries until it can take all locks, and may take
|
||||
* an arbitrarily long time to complete.
|
||||
* Must be called with irqs enabled, returns with irqs disabled
|
||||
* Must be called with clock_list_lock held
|
||||
*/
|
||||
static void clk_lock_all(void)
|
||||
{
|
||||
int ret;
|
||||
retry:
|
||||
local_irq_disable();
|
||||
|
||||
ret = __clk_lock_all_spinlocks();
|
||||
if (ret)
|
||||
goto failed_spinlocks;
|
||||
|
||||
/* All locks taken successfully, return */
|
||||
return;
|
||||
|
||||
failed_spinlocks:
|
||||
local_irq_enable();
|
||||
yield();
|
||||
goto retry;
|
||||
}
|
||||
|
||||
/*
|
||||
* Unlocks all clocks after a clk_lock_all
|
||||
* Must be called with irqs disabled, returns with irqs enabled
|
||||
* Must be called with clock_list_lock held
|
||||
*/
|
||||
static void clk_unlock_all(void)
|
||||
{
|
||||
__clk_unlock_all_spinlocks();
|
||||
|
||||
local_irq_enable();
|
||||
}
|
||||
|
||||
static struct dentry *clk_debugfs_root;
|
||||
|
||||
|
||||
static void clock_tree_show_one(struct seq_file *s, struct clk *c, int level)
|
||||
{
|
||||
struct clk *child;
|
||||
struct clk *safe;
|
||||
const char *state = "uninit";
|
||||
char div[8] = {0};
|
||||
|
||||
|
@ -564,8 +516,12 @@ static void clock_tree_show_one(struct seq_file *s, struct clk *c, int level)
|
|||
c->rate > c->max_rate ? '!' : ' ',
|
||||
!c->set ? '*' : ' ',
|
||||
30 - level * 3, c->name,
|
||||
state, c->refcnt, div, c->rate);
|
||||
list_for_each_entry_safe(child, safe, &c->children, sibling) {
|
||||
state, c->refcnt, div, clk_get_rate_all_locked(c));
|
||||
|
||||
list_for_each_entry(child, &clocks, node) {
|
||||
if (child->parent != c)
|
||||
continue;
|
||||
|
||||
clock_tree_show_one(s, child, level + 1);
|
||||
}
|
||||
}
|
||||
|
@ -573,14 +529,20 @@ static void clock_tree_show_one(struct seq_file *s, struct clk *c, int level)
|
|||
static int clock_tree_show(struct seq_file *s, void *data)
|
||||
{
|
||||
struct clk *c;
|
||||
unsigned long flags;
|
||||
seq_printf(s, " clock state ref div rate\n");
|
||||
seq_printf(s, "--------------------------------------------------------------\n");
|
||||
spin_lock_irqsave(&clock_lock, flags);
|
||||
|
||||
mutex_lock(&clock_list_lock);
|
||||
|
||||
clk_lock_all();
|
||||
|
||||
list_for_each_entry(c, &clocks, node)
|
||||
if (c->parent == NULL)
|
||||
clock_tree_show_one(s, c, 0);
|
||||
spin_unlock_irqrestore(&clock_lock, flags);
|
||||
|
||||
clk_unlock_all();
|
||||
|
||||
mutex_unlock(&clock_list_lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -20,8 +20,9 @@
|
|||
#ifndef __MACH_TEGRA_CLOCK_H
|
||||
#define __MACH_TEGRA_CLOCK_H
|
||||
|
||||
#include <linux/list.h>
|
||||
#include <linux/clkdev.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/spinlock.h>
|
||||
|
||||
#define DIV_BUS (1 << 0)
|
||||
#define DIV_U71 (1 << 1)
|
||||
|
@ -41,36 +42,13 @@
|
|||
#define ENABLE_ON_INIT (1 << 28)
|
||||
|
||||
struct clk;
|
||||
struct regulator;
|
||||
|
||||
struct dvfs_table {
|
||||
unsigned long rate;
|
||||
int millivolts;
|
||||
};
|
||||
|
||||
struct dvfs_process_id_table {
|
||||
int process_id;
|
||||
struct dvfs_table *table;
|
||||
};
|
||||
|
||||
|
||||
struct dvfs {
|
||||
struct regulator *reg;
|
||||
struct dvfs_table *table;
|
||||
int max_millivolts;
|
||||
|
||||
int process_id_table_length;
|
||||
const char *reg_id;
|
||||
bool cpu;
|
||||
struct dvfs_process_id_table process_id_table[];
|
||||
};
|
||||
|
||||
struct clk_mux_sel {
|
||||
struct clk *input;
|
||||
u32 value;
|
||||
};
|
||||
|
||||
struct clk_pll_table {
|
||||
struct clk_pll_freq_table {
|
||||
unsigned long input_rate;
|
||||
unsigned long output_rate;
|
||||
u16 n;
|
||||
|
@ -86,6 +64,7 @@ struct clk_ops {
|
|||
int (*set_parent)(struct clk *, struct clk *);
|
||||
int (*set_rate)(struct clk *, unsigned long);
|
||||
long (*round_rate)(struct clk *, unsigned long);
|
||||
void (*reset)(struct clk *, bool);
|
||||
};
|
||||
|
||||
enum clk_state {
|
||||
|
@ -96,55 +75,64 @@ enum clk_state {
|
|||
|
||||
struct clk {
|
||||
/* node for master clocks list */
|
||||
struct list_head node;
|
||||
struct list_head children; /* list of children */
|
||||
struct list_head sibling; /* node for children */
|
||||
struct list_head node; /* node for list of all clocks */
|
||||
struct clk_lookup lookup;
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
struct dentry *dent;
|
||||
struct dentry *parent_dent;
|
||||
struct dentry *dent;
|
||||
#endif
|
||||
struct clk_ops *ops;
|
||||
struct clk *parent;
|
||||
struct clk_lookup lookup;
|
||||
unsigned long rate;
|
||||
unsigned long max_rate;
|
||||
u32 flags;
|
||||
u32 refcnt;
|
||||
const char *name;
|
||||
bool set;
|
||||
struct clk_ops *ops;
|
||||
unsigned long rate;
|
||||
unsigned long max_rate;
|
||||
unsigned long min_rate;
|
||||
u32 flags;
|
||||
const char *name;
|
||||
|
||||
u32 refcnt;
|
||||
enum clk_state state;
|
||||
struct clk *parent;
|
||||
u32 div;
|
||||
u32 mul;
|
||||
|
||||
const struct clk_mux_sel *inputs;
|
||||
u32 reg;
|
||||
u32 reg_shift;
|
||||
unsigned int clk_num;
|
||||
enum clk_state state;
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
bool set;
|
||||
#endif
|
||||
|
||||
/* PLL */
|
||||
unsigned long input_min;
|
||||
unsigned long input_max;
|
||||
unsigned long cf_min;
|
||||
unsigned long cf_max;
|
||||
unsigned long vco_min;
|
||||
unsigned long vco_max;
|
||||
const struct clk_pll_table *pll_table;
|
||||
struct list_head shared_bus_list;
|
||||
|
||||
/* DIV */
|
||||
u32 div;
|
||||
u32 mul;
|
||||
union {
|
||||
struct {
|
||||
unsigned int clk_num;
|
||||
} periph;
|
||||
struct {
|
||||
unsigned long input_min;
|
||||
unsigned long input_max;
|
||||
unsigned long cf_min;
|
||||
unsigned long cf_max;
|
||||
unsigned long vco_min;
|
||||
unsigned long vco_max;
|
||||
const struct clk_pll_freq_table *freq_table;
|
||||
int lock_delay;
|
||||
} pll;
|
||||
struct {
|
||||
u32 sel;
|
||||
u32 reg_mask;
|
||||
} mux;
|
||||
struct {
|
||||
struct clk *main;
|
||||
struct clk *backup;
|
||||
} cpu;
|
||||
struct {
|
||||
struct list_head node;
|
||||
bool enabled;
|
||||
unsigned long rate;
|
||||
} shared_bus_user;
|
||||
} u;
|
||||
|
||||
/* MUX */
|
||||
const struct clk_mux_sel *inputs;
|
||||
u32 sel;
|
||||
u32 reg_mask;
|
||||
|
||||
/* Virtual cpu clock */
|
||||
struct clk *main;
|
||||
struct clk *backup;
|
||||
|
||||
struct dvfs *dvfs;
|
||||
spinlock_t spinlock;
|
||||
};
|
||||
|
||||
|
||||
struct clk_duplicate {
|
||||
const char *name;
|
||||
struct clk_lookup lookup;
|
||||
|
@ -163,11 +151,10 @@ void tegra2_periph_reset_assert(struct clk *c);
|
|||
void clk_init(struct clk *clk);
|
||||
struct clk *tegra_get_clock_by_name(const char *name);
|
||||
unsigned long clk_measure_input_freq(void);
|
||||
void clk_disable_locked(struct clk *c);
|
||||
int clk_enable_locked(struct clk *c);
|
||||
int clk_set_parent_locked(struct clk *c, struct clk *parent);
|
||||
int clk_set_rate_locked(struct clk *c, unsigned long rate);
|
||||
int clk_reparent(struct clk *c, struct clk *parent);
|
||||
void tegra_clk_init_from_table(struct tegra_clk_init_table *table);
|
||||
unsigned long clk_get_rate_locked(struct clk *c);
|
||||
int clk_set_rate_locked(struct clk *c, unsigned long rate);
|
||||
void tegra2_sdmmc_tap_delay(struct clk *c, int delay);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -25,12 +25,25 @@
|
|||
#include <asm/hardware/cache-l2x0.h>
|
||||
|
||||
#include <mach/iomap.h>
|
||||
#include <mach/dma.h>
|
||||
#include <mach/system.h>
|
||||
|
||||
#include "board.h"
|
||||
#include "clock.h"
|
||||
#include "fuse.h"
|
||||
|
||||
void (*arch_reset)(char mode, const char *cmd) = tegra_assert_system_reset;
|
||||
|
||||
void tegra_assert_system_reset(char mode, const char *cmd)
|
||||
{
|
||||
void __iomem *reset = IO_ADDRESS(TEGRA_CLK_RESET_BASE + 0x04);
|
||||
u32 reg;
|
||||
|
||||
/* use *_related to avoid spinlock since caches are off */
|
||||
reg = readl_relaxed(reset);
|
||||
reg |= 0x04;
|
||||
writel_relaxed(reg, reset);
|
||||
}
|
||||
|
||||
static __initdata struct tegra_clk_init_table common_clk_init_table[] = {
|
||||
/* name parent rate enabled */
|
||||
{ "clk_m", NULL, 0, true },
|
||||
|
@ -42,6 +55,9 @@ static __initdata struct tegra_clk_init_table common_clk_init_table[] = {
|
|||
{ "sclk", "pll_p_out4", 108000000, true },
|
||||
{ "hclk", "sclk", 108000000, true },
|
||||
{ "pclk", "hclk", 54000000, true },
|
||||
{ "csite", NULL, 0, true },
|
||||
{ "emc", NULL, 0, true },
|
||||
{ "cpu", NULL, 0, true },
|
||||
{ NULL, NULL, 0, 0},
|
||||
};
|
||||
|
||||
|
@ -50,21 +66,18 @@ void __init tegra_init_cache(void)
|
|||
#ifdef CONFIG_CACHE_L2X0
|
||||
void __iomem *p = IO_ADDRESS(TEGRA_ARM_PERIF_BASE) + 0x3000;
|
||||
|
||||
writel(0x331, p + L2X0_TAG_LATENCY_CTRL);
|
||||
writel(0x441, p + L2X0_DATA_LATENCY_CTRL);
|
||||
writel_relaxed(0x331, p + L2X0_TAG_LATENCY_CTRL);
|
||||
writel_relaxed(0x441, p + L2X0_DATA_LATENCY_CTRL);
|
||||
|
||||
l2x0_init(p, 0x6C080001, 0x8200c3fe);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
void __init tegra_common_init(void)
|
||||
void __init tegra_init_early(void)
|
||||
{
|
||||
tegra_init_fuse();
|
||||
tegra_init_clock();
|
||||
tegra_clk_init_from_table(common_clk_init_table);
|
||||
tegra_init_cache();
|
||||
#ifdef CONFIG_TEGRA_SYSTEM_DMA
|
||||
tegra_dma_init();
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#include <linux/err.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/suspend.h>
|
||||
|
||||
#include <asm/system.h>
|
||||
|
||||
|
@ -36,21 +37,25 @@
|
|||
|
||||
/* Frequency table index must be sequential starting at 0 */
|
||||
static struct cpufreq_frequency_table freq_table[] = {
|
||||
{ 0, 312000 },
|
||||
{ 1, 456000 },
|
||||
{ 2, 608000 },
|
||||
{ 3, 760000 },
|
||||
{ 4, 816000 },
|
||||
{ 5, 912000 },
|
||||
{ 6, 1000000 },
|
||||
{ 7, CPUFREQ_TABLE_END },
|
||||
{ 0, 216000 },
|
||||
{ 1, 312000 },
|
||||
{ 2, 456000 },
|
||||
{ 3, 608000 },
|
||||
{ 4, 760000 },
|
||||
{ 5, 816000 },
|
||||
{ 6, 912000 },
|
||||
{ 7, 1000000 },
|
||||
{ 8, CPUFREQ_TABLE_END },
|
||||
};
|
||||
|
||||
#define NUM_CPUS 2
|
||||
|
||||
static struct clk *cpu_clk;
|
||||
static struct clk *emc_clk;
|
||||
|
||||
static unsigned long target_cpu_speed[NUM_CPUS];
|
||||
static DEFINE_MUTEX(tegra_cpu_lock);
|
||||
static bool is_suspended;
|
||||
|
||||
int tegra_verify_speed(struct cpufreq_policy *policy)
|
||||
{
|
||||
|
@ -68,22 +73,28 @@ unsigned int tegra_getspeed(unsigned int cpu)
|
|||
return rate;
|
||||
}
|
||||
|
||||
static int tegra_update_cpu_speed(void)
|
||||
static int tegra_update_cpu_speed(unsigned long rate)
|
||||
{
|
||||
int i;
|
||||
unsigned long rate = 0;
|
||||
int ret = 0;
|
||||
struct cpufreq_freqs freqs;
|
||||
|
||||
for_each_online_cpu(i)
|
||||
rate = max(rate, target_cpu_speed[i]);
|
||||
|
||||
freqs.old = tegra_getspeed(0);
|
||||
freqs.new = rate;
|
||||
|
||||
if (freqs.old == freqs.new)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* Vote on memory bus frequency based on cpu frequency
|
||||
* This sets the minimum frequency, display or avp may request higher
|
||||
*/
|
||||
if (rate >= 816000)
|
||||
clk_set_rate(emc_clk, 600000000); /* cpu 816 MHz, emc max */
|
||||
else if (rate >= 456000)
|
||||
clk_set_rate(emc_clk, 300000000); /* cpu 456 MHz, emc 150Mhz */
|
||||
else
|
||||
clk_set_rate(emc_clk, 100000000); /* emc 50Mhz */
|
||||
|
||||
for_each_online_cpu(freqs.cpu)
|
||||
cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
|
||||
|
||||
|
@ -92,7 +103,7 @@ static int tegra_update_cpu_speed(void)
|
|||
freqs.old, freqs.new);
|
||||
#endif
|
||||
|
||||
ret = clk_set_rate_cansleep(cpu_clk, freqs.new * 1000);
|
||||
ret = clk_set_rate(cpu_clk, freqs.new * 1000);
|
||||
if (ret) {
|
||||
pr_err("cpu-tegra: Failed to set cpu frequency to %d kHz\n",
|
||||
freqs.new);
|
||||
|
@ -105,12 +116,30 @@ static int tegra_update_cpu_speed(void)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static unsigned long tegra_cpu_highest_speed(void)
|
||||
{
|
||||
unsigned long rate = 0;
|
||||
int i;
|
||||
|
||||
for_each_online_cpu(i)
|
||||
rate = max(rate, target_cpu_speed[i]);
|
||||
return rate;
|
||||
}
|
||||
|
||||
static int tegra_target(struct cpufreq_policy *policy,
|
||||
unsigned int target_freq,
|
||||
unsigned int relation)
|
||||
{
|
||||
int idx;
|
||||
unsigned int freq;
|
||||
int ret = 0;
|
||||
|
||||
mutex_lock(&tegra_cpu_lock);
|
||||
|
||||
if (is_suspended) {
|
||||
ret = -EBUSY;
|
||||
goto out;
|
||||
}
|
||||
|
||||
cpufreq_frequency_table_target(policy, freq_table, target_freq,
|
||||
relation, &idx);
|
||||
|
@ -119,9 +148,34 @@ static int tegra_target(struct cpufreq_policy *policy,
|
|||
|
||||
target_cpu_speed[policy->cpu] = freq;
|
||||
|
||||
return tegra_update_cpu_speed();
|
||||
ret = tegra_update_cpu_speed(tegra_cpu_highest_speed());
|
||||
|
||||
out:
|
||||
mutex_unlock(&tegra_cpu_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int tegra_pm_notify(struct notifier_block *nb, unsigned long event,
|
||||
void *dummy)
|
||||
{
|
||||
mutex_lock(&tegra_cpu_lock);
|
||||
if (event == PM_SUSPEND_PREPARE) {
|
||||
is_suspended = true;
|
||||
pr_info("Tegra cpufreq suspend: setting frequency to %d kHz\n",
|
||||
freq_table[0].frequency);
|
||||
tegra_update_cpu_speed(freq_table[0].frequency);
|
||||
} else if (event == PM_POST_SUSPEND) {
|
||||
is_suspended = false;
|
||||
}
|
||||
mutex_unlock(&tegra_cpu_lock);
|
||||
|
||||
return NOTIFY_OK;
|
||||
}
|
||||
|
||||
static struct notifier_block tegra_cpu_pm_notifier = {
|
||||
.notifier_call = tegra_pm_notify,
|
||||
};
|
||||
|
||||
static int tegra_cpu_init(struct cpufreq_policy *policy)
|
||||
{
|
||||
if (policy->cpu >= NUM_CPUS)
|
||||
|
@ -131,6 +185,15 @@ static int tegra_cpu_init(struct cpufreq_policy *policy)
|
|||
if (IS_ERR(cpu_clk))
|
||||
return PTR_ERR(cpu_clk);
|
||||
|
||||
emc_clk = clk_get_sys("cpu", "emc");
|
||||
if (IS_ERR(emc_clk)) {
|
||||
clk_put(cpu_clk);
|
||||
return PTR_ERR(emc_clk);
|
||||
}
|
||||
|
||||
clk_enable(emc_clk);
|
||||
clk_enable(cpu_clk);
|
||||
|
||||
cpufreq_frequency_table_cpuinfo(policy, freq_table);
|
||||
cpufreq_frequency_table_get_attr(freq_table, policy->cpu);
|
||||
policy->cur = tegra_getspeed(policy->cpu);
|
||||
|
@ -142,12 +205,17 @@ static int tegra_cpu_init(struct cpufreq_policy *policy)
|
|||
policy->shared_type = CPUFREQ_SHARED_TYPE_ALL;
|
||||
cpumask_copy(policy->related_cpus, cpu_possible_mask);
|
||||
|
||||
if (policy->cpu == 0)
|
||||
register_pm_notifier(&tegra_cpu_pm_notifier);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tegra_cpu_exit(struct cpufreq_policy *policy)
|
||||
{
|
||||
cpufreq_frequency_table_cpuinfo(policy, freq_table);
|
||||
clk_disable(emc_clk);
|
||||
clk_put(emc_clk);
|
||||
clk_put(cpu_clk);
|
||||
return 0;
|
||||
}
|
||||
|
|
505
arch/arm/mach-tegra/devices.c
Normal file
505
arch/arm/mach-tegra/devices.c
Normal file
|
@ -0,0 +1,505 @@
|
|||
/*
|
||||
* Copyright (C) 2010,2011 Google, Inc.
|
||||
*
|
||||
* Author:
|
||||
* Colin Cross <ccross@android.com>
|
||||
* Erik Gilling <ccross@android.com>
|
||||
*
|
||||
* 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 <linux/resource.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/fsl_devices.h>
|
||||
#include <linux/serial_8250.h>
|
||||
#include <asm/pmu.h>
|
||||
#include <mach/irqs.h>
|
||||
#include <mach/iomap.h>
|
||||
#include <mach/dma.h>
|
||||
|
||||
static struct resource i2c_resource1[] = {
|
||||
[0] = {
|
||||
.start = INT_I2C,
|
||||
.end = INT_I2C,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
[1] = {
|
||||
.start = TEGRA_I2C_BASE,
|
||||
.end = TEGRA_I2C_BASE + TEGRA_I2C_SIZE-1,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
};
|
||||
|
||||
static struct resource i2c_resource2[] = {
|
||||
[0] = {
|
||||
.start = INT_I2C2,
|
||||
.end = INT_I2C2,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
[1] = {
|
||||
.start = TEGRA_I2C2_BASE,
|
||||
.end = TEGRA_I2C2_BASE + TEGRA_I2C2_SIZE-1,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
};
|
||||
|
||||
static struct resource i2c_resource3[] = {
|
||||
[0] = {
|
||||
.start = INT_I2C3,
|
||||
.end = INT_I2C3,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
[1] = {
|
||||
.start = TEGRA_I2C3_BASE,
|
||||
.end = TEGRA_I2C3_BASE + TEGRA_I2C3_SIZE-1,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
};
|
||||
|
||||
static struct resource i2c_resource4[] = {
|
||||
[0] = {
|
||||
.start = INT_DVC,
|
||||
.end = INT_DVC,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
[1] = {
|
||||
.start = TEGRA_DVC_BASE,
|
||||
.end = TEGRA_DVC_BASE + TEGRA_DVC_SIZE-1,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
};
|
||||
|
||||
struct platform_device tegra_i2c_device1 = {
|
||||
.name = "tegra-i2c",
|
||||
.id = 0,
|
||||
.resource = i2c_resource1,
|
||||
.num_resources = ARRAY_SIZE(i2c_resource1),
|
||||
.dev = {
|
||||
.platform_data = 0,
|
||||
},
|
||||
};
|
||||
|
||||
struct platform_device tegra_i2c_device2 = {
|
||||
.name = "tegra-i2c",
|
||||
.id = 1,
|
||||
.resource = i2c_resource2,
|
||||
.num_resources = ARRAY_SIZE(i2c_resource2),
|
||||
.dev = {
|
||||
.platform_data = 0,
|
||||
},
|
||||
};
|
||||
|
||||
struct platform_device tegra_i2c_device3 = {
|
||||
.name = "tegra-i2c",
|
||||
.id = 2,
|
||||
.resource = i2c_resource3,
|
||||
.num_resources = ARRAY_SIZE(i2c_resource3),
|
||||
.dev = {
|
||||
.platform_data = 0,
|
||||
},
|
||||
};
|
||||
|
||||
struct platform_device tegra_i2c_device4 = {
|
||||
.name = "tegra-i2c",
|
||||
.id = 3,
|
||||
.resource = i2c_resource4,
|
||||
.num_resources = ARRAY_SIZE(i2c_resource4),
|
||||
.dev = {
|
||||
.platform_data = 0,
|
||||
},
|
||||
};
|
||||
|
||||
static struct resource spi_resource1[] = {
|
||||
[0] = {
|
||||
.start = INT_S_LINK1,
|
||||
.end = INT_S_LINK1,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
[1] = {
|
||||
.start = TEGRA_SPI1_BASE,
|
||||
.end = TEGRA_SPI1_BASE + TEGRA_SPI1_SIZE-1,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
};
|
||||
|
||||
static struct resource spi_resource2[] = {
|
||||
[0] = {
|
||||
.start = INT_SPI_2,
|
||||
.end = INT_SPI_2,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
[1] = {
|
||||
.start = TEGRA_SPI2_BASE,
|
||||
.end = TEGRA_SPI2_BASE + TEGRA_SPI2_SIZE-1,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
};
|
||||
|
||||
static struct resource spi_resource3[] = {
|
||||
[0] = {
|
||||
.start = INT_SPI_3,
|
||||
.end = INT_SPI_3,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
[1] = {
|
||||
.start = TEGRA_SPI3_BASE,
|
||||
.end = TEGRA_SPI3_BASE + TEGRA_SPI3_SIZE-1,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
};
|
||||
|
||||
static struct resource spi_resource4[] = {
|
||||
[0] = {
|
||||
.start = INT_SPI_4,
|
||||
.end = INT_SPI_4,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
[1] = {
|
||||
.start = TEGRA_SPI4_BASE,
|
||||
.end = TEGRA_SPI4_BASE + TEGRA_SPI4_SIZE-1,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
};
|
||||
|
||||
struct platform_device tegra_spi_device1 = {
|
||||
.name = "spi_tegra",
|
||||
.id = 0,
|
||||
.resource = spi_resource1,
|
||||
.num_resources = ARRAY_SIZE(spi_resource1),
|
||||
.dev = {
|
||||
.coherent_dma_mask = 0xffffffff,
|
||||
},
|
||||
};
|
||||
|
||||
struct platform_device tegra_spi_device2 = {
|
||||
.name = "spi_tegra",
|
||||
.id = 1,
|
||||
.resource = spi_resource2,
|
||||
.num_resources = ARRAY_SIZE(spi_resource2),
|
||||
.dev = {
|
||||
.coherent_dma_mask = 0xffffffff,
|
||||
},
|
||||
};
|
||||
|
||||
struct platform_device tegra_spi_device3 = {
|
||||
.name = "spi_tegra",
|
||||
.id = 2,
|
||||
.resource = spi_resource3,
|
||||
.num_resources = ARRAY_SIZE(spi_resource3),
|
||||
.dev = {
|
||||
.coherent_dma_mask = 0xffffffff,
|
||||
},
|
||||
};
|
||||
|
||||
struct platform_device tegra_spi_device4 = {
|
||||
.name = "spi_tegra",
|
||||
.id = 3,
|
||||
.resource = spi_resource4,
|
||||
.num_resources = ARRAY_SIZE(spi_resource4),
|
||||
.dev = {
|
||||
.coherent_dma_mask = 0xffffffff,
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
static struct resource sdhci_resource1[] = {
|
||||
[0] = {
|
||||
.start = INT_SDMMC1,
|
||||
.end = INT_SDMMC1,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
[1] = {
|
||||
.start = TEGRA_SDMMC1_BASE,
|
||||
.end = TEGRA_SDMMC1_BASE + TEGRA_SDMMC1_SIZE-1,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
};
|
||||
|
||||
static struct resource sdhci_resource2[] = {
|
||||
[0] = {
|
||||
.start = INT_SDMMC2,
|
||||
.end = INT_SDMMC2,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
[1] = {
|
||||
.start = TEGRA_SDMMC2_BASE,
|
||||
.end = TEGRA_SDMMC2_BASE + TEGRA_SDMMC2_SIZE-1,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
};
|
||||
|
||||
static struct resource sdhci_resource3[] = {
|
||||
[0] = {
|
||||
.start = INT_SDMMC3,
|
||||
.end = INT_SDMMC3,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
[1] = {
|
||||
.start = TEGRA_SDMMC3_BASE,
|
||||
.end = TEGRA_SDMMC3_BASE + TEGRA_SDMMC3_SIZE-1,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
};
|
||||
|
||||
static struct resource sdhci_resource4[] = {
|
||||
[0] = {
|
||||
.start = INT_SDMMC4,
|
||||
.end = INT_SDMMC4,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
[1] = {
|
||||
.start = TEGRA_SDMMC4_BASE,
|
||||
.end = TEGRA_SDMMC4_BASE + TEGRA_SDMMC4_SIZE-1,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
};
|
||||
|
||||
/* board files should fill in platform_data register the devices themselvs.
|
||||
* See board-harmony.c for an example
|
||||
*/
|
||||
struct platform_device tegra_sdhci_device1 = {
|
||||
.name = "sdhci-tegra",
|
||||
.id = 0,
|
||||
.resource = sdhci_resource1,
|
||||
.num_resources = ARRAY_SIZE(sdhci_resource1),
|
||||
};
|
||||
|
||||
struct platform_device tegra_sdhci_device2 = {
|
||||
.name = "sdhci-tegra",
|
||||
.id = 1,
|
||||
.resource = sdhci_resource2,
|
||||
.num_resources = ARRAY_SIZE(sdhci_resource2),
|
||||
};
|
||||
|
||||
struct platform_device tegra_sdhci_device3 = {
|
||||
.name = "sdhci-tegra",
|
||||
.id = 2,
|
||||
.resource = sdhci_resource3,
|
||||
.num_resources = ARRAY_SIZE(sdhci_resource3),
|
||||
};
|
||||
|
||||
struct platform_device tegra_sdhci_device4 = {
|
||||
.name = "sdhci-tegra",
|
||||
.id = 3,
|
||||
.resource = sdhci_resource4,
|
||||
.num_resources = ARRAY_SIZE(sdhci_resource4),
|
||||
};
|
||||
|
||||
static struct resource tegra_usb1_resources[] = {
|
||||
[0] = {
|
||||
.start = TEGRA_USB_BASE,
|
||||
.end = TEGRA_USB_BASE + TEGRA_USB_SIZE - 1,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
[1] = {
|
||||
.start = INT_USB,
|
||||
.end = INT_USB,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
};
|
||||
|
||||
static struct resource tegra_usb2_resources[] = {
|
||||
[0] = {
|
||||
.start = TEGRA_USB2_BASE,
|
||||
.end = TEGRA_USB2_BASE + TEGRA_USB2_SIZE - 1,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
[1] = {
|
||||
.start = INT_USB2,
|
||||
.end = INT_USB2,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
};
|
||||
|
||||
static struct resource tegra_usb3_resources[] = {
|
||||
[0] = {
|
||||
.start = TEGRA_USB3_BASE,
|
||||
.end = TEGRA_USB3_BASE + TEGRA_USB3_SIZE - 1,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
[1] = {
|
||||
.start = INT_USB3,
|
||||
.end = INT_USB3,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
};
|
||||
|
||||
static u64 tegra_ehci_dmamask = DMA_BIT_MASK(32);
|
||||
|
||||
struct platform_device tegra_ehci1_device = {
|
||||
.name = "tegra-ehci",
|
||||
.id = 0,
|
||||
.dev = {
|
||||
.dma_mask = &tegra_ehci_dmamask,
|
||||
.coherent_dma_mask = DMA_BIT_MASK(32),
|
||||
},
|
||||
.resource = tegra_usb1_resources,
|
||||
.num_resources = ARRAY_SIZE(tegra_usb1_resources),
|
||||
};
|
||||
|
||||
struct platform_device tegra_ehci2_device = {
|
||||
.name = "tegra-ehci",
|
||||
.id = 1,
|
||||
.dev = {
|
||||
.dma_mask = &tegra_ehci_dmamask,
|
||||
.coherent_dma_mask = DMA_BIT_MASK(32),
|
||||
},
|
||||
.resource = tegra_usb2_resources,
|
||||
.num_resources = ARRAY_SIZE(tegra_usb2_resources),
|
||||
};
|
||||
|
||||
struct platform_device tegra_ehci3_device = {
|
||||
.name = "tegra-ehci",
|
||||
.id = 2,
|
||||
.dev = {
|
||||
.dma_mask = &tegra_ehci_dmamask,
|
||||
.coherent_dma_mask = DMA_BIT_MASK(32),
|
||||
},
|
||||
.resource = tegra_usb3_resources,
|
||||
.num_resources = ARRAY_SIZE(tegra_usb3_resources),
|
||||
};
|
||||
|
||||
static struct resource tegra_pmu_resources[] = {
|
||||
[0] = {
|
||||
.start = INT_CPU0_PMU_INTR,
|
||||
.end = INT_CPU0_PMU_INTR,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
[1] = {
|
||||
.start = INT_CPU1_PMU_INTR,
|
||||
.end = INT_CPU1_PMU_INTR,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
};
|
||||
|
||||
struct platform_device tegra_pmu_device = {
|
||||
.name = "arm-pmu",
|
||||
.id = ARM_PMU_DEVICE_CPU,
|
||||
.num_resources = ARRAY_SIZE(tegra_pmu_resources),
|
||||
.resource = tegra_pmu_resources,
|
||||
};
|
||||
|
||||
static struct resource tegra_uarta_resources[] = {
|
||||
[0] = {
|
||||
.start = TEGRA_UARTA_BASE,
|
||||
.end = TEGRA_UARTA_BASE + TEGRA_UARTA_SIZE - 1,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
[1] = {
|
||||
.start = INT_UARTA,
|
||||
.end = INT_UARTA,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
};
|
||||
|
||||
static struct resource tegra_uartb_resources[] = {
|
||||
[0] = {
|
||||
.start = TEGRA_UARTB_BASE,
|
||||
.end = TEGRA_UARTB_BASE + TEGRA_UARTB_SIZE - 1,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
[1] = {
|
||||
.start = INT_UARTB,
|
||||
.end = INT_UARTB,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
};
|
||||
|
||||
static struct resource tegra_uartc_resources[] = {
|
||||
[0] = {
|
||||
.start = TEGRA_UARTC_BASE,
|
||||
.end = TEGRA_UARTC_BASE + TEGRA_UARTC_SIZE - 1,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
[1] = {
|
||||
.start = INT_UARTC,
|
||||
.end = INT_UARTC,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
};
|
||||
|
||||
static struct resource tegra_uartd_resources[] = {
|
||||
[0] = {
|
||||
.start = TEGRA_UARTD_BASE,
|
||||
.end = TEGRA_UARTD_BASE + TEGRA_UARTD_SIZE - 1,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
[1] = {
|
||||
.start = INT_UARTD,
|
||||
.end = INT_UARTD,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
};
|
||||
|
||||
static struct resource tegra_uarte_resources[] = {
|
||||
[0] = {
|
||||
.start = TEGRA_UARTE_BASE,
|
||||
.end = TEGRA_UARTE_BASE + TEGRA_UARTE_SIZE - 1,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
[1] = {
|
||||
.start = INT_UARTE,
|
||||
.end = INT_UARTE,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
};
|
||||
|
||||
struct platform_device tegra_uarta_device = {
|
||||
.name = "tegra_uart",
|
||||
.id = 0,
|
||||
.num_resources = ARRAY_SIZE(tegra_uarta_resources),
|
||||
.resource = tegra_uarta_resources,
|
||||
.dev = {
|
||||
.coherent_dma_mask = DMA_BIT_MASK(32),
|
||||
},
|
||||
};
|
||||
|
||||
struct platform_device tegra_uartb_device = {
|
||||
.name = "tegra_uart",
|
||||
.id = 1,
|
||||
.num_resources = ARRAY_SIZE(tegra_uartb_resources),
|
||||
.resource = tegra_uartb_resources,
|
||||
.dev = {
|
||||
.coherent_dma_mask = DMA_BIT_MASK(32),
|
||||
},
|
||||
};
|
||||
|
||||
struct platform_device tegra_uartc_device = {
|
||||
.name = "tegra_uart",
|
||||
.id = 2,
|
||||
.num_resources = ARRAY_SIZE(tegra_uartc_resources),
|
||||
.resource = tegra_uartc_resources,
|
||||
.dev = {
|
||||
.coherent_dma_mask = DMA_BIT_MASK(32),
|
||||
},
|
||||
};
|
||||
|
||||
struct platform_device tegra_uartd_device = {
|
||||
.name = "tegra_uart",
|
||||
.id = 3,
|
||||
.num_resources = ARRAY_SIZE(tegra_uartd_resources),
|
||||
.resource = tegra_uartd_resources,
|
||||
.dev = {
|
||||
.coherent_dma_mask = DMA_BIT_MASK(32),
|
||||
},
|
||||
};
|
||||
|
||||
struct platform_device tegra_uarte_device = {
|
||||
.name = "tegra_uart",
|
||||
.id = 4,
|
||||
.num_resources = ARRAY_SIZE(tegra_uarte_resources),
|
||||
.resource = tegra_uarte_resources,
|
||||
.dev = {
|
||||
.coherent_dma_mask = DMA_BIT_MASK(32),
|
||||
},
|
||||
};
|
46
arch/arm/mach-tegra/devices.h
Normal file
46
arch/arm/mach-tegra/devices.h
Normal file
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* Copyright (C) 2010,2011 Google, Inc.
|
||||
*
|
||||
* Author:
|
||||
* Colin Cross <ccross@android.com>
|
||||
* Erik Gilling <ccross@android.com>
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __MACH_TEGRA_DEVICES_H
|
||||
#define __MACH_TEGRA_DEVICES_H
|
||||
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
extern struct platform_device tegra_sdhci_device1;
|
||||
extern struct platform_device tegra_sdhci_device2;
|
||||
extern struct platform_device tegra_sdhci_device3;
|
||||
extern struct platform_device tegra_sdhci_device4;
|
||||
extern struct platform_device tegra_i2c_device1;
|
||||
extern struct platform_device tegra_i2c_device2;
|
||||
extern struct platform_device tegra_i2c_device3;
|
||||
extern struct platform_device tegra_i2c_device4;
|
||||
extern struct platform_device tegra_spi_device1;
|
||||
extern struct platform_device tegra_spi_device2;
|
||||
extern struct platform_device tegra_spi_device3;
|
||||
extern struct platform_device tegra_spi_device4;
|
||||
extern struct platform_device tegra_ehci1_device;
|
||||
extern struct platform_device tegra_ehci2_device;
|
||||
extern struct platform_device tegra_ehci3_device;
|
||||
extern struct platform_device tegra_uarta_device;
|
||||
extern struct platform_device tegra_uartb_device;
|
||||
extern struct platform_device tegra_uartc_device;
|
||||
extern struct platform_device tegra_uartd_device;
|
||||
extern struct platform_device tegra_uarte_device;
|
||||
extern struct platform_device tegra_pmu_device;
|
||||
|
||||
#endif
|
|
@ -27,9 +27,11 @@
|
|||
#include <linux/err.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/clk.h>
|
||||
#include <mach/dma.h>
|
||||
#include <mach/irqs.h>
|
||||
#include <mach/iomap.h>
|
||||
#include <mach/suspend.h>
|
||||
|
||||
#define APB_DMA_GEN 0x000
|
||||
#define GEN_ENABLE (1<<31)
|
||||
|
@ -120,17 +122,14 @@ struct tegra_dma_channel {
|
|||
void __iomem *addr;
|
||||
int mode;
|
||||
int irq;
|
||||
|
||||
/* Register shadow */
|
||||
u32 csr;
|
||||
u32 ahb_seq;
|
||||
u32 ahb_ptr;
|
||||
u32 apb_seq;
|
||||
u32 apb_ptr;
|
||||
int req_transfer_count;
|
||||
};
|
||||
|
||||
#define NV_DMA_MAX_CHANNELS 32
|
||||
|
||||
static bool tegra_dma_initialized;
|
||||
static DEFINE_MUTEX(tegra_dma_lock);
|
||||
|
||||
static DECLARE_BITMAP(channel_usage, NV_DMA_MAX_CHANNELS);
|
||||
static struct tegra_dma_channel dma_channels[NV_DMA_MAX_CHANNELS];
|
||||
|
||||
|
@ -138,7 +137,6 @@ static void tegra_dma_update_hw(struct tegra_dma_channel *ch,
|
|||
struct tegra_dma_req *req);
|
||||
static void tegra_dma_update_hw_partial(struct tegra_dma_channel *ch,
|
||||
struct tegra_dma_req *req);
|
||||
static void tegra_dma_init_hw(struct tegra_dma_channel *ch);
|
||||
static void tegra_dma_stop(struct tegra_dma_channel *ch);
|
||||
|
||||
void tegra_dma_flush(struct tegra_dma_channel *ch)
|
||||
|
@ -150,6 +148,9 @@ void tegra_dma_dequeue(struct tegra_dma_channel *ch)
|
|||
{
|
||||
struct tegra_dma_req *req;
|
||||
|
||||
if (tegra_dma_is_empty(ch))
|
||||
return;
|
||||
|
||||
req = list_entry(ch->list.next, typeof(*req), node);
|
||||
|
||||
tegra_dma_dequeue_req(ch, req);
|
||||
|
@ -158,10 +159,10 @@ void tegra_dma_dequeue(struct tegra_dma_channel *ch)
|
|||
|
||||
void tegra_dma_stop(struct tegra_dma_channel *ch)
|
||||
{
|
||||
unsigned int csr;
|
||||
unsigned int status;
|
||||
u32 csr;
|
||||
u32 status;
|
||||
|
||||
csr = ch->csr;
|
||||
csr = readl(ch->addr + APB_DMA_CHAN_CSR);
|
||||
csr &= ~CSR_IE_EOC;
|
||||
writel(csr, ch->addr + APB_DMA_CHAN_CSR);
|
||||
|
||||
|
@ -175,19 +176,16 @@ void tegra_dma_stop(struct tegra_dma_channel *ch)
|
|||
|
||||
int tegra_dma_cancel(struct tegra_dma_channel *ch)
|
||||
{
|
||||
unsigned int csr;
|
||||
u32 csr;
|
||||
unsigned long irq_flags;
|
||||
|
||||
spin_lock_irqsave(&ch->lock, irq_flags);
|
||||
while (!list_empty(&ch->list))
|
||||
list_del(ch->list.next);
|
||||
|
||||
csr = ch->csr;
|
||||
csr = readl(ch->addr + APB_DMA_CHAN_CSR);
|
||||
csr &= ~CSR_REQ_SEL_MASK;
|
||||
csr |= CSR_REQ_SEL_INVALID;
|
||||
|
||||
/* Set the enable as that is not shadowed */
|
||||
csr |= CSR_ENB;
|
||||
writel(csr, ch->addr + APB_DMA_CHAN_CSR);
|
||||
|
||||
tegra_dma_stop(ch);
|
||||
|
@ -229,18 +227,15 @@ int tegra_dma_dequeue_req(struct tegra_dma_channel *ch,
|
|||
* - Finally stop or program the DMA to the next buffer in the
|
||||
* list.
|
||||
*/
|
||||
csr = ch->csr;
|
||||
csr = readl(ch->addr + APB_DMA_CHAN_CSR);
|
||||
csr &= ~CSR_REQ_SEL_MASK;
|
||||
csr |= CSR_REQ_SEL_INVALID;
|
||||
|
||||
/* Set the enable as that is not shadowed */
|
||||
csr |= CSR_ENB;
|
||||
writel(csr, ch->addr + APB_DMA_CHAN_CSR);
|
||||
|
||||
/* Get the transfer count */
|
||||
status = readl(ch->addr + APB_DMA_CHAN_STA);
|
||||
to_transfer = (status & STA_COUNT_MASK) >> STA_COUNT_SHIFT;
|
||||
req_transfer_count = (ch->csr & CSR_WCOUNT_MASK) >> CSR_WCOUNT_SHIFT;
|
||||
req_transfer_count = ch->req_transfer_count;
|
||||
req_transfer_count += 1;
|
||||
to_transfer += 1;
|
||||
|
||||
|
@ -318,6 +313,7 @@ int tegra_dma_enqueue_req(struct tegra_dma_channel *ch,
|
|||
struct tegra_dma_req *req)
|
||||
{
|
||||
unsigned long irq_flags;
|
||||
struct tegra_dma_req *_req;
|
||||
int start_dma = 0;
|
||||
|
||||
if (req->size > NV_DMA_MAX_TRASFER_SIZE ||
|
||||
|
@ -328,6 +324,13 @@ int tegra_dma_enqueue_req(struct tegra_dma_channel *ch,
|
|||
|
||||
spin_lock_irqsave(&ch->lock, irq_flags);
|
||||
|
||||
list_for_each_entry(_req, &ch->list, node) {
|
||||
if (req == _req) {
|
||||
spin_unlock_irqrestore(&ch->lock, irq_flags);
|
||||
return -EEXIST;
|
||||
}
|
||||
}
|
||||
|
||||
req->bytes_transferred = 0;
|
||||
req->status = 0;
|
||||
req->buffer_status = 0;
|
||||
|
@ -348,7 +351,12 @@ EXPORT_SYMBOL(tegra_dma_enqueue_req);
|
|||
struct tegra_dma_channel *tegra_dma_allocate_channel(int mode)
|
||||
{
|
||||
int channel;
|
||||
struct tegra_dma_channel *ch;
|
||||
struct tegra_dma_channel *ch = NULL;
|
||||
|
||||
if (WARN_ON(!tegra_dma_initialized))
|
||||
return NULL;
|
||||
|
||||
mutex_lock(&tegra_dma_lock);
|
||||
|
||||
/* first channel is the shared channel */
|
||||
if (mode & TEGRA_DMA_SHARED) {
|
||||
|
@ -357,11 +365,14 @@ struct tegra_dma_channel *tegra_dma_allocate_channel(int mode)
|
|||
channel = find_first_zero_bit(channel_usage,
|
||||
ARRAY_SIZE(dma_channels));
|
||||
if (channel >= ARRAY_SIZE(dma_channels))
|
||||
return NULL;
|
||||
goto out;
|
||||
}
|
||||
__set_bit(channel, channel_usage);
|
||||
ch = &dma_channels[channel];
|
||||
ch->mode = mode;
|
||||
|
||||
out:
|
||||
mutex_unlock(&tegra_dma_lock);
|
||||
return ch;
|
||||
}
|
||||
EXPORT_SYMBOL(tegra_dma_allocate_channel);
|
||||
|
@ -371,22 +382,27 @@ void tegra_dma_free_channel(struct tegra_dma_channel *ch)
|
|||
if (ch->mode & TEGRA_DMA_SHARED)
|
||||
return;
|
||||
tegra_dma_cancel(ch);
|
||||
mutex_lock(&tegra_dma_lock);
|
||||
__clear_bit(ch->id, channel_usage);
|
||||
mutex_unlock(&tegra_dma_lock);
|
||||
}
|
||||
EXPORT_SYMBOL(tegra_dma_free_channel);
|
||||
|
||||
static void tegra_dma_update_hw_partial(struct tegra_dma_channel *ch,
|
||||
struct tegra_dma_req *req)
|
||||
{
|
||||
u32 apb_ptr;
|
||||
u32 ahb_ptr;
|
||||
|
||||
if (req->to_memory) {
|
||||
ch->apb_ptr = req->source_addr;
|
||||
ch->ahb_ptr = req->dest_addr;
|
||||
apb_ptr = req->source_addr;
|
||||
ahb_ptr = req->dest_addr;
|
||||
} else {
|
||||
ch->apb_ptr = req->dest_addr;
|
||||
ch->ahb_ptr = req->source_addr;
|
||||
apb_ptr = req->dest_addr;
|
||||
ahb_ptr = req->source_addr;
|
||||
}
|
||||
writel(ch->apb_ptr, ch->addr + APB_DMA_CHAN_APB_PTR);
|
||||
writel(ch->ahb_ptr, ch->addr + APB_DMA_CHAN_AHB_PTR);
|
||||
writel(apb_ptr, ch->addr + APB_DMA_CHAN_APB_PTR);
|
||||
writel(ahb_ptr, ch->addr + APB_DMA_CHAN_AHB_PTR);
|
||||
|
||||
req->status = TEGRA_DMA_REQ_INFLIGHT;
|
||||
return;
|
||||
|
@ -400,38 +416,39 @@ static void tegra_dma_update_hw(struct tegra_dma_channel *ch,
|
|||
int ahb_bus_width;
|
||||
int apb_bus_width;
|
||||
int index;
|
||||
unsigned long csr;
|
||||
|
||||
u32 ahb_seq;
|
||||
u32 apb_seq;
|
||||
u32 ahb_ptr;
|
||||
u32 apb_ptr;
|
||||
u32 csr;
|
||||
|
||||
ch->csr |= CSR_FLOW;
|
||||
ch->csr &= ~CSR_REQ_SEL_MASK;
|
||||
ch->csr |= req->req_sel << CSR_REQ_SEL_SHIFT;
|
||||
ch->ahb_seq &= ~AHB_SEQ_BURST_MASK;
|
||||
ch->ahb_seq |= AHB_SEQ_BURST_1;
|
||||
csr = CSR_IE_EOC | CSR_FLOW;
|
||||
ahb_seq = AHB_SEQ_INTR_ENB | AHB_SEQ_BURST_1;
|
||||
apb_seq = 0;
|
||||
|
||||
csr |= req->req_sel << CSR_REQ_SEL_SHIFT;
|
||||
|
||||
/* One shot mode is always single buffered,
|
||||
* continuous mode is always double buffered
|
||||
* */
|
||||
if (ch->mode & TEGRA_DMA_MODE_ONESHOT) {
|
||||
ch->csr |= CSR_ONCE;
|
||||
ch->ahb_seq &= ~AHB_SEQ_DBL_BUF;
|
||||
ch->csr &= ~CSR_WCOUNT_MASK;
|
||||
ch->csr |= ((req->size>>2) - 1) << CSR_WCOUNT_SHIFT;
|
||||
csr |= CSR_ONCE;
|
||||
ch->req_transfer_count = (req->size >> 2) - 1;
|
||||
} else {
|
||||
ch->csr &= ~CSR_ONCE;
|
||||
ch->ahb_seq |= AHB_SEQ_DBL_BUF;
|
||||
ahb_seq |= AHB_SEQ_DBL_BUF;
|
||||
|
||||
/* In double buffered mode, we set the size to half the
|
||||
* requested size and interrupt when half the buffer
|
||||
* is full */
|
||||
ch->csr &= ~CSR_WCOUNT_MASK;
|
||||
ch->csr |= ((req->size>>3) - 1) << CSR_WCOUNT_SHIFT;
|
||||
ch->req_transfer_count = (req->size >> 3) - 1;
|
||||
}
|
||||
|
||||
csr |= ch->req_transfer_count << CSR_WCOUNT_SHIFT;
|
||||
|
||||
if (req->to_memory) {
|
||||
ch->csr &= ~CSR_DIR;
|
||||
ch->apb_ptr = req->source_addr;
|
||||
ch->ahb_ptr = req->dest_addr;
|
||||
apb_ptr = req->source_addr;
|
||||
ahb_ptr = req->dest_addr;
|
||||
|
||||
apb_addr_wrap = req->source_wrap;
|
||||
ahb_addr_wrap = req->dest_wrap;
|
||||
|
@ -439,9 +456,9 @@ static void tegra_dma_update_hw(struct tegra_dma_channel *ch,
|
|||
ahb_bus_width = req->dest_bus_width;
|
||||
|
||||
} else {
|
||||
ch->csr |= CSR_DIR;
|
||||
ch->apb_ptr = req->dest_addr;
|
||||
ch->ahb_ptr = req->source_addr;
|
||||
csr |= CSR_DIR;
|
||||
apb_ptr = req->dest_addr;
|
||||
ahb_ptr = req->source_addr;
|
||||
|
||||
apb_addr_wrap = req->dest_wrap;
|
||||
ahb_addr_wrap = req->source_wrap;
|
||||
|
@ -460,8 +477,7 @@ static void tegra_dma_update_hw(struct tegra_dma_channel *ch,
|
|||
index++;
|
||||
} while (index < ARRAY_SIZE(apb_addr_wrap_table));
|
||||
BUG_ON(index == ARRAY_SIZE(apb_addr_wrap_table));
|
||||
ch->apb_seq &= ~APB_SEQ_WRAP_MASK;
|
||||
ch->apb_seq |= index << APB_SEQ_WRAP_SHIFT;
|
||||
apb_seq |= index << APB_SEQ_WRAP_SHIFT;
|
||||
|
||||
/* set address wrap for AHB size */
|
||||
index = 0;
|
||||
|
@ -471,55 +487,42 @@ static void tegra_dma_update_hw(struct tegra_dma_channel *ch,
|
|||
index++;
|
||||
} while (index < ARRAY_SIZE(ahb_addr_wrap_table));
|
||||
BUG_ON(index == ARRAY_SIZE(ahb_addr_wrap_table));
|
||||
ch->ahb_seq &= ~AHB_SEQ_WRAP_MASK;
|
||||
ch->ahb_seq |= index << AHB_SEQ_WRAP_SHIFT;
|
||||
ahb_seq |= index << AHB_SEQ_WRAP_SHIFT;
|
||||
|
||||
for (index = 0; index < ARRAY_SIZE(bus_width_table); index++) {
|
||||
if (bus_width_table[index] == ahb_bus_width)
|
||||
break;
|
||||
}
|
||||
BUG_ON(index == ARRAY_SIZE(bus_width_table));
|
||||
ch->ahb_seq &= ~AHB_SEQ_BUS_WIDTH_MASK;
|
||||
ch->ahb_seq |= index << AHB_SEQ_BUS_WIDTH_SHIFT;
|
||||
ahb_seq |= index << AHB_SEQ_BUS_WIDTH_SHIFT;
|
||||
|
||||
for (index = 0; index < ARRAY_SIZE(bus_width_table); index++) {
|
||||
if (bus_width_table[index] == apb_bus_width)
|
||||
break;
|
||||
}
|
||||
BUG_ON(index == ARRAY_SIZE(bus_width_table));
|
||||
ch->apb_seq &= ~APB_SEQ_BUS_WIDTH_MASK;
|
||||
ch->apb_seq |= index << APB_SEQ_BUS_WIDTH_SHIFT;
|
||||
apb_seq |= index << APB_SEQ_BUS_WIDTH_SHIFT;
|
||||
|
||||
ch->csr |= CSR_IE_EOC;
|
||||
writel(csr, ch->addr + APB_DMA_CHAN_CSR);
|
||||
writel(apb_seq, ch->addr + APB_DMA_CHAN_APB_SEQ);
|
||||
writel(apb_ptr, ch->addr + APB_DMA_CHAN_APB_PTR);
|
||||
writel(ahb_seq, ch->addr + APB_DMA_CHAN_AHB_SEQ);
|
||||
writel(ahb_ptr, ch->addr + APB_DMA_CHAN_AHB_PTR);
|
||||
|
||||
/* update hw registers with the shadow */
|
||||
writel(ch->csr, ch->addr + APB_DMA_CHAN_CSR);
|
||||
writel(ch->apb_seq, ch->addr + APB_DMA_CHAN_APB_SEQ);
|
||||
writel(ch->apb_ptr, ch->addr + APB_DMA_CHAN_APB_PTR);
|
||||
writel(ch->ahb_seq, ch->addr + APB_DMA_CHAN_AHB_SEQ);
|
||||
writel(ch->ahb_ptr, ch->addr + APB_DMA_CHAN_AHB_PTR);
|
||||
|
||||
csr = ch->csr | CSR_ENB;
|
||||
csr |= CSR_ENB;
|
||||
writel(csr, ch->addr + APB_DMA_CHAN_CSR);
|
||||
|
||||
req->status = TEGRA_DMA_REQ_INFLIGHT;
|
||||
}
|
||||
|
||||
static void tegra_dma_init_hw(struct tegra_dma_channel *ch)
|
||||
{
|
||||
/* One shot with an interrupt to CPU after transfer */
|
||||
ch->csr = CSR_ONCE | CSR_IE_EOC;
|
||||
ch->ahb_seq = AHB_SEQ_BUS_WIDTH_32 | AHB_SEQ_INTR_ENB;
|
||||
ch->apb_seq = APB_SEQ_BUS_WIDTH_32 | 1 << APB_SEQ_WRAP_SHIFT;
|
||||
}
|
||||
|
||||
static void handle_oneshot_dma(struct tegra_dma_channel *ch)
|
||||
{
|
||||
struct tegra_dma_req *req;
|
||||
unsigned long irq_flags;
|
||||
|
||||
spin_lock(&ch->lock);
|
||||
spin_lock_irqsave(&ch->lock, irq_flags);
|
||||
if (list_empty(&ch->list)) {
|
||||
spin_unlock(&ch->lock);
|
||||
spin_unlock_irqrestore(&ch->lock, irq_flags);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -527,8 +530,7 @@ static void handle_oneshot_dma(struct tegra_dma_channel *ch)
|
|||
if (req) {
|
||||
int bytes_transferred;
|
||||
|
||||
bytes_transferred =
|
||||
(ch->csr & CSR_WCOUNT_MASK) >> CSR_WCOUNT_SHIFT;
|
||||
bytes_transferred = ch->req_transfer_count;
|
||||
bytes_transferred += 1;
|
||||
bytes_transferred <<= 2;
|
||||
|
||||
|
@ -536,12 +538,12 @@ static void handle_oneshot_dma(struct tegra_dma_channel *ch)
|
|||
req->bytes_transferred = bytes_transferred;
|
||||
req->status = TEGRA_DMA_REQ_SUCCESS;
|
||||
|
||||
spin_unlock(&ch->lock);
|
||||
spin_unlock_irqrestore(&ch->lock, irq_flags);
|
||||
/* Callback should be called without any lock */
|
||||
pr_debug("%s: transferred %d bytes\n", __func__,
|
||||
req->bytes_transferred);
|
||||
req->complete(req);
|
||||
spin_lock(&ch->lock);
|
||||
spin_lock_irqsave(&ch->lock, irq_flags);
|
||||
}
|
||||
|
||||
if (!list_empty(&ch->list)) {
|
||||
|
@ -551,22 +553,55 @@ static void handle_oneshot_dma(struct tegra_dma_channel *ch)
|
|||
if (req->status != TEGRA_DMA_REQ_INFLIGHT)
|
||||
tegra_dma_update_hw(ch, req);
|
||||
}
|
||||
spin_unlock(&ch->lock);
|
||||
spin_unlock_irqrestore(&ch->lock, irq_flags);
|
||||
}
|
||||
|
||||
static void handle_continuous_dma(struct tegra_dma_channel *ch)
|
||||
{
|
||||
struct tegra_dma_req *req;
|
||||
unsigned long irq_flags;
|
||||
|
||||
spin_lock(&ch->lock);
|
||||
spin_lock_irqsave(&ch->lock, irq_flags);
|
||||
if (list_empty(&ch->list)) {
|
||||
spin_unlock(&ch->lock);
|
||||
spin_unlock_irqrestore(&ch->lock, irq_flags);
|
||||
return;
|
||||
}
|
||||
|
||||
req = list_entry(ch->list.next, typeof(*req), node);
|
||||
if (req) {
|
||||
if (req->buffer_status == TEGRA_DMA_REQ_BUF_STATUS_EMPTY) {
|
||||
bool is_dma_ping_complete;
|
||||
is_dma_ping_complete = (readl(ch->addr + APB_DMA_CHAN_STA)
|
||||
& STA_PING_PONG) ? true : false;
|
||||
if (req->to_memory)
|
||||
is_dma_ping_complete = !is_dma_ping_complete;
|
||||
/* Out of sync - Release current buffer */
|
||||
if (!is_dma_ping_complete) {
|
||||
int bytes_transferred;
|
||||
|
||||
bytes_transferred = ch->req_transfer_count;
|
||||
bytes_transferred += 1;
|
||||
bytes_transferred <<= 3;
|
||||
req->buffer_status = TEGRA_DMA_REQ_BUF_STATUS_FULL;
|
||||
req->bytes_transferred = bytes_transferred;
|
||||
req->status = TEGRA_DMA_REQ_SUCCESS;
|
||||
tegra_dma_stop(ch);
|
||||
|
||||
if (!list_is_last(&req->node, &ch->list)) {
|
||||
struct tegra_dma_req *next_req;
|
||||
|
||||
next_req = list_entry(req->node.next,
|
||||
typeof(*next_req), node);
|
||||
tegra_dma_update_hw(ch, next_req);
|
||||
}
|
||||
|
||||
list_del(&req->node);
|
||||
|
||||
/* DMA lock is NOT held when callbak is called */
|
||||
spin_unlock_irqrestore(&ch->lock, irq_flags);
|
||||
req->complete(req);
|
||||
return;
|
||||
}
|
||||
/* Load the next request into the hardware, if available
|
||||
* */
|
||||
if (!list_is_last(&req->node, &ch->list)) {
|
||||
|
@ -579,7 +614,7 @@ static void handle_continuous_dma(struct tegra_dma_channel *ch)
|
|||
req->buffer_status = TEGRA_DMA_REQ_BUF_STATUS_HALF_FULL;
|
||||
req->status = TEGRA_DMA_REQ_SUCCESS;
|
||||
/* DMA lock is NOT held when callback is called */
|
||||
spin_unlock(&ch->lock);
|
||||
spin_unlock_irqrestore(&ch->lock, irq_flags);
|
||||
if (likely(req->threshold))
|
||||
req->threshold(req);
|
||||
return;
|
||||
|
@ -590,8 +625,7 @@ static void handle_continuous_dma(struct tegra_dma_channel *ch)
|
|||
* the second interrupt */
|
||||
int bytes_transferred;
|
||||
|
||||
bytes_transferred =
|
||||
(ch->csr & CSR_WCOUNT_MASK) >> CSR_WCOUNT_SHIFT;
|
||||
bytes_transferred = ch->req_transfer_count;
|
||||
bytes_transferred += 1;
|
||||
bytes_transferred <<= 3;
|
||||
|
||||
|
@ -601,7 +635,7 @@ static void handle_continuous_dma(struct tegra_dma_channel *ch)
|
|||
list_del(&req->node);
|
||||
|
||||
/* DMA lock is NOT held when callbak is called */
|
||||
spin_unlock(&ch->lock);
|
||||
spin_unlock_irqrestore(&ch->lock, irq_flags);
|
||||
req->complete(req);
|
||||
return;
|
||||
|
||||
|
@ -609,7 +643,7 @@ static void handle_continuous_dma(struct tegra_dma_channel *ch)
|
|||
BUG();
|
||||
}
|
||||
}
|
||||
spin_unlock(&ch->lock);
|
||||
spin_unlock_irqrestore(&ch->lock, irq_flags);
|
||||
}
|
||||
|
||||
static irqreturn_t dma_isr(int irq, void *data)
|
||||
|
@ -646,6 +680,21 @@ int __init tegra_dma_init(void)
|
|||
int i;
|
||||
unsigned int irq;
|
||||
void __iomem *addr;
|
||||
struct clk *c;
|
||||
|
||||
bitmap_fill(channel_usage, NV_DMA_MAX_CHANNELS);
|
||||
|
||||
c = clk_get_sys("tegra-dma", NULL);
|
||||
if (IS_ERR(c)) {
|
||||
pr_err("Unable to get clock for APB DMA\n");
|
||||
ret = PTR_ERR(c);
|
||||
goto fail;
|
||||
}
|
||||
ret = clk_enable(c);
|
||||
if (ret != 0) {
|
||||
pr_err("Unable to enable clock for APB DMA\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
addr = IO_ADDRESS(TEGRA_APB_DMA_BASE);
|
||||
writel(GEN_ENABLE, addr + APB_DMA_GEN);
|
||||
|
@ -653,18 +702,9 @@ int __init tegra_dma_init(void)
|
|||
writel(0xFFFFFFFFul >> (31 - TEGRA_SYSTEM_DMA_CH_MAX),
|
||||
addr + APB_DMA_IRQ_MASK_SET);
|
||||
|
||||
memset(channel_usage, 0, sizeof(channel_usage));
|
||||
memset(dma_channels, 0, sizeof(dma_channels));
|
||||
|
||||
/* Reserve all the channels we are not supposed to touch */
|
||||
for (i = 0; i < TEGRA_SYSTEM_DMA_CH_MIN; i++)
|
||||
__set_bit(i, channel_usage);
|
||||
|
||||
for (i = TEGRA_SYSTEM_DMA_CH_MIN; i <= TEGRA_SYSTEM_DMA_CH_MAX; i++) {
|
||||
struct tegra_dma_channel *ch = &dma_channels[i];
|
||||
|
||||
__clear_bit(i, channel_usage);
|
||||
|
||||
ch->id = i;
|
||||
snprintf(ch->name, TEGRA_DMA_NAME_SIZE, "dma_channel_%d", i);
|
||||
|
||||
|
@ -673,7 +713,6 @@ int __init tegra_dma_init(void)
|
|||
|
||||
spin_lock_init(&ch->lock);
|
||||
INIT_LIST_HEAD(&ch->list);
|
||||
tegra_dma_init_hw(ch);
|
||||
|
||||
irq = INT_APB_DMA_CH0 + i;
|
||||
ret = request_threaded_irq(irq, dma_isr, dma_thread_fn, 0,
|
||||
|
@ -684,14 +723,15 @@ int __init tegra_dma_init(void)
|
|||
goto fail;
|
||||
}
|
||||
ch->irq = irq;
|
||||
|
||||
__clear_bit(i, channel_usage);
|
||||
}
|
||||
/* mark the shared channel allocated */
|
||||
__set_bit(TEGRA_SYSTEM_DMA_CH_MIN, channel_usage);
|
||||
|
||||
for (i = TEGRA_SYSTEM_DMA_CH_MAX+1; i < NV_DMA_MAX_CHANNELS; i++)
|
||||
__set_bit(i, channel_usage);
|
||||
tegra_dma_initialized = true;
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
fail:
|
||||
writel(0, addr + APB_DMA_GEN);
|
||||
for (i = TEGRA_SYSTEM_DMA_CH_MIN; i <= TEGRA_SYSTEM_DMA_CH_MAX; i++) {
|
||||
|
@ -701,6 +741,7 @@ fail:
|
|||
}
|
||||
return ret;
|
||||
}
|
||||
postcore_initcall(tegra_dma_init);
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static u32 apb_dma[5*TEGRA_SYSTEM_DMA_CH_NR + 3];
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include <linux/gpio.h>
|
||||
|
||||
#include <mach/iomap.h>
|
||||
#include <mach/suspend.h>
|
||||
|
||||
#define GPIO_BANK(x) ((x) >> 5)
|
||||
#define GPIO_PORT(x) (((x) >> 3) & 0x3)
|
||||
|
@ -380,6 +381,20 @@ static int __init tegra_gpio_init(void)
|
|||
|
||||
postcore_initcall(tegra_gpio_init);
|
||||
|
||||
void __init tegra_gpio_config(struct tegra_gpio_table *table, int num)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < num; i++) {
|
||||
int gpio = table[i].gpio;
|
||||
|
||||
if (table[i].enable)
|
||||
tegra_gpio_enable(gpio);
|
||||
else
|
||||
tegra_gpio_disable(gpio);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
|
||||
#include <linux/debugfs.h>
|
||||
|
|
|
@ -25,9 +25,7 @@ struct clk;
|
|||
void tegra_periph_reset_deassert(struct clk *c);
|
||||
void tegra_periph_reset_assert(struct clk *c);
|
||||
|
||||
int clk_enable_cansleep(struct clk *clk);
|
||||
void clk_disable_cansleep(struct clk *clk);
|
||||
int clk_set_rate_cansleep(struct clk *clk, unsigned long rate);
|
||||
int clk_set_parent_cansleep(struct clk *clk, struct clk *parent);
|
||||
unsigned long clk_get_rate_all_locked(struct clk *c);
|
||||
void tegra_sdmmc_tap_delay(struct clk *c, int delay);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -19,30 +19,15 @@
|
|||
*/
|
||||
|
||||
#include <mach/io.h>
|
||||
#include <mach/iomap.h>
|
||||
|
||||
.macro addruart, rp, rv
|
||||
ldr \rp, =IO_APB_PHYS @ physical
|
||||
ldr \rv, =IO_APB_VIRT @ virtual
|
||||
#if defined(CONFIG_TEGRA_DEBUG_UART_NONE)
|
||||
#error "A debug UART must be selected in the kernel config to use DEBUG_LL"
|
||||
#elif defined(CONFIG_TEGRA_DEBUG_UARTA)
|
||||
orr \rp, \rp, #0x6000
|
||||
orr \rv, \rv, #0x6000
|
||||
#elif defined(CONFIG_TEGRA_DEBUG_UARTB)
|
||||
orr \rp, \rp, #0x6000
|
||||
orr \rp, \rp, #0x40
|
||||
orr \rv, \rv, #0x6000
|
||||
orr \rv, \rv, #0x40
|
||||
#elif defined(CONFIG_TEGRA_DEBUG_UARTC)
|
||||
orr \rp, \rp, #0x6200
|
||||
orr \rv, \rv, #0x6200
|
||||
#elif defined(CONFIG_TEGRA_DEBUG_UARTD)
|
||||
orr \rp, \rp, #0x6300
|
||||
orr \rv, \rv, #0x6300
|
||||
#elif defined(CONFIG_TEGRA_DEBUG_UARTE)
|
||||
orr \rp, \rp, #0x6400
|
||||
orr \rv, \rv, #0x6400
|
||||
#endif
|
||||
orr \rp, \rp, #(TEGRA_DEBUG_UART_BASE & 0xFF)
|
||||
orr \rp, \rp, #(TEGRA_DEBUG_UART_BASE & 0xFF00)
|
||||
orr \rv, \rv, #(TEGRA_DEBUG_UART_BASE & 0xFF)
|
||||
orr \rv, \rv, #(TEGRA_DEBUG_UART_BASE & 0xFF00)
|
||||
.endm
|
||||
|
||||
#define UART_SHIFT 2
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#ifndef __MACH_TEGRA_GPIO_H
|
||||
#define __MACH_TEGRA_GPIO_H
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <mach/irqs.h>
|
||||
|
||||
#define TEGRA_NR_GPIOS INT_GPIO_NR
|
||||
|
@ -31,7 +32,7 @@
|
|||
#define gpio_cansleep __gpio_cansleep
|
||||
|
||||
#define TEGRA_GPIO_TO_IRQ(gpio) (INT_GPIO_BASE + (gpio))
|
||||
#define TEGRA_IRQ_TO_GPIO(irq) ((gpio) - INT_GPIO_BASE)
|
||||
#define TEGRA_IRQ_TO_GPIO(irq) ((irq) - INT_GPIO_BASE)
|
||||
|
||||
static inline int gpio_to_irq(unsigned int gpio)
|
||||
{
|
||||
|
@ -47,6 +48,12 @@ static inline int irq_to_gpio(unsigned int irq)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
struct tegra_gpio_table {
|
||||
int gpio; /* GPIO number */
|
||||
bool enable; /* Enable for GPIO at init? */
|
||||
};
|
||||
|
||||
void tegra_gpio_config(struct tegra_gpio_table *table, int num);
|
||||
void tegra_gpio_enable(int gpio);
|
||||
void tegra_gpio_disable(int gpio);
|
||||
|
||||
|
|
22
arch/arm/mach-tegra/include/mach/harmony_audio.h
Normal file
22
arch/arm/mach-tegra/include/mach/harmony_audio.h
Normal file
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
* arch/arm/mach-tegra/include/mach/harmony_audio.h
|
||||
*
|
||||
* Copyright 2011 NVIDIA, Inc.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
struct harmony_audio_platform_data {
|
||||
int gpio_spkr_en;
|
||||
int gpio_hp_det;
|
||||
int gpio_int_mic_en;
|
||||
int gpio_ext_mic_en;
|
||||
};
|
|
@ -26,6 +26,9 @@
|
|||
#define TEGRA_IRAM_BASE 0x40000000
|
||||
#define TEGRA_IRAM_SIZE SZ_256K
|
||||
|
||||
#define TEGRA_HOST1X_BASE 0x50000000
|
||||
#define TEGRA_HOST1X_SIZE 0x24000
|
||||
|
||||
#define TEGRA_ARM_PERIF_BASE 0x50040000
|
||||
#define TEGRA_ARM_PERIF_SIZE SZ_8K
|
||||
|
||||
|
@ -35,12 +38,30 @@
|
|||
#define TEGRA_ARM_INT_DIST_BASE 0x50041000
|
||||
#define TEGRA_ARM_INT_DIST_SIZE SZ_4K
|
||||
|
||||
#define TEGRA_MPE_BASE 0x54040000
|
||||
#define TEGRA_MPE_SIZE SZ_256K
|
||||
|
||||
#define TEGRA_VI_BASE 0x54080000
|
||||
#define TEGRA_VI_SIZE SZ_256K
|
||||
|
||||
#define TEGRA_ISP_BASE 0x54100000
|
||||
#define TEGRA_ISP_SIZE SZ_256K
|
||||
|
||||
#define TEGRA_DISPLAY_BASE 0x54200000
|
||||
#define TEGRA_DISPLAY_SIZE SZ_256K
|
||||
|
||||
#define TEGRA_DISPLAY2_BASE 0x54240000
|
||||
#define TEGRA_DISPLAY2_SIZE SZ_256K
|
||||
|
||||
#define TEGRA_HDMI_BASE 0x54280000
|
||||
#define TEGRA_HDMI_SIZE SZ_256K
|
||||
|
||||
#define TEGRA_GART_BASE 0x58000000
|
||||
#define TEGRA_GART_SIZE SZ_32M
|
||||
|
||||
#define TEGRA_RES_SEMA_BASE 0x60001000
|
||||
#define TEGRA_RES_SEMA_SIZE SZ_4K
|
||||
|
||||
#define TEGRA_PRIMARY_ICTLR_BASE 0x60004000
|
||||
#define TEGRA_PRIMARY_ICTLR_SIZE SZ_64
|
||||
|
||||
|
@ -140,6 +161,18 @@
|
|||
#define TEGRA_PWFM_BASE 0x7000A000
|
||||
#define TEGRA_PWFM_SIZE SZ_256
|
||||
|
||||
#define TEGRA_PWFM0_BASE 0x7000A000
|
||||
#define TEGRA_PWFM0_SIZE 4
|
||||
|
||||
#define TEGRA_PWFM1_BASE 0x7000A010
|
||||
#define TEGRA_PWFM1_SIZE 4
|
||||
|
||||
#define TEGRA_PWFM2_BASE 0x7000A020
|
||||
#define TEGRA_PWFM2_SIZE 4
|
||||
|
||||
#define TEGRA_PWFM3_BASE 0x7000A030
|
||||
#define TEGRA_PWFM3_SIZE 4
|
||||
|
||||
#define TEGRA_MIPI_BASE 0x7000B000
|
||||
#define TEGRA_MIPI_SIZE SZ_256
|
||||
|
||||
|
@ -221,4 +254,18 @@
|
|||
#define TEGRA_SDMMC4_BASE 0xC8000600
|
||||
#define TEGRA_SDMMC4_SIZE SZ_512
|
||||
|
||||
#if defined(CONFIG_TEGRA_DEBUG_UART_NONE)
|
||||
# define TEGRA_DEBUG_UART_BASE 0
|
||||
#elif defined(CONFIG_TEGRA_DEBUG_UARTA)
|
||||
# define TEGRA_DEBUG_UART_BASE TEGRA_UARTA_BASE
|
||||
#elif defined(CONFIG_TEGRA_DEBUG_UARTB)
|
||||
# define TEGRA_DEBUG_UART_BASE TEGRA_UARTB_BASE
|
||||
#elif defined(CONFIG_TEGRA_DEBUG_UARTC)
|
||||
# define TEGRA_DEBUG_UART_BASE TEGRA_UARTC_BASE
|
||||
#elif defined(CONFIG_TEGRA_DEBUG_UARTD)
|
||||
# define TEGRA_DEBUG_UART_BASE TEGRA_UARTD_BASE
|
||||
#elif defined(CONFIG_TEGRA_DEBUG_UARTE)
|
||||
# define TEGRA_DEBUG_UART_BASE TEGRA_UARTE_BASE
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
|
@ -88,7 +88,7 @@
|
|||
#define INT_SYS_STATS_MON (INT_SEC_BASE + 22)
|
||||
#define INT_GPIO5 (INT_SEC_BASE + 23)
|
||||
#define INT_CPU0_PMU_INTR (INT_SEC_BASE + 24)
|
||||
#define INT_CPU2_PMU_INTR (INT_SEC_BASE + 25)
|
||||
#define INT_CPU1_PMU_INTR (INT_SEC_BASE + 25)
|
||||
#define INT_SEC_RES_26 (INT_SEC_BASE + 26)
|
||||
#define INT_S_LINK1 (INT_SEC_BASE + 27)
|
||||
#define INT_APB_DMA_COP (INT_SEC_BASE + 28)
|
||||
|
@ -166,10 +166,18 @@
|
|||
#define INT_QUAD_RES_30 (INT_QUAD_BASE + 30)
|
||||
#define INT_QUAD_RES_31 (INT_QUAD_BASE + 31)
|
||||
|
||||
#define INT_GPIO_BASE (INT_QUAD_BASE + 32)
|
||||
#define INT_MAIN_NR (INT_QUAD_BASE + 32 - INT_PRI_BASE)
|
||||
|
||||
#define INT_GPIO_BASE (INT_PRI_BASE + INT_MAIN_NR)
|
||||
|
||||
#define INT_GPIO_NR (28 * 8)
|
||||
|
||||
#define NR_IRQS (INT_GPIO_BASE + INT_GPIO_NR)
|
||||
#define TEGRA_NR_IRQS (INT_GPIO_BASE + INT_GPIO_NR)
|
||||
|
||||
#define INT_BOARD_BASE TEGRA_NR_IRQS
|
||||
#define NR_BOARD_IRQS 32
|
||||
|
||||
#define NR_IRQS (INT_BOARD_BASE + NR_BOARD_IRQS)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
|
@ -27,5 +27,9 @@ int tegra_legacy_force_irq_status(unsigned int irq);
|
|||
void tegra_legacy_select_fiq(unsigned int irq, bool fiq);
|
||||
unsigned long tegra_legacy_vfiq(int nr);
|
||||
unsigned long tegra_legacy_class(int nr);
|
||||
int tegra_legacy_irq_set_wake(int irq, int enable);
|
||||
void tegra_legacy_irq_set_lp1_wake_mask(void);
|
||||
void tegra_legacy_irq_restore_mask(void);
|
||||
void tegra_init_legacy_irq(void);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -167,6 +167,16 @@ enum tegra_drive_pingroup {
|
|||
TEGRA_DRIVE_PINGROUP_XM2D,
|
||||
TEGRA_DRIVE_PINGROUP_XM2CLK,
|
||||
TEGRA_DRIVE_PINGROUP_MEMCOMP,
|
||||
TEGRA_DRIVE_PINGROUP_SDIO1,
|
||||
TEGRA_DRIVE_PINGROUP_CRT,
|
||||
TEGRA_DRIVE_PINGROUP_DDC,
|
||||
TEGRA_DRIVE_PINGROUP_GMA,
|
||||
TEGRA_DRIVE_PINGROUP_GMB,
|
||||
TEGRA_DRIVE_PINGROUP_GMC,
|
||||
TEGRA_DRIVE_PINGROUP_GMD,
|
||||
TEGRA_DRIVE_PINGROUP_GME,
|
||||
TEGRA_DRIVE_PINGROUP_OWR,
|
||||
TEGRA_DRIVE_PINGROUP_UAD,
|
||||
TEGRA_MAX_DRIVE_PINGROUP,
|
||||
};
|
||||
|
||||
|
|
40
arch/arm/mach-tegra/include/mach/powergate.h
Normal file
40
arch/arm/mach-tegra/include/mach/powergate.h
Normal file
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* drivers/regulator/tegra-regulator.c
|
||||
*
|
||||
* Copyright (c) 2010 Google, Inc
|
||||
*
|
||||
* Author:
|
||||
* Colin Cross <ccross@google.com>
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _MACH_TEGRA_POWERGATE_H_
|
||||
#define _MACH_TEGRA_POWERGATE_H_
|
||||
|
||||
#define TEGRA_POWERGATE_CPU 0
|
||||
#define TEGRA_POWERGATE_3D 1
|
||||
#define TEGRA_POWERGATE_VENC 2
|
||||
#define TEGRA_POWERGATE_PCIE 3
|
||||
#define TEGRA_POWERGATE_VDEC 4
|
||||
#define TEGRA_POWERGATE_L2 5
|
||||
#define TEGRA_POWERGATE_MPE 6
|
||||
#define TEGRA_NUM_POWERGATE 7
|
||||
|
||||
int tegra_powergate_power_on(int id);
|
||||
int tegra_powergate_power_off(int id);
|
||||
bool tegra_powergate_is_powered(int id);
|
||||
int tegra_powergate_remove_clamping(int id);
|
||||
|
||||
/* Must be called with clk disabled, and returns with clk enabled */
|
||||
int tegra_powergate_sequence_power_up(int id, struct clk *clk);
|
||||
|
||||
#endif /* _MACH_TEGRA_POWERGATE_H_ */
|
38
arch/arm/mach-tegra/include/mach/suspend.h
Normal file
38
arch/arm/mach-tegra/include/mach/suspend.h
Normal file
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* arch/arm/mach-tegra/include/mach/suspend.h
|
||||
*
|
||||
* Copyright (C) 2010 Google, Inc.
|
||||
*
|
||||
* Author:
|
||||
* Colin Cross <ccross@google.com>
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _MACH_TEGRA_SUSPEND_H_
|
||||
#define _MACH_TEGRA_SUSPEND_H_
|
||||
|
||||
void tegra_pinmux_suspend(void);
|
||||
void tegra_irq_suspend(void);
|
||||
void tegra_gpio_suspend(void);
|
||||
void tegra_clk_suspend(void);
|
||||
void tegra_dma_suspend(void);
|
||||
void tegra_timer_suspend(void);
|
||||
|
||||
void tegra_pinmux_resume(void);
|
||||
void tegra_irq_resume(void);
|
||||
void tegra_gpio_resume(void);
|
||||
void tegra_clk_resume(void);
|
||||
void tegra_dma_resume(void);
|
||||
void tegra_timer_resume(void);
|
||||
|
||||
#endif /* _MACH_TEGRA_SUSPEND_H_ */
|
|
@ -24,16 +24,10 @@
|
|||
#include <mach/hardware.h>
|
||||
#include <mach/iomap.h>
|
||||
|
||||
extern void (*arch_reset)(char mode, const char *cmd);
|
||||
|
||||
static inline void arch_idle(void)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void arch_reset(char mode, const char *cmd)
|
||||
{
|
||||
void __iomem *reset = IO_ADDRESS(TEGRA_CLK_RESET_BASE + 0x04);
|
||||
u32 reg = readl(reset);
|
||||
reg |= 0x04;
|
||||
writel(reg, reset);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -26,23 +26,9 @@
|
|||
|
||||
#include <mach/iomap.h>
|
||||
|
||||
#if defined(CONFIG_TEGRA_DEBUG_UARTA)
|
||||
#define DEBUG_UART_BASE TEGRA_UARTA_BASE
|
||||
#elif defined(CONFIG_TEGRA_DEBUG_UARTB)
|
||||
#define DEBUG_UART_BASE TEGRA_UARTB_BASE
|
||||
#elif defined(CONFIG_TEGRA_DEBUG_UARTC)
|
||||
#define DEBUG_UART_BASE TEGRA_UARTC_BASE
|
||||
#elif defined(CONFIG_TEGRA_DEBUG_UARTD)
|
||||
#define DEBUG_UART_BASE TEGRA_UARTD_BASE
|
||||
#elif defined(CONFIG_TEGRA_DEBUG_UARTE)
|
||||
#define DEBUG_UART_BASE TEGRA_UARTE_BASE
|
||||
#else
|
||||
#define DEBUG_UART_BASE NULL
|
||||
#endif
|
||||
|
||||
static void putc(int c)
|
||||
{
|
||||
volatile u8 *uart = (volatile u8 *)DEBUG_UART_BASE;
|
||||
volatile u8 *uart = (volatile u8 *)TEGRA_DEBUG_UART_BASE;
|
||||
int shift = 2;
|
||||
|
||||
if (uart == NULL)
|
||||
|
@ -59,7 +45,7 @@ static inline void flush(void)
|
|||
|
||||
static inline void arch_decomp_setup(void)
|
||||
{
|
||||
volatile u8 *uart = (volatile u8 *)DEBUG_UART_BASE;
|
||||
volatile u8 *uart = (volatile u8 *)TEGRA_DEBUG_UART_BASE;
|
||||
int shift = 2;
|
||||
|
||||
if (uart == NULL)
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irq.h>
|
||||
|
@ -26,73 +27,119 @@
|
|||
#include <asm/hardware/gic.h>
|
||||
|
||||
#include <mach/iomap.h>
|
||||
#include <mach/legacy_irq.h>
|
||||
#include <mach/suspend.h>
|
||||
|
||||
#include "board.h"
|
||||
|
||||
#define INT_SYS_NR (INT_GPIO_BASE - INT_PRI_BASE)
|
||||
#define INT_SYS_SZ (INT_SEC_BASE - INT_PRI_BASE)
|
||||
#define PPI_NR ((INT_SYS_NR+INT_SYS_SZ-1)/INT_SYS_SZ)
|
||||
#define PMC_CTRL 0x0
|
||||
#define PMC_CTRL_LATCH_WAKEUPS (1 << 5)
|
||||
#define PMC_WAKE_MASK 0xc
|
||||
#define PMC_WAKE_LEVEL 0x10
|
||||
#define PMC_WAKE_STATUS 0x14
|
||||
#define PMC_SW_WAKE_STATUS 0x18
|
||||
#define PMC_DPD_SAMPLE 0x20
|
||||
|
||||
#define APBDMA_IRQ_STA_CPU 0x14
|
||||
#define APBDMA_IRQ_MASK_SET 0x20
|
||||
#define APBDMA_IRQ_MASK_CLR 0x24
|
||||
static void __iomem *pmc = IO_ADDRESS(TEGRA_PMC_BASE);
|
||||
|
||||
#define ICTLR_CPU_IER 0x20
|
||||
#define ICTLR_CPU_IER_SET 0x24
|
||||
#define ICTLR_CPU_IER_CLR 0x28
|
||||
#define ICTLR_CPU_IEP_CLASS 0x2c
|
||||
#define ICTLR_COP_IER 0x30
|
||||
#define ICTLR_COP_IER_SET 0x34
|
||||
#define ICTLR_COP_IER_CLR 0x38
|
||||
#define ICTLR_COP_IEP_CLASS 0x3c
|
||||
static u32 tegra_lp0_wake_enb;
|
||||
static u32 tegra_lp0_wake_level;
|
||||
static u32 tegra_lp0_wake_level_any;
|
||||
|
||||
static void (*tegra_gic_mask_irq)(struct irq_data *d);
|
||||
static void (*tegra_gic_unmask_irq)(struct irq_data *d);
|
||||
static void (*tegra_gic_ack_irq)(struct irq_data *d);
|
||||
|
||||
#define irq_to_ictlr(irq) (((irq) - 32) >> 5)
|
||||
static void __iomem *tegra_ictlr_base = IO_ADDRESS(TEGRA_PRIMARY_ICTLR_BASE);
|
||||
#define ictlr_to_virt(ictlr) (tegra_ictlr_base + (ictlr) * 0x100)
|
||||
/* ensures that sufficient time is passed for a register write to
|
||||
* serialize into the 32KHz domain */
|
||||
static void pmc_32kwritel(u32 val, unsigned long offs)
|
||||
{
|
||||
writel(val, pmc + offs);
|
||||
udelay(130);
|
||||
}
|
||||
|
||||
int tegra_set_lp1_wake(int irq, int enable)
|
||||
{
|
||||
return tegra_legacy_irq_set_wake(irq, enable);
|
||||
}
|
||||
|
||||
void tegra_set_lp0_wake_pads(u32 wake_enb, u32 wake_level, u32 wake_any)
|
||||
{
|
||||
u32 temp;
|
||||
u32 status;
|
||||
u32 lvl;
|
||||
|
||||
wake_level &= wake_enb;
|
||||
wake_any &= wake_enb;
|
||||
|
||||
wake_level |= (tegra_lp0_wake_level & tegra_lp0_wake_enb);
|
||||
wake_any |= (tegra_lp0_wake_level_any & tegra_lp0_wake_enb);
|
||||
|
||||
wake_enb |= tegra_lp0_wake_enb;
|
||||
|
||||
pmc_32kwritel(0, PMC_SW_WAKE_STATUS);
|
||||
temp = readl(pmc + PMC_CTRL);
|
||||
temp |= PMC_CTRL_LATCH_WAKEUPS;
|
||||
pmc_32kwritel(temp, PMC_CTRL);
|
||||
temp &= ~PMC_CTRL_LATCH_WAKEUPS;
|
||||
pmc_32kwritel(temp, PMC_CTRL);
|
||||
status = readl(pmc + PMC_SW_WAKE_STATUS);
|
||||
lvl = readl(pmc + PMC_WAKE_LEVEL);
|
||||
|
||||
/* flip the wakeup trigger for any-edge triggered pads
|
||||
* which are currently asserting as wakeups */
|
||||
lvl ^= status;
|
||||
lvl &= wake_any;
|
||||
|
||||
wake_level |= lvl;
|
||||
|
||||
writel(wake_level, pmc + PMC_WAKE_LEVEL);
|
||||
/* Enable DPD sample to trigger sampling pads data and direction
|
||||
* in which pad will be driven during lp0 mode*/
|
||||
writel(0x1, pmc + PMC_DPD_SAMPLE);
|
||||
|
||||
writel(wake_enb, pmc + PMC_WAKE_MASK);
|
||||
}
|
||||
|
||||
static void tegra_mask(struct irq_data *d)
|
||||
{
|
||||
void __iomem *addr = ictlr_to_virt(irq_to_ictlr(d->irq));
|
||||
tegra_gic_mask_irq(d);
|
||||
writel(1 << (d->irq & 31), addr+ICTLR_CPU_IER_CLR);
|
||||
tegra_legacy_mask_irq(d->irq);
|
||||
}
|
||||
|
||||
static void tegra_unmask(struct irq_data *d)
|
||||
{
|
||||
void __iomem *addr = ictlr_to_virt(irq_to_ictlr(d->irq));
|
||||
tegra_gic_unmask_irq(d);
|
||||
writel(1<<(d->irq&31), addr+ICTLR_CPU_IER_SET);
|
||||
tegra_legacy_unmask_irq(d->irq);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
|
||||
static int tegra_set_wake(struct irq_data *d, unsigned int on)
|
||||
static void tegra_ack(struct irq_data *d)
|
||||
{
|
||||
return 0;
|
||||
tegra_legacy_force_irq_clr(d->irq);
|
||||
tegra_gic_ack_irq(d);
|
||||
}
|
||||
|
||||
static int tegra_retrigger(struct irq_data *d)
|
||||
{
|
||||
tegra_legacy_force_irq_set(d->irq);
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
static struct irq_chip tegra_irq = {
|
||||
.name = "PPI",
|
||||
.irq_mask = tegra_mask,
|
||||
.irq_unmask = tegra_unmask,
|
||||
#ifdef CONFIG_PM
|
||||
.irq_set_wake = tegra_set_wake,
|
||||
#endif
|
||||
.name = "PPI",
|
||||
.irq_ack = tegra_ack,
|
||||
.irq_mask = tegra_mask,
|
||||
.irq_unmask = tegra_unmask,
|
||||
.irq_retrigger = tegra_retrigger,
|
||||
};
|
||||
|
||||
void __init tegra_init_irq(void)
|
||||
{
|
||||
struct irq_chip *gic;
|
||||
unsigned int i;
|
||||
int irq;
|
||||
|
||||
for (i = 0; i < PPI_NR; i++) {
|
||||
writel(~0, ictlr_to_virt(i) + ICTLR_CPU_IER_CLR);
|
||||
writel(0, ictlr_to_virt(i) + ICTLR_CPU_IEP_CLASS);
|
||||
}
|
||||
tegra_init_legacy_irq();
|
||||
|
||||
gic_init(0, 29, IO_ADDRESS(TEGRA_ARM_INT_DIST_BASE),
|
||||
IO_ADDRESS(TEGRA_ARM_PERIF_BASE + 0x100));
|
||||
|
@ -100,72 +147,15 @@ void __init tegra_init_irq(void)
|
|||
gic = get_irq_chip(29);
|
||||
tegra_gic_unmask_irq = gic->irq_unmask;
|
||||
tegra_gic_mask_irq = gic->irq_mask;
|
||||
tegra_irq.irq_ack = gic->irq_ack;
|
||||
tegra_gic_ack_irq = gic->irq_ack;
|
||||
#ifdef CONFIG_SMP
|
||||
tegra_irq.irq_set_affinity = gic->irq_set_affinity;
|
||||
#endif
|
||||
|
||||
for (i = INT_PRI_BASE; i < INT_GPIO_BASE; i++) {
|
||||
set_irq_chip(i, &tegra_irq);
|
||||
set_irq_handler(i, handle_level_irq);
|
||||
set_irq_flags(i, IRQF_VALID);
|
||||
for (i = 0; i < INT_MAIN_NR; i++) {
|
||||
irq = INT_PRI_BASE + i;
|
||||
set_irq_chip(irq, &tegra_irq);
|
||||
set_irq_handler(irq, handle_level_irq);
|
||||
set_irq_flags(irq, IRQF_VALID);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static u32 cop_ier[PPI_NR];
|
||||
static u32 cpu_ier[PPI_NR];
|
||||
static u32 cpu_iep[PPI_NR];
|
||||
|
||||
void tegra_irq_suspend(void)
|
||||
{
|
||||
unsigned long flags;
|
||||
int i;
|
||||
|
||||
for (i = INT_PRI_BASE; i < INT_GPIO_BASE; i++) {
|
||||
struct irq_desc *desc = irq_to_desc(i);
|
||||
if (!desc)
|
||||
continue;
|
||||
if (desc->status & IRQ_WAKEUP) {
|
||||
pr_debug("irq %d is wakeup\n", i);
|
||||
continue;
|
||||
}
|
||||
disable_irq(i);
|
||||
}
|
||||
|
||||
local_irq_save(flags);
|
||||
for (i = 0; i < PPI_NR; i++) {
|
||||
void __iomem *ictlr = ictlr_to_virt(i);
|
||||
cpu_ier[i] = readl(ictlr + ICTLR_CPU_IER);
|
||||
cpu_iep[i] = readl(ictlr + ICTLR_CPU_IEP_CLASS);
|
||||
cop_ier[i] = readl(ictlr + ICTLR_COP_IER);
|
||||
writel(~0, ictlr + ICTLR_COP_IER_CLR);
|
||||
}
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
|
||||
void tegra_irq_resume(void)
|
||||
{
|
||||
unsigned long flags;
|
||||
int i;
|
||||
|
||||
local_irq_save(flags);
|
||||
for (i = 0; i < PPI_NR; i++) {
|
||||
void __iomem *ictlr = ictlr_to_virt(i);
|
||||
writel(cpu_iep[i], ictlr + ICTLR_CPU_IEP_CLASS);
|
||||
writel(~0ul, ictlr + ICTLR_CPU_IER_CLR);
|
||||
writel(cpu_ier[i], ictlr + ICTLR_CPU_IER_SET);
|
||||
writel(0, ictlr + ICTLR_COP_IEP_CLASS);
|
||||
writel(~0ul, ictlr + ICTLR_COP_IER_CLR);
|
||||
writel(cop_ier[i], ictlr + ICTLR_COP_IER_SET);
|
||||
}
|
||||
local_irq_restore(flags);
|
||||
|
||||
for (i = INT_PRI_BASE; i < INT_GPIO_BASE; i++) {
|
||||
struct irq_desc *desc = irq_to_desc(i);
|
||||
if (!desc || (desc->status & IRQ_WAKEUP))
|
||||
continue;
|
||||
enable_irq(i);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -18,16 +18,29 @@
|
|||
#include <linux/io.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <mach/iomap.h>
|
||||
#include <mach/irqs.h>
|
||||
#include <mach/legacy_irq.h>
|
||||
|
||||
#define INT_SYS_NR (INT_GPIO_BASE - INT_PRI_BASE)
|
||||
#define INT_SYS_SZ (INT_SEC_BASE - INT_PRI_BASE)
|
||||
#define PPI_NR ((INT_SYS_NR+INT_SYS_SZ-1)/INT_SYS_SZ)
|
||||
|
||||
#define ICTLR_CPU_IEP_VFIQ 0x08
|
||||
#define ICTLR_CPU_IEP_FIR 0x14
|
||||
#define ICTLR_CPU_IEP_FIR_SET 0x18
|
||||
#define ICTLR_CPU_IEP_FIR_CLR 0x1c
|
||||
|
||||
#define ICTLR_CPU_IER 0x20
|
||||
#define ICTLR_CPU_IER_SET 0x24
|
||||
#define ICTLR_CPU_IER_CLR 0x28
|
||||
#define ICTLR_CPU_IEP_CLASS 0x2C
|
||||
#define ICTLR_CPU_IEP_VFIQ 0x08
|
||||
#define ICTLR_CPU_IEP_FIR 0x14
|
||||
#define ICTLR_CPU_IEP_FIR_SET 0x18
|
||||
#define ICTLR_CPU_IEP_FIR_CLR 0x1c
|
||||
|
||||
#define ICTLR_COP_IER 0x30
|
||||
#define ICTLR_COP_IER_SET 0x34
|
||||
#define ICTLR_COP_IER_CLR 0x38
|
||||
#define ICTLR_COP_IEP_CLASS 0x3c
|
||||
|
||||
#define NUM_ICTLRS 4
|
||||
|
||||
static void __iomem *ictlr_reg_base[] = {
|
||||
IO_ADDRESS(TEGRA_PRIMARY_ICTLR_BASE),
|
||||
|
@ -36,6 +49,9 @@ static void __iomem *ictlr_reg_base[] = {
|
|||
IO_ADDRESS(TEGRA_QUATERNARY_ICTLR_BASE),
|
||||
};
|
||||
|
||||
static u32 tegra_legacy_wake_mask[4];
|
||||
static u32 tegra_legacy_saved_mask[4];
|
||||
|
||||
/* When going into deep sleep, the CPU is powered down, taking the GIC with it
|
||||
In order to wake, the wake interrupts need to be enabled in the legacy
|
||||
interrupt controller. */
|
||||
|
@ -112,3 +128,88 @@ unsigned long tegra_legacy_class(int nr)
|
|||
base = ictlr_reg_base[nr];
|
||||
return readl(base + ICTLR_CPU_IEP_CLASS);
|
||||
}
|
||||
|
||||
int tegra_legacy_irq_set_wake(int irq, int enable)
|
||||
{
|
||||
irq -= 32;
|
||||
if (enable)
|
||||
tegra_legacy_wake_mask[irq >> 5] |= 1 << (irq & 31);
|
||||
else
|
||||
tegra_legacy_wake_mask[irq >> 5] &= ~(1 << (irq & 31));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void tegra_legacy_irq_set_lp1_wake_mask(void)
|
||||
{
|
||||
void __iomem *base;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < NUM_ICTLRS; i++) {
|
||||
base = ictlr_reg_base[i];
|
||||
tegra_legacy_saved_mask[i] = readl(base + ICTLR_CPU_IER);
|
||||
writel(tegra_legacy_wake_mask[i], base + ICTLR_CPU_IER);
|
||||
}
|
||||
}
|
||||
|
||||
void tegra_legacy_irq_restore_mask(void)
|
||||
{
|
||||
void __iomem *base;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < NUM_ICTLRS; i++) {
|
||||
base = ictlr_reg_base[i];
|
||||
writel(tegra_legacy_saved_mask[i], base + ICTLR_CPU_IER);
|
||||
}
|
||||
}
|
||||
|
||||
void tegra_init_legacy_irq(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < NUM_ICTLRS; i++) {
|
||||
void __iomem *ictlr = ictlr_reg_base[i];
|
||||
writel(~0, ictlr + ICTLR_CPU_IER_CLR);
|
||||
writel(0, ictlr + ICTLR_CPU_IEP_CLASS);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static u32 cop_ier[NUM_ICTLRS];
|
||||
static u32 cpu_ier[NUM_ICTLRS];
|
||||
static u32 cpu_iep[NUM_ICTLRS];
|
||||
|
||||
void tegra_irq_suspend(void)
|
||||
{
|
||||
unsigned long flags;
|
||||
int i;
|
||||
|
||||
local_irq_save(flags);
|
||||
for (i = 0; i < NUM_ICTLRS; i++) {
|
||||
void __iomem *ictlr = ictlr_reg_base[i];
|
||||
cpu_ier[i] = readl(ictlr + ICTLR_CPU_IER);
|
||||
cpu_iep[i] = readl(ictlr + ICTLR_CPU_IEP_CLASS);
|
||||
cop_ier[i] = readl(ictlr + ICTLR_COP_IER);
|
||||
writel(~0, ictlr + ICTLR_COP_IER_CLR);
|
||||
}
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
|
||||
void tegra_irq_resume(void)
|
||||
{
|
||||
unsigned long flags;
|
||||
int i;
|
||||
|
||||
local_irq_save(flags);
|
||||
for (i = 0; i < NUM_ICTLRS; i++) {
|
||||
void __iomem *ictlr = ictlr_reg_base[i];
|
||||
writel(cpu_iep[i], ictlr + ICTLR_CPU_IEP_CLASS);
|
||||
writel(~0ul, ictlr + ICTLR_CPU_IER_CLR);
|
||||
writel(cpu_ier[i], ictlr + ICTLR_CPU_IER_SET);
|
||||
writel(0, ictlr + ICTLR_COP_IEP_CLASS);
|
||||
writel(~0ul, ictlr + ICTLR_COP_IER_CLR);
|
||||
writel(cop_ier[i], ictlr + ICTLR_COP_IER_SET);
|
||||
}
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -39,6 +39,7 @@
|
|||
#include <mach/pinmux.h>
|
||||
#include <mach/iomap.h>
|
||||
#include <mach/clk.h>
|
||||
#include <mach/powergate.h>
|
||||
|
||||
/* register definitions */
|
||||
#define AFI_OFFSET 0x3800
|
||||
|
@ -682,26 +683,43 @@ static void tegra_pcie_xclk_clamp(bool clamp)
|
|||
pmc_writel(reg, PMC_SCRATCH42);
|
||||
}
|
||||
|
||||
static int tegra_pcie_power_on(void)
|
||||
{
|
||||
tegra_pcie_xclk_clamp(true);
|
||||
tegra_periph_reset_assert(tegra_pcie.pcie_xclk);
|
||||
tegra_pcie_xclk_clamp(false);
|
||||
|
||||
clk_enable(tegra_pcie.afi_clk);
|
||||
clk_enable(tegra_pcie.pex_clk);
|
||||
return clk_enable(tegra_pcie.pll_e);
|
||||
}
|
||||
|
||||
static void tegra_pcie_power_off(void)
|
||||
{
|
||||
tegra_periph_reset_assert(tegra_pcie.pcie_xclk);
|
||||
tegra_periph_reset_assert(tegra_pcie.afi_clk);
|
||||
tegra_periph_reset_assert(tegra_pcie.pex_clk);
|
||||
|
||||
tegra_powergate_power_off(TEGRA_POWERGATE_PCIE);
|
||||
tegra_pcie_xclk_clamp(true);
|
||||
}
|
||||
|
||||
static int tegra_pcie_power_regate(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
tegra_pcie_power_off();
|
||||
|
||||
tegra_pcie_xclk_clamp(true);
|
||||
|
||||
tegra_periph_reset_assert(tegra_pcie.pcie_xclk);
|
||||
tegra_periph_reset_assert(tegra_pcie.afi_clk);
|
||||
|
||||
err = tegra_powergate_sequence_power_up(TEGRA_POWERGATE_PCIE,
|
||||
tegra_pcie.pex_clk);
|
||||
if (err) {
|
||||
pr_err("PCIE: powerup sequence failed: %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
tegra_periph_reset_deassert(tegra_pcie.afi_clk);
|
||||
|
||||
tegra_pcie_xclk_clamp(false);
|
||||
|
||||
clk_enable(tegra_pcie.afi_clk);
|
||||
clk_enable(tegra_pcie.pex_clk);
|
||||
return clk_enable(tegra_pcie.pll_e);
|
||||
}
|
||||
|
||||
static int tegra_pcie_clocks_get(void)
|
||||
{
|
||||
int err;
|
||||
|
@ -759,7 +777,7 @@ static int __init tegra_pcie_get_resources(void)
|
|||
return err;
|
||||
}
|
||||
|
||||
err = tegra_pcie_power_on();
|
||||
err = tegra_pcie_power_regate();
|
||||
if (err) {
|
||||
pr_err("PCIE: failed to power up: %d\n", err);
|
||||
goto err_pwr_on;
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
|
||||
#include <mach/iomap.h>
|
||||
#include <mach/pinmux.h>
|
||||
#include <mach/suspend.h>
|
||||
|
||||
#define DRIVE_PINGROUP(pg_name, r) \
|
||||
[TEGRA_DRIVE_PINGROUP_ ## pg_name] = { \
|
||||
|
@ -65,6 +66,16 @@ const struct tegra_drive_pingroup_desc tegra_soc_drive_pingroups[TEGRA_MAX_DRIVE
|
|||
DRIVE_PINGROUP(XM2D, 0x8cc),
|
||||
DRIVE_PINGROUP(XM2CLK, 0x8d0),
|
||||
DRIVE_PINGROUP(MEMCOMP, 0x8d4),
|
||||
DRIVE_PINGROUP(SDIO1, 0x8e0),
|
||||
DRIVE_PINGROUP(CRT, 0x8ec),
|
||||
DRIVE_PINGROUP(DDC, 0x8f0),
|
||||
DRIVE_PINGROUP(GMA, 0x8f4),
|
||||
DRIVE_PINGROUP(GMB, 0x8f8),
|
||||
DRIVE_PINGROUP(GMC, 0x8fc),
|
||||
DRIVE_PINGROUP(GMD, 0x900),
|
||||
DRIVE_PINGROUP(GME, 0x904),
|
||||
DRIVE_PINGROUP(OWR, 0x908),
|
||||
DRIVE_PINGROUP(UAD, 0x90c),
|
||||
};
|
||||
|
||||
#define PINGROUP(pg_name, vdd, f0, f1, f2, f3, f_safe, \
|
||||
|
@ -216,7 +227,8 @@ const struct tegra_pingroup_desc tegra_soc_pingroups[TEGRA_MAX_PINGROUP] = {
|
|||
#define PULLUPDOWN_REG_NUM 5
|
||||
|
||||
static u32 pinmux_reg[TRISTATE_REG_NUM + PIN_MUX_CTL_REG_NUM +
|
||||
PULLUPDOWN_REG_NUM];
|
||||
PULLUPDOWN_REG_NUM +
|
||||
ARRAY_SIZE(tegra_soc_drive_pingroups)];
|
||||
|
||||
static inline unsigned long pg_readl(unsigned long offset)
|
||||
{
|
||||
|
@ -233,14 +245,17 @@ void tegra_pinmux_suspend(void)
|
|||
unsigned int i;
|
||||
u32 *ctx = pinmux_reg;
|
||||
|
||||
for (i = 0; i < TRISTATE_REG_NUM; i++)
|
||||
*ctx++ = pg_readl(TRISTATE_REG_A + i*4);
|
||||
|
||||
for (i = 0; i < PIN_MUX_CTL_REG_NUM; i++)
|
||||
*ctx++ = pg_readl(PIN_MUX_CTL_REG_A + i*4);
|
||||
|
||||
for (i = 0; i < PULLUPDOWN_REG_NUM; i++)
|
||||
*ctx++ = pg_readl(PULLUPDOWN_REG_A + i*4);
|
||||
|
||||
for (i = 0; i < TRISTATE_REG_NUM; i++)
|
||||
*ctx++ = pg_readl(TRISTATE_REG_A + i*4);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(tegra_soc_drive_pingroups); i++)
|
||||
*ctx++ = pg_readl(tegra_soc_drive_pingroups[i].reg);
|
||||
}
|
||||
|
||||
void tegra_pinmux_resume(void)
|
||||
|
@ -256,5 +271,8 @@ void tegra_pinmux_resume(void)
|
|||
|
||||
for (i = 0; i < TRISTATE_REG_NUM; i++)
|
||||
pg_writel(*ctx++, TRISTATE_REG_A + i*4);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(tegra_soc_drive_pingroups); i++)
|
||||
pg_writel(*ctx++, tegra_soc_drive_pingroups[i].reg);
|
||||
}
|
||||
#endif
|
||||
|
|
212
arch/arm/mach-tegra/powergate.c
Normal file
212
arch/arm/mach-tegra/powergate.c
Normal file
|
@ -0,0 +1,212 @@
|
|||
/*
|
||||
* drivers/powergate/tegra-powergate.c
|
||||
*
|
||||
* Copyright (c) 2010 Google, Inc
|
||||
*
|
||||
* Author:
|
||||
* Colin Cross <ccross@google.com>
|
||||
*
|
||||
* 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 <linux/kernel.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/spinlock.h>
|
||||
|
||||
#include <mach/clk.h>
|
||||
#include <mach/iomap.h>
|
||||
#include <mach/powergate.h>
|
||||
|
||||
#define PWRGATE_TOGGLE 0x30
|
||||
#define PWRGATE_TOGGLE_START (1 << 8)
|
||||
|
||||
#define REMOVE_CLAMPING 0x34
|
||||
|
||||
#define PWRGATE_STATUS 0x38
|
||||
|
||||
static DEFINE_SPINLOCK(tegra_powergate_lock);
|
||||
|
||||
static void __iomem *pmc = IO_ADDRESS(TEGRA_PMC_BASE);
|
||||
|
||||
static u32 pmc_read(unsigned long reg)
|
||||
{
|
||||
return readl(pmc + reg);
|
||||
}
|
||||
|
||||
static void pmc_write(u32 val, unsigned long reg)
|
||||
{
|
||||
writel(val, pmc + reg);
|
||||
}
|
||||
|
||||
static int tegra_powergate_set(int id, bool new_state)
|
||||
{
|
||||
bool status;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&tegra_powergate_lock, flags);
|
||||
|
||||
status = pmc_read(PWRGATE_STATUS) & (1 << id);
|
||||
|
||||
if (status == new_state) {
|
||||
spin_unlock_irqrestore(&tegra_powergate_lock, flags);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
pmc_write(PWRGATE_TOGGLE_START | id, PWRGATE_TOGGLE);
|
||||
|
||||
spin_unlock_irqrestore(&tegra_powergate_lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tegra_powergate_power_on(int id)
|
||||
{
|
||||
if (id < 0 || id >= TEGRA_NUM_POWERGATE)
|
||||
return -EINVAL;
|
||||
|
||||
return tegra_powergate_set(id, true);
|
||||
}
|
||||
|
||||
int tegra_powergate_power_off(int id)
|
||||
{
|
||||
if (id < 0 || id >= TEGRA_NUM_POWERGATE)
|
||||
return -EINVAL;
|
||||
|
||||
return tegra_powergate_set(id, false);
|
||||
}
|
||||
|
||||
bool tegra_powergate_is_powered(int id)
|
||||
{
|
||||
u32 status;
|
||||
|
||||
if (id < 0 || id >= TEGRA_NUM_POWERGATE)
|
||||
return -EINVAL;
|
||||
|
||||
status = pmc_read(PWRGATE_STATUS) & (1 << id);
|
||||
return !!status;
|
||||
}
|
||||
|
||||
int tegra_powergate_remove_clamping(int id)
|
||||
{
|
||||
u32 mask;
|
||||
|
||||
if (id < 0 || id >= TEGRA_NUM_POWERGATE)
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* Tegra 2 has a bug where PCIE and VDE clamping masks are
|
||||
* swapped relatively to the partition ids
|
||||
*/
|
||||
if (id == TEGRA_POWERGATE_VDEC)
|
||||
mask = (1 << TEGRA_POWERGATE_PCIE);
|
||||
else if (id == TEGRA_POWERGATE_PCIE)
|
||||
mask = (1 << TEGRA_POWERGATE_VDEC);
|
||||
else
|
||||
mask = (1 << id);
|
||||
|
||||
pmc_write(mask, REMOVE_CLAMPING);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Must be called with clk disabled, and returns with clk enabled */
|
||||
int tegra_powergate_sequence_power_up(int id, struct clk *clk)
|
||||
{
|
||||
int ret;
|
||||
|
||||
tegra_periph_reset_assert(clk);
|
||||
|
||||
ret = tegra_powergate_power_on(id);
|
||||
if (ret)
|
||||
goto err_power;
|
||||
|
||||
ret = clk_enable(clk);
|
||||
if (ret)
|
||||
goto err_clk;
|
||||
|
||||
udelay(10);
|
||||
|
||||
ret = tegra_powergate_remove_clamping(id);
|
||||
if (ret)
|
||||
goto err_clamp;
|
||||
|
||||
udelay(10);
|
||||
tegra_periph_reset_deassert(clk);
|
||||
|
||||
return 0;
|
||||
|
||||
err_clamp:
|
||||
clk_disable(clk);
|
||||
err_clk:
|
||||
tegra_powergate_power_off(id);
|
||||
err_power:
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
|
||||
static const char * const powergate_name[] = {
|
||||
[TEGRA_POWERGATE_CPU] = "cpu",
|
||||
[TEGRA_POWERGATE_3D] = "3d",
|
||||
[TEGRA_POWERGATE_VENC] = "venc",
|
||||
[TEGRA_POWERGATE_VDEC] = "vdec",
|
||||
[TEGRA_POWERGATE_PCIE] = "pcie",
|
||||
[TEGRA_POWERGATE_L2] = "l2",
|
||||
[TEGRA_POWERGATE_MPE] = "mpe",
|
||||
};
|
||||
|
||||
static int powergate_show(struct seq_file *s, void *data)
|
||||
{
|
||||
int i;
|
||||
|
||||
seq_printf(s, " powergate powered\n");
|
||||
seq_printf(s, "------------------\n");
|
||||
|
||||
for (i = 0; i < TEGRA_NUM_POWERGATE; i++)
|
||||
seq_printf(s, " %9s %7s\n", powergate_name[i],
|
||||
tegra_powergate_is_powered(i) ? "yes" : "no");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int powergate_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return single_open(file, powergate_show, inode->i_private);
|
||||
}
|
||||
|
||||
static const struct file_operations powergate_fops = {
|
||||
.open = powergate_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = single_release,
|
||||
};
|
||||
|
||||
static int __init powergate_debugfs_init(void)
|
||||
{
|
||||
struct dentry *d;
|
||||
int err = -ENOMEM;
|
||||
|
||||
d = debugfs_create_file("powergate", S_IRUGO, NULL, NULL,
|
||||
&powergate_fops);
|
||||
if (!d)
|
||||
return -ENOMEM;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
late_initcall(powergate_debugfs_init);
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load diff
|
@ -1,86 +0,0 @@
|
|||
/*
|
||||
* arch/arm/mach-tegra/tegra2_dvfs.c
|
||||
*
|
||||
* Copyright (C) 2010 Google, Inc.
|
||||
*
|
||||
* Author:
|
||||
* Colin Cross <ccross@google.com>
|
||||
*
|
||||
* 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 <linux/kernel.h>
|
||||
|
||||
#include "clock.h"
|
||||
#include "tegra2_dvfs.h"
|
||||
|
||||
static struct dvfs_table virtual_cpu_process_0[] = {
|
||||
{314000000, 750},
|
||||
{456000000, 825},
|
||||
{608000000, 900},
|
||||
{760000000, 975},
|
||||
{817000000, 1000},
|
||||
{912000000, 1050},
|
||||
{1000000000, 1100},
|
||||
{0, 0},
|
||||
};
|
||||
|
||||
static struct dvfs_table virtual_cpu_process_1[] = {
|
||||
{314000000, 750},
|
||||
{456000000, 825},
|
||||
{618000000, 900},
|
||||
{770000000, 975},
|
||||
{827000000, 1000},
|
||||
{922000000, 1050},
|
||||
{1000000000, 1100},
|
||||
{0, 0},
|
||||
};
|
||||
|
||||
static struct dvfs_table virtual_cpu_process_2[] = {
|
||||
{494000000, 750},
|
||||
{675000000, 825},
|
||||
{817000000, 875},
|
||||
{922000000, 925},
|
||||
{1000000000, 975},
|
||||
{0, 0},
|
||||
};
|
||||
|
||||
static struct dvfs_table virtual_cpu_process_3[] = {
|
||||
{730000000, 750},
|
||||
{760000000, 775},
|
||||
{845000000, 800},
|
||||
{1000000000, 875},
|
||||
{0, 0},
|
||||
};
|
||||
|
||||
struct dvfs tegra_dvfs_virtual_cpu_dvfs = {
|
||||
.reg_id = "vdd_cpu",
|
||||
.process_id_table = {
|
||||
{
|
||||
.process_id = 0,
|
||||
.table = virtual_cpu_process_0,
|
||||
},
|
||||
{
|
||||
.process_id = 1,
|
||||
.table = virtual_cpu_process_1,
|
||||
},
|
||||
{
|
||||
.process_id = 2,
|
||||
.table = virtual_cpu_process_2,
|
||||
},
|
||||
{
|
||||
.process_id = 3,
|
||||
.table = virtual_cpu_process_3,
|
||||
},
|
||||
},
|
||||
.process_id_table_length = 4,
|
||||
.cpu = 1,
|
||||
};
|
178
arch/arm/mach-tegra/tegra2_emc.c
Normal file
178
arch/arm/mach-tegra/tegra2_emc.c
Normal file
|
@ -0,0 +1,178 @@
|
|||
/*
|
||||
* Copyright (C) 2011 Google, Inc.
|
||||
*
|
||||
* Author:
|
||||
* Colin Cross <ccross@android.com>
|
||||
*
|
||||
* 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 <linux/kernel.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include <mach/iomap.h>
|
||||
|
||||
#include "tegra2_emc.h"
|
||||
|
||||
#ifdef CONFIG_TEGRA_EMC_SCALING_ENABLE
|
||||
static bool emc_enable = true;
|
||||
#else
|
||||
static bool emc_enable;
|
||||
#endif
|
||||
module_param(emc_enable, bool, 0644);
|
||||
|
||||
static void __iomem *emc = IO_ADDRESS(TEGRA_EMC_BASE);
|
||||
static const struct tegra_emc_table *tegra_emc_table;
|
||||
static int tegra_emc_table_size;
|
||||
|
||||
static inline void emc_writel(u32 val, unsigned long addr)
|
||||
{
|
||||
writel(val, emc + addr);
|
||||
}
|
||||
|
||||
static inline u32 emc_readl(unsigned long addr)
|
||||
{
|
||||
return readl(emc + addr);
|
||||
}
|
||||
|
||||
static const unsigned long emc_reg_addr[TEGRA_EMC_NUM_REGS] = {
|
||||
0x2c, /* RC */
|
||||
0x30, /* RFC */
|
||||
0x34, /* RAS */
|
||||
0x38, /* RP */
|
||||
0x3c, /* R2W */
|
||||
0x40, /* W2R */
|
||||
0x44, /* R2P */
|
||||
0x48, /* W2P */
|
||||
0x4c, /* RD_RCD */
|
||||
0x50, /* WR_RCD */
|
||||
0x54, /* RRD */
|
||||
0x58, /* REXT */
|
||||
0x5c, /* WDV */
|
||||
0x60, /* QUSE */
|
||||
0x64, /* QRST */
|
||||
0x68, /* QSAFE */
|
||||
0x6c, /* RDV */
|
||||
0x70, /* REFRESH */
|
||||
0x74, /* BURST_REFRESH_NUM */
|
||||
0x78, /* PDEX2WR */
|
||||
0x7c, /* PDEX2RD */
|
||||
0x80, /* PCHG2PDEN */
|
||||
0x84, /* ACT2PDEN */
|
||||
0x88, /* AR2PDEN */
|
||||
0x8c, /* RW2PDEN */
|
||||
0x90, /* TXSR */
|
||||
0x94, /* TCKE */
|
||||
0x98, /* TFAW */
|
||||
0x9c, /* TRPAB */
|
||||
0xa0, /* TCLKSTABLE */
|
||||
0xa4, /* TCLKSTOP */
|
||||
0xa8, /* TREFBW */
|
||||
0xac, /* QUSE_EXTRA */
|
||||
0x114, /* FBIO_CFG6 */
|
||||
0xb0, /* ODT_WRITE */
|
||||
0xb4, /* ODT_READ */
|
||||
0x104, /* FBIO_CFG5 */
|
||||
0x2bc, /* CFG_DIG_DLL */
|
||||
0x2c0, /* DLL_XFORM_DQS */
|
||||
0x2c4, /* DLL_XFORM_QUSE */
|
||||
0x2e0, /* ZCAL_REF_CNT */
|
||||
0x2e4, /* ZCAL_WAIT_CNT */
|
||||
0x2a8, /* AUTO_CAL_INTERVAL */
|
||||
0x2d0, /* CFG_CLKTRIM_0 */
|
||||
0x2d4, /* CFG_CLKTRIM_1 */
|
||||
0x2d8, /* CFG_CLKTRIM_2 */
|
||||
};
|
||||
|
||||
/* Select the closest EMC rate that is higher than the requested rate */
|
||||
long tegra_emc_round_rate(unsigned long rate)
|
||||
{
|
||||
int i;
|
||||
int best = -1;
|
||||
unsigned long distance = ULONG_MAX;
|
||||
|
||||
if (!tegra_emc_table)
|
||||
return -EINVAL;
|
||||
|
||||
if (!emc_enable)
|
||||
return -EINVAL;
|
||||
|
||||
pr_debug("%s: %lu\n", __func__, rate);
|
||||
|
||||
/*
|
||||
* The EMC clock rate is twice the bus rate, and the bus rate is
|
||||
* measured in kHz
|
||||
*/
|
||||
rate = rate / 2 / 1000;
|
||||
|
||||
for (i = 0; i < tegra_emc_table_size; i++) {
|
||||
if (tegra_emc_table[i].rate >= rate &&
|
||||
(tegra_emc_table[i].rate - rate) < distance) {
|
||||
distance = tegra_emc_table[i].rate - rate;
|
||||
best = i;
|
||||
}
|
||||
}
|
||||
|
||||
if (best < 0)
|
||||
return -EINVAL;
|
||||
|
||||
pr_debug("%s: using %lu\n", __func__, tegra_emc_table[best].rate);
|
||||
|
||||
return tegra_emc_table[best].rate * 2 * 1000;
|
||||
}
|
||||
|
||||
/*
|
||||
* The EMC registers have shadow registers. When the EMC clock is updated
|
||||
* in the clock controller, the shadow registers are copied to the active
|
||||
* registers, allowing glitchless memory bus frequency changes.
|
||||
* This function updates the shadow registers for a new clock frequency,
|
||||
* and relies on the clock lock on the emc clock to avoid races between
|
||||
* multiple frequency changes
|
||||
*/
|
||||
int tegra_emc_set_rate(unsigned long rate)
|
||||
{
|
||||
int i;
|
||||
int j;
|
||||
|
||||
if (!tegra_emc_table)
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* The EMC clock rate is twice the bus rate, and the bus rate is
|
||||
* measured in kHz
|
||||
*/
|
||||
rate = rate / 2 / 1000;
|
||||
|
||||
for (i = 0; i < tegra_emc_table_size; i++)
|
||||
if (tegra_emc_table[i].rate == rate)
|
||||
break;
|
||||
|
||||
if (i >= tegra_emc_table_size)
|
||||
return -EINVAL;
|
||||
|
||||
pr_debug("%s: setting to %lu\n", __func__, rate);
|
||||
|
||||
for (j = 0; j < TEGRA_EMC_NUM_REGS; j++)
|
||||
emc_writel(tegra_emc_table[i].regs[j], emc_reg_addr[j]);
|
||||
|
||||
emc_readl(tegra_emc_table[i].regs[TEGRA_EMC_NUM_REGS - 1]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void tegra_init_emc(const struct tegra_emc_table *table, int table_size)
|
||||
{
|
||||
tegra_emc_table = table;
|
||||
tegra_emc_table_size = table_size;
|
||||
}
|
27
arch/arm/mach-tegra/tegra2_emc.h
Normal file
27
arch/arm/mach-tegra/tegra2_emc.h
Normal file
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* Copyright (C) 2011 Google, Inc.
|
||||
*
|
||||
* Author:
|
||||
* Colin Cross <ccross@android.com>
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#define TEGRA_EMC_NUM_REGS 46
|
||||
|
||||
struct tegra_emc_table {
|
||||
unsigned long rate;
|
||||
u32 regs[TEGRA_EMC_NUM_REGS];
|
||||
};
|
||||
|
||||
int tegra_emc_set_rate(unsigned long rate);
|
||||
long tegra_emc_round_rate(unsigned long rate);
|
||||
void tegra_init_emc(const struct tegra_emc_table *table, int table_size);
|
|
@ -18,6 +18,7 @@
|
|||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/time.h>
|
||||
#include <linux/interrupt.h>
|
||||
|
@ -33,10 +34,15 @@
|
|||
|
||||
#include <mach/iomap.h>
|
||||
#include <mach/irqs.h>
|
||||
#include <mach/suspend.h>
|
||||
|
||||
#include "board.h"
|
||||
#include "clock.h"
|
||||
|
||||
#define RTC_SECONDS 0x08
|
||||
#define RTC_SHADOW_SECONDS 0x0c
|
||||
#define RTC_MILLISECONDS 0x10
|
||||
|
||||
#define TIMERUS_CNTR_1US 0x10
|
||||
#define TIMERUS_USEC_CFG 0x14
|
||||
#define TIMERUS_CNTR_FREEZE 0x4c
|
||||
|
@ -49,9 +55,11 @@
|
|||
#define TIMER_PTV 0x0
|
||||
#define TIMER_PCR 0x4
|
||||
|
||||
struct tegra_timer;
|
||||
|
||||
static void __iomem *timer_reg_base = IO_ADDRESS(TEGRA_TMR1_BASE);
|
||||
static void __iomem *rtc_base = IO_ADDRESS(TEGRA_RTC_BASE);
|
||||
|
||||
static struct timespec persistent_ts;
|
||||
static u64 persistent_ms, last_persistent_ms;
|
||||
|
||||
#define timer_writel(value, reg) \
|
||||
__raw_writel(value, (u32)timer_reg_base + (reg))
|
||||
|
@ -132,6 +140,42 @@ static void notrace tegra_update_sched_clock(void)
|
|||
update_sched_clock(&cd, cyc, (u32)~0);
|
||||
}
|
||||
|
||||
/*
|
||||
* tegra_rtc_read - Reads the Tegra RTC registers
|
||||
* Care must be taken that this funciton is not called while the
|
||||
* tegra_rtc driver could be executing to avoid race conditions
|
||||
* on the RTC shadow register
|
||||
*/
|
||||
u64 tegra_rtc_read_ms(void)
|
||||
{
|
||||
u32 ms = readl(rtc_base + RTC_MILLISECONDS);
|
||||
u32 s = readl(rtc_base + RTC_SHADOW_SECONDS);
|
||||
return (u64)s * MSEC_PER_SEC + ms;
|
||||
}
|
||||
|
||||
/*
|
||||
* read_persistent_clock - Return time from a persistent clock.
|
||||
*
|
||||
* Reads the time from a source which isn't disabled during PM, the
|
||||
* 32k sync timer. Convert the cycles elapsed since last read into
|
||||
* nsecs and adds to a monotonically increasing timespec.
|
||||
* Care must be taken that this funciton is not called while the
|
||||
* tegra_rtc driver could be executing to avoid race conditions
|
||||
* on the RTC shadow register
|
||||
*/
|
||||
void read_persistent_clock(struct timespec *ts)
|
||||
{
|
||||
u64 delta;
|
||||
struct timespec *tsp = &persistent_ts;
|
||||
|
||||
last_persistent_ms = persistent_ms;
|
||||
persistent_ms = tegra_rtc_read_ms();
|
||||
delta = persistent_ms - last_persistent_ms;
|
||||
|
||||
timespec_add_ns(tsp, delta * NSEC_PER_MSEC);
|
||||
*ts = *tsp;
|
||||
}
|
||||
|
||||
static irqreturn_t tegra_timer_interrupt(int irq, void *dev_id)
|
||||
{
|
||||
struct clock_event_device *evt = (struct clock_event_device *)dev_id;
|
||||
|
@ -150,9 +194,22 @@ static struct irqaction tegra_timer_irq = {
|
|||
|
||||
static void __init tegra_init_timer(void)
|
||||
{
|
||||
struct clk *clk;
|
||||
unsigned long rate = clk_measure_input_freq();
|
||||
int ret;
|
||||
|
||||
clk = clk_get_sys("timer", NULL);
|
||||
BUG_ON(IS_ERR(clk));
|
||||
clk_enable(clk);
|
||||
|
||||
/*
|
||||
* rtc registers are used by read_persistent_clock, keep the rtc clock
|
||||
* enabled
|
||||
*/
|
||||
clk = clk_get_sys("rtc-tegra", NULL);
|
||||
BUG_ON(IS_ERR(clk));
|
||||
clk_enable(clk);
|
||||
|
||||
#ifdef CONFIG_HAVE_ARM_TWD
|
||||
twd_base = IO_ADDRESS(TEGRA_ARM_PERIF_BASE + 0x600);
|
||||
#endif
|
||||
|
@ -196,10 +253,22 @@ static void __init tegra_init_timer(void)
|
|||
tegra_clockevent.cpumask = cpu_all_mask;
|
||||
tegra_clockevent.irq = tegra_timer_irq.irq;
|
||||
clockevents_register_device(&tegra_clockevent);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
struct sys_timer tegra_timer = {
|
||||
.init = tegra_init_timer,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static u32 usec_config;
|
||||
|
||||
void tegra_timer_suspend(void)
|
||||
{
|
||||
usec_config = timer_readl(TIMERUS_USEC_CFG);
|
||||
}
|
||||
|
||||
void tegra_timer_resume(void)
|
||||
{
|
||||
timer_writel(usec_config, TIMERUS_USEC_CFG);
|
||||
}
|
||||
#endif
|
||||
|
|
Loading…
Reference in a new issue