summaryrefslogtreecommitdiff
path: root/arch/arm/mach-tegra
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-tegra')
-rw-r--r--arch/arm/mach-tegra/Kconfig39
-rw-r--r--arch/arm/mach-tegra/Makefile17
-rw-r--r--arch/arm/mach-tegra/board-harmony-pcie.c24
-rw-r--r--arch/arm/mach-tegra/board-harmony-pinmux.c35
-rw-r--r--arch/arm/mach-tegra/board-harmony-power.c117
-rw-r--r--arch/arm/mach-tegra/board-harmony.c146
-rw-r--r--arch/arm/mach-tegra/board-harmony.h15
-rw-r--r--arch/arm/mach-tegra/board-paz00-pinmux.c157
-rw-r--r--arch/arm/mach-tegra/board-paz00.c128
-rw-r--r--arch/arm/mach-tegra/board-paz00.h29
-rw-r--r--arch/arm/mach-tegra/board-seaboard-pinmux.c180
-rw-r--r--arch/arm/mach-tegra/board-seaboard.c250
-rw-r--r--arch/arm/mach-tegra/board-seaboard.h41
-rw-r--r--arch/arm/mach-tegra/board-trimslice-pinmux.c154
-rw-r--r--arch/arm/mach-tegra/board-trimslice.c125
-rw-r--r--arch/arm/mach-tegra/board-trimslice.h25
-rw-r--r--arch/arm/mach-tegra/board.h4
-rw-r--r--arch/arm/mach-tegra/clock.c532
-rw-r--r--arch/arm/mach-tegra/clock.h129
-rw-r--r--arch/arm/mach-tegra/common.c27
-rw-r--r--arch/arm/mach-tegra/cpu-tegra.c100
-rw-r--r--arch/arm/mach-tegra/devices.c575
-rw-r--r--arch/arm/mach-tegra/devices.h50
-rw-r--r--arch/arm/mach-tegra/dma.c247
-rw-r--r--arch/arm/mach-tegra/gpio.c69
-rw-r--r--arch/arm/mach-tegra/include/mach/barriers.h2
-rw-r--r--arch/arm/mach-tegra/include/mach/clk.h6
-rw-r--r--arch/arm/mach-tegra/include/mach/debug-macro.S25
-rw-r--r--arch/arm/mach-tegra/include/mach/dma.h4
-rw-r--r--arch/arm/mach-tegra/include/mach/gpio.h9
-rw-r--r--arch/arm/mach-tegra/include/mach/iomap.h50
-rw-r--r--arch/arm/mach-tegra/include/mach/irqs.h14
-rw-r--r--arch/arm/mach-tegra/include/mach/kbc.h4
-rw-r--r--arch/arm/mach-tegra/include/mach/legacy_irq.h31
-rw-r--r--arch/arm/mach-tegra/include/mach/memory.h2
-rw-r--r--arch/arm/mach-tegra/include/mach/pinmux-t2.h10
-rw-r--r--arch/arm/mach-tegra/include/mach/powergate.h40
-rw-r--r--arch/arm/mach-tegra/include/mach/sdhci.h1
-rw-r--r--arch/arm/mach-tegra/include/mach/smp.h14
-rw-r--r--arch/arm/mach-tegra/include/mach/suspend.h38
-rw-r--r--arch/arm/mach-tegra/include/mach/system.h10
-rw-r--r--arch/arm/mach-tegra/include/mach/tegra_wm8903_pdata.h (renamed from arch/arm/mach-tegra/tegra2_dvfs.h)15
-rw-r--r--arch/arm/mach-tegra/include/mach/uncompress.h18
-rw-r--r--arch/arm/mach-tegra/include/mach/usb_phy.h86
-rw-r--r--arch/arm/mach-tegra/irq.c167
-rw-r--r--arch/arm/mach-tegra/legacy_irq.c114
-rw-r--r--arch/arm/mach-tegra/localtimer.c3
-rw-r--r--arch/arm/mach-tegra/pcie.c38
-rw-r--r--arch/arm/mach-tegra/pinmux-t2-tables.c26
-rw-r--r--arch/arm/mach-tegra/platsmp.c3
-rw-r--r--arch/arm/mach-tegra/powergate.c212
-rw-r--r--arch/arm/mach-tegra/tegra2_clocks.c1123
-rw-r--r--arch/arm/mach-tegra/tegra2_dvfs.c86
-rw-r--r--arch/arm/mach-tegra/tegra2_emc.c178
-rw-r--r--arch/arm/mach-tegra/tegra2_emc.h27
-rw-r--r--arch/arm/mach-tegra/timer.c93
-rw-r--r--arch/arm/mach-tegra/usb_phy.c795
57 files changed, 5194 insertions, 1265 deletions
diff --git a/arch/arm/mach-tegra/Kconfig b/arch/arm/mach-tegra/Kconfig
index acd9552f8ada..5ec1846aa1d0 100644
--- a/arch/arm/mach-tegra/Kconfig
+++ b/arch/arm/mach-tegra/Kconfig
@@ -10,6 +10,9 @@ config ARCH_TEGRA_2x_SOC
select CPU_V7
select ARM_GIC
select ARCH_REQUIRE_GPIOLIB
+ select USB_ARCH_HAS_EHCI if USB_SUPPORT
+ select USB_ULPI if USB_SUPPORT
+ select USB_ULPI_VIEWPORT if USB_SUPPORT
help
Support for NVIDIA Tegra AP20 and T20 processors, based on the
ARM CortexA9MP CPU and the ARM PL310 L2 cache controller
@@ -24,9 +27,42 @@ comment "Tegra board type"
config MACH_HARMONY
bool "Harmony board"
+ select MACH_HAS_SND_SOC_TEGRA_WM8903
help
Support for nVidia Harmony development platform
+config MACH_KAEN
+ bool "Kaen board"
+ select MACH_SEABOARD
+ select MACH_HAS_SND_SOC_TEGRA_WM8903
+ help
+ Support for the Kaen version of Seaboard
+
+config MACH_PAZ00
+ bool "Paz00 board"
+ help
+ Support for the Toshiba AC100/Dynabook AZ netbook
+
+config MACH_SEABOARD
+ bool "Seaboard board"
+ select MACH_HAS_SND_SOC_TEGRA_WM8903
+ 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 +94,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
diff --git a/arch/arm/mach-tegra/Makefile b/arch/arm/mach-tegra/Makefile
index cdbc68e4c0ca..823c703e573c 100644
--- a/arch/arm/mach-tegra/Makefile
+++ b/arch/arm/mach-tegra/Makefile
@@ -1,21 +1,34 @@
obj-y += common.o
+obj-y += devices.o
obj-y += io.o
-obj-y += irq.o legacy_irq.o
+obj-y += 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
obj-$(CONFIG_TEGRA_SYSTEM_DMA) += dma.o
obj-$(CONFIG_CPU_FREQ) += cpu-tegra.o
obj-$(CONFIG_TEGRA_PCI) += pcie.o
+obj-$(CONFIG_USB_SUPPORT) += usb_phy.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_HARMONY} += board-harmony-power.o
+
+obj-${CONFIG_MACH_PAZ00} += board-paz00.o
+obj-${CONFIG_MACH_PAZ00} += board-paz00-pinmux.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
diff --git a/arch/arm/mach-tegra/board-harmony-pcie.c b/arch/arm/mach-tegra/board-harmony-pcie.c
index f7e7d4514b6a..9c27b95b8d86 100644
--- a/arch/arm/mach-tegra/board-harmony-pcie.c
+++ b/arch/arm/mach-tegra/board-harmony-pcie.c
@@ -27,13 +27,29 @@
#ifdef CONFIG_TEGRA_PCI
+/* GPIO 3 of the PMIC */
+#define EN_VDD_1V05_GPIO (TEGRA_NR_GPIOS + 2)
+
static int __init harmony_pcie_init(void)
{
+ struct regulator *regulator = NULL;
int err;
if (!machine_is_harmony())
return 0;
+ err = gpio_request(EN_VDD_1V05_GPIO, "EN_VDD_1V05");
+ if (err)
+ return err;
+
+ gpio_direction_output(EN_VDD_1V05_GPIO, 1);
+
+ regulator = regulator_get(NULL, "pex_clk");
+ if (IS_ERR_OR_NULL(regulator))
+ goto err_reg;
+
+ regulator_enable(regulator);
+
tegra_pinmux_set_tristate(TEGRA_PINGROUP_GPV, TEGRA_TRI_NORMAL);
tegra_pinmux_set_tristate(TEGRA_PINGROUP_SLXA, TEGRA_TRI_NORMAL);
tegra_pinmux_set_tristate(TEGRA_PINGROUP_SLXK, TEGRA_TRI_NORMAL);
@@ -49,9 +65,15 @@ err_pcie:
tegra_pinmux_set_tristate(TEGRA_PINGROUP_SLXA, TEGRA_TRI_TRISTATE);
tegra_pinmux_set_tristate(TEGRA_PINGROUP_SLXK, TEGRA_TRI_TRISTATE);
+ regulator_disable(regulator);
+ regulator_put(regulator);
+err_reg:
+ gpio_free(EN_VDD_1V05_GPIO);
+
return err;
}
-subsys_initcall(harmony_pcie_init);
+/* PCI should be initialized after I2C, mfd and regulators */
+subsys_initcall_sync(harmony_pcie_init);
#endif
diff --git a/arch/arm/mach-tegra/board-harmony-pinmux.c b/arch/arm/mach-tegra/board-harmony-pinmux.c
index 50b15d500cac..4d63e2e97a8d 100644
--- a/arch/arm/mach-tegra/board-harmony-pinmux.c
+++ b/arch/arm/mach-tegra/board-harmony-pinmux.c
@@ -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[] = {
@@ -25,19 +27,19 @@ static struct tegra_pingroup_config harmony_pinmux[] = {
{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_NORMAL},
- {TEGRA_PINGROUP_CDEV1, TEGRA_MUX_OSC, TEGRA_PUPD_PULL_DOWN, 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_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_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_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},
@@ -112,13 +114,13 @@ static struct tegra_pingroup_config harmony_pinmux[] = {
{TEGRA_PINGROUP_SLXK, TEGRA_MUX_PCIE, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
{TEGRA_PINGROUP_SPDI, TEGRA_MUX_RSVD2, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
{TEGRA_PINGROUP_SPDO, TEGRA_MUX_RSVD2, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_SPIA, TEGRA_MUX_GMI, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_SPIB, TEGRA_MUX_GMI, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_SPIC, TEGRA_MUX_GMI, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL},
+ {TEGRA_PINGROUP_SPIA, TEGRA_MUX_GMI, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
+ {TEGRA_PINGROUP_SPIB, TEGRA_MUX_GMI, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
+ {TEGRA_PINGROUP_SPIC, TEGRA_MUX_GMI, 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_SPIG, TEGRA_MUX_SPI2_ALT, TEGRA_PUPD_NORMAL, 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},
@@ -138,7 +140,22 @@ 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_SD2_CD, .enable = true },
+ { .gpio = TEGRA_GPIO_SD2_WP, .enable = true },
+ { .gpio = TEGRA_GPIO_SD2_POWER, .enable = true },
+ { .gpio = TEGRA_GPIO_SD4_CD, .enable = true },
+ { .gpio = TEGRA_GPIO_SD4_WP, .enable = true },
+ { .gpio = TEGRA_GPIO_SD4_POWER, .enable = true },
+ { .gpio = TEGRA_GPIO_CDC_IRQ, .enable = true },
+ { .gpio = TEGRA_GPIO_HP_DET, .enable = true },
+ { .gpio = TEGRA_GPIO_INT_MIC_EN, .enable = true },
+ { .gpio = TEGRA_GPIO_EXT_MIC_EN, .enable = true },
+};
+
void harmony_pinmux_init(void)
{
tegra_pinmux_config_table(harmony_pinmux, ARRAY_SIZE(harmony_pinmux));
+
+ tegra_gpio_config(gpio_table, ARRAY_SIZE(gpio_table));
}
diff --git a/arch/arm/mach-tegra/board-harmony-power.c b/arch/arm/mach-tegra/board-harmony-power.c
new file mode 100644
index 000000000000..c84442cabe07
--- /dev/null
+++ b/arch/arm/mach-tegra/board-harmony-power.c
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2010 NVIDIA, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ * 02111-1307, USA
+ */
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+
+#include <linux/regulator/machine.h>
+#include <linux/mfd/tps6586x.h>
+
+#include <mach/irqs.h>
+
+#define PMC_CTRL 0x0
+#define PMC_CTRL_INTR_LOW (1 << 17)
+
+static struct regulator_consumer_supply tps658621_ldo0_supply[] = {
+ REGULATOR_SUPPLY("pex_clk", NULL),
+};
+
+static struct regulator_init_data ldo0_data = {
+ .constraints = {
+ .min_uV = 1250 * 1000,
+ .max_uV = 3300 * 1000,
+ .valid_modes_mask = (REGULATOR_MODE_NORMAL |
+ REGULATOR_MODE_STANDBY),
+ .valid_ops_mask = (REGULATOR_CHANGE_MODE |
+ REGULATOR_CHANGE_STATUS |
+ REGULATOR_CHANGE_VOLTAGE),
+ },
+ .num_consumer_supplies = ARRAY_SIZE(tps658621_ldo0_supply),
+ .consumer_supplies = tps658621_ldo0_supply,
+};
+
+#define HARMONY_REGULATOR_INIT(_id, _minmv, _maxmv) \
+ static struct regulator_init_data _id##_data = { \
+ .constraints = { \
+ .min_uV = (_minmv)*1000, \
+ .max_uV = (_maxmv)*1000, \
+ .valid_modes_mask = (REGULATOR_MODE_NORMAL | \
+ REGULATOR_MODE_STANDBY), \
+ .valid_ops_mask = (REGULATOR_CHANGE_MODE | \
+ REGULATOR_CHANGE_STATUS | \
+ REGULATOR_CHANGE_VOLTAGE), \
+ }, \
+ }
+
+HARMONY_REGULATOR_INIT(sm0, 725, 1500);
+HARMONY_REGULATOR_INIT(sm1, 725, 1500);
+HARMONY_REGULATOR_INIT(sm2, 3000, 4550);
+HARMONY_REGULATOR_INIT(ldo1, 725, 1500);
+HARMONY_REGULATOR_INIT(ldo2, 725, 1500);
+HARMONY_REGULATOR_INIT(ldo3, 1250, 3300);
+HARMONY_REGULATOR_INIT(ldo4, 1700, 2475);
+HARMONY_REGULATOR_INIT(ldo5, 1250, 3300);
+HARMONY_REGULATOR_INIT(ldo6, 1250, 3300);
+HARMONY_REGULATOR_INIT(ldo7, 1250, 3300);
+HARMONY_REGULATOR_INIT(ldo8, 1250, 3300);
+HARMONY_REGULATOR_INIT(ldo9, 1250, 3300);
+
+#define TPS_REG(_id, _data) \
+ { \
+ .id = TPS6586X_ID_##_id, \
+ .name = "tps6586x-regulator", \
+ .platform_data = _data, \
+ }
+
+static struct tps6586x_subdev_info tps_devs[] = {
+ TPS_REG(SM_0, &sm0_data),
+ TPS_REG(SM_1, &sm1_data),
+ TPS_REG(SM_2, &sm2_data),
+ TPS_REG(LDO_0, &ldo0_data),
+ TPS_REG(LDO_1, &ldo1_data),
+ TPS_REG(LDO_2, &ldo2_data),
+ TPS_REG(LDO_3, &ldo3_data),
+ TPS_REG(LDO_4, &ldo4_data),
+ TPS_REG(LDO_5, &ldo5_data),
+ TPS_REG(LDO_6, &ldo6_data),
+ TPS_REG(LDO_7, &ldo7_data),
+ TPS_REG(LDO_8, &ldo8_data),
+ TPS_REG(LDO_9, &ldo9_data),
+};
+
+static struct tps6586x_platform_data tps_platform = {
+ .irq_base = TEGRA_NR_IRQS,
+ .num_subdevs = ARRAY_SIZE(tps_devs),
+ .subdevs = tps_devs,
+ .gpio_base = TEGRA_NR_GPIOS,
+};
+
+static struct i2c_board_info __initdata harmony_regulators[] = {
+ {
+ I2C_BOARD_INFO("tps6586x", 0x34),
+ .irq = INT_EXTERNAL_PMU,
+ .platform_data = &tps_platform,
+ },
+};
+
+int __init harmony_regulator_init(void)
+{
+ i2c_register_board_info(3, harmony_regulators, 1);
+
+ return 0;
+}
diff --git a/arch/arm/mach-tegra/board-harmony.c b/arch/arm/mach-tegra/board-harmony.c
index b9dbdb1289d0..30e18bc60647 100644
--- a/arch/arm/mach-tegra/board-harmony.c
+++ b/arch/arm/mach-tegra/board-harmony.c
@@ -2,6 +2,7 @@
* arch/arm/mach-tegra/board-harmony.c
*
* Copyright (C) 2010 Google, Inc.
+ * Copyright (C) 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
@@ -22,43 +23,27 @@
#include <linux/dma-mapping.h>
#include <linux/pda_power.h>
#include <linux/io.h>
+#include <linux/gpio.h>
+#include <linux/i2c.h>
+#include <linux/i2c-tegra.h>
+
+#include <sound/wm8903.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <asm/mach/time.h>
#include <asm/setup.h>
+#include <mach/tegra_wm8903_pdata.h>
#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[] = {
{
@@ -82,8 +67,82 @@ static struct platform_device debug_uart = {
},
};
+static struct tegra_wm8903_platform_data harmony_audio_pdata = {
+ .gpio_spkr_en = TEGRA_GPIO_SPKR_EN,
+ .gpio_hp_det = TEGRA_GPIO_HP_DET,
+ .gpio_hp_mute = -1,
+ .gpio_int_mic_en = TEGRA_GPIO_INT_MIC_EN,
+ .gpio_ext_mic_en = TEGRA_GPIO_EXT_MIC_EN,
+};
+
+static struct platform_device harmony_audio_device = {
+ .name = "tegra-snd-wm8903",
+ .id = 0,
+ .dev = {
+ .platform_data = &harmony_audio_pdata,
+ },
+};
+
+static struct tegra_i2c_platform_data harmony_i2c1_platform_data = {
+ .bus_clk_rate = 400000,
+};
+
+static struct tegra_i2c_platform_data harmony_i2c2_platform_data = {
+ .bus_clk_rate = 400000,
+};
+
+static struct tegra_i2c_platform_data harmony_i2c3_platform_data = {
+ .bus_clk_rate = 400000,
+};
+
+static struct tegra_i2c_platform_data harmony_dvc_platform_data = {
+ .bus_clk_rate = 400000,
+};
+
+static struct wm8903_platform_data harmony_wm8903_pdata = {
+ .irq_active_low = 0,
+ .micdet_cfg = 0,
+ .micdet_delay = 100,
+ .gpio_base = HARMONY_GPIO_WM8903(0),
+ .gpio_cfg = {
+ WM8903_GPIO_NO_CONFIG,
+ WM8903_GPIO_NO_CONFIG,
+ 0,
+ WM8903_GPIO_NO_CONFIG,
+ WM8903_GPIO_NO_CONFIG,
+ },
+};
+
+static struct i2c_board_info __initdata wm8903_board_info = {
+ I2C_BOARD_INFO("wm8903", 0x1a),
+ .platform_data = &harmony_wm8903_pdata,
+ .irq = TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_CDC_IRQ),
+};
+
+static void __init harmony_i2c_init(void)
+{
+ tegra_i2c_device1.dev.platform_data = &harmony_i2c1_platform_data;
+ tegra_i2c_device2.dev.platform_data = &harmony_i2c2_platform_data;
+ tegra_i2c_device3.dev.platform_data = &harmony_i2c3_platform_data;
+ tegra_i2c_device4.dev.platform_data = &harmony_dvc_platform_data;
+
+ platform_device_register(&tegra_i2c_device1);
+ platform_device_register(&tegra_i2c_device2);
+ platform_device_register(&tegra_i2c_device3);
+ platform_device_register(&tegra_i2c_device4);
+
+ i2c_register_board_info(0, &wm8903_board_info, 1);
+}
+
static struct platform_device *harmony_devices[] __initdata = {
&debug_uart,
+ &tegra_sdhci_device1,
+ &tegra_sdhci_device2,
+ &tegra_sdhci_device4,
+ &tegra_i2s_device1,
+ &tegra_das_device,
+ &tegra_pcm_device,
+ &harmony_audio_device,
};
static void __init tegra_harmony_fixup(struct machine_desc *desc,
@@ -99,25 +158,54 @@ static void __init tegra_harmony_fixup(struct machine_desc *desc,
static __initdata struct tegra_clk_init_table harmony_clk_init_table[] = {
/* name parent rate enabled */
{ "uartd", "pll_p", 216000000, true },
+ { "pll_a", "pll_p_out1", 56448000, true },
+ { "pll_a_out0", "pll_a", 11289600, true },
+ { "cdev1", NULL, 0, true },
+ { "i2s1", "pll_a_out0", 11289600, false},
{ 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_SD2_CD,
+ .wp_gpio = TEGRA_GPIO_SD2_WP,
+ .power_gpio = TEGRA_GPIO_SD2_POWER,
+};
+
+static struct tegra_sdhci_platform_data sdhci_pdata4 = {
+ .cd_gpio = TEGRA_GPIO_SD4_CD,
+ .wp_gpio = TEGRA_GPIO_SD4_WP,
+ .power_gpio = TEGRA_GPIO_SD4_POWER,
+ .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));
+ harmony_i2c_init();
+ harmony_regulator_init();
}
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
diff --git a/arch/arm/mach-tegra/board-harmony.h b/arch/arm/mach-tegra/board-harmony.h
index 09ca7755dd55..1e57b071f52d 100644
--- a/arch/arm/mach-tegra/board-harmony.h
+++ b/arch/arm/mach-tegra/board-harmony.h
@@ -17,6 +17,21 @@
#ifndef _MACH_TEGRA_BOARD_HARMONY_H
#define _MACH_TEGRA_BOARD_HARMONY_H
+#define HARMONY_GPIO_WM8903(_x_) (TEGRA_NR_GPIOS + (_x_))
+
+#define TEGRA_GPIO_SD2_CD TEGRA_GPIO_PI5
+#define TEGRA_GPIO_SD2_WP TEGRA_GPIO_PH1
+#define TEGRA_GPIO_SD2_POWER TEGRA_GPIO_PT3
+#define TEGRA_GPIO_SD4_CD TEGRA_GPIO_PH2
+#define TEGRA_GPIO_SD4_WP TEGRA_GPIO_PH3
+#define TEGRA_GPIO_SD4_POWER TEGRA_GPIO_PI6
+#define TEGRA_GPIO_CDC_IRQ TEGRA_GPIO_PX3
+#define TEGRA_GPIO_SPKR_EN HARMONY_GPIO_WM8903(2)
+#define TEGRA_GPIO_HP_DET TEGRA_GPIO_PW2
+#define TEGRA_GPIO_INT_MIC_EN TEGRA_GPIO_PX0
+#define TEGRA_GPIO_EXT_MIC_EN TEGRA_GPIO_PX1
+
void harmony_pinmux_init(void);
+int harmony_regulator_init(void);
#endif
diff --git a/arch/arm/mach-tegra/board-paz00-pinmux.c b/arch/arm/mach-tegra/board-paz00-pinmux.c
new file mode 100644
index 000000000000..2643d1bd568b
--- /dev/null
+++ b/arch/arm/mach-tegra/board-paz00-pinmux.c
@@ -0,0 +1,157 @@
+/*
+ * arch/arm/mach-tegra/board-paz00-pinmux.c
+ *
+ * Copyright (C) 2010 Marc Dietrich <marvin24@gmx.de>
+ *
+ * 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/gpio.h>
+#include <mach/pinmux.h>
+
+#include "gpio-names.h"
+#include "board-paz00.h"
+
+static struct tegra_pingroup_config paz00_pinmux[] = {
+ {TEGRA_PINGROUP_ATA, TEGRA_MUX_GMI, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
+ {TEGRA_PINGROUP_ATB, TEGRA_MUX_SDIO4, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
+ {TEGRA_PINGROUP_ATC, TEGRA_MUX_GMI, 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_NORMAL},
+ {TEGRA_PINGROUP_CDEV1, TEGRA_MUX_PLLA_OUT, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_TRISTATE},
+ {TEGRA_PINGROUP_CDEV2, TEGRA_MUX_PLLP_OUT4, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
+ {TEGRA_PINGROUP_CRTP, TEGRA_MUX_CRT, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
+ {TEGRA_PINGROUP_CSUS, TEGRA_MUX_PLLC_OUT1, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_TRISTATE},
+ {TEGRA_PINGROUP_DAP1, TEGRA_MUX_DAP1, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
+ {TEGRA_PINGROUP_DAP2, TEGRA_MUX_GMI, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
+ {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_RSVD1, TEGRA_PUPD_PULL_UP, TEGRA_TRI_TRISTATE},
+ {TEGRA_PINGROUP_DTB, TEGRA_MUX_RSVD1, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
+ {TEGRA_PINGROUP_DTC, TEGRA_MUX_RSVD1, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
+ {TEGRA_PINGROUP_DTD, TEGRA_MUX_RSVD1, TEGRA_PUPD_PULL_UP, TEGRA_TRI_TRISTATE},
+ {TEGRA_PINGROUP_DTE, TEGRA_MUX_RSVD1, TEGRA_PUPD_NORMAL, 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_NORMAL, TEGRA_TRI_NORMAL},
+ {TEGRA_PINGROUP_GMC, TEGRA_MUX_GMI, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
+ {TEGRA_PINGROUP_GMD, TEGRA_MUX_GMI, 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_NORMAL},
+ {TEGRA_PINGROUP_HDINT, TEGRA_MUX_HDMI, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL},
+ {TEGRA_PINGROUP_I2CP, TEGRA_MUX_I2C, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
+ {TEGRA_PINGROUP_IRRX, TEGRA_MUX_UARTA, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL},
+ {TEGRA_PINGROUP_IRTX, TEGRA_MUX_UARTA, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL},
+ {TEGRA_PINGROUP_KBCA, TEGRA_MUX_KBC, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL},
+ {TEGRA_PINGROUP_KBCB, TEGRA_MUX_SDIO2, 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_SDIO2, 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_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_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_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_LDC, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL},
+ {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_TRISTATE},
+ {TEGRA_PINGROUP_LHP1, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_TRISTATE},
+ {TEGRA_PINGROUP_LHP2, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_TRISTATE},
+ {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_TRISTATE},
+ {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_TRISTATE},
+ {TEGRA_PINGROUP_LPW0, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_UP, TEGRA_TRI_TRISTATE},
+ {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_TRISTATE},
+ {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_TRISTATE},
+ {TEGRA_PINGROUP_LVS, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL},
+ {TEGRA_PINGROUP_OWC, TEGRA_MUX_OWR, TEGRA_PUPD_PULL_UP, 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_PWM, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
+ {TEGRA_PINGROUP_SDC, TEGRA_MUX_TWC, TEGRA_PUPD_PULL_UP, TEGRA_TRI_TRISTATE},
+ {TEGRA_PINGROUP_SDD, TEGRA_MUX_PWM, TEGRA_PUPD_PULL_UP, TEGRA_TRI_TRISTATE},
+ {TEGRA_PINGROUP_SDIO1, TEGRA_MUX_SDIO1, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
+ {TEGRA_PINGROUP_SLXA, TEGRA_MUX_PCIE, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
+ {TEGRA_PINGROUP_SLXC, TEGRA_MUX_SPI4, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
+ {TEGRA_PINGROUP_SLXD, TEGRA_MUX_SPI4, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
+ {TEGRA_PINGROUP_SLXK, TEGRA_MUX_PCIE, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
+ {TEGRA_PINGROUP_SPDI, TEGRA_MUX_RSVD2, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
+ {TEGRA_PINGROUP_SPDO, TEGRA_MUX_RSVD2, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
+ {TEGRA_PINGROUP_SPIA, TEGRA_MUX_GMI, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_TRISTATE},
+ {TEGRA_PINGROUP_SPIB, TEGRA_MUX_GMI, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_TRISTATE},
+ {TEGRA_PINGROUP_SPIC, TEGRA_MUX_GMI, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL},
+ {TEGRA_PINGROUP_SPID, TEGRA_MUX_GMI, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_TRISTATE},
+ {TEGRA_PINGROUP_SPIE, TEGRA_MUX_GMI, TEGRA_PUPD_PULL_UP, TEGRA_TRI_TRISTATE},
+ {TEGRA_PINGROUP_SPIF, TEGRA_MUX_RSVD4, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_TRISTATE},
+ {TEGRA_PINGROUP_SPIG, TEGRA_MUX_SPI2_ALT, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL},
+ {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_RSVD4, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
+ {TEGRA_PINGROUP_UAD, TEGRA_MUX_SPDIF, 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_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_SD1_CD, .enable = true },
+ { .gpio = TEGRA_GPIO_SD1_WP, .enable = true },
+ { .gpio = TEGRA_GPIO_SD1_POWER, .enable = true },
+ { .gpio = TEGRA_GPIO_SD4_CD, .enable = true },
+ { .gpio = TEGRA_GPIO_SD4_WP, .enable = true },
+ { .gpio = TEGRA_GPIO_SD4_POWER, .enable = true },
+};
+
+void paz00_pinmux_init(void)
+{
+ tegra_pinmux_config_table(paz00_pinmux, ARRAY_SIZE(paz00_pinmux));
+
+ tegra_gpio_config(gpio_table, ARRAY_SIZE(gpio_table));
+}
diff --git a/arch/arm/mach-tegra/board-paz00.c b/arch/arm/mach-tegra/board-paz00.c
new file mode 100644
index 000000000000..57e50a823eec
--- /dev/null
+++ b/arch/arm/mach-tegra/board-paz00.c
@@ -0,0 +1,128 @@
+/*
+ * arch/arm/mach-tegra/board-paz00.c
+ *
+ * Copyright (C) 2011 Marc Dietrich <marvin24@gmx.de>
+ *
+ * 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/clk.h>
+#include <linux/dma-mapping.h>
+#include <linux/pda_power.h>
+#include <linux/io.h>
+
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/time.h>
+#include <asm/setup.h>
+
+#include <mach/iomap.h>
+#include <mach/irqs.h>
+#include <mach/sdhci.h>
+
+#include "board.h"
+#include "board-paz00.h"
+#include "clock.h"
+#include "devices.h"
+#include "gpio-names.h"
+
+static struct plat_serial8250_port debug_uart_platform_data[] = {
+ {
+ .membase = IO_ADDRESS(TEGRA_UARTD_BASE),
+ .mapbase = TEGRA_UARTD_BASE,
+ .irq = INT_UARTD,
+ .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 *paz00_devices[] __initdata = {
+ &debug_uart,
+ &tegra_sdhci_device1,
+ &tegra_sdhci_device2,
+ &tegra_sdhci_device4,
+};
+
+static void __init tegra_paz00_fixup(struct machine_desc *desc,
+ struct tag *tags, char **cmdline, struct meminfo *mi)
+{
+ mi->nr_banks = 1;
+ mi->bank[0].start = PHYS_OFFSET;
+ mi->bank[0].size = 448 * SZ_1M;
+}
+
+static __initdata struct tegra_clk_init_table paz00_clk_init_table[] = {
+ /* name parent rate enabled */
+ { "uartd", "pll_p", 216000000, true },
+ { NULL, NULL, 0, 0},
+};
+
+
+static struct tegra_sdhci_platform_data sdhci_pdata1 = {
+ .cd_gpio = TEGRA_GPIO_SD1_CD,
+ .wp_gpio = TEGRA_GPIO_SD1_WP,
+ .power_gpio = TEGRA_GPIO_SD1_POWER,
+};
+
+static struct tegra_sdhci_platform_data sdhci_pdata2 = {
+ .cd_gpio = -1,
+ .wp_gpio = -1,
+ .power_gpio = -1,
+};
+
+static struct tegra_sdhci_platform_data sdhci_pdata4 = {
+ .cd_gpio = TEGRA_GPIO_SD4_CD,
+ .wp_gpio = TEGRA_GPIO_SD4_WP,
+ .power_gpio = TEGRA_GPIO_SD4_POWER,
+ .is_8bit = 1,
+};
+
+static void __init tegra_paz00_init(void)
+{
+ tegra_clk_init_from_table(paz00_clk_init_table);
+
+ paz00_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(paz00_devices, ARRAY_SIZE(paz00_devices));
+}
+
+MACHINE_START(PAZ00, "paz00")
+ .boot_params = 0x00000100,
+ .fixup = tegra_paz00_fixup,
+ .map_io = tegra_map_common_io,
+ .init_early = tegra_init_early,
+ .init_irq = tegra_init_irq,
+ .timer = &tegra_timer,
+ .init_machine = tegra_paz00_init,
+MACHINE_END
diff --git a/arch/arm/mach-tegra/board-paz00.h b/arch/arm/mach-tegra/board-paz00.h
new file mode 100644
index 000000000000..da193ca76d3b
--- /dev/null
+++ b/arch/arm/mach-tegra/board-paz00.h
@@ -0,0 +1,29 @@
+/*
+ * arch/arm/mach-tegra/board-paz00.h
+ *
+ * Copyright (C) 2010 Marc Dietrich <marvin24@gmx.de>
+ *
+ * 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_PAZ00_H
+#define _MACH_TEGRA_BOARD_PAZ00_H
+
+#define TEGRA_GPIO_SD1_CD TEGRA_GPIO_PV5
+#define TEGRA_GPIO_SD1_WP TEGRA_GPIO_PH1
+#define TEGRA_GPIO_SD1_POWER TEGRA_GPIO_PT3
+#define TEGRA_GPIO_SD4_CD TEGRA_GPIO_PH2
+#define TEGRA_GPIO_SD4_WP TEGRA_GPIO_PH3
+#define TEGRA_GPIO_SD4_POWER TEGRA_GPIO_PI6
+
+void paz00_pinmux_init(void);
+
+#endif
diff --git a/arch/arm/mach-tegra/board-seaboard-pinmux.c b/arch/arm/mach-tegra/board-seaboard-pinmux.c
new file mode 100644
index 000000000000..0bda495e9742
--- /dev/null
+++ b/arch/arm/mach-tegra/board-seaboard-pinmux.c
@@ -0,0 +1,180 @@
+/*
+ * 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_SD2_CD, .enable = true },
+ { .gpio = TEGRA_GPIO_SD2_WP, .enable = true },
+ { .gpio = TEGRA_GPIO_SD2_POWER, .enable = true },
+ { .gpio = TEGRA_GPIO_LIDSWITCH, .enable = true },
+ { .gpio = TEGRA_GPIO_POWERKEY, .enable = true },
+ { .gpio = TEGRA_GPIO_ISL29018_IRQ, .enable = true },
+};
+
+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));
+}
diff --git a/arch/arm/mach-tegra/board-seaboard.c b/arch/arm/mach-tegra/board-seaboard.c
new file mode 100644
index 000000000000..a8d7ace9f958
--- /dev/null
+++ b/arch/arm/mach-tegra/board-seaboard.c
@@ -0,0 +1,250 @@
+/*
+ * 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/i2c.h>
+#include <linux/i2c-tegra.h>
+#include <linux/delay.h>
+#include <linux/input.h>
+#include <linux/io.h>
+#include <linux/gpio.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 tegra_i2c_platform_data seaboard_i2c1_platform_data = {
+ .bus_clk_rate = 400000.
+};
+
+static struct tegra_i2c_platform_data seaboard_i2c2_platform_data = {
+ .bus_clk_rate = 400000,
+};
+
+static struct tegra_i2c_platform_data seaboard_i2c3_platform_data = {
+ .bus_clk_rate = 400000,
+};
+
+static struct tegra_i2c_platform_data seaboard_dvc_platform_data = {
+ .bus_clk_rate = 400000,
+};
+
+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_SD2_CD,
+ .wp_gpio = TEGRA_GPIO_SD2_WP,
+ .power_gpio = TEGRA_GPIO_SD2_POWER,
+};
+
+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 struct i2c_board_info __initdata isl29018_device = {
+ I2C_BOARD_INFO("isl29018", 0x44),
+ .irq = TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_ISL29018_IRQ),
+};
+
+static struct i2c_board_info __initdata adt7461_device = {
+ I2C_BOARD_INFO("adt7461", 0x4c),
+};
+
+static void __init seaboard_i2c_init(void)
+{
+ gpio_request(TEGRA_GPIO_ISL29018_IRQ, "isl29018");
+ gpio_direction_input(TEGRA_GPIO_ISL29018_IRQ);
+
+ i2c_register_board_info(0, &isl29018_device, 1);
+
+ i2c_register_board_info(4, &adt7461_device, 1);
+
+ tegra_i2c_device1.dev.platform_data = &seaboard_i2c1_platform_data;
+ tegra_i2c_device2.dev.platform_data = &seaboard_i2c2_platform_data;
+ tegra_i2c_device3.dev.platform_data = &seaboard_i2c3_platform_data;
+ tegra_i2c_device4.dev.platform_data = &seaboard_dvc_platform_data;
+
+ platform_device_register(&tegra_i2c_device1);
+ platform_device_register(&tegra_i2c_device2);
+ platform_device_register(&tegra_i2c_device3);
+ platform_device_register(&tegra_i2c_device4);
+}
+
+static void __init seaboard_common_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;
+
+ seaboard_common_init();
+
+ seaboard_i2c_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;
+
+ seaboard_common_init();
+
+ seaboard_i2c_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;
+
+ seaboard_common_init();
+
+ seaboard_i2c_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
diff --git a/arch/arm/mach-tegra/board-seaboard.h b/arch/arm/mach-tegra/board-seaboard.h
new file mode 100644
index 000000000000..d8415e1a8434
--- /dev/null
+++ b/arch/arm/mach-tegra/board-seaboard.h
@@ -0,0 +1,41 @@
+/*
+ * 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_SD2_CD TEGRA_GPIO_PI5
+#define TEGRA_GPIO_SD2_WP TEGRA_GPIO_PH1
+#define TEGRA_GPIO_SD2_POWER TEGRA_GPIO_PI6
+#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
diff --git a/arch/arm/mach-tegra/board-trimslice-pinmux.c b/arch/arm/mach-tegra/board-trimslice-pinmux.c
new file mode 100644
index 000000000000..13534fa08abf
--- /dev/null
+++ b/arch/arm/mach-tegra/board-trimslice-pinmux.c
@@ -0,0 +1,154 @@
+/*
+ * 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 <mach/gpio.h>
+
+#include "gpio-names.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},
+};
+
+static struct tegra_gpio_table gpio_table[] = {
+ { .gpio = TRIMSLICE_GPIO_SD4_CD, .enable = true }, /* mmc4 cd */
+ { .gpio = TRIMSLICE_GPIO_SD4_WP, .enable = true }, /* mmc4 wp */
+};
+
+void __init trimslice_pinmux_init(void)
+{
+ tegra_pinmux_config_table(trimslice_pinmux, ARRAY_SIZE(trimslice_pinmux));
+ tegra_gpio_config(gpio_table, ARRAY_SIZE(gpio_table));
+}
diff --git a/arch/arm/mach-tegra/board-trimslice.c b/arch/arm/mach-tegra/board-trimslice.c
new file mode 100644
index 000000000000..cda4cfd78e84
--- /dev/null
+++ b/arch/arm/mach-tegra/board-trimslice.c
@@ -0,0 +1,125 @@
+/*
+ * 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 <mach/sdhci.h>
+
+#include "board.h"
+#include "clock.h"
+#include "devices.h"
+#include "gpio-names.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 tegra_sdhci_platform_data sdhci_pdata1 = {
+ .cd_gpio = -1,
+ .wp_gpio = -1,
+ .power_gpio = -1,
+};
+
+static struct tegra_sdhci_platform_data sdhci_pdata4 = {
+ .cd_gpio = TRIMSLICE_GPIO_SD4_CD,
+ .wp_gpio = TRIMSLICE_GPIO_SD4_WP,
+ .power_gpio = -1,
+};
+
+static struct platform_device *trimslice_devices[] __initdata = {
+ &debug_uart,
+ &tegra_sdhci_device1,
+ &tegra_sdhci_device4,
+};
+
+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();
+
+ tegra_sdhci_device1.dev.platform_data = &sdhci_pdata1;
+ tegra_sdhci_device4.dev.platform_data = &sdhci_pdata4;
+
+ 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
diff --git a/arch/arm/mach-tegra/board-trimslice.h b/arch/arm/mach-tegra/board-trimslice.h
new file mode 100644
index 000000000000..e8ef6291c6f1
--- /dev/null
+++ b/arch/arm/mach-tegra/board-trimslice.h
@@ -0,0 +1,25 @@
+/*
+ * arch/arm/mach-tegra/board-trimslice.h
+ *
+ * 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.
+ *
+ */
+
+#ifndef _MACH_TEGRA_BOARD_TRIMSLICE_H
+#define _MACH_TEGRA_BOARD_TRIMSLICE_H
+
+#define TRIMSLICE_GPIO_SD4_CD TEGRA_GPIO_PP1 /* mmc4 cd */
+#define TRIMSLICE_GPIO_SD4_WP TEGRA_GPIO_PP2 /* mmc4 wp */
+
+void trimslice_pinmux_init(void);
+
+#endif
diff --git a/arch/arm/mach-tegra/board.h b/arch/arm/mach-tegra/board.h
index 0de565ca37c5..1d14df7eb7de 100644
--- a/arch/arm/mach-tegra/board.h
+++ b/arch/arm/mach-tegra/board.h
@@ -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);
diff --git a/arch/arm/mach-tegra/clock.c b/arch/arm/mach-tegra/clock.c
index 77948e0f4909..e028320ab423 100644
--- a/arch/arm/mach-tegra/clock.c
+++ b/arch/arm/mach-tegra/clock.c
@@ -18,238 +18,177 @@
#include <linux/kernel.h>
#include <linux/clk.h>
-#include <linux/list.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/debugfs.h>
-#include <linux/slab.h>
+#include <linux/sched.h>
#include <linux/seq_file.h>
-#include <linux/regulator/consumer.h>
-#include <linux/clkdev.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;
}
-int clk_reparent(struct clk *c, struct clk *parent)
+/* Must be called with c->spinlock held */
+unsigned long clk_get_rate_locked(struct clk *c)
{
- pr_debug("%s: %s\n", __func__, c->name);
- c->parent = parent;
- list_del(&c->sibling);
- list_add_tail(&c->sibling, &parent->children);
- return 0;
-}
+ unsigned long rate;
-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);
- }
+ if (c->parent)
+ rate = clk_predict_rate_from_parent(c, c->parent);
+ else
+ rate = c->rate;
+
+ return rate;
}
-void clk_init(struct clk *c)
+unsigned long clk_get_rate(struct clk *c)
{
unsigned long flags;
+ unsigned long rate;
+
+ spin_lock_irqsave(&c->spinlock, flags);
- pr_debug("%s: %s\n", __func__, c->name);
+ rate = clk_get_rate_locked(c);
- spin_lock_irqsave(&clock_lock, flags);
+ spin_unlock_irqrestore(&c->spinlock, flags);
- INIT_LIST_HEAD(&c->children);
- INIT_LIST_HEAD(&c->sibling);
+ return rate;
+}
+EXPORT_SYMBOL(clk_get_rate);
+
+int clk_reparent(struct clk *c, struct clk *parent)
+{
+ c->parent = parent;
+ return 0;
+}
+
+void clk_init(struct clk *c)
+{
+ 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);
-
+out:
+ spin_unlock_irqrestore(&c->spinlock, flags);
return ret;
}
-EXPORT_SYMBOL(clk_enable_cansleep);
+EXPORT_SYMBOL(clk_enable);
-int clk_enable(struct clk *c)
+void clk_disable(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);
-
- return ret;
-}
-EXPORT_SYMBOL(clk_enable);
+ spin_lock_irqsave(&c->spinlock, flags);
-void clk_disable_locked(struct clk *c)
-{
- pr_debug("%s: %s\n", __func__, c->name);
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 clk_set_parent(struct clk *c, struct clk *parent)
{
int ret;
+ unsigned long flags;
+ unsigned long new_rate;
+ unsigned long old_rate;
- pr_debug("%s: %s\n", __func__, c->name);
+ spin_lock_irqsave(&c->spinlock, flags);
- if (!c->ops || !c->ops->set_parent)
- return -ENOSYS;
+ if (!c->ops || !c->ops->set_parent) {
+ ret = -ENOSYS;
+ goto out;
+ }
- ret = c->ops->set_parent(c, parent);
+ 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)
- return ret;
-
- clk_recalculate_rate(c);
-
- propagate_rate(c);
-
- return 0;
-}
+ goto out;
-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);
+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 (ret)
- return ret;
-
- clk_recalculate_rate(c);
-
- propagate_rate(c);
-
- return 0;
-}
-
-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;
+ if (rate > c->max_rate)
+ rate = c->max_rate;
- spin_lock_irqsave(&clock_lock, flags);
- ret = clk_set_rate_locked(c, rate);
- spin_unlock_irqrestore(&clock_lock, flags);
+ if (c->ops && c->ops->round_rate) {
+ new_rate = c->ops->round_rate(c, rate);
- if (ret)
- goto out;
+ if (new_rate < 0)
+ return new_rate;
- ret = dvfs_set_rate(c->dvfs, rate);
+ rate = new_rate;
+ }
-out:
- mutex_unlock(&dvfs_lock);
- return ret;
+ return c->ops->set_rate(c, rate);
}
-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);
-
- if (clk_is_dvfs(c))
- BUG();
+ spin_lock_irqsave(&c->spinlock, flags);
- 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)
-{
- unsigned long flags;
- unsigned long ret;
-
- spin_lock_irqsave(&clock_lock, flags);
- pr_debug("%s: %s\n", __func__, c->name);
+/* Must be called with clocks lock and all indvidual clock locks held */
+unsigned long clk_get_rate_all_locked(struct clk *c)
+{
+ u64 rate;
+ int mul = 1;
+ int div = 1;
+ struct clk *p = c;
+
+ while (p) {
+ c = p;
+ if (c->mul != 0 && c->div != 0) {
+ mul *= c->mul;
+ div *= c->div;
+ }
+ p = c->parent;
+ }
- ret = c->rate;
+ rate = c->rate;
+ rate *= mul;
+ do_div(rate, div);
- 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;
+
+ spin_lock_irqsave(&c->spinlock, flags);
+ tegra2_sdmmc_tap_delay(c, delay);
+ spin_unlock_irqrestore(&c->spinlock, flags);
+}
- mutex_lock(&dvfs_lock);
+#ifdef CONFIG_DEBUG_FS
- list_for_each_entry_safe(c, safe, &clocks, node)
- if (c->dvfs)
- dvfs_init(c);
+static int __clk_lock_all_spinlocks(void)
+{
+ struct clk *c;
- mutex_unlock(&dvfs_lock);
+ 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;
}
-late_initcall(tegra_init_dvfs);
+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();
+}
-#ifdef CONFIG_DEBUG_FS
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;
}
diff --git a/arch/arm/mach-tegra/clock.h b/arch/arm/mach-tegra/clock.h
index 083a4cfc6cf0..688316abc64e 100644
--- a/arch/arm/mach-tegra/clock.h
+++ b/arch/arm/mach-tegra/clock.h
@@ -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 */
-#ifdef CONFIG_DEBUG_FS
- struct dentry *dent;
- struct dentry *parent_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;
- u32 reg;
- u32 reg_shift;
- unsigned int clk_num;
- enum clk_state state;
+ struct list_head node; /* node for list of all clocks */
+ struct clk_lookup lookup;
+
#ifdef CONFIG_DEBUG_FS
- bool set;
+ struct dentry *dent;
#endif
+ 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;
- /* 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;
-
- /* DIV */
- u32 div;
- u32 mul;
-
- /* MUX */
const struct clk_mux_sel *inputs;
- u32 sel;
- u32 reg_mask;
-
- /* Virtual cpu clock */
- struct clk *main;
- struct clk *backup;
+ u32 reg;
+ u32 reg_shift;
- struct dvfs *dvfs;
+ struct list_head shared_bus_list;
+
+ 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;
+
+ 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
diff --git a/arch/arm/mach-tegra/common.c b/arch/arm/mach-tegra/common.c
index 7c91e2b9d643..d5e3f89b05af 100644
--- a/arch/arm/mach-tegra/common.c
+++ b/arch/arm/mach-tegra/common.c
@@ -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
}
diff --git a/arch/arm/mach-tegra/cpu-tegra.c b/arch/arm/mach-tegra/cpu-tegra.c
index fea5719c7072..0e1016a827ac 100644
--- a/arch/arm/mach-tegra/cpu-tegra.c
+++ b/arch/arm/mach-tegra/cpu-tegra.c
@@ -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;
}
diff --git a/arch/arm/mach-tegra/devices.c b/arch/arm/mach-tegra/devices.c
new file mode 100644
index 000000000000..1528f9daef1f
--- /dev/null
+++ b/arch/arm/mach-tegra/devices.c
@@ -0,0 +1,575 @@
+/*
+ * 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),
+ },
+};
+
+static struct resource i2s_resource1[] = {
+ [0] = {
+ .start = INT_I2S1,
+ .end = INT_I2S1,
+ .flags = IORESOURCE_IRQ
+ },
+ [1] = {
+ .start = TEGRA_DMA_REQ_SEL_I2S_1,
+ .end = TEGRA_DMA_REQ_SEL_I2S_1,
+ .flags = IORESOURCE_DMA
+ },
+ [2] = {
+ .start = TEGRA_I2S1_BASE,
+ .end = TEGRA_I2S1_BASE + TEGRA_I2S1_SIZE - 1,
+ .flags = IORESOURCE_MEM
+ }
+};
+
+static struct resource i2s_resource2[] = {
+ [0] = {
+ .start = INT_I2S2,
+ .end = INT_I2S2,
+ .flags = IORESOURCE_IRQ
+ },
+ [1] = {
+ .start = TEGRA_DMA_REQ_SEL_I2S2_1,
+ .end = TEGRA_DMA_REQ_SEL_I2S2_1,
+ .flags = IORESOURCE_DMA
+ },
+ [2] = {
+ .start = TEGRA_I2S2_BASE,
+ .end = TEGRA_I2S2_BASE + TEGRA_I2S2_SIZE - 1,
+ .flags = IORESOURCE_MEM
+ }
+};
+
+struct platform_device tegra_i2s_device1 = {
+ .name = "tegra-i2s",
+ .id = 0,
+ .resource = i2s_resource1,
+ .num_resources = ARRAY_SIZE(i2s_resource1),
+};
+
+struct platform_device tegra_i2s_device2 = {
+ .name = "tegra-i2s",
+ .id = 1,
+ .resource = i2s_resource2,
+ .num_resources = ARRAY_SIZE(i2s_resource2),
+};
+
+static struct resource tegra_das_resources[] = {
+ [0] = {
+ .start = TEGRA_APB_MISC_DAS_BASE,
+ .end = TEGRA_APB_MISC_DAS_BASE + TEGRA_APB_MISC_DAS_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+struct platform_device tegra_das_device = {
+ .name = "tegra-das",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(tegra_das_resources),
+ .resource = tegra_das_resources,
+};
+
+struct platform_device tegra_pcm_device = {
+ .name = "tegra-pcm-audio",
+ .id = -1,
+};
diff --git a/arch/arm/mach-tegra/devices.h b/arch/arm/mach-tegra/devices.h
new file mode 100644
index 000000000000..4a7dc0a097d6
--- /dev/null
+++ b/arch/arm/mach-tegra/devices.h
@@ -0,0 +1,50 @@
+/*
+ * 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;
+extern struct platform_device tegra_i2s_device1;
+extern struct platform_device tegra_i2s_device2;
+extern struct platform_device tegra_das_device;
+extern struct platform_device tegra_pcm_device;
+
+#endif
diff --git a/arch/arm/mach-tegra/dma.c b/arch/arm/mach-tegra/dma.c
index edda6ec5e925..f4ef5eb317bd 100644
--- a/arch/arm/mach-tegra/dma.c
+++ b/arch/arm/mach-tegra/dma.c
@@ -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);
@@ -225,22 +223,19 @@ int tegra_dma_dequeue_req(struct tegra_dma_channel *ch,
* - Change the source selector to invalid to stop the DMA from
* FIFO to memory.
* - Read the status register to know the number of pending
- * bytes to be transfered.
+ * bytes to be transferred.
* - 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;
@@ -249,7 +244,7 @@ int tegra_dma_dequeue_req(struct tegra_dma_channel *ch,
if (status & STA_BUSY)
req->bytes_transferred -= to_transfer;
- /* In continous transfer mode, DMA only tracks the count of the
+ /* In continuous transfer mode, DMA only tracks the count of the
* half DMA buffer. So, if the DMA already finished half the DMA
* then add the half buffer to the completed count.
*
@@ -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;
+
+ csr = CSR_IE_EOC | CSR_FLOW;
+ ahb_seq = AHB_SEQ_INTR_ENB | AHB_SEQ_BURST_1;
+ apb_seq = 0;
- 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 |= 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;
-
- ch->csr |= CSR_IE_EOC;
+ apb_seq |= index << APB_SEQ_BUS_WIDTH_SHIFT;
- /* 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);
+ 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);
- 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];
diff --git a/arch/arm/mach-tegra/gpio.c b/arch/arm/mach-tegra/gpio.c
index ad8048801513..919d63837736 100644
--- a/arch/arm/mach-tegra/gpio.c
+++ b/arch/arm/mach-tegra/gpio.c
@@ -24,7 +24,10 @@
#include <linux/io.h>
#include <linux/gpio.h>
+#include <asm/mach/irq.h>
+
#include <mach/iomap.h>
+#include <mach/suspend.h>
#define GPIO_BANK(x) ((x) >> 5)
#define GPIO_PORT(x) (((x) >> 3) & 0x3)
@@ -207,9 +210,9 @@ static int tegra_gpio_irq_set_type(struct irq_data *d, unsigned int type)
spin_unlock_irqrestore(&bank->lvl_lock[port], flags);
if (type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH))
- __set_irq_handler_unlocked(d->irq, handle_level_irq);
+ __irq_set_handler_locked(d->irq, handle_level_irq);
else if (type & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING))
- __set_irq_handler_unlocked(d->irq, handle_edge_irq);
+ __irq_set_handler_locked(d->irq, handle_edge_irq);
return 0;
}
@@ -220,10 +223,11 @@ static void tegra_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
int port;
int pin;
int unmasked = 0;
+ struct irq_chip *chip = irq_desc_get_chip(desc);
- desc->irq_data.chip->irq_ack(&desc->irq_data);
+ chained_irq_enter(chip, desc);
- bank = get_irq_data(irq);
+ bank = irq_get_handler_data(irq);
for (port = 0; port < 4; port++) {
int gpio = tegra_gpio_compose(bank->bank, port, 0);
@@ -240,7 +244,7 @@ static void tegra_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
*/
if (lvl & (0x100 << pin)) {
unmasked = 1;
- desc->irq_data.chip->irq_unmask(&desc->irq_data);
+ chained_irq_exit(chip, desc);
}
generic_handle_irq(gpio_to_irq(gpio + pin));
@@ -248,7 +252,7 @@ static void tegra_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
}
if (!unmasked)
- desc->irq_data.chip->irq_unmask(&desc->irq_data);
+ chained_irq_exit(chip, desc);
}
@@ -256,7 +260,8 @@ static void tegra_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
void tegra_gpio_resume(void)
{
unsigned long flags;
- int b, p, i;
+ int b;
+ int p;
local_irq_save(flags);
@@ -274,31 +279,13 @@ void tegra_gpio_resume(void)
}
local_irq_restore(flags);
-
- for (i = INT_GPIO_BASE; i < (INT_GPIO_BASE + TEGRA_NR_GPIOS); i++) {
- struct irq_desc *desc = irq_to_desc(i);
- if (!desc || (desc->status & IRQ_WAKEUP))
- continue;
- enable_irq(i);
- }
}
void tegra_gpio_suspend(void)
{
unsigned long flags;
- int b, p, i;
-
- for (i = INT_GPIO_BASE; i < (INT_GPIO_BASE + TEGRA_NR_GPIOS); i++) {
- struct irq_desc *desc = irq_to_desc(i);
- if (!desc)
- continue;
- if (desc->status & IRQ_WAKEUP) {
- int gpio = i - INT_GPIO_BASE;
- pr_debug("gpio %d.%d is wakeup\n", gpio/8, gpio&7);
- continue;
- }
- disable_irq(i);
- }
+ int b;
+ int p;
local_irq_save(flags);
for (b = 0; b < ARRAY_SIZE(tegra_gpio_banks); b++) {
@@ -319,7 +306,7 @@ void tegra_gpio_suspend(void)
static int tegra_gpio_wake_enable(struct irq_data *d, unsigned int enable)
{
struct tegra_gpio_bank *bank = irq_data_get_irq_chip_data(d);
- return set_irq_wake(bank->irq, enable);
+ return irq_set_irq_wake(bank->irq, enable);
}
#endif
@@ -358,18 +345,18 @@ static int __init tegra_gpio_init(void)
for (i = INT_GPIO_BASE; i < (INT_GPIO_BASE + TEGRA_NR_GPIOS); i++) {
bank = &tegra_gpio_banks[GPIO_BANK(irq_to_gpio(i))];
- lockdep_set_class(&irq_desc[i].lock, &gpio_lock_class);
- set_irq_chip_data(i, bank);
- set_irq_chip(i, &tegra_gpio_irq_chip);
- set_irq_handler(i, handle_simple_irq);
+ irq_set_lockdep_class(i, &gpio_lock_class);
+ irq_set_chip_data(i, bank);
+ irq_set_chip_and_handler(i, &tegra_gpio_irq_chip,
+ handle_simple_irq);
set_irq_flags(i, IRQF_VALID);
}
for (i = 0; i < ARRAY_SIZE(tegra_gpio_banks); i++) {
bank = &tegra_gpio_banks[i];
- set_irq_chained_handler(bank->irq, tegra_gpio_irq_handler);
- set_irq_data(bank->irq, bank);
+ irq_set_chained_handler(bank->irq, tegra_gpio_irq_handler);
+ irq_set_handler_data(bank->irq, bank);
for (j = 0; j < 4; j++)
spin_lock_init(&bank->lvl_lock[j]);
@@ -380,6 +367,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>
diff --git a/arch/arm/mach-tegra/include/mach/barriers.h b/arch/arm/mach-tegra/include/mach/barriers.h
index cc115174899b..425b42e91ef6 100644
--- a/arch/arm/mach-tegra/include/mach/barriers.h
+++ b/arch/arm/mach-tegra/include/mach/barriers.h
@@ -23,7 +23,7 @@
#include <asm/outercache.h>
-#define rmb() dmb()
+#define rmb() dsb()
#define wmb() do { dsb(); outer_sync(); } while (0)
#define mb() wmb()
diff --git a/arch/arm/mach-tegra/include/mach/clk.h b/arch/arm/mach-tegra/include/mach/clk.h
index a217f68ba57c..c8baf8f80d23 100644
--- a/arch/arm/mach-tegra/include/mach/clk.h
+++ b/arch/arm/mach-tegra/include/mach/clk.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
diff --git a/arch/arm/mach-tegra/include/mach/debug-macro.S b/arch/arm/mach-tegra/include/mach/debug-macro.S
index a0e7c12868bd..e0ebe65c1657 100644
--- a/arch/arm/mach-tegra/include/mach/debug-macro.S
+++ b/arch/arm/mach-tegra/include/mach/debug-macro.S
@@ -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
diff --git a/arch/arm/mach-tegra/include/mach/dma.h b/arch/arm/mach-tegra/include/mach/dma.h
index 39011bd9a925..d0132e8031a1 100644
--- a/arch/arm/mach-tegra/include/mach/dma.h
+++ b/arch/arm/mach-tegra/include/mach/dma.h
@@ -92,11 +92,11 @@ struct tegra_dma_req {
/* This is a called from the DMA ISR context when the DMA is still in
* progress and is actively filling same buffer.
*
- * In case of continous mode receive, this threshold is 1/2 the buffer
+ * In case of continuous mode receive, this threshold is 1/2 the buffer
* size. In other cases, this will not even be called as there is no
* hardware support for it.
*
- * In the case of continous mode receive, if there is next req already
+ * In the case of continuous mode receive, if there is next req already
* queued, DMA programs the HW to use that req when this req is
* completed. If there is no "next req" queued, then DMA ISR doesn't do
* anything before calling this callback.
diff --git a/arch/arm/mach-tegra/include/mach/gpio.h b/arch/arm/mach-tegra/include/mach/gpio.h
index e31f486d69a2..196f114dc241 100644
--- a/arch/arm/mach-tegra/include/mach/gpio.h
+++ b/arch/arm/mach-tegra/include/mach/gpio.h
@@ -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);
diff --git a/arch/arm/mach-tegra/include/mach/iomap.h b/arch/arm/mach-tegra/include/mach/iomap.h
index 44a4f4bcf91f..19dec3ac0854 100644
--- a/arch/arm/mach-tegra/include/mach/iomap.h
+++ b/arch/arm/mach-tegra/include/mach/iomap.h
@@ -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
@@ -101,6 +122,9 @@
#define TEGRA_APB_MISC_BASE 0x70000000
#define TEGRA_APB_MISC_SIZE SZ_4K
+#define TEGRA_APB_MISC_DAS_BASE 0x70000c00
+#define TEGRA_APB_MISC_DAS_SIZE SZ_128
+
#define TEGRA_AC97_BASE 0x70002000
#define TEGRA_AC97_SIZE SZ_512
@@ -140,6 +164,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 +257,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
diff --git a/arch/arm/mach-tegra/include/mach/irqs.h b/arch/arm/mach-tegra/include/mach/irqs.h
index 71bbf3422953..73265af4dda3 100644
--- a/arch/arm/mach-tegra/include/mach/irqs.h
+++ b/arch/arm/mach-tegra/include/mach/irqs.h
@@ -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
diff --git a/arch/arm/mach-tegra/include/mach/kbc.h b/arch/arm/mach-tegra/include/mach/kbc.h
index 04c779832c78..4f3572a1c684 100644
--- a/arch/arm/mach-tegra/include/mach/kbc.h
+++ b/arch/arm/mach-tegra/include/mach/kbc.h
@@ -50,13 +50,11 @@ struct tegra_kbc_platform_data {
unsigned int debounce_cnt;
unsigned int repeat_cnt;
- unsigned int wake_cnt; /* 0:wake on any key >1:wake on wake_cfg */
- const struct tegra_kbc_wake_key *wake_cfg;
-
struct tegra_kbc_pin_cfg pin_cfg[KBC_MAX_GPIO];
const struct matrix_keymap_data *keymap_data;
bool wakeup;
bool use_fn_map;
+ bool use_ghost_filter;
};
#endif
diff --git a/arch/arm/mach-tegra/include/mach/legacy_irq.h b/arch/arm/mach-tegra/include/mach/legacy_irq.h
deleted file mode 100644
index db1eb3dd04c8..000000000000
--- a/arch/arm/mach-tegra/include/mach/legacy_irq.h
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * arch/arm/mach-tegra/include/mach/legacy_irq.h
- *
- * Copyright (C) 2010 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.
- *
- */
-
-#ifndef _ARCH_ARM_MACH_TEGRA_LEGARY_IRQ_H
-#define _ARCH_ARM_MACH_TEGRA_LEGARY_IRQ_H
-
-void tegra_legacy_mask_irq(unsigned int irq);
-void tegra_legacy_unmask_irq(unsigned int irq);
-void tegra_legacy_select_fiq(unsigned int irq, bool fiq);
-void tegra_legacy_force_irq_set(unsigned int irq);
-void tegra_legacy_force_irq_clr(unsigned int irq);
-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);
-
-#endif
diff --git a/arch/arm/mach-tegra/include/mach/memory.h b/arch/arm/mach-tegra/include/mach/memory.h
index 6151bab62af2..537db3aa81a7 100644
--- a/arch/arm/mach-tegra/include/mach/memory.h
+++ b/arch/arm/mach-tegra/include/mach/memory.h
@@ -22,7 +22,7 @@
#define __MACH_TEGRA_MEMORY_H
/* physical offset of RAM */
-#define PHYS_OFFSET UL(0)
+#define PLAT_PHYS_OFFSET UL(0)
#endif
diff --git a/arch/arm/mach-tegra/include/mach/pinmux-t2.h b/arch/arm/mach-tegra/include/mach/pinmux-t2.h
index e5b9d740f973..4c2626347263 100644
--- a/arch/arm/mach-tegra/include/mach/pinmux-t2.h
+++ b/arch/arm/mach-tegra/include/mach/pinmux-t2.h
@@ -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,
};
diff --git a/arch/arm/mach-tegra/include/mach/powergate.h b/arch/arm/mach-tegra/include/mach/powergate.h
new file mode 100644
index 000000000000..401d1b725291
--- /dev/null
+++ b/arch/arm/mach-tegra/include/mach/powergate.h
@@ -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_ */
diff --git a/arch/arm/mach-tegra/include/mach/sdhci.h b/arch/arm/mach-tegra/include/mach/sdhci.h
index 3ad086e859c3..4231bc7b8652 100644
--- a/arch/arm/mach-tegra/include/mach/sdhci.h
+++ b/arch/arm/mach-tegra/include/mach/sdhci.h
@@ -24,6 +24,7 @@ struct tegra_sdhci_platform_data {
int wp_gpio;
int power_gpio;
int is_8bit;
+ int pm_flags;
};
#endif
diff --git a/arch/arm/mach-tegra/include/mach/smp.h b/arch/arm/mach-tegra/include/mach/smp.h
deleted file mode 100644
index c8221b38ee7c..000000000000
--- a/arch/arm/mach-tegra/include/mach/smp.h
+++ /dev/null
@@ -1,14 +0,0 @@
-#ifndef ASMARM_ARCH_SMP_H
-#define ASMARM_ARCH_SMP_H
-
-#include <asm/hardware/gic.h>
-
-/*
- * We use IRQ1 as the IPI
- */
-static inline void smp_cross_call(const struct cpumask *mask, int ipi)
-{
- gic_raise_softirq(mask, ipi);
-}
-
-#endif
diff --git a/arch/arm/mach-tegra/include/mach/suspend.h b/arch/arm/mach-tegra/include/mach/suspend.h
new file mode 100644
index 000000000000..5af8715d2e1e
--- /dev/null
+++ b/arch/arm/mach-tegra/include/mach/suspend.h
@@ -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_ */
diff --git a/arch/arm/mach-tegra/include/mach/system.h b/arch/arm/mach-tegra/include/mach/system.h
index 84d5d46113f7..d0183d876c3b 100644
--- a/arch/arm/mach-tegra/include/mach/system.h
+++ b/arch/arm/mach-tegra/include/mach/system.h
@@ -24,16 +24,10 @@
#include <mach/hardware.h>
#include <mach/iomap.h>
-static inline void arch_idle(void)
-{
-}
+extern void (*arch_reset)(char mode, const char *cmd);
-static inline void arch_reset(char mode, const char *cmd)
+static inline void arch_idle(void)
{
- void __iomem *reset = IO_ADDRESS(TEGRA_CLK_RESET_BASE + 0x04);
- u32 reg = readl(reset);
- reg |= 0x04;
- writel(reg, reset);
}
#endif
diff --git a/arch/arm/mach-tegra/tegra2_dvfs.h b/arch/arm/mach-tegra/include/mach/tegra_wm8903_pdata.h
index f8c1adba96a6..9d293344a7ff 100644
--- a/arch/arm/mach-tegra/tegra2_dvfs.h
+++ b/arch/arm/mach-tegra/include/mach/tegra_wm8903_pdata.h
@@ -1,10 +1,7 @@
/*
- * arch/arm/mach-tegra/tegra2_dvfs.h
+ * arch/arm/mach-tegra/include/mach/tegra_wm8903_pdata.h
*
- * Copyright (C) 2010 Google, Inc.
- *
- * Author:
- * Colin Cross <ccross@google.com>
+ * 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
@@ -17,4 +14,10 @@
*
*/
-extern struct dvfs tegra_dvfs_virtual_cpu_dvfs;
+struct tegra_wm8903_platform_data {
+ int gpio_spkr_en;
+ int gpio_hp_det;
+ int gpio_hp_mute;
+ int gpio_int_mic_en;
+ int gpio_ext_mic_en;
+};
diff --git a/arch/arm/mach-tegra/include/mach/uncompress.h b/arch/arm/mach-tegra/include/mach/uncompress.h
index 6c4dd815abd7..4e8323770c79 100644
--- a/arch/arm/mach-tegra/include/mach/uncompress.h
+++ b/arch/arm/mach-tegra/include/mach/uncompress.h
@@ -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)
diff --git a/arch/arm/mach-tegra/include/mach/usb_phy.h b/arch/arm/mach-tegra/include/mach/usb_phy.h
new file mode 100644
index 000000000000..d4b8f9e298a8
--- /dev/null
+++ b/arch/arm/mach-tegra/include/mach/usb_phy.h
@@ -0,0 +1,86 @@
+/*
+ * arch/arm/mach-tegra/include/mach/usb_phy.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_USB_PHY_H
+#define __MACH_USB_PHY_H
+
+#include <linux/clk.h>
+#include <linux/usb/otg.h>
+
+struct tegra_utmip_config {
+ u8 hssync_start_delay;
+ u8 elastic_limit;
+ u8 idle_wait_delay;
+ u8 term_range_adj;
+ u8 xcvr_setup;
+ u8 xcvr_lsfslew;
+ u8 xcvr_lsrslew;
+};
+
+struct tegra_ulpi_config {
+ int reset_gpio;
+ const char *clk;
+};
+
+enum tegra_usb_phy_port_speed {
+ TEGRA_USB_PHY_PORT_SPEED_FULL = 0,
+ TEGRA_USB_PHY_PORT_SPEED_LOW,
+ TEGRA_USB_PHY_PORT_SPEED_HIGH,
+};
+
+enum tegra_usb_phy_mode {
+ TEGRA_USB_PHY_MODE_DEVICE,
+ TEGRA_USB_PHY_MODE_HOST,
+};
+
+struct tegra_xtal_freq;
+
+struct tegra_usb_phy {
+ int instance;
+ const struct tegra_xtal_freq *freq;
+ void __iomem *regs;
+ void __iomem *pad_regs;
+ struct clk *clk;
+ struct clk *pll_u;
+ struct clk *pad_clk;
+ enum tegra_usb_phy_mode mode;
+ void *config;
+ struct otg_transceiver *ulpi;
+};
+
+struct tegra_usb_phy *tegra_usb_phy_open(int instance, void __iomem *regs,
+ void *config, enum tegra_usb_phy_mode phy_mode);
+
+int tegra_usb_phy_power_on(struct tegra_usb_phy *phy);
+
+void tegra_usb_phy_clk_disable(struct tegra_usb_phy *phy);
+
+void tegra_usb_phy_clk_enable(struct tegra_usb_phy *phy);
+
+void tegra_usb_phy_power_off(struct tegra_usb_phy *phy);
+
+void tegra_usb_phy_preresume(struct tegra_usb_phy *phy);
+
+void tegra_usb_phy_postresume(struct tegra_usb_phy *phy);
+
+void tegra_ehci_phy_restore_start(struct tegra_usb_phy *phy,
+ enum tegra_usb_phy_port_speed port_speed);
+
+void tegra_ehci_phy_restore_end(struct tegra_usb_phy *phy);
+
+void tegra_usb_phy_close(struct tegra_usb_phy *phy);
+
+#endif /* __MACH_USB_PHY_H */
diff --git a/arch/arm/mach-tegra/irq.c b/arch/arm/mach-tegra/irq.c
index 17c74d21077c..4956c3cea731 100644
--- a/arch/arm/mach-tegra/irq.c
+++ b/arch/arm/mach-tegra/irq.c
@@ -1,8 +1,8 @@
/*
- * Copyright (C) 2010 Google, Inc.
+ * Copyright (C) 2011 Google, Inc.
*
* Author:
- * Colin Cross <ccross@google.com>
+ * Colin Cross <ccross@android.com>
*
* Copyright (C) 2010, NVIDIA Corporation
*
@@ -18,7 +18,6 @@
*/
#include <linux/kernel.h>
-#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/io.h>
@@ -33,139 +32,103 @@
#define INT_SYS_SZ (INT_SEC_BASE - INT_PRI_BASE)
#define PPI_NR ((INT_SYS_NR+INT_SYS_SZ-1)/INT_SYS_SZ)
-#define APBDMA_IRQ_STA_CPU 0x14
-#define APBDMA_IRQ_MASK_SET 0x20
-#define APBDMA_IRQ_MASK_CLR 0x24
+#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_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 void (*tegra_gic_mask_irq)(struct irq_data *d);
-static void (*tegra_gic_unmask_irq)(struct irq_data *d);
+#define NUM_ICTLRS 4
+#define FIRST_LEGACY_IRQ 32
-#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)
+static void __iomem *ictlr_reg_base[] = {
+ IO_ADDRESS(TEGRA_PRIMARY_ICTLR_BASE),
+ IO_ADDRESS(TEGRA_SECONDARY_ICTLR_BASE),
+ IO_ADDRESS(TEGRA_TERTIARY_ICTLR_BASE),
+ IO_ADDRESS(TEGRA_QUATERNARY_ICTLR_BASE),
+};
-static void tegra_mask(struct irq_data *d)
+static inline void tegra_irq_write_mask(unsigned int irq, unsigned long reg)
{
- 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);
+ void __iomem *base;
+ u32 mask;
+
+ BUG_ON(irq < FIRST_LEGACY_IRQ ||
+ irq >= FIRST_LEGACY_IRQ + NUM_ICTLRS * 32);
+
+ base = ictlr_reg_base[(irq - FIRST_LEGACY_IRQ) / 32];
+ mask = BIT((irq - FIRST_LEGACY_IRQ) % 32);
+
+ __raw_writel(mask, base + reg);
}
-static void tegra_unmask(struct irq_data *d)
+static void tegra_mask(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);
-}
+ if (d->irq < FIRST_LEGACY_IRQ)
+ return;
-#ifdef CONFIG_PM
+ tegra_irq_write_mask(d->irq, ICTLR_CPU_IER_CLR);
+}
-static int tegra_set_wake(struct irq_data *d, unsigned int on)
+static void tegra_unmask(struct irq_data *d)
{
- return 0;
+ if (d->irq < FIRST_LEGACY_IRQ)
+ return;
+
+ tegra_irq_write_mask(d->irq, ICTLR_CPU_IER_SET);
}
-#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
-};
-void __init tegra_init_irq(void)
+static void tegra_ack(struct irq_data *d)
{
- struct irq_chip *gic;
- unsigned int i;
+ if (d->irq < FIRST_LEGACY_IRQ)
+ return;
- 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_irq_write_mask(d->irq, ICTLR_CPU_IEP_FIR_CLR);
+}
- gic_init(0, 29, IO_ADDRESS(TEGRA_ARM_INT_DIST_BASE),
- IO_ADDRESS(TEGRA_ARM_PERIF_BASE + 0x100));
+static void tegra_eoi(struct irq_data *d)
+{
+ if (d->irq < FIRST_LEGACY_IRQ)
+ return;
- 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;
-#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);
- }
+ tegra_irq_write_mask(d->irq, ICTLR_CPU_IEP_FIR_CLR);
}
-#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)
+static int tegra_retrigger(struct irq_data *d)
{
- unsigned long flags;
- int i;
+ if (d->irq < FIRST_LEGACY_IRQ)
+ return 0;
- 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);
- }
+ tegra_irq_write_mask(d->irq, ICTLR_CPU_IEP_FIR_SET);
- 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);
+ return 1;
}
-void tegra_irq_resume(void)
+void __init tegra_init_irq(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);
+ 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);
}
- 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);
- }
+ gic_arch_extn.irq_ack = tegra_ack;
+ gic_arch_extn.irq_eoi = tegra_eoi;
+ gic_arch_extn.irq_mask = tegra_mask;
+ gic_arch_extn.irq_unmask = tegra_unmask;
+ gic_arch_extn.irq_retrigger = tegra_retrigger;
+
+ gic_init(0, 29, IO_ADDRESS(TEGRA_ARM_INT_DIST_BASE),
+ IO_ADDRESS(TEGRA_ARM_PERIF_BASE + 0x100));
}
-#endif
diff --git a/arch/arm/mach-tegra/legacy_irq.c b/arch/arm/mach-tegra/legacy_irq.c
deleted file mode 100644
index 7cc8601c19ff..000000000000
--- a/arch/arm/mach-tegra/legacy_irq.c
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * arch/arm/mach-tegra/legacy_irq.c
- *
- * Copyright (C) 2010 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/io.h>
-#include <linux/kernel.h>
-#include <mach/iomap.h>
-#include <mach/legacy_irq.h>
-
-#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
-
-static void __iomem *ictlr_reg_base[] = {
- IO_ADDRESS(TEGRA_PRIMARY_ICTLR_BASE),
- IO_ADDRESS(TEGRA_SECONDARY_ICTLR_BASE),
- IO_ADDRESS(TEGRA_TERTIARY_ICTLR_BASE),
- IO_ADDRESS(TEGRA_QUATERNARY_ICTLR_BASE),
-};
-
-/* 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. */
-void tegra_legacy_unmask_irq(unsigned int irq)
-{
- void __iomem *base;
- pr_debug("%s: %d\n", __func__, irq);
-
- irq -= 32;
- base = ictlr_reg_base[irq>>5];
- writel(1 << (irq & 31), base + ICTLR_CPU_IER_SET);
-}
-
-void tegra_legacy_mask_irq(unsigned int irq)
-{
- void __iomem *base;
- pr_debug("%s: %d\n", __func__, irq);
-
- irq -= 32;
- base = ictlr_reg_base[irq>>5];
- writel(1 << (irq & 31), base + ICTLR_CPU_IER_CLR);
-}
-
-void tegra_legacy_force_irq_set(unsigned int irq)
-{
- void __iomem *base;
- pr_debug("%s: %d\n", __func__, irq);
-
- irq -= 32;
- base = ictlr_reg_base[irq>>5];
- writel(1 << (irq & 31), base + ICTLR_CPU_IEP_FIR_SET);
-}
-
-void tegra_legacy_force_irq_clr(unsigned int irq)
-{
- void __iomem *base;
- pr_debug("%s: %d\n", __func__, irq);
-
- irq -= 32;
- base = ictlr_reg_base[irq>>5];
- writel(1 << (irq & 31), base + ICTLR_CPU_IEP_FIR_CLR);
-}
-
-int tegra_legacy_force_irq_status(unsigned int irq)
-{
- void __iomem *base;
- pr_debug("%s: %d\n", __func__, irq);
-
- irq -= 32;
- base = ictlr_reg_base[irq>>5];
- return !!(readl(base + ICTLR_CPU_IEP_FIR) & (1 << (irq & 31)));
-}
-
-void tegra_legacy_select_fiq(unsigned int irq, bool fiq)
-{
- void __iomem *base;
- pr_debug("%s: %d\n", __func__, irq);
-
- irq -= 32;
- base = ictlr_reg_base[irq>>5];
- writel(fiq << (irq & 31), base + ICTLR_CPU_IEP_CLASS);
-}
-
-unsigned long tegra_legacy_vfiq(int nr)
-{
- void __iomem *base;
- base = ictlr_reg_base[nr];
- return readl(base + ICTLR_CPU_IEP_VFIQ);
-}
-
-unsigned long tegra_legacy_class(int nr)
-{
- void __iomem *base;
- base = ictlr_reg_base[nr];
- return readl(base + ICTLR_CPU_IEP_CLASS);
-}
diff --git a/arch/arm/mach-tegra/localtimer.c b/arch/arm/mach-tegra/localtimer.c
index f81ca7cbbc1f..e91d681d45a2 100644
--- a/arch/arm/mach-tegra/localtimer.c
+++ b/arch/arm/mach-tegra/localtimer.c
@@ -18,8 +18,9 @@
/*
* Setup the local clock events for a CPU.
*/
-void __cpuinit local_timer_setup(struct clock_event_device *evt)
+int __cpuinit local_timer_setup(struct clock_event_device *evt)
{
evt->irq = IRQ_LOCALTIMER;
twd_timer_setup(evt);
+ return 0;
}
diff --git a/arch/arm/mach-tegra/pcie.c b/arch/arm/mach-tegra/pcie.c
index 53f5fa37014a..2941212b853c 100644
--- a/arch/arm/mach-tegra/pcie.c
+++ b/arch/arm/mach-tegra/pcie.c
@@ -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,24 +683,41 @@ static void tegra_pcie_xclk_clamp(bool clamp)
pmc_writel(reg, PMC_SCRATCH42);
}
-static int tegra_pcie_power_on(void)
+static void tegra_pcie_power_off(void)
{
- tegra_pcie_xclk_clamp(true);
tegra_periph_reset_assert(tegra_pcie.pcie_xclk);
- tegra_pcie_xclk_clamp(false);
+ tegra_periph_reset_assert(tegra_pcie.afi_clk);
+ tegra_periph_reset_assert(tegra_pcie.pex_clk);
- clk_enable(tegra_pcie.afi_clk);
- clk_enable(tegra_pcie.pex_clk);
- return clk_enable(tegra_pcie.pll_e);
+ tegra_powergate_power_off(TEGRA_POWERGATE_PCIE);
+ tegra_pcie_xclk_clamp(true);
}
-static void tegra_pcie_power_off(void)
+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);
- tegra_periph_reset_assert(tegra_pcie.pex_clk);
- tegra_pcie_xclk_clamp(true);
+ 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)
@@ -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;
diff --git a/arch/arm/mach-tegra/pinmux-t2-tables.c b/arch/arm/mach-tegra/pinmux-t2-tables.c
index a6ea34e782dc..a475367befa3 100644
--- a/arch/arm/mach-tegra/pinmux-t2-tables.c
+++ b/arch/arm/mach-tegra/pinmux-t2-tables.c
@@ -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
diff --git a/arch/arm/mach-tegra/platsmp.c b/arch/arm/mach-tegra/platsmp.c
index ec1f68924edf..b8ae3c978dee 100644
--- a/arch/arm/mach-tegra/platsmp.c
+++ b/arch/arm/mach-tegra/platsmp.c
@@ -20,6 +20,7 @@
#include <linux/io.h>
#include <asm/cacheflush.h>
+#include <asm/hardware/gic.h>
#include <mach/hardware.h>
#include <asm/mach-types.h>
#include <asm/smp_scu.h>
@@ -122,6 +123,8 @@ void __init smp_init_cpus(void)
for (i = 0; i < ncores; i++)
cpu_set(i, cpu_possible_map);
+
+ set_smp_cross_call(gic_raise_softirq);
}
void __init platform_smp_prepare_cpus(unsigned int max_cpus)
diff --git a/arch/arm/mach-tegra/powergate.c b/arch/arm/mach-tegra/powergate.c
new file mode 100644
index 000000000000..3cee9aa1f2c8
--- /dev/null
+++ b/arch/arm/mach-tegra/powergate.c
@@ -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
diff --git a/arch/arm/mach-tegra/tegra2_clocks.c b/arch/arm/mach-tegra/tegra2_clocks.c
index f0dae6d8ba52..bb618075fab6 100644
--- a/arch/arm/mach-tegra/tegra2_clocks.c
+++ b/arch/arm/mach-tegra/tegra2_clocks.c
@@ -23,14 +23,15 @@
#include <linux/spinlock.h>
#include <linux/delay.h>
#include <linux/io.h>
-#include <linux/hrtimer.h>
#include <linux/clkdev.h>
+#include <linux/clk.h>
#include <mach/iomap.h>
+#include <mach/suspend.h>
#include "clock.h"
#include "fuse.h"
-#include "tegra2_dvfs.h"
+#include "tegra2_emc.h"
#define RST_DEVICES 0x004
#define RST_DEVICES_SET 0x300
@@ -51,7 +52,7 @@
#define OSC_CTRL_OSC_FREQ_19_2MHZ (1<<30)
#define OSC_CTRL_OSC_FREQ_12MHZ (2<<30)
#define OSC_CTRL_OSC_FREQ_26MHZ (3<<30)
-#define OSC_CTRL_MASK 0x3f2
+#define OSC_CTRL_MASK (0x3f2 | OSC_CTRL_OSC_FREQ_MASK)
#define OSC_FREQ_DET 0x58
#define OSC_FREQ_DET_TRIG (1<<31)
@@ -73,12 +74,15 @@
#define PERIPH_CLK_SOURCE_DIVU16_MASK 0xFFFF
#define PERIPH_CLK_SOURCE_DIV_SHIFT 0
+#define SDMMC_CLK_INT_FB_SEL (1 << 23)
+#define SDMMC_CLK_INT_FB_DLY_SHIFT 16
+#define SDMMC_CLK_INT_FB_DLY_MASK (0xF << SDMMC_CLK_INT_FB_DLY_SHIFT)
+
#define PLL_BASE 0x0
#define PLL_BASE_BYPASS (1<<31)
#define PLL_BASE_ENABLE (1<<30)
#define PLL_BASE_REF_ENABLE (1<<29)
#define PLL_BASE_OVERRIDE (1<<28)
-#define PLL_BASE_LOCK (1<<27)
#define PLL_BASE_DIVP_MASK (0x7<<20)
#define PLL_BASE_DIVP_SHIFT 20
#define PLL_BASE_DIVN_MASK (0x3FF<<8)
@@ -93,7 +97,6 @@
#define PLL_OUT_RESET_DISABLE (1<<0)
#define PLL_MISC(c) (((c)->flags & PLL_ALT_MISC_REG) ? 0x4 : 0xc)
-#define PLL_MISC_LOCK_ENABLE(c) (((c)->flags & PLLU) ? (1<<22) : (1<<18))
#define PLL_MISC_DCCON_SHIFT 20
#define PLL_MISC_CPCON_SHIFT 8
@@ -111,9 +114,9 @@
#define PLLE_MISC_READY (1 << 15)
-#define PERIPH_CLK_TO_ENB_REG(c) ((c->clk_num / 32) * 4)
-#define PERIPH_CLK_TO_ENB_SET_REG(c) ((c->clk_num / 32) * 8)
-#define PERIPH_CLK_TO_ENB_BIT(c) (1 << (c->clk_num % 32))
+#define PERIPH_CLK_TO_ENB_REG(c) ((c->u.periph.clk_num / 32) * 4)
+#define PERIPH_CLK_TO_ENB_SET_REG(c) ((c->u.periph.clk_num / 32) * 8)
+#define PERIPH_CLK_TO_ENB_BIT(c) (1 << (c->u.periph.clk_num % 32))
#define SUPER_CLK_MUX 0x00
#define SUPER_STATE_SHIFT 28
@@ -134,12 +137,42 @@
#define BUS_CLK_DISABLE (1<<3)
#define BUS_CLK_DIV_MASK 0x3
+#define PMC_CTRL 0x0
+ #define PMC_CTRL_BLINK_ENB (1 << 7)
+
+#define PMC_DPD_PADS_ORIDE 0x1c
+ #define PMC_DPD_PADS_ORIDE_BLINK_ENB (1 << 20)
+
+#define PMC_BLINK_TIMER_DATA_ON_SHIFT 0
+#define PMC_BLINK_TIMER_DATA_ON_MASK 0x7fff
+#define PMC_BLINK_TIMER_ENB (1 << 15)
+#define PMC_BLINK_TIMER_DATA_OFF_SHIFT 16
+#define PMC_BLINK_TIMER_DATA_OFF_MASK 0xffff
+
static void __iomem *reg_clk_base = IO_ADDRESS(TEGRA_CLK_RESET_BASE);
+static void __iomem *reg_pmc_base = IO_ADDRESS(TEGRA_PMC_BASE);
+
+/*
+ * Some clocks share a register with other clocks. Any clock op that
+ * non-atomically modifies a register used by another clock must lock
+ * clock_register_lock first.
+ */
+static DEFINE_SPINLOCK(clock_register_lock);
+
+/*
+ * Some peripheral clocks share an enable bit, so refcount the enable bits
+ * in registers CLK_ENABLE_L, CLK_ENABLE_H, and CLK_ENABLE_U
+ */
+static int tegra_periph_clk_enable_refcount[3 * 32];
#define clk_writel(value, reg) \
__raw_writel(value, (u32)reg_clk_base + (reg))
#define clk_readl(reg) \
__raw_readl((u32)reg_clk_base + (reg))
+#define pmc_writel(value, reg) \
+ __raw_writel(value, (u32)reg_pmc_base + (reg))
+#define pmc_readl(reg) \
+ __raw_readl((u32)reg_pmc_base + (reg))
unsigned long clk_measure_input_freq(void)
{
@@ -245,6 +278,18 @@ static struct clk_ops tegra_clk_m_ops = {
.disable = tegra2_clk_m_disable,
};
+void tegra2_periph_reset_assert(struct clk *c)
+{
+ BUG_ON(!c->ops->reset);
+ c->ops->reset(c, true);
+}
+
+void tegra2_periph_reset_deassert(struct clk *c)
+{
+ BUG_ON(!c->ops->reset);
+ c->ops->reset(c, false);
+}
+
/* super clock functions */
/* "super clocks" on tegra have two-stage muxes and a clock skipping
* super divider. We will ignore the clock skipping divider, since we
@@ -292,7 +337,7 @@ static int tegra2_super_clk_set_parent(struct clk *c, struct clk *p)
const struct clk_mux_sel *sel;
int shift;
- val = clk_readl(c->reg + SUPER_CLK_MUX);;
+ val = clk_readl(c->reg + SUPER_CLK_MUX);
BUG_ON(((val & SUPER_STATE_MASK) != SUPER_STATE_RUN) &&
((val & SUPER_STATE_MASK) != SUPER_STATE_IDLE));
shift = ((val & SUPER_STATE_MASK) == SUPER_STATE_IDLE) ?
@@ -303,12 +348,12 @@ static int tegra2_super_clk_set_parent(struct clk *c, struct clk *p)
val |= sel->value << shift;
if (c->refcnt)
- clk_enable_locked(p);
+ clk_enable(p);
clk_writel(val, c->reg);
if (c->refcnt && c->parent)
- clk_disable_locked(c->parent);
+ clk_disable(c->parent);
clk_reparent(c, p);
return 0;
@@ -317,11 +362,24 @@ static int tegra2_super_clk_set_parent(struct clk *c, struct clk *p)
return -EINVAL;
}
+/*
+ * Super clocks have "clock skippers" instead of dividers. Dividing using
+ * a clock skipper does not allow the voltage to be scaled down, so instead
+ * adjust the rate of the parent clock. This requires that the parent of a
+ * super clock have no other children, otherwise the rate will change
+ * underneath the other children.
+ */
+static int tegra2_super_clk_set_rate(struct clk *c, unsigned long rate)
+{
+ return clk_set_rate(c->parent, rate);
+}
+
static struct clk_ops tegra_super_ops = {
.init = tegra2_super_clk_init,
.enable = tegra2_super_clk_enable,
.disable = tegra2_super_clk_disable,
.set_parent = tegra2_super_clk_set_parent,
+ .set_rate = tegra2_super_clk_set_rate,
};
/* virtual cpu clock functions */
@@ -351,25 +409,36 @@ static void tegra2_cpu_clk_disable(struct clk *c)
static int tegra2_cpu_clk_set_rate(struct clk *c, unsigned long rate)
{
int ret;
- ret = clk_set_parent_locked(c->parent, c->backup);
+ /*
+ * Take an extra reference to the main pll so it doesn't turn
+ * off when we move the cpu off of it
+ */
+ clk_enable(c->u.cpu.main);
+
+ ret = clk_set_parent(c->parent, c->u.cpu.backup);
if (ret) {
- pr_err("Failed to switch cpu to clock %s\n", c->backup->name);
- return ret;
+ pr_err("Failed to switch cpu to clock %s\n", c->u.cpu.backup->name);
+ goto out;
}
- ret = clk_set_rate_locked(c->main, rate);
+ if (rate == clk_get_rate(c->u.cpu.backup))
+ goto out;
+
+ ret = clk_set_rate(c->u.cpu.main, rate);
if (ret) {
pr_err("Failed to change cpu pll to %lu\n", rate);
- return ret;
+ goto out;
}
- ret = clk_set_parent_locked(c->parent, c->main);
+ ret = clk_set_parent(c->parent, c->u.cpu.main);
if (ret) {
- pr_err("Failed to switch cpu to clock %s\n", c->main->name);
- return ret;
+ pr_err("Failed to switch cpu to clock %s\n", c->u.cpu.main->name);
+ goto out;
}
- return 0;
+out:
+ clk_disable(c->u.cpu.main);
+ return ret;
}
static struct clk_ops tegra_cpu_ops = {
@@ -379,6 +448,20 @@ static struct clk_ops tegra_cpu_ops = {
.set_rate = tegra2_cpu_clk_set_rate,
};
+/* virtual cop clock functions. Used to acquire the fake 'cop' clock to
+ * reset the COP block (i.e. AVP) */
+static void tegra2_cop_clk_reset(struct clk *c, bool assert)
+{
+ unsigned long reg = assert ? RST_DEVICES_SET : RST_DEVICES_CLR;
+
+ pr_debug("%s %s\n", __func__, assert ? "assert" : "deassert");
+ clk_writel(1 << 1, reg);
+}
+
+static struct clk_ops tegra_cop_ops = {
+ .reset = tegra2_cop_clk_reset,
+};
+
/* bus clock functions */
static void tegra2_bus_clk_init(struct clk *c)
{
@@ -390,24 +473,45 @@ static void tegra2_bus_clk_init(struct clk *c)
static int tegra2_bus_clk_enable(struct clk *c)
{
- u32 val = clk_readl(c->reg);
+ u32 val;
+ unsigned long flags;
+
+ spin_lock_irqsave(&clock_register_lock, flags);
+
+ val = clk_readl(c->reg);
val &= ~(BUS_CLK_DISABLE << c->reg_shift);
clk_writel(val, c->reg);
+
+ spin_unlock_irqrestore(&clock_register_lock, flags);
+
return 0;
}
static void tegra2_bus_clk_disable(struct clk *c)
{
- u32 val = clk_readl(c->reg);
+ u32 val;
+ unsigned long flags;
+
+ spin_lock_irqsave(&clock_register_lock, flags);
+
+ val = clk_readl(c->reg);
val |= BUS_CLK_DISABLE << c->reg_shift;
clk_writel(val, c->reg);
+
+ spin_unlock_irqrestore(&clock_register_lock, flags);
}
static int tegra2_bus_clk_set_rate(struct clk *c, unsigned long rate)
{
- u32 val = clk_readl(c->reg);
- unsigned long parent_rate = c->parent->rate;
+ u32 val;
+ unsigned long parent_rate = clk_get_rate(c->parent);
+ unsigned long flags;
+ int ret = -EINVAL;
int i;
+
+ spin_lock_irqsave(&clock_register_lock, flags);
+
+ val = clk_readl(c->reg);
for (i = 1; i <= 4; i++) {
if (rate == parent_rate / i) {
val &= ~(BUS_CLK_DIV_MASK << c->reg_shift);
@@ -415,10 +519,14 @@ static int tegra2_bus_clk_set_rate(struct clk *c, unsigned long rate)
clk_writel(val, c->reg);
c->div = i;
c->mul = 1;
- return 0;
+ ret = 0;
+ break;
}
}
- return -EINVAL;
+
+ spin_unlock_irqrestore(&clock_register_lock, flags);
+
+ return ret;
}
static struct clk_ops tegra_bus_ops = {
@@ -428,24 +536,96 @@ static struct clk_ops tegra_bus_ops = {
.set_rate = tegra2_bus_clk_set_rate,
};
-/* PLL Functions */
-static int tegra2_pll_clk_wait_for_lock(struct clk *c)
+/* Blink output functions */
+
+static void tegra2_blink_clk_init(struct clk *c)
{
- ktime_t before;
+ u32 val;
- before = ktime_get();
+ val = pmc_readl(PMC_CTRL);
+ c->state = (val & PMC_CTRL_BLINK_ENB) ? ON : OFF;
+ c->mul = 1;
+ val = pmc_readl(c->reg);
+
+ if (val & PMC_BLINK_TIMER_ENB) {
+ unsigned int on_off;
+
+ on_off = (val >> PMC_BLINK_TIMER_DATA_ON_SHIFT) &
+ PMC_BLINK_TIMER_DATA_ON_MASK;
+ val >>= PMC_BLINK_TIMER_DATA_OFF_SHIFT;
+ val &= PMC_BLINK_TIMER_DATA_OFF_MASK;
+ on_off += val;
+ /* each tick in the blink timer is 4 32KHz clocks */
+ c->div = on_off * 4;
+ } else {
+ c->div = 1;
+ }
+}
- while (!(clk_readl(c->reg + PLL_BASE) & PLL_BASE_LOCK)) {
- if (ktime_us_delta(ktime_get(), before) > 5000) {
- pr_err("Timed out waiting for lock bit on pll %s",
- c->name);
- return -1;
- }
+static int tegra2_blink_clk_enable(struct clk *c)
+{
+ u32 val;
+
+ val = pmc_readl(PMC_DPD_PADS_ORIDE);
+ pmc_writel(val | PMC_DPD_PADS_ORIDE_BLINK_ENB, PMC_DPD_PADS_ORIDE);
+
+ val = pmc_readl(PMC_CTRL);
+ pmc_writel(val | PMC_CTRL_BLINK_ENB, PMC_CTRL);
+
+ return 0;
+}
+
+static void tegra2_blink_clk_disable(struct clk *c)
+{
+ u32 val;
+
+ val = pmc_readl(PMC_CTRL);
+ pmc_writel(val & ~PMC_CTRL_BLINK_ENB, PMC_CTRL);
+
+ val = pmc_readl(PMC_DPD_PADS_ORIDE);
+ pmc_writel(val & ~PMC_DPD_PADS_ORIDE_BLINK_ENB, PMC_DPD_PADS_ORIDE);
+}
+
+static int tegra2_blink_clk_set_rate(struct clk *c, unsigned long rate)
+{
+ unsigned long parent_rate = clk_get_rate(c->parent);
+ if (rate >= parent_rate) {
+ c->div = 1;
+ pmc_writel(0, c->reg);
+ } else {
+ unsigned int on_off;
+ u32 val;
+
+ on_off = DIV_ROUND_UP(parent_rate / 8, rate);
+ c->div = on_off * 8;
+
+ val = (on_off & PMC_BLINK_TIMER_DATA_ON_MASK) <<
+ PMC_BLINK_TIMER_DATA_ON_SHIFT;
+ on_off &= PMC_BLINK_TIMER_DATA_OFF_MASK;
+ on_off <<= PMC_BLINK_TIMER_DATA_OFF_SHIFT;
+ val |= on_off;
+ val |= PMC_BLINK_TIMER_ENB;
+ pmc_writel(val, c->reg);
}
return 0;
}
+static struct clk_ops tegra_blink_clk_ops = {
+ .init = &tegra2_blink_clk_init,
+ .enable = &tegra2_blink_clk_enable,
+ .disable = &tegra2_blink_clk_disable,
+ .set_rate = &tegra2_blink_clk_set_rate,
+};
+
+/* PLL Functions */
+static int tegra2_pll_clk_wait_for_lock(struct clk *c)
+{
+ udelay(c->u.pll.lock_delay);
+
+ return 0;
+}
+
static void tegra2_pll_clk_init(struct clk *c)
{
u32 val = clk_readl(c->reg + PLL_BASE);
@@ -479,10 +659,6 @@ static int tegra2_pll_clk_enable(struct clk *c)
val |= PLL_BASE_ENABLE;
clk_writel(val, c->reg + PLL_BASE);
- val = clk_readl(c->reg + PLL_MISC(c));
- val |= PLL_MISC_LOCK_ENABLE(c);
- clk_writel(val, c->reg + PLL_MISC(c));
-
tegra2_pll_clk_wait_for_lock(c);
return 0;
@@ -502,13 +678,12 @@ static int tegra2_pll_clk_set_rate(struct clk *c, unsigned long rate)
{
u32 val;
unsigned long input_rate;
- const struct clk_pll_table *sel;
+ const struct clk_pll_freq_table *sel;
pr_debug("%s: %s %lu\n", __func__, c->name, rate);
- BUG_ON(c->refcnt != 0);
- input_rate = c->parent->rate;
- for (sel = c->pll_table; sel->input_rate != 0; sel++) {
+ input_rate = clk_get_rate(c->parent);
+ for (sel = c->u.pll.freq_table; sel->input_rate != 0; sel++) {
if (sel->input_rate == input_rate && sel->output_rate == rate) {
c->mul = sel->n;
c->div = sel->m * sel->p;
@@ -620,9 +795,11 @@ static int tegra2_pll_div_clk_enable(struct clk *c)
{
u32 val;
u32 new_val;
+ unsigned long flags;
pr_debug("%s: %s\n", __func__, c->name);
if (c->flags & DIV_U71) {
+ spin_lock_irqsave(&clock_register_lock, flags);
val = clk_readl(c->reg);
new_val = val >> c->reg_shift;
new_val &= 0xFFFF;
@@ -632,12 +809,15 @@ static int tegra2_pll_div_clk_enable(struct clk *c)
val &= ~(0xFFFF << c->reg_shift);
val |= new_val << c->reg_shift;
clk_writel(val, c->reg);
+ spin_unlock_irqrestore(&clock_register_lock, flags);
return 0;
} else if (c->flags & DIV_2) {
BUG_ON(!(c->flags & PLLD));
+ spin_lock_irqsave(&clock_register_lock, flags);
val = clk_readl(c->reg);
val &= ~PLLD_MISC_DIV_RST;
clk_writel(val, c->reg);
+ spin_unlock_irqrestore(&clock_register_lock, flags);
return 0;
}
return -EINVAL;
@@ -647,9 +827,11 @@ static void tegra2_pll_div_clk_disable(struct clk *c)
{
u32 val;
u32 new_val;
+ unsigned long flags;
pr_debug("%s: %s\n", __func__, c->name);
if (c->flags & DIV_U71) {
+ spin_lock_irqsave(&clock_register_lock, flags);
val = clk_readl(c->reg);
new_val = val >> c->reg_shift;
new_val &= 0xFFFF;
@@ -659,11 +841,14 @@ static void tegra2_pll_div_clk_disable(struct clk *c)
val &= ~(0xFFFF << c->reg_shift);
val |= new_val << c->reg_shift;
clk_writel(val, c->reg);
+ spin_unlock_irqrestore(&clock_register_lock, flags);
} else if (c->flags & DIV_2) {
BUG_ON(!(c->flags & PLLD));
+ spin_lock_irqsave(&clock_register_lock, flags);
val = clk_readl(c->reg);
val |= PLLD_MISC_DIV_RST;
clk_writel(val, c->reg);
+ spin_unlock_irqrestore(&clock_register_lock, flags);
}
}
@@ -672,10 +857,14 @@ static int tegra2_pll_div_clk_set_rate(struct clk *c, unsigned long rate)
u32 val;
u32 new_val;
int divider_u71;
+ unsigned long parent_rate = clk_get_rate(c->parent);
+ unsigned long flags;
+
pr_debug("%s: %s %lu\n", __func__, c->name, rate);
if (c->flags & DIV_U71) {
- divider_u71 = clk_div71_get_divider(c->parent->rate, rate);
+ divider_u71 = clk_div71_get_divider(parent_rate, rate);
if (divider_u71 >= 0) {
+ spin_lock_irqsave(&clock_register_lock, flags);
val = clk_readl(c->reg);
new_val = val >> c->reg_shift;
new_val &= 0xFFFF;
@@ -689,10 +878,11 @@ static int tegra2_pll_div_clk_set_rate(struct clk *c, unsigned long rate)
clk_writel(val, c->reg);
c->div = divider_u71 + 2;
c->mul = 2;
+ spin_unlock_irqrestore(&clock_register_lock, flags);
return 0;
}
} else if (c->flags & DIV_2) {
- if (c->parent->rate == rate * 2)
+ if (parent_rate == rate * 2)
return 0;
}
return -EINVAL;
@@ -701,15 +891,16 @@ static int tegra2_pll_div_clk_set_rate(struct clk *c, unsigned long rate)
static long tegra2_pll_div_clk_round_rate(struct clk *c, unsigned long rate)
{
int divider;
+ unsigned long parent_rate = clk_get_rate(c->parent);
pr_debug("%s: %s %lu\n", __func__, c->name, rate);
if (c->flags & DIV_U71) {
- divider = clk_div71_get_divider(c->parent->rate, rate);
+ divider = clk_div71_get_divider(parent_rate, rate);
if (divider < 0)
return divider;
- return c->parent->rate * 2 / (divider + 2);
+ return DIV_ROUND_UP(parent_rate * 2, divider + 2);
} else if (c->flags & DIV_2) {
- return c->parent->rate / 2;
+ return DIV_ROUND_UP(parent_rate, 2);
}
return -EINVAL;
}
@@ -755,9 +946,14 @@ static void tegra2_periph_clk_init(struct clk *c)
}
c->state = ON;
+
+ if (!c->u.periph.clk_num)
+ return;
+
if (!(clk_readl(CLK_OUT_ENB + PERIPH_CLK_TO_ENB_REG(c)) &
PERIPH_CLK_TO_ENB_BIT(c)))
c->state = OFF;
+
if (!(c->flags & PERIPH_NO_RESET))
if (clk_readl(RST_DEVICES + PERIPH_CLK_TO_ENB_REG(c)) &
PERIPH_CLK_TO_ENB_BIT(c))
@@ -767,8 +963,20 @@ static void tegra2_periph_clk_init(struct clk *c)
static int tegra2_periph_clk_enable(struct clk *c)
{
u32 val;
+ unsigned long flags;
+ int refcount;
pr_debug("%s on clock %s\n", __func__, c->name);
+ if (!c->u.periph.clk_num)
+ return 0;
+
+ spin_lock_irqsave(&clock_register_lock, flags);
+
+ refcount = tegra_periph_clk_enable_refcount[c->u.periph.clk_num]++;
+
+ if (refcount > 1)
+ goto out;
+
clk_writel(PERIPH_CLK_TO_ENB_BIT(c),
CLK_OUT_ENB_SET + PERIPH_CLK_TO_ENB_SET_REG(c));
if (!(c->flags & PERIPH_NO_RESET) && !(c->flags & PERIPH_MANUAL_RESET))
@@ -781,34 +989,48 @@ static int tegra2_periph_clk_enable(struct clk *c)
val |= 0x3 << 24;
clk_writel(val, c->reg);
}
+
+out:
+ spin_unlock_irqrestore(&clock_register_lock, flags);
+
return 0;
}
static void tegra2_periph_clk_disable(struct clk *c)
{
+ unsigned long flags;
+
pr_debug("%s on clock %s\n", __func__, c->name);
- clk_writel(PERIPH_CLK_TO_ENB_BIT(c),
- CLK_OUT_ENB_CLR + PERIPH_CLK_TO_ENB_SET_REG(c));
-}
+ if (!c->u.periph.clk_num)
+ return;
-void tegra2_periph_reset_deassert(struct clk *c)
-{
- pr_debug("%s on clock %s\n", __func__, c->name);
- if (!(c->flags & PERIPH_NO_RESET))
+ spin_lock_irqsave(&clock_register_lock, flags);
+
+ if (c->refcnt)
+ tegra_periph_clk_enable_refcount[c->u.periph.clk_num]--;
+
+ if (tegra_periph_clk_enable_refcount[c->u.periph.clk_num] == 0)
clk_writel(PERIPH_CLK_TO_ENB_BIT(c),
- RST_DEVICES_CLR + PERIPH_CLK_TO_ENB_SET_REG(c));
+ CLK_OUT_ENB_CLR + PERIPH_CLK_TO_ENB_SET_REG(c));
+
+ spin_unlock_irqrestore(&clock_register_lock, flags);
}
-void tegra2_periph_reset_assert(struct clk *c)
+static void tegra2_periph_clk_reset(struct clk *c, bool assert)
{
- pr_debug("%s on clock %s\n", __func__, c->name);
+ unsigned long base = assert ? RST_DEVICES_SET : RST_DEVICES_CLR;
+
+ pr_debug("%s %s on clock %s\n", __func__,
+ assert ? "assert" : "deassert", c->name);
+
+ BUG_ON(!c->u.periph.clk_num);
+
if (!(c->flags & PERIPH_NO_RESET))
clk_writel(PERIPH_CLK_TO_ENB_BIT(c),
- RST_DEVICES_SET + PERIPH_CLK_TO_ENB_SET_REG(c));
+ base + PERIPH_CLK_TO_ENB_SET_REG(c));
}
-
static int tegra2_periph_clk_set_parent(struct clk *c, struct clk *p)
{
u32 val;
@@ -821,12 +1043,12 @@ static int tegra2_periph_clk_set_parent(struct clk *c, struct clk *p)
val |= (sel->value) << PERIPH_CLK_SOURCE_SHIFT;
if (c->refcnt)
- clk_enable_locked(p);
+ clk_enable(p);
clk_writel(val, c->reg);
if (c->refcnt && c->parent)
- clk_disable_locked(c->parent);
+ clk_disable(c->parent);
clk_reparent(c, p);
return 0;
@@ -840,9 +1062,10 @@ static int tegra2_periph_clk_set_rate(struct clk *c, unsigned long rate)
{
u32 val;
int divider;
- pr_debug("%s: %lu\n", __func__, rate);
+ unsigned long parent_rate = clk_get_rate(c->parent);
+
if (c->flags & DIV_U71) {
- divider = clk_div71_get_divider(c->parent->rate, rate);
+ divider = clk_div71_get_divider(parent_rate, rate);
if (divider >= 0) {
val = clk_readl(c->reg);
val &= ~PERIPH_CLK_SOURCE_DIVU71_MASK;
@@ -853,7 +1076,7 @@ static int tegra2_periph_clk_set_rate(struct clk *c, unsigned long rate)
return 0;
}
} else if (c->flags & DIV_U16) {
- divider = clk_div16_get_divider(c->parent->rate, rate);
+ divider = clk_div16_get_divider(parent_rate, rate);
if (divider >= 0) {
val = clk_readl(c->reg);
val &= ~PERIPH_CLK_SOURCE_DIVU16_MASK;
@@ -863,7 +1086,7 @@ static int tegra2_periph_clk_set_rate(struct clk *c, unsigned long rate)
c->mul = 1;
return 0;
}
- } else if (c->parent->rate <= rate) {
+ } else if (parent_rate <= rate) {
c->div = 1;
c->mul = 1;
return 0;
@@ -875,19 +1098,20 @@ static long tegra2_periph_clk_round_rate(struct clk *c,
unsigned long rate)
{
int divider;
+ unsigned long parent_rate = clk_get_rate(c->parent);
pr_debug("%s: %s %lu\n", __func__, c->name, rate);
if (c->flags & DIV_U71) {
- divider = clk_div71_get_divider(c->parent->rate, rate);
+ divider = clk_div71_get_divider(parent_rate, rate);
if (divider < 0)
return divider;
- return c->parent->rate * 2 / (divider + 2);
+ return DIV_ROUND_UP(parent_rate * 2, divider + 2);
} else if (c->flags & DIV_U16) {
- divider = clk_div16_get_divider(c->parent->rate, rate);
+ divider = clk_div16_get_divider(parent_rate, rate);
if (divider < 0)
return divider;
- return c->parent->rate / (divider + 1);
+ return DIV_ROUND_UP(parent_rate, divider + 1);
}
return -EINVAL;
}
@@ -899,6 +1123,71 @@ static struct clk_ops tegra_periph_clk_ops = {
.set_parent = &tegra2_periph_clk_set_parent,
.set_rate = &tegra2_periph_clk_set_rate,
.round_rate = &tegra2_periph_clk_round_rate,
+ .reset = &tegra2_periph_clk_reset,
+};
+
+/* 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 tegra2_sdmmc_tap_delay(struct clk *c, int delay)
+{
+ u32 reg;
+
+ delay = clamp(delay, 0, 15);
+ reg = clk_readl(c->reg);
+ reg &= ~SDMMC_CLK_INT_FB_DLY_MASK;
+ reg |= SDMMC_CLK_INT_FB_SEL;
+ reg |= delay << SDMMC_CLK_INT_FB_DLY_SHIFT;
+ clk_writel(reg, c->reg);
+}
+
+/* External memory controller clock ops */
+static void tegra2_emc_clk_init(struct clk *c)
+{
+ tegra2_periph_clk_init(c);
+ c->max_rate = clk_get_rate_locked(c);
+}
+
+static long tegra2_emc_clk_round_rate(struct clk *c, unsigned long rate)
+{
+ long new_rate = rate;
+
+ new_rate = tegra_emc_round_rate(new_rate);
+ if (new_rate < 0)
+ return c->max_rate;
+
+ BUG_ON(new_rate != tegra2_periph_clk_round_rate(c, new_rate));
+
+ return new_rate;
+}
+
+static int tegra2_emc_clk_set_rate(struct clk *c, unsigned long rate)
+{
+ int ret;
+ /*
+ * The Tegra2 memory controller has an interlock with the clock
+ * block that allows memory shadowed registers to be updated,
+ * and then transfer them to the main registers at the same
+ * time as the clock update without glitches.
+ */
+ ret = tegra_emc_set_rate(rate);
+ if (ret < 0)
+ return ret;
+
+ ret = tegra2_periph_clk_set_rate(c, rate);
+ udelay(1);
+
+ return ret;
+}
+
+static struct clk_ops tegra_emc_clk_ops = {
+ .init = &tegra2_emc_clk_init,
+ .enable = &tegra2_periph_clk_enable,
+ .disable = &tegra2_periph_clk_disable,
+ .set_parent = &tegra2_periph_clk_set_parent,
+ .set_rate = &tegra2_emc_clk_set_rate,
+ .round_rate = &tegra2_emc_clk_round_rate,
+ .reset = &tegra2_periph_clk_reset,
};
/* Clock doubler ops */
@@ -907,6 +1196,10 @@ static void tegra2_clk_double_init(struct clk *c)
c->mul = 2;
c->div = 1;
c->state = ON;
+
+ if (!c->u.periph.clk_num)
+ return;
+
if (!(clk_readl(CLK_OUT_ENB + PERIPH_CLK_TO_ENB_REG(c)) &
PERIPH_CLK_TO_ENB_BIT(c)))
c->state = OFF;
@@ -914,7 +1207,7 @@ static void tegra2_clk_double_init(struct clk *c)
static int tegra2_clk_double_set_rate(struct clk *c, unsigned long rate)
{
- if (rate != 2 * c->parent->rate)
+ if (rate != 2 * clk_get_rate(c->parent))
return -EINVAL;
c->mul = 2;
c->div = 1;
@@ -928,6 +1221,7 @@ static struct clk_ops tegra_clk_double_ops = {
.set_rate = &tegra2_clk_double_set_rate,
};
+/* Audio sync clock ops */
static void tegra2_audio_sync_clk_init(struct clk *c)
{
int source;
@@ -964,12 +1258,12 @@ static int tegra2_audio_sync_clk_set_parent(struct clk *c, struct clk *p)
val |= sel->value;
if (c->refcnt)
- clk_enable_locked(p);
+ clk_enable(p);
clk_writel(val, c->reg);
if (c->refcnt && c->parent)
- clk_disable_locked(c->parent);
+ clk_disable(c->parent);
clk_reparent(c, p);
return 0;
@@ -979,33 +1273,154 @@ static int tegra2_audio_sync_clk_set_parent(struct clk *c, struct clk *p)
return -EINVAL;
}
-static int tegra2_audio_sync_clk_set_rate(struct clk *c, unsigned long rate)
-{
- unsigned long parent_rate;
- if (!c->parent) {
- pr_err("%s: clock has no parent\n", __func__);
- return -EINVAL;
- }
- parent_rate = c->parent->rate;
- if (rate != parent_rate) {
- pr_err("%s: %s/%ld differs from parent %s/%ld\n",
- __func__,
- c->name, rate,
- c->parent->name, parent_rate);
- return -EINVAL;
- }
- c->rate = parent_rate;
- return 0;
-}
-
static struct clk_ops tegra_audio_sync_clk_ops = {
.init = tegra2_audio_sync_clk_init,
.enable = tegra2_audio_sync_clk_enable,
.disable = tegra2_audio_sync_clk_disable,
- .set_rate = tegra2_audio_sync_clk_set_rate,
.set_parent = tegra2_audio_sync_clk_set_parent,
};
+/* cdev1 and cdev2 (dap_mclk1 and dap_mclk2) ops */
+
+static void tegra2_cdev_clk_init(struct clk *c)
+{
+ /* We could un-tristate the cdev1 or cdev2 pingroup here; this is
+ * currently done in the pinmux code. */
+ c->state = ON;
+
+ BUG_ON(!c->u.periph.clk_num);
+
+ if (!(clk_readl(CLK_OUT_ENB + PERIPH_CLK_TO_ENB_REG(c)) &
+ PERIPH_CLK_TO_ENB_BIT(c)))
+ c->state = OFF;
+}
+
+static int tegra2_cdev_clk_enable(struct clk *c)
+{
+ BUG_ON(!c->u.periph.clk_num);
+
+ clk_writel(PERIPH_CLK_TO_ENB_BIT(c),
+ CLK_OUT_ENB_SET + PERIPH_CLK_TO_ENB_SET_REG(c));
+ return 0;
+}
+
+static void tegra2_cdev_clk_disable(struct clk *c)
+{
+ BUG_ON(!c->u.periph.clk_num);
+
+ clk_writel(PERIPH_CLK_TO_ENB_BIT(c),
+ CLK_OUT_ENB_CLR + PERIPH_CLK_TO_ENB_SET_REG(c));
+}
+
+static struct clk_ops tegra_cdev_clk_ops = {
+ .init = &tegra2_cdev_clk_init,
+ .enable = &tegra2_cdev_clk_enable,
+ .disable = &tegra2_cdev_clk_disable,
+};
+
+/* shared bus ops */
+/*
+ * Some clocks may have multiple downstream users that need to request a
+ * higher clock rate. Shared bus clocks provide a unique shared_bus_user
+ * clock to each user. The frequency of the bus is set to the highest
+ * enabled shared_bus_user clock, with a minimum value set by the
+ * shared bus.
+ */
+static int tegra_clk_shared_bus_update(struct clk *bus)
+{
+ struct clk *c;
+ unsigned long rate = bus->min_rate;
+
+ list_for_each_entry(c, &bus->shared_bus_list, u.shared_bus_user.node)
+ if (c->u.shared_bus_user.enabled)
+ rate = max(c->u.shared_bus_user.rate, rate);
+
+ if (rate == clk_get_rate_locked(bus))
+ return 0;
+
+ return clk_set_rate_locked(bus, rate);
+};
+
+static void tegra_clk_shared_bus_init(struct clk *c)
+{
+ unsigned long flags;
+
+ c->max_rate = c->parent->max_rate;
+ c->u.shared_bus_user.rate = c->parent->max_rate;
+ c->state = OFF;
+ c->set = true;
+
+ spin_lock_irqsave(&c->parent->spinlock, flags);
+
+ list_add_tail(&c->u.shared_bus_user.node,
+ &c->parent->shared_bus_list);
+
+ spin_unlock_irqrestore(&c->parent->spinlock, flags);
+}
+
+static int tegra_clk_shared_bus_set_rate(struct clk *c, unsigned long rate)
+{
+ unsigned long flags;
+ int ret;
+ long new_rate = rate;
+
+ new_rate = clk_round_rate(c->parent, new_rate);
+ if (new_rate < 0)
+ return new_rate;
+
+ spin_lock_irqsave(&c->parent->spinlock, flags);
+
+ c->u.shared_bus_user.rate = new_rate;
+ ret = tegra_clk_shared_bus_update(c->parent);
+
+ spin_unlock_irqrestore(&c->parent->spinlock, flags);
+
+ return ret;
+}
+
+static long tegra_clk_shared_bus_round_rate(struct clk *c, unsigned long rate)
+{
+ return clk_round_rate(c->parent, rate);
+}
+
+static int tegra_clk_shared_bus_enable(struct clk *c)
+{
+ unsigned long flags;
+ int ret;
+
+ spin_lock_irqsave(&c->parent->spinlock, flags);
+
+ c->u.shared_bus_user.enabled = true;
+ ret = tegra_clk_shared_bus_update(c->parent);
+
+ spin_unlock_irqrestore(&c->parent->spinlock, flags);
+
+ return ret;
+}
+
+static void tegra_clk_shared_bus_disable(struct clk *c)
+{
+ unsigned long flags;
+ int ret;
+
+ spin_lock_irqsave(&c->parent->spinlock, flags);
+
+ c->u.shared_bus_user.enabled = false;
+ ret = tegra_clk_shared_bus_update(c->parent);
+ WARN_ON_ONCE(ret);
+
+ spin_unlock_irqrestore(&c->parent->spinlock, flags);
+}
+
+static struct clk_ops tegra_clk_shared_bus_ops = {
+ .init = tegra_clk_shared_bus_init,
+ .enable = tegra_clk_shared_bus_enable,
+ .disable = tegra_clk_shared_bus_disable,
+ .set_rate = tegra_clk_shared_bus_set_rate,
+ .round_rate = tegra_clk_shared_bus_round_rate,
+};
+
+
/* Clock definitions */
static struct clk tegra_clk_32k = {
.name = "clk_32k",
@@ -1014,7 +1429,7 @@ static struct clk tegra_clk_32k = {
.max_rate = 32768,
};
-static struct clk_pll_table tegra_pll_s_table[] = {
+static struct clk_pll_freq_table tegra_pll_s_freq_table[] = {
{32768, 12000000, 366, 1, 1, 0},
{32768, 13000000, 397, 1, 1, 0},
{32768, 19200000, 586, 1, 1, 0},
@@ -1026,16 +1441,19 @@ static struct clk tegra_pll_s = {
.name = "pll_s",
.flags = PLL_ALT_MISC_REG,
.ops = &tegra_pll_ops,
- .reg = 0xf0,
- .input_min = 32768,
- .input_max = 32768,
.parent = &tegra_clk_32k,
- .cf_min = 0, /* FIXME */
- .cf_max = 0, /* FIXME */
- .vco_min = 12000000,
- .vco_max = 26000000,
- .pll_table = tegra_pll_s_table,
.max_rate = 26000000,
+ .reg = 0xf0,
+ .u.pll = {
+ .input_min = 32768,
+ .input_max = 32768,
+ .cf_min = 0, /* FIXME */
+ .cf_max = 0, /* FIXME */
+ .vco_min = 12000000,
+ .vco_max = 26000000,
+ .freq_table = tegra_pll_s_freq_table,
+ .lock_delay = 300,
+ },
};
static struct clk_mux_sel tegra_clk_m_sel[] = {
@@ -1043,18 +1461,18 @@ static struct clk_mux_sel tegra_clk_m_sel[] = {
{ .input = &tegra_pll_s, .value = 1},
{ 0, 0},
};
+
static struct clk tegra_clk_m = {
.name = "clk_m",
.flags = ENABLE_ON_INIT,
.ops = &tegra_clk_m_ops,
.inputs = tegra_clk_m_sel,
.reg = 0x1fc,
- .reg_mask = (1<<28),
.reg_shift = 28,
.max_rate = 26000000,
};
-static struct clk_pll_table tegra_pll_c_table[] = {
+static struct clk_pll_freq_table tegra_pll_c_freq_table[] = {
{ 0, 0, 0, 0, 0, 0 },
};
@@ -1063,15 +1481,18 @@ static struct clk tegra_pll_c = {
.flags = PLL_HAS_CPCON,
.ops = &tegra_pll_ops,
.reg = 0x80,
- .input_min = 2000000,
- .input_max = 31000000,
.parent = &tegra_clk_m,
- .cf_min = 1000000,
- .cf_max = 6000000,
- .vco_min = 20000000,
- .vco_max = 1400000000,
- .pll_table = tegra_pll_c_table,
.max_rate = 600000000,
+ .u.pll = {
+ .input_min = 2000000,
+ .input_max = 31000000,
+ .cf_min = 1000000,
+ .cf_max = 6000000,
+ .vco_min = 20000000,
+ .vco_max = 1400000000,
+ .freq_table = tegra_pll_c_freq_table,
+ .lock_delay = 300,
+ },
};
static struct clk tegra_pll_c_out1 = {
@@ -1084,7 +1505,7 @@ static struct clk tegra_pll_c_out1 = {
.max_rate = 600000000,
};
-static struct clk_pll_table tegra_pll_m_table[] = {
+static struct clk_pll_freq_table tegra_pll_m_freq_table[] = {
{ 12000000, 666000000, 666, 12, 1, 8},
{ 13000000, 666000000, 666, 13, 1, 8},
{ 19200000, 666000000, 555, 16, 1, 8},
@@ -1101,15 +1522,18 @@ static struct clk tegra_pll_m = {
.flags = PLL_HAS_CPCON,
.ops = &tegra_pll_ops,
.reg = 0x90,
- .input_min = 2000000,
- .input_max = 31000000,
.parent = &tegra_clk_m,
- .cf_min = 1000000,
- .cf_max = 6000000,
- .vco_min = 20000000,
- .vco_max = 1200000000,
- .pll_table = tegra_pll_m_table,
.max_rate = 800000000,
+ .u.pll = {
+ .input_min = 2000000,
+ .input_max = 31000000,
+ .cf_min = 1000000,
+ .cf_max = 6000000,
+ .vco_min = 20000000,
+ .vco_max = 1200000000,
+ .freq_table = tegra_pll_m_freq_table,
+ .lock_delay = 300,
+ },
};
static struct clk tegra_pll_m_out1 = {
@@ -1122,7 +1546,7 @@ static struct clk tegra_pll_m_out1 = {
.max_rate = 600000000,
};
-static struct clk_pll_table tegra_pll_p_table[] = {
+static struct clk_pll_freq_table tegra_pll_p_freq_table[] = {
{ 12000000, 216000000, 432, 12, 2, 8},
{ 13000000, 216000000, 432, 13, 2, 8},
{ 19200000, 216000000, 90, 4, 2, 1},
@@ -1139,15 +1563,18 @@ static struct clk tegra_pll_p = {
.flags = ENABLE_ON_INIT | PLL_FIXED | PLL_HAS_CPCON,
.ops = &tegra_pll_ops,
.reg = 0xa0,
- .input_min = 2000000,
- .input_max = 31000000,
.parent = &tegra_clk_m,
- .cf_min = 1000000,
- .cf_max = 6000000,
- .vco_min = 20000000,
- .vco_max = 1400000000,
- .pll_table = tegra_pll_p_table,
.max_rate = 432000000,
+ .u.pll = {
+ .input_min = 2000000,
+ .input_max = 31000000,
+ .cf_min = 1000000,
+ .cf_max = 6000000,
+ .vco_min = 20000000,
+ .vco_max = 1400000000,
+ .freq_table = tegra_pll_p_freq_table,
+ .lock_delay = 300,
+ },
};
static struct clk tegra_pll_p_out1 = {
@@ -1190,11 +1617,9 @@ static struct clk tegra_pll_p_out4 = {
.max_rate = 432000000,
};
-static struct clk_pll_table tegra_pll_a_table[] = {
+static struct clk_pll_freq_table tegra_pll_a_freq_table[] = {
{ 28800000, 56448000, 49, 25, 1, 1},
{ 28800000, 73728000, 64, 25, 1, 1},
- { 28800000, 11289600, 49, 25, 1, 1},
- { 28800000, 12288000, 64, 25, 1, 1},
{ 28800000, 24000000, 5, 6, 1, 1},
{ 0, 0, 0, 0, 0, 0 },
};
@@ -1204,15 +1629,18 @@ static struct clk tegra_pll_a = {
.flags = PLL_HAS_CPCON,
.ops = &tegra_pll_ops,
.reg = 0xb0,
- .input_min = 2000000,
- .input_max = 31000000,
.parent = &tegra_pll_p_out1,
- .cf_min = 1000000,
- .cf_max = 6000000,
- .vco_min = 20000000,
- .vco_max = 1400000000,
- .pll_table = tegra_pll_a_table,
- .max_rate = 56448000,
+ .max_rate = 73728000,
+ .u.pll = {
+ .input_min = 2000000,
+ .input_max = 31000000,
+ .cf_min = 1000000,
+ .cf_max = 6000000,
+ .vco_min = 20000000,
+ .vco_max = 1400000000,
+ .freq_table = tegra_pll_a_freq_table,
+ .lock_delay = 300,
+ },
};
static struct clk tegra_pll_a_out0 = {
@@ -1222,14 +1650,25 @@ static struct clk tegra_pll_a_out0 = {
.parent = &tegra_pll_a,
.reg = 0xb4,
.reg_shift = 0,
- .max_rate = 56448000,
+ .max_rate = 73728000,
};
-static struct clk_pll_table tegra_pll_d_table[] = {
+static struct clk_pll_freq_table tegra_pll_d_freq_table[] = {
+ { 12000000, 216000000, 216, 12, 1, 4},
+ { 13000000, 216000000, 216, 13, 1, 4},
+ { 19200000, 216000000, 135, 12, 1, 3},
+ { 26000000, 216000000, 216, 26, 1, 4},
+
+ { 12000000, 594000000, 594, 12, 1, 8},
+ { 13000000, 594000000, 594, 13, 1, 8},
+ { 19200000, 594000000, 495, 16, 1, 8},
+ { 26000000, 594000000, 594, 26, 1, 8},
+
{ 12000000, 1000000000, 1000, 12, 1, 12},
{ 13000000, 1000000000, 1000, 13, 1, 12},
{ 19200000, 1000000000, 625, 12, 1, 8},
{ 26000000, 1000000000, 1000, 26, 1, 12},
+
{ 0, 0, 0, 0, 0, 0 },
};
@@ -1238,15 +1677,18 @@ static struct clk tegra_pll_d = {
.flags = PLL_HAS_CPCON | PLLD,
.ops = &tegra_pll_ops,
.reg = 0xd0,
- .input_min = 2000000,
- .input_max = 40000000,
.parent = &tegra_clk_m,
- .cf_min = 1000000,
- .cf_max = 6000000,
- .vco_min = 40000000,
- .vco_max = 1000000000,
- .pll_table = tegra_pll_d_table,
.max_rate = 1000000000,
+ .u.pll = {
+ .input_min = 2000000,
+ .input_max = 40000000,
+ .cf_min = 1000000,
+ .cf_max = 6000000,
+ .vco_min = 40000000,
+ .vco_max = 1000000000,
+ .freq_table = tegra_pll_d_freq_table,
+ .lock_delay = 1000,
+ },
};
static struct clk tegra_pll_d_out0 = {
@@ -1257,7 +1699,7 @@ static struct clk tegra_pll_d_out0 = {
.max_rate = 500000000,
};
-static struct clk_pll_table tegra_pll_u_table[] = {
+static struct clk_pll_freq_table tegra_pll_u_freq_table[] = {
{ 12000000, 480000000, 960, 12, 2, 0},
{ 13000000, 480000000, 960, 13, 2, 0},
{ 19200000, 480000000, 200, 4, 2, 0},
@@ -1270,18 +1712,21 @@ static struct clk tegra_pll_u = {
.flags = PLLU,
.ops = &tegra_pll_ops,
.reg = 0xc0,
- .input_min = 2000000,
- .input_max = 40000000,
.parent = &tegra_clk_m,
- .cf_min = 1000000,
- .cf_max = 6000000,
- .vco_min = 480000000,
- .vco_max = 960000000,
- .pll_table = tegra_pll_u_table,
.max_rate = 480000000,
-};
-
-static struct clk_pll_table tegra_pll_x_table[] = {
+ .u.pll = {
+ .input_min = 2000000,
+ .input_max = 40000000,
+ .cf_min = 1000000,
+ .cf_max = 6000000,
+ .vco_min = 480000000,
+ .vco_max = 960000000,
+ .freq_table = tegra_pll_u_freq_table,
+ .lock_delay = 1000,
+ },
+};
+
+static struct clk_pll_freq_table tegra_pll_x_freq_table[] = {
/* 1 GHz */
{ 12000000, 1000000000, 1000, 12, 1, 12},
{ 13000000, 1000000000, 1000, 13, 1, 12},
@@ -1307,10 +1752,10 @@ static struct clk_pll_table tegra_pll_x_table[] = {
{ 26000000, 760000000, 760, 26, 1, 12},
/* 608 MHz */
- { 12000000, 608000000, 760, 12, 1, 12},
- { 13000000, 608000000, 760, 13, 1, 12},
+ { 12000000, 608000000, 608, 12, 1, 12},
+ { 13000000, 608000000, 608, 13, 1, 12},
{ 19200000, 608000000, 380, 12, 1, 8},
- { 26000000, 608000000, 760, 26, 1, 12},
+ { 26000000, 608000000, 608, 26, 1, 12},
/* 456 MHz */
{ 12000000, 456000000, 456, 12, 1, 12},
@@ -1332,18 +1777,21 @@ static struct clk tegra_pll_x = {
.flags = PLL_HAS_CPCON | PLL_ALT_MISC_REG,
.ops = &tegra_pllx_ops,
.reg = 0xe0,
- .input_min = 2000000,
- .input_max = 31000000,
.parent = &tegra_clk_m,
- .cf_min = 1000000,
- .cf_max = 6000000,
- .vco_min = 20000000,
- .vco_max = 1200000000,
- .pll_table = tegra_pll_x_table,
.max_rate = 1000000000,
-};
-
-static struct clk_pll_table tegra_pll_e_table[] = {
+ .u.pll = {
+ .input_min = 2000000,
+ .input_max = 31000000,
+ .cf_min = 1000000,
+ .cf_max = 6000000,
+ .vco_min = 20000000,
+ .vco_max = 1200000000,
+ .freq_table = tegra_pll_x_freq_table,
+ .lock_delay = 300,
+ },
+};
+
+static struct clk_pll_freq_table tegra_pll_e_freq_table[] = {
{ 12000000, 100000000, 200, 24, 1, 0 },
{ 0, 0, 0, 0, 0, 0 },
};
@@ -1352,23 +1800,49 @@ static struct clk tegra_pll_e = {
.name = "pll_e",
.flags = PLL_ALT_MISC_REG,
.ops = &tegra_plle_ops,
- .input_min = 12000000,
- .input_max = 12000000,
- .max_rate = 100000000,
.parent = &tegra_clk_m,
.reg = 0xe8,
- .pll_table = tegra_pll_e_table,
+ .max_rate = 100000000,
+ .u.pll = {
+ .input_min = 12000000,
+ .input_max = 12000000,
+ .freq_table = tegra_pll_e_freq_table,
+ },
};
static struct clk tegra_clk_d = {
.name = "clk_d",
.flags = PERIPH_NO_RESET,
.ops = &tegra_clk_double_ops,
- .clk_num = 90,
.reg = 0x34,
.reg_shift = 12,
.parent = &tegra_clk_m,
.max_rate = 52000000,
+ .u.periph = {
+ .clk_num = 90,
+ },
+};
+
+/* dap_mclk1, belongs to the cdev1 pingroup. */
+static struct clk tegra_clk_cdev1 = {
+ .name = "cdev1",
+ .ops = &tegra_cdev_clk_ops,
+ .rate = 26000000,
+ .max_rate = 26000000,
+ .u.periph = {
+ .clk_num = 94,
+ },
+};
+
+/* dap_mclk2, belongs to the cdev2 pingroup. */
+static struct clk tegra_clk_cdev2 = {
+ .name = "cdev2",
+ .ops = &tegra_cdev_clk_ops,
+ .rate = 26000000,
+ .max_rate = 26000000,
+ .u.periph = {
+ .clk_num = 93,
+ },
};
/* initialized before peripheral clocks */
@@ -1394,7 +1868,7 @@ static struct clk tegra_clk_audio = {
.name = "audio",
.inputs = mux_audio_sync_clk,
.reg = 0x38,
- .max_rate = 24000000,
+ .max_rate = 73728000,
.ops = &tegra_audio_sync_clk_ops
};
@@ -1403,10 +1877,12 @@ static struct clk tegra_clk_audio_2x = {
.flags = PERIPH_NO_RESET,
.max_rate = 48000000,
.ops = &tegra_clk_double_ops,
- .clk_num = 89,
.reg = 0x34,
.reg_shift = 8,
.parent = &tegra_clk_audio,
+ .u.periph = {
+ .clk_num = 89,
+ },
};
struct clk_lookup tegra_audio_clk_lookups[] = {
@@ -1478,17 +1954,26 @@ static struct clk tegra_clk_sclk = {
.inputs = mux_sclk,
.reg = 0x28,
.ops = &tegra_super_ops,
- .max_rate = 600000000,
+ .max_rate = 240000000,
+ .min_rate = 120000000,
};
static struct clk tegra_clk_virtual_cpu = {
.name = "cpu",
.parent = &tegra_clk_cclk,
- .main = &tegra_pll_x,
- .backup = &tegra_clk_m,
.ops = &tegra_cpu_ops,
.max_rate = 1000000000,
- .dvfs = &tegra_dvfs_virtual_cpu_dvfs,
+ .u.cpu = {
+ .main = &tegra_pll_x,
+ .backup = &tegra_pll_p,
+ },
+};
+
+static struct clk tegra_clk_cop = {
+ .name = "cop",
+ .parent = &tegra_clk_sclk,
+ .ops = &tegra_cop_ops,
+ .max_rate = 240000000,
};
static struct clk tegra_clk_hclk = {
@@ -1508,7 +1993,15 @@ static struct clk tegra_clk_pclk = {
.reg = 0x30,
.reg_shift = 0,
.ops = &tegra_bus_ops,
- .max_rate = 108000000,
+ .max_rate = 120000000,
+};
+
+static struct clk tegra_clk_blink = {
+ .name = "blink",
+ .parent = &tegra_clk_32k,
+ .reg = 0x40,
+ .ops = &tegra_blink_clk_ops,
+ .max_rate = 32768,
};
static struct clk_mux_sel mux_pllm_pllc_pllp_plla[] = {
@@ -1587,6 +2080,23 @@ static struct clk_mux_sel mux_clk_32k[] = {
{ 0, 0},
};
+static struct clk_mux_sel mux_pclk[] = {
+ { .input = &tegra_clk_pclk, .value = 0},
+ { 0, 0},
+};
+
+static struct clk tegra_clk_emc = {
+ .name = "emc",
+ .ops = &tegra_emc_clk_ops,
+ .reg = 0x19c,
+ .max_rate = 800000000,
+ .inputs = mux_pllm_pllc_pllp_clkm,
+ .flags = MUX | DIV_U71 | PERIPH_EMC_ENB,
+ .u.periph = {
+ .clk_num = 57,
+ },
+};
+
#define PERIPH_CLK(_name, _dev, _con, _clk_num, _reg, _max, _inputs, _flags) \
{ \
.name = _name, \
@@ -1595,19 +2105,32 @@ static struct clk_mux_sel mux_clk_32k[] = {
.con_id = _con, \
}, \
.ops = &tegra_periph_clk_ops, \
- .clk_num = _clk_num, \
.reg = _reg, \
.inputs = _inputs, \
.flags = _flags, \
.max_rate = _max, \
+ .u.periph = { \
+ .clk_num = _clk_num, \
+ }, \
+ }
+
+#define SHARED_CLK(_name, _dev, _con, _parent) \
+ { \
+ .name = _name, \
+ .lookup = { \
+ .dev_id = _dev, \
+ .con_id = _con, \
+ }, \
+ .ops = &tegra_clk_shared_bus_ops, \
+ .parent = _parent, \
}
-struct clk tegra_periph_clks[] = {
+struct clk tegra_list_clks[] = {
+ PERIPH_CLK("apbdma", "tegra-dma", NULL, 34, 0, 108000000, mux_pclk, 0),
PERIPH_CLK("rtc", "rtc-tegra", NULL, 4, 0, 32768, mux_clk_32k, PERIPH_NO_RESET),
PERIPH_CLK("timer", "timer", NULL, 5, 0, 26000000, mux_clk_m, 0),
- PERIPH_CLK("i2s1", "i2s.0", NULL, 11, 0x100, 26000000, mux_pllaout0_audio2x_pllp_clkm, MUX | DIV_U71),
- PERIPH_CLK("i2s2", "i2s.1", NULL, 18, 0x104, 26000000, mux_pllaout0_audio2x_pllp_clkm, MUX | DIV_U71),
- /* FIXME: spdif has 2 clocks but 1 enable */
+ PERIPH_CLK("i2s1", "tegra-i2s.0", NULL, 11, 0x100, 26000000, mux_pllaout0_audio2x_pllp_clkm, MUX | DIV_U71),
+ PERIPH_CLK("i2s2", "tegra-i2s.1", NULL, 18, 0x104, 26000000, mux_pllaout0_audio2x_pllp_clkm, MUX | DIV_U71),
PERIPH_CLK("spdif_out", "spdif_out", NULL, 10, 0x108, 100000000, mux_pllaout0_audio2x_pllp_clkm, MUX | DIV_U71),
PERIPH_CLK("spdif_in", "spdif_in", NULL, 10, 0x10c, 100000000, mux_pllp_pllc_pllm, MUX | DIV_U71),
PERIPH_CLK("pwm", "pwm", NULL, 17, 0x110, 432000000, mux_pllp_pllc_audio_clkm_clk32, MUX | DIV_U71),
@@ -1620,13 +2143,15 @@ struct clk tegra_periph_clks[] = {
PERIPH_CLK("sbc4", "spi_tegra.3", NULL, 68, 0x1b4, 160000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71),
PERIPH_CLK("ide", "ide", NULL, 25, 0x144, 100000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71), /* requires min voltage */
PERIPH_CLK("ndflash", "tegra_nand", NULL, 13, 0x160, 164000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71), /* scales with voltage */
- /* FIXME: vfir shares an enable with uartb */
PERIPH_CLK("vfir", "vfir", NULL, 7, 0x168, 72000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71),
PERIPH_CLK("sdmmc1", "sdhci-tegra.0", NULL, 14, 0x150, 52000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71), /* scales with voltage */
PERIPH_CLK("sdmmc2", "sdhci-tegra.1", NULL, 9, 0x154, 52000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71), /* scales with voltage */
PERIPH_CLK("sdmmc3", "sdhci-tegra.2", NULL, 69, 0x1bc, 52000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71), /* scales with voltage */
- PERIPH_CLK("sdmmc4", "sdhci-tegra.3", NULL, 15, 0x160, 52000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71), /* scales with voltage */
- PERIPH_CLK("vde", "vde", NULL, 61, 0x1c8, 250000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71), /* scales with voltage and process_id */
+ PERIPH_CLK("sdmmc4", "sdhci-tegra.3", NULL, 15, 0x164, 52000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71), /* scales with voltage */
+ PERIPH_CLK("vcp", "tegra-avp", "vcp", 29, 0, 250000000, mux_clk_m, 0),
+ PERIPH_CLK("bsea", "tegra-avp", "bsea", 62, 0, 250000000, mux_clk_m, 0),
+ PERIPH_CLK("bsev", "tegra-aes", "bsev", 63, 0, 250000000, mux_clk_m, 0),
+ PERIPH_CLK("vde", "tegra-avp", "vde", 61, 0x1c8, 250000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71), /* scales with voltage and process_id */
PERIPH_CLK("csite", "csite", NULL, 73, 0x1d4, 144000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71), /* max rate ??? */
/* FIXME: what is la? */
PERIPH_CLK("la", "la", NULL, 76, 0x1f8, 26000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71),
@@ -1641,37 +2166,46 @@ struct clk tegra_periph_clks[] = {
PERIPH_CLK("i2c2_i2c", "tegra-i2c.1", "i2c", 0, 0, 72000000, mux_pllp_out3, 0),
PERIPH_CLK("i2c3_i2c", "tegra-i2c.2", "i2c", 0, 0, 72000000, mux_pllp_out3, 0),
PERIPH_CLK("dvc_i2c", "tegra-i2c.3", "i2c", 0, 0, 72000000, mux_pllp_out3, 0),
- PERIPH_CLK("uarta", "uart.0", NULL, 6, 0x178, 216000000, mux_pllp_pllc_pllm_clkm, MUX),
- PERIPH_CLK("uartb", "uart.1", NULL, 7, 0x17c, 216000000, mux_pllp_pllc_pllm_clkm, MUX),
- PERIPH_CLK("uartc", "uart.2", NULL, 55, 0x1a0, 216000000, mux_pllp_pllc_pllm_clkm, MUX),
- PERIPH_CLK("uartd", "uart.3", NULL, 65, 0x1c0, 216000000, mux_pllp_pllc_pllm_clkm, MUX),
- PERIPH_CLK("uarte", "uart.4", NULL, 66, 0x1c4, 216000000, mux_pllp_pllc_pllm_clkm, MUX),
+ PERIPH_CLK("uarta", "uart.0", NULL, 6, 0x178, 600000000, mux_pllp_pllc_pllm_clkm, MUX),
+ PERIPH_CLK("uartb", "uart.1", NULL, 7, 0x17c, 600000000, mux_pllp_pllc_pllm_clkm, MUX),
+ PERIPH_CLK("uartc", "uart.2", NULL, 55, 0x1a0, 600000000, mux_pllp_pllc_pllm_clkm, MUX),
+ PERIPH_CLK("uartd", "uart.3", NULL, 65, 0x1c0, 600000000, mux_pllp_pllc_pllm_clkm, MUX),
+ PERIPH_CLK("uarte", "uart.4", NULL, 66, 0x1c4, 600000000, mux_pllp_pllc_pllm_clkm, MUX),
PERIPH_CLK("3d", "3d", NULL, 24, 0x158, 300000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71 | PERIPH_MANUAL_RESET), /* scales with voltage and process_id */
PERIPH_CLK("2d", "2d", NULL, 21, 0x15c, 300000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71), /* scales with voltage and process_id */
- /* FIXME: vi and vi_sensor share an enable */
- PERIPH_CLK("vi", "vi", NULL, 20, 0x148, 150000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71), /* scales with voltage and process_id */
- PERIPH_CLK("vi_sensor", "vi_sensor", NULL, 20, 0x1a8, 150000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71 | PERIPH_NO_RESET), /* scales with voltage and process_id */
+ PERIPH_CLK("vi", "tegra_camera", "vi", 20, 0x148, 150000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71), /* scales with voltage and process_id */
+ PERIPH_CLK("vi_sensor", "tegra_camera", "vi_sensor", 20, 0x1a8, 150000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71 | PERIPH_NO_RESET), /* scales with voltage and process_id */
PERIPH_CLK("epp", "epp", NULL, 19, 0x16c, 300000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71), /* scales with voltage and process_id */
PERIPH_CLK("mpe", "mpe", NULL, 60, 0x170, 250000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71), /* scales with voltage and process_id */
PERIPH_CLK("host1x", "host1x", NULL, 28, 0x180, 166000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71), /* scales with voltage and process_id */
- /* FIXME: cve and tvo share an enable */
PERIPH_CLK("cve", "cve", NULL, 49, 0x140, 250000000, mux_pllp_plld_pllc_clkm, MUX | DIV_U71), /* requires min voltage */
PERIPH_CLK("tvo", "tvo", NULL, 49, 0x188, 250000000, mux_pllp_plld_pllc_clkm, MUX | DIV_U71), /* requires min voltage */
- PERIPH_CLK("hdmi", "hdmi", NULL, 51, 0x18c, 148500000, mux_pllp_plld_pllc_clkm, MUX | DIV_U71), /* requires min voltage */
+ PERIPH_CLK("hdmi", "hdmi", NULL, 51, 0x18c, 600000000, mux_pllp_plld_pllc_clkm, MUX | DIV_U71), /* requires min voltage */
PERIPH_CLK("tvdac", "tvdac", NULL, 53, 0x194, 250000000, mux_pllp_plld_pllc_clkm, MUX | DIV_U71), /* requires min voltage */
- PERIPH_CLK("disp1", "tegrafb.0", NULL, 27, 0x138, 190000000, mux_pllp_plld_pllc_clkm, MUX | DIV_U71), /* scales with voltage and process_id */
- PERIPH_CLK("disp2", "tegrafb.1", NULL, 26, 0x13c, 190000000, mux_pllp_plld_pllc_clkm, MUX | DIV_U71), /* scales with voltage and process_id */
+ PERIPH_CLK("disp1", "tegradc.0", NULL, 27, 0x138, 600000000, mux_pllp_plld_pllc_clkm, MUX | DIV_U71), /* scales with voltage and process_id */
+ PERIPH_CLK("disp2", "tegradc.1", NULL, 26, 0x13c, 600000000, mux_pllp_plld_pllc_clkm, MUX | DIV_U71), /* scales with voltage and process_id */
PERIPH_CLK("usbd", "fsl-tegra-udc", NULL, 22, 0, 480000000, mux_clk_m, 0), /* requires min voltage */
PERIPH_CLK("usb2", "tegra-ehci.1", NULL, 58, 0, 480000000, mux_clk_m, 0), /* requires min voltage */
PERIPH_CLK("usb3", "tegra-ehci.2", NULL, 59, 0, 480000000, mux_clk_m, 0), /* requires min voltage */
- PERIPH_CLK("emc", "emc", NULL, 57, 0x19c, 800000000, mux_pllm_pllc_pllp_clkm, MUX | DIV_U71 | PERIPH_EMC_ENB),
PERIPH_CLK("dsi", "dsi", NULL, 48, 0, 500000000, mux_plld, 0), /* scales with voltage */
- PERIPH_CLK("csi", "csi", NULL, 52, 0, 72000000, mux_pllp_out3, 0),
- PERIPH_CLK("isp", "isp", NULL, 23, 0, 150000000, mux_clk_m, 0), /* same frequency as VI */
- PERIPH_CLK("csus", "csus", NULL, 92, 0, 150000000, mux_clk_m, PERIPH_NO_RESET),
+ PERIPH_CLK("csi", "tegra_camera", "csi", 52, 0, 72000000, mux_pllp_out3, 0),
+ PERIPH_CLK("isp", "tegra_camera", "isp", 23, 0, 150000000, mux_clk_m, 0), /* same frequency as VI */
+ PERIPH_CLK("csus", "tegra_camera", "csus", 92, 0, 150000000, mux_clk_m, PERIPH_NO_RESET),
PERIPH_CLK("pex", NULL, "pex", 70, 0, 26000000, mux_clk_m, PERIPH_MANUAL_RESET),
PERIPH_CLK("afi", NULL, "afi", 72, 0, 26000000, mux_clk_m, PERIPH_MANUAL_RESET),
PERIPH_CLK("pcie_xclk", NULL, "pcie_xclk", 74, 0, 26000000, mux_clk_m, PERIPH_MANUAL_RESET),
+
+ SHARED_CLK("avp.sclk", "tegra-avp", "sclk", &tegra_clk_sclk),
+ SHARED_CLK("avp.emc", "tegra-avp", "emc", &tegra_clk_emc),
+ SHARED_CLK("cpu.emc", "cpu", "emc", &tegra_clk_emc),
+ SHARED_CLK("disp1.emc", "tegradc.0", "emc", &tegra_clk_emc),
+ SHARED_CLK("disp2.emc", "tegradc.1", "emc", &tegra_clk_emc),
+ SHARED_CLK("hdmi.emc", "hdmi", "emc", &tegra_clk_emc),
+ SHARED_CLK("host.emc", "tegra_grhost", "emc", &tegra_clk_emc),
+ SHARED_CLK("usbd.emc", "fsl-tegra-udc", "emc", &tegra_clk_emc),
+ SHARED_CLK("usb1.emc", "tegra-ehci.0", "emc", &tegra_clk_emc),
+ SHARED_CLK("usb2.emc", "tegra-ehci.1", "emc", &tegra_clk_emc),
+ SHARED_CLK("usb3.emc", "tegra-ehci.2", "emc", &tegra_clk_emc),
};
#define CLK_DUPLICATE(_name, _dev, _con) \
@@ -1693,9 +2227,22 @@ struct clk_duplicate tegra_clk_duplicates[] = {
CLK_DUPLICATE("uartc", "tegra_uart.2", NULL),
CLK_DUPLICATE("uartd", "tegra_uart.3", NULL),
CLK_DUPLICATE("uarte", "tegra_uart.4", NULL),
- CLK_DUPLICATE("host1x", "tegrafb.0", "host1x"),
- CLK_DUPLICATE("host1x", "tegrafb.1", "host1x"),
+ CLK_DUPLICATE("usbd", "utmip-pad", NULL),
CLK_DUPLICATE("usbd", "tegra-ehci.0", NULL),
+ CLK_DUPLICATE("usbd", "tegra-otg", NULL),
+ CLK_DUPLICATE("hdmi", "tegradc.0", "hdmi"),
+ CLK_DUPLICATE("hdmi", "tegradc.1", "hdmi"),
+ CLK_DUPLICATE("pwm", "tegra_pwm.0", NULL),
+ CLK_DUPLICATE("pwm", "tegra_pwm.1", NULL),
+ CLK_DUPLICATE("pwm", "tegra_pwm.2", NULL),
+ CLK_DUPLICATE("pwm", "tegra_pwm.3", NULL),
+ CLK_DUPLICATE("host1x", "tegra_grhost", "host1x"),
+ CLK_DUPLICATE("2d", "tegra_grhost", "gr2d"),
+ CLK_DUPLICATE("3d", "tegra_grhost", "gr3d"),
+ CLK_DUPLICATE("epp", "tegra_grhost", "epp"),
+ CLK_DUPLICATE("mpe", "tegra_grhost", "mpe"),
+ CLK_DUPLICATE("cop", "tegra-avp", "cop"),
+ CLK_DUPLICATE("vde", "tegra-aes", "vde"),
};
#define CLK(dev, con, ck) \
@@ -1705,68 +2252,70 @@ struct clk_duplicate tegra_clk_duplicates[] = {
.clk = ck, \
}
-struct clk_lookup tegra_clk_lookups[] = {
- /* external root sources */
- CLK(NULL, "32k_clk", &tegra_clk_32k),
- CLK(NULL, "pll_s", &tegra_pll_s),
- CLK(NULL, "clk_m", &tegra_clk_m),
- CLK(NULL, "pll_m", &tegra_pll_m),
- CLK(NULL, "pll_m_out1", &tegra_pll_m_out1),
- CLK(NULL, "pll_c", &tegra_pll_c),
- CLK(NULL, "pll_c_out1", &tegra_pll_c_out1),
- CLK(NULL, "pll_p", &tegra_pll_p),
- CLK(NULL, "pll_p_out1", &tegra_pll_p_out1),
- CLK(NULL, "pll_p_out2", &tegra_pll_p_out2),
- CLK(NULL, "pll_p_out3", &tegra_pll_p_out3),
- CLK(NULL, "pll_p_out4", &tegra_pll_p_out4),
- CLK(NULL, "pll_a", &tegra_pll_a),
- CLK(NULL, "pll_a_out0", &tegra_pll_a_out0),
- CLK(NULL, "pll_d", &tegra_pll_d),
- CLK(NULL, "pll_d_out0", &tegra_pll_d_out0),
- CLK(NULL, "pll_u", &tegra_pll_u),
- CLK(NULL, "pll_x", &tegra_pll_x),
- CLK(NULL, "pll_e", &tegra_pll_e),
- CLK(NULL, "cclk", &tegra_clk_cclk),
- CLK(NULL, "sclk", &tegra_clk_sclk),
- CLK(NULL, "hclk", &tegra_clk_hclk),
- CLK(NULL, "pclk", &tegra_clk_pclk),
- CLK(NULL, "clk_d", &tegra_clk_d),
- CLK(NULL, "cpu", &tegra_clk_virtual_cpu),
-};
+struct clk *tegra_ptr_clks[] = {
+ &tegra_clk_32k,
+ &tegra_pll_s,
+ &tegra_clk_m,
+ &tegra_pll_m,
+ &tegra_pll_m_out1,
+ &tegra_pll_c,
+ &tegra_pll_c_out1,
+ &tegra_pll_p,
+ &tegra_pll_p_out1,
+ &tegra_pll_p_out2,
+ &tegra_pll_p_out3,
+ &tegra_pll_p_out4,
+ &tegra_pll_a,
+ &tegra_pll_a_out0,
+ &tegra_pll_d,
+ &tegra_pll_d_out0,
+ &tegra_pll_u,
+ &tegra_pll_x,
+ &tegra_pll_e,
+ &tegra_clk_cclk,
+ &tegra_clk_sclk,
+ &tegra_clk_hclk,
+ &tegra_clk_pclk,
+ &tegra_clk_d,
+ &tegra_clk_cdev1,
+ &tegra_clk_cdev2,
+ &tegra_clk_virtual_cpu,
+ &tegra_clk_blink,
+ &tegra_clk_cop,
+ &tegra_clk_emc,
+};
+
+static void tegra2_init_one_clock(struct clk *c)
+{
+ clk_init(c);
+ INIT_LIST_HEAD(&c->shared_bus_list);
+ if (!c->lookup.dev_id && !c->lookup.con_id)
+ c->lookup.con_id = c->name;
+ c->lookup.clk = c;
+ clkdev_add(&c->lookup);
+}
void __init tegra2_init_clocks(void)
{
int i;
- struct clk_lookup *cl;
struct clk *c;
- struct clk_duplicate *cd;
-
- for (i = 0; i < ARRAY_SIZE(tegra_clk_lookups); i++) {
- cl = &tegra_clk_lookups[i];
- clk_init(cl->clk);
- clkdev_add(cl);
- }
- for (i = 0; i < ARRAY_SIZE(tegra_periph_clks); i++) {
- c = &tegra_periph_clks[i];
- cl = &c->lookup;
- cl->clk = c;
+ for (i = 0; i < ARRAY_SIZE(tegra_ptr_clks); i++)
+ tegra2_init_one_clock(tegra_ptr_clks[i]);
- clk_init(cl->clk);
- clkdev_add(cl);
- }
+ for (i = 0; i < ARRAY_SIZE(tegra_list_clks); i++)
+ tegra2_init_one_clock(&tegra_list_clks[i]);
for (i = 0; i < ARRAY_SIZE(tegra_clk_duplicates); i++) {
- cd = &tegra_clk_duplicates[i];
- c = tegra_get_clock_by_name(cd->name);
- if (c) {
- cl = &cd->lookup;
- cl->clk = c;
- clkdev_add(cl);
- } else {
+ c = tegra_get_clock_by_name(tegra_clk_duplicates[i].name);
+ if (!c) {
pr_err("%s: Unknown duplicate clock %s\n", __func__,
- cd->name);
+ tegra_clk_duplicates[i].name);
+ continue;
}
+
+ tegra_clk_duplicates[i].lookup.clk = c;
+ clkdev_add(&tegra_clk_duplicates[i].lookup);
}
init_audio_sync_clock_mux();
@@ -1774,7 +2323,7 @@ void __init tegra2_init_clocks(void)
#ifdef CONFIG_PM
static u32 clk_rst_suspend[RST_DEVICES_NUM + CLK_OUT_ENB_NUM +
- PERIPH_CLK_SOURCE_NUM + 3];
+ PERIPH_CLK_SOURCE_NUM + 22];
void tegra_clk_suspend(void)
{
@@ -1782,6 +2331,29 @@ void tegra_clk_suspend(void)
u32 *ctx = clk_rst_suspend;
*ctx++ = clk_readl(OSC_CTRL) & OSC_CTRL_MASK;
+ *ctx++ = clk_readl(tegra_pll_c.reg + PLL_BASE);
+ *ctx++ = clk_readl(tegra_pll_c.reg + PLL_MISC(&tegra_pll_c));
+ *ctx++ = clk_readl(tegra_pll_a.reg + PLL_BASE);
+ *ctx++ = clk_readl(tegra_pll_a.reg + PLL_MISC(&tegra_pll_a));
+ *ctx++ = clk_readl(tegra_pll_s.reg + PLL_BASE);
+ *ctx++ = clk_readl(tegra_pll_s.reg + PLL_MISC(&tegra_pll_s));
+ *ctx++ = clk_readl(tegra_pll_d.reg + PLL_BASE);
+ *ctx++ = clk_readl(tegra_pll_d.reg + PLL_MISC(&tegra_pll_d));
+ *ctx++ = clk_readl(tegra_pll_u.reg + PLL_BASE);
+ *ctx++ = clk_readl(tegra_pll_u.reg + PLL_MISC(&tegra_pll_u));
+
+ *ctx++ = clk_readl(tegra_pll_m_out1.reg);
+ *ctx++ = clk_readl(tegra_pll_a_out0.reg);
+ *ctx++ = clk_readl(tegra_pll_c_out1.reg);
+
+ *ctx++ = clk_readl(tegra_clk_cclk.reg);
+ *ctx++ = clk_readl(tegra_clk_cclk.reg + SUPER_CLK_DIVIDER);
+
+ *ctx++ = clk_readl(tegra_clk_sclk.reg);
+ *ctx++ = clk_readl(tegra_clk_sclk.reg + SUPER_CLK_DIVIDER);
+ *ctx++ = clk_readl(tegra_clk_pclk.reg);
+
+ *ctx++ = clk_readl(tegra_clk_audio.reg);
for (off = PERIPH_CLK_SOURCE_I2S1; off <= PERIPH_CLK_SOURCE_OSC;
off += 4) {
@@ -1800,6 +2372,8 @@ void tegra_clk_suspend(void)
*ctx++ = clk_readl(MISC_CLK_ENB);
*ctx++ = clk_readl(CLK_MASK_ARM);
+
+ BUG_ON(ctx - clk_rst_suspend != ARRAY_SIZE(clk_rst_suspend));
}
void tegra_clk_resume(void)
@@ -1812,6 +2386,31 @@ void tegra_clk_resume(void)
val |= *ctx++;
clk_writel(val, OSC_CTRL);
+ clk_writel(*ctx++, tegra_pll_c.reg + PLL_BASE);
+ clk_writel(*ctx++, tegra_pll_c.reg + PLL_MISC(&tegra_pll_c));
+ clk_writel(*ctx++, tegra_pll_a.reg + PLL_BASE);
+ clk_writel(*ctx++, tegra_pll_a.reg + PLL_MISC(&tegra_pll_a));
+ clk_writel(*ctx++, tegra_pll_s.reg + PLL_BASE);
+ clk_writel(*ctx++, tegra_pll_s.reg + PLL_MISC(&tegra_pll_s));
+ clk_writel(*ctx++, tegra_pll_d.reg + PLL_BASE);
+ clk_writel(*ctx++, tegra_pll_d.reg + PLL_MISC(&tegra_pll_d));
+ clk_writel(*ctx++, tegra_pll_u.reg + PLL_BASE);
+ clk_writel(*ctx++, tegra_pll_u.reg + PLL_MISC(&tegra_pll_u));
+ udelay(1000);
+
+ clk_writel(*ctx++, tegra_pll_m_out1.reg);
+ clk_writel(*ctx++, tegra_pll_a_out0.reg);
+ clk_writel(*ctx++, tegra_pll_c_out1.reg);
+
+ clk_writel(*ctx++, tegra_clk_cclk.reg);
+ clk_writel(*ctx++, tegra_clk_cclk.reg + SUPER_CLK_DIVIDER);
+
+ clk_writel(*ctx++, tegra_clk_sclk.reg);
+ clk_writel(*ctx++, tegra_clk_sclk.reg + SUPER_CLK_DIVIDER);
+ clk_writel(*ctx++, tegra_clk_pclk.reg);
+
+ clk_writel(*ctx++, tegra_clk_audio.reg);
+
/* enable all clocks before configuring clock sources */
clk_writel(0xbffffff9ul, CLK_OUT_ENB);
clk_writel(0xfefffff7ul, CLK_OUT_ENB + 4);
diff --git a/arch/arm/mach-tegra/tegra2_dvfs.c b/arch/arm/mach-tegra/tegra2_dvfs.c
deleted file mode 100644
index 5529c238dd77..000000000000
--- a/arch/arm/mach-tegra/tegra2_dvfs.c
+++ /dev/null
@@ -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,
-};
diff --git a/arch/arm/mach-tegra/tegra2_emc.c b/arch/arm/mach-tegra/tegra2_emc.c
new file mode 100644
index 000000000000..0f7ae6e90b55
--- /dev/null
+++ b/arch/arm/mach-tegra/tegra2_emc.c
@@ -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;
+}
diff --git a/arch/arm/mach-tegra/tegra2_emc.h b/arch/arm/mach-tegra/tegra2_emc.h
new file mode 100644
index 000000000000..19f08cb31603
--- /dev/null
+++ b/arch/arm/mach-tegra/tegra2_emc.h
@@ -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);
diff --git a/arch/arm/mach-tegra/timer.c b/arch/arm/mach-tegra/timer.c
index 7b8ad1f98f44..90350420c4e9 100644
--- a/arch/arm/mach-tegra/timer.c
+++ b/arch/arm/mach-tegra/timer.c
@@ -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))
@@ -90,11 +98,6 @@ static void tegra_timer_set_mode(enum clock_event_mode mode,
}
}
-static cycle_t tegra_clocksource_read(struct clocksource *cs)
-{
- return timer_readl(TIMERUS_CNTR_1US);
-}
-
static struct clock_event_device tegra_clockevent = {
.name = "timer0",
.rating = 300,
@@ -103,14 +106,6 @@ static struct clock_event_device tegra_clockevent = {
.set_mode = tegra_timer_set_mode,
};
-static struct clocksource tegra_clocksource = {
- .name = "timer_us",
- .rating = 300,
- .read = tegra_clocksource_read,
- .mask = CLOCKSOURCE_MASK(32),
- .flags = CLOCK_SOURCE_IS_CONTINUOUS,
-};
-
static DEFINE_CLOCK_DATA(cd);
/*
@@ -132,6 +127,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 +181,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
@@ -177,7 +221,8 @@ static void __init tegra_init_timer(void)
init_fixed_sched_clock(&cd, tegra_update_sched_clock, 32,
1000000, SC_MULT, SC_SHIFT);
- if (clocksource_register_hz(&tegra_clocksource, 1000000)) {
+ if (clocksource_mmio_init(timer_reg_base + TIMERUS_CNTR_1US,
+ "timer_us", 1000000, 300, 32, clocksource_mmio_readl_up)) {
printk(KERN_ERR "Failed to register clocksource\n");
BUG();
}
@@ -196,10 +241,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
diff --git a/arch/arm/mach-tegra/usb_phy.c b/arch/arm/mach-tegra/usb_phy.c
new file mode 100644
index 000000000000..88081bb3ec52
--- /dev/null
+++ b/arch/arm/mach-tegra/usb_phy.c
@@ -0,0 +1,795 @@
+/*
+ * arch/arm/mach-tegra/usb_phy.c
+ *
+ * Copyright (C) 2010 Google, Inc.
+ *
+ * Author:
+ * Erik Gilling <konkers@google.com>
+ * Benoit Goby <benoit@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/delay.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/gpio.h>
+#include <linux/usb/otg.h>
+#include <linux/usb/ulpi.h>
+#include <asm/mach-types.h>
+#include <mach/usb_phy.h>
+#include <mach/iomap.h>
+
+#define ULPI_VIEWPORT 0x170
+
+#define USB_PORTSC1 0x184
+#define USB_PORTSC1_PTS(x) (((x) & 0x3) << 30)
+#define USB_PORTSC1_PSPD(x) (((x) & 0x3) << 26)
+#define USB_PORTSC1_PHCD (1 << 23)
+#define USB_PORTSC1_WKOC (1 << 22)
+#define USB_PORTSC1_WKDS (1 << 21)
+#define USB_PORTSC1_WKCN (1 << 20)
+#define USB_PORTSC1_PTC(x) (((x) & 0xf) << 16)
+#define USB_PORTSC1_PP (1 << 12)
+#define USB_PORTSC1_SUSP (1 << 7)
+#define USB_PORTSC1_PE (1 << 2)
+#define USB_PORTSC1_CCS (1 << 0)
+
+#define USB_SUSP_CTRL 0x400
+#define USB_WAKE_ON_CNNT_EN_DEV (1 << 3)
+#define USB_WAKE_ON_DISCON_EN_DEV (1 << 4)
+#define USB_SUSP_CLR (1 << 5)
+#define USB_PHY_CLK_VALID (1 << 7)
+#define UTMIP_RESET (1 << 11)
+#define UHSIC_RESET (1 << 11)
+#define UTMIP_PHY_ENABLE (1 << 12)
+#define ULPI_PHY_ENABLE (1 << 13)
+#define USB_SUSP_SET (1 << 14)
+#define USB_WAKEUP_DEBOUNCE_COUNT(x) (((x) & 0x7) << 16)
+
+#define USB1_LEGACY_CTRL 0x410
+#define USB1_NO_LEGACY_MODE (1 << 0)
+#define USB1_VBUS_SENSE_CTL_MASK (3 << 1)
+#define USB1_VBUS_SENSE_CTL_VBUS_WAKEUP (0 << 1)
+#define USB1_VBUS_SENSE_CTL_AB_SESS_VLD_OR_VBUS_WAKEUP \
+ (1 << 1)
+#define USB1_VBUS_SENSE_CTL_AB_SESS_VLD (2 << 1)
+#define USB1_VBUS_SENSE_CTL_A_SESS_VLD (3 << 1)
+
+#define ULPI_TIMING_CTRL_0 0x424
+#define ULPI_OUTPUT_PINMUX_BYP (1 << 10)
+#define ULPI_CLKOUT_PINMUX_BYP (1 << 11)
+
+#define ULPI_TIMING_CTRL_1 0x428
+#define ULPI_DATA_TRIMMER_LOAD (1 << 0)
+#define ULPI_DATA_TRIMMER_SEL(x) (((x) & 0x7) << 1)
+#define ULPI_STPDIRNXT_TRIMMER_LOAD (1 << 16)
+#define ULPI_STPDIRNXT_TRIMMER_SEL(x) (((x) & 0x7) << 17)
+#define ULPI_DIR_TRIMMER_LOAD (1 << 24)
+#define ULPI_DIR_TRIMMER_SEL(x) (((x) & 0x7) << 25)
+
+#define UTMIP_PLL_CFG1 0x804
+#define UTMIP_XTAL_FREQ_COUNT(x) (((x) & 0xfff) << 0)
+#define UTMIP_PLLU_ENABLE_DLY_COUNT(x) (((x) & 0x1f) << 27)
+
+#define UTMIP_XCVR_CFG0 0x808
+#define UTMIP_XCVR_SETUP(x) (((x) & 0xf) << 0)
+#define UTMIP_XCVR_LSRSLEW(x) (((x) & 0x3) << 8)
+#define UTMIP_XCVR_LSFSLEW(x) (((x) & 0x3) << 10)
+#define UTMIP_FORCE_PD_POWERDOWN (1 << 14)
+#define UTMIP_FORCE_PD2_POWERDOWN (1 << 16)
+#define UTMIP_FORCE_PDZI_POWERDOWN (1 << 18)
+#define UTMIP_XCVR_HSSLEW_MSB(x) (((x) & 0x7f) << 25)
+
+#define UTMIP_BIAS_CFG0 0x80c
+#define UTMIP_OTGPD (1 << 11)
+#define UTMIP_BIASPD (1 << 10)
+
+#define UTMIP_HSRX_CFG0 0x810
+#define UTMIP_ELASTIC_LIMIT(x) (((x) & 0x1f) << 10)
+#define UTMIP_IDLE_WAIT(x) (((x) & 0x1f) << 15)
+
+#define UTMIP_HSRX_CFG1 0x814
+#define UTMIP_HS_SYNC_START_DLY(x) (((x) & 0x1f) << 1)
+
+#define UTMIP_TX_CFG0 0x820
+#define UTMIP_FS_PREABMLE_J (1 << 19)
+#define UTMIP_HS_DISCON_DISABLE (1 << 8)
+
+#define UTMIP_MISC_CFG0 0x824
+#define UTMIP_DPDM_OBSERVE (1 << 26)
+#define UTMIP_DPDM_OBSERVE_SEL(x) (((x) & 0xf) << 27)
+#define UTMIP_DPDM_OBSERVE_SEL_FS_J UTMIP_DPDM_OBSERVE_SEL(0xf)
+#define UTMIP_DPDM_OBSERVE_SEL_FS_K UTMIP_DPDM_OBSERVE_SEL(0xe)
+#define UTMIP_DPDM_OBSERVE_SEL_FS_SE1 UTMIP_DPDM_OBSERVE_SEL(0xd)
+#define UTMIP_DPDM_OBSERVE_SEL_FS_SE0 UTMIP_DPDM_OBSERVE_SEL(0xc)
+#define UTMIP_SUSPEND_EXIT_ON_EDGE (1 << 22)
+
+#define UTMIP_MISC_CFG1 0x828
+#define UTMIP_PLL_ACTIVE_DLY_COUNT(x) (((x) & 0x1f) << 18)
+#define UTMIP_PLLU_STABLE_COUNT(x) (((x) & 0xfff) << 6)
+
+#define UTMIP_DEBOUNCE_CFG0 0x82c
+#define UTMIP_BIAS_DEBOUNCE_A(x) (((x) & 0xffff) << 0)
+
+#define UTMIP_BAT_CHRG_CFG0 0x830
+#define UTMIP_PD_CHRG (1 << 0)
+
+#define UTMIP_SPARE_CFG0 0x834
+#define FUSE_SETUP_SEL (1 << 3)
+
+#define UTMIP_XCVR_CFG1 0x838
+#define UTMIP_FORCE_PDDISC_POWERDOWN (1 << 0)
+#define UTMIP_FORCE_PDCHRP_POWERDOWN (1 << 2)
+#define UTMIP_FORCE_PDDR_POWERDOWN (1 << 4)
+#define UTMIP_XCVR_TERM_RANGE_ADJ(x) (((x) & 0xf) << 18)
+
+#define UTMIP_BIAS_CFG1 0x83c
+#define UTMIP_BIAS_PDTRK_COUNT(x) (((x) & 0x1f) << 3)
+
+static DEFINE_SPINLOCK(utmip_pad_lock);
+static int utmip_pad_count;
+
+struct tegra_xtal_freq {
+ int freq;
+ u8 enable_delay;
+ u8 stable_count;
+ u8 active_delay;
+ u8 xtal_freq_count;
+ u16 debounce;
+};
+
+static const struct tegra_xtal_freq tegra_freq_table[] = {
+ {
+ .freq = 12000000,
+ .enable_delay = 0x02,
+ .stable_count = 0x2F,
+ .active_delay = 0x04,
+ .xtal_freq_count = 0x76,
+ .debounce = 0x7530,
+ },
+ {
+ .freq = 13000000,
+ .enable_delay = 0x02,
+ .stable_count = 0x33,
+ .active_delay = 0x05,
+ .xtal_freq_count = 0x7F,
+ .debounce = 0x7EF4,
+ },
+ {
+ .freq = 19200000,
+ .enable_delay = 0x03,
+ .stable_count = 0x4B,
+ .active_delay = 0x06,
+ .xtal_freq_count = 0xBB,
+ .debounce = 0xBB80,
+ },
+ {
+ .freq = 26000000,
+ .enable_delay = 0x04,
+ .stable_count = 0x66,
+ .active_delay = 0x09,
+ .xtal_freq_count = 0xFE,
+ .debounce = 0xFDE8,
+ },
+};
+
+static struct tegra_utmip_config utmip_default[] = {
+ [0] = {
+ .hssync_start_delay = 9,
+ .idle_wait_delay = 17,
+ .elastic_limit = 16,
+ .term_range_adj = 6,
+ .xcvr_setup = 9,
+ .xcvr_lsfslew = 1,
+ .xcvr_lsrslew = 1,
+ },
+ [2] = {
+ .hssync_start_delay = 9,
+ .idle_wait_delay = 17,
+ .elastic_limit = 16,
+ .term_range_adj = 6,
+ .xcvr_setup = 9,
+ .xcvr_lsfslew = 2,
+ .xcvr_lsrslew = 2,
+ },
+};
+
+static inline bool phy_is_ulpi(struct tegra_usb_phy *phy)
+{
+ return (phy->instance == 1);
+}
+
+static int utmip_pad_open(struct tegra_usb_phy *phy)
+{
+ phy->pad_clk = clk_get_sys("utmip-pad", NULL);
+ if (IS_ERR(phy->pad_clk)) {
+ pr_err("%s: can't get utmip pad clock\n", __func__);
+ return PTR_ERR(phy->pad_clk);
+ }
+
+ if (phy->instance == 0) {
+ phy->pad_regs = phy->regs;
+ } else {
+ phy->pad_regs = ioremap(TEGRA_USB_BASE, TEGRA_USB_SIZE);
+ if (!phy->pad_regs) {
+ pr_err("%s: can't remap usb registers\n", __func__);
+ clk_put(phy->pad_clk);
+ return -ENOMEM;
+ }
+ }
+ return 0;
+}
+
+static void utmip_pad_close(struct tegra_usb_phy *phy)
+{
+ if (phy->instance != 0)
+ iounmap(phy->pad_regs);
+ clk_put(phy->pad_clk);
+}
+
+static void utmip_pad_power_on(struct tegra_usb_phy *phy)
+{
+ unsigned long val, flags;
+ void __iomem *base = phy->pad_regs;
+
+ clk_enable(phy->pad_clk);
+
+ spin_lock_irqsave(&utmip_pad_lock, flags);
+
+ if (utmip_pad_count++ == 0) {
+ val = readl(base + UTMIP_BIAS_CFG0);
+ val &= ~(UTMIP_OTGPD | UTMIP_BIASPD);
+ writel(val, base + UTMIP_BIAS_CFG0);
+ }
+
+ spin_unlock_irqrestore(&utmip_pad_lock, flags);
+
+ clk_disable(phy->pad_clk);
+}
+
+static int utmip_pad_power_off(struct tegra_usb_phy *phy)
+{
+ unsigned long val, flags;
+ void __iomem *base = phy->pad_regs;
+
+ if (!utmip_pad_count) {
+ pr_err("%s: utmip pad already powered off\n", __func__);
+ return -EINVAL;
+ }
+
+ clk_enable(phy->pad_clk);
+
+ spin_lock_irqsave(&utmip_pad_lock, flags);
+
+ if (--utmip_pad_count == 0) {
+ val = readl(base + UTMIP_BIAS_CFG0);
+ val |= UTMIP_OTGPD | UTMIP_BIASPD;
+ writel(val, base + UTMIP_BIAS_CFG0);
+ }
+
+ spin_unlock_irqrestore(&utmip_pad_lock, flags);
+
+ clk_disable(phy->pad_clk);
+
+ return 0;
+}
+
+static int utmi_wait_register(void __iomem *reg, u32 mask, u32 result)
+{
+ unsigned long timeout = 2000;
+ do {
+ if ((readl(reg) & mask) == result)
+ return 0;
+ udelay(1);
+ timeout--;
+ } while (timeout);
+ return -1;
+}
+
+static void utmi_phy_clk_disable(struct tegra_usb_phy *phy)
+{
+ unsigned long val;
+ void __iomem *base = phy->regs;
+
+ if (phy->instance == 0) {
+ val = readl(base + USB_SUSP_CTRL);
+ val |= USB_SUSP_SET;
+ writel(val, base + USB_SUSP_CTRL);
+
+ udelay(10);
+
+ val = readl(base + USB_SUSP_CTRL);
+ val &= ~USB_SUSP_SET;
+ writel(val, base + USB_SUSP_CTRL);
+ }
+
+ if (phy->instance == 2) {
+ val = readl(base + USB_PORTSC1);
+ val |= USB_PORTSC1_PHCD;
+ writel(val, base + USB_PORTSC1);
+ }
+
+ if (utmi_wait_register(base + USB_SUSP_CTRL, USB_PHY_CLK_VALID, 0) < 0)
+ pr_err("%s: timeout waiting for phy to stabilize\n", __func__);
+}
+
+static void utmi_phy_clk_enable(struct tegra_usb_phy *phy)
+{
+ unsigned long val;
+ void __iomem *base = phy->regs;
+
+ if (phy->instance == 0) {
+ val = readl(base + USB_SUSP_CTRL);
+ val |= USB_SUSP_CLR;
+ writel(val, base + USB_SUSP_CTRL);
+
+ udelay(10);
+
+ val = readl(base + USB_SUSP_CTRL);
+ val &= ~USB_SUSP_CLR;
+ writel(val, base + USB_SUSP_CTRL);
+ }
+
+ if (phy->instance == 2) {
+ val = readl(base + USB_PORTSC1);
+ val &= ~USB_PORTSC1_PHCD;
+ writel(val, base + USB_PORTSC1);
+ }
+
+ if (utmi_wait_register(base + USB_SUSP_CTRL, USB_PHY_CLK_VALID,
+ USB_PHY_CLK_VALID))
+ pr_err("%s: timeout waiting for phy to stabilize\n", __func__);
+}
+
+static int utmi_phy_power_on(struct tegra_usb_phy *phy)
+{
+ unsigned long val;
+ void __iomem *base = phy->regs;
+ struct tegra_utmip_config *config = phy->config;
+
+ val = readl(base + USB_SUSP_CTRL);
+ val |= UTMIP_RESET;
+ writel(val, base + USB_SUSP_CTRL);
+
+ if (phy->instance == 0) {
+ val = readl(base + USB1_LEGACY_CTRL);
+ val |= USB1_NO_LEGACY_MODE;
+ writel(val, base + USB1_LEGACY_CTRL);
+ }
+
+ val = readl(base + UTMIP_TX_CFG0);
+ val &= ~UTMIP_FS_PREABMLE_J;
+ writel(val, base + UTMIP_TX_CFG0);
+
+ val = readl(base + UTMIP_HSRX_CFG0);
+ val &= ~(UTMIP_IDLE_WAIT(~0) | UTMIP_ELASTIC_LIMIT(~0));
+ val |= UTMIP_IDLE_WAIT(config->idle_wait_delay);
+ val |= UTMIP_ELASTIC_LIMIT(config->elastic_limit);
+ writel(val, base + UTMIP_HSRX_CFG0);
+
+ val = readl(base + UTMIP_HSRX_CFG1);
+ val &= ~UTMIP_HS_SYNC_START_DLY(~0);
+ val |= UTMIP_HS_SYNC_START_DLY(config->hssync_start_delay);
+ writel(val, base + UTMIP_HSRX_CFG1);
+
+ val = readl(base + UTMIP_DEBOUNCE_CFG0);
+ val &= ~UTMIP_BIAS_DEBOUNCE_A(~0);
+ val |= UTMIP_BIAS_DEBOUNCE_A(phy->freq->debounce);
+ writel(val, base + UTMIP_DEBOUNCE_CFG0);
+
+ val = readl(base + UTMIP_MISC_CFG0);
+ val &= ~UTMIP_SUSPEND_EXIT_ON_EDGE;
+ writel(val, base + UTMIP_MISC_CFG0);
+
+ val = readl(base + UTMIP_MISC_CFG1);
+ val &= ~(UTMIP_PLL_ACTIVE_DLY_COUNT(~0) | UTMIP_PLLU_STABLE_COUNT(~0));
+ val |= UTMIP_PLL_ACTIVE_DLY_COUNT(phy->freq->active_delay) |
+ UTMIP_PLLU_STABLE_COUNT(phy->freq->stable_count);
+ writel(val, base + UTMIP_MISC_CFG1);
+
+ val = readl(base + UTMIP_PLL_CFG1);
+ val &= ~(UTMIP_XTAL_FREQ_COUNT(~0) | UTMIP_PLLU_ENABLE_DLY_COUNT(~0));
+ val |= UTMIP_XTAL_FREQ_COUNT(phy->freq->xtal_freq_count) |
+ UTMIP_PLLU_ENABLE_DLY_COUNT(phy->freq->enable_delay);
+ writel(val, base + UTMIP_PLL_CFG1);
+
+ if (phy->mode == TEGRA_USB_PHY_MODE_DEVICE) {
+ val = readl(base + USB_SUSP_CTRL);
+ val &= ~(USB_WAKE_ON_CNNT_EN_DEV | USB_WAKE_ON_DISCON_EN_DEV);
+ writel(val, base + USB_SUSP_CTRL);
+ }
+
+ utmip_pad_power_on(phy);
+
+ val = readl(base + UTMIP_XCVR_CFG0);
+ val &= ~(UTMIP_FORCE_PD_POWERDOWN | UTMIP_FORCE_PD2_POWERDOWN |
+ UTMIP_FORCE_PDZI_POWERDOWN | UTMIP_XCVR_SETUP(~0) |
+ UTMIP_XCVR_LSFSLEW(~0) | UTMIP_XCVR_LSRSLEW(~0) |
+ UTMIP_XCVR_HSSLEW_MSB(~0));
+ val |= UTMIP_XCVR_SETUP(config->xcvr_setup);
+ val |= UTMIP_XCVR_LSFSLEW(config->xcvr_lsfslew);
+ val |= UTMIP_XCVR_LSRSLEW(config->xcvr_lsrslew);
+ writel(val, base + UTMIP_XCVR_CFG0);
+
+ val = readl(base + UTMIP_XCVR_CFG1);
+ val &= ~(UTMIP_FORCE_PDDISC_POWERDOWN | UTMIP_FORCE_PDCHRP_POWERDOWN |
+ UTMIP_FORCE_PDDR_POWERDOWN | UTMIP_XCVR_TERM_RANGE_ADJ(~0));
+ val |= UTMIP_XCVR_TERM_RANGE_ADJ(config->term_range_adj);
+ writel(val, base + UTMIP_XCVR_CFG1);
+
+ val = readl(base + UTMIP_BAT_CHRG_CFG0);
+ val &= ~UTMIP_PD_CHRG;
+ writel(val, base + UTMIP_BAT_CHRG_CFG0);
+
+ val = readl(base + UTMIP_BIAS_CFG1);
+ val &= ~UTMIP_BIAS_PDTRK_COUNT(~0);
+ val |= UTMIP_BIAS_PDTRK_COUNT(0x5);
+ writel(val, base + UTMIP_BIAS_CFG1);
+
+ if (phy->instance == 0) {
+ val = readl(base + UTMIP_SPARE_CFG0);
+ if (phy->mode == TEGRA_USB_PHY_MODE_DEVICE)
+ val &= ~FUSE_SETUP_SEL;
+ else
+ val |= FUSE_SETUP_SEL;
+ writel(val, base + UTMIP_SPARE_CFG0);
+ }
+
+ if (phy->instance == 2) {
+ val = readl(base + USB_SUSP_CTRL);
+ val |= UTMIP_PHY_ENABLE;
+ writel(val, base + USB_SUSP_CTRL);
+ }
+
+ val = readl(base + USB_SUSP_CTRL);
+ val &= ~UTMIP_RESET;
+ writel(val, base + USB_SUSP_CTRL);
+
+ if (phy->instance == 0) {
+ val = readl(base + USB1_LEGACY_CTRL);
+ val &= ~USB1_VBUS_SENSE_CTL_MASK;
+ val |= USB1_VBUS_SENSE_CTL_A_SESS_VLD;
+ writel(val, base + USB1_LEGACY_CTRL);
+
+ val = readl(base + USB_SUSP_CTRL);
+ val &= ~USB_SUSP_SET;
+ writel(val, base + USB_SUSP_CTRL);
+ }
+
+ utmi_phy_clk_enable(phy);
+
+ if (phy->instance == 2) {
+ val = readl(base + USB_PORTSC1);
+ val &= ~USB_PORTSC1_PTS(~0);
+ writel(val, base + USB_PORTSC1);
+ }
+
+ return 0;
+}
+
+static void utmi_phy_power_off(struct tegra_usb_phy *phy)
+{
+ unsigned long val;
+ void __iomem *base = phy->regs;
+
+ utmi_phy_clk_disable(phy);
+
+ if (phy->mode == TEGRA_USB_PHY_MODE_DEVICE) {
+ val = readl(base + USB_SUSP_CTRL);
+ val &= ~USB_WAKEUP_DEBOUNCE_COUNT(~0);
+ val |= USB_WAKE_ON_CNNT_EN_DEV | USB_WAKEUP_DEBOUNCE_COUNT(5);
+ writel(val, base + USB_SUSP_CTRL);
+ }
+
+ val = readl(base + USB_SUSP_CTRL);
+ val |= UTMIP_RESET;
+ writel(val, base + USB_SUSP_CTRL);
+
+ val = readl(base + UTMIP_BAT_CHRG_CFG0);
+ val |= UTMIP_PD_CHRG;
+ writel(val, base + UTMIP_BAT_CHRG_CFG0);
+
+ val = readl(base + UTMIP_XCVR_CFG0);
+ val |= UTMIP_FORCE_PD_POWERDOWN | UTMIP_FORCE_PD2_POWERDOWN |
+ UTMIP_FORCE_PDZI_POWERDOWN;
+ writel(val, base + UTMIP_XCVR_CFG0);
+
+ val = readl(base + UTMIP_XCVR_CFG1);
+ val |= UTMIP_FORCE_PDDISC_POWERDOWN | UTMIP_FORCE_PDCHRP_POWERDOWN |
+ UTMIP_FORCE_PDDR_POWERDOWN;
+ writel(val, base + UTMIP_XCVR_CFG1);
+
+ utmip_pad_power_off(phy);
+}
+
+static void utmi_phy_preresume(struct tegra_usb_phy *phy)
+{
+ unsigned long val;
+ void __iomem *base = phy->regs;
+
+ val = readl(base + UTMIP_TX_CFG0);
+ val |= UTMIP_HS_DISCON_DISABLE;
+ writel(val, base + UTMIP_TX_CFG0);
+}
+
+static void utmi_phy_postresume(struct tegra_usb_phy *phy)
+{
+ unsigned long val;
+ void __iomem *base = phy->regs;
+
+ val = readl(base + UTMIP_TX_CFG0);
+ val &= ~UTMIP_HS_DISCON_DISABLE;
+ writel(val, base + UTMIP_TX_CFG0);
+}
+
+static void utmi_phy_restore_start(struct tegra_usb_phy *phy,
+ enum tegra_usb_phy_port_speed port_speed)
+{
+ unsigned long val;
+ void __iomem *base = phy->regs;
+
+ val = readl(base + UTMIP_MISC_CFG0);
+ val &= ~UTMIP_DPDM_OBSERVE_SEL(~0);
+ if (port_speed == TEGRA_USB_PHY_PORT_SPEED_LOW)
+ val |= UTMIP_DPDM_OBSERVE_SEL_FS_K;
+ else
+ val |= UTMIP_DPDM_OBSERVE_SEL_FS_J;
+ writel(val, base + UTMIP_MISC_CFG0);
+ udelay(1);
+
+ val = readl(base + UTMIP_MISC_CFG0);
+ val |= UTMIP_DPDM_OBSERVE;
+ writel(val, base + UTMIP_MISC_CFG0);
+ udelay(10);
+}
+
+static void utmi_phy_restore_end(struct tegra_usb_phy *phy)
+{
+ unsigned long val;
+ void __iomem *base = phy->regs;
+
+ val = readl(base + UTMIP_MISC_CFG0);
+ val &= ~UTMIP_DPDM_OBSERVE;
+ writel(val, base + UTMIP_MISC_CFG0);
+ udelay(10);
+}
+
+static int ulpi_phy_power_on(struct tegra_usb_phy *phy)
+{
+ int ret;
+ unsigned long val;
+ void __iomem *base = phy->regs;
+ struct tegra_ulpi_config *config = phy->config;
+
+ gpio_direction_output(config->reset_gpio, 0);
+ msleep(5);
+ gpio_direction_output(config->reset_gpio, 1);
+
+ clk_enable(phy->clk);
+ msleep(1);
+
+ val = readl(base + USB_SUSP_CTRL);
+ val |= UHSIC_RESET;
+ writel(val, base + USB_SUSP_CTRL);
+
+ val = readl(base + ULPI_TIMING_CTRL_0);
+ val |= ULPI_OUTPUT_PINMUX_BYP | ULPI_CLKOUT_PINMUX_BYP;
+ writel(val, base + ULPI_TIMING_CTRL_0);
+
+ val = readl(base + USB_SUSP_CTRL);
+ val |= ULPI_PHY_ENABLE;
+ writel(val, base + USB_SUSP_CTRL);
+
+ val = 0;
+ writel(val, base + ULPI_TIMING_CTRL_1);
+
+ val |= ULPI_DATA_TRIMMER_SEL(4);
+ val |= ULPI_STPDIRNXT_TRIMMER_SEL(4);
+ val |= ULPI_DIR_TRIMMER_SEL(4);
+ writel(val, base + ULPI_TIMING_CTRL_1);
+ udelay(10);
+
+ val |= ULPI_DATA_TRIMMER_LOAD;
+ val |= ULPI_STPDIRNXT_TRIMMER_LOAD;
+ val |= ULPI_DIR_TRIMMER_LOAD;
+ writel(val, base + ULPI_TIMING_CTRL_1);
+
+ /* Fix VbusInvalid due to floating VBUS */
+ ret = otg_io_write(phy->ulpi, 0x40, 0x08);
+ if (ret) {
+ pr_err("%s: ulpi write failed\n", __func__);
+ return ret;
+ }
+
+ ret = otg_io_write(phy->ulpi, 0x80, 0x0B);
+ if (ret) {
+ pr_err("%s: ulpi write failed\n", __func__);
+ return ret;
+ }
+
+ val = readl(base + USB_PORTSC1);
+ val |= USB_PORTSC1_WKOC | USB_PORTSC1_WKDS | USB_PORTSC1_WKCN;
+ writel(val, base + USB_PORTSC1);
+
+ val = readl(base + USB_SUSP_CTRL);
+ val |= USB_SUSP_CLR;
+ writel(val, base + USB_SUSP_CTRL);
+ udelay(100);
+
+ val = readl(base + USB_SUSP_CTRL);
+ val &= ~USB_SUSP_CLR;
+ writel(val, base + USB_SUSP_CTRL);
+
+ return 0;
+}
+
+static void ulpi_phy_power_off(struct tegra_usb_phy *phy)
+{
+ unsigned long val;
+ void __iomem *base = phy->regs;
+ struct tegra_ulpi_config *config = phy->config;
+
+ /* Clear WKCN/WKDS/WKOC wake-on events that can cause the USB
+ * Controller to immediately bring the ULPI PHY out of low power
+ */
+ val = readl(base + USB_PORTSC1);
+ val &= ~(USB_PORTSC1_WKOC | USB_PORTSC1_WKDS | USB_PORTSC1_WKCN);
+ writel(val, base + USB_PORTSC1);
+
+ gpio_direction_output(config->reset_gpio, 0);
+ clk_disable(phy->clk);
+}
+
+struct tegra_usb_phy *tegra_usb_phy_open(int instance, void __iomem *regs,
+ void *config, enum tegra_usb_phy_mode phy_mode)
+{
+ struct tegra_usb_phy *phy;
+ struct tegra_ulpi_config *ulpi_config;
+ unsigned long parent_rate;
+ int i;
+ int err;
+
+ phy = kmalloc(sizeof(struct tegra_usb_phy), GFP_KERNEL);
+ if (!phy)
+ return ERR_PTR(-ENOMEM);
+
+ phy->instance = instance;
+ phy->regs = regs;
+ phy->config = config;
+ phy->mode = phy_mode;
+
+ if (!phy->config) {
+ if (phy_is_ulpi(phy)) {
+ pr_err("%s: ulpi phy configuration missing", __func__);
+ err = -EINVAL;
+ goto err0;
+ } else {
+ phy->config = &utmip_default[instance];
+ }
+ }
+
+ phy->pll_u = clk_get_sys(NULL, "pll_u");
+ if (IS_ERR(phy->pll_u)) {
+ pr_err("Can't get pll_u clock\n");
+ err = PTR_ERR(phy->pll_u);
+ goto err0;
+ }
+ clk_enable(phy->pll_u);
+
+ parent_rate = clk_get_rate(clk_get_parent(phy->pll_u));
+ for (i = 0; i < ARRAY_SIZE(tegra_freq_table); i++) {
+ if (tegra_freq_table[i].freq == parent_rate) {
+ phy->freq = &tegra_freq_table[i];
+ break;
+ }
+ }
+ if (!phy->freq) {
+ pr_err("invalid pll_u parent rate %ld\n", parent_rate);
+ err = -EINVAL;
+ goto err1;
+ }
+
+ if (phy_is_ulpi(phy)) {
+ ulpi_config = config;
+ phy->clk = clk_get_sys(NULL, ulpi_config->clk);
+ if (IS_ERR(phy->clk)) {
+ pr_err("%s: can't get ulpi clock\n", __func__);
+ err = -ENXIO;
+ goto err1;
+ }
+ tegra_gpio_enable(ulpi_config->reset_gpio);
+ gpio_request(ulpi_config->reset_gpio, "ulpi_phy_reset_b");
+ gpio_direction_output(ulpi_config->reset_gpio, 0);
+ phy->ulpi = otg_ulpi_create(&ulpi_viewport_access_ops, 0);
+ phy->ulpi->io_priv = regs + ULPI_VIEWPORT;
+ } else {
+ err = utmip_pad_open(phy);
+ if (err < 0)
+ goto err1;
+ }
+
+ return phy;
+
+err1:
+ clk_disable(phy->pll_u);
+ clk_put(phy->pll_u);
+err0:
+ kfree(phy);
+ return ERR_PTR(err);
+}
+
+int tegra_usb_phy_power_on(struct tegra_usb_phy *phy)
+{
+ if (phy_is_ulpi(phy))
+ return ulpi_phy_power_on(phy);
+ else
+ return utmi_phy_power_on(phy);
+}
+
+void tegra_usb_phy_power_off(struct tegra_usb_phy *phy)
+{
+ if (phy_is_ulpi(phy))
+ ulpi_phy_power_off(phy);
+ else
+ utmi_phy_power_off(phy);
+}
+
+void tegra_usb_phy_preresume(struct tegra_usb_phy *phy)
+{
+ if (!phy_is_ulpi(phy))
+ utmi_phy_preresume(phy);
+}
+
+void tegra_usb_phy_postresume(struct tegra_usb_phy *phy)
+{
+ if (!phy_is_ulpi(phy))
+ utmi_phy_postresume(phy);
+}
+
+void tegra_ehci_phy_restore_start(struct tegra_usb_phy *phy,
+ enum tegra_usb_phy_port_speed port_speed)
+{
+ if (!phy_is_ulpi(phy))
+ utmi_phy_restore_start(phy, port_speed);
+}
+
+void tegra_ehci_phy_restore_end(struct tegra_usb_phy *phy)
+{
+ if (!phy_is_ulpi(phy))
+ utmi_phy_restore_end(phy);
+}
+
+void tegra_usb_phy_clk_disable(struct tegra_usb_phy *phy)
+{
+ if (!phy_is_ulpi(phy))
+ utmi_phy_clk_disable(phy);
+}
+
+void tegra_usb_phy_clk_enable(struct tegra_usb_phy *phy)
+{
+ if (!phy_is_ulpi(phy))
+ utmi_phy_clk_enable(phy);
+}
+
+void tegra_usb_phy_close(struct tegra_usb_phy *phy)
+{
+ if (phy_is_ulpi(phy))
+ clk_put(phy->clk);
+ else
+ utmip_pad_close(phy);
+ clk_disable(phy->pll_u);
+ clk_put(phy->pll_u);
+ kfree(phy);
+}