diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-05-26 21:22:27 +0200 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-05-26 21:22:27 +0200 |
commit | ce53044c68cf4fb6c50a2a0d88786be65fae7235 (patch) | |
tree | 19c21da7d261412192e189ef3fd1a9ff4e7ba5c2 | |
parent | Merge tag 'defconfig' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/ar... (diff) | |
parent | Merge branch 'next/devel-samsung-iommu' of git://git.kernel.org/pub/scm/linux... (diff) | |
download | linux-ce53044c68cf4fb6c50a2a0d88786be65fae7235.tar.xz linux-ce53044c68cf4fb6c50a2a0d88786be65fae7235.zip |
Merge tag 'drivers' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc
Pull arm-soc driver specific updates from Olof Johansson:
"These changes are specific to some driver that may be used by multiple
boards or socs. The most significant change in here is the move of
the samsung iommu code from a platform specific in-kernel interface to
the generic iommu subsystem."
Fix up trivial conflicts in arch/arm/mach-exynos/Kconfig
* tag 'drivers' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc: (28 commits)
mmc: dt: Consolidate DT bindings
iommu/exynos: Add iommu driver for EXYNOS Platforms
ARM: davinci: optimize the DMA ISR
ARM: davinci: implement DEBUG_LL port choice
ARM: tegra: Add SMMU enabler in AHB
ARM: tegra: Add Tegra AHB driver
Input: pxa27x_keypad add choice to set direct_key_mask
Input: pxa27x_keypad direct key may be low active
Input: pxa27x_keypad bug fix for direct_key_mask
Input: pxa27x_keypad keep clock on as wakeup source
ARM: dt: tegra: pinmux changes for USB ULPI
ARM: tegra: add USB ULPI PHY reset GPIO to device tree
ARM: tegra: don't hard-code USB ULPI PHY reset_gpio
ARM: tegra: change pll_p_out4's rate to 24MHz
ARM: tegra: fix pclk rate
ARM: tegra: reparent sclk to pll_c_out1
ARM: tegra: Add pllc clock init table
ARM: dt: tegra cardhu: basic audio support
ARM: dt: tegra30.dtsi: Add audio-related nodes
ARM: tegra: add AUXDATA required for audio
...
74 files changed, 2630 insertions, 1015 deletions
diff --git a/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-ahb.txt b/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-ahb.txt new file mode 100644 index 000000000000..234406d41c12 --- /dev/null +++ b/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-ahb.txt @@ -0,0 +1,11 @@ +NVIDIA Tegra AHB + +Required properties: +- compatible : "nvidia,tegra20-ahb" or "nvidia,tegra30-ahb" +- reg : Should contain 1 register ranges(address and length) + +Example: + ahb: ahb@6000c004 { + compatible = "nvidia,tegra20-ahb"; + reg = <0x6000c004 0x10c>; /* AHB Arbitration + Gizmo Controller */ + }; diff --git a/Documentation/devicetree/bindings/mmc/fsl-esdhc.txt b/Documentation/devicetree/bindings/mmc/fsl-esdhc.txt index 64bcb8be973c..0d93b4b0e0e3 100644 --- a/Documentation/devicetree/bindings/mmc/fsl-esdhc.txt +++ b/Documentation/devicetree/bindings/mmc/fsl-esdhc.txt @@ -11,9 +11,11 @@ Required properties: - interrupt-parent : interrupt source phandle. - clock-frequency : specifies eSDHC base clock frequency. - sdhci,wp-inverted : (optional) specifies that eSDHC controller - reports inverted write-protect state; + reports inverted write-protect state; New devices should use + the generic "wp-inverted" property. - sdhci,1-bit-only : (optional) specifies that a controller can - only handle 1-bit data transfers. + only handle 1-bit data transfers. New devices should use the + generic "bus-width = <1>" property. - sdhci,auto-cmd12: (optional) specifies that a controller can only handle auto CMD12. diff --git a/Documentation/devicetree/bindings/mmc/fsl-imx-esdhc.txt b/Documentation/devicetree/bindings/mmc/fsl-imx-esdhc.txt index ab22fe6e73ab..c7e404b3ef05 100644 --- a/Documentation/devicetree/bindings/mmc/fsl-imx-esdhc.txt +++ b/Documentation/devicetree/bindings/mmc/fsl-imx-esdhc.txt @@ -9,7 +9,7 @@ Required properties: - interrupts : Should contain eSDHC interrupt Optional properties: -- fsl,card-wired : Indicate the card is wired to host permanently +- non-removable : Indicate the card is wired to host permanently - fsl,cd-internal : Indicate to use controller internal card detection - fsl,wp-internal : Indicate to use controller internal write protection - cd-gpios : Specify GPIOs for card detection diff --git a/Documentation/devicetree/bindings/mmc/mmc-spi-slot.txt b/Documentation/devicetree/bindings/mmc/mmc-spi-slot.txt index 89a0084df2f7..d64aea5a4203 100644 --- a/Documentation/devicetree/bindings/mmc/mmc-spi-slot.txt +++ b/Documentation/devicetree/bindings/mmc/mmc-spi-slot.txt @@ -10,7 +10,8 @@ Required properties: Optional properties: - gpios : may specify GPIOs in this order: Card-Detect GPIO, - Write-Protect GPIO. + Write-Protect GPIO. Note that this does not follow the + binding from mmc.txt, for historic reasons. - interrupts : the interrupt of a card detect interrupt. - interrupt-parent : the phandle for the interrupt controller that services interrupts for this device. diff --git a/Documentation/devicetree/bindings/mmc/mmc.txt b/Documentation/devicetree/bindings/mmc/mmc.txt new file mode 100644 index 000000000000..6e70dcde0a71 --- /dev/null +++ b/Documentation/devicetree/bindings/mmc/mmc.txt @@ -0,0 +1,27 @@ +These properties are common to multiple MMC host controllers. Any host +that requires the respective functionality should implement them using +these definitions. + +Required properties: +- bus-width: Number of data lines, can be <1>, <4>, or <8> + +Optional properties: +- cd-gpios : Specify GPIOs for card detection, see gpio binding +- wp-gpios : Specify GPIOs for write protection, see gpio binding +- cd-inverted: when present, polarity on the wp gpio line is inverted +- wp-inverted: when present, polarity on the wp gpio line is inverted +- non-removable: non-removable slot (like eMMC) +- max-frequency: maximum operating clock frequency + +Example: + +sdhci@ab000000 { + compatible = "sdhci"; + reg = <0xab000000 0x200>; + interrupts = <23>; + bus-width = <4>; + cd-gpios = <&gpio 69 0>; + cd-inverted; + wp-gpios = <&gpio 70 0>; + max-frequency = <50000000>; +} diff --git a/Documentation/devicetree/bindings/mmc/nvidia-sdhci.txt b/Documentation/devicetree/bindings/mmc/nvidia-sdhci.txt index 7e51154679a6..f77c3031607f 100644 --- a/Documentation/devicetree/bindings/mmc/nvidia-sdhci.txt +++ b/Documentation/devicetree/bindings/mmc/nvidia-sdhci.txt @@ -7,12 +7,12 @@ Required properties: - compatible : Should be "nvidia,<chip>-sdhci" - reg : Should contain SD/MMC registers location and length - interrupts : Should contain SD/MMC interrupt +- bus-width : Number of data lines, can be <1>, <4>, or <8> Optional properties: - cd-gpios : Specify GPIOs for card detection - wp-gpios : Specify GPIOs for write protection - power-gpios : Specify GPIOs for power control -- support-8bit : Boolean, indicates if 8-bit mode should be used. Example: @@ -23,5 +23,5 @@ sdhci@c8000200 { cd-gpios = <&gpio 69 0>; /* gpio PI5 */ wp-gpios = <&gpio 57 0>; /* gpio PH1 */ power-gpios = <&gpio 155 0>; /* gpio PT3 */ - support-8bit; + bus-width = <8>; }; diff --git a/Documentation/devicetree/bindings/mmc/ti-omap-hsmmc.txt b/Documentation/devicetree/bindings/mmc/ti-omap-hsmmc.txt index dbd4368ab8cc..8a53958c9a9f 100644 --- a/Documentation/devicetree/bindings/mmc/ti-omap-hsmmc.txt +++ b/Documentation/devicetree/bindings/mmc/ti-omap-hsmmc.txt @@ -15,7 +15,7 @@ Optional properties: ti,dual-volt: boolean, supports dual voltage cards <supply-name>-supply: phandle to the regulator device tree node "supply-name" examples are "vmmc", "vmmc_aux" etc -ti,bus-width: Number of data lines, default assumed is 1 if the property is missing. +bus-width: Number of data lines, default assumed is 1 if the property is missing. cd-gpios: GPIOs for card detection wp-gpios: GPIOs for write protection ti,non-removable: non-removable slot (like eMMC) @@ -27,7 +27,7 @@ Example: reg = <0x4809c000 0x400>; ti,hwmods = "mmc1"; ti,dual-volt; - ti,bus-width = <4>; + bus-width = <4>; vmmc-supply = <&vmmc>; /* phandle to regulator node */ ti,non-removable; }; diff --git a/Documentation/devicetree/bindings/usb/tegra-usb.txt b/Documentation/devicetree/bindings/usb/tegra-usb.txt index 007005ddbe12..e9b005dc7625 100644 --- a/Documentation/devicetree/bindings/usb/tegra-usb.txt +++ b/Documentation/devicetree/bindings/usb/tegra-usb.txt @@ -12,6 +12,9 @@ Required properties : - nvidia,vbus-gpio : If present, specifies a gpio that needs to be activated for the bus to be powered. +Required properties for phy_type == ulpi: + - nvidia,phy-reset-gpio : The GPIO used to reset the PHY. + Optional properties: - dr_mode : dual role mode. Indicates the working mode for nvidia,tegra20-ehci compatible controllers. Can be "host", "peripheral", diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug index 85348a09d655..e561adc1db0c 100644 --- a/arch/arm/Kconfig.debug +++ b/arch/arm/Kconfig.debug @@ -103,6 +103,35 @@ choice Say Y here if you want the debug print routines to direct their output to the second serial port on these devices. + config DEBUG_DAVINCI_DA8XX_UART1 + bool "Kernel low-level debugging on DaVinci DA8XX using UART1" + depends on ARCH_DAVINCI_DA8XX + help + Say Y here if you want the debug print routines to direct + their output to UART1 serial port on DaVinci DA8XX devices. + + config DEBUG_DAVINCI_DA8XX_UART2 + bool "Kernel low-level debugging on DaVinci DA8XX using UART2" + depends on ARCH_DAVINCI_DA8XX + help + Say Y here if you want the debug print routines to direct + their output to UART2 serial port on DaVinci DA8XX devices. + + config DEBUG_DAVINCI_DMx_UART0 + bool "Kernel low-level debugging on DaVinci DMx using UART0" + depends on ARCH_DAVINCI_DMx + help + Say Y here if you want the debug print routines to direct + their output to UART0 serial port on DaVinci DMx devices. + + config DEBUG_DAVINCI_TNETV107X_UART1 + bool "Kernel low-level debugging on DaVinci TNETV107x using UART1" + depends on ARCH_DAVINCI_TNETV107X + help + Say Y here if you want the debug print routines to direct + their output to UART1 serial port on DaVinci TNETV107X + devices. + config DEBUG_DC21285_PORT bool "Kernel low-level debugging messages via footbridge serial port" depends on FOOTBRIDGE diff --git a/arch/arm/boot/dts/imx53-smd.dts b/arch/arm/boot/dts/imx53-smd.dts index c7ee86c2dfb5..139138a556b0 100644 --- a/arch/arm/boot/dts/imx53-smd.dts +++ b/arch/arm/boot/dts/imx53-smd.dts @@ -35,7 +35,7 @@ }; esdhc@50008000 { /* ESDHC2 */ - fsl,card-wired; + non-removable; status = "okay"; }; @@ -76,7 +76,7 @@ }; esdhc@50020000 { /* ESDHC3 */ - fsl,card-wired; + non-removable; status = "okay"; }; }; diff --git a/arch/arm/boot/dts/imx6q-arm2.dts b/arch/arm/boot/dts/imx6q-arm2.dts index ce1c8238c897..d2eaf521c9fd 100644 --- a/arch/arm/boot/dts/imx6q-arm2.dts +++ b/arch/arm/boot/dts/imx6q-arm2.dts @@ -41,7 +41,7 @@ }; usdhc@0219c000 { /* uSDHC4 */ - fsl,card-wired; + non-removable; vmmc-supply = <®_3p3v>; status = "okay"; }; diff --git a/arch/arm/boot/dts/omap3-beagle.dts b/arch/arm/boot/dts/omap3-beagle.dts index 8c756be4d7ad..5b4506c0a8c4 100644 --- a/arch/arm/boot/dts/omap3-beagle.dts +++ b/arch/arm/boot/dts/omap3-beagle.dts @@ -57,7 +57,7 @@ &mmc1 { vmmc-supply = <&vmmc1>; vmmc_aux-supply = <&vsim>; - ti,bus-width = <8>; + bus-width = <8>; }; &mmc2 { diff --git a/arch/arm/boot/dts/omap4-panda.dts b/arch/arm/boot/dts/omap4-panda.dts index e671361bc791..1efe0c587985 100644 --- a/arch/arm/boot/dts/omap4-panda.dts +++ b/arch/arm/boot/dts/omap4-panda.dts @@ -70,7 +70,7 @@ &mmc1 { vmmc-supply = <&vmmc>; - ti,bus-width = <8>; + bus-width = <8>; }; &mmc2 { @@ -87,5 +87,5 @@ &mmc5 { ti,non-removable; - ti,bus-width = <4>; + bus-width = <4>; }; diff --git a/arch/arm/boot/dts/omap4-sdp.dts b/arch/arm/boot/dts/omap4-sdp.dts index e5eeb6f9c6e6..d08c4d137280 100644 --- a/arch/arm/boot/dts/omap4-sdp.dts +++ b/arch/arm/boot/dts/omap4-sdp.dts @@ -137,12 +137,12 @@ &mmc1 { vmmc-supply = <&vmmc>; - ti,bus-width = <8>; + bus-width = <8>; }; &mmc2 { vmmc-supply = <&vaux1>; - ti,bus-width = <8>; + bus-width = <8>; ti,non-removable; }; @@ -155,6 +155,6 @@ }; &mmc5 { - ti,bus-width = <4>; + bus-width = <4>; ti,non-removable; }; diff --git a/arch/arm/boot/dts/tegra-cardhu.dts b/arch/arm/boot/dts/tegra-cardhu.dts index 0a9f34a2c3aa..4a166357172b 100644 --- a/arch/arm/boot/dts/tegra-cardhu.dts +++ b/arch/arm/boot/dts/tegra-cardhu.dts @@ -51,6 +51,15 @@ nvidia,pull = <2>; nvidia,tristate = <0>; }; + dap2_fs_pa2 { + nvidia,pins = "dap2_fs_pa2", + "dap2_sclk_pa3", + "dap2_din_pa4", + "dap2_dout_pa5"; + nvidia,function = "i2s1"; + nvidia,pull = <0>; + nvidia,tristate = <0>; + }; }; }; @@ -92,12 +101,27 @@ i2c@7000d000 { clock-frequency = <100000>; + + wm8903: wm8903@1a { + compatible = "wlf,wm8903"; + reg = <0x1a>; + interrupt-parent = <&gpio>; + interrupts = <179 0x04>; /* gpio PW3 */ + + gpio-controller; + #gpio-cells = <2>; + + micdet-cfg = <0>; + micdet-delay = <100>; + gpio-cfg = <0xffffffff 0xffffffff 0 0xffffffff 0xffffffff>; + }; }; sdhci@78000000 { cd-gpios = <&gpio 69 0>; /* gpio PI5 */ wp-gpios = <&gpio 155 0>; /* gpio PT3 */ power-gpios = <&gpio 31 0>; /* gpio PD7 */ + bus-width = <4>; }; sdhci@78000200 { @@ -110,5 +134,46 @@ sdhci@78000400 { support-8bit; + bus-width = <8>; + }; + + ahub@70080000 { + i2s@70080300 { + status = "disable"; + }; + + i2s@70080500 { + status = "disable"; + }; + + i2s@70080600 { + status = "disable"; + }; + + i2s@70080700 { + status = "disable"; + }; + }; + + sound { + compatible = "nvidia,tegra-audio-wm8903-cardhu", + "nvidia,tegra-audio-wm8903"; + nvidia,model = "NVIDIA Tegra Cardhu"; + + nvidia,audio-routing = + "Headphone Jack", "HPOUTR", + "Headphone Jack", "HPOUTL", + "Int Spk", "ROP", + "Int Spk", "RON", + "Int Spk", "LOP", + "Int Spk", "LON", + "Mic Jack", "MICBIAS", + "IN1L", "Mic Jack"; + + nvidia,i2s-controller = <&tegra_i2s1>; + nvidia,audio-codec = <&wm8903>; + + nvidia,spkr-en-gpios = <&wm8903 2 0>; + nvidia,hp-det-gpios = <&gpio 178 0>; /* gpio PW2 */ }; }; diff --git a/arch/arm/boot/dts/tegra-harmony.dts b/arch/arm/boot/dts/tegra-harmony.dts index 1a0b1f182944..7cd513ac5ea6 100644 --- a/arch/arm/boot/dts/tegra-harmony.dts +++ b/arch/arm/boot/dts/tegra-harmony.dts @@ -167,28 +167,28 @@ }; conf_ata { nvidia,pins = "ata", "atb", "atc", "atd", "ate", - "cdev1", "dap1", "dtb", "gma", "gmb", - "gmc", "gmd", "gme", "gpu7", "gpv", - "i2cp", "pta", "rm", "slxa", "slxk", - "spia", "spib"; + "cdev1", "cdev2", "dap1", "dtb", "gma", + "gmb", "gmc", "gmd", "gme", "gpu7", + "gpv", "i2cp", "pta", "rm", "slxa", + "slxk", "spia", "spib", "uac"; nvidia,pull = <0>; nvidia,tristate = <0>; }; - conf_cdev2 { - nvidia,pins = "cdev2", "csus", "spid", "spif"; - nvidia,pull = <1>; - nvidia,tristate = <1>; - }; conf_ck32 { nvidia,pins = "ck32", "ddrc", "pmca", "pmcb", "pmcc", "pmcd", "pmce", "xm2c", "xm2d"; nvidia,pull = <0>; }; + conf_csus { + nvidia,pins = "csus", "spid", "spif"; + nvidia,pull = <1>; + nvidia,tristate = <1>; + }; conf_crtp { nvidia,pins = "crtp", "dap2", "dap3", "dap4", "dtc", "dte", "dtf", "gpu", "sdio1", "slxc", "slxd", "spdi", "spdo", "spig", - "uac", "uda"; + "uda"; nvidia,pull = <0>; nvidia,tristate = <1>; }; @@ -324,6 +324,7 @@ cd-gpios = <&gpio 69 0>; /* gpio PI5 */ wp-gpios = <&gpio 57 0>; /* gpio PH1 */ power-gpios = <&gpio 155 0>; /* gpio PT3 */ + bus-width = <4>; }; sdhci@c8000400 { @@ -335,5 +336,10 @@ wp-gpios = <&gpio 59 0>; /* gpio PH3 */ power-gpios = <&gpio 70 0>; /* gpio PI6 */ support-8bit; + bus-width = <8>; + }; + + usb@c5004000 { + nvidia,phy-reset-gpio = <&gpio 169 0>; /* gpio PV1 */ }; }; diff --git a/arch/arm/boot/dts/tegra-paz00.dts b/arch/arm/boot/dts/tegra-paz00.dts index 10943fb2561c..8d625e4c5de5 100644 --- a/arch/arm/boot/dts/tegra-paz00.dts +++ b/arch/arm/boot/dts/tegra-paz00.dts @@ -159,18 +159,14 @@ }; conf_ata { nvidia,pins = "ata", "atb", "atc", "atd", "ate", - "cdev1", "dap1", "dap2", "dtf", "gma", - "gmb", "gmc", "gmd", "gme", "gpu", - "gpu7", "gpv", "i2cp", "pta", "rm", - "sdio1", "slxk", "spdo", "uac", "uda"; + "cdev1", "cdev2", "dap1", "dap2", "dtf", + "gma", "gmb", "gmc", "gmd", "gme", + "gpu", "gpu7", "gpv", "i2cp", "pta", + "rm", "sdio1", "slxk", "spdo", "uac", + "uda"; nvidia,pull = <0>; nvidia,tristate = <0>; }; - conf_cdev2 { - nvidia,pins = "cdev2"; - nvidia,pull = <1>; - nvidia,tristate = <0>; - }; conf_ck32 { nvidia,pins = "ck32", "ddrc", "pmca", "pmcb", "pmcc", "pmcd", "pmce", "xm2c", "xm2d"; @@ -317,6 +313,7 @@ cd-gpios = <&gpio 173 0>; /* gpio PV5 */ wp-gpios = <&gpio 57 0>; /* gpio PH1 */ power-gpios = <&gpio 169 0>; /* gpio PV1 */ + bus-width = <4>; }; sdhci@c8000200 { @@ -329,6 +326,7 @@ sdhci@c8000600 { support-8bit; + bus-width = <8>; }; gpio-keys { @@ -351,4 +349,8 @@ linux,default-trigger = "rfkill0"; }; }; + + usb@c5004000 { + nvidia,phy-reset-gpio = <&gpio 168 0>; /* gpio PV0 */ + }; }; diff --git a/arch/arm/boot/dts/tegra-seaboard.dts b/arch/arm/boot/dts/tegra-seaboard.dts index ec33116f5df9..315971993cfd 100644 --- a/arch/arm/boot/dts/tegra-seaboard.dts +++ b/arch/arm/boot/dts/tegra-seaboard.dts @@ -347,10 +347,12 @@ cd-gpios = <&gpio 69 0>; /* gpio PI5 */ wp-gpios = <&gpio 57 0>; /* gpio PH1 */ power-gpios = <&gpio 70 0>; /* gpio PI6 */ + bus-width = <4>; }; sdhci@c8000600 { support-8bit; + bus-width = <8>; }; usb@c5000000 { @@ -415,4 +417,8 @@ 0x00000000 0x00000000 0x00000000 0x00000000 >; }; }; + + usb@c5004000 { + nvidia,phy-reset-gpio = <&gpio 169 0>; /* gpio PV1 */ + }; }; diff --git a/arch/arm/boot/dts/tegra-trimslice.dts b/arch/arm/boot/dts/tegra-trimslice.dts index 98efd5b0d7f9..e4fcf9a8178a 100644 --- a/arch/arm/boot/dts/tegra-trimslice.dts +++ b/arch/arm/boot/dts/tegra-trimslice.dts @@ -182,23 +182,23 @@ nvidia,tristate = <1>; }; conf_atb { - nvidia,pins = "atb", "cdev1", "dap1", "gma", - "gmc", "gmd", "gpu", "gpu7", "gpv", - "sdio1", "slxa", "slxk", "uac"; + nvidia,pins = "atb", "cdev1", "cdev2", "dap1", + "gma", "gmc", "gmd", "gpu", "gpu7", + "gpv", "sdio1", "slxa", "slxk", "uac"; nvidia,pull = <0>; nvidia,tristate = <0>; }; - conf_cdev2 { - nvidia,pins = "cdev2", "csus", "spia", "spib", - "spid", "spif"; - nvidia,pull = <1>; - nvidia,tristate = <1>; - }; conf_ck32 { nvidia,pins = "ck32", "ddrc", "pmca", "pmcb", "pmcc", "pmcd", "pmce", "xm2c", "xm2d"; nvidia,pull = <0>; }; + conf_csus { + nvidia,pins = "csus", "spia", "spib", + "spid", "spif"; + nvidia,pull = <1>; + nvidia,tristate = <1>; + }; conf_ddc { nvidia,pins = "ddc", "dtf", "rm", "sdc", "sdd"; nvidia,pull = <2>; @@ -304,4 +304,8 @@ cd-gpios = <&gpio 121 0>; wp-gpios = <&gpio 122 0>; }; + + usb@c5004000 { + nvidia,phy-reset-gpio = <&gpio 168 0>; /* gpio PV0 */ + }; }; diff --git a/arch/arm/boot/dts/tegra-ventana.dts b/arch/arm/boot/dts/tegra-ventana.dts index 71eb2e50a668..b922a26747e7 100644 --- a/arch/arm/boot/dts/tegra-ventana.dts +++ b/arch/arm/boot/dts/tegra-ventana.dts @@ -330,9 +330,15 @@ cd-gpios = <&gpio 69 0>; /* gpio PI5 */ wp-gpios = <&gpio 57 0>; /* gpio PH1 */ power-gpios = <&gpio 70 0>; /* gpio PI6 */ + bus-width = <4>; }; sdhci@c8000600 { support-8bit; + bus-width = <8>; + }; + + usb@c5004000 { + nvidia,phy-reset-gpio = <&gpio 169 0>; /* gpio PV1 */ }; }; diff --git a/arch/arm/boot/dts/tegra30.dtsi b/arch/arm/boot/dts/tegra30.dtsi index 62a7b39f1c9a..15200a949a81 100644 --- a/arch/arm/boot/dts/tegra30.dtsi +++ b/arch/arm/boot/dts/tegra30.dtsi @@ -183,4 +183,45 @@ reg = < 0x70000868 0xd0 /* Pad control registers */ 0x70003000 0x3e0 >; /* Mux registers */ }; + + ahub { + compatible = "nvidia,tegra30-ahub"; + reg = <0x70080000 0x200 0x70080200 0x100>; + interrupts = < 0 103 0x04 >; + nvidia,dma-request-selector = <&apbdma 1>; + + ranges; + #address-cells = <1>; + #size-cells = <1>; + + tegra_i2s0: i2s@70080300 { + compatible = "nvidia,tegra30-i2s"; + reg = <0x70080300 0x100>; + nvidia,ahub-cif-ids = <4 4>; + }; + + tegra_i2s1: i2s@70080400 { + compatible = "nvidia,tegra30-i2s"; + reg = <0x70080400 0x100>; + nvidia,ahub-cif-ids = <5 5>; + }; + + tegra_i2s2: i2s@70080500 { + compatible = "nvidia,tegra30-i2s"; + reg = <0x70080500 0x100>; + nvidia,ahub-cif-ids = <6 6>; + }; + + tegra_i2s3: i2s@70080600 { + compatible = "nvidia,tegra30-i2s"; + reg = <0x70080600 0x100>; + nvidia,ahub-cif-ids = <7 7>; + }; + + tegra_i2s4: i2s@70080700 { + compatible = "nvidia,tegra30-i2s"; + reg = <0x70080700 0x100>; + nvidia,ahub-cif-ids = <8 8>; + }; + }; }; diff --git a/arch/arm/mach-davinci/dma.c b/arch/arm/mach-davinci/dma.c index 95ce019c9b98..a685e9706b7b 100644 --- a/arch/arm/mach-davinci/dma.c +++ b/arch/arm/mach-davinci/dma.c @@ -353,9 +353,10 @@ static int irq2ctlr(int irq) *****************************************************************************/ static irqreturn_t dma_irq_handler(int irq, void *data) { - int i; int ctlr; - unsigned int cnt = 0; + u32 sh_ier; + u32 sh_ipr; + u32 bank; ctlr = irq2ctlr(irq); if (ctlr < 0) @@ -363,41 +364,39 @@ static irqreturn_t dma_irq_handler(int irq, void *data) dev_dbg(data, "dma_irq_handler\n"); - if ((edma_shadow0_read_array(ctlr, SH_IPR, 0) == 0) && - (edma_shadow0_read_array(ctlr, SH_IPR, 1) == 0)) - return IRQ_NONE; + sh_ipr = edma_shadow0_read_array(ctlr, SH_IPR, 0); + if (!sh_ipr) { + sh_ipr = edma_shadow0_read_array(ctlr, SH_IPR, 1); + if (!sh_ipr) + return IRQ_NONE; + sh_ier = edma_shadow0_read_array(ctlr, SH_IER, 1); + bank = 1; + } else { + sh_ier = edma_shadow0_read_array(ctlr, SH_IER, 0); + bank = 0; + } - while (1) { - int j; - if (edma_shadow0_read_array(ctlr, SH_IPR, 0) & - edma_shadow0_read_array(ctlr, SH_IER, 0)) - j = 0; - else if (edma_shadow0_read_array(ctlr, SH_IPR, 1) & - edma_shadow0_read_array(ctlr, SH_IER, 1)) - j = 1; - else - break; - dev_dbg(data, "IPR%d %08x\n", j, - edma_shadow0_read_array(ctlr, SH_IPR, j)); - for (i = 0; i < 32; i++) { - int k = (j << 5) + i; - if ((edma_shadow0_read_array(ctlr, SH_IPR, j) & BIT(i)) - && (edma_shadow0_read_array(ctlr, - SH_IER, j) & BIT(i))) { - /* Clear the corresponding IPR bits */ - edma_shadow0_write_array(ctlr, SH_ICR, j, - BIT(i)); - if (edma_cc[ctlr]->intr_data[k].callback) - edma_cc[ctlr]->intr_data[k].callback( - k, DMA_COMPLETE, - edma_cc[ctlr]->intr_data[k]. - data); - } + do { + u32 slot; + u32 channel; + + dev_dbg(data, "IPR%d %08x\n", bank, sh_ipr); + + slot = __ffs(sh_ipr); + sh_ipr &= ~(BIT(slot)); + + if (sh_ier & BIT(slot)) { + channel = (bank << 5) | slot; + /* Clear the corresponding IPR bits */ + edma_shadow0_write_array(ctlr, SH_ICR, bank, + BIT(slot)); + if (edma_cc[ctlr]->intr_data[channel].callback) + edma_cc[ctlr]->intr_data[channel].callback( + channel, DMA_COMPLETE, + edma_cc[ctlr]->intr_data[channel].data); } - cnt++; - if (cnt > 10) - break; - } + } while (sh_ipr); + edma_shadow0_write(ctlr, SH_IEVAL, 1); return IRQ_HANDLED; } diff --git a/arch/arm/mach-davinci/include/mach/debug-macro.S b/arch/arm/mach-davinci/include/mach/debug-macro.S index cf94552d5274..34290d14754b 100644 --- a/arch/arm/mach-davinci/include/mach/debug-macro.S +++ b/arch/arm/mach-davinci/include/mach/debug-macro.S @@ -22,46 +22,28 @@ #define UART_SHIFT 2 - .pushsection .data -davinci_uart_phys: .word 0 -davinci_uart_virt: .word 0 - .popsection - - .macro addruart, rp, rv, tmp - - /* Use davinci_uart_phys/virt if already configured */ -10: adr \rp, 99f @ get effective addr of 99f - ldr \rv, [\rp] @ get absolute addr of 99f - sub \rv, \rv, \rp @ offset between the two - ldr \rp, [\rp, #4] @ abs addr of omap_uart_phys - sub \tmp, \rp, \rv @ make it effective - ldr \rp, [\tmp, #0] @ davinci_uart_phys - ldr \rv, [\tmp, #4] @ davinci_uart_virt - cmp \rp, #0 @ is port configured? - cmpne \rv, #0 - bne 100f @ already configured - - /* Check the debug UART address set in uncompress.h */ - and \rp, pc, #0xff000000 - ldr \rv, =DAVINCI_UART_INFO_OFS - add \rp, \rp, \rv - - /* Copy uart phys address from decompressor uart info */ - ldr \rv, [\rp, #0] - str \rv, [\tmp, #0] - - /* Copy uart virt address from decompressor uart info */ - ldr \rv, [\rp, #4] - str \rv, [\tmp, #4] - - b 10b +#if defined(CONFIG_DEBUG_DAVINCI_DMx_UART0) +#define UART_BASE DAVINCI_UART0_BASE +#elif defined(CONFIG_DEBUG_DAVINCI_DA8XX_UART0) +#define UART_BASE DA8XX_UART0_BASE +#elif defined(CONFIG_DEBUG_DAVINCI_DA8XX_UART1) +#define UART_BASE DA8XX_UART1_BASE +#elif defined(CONFIG_DEBUG_DAVINCI_DA8XX_UART2) +#define UART_BASE DA8XX_UART2_BASE +#elif defined(CONFIG_DEBUG_DAVINCI_TNETV107X_UART1) +#define UART_BASE TNETV107X_UART2_BASE +#define UART_VIRTBASE TNETV107X_UART2_VIRT +#else +#error "Select a specifc port for DEBUG_LL" +#endif - .align -99: .word . - .word davinci_uart_phys - .ltorg +#ifndef UART_VIRTBASE +#define UART_VIRTBASE IO_ADDRESS(UART_BASE) +#endif -100: + .macro addruart, rp, rv, tmp + ldr \rp, =UART_BASE + ldr \rv, =UART_VIRTBASE .endm .macro senduart,rd,rx diff --git a/arch/arm/mach-davinci/include/mach/hardware.h b/arch/arm/mach-davinci/include/mach/hardware.h index 2184691ebc2f..16bb42291d39 100644 --- a/arch/arm/mach-davinci/include/mach/hardware.h +++ b/arch/arm/mach-davinci/include/mach/hardware.h @@ -22,7 +22,7 @@ /* * I/O mapping */ -#define IO_PHYS 0x01c00000UL +#define IO_PHYS UL(0x01c00000) #define IO_OFFSET 0xfd000000 /* Virtual IO = 0xfec00000 */ #define IO_SIZE 0x00400000 #define IO_VIRT (IO_PHYS + IO_OFFSET) diff --git a/arch/arm/mach-davinci/include/mach/serial.h b/arch/arm/mach-davinci/include/mach/serial.h index e347d88fef91..46b3cd11c3c2 100644 --- a/arch/arm/mach-davinci/include/mach/serial.h +++ b/arch/arm/mach-davinci/include/mach/serial.h @@ -15,16 +15,6 @@ #include <mach/hardware.h> -/* - * Stolen area that contains debug uart physical and virtual addresses. These - * addresses are filled in by the uncompress.h code, and are used by the debug - * macros in debug-macro.S. - * - * This area sits just below the page tables (see arch/arm/kernel/head.S). - * We define it as a relative offset from start of usable RAM. - */ -#define DAVINCI_UART_INFO_OFS 0x3ff8 - #define DAVINCI_UART0_BASE (IO_PHYS + 0x20000) #define DAVINCI_UART1_BASE (IO_PHYS + 0x20400) #define DAVINCI_UART2_BASE (IO_PHYS + 0x20800) diff --git a/arch/arm/mach-davinci/include/mach/uncompress.h b/arch/arm/mach-davinci/include/mach/uncompress.h index da2fb2c2155a..18cfd4977155 100644 --- a/arch/arm/mach-davinci/include/mach/uncompress.h +++ b/arch/arm/mach-davinci/include/mach/uncompress.h @@ -43,37 +43,27 @@ static inline void flush(void) barrier(); } -static inline void set_uart_info(u32 phys, void * __iomem virt) +static inline void set_uart_info(u32 phys) { - /* - * Get address of some.bss variable and round it down - * a la CONFIG_AUTO_ZRELADDR. - */ - u32 ram_start = (u32)&uart & 0xf8000000; - u32 *uart_info = (u32 *)(ram_start + DAVINCI_UART_INFO_OFS); - uart = (u32 *)phys; - uart_info[0] = phys; - uart_info[1] = (u32)virt; } -#define _DEBUG_LL_ENTRY(machine, phys, virt) \ - if (machine_is_##machine()) { \ - set_uart_info(phys, virt); \ - break; \ +#define _DEBUG_LL_ENTRY(machine, phys) \ + { \ + if (machine_is_##machine()) { \ + set_uart_info(phys); \ + break; \ + } \ } #define DEBUG_LL_DAVINCI(machine, port) \ - _DEBUG_LL_ENTRY(machine, DAVINCI_UART##port##_BASE, \ - IO_ADDRESS(DAVINCI_UART##port##_BASE)) + _DEBUG_LL_ENTRY(machine, DAVINCI_UART##port##_BASE) #define DEBUG_LL_DA8XX(machine, port) \ - _DEBUG_LL_ENTRY(machine, DA8XX_UART##port##_BASE, \ - IO_ADDRESS(DA8XX_UART##port##_BASE)) + _DEBUG_LL_ENTRY(machine, DA8XX_UART##port##_BASE) #define DEBUG_LL_TNETV107X(machine, port) \ - _DEBUG_LL_ENTRY(machine, TNETV107X_UART##port##_BASE, \ - TNETV107X_UART##port##_VIRT) + _DEBUG_LL_ENTRY(machine, TNETV107X_UART##port##_BASE) static inline void __arch_decomp_setup(unsigned long arch_id) { diff --git a/arch/arm/mach-ep93xx/core.c b/arch/arm/mach-ep93xx/core.c index 66b1494f23a6..ad1a91ab6acd 100644 --- a/arch/arm/mach-ep93xx/core.c +++ b/arch/arm/mach-ep93xx/core.c @@ -675,7 +675,7 @@ int ep93xx_keypad_acquire_gpio(struct platform_device *pdev) fail_gpio_d: gpio_free(EP93XX_GPIO_LINE_C(i)); fail_gpio_c: - for ( ; i >= 0; --i) { + for (--i; i >= 0; --i) { gpio_free(EP93XX_GPIO_LINE_C(i)); gpio_free(EP93XX_GPIO_LINE_D(i)); } diff --git a/arch/arm/mach-exynos/Kconfig b/arch/arm/mach-exynos/Kconfig index 15b05b89cc39..e3cfd5fd7dd5 100644 --- a/arch/arm/mach-exynos/Kconfig +++ b/arch/arm/mach-exynos/Kconfig @@ -85,10 +85,10 @@ config EXYNOS4_SETUP_FIMD0 help Common setup code for FIMD0. -config EXYNOS4_DEV_SYSMMU +config EXYNOS_DEV_SYSMMU bool help - Common setup code for SYSTEM MMU in EXYNOS4 + Common setup code for SYSTEM MMU in EXYNOS platforms config EXYNOS4_DEV_DWMCI bool @@ -201,12 +201,12 @@ config MACH_SMDKV310 select S3C_DEV_HSMMC3 select SAMSUNG_DEV_BACKLIGHT select EXYNOS_DEV_DRM + select EXYNOS_DEV_SYSMMU select EXYNOS4_DEV_AHCI select SAMSUNG_DEV_KEYPAD select EXYNOS4_DEV_DMA select SAMSUNG_DEV_PWM select EXYNOS4_DEV_USB_OHCI - select EXYNOS4_DEV_SYSMMU select EXYNOS4_SETUP_FIMD0 select EXYNOS4_SETUP_I2C1 select EXYNOS4_SETUP_KEYPAD @@ -225,7 +225,6 @@ config MACH_ARMLEX4210 select S3C_DEV_HSMMC3 select EXYNOS4_DEV_AHCI select EXYNOS4_DEV_DMA - select EXYNOS4_DEV_SYSMMU select EXYNOS4_SETUP_SDHCI help Machine support for Samsung ARMLEX4210 based on EXYNOS4210 @@ -256,6 +255,7 @@ config MACH_UNIVERSAL_C210 select S5P_DEV_MFC select S5P_DEV_ONENAND select S5P_DEV_TV + select EXYNOS_DEV_SYSMMU select EXYNOS4_DEV_DMA select EXYNOS_DEV_DRM select EXYNOS4_SETUP_FIMD0 @@ -332,6 +332,7 @@ config MACH_ORIGEN select SAMSUNG_DEV_BACKLIGHT select SAMSUNG_DEV_PWM select EXYNOS_DEV_DRM + select EXYNOS_DEV_SYSMMU select EXYNOS4_DEV_DMA select EXYNOS4_DEV_USB_OHCI select EXYNOS4_SETUP_FIMD0 @@ -360,6 +361,7 @@ config MACH_SMDK4212 select SAMSUNG_DEV_BACKLIGHT select SAMSUNG_DEV_KEYPAD select SAMSUNG_DEV_PWM + select EXYNOS_DEV_SYSMMU select EXYNOS4_DEV_DMA select EXYNOS4_SETUP_I2C1 select EXYNOS4_SETUP_I2C3 diff --git a/arch/arm/mach-exynos/Makefile b/arch/arm/mach-exynos/Makefile index 8631840d1b5e..272625231c73 100644 --- a/arch/arm/mach-exynos/Makefile +++ b/arch/arm/mach-exynos/Makefile @@ -50,7 +50,7 @@ obj-$(CONFIG_MACH_EXYNOS5_DT) += mach-exynos5-dt.o obj-y += dev-uart.o 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_EXYNOS_DEV_SYSMMU) += dev-sysmmu.o obj-$(CONFIG_EXYNOS4_DEV_DWMCI) += dev-dwmci.o obj-$(CONFIG_EXYNOS4_DEV_DMA) += dma.o obj-$(CONFIG_EXYNOS4_DEV_USB_OHCI) += dev-ohci.o diff --git a/arch/arm/mach-exynos/clock-exynos4.c b/arch/arm/mach-exynos/clock-exynos4.c index 6efd1e5919fd..bcb7db453145 100644 --- a/arch/arm/mach-exynos/clock-exynos4.c +++ b/arch/arm/mach-exynos/clock-exynos4.c @@ -168,7 +168,7 @@ static int exynos4_clk_ip_tv_ctrl(struct clk *clk, int enable) return s5p_gatectrl(EXYNOS4_CLKGATE_IP_TV, clk, enable); } -static int exynos4_clk_ip_image_ctrl(struct clk *clk, int enable) +int exynos4_clk_ip_image_ctrl(struct clk *clk, int enable) { return s5p_gatectrl(EXYNOS4_CLKGATE_IP_IMAGE, clk, enable); } @@ -198,6 +198,11 @@ static int exynos4_clk_ip_perir_ctrl(struct clk *clk, int enable) return s5p_gatectrl(EXYNOS4_CLKGATE_IP_PERIR, clk, enable); } +int exynos4_clk_ip_dmc_ctrl(struct clk *clk, int enable) +{ + return s5p_gatectrl(EXYNOS4_CLKGATE_IP_DMC, clk, enable); +} + static int exynos4_clk_hdmiphy_ctrl(struct clk *clk, int enable) { return s5p_gatectrl(S5P_HDMI_PHY_CONTROL, clk, enable); @@ -678,61 +683,55 @@ static struct clk exynos4_init_clocks_off[] = { .enable = exynos4_clk_ip_peril_ctrl, .ctrlbit = (1 << 14), }, { - .name = "SYSMMU_MDMA", + .name = SYSMMU_CLOCK_NAME, + .devname = SYSMMU_CLOCK_DEVNAME(mfc_l, 0), + .enable = exynos4_clk_ip_mfc_ctrl, + .ctrlbit = (1 << 1), + }, { + .name = SYSMMU_CLOCK_NAME, + .devname = SYSMMU_CLOCK_DEVNAME(mfc_r, 1), + .enable = exynos4_clk_ip_mfc_ctrl, + .ctrlbit = (1 << 2), + }, { + .name = SYSMMU_CLOCK_NAME, + .devname = SYSMMU_CLOCK_DEVNAME(tv, 2), + .enable = exynos4_clk_ip_tv_ctrl, + .ctrlbit = (1 << 4), + }, { + .name = SYSMMU_CLOCK_NAME, + .devname = SYSMMU_CLOCK_DEVNAME(jpeg, 3), + .enable = exynos4_clk_ip_cam_ctrl, + .ctrlbit = (1 << 11), + }, { + .name = SYSMMU_CLOCK_NAME, + .devname = SYSMMU_CLOCK_DEVNAME(rot, 4), .enable = exynos4_clk_ip_image_ctrl, - .ctrlbit = (1 << 5), + .ctrlbit = (1 << 4), }, { - .name = "SYSMMU_FIMC0", + .name = SYSMMU_CLOCK_NAME, + .devname = SYSMMU_CLOCK_DEVNAME(fimc0, 5), .enable = exynos4_clk_ip_cam_ctrl, .ctrlbit = (1 << 7), }, { - .name = "SYSMMU_FIMC1", + .name = SYSMMU_CLOCK_NAME, + .devname = SYSMMU_CLOCK_DEVNAME(fimc1, 6), .enable = exynos4_clk_ip_cam_ctrl, .ctrlbit = (1 << 8), }, { - .name = "SYSMMU_FIMC2", + .name = SYSMMU_CLOCK_NAME, + .devname = SYSMMU_CLOCK_DEVNAME(fimc2, 7), .enable = exynos4_clk_ip_cam_ctrl, .ctrlbit = (1 << 9), }, { - .name = "SYSMMU_FIMC3", + .name = SYSMMU_CLOCK_NAME, + .devname = SYSMMU_CLOCK_DEVNAME(fimc3, 8), .enable = exynos4_clk_ip_cam_ctrl, .ctrlbit = (1 << 10), }, { - .name = "SYSMMU_JPEG", - .enable = exynos4_clk_ip_cam_ctrl, - .ctrlbit = (1 << 11), - }, { - .name = "SYSMMU_FIMD0", + .name = SYSMMU_CLOCK_NAME, + .devname = SYSMMU_CLOCK_DEVNAME(fimd0, 10), .enable = exynos4_clk_ip_lcd0_ctrl, .ctrlbit = (1 << 4), - }, { - .name = "SYSMMU_FIMD1", - .enable = exynos4_clk_ip_lcd1_ctrl, - .ctrlbit = (1 << 4), - }, { - .name = "SYSMMU_PCIe", - .enable = exynos4_clk_ip_fsys_ctrl, - .ctrlbit = (1 << 18), - }, { - .name = "SYSMMU_G2D", - .enable = exynos4_clk_ip_image_ctrl, - .ctrlbit = (1 << 3), - }, { - .name = "SYSMMU_ROTATOR", - .enable = exynos4_clk_ip_image_ctrl, - .ctrlbit = (1 << 4), - }, { - .name = "SYSMMU_TV", - .enable = exynos4_clk_ip_tv_ctrl, - .ctrlbit = (1 << 4), - }, { - .name = "SYSMMU_MFC_L", - .enable = exynos4_clk_ip_mfc_ctrl, - .ctrlbit = (1 << 1), - }, { - .name = "SYSMMU_MFC_R", - .enable = exynos4_clk_ip_mfc_ctrl, - .ctrlbit = (1 << 2), } }; diff --git a/arch/arm/mach-exynos/clock-exynos4.h b/arch/arm/mach-exynos/clock-exynos4.h index cb71c29c14d1..28a119701182 100644 --- a/arch/arm/mach-exynos/clock-exynos4.h +++ b/arch/arm/mach-exynos/clock-exynos4.h @@ -26,5 +26,7 @@ extern struct clk *exynos4_clkset_group_list[]; extern int exynos4_clksrc_mask_fsys_ctrl(struct clk *clk, int enable); extern int exynos4_clk_ip_fsys_ctrl(struct clk *clk, int enable); extern int exynos4_clk_ip_lcd1_ctrl(struct clk *clk, int enable); +extern int exynos4_clk_ip_image_ctrl(struct clk *clk, int enable); +extern int exynos4_clk_ip_dmc_ctrl(struct clk *clk, int enable); #endif /* __ASM_ARCH_CLOCK_H */ diff --git a/arch/arm/mach-exynos/clock-exynos4210.c b/arch/arm/mach-exynos/clock-exynos4210.c index 3b131e4b6ef5..b8689ff60baf 100644 --- a/arch/arm/mach-exynos/clock-exynos4210.c +++ b/arch/arm/mach-exynos/clock-exynos4210.c @@ -26,6 +26,7 @@ #include <mach/hardware.h> #include <mach/map.h> #include <mach/regs-clock.h> +#include <mach/sysmmu.h> #include "common.h" #include "clock-exynos4.h" @@ -94,6 +95,16 @@ static struct clk init_clocks_off[] = { .devname = "exynos4-fb.1", .enable = exynos4_clk_ip_lcd1_ctrl, .ctrlbit = (1 << 0), + }, { + .name = SYSMMU_CLOCK_NAME, + .devname = SYSMMU_CLOCK_DEVNAME(2d, 14), + .enable = exynos4_clk_ip_image_ctrl, + .ctrlbit = (1 << 3), + }, { + .name = SYSMMU_CLOCK_NAME, + .devname = SYSMMU_CLOCK_DEVNAME(fimd1, 11), + .enable = exynos4_clk_ip_lcd1_ctrl, + .ctrlbit = (1 << 4), }, }; diff --git a/arch/arm/mach-exynos/clock-exynos4212.c b/arch/arm/mach-exynos/clock-exynos4212.c index 3ecc01e06f74..98823120570e 100644 --- a/arch/arm/mach-exynos/clock-exynos4212.c +++ b/arch/arm/mach-exynos/clock-exynos4212.c @@ -26,6 +26,7 @@ #include <mach/hardware.h> #include <mach/map.h> #include <mach/regs-clock.h> +#include <mach/sysmmu.h> #include "common.h" #include "clock-exynos4.h" @@ -39,6 +40,16 @@ static struct sleep_save exynos4212_clock_save[] = { }; #endif +static int exynos4212_clk_ip_isp0_ctrl(struct clk *clk, int enable) +{ + return s5p_gatectrl(EXYNOS4_CLKGATE_IP_ISP0, clk, enable); +} + +static int exynos4212_clk_ip_isp1_ctrl(struct clk *clk, int enable) +{ + return s5p_gatectrl(EXYNOS4_CLKGATE_IP_ISP1, clk, enable); +} + static struct clk *clk_src_mpll_user_list[] = { [0] = &clk_fin_mpll, [1] = &exynos4_clk_mout_mpll.clk, @@ -66,7 +77,22 @@ static struct clksrc_clk clksrcs[] = { }; static struct clk init_clocks_off[] = { - /* nothing here yet */ + { + .name = SYSMMU_CLOCK_NAME, + .devname = SYSMMU_CLOCK_DEVNAME(2d, 14), + .enable = exynos4_clk_ip_dmc_ctrl, + .ctrlbit = (1 << 24), + }, { + .name = SYSMMU_CLOCK_NAME, + .devname = SYSMMU_CLOCK_DEVNAME(isp, 9), + .enable = exynos4212_clk_ip_isp0_ctrl, + .ctrlbit = (7 << 8), + }, { + .name = SYSMMU_CLOCK_NAME2, + .devname = SYSMMU_CLOCK_DEVNAME(isp, 9), + .enable = exynos4212_clk_ip_isp1_ctrl, + .ctrlbit = (1 << 4), + } }; #ifdef CONFIG_PM_SLEEP diff --git a/arch/arm/mach-exynos/clock-exynos5.c b/arch/arm/mach-exynos/clock-exynos5.c index 7ac6ff4c46bd..9f87a07b0bf8 100644 --- a/arch/arm/mach-exynos/clock-exynos5.c +++ b/arch/arm/mach-exynos/clock-exynos5.c @@ -82,6 +82,11 @@ static int exynos5_clksrc_mask_peric0_ctrl(struct clk *clk, int enable) return s5p_gatectrl(EXYNOS5_CLKSRC_MASK_PERIC0, clk, enable); } +static int exynos5_clk_ip_acp_ctrl(struct clk *clk, int enable) +{ + return s5p_gatectrl(EXYNOS5_CLKGATE_IP_ACP, clk, enable); +} + static int exynos5_clk_ip_core_ctrl(struct clk *clk, int enable) { return s5p_gatectrl(EXYNOS5_CLKGATE_IP_CORE, clk, enable); @@ -127,6 +132,21 @@ static int exynos5_clk_ip_peris_ctrl(struct clk *clk, int enable) return s5p_gatectrl(EXYNOS5_CLKGATE_IP_PERIS, clk, enable); } +static int exynos5_clk_ip_gscl_ctrl(struct clk *clk, int enable) +{ + return s5p_gatectrl(EXYNOS5_CLKGATE_IP_GSCL, clk, enable); +} + +static int exynos5_clk_ip_isp0_ctrl(struct clk *clk, int enable) +{ + return s5p_gatectrl(EXYNOS5_CLKGATE_IP_ISP0, clk, enable); +} + +static int exynos5_clk_ip_isp1_ctrl(struct clk *clk, int enable) +{ + return s5p_gatectrl(EXYNOS5_CLKGATE_IP_ISP1, clk, enable); +} + /* Core list of CMU_CPU side */ static struct clksrc_clk exynos5_clk_mout_apll = { @@ -630,6 +650,76 @@ static struct clk exynos5_init_clocks_off[] = { .parent = &exynos5_clk_aclk_66.clk, .enable = exynos5_clk_ip_peric_ctrl, .ctrlbit = (1 << 14), + }, { + .name = SYSMMU_CLOCK_NAME, + .devname = SYSMMU_CLOCK_DEVNAME(mfc_l, 0), + .enable = &exynos5_clk_ip_mfc_ctrl, + .ctrlbit = (1 << 1), + }, { + .name = SYSMMU_CLOCK_NAME, + .devname = SYSMMU_CLOCK_DEVNAME(mfc_r, 1), + .enable = &exynos5_clk_ip_mfc_ctrl, + .ctrlbit = (1 << 2), + }, { + .name = SYSMMU_CLOCK_NAME, + .devname = SYSMMU_CLOCK_DEVNAME(tv, 2), + .enable = &exynos5_clk_ip_disp1_ctrl, + .ctrlbit = (1 << 9) + }, { + .name = SYSMMU_CLOCK_NAME, + .devname = SYSMMU_CLOCK_DEVNAME(jpeg, 3), + .enable = &exynos5_clk_ip_gen_ctrl, + .ctrlbit = (1 << 7), + }, { + .name = SYSMMU_CLOCK_NAME, + .devname = SYSMMU_CLOCK_DEVNAME(rot, 4), + .enable = &exynos5_clk_ip_gen_ctrl, + .ctrlbit = (1 << 6) + }, { + .name = SYSMMU_CLOCK_NAME, + .devname = SYSMMU_CLOCK_DEVNAME(gsc0, 5), + .enable = &exynos5_clk_ip_gscl_ctrl, + .ctrlbit = (1 << 7), + }, { + .name = SYSMMU_CLOCK_NAME, + .devname = SYSMMU_CLOCK_DEVNAME(gsc1, 6), + .enable = &exynos5_clk_ip_gscl_ctrl, + .ctrlbit = (1 << 8), + }, { + .name = SYSMMU_CLOCK_NAME, + .devname = SYSMMU_CLOCK_DEVNAME(gsc2, 7), + .enable = &exynos5_clk_ip_gscl_ctrl, + .ctrlbit = (1 << 9), + }, { + .name = SYSMMU_CLOCK_NAME, + .devname = SYSMMU_CLOCK_DEVNAME(gsc3, 8), + .enable = &exynos5_clk_ip_gscl_ctrl, + .ctrlbit = (1 << 10), + }, { + .name = SYSMMU_CLOCK_NAME, + .devname = SYSMMU_CLOCK_DEVNAME(isp, 9), + .enable = &exynos5_clk_ip_isp0_ctrl, + .ctrlbit = (0x3F << 8), + }, { + .name = SYSMMU_CLOCK_NAME2, + .devname = SYSMMU_CLOCK_DEVNAME(isp, 9), + .enable = &exynos5_clk_ip_isp1_ctrl, + .ctrlbit = (0xF << 4), + }, { + .name = SYSMMU_CLOCK_NAME, + .devname = SYSMMU_CLOCK_DEVNAME(camif0, 12), + .enable = &exynos5_clk_ip_gscl_ctrl, + .ctrlbit = (1 << 11), + }, { + .name = SYSMMU_CLOCK_NAME, + .devname = SYSMMU_CLOCK_DEVNAME(camif1, 13), + .enable = &exynos5_clk_ip_gscl_ctrl, + .ctrlbit = (1 << 12), + }, { + .name = SYSMMU_CLOCK_NAME, + .devname = SYSMMU_CLOCK_DEVNAME(2d, 14), + .enable = &exynos5_clk_ip_acp_ctrl, + .ctrlbit = (1 << 7) } }; diff --git a/arch/arm/mach-exynos/dev-sysmmu.c b/arch/arm/mach-exynos/dev-sysmmu.c index 781563fcb156..c5b1ea301df0 100644 --- a/arch/arm/mach-exynos/dev-sysmmu.c +++ b/arch/arm/mach-exynos/dev-sysmmu.c @@ -1,9 +1,9 @@ -/* linux/arch/arm/mach-exynos4/dev-sysmmu.c +/* linux/arch/arm/mach-exynos/dev-sysmmu.c * - * Copyright (c) 2010 Samsung Electronics Co., Ltd. + * Copyright (c) 2010-2012 Samsung Electronics Co., Ltd. * http://www.samsung.com * - * EXYNOS4 - System MMU support + * EXYNOS - System MMU support * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -12,222 +12,263 @@ #include <linux/platform_device.h> #include <linux/dma-mapping.h> -#include <linux/export.h> + +#include <plat/cpu.h> #include <mach/map.h> #include <mach/irqs.h> #include <mach/sysmmu.h> -#include <plat/s5p-clock.h> - -/* These names must be equal to the clock names in mach-exynos4/clock.c */ -const char *sysmmu_ips_name[EXYNOS4_SYSMMU_TOTAL_IPNUM] = { - "SYSMMU_MDMA" , - "SYSMMU_SSS" , - "SYSMMU_FIMC0" , - "SYSMMU_FIMC1" , - "SYSMMU_FIMC2" , - "SYSMMU_FIMC3" , - "SYSMMU_JPEG" , - "SYSMMU_FIMD0" , - "SYSMMU_FIMD1" , - "SYSMMU_PCIe" , - "SYSMMU_G2D" , - "SYSMMU_ROTATOR", - "SYSMMU_MDMA2" , - "SYSMMU_TV" , - "SYSMMU_MFC_L" , - "SYSMMU_MFC_R" , -}; -static struct resource exynos4_sysmmu_resource[] = { - [0] = { - .start = EXYNOS4_PA_SYSMMU_MDMA, - .end = EXYNOS4_PA_SYSMMU_MDMA + SZ_64K - 1, - .flags = IORESOURCE_MEM, - }, - [1] = { - .start = IRQ_SYSMMU_MDMA0_0, - .end = IRQ_SYSMMU_MDMA0_0, - .flags = IORESOURCE_IRQ, - }, - [2] = { - .start = EXYNOS4_PA_SYSMMU_SSS, - .end = EXYNOS4_PA_SYSMMU_SSS + SZ_64K - 1, - .flags = IORESOURCE_MEM, - }, - [3] = { - .start = IRQ_SYSMMU_SSS_0, - .end = IRQ_SYSMMU_SSS_0, - .flags = IORESOURCE_IRQ, - }, - [4] = { - .start = EXYNOS4_PA_SYSMMU_FIMC0, - .end = EXYNOS4_PA_SYSMMU_FIMC0 + SZ_64K - 1, - .flags = IORESOURCE_MEM, - }, - [5] = { - .start = IRQ_SYSMMU_FIMC0_0, - .end = IRQ_SYSMMU_FIMC0_0, - .flags = IORESOURCE_IRQ, - }, - [6] = { - .start = EXYNOS4_PA_SYSMMU_FIMC1, - .end = EXYNOS4_PA_SYSMMU_FIMC1 + SZ_64K - 1, - .flags = IORESOURCE_MEM, - }, - [7] = { - .start = IRQ_SYSMMU_FIMC1_0, - .end = IRQ_SYSMMU_FIMC1_0, - .flags = IORESOURCE_IRQ, - }, - [8] = { - .start = EXYNOS4_PA_SYSMMU_FIMC2, - .end = EXYNOS4_PA_SYSMMU_FIMC2 + SZ_64K - 1, - .flags = IORESOURCE_MEM, - }, - [9] = { - .start = IRQ_SYSMMU_FIMC2_0, - .end = IRQ_SYSMMU_FIMC2_0, - .flags = IORESOURCE_IRQ, - }, - [10] = { - .start = EXYNOS4_PA_SYSMMU_FIMC3, - .end = EXYNOS4_PA_SYSMMU_FIMC3 + SZ_64K - 1, - .flags = IORESOURCE_MEM, - }, - [11] = { - .start = IRQ_SYSMMU_FIMC3_0, - .end = IRQ_SYSMMU_FIMC3_0, - .flags = IORESOURCE_IRQ, - }, - [12] = { - .start = EXYNOS4_PA_SYSMMU_JPEG, - .end = EXYNOS4_PA_SYSMMU_JPEG + SZ_64K - 1, - .flags = IORESOURCE_MEM, - }, - [13] = { - .start = IRQ_SYSMMU_JPEG_0, - .end = IRQ_SYSMMU_JPEG_0, - .flags = IORESOURCE_IRQ, - }, - [14] = { - .start = EXYNOS4_PA_SYSMMU_FIMD0, - .end = EXYNOS4_PA_SYSMMU_FIMD0 + SZ_64K - 1, - .flags = IORESOURCE_MEM, - }, - [15] = { - .start = IRQ_SYSMMU_LCD0_M0_0, - .end = IRQ_SYSMMU_LCD0_M0_0, - .flags = IORESOURCE_IRQ, - }, - [16] = { - .start = EXYNOS4_PA_SYSMMU_FIMD1, - .end = EXYNOS4_PA_SYSMMU_FIMD1 + SZ_64K - 1, - .flags = IORESOURCE_MEM, - }, - [17] = { - .start = IRQ_SYSMMU_LCD1_M1_0, - .end = IRQ_SYSMMU_LCD1_M1_0, - .flags = IORESOURCE_IRQ, - }, - [18] = { - .start = EXYNOS4_PA_SYSMMU_PCIe, - .end = EXYNOS4_PA_SYSMMU_PCIe + SZ_64K - 1, - .flags = IORESOURCE_MEM, - }, - [19] = { - .start = IRQ_SYSMMU_PCIE_0, - .end = IRQ_SYSMMU_PCIE_0, - .flags = IORESOURCE_IRQ, - }, - [20] = { - .start = EXYNOS4_PA_SYSMMU_G2D, - .end = EXYNOS4_PA_SYSMMU_G2D + SZ_64K - 1, - .flags = IORESOURCE_MEM, - }, - [21] = { - .start = IRQ_SYSMMU_2D_0, - .end = IRQ_SYSMMU_2D_0, - .flags = IORESOURCE_IRQ, - }, - [22] = { - .start = EXYNOS4_PA_SYSMMU_ROTATOR, - .end = EXYNOS4_PA_SYSMMU_ROTATOR + SZ_64K - 1, - .flags = IORESOURCE_MEM, - }, - [23] = { - .start = IRQ_SYSMMU_ROTATOR_0, - .end = IRQ_SYSMMU_ROTATOR_0, - .flags = IORESOURCE_IRQ, - }, - [24] = { - .start = EXYNOS4_PA_SYSMMU_MDMA2, - .end = EXYNOS4_PA_SYSMMU_MDMA2 + SZ_64K - 1, - .flags = IORESOURCE_MEM, - }, - [25] = { - .start = IRQ_SYSMMU_MDMA1_0, - .end = IRQ_SYSMMU_MDMA1_0, - .flags = IORESOURCE_IRQ, - }, - [26] = { - .start = EXYNOS4_PA_SYSMMU_TV, - .end = EXYNOS4_PA_SYSMMU_TV + SZ_64K - 1, - .flags = IORESOURCE_MEM, - }, - [27] = { - .start = IRQ_SYSMMU_TV_M0_0, - .end = IRQ_SYSMMU_TV_M0_0, - .flags = IORESOURCE_IRQ, - }, - [28] = { - .start = EXYNOS4_PA_SYSMMU_MFC_L, - .end = EXYNOS4_PA_SYSMMU_MFC_L + SZ_64K - 1, - .flags = IORESOURCE_MEM, - }, - [29] = { - .start = IRQ_SYSMMU_MFC_M0_0, - .end = IRQ_SYSMMU_MFC_M0_0, - .flags = IORESOURCE_IRQ, - }, - [30] = { - .start = EXYNOS4_PA_SYSMMU_MFC_R, - .end = EXYNOS4_PA_SYSMMU_MFC_R + SZ_64K - 1, - .flags = IORESOURCE_MEM, - }, - [31] = { - .start = IRQ_SYSMMU_MFC_M1_0, - .end = IRQ_SYSMMU_MFC_M1_0, - .flags = IORESOURCE_IRQ, - }, -}; +static u64 exynos_sysmmu_dma_mask = DMA_BIT_MASK(32); + +#define SYSMMU_PLATFORM_DEVICE(ipname, devid) \ +static struct sysmmu_platform_data platdata_##ipname = { \ + .dbgname = #ipname, \ +}; \ +struct platform_device SYSMMU_PLATDEV(ipname) = \ +{ \ + .name = SYSMMU_DEVNAME_BASE, \ + .id = devid, \ + .dev = { \ + .dma_mask = &exynos_sysmmu_dma_mask, \ + .coherent_dma_mask = DMA_BIT_MASK(32), \ + .platform_data = &platdata_##ipname, \ + }, \ +} + +SYSMMU_PLATFORM_DEVICE(mfc_l, 0); +SYSMMU_PLATFORM_DEVICE(mfc_r, 1); +SYSMMU_PLATFORM_DEVICE(tv, 2); +SYSMMU_PLATFORM_DEVICE(jpeg, 3); +SYSMMU_PLATFORM_DEVICE(rot, 4); +SYSMMU_PLATFORM_DEVICE(fimc0, 5); /* fimc* and gsc* exist exclusively */ +SYSMMU_PLATFORM_DEVICE(fimc1, 6); +SYSMMU_PLATFORM_DEVICE(fimc2, 7); +SYSMMU_PLATFORM_DEVICE(fimc3, 8); +SYSMMU_PLATFORM_DEVICE(gsc0, 5); +SYSMMU_PLATFORM_DEVICE(gsc1, 6); +SYSMMU_PLATFORM_DEVICE(gsc2, 7); +SYSMMU_PLATFORM_DEVICE(gsc3, 8); +SYSMMU_PLATFORM_DEVICE(isp, 9); +SYSMMU_PLATFORM_DEVICE(fimd0, 10); +SYSMMU_PLATFORM_DEVICE(fimd1, 11); +SYSMMU_PLATFORM_DEVICE(camif0, 12); +SYSMMU_PLATFORM_DEVICE(camif1, 13); +SYSMMU_PLATFORM_DEVICE(2d, 14); + +#define SYSMMU_RESOURCE_NAME(core, ipname) sysmmures_##core##_##ipname + +#define SYSMMU_RESOURCE(core, ipname) \ + static struct resource SYSMMU_RESOURCE_NAME(core, ipname)[] __initdata = + +#define DEFINE_SYSMMU_RESOURCE(core, mem, irq) \ + DEFINE_RES_MEM_NAMED(core##_PA_SYSMMU_##mem, SZ_4K, #mem), \ + DEFINE_RES_IRQ_NAMED(core##_IRQ_SYSMMU_##irq##_0, #mem) + +#define SYSMMU_RESOURCE_DEFINE(core, ipname, mem, irq) \ + SYSMMU_RESOURCE(core, ipname) { \ + DEFINE_SYSMMU_RESOURCE(core, mem, irq) \ + } -struct platform_device exynos4_device_sysmmu = { - .name = "s5p-sysmmu", - .id = 32, - .num_resources = ARRAY_SIZE(exynos4_sysmmu_resource), - .resource = exynos4_sysmmu_resource, +struct sysmmu_resource_map { + struct platform_device *pdev; + struct resource *res; + u32 rnum; + struct device *pdd; + char *clocknames; }; -EXPORT_SYMBOL(exynos4_device_sysmmu); -static struct clk *sysmmu_clk[S5P_SYSMMU_TOTAL_IPNUM]; -void sysmmu_clk_init(struct device *dev, sysmmu_ips ips) -{ - sysmmu_clk[ips] = clk_get(dev, sysmmu_ips_name[ips]); - if (IS_ERR(sysmmu_clk[ips])) - sysmmu_clk[ips] = NULL; - else - clk_put(sysmmu_clk[ips]); +#define SYSMMU_RESOURCE_MAPPING(core, ipname, resname) { \ + .pdev = &SYSMMU_PLATDEV(ipname), \ + .res = SYSMMU_RESOURCE_NAME(EXYNOS##core, resname), \ + .rnum = ARRAY_SIZE(SYSMMU_RESOURCE_NAME(EXYNOS##core, resname)),\ + .clocknames = SYSMMU_CLOCK_NAME, \ } -void sysmmu_clk_enable(sysmmu_ips ips) -{ - if (sysmmu_clk[ips]) - clk_enable(sysmmu_clk[ips]); +#define SYSMMU_RESOURCE_MAPPING_MC(core, ipname, resname, pdata) { \ + .pdev = &SYSMMU_PLATDEV(ipname), \ + .res = SYSMMU_RESOURCE_NAME(EXYNOS##core, resname), \ + .rnum = ARRAY_SIZE(SYSMMU_RESOURCE_NAME(EXYNOS##core, resname)),\ + .clocknames = SYSMMU_CLOCK_NAME "," SYSMMU_CLOCK_NAME2, \ +} + +#ifdef CONFIG_EXYNOS_DEV_PD +#define SYSMMU_RESOURCE_MAPPING_PD(core, ipname, resname, pd) { \ + .pdev = &SYSMMU_PLATDEV(ipname), \ + .res = &SYSMMU_RESOURCE_NAME(EXYNOS##core, resname), \ + .rnum = ARRAY_SIZE(SYSMMU_RESOURCE_NAME(EXYNOS##core, resname)),\ + .clocknames = SYSMMU_CLOCK_NAME, \ + .pdd = &exynos##core##_device_pd[pd].dev, \ +} + +#define SYSMMU_RESOURCE_MAPPING_MCPD(core, ipname, resname, pd, pdata) {\ + .pdev = &SYSMMU_PLATDEV(ipname), \ + .res = &SYSMMU_RESOURCE_NAME(EXYNOS##core, resname), \ + .rnum = ARRAY_SIZE(SYSMMU_RESOURCE_NAME(EXYNOS##core, resname)),\ + .clocknames = SYSMMU_CLOCK_NAME "," SYSMMU_CLOCK_NAME2, \ + .pdd = &exynos##core##_device_pd[pd].dev, \ } +#else +#define SYSMMU_RESOURCE_MAPPING_PD(core, ipname, resname, pd) \ + SYSMMU_RESOURCE_MAPPING(core, ipname, resname) +#define SYSMMU_RESOURCE_MAPPING_MCPD(core, ipname, resname, pd, pdata) \ + SYSMMU_RESOURCE_MAPPING_MC(core, ipname, resname, pdata) + +#endif /* CONFIG_EXYNOS_DEV_PD */ + +#ifdef CONFIG_ARCH_EXYNOS4 +SYSMMU_RESOURCE_DEFINE(EXYNOS4, fimc0, FIMC0, FIMC0); +SYSMMU_RESOURCE_DEFINE(EXYNOS4, fimc1, FIMC1, FIMC1); +SYSMMU_RESOURCE_DEFINE(EXYNOS4, fimc2, FIMC2, FIMC2); +SYSMMU_RESOURCE_DEFINE(EXYNOS4, fimc3, FIMC3, FIMC3); +SYSMMU_RESOURCE_DEFINE(EXYNOS4, jpeg, JPEG, JPEG); +SYSMMU_RESOURCE_DEFINE(EXYNOS4, 2d, G2D, 2D); +SYSMMU_RESOURCE_DEFINE(EXYNOS4, tv, TV, TV_M0); +SYSMMU_RESOURCE_DEFINE(EXYNOS4, 2d_acp, 2D_ACP, 2D); +SYSMMU_RESOURCE_DEFINE(EXYNOS4, rot, ROTATOR, ROTATOR); +SYSMMU_RESOURCE_DEFINE(EXYNOS4, fimd0, FIMD0, LCD0_M0); +SYSMMU_RESOURCE_DEFINE(EXYNOS4, fimd1, FIMD1, LCD1_M1); +SYSMMU_RESOURCE_DEFINE(EXYNOS4, flite0, FIMC_LITE0, FIMC_LITE0); +SYSMMU_RESOURCE_DEFINE(EXYNOS4, flite1, FIMC_LITE1, FIMC_LITE1); +SYSMMU_RESOURCE_DEFINE(EXYNOS4, mfc_r, MFC_R, MFC_M0); +SYSMMU_RESOURCE_DEFINE(EXYNOS4, mfc_l, MFC_L, MFC_M1); +SYSMMU_RESOURCE(EXYNOS4, isp) { + DEFINE_SYSMMU_RESOURCE(EXYNOS4, FIMC_ISP, FIMC_ISP), + DEFINE_SYSMMU_RESOURCE(EXYNOS4, FIMC_DRC, FIMC_DRC), + DEFINE_SYSMMU_RESOURCE(EXYNOS4, FIMC_FD, FIMC_FD), + DEFINE_SYSMMU_RESOURCE(EXYNOS4, ISPCPU, FIMC_CX), +}; + +static struct sysmmu_resource_map sysmmu_resmap4[] __initdata = { + SYSMMU_RESOURCE_MAPPING_PD(4, fimc0, fimc0, PD_CAM), + SYSMMU_RESOURCE_MAPPING_PD(4, fimc1, fimc1, PD_CAM), + SYSMMU_RESOURCE_MAPPING_PD(4, fimc2, fimc2, PD_CAM), + SYSMMU_RESOURCE_MAPPING_PD(4, fimc3, fimc3, PD_CAM), + SYSMMU_RESOURCE_MAPPING_PD(4, tv, tv, PD_TV), + SYSMMU_RESOURCE_MAPPING_PD(4, mfc_r, mfc_r, PD_MFC), + SYSMMU_RESOURCE_MAPPING_PD(4, mfc_l, mfc_l, PD_MFC), + SYSMMU_RESOURCE_MAPPING_PD(4, rot, rot, PD_LCD0), + SYSMMU_RESOURCE_MAPPING_PD(4, jpeg, jpeg, PD_CAM), + SYSMMU_RESOURCE_MAPPING_PD(4, fimd0, fimd0, PD_LCD0), +}; + +static struct sysmmu_resource_map sysmmu_resmap4210[] __initdata = { + SYSMMU_RESOURCE_MAPPING_PD(4, 2d, 2d, PD_LCD0), + SYSMMU_RESOURCE_MAPPING_PD(4, fimd1, fimd1, PD_LCD1), +}; + +static struct sysmmu_resource_map sysmmu_resmap4212[] __initdata = { + SYSMMU_RESOURCE_MAPPING(4, 2d, 2d_acp), + SYSMMU_RESOURCE_MAPPING_PD(4, camif0, flite0, PD_ISP), + SYSMMU_RESOURCE_MAPPING_PD(4, camif1, flite1, PD_ISP), + SYSMMU_RESOURCE_MAPPING_PD(4, isp, isp, PD_ISP), +}; +#endif /* CONFIG_ARCH_EXYNOS4 */ -void sysmmu_clk_disable(sysmmu_ips ips) +#ifdef CONFIG_ARCH_EXYNOS5 +SYSMMU_RESOURCE_DEFINE(EXYNOS5, jpeg, JPEG, JPEG); +SYSMMU_RESOURCE_DEFINE(EXYNOS5, fimd1, FIMD1, FIMD1); +SYSMMU_RESOURCE_DEFINE(EXYNOS5, 2d, 2D, 2D); +SYSMMU_RESOURCE_DEFINE(EXYNOS5, rot, ROTATOR, ROTATOR); +SYSMMU_RESOURCE_DEFINE(EXYNOS5, tv, TV, TV); +SYSMMU_RESOURCE_DEFINE(EXYNOS5, flite0, LITE0, LITE0); +SYSMMU_RESOURCE_DEFINE(EXYNOS5, flite1, LITE1, LITE1); +SYSMMU_RESOURCE_DEFINE(EXYNOS5, gsc0, GSC0, GSC0); +SYSMMU_RESOURCE_DEFINE(EXYNOS5, gsc1, GSC1, GSC1); +SYSMMU_RESOURCE_DEFINE(EXYNOS5, gsc2, GSC2, GSC2); +SYSMMU_RESOURCE_DEFINE(EXYNOS5, gsc3, GSC3, GSC3); +SYSMMU_RESOURCE_DEFINE(EXYNOS5, mfc_r, MFC_R, MFC_R); +SYSMMU_RESOURCE_DEFINE(EXYNOS5, mfc_l, MFC_L, MFC_L); +SYSMMU_RESOURCE(EXYNOS5, isp) { + DEFINE_SYSMMU_RESOURCE(EXYNOS5, ISP, ISP), + DEFINE_SYSMMU_RESOURCE(EXYNOS5, DRC, DRC), + DEFINE_SYSMMU_RESOURCE(EXYNOS5, FD, FD), + DEFINE_SYSMMU_RESOURCE(EXYNOS5, ISPCPU, MCUISP), + DEFINE_SYSMMU_RESOURCE(EXYNOS5, SCALERC, SCALERCISP), + DEFINE_SYSMMU_RESOURCE(EXYNOS5, SCALERP, SCALERPISP), + DEFINE_SYSMMU_RESOURCE(EXYNOS5, ODC, ODC), + DEFINE_SYSMMU_RESOURCE(EXYNOS5, DIS0, DIS0), + DEFINE_SYSMMU_RESOURCE(EXYNOS5, DIS1, DIS1), + DEFINE_SYSMMU_RESOURCE(EXYNOS5, 3DNR, 3DNR), +}; + +static struct sysmmu_resource_map sysmmu_resmap5[] __initdata = { + SYSMMU_RESOURCE_MAPPING(5, jpeg, jpeg), + SYSMMU_RESOURCE_MAPPING(5, fimd1, fimd1), + SYSMMU_RESOURCE_MAPPING(5, 2d, 2d), + SYSMMU_RESOURCE_MAPPING(5, rot, rot), + SYSMMU_RESOURCE_MAPPING_PD(5, tv, tv, PD_DISP1), + SYSMMU_RESOURCE_MAPPING_PD(5, camif0, flite0, PD_GSCL), + SYSMMU_RESOURCE_MAPPING_PD(5, camif1, flite1, PD_GSCL), + SYSMMU_RESOURCE_MAPPING_PD(5, gsc0, gsc0, PD_GSCL), + SYSMMU_RESOURCE_MAPPING_PD(5, gsc1, gsc1, PD_GSCL), + SYSMMU_RESOURCE_MAPPING_PD(5, gsc2, gsc2, PD_GSCL), + SYSMMU_RESOURCE_MAPPING_PD(5, gsc3, gsc3, PD_GSCL), + SYSMMU_RESOURCE_MAPPING_PD(5, mfc_r, mfc_r, PD_MFC), + SYSMMU_RESOURCE_MAPPING_PD(5, mfc_l, mfc_l, PD_MFC), + SYSMMU_RESOURCE_MAPPING_MCPD(5, isp, isp, PD_ISP, mc_platdata), +}; +#endif /* CONFIG_ARCH_EXYNOS5 */ + +static int __init init_sysmmu_platform_device(void) { - if (sysmmu_clk[ips]) - clk_disable(sysmmu_clk[ips]); + int i, j; + struct sysmmu_resource_map *resmap[2] = {NULL, NULL}; + int nmap[2] = {0, 0}; + +#ifdef CONFIG_ARCH_EXYNOS5 + if (soc_is_exynos5250()) { + resmap[0] = sysmmu_resmap5; + nmap[0] = ARRAY_SIZE(sysmmu_resmap5); + nmap[1] = 0; + } +#endif + +#ifdef CONFIG_ARCH_EXYNOS4 + if (resmap[0] == NULL) { + resmap[0] = sysmmu_resmap4; + nmap[0] = ARRAY_SIZE(sysmmu_resmap4); + } + + if (soc_is_exynos4210()) { + resmap[1] = sysmmu_resmap4210; + nmap[1] = ARRAY_SIZE(sysmmu_resmap4210); + } + + if (soc_is_exynos4412() || soc_is_exynos4212()) { + resmap[1] = sysmmu_resmap4212; + nmap[1] = ARRAY_SIZE(sysmmu_resmap4212); + } +#endif + + for (j = 0; j < 2; j++) { + for (i = 0; i < nmap[j]; i++) { + struct sysmmu_resource_map *map; + struct sysmmu_platform_data *platdata; + + map = &resmap[j][i]; + + map->pdev->dev.parent = map->pdd; + + platdata = map->pdev->dev.platform_data; + platdata->clockname = map->clocknames; + + if (platform_device_add_resources(map->pdev, map->res, + map->rnum)) { + pr_err("%s: Failed to add device resources for " + "%s.%d\n", __func__, + map->pdev->name, map->pdev->id); + continue; + } + + if (platform_device_register(map->pdev)) { + pr_err("%s: Failed to register %s.%d\n", + __func__, map->pdev->name, + map->pdev->id); + } + } + } + + return 0; } +arch_initcall(init_sysmmu_platform_device); diff --git a/arch/arm/mach-exynos/include/mach/irqs.h b/arch/arm/mach-exynos/include/mach/irqs.h index c02dae7bf4a3..ddde8f3a24d4 100644 --- a/arch/arm/mach-exynos/include/mach/irqs.h +++ b/arch/arm/mach-exynos/include/mach/irqs.h @@ -154,6 +154,13 @@ #define EXYNOS4_IRQ_SYSMMU_MFC_M1_0 COMBINER_IRQ(5, 6) #define EXYNOS4_IRQ_SYSMMU_PCIE_0 COMBINER_IRQ(5, 7) +#define EXYNOS4_IRQ_SYSMMU_FIMC_LITE0_0 COMBINER_IRQ(16, 0) +#define EXYNOS4_IRQ_SYSMMU_FIMC_LITE1_0 COMBINER_IRQ(16, 1) +#define EXYNOS4_IRQ_SYSMMU_FIMC_ISP_0 COMBINER_IRQ(16, 2) +#define EXYNOS4_IRQ_SYSMMU_FIMC_DRC_0 COMBINER_IRQ(16, 3) +#define EXYNOS4_IRQ_SYSMMU_FIMC_FD_0 COMBINER_IRQ(16, 4) +#define EXYNOS4_IRQ_SYSMMU_FIMC_CX_0 COMBINER_IRQ(16, 5) + #define EXYNOS4_IRQ_FIMD0_FIFO COMBINER_IRQ(11, 0) #define EXYNOS4_IRQ_FIMD0_VSYNC COMBINER_IRQ(11, 1) #define EXYNOS4_IRQ_FIMD0_SYSTEM COMBINER_IRQ(11, 2) @@ -221,24 +228,6 @@ #define IRQ_KEYPAD EXYNOS4_IRQ_KEYPAD #define IRQ_PMU EXYNOS4_IRQ_PMU -#define IRQ_SYSMMU_MDMA0_0 EXYNOS4_IRQ_SYSMMU_MDMA0_0 -#define IRQ_SYSMMU_SSS_0 EXYNOS4_IRQ_SYSMMU_SSS_0 -#define IRQ_SYSMMU_FIMC0_0 EXYNOS4_IRQ_SYSMMU_FIMC0_0 -#define IRQ_SYSMMU_FIMC1_0 EXYNOS4_IRQ_SYSMMU_FIMC1_0 -#define IRQ_SYSMMU_FIMC2_0 EXYNOS4_IRQ_SYSMMU_FIMC2_0 -#define IRQ_SYSMMU_FIMC3_0 EXYNOS4_IRQ_SYSMMU_FIMC3_0 -#define IRQ_SYSMMU_JPEG_0 EXYNOS4_IRQ_SYSMMU_JPEG_0 -#define IRQ_SYSMMU_2D_0 EXYNOS4_IRQ_SYSMMU_2D_0 - -#define IRQ_SYSMMU_ROTATOR_0 EXYNOS4_IRQ_SYSMMU_ROTATOR_0 -#define IRQ_SYSMMU_MDMA1_0 EXYNOS4_IRQ_SYSMMU_MDMA1_0 -#define IRQ_SYSMMU_LCD0_M0_0 EXYNOS4_IRQ_SYSMMU_LCD0_M0_0 -#define IRQ_SYSMMU_LCD1_M1_0 EXYNOS4_IRQ_SYSMMU_LCD1_M1_0 -#define IRQ_SYSMMU_TV_M0_0 EXYNOS4_IRQ_SYSMMU_TV_M0_0 -#define IRQ_SYSMMU_MFC_M0_0 EXYNOS4_IRQ_SYSMMU_MFC_M0_0 -#define IRQ_SYSMMU_MFC_M1_0 EXYNOS4_IRQ_SYSMMU_MFC_M1_0 -#define IRQ_SYSMMU_PCIE_0 EXYNOS4_IRQ_SYSMMU_PCIE_0 - #define IRQ_FIMD0_FIFO EXYNOS4_IRQ_FIMD0_FIFO #define IRQ_FIMD0_VSYNC EXYNOS4_IRQ_FIMD0_VSYNC #define IRQ_FIMD0_SYSTEM EXYNOS4_IRQ_FIMD0_SYSTEM diff --git a/arch/arm/mach-exynos/include/mach/map.h b/arch/arm/mach-exynos/include/mach/map.h index e009a66477f4..2196af2d8218 100644 --- a/arch/arm/mach-exynos/include/mach/map.h +++ b/arch/arm/mach-exynos/include/mach/map.h @@ -95,6 +95,7 @@ #define EXYNOS5_PA_PDMA1 0x121B0000 #define EXYNOS4_PA_SYSMMU_MDMA 0x10A40000 +#define EXYNOS4_PA_SYSMMU_2D_ACP 0x10A40000 #define EXYNOS4_PA_SYSMMU_SSS 0x10A50000 #define EXYNOS4_PA_SYSMMU_FIMC0 0x11A20000 #define EXYNOS4_PA_SYSMMU_FIMC1 0x11A30000 @@ -103,6 +104,12 @@ #define EXYNOS4_PA_SYSMMU_JPEG 0x11A60000 #define EXYNOS4_PA_SYSMMU_FIMD0 0x11E20000 #define EXYNOS4_PA_SYSMMU_FIMD1 0x12220000 +#define EXYNOS4_PA_SYSMMU_FIMC_ISP 0x12260000 +#define EXYNOS4_PA_SYSMMU_FIMC_DRC 0x12270000 +#define EXYNOS4_PA_SYSMMU_FIMC_FD 0x122A0000 +#define EXYNOS4_PA_SYSMMU_ISPCPU 0x122B0000 +#define EXYNOS4_PA_SYSMMU_FIMC_LITE0 0x123B0000 +#define EXYNOS4_PA_SYSMMU_FIMC_LITE1 0x123C0000 #define EXYNOS4_PA_SYSMMU_PCIe 0x12620000 #define EXYNOS4_PA_SYSMMU_G2D 0x12A20000 #define EXYNOS4_PA_SYSMMU_ROTATOR 0x12A30000 @@ -110,6 +117,37 @@ #define EXYNOS4_PA_SYSMMU_TV 0x12E20000 #define EXYNOS4_PA_SYSMMU_MFC_L 0x13620000 #define EXYNOS4_PA_SYSMMU_MFC_R 0x13630000 + +#define EXYNOS5_PA_SYSMMU_MDMA1 0x10A40000 +#define EXYNOS5_PA_SYSMMU_SSS 0x10A50000 +#define EXYNOS5_PA_SYSMMU_2D 0x10A60000 +#define EXYNOS5_PA_SYSMMU_MFC_L 0x11200000 +#define EXYNOS5_PA_SYSMMU_MFC_R 0x11210000 +#define EXYNOS5_PA_SYSMMU_ROTATOR 0x11D40000 +#define EXYNOS5_PA_SYSMMU_MDMA2 0x11D50000 +#define EXYNOS5_PA_SYSMMU_JPEG 0x11F20000 +#define EXYNOS5_PA_SYSMMU_IOP 0x12360000 +#define EXYNOS5_PA_SYSMMU_RTIC 0x12370000 +#define EXYNOS5_PA_SYSMMU_GPS 0x12630000 +#define EXYNOS5_PA_SYSMMU_ISP 0x13260000 +#define EXYNOS5_PA_SYSMMU_DRC 0x12370000 +#define EXYNOS5_PA_SYSMMU_SCALERC 0x13280000 +#define EXYNOS5_PA_SYSMMU_SCALERP 0x13290000 +#define EXYNOS5_PA_SYSMMU_FD 0x132A0000 +#define EXYNOS5_PA_SYSMMU_ISPCPU 0x132B0000 +#define EXYNOS5_PA_SYSMMU_ODC 0x132C0000 +#define EXYNOS5_PA_SYSMMU_DIS0 0x132D0000 +#define EXYNOS5_PA_SYSMMU_DIS1 0x132E0000 +#define EXYNOS5_PA_SYSMMU_3DNR 0x132F0000 +#define EXYNOS5_PA_SYSMMU_LITE0 0x13C40000 +#define EXYNOS5_PA_SYSMMU_LITE1 0x13C50000 +#define EXYNOS5_PA_SYSMMU_GSC0 0x13E80000 +#define EXYNOS5_PA_SYSMMU_GSC1 0x13E90000 +#define EXYNOS5_PA_SYSMMU_GSC2 0x13EA0000 +#define EXYNOS5_PA_SYSMMU_GSC3 0x13EB0000 +#define EXYNOS5_PA_SYSMMU_FIMD1 0x14640000 +#define EXYNOS5_PA_SYSMMU_TV 0x14650000 + #define EXYNOS4_PA_SPI0 0x13920000 #define EXYNOS4_PA_SPI1 0x13930000 #define EXYNOS4_PA_SPI2 0x13940000 diff --git a/arch/arm/mach-exynos/include/mach/regs-clock.h b/arch/arm/mach-exynos/include/mach/regs-clock.h index d9578a58ae7f..dba83e91f0fd 100644 --- a/arch/arm/mach-exynos/include/mach/regs-clock.h +++ b/arch/arm/mach-exynos/include/mach/regs-clock.h @@ -135,6 +135,9 @@ #define EXYNOS4_CLKGATE_SCLKCPU EXYNOS_CLKREG(0x14800) #define EXYNOS4_CLKGATE_IP_CPU EXYNOS_CLKREG(0x14900) +#define EXYNOS4_CLKGATE_IP_ISP0 EXYNOS_CLKREG(0x18800) +#define EXYNOS4_CLKGATE_IP_ISP1 EXYNOS_CLKREG(0x18804) + #define EXYNOS4_APLL_LOCKTIME (0x1C20) /* 300us */ #define EXYNOS4_APLLCON0_ENABLE_SHIFT (31) @@ -303,6 +306,8 @@ #define EXYNOS5_CLKDIV_PERIC0 EXYNOS_CLKREG(0x10558) #define EXYNOS5_CLKGATE_IP_ACP EXYNOS_CLKREG(0x08800) +#define EXYNOS5_CLKGATE_IP_ISP0 EXYNOS_CLKREG(0x0C800) +#define EXYNOS5_CLKGATE_IP_ISP1 EXYNOS_CLKREG(0x0C804) #define EXYNOS5_CLKGATE_IP_GSCL EXYNOS_CLKREG(0x10920) #define EXYNOS5_CLKGATE_IP_DISP1 EXYNOS_CLKREG(0x10928) #define EXYNOS5_CLKGATE_IP_MFC EXYNOS_CLKREG(0x1092C) diff --git a/arch/arm/mach-exynos/include/mach/regs-sysmmu.h b/arch/arm/mach-exynos/include/mach/regs-sysmmu.h deleted file mode 100644 index 68ff6ad08a2b..000000000000 --- a/arch/arm/mach-exynos/include/mach/regs-sysmmu.h +++ /dev/null @@ -1,28 +0,0 @@ -/* linux/arch/arm/mach-exynos4/include/mach/regs-sysmmu.h - * - * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd. - * http://www.samsung.com - * - * EXYNOS4 - System MMU register - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. -*/ - -#ifndef __ASM_ARCH_REGS_SYSMMU_H -#define __ASM_ARCH_REGS_SYSMMU_H __FILE__ - -#define S5P_MMU_CTRL 0x000 -#define S5P_MMU_CFG 0x004 -#define S5P_MMU_STATUS 0x008 -#define S5P_MMU_FLUSH 0x00C -#define S5P_PT_BASE_ADDR 0x014 -#define S5P_INT_STATUS 0x018 -#define S5P_INT_CLEAR 0x01C -#define S5P_PAGE_FAULT_ADDR 0x024 -#define S5P_AW_FAULT_ADDR 0x028 -#define S5P_AR_FAULT_ADDR 0x02C -#define S5P_DEFAULT_SLAVE_ADDR 0x030 - -#endif /* __ASM_ARCH_REGS_SYSMMU_H */ diff --git a/arch/arm/mach-exynos/include/mach/sysmmu.h b/arch/arm/mach-exynos/include/mach/sysmmu.h index 6a5fbb534e82..998daf2add92 100644 --- a/arch/arm/mach-exynos/include/mach/sysmmu.h +++ b/arch/arm/mach-exynos/include/mach/sysmmu.h @@ -1,46 +1,66 @@ -/* linux/arch/arm/mach-exynos4/include/mach/sysmmu.h - * - * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd. +/* + * Copyright (c) 2011-2012 Samsung Electronics Co., Ltd. * http://www.samsung.com * - * Samsung sysmmu driver for EXYNOS4 + * EXYNOS - System MMU support * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. -*/ - -#ifndef __ASM_ARM_ARCH_SYSMMU_H -#define __ASM_ARM_ARCH_SYSMMU_H __FILE__ - -enum exynos4_sysmmu_ips { - SYSMMU_MDMA, - SYSMMU_SSS, - SYSMMU_FIMC0, - SYSMMU_FIMC1, - SYSMMU_FIMC2, - SYSMMU_FIMC3, - SYSMMU_JPEG, - SYSMMU_FIMD0, - SYSMMU_FIMD1, - SYSMMU_PCIe, - SYSMMU_G2D, - SYSMMU_ROTATOR, - SYSMMU_MDMA2, - SYSMMU_TV, - SYSMMU_MFC_L, - SYSMMU_MFC_R, - EXYNOS4_SYSMMU_TOTAL_IPNUM, + */ + +#ifndef _ARM_MACH_EXYNOS_SYSMMU_H_ +#define _ARM_MACH_EXYNOS_SYSMMU_H_ + +struct sysmmu_platform_data { + char *dbgname; + /* comma(,) separated list of clock names for clock gating */ + char *clockname; }; -#define S5P_SYSMMU_TOTAL_IPNUM EXYNOS4_SYSMMU_TOTAL_IPNUM +#define SYSMMU_DEVNAME_BASE "exynos-sysmmu" + +#define SYSMMU_CLOCK_NAME "sysmmu" +#define SYSMMU_CLOCK_NAME2 "sysmmu_mc" + +#ifdef CONFIG_EXYNOS_DEV_SYSMMU +#include <linux/device.h> +struct platform_device; + +#define SYSMMU_PLATDEV(ipname) exynos_device_sysmmu_##ipname + +extern struct platform_device SYSMMU_PLATDEV(mfc_l); +extern struct platform_device SYSMMU_PLATDEV(mfc_r); +extern struct platform_device SYSMMU_PLATDEV(tv); +extern struct platform_device SYSMMU_PLATDEV(jpeg); +extern struct platform_device SYSMMU_PLATDEV(rot); +extern struct platform_device SYSMMU_PLATDEV(fimc0); +extern struct platform_device SYSMMU_PLATDEV(fimc1); +extern struct platform_device SYSMMU_PLATDEV(fimc2); +extern struct platform_device SYSMMU_PLATDEV(fimc3); +extern struct platform_device SYSMMU_PLATDEV(gsc0); +extern struct platform_device SYSMMU_PLATDEV(gsc1); +extern struct platform_device SYSMMU_PLATDEV(gsc2); +extern struct platform_device SYSMMU_PLATDEV(gsc3); +extern struct platform_device SYSMMU_PLATDEV(isp); +extern struct platform_device SYSMMU_PLATDEV(fimd0); +extern struct platform_device SYSMMU_PLATDEV(fimd1); +extern struct platform_device SYSMMU_PLATDEV(camif0); +extern struct platform_device SYSMMU_PLATDEV(camif1); +extern struct platform_device SYSMMU_PLATDEV(2d); -extern const char *sysmmu_ips_name[EXYNOS4_SYSMMU_TOTAL_IPNUM]; +#ifdef CONFIG_IOMMU_API +static inline void platform_set_sysmmu( + struct device *sysmmu, struct device *dev) +{ + dev->archdata.iommu = sysmmu; +} +#endif -typedef enum exynos4_sysmmu_ips sysmmu_ips; +#else /* !CONFIG_EXYNOS_DEV_SYSMMU */ +#define platform_set_sysmmu(dev, sysmmu) do { } while (0) +#endif -void sysmmu_clk_init(struct device *dev, sysmmu_ips ips); -void sysmmu_clk_enable(sysmmu_ips ips); -void sysmmu_clk_disable(sysmmu_ips ips); +#define SYSMMU_CLOCK_DEVNAME(ipname, id) (SYSMMU_DEVNAME_BASE "." #id) -#endif /* __ASM_ARM_ARCH_SYSMMU_H */ +#endif /* _ARM_MACH_EXYNOS_SYSMMU_H_ */ diff --git a/arch/arm/mach-exynos/mach-armlex4210.c b/arch/arm/mach-exynos/mach-armlex4210.c index fed7116418eb..372e33196e8a 100644 --- a/arch/arm/mach-exynos/mach-armlex4210.c +++ b/arch/arm/mach-exynos/mach-armlex4210.c @@ -147,7 +147,6 @@ static struct platform_device *armlex4210_devices[] __initdata = { &s3c_device_hsmmc3, &s3c_device_rtc, &s3c_device_wdt, - &exynos4_device_sysmmu, &samsung_asoc_dma, &armlex4210_smsc911x, &exynos4_device_ahci, diff --git a/arch/arm/mach-exynos/mach-smdkv310.c b/arch/arm/mach-exynos/mach-smdkv310.c index 5af96064ca51..a8c7656b1fce 100644 --- a/arch/arm/mach-exynos/mach-smdkv310.c +++ b/arch/arm/mach-exynos/mach-smdkv310.c @@ -295,7 +295,6 @@ static struct platform_device *smdkv310_devices[] __initdata = { &s5p_device_mfc_l, &s5p_device_mfc_r, &exynos4_device_spdif, - &exynos4_device_sysmmu, &samsung_asoc_dma, &samsung_asoc_idma, &s5p_device_fimd0, diff --git a/arch/arm/mach-tegra/Kconfig b/arch/arm/mach-tegra/Kconfig index d0f2546706ca..6a113a9bb87a 100644 --- a/arch/arm/mach-tegra/Kconfig +++ b/arch/arm/mach-tegra/Kconfig @@ -50,6 +50,14 @@ config TEGRA_PCI depends on ARCH_TEGRA_2x_SOC select PCI +config TEGRA_AHB + bool "Enable AHB driver for NVIDIA Tegra SoCs" + default y + help + Adds AHB configuration functionality for NVIDIA Tegra SoCs, + which controls AHB bus master arbitration and some + perfomance parameters(priority, prefech size). + comment "Tegra board type" config MACH_HARMONY @@ -111,7 +119,7 @@ config MACH_VENTANA Support for the nVidia Ventana development platform choice - prompt "Low-level debug console UART" + prompt "Default low-level debug console UART" default TEGRA_DEBUG_UART_NONE config TEGRA_DEBUG_UART_NONE @@ -134,6 +142,33 @@ config TEGRA_DEBUG_UARTE endchoice +choice + prompt "Automatic low-level debug console UART" + default TEGRA_DEBUG_UART_AUTO_NONE + +config TEGRA_DEBUG_UART_AUTO_NONE + bool "None" + +config TEGRA_DEBUG_UART_AUTO_ODMDATA + bool "Via ODMDATA" + help + Automatically determines which UART to use for low-level debug based + on the ODMDATA value. This value is part of the BCT, and is written + to the boot memory device using nvflash, or other flashing tool. + When bits 19:18 are 3, then bits 17:15 indicate which UART to use; + 0/1/2/3/4 are UART A/B/C/D/E. + +config TEGRA_DEBUG_UART_AUTO_SCRATCH + bool "Via UART scratch register" + help + Automatically determines which UART to use for low-level debug based + on the UART scratch register value. Some bootloaders put ASCII 'D' + in this register when they initialize their own console UART output. + Using this option allows the kernel to automatically pick the same + UART. + +endchoice + config TEGRA_SYSTEM_DMA bool "Enable system DMA driver for NVIDIA Tegra SoCs" default y diff --git a/arch/arm/mach-tegra/board-dt-tegra30.c b/arch/arm/mach-tegra/board-dt-tegra30.c index 5f7c03e972f3..d96dae0b4aa7 100644 --- a/arch/arm/mach-tegra/board-dt-tegra30.c +++ b/arch/arm/mach-tegra/board-dt-tegra30.c @@ -51,12 +51,22 @@ struct of_dev_auxdata tegra30_auxdata_lookup[] __initdata = { OF_DEV_AUXDATA("nvidia,tegra20-i2c", 0x7000C500, "tegra-i2c.2", NULL), OF_DEV_AUXDATA("nvidia,tegra20-i2c", 0x7000C700, "tegra-i2c.3", NULL), OF_DEV_AUXDATA("nvidia,tegra20-i2c", 0x7000D000, "tegra-i2c.4", NULL), + OF_DEV_AUXDATA("nvidia,tegra30-ahub", 0x70080000, "tegra30-ahub", NULL), {} }; static __initdata struct tegra_clk_init_table tegra_dt_clk_init_table[] = { /* name parent rate enabled */ { "uarta", "pll_p", 408000000, true }, + { "pll_a", "pll_p_out1", 564480000, true }, + { "pll_a_out0", "pll_a", 11289600, true }, + { "extern1", "pll_a_out0", 0, true }, + { "clk_out_1", "extern1", 0, true }, + { "i2s0", "pll_a_out0", 11289600, false}, + { "i2s1", "pll_a_out0", 11289600, false}, + { "i2s2", "pll_a_out0", 11289600, false}, + { "i2s3", "pll_a_out0", 11289600, false}, + { "i2s4", "pll_a_out0", 11289600, false}, { NULL, NULL, 0, 0}, }; diff --git a/arch/arm/mach-tegra/board-paz00.c b/arch/arm/mach-tegra/board-paz00.c index d0735c70d688..55a1e6ccf4a2 100644 --- a/arch/arm/mach-tegra/board-paz00.c +++ b/arch/arm/mach-tegra/board-paz00.c @@ -162,6 +162,8 @@ static void paz00_i2c_init(void) static void paz00_usb_init(void) { + tegra_ehci2_ulpi_phy_config.reset_gpio = TEGRA_ULPI_RST; + platform_device_register(&tegra_ehci2_device); platform_device_register(&tegra_ehci3_device); } @@ -179,7 +181,6 @@ static __initdata struct tegra_clk_init_table paz00_clk_init_table[] = { { "uarta", "pll_p", 216000000, true }, { "uartc", "pll_p", 216000000, true }, - { "pll_p_out4", "pll_p", 24000000, true }, { "usbd", "clk_m", 12000000, false }, { "usb2", "clk_m", 12000000, false }, { "usb3", "clk_m", 12000000, false }, diff --git a/arch/arm/mach-tegra/board-trimslice.c b/arch/arm/mach-tegra/board-trimslice.c index bc59b379c6fe..832fa931c710 100644 --- a/arch/arm/mach-tegra/board-trimslice.c +++ b/arch/arm/mach-tegra/board-trimslice.c @@ -118,6 +118,8 @@ static void trimslice_usb_init(void) pdata = tegra_ehci1_device.dev.platform_data; pdata->vbus_gpio = TRIMSLICE_GPIO_USB1_MODE; + tegra_ehci2_ulpi_phy_config.reset_gpio = TEGRA_GPIO_PV0; + platform_device_register(&tegra_ehci3_device); platform_device_register(&tegra_ehci2_device); platform_device_register(&tegra_ehci1_device); diff --git a/arch/arm/mach-tegra/common.c b/arch/arm/mach-tegra/common.c index 22df10fb9972..2d80566b5383 100644 --- a/arch/arm/mach-tegra/common.c +++ b/arch/arm/mach-tegra/common.c @@ -82,10 +82,12 @@ static __initdata struct tegra_clk_init_table tegra20_clk_init_table[] = { { "pll_p_out1", "pll_p", 28800000, true }, { "pll_p_out2", "pll_p", 48000000, true }, { "pll_p_out3", "pll_p", 72000000, true }, - { "pll_p_out4", "pll_p", 108000000, true }, - { "sclk", "pll_p_out4", 108000000, true }, - { "hclk", "sclk", 108000000, true }, - { "pclk", "hclk", 54000000, true }, + { "pll_p_out4", "pll_p", 24000000, true }, + { "pll_c", "clk_m", 600000000, true }, + { "pll_c_out1", "pll_c", 120000000, true }, + { "sclk", "pll_c_out1", 120000000, true }, + { "hclk", "sclk", 120000000, true }, + { "pclk", "hclk", 60000000, true }, { "csite", NULL, 0, true }, { "emc", NULL, 0, true }, { "cpu", NULL, 0, true }, @@ -93,6 +95,17 @@ static __initdata struct tegra_clk_init_table tegra20_clk_init_table[] = { }; #endif +#ifdef CONFIG_ARCH_TEGRA_3x_SOC +static __initdata struct tegra_clk_init_table tegra30_clk_init_table[] = { + /* name parent rate enabled */ + { "clk_m", NULL, 0, true }, + { "pll_p", "clk_m", 408000000, true }, + { "pll_p_out1", "pll_p", 9600000, true }, + { NULL, NULL, 0, 0}, +}; +#endif + + static void __init tegra_init_cache(u32 tag_latency, u32 data_latency) { #ifdef CONFIG_CACHE_L2X0 @@ -127,6 +140,7 @@ void __init tegra30_init_early(void) { tegra_init_fuse(); tegra30_init_clocks(); + tegra_clk_init_from_table(tegra30_clk_init_table); tegra_init_cache(0x441, 0x551); tegra_pmc_init(); tegra_powergate_init(); diff --git a/arch/arm/mach-tegra/devices.c b/arch/arm/mach-tegra/devices.c index 2d8dfa2faf8f..c70e65ffa36b 100644 --- a/arch/arm/mach-tegra/devices.c +++ b/arch/arm/mach-tegra/devices.c @@ -439,9 +439,8 @@ static struct resource tegra_usb3_resources[] = { }, }; -static struct tegra_ulpi_config tegra_ehci2_ulpi_phy_config = { - /* All existing boards use GPIO PV0 for phy reset */ - .reset_gpio = TEGRA_GPIO_PV0, +struct tegra_ulpi_config tegra_ehci2_ulpi_phy_config = { + .reset_gpio = -1, .clk = "cdev2", }; diff --git a/arch/arm/mach-tegra/devices.h b/arch/arm/mach-tegra/devices.h index 138c642e59f4..4f5052726495 100644 --- a/arch/arm/mach-tegra/devices.h +++ b/arch/arm/mach-tegra/devices.h @@ -22,6 +22,10 @@ #include <linux/platform_device.h> #include <linux/platform_data/tegra_usb.h> +#include <mach/usb_phy.h> + +extern struct tegra_ulpi_config tegra_ehci2_ulpi_phy_config; + extern struct tegra_ehci_platform_data tegra_ehci1_pdata; extern struct tegra_ehci_platform_data tegra_ehci2_pdata; extern struct tegra_ehci_platform_data tegra_ehci3_pdata; diff --git a/arch/arm/mach-tegra/include/mach/tegra-ahb.h b/arch/arm/mach-tegra/include/mach/tegra-ahb.h new file mode 100644 index 000000000000..e0f8c84b1d8c --- /dev/null +++ b/arch/arm/mach-tegra/include/mach/tegra-ahb.h @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + */ + +#ifndef __MACH_TEGRA_AHB_H__ +#define __MACH_TEGRA_AHB_H__ + +extern int tegra_ahb_enable_smmu(struct device_node *ahb); + +#endif /* __MACH_TEGRA_AHB_H__ */ diff --git a/arch/arm/mach-tegra/include/mach/uncompress.h b/arch/arm/mach-tegra/include/mach/uncompress.h index 5a440f315e57..937c4c50219e 100644 --- a/arch/arm/mach-tegra/include/mach/uncompress.h +++ b/arch/arm/mach-tegra/include/mach/uncompress.h @@ -63,52 +63,86 @@ static inline void save_uart_address(void) buf[0] = 0; } -/* - * Setup before decompression. This is where we do UART selection for - * earlyprintk and init the uart_base register. - */ -static inline void arch_decomp_setup(void) +static const struct { + u32 base; + u32 reset_reg; + u32 clock_reg; + u32 bit; +} uarts[] = { + { + TEGRA_UARTA_BASE, + TEGRA_CLK_RESET_BASE + 0x04, + TEGRA_CLK_RESET_BASE + 0x10, + 6, + }, + { + TEGRA_UARTB_BASE, + TEGRA_CLK_RESET_BASE + 0x04, + TEGRA_CLK_RESET_BASE + 0x10, + 7, + }, + { + TEGRA_UARTC_BASE, + TEGRA_CLK_RESET_BASE + 0x08, + TEGRA_CLK_RESET_BASE + 0x14, + 23, + }, + { + TEGRA_UARTD_BASE, + TEGRA_CLK_RESET_BASE + 0x0c, + TEGRA_CLK_RESET_BASE + 0x18, + 1, + }, + { + TEGRA_UARTE_BASE, + TEGRA_CLK_RESET_BASE + 0x0c, + TEGRA_CLK_RESET_BASE + 0x18, + 2, + }, +}; + +static inline bool uart_clocked(int i) +{ + if (*(u8 *)uarts[i].reset_reg & BIT(uarts[i].bit)) + return false; + + if (!(*(u8 *)uarts[i].clock_reg & BIT(uarts[i].bit))) + return false; + + return true; +} + +#ifdef CONFIG_TEGRA_DEBUG_UART_AUTO_ODMDATA +int auto_odmdata(void) +{ + volatile u32 *pmc = (volatile u32 *)TEGRA_PMC_BASE; + u32 odmdata = pmc[0xa0 / 4]; + + /* + * Bits 19:18 are the console type: 0=default, 1=none, 2==DCC, 3==UART + * Some boards apparently swap the last two values, but we don't have + * any way of catering for that here, so we just accept either. If this + * doesn't make sense for your board, just don't enable this feature. + * + * Bits 17:15 indicate the UART to use, 0/1/2/3/4 are UART A/B/C/D/E. + */ + + switch ((odmdata >> 18) & 3) { + case 2: + case 3: + break; + default: + return -1; + } + + return (odmdata >> 15) & 7; +} +#endif + +#ifdef CONFIG_TEGRA_DEBUG_UART_AUTO_SCRATCH +int auto_scratch(void) { - static const struct { - u32 base; - u32 reset_reg; - u32 clock_reg; - u32 bit; - } uarts[] = { - { - TEGRA_UARTA_BASE, - TEGRA_CLK_RESET_BASE + 0x04, - TEGRA_CLK_RESET_BASE + 0x10, - 6, - }, - { - TEGRA_UARTB_BASE, - TEGRA_CLK_RESET_BASE + 0x04, - TEGRA_CLK_RESET_BASE + 0x10, - 7, - }, - { - TEGRA_UARTC_BASE, - TEGRA_CLK_RESET_BASE + 0x08, - TEGRA_CLK_RESET_BASE + 0x14, - 23, - }, - { - TEGRA_UARTD_BASE, - TEGRA_CLK_RESET_BASE + 0x0c, - TEGRA_CLK_RESET_BASE + 0x18, - 1, - }, - { - TEGRA_UARTE_BASE, - TEGRA_CLK_RESET_BASE + 0x0c, - TEGRA_CLK_RESET_BASE + 0x18, - 2, - }, - }; int i; - volatile u32 *apb_misc = (volatile u32 *)TEGRA_APB_MISC_BASE; - u32 chip, div; /* * Look for the first UART that: @@ -125,20 +159,60 @@ static inline void arch_decomp_setup(void) * back to what's specified in TEGRA_DEBUG_UART_BASE. */ for (i = 0; i < ARRAY_SIZE(uarts); i++) { - if (*(u8 *)uarts[i].reset_reg & BIT(uarts[i].bit)) - continue; - - if (!(*(u8 *)uarts[i].clock_reg & BIT(uarts[i].bit))) + if (!uart_clocked(i)) continue; uart = (volatile u8 *)uarts[i].base; if (uart[UART_SCR << DEBUG_UART_SHIFT] != 'D') continue; - break; + return i; } - if (i == ARRAY_SIZE(uarts)) - uart = (volatile u8 *)TEGRA_DEBUG_UART_BASE; + + return -1; +} +#endif + +/* + * Setup before decompression. This is where we do UART selection for + * earlyprintk and init the uart_base register. + */ +static inline void arch_decomp_setup(void) +{ + int uart_id, auto_uart_id; + volatile u32 *apb_misc = (volatile u32 *)TEGRA_APB_MISC_BASE; + u32 chip, div; + +#if defined(CONFIG_TEGRA_DEBUG_UARTA) + uart_id = 0; +#elif defined(CONFIG_TEGRA_DEBUG_UARTB) + uart_id = 1; +#elif defined(CONFIG_TEGRA_DEBUG_UARTC) + uart_id = 2; +#elif defined(CONFIG_TEGRA_DEBUG_UARTD) + uart_id = 3; +#elif defined(CONFIG_TEGRA_DEBUG_UARTE) + uart_id = 4; +#else + uart_id = -1; +#endif + +#if defined(CONFIG_TEGRA_DEBUG_UART_AUTO_ODMDATA) + auto_uart_id = auto_odmdata(); +#elif defined(CONFIG_TEGRA_DEBUG_UART_AUTO_SCRATCH) + auto_uart_id = auto_scratch(); +#else + auto_uart_id = -1; +#endif + if (auto_uart_id != -1) + uart_id = auto_uart_id; + + if (uart_id < 0 || uart_id >= ARRAY_SIZE(uarts) || + !uart_clocked(uart_id)) + uart = NULL; + else + uart = (volatile u8 *)uarts[uart_id].base; + save_uart_address(); if (uart == NULL) return; diff --git a/arch/arm/mach-tegra/include/mach/usb_phy.h b/arch/arm/mach-tegra/include/mach/usb_phy.h index de1a0f602b28..935ce9f65590 100644 --- a/arch/arm/mach-tegra/include/mach/usb_phy.h +++ b/arch/arm/mach-tegra/include/mach/usb_phy.h @@ -61,8 +61,8 @@ struct tegra_usb_phy { struct usb_phy *ulpi; }; -struct tegra_usb_phy *tegra_usb_phy_open(int instance, void __iomem *regs, - void *config, enum tegra_usb_phy_mode phy_mode); +struct tegra_usb_phy *tegra_usb_phy_open(struct device *dev, int instance, + void __iomem *regs, void *config, enum tegra_usb_phy_mode phy_mode); int tegra_usb_phy_power_on(struct tegra_usb_phy *phy); diff --git a/arch/arm/mach-tegra/tegra2_clocks.c b/arch/arm/mach-tegra/tegra2_clocks.c index bae09b859891..b59315ce3691 100644 --- a/arch/arm/mach-tegra/tegra2_clocks.c +++ b/arch/arm/mach-tegra/tegra2_clocks.c @@ -1486,6 +1486,10 @@ static struct clk tegra_clk_m = { }; static struct clk_pll_freq_table tegra_pll_c_freq_table[] = { + { 12000000, 600000000, 600, 12, 1, 8 }, + { 13000000, 600000000, 600, 13, 1, 8 }, + { 19200000, 600000000, 500, 16, 1, 6 }, + { 26000000, 600000000, 600, 26, 1, 8 }, { 0, 0, 0, 0, 0, 0 }, }; diff --git a/arch/arm/mach-tegra/tegra30_clocks.c b/arch/arm/mach-tegra/tegra30_clocks.c index 6d08b53f92d2..e33fe4b14a2a 100644 --- a/arch/arm/mach-tegra/tegra30_clocks.c +++ b/arch/arm/mach-tegra/tegra30_clocks.c @@ -3015,6 +3015,15 @@ struct clk_duplicate tegra_clk_duplicates[] = { CLK_DUPLICATE("sbc6", "spi_slave_tegra.5", NULL), CLK_DUPLICATE("twd", "smp_twd", NULL), CLK_DUPLICATE("vcp", "nvavp", "vcp"), + CLK_DUPLICATE("i2s0", NULL, "i2s0"), + CLK_DUPLICATE("i2s1", NULL, "i2s1"), + CLK_DUPLICATE("i2s2", NULL, "i2s2"), + CLK_DUPLICATE("i2s3", NULL, "i2s3"), + CLK_DUPLICATE("i2s4", NULL, "i2s4"), + CLK_DUPLICATE("dam0", NULL, "dam0"), + CLK_DUPLICATE("dam1", NULL, "dam1"), + CLK_DUPLICATE("dam2", NULL, "dam2"), + CLK_DUPLICATE("spdif_in", NULL, "spdif_in"), }; struct clk *tegra_ptr_clks[] = { diff --git a/arch/arm/mach-tegra/usb_phy.c b/arch/arm/mach-tegra/usb_phy.c index d71d2fed6721..54e353c8e304 100644 --- a/arch/arm/mach-tegra/usb_phy.c +++ b/arch/arm/mach-tegra/usb_phy.c @@ -26,6 +26,7 @@ #include <linux/platform_device.h> #include <linux/io.h> #include <linux/gpio.h> +#include <linux/of_gpio.h> #include <linux/usb/otg.h> #include <linux/usb/ulpi.h> #include <asm/mach-types.h> @@ -654,8 +655,8 @@ static void ulpi_phy_power_off(struct tegra_usb_phy *phy) clk_disable(phy->clk); } -struct tegra_usb_phy *tegra_usb_phy_open(int instance, void __iomem *regs, - void *config, enum tegra_usb_phy_mode phy_mode) +struct tegra_usb_phy *tegra_usb_phy_open(struct device *dev, int instance, + void __iomem *regs, void *config, enum tegra_usb_phy_mode phy_mode) { struct tegra_usb_phy *phy; struct tegra_ulpi_config *ulpi_config; @@ -711,6 +712,16 @@ struct tegra_usb_phy *tegra_usb_phy_open(int instance, void __iomem *regs, err = -ENXIO; goto err1; } + if (!gpio_is_valid(ulpi_config->reset_gpio)) + ulpi_config->reset_gpio = + of_get_named_gpio(dev->of_node, + "nvidia,phy-reset-gpio", 0); + if (!gpio_is_valid(ulpi_config->reset_gpio)) { + pr_err("%s: invalid reset gpio: %d\n", __func__, + ulpi_config->reset_gpio); + err = -EINVAL; + goto err1; + } gpio_request(ulpi_config->reset_gpio, "ulpi_phy_reset_b"); gpio_direction_output(ulpi_config->reset_gpio, 0); phy->ulpi = otg_ulpi_create(&ulpi_viewport_access_ops, 0); diff --git a/arch/arm/plat-pxa/include/plat/pxa27x_keypad.h b/arch/arm/plat-pxa/include/plat/pxa27x_keypad.h index abcc36eb1242..5ce8d5e6ea51 100644 --- a/arch/arm/plat-pxa/include/plat/pxa27x_keypad.h +++ b/arch/arm/plat-pxa/include/plat/pxa27x_keypad.h @@ -44,6 +44,10 @@ struct pxa27x_keypad_platform_data { /* direct keys */ int direct_key_num; unsigned int direct_key_map[MAX_DIRECT_KEY_NUM]; + /* the key output may be low active */ + int direct_key_low_active; + /* give board a chance to choose the start direct key */ + unsigned int direct_key_mask; /* rotary encoders 0 */ int enable_rotary0; diff --git a/arch/arm/plat-s5p/Kconfig b/arch/arm/plat-s5p/Kconfig index 96bea3202304..2c1193c59928 100644 --- a/arch/arm/plat-s5p/Kconfig +++ b/arch/arm/plat-s5p/Kconfig @@ -50,14 +50,6 @@ config S5P_PM Common code for power management support on S5P and newer SoCs Note: Do not select this for S5P6440 and S5P6450. -comment "System MMU" - -config S5P_SYSTEM_MMU - bool "S5P SYSTEM MMU" - depends on ARCH_EXYNOS4 - help - Say Y here if you want to enable System MMU - config S5P_SLEEP bool help diff --git a/arch/arm/plat-s5p/Makefile b/arch/arm/plat-s5p/Makefile index 4bd824136659..4953d50707be 100644 --- a/arch/arm/plat-s5p/Makefile +++ b/arch/arm/plat-s5p/Makefile @@ -16,7 +16,6 @@ obj-y += clock.o obj-y += irq.o obj-$(CONFIG_S5P_EXT_INT) += irq-eint.o obj-$(CONFIG_S5P_GPIO_INT) += irq-gpioint.o -obj-$(CONFIG_S5P_SYSTEM_MMU) += sysmmu.o obj-$(CONFIG_S5P_PM) += pm.o irq-pm.o obj-$(CONFIG_S5P_SLEEP) += sleep.o obj-$(CONFIG_S5P_HRT) += s5p-time.o diff --git a/arch/arm/plat-s5p/sysmmu.c b/arch/arm/plat-s5p/sysmmu.c deleted file mode 100644 index c8bec9c7655d..000000000000 --- a/arch/arm/plat-s5p/sysmmu.c +++ /dev/null @@ -1,313 +0,0 @@ -/* linux/arch/arm/plat-s5p/sysmmu.c - * - * Copyright (c) 2010 Samsung Electronics Co., Ltd. - * http://www.samsung.com - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include <linux/io.h> -#include <linux/interrupt.h> -#include <linux/platform_device.h> -#include <linux/export.h> - -#include <asm/pgtable.h> - -#include <mach/map.h> -#include <mach/regs-sysmmu.h> -#include <plat/sysmmu.h> - -#define CTRL_ENABLE 0x5 -#define CTRL_BLOCK 0x7 -#define CTRL_DISABLE 0x0 - -static struct device *dev; - -static unsigned short fault_reg_offset[SYSMMU_FAULTS_NUM] = { - S5P_PAGE_FAULT_ADDR, - S5P_AR_FAULT_ADDR, - S5P_AW_FAULT_ADDR, - S5P_DEFAULT_SLAVE_ADDR, - S5P_AR_FAULT_ADDR, - S5P_AR_FAULT_ADDR, - S5P_AW_FAULT_ADDR, - S5P_AW_FAULT_ADDR -}; - -static char *sysmmu_fault_name[SYSMMU_FAULTS_NUM] = { - "PAGE FAULT", - "AR MULTI-HIT FAULT", - "AW MULTI-HIT FAULT", - "BUS ERROR", - "AR SECURITY PROTECTION FAULT", - "AR ACCESS PROTECTION FAULT", - "AW SECURITY PROTECTION FAULT", - "AW ACCESS PROTECTION FAULT" -}; - -static int (*fault_handlers[S5P_SYSMMU_TOTAL_IPNUM])( - enum S5P_SYSMMU_INTERRUPT_TYPE itype, - unsigned long pgtable_base, - unsigned long fault_addr); - -/* - * If adjacent 2 bits are true, the system MMU is enabled. - * The system MMU is disabled, otherwise. - */ -static unsigned long sysmmu_states; - -static inline void set_sysmmu_active(sysmmu_ips ips) -{ - sysmmu_states |= 3 << (ips * 2); -} - -static inline void set_sysmmu_inactive(sysmmu_ips ips) -{ - sysmmu_states &= ~(3 << (ips * 2)); -} - -static inline int is_sysmmu_active(sysmmu_ips ips) -{ - return sysmmu_states & (3 << (ips * 2)); -} - -static void __iomem *sysmmusfrs[S5P_SYSMMU_TOTAL_IPNUM]; - -static inline void sysmmu_block(sysmmu_ips ips) -{ - __raw_writel(CTRL_BLOCK, sysmmusfrs[ips] + S5P_MMU_CTRL); - dev_dbg(dev, "%s is blocked.\n", sysmmu_ips_name[ips]); -} - -static inline void sysmmu_unblock(sysmmu_ips ips) -{ - __raw_writel(CTRL_ENABLE, sysmmusfrs[ips] + S5P_MMU_CTRL); - dev_dbg(dev, "%s is unblocked.\n", sysmmu_ips_name[ips]); -} - -static inline void __sysmmu_tlb_invalidate(sysmmu_ips ips) -{ - __raw_writel(0x1, sysmmusfrs[ips] + S5P_MMU_FLUSH); - dev_dbg(dev, "TLB of %s is invalidated.\n", sysmmu_ips_name[ips]); -} - -static inline void __sysmmu_set_ptbase(sysmmu_ips ips, unsigned long pgd) -{ - if (unlikely(pgd == 0)) { - pgd = (unsigned long)ZERO_PAGE(0); - __raw_writel(0x20, sysmmusfrs[ips] + S5P_MMU_CFG); /* 4KB LV1 */ - } else { - __raw_writel(0x0, sysmmusfrs[ips] + S5P_MMU_CFG); /* 16KB LV1 */ - } - - __raw_writel(pgd, sysmmusfrs[ips] + S5P_PT_BASE_ADDR); - - dev_dbg(dev, "Page table base of %s is initialized with 0x%08lX.\n", - sysmmu_ips_name[ips], pgd); - __sysmmu_tlb_invalidate(ips); -} - -void sysmmu_set_fault_handler(sysmmu_ips ips, - int (*handler)(enum S5P_SYSMMU_INTERRUPT_TYPE itype, - unsigned long pgtable_base, - unsigned long fault_addr)) -{ - BUG_ON(!((ips >= SYSMMU_MDMA) && (ips < S5P_SYSMMU_TOTAL_IPNUM))); - fault_handlers[ips] = handler; -} - -static irqreturn_t s5p_sysmmu_irq(int irq, void *dev_id) -{ - /* SYSMMU is in blocked when interrupt occurred. */ - unsigned long base = 0; - sysmmu_ips ips = (sysmmu_ips)dev_id; - enum S5P_SYSMMU_INTERRUPT_TYPE itype; - - itype = (enum S5P_SYSMMU_INTERRUPT_TYPE) - __ffs(__raw_readl(sysmmusfrs[ips] + S5P_INT_STATUS)); - - BUG_ON(!((itype >= 0) && (itype < 8))); - - dev_alert(dev, "%s occurred by %s.\n", sysmmu_fault_name[itype], - sysmmu_ips_name[ips]); - - if (fault_handlers[ips]) { - unsigned long addr; - - base = __raw_readl(sysmmusfrs[ips] + S5P_PT_BASE_ADDR); - addr = __raw_readl(sysmmusfrs[ips] + fault_reg_offset[itype]); - - if (fault_handlers[ips](itype, base, addr)) { - __raw_writel(1 << itype, - sysmmusfrs[ips] + S5P_INT_CLEAR); - dev_notice(dev, "%s from %s is resolved." - " Retrying translation.\n", - sysmmu_fault_name[itype], sysmmu_ips_name[ips]); - } else { - base = 0; - } - } - - sysmmu_unblock(ips); - - if (!base) - dev_notice(dev, "%s from %s is not handled.\n", - sysmmu_fault_name[itype], sysmmu_ips_name[ips]); - - return IRQ_HANDLED; -} - -void s5p_sysmmu_set_tablebase_pgd(sysmmu_ips ips, unsigned long pgd) -{ - if (is_sysmmu_active(ips)) { - sysmmu_block(ips); - __sysmmu_set_ptbase(ips, pgd); - sysmmu_unblock(ips); - } else { - dev_dbg(dev, "%s is disabled. " - "Skipping initializing page table base.\n", - sysmmu_ips_name[ips]); - } -} - -void s5p_sysmmu_enable(sysmmu_ips ips, unsigned long pgd) -{ - if (!is_sysmmu_active(ips)) { - sysmmu_clk_enable(ips); - - __sysmmu_set_ptbase(ips, pgd); - - __raw_writel(CTRL_ENABLE, sysmmusfrs[ips] + S5P_MMU_CTRL); - - set_sysmmu_active(ips); - dev_dbg(dev, "%s is enabled.\n", sysmmu_ips_name[ips]); - } else { - dev_dbg(dev, "%s is already enabled.\n", sysmmu_ips_name[ips]); - } -} - -void s5p_sysmmu_disable(sysmmu_ips ips) -{ - if (is_sysmmu_active(ips)) { - __raw_writel(CTRL_DISABLE, sysmmusfrs[ips] + S5P_MMU_CTRL); - set_sysmmu_inactive(ips); - sysmmu_clk_disable(ips); - dev_dbg(dev, "%s is disabled.\n", sysmmu_ips_name[ips]); - } else { - dev_dbg(dev, "%s is already disabled.\n", sysmmu_ips_name[ips]); - } -} - -void s5p_sysmmu_tlb_invalidate(sysmmu_ips ips) -{ - if (is_sysmmu_active(ips)) { - sysmmu_block(ips); - __sysmmu_tlb_invalidate(ips); - sysmmu_unblock(ips); - } else { - dev_dbg(dev, "%s is disabled. " - "Skipping invalidating TLB.\n", sysmmu_ips_name[ips]); - } -} - -static int s5p_sysmmu_probe(struct platform_device *pdev) -{ - int i, ret; - struct resource *res, *mem; - - dev = &pdev->dev; - - for (i = 0; i < S5P_SYSMMU_TOTAL_IPNUM; i++) { - int irq; - - sysmmu_clk_init(dev, i); - sysmmu_clk_disable(i); - - res = platform_get_resource(pdev, IORESOURCE_MEM, i); - if (!res) { - dev_err(dev, "Failed to get the resource of %s.\n", - sysmmu_ips_name[i]); - ret = -ENODEV; - goto err_res; - } - - mem = request_mem_region(res->start, resource_size(res), - pdev->name); - if (!mem) { - dev_err(dev, "Failed to request the memory region of %s.\n", - sysmmu_ips_name[i]); - ret = -EBUSY; - goto err_res; - } - - sysmmusfrs[i] = ioremap(res->start, resource_size(res)); - if (!sysmmusfrs[i]) { - dev_err(dev, "Failed to ioremap() for %s.\n", - sysmmu_ips_name[i]); - ret = -ENXIO; - goto err_reg; - } - - irq = platform_get_irq(pdev, i); - if (irq <= 0) { - dev_err(dev, "Failed to get the IRQ resource of %s.\n", - sysmmu_ips_name[i]); - ret = -ENOENT; - goto err_map; - } - - if (request_irq(irq, s5p_sysmmu_irq, IRQF_DISABLED, - pdev->name, (void *)i)) { - dev_err(dev, "Failed to request IRQ for %s.\n", - sysmmu_ips_name[i]); - ret = -ENOENT; - goto err_map; - } - } - - return 0; - -err_map: - iounmap(sysmmusfrs[i]); -err_reg: - release_mem_region(mem->start, resource_size(mem)); -err_res: - return ret; -} - -static int s5p_sysmmu_remove(struct platform_device *pdev) -{ - return 0; -} -int s5p_sysmmu_runtime_suspend(struct device *dev) -{ - return 0; -} - -int s5p_sysmmu_runtime_resume(struct device *dev) -{ - return 0; -} - -const struct dev_pm_ops s5p_sysmmu_pm_ops = { - .runtime_suspend = s5p_sysmmu_runtime_suspend, - .runtime_resume = s5p_sysmmu_runtime_resume, -}; - -static struct platform_driver s5p_sysmmu_driver = { - .probe = s5p_sysmmu_probe, - .remove = s5p_sysmmu_remove, - .driver = { - .owner = THIS_MODULE, - .name = "s5p-sysmmu", - .pm = &s5p_sysmmu_pm_ops, - } -}; - -static int __init s5p_sysmmu_init(void) -{ - return platform_driver_register(&s5p_sysmmu_driver); -} -arch_initcall(s5p_sysmmu_init); diff --git a/arch/arm/plat-samsung/include/plat/devs.h b/arch/arm/plat-samsung/include/plat/devs.h index 2155d4af62a3..4067d1dd7f1c 100644 --- a/arch/arm/plat-samsung/include/plat/devs.h +++ b/arch/arm/plat-samsung/include/plat/devs.h @@ -133,7 +133,6 @@ extern struct platform_device exynos4_device_pcm1; extern struct platform_device exynos4_device_pcm2; extern struct platform_device exynos4_device_pd[]; extern struct platform_device exynos4_device_spdif; -extern struct platform_device exynos4_device_sysmmu; extern struct platform_device samsung_asoc_dma; extern struct platform_device samsung_asoc_idma; diff --git a/arch/arm/plat-samsung/include/plat/sysmmu.h b/arch/arm/plat-samsung/include/plat/sysmmu.h deleted file mode 100644 index 5fe8ee01a5ba..000000000000 --- a/arch/arm/plat-samsung/include/plat/sysmmu.h +++ /dev/null @@ -1,95 +0,0 @@ -/* linux/arch/arm/plat-samsung/include/plat/sysmmu.h - * - * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd. - * http://www.samsung.com - * - * Samsung System MMU driver for S5P platform - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. -*/ - -#ifndef __PLAT_SAMSUNG_SYSMMU_H -#define __PLAT_SAMSUNG_SYSMMU_H __FILE__ - -enum S5P_SYSMMU_INTERRUPT_TYPE { - SYSMMU_PAGEFAULT, - SYSMMU_AR_MULTIHIT, - SYSMMU_AW_MULTIHIT, - SYSMMU_BUSERROR, - SYSMMU_AR_SECURITY, - SYSMMU_AR_ACCESS, - SYSMMU_AW_SECURITY, - SYSMMU_AW_PROTECTION, /* 7 */ - SYSMMU_FAULTS_NUM -}; - -#ifdef CONFIG_S5P_SYSTEM_MMU - -#include <mach/sysmmu.h> - -/** - * s5p_sysmmu_enable() - enable system mmu of ip - * @ips: The ip connected system mmu. - * #pgd: Base physical address of the 1st level page table - * - * This function enable system mmu to transfer address - * from virtual address to physical address - */ -void s5p_sysmmu_enable(sysmmu_ips ips, unsigned long pgd); - -/** - * s5p_sysmmu_disable() - disable sysmmu mmu of ip - * @ips: The ip connected system mmu. - * - * This function disable system mmu to transfer address - * from virtual address to physical address - */ -void s5p_sysmmu_disable(sysmmu_ips ips); - -/** - * s5p_sysmmu_set_tablebase_pgd() - set page table base address to refer page table - * @ips: The ip connected system mmu. - * @pgd: The page table base address. - * - * This function set page table base address - * When system mmu transfer address from virtaul address to physical address, - * system mmu refer address information from page table - */ -void s5p_sysmmu_set_tablebase_pgd(sysmmu_ips ips, unsigned long pgd); - -/** - * s5p_sysmmu_tlb_invalidate() - flush all TLB entry in system mmu - * @ips: The ip connected system mmu. - * - * This function flush all TLB entry in system mmu - */ -void s5p_sysmmu_tlb_invalidate(sysmmu_ips ips); - -/** s5p_sysmmu_set_fault_handler() - Fault handler for System MMUs - * @itype: type of fault. - * @pgtable_base: the physical address of page table base. This is 0 if @ips is - * SYSMMU_BUSERROR. - * @fault_addr: the device (virtual) address that the System MMU tried to - * translated. This is 0 if @ips is SYSMMU_BUSERROR. - * Called when interrupt occurred by the System MMUs - * The device drivers of peripheral devices that has a System MMU can implement - * a fault handler to resolve address translation fault by System MMU. - * The meanings of return value and parameters are described below. - - * return value: non-zero if the fault is correctly resolved. - * zero if the fault is not handled. - */ -void s5p_sysmmu_set_fault_handler(sysmmu_ips ips, - int (*handler)(enum S5P_SYSMMU_INTERRUPT_TYPE itype, - unsigned long pgtable_base, - unsigned long fault_addr)); -#else -#define s5p_sysmmu_enable(ips, pgd) do { } while (0) -#define s5p_sysmmu_disable(ips) do { } while (0) -#define s5p_sysmmu_set_tablebase_pgd(ips, pgd) do { } while (0) -#define s5p_sysmmu_tlb_invalidate(ips) do { } while (0) -#define s5p_sysmmu_set_fault_handler(ips, handler) do { } while (0) -#endif -#endif /* __ASM_PLAT_SYSMMU_H */ diff --git a/arch/powerpc/boot/dts/mpc8569mds.dts b/arch/powerpc/boot/dts/mpc8569mds.dts index 7e283c891b7f..fe0d60935e9b 100644 --- a/arch/powerpc/boot/dts/mpc8569mds.dts +++ b/arch/powerpc/boot/dts/mpc8569mds.dts @@ -119,6 +119,7 @@ sdhc@2e000 { status = "disabled"; sdhci,1-bit-only; + bus-width = <1>; }; par_io@e0100 { diff --git a/drivers/Makefile b/drivers/Makefile index 0ee98d50f975..2ba29ffef2cb 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -18,7 +18,7 @@ obj-$(CONFIG_SFI) += sfi/ # PnP must come after ACPI since it will eventually need to check if acpi # was used and do nothing if so obj-$(CONFIG_PNP) += pnp/ -obj-$(CONFIG_ARM_AMBA) += amba/ +obj-y += amba/ # Many drivers will want to use DMA so this has to be made available # really early. obj-$(CONFIG_DMA_ENGINE) += dma/ diff --git a/drivers/amba/Makefile b/drivers/amba/Makefile index 40fe74097be2..66e81c2f1e3c 100644 --- a/drivers/amba/Makefile +++ b/drivers/amba/Makefile @@ -1,2 +1,2 @@ -obj-y += bus.o - +obj-$(CONFIG_ARM_AMBA) += bus.o +obj-$(CONFIG_TEGRA_AHB) += tegra-ahb.o diff --git a/drivers/amba/tegra-ahb.c b/drivers/amba/tegra-ahb.c new file mode 100644 index 000000000000..aa0b1f160528 --- /dev/null +++ b/drivers/amba/tegra-ahb.c @@ -0,0 +1,293 @@ +/* + * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. + * Copyright (C) 2011 Google, Inc. + * + * Author: + * Jay Cheng <jacheng@nvidia.com> + * James Wylder <james.wylder@motorola.com> + * Benoit Goby <benoit@android.com> + * Colin Cross <ccross@android.com> + * Hiroshi DOYU <hdoyu@nvidia.com> + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/io.h> + +#define DRV_NAME "tegra-ahb" + +#define AHB_ARBITRATION_DISABLE 0x00 +#define AHB_ARBITRATION_PRIORITY_CTRL 0x04 +#define AHB_PRIORITY_WEIGHT(x) (((x) & 0x7) << 29) +#define PRIORITY_SELECT_USB BIT(6) +#define PRIORITY_SELECT_USB2 BIT(18) +#define PRIORITY_SELECT_USB3 BIT(17) + +#define AHB_GIZMO_AHB_MEM 0x0c +#define ENB_FAST_REARBITRATE BIT(2) +#define DONT_SPLIT_AHB_WR BIT(7) + +#define AHB_GIZMO_APB_DMA 0x10 +#define AHB_GIZMO_IDE 0x18 +#define AHB_GIZMO_USB 0x1c +#define AHB_GIZMO_AHB_XBAR_BRIDGE 0x20 +#define AHB_GIZMO_CPU_AHB_BRIDGE 0x24 +#define AHB_GIZMO_COP_AHB_BRIDGE 0x28 +#define AHB_GIZMO_XBAR_APB_CTLR 0x2c +#define AHB_GIZMO_VCP_AHB_BRIDGE 0x30 +#define AHB_GIZMO_NAND 0x3c +#define AHB_GIZMO_SDMMC4 0x44 +#define AHB_GIZMO_XIO 0x48 +#define AHB_GIZMO_BSEV 0x60 +#define AHB_GIZMO_BSEA 0x70 +#define AHB_GIZMO_NOR 0x74 +#define AHB_GIZMO_USB2 0x78 +#define AHB_GIZMO_USB3 0x7c +#define IMMEDIATE BIT(18) + +#define AHB_GIZMO_SDMMC1 0x80 +#define AHB_GIZMO_SDMMC2 0x84 +#define AHB_GIZMO_SDMMC3 0x88 +#define AHB_MEM_PREFETCH_CFG_X 0xd8 +#define AHB_ARBITRATION_XBAR_CTRL 0xdc +#define AHB_MEM_PREFETCH_CFG3 0xe0 +#define AHB_MEM_PREFETCH_CFG4 0xe4 +#define AHB_MEM_PREFETCH_CFG1 0xec +#define AHB_MEM_PREFETCH_CFG2 0xf0 +#define PREFETCH_ENB BIT(31) +#define MST_ID(x) (((x) & 0x1f) << 26) +#define AHBDMA_MST_ID MST_ID(5) +#define USB_MST_ID MST_ID(6) +#define USB2_MST_ID MST_ID(18) +#define USB3_MST_ID MST_ID(17) +#define ADDR_BNDRY(x) (((x) & 0xf) << 21) +#define INACTIVITY_TIMEOUT(x) (((x) & 0xffff) << 0) + +#define AHB_ARBITRATION_AHB_MEM_WRQUE_MST_ID 0xf8 + +#define AHB_ARBITRATION_XBAR_CTRL_SMMU_INIT_DONE BIT(17) + +static struct platform_driver tegra_ahb_driver; + +static const u32 tegra_ahb_gizmo[] = { + AHB_ARBITRATION_DISABLE, + AHB_ARBITRATION_PRIORITY_CTRL, + AHB_GIZMO_AHB_MEM, + AHB_GIZMO_APB_DMA, + AHB_GIZMO_IDE, + AHB_GIZMO_USB, + AHB_GIZMO_AHB_XBAR_BRIDGE, + AHB_GIZMO_CPU_AHB_BRIDGE, + AHB_GIZMO_COP_AHB_BRIDGE, + AHB_GIZMO_XBAR_APB_CTLR, + AHB_GIZMO_VCP_AHB_BRIDGE, + AHB_GIZMO_NAND, + AHB_GIZMO_SDMMC4, + AHB_GIZMO_XIO, + AHB_GIZMO_BSEV, + AHB_GIZMO_BSEA, + AHB_GIZMO_NOR, + AHB_GIZMO_USB2, + AHB_GIZMO_USB3, + AHB_GIZMO_SDMMC1, + AHB_GIZMO_SDMMC2, + AHB_GIZMO_SDMMC3, + AHB_MEM_PREFETCH_CFG_X, + AHB_ARBITRATION_XBAR_CTRL, + AHB_MEM_PREFETCH_CFG3, + AHB_MEM_PREFETCH_CFG4, + AHB_MEM_PREFETCH_CFG1, + AHB_MEM_PREFETCH_CFG2, + AHB_ARBITRATION_AHB_MEM_WRQUE_MST_ID, +}; + +struct tegra_ahb { + void __iomem *regs; + struct device *dev; + u32 ctx[0]; +}; + +static inline u32 gizmo_readl(struct tegra_ahb *ahb, u32 offset) +{ + return readl(ahb->regs + offset); +} + +static inline void gizmo_writel(struct tegra_ahb *ahb, u32 value, u32 offset) +{ + writel(value, ahb->regs + offset); +} + +#ifdef CONFIG_ARCH_TEGRA_3x_SOC +static int tegra_ahb_match_by_smmu(struct device *dev, void *data) +{ + struct tegra_ahb *ahb = dev_get_drvdata(dev); + struct device_node *dn = data; + + return (ahb->dev->of_node == dn) ? 1 : 0; +} + +int tegra_ahb_enable_smmu(struct device_node *dn) +{ + struct device *dev; + u32 val; + struct tegra_ahb *ahb; + + dev = driver_find_device(&tegra_ahb_driver.driver, NULL, dn, + tegra_ahb_match_by_smmu); + if (!dev) + return -EPROBE_DEFER; + ahb = dev_get_drvdata(dev); + val = gizmo_readl(ahb, AHB_ARBITRATION_XBAR_CTRL); + val |= AHB_ARBITRATION_XBAR_CTRL_SMMU_INIT_DONE; + gizmo_writel(ahb, val, AHB_ARBITRATION_XBAR_CTRL); + return 0; +} +EXPORT_SYMBOL(tegra_ahb_enable_smmu); +#endif + +static int tegra_ahb_suspend(struct device *dev) +{ + int i; + struct tegra_ahb *ahb = dev_get_drvdata(dev); + + for (i = 0; i < ARRAY_SIZE(tegra_ahb_gizmo); i++) + ahb->ctx[i] = gizmo_readl(ahb, tegra_ahb_gizmo[i]); + return 0; +} + +static int tegra_ahb_resume(struct device *dev) +{ + int i; + struct tegra_ahb *ahb = dev_get_drvdata(dev); + + for (i = 0; i < ARRAY_SIZE(tegra_ahb_gizmo); i++) + gizmo_writel(ahb, ahb->ctx[i], tegra_ahb_gizmo[i]); + return 0; +} + +static UNIVERSAL_DEV_PM_OPS(tegra_ahb_pm, + tegra_ahb_suspend, + tegra_ahb_resume, NULL); + +static void tegra_ahb_gizmo_init(struct tegra_ahb *ahb) +{ + u32 val; + + val = gizmo_readl(ahb, AHB_GIZMO_AHB_MEM); + val |= ENB_FAST_REARBITRATE | IMMEDIATE | DONT_SPLIT_AHB_WR; + gizmo_writel(ahb, val, AHB_GIZMO_AHB_MEM); + + val = gizmo_readl(ahb, AHB_GIZMO_USB); + val |= IMMEDIATE; + gizmo_writel(ahb, val, AHB_GIZMO_USB); + + val = gizmo_readl(ahb, AHB_GIZMO_USB2); + val |= IMMEDIATE; + gizmo_writel(ahb, val, AHB_GIZMO_USB2); + + val = gizmo_readl(ahb, AHB_GIZMO_USB3); + val |= IMMEDIATE; + gizmo_writel(ahb, val, AHB_GIZMO_USB3); + + val = gizmo_readl(ahb, AHB_ARBITRATION_PRIORITY_CTRL); + val |= PRIORITY_SELECT_USB | + PRIORITY_SELECT_USB2 | + PRIORITY_SELECT_USB3 | + AHB_PRIORITY_WEIGHT(7); + gizmo_writel(ahb, val, AHB_ARBITRATION_PRIORITY_CTRL); + + val = gizmo_readl(ahb, AHB_MEM_PREFETCH_CFG1); + val &= ~MST_ID(~0); + val |= PREFETCH_ENB | + AHBDMA_MST_ID | + ADDR_BNDRY(0xc) | + INACTIVITY_TIMEOUT(0x1000); + gizmo_writel(ahb, val, AHB_MEM_PREFETCH_CFG1); + + val = gizmo_readl(ahb, AHB_MEM_PREFETCH_CFG2); + val &= ~MST_ID(~0); + val |= PREFETCH_ENB | + USB_MST_ID | + ADDR_BNDRY(0xc) | + INACTIVITY_TIMEOUT(0x1000); + gizmo_writel(ahb, val, AHB_MEM_PREFETCH_CFG2); + + val = gizmo_readl(ahb, AHB_MEM_PREFETCH_CFG3); + val &= ~MST_ID(~0); + val |= PREFETCH_ENB | + USB3_MST_ID | + ADDR_BNDRY(0xc) | + INACTIVITY_TIMEOUT(0x1000); + gizmo_writel(ahb, val, AHB_MEM_PREFETCH_CFG3); + + val = gizmo_readl(ahb, AHB_MEM_PREFETCH_CFG4); + val &= ~MST_ID(~0); + val |= PREFETCH_ENB | + USB2_MST_ID | + ADDR_BNDRY(0xc) | + INACTIVITY_TIMEOUT(0x1000); + gizmo_writel(ahb, val, AHB_MEM_PREFETCH_CFG4); +} + +static int __devinit tegra_ahb_probe(struct platform_device *pdev) +{ + struct resource *res; + struct tegra_ahb *ahb; + size_t bytes; + + bytes = sizeof(*ahb) + sizeof(u32) * ARRAY_SIZE(tegra_ahb_gizmo); + ahb = devm_kzalloc(&pdev->dev, bytes, GFP_KERNEL); + if (!ahb) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + return -ENODEV; + ahb->regs = devm_request_and_ioremap(&pdev->dev, res); + if (!ahb->regs) + return -EBUSY; + + ahb->dev = &pdev->dev; + platform_set_drvdata(pdev, ahb); + tegra_ahb_gizmo_init(ahb); + return 0; +} + +static int __devexit tegra_ahb_remove(struct platform_device *pdev) +{ + return 0; +} + +static const struct of_device_id tegra_ahb_of_match[] __devinitconst = { + { .compatible = "nvidia,tegra30-ahb", }, + { .compatible = "nvidia,tegra20-ahb", }, + {}, +}; + +static struct platform_driver tegra_ahb_driver = { + .probe = tegra_ahb_probe, + .remove = __devexit_p(tegra_ahb_remove), + .driver = { + .name = DRV_NAME, + .owner = THIS_MODULE, + .of_match_table = tegra_ahb_of_match, + .pm = &tegra_ahb_pm, + }, +}; +module_platform_driver(tegra_ahb_driver); + +MODULE_AUTHOR("Hiroshi DOYU <hdoyu@nvidia.com>"); +MODULE_DESCRIPTION("Tegra AHB driver"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:" DRV_NAME); diff --git a/drivers/dma/ep93xx_dma.c b/drivers/dma/ep93xx_dma.c index f6e9b572b998..c64917ec313d 100644 --- a/drivers/dma/ep93xx_dma.c +++ b/drivers/dma/ep93xx_dma.c @@ -71,6 +71,7 @@ #define M2M_CONTROL_TM_SHIFT 13 #define M2M_CONTROL_TM_TX (1 << M2M_CONTROL_TM_SHIFT) #define M2M_CONTROL_TM_RX (2 << M2M_CONTROL_TM_SHIFT) +#define M2M_CONTROL_NFBINT BIT(21) #define M2M_CONTROL_RSS_SHIFT 22 #define M2M_CONTROL_RSS_SSPRX (1 << M2M_CONTROL_RSS_SHIFT) #define M2M_CONTROL_RSS_SSPTX (2 << M2M_CONTROL_RSS_SHIFT) @@ -79,7 +80,22 @@ #define M2M_CONTROL_PWSC_SHIFT 25 #define M2M_INTERRUPT 0x0004 -#define M2M_INTERRUPT_DONEINT BIT(1) +#define M2M_INTERRUPT_MASK 6 + +#define M2M_STATUS 0x000c +#define M2M_STATUS_CTL_SHIFT 1 +#define M2M_STATUS_CTL_IDLE (0 << M2M_STATUS_CTL_SHIFT) +#define M2M_STATUS_CTL_STALL (1 << M2M_STATUS_CTL_SHIFT) +#define M2M_STATUS_CTL_MEMRD (2 << M2M_STATUS_CTL_SHIFT) +#define M2M_STATUS_CTL_MEMWR (3 << M2M_STATUS_CTL_SHIFT) +#define M2M_STATUS_CTL_BWCWAIT (4 << M2M_STATUS_CTL_SHIFT) +#define M2M_STATUS_CTL_MASK (7 << M2M_STATUS_CTL_SHIFT) +#define M2M_STATUS_BUF_SHIFT 4 +#define M2M_STATUS_BUF_NO (0 << M2M_STATUS_BUF_SHIFT) +#define M2M_STATUS_BUF_ON (1 << M2M_STATUS_BUF_SHIFT) +#define M2M_STATUS_BUF_NEXT (2 << M2M_STATUS_BUF_SHIFT) +#define M2M_STATUS_BUF_MASK (3 << M2M_STATUS_BUF_SHIFT) +#define M2M_STATUS_DONE BIT(6) #define M2M_BCR0 0x0010 #define M2M_BCR1 0x0014 @@ -426,15 +442,6 @@ static int m2p_hw_interrupt(struct ep93xx_dma_chan *edmac) /* * M2M DMA implementation - * - * For the M2M transfers we don't use NFB at all. This is because it simply - * doesn't work well with memcpy transfers. When you submit both buffers it is - * extremely unlikely that you get an NFB interrupt, but it instead reports - * DONE interrupt and both buffers are already transferred which means that we - * weren't able to update the next buffer. - * - * So for now we "simulate" NFB by just submitting buffer after buffer - * without double buffering. */ static int m2m_hw_setup(struct ep93xx_dma_chan *edmac) @@ -543,6 +550,11 @@ static void m2m_hw_submit(struct ep93xx_dma_chan *edmac) m2m_fill_desc(edmac); control |= M2M_CONTROL_DONEINT; + if (ep93xx_dma_advance_active(edmac)) { + m2m_fill_desc(edmac); + control |= M2M_CONTROL_NFBINT; + } + /* * Now we can finally enable the channel. For M2M channel this must be * done _after_ the BCRx registers are programmed. @@ -560,32 +572,89 @@ static void m2m_hw_submit(struct ep93xx_dma_chan *edmac) } } +/* + * According to EP93xx User's Guide, we should receive DONE interrupt when all + * M2M DMA controller transactions complete normally. This is not always the + * case - sometimes EP93xx M2M DMA asserts DONE interrupt when the DMA channel + * is still running (channel Buffer FSM in DMA_BUF_ON state, and channel + * Control FSM in DMA_MEM_RD state, observed at least in IDE-DMA operation). + * In effect, disabling the channel when only DONE bit is set could stop + * currently running DMA transfer. To avoid this, we use Buffer FSM and + * Control FSM to check current state of DMA channel. + */ static int m2m_hw_interrupt(struct ep93xx_dma_chan *edmac) { + u32 status = readl(edmac->regs + M2M_STATUS); + u32 ctl_fsm = status & M2M_STATUS_CTL_MASK; + u32 buf_fsm = status & M2M_STATUS_BUF_MASK; + bool done = status & M2M_STATUS_DONE; + bool last_done; u32 control; + struct ep93xx_dma_desc *desc; - if (!(readl(edmac->regs + M2M_INTERRUPT) & M2M_INTERRUPT_DONEINT)) + /* Accept only DONE and NFB interrupts */ + if (!(readl(edmac->regs + M2M_INTERRUPT) & M2M_INTERRUPT_MASK)) return INTERRUPT_UNKNOWN; - /* Clear the DONE bit */ - writel(0, edmac->regs + M2M_INTERRUPT); + if (done) { + /* Clear the DONE bit */ + writel(0, edmac->regs + M2M_INTERRUPT); + } - /* Disable interrupts and the channel */ - control = readl(edmac->regs + M2M_CONTROL); - control &= ~(M2M_CONTROL_DONEINT | M2M_CONTROL_ENABLE); - writel(control, edmac->regs + M2M_CONTROL); + /* + * Check whether we are done with descriptors or not. This, together + * with DMA channel state, determines action to take in interrupt. + */ + desc = ep93xx_dma_get_active(edmac); + last_done = !desc || desc->txd.cookie; /* - * Since we only get DONE interrupt we have to find out ourselves - * whether there still is something to process. So we try to advance - * the chain an see whether it succeeds. + * Use M2M DMA Buffer FSM and Control FSM to check current state of + * DMA channel. Using DONE and NFB bits from channel status register + * or bits from channel interrupt register is not reliable. */ - if (ep93xx_dma_advance_active(edmac)) { - edmac->edma->hw_submit(edmac); - return INTERRUPT_NEXT_BUFFER; + if (!last_done && + (buf_fsm == M2M_STATUS_BUF_NO || + buf_fsm == M2M_STATUS_BUF_ON)) { + /* + * Two buffers are ready for update when Buffer FSM is in + * DMA_NO_BUF state. Only one buffer can be prepared without + * disabling the channel or polling the DONE bit. + * To simplify things, always prepare only one buffer. + */ + if (ep93xx_dma_advance_active(edmac)) { + m2m_fill_desc(edmac); + if (done && !edmac->chan.private) { + /* Software trigger for memcpy channel */ + control = readl(edmac->regs + M2M_CONTROL); + control |= M2M_CONTROL_START; + writel(control, edmac->regs + M2M_CONTROL); + } + return INTERRUPT_NEXT_BUFFER; + } else { + last_done = true; + } + } + + /* + * Disable the channel only when Buffer FSM is in DMA_NO_BUF state + * and Control FSM is in DMA_STALL state. + */ + if (last_done && + buf_fsm == M2M_STATUS_BUF_NO && + ctl_fsm == M2M_STATUS_CTL_STALL) { + /* Disable interrupts and the channel */ + control = readl(edmac->regs + M2M_CONTROL); + control &= ~(M2M_CONTROL_DONEINT | M2M_CONTROL_NFBINT + | M2M_CONTROL_ENABLE); + writel(control, edmac->regs + M2M_CONTROL); + return INTERRUPT_DONE; } - return INTERRUPT_DONE; + /* + * Nothing to do this time. + */ + return INTERRUPT_NEXT_BUFFER; } /* diff --git a/drivers/input/keyboard/pxa27x_keypad.c b/drivers/input/keyboard/pxa27x_keypad.c index 29fe1b2be1c1..7f7b72464a37 100644 --- a/drivers/input/keyboard/pxa27x_keypad.c +++ b/drivers/input/keyboard/pxa27x_keypad.c @@ -311,7 +311,15 @@ static void pxa27x_keypad_scan_direct(struct pxa27x_keypad *keypad) if (pdata->enable_rotary0 || pdata->enable_rotary1) pxa27x_keypad_scan_rotary(keypad); - new_state = KPDK_DK(kpdk) & keypad->direct_key_mask; + /* + * The KPDR_DK only output the key pin level, so it relates to board, + * and low level may be active. + */ + if (pdata->direct_key_low_active) + new_state = ~KPDK_DK(kpdk) & keypad->direct_key_mask; + else + new_state = KPDK_DK(kpdk) & keypad->direct_key_mask; + bits_changed = keypad->direct_key_state ^ new_state; if (bits_changed == 0) @@ -383,7 +391,14 @@ static void pxa27x_keypad_config(struct pxa27x_keypad *keypad) if (pdata->direct_key_num > direct_key_num) direct_key_num = pdata->direct_key_num; - keypad->direct_key_mask = ((2 << direct_key_num) - 1) & ~mask; + /* + * Direct keys usage may not start from KP_DKIN0, check the platfrom + * mask data to config the specific. + */ + if (pdata->direct_key_mask) + keypad->direct_key_mask = pdata->direct_key_mask; + else + keypad->direct_key_mask = ((1 << direct_key_num) - 1) & ~mask; /* enable direct key */ if (direct_key_num) @@ -399,7 +414,7 @@ static int pxa27x_keypad_open(struct input_dev *dev) struct pxa27x_keypad *keypad = input_get_drvdata(dev); /* Enable unit clock */ - clk_enable(keypad->clk); + clk_prepare_enable(keypad->clk); pxa27x_keypad_config(keypad); return 0; @@ -410,7 +425,7 @@ static void pxa27x_keypad_close(struct input_dev *dev) struct pxa27x_keypad *keypad = input_get_drvdata(dev); /* Disable clock unit */ - clk_disable(keypad->clk); + clk_disable_unprepare(keypad->clk); } #ifdef CONFIG_PM @@ -419,10 +434,14 @@ static int pxa27x_keypad_suspend(struct device *dev) struct platform_device *pdev = to_platform_device(dev); struct pxa27x_keypad *keypad = platform_get_drvdata(pdev); - clk_disable(keypad->clk); - + /* + * If the keypad is used a wake up source, clock can not be disabled. + * Or it can not detect the key pressing. + */ if (device_may_wakeup(&pdev->dev)) enable_irq_wake(keypad->irq); + else + clk_disable_unprepare(keypad->clk); return 0; } @@ -433,19 +452,24 @@ static int pxa27x_keypad_resume(struct device *dev) struct pxa27x_keypad *keypad = platform_get_drvdata(pdev); struct input_dev *input_dev = keypad->input_dev; - if (device_may_wakeup(&pdev->dev)) + /* + * If the keypad is used as wake up source, the clock is not turned + * off. So do not need configure it again. + */ + if (device_may_wakeup(&pdev->dev)) { disable_irq_wake(keypad->irq); + } else { + mutex_lock(&input_dev->mutex); - mutex_lock(&input_dev->mutex); + if (input_dev->users) { + /* Enable unit clock */ + clk_prepare_enable(keypad->clk); + pxa27x_keypad_config(keypad); + } - if (input_dev->users) { - /* Enable unit clock */ - clk_enable(keypad->clk); - pxa27x_keypad_config(keypad); + mutex_unlock(&input_dev->mutex); } - mutex_unlock(&input_dev->mutex); - return 0; } diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig index c69843742bb0..340893727538 100644 --- a/drivers/iommu/Kconfig +++ b/drivers/iommu/Kconfig @@ -162,4 +162,25 @@ config TEGRA_IOMMU_SMMU space through the SMMU (System Memory Management Unit) hardware included on Tegra SoCs. +config EXYNOS_IOMMU + bool "Exynos IOMMU Support" + depends on ARCH_EXYNOS && EXYNOS_DEV_SYSMMU + select IOMMU_API + help + Support for the IOMMU(System MMU) of Samsung Exynos application + processor family. This enables H/W multimedia accellerators to see + non-linear physical memory chunks as a linear memory in their + address spaces + + If unsure, say N here. + +config EXYNOS_IOMMU_DEBUG + bool "Debugging log for Exynos IOMMU" + depends on EXYNOS_IOMMU + help + Select this to see the detailed log message that shows what + happens in the IOMMU driver + + Say N unless you need kernel log message for IOMMU debugging + endif # IOMMU_SUPPORT diff --git a/drivers/iommu/Makefile b/drivers/iommu/Makefile index 3e5e82ae9f0d..76e54ef796de 100644 --- a/drivers/iommu/Makefile +++ b/drivers/iommu/Makefile @@ -10,3 +10,4 @@ obj-$(CONFIG_OMAP_IOVMM) += omap-iovmm.o obj-$(CONFIG_OMAP_IOMMU_DEBUG) += omap-iommu-debug.o obj-$(CONFIG_TEGRA_IOMMU_GART) += tegra-gart.o obj-$(CONFIG_TEGRA_IOMMU_SMMU) += tegra-smmu.o +obj-$(CONFIG_EXYNOS_IOMMU) += exynos-iommu.o diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c new file mode 100644 index 000000000000..9a114b9ff170 --- /dev/null +++ b/drivers/iommu/exynos-iommu.c @@ -0,0 +1,1076 @@ +/* linux/drivers/iommu/exynos_iommu.c + * + * Copyright (c) 2011 Samsung Electronics Co., Ltd. + * http://www.samsung.com + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifdef CONFIG_EXYNOS_IOMMU_DEBUG +#define DEBUG +#endif + +#include <linux/io.h> +#include <linux/interrupt.h> +#include <linux/platform_device.h> +#include <linux/slab.h> +#include <linux/pm_runtime.h> +#include <linux/clk.h> +#include <linux/err.h> +#include <linux/mm.h> +#include <linux/iommu.h> +#include <linux/errno.h> +#include <linux/list.h> +#include <linux/memblock.h> +#include <linux/export.h> + +#include <asm/cacheflush.h> +#include <asm/pgtable.h> + +#include <mach/sysmmu.h> + +/* We does not consider super section mapping (16MB) */ +#define SECT_ORDER 20 +#define LPAGE_ORDER 16 +#define SPAGE_ORDER 12 + +#define SECT_SIZE (1 << SECT_ORDER) +#define LPAGE_SIZE (1 << LPAGE_ORDER) +#define SPAGE_SIZE (1 << SPAGE_ORDER) + +#define SECT_MASK (~(SECT_SIZE - 1)) +#define LPAGE_MASK (~(LPAGE_SIZE - 1)) +#define SPAGE_MASK (~(SPAGE_SIZE - 1)) + +#define lv1ent_fault(sent) (((*(sent) & 3) == 0) || ((*(sent) & 3) == 3)) +#define lv1ent_page(sent) ((*(sent) & 3) == 1) +#define lv1ent_section(sent) ((*(sent) & 3) == 2) + +#define lv2ent_fault(pent) ((*(pent) & 3) == 0) +#define lv2ent_small(pent) ((*(pent) & 2) == 2) +#define lv2ent_large(pent) ((*(pent) & 3) == 1) + +#define section_phys(sent) (*(sent) & SECT_MASK) +#define section_offs(iova) ((iova) & 0xFFFFF) +#define lpage_phys(pent) (*(pent) & LPAGE_MASK) +#define lpage_offs(iova) ((iova) & 0xFFFF) +#define spage_phys(pent) (*(pent) & SPAGE_MASK) +#define spage_offs(iova) ((iova) & 0xFFF) + +#define lv1ent_offset(iova) ((iova) >> SECT_ORDER) +#define lv2ent_offset(iova) (((iova) & 0xFF000) >> SPAGE_ORDER) + +#define NUM_LV1ENTRIES 4096 +#define NUM_LV2ENTRIES 256 + +#define LV2TABLE_SIZE (NUM_LV2ENTRIES * sizeof(long)) + +#define SPAGES_PER_LPAGE (LPAGE_SIZE / SPAGE_SIZE) + +#define lv2table_base(sent) (*(sent) & 0xFFFFFC00) + +#define mk_lv1ent_sect(pa) ((pa) | 2) +#define mk_lv1ent_page(pa) ((pa) | 1) +#define mk_lv2ent_lpage(pa) ((pa) | 1) +#define mk_lv2ent_spage(pa) ((pa) | 2) + +#define CTRL_ENABLE 0x5 +#define CTRL_BLOCK 0x7 +#define CTRL_DISABLE 0x0 + +#define REG_MMU_CTRL 0x000 +#define REG_MMU_CFG 0x004 +#define REG_MMU_STATUS 0x008 +#define REG_MMU_FLUSH 0x00C +#define REG_MMU_FLUSH_ENTRY 0x010 +#define REG_PT_BASE_ADDR 0x014 +#define REG_INT_STATUS 0x018 +#define REG_INT_CLEAR 0x01C + +#define REG_PAGE_FAULT_ADDR 0x024 +#define REG_AW_FAULT_ADDR 0x028 +#define REG_AR_FAULT_ADDR 0x02C +#define REG_DEFAULT_SLAVE_ADDR 0x030 + +#define REG_MMU_VERSION 0x034 + +#define REG_PB0_SADDR 0x04C +#define REG_PB0_EADDR 0x050 +#define REG_PB1_SADDR 0x054 +#define REG_PB1_EADDR 0x058 + +static unsigned long *section_entry(unsigned long *pgtable, unsigned long iova) +{ + return pgtable + lv1ent_offset(iova); +} + +static unsigned long *page_entry(unsigned long *sent, unsigned long iova) +{ + return (unsigned long *)__va(lv2table_base(sent)) + lv2ent_offset(iova); +} + +enum exynos_sysmmu_inttype { + SYSMMU_PAGEFAULT, + SYSMMU_AR_MULTIHIT, + SYSMMU_AW_MULTIHIT, + SYSMMU_BUSERROR, + SYSMMU_AR_SECURITY, + SYSMMU_AR_ACCESS, + SYSMMU_AW_SECURITY, + SYSMMU_AW_PROTECTION, /* 7 */ + SYSMMU_FAULT_UNKNOWN, + SYSMMU_FAULTS_NUM +}; + +/* + * @itype: type of fault. + * @pgtable_base: the physical address of page table base. This is 0 if @itype + * is SYSMMU_BUSERROR. + * @fault_addr: the device (virtual) address that the System MMU tried to + * translated. This is 0 if @itype is SYSMMU_BUSERROR. + */ +typedef int (*sysmmu_fault_handler_t)(enum exynos_sysmmu_inttype itype, + unsigned long pgtable_base, unsigned long fault_addr); + +static unsigned short fault_reg_offset[SYSMMU_FAULTS_NUM] = { + REG_PAGE_FAULT_ADDR, + REG_AR_FAULT_ADDR, + REG_AW_FAULT_ADDR, + REG_DEFAULT_SLAVE_ADDR, + REG_AR_FAULT_ADDR, + REG_AR_FAULT_ADDR, + REG_AW_FAULT_ADDR, + REG_AW_FAULT_ADDR +}; + +static char *sysmmu_fault_name[SYSMMU_FAULTS_NUM] = { + "PAGE FAULT", + "AR MULTI-HIT FAULT", + "AW MULTI-HIT FAULT", + "BUS ERROR", + "AR SECURITY PROTECTION FAULT", + "AR ACCESS PROTECTION FAULT", + "AW SECURITY PROTECTION FAULT", + "AW ACCESS PROTECTION FAULT", + "UNKNOWN FAULT" +}; + +struct exynos_iommu_domain { + struct list_head clients; /* list of sysmmu_drvdata.node */ + unsigned long *pgtable; /* lv1 page table, 16KB */ + short *lv2entcnt; /* free lv2 entry counter for each section */ + spinlock_t lock; /* lock for this structure */ + spinlock_t pgtablelock; /* lock for modifying page table @ pgtable */ +}; + +struct sysmmu_drvdata { + struct list_head node; /* entry of exynos_iommu_domain.clients */ + struct device *sysmmu; /* System MMU's device descriptor */ + struct device *dev; /* Owner of system MMU */ + char *dbgname; + int nsfrs; + void __iomem **sfrbases; + struct clk *clk[2]; + int activations; + rwlock_t lock; + struct iommu_domain *domain; + sysmmu_fault_handler_t fault_handler; + unsigned long pgtable; +}; + +static bool set_sysmmu_active(struct sysmmu_drvdata *data) +{ + /* return true if the System MMU was not active previously + and it needs to be initialized */ + return ++data->activations == 1; +} + +static bool set_sysmmu_inactive(struct sysmmu_drvdata *data) +{ + /* return true if the System MMU is needed to be disabled */ + BUG_ON(data->activations < 1); + return --data->activations == 0; +} + +static bool is_sysmmu_active(struct sysmmu_drvdata *data) +{ + return data->activations > 0; +} + +static void sysmmu_unblock(void __iomem *sfrbase) +{ + __raw_writel(CTRL_ENABLE, sfrbase + REG_MMU_CTRL); +} + +static bool sysmmu_block(void __iomem *sfrbase) +{ + int i = 120; + + __raw_writel(CTRL_BLOCK, sfrbase + REG_MMU_CTRL); + while ((i > 0) && !(__raw_readl(sfrbase + REG_MMU_STATUS) & 1)) + --i; + + if (!(__raw_readl(sfrbase + REG_MMU_STATUS) & 1)) { + sysmmu_unblock(sfrbase); + return false; + } + + return true; +} + +static void __sysmmu_tlb_invalidate(void __iomem *sfrbase) +{ + __raw_writel(0x1, sfrbase + REG_MMU_FLUSH); +} + +static void __sysmmu_tlb_invalidate_entry(void __iomem *sfrbase, + unsigned long iova) +{ + __raw_writel((iova & SPAGE_MASK) | 1, sfrbase + REG_MMU_FLUSH_ENTRY); +} + +static void __sysmmu_set_ptbase(void __iomem *sfrbase, + unsigned long pgd) +{ + __raw_writel(0x1, sfrbase + REG_MMU_CFG); /* 16KB LV1, LRU */ + __raw_writel(pgd, sfrbase + REG_PT_BASE_ADDR); + + __sysmmu_tlb_invalidate(sfrbase); +} + +static void __sysmmu_set_prefbuf(void __iomem *sfrbase, unsigned long base, + unsigned long size, int idx) +{ + __raw_writel(base, sfrbase + REG_PB0_SADDR + idx * 8); + __raw_writel(size - 1 + base, sfrbase + REG_PB0_EADDR + idx * 8); +} + +void exynos_sysmmu_set_prefbuf(struct device *dev, + unsigned long base0, unsigned long size0, + unsigned long base1, unsigned long size1) +{ + struct sysmmu_drvdata *data = dev_get_drvdata(dev->archdata.iommu); + unsigned long flags; + int i; + + BUG_ON((base0 + size0) <= base0); + BUG_ON((size1 > 0) && ((base1 + size1) <= base1)); + + read_lock_irqsave(&data->lock, flags); + if (!is_sysmmu_active(data)) + goto finish; + + for (i = 0; i < data->nsfrs; i++) { + if ((readl(data->sfrbases[i] + REG_MMU_VERSION) >> 28) == 3) { + if (!sysmmu_block(data->sfrbases[i])) + continue; + + if (size1 == 0) { + if (size0 <= SZ_128K) { + base1 = base0; + size1 = size0; + } else { + size1 = size0 - + ALIGN(size0 / 2, SZ_64K); + size0 = size0 - size1; + base1 = base0 + size0; + } + } + + __sysmmu_set_prefbuf( + data->sfrbases[i], base0, size0, 0); + __sysmmu_set_prefbuf( + data->sfrbases[i], base1, size1, 1); + + sysmmu_unblock(data->sfrbases[i]); + } + } +finish: + read_unlock_irqrestore(&data->lock, flags); +} + +static void __set_fault_handler(struct sysmmu_drvdata *data, + sysmmu_fault_handler_t handler) +{ + unsigned long flags; + + write_lock_irqsave(&data->lock, flags); + data->fault_handler = handler; + write_unlock_irqrestore(&data->lock, flags); +} + +void exynos_sysmmu_set_fault_handler(struct device *dev, + sysmmu_fault_handler_t handler) +{ + struct sysmmu_drvdata *data = dev_get_drvdata(dev->archdata.iommu); + + __set_fault_handler(data, handler); +} + +static int default_fault_handler(enum exynos_sysmmu_inttype itype, + unsigned long pgtable_base, unsigned long fault_addr) +{ + unsigned long *ent; + + if ((itype >= SYSMMU_FAULTS_NUM) || (itype < SYSMMU_PAGEFAULT)) + itype = SYSMMU_FAULT_UNKNOWN; + + pr_err("%s occured at 0x%lx(Page table base: 0x%lx)\n", + sysmmu_fault_name[itype], fault_addr, pgtable_base); + + ent = section_entry(__va(pgtable_base), fault_addr); + pr_err("\tLv1 entry: 0x%lx\n", *ent); + + if (lv1ent_page(ent)) { + ent = page_entry(ent, fault_addr); + pr_err("\t Lv2 entry: 0x%lx\n", *ent); + } + + pr_err("Generating Kernel OOPS... because it is unrecoverable.\n"); + + BUG(); + + return 0; +} + +static irqreturn_t exynos_sysmmu_irq(int irq, void *dev_id) +{ + /* SYSMMU is in blocked when interrupt occurred. */ + struct sysmmu_drvdata *data = dev_id; + struct resource *irqres; + struct platform_device *pdev; + enum exynos_sysmmu_inttype itype; + unsigned long addr = -1; + + int i, ret = -ENOSYS; + + read_lock(&data->lock); + + WARN_ON(!is_sysmmu_active(data)); + + pdev = to_platform_device(data->sysmmu); + for (i = 0; i < (pdev->num_resources / 2); i++) { + irqres = platform_get_resource(pdev, IORESOURCE_IRQ, i); + if (irqres && ((int)irqres->start == irq)) + break; + } + + if (i == pdev->num_resources) { + itype = SYSMMU_FAULT_UNKNOWN; + } else { + itype = (enum exynos_sysmmu_inttype) + __ffs(__raw_readl(data->sfrbases[i] + REG_INT_STATUS)); + if (WARN_ON(!((itype >= 0) && (itype < SYSMMU_FAULT_UNKNOWN)))) + itype = SYSMMU_FAULT_UNKNOWN; + else + addr = __raw_readl( + data->sfrbases[i] + fault_reg_offset[itype]); + } + + if (data->domain) + ret = report_iommu_fault(data->domain, data->dev, + addr, itype); + + if ((ret == -ENOSYS) && data->fault_handler) { + unsigned long base = data->pgtable; + if (itype != SYSMMU_FAULT_UNKNOWN) + base = __raw_readl( + data->sfrbases[i] + REG_PT_BASE_ADDR); + ret = data->fault_handler(itype, base, addr); + } + + if (!ret && (itype != SYSMMU_FAULT_UNKNOWN)) + __raw_writel(1 << itype, data->sfrbases[i] + REG_INT_CLEAR); + else + dev_dbg(data->sysmmu, "(%s) %s is not handled.\n", + data->dbgname, sysmmu_fault_name[itype]); + + if (itype != SYSMMU_FAULT_UNKNOWN) + sysmmu_unblock(data->sfrbases[i]); + + read_unlock(&data->lock); + + return IRQ_HANDLED; +} + +static bool __exynos_sysmmu_disable(struct sysmmu_drvdata *data) +{ + unsigned long flags; + bool disabled = false; + int i; + + write_lock_irqsave(&data->lock, flags); + + if (!set_sysmmu_inactive(data)) + goto finish; + + for (i = 0; i < data->nsfrs; i++) + __raw_writel(CTRL_DISABLE, data->sfrbases[i] + REG_MMU_CTRL); + + if (data->clk[1]) + clk_disable(data->clk[1]); + if (data->clk[0]) + clk_disable(data->clk[0]); + + disabled = true; + data->pgtable = 0; + data->domain = NULL; +finish: + write_unlock_irqrestore(&data->lock, flags); + + if (disabled) + dev_dbg(data->sysmmu, "(%s) Disabled\n", data->dbgname); + else + dev_dbg(data->sysmmu, "(%s) %d times left to be disabled\n", + data->dbgname, data->activations); + + return disabled; +} + +/* __exynos_sysmmu_enable: Enables System MMU + * + * returns -error if an error occurred and System MMU is not enabled, + * 0 if the System MMU has been just enabled and 1 if System MMU was already + * enabled before. + */ +static int __exynos_sysmmu_enable(struct sysmmu_drvdata *data, + unsigned long pgtable, struct iommu_domain *domain) +{ + int i, ret = 0; + unsigned long flags; + + write_lock_irqsave(&data->lock, flags); + + if (!set_sysmmu_active(data)) { + if (WARN_ON(pgtable != data->pgtable)) { + ret = -EBUSY; + set_sysmmu_inactive(data); + } else { + ret = 1; + } + + dev_dbg(data->sysmmu, "(%s) Already enabled\n", data->dbgname); + goto finish; + } + + if (data->clk[0]) + clk_enable(data->clk[0]); + if (data->clk[1]) + clk_enable(data->clk[1]); + + data->pgtable = pgtable; + + for (i = 0; i < data->nsfrs; i++) { + __sysmmu_set_ptbase(data->sfrbases[i], pgtable); + + if ((readl(data->sfrbases[i] + REG_MMU_VERSION) >> 28) == 3) { + /* System MMU version is 3.x */ + __raw_writel((1 << 12) | (2 << 28), + data->sfrbases[i] + REG_MMU_CFG); + __sysmmu_set_prefbuf(data->sfrbases[i], 0, -1, 0); + __sysmmu_set_prefbuf(data->sfrbases[i], 0, -1, 1); + } + + __raw_writel(CTRL_ENABLE, data->sfrbases[i] + REG_MMU_CTRL); + } + + data->domain = domain; + + dev_dbg(data->sysmmu, "(%s) Enabled\n", data->dbgname); +finish: + write_unlock_irqrestore(&data->lock, flags); + + return ret; +} + +int exynos_sysmmu_enable(struct device *dev, unsigned long pgtable) +{ + struct sysmmu_drvdata *data = dev_get_drvdata(dev->archdata.iommu); + int ret; + + BUG_ON(!memblock_is_memory(pgtable)); + + ret = pm_runtime_get_sync(data->sysmmu); + if (ret < 0) { + dev_dbg(data->sysmmu, "(%s) Failed to enable\n", data->dbgname); + return ret; + } + + ret = __exynos_sysmmu_enable(data, pgtable, NULL); + if (WARN_ON(ret < 0)) { + pm_runtime_put(data->sysmmu); + dev_err(data->sysmmu, + "(%s) Already enabled with page table %#lx\n", + data->dbgname, data->pgtable); + } else { + data->dev = dev; + } + + return ret; +} + +bool exynos_sysmmu_disable(struct device *dev) +{ + struct sysmmu_drvdata *data = dev_get_drvdata(dev->archdata.iommu); + bool disabled; + + disabled = __exynos_sysmmu_disable(data); + pm_runtime_put(data->sysmmu); + + return disabled; +} + +static void sysmmu_tlb_invalidate_entry(struct device *dev, unsigned long iova) +{ + unsigned long flags; + struct sysmmu_drvdata *data = dev_get_drvdata(dev->archdata.iommu); + + read_lock_irqsave(&data->lock, flags); + + if (is_sysmmu_active(data)) { + int i; + for (i = 0; i < data->nsfrs; i++) { + if (sysmmu_block(data->sfrbases[i])) { + __sysmmu_tlb_invalidate_entry( + data->sfrbases[i], iova); + sysmmu_unblock(data->sfrbases[i]); + } + } + } else { + dev_dbg(data->sysmmu, + "(%s) Disabled. Skipping invalidating TLB.\n", + data->dbgname); + } + + read_unlock_irqrestore(&data->lock, flags); +} + +void exynos_sysmmu_tlb_invalidate(struct device *dev) +{ + unsigned long flags; + struct sysmmu_drvdata *data = dev_get_drvdata(dev->archdata.iommu); + + read_lock_irqsave(&data->lock, flags); + + if (is_sysmmu_active(data)) { + int i; + for (i = 0; i < data->nsfrs; i++) { + if (sysmmu_block(data->sfrbases[i])) { + __sysmmu_tlb_invalidate(data->sfrbases[i]); + sysmmu_unblock(data->sfrbases[i]); + } + } + } else { + dev_dbg(data->sysmmu, + "(%s) Disabled. Skipping invalidating TLB.\n", + data->dbgname); + } + + read_unlock_irqrestore(&data->lock, flags); +} + +static int exynos_sysmmu_probe(struct platform_device *pdev) +{ + int i, ret; + struct device *dev; + struct sysmmu_drvdata *data; + + dev = &pdev->dev; + + data = kzalloc(sizeof(*data), GFP_KERNEL); + if (!data) { + dev_dbg(dev, "Not enough memory\n"); + ret = -ENOMEM; + goto err_alloc; + } + + ret = dev_set_drvdata(dev, data); + if (ret) { + dev_dbg(dev, "Unabled to initialize driver data\n"); + goto err_init; + } + + data->nsfrs = pdev->num_resources / 2; + data->sfrbases = kmalloc(sizeof(*data->sfrbases) * data->nsfrs, + GFP_KERNEL); + if (data->sfrbases == NULL) { + dev_dbg(dev, "Not enough memory\n"); + ret = -ENOMEM; + goto err_init; + } + + for (i = 0; i < data->nsfrs; i++) { + struct resource *res; + res = platform_get_resource(pdev, IORESOURCE_MEM, i); + if (!res) { + dev_dbg(dev, "Unable to find IOMEM region\n"); + ret = -ENOENT; + goto err_res; + } + + data->sfrbases[i] = ioremap(res->start, resource_size(res)); + if (!data->sfrbases[i]) { + dev_dbg(dev, "Unable to map IOMEM @ PA:%#x\n", + res->start); + ret = -ENOENT; + goto err_res; + } + } + + for (i = 0; i < data->nsfrs; i++) { + ret = platform_get_irq(pdev, i); + if (ret <= 0) { + dev_dbg(dev, "Unable to find IRQ resource\n"); + goto err_irq; + } + + ret = request_irq(ret, exynos_sysmmu_irq, 0, + dev_name(dev), data); + if (ret) { + dev_dbg(dev, "Unabled to register interrupt handler\n"); + goto err_irq; + } + } + + if (dev_get_platdata(dev)) { + char *deli, *beg; + struct sysmmu_platform_data *platdata = dev_get_platdata(dev); + + beg = platdata->clockname; + + for (deli = beg; (*deli != '\0') && (*deli != ','); deli++) + /* NOTHING */; + + if (*deli == '\0') + deli = NULL; + else + *deli = '\0'; + + data->clk[0] = clk_get(dev, beg); + if (IS_ERR(data->clk[0])) { + data->clk[0] = NULL; + dev_dbg(dev, "No clock descriptor registered\n"); + } + + if (data->clk[0] && deli) { + *deli = ','; + data->clk[1] = clk_get(dev, deli + 1); + if (IS_ERR(data->clk[1])) + data->clk[1] = NULL; + } + + data->dbgname = platdata->dbgname; + } + + data->sysmmu = dev; + rwlock_init(&data->lock); + INIT_LIST_HEAD(&data->node); + + __set_fault_handler(data, &default_fault_handler); + + if (dev->parent) + pm_runtime_enable(dev); + + dev_dbg(dev, "(%s) Initialized\n", data->dbgname); + return 0; +err_irq: + while (i-- > 0) { + int irq; + + irq = platform_get_irq(pdev, i); + free_irq(irq, data); + } +err_res: + while (data->nsfrs-- > 0) + iounmap(data->sfrbases[data->nsfrs]); + kfree(data->sfrbases); +err_init: + kfree(data); +err_alloc: + dev_err(dev, "Failed to initialize\n"); + return ret; +} + +static struct platform_driver exynos_sysmmu_driver = { + .probe = exynos_sysmmu_probe, + .driver = { + .owner = THIS_MODULE, + .name = "exynos-sysmmu", + } +}; + +static inline void pgtable_flush(void *vastart, void *vaend) +{ + dmac_flush_range(vastart, vaend); + outer_flush_range(virt_to_phys(vastart), + virt_to_phys(vaend)); +} + +static int exynos_iommu_domain_init(struct iommu_domain *domain) +{ + struct exynos_iommu_domain *priv; + + priv = kzalloc(sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->pgtable = (unsigned long *)__get_free_pages( + GFP_KERNEL | __GFP_ZERO, 2); + if (!priv->pgtable) + goto err_pgtable; + + priv->lv2entcnt = (short *)__get_free_pages( + GFP_KERNEL | __GFP_ZERO, 1); + if (!priv->lv2entcnt) + goto err_counter; + + pgtable_flush(priv->pgtable, priv->pgtable + NUM_LV1ENTRIES); + + spin_lock_init(&priv->lock); + spin_lock_init(&priv->pgtablelock); + INIT_LIST_HEAD(&priv->clients); + + domain->priv = priv; + return 0; + +err_counter: + free_pages((unsigned long)priv->pgtable, 2); +err_pgtable: + kfree(priv); + return -ENOMEM; +} + +static void exynos_iommu_domain_destroy(struct iommu_domain *domain) +{ + struct exynos_iommu_domain *priv = domain->priv; + struct sysmmu_drvdata *data; + unsigned long flags; + int i; + + WARN_ON(!list_empty(&priv->clients)); + + spin_lock_irqsave(&priv->lock, flags); + + list_for_each_entry(data, &priv->clients, node) { + while (!exynos_sysmmu_disable(data->dev)) + ; /* until System MMU is actually disabled */ + } + + spin_unlock_irqrestore(&priv->lock, flags); + + for (i = 0; i < NUM_LV1ENTRIES; i++) + if (lv1ent_page(priv->pgtable + i)) + kfree(__va(lv2table_base(priv->pgtable + i))); + + free_pages((unsigned long)priv->pgtable, 2); + free_pages((unsigned long)priv->lv2entcnt, 1); + kfree(domain->priv); + domain->priv = NULL; +} + +static int exynos_iommu_attach_device(struct iommu_domain *domain, + struct device *dev) +{ + struct sysmmu_drvdata *data = dev_get_drvdata(dev->archdata.iommu); + struct exynos_iommu_domain *priv = domain->priv; + unsigned long flags; + int ret; + + ret = pm_runtime_get_sync(data->sysmmu); + if (ret < 0) + return ret; + + ret = 0; + + spin_lock_irqsave(&priv->lock, flags); + + ret = __exynos_sysmmu_enable(data, __pa(priv->pgtable), domain); + + if (ret == 0) { + /* 'data->node' must not be appeared in priv->clients */ + BUG_ON(!list_empty(&data->node)); + data->dev = dev; + list_add_tail(&data->node, &priv->clients); + } + + spin_unlock_irqrestore(&priv->lock, flags); + + if (ret < 0) { + dev_err(dev, "%s: Failed to attach IOMMU with pgtable %#lx\n", + __func__, __pa(priv->pgtable)); + pm_runtime_put(data->sysmmu); + } else if (ret > 0) { + dev_dbg(dev, "%s: IOMMU with pgtable 0x%lx already attached\n", + __func__, __pa(priv->pgtable)); + } else { + dev_dbg(dev, "%s: Attached new IOMMU with pgtable 0x%lx\n", + __func__, __pa(priv->pgtable)); + } + + return ret; +} + +static void exynos_iommu_detach_device(struct iommu_domain *domain, + struct device *dev) +{ + struct sysmmu_drvdata *data = dev_get_drvdata(dev->archdata.iommu); + struct exynos_iommu_domain *priv = domain->priv; + struct list_head *pos; + unsigned long flags; + bool found = false; + + spin_lock_irqsave(&priv->lock, flags); + + list_for_each(pos, &priv->clients) { + if (list_entry(pos, struct sysmmu_drvdata, node) == data) { + found = true; + break; + } + } + + if (!found) + goto finish; + + if (__exynos_sysmmu_disable(data)) { + dev_dbg(dev, "%s: Detached IOMMU with pgtable %#lx\n", + __func__, __pa(priv->pgtable)); + list_del(&data->node); + INIT_LIST_HEAD(&data->node); + + } else { + dev_dbg(dev, "%s: Detaching IOMMU with pgtable %#lx delayed", + __func__, __pa(priv->pgtable)); + } + +finish: + spin_unlock_irqrestore(&priv->lock, flags); + + if (found) + pm_runtime_put(data->sysmmu); +} + +static unsigned long *alloc_lv2entry(unsigned long *sent, unsigned long iova, + short *pgcounter) +{ + if (lv1ent_fault(sent)) { + unsigned long *pent; + + pent = kzalloc(LV2TABLE_SIZE, GFP_ATOMIC); + BUG_ON((unsigned long)pent & (LV2TABLE_SIZE - 1)); + if (!pent) + return NULL; + + *sent = mk_lv1ent_page(__pa(pent)); + *pgcounter = NUM_LV2ENTRIES; + pgtable_flush(pent, pent + NUM_LV2ENTRIES); + pgtable_flush(sent, sent + 1); + } + + return page_entry(sent, iova); +} + +static int lv1set_section(unsigned long *sent, phys_addr_t paddr, short *pgcnt) +{ + if (lv1ent_section(sent)) + return -EADDRINUSE; + + if (lv1ent_page(sent)) { + if (*pgcnt != NUM_LV2ENTRIES) + return -EADDRINUSE; + + kfree(page_entry(sent, 0)); + + *pgcnt = 0; + } + + *sent = mk_lv1ent_sect(paddr); + + pgtable_flush(sent, sent + 1); + + return 0; +} + +static int lv2set_page(unsigned long *pent, phys_addr_t paddr, size_t size, + short *pgcnt) +{ + if (size == SPAGE_SIZE) { + if (!lv2ent_fault(pent)) + return -EADDRINUSE; + + *pent = mk_lv2ent_spage(paddr); + pgtable_flush(pent, pent + 1); + *pgcnt -= 1; + } else { /* size == LPAGE_SIZE */ + int i; + for (i = 0; i < SPAGES_PER_LPAGE; i++, pent++) { + if (!lv2ent_fault(pent)) { + memset(pent, 0, sizeof(*pent) * i); + return -EADDRINUSE; + } + + *pent = mk_lv2ent_lpage(paddr); + } + pgtable_flush(pent - SPAGES_PER_LPAGE, pent); + *pgcnt -= SPAGES_PER_LPAGE; + } + + return 0; +} + +static int exynos_iommu_map(struct iommu_domain *domain, unsigned long iova, + phys_addr_t paddr, size_t size, int prot) +{ + struct exynos_iommu_domain *priv = domain->priv; + unsigned long *entry; + unsigned long flags; + int ret = -ENOMEM; + + BUG_ON(priv->pgtable == NULL); + + spin_lock_irqsave(&priv->pgtablelock, flags); + + entry = section_entry(priv->pgtable, iova); + + if (size == SECT_SIZE) { + ret = lv1set_section(entry, paddr, + &priv->lv2entcnt[lv1ent_offset(iova)]); + } else { + unsigned long *pent; + + pent = alloc_lv2entry(entry, iova, + &priv->lv2entcnt[lv1ent_offset(iova)]); + + if (!pent) + ret = -ENOMEM; + else + ret = lv2set_page(pent, paddr, size, + &priv->lv2entcnt[lv1ent_offset(iova)]); + } + + if (ret) { + pr_debug("%s: Failed to map iova 0x%lx/0x%x bytes\n", + __func__, iova, size); + } + + spin_unlock_irqrestore(&priv->pgtablelock, flags); + + return ret; +} + +static size_t exynos_iommu_unmap(struct iommu_domain *domain, + unsigned long iova, size_t size) +{ + struct exynos_iommu_domain *priv = domain->priv; + struct sysmmu_drvdata *data; + unsigned long flags; + unsigned long *ent; + + BUG_ON(priv->pgtable == NULL); + + spin_lock_irqsave(&priv->pgtablelock, flags); + + ent = section_entry(priv->pgtable, iova); + + if (lv1ent_section(ent)) { + BUG_ON(size < SECT_SIZE); + + *ent = 0; + pgtable_flush(ent, ent + 1); + size = SECT_SIZE; + goto done; + } + + if (unlikely(lv1ent_fault(ent))) { + if (size > SECT_SIZE) + size = SECT_SIZE; + goto done; + } + + /* lv1ent_page(sent) == true here */ + + ent = page_entry(ent, iova); + + if (unlikely(lv2ent_fault(ent))) { + size = SPAGE_SIZE; + goto done; + } + + if (lv2ent_small(ent)) { + *ent = 0; + size = SPAGE_SIZE; + priv->lv2entcnt[lv1ent_offset(iova)] += 1; + goto done; + } + + /* lv1ent_large(ent) == true here */ + BUG_ON(size < LPAGE_SIZE); + + memset(ent, 0, sizeof(*ent) * SPAGES_PER_LPAGE); + + size = LPAGE_SIZE; + priv->lv2entcnt[lv1ent_offset(iova)] += SPAGES_PER_LPAGE; +done: + spin_unlock_irqrestore(&priv->pgtablelock, flags); + + spin_lock_irqsave(&priv->lock, flags); + list_for_each_entry(data, &priv->clients, node) + sysmmu_tlb_invalidate_entry(data->dev, iova); + spin_unlock_irqrestore(&priv->lock, flags); + + + return size; +} + +static phys_addr_t exynos_iommu_iova_to_phys(struct iommu_domain *domain, + unsigned long iova) +{ + struct exynos_iommu_domain *priv = domain->priv; + unsigned long *entry; + unsigned long flags; + phys_addr_t phys = 0; + + spin_lock_irqsave(&priv->pgtablelock, flags); + + entry = section_entry(priv->pgtable, iova); + + if (lv1ent_section(entry)) { + phys = section_phys(entry) + section_offs(iova); + } else if (lv1ent_page(entry)) { + entry = page_entry(entry, iova); + + if (lv2ent_large(entry)) + phys = lpage_phys(entry) + lpage_offs(iova); + else if (lv2ent_small(entry)) + phys = spage_phys(entry) + spage_offs(iova); + } + + spin_unlock_irqrestore(&priv->pgtablelock, flags); + + return phys; +} + +static struct iommu_ops exynos_iommu_ops = { + .domain_init = &exynos_iommu_domain_init, + .domain_destroy = &exynos_iommu_domain_destroy, + .attach_dev = &exynos_iommu_attach_device, + .detach_dev = &exynos_iommu_detach_device, + .map = &exynos_iommu_map, + .unmap = &exynos_iommu_unmap, + .iova_to_phys = &exynos_iommu_iova_to_phys, + .pgsize_bitmap = SECT_SIZE | LPAGE_SIZE | SPAGE_SIZE, +}; + +static int __init exynos_iommu_init(void) +{ + int ret; + + ret = platform_driver_register(&exynos_sysmmu_driver); + + if (ret == 0) + bus_set_iommu(&platform_bus_type, &exynos_iommu_ops); + + return ret; +} +subsys_initcall(exynos_iommu_init); diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index a9fc714fb38d..9a7a60aeb19e 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -1781,7 +1781,7 @@ static struct omap_mmc_platform_data *of_get_hsmmc_pdata(struct device *dev) pdata->slots[0].nonremovable = true; pdata->slots[0].no_regulator_off_init = true; } - of_property_read_u32(np, "ti,bus-width", &bus_width); + of_property_read_u32(np, "bus-width", &bus_width); if (bus_width == 4) pdata->slots[0].caps |= MMC_CAP_4_BIT_DATA; else if (bus_width == 8) diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c index d190d04636a7..365b16c230f8 100644 --- a/drivers/mmc/host/sdhci-esdhc-imx.c +++ b/drivers/mmc/host/sdhci-esdhc-imx.c @@ -404,7 +404,7 @@ sdhci_esdhc_imx_probe_dt(struct platform_device *pdev, if (!np) return -ENODEV; - if (of_get_property(np, "fsl,card-wired", NULL)) + if (of_get_property(np, "non-removable", NULL)) boarddata->cd_type = ESDHC_CD_PERMANENT; if (of_get_property(np, "fsl,cd-controller", NULL)) diff --git a/drivers/mmc/host/sdhci-pltfm.c b/drivers/mmc/host/sdhci-pltfm.c index c5c2a48bdd94..d9a4ef4f1ed0 100644 --- a/drivers/mmc/host/sdhci-pltfm.c +++ b/drivers/mmc/host/sdhci-pltfm.c @@ -42,7 +42,8 @@ static struct sdhci_ops sdhci_pltfm_ops = { #ifdef CONFIG_OF static bool sdhci_of_wp_inverted(struct device_node *np) { - if (of_get_property(np, "sdhci,wp-inverted", NULL)) + if (of_get_property(np, "sdhci,wp-inverted", NULL) || + of_get_property(np, "wp-inverted", NULL)) return true; /* Old device trees don't have the wp-inverted property. */ @@ -59,13 +60,16 @@ void sdhci_get_of_property(struct platform_device *pdev) struct sdhci_host *host = platform_get_drvdata(pdev); struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); const __be32 *clk; + u32 bus_width; int size; if (of_device_is_available(np)) { if (of_get_property(np, "sdhci,auto-cmd12", NULL)) host->quirks |= SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12; - if (of_get_property(np, "sdhci,1-bit-only", NULL)) + if (of_get_property(np, "sdhci,1-bit-only", NULL) || + (of_property_read_u32(np, "bus-width", &bus_width) == 0 && + bus_width == 1)) host->quirks |= SDHCI_QUIRK_FORCE_1_BIT_DATA; if (sdhci_of_wp_inverted(np)) diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c index 4a44bf833611..68548236ec42 100644 --- a/drivers/usb/host/ehci-tegra.c +++ b/drivers/usb/host/ehci-tegra.c @@ -722,8 +722,9 @@ static int tegra_ehci_probe(struct platform_device *pdev) } } - tegra->phy = tegra_usb_phy_open(instance, hcd->regs, pdata->phy_config, - TEGRA_USB_PHY_MODE_HOST); + tegra->phy = tegra_usb_phy_open(&pdev->dev, instance, hcd->regs, + pdata->phy_config, + TEGRA_USB_PHY_MODE_HOST); if (IS_ERR(tegra->phy)) { dev_err(&pdev->dev, "Failed to open USB phy\n"); err = -ENXIO; |