Merge branch 'samsung/exynos5' into next/soc2
Arnd Bergmann [Thu, 15 Mar 2012 21:07:57 +0000 (21:07 +0000)]
217 files changed:
Documentation/ABI/testing/sysfs-devices-soc [new file with mode: 0644]
Documentation/devicetree/bindings/arm/tegra/emc.txt [new file with mode: 0644]
Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-pmc.txt [new file with mode: 0644]
Documentation/devicetree/bindings/dma/tegra20-apbdma.txt [new file with mode: 0644]
Documentation/devicetree/bindings/gpio/gpio_nvidia.txt
Documentation/dynamic-debug-howto.txt
Documentation/filesystems/debugfs.txt
arch/arm/Kconfig
arch/arm/boot/dts/tegra-cardhu.dts
arch/arm/boot/dts/tegra-harmony.dts
arch/arm/boot/dts/tegra-paz00.dts
arch/arm/boot/dts/tegra-seaboard.dts
arch/arm/boot/dts/tegra-trimslice.dts
arch/arm/boot/dts/tegra-ventana.dts
arch/arm/boot/dts/tegra20.dtsi
arch/arm/boot/dts/tegra30.dtsi
arch/arm/include/asm/hardware/entry-macro-iomd.S
arch/arm/kernel/entry-armv.S
arch/arm/kernel/entry-common.S
arch/arm/mach-at91/include/mach/entry-macro.S
arch/arm/mach-bcmring/include/mach/entry-macro.S
arch/arm/mach-clps711x/include/mach/entry-macro.S
arch/arm/mach-cns3xxx/include/mach/entry-macro.S [deleted file]
arch/arm/mach-davinci/include/mach/entry-macro.S
arch/arm/mach-dove/include/mach/entry-macro.S
arch/arm/mach-ebsa110/include/mach/entry-macro.S
arch/arm/mach-ep93xx/include/mach/entry-macro.S [deleted file]
arch/arm/mach-exynos/include/mach/entry-macro.S [deleted file]
arch/arm/mach-footbridge/include/mach/entry-macro.S
arch/arm/mach-gemini/include/mach/entry-macro.S
arch/arm/mach-h720x/include/mach/entry-macro.S
arch/arm/mach-highbank/include/mach/entry-macro.S [deleted file]
arch/arm/mach-integrator/include/mach/entry-macro.S
arch/arm/mach-iop13xx/include/mach/entry-macro.S
arch/arm/mach-iop32x/include/mach/entry-macro.S
arch/arm/mach-iop33x/include/mach/entry-macro.S
arch/arm/mach-ixp2000/include/mach/entry-macro.S
arch/arm/mach-ixp23xx/include/mach/entry-macro.S
arch/arm/mach-ixp4xx/include/mach/entry-macro.S
arch/arm/mach-kirkwood/include/mach/entry-macro.S
arch/arm/mach-ks8695/include/mach/entry-macro.S
arch/arm/mach-lpc32xx/include/mach/entry-macro.S
arch/arm/mach-mmp/include/mach/entry-macro.S
arch/arm/mach-msm/include/mach/entry-macro.S
arch/arm/mach-mv78xx0/include/mach/entry-macro.S
arch/arm/mach-mxs/include/mach/entry-macro.S
arch/arm/mach-netx/include/mach/entry-macro.S [deleted file]
arch/arm/mach-nomadik/include/mach/entry-macro.S [deleted file]
arch/arm/mach-omap1/include/mach/entry-macro.S
arch/arm/mach-omap2/include/mach/entry-macro.S [deleted file]
arch/arm/mach-orion5x/include/mach/entry-macro.S
arch/arm/mach-picoxcell/include/mach/entry-macro.S [deleted file]
arch/arm/mach-pnx4008/include/mach/entry-macro.S
arch/arm/mach-prima2/include/mach/entry-macro.S
arch/arm/mach-pxa/include/mach/entry-macro.S [deleted file]
arch/arm/mach-realview/include/mach/entry-macro.S [deleted file]
arch/arm/mach-rpc/Makefile
arch/arm/mach-rpc/fiq.S [new file with mode: 0644]
arch/arm/mach-rpc/include/mach/entry-macro.S
arch/arm/mach-rpc/irq.c
arch/arm/mach-s3c2410/include/mach/entry-macro.S
arch/arm/mach-s3c64xx/include/mach/entry-macro.S [deleted file]
arch/arm/mach-s5p64x0/include/mach/entry-macro.S [deleted file]
arch/arm/mach-s5pc100/include/mach/entry-macro.S
arch/arm/mach-s5pv210/include/mach/entry-macro.S [deleted file]
arch/arm/mach-sa1100/include/mach/entry-macro.S
arch/arm/mach-shark/include/mach/entry-macro.S
arch/arm/mach-shmobile/include/mach/entry-macro.S [deleted file]
arch/arm/mach-spear3xx/include/mach/entry-macro.S [deleted file]
arch/arm/mach-spear6xx/include/mach/entry-macro.S [deleted file]
arch/arm/mach-tegra/Makefile
arch/arm/mach-tegra/apbio.c [new file with mode: 0644]
arch/arm/mach-tegra/apbio.h [new file with mode: 0644]
arch/arm/mach-tegra/board-dt-tegra30.c
arch/arm/mach-tegra/board-harmony-power.c
arch/arm/mach-tegra/board-harmony.c
arch/arm/mach-tegra/board-seaboard.c
arch/arm/mach-tegra/clock.c
arch/arm/mach-tegra/clock.h
arch/arm/mach-tegra/common.c
arch/arm/mach-tegra/cpuidle.c [new file with mode: 0644]
arch/arm/mach-tegra/dma.c
arch/arm/mach-tegra/flowctrl.c [new file with mode: 0644]
arch/arm/mach-tegra/flowctrl.h [new file with mode: 0644]
arch/arm/mach-tegra/fuse.c
arch/arm/mach-tegra/fuse.h
arch/arm/mach-tegra/headsmp.S
arch/arm/mach-tegra/include/mach/clk.h
arch/arm/mach-tegra/include/mach/debug-macro.S
arch/arm/mach-tegra/include/mach/gpio-tegra.h
arch/arm/mach-tegra/include/mach/iomap.h
arch/arm/mach-tegra/include/mach/irammap.h [new file with mode: 0644]
arch/arm/mach-tegra/include/mach/irqs.h
arch/arm/mach-tegra/include/mach/powergate.h
arch/arm/mach-tegra/include/mach/uncompress.h
arch/arm/mach-tegra/irq.c
arch/arm/mach-tegra/platsmp.c
arch/arm/mach-tegra/pmc.c [new file with mode: 0644]
arch/arm/mach-tegra/pmc.h [new file with mode: 0644]
arch/arm/mach-tegra/powergate.c
arch/arm/mach-tegra/reset.c [new file with mode: 0644]
arch/arm/mach-tegra/reset.h [new file with mode: 0644]
arch/arm/mach-tegra/sleep.S [new file with mode: 0644]
arch/arm/mach-tegra/tegra2_clocks.c
arch/arm/mach-tegra/tegra2_emc.c
arch/arm/mach-tegra/tegra2_emc.h
arch/arm/mach-tegra/tegra30_clocks.c [new file with mode: 0644]
arch/arm/mach-u300/include/mach/entry-macro.S [deleted file]
arch/arm/mach-ux500/Kconfig
arch/arm/mach-ux500/board-mop500-sdi.c
arch/arm/mach-ux500/board-mop500.c
arch/arm/mach-ux500/board-mop500.h
arch/arm/mach-ux500/board-u5500-sdi.c
arch/arm/mach-ux500/board-u5500.c
arch/arm/mach-ux500/cpu-db5500.c
arch/arm/mach-ux500/cpu-db8500.c
arch/arm/mach-ux500/cpu.c
arch/arm/mach-ux500/devices-common.c
arch/arm/mach-ux500/devices-common.h
arch/arm/mach-ux500/devices-db5500.h
arch/arm/mach-ux500/devices-db8500.h
arch/arm/mach-ux500/dma-db5500.c
arch/arm/mach-ux500/include/mach/db8500-regs.h
arch/arm/mach-ux500/include/mach/entry-macro.S [deleted file]
arch/arm/mach-ux500/include/mach/setup.h
arch/arm/mach-ux500/include/mach/usb.h
arch/arm/mach-ux500/usb.c
arch/arm/mach-versatile/include/mach/entry-macro.S [deleted file]
arch/arm/mach-vexpress/include/mach/entry-macro.S [deleted file]
arch/arm/mach-vt8500/include/mach/entry-macro.S
arch/arm/mach-w90x900/include/mach/entry-macro.S
arch/arm/mach-zynq/include/mach/entry-macro.S [deleted file]
arch/arm/plat-mxc/include/mach/entry-macro.S [deleted file]
arch/x86/Kconfig
arch/x86/crypto/aesni-intel_glue.c
arch/x86/crypto/crc32c-intel.c
arch/x86/crypto/ghash-clmulni-intel_glue.c
arch/x86/include/asm/cpu_device_id.h [new file with mode: 0644]
arch/x86/include/asm/cpufeature.h
arch/x86/kernel/cpu/Makefile
arch/x86/kernel/cpu/match.c [new file with mode: 0644]
arch/x86/kernel/cpu/scattered.c
arch/x86/kernel/microcode_core.c
drivers/acpi/processor_driver.c
drivers/acpi/processor_perflib.c
drivers/base/Kconfig
drivers/base/Makefile
drivers/base/bus.c
drivers/base/cpu.c
drivers/base/driver.c
drivers/base/soc.c [new file with mode: 0644]
drivers/cpufreq/cpufreq-nforce2.c
drivers/cpufreq/e_powersaver.c
drivers/cpufreq/elanfreq.c
drivers/cpufreq/gx-suspmod.c
drivers/cpufreq/longhaul.c
drivers/cpufreq/longrun.c
drivers/cpufreq/p4-clockmod.c
drivers/cpufreq/powernow-k6.c
drivers/cpufreq/powernow-k7.c
drivers/cpufreq/powernow-k8.c
drivers/cpufreq/sc520_freq.c
drivers/cpufreq/speedstep-centrino.c
drivers/cpufreq/speedstep-ich.c
drivers/cpufreq/speedstep-lib.c
drivers/cpufreq/speedstep-smi.c
drivers/crypto/padlock-aes.c
drivers/crypto/padlock-sha.c
drivers/gpio/gpio-tegra.c
drivers/hid/hid-core.c
drivers/hv/channel_mgmt.c
drivers/hv/hv.c
drivers/hv/hv_kvp.c
drivers/hv/hv_kvp.h [deleted file]
drivers/hv/hv_util.c
drivers/hv/hyperv_vmbus.h
drivers/hwmon/coretemp.c
drivers/hwmon/via-cputemp.c
drivers/idle/intel_idle.c
drivers/input/gameport/gameport.c
drivers/input/serio/serio.c
drivers/media/video/cx18/cx18-alsa-main.c
drivers/media/video/ivtv/ivtvfb.c
drivers/media/video/s5p-fimc/fimc-mdevice.c
drivers/media/video/s5p-tv/mixer_video.c
drivers/net/phy/phy_device.c
drivers/pci/pci-driver.c
drivers/pci/xen-pcifront.c
drivers/pcmcia/ds.c
drivers/s390/cio/ccwgroup.c
drivers/s390/cio/device.c
drivers/s390/net/smsgiucv_app.c
drivers/ssb/main.c
drivers/usb/core/driver.c
drivers/usb/dwc3/dwc3-pci.c
drivers/w1/masters/w1-gpio.c
fs/debugfs/inode.c
fs/sysfs/dir.c
fs/sysfs/inode.c
fs/sysfs/mount.c
fs/sysfs/sysfs.h
include/acpi/processor.h
include/linux/connector.h
include/linux/cpu.h
include/linux/device.h
include/linux/dynamic_debug.h
include/linux/hyperv.h
include/linux/mod_devicetable.h
include/linux/netdevice.h
include/linux/pci.h
include/linux/platform_data/tegra_emc.h [moved from arch/arm/mach-tegra/include/mach/entry-macro.S with 56% similarity]
include/linux/printk.h
include/linux/sys_soc.h [new file with mode: 0644]
lib/dma-debug.c
lib/dynamic_debug.c
scripts/mod/file2alias.c
tools/hv/hv_kvp_daemon.c

diff --git a/Documentation/ABI/testing/sysfs-devices-soc b/Documentation/ABI/testing/sysfs-devices-soc
new file mode 100644 (file)
index 0000000..6d9cc25
--- /dev/null
@@ -0,0 +1,58 @@
+What:          /sys/devices/socX
+Date:          January 2012
+contact:       Lee Jones <lee.jones@linaro.org>
+Description:
+               The /sys/devices/ directory contains a sub-directory for each
+               System-on-Chip (SoC) device on a running platform. Information
+               regarding each SoC can be obtained by reading sysfs files. This
+               functionality is only available if implemented by the platform.
+
+               The directory created for each SoC will also house information
+               about devices which are commonly contained in /sys/devices/platform.
+               It has been agreed that if an SoC device exists, its supported
+               devices would be better suited to appear as children of that SoC.
+
+What:          /sys/devices/socX/machine
+Date:          January 2012
+contact:       Lee Jones <lee.jones@linaro.org>
+Description:
+               Read-only attribute common to all SoCs. Contains the SoC machine
+               name (e.g. Ux500).
+
+What:          /sys/devices/socX/family
+Date:          January 2012
+contact:       Lee Jones <lee.jones@linaro.org>
+Description:
+               Read-only attribute common to all SoCs. Contains SoC family name
+               (e.g. DB8500).
+
+What:          /sys/devices/socX/soc_id
+Date:          January 2012
+contact:       Lee Jones <lee.jones@linaro.org>
+Description:
+               Read-only attribute supported by most SoCs. In the case of
+               ST-Ericsson's chips this contains the SoC serial number.
+
+What:          /sys/devices/socX/revision
+Date:          January 2012
+contact:       Lee Jones <lee.jones@linaro.org>
+Description:
+               Read-only attribute supported by most SoCs. Contains the SoC's
+               manufacturing revision number.
+
+What:          /sys/devices/socX/process
+Date:          January 2012
+contact:       Lee Jones <lee.jones@linaro.org>
+Description:
+               Read-only attribute supported ST-Ericsson's silicon. Contains the
+               the process by which the silicon chip was manufactured.
+
+What:          /sys/bus/soc
+Date:          January 2012
+contact:       Lee Jones <lee.jones@linaro.org>
+Description:
+               The /sys/bus/soc/ directory contains the usual sub-folders
+               expected under most buses. /sys/bus/soc/devices is of particular
+               interest, as it contains a symlink for each SoC device found on
+               the system. Each symlink points back into the aforementioned
+               /sys/devices/socX devices.
diff --git a/Documentation/devicetree/bindings/arm/tegra/emc.txt b/Documentation/devicetree/bindings/arm/tegra/emc.txt
new file mode 100644 (file)
index 0000000..09335f8
--- /dev/null
@@ -0,0 +1,100 @@
+Embedded Memory Controller
+
+Properties:
+- name : Should be emc
+- #address-cells : Should be 1
+- #size-cells : Should be 0
+- compatible : Should contain "nvidia,tegra20-emc".
+- reg : Offset and length of the register set for the device
+- nvidia,use-ram-code : If present, the sub-nodes will be addressed
+  and chosen using the ramcode board selector. If omitted, only one
+  set of tables can be present and said tables will be used
+  irrespective of ram-code configuration.
+
+Child device nodes describe the memory settings for different configurations and clock rates.
+
+Example:
+
+       emc@7000f400 {
+               #address-cells = < 1 >;
+               #size-cells = < 0 >;
+               compatible = "nvidia,tegra20-emc";
+               reg = <0x7000f4000 0x200>;
+       }
+
+
+Embedded Memory Controller ram-code table
+
+If the emc node has the nvidia,use-ram-code property present, then the
+next level of nodes below the emc table are used to specify which settings
+apply for which ram-code settings.
+
+If the emc node lacks the nvidia,use-ram-code property, this level is omitted
+and the tables are stored directly under the emc node (see below).
+
+Properties:
+
+- name : Should be emc-tables
+- nvidia,ram-code : the binary representation of the ram-code board strappings
+  for which this node (and children) are valid.
+
+
+
+Embedded Memory Controller configuration table
+
+This is a table containing the EMC register settings for the various
+operating speeds of the memory controller. They are always located as
+subnodes of the emc controller node.
+
+There are two ways of specifying which tables to use:
+
+* The simplest is if there is just one set of tables in the device tree,
+  and they will always be used (based on which frequency is used).
+  This is the preferred method, especially when firmware can fill in
+  this information based on the specific system information and just
+  pass it on to the kernel.
+
+* The slightly more complex one is when more than one memory configuration
+  might exist on the system.  The Tegra20 platform handles this during
+  early boot by selecting one out of possible 4 memory settings based
+  on a 2-pin "ram code" bootstrap setting on the board. The values of
+  these strappings can be read through a register in the SoC, and thus
+  used to select which tables to use.
+
+Properties:
+- name : Should be emc-table
+- compatible : Should contain "nvidia,tegra20-emc-table".
+- reg : either an opaque enumerator to tell different tables apart, or
+  the valid frequency for which the table should be used (in kHz).
+- clock-frequency : the clock frequency for the EMC at which this
+  table should be used (in kHz).
+- nvidia,emc-registers : a 46 word array of EMC registers to be programmed
+  for operation at the 'clock-frequency' setting.
+  The order and contents of the registers are:
+    RC, RFC, RAS, RP, R2W, W2R, R2P, W2P, RD_RCD, WR_RCD, RRD, REXT,
+    WDV, QUSE, QRST, QSAFE, RDV, REFRESH, BURST_REFRESH_NUM, PDEX2WR,
+    PDEX2RD, PCHG2PDEN, ACT2PDEN, AR2PDEN, RW2PDEN, TXSR, TCKE, TFAW,
+    TRPAB, TCLKSTABLE, TCLKSTOP, TREFBW, QUSE_EXTRA, FBIO_CFG6, ODT_WRITE,
+    ODT_READ, FBIO_CFG5, CFG_DIG_DLL, DLL_XFORM_DQS, DLL_XFORM_QUSE,
+    ZCAL_REF_CNT, ZCAL_WAIT_CNT, AUTO_CAL_INTERVAL, CFG_CLKTRIM_0,
+    CFG_CLKTRIM_1, CFG_CLKTRIM_2
+
+               emc-table@166000 {
+                       reg = <166000>;
+                       compatible = "nvidia,tegra20-emc-table";
+                       clock-frequency = < 166000 >;
+                       nvidia,emc-registers = < 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+                                                0 0 0 0 0 0 0 0 0 0 0 0 0 0
+                                                0 0 0 0 0 0 0 0 0 0 0 0 0 0
+                                                0 0 0 0 >;
+               };
+
+               emc-table@333000 {
+                       reg = <333000>;
+                       compatible = "nvidia,tegra20-emc-table";
+                       clock-frequency = < 333000 >;
+                       nvidia,emc-registers = < 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+                                                0 0 0 0 0 0 0 0 0 0 0 0 0 0
+                                                0 0 0 0 0 0 0 0 0 0 0 0 0 0
+                                                0 0 0 0 >;
+               };
diff --git a/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-pmc.txt b/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-pmc.txt
new file mode 100644 (file)
index 0000000..b5846e2
--- /dev/null
@@ -0,0 +1,19 @@
+NVIDIA Tegra Power Management Controller (PMC)
+
+Properties:
+- name : Should be pmc
+- compatible : Should contain "nvidia,tegra<chip>-pmc".
+- reg : Offset and length of the register set for the device
+- nvidia,invert-interrupt : If present, inverts the PMU interrupt signal.
+  The PMU is an external Power Management Unit, whose interrupt output
+  signal is fed into the PMC. This signal is optionally inverted, and then
+  fed into the ARM GIC. The PMC is not involved in the detection or
+  handling of this interrupt signal, merely its inversion.
+
+Example:
+
+pmc@7000f400 {
+       compatible = "nvidia,tegra20-pmc";
+       reg = <0x7000e400 0x400>;
+       nvidia,invert-interrupt;
+};
diff --git a/Documentation/devicetree/bindings/dma/tegra20-apbdma.txt b/Documentation/devicetree/bindings/dma/tegra20-apbdma.txt
new file mode 100644 (file)
index 0000000..90fa7da
--- /dev/null
@@ -0,0 +1,30 @@
+* NVIDIA Tegra APB DMA controller
+
+Required properties:
+- compatible: Should be "nvidia,<chip>-apbdma"
+- reg: Should contain DMA registers location and length. This shuld include
+  all of the per-channel registers.
+- interrupts: Should contain all of the per-channel DMA interrupts.
+
+Examples:
+
+apbdma: dma@6000a000 {
+       compatible = "nvidia,tegra20-apbdma";
+       reg = <0x6000a000 0x1200>;
+       interrupts = < 0 136 0x04
+                      0 137 0x04
+                      0 138 0x04
+                      0 139 0x04
+                      0 140 0x04
+                      0 141 0x04
+                      0 142 0x04
+                      0 143 0x04
+                      0 144 0x04
+                      0 145 0x04
+                      0 146 0x04
+                      0 147 0x04
+                      0 148 0x04
+                      0 149 0x04
+                      0 150 0x04
+                      0 151 0x04 >;
+};
index eb4b530..023c952 100644 (file)
@@ -1,8 +1,40 @@
-NVIDIA Tegra 2 GPIO controller
+NVIDIA Tegra GPIO controller
 
 Required properties:
-- compatible : "nvidia,tegra20-gpio"
+- compatible : "nvidia,tegra<chip>-gpio"
+- reg : Physical base address and length of the controller's registers.
+- interrupts : The interrupt outputs from the controller. For Tegra20,
+  there should be 7 interrupts specified, and for Tegra30, there should
+  be 8 interrupts specified.
 - #gpio-cells : Should be two. The first cell is the pin number and the
   second cell is used to specify optional parameters:
   - bit 0 specifies polarity (0 for normal, 1 for inverted)
 - gpio-controller : Marks the device node as a GPIO controller.
+- #interrupt-cells : Should be 2.
+  The first cell is the GPIO number.
+  The second cell is used to specify flags:
+    bits[3:0] trigger type and level flags:
+      1 = low-to-high edge triggered.
+      2 = high-to-low edge triggered.
+      4 = active high level-sensitive.
+      8 = active low level-sensitive.
+      Valid combinations are 1, 2, 3, 4, 8.
+- interrupt-controller : Marks the device node as an interrupt controller.
+
+Example:
+
+gpio: gpio@6000d000 {
+       compatible = "nvidia,tegra20-gpio";
+       reg = < 0x6000d000 0x1000 >;
+       interrupts = < 0 32 0x04
+                      0 33 0x04
+                      0 34 0x04
+                      0 35 0x04
+                      0 55 0x04
+                      0 87 0x04
+                      0 89 0x04 >;
+       #gpio-cells = <2>;
+       gpio-controller;
+       #interrupt-cells = <2>;
+       interrupt-controller;
+};
index f959909..74e6c77 100644 (file)
@@ -12,7 +12,7 @@ dynamically enabled per-callsite.
 Dynamic debug has even more useful features:
 
  * Simple query language allows turning on and off debugging statements by
-   matching any combination of:
+   matching any combination of 0 or 1 of:
 
    - source filename
    - function name
@@ -79,31 +79,24 @@ Command Language Reference
 ==========================
 
 At the lexical level, a command comprises a sequence of words separated
-by whitespace characters.  Note that newlines are treated as word
-separators and do *not* end a command or allow multiple commands to
-be done together.  So these are all equivalent:
+by spaces or tabs.  So these are all equivalent:
 
 nullarbor:~ # echo -c 'file svcsock.c line 1603 +p' >
                                <debugfs>/dynamic_debug/control
 nullarbor:~ # echo -c '  file   svcsock.c     line  1603 +p  ' >
                                <debugfs>/dynamic_debug/control
-nullarbor:~ # echo -c 'file svcsock.c\nline 1603 +p' >
-                               <debugfs>/dynamic_debug/control
 nullarbor:~ # echo -n 'file svcsock.c line 1603 +p' >
                                <debugfs>/dynamic_debug/control
 
-Commands are bounded by a write() system call.  If you want to do
-multiple commands you need to do a separate "echo" for each, like:
+Command submissions are bounded by a write() system call.
+Multiple commands can be written together, separated by ';' or '\n'.
 
-nullarbor:~ # echo 'file svcsock.c line 1603 +p' > /proc/dprintk ;\
-> echo 'file svcsock.c line 1563 +p' > /proc/dprintk
+  ~# echo "func pnpacpi_get_resources +p; func pnp_assign_mem +p" \
+     > <debugfs>/dynamic_debug/control
 
-or even like:
+If your query set is big, you can batch them too:
 
-nullarbor:~ # (
-> echo 'file svcsock.c line 1603 +p' ;\
-> echo 'file svcsock.c line 1563 +p' ;\
-> ) > /proc/dprintk
+  ~# cat query-batch-file > <debugfs>/dynamic_debug/control
 
 At the syntactical level, a command comprises a sequence of match
 specifications, followed by a flags change specification.
@@ -144,11 +137,12 @@ func
     func svc_tcp_accept
 
 file
-    The given string is compared against either the full
-    pathname or the basename of the source file of each
-    callsite.  Examples:
+    The given string is compared against either the full pathname, the
+    src-root relative pathname, or the basename of the source file of
+    each callsite.  Examples:
 
     file svcsock.c
+    file kernel/freezer.c
     file /usr/src/packages/BUILD/sgi-enhancednfs-1.4/default/net/sunrpc/svcsock.c
 
 module
index 6872c91..4e25758 100644 (file)
@@ -14,7 +14,10 @@ Debugfs is typically mounted with a command like:
 
     mount -t debugfs none /sys/kernel/debug
 
-(Or an equivalent /etc/fstab line). 
+(Or an equivalent /etc/fstab line).
+The debugfs root directory is accessible by anyone by default. To
+restrict access to the tree the "uid", "gid" and "mode" mount
+options can be used.
 
 Note that the debugfs API is exported GPL-only to modules.
 
index a48aecc..7d809b7 100644 (file)
@@ -186,6 +186,9 @@ config GENERIC_ISA_DMA
 config FIQ
        bool
 
+config NEED_RET_TO_USER
+       bool
+
 config ARCH_MTD_XIP
        bool
 
@@ -479,6 +482,7 @@ config ARCH_IOP13XX
        select ARCH_SUPPORTS_MSI
        select VMSPLIT_1G
        select NEED_MACH_MEMORY_H
+       select NEED_RET_TO_USER
        help
          Support for Intel's IOP13XX (XScale) family of processors.
 
@@ -486,6 +490,7 @@ config ARCH_IOP32X
        bool "IOP32x-based"
        depends on MMU
        select CPU_XSCALE
+       select NEED_RET_TO_USER
        select PLAT_IOP
        select PCI
        select ARCH_REQUIRE_GPIOLIB
@@ -497,6 +502,7 @@ config ARCH_IOP33X
        bool "IOP33x-based"
        depends on MMU
        select CPU_XSCALE
+       select NEED_RET_TO_USER
        select PLAT_IOP
        select PCI
        select ARCH_REQUIRE_GPIOLIB
index 70c41fc..0419690 100644 (file)
                clock-frequency = < 408000000 >;
        };
 
+       serial@70006040 {
+               status = "disable";
+       };
+
+       serial@70006200 {
+               status = "disable";
+       };
+
+       serial@70006300 {
+               status = "disable";
+       };
+
+       serial@70006400 {
+               status = "disable";
+       };
+
        i2c@7000c000 {
                clock-frequency = <100000>;
        };
index 80afa1b..6e8447d 100644 (file)
                reg = < 0x00000000 0x40000000 >;
        };
 
+       pmc@7000f400 {
+               nvidia,invert-interrupt;
+       };
+
        i2c@7000c000 {
                clock-frequency = <400000>;
 
-               codec: wm8903@1a {
+               wm8903: wm8903@1a {
                        compatible = "wlf,wm8903";
                        reg = <0x1a>;
-                       interrupts = < 347 >;
+                       interrupt-parent = <&gpio>;
+                       interrupts = < 187 0x04 >;
 
                        gpio-controller;
                        #gpio-cells = <2>;
 
-                       /* 0x8000 = Not configured */
-                       gpio-cfg = < 0x8000 0x8000 0 0x8000 0x8000 >;
+                       micdet-cfg = <0>;
+                       micdet-delay = <100>;
+                       gpio-cfg = < 0xffffffff 0xffffffff 0 0xffffffff 0xffffffff >;
                };
        };
 
                clock-frequency = <400000>;
        };
 
-       sound {
-               compatible = "nvidia,harmony-sound", "nvidia,tegra-wm8903";
+       i2s@70002a00 {
+               status = "disable";
+       };
 
-               spkr-en-gpios = <&codec 2 0>;
-               hp-det-gpios = <&gpio 178 0>;
-               int-mic-en-gpios = <&gpio 184 0>;
-               ext-mic-en-gpios = <&gpio 185 0>;
+       sound {
+               compatible = "nvidia,tegra-audio-wm8903-harmony",
+                            "nvidia,tegra-audio-wm8903";
+               nvidia,model = "NVIDIA Tegra Harmony";
+
+               nvidia,audio-routing =
+                       "Headphone Jack", "HPOUTR",
+                       "Headphone Jack", "HPOUTL",
+                       "Int Spk", "ROP",
+                       "Int Spk", "RON",
+                       "Int Spk", "LOP",
+                       "Int Spk", "LON",
+                       "Mic Jack", "MICBIAS",
+                       "IN1L", "Mic Jack";
+
+               nvidia,i2s-controller = <&tegra_i2s1>;
+               nvidia,audio-codec = <&wm8903>;
+
+               nvidia,spkr-en-gpios = <&wm8903 2 0>;
+               nvidia,hp-det-gpios = <&gpio 178 0>; /* gpio PW2 */
+               nvidia,int-mic-en-gpios = <&gpio 184 0>; /*gpio PX0 */
+               nvidia,ext-mic-en-gpios = <&gpio 185 0>; /* gpio PX1 */
        };
 
        serial@70006000 {
index 825d295..e4b552b 100644 (file)
 
        i2c@7000c000 {
                clock-frequency = <400000>;
+
+               alc5632: alc5632@1e {
+                       compatible = "realtek,alc5632";
+                       reg = <0x1e>;
+                       gpio-controller;
+                       #gpio-cells = <2>;
+               };
        };
 
        i2c@7000c400 {
                clock-frequency = <400000>;
        };
 
+       i2s@70002a00 {
+               status = "disable";
+       };
+
+       sound {
+               compatible = "nvidia,tegra-audio-alc5632-paz00",
+                       "nvidia,tegra-audio-alc5632";
+
+               nvidia,model = "Compal PAZ00";
+
+               nvidia,audio-routing =
+                       "Int Spk", "SPKOUT",
+                       "Int Spk", "SPKOUTN",
+                       "Headset Mic", "MICBIAS1",
+                       "MIC1", "Headset Mic",
+                       "Headset Stereophone", "HPR",
+                       "Headset Stereophone", "HPL";
+
+               nvidia,audio-codec = <&alc5632>;
+               nvidia,i2s-controller = <&tegra_i2s1>;
+               nvidia,hp-det-gpios = <&gpio 178 0>; /* gpio PW2 */
+       };
+
        serial@70006000 {
                clock-frequency = <216000000>;
        };
index b55a02e..876d5c9 100644 (file)
 
        i2c@7000c000 {
                clock-frequency = <400000>;
+
+               wm8903: wm8903@1a {
+                       compatible = "wlf,wm8903";
+                       reg = <0x1a>;
+                       interrupt-parent = <&gpio>;
+                       interrupts = < 187 0x04 >;
+
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       micdet-cfg = <0>;
+                       micdet-delay = <100>;
+                       gpio-cfg = < 0xffffffff 0xffffffff 0 0xffffffff 0xffffffff >;
+               };
        };
 
        i2c@7000c400 {
                };
        };
 
+       i2s@70002a00 {
+               status = "disable";
+       };
+
+       sound {
+               compatible = "nvidia,tegra-audio-wm8903-seaboard",
+                            "nvidia,tegra-audio-wm8903";
+               nvidia,model = "NVIDIA Tegra Seaboard";
+
+               nvidia,audio-routing =
+                       "Headphone Jack", "HPOUTR",
+                       "Headphone Jack", "HPOUTL",
+                       "Int Spk", "ROP",
+                       "Int Spk", "RON",
+                       "Int Spk", "LOP",
+                       "Int Spk", "LON",
+                       "Mic Jack", "MICBIAS",
+                       "IN1R", "Mic Jack";
+
+               nvidia,i2s-controller = <&tegra_i2s1>;
+               nvidia,audio-codec = <&wm8903>;
+
+               nvidia,spkr-en-gpios = <&wm8903 2 0>;
+               nvidia,hp-det-gpios = <&gpio 185 0>; /* gpio PX1 */
+       };
+
        serial@70006000 {
                status = "disable";
        };
                        gpio-key,wakeup;
                };
        };
+
+       emc@7000f400 {
+               emc-table@190000 {
+                       reg = < 190000 >;
+                       compatible = "nvidia,tegra20-emc-table";
+                       clock-frequency = < 190000 >;
+                       nvidia,emc-registers = < 0x0000000c 0x00000026
+                               0x00000009 0x00000003 0x00000004 0x00000004
+                               0x00000002 0x0000000c 0x00000003 0x00000003
+                               0x00000002 0x00000001 0x00000004 0x00000005
+                               0x00000004 0x00000009 0x0000000d 0x0000059f
+                               0x00000000 0x00000003 0x00000003 0x00000003
+                               0x00000003 0x00000001 0x0000000b 0x000000c8
+                               0x00000003 0x00000007 0x00000004 0x0000000f
+                               0x00000002 0x00000000 0x00000000 0x00000002
+                               0x00000000 0x00000000 0x00000083 0xa06204ae
+                               0x007dc010 0x00000000 0x00000000 0x00000000
+                               0x00000000 0x00000000 0x00000000 0x00000000 >;
+               };
+
+               emc-table@380000 {
+                       reg = < 380000 >;
+                       compatible = "nvidia,tegra20-emc-table";
+                       clock-frequency = < 380000 >;
+                       nvidia,emc-registers = < 0x00000017 0x0000004b
+                               0x00000012 0x00000006 0x00000004 0x00000005
+                               0x00000003 0x0000000c 0x00000006 0x00000006
+                               0x00000003 0x00000001 0x00000004 0x00000005
+                               0x00000004 0x00000009 0x0000000d 0x00000b5f
+                               0x00000000 0x00000003 0x00000003 0x00000006
+                               0x00000006 0x00000001 0x00000011 0x000000c8
+                               0x00000003 0x0000000e 0x00000007 0x0000000f
+                               0x00000002 0x00000000 0x00000000 0x00000002
+                               0x00000000 0x00000000 0x00000083 0xe044048b
+                               0x007d8010 0x00000000 0x00000000 0x00000000
+                               0x00000000 0x00000000 0x00000000 0x00000000 >;
+               };
+       };
 };
index 3b3ee7d..2524768 100644 (file)
                status = "disable";
        };
 
+       i2s@70002800 {
+               status = "disable";
+       };
+
+       i2s@70002a00 {
+               status = "disable";
+       };
+
+       das@70000c00 {
+               status = "disable";
+       };
+
        serial@70006000 {
                clock-frequency = < 216000000 >;
        };
index c7d3b87..2dcff87 100644 (file)
 
        i2c@7000c000 {
                clock-frequency = <400000>;
+
+               wm8903: wm8903@1a {
+                       compatible = "wlf,wm8903";
+                       reg = <0x1a>;
+                       interrupt-parent = <&gpio>;
+                       interrupts = < 187 0x04 >;
+
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       micdet-cfg = <0>;
+                       micdet-delay = <100>;
+                       gpio-cfg = < 0xffffffff 0xffffffff 0 0xffffffff 0xffffffff >;
+               };
        };
 
        i2c@7000c400 {
                clock-frequency = <400000>;
        };
 
+       i2s@70002a00 {
+               status = "disable";
+       };
+
+       sound {
+               compatible = "nvidia,tegra-audio-wm8903-ventana",
+                            "nvidia,tegra-audio-wm8903";
+               nvidia,model = "NVIDIA Tegra Ventana";
+
+               nvidia,audio-routing =
+                       "Headphone Jack", "HPOUTR",
+                       "Headphone Jack", "HPOUTL",
+                       "Int Spk", "ROP",
+                       "Int Spk", "RON",
+                       "Int Spk", "LOP",
+                       "Int Spk", "LON",
+                       "Mic Jack", "MICBIAS",
+                       "IN1L", "Mic Jack";
+
+               nvidia,i2s-controller = <&tegra_i2s1>;
+               nvidia,audio-codec = <&wm8903>;
+
+               nvidia,spkr-en-gpios = <&wm8903 2 0>;
+               nvidia,hp-det-gpios = <&gpio 178 0>; /* gpio PW2 */
+               nvidia,int-mic-en-gpios = <&gpio 184 0>; /*gpio PX0 */
+               nvidia,ext-mic-en-gpios = <&gpio 185 0>; /* gpio PX1 */
+       };
+
        serial@70006000 {
                status = "disable";
        };
index 3da7afd..ec1f010 100644 (file)
@@ -4,6 +4,11 @@
        compatible = "nvidia,tegra20";
        interrupt-parent = <&intc>;
 
+       pmc@7000f400 {
+               compatible = "nvidia,tegra20-pmc";
+               reg = <0x7000e400 0x400>;
+       };
+
        intc: interrupt-controller@50041000 {
                compatible = "arm,cortex-a9-gic";
                interrupt-controller;
                      < 0x50040100 0x0100 >;
        };
 
+       apbdma: dma@6000a000 {
+               compatible = "nvidia,tegra20-apbdma";
+               reg = <0x6000a000 0x1200>;
+               interrupts = < 0 104 0x04
+                              0 105 0x04
+                              0 106 0x04
+                              0 107 0x04
+                              0 108 0x04
+                              0 109 0x04
+                              0 110 0x04
+                              0 111 0x04
+                              0 112 0x04
+                              0 113 0x04
+                              0 114 0x04
+                              0 115 0x04
+                              0 116 0x04
+                              0 117 0x04
+                              0 118 0x04
+                              0 119 0x04 >;
+       };
+
        i2c@7000c000 {
                #address-cells = <1>;
                #size-cells = <0>;
                interrupts = < 0 53 0x04 >;
        };
 
-       i2s@70002800 {
+       tegra_i2s1: i2s@70002800 {
                compatible = "nvidia,tegra20-i2s";
                reg = <0x70002800 0x200>;
                interrupts = < 0 13 0x04 >;
-               dma-channel = < 2 >;
+               nvidia,dma-request-selector = < &apbdma 2 >;
        };
 
-       i2s@70002a00 {
+       tegra_i2s2: i2s@70002a00 {
                compatible = "nvidia,tegra20-i2s";
                reg = <0x70002a00 0x200>;
                interrupts = < 0 3 0x04 >;
-               dma-channel = < 1 >;
+               nvidia,dma-request-selector = < &apbdma 1 >;
        };
 
        das@70000c00 {
                               0 89 0x04 >;
                #gpio-cells = <2>;
                gpio-controller;
+               #interrupt-cells = <2>;
+               interrupt-controller;
        };
 
        pinmux: pinmux@70000000 {
                interrupts = < 0 91 0x04 >;
        };
 
+       emc@7000f400 {
+               #address-cells = <1>;
+               #size-cells = <0>;
+               compatible = "nvidia,tegra20-emc";
+               reg = <0x7000f400 0x200>;
+       };
+
        sdhci@c8000000 {
                compatible = "nvidia,tegra20-sdhci";
                reg = <0xc8000000 0x200>;
index ee7db98..ac4b75c 100644 (file)
@@ -4,6 +4,11 @@
        compatible = "nvidia,tegra30";
        interrupt-parent = <&intc>;
 
+       pmc@7000f400 {
+               compatible = "nvidia,tegra20-pmc", "nvidia,tegra30-pmc";
+               reg = <0x7000e400 0x400>;
+       };
+
        intc: interrupt-controller@50041000 {
                compatible = "arm,cortex-a9-gic";
                interrupt-controller;
                      < 0x50040100 0x0100 >;
        };
 
+       apbdma: dma@6000a000 {
+               compatible = "nvidia,tegra30-apbdma", "nvidia,tegra20-apbdma";
+               reg = <0x6000a000 0x1400>;
+               interrupts = < 0 104 0x04
+                              0 105 0x04
+                              0 106 0x04
+                              0 107 0x04
+                              0 108 0x04
+                              0 109 0x04
+                              0 110 0x04
+                              0 111 0x04
+                              0 112 0x04
+                              0 113 0x04
+                              0 114 0x04
+                              0 115 0x04
+                              0 116 0x04
+                              0 117 0x04
+                              0 118 0x04
+                              0 119 0x04
+                              0 128 0x04
+                              0 129 0x04
+                              0 130 0x04
+                              0 131 0x04
+                              0 132 0x04
+                              0 133 0x04
+                              0 134 0x04
+                              0 135 0x04
+                              0 136 0x04
+                              0 137 0x04
+                              0 138 0x04
+                              0 139 0x04
+                              0 140 0x04
+                              0 141 0x04
+                              0 142 0x04
+                              0 143 0x04 >;
+       };
+
        i2c@7000c000 {
                #address-cells = <1>;
                #size-cells = <0>;
        gpio: gpio@6000d000 {
                compatible = "nvidia,tegra30-gpio", "nvidia,tegra20-gpio";
                reg = < 0x6000d000 0x1000 >;
-               interrupts = < 0 32 0x04 0 33 0x04 0 34 0x04 0 35 0x04 0 55 0x04 0 87 0x04 0 89 0x04 >;
+               interrupts = < 0 32 0x04
+                              0 33 0x04
+                              0 34 0x04
+                              0 35 0x04
+                              0 55 0x04
+                              0 87 0x04
+                              0 89 0x04
+                              0 125 0x04 >;
                #gpio-cells = <2>;
                gpio-controller;
+               #interrupt-cells = <2>;
+               interrupt-controller;
        };
 
        serial@70006000 {
index e0af498..8c215ac 100644 (file)
 /* IOC / IOMD based hardware */
 #include <asm/hardware/iomd.h>
 
-               .macro  disable_fiq
-               mov     r12, #ioc_base_high
-               .if     ioc_base_low
-               orr     r12, r12, #ioc_base_low
-               .endif
-               strb    r12, [r12, #0x38]       @ Disable FIQ register
-               .endm
-
                .macro  get_irqnr_and_base, irqnr, irqstat, base, tmp
                ldrb    \irqstat, [\base, #IOMD_IRQREQB]        @ get high priority first
                ldr     \tmp, =irq_prio_h
index be16a48..22f0ed3 100644 (file)
@@ -19,7 +19,9 @@
 #include <asm/glue-df.h>
 #include <asm/glue-pf.h>
 #include <asm/vfpmacros.h>
+#ifndef CONFIG_MULTI_IRQ_HANDLER
 #include <mach/entry-macro.S>
+#endif
 #include <asm/thread_notify.h>
 #include <asm/unwind.h>
 #include <asm/unistd.h>
@@ -1101,7 +1103,6 @@ __stubs_start:
  * get out of that mode without clobbering one register.
  */
 vector_fiq:
-       disable_fiq
        subs    pc, lr, #4
 
 /*=============================================================================
index 9fd0ba9..54ee265 100644 (file)
 
 #include <asm/unistd.h>
 #include <asm/ftrace.h>
-#include <mach/entry-macro.S>
 #include <asm/unwind.h>
 
+#ifdef CONFIG_NEED_RET_TO_USER
+#include <mach/entry-macro.S>
+#else
+       .macro  arch_ret_to_user, tmp1, tmp2
+       .endm
+#endif
+
 #include "entry-header.S"
 
 
index 423eea0..903bf20 100644 (file)
 #include <mach/hardware.h>
 #include <mach/at91_aic.h>
 
-       .macro  disable_fiq
-       .endm
-
        .macro  get_irqnr_preamble, base, tmp
        ldr     \base, =at91_aic_base           @ base virtual address of AIC peripheral
        ldr     \base, [\base]
        .endm
 
-       .macro  arch_ret_to_user, tmp1, tmp2
-       .endm
-
        .macro  get_irqnr_and_base, irqnr, irqstat, base, tmp
        ldr     \irqnr, [\base, #AT91_AIC_IVR]          @ read IRQ vector register: de-asserts nIRQ to processor (and clears interrupt)
        ldr     \irqstat, [\base, #AT91_AIC_ISR]        @ read interrupt source number
index 94c950d..2f316f0 100644 (file)
@@ -21,9 +21,6 @@
 #include <mach/hardware.h>
 #include <mach/csp/mm_io.h>
 
-               .macro  disable_fiq
-               .endm
-
                .macro  get_irqnr_and_base, irqnr, irqstat, base, tmp
                ldr     \base, =(MM_IO_BASE_INTC0)
                ldr     \irqstat, [\base, #0]           @ get status
@@ -77,6 +74,3 @@
 
                .macro  get_irqnr_preamble, base, tmp
                .endm
-
-               .macro  arch_ret_to_user, tmp1, tmp2
-               .endm
index 90fa2f7..125af59 100644 (file)
 #include <mach/hardware.h>
 #include <asm/hardware/clps7111.h>
 
-               .macro  disable_fiq
-               .endm
-
                .macro  get_irqnr_preamble, base, tmp
                .endm
 
-               .macro  arch_ret_to_user, tmp1, tmp2
-               .endm
-
 #if (INTSR2 - INTSR1) != (INTMR2 - INTMR1)
 #error INTSR stride != INTMR stride
 #endif
diff --git a/arch/arm/mach-cns3xxx/include/mach/entry-macro.S b/arch/arm/mach-cns3xxx/include/mach/entry-macro.S
deleted file mode 100644 (file)
index 01c57df..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-/*
- * Low-level IRQ helper macros for Cavium Networks platforms
- *
- * Copyright 2008 Cavium Networks
- *
- * This file 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.
- */
-
-               .macro  disable_fiq
-               .endm
-
-               .macro  arch_ret_to_user, tmp1, tmp2
-               .endm
index e14c0dc..c1661d2 100644 (file)
 #include <mach/io.h>
 #include <mach/irqs.h>
 
-               .macro  disable_fiq
-               .endm
-
                .macro  get_irqnr_preamble, base, tmp
                ldr \base, =davinci_intc_base
                ldr \base, [\base]
                .endm
 
-               .macro  arch_ret_to_user, tmp1, tmp2
-               .endm
-
                .macro  get_irqnr_and_base, irqnr, irqstat, base, tmp
 #if defined(CONFIG_AINTC) && defined(CONFIG_CP_INTC)
                ldr \tmp, =davinci_intc_type
index e84c78c..72d622b 100644 (file)
 
 #include <mach/bridge-regs.h>
 
-       .macro  disable_fiq
-       .endm
-
-       .macro  arch_ret_to_user, tmp1, tmp2
-       .endm
-
        .macro  get_irqnr_preamble, base, tmp
        ldr     \base, =IRQ_VIRT_BASE
        .endm
index cc3e599..14b110d 100644 (file)
 
 #define IRQ_STAT               0xff000000      /* read */
 
-       .macro  disable_fiq
-       .endm
-
        .macro  get_irqnr_preamble, base, tmp
        mov     \base, #IRQ_STAT
        .endm
 
-       .macro  arch_ret_to_user, tmp1, tmp2
-       .endm
-
        .macro  get_irqnr_and_base, irqnr, stat, base, tmp
        ldrb    \stat, [\base]                  @ get interrupts
        mov     \irqnr, #0
diff --git a/arch/arm/mach-ep93xx/include/mach/entry-macro.S b/arch/arm/mach-ep93xx/include/mach/entry-macro.S
deleted file mode 100644 (file)
index 9be6edc..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-/*
- * arch/arm/mach-ep93xx/include/mach/entry-macro.S
- * IRQ demultiplexing for EP93xx
- *
- * Copyright (C) 2006 Lennert Buytenhek <buytenh@wantstofly.org>
- *
- * 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.
- */
-
-               .macro  disable_fiq
-               .endm
-
-               .macro  arch_ret_to_user, tmp1, tmp2
-               .endm
diff --git a/arch/arm/mach-exynos/include/mach/entry-macro.S b/arch/arm/mach-exynos/include/mach/entry-macro.S
deleted file mode 100644 (file)
index 3ba4f54..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-/* arch/arm/mach-exynos4/include/mach/entry-macro.S
- *
- * Cloned from arch/arm/mach-realview/include/mach/entry-macro.S
- *
- * Low-level IRQ helper macros for EXYNOS4 platforms
- *
- * This file is licensed under  the terms of the GNU General Public
- * License version 2. This program is licensed "as is" without any
- * warranty of any kind, whether express or implied.
-*/
-
-               .macro  disable_fiq
-               .endm
-
-               .macro  arch_ret_to_user, tmp1, tmp2
-               .endm
index d3847be..dabbd5c 100644 (file)
@@ -14,9 +14,6 @@
                .equ    dc21285_high, ARMCSR_BASE & 0xff000000
                .equ    dc21285_low, ARMCSR_BASE & 0x00ffffff
 
-               .macro  disable_fiq
-               .endm
-
                .macro  get_irqnr_preamble, base, tmp
                mov     \base, #dc21285_high
                .if     dc21285_low
@@ -24,9 +21,6 @@
                .endif
                .endm
 
-               .macro  arch_ret_to_user, tmp1, tmp2
-               .endm
-
                .macro  get_irqnr_and_base, irqnr, irqstat, base, tmp
                ldr     \irqstat, [\base, #0x180]       @ get interrupts
 
index 1624f91..f044e43 100644 (file)
 
 #define IRQ_STATUS     0x14
 
-       .macro  disable_fiq
-       .endm
-
        .macro  get_irqnr_preamble, base, tmp
        .endm
 
-       .macro  arch_ret_to_user, tmp1, tmp2
-       .endm
-
        .macro  get_irqnr_and_base, irqnr, irqstat, base, tmp
        ldr     \irqstat, =IO_ADDRESS(GEMINI_INTERRUPT_BASE + IRQ_STATUS)
        ldr     \irqnr, [\irqstat]
index c3948e5..75267fa 100644 (file)
@@ -8,15 +8,9 @@
  * warranty of any kind, whether express or implied.
  */
 
-               .macro  disable_fiq
-               .endm
-
                .macro  get_irqnr_preamble, base, tmp
                .endm
 
-               .macro  arch_ret_to_user, tmp1, tmp2
-               .endm
-
                .macro  get_irqnr_and_base, irqnr, irqstat, base, tmp
 #if defined (CONFIG_CPU_H7201) || defined (CONFIG_CPU_H7202)
                @ we could use the id register on H7202, but this is not
diff --git a/arch/arm/mach-highbank/include/mach/entry-macro.S b/arch/arm/mach-highbank/include/mach/entry-macro.S
deleted file mode 100644 (file)
index a14f9e6..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-       .macro  disable_fiq
-       .endm
-
-       .macro  arch_ret_to_user, tmp1, tmp2
-       .endm
index 3d029c9..5cc7b85 100644 (file)
 #include <mach/platform.h>
 #include <mach/irqs.h>
 
-               .macro  disable_fiq
-               .endm
-
                .macro  get_irqnr_preamble, base, tmp
                .endm
 
-               .macro  arch_ret_to_user, tmp1, tmp2
-               .endm
-
                .macro  get_irqnr_and_base, irqnr, irqstat, base, tmp
 /* FIXME: should not be using soo many LDRs here */
                ldr     \base, =IO_ADDRESS(INTEGRATOR_IC_BASE)
index a624a78..1a2d603 100644 (file)
@@ -16,9 +16,6 @@
  * Place - Suite 330, Boston, MA 02111-1307 USA.
  *
  */
-       .macro  disable_fiq
-       .endm
-
        .macro get_irqnr_preamble, base, tmp
        mrc     p15, 0, \tmp, c15, c1, 0
        orr     \tmp, \tmp, #(1 << 6)
index b02fb56..ea13ae0 100644 (file)
@@ -9,9 +9,6 @@
  */
 #include <mach/iop32x.h>
 
-       .macro  disable_fiq
-       .endm
-
        .macro get_irqnr_preamble, base, tmp
        mrc     p15, 0, \tmp, c15, c1, 0
        orr     \tmp, \tmp, #(1 << 6)
index 4e1f728..0a398fe 100644 (file)
@@ -9,9 +9,6 @@
  */
 #include <mach/iop33x.h>
 
-       .macro  disable_fiq
-       .endm
-
        .macro get_irqnr_preamble, base, tmp
        mrc     p15, 0, \tmp, c15, c1, 0
        orr     \tmp, \tmp, #(1 << 6)
index 5850ffc..c4444df 100644 (file)
@@ -9,15 +9,9 @@
  */
 #include <mach/irqs.h>
 
-               .macro  disable_fiq
-               .endm
-
                .macro  get_irqnr_preamble, base, tmp
                .endm
 
-               .macro  arch_ret_to_user, tmp1, tmp2
-               .endm
-
                .macro  get_irqnr_and_base, irqnr, irqstat, base, tmp
 
                mov     \irqnr, #0x0              @clear out irqnr as default
index 3f5338a..3fd2cb9 100644 (file)
@@ -2,15 +2,9 @@
  * arch/arm/mach-ixp23xx/include/mach/entry-macro.S
  */
 
-               .macro  disable_fiq
-               .endm
-
                .macro  get_irqnr_preamble, base, tmp
                .endm
 
-               .macro  arch_ret_to_user, tmp1, tmp2
-               .endm
-
                .macro  get_irqnr_and_base, irqnr, irqstat, base, tmp
                ldr     \irqnr, =(IXP23XX_INTC_VIRT + IXP23XX_INTR_IRQ_ENC_ST_OFFSET)
                ldr     \irqnr, [\irqnr]        @ get interrupt number
index f2e14e9..79adf83 100644 (file)
@@ -9,15 +9,9 @@
  */
 #include <mach/hardware.h>
 
-               .macro  disable_fiq
-               .endm
-
                .macro  get_irqnr_preamble, base, tmp
                .endm
 
-               .macro  arch_ret_to_user, tmp1, tmp2
-               .endm
-
                .macro  get_irqnr_and_base, irqnr, irqstat, base, tmp
                ldr     \irqstat, =(IXP4XX_INTC_BASE_VIRT+IXP4XX_ICIP_OFFSET)
                ldr     \irqstat, [\irqstat]            @ get interrupts
index 8939d36..82db29f 100644 (file)
 
 #include <mach/bridge-regs.h>
 
-       .macro  disable_fiq
-       .endm
-
-       .macro  arch_ret_to_user, tmp1, tmp2
-       .endm
-
        .macro  get_irqnr_preamble, base, tmp
        ldr     \base, =IRQ_VIRT_BASE
        .endm
index b4fe0c1..8315b34 100644 (file)
 #include <mach/hardware.h>
 #include <mach/regs-irq.h>
 
-       .macro  disable_fiq
-       .endm
-
        .macro  get_irqnr_preamble, base, tmp
                ldr     \base, =KS8695_IRQ_VA                   @ Base address of interrupt controller
        .endm
 
-       .macro  arch_ret_to_user, tmp1, tmp2
-       .endm
-
        .macro  get_irqnr_and_base, irqnr, irqstat, base, tmp
                ldr     \irqstat, [\base, #KS8695_INTMS]        @ Mask Status register
 
index b725f6c..24ca11b 100644 (file)
 
 #define LPC32XX_INTC_MASKED_STATUS_OFS 0x8
 
-       .macro  disable_fiq
-       .endm
-
        .macro  get_irqnr_preamble, base, tmp
        ldr     \base, =IO_ADDRESS(LPC32XX_MIC_BASE)
        .endm
 
-       .macro  arch_ret_to_user, tmp1, tmp2
-       .endm
-
 /*
  * Return IRQ number in irqnr. Also return processor Z flag status in CPSR
  * as set if an interrupt is pending.
index c42d9d4..9cff9e7 100644 (file)
@@ -8,12 +8,6 @@
 
 #include <mach/regs-icu.h>
 
-       .macro  disable_fiq
-       .endm
-
-       .macro  arch_ret_to_user, tmp1, tmp2
-       .endm
-
        .macro  get_irqnr_preamble, base, tmp
        mrc     p15, 0, \tmp, c0, c0, 0         @ CPUID
        and     \tmp, \tmp, #0xff00
index 41f7003..f2ae908 100644 (file)
  *
  */
 
-       .macro  disable_fiq
-       .endm
-
-       .macro  arch_ret_to_user, tmp1, tmp2
-       .endm
-
 #if !defined(CONFIG_ARM_GIC)
 #include <mach/msm_iomap.h>
 
index 66ae2d2..6b1f088 100644 (file)
 
 #include <mach/bridge-regs.h>
 
-       .macro  disable_fiq
-       .endm
-
-       .macro  arch_ret_to_user, tmp1, tmp2
-       .endm
-
        .macro  get_irqnr_preamble, base, tmp
        ldr     \base, =IRQ_VIRT_BASE
        .endm
index 9f0da12..0c14259 100644 (file)
@@ -23,9 +23,6 @@
 #define MXS_ICOLL_VBASE                MXS_IO_ADDRESS(MXS_ICOLL_BASE_ADDR)
 #define HW_ICOLL_STAT_OFFSET   0x70
 
-       .macro  disable_fiq
-       .endm
-
        .macro  get_irqnr_and_base, irqnr, irqstat, base, tmp
        ldr     \irqnr, [\base, #HW_ICOLL_STAT_OFFSET]
        cmp     \irqnr, #0x7F
@@ -36,6 +33,3 @@
        .macro  get_irqnr_preamble, base, tmp
        ldr     \base, =MXS_ICOLL_VBASE
        .endm
-
-       .macro  arch_ret_to_user, tmp1, tmp2
-       .endm
diff --git a/arch/arm/mach-netx/include/mach/entry-macro.S b/arch/arm/mach-netx/include/mach/entry-macro.S
deleted file mode 100644 (file)
index 6e9f1cb..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * arch/arm/mach-netx/include/mach/entry-macro.S
- *
- * Low-level IRQ helper macros for Hilscher netX based platforms
- *
- * Copyright (C) 2005 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-
-               .macro  disable_fiq
-               .endm
-
-               .macro  arch_ret_to_user, tmp1, tmp2
-               .endm
diff --git a/arch/arm/mach-nomadik/include/mach/entry-macro.S b/arch/arm/mach-nomadik/include/mach/entry-macro.S
deleted file mode 100644 (file)
index 98ea1c1..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-/*
- * Low-level IRQ helper macros for Nomadik platforms
- *
- * This file is licensed under  the terms of the GNU General Public
- * License version 2. This program is licensed "as is" without any
- * warranty of any kind, whether express or implied.
- */
-
-       .macro  disable_fiq
-       .endm
-
-       .macro  arch_ret_to_user, tmp1, tmp2
-       .endm
index bfb4fb1..83c0250 100644 (file)
 #include <mach/irqs.h>
 #include <asm/hardware/gic.h>
 
-               .macro  disable_fiq
-               .endm
-
                .macro  get_irqnr_preamble, base, tmp
                .endm
 
-               .macro  arch_ret_to_user, tmp1, tmp2
-               .endm
-
                .macro  get_irqnr_and_base, irqnr, irqstat, base, tmp
                ldr     \base, =OMAP1_IO_ADDRESS(OMAP_IH1_BASE)
                ldr     \irqnr, [\base, #IRQ_ITR_REG_OFFSET]
diff --git a/arch/arm/mach-omap2/include/mach/entry-macro.S b/arch/arm/mach-omap2/include/mach/entry-macro.S
deleted file mode 100644 (file)
index 56964a0..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
- * arch/arm/plat-omap/include/mach/entry-macro.S
- *
- * Low-level IRQ helper macros for OMAP-based platforms
- *
- * Copyright (C) 2009 Texas Instruments
- * Added OMAP4 support - Santosh Shilimkar <santosh.shilimkar@ti.com>
- *
- * This file is licensed under  the terms of the GNU General Public
- * License version 2. This program is licensed "as is" without any
- * warranty of any kind, whether express or implied.
- */
-
-               .macro  disable_fiq
-               .endm
-
-               .macro  arch_ret_to_user, tmp1, tmp2
-               .endm
index d658992..79eb502 100644 (file)
 
 #include <mach/bridge-regs.h>
 
-       .macro  disable_fiq
-       .endm
-
-       .macro  arch_ret_to_user, tmp1, tmp2
-       .endm
-
        .macro  get_irqnr_preamble, base, tmp
        ldr     \base, =MAIN_IRQ_CAUSE
        .endm
diff --git a/arch/arm/mach-picoxcell/include/mach/entry-macro.S b/arch/arm/mach-picoxcell/include/mach/entry-macro.S
deleted file mode 100644 (file)
index 9b505ac..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-/*
- * entry-macro.S
- *
- * Copyright (c) 2011 Picochip Ltd., Jamie Iles
- *
- * Low-level IRQ helper macros for picoXcell platforms
- *
- * This file is licensed under  the terms of the GNU General Public
- * License version 2. This program is licensed "as is" without any
- * warranty of any kind, whether express or implied.
- */
-       .macro  disable_fiq
-       .endm
-
-       .macro  arch_ret_to_user, tmp1, tmp2
-       .endm
index db7eeeb..77a5558 100644 (file)
 #define SIC1_BASE_INT   32
 #define SIC2_BASE_INT   64
 
-               .macro  disable_fiq
-               .endm
-
                .macro  get_irqnr_preamble, base, tmp
                .endm
 
-               .macro  arch_ret_to_user, tmp1, tmp2
-               .endm
-
                .macro  get_irqnr_and_base, irqnr, irqstat, base, tmp
 /* decode the MIC interrupt numbers */
                ldr     \base, =IO_ADDRESS(PNX4008_INTCTRLMIC_BASE)
index 1c8a50f..86434e7 100644 (file)
        cmp \irqnr, #0x40                       @ the irq num can't be larger than 0x3f
        movges \irqnr, #0
        .endm
-
-       .macro  disable_fiq
-       .endm
-
-       .macro  arch_ret_to_user, tmp1, tmp2
-       .endm
-
diff --git a/arch/arm/mach-pxa/include/mach/entry-macro.S b/arch/arm/mach-pxa/include/mach/entry-macro.S
deleted file mode 100644 (file)
index 260c0c1..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-/*
- * arch/arm/mach-pxa/include/mach/entry-macro.S
- *
- * Low-level IRQ helper macros for PXA-based platforms
- *
- * This file is licensed under  the terms of the GNU General Public
- * License version 2. This program is licensed "as is" without any
- * warranty of any kind, whether express or implied.
- */
-
-               .macro  disable_fiq
-               .endm
-
-               .macro  arch_ret_to_user, tmp1, tmp2
-               .endm
diff --git a/arch/arm/mach-realview/include/mach/entry-macro.S b/arch/arm/mach-realview/include/mach/entry-macro.S
deleted file mode 100644 (file)
index e8a5179..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-/*
- * arch/arm/mach-realview/include/mach/entry-macro.S
- *
- * Low-level IRQ helper macros for RealView platforms
- *
- * This file is licensed under  the terms of the GNU General Public
- * License version 2. This program is licensed "as is" without any
- * warranty of any kind, whether express or implied.
- */
-
-               .macro  disable_fiq
-               .endm
-
-               .macro  arch_ret_to_user, tmp1, tmp2
-               .endm
-
index aa77bc9..dfa405c 100644 (file)
@@ -4,7 +4,7 @@
 
 # Object file lists.
 
-obj-y                  := dma.o irq.o riscpc.o
+obj-y                  := dma.o fiq.o irq.o riscpc.o
 obj-m                  :=
 obj-n                  :=
 obj-                   :=
diff --git a/arch/arm/mach-rpc/fiq.S b/arch/arm/mach-rpc/fiq.S
new file mode 100644 (file)
index 0000000..48ddd57
--- /dev/null
@@ -0,0 +1,16 @@
+#include <linux/linkage.h>
+#include <asm/assembler.h>
+#include <mach/hardware.h>
+#include <mach/entry-macro.S>
+
+       .text
+
+       .global rpc_default_fiq_end
+ENTRY(rpc_default_fiq_start)
+       mov     r12, #ioc_base_high
+       .if     ioc_base_low
+       orr     r12, r12, #ioc_base_low
+       .endif
+       strb    r12, [r12, #0x38]       @ Disable FIQ register
+       subs    pc, lr, #4
+rpc_default_fiq_end:
index 4e7e541..7178368 100644 (file)
@@ -10,7 +10,3 @@
        orr     \base, \base, #ioc_base_low
        .endif
        .endm
-
-       .macro  arch_ret_to_user, tmp1, tmp2
-       .endm
-
index 2e1b530..cf0e669 100644 (file)
@@ -5,6 +5,7 @@
 #include <asm/mach/irq.h>
 #include <asm/hardware/iomd.h>
 #include <asm/irq.h>
+#include <asm/fiq.h>
 
 static void iomd_ack_irq_a(struct irq_data *d)
 {
@@ -112,6 +113,8 @@ static struct irq_chip iomd_fiq_chip = {
        .irq_unmask     = iomd_unmask_irq_fiq,
 };
 
+extern unsigned char rpc_default_fiq_start, rpc_default_fiq_end;
+
 void __init rpc_init_irq(void)
 {
        unsigned int irq, flags;
@@ -121,6 +124,9 @@ void __init rpc_init_irq(void)
        iomd_writeb(0, IOMD_FIQMASK);
        iomd_writeb(0, IOMD_DMAMASK);
 
+       set_fiq_handler(&rpc_default_fiq_start,
+               &rpc_default_fiq_end - &rpc_default_fiq_start);
+
        for (irq = 0; irq < NR_IRQS; irq++) {
                flags = IRQF_VALID;
 
index 473b3cd..7615a14 100644 (file)
@@ -25,9 +25,6 @@
        .macro  get_irqnr_preamble, base, tmp
        .endm
 
-       .macro  arch_ret_to_user, tmp1, tmp2
-       .endm
-
        .macro  get_irqnr_and_base, irqnr, irqstat, base, tmp
 
                mov     \base, #S3C24XX_VA_IRQ
@@ -71,8 +68,3 @@
                @@ exit here, Z flag unset if IRQ
 
        .endm
-
-               /* currently don't need an disable_fiq macro */
-
-               .macro  disable_fiq
-               .endm
diff --git a/arch/arm/mach-s3c64xx/include/mach/entry-macro.S b/arch/arm/mach-s3c64xx/include/mach/entry-macro.S
deleted file mode 100644 (file)
index dc2bc15..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-/* arch/arm/mach-s3c6400/include/mach/entry-macro.S
- *
- * Copyright 2008 Openmoko, Inc.
- * Copyright 2008 Simtec Electronics
- *     http://armlinux.simtec.co.uk/
- *     Ben Dooks <ben@simtec.co.uk>
- *
- * Low-level IRQ helper macros for the Samsung S3C64XX series
- *
- * This file is licensed under  the terms of the GNU General Public
- * License version 2. This program is licensed "as is" without any
- * warranty of any kind, whether express or implied.
-*/
-
-               .macro  disable_fiq
-               .endm
-
-               .macro  arch_ret_to_user, tmp1, tmp2
-               .endm
diff --git a/arch/arm/mach-s5p64x0/include/mach/entry-macro.S b/arch/arm/mach-s5p64x0/include/mach/entry-macro.S
deleted file mode 100644 (file)
index fbb246d..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-/* linux/arch/arm/mach-s5p64x0/include/mach/entry-macro.S
- *
- * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
- *             http://www.samsung.com
- *
- * Low-level IRQ helper macros for the Samsung S5P64X0
- *
- * 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.
-*/
-
-               .macro  disable_fiq
-               .endm
-
-               .macro  arch_ret_to_user, tmp1, tmp2
-               .endm
index b8c242e..bad0700 100644 (file)
  * warranty of any kind, whether express or implied.
 */
 
-       .macro  disable_fiq
-       .endm
-
        .macro  get_irqnr_preamble, base, tmp
        .endm
 
-       .macro  arch_ret_to_user, tmp1, tmp2
-       .endm
-
        .macro  get_irqnr_and_base, irqnr, irqstat, base, tmp
        .endm
diff --git a/arch/arm/mach-s5pv210/include/mach/entry-macro.S b/arch/arm/mach-s5pv210/include/mach/entry-macro.S
deleted file mode 100644 (file)
index bebca1b..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-/* linux/arch/arm/mach-s5pv210/include/mach/entry-macro.S
- *
- * Copyright (c) 2010 Samsung Electronics Co., Ltd.
- *             http://www.samsung.com/
- *
- * Low-level IRQ helper macros for the Samsung S5PV210
- *
- * 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.
-*/
-
-       .macro  disable_fiq
-       .endm
-
-       .macro  arch_ret_to_user, tmp1, tmp2
-       .endm
index 6aa13c4..8cf7630 100644 (file)
@@ -8,17 +8,11 @@
  * warranty of any kind, whether express or implied.
  */
 
-               .macro  disable_fiq
-               .endm
-
                .macro  get_irqnr_preamble, base, tmp
                mov     \base, #0xfa000000              @ ICIP = 0xfa050000
                add     \base, \base, #0x00050000
                .endm
 
-               .macro  arch_ret_to_user, tmp1, tmp2
-               .endm
-
                .macro  get_irqnr_and_base, irqnr, irqstat, base, tmp
                ldr     \irqstat, [\base]               @ get irqs
                ldr     \irqnr, [\base, #4]             @ ICMR = 0xfa050004
index 0bb6cc6..5901b09 100644 (file)
@@ -7,16 +7,10 @@
  * License version 2. This program is licensed "as is" without any
  * warranty of any kind, whether express or implied.
  */
-               .macro  disable_fiq
-               .endm
-
                .macro  get_irqnr_preamble, base, tmp
                mov     \base, #0xe0000000
                .endm
 
-               .macro  arch_ret_to_user, tmp1, tmp2
-               .endm
-
                .macro  get_irqnr_and_base, irqnr, irqstat, base, tmp
 
                mov     \irqstat, #0x0C
diff --git a/arch/arm/mach-shmobile/include/mach/entry-macro.S b/arch/arm/mach-shmobile/include/mach/entry-macro.S
deleted file mode 100644 (file)
index 2a57b29..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * Copyright (C) 2010  Paul Mundt
- *
- * 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 St, Fifth Floor, Boston, MA  02110-1301  USA
- */
-
-       .macro  disable_fiq
-       .endm
-
-       .macro  arch_ret_to_user, tmp1, tmp2
-       .endm
diff --git a/arch/arm/mach-spear3xx/include/mach/entry-macro.S b/arch/arm/mach-spear3xx/include/mach/entry-macro.S
deleted file mode 100644 (file)
index de3bb41..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
- * arch/arm/mach-spear3xx/include/mach/entry-macro.S
- *
- * Low-level IRQ helper macros for SPEAr3xx machine family
- *
- * Copyright (C) 2009 ST Microelectronics
- * Viresh Kumar<viresh.kumar@st.com>
- *
- * This file is licensed under the terms of the GNU General Public
- * License version 2. This program is licensed "as is" without any
- * warranty of any kind, whether express or implied.
- */
-
-               .macro  disable_fiq
-               .endm
-
-               .macro  arch_ret_to_user, tmp1, tmp2
-               .endm
diff --git a/arch/arm/mach-spear6xx/include/mach/entry-macro.S b/arch/arm/mach-spear6xx/include/mach/entry-macro.S
deleted file mode 100644 (file)
index d490a91..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
- * arch/arm/mach-spear6xx/include/mach/entry-macro.S
- *
- * Low-level IRQ helper macros for SPEAr6xx machine family
- *
- * Copyright (C) 2009 ST Microelectronics
- * Rajeev Kumar<rajeev-dlh.kumar@st.com>
- *
- * This file is licensed under the terms of the GNU General Public
- * License version 2. This program is licensed "as is" without any
- * warranty of any kind, whether express or implied.
- */
-
-               .macro  disable_fiq
-               .endm
-
-               .macro  arch_ret_to_user, tmp1, tmp2
-               .endm
index e120ff5..7c77a53 100644 (file)
@@ -7,15 +7,21 @@ obj-y                                   += clock.o
 obj-y                                   += timer.o
 obj-y                                   += pinmux.o
 obj-y                                  += fuse.o
+obj-y                                  += pmc.o
+obj-y                                  += flowctrl.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 localtimer.o headsmp.o
+obj-$(CONFIG_SMP)                       += reset.o
 obj-$(CONFIG_HOTPLUG_CPU)               += hotplug.o
-obj-$(CONFIG_TEGRA_SYSTEM_DMA)         += dma.o
+obj-$(CONFIG_TEGRA_SYSTEM_DMA)         += dma.o apbio.o
 obj-$(CONFIG_CPU_FREQ)                  += cpu-tegra.o
 obj-$(CONFIG_TEGRA_PCI)                        += pcie.o
 obj-$(CONFIG_USB_SUPPORT)              += usb_phy.o
diff --git a/arch/arm/mach-tegra/apbio.c b/arch/arm/mach-tegra/apbio.c
new file mode 100644 (file)
index 0000000..e75451e
--- /dev/null
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2010 NVIDIA Corporation.
+ * Copyright (C) 2010 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/io.h>
+#include <linux/dma-mapping.h>
+#include <linux/spinlock.h>
+#include <linux/completion.h>
+#include <linux/sched.h>
+#include <linux/mutex.h>
+
+#include <mach/dma.h>
+#include <mach/iomap.h>
+
+#include "apbio.h"
+
+static DEFINE_MUTEX(tegra_apb_dma_lock);
+
+static struct tegra_dma_channel *tegra_apb_dma;
+static u32 *tegra_apb_bb;
+static dma_addr_t tegra_apb_bb_phys;
+static DECLARE_COMPLETION(tegra_apb_wait);
+
+bool tegra_apb_init(void)
+{
+       struct tegra_dma_channel *ch;
+
+       mutex_lock(&tegra_apb_dma_lock);
+
+       /* Check to see if we raced to setup */
+       if (tegra_apb_dma)
+               goto out;
+
+       ch = tegra_dma_allocate_channel(TEGRA_DMA_MODE_ONESHOT |
+               TEGRA_DMA_SHARED);
+
+       if (!ch)
+               goto out_fail;
+
+       tegra_apb_bb = dma_alloc_coherent(NULL, sizeof(u32),
+               &tegra_apb_bb_phys, GFP_KERNEL);
+       if (!tegra_apb_bb) {
+               pr_err("%s: can not allocate bounce buffer\n", __func__);
+               tegra_dma_free_channel(ch);
+               goto out_fail;
+       }
+
+       tegra_apb_dma = ch;
+out:
+       mutex_unlock(&tegra_apb_dma_lock);
+       return true;
+
+out_fail:
+       mutex_unlock(&tegra_apb_dma_lock);
+       return false;
+}
+
+static void apb_dma_complete(struct tegra_dma_req *req)
+{
+       complete(&tegra_apb_wait);
+}
+
+u32 tegra_apb_readl(unsigned long offset)
+{
+       struct tegra_dma_req req;
+       int ret;
+
+       if (!tegra_apb_dma && !tegra_apb_init())
+               return readl(IO_TO_VIRT(offset));
+
+       mutex_lock(&tegra_apb_dma_lock);
+       req.complete = apb_dma_complete;
+       req.to_memory = 1;
+       req.dest_addr = tegra_apb_bb_phys;
+       req.dest_bus_width = 32;
+       req.dest_wrap = 1;
+       req.source_addr = offset;
+       req.source_bus_width = 32;
+       req.source_wrap = 4;
+       req.req_sel = TEGRA_DMA_REQ_SEL_CNTR;
+       req.size = 4;
+
+       INIT_COMPLETION(tegra_apb_wait);
+
+       tegra_dma_enqueue_req(tegra_apb_dma, &req);
+
+       ret = wait_for_completion_timeout(&tegra_apb_wait,
+               msecs_to_jiffies(50));
+
+       if (WARN(ret == 0, "apb read dma timed out")) {
+               tegra_dma_dequeue_req(tegra_apb_dma, &req);
+               *(u32 *)tegra_apb_bb = 0;
+       }
+
+       mutex_unlock(&tegra_apb_dma_lock);
+       return *((u32 *)tegra_apb_bb);
+}
+
+void tegra_apb_writel(u32 value, unsigned long offset)
+{
+       struct tegra_dma_req req;
+       int ret;
+
+       if (!tegra_apb_dma && !tegra_apb_init()) {
+               writel(value, IO_TO_VIRT(offset));
+               return;
+       }
+
+       mutex_lock(&tegra_apb_dma_lock);
+       *((u32 *)tegra_apb_bb) = value;
+       req.complete = apb_dma_complete;
+       req.to_memory = 0;
+       req.dest_addr = offset;
+       req.dest_wrap = 4;
+       req.dest_bus_width = 32;
+       req.source_addr = tegra_apb_bb_phys;
+       req.source_bus_width = 32;
+       req.source_wrap = 1;
+       req.req_sel = TEGRA_DMA_REQ_SEL_CNTR;
+       req.size = 4;
+
+       INIT_COMPLETION(tegra_apb_wait);
+
+       tegra_dma_enqueue_req(tegra_apb_dma, &req);
+
+       ret = wait_for_completion_timeout(&tegra_apb_wait,
+               msecs_to_jiffies(50));
+
+       if (WARN(ret == 0, "apb write dma timed out"))
+               tegra_dma_dequeue_req(tegra_apb_dma, &req);
+
+       mutex_unlock(&tegra_apb_dma_lock);
+}
diff --git a/arch/arm/mach-tegra/apbio.h b/arch/arm/mach-tegra/apbio.h
new file mode 100644 (file)
index 0000000..8b49e8c
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2010 NVIDIA Corporation.
+ * Copyright (C) 2010 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef __MACH_TEGRA_APBIO_H
+#define __MACH_TEGRA_APBIO_H
+
+#ifdef CONFIG_TEGRA_SYSTEM_DMA
+
+u32 tegra_apb_readl(unsigned long offset);
+void tegra_apb_writel(u32 value, unsigned long offset);
+
+#else
+#include <asm/io.h>
+#include <mach/io.h>
+
+static inline u32 tegra_apb_readl(unsigned long offset)
+{
+        return readl(IO_TO_VIRT(offset));
+}
+
+static inline void tegra_apb_writel(u32 value, unsigned long offset)
+{
+        writel(value, IO_TO_VIRT(offset));
+}
+#endif
+
+#endif
index 3c197e2..11f7abd 100644 (file)
 #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 */
+       { "uarta",      "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[] = {
index 21d1285..976edfb 100644 (file)
 #include <linux/i2c.h>
 #include <linux/platform_device.h>
 #include <linux/gpio.h>
-#include <linux/io.h>
 #include <linux/regulator/machine.h>
 #include <linux/mfd/tps6586x.h>
 
-#include <mach/iomap.h>
 #include <mach/irqs.h>
 
 #include "board-harmony.h"
 
-#define PMC_CTRL               0x0
-#define PMC_CTRL_INTR_LOW      (1 << 17)
-
 static struct regulator_consumer_supply tps658621_ldo0_supply[] = {
        REGULATOR_SUPPLY("pex_clk", NULL),
 };
@@ -114,16 +109,6 @@ static struct i2c_board_info __initdata harmony_regulators[] = {
 
 int __init harmony_regulator_init(void)
 {
-       void __iomem *pmc = IO_ADDRESS(TEGRA_PMC_BASE);
-       u32 pmc_ctrl;
-
-       /*
-        * Configure the power management controller to trigger PMU
-        * interrupts when low
-        */
-       pmc_ctrl = readl(pmc + PMC_CTRL);
-       writel(pmc_ctrl | PMC_CTRL_INTR_LOW, pmc + PMC_CTRL);
-
        i2c_register_board_info(3, harmony_regulators, 1);
 
        return 0;
index 789bdc9..c00aadb 100644 (file)
@@ -101,7 +101,6 @@ static struct wm8903_platform_data harmony_wm8903_pdata = {
 static struct i2c_board_info __initdata wm8903_board_info = {
        I2C_BOARD_INFO("wm8903", 0x1a),
        .platform_data = &harmony_wm8903_pdata,
-       .irq = TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_CDC_IRQ),
 };
 
 static void __init harmony_i2c_init(void)
@@ -111,6 +110,7 @@ static void __init harmony_i2c_init(void)
        platform_device_register(&tegra_i2c_device3);
        platform_device_register(&tegra_i2c_device4);
 
+       wm8903_board_info.irq = gpio_to_irq(TEGRA_GPIO_CDC_IRQ);
        i2c_register_board_info(0, &wm8903_board_info, 1);
 }
 
index ebac65f..d669847 100644 (file)
@@ -159,7 +159,6 @@ static struct platform_device *seaboard_devices[] __initdata = {
 
 static struct i2c_board_info __initdata isl29018_device = {
        I2C_BOARD_INFO("isl29018", 0x44),
-       .irq = TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_ISL29018_IRQ),
 };
 
 static struct i2c_board_info __initdata adt7461_device = {
@@ -183,7 +182,6 @@ static struct wm8903_platform_data wm8903_pdata = {
 static struct i2c_board_info __initdata wm8903_device = {
        I2C_BOARD_INFO("wm8903", 0x1a),
        .platform_data = &wm8903_pdata,
-       .irq = TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_CDC_IRQ),
 };
 
 static int seaboard_ehci_init(void)
@@ -214,7 +212,10 @@ static void __init seaboard_i2c_init(void)
        gpio_request(TEGRA_GPIO_ISL29018_IRQ, "isl29018");
        gpio_direction_input(TEGRA_GPIO_ISL29018_IRQ);
 
+       isl29018_device.irq = gpio_to_irq(TEGRA_GPIO_ISL29018_IRQ);
        i2c_register_board_info(0, &isl29018_device, 1);
+
+       wm8903_device.irq = gpio_to_irq(TEGRA_GPIO_CDC_IRQ);
        i2c_register_board_info(0, &wm8903_device, 1);
 
        i2c_register_board_info(3, &adt7461_device, 1);
index 8337068..8dad8d1 100644 (file)
@@ -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)
index 5c44106..bc30065 100644 (file)
@@ -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)
 #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);
index 2db20da..68815ce 100644 (file)
 #include <asm/hardware/gic.h>
 
 #include <mach/iomap.h>
+#include <mach/powergate.h>
 
 #include "board.h"
 #include "clock.h"
 #include "fuse.h"
+#include "pmc.h"
+
+/*
+ * Storage for debug-macro.S's state.
+ *
+ * This must be in .data not .bss so that it gets initialized each time the
+ * kernel is loaded. The data is declared here rather than debug-macro.S so
+ * that multiple inclusions of debug-macro.S point at the same data.
+ */
+#define TEGRA_DEBUG_UART_OFFSET (TEGRA_DEBUG_UART_BASE & 0xFFFF)
+u32 tegra_uart_config[3] = {
+       /* Debug UART initialization required */
+       1,
+       /* Debug UART physical address */
+       (u32)(IO_APB_PHYS + TEGRA_DEBUG_UART_OFFSET),
+       /* Debug UART virtual address */
+       (u32)(IO_APB_VIRT + TEGRA_DEBUG_UART_OFFSET),
+};
 
 #ifdef CONFIG_OF
 static const struct of_device_id tegra_dt_irq_match[] __initconst = {
@@ -101,11 +120,17 @@ void __init tegra20_init_early(void)
        tegra2_init_clocks();
        tegra_clk_init_from_table(tegra20_clk_init_table);
        tegra_init_cache(0x331, 0x441);
+       tegra_pmc_init();
+       tegra_powergate_init();
 }
 #endif
 #ifdef CONFIG_ARCH_TEGRA_3x_SOC
 void __init tegra30_init_early(void)
 {
+       tegra_init_fuse();
+       tegra30_init_clocks();
        tegra_init_cache(0x441, 0x551);
+       tegra_pmc_init();
+       tegra_powergate_init();
 }
 #endif
diff --git a/arch/arm/mach-tegra/cpuidle.c b/arch/arm/mach-tegra/cpuidle.c
new file mode 100644 (file)
index 0000000..d83a8c0
--- /dev/null
@@ -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);
index c0cf967..abea4f6 100644 (file)
@@ -33,6 +33,8 @@
 #include <mach/iomap.h>
 #include <mach/suspend.h>
 
+#include "apbio.h"
+
 #define APB_DMA_GEN                            0x000
 #define GEN_ENABLE                             (1<<31)
 
@@ -50,8 +52,6 @@
 #define CSR_ONCE                               (1<<27)
 #define CSR_FLOW                               (1<<21)
 #define CSR_REQ_SEL_SHIFT                      16
-#define CSR_REQ_SEL_MASK                       (0x1F<<CSR_REQ_SEL_SHIFT)
-#define CSR_REQ_SEL_INVALID                    (31<<CSR_REQ_SEL_SHIFT)
 #define CSR_WCOUNT_SHIFT                       2
 #define CSR_WCOUNT_MASK                                0xFFFC
 
@@ -133,6 +133,7 @@ struct tegra_dma_channel {
 
 static bool tegra_dma_initialized;
 static DEFINE_MUTEX(tegra_dma_lock);
+static DEFINE_SPINLOCK(enable_lock);
 
 static DECLARE_BITMAP(channel_usage, NV_DMA_MAX_CHANNELS);
 static struct tegra_dma_channel dma_channels[NV_DMA_MAX_CHANNELS];
@@ -180,36 +181,94 @@ static void tegra_dma_stop(struct tegra_dma_channel *ch)
 
 static int tegra_dma_cancel(struct tegra_dma_channel *ch)
 {
-       u32 csr;
        unsigned long irq_flags;
 
        spin_lock_irqsave(&ch->lock, irq_flags);
        while (!list_empty(&ch->list))
                list_del(ch->list.next);
 
-       csr = readl(ch->addr + APB_DMA_CHAN_CSR);
-       csr &= ~CSR_REQ_SEL_MASK;
-       csr |= CSR_REQ_SEL_INVALID;
-       writel(csr, ch->addr + APB_DMA_CHAN_CSR);
-
        tegra_dma_stop(ch);
 
        spin_unlock_irqrestore(&ch->lock, irq_flags);
        return 0;
 }
 
+static unsigned int get_channel_status(struct tegra_dma_channel *ch,
+                       struct tegra_dma_req *req, bool is_stop_dma)
+{
+       void __iomem *addr = IO_ADDRESS(TEGRA_APB_DMA_BASE);
+       unsigned int status;
+
+       if (is_stop_dma) {
+               /*
+                * STOP the DMA and get the transfer count.
+                * Getting the transfer count is tricky.
+                *  - Globally disable DMA on all channels
+                *  - Read the channel's status register to know the number
+                *    of pending bytes to be transfered.
+                *  - Stop the dma channel
+                *  - Globally re-enable DMA to resume other transfers
+                */
+               spin_lock(&enable_lock);
+               writel(0, addr + APB_DMA_GEN);
+               udelay(20);
+               status = readl(ch->addr + APB_DMA_CHAN_STA);
+               tegra_dma_stop(ch);
+               writel(GEN_ENABLE, addr + APB_DMA_GEN);
+               spin_unlock(&enable_lock);
+               if (status & STA_ISE_EOC) {
+                       pr_err("Got Dma Int here clearing");
+                       writel(status, ch->addr + APB_DMA_CHAN_STA);
+               }
+               req->status = TEGRA_DMA_REQ_ERROR_ABORTED;
+       } else {
+               status = readl(ch->addr + APB_DMA_CHAN_STA);
+       }
+       return status;
+}
+
+/* should be called with the channel lock held */
+static unsigned int dma_active_count(struct tegra_dma_channel *ch,
+       struct tegra_dma_req *req, unsigned int status)
+{
+       unsigned int to_transfer;
+       unsigned int req_transfer_count;
+       unsigned int bytes_transferred;
+
+       to_transfer = ((status & STA_COUNT_MASK) >> STA_COUNT_SHIFT) + 1;
+       req_transfer_count = ch->req_transfer_count + 1;
+       bytes_transferred = req_transfer_count;
+       if (status & STA_BUSY)
+               bytes_transferred -= to_transfer;
+       /*
+        * In continuous transfer mode, DMA only tracks the count of the
+        * half DMA buffer. So, if the DMA already finished half the DMA
+        * then add the half buffer to the completed count.
+        */
+       if (ch->mode & TEGRA_DMA_MODE_CONTINOUS) {
+               if (req->buffer_status == TEGRA_DMA_REQ_BUF_STATUS_HALF_FULL)
+                       bytes_transferred += req_transfer_count;
+               if (status & STA_ISE_EOC)
+                       bytes_transferred += req_transfer_count;
+       }
+       bytes_transferred *= 4;
+       return bytes_transferred;
+}
+
 int tegra_dma_dequeue_req(struct tegra_dma_channel *ch,
        struct tegra_dma_req *_req)
 {
-       unsigned int csr;
        unsigned int status;
        struct tegra_dma_req *req = NULL;
        int found = 0;
        unsigned long irq_flags;
-       int to_transfer;
-       int req_transfer_count;
+       int stop = 0;
 
        spin_lock_irqsave(&ch->lock, irq_flags);
+
+       if (list_entry(ch->list.next, struct tegra_dma_req, node) == _req)
+               stop = 1;
+
        list_for_each_entry(req, &ch->list, node) {
                if (req == _req) {
                        list_del(&req->node);
@@ -222,47 +281,12 @@ int tegra_dma_dequeue_req(struct tegra_dma_channel *ch,
                return 0;
        }
 
-       /* STOP the DMA and get the transfer count.
-        * Getting the transfer count is tricky.
-        *  - Change the source selector to invalid to stop the DMA from
-        *    FIFO to memory.
-        *  - Read the status register to know the number of pending
-        *    bytes to be transferred.
-        *  - Finally stop or program the DMA to the next buffer in the
-        *    list.
-        */
-       csr = readl(ch->addr + APB_DMA_CHAN_CSR);
-       csr &= ~CSR_REQ_SEL_MASK;
-       csr |= CSR_REQ_SEL_INVALID;
-       writel(csr, ch->addr + APB_DMA_CHAN_CSR);
-
-       /* Get the transfer count */
-       status = readl(ch->addr + APB_DMA_CHAN_STA);
-       to_transfer = (status & STA_COUNT_MASK) >> STA_COUNT_SHIFT;
-       req_transfer_count = ch->req_transfer_count;
-       req_transfer_count += 1;
-       to_transfer += 1;
-
-       req->bytes_transferred = req_transfer_count;
-
-       if (status & STA_BUSY)
-               req->bytes_transferred -= to_transfer;
-
-       /* In continuous transfer mode, DMA only tracks the count of the
-        * half DMA buffer. So, if the DMA already finished half the DMA
-        * then add the half buffer to the completed count.
-        *
-        *      FIXME: There can be a race here. What if the req to
-        *      dequue happens at the same time as the DMA just moved to
-        *      the new buffer and SW didn't yet received the interrupt?
-        */
-       if (ch->mode & TEGRA_DMA_MODE_CONTINOUS)
-               if (req->buffer_status == TEGRA_DMA_REQ_BUF_STATUS_HALF_FULL)
-                       req->bytes_transferred += req_transfer_count;
+       if (!stop)
+               goto skip_stop_dma;
 
-       req->bytes_transferred *= 4;
+       status = get_channel_status(ch, req, true);
+       req->bytes_transferred = dma_active_count(ch, req, status);
 
-       tegra_dma_stop(ch);
        if (!list_empty(&ch->list)) {
                /* if the list is not empty, queue the next request */
                struct tegra_dma_req *next_req;
@@ -270,6 +294,8 @@ int tegra_dma_dequeue_req(struct tegra_dma_channel *ch,
                        typeof(*next_req), node);
                tegra_dma_update_hw(ch, next_req);
        }
+
+skip_stop_dma:
        req->status = -TEGRA_DMA_REQ_ERROR_ABORTED;
 
        spin_unlock_irqrestore(&ch->lock, irq_flags);
@@ -357,7 +383,7 @@ struct tegra_dma_channel *tegra_dma_allocate_channel(int mode)
        int channel;
        struct tegra_dma_channel *ch = NULL;
 
-       if (WARN_ON(!tegra_dma_initialized))
+       if (!tegra_dma_initialized)
                return NULL;
 
        mutex_lock(&tegra_dma_lock);
diff --git a/arch/arm/mach-tegra/flowctrl.c b/arch/arm/mach-tegra/flowctrl.c
new file mode 100644 (file)
index 0000000..fef66a7
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * arch/arm/mach-tegra/flowctrl.c
+ *
+ * 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/>.
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/io.h>
+
+#include <mach/iomap.h>
+
+#include "flowctrl.h"
+
+u8 flowctrl_offset_halt_cpu[] = {
+       FLOW_CTRL_HALT_CPU0_EVENTS,
+       FLOW_CTRL_HALT_CPU1_EVENTS,
+       FLOW_CTRL_HALT_CPU1_EVENTS + 8,
+       FLOW_CTRL_HALT_CPU1_EVENTS + 16,
+};
+
+u8 flowctrl_offset_cpu_csr[] = {
+       FLOW_CTRL_CPU0_CSR,
+       FLOW_CTRL_CPU1_CSR,
+       FLOW_CTRL_CPU1_CSR + 8,
+       FLOW_CTRL_CPU1_CSR + 16,
+};
+
+static void flowctrl_update(u8 offset, u32 value)
+{
+       void __iomem *addr = IO_ADDRESS(TEGRA_FLOW_CTRL_BASE) + offset;
+
+       writel(value, addr);
+
+       /* ensure the update has reached the flow controller */
+       wmb();
+       readl_relaxed(addr);
+}
+
+void flowctrl_write_cpu_csr(unsigned int cpuid, u32 value)
+{
+       return flowctrl_update(flowctrl_offset_halt_cpu[cpuid], value);
+}
+
+void flowctrl_write_cpu_halt(unsigned int cpuid, u32 value)
+{
+       return flowctrl_update(flowctrl_offset_cpu_csr[cpuid], value);
+}
diff --git a/arch/arm/mach-tegra/flowctrl.h b/arch/arm/mach-tegra/flowctrl.h
new file mode 100644 (file)
index 0000000..1942817
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * 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
+
+#ifndef __ASSEMBLY__
+void flowctrl_write_cpu_csr(unsigned int cpuid, u32 value);
+void flowctrl_write_cpu_halt(unsigned int cpuid, u32 value);
+#endif
+
+#endif
index 1fa26d9..027f2b2 100644 (file)
 #include <mach/iomap.h>
 
 #include "fuse.h"
+#include "apbio.h"
 
 #define FUSE_UID_LOW           0x108
 #define FUSE_UID_HIGH          0x10c
 #define FUSE_SKU_INFO          0x110
 #define FUSE_SPARE_BIT         0x200
 
-static inline u32 fuse_readl(unsigned long offset)
+int tegra_sku_id;
+int tegra_cpu_process_id;
+int tegra_core_process_id;
+int tegra_chip_id;
+enum tegra_revision tegra_revision;
+
+/* The BCT to use at boot is specified by board straps that can be read
+ * through a APB misc register and decoded. 2 bits, i.e. 4 possible BCTs.
+ */
+int tegra_bct_strapping;
+
+#define STRAP_OPT 0x008
+#define GMI_AD0 (1 << 4)
+#define GMI_AD1 (1 << 5)
+#define RAM_ID_MASK (GMI_AD0 | GMI_AD1)
+#define RAM_CODE_SHIFT 4
+
+static const char *tegra_revision_name[TEGRA_REVISION_MAX] = {
+       [TEGRA_REVISION_UNKNOWN] = "unknown",
+       [TEGRA_REVISION_A01]     = "A01",
+       [TEGRA_REVISION_A02]     = "A02",
+       [TEGRA_REVISION_A03]     = "A03",
+       [TEGRA_REVISION_A03p]    = "A03 prime",
+       [TEGRA_REVISION_A04]     = "A04",
+};
+
+static inline u32 tegra_fuse_readl(unsigned long offset)
 {
-       return readl(IO_TO_VIRT(TEGRA_FUSE_BASE + offset));
+       return tegra_apb_readl(TEGRA_FUSE_BASE + offset);
 }
 
-static inline void fuse_writel(u32 value, unsigned long offset)
+static inline bool get_spare_fuse(int bit)
 {
-       writel(value, IO_TO_VIRT(TEGRA_FUSE_BASE + offset));
+       return tegra_fuse_readl(FUSE_SPARE_BIT + bit * 4);
+}
+
+static enum tegra_revision tegra_get_revision(u32 id)
+{
+       u32 minor_rev = (id >> 16) & 0xf;
+
+       switch (minor_rev) {
+       case 1:
+               return TEGRA_REVISION_A01;
+       case 2:
+               return TEGRA_REVISION_A02;
+       case 3:
+               if (tegra_chip_id == TEGRA20 &&
+                       (get_spare_fuse(18) || get_spare_fuse(19)))
+                       return TEGRA_REVISION_A03p;
+               else
+                       return TEGRA_REVISION_A03;
+       case 4:
+               return TEGRA_REVISION_A04;
+       default:
+               return TEGRA_REVISION_UNKNOWN;
+       }
 }
 
 void tegra_init_fuse(void)
 {
+       u32 id;
+
        u32 reg = readl(IO_TO_VIRT(TEGRA_CLK_RESET_BASE + 0x48));
        reg |= 1 << 28;
        writel(reg, IO_TO_VIRT(TEGRA_CLK_RESET_BASE + 0x48));
 
-       pr_info("Tegra SKU: %d CPU Process: %d Core Process: %d\n",
-               tegra_sku_id(), tegra_cpu_process_id(),
-               tegra_core_process_id());
-}
+       reg = tegra_fuse_readl(FUSE_SKU_INFO);
+       tegra_sku_id = reg & 0xFF;
 
-unsigned long long tegra_chip_uid(void)
-{
-       unsigned long long lo, hi;
+       reg = tegra_fuse_readl(FUSE_SPARE_BIT);
+       tegra_cpu_process_id = (reg >> 6) & 3;
 
-       lo = fuse_readl(FUSE_UID_LOW);
-       hi = fuse_readl(FUSE_UID_HIGH);
-       return (hi << 32ull) | lo;
-}
+       reg = tegra_fuse_readl(FUSE_SPARE_BIT);
+       tegra_core_process_id = (reg >> 12) & 3;
 
-int tegra_sku_id(void)
-{
-       int sku_id;
-       u32 reg = fuse_readl(FUSE_SKU_INFO);
-       sku_id = reg & 0xFF;
-       return sku_id;
-}
+       reg = tegra_apb_readl(TEGRA_APB_MISC_BASE + STRAP_OPT);
+       tegra_bct_strapping = (reg & RAM_ID_MASK) >> RAM_CODE_SHIFT;
 
-int tegra_cpu_process_id(void)
-{
-       int cpu_process_id;
-       u32 reg = fuse_readl(FUSE_SPARE_BIT);
-       cpu_process_id = (reg >> 6) & 3;
-       return cpu_process_id;
+       id = readl_relaxed(IO_ADDRESS(TEGRA_APB_MISC_BASE) + 0x804);
+       tegra_chip_id = (id >> 8) & 0xff;
+
+       tegra_revision = tegra_get_revision(id);
+
+       pr_info("Tegra Revision: %s SKU: %d CPU Process: %d Core Process: %d\n",
+               tegra_revision_name[tegra_revision],
+               tegra_sku_id, tegra_cpu_process_id,
+               tegra_core_process_id);
 }
 
-int tegra_core_process_id(void)
+unsigned long long tegra_chip_uid(void)
 {
-       int core_process_id;
-       u32 reg = fuse_readl(FUSE_SPARE_BIT);
-       core_process_id = (reg >> 12) & 3;
-       return core_process_id;
+       unsigned long long lo, hi;
+
+       lo = tegra_fuse_readl(FUSE_UID_LOW);
+       hi = tegra_fuse_readl(FUSE_UID_HIGH);
+       return (hi << 32ull) | lo;
 }
index 584b2e2..d2107b2 100644 (file)
@@ -1,6 +1,4 @@
 /*
- * arch/arm/mach-tegra/fuse.c
- *
  * Copyright (C) 2010 Google, Inc.
  *
  * Author:
  *
  */
 
+#ifndef __MACH_TEGRA_FUSE_H
+#define __MACH_TEGRA_FUSE_H
+
+enum tegra_revision {
+       TEGRA_REVISION_UNKNOWN = 0,
+       TEGRA_REVISION_A01,
+       TEGRA_REVISION_A02,
+       TEGRA_REVISION_A03,
+       TEGRA_REVISION_A03p,
+       TEGRA_REVISION_A04,
+       TEGRA_REVISION_MAX,
+};
+
+#define SKU_ID_T20     8
+#define SKU_ID_T25SE   20
+#define SKU_ID_AP25    23
+#define SKU_ID_T25     24
+#define SKU_ID_AP25E   27
+#define SKU_ID_T25E    28
+
+#define TEGRA20                0x20
+#define TEGRA30                0x30
+
+extern int tegra_sku_id;
+extern int tegra_cpu_process_id;
+extern int tegra_core_process_id;
+extern int tegra_chip_id;
+extern enum tegra_revision tegra_revision;
+
+extern int tegra_bct_strapping;
+
 unsigned long long tegra_chip_uid(void);
-int tegra_sku_id(void);
-int tegra_cpu_process_id(void);
-int tegra_core_process_id(void);
 void tegra_init_fuse(void);
+
+#endif
index b5349b2..fef9c2c 100644 (file)
@@ -1,6 +1,23 @@
 #include <linux/linkage.h>
 #include <linux/init.h>
 
+#include <asm/cache.h>
+
+#include <mach/iomap.h>
+
+#include "flowctrl.h"
+#include "reset.h"
+
+#define APB_MISC_GP_HIDREV     0x804
+#define PMC_SCRATCH41  0x140
+
+#define RESET_DATA(x)  ((TEGRA_RESET_##x)*4)
+
+       .macro mov32, reg, val
+       movw    \reg, #:lower16:\val
+       movt    \reg, #:upper16:\val
+       .endm
+
         .section ".text.head", "ax"
        __CPUINIT
 
@@ -47,15 +64,149 @@ ENTRY(v7_invalidate_l1)
         mov     pc, lr
 ENDPROC(v7_invalidate_l1)
 
+
 ENTRY(tegra_secondary_startup)
-       msr     cpsr_fsxc, #0xd3
         bl      v7_invalidate_l1
-       mrc     p15, 0, r0, c0, c0, 5
-        and    r0, r0, #15
-        ldr     r1, =0x6000f100
-        str     r0, [r1]
-1:      ldr     r2, [r1]
-        cmp     r0, r2
-        beq     1b
+       /* Enable coresight */
+       mov32   r0, 0xC5ACCE55
+       mcr     p14, 0, r0, c7, c12, 6
         b       secondary_startup
 ENDPROC(tegra_secondary_startup)
+
+       .align L1_CACHE_SHIFT
+ENTRY(__tegra_cpu_reset_handler_start)
+
+/*
+ * __tegra_cpu_reset_handler:
+ *
+ * Common handler for all CPU reset events.
+ *
+ * Register usage within the reset handler:
+ *
+ *      R7  = CPU present (to the OS) mask
+ *      R8  = CPU in LP1 state mask
+ *      R9  = CPU in LP2 state mask
+ *      R10 = CPU number
+ *      R11 = CPU mask
+ *      R12 = pointer to reset handler data
+ *
+ * NOTE: This code is copied to IRAM. All code and data accesses
+ *       must be position-independent.
+ */
+
+       .align L1_CACHE_SHIFT
+ENTRY(__tegra_cpu_reset_handler)
+
+       cpsid   aif, 0x13                       @ SVC mode, interrupts disabled
+       mrc     p15, 0, r10, c0, c0, 5          @ MPIDR
+       and     r10, r10, #0x3                  @ R10 = CPU number
+       mov     r11, #1
+       mov     r11, r11, lsl r10               @ R11 = CPU mask
+       adr     r12, __tegra_cpu_reset_handler_data
+
+#ifdef CONFIG_SMP
+       /* Does the OS know about this CPU? */
+       ldr     r7, [r12, #RESET_DATA(MASK_PRESENT)]
+       tst     r7, r11                         @ if !present
+       bleq    __die                           @ CPU not present (to OS)
+#endif
+
+#ifdef CONFIG_ARCH_TEGRA_2x_SOC
+       /* Are we on Tegra20? */
+       mov32   r6, TEGRA_APB_MISC_BASE
+       ldr     r0, [r6, #APB_MISC_GP_HIDREV]
+       and     r0, r0, #0xff00
+       cmp     r0, #(0x20 << 8)
+       bne     1f
+       /* If not CPU0, don't let CPU0 reset CPU1 now that CPU1 is coming up. */
+       mov32   r6, TEGRA_PMC_BASE
+       mov     r0, #0
+       cmp     r10, #0
+       strne   r0, [r6, #PMC_SCRATCH41]
+1:
+#endif
+
+#ifdef CONFIG_SMP
+       /*
+        * Can only be secondary boot (initial or hotplug) but CPU 0
+        * cannot be here.
+        */
+       cmp     r10, #0
+       bleq    __die                           @ CPU0 cannot be here
+       ldr     lr, [r12, #RESET_DATA(STARTUP_SECONDARY)]
+       cmp     lr, #0
+       bleq    __die                           @ no secondary startup handler
+       bx      lr
+#endif
+
+/*
+ * We don't know why the CPU reset. Just kill it.
+ * The LR register will contain the address we died at + 4.
+ */
+
+__die:
+       sub     lr, lr, #4
+       mov32   r7, TEGRA_PMC_BASE
+       str     lr, [r7, #PMC_SCRATCH41]
+
+       mov32   r7, TEGRA_CLK_RESET_BASE
+
+       /* Are we on Tegra20? */
+       mov32   r6, TEGRA_APB_MISC_BASE
+       ldr     r0, [r6, #APB_MISC_GP_HIDREV]
+       and     r0, r0, #0xff00
+       cmp     r0, #(0x20 << 8)
+       bne     1f
+
+#ifdef CONFIG_ARCH_TEGRA_2x_SOC
+       mov32   r0, 0x1111
+       mov     r1, r0, lsl r10
+       str     r1, [r7, #0x340]                @ CLK_RST_CPU_CMPLX_SET
+#endif
+1:
+#ifdef CONFIG_ARCH_TEGRA_3x_SOC
+       mov32   r6, TEGRA_FLOW_CTRL_BASE
+
+       cmp     r10, #0
+       moveq   r1, #FLOW_CTRL_HALT_CPU0_EVENTS
+       moveq   r2, #FLOW_CTRL_CPU0_CSR
+       movne   r1, r10, lsl #3
+       addne   r2, r1, #(FLOW_CTRL_CPU1_CSR-8)
+       addne   r1, r1, #(FLOW_CTRL_HALT_CPU1_EVENTS-8)
+
+       /* Clear CPU "event" and "interrupt" flags and power gate
+          it when halting but not before it is in the "WFI" state. */
+       ldr     r0, [r6, +r2]
+       orr     r0, r0, #FLOW_CTRL_CSR_INTR_FLAG | FLOW_CTRL_CSR_EVENT_FLAG
+       orr     r0, r0, #FLOW_CTRL_CSR_ENABLE
+       str     r0, [r6, +r2]
+
+       /* Unconditionally halt this CPU */
+       mov     r0, #FLOW_CTRL_WAITEVENT
+       str     r0, [r6, +r1]
+       ldr     r0, [r6, +r1]                   @ memory barrier
+
+       dsb
+       isb
+       wfi                                     @ CPU should be power gated here
+
+       /* If the CPU didn't power gate above just kill it's clock. */
+
+       mov     r0, r11, lsl #8
+       str     r0, [r7, #348]                  @ CLK_CPU_CMPLX_SET
+#endif
+
+       /* If the CPU still isn't dead, just spin here. */
+       b       .
+ENDPROC(__tegra_cpu_reset_handler)
+
+       .align L1_CACHE_SHIFT
+       .type   __tegra_cpu_reset_handler_data, %object
+       .globl  __tegra_cpu_reset_handler_data
+__tegra_cpu_reset_handler_data:
+       .rept   TEGRA_RESET_DATA_SIZE
+       .long   0
+       .endr
+       .align L1_CACHE_SHIFT
+
+ENTRY(__tegra_cpu_reset_handler_end)
index fc3ecb6..d97e403 100644 (file)
 
 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
index 619abc6..90069ab 100644 (file)
@@ -1,11 +1,17 @@
 /*
  * arch/arm/mach-tegra/include/mach/debug-macro.S
  *
- * Copyright (C) 2010 Google, Inc.
+ * Copyright (C) 2010,2011 Google, Inc.
+ * Copyright (C) 2011-2012 NVIDIA CORPORATION. All Rights Reserved.
  *
  * Author:
  *     Colin Cross <ccross@google.com>
  *     Erik Gilling <konkers@google.com>
+ *     Doug Anderson <dianders@chromium.org>
+ *     Stephen Warren <swarren@nvidia.com>
+ *
+ * Portions based on mach-omap2's debug-macro.S
+ * Copyright (C) 1994-1999 Russell King
  *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
  *
  */
 
+#include <linux/serial_reg.h>
+
 #include <mach/io.h>
 #include <mach/iomap.h>
+#include <mach/irammap.h>
+
+               .macro  addruart, rp, rv, tmp
+               adr     \rp, 99f                @ actual addr of 99f
+               ldr     \rv, [\rp]              @ linked addr is stored there
+               sub     \rv, \rv, \rp           @ offset between the two
+               ldr     \rp, [\rp, #4]          @ linked tegra_uart_config
+               sub     \tmp, \rp, \rv          @ actual tegra_uart_config
+               ldr     \rp, [\tmp]             @ Load tegra_uart_config
+               cmp     \rp, #1                 @ needs intitialization?
+               bne     100f                    @ no; go load the addresses
+               mov     \rv, #0                 @ yes; record init is done
+               str     \rv, [\tmp]
+               mov     \rp, #TEGRA_IRAM_BASE   @ See if cookie is in IRAM
+               ldr     \rv, [\rp, #TEGRA_IRAM_DEBUG_UART_OFFSET]
+               movw    \rp, #TEGRA_IRAM_DEBUG_UART_COOKIE & 0xffff
+               movt    \rp, #TEGRA_IRAM_DEBUG_UART_COOKIE >> 16
+               cmp     \rv, \rp                @ Cookie present?
+               bne     100f                    @ No, use default UART
+               mov     \rp, #TEGRA_IRAM_BASE   @ Load UART address from IRAM
+               ldr     \rv, [\rp, #TEGRA_IRAM_DEBUG_UART_OFFSET + 4]
+               str     \rv, [\tmp, #4]         @ Store in tegra_uart_phys
+               sub     \rv, \rv, #IO_APB_PHYS  @ Calculate virt address
+               add     \rv, \rv, #IO_APB_VIRT
+               str     \rv, [\tmp, #8]         @ Store in tegra_uart_virt
+               b       100f
+
+               .align
+99:            .word   .
+               .word   tegra_uart_config
+               .ltorg
+
+100:           ldr     \rp, [\tmp, #4]         @ Load tegra_uart_phys
+               ldr     \rv, [\tmp, #8]         @ Load tegra_uart_virt
+               .endm
+
+#define UART_SHIFT 2
+
+/*
+ * Code below is swiped from <asm/hardware/debug-8250.S>, but add an extra
+ * check to make sure that we aren't in the CONFIG_TEGRA_DEBUG_UART_NONE case.
+ * We use the fact that all 5 valid UART addresses all have something in the
+ * 2nd-to-lowest byte.
+ */
 
-       .macro  addruart, rp, rv, tmp
-        ldr     \rp, =IO_APB_PHYS       @ physical
-        ldr     \rv, =IO_APB_VIRT        @ virtual
-       orr     \rp, \rp, #(TEGRA_DEBUG_UART_BASE & 0xFF)
-       orr     \rp, \rp, #(TEGRA_DEBUG_UART_BASE & 0xFF00)
-       orr     \rv, \rv, #(TEGRA_DEBUG_UART_BASE & 0xFF)
-       orr     \rv, \rv, #(TEGRA_DEBUG_UART_BASE & 0xFF00)
-       .endm
+               .macro  senduart, rd, rx
+               tst     \rx, #0x0000ff00
+               strneb  \rd, [\rx, #UART_TX << UART_SHIFT]
+1001:
+               .endm
 
-#define UART_SHIFT     2
-#include <asm/hardware/debug-8250.S>
+               .macro  busyuart, rd, rx
+               tst     \rx, #0x0000ff00
+               beq     1002f
+1001:          ldrb    \rd, [\rx, #UART_LSR << UART_SHIFT]
+               and     \rd, \rd, #UART_LSR_TEMT | UART_LSR_THRE
+               teq     \rd, #UART_LSR_TEMT | UART_LSR_THRE
+               bne     1001b
+1002:
+               .endm
 
+               .macro  waituart, rd, rx
+#ifdef FLOW_CONTROL
+               tst     \rx, #0x0000ff00
+               beq     1002f
+1001:          ldrb    \rd, [\rx, #UART_MSR << UART_SHIFT]
+               tst     \rd, #UART_MSR_CTS
+               beq     1001b
+1002:
+#endif
+               .endm
index 87d37fd..6140820 100644 (file)
@@ -25,8 +25,6 @@
 
 #define TEGRA_NR_GPIOS         INT_GPIO_NR
 
-#define TEGRA_GPIO_TO_IRQ(gpio) (INT_GPIO_BASE + (gpio))
-
 struct tegra_gpio_table {
        int     gpio;   /* GPIO number */
        bool    enable; /* Enable for GPIO at init? */
index 19dec3a..cff672a 100644 (file)
@@ -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
 
 #define TEGRA_AHB_GIZMO_BASE           0x6000C004
 #define TEGRA_AHB_GIZMO_SIZE           0x10C
 
+#define TEGRA_SB_BASE                  0x6000C200
+#define TEGRA_SB_SIZE                  256
+
 #define TEGRA_STATMON_BASE             0x6000C400
 #define TEGRA_STATMON_SIZE             SZ_1K
 
diff --git a/arch/arm/mach-tegra/include/mach/irammap.h b/arch/arm/mach-tegra/include/mach/irammap.h
new file mode 100644 (file)
index 0000000..0cbe632
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 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 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_IRAMMAP_H
+#define __MACH_TEGRA_IRAMMAP_H
+
+#include <asm/sizes.h>
+
+/* The first 1K of IRAM is permanently reserved for the CPU reset handler */
+#define TEGRA_IRAM_RESET_HANDLER_OFFSET        0
+#define TEGRA_IRAM_RESET_HANDLER_SIZE  SZ_1K
+
+/*
+ * These locations are written to by uncompress.h, and read by debug-macro.S.
+ * The first word holds the cookie value if the data is valid. The second
+ * word holds the UART physical address.
+ */
+#define TEGRA_IRAM_DEBUG_UART_OFFSET   SZ_1K
+#define TEGRA_IRAM_DEBUG_UART_SIZE     8
+#define TEGRA_IRAM_DEBUG_UART_COOKIE   0x55415254
+
+#endif
index a2146cd..aad1a2c 100644 (file)
 #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)
 
index 39c396d..4752b1a 100644 (file)
 #define TEGRA_POWERGATE_VDEC   4
 #define TEGRA_POWERGATE_L2     5
 #define TEGRA_POWERGATE_MPE    6
-#define TEGRA_NUM_POWERGATE    7
+#define TEGRA_POWERGATE_HEG    7
+#define TEGRA_POWERGATE_SATA   8
+#define TEGRA_POWERGATE_CPU1   9
+#define TEGRA_POWERGATE_CPU2   10
+#define TEGRA_POWERGATE_CPU3   11
+#define TEGRA_POWERGATE_CELP   12
+#define TEGRA_POWERGATE_3D1    13
 
+#define TEGRA_POWERGATE_CPU0   TEGRA_POWERGATE_CPU
+#define TEGRA_POWERGATE_3D0    TEGRA_POWERGATE_3D
+
+int  __init tegra_powergate_init(void);
+
+int tegra_cpu_powergate_id(int cpuid);
+int tegra_powergate_is_powered(int id);
 int tegra_powergate_power_on(int id);
 int tegra_powergate_power_off(int id);
 int tegra_powergate_remove_clamping(int id);
index 4e83237..b066ba0 100644 (file)
@@ -2,10 +2,14 @@
  * arch/arm/mach-tegra/include/mach/uncompress.h
  *
  * Copyright (C) 2010 Google, Inc.
+ * Copyright (C) 2011 Google, Inc.
+ * Copyright (C) 2011-2012 NVIDIA CORPORATION. All Rights Reserved.
  *
  * Author:
  *     Colin Cross <ccross@google.com>
  *     Erik Gilling <konkers@google.com>
+ *     Doug Anderson <dianders@chromium.org>
+ *     Stephen Warren <swarren@nvidia.com>
  *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
 #ifndef __MACH_TEGRA_UNCOMPRESS_H
 #define __MACH_TEGRA_UNCOMPRESS_H
 
+#include <linux/kernel.h>
 #include <linux/types.h>
 #include <linux/serial_reg.h>
 
 #include <mach/iomap.h>
+#include <mach/irammap.h>
+
+#define DEBUG_UART_SHIFT 2
+
+volatile u8 *uart;
 
 static void putc(int c)
 {
-       volatile u8 *uart = (volatile u8 *)TEGRA_DEBUG_UART_BASE;
-       int shift = 2;
-
        if (uart == NULL)
                return;
 
-       while (!(uart[UART_LSR << shift] & UART_LSR_THRE))
+       while (!(uart[UART_LSR << DEBUG_UART_SHIFT] & UART_LSR_THRE))
                barrier();
-       uart[UART_TX << shift] = c;
+       uart[UART_TX << DEBUG_UART_SHIFT] = c;
 }
 
 static inline void flush(void)
 {
 }
 
+static inline void save_uart_address(void)
+{
+       u32 *buf = (u32 *)(TEGRA_IRAM_BASE + TEGRA_IRAM_DEBUG_UART_OFFSET);
+
+       if (uart) {
+               buf[0] = TEGRA_IRAM_DEBUG_UART_COOKIE;
+               buf[1] = (u32)uart;
+       } else
+               buf[0] = 0;
+}
+
+/*
+ * Setup before decompression.  This is where we do UART selection for
+ * earlyprintk and init the uart_base register.
+ */
 static inline void arch_decomp_setup(void)
 {
-       volatile u8 *uart = (volatile u8 *)TEGRA_DEBUG_UART_BASE;
-       int shift = 2;
+       static const struct {
+               u32 base;
+               u32 reset_reg;
+               u32 clock_reg;
+               u32 bit;
+       } uarts[] = {
+               {
+                       TEGRA_UARTA_BASE,
+                       TEGRA_CLK_RESET_BASE + 0x04,
+                       TEGRA_CLK_RESET_BASE + 0x10,
+                       6,
+               },
+               {
+                       TEGRA_UARTB_BASE,
+                       TEGRA_CLK_RESET_BASE + 0x04,
+                       TEGRA_CLK_RESET_BASE + 0x10,
+                       7,
+               },
+               {
+                       TEGRA_UARTC_BASE,
+                       TEGRA_CLK_RESET_BASE + 0x08,
+                       TEGRA_CLK_RESET_BASE + 0x14,
+                       23,
+               },
+               {
+                       TEGRA_UARTD_BASE,
+                       TEGRA_CLK_RESET_BASE + 0x0c,
+                       TEGRA_CLK_RESET_BASE + 0x18,
+                       1,
+               },
+               {
+                       TEGRA_UARTE_BASE,
+                       TEGRA_CLK_RESET_BASE + 0x0c,
+                       TEGRA_CLK_RESET_BASE + 0x18,
+                       2,
+               },
+       };
+       int i;
+       volatile u32 *apb_misc = (volatile u32 *)TEGRA_APB_MISC_BASE;
+       u32 chip, div;
+
+       /*
+        * Look for the first UART that:
+        * a) Is not in reset.
+        * b) Is clocked.
+        * c) Has a 'D' in the scratchpad register.
+        *
+        * Note that on Tegra30, the first two conditions are required, since
+        * if not true, accesses to the UART scratch register will hang.
+        * Tegra20 doesn't have this issue.
+        *
+        * The intent is that the bootloader will tell the kernel which UART
+        * to use by setting up those conditions. If nothing found, we'll fall
+        * back to what's specified in TEGRA_DEBUG_UART_BASE.
+        */
+       for (i = 0; i < ARRAY_SIZE(uarts); i++) {
+               if (*(u8 *)uarts[i].reset_reg & BIT(uarts[i].bit))
+                       continue;
 
+               if (!(*(u8 *)uarts[i].clock_reg & BIT(uarts[i].bit)))
+                       continue;
+
+               uart = (volatile u8 *)uarts[i].base;
+               if (uart[UART_SCR << DEBUG_UART_SHIFT] != 'D')
+                       continue;
+
+               break;
+       }
+       if (i == ARRAY_SIZE(uarts))
+               uart = (volatile u8 *)TEGRA_DEBUG_UART_BASE;
+       save_uart_address();
        if (uart == NULL)
                return;
 
-       uart[UART_LCR << shift] |= UART_LCR_DLAB;
-       uart[UART_DLL << shift] = 0x75;
-       uart[UART_DLM << shift] = 0x0;
-       uart[UART_LCR << shift] = 3;
+       chip = (apb_misc[0x804 / 4] >> 8) & 0xff;
+       if (chip == 0x20)
+               div = 0x0075;
+       else
+               div = 0x00dd;
+
+       uart[UART_LCR << DEBUG_UART_SHIFT] |= UART_LCR_DLAB;
+       uart[UART_DLL << DEBUG_UART_SHIFT] = div & 0xff;
+       uart[UART_DLM << DEBUG_UART_SHIFT] = div >> 8;
+       uart[UART_LCR << DEBUG_UART_SHIFT] = 3;
 }
 
 static inline void arch_decomp_wdog(void)
index 4e1afcd..2f5bd2d 100644 (file)
 #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));
 }
index 7d2b5d0..1a208db 100644 (file)
 #include <asm/mach-types.h>
 #include <asm/smp_scu.h>
 
+#include <mach/clk.h>
 #include <mach/iomap.h>
+#include <mach/powergate.h>
+
+#include "fuse.h"
+#include "flowctrl.h"
+#include "reset.h"
 
 extern void tegra_secondary_startup(void);
 
-static DEFINE_SPINLOCK(boot_lock);
 static void __iomem *scu_base = IO_ADDRESS(TEGRA_ARM_PERIF_BASE);
 
 #define EVP_CPU_RESET_VECTOR \
        (IO_ADDRESS(TEGRA_EXCEPTION_VECTORS_BASE) + 0x100)
 #define CLK_RST_CONTROLLER_CLK_CPU_CMPLX \
        (IO_ADDRESS(TEGRA_CLK_RESET_BASE) + 0x4c)
+#define CLK_RST_CONTROLLER_RST_CPU_CMPLX_SET \
+       (IO_ADDRESS(TEGRA_CLK_RESET_BASE) + 0x340)
 #define CLK_RST_CONTROLLER_RST_CPU_CMPLX_CLR \
        (IO_ADDRESS(TEGRA_CLK_RESET_BASE) + 0x344)
+#define CLK_RST_CONTROLLER_CLK_CPU_CMPLX_CLR \
+       (IO_ADDRESS(TEGRA_CLK_RESET_BASE) + 0x34c)
+
+#define CPU_CLOCK(cpu) (0x1<<(8+cpu))
+#define CPU_RESET(cpu) (0x1111ul<<(cpu))
 
 void __cpuinit platform_secondary_init(unsigned int cpu)
 {
@@ -47,63 +59,106 @@ void __cpuinit platform_secondary_init(unsigned int cpu)
         */
        gic_secondary_init(0);
 
-       /*
-        * Synchronise with the boot thread.
-        */
-       spin_lock(&boot_lock);
-       spin_unlock(&boot_lock);
 }
 
-int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle)
+static int tegra20_power_up_cpu(unsigned int cpu)
 {
-       unsigned long old_boot_vector;
-       unsigned long boot_vector;
-       unsigned long timeout;
        u32 reg;
 
-       /*
-        * set synchronisation state between this boot processor
-        * and the secondary one
-        */
-       spin_lock(&boot_lock);
+       /* Enable the CPU clock. */
+       reg = readl(CLK_RST_CONTROLLER_CLK_CPU_CMPLX);
+       writel(reg & ~CPU_CLOCK(cpu), CLK_RST_CONTROLLER_CLK_CPU_CMPLX);
+       barrier();
+       reg = readl(CLK_RST_CONTROLLER_CLK_CPU_CMPLX);
 
+       /* Clear flow controller CSR. */
+       flowctrl_write_cpu_csr(cpu, 0);
 
-       /* set the reset vector to point to the secondary_startup routine */
+       return 0;
+}
 
-       boot_vector = virt_to_phys(tegra_secondary_startup);
-       old_boot_vector = readl(EVP_CPU_RESET_VECTOR);
-       writel(boot_vector, EVP_CPU_RESET_VECTOR);
+static int tegra30_power_up_cpu(unsigned int cpu)
+{
+       u32 reg;
+       int ret, pwrgateid;
+       unsigned long timeout;
 
-       /* enable cpu clock on cpu1 */
-       reg = readl(CLK_RST_CONTROLLER_CLK_CPU_CMPLX);
-       writel(reg & ~(1<<9), CLK_RST_CONTROLLER_CLK_CPU_CMPLX);
+       pwrgateid = tegra_cpu_powergate_id(cpu);
+       if (pwrgateid < 0)
+               return pwrgateid;
+
+       /* If this is the first boot, toggle powergates directly. */
+       if (!tegra_powergate_is_powered(pwrgateid)) {
+               ret = tegra_powergate_power_on(pwrgateid);
+               if (ret)
+                       return ret;
+
+               /* Wait for the power to come up. */
+               timeout = jiffies + 10*HZ;
+               while (tegra_powergate_is_powered(pwrgateid)) {
+                       if (time_after(jiffies, timeout))
+                               return -ETIMEDOUT;
+                       udelay(10);
+               }
+       }
 
-       reg = (1<<13) | (1<<9) | (1<<5) | (1<<1);
-       writel(reg, CLK_RST_CONTROLLER_RST_CPU_CMPLX_CLR);
+       /* CPU partition is powered. Enable the CPU clock. */
+       writel(CPU_CLOCK(cpu), CLK_RST_CONTROLLER_CLK_CPU_CMPLX_CLR);
+       reg = readl(CLK_RST_CONTROLLER_CLK_CPU_CMPLX_CLR);
+       udelay(10);
 
-       smp_wmb();
-       flush_cache_all();
+       /* Remove I/O clamps. */
+       ret = tegra_powergate_remove_clamping(pwrgateid);
+       udelay(10);
 
-       /* unhalt the cpu */
-       writel(0, IO_ADDRESS(TEGRA_FLOW_CTRL_BASE) + 0x14);
+       /* Clear flow controller CSR. */
+       flowctrl_write_cpu_csr(cpu, 0);
 
-       timeout = jiffies + (1 * HZ);
-       while (time_before(jiffies, timeout)) {
-               if (readl(EVP_CPU_RESET_VECTOR) != boot_vector)
-                       break;
-               udelay(10);
-       }
+       return 0;
+}
+
+int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle)
+{
+       int status;
 
-       /* put the old boot vector back */
-       writel(old_boot_vector, EVP_CPU_RESET_VECTOR);
+       /*
+        * Force the CPU into reset. The CPU must remain in reset when the
+        * flow controller state is cleared (which will cause the flow
+        * controller to stop driving reset if the CPU has been power-gated
+        * via the flow controller). This will have no effect on first boot
+        * of the CPU since it should already be in reset.
+        */
+       writel(CPU_RESET(cpu), CLK_RST_CONTROLLER_RST_CPU_CMPLX_SET);
+       dmb();
 
        /*
-        * now the secondary core is starting up let it run its
-        * calibrations, then wait for it to finish
+        * Unhalt the CPU. If the flow controller was used to power-gate the
+        * CPU this will cause the flow controller to stop driving reset.
+        * The CPU will remain in reset because the clock and reset block
+        * is now driving reset.
         */
-       spin_unlock(&boot_lock);
+       flowctrl_write_cpu_halt(cpu, 0);
+
+       switch (tegra_chip_id) {
+       case TEGRA20:
+               status = tegra20_power_up_cpu(cpu);
+               break;
+       case TEGRA30:
+               status = tegra30_power_up_cpu(cpu);
+               break;
+       default:
+               status = -EINVAL;
+               break;
+       }
 
-       return 0;
+       if (status)
+               goto done;
+
+       /* Take the CPU out of reset. */
+       writel(CPU_RESET(cpu), CLK_RST_CONTROLLER_RST_CPU_CMPLX_CLR);
+       wmb();
+done:
+       return status;
 }
 
 /*
@@ -128,6 +183,6 @@ void __init smp_init_cpus(void)
 
 void __init platform_smp_prepare_cpus(unsigned int max_cpus)
 {
-
+       tegra_cpu_reset_handler_init();
        scu_enable(scu_base);
 }
diff --git a/arch/arm/mach-tegra/pmc.c b/arch/arm/mach-tegra/pmc.c
new file mode 100644 (file)
index 0000000..7af6a54
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 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 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/>.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/io.h>
+#include <linux/of.h>
+
+#include <mach/iomap.h>
+
+#define PMC_CTRL               0x0
+#define PMC_CTRL_INTR_LOW      (1 << 17)
+
+static inline u32 tegra_pmc_readl(u32 reg)
+{
+       return readl(IO_ADDRESS(TEGRA_PMC_BASE + reg));
+}
+
+static inline void tegra_pmc_writel(u32 val, u32 reg)
+{
+       writel(val, IO_ADDRESS(TEGRA_PMC_BASE + reg));
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id matches[] __initconst = {
+       { .compatible = "nvidia,tegra20-pmc" },
+       { }
+};
+#endif
+
+void __init tegra_pmc_init(void)
+{
+       /*
+        * For now, Harmony is the only board that uses the PMC, and it wants
+        * the signal inverted. Seaboard would too if it used the PMC.
+        * Hopefully by the time other boards want to use the PMC, everything
+        * will be device-tree, or they also want it inverted.
+        */
+       bool invert_interrupt = true;
+       u32 val;
+
+#ifdef CONFIG_OF
+       if (of_have_populated_dt()) {
+               struct device_node *np;
+
+               invert_interrupt = false;
+
+               np = of_find_matching_node(NULL, matches);
+               if (np) {
+                       if (of_find_property(np, "nvidia,invert-interrupt",
+                                               NULL))
+                               invert_interrupt = true;
+               }
+       }
+#endif
+
+       val = tegra_pmc_readl(PMC_CTRL);
+       if (invert_interrupt)
+               val |= PMC_CTRL_INTR_LOW;
+       else
+               val &= ~PMC_CTRL_INTR_LOW;
+       tegra_pmc_writel(val, PMC_CTRL);
+}
diff --git a/arch/arm/mach-tegra/pmc.h b/arch/arm/mach-tegra/pmc.h
new file mode 100644 (file)
index 0000000..8995ee4
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 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 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_PMC_H
+#define __MACH_TEGRA_PMC_H
+
+void tegra_pmc_init(void);
+
+#endif
index 9483064..c238699 100644 (file)
@@ -31,6 +31,8 @@
 #include <mach/iomap.h>
 #include <mach/powergate.h>
 
+#include "fuse.h"
+
 #define PWRGATE_TOGGLE         0x30
 #define  PWRGATE_TOGGLE_START  (1 << 8)
 
 
 #define PWRGATE_STATUS         0x38
 
+static int tegra_num_powerdomains;
+static int tegra_num_cpu_domains;
+static u8 *tegra_cpu_domains;
+static u8 tegra30_cpu_domains[] = {
+       TEGRA_POWERGATE_CPU0,
+       TEGRA_POWERGATE_CPU1,
+       TEGRA_POWERGATE_CPU2,
+       TEGRA_POWERGATE_CPU3,
+};
+
 static DEFINE_SPINLOCK(tegra_powergate_lock);
 
 static void __iomem *pmc = IO_ADDRESS(TEGRA_PMC_BASE);
@@ -75,7 +87,7 @@ static int tegra_powergate_set(int id, bool new_state)
 
 int tegra_powergate_power_on(int id)
 {
-       if (id < 0 || id >= TEGRA_NUM_POWERGATE)
+       if (id < 0 || id >= tegra_num_powerdomains)
                return -EINVAL;
 
        return tegra_powergate_set(id, true);
@@ -83,17 +95,18 @@ int tegra_powergate_power_on(int id)
 
 int tegra_powergate_power_off(int id)
 {
-       if (id < 0 || id >= TEGRA_NUM_POWERGATE)
+       if (id < 0 || id >= tegra_num_powerdomains)
                return -EINVAL;
 
        return tegra_powergate_set(id, false);
 }
 
-static bool tegra_powergate_is_powered(int id)
+int tegra_powergate_is_powered(int id)
 {
        u32 status;
 
-       WARN_ON(id < 0 || id >= TEGRA_NUM_POWERGATE);
+       if (id < 0 || id >= tegra_num_powerdomains)
+               return -EINVAL;
 
        status = pmc_read(PWRGATE_STATUS) & (1 << id);
        return !!status;
@@ -103,7 +116,7 @@ int tegra_powergate_remove_clamping(int id)
 {
        u32 mask;
 
-       if (id < 0 || id >= TEGRA_NUM_POWERGATE)
+       if (id < 0 || id >= tegra_num_powerdomains)
                return -EINVAL;
 
        /*
@@ -156,6 +169,34 @@ err_power:
        return ret;
 }
 
+int tegra_cpu_powergate_id(int cpuid)
+{
+       if (cpuid > 0 && cpuid < tegra_num_cpu_domains)
+               return tegra_cpu_domains[cpuid];
+
+       return -EINVAL;
+}
+
+int __init tegra_powergate_init(void)
+{
+       switch (tegra_chip_id) {
+       case TEGRA20:
+               tegra_num_powerdomains = 7;
+               break;
+       case TEGRA30:
+               tegra_num_powerdomains = 14;
+               tegra_num_cpu_domains = 4;
+               tegra_cpu_domains = tegra30_cpu_domains;
+               break;
+       default:
+               /* Unknown Tegra variant. Disable powergating */
+               tegra_num_powerdomains = 0;
+               break;
+       }
+
+       return 0;
+}
+
 #ifdef CONFIG_DEBUG_FS
 
 static const char * const powergate_name[] = {
@@ -175,7 +216,7 @@ static int powergate_show(struct seq_file *s, void *data)
        seq_printf(s, " powergate powered\n");
        seq_printf(s, "------------------\n");
 
-       for (i = 0; i < TEGRA_NUM_POWERGATE; i++)
+       for (i = 0; i < tegra_num_powerdomains; i++)
                seq_printf(s, " %9s %7s\n", powergate_name[i],
                        tegra_powergate_is_powered(i) ? "yes" : "no");
        return 0;
diff --git a/arch/arm/mach-tegra/reset.c b/arch/arm/mach-tegra/reset.c
new file mode 100644 (file)
index 0000000..4d6a2ee
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * arch/arm/mach-tegra/reset.c
+ *
+ * Copyright (C) 2011,2012 NVIDIA Corporation.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/cpumask.h>
+#include <linux/bitops.h>
+
+#include <asm/cacheflush.h>
+#include <asm/hardware/cache-l2x0.h>
+
+#include <mach/iomap.h>
+#include <mach/irammap.h>
+
+#include "reset.h"
+#include "fuse.h"
+
+#define TEGRA_IRAM_RESET_BASE (TEGRA_IRAM_BASE + \
+                               TEGRA_IRAM_RESET_HANDLER_OFFSET)
+
+static bool is_enabled;
+
+static void tegra_cpu_reset_handler_enable(void)
+{
+       void __iomem *iram_base = IO_ADDRESS(TEGRA_IRAM_RESET_BASE);
+       void __iomem *evp_cpu_reset =
+               IO_ADDRESS(TEGRA_EXCEPTION_VECTORS_BASE + 0x100);
+       void __iomem *sb_ctrl = IO_ADDRESS(TEGRA_SB_BASE);
+       u32 reg;
+
+       BUG_ON(is_enabled);
+       BUG_ON(tegra_cpu_reset_handler_size > TEGRA_IRAM_RESET_HANDLER_SIZE);
+
+       memcpy(iram_base, (void *)__tegra_cpu_reset_handler_start,
+                       tegra_cpu_reset_handler_size);
+
+       /*
+        * NOTE: This must be the one and only write to the EVP CPU reset
+        *       vector in the entire system.
+        */
+       writel(TEGRA_IRAM_RESET_BASE + tegra_cpu_reset_handler_offset,
+                       evp_cpu_reset);
+       wmb();
+       reg = readl(evp_cpu_reset);
+
+       /*
+        * Prevent further modifications to the physical reset vector.
+        *  NOTE: Has no effect on chips prior to Tegra30.
+        */
+       if (tegra_chip_id != TEGRA20) {
+               reg = readl(sb_ctrl);
+               reg |= 2;
+               writel(reg, sb_ctrl);
+               wmb();
+       }
+
+       is_enabled = true;
+}
+
+void __init tegra_cpu_reset_handler_init(void)
+{
+
+#ifdef CONFIG_SMP
+       __tegra_cpu_reset_handler_data[TEGRA_RESET_MASK_PRESENT] =
+               *((u32 *)cpu_present_mask);
+       __tegra_cpu_reset_handler_data[TEGRA_RESET_STARTUP_SECONDARY] =
+               virt_to_phys((void *)tegra_secondary_startup);
+#endif
+
+       tegra_cpu_reset_handler_enable();
+}
diff --git a/arch/arm/mach-tegra/reset.h b/arch/arm/mach-tegra/reset.h
new file mode 100644 (file)
index 0000000..de88bf8
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * arch/arm/mach-tegra/reset.h
+ *
+ * CPU reset dispatcher.
+ *
+ * Copyright (c) 2011, NVIDIA Corporation.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef __MACH_TEGRA_RESET_H
+#define __MACH_TEGRA_RESET_H
+
+#define TEGRA_RESET_MASK_PRESENT       0
+#define TEGRA_RESET_MASK_LP1           1
+#define TEGRA_RESET_MASK_LP2           2
+#define TEGRA_RESET_STARTUP_SECONDARY  3
+#define TEGRA_RESET_STARTUP_LP2                4
+#define TEGRA_RESET_STARTUP_LP1                5
+#define TEGRA_RESET_DATA_SIZE          6
+
+#ifndef __ASSEMBLY__
+
+extern unsigned long __tegra_cpu_reset_handler_data[TEGRA_RESET_DATA_SIZE];
+
+void __tegra_cpu_reset_handler_start(void);
+void __tegra_cpu_reset_handler(void);
+void __tegra_cpu_reset_handler_end(void);
+void tegra_secondary_startup(void);
+
+#define tegra_cpu_reset_handler_offset \
+               ((u32)__tegra_cpu_reset_handler - \
+                (u32)__tegra_cpu_reset_handler_start)
+
+#define tegra_cpu_reset_handler_size \
+               (__tegra_cpu_reset_handler_end - \
+                __tegra_cpu_reset_handler_start)
+
+void __init tegra_cpu_reset_handler_init(void);
+
+#endif
+#endif
diff --git a/arch/arm/mach-tegra/sleep.S b/arch/arm/mach-tegra/sleep.S
new file mode 100644 (file)
index 0000000..8f9fde1
--- /dev/null
@@ -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)
+
index ff9e6b6..592a4ee 100644 (file)
@@ -720,7 +720,7 @@ static void tegra2_pllx_clk_init(struct clk *c)
 {
        tegra2_pll_clk_init(c);
 
-       if (tegra_sku_id() == 7)
+       if (tegra_sku_id == 7)
                c->max_rate = 750000000;
 }
 
@@ -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)
index 0f7ae6e..5070d83 100644 (file)
  */
 
 #include <linux/kernel.h>
+#include <linux/device.h>
 #include <linux/clk.h>
 #include <linux/err.h>
 #include <linux/io.h>
 #include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/platform_data/tegra_emc.h>
 
 #include <mach/iomap.h>
 
 #include "tegra2_emc.h"
+#include "fuse.h"
 
 #ifdef CONFIG_TEGRA_EMC_SCALING_ENABLE
 static bool emc_enable = true;
@@ -32,18 +37,17 @@ static bool emc_enable;
 #endif
 module_param(emc_enable, bool, 0644);
 
-static void __iomem *emc = IO_ADDRESS(TEGRA_EMC_BASE);
-static const struct tegra_emc_table *tegra_emc_table;
-static int tegra_emc_table_size;
+static struct platform_device *emc_pdev;
+static void __iomem *emc_regbase;
 
 static inline void emc_writel(u32 val, unsigned long addr)
 {
-       writel(val, emc + addr);
+       writel(val, emc_regbase + addr);
 }
 
 static inline u32 emc_readl(unsigned long addr)
 {
-       return readl(emc + addr);
+       return readl(emc_regbase + addr);
 }
 
 static const unsigned long emc_reg_addr[TEGRA_EMC_NUM_REGS] = {
@@ -98,15 +102,15 @@ static const unsigned long emc_reg_addr[TEGRA_EMC_NUM_REGS] = {
 /* Select the closest EMC rate that is higher than the requested rate */
 long tegra_emc_round_rate(unsigned long rate)
 {
+       struct tegra_emc_pdata *pdata;
        int i;
        int best = -1;
        unsigned long distance = ULONG_MAX;
 
-       if (!tegra_emc_table)
+       if (!emc_pdev)
                return -EINVAL;
 
-       if (!emc_enable)
-               return -EINVAL;
+       pdata = emc_pdev->dev.platform_data;
 
        pr_debug("%s: %lu\n", __func__, rate);
 
@@ -116,10 +120,10 @@ long tegra_emc_round_rate(unsigned long rate)
         */
        rate = rate / 2 / 1000;
 
-       for (i = 0; i < tegra_emc_table_size; i++) {
-               if (tegra_emc_table[i].rate >= rate &&
-                   (tegra_emc_table[i].rate - rate) < distance) {
-                       distance = tegra_emc_table[i].rate - rate;
+       for (i = 0; i < pdata->num_tables; i++) {
+               if (pdata->tables[i].rate >= rate &&
+                   (pdata->tables[i].rate - rate) < distance) {
+                       distance = pdata->tables[i].rate - rate;
                        best = i;
                }
        }
@@ -127,9 +131,9 @@ long tegra_emc_round_rate(unsigned long rate)
        if (best < 0)
                return -EINVAL;
 
-       pr_debug("%s: using %lu\n", __func__, tegra_emc_table[best].rate);
+       pr_debug("%s: using %lu\n", __func__, pdata->tables[best].rate);
 
-       return tegra_emc_table[best].rate * 2 * 1000;
+       return pdata->tables[best].rate * 2 * 1000;
 }
 
 /*
@@ -142,37 +146,211 @@ long tegra_emc_round_rate(unsigned long rate)
  */
 int tegra_emc_set_rate(unsigned long rate)
 {
+       struct tegra_emc_pdata *pdata;
        int i;
        int j;
 
-       if (!tegra_emc_table)
+       if (!emc_pdev)
                return -EINVAL;
 
+       pdata = emc_pdev->dev.platform_data;
+
        /*
         * The EMC clock rate is twice the bus rate, and the bus rate is
         * measured in kHz
         */
        rate = rate / 2 / 1000;
 
-       for (i = 0; i < tegra_emc_table_size; i++)
-               if (tegra_emc_table[i].rate == rate)
+       for (i = 0; i < pdata->num_tables; i++)
+               if (pdata->tables[i].rate == rate)
                        break;
 
-       if (i >= tegra_emc_table_size)
+       if (i >= pdata->num_tables)
                return -EINVAL;
 
        pr_debug("%s: setting to %lu\n", __func__, rate);
 
        for (j = 0; j < TEGRA_EMC_NUM_REGS; j++)
-               emc_writel(tegra_emc_table[i].regs[j], emc_reg_addr[j]);
+               emc_writel(pdata->tables[i].regs[j], emc_reg_addr[j]);
 
-       emc_readl(tegra_emc_table[i].regs[TEGRA_EMC_NUM_REGS - 1]);
+       emc_readl(pdata->tables[i].regs[TEGRA_EMC_NUM_REGS - 1]);
 
        return 0;
 }
 
-void tegra_init_emc(const struct tegra_emc_table *table, int table_size)
+#ifdef CONFIG_OF
+static struct device_node *tegra_emc_ramcode_devnode(struct device_node *np)
+{
+       struct device_node *iter;
+       u32 reg;
+
+       for_each_child_of_node(np, iter) {
+               if (of_property_read_u32(np, "nvidia,ram-code", &reg))
+                       continue;
+               if (reg == tegra_bct_strapping)
+                       return of_node_get(iter);
+       }
+
+       return NULL;
+}
+
+static struct tegra_emc_pdata *tegra_emc_dt_parse_pdata(
+               struct platform_device *pdev)
+{
+       struct device_node *np = pdev->dev.of_node;
+       struct device_node *tnp, *iter;
+       struct tegra_emc_pdata *pdata;
+       int ret, i, num_tables;
+
+       if (!np)
+               return NULL;
+
+       if (of_find_property(np, "nvidia,use-ram-code", NULL)) {
+               tnp = tegra_emc_ramcode_devnode(np);
+               if (!tnp)
+                       dev_warn(&pdev->dev,
+                                "can't find emc table for ram-code 0x%02x\n",
+                                tegra_bct_strapping);
+       } else
+               tnp = of_node_get(np);
+
+       if (!tnp)
+               return NULL;
+
+       num_tables = 0;
+       for_each_child_of_node(tnp, iter)
+               if (of_device_is_compatible(iter, "nvidia,tegra20-emc-table"))
+                       num_tables++;
+
+       if (!num_tables) {
+               pdata = NULL;
+               goto out;
+       }
+
+       pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
+       pdata->tables = devm_kzalloc(&pdev->dev,
+                                    sizeof(*pdata->tables) * num_tables,
+                                    GFP_KERNEL);
+
+       i = 0;
+       for_each_child_of_node(tnp, iter) {
+               u32 prop;
+
+               ret = of_property_read_u32(iter, "clock-frequency", &prop);
+               if (ret) {
+                       dev_err(&pdev->dev, "no clock-frequency in %s\n",
+                               iter->full_name);
+                       continue;
+               }
+               pdata->tables[i].rate = prop;
+
+               ret = of_property_read_u32_array(iter, "nvidia,emc-registers",
+                                                pdata->tables[i].regs,
+                                                TEGRA_EMC_NUM_REGS);
+               if (ret) {
+                       dev_err(&pdev->dev,
+                               "malformed emc-registers property in %s\n",
+                               iter->full_name);
+                       continue;
+               }
+
+               i++;
+       }
+       pdata->num_tables = i;
+
+out:
+       of_node_put(tnp);
+       return pdata;
+}
+#else
+static struct tegra_emc_pdata *tegra_emc_dt_parse_pdata(
+               struct platform_device *pdev)
+{
+       return NULL;
+}
+#endif
+
+static struct tegra_emc_pdata __devinit *tegra_emc_fill_pdata(struct platform_device *pdev)
+{
+       struct clk *c = clk_get_sys(NULL, "emc");
+       struct tegra_emc_pdata *pdata;
+       unsigned long khz;
+       int i;
+
+       WARN_ON(pdev->dev.platform_data);
+       BUG_ON(IS_ERR_OR_NULL(c));
+
+       pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
+       pdata->tables = devm_kzalloc(&pdev->dev, sizeof(*pdata->tables),
+                                    GFP_KERNEL);
+
+       pdata->tables[0].rate = clk_get_rate(c) / 2 / 1000;
+
+       for (i = 0; i < TEGRA_EMC_NUM_REGS; i++)
+               pdata->tables[0].regs[i] = emc_readl(emc_reg_addr[i]);
+
+       pdata->num_tables = 1;
+
+       khz = pdata->tables[0].rate;
+       dev_info(&pdev->dev, "no tables provided, using %ld kHz emc, "
+                "%ld kHz mem\n", khz * 2, khz);
+
+       return pdata;
+}
+
+static int __devinit tegra_emc_probe(struct platform_device *pdev)
+{
+       struct tegra_emc_pdata *pdata;
+       struct resource *res;
+
+       if (!emc_enable) {
+               dev_err(&pdev->dev, "disabled per module parameter\n");
+               return -ENODEV;
+       }
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res) {
+               dev_err(&pdev->dev, "missing register base\n");
+               return -ENOMEM;
+       }
+
+       emc_regbase = devm_request_and_ioremap(&pdev->dev, res);
+       if (!emc_regbase) {
+               dev_err(&pdev->dev, "failed to remap registers\n");
+               return -ENOMEM;
+       }
+
+       pdata = pdev->dev.platform_data;
+
+       if (!pdata)
+               pdata = tegra_emc_dt_parse_pdata(pdev);
+
+       if (!pdata)
+               pdata = tegra_emc_fill_pdata(pdev);
+
+       pdev->dev.platform_data = pdata;
+
+       emc_pdev = pdev;
+
+       return 0;
+}
+
+static struct of_device_id tegra_emc_of_match[] __devinitdata = {
+       { .compatible = "nvidia,tegra20-emc", },
+       { },
+};
+
+static struct platform_driver tegra_emc_driver = {
+       .driver         = {
+               .name   = "tegra-emc",
+               .owner  = THIS_MODULE,
+               .of_match_table = tegra_emc_of_match,
+       },
+       .probe          = tegra_emc_probe,
+};
+
+static int __init tegra_emc_init(void)
 {
-       tegra_emc_table = table;
-       tegra_emc_table_size = table_size;
+       return platform_driver_register(&tegra_emc_driver);
 }
+device_initcall(tegra_emc_init);
index 19f08cb..f61409b 100644 (file)
  *
  */
 
-#define TEGRA_EMC_NUM_REGS 46
-
-struct tegra_emc_table {
-       unsigned long rate;
-       u32 regs[TEGRA_EMC_NUM_REGS];
-};
+#ifndef __MACH_TEGRA_TEGRA2_EMC_H_
+#define __MACH_TEGRA_TEGRA2_EMC_H
 
 int tegra_emc_set_rate(unsigned long rate);
 long tegra_emc_round_rate(unsigned long rate);
-void tegra_init_emc(const struct tegra_emc_table *table, int table_size);
+
+#endif
diff --git a/arch/arm/mach-tegra/tegra30_clocks.c b/arch/arm/mach-tegra/tegra30_clocks.c
new file mode 100644 (file)
index 0000000..6d08b53
--- /dev/null
@@ -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;
+               }
+       }
+
+ &