Merge branch 'topic-0620/samsung-base-3.4' into chromeos-exynos-3.4
authorOlof Johansson <olofj@chromium.org>
Wed, 20 Jun 2012 17:30:57 +0000 (10:30 -0700)
committerOlof Johansson <olofj@chromium.org>
Wed, 20 Jun 2012 17:30:57 +0000 (10:30 -0700)
* topic-0620/samsung-base-3.4: (28 commits)
  UPSTREAM: ARM: dts: Add nodes for dw_mmc controllers for Samsung Exynos5250 platforms
  UPSTREAM: ARM: Exynos5: Add AUXDATA support for MSHC controllers
  UPSTREAM: ARM: Samsung: Add support for MSHC controller clocks
  UPSTREAM: mmc: dw_mmc: add samsung exynos5250 specific extentions
  UPSTREAM: mmc: dw_mmc: add device tree support
  UPSTREAM: mmc: dw_mmc: add quirk to indicate missing write protect line
  UPSTREAM: mmc: dw_mmc: lookup for optional biu and ciu clocks
  UPSTREAM: mmc: dw_mmc: make multiple instances of dw_mci_card_workqueue
  UPSTREAM: ARM: Exynos5: Add SROMC bank initialization for LAN9215 controller
  UPSTREAM: ARM: Exynos5: Add AUXDATA for i2c controllers
  UPSTREAM: ARM: Exynos5: Add combiner, wakeup interrupt controller and ethernet nodes
  UPSTREAM: ARM: dts: Update device tree source files for EXYNOS5250
  UPSTREAM: ARM: Exynos: Add device tree support for gpio wakeup interrupt controller
  UPSTREAM: ARM: Exynos: Remove arch_initcall for wakeup interrupt initialization
  UPSTREAM: ARM: Exynos: Add irq_domain support for gpio wakeup interrupts
  UPSTREAM: ARM: Exynos: Simplify the wakeup interrupt setup code
  UPSTREAM: ARM: Exynos: Add device tree support for interrupt combiner
  UPSTREAM: ARM: Exynos: Add irq_domain support for interrupt combiner
  UPSTREAM: of/irq: add retry support for interrupt controller tree initialization
  UPSTREAM: of/irq: fix interrupt parent lookup procedure
  ...

27 files changed:
Documentation/devicetree/bindings/arm/samsung/interrupt-combiner.txt [new file with mode: 0644]
Documentation/devicetree/bindings/mmc/synposis-dw-mshc.txt [new file with mode: 0644]
arch/arm/boot/dts/exynos5250-smdk5250.dts
arch/arm/boot/dts/exynos5250.dtsi
arch/arm/mach-exynos/Kconfig
arch/arm/mach-exynos/Makefile
arch/arm/mach-exynos/clock-exynos5.c
arch/arm/mach-exynos/common.c
arch/arm/mach-exynos/dma.c
arch/arm/mach-exynos/include/mach/gpio.h
arch/arm/mach-exynos/include/mach/irqs.h
arch/arm/mach-exynos/include/mach/map.h
arch/arm/mach-exynos/include/mach/regs-clock.h
arch/arm/mach-exynos/include/mach/regs-gpio.h
arch/arm/mach-exynos/mach-exynos5-dt.c
arch/arm/mach-exynos/mct.c
arch/arm/mach-exynos/pm.c
arch/arm/plat-s5p/clock.c
arch/arm/plat-samsung/Kconfig
arch/arm/plat-samsung/include/plat/cpu.h
arch/arm/plat-samsung/include/plat/dma-pl330.h
drivers/gpio/gpio-samsung.c
drivers/mmc/host/dw_mmc-pltfm.c
drivers/mmc/host/dw_mmc.c
drivers/mmc/host/dw_mmc.h
drivers/of/irq.c
include/linux/mmc/dw_mmc.h

diff --git a/Documentation/devicetree/bindings/arm/samsung/interrupt-combiner.txt b/Documentation/devicetree/bindings/arm/samsung/interrupt-combiner.txt
new file mode 100644 (file)
index 0000000..f2f2171
--- /dev/null
@@ -0,0 +1,52 @@
+* Samsung Exynos Interrupt Combiner Controller
+
+Samsung's Exynos4 architecture includes a interrupt combiner controller which
+can combine interrupt sources as a group and provide a single interrupt request
+for the group. The interrupt request from each group are connected to a parent
+interrupt controller, such as GIC in case of Exynos4210.
+
+The interrupt combiner controller consists of multiple combiners. Upto eight
+interrupt sources can be connected to a combiner. The combiner outputs one
+combined interrupt for its eight interrupt sources. The combined interrupt
+is usually connected to a parent interrupt controller.
+
+A single node in the device tree is used to describe the interrupt combiner
+controller module (which includes multiple combiners). A combiner in the
+interrupt controller module shares config/control registers with other
+combiners. For example, a 32-bit interrupt enable/disable config register
+can accommodate upto 4 interrupt combiners (with each combiner supporting
+upto 8 interrupt sources).
+
+Required properties:
+- compatible: should be "samsung,exynos4210-combiner".
+- interrupt-controller: Identifies the node as an interrupt controller.
+- #interrupt-cells: should be <2>. The meaning of the cells are
+       * First Cell: Combiner Group Number.
+       * Second Cell: Interrupt number within the group.
+- reg: Base address and size of interrupt combiner registers.
+- interrupts: The list of interrupts generated by the combiners which are then
+    connected to a parent interrupt controller. The format of the interrupt
+    specifier depends in the interrupt parent controller.
+
+Optional properties:
+- samsung,combiner-nr: The number of interrupt combiners supported. If this
+  property is not specified, the default number of combiners is assumed
+  to be 16.
+- interrupt-parent: pHandle of the parent interrupt controller, if not
+  inherited from the parent node.
+
+
+Example:
+
+       The following is a an example from the Exynos4210 SoC dtsi file.
+
+       combiner:interrupt-controller@10440000 {
+               compatible = "samsung,exynos4210-combiner";
+               interrupt-controller;
+               #interrupt-cells = <2>;
+               reg = <0x10440000 0x1000>;
+               interrupts = <0 0 0>, <0 1 0>, <0 2 0>, <0 3 0>,
+                            <0 4 0>, <0 5 0>, <0 6 0>, <0 7 0>,
+                            <0 8 0>, <0 9 0>, <0 10 0>, <0 11 0>,
+                            <0 12 0>, <0 13 0>, <0 14 0>, <0 15 0>;
+       };
diff --git a/Documentation/devicetree/bindings/mmc/synposis-dw-mshc.txt b/Documentation/devicetree/bindings/mmc/synposis-dw-mshc.txt
new file mode 100644 (file)
index 0000000..465fc31
--- /dev/null
@@ -0,0 +1,116 @@
+* Synopsis Designware Mobile Storage Host Controller
+
+The Synopsis designware mobile storage host controller is used to interface
+a SoC with storage medium such as eMMC or SD/MMC cards.
+
+Required Properties:
+
+* compatible: should be one of the following
+       - synopsis,dw-mshc: for controllers compliant with synopsis dw-mshc.
+       - synopsis,dw-mshc-exynos5250: for controllers with Samsung
+         Exynos5250 specific extentions.
+
+* reg: physical base address of the dw-mshc controller and size of its memory
+  region.
+
+* interrupts: interrupt specifier for the controller. The format and value of
+  the interrupt specifier depends on the interrupt parent for the controller.
+
+# Slots: The slot specific information are contained within child-nodes with
+  each child-node representing a supported slot. There should be atleast one
+  child node representing a card slot. The name of the slot child node should
+  be 'slot{n}' where n is the unique number of the slot connnected to the
+  controller. The following are optional properties which can be included in
+  the slot child node.
+
+       * bus-width: specifies the width of the data bus connected from the
+         controller to the card slot. The value should be 1, 4 or 8. In case
+         this property is not specified, a default value of 1 is assumed for
+         this property.
+
+       * cd-gpios: specifies the card detect gpio line. The format of the
+         gpio specifier depends on the gpio controller.
+
+       * wp-gpios: specifies the write protect gpio line. The format of the
+         gpio specifier depends on the gpio controller.
+
+       * gpios: specifies a list of gpios used for command, clock and data
+         bus. The first gpio is the command line and the second gpio is the
+         clock line. The rest of the gpios (depending on the bus-width
+         property) are the data lines in no particular order. The format of
+         the gpio specifier depends on the gpio controller.
+
+Optional properties:
+
+* fifo-depth: The maximum size of the tx/rx fifo's. If this property is not
+  specified, the default value of the fifo size is determined from the
+  controller registers.
+
+*  card-detect-delay: Delay in milli-seconds before detecting card after card
+   insert event. The default value is 0.
+
+* supports-highspeed: Enables support for high speed cards (upto 50MHz)
+
+* card-detection-broken: The card detection functionality is not available on
+  any of the slots.
+
+* no-write-protect: The write protect pad of the controller is not connected
+  to the write protect pin on the slot.
+
+Samsung Exynos5250 specific properties:
+
+* samsung,dw-mshc-sdr-timing: Specifies the value of CUI clock divider, CIU
+  clock phase shift value in transmit mode and CIU clock phase shift value in
+  receive mode for single data rate mode operation. Refer notes of the valid
+  values below.
+
+* samsung,dw-mshc-ddr-timing: Specifies the value of CUI clock divider, CIU
+  clock phase shift value in transmit mode and CIU clock phase shift value in
+  receive mode for double data rate mode operation. Refer notes of the valid
+  values below. The order of the cells should be
+
+    - First Cell:      CIU clock divider value.
+    - Second Cell:     CIU clock phase shift value for tx mode.
+    - Third Cell:      CIU clock phase shift value for rx mode.
+
+  Valid values for SDR and DDR CIU clock timing:
+
+    - valid values for CIU clock divider, tx phase shift and rx phase shift
+      is 0 to 7.
+
+    - When CIU clock divider value is set to 3, all possible 8 phase shift
+      values can be used.
+
+    - If CIU clock divider value is 0 (that is divide by 1), both tx and rx
+      phase shift clocks should be 0.
+
+Example:
+
+  The MSHC controller node can be split into two portions, SoC specific and
+  board specific portions as listed below.
+
+       dwmmc0@12200000 {
+               compatible = "synopsis,dw-mshc-exynos5250";
+               reg = <0x12200000 0x1000>;
+               interrupts = <0 75 0>;
+       };
+
+       dwmmc0@12200000 {
+               supports-highspeed;
+               card-detection-broken;
+               no-write-protect;
+               fifo-depth = <0x80>;
+               card-detect-delay = <200>;
+               samsung,dw-mshc-sdr-timing = <2 3 3>;
+               samsung,dw-mshc-ddr-timing = <1 2 3>;
+
+               slot0 {
+                       bus-width = <8>;
+                       cd-gpios = <&gpc0 2 2 3 3>;
+                       gpios = <&gpc0 0 2 0 3>, <&gpc0 1 2 0 3>,
+                               <&gpc1 0 2 3 3>, <&gpc1 1 2 3 3>,
+                               <&gpc1 2 2 3 3>, <&gpc1 3 2 3 3>,
+                               <&gpc0 3 2 3 3>, <&gpc0 4 2 3 3>,
+                               <&gpc0 5 2 3 3>, <&gpc0 6 2 3 3>;
+               };
+       };
index 399d17b..ac9df2f 100644 (file)
        };
 
        chosen {
-               bootargs = "root=/dev/ram0 rw ramdisk=8192 console=ttySAC1,115200";
+               bootargs = "root=/dev/ram0 rw ramdisk=8192 initrd=0x41000000,8M console=ttySAC3,115200 init=/linuxrc";
+       };
+
+       lan9215@0x05000000 {
+               compatible = "smsc,lan9215", "smsc,lan9115";
+               reg = <0x05000000 0x20000>;
+               interrupts = <5 0>;
+               interrupt-parent = <&wakeup_eint>;
+               phy-mode = "mii";
+               smsc,irq-push-pull;
+               smsc,force-internal-phy;
+               local-mac-address = [00 80 00 23 45 67];
+       };
+
+       i2c@12C60000 {
+               #address-cells = <1>;
+               #size-cells = <0>;
+               samsung,i2c-sda-delay = <100>;
+               samsung,i2c-max-bus-freq = <20000>;
+               gpios = <&gpb3 0 2 3 0>,
+                       <&gpb3 1 2 3 0>;
+
+               eeprom@50 {
+                       compatible = "samsung,s524ad0xd1";
+                       reg = <0x50>;
+               };
+       };
+
+       i2c@12C70000 {
+               #address-cells = <1>;
+               #size-cells = <0>;
+               samsung,i2c-sda-delay = <100>;
+               samsung,i2c-max-bus-freq = <20000>;
+               gpios = <&gpb3 2 2 3 0>,
+                       <&gpb3 3 2 3 0>;
+
+               eeprom@51 {
+                       compatible = "samsung,s524ad0xd1";
+                       reg = <0x51>;
+               };
+       };
+
+       i2c@12C80000 {
+               status = "disabled";
+       };
+
+       i2c@12C90000 {
+               status = "disabled";
+       };
+
+       i2c@12CA0000 {
+               status = "disabled";
+       };
+
+       i2c@12CB0000 {
+               status = "disabled";
+       };
+
+       i2c@12CC0000 {
+               status = "disabled";
+       };
+
+       i2c@12CD0000 {
+               status = "disabled";
+       };
+
+       dwmmc0@12200000 {
+               supports-highspeed;
+               card-detection-broken;
+               no-write-protect;
+               fifo-depth = <0x80>;
+               card-detect-delay = <200>;
+               samsung,dw-mshc-sdr-timing = <2 3 3>;
+               samsung,dw-mshc-ddr-timing = <1 2 3>;
+               
+               slot0 {
+                       bus-width = <8>;
+                       cd-gpios = <&gpc0 2 2 3 3>;
+                       gpios = <&gpc0 0 2 0 3>, <&gpc0 1 2 0 3>,
+                               <&gpc1 0 2 3 3>, <&gpc1 1 2 3 3>,
+                               <&gpc1 2 2 3 3>, <&gpc1 3 2 3 3>,
+                               <&gpc0 3 2 3 3>, <&gpc0 4 2 3 3>,
+                               <&gpc0 5 2 3 3>, <&gpc0 6 2 3 3>;
+               };
+       };
+
+       dwmmc1@12210000 {
+               status = "disabled";
+       };
+
+       dwmmc2@12220000 {
+               supports-highspeed;
+               card-detection-broken;
+               no-write-protect;
+               fifo-depth = <0x80>;
+               card-detect-delay = <200>;
+               samsung,dw-mshc-sdr-timing = <2 3 3>;
+               samsung,dw-mshc-ddr-timing = <1 2 3>;
+               
+               slot0 {
+                       bus-width = <4>;
+                       cd-gpios = <&gpc3 2 2 3 3>;
+                       gpios = <&gpc3 0 2 0 3>, <&gpc3 1 2 0 3>,
+                               <&gpc3 3 2 3 3>, <&gpc3 4 2 3 3>,
+                               <&gpc3 5 2 3 3>, <&gpc3 6 2 3 3>,
+                               <&gpc4 3 3 3 3>, <&gpc4 3 3 3 3>,
+                               <&gpc4 5 3 3 3>, <&gpc4 6 3 3 3>;
+               };
+       };
+
+       dwmmc3@12230000 {
+               status = "disabled";
        };
 };
index dfc4335..345e0bb 100644 (file)
        compatible = "samsung,exynos5250";
        interrupt-parent = <&gic>;
 
-       gic:interrupt-controller@10490000 {
+       gic:interrupt-controller@10481000 {
                compatible = "arm,cortex-a9-gic";
                #interrupt-cells = <3>;
+               #address-cells = <0>;
+               #size-cells = <0>;
                interrupt-controller;
-               reg = <0x10490000 0x1000>, <0x10480000 0x100>;
+               reg = <0x10481000 0x1000>, <0x10482000 0x2000>;
        };
 
+       combiner:interrupt-controller@10440000 {
+               compatible = "samsung,exynos4210-combiner";
+               #interrupt-cells = <2>;
+               interrupt-controller;
+               samsung,combiner-nr = <32>;
+               reg = <0x10440000 0x1000>;
+               interrupts = <0 0 0>, <0 1 0>, <0 2 0>, <0 3 0>,
+                            <0 4 0>, <0 5 0>, <0 6 0>, <0 7 0>,
+                            <0 8 0>, <0 9 0>, <0 10 0>, <0 11 0>,
+                            <0 12 0>, <0 13 0>, <0 14 0>, <0 15 0>,
+                            <0 16 0>, <0 17 0>, <0 18 0>, <0 19 0>,
+                            <0 20 0>, <0 21 0>, <0 22 0>, <0 23 0>,
+                            <0 24 0>, <0 25 0>, <0 26 0>, <0 27 0>,
+                            <0 28 0>, <0 29 0>, <0 30 0>, <0 31 0>;
+       };
+
+       wakeup_eint: interrupt-controller@11400000 {
+               compatible = "samsung,exynos5210-wakeup-eint";
+               reg = <0x11400000 0x1000>;
+               interrupt-controller;
+               #interrupt-cells = <2>;
+               interrupt-parent = <&wakeup_map>;
+               interrupts = <0x0 0>, <0x1 0>, <0x2 0>, <0x3 0>,
+                            <0x4 0>, <0x5 0>, <0x6 0>, <0x7 0>,
+                            <0x8 0>, <0x9 0>, <0xa 0>, <0xb 0>,
+                            <0xc 0>, <0xd 0>, <0xe 0>, <0xf 0>,
+                            <0x10 0>;
+
+                wakeup_map: interrupt-map {
+                       compatible = "samsung,exynos5210-wakeup-eint-map";
+                        #interrupt-cells = <2>;
+                        #address-cells = <0>;
+                        #size-cells = <0>;
+                        interrupt-map = <0x0 0 &combiner 23 0>,
+                                        <0x1 0 &combiner 24 0>,
+                                        <0x2 0 &combiner 25 0>,
+                                        <0x3 0 &combiner 25 1>,
+                                        <0x4 0 &combiner 26 0>,
+                                        <0x5 0 &combiner 26 1>,
+                                        <0x6 0 &combiner 27 0>,
+                                        <0x7 0 &combiner 27 1>,
+                                        <0x8 0 &combiner 28 0>,
+                                        <0x9 0 &combiner 28 1>,
+                                        <0xa 0 &combiner 29 0>,
+                                        <0xb 0 &combiner 29 1>,
+                                        <0xc 0 &combiner 30 0>,
+                                        <0xd 0 &combiner 30 1>,
+                                        <0xe 0 &combiner 31 0>,
+                                        <0xf 0 &combiner 31 1>,
+                                        <0x10 0 &gic 0 32 0>;
+                };
+        };
+
        watchdog {
                compatible = "samsung,s3c2410-wdt";
                reg = <0x101D0000 0x100>;
                interrupts = <0 43 0>, <0 44 0>;
        };
 
-       sdhci@12200000 {
-               compatible = "samsung,exynos4210-sdhci";
-               reg = <0x12200000 0x100>;
-               interrupts = <0 75 0>;
-       };
-
-       sdhci@12210000 {
-               compatible = "samsung,exynos4210-sdhci";
-               reg = <0x12210000 0x100>;
-               interrupts = <0 76 0>;
-       };
-
-       sdhci@12220000 {
-               compatible = "samsung,exynos4210-sdhci";
-               reg = <0x12220000 0x100>;
-               interrupts = <0 77 0>;
-       };
-
-       sdhci@12230000 {
-               compatible = "samsung,exynos4210-sdhci";
-               reg = <0x12230000 0x100>;
-               interrupts = <0 78 0>;
-       };
-
        serial@12C00000 {
                compatible = "samsung,exynos4210-uart";
                reg = <0x12C00000 0x100>;
                interrupts = <0 63 0>;
        };
 
+       dwmmc0@12200000 {
+               compatible = "synopsis,dw-mshc-exynos5250";
+               reg = <0x12200000 0x1000>;
+               interrupts = <0 75 0>;
+       };
+
+       dwmmc1@12210000 {
+               compatible = "synopsis,dw-mshc-exynos5250";
+               reg = <0x12210000 0x1000>;
+               interrupts = <0 76 0>;
+       };
+
+       dwmmc2@12220000 {
+               compatible = "synopsis,dw-mshc-exynos5250";
+               reg = <0x12220000 0x1000>;
+               interrupts = <0 77 0>;
+       };
+       
+       dwmmc3@12230000 {
+               compatible = "synopsis,dw-mshc-exynos5250";
+               reg = <0x12230000 0x1000>;
+               interrupts = <0 78 0>;
+       };
+
        amba {
                #address-cells = <1>;
                #size-cells = <1>;
                        interrupts = <0 35 0>;
                };
 
-               mdma0: pdma@10800000 {
+               mdma0: mdma@10800000 {
                        compatible = "arm,pl330", "arm,primecell";
                        reg = <0x10800000 0x1000>;
                        interrupts = <0 33 0>;
                };
 
-               mdma1: pdma@11C10000 {
+               mdma1: mdma@11C10000 {
                        compatible = "arm,pl330", "arm,primecell";
                        reg = <0x11C10000 0x1000>;
                        interrupts = <0 124 0>;
                        #gpio-cells = <4>;
                };
 
+               gpc4: gpio-controller@114002E0 {
+                       compatible = "samsung,exynos4-gpio";
+                       reg = <0x114002E0 0x20>;
+                       #gpio-cells = <4>;
+               };
+
                gpd0: gpio-controller@11400160 {
                        compatible = "samsung,exynos4-gpio";
                        reg = <0x11400160 0x20>;
 
                gpv2: gpio-controller@10D10040 {
                        compatible = "samsung,exynos4-gpio";
-                       reg = <0x10D10040 0x20>;
+                       reg = <0x10D10060 0x20>;
                        #gpio-cells = <4>;
                };
 
                gpv3: gpio-controller@10D10060 {
                        compatible = "samsung,exynos4-gpio";
-                       reg = <0x10D10060 0x20>;
+                       reg = <0x10D10080 0x20>;
                        #gpio-cells = <4>;
                };
 
                gpv4: gpio-controller@10D10080 {
                        compatible = "samsung,exynos4-gpio";
-                       reg = <0x10D10080 0x20>;
+                       reg = <0x10D100C0 0x20>;
                        #gpio-cells = <4>;
                };
 
index b8df521..e95448d 100644 (file)
@@ -61,6 +61,7 @@ config SOC_EXYNOS5250
        bool "SAMSUNG EXYNOS5250"
        default y
        depends on ARCH_EXYNOS5
+       select SAMSUNG_DMADEV
        help
          Enable EXYNOS5250 SoC support
 
@@ -70,7 +71,7 @@ config EXYNOS4_MCT
        help
          Use MCT (Multi Core Timer) as kernel timers
 
-config EXYNOS4_DEV_DMA
+config EXYNOS_DEV_DMA
        bool
        help
          Compile in amba device definitions for DMA controller
@@ -223,7 +224,7 @@ config MACH_ARMLEX4210
        select S3C_DEV_HSMMC2
        select S3C_DEV_HSMMC3
        select EXYNOS4_DEV_AHCI
-       select EXYNOS4_DEV_DMA
+       select EXYNOS_DEV_DMA
        select EXYNOS4_DEV_SYSMMU
        select EXYNOS4_SETUP_SDHCI
        help
@@ -348,7 +349,7 @@ config MACH_SMDK4212
        select SAMSUNG_DEV_BACKLIGHT
        select SAMSUNG_DEV_KEYPAD
        select SAMSUNG_DEV_PWM
-       select EXYNOS4_DEV_DMA
+       select EXYNOS_DEV_DMA
        select EXYNOS4_SETUP_I2C1
        select EXYNOS4_SETUP_I2C3
        select EXYNOS4_SETUP_I2C7
index 8631840..839e78f 100644 (file)
@@ -52,7 +52,7 @@ obj-$(CONFIG_ARCH_EXYNOS4)            += dev-audio.o
 obj-$(CONFIG_EXYNOS4_DEV_AHCI)         += dev-ahci.o
 obj-$(CONFIG_EXYNOS4_DEV_SYSMMU)       += dev-sysmmu.o
 obj-$(CONFIG_EXYNOS4_DEV_DWMCI)                += dev-dwmci.o
-obj-$(CONFIG_EXYNOS4_DEV_DMA)          += dma.o
+obj-$(CONFIG_EXYNOS_DEV_DMA)           += dma.o
 obj-$(CONFIG_EXYNOS4_DEV_USB_OHCI)     += dev-ohci.o
 
 obj-$(CONFIG_ARCH_EXYNOS)              += setup-i2c0.o
index 7ac6ff4..4e17131 100644 (file)
@@ -145,6 +145,39 @@ static struct clksrc_clk exynos5_clk_sclk_apll = {
        .reg_div = { .reg = EXYNOS5_CLKDIV_CPU0, .shift = 24, .size = 3 },
 };
 
+static struct clk clk_fout_bpll_div2 = {
+       .name   = "fout_bpll_div2",
+};
+
+static struct clk *exynos5_clkset_mout_bpll_fout_list[] = {
+       [0] = &clk_fout_bpll_div2,
+       [1] = &clk_fout_bpll,
+};
+
+static struct clksrc_sources exynos5_clkset_mout_bpll_fout = {
+       .sources        = exynos5_clkset_mout_bpll_fout_list,
+       .nr_sources     = ARRAY_SIZE(exynos5_clkset_mout_bpll_fout_list),
+};
+
+static struct clksrc_clk exynos5_clk_mout_bpll_fout = {
+       .clk    = {
+               .name           = "mout_bpll_fout",
+       },
+       .sources = &exynos5_clkset_mout_bpll_fout,
+       .reg_src = { .reg = EXYNOS5_PLL_DIV2_SEL, .shift = 0, .size = 1 },
+};
+
+/* Possible clock sources for BPLL Mux */
+static struct clk *clk_src_bpll_list[] = {
+       [0] = &clk_fin_bpll,
+       [1] = &exynos5_clk_mout_bpll_fout.clk,
+};
+
+struct clksrc_sources clk_src_bpll = {
+       .sources        = clk_src_bpll_list,
+       .nr_sources     = ARRAY_SIZE(clk_src_bpll_list),
+};
+
 static struct clksrc_clk exynos5_clk_mout_bpll = {
        .clk    = {
                .name           = "mout_bpll",
@@ -187,11 +220,43 @@ static struct clksrc_clk exynos5_clk_mout_epll = {
        .reg_src = { .reg = EXYNOS5_CLKSRC_TOP2, .shift = 12, .size = 1 },
 };
 
+static struct clk clk_fout_mpll_div2 = {
+       .name   = "fout_mpll_div2",
+};
+
+static struct clk *exynos5_clkset_mout_mpll_fout_list[] = {
+       [0] = &clk_fout_mpll_div2,
+       [1] = &clk_fout_mpll,
+};
+
+static struct clksrc_sources exynos5_clkset_mout_mpll_fout = {
+       .sources        = exynos5_clkset_mout_mpll_fout_list,
+       .nr_sources     = ARRAY_SIZE(exynos5_clkset_mout_mpll_fout_list),
+};
+
+static struct clksrc_clk exynos5_clk_mout_mpll_fout = {
+       .clk    = {
+               .name           = "mout_mpll_fout",
+       },
+       .sources = &exynos5_clkset_mout_mpll_fout,
+       .reg_src = { .reg = EXYNOS5_PLL_DIV2_SEL, .shift = 4, .size = 1 },
+};
+
+static struct clk *exynos5_clk_src_mpll_list[] = {
+       [0] = &clk_fin_mpll,
+       [1] = &exynos5_clk_mout_mpll_fout.clk,
+};
+
+struct clksrc_sources exynos5_clk_src_mpll = {
+       .sources        = exynos5_clk_src_mpll_list,
+       .nr_sources     = ARRAY_SIZE(exynos5_clk_src_mpll_list),
+};
+
 struct clksrc_clk exynos5_clk_mout_mpll = {
        .clk = {
                .name           = "mout_mpll",
        },
-       .sources = &clk_src_mpll,
+       .sources = &exynos5_clk_src_mpll,
        .reg_src = { .reg = EXYNOS5_CLKSRC_CORE1, .shift = 8, .size = 1 },
 };
 
@@ -454,34 +519,34 @@ static struct clk exynos5_init_clocks_off[] = {
                .enable         = exynos5_clk_ip_peris_ctrl,
                .ctrlbit        = (1 << 20),
        }, {
-               .name           = "hsmmc",
-               .devname        = "exynos4-sdhci.0",
+               .name           = "watchdog",
+               .parent         = &exynos5_clk_aclk_66.clk,
+               .enable         = exynos5_clk_ip_peris_ctrl,
+               .ctrlbit        = (1 << 19),
+       }, {
+               .name           = "biu",
+               .devname        = "dw_mmc.0",
                .parent         = &exynos5_clk_aclk_200.clk,
                .enable         = exynos5_clk_ip_fsys_ctrl,
                .ctrlbit        = (1 << 12),
        }, {
-               .name           = "hsmmc",
-               .devname        = "exynos4-sdhci.1",
+               .name           = "biu",
+               .devname        = "dw_mmc.1",
                .parent         = &exynos5_clk_aclk_200.clk,
                .enable         = exynos5_clk_ip_fsys_ctrl,
                .ctrlbit        = (1 << 13),
        }, {
-               .name           = "hsmmc",
-               .devname        = "exynos4-sdhci.2",
+               .name           = "biu",
+               .devname        = "dw_mmc.2",
                .parent         = &exynos5_clk_aclk_200.clk,
                .enable         = exynos5_clk_ip_fsys_ctrl,
                .ctrlbit        = (1 << 14),
        }, {
-               .name           = "hsmmc",
-               .devname        = "exynos4-sdhci.3",
+               .name           = "biu",
+               .devname        = "dw_mmc.3",
                .parent         = &exynos5_clk_aclk_200.clk,
                .enable         = exynos5_clk_ip_fsys_ctrl,
                .ctrlbit        = (1 << 15),
-       }, {
-               .name           = "dwmci",
-               .parent         = &exynos5_clk_aclk_200.clk,
-               .enable         = exynos5_clk_ip_fsys_ctrl,
-               .ctrlbit        = (1 << 16),
        }, {
                .name           = "sata",
                .devname        = "ahci",
@@ -812,8 +877,8 @@ static struct clksrc_clk exynos5_clk_sclk_uart3 = {
 
 static struct clksrc_clk exynos5_clk_sclk_mmc0 = {
        .clk    = {
-               .name           = "sclk_mmc",
-               .devname        = "exynos4-sdhci.0",
+               .name           = "ciu",
+               .devname        = "dw_mmc.0",
                .parent         = &exynos5_clk_dout_mmc0.clk,
                .enable         = exynos5_clksrc_mask_fsys_ctrl,
                .ctrlbit        = (1 << 0),
@@ -823,8 +888,8 @@ static struct clksrc_clk exynos5_clk_sclk_mmc0 = {
 
 static struct clksrc_clk exynos5_clk_sclk_mmc1 = {
        .clk    = {
-               .name           = "sclk_mmc",
-               .devname        = "exynos4-sdhci.1",
+               .name           = "ciu",
+               .devname        = "dw_mmc.1",
                .parent         = &exynos5_clk_dout_mmc1.clk,
                .enable         = exynos5_clksrc_mask_fsys_ctrl,
                .ctrlbit        = (1 << 4),
@@ -834,8 +899,8 @@ static struct clksrc_clk exynos5_clk_sclk_mmc1 = {
 
 static struct clksrc_clk exynos5_clk_sclk_mmc2 = {
        .clk    = {
-               .name           = "sclk_mmc",
-               .devname        = "exynos4-sdhci.2",
+               .name           = "ciu",
+               .devname        = "dw_mmc.2",
                .parent         = &exynos5_clk_dout_mmc2.clk,
                .enable         = exynos5_clksrc_mask_fsys_ctrl,
                .ctrlbit        = (1 << 8),
@@ -845,8 +910,8 @@ static struct clksrc_clk exynos5_clk_sclk_mmc2 = {
 
 static struct clksrc_clk exynos5_clk_sclk_mmc3 = {
        .clk    = {
-               .name           = "sclk_mmc",
-               .devname        = "exynos4-sdhci.3",
+               .name           = "ciu",
+               .devname        = "dw_mmc.3",
                .parent         = &exynos5_clk_dout_mmc3.clk,
                .enable         = exynos5_clksrc_mask_fsys_ctrl,
                .ctrlbit        = (1 << 12),
@@ -856,14 +921,6 @@ static struct clksrc_clk exynos5_clk_sclk_mmc3 = {
 
 static struct clksrc_clk exynos5_clksrcs[] = {
        {
-               .clk    = {
-                       .name           = "sclk_dwmci",
-                       .parent         = &exynos5_clk_dout_mmc4.clk,
-                       .enable         = exynos5_clksrc_mask_fsys_ctrl,
-                       .ctrlbit        = (1 << 16),
-               },
-               .reg_div = { .reg = EXYNOS5_CLKDIV_FSYS3, .shift = 8, .size = 8 },
-       }, {
                .clk    = {
                        .name           = "sclk_fimd",
                        .devname        = "s3cfb.1",
@@ -941,10 +998,12 @@ static struct clksrc_clk *exynos5_sysclks[] = {
        &exynos5_clk_mout_apll,
        &exynos5_clk_sclk_apll,
        &exynos5_clk_mout_bpll,
+       &exynos5_clk_mout_bpll_fout,
        &exynos5_clk_mout_bpll_user,
        &exynos5_clk_mout_cpll,
        &exynos5_clk_mout_epll,
        &exynos5_clk_mout_mpll,
+       &exynos5_clk_mout_mpll_fout,
        &exynos5_clk_mout_mpll_user,
        &exynos5_clk_vpllsrc,
        &exynos5_clk_sclk_vpll,
@@ -1008,6 +1067,8 @@ static struct clk *exynos5_clks[] __initdata = {
        &exynos5_clk_sclk_hdmi27m,
        &exynos5_clk_sclk_hdmiphy,
        &clk_fout_bpll,
+       &clk_fout_bpll_div2,
+       &clk_fout_mpll_div2,
        &clk_fout_cpll,
        &exynos5_clk_armclk,
 };
@@ -1173,8 +1234,10 @@ void __init_or_cpufreq exynos5_setup_clocks(void)
 
        clk_fout_apll.ops = &exynos5_fout_apll_ops;
        clk_fout_bpll.rate = bpll;
+       clk_fout_bpll_div2.rate = bpll >> 1;
        clk_fout_cpll.rate = cpll;
        clk_fout_mpll.rate = mpll;
+       clk_fout_mpll_div2.rate = mpll >> 1;
        clk_fout_epll.rate = epll;
        clk_fout_vpll.rate = vpll;
 
index 5ccd6e8..074508f 100644 (file)
@@ -19,6 +19,9 @@
 #include <linux/serial_core.h>
 #include <linux/of.h>
 #include <linux/of_irq.h>
+#include <linux/export.h>
+#include <linux/irqdomain.h>
+#include <linux/of_address.h>
 
 #include <asm/proc-fns.h>
 #include <asm/exception.h>
@@ -61,6 +64,8 @@ static void exynos4_init_clocks(int xtal);
 static void exynos5_init_clocks(int xtal);
 static void exynos_init_uarts(struct s3c2410_uartcfg *cfg, int no);
 static int exynos_init(void);
+static int exynos_init_irq_eint(struct device_node *np,
+                               struct device_node *parent);
 
 static struct cpu_table cpu_ids[] __initdata = {
        {
@@ -265,12 +270,12 @@ static struct map_desc exynos5_iodesc[] __initdata = {
        }, {
                .virtual        = (unsigned long)S5P_VA_GIC_CPU,
                .pfn            = __phys_to_pfn(EXYNOS5_PA_GIC_CPU),
-               .length         = SZ_64K,
+               .length         = SZ_8K,
                .type           = MT_DEVICE,
        }, {
                .virtual        = (unsigned long)S5P_VA_GIC_DIST,
                .pfn            = __phys_to_pfn(EXYNOS5_PA_GIC_DIST),
-               .length         = SZ_64K,
+               .length         = SZ_4K,
                .type           = MT_DEVICE,
        },
 };
@@ -399,6 +404,7 @@ struct combiner_chip_data {
        void __iomem *base;
 };
 
+static struct irq_domain *combiner_irq_domain;
 static struct combiner_chip_data combiner_data[MAX_COMBINER_NR];
 
 static inline void __iomem *combiner_base(struct irq_data *data)
@@ -411,14 +417,14 @@ static inline void __iomem *combiner_base(struct irq_data *data)
 
 static void combiner_mask_irq(struct irq_data *data)
 {
-       u32 mask = 1 << (data->irq % 32);
+       u32 mask = 1 << (data->hwirq % 32);
 
        __raw_writel(mask, combiner_base(data) + COMBINER_ENABLE_CLEAR);
 }
 
 static void combiner_unmask_irq(struct irq_data *data)
 {
-       u32 mask = 1 << (data->irq % 32);
+       u32 mask = 1 << (data->hwirq % 32);
 
        __raw_writel(mask, combiner_base(data) + COMBINER_ENABLE_SET);
 }
@@ -474,49 +480,124 @@ static void __init combiner_cascade_irq(unsigned int combiner_nr, unsigned int i
        irq_set_chained_handler(irq, combiner_handle_cascade_irq);
 }
 
-static void __init combiner_init(unsigned int combiner_nr, void __iomem *base,
-                         unsigned int irq_start)
+static void __init combiner_init_one(unsigned int combiner_nr,
+                                               void __iomem *base)
 {
-       unsigned int i;
-       unsigned int max_nr;
-
-       if (soc_is_exynos5250())
-               max_nr = EXYNOS5_MAX_COMBINER_NR;
-       else
-               max_nr = EXYNOS4_MAX_COMBINER_NR;
-
-       if (combiner_nr >= max_nr)
-               BUG();
-
        combiner_data[combiner_nr].base = base;
-       combiner_data[combiner_nr].irq_offset = irq_start;
+       combiner_data[combiner_nr].irq_offset = irq_find_mapping(
+               combiner_irq_domain, combiner_nr * MAX_IRQ_IN_COMBINER);
        combiner_data[combiner_nr].irq_mask = 0xff << ((combiner_nr % 4) << 3);
 
        /* Disable all interrupts */
 
        __raw_writel(combiner_data[combiner_nr].irq_mask,
                     base + COMBINER_ENABLE_CLEAR);
+}
+
+#ifdef CONFIG_OF
+static int combiner_irq_domain_xlate(struct irq_domain *d,
+               struct device_node *controller, const u32 *intspec,
+               unsigned int intsize, unsigned long *out_hwirq,
+               unsigned int *out_type)
+{
+       if (d->of_node != controller)
+               return -EINVAL;
+       if (intsize < 2)
+               return -EINVAL;
+       *out_hwirq = intspec[0] * MAX_IRQ_IN_COMBINER + intspec[1];
+       *out_type = 0;
+       return 0;
+}
+#else
+static int combiner_irq_domain_xlate(struct irq_domain *d,
+               struct device_node *controller, const u32 *intspec,
+               unsigned int intsize, unsigned long *out_hwirq,
+               unsigned int *out_type)
+{
+       return -EINVAL;
+}
+#endif
+
+static int combiner_irq_domain_map(struct irq_domain *d, unsigned int irq,
+                                       irq_hw_number_t hw)
+{
+       irq_set_chip_and_handler(irq, &combiner_chip, handle_level_irq);
+       irq_set_chip_data(irq, &combiner_data[hw >> 3]);
+       set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
+       return 0;
+}
+
+static struct irq_domain_ops combiner_irq_domain_ops = {
+       .xlate = combiner_irq_domain_xlate,
+       .map = combiner_irq_domain_map,
+};
+
+void __init combiner_init(void __iomem *combiner_base, struct device_node *np)
+{
+       int i, irq, irq_base;
+       unsigned int max_nr, nr_irq;
+
+       if (np) {
+               if (of_property_read_u32(np, "samsung,combiner-nr", &max_nr)) {
+                       pr_warning("%s: number of combiners not specified, "
+                               "setting default as %d.\n",
+                               __func__, EXYNOS4_MAX_COMBINER_NR);
+                       max_nr = EXYNOS4_MAX_COMBINER_NR;
+               }
+       } else {
+               max_nr = soc_is_exynos5250() ? EXYNOS5_MAX_COMBINER_NR :
+                                               EXYNOS4_MAX_COMBINER_NR;
+       }
+       nr_irq = max_nr * MAX_IRQ_IN_COMBINER;
 
-       /* Setup the Linux IRQ subsystem */
+       irq_base = irq_alloc_descs(COMBINER_IRQ(0, 0), 1, nr_irq, 0);
+       if (IS_ERR_VALUE(irq_base)) {
+               irq_base = COMBINER_IRQ(0, 0);
+               pr_warning("%s: irq desc alloc failed. Continuing with %d as "
+                               "linux irq base\n", __func__, irq_base);
+       }
+
+       combiner_irq_domain = irq_domain_add_legacy(np, nr_irq, irq_base, 0,
+                               &combiner_irq_domain_ops, &combiner_data);
+       if (WARN_ON(!combiner_irq_domain)) {
+               pr_warning("%s: irq domain init failed\n", __func__);
+               return;
+       }
 
-       for (i = irq_start; i < combiner_data[combiner_nr].irq_offset
-                               + MAX_IRQ_IN_COMBINER; i++) {
-               irq_set_chip_and_handler(i, &combiner_chip, handle_level_irq);
-               irq_set_chip_data(i, &combiner_data[combiner_nr]);
-               set_irq_flags(i, IRQF_VALID | IRQF_PROBE);
+       for (i = 0; i < max_nr; i++) {
+               combiner_init_one(i, combiner_base + (i >> 2) * 0x10);
+               irq = np ? irq_of_parse_and_map(np, i) : IRQ_SPI(i);
+               combiner_cascade_irq(i, irq);
        }
 }
 
 #ifdef CONFIG_OF
+int __init combiner_of_init(struct device_node *np, struct device_node *parent)
+{
+       void __iomem *combiner_base;
+
+       combiner_base = of_iomap(np, 0);
+       if (!combiner_base) {
+               pr_err("%s: failed to map combiner registers\n", __func__);
+               return -ENXIO;
+       }
+
+       combiner_init(combiner_base, np);
+       return 0;
+}
+
 static const struct of_device_id exynos4_dt_irq_match[] = {
        { .compatible = "arm,cortex-a9-gic", .data = gic_of_init, },
+       { .compatible = "samsung,exynos4210-combiner",
+                       .data = combiner_of_init, },
+       { .compatible = "samsung,exynos5210-wakeup-eint-map",
+                       .data = exynos_init_irq_eint, },
        {},
 };
 #endif
 
 void __init exynos4_init_irq(void)
 {
-       int irq;
        unsigned int gic_bank_offset;
 
        gic_bank_offset = soc_is_exynos4412() ? 0x4000 : 0x8000;
@@ -528,11 +609,9 @@ void __init exynos4_init_irq(void)
                of_irq_init(exynos4_dt_irq_match);
 #endif
 
-       for (irq = 0; irq < EXYNOS4_MAX_COMBINER_NR; irq++) {
-
-               combiner_init(irq, (void __iomem *)S5P_VA_COMBINER(irq),
-                               COMBINER_IRQ(irq, 0));
-               combiner_cascade_irq(irq, IRQ_SPI(irq));
+       if (!of_have_populated_dt()) {
+               combiner_init(S5P_VA_COMBINER_BASE, NULL);
+               exynos_init_irq_eint(NULL, NULL);
        }
 
        /*
@@ -545,18 +624,9 @@ void __init exynos4_init_irq(void)
 
 void __init exynos5_init_irq(void)
 {
-       int irq;
-
 #ifdef CONFIG_OF
        of_irq_init(exynos4_dt_irq_match);
 #endif
-
-       for (irq = 0; irq < EXYNOS5_MAX_COMBINER_NR; irq++) {
-               combiner_init(irq, (void __iomem *)S5P_VA_COMBINER(irq),
-                               COMBINER_IRQ(irq, 0));
-               combiner_cascade_irq(irq, IRQ_SPI(irq));
-       }
-
        /*
         * The parameters of s5p_init_irq() are for VIC init.
         * Theses parameters should be NULL and 0 because EXYNOS4
@@ -565,30 +635,18 @@ void __init exynos5_init_irq(void)
        s5p_init_irq(NULL, 0);
 }
 
-struct bus_type exynos4_subsys = {
-       .name           = "exynos4-core",
-       .dev_name       = "exynos4-core",
-};
-
-struct bus_type exynos5_subsys = {
-       .name           = "exynos5-core",
-       .dev_name       = "exynos5-core",
+struct bus_type exynos_subsys = {
+       .name           = "exynos-core",
+       .dev_name       = "exynos-core",
 };
 
 static struct device exynos4_dev = {
-       .bus    = &exynos4_subsys,
-};
-
-static struct device exynos5_dev = {
-       .bus    = &exynos5_subsys,
+       .bus    = &exynos_subsys,
 };
 
 static int __init exynos_core_init(void)
 {
-       if (soc_is_exynos5250())
-               return subsys_system_register(&exynos5_subsys, NULL);
-       else
-               return subsys_system_register(&exynos4_subsys, NULL);
+       return subsys_system_register(&exynos_subsys, NULL);
 }
 core_initcall(exynos_core_init);
 
@@ -675,10 +733,7 @@ static int __init exynos_init(void)
 {
        printk(KERN_INFO "EXYNOS: Initializing architecture\n");
 
-       if (soc_is_exynos5250())
-               return device_register(&exynos5_dev);
-       else
-               return device_register(&exynos4_dev);
+       return device_register(&exynos4_dev);
 }
 
 /* uart registration process */
@@ -703,6 +758,9 @@ static DEFINE_SPINLOCK(eint_lock);
 
 static unsigned int eint0_15_data[16];
 
+#define EXYNOS_EINT_NR 32
+static struct irq_domain *irq_domain;
+
 static inline int exynos4_irq_to_gpio(unsigned int irq)
 {
        if (irq < IRQ_EINT(0))
@@ -793,9 +851,9 @@ static inline void exynos_irq_eint_mask(struct irq_data *data)
        u32 mask;
 
        spin_lock(&eint_lock);
-       mask = __raw_readl(EINT_MASK(exynos_eint_base, data->irq));
-       mask |= EINT_OFFSET_BIT(data->irq);
-       __raw_writel(mask, EINT_MASK(exynos_eint_base, data->irq));
+       mask = __raw_readl(EINT_MASK(exynos_eint_base, data->hwirq));
+       mask |= EINT_OFFSET_BIT(data->hwirq);
+       __raw_writel(mask, EINT_MASK(exynos_eint_base, data->hwirq));
        spin_unlock(&eint_lock);
 }
 
@@ -804,16 +862,16 @@ static void exynos_irq_eint_unmask(struct irq_data *data)
        u32 mask;
 
        spin_lock(&eint_lock);
-       mask = __raw_readl(EINT_MASK(exynos_eint_base, data->irq));
-       mask &= ~(EINT_OFFSET_BIT(data->irq));
-       __raw_writel(mask, EINT_MASK(exynos_eint_base, data->irq));
+       mask = __raw_readl(EINT_MASK(exynos_eint_base, data->hwirq));
+       mask &= ~(EINT_OFFSET_BIT(data->hwirq));
+       __raw_writel(mask, EINT_MASK(exynos_eint_base, data->hwirq));
        spin_unlock(&eint_lock);
 }
 
 static inline void exynos_irq_eint_ack(struct irq_data *data)
 {
-       __raw_writel(EINT_OFFSET_BIT(data->irq),
-                    EINT_PEND(exynos_eint_base, data->irq));
+       __raw_writel(EINT_OFFSET_BIT(data->hwirq),
+                    EINT_PEND(exynos_eint_base, data->hwirq));
 }
 
 static void exynos_irq_eint_maskack(struct irq_data *data)
@@ -824,7 +882,7 @@ static void exynos_irq_eint_maskack(struct irq_data *data)
 
 static int exynos_irq_eint_set_type(struct irq_data *data, unsigned int type)
 {
-       int offs = EINT_OFFSET(data->irq);
+       int offs = data->hwirq;
        int shift;
        u32 ctrl, mask;
        u32 newvalue = 0;
@@ -859,10 +917,10 @@ static int exynos_irq_eint_set_type(struct irq_data *data, unsigned int type)
        mask = 0x7 << shift;
 
        spin_lock(&eint_lock);
-       ctrl = __raw_readl(EINT_CON(exynos_eint_base, data->irq));
+       ctrl = __raw_readl(EINT_CON(exynos_eint_base, data->hwirq));
        ctrl &= ~mask;
        ctrl |= newvalue << shift;
-       __raw_writel(ctrl, EINT_CON(exynos_eint_base, data->irq));
+       __raw_writel(ctrl, EINT_CON(exynos_eint_base, data->hwirq));
        spin_unlock(&eint_lock);
 
        if (soc_is_exynos5250())
@@ -906,7 +964,7 @@ static inline void exynos_irq_demux_eint(unsigned int start)
 
        while (status) {
                irq = fls(status) - 1;
-               generic_handle_irq(irq + start);
+               generic_handle_irq(irq_find_mapping(irq_domain, irq + start));
                status &= ~(1 << irq);
        }
 }
@@ -915,8 +973,8 @@ static void exynos_irq_demux_eint16_31(unsigned int irq, struct irq_desc *desc)
 {
        struct irq_chip *chip = irq_get_chip(irq);
        chained_irq_enter(chip, desc);
-       exynos_irq_demux_eint(IRQ_EINT(16));
-       exynos_irq_demux_eint(IRQ_EINT(24));
+       exynos_irq_demux_eint(16);
+       exynos_irq_demux_eint(24);
        chained_irq_exit(chip, desc);
 }
 
@@ -924,6 +982,7 @@ static void exynos_irq_eint0_15(unsigned int irq, struct irq_desc *desc)
 {
        u32 *irq_data = irq_get_handler_data(irq);
        struct irq_chip *chip = irq_get_chip(irq);
+       int eint_irq;
 
        chained_irq_enter(chip, desc);
        chip->irq_mask(&desc->irq_data);
@@ -931,50 +990,123 @@ static void exynos_irq_eint0_15(unsigned int irq, struct irq_desc *desc)
        if (chip->irq_ack)
                chip->irq_ack(&desc->irq_data);
 
-       generic_handle_irq(*irq_data);
+       eint_irq = irq_find_mapping(irq_domain, *irq_data);
+       generic_handle_irq(eint_irq);
 
        chip->irq_unmask(&desc->irq_data);
        chained_irq_exit(chip, desc);
 }
 
-static int __init exynos_init_irq_eint(void)
+static int exynos_eint_irq_domain_map(struct irq_domain *d, unsigned int irq,
+                                       irq_hw_number_t hw)
 {
-       int irq;
+       irq_set_chip_and_handler(irq, &exynos_irq_eint, handle_level_irq);
+       set_irq_flags(irq, IRQF_VALID);
+       return 0;
+}
 
-       if (soc_is_exynos5250())
-               exynos_eint_base = ioremap(EXYNOS5_PA_GPIO1, SZ_4K);
-       else
-               exynos_eint_base = ioremap(EXYNOS4_PA_GPIO2, SZ_4K);
+#ifdef CONFIG_OF
+static int exynos_eint_irq_domain_xlate(struct irq_domain *d,
+               struct device_node *controller, const u32 *intspec,
+               unsigned int intsize, unsigned long *out_hwirq,
+               unsigned int *out_type)
+{
+       if (d->of_node != controller)
+               return -EINVAL;
+       if (intsize < 2)
+               return -EINVAL;
+       *out_hwirq = intspec[0];
+
+       switch (intspec[1]) {
+       case S5P_IRQ_TYPE_LEVEL_LOW:
+               *out_type = IRQ_TYPE_LEVEL_LOW;
+               break;
+       case S5P_IRQ_TYPE_LEVEL_HIGH:
+               *out_type = IRQ_TYPE_LEVEL_HIGH;
+               break;
+       case S5P_IRQ_TYPE_EDGE_FALLING:
+               *out_type = IRQ_TYPE_EDGE_FALLING;
+               break;
+       case S5P_IRQ_TYPE_EDGE_RISING:
+               *out_type = IRQ_TYPE_EDGE_RISING;
+               break;
+       case S5P_IRQ_TYPE_EDGE_BOTH:
+               *out_type = IRQ_TYPE_EDGE_BOTH;
+               break;
+       };
+
+       return 0;
+}
+#else
+static int exynos_eint_irq_domain_xlate(struct irq_domain *d,
+               struct device_node *controller, const u32 *intspec,
+               unsigned int intsize, unsigned long *out_hwirq,
+               unsigned int *out_type)
+{
+       return -EINVAL;
+}
+#endif
+
+static struct irq_domain_ops exynos_eint_irq_domain_ops = {
+       .xlate = exynos_eint_irq_domain_xlate,
+       .map = exynos_eint_irq_domain_map,
+};
 
-       if (exynos_eint_base == NULL) {
+static int __init exynos_init_irq_eint(struct device_node *eint_np,
+                                       struct device_node *parent)
+{
+       int irq, *src_int, irq_base, irq_eint;
+       unsigned int paddr;
+       static unsigned int retry = 0;
+       static struct device_node *np;
+
+       if (retry)
+               goto retry_init;
+
+       if (!eint_np) {
+               paddr = soc_is_exynos5250() ? EXYNOS5_PA_GPIO1 :
+                                               EXYNOS4_PA_GPIO2;
+               exynos_eint_base = ioremap(paddr, SZ_4K);
+       } else {
+               np = of_get_parent(eint_np);
+               exynos_eint_base = of_iomap(np, 0);
+       }
+       if (!exynos_eint_base) {
                pr_err("unable to ioremap for EINT base address\n");
-               return -ENOMEM;
+               return -ENXIO;
        }
 
-       for (irq = 0 ; irq <= 31 ; irq++) {
-               irq_set_chip_and_handler(IRQ_EINT(irq), &exynos_irq_eint,
-                                        handle_level_irq);
-               set_irq_flags(IRQ_EINT(irq), IRQF_VALID);
+       irq_base = irq_alloc_descs(IRQ_EINT(0), 1, EXYNOS_EINT_NR, 0);
+       if (IS_ERR_VALUE(irq_base)) {
+               irq_base = IRQ_EINT(0);
+               pr_warning("%s: irq desc alloc failed. Continuing with %d as "
+                               "linux irq base\n", __func__, irq_base);
+       }
+
+       irq_domain = irq_domain_add_legacy(np, EXYNOS_EINT_NR, irq_base, 0,
+                                        &exynos_eint_irq_domain_ops, NULL);
+       if (WARN_ON(!irq_domain)) {
+               pr_warning("%s: irq domain init failed\n", __func__);
+               return 0;
        }
 
-       irq_set_chained_handler(EXYNOS_IRQ_EINT16_31, exynos_irq_demux_eint16_31);
-
-       for (irq = 0 ; irq <= 15 ; irq++) {
-               eint0_15_data[irq] = IRQ_EINT(irq);
-
-               if (soc_is_exynos5250()) {
-                       irq_set_handler_data(exynos5_eint0_15_src_int[irq],
-                                            &eint0_15_data[irq]);
-                       irq_set_chained_handler(exynos5_eint0_15_src_int[irq],
-                                               exynos_irq_eint0_15);
-               } else {
-                       irq_set_handler_data(exynos4_eint0_15_src_int[irq],
-                                            &eint0_15_data[irq]);
-                       irq_set_chained_handler(exynos4_eint0_15_src_int[irq],
-                                               exynos_irq_eint0_15);
+       irq_eint = eint_np ? irq_of_parse_and_map(np, 16) : EXYNOS_IRQ_EINT16_31;
+       irq_set_chained_handler(irq_eint, exynos_irq_demux_eint16_31);
+
+retry_init:
+       for (irq = 0; irq <= 15; irq++) {
+               eint0_15_data[irq] = irq;
+               src_int = soc_is_exynos5250() ? exynos5_eint0_15_src_int :
+                                               exynos4_eint0_15_src_int;
+               irq_eint = eint_np ? irq_of_parse_and_map(np, irq) : src_int[irq];
+               if (!irq_eint) {
+                       of_node_put(np);
+                       retry = 1;
+                       return -EAGAIN;
                }
+               irq_set_handler_data(irq_eint, &eint0_15_data[irq]);
+               irq_set_chained_handler(irq_eint, exynos_irq_eint0_15);
        }
 
        return 0;
 }
-arch_initcall(exynos_init_irq_eint);
index 69aaa45..4ebe2ab 100644 (file)
@@ -103,10 +103,45 @@ static u8 exynos4212_pdma0_peri[] = {
        DMACH_MIPI_HSI5,
 };
 
-struct dma_pl330_platdata exynos4_pdma0_pdata;
+static u8 exynos5250_pdma0_peri[] = {
+       DMACH_PCM0_RX,
+       DMACH_PCM0_TX,
+       DMACH_PCM2_RX,
+       DMACH_PCM2_TX,
+       DMACH_SPI0_RX,
+       DMACH_SPI0_TX,
+       DMACH_SPI2_RX,
+       DMACH_SPI2_TX,
+       DMACH_I2S0S_TX,
+       DMACH_I2S0_RX,
+       DMACH_I2S0_TX,
+       DMACH_I2S2_RX,
+       DMACH_I2S2_TX,
+       DMACH_UART0_RX,
+       DMACH_UART0_TX,
+       DMACH_UART2_RX,
+       DMACH_UART2_TX,
+       DMACH_UART4_RX,
+       DMACH_UART4_TX,
+       DMACH_SLIMBUS0_RX,
+       DMACH_SLIMBUS0_TX,
+       DMACH_SLIMBUS2_RX,
+       DMACH_SLIMBUS2_TX,
+       DMACH_SLIMBUS4_RX,
+       DMACH_SLIMBUS4_TX,
+       DMACH_AC97_MICIN,
+       DMACH_AC97_PCMIN,
+       DMACH_AC97_PCMOUT,
+       DMACH_MIPI_HSI0,
+       DMACH_MIPI_HSI2,
+       DMACH_MIPI_HSI4,
+       DMACH_MIPI_HSI6,
+};
+
+static struct dma_pl330_platdata exynos_pdma0_pdata;
 
 static AMBA_AHB_DEVICE(exynos4_pdma0, "dma-pl330.0", 0x00041330,
-       EXYNOS4_PA_PDMA0, {EXYNOS4_IRQ_PDMA0}, &exynos4_pdma0_pdata);
+       EXYNOS4_PA_PDMA0, {EXYNOS4_IRQ_PDMA0}, &exynos_pdma0_pdata);
 
 static u8 exynos4210_pdma1_peri[] = {
        DMACH_PCM0_RX,
@@ -169,10 +204,45 @@ static u8 exynos4212_pdma1_peri[] = {
        DMACH_MIPI_HSI7,
 };
 
-static struct dma_pl330_platdata exynos4_pdma1_pdata;
+static u8 exynos5250_pdma1_peri[] = {
+       DMACH_PCM0_RX,
+       DMACH_PCM0_TX,
+       DMACH_PCM1_RX,
+       DMACH_PCM1_TX,
+       DMACH_SPI1_RX,
+       DMACH_SPI1_TX,
+       DMACH_PWM,
+       DMACH_SPDIF,
+       DMACH_I2S0S_TX,
+       DMACH_I2S0_RX,
+       DMACH_I2S0_TX,
+       DMACH_I2S1_RX,
+       DMACH_I2S1_TX,
+       DMACH_UART0_RX,
+       DMACH_UART0_TX,
+       DMACH_UART1_RX,
+       DMACH_UART1_TX,
+       DMACH_UART3_RX,
+       DMACH_UART3_TX,
+       DMACH_SLIMBUS1_RX,
+       DMACH_SLIMBUS1_TX,
+       DMACH_SLIMBUS3_RX,
+       DMACH_SLIMBUS3_TX,
+       DMACH_SLIMBUS5_RX,
+       DMACH_SLIMBUS5_TX,
+       DMACH_SLIMBUS0AUX_RX,
+       DMACH_SLIMBUS0AUX_TX,
+       DMACH_DISP1,
+       DMACH_MIPI_HSI1,
+       DMACH_MIPI_HSI3,
+       DMACH_MIPI_HSI5,
+       DMACH_MIPI_HSI7,
+};
+
+static struct dma_pl330_platdata exynos_pdma1_pdata;
 
 static AMBA_AHB_DEVICE(exynos4_pdma1,  "dma-pl330.1", 0x00041330,
-       EXYNOS4_PA_PDMA1, {EXYNOS4_IRQ_PDMA1}, &exynos4_pdma1_pdata);
+       EXYNOS4_PA_PDMA1, {EXYNOS4_IRQ_PDMA1}, &exynos_pdma1_pdata);
 
 static u8 mdma_peri[] = {
        DMACH_MTOM_0,
@@ -185,46 +255,63 @@ static u8 mdma_peri[] = {
        DMACH_MTOM_7,
 };
 
-static struct dma_pl330_platdata exynos4_mdma1_pdata = {
+static struct dma_pl330_platdata exynos_mdma1_pdata = {
        .nr_valid_peri = ARRAY_SIZE(mdma_peri),
        .peri_id = mdma_peri,
 };
 
 static AMBA_AHB_DEVICE(exynos4_mdma1,  "dma-pl330.2", 0x00041330,
-       EXYNOS4_PA_MDMA1, {EXYNOS4_IRQ_MDMA1}, &exynos4_mdma1_pdata);
+       EXYNOS4_PA_MDMA1, {EXYNOS4_IRQ_MDMA1}, &exynos_mdma1_pdata);
 
-static int __init exynos4_dma_init(void)
+static int __init exynos_dma_init(void)
 {
        if (of_have_populated_dt())
                return 0;
 
        if (soc_is_exynos4210()) {
-               exynos4_pdma0_pdata.nr_valid_peri =
+               exynos_pdma0_pdata.nr_valid_peri =
                        ARRAY_SIZE(exynos4210_pdma0_peri);
-               exynos4_pdma0_pdata.peri_id = exynos4210_pdma0_peri;
-               exynos4_pdma1_pdata.nr_valid_peri =
+               exynos_pdma0_pdata.peri_id = exynos4210_pdma0_peri;
+               exynos_pdma1_pdata.nr_valid_peri =
                        ARRAY_SIZE(exynos4210_pdma1_peri);
-               exynos4_pdma1_pdata.peri_id = exynos4210_pdma1_peri;
+               exynos_pdma1_pdata.peri_id = exynos4210_pdma1_peri;
        } else if (soc_is_exynos4212() || soc_is_exynos4412()) {
-               exynos4_pdma0_pdata.nr_valid_peri =
+               exynos_pdma0_pdata.nr_valid_peri =
                        ARRAY_SIZE(exynos4212_pdma0_peri);
-               exynos4_pdma0_pdata.peri_id = exynos4212_pdma0_peri;
-               exynos4_pdma1_pdata.nr_valid_peri =
+               exynos_pdma0_pdata.peri_id = exynos4212_pdma0_peri;
+               exynos_pdma1_pdata.nr_valid_peri =
                        ARRAY_SIZE(exynos4212_pdma1_peri);
-               exynos4_pdma1_pdata.peri_id = exynos4212_pdma1_peri;
+               exynos_pdma1_pdata.peri_id = exynos4212_pdma1_peri;
+       } else if (soc_is_exynos5250()) {
+               exynos_pdma0_pdata.nr_valid_peri =
+                       ARRAY_SIZE(exynos5250_pdma0_peri);
+               exynos_pdma0_pdata.peri_id = exynos5250_pdma0_peri;
+               exynos_pdma1_pdata.nr_valid_peri =
+                       ARRAY_SIZE(exynos5250_pdma1_peri);
+               exynos_pdma1_pdata.peri_id = exynos5250_pdma1_peri;
+
+               exynos4_pdma0_device.res.start = EXYNOS5_PA_PDMA0;
+               exynos4_pdma0_device.res.end = EXYNOS5_PA_PDMA0 + SZ_4K;
+               exynos4_pdma0_device.irq[0] = EXYNOS5_IRQ_PDMA0;
+               exynos4_pdma1_device.res.start = EXYNOS5_PA_PDMA1;
+               exynos4_pdma1_device.res.end = EXYNOS5_PA_PDMA1 + SZ_4K;
+               exynos4_pdma0_device.irq[0] = EXYNOS5_IRQ_PDMA1;
+               exynos4_mdma1_device.res.start = EXYNOS5_PA_MDMA1;
+               exynos4_mdma1_device.res.end = EXYNOS5_PA_MDMA1 + SZ_4K;
+               exynos4_pdma0_device.irq[0] = EXYNOS5_IRQ_MDMA1;
        }
 
-       dma_cap_set(DMA_SLAVE, exynos4_pdma0_pdata.cap_mask);
-       dma_cap_set(DMA_CYCLIC, exynos4_pdma0_pdata.cap_mask);
+       dma_cap_set(DMA_SLAVE, exynos_pdma0_pdata.cap_mask);
+       dma_cap_set(DMA_CYCLIC, exynos_pdma0_pdata.cap_mask);
        amba_device_register(&exynos4_pdma0_device, &iomem_resource);
 
-       dma_cap_set(DMA_SLAVE, exynos4_pdma1_pdata.cap_mask);
-       dma_cap_set(DMA_CYCLIC, exynos4_pdma1_pdata.cap_mask);
+       dma_cap_set(DMA_SLAVE, exynos_pdma1_pdata.cap_mask);
+       dma_cap_set(DMA_CYCLIC, exynos_pdma1_pdata.cap_mask);
        amba_device_register(&exynos4_pdma1_device, &iomem_resource);
 
-       dma_cap_set(DMA_MEMCPY, exynos4_mdma1_pdata.cap_mask);
+       dma_cap_set(DMA_MEMCPY, exynos_mdma1_pdata.cap_mask);
        amba_device_register(&exynos4_mdma1_device, &iomem_resource);
 
        return 0;
 }
-arch_initcall(exynos4_dma_init);
+arch_initcall(exynos_dma_init);
index d7498af..eb24f1e 100644 (file)
@@ -153,10 +153,11 @@ enum exynos4_gpio_number {
 #define EXYNOS5_GPIO_B2_NR     (4)
 #define EXYNOS5_GPIO_B3_NR     (4)
 #define EXYNOS5_GPIO_C0_NR     (7)
-#define EXYNOS5_GPIO_C1_NR     (7)
+#define EXYNOS5_GPIO_C1_NR     (4)
 #define EXYNOS5_GPIO_C2_NR     (7)
 #define EXYNOS5_GPIO_C3_NR     (7)
-#define EXYNOS5_GPIO_D0_NR     (8)
+#define EXYNOS5_GPIO_C4_NR     (7)
+#define EXYNOS5_GPIO_D0_NR     (4)
 #define EXYNOS5_GPIO_D1_NR     (8)
 #define EXYNOS5_GPIO_Y0_NR     (6)
 #define EXYNOS5_GPIO_Y1_NR     (4)
@@ -199,7 +200,8 @@ enum exynos5_gpio_number {
        EXYNOS5_GPIO_C1_START           = EXYNOS_GPIO_NEXT(EXYNOS5_GPIO_C0),
        EXYNOS5_GPIO_C2_START           = EXYNOS_GPIO_NEXT(EXYNOS5_GPIO_C1),
        EXYNOS5_GPIO_C3_START           = EXYNOS_GPIO_NEXT(EXYNOS5_GPIO_C2),
-       EXYNOS5_GPIO_D0_START           = EXYNOS_GPIO_NEXT(EXYNOS5_GPIO_C3),
+       EXYNOS5_GPIO_C4_START           = EXYNOS_GPIO_NEXT(EXYNOS5_GPIO_C3),
+       EXYNOS5_GPIO_D0_START           = EXYNOS_GPIO_NEXT(EXYNOS5_GPIO_C4),
        EXYNOS5_GPIO_D1_START           = EXYNOS_GPIO_NEXT(EXYNOS5_GPIO_D0),
        EXYNOS5_GPIO_Y0_START           = EXYNOS_GPIO_NEXT(EXYNOS5_GPIO_D1),
        EXYNOS5_GPIO_Y1_START           = EXYNOS_GPIO_NEXT(EXYNOS5_GPIO_Y0),
@@ -242,6 +244,7 @@ enum exynos5_gpio_number {
 #define EXYNOS5_GPC1(_nr)      (EXYNOS5_GPIO_C1_START + (_nr))
 #define EXYNOS5_GPC2(_nr)      (EXYNOS5_GPIO_C2_START + (_nr))
 #define EXYNOS5_GPC3(_nr)      (EXYNOS5_GPIO_C3_START + (_nr))
+#define EXYNOS5_GPC4(_nr)      (EXYNOS5_GPIO_C4_START + (_nr))
 #define EXYNOS5_GPD0(_nr)      (EXYNOS5_GPIO_D0_START + (_nr))
 #define EXYNOS5_GPD1(_nr)      (EXYNOS5_GPIO_D1_START + (_nr))
 #define EXYNOS5_GPY0(_nr)      (EXYNOS5_GPIO_Y0_START + (_nr))
index 591e785..46d4734 100644 (file)
 #define EXYNOS5_IRQ_MIPICSI1           IRQ_SPI(80)
 #define EXYNOS5_IRQ_EFNFCON_DMA_ABORT  IRQ_SPI(81)
 #define EXYNOS5_IRQ_MIPIDSI0           IRQ_SPI(82)
+#define EXYNOS5_IRQ_WDT_IOP            IRQ_SPI(83)
 #define EXYNOS5_IRQ_ROTATOR            IRQ_SPI(84)
 #define EXYNOS5_IRQ_GSC0               IRQ_SPI(85)
 #define EXYNOS5_IRQ_GSC1               IRQ_SPI(86)
 #define EXYNOS5_IRQ_JPEG               IRQ_SPI(89)
 #define EXYNOS5_IRQ_EFNFCON_DMA                IRQ_SPI(90)
 #define EXYNOS5_IRQ_2D                 IRQ_SPI(91)
-#define EXYNOS5_IRQ_SFMC0              IRQ_SPI(92)
-#define EXYNOS5_IRQ_SFMC1              IRQ_SPI(93)
+#define EXYNOS5_IRQ_EFNFCON_0          IRQ_SPI(92)
+#define EXYNOS5_IRQ_EFNFCON_1          IRQ_SPI(93)
 #define EXYNOS5_IRQ_MIXER              IRQ_SPI(94)
 #define EXYNOS5_IRQ_HDMI               IRQ_SPI(95)
 #define EXYNOS5_IRQ_MFC                        IRQ_SPI(96)
 #define EXYNOS5_IRQ_PCM2               IRQ_SPI(104)
 #define EXYNOS5_IRQ_SPDIF              IRQ_SPI(105)
 #define EXYNOS5_IRQ_ADC0               IRQ_SPI(106)
-
+#define EXYNOS5_IRQ_ADC1               IRQ_SPI(107)
 #define EXYNOS5_IRQ_SATA_PHY           IRQ_SPI(108)
 #define EXYNOS5_IRQ_SATA_PMEMREQ       IRQ_SPI(109)
 #define EXYNOS5_IRQ_CAM_C              IRQ_SPI(110)
 #define EXYNOS5_IRQ_DP1_INTP1          IRQ_SPI(113)
 #define EXYNOS5_IRQ_CEC                        IRQ_SPI(114)
 #define EXYNOS5_IRQ_SATA               IRQ_SPI(115)
-#define EXYNOS5_IRQ_NFCON              IRQ_SPI(116)
 
+#define EXYNOS5_IRQ_MCT_L0             IRQ_SPI(120)
+#define EXYNOS5_IRQ_MCT_L1             IRQ_SPI(121)
 #define EXYNOS5_IRQ_MMC44              IRQ_SPI(123)
 #define EXYNOS5_IRQ_MDMA1              IRQ_SPI(124)
 #define EXYNOS5_IRQ_FIMC_LITE0         IRQ_SPI(125)
 #define EXYNOS5_IRQ_RP_TIMER           IRQ_SPI(127)
 
 #define EXYNOS5_IRQ_PMU                        COMBINER_IRQ(1, 2)
-#define EXYNOS5_IRQ_PMU_CPU1           COMBINER_IRQ(1, 6)
 
 #define EXYNOS5_IRQ_SYSMMU_GSC0_0      COMBINER_IRQ(2, 0)
 #define EXYNOS5_IRQ_SYSMMU_GSC0_1      COMBINER_IRQ(2, 1)
 #define EXYNOS5_IRQ_SYSMMU_GSC3_0      COMBINER_IRQ(2, 6)
 #define EXYNOS5_IRQ_SYSMMU_GSC3_1      COMBINER_IRQ(2, 7)
 
+#define EXYNOS5_IRQ_SYSMMU_LITE2_0     COMBINER_IRQ(3, 0)
+#define EXYNOS5_IRQ_SYSMMU_LITE2_1     COMBINER_IRQ(3, 1)
 #define EXYNOS5_IRQ_SYSMMU_FIMD1_0     COMBINER_IRQ(3, 2)
 #define EXYNOS5_IRQ_SYSMMU_FIMD1_1     COMBINER_IRQ(3, 3)
 #define EXYNOS5_IRQ_SYSMMU_LITE0_0     COMBINER_IRQ(3, 4)
 
 #define EXYNOS5_IRQ_SYSMMU_ARM_0       COMBINER_IRQ(6, 0)
 #define EXYNOS5_IRQ_SYSMMU_ARM_1       COMBINER_IRQ(6, 1)
-#define EXYNOS5_IRQ_SYSMMU_MFC_L_0     COMBINER_IRQ(6, 2)
-#define EXYNOS5_IRQ_SYSMMU_MFC_L_1     COMBINER_IRQ(6, 3)
+#define EXYNOS5_IRQ_SYSMMU_MFC_R_0     COMBINER_IRQ(6, 2)
+#define EXYNOS5_IRQ_SYSMMU_MFC_R_1     COMBINER_IRQ(6, 3)
 #define EXYNOS5_IRQ_SYSMMU_RTIC_0      COMBINER_IRQ(6, 4)
 #define EXYNOS5_IRQ_SYSMMU_RTIC_1      COMBINER_IRQ(6, 5)
 #define EXYNOS5_IRQ_SYSMMU_SSS_0       COMBINER_IRQ(6, 6)
 #define EXYNOS5_IRQ_SYSMMU_MDMA1_1     COMBINER_IRQ(7, 3)
 #define EXYNOS5_IRQ_SYSMMU_TV_0                COMBINER_IRQ(7, 4)
 #define EXYNOS5_IRQ_SYSMMU_TV_1                COMBINER_IRQ(7, 5)
-#define EXYNOS5_IRQ_SYSMMU_GPSX_0      COMBINER_IRQ(7, 6)
-#define EXYNOS5_IRQ_SYSMMU_GPSX_1      COMBINER_IRQ(7, 7)
 
-#define EXYNOS5_IRQ_SYSMMU_MFC_R_0     COMBINER_IRQ(8, 5)
-#define EXYNOS5_IRQ_SYSMMU_MFC_R_1     COMBINER_IRQ(8, 6)
+#define EXYNOS5_IRQ_SYSMMU_MFC_L_0     COMBINER_IRQ(8, 5)
+#define EXYNOS5_IRQ_SYSMMU_MFC_L_1     COMBINER_IRQ(8, 6)
 
 #define EXYNOS5_IRQ_SYSMMU_DIS1_0      COMBINER_IRQ(9, 4)
 #define EXYNOS5_IRQ_SYSMMU_DIS1_1      COMBINER_IRQ(9, 5)
 #define EXYNOS5_IRQ_SYSMMU_DRC_0       COMBINER_IRQ(11, 6)
 #define EXYNOS5_IRQ_SYSMMU_DRC_1       COMBINER_IRQ(11, 7)
 
+#define EXYNOS5_IRQ_MDMA1_ABORT                COMBINER_IRQ(13, 1)
+
+#define EXYNOS5_IRQ_MDMA0_ABORT                COMBINER_IRQ(15, 3)
+
 #define EXYNOS5_IRQ_FIMD1_FIFO         COMBINER_IRQ(18, 4)
 #define EXYNOS5_IRQ_FIMD1_VSYNC                COMBINER_IRQ(18, 5)
 #define EXYNOS5_IRQ_FIMD1_SYSTEM       COMBINER_IRQ(18, 6)
 
+#define EXYNOS5_IRQ_ARMIOP_GIC         COMBINER_IRQ(19, 0)
+#define EXYNOS5_IRQ_ARMISP_GIC         COMBINER_IRQ(19, 1)
+#define EXYNOS5_IRQ_IOP_GIC            COMBINER_IRQ(19, 3)
+#define EXYNOS5_IRQ_ISP_GIC            COMBINER_IRQ(19, 4)
+
+#define EXYNOS5_IRQ_PMU_CPU1           COMBINER_IRQ(22, 4)
+
 #define EXYNOS5_IRQ_EINT0              COMBINER_IRQ(23, 0)
-#define EXYNOS5_IRQ_MCT_L0             COMBINER_IRQ(23, 1)
-#define EXYNOS5_IRQ_MCT_L1             COMBINER_IRQ(23, 2)
 #define EXYNOS5_IRQ_MCT_G0             COMBINER_IRQ(23, 3)
 #define EXYNOS5_IRQ_MCT_G1             COMBINER_IRQ(23, 4)
-#define EXYNOS5_IRQ_MCT_G2             COMBINER_IRQ(23, 5)
-#define EXYNOS5_IRQ_MCT_G3             COMBINER_IRQ(23, 6)
 
 #define EXYNOS5_IRQ_EINT1              COMBINER_IRQ(24, 0)
 #define EXYNOS5_IRQ_SYSMMU_LITE1_0     COMBINER_IRQ(24, 1)
 
 #define EXYNOS5_MAX_COMBINER_NR                32
 
-#define EXYNOS5_IRQ_GPIO1_NR_GROUPS    13
+#define EXYNOS5_IRQ_GPIO1_NR_GROUPS    14
 #define EXYNOS5_IRQ_GPIO2_NR_GROUPS    9
 #define EXYNOS5_IRQ_GPIO3_NR_GROUPS    5
 #define EXYNOS5_IRQ_GPIO4_NR_GROUPS    1
index 6e6d11f..cf7d200 100644 (file)
@@ -78,8 +78,8 @@
 
 #define EXYNOS4_PA_GIC_CPU             0x10480000
 #define EXYNOS4_PA_GIC_DIST            0x10490000
-#define EXYNOS5_PA_GIC_CPU             0x10480000
-#define EXYNOS5_PA_GIC_DIST            0x10490000
+#define EXYNOS5_PA_GIC_CPU             0x10482000
+#define EXYNOS5_PA_GIC_DIST            0x10481000
 
 #define EXYNOS4_PA_COREPERI            0x10500000
 #define EXYNOS4_PA_TWD                 0x10500600
index d9578a5..130034d 100644 (file)
 #define EXYNOS5_CLKGATE_IP_PERIS               EXYNOS_CLKREG(0x10960)
 #define EXYNOS5_CLKGATE_BLOCK                  EXYNOS_CLKREG(0x10980)
 
+#define EXYNOS5_PLL_DIV2_SEL                   EXYNOS_CLKREG(0x20A24)
+
 #define EXYNOS5_BPLL_CON0                      EXYNOS_CLKREG(0x20110)
 #define EXYNOS5_CLKSRC_CDREX                   EXYNOS_CLKREG(0x20200)
 #define EXYNOS5_CLKDIV_CDREX                   EXYNOS_CLKREG(0x20500)
index e4b5b60..24bf4ec 100644 (file)
 #include <mach/map.h>
 #include <mach/irqs.h>
 
-#define EINT_REG_NR(x)                 (EINT_OFFSET(x) >> 3)
+#define EINT_REG_NR(x)                 ((x) >> 3)
 #define EINT_CON(b, x)                 (b + 0xE00 + (EINT_REG_NR(x) * 4))
 #define EINT_FLTCON(b, x)              (b + 0xE80 + (EINT_REG_NR(x) * 4))
 #define EINT_MASK(b, x)                        (b + 0xF00 + (EINT_REG_NR(x) * 4))
 #define EINT_PEND(b, x)                        (b + 0xF40 + (EINT_REG_NR(x) * 4))
 
-#define EINT_OFFSET_BIT(x)             (1 << (EINT_OFFSET(x) & 0x7))
+#define EINT_OFFSET_BIT(x)             (1 << ((x) & 0x7))
 
 /* compatibility for plat-s5p/irq-pm.c */
 #define EXYNOS4_EINT40CON              (S5P_VA_GPIO2 + 0xE00)
index 4711c89..4a060f1 100644 (file)
@@ -11,6 +11,7 @@
 
 #include <linux/of_platform.h>
 #include <linux/serial_core.h>
+#include <linux/smsc911x.h>
 
 #include <asm/mach/arch.h>
 #include <asm/hardware/gic.h>
 
 #include <plat/cpu.h>
 #include <plat/regs-serial.h>
+#include <plat/regs-srom.h>
 
 #include "common.h"
 
+static void __init smsc911x_init(int ncs)
+{
+       u32 data;
+
+       /* configure nCS1 width to 16 bits */
+       data = __raw_readl(S5P_SROM_BW) &
+               ~(S5P_SROM_BW__CS_MASK << (ncs * 4));
+       data |= ((1 << S5P_SROM_BW__DATAWIDTH__SHIFT) |
+               (1 << S5P_SROM_BW__WAITENABLE__SHIFT) |
+               (1 << S5P_SROM_BW__BYTEENABLE__SHIFT)) << (ncs * 4);
+       __raw_writel(data, S5P_SROM_BW);
+
+       /* set timing for nCS1 suitable for ethernet chip */
+       __raw_writel((0x1 << S5P_SROM_BCX__PMC__SHIFT) |
+               (0x9 << S5P_SROM_BCX__TACP__SHIFT) |
+               (0xc << S5P_SROM_BCX__TCAH__SHIFT) |
+               (0x1 << S5P_SROM_BCX__TCOH__SHIFT) |
+               (0x6 << S5P_SROM_BCX__TACC__SHIFT) |
+               (0x1 << S5P_SROM_BCX__TCOS__SHIFT) |
+               (0x1 << S5P_SROM_BCX__TACS__SHIFT),
+               S5P_SROM_BC0 + (ncs * 4));
+}
+
 /*
  * The following lookup table is used to override device names when devices
  * are registered from device tree. This is temporarily added to enable
@@ -43,6 +68,18 @@ static const struct of_dev_auxdata exynos5250_auxdata_lookup[] __initconst = {
                                "exynos4210-uart.2", NULL),
        OF_DEV_AUXDATA("samsung,exynos4210-uart", EXYNOS5_PA_UART3,
                                "exynos4210-uart.3", NULL),
+       OF_DEV_AUXDATA("samsung,s3c2440-i2c", EXYNOS5_PA_IIC(0),
+                               "s3c2440-i2c.0", NULL),
+       OF_DEV_AUXDATA("samsung,s3c2440-i2c", EXYNOS5_PA_IIC(1),
+                               "s3c2440-i2c.1", NULL),
+       OF_DEV_AUXDATA("synopsis,dw-mshc-exynos5250", 0x12200000,
+                               "dw_mmc.0", NULL),
+       OF_DEV_AUXDATA("synopsis,dw-mshc-exynos5250", 0x12210000,
+                               "dw_mmc.1", NULL),
+       OF_DEV_AUXDATA("synopsis,dw-mshc-exynos5250", 0x12220000,
+                               "dw_mmc.2", NULL),
+       OF_DEV_AUXDATA("synopsis,dw-mshc-exynos5250", 0x12230000,
+                               "dw_mmc.3", NULL),
        OF_DEV_AUXDATA("arm,pl330", EXYNOS5_PA_PDMA0, "dma-pl330.0", NULL),
        OF_DEV_AUXDATA("arm,pl330", EXYNOS5_PA_PDMA1, "dma-pl330.1", NULL),
        OF_DEV_AUXDATA("arm,pl330", EXYNOS5_PA_MDMA1, "dma-pl330.2", NULL),
@@ -57,6 +94,9 @@ static void __init exynos5250_dt_map_io(void)
 
 static void __init exynos5250_dt_machine_init(void)
 {
+       if (of_machine_is_compatible("samsung,smdk5250"))
+               smsc911x_init(1);
+
        of_platform_populate(NULL, of_default_bus_match_table,
                                exynos5250_auxdata_lookup, NULL);
 }
index 897d9a9..b601fb8 100644 (file)
@@ -388,6 +388,7 @@ static int __cpuinit exynos4_local_timer_setup(struct clock_event_device *evt)
 {
        struct mct_clock_event_device *mevt;
        unsigned int cpu = smp_processor_id();
+       int mct_lx_irq;
 
        mevt = this_cpu_ptr(&percpu_mct_tick);
        mevt->evt = evt;
@@ -414,14 +415,18 @@ static int __cpuinit exynos4_local_timer_setup(struct clock_event_device *evt)
 
        if (mct_int_type == MCT_INT_SPI) {
                if (cpu == 0) {
+                       mct_lx_irq = soc_is_exynos4210() ? EXYNOS4_IRQ_MCT_L0 :
+                                               EXYNOS5_IRQ_MCT_L0;
                        mct_tick0_event_irq.dev_id = mevt;
-                       evt->irq = EXYNOS4_IRQ_MCT_L0;
-                       setup_irq(EXYNOS4_IRQ_MCT_L0, &mct_tick0_event_irq);
+                       evt->irq = mct_lx_irq;
+                       setup_irq(mct_lx_irq, &mct_tick0_event_irq);
                } else {
+                       mct_lx_irq = soc_is_exynos4210() ? EXYNOS4_IRQ_MCT_L1 :
+                                               EXYNOS5_IRQ_MCT_L1;
                        mct_tick1_event_irq.dev_id = mevt;
-                       evt->irq = EXYNOS4_IRQ_MCT_L1;
-                       setup_irq(EXYNOS4_IRQ_MCT_L1, &mct_tick1_event_irq);
-                       irq_set_affinity(EXYNOS4_IRQ_MCT_L1, cpumask_of(1));
+                       evt->irq = mct_lx_irq;
+                       setup_irq(mct_lx_irq, &mct_tick1_event_irq);
+                       irq_set_affinity(mct_lx_irq, cpumask_of(1));
                }
        } else {
                enable_percpu_irq(EXYNOS_IRQ_MCT_LOCALTIMER, 0);
@@ -473,7 +478,7 @@ static void __init exynos4_timer_resources(void)
 
 static void __init exynos4_timer_init(void)
 {
-       if (soc_is_exynos4210())
+       if ((soc_is_exynos4210()) || (soc_is_exynos5250()))
                mct_int_type = MCT_INT_SPI;
        else
                mct_int_type = MCT_INT_PPI;
index 428cfeb..7164aa9 100644 (file)
@@ -275,7 +275,7 @@ static void exynos4_restore_pll(void)
 
 static struct subsys_interface exynos4_pm_interface = {
        .name           = "exynos4_pm",
-       .subsys         = &exynos4_subsys,
+       .subsys         = &exynos_subsys,
        .add_dev        = exynos4_pm_add,
 };
 
index f68a9bb..bea0907 100644 (file)
@@ -115,17 +115,6 @@ struct clksrc_sources clk_src_apll = {
        .nr_sources     = ARRAY_SIZE(clk_src_apll_list),
 };
 
-/* Possible clock sources for BPLL Mux */
-static struct clk *clk_src_bpll_list[] = {
-       [0] = &clk_fin_bpll,
-       [1] = &clk_fout_bpll,
-};
-
-struct clksrc_sources clk_src_bpll = {
-       .sources        = clk_src_bpll_list,
-       .nr_sources     = ARRAY_SIZE(clk_src_bpll_list),
-};
-
 /* Possible clock sources for CPLL Mux */
 static struct clk *clk_src_cpll_list[] = {
        [0] = &clk_fin_cpll,
index a0ffc77..77e65b4 100644 (file)
@@ -291,7 +291,7 @@ config S3C_DMA
 config SAMSUNG_DMADEV
        bool
        select DMADEVICES
-       select PL330_DMA if (CPU_EXYNOS4210 || CPU_S5PV210 || CPU_S5PC100 || \
+       select PL330_DMA if (ARCH_EXYNOS5 || ARCH_EXYNOS4 || CPU_S5PV210 || CPU_S5PC100 || \
                                        CPU_S5P6450 || CPU_S5P6440)
        select ARM_AMBA
        help
index 787ceac..0721293 100644 (file)
@@ -202,7 +202,7 @@ extern struct bus_type s3c2443_subsys;
 extern struct bus_type s3c6410_subsys;
 extern struct bus_type s5p64x0_subsys;
 extern struct bus_type s5pv210_subsys;
-extern struct bus_type exynos4_subsys;
+extern struct bus_type exynos_subsys;
 
 extern void (*s5pc1xx_idle)(void);
 
index 0670f37..d384a80 100644 (file)
@@ -90,6 +90,7 @@ enum dma_ch {
        DMACH_MIPI_HSI5,
        DMACH_MIPI_HSI6,
        DMACH_MIPI_HSI7,
+       DMACH_DISP1,
        DMACH_MTOM_0,
        DMACH_MTOM_1,
        DMACH_MTOM_2,
index e991d91..f88bb9f 100644 (file)
@@ -2452,6 +2452,12 @@ static struct samsung_gpio_chip exynos5_gpios_1[] = {
                        .ngpio  = EXYNOS5_GPIO_C3_NR,
                        .label  = "GPC3",
                },
+       }, {
+               .chip   = {
+                       .base   = EXYNOS5_GPC4(0),
+                       .ngpio  = EXYNOS5_GPIO_C4_NR,
+                       .label  = "GPC4",
+               },
        }, {
                .chip   = {
                        .base   = EXYNOS5_GPD0(0),
@@ -2878,8 +2884,11 @@ static __init int samsung_gpiolib_init(void)
                        goto err_ioremap1;
                }
 
+               /* need to set base address for gpc4 */
+               exynos5_gpios_1[11].base = gpio_base1 + 0x2E0;
+
                /* need to set base address for gpx */
-               chip = &exynos5_gpios_1[20];
+               chip = &exynos5_gpios_1[21];
                gpx_base = gpio_base1 + 0xC00;
                for (i = 0; i < 4; i++, chip++, gpx_base += 0x20)
                        chip->base = gpx_base;
index 92ec3eb..35056fd 100644 (file)
 #include <linux/mmc/host.h>
 #include <linux/mmc/mmc.h>
 #include <linux/mmc/dw_mmc.h>
+#include <linux/of.h>
 #include "dw_mmc.h"
 
+#ifdef CONFIG_OF
+static struct dw_mci_drv_data synopsis_drv_data = {
+       .ctrl_type      = DW_MCI_TYPE_SYNOPSIS,
+};
+
+static struct dw_mci_drv_data exynos5250_drv_data = {
+       .ctrl_type      = DW_MCI_TYPE_EXYNOS5250,
+       .caps           = MMC_CAP_UHS_DDR50 | MMC_CAP_1_8V_DDR |
+                               MMC_CAP_8_BIT_DATA | MMC_CAP_CMD23,
+};
+
+static const struct of_device_id dw_mci_pltfm_match[] = {
+       { .compatible = "synopsis,dw-mshc",
+                       .data = (void *)&synopsis_drv_data, },
+       { .compatible = "synopsis,dw-mshc-exynos5250",
+                       .data = (void *)&exynos5250_drv_data, },
+       {},
+};
+MODULE_DEVICE_TABLE(of, dw_mci_pltfm_match);
+#else
+static const struct of_device_id dw_mci_pltfm_match[];
+#endif
+
 static int dw_mci_pltfm_probe(struct platform_device *pdev)
 {
        struct dw_mci *host;
@@ -51,6 +75,13 @@ static int dw_mci_pltfm_probe(struct platform_device *pdev)
        if (!host->regs)
                goto err_free;
        platform_set_drvdata(pdev, host);
+
+       if (pdev->dev.of_node) {
+               const struct of_device_id *match;
+               match = of_match_node(dw_mci_pltfm_match, pdev->dev.of_node);
+               host->drv_data = match->data;
+       }
+
        ret = dw_mci_probe(host);
        if (ret)
                goto err_out;
@@ -111,6 +142,7 @@ static struct platform_driver dw_mci_pltfm_driver = {
        .remove         = __exit_p(dw_mci_pltfm_remove),
        .driver         = {
                .name           = "dw_mmc",
+               .of_match_table = of_match_ptr(dw_mci_pltfm_match),
                .pm             = &dw_mci_pltfm_pmops,
        },
 };
index ab3fc46..ed511e9 100644 (file)
 #include <linux/bitops.h>
 #include <linux/regulator/consumer.h>
 #include <linux/workqueue.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
 
 #include "dw_mmc.h"
 
+#define NUM_PINS(x) (x + 2)
+
 /* Common flag combinations */
 #define DW_MCI_DATA_ERROR_FLAGS        (SDMMC_INT_DTO | SDMMC_INT_DCRC | \
                                 SDMMC_INT_HTO | SDMMC_INT_SBE  | \
@@ -86,6 +90,8 @@ struct idmac_desc {
 struct dw_mci_slot {
        struct mmc_host         *mmc;
        struct dw_mci           *host;
+       int                     wp_gpio;
+       int                     cd_gpio;
 
        u32                     ctype;
 
@@ -100,8 +106,6 @@ struct dw_mci_slot {
        int                     last_detect_state;
 };
 
-static struct workqueue_struct *dw_mci_card_workqueue;
-
 #if defined(CONFIG_DEBUG_FS)
 static int dw_mci_req_show(struct seq_file *s, void *v)
 {
@@ -232,6 +236,7 @@ static void dw_mci_set_timeout(struct dw_mci *host)
 static u32 dw_mci_prepare_command(struct mmc_host *mmc, struct mmc_command *cmd)
 {
        struct mmc_data *data;
+       struct dw_mci_slot *slot = mmc_priv(mmc);
        u32 cmdr;
        cmd->error = -EINPROGRESS;
 
@@ -261,6 +266,10 @@ static u32 dw_mci_prepare_command(struct mmc_host *mmc, struct mmc_command *cmd)
                        cmdr |= SDMMC_CMD_DAT_WR;
        }
 
+       if (slot->host->drv_data->ctrl_type == DW_MCI_TYPE_EXYNOS5250)
+               if (SDMMC_CLKSEL_GET_SELCLK_DRV(mci_readl(slot->host, CLKSEL)))
+                       cmdr |= SDMMC_USE_HOLD_REG;
+
        return cmdr;
 }
 
@@ -783,10 +792,19 @@ static void dw_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
        regs = mci_readl(slot->host, UHS_REG);
 
        /* DDR mode set */
-       if (ios->timing == MMC_TIMING_UHS_DDR50)
+       if (ios->timing == MMC_TIMING_UHS_DDR50) {
                regs |= (0x1 << slot->id) << 16;
-       else
+               mci_writel(slot->host, CLKSEL, slot->host->ddr_timing);
+       } else {
                regs &= ~(0x1 << slot->id) << 16;
+               mci_writel(slot->host, CLKSEL, slot->host->sdr_timing);
+       }
+
+       if (slot->host->drv_data->ctrl_type == DW_MCI_TYPE_EXYNOS5250) {
+               slot->host->bus_hz = clk_get_rate(slot->host->ciu_clk);
+               slot->host->bus_hz /= SDMMC_CLKSEL_GET_DIVRATIO(
+                                       mci_readl(slot->host, CLKSEL));
+       }
 
        mci_writel(slot->host, UHS_REG, regs);
 
@@ -814,8 +832,12 @@ static int dw_mci_get_ro(struct mmc_host *mmc)
        struct dw_mci_board *brd = slot->host->pdata;
 
        /* Use platform get_ro function, else try on board write protect */
-       if (brd->get_ro)
+       if (brd->quirks & DW_MCI_QUIRK_NO_WRITE_PROTECT)
+               read_only = 0;
+       else if (brd->get_ro)
                read_only = brd->get_ro(slot->id);
+       else if (gpio_is_valid(slot->wp_gpio))
+               read_only = gpio_get_value(slot->wp_gpio);
        else
                read_only =
                        mci_readl(slot->host, WRTPRT) & (1 << slot->id) ? 1 : 0;
@@ -837,6 +859,8 @@ static int dw_mci_get_cd(struct mmc_host *mmc)
                present = 1;
        else if (brd->get_cd)
                present = !brd->get_cd(slot->id);
+       else if (gpio_is_valid(slot->cd_gpio))
+               present = gpio_get_value(slot->cd_gpio);
        else
                present = (mci_readl(slot->host, CDETECT) & (1 << slot->id))
                        == 0 ? 1 : 0;
@@ -1605,7 +1629,7 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id)
 
                if (pending & SDMMC_INT_CD) {
                        mci_writel(host, RINTSTS, SDMMC_INT_CD);
-                       queue_work(dw_mci_card_workqueue, &host->card_work);
+                       queue_work(host->card_workqueue, &host->card_work);
                }
 
                /* Handle SDIO Interrupts */
@@ -1747,6 +1771,96 @@ static void dw_mci_work_routine_card(struct work_struct *work)
        }
 }
 
+#ifdef CONFIG_OF
+static struct device_node *dw_mci_of_find_slot_node(struct device *dev, u8 slot)
+{
+       struct device_node *np;
+       char name[7];
+
+       if (!dev || !dev->of_node)
+               return NULL;
+
+       for_each_child_of_node(dev->of_node, np) {
+               sprintf(name, "slot%d", slot);
+               if (!strcmp(name, np->name))
+                       return np;
+       }
+       return NULL;
+}
+
+static u32 dw_mci_of_get_bus_wd(struct device *dev, u8 slot)
+{
+       struct device_node *np = dw_mci_of_find_slot_node(dev, slot);
+       u32 bus_wd = 1;
+
+       if (!np)
+               return 1;
+
+       if (of_property_read_u32(np, "bus-width", &bus_wd))
+               dev_err(dev, "bus-width property not found, assuming width"
+                              " as 1\n");
+       return bus_wd;
+}
+
+static int dw_mci_of_setup_bus(struct dw_mci *host, u8 slot, u32 bus_wd)
+{
+       struct device_node *np = dw_mci_of_find_slot_node(&host->dev, slot);
+       int idx, gpio, ret;
+
+       for (idx = 0; idx < NUM_PINS(bus_wd); idx++) {
+               gpio = of_get_gpio(np, idx);
+               if (!gpio_is_valid(gpio)) {
+                       dev_err(&host->dev, "invalid gpio: %d\n", gpio);
+                       return -EINVAL;
+               }
+
+               ret = devm_gpio_request(&host->dev, gpio, "dw-mci-bus");
+               if (ret) {
+                       dev_err(&host->dev, "gpio [%d] request failed\n", gpio);
+                       return -EBUSY;
+               }
+       }
+
+       host->slot[slot]->wp_gpio = -1;
+       gpio = of_get_named_gpio(np, "wp_gpios", 0);
+       if (!gpio_is_valid(gpio)) {
+               dev_info(&host->dev, "wp gpio not available");
+       } else {
+               ret = devm_gpio_request(&host->dev, gpio, "dw-mci-wp");
+               if (ret)
+                       dev_info(&host->dev, "gpio [%d] request failed\n",
+                                               gpio);
+               else
+                       host->slot[slot]->wp_gpio = gpio;
+       }
+
+       host->slot[slot]->cd_gpio = -1;
+       gpio = of_get_named_gpio(np, "cd-gpios", 0);
+       if (!gpio_is_valid(gpio)) {
+               dev_info(&host->dev, "cd gpio not available");
+       } else {
+               ret = devm_gpio_request(&host->dev, gpio, "dw-mci-cd");
+               if (ret)
+                       dev_err(&host->dev, "gpio [%d] request failed\n", gpio);
+               else
+                       host->slot[slot]->cd_gpio = gpio;
+       }
+
+       return 0;
+}
+
+#else /* CONFIG_OF */
+static u32 dw_mci_of_get_bus_wd(struct device *dev, u8 slot)
+{
+       return 1;
+}
+
+static int dw_mci_of_setup_bus(struct dw_mci *host, u8 slot, u32 bus_wd)
+{
+       return -EINVAL;
+}
+#endif /* CONFIG_OF */
+
 static int __init dw_mci_init_slot(struct dw_mci *host, unsigned int id)
 {
        struct mmc_host *mmc;
@@ -1760,6 +1874,7 @@ static int __init dw_mci_init_slot(struct dw_mci *host, unsigned int id)
        slot->id = id;
        slot->mmc = mmc;
        slot->host = host;
+       host->slot[id] = slot;
 
        mmc->ops = &dw_mci_ops;
        mmc->f_min = DIV_ROUND_UP(host->bus_hz, 510);
@@ -1780,12 +1895,21 @@ static int __init dw_mci_init_slot(struct dw_mci *host, unsigned int id)
        if (host->pdata->caps)
                mmc->caps = host->pdata->caps;
 
+       mmc->caps |= host->drv_data->caps;
+
        if (host->pdata->caps2)
                mmc->caps2 = host->pdata->caps2;
 
-       if (host->pdata->get_bus_wd)
+       if (host->pdata->get_bus_wd) {
                if (host->pdata->get_bus_wd(slot->id) >= 4)
                        mmc->caps |= MMC_CAP_4_BIT_DATA;
+       } else if (host->dev.of_node) {
+               unsigned int bus_width;
+               bus_width = dw_mci_of_get_bus_wd(&host->dev, slot->id);
+               if (bus_width >= 4)
+                       mmc->caps |= MMC_CAP_4_BIT_DATA;
+               dw_mci_of_setup_bus(host, slot->id, bus_width);
+       }
 
        if (host->pdata->quirks & DW_MCI_QUIRK_HIGHSPEED)
                mmc->caps |= MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED;
@@ -1830,7 +1954,6 @@ static int __init dw_mci_init_slot(struct dw_mci *host, unsigned int id)
        else
                clear_bit(DW_MMC_CARD_PRESENT, &slot->flags);
 
-       host->slot[id] = slot;
        mmc_add_host(mmc);
 
 #if defined(CONFIG_DEBUG_FS)
@@ -1844,7 +1967,7 @@ static int __init dw_mci_init_slot(struct dw_mci *host, unsigned int id)
         * Card may have been plugged in prior to boot so we
         * need to run the detect tasklet
         */
-       queue_work(dw_mci_card_workqueue, &host->card_work);
+       queue_work(host->card_workqueue, &host->card_work);
 
        return 0;
 }
@@ -1923,15 +2046,88 @@ static bool mci_wait_reset(struct device *dev, struct dw_mci *host)
        return false;
 }
 
+#ifdef CONFIG_OF
+static struct dw_mci_of_quirks {
+       char *quirk;
+       int id;
+} of_quriks[] = {
+       {
+               .quirk  = "supports-highspeed",
+               .id     = DW_MCI_QUIRK_HIGHSPEED,
+       }, {
+               .quirk  = "card-detection-broken",
+               .id     = DW_MCI_QUIRK_BROKEN_CARD_DETECTION,
+       }, {
+               .quirk  = "no-write-protect",
+               .id     = DW_MCI_QUIRK_NO_WRITE_PROTECT,
+       }
+};
+
+static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host)
+{
+       struct dw_mci_board *pdata;
+       struct device *dev = &host->dev;
+       struct device_node *np = dev->of_node, *slot;
+       u32 timing[3];
+       int idx, cnt;
+
+       pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
+       if (!pdata) {
+               dev_err(dev, "could not allocate memory for pdata\n");
+               return ERR_PTR(-ENOMEM);
+       }
+
+       /* find out number of slots supported */
+       for_each_child_of_node(np, slot)
+               pdata->num_slots++;
+
+       /* get quirks */
+       cnt = sizeof(of_quriks) / sizeof(struct dw_mci_of_quirks);
+       for (idx = 0; idx < cnt; idx++)
+               if (of_get_property(np, of_quriks[idx].quirk, NULL))
+                       pdata->quirks |= of_quriks[idx].id;
+
+       if (of_property_read_u32_array(dev->of_node,
+                       "samsung,dw-mshc-sdr-timing", timing, 3))
+               host->sdr_timing = DW_MCI_DEF_SDR_TIMING;
+       else
+               host->sdr_timing = SDMMC_CLKSEL_TIMING(timing[0],
+                                       timing[1], timing[2]);
+
+       if (of_property_read_u32_array(dev->of_node,
+                       "samsung,dw-mshc-ddr-timing", timing, 3))
+               host->ddr_timing = DW_MCI_DEF_DDR_TIMING;
+       else
+               host->ddr_timing = SDMMC_CLKSEL_TIMING(timing[0],
+                                       timing[1], timing[2]);
+
+       if (of_property_read_u32(np, "fifo-depth", &pdata->fifo_depth))
+               dev_info(dev, "fifo-depth property not found, using "
+                               "value of FIFOTH register as default\n");
+
+       of_property_read_u32(np, "card-detect-delay", &pdata->detect_delay_ms);
+
+       return pdata;
+}
+
+#else /* CONFIG_OF */
+static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host)
+{
+       return ERR_PTR(-EINVAL);
+}
+#endif /* CONFIG_OF */
+
 int dw_mci_probe(struct dw_mci *host)
 {
        int width, i, ret = 0;
        u32 fifo_size;
 
-       if (!host->pdata || !host->pdata->init) {
-               dev_err(&host->dev,
-                       "Platform data must supply init function\n");
-               return -ENODEV;
+       if (!host->pdata) {
+               host->pdata = dw_mci_parse_dt(host);
+               if (IS_ERR(host->pdata)) {
+                       dev_err(&host->dev, "platform data not available\n");
+                       return -EINVAL;
+               }
        }
 
        if (!host->pdata->select_slot && host->pdata->num_slots > 1) {
@@ -1940,19 +2136,35 @@ int dw_mci_probe(struct dw_mci *host)
                return -ENODEV;
        }
 
-       if (!host->pdata->bus_hz) {
+       host->biu_clk = clk_get(&host->dev, "biu");
+       if (IS_ERR(host->biu_clk))
+               dev_info(&host->dev, "biu clock not available\n");
+       else
+               clk_enable(host->biu_clk);
+
+       host->ciu_clk = clk_get(&host->dev, "ciu");
+       if (IS_ERR(host->ciu_clk))
+               dev_info(&host->dev, "ciu clock not available\n");
+       else
+               clk_enable(host->ciu_clk);
+
+       if (IS_ERR(host->ciu_clk))
+               host->bus_hz = host->pdata->bus_hz;
+       else
+               host->bus_hz = clk_get_rate(host->ciu_clk);
+
+       if (!host->bus_hz) {
                dev_err(&host->dev,
                        "Platform data must supply bus speed\n");
-               return -ENODEV;
+               ret = -ENODEV;
+               goto err_clk;
        }
 
-       host->bus_hz = host->pdata->bus_hz;
        host->quirks = host->pdata->quirks;
 
        spin_lock_init(&host->lock);
        INIT_LIST_HEAD(&host->queue);
 
-
        host->dma_ops = host->pdata->dma_ops;
        dw_mci_init_dma(host);
 
@@ -2021,9 +2233,9 @@ int dw_mci_probe(struct dw_mci *host)
        mci_writel(host, CLKSRC, 0);
 
        tasklet_init(&host->tasklet, dw_mci_tasklet_func, (unsigned long)host);
-       dw_mci_card_workqueue = alloc_workqueue("dw-mci-card",
+       host->card_workqueue = alloc_workqueue("dw-mci-card",
                        WQ_MEM_RECLAIM | WQ_NON_REENTRANT, 1);
-       if (!dw_mci_card_workqueue)
+       if (!host->card_workqueue)
                goto err_dmaunmap;
        INIT_WORK(&host->card_work, dw_mci_work_routine_card);
        ret = request_irq(host->irq, dw_mci_interrupt, host->irq_flags, "dw-mci", host);
@@ -2085,7 +2297,7 @@ err_init_slot:
        free_irq(host->irq, host);
 
 err_workqueue:
-       destroy_workqueue(dw_mci_card_workqueue);
+       destroy_workqueue(host->card_workqueue);
 
 err_dmaunmap:
        if (host->use_dma && host->dma_ops->exit)
@@ -2097,6 +2309,13 @@ err_dmaunmap:
                regulator_disable(host->vmmc);
                regulator_put(host->vmmc);
        }
+       kfree(host);
+
+err_clk:
+       clk_disable(host->ciu_clk);
+       clk_disable(host->biu_clk);
+       clk_put(host->ciu_clk);
+       clk_put(host->biu_clk);
        return ret;
 }
 EXPORT_SYMBOL(dw_mci_probe);
@@ -2119,7 +2338,7 @@ void dw_mci_remove(struct dw_mci *host)
        mci_writel(host, CLKSRC, 0);
 
        free_irq(host->irq, host);
-       destroy_workqueue(dw_mci_card_workqueue);
+       destroy_workqueue(host->card_workqueue);
        dma_free_coherent(&host->dev, PAGE_SIZE, host->sg_cpu, host->sg_dma);
 
        if (host->use_dma && host->dma_ops->exit)
@@ -2130,6 +2349,10 @@ void dw_mci_remove(struct dw_mci *host)
                regulator_put(host->vmmc);
        }
 
+       clk_disable(host->ciu_clk);
+       clk_disable(host->biu_clk);
+       clk_put(host->ciu_clk);
+       clk_put(host->biu_clk);
 }
 EXPORT_SYMBOL(dw_mci_remove);
 
index 15c27e1..4b7e42b 100644 (file)
@@ -53,6 +53,7 @@
 #define SDMMC_IDINTEN          0x090
 #define SDMMC_DSCADDR          0x094
 #define SDMMC_BUFADDR          0x098
+#define SDMMC_CLKSEL           0x09C /* specific to Samsung Exynos5250 */
 #define SDMMC_DATA(x)          (x)
 
 /*
 #define SDMMC_INT_ERROR                        0xbfc2
 /* Command register defines */
 #define SDMMC_CMD_START                        BIT(31)
+#define SDMMC_USE_HOLD_REG             BIT(29)
 #define SDMMC_CMD_CCS_EXP              BIT(23)
 #define SDMMC_CMD_CEATA_RD             BIT(22)
 #define SDMMC_CMD_UPD_CLK              BIT(21)
 /* Version ID register define */
 #define SDMMC_GET_VERID(x)             ((x) & 0xFFFF)
 
+#define DW_MCI_DEF_SDR_TIMING          0x03030002
+#define DW_MCI_DEF_DDR_TIMING          0x03020001
+#define SDMMC_CLKSEL_CCLK_SAMPLE(x)    (((x) & 3) << 0)
+#define SDMMC_CLKSEL_CCLK_DRIVE(x)     (((x) & 3) << 16)
+#define SDMMC_CLKSEL_CCLK_DIVIDER(x)   (((x) & 3) << 24)
+#define SDMMC_CLKSEL_TIMING(x, y, z)   (SDMMC_CLKSEL_CCLK_SAMPLE(x) |  \
+                                       SDMMC_CLKSEL_CCLK_DRIVE(y) |    \
+                                       SDMMC_CLKSEL_CCLK_DIVIDER(z))
+#define SDMMC_CLKSEL_GET_DIVRATIO(x)   ((((x) >> 24) & 0x7) + 1)
+#define SDMMC_CLKSEL_GET_SELCLK_DRV(x) (((x) >> 16) & 0x7)
+
 /* Register access macros */
 #define mci_readl(dev, reg)                    \
        __raw_readl((dev)->regs + SDMMC_##reg)
@@ -182,4 +195,14 @@ extern int dw_mci_suspend(struct dw_mci *host);
 extern int dw_mci_resume(struct dw_mci *host);
 #endif
 
+/* Variations in the dw_mci controller */
+#define DW_MCI_TYPE_SYNOPSIS           0
+#define DW_MCI_TYPE_EXYNOS5250         1 /* Samsung Exynos5250 Extensions */
+
+/* dw_mci platform driver data */
+struct dw_mci_drv_data {
+       unsigned long           ctrl_type;
+       unsigned long           caps;
+};
+
 #endif /* _DW_MMC_H_ */
index 9cf0060..bbe6039 100644 (file)
@@ -66,14 +66,16 @@ struct device_node *of_irq_find_parent(struct device_node *child)
                if (parp == NULL)
                        p = of_get_parent(child);
                else {
+                       of_node_put(child);
                        if (of_irq_workarounds & OF_IMAP_NO_PHANDLE)
                                p = of_node_get(of_irq_dflt_pic);
                        else
                                p = of_find_node_by_phandle(be32_to_cpup(parp));
+                       return p;
                }
                of_node_put(child);
                child = p;
-       } while (p && of_get_property(p, "#interrupt-cells", NULL) == NULL);
+       } while (p);
 
        return p;
 }
@@ -416,8 +418,6 @@ void __init of_irq_init(const struct of_device_id *matches)
        INIT_LIST_HEAD(&intc_parent_list);
 
        for_each_matching_node(np, matches) {
-               if (!of_find_property(np, "interrupt-controller", NULL))
-                       continue;
                /*
                 * Here, we allocate and populate an intc_desc with the node
                 * pointer, interrupt-parent device_node etc.
@@ -452,7 +452,6 @@ void __init of_irq_init(const struct of_device_id *matches)
                        if (desc->interrupt_parent != parent)
                                continue;
 
-                       list_del(&desc->list);
                        match = of_match_node(matches, desc->dev);
                        if (WARN(!match->data,
                            "of_irq_init: no init function for %s\n",
@@ -466,6 +465,15 @@ void __init of_irq_init(const struct of_device_id *matches)
                                 desc->dev, desc->interrupt_parent);
                        irq_init_cb = match->data;
                        ret = irq_init_cb(desc->dev, desc->interrupt_parent);
+                       if (ret == -EAGAIN)
+                               /* 
+                                * Interrupt controller's initialization did not
+                                * complete and should be retried. So let its
+                                * intc_desc be on intc_desc_list.
+                                */
+                               continue;
+                       list_del(&desc->list);
+
                        if (ret) {
                                kfree(desc);
                                continue;
@@ -482,7 +490,18 @@ void __init of_irq_init(const struct of_device_id *matches)
                desc = list_first_entry(&intc_parent_list, typeof(*desc), list);
                if (list_empty(&intc_parent_list) || !desc) {
                        pr_err("of_irq_init: children remain, but no parents\n");
-                       break;
+                       /*
+                        * If a search with NULL as parent did not result in any
+                        * new parent being found, then the scan for matching
+                        * interrupt controller nodes is considered as complete.
+                        * Otherwise, if there are pending elements on the
+                        * intc_desc_list, then retry this process again with
+                        * NULL as parent.
+                        */
+                       if (!parent)
+                               break;
+                       parent = NULL;
+                       continue;
                }
                list_del(&desc->list);
                parent = desc->dev;
index 8f66e28..6e6d036 100644 (file)
@@ -78,7 +78,12 @@ struct mmc_data;
  * @data_offset: Set the offset of DATA register according to VERID.
  * @dev: Device associated with the MMC controller.
  * @pdata: Platform data associated with the MMC controller.
+ * @drv_data: Driver specific data for identified variant of the controller
+ * @biu_clk: Pointer to bus interface unit clock instance.
+ * @ciu_clk: Pointer to card interface unit clock instance.
  * @slot: Slots sharing this MMC controller.
+ * @sdr_timing: Clock phase shifting for driving and sampling in sdr mode
+ * @ddr_timing: Clock phase shifting for driving and sampling in ddr mode
  * @fifo_depth: depth of FIFO.
  * @data_shift: log2 of FIFO item size.
  * @part_buf_start: Start index in part_buf.
@@ -125,6 +130,7 @@ struct dw_mci {
        struct mmc_request      *mrq;
        struct mmc_command      *cmd;
        struct mmc_data         *data;
+       struct workqueue_struct *card_workqueue;
 
        /* DMA interface members*/
        int                     use_dma;
@@ -157,8 +163,15 @@ struct dw_mci {
        u16                     data_offset;
        struct device           dev;
        struct dw_mci_board     *pdata;
+       struct dw_mci_drv_data  *drv_data;
+       struct clk              *biu_clk;
+       struct clk              *ciu_clk;
        struct dw_mci_slot      *slot[MAX_MCI_SLOTS];
 
+       /* Phase Shift Value (for exynos5250 variant) */
+       u32                     sdr_timing;
+       u32                     ddr_timing;
+
        /* FIFO push and pull */
        int                     fifo_depth;
        int                     data_shift;
@@ -200,7 +213,8 @@ struct dw_mci_dma_ops {
 #define DW_MCI_QUIRK_HIGHSPEED                 BIT(2)
 /* Unreliable card detection */
 #define DW_MCI_QUIRK_BROKEN_CARD_DETECTION     BIT(3)
-
+/* Write Protect detection not available */
+#define DW_MCI_QUIRK_NO_WRITE_PROTECT          BIT(4)
 
 struct dma_pdata;