summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--arch/arm/Kconfig1
-rw-r--r--arch/arm/boot/dts/at91sam9g25ek.dts37
-rw-r--r--arch/arm/boot/dts/at91sam9x5.dtsi172
-rw-r--r--arch/arm/boot/dts/at91sam9x5cm.dtsi14
-rw-r--r--arch/arm/common/timer-sp.c17
-rw-r--r--arch/arm/configs/imx_v6_v7_defconfig5
-rw-r--r--arch/arm/configs/mxs_defconfig20
-rw-r--r--arch/arm/include/asm/hardware/timer-sp.h15
-rw-r--r--arch/arm/mach-at91/Kconfig9
-rw-r--r--arch/arm/mach-at91/Makefile1
-rw-r--r--arch/arm/mach-at91/at91sam9x5.c373
-rw-r--r--arch/arm/mach-at91/board-dt.c1
-rw-r--r--arch/arm/mach-at91/clock.c83
-rw-r--r--arch/arm/mach-at91/include/mach/at91_pmc.h60
-rw-r--r--arch/arm/mach-at91/include/mach/at91sam9x5.h80
-rw-r--r--arch/arm/mach-at91/include/mach/at91sam9x5_matrix.h53
-rw-r--r--arch/arm/mach-at91/include/mach/hardware.h2
-rw-r--r--arch/arm/mach-exynos/clock-exynos4.c5
-rw-r--r--arch/arm/mach-exynos/common.c60
-rw-r--r--arch/arm/mach-exynos/cpuidle.c151
-rw-r--r--arch/arm/mach-exynos/include/mach/map.h7
-rw-r--r--arch/arm/mach-exynos/include/mach/pmu.h2
-rw-r--r--arch/arm/mach-exynos/mct.c21
-rw-r--r--arch/arm/mach-exynos/pm.c15
-rw-r--r--arch/arm/mach-highbank/highbank.c2
-rw-r--r--arch/arm/mach-highbank/include/mach/memory.h1
-rw-r--r--arch/arm/mach-imx/Makefile4
-rw-r--r--arch/arm/mach-imx/cpu-imx5.c36
-rw-r--r--arch/arm/mach-imx/crmregs-imx3.h1
-rw-r--r--arch/arm/mach-imx/mm-imx3.c11
-rw-r--r--arch/arm/mach-imx/mm-imx5.c10
-rw-r--r--arch/arm/mach-imx/pm-imx3.c37
-rw-r--r--arch/arm/mach-mxs/clock-mx23.c34
-rw-r--r--arch/arm/mach-mxs/clock-mx28.c57
-rw-r--r--arch/arm/mach-mxs/devices/platform-mxs-mmc.c2
-rw-r--r--arch/arm/mach-mxs/include/mach/common.h2
-rw-r--r--arch/arm/mach-mxs/system.c16
-rw-r--r--arch/arm/mach-omap2/id.c186
-rw-r--r--arch/arm/mach-omap2/io.c9
-rw-r--r--arch/arm/mach-s3c64xx/Kconfig8
-rw-r--r--arch/arm/mach-s3c64xx/Makefile2
-rw-r--r--arch/arm/mach-s3c64xx/clock.c121
-rw-r--r--arch/arm/mach-s3c64xx/cpuidle.c91
-rw-r--r--arch/arm/mach-s3c64xx/mach-crag6410.c4
-rw-r--r--arch/arm/mach-s3c64xx/mach-smartq.c3
-rw-r--r--arch/arm/mach-s3c64xx/mach-smdk6410.c4
-rw-r--r--arch/arm/mach-s3c64xx/setup-usb-phy.c90
-rw-r--r--arch/arm/mach-s5pv210/Kconfig6
-rw-r--r--arch/arm/mach-s5pv210/Makefile1
-rw-r--r--arch/arm/mach-s5pv210/include/mach/regs-sys.h4
-rw-r--r--arch/arm/mach-s5pv210/setup-usb-phy.c90
-rw-r--r--arch/arm/mach-tegra/Makefile3
-rw-r--r--arch/arm/mach-tegra/board-dt-tegra30.c24
-rw-r--r--arch/arm/mach-tegra/clock.c22
-rw-r--r--arch/arm/mach-tegra/clock.h15
-rw-r--r--arch/arm/mach-tegra/common.c1
-rw-r--r--arch/arm/mach-tegra/cpuidle.c107
-rw-r--r--arch/arm/mach-tegra/flowctrl.h37
-rw-r--r--arch/arm/mach-tegra/include/mach/clk.h10
-rw-r--r--arch/arm/mach-tegra/include/mach/iomap.h3
-rw-r--r--arch/arm/mach-tegra/include/mach/irqs.h7
-rw-r--r--arch/arm/mach-tegra/irq.c20
-rw-r--r--arch/arm/mach-tegra/sleep.S91
-rw-r--r--arch/arm/mach-tegra/tegra2_clocks.c30
-rw-r--r--arch/arm/mach-tegra/tegra30_clocks.c3099
-rw-r--r--arch/arm/plat-mxc/cpu.c24
-rw-r--r--arch/arm/plat-mxc/include/mach/common.h9
-rw-r--r--arch/arm/plat-omap/include/plat/cpu.h7
-rw-r--r--arch/arm/plat-s5p/Kconfig10
-rw-r--r--arch/arm/plat-s5p/sleep.S44
-rw-r--r--arch/arm/plat-samsung/clock.c12
-rw-r--r--arch/arm/plat-samsung/dev-backlight.c4
-rw-r--r--arch/arm/plat-samsung/devs.c68
-rw-r--r--arch/arm/plat-samsung/include/plat/devs.h2
-rw-r--r--arch/arm/plat-samsung/include/plat/regs-usb-hsotg-phy.h7
-rw-r--r--arch/arm/plat-samsung/include/plat/udc-hs.h5
76 files changed, 5351 insertions, 346 deletions
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 0e8db19899c4..dae718ab1d66 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -1131,6 +1131,7 @@ config PLAT_VERSATILE
config ARM_TIMER_SP804
bool
select CLKSRC_MMIO
+ select HAVE_SCHED_CLOCK
source arch/arm/mm/Kconfig
diff --git a/arch/arm/boot/dts/at91sam9g25ek.dts b/arch/arm/boot/dts/at91sam9g25ek.dts
new file mode 100644
index 000000000000..e64eb932083b
--- /dev/null
+++ b/arch/arm/boot/dts/at91sam9g25ek.dts
@@ -0,0 +1,37 @@
+/*
+ * at91sam9g25ek.dts - Device Tree file for AT91SAM9G25-EK board
+ *
+ * Copyright (C) 2012 Atmel,
+ * 2012 Nicolas Ferre <nicolas.ferre@atmel.com>
+ *
+ * Licensed under GPLv2 or later.
+ */
+/dts-v1/;
+/include/ "at91sam9x5.dtsi"
+/include/ "at91sam9x5cm.dtsi"
+
+/ {
+ model = "Atmel AT91SAM9G25-EK";
+ compatible = "atmel,at91sam9g25ek", "atmel,at91sam9x5ek", "atmel,at91sam9x5", "atmel,at91sam9";
+
+ chosen {
+ bootargs = "128M console=ttyS0,115200 mtdparts=atmel_nand:8M(bootstrap/uboot/kernel)ro,-(rootfs) root=/dev/mtdblock1 rw rootfstype=ubifs ubi.mtd=1 root=ubi0:rootfs";
+ };
+
+ ahb {
+ apb {
+ dbgu: serial@fffff200 {
+ status = "okay";
+ };
+
+ usart0: serial@f801c000 {
+ status = "okay";
+ };
+
+ macb0: ethernet@f802c000 {
+ phy-mode = "rmii";
+ status = "okay";
+ };
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/at91sam9x5.dtsi b/arch/arm/boot/dts/at91sam9x5.dtsi
new file mode 100644
index 000000000000..e91391f50730
--- /dev/null
+++ b/arch/arm/boot/dts/at91sam9x5.dtsi
@@ -0,0 +1,172 @@
+/*
+ * at91sam9x5.dtsi - Device Tree Include file for AT91SAM9x5 family SoC
+ * applies to AT91SAM9G15, AT91SAM9G25, AT91SAM9G35,
+ * AT91SAM9X25, AT91SAM9X35 SoC
+ *
+ * Copyright (C) 2012 Atmel,
+ * 2012 Nicolas Ferre <nicolas.ferre@atmel.com>
+ *
+ * Licensed under GPLv2 or later.
+ */
+
+/include/ "skeleton.dtsi"
+
+/ {
+ model = "Atmel AT91SAM9x5 family SoC";
+ compatible = "atmel,at91sam9x5";
+ interrupt-parent = <&aic>;
+
+ aliases {
+ serial0 = &dbgu;
+ serial1 = &usart0;
+ serial2 = &usart1;
+ serial3 = &usart2;
+ gpio0 = &pioA;
+ gpio1 = &pioB;
+ gpio2 = &pioC;
+ gpio3 = &pioD;
+ tcb0 = &tcb0;
+ tcb1 = &tcb1;
+ };
+ cpus {
+ cpu@0 {
+ compatible = "arm,arm926ejs";
+ };
+ };
+
+ memory@20000000 {
+ reg = <0x20000000 0x10000000>;
+ };
+
+ ahb {
+ compatible = "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
+ apb {
+ compatible = "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
+ aic: interrupt-controller@fffff000 {
+ #interrupt-cells = <2>;
+ compatible = "atmel,at91rm9200-aic";
+ interrupt-controller;
+ interrupt-parent;
+ reg = <0xfffff000 0x200>;
+ };
+
+ pit: timer@fffffe30 {
+ compatible = "atmel,at91sam9260-pit";
+ reg = <0xfffffe30 0xf>;
+ interrupts = <1 4>;
+ };
+
+ tcb0: timer@f8008000 {
+ compatible = "atmel,at91sam9x5-tcb";
+ reg = <0xf8008000 0x100>;
+ interrupts = <17 4>;
+ };
+
+ tcb1: timer@f800c000 {
+ compatible = "atmel,at91sam9x5-tcb";
+ reg = <0xf800c000 0x100>;
+ interrupts = <17 4>;
+ };
+
+ dma0: dma-controller@ffffec00 {
+ compatible = "atmel,at91sam9g45-dma";
+ reg = <0xffffec00 0x200>;
+ interrupts = <20 4>;
+ };
+
+ dma1: dma-controller@ffffee00 {
+ compatible = "atmel,at91sam9g45-dma";
+ reg = <0xffffee00 0x200>;
+ interrupts = <21 4>;
+ };
+
+ pioA: gpio@fffff400 {
+ compatible = "atmel,at91rm9200-gpio";
+ reg = <0xfffff400 0x100>;
+ interrupts = <2 4>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ };
+
+ pioB: gpio@fffff600 {
+ compatible = "atmel,at91rm9200-gpio";
+ reg = <0xfffff600 0x100>;
+ interrupts = <2 4>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ };
+
+ pioC: gpio@fffff800 {
+ compatible = "atmel,at91rm9200-gpio";
+ reg = <0xfffff800 0x100>;
+ interrupts = <3 4>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ };
+
+ pioD: gpio@fffffa00 {
+ compatible = "atmel,at91rm9200-gpio";
+ reg = <0xfffffa00 0x100>;
+ interrupts = <3 4>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ };
+
+ dbgu: serial@fffff200 {
+ compatible = "atmel,at91sam9260-usart";
+ reg = <0xfffff200 0x200>;
+ interrupts = <1 4>;
+ status = "disabled";
+ };
+
+ usart0: serial@f801c000 {
+ compatible = "atmel,at91sam9260-usart";
+ reg = <0xf801c000 0x200>;
+ interrupts = <5 4>;
+ atmel,use-dma-rx;
+ atmel,use-dma-tx;
+ status = "disabled";
+ };
+
+ usart1: serial@f8020000 {
+ compatible = "atmel,at91sam9260-usart";
+ reg = <0xf8020000 0x200>;
+ interrupts = <6 4>;
+ atmel,use-dma-rx;
+ atmel,use-dma-tx;
+ status = "disabled";
+ };
+
+ usart2: serial@f8024000 {
+ compatible = "atmel,at91sam9260-usart";
+ reg = <0xf8024000 0x200>;
+ interrupts = <7 4>;
+ atmel,use-dma-rx;
+ atmel,use-dma-tx;
+ status = "disabled";
+ };
+
+ macb0: ethernet@f802c000 {
+ compatible = "cdns,at32ap7000-macb", "cdns,macb";
+ reg = <0xf802c000 0x100>;
+ interrupts = <24 4>;
+ status = "disabled";
+ };
+
+ macb1: ethernet@f8030000 {
+ compatible = "cdns,at32ap7000-macb", "cdns,macb";
+ reg = <0xf8030000 0x100>;
+ interrupts = <27 4>;
+ status = "disabled";
+ };
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/at91sam9x5cm.dtsi b/arch/arm/boot/dts/at91sam9x5cm.dtsi
new file mode 100644
index 000000000000..4ab5a77f4afc
--- /dev/null
+++ b/arch/arm/boot/dts/at91sam9x5cm.dtsi
@@ -0,0 +1,14 @@
+/*
+ * at91sam9x5cm.dtsi - Device Tree Include file for AT91SAM9x5 CPU Module
+ *
+ * Copyright (C) 2012 Atmel,
+ * 2012 Nicolas Ferre <nicolas.ferre@atmel.com>
+ *
+ * Licensed under GPLv2 or later.
+ */
+
+/ {
+ memory@20000000 {
+ reg = <0x20000000 0x8000000>;
+ };
+};
diff --git a/arch/arm/common/timer-sp.c b/arch/arm/common/timer-sp.c
index 8794a34eae61..df13a3ffff35 100644
--- a/arch/arm/common/timer-sp.c
+++ b/arch/arm/common/timer-sp.c
@@ -26,6 +26,7 @@
#include <linux/irq.h>
#include <linux/io.h>
+#include <asm/sched_clock.h>
#include <asm/hardware/arm_timer.h>
static long __init sp804_get_clock_rate(const char *name)
@@ -67,7 +68,16 @@ static long __init sp804_get_clock_rate(const char *name)
return rate;
}
-void __init sp804_clocksource_init(void __iomem *base, const char *name)
+static void __iomem *sched_clock_base;
+
+static u32 sp804_read(void)
+{
+ return ~readl_relaxed(sched_clock_base + TIMER_VALUE);
+}
+
+void __init __sp804_clocksource_and_sched_clock_init(void __iomem *base,
+ const char *name,
+ int use_sched_clock)
{
long rate = sp804_get_clock_rate(name);
@@ -83,6 +93,11 @@ void __init sp804_clocksource_init(void __iomem *base, const char *name)
clocksource_mmio_init(base + TIMER_VALUE, name,
rate, 200, 32, clocksource_mmio_readl_down);
+
+ if (use_sched_clock) {
+ sched_clock_base = base;
+ setup_sched_clock(sp804_read, 32, rate);
+ }
}
diff --git a/arch/arm/configs/imx_v6_v7_defconfig b/arch/arm/configs/imx_v6_v7_defconfig
index 3a4fb2e5fc68..3cd606905178 100644
--- a/arch/arm/configs/imx_v6_v7_defconfig
+++ b/arch/arm/configs/imx_v6_v7_defconfig
@@ -5,6 +5,7 @@ CONFIG_SYSVIPC=y
CONFIG_LOG_BUF_SHIFT=18
CONFIG_CGROUPS=y
CONFIG_RELAY=y
+CONFIG_BLK_DEV_INITRD=y
CONFIG_EXPERT=y
# CONFIG_SLUB_DEBUG is not set
# CONFIG_COMPAT_BRK is not set
@@ -12,7 +13,6 @@ CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
CONFIG_MODVERSIONS=y
CONFIG_MODULE_SRCVERSION_ALL=y
-# CONFIG_LBDAF is not set
# CONFIG_BLK_DEV_BSG is not set
CONFIG_ARCH_MXC=y
CONFIG_MACH_MX31LILLY=y
@@ -26,7 +26,6 @@ CONFIG_MACH_ARMADILLO5X0=y
CONFIG_MACH_KZM_ARM11_01=y
CONFIG_MACH_PCM043=y
CONFIG_MACH_MX35_3DS=y
-CONFIG_MACH_EUKREA_CPUIMX35=y
CONFIG_MACH_VPR200=y
CONFIG_MACH_IMX51_DT=y
CONFIG_MACH_MX51_3DS=y
@@ -83,7 +82,6 @@ CONFIG_NETDEVICES=y
# CONFIG_NET_VENDOR_BROADCOM is not set
# CONFIG_NET_VENDOR_CHELSIO is not set
# CONFIG_NET_VENDOR_FARADAY is not set
-CONFIG_FEC=y
# CONFIG_NET_VENDOR_INTEL is not set
# CONFIG_NET_VENDOR_MARVELL is not set
# CONFIG_NET_VENDOR_MICREL is not set
@@ -126,6 +124,7 @@ CONFIG_WATCHDOG=y
CONFIG_IMX2_WDT=y
CONFIG_MFD_MC13XXX=y
CONFIG_REGULATOR=y
+CONFIG_REGULATOR_FIXED_VOLTAGE=y
CONFIG_REGULATOR_MC13892=y
CONFIG_USB=y
CONFIG_USB_EHCI_HCD=y
diff --git a/arch/arm/configs/mxs_defconfig b/arch/arm/configs/mxs_defconfig
index 6ee781bf6bf1..1ebbf451c48d 100644
--- a/arch/arm/configs/mxs_defconfig
+++ b/arch/arm/configs/mxs_defconfig
@@ -77,10 +77,10 @@ CONFIG_DEVPTS_MULTIPLE_INSTANCES=y
CONFIG_SERIAL_AMBA_PL011=y
CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
# CONFIG_HW_RANDOM is not set
-CONFIG_I2C=m
+CONFIG_I2C=y
# CONFIG_I2C_COMPAT is not set
-CONFIG_I2C_CHARDEV=m
-CONFIG_I2C_MXS=m
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_MXS=y
CONFIG_SPI=y
CONFIG_SPI_GPIO=m
CONFIG_DEBUG_GPIO=y
@@ -90,6 +90,20 @@ CONFIG_GPIO_SYSFS=y
CONFIG_DISPLAY_SUPPORT=m
# CONFIG_HID_SUPPORT is not set
# CONFIG_USB_SUPPORT is not set
+CONFIG_SOUND=y
+CONFIG_SND=y
+CONFIG_SND_TIMER=y
+CONFIG_SND_PCM=y
+CONFIG_SND_JACK=y
+CONFIG_SND_DRIVERS=y
+CONFIG_SND_ARM=y
+CONFIG_SND_SOC=y
+CONFIG_SND_MXS_SOC=y
+CONFIG_SND_SOC_MXS_SGTL5000=y
+CONFIG_SND_SOC_I2C_AND_SPI=y
+CONFIG_SND_SOC_SGTL5000=y
+CONFIG_REGULATOR=y
+CONFIG_REGULATOR_FIXED_VOLTAGE=y
CONFIG_MMC=y
CONFIG_MMC_MXS=y
CONFIG_RTC_CLASS=y
diff --git a/arch/arm/include/asm/hardware/timer-sp.h b/arch/arm/include/asm/hardware/timer-sp.h
index 4384d81eee79..2dd9d3f83f29 100644
--- a/arch/arm/include/asm/hardware/timer-sp.h
+++ b/arch/arm/include/asm/hardware/timer-sp.h
@@ -1,2 +1,15 @@
-void sp804_clocksource_init(void __iomem *, const char *);
+void __sp804_clocksource_and_sched_clock_init(void __iomem *,
+ const char *, int);
+
+static inline void sp804_clocksource_init(void __iomem *base, const char *name)
+{
+ __sp804_clocksource_and_sched_clock_init(base, name, 0);
+}
+
+static inline void sp804_clocksource_and_sched_clock_init(void __iomem *base,
+ const char *name)
+{
+ __sp804_clocksource_and_sched_clock_init(base, name, 1);
+}
+
void sp804_clockevents_init(void __iomem *, unsigned int, const char *);
diff --git a/arch/arm/mach-at91/Kconfig b/arch/arm/mach-at91/Kconfig
index 0284e66c47f9..e55cdcbd81fb 100644
--- a/arch/arm/mach-at91/Kconfig
+++ b/arch/arm/mach-at91/Kconfig
@@ -102,6 +102,15 @@ config ARCH_AT91SAM9G45
select HAVE_AT91_DBGU1
select AT91_SAM9G45_RESET
+config ARCH_AT91SAM9X5
+ bool "AT91SAM9x5 family"
+ select CPU_ARM926T
+ select GENERIC_CLOCKEVENTS
+ select HAVE_FB_ATMEL
+ select HAVE_NET_MACB
+ select HAVE_AT91_DBGU0
+ select AT91_SAM9G45_RESET
+
config ARCH_AT91X40
bool "AT91x40"
select ARCH_USES_GETTIMEOFFSET
diff --git a/arch/arm/mach-at91/Makefile b/arch/arm/mach-at91/Makefile
index aeb76f1690d9..1b6518518d99 100644
--- a/arch/arm/mach-at91/Makefile
+++ b/arch/arm/mach-at91/Makefile
@@ -20,6 +20,7 @@ obj-$(CONFIG_ARCH_AT91SAM9263) += at91sam9263.o at91sam926x_time.o at91sam9263_d
obj-$(CONFIG_ARCH_AT91SAM9RL) += at91sam9rl.o at91sam926x_time.o at91sam9rl_devices.o sam9_smc.o
obj-$(CONFIG_ARCH_AT91SAM9G20) += at91sam9260.o at91sam926x_time.o at91sam9260_devices.o sam9_smc.o
obj-$(CONFIG_ARCH_AT91SAM9G45) += at91sam9g45.o at91sam926x_time.o at91sam9g45_devices.o sam9_smc.o
+obj-$(CONFIG_ARCH_AT91SAM9X5) += at91sam9x5.o at91sam926x_time.o
obj-$(CONFIG_ARCH_AT91X40) += at91x40.o at91x40_time.o
# AT91RM9200 board-specific support
diff --git a/arch/arm/mach-at91/at91sam9x5.c b/arch/arm/mach-at91/at91sam9x5.c
new file mode 100644
index 000000000000..1c3444d2ee0c
--- /dev/null
+++ b/arch/arm/mach-at91/at91sam9x5.c
@@ -0,0 +1,373 @@
+/*
+ * Chip-specific setup code for the AT91SAM9x5 family
+ *
+ * Copyright (C) 2010-2012 Atmel Corporation.
+ *
+ * Licensed under GPLv2 or later.
+ */
+
+#include <linux/module.h>
+#include <linux/dma-mapping.h>
+
+#include <asm/irq.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <mach/at91sam9x5.h>
+#include <mach/at91_pmc.h>
+#include <mach/cpu.h>
+#include <mach/board.h>
+
+#include "soc.h"
+#include "generic.h"
+#include "clock.h"
+#include "sam9_smc.h"
+
+/* --------------------------------------------------------------------
+ * Clocks
+ * -------------------------------------------------------------------- */
+
+/*
+ * The peripheral clocks.
+ */
+static struct clk pioAB_clk = {
+ .name = "pioAB_clk",
+ .pmc_mask = 1 << AT91SAM9X5_ID_PIOAB,
+ .type = CLK_TYPE_PERIPHERAL,
+};
+static struct clk pioCD_clk = {
+ .name = "pioCD_clk",
+ .pmc_mask = 1 << AT91SAM9X5_ID_PIOCD,
+ .type = CLK_TYPE_PERIPHERAL,
+};
+static struct clk smd_clk = {
+ .name = "smd_clk",
+ .pmc_mask = 1 << AT91SAM9X5_ID_SMD,
+ .type = CLK_TYPE_PERIPHERAL,
+};
+static struct clk usart0_clk = {
+ .name = "usart0_clk",
+ .pmc_mask = 1 << AT91SAM9X5_ID_USART0,
+ .type = CLK_TYPE_PERIPHERAL,
+};
+static struct clk usart1_clk = {
+ .name = "usart1_clk",
+ .pmc_mask = 1 << AT91SAM9X5_ID_USART1,
+ .type = CLK_TYPE_PERIPHERAL,
+};
+static struct clk usart2_clk = {
+ .name = "usart2_clk",
+ .pmc_mask = 1 << AT91SAM9X5_ID_USART2,
+ .type = CLK_TYPE_PERIPHERAL,
+};
+/* USART3 clock - Only for sam9g25/sam9x25 */
+static struct clk usart3_clk = {
+ .name = "usart3_clk",
+ .pmc_mask = 1 << AT91SAM9X5_ID_USART3,
+ .type = CLK_TYPE_PERIPHERAL,
+};
+static struct clk twi0_clk = {
+ .name = "twi0_clk",
+ .pmc_mask = 1 << AT91SAM9X5_ID_TWI0,
+ .type = CLK_TYPE_PERIPHERAL,
+};
+static struct clk twi1_clk = {
+ .name = "twi1_clk",
+ .pmc_mask = 1 << AT91SAM9X5_ID_TWI1,
+ .type = CLK_TYPE_PERIPHERAL,
+};
+static struct clk twi2_clk = {
+ .name = "twi2_clk",
+ .pmc_mask = 1 << AT91SAM9X5_ID_TWI2,
+ .type = CLK_TYPE_PERIPHERAL,
+};
+static struct clk mmc0_clk = {
+ .name = "mci0_clk",
+ .pmc_mask = 1 << AT91SAM9X5_ID_MCI0,
+ .type = CLK_TYPE_PERIPHERAL,
+};
+static struct clk spi0_clk = {
+ .name = "spi0_clk",
+ .pmc_mask = 1 << AT91SAM9X5_ID_SPI0,
+ .type = CLK_TYPE_PERIPHERAL,
+};
+static struct clk spi1_clk = {
+ .name = "spi1_clk",
+ .pmc_mask = 1 << AT91SAM9X5_ID_SPI1,
+ .type = CLK_TYPE_PERIPHERAL,
+};
+static struct clk uart0_clk = {
+ .name = "uart0_clk",
+ .pmc_mask = 1 << AT91SAM9X5_ID_UART0,
+ .type = CLK_TYPE_PERIPHERAL,
+};
+static struct clk uart1_clk = {
+ .name = "uart1_clk",
+ .pmc_mask = 1 << AT91SAM9X5_ID_UART1,
+ .type = CLK_TYPE_PERIPHERAL,
+};
+static struct clk tcb0_clk = {
+ .name = "tcb0_clk",
+ .pmc_mask = 1 << AT91SAM9X5_ID_TCB,
+ .type = CLK_TYPE_PERIPHERAL,
+};
+static struct clk pwm_clk = {
+ .name = "pwm_clk",
+ .pmc_mask = 1 << AT91SAM9X5_ID_PWM,
+ .type = CLK_TYPE_PERIPHERAL,
+};
+static struct clk adc_clk = {
+ .name = "adc_clk",
+ .pmc_mask = 1 << AT91SAM9X5_ID_ADC,
+ .type = CLK_TYPE_PERIPHERAL,
+};
+static struct clk dma0_clk = {
+ .name = "dma0_clk",
+ .pmc_mask = 1 << AT91SAM9X5_ID_DMA0,
+ .type = CLK_TYPE_PERIPHERAL,
+};
+static struct clk dma1_clk = {
+ .name = "dma1_clk",
+ .pmc_mask = 1 << AT91SAM9X5_ID_DMA1,
+ .type = CLK_TYPE_PERIPHERAL,
+};
+static struct clk uhphs_clk = {
+ .name = "uhphs_clk",
+ .pmc_mask = 1 << AT91SAM9X5_ID_UHPHS,
+ .type = CLK_TYPE_PERIPHERAL,
+};
+static struct clk udphs_clk = {
+ .name = "udphs_clk",
+ .pmc_mask = 1 << AT91SAM9X5_ID_UDPHS,
+ .type = CLK_TYPE_PERIPHERAL,
+};
+/* emac0 clock - Only for sam9g25/sam9x25/sam9g35/sam9x35 */
+static struct clk macb0_clk = {
+ .name = "pclk",
+ .pmc_mask = 1 << AT91SAM9X5_ID_EMAC0,
+ .type = CLK_TYPE_PERIPHERAL,
+};
+/* lcd clock - Only for sam9g15/sam9g35/sam9x35 */
+static struct clk lcdc_clk = {
+ .name = "lcdc_clk",
+ .pmc_mask = 1 << AT91SAM9X5_ID_LCDC,
+ .type = CLK_TYPE_PERIPHERAL,
+};
+/* isi clock - Only for sam9g25 */
+static struct clk isi_clk = {
+ .name = "isi_clk",
+ .pmc_mask = 1 << AT91SAM9X5_ID_ISI,
+ .type = CLK_TYPE_PERIPHERAL,
+};
+static struct clk mmc1_clk = {
+ .name = "mci1_clk",
+ .pmc_mask = 1 << AT91SAM9X5_ID_MCI1,
+ .type = CLK_TYPE_PERIPHERAL,
+};
+/* emac1 clock - Only for sam9x25 */
+static struct clk macb1_clk = {
+ .name = "pclk",
+ .pmc_mask = 1 << AT91SAM9X5_ID_EMAC1,
+ .type = CLK_TYPE_PERIPHERAL,
+};
+static struct clk ssc_clk = {
+ .name = "ssc_clk",
+ .pmc_mask = 1 << AT91SAM9X5_ID_SSC,
+ .type = CLK_TYPE_PERIPHERAL,
+};
+/* can0 clock - Only for sam9x35 */
+static struct clk can0_clk = {
+ .name = "can0_clk",
+ .pmc_mask = 1 << AT91SAM9X5_ID_CAN0,
+ .type = CLK_TYPE_PERIPHERAL,
+};
+/* can1 clock - Only for sam9x35 */
+static struct clk can1_clk = {
+ .name = "can1_clk",
+ .pmc_mask = 1 << AT91SAM9X5_ID_CAN1,
+ .type = CLK_TYPE_PERIPHERAL,
+};
+
+static struct clk *periph_clocks[] __initdata = {
+ &pioAB_clk,
+ &pioCD_clk,
+ &smd_clk,
+ &usart0_clk,
+ &usart1_clk,
+ &usart2_clk,
+ &twi0_clk,
+ &twi1_clk,
+ &twi2_clk,
+ &mmc0_clk,
+ &spi0_clk,
+ &spi1_clk,
+ &uart0_clk,
+ &uart1_clk,
+ &tcb0_clk,
+ &pwm_clk,
+ &adc_clk,
+ &dma0_clk,
+ &dma1_clk,
+ &uhphs_clk,
+ &udphs_clk,
+ &mmc1_clk,
+ &ssc_clk,
+ // irq0
+};
+
+static struct clk_lookup periph_clocks_lookups[] = {
+ /* lookup table for DT entries */
+ CLKDEV_CON_DEV_ID("usart", "fffff200.serial", &mck),
+ CLKDEV_CON_DEV_ID("usart", "f801c000.serial", &usart0_clk),
+ CLKDEV_CON_DEV_ID("usart", "f8020000.serial", &usart1_clk),
+ CLKDEV_CON_DEV_ID("usart", "f8024000.serial", &usart2_clk),
+ CLKDEV_CON_DEV_ID("usart", "f8028000.serial", &usart3_clk),
+ CLKDEV_CON_DEV_ID("t0_clk", "f8008000.timer", &tcb0_clk),
+ CLKDEV_CON_DEV_ID("t0_clk", "f800c000.timer", &tcb0_clk),
+ CLKDEV_CON_ID("pioA", &pioAB_clk),
+ CLKDEV_CON_ID("pioB", &pioAB_clk),
+ CLKDEV_CON_ID("pioC", &pioCD_clk),
+ CLKDEV_CON_ID("pioD", &pioCD_clk),
+ /* additional fake clock for macb_hclk */
+ CLKDEV_CON_DEV_ID("hclk", "f802c000.ethernet", &macb0_clk),
+ CLKDEV_CON_DEV_ID("hclk", "f8030000.ethernet", &macb1_clk),
+};
+
+/*
+ * The two programmable clocks.
+ * You must configure pin multiplexing to bring these signals out.
+ */
+static struct clk pck0 = {
+ .name = "pck0",
+ .pmc_mask = AT91_PMC_PCK0,
+ .type = CLK_TYPE_PROGRAMMABLE,
+ .id = 0,
+};
+static struct clk pck1 = {
+ .name = "pck1",
+ .pmc_mask = AT91_PMC_PCK1,
+ .type = CLK_TYPE_PROGRAMMABLE,
+ .id = 1,
+};
+
+static void __init at91sam9x5_register_clocks(void)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(periph_clocks); i++)
+ clk_register(periph_clocks[i]);
+
+ clkdev_add_table(periph_clocks_lookups,
+ ARRAY_SIZE(periph_clocks_lookups));
+
+ if (cpu_is_at91sam9g25()
+ || cpu_is_at91sam9x25())
+ clk_register(&usart3_clk);
+
+ if (cpu_is_at91sam9g25()
+ || cpu_is_at91sam9x25()
+ || cpu_is_at91sam9g35()
+ || cpu_is_at91sam9x35())
+ clk_register(&macb0_clk);
+
+ if (cpu_is_at91sam9g15()
+ || cpu_is_at91sam9g35()
+ || cpu_is_at91sam9x35())
+ clk_register(&lcdc_clk);
+
+ if (cpu_is_at91sam9g25())
+ clk_register(&isi_clk);
+
+ if (cpu_is_at91sam9x25())
+ clk_register(&macb1_clk);
+
+ if (cpu_is_at91sam9x25()
+ || cpu_is_at91sam9x35()) {
+ clk_register(&can0_clk);
+ clk_register(&can1_clk);
+ }
+
+ clk_register(&pck0);
+ clk_register(&pck1);
+}
+
+/* --------------------------------------------------------------------
+ * AT91SAM9x5 processor initialization
+ * -------------------------------------------------------------------- */
+
+static void __init at91sam9x5_map_io(void)
+{
+ at91_init_sram(0, AT91SAM9X5_SRAM_BASE, AT91SAM9X5_SRAM_SIZE);
+}
+
+static void __init at91sam9x5_ioremap_registers(void)
+{
+ if (of_at91sam926x_pit_init() < 0)
+ panic("Impossible to find PIT\n");
+}
+
+void __init at91sam9x5_initialize(void)
+{
+ arm_pm_restart = at91sam9g45_restart;
+ at91_extern_irq = (1 << AT91SAM9X5_ID_IRQ0);
+
+ /* Register GPIO subsystem (using DT) */
+ at91_gpio_init(NULL, 0);
+}
+
+/* --------------------------------------------------------------------
+ * AT91SAM9x5 devices (temporary before modification of code)
+ * -------------------------------------------------------------------- */
+void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins) {}
+void __init at91_set_serial_console(unsigned portnr) {}
+struct platform_device *atmel_default_console_device = NULL;
+
+void __init at91_add_device_nand(struct atmel_nand_data *data) {}
+
+/* --------------------------------------------------------------------
+ * Interrupt initialization
+ * -------------------------------------------------------------------- */
+/*
+ * The default interrupt priority levels (0 = lowest, 7 = highest).
+ */
+static unsigned int at91sam9x5_default_irq_priority[NR_AIC_IRQS] __initdata = {
+ 7, /* Advanced Interrupt Controller (FIQ) */
+ 7, /* System Peripherals */
+ 1, /* Parallel IO Controller A and B */
+ 1, /* Parallel IO Controller C and D */
+ 4, /* Soft Modem */
+ 5, /* USART 0 */
+ 5, /* USART 1 */
+ 5, /* USART 2 */
+ 5, /* USART 3 */
+ 6, /* Two-Wire Interface 0 */
+ 6, /* Two-Wire Interface 1 */
+ 6, /* Two-Wire Interface 2 */
+ 0, /* Multimedia Card Interface 0 */
+ 5, /* Serial Peripheral Interface 0 */
+ 5, /* Serial Peripheral Interface 1 */
+ 5, /* UART 0 */
+ 5, /* UART 1 */
+ 0, /* Timer Counter 0, 1, 2, 3, 4 and 5 */
+ 0, /* Pulse Width Modulation Controller */
+ 0, /* ADC Controller */
+ 0, /* DMA Controller 0 */
+ 0, /* DMA Controller 1 */
+ 2, /* USB Host High Speed port */
+ 2, /* USB Device High speed port */
+ 3, /* Ethernet MAC 0 */
+ 3, /* LDC Controller or Image Sensor Interface */
+ 0, /* Multimedia Card Interface 1 */
+ 3, /* Ethernet MAC 1 */
+ 4, /* Synchronous Serial Interface */
+ 4, /* CAN Controller 0 */
+ 4, /* CAN Controller 1 */
+ 0, /* Advanced Interrupt Controller (IRQ0) */
+};
+
+struct at91_init_soc __initdata at91sam9x5_soc = {
+ .map_io = at91sam9x5_map_io,
+ .default_irq_priority = at91sam9x5_default_irq_priority,
+ .ioremap_registers = at91sam9x5_ioremap_registers,
+ .register_clocks = at91sam9x5_register_clocks,
+ .init = at91sam9x5_initialize,
+};
diff --git a/arch/arm/mach-at91/board-dt.c b/arch/arm/mach-at91/board-dt.c
index bb6b434ec0c1..05793156d178 100644
--- a/arch/arm/mach-at91/board-dt.c
+++ b/arch/arm/mach-at91/board-dt.c
@@ -109,6 +109,7 @@ static void __init at91_dt_device_init(void)
static const char *at91_dt_board_compat[] __initdata = {
"atmel,at91sam9m10g45ek",
+ "atmel,at91sam9x5ek",
"calao,usb-a9g20",
NULL
};
diff --git a/arch/arm/mach-at91/clock.c b/arch/arm/mach-at91/clock.c
index aa04e22a9da6..a5291e0e7004 100644
--- a/arch/arm/mach-at91/clock.c
+++ b/arch/arm/mach-at91/clock.c
@@ -48,24 +48,37 @@
* Chips have some kind of clocks : group them by functionality
*/
#define cpu_has_utmi() ( cpu_is_at91sam9rl() \
- || cpu_is_at91sam9g45())
+ || cpu_is_at91sam9g45() \
+ || cpu_is_at91sam9x5())
#define cpu_has_800M_plla() ( cpu_is_at91sam9g20() \
- || cpu_is_at91sam9g45())
+ || cpu_is_at91sam9g45() \
+ || cpu_is_at91sam9x5())
#define cpu_has_300M_plla() (cpu_is_at91sam9g10())
#define cpu_has_pllb() (!(cpu_is_at91sam9rl() \
- || cpu_is_at91sam9g45()))
+ || cpu_is_at91sam9g45() \
+ || cpu_is_at91sam9x5()))
-#define cpu_has_upll() (cpu_is_at91sam9g45())
+#define cpu_has_upll() (cpu_is_at91sam9g45() \
+ || cpu_is_at91sam9x5())
/* USB host HS & FS */
#define cpu_has_uhp() (!cpu_is_at91sam9rl())
/* USB device FS only */
#define cpu_has_udpfs() (!(cpu_is_at91sam9rl() \
- || cpu_is_at91sam9g45()))
+ || cpu_is_at91sam9g45() \
+ || cpu_is_at91sam9x5()))
+
+#define cpu_has_plladiv2() (cpu_is_at91sam9g45() \
+ || cpu_is_at91sam9x5())
+
+#define cpu_has_mdiv3() (cpu_is_at91sam9g45() \
+ || cpu_is_at91sam9x5())
+
+#define cpu_has_alt_prescaler() (cpu_is_at91sam9x5())
static LIST_HEAD(clocks);
static DEFINE_SPINLOCK(clk_lock);
@@ -138,13 +151,6 @@ static void pmc_uckr_mode(struct clk *clk, int is_on)
{
unsigned int uckr = at91_sys_read(AT91_CKGR_UCKR);
- if (cpu_is_at91sam9g45()) {
- if (is_on)
- uckr |= AT91_PMC_BIASEN;
- else
- uckr &= ~AT91_PMC_BIASEN;
- }
-
if (is_on) {
is_on = AT91_PMC_LOCKU;
at91_sys_write(AT91_CKGR_UCKR, uckr | clk->pmc_mask);
@@ -209,11 +215,24 @@ static struct clk __init *at91_css_to_clk(unsigned long css)
return &utmi_clk;
else if (cpu_has_pllb())
return &pllb;
+ break;
+ /* alternate PMC: can use master clock */
+ case AT91_PMC_CSS_MASTER:
+ return &mck;
}
return NULL;
}
+static int pmc_prescaler_divider(u32 reg)
+{
+ if (cpu_has_alt_prescaler()) {
+ return 1 << ((reg & AT91_PMC_ALT_PRES) >> PMC_ALT_PRES_OFFSET);
+ } else {
+ return 1 << ((reg & AT91_PMC_PRES) >> PMC_PRES_OFFSET);
+ }
+}
+
static void __clk_enable(struct clk *clk)
{
if (clk->parent)
@@ -315,12 +334,22 @@ int clk_set_rate(struct clk *clk, unsigned long rate)
{
unsigned long flags;
unsigned prescale;
+ unsigned long prescale_offset, css_mask;
unsigned long actual;
if (!clk_is_programmable(clk))
return -EINVAL;
if (clk->users)
return -EBUSY;
+
+ if (cpu_has_alt_prescaler()) {
+ prescale_offset = PMC_ALT_PRES_OFFSET;
+ css_mask = AT91_PMC_ALT_PCKR_CSS;
+ } else {
+ prescale_offset = PMC_PRES_OFFSET;
+ css_mask = AT91_PMC_CSS;
+ }
+
spin_lock_irqsave(&clk_lock, flags);
actual = clk->parent->rate_hz;
@@ -329,8 +358,8 @@ int clk_set_rate(struct clk *clk, unsigned long rate)
u32 pckr;
pckr = at91_sys_read(AT91_PMC_PCKR(clk->id));
- pckr &= AT91_PMC_CSS; /* clock selection */
- pckr |= prescale << 2;
+ pckr &= css_mask; /* keep clock selection */
+ pckr |= prescale << prescale_offset;
at91_sys_write(AT91_PMC_PCKR(clk->id), pckr);
clk->rate_hz = actual;
break;
@@ -377,11 +406,17 @@ static void __init init_programmable_clock(struct clk *clk)
{
struct clk *parent;
u32 pckr;
+ unsigned int css_mask;
+
+ if (cpu_has_alt_prescaler())
+ css_mask = AT91_PMC_ALT_PCKR_CSS;
+ else
+ css_mask = AT91_PMC_CSS;
pckr = at91_sys_read(AT91_PMC_PCKR(clk->id));
- parent = at91_css_to_clk(pckr & AT91_PMC_CSS);
+ parent = at91_css_to_clk(pckr & css_mask);
clk->parent = parent;
- clk->rate_hz = parent->rate_hz / (1 << ((pckr & AT91_PMC_PRES) >> 2));
+ clk->rate_hz = parent->rate_hz / pmc_prescaler_divider(pckr);
}
#endif /* CONFIG_AT91_PROGRAMMABLE_CLOCKS */
@@ -663,7 +698,7 @@ int __init at91_clock_init(unsigned long main_clock)
if (pll_overclock)
pr_info("Clocks: PLLA overclocked, %ld MHz\n", plla.rate_hz / 1000000);
- if (cpu_is_at91sam9g45()) {
+ if (cpu_has_plladiv2()) {
mckr = at91_sys_read(AT91_PMC_MCKR);
plla.rate_hz /= (1 << ((mckr & AT91_PMC_PLLADIV2) >> 12)); /* plla divisor by 2 */
}
@@ -685,6 +720,10 @@ int __init at91_clock_init(unsigned long main_clock)
* (obtain the USB High Speed 480 MHz when input is 12 MHz)
*/
utmi_clk.rate_hz = 40 * utmi_clk.parent->rate_hz;
+
+ /* UTMI bias and PLL are managed at the same time */
+ if (cpu_has_upll())
+ utmi_clk.pmc_mask |= AT91_PMC_BIASEN;
}
/*
@@ -703,7 +742,7 @@ int __init at91_clock_init(unsigned long main_clock)
mckr = at91_sys_read(AT91_PMC_MCKR);
mck.parent = at91_css_to_clk(mckr & AT91_PMC_CSS);
freq = mck.parent->rate_hz;
- freq /= (1 << ((mckr & AT91_PMC_PRES) >> 2)); /* prescale */
+ freq /= pmc_prescaler_divider(mckr); /* prescale */
if (cpu_is_at91rm9200()) {
mck.rate_hz = freq / (1 + ((mckr & AT91_PMC_MDIV) >> 8)); /* mdiv */
} else if (cpu_is_at91sam9g20()) {
@@ -711,13 +750,19 @@ int __init at91_clock_init(unsigned long main_clock)
freq / ((mckr & AT91_PMC_MDIV) >> 7) : freq; /* mdiv ; (x >> 7) = ((x >> 8) * 2) */
if (mckr & AT91_PMC_PDIV)
freq /= 2; /* processor clock division */
- } else if (cpu_is_at91sam9g45()) {
+ } else if (cpu_has_mdiv3()) {
mck.rate_hz = (mckr & AT91_PMC_MDIV) == AT91SAM9_PMC_MDIV_3 ?
freq / 3 : freq / (1 << ((mckr & AT91_PMC_MDIV) >> 8)); /* mdiv */
} else {
mck.rate_hz = freq / (1 << ((mckr & AT91_PMC_MDIV) >> 8)); /* mdiv */
}
+ if (cpu_has_alt_prescaler()) {
+ /* Programmable clocks can use MCK */
+ mck.type |= CLK_TYPE_PRIMARY;
+ mck.id = 4;
+ }
+
/* Register the PMC's standard clocks */
for (i = 0; i < ARRAY_SIZE(standard_pmc_clocks); i++)
at91_clk_add(standard_pmc_clocks[i]);
diff --git a/arch/arm/mach-at91/include/mach/at91_pmc.h b/arch/arm/mach-at91/include/mach/at91_pmc.h
index dbdd6ae473d5..f9fdbbe0c53a 100644
--- a/arch/arm/mach-at91/include/mach/at91_pmc.h
+++ b/arch/arm/mach-at91/include/mach/at91_pmc.h
@@ -45,9 +45,13 @@
#define AT91_PMC_BIASCOUNT (0xf << 28) /* UTMI BIAS Start-up Time */
#define AT91_CKGR_MOR (AT91_PMC + 0x20) /* Main Oscillator Register [not on SAM9RL] */
-#define AT91_PMC_MOSCEN (1 << 0) /* Main Oscillator Enable */
-#define AT91_PMC_OSCBYPASS (1 << 1) /* Oscillator Bypass [SAM9x] */
-#define AT91_PMC_OSCOUNT (0xff << 8) /* Main Oscillator Start-up Time */
+#define AT91_PMC_MOSCEN (1 << 0) /* Main Oscillator Enable */
+#define AT91_PMC_OSCBYPASS (1 << 1) /* Oscillator Bypass */
+#define AT91_PMC_MOSCRCEN (1 << 3) /* Main On-Chip RC Oscillator Enable [some SAM9] */
+#define AT91_PMC_OSCOUNT (0xff << 8) /* Main Oscillator Start-up Time */
+#define AT91_PMC_KEY (0x37 << 16) /* MOR Writing Key */
+#define AT91_PMC_MOSCSEL (1 << 24) /* Main Oscillator Selection [some SAM9] */
+#define AT91_PMC_CFDEN (1 << 25) /* Clock Failure Detector Enable [some SAM9] */
#define AT91_CKGR_MCFR (AT91_PMC + 0x24) /* Main Clock Frequency Register */
#define AT91_PMC_MAINF (0xffff << 0) /* Main Clock Frequency */
@@ -72,14 +76,24 @@
#define AT91_PMC_CSS_PLLA (2 << 0)
#define AT91_PMC_CSS_PLLB (3 << 0)
#define AT91_PMC_CSS_UPLL (3 << 0) /* [some SAM9 only] */
-#define AT91_PMC_PRES (7 << 2) /* Master Clock Prescaler */
-#define AT91_PMC_PRES_1 (0 << 2)
-#define AT91_PMC_PRES_2 (1 << 2)
-#define AT91_PMC_PRES_4 (2 << 2)
-#define AT91_PMC_PRES_8 (3 << 2)
-#define AT91_PMC_PRES_16 (4 << 2)
-#define AT91_PMC_PRES_32 (5 << 2)
-#define AT91_PMC_PRES_64 (6 << 2)
+#define PMC_PRES_OFFSET 2
+#define AT91_PMC_PRES (7 << PMC_PRES_OFFSET) /* Master Clock Prescaler */
+#define AT91_PMC_PRES_1 (0 << PMC_PRES_OFFSET)
+#define AT91_PMC_PRES_2 (1 << PMC_PRES_OFFSET)
+#define AT91_PMC_PRES_4 (2 << PMC_PRES_OFFSET)
+#define AT91_PMC_PRES_8 (3 << PMC_PRES_OFFSET)
+#define AT91_PMC_PRES_16 (4 << PMC_PRES_OFFSET)
+#define AT91_PMC_PRES_32 (5 << PMC_PRES_OFFSET)
+#define AT91_PMC_PRES_64 (6 << PMC_PRES_OFFSET)
+#define PMC_ALT_PRES_OFFSET 4
+#define AT91_PMC_ALT_PRES (7 << PMC_ALT_PRES_OFFSET) /* Master Clock Prescaler [alternate location] */
+#define AT91_PMC_ALT_PRES_1 (0 << PMC_ALT_PRES_OFFSET)
+#define AT91_PMC_ALT_PRES_2 (1 << PMC_ALT_PRES_OFFSET)
+#define AT91_PMC_ALT_PRES_4 (2 << PMC_ALT_PRES_OFFSET)
+#define AT91_PMC_ALT_PRES_8 (3 << PMC_ALT_PRES_OFFSET)
+#define AT91_PMC_ALT_PRES_16 (4 << PMC_ALT_PRES_OFFSET)
+#define AT91_PMC_ALT_PRES_32 (5 << PMC_ALT_PRES_OFFSET)
+#define AT91_PMC_ALT_PRES_64 (6 << PMC_ALT_PRES_OFFSET)
#define AT91_PMC_MDIV (3 << 8) /* Master Clock Division */
#define AT91RM9200_PMC_MDIV_1 (0 << 8) /* [AT91RM9200 only] */
#define AT91RM9200_PMC_MDIV_2 (1 << 8)
@@ -103,7 +117,14 @@
#define AT91_PMC_USBS_UPLL (1 << 0)
#define AT91_PMC_OHCIUSBDIV (0xF << 8) /* Divider for USB OHCI Clock */
+#define AT91_PMC_SMD (AT91_PMC + 0x3c) /* Soft Modem Clock Register [some SAM9 only] */
+#define AT91_PMC_SMDS (0x1 << 0) /* SMD input clock selection */
+#define AT91_PMC_SMD_DIV (0x1f << 8) /* SMD input clock divider */
+#define AT91_PMC_SMDDIV(n) (((n) << 8) & AT91_PMC_SMD_DIV)
+
#define AT91_PMC_PCKR(n) (AT91_PMC + 0x40 + ((n) * 4)) /* Programmable Clock 0-N Registers */
+#define AT91_PMC_ALT_PCKR_CSS (0x7 << 0) /* Programmable Clock Source Selection [alternate length] */
+#define AT91_PMC_CSS_MASTER (4 << 0) /* [some SAM9 only] */
#define AT91_PMC_CSSMCK (0x1 << 8) /* CSS or Master Clock Selection */
#define AT91_PMC_CSSMCK_CSS (0 << 8)
#define AT91_PMC_CSSMCK_MCK (1 << 8)
@@ -120,10 +141,25 @@
#define AT91_PMC_PCK1RDY (1 << 9) /* Programmable Clock 1 */
#define AT91_PMC_PCK2RDY (1 << 10) /* Programmable Clock 2 */
#define AT91_PMC_PCK3RDY (1 << 11) /* Programmable Clock 3 */
+#define AT91_PMC_MOSCSELS (1 << 16) /* Main Oscillator Selection [some SAM9] */
+#define AT91_PMC_MOSCRCS (1 << 17) /* Main On-Chip RC [some SAM9] */
+#define AT91_PMC_CFDEV (1 << 18) /* Clock Failure Detector Event [some SAM9] */
#define AT91_PMC_IMR (AT91_PMC + 0x6c) /* Interrupt Mask Register */
#define AT91_PMC_PROT (AT91_PMC + 0xe4) /* Write Protect Mode Register [some SAM9] */
-#define AT91_PMC_PROTKEY 0x504d4301 /* Activation Code */
+#define AT91_PMC_WPEN (0x1 << 0) /* Write Protect Enable */
+#define AT91_PMC_WPKEY (0xffffff << 8) /* Write Protect Key */
+#define AT91_PMC_PROTKEY (0x504d43 << 8) /* Activation Code */
+
+#define AT91_PMC_WPSR (AT91_PMC + 0xe8) /* Write Protect Status Register [some SAM9] */
+#define AT91_PMC_WPVS (0x1 << 0) /* Write Protect Violation Status */
+#define AT91_PMC_WPVSRC (0xffff << 8) /* Write Protect Violation Source */
+#define AT91_PMC_PCR (AT91_PMC + 0x10c) /* Peripheral Control Register [some SAM9] */
+#define AT91_PMC_PCR_PID (0x3f << 0) /* Peripheral ID */
+#define AT91_PMC_PCR_CMD (0x1 << 12) /* Command */
+#define AT91_PMC_PCR_DIV (0x3 << 16) /* Divisor Value */
+#define AT91_PMC_PCRDIV(n) (((n) << 16) & AT91_PMC_PCR_DIV)
+#define AT91_PMC_PCR_EN (0x1 << 28) /* Enable */
#endif
diff --git a/arch/arm/mach-at91/include/mach/at91sam9x5.h b/arch/arm/mach-at91/include/mach/at91sam9x5.h
new file mode 100644
index 000000000000..8476871a2f9f
--- /dev/null
+++ b/arch/arm/mach-at91/include/mach/at91sam9x5.h
@@ -0,0 +1,80 @@
+/*
+ * Chip-specific header file for the AT91SAM9x5 family
+ *
+ * Copyright (C) 2009-2012 Atmel Corporation.
+ *
+ * Common definitions.
+ * Based on AT91SAM9x5 datasheet.
+ *
+ * Licensed under GPLv2 or later.
+ */
+
+#ifndef AT91SAM9X5_H
+#define AT91SAM9X5_H
+
+/*
+ * Peripheral identifiers/interrupts.
+ */
+#define AT91SAM9X5_ID_PIOAB 2 /* Parallel I/O Controller A and B */
+#define AT91SAM9X5_ID_PIOCD 3 /* Parallel I/O Controller C and D */
+#define AT91SAM9X5_ID_SMD 4 /* SMD Soft Modem (SMD) */
+#define AT91SAM9X5_ID_USART0 5 /* USART 0 */
+#define AT91SAM9X5_ID_USART1 6 /* USART 1 */
+#define AT91SAM9X5_ID_USART2 7 /* USART 2 */
+#define AT91SAM9X5_ID_USART3 8 /* USART 3 */
+#define AT91SAM9X5_ID_TWI0 9 /* Two-Wire Interface 0 */
+#define AT91SAM9X5_ID_TWI1 10 /* Two-Wire Interface 1 */
+#define AT91SAM9X5_ID_TWI2 11 /* Two-Wire Interface 2 */
+#define AT91SAM9X5_ID_MCI0 12 /* High Speed Multimedia Card Interface 0 */
+#define AT91SAM9X5_ID_SPI0 13 /* Serial Peripheral Interface 0 */
+#define AT91SAM9X5_ID_SPI1 14 /* Serial Peripheral Interface 1 */
+#define AT91SAM9X5_ID_UART0 15 /* UART 0 */
+#define AT91SAM9X5_ID_UART1 16 /* UART 1 */
+#define AT91SAM9X5_ID_TCB 17 /* Timer Counter 0, 1, 2, 3, 4 and 5 */
+#define AT91SAM9X5_ID_PWM 18 /* Pulse Width Modulation Controller */
+#define AT91SAM9X5_ID_ADC 19 /* ADC Controller */
+#define AT91SAM9X5_ID_DMA0 20 /* DMA Controller 0 */
+#define AT91SAM9X5_ID_DMA1 21 /* DMA Controller 1 */
+#define AT91SAM9X5_ID_UHPHS 22 /* USB Host High Speed */
+#define AT91SAM9X5_ID_UDPHS 23 /* USB Device High Speed */
+#define AT91SAM9X5_ID_EMAC0 24 /* Ethernet MAC0 */
+#define AT91SAM9X5_ID_LCDC 25 /* LCD Controller */
+#define AT91SAM9X5_ID_ISI 25 /* Image Sensor Interface */
+#define AT91SAM9X5_ID_MCI1 26 /* High Speed Multimedia Card Interface 1 */
+#define AT91SAM9X5_ID_EMAC1 27 /* Ethernet MAC1 */
+#define AT91SAM9X5_ID_SSC 28 /* Synchronous Serial Controller */
+#define AT91SAM9X5_ID_CAN0 29 /* CAN Controller 0 */
+#define AT91SAM9X5_ID_CAN1 30 /* CAN Controller 1 */
+#define AT91SAM9X5_ID_IRQ0 31 /* Advanced Interrupt Controller */
+
+/*
+ * User Peripheral physical base addresses.
+ */
+#define AT91SAM9X5_BASE_USART0 0xf801c000
+#define AT91SAM9X5_BASE_USART1 0xf8020000
+#define AT91SAM9X5_BASE_USART2 0xf8024000
+
+/*
+ * System Peripherals (offset from AT91_BASE_SYS)
+ */
+#define AT91_DDRSDRC0 (0xffffe800 - AT91_BASE_SYS)
+#define AT91_PMC (0xfffffc00 - AT91_BASE_SYS)
+
+/*
+ * Base addresses for early serial code (uncompress.h)
+ */
+#define AT91_DBGU AT91_BASE_DBGU0
+#define AT91_USART0 AT91SAM9X5_BASE_USART0
+#define AT91_USART1 AT91SAM9X5_BASE_USART1
+#define AT91_USART2 AT91SAM9X5_BASE_USART2
+
+/*
+ * Internal Memory.
+ */
+#define AT91SAM9X5_SRAM_BASE 0x00300000 /* Internal SRAM base address */
+#define AT91SAM9X5_SRAM_SIZE SZ_32K /* Internal SRAM size (32Kb) */
+
+#define AT91SAM9X5_ROM_BASE 0x00400000 /* Internal ROM base address */
+#define AT91SAM9X5_ROM_SIZE SZ_64K /* Internal ROM size (64Kb) */
+
+#endif
diff --git a/arch/arm/mach-at91/include/mach/at91sam9x5_matrix.h b/arch/arm/mach-at91/include/mach/at91sam9x5_matrix.h
new file mode 100644
index 000000000000..a606d3966470
--- /dev/null
+++ b/arch/arm/mach-at91/include/mach/at91sam9x5_matrix.h
@@ -0,0 +1,53 @@
+/*
+ * Matrix-centric header file for the AT91SAM9x5 family
+ *
+ * Copyright (C) 2009-2012 Atmel Corporation.
+ *
+ * Only EBI related registers.
+ * Write Protect register definitions may be useful.
+ *
+ * Licensed under GPLv2 or later.
+ */
+
+#ifndef AT91SAM9X5_MATRIX_H
+#define AT91SAM9X5_MATRIX_H
+
+#define AT91_MATRIX_EBICSA (AT91_MATRIX + 0x120) /* EBI Chip Select Assignment Register */
+#define AT91_MATRIX_EBI_CS1A (1 << 1) /* Chip Select 1 Assignment */
+#define AT91_MATRIX_EBI_CS1A_SMC (0 << 1)
+#define AT91_MATRIX_EBI_CS1A_SDRAMC (1 << 1)
+#define AT91_MATRIX_EBI_CS3A (1 << 3) /* Chip Select 3 Assignment */
+#define AT91_MATRIX_EBI_CS3A_SMC (0 << 3)
+#define AT91_MATRIX_EBI_CS3A_SMC_NANDFLASH (1 << 3)
+#define AT91_MATRIX_EBI_DBPUC (1 << 8) /* Data Bus Pull-up Configuration */
+#define AT91_MATRIX_EBI_DBPU_ON (0 << 8)
+#define AT91_MATRIX_EBI_DBPU_OFF (1 << 8)
+#define AT91_MATRIX_EBI_VDDIOMSEL (1 << 16) /* Memory voltage selection */
+#define AT91_MATRIX_EBI_VDDIOMSEL_1_8V (0 << 16)
+#define AT91_MATRIX_EBI_VDDIOMSEL_3_3V (1 << 16)
+#define AT91_MATRIX_EBI_EBI_IOSR (1 << 17) /* EBI I/O slew rate selection */
+#define AT91_MATRIX_EBI_EBI_IOSR_REDUCED (0 << 17)
+#define AT91_MATRIX_EBI_EBI_IOSR_NORMAL (1 << 17)
+#define AT91_MATRIX_EBI_DDR_IOSR (1 << 18) /* DDR2 dedicated port I/O slew rate selection */
+#define AT91_MATRIX_EBI_DDR_IOSR_REDUCED (0 << 18)
+#define AT91_MATRIX_EBI_DDR_IOSR_NORMAL (1 << 18)
+#define AT91_MATRIX_NFD0_SELECT (1 << 24) /* NAND Flash Data Bus Selection */
+#define AT91_MATRIX_NFD0_ON_D0 (0 << 24)
+#define AT91_MATRIX_NFD0_ON_D16 (1 << 24)
+#define AT91_MATRIX_DDR_MP_EN (1 << 25) /* DDR Multi-port Enable */
+#define AT91_MATRIX_MP_OFF (0 << 25)
+#define AT91_MATRIX_MP_ON (1 << 25)
+
+#define AT91_MATRIX_WPMR (AT91_MATRIX + 0x1E4) /* Write Protect Mode Register */
+#define AT91_MATRIX_WPMR_WPEN (1 << 0) /* Write Protect ENable */
+#define AT91_MATRIX_WPMR_WP_WPDIS (0 << 0)
+#define AT91_MATRIX_WPMR_WP_WPEN (1 << 0)
+#define AT91_MATRIX_WPMR_WPKEY (0xFFFFFF << 8) /* Write Protect KEY */
+
+#define AT91_MATRIX_WPSR (AT91_MATRIX + 0x1E8) /* Write Protect Status Register */
+#define AT91_MATRIX_WPSR_WPVS (1 << 0) /* Write Protect Violation Status */
+#define AT91_MATRIX_WPSR_NO_WPV (0 << 0)
+#define AT91_MATRIX_WPSR_WPV (1 << 0)
+#define AT91_MATRIX_WPSR_WPVSRC (0xFFFF << 8) /* Write Protect Violation Source */
+
+#endif
diff --git a/arch/arm/mach-at91/include/mach/hardware.h b/arch/arm/mach-at91/include/mach/hardware.h
index c213f28628c0..fd7dce4f7378 100644
--- a/arch/arm/mach-at91/include/mach/hardware.h
+++ b/arch/arm/mach-at91/include/mach/hardware.h
@@ -34,6 +34,8 @@
#include <mach/at91sam9rl.h>
#elif defined(CONFIG_ARCH_AT91SAM9G45)
#include <mach/at91sam9g45.h>
+#elif defined(CONFIG_ARCH_AT91SAM9X5)
+#include <mach/at91sam9x5.h>
#elif defined(CONFIG_ARCH_AT91X40)
#include <mach/at91x40.h>
#else
diff --git a/arch/arm/mach-exynos/clock-exynos4.c b/arch/arm/mach-exynos/clock-exynos4.c
index 31b59e65463a..060dde7d7ad6 100644
--- a/arch/arm/mach-exynos/clock-exynos4.c
+++ b/arch/arm/mach-exynos/clock-exynos4.c
@@ -471,6 +471,11 @@ static struct clk exynos4_init_clocks_off[] = {
.enable = exynos4_clk_ip_cam_ctrl,
.ctrlbit = (1 << 5),
}, {
+ .name = "jpeg",
+ .id = 0,
+ .enable = exynos4_clk_ip_cam_ctrl,
+ .ctrlbit = (1 << 6),
+ }, {
.name = "fimc",
.devname = "exynos4-fimc.0",
.enable = exynos4_clk_ip_cam_ctrl,
diff --git a/arch/arm/mach-exynos/common.c b/arch/arm/mach-exynos/common.c
index f494db872c67..97ca2592ce83 100644
--- a/arch/arm/mach-exynos/common.c
+++ b/arch/arm/mach-exynos/common.c
@@ -26,10 +26,12 @@
#include <asm/hardware/gic.h>
#include <asm/mach/map.h>
#include <asm/mach/irq.h>
+#include <asm/cacheflush.h>
#include <mach/regs-irq.h>
#include <mach/regs-pmu.h>
#include <mach/regs-gpio.h>
+#include <mach/pmu.h>
#include <plat/cpu.h>
#include <plat/clock.h>
@@ -45,6 +47,8 @@
#include <plat/regs-serial.h>
#include "common.h"
+#define L2_AUX_VAL 0x7C470001
+#define L2_AUX_MASK 0xC200ffff
static const char name_exynos4210[] = "EXYNOS4210";
static const char name_exynos4212[] = "EXYNOS4212";
@@ -173,7 +177,12 @@ static struct map_desc exynos4_iodesc[] __initdata = {
}, {
.virtual = (unsigned long)S5P_VA_DMC0,
.pfn = __phys_to_pfn(EXYNOS4_PA_DMC0),
- .length = SZ_4K,
+ .length = SZ_64K,
+ .type = MT_DEVICE,
+ }, {
+ .virtual = (unsigned long)S5P_VA_DMC1,
+ .pfn = __phys_to_pfn(EXYNOS4_PA_DMC1),
+ .length = SZ_64K,
.type = MT_DEVICE,
}, {
.virtual = (unsigned long)S3C_VA_USB_HSPHY,
@@ -433,23 +442,48 @@ core_initcall(exynos4_core_init);
#ifdef CONFIG_CACHE_L2X0
static int __init exynos4_l2x0_cache_init(void)
{
- /* TAG, Data Latency Control: 2cycle */
- __raw_writel(0x110, S5P_VA_L2CC + L2X0_TAG_LATENCY_CTRL);
+ int ret;
+ ret = l2x0_of_init(L2_AUX_VAL, L2_AUX_MASK);
+ if (!ret) {
+ l2x0_regs_phys = virt_to_phys(&l2x0_saved_regs);
+ clean_dcache_area(&l2x0_regs_phys, sizeof(unsigned long));
+ return 0;
+ }
- if (soc_is_exynos4210())
- __raw_writel(0x110, S5P_VA_L2CC + L2X0_DATA_LATENCY_CTRL);
- else if (soc_is_exynos4212() || soc_is_exynos4412())
- __raw_writel(0x120, S5P_VA_L2CC + L2X0_DATA_LATENCY_CTRL);
+ if (!(__raw_readl(S5P_VA_L2CC + L2X0_CTRL) & 0x1)) {
+ l2x0_saved_regs.phy_base = EXYNOS4_PA_L2CC;
+ /* TAG, Data Latency Control: 2 cycles */
+ l2x0_saved_regs.tag_latency = 0x110;
+
+ if (soc_is_exynos4212() || soc_is_exynos4412())
+ l2x0_saved_regs.data_latency = 0x120;
+ else
+ l2x0_saved_regs.data_latency = 0x110;
+
+ l2x0_saved_regs.prefetch_ctrl = 0x30000007;
+ l2x0_saved_regs.pwr_ctrl =
+ (L2X0_DYNAMIC_CLK_GATING_EN | L2X0_STNDBY_MODE_EN);
- /* L2X0 Prefetch Control */
- __raw_writel(0x30000007, S5P_VA_L2CC + L2X0_PREFETCH_CTRL);
+ l2x0_regs_phys = virt_to_phys(&l2x0_saved_regs);
- /* L2X0 Power Control */
- __raw_writel(L2X0_DYNAMIC_CLK_GATING_EN | L2X0_STNDBY_MODE_EN,
- S5P_VA_L2CC + L2X0_POWER_CTRL);
+ __raw_writel(l2x0_saved_regs.tag_latency,
+ S5P_VA_L2CC + L2X0_TAG_LATENCY_CTRL);
+ __raw_writel(l2x0_saved_regs.data_latency,
+ S5P_VA_L2CC + L2X0_DATA_LATENCY_CTRL);
- l2x0_init(S5P_VA_L2CC, 0x7C470001, 0xC200ffff);
+ /* L2X0 Prefetch Control */
+ __raw_writel(l2x0_saved_regs.prefetch_ctrl,
+ S5P_VA_L2CC + L2X0_PREFETCH_CTRL);
+
+ /* L2X0 Power Control */
+ __raw_writel(l2x0_saved_regs.pwr_ctrl,
+ S5P_VA_L2CC + L2X0_POWER_CTRL);
+
+ clean_dcache_area(&l2x0_regs_phys, sizeof(unsigned long));
+ clean_dcache_area(&l2x0_saved_regs, sizeof(struct l2x0_regs));
+ }
+ l2x0_init(S5P_VA_L2CC, L2_AUX_VAL, L2_AUX_MASK);
return 0;
}
diff --git a/arch/arm/mach-exynos/cpuidle.c b/arch/arm/mach-exynos/cpuidle.c
index 4ebb382c5979..33ab4e7558af 100644
--- a/arch/arm/mach-exynos/cpuidle.c
+++ b/arch/arm/mach-exynos/cpuidle.c
@@ -11,25 +11,53 @@
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/cpuidle.h>
+#include <linux/cpu_pm.h>
#include <linux/io.h>
#include <linux/export.h>
#include <linux/time.h>
#include <asm/proc-fns.h>
+#include <asm/smp_scu.h>
+#include <asm/suspend.h>
+#include <asm/unified.h>
+#include <mach/regs-pmu.h>
+#include <mach/pmu.h>
+
+#include <plat/cpu.h>
+
+#define REG_DIRECTGO_ADDR (samsung_rev() == EXYNOS4210_REV_1_1 ? \
+ S5P_INFORM7 : (samsung_rev() == EXYNOS4210_REV_1_0 ? \
+ (S5P_VA_SYSRAM + 0x24) : S5P_INFORM0))
+#define REG_DIRECTGO_FLAG (samsung_rev() == EXYNOS4210_REV_1_1 ? \
+ S5P_INFORM6 : (samsung_rev() == EXYNOS4210_REV_1_0 ? \
+ (S5P_VA_SYSRAM + 0x20) : S5P_INFORM1))
+
+#define S5P_CHECK_AFTR 0xFCBA0D10
static int exynos4_enter_idle(struct cpuidle_device *dev,
struct cpuidle_driver *drv,
int index);
+static int exynos4_enter_lowpower(struct cpuidle_device *dev,
+ struct cpuidle_driver *drv,
+ int index);
-static struct cpuidle_state exynos4_cpuidle_set[] = {
+static struct cpuidle_state exynos4_cpuidle_set[] __initdata = {
[0] = {
.enter = exynos4_enter_idle,
.exit_latency = 1,
.target_residency = 100000,
.flags = CPUIDLE_FLAG_TIME_VALID,
- .name = "IDLE",
+ .name = "C0",
.desc = "ARM clock gating(WFI)",
},
+ [1] = {
+ .enter = exynos4_enter_lowpower,
+ .exit_latency = 300,
+ .target_residency = 100000,
+ .flags = CPUIDLE_FLAG_TIME_VALID,
+ .name = "C1",
+ .desc = "ARM power down",
+ },
};
static DEFINE_PER_CPU(struct cpuidle_device, exynos4_cpuidle_device);
@@ -39,9 +67,102 @@ static struct cpuidle_driver exynos4_idle_driver = {
.owner = THIS_MODULE,
};
+/* Ext-GIC nIRQ/nFIQ is the only wakeup source in AFTR */
+static void exynos4_set_wakeupmask(void)
+{
+ __raw_writel(0x0000ff3e, S5P_WAKEUP_MASK);
+}
+
+static unsigned int g_pwr_ctrl, g_diag_reg;
+
+static void save_cpu_arch_register(void)
+{
+ /*read power control register*/
+ asm("mrc p15, 0, %0, c15, c0, 0" : "=r"(g_pwr_ctrl) : : "cc");
+ /*read diagnostic register*/
+ asm("mrc p15, 0, %0, c15, c0, 1" : "=r"(g_diag_reg) : : "cc");
+ return;
+}
+
+static void restore_cpu_arch_register(void)
+{
+ /*write power control register*/
+ asm("mcr p15, 0, %0, c15, c0, 0" : : "r"(g_pwr_ctrl) : "cc");
+ /*write diagnostic register*/
+ asm("mcr p15, 0, %0, c15, c0, 1" : : "r"(g_diag_reg) : "cc");
+ return;
+}
+
+static int idle_finisher(unsigned long flags)
+{
+ cpu_do_idle();
+ return 1;
+}
+
+static int exynos4_enter_core0_aftr(struct cpuidle_device *dev,
+ struct cpuidle_driver *drv,
+ int index)
+{
+ struct timeval before, after;
+ int idle_time;
+ unsigned long tmp;
+
+ local_irq_disable();
+ do_gettimeofday(&before);
+
+ exynos4_set_wakeupmask();
+
+ /* Set value of power down register for aftr mode */
+ exynos4_sys_powerdown_conf(SYS_AFTR);
+
+ __raw_writel(virt_to_phys(s3c_cpu_resume), REG_DIRECTGO_ADDR);
+ __raw_writel(S5P_CHECK_AFTR, REG_DIRECTGO_FLAG);
+
+ save_cpu_arch_register();
+
+ /* Setting Central Sequence Register for power down mode */
+ tmp = __raw_readl(S5P_CENTRAL_SEQ_CONFIGURATION);
+ tmp &= ~S5P_CENTRAL_LOWPWR_CFG;
+ __raw_writel(tmp, S5P_CENTRAL_SEQ_CONFIGURATION);
+
+ cpu_pm_enter();
+ cpu_suspend(0, idle_finisher);
+
+#ifdef CONFIG_SMP
+ scu_enable(S5P_VA_SCU);
+#endif
+ cpu_pm_exit();
+
+ restore_cpu_arch_register();
+
+ /*
+ * If PMU failed while entering sleep mode, WFI will be
+ * ignored by PMU and then exiting cpu_do_idle().
+ * S5P_CENTRAL_LOWPWR_CFG bit will not be set automatically
+ * in this situation.
+ */
+ tmp = __raw_readl(S5P_CENTRAL_SEQ_CONFIGURATION);
+ if (!(tmp & S5P_CENTRAL_LOWPWR_CFG)) {
+ tmp |= S5P_CENTRAL_LOWPWR_CFG;
+ __raw_writel(tmp, S5P_CENTRAL_SEQ_CONFIGURATION);
+ }
+
+ /* Clear wakeup state register */
+ __raw_writel(0x0, S5P_WAKEUP_STAT);
+
+ do_gettimeofday(&after);
+
+ local_irq_enable();
+ idle_time = (after.tv_sec - before.tv_sec) * USEC_PER_SEC +
+ (after.tv_usec - before.tv_usec);
+
+ dev->last_residency = idle_time;
+ return index;
+}
+
static int exynos4_enter_idle(struct cpuidle_device *dev,
struct cpuidle_driver *drv,
- int index)
+ int index)
{
struct timeval before, after;
int idle_time;
@@ -60,6 +181,22 @@ static int exynos4_enter_idle(struct cpuidle_device *dev,
return index;
}
+static int exynos4_enter_lowpower(struct cpuidle_device *dev,
+ struct cpuidle_driver *drv,
+ int index)
+{
+ int new_index = index;
+
+ /* This mode only can be entered when other core's are offline */
+ if (num_online_cpus() > 1)
+ new_index = drv->safe_state_index;
+
+ if (new_index == 0)
+ return exynos4_enter_idle(dev, drv, new_index);
+ else
+ return exynos4_enter_core0_aftr(dev, drv, new_index);
+}
+
static int __init exynos4_init_cpuidle(void)
{
int i, max_cpuidle_state, cpu_id;
@@ -74,19 +211,25 @@ static int __init exynos4_init_cpuidle(void)
memcpy(&drv->states[i], &exynos4_cpuidle_set[i],
sizeof(struct cpuidle_state));
}
+ drv->safe_state_index = 0;
cpuidle_register_driver(&exynos4_idle_driver);
for_each_cpu(cpu_id, cpu_online_mask) {
device = &per_cpu(exynos4_cpuidle_device, cpu_id);
device->cpu = cpu_id;
- device->state_count = drv->state_count;
+ if (cpu_id == 0)
+ device->state_count = (sizeof(exynos4_cpuidle_set) /
+ sizeof(struct cpuidle_state));
+ else
+ device->state_count = 1; /* Support IDLE only */
if (cpuidle_register_device(device)) {
printk(KERN_ERR "CPUidle register device failed\n,");
return -EIO;
}
}
+
return 0;
}
device_initcall(exynos4_init_cpuidle);
diff --git a/arch/arm/mach-exynos/include/mach/map.h b/arch/arm/mach-exynos/include/mach/map.h
index c754a22a2bb3..a8cd65fcc685 100644
--- a/arch/arm/mach-exynos/include/mach/map.h
+++ b/arch/arm/mach-exynos/include/mach/map.h
@@ -31,6 +31,10 @@
#define EXYNOS4_PA_FIMC2 0x11820000
#define EXYNOS4_PA_FIMC3 0x11830000
+#define EXYNOS4_PA_JPEG 0x11840000
+
+#define EXYNOS4_PA_G2D 0x12800000
+
#define EXYNOS4_PA_I2S0 0x03830000
#define EXYNOS4_PA_I2S1 0xE3100000
#define EXYNOS4_PA_I2S2 0xE2A00000
@@ -57,6 +61,7 @@
#define EXYNOS4_PA_KEYPAD 0x100A0000
#define EXYNOS4_PA_DMC0 0x10400000
+#define EXYNOS4_PA_DMC1 0x10410000
#define EXYNOS4_PA_COMBINER 0x10440000
@@ -162,6 +167,8 @@
#define S5P_PA_FIMC1 EXYNOS4_PA_FIMC1
#define S5P_PA_FIMC2 EXYNOS4_PA_FIMC2
#define S5P_PA_FIMC3 EXYNOS4_PA_FIMC3
+#define S5P_PA_JPEG EXYNOS4_PA_JPEG
+#define S5P_PA_G2D EXYNOS4_PA_G2D
#define S5P_PA_FIMD0 EXYNOS4_PA_FIMD0
#define S5P_PA_HDMI EXYNOS4_PA_HDMI
#define S5P_PA_IIC_HDMIPHY EXYNOS4_PA_IIC_HDMIPHY
diff --git a/arch/arm/mach-exynos/include/mach/pmu.h b/arch/arm/mach-exynos/include/mach/pmu.h
index 632dd5630138..e76b7faba66b 100644
--- a/arch/arm/mach-exynos/include/mach/pmu.h
+++ b/arch/arm/mach-exynos/include/mach/pmu.h
@@ -22,11 +22,13 @@ enum sys_powerdown {
NUM_SYS_POWERDOWN,
};
+extern unsigned long l2x0_regs_phys;
struct exynos4_pmu_conf {
void __iomem *reg;
unsigned int val[NUM_SYS_POWERDOWN];
};
extern void exynos4_sys_powerdown_conf(enum sys_powerdown mode);
+extern void s3c_cpu_resume(void);
#endif /* __ASM_ARCH_PMU_H */
diff --git a/arch/arm/mach-exynos/mct.c b/arch/arm/mach-exynos/mct.c
index edc4b9488f2f..e8a1caaf1902 100644
--- a/arch/arm/mach-exynos/mct.c
+++ b/arch/arm/mach-exynos/mct.c
@@ -30,12 +30,13 @@
#include <mach/regs-mct.h>
#include <asm/mach/time.h>
+#define TICK_BASE_CNT 1
+
enum {
MCT_INT_SPI,
MCT_INT_PPI
};
-static unsigned long clk_cnt_per_tick;
static unsigned long clk_rate;
static unsigned int mct_int_type;
@@ -206,11 +207,14 @@ static int exynos4_comp_set_next_event(unsigned long cycles,
static void exynos4_comp_set_mode(enum clock_event_mode mode,
struct clock_event_device *evt)
{
+ unsigned long cycles_per_jiffy;
exynos4_mct_comp0_stop();
switch (mode) {
case CLOCK_EVT_MODE_PERIODIC:
- exynos4_mct_comp0_start(mode, clk_cnt_per_tick);
+ cycles_per_jiffy =
+ (((unsigned long long) NSEC_PER_SEC / HZ * evt->mult) >> evt->shift);
+ exynos4_mct_comp0_start(mode, cycles_per_jiffy);
break;
case CLOCK_EVT_MODE_ONESHOT:
@@ -249,9 +253,7 @@ static struct irqaction mct_comp_event_irq = {
static void exynos4_clockevent_init(void)
{
- clk_cnt_per_tick = clk_rate / 2 / HZ;
-
- clockevents_calc_mult_shift(&mct_comp_device, clk_rate / 2, 5);
+ clockevents_calc_mult_shift(&mct_comp_device, clk_rate, 5);
mct_comp_device.max_delta_ns =
clockevent_delta2ns(0xffffffff, &mct_comp_device);
mct_comp_device.min_delta_ns =
@@ -315,12 +317,15 @@ static inline void exynos4_tick_set_mode(enum clock_event_mode mode,
struct clock_event_device *evt)
{
struct mct_clock_event_device *mevt = this_cpu_ptr(&percpu_mct_tick);
+ unsigned long cycles_per_jiffy;
exynos4_mct_tick_stop(mevt);
switch (mode) {
case CLOCK_EVT_MODE_PERIODIC:
- exynos4_mct_tick_start(clk_cnt_per_tick, mevt);
+ cycles_per_jiffy =
+ (((unsigned long long) NSEC_PER_SEC / HZ * evt->mult) >> evt->shift);
+ exynos4_mct_tick_start(cycles_per_jiffy, mevt);
break;
case CLOCK_EVT_MODE_ONESHOT:
@@ -394,7 +399,7 @@ static int __cpuinit exynos4_local_timer_setup(struct clock_event_device *evt)
evt->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT;
evt->rating = 450;
- clockevents_calc_mult_shift(evt, clk_rate / 2, 5);
+ clockevents_calc_mult_shift(evt, clk_rate / (TICK_BASE_CNT + 1), 5);
evt->max_delta_ns =
clockevent_delta2ns(0x7fffffff, evt);
evt->min_delta_ns =
@@ -402,7 +407,7 @@ static int __cpuinit exynos4_local_timer_setup(struct clock_event_device *evt)
clockevents_register_device(evt);
- exynos4_mct_write(0x1, mevt->base + MCT_L_TCNTB_OFFSET);
+ exynos4_mct_write(TICK_BASE_CNT, mevt->base + MCT_L_TCNTB_OFFSET);
if (mct_int_type == MCT_INT_SPI) {
if (cpu == 0) {
diff --git a/arch/arm/mach-exynos/pm.c b/arch/arm/mach-exynos/pm.c
index f105bd2b6765..428cfeb57724 100644
--- a/arch/arm/mach-exynos/pm.c
+++ b/arch/arm/mach-exynos/pm.c
@@ -155,13 +155,6 @@ static struct sleep_save exynos4_core_save[] = {
SAVE_ITEM(S5P_SROM_BC3),
};
-static struct sleep_save exynos4_l2cc_save[] = {
- SAVE_ITEM(S5P_VA_L2CC + L2X0_TAG_LATENCY_CTRL),
- SAVE_ITEM(S5P_VA_L2CC + L2X0_DATA_LATENCY_CTRL),
- SAVE_ITEM(S5P_VA_L2CC + L2X0_PREFETCH_CTRL),
- SAVE_ITEM(S5P_VA_L2CC + L2X0_POWER_CTRL),
- SAVE_ITEM(S5P_VA_L2CC + L2X0_AUX_CTRL),
-};
/* For Cortex-A9 Diagnostic and Power control register */
static unsigned int save_arm_register[2];
@@ -182,7 +175,6 @@ static void exynos4_pm_prepare(void)
u32 tmp;
s3c_pm_do_save(exynos4_core_save, ARRAY_SIZE(exynos4_core_save));
- s3c_pm_do_save(exynos4_l2cc_save, ARRAY_SIZE(exynos4_l2cc_save));
s3c_pm_do_save(exynos4_epll_save, ARRAY_SIZE(exynos4_epll_save));
s3c_pm_do_save(exynos4_vpll_save, ARRAY_SIZE(exynos4_vpll_save));
@@ -388,13 +380,6 @@ static void exynos4_pm_resume(void)
scu_enable(S5P_VA_SCU);
#endif
-#ifdef CONFIG_CACHE_L2X0
- s3c_pm_do_restore_core(exynos4_l2cc_save, ARRAY_SIZE(exynos4_l2cc_save));
- outer_inv_all();
- /* enable L2X0*/
- writel_relaxed(1, S5P_VA_L2CC + L2X0_CTRL);
-#endif
-
early_wakeup:
return;
}
diff --git a/arch/arm/mach-highbank/highbank.c b/arch/arm/mach-highbank/highbank.c
index bb1684f9b68b..808b055289b2 100644
--- a/arch/arm/mach-highbank/highbank.c
+++ b/arch/arm/mach-highbank/highbank.c
@@ -110,7 +110,7 @@ static void __init highbank_timer_init(void)
highbank_clocks_init();
- sp804_clocksource_init(timer_base + 0x20, "timer1");
+ sp804_clocksource_and_sched_clock_init(timer_base + 0x20, "timer1");
sp804_clockevents_init(timer_base, irq, "timer0");
twd_local_timer_of_register();
diff --git a/arch/arm/mach-highbank/include/mach/memory.h b/arch/arm/mach-highbank/include/mach/memory.h
deleted file mode 100644
index 40a8c178f10d..000000000000
--- a/arch/arm/mach-highbank/include/mach/memory.h
+++ /dev/null
@@ -1 +0,0 @@
-/* empty */
diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile
index 190d57006163..1ca9558723c2 100644
--- a/arch/arm/mach-imx/Makefile
+++ b/arch/arm/mach-imx/Makefile
@@ -8,8 +8,8 @@ obj-$(CONFIG_SOC_IMX25) += clock-imx25.o mm-imx25.o ehci-imx25.o cpu-imx25.o
obj-$(CONFIG_SOC_IMX27) += cpu-imx27.o pm-imx27.o
obj-$(CONFIG_SOC_IMX27) += clock-imx27.o mm-imx27.o ehci-imx27.o
-obj-$(CONFIG_SOC_IMX31) += mm-imx3.o cpu-imx31.o clock-imx31.o iomux-imx31.o ehci-imx31.o
-obj-$(CONFIG_SOC_IMX35) += mm-imx3.o cpu-imx35.o clock-imx35.o ehci-imx35.o
+obj-$(CONFIG_SOC_IMX31) += mm-imx3.o cpu-imx31.o clock-imx31.o iomux-imx31.o ehci-imx31.o pm-imx3.o
+obj-$(CONFIG_SOC_IMX35) += mm-imx3.o cpu-imx35.o clock-imx35.o ehci-imx35.o pm-imx3.o
obj-$(CONFIG_SOC_IMX5) += cpu-imx5.o mm-imx5.o clock-mx51-mx53.o ehci-imx5.o pm-imx5.o cpu_op-mx51.o
diff --git a/arch/arm/mach-imx/cpu-imx5.c b/arch/arm/mach-imx/cpu-imx5.c
index 5e2e7a843860..aa15c517d06e 100644
--- a/arch/arm/mach-imx/cpu-imx5.c
+++ b/arch/arm/mach-imx/cpu-imx5.c
@@ -149,39 +149,3 @@ int mx50_revision(void)
return mx5_cpu_rev;
}
EXPORT_SYMBOL(mx50_revision);
-
-static int __init post_cpu_init(void)
-{
- unsigned int reg;
- void __iomem *base;
-
- if (cpu_is_mx51() || cpu_is_mx53()) {
- if (cpu_is_mx51())
- base = MX51_IO_ADDRESS(MX51_AIPS1_BASE_ADDR);
- else
- base = MX53_IO_ADDRESS(MX53_AIPS1_BASE_ADDR);
-
- __raw_writel(0x0, base + 0x40);
- __raw_writel(0x0, base + 0x44);
- __raw_writel(0x0, base + 0x48);
- __raw_writel(0x0, base + 0x4C);
- reg = __raw_readl(base + 0x50) & 0x00FFFFFF;
- __raw_writel(reg, base + 0x50);
-
- if (cpu_is_mx51())
- base = MX51_IO_ADDRESS(MX51_AIPS2_BASE_ADDR);
- else
- base = MX53_IO_ADDRESS(MX53_AIPS2_BASE_ADDR);
-
- __raw_writel(0x0, base + 0x40);
- __raw_writel(0x0, base + 0x44);
- __raw_writel(0x0, base + 0x48);
- __raw_writel(0x0, base + 0x4C);
- reg = __raw_readl(base + 0x50) & 0x00FFFFFF;
- __raw_writel(reg, base + 0x50);
- }
-
- return 0;
-}
-
-postcore_initcall(post_cpu_init);
diff --git a/arch/arm/mach-imx/crmregs-imx3.h b/arch/arm/mach-imx/crmregs-imx3.h
index d7691e2362c1..53141273df45 100644
--- a/arch/arm/mach-imx/crmregs-imx3.h
+++ b/arch/arm/mach-imx/crmregs-imx3.h
@@ -77,6 +77,7 @@ MX31_IO_ADDRESS(MX31_CCM_BASE_ADDR) : MX35_IO_ADDRESS(MX35_CCM_BASE_ADDR))
#define MXC_CCM_CCMR_SSI2S_MASK (0x3 << 21)
#define MXC_CCM_CCMR_LPM_OFFSET 14
#define MXC_CCM_CCMR_LPM_MASK (0x3 << 14)
+#define MXC_CCM_CCMR_LPM_WAIT_MX35 (0x1 << 14)
#define MXC_CCM_CCMR_FIRS_OFFSET 11
#define MXC_CCM_CCMR_FIRS_MASK (0x3 << 11)
#define MXC_CCM_CCMR_UPE (1 << 9)
diff --git a/arch/arm/mach-imx/mm-imx3.c b/arch/arm/mach-imx/mm-imx3.c
index 07699196b461..f8ca96c354f2 100644
--- a/arch/arm/mach-imx/mm-imx3.c
+++ b/arch/arm/mach-imx/mm-imx3.c
@@ -34,6 +34,8 @@ static void imx3_idle(void)
{
unsigned long reg = 0;
+ mx3_cpu_lp_set(MX3_WAIT);
+
__asm__ __volatile__(
/* disable I and D cache */
"mrc p15, 0, %0, c1, c0, 0\n"
@@ -177,6 +179,10 @@ void __init imx31_soc_init(void)
}
imx_add_imx_sdma("imx31-sdma", MX31_SDMA_BASE_ADDR, MX31_INT_SDMA, &imx31_sdma_pdata);
+
+ imx_set_aips(MX31_IO_ADDRESS(MX31_AIPS1_BASE_ADDR));
+ imx_set_aips(MX31_IO_ADDRESS(MX31_AIPS2_BASE_ADDR));
+
platform_device_register_simple("imx31-audmux", 0, imx31_audmux_res,
ARRAY_SIZE(imx31_audmux_res));
}
@@ -267,6 +273,11 @@ void __init imx35_soc_init(void)
}
imx_add_imx_sdma("imx35-sdma", MX35_SDMA_BASE_ADDR, MX35_INT_SDMA, &imx35_sdma_pdata);
+
+ /* Setup AIPS registers */
+ imx_set_aips(MX35_IO_ADDRESS(MX35_AIPS1_BASE_ADDR));
+ imx_set_aips(MX35_IO_ADDRESS(MX35_AIPS2_BASE_ADDR));
+
/* i.mx35 has the i.mx31 type audmux */
platform_device_register_simple("imx31-audmux", 0, imx35_audmux_res,
ARRAY_SIZE(imx35_audmux_res));
diff --git a/arch/arm/mach-imx/mm-imx5.c b/arch/arm/mach-imx/mm-imx5.c
index dc7c4ed81531..51af9fa56944 100644
--- a/arch/arm/mach-imx/mm-imx5.c
+++ b/arch/arm/mach-imx/mm-imx5.c
@@ -201,6 +201,11 @@ void __init imx51_soc_init(void)
/* i.mx51 has the i.mx35 type sdma */
imx_add_imx_sdma("imx35-sdma", MX51_SDMA_BASE_ADDR, MX51_INT_SDMA, &imx51_sdma_pdata);
+
+ /* Setup AIPS registers */
+ imx_set_aips(MX51_IO_ADDRESS(MX51_AIPS1_BASE_ADDR));
+ imx_set_aips(MX51_IO_ADDRESS(MX51_AIPS2_BASE_ADDR));
+
/* i.mx51 has the i.mx31 type audmux */
platform_device_register_simple("imx31-audmux", 0, imx51_audmux_res,
ARRAY_SIZE(imx51_audmux_res));
@@ -219,6 +224,11 @@ void __init imx53_soc_init(void)
/* i.mx53 has the i.mx35 type sdma */
imx_add_imx_sdma("imx35-sdma", MX53_SDMA_BASE_ADDR, MX53_INT_SDMA, &imx53_sdma_pdata);
+
+ /* Setup AIPS registers */
+ imx_set_aips(MX53_IO_ADDRESS(MX53_AIPS1_BASE_ADDR));
+ imx_set_aips(MX53_IO_ADDRESS(MX53_AIPS2_BASE_ADDR));
+
/* i.mx53 has the i.mx31 type audmux */
platform_device_register_simple("imx31-audmux", 0, imx53_audmux_res,
ARRAY_SIZE(imx53_audmux_res));
diff --git a/arch/arm/mach-imx/pm-imx3.c b/arch/arm/mach-imx/pm-imx3.c
new file mode 100644
index 000000000000..b3752439632e
--- /dev/null
+++ b/arch/arm/mach-imx/pm-imx3.c
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2012 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+#include <linux/io.h>
+#include <mach/common.h>
+#include <mach/hardware.h>
+#include <mach/devices-common.h>
+#include "crmregs-imx3.h"
+
+/*
+ * Set cpu low power mode before WFI instruction. This function is called
+ * mx3 because it can be used for mx31 and mx35.
+ * Currently only WAIT_MODE is supported.
+ */
+void mx3_cpu_lp_set(enum mx3_cpu_pwr_mode mode)
+{
+ int reg = __raw_readl(MXC_CCM_CCMR);
+ reg &= ~MXC_CCM_CCMR_LPM_MASK;
+
+ switch (mode) {
+ case MX3_WAIT:
+ if (cpu_is_mx35())
+ reg |= MXC_CCM_CCMR_LPM_WAIT_MX35;
+ __raw_writel(reg, MXC_CCM_CCMR);
+ break;
+ default:
+ pr_err("Unknown cpu power mode: %d\n", mode);
+ return;
+ }
+}
diff --git a/arch/arm/mach-mxs/clock-mx23.c b/arch/arm/mach-mxs/clock-mx23.c
index e12e11231dc7..293958beb505 100644
--- a/arch/arm/mach-mxs/clock-mx23.c
+++ b/arch/arm/mach-mxs/clock-mx23.c
@@ -223,7 +223,6 @@ static int cpu_clk_set_rate(struct clk *clk, unsigned long rate)
{
u32 reg, bm_busy, div_max, d, f, div, frac;
unsigned long diff, parent_rate, calc_rate;
- int i;
parent_rate = clk_get_rate(clk->parent);
@@ -275,14 +274,7 @@ static int cpu_clk_set_rate(struct clk *clk, unsigned long rate)
reg |= div << BP_CLKCTRL_CPU_DIV_CPU;
__raw_writel(reg, CLKCTRL_BASE_ADDR + HW_CLKCTRL_CPU);
- for (i = 10000; i; i--)
- if (!(__raw_readl(CLKCTRL_BASE_ADDR +
- HW_CLKCTRL_CPU) & bm_busy))
- break;
- if (!i) {
- pr_err("%s: divider writing timeout\n", __func__);
- return -ETIMEDOUT;
- }
+ mxs_clkctrl_timeout(HW_CLKCTRL_CPU, bm_busy);
return 0;
}
@@ -292,7 +284,6 @@ static int name##_set_rate(struct clk *clk, unsigned long rate) \
{ \
u32 reg, div_max, div; \
unsigned long parent_rate; \
- int i; \
\
parent_rate = clk_get_rate(clk->parent); \
div_max = BM_CLKCTRL_##dr##_DIV >> BP_CLKCTRL_##dr##_DIV; \
@@ -310,15 +301,7 @@ static int name##_set_rate(struct clk *clk, unsigned long rate) \
} \
__raw_writel(reg, CLKCTRL_BASE_ADDR + HW_CLKCTRL_##dr); \
\
- for (i = 10000; i; i--) \
- if (!(__raw_readl(CLKCTRL_BASE_ADDR + \
- HW_CLKCTRL_##dr) & BM_CLKCTRL_##dr##_BUSY)) \
- break; \
- if (!i) { \
- pr_err("%s: divider writing timeout\n", __func__); \
- return -ETIMEDOUT; \
- } \
- \
+ mxs_clkctrl_timeout(HW_CLKCTRL_##dr, BM_CLKCTRL_##dr##_BUSY); \
return 0; \
}
@@ -461,7 +444,7 @@ static struct clk_lookup lookups[] = {
static int clk_misc_init(void)
{
u32 reg;
- int i;
+ int ret;
/* Fix up parent per register setting */
reg = __raw_readl(CLKCTRL_BASE_ADDR + HW_CLKCTRL_CLKSEQ);
@@ -510,14 +493,7 @@ static int clk_misc_init(void)
reg |= 3 << BP_CLKCTRL_HBUS_DIV;
__raw_writel(reg, CLKCTRL_BASE_ADDR + HW_CLKCTRL_HBUS);
- for (i = 10000; i; i--)
- if (!(__raw_readl(CLKCTRL_BASE_ADDR +
- HW_CLKCTRL_HBUS) & BM_CLKCTRL_HBUS_BUSY))
- break;
- if (!i) {
- pr_err("%s: divider writing timeout\n", __func__);
- return -ETIMEDOUT;
- }
+ ret = mxs_clkctrl_timeout(HW_CLKCTRL_HBUS, BM_CLKCTRL_HBUS_BUSY);
/* Gate off cpu clock in WFI for power saving */
__raw_writel(BM_CLKCTRL_CPU_INTERRUPT_WAIT,
@@ -532,7 +508,7 @@ static int clk_misc_init(void)
reg |= 30 << BP_CLKCTRL_FRAC_IOFRAC;
__raw_writel(reg, CLKCTRL_BASE_ADDR + HW_CLKCTRL_FRAC);
- return 0;
+ return ret;
}
int __init mx23_clocks_init(void)
diff --git a/arch/arm/mach-mxs/clock-mx28.c b/arch/arm/mach-mxs/clock-mx28.c
index 5d68e4152220..22ad12f6e4de 100644
--- a/arch/arm/mach-mxs/clock-mx28.c
+++ b/arch/arm/mach-mxs/clock-mx28.c
@@ -322,7 +322,6 @@ static int name##_set_rate(struct clk *clk, unsigned long rate) \
{ \
u32 reg, bm_busy, div_max, d, f, div, frac; \
unsigned long diff, parent_rate, calc_rate; \
- int i; \
\
div_max = BM_CLKCTRL_##dr##_DIV >> BP_CLKCTRL_##dr##_DIV; \
bm_busy = BM_CLKCTRL_##dr##_BUSY; \
@@ -396,16 +395,7 @@ static int name##_set_rate(struct clk *clk, unsigned long rate) \
} \
__raw_writel(reg, CLKCTRL_BASE_ADDR + HW_CLKCTRL_##dr); \
\
- for (i = 10000; i; i--) \
- if (!(__raw_readl(CLKCTRL_BASE_ADDR + \
- HW_CLKCTRL_##dr) & bm_busy)) \
- break; \
- if (!i) { \
- pr_err("%s: divider writing timeout\n", __func__); \
- return -ETIMEDOUT; \
- } \
- \
- return 0; \
+ return mxs_clkctrl_timeout(HW_CLKCTRL_##dr, bm_busy); \
}
_CLK_SET_RATE(cpu_clk, CPU, FRAC0, CPU)
@@ -421,7 +411,6 @@ static int name##_set_rate(struct clk *clk, unsigned long rate) \
{ \
u32 reg, div_max, div; \
unsigned long parent_rate; \
- int i; \
\
parent_rate = clk_get_rate(clk->parent); \
div_max = BM_CLKCTRL_##dr##_DIV >> BP_CLKCTRL_##dr##_DIV; \
@@ -439,16 +428,7 @@ static int name##_set_rate(struct clk *clk, unsigned long rate) \
} \
__raw_writel(reg, CLKCTRL_BASE_ADDR + HW_CLKCTRL_##dr); \
\
- for (i = 10000; i; i--) \
- if (!(__raw_readl(CLKCTRL_BASE_ADDR + \
- HW_CLKCTRL_##dr) & BM_CLKCTRL_##dr##_BUSY)) \
- break; \
- if (!i) { \
- pr_err("%s: divider writing timeout\n", __func__); \
- return -ETIMEDOUT; \
- } \
- \
- return 0; \
+ return mxs_clkctrl_timeout(HW_CLKCTRL_##dr, BM_CLKCTRL_##dr##_BUSY);\
}
_CLK_SET_RATE1(xbus_clk, XBUS)
@@ -461,7 +441,6 @@ static int name##_set_rate(struct clk *clk, unsigned long rate) \
u32 reg; \
u64 lrate; \
unsigned long parent_rate; \
- int i; \
\
parent_rate = clk_get_rate(clk->parent); \
if (rate > parent_rate) \
@@ -477,18 +456,13 @@ static int name##_set_rate(struct clk *clk, unsigned long rate) \
reg = __raw_readl(CLKCTRL_BASE_ADDR + HW_CLKCTRL_##rs); \
reg &= ~BM_CLKCTRL_##rs##_DIV; \
reg |= div << BP_CLKCTRL_##rs##_DIV; \
- __raw_writel(reg, CLKCTRL_BASE_ADDR + HW_CLKCTRL_##rs); \
- \
- for (i = 10000; i; i--) \
- if (!(__raw_readl(CLKCTRL_BASE_ADDR + \
- HW_CLKCTRL_##rs) & BM_CLKCTRL_##rs##_BUSY)) \
- break; \
- if (!i) { \
- pr_err("%s: divider writing timeout\n", __func__); \
- return -ETIMEDOUT; \
+ if (reg & (1 << clk->enable_shift)) { \
+ pr_err("%s: clock is gated\n", __func__); \
+ return -EINVAL; \
} \
+ __raw_writel(reg, CLKCTRL_BASE_ADDR + HW_CLKCTRL_##rs); \
\
- return 0; \
+ return mxs_clkctrl_timeout(HW_CLKCTRL_##rs, BM_CLKCTRL_##rs##_BUSY);\
}
_CLK_SET_RATE_SAIF(saif0_clk, SAIF0)
@@ -654,6 +628,8 @@ static struct clk_lookup lookups[] = {
_REGISTER_CLOCK("mxs-dma-apbx", NULL, xbus_clk)
_REGISTER_CLOCK("mxs-mmc.0", NULL, ssp0_clk)
_REGISTER_CLOCK("mxs-mmc.1", NULL, ssp1_clk)
+ _REGISTER_CLOCK("mxs-mmc.2", NULL, ssp2_clk)
+ _REGISTER_CLOCK("mxs-mmc.3", NULL, ssp3_clk)
_REGISTER_CLOCK("flexcan.0", NULL, can0_clk)
_REGISTER_CLOCK("flexcan.1", NULL, can1_clk)
_REGISTER_CLOCK(NULL, "usb0", usb0_clk)
@@ -676,7 +652,7 @@ static struct clk_lookup lookups[] = {
static int clk_misc_init(void)
{
u32 reg;
- int i;
+ int ret;
/* Fix up parent per register setting */
reg = __raw_readl(CLKCTRL_BASE_ADDR + HW_CLKCTRL_CLKSEQ);
@@ -756,14 +732,7 @@ static int clk_misc_init(void)
reg |= 3 << BP_CLKCTRL_HBUS_DIV;
__raw_writel(reg, CLKCTRL_BASE_ADDR + HW_CLKCTRL_HBUS);
- for (i = 10000; i; i--)
- if (!(__raw_readl(CLKCTRL_BASE_ADDR +
- HW_CLKCTRL_HBUS) & BM_CLKCTRL_HBUS_ASM_BUSY))
- break;
- if (!i) {
- pr_err("%s: divider writing timeout\n", __func__);
- return -ETIMEDOUT;
- }
+ ret = mxs_clkctrl_timeout(HW_CLKCTRL_HBUS, BM_CLKCTRL_HBUS_ASM_BUSY);
/* Gate off cpu clock in WFI for power saving */
__raw_writel(BM_CLKCTRL_CPU_INTERRUPT_WAIT,
@@ -790,7 +759,7 @@ static int clk_misc_init(void)
reg |= 30 << BP_CLKCTRL_FRAC0_IO0FRAC;
__raw_writel(reg, CLKCTRL_BASE_ADDR + HW_CLKCTRL_FRAC0);
- return 0;
+ return ret;
}
int __init mx28_clocks_init(void)
@@ -803,6 +772,8 @@ int __init mx28_clocks_init(void)
*/
clk_set_parent(&ssp0_clk, &ref_io0_clk);
clk_set_parent(&ssp1_clk, &ref_io0_clk);
+ clk_set_parent(&ssp2_clk, &ref_io1_clk);
+ clk_set_parent(&ssp3_clk, &ref_io1_clk);
clk_prepare_enable(&cpu_clk);
clk_prepare_enable(&hbus_clk);
diff --git a/arch/arm/mach-mxs/devices/platform-mxs-mmc.c b/arch/arm/mach-mxs/devices/platform-mxs-mmc.c
index 382dacbeca21..bef9d923f54e 100644
--- a/arch/arm/mach-mxs/devices/platform-mxs-mmc.c
+++ b/arch/arm/mach-mxs/devices/platform-mxs-mmc.c
@@ -41,6 +41,8 @@ const struct mxs_mxs_mmc_data mx23_mxs_mmc_data[] __initconst = {
const struct mxs_mxs_mmc_data mx28_mxs_mmc_data[] __initconst = {
mxs_mxs_mmc_data_entry(MX28, 0, 0),
mxs_mxs_mmc_data_entry(MX28, 1, 1),
+ mxs_mxs_mmc_data_entry(MX28, 2, 2),
+ mxs_mxs_mmc_data_entry(MX28, 3, 3),
};
#endif
diff --git a/arch/arm/mach-mxs/include/mach/common.h b/arch/arm/mach-mxs/include/mach/common.h
index e1237ab25862..c50c3ea28a9d 100644
--- a/arch/arm/mach-mxs/include/mach/common.h
+++ b/arch/arm/mach-mxs/include/mach/common.h
@@ -31,4 +31,6 @@ extern void mx28_init_irq(void);
extern void icoll_init_irq(void);
+extern int mxs_clkctrl_timeout(unsigned int reg_offset, unsigned int mask);
+
#endif /* __MACH_MXS_COMMON_H__ */
diff --git a/arch/arm/mach-mxs/system.c b/arch/arm/mach-mxs/system.c
index 54f91ad1c965..7aa5ac5d78bf 100644
--- a/arch/arm/mach-mxs/system.c
+++ b/arch/arm/mach-mxs/system.c
@@ -37,6 +37,8 @@
#define MXS_MODULE_CLKGATE (1 << 30)
#define MXS_MODULE_SFTRST (1 << 31)
+#define CLKCTRL_TIMEOUT 10 /* 10 ms */
+
static void __iomem *mxs_clkctrl_reset_addr;
/*
@@ -137,3 +139,17 @@ error:
return -ETIMEDOUT;
}
EXPORT_SYMBOL(mxs_reset_block);
+
+int mxs_clkctrl_timeout(unsigned int reg_offset, unsigned int mask)
+{
+ unsigned long timeout = jiffies + msecs_to_jiffies(CLKCTRL_TIMEOUT);
+ while (readl_relaxed(MXS_IO_ADDRESS(MXS_CLKCTRL_BASE_ADDR)
+ + reg_offset) & mask) {
+ if (time_after(jiffies, timeout)) {
+ pr_err("Timeout at CLKCTRL + 0x%x\n", reg_offset);
+ return -ETIMEDOUT;
+ }
+ }
+
+ return 0;
+}
diff --git a/arch/arm/mach-omap2/id.c b/arch/arm/mach-omap2/id.c
index 613e2c1eeb2f..0e79b7bc6aa4 100644
--- a/arch/arm/mach-omap2/id.c
+++ b/arch/arm/mach-omap2/id.c
@@ -29,7 +29,7 @@
#include "control.h"
static unsigned int omap_revision;
-
+static const char *cpu_rev;
u32 omap_features;
unsigned int omap_rev(void)
@@ -114,7 +114,7 @@ void omap_get_die_id(struct omap_die_id *odi)
odi->id_3 = read_tap_reg(OMAP_TAP_DIE_ID_3);
}
-static void __init omap24xx_check_revision(void)
+void __init omap2xxx_check_revision(void)
{
int i, j;
u32 idcode, prod_id;
@@ -168,13 +168,63 @@ static void __init omap24xx_check_revision(void)
pr_info("\n");
}
+#define OMAP3_SHOW_FEATURE(feat) \
+ if (omap3_has_ ##feat()) \
+ printk(#feat" ");
+
+static void __init omap3_cpuinfo(void)
+{
+ const char *cpu_name;
+
+ /*
+ * OMAP3430 and OMAP3530 are assumed to be same.
+ *
+ * OMAP3525, OMAP3515 and OMAP3503 can be detected only based
+ * on available features. Upon detection, update the CPU id
+ * and CPU class bits.
+ */
+ if (cpu_is_omap3630()) {
+ cpu_name = "OMAP3630";
+ } else if (cpu_is_omap3517()) {
+ /* AM35xx devices */
+ cpu_name = (omap3_has_sgx()) ? "AM3517" : "AM3505";
+ } else if (cpu_is_ti816x()) {
+ cpu_name = "TI816X";
+ } else if (cpu_is_am335x()) {
+ cpu_name = "AM335X";
+ } else if (cpu_is_ti814x()) {
+ cpu_name = "TI814X";
+ } else if (omap3_has_iva() && omap3_has_sgx()) {
+ /* OMAP3430, OMAP3525, OMAP3515, OMAP3503 devices */
+ cpu_name = "OMAP3430/3530";
+ } else if (omap3_has_iva()) {
+ cpu_name = "OMAP3525";
+ } else if (omap3_has_sgx()) {
+ cpu_name = "OMAP3515";
+ } else {
+ cpu_name = "OMAP3503";
+ }
+
+ /* Print verbose information */
+ pr_info("%s ES%s (", cpu_name, cpu_rev);
+
+ OMAP3_SHOW_FEATURE(l2cache);
+ OMAP3_SHOW_FEATURE(iva);
+ OMAP3_SHOW_FEATURE(sgx);
+ OMAP3_SHOW_FEATURE(neon);
+ OMAP3_SHOW_FEATURE(isp);
+ OMAP3_SHOW_FEATURE(192mhz_clk);
+
+ printk(")\n");
+}
+
#define OMAP3_CHECK_FEATURE(status,feat) \
if (((status & OMAP3_ ##feat## _MASK) \
>> OMAP3_ ##feat## _SHIFT) != FEAT_ ##feat## _NONE) { \
omap_features |= OMAP3_HAS_ ##feat; \
}
-static void __init omap3_check_features(void)
+void __init omap3xxx_check_features(void)
{
u32 status;
@@ -201,9 +251,11 @@ static void __init omap3_check_features(void)
* TODO: Get additional info (where applicable)
* e.g. Size of L2 cache.
*/
+
+ omap3_cpuinfo();
}
-static void __init omap4_check_features(void)
+void __init omap4xxx_check_features(void)
{
u32 si_type;
@@ -228,12 +280,13 @@ static void __init omap4_check_features(void)
}
}
-static void __init ti81xx_check_features(void)
+void __init ti81xx_check_features(void)
{
omap_features = OMAP3_HAS_NEON;
+ omap3_cpuinfo();
}
-static void __init omap3_check_revision(const char **cpu_rev)
+void __init omap3xxx_check_revision(void)
{
u32 cpuid, idcode;
u16 hawkeye;
@@ -247,7 +300,7 @@ static void __init omap3_check_revision(const char **cpu_rev)
cpuid = read_cpuid(CPUID_ID);
if ((((cpuid >> 4) & 0xfff) == 0xc08) && ((cpuid & 0xf) == 0x0)) {
omap_revision = OMAP3430_REV_ES1_0;
- *cpu_rev = "1.0";
+ cpu_rev = "1.0";
return;
}
@@ -268,26 +321,26 @@ static void __init omap3_check_revision(const char **cpu_rev)
case 0: /* Take care of early samples */
case 1:
omap_revision = OMAP3430_REV_ES2_0;
- *cpu_rev = "2.0";
+ cpu_rev = "2.0";
break;
case 2:
omap_revision = OMAP3430_REV_ES2_1;
- *cpu_rev = "2.1";
+ cpu_rev = "2.1";
break;
case 3:
omap_revision = OMAP3430_REV_ES3_0;
- *cpu_rev = "3.0";
+ cpu_rev = "3.0";
break;
case 4:
omap_revision = OMAP3430_REV_ES3_1;
- *cpu_rev = "3.1";
+ cpu_rev = "3.1";
break;
case 7:
/* FALLTHROUGH */
default:
/* Use the latest known revision as default */
omap_revision = OMAP3430_REV_ES3_1_2;
- *cpu_rev = "3.1.2";
+ cpu_rev = "3.1.2";
}
break;
case 0xb868:
@@ -300,13 +353,13 @@ static void __init omap3_check_revision(const char **cpu_rev)
switch (rev) {
case 0:
omap_revision = OMAP3517_REV_ES1_0;
- *cpu_rev = "1.0";
+ cpu_rev = "1.0";
break;
case 1:
/* FALLTHROUGH */
default:
omap_revision = OMAP3517_REV_ES1_1;
- *cpu_rev = "1.1";
+ cpu_rev = "1.1";
}
break;
case 0xb891:
@@ -315,36 +368,36 @@ static void __init omap3_check_revision(const char **cpu_rev)
switch(rev) {
case 0: /* Take care of early samples */
omap_revision = OMAP3630_REV_ES1_0;
- *cpu_rev = "1.0";
+ cpu_rev = "1.0";
break;
case 1:
omap_revision = OMAP3630_REV_ES1_1;
- *cpu_rev = "1.1";
+ cpu_rev = "1.1";
break;
case 2:
/* FALLTHROUGH */
default:
omap_revision = OMAP3630_REV_ES1_2;
- *cpu_rev = "1.2";
+ cpu_rev = "1.2";
}
break;
case 0xb81e:
switch (rev) {
case 0:
omap_revision = TI8168_REV_ES1_0;
- *cpu_rev = "1.0";
+ cpu_rev = "1.0";
break;
case 1:
/* FALLTHROUGH */
default:
omap_revision = TI8168_REV_ES1_1;
- *cpu_rev = "1.1";
+ cpu_rev = "1.1";
break;
}
break;
case 0xb944:
omap_revision = AM335X_REV_ES1_0;
- *cpu_rev = "1.0";
+ cpu_rev = "1.0";
break;
case 0xb8f2:
switch (rev) {
@@ -352,29 +405,29 @@ static void __init omap3_check_revision(const char **cpu_rev)
/* FALLTHROUGH */
case 1:
omap_revision = TI8148_REV_ES1_0;
- *cpu_rev = "1.0";
+ cpu_rev = "1.0";
break;
case 2:
omap_revision = TI8148_REV_ES2_0;
- *cpu_rev = "2.0";
+ cpu_rev = "2.0";
break;
case 3:
/* FALLTHROUGH */
default:
omap_revision = TI8148_REV_ES2_1;
- *cpu_rev = "2.1";
+ cpu_rev = "2.1";
break;
}
break;
default:
/* Unknown default to latest silicon rev as default */
omap_revision = OMAP3630_REV_ES1_2;
- *cpu_rev = "1.2";
+ cpu_rev = "1.2";
pr_warn("Warning: unknown chip type; assuming OMAP3630ES1.2\n");
}
}
-static void __init omap4_check_revision(void)
+void __init omap4xxx_check_revision(void)
{
u32 idcode;
u16 hawkeye;
@@ -447,89 +500,6 @@ static void __init omap4_check_revision(void)
((omap_rev() >> 12) & 0xf), ((omap_rev() >> 8) & 0xf));
}
-#define OMAP3_SHOW_FEATURE(feat) \
- if (omap3_has_ ##feat()) \
- printk(#feat" ");
-
-static void __init omap3_cpuinfo(const char *cpu_rev)
-{
- const char *cpu_name;
-
- /*
- * OMAP3430 and OMAP3530 are assumed to be same.
- *
- * OMAP3525, OMAP3515 and OMAP3503 can be detected only based
- * on available features. Upon detection, update the CPU id
- * and CPU class bits.
- */
- if (cpu_is_omap3630()) {
- cpu_name = "OMAP3630";
- } else if (cpu_is_omap3517()) {
- /* AM35xx devices */
- cpu_name = (omap3_has_sgx()) ? "AM3517" : "AM3505";
- } else if (cpu_is_ti816x()) {
- cpu_name = "TI816X";
- } else if (cpu_is_am335x()) {
- cpu_name = "AM335X";
- } else if (cpu_is_ti814x()) {
- cpu_name = "TI814X";
- } else if (omap3_has_iva() && omap3_has_sgx()) {
- /* OMAP3430, OMAP3525, OMAP3515, OMAP3503 devices */
- cpu_name = "OMAP3430/3530";
- } else if (omap3_has_iva()) {
- cpu_name = "OMAP3525";
- } else if (omap3_has_sgx()) {
- cpu_name = "OMAP3515";
- } else {
- cpu_name = "OMAP3503";
- }
-
- /* Print verbose information */
- pr_info("%s ES%s (", cpu_name, cpu_rev);
-
- OMAP3_SHOW_FEATURE(l2cache);
- OMAP3_SHOW_FEATURE(iva);
- OMAP3_SHOW_FEATURE(sgx);
- OMAP3_SHOW_FEATURE(neon);
- OMAP3_SHOW_FEATURE(isp);
- OMAP3_SHOW_FEATURE(192mhz_clk);
-
- printk(")\n");
-}
-
-/*
- * Try to detect the exact revision of the omap we're running on
- */
-void __init omap2_check_revision(void)
-{
- const char *cpu_rev;
-
- /*
- * At this point we have an idea about the processor revision set
- * earlier with omap2_set_globals_tap().
- */
- if (cpu_is_omap24xx()) {
- omap24xx_check_revision();
- } else if (cpu_is_omap34xx()) {
- omap3_check_revision(&cpu_rev);
-
- /* TI81XX doesn't have feature register */
- if (!cpu_is_ti81xx())
- omap3_check_features();
- else
- ti81xx_check_features();
-
- omap3_cpuinfo(cpu_rev);
- return;
- } else if (cpu_is_omap44xx()) {
- omap4_check_revision();
- omap4_check_features();
- return;
- } else {
- pr_err("OMAP revision unknown, please fix!\n");
- }
-}
-
/*
* Set up things for map_io and processor detection later on. Gets called
* pretty much first thing from board init. For multi-omap, this gets
diff --git a/arch/arm/mach-omap2/io.c b/arch/arm/mach-omap2/io.c
index cd47a71297b9..065bd768987c 100644
--- a/arch/arm/mach-omap2/io.c
+++ b/arch/arm/mach-omap2/io.c
@@ -348,7 +348,6 @@ static int _set_hwmod_postsetup_state(struct omap_hwmod *oh, void *data)
static void __init omap_common_init_early(void)
{
- omap2_check_revision();
omap_init_consistent_dma_size();
}
@@ -389,6 +388,7 @@ static void __init omap_hwmod_init_postsetup(void)
void __init omap2420_init_early(void)
{
omap2_set_globals_242x();
+ omap2xxx_check_revision();
omap_common_init_early();
omap2xxx_voltagedomains_init();
omap242x_powerdomains_init();
@@ -403,6 +403,7 @@ void __init omap2420_init_early(void)
void __init omap2430_init_early(void)
{
omap2_set_globals_243x();
+ omap2xxx_check_revision();
omap_common_init_early();
omap2xxx_voltagedomains_init();
omap243x_powerdomains_init();
@@ -421,6 +422,8 @@ void __init omap2430_init_early(void)
void __init omap3_init_early(void)
{
omap2_set_globals_3xxx();
+ omap3xxx_check_revision();
+ omap3xxx_check_features();
omap_common_init_early();
omap3xxx_voltagedomains_init();
omap3xxx_powerdomains_init();
@@ -453,6 +456,8 @@ void __init am35xx_init_early(void)
void __init ti81xx_init_early(void)
{
omap2_set_globals_ti81xx();
+ omap3xxx_check_revision();
+ ti81xx_check_features();
omap_common_init_early();
omap3xxx_voltagedomains_init();
omap3xxx_powerdomains_init();
@@ -467,6 +472,8 @@ void __init ti81xx_init_early(void)
void __init omap4430_init_early(void)
{
omap2_set_globals_443x();
+ omap4xxx_check_revision();
+ omap4xxx_check_features();
omap_common_init_early();
omap44xx_voltagedomains_init();
omap44xx_powerdomains_init();
diff --git a/arch/arm/mach-s3c64xx/Kconfig b/arch/arm/mach-s3c64xx/Kconfig
index dd20c66cd700..326ea3a98725 100644
--- a/arch/arm/mach-s3c64xx/Kconfig
+++ b/arch/arm/mach-s3c64xx/Kconfig
@@ -83,6 +83,11 @@ config S3C64XX_SETUP_SPI
help
Common setup code for SPI GPIO configurations
+config S3C64XX_SETUP_USB_PHY
+ bool
+ help
+ Common setup code for USB PHY controller
+
# S36400 Macchine support
config MACH_SMDK6400
@@ -157,6 +162,7 @@ config MACH_SMDK6410
select S3C64XX_SETUP_IDE
select S3C64XX_SETUP_FB_24BPP
select S3C64XX_SETUP_KEYPAD
+ select S3C64XX_SETUP_USB_PHY
help
Machine support for the Samsung SMDK6410
@@ -256,6 +262,7 @@ config MACH_SMARTQ
select S3C_DEV_USB_HOST
select S3C64XX_SETUP_SDHCI
select S3C64XX_SETUP_FB_24BPP
+ select S3C64XX_SETUP_USB_PHY
select SAMSUNG_DEV_ADC
select SAMSUNG_DEV_PWM
select SAMSUNG_DEV_TS
@@ -283,6 +290,7 @@ config MACH_WLF_CRAGG_6410
select S3C64XX_SETUP_FB_24BPP
select S3C64XX_SETUP_KEYPAD
select S3C64XX_SETUP_SPI
+ select S3C64XX_SETUP_USB_PHY
select SAMSUNG_DEV_ADC
select SAMSUNG_DEV_KEYPAD
select S3C_DEV_USB_HOST
diff --git a/arch/arm/mach-s3c64xx/Makefile b/arch/arm/mach-s3c64xx/Makefile
index 1822ac2eba31..f9ce1dc28ce4 100644
--- a/arch/arm/mach-s3c64xx/Makefile
+++ b/arch/arm/mach-s3c64xx/Makefile
@@ -22,6 +22,7 @@ obj-$(CONFIG_CPU_S3C6410) += s3c6410.o
# PM
obj-$(CONFIG_PM) += pm.o irq-pm.o sleep.o
+obj-$(CONFIG_CPU_IDLE) += cpuidle.o
# DMA support
@@ -42,6 +43,7 @@ obj-$(CONFIG_S3C64XX_SETUP_IDE) += setup-ide.o
obj-$(CONFIG_S3C64XX_SETUP_KEYPAD) += setup-keypad.o
obj-$(CONFIG_S3C64XX_SETUP_SDHCI_GPIO) += setup-sdhci-gpio.o
obj-$(CONFIG_S3C64XX_SETUP_SPI) += setup-spi.o
+obj-$(CONFIG_S3C64XX_SETUP_USB_PHY) += setup-usb-phy.o
# Machine support
diff --git a/arch/arm/mach-s3c64xx/clock.c b/arch/arm/mach-s3c64xx/clock.c
index aebbcc291b4e..52f079a691cb 100644
--- a/arch/arm/mach-s3c64xx/clock.c
+++ b/arch/arm/mach-s3c64xx/clock.c
@@ -207,6 +207,15 @@ static struct clk init_clocks_off[] = {
.enable = s3c64xx_sclk_ctrl,
.ctrlbit = S3C_CLKCON_SCLK_MMC2_48,
}, {
+ .name = "ac97",
+ .parent = &clk_p,
+ .ctrlbit = S3C_CLKCON_PCLK_AC97,
+ }, {
+ .name = "cfcon",
+ .parent = &clk_h,
+ .enable = s3c64xx_hclk_ctrl,
+ .ctrlbit = S3C_CLKCON_HCLK_IHOST,
+ }, {
.name = "dma0",
.parent = &clk_h,
.enable = s3c64xx_hclk_ctrl,
@@ -216,6 +225,107 @@ static struct clk init_clocks_off[] = {
.parent = &clk_h,
.enable = s3c64xx_hclk_ctrl,
.ctrlbit = S3C_CLKCON_HCLK_DMA1,
+ }, {
+ .name = "3dse",
+ .parent = &clk_h,
+ .enable = s3c64xx_hclk_ctrl,
+ .ctrlbit = S3C_CLKCON_HCLK_3DSE,
+ }, {
+ .name = "hclk_secur",
+ .parent = &clk_h,
+ .enable = s3c64xx_hclk_ctrl,
+ .ctrlbit = S3C_CLKCON_HCLK_SECUR,
+ }, {
+ .name = "sdma1",
+ .parent = &clk_h,
+ .enable = s3c64xx_hclk_ctrl,
+ .ctrlbit = S3C_CLKCON_HCLK_SDMA1,
+ }, {
+ .name = "sdma0",
+ .parent = &clk_h,
+ .enable = s3c64xx_hclk_ctrl,
+ .ctrlbit = S3C_CLKCON_HCLK_SDMA0,
+ }, {
+ .name = "hclk_jpeg",
+ .parent = &clk_h,
+ .enable = s3c64xx_hclk_ctrl,
+ .ctrlbit = S3C_CLKCON_HCLK_JPEG,
+ }, {
+ .name = "camif",
+ .parent = &clk_h,
+ .enable = s3c64xx_hclk_ctrl,
+ .ctrlbit = S3C_CLKCON_HCLK_CAMIF,
+ }, {
+ .name = "hclk_scaler",
+ .parent = &clk_h,
+ .enable = s3c64xx_hclk_ctrl,
+ .ctrlbit = S3C_CLKCON_HCLK_SCALER,
+ }, {
+ .name = "2d",
+ .parent = &clk_h,
+ .enable = s3c64xx_hclk_ctrl,
+ .ctrlbit = S3C_CLKCON_HCLK_2D,
+ }, {
+ .name = "tv",
+ .parent = &clk_h,
+ .enable = s3c64xx_hclk_ctrl,
+ .ctrlbit = S3C_CLKCON_HCLK_TV,
+ }, {
+ .name = "post0",
+ .parent = &clk_h,
+ .enable = s3c64xx_hclk_ctrl,
+ .ctrlbit = S3C_CLKCON_HCLK_POST0,
+ }, {
+ .name = "rot",
+ .parent = &clk_h,
+ .enable = s3c64xx_hclk_ctrl,
+ .ctrlbit = S3C_CLKCON_HCLK_ROT,
+ }, {
+ .name = "hclk_mfc",
+ .parent = &clk_h,
+ .enable = s3c64xx_hclk_ctrl,
+ .ctrlbit = S3C_CLKCON_HCLK_MFC,
+ }, {
+ .name = "pclk_mfc",
+ .parent = &clk_p,
+ .enable = s3c64xx_pclk_ctrl,
+ .ctrlbit = S3C_CLKCON_PCLK_MFC,
+ }, {
+ .name = "dac27",
+ .enable = s3c64xx_sclk_ctrl,
+ .ctrlbit = S3C_CLKCON_SCLK_DAC27,
+ }, {
+ .name = "tv27",
+ .enable = s3c64xx_sclk_ctrl,
+ .ctrlbit = S3C_CLKCON_SCLK_TV27,
+ }, {
+ .name = "scaler27",
+ .enable = s3c64xx_sclk_ctrl,
+ .ctrlbit = S3C_CLKCON_SCLK_SCALER27,
+ }, {
+ .name = "sclk_scaler",
+ .enable = s3c64xx_sclk_ctrl,
+ .ctrlbit = S3C_CLKCON_SCLK_SCALER,
+ }, {
+ .name = "post0_27",
+ .enable = s3c64xx_sclk_ctrl,
+ .ctrlbit = S3C_CLKCON_SCLK_POST0_27,
+ }, {
+ .name = "secur",
+ .enable = s3c64xx_sclk_ctrl,
+ .ctrlbit = S3C_CLKCON_SCLK_SECUR,
+ }, {
+ .name = "sclk_mfc",
+ .enable = s3c64xx_sclk_ctrl,
+ .ctrlbit = S3C_CLKCON_SCLK_MFC,
+ }, {
+ .name = "cam",
+ .enable = s3c64xx_sclk_ctrl,
+ .ctrlbit = S3C_CLKCON_SCLK_CAM,
+ }, {
+ .name = "sclk_jpeg",
+ .enable = s3c64xx_sclk_ctrl,
+ .ctrlbit = S3C_CLKCON_SCLK_JPEG,
},
};
@@ -289,16 +399,7 @@ static struct clk init_clocks[] = {
.name = "watchdog",
.parent = &clk_p,
.ctrlbit = S3C_CLKCON_PCLK_WDT,
- }, {
- .name = "ac97",
- .parent = &clk_p,
- .ctrlbit = S3C_CLKCON_PCLK_AC97,
- }, {
- .name = "cfcon",
- .parent = &clk_h,
- .enable = s3c64xx_hclk_ctrl,
- .ctrlbit = S3C_CLKCON_HCLK_IHOST,
- }
+ },
};
static struct clk clk_hsmmc0 = {
diff --git a/arch/arm/mach-s3c64xx/cpuidle.c b/arch/arm/mach-s3c64xx/cpuidle.c
new file mode 100644
index 000000000000..179460f38db7
--- /dev/null
+++ b/arch/arm/mach-s3c64xx/cpuidle.c
@@ -0,0 +1,91 @@
+/* linux/arch/arm/mach-s3c64xx/cpuidle.c
+ *
+ * Copyright (c) 2011 Wolfson Microelectronics, plc
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * 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.
+*/
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/cpuidle.h>
+#include <linux/io.h>
+#include <linux/export.h>
+#include <linux/time.h>
+
+#include <asm/proc-fns.h>
+
+#include <mach/map.h>
+
+#include <mach/regs-sys.h>
+#include <mach/regs-syscon-power.h>
+
+static int s3c64xx_enter_idle(struct cpuidle_device *dev,
+ struct cpuidle_driver *drv,
+ int index)
+{
+ struct timeval before, after;
+ unsigned long tmp;
+ int idle_time;
+
+ local_irq_disable();
+ do_gettimeofday(&before);
+
+ /* Setup PWRCFG to enter idle mode */
+ tmp = __raw_readl(S3C64XX_PWR_CFG);
+ tmp &= ~S3C64XX_PWRCFG_CFG_WFI_MASK;
+ tmp |= S3C64XX_PWRCFG_CFG_WFI_IDLE;
+ __raw_writel(tmp, S3C64XX_PWR_CFG);
+
+ cpu_do_idle();
+
+ do_gettimeofday(&after);
+ local_irq_enable();
+ idle_time = (after.tv_sec - before.tv_sec) * USEC_PER_SEC +
+ (after.tv_usec - before.tv_usec);
+
+ dev->last_residency = idle_time;
+ return index;
+}
+
+static struct cpuidle_state s3c64xx_cpuidle_set[] = {
+ [0] = {
+ .enter = s3c64xx_enter_idle,
+ .exit_latency = 1,
+ .target_residency = 1,
+ .flags = CPUIDLE_FLAG_TIME_VALID,
+ .name = "IDLE",
+ .desc = "System active, ARM gated",
+ },
+};
+
+static struct cpuidle_driver s3c64xx_cpuidle_driver = {
+ .name = "s3c64xx_cpuidle",
+ .owner = THIS_MODULE,
+ .state_count = ARRAY_SIZE(s3c64xx_cpuidle_set),
+};
+
+static struct cpuidle_device s3c64xx_cpuidle_device = {
+ .state_count = ARRAY_SIZE(s3c64xx_cpuidle_set),
+};
+
+static int __init s3c64xx_init_cpuidle(void)
+{
+ int ret;
+
+ memcpy(s3c64xx_cpuidle_driver.states, s3c64xx_cpuidle_set,
+ sizeof(s3c64xx_cpuidle_set));
+ cpuidle_register_driver(&s3c64xx_cpuidle_driver);
+
+ ret = cpuidle_register_device(&s3c64xx_cpuidle_device);
+ if (ret) {
+ pr_err("Failed to register cpuidle device: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+device_initcall(s3c64xx_init_cpuidle);
diff --git a/arch/arm/mach-s3c64xx/mach-crag6410.c b/arch/arm/mach-s3c64xx/mach-crag6410.c
index 8077f650eb0e..3b56bd9cb880 100644
--- a/arch/arm/mach-s3c64xx/mach-crag6410.c
+++ b/arch/arm/mach-s3c64xx/mach-crag6410.c
@@ -59,6 +59,7 @@
#include <plat/sdhci.h>
#include <plat/gpio-cfg.h>
#include <plat/s3c64xx-spi.h>
+#include <plat/udc-hs.h>
#include <plat/keypad.h>
#include <plat/clock.h>
@@ -698,6 +699,8 @@ static struct s3c_sdhci_platdata crag6410_hsmmc0_pdata = {
.cfg_gpio = crag6410_cfg_sdhci0,
};
+static struct s3c_hsotg_plat crag6410_hsotg_pdata;
+
static void __init crag6410_machine_init(void)
{
/* Open drain IRQs need pullups */
@@ -722,6 +725,7 @@ static void __init crag6410_machine_init(void)
s3c_i2c0_set_platdata(&i2c0_pdata);
s3c_i2c1_set_platdata(&i2c1_pdata);
s3c_fb_set_platdata(&crag6410_lcd_pdata);
+ s3c_hsotg_set_platdata(&crag6410_hsotg_pdata);
i2c_register_board_info(0, i2c_devs0, ARRAY_SIZE(i2c_devs0));
i2c_register_board_info(1, i2c_devs1, ARRAY_SIZE(i2c_devs1));
diff --git a/arch/arm/mach-s3c64xx/mach-smartq.c b/arch/arm/mach-s3c64xx/mach-smartq.c
index ce31db136231..ce745e19aa27 100644
--- a/arch/arm/mach-s3c64xx/mach-smartq.c
+++ b/arch/arm/mach-s3c64xx/mach-smartq.c
@@ -187,6 +187,8 @@ static struct s3c_hwmon_pdata smartq_hwmon_pdata __initdata = {
},
};
+static struct s3c_hsotg_plat smartq_hsotg_pdata;
+
static int __init smartq_lcd_setup_gpio(void)
{
int ret;
@@ -383,6 +385,7 @@ void __init smartq_map_io(void)
void __init smartq_machine_init(void)
{
s3c_i2c0_set_platdata(NULL);
+ s3c_hsotg_set_platdata(&smartq_hsotg_pdata);
s3c_hwmon_set_platdata(&smartq_hwmon_pdata);
s3c_sdhci1_set_platdata(&smartq_internal_hsmmc_pdata);
s3c_sdhci2_set_platdata(&smartq_internal_hsmmc_pdata);
diff --git a/arch/arm/mach-s3c64xx/mach-smdk6410.c b/arch/arm/mach-s3c64xx/mach-smdk6410.c
index ca6fc204f0ea..d55bc96d9582 100644
--- a/arch/arm/mach-s3c64xx/mach-smdk6410.c
+++ b/arch/arm/mach-s3c64xx/mach-smdk6410.c
@@ -72,6 +72,7 @@
#include <plat/keypad.h>
#include <plat/backlight.h>
#include <plat/regs-fb-v4.h>
+#include <plat/udc-hs.h>
#include "common.h"
@@ -631,6 +632,8 @@ static struct platform_pwm_backlight_data smdk6410_bl_data = {
.pwm_id = 1,
};
+static struct s3c_hsotg_plat smdk6410_hsotg_pdata;
+
static void __init smdk6410_map_io(void)
{
u32 tmp;
@@ -659,6 +662,7 @@ static void __init smdk6410_machine_init(void)
s3c_i2c0_set_platdata(NULL);
s3c_i2c1_set_platdata(NULL);
s3c_fb_set_platdata(&smdk6410_lcd_pdata);
+ s3c_hsotg_set_platdata(&smdk6410_hsotg_pdata);
samsung_keypad_set_platdata(&smdk6410_keypad_data);
diff --git a/arch/arm/mach-s3c64xx/setup-usb-phy.c b/arch/arm/mach-s3c64xx/setup-usb-phy.c
new file mode 100644
index 000000000000..f6757e02d7db
--- /dev/null
+++ b/arch/arm/mach-s3c64xx/setup-usb-phy.c
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2011 Samsung Electronics Co.Ltd
+ * Author: Joonyoung Shim <jy0922.shim@samsung.com>
+ *
+ * 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.
+ *
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <mach/map.h>
+#include <mach/regs-sys.h>
+#include <plat/cpu.h>
+#include <plat/regs-usb-hsotg-phy.h>
+#include <plat/usb-phy.h>
+
+static int s3c_usb_otgphy_init(struct platform_device *pdev)
+{
+ struct clk *xusbxti;
+ u32 phyclk;
+
+ writel(readl(S3C64XX_OTHERS) | S3C64XX_OTHERS_USBMASK, S3C64XX_OTHERS);
+
+ /* set clock frequency for PLL */
+ phyclk = readl(S3C_PHYCLK) & ~S3C_PHYCLK_CLKSEL_MASK;
+
+ xusbxti = clk_get(&pdev->dev, "xusbxti");
+ if (xusbxti && !IS_ERR(xusbxti)) {
+ switch (clk_get_rate(xusbxti)) {
+ case 12 * MHZ:
+ phyclk |= S3C_PHYCLK_CLKSEL_12M;
+ break;
+ case 24 * MHZ:
+ phyclk |= S3C_PHYCLK_CLKSEL_24M;
+ break;
+ default:
+ case 48 * MHZ:
+ /* default reference clock */
+ break;
+ }
+ clk_put(xusbxti);
+ }
+
+ /* TODO: select external clock/oscillator */
+ writel(phyclk | S3C_PHYCLK_CLK_FORCE, S3C_PHYCLK);
+
+ /* set to normal OTG PHY */
+ writel((readl(S3C_PHYPWR) & ~S3C_PHYPWR_NORMAL_MASK), S3C_PHYPWR);
+ mdelay(1);
+
+ /* reset OTG PHY and Link */
+ writel(S3C_RSTCON_PHY | S3C_RSTCON_HCLK | S3C_RSTCON_PHYCLK,
+ S3C_RSTCON);
+ udelay(20); /* at-least 10uS */
+ writel(0, S3C_RSTCON);
+
+ return 0;
+}
+
+static int s3c_usb_otgphy_exit(struct platform_device *pdev)
+{
+ writel((readl(S3C_PHYPWR) | S3C_PHYPWR_ANALOG_POWERDOWN |
+ S3C_PHYPWR_OTG_DISABLE), S3C_PHYPWR);
+
+ writel(readl(S3C64XX_OTHERS) & ~S3C64XX_OTHERS_USBMASK, S3C64XX_OTHERS);
+
+ return 0;
+}
+
+int s5p_usb_phy_init(struct platform_device *pdev, int type)
+{
+ if (type == S5P_USB_PHY_DEVICE)
+ return s3c_usb_otgphy_init(pdev);
+
+ return -EINVAL;
+}
+
+int s5p_usb_phy_exit(struct platform_device *pdev, int type)
+{
+ if (type == S5P_USB_PHY_DEVICE)
+ return s3c_usb_otgphy_exit(pdev);
+
+ return -EINVAL;
+}
diff --git a/arch/arm/mach-s5pv210/Kconfig b/arch/arm/mach-s5pv210/Kconfig
index 2cdc42e838b8..82525e3831e9 100644
--- a/arch/arm/mach-s5pv210/Kconfig
+++ b/arch/arm/mach-s5pv210/Kconfig
@@ -65,6 +65,11 @@ config S5PV210_SETUP_SPI
help
Common setup code for SPI GPIO configurations.
+config S5PV210_SETUP_USB_PHY
+ bool
+ help
+ Common setup code for USB PHY controller
+
menu "S5PC110 Machines"
config MACH_AQUILA
@@ -107,6 +112,7 @@ config MACH_GONI
select S5PV210_SETUP_KEYPAD
select S5PV210_SETUP_SDHCI
select S5PV210_SETUP_FIMC
+ select S5PV210_SETUP_USB_PHY
help
Machine support for Samsung GONI board
S5PC110(MCP) is one of package option of S5PV210
diff --git a/arch/arm/mach-s5pv210/Makefile b/arch/arm/mach-s5pv210/Makefile
index 76a121dd52b4..1c4e41998a10 100644
--- a/arch/arm/mach-s5pv210/Makefile
+++ b/arch/arm/mach-s5pv210/Makefile
@@ -39,3 +39,4 @@ obj-$(CONFIG_S5PV210_SETUP_IDE) += setup-ide.o
obj-$(CONFIG_S5PV210_SETUP_KEYPAD) += setup-keypad.o
obj-$(CONFIG_S5PV210_SETUP_SDHCI_GPIO) += setup-sdhci-gpio.o
obj-$(CONFIG_S5PV210_SETUP_SPI) += setup-spi.o
+obj-$(CONFIG_S5PV210_SETUP_USB_PHY) += setup-usb-phy.o
diff --git a/arch/arm/mach-s5pv210/include/mach/regs-sys.h b/arch/arm/mach-s5pv210/include/mach/regs-sys.h
index 26691d39d0f4..cccb1eddaa38 100644
--- a/arch/arm/mach-s5pv210/include/mach/regs-sys.h
+++ b/arch/arm/mach-s5pv210/include/mach/regs-sys.h
@@ -13,7 +13,3 @@
#define S5PV210_USB_PHY_CON (S3C_VA_SYS + 0xE80C)
#define S5PV210_USB_PHY0_EN (1 << 0)
#define S5PV210_USB_PHY1_EN (1 << 1)
-
-/* compatibility defines for s3c-hsotg driver */
-#define S3C64XX_OTHERS S5PV210_USB_PHY_CON
-#define S3C64XX_OTHERS_USBMASK S5PV210_USB_PHY0_EN
diff --git a/arch/arm/mach-s5pv210/setup-usb-phy.c b/arch/arm/mach-s5pv210/setup-usb-phy.c
new file mode 100644
index 000000000000..be39cf4aa91b
--- /dev/null
+++ b/arch/arm/mach-s5pv210/setup-usb-phy.c
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2012 Samsung Electronics Co.Ltd
+ * Author: Joonyoung Shim <jy0922.shim@samsung.com>
+ *
+ * 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 Foundationr
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <mach/map.h>
+#include <mach/regs-sys.h>
+#include <plat/cpu.h>
+#include <plat/regs-usb-hsotg-phy.h>
+#include <plat/usb-phy.h>
+
+static int s5pv210_usb_otgphy_init(struct platform_device *pdev)
+{
+ struct clk *xusbxti;
+ u32 phyclk;
+
+ writel(readl(S5PV210_USB_PHY_CON) | S5PV210_USB_PHY0_EN,
+ S5PV210_USB_PHY_CON);
+
+ /* set clock frequency for PLL */
+ phyclk = readl(S3C_PHYCLK) & ~S3C_PHYCLK_CLKSEL_MASK;
+
+ xusbxti = clk_get(&pdev->dev, "xusbxti");
+ if (xusbxti && !IS_ERR(xusbxti)) {
+ switch (clk_get_rate(xusbxti)) {
+ case 12 * MHZ:
+ phyclk |= S3C_PHYCLK_CLKSEL_12M;
+ break;
+ case 24 * MHZ:
+ phyclk |= S3C_PHYCLK_CLKSEL_24M;
+ break;
+ default:
+ case 48 * MHZ:
+ /* default reference clock */
+ break;
+ }
+ clk_put(xusbxti);
+ }
+
+ /* TODO: select external clock/oscillator */
+ writel(phyclk | S3C_PHYCLK_CLK_FORCE, S3C_PHYCLK);
+
+ /* set to normal OTG PHY */
+ writel((readl(S3C_PHYPWR) & ~S3C_PHYPWR_NORMAL_MASK), S3C_PHYPWR);
+ mdelay(1);
+
+ /* reset OTG PHY and Link */
+ writel(S3C_RSTCON_PHY | S3C_RSTCON_HCLK | S3C_RSTCON_PHYCLK,
+ S3C_RSTCON);
+ udelay(20); /* at-least 10uS */
+ writel(0, S3C_RSTCON);
+
+ return 0;
+}
+
+static int s5pv210_usb_otgphy_exit(struct platform_device *pdev)
+{
+ writel((readl(S3C_PHYPWR) | S3C_PHYPWR_ANALOG_POWERDOWN |
+ S3C_PHYPWR_OTG_DISABLE), S3C_PHYPWR);
+
+ writel(readl(S5PV210_USB_PHY_CON) & ~S5PV210_USB_PHY0_EN,
+ S5PV210_USB_PHY_CON);
+
+ return 0;
+}
+
+int s5p_usb_phy_init(struct platform_device *pdev, int type)
+{
+ if (type == S5P_USB_PHY_DEVICE)
+ return s5pv210_usb_otgphy_init(pdev);
+
+ return -EINVAL;
+}
+
+int s5p_usb_phy_exit(struct platform_device *pdev, int type)
+{
+ if (type == S5P_USB_PHY_DEVICE)
+ return s5pv210_usb_otgphy_exit(pdev);
+
+ return -EINVAL;
+}
diff --git a/arch/arm/mach-tegra/Makefile b/arch/arm/mach-tegra/Makefile
index bcbb4e8d5530..76a79b8a1721 100644
--- a/arch/arm/mach-tegra/Makefile
+++ b/arch/arm/mach-tegra/Makefile
@@ -7,12 +7,15 @@ obj-y += clock.o
obj-y += timer.o
obj-y += pinmux.o
obj-y += fuse.o
+obj-$(CONFIG_CPU_IDLE) += cpuidle.o
+obj-$(CONFIG_CPU_IDLE) += sleep.o
obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += powergate.o
obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra2_clocks.o
obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra2_emc.o
obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += pinmux-tegra20-tables.o
obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += pinmux-tegra30-tables.o
obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += board-dt-tegra30.o
+obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += tegra30_clocks.o
obj-$(CONFIG_SMP) += platsmp.o headsmp.o
obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o
obj-$(CONFIG_TEGRA_SYSTEM_DMA) += dma.o
diff --git a/arch/arm/mach-tegra/board-dt-tegra30.c b/arch/arm/mach-tegra/board-dt-tegra30.c
index 3c197e2440b7..b4124b12a779 100644
--- a/arch/arm/mach-tegra/board-dt-tegra30.c
+++ b/arch/arm/mach-tegra/board-dt-tegra30.c
@@ -34,16 +34,38 @@
#include <asm/hardware/gic.h>
#include "board.h"
+#include "clock.h"
static struct of_device_id tegra_dt_match_table[] __initdata = {
{ .compatible = "simple-bus", },
{}
};
+struct of_dev_auxdata tegra30_auxdata_lookup[] __initdata = {
+ OF_DEV_AUXDATA("nvidia,tegra20-sdhci", 0x78000000, "sdhci-tegra.0", NULL),
+ OF_DEV_AUXDATA("nvidia,tegra20-sdhci", 0x78000200, "sdhci-tegra.1", NULL),
+ OF_DEV_AUXDATA("nvidia,tegra20-sdhci", 0x78000400, "sdhci-tegra.2", NULL),
+ OF_DEV_AUXDATA("nvidia,tegra20-sdhci", 0x78000600, "sdhci-tegra.3", NULL),
+ OF_DEV_AUXDATA("nvidia,tegra20-i2c", 0x7000C000, "tegra-i2c.0", NULL),
+ OF_DEV_AUXDATA("nvidia,tegra20-i2c", 0x7000C400, "tegra-i2c.1", NULL),
+ OF_DEV_AUXDATA("nvidia,tegra20-i2c", 0x7000C500, "tegra-i2c.2", NULL),
+ OF_DEV_AUXDATA("nvidia,tegra20-i2c", 0x7000C700, "tegra-i2c.3", NULL),
+ OF_DEV_AUXDATA("nvidia,tegra20-i2c", 0x7000D000, "tegra-i2c.4", NULL),
+ {}
+};
+
+static __initdata struct tegra_clk_init_table tegra_dt_clk_init_table[] = {
+ /* name parent rate enabled */
+ { "uartd", "pll_p", 408000000, true },
+ { NULL, NULL, 0, 0},
+};
+
static void __init tegra30_dt_init(void)
{
+ tegra_clk_init_from_table(tegra_dt_clk_init_table);
+
of_platform_populate(NULL, tegra_dt_match_table,
- NULL, NULL);
+ tegra30_auxdata_lookup, NULL);
}
static const char *tegra30_dt_board_compat[] = {
diff --git a/arch/arm/mach-tegra/clock.c b/arch/arm/mach-tegra/clock.c
index 8337068a4abe..8dad8d18cb49 100644
--- a/arch/arm/mach-tegra/clock.c
+++ b/arch/arm/mach-tegra/clock.c
@@ -399,6 +399,28 @@ void tegra_periph_reset_assert(struct clk *c)
}
EXPORT_SYMBOL(tegra_periph_reset_assert);
+/* Several extended clock configuration bits (e.g., clock routing, clock
+ * phase control) are included in PLL and peripheral clock source
+ * registers. */
+int tegra_clk_cfg_ex(struct clk *c, enum tegra_clk_ex_param p, u32 setting)
+{
+ int ret = 0;
+ unsigned long flags;
+
+ spin_lock_irqsave(&c->spinlock, flags);
+
+ if (!c->ops || !c->ops->clk_cfg_ex) {
+ ret = -ENOSYS;
+ goto out;
+ }
+ ret = c->ops->clk_cfg_ex(c, p, setting);
+
+out:
+ spin_unlock_irqrestore(&c->spinlock, flags);
+
+ return ret;
+}
+
#ifdef CONFIG_DEBUG_FS
static int __clk_lock_all_spinlocks(void)
diff --git a/arch/arm/mach-tegra/clock.h b/arch/arm/mach-tegra/clock.h
index 5c44106616c5..bc300657deba 100644
--- a/arch/arm/mach-tegra/clock.h
+++ b/arch/arm/mach-tegra/clock.h
@@ -24,6 +24,8 @@
#include <linux/list.h>
#include <linux/spinlock.h>
+#include <mach/clk.h>
+
#define DIV_BUS (1 << 0)
#define DIV_U71 (1 << 1)
#define DIV_U71_FIXED (1 << 2)
@@ -39,7 +41,16 @@
#define PERIPH_MANUAL_RESET (1 << 12)
#define PLL_ALT_MISC_REG (1 << 13)
#define PLLU (1 << 14)
+#define PLLX (1 << 15)
+#define MUX_PWM (1 << 16)
+#define MUX8 (1 << 17)
+#define DIV_U71_UART (1 << 18)
+#define MUX_CLK_OUT (1 << 19)
+#define PLLM (1 << 20)
+#define DIV_U71_INT (1 << 21)
+#define DIV_U71_IDLE (1 << 22)
#define ENABLE_ON_INIT (1 << 28)
+#define PERIPH_ON_APB (1 << 29)
struct clk;
@@ -65,6 +76,8 @@ struct clk_ops {
int (*set_rate)(struct clk *, unsigned long);
long (*round_rate)(struct clk *, unsigned long);
void (*reset)(struct clk *, bool);
+ int (*clk_cfg_ex)(struct clk *,
+ enum tegra_clk_ex_param, u32);
};
enum clk_state {
@@ -114,6 +127,7 @@ struct clk {
unsigned long vco_max;
const struct clk_pll_freq_table *freq_table;
int lock_delay;
+ unsigned long fixed_rate;
} pll;
struct {
u32 sel;
@@ -146,6 +160,7 @@ struct tegra_clk_init_table {
};
void tegra2_init_clocks(void);
+void tegra30_init_clocks(void);
void clk_init(struct clk *clk);
struct clk *tegra_get_clock_by_name(const char *name);
int clk_reparent(struct clk *c, struct clk *parent);
diff --git a/arch/arm/mach-tegra/common.c b/arch/arm/mach-tegra/common.c
index fac449e84d80..6c93cd0e520c 100644
--- a/arch/arm/mach-tegra/common.c
+++ b/arch/arm/mach-tegra/common.c
@@ -104,6 +104,7 @@ void __init tegra20_init_early(void)
#ifdef CONFIG_ARCH_TEGRA_3x_SOC
void __init tegra30_init_early(void)
{
+ tegra30_init_clocks();
tegra_init_cache(0x441, 0x551);
}
#endif
diff --git a/arch/arm/mach-tegra/cpuidle.c b/arch/arm/mach-tegra/cpuidle.c
new file mode 100644
index 000000000000..d83a8c0296f5
--- /dev/null
+++ b/arch/arm/mach-tegra/cpuidle.c
@@ -0,0 +1,107 @@
+/*
+ * arch/arm/mach-tegra/cpuidle.c
+ *
+ * CPU idle driver for Tegra CPUs
+ *
+ * Copyright (c) 2010-2012, NVIDIA Corporation.
+ * Copyright (c) 2011 Google, Inc.
+ * Author: Colin Cross <ccross@android.com>
+ * Gary King <gking@nvidia.com>
+ *
+ * Rework for 3.3 by Peter De Schrijver <pdeschrijver@nvidia.com>
+ *
+ * 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/module.h>
+#include <linux/cpu.h>
+#include <linux/cpuidle.h>
+#include <linux/hrtimer.h>
+
+#include <mach/iomap.h>
+
+extern void tegra_cpu_wfi(void);
+
+static int tegra_idle_enter_lp3(struct cpuidle_device *dev,
+ struct cpuidle_driver *drv, int index);
+
+struct cpuidle_driver tegra_idle_driver = {
+ .name = "tegra_idle",
+ .owner = THIS_MODULE,
+ .state_count = 1,
+ .states = {
+ [0] = {
+ .enter = tegra_idle_enter_lp3,
+ .exit_latency = 10,
+ .target_residency = 10,
+ .power_usage = 600,
+ .flags = CPUIDLE_FLAG_TIME_VALID,
+ .name = "LP3",
+ .desc = "CPU flow-controlled",
+ },
+ },
+};
+
+static DEFINE_PER_CPU(struct cpuidle_device, tegra_idle_device);
+
+static int tegra_idle_enter_lp3(struct cpuidle_device *dev,
+ struct cpuidle_driver *drv, int index)
+{
+ ktime_t enter, exit;
+ s64 us;
+
+ local_irq_disable();
+ local_fiq_disable();
+
+ enter = ktime_get();
+
+ tegra_cpu_wfi();
+
+ exit = ktime_sub(ktime_get(), enter);
+ us = ktime_to_us(exit);
+
+ local_fiq_enable();
+ local_irq_enable();
+
+ dev->last_residency = us;
+
+ return index;
+}
+
+static int __init tegra_cpuidle_init(void)
+{
+ int ret;
+ unsigned int cpu;
+ struct cpuidle_device *dev;
+ struct cpuidle_driver *drv = &tegra_idle_driver;
+
+ ret = cpuidle_register_driver(&tegra_idle_driver);
+ if (ret) {
+ pr_err("CPUidle driver registration failed\n");
+ return ret;
+ }
+
+ for_each_possible_cpu(cpu) {
+ dev = &per_cpu(tegra_idle_device, cpu);
+ dev->cpu = cpu;
+
+ dev->state_count = drv->state_count;
+ ret = cpuidle_register_device(dev);
+ if (ret) {
+ pr_err("CPU%u: CPUidle device registration failed\n",
+ cpu);
+ return ret;
+ }
+ }
+ return 0;
+}
+device_initcall(tegra_cpuidle_init);
diff --git a/arch/arm/mach-tegra/flowctrl.h b/arch/arm/mach-tegra/flowctrl.h
new file mode 100644
index 000000000000..74c6efbe52fa
--- /dev/null
+++ b/arch/arm/mach-tegra/flowctrl.h
@@ -0,0 +1,37 @@
+/*
+ * arch/arm/mach-tegra/flowctrl.h
+ *
+ * functions and macros to control the flowcontroller
+ *
+ * Copyright (c) 2010-2012, NVIDIA Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __MACH_TEGRA_FLOWCTRL_H
+#define __MACH_TEGRA_FLOWCTRL_H
+
+#define FLOW_CTRL_HALT_CPU0_EVENTS 0x0
+#define FLOW_CTRL_WAITEVENT (2 << 29)
+#define FLOW_CTRL_WAIT_FOR_INTERRUPT (4 << 29)
+#define FLOW_CTRL_JTAG_RESUME (1 << 28)
+#define FLOW_CTRL_HALT_CPU_IRQ (1 << 10)
+#define FLOW_CTRL_HALT_CPU_FIQ (1 << 8)
+#define FLOW_CTRL_CPU0_CSR 0x8
+#define FLOW_CTRL_CSR_INTR_FLAG (1 << 15)
+#define FLOW_CTRL_CSR_EVENT_FLAG (1 << 14)
+#define FLOW_CTRL_CSR_ENABLE (1 << 0)
+#define FLOW_CTRL_HALT_CPU1_EVENTS 0x14
+#define FLOW_CTRL_CPU1_CSR 0x18
+
+#endif
diff --git a/arch/arm/mach-tegra/include/mach/clk.h b/arch/arm/mach-tegra/include/mach/clk.h
index fc3ecb66de08..d97e403303a0 100644
--- a/arch/arm/mach-tegra/include/mach/clk.h
+++ b/arch/arm/mach-tegra/include/mach/clk.h
@@ -22,10 +22,20 @@
struct clk;
+enum tegra_clk_ex_param {
+ TEGRA_CLK_VI_INP_SEL,
+ TEGRA_CLK_DTV_INVERT,
+ TEGRA_CLK_NAND_PAD_DIV2_ENB,
+ TEGRA_CLK_PLLD_CSI_OUT_ENB,
+ TEGRA_CLK_PLLD_DSI_OUT_ENB,
+ TEGRA_CLK_PLLD_MIPI_MUX_SEL,
+};
+
void tegra_periph_reset_deassert(struct clk *c);
void tegra_periph_reset_assert(struct clk *c);
unsigned long clk_get_rate_all_locked(struct clk *c);
void tegra2_sdmmc_tap_delay(struct clk *c, int delay);
+int tegra_clk_cfg_ex(struct clk *c, enum tegra_clk_ex_param p, u32 setting);
#endif
diff --git a/arch/arm/mach-tegra/include/mach/iomap.h b/arch/arm/mach-tegra/include/mach/iomap.h
index 19dec3ac0854..67644c905d8e 100644
--- a/arch/arm/mach-tegra/include/mach/iomap.h
+++ b/arch/arm/mach-tegra/include/mach/iomap.h
@@ -74,6 +74,9 @@
#define TEGRA_QUATERNARY_ICTLR_BASE 0x60004300
#define TEGRA_QUATERNARY_ICTLR_SIZE SZ_64
+#define TEGRA_QUINARY_ICTLR_BASE 0x60004400
+#define TEGRA_QUINARY_ICTLR_SIZE SZ_64
+
#define TEGRA_TMR1_BASE 0x60005000
#define TEGRA_TMR1_SIZE SZ_8
diff --git a/arch/arm/mach-tegra/include/mach/irqs.h b/arch/arm/mach-tegra/include/mach/irqs.h
index a2146cd6867d..aad1a2c1d714 100644
--- a/arch/arm/mach-tegra/include/mach/irqs.h
+++ b/arch/arm/mach-tegra/include/mach/irqs.h
@@ -165,11 +165,12 @@
#define INT_QUAD_RES_30 (INT_QUAD_BASE + 30)
#define INT_QUAD_RES_31 (INT_QUAD_BASE + 31)
-#define INT_MAIN_NR (INT_QUAD_BASE + 32 - INT_PRI_BASE)
-
+/* Tegra30 has 5 banks of 32 IRQs */
+#define INT_MAIN_NR (32 * 5)
#define INT_GPIO_BASE (INT_PRI_BASE + INT_MAIN_NR)
-#define INT_GPIO_NR (28 * 8)
+/* Tegra30 has 8 banks of 32 GPIOs */
+#define INT_GPIO_NR (32 * 8)
#define TEGRA_NR_IRQS (INT_GPIO_BASE + INT_GPIO_NR)
diff --git a/arch/arm/mach-tegra/irq.c b/arch/arm/mach-tegra/irq.c
index 4e1afcd54fae..2f5bd2db8e1f 100644
--- a/arch/arm/mach-tegra/irq.c
+++ b/arch/arm/mach-tegra/irq.c
@@ -44,14 +44,16 @@
#define ICTLR_COP_IER_CLR 0x38
#define ICTLR_COP_IEP_CLASS 0x3c
-#define NUM_ICTLRS 4
#define FIRST_LEGACY_IRQ 32
+static int num_ictlrs;
+
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),
+ IO_ADDRESS(TEGRA_QUINARY_ICTLR_BASE),
};
static inline void tegra_irq_write_mask(unsigned int irq, unsigned long reg)
@@ -60,7 +62,7 @@ static inline void tegra_irq_write_mask(unsigned int irq, unsigned long reg)
u32 mask;
BUG_ON(irq < FIRST_LEGACY_IRQ ||
- irq >= FIRST_LEGACY_IRQ + NUM_ICTLRS * 32);
+ irq >= FIRST_LEGACY_IRQ + num_ictlrs * 32);
base = ictlr_reg_base[(irq - FIRST_LEGACY_IRQ) / 32];
mask = BIT((irq - FIRST_LEGACY_IRQ) % 32);
@@ -113,8 +115,18 @@ static int tegra_retrigger(struct irq_data *d)
void __init tegra_init_irq(void)
{
int i;
+ void __iomem *distbase;
+
+ distbase = IO_ADDRESS(TEGRA_ARM_INT_DIST_BASE);
+ num_ictlrs = readl_relaxed(distbase + GIC_DIST_CTR) & 0x1f;
+
+ if (num_ictlrs > ARRAY_SIZE(ictlr_reg_base)) {
+ WARN(1, "Too many (%d) interrupt controllers found. Maximum is %d.",
+ num_ictlrs, ARRAY_SIZE(ictlr_reg_base));
+ num_ictlrs = ARRAY_SIZE(ictlr_reg_base);
+ }
- for (i = 0; i < NUM_ICTLRS; i++) {
+ for (i = 0; i < num_ictlrs; i++) {
void __iomem *ictlr = ictlr_reg_base[i];
writel(~0, ictlr + ICTLR_CPU_IER_CLR);
writel(0, ictlr + ICTLR_CPU_IEP_CLASS);
@@ -131,6 +143,6 @@ void __init tegra_init_irq(void)
* initialized elsewhere under DT.
*/
if (!of_have_populated_dt())
- gic_init(0, 29, IO_ADDRESS(TEGRA_ARM_INT_DIST_BASE),
+ gic_init(0, 29, distbase,
IO_ADDRESS(TEGRA_ARM_PERIF_BASE + 0x100));
}
diff --git a/arch/arm/mach-tegra/sleep.S b/arch/arm/mach-tegra/sleep.S
new file mode 100644
index 000000000000..8f9fde161c34
--- /dev/null
+++ b/arch/arm/mach-tegra/sleep.S
@@ -0,0 +1,91 @@
+/*
+ * arch/arm/mach-tegra/sleep.S
+ *
+ * Copyright (c) 2010-2011, NVIDIA Corporation.
+ * Copyright (c) 2011, Google, Inc.
+ *
+ * Author: Colin Cross <ccross@android.com>
+ * Gary King <gking@nvidia.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <linux/linkage.h>
+#include <mach/io.h>
+#include <mach/iomap.h>
+
+#include "flowctrl.h"
+
+#define TEGRA_FLOW_CTRL_VIRT (TEGRA_FLOW_CTRL_BASE - IO_PPSB_PHYS \
+ + IO_PPSB_VIRT)
+
+/* returns the offset of the flow controller halt register for a cpu */
+.macro cpu_to_halt_reg rd, rcpu
+ cmp \rcpu, #0
+ subne \rd, \rcpu, #1
+ movne \rd, \rd, lsl #3
+ addne \rd, \rd, #0x14
+ moveq \rd, #0
+.endm
+
+/* returns the offset of the flow controller csr register for a cpu */
+.macro cpu_to_csr_reg rd, rcpu
+ cmp \rcpu, #0
+ subne \rd, \rcpu, #1
+ movne \rd, \rd, lsl #3
+ addne \rd, \rd, #0x18
+ moveq \rd, #8
+.endm
+
+/* returns the ID of the current processor */
+.macro cpu_id, rd
+ mrc p15, 0, \rd, c0, c0, 5
+ and \rd, \rd, #0xF
+.endm
+
+/* loads a 32-bit value into a register without a data access */
+.macro mov32, reg, val
+ movw \reg, #:lower16:\val
+ movt \reg, #:upper16:\val
+.endm
+
+/*
+ * tegra_cpu_wfi
+ *
+ * puts current CPU in clock-gated wfi using the flow controller
+ *
+ * corrupts r0-r3
+ * must be called with MMU on
+ */
+
+ENTRY(tegra_cpu_wfi)
+ cpu_id r0
+ cpu_to_halt_reg r1, r0
+ cpu_to_csr_reg r2, r0
+ mov32 r0, TEGRA_FLOW_CTRL_VIRT
+ mov r3, #FLOW_CTRL_CSR_INTR_FLAG | FLOW_CTRL_CSR_EVENT_FLAG
+ str r3, [r0, r2] @ clear event & interrupt status
+ mov r3, #FLOW_CTRL_WAIT_FOR_INTERRUPT | FLOW_CTRL_JTAG_RESUME
+ str r3, [r0, r1] @ put flow controller in wait irq mode
+ dsb
+ wfi
+ mov r3, #0
+ str r3, [r0, r1] @ clear flow controller halt status
+ mov r3, #FLOW_CTRL_CSR_INTR_FLAG | FLOW_CTRL_CSR_EVENT_FLAG
+ str r3, [r0, r2] @ clear event & interrupt status
+ dsb
+ mov pc, lr
+ENDPROC(tegra_cpu_wfi)
+
diff --git a/arch/arm/mach-tegra/tegra2_clocks.c b/arch/arm/mach-tegra/tegra2_clocks.c
index ff9e6b6c0460..1976e934cdd9 100644
--- a/arch/arm/mach-tegra/tegra2_clocks.c
+++ b/arch/arm/mach-tegra/tegra2_clocks.c
@@ -1143,15 +1143,35 @@ static void tegra2_emc_clk_init(struct clk *c)
static long tegra2_emc_clk_round_rate(struct clk *c, unsigned long rate)
{
- long new_rate = rate;
+ long emc_rate;
+ long clk_rate;
- new_rate = tegra_emc_round_rate(new_rate);
- if (new_rate < 0)
+ /*
+ * The slowest entry in the EMC clock table that is at least as
+ * fast as rate.
+ */
+ emc_rate = tegra_emc_round_rate(rate);
+ if (emc_rate < 0)
return c->max_rate;
- BUG_ON(new_rate != tegra2_periph_clk_round_rate(c, new_rate));
+ /*
+ * The fastest rate the PLL will generate that is at most the
+ * requested rate.
+ */
+ clk_rate = tegra2_periph_clk_round_rate(c, emc_rate);
+
+ /*
+ * If this fails, and emc_rate > clk_rate, it's because the maximum
+ * rate in the EMC tables is larger than the maximum rate of the EMC
+ * clock. The EMC clock's max rate is the rate it was running when the
+ * kernel booted. Such a mismatch is probably due to using the wrong
+ * BCT, i.e. using a Tegra20 BCT with an EMC table written for Tegra25.
+ */
+ WARN_ONCE(emc_rate != clk_rate,
+ "emc_rate %ld != clk_rate %ld",
+ emc_rate, clk_rate);
- return new_rate;
+ return emc_rate;
}
static int tegra2_emc_clk_set_rate(struct clk *c, unsigned long rate)
diff --git a/arch/arm/mach-tegra/tegra30_clocks.c b/arch/arm/mach-tegra/tegra30_clocks.c
new file mode 100644
index 000000000000..6d08b53f92d2
--- /dev/null
+++ b/arch/arm/mach-tegra/tegra30_clocks.c
@@ -0,0 +1,3099 @@
+/*
+ * arch/arm/mach-tegra/tegra30_clocks.c
+ *
+ * Copyright (c) 2010-2011 NVIDIA CORPORATION. All rights reserved.
+ *
+ * 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; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/cpufreq.h>
+#include <linux/syscore_ops.h>
+
+#include <asm/clkdev.h>
+
+#include <mach/iomap.h>
+
+#include "clock.h"
+#include "fuse.h"
+
+#define USE_PLL_LOCK_BITS 0
+
+#define RST_DEVICES_L 0x004
+#define RST_DEVICES_H 0x008
+#define RST_DEVICES_U 0x00C
+#define RST_DEVICES_V 0x358
+#define RST_DEVICES_W 0x35C
+#define RST_DEVICES_SET_L 0x300
+#define RST_DEVICES_CLR_L 0x304
+#define RST_DEVICES_SET_V 0x430
+#define RST_DEVICES_CLR_V 0x434
+#define RST_DEVICES_NUM 5
+
+#define CLK_OUT_ENB_L 0x010
+#define CLK_OUT_ENB_H 0x014
+#define CLK_OUT_ENB_U 0x018
+#define CLK_OUT_ENB_V 0x360
+#define CLK_OUT_ENB_W 0x364
+#define CLK_OUT_ENB_SET_L 0x320
+#define CLK_OUT_ENB_CLR_L 0x324
+#define CLK_OUT_ENB_SET_V 0x440
+#define CLK_OUT_ENB_CLR_V 0x444
+#define CLK_OUT_ENB_NUM 5
+
+#define RST_DEVICES_V_SWR_CPULP_RST_DIS (0x1 << 1)
+#define CLK_OUT_ENB_V_CLK_ENB_CPULP_EN (0x1 << 1)
+
+#define PERIPH_CLK_TO_BIT(c) (1 << (c->u.periph.clk_num % 32))
+#define PERIPH_CLK_TO_RST_REG(c) \
+ periph_clk_to_reg((c), RST_DEVICES_L, RST_DEVICES_V, 4)
+#define PERIPH_CLK_TO_RST_SET_REG(c) \
+ periph_clk_to_reg((c), RST_DEVICES_SET_L, RST_DEVICES_SET_V, 8)
+#define PERIPH_CLK_TO_RST_CLR_REG(c) \
+ periph_clk_to_reg((c), RST_DEVICES_CLR_L, RST_DEVICES_CLR_V, 8)
+
+#define PERIPH_CLK_TO_ENB_REG(c) \
+ periph_clk_to_reg((c), CLK_OUT_ENB_L, CLK_OUT_ENB_V, 4)
+#define PERIPH_CLK_TO_ENB_SET_REG(c) \
+ periph_clk_to_reg((c), CLK_OUT_ENB_SET_L, CLK_OUT_ENB_SET_V, 8)
+#define PERIPH_CLK_TO_ENB_CLR_REG(c) \
+ periph_clk_to_reg((c), CLK_OUT_ENB_CLR_L, CLK_OUT_ENB_CLR_V, 8)
+
+#define CLK_MASK_ARM 0x44
+#define MISC_CLK_ENB 0x48
+
+#define OSC_CTRL 0x50
+#define OSC_CTRL_OSC_FREQ_MASK (0xF<<28)
+#define OSC_CTRL_OSC_FREQ_13MHZ (0x0<<28)
+#define OSC_CTRL_OSC_FREQ_19_2MHZ (0x4<<28)
+#define OSC_CTRL_OSC_FREQ_12MHZ (0x8<<28)
+#define OSC_CTRL_OSC_FREQ_26MHZ (0xC<<28)
+#define OSC_CTRL_OSC_FREQ_16_8MHZ (0x1<<28)
+#define OSC_CTRL_OSC_FREQ_38_4MHZ (0x5<<28)
+#define OSC_CTRL_OSC_FREQ_48MHZ (0x9<<28)
+#define OSC_CTRL_MASK (0x3f2 | OSC_CTRL_OSC_FREQ_MASK)
+
+#define OSC_CTRL_PLL_REF_DIV_MASK (3<<26)
+#define OSC_CTRL_PLL_REF_DIV_1 (0<<26)
+#define OSC_CTRL_PLL_REF_DIV_2 (1<<26)
+#define OSC_CTRL_PLL_REF_DIV_4 (2<<26)
+
+#define OSC_FREQ_DET 0x58
+#define OSC_FREQ_DET_TRIG (1<<31)
+
+#define OSC_FREQ_DET_STATUS 0x5C
+#define OSC_FREQ_DET_BUSY (1<<31)
+#define OSC_FREQ_DET_CNT_MASK 0xFFFF
+
+#define PERIPH_CLK_SOURCE_I2S1 0x100
+#define PERIPH_CLK_SOURCE_EMC 0x19c
+#define PERIPH_CLK_SOURCE_OSC 0x1fc
+#define PERIPH_CLK_SOURCE_NUM1 \
+ ((PERIPH_CLK_SOURCE_OSC - PERIPH_CLK_SOURCE_I2S1) / 4)
+
+#define PERIPH_CLK_SOURCE_G3D2 0x3b0
+#define PERIPH_CLK_SOURCE_SE 0x42c
+#define PERIPH_CLK_SOURCE_NUM2 \
+ ((PERIPH_CLK_SOURCE_SE - PERIPH_CLK_SOURCE_G3D2) / 4 + 1)
+
+#define AUDIO_DLY_CLK 0x49c
+#define AUDIO_SYNC_CLK_SPDIF 0x4b4
+#define PERIPH_CLK_SOURCE_NUM3 \
+ ((AUDIO_SYNC_CLK_SPDIF - AUDIO_DLY_CLK) / 4 + 1)
+
+#define PERIPH_CLK_SOURCE_NUM (PERIPH_CLK_SOURCE_NUM1 + \
+ PERIPH_CLK_SOURCE_NUM2 + \
+ PERIPH_CLK_SOURCE_NUM3)
+
+#define CPU_SOFTRST_CTRL 0x380
+
+#define PERIPH_CLK_SOURCE_DIVU71_MASK 0xFF
+#define PERIPH_CLK_SOURCE_DIVU16_MASK 0xFFFF
+#define PERIPH_CLK_SOURCE_DIV_SHIFT 0
+#define PERIPH_CLK_SOURCE_DIVIDLE_SHIFT 8
+#define PERIPH_CLK_SOURCE_DIVIDLE_VAL 50
+#define PERIPH_CLK_UART_DIV_ENB (1<<24)
+#define PERIPH_CLK_VI_SEL_EX_SHIFT 24
+#define PERIPH_CLK_VI_SEL_EX_MASK (0x3<<PERIPH_CLK_VI_SEL_EX_SHIFT)
+#define PERIPH_CLK_NAND_DIV_EX_ENB (1<<8)
+#define PERIPH_CLK_DTV_POLARITY_INV (1<<25)
+
+#define AUDIO_SYNC_SOURCE_MASK 0x0F
+#define AUDIO_SYNC_DISABLE_BIT 0x10
+#define AUDIO_SYNC_TAP_NIBBLE_SHIFT(c) ((c->reg_shift - 24) * 4)
+
+#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)
+#define PLL_BASE_DIVN_SHIFT 8
+#define PLL_BASE_DIVM_MASK (0x1F)
+#define PLL_BASE_DIVM_SHIFT 0
+
+#define PLL_OUT_RATIO_MASK (0xFF<<8)
+#define PLL_OUT_RATIO_SHIFT 8
+#define PLL_OUT_OVERRIDE (1<<2)
+#define PLL_OUT_CLKEN (1<<1)
+#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 | PLLD)) ? (1<<22) : (1<<18))
+
+#define PLL_MISC_DCCON_SHIFT 20
+#define PLL_MISC_CPCON_SHIFT 8
+#define PLL_MISC_CPCON_MASK (0xF<<PLL_MISC_CPCON_SHIFT)
+#define PLL_MISC_LFCON_SHIFT 4
+#define PLL_MISC_LFCON_MASK (0xF<<PLL_MISC_LFCON_SHIFT)
+#define PLL_MISC_VCOCON_SHIFT 0
+#define PLL_MISC_VCOCON_MASK (0xF<<PLL_MISC_VCOCON_SHIFT)
+#define PLLD_MISC_CLKENABLE (1<<30)
+
+#define PLLU_BASE_POST_DIV (1<<20)
+
+#define PLLD_BASE_DSIB_MUX_SHIFT 25
+#define PLLD_BASE_DSIB_MUX_MASK (1<<PLLD_BASE_DSIB_MUX_SHIFT)
+#define PLLD_BASE_CSI_CLKENABLE (1<<26)
+#define PLLD_MISC_DSI_CLKENABLE (1<<30)
+#define PLLD_MISC_DIV_RST (1<<23)
+#define PLLD_MISC_DCCON_SHIFT 12
+
+#define PLLDU_LFCON_SET_DIVN 600
+
+/* FIXME: OUT_OF_TABLE_CPCON per pll */
+#define OUT_OF_TABLE_CPCON 0x8
+
+#define SUPER_CLK_MUX 0x00
+#define SUPER_STATE_SHIFT 28
+#define SUPER_STATE_MASK (0xF << SUPER_STATE_SHIFT)
+#define SUPER_STATE_STANDBY (0x0 << SUPER_STATE_SHIFT)
+#define SUPER_STATE_IDLE (0x1 << SUPER_STATE_SHIFT)
+#define SUPER_STATE_RUN (0x2 << SUPER_STATE_SHIFT)
+#define SUPER_STATE_IRQ (0x3 << SUPER_STATE_SHIFT)
+#define SUPER_STATE_FIQ (0x4 << SUPER_STATE_SHIFT)
+#define SUPER_LP_DIV2_BYPASS (0x1 << 16)
+#define SUPER_SOURCE_MASK 0xF
+#define SUPER_FIQ_SOURCE_SHIFT 12
+#define SUPER_IRQ_SOURCE_SHIFT 8
+#define SUPER_RUN_SOURCE_SHIFT 4
+#define SUPER_IDLE_SOURCE_SHIFT 0
+
+#define SUPER_CLK_DIVIDER 0x04
+#define SUPER_CLOCK_DIV_U71_SHIFT 16
+#define SUPER_CLOCK_DIV_U71_MASK (0xff << SUPER_CLOCK_DIV_U71_SHIFT)
+/* guarantees safe cpu backup */
+#define SUPER_CLOCK_DIV_U71_MIN 0x2
+
+#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
+
+#define PMC_PLLP_WB0_OVERRIDE 0xf8
+#define PMC_PLLP_WB0_OVERRIDE_PLLM_ENABLE (1 << 12)
+
+#define UTMIP_PLL_CFG2 0x488
+#define UTMIP_PLL_CFG2_STABLE_COUNT(x) (((x) & 0xfff) << 6)
+#define UTMIP_PLL_CFG2_ACTIVE_DLY_COUNT(x) (((x) & 0x3f) << 18)
+#define UTMIP_PLL_CFG2_FORCE_PD_SAMP_A_POWERDOWN (1 << 0)
+#define UTMIP_PLL_CFG2_FORCE_PD_SAMP_B_POWERDOWN (1 << 2)
+#define UTMIP_PLL_CFG2_FORCE_PD_SAMP_C_POWERDOWN (1 << 4)
+
+#define UTMIP_PLL_CFG1 0x484
+#define UTMIP_PLL_CFG1_ENABLE_DLY_COUNT(x) (((x) & 0x1f) << 27)
+#define UTMIP_PLL_CFG1_XTAL_FREQ_COUNT(x) (((x) & 0xfff) << 0)
+#define UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERDOWN (1 << 14)
+#define UTMIP_PLL_CFG1_FORCE_PLL_ACTIVE_POWERDOWN (1 << 12)
+#define UTMIP_PLL_CFG1_FORCE_PLLU_POWERDOWN (1 << 16)
+
+#define PLLE_BASE_CML_ENABLE (1<<31)
+#define PLLE_BASE_ENABLE (1<<30)
+#define PLLE_BASE_DIVCML_SHIFT 24
+#define PLLE_BASE_DIVCML_MASK (0xf<<PLLE_BASE_DIVCML_SHIFT)
+#define PLLE_BASE_DIVP_SHIFT 16
+#define PLLE_BASE_DIVP_MASK (0x3f<<PLLE_BASE_DIVP_SHIFT)
+#define PLLE_BASE_DIVN_SHIFT 8
+#define PLLE_BASE_DIVN_MASK (0xFF<<PLLE_BASE_DIVN_SHIFT)
+#define PLLE_BASE_DIVM_SHIFT 0
+#define PLLE_BASE_DIVM_MASK (0xFF<<PLLE_BASE_DIVM_SHIFT)
+#define PLLE_BASE_DIV_MASK \
+ (PLLE_BASE_DIVCML_MASK | PLLE_BASE_DIVP_MASK | \
+ PLLE_BASE_DIVN_MASK | PLLE_BASE_DIVM_MASK)
+#define PLLE_BASE_DIV(m, n, p, cml) \
+ (((cml)<<PLLE_BASE_DIVCML_SHIFT) | ((p)<<PLLE_BASE_DIVP_SHIFT) | \
+ ((n)<<PLLE_BASE_DIVN_SHIFT) | ((m)<<PLLE_BASE_DIVM_SHIFT))
+
+#define PLLE_MISC_SETUP_BASE_SHIFT 16
+#define PLLE_MISC_SETUP_BASE_MASK (0xFFFF<<PLLE_MISC_SETUP_BASE_SHIFT)
+#define PLLE_MISC_READY (1<<15)
+#define PLLE_MISC_LOCK (1<<11)
+#define PLLE_MISC_LOCK_ENABLE (1<<9)
+#define PLLE_MISC_SETUP_EX_SHIFT 2
+#define PLLE_MISC_SETUP_EX_MASK (0x3<<PLLE_MISC_SETUP_EX_SHIFT)
+#define PLLE_MISC_SETUP_MASK \
+ (PLLE_MISC_SETUP_BASE_MASK | PLLE_MISC_SETUP_EX_MASK)
+#define PLLE_MISC_SETUP_VALUE \
+ ((0x7<<PLLE_MISC_SETUP_BASE_SHIFT) | (0x0<<PLLE_MISC_SETUP_EX_SHIFT))
+
+#define PLLE_SS_CTRL 0x68
+#define PLLE_SS_INCINTRV_SHIFT 24
+#define PLLE_SS_INCINTRV_MASK (0x3f<<PLLE_SS_INCINTRV_SHIFT)
+#define PLLE_SS_INC_SHIFT 16
+#define PLLE_SS_INC_MASK (0xff<<PLLE_SS_INC_SHIFT)
+#define PLLE_SS_MAX_SHIFT 0
+#define PLLE_SS_MAX_MASK (0x1ff<<PLLE_SS_MAX_SHIFT)
+#define PLLE_SS_COEFFICIENTS_MASK \
+ (PLLE_SS_INCINTRV_MASK | PLLE_SS_INC_MASK | PLLE_SS_MAX_MASK)
+#define PLLE_SS_COEFFICIENTS_12MHZ \
+ ((0x18<<PLLE_SS_INCINTRV_SHIFT) | (0x1<<PLLE_SS_INC_SHIFT) | \
+ (0x24<<PLLE_SS_MAX_SHIFT))
+#define PLLE_SS_DISABLE ((1<<12) | (1<<11) | (1<<10))
+
+#define PLLE_AUX 0x48c
+#define PLLE_AUX_PLLP_SEL (1<<2)
+#define PLLE_AUX_CML_SATA_ENABLE (1<<1)
+#define PLLE_AUX_CML_PCIE_ENABLE (1<<0)
+
+#define PMC_SATA_PWRGT 0x1ac
+#define PMC_SATA_PWRGT_PLLE_IDDQ_VALUE (1<<5)
+#define PMC_SATA_PWRGT_PLLE_IDDQ_SWCTL (1<<4)
+
+#define ROUND_DIVIDER_UP 0
+#define ROUND_DIVIDER_DOWN 1
+
+/* FIXME: recommended safety delay after lock is detected */
+#define PLL_POST_LOCK_DELAY 100
+
+/**
+* Structure defining the fields for USB UTMI clocks Parameters.
+*/
+struct utmi_clk_param {
+ /* Oscillator Frequency in KHz */
+ u32 osc_frequency;
+ /* UTMIP PLL Enable Delay Count */
+ u8 enable_delay_count;
+ /* UTMIP PLL Stable count */
+ u8 stable_count;
+ /* UTMIP PLL Active delay count */
+ u8 active_delay_count;
+ /* UTMIP PLL Xtal frequency count */
+ u8 xtal_freq_count;
+};
+
+static const struct utmi_clk_param utmi_parameters[] = {
+ {
+ .osc_frequency = 13000000,
+ .enable_delay_count = 0x02,
+ .stable_count = 0x33,
+ .active_delay_count = 0x05,
+ .xtal_freq_count = 0x7F
+ },
+ {
+ .osc_frequency = 19200000,
+ .enable_delay_count = 0x03,
+ .stable_count = 0x4B,
+ .active_delay_count = 0x06,
+ .xtal_freq_count = 0xBB},
+ {
+ .osc_frequency = 12000000,
+ .enable_delay_count = 0x02,
+ .stable_count = 0x2F,
+ .active_delay_count = 0x04,
+ .xtal_freq_count = 0x76
+ },
+ {
+ .osc_frequency = 26000000,
+ .enable_delay_count = 0x04,
+ .stable_count = 0x66,
+ .active_delay_count = 0x09,
+ .xtal_freq_count = 0xFE
+ },
+ {
+ .osc_frequency = 16800000,
+ .enable_delay_count = 0x03,
+ .stable_count = 0x41,
+ .active_delay_count = 0x0A,
+ .xtal_freq_count = 0xA4
+ },
+};
+
+static void __iomem *reg_clk_base = IO_ADDRESS(TEGRA_CLK_RESET_BASE);
+static void __iomem *reg_pmc_base = IO_ADDRESS(TEGRA_PMC_BASE);
+static void __iomem *misc_gp_hidrev_base = IO_ADDRESS(TEGRA_APB_MISC_BASE);
+
+#define MISC_GP_HIDREV 0x804
+
+/*
+ * Some peripheral clocks share an enable bit, so refcount the enable bits
+ * in registers CLK_ENABLE_L, ... CLK_ENABLE_W
+ */
+static int tegra_periph_clk_enable_refcount[CLK_OUT_ENB_NUM * 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))
+#define chipid_readl() \
+ __raw_readl((u32)misc_gp_hidrev_base + MISC_GP_HIDREV)
+
+#define clk_writel_delay(value, reg) \
+ do { \
+ __raw_writel((value), (u32)reg_clk_base + (reg)); \
+ udelay(2); \
+ } while (0)
+
+
+static inline int clk_set_div(struct clk *c, u32 n)
+{
+ return clk_set_rate(c, (clk_get_rate(c->parent) + n-1) / n);
+}
+
+static inline u32 periph_clk_to_reg(
+ struct clk *c, u32 reg_L, u32 reg_V, int offs)
+{
+ u32 reg = c->u.periph.clk_num / 32;
+ BUG_ON(reg >= RST_DEVICES_NUM);
+ if (reg < 3)
+ reg = reg_L + (reg * offs);
+ else
+ reg = reg_V + ((reg - 3) * offs);
+ return reg;
+}
+
+static unsigned long clk_measure_input_freq(void)
+{
+ u32 clock_autodetect;
+ clk_writel(OSC_FREQ_DET_TRIG | 1, OSC_FREQ_DET);
+ do {} while (clk_readl(OSC_FREQ_DET_STATUS) & OSC_FREQ_DET_BUSY);
+ clock_autodetect = clk_readl(OSC_FREQ_DET_STATUS);
+ if (clock_autodetect >= 732 - 3 && clock_autodetect <= 732 + 3) {
+ return 12000000;
+ } else if (clock_autodetect >= 794 - 3 && clock_autodetect <= 794 + 3) {
+ return 13000000;
+ } else if (clock_autodetect >= 1172 - 3 && clock_autodetect <= 1172 + 3) {
+ return 19200000;
+ } else if (clock_autodetect >= 1587 - 3 && clock_autodetect <= 1587 + 3) {
+ return 26000000;
+ } else if (clock_autodetect >= 1025 - 3 && clock_autodetect <= 1025 + 3) {
+ return 16800000;
+ } else if (clock_autodetect >= 2344 - 3 && clock_autodetect <= 2344 + 3) {
+ return 38400000;
+ } else if (clock_autodetect >= 2928 - 3 && clock_autodetect <= 2928 + 3) {
+ return 48000000;
+ } else {
+ pr_err("%s: Unexpected clock autodetect value %d", __func__,
+ clock_autodetect);
+ BUG();
+ return 0;
+ }
+}
+
+static int clk_div71_get_divider(unsigned long parent_rate, unsigned long rate,
+ u32 flags, u32 round_mode)
+{
+ s64 divider_u71 = parent_rate;
+ if (!rate)
+ return -EINVAL;
+
+ if (!(flags & DIV_U71_INT))
+ divider_u71 *= 2;
+ if (round_mode == ROUND_DIVIDER_UP)
+ divider_u71 += rate - 1;
+ do_div(divider_u71, rate);
+ if (flags & DIV_U71_INT)
+ divider_u71 *= 2;
+
+ if (divider_u71 - 2 < 0)
+ return 0;
+
+ if (divider_u71 - 2 > 255)
+ return -EINVAL;
+
+ return divider_u71 - 2;
+}
+
+static int clk_div16_get_divider(unsigned long parent_rate, unsigned long rate)
+{
+ s64 divider_u16;
+
+ divider_u16 = parent_rate;
+ if (!rate)
+ return -EINVAL;
+ divider_u16 += rate - 1;
+ do_div(divider_u16, rate);
+
+ if (divider_u16 - 1 < 0)
+ return 0;
+
+ if (divider_u16 - 1 > 0xFFFF)
+ return -EINVAL;
+
+ return divider_u16 - 1;
+}
+
+/* clk_m functions */
+static unsigned long tegra30_clk_m_autodetect_rate(struct clk *c)
+{
+ u32 osc_ctrl = clk_readl(OSC_CTRL);
+ u32 auto_clock_control = osc_ctrl & ~OSC_CTRL_OSC_FREQ_MASK;
+ u32 pll_ref_div = osc_ctrl & OSC_CTRL_PLL_REF_DIV_MASK;
+
+ c->rate = clk_measure_input_freq();
+ switch (c->rate) {
+ case 12000000:
+ auto_clock_control |= OSC_CTRL_OSC_FREQ_12MHZ;
+ BUG_ON(pll_ref_div != OSC_CTRL_PLL_REF_DIV_1);
+ break;
+ case 13000000:
+ auto_clock_control |= OSC_CTRL_OSC_FREQ_13MHZ;
+ BUG_ON(pll_ref_div != OSC_CTRL_PLL_REF_DIV_1);
+ break;
+ case 19200000:
+ auto_clock_control |= OSC_CTRL_OSC_FREQ_19_2MHZ;
+ BUG_ON(pll_ref_div != OSC_CTRL_PLL_REF_DIV_1);
+ break;
+ case 26000000:
+ auto_clock_control |= OSC_CTRL_OSC_FREQ_26MHZ;
+ BUG_ON(pll_ref_div != OSC_CTRL_PLL_REF_DIV_1);
+ break;
+ case 16800000:
+ auto_clock_control |= OSC_CTRL_OSC_FREQ_16_8MHZ;
+ BUG_ON(pll_ref_div != OSC_CTRL_PLL_REF_DIV_1);
+ break;
+ case 38400000:
+ auto_clock_control |= OSC_CTRL_OSC_FREQ_38_4MHZ;
+ BUG_ON(pll_ref_div != OSC_CTRL_PLL_REF_DIV_2);
+ break;
+ case 48000000:
+ auto_clock_control |= OSC_CTRL_OSC_FREQ_48MHZ;
+ BUG_ON(pll_ref_div != OSC_CTRL_PLL_REF_DIV_4);
+ break;
+ default:
+ pr_err("%s: Unexpected clock rate %ld", __func__, c->rate);
+ BUG();
+ }
+ clk_writel(auto_clock_control, OSC_CTRL);
+ return c->rate;
+}
+
+static void tegra30_clk_m_init(struct clk *c)
+{
+ pr_debug("%s on clock %s\n", __func__, c->name);
+ tegra30_clk_m_autodetect_rate(c);
+}
+
+static int tegra30_clk_m_enable(struct clk *c)
+{
+ pr_debug("%s on clock %s\n", __func__, c->name);
+ return 0;
+}
+
+static void tegra30_clk_m_disable(struct clk *c)
+{
+ pr_debug("%s on clock %s\n", __func__, c->name);
+ WARN(1, "Attempting to disable main SoC clock\n");
+}
+
+static struct clk_ops tegra_clk_m_ops = {
+ .init = tegra30_clk_m_init,
+ .enable = tegra30_clk_m_enable,
+ .disable = tegra30_clk_m_disable,
+};
+
+static struct clk_ops tegra_clk_m_div_ops = {
+ .enable = tegra30_clk_m_enable,
+};
+
+/* PLL reference divider functions */
+static void tegra30_pll_ref_init(struct clk *c)
+{
+ u32 pll_ref_div = clk_readl(OSC_CTRL) & OSC_CTRL_PLL_REF_DIV_MASK;
+ pr_debug("%s on clock %s\n", __func__, c->name);
+
+ switch (pll_ref_div) {
+ case OSC_CTRL_PLL_REF_DIV_1:
+ c->div = 1;
+ break;
+ case OSC_CTRL_PLL_REF_DIV_2:
+ c->div = 2;
+ break;
+ case OSC_CTRL_PLL_REF_DIV_4:
+ c->div = 4;
+ break;
+ default:
+ pr_err("%s: Invalid pll ref divider %d", __func__, pll_ref_div);
+ BUG();
+ }
+ c->mul = 1;
+ c->state = ON;
+}
+
+static struct clk_ops tegra_pll_ref_ops = {
+ .init = tegra30_pll_ref_init,
+ .enable = tegra30_clk_m_enable,
+ .disable = tegra30_clk_m_disable,
+};
+
+/* super clock functions */
+/* "super clocks" on tegra30 have two-stage muxes, fractional 7.1 divider and
+ * clock skipping super divider. We will ignore the clock skipping divider,
+ * since we can't lower the voltage when using the clock skip, but we can if
+ * we lower the PLL frequency. We will use 7.1 divider for CPU super-clock
+ * only when its parent is a fixed rate PLL, since we can't change PLL rate
+ * in this case.
+ */
+static void tegra30_super_clk_init(struct clk *c)
+{
+ u32 val;
+ int source;
+ int shift;
+ const struct clk_mux_sel *sel;
+ val = clk_readl(c->reg + SUPER_CLK_MUX);
+ c->state = ON;
+ BUG_ON(((val & SUPER_STATE_MASK) != SUPER_STATE_RUN) &&
+ ((val & SUPER_STATE_MASK) != SUPER_STATE_IDLE));
+ shift = ((val & SUPER_STATE_MASK) == SUPER_STATE_IDLE) ?
+ SUPER_IDLE_SOURCE_SHIFT : SUPER_RUN_SOURCE_SHIFT;
+ source = (val >> shift) & SUPER_SOURCE_MASK;
+ if (c->flags & DIV_2)
+ source |= val & SUPER_LP_DIV2_BYPASS;
+ for (sel = c->inputs; sel->input != NULL; sel++) {
+ if (sel->value == source)
+ break;
+ }
+ BUG_ON(sel->input == NULL);
+ c->parent = sel->input;
+
+ if (c->flags & DIV_U71) {
+ /* Init safe 7.1 divider value (does not affect PLLX path) */
+ clk_writel(SUPER_CLOCK_DIV_U71_MIN << SUPER_CLOCK_DIV_U71_SHIFT,
+ c->reg + SUPER_CLK_DIVIDER);
+ c->mul = 2;
+ c->div = 2;
+ if (!(c->parent->flags & PLLX))
+ c->div += SUPER_CLOCK_DIV_U71_MIN;
+ } else
+ clk_writel(0, c->reg + SUPER_CLK_DIVIDER);
+}
+
+static int tegra30_super_clk_enable(struct clk *c)
+{
+ return 0;
+}
+
+static void tegra30_super_clk_disable(struct clk *c)
+{
+ /* since tegra 3 has 2 CPU super clocks - low power lp-mode clock and
+ geared up g-mode super clock - mode switch may request to disable
+ either of them; accept request with no affect on h/w */
+}
+
+static int tegra30_super_clk_set_parent(struct clk *c, struct clk *p)
+{
+ u32 val;
+ const struct clk_mux_sel *sel;
+ int shift;
+
+ 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) ?
+ SUPER_IDLE_SOURCE_SHIFT : SUPER_RUN_SOURCE_SHIFT;
+ for (sel = c->inputs; sel->input != NULL; sel++) {
+ if (sel->input == p) {
+ /* For LP mode super-clock switch between PLLX direct
+ and divided-by-2 outputs is allowed only when other
+ than PLLX clock source is current parent */
+ if ((c->flags & DIV_2) && (p->flags & PLLX) &&
+ ((sel->value ^ val) & SUPER_LP_DIV2_BYPASS)) {
+ if (c->parent->flags & PLLX)
+ return -EINVAL;
+ val ^= SUPER_LP_DIV2_BYPASS;
+ clk_writel_delay(val, c->reg);
+ }
+ val &= ~(SUPER_SOURCE_MASK << shift);
+ val |= (sel->value & SUPER_SOURCE_MASK) << shift;
+
+ /* 7.1 divider for CPU super-clock does not affect
+ PLLX path */
+ if (c->flags & DIV_U71) {
+ u32 div = 0;
+ if (!(p->flags & PLLX)) {
+ div = clk_readl(c->reg +
+ SUPER_CLK_DIVIDER);
+ div &= SUPER_CLOCK_DIV_U71_MASK;
+ div >>= SUPER_CLOCK_DIV_U71_SHIFT;
+ }
+ c->div = div + 2;
+ c->mul = 2;
+ }
+
+ if (c->refcnt)
+ clk_enable(p);
+
+ clk_writel_delay(val, c->reg);
+
+ if (c->refcnt && c->parent)
+ clk_disable(c->parent);
+
+ clk_reparent(c, p);
+ return 0;
+ }
+ }
+ return -EINVAL;
+}
+
+/*
+ * Do not use super clocks "skippers", since dividing using a clock skipper
+ * does not allow the voltage to be scaled down. 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. Special case: if fixed rate PLL is CPU super clock parent the
+ * rate of this PLL can't be changed, and it has many other children. In
+ * this case use 7.1 fractional divider to adjust the super clock rate.
+ */
+static int tegra30_super_clk_set_rate(struct clk *c, unsigned long rate)
+{
+ if ((c->flags & DIV_U71) && (c->parent->flags & PLL_FIXED)) {
+ int div = clk_div71_get_divider(c->parent->u.pll.fixed_rate,
+ rate, c->flags, ROUND_DIVIDER_DOWN);
+ div = max(div, SUPER_CLOCK_DIV_U71_MIN);
+
+ clk_writel(div << SUPER_CLOCK_DIV_U71_SHIFT,
+ c->reg + SUPER_CLK_DIVIDER);
+ c->div = div + 2;
+ c->mul = 2;
+ return 0;
+ }
+ return clk_set_rate(c->parent, rate);
+}
+
+static struct clk_ops tegra_super_ops = {
+ .init = tegra30_super_clk_init,
+ .enable = tegra30_super_clk_enable,
+ .disable = tegra30_super_clk_disable,
+ .set_parent = tegra30_super_clk_set_parent,
+ .set_rate = tegra30_super_clk_set_rate,
+};
+
+static int tegra30_twd_clk_set_rate(struct clk *c, unsigned long rate)
+{
+ /* The input value 'rate' is the clock rate of the CPU complex. */
+ c->rate = (rate * c->mul) / c->div;
+ return 0;
+}
+
+static struct clk_ops tegra30_twd_ops = {
+ .set_rate = tegra30_twd_clk_set_rate,
+};
+
+/* Blink output functions */
+
+static void tegra30_blink_clk_init(struct clk *c)
+{
+ u32 val;
+
+ 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;
+ }
+}
+
+static int tegra30_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 tegra30_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 tegra30_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 = &tegra30_blink_clk_init,
+ .enable = &tegra30_blink_clk_enable,
+ .disable = &tegra30_blink_clk_disable,
+ .set_rate = &tegra30_blink_clk_set_rate,
+};
+
+/* PLL Functions */
+static int tegra30_pll_clk_wait_for_lock(struct clk *c, u32 lock_reg,
+ u32 lock_bit)
+{
+#if USE_PLL_LOCK_BITS
+ int i;
+ for (i = 0; i < c->u.pll.lock_delay; i++) {
+ if (clk_readl(lock_reg) & lock_bit) {
+ udelay(PLL_POST_LOCK_DELAY);
+ return 0;
+ }
+ udelay(2); /* timeout = 2 * lock time */
+ }
+ pr_err("Timed out waiting for lock bit on pll %s", c->name);
+ return -1;
+#endif
+ udelay(c->u.pll.lock_delay);
+
+ return 0;
+}
+
+
+static void tegra30_utmi_param_configure(struct clk *c)
+{
+ u32 reg;
+ int i;
+ unsigned long main_rate =
+ clk_get_rate(c->parent->parent);
+
+ for (i = 0; i < ARRAY_SIZE(utmi_parameters); i++) {
+ if (main_rate == utmi_parameters[i].osc_frequency)
+ break;
+ }
+
+ if (i >= ARRAY_SIZE(utmi_parameters)) {
+ pr_err("%s: Unexpected main rate %lu\n", __func__, main_rate);
+ return;
+ }
+
+ reg = clk_readl(UTMIP_PLL_CFG2);
+
+ /* Program UTMIP PLL stable and active counts */
+ /* [FIXME] arclk_rst.h says WRONG! This should be 1ms -> 0x50 Check! */
+ reg &= ~UTMIP_PLL_CFG2_STABLE_COUNT(~0);
+ reg |= UTMIP_PLL_CFG2_STABLE_COUNT(
+ utmi_parameters[i].stable_count);
+
+ reg &= ~UTMIP_PLL_CFG2_ACTIVE_DLY_COUNT(~0);
+
+ reg |= UTMIP_PLL_CFG2_ACTIVE_DLY_COUNT(
+ utmi_parameters[i].active_delay_count);
+
+ /* Remove power downs from UTMIP PLL control bits */
+ reg &= ~UTMIP_PLL_CFG2_FORCE_PD_SAMP_A_POWERDOWN;
+ reg &= ~UTMIP_PLL_CFG2_FORCE_PD_SAMP_B_POWERDOWN;
+ reg &= ~UTMIP_PLL_CFG2_FORCE_PD_SAMP_C_POWERDOWN;
+
+ clk_writel(reg, UTMIP_PLL_CFG2);
+
+ /* Program UTMIP PLL delay and oscillator frequency counts */
+ reg = clk_readl(UTMIP_PLL_CFG1);
+ reg &= ~UTMIP_PLL_CFG1_ENABLE_DLY_COUNT(~0);
+
+ reg |= UTMIP_PLL_CFG1_ENABLE_DLY_COUNT(
+ utmi_parameters[i].enable_delay_count);
+
+ reg &= ~UTMIP_PLL_CFG1_XTAL_FREQ_COUNT(~0);
+ reg |= UTMIP_PLL_CFG1_XTAL_FREQ_COUNT(
+ utmi_parameters[i].xtal_freq_count);
+
+ /* Remove power downs from UTMIP PLL control bits */
+ reg &= ~UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERDOWN;
+ reg &= ~UTMIP_PLL_CFG1_FORCE_PLL_ACTIVE_POWERDOWN;
+ reg &= ~UTMIP_PLL_CFG1_FORCE_PLLU_POWERDOWN;
+
+ clk_writel(reg, UTMIP_PLL_CFG1);
+}
+
+static void tegra30_pll_clk_init(struct clk *c)
+{
+ u32 val = clk_readl(c->reg + PLL_BASE);
+
+ c->state = (val & PLL_BASE_ENABLE) ? ON : OFF;
+
+ if (c->flags & PLL_FIXED && !(val & PLL_BASE_OVERRIDE)) {
+ const struct clk_pll_freq_table *sel;
+ unsigned long 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 == c->u.pll.fixed_rate) {
+ c->mul = sel->n;
+ c->div = sel->m * sel->p;
+ return;
+ }
+ }
+ pr_err("Clock %s has unknown fixed frequency\n", c->name);
+ BUG();
+ } else if (val & PLL_BASE_BYPASS) {
+ c->mul = 1;
+ c->div = 1;
+ } else {
+ c->mul = (val & PLL_BASE_DIVN_MASK) >> PLL_BASE_DIVN_SHIFT;
+ c->div = (val & PLL_BASE_DIVM_MASK) >> PLL_BASE_DIVM_SHIFT;
+ if (c->flags & PLLU)
+ c->div *= (val & PLLU_BASE_POST_DIV) ? 1 : 2;
+ else
+ c->div *= (0x1 << ((val & PLL_BASE_DIVP_MASK) >>
+ PLL_BASE_DIVP_SHIFT));
+ if (c->flags & PLL_FIXED) {
+ unsigned long rate = clk_get_rate_locked(c);
+ BUG_ON(rate != c->u.pll.fixed_rate);
+ }
+ }
+
+ if (c->flags & PLLU)
+ tegra30_utmi_param_configure(c);
+}
+
+static int tegra30_pll_clk_enable(struct clk *c)
+{
+ u32 val;
+ pr_debug("%s on clock %s\n", __func__, c->name);
+
+#if USE_PLL_LOCK_BITS
+ val = clk_readl(c->reg + PLL_MISC(c));
+ val |= PLL_MISC_LOCK_ENABLE(c);
+ clk_writel(val, c->reg + PLL_MISC(c));
+#endif
+ val = clk_readl(c->reg + PLL_BASE);
+ val &= ~PLL_BASE_BYPASS;
+ val |= PLL_BASE_ENABLE;
+ clk_writel(val, c->reg + PLL_BASE);
+
+ if (c->flags & PLLM) {
+ val = pmc_readl(PMC_PLLP_WB0_OVERRIDE);
+ val |= PMC_PLLP_WB0_OVERRIDE_PLLM_ENABLE;
+ pmc_writel(val, PMC_PLLP_WB0_OVERRIDE);
+ }
+
+ tegra30_pll_clk_wait_for_lock(c, c->reg + PLL_BASE, PLL_BASE_LOCK);
+
+ return 0;
+}
+
+static void tegra30_pll_clk_disable(struct clk *c)
+{
+ u32 val;
+ pr_debug("%s on clock %s\n", __func__, c->name);
+
+ val = clk_readl(c->reg);
+ val &= ~(PLL_BASE_BYPASS | PLL_BASE_ENABLE);
+ clk_writel(val, c->reg);
+
+ if (c->flags & PLLM) {
+ val = pmc_readl(PMC_PLLP_WB0_OVERRIDE);
+ val &= ~PMC_PLLP_WB0_OVERRIDE_PLLM_ENABLE;
+ pmc_writel(val, PMC_PLLP_WB0_OVERRIDE);
+ }
+}
+
+static int tegra30_pll_clk_set_rate(struct clk *c, unsigned long rate)
+{
+ u32 val, p_div, old_base;
+ unsigned long input_rate;
+ const struct clk_pll_freq_table *sel;
+ struct clk_pll_freq_table cfg;
+
+ pr_debug("%s: %s %lu\n", __func__, c->name, rate);
+
+ if (c->flags & PLL_FIXED) {
+ int ret = 0;
+ if (rate != c->u.pll.fixed_rate) {
+ pr_err("%s: Can not change %s fixed rate %lu to %lu\n",
+ __func__, c->name, c->u.pll.fixed_rate, rate);
+ ret = -EINVAL;
+ }
+ return ret;
+ }
+
+ if (c->flags & PLLM) {
+ if (rate != clk_get_rate_locked(c)) {
+ pr_err("%s: Can not change memory %s rate in flight\n",
+ __func__, c->name);
+ return -EINVAL;
+ }
+ return 0;
+ }
+
+ p_div = 0;
+ input_rate = clk_get_rate(c->parent);
+
+ /* Check if the target rate is tabulated */
+ for (sel = c->u.pll.freq_table; sel->input_rate != 0; sel++) {
+ if (sel->input_rate == input_rate && sel->output_rate == rate) {
+ if (c->flags & PLLU) {
+ BUG_ON(sel->p < 1 || sel->p > 2);
+ if (sel->p == 1)
+ p_div = PLLU_BASE_POST_DIV;
+ } else {
+ BUG_ON(sel->p < 1);
+ for (val = sel->p; val > 1; val >>= 1)
+ p_div++;
+ p_div <<= PLL_BASE_DIVP_SHIFT;
+ }
+ break;
+ }
+ }
+
+ /* Configure out-of-table rate */
+ if (sel->input_rate == 0) {
+ unsigned long cfreq;
+ BUG_ON(c->flags & PLLU);
+ sel = &cfg;
+
+ switch (input_rate) {
+ case 12000000:
+ case 26000000:
+ cfreq = (rate <= 1000000 * 1000) ? 1000000 : 2000000;
+ break;
+ case 13000000:
+ cfreq = (rate <= 1000000 * 1000) ? 1000000 : 2600000;
+ break;
+ case 16800000:
+ case 19200000:
+ cfreq = (rate <= 1200000 * 1000) ? 1200000 : 2400000;
+ break;
+ default:
+ pr_err("%s: Unexpected reference rate %lu\n",
+ __func__, input_rate);
+ BUG();
+ }
+
+ /* Raise VCO to guarantee 0.5% accuracy */
+ for (cfg.output_rate = rate; cfg.output_rate < 200 * cfreq;
+ cfg.output_rate <<= 1)
+ p_div++;
+
+ cfg.p = 0x1 << p_div;
+ cfg.m = input_rate / cfreq;
+ cfg.n = cfg.output_rate / cfreq;
+ cfg.cpcon = OUT_OF_TABLE_CPCON;
+
+ if ((cfg.m > (PLL_BASE_DIVM_MASK >> PLL_BASE_DIVM_SHIFT)) ||
+ (cfg.n > (PLL_BASE_DIVN_MASK >> PLL_BASE_DIVN_SHIFT)) ||
+ (p_div > (PLL_BASE_DIVP_MASK >> PLL_BASE_DIVP_SHIFT)) ||
+ (cfg.output_rate > c->u.pll.vco_max)) {
+ pr_err("%s: Failed to set %s out-of-table rate %lu\n",
+ __func__, c->name, rate);
+ return -EINVAL;
+ }
+ p_div <<= PLL_BASE_DIVP_SHIFT;
+ }
+
+ c->mul = sel->n;
+ c->div = sel->m * sel->p;
+
+ old_base = val = clk_readl(c->reg + PLL_BASE);
+ val &= ~(PLL_BASE_DIVM_MASK | PLL_BASE_DIVN_MASK |
+ ((c->flags & PLLU) ? PLLU_BASE_POST_DIV : PLL_BASE_DIVP_MASK));
+ val |= (sel->m << PLL_BASE_DIVM_SHIFT) |
+ (sel->n << PLL_BASE_DIVN_SHIFT) | p_div;
+ if (val == old_base)
+ return 0;
+
+ if (c->state == ON) {
+ tegra30_pll_clk_disable(c);
+ val &= ~(PLL_BASE_BYPASS | PLL_BASE_ENABLE);
+ }
+ clk_writel(val, c->reg + PLL_BASE);
+
+ if (c->flags & PLL_HAS_CPCON) {
+ val = clk_readl(c->reg + PLL_MISC(c));
+ val &= ~PLL_MISC_CPCON_MASK;
+ val |= sel->cpcon << PLL_MISC_CPCON_SHIFT;
+ if (c->flags & (PLLU | PLLD)) {
+ val &= ~PLL_MISC_LFCON_MASK;
+ if (sel->n >= PLLDU_LFCON_SET_DIVN)
+ val |= 0x1 << PLL_MISC_LFCON_SHIFT;
+ } else if (c->flags & (PLLX | PLLM)) {
+ val &= ~(0x1 << PLL_MISC_DCCON_SHIFT);
+ if (rate >= (c->u.pll.vco_max >> 1))
+ val |= 0x1 << PLL_MISC_DCCON_SHIFT;
+ }
+ clk_writel(val, c->reg + PLL_MISC(c));
+ }
+
+ if (c->state == ON)
+ tegra30_pll_clk_enable(c);
+
+ return 0;
+}
+
+static struct clk_ops tegra_pll_ops = {
+ .init = tegra30_pll_clk_init,
+ .enable = tegra30_pll_clk_enable,
+ .disable = tegra30_pll_clk_disable,
+ .set_rate = tegra30_pll_clk_set_rate,
+};
+
+static int
+tegra30_plld_clk_cfg_ex(struct clk *c, enum tegra_clk_ex_param p, u32 setting)
+{
+ u32 val, mask, reg;
+
+ switch (p) {
+ case TEGRA_CLK_PLLD_CSI_OUT_ENB:
+ mask = PLLD_BASE_CSI_CLKENABLE;
+ reg = c->reg + PLL_BASE;
+ break;
+ case TEGRA_CLK_PLLD_DSI_OUT_ENB:
+ mask = PLLD_MISC_DSI_CLKENABLE;
+ reg = c->reg + PLL_MISC(c);
+ break;
+ case TEGRA_CLK_PLLD_MIPI_MUX_SEL:
+ if (!(c->flags & PLL_ALT_MISC_REG)) {
+ mask = PLLD_BASE_DSIB_MUX_MASK;
+ reg = c->reg + PLL_BASE;
+ break;
+ }
+ /* fall through - error since PLLD2 does not have MUX_SEL control */
+ default:
+ return -EINVAL;
+ }
+
+ val = clk_readl(reg);
+ if (setting)
+ val |= mask;
+ else
+ val &= ~mask;
+ clk_writel(val, reg);
+ return 0;
+}
+
+static struct clk_ops tegra_plld_ops = {
+ .init = tegra30_pll_clk_init,
+ .enable = tegra30_pll_clk_enable,
+ .disable = tegra30_pll_clk_disable,
+ .set_rate = tegra30_pll_clk_set_rate,
+ .clk_cfg_ex = tegra30_plld_clk_cfg_ex,
+};
+
+static void tegra30_plle_clk_init(struct clk *c)
+{
+ u32 val;
+
+ val = clk_readl(PLLE_AUX);
+ c->parent = (val & PLLE_AUX_PLLP_SEL) ?
+ tegra_get_clock_by_name("pll_p") :
+ tegra_get_clock_by_name("pll_ref");
+
+ val = clk_readl(c->reg + PLL_BASE);
+ c->state = (val & PLLE_BASE_ENABLE) ? ON : OFF;
+ c->mul = (val & PLLE_BASE_DIVN_MASK) >> PLLE_BASE_DIVN_SHIFT;
+ c->div = (val & PLLE_BASE_DIVM_MASK) >> PLLE_BASE_DIVM_SHIFT;
+ c->div *= (val & PLLE_BASE_DIVP_MASK) >> PLLE_BASE_DIVP_SHIFT;
+}
+
+static void tegra30_plle_clk_disable(struct clk *c)
+{
+ u32 val;
+ pr_debug("%s on clock %s\n", __func__, c->name);
+
+ val = clk_readl(c->reg + PLL_BASE);
+ val &= ~(PLLE_BASE_CML_ENABLE | PLLE_BASE_ENABLE);
+ clk_writel(val, c->reg + PLL_BASE);
+}
+
+static void tegra30_plle_training(struct clk *c)
+{
+ u32 val;
+
+ /* PLLE is already disabled, and setup cleared;
+ * create falling edge on PLLE IDDQ input */
+ val = pmc_readl(PMC_SATA_PWRGT);
+ val |= PMC_SATA_PWRGT_PLLE_IDDQ_VALUE;
+ pmc_writel(val, PMC_SATA_PWRGT);
+
+ val = pmc_readl(PMC_SATA_PWRGT);
+ val |= PMC_SATA_PWRGT_PLLE_IDDQ_SWCTL;
+ pmc_writel(val, PMC_SATA_PWRGT);
+
+ val = pmc_readl(PMC_SATA_PWRGT);
+ val &= ~PMC_SATA_PWRGT_PLLE_IDDQ_VALUE;
+ pmc_writel(val, PMC_SATA_PWRGT);
+
+ do {
+ val = clk_readl(c->reg + PLL_MISC(c));
+ } while (!(val & PLLE_MISC_READY));
+}
+
+static int tegra30_plle_configure(struct clk *c, bool force_training)
+{
+ u32 val;
+ const struct clk_pll_freq_table *sel;
+ unsigned long rate = c->u.pll.fixed_rate;
+ unsigned long 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)
+ break;
+ }
+
+ if (sel->input_rate == 0)
+ return -ENOSYS;
+
+ /* disable PLLE, clear setup fiels */
+ tegra30_plle_clk_disable(c);
+
+ val = clk_readl(c->reg + PLL_MISC(c));
+ val &= ~(PLLE_MISC_LOCK_ENABLE | PLLE_MISC_SETUP_MASK);
+ clk_writel(val, c->reg + PLL_MISC(c));
+
+ /* training */
+ val = clk_readl(c->reg + PLL_MISC(c));
+ if (force_training || (!(val & PLLE_MISC_READY)))
+ tegra30_plle_training(c);
+
+ /* configure dividers, setup, disable SS */
+ val = clk_readl(c->reg + PLL_BASE);
+ val &= ~PLLE_BASE_DIV_MASK;
+ val |= PLLE_BASE_DIV(sel->m, sel->n, sel->p, sel->cpcon);
+ clk_writel(val, c->reg + PLL_BASE);
+ c->mul = sel->n;
+ c->div = sel->m * sel->p;
+
+ val = clk_readl(c->reg + PLL_MISC(c));
+ val |= PLLE_MISC_SETUP_VALUE;
+ val |= PLLE_MISC_LOCK_ENABLE;
+ clk_writel(val, c->reg + PLL_MISC(c));
+
+ val = clk_readl(PLLE_SS_CTRL);
+ val |= PLLE_SS_DISABLE;
+ clk_writel(val, PLLE_SS_CTRL);
+
+ /* enable and lock PLLE*/
+ val = clk_readl(c->reg + PLL_BASE);
+ val |= (PLLE_BASE_CML_ENABLE | PLLE_BASE_ENABLE);
+ clk_writel(val, c->reg + PLL_BASE);
+
+ tegra30_pll_clk_wait_for_lock(c, c->reg + PLL_MISC(c), PLLE_MISC_LOCK);
+
+ return 0;
+}
+
+static int tegra30_plle_clk_enable(struct clk *c)
+{
+ pr_debug("%s on clock %s\n", __func__, c->name);
+ return tegra30_plle_configure(c, !c->set);
+}
+
+static struct clk_ops tegra_plle_ops = {
+ .init = tegra30_plle_clk_init,
+ .enable = tegra30_plle_clk_enable,
+ .disable = tegra30_plle_clk_disable,
+};
+
+/* Clock divider ops */
+static void tegra30_pll_div_clk_init(struct clk *c)
+{
+ if (c->flags & DIV_U71) {
+ u32 divu71;
+ u32 val = clk_readl(c->reg);
+ val >>= c->reg_shift;
+ c->state = (val & PLL_OUT_CLKEN) ? ON : OFF;
+ if (!(val & PLL_OUT_RESET_DISABLE))
+ c->state = OFF;
+
+ divu71 = (val & PLL_OUT_RATIO_MASK) >> PLL_OUT_RATIO_SHIFT;
+ c->div = (divu71 + 2);
+ c->mul = 2;
+ } else if (c->flags & DIV_2) {
+ c->state = ON;
+ if (c->flags & (PLLD | PLLX)) {
+ c->div = 2;
+ c->mul = 1;
+ } else
+ BUG();
+ } else {
+ c->state = ON;
+ c->div = 1;
+ c->mul = 1;
+ }
+}
+
+static int tegra30_pll_div_clk_enable(struct clk *c)
+{
+ u32 val;
+ u32 new_val;
+
+ pr_debug("%s: %s\n", __func__, c->name);
+ if (c->flags & DIV_U71) {
+ val = clk_readl(c->reg);
+ new_val = val >> c->reg_shift;
+ new_val &= 0xFFFF;
+
+ new_val |= PLL_OUT_CLKEN | PLL_OUT_RESET_DISABLE;
+
+ val &= ~(0xFFFF << c->reg_shift);
+ val |= new_val << c->reg_shift;
+ clk_writel_delay(val, c->reg);
+ return 0;
+ } else if (c->flags & DIV_2) {
+ return 0;
+ }
+ return -EINVAL;
+}
+
+static void tegra30_pll_div_clk_disable(struct clk *c)
+{
+ u32 val;
+ u32 new_val;
+
+ pr_debug("%s: %s\n", __func__, c->name);
+ if (c->flags & DIV_U71) {
+ val = clk_readl(c->reg);
+ new_val = val >> c->reg_shift;
+ new_val &= 0xFFFF;
+
+ new_val &= ~(PLL_OUT_CLKEN | PLL_OUT_RESET_DISABLE);
+
+ val &= ~(0xFFFF << c->reg_shift);
+ val |= new_val << c->reg_shift;
+ clk_writel_delay(val, c->reg);
+ }
+}
+
+static int tegra30_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);
+
+ pr_debug("%s: %s %lu\n", __func__, c->name, rate);
+ if (c->flags & DIV_U71) {
+ divider_u71 = clk_div71_get_divider(
+ parent_rate, rate, c->flags, ROUND_DIVIDER_UP);
+ if (divider_u71 >= 0) {
+ val = clk_readl(c->reg);
+ new_val = val >> c->reg_shift;
+ new_val &= 0xFFFF;
+ if (c->flags & DIV_U71_FIXED)
+ new_val |= PLL_OUT_OVERRIDE;
+ new_val &= ~PLL_OUT_RATIO_MASK;
+ new_val |= divider_u71 << PLL_OUT_RATIO_SHIFT;
+
+ val &= ~(0xFFFF << c->reg_shift);
+ val |= new_val << c->reg_shift;
+ clk_writel_delay(val, c->reg);
+ c->div = divider_u71 + 2;
+ c->mul = 2;
+ return 0;
+ }
+ } else if (c->flags & DIV_2)
+ return clk_set_rate(c->parent, rate * 2);
+
+ return -EINVAL;
+}
+
+static long tegra30_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(
+ parent_rate, rate, c->flags, ROUND_DIVIDER_UP);
+ if (divider < 0)
+ return divider;
+ return DIV_ROUND_UP(parent_rate * 2, divider + 2);
+ } else if (c->flags & DIV_2)
+ /* no rounding - fixed DIV_2 dividers pass rate to parent PLL */
+ return rate;
+
+ return -EINVAL;
+}
+
+static struct clk_ops tegra_pll_div_ops = {
+ .init = tegra30_pll_div_clk_init,
+ .enable = tegra30_pll_div_clk_enable,
+ .disable = tegra30_pll_div_clk_disable,
+ .set_rate = tegra30_pll_div_clk_set_rate,
+ .round_rate = tegra30_pll_div_clk_round_rate,
+};
+
+/* Periph clk ops */
+static inline u32 periph_clk_source_mask(struct clk *c)
+{
+ if (c->flags & MUX8)
+ return 7 << 29;
+ else if (c->flags & MUX_PWM)
+ return 3 << 28;
+ else if (c->flags & MUX_CLK_OUT)
+ return 3 << (c->u.periph.clk_num + 4);
+ else if (c->flags & PLLD)
+ return PLLD_BASE_DSIB_MUX_MASK;
+ else
+ return 3 << 30;
+}
+
+static inline u32 periph_clk_source_shift(struct clk *c)
+{
+ if (c->flags & MUX8)
+ return 29;
+ else if (c->flags & MUX_PWM)
+ return 28;
+ else if (c->flags & MUX_CLK_OUT)
+ return c->u.periph.clk_num + 4;
+ else if (c->flags & PLLD)
+ return PLLD_BASE_DSIB_MUX_SHIFT;
+ else
+ return 30;
+}
+
+static void tegra30_periph_clk_init(struct clk *c)
+{
+ u32 val = clk_readl(c->reg);
+ const struct clk_mux_sel *mux = 0;
+ const struct clk_mux_sel *sel;
+ if (c->flags & MUX) {
+ for (sel = c->inputs; sel->input != NULL; sel++) {
+ if (((val & periph_clk_source_mask(c)) >>
+ periph_clk_source_shift(c)) == sel->value)
+ mux = sel;
+ }
+ BUG_ON(!mux);
+
+ c->parent = mux->input;
+ } else {
+ c->parent = c->inputs[0].input;
+ }
+
+ if (c->flags & DIV_U71) {
+ u32 divu71 = val & PERIPH_CLK_SOURCE_DIVU71_MASK;
+ if ((c->flags & DIV_U71_UART) &&
+ (!(val & PERIPH_CLK_UART_DIV_ENB))) {
+ divu71 = 0;
+ }
+ if (c->flags & DIV_U71_IDLE) {
+ val &= ~(PERIPH_CLK_SOURCE_DIVU71_MASK <<
+ PERIPH_CLK_SOURCE_DIVIDLE_SHIFT);
+ val |= (PERIPH_CLK_SOURCE_DIVIDLE_VAL <<
+ PERIPH_CLK_SOURCE_DIVIDLE_SHIFT);
+ clk_writel(val, c->reg);
+ }
+ c->div = divu71 + 2;
+ c->mul = 2;
+ } else if (c->flags & DIV_U16) {
+ u32 divu16 = val & PERIPH_CLK_SOURCE_DIVU16_MASK;
+ c->div = divu16 + 1;
+ c->mul = 1;
+ } else {
+ c->div = 1;
+ c->mul = 1;
+ }
+
+ c->state = ON;
+ if (!(clk_readl(PERIPH_CLK_TO_ENB_REG(c)) & PERIPH_CLK_TO_BIT(c)))
+ c->state = OFF;
+ if (!(c->flags & PERIPH_NO_RESET))
+ if (clk_readl(PERIPH_CLK_TO_RST_REG(c)) & PERIPH_CLK_TO_BIT(c))
+ c->state = OFF;
+}
+
+static int tegra30_periph_clk_enable(struct clk *c)
+{
+ pr_debug("%s on clock %s\n", __func__, c->name);
+
+ tegra_periph_clk_enable_refcount[c->u.periph.clk_num]++;
+ if (tegra_periph_clk_enable_refcount[c->u.periph.clk_num] > 1)
+ return 0;
+
+ clk_writel_delay(PERIPH_CLK_TO_BIT(c), PERIPH_CLK_TO_ENB_SET_REG(c));
+ if (!(c->flags & PERIPH_NO_RESET) &&
+ !(c->flags & PERIPH_MANUAL_RESET)) {
+ if (clk_readl(PERIPH_CLK_TO_RST_REG(c)) &
+ PERIPH_CLK_TO_BIT(c)) {
+ udelay(5); /* reset propagation delay */
+ clk_writel(PERIPH_CLK_TO_BIT(c),
+ PERIPH_CLK_TO_RST_CLR_REG(c));
+ }
+ }
+ return 0;
+}
+
+static void tegra30_periph_clk_disable(struct clk *c)
+{
+ unsigned long val;
+ pr_debug("%s on clock %s\n", __func__, c->name);
+
+ 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) {
+ /* If peripheral is in the APB bus then read the APB bus to
+ * flush the write operation in apb bus. This will avoid the
+ * peripheral access after disabling clock*/
+ if (c->flags & PERIPH_ON_APB)
+ val = chipid_readl();
+
+ clk_writel_delay(
+ PERIPH_CLK_TO_BIT(c), PERIPH_CLK_TO_ENB_CLR_REG(c));
+ }
+}
+
+static void tegra30_periph_clk_reset(struct clk *c, bool assert)
+{
+ unsigned long val;
+ pr_debug("%s %s on clock %s\n", __func__,
+ assert ? "assert" : "deassert", c->name);
+
+ if (!(c->flags & PERIPH_NO_RESET)) {
+ if (assert) {
+ /* If peripheral is in the APB bus then read the APB
+ * bus to flush the write operation in apb bus. This
+ * will avoid the peripheral access after disabling
+ * clock */
+ if (c->flags & PERIPH_ON_APB)
+ val = chipid_readl();
+
+ clk_writel(PERIPH_CLK_TO_BIT(c),
+ PERIPH_CLK_TO_RST_SET_REG(c));
+ } else
+ clk_writel(PERIPH_CLK_TO_BIT(c),
+ PERIPH_CLK_TO_RST_CLR_REG(c));
+ }
+}
+
+static int tegra30_periph_clk_set_parent(struct clk *c, struct clk *p)
+{
+ u32 val;
+ const struct clk_mux_sel *sel;
+ pr_debug("%s: %s %s\n", __func__, c->name, p->name);
+
+ if (!(c->flags & MUX))
+ return (p == c->parent) ? 0 : (-EINVAL);
+
+ for (sel = c->inputs; sel->input != NULL; sel++) {
+ if (sel->input == p) {
+ val = clk_readl(c->reg);
+ val &= ~periph_clk_source_mask(c);
+ val |= (sel->value << periph_clk_source_shift(c));
+
+ if (c->refcnt)
+ clk_enable(p);
+
+ clk_writel_delay(val, c->reg);
+
+ if (c->refcnt && c->parent)
+ clk_disable(c->parent);
+
+ clk_reparent(c, p);
+ return 0;
+ }
+ }
+
+ return -EINVAL;
+}
+
+static int tegra30_periph_clk_set_rate(struct clk *c, unsigned long rate)
+{
+ u32 val;
+ int divider;
+ unsigned long parent_rate = clk_get_rate(c->parent);
+
+ if (c->flags & DIV_U71) {
+ divider = clk_div71_get_divider(
+ parent_rate, rate, c->flags, ROUND_DIVIDER_UP);
+ if (divider >= 0) {
+ val = clk_readl(c->reg);
+ val &= ~PERIPH_CLK_SOURCE_DIVU71_MASK;
+ val |= divider;
+ if (c->flags & DIV_U71_UART) {
+ if (divider)
+ val |= PERIPH_CLK_UART_DIV_ENB;
+ else
+ val &= ~PERIPH_CLK_UART_DIV_ENB;
+ }
+ clk_writel_delay(val, c->reg);
+ c->div = divider + 2;
+ c->mul = 2;
+ return 0;
+ }
+ } else if (c->flags & DIV_U16) {
+ divider = clk_div16_get_divider(parent_rate, rate);
+ if (divider >= 0) {
+ val = clk_readl(c->reg);
+ val &= ~PERIPH_CLK_SOURCE_DIVU16_MASK;
+ val |= divider;
+ clk_writel_delay(val, c->reg);
+ c->div = divider + 1;
+ c->mul = 1;
+ return 0;
+ }
+ } else if (parent_rate <= rate) {
+ c->div = 1;
+ c->mul = 1;
+ return 0;
+ }
+ return -EINVAL;
+}
+
+static long tegra30_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(
+ parent_rate, rate, c->flags, ROUND_DIVIDER_UP);
+ if (divider < 0)
+ return divider;
+
+ return DIV_ROUND_UP(parent_rate * 2, divider + 2);
+ } else if (c->flags & DIV_U16) {
+ divider = clk_div16_get_divider(parent_rate, rate);
+ if (divider < 0)
+ return divider;
+ return DIV_ROUND_UP(parent_rate, divider + 1);
+ }
+ return -EINVAL;
+}
+
+static struct clk_ops tegra_periph_clk_ops = {
+ .init = &tegra30_periph_clk_init,
+ .enable = &tegra30_periph_clk_enable,
+ .disable = &tegra30_periph_clk_disable,
+ .set_parent = &tegra30_periph_clk_set_parent,
+ .set_rate = &tegra30_periph_clk_set_rate,
+ .round_rate = &tegra30_periph_clk_round_rate,
+ .reset = &tegra30_periph_clk_reset,
+};
+
+
+/* Periph extended clock configuration ops */
+static int
+tegra30_vi_clk_cfg_ex(struct clk *c, enum tegra_clk_ex_param p, u32 setting)
+{
+ if (p == TEGRA_CLK_VI_INP_SEL) {
+ u32 val = clk_readl(c->reg);
+ val &= ~PERIPH_CLK_VI_SEL_EX_MASK;
+ val |= (setting << PERIPH_CLK_VI_SEL_EX_SHIFT) &
+ PERIPH_CLK_VI_SEL_EX_MASK;
+ clk_writel(val, c->reg);
+ return 0;
+ }
+ return -EINVAL;
+}
+
+static struct clk_ops tegra_vi_clk_ops = {
+ .init = &tegra30_periph_clk_init,
+ .enable = &tegra30_periph_clk_enable,
+ .disable = &tegra30_periph_clk_disable,
+ .set_parent = &tegra30_periph_clk_set_parent,
+ .set_rate = &tegra30_periph_clk_set_rate,
+ .round_rate = &tegra30_periph_clk_round_rate,
+ .clk_cfg_ex = &tegra30_vi_clk_cfg_ex,
+ .reset = &tegra30_periph_clk_reset,
+};
+
+static int
+tegra30_nand_clk_cfg_ex(struct clk *c, enum tegra_clk_ex_param p, u32 setting)
+{
+ if (p == TEGRA_CLK_NAND_PAD_DIV2_ENB) {
+ u32 val = clk_readl(c->reg);
+ if (setting)
+ val |= PERIPH_CLK_NAND_DIV_EX_ENB;
+ else
+ val &= ~PERIPH_CLK_NAND_DIV_EX_ENB;
+ clk_writel(val, c->reg);
+ return 0;
+ }
+ return -EINVAL;
+}
+
+static struct clk_ops tegra_nand_clk_ops = {
+ .init = &tegra30_periph_clk_init,
+ .enable = &tegra30_periph_clk_enable,
+ .disable = &tegra30_periph_clk_disable,
+ .set_parent = &tegra30_periph_clk_set_parent,
+ .set_rate = &tegra30_periph_clk_set_rate,
+ .round_rate = &tegra30_periph_clk_round_rate,
+ .clk_cfg_ex = &tegra30_nand_clk_cfg_ex,
+ .reset = &tegra30_periph_clk_reset,
+};
+
+
+static int
+tegra30_dtv_clk_cfg_ex(struct clk *c, enum tegra_clk_ex_param p, u32 setting)
+{
+ if (p == TEGRA_CLK_DTV_INVERT) {
+ u32 val = clk_readl(c->reg);
+ if (setting)
+ val |= PERIPH_CLK_DTV_POLARITY_INV;
+ else
+ val &= ~PERIPH_CLK_DTV_POLARITY_INV;
+ clk_writel(val, c->reg);
+ return 0;
+ }
+ return -EINVAL;
+}
+
+static struct clk_ops tegra_dtv_clk_ops = {
+ .init = &tegra30_periph_clk_init,
+ .enable = &tegra30_periph_clk_enable,
+ .disable = &tegra30_periph_clk_disable,
+ .set_parent = &tegra30_periph_clk_set_parent,
+ .set_rate = &tegra30_periph_clk_set_rate,
+ .round_rate = &tegra30_periph_clk_round_rate,
+ .clk_cfg_ex = &tegra30_dtv_clk_cfg_ex,
+ .reset = &tegra30_periph_clk_reset,
+};
+
+static int tegra30_dsib_clk_set_parent(struct clk *c, struct clk *p)
+{
+ const struct clk_mux_sel *sel;
+ struct clk *d = tegra_get_clock_by_name("pll_d");
+
+ pr_debug("%s: %s %s\n", __func__, c->name, p->name);
+
+ for (sel = c->inputs; sel->input != NULL; sel++) {
+ if (sel->input == p) {
+ if (c->refcnt)
+ clk_enable(p);
+
+ /* The DSIB parent selection bit is in PLLD base
+ register - can not do direct r-m-w, must be
+ protected by PLLD lock */
+ tegra_clk_cfg_ex(
+ d, TEGRA_CLK_PLLD_MIPI_MUX_SEL, sel->value);
+
+ if (c->refcnt && c->parent)
+ clk_disable(c->parent);
+
+ clk_reparent(c, p);
+ return 0;
+ }
+ }
+
+ return -EINVAL;
+}
+
+static struct clk_ops tegra_dsib_clk_ops = {
+ .init = &tegra30_periph_clk_init,
+ .enable = &tegra30_periph_clk_enable,
+ .disable = &tegra30_periph_clk_disable,
+ .set_parent = &tegra30_dsib_clk_set_parent,
+ .set_rate = &tegra30_periph_clk_set_rate,
+ .round_rate = &tegra30_periph_clk_round_rate,
+ .reset = &tegra30_periph_clk_reset,
+};
+
+/* pciex clock support only reset function */
+static struct clk_ops tegra_pciex_clk_ops = {
+ .reset = tegra30_periph_clk_reset,
+};
+
+/* Output clock ops */
+
+static DEFINE_SPINLOCK(clk_out_lock);
+
+static void tegra30_clk_out_init(struct clk *c)
+{
+ const struct clk_mux_sel *mux = 0;
+ const struct clk_mux_sel *sel;
+ u32 val = pmc_readl(c->reg);
+
+ c->state = (val & (0x1 << c->u.periph.clk_num)) ? ON : OFF;
+ c->mul = 1;
+ c->div = 1;
+
+ for (sel = c->inputs; sel->input != NULL; sel++) {
+ if (((val & periph_clk_source_mask(c)) >>
+ periph_clk_source_shift(c)) == sel->value)
+ mux = sel;
+ }
+ BUG_ON(!mux);
+ c->parent = mux->input;
+}
+
+static int tegra30_clk_out_enable(struct clk *c)
+{
+ u32 val;
+ unsigned long flags;
+
+ pr_debug("%s on clock %s\n", __func__, c->name);
+
+ spin_lock_irqsave(&clk_out_lock, flags);
+ val = pmc_readl(c->reg);
+ val |= (0x1 << c->u.periph.clk_num);
+ pmc_writel(val, c->reg);
+ spin_unlock_irqrestore(&clk_out_lock, flags);
+
+ return 0;
+}
+
+static void tegra30_clk_out_disable(struct clk *c)
+{
+ u32 val;
+ unsigned long flags;
+
+ pr_debug("%s on clock %s\n", __func__, c->name);
+
+ spin_lock_irqsave(&clk_out_lock, flags);
+ val = pmc_readl(c->reg);
+ val &= ~(0x1 << c->u.periph.clk_num);
+ pmc_writel(val, c->reg);
+ spin_unlock_irqrestore(&clk_out_lock, flags);
+}
+
+static int tegra30_clk_out_set_parent(struct clk *c, struct clk *p)
+{
+ u32 val;
+ unsigned long flags;
+ const struct clk_mux_sel *sel;
+
+ pr_debug("%s: %s %s\n", __func__, c->name, p->name);
+
+ for (sel = c->inputs; sel->input != NULL; sel++) {
+ if (sel->input == p) {
+ if (c->refcnt)
+ clk_enable(p);
+
+ spin_lock_irqsave(&clk_out_lock, flags);
+ val = pmc_readl(c->reg);
+ val &= ~periph_clk_source_mask(c);
+ val |= (sel->value << periph_clk_source_shift(c));
+ pmc_writel(val, c->reg);
+ spin_unlock_irqrestore(&clk_out_lock, flags);
+
+ if (c->refcnt && c->parent)
+ clk_disable(c->parent);
+
+ clk_reparent(c, p);
+ return 0;
+ }
+ }
+ return -EINVAL;
+}
+
+static struct clk_ops tegra_clk_out_ops = {
+ .init = &tegra30_clk_out_init,
+ .enable = &tegra30_clk_out_enable,
+ .disable = &tegra30_clk_out_disable,
+ .set_parent = &tegra30_clk_out_set_parent,
+};
+
+
+/* Clock doubler ops */
+static void tegra30_clk_double_init(struct clk *c)
+{
+ u32 val = clk_readl(c->reg);
+ c->mul = val & (0x1 << c->reg_shift) ? 1 : 2;
+ c->div = 1;
+ c->state = ON;
+ if (!(clk_readl(PERIPH_CLK_TO_ENB_REG(c)) & PERIPH_CLK_TO_BIT(c)))
+ c->state = OFF;
+};
+
+static int tegra30_clk_double_set_rate(struct clk *c, unsigned long rate)
+{
+ u32 val;
+ unsigned long parent_rate = clk_get_rate(c->parent);
+ if (rate == parent_rate) {
+ val = clk_readl(c->reg) | (0x1 << c->reg_shift);
+ clk_writel(val, c->reg);
+ c->mul = 1;
+ c->div = 1;
+ return 0;
+ } else if (rate == 2 * parent_rate) {
+ val = clk_readl(c->reg) & (~(0x1 << c->reg_shift));
+ clk_writel(val, c->reg);
+ c->mul = 2;
+ c->div = 1;
+ return 0;
+ }
+ return -EINVAL;
+}
+
+static struct clk_ops tegra_clk_double_ops = {
+ .init = &tegra30_clk_double_init,
+ .enable = &tegra30_periph_clk_enable,
+ .disable = &tegra30_periph_clk_disable,
+ .set_rate = &tegra30_clk_double_set_rate,
+};
+
+/* Audio sync clock ops */
+static int tegra30_sync_source_set_rate(struct clk *c, unsigned long rate)
+{
+ c->rate = rate;
+ return 0;
+}
+
+static struct clk_ops tegra_sync_source_ops = {
+ .set_rate = &tegra30_sync_source_set_rate,
+};
+
+static void tegra30_audio_sync_clk_init(struct clk *c)
+{
+ int source;
+ const struct clk_mux_sel *sel;
+ u32 val = clk_readl(c->reg);
+ c->state = (val & AUDIO_SYNC_DISABLE_BIT) ? OFF : ON;
+ source = val & AUDIO_SYNC_SOURCE_MASK;
+ for (sel = c->inputs; sel->input != NULL; sel++)
+ if (sel->value == source)
+ break;
+ BUG_ON(sel->input == NULL);
+ c->parent = sel->input;
+}
+
+static int tegra30_audio_sync_clk_enable(struct clk *c)
+{
+ u32 val = clk_readl(c->reg);
+ clk_writel((val & (~AUDIO_SYNC_DISABLE_BIT)), c->reg);
+ return 0;
+}
+
+static void tegra30_audio_sync_clk_disable(struct clk *c)
+{
+ u32 val = clk_readl(c->reg);
+ clk_writel((val | AUDIO_SYNC_DISABLE_BIT), c->reg);
+}
+
+static int tegra30_audio_sync_clk_set_parent(struct clk *c, struct clk *p)
+{
+ u32 val;
+ const struct clk_mux_sel *sel;
+ for (sel = c->inputs; sel->input != NULL; sel++) {
+ if (sel->input == p) {
+ val = clk_readl(c->reg);
+ val &= ~AUDIO_SYNC_SOURCE_MASK;
+ val |= sel->value;
+
+ if (c->refcnt)
+ clk_enable(p);
+
+ clk_writel(val, c->reg);
+
+ if (c->refcnt && c->parent)
+ clk_disable(c->parent);
+
+ clk_reparent(c, p);
+ return 0;
+ }
+ }
+
+ return -EINVAL;
+}
+
+static struct clk_ops tegra_audio_sync_clk_ops = {
+ .init = tegra30_audio_sync_clk_init,
+ .enable = tegra30_audio_sync_clk_enable,
+ .disable = tegra30_audio_sync_clk_disable,
+ .set_parent = tegra30_audio_sync_clk_set_parent,
+};
+
+/* cml0 (pcie), and cml1 (sata) clock ops */
+static void tegra30_cml_clk_init(struct clk *c)
+{
+ u32 val = clk_readl(c->reg);
+ c->state = val & (0x1 << c->u.periph.clk_num) ? ON : OFF;
+}
+
+static int tegra30_cml_clk_enable(struct clk *c)
+{
+ u32 val = clk_readl(c->reg);
+ val |= (0x1 << c->u.periph.clk_num);
+ clk_writel(val, c->reg);
+ return 0;
+}
+
+static void tegra30_cml_clk_disable(struct clk *c)
+{
+ u32 val = clk_readl(c->reg);
+ val &= ~(0x1 << c->u.periph.clk_num);
+ clk_writel(val, c->reg);
+}
+
+static struct clk_ops tegra_cml_clk_ops = {
+ .init = &tegra30_cml_clk_init,
+ .enable = &tegra30_cml_clk_enable,
+ .disable = &tegra30_cml_clk_disable,
+};
+
+/* Clock definitions */
+static struct clk tegra_clk_32k = {
+ .name = "clk_32k",
+ .rate = 32768,
+ .ops = NULL,
+ .max_rate = 32768,
+};
+
+static struct clk tegra_clk_m = {
+ .name = "clk_m",
+ .flags = ENABLE_ON_INIT,
+ .ops = &tegra_clk_m_ops,
+ .reg = 0x1fc,
+ .reg_shift = 28,
+ .max_rate = 48000000,
+};
+
+static struct clk tegra_clk_m_div2 = {
+ .name = "clk_m_div2",
+ .ops = &tegra_clk_m_div_ops,
+ .parent = &tegra_clk_m,
+ .mul = 1,
+ .div = 2,
+ .state = ON,
+ .max_rate = 24000000,
+};
+
+static struct clk tegra_clk_m_div4 = {
+ .name = "clk_m_div4",
+ .ops = &tegra_clk_m_div_ops,
+ .parent = &tegra_clk_m,
+ .mul = 1,
+ .div = 4,
+ .state = ON,
+ .max_rate = 12000000,
+};
+
+static struct clk tegra_pll_ref = {
+ .name = "pll_ref",
+ .flags = ENABLE_ON_INIT,
+ .ops = &tegra_pll_ref_ops,
+ .parent = &tegra_clk_m,
+ .max_rate = 26000000,
+};
+
+static struct clk_pll_freq_table tegra_pll_c_freq_table[] = {
+ { 12000000, 1040000000, 520, 6, 1, 8},
+ { 13000000, 1040000000, 480, 6, 1, 8},
+ { 16800000, 1040000000, 495, 8, 1, 8}, /* actual: 1039.5 MHz */
+ { 19200000, 1040000000, 325, 6, 1, 6},
+ { 26000000, 1040000000, 520, 13, 1, 8},
+
+ { 12000000, 832000000, 416, 6, 1, 8},
+ { 13000000, 832000000, 832, 13, 1, 8},
+ { 16800000, 832000000, 396, 8, 1, 8}, /* actual: 831.6 MHz */
+ { 19200000, 832000000, 260, 6, 1, 8},
+ { 26000000, 832000000, 416, 13, 1, 8},
+
+ { 12000000, 624000000, 624, 12, 1, 8},
+ { 13000000, 624000000, 624, 13, 1, 8},
+ { 16800000, 600000000, 520, 14, 1, 8},
+ { 19200000, 624000000, 520, 16, 1, 8},
+ { 26000000, 624000000, 624, 26, 1, 8},
+
+ { 12000000, 600000000, 600, 12, 1, 8},
+ { 13000000, 600000000, 600, 13, 1, 8},
+ { 16800000, 600000000, 500, 14, 1, 8},
+ { 19200000, 600000000, 375, 12, 1, 6},
+ { 26000000, 600000000, 600, 26, 1, 8},
+
+ { 12000000, 520000000, 520, 12, 1, 8},
+ { 13000000, 520000000, 520, 13, 1, 8},
+ { 16800000, 520000000, 495, 16, 1, 8}, /* actual: 519.75 MHz */
+ { 19200000, 520000000, 325, 12, 1, 6},
+ { 26000000, 520000000, 520, 26, 1, 8},
+
+ { 12000000, 416000000, 416, 12, 1, 8},
+ { 13000000, 416000000, 416, 13, 1, 8},
+ { 16800000, 416000000, 396, 16, 1, 8}, /* actual: 415.8 MHz */
+ { 19200000, 416000000, 260, 12, 1, 6},
+ { 26000000, 416000000, 416, 26, 1, 8},
+ { 0, 0, 0, 0, 0, 0 },
+};
+
+static struct clk tegra_pll_c = {
+ .name = "pll_c",
+ .flags = PLL_HAS_CPCON,
+ .ops = &tegra_pll_ops,
+ .reg = 0x80,
+ .parent = &tegra_pll_ref,
+ .max_rate = 1400000000,
+ .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 = {
+ .name = "pll_c_out1",
+ .ops = &tegra_pll_div_ops,
+ .flags = DIV_U71,
+ .parent = &tegra_pll_c,
+ .reg = 0x84,
+ .reg_shift = 0,
+ .max_rate = 700000000,
+};
+
+static struct clk_pll_freq_table tegra_pll_m_freq_table[] = {
+ { 12000000, 666000000, 666, 12, 1, 8},
+ { 13000000, 666000000, 666, 13, 1, 8},
+ { 16800000, 666000000, 555, 14, 1, 8},
+ { 19200000, 666000000, 555, 16, 1, 8},
+ { 26000000, 666000000, 666, 26, 1, 8},
+ { 12000000, 600000000, 600, 12, 1, 8},
+ { 13000000, 600000000, 600, 13, 1, 8},
+ { 16800000, 600000000, 500, 14, 1, 8},
+ { 19200000, 600000000, 375, 12, 1, 6},
+ { 26000000, 600000000, 600, 26, 1, 8},
+ { 0, 0, 0, 0, 0, 0 },
+};
+
+static struct clk tegra_pll_m = {
+ .name = "pll_m",
+ .flags = PLL_HAS_CPCON | PLLM,
+ .ops = &tegra_pll_ops,
+ .reg = 0x90,
+ .parent = &tegra_pll_ref,
+ .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 = {
+ .name = "pll_m_out1",
+ .ops = &tegra_pll_div_ops,
+ .flags = DIV_U71,
+ .parent = &tegra_pll_m,
+ .reg = 0x94,
+ .reg_shift = 0,
+ .max_rate = 600000000,
+};
+
+static struct clk_pll_freq_table tegra_pll_p_freq_table[] = {
+ { 12000000, 216000000, 432, 12, 2, 8},
+ { 13000000, 216000000, 432, 13, 2, 8},
+ { 16800000, 216000000, 360, 14, 2, 8},
+ { 19200000, 216000000, 360, 16, 2, 8},
+ { 26000000, 216000000, 432, 26, 2, 8},
+ { 0, 0, 0, 0, 0, 0 },
+};
+
+static struct clk tegra_pll_p = {
+ .name = "pll_p",
+ .flags = ENABLE_ON_INIT | PLL_FIXED | PLL_HAS_CPCON,
+ .ops = &tegra_pll_ops,
+ .reg = 0xa0,
+ .parent = &tegra_pll_ref,
+ .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,
+ .fixed_rate = 408000000,
+ },
+};
+
+static struct clk tegra_pll_p_out1 = {
+ .name = "pll_p_out1",
+ .ops = &tegra_pll_div_ops,
+ .flags = ENABLE_ON_INIT | DIV_U71 | DIV_U71_FIXED,
+ .parent = &tegra_pll_p,
+ .reg = 0xa4,
+ .reg_shift = 0,
+ .max_rate = 432000000,
+};
+
+static struct clk tegra_pll_p_out2 = {
+ .name = "pll_p_out2",
+ .ops = &tegra_pll_div_ops,
+ .flags = ENABLE_ON_INIT | DIV_U71 | DIV_U71_FIXED,
+ .parent = &tegra_pll_p,
+ .reg = 0xa4,
+ .reg_shift = 16,
+ .max_rate = 432000000,
+};
+
+static struct clk tegra_pll_p_out3 = {
+ .name = "pll_p_out3",
+ .ops = &tegra_pll_div_ops,
+ .flags = ENABLE_ON_INIT | DIV_U71 | DIV_U71_FIXED,
+ .parent = &tegra_pll_p,
+ .reg = 0xa8,
+ .reg_shift = 0,
+ .max_rate = 432000000,
+};
+
+static struct clk tegra_pll_p_out4 = {
+ .name = "pll_p_out4",
+ .ops = &tegra_pll_div_ops,
+ .flags = ENABLE_ON_INIT | DIV_U71 | DIV_U71_FIXED,
+ .parent = &tegra_pll_p,
+ .reg = 0xa8,
+ .reg_shift = 16,
+ .max_rate = 432000000,
+};
+
+static struct clk_pll_freq_table tegra_pll_a_freq_table[] = {
+ { 9600000, 564480000, 294, 5, 1, 4},
+ { 9600000, 552960000, 288, 5, 1, 4},
+ { 9600000, 24000000, 5, 2, 1, 1},
+
+ { 28800000, 56448000, 49, 25, 1, 1},
+ { 28800000, 73728000, 64, 25, 1, 1},
+ { 28800000, 24000000, 5, 6, 1, 1},
+ { 0, 0, 0, 0, 0, 0 },
+};
+
+static struct clk tegra_pll_a = {
+ .name = "pll_a",
+ .flags = PLL_HAS_CPCON,
+ .ops = &tegra_pll_ops,
+ .reg = 0xb0,
+ .parent = &tegra_pll_p_out1,
+ .max_rate = 700000000,
+ .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 = {
+ .name = "pll_a_out0",
+ .ops = &tegra_pll_div_ops,
+ .flags = DIV_U71,
+ .parent = &tegra_pll_a,
+ .reg = 0xb4,
+ .reg_shift = 0,
+ .max_rate = 100000000,
+};
+
+static struct clk_pll_freq_table tegra_pll_d_freq_table[] = {
+ { 12000000, 216000000, 216, 12, 1, 4},
+ { 13000000, 216000000, 216, 13, 1, 4},
+ { 16800000, 216000000, 180, 14, 1, 4},
+ { 19200000, 216000000, 180, 16, 1, 4},
+ { 26000000, 216000000, 216, 26, 1, 4},
+
+ { 12000000, 594000000, 594, 12, 1, 8},
+ { 13000000, 594000000, 594, 13, 1, 8},
+ { 16800000, 594000000, 495, 14, 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 },
+};
+
+static struct clk tegra_pll_d = {
+ .name = "pll_d",
+ .flags = PLL_HAS_CPCON | PLLD,
+ .ops = &tegra_plld_ops,
+ .reg = 0xd0,
+ .parent = &tegra_pll_ref,
+ .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 = {
+ .name = "pll_d_out0",
+ .ops = &tegra_pll_div_ops,
+ .flags = DIV_2 | PLLD,
+ .parent = &tegra_pll_d,
+ .max_rate = 500000000,
+};
+
+static struct clk tegra_pll_d2 = {
+ .name = "pll_d2",
+ .flags = PLL_HAS_CPCON | PLL_ALT_MISC_REG | PLLD,
+ .ops = &tegra_plld_ops,
+ .reg = 0x4b8,
+ .parent = &tegra_pll_ref,
+ .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_d2_out0 = {
+ .name = "pll_d2_out0",
+ .ops = &tegra_pll_div_ops,
+ .flags = DIV_2 | PLLD,
+ .parent = &tegra_pll_d2,
+ .max_rate = 500000000,
+};
+
+static struct clk_pll_freq_table tegra_pll_u_freq_table[] = {
+ { 12000000, 480000000, 960, 12, 2, 12},
+ { 13000000, 480000000, 960, 13, 2, 12},
+ { 16800000, 480000000, 400, 7, 2, 5},
+ { 19200000, 480000000, 200, 4, 2, 3},
+ { 26000000, 480000000, 960, 26, 2, 12},
+ { 0, 0, 0, 0, 0, 0 },
+};
+
+static struct clk tegra_pll_u = {
+ .name = "pll_u",
+ .flags = PLL_HAS_CPCON | PLLU,
+ .ops = &tegra_pll_ops,
+ .reg = 0xc0,
+ .parent = &tegra_pll_ref,
+ .max_rate = 480000000,
+ .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.7 GHz */
+ { 12000000, 1700000000, 850, 6, 1, 8},
+ { 13000000, 1700000000, 915, 7, 1, 8}, /* actual: 1699.2 MHz */
+ { 16800000, 1700000000, 708, 7, 1, 8}, /* actual: 1699.2 MHz */
+ { 19200000, 1700000000, 885, 10, 1, 8}, /* actual: 1699.2 MHz */
+ { 26000000, 1700000000, 850, 13, 1, 8},
+
+ /* 1.6 GHz */
+ { 12000000, 1600000000, 800, 6, 1, 8},
+ { 13000000, 1600000000, 738, 6, 1, 8}, /* actual: 1599.0 MHz */
+ { 16800000, 1600000000, 857, 9, 1, 8}, /* actual: 1599.7 MHz */
+ { 19200000, 1600000000, 500, 6, 1, 8},
+ { 26000000, 1600000000, 800, 13, 1, 8},
+
+ /* 1.5 GHz */
+ { 12000000, 1500000000, 750, 6, 1, 8},
+ { 13000000, 1500000000, 923, 8, 1, 8}, /* actual: 1499.8 MHz */
+ { 16800000, 1500000000, 625, 7, 1, 8},
+ { 19200000, 1500000000, 625, 8, 1, 8},
+ { 26000000, 1500000000, 750, 13, 1, 8},
+
+ /* 1.4 GHz */
+ { 12000000, 1400000000, 700, 6, 1, 8},
+ { 13000000, 1400000000, 969, 9, 1, 8}, /* actual: 1399.7 MHz */
+ { 16800000, 1400000000, 1000, 12, 1, 8},
+ { 19200000, 1400000000, 875, 12, 1, 8},
+ { 26000000, 1400000000, 700, 13, 1, 8},
+
+ /* 1.3 GHz */
+ { 12000000, 1300000000, 975, 9, 1, 8},
+ { 13000000, 1300000000, 1000, 10, 1, 8},
+ { 16800000, 1300000000, 928, 12, 1, 8}, /* actual: 1299.2 MHz */
+ { 19200000, 1300000000, 812, 12, 1, 8}, /* actual: 1299.2 MHz */
+ { 26000000, 1300000000, 650, 13, 1, 8},
+
+ /* 1.2 GHz */
+ { 12000000, 1200000000, 1000, 10, 1, 8},
+ { 13000000, 1200000000, 923, 10, 1, 8}, /* actual: 1199.9 MHz */
+ { 16800000, 1200000000, 1000, 14, 1, 8},
+ { 19200000, 1200000000, 1000, 16, 1, 8},
+ { 26000000, 1200000000, 600, 13, 1, 8},
+
+ /* 1.1 GHz */
+ { 12000000, 1100000000, 825, 9, 1, 8},
+ { 13000000, 1100000000, 846, 10, 1, 8}, /* actual: 1099.8 MHz */
+ { 16800000, 1100000000, 982, 15, 1, 8}, /* actual: 1099.8 MHz */
+ { 19200000, 1100000000, 859, 15, 1, 8}, /* actual: 1099.5 MHz */
+ { 26000000, 1100000000, 550, 13, 1, 8},
+
+ /* 1 GHz */
+ { 12000000, 1000000000, 1000, 12, 1, 8},
+ { 13000000, 1000000000, 1000, 13, 1, 8},
+ { 16800000, 1000000000, 833, 14, 1, 8}, /* actual: 999.6 MHz */
+ { 19200000, 1000000000, 625, 12, 1, 8},
+ { 26000000, 1000000000, 1000, 26, 1, 8},
+
+ { 0, 0, 0, 0, 0, 0 },
+};
+
+static struct clk tegra_pll_x = {
+ .name = "pll_x",
+ .flags = PLL_HAS_CPCON | PLL_ALT_MISC_REG | PLLX,
+ .ops = &tegra_pll_ops,
+ .reg = 0xe0,
+ .parent = &tegra_pll_ref,
+ .max_rate = 1700000000,
+ .u.pll = {
+ .input_min = 2000000,
+ .input_max = 31000000,
+ .cf_min = 1000000,
+ .cf_max = 6000000,
+ .vco_min = 20000000,
+ .vco_max = 1700000000,
+ .freq_table = tegra_pll_x_freq_table,
+ .lock_delay = 300,
+ },
+};
+
+static struct clk tegra_pll_x_out0 = {
+ .name = "pll_x_out0",
+ .ops = &tegra_pll_div_ops,
+ .flags = DIV_2 | PLLX,
+ .parent = &tegra_pll_x,
+ .max_rate = 850000000,
+};
+
+
+static struct clk_pll_freq_table tegra_pll_e_freq_table[] = {
+ /* PLLE special case: use cpcon field to store cml divider value */
+ { 12000000, 100000000, 150, 1, 18, 11},
+ { 216000000, 100000000, 200, 18, 24, 13},
+ { 0, 0, 0, 0, 0, 0 },
+};
+
+static struct clk tegra_pll_e = {
+ .name = "pll_e",
+ .flags = PLL_ALT_MISC_REG,
+ .ops = &tegra_plle_ops,
+ .reg = 0xe8,
+ .max_rate = 100000000,
+ .u.pll = {
+ .input_min = 12000000,
+ .input_max = 216000000,
+ .cf_min = 12000000,
+ .cf_max = 12000000,
+ .vco_min = 1200000000,
+ .vco_max = 2400000000U,
+ .freq_table = tegra_pll_e_freq_table,
+ .lock_delay = 300,
+ .fixed_rate = 100000000,
+ },
+};
+
+static struct clk tegra_cml0_clk = {
+ .name = "cml0",
+ .parent = &tegra_pll_e,
+ .ops = &tegra_cml_clk_ops,
+ .reg = PLLE_AUX,
+ .max_rate = 100000000,
+ .u.periph = {
+ .clk_num = 0,
+ },
+};
+
+static struct clk tegra_cml1_clk = {
+ .name = "cml1",
+ .parent = &tegra_pll_e,
+ .ops = &tegra_cml_clk_ops,
+ .reg = PLLE_AUX,
+ .max_rate = 100000000,
+ .u.periph = {
+ .clk_num = 1,
+ },
+};
+
+static struct clk tegra_pciex_clk = {
+ .name = "pciex",
+ .parent = &tegra_pll_e,
+ .ops = &tegra_pciex_clk_ops,
+ .max_rate = 100000000,
+ .u.periph = {
+ .clk_num = 74,
+ },
+};
+
+/* Audio sync clocks */
+#define SYNC_SOURCE(_id) \
+ { \
+ .name = #_id "_sync", \
+ .rate = 24000000, \
+ .max_rate = 24000000, \
+ .ops = &tegra_sync_source_ops \
+ }
+static struct clk tegra_sync_source_list[] = {
+ SYNC_SOURCE(spdif_in),
+ SYNC_SOURCE(i2s0),
+ SYNC_SOURCE(i2s1),
+ SYNC_SOURCE(i2s2),
+ SYNC_SOURCE(i2s3),
+ SYNC_SOURCE(i2s4),
+ SYNC_SOURCE(vimclk),
+};
+
+static struct clk_mux_sel mux_audio_sync_clk[] = {
+ { .input = &tegra_sync_source_list[0], .value = 0},
+ { .input = &tegra_sync_source_list[1], .value = 1},
+ { .input = &tegra_sync_source_list[2], .value = 2},
+ { .input = &tegra_sync_source_list[3], .value = 3},
+ { .input = &tegra_sync_source_list[4], .value = 4},
+ { .input = &tegra_sync_source_list[5], .value = 5},
+ { .input = &tegra_pll_a_out0, .value = 6},
+ { .input = &tegra_sync_source_list[6], .value = 7},
+ { 0, 0 }
+};
+
+#define AUDIO_SYNC_CLK(_id, _index) \
+ { \
+ .name = #_id, \
+ .inputs = mux_audio_sync_clk, \
+ .reg = 0x4A0 + (_index) * 4, \
+ .max_rate = 24000000, \
+ .ops = &tegra_audio_sync_clk_ops \
+ }
+static struct clk tegra_clk_audio_list[] = {
+ AUDIO_SYNC_CLK(audio0, 0),
+ AUDIO_SYNC_CLK(audio1, 1),
+ AUDIO_SYNC_CLK(audio2, 2),
+ AUDIO_SYNC_CLK(audio3, 3),
+ AUDIO_SYNC_CLK(audio4, 4),
+ AUDIO_SYNC_CLK(audio, 5), /* SPDIF */
+};
+
+#define AUDIO_SYNC_2X_CLK(_id, _index) \
+ { \
+ .name = #_id "_2x", \
+ .flags = PERIPH_NO_RESET, \
+ .max_rate = 48000000, \
+ .ops = &tegra_clk_double_ops, \
+ .reg = 0x49C, \
+ .reg_shift = 24 + (_index), \
+ .parent = &tegra_clk_audio_list[(_index)], \
+ .u.periph = { \
+ .clk_num = 113 + (_index), \
+ }, \
+ }
+static struct clk tegra_clk_audio_2x_list[] = {
+ AUDIO_SYNC_2X_CLK(audio0, 0),
+ AUDIO_SYNC_2X_CLK(audio1, 1),
+ AUDIO_SYNC_2X_CLK(audio2, 2),
+ AUDIO_SYNC_2X_CLK(audio3, 3),
+ AUDIO_SYNC_2X_CLK(audio4, 4),
+ AUDIO_SYNC_2X_CLK(audio, 5), /* SPDIF */
+};
+
+#define MUX_I2S_SPDIF(_id, _index) \
+static struct clk_mux_sel mux_pllaout0_##_id##_2x_pllp_clkm[] = { \
+ {.input = &tegra_pll_a_out0, .value = 0}, \
+ {.input = &tegra_clk_audio_2x_list[(_index)], .value = 1}, \
+ {.input = &tegra_pll_p, .value = 2}, \
+ {.input = &tegra_clk_m, .value = 3}, \
+ { 0, 0}, \
+}
+MUX_I2S_SPDIF(audio0, 0);
+MUX_I2S_SPDIF(audio1, 1);
+MUX_I2S_SPDIF(audio2, 2);
+MUX_I2S_SPDIF(audio3, 3);
+MUX_I2S_SPDIF(audio4, 4);
+MUX_I2S_SPDIF(audio, 5); /* SPDIF */
+
+/* External clock outputs (through PMC) */
+#define MUX_EXTERN_OUT(_id) \
+static struct clk_mux_sel mux_clkm_clkm2_clkm4_extern##_id[] = { \
+ {.input = &tegra_clk_m, .value = 0}, \
+ {.input = &tegra_clk_m_div2, .value = 1}, \
+ {.input = &tegra_clk_m_div4, .value = 2}, \
+ {.input = NULL, .value = 3}, /* placeholder */ \
+ { 0, 0}, \
+}
+MUX_EXTERN_OUT(1);
+MUX_EXTERN_OUT(2);
+MUX_EXTERN_OUT(3);
+
+static struct clk_mux_sel *mux_extern_out_list[] = {
+ mux_clkm_clkm2_clkm4_extern1,
+ mux_clkm_clkm2_clkm4_extern2,
+ mux_clkm_clkm2_clkm4_extern3,
+};
+
+#define CLK_OUT_CLK(_id) \
+ { \
+ .name = "clk_out_" #_id, \
+ .lookup = { \
+ .dev_id = "clk_out_" #_id, \
+ .con_id = "extern" #_id, \
+ }, \
+ .ops = &tegra_clk_out_ops, \
+ .reg = 0x1a8, \
+ .inputs = mux_clkm_clkm2_clkm4_extern##_id, \
+ .flags = MUX_CLK_OUT, \
+ .max_rate = 216000000, \
+ .u.periph = { \
+ .clk_num = (_id - 1) * 8 + 2, \
+ }, \
+ }
+static struct clk tegra_clk_out_list[] = {
+ CLK_OUT_CLK(1),
+ CLK_OUT_CLK(2),
+ CLK_OUT_CLK(3),
+};
+
+/* called after peripheral external clocks are initialized */
+static void init_clk_out_mux(void)
+{
+ int i;
+ struct clk *c;
+
+ /* output clock con_id is the name of peripheral
+ external clock connected to input 3 of the output mux */
+ for (i = 0; i < ARRAY_SIZE(tegra_clk_out_list); i++) {
+ c = tegra_get_clock_by_name(
+ tegra_clk_out_list[i].lookup.con_id);
+ if (!c)
+ pr_err("%s: could not find clk %s\n", __func__,
+ tegra_clk_out_list[i].lookup.con_id);
+ mux_extern_out_list[i][3].input = c;
+ }
+}
+
+/* Peripheral muxes */
+static struct clk_mux_sel mux_sclk[] = {
+ { .input = &tegra_clk_m, .value = 0},
+ { .input = &tegra_pll_c_out1, .value = 1},
+ { .input = &tegra_pll_p_out4, .value = 2},
+ { .input = &tegra_pll_p_out3, .value = 3},
+ { .input = &tegra_pll_p_out2, .value = 4},
+ /* { .input = &tegra_clk_d, .value = 5}, - no use on tegra30 */
+ { .input = &tegra_clk_32k, .value = 6},
+ { .input = &tegra_pll_m_out1, .value = 7},
+ { 0, 0},
+};
+
+static struct clk tegra_clk_sclk = {
+ .name = "sclk",
+ .inputs = mux_sclk,
+ .reg = 0x28,
+ .ops = &tegra_super_ops,
+ .max_rate = 334000000,
+ .min_rate = 40000000,
+};
+
+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[] = {
+ { .input = &tegra_pll_m, .value = 0},
+ { .input = &tegra_pll_c, .value = 1},
+ { .input = &tegra_pll_p, .value = 2},
+ { .input = &tegra_pll_a_out0, .value = 3},
+ { 0, 0},
+};
+
+static struct clk_mux_sel mux_pllp_pllc_pllm_clkm[] = {
+ { .input = &tegra_pll_p, .value = 0},
+ { .input = &tegra_pll_c, .value = 1},
+ { .input = &tegra_pll_m, .value = 2},
+ { .input = &tegra_clk_m, .value = 3},
+ { 0, 0},
+};
+
+static struct clk_mux_sel mux_pllp_clkm[] = {
+ { .input = &tegra_pll_p, .value = 0},
+ { .input = &tegra_clk_m, .value = 3},
+ { 0, 0},
+};
+
+static struct clk_mux_sel mux_pllp_plld_pllc_clkm[] = {
+ {.input = &tegra_pll_p, .value = 0},
+ {.input = &tegra_pll_d_out0, .value = 1},
+ {.input = &tegra_pll_c, .value = 2},
+ {.input = &tegra_clk_m, .value = 3},
+ { 0, 0},
+};
+
+static struct clk_mux_sel mux_pllp_pllm_plld_plla_pllc_plld2_clkm[] = {
+ {.input = &tegra_pll_p, .value = 0},
+ {.input = &tegra_pll_m, .value = 1},
+ {.input = &tegra_pll_d_out0, .value = 2},
+ {.input = &tegra_pll_a_out0, .value = 3},
+ {.input = &tegra_pll_c, .value = 4},
+ {.input = &tegra_pll_d2_out0, .value = 5},
+ {.input = &tegra_clk_m, .value = 6},
+ { 0, 0},
+};
+
+static struct clk_mux_sel mux_plla_pllc_pllp_clkm[] = {
+ { .input = &tegra_pll_a_out0, .value = 0},
+ /* { .input = &tegra_pll_c, .value = 1}, no use on tegra30 */
+ { .input = &tegra_pll_p, .value = 2},
+ { .input = &tegra_clk_m, .value = 3},
+ { 0, 0},
+};
+
+static struct clk_mux_sel mux_pllp_pllc_clk32_clkm[] = {
+ {.input = &tegra_pll_p, .value = 0},
+ {.input = &tegra_pll_c, .value = 1},
+ {.input = &tegra_clk_32k, .value = 2},
+ {.input = &tegra_clk_m, .value = 3},
+ { 0, 0},
+};
+
+static struct clk_mux_sel mux_pllp_pllc_clkm_clk32[] = {
+ {.input = &tegra_pll_p, .value = 0},
+ {.input = &tegra_pll_c, .value = 1},
+ {.input = &tegra_clk_m, .value = 2},
+ {.input = &tegra_clk_32k, .value = 3},
+ { 0, 0},
+};
+
+static struct clk_mux_sel mux_pllp_pllc_pllm[] = {
+ {.input = &tegra_pll_p, .value = 0},
+ {.input = &tegra_pll_c, .value = 1},
+ {.input = &tegra_pll_m, .value = 2},
+ { 0, 0},
+};
+
+static struct clk_mux_sel mux_clk_m[] = {
+ { .input = &tegra_clk_m, .value = 0},
+ { 0, 0},
+};
+
+static struct clk_mux_sel mux_pllp_out3[] = {
+ { .input = &tegra_pll_p_out3, .value = 0},
+ { 0, 0},
+};
+
+static struct clk_mux_sel mux_plld_out0[] = {
+ { .input = &tegra_pll_d_out0, .value = 0},
+ { 0, 0},
+};
+
+static struct clk_mux_sel mux_plld_out0_plld2_out0[] = {
+ { .input = &tegra_pll_d_out0, .value = 0},
+ { .input = &tegra_pll_d2_out0, .value = 1},
+ { 0, 0},
+};
+
+static struct clk_mux_sel mux_clk_32k[] = {
+ { .input = &tegra_clk_32k, .value = 0},
+ { 0, 0},
+};
+
+static struct clk_mux_sel mux_plla_clk32_pllp_clkm_plle[] = {
+ { .input = &tegra_pll_a_out0, .value = 0},
+ { .input = &tegra_clk_32k, .value = 1},
+ { .input = &tegra_pll_p, .value = 2},
+ { .input = &tegra_clk_m, .value = 3},
+ { .input = &tegra_pll_e, .value = 4},
+ { 0, 0},
+};
+
+static struct clk_mux_sel mux_cclk_g[] = {
+ { .input = &tegra_clk_m, .value = 0},
+ { .input = &tegra_pll_c, .value = 1},
+ { .input = &tegra_clk_32k, .value = 2},
+ { .input = &tegra_pll_m, .value = 3},
+ { .input = &tegra_pll_p, .value = 4},
+ { .input = &tegra_pll_p_out4, .value = 5},
+ { .input = &tegra_pll_p_out3, .value = 6},
+ { .input = &tegra_pll_x, .value = 8},
+ { 0, 0},
+};
+
+static struct clk tegra_clk_cclk_g = {
+ .name = "cclk_g",
+ .flags = DIV_U71 | DIV_U71_INT,
+ .inputs = mux_cclk_g,
+ .reg = 0x368,
+ .ops = &tegra_super_ops,
+ .max_rate = 1700000000,
+};
+
+static struct clk tegra30_clk_twd = {
+ .parent = &tegra_clk_cclk_g,
+ .name = "twd",
+ .ops = &tegra30_twd_ops,
+ .max_rate = 1400000000, /* Same as tegra_clk_cpu_cmplx.max_rate */
+ .mul = 1,
+ .div = 2,
+};
+
+#define PERIPH_CLK(_name, _dev, _con, _clk_num, _reg, _max, _inputs, _flags) \
+ { \
+ .name = _name, \
+ .lookup = { \
+ .dev_id = _dev, \
+ .con_id = _con, \
+ }, \
+ .ops = &tegra_periph_clk_ops, \
+ .reg = _reg, \
+ .inputs = _inputs, \
+ .flags = _flags, \
+ .max_rate = _max, \
+ .u.periph = { \
+ .clk_num = _clk_num, \
+ }, \
+ }
+
+#define PERIPH_CLK_EX(_name, _dev, _con, _clk_num, _reg, _max, _inputs, \
+ _flags, _ops) \
+ { \
+ .name = _name, \
+ .lookup = { \
+ .dev_id = _dev, \
+ .con_id = _con, \
+ }, \
+ .ops = _ops, \
+ .reg = _reg, \
+ .inputs = _inputs, \
+ .flags = _flags, \
+ .max_rate = _max, \
+ .u.periph = { \
+ .clk_num = _clk_num, \
+ }, \
+ }
+
+#define SHARED_CLK(_name, _dev, _con, _parent, _id, _div, _mode)\
+ { \
+ .name = _name, \
+ .lookup = { \
+ .dev_id = _dev, \
+ .con_id = _con, \
+ }, \
+ .ops = &tegra_clk_shared_bus_ops, \
+ .parent = _parent, \
+ .u.shared_bus_user = { \
+ .client_id = _id, \
+ .client_div = _div, \
+ .mode = _mode, \
+ }, \
+ }
+struct clk tegra_list_clks[] = {
+ PERIPH_CLK("apbdma", "tegra-dma", NULL, 34, 0, 26000000, mux_clk_m, 0),
+ PERIPH_CLK("rtc", "rtc-tegra", NULL, 4, 0, 32768, mux_clk_32k, PERIPH_NO_RESET | PERIPH_ON_APB),
+ PERIPH_CLK("kbc", "tegra-kbc", NULL, 36, 0, 32768, mux_clk_32k, PERIPH_NO_RESET | PERIPH_ON_APB),
+ PERIPH_CLK("timer", "timer", NULL, 5, 0, 26000000, mux_clk_m, 0),
+ PERIPH_CLK("kfuse", "kfuse-tegra", NULL, 40, 0, 26000000, mux_clk_m, 0),
+ PERIPH_CLK("fuse", "fuse-tegra", "fuse", 39, 0, 26000000, mux_clk_m, PERIPH_ON_APB),
+ PERIPH_CLK("fuse_burn", "fuse-tegra", "fuse_burn", 39, 0, 26000000, mux_clk_m, PERIPH_ON_APB),
+ PERIPH_CLK("apbif", "tegra30-ahub", "apbif", 107, 0, 26000000, mux_clk_m, 0),
+ PERIPH_CLK("i2s0", "tegra30-i2s.0", NULL, 30, 0x1d8, 26000000, mux_pllaout0_audio0_2x_pllp_clkm, MUX | DIV_U71 | PERIPH_ON_APB),
+ PERIPH_CLK("i2s1", "tegra30-i2s.1", NULL, 11, 0x100, 26000000, mux_pllaout0_audio1_2x_pllp_clkm, MUX | DIV_U71 | PERIPH_ON_APB),
+ PERIPH_CLK("i2s2", "tegra30-i2s.2", NULL, 18, 0x104, 26000000, mux_pllaout0_audio2_2x_pllp_clkm, MUX | DIV_U71 | PERIPH_ON_APB),
+ PERIPH_CLK("i2s3", "tegra30-i2s.3", NULL, 101, 0x3bc, 26000000, mux_pllaout0_audio3_2x_pllp_clkm, MUX | DIV_U71 | PERIPH_ON_APB),
+ PERIPH_CLK("i2s4", "tegra30-i2s.4", NULL, 102, 0x3c0, 26000000, mux_pllaout0_audio4_2x_pllp_clkm, MUX | DIV_U71 | PERIPH_ON_APB),
+ PERIPH_CLK("spdif_out", "tegra30-spdif", "spdif_out", 10, 0x108, 100000000, mux_pllaout0_audio_2x_pllp_clkm, MUX | DIV_U71 | PERIPH_ON_APB),
+ PERIPH_CLK("spdif_in", "tegra30-spdif", "spdif_in", 10, 0x10c, 100000000, mux_pllp_pllc_pllm, MUX | DIV_U71 | PERIPH_ON_APB),
+ PERIPH_CLK("pwm", "pwm", NULL, 17, 0x110, 432000000, mux_pllp_pllc_clk32_clkm, MUX | MUX_PWM | DIV_U71 | PERIPH_ON_APB),
+ PERIPH_CLK("d_audio", "tegra30-ahub", "d_audio", 106, 0x3d0, 48000000, mux_plla_pllc_pllp_clkm, MUX | DIV_U71),
+ PERIPH_CLK("dam0", "tegra30-dam.0", NULL, 108, 0x3d8, 48000000, mux_plla_pllc_pllp_clkm, MUX | DIV_U71),
+ PERIPH_CLK("dam1", "tegra30-dam.1", NULL, 109, 0x3dc, 48000000, mux_plla_pllc_pllp_clkm, MUX | DIV_U71),
+ PERIPH_CLK("dam2", "tegra30-dam.2", NULL, 110, 0x3e0, 48000000, mux_plla_pllc_pllp_clkm, MUX | DIV_U71),
+ PERIPH_CLK("hda", "tegra30-hda", "hda", 125, 0x428, 108000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71),
+ PERIPH_CLK("hda2codec_2x", "tegra30-hda", "hda2codec", 111, 0x3e4, 48000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71),
+ PERIPH_CLK("hda2hdmi", "tegra30-hda", "hda2hdmi", 128, 0, 48000000, mux_clk_m, 0),
+ PERIPH_CLK("sbc1", "spi_tegra.0", NULL, 41, 0x134, 160000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | PERIPH_ON_APB),
+ PERIPH_CLK("sbc2", "spi_tegra.1", NULL, 44, 0x118, 160000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | PERIPH_ON_APB),
+ PERIPH_CLK("sbc3", "spi_tegra.2", NULL, 46, 0x11c, 160000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | PERIPH_ON_APB),
+ PERIPH_CLK("sbc4", "spi_tegra.3", NULL, 68, 0x1b4, 160000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | PERIPH_ON_APB),
+ PERIPH_CLK("sbc5", "spi_tegra.4", NULL, 104, 0x3c8, 160000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | PERIPH_ON_APB),
+ PERIPH_CLK("sbc6", "spi_tegra.5", NULL, 105, 0x3cc, 160000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | PERIPH_ON_APB),
+ PERIPH_CLK("sata_oob", "tegra_sata_oob", NULL, 123, 0x420, 216000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71),
+ PERIPH_CLK("sata", "tegra_sata", NULL, 124, 0x424, 216000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71),
+ PERIPH_CLK("sata_cold", "tegra_sata_cold", NULL, 129, 0, 48000000, mux_clk_m, 0),
+ PERIPH_CLK_EX("ndflash", "tegra_nand", NULL, 13, 0x160, 240000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71, &tegra_nand_clk_ops),
+ PERIPH_CLK("ndspeed", "tegra_nand_speed", NULL, 80, 0x3f8, 240000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71),
+ PERIPH_CLK("vfir", "vfir", NULL, 7, 0x168, 72000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | PERIPH_ON_APB),
+ PERIPH_CLK("sdmmc1", "sdhci-tegra.0", NULL, 14, 0x150, 208000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71), /* scales with voltage */
+ PERIPH_CLK("sdmmc2", "sdhci-tegra.1", NULL, 9, 0x154, 104000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71), /* scales with voltage */
+ PERIPH_CLK("sdmmc3", "sdhci-tegra.2", NULL, 69, 0x1bc, 208000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71), /* scales with voltage */
+ PERIPH_CLK("sdmmc4", "sdhci-tegra.3", NULL, 15, 0x164, 104000000, 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", "vde", NULL, 61, 0x1c8, 520000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | DIV_U71_INT),
+ PERIPH_CLK("csite", "csite", NULL, 73, 0x1d4, 144000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71), /* max rate ??? */
+ PERIPH_CLK("la", "la", NULL, 76, 0x1f8, 26000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71),
+ PERIPH_CLK("owr", "tegra_w1", NULL, 71, 0x1cc, 26000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | PERIPH_ON_APB),
+ PERIPH_CLK("nor", "nor", NULL, 42, 0x1d0, 127000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71), /* requires min voltage */
+ PERIPH_CLK("mipi", "mipi", NULL, 50, 0x174, 60000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | PERIPH_ON_APB), /* scales with voltage */
+ PERIPH_CLK("i2c1", "tegra-i2c.0", NULL, 12, 0x124, 26000000, mux_pllp_clkm, MUX | DIV_U16 | PERIPH_ON_APB),
+ PERIPH_CLK("i2c2", "tegra-i2c.1", NULL, 54, 0x198, 26000000, mux_pllp_clkm, MUX | DIV_U16 | PERIPH_ON_APB),
+ PERIPH_CLK("i2c3", "tegra-i2c.2", NULL, 67, 0x1b8, 26000000, mux_pllp_clkm, MUX | DIV_U16 | PERIPH_ON_APB),
+ PERIPH_CLK("i2c4", "tegra-i2c.3", NULL, 103, 0x3c4, 26000000, mux_pllp_clkm, MUX | DIV_U16 | PERIPH_ON_APB),
+ PERIPH_CLK("i2c5", "tegra-i2c.4", NULL, 47, 0x128, 26000000, mux_pllp_clkm, MUX | DIV_U16 | PERIPH_ON_APB),
+ PERIPH_CLK("uarta", "tegra_uart.0", NULL, 6, 0x178, 800000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | DIV_U71_UART | PERIPH_ON_APB),
+ PERIPH_CLK("uartb", "tegra_uart.1", NULL, 7, 0x17c, 800000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | DIV_U71_UART | PERIPH_ON_APB),
+ PERIPH_CLK("uartc", "tegra_uart.2", NULL, 55, 0x1a0, 800000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | DIV_U71_UART | PERIPH_ON_APB),
+ PERIPH_CLK("uartd", "tegra_uart.3", NULL, 65, 0x1c0, 800000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | DIV_U71_UART | PERIPH_ON_APB),
+ PERIPH_CLK("uarte", "tegra_uart.4", NULL, 66, 0x1c4, 800000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | DIV_U71_UART | PERIPH_ON_APB),
+ PERIPH_CLK("uarta_dbg", "serial8250.0", "uarta", 6, 0x178, 800000000, mux_pllp_clkm, MUX | DIV_U71 | DIV_U71_UART | PERIPH_ON_APB),
+ PERIPH_CLK("uartb_dbg", "serial8250.0", "uartb", 7, 0x17c, 800000000, mux_pllp_clkm, MUX | DIV_U71 | DIV_U71_UART | PERIPH_ON_APB),
+ PERIPH_CLK("uartc_dbg", "serial8250.0", "uartc", 55, 0x1a0, 800000000, mux_pllp_clkm, MUX | DIV_U71 | DIV_U71_UART | PERIPH_ON_APB),
+ PERIPH_CLK("uartd_dbg", "serial8250.0", "uartd", 65, 0x1c0, 800000000, mux_pllp_clkm, MUX | DIV_U71 | DIV_U71_UART | PERIPH_ON_APB),
+ PERIPH_CLK("uarte_dbg", "serial8250.0", "uarte", 66, 0x1c4, 800000000, mux_pllp_clkm, MUX | DIV_U71 | DIV_U71_UART | PERIPH_ON_APB),
+ PERIPH_CLK_EX("vi", "tegra_camera", "vi", 20, 0x148, 425000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71 | DIV_U71_INT, &tegra_vi_clk_ops),
+ PERIPH_CLK("3d", "3d", NULL, 24, 0x158, 520000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71 | DIV_U71_INT | DIV_U71_IDLE | PERIPH_MANUAL_RESET),
+ PERIPH_CLK("3d2", "3d2", NULL, 98, 0x3b0, 520000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71 | DIV_U71_INT | DIV_U71_IDLE | PERIPH_MANUAL_RESET),
+ PERIPH_CLK("2d", "2d", NULL, 21, 0x15c, 520000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71 | DIV_U71_INT | DIV_U71_IDLE),
+ PERIPH_CLK("vi_sensor", "tegra_camera", "vi_sensor", 20, 0x1a8, 150000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71 | PERIPH_NO_RESET),
+ PERIPH_CLK("epp", "epp", NULL, 19, 0x16c, 520000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71 | DIV_U71_INT),
+ PERIPH_CLK("mpe", "mpe", NULL, 60, 0x170, 520000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71 | DIV_U71_INT),
+ PERIPH_CLK("host1x", "host1x", NULL, 28, 0x180, 260000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71 | DIV_U71_INT),
+ 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_EX("dtv", "dtv", NULL, 79, 0x1dc, 250000000, mux_clk_m, 0, &tegra_dtv_clk_ops),
+ PERIPH_CLK("hdmi", "hdmi", NULL, 51, 0x18c, 148500000, mux_pllp_pllm_plld_plla_pllc_plld2_clkm, MUX | MUX8 | DIV_U71),
+ PERIPH_CLK("tvdac", "tvdac", NULL, 53, 0x194, 220000000, mux_pllp_plld_pllc_clkm, MUX | DIV_U71), /* requires min voltage */
+ PERIPH_CLK("disp1", "tegradc.0", NULL, 27, 0x138, 600000000, mux_pllp_pllm_plld_plla_pllc_plld2_clkm, MUX | MUX8),
+ PERIPH_CLK("disp2", "tegradc.1", NULL, 26, 0x13c, 600000000, mux_pllp_pllm_plld_plla_pllc_plld2_clkm, MUX | MUX8),
+ 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("dsia", "tegradc.0", "dsia", 48, 0, 500000000, mux_plld_out0, 0),
+ PERIPH_CLK_EX("dsib", "tegradc.1", "dsib", 82, 0xd0, 500000000, mux_plld_out0_plld2_out0, MUX | PLLD, &tegra_dsib_clk_ops),
+ PERIPH_CLK("csi", "tegra_camera", "csi", 52, 0, 102000000, 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("tsensor", "tegra-tsensor", NULL, 100, 0x3b8, 216000000, mux_pllp_pllc_clkm_clk32, MUX | DIV_U71),
+ PERIPH_CLK("actmon", "actmon", NULL, 119, 0x3e8, 216000000, mux_pllp_pllc_clk32_clkm, MUX | DIV_U71),
+ PERIPH_CLK("extern1", "extern1", NULL, 120, 0x3ec, 216000000, mux_plla_clk32_pllp_clkm_plle, MUX | MUX8 | DIV_U71),
+ PERIPH_CLK("extern2", "extern2", NULL, 121, 0x3f0, 216000000, mux_plla_clk32_pllp_clkm_plle, MUX | MUX8 | DIV_U71),
+ PERIPH_CLK("extern3", "extern3", NULL, 122, 0x3f4, 216000000, mux_plla_clk32_pllp_clkm_plle, MUX | MUX8 | DIV_U71),
+ PERIPH_CLK("i2cslow", "i2cslow", NULL, 81, 0x3fc, 26000000, mux_pllp_pllc_clk32_clkm, MUX | DIV_U71 | PERIPH_ON_APB),
+ PERIPH_CLK("pcie", "tegra-pcie", "pcie", 70, 0, 250000000, mux_clk_m, 0),
+ PERIPH_CLK("afi", "tegra-pcie", "afi", 72, 0, 250000000, mux_clk_m, 0),
+ PERIPH_CLK("se", "se", NULL, 127, 0x42c, 520000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | DIV_U71_INT),
+};
+
+#define CLK_DUPLICATE(_name, _dev, _con) \
+ { \
+ .name = _name, \
+ .lookup = { \
+ .dev_id = _dev, \
+ .con_id = _con, \
+ }, \
+ }
+
+/* Some clocks may be used by different drivers depending on the board
+ * configuration. List those here to register them twice in the clock lookup
+ * table under two names.
+ */
+struct clk_duplicate tegra_clk_duplicates[] = {
+ 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("dsib", "tegradc.0", "dsib"),
+ CLK_DUPLICATE("dsia", "tegradc.1", "dsia"),
+ 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("bsev", "tegra-avp", "bsev"),
+ CLK_DUPLICATE("bsev", "nvavp", "bsev"),
+ CLK_DUPLICATE("vde", "tegra-aes", "vde"),
+ CLK_DUPLICATE("bsea", "tegra-aes", "bsea"),
+ CLK_DUPLICATE("bsea", "nvavp", "bsea"),
+ CLK_DUPLICATE("cml1", "tegra_sata_cml", NULL),
+ CLK_DUPLICATE("cml0", "tegra_pcie", "cml"),
+ CLK_DUPLICATE("pciex", "tegra_pcie", "pciex"),
+ CLK_DUPLICATE("i2c1", "tegra-i2c-slave.0", NULL),
+ CLK_DUPLICATE("i2c2", "tegra-i2c-slave.1", NULL),
+ CLK_DUPLICATE("i2c3", "tegra-i2c-slave.2", NULL),
+ CLK_DUPLICATE("i2c4", "tegra-i2c-slave.3", NULL),
+ CLK_DUPLICATE("i2c5", "tegra-i2c-slave.4", NULL),
+ CLK_DUPLICATE("sbc1", "spi_slave_tegra.0", NULL),
+ CLK_DUPLICATE("sbc2", "spi_slave_tegra.1", NULL),
+ CLK_DUPLICATE("sbc3", "spi_slave_tegra.2", NULL),
+ CLK_DUPLICATE("sbc4", "spi_slave_tegra.3", NULL),
+ CLK_DUPLICATE("sbc5", "spi_slave_tegra.4", NULL),
+ CLK_DUPLICATE("sbc6", "spi_slave_tegra.5", NULL),
+ CLK_DUPLICATE("twd", "smp_twd", NULL),
+ CLK_DUPLICATE("vcp", "nvavp", "vcp"),
+};
+
+struct clk *tegra_ptr_clks[] = {
+ &tegra_clk_32k,
+ &tegra_clk_m,
+ &tegra_clk_m_div2,
+ &tegra_clk_m_div4,
+ &tegra_pll_ref,
+ &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_d2,
+ &tegra_pll_d2_out0,
+ &tegra_pll_u,
+ &tegra_pll_x,
+ &tegra_pll_x_out0,
+ &tegra_pll_e,
+ &tegra_clk_cclk_g,
+ &tegra_cml0_clk,
+ &tegra_cml1_clk,
+ &tegra_pciex_clk,
+ &tegra_clk_sclk,
+ &tegra_clk_blink,
+ &tegra30_clk_twd,
+};
+
+
+static void tegra30_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 tegra30_init_clocks(void)
+{
+ int i;
+ struct clk *c;
+
+ for (i = 0; i < ARRAY_SIZE(tegra_ptr_clks); i++)
+ tegra30_init_one_clock(tegra_ptr_clks[i]);
+
+ for (i = 0; i < ARRAY_SIZE(tegra_list_clks); i++)
+ tegra30_init_one_clock(&tegra_list_clks[i]);
+
+ for (i = 0; i < ARRAY_SIZE(tegra_clk_duplicates); i++) {
+ c = tegra_get_clock_by_name(tegra_clk_duplicates[i].name);
+ if (!c) {
+ pr_err("%s: Unknown duplicate clock %s\n", __func__,
+ tegra_clk_duplicates[i].name);
+ continue;
+ }
+
+ tegra_clk_duplicates[i].lookup.clk = c;
+ clkdev_add(&tegra_clk_duplicates[i].lookup);
+ }
+
+ for (i = 0; i < ARRAY_SIZE(tegra_sync_source_list); i++)
+ tegra30_init_one_clock(&tegra_sync_source_list[i]);
+ for (i = 0; i < ARRAY_SIZE(tegra_clk_audio_list); i++)
+ tegra30_init_one_clock(&tegra_clk_audio_list[i]);
+ for (i = 0; i < ARRAY_SIZE(tegra_clk_audio_2x_list); i++)
+ tegra30_init_one_clock(&tegra_clk_audio_2x_list[i]);
+
+ init_clk_out_mux();
+ for (i = 0; i < ARRAY_SIZE(tegra_clk_out_list); i++)
+ tegra30_init_one_clock(&tegra_clk_out_list[i]);
+
+}
diff --git a/arch/arm/plat-mxc/cpu.c b/arch/arm/plat-mxc/cpu.c
index f5b7e0fa237f..220dd6f93126 100644
--- a/arch/arm/plat-mxc/cpu.c
+++ b/arch/arm/plat-mxc/cpu.c
@@ -1,5 +1,6 @@
#include <linux/module.h>
+#include <linux/io.h>
#include <mach/hardware.h>
unsigned int __mxc_cpu_type;
@@ -18,3 +19,26 @@ void imx_print_silicon_rev(const char *cpu, int srev)
pr_info("CPU identified as %s, silicon rev %d.%d\n",
cpu, (srev >> 4) & 0xf, srev & 0xf);
}
+
+void __init imx_set_aips(void __iomem *base)
+{
+ unsigned int reg;
+/*
+ * Set all MPROTx to be non-bufferable, trusted for R/W,
+ * not forced to user-mode.
+ */
+ __raw_writel(0x77777777, base + 0x0);
+ __raw_writel(0x77777777, base + 0x4);
+
+/*
+ * Set all OPACRx to be non-bufferable, to not require
+ * supervisor privilege level for access, allow for
+ * write access and untrusted master access.
+ */
+ __raw_writel(0x0, base + 0x40);
+ __raw_writel(0x0, base + 0x44);
+ __raw_writel(0x0, base + 0x48);
+ __raw_writel(0x0, base + 0x4C);
+ reg = __raw_readl(base + 0x50) & 0x00FFFFFF;
+ __raw_writel(reg, base + 0x50);
+}
diff --git a/arch/arm/plat-mxc/include/mach/common.h b/arch/arm/plat-mxc/include/mach/common.h
index 1bf0df81bdc6..7c24e5ab7d50 100644
--- a/arch/arm/plat-mxc/include/mach/common.h
+++ b/arch/arm/plat-mxc/include/mach/common.h
@@ -75,6 +75,7 @@ extern void mxc_restart(char, const char *);
extern void mxc_arch_reset_init(void __iomem *);
extern int mx53_revision(void);
extern int mx53_display_revision(void);
+extern void imx_set_aips(void __iomem *);
enum mxc_cpu_pwr_mode {
WAIT_CLOCKED, /* wfi only */
@@ -84,6 +85,14 @@ enum mxc_cpu_pwr_mode {
STOP_POWER_OFF, /* STOP + SRPG */
};
+enum mx3_cpu_pwr_mode {
+ MX3_RUN,
+ MX3_WAIT,
+ MX3_DOZE,
+ MX3_SLEEP,
+};
+
+extern void mx3_cpu_lp_set(enum mx3_cpu_pwr_mode mode);
extern void mx5_cpu_lp_set(enum mxc_cpu_pwr_mode mode);
extern void imx_print_silicon_rev(const char *cpu, int srev);
diff --git a/arch/arm/plat-omap/include/plat/cpu.h b/arch/arm/plat-omap/include/plat/cpu.h
index 4f18eaed4511..dc6a86bf2172 100644
--- a/arch/arm/plat-omap/include/plat/cpu.h
+++ b/arch/arm/plat-omap/include/plat/cpu.h
@@ -449,7 +449,12 @@ IS_OMAP_TYPE(3517, 0x3517)
#define OMAP447X_CLASS 0x44700044
#define OMAP4470_REV_ES1_0 (OMAP447X_CLASS | (0x10 << 8))
-void omap2_check_revision(void);
+void omap2xxx_check_revision(void);
+void omap3xxx_check_revision(void);
+void omap4xxx_check_revision(void);
+void omap3xxx_check_features(void);
+void ti81xx_check_features(void);
+void omap4xxx_check_features(void);
/*
* Runtime detection of OMAP3 features
diff --git a/arch/arm/plat-s5p/Kconfig b/arch/arm/plat-s5p/Kconfig
index 8167ce66188c..7a308699f816 100644
--- a/arch/arm/plat-s5p/Kconfig
+++ b/arch/arm/plat-s5p/Kconfig
@@ -80,6 +80,16 @@ config S5P_DEV_FIMC3
help
Compile in platform device definitions for FIMC controller 3
+config S5P_DEV_JPEG
+ bool
+ help
+ Compile in platform device definitions for JPEG codec
+
+config S5P_DEV_G2D
+ bool
+ help
+ Compile in platform device definitions for G2D device
+
config S5P_DEV_FIMD0
bool
help
diff --git a/arch/arm/plat-s5p/sleep.S b/arch/arm/plat-s5p/sleep.S
index 0fd591bfc9fd..006bd01eda02 100644
--- a/arch/arm/plat-s5p/sleep.S
+++ b/arch/arm/plat-s5p/sleep.S
@@ -23,9 +23,18 @@
*/
#include <linux/linkage.h>
-#include <asm/assembler.h>
+#include <asm/asm-offsets.h>
+#include <asm/hardware/cache-l2x0.h>
- .text
+/*
+ * The following code is located into the .data section. This is to
+ * allow l2x0_regs_phys to be accessed with a relative load while we
+ * can't rely on any MMU translation. We could have put l2x0_regs_phys
+ * in the .text section as well, but some setups might insist on it to
+ * be truly read-only. (Reference from: arch/arm/kernel/sleep.S)
+ */
+ .data
+ .align
/*
* sleep magic, to allow the bootloader to check for an valid
@@ -39,11 +48,34 @@
* s3c_cpu_resume
*
* resume code entry for bootloader to call
- *
- * we must put this code here in the data segment as we have no
- * other way of restoring the stack pointer after sleep, and we
- * must not write to the code segment (code is read-only)
*/
ENTRY(s3c_cpu_resume)
+#ifdef CONFIG_CACHE_L2X0
+ adr r0, l2x0_regs_phys
+ ldr r0, [r0]
+ ldr r1, [r0, #L2X0_R_PHY_BASE]
+ ldr r2, [r1, #L2X0_CTRL]
+ tst r2, #0x1
+ bne resume_l2on
+ ldr r2, [r0, #L2X0_R_AUX_CTRL]
+ str r2, [r1, #L2X0_AUX_CTRL]
+ ldr r2, [r0, #L2X0_R_TAG_LATENCY]
+ str r2, [r1, #L2X0_TAG_LATENCY_CTRL]
+ ldr r2, [r0, #L2X0_R_DATA_LATENCY]
+ str r2, [r1, #L2X0_DATA_LATENCY_CTRL]
+ ldr r2, [r0, #L2X0_R_PREFETCH_CTRL]
+ str r2, [r1, #L2X0_PREFETCH_CTRL]
+ ldr r2, [r0, #L2X0_R_PWR_CTRL]
+ str r2, [r1, #L2X0_POWER_CTRL]
+ mov r2, #1
+ str r2, [r1, #L2X0_CTRL]
+resume_l2on:
+#endif
b cpu_resume
+ENDPROC(s3c_cpu_resume)
+#ifdef CONFIG_CACHE_L2X0
+ .globl l2x0_regs_phys
+l2x0_regs_phys:
+ .long 0
+#endif
diff --git a/arch/arm/plat-samsung/clock.c b/arch/arm/plat-samsung/clock.c
index 10f71179071f..65c5eca475e7 100644
--- a/arch/arm/plat-samsung/clock.c
+++ b/arch/arm/plat-samsung/clock.c
@@ -84,31 +84,35 @@ static int clk_null_enable(struct clk *clk, int enable)
int clk_enable(struct clk *clk)
{
+ unsigned long flags;
+
if (IS_ERR(clk) || clk == NULL)
return -EINVAL;
clk_enable(clk->parent);
- spin_lock(&clocks_lock);
+ spin_lock_irqsave(&clocks_lock, flags);
if ((clk->usage++) == 0)
(clk->enable)(clk, 1);
- spin_unlock(&clocks_lock);
+ spin_unlock_irqrestore(&clocks_lock, flags);
return 0;
}
void clk_disable(struct clk *clk)
{
+ unsigned long flags;
+
if (IS_ERR(clk) || clk == NULL)
return;
- spin_lock(&clocks_lock);
+ spin_lock_irqsave(&clocks_lock, flags);
if ((--clk->usage) == 0)
(clk->enable)(clk, 0);
- spin_unlock(&clocks_lock);
+ spin_unlock_irqrestore(&clocks_lock, flags);
clk_disable(clk->parent);
}
diff --git a/arch/arm/plat-samsung/dev-backlight.c b/arch/arm/plat-samsung/dev-backlight.c
index a976c023b286..5f197dcaf10c 100644
--- a/arch/arm/plat-samsung/dev-backlight.c
+++ b/arch/arm/plat-samsung/dev-backlight.c
@@ -77,7 +77,7 @@ static struct platform_device samsung_dfl_bl_device __initdata = {
* @gpio_info: structure containing GPIO info for PWM timer
* @bl_data: structure containing Backlight control data
*/
-void samsung_bl_set(struct samsung_bl_gpio_info *gpio_info,
+void __init samsung_bl_set(struct samsung_bl_gpio_info *gpio_info,
struct platform_pwm_backlight_data *bl_data)
{
int ret = 0;
@@ -115,6 +115,8 @@ void samsung_bl_set(struct samsung_bl_gpio_info *gpio_info,
samsung_bl_data->init = bl_data->init;
if (bl_data->notify)
samsung_bl_data->notify = bl_data->notify;
+ if (bl_data->notify_after)
+ samsung_bl_data->notify_after = bl_data->notify_after;
if (bl_data->exit)
samsung_bl_data->exit = bl_data->exit;
if (bl_data->check_fb)
diff --git a/arch/arm/plat-samsung/devs.c b/arch/arm/plat-samsung/devs.c
index d322ba883f2f..8b928f9bc1c3 100644
--- a/arch/arm/plat-samsung/devs.c
+++ b/arch/arm/plat-samsung/devs.c
@@ -57,6 +57,7 @@
#include <plat/sdhci.h>
#include <plat/ts.h>
#include <plat/udc.h>
+#include <plat/udc-hs.h>
#include <plat/usb-control.h>
#include <plat/usb-phy.h>
#include <plat/regs-iic.h>
@@ -267,6 +268,52 @@ struct platform_device s5p_device_fimc3 = {
};
#endif /* CONFIG_S5P_DEV_FIMC3 */
+/* G2D */
+
+#ifdef CONFIG_S5P_DEV_G2D
+static struct resource s5p_g2d_resource[] = {
+ [0] = {
+ .start = S5P_PA_G2D,
+ .end = S5P_PA_G2D + SZ_4K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = IRQ_2D,
+ .end = IRQ_2D,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+struct platform_device s5p_device_g2d = {
+ .name = "s5p-g2d",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(s5p_g2d_resource),
+ .resource = s5p_g2d_resource,
+ .dev = {
+ .dma_mask = &samsung_device_dma_mask,
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ },
+};
+#endif /* CONFIG_S5P_DEV_G2D */
+
+#ifdef CONFIG_S5P_DEV_JPEG
+static struct resource s5p_jpeg_resource[] = {
+ [0] = DEFINE_RES_MEM(S5P_PA_JPEG, SZ_4K),
+ [1] = DEFINE_RES_IRQ(IRQ_JPEG),
+};
+
+struct platform_device s5p_device_jpeg = {
+ .name = "s5p-jpeg",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(s5p_jpeg_resource),
+ .resource = s5p_jpeg_resource,
+ .dev = {
+ .dma_mask = &samsung_device_dma_mask,
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ },
+};
+#endif /* CONFIG_S5P_DEV_JPEG */
+
/* FIMD0 */
#ifdef CONFIG_S5P_DEV_FIMD0
@@ -758,7 +805,7 @@ struct platform_device s3c_device_cfcon = {
.resource = s3c_cfcon_resource,
};
-void s3c_ide_set_platdata(struct s3c_ide_platdata *pdata)
+void __init s3c_ide_set_platdata(struct s3c_ide_platdata *pdata)
{
s3c_set_platdata(pdata, sizeof(struct s3c_ide_platdata),
&s3c_device_cfcon);
@@ -876,7 +923,7 @@ struct platform_device s5p_device_mfc_r = {
#ifdef CONFIG_S5P_DEV_CSIS0
static struct resource s5p_mipi_csis0_resource[] = {
- [0] = DEFINE_RES_MEM(S5P_PA_MIPI_CSIS0, SZ_4K),
+ [0] = DEFINE_RES_MEM(S5P_PA_MIPI_CSIS0, SZ_16K),
[1] = DEFINE_RES_IRQ(IRQ_MIPI_CSIS0),
};
@@ -890,7 +937,7 @@ struct platform_device s5p_device_mipi_csis0 = {
#ifdef CONFIG_S5P_DEV_CSIS1
static struct resource s5p_mipi_csis1_resource[] = {
- [0] = DEFINE_RES_MEM(S5P_PA_MIPI_CSIS1, SZ_4K),
+ [0] = DEFINE_RES_MEM(S5P_PA_MIPI_CSIS1, SZ_16K),
[1] = DEFINE_RES_IRQ(IRQ_MIPI_CSIS1),
};
@@ -1038,7 +1085,7 @@ struct platform_device s3c64xx_device_onenand1 = {
.resource = s3c64xx_onenand1_resources,
};
-void s3c64xx_onenand1_set_platdata(struct onenand_platform_data *pdata)
+void __init s3c64xx_onenand1_set_platdata(struct onenand_platform_data *pdata)
{
s3c_set_platdata(pdata, sizeof(struct onenand_platform_data),
&s3c64xx_device_onenand1);
@@ -1412,6 +1459,19 @@ struct platform_device s3c_device_usb_hsotg = {
.coherent_dma_mask = DMA_BIT_MASK(32),
},
};
+
+void __init s3c_hsotg_set_platdata(struct s3c_hsotg_plat *pd)
+{
+ struct s3c_hsotg_plat *npd;
+
+ npd = s3c_set_platdata(pd, sizeof(struct s3c_hsotg_plat),
+ &s3c_device_usb_hsotg);
+
+ if (!npd->phy_init)
+ npd->phy_init = s5p_usb_phy_init;
+ if (!npd->phy_exit)
+ npd->phy_exit = s5p_usb_phy_exit;
+}
#endif /* CONFIG_S3C_DEV_USB_HSOTG */
/* USB High Spped 2.0 Device (Gadget) */
diff --git a/arch/arm/plat-samsung/include/plat/devs.h b/arch/arm/plat-samsung/include/plat/devs.h
index 4214ea0ff8fe..5e7972de3ed5 100644
--- a/arch/arm/plat-samsung/include/plat/devs.h
+++ b/arch/arm/plat-samsung/include/plat/devs.h
@@ -79,6 +79,8 @@ extern struct platform_device s5p_device_fimc1;
extern struct platform_device s5p_device_fimc2;
extern struct platform_device s5p_device_fimc3;
extern struct platform_device s5p_device_fimc_md;
+extern struct platform_device s5p_device_jpeg;
+extern struct platform_device s5p_device_g2d;
extern struct platform_device s5p_device_fimd0;
extern struct platform_device s5p_device_hdmi;
extern struct platform_device s5p_device_i2c_hdmiphy;
diff --git a/arch/arm/plat-samsung/include/plat/regs-usb-hsotg-phy.h b/arch/arm/plat-samsung/include/plat/regs-usb-hsotg-phy.h
index a111ad871833..fcf279662067 100644
--- a/arch/arm/plat-samsung/include/plat/regs-usb-hsotg-phy.h
+++ b/arch/arm/plat-samsung/include/plat/regs-usb-hsotg-phy.h
@@ -25,8 +25,9 @@
#define S3C_HSOTG_PHYREG(x) ((x) + S3C_VA_USB_HSPHY)
#define S3C_PHYPWR S3C_HSOTG_PHYREG(0x00)
-#define SRC_PHYPWR_OTG_DISABLE (1 << 4)
-#define SRC_PHYPWR_ANALOG_POWERDOWN (1 << 3)
+#define S3C_PHYPWR_NORMAL_MASK (0x19 << 0)
+#define S3C_PHYPWR_OTG_DISABLE (1 << 4)
+#define S3C_PHYPWR_ANALOG_POWERDOWN (1 << 3)
#define SRC_PHYPWR_FORCE_SUSPEND (1 << 1)
#define S3C_PHYCLK S3C_HSOTG_PHYREG(0x04)
@@ -42,7 +43,7 @@
#define S3C_RSTCON S3C_HSOTG_PHYREG(0x08)
#define S3C_RSTCON_PHYCLK (1 << 2)
-#define S3C_RSTCON_HCLK (1 << 2)
+#define S3C_RSTCON_HCLK (1 << 1)
#define S3C_RSTCON_PHY (1 << 0)
#define S3C_PHYTUNE S3C_HSOTG_PHYREG(0x20)
diff --git a/arch/arm/plat-samsung/include/plat/udc-hs.h b/arch/arm/plat-samsung/include/plat/udc-hs.h
index a22a4f2eea94..c9e3667cb2b1 100644
--- a/arch/arm/plat-samsung/include/plat/udc-hs.h
+++ b/arch/arm/plat-samsung/include/plat/udc-hs.h
@@ -26,4 +26,9 @@ enum s3c_hsotg_dmamode {
struct s3c_hsotg_plat {
enum s3c_hsotg_dmamode dma;
unsigned int is_osc : 1;
+
+ int (*phy_init)(struct platform_device *pdev, int type);
+ int (*phy_exit)(struct platform_device *pdev, int type);
};
+
+extern void s3c_hsotg_set_platdata(struct s3c_hsotg_plat *pd);