]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/commitdiff
Merge tag 'drivers-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/arm...
authorLinus Torvalds <torvalds@linux-foundation.org>
Wed, 8 Oct 2014 21:37:16 +0000 (17:37 -0400)
committerLinus Torvalds <torvalds@linux-foundation.org>
Wed, 8 Oct 2014 21:37:16 +0000 (17:37 -0400)
Pull ARM SoC driver updates from Arnd Bergmann:
 "These are changes for drivers that are intimately tied to some SoC and
  for some reason could not get merged through the respective subsystem
  maintainer tree.

  Most of the new code is for the Keystone Navigator driver, which is
  new base support that is going to be needed for their hardware
  accelerated network driver and other units.

  Most of the commits are for moving old code around from at91 and omap
  for things that are done in device drivers nowadays.

   - at91: move reset, poweroff, memory and clocksource code into
     drivers directories
   - socfpga: add edac driver (through arm-soc, as requested by Boris)
   - omap: move omap-intc code to drivers/irqchip
   - sunxi: added an RTC driver for sun6i
   - omap: mailbox driver related changes
   - keystone: support for the "Navigator" component
   - versatile: new reboot, led and soc drivers"

* tag 'drivers-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc: (92 commits)
  bus: arm-ccn: Fix spurious warning message
  leds: add device tree bindings for register bit LEDs
  soc: add driver for the ARM RealView
  power: reset: driver for the Versatile syscon reboot
  leds: add a driver for syscon-based LEDs
  drivers/soc: ti: fix build break with modules
  MAINTAINERS: Add Keystone Multicore Navigator drivers entry
  soc: ti: add Keystone Navigator DMA support
  Documentation: dt: soc: add Keystone Navigator DMA bindings
  soc: ti: add Keystone Navigator QMSS driver
  Documentation: dt: soc: add Keystone Navigator QMSS bindings
  rtc: sunxi: Depend on platforms sun4i/sun7i that actually have the rtc
  rtc: sun6i: Add sun6i RTC driver
  irqchip: omap-intc: remove unnecessary comments
  irqchip: omap-intc: correct maximum number or MIR registers
  irqchip: omap-intc: enable TURBO idle mode
  irqchip: omap-intc: enable IP protection
  irqchip: omap-intc: remove unnecesary of_address_to_resource() call
  irqchip: omap-intc: comment style cleanup
  irqchip: omap-intc: minor improvement to omap_irq_pending()
  ...

108 files changed:
Documentation/devicetree/bindings/arm/atmel-at91.txt
Documentation/devicetree/bindings/leds/register-bit-led.txt [new file with mode: 0644]
Documentation/devicetree/bindings/mailbox/omap-mailbox.txt [new file with mode: 0644]
Documentation/devicetree/bindings/rtc/sun6i-rtc.txt [new file with mode: 0644]
Documentation/devicetree/bindings/soc/ti/keystone-navigator-dma.txt [new file with mode: 0644]
Documentation/devicetree/bindings/soc/ti/keystone-navigator-qmss.txt [new file with mode: 0644]
MAINTAINERS
arch/arm/boot/dts/am33xx.dtsi
arch/arm/boot/dts/omap2.dtsi
arch/arm/boot/dts/omap2420-n810.dts
arch/arm/boot/dts/omap2420-n8x0-common.dtsi
arch/arm/boot/dts/omap3.dtsi
arch/arm/mach-at91/Kconfig
arch/arm/mach-at91/Makefile
arch/arm/mach-at91/at91_rstc.h [deleted file]
arch/arm/mach-at91/at91_shdwc.h [deleted file]
arch/arm/mach-at91/at91sam9260.c
arch/arm/mach-at91/at91sam9261.c
arch/arm/mach-at91/at91sam9263.c
arch/arm/mach-at91/at91sam926x_time.c [deleted file]
arch/arm/mach-at91/at91sam9_alt_reset.S [deleted file]
arch/arm/mach-at91/at91sam9g45.c
arch/arm/mach-at91/at91sam9g45_reset.S [deleted file]
arch/arm/mach-at91/at91sam9rl.c
arch/arm/mach-at91/board-afeb-9260v1.c
arch/arm/mach-at91/board-cam60.c
arch/arm/mach-at91/board-cpu9krea.c
arch/arm/mach-at91/board-dt-sam9.c
arch/arm/mach-at91/board-dt-sama5.c
arch/arm/mach-at91/board-flexibity.c
arch/arm/mach-at91/board-gsia18s.c
arch/arm/mach-at91/board-pcontrol-g20.c
arch/arm/mach-at91/board-sam9-l9260.c
arch/arm/mach-at91/board-sam9260ek.c
arch/arm/mach-at91/board-sam9261ek.c
arch/arm/mach-at91/board-sam9263ek.c
arch/arm/mach-at91/board-sam9g20ek.c
arch/arm/mach-at91/board-sam9m10g45ek.c
arch/arm/mach-at91/board-sam9rlek.c
arch/arm/mach-at91/board-snapper9260.c
arch/arm/mach-at91/board-stamp9g20.c
arch/arm/mach-at91/generic.h
arch/arm/mach-at91/pm.c
arch/arm/mach-at91/setup.c
arch/arm/mach-at91/soc.h
arch/arm/mach-omap2/Kconfig
arch/arm/mach-omap2/Makefile
arch/arm/mach-omap2/board-3430sdp.c
arch/arm/mach-omap2/board-am3517crane.c
arch/arm/mach-omap2/board-am3517evm.c
arch/arm/mach-omap2/board-cm-t35.c
arch/arm/mach-omap2/board-cm-t3517.c
arch/arm/mach-omap2/board-devkit8000.c
arch/arm/mach-omap2/board-generic.c
arch/arm/mach-omap2/board-ldp.c
arch/arm/mach-omap2/board-n8x0.c
arch/arm/mach-omap2/board-omap3beagle.c
arch/arm/mach-omap2/board-omap3logic.c
arch/arm/mach-omap2/board-omap3pandora.c
arch/arm/mach-omap2/board-omap3stalker.c
arch/arm/mach-omap2/board-omap3touchbook.c
arch/arm/mach-omap2/board-overo.c
arch/arm/mach-omap2/board-rx51.c
arch/arm/mach-omap2/common-board-devices.h
arch/arm/mach-omap2/common.h
arch/arm/mach-omap2/irq.c [deleted file]
arch/arm/mach-omap2/pdata-quirks.c
drivers/Kconfig
drivers/bus/arm-ccn.c
drivers/clk/at91/clk-system.c
drivers/clocksource/Kconfig
drivers/clocksource/Makefile
drivers/clocksource/timer-atmel-pit.c [new file with mode: 0644]
drivers/edac/Kconfig
drivers/edac/Makefile
drivers/edac/altera_edac.c [new file with mode: 0644]
drivers/irqchip/Kconfig
drivers/irqchip/Makefile
drivers/irqchip/irq-omap-intc.c [new file with mode: 0644]
drivers/leds/Kconfig
drivers/leds/Makefile
drivers/leds/leds-syscon.c [new file with mode: 0644]
drivers/mailbox/omap-mailbox.c
drivers/memory/Kconfig
drivers/memory/Makefile
drivers/memory/atmel-sdramc.c [new file with mode: 0644]
drivers/power/reset/Kconfig
drivers/power/reset/Makefile
drivers/power/reset/arm-versatile-reboot.c [new file with mode: 0644]
drivers/power/reset/at91-poweroff.c [new file with mode: 0644]
drivers/power/reset/at91-reset.c [new file with mode: 0644]
drivers/rtc/Kconfig
drivers/rtc/Makefile
drivers/rtc/rtc-sun6i.c [new file with mode: 0644]
drivers/soc/Kconfig
drivers/soc/Makefile
drivers/soc/ti/Kconfig [new file with mode: 0644]
drivers/soc/ti/Makefile [new file with mode: 0644]
drivers/soc/ti/knav_dma.c [new file with mode: 0644]
drivers/soc/ti/knav_qmss.h [new file with mode: 0644]
drivers/soc/ti/knav_qmss_acc.c [new file with mode: 0644]
drivers/soc/ti/knav_qmss_queue.c [new file with mode: 0644]
drivers/soc/versatile/Kconfig [new file with mode: 0644]
drivers/soc/versatile/Makefile [new file with mode: 0644]
drivers/soc/versatile/soc-realview.c [new file with mode: 0644]
include/linux/irqchip/irq-omap-intc.h [new file with mode: 0644]
include/linux/soc/ti/knav_dma.h [new file with mode: 0644]
include/linux/soc/ti/knav_qmss.h [new file with mode: 0644]

index 4949e805f7fc0ee970e6c2fcf407321a6a86810d..562cda9d86d9a9de78c617c67b38fa5313cc20cc 100644 (file)
@@ -98,8 +98,8 @@ RAMC SDRAM/DDR Controller required properties:
 - compatible: Should be "atmel,at91rm9200-sdramc",
                        "atmel,at91sam9260-sdramc",
                        "atmel,at91sam9g45-ddramc",
+                       "atmel,sama5d3-ddramc",
 - reg: Should contain registers location and length
-  For at91sam9263 and at91sam9g45 you must specify 2 entries.
 
 Examples:
 
@@ -108,12 +108,6 @@ Examples:
                reg = <0xffffe800 0x200>;
        };
 
-       ramc0: ramc@ffffe400 {
-               compatible = "atmel,at91sam9g45-ddramc";
-               reg = <0xffffe400 0x200
-                      0xffffe600 0x200>;
-       };
-
 SHDWC Shutdown Controller
 
 required properties:
diff --git a/Documentation/devicetree/bindings/leds/register-bit-led.txt b/Documentation/devicetree/bindings/leds/register-bit-led.txt
new file mode 100644 (file)
index 0000000..379cefd
--- /dev/null
@@ -0,0 +1,99 @@
+Device Tree Bindings for Register Bit LEDs
+
+Register bit leds are used with syscon multifunctional devices
+where single bits in a certain register can turn on/off a
+single LED. The register bit LEDs appear as children to the
+syscon device, with the proper compatible string. For the
+syscon bindings see:
+Documentation/devicetree/bindings/mfd/syscon.txt
+
+Each LED is represented as a sub-node of the syscon device. Each
+node's name represents the name of the corresponding LED.
+
+LED sub-node properties:
+
+Required properties:
+- compatible : must be "register-bit-led"
+- offset : register offset to the register controlling this LED
+- mask : bit mask for the bit controlling this LED in the register
+  typically 0x01, 0x02, 0x04 ...
+
+Optional properties:
+- label : (optional)
+  see Documentation/devicetree/bindings/leds/common.txt
+- linux,default-trigger : (optional)
+  see Documentation/devicetree/bindings/leds/common.txt
+- default-state: (optional) The initial state of the LED. Valid
+  values are "on", "off", and "keep". If the LED is already on or off
+  and the default-state property is set the to same value, then no
+  glitch should be produced where the LED momentarily turns off (or
+  on). The "keep" setting will keep the LED at whatever its current
+  state is, without producing a glitch.  The default is off if this
+  property is not present.
+
+Example:
+
+syscon: syscon@10000000 {
+       compatible = "arm,realview-pb1176-syscon", "syscon";
+       reg = <0x10000000 0x1000>;
+
+       led@08.0 {
+               compatible = "register-bit-led";
+               offset = <0x08>;
+               mask = <0x01>;
+               label = "versatile:0";
+               linux,default-trigger = "heartbeat";
+               default-state = "on";
+       };
+       led@08.1 {
+               compatible = "register-bit-led";
+               offset = <0x08>;
+               mask = <0x02>;
+               label = "versatile:1";
+               linux,default-trigger = "mmc0";
+               default-state = "off";
+       };
+       led@08.2 {
+               compatible = "register-bit-led";
+               offset = <0x08>;
+               mask = <0x04>;
+               label = "versatile:2";
+               linux,default-trigger = "cpu0";
+               default-state = "off";
+       };
+       led@08.3 {
+               compatible = "register-bit-led";
+               offset = <0x08>;
+               mask = <0x08>;
+               label = "versatile:3";
+               default-state = "off";
+       };
+       led@08.4 {
+               compatible = "register-bit-led";
+               offset = <0x08>;
+               mask = <0x10>;
+               label = "versatile:4";
+               default-state = "off";
+       };
+       led@08.5 {
+               compatible = "register-bit-led";
+               offset = <0x08>;
+               mask = <0x20>;
+               label = "versatile:5";
+               default-state = "off";
+       };
+       led@08.6 {
+               compatible = "register-bit-led";
+               offset = <0x08>;
+               mask = <0x40>;
+               label = "versatile:6";
+               default-state = "off";
+       };
+       led@08.7 {
+               compatible = "register-bit-led";
+               offset = <0x08>;
+               mask = <0x80>;
+               label = "versatile:7";
+               default-state = "off";
+       };
+};
diff --git a/Documentation/devicetree/bindings/mailbox/omap-mailbox.txt b/Documentation/devicetree/bindings/mailbox/omap-mailbox.txt
new file mode 100644 (file)
index 0000000..48edc4b
--- /dev/null
@@ -0,0 +1,108 @@
+OMAP2+ Mailbox Driver
+=====================
+
+The OMAP mailbox hardware facilitates communication between different processors
+using a queued mailbox interrupt mechanism. The IP block is external to the
+various processor subsystems and is connected on an interconnect bus. The
+communication is achieved through a set of registers for message storage and
+interrupt configuration registers.
+
+Each mailbox IP block has a certain number of h/w fifo queues and output
+interrupt lines. An output interrupt line is routed to an interrupt controller
+within a processor subsystem, and there can be more than one line going to a
+specific processor's interrupt controller. The interrupt line connections are
+fixed for an instance and are dictated by the IP integration into the SoC
+(excluding the SoCs that have a Interrupt Crossbar IP). Each interrupt line is
+programmable through a set of interrupt configuration registers, and have a rx
+and tx interrupt source per h/w fifo. Communication between different processors
+is achieved through the appropriate programming of the rx and tx interrupt
+sources on the appropriate interrupt lines.
+
+The number of h/w fifo queues and interrupt lines dictate the usable registers.
+All the current OMAP SoCs except for the newest DRA7xx SoC has a single IP
+instance. DRA7xx has multiple instances with different number of h/w fifo queues
+and interrupt lines between different instances. The interrupt lines can also be
+routed to different processor sub-systems on DRA7xx as they are routed through
+the Crossbar, a kind of interrupt router/multiplexer.
+
+Mailbox Device Node:
+====================
+A Mailbox device node is used to represent a Mailbox IP instance within a SoC.
+The sub-mailboxes are represented as child nodes of this parent node.
+
+Required properties:
+--------------------
+- compatible:          Should be one of the following,
+                           "ti,omap2-mailbox" for OMAP2420, OMAP2430 SoCs
+                           "ti,omap3-mailbox" for OMAP3430, OMAP3630 SoCs
+                           "ti,omap4-mailbox" for OMAP44xx, OMAP54xx, AM33xx,
+                                                  AM43xx and DRA7xx SoCs
+- reg:                 Contains the mailbox register address range (base
+                       address and length)
+- interrupts:          Contains the interrupt information for the mailbox
+                       device. The format is dependent on which interrupt
+                       controller the OMAP device uses
+- ti,hwmods:           Name of the hwmod associated with the mailbox
+- ti,mbox-num-users:   Number of targets (processor devices) that the mailbox
+                       device can interrupt
+- ti,mbox-num-fifos:   Number of h/w fifo queues within the mailbox IP block
+
+Child Nodes:
+============
+A child node is used for representing the actual sub-mailbox device that is
+used for the communication between the host processor and a remote processor.
+Each child node should have a unique node name across all the different
+mailbox device nodes.
+
+Required properties:
+--------------------
+- ti,mbox-tx:          sub-mailbox descriptor property defining a Tx fifo
+- ti,mbox-rx:          sub-mailbox descriptor property defining a Rx fifo
+
+Sub-mailbox Descriptor Data
+---------------------------
+Each of the above ti,mbox-tx and ti,mbox-rx properties should have 3 cells of
+data that represent the following:
+    Cell #1 (fifo_id) - mailbox fifo id used either for transmitting
+                        (ti,mbox-tx) or for receiving (ti,mbox-rx)
+    Cell #2 (irq_id)  - irq identifier index number to use from the parent's
+                        interrupts data. Should be 0 for most of the cases, a
+                        positive index value is seen only on mailboxes that have
+                        multiple interrupt lines connected to the MPU processor.
+    Cell #3 (usr_id)  - mailbox user id for identifying the interrupt line
+                        associated with generating a tx/rx fifo interrupt.
+
+Example:
+--------
+
+/* OMAP4 */
+mailbox: mailbox@4a0f4000 {
+       compatible = "ti,omap4-mailbox";
+       reg = <0x4a0f4000 0x200>;
+       interrupts = <GIC_SPI 26 IRQ_TYPE_LEVEL_HIGH>;
+       ti,hwmods = "mailbox";
+       ti,mbox-num-users = <3>;
+       ti,mbox-num-fifos = <8>;
+       mbox_ipu: mbox_ipu {
+               ti,mbox-tx = <0 0 0>;
+               ti,mbox-rx = <1 0 0>;
+       };
+       mbox_dsp: mbox_dsp {
+               ti,mbox-tx = <3 0 0>;
+               ti,mbox-rx = <2 0 0>;
+       };
+};
+
+/* AM33xx */
+mailbox: mailbox@480C8000 {
+       compatible = "ti,omap4-mailbox";
+       reg = <0x480C8000 0x200>;
+       interrupts = <77>;
+       ti,hwmods = "mailbox";
+       ti,mbox-num-users = <4>;
+       ti,mbox-num-fifos = <8>;
+       mbox_wkupm3: wkup_m3 {
+               ti,mbox-tx = <0 0 0>;
+               ti,mbox-rx = <0 0 3>;
+       };
+};
diff --git a/Documentation/devicetree/bindings/rtc/sun6i-rtc.txt b/Documentation/devicetree/bindings/rtc/sun6i-rtc.txt
new file mode 100644 (file)
index 0000000..f007e42
--- /dev/null
@@ -0,0 +1,17 @@
+* sun6i Real Time Clock
+
+RTC controller for the Allwinner A31
+
+Required properties:
+- compatible   : Should be "allwinner,sun6i-a31-rtc"
+- reg          : physical base address of the controller and length of
+                 memory mapped region.
+- interrupts   : IRQ lines for the RTC alarm 0 and alarm 1, in that order.
+
+Example:
+
+rtc: rtc@01f00000 {
+       compatible = "allwinner,sun6i-a31-rtc";
+       reg = <0x01f00000 0x54>;
+       interrupts = <0 40 4>, <0 41 4>;
+};
diff --git a/Documentation/devicetree/bindings/soc/ti/keystone-navigator-dma.txt b/Documentation/devicetree/bindings/soc/ti/keystone-navigator-dma.txt
new file mode 100644 (file)
index 0000000..337c4ea
--- /dev/null
@@ -0,0 +1,111 @@
+Keystone Navigator DMA Controller
+
+This document explains the device tree bindings for the packet dma
+on keystone devices. The Keystone Navigator DMA driver sets up the dma
+channels and flows for the QMSS(Queue Manager SubSystem) who triggers
+the actual data movements across clients using destination queues. Every
+client modules like  NETCP(Network Coprocessor), SRIO(Serial Rapid IO),
+CRYPTO Engines etc has its own instance of dma hardware. QMSS has also
+an internal packet DMA module which is used as an infrastructure DMA
+with zero copy.
+
+Navigator DMA cloud layout:
+       ------------------
+       | Navigator DMAs |
+       ------------------
+               |
+               |-> DMA instance #0
+               |
+               |-> DMA instance #1
+                       .
+                       .
+               |
+               |-> DMA instance #n
+
+Navigator DMA properties:
+Required properties:
+ - compatible: Should be "ti,keystone-navigator-dma"
+ - clocks: phandle to dma instances clocks. The clock handles can be as
+       many as the dma instances. The order should be maintained as per
+       the dma instances.
+ - ti,navigator-cloud-address: Should contain base address for the multi-core
+       navigator cloud and number of addresses depends on SOC integration
+       configuration.. Navigator cloud global address needs to be programmed
+       into DMA and the DMA uses it as the physical addresses to reach queue
+       managers. Note that these addresses though points to queue managers,
+       they are relevant only from DMA perspective. The QMSS may not choose to
+       use them since it has a different address space view to reach all
+       its components.
+
+DMA instance properties:
+Required properties:
+ - reg: Should contain register location and length of the following dma
+       register regions. Register regions should be specified in the following
+       order.
+       - Global control register region (global).
+       - Tx DMA channel configuration register region (txchan).
+       - Rx DMA channel configuration register region (rxchan).
+       - Tx DMA channel Scheduler configuration register region (txsched).
+       - Rx DMA flow configuration register region (rxflow).
+
+Optional properties:
+ - reg-names: Names for the register regions.
+ - ti,enable-all: Enable all DMA channels vs clients opening specific channels
+       what they need. This property is useful for the userspace fast path
+       case where the linux drivers enables the channels used by userland
+       stack.
+ - ti,loop-back: To loopback Tx streaming I/F to Rx streaming I/F. Used for
+             infrastructure transfers.
+ - ti,rx-retry-timeout: Number of dma cycles to wait before retry on buffer
+                    starvation.
+
+Example:
+
+       knav_dmas: knav_dmas@0 {
+               compatible = "ti,keystone-navigator-dma";
+               clocks = <&papllclk>, <&clkxge>;
+               #address-cells = <1>;
+               #size-cells = <1>;
+               ranges;
+               ti,navigator-cloud-address = <0x23a80000 0x23a90000
+                                          0x23aa0000 0x23ab0000>;
+
+               dma_gbe: dma_gbe@0 {
+                       reg = <0x2004000 0x100>,
+                                 <0x2004400 0x120>,
+                                 <0x2004800 0x300>,
+                                 <0x2004c00 0x120>,
+                                 <0x2005000 0x400>;
+                       reg-names = "global", "txchan", "rxchan",
+                                       "txsched", "rxflow";
+               };
+
+               dma_xgbe: dma_xgbe@0 {
+                       reg = <0x2fa1000 0x100>,
+                               <0x2fa1400 0x200>,
+                               <0x2fa1800 0x200>,
+                               <0x2fa1c00 0x200>,
+                               <0x2fa2000 0x400>;
+                       reg-names = "global", "txchan", "rxchan",
+                                       "txsched", "rxflow";
+               };
+       };
+
+Navigator DMA client:
+Required properties:
+ - ti,navigator-dmas: List of one or more DMA specifiers, each consisting of
+                       - A phandle pointing to DMA instance node
+                       - A DMA channel number as a phandle arg.
+ - ti,navigator-dma-names: Contains dma channel name for each DMA specifier in
+                       the 'ti,navigator-dmas' property.
+
+Example:
+
+       netcp: netcp@2090000 {
+               ..
+               ti,navigator-dmas = <&dma_gbe 22>,
+                               <&dma_gbe 23>,
+                               <&dma_gbe 8>;
+               ti,navigator-dma-names = "netrx0", "netrx1", "nettx";
+               ..
+       };
diff --git a/Documentation/devicetree/bindings/soc/ti/keystone-navigator-qmss.txt b/Documentation/devicetree/bindings/soc/ti/keystone-navigator-qmss.txt
new file mode 100644 (file)
index 0000000..d8e8cdb
--- /dev/null
@@ -0,0 +1,232 @@
+* Texas Instruments Keystone Navigator Queue Management SubSystem driver
+
+The QMSS (Queue Manager Sub System) found on Keystone SOCs is one of
+the main hardware sub system which forms the backbone of the Keystone
+multi-core Navigator. QMSS consist of queue managers, packed-data structure
+processors(PDSP), linking RAM, descriptor pools and infrastructure
+Packet DMA.
+The Queue Manager is a hardware module that is responsible for accelerating
+management of the packet queues. Packets are queued/de-queued by writing or
+reading descriptor address to a particular memory mapped location. The PDSPs
+perform QMSS related functions like accumulation, QoS, or event management.
+Linking RAM registers are used to link the descriptors which are stored in
+descriptor RAM. Descriptor RAM is configurable as internal or external memory.
+The QMSS driver manages the PDSP setups, linking RAM regions,
+queue pool management (allocation, push, pop and notify) and descriptor
+pool management.
+
+
+Required properties:
+- compatible   : Must be "ti,keystone-navigator-qmss";
+- clocks       : phandle to the reference clock for this device.
+- queue-range  : <start number> total range of queue numbers for the device.
+- linkram0     : <address size> for internal link ram, where size is the total
+                 link ram entries.
+- linkram1     : <address size> for external link ram, where size is the total
+                 external link ram entries. If the address is specified as "0"
+                 driver will allocate memory.
+- qmgrs         : child node describing the individual queue managers on the
+                 SoC. On keystone 1 devices there should be only one node.
+                 On keystone 2 devices there can be more than 1 node.
+  -- managed-queues    : the actual queues managed by each queue manager
+                         instance, specified as <"base queue #" "# of queues">.
+  -- reg               : Address and size of the register set for the device.
+                         Register regions should be specified in the following
+                         order
+                         - Queue Peek region.
+                         - Queue status RAM.
+                         - Queue configuration region.
+                         - Descriptor memory setup region.
+                         - Queue Management/Queue Proxy region for queue Push.
+                         - Queue Management/Queue Proxy region for queue Pop.
+- queue-pools  : child node classifying the queue ranges into pools.
+                 Queue ranges are grouped into 3 type of pools:
+                 - qpend           : pool of qpend(interruptible) queues
+                 - general-purpose : pool of general queues, primarly used
+                                     as free descriptor queues or the
+                                     transmit DMA queues.
+                 - accumulator     : pool of queues on PDSP accumulator channel
+                 Each range can have the following properties:
+  -- qrange            : number of queues to use per queue range, specified as
+                         <"base queue #" "# of queues">.
+  -- interrupts                : Optional property to specify the interrupt mapping
+                         for interruptible queues. The driver additionaly sets
+                         the interrupt affinity hint based on the cpu mask.
+  -- qalloc-by-id      : Optional property to specify that the queues in this
+                         range can only be allocated by queue id.
+  -- accumulator       : Accumulator channel specification. Any of the PDSPs in
+                         QMSS can be loaded with the accumulator firmware. The
+                         accumulator firmware’s job is to poll a select number of
+                         queues looking for descriptors that have been pushed
+                         into them. Descriptors are popped from the queue and
+                         placed in a buffer provided by the host. When the list
+                         becomes full or a programmed time period expires, the
+                         accumulator triggers an interrupt to the host to read
+                         the buffer for descriptor information. This firmware
+                         comes in 16, 32, and 48 channel builds. Each of these
+                         channels can be configured to monitor 32 contiguous
+                         queues.  Accumulator channel property is specified as:
+                         <pdsp-id, channel, entries, pacing mode, latency>
+                         pdsp-id     : QMSS PDSP running accumulator firmware
+                                       on which the channel has to be
+                                       configured
+                         channel     : Accumulator channel number
+                         entries     : Size of the accumulator descriptor list
+                         pacing mode : Interrupt pacing mode
+                                       0 : None, i.e interrupt on list full only
+                                       1 : Time delay since last interrupt
+                                       2 : Time delay since first new packet
+                                       3 : Time delay since last new packet
+                         latency     : time to delay the interrupt, specified
+                                       in microseconds.
+  -- multi-queue       : Optional property to specify that the channel has to
+                         monitor upto 32 queues starting at the base queue #.
+- descriptor-regions   : child node describing the memory regions for keystone
+                         navigator packet DMA descriptors. The memory for
+                         descriptors will be allocated by the driver.
+  -- id                                : region number in QMSS.
+  -- region-spec               : specifies the number of descriptors in the
+                                 region, specified as
+                                 <"# of descriptors" "descriptor size">.
+  -- link-index                        : start index, i.e. index of the first
+                                 descriptor in the region.
+
+Optional properties:
+- dma-coherent : Present if DMA operations are coherent.
+- pdsps                : child node describing the PDSP configuration.
+  -- firmware          : firmware to be loaded on the PDSP.
+  -- id                        : the qmss pdsp that will run the firmware.
+  -- reg               : Address and size of the register set for the PDSP.
+                         Register regions should be specified in the following
+                         order
+                         - PDSP internal RAM region.
+                         - PDSP control/status region registers.
+                         - QMSS interrupt distributor registers.
+                         - PDSP command interface region.
+
+Example:
+
+qmss: qmss@2a40000 {
+       compatible = "ti,keystone-qmss";
+       dma-coherent;
+       #address-cells = <1>;
+       #size-cells = <1>;
+       clocks = <&chipclk13>;
+       ranges;
+       queue-range     = <0 0x4000>;
+       linkram0        = <0x100000 0x8000>;
+       linkram1        = <0x0 0x10000>;
+
+       qmgrs {
+               #address-cells = <1>;
+               #size-cells = <1>;
+               ranges;
+               qmgr0 {
+                       managed-queues = <0 0x2000>;
+                       reg = <0x2a40000 0x20000>,
+                             <0x2a06000 0x400>,
+                             <0x2a02000 0x1000>,
+                             <0x2a03000 0x1000>,
+                             <0x23a80000 0x20000>,
+                             <0x2a80000 0x20000>;
+               };
+
+               qmgr1 {
+                       managed-queues = <0x2000 0x2000>;
+                       reg = <0x2a60000 0x20000>,
+                             <0x2a06400 0x400>,
+                             <0x2a04000 0x1000>,
+                             <0x2a05000 0x1000>,
+                             <0x23aa0000 0x20000>,
+                             <0x2aa0000 0x20000>;
+               };
+       };
+       queue-pools {
+               qpend {
+                       qpend-0 {
+                               qrange = <658 8>;
+                               interrupts =<0 40 0xf04 0 41 0xf04 0 42 0xf04
+                                            0 43 0xf04 0 44 0xf04 0 45 0xf04
+                                            0 46 0xf04 0 47 0xf04>;
+                       };
+                       qpend-1 {
+                               qrange = <8704 16>;
+                               interrupts = <0 48 0xf04 0 49 0xf04 0 50 0xf04
+                                             0 51 0xf04 0 52 0xf04 0 53 0xf04
+                                             0 54 0xf04 0 55 0xf04 0 56 0xf04
+                                             0 57 0xf04 0 58 0xf04 0 59 0xf04
+                                             0 60 0xf04 0 61 0xf04 0 62 0xf04
+                                             0 63 0xf04>;
+                               qalloc-by-id;
+                       };
+                       qpend-2 {
+                               qrange = <8720 16>;
+                               interrupts = <0 64 0xf04 0 65 0xf04 0 66 0xf04
+                                             0 59 0xf04 0 68 0xf04 0 69 0xf04
+                                             0 70 0xf04 0 71 0xf04 0 72 0xf04
+                                             0 73 0xf04 0 74 0xf04 0 75 0xf04
+                                             0 76 0xf04 0 77 0xf04 0 78 0xf04
+                                             0 79 0xf04>;
+                       };
+               };
+               general-purpose {
+                       gp-0 {
+                               qrange = <4000 64>;
+                       };
+                       netcp-tx {
+                               qrange = <640 9>;
+                               qalloc-by-id;
+                       };
+               };
+               accumulator {
+                       acc-0 {
+                               qrange = <128 32>;
+                               accumulator = <0 36 16 2 50>;
+                               interrupts = <0 215 0xf01>;
+                               multi-queue;
+                               qalloc-by-id;
+                       };
+                       acc-1 {
+                               qrange = <160 32>;
+                               accumulator = <0 37 16 2 50>;
+                               interrupts = <0 216 0xf01>;
+                               multi-queue;
+                       };
+                       acc-2 {
+                               qrange = <192 32>;
+                               accumulator = <0 38 16 2 50>;
+                               interrupts = <0 217 0xf01>;
+                               multi-queue;
+                       };
+                       acc-3 {
+                               qrange = <224 32>;
+                               accumulator = <0 39 16 2 50>;
+                               interrupts = <0 218 0xf01>;
+                               multi-queue;
+                       };
+               };
+       };
+       descriptor-regions {
+               #address-cells = <1>;
+               #size-cells = <1>;
+               ranges;
+               region-12 {
+                       id = <12>;
+                       region-spec = <8192 128>; /* num_desc desc_size */
+                       link-index = <0x4000>;
+               };
+       };
+       pdsps {
+               #address-cells = <1>;
+               #size-cells = <1>;
+               ranges;
+               pdsp0@0x2a10000 {
+                       firmware = "keystone/qmss_pdsp_acc48_k2_le_1_0_0_8.fw";
+                       reg = <0x2a10000 0x1000>,
+                             <0x2a0f000 0x100>,
+                             <0x2a0c000 0x3c8>,
+                             <0x2a20000 0x4000>;
+                       id = <0>;
+               };
+       };
+}; /* qmss */
index d172f636df24671f07fe77666fc0abfb1d9d7e62..0fa3ff342af6f958528dd0aa45aab1497ea2062d 100644 (file)
@@ -1404,6 +1404,11 @@ M:       Dinh Nguyen <dinguyen@opensource.altera.com>
 S:     Maintained
 F:     drivers/clk/socfpga/
 
+ARM/SOCFPGA EDAC SUPPORT
+M:     Thor Thayer <tthayer@opensource.altera.com>
+S:     Maintained
+F:     drivers/edac/altera_edac.
+
 ARM/STI ARCHITECTURE
 M:     Srinivas Kandagatla <srinivas.kandagatla@gmail.com>
 M:     Maxime Coquelin <maxime.coquelin@st.com>
@@ -9194,6 +9199,15 @@ F:       drivers/misc/tifm*
 F:     drivers/mmc/host/tifm_sd.c
 F:     include/linux/tifm.h
 
+TI KEYSTONE MULTICORE NAVIGATOR DRIVERS
+M:     Santosh Shilimkar <santosh.shilimkar@ti.com>
+L:     linux-kernel@vger.kernel.org
+L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
+S:     Maintained
+F:     drivers/soc/ti/*
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/ssantosh/linux-keystone.git
+
+
 TI LM49xxx FAMILY ASoC CODEC DRIVERS
 M:     M R Swami Reddy <mr.swami.reddy@ti.com>
 M:     Vishwas A Deshpande <vishwas.a.deshpande@ti.com>
index 9e7d45571cd59de0703e79b00732b291dcfa79b3..abe530f7029634e715a7392b40cab387b4d2abfa 100644 (file)
                };
 
                intc: interrupt-controller@48200000 {
-                       compatible = "ti,omap2-intc";
+                       compatible = "ti,am33xx-intc";
                        interrupt-controller;
                        #interrupt-cells = <1>;
-                       ti,intc-size = <128>;
                        reg = <0x48200000 0x1000>;
                };
 
index 8f8c07da4ac148d550ae45cd3501d4a992f4e7c8..59d1c297bb30f17aaab458f94e6ba52363c635cb 100644 (file)
@@ -75,7 +75,6 @@
                        compatible = "ti,omap2-intc";
                        interrupt-controller;
                        #interrupt-cells = <1>;
-                       ti,intc-size = <96>;
                        reg = <0x480FE000 0x1000>;
                };
 
index 21baec154b7873aa3bd25583dcc0f3bbd37d3398..b604d26bd48c3493155b22081209525b2fcb2070 100644 (file)
@@ -6,3 +6,10 @@
        model = "Nokia N810";
        compatible = "nokia,n810", "nokia,n8x0", "ti,omap2420", "ti,omap2";
 };
+
+&i2c2 {
+       aic3x@18 {
+               compatible = "tlv320aic3x";
+               reg = <0x18>;
+       };
+};
index 89608b2065198f06107d5aa4be9125c228bde663..24c50db2a478cf2a7e55865af10577db6fc5f14d 100644 (file)
 
 &i2c1 {
        clock-frequency = <400000>;
+
+       pmic@72 {
+               compatible = "menelaus";
+               reg = <0x72>;
+               interrupts = <7 IRQ_TYPE_EDGE_RISING>;
+       };
 };
 
 &i2c2 {
index 226f3631c230252cabc60403fc706ea862d11b7a..d0e884d3a7372f003f1777aeba1f6ccc15c2e26c 100644 (file)
                };
 
                intc: interrupt-controller@48200000 {
-                       compatible = "ti,omap2-intc";
+                       compatible = "ti,omap3-intc";
                        interrupt-controller;
                        #interrupt-cells = <1>;
-                       ti,intc-size = <96>;
                        reg = <0x48200000 0x1000>;
                };
 
index 1947a09e5a3f04f4170d82a46a29a12b80bf81a1..0e6d548b70d9720d78c55c8a3341402486bc6dc9 100644 (file)
@@ -36,17 +36,6 @@ config OLD_IRQ_AT91
        select MULTI_IRQ_HANDLER
        select SPARSE_IRQ
 
-config AT91_SAM9_ALT_RESET
-       bool
-       default !ARCH_AT91X40
-
-config AT91_SAM9G45_RESET
-       bool
-       default !ARCH_AT91X40
-
-config AT91_SAM9_TIME
-       bool
-
 config HAVE_AT91_SMD
        bool
 
@@ -55,18 +44,20 @@ config HAVE_AT91_H32MX
 
 config SOC_AT91SAM9
        bool
-       select AT91_SAM9_TIME
        select ATMEL_AIC_IRQ if !OLD_IRQ_AT91
        select CPU_ARM926T
        select GENERIC_CLOCKEVENTS
+       select MEMORY if USE_OF
+       select ATMEL_SDRAMC if USE_OF
 
 config SOC_SAMA5
        bool
-       select AT91_SAM9_TIME
        select ATMEL_AIC5_IRQ
        select CPU_V7
        select GENERIC_CLOCKEVENTS
        select USE_OF
+       select MEMORY
+       select ATMEL_SDRAMC
 
 menu "Atmel AT91 System-on-Chip"
 
index 603365e44ed57adaf21ee8d54e4aa1321f42dd73..ac99d87ffefea5562346f454ae145c1f3e94200e 100644 (file)
@@ -9,9 +9,6 @@ obj-            :=
 
 obj-$(CONFIG_OLD_IRQ_AT91)     += irq.o
 obj-$(CONFIG_OLD_CLK_AT91)     += clock.o
-obj-$(CONFIG_AT91_SAM9_ALT_RESET) += at91sam9_alt_reset.o
-obj-$(CONFIG_AT91_SAM9G45_RESET) += at91sam9g45_reset.o
-obj-$(CONFIG_AT91_SAM9_TIME)   += at91sam926x_time.o
 obj-$(CONFIG_SOC_AT91SAM9)     += sam9_smc.o
 
 # CPU-specific support
diff --git a/arch/arm/mach-at91/at91_rstc.h b/arch/arm/mach-at91/at91_rstc.h
deleted file mode 100644 (file)
index a600e69..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * arch/arm/mach-at91/include/mach/at91_rstc.h
- *
- * Copyright (C) 2007 Andrew Victor
- * Copyright (C) 2007 Atmel Corporation.
- *
- * Reset Controller (RSTC) - System peripherals regsters.
- * Based on AT91SAM9261 datasheet revision D.
- *
- * 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.
- */
-
-#ifndef AT91_RSTC_H
-#define AT91_RSTC_H
-
-#ifndef __ASSEMBLY__
-extern void __iomem *at91_rstc_base;
-
-#define at91_rstc_read(field) \
-       __raw_readl(at91_rstc_base + field)
-
-#define at91_rstc_write(field, value) \
-       __raw_writel(value, at91_rstc_base + field)
-#else
-.extern at91_rstc_base
-#endif
-
-#define AT91_RSTC_CR           0x00                    /* Reset Controller Control Register */
-#define                AT91_RSTC_PROCRST       (1 << 0)                /* Processor Reset */
-#define                AT91_RSTC_PERRST        (1 << 2)                /* Peripheral Reset */
-#define                AT91_RSTC_EXTRST        (1 << 3)                /* External Reset */
-#define                AT91_RSTC_KEY           (0xa5 << 24)            /* KEY Password */
-
-#define AT91_RSTC_SR           0x04                    /* Reset Controller Status Register */
-#define                AT91_RSTC_URSTS         (1 << 0)                /* User Reset Status */
-#define                AT91_RSTC_RSTTYP        (7 << 8)                /* Reset Type */
-#define                        AT91_RSTC_RSTTYP_GENERAL        (0 << 8)
-#define                        AT91_RSTC_RSTTYP_WAKEUP         (1 << 8)
-#define                        AT91_RSTC_RSTTYP_WATCHDOG       (2 << 8)
-#define                        AT91_RSTC_RSTTYP_SOFTWARE       (3 << 8)
-#define                        AT91_RSTC_RSTTYP_USER   (4 << 8)
-#define                AT91_RSTC_NRSTL         (1 << 16)               /* NRST Pin Level */
-#define                AT91_RSTC_SRCMP         (1 << 17)               /* Software Reset Command in Progress */
-
-#define AT91_RSTC_MR           0x08                    /* Reset Controller Mode Register */
-#define                AT91_RSTC_URSTEN        (1 << 0)                /* User Reset Enable */
-#define                AT91_RSTC_URSTIEN       (1 << 4)                /* User Reset Interrupt Enable */
-#define                AT91_RSTC_ERSTL         (0xf << 8)              /* External Reset Length */
-
-#endif
diff --git a/arch/arm/mach-at91/at91_shdwc.h b/arch/arm/mach-at91/at91_shdwc.h
deleted file mode 100644 (file)
index 9e29f31..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * arch/arm/mach-at91/include/mach/at91_shdwc.h
- *
- * Copyright (C) 2007 Andrew Victor
- * Copyright (C) 2007 Atmel Corporation.
- *
- * Shutdown Controller (SHDWC) - System peripherals regsters.
- * Based on AT91SAM9261 datasheet revision D.
- *
- * 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.
- */
-
-#ifndef AT91_SHDWC_H
-#define AT91_SHDWC_H
-
-#ifndef __ASSEMBLY__
-extern void __iomem *at91_shdwc_base;
-
-#define at91_shdwc_read(field) \
-       __raw_readl(at91_shdwc_base + field)
-
-#define at91_shdwc_write(field, value) \
-       __raw_writel(value, at91_shdwc_base + field)
-#endif
-
-#define AT91_SHDW_CR           0x00                    /* Shut Down Control Register */
-#define                AT91_SHDW_SHDW          (1    << 0)             /* Shut Down command */
-#define                AT91_SHDW_KEY           (0xa5 << 24)            /* KEY Password */
-
-#define AT91_SHDW_MR           0x04                    /* Shut Down Mode Register */
-#define                AT91_SHDW_WKMODE0       (3 << 0)                /* Wake-up 0 Mode Selection */
-#define                        AT91_SHDW_WKMODE0_NONE          0
-#define                        AT91_SHDW_WKMODE0_HIGH          1
-#define                        AT91_SHDW_WKMODE0_LOW           2
-#define                        AT91_SHDW_WKMODE0_ANYLEVEL      3
-#define                AT91_SHDW_CPTWK0_MAX    0xf                     /* Maximum Counter On Wake Up 0 */
-#define                AT91_SHDW_CPTWK0        (AT91_SHDW_CPTWK0_MAX << 4) /* Counter On Wake Up 0 */
-#define                        AT91_SHDW_CPTWK0_(x)    ((x) << 4)
-#define                AT91_SHDW_RTTWKEN       (1   << 16)             /* Real Time Timer Wake-up Enable */
-#define                AT91_SHDW_RTCWKEN       (1   << 17)             /* Real Time Clock Wake-up Enable */
-
-#define AT91_SHDW_SR           0x08                    /* Shut Down Status Register */
-#define                AT91_SHDW_WAKEUP0       (1 <<  0)               /* Wake-up 0 Status */
-#define                AT91_SHDW_RTTWK         (1 << 16)               /* Real-time Timer Wake-up */
-#define                AT91_SHDW_RTCWK         (1 << 17)               /* Real-time Clock Wake-up [SAM9RL] */
-
-#endif
index 3477ba94c4c5b8a8e80c99967a352c1c6ab3e477..aab1f969a7c3f6bba1b2d51824c34e3e28a2f13d 100644 (file)
@@ -11,6 +11,7 @@
  */
 
 #include <linux/module.h>
+#include <linux/platform_device.h>
 #include <linux/clk/at91_pmc.h>
 
 #include <asm/proc-fns.h>
@@ -24,7 +25,6 @@
 #include <mach/hardware.h>
 
 #include "at91_aic.h"
-#include "at91_rstc.h"
 #include "soc.h"
 #include "generic.h"
 #include "sam9_smc.h"
@@ -342,8 +342,6 @@ static void __init at91sam9260_map_io(void)
 
 static void __init at91sam9260_ioremap_registers(void)
 {
-       at91_ioremap_shdwc(AT91SAM9260_BASE_SHDWC);
-       at91_ioremap_rstc(AT91SAM9260_BASE_RSTC);
        at91_ioremap_ramc(0, AT91SAM9260_BASE_SDRAMC, 512);
        at91sam926x_ioremap_pit(AT91SAM9260_BASE_PIT);
        at91sam9_ioremap_smc(0, AT91SAM9260_BASE_SMC);
@@ -354,7 +352,6 @@ static void __init at91sam9260_ioremap_registers(void)
 static void __init at91sam9260_initialize(void)
 {
        arm_pm_idle = at91sam9_idle;
-       arm_pm_restart = at91sam9_alt_restart;
 
        at91_sysirq_mask_rtt(AT91SAM9260_BASE_RTT);
 
@@ -362,6 +359,45 @@ static void __init at91sam9260_initialize(void)
        at91_gpio_init(at91sam9260_gpio, 3);
 }
 
+static struct resource rstc_resources[] = {
+       [0] = {
+               .start  = AT91SAM9260_BASE_RSTC,
+               .end    = AT91SAM9260_BASE_RSTC + SZ_16 - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = AT91SAM9260_BASE_SDRAMC,
+               .end    = AT91SAM9260_BASE_SDRAMC + SZ_512 - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+};
+
+static struct platform_device rstc_device = {
+       .name           = "at91-sam9260-reset",
+       .resource       = rstc_resources,
+       .num_resources  = ARRAY_SIZE(rstc_resources),
+};
+
+static struct resource shdwc_resources[] = {
+       [0] = {
+               .start  = AT91SAM9260_BASE_SHDWC,
+               .end    = AT91SAM9260_BASE_SHDWC + SZ_16 - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+};
+
+static struct platform_device shdwc_device = {
+       .name           = "at91-poweroff",
+       .resource       = shdwc_resources,
+       .num_resources  = ARRAY_SIZE(shdwc_resources),
+};
+
+static void __init at91sam9260_register_devices(void)
+{
+       platform_device_register(&rstc_device);
+       platform_device_register(&shdwc_device);
+}
+
 /* --------------------------------------------------------------------
  *  Interrupt initialization
  * -------------------------------------------------------------------- */
@@ -404,6 +440,11 @@ static unsigned int at91sam9260_default_irq_priority[NR_AIC_IRQS] __initdata = {
        0,      /* Advanced Interrupt Controller */
 };
 
+static void __init at91sam9260_init_time(void)
+{
+       at91sam926x_pit_init(NR_IRQS_LEGACY + AT91_ID_SYS);
+}
+
 AT91_SOC_START(at91sam9260)
        .map_io = at91sam9260_map_io,
        .default_irq_priority = at91sam9260_default_irq_priority,
@@ -411,5 +452,7 @@ AT91_SOC_START(at91sam9260)
                    | (1 << AT91SAM9260_ID_IRQ2),
        .ioremap_registers = at91sam9260_ioremap_registers,
        .register_clocks = at91sam9260_register_clocks,
+       .register_devices = at91sam9260_register_devices,
        .init = at91sam9260_initialize,
+       .init_time = at91sam9260_init_time,
 AT91_SOC_END
index fb164a5d04a906b09cb44872f7be7edf1784737a..a8bd35963332f540bdcac00e87f04d09f121b805 100644 (file)
@@ -11,6 +11,7 @@
  */
 
 #include <linux/module.h>
+#include <linux/platform_device.h>
 #include <linux/clk/at91_pmc.h>
 
 #include <asm/proc-fns.h>
@@ -23,7 +24,6 @@
 #include <mach/hardware.h>
 
 #include "at91_aic.h"
-#include "at91_rstc.h"
 #include "soc.h"
 #include "generic.h"
 #include "sam9_smc.h"
@@ -301,8 +301,6 @@ static void __init at91sam9261_map_io(void)
 
 static void __init at91sam9261_ioremap_registers(void)
 {
-       at91_ioremap_shdwc(AT91SAM9261_BASE_SHDWC);
-       at91_ioremap_rstc(AT91SAM9261_BASE_RSTC);
        at91_ioremap_ramc(0, AT91SAM9261_BASE_SDRAMC, 512);
        at91sam926x_ioremap_pit(AT91SAM9261_BASE_PIT);
        at91sam9_ioremap_smc(0, AT91SAM9261_BASE_SMC);
@@ -313,7 +311,6 @@ static void __init at91sam9261_ioremap_registers(void)
 static void __init at91sam9261_initialize(void)
 {
        arm_pm_idle = at91sam9_idle;
-       arm_pm_restart = at91sam9_alt_restart;
 
        at91_sysirq_mask_rtt(AT91SAM9261_BASE_RTT);
 
@@ -321,6 +318,45 @@ static void __init at91sam9261_initialize(void)
        at91_gpio_init(at91sam9261_gpio, 3);
 }
 
+static struct resource rstc_resources[] = {
+       [0] = {
+               .start  = AT91SAM9261_BASE_RSTC,
+               .end    = AT91SAM9261_BASE_RSTC + SZ_16 - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = AT91SAM9261_BASE_SDRAMC,
+               .end    = AT91SAM9261_BASE_SDRAMC + SZ_512 - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+};
+
+static struct platform_device rstc_device = {
+       .name           = "at91-sam9260-reset",
+       .resource       = rstc_resources,
+       .num_resources  = ARRAY_SIZE(rstc_resources),
+};
+
+static struct resource shdwc_resources[] = {
+       [0] = {
+               .start  = AT91SAM9261_BASE_SHDWC,
+               .end    = AT91SAM9261_BASE_SHDWC + SZ_16 - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+};
+
+static struct platform_device shdwc_device = {
+       .name           = "at91-poweroff",
+       .resource       = shdwc_resources,
+       .num_resources  = ARRAY_SIZE(shdwc_resources),
+};
+
+static void __init at91sam9261_register_devices(void)
+{
+       platform_device_register(&rstc_device);
+       platform_device_register(&shdwc_device);
+}
+
 /* --------------------------------------------------------------------
  *  Interrupt initialization
  * -------------------------------------------------------------------- */
@@ -363,6 +399,11 @@ static unsigned int at91sam9261_default_irq_priority[NR_AIC_IRQS] __initdata = {
        0,      /* Advanced Interrupt Controller */
 };
 
+static void __init at91sam9261_init_time(void)
+{
+       at91sam926x_pit_init(NR_IRQS_LEGACY + AT91_ID_SYS);
+}
+
 AT91_SOC_START(at91sam9261)
        .map_io = at91sam9261_map_io,
        .default_irq_priority = at91sam9261_default_irq_priority,
@@ -370,5 +411,7 @@ AT91_SOC_START(at91sam9261)
                    | (1 << AT91SAM9261_ID_IRQ2),
        .ioremap_registers = at91sam9261_ioremap_registers,
        .register_clocks = at91sam9261_register_clocks,
+       .register_devices = at91sam9261_register_devices,
        .init = at91sam9261_initialize,
+       .init_time = at91sam9261_init_time,
 AT91_SOC_END
index 810fa5f15a51a0c7b4db7ca022185910e2d9e064..fbff228cc63ed5e54da7c97f79f140083845dc6d 100644 (file)
@@ -11,6 +11,7 @@
  */
 
 #include <linux/module.h>
+#include <linux/platform_device.h>
 #include <linux/clk/at91_pmc.h>
 
 #include <asm/proc-fns.h>
@@ -22,7 +23,6 @@
 #include <mach/hardware.h>
 
 #include "at91_aic.h"
-#include "at91_rstc.h"
 #include "soc.h"
 #include "generic.h"
 #include "sam9_smc.h"
@@ -321,8 +321,6 @@ static void __init at91sam9263_map_io(void)
 
 static void __init at91sam9263_ioremap_registers(void)
 {
-       at91_ioremap_shdwc(AT91SAM9263_BASE_SHDWC);
-       at91_ioremap_rstc(AT91SAM9263_BASE_RSTC);
        at91_ioremap_ramc(0, AT91SAM9263_BASE_SDRAMC0, 512);
        at91_ioremap_ramc(1, AT91SAM9263_BASE_SDRAMC1, 512);
        at91sam926x_ioremap_pit(AT91SAM9263_BASE_PIT);
@@ -335,7 +333,6 @@ static void __init at91sam9263_ioremap_registers(void)
 static void __init at91sam9263_initialize(void)
 {
        arm_pm_idle = at91sam9_idle;
-       arm_pm_restart = at91sam9_alt_restart;
 
        at91_sysirq_mask_rtt(AT91SAM9263_BASE_RTT0);
        at91_sysirq_mask_rtt(AT91SAM9263_BASE_RTT1);
@@ -344,6 +341,45 @@ static void __init at91sam9263_initialize(void)
        at91_gpio_init(at91sam9263_gpio, 5);
 }
 
+static struct resource rstc_resources[] = {
+       [0] = {
+               .start  = AT91SAM9263_BASE_RSTC,
+               .end    = AT91SAM9263_BASE_RSTC + SZ_16 - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = AT91SAM9263_BASE_SDRAMC0,
+               .end    = AT91SAM9263_BASE_SDRAMC0 + SZ_512 - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+};
+
+static struct platform_device rstc_device = {
+       .name           = "at91-sam9260-reset",
+       .resource       = rstc_resources,
+       .num_resources  = ARRAY_SIZE(rstc_resources),
+};
+
+static struct resource shdwc_resources[] = {
+       [0] = {
+               .start  = AT91SAM9263_BASE_SHDWC,
+               .end    = AT91SAM9263_BASE_SHDWC + SZ_16 - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+};
+
+static struct platform_device shdwc_device = {
+       .name           = "at91-poweroff",
+       .resource       = shdwc_resources,
+       .num_resources  = ARRAY_SIZE(shdwc_resources),
+};
+
+static void __init at91sam9263_register_devices(void)
+{
+       platform_device_register(&rstc_device);
+       platform_device_register(&shdwc_device);
+}
+
 /* --------------------------------------------------------------------
  *  Interrupt initialization
  * -------------------------------------------------------------------- */
@@ -386,11 +422,18 @@ static unsigned int at91sam9263_default_irq_priority[NR_AIC_IRQS] __initdata = {
        0,      /* Advanced Interrupt Controller (IRQ1) */
 };
 
+static void __init at91sam9263_init_time(void)
+{
+       at91sam926x_pit_init(NR_IRQS_LEGACY + AT91_ID_SYS);
+}
+
 AT91_SOC_START(at91sam9263)
        .map_io = at91sam9263_map_io,
        .default_irq_priority = at91sam9263_default_irq_priority,
        .extern_irq = (1 << AT91SAM9263_ID_IRQ0) | (1 << AT91SAM9263_ID_IRQ1),
        .ioremap_registers = at91sam9263_ioremap_registers,
        .register_clocks = at91sam9263_register_clocks,
+       .register_devices = at91sam9263_register_devices,
        .init = at91sam9263_initialize,
+       .init_time = at91sam9263_init_time,
 AT91_SOC_END
diff --git a/arch/arm/mach-at91/at91sam926x_time.c b/arch/arm/mach-at91/at91sam926x_time.c
deleted file mode 100644 (file)
index 0a9e2fc..0000000
+++ /dev/null
@@ -1,294 +0,0 @@
-/*
- * at91sam926x_time.c - Periodic Interval Timer (PIT) for at91sam926x
- *
- * Copyright (C) 2005-2006 M. Amine SAYA, ATMEL Rousset, France
- * Revision     2005 M. Nicolas Diremdjian, ATMEL Rousset, France
- * Converted to ClockSource/ClockEvents by David Brownell.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-#include <linux/interrupt.h>
-#include <linux/irq.h>
-#include <linux/kernel.h>
-#include <linux/clk.h>
-#include <linux/clockchips.h>
-#include <linux/of.h>
-#include <linux/of_address.h>
-#include <linux/of_irq.h>
-
-#include <asm/mach/time.h>
-#include <mach/hardware.h>
-
-#define AT91_PIT_MR            0x00                    /* Mode Register */
-#define                AT91_PIT_PITIEN         (1 << 25)               /* Timer Interrupt Enable */
-#define                AT91_PIT_PITEN          (1 << 24)               /* Timer Enabled */
-#define                AT91_PIT_PIV            (0xfffff)               /* Periodic Interval Value */
-
-#define AT91_PIT_SR            0x04                    /* Status Register */
-#define                AT91_PIT_PITS           (1 << 0)                /* Timer Status */
-
-#define AT91_PIT_PIVR          0x08                    /* Periodic Interval Value Register */
-#define AT91_PIT_PIIR          0x0c                    /* Periodic Interval Image Register */
-#define                AT91_PIT_PICNT          (0xfff << 20)           /* Interval Counter */
-#define                AT91_PIT_CPIV           (0xfffff)               /* Inverval Value */
-
-#define PIT_CPIV(x)    ((x) & AT91_PIT_CPIV)
-#define PIT_PICNT(x)   (((x) & AT91_PIT_PICNT) >> 20)
-
-static u32 pit_cycle;          /* write-once */
-static u32 pit_cnt;            /* access only w/system irq blocked */
-static void __iomem *pit_base_addr __read_mostly;
-static struct clk *mck;
-
-static inline unsigned int pit_read(unsigned int reg_offset)
-{
-       return __raw_readl(pit_base_addr + reg_offset);
-}
-
-static inline void pit_write(unsigned int reg_offset, unsigned long value)
-{
-       __raw_writel(value, pit_base_addr + reg_offset);
-}
-
-/*
- * Clocksource:  just a monotonic counter of MCK/16 cycles.
- * We don't care whether or not PIT irqs are enabled.
- */
-static cycle_t read_pit_clk(struct clocksource *cs)
-{
-       unsigned long flags;
-       u32 elapsed;
-       u32 t;
-
-       raw_local_irq_save(flags);
-       elapsed = pit_cnt;
-       t = pit_read(AT91_PIT_PIIR);
-       raw_local_irq_restore(flags);
-
-       elapsed += PIT_PICNT(t) * pit_cycle;
-       elapsed += PIT_CPIV(t);
-       return elapsed;
-}
-
-static struct clocksource pit_clk = {
-       .name           = "pit",
-       .rating         = 175,
-       .read           = read_pit_clk,
-       .flags          = CLOCK_SOURCE_IS_CONTINUOUS,
-};
-
-
-/*
- * Clockevent device:  interrupts every 1/HZ (== pit_cycles * MCK/16)
- */
-static void
-pit_clkevt_mode(enum clock_event_mode mode, struct clock_event_device *dev)
-{
-       switch (mode) {
-       case CLOCK_EVT_MODE_PERIODIC:
-               /* update clocksource counter */
-               pit_cnt += pit_cycle * PIT_PICNT(pit_read(AT91_PIT_PIVR));
-               pit_write(AT91_PIT_MR, (pit_cycle - 1) | AT91_PIT_PITEN
-                               | AT91_PIT_PITIEN);
-               break;
-       case CLOCK_EVT_MODE_ONESHOT:
-               BUG();
-               /* FALLTHROUGH */
-       case CLOCK_EVT_MODE_SHUTDOWN:
-       case CLOCK_EVT_MODE_UNUSED:
-               /* disable irq, leaving the clocksource active */
-               pit_write(AT91_PIT_MR, (pit_cycle - 1) | AT91_PIT_PITEN);
-               break;
-       case CLOCK_EVT_MODE_RESUME:
-               break;
-       }
-}
-
-static void at91sam926x_pit_suspend(struct clock_event_device *cedev)
-{
-       /* Disable timer */
-       pit_write(AT91_PIT_MR, 0);
-}
-
-static void at91sam926x_pit_reset(void)
-{
-       /* Disable timer and irqs */
-       pit_write(AT91_PIT_MR, 0);
-
-       /* Clear any pending interrupts, wait for PIT to stop counting */
-       while (PIT_CPIV(pit_read(AT91_PIT_PIVR)) != 0)
-               cpu_relax();
-
-       /* Start PIT but don't enable IRQ */
-       pit_write(AT91_PIT_MR, (pit_cycle - 1) | AT91_PIT_PITEN);
-}
-
-static void at91sam926x_pit_resume(struct clock_event_device *cedev)
-{
-       at91sam926x_pit_reset();
-}
-
-static struct clock_event_device pit_clkevt = {
-       .name           = "pit",
-       .features       = CLOCK_EVT_FEAT_PERIODIC,
-       .shift          = 32,
-       .rating         = 100,
-       .set_mode       = pit_clkevt_mode,
-       .suspend        = at91sam926x_pit_suspend,
-       .resume         = at91sam926x_pit_resume,
-};
-
-
-/*
- * IRQ handler for the timer.
- */
-static irqreturn_t at91sam926x_pit_interrupt(int irq, void *dev_id)
-{
-       /*
-        * irqs should be disabled here, but as the irq is shared they are only
-        * guaranteed to be off if the timer irq is registered first.
-        */
-       WARN_ON_ONCE(!irqs_disabled());
-
-       /* The PIT interrupt may be disabled, and is shared */
-       if ((pit_clkevt.mode == CLOCK_EVT_MODE_PERIODIC)
-                       && (pit_read(AT91_PIT_SR) & AT91_PIT_PITS)) {
-               unsigned nr_ticks;
-
-               /* Get number of ticks performed before irq, and ack it */
-               nr_ticks = PIT_PICNT(pit_read(AT91_PIT_PIVR));
-               do {
-                       pit_cnt += pit_cycle;
-                       pit_clkevt.event_handler(&pit_clkevt);
-                       nr_ticks--;
-               } while (nr_ticks);
-
-               return IRQ_HANDLED;
-       }
-
-       return IRQ_NONE;
-}
-
-static struct irqaction at91sam926x_pit_irq = {
-       .name           = "at91_tick",
-       .flags          = IRQF_SHARED | IRQF_TIMER | IRQF_IRQPOLL,
-       .handler        = at91sam926x_pit_interrupt,
-       .irq            = NR_IRQS_LEGACY + AT91_ID_SYS,
-};
-
-#ifdef CONFIG_OF
-static struct of_device_id pit_timer_ids[] = {
-       { .compatible = "atmel,at91sam9260-pit" },
-       { /* sentinel */ }
-};
-
-static int __init of_at91sam926x_pit_init(void)
-{
-       struct device_node      *np;
-       int                     ret;
-
-       np = of_find_matching_node(NULL, pit_timer_ids);
-       if (!np)
-               goto err;
-
-       pit_base_addr = of_iomap(np, 0);
-       if (!pit_base_addr)
-               goto node_err;
-
-       mck = of_clk_get(np, 0);
-
-       /* Get the interrupts property */
-       ret = irq_of_parse_and_map(np, 0);
-       if (!ret) {
-               pr_crit("AT91: PIT: Unable to get IRQ from DT\n");
-               if (!IS_ERR(mck))
-                       clk_put(mck);
-               goto ioremap_err;
-       }
-       at91sam926x_pit_irq.irq = ret;
-
-       of_node_put(np);
-
-       return 0;
-
-ioremap_err:
-       iounmap(pit_base_addr);
-node_err:
-       of_node_put(np);
-err:
-       return -EINVAL;
-}
-#else
-static int __init of_at91sam926x_pit_init(void)
-{
-       return -EINVAL;
-}
-#endif
-
-/*
- * Set up both clocksource and clockevent support.
- */
-void __init at91sam926x_pit_init(void)
-{
-       unsigned long   pit_rate;
-       unsigned        bits;
-       int             ret;
-
-       mck = ERR_PTR(-ENOENT);
-
-       /* For device tree enabled device: initialize here */
-       of_at91sam926x_pit_init();
-
-       /*
-        * Use our actual MCK to figure out how many MCK/16 ticks per
-        * 1/HZ period (instead of a compile-time constant LATCH).
-        */
-       if (IS_ERR(mck))
-               mck = clk_get(NULL, "mck");
-
-       if (IS_ERR(mck))
-               panic("AT91: PIT: Unable to get mck clk\n");
-       pit_rate = clk_get_rate(mck) / 16;
-       pit_cycle = (pit_rate + HZ/2) / HZ;
-       WARN_ON(((pit_cycle - 1) & ~AT91_PIT_PIV) != 0);
-
-       /* Initialize and enable the timer */
-       at91sam926x_pit_reset();
-
-       /*
-        * Register clocksource.  The high order bits of PIV are unused,
-        * so this isn't a 32-bit counter unless we get clockevent irqs.
-        */
-       bits = 12 /* PICNT */ + ilog2(pit_cycle) /* PIV */;
-       pit_clk.mask = CLOCKSOURCE_MASK(bits);
-       clocksource_register_hz(&pit_clk, pit_rate);
-
-       /* Set up irq handler */
-       ret = setup_irq(at91sam926x_pit_irq.irq, &at91sam926x_pit_irq);
-       if (ret)
-               pr_crit("AT91: PIT: Unable to setup IRQ\n");
-
-       /* Set up and register clockevents */
-       pit_clkevt.mult = div_sc(pit_rate, NSEC_PER_SEC, pit_clkevt.shift);
-       pit_clkevt.cpumask = cpumask_of(0);
-       clockevents_register_device(&pit_clkevt);
-}
-
-void __init at91sam926x_ioremap_pit(u32 addr)
-{
-#if defined(CONFIG_OF)
-       struct device_node *np =
-               of_find_matching_node(NULL, pit_timer_ids);
-
-       if (np) {
-               of_node_put(np);
-               return;
-       }
-#endif
-       pit_base_addr = ioremap(addr, 16);
-
-       if (!pit_base_addr)
-               panic("Impossible to ioremap PIT\n");
-}
diff --git a/arch/arm/mach-at91/at91sam9_alt_reset.S b/arch/arm/mach-at91/at91sam9_alt_reset.S
deleted file mode 100644 (file)
index f039538..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * reset AT91SAM9G20 as per errata
- *
- * (C) BitBox Ltd 2010
- *
- * unless the SDRAM is cleanly shutdown before we hit the
- * reset register it can be left driving the data bus and
- * killing the chance of a subsequent boot from NAND
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#include <linux/linkage.h>
-#include <mach/hardware.h>
-#include <mach/at91_ramc.h>
-#include "at91_rstc.h"
-
-                       .arm
-
-                       .globl  at91sam9_alt_restart
-
-at91sam9_alt_restart:  ldr     r0, =at91_ramc_base             @ preload constants
-                       ldr     r0, [r0]
-                       ldr     r4, =at91_rstc_base
-                       ldr     r1, [r4]
-
-                       mov     r2, #1
-                       mov     r3, #AT91_SDRAMC_LPCB_POWER_DOWN
-                       ldr     r4, =AT91_RSTC_KEY | AT91_RSTC_PERRST | AT91_RSTC_PROCRST
-
-                       .balign 32                              @ align to cache line
-
-                       str     r2, [r0, #AT91_SDRAMC_TR]       @ disable SDRAM access
-                       str     r3, [r0, #AT91_SDRAMC_LPR]      @ power down SDRAM
-                       str     r4, [r1, #AT91_RSTC_CR]         @ reset processor
-
-                       b       .
index 9d45496e4932689b5c2f4e14ac477280cbb149c0..405427ec05f8a923f153fa9d384071fd8f3ef72a 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/module.h>
 #include <linux/dma-mapping.h>
 #include <linux/clk/at91_pmc.h>
+#include <linux/platform_device.h>
 
 #include <asm/irq.h>
 #include <asm/mach/arch.h>
@@ -371,8 +372,6 @@ static void __init at91sam9g45_map_io(void)
 
 static void __init at91sam9g45_ioremap_registers(void)
 {
-       at91_ioremap_shdwc(AT91SAM9G45_BASE_SHDWC);
-       at91_ioremap_rstc(AT91SAM9G45_BASE_RSTC);
        at91_ioremap_ramc(0, AT91SAM9G45_BASE_DDRSDRC1, 512);
        at91_ioremap_ramc(1, AT91SAM9G45_BASE_DDRSDRC0, 512);
        at91sam926x_ioremap_pit(AT91SAM9G45_BASE_PIT);
@@ -384,7 +383,6 @@ static void __init at91sam9g45_ioremap_registers(void)
 static void __init at91sam9g45_initialize(void)
 {
        arm_pm_idle = at91sam9_idle;
-       arm_pm_restart = at91sam9g45_restart;
 
        at91_sysirq_mask_rtc(AT91SAM9G45_BASE_RTC);
        at91_sysirq_mask_rtt(AT91SAM9G45_BASE_RTT);
@@ -393,6 +391,50 @@ static void __init at91sam9g45_initialize(void)
        at91_gpio_init(at91sam9g45_gpio, 5);
 }
 
+static struct resource rstc_resources[] = {
+       [0] = {
+               .start  = AT91SAM9G45_BASE_RSTC,
+               .end    = AT91SAM9G45_BASE_RSTC + SZ_16 - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = AT91SAM9G45_BASE_DDRSDRC1,
+               .end    = AT91SAM9G45_BASE_DDRSDRC1 + SZ_512 - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       [2] = {
+               .start  = AT91SAM9G45_BASE_DDRSDRC0,
+               .end    = AT91SAM9G45_BASE_DDRSDRC0 + SZ_512 - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+};
+
+static struct platform_device rstc_device = {
+       .name           = "at91-sam9g45-reset",
+       .resource       = rstc_resources,
+       .num_resources  = ARRAY_SIZE(rstc_resources),
+};
+
+static struct resource shdwc_resources[] = {
+       [0] = {
+               .start  = AT91SAM9G45_BASE_SHDWC,
+               .end    = AT91SAM9G45_BASE_SHDWC + SZ_16 - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+};
+
+static struct platform_device shdwc_device = {
+       .name           = "at91-poweroff",
+       .resource       = shdwc_resources,
+       .num_resources  = ARRAY_SIZE(shdwc_resources),
+};
+
+static void __init at91sam9g45_register_devices(void)
+{
+       platform_device_register(&rstc_device);
+       platform_device_register(&shdwc_device);
+}
+
 /* --------------------------------------------------------------------
  *  Interrupt initialization
  * -------------------------------------------------------------------- */
@@ -435,11 +477,18 @@ static unsigned int at91sam9g45_default_irq_priority[NR_AIC_IRQS] __initdata = {
        0,      /* Advanced Interrupt Controller (IRQ0) */
 };
 
+static void __init at91sam9g45_init_time(void)
+{
+       at91sam926x_pit_init(NR_IRQS_LEGACY + AT91_ID_SYS);
+}
+
 AT91_SOC_START(at91sam9g45)
        .map_io = at91sam9g45_map_io,
        .default_irq_priority = at91sam9g45_default_irq_priority,
        .extern_irq = (1 << AT91SAM9G45_ID_IRQ0),
        .ioremap_registers = at91sam9g45_ioremap_registers,
        .register_clocks = at91sam9g45_register_clocks,
+       .register_devices = at91sam9g45_register_devices,
        .init = at91sam9g45_initialize,
+       .init_time = at91sam9g45_init_time,
 AT91_SOC_END
diff --git a/arch/arm/mach-at91/at91sam9g45_reset.S b/arch/arm/mach-at91/at91sam9g45_reset.S
deleted file mode 100644 (file)
index c40c1e2..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * reset AT91SAM9G45 as per errata
- *
- * Copyright (C) 2011 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcosoft.com>
- *
- * unless the SDRAM is cleanly shutdown before we hit the
- * reset register it can be left driving the data bus and
- * killing the chance of a subsequent boot from NAND
- *
- * GPLv2 Only
- */
-
-#include <linux/linkage.h>
-#include <mach/hardware.h>
-#include <mach/at91_ramc.h>
-#include "at91_rstc.h"
-                       .arm
-
-/*
- * at91_ramc_base is an array void*
- * init at NULL if only one DDR controler is present in or DT
- */
-                       .globl  at91sam9g45_restart
-
-at91sam9g45_restart:
-                       ldr     r5, =at91_ramc_base             @ preload constants
-                       ldr     r0, [r5]
-                       ldr     r5, [r5, #4]                    @ ddr1
-                       cmp     r5, #0
-                       ldr     r4, =at91_rstc_base
-                       ldr     r1, [r4]
-
-                       mov     r2, #1
-                       mov     r3, #AT91_DDRSDRC_LPCB_POWER_DOWN
-                       ldr     r4, =AT91_RSTC_KEY | AT91_RSTC_PERRST | AT91_RSTC_PROCRST
-
-                       .balign 32                              @ align to cache line
-
-                       strne   r2, [r5, #AT91_DDRSDRC_RTR]     @ disable DDR1 access
-                       strne   r3, [r5, #AT91_DDRSDRC_LPR]     @ power down DDR1
-                       str     r2, [r0, #AT91_DDRSDRC_RTR]     @ disable DDR0 access
-                       str     r3, [r0, #AT91_DDRSDRC_LPR]     @ power down DDR0
-                       str     r4, [r1, #AT91_RSTC_CR]         @ reset processor
-
-                       b       .
index 878d5015daab65973686666d0af41446ebc96caf..f553e4ea034bade189daebc308c79343939aa813 100644 (file)
@@ -10,6 +10,7 @@
  */
 
 #include <linux/module.h>
+#include <linux/platform_device.h>
 #include <linux/clk/at91_pmc.h>
 
 #include <asm/proc-fns.h>
@@ -23,7 +24,6 @@
 #include <mach/hardware.h>
 
 #include "at91_aic.h"
-#include "at91_rstc.h"
 #include "soc.h"
 #include "generic.h"
 #include "sam9_smc.h"
@@ -311,8 +311,6 @@ static void __init at91sam9rl_map_io(void)
 
 static void __init at91sam9rl_ioremap_registers(void)
 {
-       at91_ioremap_shdwc(AT91SAM9RL_BASE_SHDWC);
-       at91_ioremap_rstc(AT91SAM9RL_BASE_RSTC);
        at91_ioremap_ramc(0, AT91SAM9RL_BASE_SDRAMC, 512);
        at91sam926x_ioremap_pit(AT91SAM9RL_BASE_PIT);
        at91sam9_ioremap_smc(0, AT91SAM9RL_BASE_SMC);
@@ -323,7 +321,6 @@ static void __init at91sam9rl_ioremap_registers(void)
 static void __init at91sam9rl_initialize(void)
 {
        arm_pm_idle = at91sam9_idle;
-       arm_pm_restart = at91sam9_alt_restart;
 
        at91_sysirq_mask_rtc(AT91SAM9RL_BASE_RTC);
        at91_sysirq_mask_rtt(AT91SAM9RL_BASE_RTT);
@@ -332,6 +329,45 @@ static void __init at91sam9rl_initialize(void)
        at91_gpio_init(at91sam9rl_gpio, 4);
 }
 
+static struct resource rstc_resources[] = {
+       [0] = {
+               .start  = AT91SAM9RL_BASE_RSTC,
+               .end    = AT91SAM9RL_BASE_RSTC + SZ_16 - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = AT91SAM9RL_BASE_SDRAMC,
+               .end    = AT91SAM9RL_BASE_SDRAMC + SZ_512 - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+};
+
+static struct platform_device rstc_device = {
+       .name           = "at91-sam9260-reset",
+       .resource       = rstc_resources,
+       .num_resources  = ARRAY_SIZE(rstc_resources),
+};
+
+static struct resource shdwc_resources[] = {
+       [0] = {
+               .start  = AT91SAM9RL_BASE_SHDWC,
+               .end    = AT91SAM9RL_BASE_SHDWC + SZ_16 - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+};
+
+static struct platform_device shdwc_device = {
+       .name           = "at91-poweroff",
+       .resource       = shdwc_resources,
+       .num_resources  = ARRAY_SIZE(shdwc_resources),
+};
+
+static void __init at91sam9rl_register_devices(void)
+{
+       platform_device_register(&rstc_device);
+       platform_device_register(&shdwc_device);
+}
+
 /* --------------------------------------------------------------------
  *  Interrupt initialization
  * -------------------------------------------------------------------- */
@@ -374,6 +410,11 @@ static unsigned int at91sam9rl_default_irq_priority[NR_AIC_IRQS] __initdata = {
        0,      /* Advanced Interrupt Controller */
 };
 
+static void __init at91sam9rl_init_time(void)
+{
+       at91sam926x_pit_init(NR_IRQS_LEGACY + AT91_ID_SYS);
+}
+
 AT91_SOC_START(at91sam9rl)
        .map_io = at91sam9rl_map_io,
        .default_irq_priority = at91sam9rl_default_irq_priority,
@@ -382,5 +423,7 @@ AT91_SOC_START(at91sam9rl)
 #if defined(CONFIG_OLD_CLK_AT91)
        .register_clocks = at91sam9rl_register_clocks,
 #endif
+       .register_devices = at91sam9rl_register_devices,
        .init = at91sam9rl_initialize,
+       .init_time = at91sam9rl_init_time,
 AT91_SOC_END
index 597c649170aa6f0940ac9e4497b29260f829f52d..e76e35ce81e771fe05248794d5aacbc5fd1ea396 100644 (file)
@@ -167,6 +167,8 @@ static struct at91_cf_data afeb9260_cf_data = {
 
 static void __init afeb9260_board_init(void)
 {
+       at91_register_devices();
+
        /* Serial */
        /* DBGU on ttyS0. (Rx & Tx only) */
        at91_register_uart(0, 0, 0);
@@ -211,7 +213,7 @@ static void __init afeb9260_board_init(void)
 
 MACHINE_START(AFEB9260, "Custom afeb9260 board")
        /* Maintainer: Sergey Lapin <slapin@ossfans.org> */
-       .init_time      = at91sam926x_pit_init,
+       .init_time      = at91_init_time,
        .map_io         = at91_map_io,
        .handle_irq     = at91_aic_handle_irq,
        .init_early     = afeb9260_init_early,
index a30502c8d3790b89ac80d04b3d12d7290f9e14b7..ae827dd2d0d261b860669bab62928ba02e86fbeb 100644 (file)
@@ -170,6 +170,8 @@ static void __init cam60_add_device_nand(void)
 
 static void __init cam60_board_init(void)
 {
+       at91_register_devices();
+
        /* Serial */
        /* DBGU on ttyS0. (Rx & Tx only) */
        at91_register_uart(0, 0, 0);
@@ -188,7 +190,7 @@ static void __init cam60_board_init(void)
 
 MACHINE_START(CAM60, "KwikByte CAM60")
        /* Maintainer: KwikByte */
-       .init_time      = at91sam926x_pit_init,
+       .init_time      = at91_init_time,
        .map_io         = at91_map_io,
        .handle_irq     = at91_aic_handle_irq,
        .init_early     = cam60_init_early,
index 2037f78c84e7c7c4e0eef21f4f050a2a07d3ae0d..731c8318f4f53f0688056762ffbb192744fce246 100644 (file)
@@ -322,6 +322,8 @@ static struct mci_platform_data __initdata cpu9krea_mci0_data = {
 
 static void __init cpu9krea_board_init(void)
 {
+       at91_register_devices();
+
        /* NOR */
        cpu9krea_add_device_nor();
        /* Serial */
@@ -375,7 +377,7 @@ MACHINE_START(CPUAT9260, "Eukrea CPU9260")
 MACHINE_START(CPUAT9G20, "Eukrea CPU9G20")
 #endif
        /* Maintainer: Eric Benard - EUKREA Electromatique */
-       .init_time      = at91sam926x_pit_init,
+       .init_time      = at91_init_time,
        .map_io         = at91_map_io,
        .handle_irq     = at91_aic_handle_irq,
        .init_early     = cpu9krea_init_early,
index dfa8d48146fe57d93c6c522f1ca36cf32a1df565..d3048ccdc41f1dd936c1a01d1cf41b0fec8ebe65 100644 (file)
 #include "board.h"
 #include "generic.h"
 
-
-static void __init sam9_dt_timer_init(void)
-{
-#if defined(CONFIG_COMMON_CLK)
-       of_clk_init(NULL);
-#endif
-       at91sam926x_pit_init();
-}
-
 static const char *at91_dt_board_compat[] __initdata = {
        "atmel,at91sam9",
        NULL
@@ -41,7 +32,6 @@ static const char *at91_dt_board_compat[] __initdata = {
 
 DT_MACHINE_START(at91sam_dt, "Atmel AT91SAM (Device Tree)")
        /* Maintainer: Atmel */
-       .init_time      = sam9_dt_timer_init,
        .map_io         = at91_map_io,
        .init_early     = at91_dt_initialize,
        .dt_compat      = at91_dt_board_compat,
index 6a064e53f4d6e6f211ba48bb683344eda7aecf19..129e2917506bb29f2d810432c25376b0150ad4bf 100644 (file)
 #include "at91_aic.h"
 #include "generic.h"
 
-static void __init sama5_dt_timer_init(void)
-{
-#if defined(CONFIG_COMMON_CLK)
-       of_clk_init(NULL);
-#endif
-       at91sam926x_pit_init();
-}
-
 static void __init sama5_dt_device_init(void)
 {
        of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
@@ -47,7 +39,6 @@ static const char *sama5_dt_board_compat[] __initconst = {
 
 DT_MACHINE_START(sama5_dt, "Atmel SAMA5 (Device Tree)")
        /* Maintainer: Atmel */
-       .init_time      = sama5_dt_timer_init,
        .map_io         = at91_map_io,
        .init_early     = at91_dt_initialize,
        .init_machine   = sama5_dt_device_init,
index 68f1ab6bd08f499dc7e9a5366071024d14685150..a6aa4a2432f2d36166f74fcd5f1414b886a39f75 100644 (file)
@@ -138,6 +138,8 @@ static struct gpio_led flexibity_leds[] = {
 
 static void __init flexibity_board_init(void)
 {
+       at91_register_devices();
+
        /* Serial */
        /* DBGU on ttyS0. (Rx & Tx only) */
        at91_register_uart(0, 0, 0);
@@ -160,7 +162,7 @@ static void __init flexibity_board_init(void)
 
 MACHINE_START(FLEXIBITY, "Flexibity Connect")
        /* Maintainer: Maxim Osipov */
-       .init_time      = at91sam926x_pit_init,
+       .init_time      = at91_init_time,
        .map_io         = at91_map_io,
        .handle_irq     = at91_aic_handle_irq,
        .init_early     = flexibity_init_early,
index b729dd1271bfbb2210e0e564a11cbbfbfd73e6fe..bf5cc55c7db6a623db03db2670aa22c32fec9acb 100644 (file)
@@ -576,7 +576,7 @@ static void __init gsia18s_board_init(void)
 }
 
 MACHINE_START(GSIA18S, "GS_IA18_S")
-       .init_time      = at91sam926x_pit_init,
+       .init_time      = at91_init_time,
        .map_io         = at91_map_io,
        .handle_irq     = at91_aic_handle_irq,
        .init_early     = gsia18s_init_early,
index b48d95ec5152954d26e9485c0a5e1f97977a1d5f..9c26b94ce4489bf1a4c5f64c2ec6aa28df1cd71a 100644 (file)
@@ -219,7 +219,7 @@ static void __init pcontrol_g20_board_init(void)
 
 MACHINE_START(PCONTROL_G20, "PControl G20")
        /* Maintainer: pgsellmann@portner-elektronik.at */
-       .init_time      = at91sam926x_pit_init,
+       .init_time      = at91_init_time,
        .map_io         = at91_map_io,
        .handle_irq     = at91_aic_handle_irq,
        .init_early     = pcontrol_g20_init_early,
index d24dda67e2d343c49259b654c3d2d8d5266759aa..c2166e3a236c54fcdf9e7e28e097a4b1b32489c3 100644 (file)
@@ -187,6 +187,8 @@ static struct gpio_led ek_leds[] = {
 
 static void __init ek_board_init(void)
 {
+       at91_register_devices();
+
        /* Serial */
        /* DBGU on ttyS0. (Rx & Tx only) */
        at91_register_uart(0, 0, 0);
@@ -219,7 +221,7 @@ static void __init ek_board_init(void)
 
 MACHINE_START(SAM9_L9260, "Olimex SAM9-L9260")
        /* Maintainer: Olimex */
-       .init_time      = at91sam926x_pit_init,
+       .init_time      = at91_init_time,
        .map_io         = at91_map_io,
        .handle_irq     = at91_aic_handle_irq,
        .init_early     = ek_init_early,
index 65dea12d685ef98ef32e04aade12bf1f2be0d9b5..bf8a946b4cd0e13d59838c47fbd5cbc7d4d2e3bf 100644 (file)
@@ -45,7 +45,6 @@
 #include <mach/system_rev.h>
 
 #include "at91_aic.h"
-#include "at91_shdwc.h"
 #include "board.h"
 #include "sam9_smc.h"
 #include "generic.h"
@@ -307,6 +306,8 @@ static void __init ek_add_device_buttons(void) {}
 
 static void __init ek_board_init(void)
 {
+       at91_register_devices();
+
        /* Serial */
        /* DBGU on ttyS0. (Rx & Tx only) */
        at91_register_uart(0, 0, 0);
@@ -344,7 +345,7 @@ static void __init ek_board_init(void)
 
 MACHINE_START(AT91SAM9260EK, "Atmel AT91SAM9260-EK")
        /* Maintainer: Atmel */
-       .init_time      = at91sam926x_pit_init,
+       .init_time      = at91_init_time,
        .map_io         = at91_map_io,
        .handle_irq     = at91_aic_handle_irq,
        .init_early     = ek_init_early,
index 4637432de08f32486e0345b71bc15af121e69d95..e85ada820bfb335815d60ed959525e139632857b 100644 (file)
@@ -49,7 +49,6 @@
 #include <mach/system_rev.h>
 
 #include "at91_aic.h"
-#include "at91_shdwc.h"
 #include "board.h"
 #include "sam9_smc.h"
 #include "generic.h"
@@ -561,6 +560,8 @@ static struct gpio_led ek_leds[] = {
 
 static void __init ek_board_init(void)
 {
+       at91_register_devices();
+
        /* Serial */
        /* DBGU on ttyS0. (Rx & Tx only) */
        at91_register_uart(0, 0, 0);
@@ -603,7 +604,7 @@ static void __init ek_board_init(void)
 
 MACHINE_START(AT91SAM9261EK, "Atmel AT91SAM9261-EK")
        /* Maintainer: Atmel */
-       .init_time      = at91sam926x_pit_init,
+       .init_time      = at91_init_time,
        .map_io         = at91_map_io,
        .handle_irq     = at91_aic_handle_irq,
        .init_early     = ek_init_early,
@@ -613,7 +614,7 @@ MACHINE_END
 
 MACHINE_START(AT91SAM9G10EK, "Atmel AT91SAM9G10-EK")
        /* Maintainer: Atmel */
-       .init_time      = at91sam926x_pit_init,
+       .init_time      = at91_init_time,
        .map_io         = at91_map_io,
        .handle_irq     = at91_aic_handle_irq,
        .init_early     = ek_init_early,
index fc446097f410846b7d0c8fe3d347863317d4b696..d76680f2a209301c16a11b4b1aafc9bbceb7e85c 100644 (file)
@@ -50,7 +50,6 @@
 #include <mach/system_rev.h>
 
 #include "at91_aic.h"
-#include "at91_shdwc.h"
 #include "board.h"
 #include "sam9_smc.h"
 #include "generic.h"
@@ -439,6 +438,8 @@ static struct platform_device *devices[] __initdata = {
 
 static void __init ek_board_init(void)
 {
+       at91_register_devices();
+
        /* Serial */
        /* DBGU on ttyS0. (Rx & Tx only) */
        at91_register_uart(0, 0, 0);
@@ -483,7 +484,7 @@ static void __init ek_board_init(void)
 
 MACHINE_START(AT91SAM9263EK, "Atmel AT91SAM9263-EK")
        /* Maintainer: Atmel */
-       .init_time      = at91sam926x_pit_init,
+       .init_time      = at91_init_time,
        .map_io         = at91_map_io,
        .handle_irq     = at91_aic_handle_irq,
        .init_early     = ek_init_early,
index e1be6e25b380aab2e002f3b80352be164b637877..49f0752134510a2dc4a22a7c2f61af78bc71bdd4 100644 (file)
@@ -410,7 +410,7 @@ static void __init ek_board_init(void)
 
 MACHINE_START(AT91SAM9G20EK, "Atmel AT91SAM9G20-EK")
        /* Maintainer: Atmel */
-       .init_time      = at91sam926x_pit_init,
+       .init_time      = at91_init_time,
        .map_io         = at91_map_io,
        .handle_irq     = at91_aic_handle_irq,
        .init_early     = ek_init_early,
@@ -420,7 +420,7 @@ MACHINE_END
 
 MACHINE_START(AT91SAM9G20EK_2MMC, "Atmel AT91SAM9G20-EK 2 MMC Slot Mod")
        /* Maintainer: Atmel */
-       .init_time      = at91sam926x_pit_init,
+       .init_time      = at91_init_time,
        .map_io         = at91_map_io,
        .handle_irq     = at91_aic_handle_irq,
        .init_early     = ek_init_early,
index b227732b0c8343155a35d57e6ca9f8bcb530ed91..a517c7f7af92b4536d718a01e3f2afd957f2521d 100644 (file)
@@ -48,7 +48,6 @@
 #include <mach/system_rev.h>
 
 #include "at91_aic.h"
-#include "at91_shdwc.h"
 #include "board.h"
 #include "sam9_smc.h"
 #include "generic.h"
@@ -471,6 +470,8 @@ static struct platform_device *devices[] __initdata = {
 
 static void __init ek_board_init(void)
 {
+       at91_register_devices();
+
        /* Serial */
        /* DGBU on ttyS0. (Rx & Tx only) */
        at91_register_uart(0, 0, 0);
@@ -517,7 +518,7 @@ static void __init ek_board_init(void)
 
 MACHINE_START(AT91SAM9M10G45EK, "Atmel AT91SAM9M10G45-EK")
        /* Maintainer: Atmel */
-       .init_time      = at91sam926x_pit_init,
+       .init_time      = at91_init_time,
        .map_io         = at91_map_io,
        .handle_irq     = at91_aic_handle_irq,
        .init_early     = ek_init_early,
index b64648b4a1fc9a8720d0b3f45495b08240beba48..8bca329b0293a2c4b6e6e43c083e300218038078 100644 (file)
@@ -35,7 +35,6 @@
 
 
 #include "at91_aic.h"
-#include "at91_shdwc.h"
 #include "board.h"
 #include "sam9_smc.h"
 #include "generic.h"
@@ -292,6 +291,8 @@ static void __init ek_add_device_buttons(void) {}
 
 static void __init ek_board_init(void)
 {
+       at91_register_devices();
+
        /* Serial */
        /* DBGU on ttyS0. (Rx & Tx only) */
        at91_register_uart(0, 0, 0);
@@ -323,7 +324,7 @@ static void __init ek_board_init(void)
 
 MACHINE_START(AT91SAM9RLEK, "Atmel AT91SAM9RL-EK")
        /* Maintainer: Atmel */
-       .init_time      = at91sam926x_pit_init,
+       .init_time      = at91_init_time,
        .map_io         = at91_map_io,
        .handle_irq     = at91_aic_handle_irq,
        .init_early     = ek_init_early,
index 1b870e6def0cf54b5ea692e5e244a7d69a187b61..b4aff840a1a095cc509395a6e39dd6aa4233b69f 100644 (file)
@@ -154,6 +154,8 @@ static void __init snapper9260_add_device_nand(void)
 
 static void __init snapper9260_board_init(void)
 {
+       at91_register_devices();
+
        at91_add_device_i2c(snapper9260_i2c_devices,
                            ARRAY_SIZE(snapper9260_i2c_devices));
 
@@ -178,7 +180,7 @@ static void __init snapper9260_board_init(void)
 }
 
 MACHINE_START(SNAPPER_9260, "Bluewater Systems Snapper 9260/9G20 module")
-       .init_time      = at91sam926x_pit_init,
+       .init_time      = at91_init_time,
        .map_io         = at91_map_io,
        .handle_irq     = at91_aic_handle_irq,
        .init_early     = snapper9260_init_early,
index 3b575036ff961ce73d3e657b1f289a4962993556..e825641a1dee80ff099f1691174a510190aea4ad 100644 (file)
@@ -275,7 +275,7 @@ static void __init stamp9g20evb_board_init(void)
 
 MACHINE_START(PORTUXG20, "taskit PortuxG20")
        /* Maintainer: taskit GmbH */
-       .init_time      = at91sam926x_pit_init,
+       .init_time      = at91_init_time,
        .map_io         = at91_map_io,
        .handle_irq     = at91_aic_handle_irq,
        .init_early     = stamp9g20_init_early,
@@ -285,7 +285,7 @@ MACHINE_END
 
 MACHINE_START(STAMP9G20, "taskit Stamp9G20")
        /* Maintainer: taskit GmbH */
-       .init_time      = at91sam926x_pit_init,
+       .init_time      = at91_init_time,
        .map_io         = at91_map_io,
        .handle_irq     = at91_aic_handle_irq,
        .init_early     = stamp9g20_init_early,
index cddf1e51c50eb0518e33f59f5d6cf07f17917583..81959cf4a13715ebd60405b768b7e20af423efc2 100644 (file)
@@ -8,6 +8,9 @@
  * published by the Free Software Foundation.
  */
 
+#ifndef _AT91_GENERIC_H
+#define _AT91_GENERIC_H
+
 #include <linux/clkdev.h>
 #include <linux/of.h>
 #include <linux/reboot.h>
@@ -38,12 +41,15 @@ extern int  __init at91_aic5_of_init(struct device_node *node,
 extern void __init at91_sysirq_mask_rtc(u32 rtc_base);
 extern void __init at91_sysirq_mask_rtt(u32 rtt_base);
 
+ /* Devices */
+extern void __init at91_register_devices(void);
 
  /* Timer */
+extern void __init at91_init_time(void);
 extern void at91rm9200_ioremap_st(u32 addr);
 extern void at91rm9200_timer_init(void);
 extern void at91sam926x_ioremap_pit(u32 addr);
-extern void at91sam926x_pit_init(void);
+extern void at91sam926x_pit_init(int irq);
 extern void at91x40_timer_init(void);
 
  /* Clocks */
@@ -63,14 +69,6 @@ extern void at91_irq_resume(void);
 /* idle */
 extern void at91sam9_idle(void);
 
-/* reset */
-extern void at91_ioremap_rstc(u32 base_addr);
-extern void at91sam9_alt_restart(enum reboot_mode, const char *);
-extern void at91sam9g45_restart(enum reboot_mode, const char *);
-
-/* shutdown */
-extern void at91_ioremap_shdwc(u32 base_addr);
-
 /* Matrix */
 extern void at91_ioremap_matrix(u32 base_addr);
 
@@ -91,3 +89,5 @@ extern int  __init at91_gpio_of_irq_setup(struct device_node *node,
                                          struct device_node *parent);
 
 extern u32 at91_get_extern_irq(void);
+
+#endif /* _AT91_GENERIC_H */
index 5920373809c52dd5195200e99171f16ce1647bcb..4073ab7f38f3db39954ae8363071fba8635745b1 100644 (file)
 #include "pm.h"
 #include "gpio.h"
 
-/*
- * Show the reason for the previous system reset.
- */
-
-#include "at91_rstc.h"
-#include "at91_shdwc.h"
-
 static void (*at91_pm_standby)(void);
 
-static void __init show_reset_status(void)
-{
-       static char reset[] __initdata = "reset";
-
-       static char general[] __initdata = "general";
-       static char wakeup[] __initdata = "wakeup";
-       static char watchdog[] __initdata = "watchdog";
-       static char software[] __initdata = "software";
-       static char user[] __initdata = "user";
-       static char unknown[] __initdata = "unknown";
-
-       static char signal[] __initdata = "signal";
-       static char rtc[] __initdata = "rtc";
-       static char rtt[] __initdata = "rtt";
-       static char restore[] __initdata = "power-restored";
-
-       char *reason, *r2 = reset;
-       u32 reset_type, wake_type;
-
-       if (!at91_shdwc_base || !at91_rstc_base)
-               return;
-
-       reset_type = at91_rstc_read(AT91_RSTC_SR) & AT91_RSTC_RSTTYP;
-       wake_type = at91_shdwc_read(AT91_SHDW_SR);
-
-       switch (reset_type) {
-       case AT91_RSTC_RSTTYP_GENERAL:
-               reason = general;
-               break;
-       case AT91_RSTC_RSTTYP_WAKEUP:
-               /* board-specific code enabled the wakeup sources */
-               reason = wakeup;
-
-               /* "wakeup signal" */
-               if (wake_type & AT91_SHDW_WAKEUP0)
-                       r2 = signal;
-               else {
-                       r2 = reason;
-                       if (wake_type & AT91_SHDW_RTTWK)        /* rtt wakeup */
-                               reason = rtt;
-                       else if (wake_type & AT91_SHDW_RTCWK)   /* rtc wakeup */
-                               reason = rtc;
-                       else if (wake_type == 0)        /* power-restored wakeup */
-                               reason = restore;
-                       else                            /* unknown wakeup */
-                               reason = unknown;
-               }
-               break;
-       case AT91_RSTC_RSTTYP_WATCHDOG:
-               reason = watchdog;
-               break;
-       case AT91_RSTC_RSTTYP_SOFTWARE:
-               reason = software;
-               break;
-       case AT91_RSTC_RSTTYP_USER:
-               reason = user;
-               break;
-       default:
-               reason = unknown;
-               break;
-       }
-       pr_info("AT91: Starting after %s %s\n", reason, r2);
-}
-
 static int at91_pm_valid_state(suspend_state_t state)
 {
        switch (state) {
@@ -346,7 +275,6 @@ static int __init at91_pm_init(void)
 
        suspend_set_ops(&at91_pm_ops);
 
-       show_reset_status();
        return 0;
 }
 arch_initcall(at91_pm_init);
index ebe7fdca9e83fb6b5eb6f1d72eaa1b801139a3fa..961079250b837c25ca7623563285fc090dd09e00 100644 (file)
@@ -5,6 +5,8 @@
  * Under GPLv2
  */
 
+#define pr_fmt(fmt)    "AT91: " fmt
+
 #include <linux/module.h>
 #include <linux/io.h>
 #include <linux/mm.h>
@@ -20,7 +22,6 @@
 #include <mach/cpu.h>
 #include <mach/at91_dbgu.h>
 
-#include "at91_shdwc.h"
 #include "soc.h"
 #include "generic.h"
 #include "pm.h"
@@ -37,7 +38,7 @@ void __init at91rm9200_set_type(int type)
        else
                at91_soc_initdata.subtype = AT91_SOC_RM9200_BGA;
 
-       pr_info("AT91: filled in soc subtype: %s\n",
+       pr_info("filled in soc subtype: %s\n",
                at91_get_soc_subtype(&at91_soc_initdata));
 }
 
@@ -67,7 +68,7 @@ void __init at91_ioremap_ramc(int id, u32 addr, u32 size)
        }
        at91_ramc_base[id] = ioremap(addr, size);
        if (!at91_ramc_base[id])
-               panic("Impossible to ioremap ramc.%d 0x%x\n", id, addr);
+               panic(pr_fmt("Impossible to ioremap ramc.%d 0x%x\n"), id, addr);
 }
 
 static struct map_desc sram_desc[2] __initdata;
@@ -84,7 +85,7 @@ void __init at91_init_sram(int bank, unsigned long base, unsigned int length)
        desc->length = length;
        desc->type = MT_MEMORY_RWX_NONCACHED;
 
-       pr_info("AT91: sram at 0x%lx of 0x%x mapped at 0x%lx\n",
+       pr_info("sram at 0x%lx of 0x%x mapped at 0x%lx\n",
                base, length, desc->virtual);
 
        iotable_init(desc, 1);
@@ -367,45 +368,21 @@ void __init at91_map_io(void)
                soc_detect(AT91_BASE_DBGU1);
 
        if (!at91_soc_is_detected())
-               panic("AT91: Impossible to detect the SOC type");
+               panic(pr_fmt("Impossible to detect the SOC type"));
 
-       pr_info("AT91: Detected soc type: %s\n",
+       pr_info("Detected soc type: %s\n",
                at91_get_soc_type(&at91_soc_initdata));
        if (at91_soc_initdata.subtype != AT91_SOC_SUBTYPE_NONE)
-               pr_info("AT91: Detected soc subtype: %s\n",
+               pr_info("Detected soc subtype: %s\n",
                        at91_get_soc_subtype(&at91_soc_initdata));
 
        if (!at91_soc_is_enabled())
-               panic("AT91: Soc not enabled");
+               panic(pr_fmt("Soc not enabled"));
 
        if (at91_boot_soc.map_io)
                at91_boot_soc.map_io();
 }
 
-void __iomem *at91_shdwc_base = NULL;
-
-static void at91sam9_poweroff(void)
-{
-       at91_shdwc_write(AT91_SHDW_CR, AT91_SHDW_KEY | AT91_SHDW_SHDW);
-}
-
-void __init at91_ioremap_shdwc(u32 base_addr)
-{
-       at91_shdwc_base = ioremap(base_addr, 16);
-       if (!at91_shdwc_base)
-               panic("Impossible to ioremap at91_shdwc_base\n");
-       pm_power_off = at91sam9_poweroff;
-}
-
-void __iomem *at91_rstc_base;
-
-void __init at91_ioremap_rstc(u32 base_addr)
-{
-       at91_rstc_base = ioremap(base_addr, 16);
-       if (!at91_rstc_base)
-               panic("Impossible to ioremap at91_rstc_base\n");
-}
-
 void __init at91_alt_map_io(void)
 {
        /* Map peripherals */
@@ -438,42 +415,15 @@ void __init at91_ioremap_matrix(u32 base_addr)
 {
        at91_matrix_base = ioremap(base_addr, 512);
        if (!at91_matrix_base)
-               panic("Impossible to ioremap at91_matrix_base\n");
+               panic(pr_fmt("Impossible to ioremap at91_matrix_base\n"));
 }
 
 #if defined(CONFIG_OF) && !defined(CONFIG_ARCH_AT91X40)
-static struct of_device_id rstc_ids[] = {
-       { .compatible = "atmel,at91sam9260-rstc", .data = at91sam9_alt_restart },
-       { .compatible = "atmel,at91sam9g45-rstc", .data = at91sam9g45_restart },
-       { /*sentinel*/ }
-};
-
-static void at91_dt_rstc(void)
-{
-       struct device_node *np;
-       const struct of_device_id *of_id;
-
-       np = of_find_matching_node(NULL, rstc_ids);
-       if (!np)
-               panic("unable to find compatible rstc node in dtb\n");
-
-       at91_rstc_base = of_iomap(np, 0);
-       if (!at91_rstc_base)
-               panic("unable to map rstc cpu registers\n");
-
-       of_id = of_match_node(rstc_ids, np);
-       if (!of_id)
-               panic("AT91: rtsc no restart function available\n");
-
-       arm_pm_restart = of_id->data;
-
-       of_node_put(np);
-}
-
 static struct of_device_id ramc_ids[] = {
        { .compatible = "atmel,at91rm9200-sdramc", .data = at91rm9200_standby },
        { .compatible = "atmel,at91sam9260-sdramc", .data = at91sam9_sdram_standby },
        { .compatible = "atmel,at91sam9g45-ddramc", .data = at91_ddr_standby },
+       { .compatible = "atmel,sama5d3-ddramc", .data = at91_ddr_standby },
        { /*sentinel*/ }
 };
 
@@ -481,100 +431,29 @@ static void at91_dt_ramc(void)
 {
        struct device_node *np;
        const struct of_device_id *of_id;
+       int idx = 0;
+       const void *standby = NULL;
 
-       np = of_find_matching_node(NULL, ramc_ids);
-       if (!np)
-               panic("unable to find compatible ram controller node in dtb\n");
-
-       at91_ramc_base[0] = of_iomap(np, 0);
-       if (!at91_ramc_base[0])
-               panic("unable to map ramc[0] cpu registers\n");
-       /* the controller may have 2 banks */
-       at91_ramc_base[1] = of_iomap(np, 1);
-
-       of_id = of_match_node(ramc_ids, np);
-       if (!of_id)
-               pr_warn("AT91: ramc no standby function available\n");
-       else
-               at91_pm_set_standby(of_id->data);
-
-       of_node_put(np);
-}
-
-static struct of_device_id shdwc_ids[] = {
-       { .compatible = "atmel,at91sam9260-shdwc", },
-       { .compatible = "atmel,at91sam9rl-shdwc", },
-       { .compatible = "atmel,at91sam9x5-shdwc", },
-       { /*sentinel*/ }
-};
-
-static const char *shdwc_wakeup_modes[] = {
-       [AT91_SHDW_WKMODE0_NONE]        = "none",
-       [AT91_SHDW_WKMODE0_HIGH]        = "high",
-       [AT91_SHDW_WKMODE0_LOW]         = "low",
-       [AT91_SHDW_WKMODE0_ANYLEVEL]    = "any",
-};
+       for_each_matching_node_and_match(np, ramc_ids, &of_id) {
+               at91_ramc_base[idx] = of_iomap(np, 0);
+               if (!at91_ramc_base[idx])
+                       panic(pr_fmt("unable to map ramc[%d] cpu registers\n"), idx);
 
-const int at91_dtget_shdwc_wakeup_mode(struct device_node *np)
-{
-       const char *pm;
-       int err, i;
-
-       err = of_property_read_string(np, "atmel,wakeup-mode", &pm);
-       if (err < 0)
-               return AT91_SHDW_WKMODE0_ANYLEVEL;
-
-       for (i = 0; i < ARRAY_SIZE(shdwc_wakeup_modes); i++)
-               if (!strcasecmp(pm, shdwc_wakeup_modes[i]))
-                       return i;
-
-       return -ENODEV;
-}
-
-static void at91_dt_shdwc(void)
-{
-       struct device_node *np;
-       int wakeup_mode;
-       u32 reg;
-       u32 mode = 0;
+               if (!standby)
+                       standby = of_id->data;
 
-       np = of_find_matching_node(NULL, shdwc_ids);
-       if (!np) {
-               pr_debug("AT91: unable to find compatible shutdown (shdwc) controller node in dtb\n");
-               return;
+               idx++;
        }
 
-       at91_shdwc_base = of_iomap(np, 0);
-       if (!at91_shdwc_base)
-               panic("AT91: unable to map shdwc cpu registers\n");
-
-       wakeup_mode = at91_dtget_shdwc_wakeup_mode(np);
-       if (wakeup_mode < 0) {
-               pr_warn("AT91: shdwc unknown wakeup mode\n");
-               goto end;
-       }
+       if (!idx)
+               panic(pr_fmt("unable to find compatible ram controller node in dtb\n"));
 
-       if (!of_property_read_u32(np, "atmel,wakeup-counter", &reg)) {
-               if (reg > AT91_SHDW_CPTWK0_MAX) {
-                       pr_warn("AT91: shdwc wakeup counter 0x%x > 0x%x reduce it to 0x%x\n",
-                               reg, AT91_SHDW_CPTWK0_MAX, AT91_SHDW_CPTWK0_MAX);
-                       reg = AT91_SHDW_CPTWK0_MAX;
-               }
-               mode |= AT91_SHDW_CPTWK0_(reg);
+       if (!standby) {
+               pr_warn("ramc no standby function available\n");
+               return;
        }
 
-       if (of_property_read_bool(np, "atmel,wakeup-rtc-timer"))
-                       mode |= AT91_SHDW_RTCWKEN;
-
-       if (of_property_read_bool(np, "atmel,wakeup-rtt-timer"))
-                       mode |= AT91_SHDW_RTTWKEN;
-
-       at91_shdwc_write(AT91_SHDW_MR, wakeup_mode | mode);
-
-end:
-       pm_power_off = at91sam9_poweroff;
-
-       of_node_put(np);
+       at91_pm_set_standby(standby);
 }
 
 void __init at91rm9200_dt_initialize(void)
@@ -593,9 +472,7 @@ void __init at91rm9200_dt_initialize(void)
 
 void __init at91_dt_initialize(void)
 {
-       at91_dt_rstc();
        at91_dt_ramc();
-       at91_dt_shdwc();
 
        /* Init clock subsystem */
        at91_dt_clock_init();
@@ -623,3 +500,13 @@ void __init at91_initialize(unsigned long main_clock)
 
        pinctrl_provide_dummies();
 }
+
+void __init at91_register_devices(void)
+{
+       at91_boot_soc.register_devices();
+}
+
+void __init at91_init_time(void)
+{
+       at91_boot_soc.init_time();
+}
index 8ecaee67f9533fb85720747b404776bf9c87be0d..9a8fd97a8befe1502c9dc12ed64ecc597b2d98b1 100644 (file)
@@ -11,7 +11,9 @@ struct at91_init_soc {
        void (*map_io)(void);
        void (*ioremap_registers)(void);
        void (*register_clocks)(void);
+       void (*register_devices)(void);
        void (*init)(void);
+       void (*init_time)(void);
 };
 
 extern struct at91_init_soc at91_boot_soc;
index 75212c064b31ccab93106c7b8af9db062efa5674..f4d06aea84605993bc2464313adf4f79628ab914 100644 (file)
@@ -83,6 +83,7 @@ config ARCH_OMAP2PLUS
        select PINCTRL
        select SOC_BUS
        select TI_PRIV_EDMA
+       select OMAP_IRQCHIP
        help
          Systems based on OMAP2, OMAP3, OMAP4 or OMAP5
 
index d9dd99c6aa2813f3e67ec2744f9f918a0070a452..d9e94122073ecc44efd9058e5ad80cf047e6abff 100644 (file)
@@ -10,7 +10,6 @@ obj-y := id.o io.o control.o mux.o devices.o fb.o serial.o gpmc.o timer.o pm.o \
         common.o gpio.o dma.o wd_timer.o display.o i2c.o hdq1w.o omap_hwmod.o \
         omap_device.o sram.o drm.o
 
-omap-2-3-common                                = irq.o
 hwmod-common                           = omap_hwmod.o omap_hwmod_reset.o \
                                          omap_hwmod_common_data.o
 clock-common                           = clock.o clock_common_data.o \
@@ -20,7 +19,7 @@ secure-common                         = omap-smc.o omap-secure.o
 obj-$(CONFIG_ARCH_OMAP2) += $(omap-2-3-common) $(hwmod-common)
 obj-$(CONFIG_ARCH_OMAP3) += $(omap-2-3-common) $(hwmod-common) $(secure-common)
 obj-$(CONFIG_ARCH_OMAP4) += $(hwmod-common) $(secure-common)
-obj-$(CONFIG_SOC_AM33XX) += irq.o $(hwmod-common)
+obj-$(CONFIG_SOC_AM33XX) += $(hwmod-common)
 obj-$(CONFIG_SOC_OMAP5)         += $(hwmod-common) $(secure-common)
 obj-$(CONFIG_SOC_AM43XX) += $(hwmod-common) $(secure-common)
 obj-$(CONFIG_SOC_DRA7XX) += $(hwmod-common) $(secure-common)
index d95d0ef1354aeb0b44fecdb2d774d728f820463d..d21a3048d06b6846c926b066ba21a2661645540b 100644 (file)
@@ -625,7 +625,6 @@ MACHINE_START(OMAP_3430SDP, "OMAP3430 3430SDP board")
        .map_io         = omap3_map_io,
        .init_early     = omap3430_init_early,
        .init_irq       = omap3_init_irq,
-       .handle_irq     = omap3_intc_handle_irq,
        .init_machine   = omap_3430sdp_init,
        .init_late      = omap3430_init_late,
        .init_time      = omap3_sync32k_timer_init,
index 0d499a1878f6917f7ce4ffcd61dd04cb92fb6db5..212c3160de183810438a3f8ca2e725674231edb3 100644 (file)
@@ -142,7 +142,6 @@ MACHINE_START(CRANEBOARD, "AM3517/05 CRANEBOARD")
        .map_io         = omap3_map_io,
        .init_early     = am35xx_init_early,
        .init_irq       = omap3_init_irq,
-       .handle_irq     = omap3_intc_handle_irq,
        .init_machine   = am3517_crane_init,
        .init_late      = am35xx_init_late,
        .init_time      = omap3_sync32k_timer_init,
index 4f9383cecf763197c361266ffde549fda56a72db..1c091b3fa31228ada75d14d3415aff0702fa628a 100644 (file)
@@ -366,7 +366,6 @@ MACHINE_START(OMAP3517EVM, "OMAP3517/AM3517 EVM")
        .map_io         = omap3_map_io,
        .init_early     = am35xx_init_early,
        .init_irq       = omap3_init_irq,
-       .handle_irq     = omap3_intc_handle_irq,
        .init_machine   = am3517_evm_init,
        .init_late      = am35xx_init_late,
        .init_time      = omap3_sync32k_timer_init,
index 018353d88b96820faeef14bdd32f4273cfc0264f..c6df8eec45532d2ed26d0180480e416aecf2696f 100644 (file)
@@ -766,7 +766,6 @@ MACHINE_START(CM_T35, "Compulab CM-T35")
        .map_io         = omap3_map_io,
        .init_early     = omap35xx_init_early,
        .init_irq       = omap3_init_irq,
-       .handle_irq     = omap3_intc_handle_irq,
        .init_machine   = cm_t35_init,
        .init_late      = omap35xx_init_late,
        .init_time      = omap3_sync32k_timer_init,
@@ -779,7 +778,6 @@ MACHINE_START(CM_T3730, "Compulab CM-T3730")
        .map_io         = omap3_map_io,
        .init_early     = omap3630_init_early,
        .init_irq       = omap3_init_irq,
-       .handle_irq     = omap3_intc_handle_irq,
        .init_machine   = cm_t3730_init,
        .init_late     = omap3630_init_late,
        .init_time      = omap3_sync32k_timer_init,
index 4eb5e6f2f7f5c7e164797069c4f84a03d1995ad1..8a2c1677964cbb5c0d60c56bb27645b237e1b2fb 100644 (file)
@@ -329,7 +329,6 @@ MACHINE_START(CM_T3517, "Compulab CM-T3517")
        .map_io         = omap3_map_io,
        .init_early     = am35xx_init_early,
        .init_irq       = omap3_init_irq,
-       .handle_irq     = omap3_intc_handle_irq,
        .init_machine   = cm_t3517_init,
        .init_late      = am35xx_init_late,
        .init_time      = omap3_gptimer_timer_init,
index cdc4fb9960a99dda470d6b939366db4d678be595..d8e4f346936a2a0f48755b75233943aed860c34d 100644 (file)
@@ -647,7 +647,6 @@ MACHINE_START(DEVKIT8000, "OMAP3 Devkit8000")
        .map_io         = omap3_map_io,
        .init_early     = omap35xx_init_early,
        .init_irq       = omap3_init_irq,
-       .handle_irq     = omap3_intc_handle_irq,
        .init_machine   = devkit8000_init,
        .init_late      = omap35xx_init_late,
        .init_time      = omap3_secure_sync32k_timer_init,
index 69166eed5dba6e7c7f5d77022be5dc8322e5e656..608079a1aba6774e5ff6682354ecc08ba2d7a882 100644 (file)
@@ -52,8 +52,6 @@ DT_MACHINE_START(OMAP242X_DT, "Generic OMAP2420 (Flattened Device Tree)")
        .reserve        = omap_reserve,
        .map_io         = omap242x_map_io,
        .init_early     = omap2420_init_early,
-       .init_irq       = omap_intc_of_init,
-       .handle_irq     = omap2_intc_handle_irq,
        .init_machine   = omap_generic_init,
        .init_time      = omap2_sync32k_timer_init,
        .dt_compat      = omap242x_boards_compat,
@@ -71,8 +69,6 @@ DT_MACHINE_START(OMAP243X_DT, "Generic OMAP2430 (Flattened Device Tree)")
        .reserve        = omap_reserve,
        .map_io         = omap243x_map_io,
        .init_early     = omap2430_init_early,
-       .init_irq       = omap_intc_of_init,
-       .handle_irq     = omap2_intc_handle_irq,
        .init_machine   = omap_generic_init,
        .init_time      = omap2_sync32k_timer_init,
        .dt_compat      = omap243x_boards_compat,
@@ -91,8 +87,6 @@ DT_MACHINE_START(OMAP3_DT, "Generic OMAP3 (Flattened Device Tree)")
        .reserve        = omap_reserve,
        .map_io         = omap3_map_io,
        .init_early     = omap3430_init_early,
-       .init_irq       = omap_intc_of_init,
-       .handle_irq     = omap3_intc_handle_irq,
        .init_machine   = omap_generic_init,
        .init_late      = omap3_init_late,
        .init_time      = omap3_sync32k_timer_init,
@@ -109,8 +103,6 @@ DT_MACHINE_START(OMAP36XX_DT, "Generic OMAP36xx (Flattened Device Tree)")
        .reserve        = omap_reserve,
        .map_io         = omap3_map_io,
        .init_early     = omap3630_init_early,
-       .init_irq       = omap_intc_of_init,
-       .handle_irq     = omap3_intc_handle_irq,
        .init_machine   = omap_generic_init,
        .init_late      = omap3_init_late,
        .init_time      = omap3_sync32k_timer_init,
@@ -128,8 +120,6 @@ DT_MACHINE_START(OMAP3_GP_DT, "Generic OMAP3-GP (Flattened Device Tree)")
        .reserve        = omap_reserve,
        .map_io         = omap3_map_io,
        .init_early     = omap3430_init_early,
-       .init_irq       = omap_intc_of_init,
-       .handle_irq     = omap3_intc_handle_irq,
        .init_machine   = omap_generic_init,
        .init_late      = omap3_init_late,
        .init_time      = omap3_secure_sync32k_timer_init,
@@ -146,8 +136,6 @@ DT_MACHINE_START(AM3517_DT, "Generic AM3517 (Flattened Device Tree)")
        .reserve        = omap_reserve,
        .map_io         = omap3_map_io,
        .init_early     = am35xx_init_early,
-       .init_irq       = omap_intc_of_init,
-       .handle_irq     = omap3_intc_handle_irq,
        .init_machine   = omap_generic_init,
        .init_late      = omap3_init_late,
        .init_time      = omap3_gptimer_timer_init,
@@ -166,8 +154,6 @@ DT_MACHINE_START(AM33XX_DT, "Generic AM33XX (Flattened Device Tree)")
        .reserve        = omap_reserve,
        .map_io         = am33xx_map_io,
        .init_early     = am33xx_init_early,
-       .init_irq       = omap_intc_of_init,
-       .handle_irq     = omap3_intc_handle_irq,
        .init_machine   = omap_generic_init,
        .init_late      = am33xx_init_late,
        .init_time      = omap3_gptimer_timer_init,
index 44a59c3abfb0535e8c9168284a5bf67ed0f13bb6..c2975af4cd5dee360e37fa886d3188314e347af3 100644 (file)
@@ -422,7 +422,6 @@ MACHINE_START(OMAP_LDP, "OMAP LDP board")
        .map_io         = omap3_map_io,
        .init_early     = omap3430_init_early,
        .init_irq       = omap3_init_irq,
-       .handle_irq     = omap3_intc_handle_irq,
        .init_machine   = omap_ldp_init,
        .init_late      = omap3430_init_late,
        .init_time      = omap3_sync32k_timer_init,
index aead77a4bc6dc34d75a16a80631ce8ff9d703bf4..97767a27ca9d8b3a27b6206b6867903044f9da29 100644 (file)
@@ -33,6 +33,7 @@
 #include "mmc.h"
 #include "soc.h"
 #include "gpmc-onenand.h"
+#include "common-board-devices.h"
 
 #define TUSB6010_ASYNC_CS      1
 #define TUSB6010_SYNC_CS       4
@@ -568,29 +569,14 @@ static int n8x0_menelaus_late_init(struct device *dev)
 }
 #endif
 
-static struct menelaus_platform_data n8x0_menelaus_platform_data __initdata = {
+struct menelaus_platform_data n8x0_menelaus_platform_data __initdata = {
        .late_init = n8x0_menelaus_late_init,
 };
 
-static struct i2c_board_info __initdata n8x0_i2c_board_info_1[] __initdata = {
-       {
-               I2C_BOARD_INFO("menelaus", 0x72),
-               .irq = 7 + OMAP_INTC_START,
-               .platform_data = &n8x0_menelaus_platform_data,
-       },
-};
-
-static struct aic3x_pdata n810_aic33_data __initdata = {
+struct aic3x_pdata n810_aic33_data __initdata = {
        .gpio_reset = 118,
 };
 
-static struct i2c_board_info n810_i2c_board_info_2[] __initdata = {
-       {
-               I2C_BOARD_INFO("tlv320aic3x", 0x18),
-               .platform_data = &n810_aic33_data,
-       },
-};
-
 static int __init n8x0_late_initcall(void)
 {
        if (!board_caps)
@@ -612,11 +598,5 @@ void * __init n8x0_legacy_init(void)
        board_check_revision();
        spi_register_board_info(n800_spi_board_info,
                                ARRAY_SIZE(n800_spi_board_info));
-       i2c_register_board_info(0, n8x0_i2c_board_info_1,
-                               ARRAY_SIZE(n8x0_i2c_board_info_1));
-       if (board_is_n810())
-               i2c_register_board_info(1, n810_i2c_board_info_2,
-                                       ARRAY_SIZE(n810_i2c_board_info_2));
-
        return &mmc1_data;
 }
index e2e52031f0565e09d4c815b6c0e9f026b5e13467..81de1c68b36020d6efa43561e498861052020c65 100644 (file)
@@ -588,7 +588,6 @@ MACHINE_START(OMAP3_BEAGLE, "OMAP3 Beagle Board")
        .map_io         = omap3_map_io,
        .init_early     = omap3_init_early,
        .init_irq       = omap3_init_irq,
-       .handle_irq     = omap3_intc_handle_irq,
        .init_machine   = omap3_beagle_init,
        .init_late      = omap3_init_late,
        .init_time      = omap3_secure_sync32k_timer_init,
index bab51e64c4b5c76dbd2b6a88c48c010d91ee9e8e..6049f60a88132b36400c301109910dee326d26af 100644 (file)
@@ -230,7 +230,6 @@ MACHINE_START(OMAP3_TORPEDO, "Logic OMAP3 Torpedo board")
        .map_io         = omap3_map_io,
        .init_early     = omap35xx_init_early,
        .init_irq       = omap3_init_irq,
-       .handle_irq     = omap3_intc_handle_irq,
        .init_machine   = omap3logic_init,
        .init_late      = omap35xx_init_late,
        .init_time      = omap3_sync32k_timer_init,
@@ -243,7 +242,6 @@ MACHINE_START(OMAP3530_LV_SOM, "OMAP Logic 3530 LV SOM board")
        .map_io         = omap3_map_io,
        .init_early     = omap35xx_init_early,
        .init_irq       = omap3_init_irq,
-       .handle_irq     = omap3_intc_handle_irq,
        .init_machine   = omap3logic_init,
        .init_late      = omap35xx_init_late,
        .init_time      = omap3_sync32k_timer_init,
index cf18340eb3bbd5ecc4655cf8c12eb54de1279f2b..f32201656cf30b5af416d53176c282d467ea2491 100644 (file)
@@ -624,7 +624,6 @@ MACHINE_START(OMAP3_PANDORA, "Pandora Handheld Console")
        .map_io         = omap3_map_io,
        .init_early     = omap35xx_init_early,
        .init_irq       = omap3_init_irq,
-       .handle_irq     = omap3_intc_handle_irq,
        .init_machine   = omap3pandora_init,
        .init_late      = omap35xx_init_late,
        .init_time      = omap3_sync32k_timer_init,
index a2e035e0792a3798e54c97021d90308e91a2930e..6311f4b1ee448308a3afe112a2acefd0d5cbf287 100644 (file)
@@ -426,7 +426,6 @@ MACHINE_START(SBC3530, "OMAP3 STALKER")
        .map_io                 = omap3_map_io,
        .init_early             = omap35xx_init_early,
        .init_irq               = omap3_init_irq,
-       .handle_irq             = omap3_intc_handle_irq,
        .init_machine           = omap3_stalker_init,
        .init_late              = omap35xx_init_late,
        .init_time              = omap3_secure_sync32k_timer_init,
index 70b904c010c682b54f59df863f6cbf900c5072ee..a01993e5500f3b10e4405a82458fc57497a53729 100644 (file)
@@ -388,7 +388,6 @@ MACHINE_START(TOUCHBOOK, "OMAP3 touchbook Board")
        .map_io         = omap3_map_io,
        .init_early     = omap3430_init_early,
        .init_irq       = omap3_init_irq,
-       .handle_irq     = omap3_intc_handle_irq,
        .init_machine   = omap3_touchbook_init,
        .init_late      = omap3430_init_late,
        .init_time      = omap3_secure_sync32k_timer_init,
index f6d3841119118c6cfe3c56664a4dc160ae2f2d05..2dae6ccd39bb9757956279a08399257cd4bcfc26 100644 (file)
@@ -564,7 +564,6 @@ MACHINE_START(OVERO, "Gumstix Overo")
        .map_io         = omap3_map_io,
        .init_early     = omap35xx_init_early,
        .init_irq       = omap3_init_irq,
-       .handle_irq     = omap3_intc_handle_irq,
        .init_machine   = overo_init,
        .init_late      = omap35xx_init_late,
        .init_time      = omap3_sync32k_timer_init,
index db168c9627a15e2ba5d0ea11bf02001cc73b83ff..2d1e5a6beb855d47e4366df52876c667497c6c0b 100644 (file)
@@ -134,7 +134,6 @@ MACHINE_START(NOKIA_RX51, "Nokia RX-51 board")
        .map_io         = omap3_map_io,
        .init_early     = omap3430_init_early,
        .init_irq       = omap3_init_irq,
-       .handle_irq     = omap3_intc_handle_irq,
        .init_machine   = rx51_init,
        .init_late      = omap3430_init_late,
        .init_time      = omap3_sync32k_timer_init,
index f338177e6900c16b4a526f4e33710b50368bc62f..07c88ae083fbc6542e5beb413f365d88e17cdb25 100644 (file)
@@ -1,6 +1,8 @@
 #ifndef __OMAP_COMMON_BOARD_DEVICES__
 #define __OMAP_COMMON_BOARD_DEVICES__
 
+#include <sound/tlv320aic3x.h>
+#include <linux/mfd/menelaus.h>
 #include "twl-common.h"
 
 #define NAND_BLOCK_SIZE        SZ_128K
@@ -12,4 +14,7 @@ void omap_ads7846_init(int bus_num, int gpio_pendown, int gpio_debounce,
                       struct ads7846_platform_data *board_pdata);
 void *n8x0_legacy_init(void);
 
+extern struct menelaus_platform_data n8x0_menelaus_platform_data;
+extern struct aic3x_pdata n810_aic33_data;
+
 #endif /* __OMAP_COMMON_BOARD_DEVICES__ */
index 98fe235f6670a94c3d07cb1ce6b0885017e2e004..377eea849e7bcdaf1142f6b1087ed6857a92b046 100644 (file)
@@ -32,6 +32,7 @@
 #include <linux/i2c/twl.h>
 #include <linux/i2c-omap.h>
 #include <linux/reboot.h>
+#include <linux/irqchip/irq-omap-intc.h>
 
 #include <asm/proc-fns.h>
 
@@ -210,18 +211,6 @@ extern struct device *omap2_get_iva_device(void);
 extern struct device *omap2_get_l3_device(void);
 extern struct device *omap4_get_dsp_device(void);
 
-void omap2_init_irq(void);
-void omap3_init_irq(void);
-void ti81xx_init_irq(void);
-extern int omap_irq_pending(void);
-void omap_intc_save_context(void);
-void omap_intc_restore_context(void);
-void omap3_intc_suspend(void);
-void omap3_intc_prepare_idle(void);
-void omap3_intc_resume_idle(void);
-void omap2_intc_handle_irq(struct pt_regs *regs);
-void omap3_intc_handle_irq(struct pt_regs *regs);
-void omap_intc_of_init(void);
 void omap_gic_of_init(void);
 
 #ifdef CONFIG_CACHE_L2X0
@@ -229,16 +218,6 @@ extern void __iomem *omap4_get_l2cache_base(void);
 #endif
 
 struct device_node;
-#ifdef CONFIG_OF
-int __init intc_of_init(struct device_node *node,
-                            struct device_node *parent);
-#else
-int __init intc_of_init(struct device_node *node,
-                            struct device_node *parent)
-{
-       return 0;
-}
-#endif
 
 #ifdef CONFIG_SMP
 extern void __iomem *omap4_get_scu_base(void);
diff --git a/arch/arm/mach-omap2/irq.c b/arch/arm/mach-omap2/irq.c
deleted file mode 100644 (file)
index 604a976..0000000
+++ /dev/null
@@ -1,380 +0,0 @@
-/*
- * linux/arch/arm/mach-omap2/irq.c
- *
- * Interrupt handler for OMAP2 boards.
- *
- * Copyright (C) 2005 Nokia Corporation
- * Author: Paul Mundt <paul.mundt@nokia.com>
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
- */
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/io.h>
-
-#include <asm/exception.h>
-#include <asm/mach/irq.h>
-#include <linux/irqdomain.h>
-#include <linux/of.h>
-#include <linux/of_address.h>
-#include <linux/of_irq.h>
-
-#include "soc.h"
-#include "iomap.h"
-#include "common.h"
-
-/* selected INTC register offsets */
-
-#define INTC_REVISION          0x0000
-#define INTC_SYSCONFIG         0x0010
-#define INTC_SYSSTATUS         0x0014
-#define INTC_SIR               0x0040
-#define INTC_CONTROL           0x0048
-#define INTC_PROTECTION                0x004C
-#define INTC_IDLE              0x0050
-#define INTC_THRESHOLD         0x0068
-#define INTC_MIR0              0x0084
-#define INTC_MIR_CLEAR0                0x0088
-#define INTC_MIR_SET0          0x008c
-#define INTC_PENDING_IRQ0      0x0098
-/* Number of IRQ state bits in each MIR register */
-#define IRQ_BITS_PER_REG       32
-
-#define OMAP2_IRQ_BASE         OMAP2_L4_IO_ADDRESS(OMAP24XX_IC_BASE)
-#define OMAP3_IRQ_BASE         OMAP2_L4_IO_ADDRESS(OMAP34XX_IC_BASE)
-#define INTCPS_SIR_IRQ_OFFSET  0x0040  /* omap2/3 active interrupt offset */
-#define ACTIVEIRQ_MASK         0x7f    /* omap2/3 active interrupt bits */
-#define INTCPS_NR_MIR_REGS     3
-#define INTCPS_NR_IRQS         96
-
-/*
- * OMAP2 has a number of different interrupt controllers, each interrupt
- * controller is identified as its own "bank". Register definitions are
- * fairly consistent for each bank, but not all registers are implemented
- * for each bank.. when in doubt, consult the TRM.
- */
-static struct omap_irq_bank {
-       void __iomem *base_reg;
-       unsigned int nr_irqs;
-} __attribute__ ((aligned(4))) irq_banks[] = {
-       {
-               /* MPU INTC */
-               .nr_irqs        = 96,
-       },
-};
-
-static struct irq_domain *domain;
-
-/* Structure to save interrupt controller context */
-struct omap3_intc_regs {
-       u32 sysconfig;
-       u32 protection;
-       u32 idle;
-       u32 threshold;
-       u32 ilr[INTCPS_NR_IRQS];
-       u32 mir[INTCPS_NR_MIR_REGS];
-};
-
-/* INTC bank register get/set */
-
-static void intc_bank_write_reg(u32 val, struct omap_irq_bank *bank, u16 reg)
-{
-       writel_relaxed(val, bank->base_reg + reg);
-}
-
-static u32 intc_bank_read_reg(struct omap_irq_bank *bank, u16 reg)
-{
-       return readl_relaxed(bank->base_reg + reg);
-}
-
-/* XXX: FIQ and additional INTC support (only MPU at the moment) */
-static void omap_ack_irq(struct irq_data *d)
-{
-       intc_bank_write_reg(0x1, &irq_banks[0], INTC_CONTROL);
-}
-
-static void omap_mask_ack_irq(struct irq_data *d)
-{
-       irq_gc_mask_disable_reg(d);
-       omap_ack_irq(d);
-}
-
-static void __init omap_irq_bank_init_one(struct omap_irq_bank *bank)
-{
-       unsigned long tmp;
-
-       tmp = intc_bank_read_reg(bank, INTC_REVISION) & 0xff;
-       pr_info("IRQ: Found an INTC at 0x%p (revision %ld.%ld) with %d interrupts\n",
-               bank->base_reg, tmp >> 4, tmp & 0xf, bank->nr_irqs);
-
-       tmp = intc_bank_read_reg(bank, INTC_SYSCONFIG);
-       tmp |= 1 << 1;  /* soft reset */
-       intc_bank_write_reg(tmp, bank, INTC_SYSCONFIG);
-
-       while (!(intc_bank_read_reg(bank, INTC_SYSSTATUS) & 0x1))
-               /* Wait for reset to complete */;
-
-       /* Enable autoidle */
-       intc_bank_write_reg(1 << 0, bank, INTC_SYSCONFIG);
-}
-
-int omap_irq_pending(void)
-{
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(irq_banks); i++) {
-               struct omap_irq_bank *bank = irq_banks + i;
-               int irq;
-
-               for (irq = 0; irq < bank->nr_irqs; irq += 32)
-                       if (intc_bank_read_reg(bank, INTC_PENDING_IRQ0 +
-                                              ((irq >> 5) << 5)))
-                               return 1;
-       }
-       return 0;
-}
-
-static __init void
-omap_alloc_gc(void __iomem *base, unsigned int irq_start, unsigned int num)
-{
-       struct irq_chip_generic *gc;
-       struct irq_chip_type *ct;
-
-       gc = irq_alloc_generic_chip("INTC", 1, irq_start, base,
-                                       handle_level_irq);
-       ct = gc->chip_types;
-       ct->chip.irq_ack = omap_mask_ack_irq;
-       ct->chip.irq_mask = irq_gc_mask_disable_reg;
-       ct->chip.irq_unmask = irq_gc_unmask_enable_reg;
-       ct->chip.flags |= IRQCHIP_SKIP_SET_WAKE;
-
-       ct->regs.enable = INTC_MIR_CLEAR0;
-       ct->regs.disable = INTC_MIR_SET0;
-       irq_setup_generic_chip(gc, IRQ_MSK(num), IRQ_GC_INIT_MASK_CACHE,
-                               IRQ_NOREQUEST | IRQ_NOPROBE, 0);
-}
-
-static void __init omap_init_irq(u32 base, int nr_irqs,
-                                struct device_node *node)
-{
-       void __iomem *omap_irq_base;
-       unsigned long nr_of_irqs = 0;
-       unsigned int nr_banks = 0;
-       int i, j, irq_base;
-
-       omap_irq_base = ioremap(base, SZ_4K);
-       if (WARN_ON(!omap_irq_base))
-               return;
-
-       irq_base = irq_alloc_descs(-1, 0, nr_irqs, 0);
-       if (irq_base < 0) {
-               pr_warn("Couldn't allocate IRQ numbers\n");
-               irq_base = 0;
-       }
-
-       domain = irq_domain_add_legacy(node, nr_irqs, irq_base, 0,
-                                      &irq_domain_simple_ops, NULL);
-
-       for (i = 0; i < ARRAY_SIZE(irq_banks); i++) {
-               struct omap_irq_bank *bank = irq_banks + i;
-
-               bank->nr_irqs = nr_irqs;
-
-               /* Static mapping, never released */
-               bank->base_reg = ioremap(base, SZ_4K);
-               if (!bank->base_reg) {
-                       pr_err("Could not ioremap irq bank%i\n", i);
-                       continue;
-               }
-
-               omap_irq_bank_init_one(bank);
-
-               for (j = 0; j < bank->nr_irqs; j += 32)
-                       omap_alloc_gc(bank->base_reg + j, j + irq_base, 32);
-
-               nr_of_irqs += bank->nr_irqs;
-               nr_banks++;
-       }
-
-       pr_info("Total of %ld interrupts on %d active controller%s\n",
-               nr_of_irqs, nr_banks, nr_banks > 1 ? "s" : "");
-}
-
-void __init omap2_init_irq(void)
-{
-       omap_init_irq(OMAP24XX_IC_BASE, 96, NULL);
-}
-
-void __init omap3_init_irq(void)
-{
-       omap_init_irq(OMAP34XX_IC_BASE, 96, NULL);
-}
-
-void __init ti81xx_init_irq(void)
-{
-       omap_init_irq(OMAP34XX_IC_BASE, 128, NULL);
-}
-
-static inline void omap_intc_handle_irq(void __iomem *base_addr, struct pt_regs *regs)
-{
-       u32 irqnr;
-       int handled_irq = 0;
-
-       do {
-               irqnr = readl_relaxed(base_addr + 0x98);
-               if (irqnr)
-                       goto out;
-
-               irqnr = readl_relaxed(base_addr + 0xb8);
-               if (irqnr)
-                       goto out;
-
-               irqnr = readl_relaxed(base_addr + 0xd8);
-#if IS_ENABLED(CONFIG_SOC_TI81XX) || IS_ENABLED(CONFIG_SOC_AM33XX)
-               if (irqnr)
-                       goto out;
-               irqnr = readl_relaxed(base_addr + 0xf8);
-#endif
-
-out:
-               if (!irqnr)
-                       break;
-
-               irqnr = readl_relaxed(base_addr + INTCPS_SIR_IRQ_OFFSET);
-               irqnr &= ACTIVEIRQ_MASK;
-
-               if (irqnr) {
-                       irqnr = irq_find_mapping(domain, irqnr);
-                       handle_IRQ(irqnr, regs);
-                       handled_irq = 1;
-               }
-       } while (irqnr);
-
-       /* If an irq is masked or deasserted while active, we will
-        * keep ending up here with no irq handled. So remove it from
-        * the INTC with an ack.*/
-       if (!handled_irq)
-               omap_ack_irq(NULL);
-}
-
-asmlinkage void __exception_irq_entry omap2_intc_handle_irq(struct pt_regs *regs)
-{
-       void __iomem *base_addr = OMAP2_IRQ_BASE;
-       omap_intc_handle_irq(base_addr, regs);
-}
-
-int __init intc_of_init(struct device_node *node,
-                            struct device_node *parent)
-{
-       struct resource res;
-       u32 nr_irq = 96;
-
-       if (WARN_ON(!node))
-               return -ENODEV;
-
-       if (of_address_to_resource(node, 0, &res)) {
-               WARN(1, "unable to get intc registers\n");
-               return -EINVAL;
-       }
-
-       if (of_property_read_u32(node, "ti,intc-size", &nr_irq))
-               pr_warn("unable to get intc-size, default to %d\n", nr_irq);
-
-       omap_init_irq(res.start, nr_irq, of_node_get(node));
-
-       return 0;
-}
-
-static const struct of_device_id irq_match[] __initconst = {
-       { .compatible = "ti,omap2-intc", .data = intc_of_init, },
-       { }
-};
-
-void __init omap_intc_of_init(void)
-{
-       of_irq_init(irq_match);
-}
-
-#if defined(CONFIG_ARCH_OMAP3) || defined(CONFIG_SOC_AM33XX)
-static struct omap3_intc_regs intc_context[ARRAY_SIZE(irq_banks)];
-
-void omap_intc_save_context(void)
-{
-       int ind = 0, i = 0;
-       for (ind = 0; ind < ARRAY_SIZE(irq_banks); ind++) {
-               struct omap_irq_bank *bank = irq_banks + ind;
-               intc_context[ind].sysconfig =
-                       intc_bank_read_reg(bank, INTC_SYSCONFIG);
-               intc_context[ind].protection =
-                       intc_bank_read_reg(bank, INTC_PROTECTION);
-               intc_context[ind].idle =
-                       intc_bank_read_reg(bank, INTC_IDLE);
-               intc_context[ind].threshold =
-                       intc_bank_read_reg(bank, INTC_THRESHOLD);
-               for (i = 0; i < INTCPS_NR_IRQS; i++)
-                       intc_context[ind].ilr[i] =
-                               intc_bank_read_reg(bank, (0x100 + 0x4*i));
-               for (i = 0; i < INTCPS_NR_MIR_REGS; i++)
-                       intc_context[ind].mir[i] =
-                               intc_bank_read_reg(&irq_banks[0], INTC_MIR0 +
-                               (0x20 * i));
-       }
-}
-
-void omap_intc_restore_context(void)
-{
-       int ind = 0, i = 0;
-
-       for (ind = 0; ind < ARRAY_SIZE(irq_banks); ind++) {
-               struct omap_irq_bank *bank = irq_banks + ind;
-               intc_bank_write_reg(intc_context[ind].sysconfig,
-                                       bank, INTC_SYSCONFIG);
-               intc_bank_write_reg(intc_context[ind].sysconfig,
-                                       bank, INTC_SYSCONFIG);
-               intc_bank_write_reg(intc_context[ind].protection,
-                                       bank, INTC_PROTECTION);
-               intc_bank_write_reg(intc_context[ind].idle,
-                                       bank, INTC_IDLE);
-               intc_bank_write_reg(intc_context[ind].threshold,
-                                       bank, INTC_THRESHOLD);
-               for (i = 0; i < INTCPS_NR_IRQS; i++)
-                       intc_bank_write_reg(intc_context[ind].ilr[i],
-                               bank, (0x100 + 0x4*i));
-               for (i = 0; i < INTCPS_NR_MIR_REGS; i++)
-                       intc_bank_write_reg(intc_context[ind].mir[i],
-                                &irq_banks[0], INTC_MIR0 + (0x20 * i));
-       }
-       /* MIRs are saved and restore with other PRCM registers */
-}
-
-void omap3_intc_suspend(void)
-{
-       /* A pending interrupt would prevent OMAP from entering suspend */
-       omap_ack_irq(NULL);
-}
-
-void omap3_intc_prepare_idle(void)
-{
-       /*
-        * Disable autoidle as it can stall interrupt controller,
-        * cf. errata ID i540 for 3430 (all revisions up to 3.1.x)
-        */
-       intc_bank_write_reg(0, &irq_banks[0], INTC_SYSCONFIG);
-}
-
-void omap3_intc_resume_idle(void)
-{
-       /* Re-enable autoidle */
-       intc_bank_write_reg(1, &irq_banks[0], INTC_SYSCONFIG);
-}
-
-asmlinkage void __exception_irq_entry omap3_intc_handle_irq(struct pt_regs *regs)
-{
-       void __iomem *base_addr = OMAP3_IRQ_BASE;
-       omap_intc_handle_irq(base_addr, regs);
-}
-#endif /* CONFIG_ARCH_OMAP3 */
index c8ac72604207c2202a782e30e7fa1e6d388f9d18..c95346c948297fcb14f5f6a5dd33d71b7247166a 100644 (file)
@@ -344,6 +344,8 @@ static struct pdata_init auxdata_quirks[] __initdata = {
 struct of_dev_auxdata omap_auxdata_lookup[] __initdata = {
 #ifdef CONFIG_MACH_NOKIA_N8X0
        OF_DEV_AUXDATA("ti,omap2420-mmc", 0x4809c000, "mmci-omap.0", NULL),
+       OF_DEV_AUXDATA("menelaus", 0x72, "1-0072", &n8x0_menelaus_platform_data),
+       OF_DEV_AUXDATA("tlv320aic3x", 0x18, "2-0018", &n810_aic33_data),
 #endif
 #ifdef CONFIG_ARCH_OMAP3
        OF_DEV_AUXDATA("ti,omap3-padconf", 0x48002030, "48002030.pinmux", &pcs_pdata),
index 622fa266b29e959ab7ccb4590908492eb4608ac6..1a693d3f9d51b52e116ee3ad76ad30023a2ea49c 100644 (file)
@@ -148,6 +148,8 @@ source "drivers/remoteproc/Kconfig"
 
 source "drivers/rpmsg/Kconfig"
 
+source "drivers/soc/Kconfig"
+
 source "drivers/devfreq/Kconfig"
 
 source "drivers/extcon/Kconfig"
index a60f26400705e11aae4ef6abcb8c840e94a33806..aaa0f2a871185f139844b5fd682225a6160ba3d2 100644 (file)
@@ -57,6 +57,7 @@
 #define CCN_DT_PMCCNTRSR               0x0190
 #define CCN_DT_PMOVSR                  0x0198
 #define CCN_DT_PMOVSR_CLR              0x01a0
+#define CCN_DT_PMOVSR_CLR__MASK                                0x1f
 #define CCN_DT_PMCR                    0x01a8
 #define CCN_DT_PMCR__OVFL_INTR_EN                      (1 << 6)
 #define CCN_DT_PMCR__PMU_EN                            (1 << 0)
@@ -1051,7 +1052,8 @@ static irqreturn_t arm_ccn_pmu_overflow_handler(struct arm_ccn_dt *dt)
                struct perf_event *event = dt->pmu_counters[idx].event;
                int overflowed = pmovsr & BIT(idx);
 
-               WARN_ON_ONCE(overflowed && !event);
+               WARN_ON_ONCE(overflowed && !event &&
+                               idx != CCN_IDX_PMU_CYCLE_COUNTER);
 
                if (!event || !overflowed)
                        continue;
@@ -1087,6 +1089,7 @@ static int arm_ccn_pmu_init(struct arm_ccn *ccn)
        /* Initialize DT subsystem */
        ccn->dt.base = ccn->base + CCN_REGION_SIZE;
        spin_lock_init(&ccn->dt.config_lock);
+       writel(CCN_DT_PMOVSR_CLR__MASK, ccn->dt.base + CCN_DT_PMOVSR_CLR);
        writel(CCN_DT_CTL__DT_EN, ccn->dt.base + CCN_DT_CTL);
        writel(CCN_DT_PMCR__OVFL_INTR_EN | CCN_DT_PMCR__PMU_EN,
                        ccn->dt.base + CCN_DT_PMCR);
index 8c96307d736343e3cbc6924c09580408f32c2da7..a76d03fd577be05fe86a95d51092380ab01e4eb1 100644 (file)
@@ -119,13 +119,7 @@ at91_clk_register_system(struct at91_pmc *pmc, const char *name,
        init.ops = &system_ops;
        init.parent_names = &parent_name;
        init.num_parents = 1;
-       /*
-        * CLK_IGNORE_UNUSED is used to avoid ddrck switch off.
-        * TODO : we should implement a driver supporting at91 ddr controller
-        * (see drivers/memory) which would request and enable the ddrck clock.
-        * When this is done we will be able to remove CLK_IGNORE_UNUSED flag.
-        */
-       init.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED;
+       init.flags = CLK_SET_RATE_PARENT;
 
        sys->id = id;
        sys->hw.init = &init;
index cfd6519df6615fc1a9268fcaf092859adf4323c9..82a2ebe41e27706213a1670a2f3cdee3488b0a94 100644 (file)
@@ -120,6 +120,10 @@ config CLKSRC_ARM_GLOBAL_TIMER_SCHED_CLOCK
        help
         Use ARM global timer clock source as sched_clock
 
+config ATMEL_PIT
+       select CLKSRC_OF if OF
+       def_bool SOC_AT91SAM9 || SOC_SAMA5
+
 config CLKSRC_METAG_GENERIC
        def_bool y if METAG
        help
index 7fd9fd1dff42f29aebec34bfa684bc950cb97ab8..e566f6c7ded4925c2904132f376f5380ce4bb6d1 100644 (file)
@@ -1,4 +1,5 @@
 obj-$(CONFIG_CLKSRC_OF)        += clksrc-of.o
+obj-$(CONFIG_ATMEL_PIT)                += timer-atmel-pit.o
 obj-$(CONFIG_ATMEL_TCB_CLKSRC) += tcb_clksrc.o
 obj-$(CONFIG_X86_PM_TIMER)     += acpi_pm.o
 obj-$(CONFIG_SCx200HR_TIMER)   += scx200_hrt.o
diff --git a/drivers/clocksource/timer-atmel-pit.c b/drivers/clocksource/timer-atmel-pit.c
new file mode 100644 (file)
index 0000000..d528909
--- /dev/null
@@ -0,0 +1,296 @@
+/*
+ * at91sam926x_time.c - Periodic Interval Timer (PIT) for at91sam926x
+ *
+ * Copyright (C) 2005-2006 M. Amine SAYA, ATMEL Rousset, France
+ * Revision     2005 M. Nicolas Diremdjian, ATMEL Rousset, France
+ * Converted to ClockSource/ClockEvents by David Brownell.
+ *
+ * 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.
+ */
+
+#define pr_fmt(fmt)    "AT91: PIT: " fmt
+
+#include <linux/clk.h>
+#include <linux/clockchips.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/slab.h>
+
+#define AT91_PIT_MR            0x00                    /* Mode Register */
+#define AT91_PIT_PITIEN                        BIT(25)                 /* Timer Interrupt Enable */
+#define AT91_PIT_PITEN                 BIT(24)                 /* Timer Enabled */
+#define AT91_PIT_PIV                   GENMASK(19, 0)          /* Periodic Interval Value */
+
+#define AT91_PIT_SR            0x04                    /* Status Register */
+#define AT91_PIT_PITS                  BIT(0)                  /* Timer Status */
+
+#define AT91_PIT_PIVR          0x08                    /* Periodic Interval Value Register */
+#define AT91_PIT_PIIR          0x0c                    /* Periodic Interval Image Register */
+#define AT91_PIT_PICNT                 GENMASK(31, 20)         /* Interval Counter */
+#define AT91_PIT_CPIV                  GENMASK(19, 0)          /* Inverval Value */
+
+#define PIT_CPIV(x)    ((x) & AT91_PIT_CPIV)
+#define PIT_PICNT(x)   (((x) & AT91_PIT_PICNT) >> 20)
+
+struct pit_data {
+       struct clock_event_device       clkevt;
+       struct clocksource              clksrc;
+
+       void __iomem    *base;
+       u32             cycle;
+       u32             cnt;
+       unsigned int    irq;
+       struct clk      *mck;
+};
+
+static inline struct pit_data *clksrc_to_pit_data(struct clocksource *clksrc)
+{
+       return container_of(clksrc, struct pit_data, clksrc);
+}
+
+static inline struct pit_data *clkevt_to_pit_data(struct clock_event_device *clkevt)
+{
+       return container_of(clkevt, struct pit_data, clkevt);
+}
+
+static inline unsigned int pit_read(void __iomem *base, unsigned int reg_offset)
+{
+       return __raw_readl(base + reg_offset);
+}
+
+static inline void pit_write(void __iomem *base, unsigned int reg_offset, unsigned long value)
+{
+       __raw_writel(value, base + reg_offset);
+}
+
+/*
+ * Clocksource:  just a monotonic counter of MCK/16 cycles.
+ * We don't care whether or not PIT irqs are enabled.
+ */
+static cycle_t read_pit_clk(struct clocksource *cs)
+{
+       struct pit_data *data = clksrc_to_pit_data(cs);
+       unsigned long flags;
+       u32 elapsed;
+       u32 t;
+
+       raw_local_irq_save(flags);
+       elapsed = data->cnt;
+       t = pit_read(data->base, AT91_PIT_PIIR);
+       raw_local_irq_restore(flags);
+
+       elapsed += PIT_PICNT(t) * data->cycle;
+       elapsed += PIT_CPIV(t);
+       return elapsed;
+}
+
+/*
+ * Clockevent device:  interrupts every 1/HZ (== pit_cycles * MCK/16)
+ */
+static void
+pit_clkevt_mode(enum clock_event_mode mode, struct clock_event_device *dev)
+{
+       struct pit_data *data = clkevt_to_pit_data(dev);
+
+       switch (mode) {
+       case CLOCK_EVT_MODE_PERIODIC:
+               /* update clocksource counter */
+               data->cnt += data->cycle * PIT_PICNT(pit_read(data->base, AT91_PIT_PIVR));
+               pit_write(data->base, AT91_PIT_MR,
+                         (data->cycle - 1) | AT91_PIT_PITEN | AT91_PIT_PITIEN);
+               break;
+       case CLOCK_EVT_MODE_ONESHOT:
+               BUG();
+               /* FALLTHROUGH */
+       case CLOCK_EVT_MODE_SHUTDOWN:
+       case CLOCK_EVT_MODE_UNUSED:
+               /* disable irq, leaving the clocksource active */
+               pit_write(data->base, AT91_PIT_MR,
+                         (data->cycle - 1) | AT91_PIT_PITEN);
+               break;
+       case CLOCK_EVT_MODE_RESUME:
+               break;
+       }
+}
+
+static void at91sam926x_pit_suspend(struct clock_event_device *cedev)
+{
+       struct pit_data *data = clkevt_to_pit_data(cedev);
+
+       /* Disable timer */
+       pit_write(data->base, AT91_PIT_MR, 0);
+}
+
+static void at91sam926x_pit_reset(struct pit_data *data)
+{
+       /* Disable timer and irqs */
+       pit_write(data->base, AT91_PIT_MR, 0);
+
+       /* Clear any pending interrupts, wait for PIT to stop counting */
+       while (PIT_CPIV(pit_read(data->base, AT91_PIT_PIVR)) != 0)
+               cpu_relax();
+
+       /* Start PIT but don't enable IRQ */
+       pit_write(data->base, AT91_PIT_MR,
+                 (data->cycle - 1) | AT91_PIT_PITEN);
+}
+
+static void at91sam926x_pit_resume(struct clock_event_device *cedev)
+{
+       struct pit_data *data = clkevt_to_pit_data(cedev);
+
+       at91sam926x_pit_reset(data);
+}
+
+/*
+ * IRQ handler for the timer.
+ */
+static irqreturn_t at91sam926x_pit_interrupt(int irq, void *dev_id)
+{
+       struct pit_data *data = dev_id;
+
+       /*
+        * irqs should be disabled here, but as the irq is shared they are only
+        * guaranteed to be off if the timer irq is registered first.
+        */
+       WARN_ON_ONCE(!irqs_disabled());
+
+       /* The PIT interrupt may be disabled, and is shared */
+       if ((data->clkevt.mode == CLOCK_EVT_MODE_PERIODIC) &&
+           (pit_read(data->base, AT91_PIT_SR) & AT91_PIT_PITS)) {
+               unsigned nr_ticks;
+
+               /* Get number of ticks performed before irq, and ack it */
+               nr_ticks = PIT_PICNT(pit_read(data->base, AT91_PIT_PIVR));
+               do {
+                       data->cnt += data->cycle;
+                       data->clkevt.event_handler(&data->clkevt);
+                       nr_ticks--;
+               } while (nr_ticks);
+
+               return IRQ_HANDLED;
+       }
+
+       return IRQ_NONE;
+}
+
+/*
+ * Set up both clocksource and clockevent support.
+ */
+static void __init at91sam926x_pit_common_init(struct pit_data *data)
+{
+       unsigned long   pit_rate;
+       unsigned        bits;
+       int             ret;
+
+       /*
+        * Use our actual MCK to figure out how many MCK/16 ticks per
+        * 1/HZ period (instead of a compile-time constant LATCH).
+        */
+       pit_rate = clk_get_rate(data->mck) / 16;
+       data->cycle = DIV_ROUND_CLOSEST(pit_rate, HZ);
+       WARN_ON(((data->cycle - 1) & ~AT91_PIT_PIV) != 0);
+
+       /* Initialize and enable the timer */
+       at91sam926x_pit_reset(data);
+
+       /*
+        * Register clocksource.  The high order bits of PIV are unused,
+        * so this isn't a 32-bit counter unless we get clockevent irqs.
+        */
+       bits = 12 /* PICNT */ + ilog2(data->cycle) /* PIV */;
+       data->clksrc.mask = CLOCKSOURCE_MASK(bits);
+       data->clksrc.name = "pit";
+       data->clksrc.rating = 175;
+       data->clksrc.read = read_pit_clk,
+       data->clksrc.flags = CLOCK_SOURCE_IS_CONTINUOUS,
+       clocksource_register_hz(&data->clksrc, pit_rate);
+
+       /* Set up irq handler */
+       ret = request_irq(data->irq, at91sam926x_pit_interrupt,
+                         IRQF_SHARED | IRQF_TIMER | IRQF_IRQPOLL,
+                         "at91_tick", data);
+       if (ret)
+               panic(pr_fmt("Unable to setup IRQ\n"));
+
+       /* Set up and register clockevents */
+       data->clkevt.name = "pit";
+       data->clkevt.features = CLOCK_EVT_FEAT_PERIODIC;
+       data->clkevt.shift = 32;
+       data->clkevt.mult = div_sc(pit_rate, NSEC_PER_SEC, data->clkevt.shift);
+       data->clkevt.rating = 100;
+       data->clkevt.cpumask = cpumask_of(0);
+
+       data->clkevt.set_mode = pit_clkevt_mode;
+       data->clkevt.resume = at91sam926x_pit_resume;
+       data->clkevt.suspend = at91sam926x_pit_suspend;
+       clockevents_register_device(&data->clkevt);
+}
+
+static void __init at91sam926x_pit_dt_init(struct device_node *node)
+{
+       struct pit_data *data;
+
+       data = kzalloc(sizeof(*data), GFP_KERNEL);
+       if (!data)
+               panic(pr_fmt("Unable to allocate memory\n"));
+
+       data->base = of_iomap(node, 0);
+       if (!data->base)
+               panic(pr_fmt("Could not map PIT address\n"));
+
+       data->mck = of_clk_get(node, 0);
+       if (IS_ERR(data->mck))
+               /* Fallback on clkdev for !CCF-based boards */
+               data->mck = clk_get(NULL, "mck");
+
+       if (IS_ERR(data->mck))
+               panic(pr_fmt("Unable to get mck clk\n"));
+
+       /* Get the interrupts property */
+       data->irq = irq_of_parse_and_map(node, 0);
+       if (!data->irq)
+               panic(pr_fmt("Unable to get IRQ from DT\n"));
+
+       at91sam926x_pit_common_init(data);
+}
+CLOCKSOURCE_OF_DECLARE(at91sam926x_pit, "atmel,at91sam9260-pit",
+                      at91sam926x_pit_dt_init);
+
+static void __iomem *pit_base_addr;
+
+void __init at91sam926x_pit_init(int irq)
+{
+       struct pit_data *data;
+
+       data = kzalloc(sizeof(*data), GFP_KERNEL);
+       if (!data)
+               panic(pr_fmt("Unable to allocate memory\n"));
+
+       data->base = pit_base_addr;
+
+       data->mck = clk_get(NULL, "mck");
+       if (IS_ERR(data->mck))
+               panic(pr_fmt("Unable to get mck clk\n"));
+
+       data->irq = irq;
+
+       at91sam926x_pit_common_init(data);
+}
+
+void __init at91sam926x_ioremap_pit(u32 addr)
+{
+       if (of_have_populated_dt())
+               return;
+
+       pit_base_addr = ioremap(addr, 16);
+
+       if (!pit_base_addr)
+               panic(pr_fmt("Impossible to ioremap PIT\n"));
+}
index fd89ca982748ed9cac8ff11e0b0c4bce59110c2c..7072c2892d633eb72dbea1bcea973a09eae68e30 100644 (file)
@@ -376,4 +376,13 @@ config EDAC_OCTEON_PCI
          Support for error detection and correction on the
          Cavium Octeon family of SOCs.
 
+config EDAC_ALTERA_MC
+       tristate "Altera SDRAM Memory Controller EDAC"
+       depends on EDAC_MM_EDAC && ARCH_SOCFPGA
+       help
+         Support for error detection and correction on the
+         Altera SDRAM memory controller. Note that the
+         preloader must initialize the SDRAM before loading
+         the kernel.
+
 endif # EDAC
index c479a24d8f77b0d5f05dda160b91b30d1db33d6d..359aa499b200d0f8bdd50c0532345dbaf7324956 100644 (file)
@@ -65,3 +65,5 @@ obj-$(CONFIG_EDAC_OCTEON_PC)          += octeon_edac-pc.o
 obj-$(CONFIG_EDAC_OCTEON_L2C)          += octeon_edac-l2c.o
 obj-$(CONFIG_EDAC_OCTEON_LMC)          += octeon_edac-lmc.o
 obj-$(CONFIG_EDAC_OCTEON_PCI)          += octeon_edac-pci.o
+
+obj-$(CONFIG_EDAC_ALTERA_MC)           += altera_edac.o
diff --git a/drivers/edac/altera_edac.c b/drivers/edac/altera_edac.c
new file mode 100644 (file)
index 0000000..3c4929f
--- /dev/null
@@ -0,0 +1,410 @@
+/*
+ *  Copyright Altera Corporation (C) 2014. All rights reserved.
+ *  Copyright 2011-2012 Calxeda, Inc.
+ *
+ * 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/>.
+ *
+ * Adapted from the highbank_mc_edac driver.
+ */
+
+#include <linux/ctype.h>
+#include <linux/edac.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/mfd/syscon.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/types.h>
+#include <linux/uaccess.h>
+
+#include "edac_core.h"
+#include "edac_module.h"
+
+#define EDAC_MOD_STR           "altera_edac"
+#define EDAC_VERSION           "1"
+
+/* SDRAM Controller CtrlCfg Register */
+#define CTLCFG_OFST             0x00
+
+/* SDRAM Controller CtrlCfg Register Bit Masks */
+#define CTLCFG_ECC_EN           0x400
+#define CTLCFG_ECC_CORR_EN      0x800
+#define CTLCFG_GEN_SB_ERR       0x2000
+#define CTLCFG_GEN_DB_ERR       0x4000
+
+#define CTLCFG_ECC_AUTO_EN     (CTLCFG_ECC_EN | \
+                                CTLCFG_ECC_CORR_EN)
+
+/* SDRAM Controller Address Width Register */
+#define DRAMADDRW_OFST          0x2C
+
+/* SDRAM Controller Address Widths Field Register */
+#define DRAMADDRW_COLBIT_MASK   0x001F
+#define DRAMADDRW_COLBIT_SHIFT  0
+#define DRAMADDRW_ROWBIT_MASK   0x03E0
+#define DRAMADDRW_ROWBIT_SHIFT  5
+#define DRAMADDRW_BANKBIT_MASK 0x1C00
+#define DRAMADDRW_BANKBIT_SHIFT 10
+#define DRAMADDRW_CSBIT_MASK   0xE000
+#define DRAMADDRW_CSBIT_SHIFT   13
+
+/* SDRAM Controller Interface Data Width Register */
+#define DRAMIFWIDTH_OFST        0x30
+
+/* SDRAM Controller Interface Data Width Defines */
+#define DRAMIFWIDTH_16B_ECC     24
+#define DRAMIFWIDTH_32B_ECC     40
+
+/* SDRAM Controller DRAM Status Register */
+#define DRAMSTS_OFST            0x38
+
+/* SDRAM Controller DRAM Status Register Bit Masks */
+#define DRAMSTS_SBEERR          0x04
+#define DRAMSTS_DBEERR          0x08
+#define DRAMSTS_CORR_DROP       0x10
+
+/* SDRAM Controller DRAM IRQ Register */
+#define DRAMINTR_OFST           0x3C
+
+/* SDRAM Controller DRAM IRQ Register Bit Masks */
+#define DRAMINTR_INTREN         0x01
+#define DRAMINTR_SBEMASK        0x02
+#define DRAMINTR_DBEMASK        0x04
+#define DRAMINTR_CORRDROPMASK   0x08
+#define DRAMINTR_INTRCLR        0x10
+
+/* SDRAM Controller Single Bit Error Count Register */
+#define SBECOUNT_OFST           0x40
+
+/* SDRAM Controller Single Bit Error Count Register Bit Masks */
+#define SBECOUNT_MASK           0x0F
+
+/* SDRAM Controller Double Bit Error Count Register */
+#define DBECOUNT_OFST           0x44
+
+/* SDRAM Controller Double Bit Error Count Register Bit Masks */
+#define DBECOUNT_MASK           0x0F
+
+/* SDRAM Controller ECC Error Address Register */
+#define ERRADDR_OFST            0x48
+
+/* SDRAM Controller ECC Error Address Register Bit Masks */
+#define ERRADDR_MASK            0xFFFFFFFF
+
+/* Altera SDRAM Memory Controller data */
+struct altr_sdram_mc_data {
+       struct regmap *mc_vbase;
+};
+
+static irqreturn_t altr_sdram_mc_err_handler(int irq, void *dev_id)
+{
+       struct mem_ctl_info *mci = dev_id;
+       struct altr_sdram_mc_data *drvdata = mci->pvt_info;
+       u32 status, err_count, err_addr;
+
+       /* Error Address is shared by both SBE & DBE */
+       regmap_read(drvdata->mc_vbase, ERRADDR_OFST, &err_addr);
+
+       regmap_read(drvdata->mc_vbase, DRAMSTS_OFST, &status);
+
+       if (status & DRAMSTS_DBEERR) {
+               regmap_read(drvdata->mc_vbase, DBECOUNT_OFST, &err_count);
+               panic("\nEDAC: [%d Uncorrectable errors @ 0x%08X]\n",
+                     err_count, err_addr);
+       }
+       if (status & DRAMSTS_SBEERR) {
+               regmap_read(drvdata->mc_vbase, SBECOUNT_OFST, &err_count);
+               edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, err_count,
+                                    err_addr >> PAGE_SHIFT,
+                                    err_addr & ~PAGE_MASK, 0,
+                                    0, 0, -1, mci->ctl_name, "");
+       }
+
+       regmap_write(drvdata->mc_vbase, DRAMINTR_OFST,
+                    (DRAMINTR_INTRCLR | DRAMINTR_INTREN));
+
+       return IRQ_HANDLED;
+}
+
+#ifdef CONFIG_EDAC_DEBUG
+static ssize_t altr_sdr_mc_err_inject_write(struct file *file,
+                                           const char __user *data,
+                                           size_t count, loff_t *ppos)
+{
+       struct mem_ctl_info *mci = file->private_data;
+       struct altr_sdram_mc_data *drvdata = mci->pvt_info;
+       u32 *ptemp;
+       dma_addr_t dma_handle;
+       u32 reg, read_reg;
+
+       ptemp = dma_alloc_coherent(mci->pdev, 16, &dma_handle, GFP_KERNEL);
+       if (!ptemp) {
+               dma_free_coherent(mci->pdev, 16, ptemp, dma_handle);
+               edac_printk(KERN_ERR, EDAC_MC,
+                           "Inject: Buffer Allocation error\n");
+               return -ENOMEM;
+       }
+
+       regmap_read(drvdata->mc_vbase, CTLCFG_OFST, &read_reg);
+       read_reg &= ~(CTLCFG_GEN_SB_ERR | CTLCFG_GEN_DB_ERR);
+
+       /* Error are injected by writing a word while the SBE or DBE
+        * bit in the CTLCFG register is set. Reading the word will
+        * trigger the SBE or DBE error and the corresponding IRQ.
+        */
+       if (count == 3) {
+               edac_printk(KERN_ALERT, EDAC_MC,
+                           "Inject Double bit error\n");
+               regmap_write(drvdata->mc_vbase, CTLCFG_OFST,
+                            (read_reg | CTLCFG_GEN_DB_ERR));
+       } else {
+               edac_printk(KERN_ALERT, EDAC_MC,
+                           "Inject Single bit error\n");
+               regmap_write(drvdata->mc_vbase, CTLCFG_OFST,
+                            (read_reg | CTLCFG_GEN_SB_ERR));
+       }
+
+       ptemp[0] = 0x5A5A5A5A;
+       ptemp[1] = 0xA5A5A5A5;
+
+       /* Clear the error injection bits */
+       regmap_write(drvdata->mc_vbase, CTLCFG_OFST, read_reg);
+       /* Ensure it has been written out */
+       wmb();
+
+       /*
+        * To trigger the error, we need to read the data back
+        * (the data was written with errors above).
+        * The ACCESS_ONCE macros and printk are used to prevent the
+        * the compiler optimizing these reads out.
+        */
+       reg = ACCESS_ONCE(ptemp[0]);
+       read_reg = ACCESS_ONCE(ptemp[1]);
+       /* Force Read */
+       rmb();
+
+       edac_printk(KERN_ALERT, EDAC_MC, "Read Data [0x%X, 0x%X]\n",
+                   reg, read_reg);
+
+       dma_free_coherent(mci->pdev, 16, ptemp, dma_handle);
+
+       return count;
+}
+
+static const struct file_operations altr_sdr_mc_debug_inject_fops = {
+       .open = simple_open,
+       .write = altr_sdr_mc_err_inject_write,
+       .llseek = generic_file_llseek,
+};
+
+static void altr_sdr_mc_create_debugfs_nodes(struct mem_ctl_info *mci)
+{
+       if (mci->debugfs)
+               debugfs_create_file("inject_ctrl", S_IWUSR, mci->debugfs, mci,
+                                   &altr_sdr_mc_debug_inject_fops);
+}
+#else
+static void altr_sdr_mc_create_debugfs_nodes(struct mem_ctl_info *mci)
+{}
+#endif
+
+/* Get total memory size in bytes */
+static u32 altr_sdram_get_total_mem_size(struct regmap *mc_vbase)
+{
+       u32 size, read_reg, row, bank, col, cs, width;
+
+       if (regmap_read(mc_vbase, DRAMADDRW_OFST, &read_reg) < 0)
+               return 0;
+
+       if (regmap_read(mc_vbase, DRAMIFWIDTH_OFST, &width) < 0)
+               return 0;
+
+       col = (read_reg & DRAMADDRW_COLBIT_MASK) >>
+               DRAMADDRW_COLBIT_SHIFT;
+       row = (read_reg & DRAMADDRW_ROWBIT_MASK) >>
+               DRAMADDRW_ROWBIT_SHIFT;
+       bank = (read_reg & DRAMADDRW_BANKBIT_MASK) >>
+               DRAMADDRW_BANKBIT_SHIFT;
+       cs = (read_reg & DRAMADDRW_CSBIT_MASK) >>
+               DRAMADDRW_CSBIT_SHIFT;
+
+       /* Correct for ECC as its not addressible */
+       if (width == DRAMIFWIDTH_32B_ECC)
+               width = 32;
+       if (width == DRAMIFWIDTH_16B_ECC)
+               width = 16;
+
+       /* calculate the SDRAM size base on this info */
+       size = 1 << (row + bank + col);
+       size = size * cs * (width / 8);
+       return size;
+}
+
+static int altr_sdram_probe(struct platform_device *pdev)
+{
+       struct edac_mc_layer layers[2];
+       struct mem_ctl_info *mci;
+       struct altr_sdram_mc_data *drvdata;
+       struct regmap *mc_vbase;
+       struct dimm_info *dimm;
+       u32 read_reg, mem_size;
+       int irq;
+       int res = 0;
+
+       /* Validate the SDRAM controller has ECC enabled */
+       /* Grab the register range from the sdr controller in device tree */
+       mc_vbase = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
+                                                  "altr,sdr-syscon");
+       if (IS_ERR(mc_vbase)) {
+               edac_printk(KERN_ERR, EDAC_MC,
+                           "regmap for altr,sdr-syscon lookup failed.\n");
+               return -ENODEV;
+       }
+
+       if (regmap_read(mc_vbase, CTLCFG_OFST, &read_reg) ||
+           ((read_reg & CTLCFG_ECC_AUTO_EN) != CTLCFG_ECC_AUTO_EN)) {
+               edac_printk(KERN_ERR, EDAC_MC,
+                           "No ECC/ECC disabled [0x%08X]\n", read_reg);
+               return -ENODEV;
+       }
+
+       /* Grab memory size from device tree. */
+       mem_size = altr_sdram_get_total_mem_size(mc_vbase);
+       if (!mem_size) {
+               edac_printk(KERN_ERR, EDAC_MC,
+                           "Unable to calculate memory size\n");
+               return -ENODEV;
+       }
+
+       /* Ensure the SDRAM Interrupt is disabled and cleared */
+       if (regmap_write(mc_vbase, DRAMINTR_OFST, DRAMINTR_INTRCLR)) {
+               edac_printk(KERN_ERR, EDAC_MC,
+                           "Error clearing SDRAM ECC IRQ\n");
+               return -ENODEV;
+       }
+
+       irq = platform_get_irq(pdev, 0);
+       if (irq < 0) {
+               edac_printk(KERN_ERR, EDAC_MC,
+                           "No irq %d in DT\n", irq);
+               return -ENODEV;
+       }
+
+       layers[0].type = EDAC_MC_LAYER_CHIP_SELECT;
+       layers[0].size = 1;
+       layers[0].is_virt_csrow = true;
+       layers[1].type = EDAC_MC_LAYER_CHANNEL;
+       layers[1].size = 1;
+       layers[1].is_virt_csrow = false;
+       mci = edac_mc_alloc(0, ARRAY_SIZE(layers), layers,
+                           sizeof(struct altr_sdram_mc_data));
+       if (!mci)
+               return -ENOMEM;
+
+       mci->pdev = &pdev->dev;
+       drvdata = mci->pvt_info;
+       drvdata->mc_vbase = mc_vbase;
+       platform_set_drvdata(pdev, mci);
+
+       if (!devres_open_group(&pdev->dev, NULL, GFP_KERNEL)) {
+               res = -ENOMEM;
+               goto free;
+       }
+
+       mci->mtype_cap = MEM_FLAG_DDR3;
+       mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED;
+       mci->edac_cap = EDAC_FLAG_SECDED;
+       mci->mod_name = EDAC_MOD_STR;
+       mci->mod_ver = EDAC_VERSION;
+       mci->ctl_name = dev_name(&pdev->dev);
+       mci->scrub_mode = SCRUB_SW_SRC;
+       mci->dev_name = dev_name(&pdev->dev);
+
+       dimm = *mci->dimms;
+       dimm->nr_pages = ((mem_size - 1) >> PAGE_SHIFT) + 1;
+       dimm->grain = 8;
+       dimm->dtype = DEV_X8;
+       dimm->mtype = MEM_DDR3;
+       dimm->edac_mode = EDAC_SECDED;
+
+       res = edac_mc_add_mc(mci);
+       if (res < 0)
+               goto err;
+
+       res = devm_request_irq(&pdev->dev, irq, altr_sdram_mc_err_handler,
+                              0, dev_name(&pdev->dev), mci);
+       if (res < 0) {
+               edac_mc_printk(mci, KERN_ERR,
+                              "Unable to request irq %d\n", irq);
+               res = -ENODEV;
+               goto err2;
+       }
+
+       if (regmap_write(drvdata->mc_vbase, DRAMINTR_OFST,
+                        (DRAMINTR_INTRCLR | DRAMINTR_INTREN))) {
+               edac_mc_printk(mci, KERN_ERR,
+                              "Error enabling SDRAM ECC IRQ\n");
+               res = -ENODEV;
+               goto err2;
+       }
+
+       altr_sdr_mc_create_debugfs_nodes(mci);
+
+       devres_close_group(&pdev->dev, NULL);
+
+       return 0;
+
+err2:
+       edac_mc_del_mc(&pdev->dev);
+err:
+       devres_release_group(&pdev->dev, NULL);
+free:
+       edac_mc_free(mci);
+       edac_printk(KERN_ERR, EDAC_MC,
+                   "EDAC Probe Failed; Error %d\n", res);
+
+       return res;
+}
+
+static int altr_sdram_remove(struct platform_device *pdev)
+{
+       struct mem_ctl_info *mci = platform_get_drvdata(pdev);
+
+       edac_mc_del_mc(&pdev->dev);
+       edac_mc_free(mci);
+       platform_set_drvdata(pdev, NULL);
+
+       return 0;
+}
+
+static const struct of_device_id altr_sdram_ctrl_of_match[] = {
+       { .compatible = "altr,sdram-edac", },
+       {},
+};
+MODULE_DEVICE_TABLE(of, altr_sdram_ctrl_of_match);
+
+static struct platform_driver altr_sdram_edac_driver = {
+       .probe = altr_sdram_probe,
+       .remove = altr_sdram_remove,
+       .driver = {
+               .name = "altr_sdram_edac",
+               .of_match_table = altr_sdram_ctrl_of_match,
+       },
+};
+
+module_platform_driver(altr_sdram_edac_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Thor Thayer");
+MODULE_DESCRIPTION("EDAC Driver for Altera SDRAM Controller");
index a31a9e40eed9389bcfb2e26a336a3093fb042496..78d4ff551590d44612d17e9d05f2cc5f36e48c1e 100644 (file)
@@ -75,6 +75,11 @@ config OR1K_PIC
        bool
        select IRQ_DOMAIN
 
+config OMAP_IRQCHIP
+       bool
+       select GENERIC_IRQ_CHIP
+       select IRQ_DOMAIN
+
 config ORION_IRQCHIP
        bool
        select IRQ_DOMAIN
index 73052ba9ca627c27fae12486a3b4f913692a752c..d0a2613c73bc3fbf17ca2b4063f6dd344ca6bb4f 100644 (file)
@@ -13,6 +13,7 @@ obj-$(CONFIG_ARCH_MOXART)             += irq-moxart.o
 obj-$(CONFIG_CLPS711X_IRQCHIP)         += irq-clps711x.o
 obj-$(CONFIG_OR1K_PIC)                 += irq-or1k-pic.o
 obj-$(CONFIG_ORION_IRQCHIP)            += irq-orion.o
+obj-$(CONFIG_OMAP_IRQCHIP)             += irq-omap-intc.o
 obj-$(CONFIG_ARCH_SUNXI)               += irq-sun4i.o
 obj-$(CONFIG_ARCH_SUNXI)               += irq-sunxi-nmi.o
 obj-$(CONFIG_ARCH_SPEAR3XX)            += spear-shirq.o
diff --git a/drivers/irqchip/irq-omap-intc.c b/drivers/irqchip/irq-omap-intc.c
new file mode 100644 (file)
index 0000000..f3814e7
--- /dev/null
@@ -0,0 +1,403 @@
+/*
+ * linux/arch/arm/mach-omap2/irq.c
+ *
+ * Interrupt handler for OMAP2 boards.
+ *
+ * Copyright (C) 2005 Nokia Corporation
+ * Author: Paul Mundt <paul.mundt@nokia.com>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+
+#include <asm/exception.h>
+#include <linux/irqdomain.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+
+#include "irqchip.h"
+
+/* Define these here for now until we drop all board-files */
+#define OMAP24XX_IC_BASE       0x480fe000
+#define OMAP34XX_IC_BASE       0x48200000
+
+/* selected INTC register offsets */
+
+#define INTC_REVISION          0x0000
+#define INTC_SYSCONFIG         0x0010
+#define INTC_SYSSTATUS         0x0014
+#define INTC_SIR               0x0040
+#define INTC_CONTROL           0x0048
+#define INTC_PROTECTION                0x004C
+#define INTC_IDLE              0x0050
+#define INTC_THRESHOLD         0x0068
+#define INTC_MIR0              0x0084
+#define INTC_MIR_CLEAR0                0x0088
+#define INTC_MIR_SET0          0x008c
+#define INTC_PENDING_IRQ0      0x0098
+#define INTC_PENDING_IRQ1      0x00b8
+#define INTC_PENDING_IRQ2      0x00d8
+#define INTC_PENDING_IRQ3      0x00f8
+#define INTC_ILR0              0x0100
+
+#define ACTIVEIRQ_MASK         0x7f    /* omap2/3 active interrupt bits */
+#define INTCPS_NR_ILR_REGS     128
+#define INTCPS_NR_MIR_REGS     4
+
+#define INTC_IDLE_FUNCIDLE     (1 << 0)
+#define INTC_IDLE_TURBO                (1 << 1)
+
+#define INTC_PROTECTION_ENABLE (1 << 0)
+
+struct omap_intc_regs {
+       u32 sysconfig;
+       u32 protection;
+       u32 idle;
+       u32 threshold;
+       u32 ilr[INTCPS_NR_ILR_REGS];
+       u32 mir[INTCPS_NR_MIR_REGS];
+};
+static struct omap_intc_regs intc_context;
+
+static struct irq_domain *domain;
+static void __iomem *omap_irq_base;
+static int omap_nr_pending = 3;
+static int omap_nr_irqs = 96;
+
+static void intc_writel(u32 reg, u32 val)
+{
+       writel_relaxed(val, omap_irq_base + reg);
+}
+
+static u32 intc_readl(u32 reg)
+{
+       return readl_relaxed(omap_irq_base + reg);
+}
+
+void omap_intc_save_context(void)
+{
+       int i;
+
+       intc_context.sysconfig =
+               intc_readl(INTC_SYSCONFIG);
+       intc_context.protection =
+               intc_readl(INTC_PROTECTION);
+       intc_context.idle =
+               intc_readl(INTC_IDLE);
+       intc_context.threshold =
+               intc_readl(INTC_THRESHOLD);
+
+       for (i = 0; i < omap_nr_irqs; i++)
+               intc_context.ilr[i] =
+                       intc_readl((INTC_ILR0 + 0x4 * i));
+       for (i = 0; i < INTCPS_NR_MIR_REGS; i++)
+               intc_context.mir[i] =
+                       intc_readl(INTC_MIR0 + (0x20 * i));
+}
+
+void omap_intc_restore_context(void)
+{
+       int i;
+
+       intc_writel(INTC_SYSCONFIG, intc_context.sysconfig);
+       intc_writel(INTC_PROTECTION, intc_context.protection);
+       intc_writel(INTC_IDLE, intc_context.idle);
+       intc_writel(INTC_THRESHOLD, intc_context.threshold);
+
+       for (i = 0; i < omap_nr_irqs; i++)
+               intc_writel(INTC_ILR0 + 0x4 * i,
+                               intc_context.ilr[i]);
+
+       for (i = 0; i < INTCPS_NR_MIR_REGS; i++)
+               intc_writel(INTC_MIR0 + 0x20 * i,
+                       intc_context.mir[i]);
+       /* MIRs are saved and restore with other PRCM registers */
+}
+
+void omap3_intc_prepare_idle(void)
+{
+       /*
+        * Disable autoidle as it can stall interrupt controller,
+        * cf. errata ID i540 for 3430 (all revisions up to 3.1.x)
+        */
+       intc_writel(INTC_SYSCONFIG, 0);
+       intc_writel(INTC_IDLE, INTC_IDLE_TURBO);
+}
+
+void omap3_intc_resume_idle(void)
+{
+       /* Re-enable autoidle */
+       intc_writel(INTC_SYSCONFIG, 1);
+       intc_writel(INTC_IDLE, 0);
+}
+
+/* XXX: FIQ and additional INTC support (only MPU at the moment) */
+static void omap_ack_irq(struct irq_data *d)
+{
+       intc_writel(INTC_CONTROL, 0x1);
+}
+
+static void omap_mask_ack_irq(struct irq_data *d)
+{
+       irq_gc_mask_disable_reg(d);
+       omap_ack_irq(d);
+}
+
+static void __init omap_irq_soft_reset(void)
+{
+       unsigned long tmp;
+
+       tmp = intc_readl(INTC_REVISION) & 0xff;
+
+       pr_info("IRQ: Found an INTC at 0x%p (revision %ld.%ld) with %d interrupts\n",
+               omap_irq_base, tmp >> 4, tmp & 0xf, omap_nr_irqs);
+
+       tmp = intc_readl(INTC_SYSCONFIG);
+       tmp |= 1 << 1;  /* soft reset */
+       intc_writel(INTC_SYSCONFIG, tmp);
+
+       while (!(intc_readl(INTC_SYSSTATUS) & 0x1))
+               /* Wait for reset to complete */;
+
+       /* Enable autoidle */
+       intc_writel(INTC_SYSCONFIG, 1 << 0);
+}
+
+int omap_irq_pending(void)
+{
+       int i;
+
+       for (i = 0; i < omap_nr_pending; i++)
+               if (intc_readl(INTC_PENDING_IRQ0 + (0x20 * i)))
+                       return 1;
+       return 0;
+}
+
+void omap3_intc_suspend(void)
+{
+       /* A pending interrupt would prevent OMAP from entering suspend */
+       omap_ack_irq(NULL);
+}
+
+static int __init omap_alloc_gc_of(struct irq_domain *d, void __iomem *base)
+{
+       int ret;
+       int i;
+
+       ret = irq_alloc_domain_generic_chips(d, 32, 1, "INTC",
+                       handle_level_irq, IRQ_NOREQUEST | IRQ_NOPROBE,
+                       IRQ_LEVEL, 0);
+       if (ret) {
+               pr_warn("Failed to allocate irq chips\n");
+               return ret;
+       }
+
+       for (i = 0; i < omap_nr_pending; i++) {
+               struct irq_chip_generic *gc;
+               struct irq_chip_type *ct;
+
+               gc = irq_get_domain_generic_chip(d, 32 * i);
+               gc->reg_base = base;
+               ct = gc->chip_types;
+
+               ct->type = IRQ_TYPE_LEVEL_MASK;
+               ct->handler = handle_level_irq;
+
+               ct->chip.irq_ack = omap_mask_ack_irq;
+               ct->chip.irq_mask = irq_gc_mask_disable_reg;
+               ct->chip.irq_unmask = irq_gc_unmask_enable_reg;
+
+               ct->chip.flags |= IRQCHIP_SKIP_SET_WAKE;
+
+               ct->regs.enable = INTC_MIR_CLEAR0 + 32 * i;
+               ct->regs.disable = INTC_MIR_SET0 + 32 * i;
+       }
+
+       return 0;
+}
+
+static void __init omap_alloc_gc_legacy(void __iomem *base,
+               unsigned int irq_start, unsigned int num)
+{
+       struct irq_chip_generic *gc;
+       struct irq_chip_type *ct;
+
+       gc = irq_alloc_generic_chip("INTC", 1, irq_start, base,
+                       handle_level_irq);
+       ct = gc->chip_types;
+       ct->chip.irq_ack = omap_mask_ack_irq;
+       ct->chip.irq_mask = irq_gc_mask_disable_reg;
+       ct->chip.irq_unmask = irq_gc_unmask_enable_reg;
+       ct->chip.flags |= IRQCHIP_SKIP_SET_WAKE;
+
+       ct->regs.enable = INTC_MIR_CLEAR0;
+       ct->regs.disable = INTC_MIR_SET0;
+       irq_setup_generic_chip(gc, IRQ_MSK(num), IRQ_GC_INIT_MASK_CACHE,
+                       IRQ_NOREQUEST | IRQ_NOPROBE, 0);
+}
+
+static int __init omap_init_irq_of(struct device_node *node)
+{
+       int ret;
+
+       omap_irq_base = of_iomap(node, 0);
+       if (WARN_ON(!omap_irq_base))
+               return -ENOMEM;
+
+       domain = irq_domain_add_linear(node, omap_nr_irqs,
+                       &irq_generic_chip_ops, NULL);
+
+       omap_irq_soft_reset();
+
+       ret = omap_alloc_gc_of(domain, omap_irq_base);
+       if (ret < 0)
+               irq_domain_remove(domain);
+
+       return ret;
+}
+
+static int __init omap_init_irq_legacy(u32 base)
+{
+       int j, irq_base;
+
+       omap_irq_base = ioremap(base, SZ_4K);
+       if (WARN_ON(!omap_irq_base))
+               return -ENOMEM;
+
+       irq_base = irq_alloc_descs(-1, 0, omap_nr_irqs, 0);
+       if (irq_base < 0) {
+               pr_warn("Couldn't allocate IRQ numbers\n");
+               irq_base = 0;
+       }
+
+       domain = irq_domain_add_legacy(NULL, omap_nr_irqs, irq_base, 0,
+                       &irq_domain_simple_ops, NULL);
+
+       omap_irq_soft_reset();
+
+       for (j = 0; j < omap_nr_irqs; j += 32)
+               omap_alloc_gc_legacy(omap_irq_base + j, j + irq_base, 32);
+
+       return 0;
+}
+
+static void __init omap_irq_enable_protection(void)
+{
+       u32 reg;
+
+       reg = intc_readl(INTC_PROTECTION);
+       reg |= INTC_PROTECTION_ENABLE;
+       intc_writel(INTC_PROTECTION, reg);
+}
+
+static int __init omap_init_irq(u32 base, struct device_node *node)
+{
+       int ret;
+
+       if (node)
+               ret = omap_init_irq_of(node);
+       else
+               ret = omap_init_irq_legacy(base);
+
+       if (ret == 0)
+               omap_irq_enable_protection();
+
+       return ret;
+}
+
+static asmlinkage void __exception_irq_entry
+omap_intc_handle_irq(struct pt_regs *regs)
+{
+       u32 irqnr = 0;
+       int handled_irq = 0;
+       int i;
+
+       do {
+               for (i = 0; i < omap_nr_pending; i++) {
+                       irqnr = intc_readl(INTC_PENDING_IRQ0 + (0x20 * i));
+                       if (irqnr)
+                               goto out;
+               }
+
+out:
+               if (!irqnr)
+                       break;
+
+               irqnr = intc_readl(INTC_SIR);
+               irqnr &= ACTIVEIRQ_MASK;
+
+               if (irqnr) {
+                       irqnr = irq_find_mapping(domain, irqnr);
+                       handle_IRQ(irqnr, regs);
+                       handled_irq = 1;
+               }
+       } while (irqnr);
+
+       /*
+        * If an irq is masked or deasserted while active, we will
+        * keep ending up here with no irq handled. So remove it from
+        * the INTC with an ack.
+        */
+       if (!handled_irq)
+               omap_ack_irq(NULL);
+}
+
+void __init omap2_init_irq(void)
+{
+       omap_nr_irqs = 96;
+       omap_nr_pending = 3;
+       omap_init_irq(OMAP24XX_IC_BASE, NULL);
+       set_handle_irq(omap_intc_handle_irq);
+}
+
+void __init omap3_init_irq(void)
+{
+       omap_nr_irqs = 96;
+       omap_nr_pending = 3;
+       omap_init_irq(OMAP34XX_IC_BASE, NULL);
+       set_handle_irq(omap_intc_handle_irq);
+}
+
+void __init ti81xx_init_irq(void)
+{
+       omap_nr_irqs = 96;
+       omap_nr_pending = 4;
+       omap_init_irq(OMAP34XX_IC_BASE, NULL);
+       set_handle_irq(omap_intc_handle_irq);
+}
+
+static int __init intc_of_init(struct device_node *node,
+                            struct device_node *parent)
+{
+       int ret;
+
+       omap_nr_pending = 3;
+       omap_nr_irqs = 96;
+
+       if (WARN_ON(!node))
+               return -ENODEV;
+
+       if (of_device_is_compatible(node, "ti,am33xx-intc")) {
+               omap_nr_irqs = 128;
+               omap_nr_pending = 4;
+       }
+
+       ret = omap_init_irq(-1, of_node_get(node));
+       if (ret < 0)
+               return ret;
+
+       set_handle_irq(omap_intc_handle_irq);
+
+       return 0;
+}
+
+IRQCHIP_DECLARE(omap2_intc, "ti,omap2-intc", intc_of_init);
+IRQCHIP_DECLARE(omap3_intc, "ti,omap3-intc", intc_of_init);
+IRQCHIP_DECLARE(am33xx_intc, "ti,am33xx-intc", intc_of_init);
index f6ef7bb2dc11945355bf87359c192a1085f336b5..90e108f9e22ee29b04c94da98d74460eac4a7ff6 100644 (file)
@@ -478,6 +478,16 @@ config LEDS_BLINKM
          This option enables support for the BlinkM RGB LED connected
          through I2C. Say Y to enable support for the BlinkM LED.
 
+config LEDS_SYSCON
+       bool "LED support for LEDs on system controllers"
+       depends on LEDS_CLASS=y
+       depends on MFD_SYSCON
+       depends on OF
+       help
+         This option enabled support for the LEDs on syscon type
+         devices. This will only work with device tree enabled
+         devices.
+
 config LEDS_VERSATILE
        tristate "LED support for the ARM Versatile and RealView"
        depends on ARCH_REALVIEW || ARCH_VERSATILE
index d8cc5f2777de94e880da92d6fdde7894cf8877c8..822dd83ef97a7c904439d42b66ebd07049497f0b 100644 (file)
@@ -53,6 +53,7 @@ obj-$(CONFIG_LEDS_ASIC3)              += leds-asic3.o
 obj-$(CONFIG_LEDS_MAX8997)             += leds-max8997.o
 obj-$(CONFIG_LEDS_LM355x)              += leds-lm355x.o
 obj-$(CONFIG_LEDS_BLINKM)              += leds-blinkm.o
+obj-$(CONFIG_LEDS_SYSCON)              += leds-syscon.o
 obj-$(CONFIG_LEDS_VERSATILE)           += leds-versatile.o
 
 # LED SPI Drivers
diff --git a/drivers/leds/leds-syscon.c b/drivers/leds/leds-syscon.c
new file mode 100644 (file)
index 0000000..3afec79
--- /dev/null
@@ -0,0 +1,166 @@
+/*
+ * Generic Syscon LEDs Driver
+ *
+ * Copyright (c) 2014, Linaro Limited
+ * Author: Linus Walleij <linus.walleij@linaro.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.
+ *
+ * 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
+ *
+ * This driver provides system reboot functionality for APM X-Gene SoC.
+ * For system shutdown, this is board specify. If a board designer
+ * implements GPIO shutdown, use the gpio-poweroff.c driver.
+ */
+#include <linux/io.h>
+#include <linux/of_device.h>
+#include <linux/of_address.h>
+#include <linux/platform_device.h>
+#include <linux/stat.h>
+#include <linux/slab.h>
+#include <linux/mfd/syscon.h>
+#include <linux/regmap.h>
+#include <linux/leds.h>
+
+/**
+ * struct syscon_led - state container for syscon based LEDs
+ * @cdev: LED class device for this LED
+ * @map: regmap to access the syscon device backing this LED
+ * @offset: the offset into the syscon regmap for the LED register
+ * @mask: the bit in the register corresponding to the LED
+ * @state: current state of the LED
+ */
+struct syscon_led {
+       struct led_classdev cdev;
+       struct regmap *map;
+       u32 offset;
+       u32 mask;
+       bool state;
+};
+
+static void syscon_led_set(struct led_classdev *led_cdev,
+       enum led_brightness value)
+{
+       struct syscon_led *sled =
+               container_of(led_cdev, struct syscon_led, cdev);
+       u32 val;
+       int ret;
+
+       if (value == LED_OFF) {
+               val = 0;
+               sled->state = false;
+       } else {
+               val = sled->mask;
+               sled->state = true;
+       }
+
+       ret = regmap_update_bits(sled->map, sled->offset, sled->mask, val);
+       if (ret < 0)
+               dev_err(sled->cdev.dev, "error updating LED status\n");
+}
+
+static const struct of_device_id syscon_match[] = {
+       { .compatible = "syscon", },
+       {},
+};
+
+static int __init syscon_leds_init(void)
+{
+       const struct of_device_id *devid;
+       struct device_node *np;
+       struct device_node *child;
+       struct regmap *map;
+       struct platform_device *pdev;
+       struct device *dev;
+       int ret;
+
+       np = of_find_matching_node_and_match(NULL, syscon_match,
+                                            &devid);
+       if (!np)
+               return -ENODEV;
+
+       map = syscon_node_to_regmap(np);
+       if (IS_ERR(map))
+               return PTR_ERR(map);
+
+       /*
+        * If the map is there, the device should be there, we allocate
+        * memory on the syscon device's behalf here.
+        */
+       pdev = of_find_device_by_node(np);
+       if (!pdev)
+               return -ENODEV;
+       dev = &pdev->dev;
+
+       for_each_available_child_of_node(np, child) {
+               struct syscon_led *sled;
+               const char *state;
+
+               /* Only check for register-bit-leds */
+               if (of_property_match_string(child, "compatible",
+                                            "register-bit-led") < 0)
+                       continue;
+
+               sled = devm_kzalloc(dev, sizeof(*sled), GFP_KERNEL);
+               if (!sled)
+                       return -ENOMEM;
+
+               sled->map = map;
+
+               if (of_property_read_u32(child, "offset", &sled->offset))
+                       return -EINVAL;
+               if (of_property_read_u32(child, "mask", &sled->mask))
+                       return -EINVAL;
+               sled->cdev.name =
+                       of_get_property(child, "label", NULL) ? : child->name;
+               sled->cdev.default_trigger =
+                       of_get_property(child, "linux,default-trigger", NULL);
+
+               state = of_get_property(child, "default-state", NULL);
+               if (state) {
+                       if (!strcmp(state, "keep")) {
+                               u32 val;
+
+                               ret = regmap_read(map, sled->offset, &val);
+                               if (ret < 0)
+                                       return ret;
+                               sled->state = !!(val & sled->mask);
+                       } else if (!strcmp(state, "on")) {
+                               sled->state = true;
+                               ret = regmap_update_bits(map, sled->offset,
+                                                        sled->mask,
+                                                        sled->mask);
+                               if (ret < 0)
+                                       return ret;
+                       } else {
+                               sled->state = false;
+                               ret = regmap_update_bits(map, sled->offset,
+                                                        sled->mask, 0);
+                               if (ret < 0)
+                                       return ret;
+                       }
+
+               }
+               sled->cdev.brightness_set = syscon_led_set;
+
+               ret = led_classdev_register(dev, &sled->cdev);
+               if (ret < 0)
+                       return ret;
+
+               dev_info(dev, "registered LED %s\n", sled->cdev.name);
+       }
+
+       return 0;
+}
+device_initcall(syscon_leds_init);
index a27e00e63a8a8ef66aa6c4f380b51b1dbd376e9a..bcc7ee1292764711e64f8ffabc60628a24c8121a 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/err.h>
 #include <linux/notifier.h>
 #include <linux/module.h>
+#include <linux/of_device.h>
 #include <linux/platform_device.h>
 #include <linux/pm_runtime.h>
 #include <linux/platform_data/mailbox-omap.h>
@@ -94,6 +95,18 @@ struct omap_mbox_device {
        struct list_head elem;
 };
 
+struct omap_mbox_fifo_info {
+       int tx_id;
+       int tx_usr;
+       int tx_irq;
+
+       int rx_id;
+       int rx_usr;
+       int rx_irq;
+
+       const char *name;
+};
+
 struct omap_mbox {
        const char              *name;
        int                     irq;
@@ -587,24 +600,118 @@ static int omap_mbox_unregister(struct omap_mbox_device *mdev)
        return 0;
 }
 
+static const struct of_device_id omap_mailbox_of_match[] = {
+       {
+               .compatible     = "ti,omap2-mailbox",
+               .data           = (void *)MBOX_INTR_CFG_TYPE1,
+       },
+       {
+               .compatible     = "ti,omap3-mailbox",
+               .data           = (void *)MBOX_INTR_CFG_TYPE1,
+       },
+       {
+               .compatible     = "ti,omap4-mailbox",
+               .data           = (void *)MBOX_INTR_CFG_TYPE2,
+       },
+       {
+               /* end */
+       },
+};
+MODULE_DEVICE_TABLE(of, omap_mailbox_of_match);
+
 static int omap_mbox_probe(struct platform_device *pdev)
 {
        struct resource *mem;
        int ret;
        struct omap_mbox **list, *mbox, *mboxblk;
        struct omap_mbox_pdata *pdata = pdev->dev.platform_data;
-       struct omap_mbox_dev_info *info;
+       struct omap_mbox_dev_info *info = NULL;
+       struct omap_mbox_fifo_info *finfo, *finfoblk;
        struct omap_mbox_device *mdev;
        struct omap_mbox_fifo *fifo;
-       u32 intr_type;
+       struct device_node *node = pdev->dev.of_node;
+       struct device_node *child;
+       const struct of_device_id *match;
+       u32 intr_type, info_count;
+       u32 num_users, num_fifos;
+       u32 tmp[3];
        u32 l;
        int i;
 
-       if (!pdata || !pdata->info_cnt || !pdata->info) {
+       if (!node && (!pdata || !pdata->info_cnt || !pdata->info)) {
                pr_err("%s: platform not supported\n", __func__);
                return -ENODEV;
        }
 
+       if (node) {
+               match = of_match_device(omap_mailbox_of_match, &pdev->dev);
+               if (!match)
+                       return -ENODEV;
+               intr_type = (u32)match->data;
+
+               if (of_property_read_u32(node, "ti,mbox-num-users",
+                                        &num_users))
+                       return -ENODEV;
+
+               if (of_property_read_u32(node, "ti,mbox-num-fifos",
+                                        &num_fifos))
+                       return -ENODEV;
+
+               info_count = of_get_available_child_count(node);
+               if (!info_count) {
+                       dev_err(&pdev->dev, "no available mbox devices found\n");
+                       return -ENODEV;
+               }
+       } else { /* non-DT device creation */
+               info_count = pdata->info_cnt;
+               info = pdata->info;
+               intr_type = pdata->intr_type;
+               num_users = pdata->num_users;
+               num_fifos = pdata->num_fifos;
+       }
+
+       finfoblk = devm_kzalloc(&pdev->dev, info_count * sizeof(*finfoblk),
+                               GFP_KERNEL);
+       if (!finfoblk)
+               return -ENOMEM;
+
+       finfo = finfoblk;
+       child = NULL;
+       for (i = 0; i < info_count; i++, finfo++) {
+               if (node) {
+                       child = of_get_next_available_child(node, child);
+                       ret = of_property_read_u32_array(child, "ti,mbox-tx",
+                                                        tmp, ARRAY_SIZE(tmp));
+                       if (ret)
+                               return ret;
+                       finfo->tx_id = tmp[0];
+                       finfo->tx_irq = tmp[1];
+                       finfo->tx_usr = tmp[2];
+
+                       ret = of_property_read_u32_array(child, "ti,mbox-rx",
+                                                        tmp, ARRAY_SIZE(tmp));
+                       if (ret)
+                               return ret;
+                       finfo->rx_id = tmp[0];
+                       finfo->rx_irq = tmp[1];
+                       finfo->rx_usr = tmp[2];
+
+                       finfo->name = child->name;
+               } else {
+                       finfo->tx_id = info->tx_id;
+                       finfo->rx_id = info->rx_id;
+                       finfo->tx_usr = info->usr_id;
+                       finfo->tx_irq = info->irq_id;
+                       finfo->rx_usr = info->usr_id;
+                       finfo->rx_irq = info->irq_id;
+                       finfo->name = info->name;
+                       info++;
+               }
+               if (finfo->tx_id >= num_fifos || finfo->rx_id >= num_fifos ||
+                   finfo->tx_usr >= num_users || finfo->rx_usr >= num_users)
+                       return -EINVAL;
+       }
+
        mdev = devm_kzalloc(&pdev->dev, sizeof(*mdev), GFP_KERNEL);
        if (!mdev)
                return -ENOMEM;
@@ -615,41 +722,40 @@ static int omap_mbox_probe(struct platform_device *pdev)
                return PTR_ERR(mdev->mbox_base);
 
        /* allocate one extra for marking end of list */
-       list = devm_kzalloc(&pdev->dev, (pdata->info_cnt + 1) * sizeof(*list),
+       list = devm_kzalloc(&pdev->dev, (info_count + 1) * sizeof(*list),
                            GFP_KERNEL);
        if (!list)
                return -ENOMEM;
 
-       mboxblk = devm_kzalloc(&pdev->dev, pdata->info_cnt * sizeof(*mbox),
+       mboxblk = devm_kzalloc(&pdev->dev, info_count * sizeof(*mbox),
                               GFP_KERNEL);
        if (!mboxblk)
                return -ENOMEM;
 
-       info = pdata->info;
-       intr_type = pdata->intr_type;
        mbox = mboxblk;
-       for (i = 0; i < pdata->info_cnt; i++, info++) {
+       finfo = finfoblk;
+       for (i = 0; i < info_count; i++, finfo++) {
                fifo = &mbox->tx_fifo;
-               fifo->msg = MAILBOX_MESSAGE(info->tx_id);
-               fifo->fifo_stat = MAILBOX_FIFOSTATUS(info->tx_id);
-               fifo->intr_bit = MAILBOX_IRQ_NOTFULL(info->tx_id);
-               fifo->irqenable = MAILBOX_IRQENABLE(intr_type, info->usr_id);
-               fifo->irqstatus = MAILBOX_IRQSTATUS(intr_type, info->usr_id);
-               fifo->irqdisable = MAILBOX_IRQDISABLE(intr_type, info->usr_id);
+               fifo->msg = MAILBOX_MESSAGE(finfo->tx_id);
+               fifo->fifo_stat = MAILBOX_FIFOSTATUS(finfo->tx_id);
+               fifo->intr_bit = MAILBOX_IRQ_NOTFULL(finfo->tx_id);
+               fifo->irqenable = MAILBOX_IRQENABLE(intr_type, finfo->tx_usr);
+               fifo->irqstatus = MAILBOX_IRQSTATUS(intr_type, finfo->tx_usr);
+               fifo->irqdisable = MAILBOX_IRQDISABLE(intr_type, finfo->tx_usr);
 
                fifo = &mbox->rx_fifo;
-               fifo->msg =  MAILBOX_MESSAGE(info->rx_id);
-               fifo->msg_stat =  MAILBOX_MSGSTATUS(info->rx_id);
-               fifo->intr_bit = MAILBOX_IRQ_NEWMSG(info->rx_id);
-               fifo->irqenable = MAILBOX_IRQENABLE(intr_type, info->usr_id);
-               fifo->irqstatus = MAILBOX_IRQSTATUS(intr_type, info->usr_id);
-               fifo->irqdisable = MAILBOX_IRQDISABLE(intr_type, info->usr_id);
+               fifo->msg = MAILBOX_MESSAGE(finfo->rx_id);
+               fifo->msg_stat =  MAILBOX_MSGSTATUS(finfo->rx_id);
+               fifo->intr_bit = MAILBOX_IRQ_NEWMSG(finfo->rx_id);
+               fifo->irqenable = MAILBOX_IRQENABLE(intr_type, finfo->rx_usr);
+               fifo->irqstatus = MAILBOX_IRQSTATUS(intr_type, finfo->rx_usr);
+               fifo->irqdisable = MAILBOX_IRQDISABLE(intr_type, finfo->rx_usr);
 
                mbox->intr_type = intr_type;
 
                mbox->parent = mdev;
-               mbox->name = info->name;
-               mbox->irq = platform_get_irq(pdev, info->irq_id);
+               mbox->name = finfo->name;
+               mbox->irq = platform_get_irq(pdev, finfo->tx_irq);
                if (mbox->irq < 0)
                        return mbox->irq;
                list[i] = mbox++;
@@ -657,8 +763,8 @@ static int omap_mbox_probe(struct platform_device *pdev)
 
        mutex_init(&mdev->cfg_lock);
        mdev->dev = &pdev->dev;
-       mdev->num_users = pdata->num_users;
-       mdev->num_fifos = pdata->num_fifos;
+       mdev->num_users = num_users;
+       mdev->num_fifos = num_fifos;
        mdev->mboxes = list;
        ret = omap_mbox_register(mdev);
        if (ret)
@@ -684,6 +790,7 @@ static int omap_mbox_probe(struct platform_device *pdev)
        if (ret < 0)
                goto unregister;
 
+       devm_kfree(&pdev->dev, finfoblk);
        return 0;
 
 unregister:
@@ -708,6 +815,7 @@ static struct platform_driver omap_mbox_driver = {
        .driver = {
                .name = "omap-mailbox",
                .owner = THIS_MODULE,
+               .of_match_table = of_match_ptr(omap_mailbox_of_match),
        },
 };
 
index fab81a143bd7ea80e257cf21637e99872ed751c0..6d91c27fd4c8f325f29b7d21f5e93a89cff59691 100644 (file)
@@ -7,6 +7,16 @@ menuconfig MEMORY
 
 if MEMORY
 
+config ATMEL_SDRAMC
+       bool "Atmel (Multi-port DDR-)SDRAM Controller"
+       default y
+       depends on ARCH_AT91 && OF
+       help
+         This driver is for Atmel SDRAM Controller or Atmel Multi-port
+         DDR-SDRAM Controller available on Atmel AT91SAM9 and SAMA5 SoCs.
+         Starting with the at91sam9g45, this controller supports SDR, DDR and
+         LP-DDR memories.
+
 config TI_AEMIF
        tristate "Texas Instruments AEMIF driver"
        depends on (ARCH_DAVINCI || ARCH_KEYSTONE) && OF
index 4055c47f45ab337362524804bfeff4d20ca8699c..c32d31981be314518d16c8933177937e97841545 100644 (file)
@@ -5,6 +5,7 @@
 ifeq ($(CONFIG_DDR),y)
 obj-$(CONFIG_OF)               += of_memory.o
 endif
+obj-$(CONFIG_ATMEL_SDRAMC)     += atmel-sdramc.o
 obj-$(CONFIG_TI_AEMIF)         += ti-aemif.o
 obj-$(CONFIG_TI_EMIF)          += emif.o
 obj-$(CONFIG_FSL_CORENET_CF)   += fsl-corenet-cf.o
diff --git a/drivers/memory/atmel-sdramc.c b/drivers/memory/atmel-sdramc.c
new file mode 100644 (file)
index 0000000..fed04e8
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ * Atmel (Multi-port DDR-)SDRAM Controller driver
+ *
+ * Copyright (C) 2014 Atmel
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+
+struct at91_ramc_caps {
+       bool has_ddrck;
+       bool has_mpddr_clk;
+};
+
+static const struct at91_ramc_caps at91rm9200_caps = { };
+
+static const struct at91_ramc_caps at91sam9g45_caps = {
+       .has_ddrck = 1,
+       .has_mpddr_clk = 0,
+};
+
+static const struct at91_ramc_caps sama5d3_caps = {
+       .has_ddrck = 1,
+       .has_mpddr_clk = 1,
+};
+
+static const struct of_device_id atmel_ramc_of_match[] = {
+       { .compatible = "atmel,at91rm9200-sdramc", .data = &at91rm9200_caps, },
+       { .compatible = "atmel,at91sam9260-sdramc", .data = &at91rm9200_caps, },
+       { .compatible = "atmel,at91sam9g45-ddramc", .data = &at91sam9g45_caps, },
+       { .compatible = "atmel,sama5d3-ddramc", .data = &sama5d3_caps, },
+       {},
+};
+MODULE_DEVICE_TABLE(of, atmel_ramc_of_match);
+
+static int atmel_ramc_probe(struct platform_device *pdev)
+{
+       const struct of_device_id *match;
+       const struct at91_ramc_caps *caps;
+       struct clk *clk;
+
+       match = of_match_device(atmel_ramc_of_match, &pdev->dev);
+       caps = match->data;
+
+       if (caps->has_ddrck) {
+               clk = devm_clk_get(&pdev->dev, "ddrck");
+               if (IS_ERR(clk))
+                       return PTR_ERR(clk);
+               clk_prepare_enable(clk);
+       }
+
+       if (caps->has_mpddr_clk) {
+               clk = devm_clk_get(&pdev->dev, "mpddr");
+               if (IS_ERR(clk)) {
+                       pr_err("AT91 RAMC: couldn't get mpddr clock\n");
+                       return PTR_ERR(clk);
+               }
+               clk_prepare_enable(clk);
+       }
+
+       return 0;
+}
+
+static struct platform_driver atmel_ramc_driver = {
+       .probe          = atmel_ramc_probe,
+       .driver         = {
+               .name   = "atmel-ramc",
+               .owner  = THIS_MODULE,
+               .of_match_table = atmel_ramc_of_match,
+       },
+};
+
+static int __init atmel_ramc_init(void)
+{
+       return platform_driver_register(&atmel_ramc_driver);
+}
+module_init(atmel_ramc_init);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Alexandre Belloni <alexandre.belloni@free-electrons.com>");
+MODULE_DESCRIPTION("Atmel (Multi-port DDR-)SDRAM Controller");
index ca41523bbebf767ad1af56594cd1ba57d297b06e..527a0f47ef448c1c39650a294eaadc3d9c2709ad 100644 (file)
@@ -6,15 +6,33 @@ menuconfig POWER_RESET
 
          Say Y here to enable board reset and power off
 
+if POWER_RESET
+
 config POWER_RESET_AS3722
        bool "ams AS3722 power-off driver"
-       depends on MFD_AS3722 && POWER_RESET
+       depends on MFD_AS3722
        help
          This driver supports turning off board via a ams AS3722 power-off.
 
+config POWER_RESET_AT91_POWEROFF
+       bool "Atmel AT91 poweroff driver"
+       depends on ARCH_AT91
+       default SOC_AT91SAM9 || SOC_SAMA5
+       help
+         This driver supports poweroff for Atmel AT91SAM9 and SAMA5
+         SoCs
+
+config POWER_RESET_AT91_RESET
+       bool "Atmel AT91 reset driver"
+       depends on ARCH_AT91
+       default SOC_AT91SAM9 || SOC_SAMA5
+       help
+         This driver supports restart for Atmel AT91SAM9 and SAMA5
+         SoCs
+
 config POWER_RESET_AXXIA
        bool "LSI Axxia reset driver"
-       depends on POWER_RESET && ARCH_AXXIA
+       depends on ARCH_AXXIA
        help
          This driver supports restart for Axxia SoC.
 
@@ -33,7 +51,7 @@ config POWER_RESET_BRCMSTB
 
 config POWER_RESET_GPIO
        bool "GPIO power-off driver"
-       depends on OF_GPIO && POWER_RESET
+       depends on OF_GPIO
        help
          This driver supports turning off your board via a GPIO line.
          If your board needs a GPIO high/low to power down, say Y and
@@ -47,13 +65,13 @@ config POWER_RESET_HISI
 
 config POWER_RESET_MSM
        bool "Qualcomm MSM power-off driver"
-       depends on POWER_RESET && ARCH_QCOM
+       depends on ARCH_QCOM
        help
          Power off and restart support for Qualcomm boards.
 
 config POWER_RESET_QNAP
        bool "QNAP power-off driver"
-       depends on OF_GPIO && POWER_RESET && PLAT_ORION
+       depends on OF_GPIO && PLAT_ORION
        help
          This driver supports turning off QNAP NAS devices by sending
          commands to the microcontroller which controls the main power.
@@ -71,14 +89,22 @@ config POWER_RESET_RESTART
 config POWER_RESET_SUN6I
        bool "Allwinner A31 SoC reset driver"
        depends on ARCH_SUNXI
-       depends on POWER_RESET
        help
          Reboot support for the Allwinner A31 SoCs.
 
+config POWER_RESET_VERSATILE
+       bool "ARM Versatile family reboot driver"
+       depends on ARM
+       depends on MFD_SYSCON
+       depends on OF
+       help
+         Power off and restart support for ARM Versatile family of
+         reference boards.
+
 config POWER_RESET_VEXPRESS
        bool "ARM Versatile Express power-off and reset driver"
        depends on ARM || ARM64
-       depends on POWER_RESET && VEXPRESS_CONFIG
+       depends on VEXPRESS_CONFIG
        help
          Power off and reset support for the ARM Ltd. Versatile
          Express boards.
@@ -86,7 +112,6 @@ config POWER_RESET_VEXPRESS
 config POWER_RESET_XGENE
        bool "APM SoC X-Gene reset driver"
        depends on ARM64
-       depends on POWER_RESET
        help
          Reboot support for the APM SoC X-Gene Eval boards.
 
@@ -97,3 +122,4 @@ config POWER_RESET_KEYSTONE
        help
          Reboot support for the KEYSTONE SoCs.
 
+endif
index a42e70edd0376912b88b4f4a4a3f3fc01ef17496..73221009f2bff61f86207a15ad4d34be547cb1af 100644 (file)
@@ -1,4 +1,6 @@
 obj-$(CONFIG_POWER_RESET_AS3722) += as3722-poweroff.o
+obj-$(CONFIG_POWER_RESET_AT91_POWEROFF) += at91-poweroff.o
+obj-$(CONFIG_POWER_RESET_AT91_RESET) += at91-reset.o
 obj-$(CONFIG_POWER_RESET_AXXIA) += axxia-reset.o
 obj-$(CONFIG_POWER_RESET_BRCMSTB) += brcmstb-reboot.o
 obj-$(CONFIG_POWER_RESET_GPIO) += gpio-poweroff.o
@@ -7,6 +9,7 @@ obj-$(CONFIG_POWER_RESET_MSM) += msm-poweroff.o
 obj-$(CONFIG_POWER_RESET_QNAP) += qnap-poweroff.o
 obj-$(CONFIG_POWER_RESET_RESTART) += restart-poweroff.o
 obj-$(CONFIG_POWER_RESET_SUN6I) += sun6i-reboot.o
+obj-$(CONFIG_POWER_RESET_VERSATILE) += arm-versatile-reboot.o
 obj-$(CONFIG_POWER_RESET_VEXPRESS) += vexpress-poweroff.o
 obj-$(CONFIG_POWER_RESET_XGENE) += xgene-reboot.o
 obj-$(CONFIG_POWER_RESET_KEYSTONE) += keystone-reset.o
diff --git a/drivers/power/reset/arm-versatile-reboot.c b/drivers/power/reset/arm-versatile-reboot.c
new file mode 100644 (file)
index 0000000..5b08bff
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2014 Linaro Ltd.
+ *
+ * Author: Linus Walleij <linus.walleij@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2, as
+ * published by the Free Software Foundation.
+ *
+ */
+#include <linux/init.h>
+#include <linux/mfd/syscon.h>
+#include <linux/reboot.h>
+#include <linux/regmap.h>
+#include <linux/of.h>
+#include <asm/system_misc.h>
+
+#define REALVIEW_SYS_LOCK_OFFSET       0x20
+#define REALVIEW_SYS_LOCK_VAL          0xA05F
+#define REALVIEW_SYS_RESETCTL_OFFSET   0x40
+
+/*
+ * We detect the different syscon types from the compatible strings.
+ */
+enum versatile_reboot {
+       REALVIEW_REBOOT_EB,
+       REALVIEW_REBOOT_PB1176,
+       REALVIEW_REBOOT_PB11MP,
+       REALVIEW_REBOOT_PBA8,
+       REALVIEW_REBOOT_PBX,
+};
+
+/* Pointer to the system controller */
+static struct regmap *syscon_regmap;
+static enum versatile_reboot versatile_reboot_type;
+
+static const struct of_device_id versatile_reboot_of_match[] = {
+       {
+               .compatible = "arm,realview-eb-syscon",
+               .data = (void *)REALVIEW_REBOOT_EB,
+       },
+       {
+               .compatible = "arm,realview-pb1176-syscon",
+               .data = (void *)REALVIEW_REBOOT_PB1176,
+       },
+       {
+               .compatible = "arm,realview-pb11mp-syscon",
+               .data = (void *)REALVIEW_REBOOT_PB11MP,
+       },
+       {
+               .compatible = "arm,realview-pba8-syscon",
+               .data = (void *)REALVIEW_REBOOT_PBA8,
+       },
+       {
+               .compatible = "arm,realview-pbx-syscon",
+               .data = (void *)REALVIEW_REBOOT_PBX,
+       },
+};
+
+static void versatile_reboot(enum reboot_mode mode, const char *cmd)
+{
+       /* Unlock the reset register */
+       regmap_write(syscon_regmap, REALVIEW_SYS_LOCK_OFFSET,
+                    REALVIEW_SYS_LOCK_VAL);
+       /* Then hit reset on the different machines */
+       switch (versatile_reboot_type) {
+       case REALVIEW_REBOOT_EB:
+               regmap_write(syscon_regmap,
+                            REALVIEW_SYS_RESETCTL_OFFSET, 0x0008);
+               break;
+       case REALVIEW_REBOOT_PB1176:
+               regmap_write(syscon_regmap,
+                            REALVIEW_SYS_RESETCTL_OFFSET, 0x0100);
+               break;
+       case REALVIEW_REBOOT_PB11MP:
+       case REALVIEW_REBOOT_PBA8:
+               regmap_write(syscon_regmap, REALVIEW_SYS_RESETCTL_OFFSET,
+                            0x0000);
+               regmap_write(syscon_regmap, REALVIEW_SYS_RESETCTL_OFFSET,
+                            0x0004);
+               break;
+       case REALVIEW_REBOOT_PBX:
+               regmap_write(syscon_regmap, REALVIEW_SYS_RESETCTL_OFFSET,
+                            0x00f0);
+               regmap_write(syscon_regmap, REALVIEW_SYS_RESETCTL_OFFSET,
+                            0x00f4);
+               break;
+       }
+       dsb();
+}
+
+static int __init versatile_reboot_probe(void)
+{
+       const struct of_device_id *reboot_id;
+       struct device_node *np;
+
+       np = of_find_matching_node_and_match(NULL, versatile_reboot_of_match,
+                                                &reboot_id);
+       if (!np)
+               return -ENODEV;
+       versatile_reboot_type = (enum versatile_reboot)reboot_id->data;
+
+       syscon_regmap = syscon_node_to_regmap(np);
+       if (IS_ERR(syscon_regmap))
+               return PTR_ERR(syscon_regmap);
+
+       arm_pm_restart = versatile_reboot;
+       pr_info("versatile reboot driver registered\n");
+       return 0;
+}
+device_initcall(versatile_reboot_probe);
diff --git a/drivers/power/reset/at91-poweroff.c b/drivers/power/reset/at91-poweroff.c
new file mode 100644 (file)
index 0000000..c610003
--- /dev/null
@@ -0,0 +1,156 @@
+/*
+ * Atmel AT91 SAM9 SoCs reset code
+ *
+ * Copyright (C) 2007 Atmel Corporation.
+ * Copyright (C) 2011 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+ * Copyright (C) 2014 Free Electrons
+ *
+ * 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.
+ */
+
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/printk.h>
+
+#define AT91_SHDW_CR   0x00            /* Shut Down Control Register */
+#define AT91_SHDW_SHDW         BIT(0)                  /* Shut Down command */
+#define AT91_SHDW_KEY          (0xa5 << 24)            /* KEY Password */
+
+#define AT91_SHDW_MR   0x04            /* Shut Down Mode Register */
+#define AT91_SHDW_WKMODE0      GENMASK(2, 0)           /* Wake-up 0 Mode Selection */
+#define AT91_SHDW_CPTWK0_MAX   0xf                     /* Maximum Counter On Wake Up 0 */
+#define AT91_SHDW_CPTWK0       (AT91_SHDW_CPTWK0_MAX << 4) /* Counter On Wake Up 0 */
+#define AT91_SHDW_CPTWK0_(x)   ((x) << 4)
+#define AT91_SHDW_RTTWKEN      BIT(16)                 /* Real Time Timer Wake-up Enable */
+#define AT91_SHDW_RTCWKEN      BIT(17)                 /* Real Time Clock Wake-up Enable */
+
+#define AT91_SHDW_SR   0x08            /* Shut Down Status Register */
+#define AT91_SHDW_WAKEUP0      BIT(0)                  /* Wake-up 0 Status */
+#define AT91_SHDW_RTTWK                BIT(16)                 /* Real-time Timer Wake-up */
+#define AT91_SHDW_RTCWK                BIT(17)                 /* Real-time Clock Wake-up [SAM9RL] */
+
+enum wakeup_type {
+       AT91_SHDW_WKMODE0_NONE          = 0,
+       AT91_SHDW_WKMODE0_HIGH          = 1,
+       AT91_SHDW_WKMODE0_LOW           = 2,
+       AT91_SHDW_WKMODE0_ANYLEVEL      = 3,
+};
+
+static const char *shdwc_wakeup_modes[] = {
+       [AT91_SHDW_WKMODE0_NONE]        = "none",
+       [AT91_SHDW_WKMODE0_HIGH]        = "high",
+       [AT91_SHDW_WKMODE0_LOW]         = "low",
+       [AT91_SHDW_WKMODE0_ANYLEVEL]    = "any",
+};
+
+static void __iomem *at91_shdwc_base;
+
+static void __init at91_wakeup_status(void)
+{
+       u32 reg = readl(at91_shdwc_base + AT91_SHDW_SR);
+       char *reason = "unknown";
+
+       /* Simple power-on, just bail out */
+       if (!reg)
+               return;
+
+       if (reg & AT91_SHDW_RTTWK)
+               reason = "RTT";
+       else if (reg & AT91_SHDW_RTCWK)
+               reason = "RTC";
+
+       pr_info("AT91: Wake-Up source: %s\n", reason);
+}
+
+static void at91_poweroff(void)
+{
+       writel(AT91_SHDW_KEY | AT91_SHDW_SHDW, at91_shdwc_base + AT91_SHDW_CR);
+}
+
+const enum wakeup_type at91_poweroff_get_wakeup_mode(struct device_node *np)
+{
+       const char *pm;
+       int err, i;
+
+       err = of_property_read_string(np, "atmel,wakeup-mode", &pm);
+       if (err < 0)
+               return AT91_SHDW_WKMODE0_ANYLEVEL;
+
+       for (i = 0; i < ARRAY_SIZE(shdwc_wakeup_modes); i++)
+               if (!strcasecmp(pm, shdwc_wakeup_modes[i]))
+                       return i;
+
+       return -ENODEV;
+}
+
+static void at91_poweroff_dt_set_wakeup_mode(struct platform_device *pdev)
+{
+       struct device_node *np = pdev->dev.of_node;
+       enum wakeup_type wakeup_mode;
+       u32 mode = 0, tmp;
+
+       wakeup_mode = at91_poweroff_get_wakeup_mode(np);
+       if (wakeup_mode < 0) {
+               dev_warn(&pdev->dev, "shdwc unknown wakeup mode\n");
+               return;
+       }
+
+       if (!of_property_read_u32(np, "atmel,wakeup-counter", &tmp)) {
+               if (tmp > AT91_SHDW_CPTWK0_MAX) {
+                       dev_warn(&pdev->dev,
+                                "shdwc wakeup counter 0x%x > 0x%x reduce it to 0x%x\n",
+                                tmp, AT91_SHDW_CPTWK0_MAX, AT91_SHDW_CPTWK0_MAX);
+                       tmp = AT91_SHDW_CPTWK0_MAX;
+               }
+               mode |= AT91_SHDW_CPTWK0_(tmp);
+       }
+
+       if (of_property_read_bool(np, "atmel,wakeup-rtc-timer"))
+                       mode |= AT91_SHDW_RTCWKEN;
+
+       if (of_property_read_bool(np, "atmel,wakeup-rtt-timer"))
+                       mode |= AT91_SHDW_RTTWKEN;
+
+       writel(wakeup_mode | mode, at91_shdwc_base + AT91_SHDW_MR);
+}
+
+static int at91_poweroff_probe(struct platform_device *pdev)
+{
+       struct resource *res;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       at91_shdwc_base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(at91_shdwc_base)) {
+               dev_err(&pdev->dev, "Could not map reset controller address\n");
+               return PTR_ERR(at91_shdwc_base);
+       }
+
+       at91_wakeup_status();
+
+       if (pdev->dev.of_node)
+               at91_poweroff_dt_set_wakeup_mode(pdev);
+
+       pm_power_off = at91_poweroff;
+
+       return 0;
+}
+
+static struct of_device_id at91_poweroff_of_match[] = {
+       { .compatible = "atmel,at91sam9260-shdwc", },
+       { .compatible = "atmel,at91sam9rl-shdwc", },
+       { .compatible = "atmel,at91sam9x5-shdwc", },
+       { /*sentinel*/ }
+};
+
+static struct platform_driver at91_poweroff_driver = {
+       .probe = at91_poweroff_probe,
+       .driver = {
+               .name = "at91-poweroff",
+               .of_match_table = at91_poweroff_of_match,
+       },
+};
+module_platform_driver(at91_poweroff_driver);
diff --git a/drivers/power/reset/at91-reset.c b/drivers/power/reset/at91-reset.c
new file mode 100644 (file)
index 0000000..3611806
--- /dev/null
@@ -0,0 +1,252 @@
+/*
+ * Atmel AT91 SAM9 SoCs reset code
+ *
+ * Copyright (C) 2007 Atmel Corporation.
+ * Copyright (C) BitBox Ltd 2010
+ * Copyright (C) 2011 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcosoft.com>
+ * Copyright (C) 2014 Free Electrons
+ *
+ * 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.
+ */
+
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/platform_device.h>
+#include <linux/reboot.h>
+
+#include <asm/system_misc.h>
+
+#include <mach/at91sam9_ddrsdr.h>
+#include <mach/at91sam9_sdramc.h>
+
+#define AT91_RSTC_CR   0x00            /* Reset Controller Control Register */
+#define AT91_RSTC_PROCRST      BIT(0)          /* Processor Reset */
+#define AT91_RSTC_PERRST       BIT(2)          /* Peripheral Reset */
+#define AT91_RSTC_EXTRST       BIT(3)          /* External Reset */
+#define AT91_RSTC_KEY          (0xa5 << 24)    /* KEY Password */
+
+#define AT91_RSTC_SR   0x04            /* Reset Controller Status Register */
+#define AT91_RSTC_URSTS                BIT(0)          /* User Reset Status */
+#define AT91_RSTC_RSTTYP       GENMASK(10, 8)  /* Reset Type */
+#define AT91_RSTC_NRSTL                BIT(16)         /* NRST Pin Level */
+#define AT91_RSTC_SRCMP                BIT(17)         /* Software Reset Command in Progress */
+
+#define AT91_RSTC_MR   0x08            /* Reset Controller Mode Register */
+#define AT91_RSTC_URSTEN       BIT(0)          /* User Reset Enable */
+#define AT91_RSTC_URSTIEN      BIT(4)          /* User Reset Interrupt Enable */
+#define AT91_RSTC_ERSTL                GENMASK(11, 8)  /* External Reset Length */
+
+enum reset_type {
+       RESET_TYPE_GENERAL      = 0,
+       RESET_TYPE_WAKEUP       = 1,
+       RESET_TYPE_WATCHDOG     = 2,
+       RESET_TYPE_SOFTWARE     = 3,
+       RESET_TYPE_USER         = 4,
+};
+
+static void __iomem *at91_ramc_base[2], *at91_rstc_base;
+
+/*
+* unless the SDRAM is cleanly shutdown before we hit the
+* reset register it can be left driving the data bus and
+* killing the chance of a subsequent boot from NAND
+*/
+static void at91sam9260_restart(enum reboot_mode mode, const char *cmd)
+{
+       asm volatile(
+               /* Align to cache lines */
+               ".balign 32\n\t"
+
+               /* Disable SDRAM accesses */
+               "str    %2, [%0, #" __stringify(AT91_SDRAMC_TR) "]\n\t"
+
+               /* Power down SDRAM */
+               "str    %3, [%0, #" __stringify(AT91_SDRAMC_LPR) "]\n\t"
+
+               /* Reset CPU */
+               "str    %4, [%1, #" __stringify(AT91_RSTC_CR) "]\n\t"
+
+               "b      .\n\t"
+               :
+               : "r" (at91_ramc_base[0]),
+                 "r" (at91_rstc_base),
+                 "r" (1),
+                 "r" (AT91_SDRAMC_LPCB_POWER_DOWN),
+                 "r" (AT91_RSTC_KEY | AT91_RSTC_PERRST | AT91_RSTC_PROCRST));
+}
+
+static void at91sam9g45_restart(enum reboot_mode mode, const char *cmd)
+{
+       asm volatile(
+               /*
+                * Test wether we have a second RAM controller to care
+                * about.
+                *
+                * First, test that we can dereference the virtual address.
+                */
+               "cmp    %1, #0\n\t"
+               "beq    1f\n\t"
+
+               /* Then, test that the RAM controller is enabled */
+               "ldr    r0, [%1]\n\t"
+               "cmp    r0, #0\n\t"
+
+               /* Align to cache lines */
+               ".balign 32\n\t"
+
+               /* Disable SDRAM0 accesses */
+               "1:     str     %3, [%0, #" __stringify(AT91_DDRSDRC_RTR) "]\n\t"
+               /* Power down SDRAM0 */
+               "       str     %4, [%0, #" __stringify(AT91_DDRSDRC_RTR) "]\n\t"
+               /* Disable SDRAM1 accesses */
+               "       strne   %3, [%1, #" __stringify(AT91_DDRSDRC_RTR) "]\n\t"
+               /* Power down SDRAM1 */
+               "       strne   %4, [%1, #" __stringify(AT91_DDRSDRC_RTR) "]\n\t"
+               /* Reset CPU */
+               "       str     %5, [%2, #" __stringify(AT91_RSTC_CR) "]\n\t"
+
+               "       b       .\n\t"
+               :
+               : "r" (at91_ramc_base[0]),
+                 "r" (at91_ramc_base[1]),
+                 "r" (at91_rstc_base),
+                 "r" (1),
+                 "r" (AT91_DDRSDRC_LPCB_POWER_DOWN),
+                 "r" (AT91_RSTC_KEY | AT91_RSTC_PERRST | AT91_RSTC_PROCRST)
+               : "r0");
+}
+
+static void __init at91_reset_status(struct platform_device *pdev)
+{
+       u32 reg = readl(at91_rstc_base + AT91_RSTC_SR);
+       char *reason;
+
+       switch ((reg & AT91_RSTC_RSTTYP) >> 8) {
+       case RESET_TYPE_GENERAL:
+               reason = "general reset";
+               break;
+       case RESET_TYPE_WAKEUP:
+               reason = "wakeup";
+               break;
+       case RESET_TYPE_WATCHDOG:
+               reason = "watchdog reset";
+               break;
+       case RESET_TYPE_SOFTWARE:
+               reason = "software reset";
+               break;
+       case RESET_TYPE_USER:
+               reason = "user reset";
+               break;
+       default:
+               reason = "unknown reset";
+               break;
+       }
+
+       pr_info("AT91: Starting after %s\n", reason);
+}
+
+static struct of_device_id at91_ramc_of_match[] = {
+       { .compatible = "atmel,at91sam9260-sdramc", },
+       { .compatible = "atmel,at91sam9g45-ddramc", },
+       { .compatible = "atmel,sama5d3-ddramc", },
+       { /* sentinel */ }
+};
+
+static struct of_device_id at91_reset_of_match[] = {
+       { .compatible = "atmel,at91sam9260-rstc", .data = at91sam9260_restart },
+       { .compatible = "atmel,at91sam9g45-rstc", .data = at91sam9g45_restart },
+       { /* sentinel */ }
+};
+
+static int at91_reset_of_probe(struct platform_device *pdev)
+{
+       const struct of_device_id *match;
+       struct device_node *np;
+       int idx = 0;
+
+       at91_rstc_base = of_iomap(pdev->dev.of_node, 0);
+       if (!at91_rstc_base) {
+               dev_err(&pdev->dev, "Could not map reset controller address\n");
+               return -ENODEV;
+       }
+
+       for_each_matching_node(np, at91_ramc_of_match) {
+               at91_ramc_base[idx] = of_iomap(np, 0);
+               if (!at91_ramc_base[idx]) {
+                       dev_err(&pdev->dev, "Could not map ram controller address\n");
+                       return -ENODEV;
+               }
+               idx++;
+       }
+
+       match = of_match_node(at91_reset_of_match, pdev->dev.of_node);
+       arm_pm_restart = match->data;
+
+       return 0;
+}
+
+static int at91_reset_platform_probe(struct platform_device *pdev)
+{
+       const struct platform_device_id *match;
+       struct resource *res;
+       int idx = 0;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       at91_rstc_base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(at91_rstc_base)) {
+               dev_err(&pdev->dev, "Could not map reset controller address\n");
+               return PTR_ERR(at91_rstc_base);
+       }
+
+       for (idx = 0; idx < 2; idx++) {
+               res = platform_get_resource(pdev, IORESOURCE_MEM, idx + 1 );
+               at91_ramc_base[idx] = devm_ioremap(&pdev->dev, res->start,
+                                                  resource_size(res));
+               if (IS_ERR(at91_ramc_base[idx])) {
+                       dev_err(&pdev->dev, "Could not map ram controller address\n");
+                       return PTR_ERR(at91_ramc_base[idx]);
+               }
+       }
+
+       match = platform_get_device_id(pdev);
+       arm_pm_restart = (void (*)(enum reboot_mode, const char*))
+               match->driver_data;
+
+       return 0;
+}
+
+static int at91_reset_probe(struct platform_device *pdev)
+{
+       int ret;
+
+       if (pdev->dev.of_node)
+               ret = at91_reset_of_probe(pdev);
+       else
+               ret = at91_reset_platform_probe(pdev);
+
+       if (ret)
+               return ret;
+
+       at91_reset_status(pdev);
+
+       return 0;
+}
+
+static struct platform_device_id at91_reset_plat_match[] = {
+       { "at91-sam9260-reset", (unsigned long)at91sam9260_restart },
+       { "at91-sam9g45-reset", (unsigned long)at91sam9g45_restart },
+       { /* sentinel */ }
+};
+
+static struct platform_driver at91_reset_driver = {
+       .probe = at91_reset_probe,
+       .driver = {
+               .name = "at91-reset",
+               .of_match_table = at91_reset_of_match,
+       },
+       .id_table = at91_reset_plat_match,
+};
+module_platform_driver(at91_reset_driver);
index fae9464eed9c500bd9932457db5f5df6f54ae056..1bea0fc43464f9dcc2ce3f94a87d3628590d6de5 100644 (file)
@@ -1175,9 +1175,16 @@ config RTC_DRV_SUN4V
          If you say Y here you will get support for the Hypervisor
          based RTC on SUN4V systems.
 
+config RTC_DRV_SUN6I
+       tristate "Allwinner A31 RTC"
+       depends on MACH_SUN6I || MACH_SUN8I
+       help
+         If you say Y here you will get support for the RTC found on
+         Allwinner A31.
+
 config RTC_DRV_SUNXI
        tristate "Allwinner sun4i/sun7i RTC"
-       depends on ARCH_SUNXI
+       depends on MACH_SUN4I || MACH_SUN7I
        help
          If you say Y here you will get support for the RTC found on
          Allwinner A10/A20.
index 56f061c7c815b9ad9a8ca1408484beccadf8a549..9055b7dd3dc5b93655088bd83f7911ca678e9d50 100644 (file)
@@ -128,6 +128,7 @@ obj-$(CONFIG_RTC_DRV_STARFIRE)      += rtc-starfire.o
 obj-$(CONFIG_RTC_DRV_STK17TA8) += rtc-stk17ta8.o
 obj-$(CONFIG_RTC_DRV_STMP)     += rtc-stmp3xxx.o
 obj-$(CONFIG_RTC_DRV_SUN4V)    += rtc-sun4v.o
+obj-$(CONFIG_RTC_DRV_SUN6I)    += rtc-sun6i.o
 obj-$(CONFIG_RTC_DRV_SUNXI)    += rtc-sunxi.o
 obj-$(CONFIG_RTC_DRV_TEGRA)    += rtc-tegra.o
 obj-$(CONFIG_RTC_DRV_TEST)     += rtc-test.o
diff --git a/drivers/rtc/rtc-sun6i.c b/drivers/rtc/rtc-sun6i.c
new file mode 100644 (file)
index 0000000..c169a2c
--- /dev/null
@@ -0,0 +1,447 @@
+/*
+ * An RTC driver for Allwinner A31/A23
+ *
+ * Copyright (c) 2014, Chen-Yu Tsai <wens@csie.org>
+ *
+ * based on rtc-sunxi.c
+ *
+ * An RTC driver for Allwinner A10/A20
+ *
+ * Copyright (c) 2013, Carlo Caione <carlo.caione@gmail.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/delay.h>
+#include <linux/err.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/rtc.h>
+#include <linux/types.h>
+
+/* Control register */
+#define SUN6I_LOSC_CTRL                                0x0000
+#define SUN6I_LOSC_CTRL_ALM_DHMS_ACC           BIT(9)
+#define SUN6I_LOSC_CTRL_RTC_HMS_ACC            BIT(8)
+#define SUN6I_LOSC_CTRL_RTC_YMD_ACC            BIT(7)
+#define SUN6I_LOSC_CTRL_ACC_MASK               GENMASK(9, 7)
+
+/* RTC */
+#define SUN6I_RTC_YMD                          0x0010
+#define SUN6I_RTC_HMS                          0x0014
+
+/* Alarm 0 (counter) */
+#define SUN6I_ALRM_COUNTER                     0x0020
+#define SUN6I_ALRM_CUR_VAL                     0x0024
+#define SUN6I_ALRM_EN                          0x0028
+#define SUN6I_ALRM_EN_CNT_EN                   BIT(0)
+#define SUN6I_ALRM_IRQ_EN                      0x002c
+#define SUN6I_ALRM_IRQ_EN_CNT_IRQ_EN           BIT(0)
+#define SUN6I_ALRM_IRQ_STA                     0x0030
+#define SUN6I_ALRM_IRQ_STA_CNT_IRQ_PEND                BIT(0)
+
+/* Alarm 1 (wall clock) */
+#define SUN6I_ALRM1_EN                         0x0044
+#define SUN6I_ALRM1_IRQ_EN                     0x0048
+#define SUN6I_ALRM1_IRQ_STA                    0x004c
+#define SUN6I_ALRM1_IRQ_STA_WEEK_IRQ_PEND      BIT(0)
+
+/* Alarm config */
+#define SUN6I_ALARM_CONFIG                     0x0050
+#define SUN6I_ALARM_CONFIG_WAKEUP              BIT(0)
+
+/*
+ * Get date values
+ */
+#define SUN6I_DATE_GET_DAY_VALUE(x)            ((x)  & 0x0000001f)
+#define SUN6I_DATE_GET_MON_VALUE(x)            (((x) & 0x00000f00) >> 8)
+#define SUN6I_DATE_GET_YEAR_VALUE(x)           (((x) & 0x003f0000) >> 16)
+#define SUN6I_LEAP_GET_VALUE(x)                        (((x) & 0x00400000) >> 22)
+
+/*
+ * Get time values
+ */
+#define SUN6I_TIME_GET_SEC_VALUE(x)            ((x)  & 0x0000003f)
+#define SUN6I_TIME_GET_MIN_VALUE(x)            (((x) & 0x00003f00) >> 8)
+#define SUN6I_TIME_GET_HOUR_VALUE(x)           (((x) & 0x001f0000) >> 16)
+
+/*
+ * Set date values
+ */
+#define SUN6I_DATE_SET_DAY_VALUE(x)            ((x)       & 0x0000001f)
+#define SUN6I_DATE_SET_MON_VALUE(x)            ((x) <<  8 & 0x00000f00)
+#define SUN6I_DATE_SET_YEAR_VALUE(x)           ((x) << 16 & 0x003f0000)
+#define SUN6I_LEAP_SET_VALUE(x)                        ((x) << 22 & 0x00400000)
+
+/*
+ * Set time values
+ */
+#define SUN6I_TIME_SET_SEC_VALUE(x)            ((x)       & 0x0000003f)
+#define SUN6I_TIME_SET_MIN_VALUE(x)            ((x) <<  8 & 0x00003f00)
+#define SUN6I_TIME_SET_HOUR_VALUE(x)           ((x) << 16 & 0x001f0000)
+
+/*
+ * The year parameter passed to the driver is usually an offset relative to
+ * the year 1900. This macro is used to convert this offset to another one
+ * relative to the minimum year allowed by the hardware.
+ *
+ * The year range is 1970 - 2033. This range is selected to match Allwinner's
+ * driver, even though it is somewhat limited.
+ */
+#define SUN6I_YEAR_MIN                         1970
+#define SUN6I_YEAR_MAX                         2033
+#define SUN6I_YEAR_OFF                         (SUN6I_YEAR_MIN - 1900)
+
+struct sun6i_rtc_dev {
+       struct rtc_device *rtc;
+       struct device *dev;
+       void __iomem *base;
+       int irq;
+       unsigned long alarm;
+};
+
+static irqreturn_t sun6i_rtc_alarmirq(int irq, void *id)
+{
+       struct sun6i_rtc_dev *chip = (struct sun6i_rtc_dev *) id;
+       u32 val;
+
+       val = readl(chip->base + SUN6I_ALRM_IRQ_STA);
+
+       if (val & SUN6I_ALRM_IRQ_STA_CNT_IRQ_PEND) {
+               val |= SUN6I_ALRM_IRQ_STA_CNT_IRQ_PEND;
+               writel(val, chip->base + SUN6I_ALRM_IRQ_STA);
+
+               rtc_update_irq(chip->rtc, 1, RTC_AF | RTC_IRQF);
+
+               return IRQ_HANDLED;
+       }
+
+       return IRQ_NONE;
+}
+
+static void sun6i_rtc_setaie(int to, struct sun6i_rtc_dev *chip)
+{
+       u32 alrm_val = 0;
+       u32 alrm_irq_val = 0;
+       u32 alrm_wake_val = 0;
+
+       if (to) {
+               alrm_val = SUN6I_ALRM_EN_CNT_EN;
+               alrm_irq_val = SUN6I_ALRM_IRQ_EN_CNT_IRQ_EN;
+               alrm_wake_val = SUN6I_ALARM_CONFIG_WAKEUP;
+       } else {
+               writel(SUN6I_ALRM_IRQ_STA_CNT_IRQ_PEND,
+                      chip->base + SUN6I_ALRM_IRQ_STA);
+       }
+
+       writel(alrm_val, chip->base + SUN6I_ALRM_EN);
+       writel(alrm_irq_val, chip->base + SUN6I_ALRM_IRQ_EN);
+       writel(alrm_wake_val, chip->base + SUN6I_ALARM_CONFIG);
+}
+
+static int sun6i_rtc_gettime(struct device *dev, struct rtc_time *rtc_tm)
+{
+       struct sun6i_rtc_dev *chip = dev_get_drvdata(dev);
+       u32 date, time;
+
+       /*
+        * read again in case it changes
+        */
+       do {
+               date = readl(chip->base + SUN6I_RTC_YMD);
+               time = readl(chip->base + SUN6I_RTC_HMS);
+       } while ((date != readl(chip->base + SUN6I_RTC_YMD)) ||
+                (time != readl(chip->base + SUN6I_RTC_HMS)));
+
+       rtc_tm->tm_sec  = SUN6I_TIME_GET_SEC_VALUE(time);
+       rtc_tm->tm_min  = SUN6I_TIME_GET_MIN_VALUE(time);
+       rtc_tm->tm_hour = SUN6I_TIME_GET_HOUR_VALUE(time);
+
+       rtc_tm->tm_mday = SUN6I_DATE_GET_DAY_VALUE(date);
+       rtc_tm->tm_mon  = SUN6I_DATE_GET_MON_VALUE(date);
+       rtc_tm->tm_year = SUN6I_DATE_GET_YEAR_VALUE(date);
+
+       rtc_tm->tm_mon  -= 1;
+
+       /*
+        * switch from (data_year->min)-relative offset to
+        * a (1900)-relative one
+        */
+       rtc_tm->tm_year += SUN6I_YEAR_OFF;
+
+       return rtc_valid_tm(rtc_tm);
+}
+
+static int sun6i_rtc_getalarm(struct device *dev, struct rtc_wkalrm *wkalrm)
+{
+       struct sun6i_rtc_dev *chip = dev_get_drvdata(dev);
+       u32 alrm_st;
+       u32 alrm_en;
+
+       alrm_en = readl(chip->base + SUN6I_ALRM_IRQ_EN);
+       alrm_st = readl(chip->base + SUN6I_ALRM_IRQ_STA);
+       wkalrm->enabled = !!(alrm_en & SUN6I_ALRM_EN_CNT_EN);
+       wkalrm->pending = !!(alrm_st & SUN6I_ALRM_EN_CNT_EN);
+       rtc_time_to_tm(chip->alarm, &wkalrm->time);
+
+       return 0;
+}
+
+static int sun6i_rtc_setalarm(struct device *dev, struct rtc_wkalrm *wkalrm)
+{
+       struct sun6i_rtc_dev *chip = dev_get_drvdata(dev);
+       struct rtc_time *alrm_tm = &wkalrm->time;
+       struct rtc_time tm_now;
+       unsigned long time_now = 0;
+       unsigned long time_set = 0;
+       unsigned long time_gap = 0;
+       int ret = 0;
+
+       ret = sun6i_rtc_gettime(dev, &tm_now);
+       if (ret < 0) {
+               dev_err(dev, "Error in getting time\n");
+               return -EINVAL;
+       }
+
+       rtc_tm_to_time(alrm_tm, &time_set);
+       rtc_tm_to_time(&tm_now, &time_now);
+       if (time_set <= time_now) {
+               dev_err(dev, "Date to set in the past\n");
+               return -EINVAL;
+       }
+
+       time_gap = time_set - time_now;
+
+       if (time_gap > U32_MAX) {
+               dev_err(dev, "Date too far in the future\n");
+               return -EINVAL;
+       }
+
+       sun6i_rtc_setaie(0, chip);
+       writel(0, chip->base + SUN6I_ALRM_COUNTER);
+       usleep_range(100, 300);
+
+       writel(time_gap, chip->base + SUN6I_ALRM_COUNTER);
+       chip->alarm = time_set;
+
+       sun6i_rtc_setaie(wkalrm->enabled, chip);
+
+       return 0;
+}
+
+static int sun6i_rtc_wait(struct sun6i_rtc_dev *chip, int offset,
+                         unsigned int mask, unsigned int ms_timeout)
+{
+       const unsigned long timeout = jiffies + msecs_to_jiffies(ms_timeout);
+       u32 reg;
+
+       do {
+               reg = readl(chip->base + offset);
+               reg &= mask;
+
+               if (!reg)
+                       return 0;
+
+       } while (time_before(jiffies, timeout));
+
+       return -ETIMEDOUT;
+}
+
+static int sun6i_rtc_settime(struct device *dev, struct rtc_time *rtc_tm)
+{
+       struct sun6i_rtc_dev *chip = dev_get_drvdata(dev);
+       u32 date = 0;
+       u32 time = 0;
+       int year;
+
+       year = rtc_tm->tm_year + 1900;
+       if (year < SUN6I_YEAR_MIN || year > SUN6I_YEAR_MAX) {
+               dev_err(dev, "rtc only supports year in range %d - %d\n",
+                       SUN6I_YEAR_MIN, SUN6I_YEAR_MAX);
+               return -EINVAL;
+       }
+
+       rtc_tm->tm_year -= SUN6I_YEAR_OFF;
+       rtc_tm->tm_mon += 1;
+
+       date = SUN6I_DATE_SET_DAY_VALUE(rtc_tm->tm_mday) |
+               SUN6I_DATE_SET_MON_VALUE(rtc_tm->tm_mon)  |
+               SUN6I_DATE_SET_YEAR_VALUE(rtc_tm->tm_year);
+
+       if (is_leap_year(year))
+               date |= SUN6I_LEAP_SET_VALUE(1);
+
+       time = SUN6I_TIME_SET_SEC_VALUE(rtc_tm->tm_sec)  |
+               SUN6I_TIME_SET_MIN_VALUE(rtc_tm->tm_min)  |
+               SUN6I_TIME_SET_HOUR_VALUE(rtc_tm->tm_hour);
+
+       /* Check whether registers are writable */
+       if (sun6i_rtc_wait(chip, SUN6I_LOSC_CTRL,
+                          SUN6I_LOSC_CTRL_ACC_MASK, 50)) {
+               dev_err(dev, "rtc is still busy.\n");
+               return -EBUSY;
+       }
+
+       writel(time, chip->base + SUN6I_RTC_HMS);
+
+       /*
+        * After writing the RTC HH-MM-SS register, the
+        * SUN6I_LOSC_CTRL_RTC_HMS_ACC bit is set and it will not
+        * be cleared until the real writing operation is finished
+        */
+
+       if (sun6i_rtc_wait(chip, SUN6I_LOSC_CTRL,
+                          SUN6I_LOSC_CTRL_RTC_HMS_ACC, 50)) {
+               dev_err(dev, "Failed to set rtc time.\n");
+               return -ETIMEDOUT;
+       }
+
+       writel(date, chip->base + SUN6I_RTC_YMD);
+
+       /*
+        * After writing the RTC YY-MM-DD register, the
+        * SUN6I_LOSC_CTRL_RTC_YMD_ACC bit is set and it will not
+        * be cleared until the real writing operation is finished
+        */
+
+       if (sun6i_rtc_wait(chip, SUN6I_LOSC_CTRL,
+                          SUN6I_LOSC_CTRL_RTC_YMD_ACC, 50)) {
+               dev_err(dev, "Failed to set rtc time.\n");
+               return -ETIMEDOUT;
+       }
+
+       return 0;
+}
+
+static int sun6i_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
+{
+       struct sun6i_rtc_dev *chip = dev_get_drvdata(dev);
+
+       if (!enabled)
+               sun6i_rtc_setaie(enabled, chip);
+
+       return 0;
+}
+
+static const struct rtc_class_ops sun6i_rtc_ops = {
+       .read_time              = sun6i_rtc_gettime,
+       .set_time               = sun6i_rtc_settime,
+       .read_alarm             = sun6i_rtc_getalarm,
+       .set_alarm              = sun6i_rtc_setalarm,
+       .alarm_irq_enable       = sun6i_rtc_alarm_irq_enable
+};
+
+static int sun6i_rtc_probe(struct platform_device *pdev)
+{
+       struct sun6i_rtc_dev *chip;
+       struct resource *res;
+       int ret;
+
+       chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL);
+       if (!chip)
+               return -ENOMEM;
+
+       platform_set_drvdata(pdev, chip);
+       chip->dev = &pdev->dev;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       chip->base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(chip->base))
+               return PTR_ERR(chip->base);
+
+       chip->irq = platform_get_irq(pdev, 0);
+       if (chip->irq < 0) {
+               dev_err(&pdev->dev, "No IRQ resource\n");
+               return chip->irq;
+       }
+
+       ret = devm_request_irq(&pdev->dev, chip->irq, sun6i_rtc_alarmirq,
+                              0, dev_name(&pdev->dev), chip);
+       if (ret) {
+               dev_err(&pdev->dev, "Could not request IRQ\n");
+               return ret;
+       }
+
+       /* clear the alarm counter value */
+       writel(0, chip->base + SUN6I_ALRM_COUNTER);
+
+       /* disable counter alarm */
+       writel(0, chip->base + SUN6I_ALRM_EN);
+
+       /* disable counter alarm interrupt */
+       writel(0, chip->base + SUN6I_ALRM_IRQ_EN);
+
+       /* disable week alarm */
+       writel(0, chip->base + SUN6I_ALRM1_EN);
+
+       /* disable week alarm interrupt */
+       writel(0, chip->base + SUN6I_ALRM1_IRQ_EN);
+
+       /* clear counter alarm pending interrupts */
+       writel(SUN6I_ALRM_IRQ_STA_CNT_IRQ_PEND,
+              chip->base + SUN6I_ALRM_IRQ_STA);
+
+       /* clear week alarm pending interrupts */
+       writel(SUN6I_ALRM1_IRQ_STA_WEEK_IRQ_PEND,
+              chip->base + SUN6I_ALRM1_IRQ_STA);
+
+       /* disable alarm wakeup */
+       writel(0, chip->base + SUN6I_ALARM_CONFIG);
+
+       chip->rtc = rtc_device_register("rtc-sun6i", &pdev->dev,
+                                       &sun6i_rtc_ops, THIS_MODULE);
+       if (IS_ERR(chip->rtc)) {
+               dev_err(&pdev->dev, "unable to register device\n");
+               return PTR_ERR(chip->rtc);
+       }
+
+       dev_info(&pdev->dev, "RTC enabled\n");
+
+       return 0;
+}
+
+static int sun6i_rtc_remove(struct platform_device *pdev)
+{
+       struct sun6i_rtc_dev *chip = platform_get_drvdata(pdev);
+
+       rtc_device_unregister(chip->rtc);
+
+       return 0;
+}
+
+static const struct of_device_id sun6i_rtc_dt_ids[] = {
+       { .compatible = "allwinner,sun6i-a31-rtc" },
+       { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, sun6i_rtc_dt_ids);
+
+static struct platform_driver sun6i_rtc_driver = {
+       .probe          = sun6i_rtc_probe,
+       .remove         = sun6i_rtc_remove,
+       .driver         = {
+               .name           = "sun6i-rtc",
+               .of_match_table = sun6i_rtc_dt_ids,
+       },
+};
+
+module_platform_driver(sun6i_rtc_driver);
+
+MODULE_DESCRIPTION("sun6i RTC driver");
+MODULE_AUTHOR("Chen-Yu Tsai <wens@csie.org>");
+MODULE_LICENSE("GPL");
index c8543855aa8253969f5c05c528683a7ea633e790..76d6bd4da138f1162fc8a7dcc516b54d4f26b26b 100644 (file)
@@ -1,5 +1,7 @@
 menu "SOC (System On Chip) specific Drivers"
 
 source "drivers/soc/qcom/Kconfig"
+source "drivers/soc/ti/Kconfig"
+source "drivers/soc/versatile/Kconfig"
 
 endmenu
index 3b1b95d932d194e0533944ed4f0d021d405c24a3..063113d0bd3871b131caec6ea902cef2f283209e 100644 (file)
@@ -4,3 +4,5 @@
 
 obj-$(CONFIG_ARCH_QCOM)                += qcom/
 obj-$(CONFIG_ARCH_TEGRA)       += tegra/
+obj-$(CONFIG_SOC_TI)           += ti/
+obj-$(CONFIG_PLAT_VERSATILE)   += versatile/
diff --git a/drivers/soc/ti/Kconfig b/drivers/soc/ti/Kconfig
new file mode 100644 (file)
index 0000000..7266b21
--- /dev/null
@@ -0,0 +1,31 @@
+#
+# TI SOC drivers
+#
+menuconfig SOC_TI
+       bool "TI SOC drivers support"
+
+if SOC_TI
+
+config KEYSTONE_NAVIGATOR_QMSS
+       tristate "Keystone Queue Manager Sub System"
+       depends on ARCH_KEYSTONE
+       help
+         Say y here to support the Keystone multicore Navigator Queue
+         Manager support. The Queue Manager is a hardware module that
+         is responsible for accelerating management of the packet queues.
+         Packets are queued/de-queued by writing/reading descriptor address
+         to a particular memory mapped location in the Queue Manager module.
+
+         If unsure, say N.
+
+config KEYSTONE_NAVIGATOR_DMA
+       tristate "TI Keystone Navigator Packet DMA support"
+       depends on ARCH_KEYSTONE
+       help
+         Say y tp enable support for the Keystone Navigator Packet DMA on
+         on Keystone family of devices. It sets up the dma channels for the
+         Queue Manager Sub System.
+
+         If unsure, say N.
+
+endif # SOC_TI
diff --git a/drivers/soc/ti/Makefile b/drivers/soc/ti/Makefile
new file mode 100644 (file)
index 0000000..6bed611
--- /dev/null
@@ -0,0 +1,5 @@
+#
+# TI Keystone SOC drivers
+#
+obj-$(CONFIG_KEYSTONE_NAVIGATOR_QMSS)  += knav_qmss_queue.o knav_qmss_acc.o
+obj-$(CONFIG_KEYSTONE_NAVIGATOR_DMA)   += knav_dma.o
diff --git a/drivers/soc/ti/knav_dma.c b/drivers/soc/ti/knav_dma.c
new file mode 100644 (file)
index 0000000..1726427
--- /dev/null
@@ -0,0 +1,815 @@
+/*
+ * Copyright (C) 2014 Texas Instruments Incorporated
+ * Authors:    Santosh Shilimkar <santosh.shilimkar@ti.com>
+ *             Sandeep Nair <sandeep_n@ti.com>
+ *             Cyril Chemparathy <cyril@ti.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 version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/io.h>
+#include <linux/sched.h>
+#include <linux/module.h>
+#include <linux/dma-direction.h>
+#include <linux/interrupt.h>
+#include <linux/pm_runtime.h>
+#include <linux/of_dma.h>
+#include <linux/of_address.h>
+#include <linux/platform_device.h>
+#include <linux/soc/ti/knav_dma.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+
+#define REG_MASK               0xffffffff
+
+#define DMA_LOOPBACK           BIT(31)
+#define DMA_ENABLE             BIT(31)
+#define DMA_TEARDOWN           BIT(30)
+
+#define DMA_TX_FILT_PSWORDS    BIT(29)
+#define DMA_TX_FILT_EINFO      BIT(30)
+#define DMA_TX_PRIO_SHIFT      0
+#define DMA_RX_PRIO_SHIFT      16
+#define DMA_PRIO_MASK          GENMASK(3, 0)
+#define DMA_PRIO_DEFAULT       0
+#define DMA_RX_TIMEOUT_DEFAULT 17500 /* cycles */
+#define DMA_RX_TIMEOUT_MASK    GENMASK(16, 0)
+#define DMA_RX_TIMEOUT_SHIFT   0
+
+#define CHAN_HAS_EPIB          BIT(30)
+#define CHAN_HAS_PSINFO                BIT(29)
+#define CHAN_ERR_RETRY         BIT(28)
+#define CHAN_PSINFO_AT_SOP     BIT(25)
+#define CHAN_SOP_OFF_SHIFT     16
+#define CHAN_SOP_OFF_MASK      GENMASK(9, 0)
+#define DESC_TYPE_SHIFT                26
+#define DESC_TYPE_MASK         GENMASK(2, 0)
+
+/*
+ * QMGR & QNUM together make up 14 bits with QMGR as the 2 MSb's in the logical
+ * navigator cloud mapping scheme.
+ * using the 14bit physical queue numbers directly maps into this scheme.
+ */
+#define CHAN_QNUM_MASK         GENMASK(14, 0)
+#define DMA_MAX_QMS            4
+#define DMA_TIMEOUT            1       /* msecs */
+#define DMA_INVALID_ID         0xffff
+
+struct reg_global {
+       u32     revision;
+       u32     perf_control;
+       u32     emulation_control;
+       u32     priority_control;
+       u32     qm_base_address[DMA_MAX_QMS];
+};
+
+struct reg_chan {
+       u32     control;
+       u32     mode;
+       u32     __rsvd[6];
+};
+
+struct reg_tx_sched {
+       u32     prio;
+};
+
+struct reg_rx_flow {
+       u32     control;
+       u32     tags;
+       u32     tag_sel;
+       u32     fdq_sel[2];
+       u32     thresh[3];
+};
+
+struct knav_dma_pool_device {
+       struct device                   *dev;
+       struct list_head                list;
+};
+
+struct knav_dma_device {
+       bool                            loopback, enable_all;
+       unsigned                        tx_priority, rx_priority, rx_timeout;
+       unsigned                        logical_queue_managers;
+       unsigned                        qm_base_address[DMA_MAX_QMS];
+       struct reg_global __iomem       *reg_global;
+       struct reg_chan __iomem         *reg_tx_chan;
+       struct reg_rx_flow __iomem      *reg_rx_flow;
+       struct reg_chan __iomem         *reg_rx_chan;
+       struct reg_tx_sched __iomem     *reg_tx_sched;
+       unsigned                        max_rx_chan, max_tx_chan;
+       unsigned                        max_rx_flow;
+       char                            name[32];
+       atomic_t                        ref_count;
+       struct list_head                list;
+       struct list_head                chan_list;
+       spinlock_t                      lock;
+};
+
+struct knav_dma_chan {
+       enum dma_transfer_direction     direction;
+       struct knav_dma_device          *dma;
+       atomic_t                        ref_count;
+
+       /* registers */
+       struct reg_chan __iomem         *reg_chan;
+       struct reg_tx_sched __iomem     *reg_tx_sched;
+       struct reg_rx_flow __iomem      *reg_rx_flow;
+
+       /* configuration stuff */
+       unsigned                        channel, flow;
+       struct knav_dma_cfg             cfg;
+       struct list_head                list;
+       spinlock_t                      lock;
+};
+
+#define chan_number(ch)        ((ch->direction == DMA_MEM_TO_DEV) ? \
+                       ch->channel : ch->flow)
+
+static struct knav_dma_pool_device *kdev;
+
+static bool check_config(struct knav_dma_chan *chan, struct knav_dma_cfg *cfg)
+{
+       if (!memcmp(&chan->cfg, cfg, sizeof(*cfg)))
+               return true;
+       else
+               return false;
+}
+
+static int chan_start(struct knav_dma_chan *chan,
+                       struct knav_dma_cfg *cfg)
+{
+       u32 v = 0;
+
+       spin_lock(&chan->lock);
+       if ((chan->direction == DMA_MEM_TO_DEV) && chan->reg_chan) {
+               if (cfg->u.tx.filt_pswords)
+                       v |= DMA_TX_FILT_PSWORDS;
+               if (cfg->u.tx.filt_einfo)
+                       v |= DMA_TX_FILT_EINFO;
+               writel_relaxed(v, &chan->reg_chan->mode);
+               writel_relaxed(DMA_ENABLE, &chan->reg_chan->control);
+       }
+
+       if (chan->reg_tx_sched)
+               writel_relaxed(cfg->u.tx.priority, &chan->reg_tx_sched->prio);
+
+       if (chan->reg_rx_flow) {
+               v = 0;
+
+               if (cfg->u.rx.einfo_present)
+                       v |= CHAN_HAS_EPIB;
+               if (cfg->u.rx.psinfo_present)
+                       v |= CHAN_HAS_PSINFO;
+               if (cfg->u.rx.err_mode == DMA_RETRY)
+                       v |= CHAN_ERR_RETRY;
+               v |= (cfg->u.rx.desc_type & DESC_TYPE_MASK) << DESC_TYPE_SHIFT;
+               if (cfg->u.rx.psinfo_at_sop)
+                       v |= CHAN_PSINFO_AT_SOP;
+               v |= (cfg->u.rx.sop_offset & CHAN_SOP_OFF_MASK)
+                       << CHAN_SOP_OFF_SHIFT;
+               v |= cfg->u.rx.dst_q & CHAN_QNUM_MASK;
+
+               writel_relaxed(v, &chan->reg_rx_flow->control);
+               writel_relaxed(0, &chan->reg_rx_flow->tags);
+               writel_relaxed(0, &chan->reg_rx_flow->tag_sel);
+
+               v =  cfg->u.rx.fdq[0] << 16;
+               v |=  cfg->u.rx.fdq[1] & CHAN_QNUM_MASK;
+               writel_relaxed(v, &chan->reg_rx_flow->fdq_sel[0]);
+
+               v =  cfg->u.rx.fdq[2] << 16;
+               v |=  cfg->u.rx.fdq[3] & CHAN_QNUM_MASK;
+               writel_relaxed(v, &chan->reg_rx_flow->fdq_sel[1]);
+
+               writel_relaxed(0, &chan->reg_rx_flow->thresh[0]);
+               writel_relaxed(0, &chan->reg_rx_flow->thresh[1]);
+               writel_relaxed(0, &chan->reg_rx_flow->thresh[2]);
+       }
+
+       /* Keep a copy of the cfg */
+       memcpy(&chan->cfg, cfg, sizeof(*cfg));
+       spin_unlock(&chan->lock);
+
+       return 0;
+}
+
+static int chan_teardown(struct knav_dma_chan *chan)
+{
+       unsigned long end, value;
+
+       if (!chan->reg_chan)
+               return 0;
+
+       /* indicate teardown */
+       writel_relaxed(DMA_TEARDOWN, &chan->reg_chan->control);
+
+       /* wait for the dma to shut itself down */
+       end = jiffies + msecs_to_jiffies(DMA_TIMEOUT);
+       do {
+               value = readl_relaxed(&chan->reg_chan->control);
+               if ((value & DMA_ENABLE) == 0)
+                       break;
+       } while (time_after(end, jiffies));
+
+       if (readl_relaxed(&chan->reg_chan->control) & DMA_ENABLE) {
+               dev_err(kdev->dev, "timeout waiting for teardown\n");
+               return -ETIMEDOUT;
+       }
+
+       return 0;
+}
+
+static void chan_stop(struct knav_dma_chan *chan)
+{
+       spin_lock(&chan->lock);
+       if (chan->reg_rx_flow) {
+               /* first detach fdqs, starve out the flow */
+               writel_relaxed(0, &chan->reg_rx_flow->fdq_sel[0]);
+               writel_relaxed(0, &chan->reg_rx_flow->fdq_sel[1]);
+               writel_relaxed(0, &chan->reg_rx_flow->thresh[0]);
+               writel_relaxed(0, &chan->reg_rx_flow->thresh[1]);
+               writel_relaxed(0, &chan->reg_rx_flow->thresh[2]);
+       }
+
+       /* teardown the dma channel */
+       chan_teardown(chan);
+
+       /* then disconnect the completion side */
+       if (chan->reg_rx_flow) {
+               writel_relaxed(0, &chan->reg_rx_flow->control);
+               writel_relaxed(0, &chan->reg_rx_flow->tags);
+               writel_relaxed(0, &chan->reg_rx_flow->tag_sel);
+       }
+
+       memset(&chan->cfg, 0, sizeof(struct knav_dma_cfg));
+       spin_unlock(&chan->lock);
+
+       dev_dbg(kdev->dev, "channel stopped\n");
+}
+
+static void dma_hw_enable_all(struct knav_dma_device *dma)
+{
+       int i;
+
+       for (i = 0; i < dma->max_tx_chan; i++) {
+               writel_relaxed(0, &dma->reg_tx_chan[i].mode);
+               writel_relaxed(DMA_ENABLE, &dma->reg_tx_chan[i].control);
+       }
+}
+
+
+static void knav_dma_hw_init(struct knav_dma_device *dma)
+{
+       unsigned v;
+       int i;
+
+       spin_lock(&dma->lock);
+       v  = dma->loopback ? DMA_LOOPBACK : 0;
+       writel_relaxed(v, &dma->reg_global->emulation_control);
+
+       v = readl_relaxed(&dma->reg_global->perf_control);
+       v |= ((dma->rx_timeout & DMA_RX_TIMEOUT_MASK) << DMA_RX_TIMEOUT_SHIFT);
+       writel_relaxed(v, &dma->reg_global->perf_control);
+
+       v = ((dma->tx_priority << DMA_TX_PRIO_SHIFT) |
+            (dma->rx_priority << DMA_RX_PRIO_SHIFT));
+
+       writel_relaxed(v, &dma->reg_global->priority_control);
+
+       /* Always enable all Rx channels. Rx paths are managed using flows */
+       for (i = 0; i < dma->max_rx_chan; i++)
+               writel_relaxed(DMA_ENABLE, &dma->reg_rx_chan[i].control);
+
+       for (i = 0; i < dma->logical_queue_managers; i++)
+               writel_relaxed(dma->qm_base_address[i],
+                              &dma->reg_global->qm_base_address[i]);
+       spin_unlock(&dma->lock);
+}
+
+static void knav_dma_hw_destroy(struct knav_dma_device *dma)
+{
+       int i;
+       unsigned v;
+
+       spin_lock(&dma->lock);
+       v = ~DMA_ENABLE & REG_MASK;
+
+       for (i = 0; i < dma->max_rx_chan; i++)
+               writel_relaxed(v, &dma->reg_rx_chan[i].control);
+
+       for (i = 0; i < dma->max_tx_chan; i++)
+               writel_relaxed(v, &dma->reg_tx_chan[i].control);
+       spin_unlock(&dma->lock);
+}
+
+static void dma_debug_show_channels(struct seq_file *s,
+                                       struct knav_dma_chan *chan)
+{
+       int i;
+
+       seq_printf(s, "\t%s %d:\t",
+               ((chan->direction == DMA_MEM_TO_DEV) ? "tx chan" : "rx flow"),
+               chan_number(chan));
+
+       if (chan->direction == DMA_MEM_TO_DEV) {
+               seq_printf(s, "einfo - %d, pswords - %d, priority - %d\n",
+                       chan->cfg.u.tx.filt_einfo,
+                       chan->cfg.u.tx.filt_pswords,
+                       chan->cfg.u.tx.priority);
+       } else {
+               seq_printf(s, "einfo - %d, psinfo - %d, desc_type - %d\n",
+                       chan->cfg.u.rx.einfo_present,
+                       chan->cfg.u.rx.psinfo_present,
+                       chan->cfg.u.rx.desc_type);
+               seq_printf(s, "\t\t\tdst_q: [%d], thresh: %d fdq: ",
+                       chan->cfg.u.rx.dst_q,
+                       chan->cfg.u.rx.thresh);
+               for (i = 0; i < KNAV_DMA_FDQ_PER_CHAN; i++)
+                       seq_printf(s, "[%d]", chan->cfg.u.rx.fdq[i]);
+               seq_printf(s, "\n");
+       }
+}
+
+static void dma_debug_show_devices(struct seq_file *s,
+                                       struct knav_dma_device *dma)
+{
+       struct knav_dma_chan *chan;
+
+       list_for_each_entry(chan, &dma->chan_list, list) {
+               if (atomic_read(&chan->ref_count))
+                       dma_debug_show_channels(s, chan);
+       }
+}
+
+static int dma_debug_show(struct seq_file *s, void *v)
+{
+       struct knav_dma_device *dma;
+
+       list_for_each_entry(dma, &kdev->list, list) {
+               if (atomic_read(&dma->ref_count)) {
+                       seq_printf(s, "%s : max_tx_chan: (%d), max_rx_flows: (%d)\n",
+                       dma->name, dma->max_tx_chan, dma->max_rx_flow);
+                       dma_debug_show_devices(s, dma);
+               }
+       }
+
+       return 0;
+}
+
+static int knav_dma_debug_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, dma_debug_show, NULL);
+}
+
+static const struct file_operations knav_dma_debug_ops = {
+       .open           = knav_dma_debug_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
+static int of_channel_match_helper(struct device_node *np, const char *name,
+                                       const char **dma_instance)
+{
+       struct of_phandle_args args;
+       struct device_node *dma_node;
+       int index;
+
+       dma_node = of_parse_phandle(np, "ti,navigator-dmas", 0);
+       if (!dma_node)
+               return -ENODEV;
+
+       *dma_instance = dma_node->name;
+       index = of_property_match_string(np, "ti,navigator-dma-names", name);
+       if (index < 0) {
+               dev_err(kdev->dev, "No 'ti,navigator-dma-names' propery\n");
+               return -ENODEV;
+       }
+
+       if (of_parse_phandle_with_fixed_args(np, "ti,navigator-dmas",
+                                       1, index, &args)) {
+               dev_err(kdev->dev, "Missing the pahndle args name %s\n", name);
+               return -ENODEV;
+       }
+
+       if (args.args[0] < 0) {
+               dev_err(kdev->dev, "Missing args for %s\n", name);
+               return -ENODEV;
+       }
+
+       return args.args[0];
+}
+
+/**
+ * knav_dma_open_channel() - try to setup an exclusive slave channel
+ * @dev:       pointer to client device structure
+ * @name:      slave channel name
+ * @config:    dma configuration parameters
+ *
+ * Returns pointer to appropriate DMA channel on success or NULL.
+ */
+void *knav_dma_open_channel(struct device *dev, const char *name,
+                                       struct knav_dma_cfg *config)
+{
+       struct knav_dma_chan *chan;
+       struct knav_dma_device *dma;
+       bool found = false;
+       int chan_num = -1;
+       const char *instance;
+
+       if (!kdev) {
+               pr_err("keystone-navigator-dma driver not registered\n");
+               return (void *)-EINVAL;
+       }
+
+       chan_num = of_channel_match_helper(dev->of_node, name, &instance);
+       if (chan_num < 0) {
+               dev_err(kdev->dev, "No DMA instace with name %s\n", name);
+               return (void *)-EINVAL;
+       }
+
+       dev_dbg(kdev->dev, "initializing %s channel %d from DMA %s\n",
+                 config->direction == DMA_MEM_TO_DEV   ? "transmit" :
+                 config->direction == DMA_DEV_TO_MEM ? "receive"  :
+                 "unknown", chan_num, instance);
+
+       if (config->direction != DMA_MEM_TO_DEV &&
+           config->direction != DMA_DEV_TO_MEM) {
+               dev_err(kdev->dev, "bad direction\n");
+               return (void *)-EINVAL;
+       }
+
+       /* Look for correct dma instance */
+       list_for_each_entry(dma, &kdev->list, list) {
+               if (!strcmp(dma->name, instance)) {
+                       found = true;
+                       break;
+               }
+       }
+       if (!found) {
+               dev_err(kdev->dev, "No DMA instace with name %s\n", instance);
+               return (void *)-EINVAL;
+       }
+
+       /* Look for correct dma channel from dma instance */
+       found = false;
+       list_for_each_entry(chan, &dma->chan_list, list) {
+               if (config->direction == DMA_MEM_TO_DEV) {
+                       if (chan->channel == chan_num) {
+                               found = true;
+                               break;
+                       }
+               } else {
+                       if (chan->flow == chan_num) {
+                               found = true;
+                               break;
+                       }
+               }
+       }
+       if (!found) {
+               dev_err(kdev->dev, "channel %d is not in DMA %s\n",
+                               chan_num, instance);
+               return (void *)-EINVAL;
+       }
+
+       if (atomic_read(&chan->ref_count) >= 1) {
+               if (!check_config(chan, config)) {
+                       dev_err(kdev->dev, "channel %d config miss-match\n",
+                               chan_num);
+                       return (void *)-EINVAL;
+               }
+       }
+
+       if (atomic_inc_return(&chan->dma->ref_count) <= 1)
+               knav_dma_hw_init(chan->dma);
+
+       if (atomic_inc_return(&chan->ref_count) <= 1)
+               chan_start(chan, config);
+
+       dev_dbg(kdev->dev, "channel %d opened from DMA %s\n",
+                               chan_num, instance);
+
+       return chan;
+}
+EXPORT_SYMBOL_GPL(knav_dma_open_channel);
+
+/**
+ * knav_dma_close_channel()    - Destroy a dma channel
+ *
+ * channel:    dma channel handle
+ *
+ */
+void knav_dma_close_channel(void *channel)
+{
+       struct knav_dma_chan *chan = channel;
+
+       if (!kdev) {
+               pr_err("keystone-navigator-dma driver not registered\n");
+               return;
+       }
+
+       if (atomic_dec_return(&chan->ref_count) <= 0)
+               chan_stop(chan);
+
+       if (atomic_dec_return(&chan->dma->ref_count) <= 0)
+               knav_dma_hw_destroy(chan->dma);
+
+       dev_dbg(kdev->dev, "channel %d or flow %d closed from DMA %s\n",
+                       chan->channel, chan->flow, chan->dma->name);
+}
+EXPORT_SYMBOL_GPL(knav_dma_close_channel);
+
+static void __iomem *pktdma_get_regs(struct knav_dma_device *dma,
+                               struct device_node *node,
+                               unsigned index, resource_size_t *_size)
+{
+       struct device *dev = kdev->dev;
+       struct resource res;
+       void __iomem *regs;
+       int ret;
+
+       ret = of_address_to_resource(node, index, &res);
+       if (ret) {
+               dev_err(dev, "Can't translate of node(%s) address for index(%d)\n",
+                       node->name, index);
+               return ERR_PTR(ret);
+       }
+
+       regs = devm_ioremap_resource(kdev->dev, &res);
+       if (IS_ERR(regs))
+               dev_err(dev, "Failed to map register base for index(%d) node(%s)\n",
+                       index, node->name);
+       if (_size)
+               *_size = resource_size(&res);
+
+       return regs;
+}
+
+static int pktdma_init_rx_chan(struct knav_dma_chan *chan, u32 flow)
+{
+       struct knav_dma_device *dma = chan->dma;
+
+       chan->flow = flow;
+       chan->reg_rx_flow = dma->reg_rx_flow + flow;
+       chan->channel = DMA_INVALID_ID;
+       dev_dbg(kdev->dev, "rx flow(%d) (%p)\n", chan->flow, chan->reg_rx_flow);
+
+       return 0;
+}
+
+static int pktdma_init_tx_chan(struct knav_dma_chan *chan, u32 channel)
+{
+       struct knav_dma_device *dma = chan->dma;
+
+       chan->channel = channel;
+       chan->reg_chan = dma->reg_tx_chan + channel;
+       chan->reg_tx_sched = dma->reg_tx_sched + channel;
+       chan->flow = DMA_INVALID_ID;
+       dev_dbg(kdev->dev, "tx channel(%d) (%p)\n", chan->channel, chan->reg_chan);
+
+       return 0;
+}
+
+static int pktdma_init_chan(struct knav_dma_device *dma,
+                               enum dma_transfer_direction dir,
+                               unsigned chan_num)
+{
+       struct device *dev = kdev->dev;
+       struct knav_dma_chan *chan;
+       int ret = -EINVAL;
+
+       chan = devm_kzalloc(dev, sizeof(*chan), GFP_KERNEL);
+       if (!chan)
+               return -ENOMEM;
+
+       INIT_LIST_HEAD(&chan->list);
+       chan->dma       = dma;
+       chan->direction = DMA_NONE;
+       atomic_set(&chan->ref_count, 0);
+       spin_lock_init(&chan->lock);
+
+       if (dir == DMA_MEM_TO_DEV) {
+               chan->direction = dir;
+               ret = pktdma_init_tx_chan(chan, chan_num);
+       } else if (dir == DMA_DEV_TO_MEM) {
+               chan->direction = dir;
+               ret = pktdma_init_rx_chan(chan, chan_num);
+       } else {
+               dev_err(dev, "channel(%d) direction unknown\n", chan_num);
+       }
+
+       list_add_tail(&chan->list, &dma->chan_list);
+
+       return ret;
+}
+
+static int dma_init(struct device_node *cloud, struct device_node *dma_node)
+{
+       unsigned max_tx_chan, max_rx_chan, max_rx_flow, max_tx_sched;
+       struct device_node *node = dma_node;
+       struct knav_dma_device *dma;
+       int ret, len, num_chan = 0;
+       resource_size_t size;
+       u32 timeout;
+       u32 i;
+
+       dma = devm_kzalloc(kdev->dev, sizeof(*dma), GFP_KERNEL);
+       if (!dma) {
+               dev_err(kdev->dev, "could not allocate driver mem\n");
+               return -ENOMEM;
+       }
+       INIT_LIST_HEAD(&dma->list);
+       INIT_LIST_HEAD(&dma->chan_list);
+
+       if (!of_find_property(cloud, "ti,navigator-cloud-address", &len)) {
+               dev_err(kdev->dev, "unspecified navigator cloud addresses\n");
+               return -ENODEV;
+       }
+
+       dma->logical_queue_managers = len / sizeof(u32);
+       if (dma->logical_queue_managers > DMA_MAX_QMS) {
+               dev_warn(kdev->dev, "too many queue mgrs(>%d) rest ignored\n",
+                        dma->logical_queue_managers);
+               dma->logical_queue_managers = DMA_MAX_QMS;
+       }
+
+       ret = of_property_read_u32_array(cloud, "ti,navigator-cloud-address",
+                                       dma->qm_base_address,
+                                       dma->logical_queue_managers);
+       if (ret) {
+               dev_err(kdev->dev, "invalid navigator cloud addresses\n");
+               return -ENODEV;
+       }
+
+       dma->reg_global  = pktdma_get_regs(dma, node, 0, &size);
+       if (!dma->reg_global)
+               return -ENODEV;
+       if (size < sizeof(struct reg_global)) {
+               dev_err(kdev->dev, "bad size %pa for global regs\n", &size);
+               return -ENODEV;
+       }
+
+       dma->reg_tx_chan = pktdma_get_regs(dma, node, 1, &size);
+       if (!dma->reg_tx_chan)
+               return -ENODEV;
+
+       max_tx_chan = size / sizeof(struct reg_chan);
+       dma->reg_rx_chan = pktdma_get_regs(dma, node, 2, &size);
+       if (!dma->reg_rx_chan)
+               return -ENODEV;
+
+       max_rx_chan = size / sizeof(struct reg_chan);
+       dma->reg_tx_sched = pktdma_get_regs(dma, node, 3, &size);
+       if (!dma->reg_tx_sched)
+               return -ENODEV;
+
+       max_tx_sched = size / sizeof(struct reg_tx_sched);
+       dma->reg_rx_flow = pktdma_get_regs(dma, node, 4, &size);
+       if (!dma->reg_rx_flow)
+               return -ENODEV;
+
+       max_rx_flow = size / sizeof(struct reg_rx_flow);
+       dma->rx_priority = DMA_PRIO_DEFAULT;
+       dma->tx_priority = DMA_PRIO_DEFAULT;
+
+       dma->enable_all = (of_get_property(node, "ti,enable-all", NULL) != NULL);
+       dma->loopback   = (of_get_property(node, "ti,loop-back",  NULL) != NULL);
+
+       ret = of_property_read_u32(node, "ti,rx-retry-timeout", &timeout);
+       if (ret < 0) {
+               dev_dbg(kdev->dev, "unspecified rx timeout using value %d\n",
+                       DMA_RX_TIMEOUT_DEFAULT);
+               timeout = DMA_RX_TIMEOUT_DEFAULT;
+       }
+
+       dma->rx_timeout = timeout;
+       dma->max_rx_chan = max_rx_chan;
+       dma->max_rx_flow = max_rx_flow;
+       dma->max_tx_chan = min(max_tx_chan, max_tx_sched);
+       atomic_set(&dma->ref_count, 0);
+       strcpy(dma->name, node->name);
+       spin_lock_init(&dma->lock);
+
+       for (i = 0; i < dma->max_tx_chan; i++) {
+               if (pktdma_init_chan(dma, DMA_MEM_TO_DEV, i) >= 0)
+                       num_chan++;
+       }
+
+       for (i = 0; i < dma->max_rx_flow; i++) {
+               if (pktdma_init_chan(dma, DMA_DEV_TO_MEM, i) >= 0)
+                       num_chan++;
+       }
+
+       list_add_tail(&dma->list, &kdev->list);
+
+       /*
+        * For DSP software usecases or userpace transport software, setup all
+        * the DMA hardware resources.
+        */
+       if (dma->enable_all) {
+               atomic_inc(&dma->ref_count);
+               knav_dma_hw_init(dma);
+               dma_hw_enable_all(dma);
+       }
+
+       dev_info(kdev->dev, "DMA %s registered %d logical channels, flows %d, tx chans: %d, rx chans: %d%s\n",
+               dma->name, num_chan, dma->max_rx_flow,
+               dma->max_tx_chan, dma->max_rx_chan,
+               dma->loopback ? ", loopback" : "");
+
+       return 0;
+}
+
+static int knav_dma_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct device_node *node = pdev->dev.of_node;
+       struct device_node *child;
+       int ret = 0;
+
+       if (!node) {
+               dev_err(&pdev->dev, "could not find device info\n");
+               return -EINVAL;
+       }
+
+       kdev = devm_kzalloc(dev,
+                       sizeof(struct knav_dma_pool_device), GFP_KERNEL);
+       if (!kdev) {
+               dev_err(dev, "could not allocate driver mem\n");
+               return -ENOMEM;
+       }
+
+       kdev->dev = dev;
+       INIT_LIST_HEAD(&kdev->list);
+
+       pm_runtime_enable(kdev->dev);
+       ret = pm_runtime_get_sync(kdev->dev);
+       if (ret < 0) {
+               dev_err(kdev->dev, "unable to enable pktdma, err %d\n", ret);
+               return ret;
+       }
+
+       /* Initialise all packet dmas */
+       for_each_child_of_node(node, child) {
+               ret = dma_init(node, child);
+               if (ret) {
+                       dev_err(&pdev->dev, "init failed with %d\n", ret);
+                       break;
+               }
+       }
+
+       if (list_empty(&kdev->list)) {
+               dev_err(dev, "no valid dma instance\n");
+               return -ENODEV;
+       }
+
+       debugfs_create_file("knav_dma", S_IFREG | S_IRUGO, NULL, NULL,
+                           &knav_dma_debug_ops);
+
+       return ret;
+}
+
+static int knav_dma_remove(struct platform_device *pdev)
+{
+       struct knav_dma_device *dma;
+
+       list_for_each_entry(dma, &kdev->list, list) {
+               if (atomic_dec_return(&dma->ref_count) == 0)
+                       knav_dma_hw_destroy(dma);
+       }
+
+       pm_runtime_put_sync(&pdev->dev);
+       pm_runtime_disable(&pdev->dev);
+
+       return 0;
+}
+
+static struct of_device_id of_match[] = {
+       { .compatible = "ti,keystone-navigator-dma", },
+       {},
+};
+
+MODULE_DEVICE_TABLE(of, of_match);
+
+static struct platform_driver knav_dma_driver = {
+       .probe  = knav_dma_probe,
+       .remove = knav_dma_remove,
+       .driver = {
+               .name           = "keystone-navigator-dma",
+               .owner          = THIS_MODULE,
+               .of_match_table = of_match,
+       },
+};
+module_platform_driver(knav_dma_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("TI Keystone Navigator Packet DMA driver");
+MODULE_AUTHOR("Sandeep Nair <sandeep_n@ti.com>");
+MODULE_AUTHOR("Santosh Shilimkar <santosh.shilimkar@ti.com>");
diff --git a/drivers/soc/ti/knav_qmss.h b/drivers/soc/ti/knav_qmss.h
new file mode 100644 (file)
index 0000000..bc9dcc8
--- /dev/null
@@ -0,0 +1,386 @@
+/*
+ * Keystone Navigator QMSS driver internal header
+ *
+ * Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com
+ * Author:     Sandeep Nair <sandeep_n@ti.com>
+ *             Cyril Chemparathy <cyril@ti.com>
+ *             Santosh Shilimkar <santosh.shilimkar@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * 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 __KNAV_QMSS_H__
+#define __KNAV_QMSS_H__
+
+#define THRESH_GTE     BIT(7)
+#define THRESH_LT      0
+
+#define PDSP_CTRL_PC_MASK      0xffff0000
+#define PDSP_CTRL_SOFT_RESET   BIT(0)
+#define PDSP_CTRL_ENABLE       BIT(1)
+#define PDSP_CTRL_RUNNING      BIT(15)
+
+#define ACC_MAX_CHANNEL                48
+#define ACC_DEFAULT_PERIOD     25 /* usecs */
+
+#define ACC_CHANNEL_INT_BASE           2
+
+#define ACC_LIST_ENTRY_TYPE            1
+#define ACC_LIST_ENTRY_WORDS           (1 << ACC_LIST_ENTRY_TYPE)
+#define ACC_LIST_ENTRY_QUEUE_IDX       0
+#define ACC_LIST_ENTRY_DESC_IDX        (ACC_LIST_ENTRY_WORDS - 1)
+
+#define ACC_CMD_DISABLE_CHANNEL        0x80
+#define ACC_CMD_ENABLE_CHANNEL 0x81
+#define ACC_CFG_MULTI_QUEUE            BIT(21)
+
+#define ACC_INTD_OFFSET_EOI            (0x0010)
+#define ACC_INTD_OFFSET_COUNT(ch)      (0x0300 + 4 * (ch))
+#define ACC_INTD_OFFSET_STATUS(ch)     (0x0200 + 4 * ((ch) / 32))
+
+#define RANGE_MAX_IRQS                 64
+
+#define ACC_DESCS_MAX          SZ_1K
+#define ACC_DESCS_MASK         (ACC_DESCS_MAX - 1)
+#define DESC_SIZE_MASK         0xful
+#define DESC_PTR_MASK          (~DESC_SIZE_MASK)
+
+#define KNAV_NAME_SIZE                 32
+
+enum knav_acc_result {
+       ACC_RET_IDLE,
+       ACC_RET_SUCCESS,
+       ACC_RET_INVALID_COMMAND,
+       ACC_RET_INVALID_CHANNEL,
+       ACC_RET_INACTIVE_CHANNEL,
+       ACC_RET_ACTIVE_CHANNEL,
+       ACC_RET_INVALID_QUEUE,
+       ACC_RET_INVALID_RET,
+};
+
+struct knav_reg_config {
+       u32             revision;
+       u32             __pad1;
+       u32             divert;
+       u32             link_ram_base0;
+       u32             link_ram_size0;
+       u32             link_ram_base1;
+       u32             __pad2[2];
+       u32             starvation[0];
+};
+
+struct knav_reg_region {
+       u32             base;
+       u32             start_index;
+       u32             size_count;
+       u32             __pad;
+};
+
+struct knav_reg_pdsp_regs {
+       u32             control;
+       u32             status;
+       u32             cycle_count;
+       u32             stall_count;
+};
+
+struct knav_reg_acc_command {
+       u32             command;
+       u32             queue_mask;
+       u32             list_phys;
+       u32             queue_num;
+       u32             timer_config;
+};
+
+struct knav_link_ram_block {
+       dma_addr_t       phys;
+       void            *virt;
+       size_t           size;
+};
+
+struct knav_acc_info {
+       u32                      pdsp_id;
+       u32                      start_channel;
+       u32                      list_entries;
+       u32                      pacing_mode;
+       u32                      timer_count;
+       int                      mem_size;
+       int                      list_size;
+       struct knav_pdsp_info   *pdsp;
+};
+
+struct knav_acc_channel {
+       u32                     channel;
+       u32                     list_index;
+       u32                     open_mask;
+       u32                     *list_cpu[2];
+       dma_addr_t              list_dma[2];
+       char                    name[KNAV_NAME_SIZE];
+       atomic_t                retrigger_count;
+};
+
+struct knav_pdsp_info {
+       const char                                      *name;
+       struct knav_reg_pdsp_regs  __iomem              *regs;
+       union {
+               void __iomem                            *command;
+               struct knav_reg_acc_command __iomem     *acc_command;
+               u32 __iomem                             *qos_command;
+       };
+       void __iomem                                    *intd;
+       u32 __iomem                                     *iram;
+       const char                                      *firmware;
+       u32                                             id;
+       struct list_head                                list;
+};
+
+struct knav_qmgr_info {
+       unsigned                        start_queue;
+       unsigned                        num_queues;
+       struct knav_reg_config __iomem  *reg_config;
+       struct knav_reg_region __iomem  *reg_region;
+       struct knav_reg_queue __iomem   *reg_push, *reg_pop, *reg_peek;
+       void __iomem                    *reg_status;
+       struct list_head                list;
+};
+
+#define KNAV_NUM_LINKRAM       2
+
+/**
+ * struct knav_queue_stats:    queue statistics
+ * pushes:                     number of push operations
+ * pops:                       number of pop operations
+ * push_errors:                        number of push errors
+ * pop_errors:                 number of pop errors
+ * notifies:                   notifier counts
+ */
+struct knav_queue_stats {
+       atomic_t         pushes;
+       atomic_t         pops;
+       atomic_t         push_errors;
+       atomic_t         pop_errors;
+       atomic_t         notifies;
+};
+
+/**
+ * struct knav_reg_queue:      queue registers
+ * @entry_count:               valid entries in the queue
+ * @byte_count:                        total byte count in thhe queue
+ * @packet_size:               packet size for the queue
+ * @ptr_size_thresh:           packet pointer size threshold
+ */
+struct knav_reg_queue {
+       u32             entry_count;
+       u32             byte_count;
+       u32             packet_size;
+       u32             ptr_size_thresh;
+};
+
+/**
+ * struct knav_region:         qmss region info
+ * @dma_start, dma_end:                start and end dma address
+ * @virt_start, virt_end:      start and end virtual address
+ * @desc_size:                 descriptor size
+ * @used_desc:                 consumed descriptors
+ * @id:                                region number
+ * @num_desc:                  total descriptors
+ * @link_index:                        index of the first descriptor
+ * @name:                      region name
+ * @list:                      instance in the device's region list
+ * @pools:                     list of descriptor pools in the region
+ */
+struct knav_region {
+       dma_addr_t              dma_start, dma_end;
+       void                    *virt_start, *virt_end;
+       unsigned                desc_size;
+       unsigned                used_desc;
+       unsigned                id;
+       unsigned                num_desc;
+       unsigned                link_index;
+       const char              *name;
+       struct list_head        list;
+       struct list_head        pools;
+};
+
+/**
+ * struct knav_pool:           qmss pools
+ * @dev:                       device pointer
+ * @region:                    qmss region info
+ * @queue:                     queue registers
+ * @kdev:                      qmss device pointer
+ * @region_offset:             offset from the base
+ * @num_desc:                  total descriptors
+ * @desc_size:                 descriptor size
+ * @region_id:                 region number
+ * @name:                      pool name
+ * @list:                      list head
+ * @region_inst:               instance in the region's pool list
+ */
+struct knav_pool {
+       struct device                   *dev;
+       struct knav_region              *region;
+       struct knav_queue               *queue;
+       struct knav_device              *kdev;
+       int                             region_offset;
+       int                             num_desc;
+       int                             desc_size;
+       int                             region_id;
+       const char                      *name;
+       struct list_head                list;
+       struct list_head                region_inst;
+};
+
+/**
+ * struct knav_queue_inst:             qmss queue instace properties
+ * @descs:                             descriptor pointer
+ * @desc_head, desc_tail, desc_count:  descriptor counters
+ * @acc:                               accumulator channel pointer
+ * @kdev:                              qmss device pointer
+ * @range:                             range info
+ * @qmgr:                              queue manager info
+ * @id:                                        queue instace id
+ * @irq_num:                           irq line number
+ * @notify_needed:                     notifier needed based on queue type
+ * @num_notifiers:                     total notifiers
+ * @handles:                           list head
+ * @name:                              queue instance name
+ * @irq_name:                          irq line name
+ */
+struct knav_queue_inst {
+       u32                             *descs;
+       atomic_t                        desc_head, desc_tail, desc_count;
+       struct knav_acc_channel *acc;
+       struct knav_device              *kdev;
+       struct knav_range_info          *range;
+       struct knav_qmgr_info           *qmgr;
+       u32                             id;
+       int                             irq_num;
+       int                             notify_needed;
+       atomic_t                        num_notifiers;
+       struct list_head                handles;
+       const char                      *name;
+       const char                      *irq_name;
+};
+
+/**
+ * struct knav_queue:                  qmss queue properties
+ * @reg_push, reg_pop, reg_peek:       push, pop queue registers
+ * @inst:                              qmss queue instace properties
+ * @notifier_fn:                       notifier function
+ * @notifier_fn_arg:                   notifier function argument
+ * @notifier_enabled:                  notier enabled for a give queue
+ * @rcu:                               rcu head
+ * @flags:                             queue flags
+ * @list:                              list head
+ */
+struct knav_queue {
+       struct knav_reg_queue __iomem   *reg_push, *reg_pop, *reg_peek;
+       struct knav_queue_inst          *inst;
+       struct knav_queue_stats stats;
+       knav_queue_notify_fn            notifier_fn;
+       void                            *notifier_fn_arg;
+       atomic_t                        notifier_enabled;
+       struct rcu_head                 rcu;
+       unsigned                        flags;
+       struct list_head                list;
+};
+
+struct knav_device {
+       struct device                           *dev;
+       unsigned                                base_id;
+       unsigned                                num_queues;
+       unsigned                                num_queues_in_use;
+       unsigned                                inst_shift;
+       struct knav_link_ram_block              link_rams[KNAV_NUM_LINKRAM];
+       void                                    *instances;
+       struct list_head                        regions;
+       struct list_head                        queue_ranges;
+       struct list_head                        pools;
+       struct list_head                        pdsps;
+       struct list_head                        qmgrs;
+};
+
+struct knav_range_ops {
+       int     (*init_range)(struct knav_range_info *range);
+       int     (*free_range)(struct knav_range_info *range);
+       int     (*init_queue)(struct knav_range_info *range,
+                             struct knav_queue_inst *inst);
+       int     (*open_queue)(struct knav_range_info *range,
+                             struct knav_queue_inst *inst, unsigned flags);
+       int     (*close_queue)(struct knav_range_info *range,
+                              struct knav_queue_inst *inst);
+       int     (*set_notify)(struct knav_range_info *range,
+                             struct knav_queue_inst *inst, bool enabled);
+};
+
+struct knav_irq_info {
+       int     irq;
+       u32     cpu_map;
+};
+
+struct knav_range_info {
+       const char                      *name;
+       struct knav_device              *kdev;
+       unsigned                        queue_base;
+       unsigned                        num_queues;
+       void                            *queue_base_inst;
+       unsigned                        flags;
+       struct list_head                list;
+       struct knav_range_ops           *ops;
+       struct knav_acc_info            acc_info;
+       struct knav_acc_channel *acc;
+       unsigned                        num_irqs;
+       struct knav_irq_info            irqs[RANGE_MAX_IRQS];
+};
+
+#define RANGE_RESERVED         BIT(0)
+#define RANGE_HAS_IRQ          BIT(1)
+#define RANGE_HAS_ACCUMULATOR  BIT(2)
+#define RANGE_MULTI_QUEUE      BIT(3)
+
+#define for_each_region(kdev, region)                          \
+       list_for_each_entry(region, &kdev->regions, list)
+
+#define first_region(kdev)                                     \
+       list_first_entry(&kdev->regions, \
+                       struct knav_region, list)
+
+#define for_each_queue_range(kdev, range)                      \
+       list_for_each_entry(range, &kdev->queue_ranges, list)
+
+#define first_queue_range(kdev)                                        \
+       list_first_entry(&kdev->queue_ranges, \
+                       struct knav_range_info, list)
+
+#define for_each_pool(kdev, pool)                              \
+       list_for_each_entry(pool, &kdev->pools, list)
+
+#define for_each_pdsp(kdev, pdsp)                              \
+       list_for_each_entry(pdsp, &kdev->pdsps, list)
+
+#define for_each_qmgr(kdev, qmgr)                              \
+       list_for_each_entry(qmgr, &kdev->qmgrs, list)
+
+static inline struct knav_pdsp_info *
+knav_find_pdsp(struct knav_device *kdev, unsigned pdsp_id)
+{
+       struct knav_pdsp_info *pdsp;
+
+       for_each_pdsp(kdev, pdsp)
+               if (pdsp_id == pdsp->id)
+                       return pdsp;
+       return NULL;
+}
+
+extern int knav_init_acc_range(struct knav_device *kdev,
+                                       struct device_node *node,
+                                       struct knav_range_info *range);
+extern void knav_queue_notify(struct knav_queue_inst *inst);
+
+#endif /* __KNAV_QMSS_H__ */
diff --git a/drivers/soc/ti/knav_qmss_acc.c b/drivers/soc/ti/knav_qmss_acc.c
new file mode 100644 (file)
index 0000000..6fbfde6
--- /dev/null
@@ -0,0 +1,591 @@
+/*
+ * Keystone accumulator queue manager
+ *
+ * Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com
+ * Author:     Sandeep Nair <sandeep_n@ti.com>
+ *             Cyril Chemparathy <cyril@ti.com>
+ *             Santosh Shilimkar <santosh.shilimkar@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * 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/device.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/bitops.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/soc/ti/knav_qmss.h>
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_address.h>
+#include <linux/firmware.h>
+
+#include "knav_qmss.h"
+
+#define knav_range_offset_to_inst(kdev, range, q)      \
+       (range->queue_base_inst + (q << kdev->inst_shift))
+
+static void __knav_acc_notify(struct knav_range_info *range,
+                               struct knav_acc_channel *acc)
+{
+       struct knav_device *kdev = range->kdev;
+       struct knav_queue_inst *inst;
+       int range_base, queue;
+
+       range_base = kdev->base_id + range->queue_base;
+
+       if (range->flags & RANGE_MULTI_QUEUE) {
+               for (queue = 0; queue < range->num_queues; queue++) {
+                       inst = knav_range_offset_to_inst(kdev, range,
+                                                               queue);
+                       if (inst->notify_needed) {
+                               inst->notify_needed = 0;
+                               dev_dbg(kdev->dev, "acc-irq: notifying %d\n",
+                                       range_base + queue);
+                               knav_queue_notify(inst);
+                       }
+               }
+       } else {
+               queue = acc->channel - range->acc_info.start_channel;
+               inst = knav_range_offset_to_inst(kdev, range, queue);
+               dev_dbg(kdev->dev, "acc-irq: notifying %d\n",
+                       range_base + queue);
+               knav_queue_notify(inst);
+       }
+}
+
+static int knav_acc_set_notify(struct knav_range_info *range,
+                               struct knav_queue_inst *kq,
+                               bool enabled)
+{
+       struct knav_pdsp_info *pdsp = range->acc_info.pdsp;
+       struct knav_device *kdev = range->kdev;
+       u32 mask, offset;
+
+       /*
+        * when enabling, we need to re-trigger an interrupt if we
+        * have descriptors pending
+        */
+       if (!enabled || atomic_read(&kq->desc_count) <= 0)
+               return 0;
+
+       kq->notify_needed = 1;
+       atomic_inc(&kq->acc->retrigger_count);
+       mask = BIT(kq->acc->channel % 32);
+       offset = ACC_INTD_OFFSET_STATUS(kq->acc->channel);
+       dev_dbg(kdev->dev, "setup-notify: re-triggering irq for %s\n",
+               kq->acc->name);
+       writel_relaxed(mask, pdsp->intd + offset);
+       return 0;
+}
+
+static irqreturn_t knav_acc_int_handler(int irq, void *_instdata)
+{
+       struct knav_acc_channel *acc;
+       struct knav_queue_inst *kq = NULL;
+       struct knav_range_info *range;
+       struct knav_pdsp_info *pdsp;
+       struct knav_acc_info *info;
+       struct knav_device *kdev;
+
+       u32 *list, *list_cpu, val, idx, notifies;
+       int range_base, channel, queue = 0;
+       dma_addr_t list_dma;
+
+       range = _instdata;
+       info  = &range->acc_info;
+       kdev  = range->kdev;
+       pdsp  = range->acc_info.pdsp;
+       acc   = range->acc;
+
+       range_base = kdev->base_id + range->queue_base;
+       if ((range->flags & RANGE_MULTI_QUEUE) == 0) {
+               for (queue = 0; queue < range->num_irqs; queue++)
+                       if (range->irqs[queue].irq == irq)
+                               break;
+               kq = knav_range_offset_to_inst(kdev, range, queue);
+               acc += queue;
+       }
+
+       channel = acc->channel;
+       list_dma = acc->list_dma[acc->list_index];
+       list_cpu = acc->list_cpu[acc->list_index];
+       dev_dbg(kdev->dev, "acc-irq: channel %d, list %d, virt %p, phys %x\n",
+               channel, acc->list_index, list_cpu, list_dma);
+       if (atomic_read(&acc->retrigger_count)) {
+               atomic_dec(&acc->retrigger_count);
+               __knav_acc_notify(range, acc);
+               writel_relaxed(1, pdsp->intd + ACC_INTD_OFFSET_COUNT(channel));
+               /* ack the interrupt */
+               writel_relaxed(ACC_CHANNEL_INT_BASE + channel,
+                              pdsp->intd + ACC_INTD_OFFSET_EOI);
+
+               return IRQ_HANDLED;
+       }
+
+       notifies = readl_relaxed(pdsp->intd + ACC_INTD_OFFSET_COUNT(channel));
+       WARN_ON(!notifies);
+       dma_sync_single_for_cpu(kdev->dev, list_dma, info->list_size,
+                               DMA_FROM_DEVICE);
+
+       for (list = list_cpu; list < list_cpu + (info->list_size / sizeof(u32));
+            list += ACC_LIST_ENTRY_WORDS) {
+               if (ACC_LIST_ENTRY_WORDS == 1) {
+                       dev_dbg(kdev->dev,
+                               "acc-irq: list %d, entry @%p, %08x\n",
+                               acc->list_index, list, list[0]);
+               } else if (ACC_LIST_ENTRY_WORDS == 2) {
+                       dev_dbg(kdev->dev,
+                               "acc-irq: list %d, entry @%p, %08x %08x\n",
+                               acc->list_index, list, list[0], list[1]);
+               } else if (ACC_LIST_ENTRY_WORDS == 4) {
+                       dev_dbg(kdev->dev,
+                               "acc-irq: list %d, entry @%p, %08x %08x %08x %08x\n",
+                               acc->list_index, list, list[0], list[1],
+                               list[2], list[3]);
+               }
+
+               val = list[ACC_LIST_ENTRY_DESC_IDX];
+               if (!val)
+                       break;
+
+               if (range->flags & RANGE_MULTI_QUEUE) {
+                       queue = list[ACC_LIST_ENTRY_QUEUE_IDX] >> 16;
+                       if (queue < range_base ||
+                           queue >= range_base + range->num_queues) {
+                               dev_err(kdev->dev,
+                                       "bad queue %d, expecting %d-%d\n",
+                                       queue, range_base,
+                                       range_base + range->num_queues);
+                               break;
+                       }
+                       queue -= range_base;
+                       kq = knav_range_offset_to_inst(kdev, range,
+                                                               queue);
+               }
+
+               if (atomic_inc_return(&kq->desc_count) >= ACC_DESCS_MAX) {
+                       atomic_dec(&kq->desc_count);
+                       dev_err(kdev->dev,
+                               "acc-irq: queue %d full, entry dropped\n",
+                               queue + range_base);
+                       continue;
+               }
+
+               idx = atomic_inc_return(&kq->desc_tail) & ACC_DESCS_MASK;
+               kq->descs[idx] = val;
+               kq->notify_needed = 1;
+               dev_dbg(kdev->dev, "acc-irq: enqueue %08x at %d, queue %d\n",
+                       val, idx, queue + range_base);
+       }
+
+       __knav_acc_notify(range, acc);
+       memset(list_cpu, 0, info->list_size);
+       dma_sync_single_for_device(kdev->dev, list_dma, info->list_size,
+                                  DMA_TO_DEVICE);
+
+       /* flip to the other list */
+       acc->list_index ^= 1;
+
+       /* reset the interrupt counter */
+       writel_relaxed(1, pdsp->intd + ACC_INTD_OFFSET_COUNT(channel));
+
+       /* ack the interrupt */
+       writel_relaxed(ACC_CHANNEL_INT_BASE + channel,
+                      pdsp->intd + ACC_INTD_OFFSET_EOI);
+
+       return IRQ_HANDLED;
+}
+
+int knav_range_setup_acc_irq(struct knav_range_info *range,
+                               int queue, bool enabled)
+{
+       struct knav_device *kdev = range->kdev;
+       struct knav_acc_channel *acc;
+       unsigned long cpu_map;
+       int ret = 0, irq;
+       u32 old, new;
+
+       if (range->flags & RANGE_MULTI_QUEUE) {
+               acc = range->acc;
+               irq = range->irqs[0].irq;
+               cpu_map = range->irqs[0].cpu_map;
+       } else {
+               acc = range->acc + queue;
+               irq = range->irqs[queue].irq;
+               cpu_map = range->irqs[queue].cpu_map;
+       }
+
+       old = acc->open_mask;
+       if (enabled)
+               new = old | BIT(queue);
+       else
+               new = old & ~BIT(queue);
+       acc->open_mask = new;
+
+       dev_dbg(kdev->dev,
+               "setup-acc-irq: open mask old %08x, new %08x, channel %s\n",
+               old, new, acc->name);
+
+       if (likely(new == old))
+               return 0;
+
+       if (new && !old) {
+               dev_dbg(kdev->dev,
+                       "setup-acc-irq: requesting %s for channel %s\n",
+                       acc->name, acc->name);
+               ret = request_irq(irq, knav_acc_int_handler, 0, acc->name,
+                                 range);
+               if (!ret && cpu_map) {
+                       ret = irq_set_affinity_hint(irq, to_cpumask(&cpu_map));
+                       if (ret) {
+                               dev_warn(range->kdev->dev,
+                                        "Failed to set IRQ affinity\n");
+                               return ret;
+                       }
+               }
+       }
+
+       if (old && !new) {
+               dev_dbg(kdev->dev, "setup-acc-irq: freeing %s for channel %s\n",
+                       acc->name, acc->name);
+               free_irq(irq, range);
+       }
+
+       return ret;
+}
+
+static const char *knav_acc_result_str(enum knav_acc_result result)
+{
+       static const char * const result_str[] = {
+               [ACC_RET_IDLE]                  = "idle",
+               [ACC_RET_SUCCESS]               = "success",
+               [ACC_RET_INVALID_COMMAND]       = "invalid command",
+               [ACC_RET_INVALID_CHANNEL]       = "invalid channel",
+               [ACC_RET_INACTIVE_CHANNEL]      = "inactive channel",
+               [ACC_RET_ACTIVE_CHANNEL]        = "active channel",
+               [ACC_RET_INVALID_QUEUE]         = "invalid queue",
+               [ACC_RET_INVALID_RET]           = "invalid return code",
+       };
+
+       if (result >= ARRAY_SIZE(result_str))
+               return result_str[ACC_RET_INVALID_RET];
+       else
+               return result_str[result];
+}
+
+static enum knav_acc_result
+knav_acc_write(struct knav_device *kdev, struct knav_pdsp_info *pdsp,
+               struct knav_reg_acc_command *cmd)
+{
+       u32 result;
+
+       dev_dbg(kdev->dev, "acc command %08x %08x %08x %08x %08x\n",
+               cmd->command, cmd->queue_mask, cmd->list_phys,
+               cmd->queue_num, cmd->timer_config);
+
+       writel_relaxed(cmd->timer_config, &pdsp->acc_command->timer_config);
+       writel_relaxed(cmd->queue_num, &pdsp->acc_command->queue_num);
+       writel_relaxed(cmd->list_phys, &pdsp->acc_command->list_phys);
+       writel_relaxed(cmd->queue_mask, &pdsp->acc_command->queue_mask);
+       writel_relaxed(cmd->command, &pdsp->acc_command->command);
+
+       /* wait for the command to clear */
+       do {
+               result = readl_relaxed(&pdsp->acc_command->command);
+       } while ((result >> 8) & 0xff);
+
+       return (result >> 24) & 0xff;
+}
+
+static void knav_acc_setup_cmd(struct knav_device *kdev,
+                               struct knav_range_info *range,
+                               struct knav_reg_acc_command *cmd,
+                               int queue)
+{
+       struct knav_acc_info *info = &range->acc_info;
+       struct knav_acc_channel *acc;
+       int queue_base;
+       u32 queue_mask;
+
+       if (range->flags & RANGE_MULTI_QUEUE) {
+               acc = range->acc;
+               queue_base = range->queue_base;
+               queue_mask = BIT(range->num_queues) - 1;
+       } else {
+               acc = range->acc + queue;
+               queue_base = range->queue_base + queue;
+               queue_mask = 0;
+       }
+
+       memset(cmd, 0, sizeof(*cmd));
+       cmd->command    = acc->channel;
+       cmd->queue_mask = queue_mask;
+       cmd->list_phys  = acc->list_dma[0];
+       cmd->queue_num  = info->list_entries << 16;
+       cmd->queue_num |= queue_base;
+
+       cmd->timer_config = ACC_LIST_ENTRY_TYPE << 18;
+       if (range->flags & RANGE_MULTI_QUEUE)
+               cmd->timer_config |= ACC_CFG_MULTI_QUEUE;
+       cmd->timer_config |= info->pacing_mode << 16;
+       cmd->timer_config |= info->timer_count;
+}
+
+static void knav_acc_stop(struct knav_device *kdev,
+                               struct knav_range_info *range,
+                               int queue)
+{
+       struct knav_reg_acc_command cmd;
+       struct knav_acc_channel *acc;
+       enum knav_acc_result result;
+
+       acc = range->acc + queue;
+
+       knav_acc_setup_cmd(kdev, range, &cmd, queue);
+       cmd.command |= ACC_CMD_DISABLE_CHANNEL << 8;
+       result = knav_acc_write(kdev, range->acc_info.pdsp, &cmd);
+
+       dev_dbg(kdev->dev, "stopped acc channel %s, result %s\n",
+               acc->name, knav_acc_result_str(result));
+}
+
+static enum knav_acc_result knav_acc_start(struct knav_device *kdev,
+                                               struct knav_range_info *range,
+                                               int queue)
+{
+       struct knav_reg_acc_command cmd;
+       struct knav_acc_channel *acc;
+       enum knav_acc_result result;
+
+       acc = range->acc + queue;
+
+       knav_acc_setup_cmd(kdev, range, &cmd, queue);
+       cmd.command |= ACC_CMD_ENABLE_CHANNEL << 8;
+       result = knav_acc_write(kdev, range->acc_info.pdsp, &cmd);
+
+       dev_dbg(kdev->dev, "started acc channel %s, result %s\n",
+               acc->name, knav_acc_result_str(result));
+
+       return result;
+}
+
+static int knav_acc_init_range(struct knav_range_info *range)
+{
+       struct knav_device *kdev = range->kdev;
+       struct knav_acc_channel *acc;
+       enum knav_acc_result result;
+       int queue;
+
+       for (queue = 0; queue < range->num_queues; queue++) {
+               acc = range->acc + queue;
+
+               knav_acc_stop(kdev, range, queue);
+               acc->list_index = 0;
+               result = knav_acc_start(kdev, range, queue);
+
+               if (result != ACC_RET_SUCCESS)
+                       return -EIO;
+
+               if (range->flags & RANGE_MULTI_QUEUE)
+                       return 0;
+       }
+       return 0;
+}
+
+static int knav_acc_init_queue(struct knav_range_info *range,
+                               struct knav_queue_inst *kq)
+{
+       unsigned id = kq->id - range->queue_base;
+
+       kq->descs = devm_kzalloc(range->kdev->dev,
+                                ACC_DESCS_MAX * sizeof(u32), GFP_KERNEL);
+       if (!kq->descs)
+               return -ENOMEM;
+
+       kq->acc = range->acc;
+       if ((range->flags & RANGE_MULTI_QUEUE) == 0)
+               kq->acc += id;
+       return 0;
+}
+
+static int knav_acc_open_queue(struct knav_range_info *range,
+                               struct knav_queue_inst *inst, unsigned flags)
+{
+       unsigned id = inst->id - range->queue_base;
+
+       return knav_range_setup_acc_irq(range, id, true);
+}
+
+static int knav_acc_close_queue(struct knav_range_info *range,
+                                       struct knav_queue_inst *inst)
+{
+       unsigned id = inst->id - range->queue_base;
+
+       return knav_range_setup_acc_irq(range, id, false);
+}
+
+static int knav_acc_free_range(struct knav_range_info *range)
+{
+       struct knav_device *kdev = range->kdev;
+       struct knav_acc_channel *acc;
+       struct knav_acc_info *info;
+       int channel, channels;
+
+       info = &range->acc_info;
+
+       if (range->flags & RANGE_MULTI_QUEUE)
+               channels = 1;
+       else
+               channels = range->num_queues;
+
+       for (channel = 0; channel < channels; channel++) {
+               acc = range->acc + channel;
+               if (!acc->list_cpu[0])
+                       continue;
+               dma_unmap_single(kdev->dev, acc->list_dma[0],
+                                info->mem_size, DMA_BIDIRECTIONAL);
+               free_pages_exact(acc->list_cpu[0], info->mem_size);
+       }
+       devm_kfree(range->kdev->dev, range->acc);
+       return 0;
+}
+
+struct knav_range_ops knav_acc_range_ops = {
+       .set_notify     = knav_acc_set_notify,
+       .init_queue     = knav_acc_init_queue,
+       .open_queue     = knav_acc_open_queue,
+       .close_queue    = knav_acc_close_queue,
+       .init_range     = knav_acc_init_range,
+       .free_range     = knav_acc_free_range,
+};
+
+/**
+ * knav_init_acc_range: Initialise accumulator ranges
+ *
+ * @kdev:              qmss device
+ * @node:              device node
+ * @range:             qmms range information
+ *
+ * Return 0 on success or error
+ */
+int knav_init_acc_range(struct knav_device *kdev,
+                               struct device_node *node,
+                               struct knav_range_info *range)
+{
+       struct knav_acc_channel *acc;
+       struct knav_pdsp_info *pdsp;
+       struct knav_acc_info *info;
+       int ret, channel, channels;
+       int list_size, mem_size;
+       dma_addr_t list_dma;
+       void *list_mem;
+       u32 config[5];
+
+       range->flags |= RANGE_HAS_ACCUMULATOR;
+       info = &range->acc_info;
+
+       ret = of_property_read_u32_array(node, "accumulator", config, 5);
+       if (ret)
+               return ret;
+
+       info->pdsp_id           = config[0];
+       info->start_channel     = config[1];
+       info->list_entries      = config[2];
+       info->pacing_mode       = config[3];
+       info->timer_count       = config[4] / ACC_DEFAULT_PERIOD;
+
+       if (info->start_channel > ACC_MAX_CHANNEL) {
+               dev_err(kdev->dev, "channel %d invalid for range %s\n",
+                       info->start_channel, range->name);
+               return -EINVAL;
+       }
+
+       if (info->pacing_mode > 3) {
+               dev_err(kdev->dev, "pacing mode %d invalid for range %s\n",
+                       info->pacing_mode, range->name);
+               return -EINVAL;
+       }
+
+       pdsp = knav_find_pdsp(kdev, info->pdsp_id);
+       if (!pdsp) {
+               dev_err(kdev->dev, "pdsp id %d not found for range %s\n",
+                       info->pdsp_id, range->name);
+               return -EINVAL;
+       }
+
+       info->pdsp = pdsp;
+       channels = range->num_queues;
+       if (of_get_property(node, "multi-queue", NULL)) {
+               range->flags |= RANGE_MULTI_QUEUE;
+               channels = 1;
+               if (range->queue_base & (32 - 1)) {
+                       dev_err(kdev->dev,
+                               "misaligned multi-queue accumulator range %s\n",
+                               range->name);
+                       return -EINVAL;
+               }
+               if (range->num_queues > 32) {
+                       dev_err(kdev->dev,
+                               "too many queues in accumulator range %s\n",
+                               range->name);
+                       return -EINVAL;
+               }
+       }
+
+       /* figure out list size */
+       list_size  = info->list_entries;
+       list_size *= ACC_LIST_ENTRY_WORDS * sizeof(u32);
+       info->list_size = list_size;
+       mem_size   = PAGE_ALIGN(list_size * 2);
+       info->mem_size  = mem_size;
+       range->acc = devm_kzalloc(kdev->dev, channels * sizeof(*range->acc),
+                                 GFP_KERNEL);
+       if (!range->acc)
+               return -ENOMEM;
+
+       for (channel = 0; channel < channels; channel++) {
+               acc = range->acc + channel;
+               acc->channel = info->start_channel + channel;
+
+               /* allocate memory for the two lists */
+               list_mem = alloc_pages_exact(mem_size, GFP_KERNEL | GFP_DMA);
+               if (!list_mem)
+                       return -ENOMEM;
+
+               list_dma = dma_map_single(kdev->dev, list_mem, mem_size,
+                                         DMA_BIDIRECTIONAL);
+               if (dma_mapping_error(kdev->dev, list_dma)) {
+                       free_pages_exact(list_mem, mem_size);
+                       return -ENOMEM;
+               }
+
+               memset(list_mem, 0, mem_size);
+               dma_sync_single_for_device(kdev->dev, list_dma, mem_size,
+                                          DMA_TO_DEVICE);
+               scnprintf(acc->name, sizeof(acc->name), "hwqueue-acc-%d",
+                         acc->channel);
+               acc->list_cpu[0] = list_mem;
+               acc->list_cpu[1] = list_mem + list_size;
+               acc->list_dma[0] = list_dma;
+               acc->list_dma[1] = list_dma + list_size;
+               dev_dbg(kdev->dev, "%s: channel %d, phys %08x, virt %8p\n",
+                       acc->name, acc->channel, list_dma, list_mem);
+       }
+
+       range->ops = &knav_acc_range_ops;
+       return 0;
+}
+EXPORT_SYMBOL_GPL(knav_init_acc_range);
diff --git a/drivers/soc/ti/knav_qmss_queue.c b/drivers/soc/ti/knav_qmss_queue.c
new file mode 100644 (file)
index 0000000..0a2c863
--- /dev/null
@@ -0,0 +1,1816 @@
+/*
+ * Keystone Queue Manager subsystem driver
+ *
+ * Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com
+ * Authors:    Sandeep Nair <sandeep_n@ti.com>
+ *             Cyril Chemparathy <cyril@ti.com>
+ *             Santosh Shilimkar <santosh.shilimkar@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * 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/device.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/bitops.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/of_device.h>
+#include <linux/of_address.h>
+#include <linux/pm_runtime.h>
+#include <linux/firmware.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+#include <linux/string.h>
+#include <linux/soc/ti/knav_qmss.h>
+
+#include "knav_qmss.h"
+
+static struct knav_device *kdev;
+static DEFINE_MUTEX(knav_dev_lock);
+
+/* Queue manager register indices in DTS */
+#define KNAV_QUEUE_PEEK_REG_INDEX      0
+#define KNAV_QUEUE_STATUS_REG_INDEX    1
+#define KNAV_QUEUE_CONFIG_REG_INDEX    2
+#define KNAV_QUEUE_REGION_REG_INDEX    3
+#define KNAV_QUEUE_PUSH_REG_INDEX      4
+#define KNAV_QUEUE_POP_REG_INDEX       5
+
+/* PDSP register indices in DTS */
+#define KNAV_QUEUE_PDSP_IRAM_REG_INDEX 0
+#define KNAV_QUEUE_PDSP_REGS_REG_INDEX 1
+#define KNAV_QUEUE_PDSP_INTD_REG_INDEX 2
+#define KNAV_QUEUE_PDSP_CMD_REG_INDEX  3
+
+#define knav_queue_idx_to_inst(kdev, idx)                      \
+       (kdev->instances + (idx << kdev->inst_shift))
+
+#define for_each_handle_rcu(qh, inst)                  \
+       list_for_each_entry_rcu(qh, &inst->handles, list)
+
+#define for_each_instance(idx, inst, kdev)             \
+       for (idx = 0, inst = kdev->instances;           \
+            idx < (kdev)->num_queues_in_use;                   \
+            idx++, inst = knav_queue_idx_to_inst(kdev, idx))
+
+/**
+ * knav_queue_notify: qmss queue notfier call
+ *
+ * @inst:              qmss queue instance like accumulator
+ */
+void knav_queue_notify(struct knav_queue_inst *inst)
+{
+       struct knav_queue *qh;
+
+       if (!inst)
+               return;
+
+       rcu_read_lock();
+       for_each_handle_rcu(qh, inst) {
+               if (atomic_read(&qh->notifier_enabled) <= 0)
+                       continue;
+               if (WARN_ON(!qh->notifier_fn))
+                       continue;
+               atomic_inc(&qh->stats.notifies);
+               qh->notifier_fn(qh->notifier_fn_arg);
+       }
+       rcu_read_unlock();
+}
+EXPORT_SYMBOL_GPL(knav_queue_notify);
+
+static irqreturn_t knav_queue_int_handler(int irq, void *_instdata)
+{
+       struct knav_queue_inst *inst = _instdata;
+
+       knav_queue_notify(inst);
+       return IRQ_HANDLED;
+}
+
+static int knav_queue_setup_irq(struct knav_range_info *range,
+                         struct knav_queue_inst *inst)
+{
+       unsigned queue = inst->id - range->queue_base;
+       unsigned long cpu_map;
+       int ret = 0, irq;
+
+       if (range->flags & RANGE_HAS_IRQ) {
+               irq = range->irqs[queue].irq;
+               cpu_map = range->irqs[queue].cpu_map;
+               ret = request_irq(irq, knav_queue_int_handler, 0,
+                                       inst->irq_name, inst);
+               if (ret)
+                       return ret;
+               disable_irq(irq);
+               if (cpu_map) {
+                       ret = irq_set_affinity_hint(irq, to_cpumask(&cpu_map));
+                       if (ret) {
+                               dev_warn(range->kdev->dev,
+                                        "Failed to set IRQ affinity\n");
+                               return ret;
+                       }
+               }
+       }
+       return ret;
+}
+
+static void knav_queue_free_irq(struct knav_queue_inst *inst)
+{
+       struct knav_range_info *range = inst->range;
+       unsigned queue = inst->id - inst->range->queue_base;
+       int irq;
+
+       if (range->flags & RANGE_HAS_IRQ) {
+               irq = range->irqs[queue].irq;
+               irq_set_affinity_hint(irq, NULL);
+               free_irq(irq, inst);
+       }
+}
+
+static inline bool knav_queue_is_busy(struct knav_queue_inst *inst)
+{
+       return !list_empty(&inst->handles);
+}
+
+static inline bool knav_queue_is_reserved(struct knav_queue_inst *inst)
+{
+       return inst->range->flags & RANGE_RESERVED;
+}
+
+static inline bool knav_queue_is_shared(struct knav_queue_inst *inst)
+{
+       struct knav_queue *tmp;
+
+       rcu_read_lock();
+       for_each_handle_rcu(tmp, inst) {
+               if (tmp->flags & KNAV_QUEUE_SHARED) {
+                       rcu_read_unlock();
+                       return true;
+               }
+       }
+       rcu_read_unlock();
+       return false;
+}
+
+static inline bool knav_queue_match_type(struct knav_queue_inst *inst,
+                                               unsigned type)
+{
+       if ((type == KNAV_QUEUE_QPEND) &&
+           (inst->range->flags & RANGE_HAS_IRQ)) {
+               return true;
+       } else if ((type == KNAV_QUEUE_ACC) &&
+               (inst->range->flags & RANGE_HAS_ACCUMULATOR)) {
+               return true;
+       } else if ((type == KNAV_QUEUE_GP) &&
+               !(inst->range->flags &
+                       (RANGE_HAS_ACCUMULATOR | RANGE_HAS_IRQ))) {
+               return true;
+       }
+       return false;
+}
+
+static inline struct knav_queue_inst *
+knav_queue_match_id_to_inst(struct knav_device *kdev, unsigned id)
+{
+       struct knav_queue_inst *inst;
+       int idx;
+
+       for_each_instance(idx, inst, kdev) {
+               if (inst->id == id)
+                       return inst;
+       }
+       return NULL;
+}
+
+static inline struct knav_queue_inst *knav_queue_find_by_id(int id)
+{
+       if (kdev->base_id <= id &&
+           kdev->base_id + kdev->num_queues > id) {
+               id -= kdev->base_id;
+               return knav_queue_match_id_to_inst(kdev, id);
+       }
+       return NULL;
+}
+
+static struct knav_queue *__knav_queue_open(struct knav_queue_inst *inst,
+                                     const char *name, unsigned flags)
+{
+       struct knav_queue *qh;
+       unsigned id;
+       int ret = 0;
+
+       qh = devm_kzalloc(inst->kdev->dev, sizeof(*qh), GFP_KERNEL);
+       if (!qh)
+               return ERR_PTR(-ENOMEM);
+
+       qh->flags = flags;
+       qh->inst = inst;
+       id = inst->id - inst->qmgr->start_queue;
+       qh->reg_push = &inst->qmgr->reg_push[id];
+       qh->reg_pop = &inst->qmgr->reg_pop[id];
+       qh->reg_peek = &inst->qmgr->reg_peek[id];
+
+       /* first opener? */
+       if (!knav_queue_is_busy(inst)) {
+               struct knav_range_info *range = inst->range;
+
+               inst->name = kstrndup(name, KNAV_NAME_SIZE, GFP_KERNEL);
+               if (range->ops && range->ops->open_queue)
+                       ret = range->ops->open_queue(range, inst, flags);
+
+               if (ret) {
+                       devm_kfree(inst->kdev->dev, qh);
+                       return ERR_PTR(ret);
+               }
+       }
+       list_add_tail_rcu(&qh->list, &inst->handles);
+       return qh;
+}
+
+static struct knav_queue *
+knav_queue_open_by_id(const char *name, unsigned id, unsigned flags)
+{
+       struct knav_queue_inst *inst;
+       struct knav_queue *qh;
+
+       mutex_lock(&knav_dev_lock);
+
+       qh = ERR_PTR(-ENODEV);
+       inst = knav_queue_find_by_id(id);
+       if (!inst)
+               goto unlock_ret;
+
+       qh = ERR_PTR(-EEXIST);
+       if (!(flags & KNAV_QUEUE_SHARED) && knav_queue_is_busy(inst))
+               goto unlock_ret;
+
+       qh = ERR_PTR(-EBUSY);
+       if ((flags & KNAV_QUEUE_SHARED) &&
+           (knav_queue_is_busy(inst) && !knav_queue_is_shared(inst)))
+               goto unlock_ret;
+
+       qh = __knav_queue_open(inst, name, flags);
+
+unlock_ret:
+       mutex_unlock(&knav_dev_lock);
+
+       return qh;
+}
+
+static struct knav_queue *knav_queue_open_by_type(const char *name,
+                                               unsigned type, unsigned flags)
+{
+       struct knav_queue_inst *inst;
+       struct knav_queue *qh = ERR_PTR(-EINVAL);
+       int idx;
+
+       mutex_lock(&knav_dev_lock);
+
+       for_each_instance(idx, inst, kdev) {
+               if (knav_queue_is_reserved(inst))
+                       continue;
+               if (!knav_queue_match_type(inst, type))
+                       continue;
+               if (knav_queue_is_busy(inst))
+                       continue;
+               qh = __knav_queue_open(inst, name, flags);
+               goto unlock_ret;
+       }
+
+unlock_ret:
+       mutex_unlock(&knav_dev_lock);
+       return qh;
+}
+
+static void knav_queue_set_notify(struct knav_queue_inst *inst, bool enabled)
+{
+       struct knav_range_info *range = inst->range;
+
+       if (range->ops && range->ops->set_notify)
+               range->ops->set_notify(range, inst, enabled);
+}
+
+static int knav_queue_enable_notifier(struct knav_queue *qh)
+{
+       struct knav_queue_inst *inst = qh->inst;
+       bool first;
+
+       if (WARN_ON(!qh->notifier_fn))
+               return -EINVAL;
+
+       /* Adjust the per handle notifier count */
+       first = (atomic_inc_return(&qh->notifier_enabled) == 1);
+       if (!first)
+               return 0; /* nothing to do */
+
+       /* Now adjust the per instance notifier count */
+       first = (atomic_inc_return(&inst->num_notifiers) == 1);
+       if (first)
+               knav_queue_set_notify(inst, true);
+
+       return 0;
+}
+
+static int knav_queue_disable_notifier(struct knav_queue *qh)
+{
+       struct knav_queue_inst *inst = qh->inst;
+       bool last;
+
+       last = (atomic_dec_return(&qh->notifier_enabled) == 0);
+       if (!last)
+               return 0; /* nothing to do */
+
+       last = (atomic_dec_return(&inst->num_notifiers) == 0);
+       if (last)
+               knav_queue_set_notify(inst, false);
+
+       return 0;
+}
+
+static int knav_queue_set_notifier(struct knav_queue *qh,
+                               struct knav_queue_notify_config *cfg)
+{
+       knav_queue_notify_fn old_fn = qh->notifier_fn;
+
+       if (!cfg)
+               return -EINVAL;
+
+       if (!(qh->inst->range->flags & (RANGE_HAS_ACCUMULATOR | RANGE_HAS_IRQ)))
+               return -ENOTSUPP;
+
+       if (!cfg->fn && old_fn)
+               knav_queue_disable_notifier(qh);
+
+       qh->notifier_fn = cfg->fn;
+       qh->notifier_fn_arg = cfg->fn_arg;
+
+       if (cfg->fn && !old_fn)
+               knav_queue_enable_notifier(qh);
+
+       return 0;
+}
+
+static int knav_gp_set_notify(struct knav_range_info *range,
+                              struct knav_queue_inst *inst,
+                              bool enabled)
+{
+       unsigned queue;
+
+       if (range->flags & RANGE_HAS_IRQ) {
+               queue = inst->id - range->queue_base;
+               if (enabled)
+                       enable_irq(range->irqs[queue].irq);
+               else
+                       disable_irq_nosync(range->irqs[queue].irq);
+       }
+       return 0;
+}
+
+static int knav_gp_open_queue(struct knav_range_info *range,
+                               struct knav_queue_inst *inst, unsigned flags)
+{
+       return knav_queue_setup_irq(range, inst);
+}
+
+static int knav_gp_close_queue(struct knav_range_info *range,
+                               struct knav_queue_inst *inst)
+{
+       knav_queue_free_irq(inst);
+       return 0;
+}
+
+struct knav_range_ops knav_gp_range_ops = {
+       .set_notify     = knav_gp_set_notify,
+       .open_queue     = knav_gp_open_queue,
+       .close_queue    = knav_gp_close_queue,
+};
+
+
+static int knav_queue_get_count(void *qhandle)
+{
+       struct knav_queue *qh = qhandle;
+       struct knav_queue_inst *inst = qh->inst;
+
+       return readl_relaxed(&qh->reg_peek[0].entry_count) +
+               atomic_read(&inst->desc_count);
+}
+
+static void knav_queue_debug_show_instance(struct seq_file *s,
+                                       struct knav_queue_inst *inst)
+{
+       struct knav_device *kdev = inst->kdev;
+       struct knav_queue *qh;
+
+       if (!knav_queue_is_busy(inst))
+               return;
+
+       seq_printf(s, "\tqueue id %d (%s)\n",
+                  kdev->base_id + inst->id, inst->name);
+       for_each_handle_rcu(qh, inst) {
+               seq_printf(s, "\t\thandle %p: ", qh);
+               seq_printf(s, "pushes %8d, ",
+                          atomic_read(&qh->stats.pushes));
+               seq_printf(s, "pops %8d, ",
+                          atomic_read(&qh->stats.pops));
+               seq_printf(s, "count %8d, ",
+                          knav_queue_get_count(qh));
+               seq_printf(s, "notifies %8d, ",
+                          atomic_read(&qh->stats.notifies));
+               seq_printf(s, "push errors %8d, ",
+                          atomic_read(&qh->stats.push_errors));
+               seq_printf(s, "pop errors %8d\n",
+                          atomic_read(&qh->stats.pop_errors));
+       }
+}
+
+static int knav_queue_debug_show(struct seq_file *s, void *v)
+{
+       struct knav_queue_inst *inst;
+       int idx;
+
+       mutex_lock(&knav_dev_lock);
+       seq_printf(s, "%s: %u-%u\n",
+                  dev_name(kdev->dev), kdev->base_id,
+                  kdev->base_id + kdev->num_queues - 1);
+       for_each_instance(idx, inst, kdev)
+               knav_queue_debug_show_instance(s, inst);
+       mutex_unlock(&knav_dev_lock);
+
+       return 0;
+}
+
+static int knav_queue_debug_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, knav_queue_debug_show, NULL);
+}
+
+static const struct file_operations knav_queue_debug_ops = {
+       .open           = knav_queue_debug_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
+static inline int knav_queue_pdsp_wait(u32 * __iomem addr, unsigned timeout,
+                                       u32 flags)
+{
+       unsigned long end;
+       u32 val = 0;
+
+       end = jiffies + msecs_to_jiffies(timeout);
+       while (time_after(end, jiffies)) {
+               val = readl_relaxed(addr);
+               if (flags)
+                       val &= flags;
+               if (!val)
+                       break;
+               cpu_relax();
+       }
+       return val ? -ETIMEDOUT : 0;
+}
+
+
+static int knav_queue_flush(struct knav_queue *qh)
+{
+       struct knav_queue_inst *inst = qh->inst;
+       unsigned id = inst->id - inst->qmgr->start_queue;
+
+       atomic_set(&inst->desc_count, 0);
+       writel_relaxed(0, &inst->qmgr->reg_push[id].ptr_size_thresh);
+       return 0;
+}
+
+/**
+ * knav_queue_open()   - open a hardware queue
+ * @name               - name to give the queue handle
+ * @id                 - desired queue number if any or specifes the type
+ *                       of queue
+ * @flags              - the following flags are applicable to queues:
+ *     KNAV_QUEUE_SHARED - allow the queue to be shared. Queues are
+ *                          exclusive by default.
+ *                          Subsequent attempts to open a shared queue should
+ *                          also have this flag.
+ *
+ * Returns a handle to the open hardware queue if successful. Use IS_ERR()
+ * to check the returned value for error codes.
+ */
+void *knav_queue_open(const char *name, unsigned id,
+                                       unsigned flags)
+{
+       struct knav_queue *qh = ERR_PTR(-EINVAL);
+
+       switch (id) {
+       case KNAV_QUEUE_QPEND:
+       case KNAV_QUEUE_ACC:
+       case KNAV_QUEUE_GP:
+               qh = knav_queue_open_by_type(name, id, flags);
+               break;
+
+       default:
+               qh = knav_queue_open_by_id(name, id, flags);
+               break;
+       }
+       return qh;
+}
+EXPORT_SYMBOL_GPL(knav_queue_open);
+
+/**
+ * knav_queue_close()  - close a hardware queue handle
+ * @qh                 - handle to close
+ */
+void knav_queue_close(void *qhandle)
+{
+       struct knav_queue *qh = qhandle;
+       struct knav_queue_inst *inst = qh->inst;
+
+       while (atomic_read(&qh->notifier_enabled) > 0)
+               knav_queue_disable_notifier(qh);
+
+       mutex_lock(&knav_dev_lock);
+       list_del_rcu(&qh->list);
+       mutex_unlock(&knav_dev_lock);
+       synchronize_rcu();
+       if (!knav_queue_is_busy(inst)) {
+               struct knav_range_info *range = inst->range;
+
+               if (range->ops && range->ops->close_queue)
+                       range->ops->close_queue(range, inst);
+       }
+       devm_kfree(inst->kdev->dev, qh);
+}
+EXPORT_SYMBOL_GPL(knav_queue_close);
+
+/**
+ * knav_queue_device_control() - Perform control operations on a queue
+ * @qh                         - queue handle
+ * @cmd                                - control commands
+ * @arg                                - command argument
+ *
+ * Returns 0 on success, errno otherwise.
+ */
+int knav_queue_device_control(void *qhandle, enum knav_queue_ctrl_cmd cmd,
+                               unsigned long arg)
+{
+       struct knav_queue *qh = qhandle;
+       struct knav_queue_notify_config *cfg;
+       int ret;
+
+       switch ((int)cmd) {
+       case KNAV_QUEUE_GET_ID:
+               ret = qh->inst->kdev->base_id + qh->inst->id;
+               break;
+
+       case KNAV_QUEUE_FLUSH:
+               ret = knav_queue_flush(qh);
+               break;
+
+       case KNAV_QUEUE_SET_NOTIFIER:
+               cfg = (void *)arg;
+               ret = knav_queue_set_notifier(qh, cfg);
+               break;
+
+       case KNAV_QUEUE_ENABLE_NOTIFY:
+               ret = knav_queue_enable_notifier(qh);
+               break;
+
+       case KNAV_QUEUE_DISABLE_NOTIFY:
+               ret = knav_queue_disable_notifier(qh);
+               break;
+
+       case KNAV_QUEUE_GET_COUNT:
+               ret = knav_queue_get_count(qh);
+               break;
+
+       default:
+               ret = -ENOTSUPP;
+               break;
+       }
+       return ret;
+}
+EXPORT_SYMBOL_GPL(knav_queue_device_control);
+
+
+
+/**
+ * knav_queue_push()   - push data (or descriptor) to the tail of a queue
+ * @qh                 - hardware queue handle
+ * @data               - data to push
+ * @size               - size of data to push
+ * @flags              - can be used to pass additional information
+ *
+ * Returns 0 on success, errno otherwise.
+ */
+int knav_queue_push(void *qhandle, dma_addr_t dma,
+                                       unsigned size, unsigned flags)
+{
+       struct knav_queue *qh = qhandle;
+       u32 val;
+
+       val = (u32)dma | ((size / 16) - 1);
+       writel_relaxed(val, &qh->reg_push[0].ptr_size_thresh);
+
+       atomic_inc(&qh->stats.pushes);
+       return 0;
+}
+
+/**
+ * knav_queue_pop()    - pop data (or descriptor) from the head of a queue
+ * @qh                 - hardware queue handle
+ * @size               - (optional) size of the data pop'ed.
+ *
+ * Returns a DMA address on success, 0 on failure.
+ */
+dma_addr_t knav_queue_pop(void *qhandle, unsigned *size)
+{
+       struct knav_queue *qh = qhandle;
+       struct knav_queue_inst *inst = qh->inst;
+       dma_addr_t dma;
+       u32 val, idx;
+
+       /* are we accumulated? */
+       if (inst->descs) {
+               if (unlikely(atomic_dec_return(&inst->desc_count) < 0)) {
+                       atomic_inc(&inst->desc_count);
+                       return 0;
+               }
+               idx  = atomic_inc_return(&inst->desc_head);
+               idx &= ACC_DESCS_MASK;
+               val = inst->descs[idx];
+       } else {
+               val = readl_relaxed(&qh->reg_pop[0].ptr_size_thresh);
+               if (unlikely(!val))
+                       return 0;
+       }
+
+       dma = val & DESC_PTR_MASK;
+       if (size)
+               *size = ((val & DESC_SIZE_MASK) + 1) * 16;
+
+       atomic_inc(&qh->stats.pops);
+       return dma;
+}
+
+/* carve out descriptors and push into queue */
+static void kdesc_fill_pool(struct knav_pool *pool)
+{
+       struct knav_region *region;
+       int i;
+
+       region = pool->region;
+       pool->desc_size = region->desc_size;
+       for (i = 0; i < pool->num_desc; i++) {
+               int index = pool->region_offset + i;
+               dma_addr_t dma_addr;
+               unsigned dma_size;
+               dma_addr = region->dma_start + (region->desc_size * index);
+               dma_size = ALIGN(pool->desc_size, SMP_CACHE_BYTES);
+               dma_sync_single_for_device(pool->dev, dma_addr, dma_size,
+                                          DMA_TO_DEVICE);
+               knav_queue_push(pool->queue, dma_addr, dma_size, 0);
+       }
+}
+
+/* pop out descriptors and close the queue */
+static void kdesc_empty_pool(struct knav_pool *pool)
+{
+       dma_addr_t dma;
+       unsigned size;
+       void *desc;
+       int i;
+
+       if (!pool->queue)
+               return;
+
+       for (i = 0;; i++) {
+               dma = knav_queue_pop(pool->queue, &size);
+               if (!dma)
+                       break;
+               desc = knav_pool_desc_dma_to_virt(pool, dma);
+               if (!desc) {
+                       dev_dbg(pool->kdev->dev,
+                               "couldn't unmap desc, continuing\n");
+                       continue;
+               }
+       }
+       WARN_ON(i != pool->num_desc);
+       knav_queue_close(pool->queue);
+}
+
+
+/* Get the DMA address of a descriptor */
+dma_addr_t knav_pool_desc_virt_to_dma(void *ph, void *virt)
+{
+       struct knav_pool *pool = ph;
+       return pool->region->dma_start + (virt - pool->region->virt_start);
+}
+
+void *knav_pool_desc_dma_to_virt(void *ph, dma_addr_t dma)
+{
+       struct knav_pool *pool = ph;
+       return pool->region->virt_start + (dma - pool->region->dma_start);
+}
+
+/**
+ * knav_pool_create()  - Create a pool of descriptors
+ * @name               - name to give the pool handle
+ * @num_desc           - numbers of descriptors in the pool
+ * @region_id          - QMSS region id from which the descriptors are to be
+ *                       allocated.
+ *
+ * Returns a pool handle on success.
+ * Use IS_ERR_OR_NULL() to identify error values on return.
+ */
+void *knav_pool_create(const char *name,
+                                       int num_desc, int region_id)
+{
+       struct knav_region *reg_itr, *region = NULL;
+       struct knav_pool *pool, *pi;
+       struct list_head *node;
+       unsigned last_offset;
+       bool slot_found;
+       int ret;
+
+       if (!kdev->dev)
+               return ERR_PTR(-ENODEV);
+
+       pool = devm_kzalloc(kdev->dev, sizeof(*pool), GFP_KERNEL);
+       if (!pool) {
+               dev_err(kdev->dev, "out of memory allocating pool\n");
+               return ERR_PTR(-ENOMEM);
+       }
+
+       for_each_region(kdev, reg_itr) {
+               if (reg_itr->id != region_id)
+                       continue;
+               region = reg_itr;
+               break;
+       }
+
+       if (!region) {
+               dev_err(kdev->dev, "region-id(%d) not found\n", region_id);
+               ret = -EINVAL;
+               goto err;
+       }
+
+       pool->queue = knav_queue_open(name, KNAV_QUEUE_GP, 0);
+       if (IS_ERR_OR_NULL(pool->queue)) {
+               dev_err(kdev->dev,
+                       "failed to open queue for pool(%s), error %ld\n",
+                       name, PTR_ERR(pool->queue));
+               ret = PTR_ERR(pool->queue);
+               goto err;
+       }
+
+       pool->name = kstrndup(name, KNAV_NAME_SIZE, GFP_KERNEL);
+       pool->kdev = kdev;
+       pool->dev = kdev->dev;
+
+       mutex_lock(&knav_dev_lock);
+
+       if (num_desc > (region->num_desc - region->used_desc)) {
+               dev_err(kdev->dev, "out of descs in region(%d) for pool(%s)\n",
+                       region_id, name);
+               ret = -ENOMEM;
+               goto err;
+       }
+
+       /* Region maintains a sorted (by region offset) list of pools
+        * use the first free slot which is large enough to accomodate
+        * the request
+        */
+       last_offset = 0;
+       slot_found = false;
+       node = &region->pools;
+       list_for_each_entry(pi, &region->pools, region_inst) {
+               if ((pi->region_offset - last_offset) >= num_desc) {
+                       slot_found = true;
+                       break;
+               }
+               last_offset = pi->region_offset + pi->num_desc;
+       }
+       node = &pi->region_inst;
+
+       if (slot_found) {
+               pool->region = region;
+               pool->num_desc = num_desc;
+               pool->region_offset = last_offset;
+               region->used_desc += num_desc;
+               list_add_tail(&pool->list, &kdev->pools);
+               list_add_tail(&pool->region_inst, node);
+       } else {
+               dev_err(kdev->dev, "pool(%s) create failed: fragmented desc pool in region(%d)\n",
+                       name, region_id);
+               ret = -ENOMEM;
+               goto err;
+       }
+
+       mutex_unlock(&knav_dev_lock);
+       kdesc_fill_pool(pool);
+       return pool;
+
+err:
+       mutex_unlock(&knav_dev_lock);
+       kfree(pool->name);
+       devm_kfree(kdev->dev, pool);
+       return ERR_PTR(ret);
+}
+EXPORT_SYMBOL_GPL(knav_pool_create);
+
+/**
+ * knav_pool_destroy() - Free a pool of descriptors
+ * @pool               - pool handle
+ */
+void knav_pool_destroy(void *ph)
+{
+       struct knav_pool *pool = ph;
+
+       if (!pool)
+               return;
+
+       if (!pool->region)
+               return;
+
+       kdesc_empty_pool(pool);
+       mutex_lock(&knav_dev_lock);
+
+       pool->region->used_desc -= pool->num_desc;
+       list_del(&pool->region_inst);
+       list_del(&pool->list);
+
+       mutex_unlock(&knav_dev_lock);
+       kfree(pool->name);
+       devm_kfree(kdev->dev, pool);
+}
+EXPORT_SYMBOL_GPL(knav_pool_destroy);
+
+
+/**
+ * knav_pool_desc_get()        - Get a descriptor from the pool
+ * @pool                       - pool handle
+ *
+ * Returns descriptor from the pool.
+ */
+void *knav_pool_desc_get(void *ph)
+{
+       struct knav_pool *pool = ph;
+       dma_addr_t dma;
+       unsigned size;
+       void *data;
+
+       dma = knav_queue_pop(pool->queue, &size);
+       if (unlikely(!dma))
+               return ERR_PTR(-ENOMEM);
+       data = knav_pool_desc_dma_to_virt(pool, dma);
+       return data;
+}
+
+/**
+ * knav_pool_desc_put()        - return a descriptor to the pool
+ * @pool                       - pool handle
+ */
+void knav_pool_desc_put(void *ph, void *desc)
+{
+       struct knav_pool *pool = ph;
+       dma_addr_t dma;
+       dma = knav_pool_desc_virt_to_dma(pool, desc);
+       knav_queue_push(pool->queue, dma, pool->region->desc_size, 0);
+}
+
+/**
+ * knav_pool_desc_map()        - Map descriptor for DMA transfer
+ * @pool                       - pool handle
+ * @desc                       - address of descriptor to map
+ * @size                       - size of descriptor to map
+ * @dma                                - DMA address return pointer
+ * @dma_sz                     - adjusted return pointer
+ *
+ * Returns 0 on success, errno otherwise.
+ */
+int knav_pool_desc_map(void *ph, void *desc, unsigned size,
+                                       dma_addr_t *dma, unsigned *dma_sz)
+{
+       struct knav_pool *pool = ph;
+       *dma = knav_pool_desc_virt_to_dma(pool, desc);
+       size = min(size, pool->region->desc_size);
+       size = ALIGN(size, SMP_CACHE_BYTES);
+       *dma_sz = size;
+       dma_sync_single_for_device(pool->dev, *dma, size, DMA_TO_DEVICE);
+
+       /* Ensure the descriptor reaches to the memory */
+       __iowmb();
+
+       return 0;
+}
+
+/**
+ * knav_pool_desc_unmap()      - Unmap descriptor after DMA transfer
+ * @pool                       - pool handle
+ * @dma                                - DMA address of descriptor to unmap
+ * @dma_sz                     - size of descriptor to unmap
+ *
+ * Returns descriptor address on success, Use IS_ERR_OR_NULL() to identify
+ * error values on return.
+ */
+void *knav_pool_desc_unmap(void *ph, dma_addr_t dma, unsigned dma_sz)
+{
+       struct knav_pool *pool = ph;
+       unsigned desc_sz;
+       void *desc;
+
+       desc_sz = min(dma_sz, pool->region->desc_size);
+       desc = knav_pool_desc_dma_to_virt(pool, dma);
+       dma_sync_single_for_cpu(pool->dev, dma, desc_sz, DMA_FROM_DEVICE);
+       prefetch(desc);
+       return desc;
+}
+
+/**
+ * knav_pool_count()   - Get the number of descriptors in pool.
+ * @pool               - pool handle
+ * Returns number of elements in the pool.
+ */
+int knav_pool_count(void *ph)
+{
+       struct knav_pool *pool = ph;
+       return knav_queue_get_count(pool->queue);
+}
+
+static void knav_queue_setup_region(struct knav_device *kdev,
+                                       struct knav_region *region)
+{
+       unsigned hw_num_desc, hw_desc_size, size;
+       struct knav_reg_region __iomem  *regs;
+       struct knav_qmgr_info *qmgr;
+       struct knav_pool *pool;
+       int id = region->id;
+       struct page *page;
+
+       /* unused region? */
+       if (!region->num_desc) {
+               dev_warn(kdev->dev, "unused region %s\n", region->name);
+               return;
+       }
+
+       /* get hardware descriptor value */
+       hw_num_desc = ilog2(region->num_desc - 1) + 1;
+
+       /* did we force fit ourselves into nothingness? */
+       if (region->num_desc < 32) {
+               region->num_desc = 0;
+               dev_warn(kdev->dev, "too few descriptors in region %s\n",
+                        region->name);
+               return;
+       }
+
+       size = region->num_desc * region->desc_size;
+       region->virt_start = alloc_pages_exact(size, GFP_KERNEL | GFP_DMA |
+                                               GFP_DMA32);
+       if (!region->virt_start) {
+               region->num_desc = 0;
+               dev_err(kdev->dev, "memory alloc failed for region %s\n",
+                       region->name);
+               return;
+       }
+       region->virt_end = region->virt_start + size;
+       page = virt_to_page(region->virt_start);
+
+       region->dma_start = dma_map_page(kdev->dev, page, 0, size,
+                                        DMA_BIDIRECTIONAL);
+       if (dma_mapping_error(kdev->dev, region->dma_start)) {
+               dev_err(kdev->dev, "dma map failed for region %s\n",
+                       region->name);
+               goto fail;
+       }
+       region->dma_end = region->dma_start + size;
+
+       pool = devm_kzalloc(kdev->dev, sizeof(*pool), GFP_KERNEL);
+       if (!pool) {
+               dev_err(kdev->dev, "out of memory allocating dummy pool\n");
+               goto fail;
+       }
+       pool->num_desc = 0;
+       pool->region_offset = region->num_desc;
+       list_add(&pool->region_inst, &region->pools);
+
+       dev_dbg(kdev->dev,
+               "region %s (%d): size:%d, link:%d@%d, phys:%08x-%08x, virt:%p-%p\n",
+               region->name, id, region->desc_size, region->num_desc,
+               region->link_index, region->dma_start, region->dma_end,
+               region->virt_start, region->virt_end);
+
+       hw_desc_size = (region->desc_size / 16) - 1;
+       hw_num_desc -= 5;
+
+       for_each_qmgr(kdev, qmgr) {
+               regs = qmgr->reg_region + id;
+               writel_relaxed(region->dma_start, &regs->base);
+               writel_relaxed(region->link_index, &regs->start_index);
+               writel_relaxed(hw_desc_size << 16 | hw_num_desc,
+                              &regs->size_count);
+       }
+       return;
+
+fail:
+       if (region->dma_start)
+               dma_unmap_page(kdev->dev, region->dma_start, size,
+                               DMA_BIDIRECTIONAL);
+       if (region->virt_start)
+               free_pages_exact(region->virt_start, size);
+       region->num_desc = 0;
+       return;
+}
+
+static const char *knav_queue_find_name(struct device_node *node)
+{
+       const char *name;
+
+       if (of_property_read_string(node, "label", &name) < 0)
+               name = node->name;
+       if (!name)
+               name = "unknown";
+       return name;
+}
+
+static int knav_queue_setup_regions(struct knav_device *kdev,
+                                       struct device_node *regions)
+{
+       struct device *dev = kdev->dev;
+       struct knav_region *region;
+       struct device_node *child;
+       u32 temp[2];
+       int ret;
+
+       for_each_child_of_node(regions, child) {
+               region = devm_kzalloc(dev, sizeof(*region), GFP_KERNEL);
+               if (!region) {
+                       dev_err(dev, "out of memory allocating region\n");
+                       return -ENOMEM;
+               }
+
+               region->name = knav_queue_find_name(child);
+               of_property_read_u32(child, "id", &region->id);
+               ret = of_property_read_u32_array(child, "region-spec", temp, 2);
+               if (!ret) {
+                       region->num_desc  = temp[0];
+                       region->desc_size = temp[1];
+               } else {
+                       dev_err(dev, "invalid region info %s\n", region->name);
+                       devm_kfree(dev, region);
+                       continue;
+               }
+
+               if (!of_get_property(child, "link-index", NULL)) {
+                       dev_err(dev, "No link info for %s\n", region->name);
+                       devm_kfree(dev, region);
+                       continue;
+               }
+               ret = of_property_read_u32(child, "link-index",
+                                          &region->link_index);
+               if (ret) {
+                       dev_err(dev, "link index not found for %s\n",
+                               region->name);
+                       devm_kfree(dev, region);
+                       continue;
+               }
+
+               INIT_LIST_HEAD(&region->pools);
+               list_add_tail(&region->list, &kdev->regions);
+       }
+       if (list_empty(&kdev->regions)) {
+               dev_err(dev, "no valid region information found\n");
+               return -ENODEV;
+       }
+
+       /* Next, we run through the regions and set things up */
+       for_each_region(kdev, region)
+               knav_queue_setup_region(kdev, region);
+
+       return 0;
+}
+
+static int knav_get_link_ram(struct knav_device *kdev,
+                                      const char *name,
+                                      struct knav_link_ram_block *block)
+{
+       struct platform_device *pdev = to_platform_device(kdev->dev);
+       struct device_node *node = pdev->dev.of_node;
+       u32 temp[2];
+
+       /*
+        * Note: link ram resources are specified in "entry" sized units. In
+        * reality, although entries are ~40bits in hardware, we treat them as
+        * 64-bit entities here.
+        *
+        * For example, to specify the internal link ram for Keystone-I class
+        * devices, we would set the linkram0 resource to 0x80000-0x83fff.
+        *
+        * This gets a bit weird when other link rams are used.  For example,
+        * if the range specified is 0x0c000000-0x0c003fff (i.e., 16K entries
+        * in MSMC SRAM), the actual memory used is 0x0c000000-0x0c020000,
+        * which accounts for 64-bits per entry, for 16K entries.
+        */
+       if (!of_property_read_u32_array(node, name , temp, 2)) {
+               if (temp[0]) {
+                       /*
+                        * queue_base specified => using internal or onchip
+                        * link ram WARNING - we do not "reserve" this block
+                        */
+                       block->phys = (dma_addr_t)temp[0];
+                       block->virt = NULL;
+                       block->size = temp[1];
+               } else {
+                       block->size = temp[1];
+                       /* queue_base not specific => allocate requested size */
+                       block->virt = dmam_alloc_coherent(kdev->dev,
+                                                 8 * block->size, &block->phys,
+                                                 GFP_KERNEL);
+                       if (!block->virt) {
+                               dev_err(kdev->dev, "failed to alloc linkram\n");
+                               return -ENOMEM;
+                       }
+               }
+       } else {
+               return -ENODEV;
+       }
+       return 0;
+}
+
+static int knav_queue_setup_link_ram(struct knav_device *kdev)
+{
+       struct knav_link_ram_block *block;
+       struct knav_qmgr_info *qmgr;
+
+       for_each_qmgr(kdev, qmgr) {
+               block = &kdev->link_rams[0];
+               dev_dbg(kdev->dev, "linkram0: phys:%x, virt:%p, size:%x\n",
+                       block->phys, block->virt, block->size);
+               writel_relaxed(block->phys, &qmgr->reg_config->link_ram_base0);
+               writel_relaxed(block->size, &qmgr->reg_config->link_ram_size0);
+
+               block++;
+               if (!block->size)
+                       return 0;
+
+               dev_dbg(kdev->dev, "linkram1: phys:%x, virt:%p, size:%x\n",
+                       block->phys, block->virt, block->size);
+               writel_relaxed(block->phys, &qmgr->reg_config->link_ram_base1);
+       }
+
+       return 0;
+}
+
+static int knav_setup_queue_range(struct knav_device *kdev,
+                                       struct device_node *node)
+{
+       struct device *dev = kdev->dev;
+       struct knav_range_info *range;
+       struct knav_qmgr_info *qmgr;
+       u32 temp[2], start, end, id, index;
+       int ret, i;
+
+       range = devm_kzalloc(dev, sizeof(*range), GFP_KERNEL);
+       if (!range) {
+               dev_err(dev, "out of memory allocating range\n");
+               return -ENOMEM;
+       }
+
+       range->kdev = kdev;
+       range->name = knav_queue_find_name(node);
+       ret = of_property_read_u32_array(node, "qrange", temp, 2);
+       if (!ret) {
+               range->queue_base = temp[0] - kdev->base_id;
+               range->num_queues = temp[1];
+       } else {
+               dev_err(dev, "invalid queue range %s\n", range->name);
+               devm_kfree(dev, range);
+               return -EINVAL;
+       }
+
+       for (i = 0; i < RANGE_MAX_IRQS; i++) {
+               struct of_phandle_args oirq;
+
+               if (of_irq_parse_one(node, i, &oirq))
+                       break;
+
+               range->irqs[i].irq = irq_create_of_mapping(&oirq);
+               if (range->irqs[i].irq == IRQ_NONE)
+                       break;
+
+               range->num_irqs++;
+
+               if (oirq.args_count == 3)
+                       range->irqs[i].cpu_map =
+                               (oirq.args[2] & 0x0000ff00) >> 8;
+       }
+
+       range->num_irqs = min(range->num_irqs, range->num_queues);
+       if (range->num_irqs)
+               range->flags |= RANGE_HAS_IRQ;
+
+       if (of_get_property(node, "qalloc-by-id", NULL))
+               range->flags |= RANGE_RESERVED;
+
+       if (of_get_property(node, "accumulator", NULL)) {
+               ret = knav_init_acc_range(kdev, node, range);
+               if (ret < 0) {
+                       devm_kfree(dev, range);
+                       return ret;
+               }
+       } else {
+               range->ops = &knav_gp_range_ops;
+       }
+
+       /* set threshold to 1, and flush out the queues */
+       for_each_qmgr(kdev, qmgr) {
+               start = max(qmgr->start_queue, range->queue_base);
+               end   = min(qmgr->start_queue + qmgr->num_queues,
+                           range->queue_base + range->num_queues);
+               for (id = start; id < end; id++) {
+                       index = id - qmgr->start_queue;
+                       writel_relaxed(THRESH_GTE | 1,
+                                      &qmgr->reg_peek[index].ptr_size_thresh);
+                       writel_relaxed(0,
+                                      &qmgr->reg_push[index].ptr_size_thresh);
+               }
+       }
+
+       list_add_tail(&range->list, &kdev->queue_ranges);
+       dev_dbg(dev, "added range %s: %d-%d, %d irqs%s%s%s\n",
+               range->name, range->queue_base,
+               range->queue_base + range->num_queues - 1,
+               range->num_irqs,
+               (range->flags & RANGE_HAS_IRQ) ? ", has irq" : "",
+               (range->flags & RANGE_RESERVED) ? ", reserved" : "",
+               (range->flags & RANGE_HAS_ACCUMULATOR) ? ", acc" : "");
+       kdev->num_queues_in_use += range->num_queues;
+       return 0;
+}
+
+static int knav_setup_queue_pools(struct knav_device *kdev,
+                                  struct device_node *queue_pools)
+{
+       struct device_node *type, *range;
+       int ret;
+
+       for_each_child_of_node(queue_pools, type) {
+               for_each_child_of_node(type, range) {
+                       ret = knav_setup_queue_range(kdev, range);
+                       /* return value ignored, we init the rest... */
+               }
+       }
+
+       /* ... and barf if they all failed! */
+       if (list_empty(&kdev->queue_ranges)) {
+               dev_err(kdev->dev, "no valid queue range found\n");
+               return -ENODEV;
+       }
+       return 0;
+}
+
+static void knav_free_queue_range(struct knav_device *kdev,
+                                 struct knav_range_info *range)
+{
+       if (range->ops && range->ops->free_range)
+               range->ops->free_range(range);
+       list_del(&range->list);
+       devm_kfree(kdev->dev, range);
+}
+
+static void knav_free_queue_ranges(struct knav_device *kdev)
+{
+       struct knav_range_info *range;
+
+       for (;;) {
+               range = first_queue_range(kdev);
+               if (!range)
+                       break;
+               knav_free_queue_range(kdev, range);
+       }
+}
+
+static void knav_queue_free_regions(struct knav_device *kdev)
+{
+       struct knav_region *region;
+       struct knav_pool *pool;
+       unsigned size;
+
+       for (;;) {
+               region = first_region(kdev);
+               if (!region)
+                       break;
+               list_for_each_entry(pool, &region->pools, region_inst)
+                       knav_pool_destroy(pool);
+
+               size = region->virt_end - region->virt_start;
+               if (size)
+                       free_pages_exact(region->virt_start, size);
+               list_del(&region->list);
+               devm_kfree(kdev->dev, region);
+       }
+}
+
+static void __iomem *knav_queue_map_reg(struct knav_device *kdev,
+                                       struct device_node *node, int index)
+{
+       struct resource res;
+       void __iomem *regs;
+       int ret;
+
+       ret = of_address_to_resource(node, index, &res);
+       if (ret) {
+               dev_err(kdev->dev, "Can't translate of node(%s) address for index(%d)\n",
+                       node->name, index);
+               return ERR_PTR(ret);
+       }
+
+       regs = devm_ioremap_resource(kdev->dev, &res);
+       if (IS_ERR(regs))
+               dev_err(kdev->dev, "Failed to map register base for index(%d) node(%s)\n",
+                       index, node->name);
+       return regs;
+}
+
+static int knav_queue_init_qmgrs(struct knav_device *kdev,
+                                       struct device_node *qmgrs)
+{
+       struct device *dev = kdev->dev;
+       struct knav_qmgr_info *qmgr;
+       struct device_node *child;
+       u32 temp[2];
+       int ret;
+
+       for_each_child_of_node(qmgrs, child) {
+               qmgr = devm_kzalloc(dev, sizeof(*qmgr), GFP_KERNEL);
+               if (!qmgr) {
+                       dev_err(dev, "out of memory allocating qmgr\n");
+                       return -ENOMEM;
+               }
+
+               ret = of_property_read_u32_array(child, "managed-queues",
+                                                temp, 2);
+               if (!ret) {
+                       qmgr->start_queue = temp[0];
+                       qmgr->num_queues = temp[1];
+               } else {
+                       dev_err(dev, "invalid qmgr queue range\n");
+                       devm_kfree(dev, qmgr);
+                       continue;
+               }
+
+               dev_info(dev, "qmgr start queue %d, number of queues %d\n",
+                        qmgr->start_queue, qmgr->num_queues);
+
+               qmgr->reg_peek =
+                       knav_queue_map_reg(kdev, child,
+                                          KNAV_QUEUE_PEEK_REG_INDEX);
+               qmgr->reg_status =
+                       knav_queue_map_reg(kdev, child,
+                                          KNAV_QUEUE_STATUS_REG_INDEX);
+               qmgr->reg_config =
+                       knav_queue_map_reg(kdev, child,
+                                          KNAV_QUEUE_CONFIG_REG_INDEX);
+               qmgr->reg_region =
+                       knav_queue_map_reg(kdev, child,
+                                          KNAV_QUEUE_REGION_REG_INDEX);
+               qmgr->reg_push =
+                       knav_queue_map_reg(kdev, child,
+                                          KNAV_QUEUE_PUSH_REG_INDEX);
+               qmgr->reg_pop =
+                       knav_queue_map_reg(kdev, child,
+                                          KNAV_QUEUE_POP_REG_INDEX);
+
+               if (IS_ERR(qmgr->reg_peek) || IS_ERR(qmgr->reg_status) ||
+                   IS_ERR(qmgr->reg_config) || IS_ERR(qmgr->reg_region) ||
+                   IS_ERR(qmgr->reg_push) || IS_ERR(qmgr->reg_pop)) {
+                       dev_err(dev, "failed to map qmgr regs\n");
+                       if (!IS_ERR(qmgr->reg_peek))
+                               devm_iounmap(dev, qmgr->reg_peek);
+                       if (!IS_ERR(qmgr->reg_status))
+                               devm_iounmap(dev, qmgr->reg_status);
+                       if (!IS_ERR(qmgr->reg_config))
+                               devm_iounmap(dev, qmgr->reg_config);
+                       if (!IS_ERR(qmgr->reg_region))
+                               devm_iounmap(dev, qmgr->reg_region);
+                       if (!IS_ERR(qmgr->reg_push))
+                               devm_iounmap(dev, qmgr->reg_push);
+                       if (!IS_ERR(qmgr->reg_pop))
+                               devm_iounmap(dev, qmgr->reg_pop);
+                       devm_kfree(dev, qmgr);
+                       continue;
+               }
+
+               list_add_tail(&qmgr->list, &kdev->qmgrs);
+               dev_info(dev, "added qmgr start queue %d, num of queues %d, reg_peek %p, reg_status %p, reg_config %p, reg_region %p, reg_push %p, reg_pop %p\n",
+                        qmgr->start_queue, qmgr->num_queues,
+                        qmgr->reg_peek, qmgr->reg_status,
+                        qmgr->reg_config, qmgr->reg_region,
+                        qmgr->reg_push, qmgr->reg_pop);
+       }
+       return 0;
+}
+
+static int knav_queue_init_pdsps(struct knav_device *kdev,
+                                       struct device_node *pdsps)
+{
+       struct device *dev = kdev->dev;
+       struct knav_pdsp_info *pdsp;
+       struct device_node *child;
+       int ret;
+
+       for_each_child_of_node(pdsps, child) {
+               pdsp = devm_kzalloc(dev, sizeof(*pdsp), GFP_KERNEL);
+               if (!pdsp) {
+                       dev_err(dev, "out of memory allocating pdsp\n");
+                       return -ENOMEM;
+               }
+               pdsp->name = knav_queue_find_name(child);
+               ret = of_property_read_string(child, "firmware",
+                                             &pdsp->firmware);
+               if (ret < 0 || !pdsp->firmware) {
+                       dev_err(dev, "unknown firmware for pdsp %s\n",
+                               pdsp->name);
+                       devm_kfree(dev, pdsp);
+                       continue;
+               }
+               dev_dbg(dev, "pdsp name %s fw name :%s\n", pdsp->name,
+                       pdsp->firmware);
+
+               pdsp->iram =
+                       knav_queue_map_reg(kdev, child,
+                                          KNAV_QUEUE_PDSP_IRAM_REG_INDEX);
+               pdsp->regs =
+                       knav_queue_map_reg(kdev, child,
+                                          KNAV_QUEUE_PDSP_REGS_REG_INDEX);
+               pdsp->intd =
+                       knav_queue_map_reg(kdev, child,
+                                          KNAV_QUEUE_PDSP_INTD_REG_INDEX);
+               pdsp->command =
+                       knav_queue_map_reg(kdev, child,
+                                          KNAV_QUEUE_PDSP_CMD_REG_INDEX);
+
+               if (IS_ERR(pdsp->command) || IS_ERR(pdsp->iram) ||
+                   IS_ERR(pdsp->regs) || IS_ERR(pdsp->intd)) {
+                       dev_err(dev, "failed to map pdsp %s regs\n",
+                               pdsp->name);
+                       if (!IS_ERR(pdsp->command))
+                               devm_iounmap(dev, pdsp->command);
+                       if (!IS_ERR(pdsp->iram))
+                               devm_iounmap(dev, pdsp->iram);
+                       if (!IS_ERR(pdsp->regs))
+                               devm_iounmap(dev, pdsp->regs);
+                       if (!IS_ERR(pdsp->intd))
+                               devm_iounmap(dev, pdsp->intd);
+                       devm_kfree(dev, pdsp);
+                       continue;
+               }
+               of_property_read_u32(child, "id", &pdsp->id);
+               list_add_tail(&pdsp->list, &kdev->pdsps);
+               dev_dbg(dev, "added pdsp %s: command %p, iram %p, regs %p, intd %p, firmware %s\n",
+                       pdsp->name, pdsp->command, pdsp->iram, pdsp->regs,
+                       pdsp->intd, pdsp->firmware);
+       }
+       return 0;
+}
+
+static int knav_queue_stop_pdsp(struct knav_device *kdev,
+                         struct knav_pdsp_info *pdsp)
+{
+       u32 val, timeout = 1000;
+       int ret;
+
+       val = readl_relaxed(&pdsp->regs->control) & ~PDSP_CTRL_ENABLE;
+       writel_relaxed(val, &pdsp->regs->control);
+       ret = knav_queue_pdsp_wait(&pdsp->regs->control, timeout,
+                                       PDSP_CTRL_RUNNING);
+       if (ret < 0) {
+               dev_err(kdev->dev, "timed out on pdsp %s stop\n", pdsp->name);
+               return ret;
+       }
+       return 0;
+}
+
+static int knav_queue_load_pdsp(struct knav_device *kdev,
+                         struct knav_pdsp_info *pdsp)
+{
+       int i, ret, fwlen;
+       const struct firmware *fw;
+       u32 *fwdata;
+
+       ret = request_firmware(&fw, pdsp->firmware, kdev->dev);
+       if (ret) {
+               dev_err(kdev->dev, "failed to get firmware %s for pdsp %s\n",
+                       pdsp->firmware, pdsp->name);
+               return ret;
+       }
+       writel_relaxed(pdsp->id + 1, pdsp->command + 0x18);
+       /* download the firmware */
+       fwdata = (u32 *)fw->data;
+       fwlen = (fw->size + sizeof(u32) - 1) / sizeof(u32);
+       for (i = 0; i < fwlen; i++)
+               writel_relaxed(be32_to_cpu(fwdata[i]), pdsp->iram + i);
+
+       release_firmware(fw);
+       return 0;
+}
+
+static int knav_queue_start_pdsp(struct knav_device *kdev,
+                          struct knav_pdsp_info *pdsp)
+{
+       u32 val, timeout = 1000;
+       int ret;
+
+       /* write a command for sync */
+       writel_relaxed(0xffffffff, pdsp->command);
+       while (readl_relaxed(pdsp->command) != 0xffffffff)
+               cpu_relax();
+
+       /* soft reset the PDSP */
+       val  = readl_relaxed(&pdsp->regs->control);
+       val &= ~(PDSP_CTRL_PC_MASK | PDSP_CTRL_SOFT_RESET);
+       writel_relaxed(val, &pdsp->regs->control);
+
+       /* enable pdsp */
+       val = readl_relaxed(&pdsp->regs->control) | PDSP_CTRL_ENABLE;
+       writel_relaxed(val, &pdsp->regs->control);
+
+       /* wait for command register to clear */
+       ret = knav_queue_pdsp_wait(pdsp->command, timeout, 0);
+       if (ret < 0) {
+               dev_err(kdev->dev,
+                       "timed out on pdsp %s command register wait\n",
+                       pdsp->name);
+               return ret;
+       }
+       return 0;
+}
+
+static void knav_queue_stop_pdsps(struct knav_device *kdev)
+{
+       struct knav_pdsp_info *pdsp;
+
+       /* disable all pdsps */
+       for_each_pdsp(kdev, pdsp)
+               knav_queue_stop_pdsp(kdev, pdsp);
+}
+
+static int knav_queue_start_pdsps(struct knav_device *kdev)
+{
+       struct knav_pdsp_info *pdsp;
+       int ret;
+
+       knav_queue_stop_pdsps(kdev);
+       /* now load them all */
+       for_each_pdsp(kdev, pdsp) {
+               ret = knav_queue_load_pdsp(kdev, pdsp);
+               if (ret < 0)
+                       return ret;
+       }
+
+       for_each_pdsp(kdev, pdsp) {
+               ret = knav_queue_start_pdsp(kdev, pdsp);
+               WARN_ON(ret);
+       }
+       return 0;
+}
+
+static inline struct knav_qmgr_info *knav_find_qmgr(unsigned id)
+{
+       struct knav_qmgr_info *qmgr;
+
+       for_each_qmgr(kdev, qmgr) {
+               if ((id >= qmgr->start_queue) &&
+                   (id < qmgr->start_queue + qmgr->num_queues))
+                       return qmgr;
+       }
+       return NULL;
+}
+
+static int knav_queue_init_queue(struct knav_device *kdev,
+                                       struct knav_range_info *range,
+                                       struct knav_queue_inst *inst,
+                                       unsigned id)
+{
+       char irq_name[KNAV_NAME_SIZE];
+       inst->qmgr = knav_find_qmgr(id);
+       if (!inst->qmgr)
+               return -1;
+
+       INIT_LIST_HEAD(&inst->handles);
+       inst->kdev = kdev;
+       inst->range = range;
+       inst->irq_num = -1;
+       inst->id = id;
+       scnprintf(irq_name, sizeof(irq_name), "hwqueue-%d", id);
+       inst->irq_name = kstrndup(irq_name, sizeof(irq_name), GFP_KERNEL);
+
+       if (range->ops && range->ops->init_queue)
+               return range->ops->init_queue(range, inst);
+       else
+               return 0;
+}
+
+static int knav_queue_init_queues(struct knav_device *kdev)
+{
+       struct knav_range_info *range;
+       int size, id, base_idx;
+       int idx = 0, ret = 0;
+
+       /* how much do we need for instance data? */
+       size = sizeof(struct knav_queue_inst);
+
+       /* round this up to a power of 2, keep the index to instance
+        * arithmetic fast.
+        * */
+       kdev->inst_shift = order_base_2(size);
+       size = (1 << kdev->inst_shift) * kdev->num_queues_in_use;
+       kdev->instances = devm_kzalloc(kdev->dev, size, GFP_KERNEL);
+       if (!kdev->instances)
+               return -1;
+
+       for_each_queue_range(kdev, range) {
+               if (range->ops && range->ops->init_range)
+                       range->ops->init_range(range);
+               base_idx = idx;
+               for (id = range->queue_base;
+                    id < range->queue_base + range->num_queues; id++, idx++) {
+                       ret = knav_queue_init_queue(kdev, range,
+                                       knav_queue_idx_to_inst(kdev, idx), id);
+                       if (ret < 0)
+                               return ret;
+               }
+               range->queue_base_inst =
+                       knav_queue_idx_to_inst(kdev, base_idx);
+       }
+       return 0;
+}
+
+static int knav_queue_probe(struct platform_device *pdev)
+{
+       struct device_node *node = pdev->dev.of_node;
+       struct device_node *qmgrs, *queue_pools, *regions, *pdsps;
+       struct device *dev = &pdev->dev;
+       u32 temp[2];
+       int ret;
+
+       if (!node) {
+               dev_err(dev, "device tree info unavailable\n");
+               return -ENODEV;
+       }
+
+       kdev = devm_kzalloc(dev, sizeof(struct knav_device), GFP_KERNEL);
+       if (!kdev) {
+               dev_err(dev, "memory allocation failed\n");
+               return -ENOMEM;
+       }
+
+       platform_set_drvdata(pdev, kdev);
+       kdev->dev = dev;
+       INIT_LIST_HEAD(&kdev->queue_ranges);
+       INIT_LIST_HEAD(&kdev->qmgrs);
+       INIT_LIST_HEAD(&kdev->pools);
+       INIT_LIST_HEAD(&kdev->regions);
+       INIT_LIST_HEAD(&kdev->pdsps);
+
+       pm_runtime_enable(&pdev->dev);
+       ret = pm_runtime_get_sync(&pdev->dev);
+       if (ret < 0) {
+               dev_err(dev, "Failed to enable QMSS\n");
+               return ret;
+       }
+
+       if (of_property_read_u32_array(node, "queue-range", temp, 2)) {
+               dev_err(dev, "queue-range not specified\n");
+               ret = -ENODEV;
+               goto err;
+       }
+       kdev->base_id    = temp[0];
+       kdev->num_queues = temp[1];
+
+       /* Initialize queue managers using device tree configuration */
+       qmgrs =  of_get_child_by_name(node, "qmgrs");
+       if (!qmgrs) {
+               dev_err(dev, "queue manager info not specified\n");
+               ret = -ENODEV;
+               goto err;
+       }
+       ret = knav_queue_init_qmgrs(kdev, qmgrs);
+       of_node_put(qmgrs);
+       if (ret)
+               goto err;
+
+       /* get pdsp configuration values from device tree */
+       pdsps =  of_get_child_by_name(node, "pdsps");
+       if (pdsps) {
+               ret = knav_queue_init_pdsps(kdev, pdsps);
+               if (ret)
+                       goto err;
+
+               ret = knav_queue_start_pdsps(kdev);
+               if (ret)
+                       goto err;
+       }
+       of_node_put(pdsps);
+
+       /* get usable queue range values from device tree */
+       queue_pools = of_get_child_by_name(node, "queue-pools");
+       if (!queue_pools) {
+               dev_err(dev, "queue-pools not specified\n");
+               ret = -ENODEV;
+               goto err;
+       }
+       ret = knav_setup_queue_pools(kdev, queue_pools);
+       of_node_put(queue_pools);
+       if (ret)
+               goto err;
+
+       ret = knav_get_link_ram(kdev, "linkram0", &kdev->link_rams[0]);
+       if (ret) {
+               dev_err(kdev->dev, "could not setup linking ram\n");
+               goto err;
+       }
+
+       ret = knav_get_link_ram(kdev, "linkram1", &kdev->link_rams[1]);
+       if (ret) {
+               /*
+                * nothing really, we have one linking ram already, so we just
+                * live within our means
+                */
+       }
+
+       ret = knav_queue_setup_link_ram(kdev);
+       if (ret)
+               goto err;
+
+       regions =  of_get_child_by_name(node, "descriptor-regions");
+       if (!regions) {
+               dev_err(dev, "descriptor-regions not specified\n");
+               goto err;
+       }
+       ret = knav_queue_setup_regions(kdev, regions);
+       of_node_put(regions);
+       if (ret)
+               goto err;
+
+       ret = knav_queue_init_queues(kdev);
+       if (ret < 0) {
+               dev_err(dev, "hwqueue initialization failed\n");
+               goto err;
+       }
+
+       debugfs_create_file("qmss", S_IFREG | S_IRUGO, NULL, NULL,
+                           &knav_queue_debug_ops);
+       return 0;
+
+err:
+       knav_queue_stop_pdsps(kdev);
+       knav_queue_free_regions(kdev);
+       knav_free_queue_ranges(kdev);
+       pm_runtime_put_sync(&pdev->dev);
+       pm_runtime_disable(&pdev->dev);
+       return ret;
+}
+
+static int knav_queue_remove(struct platform_device *pdev)
+{
+       /* TODO: Free resources */
+       pm_runtime_put_sync(&pdev->dev);
+       pm_runtime_disable(&pdev->dev);
+       return 0;
+}
+
+/* Match table for of_platform binding */
+static struct of_device_id keystone_qmss_of_match[] = {
+       { .compatible = "ti,keystone-navigator-qmss", },
+       {},
+};
+MODULE_DEVICE_TABLE(of, keystone_qmss_of_match);
+
+static struct platform_driver keystone_qmss_driver = {
+       .probe          = knav_queue_probe,
+       .remove         = knav_queue_remove,
+       .driver         = {
+               .name   = "keystone-navigator-qmss",
+               .owner  = THIS_MODULE,
+               .of_match_table = keystone_qmss_of_match,
+       },
+};
+module_platform_driver(keystone_qmss_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("TI QMSS driver for Keystone SOCs");
+MODULE_AUTHOR("Sandeep Nair <sandeep_n@ti.com>");
+MODULE_AUTHOR("Santosh Shilimkar <santosh.shilimkar@ti.com>");
diff --git a/drivers/soc/versatile/Kconfig b/drivers/soc/versatile/Kconfig
new file mode 100644 (file)
index 0000000..bf5ee9c
--- /dev/null
@@ -0,0 +1,10 @@
+#
+# ARM Versatile SoC drivers
+#
+config SOC_REALVIEW
+       bool "SoC bus device for the ARM RealView platforms"
+       depends on ARCH_REALVIEW
+       select SOC_BUS
+       help
+         Include support for the SoC bus on the ARM RealView platforms
+         providing some sysfs information about the ASIC variant.
diff --git a/drivers/soc/versatile/Makefile b/drivers/soc/versatile/Makefile
new file mode 100644 (file)
index 0000000..ad54743
--- /dev/null
@@ -0,0 +1 @@
+obj-$(CONFIG_SOC_REALVIEW)     += soc-realview.o
diff --git a/drivers/soc/versatile/soc-realview.c b/drivers/soc/versatile/soc-realview.c
new file mode 100644 (file)
index 0000000..cea8ea3
--- /dev/null
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) 2014 Linaro Ltd.
+ *
+ * Author: Linus Walleij <linus.walleij@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2, as
+ * published by the Free Software Foundation.
+ *
+ */
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/sys_soc.h>
+#include <linux/platform_device.h>
+#include <linux/mfd/syscon.h>
+#include <linux/regmap.h>
+#include <linux/of.h>
+
+/* System ID in syscon */
+#define REALVIEW_SYS_ID_OFFSET 0x00
+
+static const struct of_device_id realview_soc_of_match[] = {
+       { .compatible = "arm,realview-eb-soc",  },
+       { .compatible = "arm,realview-pb1176-soc", },
+       { .compatible = "arm,realview-pb11mp-soc", },
+       { .compatible = "arm,realview-pba8-soc", },
+       { .compatible = "arm,realview-pbx-soc", },
+};
+
+static u32 realview_coreid;
+
+static const char *realview_board_str(u32 id)
+{
+       switch ((id >> 16) & 0xfff) {
+       case 0x0147:
+               return "HBI-0147";
+       default:
+               return "Unknown";
+       }
+}
+
+static const char *realview_arch_str(u32 id)
+{
+       switch ((id >> 8) & 0xf) {
+       case 0x05:
+               return "Multi-layer AXI";
+       default:
+               return "Unknown";
+       }
+}
+
+static ssize_t realview_get_manf(struct device *dev,
+                             struct device_attribute *attr,
+                             char *buf)
+{
+       return sprintf(buf, "%02x\n", realview_coreid >> 24);
+}
+
+static struct device_attribute realview_manf_attr =
+       __ATTR(manufacturer,  S_IRUGO, realview_get_manf,  NULL);
+
+static ssize_t realview_get_board(struct device *dev,
+                             struct device_attribute *attr,
+                             char *buf)
+{
+       return sprintf(buf, "%s\n", realview_board_str(realview_coreid));
+}
+
+static struct device_attribute realview_board_attr =
+       __ATTR(board,  S_IRUGO, realview_get_board,  NULL);
+
+static ssize_t realview_get_arch(struct device *dev,
+                             struct device_attribute *attr,
+                             char *buf)
+{
+       return sprintf(buf, "%s\n", realview_arch_str(realview_coreid));
+}
+
+static struct device_attribute realview_arch_attr =
+       __ATTR(fpga,  S_IRUGO, realview_get_arch,  NULL);
+
+static ssize_t realview_get_build(struct device *dev,
+                              struct device_attribute *attr,
+                              char *buf)
+{
+       return sprintf(buf, "%02x\n", (realview_coreid & 0xFF));
+}
+
+static struct device_attribute realview_build_attr =
+       __ATTR(build,  S_IRUGO, realview_get_build,  NULL);
+
+static int realview_soc_probe(struct platform_device *pdev)
+{
+       static struct regmap *syscon_regmap;
+       struct soc_device *soc_dev;
+       struct soc_device_attribute *soc_dev_attr;
+       struct device_node *np = pdev->dev.of_node;
+       int ret;
+
+       syscon_regmap = syscon_regmap_lookup_by_phandle(np, "regmap");
+       if (IS_ERR(syscon_regmap))
+               return PTR_ERR(syscon_regmap);
+
+       soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL);
+       if (!soc_dev_attr)
+               return -ENOMEM;
+
+       ret = of_property_read_string(np, "compatible",
+                                     &soc_dev_attr->soc_id);
+       if (ret)
+               return -EINVAL;
+
+       soc_dev_attr->machine = "RealView";
+       soc_dev_attr->family = "Versatile";
+       soc_dev = soc_device_register(soc_dev_attr);
+       if (IS_ERR(soc_dev)) {
+               kfree(soc_dev_attr);
+               return -ENODEV;
+       }
+       ret = regmap_read(syscon_regmap, REALVIEW_SYS_ID_OFFSET,
+                         &realview_coreid);
+       if (ret)
+               return -ENODEV;
+
+       device_create_file(soc_device_to_device(soc_dev), &realview_manf_attr);
+       device_create_file(soc_device_to_device(soc_dev), &realview_board_attr);
+       device_create_file(soc_device_to_device(soc_dev), &realview_arch_attr);
+       device_create_file(soc_device_to_device(soc_dev), &realview_build_attr);
+
+       dev_info(&pdev->dev, "RealView Syscon Core ID: 0x%08x\n",
+                realview_coreid);
+       /* FIXME: add attributes for SoC to sysfs */
+       return 0;
+}
+
+static struct platform_driver realview_soc_driver = {
+       .probe = realview_soc_probe,
+       .driver = {
+               .name = "realview-soc",
+               .of_match_table = realview_soc_of_match,
+       },
+};
+module_platform_driver(realview_soc_driver);
diff --git a/include/linux/irqchip/irq-omap-intc.h b/include/linux/irqchip/irq-omap-intc.h
new file mode 100644 (file)
index 0000000..e06b370
--- /dev/null
@@ -0,0 +1,32 @@
+/**
+ * irq-omap-intc.h - INTC Idle Functions
+ *
+ * Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com
+ *
+ * Author: Felipe Balbi <balbi@ti.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2  of
+ * the License 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.
+ */
+
+#ifndef __INCLUDE_LINUX_IRQCHIP_IRQ_OMAP_INTC_H
+#define __INCLUDE_LINUX_IRQCHIP_IRQ_OMAP_INTC_H
+
+void omap2_init_irq(void);
+void omap3_init_irq(void);
+void ti81xx_init_irq(void);
+
+int omap_irq_pending(void);
+void omap_intc_save_context(void);
+void omap_intc_restore_context(void);
+void omap3_intc_suspend(void);
+void omap3_intc_prepare_idle(void);
+void omap3_intc_resume_idle(void);
+
+#endif /* __INCLUDE_LINUX_IRQCHIP_IRQ_OMAP_INTC_H */
diff --git a/include/linux/soc/ti/knav_dma.h b/include/linux/soc/ti/knav_dma.h
new file mode 100644 (file)
index 0000000..dad035c
--- /dev/null
@@ -0,0 +1,175 @@
+/*
+ * Copyright (C) 2014 Texas Instruments Incorporated
+ * Authors:    Sandeep Nair <sandeep_n@ti.com
+ *             Cyril Chemparathy <cyril@ti.com
+               Santosh Shilimkar <santosh.shilimkar@ti.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 version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __SOC_TI_KEYSTONE_NAVIGATOR_DMA_H__
+#define __SOC_TI_KEYSTONE_NAVIGATOR_DMA_H__
+
+/*
+ * PKTDMA descriptor manipulation macros for host packet descriptor
+ */
+#define MASK(x)                                        (BIT(x) - 1)
+#define KNAV_DMA_DESC_PKT_LEN_MASK             MASK(22)
+#define KNAV_DMA_DESC_PKT_LEN_SHIFT            0
+#define KNAV_DMA_DESC_PS_INFO_IN_SOP           BIT(22)
+#define KNAV_DMA_DESC_PS_INFO_IN_DESC          0
+#define KNAV_DMA_DESC_TAG_MASK                 MASK(8)
+#define KNAV_DMA_DESC_SAG_HI_SHIFT             24
+#define KNAV_DMA_DESC_STAG_LO_SHIFT            16
+#define KNAV_DMA_DESC_DTAG_HI_SHIFT            8
+#define KNAV_DMA_DESC_DTAG_LO_SHIFT            0
+#define KNAV_DMA_DESC_HAS_EPIB                 BIT(31)
+#define KNAV_DMA_DESC_NO_EPIB                  0
+#define KNAV_DMA_DESC_PSLEN_SHIFT              24
+#define KNAV_DMA_DESC_PSLEN_MASK               MASK(6)
+#define KNAV_DMA_DESC_ERR_FLAG_SHIFT           20
+#define KNAV_DMA_DESC_ERR_FLAG_MASK            MASK(4)
+#define KNAV_DMA_DESC_PSFLAG_SHIFT             16
+#define KNAV_DMA_DESC_PSFLAG_MASK              MASK(4)
+#define KNAV_DMA_DESC_RETQ_SHIFT               0
+#define KNAV_DMA_DESC_RETQ_MASK                        MASK(14)
+#define KNAV_DMA_DESC_BUF_LEN_MASK             MASK(22)
+
+#define KNAV_DMA_NUM_EPIB_WORDS                        4
+#define KNAV_DMA_NUM_PS_WORDS                  16
+#define KNAV_DMA_FDQ_PER_CHAN                  4
+
+/* Tx channel scheduling priority */
+enum knav_dma_tx_priority {
+       DMA_PRIO_HIGH   = 0,
+       DMA_PRIO_MED_H,
+       DMA_PRIO_MED_L,
+       DMA_PRIO_LOW
+};
+
+/* Rx channel error handling mode during buffer starvation */
+enum knav_dma_rx_err_mode {
+       DMA_DROP = 0,
+       DMA_RETRY
+};
+
+/* Rx flow size threshold configuration */
+enum knav_dma_rx_thresholds {
+       DMA_THRESH_NONE         = 0,
+       DMA_THRESH_0            = 1,
+       DMA_THRESH_0_1          = 3,
+       DMA_THRESH_0_1_2        = 7
+};
+
+/* Descriptor type */
+enum knav_dma_desc_type {
+       DMA_DESC_HOST = 0,
+       DMA_DESC_MONOLITHIC = 2
+};
+
+/**
+ * struct knav_dma_tx_cfg:     Tx channel configuration
+ * @filt_einfo:                        Filter extended packet info
+ * @filt_pswords:              Filter PS words present
+ * @knav_dma_tx_priority:      Tx channel scheduling priority
+ */
+struct knav_dma_tx_cfg {
+       bool                            filt_einfo;
+       bool                            filt_pswords;
+       enum knav_dma_tx_priority       priority;
+};
+
+/**
+ * struct knav_dma_rx_cfg:     Rx flow configuration
+ * @einfo_present:             Extended packet info present
+ * @psinfo_present:            PS words present
+ * @knav_dma_rx_err_mode:      Error during buffer starvation
+ * @knav_dma_desc_type:        Host or Monolithic desc
+ * @psinfo_at_sop:             PS word located at start of packet
+ * @sop_offset:                        Start of packet offset
+ * @dst_q:                     Destination queue for a given flow
+ * @thresh:                    Rx flow size threshold
+ * @fdq[]:                     Free desc Queue array
+ * @sz_thresh0:                        RX packet size threshold 0
+ * @sz_thresh1:                        RX packet size threshold 1
+ * @sz_thresh2:                        RX packet size threshold 2
+ */
+struct knav_dma_rx_cfg {
+       bool                            einfo_present;
+       bool                            psinfo_present;
+       enum knav_dma_rx_err_mode       err_mode;
+       enum knav_dma_desc_type         desc_type;
+       bool                            psinfo_at_sop;
+       unsigned int                    sop_offset;
+       unsigned int                    dst_q;
+       enum knav_dma_rx_thresholds     thresh;
+       unsigned int                    fdq[KNAV_DMA_FDQ_PER_CHAN];
+       unsigned int                    sz_thresh0;
+       unsigned int                    sz_thresh1;
+       unsigned int                    sz_thresh2;
+};
+
+/**
+ * struct knav_dma_cfg:        Pktdma channel configuration
+ * @sl_cfg:                    Slave configuration
+ * @tx:                                Tx channel configuration
+ * @rx:                                Rx flow configuration
+ */
+struct knav_dma_cfg {
+       enum dma_transfer_direction direction;
+       union {
+               struct knav_dma_tx_cfg  tx;
+               struct knav_dma_rx_cfg  rx;
+       } u;
+};
+
+/**
+ * struct knav_dma_desc:       Host packet descriptor layout
+ * @desc_info:                 Descriptor information like id, type, length
+ * @tag_info:                  Flow tag info written in during RX
+ * @packet_info:               Queue Manager, policy, flags etc
+ * @buff_len:                  Buffer length in bytes
+ * @buff:                      Buffer pointer
+ * @next_desc:                 For chaining the descriptors
+ * @orig_len:                  length since 'buff_len' can be overwritten
+ * @orig_buff:                 buff pointer since 'buff' can be overwritten
+ * @epib:                      Extended packet info block
+ * @psdata:                    Protocol specific
+ */
+struct knav_dma_desc {
+       u32     desc_info;
+       u32     tag_info;
+       u32     packet_info;
+       u32     buff_len;
+       u32     buff;
+       u32     next_desc;
+       u32     orig_len;
+       u32     orig_buff;
+       u32     epib[KNAV_DMA_NUM_EPIB_WORDS];
+       u32     psdata[KNAV_DMA_NUM_PS_WORDS];
+       u32     pad[4];
+} ____cacheline_aligned;
+
+#if IS_ENABLED(CONFIG_KEYSTONE_NAVIGATOR_DMA)
+void *knav_dma_open_channel(struct device *dev, const char *name,
+                               struct knav_dma_cfg *config);
+void knav_dma_close_channel(void *channel);
+#else
+static inline void *knav_dma_open_channel(struct device *dev, const char *name,
+                               struct knav_dma_cfg *config)
+{
+       return (void *) NULL;
+}
+static inline void knav_dma_close_channel(void *channel)
+{}
+
+#endif
+
+#endif /* __SOC_TI_KEYSTONE_NAVIGATOR_DMA_H__ */
diff --git a/include/linux/soc/ti/knav_qmss.h b/include/linux/soc/ti/knav_qmss.h
new file mode 100644 (file)
index 0000000..9f0ebb3
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * Keystone Navigator Queue Management Sub-System header
+ *
+ * Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com
+ * Author:     Sandeep Nair <sandeep_n@ti.com>
+ *             Cyril Chemparathy <cyril@ti.com>
+ *             Santosh Shilimkar <santosh.shilimkar@ti.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 version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __SOC_TI_KNAV_QMSS_H__
+#define __SOC_TI_KNAV_QMSS_H__
+
+#include <linux/err.h>
+#include <linux/time.h>
+#include <linux/atomic.h>
+#include <linux/device.h>
+#include <linux/fcntl.h>
+#include <linux/dma-mapping.h>
+
+/* queue types */
+#define KNAV_QUEUE_QPEND       ((unsigned)-2) /* interruptible qpend queue */
+#define KNAV_QUEUE_ACC         ((unsigned)-3) /* Accumulated queue */
+#define KNAV_QUEUE_GP          ((unsigned)-4) /* General purpose queue */
+
+/* queue flags */
+#define KNAV_QUEUE_SHARED      0x0001          /* Queue can be shared */
+
+/**
+ * enum knav_queue_ctrl_cmd -  queue operations.
+ * @KNAV_QUEUE_GET_ID:         Get the ID number for an open queue
+ * @KNAV_QUEUE_FLUSH:          forcibly empty a queue if possible
+ * @KNAV_QUEUE_SET_NOTIFIER:   Set a notifier callback to a queue handle.
+ * @KNAV_QUEUE_ENABLE_NOTIFY:  Enable notifier callback for a queue handle.
+ * @KNAV_QUEUE_DISABLE_NOTIFY: Disable notifier callback for a queue handle.
+ * @KNAV_QUEUE_GET_COUNT:      Get number of queues.
+ */
+enum knav_queue_ctrl_cmd {
+       KNAV_QUEUE_GET_ID,
+       KNAV_QUEUE_FLUSH,
+       KNAV_QUEUE_SET_NOTIFIER,
+       KNAV_QUEUE_ENABLE_NOTIFY,
+       KNAV_QUEUE_DISABLE_NOTIFY,
+       KNAV_QUEUE_GET_COUNT
+};
+
+/* Queue notifier callback prototype */
+typedef void (*knav_queue_notify_fn)(void *arg);
+
+/**
+ * struct knav_queue_notify_config:    Notifier configuration
+ * @fn:                                        Notifier function
+ * @fn_arg:                            Notifier function arguments
+ */
+struct knav_queue_notify_config {
+       knav_queue_notify_fn fn;
+       void *fn_arg;
+};
+
+void *knav_queue_open(const char *name, unsigned id,
+                                       unsigned flags);
+void knav_queue_close(void *qhandle);
+int knav_queue_device_control(void *qhandle,
+                               enum knav_queue_ctrl_cmd cmd,
+                               unsigned long arg);
+dma_addr_t knav_queue_pop(void *qhandle, unsigned *size);
+int knav_queue_push(void *qhandle, dma_addr_t dma,
+                               unsigned size, unsigned flags);
+
+void *knav_pool_create(const char *name,
+                               int num_desc, int region_id);
+void knav_pool_destroy(void *ph);
+int knav_pool_count(void *ph);
+void *knav_pool_desc_get(void *ph);
+void knav_pool_desc_put(void *ph, void *desc);
+int knav_pool_desc_map(void *ph, void *desc, unsigned size,
+                                       dma_addr_t *dma, unsigned *dma_sz);
+void *knav_pool_desc_unmap(void *ph, dma_addr_t dma, unsigned dma_sz);
+dma_addr_t knav_pool_desc_virt_to_dma(void *ph, void *virt);
+void *knav_pool_desc_dma_to_virt(void *ph, dma_addr_t dma);
+
+#endif /* __SOC_TI_KNAV_QMSS_H__ */